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.

693 lines
18KB

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