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.

688 lines
18KB

  1. /*
  2. Copyright (C) 2001 Paul Davis
  3. Copyright (C) 2004 Karsten Wiese, Rui Nuno Capela
  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. $Id: usx2y.c,v 1.2 2005/09/29 14:51:59 letz Exp $
  16. */
  17. //#include <jack/hardware.h>
  18. #include "hardware.h"
  19. #include "alsa_driver.h"
  20. #include "usx2y.h"
  21. //#include <jack/internal.h>
  22. //#include <jack/engine.h>
  23. #include <jack/messagebuffer.h>
  24. #include <sys/mman.h>
  25. #ifndef ARRAY_SIZE
  26. #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
  27. #endif
  28. //#define DBGHWDEP
  29. #ifdef DBGHWDEP
  30. int dbg_offset;
  31. char dbg_buffer[8096];
  32. #endif
  33. static
  34. int usx2y_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask)
  35. {
  36. return -1;
  37. }
  38. static
  39. int usx2y_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode)
  40. {
  41. return -1;
  42. }
  43. static void
  44. usx2y_release (jack_hardware_t *hw)
  45. {
  46. usx2y_t *h = (usx2y_t *) hw->private;
  47. if (h == 0)
  48. return;
  49. if (h->hwdep_handle)
  50. snd_hwdep_close(h->hwdep_handle);
  51. free(h);
  52. }
  53. static int
  54. usx2y_driver_get_channel_addresses_playback (alsa_driver_t *driver,
  55. snd_pcm_uframes_t *playback_avail)
  56. {
  57. channel_t chn;
  58. int iso;
  59. snd_pcm_uframes_t playback_iso_avail;
  60. char *playback;
  61. usx2y_t *h = (usx2y_t *) driver->hw->private;
  62. if (0 > h->playback_iso_start) {
  63. int bytes = driver->playback_sample_bytes * 2 * driver->frames_per_cycle *
  64. driver->user_nperiods;
  65. iso = h->hwdep_pcm_shm->playback_iso_start;
  66. if (0 > iso)
  67. return 0; /* FIXME: return -1; */
  68. if (++iso >= ARRAY_SIZE(h->hwdep_pcm_shm->captured_iso))
  69. iso = 0;
  70. while((bytes -= h->hwdep_pcm_shm->captured_iso[iso].length) > 0)
  71. if (++iso >= ARRAY_SIZE(h->hwdep_pcm_shm->captured_iso))
  72. iso = 0;
  73. h->playback_iso_bytes_done = h->hwdep_pcm_shm->captured_iso[iso].length + bytes;
  74. #ifdef DBGHWDEP
  75. dbg_offset = sprintf(dbg_buffer, "first iso = %i %i@%p:%i\n",
  76. iso, h->hwdep_pcm_shm->captured_iso[iso].length,
  77. h->hwdep_pcm_shm->playback,
  78. h->hwdep_pcm_shm->captured_iso[iso].offset);
  79. #endif
  80. } else {
  81. iso = h->playback_iso_start;
  82. }
  83. #ifdef DBGHWDEP
  84. dbg_offset += sprintf(dbg_buffer + dbg_offset, "iso = %i(%i;%i); ", iso,
  85. h->hwdep_pcm_shm->captured_iso[iso].offset,
  86. h->hwdep_pcm_shm->captured_iso[iso].frame);
  87. #endif
  88. playback = h->hwdep_pcm_shm->playback +
  89. h->hwdep_pcm_shm->captured_iso[iso].offset +
  90. h->playback_iso_bytes_done;
  91. playback_iso_avail = (h->hwdep_pcm_shm->captured_iso[iso].length -
  92. h->playback_iso_bytes_done) /
  93. (driver->playback_sample_bytes * 2);
  94. if (*playback_avail >= playback_iso_avail) {
  95. *playback_avail = playback_iso_avail;
  96. if (++iso >= ARRAY_SIZE(h->hwdep_pcm_shm->captured_iso))
  97. iso = 0;
  98. h->playback_iso_bytes_done = 0;
  99. } else
  100. h->playback_iso_bytes_done =
  101. *playback_avail * (driver->playback_sample_bytes * 2);
  102. h->playback_iso_start = iso;
  103. for (chn = 0; chn < driver->playback_nchannels; chn++) {
  104. const snd_pcm_channel_area_t *a = &driver->playback_areas[chn];
  105. driver->playback_addr[chn] = playback + a->first / 8;
  106. }
  107. #ifdef DBGHWDEP
  108. if (dbg_offset < (sizeof(dbg_buffer) - 256))
  109. dbg_offset += sprintf(dbg_buffer + dbg_offset, "avail %li@%p\n", *playback_avail, driver->playback_addr[0]);
  110. else {
  111. printf(dbg_buffer);
  112. return -1;
  113. }
  114. #endif
  115. return 0;
  116. }
  117. static int
  118. usx2y_driver_get_channel_addresses_capture (alsa_driver_t *driver,
  119. snd_pcm_uframes_t *capture_avail)
  120. {
  121. channel_t chn;
  122. int iso;
  123. snd_pcm_uframes_t capture_iso_avail;
  124. int capture_offset;
  125. usx2y_t *h = (usx2y_t *) driver->hw->private;
  126. if (0 > h->capture_iso_start) {
  127. iso = h->hwdep_pcm_shm->capture_iso_start;
  128. if (0 > iso)
  129. return 0; /* FIXME: return -1; */
  130. h->capture_iso_bytes_done = 0;
  131. #ifdef DBGHWDEP
  132. dbg_offset = sprintf(dbg_buffer, "cfirst iso = %i %i@%p:%i\n",
  133. iso, h->hwdep_pcm_shm->captured_iso[iso].length,
  134. h->hwdep_pcm_shm->capture0x8,
  135. h->hwdep_pcm_shm->captured_iso[iso].offset);
  136. #endif
  137. } else {
  138. iso = h->capture_iso_start;
  139. }
  140. #ifdef DBGHWDEP
  141. dbg_offset += sprintf(dbg_buffer + dbg_offset, "ciso = %i(%i;%i); ", iso,
  142. h->hwdep_pcm_shm->captured_iso[iso].offset,
  143. h->hwdep_pcm_shm->captured_iso[iso].frame);
  144. #endif
  145. capture_offset =
  146. h->hwdep_pcm_shm->captured_iso[iso].offset +
  147. h->capture_iso_bytes_done;
  148. capture_iso_avail = (h->hwdep_pcm_shm->captured_iso[iso].length -
  149. h->capture_iso_bytes_done) /
  150. (driver->capture_sample_bytes * 2);
  151. if (*capture_avail >= capture_iso_avail) {
  152. *capture_avail = capture_iso_avail;
  153. if (++iso >= ARRAY_SIZE(h->hwdep_pcm_shm->captured_iso))
  154. iso = 0;
  155. h->capture_iso_bytes_done = 0;
  156. } else
  157. h->capture_iso_bytes_done =
  158. *capture_avail * (driver->capture_sample_bytes * 2);
  159. h->capture_iso_start = iso;
  160. for (chn = 0; chn < driver->capture_nchannels; chn++) {
  161. driver->capture_addr[chn] =
  162. (chn < 2 ? h->hwdep_pcm_shm->capture0x8 : h->hwdep_pcm_shm->capture0xA)
  163. + capture_offset +
  164. ((chn & 1) ? driver->capture_sample_bytes : 0);
  165. }
  166. #ifdef DBGHWDEP
  167. {
  168. int f = 0;
  169. unsigned *u = driver->capture_addr[0];
  170. static unsigned last;
  171. dbg_offset += sprintf(dbg_buffer + dbg_offset, "\nvon %6u bis %6u\n", last, u[0]);
  172. while (f < *capture_avail && dbg_offset < (sizeof(dbg_buffer) - 256)) {
  173. if (u[f] != last + 1)
  174. dbg_offset += sprintf(dbg_buffer + dbg_offset, "\nooops %6u %6u\n", last, u[f]);
  175. last = u[f++];
  176. }
  177. }
  178. if (dbg_offset < (sizeof(dbg_buffer) - 256))
  179. dbg_offset += sprintf(dbg_buffer + dbg_offset, "avail %li@%p\n", *capture_avail, driver->capture_addr[0]);
  180. else {
  181. printf(dbg_buffer);
  182. return -1;
  183. }
  184. #endif
  185. return 0;
  186. }
  187. static int
  188. usx2y_driver_start (alsa_driver_t *driver)
  189. {
  190. int err, i;
  191. snd_pcm_uframes_t poffset, pavail;
  192. usx2y_t *h = (usx2y_t *) driver->hw->private;
  193. for (i = 0; i < driver->capture_nchannels; i++)
  194. // US428 channels 3+4 are on a seperate 2 channel stream.
  195. // ALSA thinks its 1 stream with 4 channels.
  196. driver->capture_interleave_skip[i] = 2 * driver->capture_sample_bytes;
  197. driver->playback_interleave_skip[0] = 2 * driver->playback_sample_bytes;
  198. driver->playback_interleave_skip[1] = 2 * driver->playback_sample_bytes;
  199. driver->poll_last = 0;
  200. driver->poll_next = 0;
  201. if ((err = snd_pcm_prepare (driver->playback_handle)) < 0) {
  202. jack_error ("ALSA/USX2Y: prepare error for playback: %s", snd_strerror(err));
  203. return -1;
  204. }
  205. if (driver->playback_handle) {
  206. /* int i, j; */
  207. /* char buffer[2000]; */
  208. h->playback_iso_start =
  209. h->capture_iso_start = -1;
  210. snd_hwdep_poll_descriptors(h->hwdep_handle, &h->pfds, 1);
  211. h->hwdep_pcm_shm = (snd_usX2Y_hwdep_pcm_shm_t*)
  212. mmap(NULL, sizeof(snd_usX2Y_hwdep_pcm_shm_t),
  213. PROT_READ,
  214. MAP_SHARED, h->pfds.fd,
  215. 0);
  216. if (MAP_FAILED == h->hwdep_pcm_shm) {
  217. perror("ALSA/USX2Y: mmap");
  218. return -1;
  219. }
  220. if (mprotect(h->hwdep_pcm_shm->playback,
  221. sizeof(h->hwdep_pcm_shm->playback),
  222. PROT_READ|PROT_WRITE)) {
  223. perror("ALSA/USX2Y: mprotect");
  224. return -1;
  225. }
  226. memset(h->hwdep_pcm_shm->playback, 0, sizeof(h->hwdep_pcm_shm->playback));
  227. /* for (i = 0, j = 0; i < 2000;) { */
  228. /* j += sprintf(buffer + j, "%04hX ", */
  229. /* *(unsigned short*)(h->hwdep_pcm_shm->capture + i)); */
  230. /* if (((i += 2) % 32) == 0) { */
  231. /* jack_error(buffer); */
  232. /* j = 0; */
  233. /* } */
  234. /* } */
  235. }
  236. if (driver->hw_monitoring) {
  237. driver->hw->set_input_monitor_mask (driver->hw,
  238. driver->input_monitor_mask);
  239. }
  240. if (driver->playback_handle) {
  241. /* fill playback buffer with zeroes, and mark
  242. all fragments as having data.
  243. */
  244. pavail = snd_pcm_avail_update (driver->playback_handle);
  245. if (pavail != driver->frames_per_cycle * driver->playback_nperiods) {
  246. jack_error ("ALSA/USX2Y: full buffer not available at start");
  247. return -1;
  248. }
  249. if (snd_pcm_mmap_begin(
  250. driver->playback_handle,
  251. &driver->playback_areas,
  252. &poffset, &pavail) < 0) {
  253. return -1;
  254. }
  255. /* XXX this is cheating. ALSA offers no guarantee that
  256. we can access the entire buffer at any one time. It
  257. works on most hardware tested so far, however, buts
  258. its a liability in the long run. I think that
  259. alsa-lib may have a better function for doing this
  260. here, where the goal is to silence the entire
  261. buffer.
  262. */
  263. {
  264. /* snd_pcm_uframes_t frag, nframes = driver->buffer_frames; */
  265. /* while (nframes) { */
  266. /* frag = nframes; */
  267. /* if (usx2y_driver_get_channel_addresses_playback(driver, &frag) < 0) */
  268. /* return -1; */
  269. /* for (chn = 0; chn < driver->playback_nchannels; chn++) */
  270. /* alsa_driver_silence_on_channel (driver, chn, frag); */
  271. /* nframes -= frag; */
  272. /* } */
  273. }
  274. snd_pcm_mmap_commit (driver->playback_handle, poffset,
  275. driver->user_nperiods * driver->frames_per_cycle);
  276. if ((err = snd_pcm_start (driver->playback_handle)) < 0) {
  277. jack_error ("ALSA/USX2Y: could not start playback (%s)",
  278. snd_strerror (err));
  279. return -1;
  280. }
  281. }
  282. if (driver->hw_monitoring &&
  283. (driver->input_monitor_mask || driver->all_monitor_in)) {
  284. if (driver->all_monitor_in) {
  285. driver->hw->set_input_monitor_mask (driver->hw, ~0U);
  286. } else {
  287. driver->hw->set_input_monitor_mask (
  288. driver->hw, driver->input_monitor_mask);
  289. }
  290. }
  291. driver->playback_nfds = snd_pcm_poll_descriptors_count (driver->playback_handle);
  292. driver->capture_nfds = snd_pcm_poll_descriptors_count (driver->capture_handle);
  293. if (driver->pfd) {
  294. free (driver->pfd);
  295. }
  296. driver->pfd = (struct pollfd *)
  297. malloc (sizeof (struct pollfd) *
  298. (driver->playback_nfds + driver->capture_nfds + 2));
  299. return 0;
  300. }
  301. static int
  302. usx2y_driver_stop (alsa_driver_t *driver)
  303. {
  304. int err;
  305. JSList* node;
  306. int chn;
  307. usx2y_t *h = (usx2y_t *) driver->hw->private;
  308. /* silence all capture port buffers, because we might
  309. be entering offline mode.
  310. */
  311. for (chn = 0, node = driver->capture_ports; node;
  312. node = jack_slist_next (node), chn++) {
  313. jack_port_t* port;
  314. char* buf;
  315. jack_nframes_t nframes = driver->engine->control->buffer_size;
  316. port = (jack_port_t *) node->data;
  317. buf = jack_port_get_buffer (port, nframes);
  318. memset (buf, 0, sizeof (jack_default_audio_sample_t) * nframes);
  319. }
  320. if (driver->playback_handle) {
  321. if ((err = snd_pcm_drop (driver->playback_handle)) < 0) {
  322. jack_error ("ALSA/USX2Y: channel flush for playback "
  323. "failed (%s)", snd_strerror (err));
  324. return -1;
  325. }
  326. }
  327. if (driver->hw_monitoring) {
  328. driver->hw->set_input_monitor_mask (driver->hw, 0);
  329. }
  330. munmap(h->hwdep_pcm_shm, sizeof(snd_usX2Y_hwdep_pcm_shm_t));
  331. return 0;
  332. }
  333. static int
  334. usx2y_driver_null_cycle (alsa_driver_t* driver, jack_nframes_t nframes)
  335. {
  336. jack_nframes_t nf;
  337. snd_pcm_uframes_t offset;
  338. snd_pcm_uframes_t contiguous, contiguous_;
  339. int chn;
  340. VERBOSE(driver->engine,
  341. "usx2y_driver_null_cycle (%p, %i)\n", driver, nframes);
  342. if (driver->capture_handle) {
  343. nf = nframes;
  344. offset = 0;
  345. while (nf) {
  346. contiguous = (nf > driver->frames_per_cycle) ?
  347. driver->frames_per_cycle : nf;
  348. if (snd_pcm_mmap_begin (
  349. driver->capture_handle,
  350. &driver->capture_areas,
  351. (snd_pcm_uframes_t *) &offset,
  352. (snd_pcm_uframes_t *) &contiguous)) {
  353. return -1;
  354. }
  355. contiguous_ = contiguous;
  356. while (contiguous_) {
  357. snd_pcm_uframes_t frag = contiguous_;
  358. if (usx2y_driver_get_channel_addresses_capture(driver, &frag) < 0)
  359. return -1;
  360. contiguous_ -= frag;
  361. }
  362. if (snd_pcm_mmap_commit (driver->capture_handle,
  363. offset, contiguous) < 0) {
  364. return -1;
  365. }
  366. nf -= contiguous;
  367. }
  368. }
  369. if (driver->playback_handle) {
  370. nf = nframes;
  371. offset = 0;
  372. while (nf) {
  373. contiguous = (nf > driver->frames_per_cycle) ?
  374. driver->frames_per_cycle : nf;
  375. if (snd_pcm_mmap_begin (
  376. driver->playback_handle,
  377. &driver->playback_areas,
  378. (snd_pcm_uframes_t *) &offset,
  379. (snd_pcm_uframes_t *) &contiguous)) {
  380. return -1;
  381. }
  382. {
  383. snd_pcm_uframes_t frag, nframes = contiguous;
  384. while (nframes) {
  385. frag = nframes;
  386. if (usx2y_driver_get_channel_addresses_playback(driver, &frag) < 0)
  387. return -1;
  388. for (chn = 0; chn < driver->playback_nchannels; chn++)
  389. alsa_driver_silence_on_channel (driver, chn, frag);
  390. nframes -= frag;
  391. }
  392. }
  393. if (snd_pcm_mmap_commit (driver->playback_handle,
  394. offset, contiguous) < 0) {
  395. return -1;
  396. }
  397. nf -= contiguous;
  398. }
  399. }
  400. return 0;
  401. }
  402. static int
  403. usx2y_driver_read (alsa_driver_t *driver, jack_nframes_t nframes)
  404. {
  405. snd_pcm_uframes_t contiguous;
  406. snd_pcm_sframes_t nread;
  407. snd_pcm_uframes_t offset;
  408. jack_default_audio_sample_t* buf[4];
  409. channel_t chn;
  410. JSList *node;
  411. jack_port_t* port;
  412. int err;
  413. snd_pcm_uframes_t nframes_ = nframes;
  414. if (!driver->capture_handle || driver->engine->freewheeling) {
  415. return 0;
  416. }
  417. nread = 0;
  418. if (snd_pcm_mmap_begin (driver->capture_handle,
  419. &driver->capture_areas,
  420. &offset, &nframes_) < 0) {
  421. jack_error ("ALSA/USX2Y: %s: mmap areas info error",
  422. driver->alsa_name_capture);
  423. return -1;
  424. }
  425. for (chn = 0, node = driver->capture_ports;
  426. node; node = jack_slist_next (node), chn++) {
  427. port = (jack_port_t *) node->data;
  428. if (!jack_port_connected (port)) {
  429. continue;
  430. }
  431. buf[chn] = jack_port_get_buffer (port, nframes_);
  432. }
  433. while (nframes) {
  434. contiguous = nframes;
  435. if (usx2y_driver_get_channel_addresses_capture (
  436. driver, &contiguous) < 0) {
  437. return -1;
  438. }
  439. for (chn = 0, node = driver->capture_ports;
  440. node; node = jack_slist_next (node), chn++) {
  441. port = (jack_port_t *) node->data;
  442. if (!jack_port_connected (port)) {
  443. /* no-copy optimization */
  444. continue;
  445. }
  446. alsa_driver_read_from_channel (driver, chn,
  447. buf[chn] + nread,
  448. contiguous);
  449. /* sample_move_dS_s24(buf[chn] + nread, */
  450. /* driver->capture_addr[chn], */
  451. /* contiguous, */
  452. /* driver->capture_interleave_skip); */
  453. }
  454. nread += contiguous;
  455. nframes -= contiguous;
  456. }
  457. if ((err = snd_pcm_mmap_commit (driver->capture_handle,
  458. offset, nframes_)) < 0) {
  459. jack_error ("ALSA/USX2Y: could not complete read of %"
  460. PRIu32 " frames: error = %d", nframes_, err);
  461. return -1;
  462. }
  463. return 0;
  464. }
  465. static int
  466. usx2y_driver_write (alsa_driver_t* driver, jack_nframes_t nframes)
  467. {
  468. channel_t chn;
  469. JSList *node;
  470. jack_default_audio_sample_t* buf[2];
  471. snd_pcm_sframes_t nwritten;
  472. snd_pcm_uframes_t contiguous;
  473. snd_pcm_uframes_t offset;
  474. jack_port_t *port;
  475. int err;
  476. snd_pcm_uframes_t nframes_ = nframes;
  477. driver->process_count++;
  478. if (!driver->playback_handle || driver->engine->freewheeling) {
  479. return 0;
  480. }
  481. nwritten = 0;
  482. /* check current input monitor request status */
  483. driver->input_monitor_mask = 0;
  484. for (chn = 0, node = driver->capture_ports; node;
  485. node = jack_slist_next (node), chn++) {
  486. if (((jack_port_t *) node->data)->shared->monitor_requests) {
  487. driver->input_monitor_mask |= (1<<chn);
  488. }
  489. }
  490. if (driver->hw_monitoring) {
  491. if ((driver->hw->input_monitor_mask
  492. != driver->input_monitor_mask)
  493. && !driver->all_monitor_in) {
  494. driver->hw->set_input_monitor_mask (
  495. driver->hw, driver->input_monitor_mask);
  496. }
  497. }
  498. if (snd_pcm_mmap_begin(driver->playback_handle,
  499. &driver->playback_areas,
  500. &offset, &nframes_) < 0) {
  501. jack_error ("ALSA/USX2Y: %s: mmap areas info error",
  502. driver->alsa_name_capture);
  503. return -1;
  504. }
  505. for (chn = 0, node = driver->playback_ports;
  506. node; node = jack_slist_next (node), chn++) {
  507. port = (jack_port_t *) node->data;
  508. buf[chn] = jack_port_get_buffer (port, nframes_);
  509. }
  510. while (nframes) {
  511. contiguous = nframes;
  512. if (usx2y_driver_get_channel_addresses_playback (
  513. driver, &contiguous) < 0) {
  514. return -1;
  515. }
  516. for (chn = 0, node = driver->playback_ports;
  517. node; node = jack_slist_next (node), chn++) {
  518. port = (jack_port_t *) node->data;
  519. alsa_driver_write_to_channel (driver, chn,
  520. buf[chn] + nwritten,
  521. contiguous);
  522. }
  523. nwritten += contiguous;
  524. nframes -= contiguous;
  525. }
  526. if ((err = snd_pcm_mmap_commit (driver->playback_handle,
  527. offset, nframes_)) < 0) {
  528. jack_error ("ALSA/USX2Y: could not complete playback of %"
  529. PRIu32 " frames: error = %d", nframes_, err);
  530. if (err != EPIPE && err != ESTRPIPE)
  531. return -1;
  532. }
  533. return 0;
  534. }
  535. static void
  536. usx2y_driver_setup (alsa_driver_t *driver)
  537. {
  538. driver->nt_start = (JackDriverNTStartFunction) usx2y_driver_start;
  539. driver->nt_stop = (JackDriverNTStopFunction) usx2y_driver_stop;
  540. driver->read = (JackDriverReadFunction) usx2y_driver_read;
  541. driver->write = (JackDriverReadFunction) usx2y_driver_write;
  542. driver->null_cycle =
  543. (JackDriverNullCycleFunction) usx2y_driver_null_cycle;
  544. }
  545. jack_hardware_t *
  546. jack_alsa_usx2y_hw_new (alsa_driver_t *driver)
  547. {
  548. jack_hardware_t *hw;
  549. usx2y_t *h;
  550. int hwdep_cardno;
  551. int hwdep_devno;
  552. char *hwdep_colon;
  553. char hwdep_name[9];
  554. snd_hwdep_t *hwdep_handle;
  555. hw = (jack_hardware_t *) malloc (sizeof (jack_hardware_t));
  556. hw->capabilities = 0;
  557. hw->input_monitor_mask = 0;
  558. hw->private = 0;
  559. hw->set_input_monitor_mask = usx2y_set_input_monitor_mask;
  560. hw->change_sample_clock = usx2y_change_sample_clock;
  561. hw->release = usx2y_release;
  562. /* Derive the special USB US-X2Y hwdep pcm device name from
  563. * the playback one, thus allowing the use of the "rawusb"
  564. * experimental stuff if, and only if, the "hw:n,2" device
  565. * name is specified. Otherwise, fallback to generic backend.
  566. */
  567. hwdep_handle = NULL;
  568. hwdep_cardno = hwdep_devno = 0;
  569. if ((hwdep_colon = strrchr(driver->alsa_name_playback, ':')) != NULL)
  570. sscanf(hwdep_colon, ":%d,%d", &hwdep_cardno, &hwdep_devno);
  571. if (hwdep_devno == 2) {
  572. snprintf(hwdep_name, sizeof(hwdep_name), "hw:%d,1", hwdep_cardno);
  573. if (snd_hwdep_open (&hwdep_handle, hwdep_name, O_RDWR) < 0) {
  574. jack_error ("ALSA/USX2Y: Cannot open hwdep device \"%s\"", hwdep_name);
  575. } else {
  576. /* Allocate specific USX2Y hwdep pcm struct. */
  577. h = (usx2y_t *) malloc (sizeof (usx2y_t));
  578. h->driver = driver;
  579. h->hwdep_handle = hwdep_handle;
  580. hw->private = h;
  581. /* Set our own operational function pointers. */
  582. usx2y_driver_setup(driver);
  583. printf("ALSA/USX2Y: EXPERIMENTAL hwdep pcm device %s"
  584. " (aka \"rawusb\")\n", driver->alsa_name_playback);
  585. }
  586. }
  587. return hw;
  588. }