~ubuntu-branches/ubuntu/lucid/jack-audio-connection-kit/lucid

« back to all changes in this revision

Viewing changes to drivers/alsa/usx2y.c

  • Committer: Bazaar Package Importer
  • Author(s): Luca Falavigna
  • Date: 2008-12-06 11:05:15 UTC
  • mfrom: (4.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20081206110515-xa9v9pajr9jqvfvg
Tags: 0.115.6-1ubuntu1
* Merge from Debian unstable, remaining Ubuntu changes:
  - Redirect stderr in bash completion (Debian #504488).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (C) 2001 Paul Davis 
 
3
    Copyright (C) 2005 Karsten Wiese, Rui Nuno Capela
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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.
 
18
 
 
19
*/
 
20
 
 
21
#include <jack/hardware.h>
 
22
#include "alsa_driver.h"
 
23
#include "usx2y.h"
 
24
#include <jack/internal.h>
 
25
#include <jack/engine.h>
 
26
#include <jack/messagebuffer.h>
 
27
#include <sys/mman.h>
 
28
 
 
29
#ifndef ARRAY_SIZE
 
30
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
31
#endif
 
32
 
 
33
//#define DBGHWDEP
 
34
 
 
35
#ifdef DBGHWDEP
 
36
int dbg_offset;
 
37
char dbg_buffer[8096];
 
38
#endif
 
39
static 
 
40
int usx2y_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask)
 
41
{
 
42
        return -1;
 
43
}
 
44
 
 
45
static
 
46
int usx2y_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode) 
 
47
{
 
48
        return -1;
 
49
}
 
50
 
 
51
static void
 
52
usx2y_release (jack_hardware_t *hw)
 
53
{
 
54
        usx2y_t *h = (usx2y_t *) hw->private;
 
55
 
 
56
        if (h == 0)
 
57
                return;
 
58
        
 
59
        if (h->hwdep_handle)
 
60
                snd_hwdep_close(h->hwdep_handle);
 
61
 
 
62
        free(h);
 
63
}
 
64
 
 
65
static int
 
66
usx2y_driver_get_channel_addresses_playback (alsa_driver_t *driver,
 
67
                                        snd_pcm_uframes_t *playback_avail)
 
68
{
 
69
        channel_t chn;
 
70
        int iso;
 
71
        snd_pcm_uframes_t playback_iso_avail;
 
72
        char *playback;
 
73
 
 
74
        usx2y_t *h = (usx2y_t *) driver->hw->private;
 
75
 
 
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;
 
80
                if (0 > iso)
 
81
                        return 0; /* FIXME: return -1; */
 
82
                if (++iso >= ARRAY_SIZE(h->hwdep_pcm_shm->captured_iso))
 
83
                        iso = 0;
 
84
                while((bytes -= h->hwdep_pcm_shm->captured_iso[iso].length) > 0)
 
85
                        if (++iso >= ARRAY_SIZE(h->hwdep_pcm_shm->captured_iso))
 
86
                                iso = 0;
 
87
                h->playback_iso_bytes_done = h->hwdep_pcm_shm->captured_iso[iso].length + bytes;
 
88
#ifdef DBGHWDEP
 
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);
 
93
#endif
 
94
        } else {
 
95
                iso = h->playback_iso_start;
 
96
        }
 
97
#ifdef DBGHWDEP
 
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);
 
101
#endif
 
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))
 
111
                        iso = 0;
 
112
                h->playback_iso_bytes_done = 0;
 
113
        } else
 
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;
 
120
        }
 
121
#ifdef DBGHWDEP
 
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]);
 
124
        else {
 
125
                printf(dbg_buffer);
 
126
                return -1;
 
127
        }
 
128
#endif
 
129
 
 
130
        return 0;
 
131
}
 
132
 
 
133
static int
 
134
usx2y_driver_get_channel_addresses_capture (alsa_driver_t *driver,
 
135
                                        snd_pcm_uframes_t *capture_avail)
 
136
{
 
137
        channel_t chn;
 
138
        int iso;
 
139
        snd_pcm_uframes_t capture_iso_avail;
 
140
        int capture_offset;
 
141
 
 
142
        usx2y_t *h = (usx2y_t *) driver->hw->private;
 
143
 
 
144
        if (0 > h->capture_iso_start) {
 
145
                iso = h->hwdep_pcm_shm->capture_iso_start;
 
146
                if (0 > iso)
 
147
                        return 0; /* FIXME: return -1; */
 
148
                h->capture_iso_bytes_done = 0;
 
149
#ifdef DBGHWDEP
 
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);
 
154
#endif
 
155
        } else {
 
156
                iso = h->capture_iso_start;
 
157
        }
 
158
#ifdef DBGHWDEP
 
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);
 
