jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

506 lines
15KB

  1. /*
  2. Copyright (C) 2001-2005 Paul Davis
  3. Copyright (C) 2004-2006 Grame
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. */
  16. #ifdef WIN32
  17. #pragma warning (disable : 4786)
  18. #endif
  19. #include "JackDriverLoader.h"
  20. #include "JackError.h"
  21. #include <getopt.h>
  22. #ifndef WIN32
  23. #include <dirent.h>
  24. #endif
  25. static void
  26. jack_print_driver_options (jack_driver_desc_t * desc, FILE *file)
  27. {
  28. unsigned long i;
  29. char arg_default[JACK_DRIVER_PARAM_STRING_MAX + 1];
  30. for (i = 0; i < desc->nparams; i++) {
  31. switch (desc->params[i].type) {
  32. case JackDriverParamInt:
  33. //sprintf (arg_default, "%" PRIi32, desc->params[i].value.i);
  34. sprintf (arg_default, "%" "i", desc->params[i].value.i);
  35. break;
  36. case JackDriverParamUInt:
  37. //sprintf (arg_default, "%" PRIu32, desc->params[i].value.ui);
  38. sprintf (arg_default, "%" "u", desc->params[i].value.ui);
  39. break;
  40. case JackDriverParamChar:
  41. sprintf (arg_default, "%c", desc->params[i].value.c);
  42. break;
  43. case JackDriverParamString:
  44. if (desc->params[i].value.str && strcmp (desc->params[i].value.str, "") != 0)
  45. sprintf (arg_default, "%s", desc->params[i].value.str);
  46. else
  47. sprintf (arg_default, "none");
  48. break;
  49. case JackDriverParamBool:
  50. sprintf (arg_default, "%s", desc->params[i].value.i ? "true" : "false");
  51. break;
  52. }
  53. fprintf (file, "\t-%c, --%s \t%s (default: %s)\n",
  54. desc->params[i].character,
  55. desc->params[i].name,
  56. desc->params[i].short_desc,
  57. arg_default);
  58. }
  59. }
  60. static void
  61. jack_print_driver_param_usage (jack_driver_desc_t * desc, unsigned long param, FILE *file)
  62. {
  63. fprintf (file, "Usage information for the '%s' parameter for driver '%s':\n",
  64. desc->params[param].name, desc->name);
  65. fprintf (file, "%s\n", desc->params[param].long_desc);
  66. }
  67. EXPORT int
  68. jack_parse_driver_params (jack_driver_desc_t * desc, int argc, char* argv[], JSList ** param_ptr)
  69. {
  70. struct option * long_options;
  71. char * options, * options_ptr;
  72. unsigned long i;
  73. int opt;
  74. unsigned int param_index;
  75. JSList * params = NULL;
  76. jack_driver_param_t * driver_param;
  77. if (argc <= 1) {
  78. *param_ptr = NULL;
  79. return 0;
  80. }
  81. /* check for help */
  82. if (strcmp (argv[1], "-h") == 0 || strcmp (argv[1], "--help") == 0) {
  83. if (argc > 2) {
  84. for (i = 0; i < desc->nparams; i++) {
  85. if (strcmp (desc->params[i].name, argv[2]) == 0) {
  86. jack_print_driver_param_usage (desc, i, stdout);
  87. return 1;
  88. }
  89. }
  90. fprintf (stderr, "jackd: unknown option '%s' "
  91. "for driver '%s'\n", argv[2],
  92. desc->name);
  93. }
  94. printf ("Parameters for driver '%s' (all parameters are optional):\n", desc->name);
  95. jack_print_driver_options (desc, stdout);
  96. return 1;
  97. }
  98. /* set up the stuff for getopt */
  99. options = (char*)calloc (desc->nparams * 3 + 1, sizeof (char));
  100. long_options = (option*)calloc (desc->nparams + 1, sizeof (struct option));
  101. options_ptr = options;
  102. for (i = 0; i < desc->nparams; i++) {
  103. sprintf (options_ptr, "%c::", desc->params[i].character);
  104. options_ptr += 3;
  105. long_options[i].name = desc->params[i].name;
  106. long_options[i].flag = NULL;
  107. long_options[i].val = desc->params[i].character;
  108. long_options[i].has_arg = optional_argument;
  109. }
  110. /* create the params */
  111. optind = 0;
  112. opterr = 0;
  113. while ((opt = getopt_long(argc, argv, options, long_options, NULL)) != -1) {
  114. if (opt == ':' || opt == '?') {
  115. if (opt == ':') {
  116. fprintf (stderr, "Missing option to argument '%c'\n", optopt);
  117. } else {
  118. fprintf (stderr, "Unknownage with option '%c'\n", optopt);
  119. }
  120. fprintf (stderr, "Options for driver '%s':\n", desc->name);
  121. jack_print_driver_options (desc, stderr);
  122. exit (1);
  123. }
  124. for (param_index = 0; param_index < desc->nparams; param_index++) {
  125. if (opt == desc->params[param_index].character) {
  126. break;
  127. }
  128. }
  129. driver_param = (jack_driver_param_t*)calloc (1, sizeof (jack_driver_param_t));
  130. driver_param->character = desc->params[param_index].character;
  131. if (!optarg && optind < argc &&
  132. strlen(argv[optind]) &&
  133. argv[optind][0] != '-') {
  134. optarg = argv[optind];
  135. }
  136. if (optarg) {
  137. switch (desc->params[param_index].type) {
  138. case JackDriverParamInt:
  139. driver_param->value.i = atoi (optarg);
  140. break;
  141. case JackDriverParamUInt:
  142. driver_param->value.ui = strtoul (optarg, NULL, 10);
  143. break;
  144. case JackDriverParamChar:
  145. driver_param->value.c = optarg[0];
  146. break;
  147. case JackDriverParamString:
  148. strncpy (driver_param->value.str, optarg, JACK_DRIVER_PARAM_STRING_MAX);
  149. break;
  150. case JackDriverParamBool:
  151. /*
  152. if (strcasecmp ("false", optarg) == 0 ||
  153. strcasecmp ("off", optarg) == 0 ||
  154. strcasecmp ("no", optarg) == 0 ||
  155. strcasecmp ("0", optarg) == 0 ||
  156. strcasecmp ("(null)", optarg) == 0 ) {
  157. */
  158. // steph
  159. if (strcmp ("false", optarg) == 0 ||
  160. strcmp ("off", optarg) == 0 ||
  161. strcmp ("no", optarg) == 0 ||
  162. strcmp ("0", optarg) == 0 ||
  163. strcmp ("(null)", optarg) == 0 ) {
  164. driver_param->value.i = false;
  165. } else {
  166. driver_param->value.i = true;
  167. }
  168. break;
  169. }
  170. } else {
  171. if (desc->params[param_index].type == JackDriverParamBool) {
  172. driver_param->value.i = true;
  173. } else {
  174. driver_param->value = desc->params[param_index].value;
  175. }
  176. }
  177. params = jack_slist_append (params, driver_param);
  178. }
  179. free (options);
  180. free (long_options);
  181. if (param_ptr)
  182. *param_ptr = params;
  183. return 0;
  184. }
  185. EXPORT jack_driver_desc_t *
  186. jack_find_driver_descriptor (JSList * drivers, const char * name)
  187. {
  188. jack_driver_desc_t * desc = 0;
  189. JSList * node;
  190. for (node = drivers; node; node = jack_slist_next (node)) {
  191. desc = (jack_driver_desc_t *) node->data;
  192. if (strcmp (desc->name, name) != 0) {
  193. desc = NULL;
  194. } else {
  195. break;
  196. }
  197. }
  198. return desc;
  199. }
  200. jack_driver_desc_t *
  201. jack_drivers_get_descriptor (JSList * drivers, const char * sofile)
  202. {
  203. jack_driver_desc_t * descriptor, * other_descriptor;
  204. JackDriverDescFunction so_get_descriptor = NULL;
  205. JSList * node;
  206. void * dlhandle;
  207. char * filename;
  208. #ifdef WIN32
  209. int dlerr;
  210. #else
  211. const char * dlerr;
  212. #endif
  213. int err;
  214. /*
  215. char* driver_dir;
  216. if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
  217. driver_dir = ADDON_DIR;
  218. }
  219. */
  220. #ifdef WIN32
  221. char* driver_dir = ADDON_DIR;
  222. if (strcmp(ADDON_DIR, "") == 0) {
  223. char temp_driver_dir1[512];
  224. char temp_driver_dir2[512];
  225. GetCurrentDirectory(512, temp_driver_dir1);
  226. sprintf(temp_driver_dir2, "%s/%s", temp_driver_dir1, ADDON_DIR);
  227. driver_dir = temp_driver_dir2;
  228. }
  229. #else
  230. char driver_dir[512];
  231. snprintf(driver_dir, sizeof(driver_dir) - 1, "%s/%s/jackmp", ADDON_DIR, LIB_DIR);
  232. #endif
  233. filename = (char *)malloc(strlen (driver_dir) + 1 + strlen(sofile) + 1);
  234. sprintf (filename, "%s/%s", driver_dir, sofile);
  235. if ((dlhandle = LoadDriverModule(filename)) == NULL) {
  236. #ifdef WIN32
  237. jack_error ("could not open driver .dll '%s': %ld\n", filename, GetLastError());
  238. #else
  239. jack_error ("could not open driver .so '%s': %s\n", filename, dlerror());
  240. #endif
  241. free(filename);
  242. return NULL;
  243. }
  244. so_get_descriptor = (JackDriverDescFunction)
  245. GetProc(dlhandle, "driver_get_descriptor");
  246. #ifdef WIN32
  247. if ((so_get_descriptor == NULL) && (dlerr = GetLastError()) != 0) {
  248. fprintf(stderr, "%ld\n", dlerr);
  249. #else
  250. if ((so_get_descriptor == NULL) && (dlerr = dlerror ()) != NULL) {
  251. fprintf(stderr, "%s\n", dlerr);
  252. #endif
  253. UnloadDriverModule(dlhandle);
  254. free(filename);
  255. return NULL;
  256. }
  257. if ((descriptor = so_get_descriptor ()) == NULL) {
  258. jack_error("driver from '%s' returned NULL descriptor\n", filename);
  259. UnloadDriverModule(dlhandle);
  260. free(filename);
  261. return NULL;
  262. }
  263. #ifdef WIN32
  264. if ((err = UnloadDriverModule(dlhandle)) == 0) {
  265. jack_error ("error closing driver .so '%s': %ld\n", filename, GetLastError ());
  266. }
  267. #else
  268. if ((err = UnloadDriverModule(dlhandle)) != 0) {
  269. jack_error ("error closing driver .so '%s': %s\n", filename, dlerror ());
  270. }
  271. #endif
  272. /* check it doesn't exist already */
  273. for (node = drivers; node; node = jack_slist_next (node)) {
  274. other_descriptor = (jack_driver_desc_t *) node->data;
  275. if (strcmp(descriptor->name, other_descriptor->name) == 0) {
  276. jack_error("the drivers in '%s' and '%s' both have the name '%s'; using the first\n",
  277. other_descriptor->file, filename, other_descriptor->name);
  278. /* FIXME: delete the descriptor */
  279. free(filename);
  280. return NULL;
  281. }
  282. }
  283. strncpy(descriptor->file, filename, PATH_MAX);
  284. free(filename);
  285. return descriptor;
  286. }
  287. #ifdef WIN32
  288. EXPORT JSList *
  289. jack_drivers_load (JSList * drivers) {
  290. char driver_dir[512];
  291. char dll_filename[512];
  292. WIN32_FIND_DATA filedata;
  293. HANDLE file;
  294. const char * ptr = NULL;
  295. JSList * driver_list = NULL;
  296. jack_driver_desc_t * desc;
  297. GetCurrentDirectory(512, driver_dir);
  298. sprintf(dll_filename, "%s/%s", ADDON_DIR, "*.dll");
  299. file = (HANDLE )FindFirstFile(dll_filename, &filedata);
  300. if (file == INVALID_HANDLE_VALUE) {
  301. printf("error\n");
  302. return NULL;
  303. }
  304. do {
  305. ptr = strrchr (filedata.cFileName, '.');
  306. if (!ptr) {
  307. continue;
  308. }
  309. ptr++;
  310. if (strncmp ("dll", ptr, 3) != 0) {
  311. continue;
  312. }
  313. desc = jack_drivers_get_descriptor (drivers, filedata.cFileName);
  314. if (desc) {
  315. driver_list = jack_slist_append (driver_list, desc);
  316. }
  317. } while (FindNextFile(file, &filedata));
  318. if (!driver_list) {
  319. jack_error ("could not find any drivers in %s!\n", driver_dir);
  320. return NULL;
  321. }
  322. return driver_list;
  323. }
  324. #else
  325. JSList *
  326. jack_drivers_load (JSList * drivers) {
  327. struct dirent * dir_entry;
  328. DIR * dir_stream;
  329. const char * ptr;
  330. int err;
  331. JSList * driver_list = NULL;
  332. jack_driver_desc_t * desc;
  333. /*
  334. char* driver_dir;
  335. if ((driver_dir = getenv("JACK_DRIVER_DIR")) == 0) {
  336. driver_dir = ADDON_DIR;
  337. }
  338. */
  339. char driver_dir[512];
  340. snprintf(driver_dir, sizeof(driver_dir) - 1, "%s/%s/jackmp", ADDON_DIR, LIB_DIR);
  341. /* search through the driver_dir and add get descriptors
  342. from the .so files in it */
  343. dir_stream = opendir (driver_dir);
  344. if (!dir_stream) {
  345. jack_error ("could not open driver directory %s: %s\n",
  346. driver_dir, strerror (errno));
  347. return NULL;
  348. }
  349. while ((dir_entry = readdir(dir_stream))) {
  350. /* check the filename is of the right format */
  351. if (strncmp ("jack_", dir_entry->d_name, 5) != 0) {
  352. continue;
  353. }
  354. ptr = strrchr (dir_entry->d_name, '.');
  355. if (!ptr) {
  356. continue;
  357. }
  358. ptr++;
  359. if (strncmp ("so", ptr, 2) != 0) {
  360. continue;
  361. }
  362. desc = jack_drivers_get_descriptor (drivers, dir_entry->d_name);
  363. if (desc) {
  364. driver_list = jack_slist_append (driver_list, desc);
  365. }
  366. }
  367. err = closedir (dir_stream);
  368. if (err) {
  369. jack_error ("error closing driver directory %s: %s\n",
  370. driver_dir, strerror (errno));
  371. }
  372. if (!driver_list) {
  373. jack_error ("could not find any drivers in %s!\n", driver_dir);
  374. return NULL;
  375. }
  376. return driver_list;
  377. }
  378. #endif
  379. jack_driver_info_t *
  380. jack_load_driver (jack_driver_desc_t * driver_desc) {
  381. #ifdef WIN32
  382. int errstr;
  383. #else
  384. const char * errstr;
  385. #endif
  386. jack_driver_info_t *info;
  387. info = (jack_driver_info_t *) calloc (1, sizeof (*info));
  388. info->handle = LoadDriverModule (driver_desc->file);
  389. if (info->handle == NULL) {
  390. #ifdef WIN32
  391. if ((errstr = GetLastError ()) != 0) {
  392. jack_error ("can't load \"%s\": %ld", driver_desc->file,
  393. errstr);
  394. #else
  395. if ((errstr = dlerror ()) != 0) {
  396. jack_error ("can't load \"%s\": %s", driver_desc->file,
  397. errstr);
  398. #endif
  399. } else {
  400. jack_error ("bizarre error loading driver shared "
  401. "object %s", driver_desc->file);
  402. }
  403. goto fail;
  404. }
  405. info->initialize = (initialize)GetProc(info->handle, "driver_initialize");
  406. #ifdef WIN32
  407. if ((info->initialize == NULL) && (errstr = GetLastError ()) != 0) {
  408. #else
  409. if ((info->initialize == NULL) && (errstr = dlerror ()) != 0) {
  410. #endif
  411. jack_error ("no initialize function in shared object %s\n",
  412. driver_desc->file);
  413. goto fail;
  414. }
  415. return info;
  416. fail:
  417. if (info->handle) {
  418. UnloadDriverModule(info->handle);
  419. }
  420. free (info);
  421. return NULL;
  422. }