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.
21
#include <jack/hardware.h>
22
#include "alsa_driver.h"
24
#include <jack/internal.h>
25
#include <jack/engine.h>
26
#include <jack/messagebuffer.h>
30
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
37
char dbg_buffer[8096];
40
int usx2y_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask)
46
int usx2y_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode)
52
usx2y_release (jack_hardware_t *hw)
54
usx2y_t *h = (usx2y_t *) hw->private;
60
snd_hwdep_close(h->hwdep_handle);
66
usx2y_driver_get_channel_addresses_playback (alsa_driver_t *driver,
67
snd_pcm_uframes_t *playback_avail)
71
snd_pcm_uframes_t playback_iso_avail;
74
usx2y_t *h = (usx2y_t *) driver->hw->private;
76
if (0 > h->playback_iso_start) {
77
int bytes = driver->playback_sample_bytes * 2 * driver->frames_per_cycle *
78
driver->user_nperiods;
79
iso = h->hwdep_pcm_shm->playback_iso_start;
81
return 0; /* FIXME: return -1; */
82
if (++iso >= ARRAY_SIZE(h->hwdep_pcm_shm->captured_iso))
84
while((bytes -= h->hwdep_pcm_shm->captured_iso[iso].length) > 0)
85
if (++iso >= ARRAY_SIZE(h->hwdep_pcm_shm->captured_iso))
87
h->playback_iso_bytes_done = h->hwdep_pcm_shm->captured_iso[iso].length + bytes;
89
dbg_offset = sprintf(dbg_buffer, "first iso = %i %i@%p:%i\n",
90
iso, h->hwdep_pcm_shm->captured_iso[iso].length,
91
h->hwdep_pcm_shm->playback,
92
h->hwdep_pcm_shm->captured_iso[iso].offset);
95
iso = h->playback_iso_start;
98
dbg_offset += sprintf(dbg_buffer + dbg_offset, "iso = %i(%i;%i); ", iso,
99
h->hwdep_pcm_shm->captured_iso[iso].offset,
100
h->hwdep_pcm_shm->captured_iso[iso].frame);
102
playback = h->hwdep_pcm_shm->playback +
103
h->hwdep_pcm_shm->captured_iso[iso].offset +
104
h->playback_iso_bytes_done;
105
playback_iso_avail = (h->hwdep_pcm_shm->captured_iso[iso].length -
106
h->playback_iso_bytes_done) /
107
(driver->playback_sample_bytes * 2);
108
if (*playback_avail >= playback_iso_avail) {
109
*playback_avail = playback_iso_avail;
110
if (++iso >= ARRAY_SIZE(h->hwdep_pcm_shm->captured_iso))
112
h->playback_iso_bytes_done = 0;
114
h->playback_iso_bytes_done =
115
*playback_avail * (driver->playback_sample_bytes * 2);
116
h->playback_iso_start = iso;
117
for (chn = 0; chn < driver->playback_nchannels; chn++) {
118
const snd_pcm_channel_area_t *a = &driver->playback_areas[chn];
119
driver->playback_addr[chn] = playback + a->first / 8;
122
if (dbg_offset < (sizeof(dbg_buffer) - 256))
123
dbg_offset += sprintf(dbg_buffer + dbg_offset, "avail %li@%p\n", *playback_avail, driver->playback_addr[0]);
134
usx2y_driver_get_channel_addresses_capture (alsa_driver_t *driver,
135
snd_pcm_uframes_t *capture_avail)
139
snd_pcm_uframes_t capture_iso_avail;
142
usx2y_t *h = (usx2y_t *) driver->hw->private;
144
if (0 > h->capture_iso_start) {
145
iso = h->hwdep_pcm_shm->capture_iso_start;
147
return 0; /* FIXME: return -1; */
148
h->capture_iso_bytes_done = 0;
150
dbg_offset = sprintf(dbg_buffer, "cfirst iso = %i %i@%p:%i\n",
151
iso, h->hwdep_pcm_shm->captured_iso[iso].length,
152
h->hwdep_pcm_shm->capture0x8,
153
h->hwdep_pcm_shm->captured_iso[iso].offset);
156
iso = h->capture_iso_start;
159
dbg_offset += sprintf(dbg_buffer + dbg_offset, "ciso = %i(%i;%i); ", iso,
160
h->hwdep_pcm_shm->captured_iso[iso].offset,
161
h->hwdep_pcm_shm->captured_iso[iso].frame);
164
h->hwdep_pcm_shm->captured_iso[iso].offset +
165
h->capture_iso_bytes_done;
166
capture_iso_avail = (h->hwdep_pcm_shm->captured_iso[iso].length -
167
h->capture_iso_bytes_done) /
168
(driver->capture_sample_bytes * 2);
169
if (*capture_avail >= capture_iso_avail) {
170
*capture_avail = capture_iso_avail;
171
if (++iso >= ARRAY_SIZE(h->hwdep_pcm_shm->captured_iso))
173
h->capture_iso_bytes_done = 0;
175
h->capture_iso_bytes_done =
176
*capture_avail * (driver->capture_sample_bytes * 2);
177
h->capture_iso_start = iso;
178
for (chn = 0; chn < driver->capture_nchannels; chn++) {
179
driver->capture_addr[chn] =
180
(chn < 2 ? h->hwdep_pcm_shm->capture0x8 : h->hwdep_pcm_shm->capture0xA)
182
((chn & 1) ? driver->capture_sample_bytes : 0);
187
unsigned *u = driver->capture_addr[0];
188
static unsigned last;
189
dbg_offset += sprintf(dbg_buffer + dbg_offset, "\nvon %6u bis %6u\n", last, u[0]);
190
while (f < *capture_avail && dbg_offset < (sizeof(dbg_buffer) - 256)) {
191
if (u[f] != last + 1)
192
dbg_offset += sprintf(dbg_buffer + dbg_offset, "\nooops %6u %6u\n", last, u[f]);
196
if (dbg_offset < (sizeof(dbg_buffer) - 256))
197
dbg_offset += sprintf(dbg_buffer + dbg_offset, "avail %li@%p\n", *capture_avail, driver->capture_addr[0]);
208
usx2y_driver_start (alsa_driver_t *driver)
211
snd_pcm_uframes_t poffset, pavail;
213
usx2y_t *h = (usx2y_t *) driver->hw->private;
215
for (i = 0; i < driver->capture_nchannels; i++)
216
// US428 channels 3+4 are on a seperate 2 channel stream.
217
// ALSA thinks its 1 stream with 4 channels.
218
driver->capture_interleave_skip[i] = 2 * driver->capture_sample_bytes;
221
driver->playback_interleave_skip[0] = 2 * driver->playback_sample_bytes;
222
driver->playback_interleave_skip[1] = 2 * driver->playback_sample_bytes;
224
driver->poll_last = 0;
225
driver->poll_next = 0;
227
if ((err = snd_pcm_prepare (driver->playback_handle)) < 0) {
228
jack_error ("ALSA/USX2Y: prepare error for playback: %s", snd_strerror(err));
232
if (driver->midi && !driver->xrun_recovery)
233
(driver->midi->start)(driver->midi);
235
if (driver->playback_handle) {
237
/* char buffer[2000]; */
238
h->playback_iso_start =
239
h->capture_iso_start = -1;
240
snd_hwdep_poll_descriptors(h->hwdep_handle, &h->pfds, 1);
241
h->hwdep_pcm_shm = (snd_usX2Y_hwdep_pcm_shm_t*)
242
mmap(NULL, sizeof(snd_usX2Y_hwdep_pcm_shm_t),
244
MAP_SHARED, h->pfds.fd,
246
if (MAP_FAILED == h->hwdep_pcm_shm) {
247
perror("ALSA/USX2Y: mmap");
250
if (mprotect(h->hwdep_pcm_shm->playback,
251
sizeof(h->hwdep_pcm_shm->playback),
252
PROT_READ|PROT_WRITE)) {
253
perror("ALSA/USX2Y: mprotect");
256
memset(h->hwdep_pcm_shm->playback, 0, sizeof(h->hwdep_pcm_shm->playback));
257
/* for (i = 0, j = 0; i < 2000;) { */
258
/* j += sprintf(buffer + j, "%04hX ", */
259
/* *(unsigned short*)(h->hwdep_pcm_shm->capture + i)); */
260
/* if (((i += 2) % 32) == 0) { */
261
/* jack_error(buffer); */
267
if (driver->hw_monitoring) {
268
driver->hw->set_input_monitor_mask (driver->hw,
269
driver->input_monitor_mask);
272
if (driver->playback_handle) {
273
/* fill playback buffer with zeroes, and mark
274
all fragments as having data.
277
pavail = snd_pcm_avail_update (driver->playback_handle);
279
if (pavail != driver->frames_per_cycle * driver->playback_nperiods) {
280
jack_error ("ALSA/USX2Y: full buffer not available at start");
284
if (snd_pcm_mmap_begin(
285
driver->playback_handle,
286
&driver->playback_areas,
287
&poffset, &pavail) < 0) {
291
/* XXX this is cheating. ALSA offers no guarantee that
292
we can access the entire buffer at any one time. It
293
works on most hardware tested so far, however, buts
294
its a liability in the long run. I think that
295
alsa-lib may have a better function for doing this
296
here, where the goal is to silence the entire
300
/* snd_pcm_uframes_t frag, nframes = driver->buffer_frames; */
301
/* while (nframes) { */
302
/* frag = nframes; */
303
/* if (usx2y_driver_get_channel_addresses_playback(driver, &frag) < 0) */
306
/* for (chn = 0; chn < driver->playback_nchannels; chn++) */
307
/* alsa_driver_silence_on_channel (driver, chn, frag); */
308
/* nframes -= frag; */
312
snd_pcm_mmap_commit (driver->playback_handle, poffset,
313
driver->user_nperiods * driver->frames_per_cycle);
315
if ((err = snd_pcm_start (driver->playback_handle)) < 0) {
316
jack_error ("ALSA/USX2Y: could not start playback (%s)",
322
if (driver->hw_monitoring &&
323
(driver->input_monitor_mask || driver->all_monitor_in)) {
324
if (driver->all_monitor_in) {
325
driver->hw->set_input_monitor_mask (driver->hw, ~0U);
327
driver->hw->set_input_monitor_mask (
328
driver->hw, driver->input_monitor_mask);
332
driver->playback_nfds = snd_pcm_poll_descriptors_count (driver->playback_handle);
333
driver->capture_nfds = snd_pcm_poll_descriptors_count (driver->capture_handle);
339
driver->pfd = (struct pollfd *)
340
malloc (sizeof (struct pollfd) *
341
(driver->playback_nfds + driver->capture_nfds + 2));
347
usx2y_driver_stop (alsa_driver_t *driver)
353
usx2y_t *h = (usx2y_t *) driver->hw->private;
355
/* silence all capture port buffers, because we might
356
be entering offline mode.
359
for (chn = 0, node = driver->capture_ports; node;
360
node = jack_slist_next (node), chn++) {
364
jack_nframes_t nframes = driver->engine->control->buffer_size;
366
port = (jack_port_t *) node->data;
367
buf = jack_port_get_buffer (port, nframes);
368
memset (buf, 0, sizeof (jack_default_audio_sample_t) * nframes);
371
if (driver->playback_handle) {
372
if ((err = snd_pcm_drop (driver->playback_handle)) < 0) {
373
jack_error ("ALSA/USX2Y: channel flush for playback "
374
"failed (%s)", snd_strerror (err));
379
if (driver->hw_monitoring) {
380
driver->hw->set_input_monitor_mask (driver->hw, 0);
383
munmap(h->hwdep_pcm_shm, sizeof(snd_usX2Y_hwdep_pcm_shm_t));
385
if (driver->midi && !driver->xrun_recovery)
386
(driver->midi->stop)(driver->midi);
392
usx2y_driver_null_cycle (alsa_driver_t* driver, jack_nframes_t nframes)
395
snd_pcm_uframes_t offset;
396
snd_pcm_uframes_t contiguous, contiguous_;
399
VERBOSE(driver->engine,
400
"usx2y_driver_null_cycle (%p, %i)", driver, nframes);
402
if (driver->capture_handle) {
407
contiguous = (nf > driver->frames_per_cycle) ?
408
driver->frames_per_cycle : nf;
410
if (snd_pcm_mmap_begin (
411
driver->capture_handle,
412
&driver->capture_areas,
413
(snd_pcm_uframes_t *) &offset,
414
(snd_pcm_uframes_t *) &contiguous)) {
417
contiguous_ = contiguous;
418
while (contiguous_) {
419
snd_pcm_uframes_t frag = contiguous_;
420
if (usx2y_driver_get_channel_addresses_capture(driver, &frag) < 0)
425
if (snd_pcm_mmap_commit (driver->capture_handle,
426
offset, contiguous) < 0) {
434
if (driver->playback_handle) {
438
contiguous = (nf > driver->frames_per_cycle) ?
439
driver->frames_per_cycle : nf;
441
if (snd_pcm_mmap_begin (
442
driver->playback_handle,
443
&driver->playback_areas,
444
(snd_pcm_uframes_t *) &offset,
445
(snd_pcm_uframes_t *) &contiguous)) {
450
snd_pcm_uframes_t frag, nframes = contiguous;
453
if (usx2y_driver_get_channel_addresses_playback(driver, &frag) < 0)
455
for (chn = 0; chn < driver->playback_nchannels; chn++)
456
alsa_driver_silence_on_channel (driver, chn, frag);
461
if (snd_pcm_mmap_commit (driver->playback_handle,
462
offset, contiguous) < 0) {
474
usx2y_driver_read (alsa_driver_t *driver, jack_nframes_t nframes)
476
snd_pcm_uframes_t contiguous;
477
snd_pcm_sframes_t nread;
478
snd_pcm_uframes_t offset;
479
jack_default_audio_sample_t* buf[4];
484
snd_pcm_uframes_t nframes_ = nframes;
486
if (!driver->capture_handle || driver->engine->freewheeling) {
491
(driver->midi->read)(driver->midi, nframes);
495
if (snd_pcm_mmap_begin (driver->capture_handle,
496
&driver->capture_areas,
497
&offset, &nframes_) < 0) {
498
jack_error ("ALSA/USX2Y: %s: mmap areas info error",
499
driver->alsa_name_capture);
503
for (chn = 0, node = driver->capture_ports;
504
node; node = jack_slist_next (node), chn++) {
505
port = (jack_port_t *) node->data;
506
if (!jack_port_connected (port)) {
509
buf[chn] = jack_port_get_buffer (port, nframes_);
514
contiguous = nframes;
515
if (usx2y_driver_get_channel_addresses_capture (
516
driver, &contiguous) < 0) {
519
for (chn = 0, node = driver->capture_ports;
520
node; node = jack_slist_next (node), chn++) {
521
port = (jack_port_t *) node->data;
522
if (!jack_port_connected (port)) {
523
/* no-copy optimization */
526
alsa_driver_read_from_channel (driver, chn,
529
/* sample_move_dS_s24(buf[chn] + nread, */
530
/* driver->capture_addr[chn], */
532
/* driver->capture_interleave_skip); */
535
nframes -= contiguous;
538
if ((err = snd_pcm_mmap_commit (driver->capture_handle,
539
offset, nframes_)) < 0) {
540
jack_error ("ALSA/USX2Y: could not complete read of %"
541
PRIu32 " frames: error = %d", nframes_, err);
549
usx2y_driver_write (alsa_driver_t* driver, jack_nframes_t nframes)
553
jack_default_audio_sample_t* buf[2];
554
snd_pcm_sframes_t nwritten;
555
snd_pcm_uframes_t contiguous;
556
snd_pcm_uframes_t offset;
559
snd_pcm_uframes_t nframes_ = nframes;
561
driver->process_count++;
563
if (!driver->playback_handle || driver->engine->freewheeling) {
568
(driver->midi->write)(driver->midi, nframes);
572
/* check current input monitor request status */
574
driver->input_monitor_mask = 0;
576
for (chn = 0, node = driver->capture_ports; node;
577
node = jack_slist_next (node), chn++) {
578
if (((jack_port_t *) node->data)->shared->monitor_requests) {
579
driver->input_monitor_mask |= (1<<chn);
583
if (driver->hw_monitoring) {
584
if ((driver->hw->input_monitor_mask
585
!= driver->input_monitor_mask)
586
&& !driver->all_monitor_in) {
587
driver->hw->set_input_monitor_mask (
588
driver->hw, driver->input_monitor_mask);
592
if (snd_pcm_mmap_begin(driver->playback_handle,
593
&driver->playback_areas,
594
&offset, &nframes_) < 0) {
595
jack_error ("ALSA/USX2Y: %s: mmap areas info error",
596
driver->alsa_name_capture);
600
for (chn = 0, node = driver->playback_ports;
601
node; node = jack_slist_next (node), chn++) {
602
port = (jack_port_t *) node->data;
603
buf[chn] = jack_port_get_buffer (port, nframes_);
608
contiguous = nframes;
609
if (usx2y_driver_get_channel_addresses_playback (
610
driver, &contiguous) < 0) {
613
for (chn = 0, node = driver->playback_ports;
614
node; node = jack_slist_next (node), chn++) {
615
port = (jack_port_t *) node->data;
616
alsa_driver_write_to_channel (driver, chn,
620
nwritten += contiguous;
621
nframes -= contiguous;
624
if ((err = snd_pcm_mmap_commit (driver->playback_handle,
625
offset, nframes_)) < 0) {
626
jack_error ("ALSA/USX2Y: could not complete playback of %"
627
PRIu32 " frames: error = %d", nframes_, err);
628
if (err != EPIPE && err != ESTRPIPE)
636
usx2y_driver_setup (alsa_driver_t *driver)
638
driver->nt_start = (JackDriverNTStartFunction) usx2y_driver_start;
639
driver->nt_stop = (JackDriverNTStopFunction) usx2y_driver_stop;
640
driver->read = (JackDriverReadFunction) usx2y_driver_read;
641
driver->write = (JackDriverReadFunction) usx2y_driver_write;
643
(JackDriverNullCycleFunction) usx2y_driver_null_cycle;
648
jack_alsa_usx2y_hw_new (alsa_driver_t *driver)
657
snd_hwdep_t *hwdep_handle;
659
hw = (jack_hardware_t *) malloc (sizeof (jack_hardware_t));
661
hw->capabilities = 0;
662
hw->input_monitor_mask = 0;
665
hw->set_input_monitor_mask = usx2y_set_input_monitor_mask;
666
hw->change_sample_clock = usx2y_change_sample_clock;
667
hw->release = usx2y_release;
669
/* Derive the special USB US-X2Y hwdep pcm device name from
670
* the playback one, thus allowing the use of the "rawusb"
671
* experimental stuff if, and only if, the "hw:n,2" device
672
* name is specified. Otherwise, fallback to generic backend.
675
hwdep_cardno = hwdep_devno = 0;
676
if ((hwdep_colon = strrchr(driver->alsa_name_playback, ':')) != NULL)
677
sscanf(hwdep_colon, ":%d,%d", &hwdep_cardno, &hwdep_devno);
678
if (hwdep_devno == 2) {
679
snprintf(hwdep_name, sizeof(hwdep_name), "hw:%d,1", hwdep_cardno);
680
if (snd_hwdep_open (&hwdep_handle, hwdep_name, O_RDWR) < 0) {
681
jack_error ("ALSA/USX2Y: Cannot open hwdep device \"%s\"", hwdep_name);
683
/* Allocate specific USX2Y hwdep pcm struct. */
684
h = (usx2y_t *) malloc (sizeof (usx2y_t));
686
h->hwdep_handle = hwdep_handle;
688
/* Set our own operational function pointers. */
689
usx2y_driver_setup(driver);
690
jack_info("ALSA/USX2Y: EXPERIMENTAL hwdep pcm device %s"
691
" (aka \"rawusb\")", driver->alsa_name_playback);