162
#endif
 
163
        capture_offset =
 
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))
 
172
                        iso = 0;
 
173
                h->capture_iso_bytes_done = 0;
 
174
        } else
 
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)
 
181
                        + capture_offset +
 
182
                        ((chn & 1) ? driver->capture_sample_bytes : 0);
 
183
        }
 
184
#ifdef DBGHWDEP
 
185
 {
 
186
        int f = 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]);
 
193
                last = u[f++];
 
194
        }
 
195
 }
 
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]);
 
198
        else {
 
199
                printf(dbg_buffer);
 
200
                return -1;
 
201
        }
 
202
#endif
 
203
 
 
204
        return 0;
 
205
}
 
206
 
 
207
static int
 
208
usx2y_driver_start (alsa_driver_t *driver)
 
209
{
 
210
        int err, i;
 
211
        snd_pcm_uframes_t poffset, pavail;
 
212
 
 
213
        usx2y_t *h = (usx2y_t *) driver->hw->private;
 
214
 
 
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;
 
219
 
 
220
 
 
221
        driver->playback_interleave_skip[0] = 2 * driver->playback_sample_bytes;
 
222
        driver->playback_interleave_skip[1] = 2 * driver->playback_sample_bytes;
 
223
 
 
224
        driver->poll_last = 0;
 
225
        driver->poll_next = 0;
 
226
 
 
227
        if ((err = snd_pcm_prepare (driver->playback_handle)) < 0) {
 
228
                jack_error ("ALSA/USX2Y: prepare error for playback: %s", snd_strerror(err));
 
229
                return -1;
 
230
        }
 
231
 
 
232
        if (driver->midi && !driver->xrun_recovery)
 
233
                (driver->midi->start)(driver->midi);
 
234
 
 
235
        if (driver->playback_handle) {
 
236
/*              int i, j; */
 
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),
 
243
                             PROT_READ,
 
244
                             MAP_SHARED, h->pfds.fd,
 
245
                             0);
 
246
                if (MAP_FAILED == h->hwdep_pcm_shm) {
 
247
                        perror("ALSA/USX2Y: mmap");
 
248
                        return -1;
 
249
                }
 
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");
 
254
                        return -1;
 
255
                }
 
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); */
 
262
/*                              j = 0; */
 
263
/*                      } */
 
264
/*              } */
 
265
        }
 
266
 
 
267
        if (driver->hw_monitoring) {
 
268
                driver->hw->set_input_monitor_mask (driver->hw,
 
269
                                                    driver->input_monitor_mask);
 
270
        }
 
271
 
 
272
        if (driver->playback_handle) {
 
273
                /* fill playback buffer with zeroes, and mark
 
274
                   all fragments as having data.
 
275
                */
 
276
 
 
277
                pavail = snd_pcm_avail_update (driver->playback_handle);
 
278
 
 
279
                if (pavail != driver->frames_per_cycle * driver->playback_nperiods) {
 
280
                        jack_error ("ALSA/USX2Y: full buffer not available at start");
 
281
                        return -1;
 
282
                }
 
283
 
 
284
                if (snd_pcm_mmap_begin(
 
285
                                        driver->playback_handle,
 
286
                                        &driver->playback_areas,
 
287
                                        &poffset, &pavail) < 0) {
 
288
                        return -1;
 
289
                }
 
290
 
 
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
 
297
                   buffer.
 
298
                */
 
299
                {
 
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) */
 
304
/*                                      return -1; */
 
305
 
 
306
/*                              for (chn = 0; chn < driver->playback_nchannels; chn++) */
 
307
/*                                      alsa_driver_silence_on_channel (driver, chn, frag); */
 
308
/*                              nframes -= frag; */
 
309
/*                      } */
 
310
                }
 
311
 
 
312
                snd_pcm_mmap_commit (driver->playback_handle, poffset,
 
313
                                                driver->user_nperiods * driver->frames_per_cycle);
 
314
 
 
315
                if ((err = snd_pcm_start (driver->playback_handle)) < 0) {
 
316
                        jack_error ("ALSA/USX2Y: could not start playback (%s)",
 
317
                                    snd_strerror (err));
 
318
                        return -1;
 
319
                }
 
320
        }
 
321
 
 
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);
 
326
                } else {
 
327
                        driver->hw->set_input_monitor_mask (
 
328
                                driver->hw, driver->input_monitor_mask);
 
329
                }
 
330
        }
 
331
 
 
332
        driver->playback_nfds = snd_pcm_poll_descriptors_count (driver->playback_handle);
 
333
        driver->capture_nfds = snd_pcm_poll_descriptors_count (driver->capture_handle);
 
334
 
 
335
        if (driver->pfd) {
 
336
                free (driver->pfd);
 
337
        }
 
