2 Copyright (C) 2001 Paul Davis
3 Copyright (C) 2005 Karsten Wiese, Rui Nuno Capela
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "alsa_driver.h"
27 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
34 char dbg_buffer
[8096];
37 int usx2y_set_input_monitor_mask (jack_hardware_t
*hw
, unsigned long mask
)
43 int usx2y_change_sample_clock (jack_hardware_t
*hw
, SampleClockMode mode
)
49 usx2y_release (jack_hardware_t
*hw
)
51 usx2y_t
*h
= (usx2y_t
*) hw
->private_hw
;
57 snd_hwdep_close(h
->hwdep_handle
);
63 usx2y_driver_get_channel_addresses_playback (alsa_driver_t
*driver
,
64 snd_pcm_uframes_t
*playback_avail
)
68 snd_pcm_uframes_t playback_iso_avail
;
71 usx2y_t
*h
= (usx2y_t
*) driver
->hw
->private_hw
;
73 if (0 > h
->playback_iso_start
) {
74 int bytes
= driver
->playback_sample_bytes
* 2 * driver
->frames_per_cycle
*
75 driver
->user_nperiods
;
76 iso
= h
->hwdep_pcm_shm
->playback_iso_start
;
78 return 0; /* FIXME: return -1; */
79 if (++iso
>= ARRAY_SIZE(h
->hwdep_pcm_shm
->captured_iso
))
81 while((bytes
-= h
->hwdep_pcm_shm
->captured_iso
[iso
].length
) > 0)
82 if (++iso
>= ARRAY_SIZE(h
->hwdep_pcm_shm
->captured_iso
))
84 h
->playback_iso_bytes_done
= h
->hwdep_pcm_shm
->captured_iso
[iso
].length
+ bytes
;
86 dbg_offset
= sprintf(dbg_buffer
, "first iso = %i %i@%p:%i\n",
87 iso
, h
->hwdep_pcm_shm
->captured_iso
[iso
].length
,
88 h
->hwdep_pcm_shm
->playback
,
89 h
->hwdep_pcm_shm
->captured_iso
[iso
].offset
);
92 iso
= h
->playback_iso_start
;
95 dbg_offset
+= sprintf(dbg_buffer
+ dbg_offset
, "iso = %i(%i;%i); ", iso
,
96 h
->hwdep_pcm_shm
->captured_iso
[iso
].offset
,
97 h
->hwdep_pcm_shm
->captured_iso
[iso
].frame
);
99 playback
= h
->hwdep_pcm_shm
->playback
+
100 h
->hwdep_pcm_shm
->captured_iso
[iso
].offset
+
101 h
->playback_iso_bytes_done
;
102 playback_iso_avail
= (h
->hwdep_pcm_shm
->captured_iso
[iso
].length
-
103 h
->playback_iso_bytes_done
) /
104 (driver
->playback_sample_bytes
* 2);
105 if (*playback_avail
>= playback_iso_avail
) {
106 *playback_avail
= playback_iso_avail
;
107 if (++iso
>= ARRAY_SIZE(h
->hwdep_pcm_shm
->captured_iso
))
109 h
->playback_iso_bytes_done
= 0;
111 h
->playback_iso_bytes_done
=
112 *playback_avail
* (driver
->playback_sample_bytes
* 2);
113 h
->playback_iso_start
= iso
;
114 for (chn
= 0; chn
< driver
->playback_nchannels
; chn
++) {
115 const snd_pcm_channel_area_t
*a
= &driver
->playback_areas
[chn
];
116 driver
->playback_addr
[chn
] = playback
+ a
->first
/ 8;
119 if (dbg_offset
< (sizeof(dbg_buffer
) - 256))
120 dbg_offset
+= sprintf(dbg_buffer
+ dbg_offset
, "avail %li@%p\n", *playback_avail
, driver
->playback_addr
[0]);
131 usx2y_driver_get_channel_addresses_capture (alsa_driver_t
*driver
,
132 snd_pcm_uframes_t
*capture_avail
)
136 snd_pcm_uframes_t capture_iso_avail
;
139 usx2y_t
*h
= (usx2y_t
*) driver
->hw
->private_hw
;
141 if (0 > h
->capture_iso_start
) {
142 iso
= h
->hwdep_pcm_shm
->capture_iso_start
;
144 return 0; /* FIXME: return -1; */
145 h
->capture_iso_bytes_done
= 0;
147 dbg_offset
= sprintf(dbg_buffer
, "cfirst iso = %i %i@%p:%i\n",
148 iso
, h
->hwdep_pcm_shm
->captured_iso
[iso
].length
,
149 h
->hwdep_pcm_shm
->capture0x8
,
150 h
->hwdep_pcm_shm
->captured_iso
[iso
].offset
);
153 iso
= h
->capture_iso_start
;
156 dbg_offset
+= sprintf(dbg_buffer
+ dbg_offset
, "ciso = %i(%i;%i); ", iso
,
157 h
->hwdep_pcm_shm
->captured_iso
[iso
].offset
,
158 h
->hwdep_pcm_shm
->captured_iso
[iso
].frame
);
161 h
->hwdep_pcm_shm
->captured_iso
[iso
].offset
+
162 h
->capture_iso_bytes_done
;
163 capture_iso_avail
= (h
->hwdep_pcm_shm
->captured_iso
[iso
].length
-
164 h
->capture_iso_bytes_done
) /
165 (driver
->capture_sample_bytes
* 2);
166 if (*capture_avail
>= capture_iso_avail
) {
167 *capture_avail
= capture_iso_avail
;
168 if (++iso
>= ARRAY_SIZE(h
->hwdep_pcm_shm
->captured_iso
))
170 h
->capture_iso_bytes_done
= 0;
172 h
->capture_iso_bytes_done
=
173 *capture_avail
* (driver
->capture_sample_bytes
* 2);
174 h
->capture_iso_start
= iso
;
175 for (chn
= 0; chn
< driver
->capture_nchannels
; chn
++) {
176 driver
->capture_addr
[chn
] =
177 (chn
< 2 ? h
->hwdep_pcm_shm
->capture0x8
: h
->hwdep_pcm_shm
->capture0xA
)
179 ((chn
& 1) ? driver
->capture_sample_bytes
: 0);
184 unsigned *u
= driver
->capture_addr
[0];
185 static unsigned last
;
186 dbg_offset
+= sprintf(dbg_buffer
+ dbg_offset
, "\nvon %6u bis %6u\n", last
, u
[0]);
187 while (f
< *capture_avail
&& dbg_offset
< (sizeof(dbg_buffer
) - 256)) {
188 if (u
[f
] != last
+ 1)
189 dbg_offset
+= sprintf(dbg_buffer
+ dbg_offset
, "\nooops %6u %6u\n", last
, u
[f
]);
193 if (dbg_offset
< (sizeof(dbg_buffer
) - 256))
194 dbg_offset
+= sprintf(dbg_buffer
+ dbg_offset
, "avail %li@%p\n", *capture_avail
, driver
->capture_addr
[0]);
205 usx2y_driver_start (alsa_driver_t
*driver
)
208 snd_pcm_uframes_t poffset
, pavail
;
210 usx2y_t
*h
= (usx2y_t
*) driver
->hw
->private_hw
;
212 for (i
= 0; i
< driver
->capture_nchannels
; i
++)
213 // US428 channels 3+4 are on a separate 2 channel stream.
214 // ALSA thinks its 1 stream with 4 channels.
215 driver
->capture_interleave_skip
[i
] = 2 * driver
->capture_sample_bytes
;
218 driver
->playback_interleave_skip
[0] = 2 * driver
->playback_sample_bytes
;
219 driver
->playback_interleave_skip
[1] = 2 * driver
->playback_sample_bytes
;
221 driver
->poll_last
= 0;
222 driver
->poll_next
= 0;
224 if ((err
= snd_pcm_prepare (driver
->playback_handle
)) < 0) {
225 jack_error ("ALSA/USX2Y: prepare error for playback: %s", snd_strerror(err
));
229 if (driver
->midi
&& !driver
->xrun_recovery
)
230 (driver
->midi
->start
)(driver
->midi
);
232 if (driver
->playback_handle
) {
234 /* char buffer[2000]; */
235 h
->playback_iso_start
=
236 h
->capture_iso_start
= -1;
237 snd_hwdep_poll_descriptors(h
->hwdep_handle
, &h
->pfds
, 1);
238 h
->hwdep_pcm_shm
= (snd_usX2Y_hwdep_pcm_shm_t
*)
239 mmap(NULL
, sizeof(snd_usX2Y_hwdep_pcm_shm_t
),
241 MAP_SHARED
, h
->pfds
.fd
,
243 if (MAP_FAILED
== h
->hwdep_pcm_shm
) {
244 perror("ALSA/USX2Y: mmap");
247 if (mprotect(h
->hwdep_pcm_shm
->playback
,
248 sizeof(h
->hwdep_pcm_shm
->playback
),
249 PROT_READ
|PROT_WRITE
)) {
250 perror("ALSA/USX2Y: mprotect");
253 memset(h
->hwdep_pcm_shm
->playback
, 0, sizeof(h
->hwdep_pcm_shm
->playback
));
254 /* for (i = 0, j = 0; i < 2000;) { */
255 /* j += sprintf(buffer + j, "%04hX ", */
256 /* *(unsigned short*)(h->hwdep_pcm_shm->capture + i)); */
257 /* if (((i += 2) % 32) == 0) { */
258 /* jack_error(buffer); */
264 if (driver
->hw_monitoring
) {
265 driver
->hw
->set_input_monitor_mask (driver
->hw
,
266 driver
->input_monitor_mask
);
269 if (driver
->playback_handle
) {
270 /* fill playback buffer with zeroes, and mark
271 all fragments as having data.
274 pavail
= snd_pcm_avail_update (driver
->playback_handle
);
276 if (pavail
!= driver
->frames_per_cycle
* driver
->playback_nperiods
) {
277 jack_error ("ALSA/USX2Y: full buffer not available at start");
281 if (snd_pcm_mmap_begin(
282 driver
->playback_handle
,
283 &driver
->playback_areas
,
284 &poffset
, &pavail
) < 0) {
288 /* XXX this is cheating. ALSA offers no guarantee that
289 we can access the entire buffer at any one time. It
290 works on most hardware tested so far, however, buts
291 its a liability in the long run. I think that
292 alsa-lib may have a better function for doing this
293 here, where the goal is to silence the entire
297 /* snd_pcm_uframes_t frag, nframes = driver->buffer_frames; */
298 /* while (nframes) { */
299 /* frag = nframes; */
300 /* if (usx2y_driver_get_channel_addresses_playback(driver, &frag) < 0) */
303 /* for (chn = 0; chn < driver->playback_nchannels; chn++) */
304 /* alsa_driver_silence_on_channel (driver, chn, frag); */
305 /* nframes -= frag; */
309 snd_pcm_mmap_commit (driver
->playback_handle
, poffset
,
310 driver
->user_nperiods
* driver
->frames_per_cycle
);
312 if ((err
= snd_pcm_start (driver
->playback_handle
)) < 0) {
313 jack_error ("ALSA/USX2Y: could not start playback (%s)",
319 if (driver
->hw_monitoring
&&
320 (driver
->input_monitor_mask
|| driver
->all_monitor_in
)) {
321 if (driver
->all_monitor_in
) {
322 driver
->hw
->set_input_monitor_mask (driver
->hw
, ~0U);
324 driver
->hw
->set_input_monitor_mask (
325 driver
->hw
, driver
->input_monitor_mask
);
329 driver
->playback_nfds
= snd_pcm_poll_descriptors_count (driver
->playback_handle
);
330 driver
->capture_nfds
= snd_pcm_poll_descriptors_count (driver
->capture_handle
);
336 driver
->pfd
= (struct pollfd
*)
337 malloc (sizeof (struct pollfd
) *
338 (driver
->playback_nfds
+ driver
->capture_nfds
+ 2));
344 usx2y_driver_stop (alsa_driver_t
*driver
)
350 usx2y_t
*h
= (usx2y_t
*) driver
->hw
->private_hw
;
352 /* silence all capture port buffers, because we might
353 be entering offline mode.
356 for (chn
= 0, node
= driver
->capture_ports
; node
;
357 node
= jack_slist_next (node
), chn
++) {
361 jack_nframes_t nframes
= driver
->engine
->control
->buffer_size
;
363 port
= (jack_port_t
*) node
->data
;
364 buf
= jack_port_get_buffer (port
, nframes
);
365 memset (buf
, 0, sizeof (jack_default_audio_sample_t
) * nframes
);
368 if (driver
->playback_handle
) {
369 if ((err
= snd_pcm_drop (driver
->playback_handle
)) < 0) {
370 jack_error ("ALSA/USX2Y: channel flush for playback "
371 "failed (%s)", snd_strerror (err
));
376 if (driver
->hw_monitoring
) {
377 driver
->hw
->set_input_monitor_mask (driver
->hw
, 0);
380 munmap(h
->hwdep_pcm_shm
, sizeof(snd_usX2Y_hwdep_pcm_shm_t
));
382 if (driver
->midi
&& !driver
->xrun_recovery
)
383 (driver
->midi
->stop
)(driver
->midi
);
389 usx2y_driver_null_cycle (alsa_driver_t
* driver
, jack_nframes_t nframes
)
392 snd_pcm_uframes_t offset
;
393 snd_pcm_uframes_t contiguous
, contiguous_
;
396 VERBOSE(driver
->engine
,
397 "usx2y_driver_null_cycle (%p, %i)", driver
, nframes
);
399 if (driver
->capture_handle
) {
404 contiguous
= (nf
> driver
->frames_per_cycle
) ?
405 driver
->frames_per_cycle
: nf
;
407 if (snd_pcm_mmap_begin (
408 driver
->capture_handle
,
409 &driver
->capture_areas
,
410 (snd_pcm_uframes_t
*) &offset
,
411 (snd_pcm_uframes_t
*) &contiguous
)) {
414 contiguous_
= contiguous
;
415 while (contiguous_
) {
416 snd_pcm_uframes_t frag
= contiguous_
;
417 if (usx2y_driver_get_channel_addresses_capture(driver
, &frag
) < 0)
422 if (snd_pcm_mmap_commit (driver
->capture_handle
,
423 offset
, contiguous
) < 0) {
431 if (driver
->playback_handle
) {
435 contiguous
= (nf
> driver
->frames_per_cycle
) ?
436 driver
->frames_per_cycle
: nf
;
438 if (snd_pcm_mmap_begin (
439 driver
->playback_handle
,
440 &driver
->playback_areas
,
441 (snd_pcm_uframes_t
*) &offset
,
442 (snd_pcm_uframes_t
*) &contiguous
)) {
447 snd_pcm_uframes_t frag
, nframes
= contiguous
;
450 if (usx2y_driver_get_channel_addresses_playback(driver
, &frag
) < 0)
452 for (chn
= 0; chn
< driver
->playback_nchannels
; chn
++)
453 alsa_driver_silence_on_channel (driver
, chn
, frag
);
458 if (snd_pcm_mmap_commit (driver
->playback_handle
,
459 offset
, contiguous
) < 0) {
471 usx2y_driver_read (alsa_driver_t
*driver
, jack_nframes_t nframes
)
473 snd_pcm_uframes_t contiguous
;
474 snd_pcm_sframes_t nread
;
475 snd_pcm_uframes_t offset
;
476 jack_default_audio_sample_t
* buf
[4];
481 snd_pcm_uframes_t nframes_
= nframes
;
483 if (!driver
->capture_handle
|| driver
->engine
->freewheeling
) {
488 (driver
->midi
->read
)(driver
->midi
, nframes
);
492 if (snd_pcm_mmap_begin (driver
->capture_handle
,
493 &driver
->capture_areas
,
494 &offset
, &nframes_
) < 0) {
495 jack_error ("ALSA/USX2Y: %s: mmap areas info error",
496 driver
->alsa_name_capture
);
500 for (chn
= 0, node
= driver
->capture_ports
;
501 node
; node
= jack_slist_next (node
), chn
++) {
502 port
= (jack_port_t
*) node
->data
;
503 if (!jack_port_connected (port
)) {
506 buf
[chn
] = jack_port_get_buffer (port
, nframes_
);
511 contiguous
= nframes
;
512 if (usx2y_driver_get_channel_addresses_capture (
513 driver
, &contiguous
) < 0) {
516 for (chn
= 0, node
= driver
->capture_ports
;
517 node
; node
= jack_slist_next (node
), chn
++) {
518 port
= (jack_port_t
*) node
->data
;
519 if (!jack_port_connected (port
)) {
520 /* no-copy optimization */
523 alsa_driver_read_from_channel (driver
, chn
,
526 /* sample_move_dS_s24(buf[chn] + nread, */
527 /* driver->capture_addr[chn], */
529 /* driver->capture_interleave_skip); */
532 nframes
-= contiguous
;
535 if ((err
= snd_pcm_mmap_commit (driver
->capture_handle
,
536 offset
, nframes_
)) < 0) {
537 jack_error ("ALSA/USX2Y: could not complete read of %"
538 PRIu32
" frames: error = %d", nframes_
, err
);
546 usx2y_driver_write (alsa_driver_t
* driver
, jack_nframes_t nframes
)
550 jack_default_audio_sample_t
* buf
[2];
551 snd_pcm_sframes_t nwritten
;
552 snd_pcm_uframes_t contiguous
;
553 snd_pcm_uframes_t offset
;
556 snd_pcm_uframes_t nframes_
= nframes
;
558 driver
->process_count
++;
560 if (!driver
->playback_handle
|| driver
->engine
->freewheeling
) {
565 (driver
->midi
->write
)(driver
->midi
, nframes
);
569 /* check current input monitor request status */
571 driver
->input_monitor_mask
= 0;
573 for (chn
= 0, node
= driver
->capture_ports
; node
;
574 node
= jack_slist_next (node
), chn
++) {
575 if (((jack_port_t
*) node
->data
)->shared
->monitor_requests
) {
576 driver
->input_monitor_mask
|= (1<<chn
);
580 if (driver
->hw_monitoring
) {
581 if ((driver
->hw
->input_monitor_mask
582 != driver
->input_monitor_mask
)
583 && !driver
->all_monitor_in
) {
584 driver
->hw
->set_input_monitor_mask (
585 driver
->hw
, driver
->input_monitor_mask
);
589 if (snd_pcm_mmap_begin(driver
->playback_handle
,
590 &driver
->playback_areas
,
591 &offset
, &nframes_
) < 0) {
592 jack_error ("ALSA/USX2Y: %s: mmap areas info error",
593 driver
->alsa_name_capture
);
597 for (chn
= 0, node
= driver
->playback_ports
;
598 node
; node
= jack_slist_next (node
), chn
++) {
599 port
= (jack_port_t
*) node
->data
;
600 buf
[chn
] = jack_port_get_buffer (port
, nframes_
);
605 contiguous
= nframes
;
606 if (usx2y_driver_get_channel_addresses_playback (
607 driver
, &contiguous
) < 0) {
610 for (chn
= 0, node
= driver
->playback_ports
;
611 node
; node
= jack_slist_next (node
), chn
++) {
612 port
= (jack_port_t
*) node
->data
;
613 alsa_driver_write_to_channel (driver
, chn
,
617 nwritten
+= contiguous
;
618 nframes
-= contiguous
;
621 if ((err
= snd_pcm_mmap_commit (driver
->playback_handle
,
622 offset
, nframes_
)) < 0) {
623 jack_error ("ALSA/USX2Y: could not complete playback of %"
624 PRIu32
" frames: error = %d", nframes_
, err
);
625 if (err
!= -EPIPE
&& err
!= -ESTRPIPE
)
633 usx2y_driver_setup (alsa_driver_t
*driver
)
635 driver
->nt_start
= (JackDriverNTStartFunction
) usx2y_driver_start
;
636 driver
->nt_stop
= (JackDriverNTStopFunction
) usx2y_driver_stop
;
637 driver
->read
= (JackDriverReadFunction
) usx2y_driver_read
;
638 driver
->write
= (JackDriverReadFunction
) usx2y_driver_write
;
640 (JackDriverNullCycleFunction
) usx2y_driver_null_cycle
;
644 jack_alsa_usx2y_hw_new (alsa_driver_t
*driver
)
653 snd_hwdep_t
*hwdep_handle
;
655 hw
= (jack_hardware_t
*) malloc (sizeof (jack_hardware_t
));
657 hw
->capabilities
= 0;
658 hw
->input_monitor_mask
= 0;
661 hw
->set_input_monitor_mask
= usx2y_set_input_monitor_mask
;
662 hw
->change_sample_clock
= usx2y_change_sample_clock
;
663 hw
->release
= usx2y_release
;
665 /* Derive the special USB US-X2Y hwdep pcm device name from
666 * the playback one, thus allowing the use of the "rawusb"
667 * experimental stuff if, and only if, the "hw:n,2" device
668 * name is specified. Otherwise, fallback to generic backend.
671 hwdep_cardno
= hwdep_devno
= 0;
672 if ((hwdep_colon
= strrchr(driver
->alsa_name_playback
, ':')) != NULL
)
673 sscanf(hwdep_colon
, ":%d,%d", &hwdep_cardno
, &hwdep_devno
);
674 if (hwdep_devno
== 2) {
675 snprintf(hwdep_name
, sizeof(hwdep_name
), "hw:%d,1", hwdep_cardno
);
676 if (snd_hwdep_open (&hwdep_handle
, hwdep_name
, O_RDWR
) < 0) {
677 jack_error ("ALSA/USX2Y: Cannot open hwdep device \"%s\"", hwdep_name
);
679 /* Allocate specific USX2Y hwdep pcm struct. */
680 h
= (usx2y_t
*) malloc (sizeof (usx2y_t
));
682 h
->hwdep_handle
= hwdep_handle
;
684 /* Set our own operational function pointers. */
685 usx2y_driver_setup(driver
);
686 jack_info("ALSA/USX2Y: EXPERIMENTAL hwdep pcm device %s"
687 " (aka \"rawusb\")", driver
->alsa_name_playback
);