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.

685 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;
  191. snd_pcm_uframes_t poffset, pavail;
  192. usx2y_t *h = (usx2y_t *) driver->hw->private;
  193. if (driver->capture_nchannels == 4) {
  194. // US428 channels 3+4 are on a seperate 2 channel stream.
  195. // ALSA thinks its 1 stream with 4 channels, so we have to hack here.
  196. driver->capture_interleave_skip = 2 * driver->capture_sample_bytes;
  197. }
  198. driver->poll_last = 0;
  199. driver->poll_next = 0;
  200. if ((err = snd_pcm_prepare (driver->playback_handle)) < 0) {
  201. jack_error ("ALSA/USX2Y: prepare error for playback: %s", snd_strerror(err));
  202. return -1;
  203. }
  204. if (driver->playback_handle) {
  205. /* int i, j; */
  206. /* char buffer[2000]; */
  207. h->playback_iso_start =
  208. h->capture_iso_start = -1;
  209. snd_hwdep_poll_descriptors(h->hwdep_handle, &h->pfds, 1);
  210. h->hwdep_pcm_shm = (snd_usX2Y_hwdep_pcm_shm_t*)
  211. mmap(NULL, sizeof(snd_usX2Y_hwdep_pcm_shm_t),
  212. PROT_READ,
  213. MAP_SHARED, h->pfds.fd,
  214. 0);
  215. if (MAP_FAILED == h->hwdep_pcm_shm) {
  216. perror("ALSA/USX2Y: mmap");
  217. return -1;
  218. }
  219. if (mprotect(h->hwdep_pcm_shm->playback,
  220. sizeof(h->hwdep_pcm_shm->playback),
  221. PROT_READ|PROT_WRITE)) {
  222. perror("ALSA/USX2Y: mprotect");
  223. return -1;
  224. }
  225. memset(h->hwdep_pcm_shm->playback, 0, sizeof(h->hwdep_pcm_shm->playback));
  226. /* for (i = 0, j = 0; i < 2000;) { */
  227. /* j += sprintf(buffer + j, "%04hX ", */
  228. /* *(unsigned short*)(h->hwdep_pcm_shm->capture + i)); */
  229. /* if (((i += 2) % 32) == 0) { */
  230. /* jack_error(buffer); */
  231. /* j = 0; */
  232. /* } */
  233. /* } */
  234. }
  235. if (driver->hw_monitoring) {
  236. driver->hw->set_input_monitor_mask (driver->hw,
  237. driver->input_monitor_mask);
  238. }
  239. if (driver->playback_handle) {
  240. /* fill playback buffer with zeroes, and mark
  241. all fragments as having data.
  242. */
  243. pavail = snd_pcm_avail_update (driver->playback_handle);
  244. if (pavail != driver->frames_per_cycle * driver->playback_nperiods) {
  245. jack_error ("ALSA/USX2Y: full buffer not available at start");
  246. return -1;
  247. }
  248. if (snd_pcm_mmap_begin(
  249. driver->playback_handle,
  250. &driver->playback_areas,
  251. &poffset, &pavail) < 0) {
  252. return -1;
  253. }
  254. /* XXX this is cheating. ALSA offers no guarantee that
  255. we can access the entire buffer at any one time. It
  256. works on most hardware tested so far, however, buts
  257. its a liability in the long run. I think that
  258. alsa-lib may have a better function for doing this
  259. here, where the goal is to silence the entire
  260. buffer.
  261. */
  262. {
  263. /* snd_pcm_uframes_t frag, nframes = driver->buffer_frames; */
  264. /* while (nframes) { */
  265. /* frag = nframes; */
  266. /* if (usx2y_driver_get_channel_addresses_playback(driver, &frag) < 0) */
  267. /* return -1; */
  268. /* for (chn = 0; chn < driver->playback_nchannels; chn++) */
  269. /* alsa_driver_silence_on_channel (driver, chn, frag); */
  270. /* nframes -= frag; */
  271. /* } */
  272. }
  273. snd_pcm_mmap_commit (driver->playback_handle, poffset,
  274. driver->user_nperiods * driver->frames_per_cycle);
  275. if ((err = snd_pcm_start (driver->playback_handle)) < 0) {
  276. jack_error ("ALSA/USX2Y: could not start playback (%s)",
  277. snd_strerror (err));
  278. return -1;
  279. }
  280. }
  281. if (driver->hw_monitoring &&
  282. (driver->input_monitor_mask || driver->all_monitor_in)) {
  283. if (driver->all_monitor_in) {
  284. driver->hw->set_input_monitor_mask (driver->hw, ~0U);
  285. } else {
  286. driver->hw->set_input_monitor_mask (
  287. driver->hw, driver->input_monitor_mask);
  288. }
  289. }
  290. driver->playback_nfds = snd_pcm_poll_descriptors_count (driver->playback_handle);
  291. driver->capture_nfds = snd_pcm_poll_descriptors_count (driver->capture_handle);
  292. if (driver->pfd) {
  293. free (driver->pfd);
  294. }
  295. driver->pfd = (struct pollfd *)
  296. malloc (sizeof (struct pollfd) *
  297. (driver->playback_nfds + driver->capture_nfds + 2));
  298. return 0;
  299. }
  300. static int
  301. usx2y_driver_stop (alsa_driver_t *driver)
  302. {
  303. int err;
  304. JSList* node;
  305. int chn;
  306. usx2y_t *h = (usx2y_t *) driver->hw->private;
  307. /* silence all capture port buffers, because we might
  308. be entering offline mode.
  309. */
  310. for (chn = 0, node = driver->capture_ports; node;
  311. node = jack_slist_next (node), chn++) {
  312. jack_port_t* port;
  313. char* buf;
  314. jack_nframes_t nframes = driver->engine->control->buffer_size;
  315. port = (jack_port_t *) node->data;
  316. buf = jack_port_get_buffer (port, nframes);
  317. memset (buf, 0, sizeof (jack_default_audio_sample_t) * nframes);
  318. }
  319. if (driver->playback_handle) {
  320. if ((err = snd_pcm_drop (driver->playback_handle)) < 0) {
  321. jack_error ("ALSA/USX2Y: channel flush for playback "
  322. "failed (%s)", snd_strerror (err));
  323. return -1;
  324. }
  325. }
  326. if (driver->hw_monitoring) {
  327. driver->hw->set_input_monitor_mask (driver->hw, 0);
  328. }
  329. munmap(h->hwdep_pcm_shm, sizeof(snd_usX2Y_hwdep_pcm_shm_t));
  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)\n", 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. nread = 0;
  417. if (snd_pcm_mmap_begin (driver->capture_handle,
  418. &driver->capture_areas,
  419. &offset, &nframes_) < 0) {
  420. jack_error ("ALSA/USX2Y: %s: mmap areas info error",
  421. driver->alsa_name_capture);
  422. return -1;
  423. }
  424. for (chn = 0, node = driver->capture_ports;
  425. node; node = jack_slist_next (node), chn++) {
  426. port = (jack_port_t *) node->data;
  427. if (!jack_port_connected (port)) {
  428. continue;
  429. }
  430. buf[chn] = jack_port_get_buffer (port, nframes_);
  431. }
  432. while (nframes) {
  433. contiguous = nframes;
  434. if (usx2y_driver_get_channel_addresses_capture (
  435. driver, &contiguous) < 0) {
  436. return -1;
  437. }
  438. for (chn = 0, node = driver->capture_ports;
  439. node; node = jack_slist_next (node), chn++) {
  440. port = (jack_port_t *) node->data;
  441. if (!jack_port_connected (port)) {
  442. /* no-copy optimization */
  443. continue;
  444. }
  445. alsa_driver_read_from_channel (driver, chn,
  446. buf[chn] + nread,
  447. contiguous);
  448. /* sample_move_dS_s24(buf[chn] + nread, */
  449. /* driver->capture_addr[chn], */
  450. /* contiguous, */
  451. /* driver->capture_interleave_skip); */
  452. }
  453. nread += contiguous;
  454. nframes -= contiguous;
  455. }
  456. if ((err = snd_pcm_mmap_commit (driver->capture_handle,
  457. offset, nframes_)) < 0) {
  458. jack_error ("ALSA/USX2Y: could not complete read of %"
  459. PRIu32 " frames: error = %d", nframes_, err);
  460. return -1;
  461. }
  462. return 0;
  463. }
  464. static int
  465. usx2y_driver_write (alsa_driver_t* driver, jack_nframes_t nframes)
  466. {
  467. channel_t chn;
  468. JSList *node;
  469. jack_default_audio_sample_t* buf[2];
  470. snd_pcm_sframes_t nwritten;
  471. snd_pcm_uframes_t contiguous;
  472. snd_pcm_uframes_t offset;
  473. jack_port_t *port;
  474. int err;
  475. snd_pcm_uframes_t nframes_ = nframes;
  476. driver->process_count++;
  477. if (!driver->playback_handle || driver->engine->freewheeling) {
  478. return 0;
  479. }
  480. nwritten = 0;
  481. /* check current input monitor request status */
  482. driver->input_monitor_mask = 0;
  483. for (chn = 0, node = driver->capture_ports; node;
  484. node = jack_slist_next (node), chn++) {
  485. if (((jack_port_t *) node->data)->shared->monitor_requests) {
  486. driver->input_monitor_mask |= (1<<chn);
  487. }
  488. }
  489. if (driver->hw_monitoring) {
  490. if ((driver->hw->input_monitor_mask
  491. != driver->input_monitor_mask)
  492. && !driver->all_monitor_in) {
  493. driver->hw->set_input_monitor_mask (
  494. driver->hw, driver->input_monitor_mask);
  495. }
  496. }
  497. if (snd_pcm_mmap_begin(driver->playback_handle,
  498. &driver->playback_areas,
  499. &offset, &nframes_) < 0) {
  500. jack_error ("ALSA/USX2Y: %s: mmap areas info error",
  501. driver->alsa_name_capture);
  502. return -1;
  503. }
  504. for (chn = 0, node = driver->playback_ports;
  505. node; node = jack_slist_next (node), chn++) {
  506. port = (jack_port_t *) node->data;
  507. buf[chn] = jack_port_get_buffer (port, nframes_);
  508. }
  509. while (nframes) {
  510. contiguous = nframes;
  511. if (usx2y_driver_get_channel_addresses_playback (
  512. driver, &contiguous) < 0) {
  513. return -1;
  514. }
  515. for (chn = 0, node = driver->playback_ports;
  516. node; node = jack_slist_next (node), chn++) {
  517. port = (jack_port_t *) node->data;
  518. alsa_driver_write_to_channel (driver, chn,
  519. buf[chn] + nwritten,
  520. contiguous);
  521. }
  522. nwritten += contiguous;
  523. nframes -= contiguous;
  524. }
  525. if ((err = snd_pcm_mmap_commit (driver->playback_handle,
  526. offset, nframes_)) < 0) {
  527. jack_error ("ALSA/USX2Y: could not complete playback of %"
  528. PRIu32 " frames: error = %d", nframes_, err);
  529. if (err != EPIPE && err != ESTRPIPE)
  530. return -1;
  531. }
  532. return 0;
  533. }
  534. static void
  535. usx2y_driver_setup (alsa_driver_t *driver)
  536. {
  537. driver->nt_start = (JackDriverNTStartFunction) usx2y_driver_start;
  538. driver->nt_stop = (JackDriverNTStopFunction) usx2y_driver_stop;
  539. driver->read = (JackDriverReadFunction) usx2y_driver_read;
  540. driver->write = (JackDriverReadFunction) usx2y_driver_write;
  541. driver->null_cycle =
  542. (JackDriverNullCycleFunction) usx2y_driver_null_cycle;
  543. }
  544. jack_hardware_t *
  545. jack_alsa_usx2y_hw_new (alsa_driver_t *driver)
  546. {
  547. jack_hardware_t *hw;
  548. usx2y_t *h;
  549. int hwdep_cardno;
  550. int hwdep_devno;
  551. char *hwdep_colon;
  552. char hwdep_name[9];
  553. snd_hwdep_t *hwdep_handle;
  554. hw = (jack_hardware_t *) malloc (sizeof (jack_hardware_t));
  555. hw->capabilities = 0;
  556. hw->input_monitor_mask = 0;
  557. hw->private = 0;
  558. hw->set_input_monitor_mask = usx2y_set_input_monitor_mask;
  559. hw->change_sample_clock = usx2y_change_sample_clock;
  560. hw->release = usx2y_release;
  561. /* Derive the special USB US-X2Y hwdep pcm device name from
  562. * the playback one, thus allowing the use of the "rawusb"
  563. * experimental stuff if, and only if, the "hw:n,2" device
  564. * name is specified. Otherwise, fallback to generic backend.
  565. */
  566. hwdep_handle = NULL;
  567. hwdep_cardno = hwdep_devno = 0;
  568. if ((hwdep_colon = strrchr(driver->alsa_name_playback, ':')) != NULL)
  569. sscanf(hwdep_colon, ":%d,%d", &hwdep_cardno, &hwdep_devno);
  570. if (hwdep_devno == 2) {
  571. snprintf(hwdep_name, sizeof(hwdep_name), "hw:%d,1", hwdep_cardno);
  572. if (snd_hwdep_open (&hwdep_handle, hwdep_name, O_RDWR) < 0) {
  573. jack_error ("ALSA/USX2Y: Cannot open hwdep device \"%s\"", hwdep_name);
  574. } else {
  575. /* Allocate specific USX2Y hwdep pcm struct. */
  576. h = (usx2y_t *) malloc (sizeof (usx2y_t));
  577. h->driver = driver;
  578. h->hwdep_handle = hwdep_handle;
  579. hw->private = h;
  580. /* Set our own operational function pointers. */
  581. usx2y_driver_setup(driver);
  582. printf("ALSA/USX2Y: EXPERIMENTAL hwdep pcm device %s"
  583. " (aka \"rawusb\")\n", driver->alsa_name_playback);
  584. }
  585. }
  586. return hw;
  587. }