338
 
 
339
        driver->pfd = (struct pollfd *)
 
340
                malloc (sizeof (struct pollfd) *
 
341
                        (driver->playback_nfds + driver->capture_nfds + 2));
 
342
 
 
343
        return 0;
 
344
}
 
345
 
 
346
static int
 
347
usx2y_driver_stop (alsa_driver_t *driver)
 
348
{
 
349
        int err;
 
350
        JSList* node;
 
351
        int chn;
 
352
 
 
353
        usx2y_t *h = (usx2y_t *) driver->hw->private;
 
354
 
 
355
        /* silence all capture port buffers, because we might
 
356
           be entering offline mode.
 
357
        */
 
358
 
 
359
        for (chn = 0, node = driver->capture_ports; node;
 
360
                node = jack_slist_next (node), chn++) {
 
361
 
 
362
                jack_port_t* port;
 
363
                char* buf;
 
364
                jack_nframes_t nframes = driver->engine->control->buffer_size;
 
365
 
 
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);
 
369
        }
 
370
 
 
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));
 
375
                        return -1;
 
376
                }
 
377
        }
 
378
 
 
379
        if (driver->hw_monitoring) {
 
380
                driver->hw->set_input_monitor_mask (driver->hw, 0);
 
381
        }
 
382
 
 
383
        munmap(h->hwdep_pcm_shm, sizeof(snd_usX2Y_hwdep_pcm_shm_t));
 
384
 
 
385
        if (driver->midi && !driver->xrun_recovery)
 
386
                (driver->midi->stop)(driver->midi);
 
387
 
 
388
        return 0;
 
389
}
 
390
 
 
391
static int
 
392
usx2y_driver_null_cycle (alsa_driver_t* driver, jack_nframes_t nframes)
 
393
{
 
394
        jack_nframes_t nf;
 
395
        snd_pcm_uframes_t offset;
 
396
        snd_pcm_uframes_t contiguous, contiguous_;
 
397
        int chn;
 
398
 
 
399
        VERBOSE(driver->engine,
 
400
                "usx2y_driver_null_cycle (%p, %i)", driver, nframes);
 
401
 
 
402
        if (driver->capture_handle) {
 
403
                nf = nframes;
 
404
                offset = 0;
 
405
                while (nf) {
 
406
 
 
407
                        contiguous = (nf > driver->frames_per_cycle) ?
 
408
                                driver->frames_per_cycle : nf;
 
409
 
 
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)) {
 
415
                                return -1;
 
416
                        }
 
417
                        contiguous_ = contiguous;
 
418
                        while (contiguous_) {
 
419
                                snd_pcm_uframes_t frag = contiguous_;
 
420
                                if (usx2y_driver_get_channel_addresses_capture(driver, &frag) < 0)
 
421
                                        return -1;
 
422
                                contiguous_ -= frag;
 
423
                        }
 
424
 
 
425
                        if (snd_pcm_mmap_commit (driver->capture_handle,
 
426
                                                offset, contiguous) < 0) {
 
427
                                return -1;
 
428
                        }
 
429
 
 
430
                        nf -= contiguous;
 
431
                }
 
432
        }
 
433
 
 
434
        if (driver->playback_handle) {
 
435
                nf = nframes;
 
436
                offset = 0;
 
437
                while (nf) {
 
438
                        contiguous = (nf > driver->frames_per_cycle) ?
 
439
                                driver->frames_per_cycle : nf;
 
440
 
 
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)) {
 
446
                                return -1;
 
447
                        }
 
448
 
 
449
                        {
 
450
                                snd_pcm_uframes_t frag, nframes = contiguous;
 
451
                                while (nframes) {
 
452
                                        frag = nframes;
 
453
                                        if (usx2y_driver_get_channel_addresses_playback(driver, &frag) < 0)
 
454
                                                return -1;
 
455
                                        for (chn = 0; chn < driver->playback_nchannels; chn++)
 
456
                                                alsa_driver_silence_on_channel (driver, chn, frag);
 
457
                                        nframes -= frag;
 
458
                                }
 
459
                        }
 
460
 
 
461
                        if (snd_pcm_mmap_commit (driver->playback_handle,
 
462
                                                offset, contiguous) < 0) {
 
463
                                return -1;
 
464
                        }
 
465
 
 
466
                        nf -= contiguous;
 
467
                }
 
468
        }
 
469
 
 
470
        return 0;
 
471
}
 
472
 
 
473
static int
 
474
usx2y_driver_read (alsa_driver_t *driver, jack_nframes_t nframes)
 
475
{
 
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];
 
480
        channel_t chn;
 
481
        JSList *node;
 
482
        jack_port_t* port;
 
483
        int err;
 
484
        snd_pcm_uframes_t nframes_ = nframes;
 
