Annotation of src/usr.bin/aucat/dev.c, Revision 1.64
1.64 ! ratchov 1: /* $OpenBSD: dev.c,v 1.63 2010/07/31 08:46:56 ratchov Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
1.51 ratchov 17: /*
18: * Device abstraction module
19: *
20: * This module exposes a ``enhanced device'' that uses aproc
21: * structures framework; it does conversions on the fly and can
22: * handle multiple streams. The enhanced device starts and stops
23: * automatically, when streams are attached, and provides
24: * primitives for MIDI control
25: *
26: * From the main loop, the device is used as follows:
27: *
1.57 ratchov 28: * 1. create the device using dev_new_xxx()
1.51 ratchov 29: * 2. call dev_run() in the event loop
1.57 ratchov 30: * 3. destroy the device using dev_del()
1.51 ratchov 31: * 4. continue running the event loop to drain
32: *
33: * The device is used as follows from aproc context:
34: *
35: * 1. open the device with dev_ref()
36: * 2. negociate parameters (mode, rate, ...)
37: * 3. create your stream (ie allocate and fill abufs)
38: * 4. attach your stream atomically:
39: * - first call dev_wakeup() to ensure device is not suspended
40: * - possibly fetch dynamic parameters (eg. dev_getpos())
41: * - attach your buffers with dev_attach()
42: * 5. close your stream, ie abuf_eof() or abuf_hup()
43: * 6. close the device with dev_unref()
44: *
45: * The device has the following states:
46: *
47: * CLOSED sio_open() is not called, it's not ready and
48: * no streams can be attached; dev_ref() must
49: * be called to open the device
50: *
51: * INIT device is opened, processing chain is ready, but
52: * DMA is not started yet. Streams can attach,
53: * in which case device will automatically switch
54: * to the START state
55: *
56: * START at least one stream is attached, play buffers
57: * are primed (if necessary) DMA is ready and
58: * will start immeadiately (next cycle)
59: *
60: * RUN DMA is started. New streams can attach. If the
61: * device is idle (all streams are closed and
62: * finished draining), then the device
63: * automatically switches to INIT or CLOSED
64: */
65: /*
66: * TODO:
67: *
68: * priming buffer is not ok, because it will insert silence and
69: * break synchronization to other programs.
70: *
71: * priming buffer in server mode is required, because f->bufsz may
72: * be smaller than the server buffer and may cause underrun in the
73: * dev_bufsz part of the buffer, in turn causing apps to break. It
74: * doesn't hurt because we care only in synchronization between
75: * clients.
76: *
77: * Priming is not required in non-server mode, because streams
78: * actually start when they are in the READY state, and their
79: * buffer is large enough to never cause underruns of dev_bufsz.
80: *
81: * Fix sock.c to allocate dev_bufsz, but to use only appbufsz --
82: * or whatever -- but to avoid underruns in dev_bufsz. Then remove
83: * this ugly hack.
84: *
85: */
1.1 ratchov 86: #include <stdio.h>
87: #include <stdlib.h>
88: #include <unistd.h>
89:
90: #include "abuf.h"
91: #include "aproc.h"
1.27 ratchov 92: #include "conf.h"
93: #include "dev.h"
1.3 ratchov 94: #include "pipe.h"
1.38 ratchov 95: #include "miofile.h"
1.42 ratchov 96: #include "siofile.h"
1.28 ratchov 97: #include "midi.h"
1.46 ratchov 98: #include "opt.h"
1.39 ratchov 99: #ifdef DEBUG
100: #include "dbg.h"
101: #endif
1.1 ratchov 102:
1.57 ratchov 103: int dev_open(struct dev *);
104: void dev_close(struct dev *);
105: void dev_start(struct dev *);
106: void dev_stop(struct dev *);
107: void dev_clear(struct dev *);
108:
109: struct dev *dev_list = NULL;
1.38 ratchov 110:
111: /*
1.51 ratchov 112: * Create a sndio device
1.28 ratchov 113: */
1.57 ratchov 114: struct dev *
115: dev_new_sio(char *path,
116: unsigned mode, struct aparams *dipar, struct aparams *dopar,
1.58 ratchov 117: unsigned bufsz, unsigned round, unsigned hold)
1.57 ratchov 118: {
119: struct dev *d;
120:
121: d = malloc(sizeof(struct dev));
122: if (d == NULL) {
123: perror("malloc");
124: exit(1);
125: }
126: d->path = path;
127: d->reqmode = mode;
1.51 ratchov 128: if (mode & MODE_PLAY)
1.57 ratchov 129: d->reqopar = *dopar;
1.51 ratchov 130: if (mode & MODE_RECMASK)
1.57 ratchov 131: d->reqipar = *dipar;
132: d->reqbufsz = bufsz;
133: d->reqround = round;
134: d->hold = hold;
135: d->pstate = DEV_CLOSED;
136: d->next = dev_list;
137: dev_list = d;
138: if (d->hold && !dev_open(d)) {
139: dev_del(d);
140: return NULL;
141: }
142: return d;
1.28 ratchov 143: }
1.24 ratchov 144:
145: /*
1.51 ratchov 146: * Create a loopback synchronous device
1.24 ratchov 147: */
1.57 ratchov 148: struct dev *
149: dev_new_loop(struct aparams *dipar, struct aparams *dopar, unsigned bufsz)
1.24 ratchov 150: {
151: struct aparams par;
152: unsigned cmin, cmax, rate;
1.57 ratchov 153: struct dev *d;
1.24 ratchov 154:
1.57 ratchov 155: d = malloc(sizeof(struct dev));
156: if (d == NULL) {
157: perror("malloc");
158: exit(1);
159: }
1.24 ratchov 160: cmin = (dipar->cmin < dopar->cmin) ? dipar->cmin : dopar->cmin;
161: cmax = (dipar->cmax > dopar->cmax) ? dipar->cmax : dopar->cmax;
162: rate = (dipar->rate > dopar->rate) ? dipar->rate : dopar->rate;
163: aparams_init(&par, cmin, cmax, rate);
1.57 ratchov 164: d->reqipar = par;
165: d->reqopar = par;
166: d->rate = rate;
167: d->reqround = (bufsz + 1) / 2;
168: d->reqbufsz = d->reqround * 2;
1.64 ! ratchov 169: d->reqmode = MODE_PLAY | MODE_REC | MODE_LOOP | MODE_MIDIMASK;
1.57 ratchov 170: d->pstate = DEV_CLOSED;
171: d->hold = 0;
1.62 ratchov 172: d->path = "loop";
1.57 ratchov 173: d->next = dev_list;
174: dev_list = d;
175: return d;
1.24 ratchov 176: }
1.1 ratchov 177:
1.51 ratchov 178: /*
179: * Create a MIDI thru box device
180: */
1.57 ratchov 181: struct dev *
182: dev_new_thru(void)
1.1 ratchov 183: {
1.57 ratchov 184: struct dev *d;
185:
186: d = malloc(sizeof(struct dev));
187: if (d == NULL) {
188: perror("malloc");
189: exit(1);
190: }
1.64 ! ratchov 191: d->reqmode = MODE_MIDIMASK;
1.57 ratchov 192: d->pstate = DEV_CLOSED;
193: d->hold = 0;
1.62 ratchov 194: d->path = "midithru";
1.57 ratchov 195: d->next = dev_list;
196: dev_list = d;
197: return d;
1.1 ratchov 198: }
199:
200: /*
1.51 ratchov 201: * Open the device with the dev_reqxxx capabilities. Setup a mixer, demuxer,
202: * monitor, midi control, and any necessary conversions.
1.1 ratchov 203: */
1.26 ratchov 204: int
1.57 ratchov 205: dev_open(struct dev *d)
1.1 ratchov 206: {
1.23 ratchov 207: struct file *f;
1.51 ratchov 208: struct aparams par;
1.1 ratchov 209: struct aproc *conv;
210: struct abuf *buf;
1.51 ratchov 211: unsigned siomode;
212:
1.57 ratchov 213: d->mode = d->reqmode;
214: d->round = d->reqround;
215: d->bufsz = d->reqbufsz;
216: d->ipar = d->reqipar;
217: d->opar = d->reqopar;
218: d->rec = NULL;
219: d->play = NULL;
220: d->mon = NULL;
1.61 jakemsr 221: d->mix = NULL;
222: d->sub = NULL;
1.57 ratchov 223: d->submon = NULL;
1.61 jakemsr 224: d->midi = NULL;
1.57 ratchov 225: d->rate = 0;
1.36 ratchov 226:
1.3 ratchov 227: /*
1.51 ratchov 228: * If needed, open the device (ie create dev_rec and dev_play)
1.3 ratchov 229: */
1.57 ratchov 230: if ((d->mode & (MODE_PLAY | MODE_REC)) && !(d->mode & MODE_LOOP)) {
231: siomode = d->mode & (MODE_PLAY | MODE_REC);
1.51 ratchov 232: f = (struct file *)siofile_new(&siofile_ops,
1.57 ratchov 233: d->path,
1.51 ratchov 234: &siomode,
1.57 ratchov 235: &d->ipar,
236: &d->opar,
237: &d->bufsz,
238: &d->round);
1.51 ratchov 239: if (f == NULL) {
1.39 ratchov 240: #ifdef DEBUG
1.51 ratchov 241: if (debug_level >= 1) {
1.62 ratchov 242: dbg_puts(d->path);
1.51 ratchov 243: dbg_puts(": failed to open audio device\n");
244: }
245: #endif
246: return 0;
1.39 ratchov 247: }
1.51 ratchov 248: if (!(siomode & MODE_PLAY))
1.57 ratchov 249: d->mode &= ~(MODE_PLAY | MODE_MON);
1.51 ratchov 250: if (!(siomode & MODE_REC))
1.57 ratchov 251: d->mode &= ~MODE_REC;
252: if ((d->mode & (MODE_PLAY | MODE_REC)) == 0) {
1.51 ratchov 253: #ifdef DEBUG
254: if (debug_level >= 1) {
1.62 ratchov 255: dbg_puts(d->path);
1.51 ratchov 256: dbg_puts(": mode not supported by device\n");
257: }
1.39 ratchov 258: #endif
1.51 ratchov 259: return 0;
260: }
1.57 ratchov 261: d->rate = d->mode & MODE_REC ? d->ipar.rate : d->opar.rate;
1.39 ratchov 262: #ifdef DEBUG
263: if (debug_level >= 2) {
1.57 ratchov 264: if (d->mode & MODE_REC) {
1.62 ratchov 265: dbg_puts(d->path);
266: dbg_puts(": recording ");
1.57 ratchov 267: aparams_dbg(&d->ipar);
1.51 ratchov 268: dbg_puts("\n");
269: }
1.57 ratchov 270: if (d->mode & MODE_PLAY) {
1.62 ratchov 271: dbg_puts(d->path);
272: dbg_puts(": playing ");
1.57 ratchov 273: aparams_dbg(&d->opar);
1.51 ratchov 274: dbg_puts("\n");
275: }
1.39 ratchov 276: }
277: #endif
1.57 ratchov 278: if (d->mode & MODE_REC) {
279: d->rec = rsio_new(f);
280: d->rec->refs++;
281: }
282: if (d->mode & MODE_PLAY) {
283: d->play = wsio_new(f);
284: d->play->refs++;
1.51 ratchov 285: }
1.3 ratchov 286: }
1.11 ratchov 287:
288: /*
1.51 ratchov 289: * Create the midi control end, or a simple thru box
290: * if there's no device
291: */
1.64 ! ratchov 292: if (d->mode & MODE_MIDIMASK) {
! 293: d->midi = (d->mode & (MODE_PLAY | MODE_RECMASK)) ?
! 294: ctl_new("ctl", d) : thru_new("thru");
! 295: d->midi->refs++;
! 296: }
1.51 ratchov 297:
298: /*
299: * Create mixer, demuxer and monitor
1.1 ratchov 300: */
1.57 ratchov 301: if (d->mode & MODE_PLAY) {
302: d->mix = mix_new("play", d->bufsz, d->round);
303: d->mix->refs++;
304: d->mix->u.mix.ctl = d->midi;
305: }
306: if (d->mode & MODE_REC) {
307: d->sub = sub_new("rec", d->bufsz, d->round);
308: d->sub->refs++;
1.51 ratchov 309: /*
310: * If not playing, use the record end as clock source
311: */
1.57 ratchov 312: if (!(d->mode & MODE_PLAY))
313: d->sub->u.sub.ctl = d->midi;
1.51 ratchov 314: }
1.57 ratchov 315: if (d->mode & MODE_LOOP) {
1.51 ratchov 316: /*
317: * connect mixer out to demuxer in
318: */
1.57 ratchov 319: buf = abuf_new(d->bufsz, &d->opar);
320: aproc_setout(d->mix, buf);
321: aproc_setin(d->sub, buf);
322:
323: d->mix->flags |= APROC_QUIT;
324: d->sub->flags |= APROC_QUIT;
325: d->rate = d->opar.rate;
1.51 ratchov 326: }
1.57 ratchov 327: if (d->rec) {
328: aparams_init(&par, d->ipar.cmin, d->ipar.cmax, d->rate);
1.51 ratchov 329:
1.1 ratchov 330: /*
1.51 ratchov 331: * Create device <-> demuxer buffer
1.1 ratchov 332: */
1.57 ratchov 333: buf = abuf_new(d->bufsz, &d->ipar);
334: aproc_setout(d->rec, buf);
1.1 ratchov 335:
336: /*
1.51 ratchov 337: * Insert a converter, if needed.
1.1 ratchov 338: */
1.57 ratchov 339: if (!aparams_eqenc(&d->ipar, &par)) {
340: conv = dec_new("rec", &d->ipar);
1.1 ratchov 341: aproc_setin(conv, buf);
1.57 ratchov 342: buf = abuf_new(d->round, &par);
1.1 ratchov 343: aproc_setout(conv, buf);
344: }
1.57 ratchov 345: d->ipar = par;
346: aproc_setin(d->sub, buf);
1.1 ratchov 347: }
1.57 ratchov 348: if (d->play) {
349: aparams_init(&par, d->opar.cmin, d->opar.cmax, d->rate);
1.1 ratchov 350:
351: /*
1.51 ratchov 352: * Create device <-> mixer buffer
1.1 ratchov 353: */
1.57 ratchov 354: buf = abuf_new(d->bufsz, &d->opar);
355: aproc_setin(d->play, buf);
1.25 ratchov 356:
1.1 ratchov 357: /*
1.27 ratchov 358: * Append a converter, if needed.
1.1 ratchov 359: */
1.57 ratchov 360: if (!aparams_eqenc(&par, &d->opar)) {
361: conv = enc_new("play", &d->opar);
1.1 ratchov 362: aproc_setout(conv, buf);
1.57 ratchov 363: buf = abuf_new(d->round, &par);
1.1 ratchov 364: aproc_setin(conv, buf);
365: }
1.57 ratchov 366: d->opar = par;
367: aproc_setout(d->mix, buf);
1.1 ratchov 368: }
1.57 ratchov 369: if (d->mode & MODE_MON) {
370: d->mon = mon_new("mon", d->bufsz);
371: d->mon->refs++;
372: buf = abuf_new(d->bufsz, &d->opar);
373: aproc_setout(d->mon, buf);
1.46 ratchov 374:
375: /*
376: * Append a "sub" to which clients will connect.
377: */
1.57 ratchov 378: d->submon = sub_new("mon", d->bufsz, d->round);
379: d->submon->refs++;
380: aproc_setin(d->submon, buf);
1.46 ratchov 381:
382: /*
1.51 ratchov 383: * Attach to the mixer
1.46 ratchov 384: */
1.57 ratchov 385: d->mix->u.mix.mon = d->mon;
386: d->mon->refs++;
1.46 ratchov 387: }
1.39 ratchov 388: #ifdef DEBUG
1.51 ratchov 389: if (debug_level >= 2) {
1.57 ratchov 390: if (d->mode & (MODE_PLAY | MODE_RECMASK)) {
1.62 ratchov 391: dbg_puts(d->path);
392: dbg_puts(": block size is ");
1.57 ratchov 393: dbg_putu(d->round);
1.51 ratchov 394: dbg_puts(" frames, using ");
1.57 ratchov 395: dbg_putu(d->bufsz / d->round);
1.51 ratchov 396: dbg_puts(" blocks\n");
397: }
1.39 ratchov 398: }
399: #endif
1.57 ratchov 400: d->pstate = DEV_INIT;
1.26 ratchov 401: return 1;
1.1 ratchov 402: }
403:
404: /*
1.27 ratchov 405: * Cleanly stop and drain everything and close the device
406: * once both play chain and record chain are gone.
1.1 ratchov 407: */
408: void
1.57 ratchov 409: dev_close(struct dev *d)
1.1 ratchov 410: {
411: struct file *f;
412:
1.50 ratchov 413: /*
414: * if the device is starting, ensure it actually starts
415: * so buffers are drained, else clear any buffers
416: */
1.57 ratchov 417: switch (d->pstate) {
1.50 ratchov 418: case DEV_START:
419: #ifdef DEBUG
420: if (debug_level >= 3)
421: dbg_puts("draining device\n");
422: #endif
1.57 ratchov 423: dev_start(d);
1.50 ratchov 424: break;
425: case DEV_INIT:
426: #ifdef DEBUG
427: if (debug_level >= 3)
428: dbg_puts("flushing device\n");
429: #endif
1.57 ratchov 430: dev_clear(d);
1.50 ratchov 431: break;
432: }
1.39 ratchov 433: #ifdef DEBUG
434: if (debug_level >= 2)
1.51 ratchov 435: dbg_puts("closing device\n");
1.39 ratchov 436: #endif
1.51 ratchov 437:
1.57 ratchov 438: if (d->mix) {
1.3 ratchov 439: /*
1.32 ratchov 440: * Put the mixer in ``autoquit'' state and generate
441: * EOF on all inputs connected it. Once buffers are
442: * drained the mixer will terminate and shutdown the
443: * device.
1.3 ratchov 444: *
445: * NOTE: since file_eof() can destroy the file and
446: * reorder the file_list, we have to restart the loop
1.27 ratchov 447: * after each call to file_eof().
1.3 ratchov 448: */
1.57 ratchov 449: if (APROC_OK(d->mix))
450: mix_quit(d->mix);
1.51 ratchov 451:
452: /*
453: * XXX: handle this in mix_done()
454: */
1.57 ratchov 455: if (APROC_OK(d->mix->u.mix.mon)) {
456: d->mix->u.mix.mon->refs--;
457: aproc_del(d->mix->u.mix.mon);
458: d->mix->u.mix.mon = NULL;
1.46 ratchov 459: }
1.32 ratchov 460: restart_mix:
1.3 ratchov 461: LIST_FOREACH(f, &file_list, entry) {
1.32 ratchov 462: if (f->rproc != NULL &&
1.57 ratchov 463: aproc_depend(d->mix, f->rproc)) {
1.3 ratchov 464: file_eof(f);
1.32 ratchov 465: goto restart_mix;
1.3 ratchov 466: }
467: }
1.59 ratchov 468: } else if (d->sub) {
1.3 ratchov 469: /*
1.32 ratchov 470: * Same as above, but since there's no mixer,
471: * we generate EOF on the record-end of the
472: * device.
473: */
474: restart_sub:
475: LIST_FOREACH(f, &file_list, entry) {
476: if (f->rproc != NULL &&
1.59 ratchov 477: aproc_depend(d->sub, f->rproc)) {
1.32 ratchov 478: file_eof(f);
479: goto restart_sub;
1.59 ratchov 480: }
481: }
482: } else if (d->submon) {
483: /*
484: * Same as above
485: */
486: restart_submon:
487: LIST_FOREACH(f, &file_list, entry) {
488: if (f->rproc != NULL &&
489: aproc_depend(d->submon, f->rproc)) {
490: file_eof(f);
491: goto restart_submon;
1.23 ratchov 492: }
1.32 ratchov 493: }
494: }
1.57 ratchov 495: if (d->midi) {
496: d->midi->flags |= APROC_QUIT;
497: if (LIST_EMPTY(&d->midi->ins))
498: aproc_del(d->midi);
1.36 ratchov 499: restart_midi:
500: LIST_FOREACH(f, &file_list, entry) {
501: if (f->rproc &&
1.57 ratchov 502: aproc_depend(d->midi, f->rproc)) {
1.36 ratchov 503: file_eof(f);
504: goto restart_midi;
505: }
506: }
507: }
1.57 ratchov 508: if (d->mix) {
509: if (--d->mix->refs == 0 && (d->mix->flags & APROC_ZOMB))
510: aproc_del(d->mix);
511: d->mix = NULL;
512: }
513: if (d->play) {
514: if (--d->play->refs == 0 && (d->play->flags & APROC_ZOMB))
515: aproc_del(d->play);
516: d->play = NULL;
517: }
518: if (d->sub) {
519: if (--d->sub->refs == 0 && (d->sub->flags & APROC_ZOMB))
520: aproc_del(d->sub);
521: d->sub = NULL;
522: }
523: if (d->rec) {
524: if (--d->rec->refs == 0 && (d->rec->flags & APROC_ZOMB))
525: aproc_del(d->rec);
526: d->rec = NULL;
527: }
528: if (d->submon) {
529: if (--d->submon->refs == 0 && (d->submon->flags & APROC_ZOMB))
530: aproc_del(d->submon);
531: d->submon = NULL;
532: }
533: if (d->mon) {
534: if (--d->mon->refs == 0 && (d->mon->flags & APROC_ZOMB))
535: aproc_del(d->mon);
536: d->mon = NULL;
537: }
538: if (d->midi) {
539: if (--d->midi->refs == 0 && (d->midi->flags & APROC_ZOMB))
540: aproc_del(d->midi);
541: d->midi = NULL;
1.32 ratchov 542: }
1.57 ratchov 543: d->pstate = DEV_CLOSED;
1.51 ratchov 544: }
545:
546: /*
1.60 ratchov 547: * Unless the device is already in process of closing, request it to close
548: */
549: void
550: dev_drain(struct dev *d)
551: {
552: if (d->pstate != DEV_CLOSED)
553: dev_close(d);
554: }
555:
556: /*
1.51 ratchov 557: * Free the device
558: */
559: void
1.57 ratchov 560: dev_del(struct dev *d)
1.51 ratchov 561: {
1.57 ratchov 562: struct dev **p;
563:
1.60 ratchov 564: dev_drain(d);
1.57 ratchov 565: for (p = &dev_list; *p != d; p = &(*p)->next) {
566: #ifdef DEBUG
567: if (*p == NULL) {
568: dbg_puts("device to delete not on the list\n");
569: dbg_panic();
570: }
571: #endif
572: }
573: *p = d->next;
574: free(d);
1.51 ratchov 575: }
576:
577: /*
578: * Open a MIDI device and connect it to the thru box
579: */
580: int
1.57 ratchov 581: dev_thruadd(struct dev *d, char *name, int in, int out)
1.51 ratchov 582: {
583: struct file *f;
584: struct abuf *rbuf = NULL, *wbuf = NULL;
585: struct aproc *rproc, *wproc;
586:
1.57 ratchov 587: if (!dev_ref(d))
1.51 ratchov 588: return 0;
589: f = (struct file *)miofile_new(&miofile_ops, name, in, out);
590: if (f == NULL)
591: return 0;
592: if (in) {
593: rproc = rfile_new(f);
594: rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
595: aproc_setout(rproc, rbuf);
596: }
597: if (out) {
598: wproc = wfile_new(f);
599: wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
600: aproc_setin(wproc, wbuf);
601: }
1.57 ratchov 602: dev_midiattach(d, rbuf, wbuf);
1.51 ratchov 603: return 1;
604: }
605:
606: /*
607: * Attach a bi-directional MIDI stream to the MIDI device
608: */
609: void
1.57 ratchov 610: dev_midiattach(struct dev *d, struct abuf *ibuf, struct abuf *obuf)
1.51 ratchov 611: {
612: if (ibuf)
1.57 ratchov 613: aproc_setin(d->midi, ibuf);
1.51 ratchov 614: if (obuf) {
1.57 ratchov 615: aproc_setout(d->midi, obuf);
1.51 ratchov 616: if (ibuf) {
617: ibuf->duplex = obuf;
618: obuf->duplex = ibuf;
619: }
1.1 ratchov 620: }
621: }
622:
1.51 ratchov 623: unsigned
1.57 ratchov 624: dev_roundof(struct dev *d, unsigned newrate)
1.51 ratchov 625: {
1.57 ratchov 626: return (d->round * newrate + d->rate / 2) / d->rate;
1.51 ratchov 627: }
628:
1.1 ratchov 629: /*
1.27 ratchov 630: * Start the (paused) device. By default it's paused.
1.1 ratchov 631: */
632: void
1.57 ratchov 633: dev_start(struct dev *d)
1.1 ratchov 634: {
1.22 ratchov 635: struct file *f;
636:
1.46 ratchov 637: #ifdef DEBUG
638: if (debug_level >= 2)
1.51 ratchov 639: dbg_puts("starting device\n");
1.46 ratchov 640: #endif
1.57 ratchov 641: d->pstate = DEV_RUN;
642: if (d->mode & MODE_LOOP)
1.52 ratchov 643: return;
1.57 ratchov 644: if (APROC_OK(d->mix))
645: d->mix->flags |= APROC_DROP;
646: if (APROC_OK(d->sub))
647: d->sub->flags |= APROC_DROP;
648: if (APROC_OK(d->submon))
649: d->submon->flags |= APROC_DROP;
650: if (APROC_OK(d->play) && d->play->u.io.file) {
651: f = d->play->u.io.file;
1.22 ratchov 652: f->ops->start(f);
1.57 ratchov 653: } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
654: f = d->rec->u.io.file;
1.22 ratchov 655: f->ops->start(f);
656: }
1.1 ratchov 657: }
658:
659: /*
1.46 ratchov 660: * Pause the device. This may trigger context switches,
661: * so it shouldn't be called from aproc methods
1.1 ratchov 662: */
663: void
1.57 ratchov 664: dev_stop(struct dev *d)
1.1 ratchov 665: {
1.22 ratchov 666: struct file *f;
667:
1.52 ratchov 668: #ifdef DEBUG
669: if (debug_level >= 2)
1.57 ratchov 670: dbg_puts("device stopped\n");
1.52 ratchov 671: #endif
1.57 ratchov 672: d->pstate = DEV_INIT;
673: if (d->mode & MODE_LOOP)
1.52 ratchov 674: return;
1.57 ratchov 675: if (APROC_OK(d->play) && d->play->u.io.file) {
676: f = d->play->u.io.file;
1.22 ratchov 677: f->ops->stop(f);
1.57 ratchov 678: } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
679: f = d->rec->u.io.file;
1.22 ratchov 680: f->ops->stop(f);
681: }
1.57 ratchov 682: if (APROC_OK(d->mix))
683: d->mix->flags &= ~APROC_DROP;
684: if (APROC_OK(d->sub))
685: d->sub->flags &= ~APROC_DROP;
686: if (APROC_OK(d->submon))
687: d->submon->flags &= ~APROC_DROP;
1.51 ratchov 688: }
689:
690: int
1.57 ratchov 691: dev_ref(struct dev *d)
1.51 ratchov 692: {
693: #ifdef DEBUG
694: if (debug_level >= 3)
695: dbg_puts("device requested\n");
696: #endif
1.57 ratchov 697: if (d->pstate == DEV_CLOSED && !dev_open(d)) {
698: if (d->hold)
699: dev_del(d);
1.51 ratchov 700: return 0;
1.57 ratchov 701: }
702: d->refcnt++;
1.51 ratchov 703: return 1;
704: }
705:
706: void
1.57 ratchov 707: dev_unref(struct dev *d)
1.51 ratchov 708: {
709: #ifdef DEBUG
710: if (debug_level >= 3)
711: dbg_puts("device released\n");
712: #endif
1.57 ratchov 713: d->refcnt--;
714: if (d->refcnt == 0 && d->pstate == DEV_INIT && !d->hold)
715: dev_close(d);
1.51 ratchov 716: }
717:
718: /*
719: * There are actions (like start/stop/close ... ) that may trigger aproc
720: * operations, a thus cannot be started from aproc context.
721: * To avoid problems, aprocs only change the s!tate of the device,
722: * and actual operations are triggered from the main loop,
723: * outside the aproc code path.
724: *
725: * The following routine invokes pending actions, returns 0
726: * on fatal error
727: */
728: int
1.57 ratchov 729: dev_run(struct dev *d)
1.51 ratchov 730: {
1.57 ratchov 731: if (d->pstate == DEV_CLOSED)
1.51 ratchov 732: return 1;
733: /*
734: * check if device isn't gone
735: */
1.57 ratchov 736: if (((d->mode & MODE_PLAY) && !APROC_OK(d->mix)) ||
737: ((d->mode & MODE_REC) && !APROC_OK(d->sub)) ||
738: ((d->mode & MODE_MON) && !APROC_OK(d->submon))) {
1.51 ratchov 739: #ifdef DEBUG
740: if (debug_level >= 1)
741: dbg_puts("device disappeared\n");
742: #endif
1.57 ratchov 743: if (d->hold) {
744: dev_del(d);
745: return 0;
746: }
747: dev_close(d);
748: return 1;
1.51 ratchov 749: }
1.57 ratchov 750: switch (d->pstate) {
1.51 ratchov 751: case DEV_INIT:
752: /* nothing */
753: break;
754: case DEV_START:
1.57 ratchov 755: dev_start(d);
1.51 ratchov 756: /* PASSTHROUGH */
757: case DEV_RUN:
758: /*
759: * if the device is not used, then stop it
760: */
1.57 ratchov 761: if ((!APROC_OK(d->mix) ||
762: d->mix->u.mix.idle > 2 * d->bufsz) &&
763: (!APROC_OK(d->sub) ||
764: d->sub->u.sub.idle > 2 * d->bufsz) &&
765: (!APROC_OK(d->submon) ||
766: d->submon->u.sub.idle > 2 * d->bufsz) &&
767: (!APROC_OK(d->midi) ||
768: d->midi->u.ctl.tstate != CTL_RUN)) {
1.51 ratchov 769: #ifdef DEBUG
770: if (debug_level >= 3)
771: dbg_puts("device idle, suspending\n");
1.46 ratchov 772: #endif
1.57 ratchov 773: dev_stop(d);
774: if (d->refcnt == 0 && !d->hold)
775: dev_close(d);
1.58 ratchov 776: else
1.57 ratchov 777: dev_clear(d);
1.51 ratchov 778: }
779: break;
780: }
781: return 1;
782: }
783:
784: /*
1.58 ratchov 785: * If the device is paused, then resume it.
1.51 ratchov 786: * This routine can be called from aproc context.
787: */
788: void
1.57 ratchov 789: dev_wakeup(struct dev *d)
1.51 ratchov 790: {
1.57 ratchov 791: if (d->pstate == DEV_INIT)
792: d->pstate = DEV_START;
1.1 ratchov 793: }
794:
795: /*
1.27 ratchov 796: * Find the end points connected to the mix/sub.
1.14 ratchov 797: */
798: int
1.57 ratchov 799: dev_getep(struct dev *d,
800: unsigned mode, struct abuf **sibuf, struct abuf **sobuf)
1.14 ratchov 801: {
802: struct abuf *ibuf, *obuf;
803:
1.46 ratchov 804: if (mode & MODE_PLAY) {
1.57 ratchov 805: if (!APROC_OK(d->mix))
1.46 ratchov 806: return 0;
1.14 ratchov 807: ibuf = *sibuf;
808: for (;;) {
809: if (!ibuf || !ibuf->rproc) {
1.39 ratchov 810: #ifdef DEBUG
811: if (debug_level >= 3) {
812: abuf_dbg(*sibuf);
813: dbg_puts(": not connected to device\n");
814: }
815: #endif
1.14 ratchov 816: return 0;
817: }
1.57 ratchov 818: if (ibuf->rproc == d->mix)
1.14 ratchov 819: break;
1.49 ratchov 820: ibuf = LIST_FIRST(&ibuf->rproc->outs);
1.14 ratchov 821: }
1.21 ratchov 822: *sibuf = ibuf;
1.14 ratchov 823: }
1.46 ratchov 824: if (mode & MODE_REC) {
1.57 ratchov 825: if (!APROC_OK(d->sub))
1.46 ratchov 826: return 0;
1.14 ratchov 827: obuf = *sobuf;
828: for (;;) {
829: if (!obuf || !obuf->wproc) {
1.39 ratchov 830: #ifdef DEBUG
831: if (debug_level >= 3) {
832: abuf_dbg(*sobuf);
833: dbg_puts(": not connected to device\n");
834: }
835: #endif
1.14 ratchov 836: return 0;
837: }
1.57 ratchov 838: if (obuf->wproc == d->sub)
1.14 ratchov 839: break;
1.49 ratchov 840: obuf = LIST_FIRST(&obuf->wproc->ins);
1.14 ratchov 841: }
1.21 ratchov 842: *sobuf = obuf;
1.14 ratchov 843: }
1.46 ratchov 844: if (mode & MODE_MON) {
1.57 ratchov 845: if (!APROC_OK(d->submon))
1.46 ratchov 846: return 0;
847: obuf = *sobuf;
848: for (;;) {
849: if (!obuf || !obuf->wproc) {
850: #ifdef DEBUG
851: if (debug_level >= 3) {
852: abuf_dbg(*sobuf);
853: dbg_puts(": not connected to device\n");
854: }
855: #endif
856: return 0;
857: }
1.57 ratchov 858: if (obuf->wproc == d->submon)
1.46 ratchov 859: break;
1.49 ratchov 860: obuf = LIST_FIRST(&obuf->wproc->ins);
1.46 ratchov 861: }
862: *sobuf = obuf;
863: }
1.14 ratchov 864: return 1;
865: }
866:
867: /*
1.27 ratchov 868: * Sync play buffer to rec buffer (for instance when one of
869: * them underruns/overruns).
1.1 ratchov 870: */
871: void
1.57 ratchov 872: dev_sync(struct dev *d, unsigned mode, struct abuf *ibuf, struct abuf *obuf)
1.1 ratchov 873: {
1.53 ratchov 874: int delta, offs;
1.57 ratchov 875: struct abuf *mbuf = NULL;
1.3 ratchov 876:
1.57 ratchov 877: if (!dev_getep(d, mode, &ibuf, &obuf))
1.3 ratchov 878: return;
879: /*
1.27 ratchov 880: * Calculate delta, the number of frames the play chain is ahead
1.3 ratchov 881: * of the record chain. It's necessary to schedule silences (or
882: * drops) in order to start playback and record in sync.
883: */
1.53 ratchov 884: offs = 0;
885: delta = 0;
1.57 ratchov 886: if (APROC_OK(d->mix)) {
887: mbuf = LIST_FIRST(&d->mix->outs);
1.53 ratchov 888: offs += mbuf->w.mix.todo;
1.57 ratchov 889: delta += d->mix->u.mix.lat;
1.53 ratchov 890: }
1.57 ratchov 891: if (APROC_OK(d->sub))
892: delta += d->sub->u.sub.lat;
1.39 ratchov 893: #ifdef DEBUG
894: if (debug_level >= 3) {
1.53 ratchov 895: dbg_puts("syncing device");
1.57 ratchov 896: if (APROC_OK(d->mix)) {
1.51 ratchov 897: dbg_puts(", ");
1.57 ratchov 898: aproc_dbg(d->mix);
1.53 ratchov 899: dbg_puts(": todo = ");
900: dbg_putu(mbuf->w.mix.todo);
901: dbg_puts(": lat = ");
1.57 ratchov 902: dbg_putu(d->mix->u.mix.lat);
1.46 ratchov 903: }
1.57 ratchov 904: if (APROC_OK(d->sub)) {
1.51 ratchov 905: dbg_puts(", ");
1.57 ratchov 906: aproc_dbg(d->sub);
1.53 ratchov 907: dbg_puts(": lat = ");
1.57 ratchov 908: dbg_putu(d->sub->u.sub.lat);
1.46 ratchov 909: }
1.39 ratchov 910: dbg_puts("\n");
911: }
912: #endif
1.53 ratchov 913: if (mode & MODE_PLAY)
914: mix_drop(ibuf, -offs);
915: if (mode & MODE_RECMASK)
916: sub_silence(obuf, -(offs + delta));
1.36 ratchov 917: }
918:
919: /*
920: * return the current latency (in frames), ie the latency that
921: * a stream would have if dev_attach() is called on it.
922: */
923: int
1.57 ratchov 924: dev_getpos(struct dev *d)
1.36 ratchov 925: {
1.53 ratchov 926: struct abuf *mbuf = NULL;
1.36 ratchov 927:
1.57 ratchov 928: if (APROC_OK(d->mix)) {
929: mbuf = LIST_FIRST(&d->mix->outs);
930: return -(mbuf->w.mix.todo + d->mix->u.mix.lat);
1.54 ratchov 931: } else
932: return 0;
1.1 ratchov 933: }
934:
935: /*
1.27 ratchov 936: * Attach the given input and output buffers to the mixer and the
1.1 ratchov 937: * multiplexer respectively. The operation is done synchronously, so
938: * both buffers enter in sync. If buffers do not match play
1.27 ratchov 939: * and rec.
1.1 ratchov 940: */
941: void
1.57 ratchov 942: dev_attach(struct dev *d, char *name, unsigned mode,
1.48 ratchov 943: struct abuf *ibuf, struct aparams *sipar, unsigned inch,
944: struct abuf *obuf, struct aparams *sopar, unsigned onch,
1.46 ratchov 945: unsigned xrun, int vol)
1.1 ratchov 946: {
947: struct abuf *pbuf = NULL, *rbuf = NULL;
1.12 ratchov 948: struct aparams ipar, opar;
1.1 ratchov 949: struct aproc *conv;
1.48 ratchov 950: unsigned round, nblk, nch;
1.20 ratchov 951:
1.46 ratchov 952: #ifdef DEBUG
1.57 ratchov 953: if ((!APROC_OK(d->mix) && (mode & MODE_PLAY)) ||
954: (!APROC_OK(d->sub) && (mode & MODE_REC)) ||
955: (!APROC_OK(d->submon) && (mode & MODE_MON))) {
1.46 ratchov 956: dbg_puts("mode beyond device mode, not attaching\n");
957: return;
958: }
959: #endif
960: if (mode & MODE_PLAY) {
1.12 ratchov 961: ipar = *sipar;
1.57 ratchov 962: pbuf = LIST_FIRST(&d->mix->outs);
963: nblk = (d->bufsz / d->round + 3) / 4;
964: round = dev_roundof(d, ipar.rate);
1.48 ratchov 965: nch = ipar.cmax - ipar.cmin + 1;
1.57 ratchov 966: if (!aparams_eqenc(&ipar, &d->opar)) {
1.10 ratchov 967: conv = dec_new(name, &ipar);
1.57 ratchov 968: ipar.bps = d->opar.bps;
969: ipar.bits = d->opar.bits;
970: ipar.sig = d->opar.sig;
971: ipar.le = d->opar.le;
972: ipar.msb = d->opar.msb;
1.25 ratchov 973: aproc_setin(conv, ibuf);
1.20 ratchov 974: ibuf = abuf_new(nblk * round, &ipar);
1.9 ratchov 975: aproc_setout(conv, ibuf);
1.8 ratchov 976: }
1.48 ratchov 977: if (inch > 0 && nch >= inch * 2) {
978: conv = join_new(name);
979: aproc_setin(conv, ibuf);
980: ipar.cmax = ipar.cmin + inch - 1;
981: ibuf = abuf_new(nblk * round, &ipar);
982: aproc_setout(conv, ibuf);
983: }
1.57 ratchov 984: if (!aparams_eqrate(&ipar, &d->opar)) {
985: conv = resamp_new(name, round, d->round);
986: ipar.rate = d->opar.rate;
987: round = d->round;
1.5 ratchov 988: aproc_setin(conv, ibuf);
1.20 ratchov 989: ibuf = abuf_new(nblk * round, &ipar);
1.5 ratchov 990: aproc_setout(conv, ibuf);
1.1 ratchov 991: }
1.48 ratchov 992: if (inch > 0 && nch * 2 <= inch) {
993: conv = join_new(name);
994: aproc_setin(conv, ibuf);
995: ipar.cmax = ipar.cmin + inch - 1;
996: ibuf = abuf_new(nblk * round, &ipar);
997: aproc_setout(conv, ibuf);
998: }
1.57 ratchov 999: aproc_setin(d->mix, ibuf);
1.46 ratchov 1000: ibuf->r.mix.xrun = xrun;
1.31 ratchov 1001: ibuf->r.mix.maxweight = vol;
1.57 ratchov 1002: mix_setmaster(d->mix);
1.1 ratchov 1003: }
1.46 ratchov 1004: if (mode & MODE_REC) {
1.12 ratchov 1005: opar = *sopar;
1.57 ratchov 1006: rbuf = LIST_FIRST(&d->sub->ins);
1007: round = dev_roundof(d, opar.rate);
1008: nblk = (d->bufsz / d->round + 3) / 4;
1.48 ratchov 1009: nch = opar.cmax - opar.cmin + 1;
1.57 ratchov 1010: if (!aparams_eqenc(&opar, &d->ipar)) {
1.10 ratchov 1011: conv = enc_new(name, &opar);
1.57 ratchov 1012: opar.bps = d->ipar.bps;
1013: opar.bits = d->ipar.bits;
1014: opar.sig = d->ipar.sig;
1015: opar.le = d->ipar.le;
1016: opar.msb = d->ipar.msb;
1.9 ratchov 1017: aproc_setout(conv, obuf);
1.20 ratchov 1018: obuf = abuf_new(nblk * round, &opar);
1.9 ratchov 1019: aproc_setin(conv, obuf);
1.8 ratchov 1020: }
1.48 ratchov 1021: if (onch > 0 && nch >= onch * 2) {
1022: conv = join_new(name);
1023: aproc_setout(conv, obuf);
1024: opar.cmax = opar.cmin + onch - 1;
1025: obuf = abuf_new(nblk * round, &opar);
1026: aproc_setin(conv, obuf);
1027: }
1.57 ratchov 1028: if (!aparams_eqrate(&opar, &d->ipar)) {
1029: conv = resamp_new(name, d->round, round);
1030: opar.rate = d->ipar.rate;
1031: round = d->round;
1.1 ratchov 1032: aproc_setout(conv, obuf);
1.20 ratchov 1033: obuf = abuf_new(nblk * round, &opar);
1.1 ratchov 1034: aproc_setin(conv, obuf);
1035: }
1.48 ratchov 1036: if (onch > 0 && nch * 2 <= onch) {
1037: conv = join_new(name);
1038: aproc_setout(conv, obuf);
1039: opar.cmax = opar.cmin + onch - 1;
1040: obuf = abuf_new(nblk * round, &opar);
1041: aproc_setin(conv, obuf);
1042: }
1.57 ratchov 1043: aproc_setout(d->sub, obuf);
1.46 ratchov 1044: obuf->w.sub.xrun = xrun;
1045: }
1046: if (mode & MODE_MON) {
1047: opar = *sopar;
1.57 ratchov 1048: rbuf = LIST_FIRST(&d->submon->ins);
1049: round = dev_roundof(d, opar.rate);
1050: nblk = (d->bufsz / d->round + 3) / 4;
1.48 ratchov 1051: nch = opar.cmax - opar.cmin + 1;
1.57 ratchov 1052: if (!aparams_eqenc(&opar, &d->opar)) {
1.46 ratchov 1053: conv = enc_new(name, &opar);
1.57 ratchov 1054: opar.bps = d->opar.bps;
1055: opar.bits = d->opar.bits;
1056: opar.sig = d->opar.sig;
1057: opar.le = d->opar.le;
1058: opar.msb = d->opar.msb;
1.46 ratchov 1059: aproc_setout(conv, obuf);
1060: obuf = abuf_new(nblk * round, &opar);
1061: aproc_setin(conv, obuf);
1062: }
1.48 ratchov 1063: if (onch > 0 && nch >= onch * 2) {
1064: conv = join_new(name);
1065: aproc_setout(conv, obuf);
1066: opar.cmax = opar.cmin + onch - 1;
1067: obuf = abuf_new(nblk * round, &opar);
1068: aproc_setin(conv, obuf);
1069: }
1.57 ratchov 1070: if (!aparams_eqrate(&opar, &d->opar)) {
1071: conv = resamp_new(name, d->round, round);
1072: opar.rate = d->opar.rate;
1073: round = d->round;
1.46 ratchov 1074: aproc_setout(conv, obuf);
1.48 ratchov 1075: obuf = abuf_new(nblk * round, &opar);
1076: aproc_setin(conv, obuf);
1077: }
1078: if (onch > 0 && nch * 2 <= onch) {
1079: conv = join_new(name);
1080: aproc_setout(conv, obuf);
1081: opar.cmax = opar.cmin + onch - 1;
1.46 ratchov 1082: obuf = abuf_new(nblk * round, &opar);
1083: aproc_setin(conv, obuf);
1084: }
1.57 ratchov 1085: aproc_setout(d->submon, obuf);
1.46 ratchov 1086: obuf->w.sub.xrun = xrun;
1.1 ratchov 1087: }
1088:
1089: /*
1.27 ratchov 1090: * Sync play to record.
1.1 ratchov 1091: */
1.46 ratchov 1092: if ((mode & MODE_PLAY) && (mode & MODE_RECMASK)) {
1.3 ratchov 1093: ibuf->duplex = obuf;
1094: obuf->duplex = ibuf;
1.13 ratchov 1095: }
1.57 ratchov 1096: dev_sync(d, mode, ibuf, obuf);
1.14 ratchov 1097: }
1098:
1099: /*
1.27 ratchov 1100: * Change the playback volume of the given stream.
1.14 ratchov 1101: */
1102: void
1.57 ratchov 1103: dev_setvol(struct dev *d, struct abuf *ibuf, int vol)
1.14 ratchov 1104: {
1.39 ratchov 1105: #ifdef DEBUG
1106: if (debug_level >= 3) {
1107: abuf_dbg(ibuf);
1108: dbg_puts(": setting volume to ");
1109: dbg_putu(vol);
1110: dbg_puts("\n");
1111: }
1112: #endif
1.57 ratchov 1113: if (!dev_getep(d, MODE_PLAY, &ibuf, NULL)) {
1.14 ratchov 1114: return;
1.16 ratchov 1115: }
1.31 ratchov 1116: ibuf->r.mix.vol = vol;
1.13 ratchov 1117: }
1118:
1119: /*
1.27 ratchov 1120: * Clear buffers of the play and record chains so that when the device
1121: * is started, playback and record start in sync.
1.13 ratchov 1122: */
1123: void
1.57 ratchov 1124: dev_clear(struct dev *d)
1.13 ratchov 1125: {
1126: struct abuf *buf;
1127:
1.57 ratchov 1128: if (APROC_OK(d->mix)) {
1.39 ratchov 1129: #ifdef DEBUG
1.57 ratchov 1130: if (!LIST_EMPTY(&d->mix->ins)) {
1.39 ratchov 1131: dbg_puts("play end not idle, can't clear device\n");
1132: dbg_panic();
1133: }
1134: #endif
1.57 ratchov 1135: buf = LIST_FIRST(&d->mix->outs);
1.13 ratchov 1136: while (buf) {
1137: abuf_clear(buf);
1.49 ratchov 1138: buf = LIST_FIRST(&buf->rproc->outs);
1.13 ratchov 1139: }
1.57 ratchov 1140: mix_clear(d->mix);
1.13 ratchov 1141: }
1.57 ratchov 1142: if (APROC_OK(d->sub)) {
1.39 ratchov 1143: #ifdef DEBUG
1.57 ratchov 1144: if (!LIST_EMPTY(&d->sub->outs)) {
1.39 ratchov 1145: dbg_puts("record end not idle, can't clear device\n");
1146: dbg_panic();
1147: }
1148: #endif
1.57 ratchov 1149: buf = LIST_FIRST(&d->sub->ins);
1.13 ratchov 1150: while (buf) {
1151: abuf_clear(buf);
1.49 ratchov 1152: buf = LIST_FIRST(&buf->wproc->ins);
1.13 ratchov 1153: }
1.57 ratchov 1154: sub_clear(d->sub);
1.40 ratchov 1155: }
1.57 ratchov 1156: if (APROC_OK(d->submon)) {
1.46 ratchov 1157: #ifdef DEBUG
1.57 ratchov 1158: if (!LIST_EMPTY(&d->submon->outs)) {
1.46 ratchov 1159: dbg_puts("monitoring end not idle, can't clear device\n");
1160: dbg_panic();
1161: }
1162: #endif
1.57 ratchov 1163: buf = LIST_FIRST(&d->submon->ins);
1.46 ratchov 1164: while (buf) {
1165: abuf_clear(buf);
1.49 ratchov 1166: buf = LIST_FIRST(&buf->wproc->ins);
1.46 ratchov 1167: }
1.57 ratchov 1168: sub_clear(d->submon);
1169: mon_clear(d->mon);
1.1 ratchov 1170: }
1171: }