485
 
 
486
        if (!driver->capture_handle || driver->engine->freewheeling) {
 
487
                return 0;
 
488
        }
 
489
 
 
490
    if (driver->midi)
 
491
        (driver->midi->read)(driver->midi, nframes);
 
492
 
 
493
        nread = 0;
 
494
 
 
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);
 
500
                return -1;
 
501
        }
 
502
 
 
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)) {
 
507
                        continue;
 
508
                }
 
509
                buf[chn] = jack_port_get_buffer (port, nframes_);
 
510
        }
 
511
 
 
512
        while (nframes) {
 
513
 
 
514
                contiguous = nframes;
 
515
                if (usx2y_driver_get_channel_addresses_capture (
 
516
                            driver, &contiguous) < 0) {
 
517
                        return -1;
 
518
                }
 
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 */
 
524
                                continue;
 
525
                        }
 
526
                        alsa_driver_read_from_channel (driver, chn,
 
527
                                                       buf[chn] + nread,
 
528
                                                       contiguous);
 
529
/*                      sample_move_dS_s24(buf[chn] + nread, */
 
530
/*                                         driver->capture_addr[chn], */
 
531
/*                                         contiguous, */
 
532
/*                                         driver->capture_interleave_skip); */
 
533
                }
 
534
                nread += contiguous;
 
535
                nframes -= contiguous;
 
536
        }
 
537
 
 
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);
 
542
                return -1;
 
543
        }
 
544
 
 
545
        return 0;
 
546
}
 
547
 
 
548
static int
 
549
usx2y_driver_write (alsa_driver_t* driver, jack_nframes_t nframes)
 
550
{
 
551
        channel_t chn;
 
552
        JSList *node;
 
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;
 
557
        jack_port_t *port;
 
558
        int err;
 
559
        snd_pcm_uframes_t nframes_ = nframes;
 
560
 
 
561
        driver->process_count++;
 
562
 
 
563
        if (!driver->playback_handle || driver->engine->freewheeling) {
 
564
                return 0;
 
565
        }
 
566
 
 
567
    if (driver->midi)
 
568
        (driver->midi->write)(driver->midi, nframes);
 
569
 
 
570
        nwritten = 0;
 
571
 
 
572
        /* check current input monitor request status */
 
573
 
 
574
        driver->input_monitor_mask = 0;
 
575
 
 
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);
 
580
                }
 
581
        }
 
582
 
 
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);
 
589
                }
 
590
        }
 
591
 
 
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);
 
597
                return -1;
 
598
        }
 
599
 
 
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_);
 
604
        }
 
605
 
 
606
        while (nframes) {
 
607
 
 
608
                contiguous = nframes;
 
609
                if (usx2y_driver_get_channel_addresses_playback (
 
610
                            driver, &contiguous) < 0) {
 
611
                        return -1;
 
612
                }
 
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,
 
617
                                                      buf[chn] + nwritten,
 
618
                                                      contiguous);
 
619
                }
 
620
                nwritten += contiguous;
 
621
                nframes -= contiguous;
 
622
        }
 
623
 
 
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)
 
629
                        return -1;
 
630
        }
 
631
 
 
632
        return 0;
 
633
}
 
634
 
 
635
static void
 
636
usx2y_driver_setup (alsa_driver_t *driver)
 
637
{
 
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;
 
642
        driver->null_cycle =
 
643
                (JackDriverNullCycleFunction) usx2y_driver_null_cycle;
 
644
}
 
645
 
 
646
 
 
647
jack_hardware_t *
 
648
jack_alsa_usx2y_hw_new (alsa_driver_t *driver)
 
649
{
 
650
        jack_hardware_t *hw;
 
651
        usx2y_t *h;
 
652
 
 
653
        int   hwdep_cardno;
 
654
    int   hwdep_devno;
 
655
        char *hwdep_colon;
 
656
        char  hwdep_name[9];
 
657
        snd_hwdep_t *hwdep_handle;
 
658
 
 
659
    hw = (jack_hardware_t *) malloc (sizeof (jack_hardware_t));
 
660
 
 
661
        hw->capabilities = 0;
 
662
        hw->input_monitor_mask = 0;
 
663
        hw->private = 0;
 
664
 
 
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;
 
668
 
 
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.
 
673
         */
 
674
        hwdep_handle = NULL;
 
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);
 
682
                } else {
 
683
                        /* Allocate specific USX2Y hwdep pcm struct. */
 
684
                        h = (usx2y_t *) malloc (sizeof (usx2y_t));
 
685
                        h->driver = driver;
 
686
                        h->hwdep_handle = hwdep_handle;
 
687
                        hw->private = h;
 
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);
 
692
                }
 
693
        }
 
694
 
 
695
        return hw;
 
696
}