Annotation of src/usr.bin/aucat/dev.c, Revision 1.61
1.61 ! jakemsr 1: /* $OpenBSD: dev.c,v 1.60 2010/06/25 07:32:05 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;
169: d->reqmode = MODE_PLAY | MODE_REC | MODE_LOOP;
170: d->pstate = DEV_CLOSED;
171: d->hold = 0;
172: d->next = dev_list;
173: dev_list = d;
174: return d;
1.24 ratchov 175: }
1.1 ratchov 176:
1.51 ratchov 177: /*
178: * Create a MIDI thru box device
179: */
1.57 ratchov 180: struct dev *
181: dev_new_thru(void)
1.1 ratchov 182: {
1.57 ratchov 183: struct dev *d;
184:
185: d = malloc(sizeof(struct dev));
186: if (d == NULL) {
187: perror("malloc");
188: exit(1);
189: }
190: d->reqmode = 0;
191: d->pstate = DEV_CLOSED;
192: d->hold = 0;
193: d->next = dev_list;
194: dev_list = d;
195: return d;
1.1 ratchov 196: }
197:
198: /*
1.51 ratchov 199: * Open the device with the dev_reqxxx capabilities. Setup a mixer, demuxer,
200: * monitor, midi control, and any necessary conversions.
1.1 ratchov 201: */
1.26 ratchov 202: int
1.57 ratchov 203: dev_open(struct dev *d)
1.1 ratchov 204: {
1.23 ratchov 205: struct file *f;
1.51 ratchov 206: struct aparams par;
1.1 ratchov 207: struct aproc *conv;
208: struct abuf *buf;
1.51 ratchov 209: unsigned siomode;
210:
1.57 ratchov 211: d->mode = d->reqmode;
212: d->round = d->reqround;
213: d->bufsz = d->reqbufsz;
214: d->ipar = d->reqipar;
215: d->opar = d->reqopar;
216: d->rec = NULL;
217: d->play = NULL;
218: d->mon = NULL;
1.61 ! jakemsr 219: d->mix = NULL;
! 220: d->sub = NULL;
1.57 ratchov 221: d->submon = NULL;
1.61 ! jakemsr 222: d->midi = NULL;
1.57 ratchov 223: d->rate = 0;
1.36 ratchov 224:
1.3 ratchov 225: /*
1.51 ratchov 226: * If needed, open the device (ie create dev_rec and dev_play)
1.3 ratchov 227: */
1.57 ratchov 228: if ((d->mode & (MODE_PLAY | MODE_REC)) && !(d->mode & MODE_LOOP)) {
229: siomode = d->mode & (MODE_PLAY | MODE_REC);
1.51 ratchov 230: f = (struct file *)siofile_new(&siofile_ops,
1.57 ratchov 231: d->path,
1.51 ratchov 232: &siomode,
1.57 ratchov 233: &d->ipar,
234: &d->opar,
235: &d->bufsz,
236: &d->round);
1.51 ratchov 237: if (f == NULL) {
1.39 ratchov 238: #ifdef DEBUG
1.51 ratchov 239: if (debug_level >= 1) {
1.57 ratchov 240: dbg_puts(d->path ? d->path : "default");
1.51 ratchov 241: dbg_puts(": failed to open audio device\n");
242: }
243: #endif
244: return 0;
1.39 ratchov 245: }
1.51 ratchov 246: if (!(siomode & MODE_PLAY))
1.57 ratchov 247: d->mode &= ~(MODE_PLAY | MODE_MON);
1.51 ratchov 248: if (!(siomode & MODE_REC))
1.57 ratchov 249: d->mode &= ~MODE_REC;
250: if ((d->mode & (MODE_PLAY | MODE_REC)) == 0) {
1.51 ratchov 251: #ifdef DEBUG
252: if (debug_level >= 1) {
1.57 ratchov 253: dbg_puts(d->path ? d->path : "default");
1.51 ratchov 254: dbg_puts(": mode not supported by device\n");
255: }
1.39 ratchov 256: #endif
1.51 ratchov 257: return 0;
258: }
1.57 ratchov 259: d->rate = d->mode & MODE_REC ? d->ipar.rate : d->opar.rate;
1.39 ratchov 260: #ifdef DEBUG
261: if (debug_level >= 2) {
1.57 ratchov 262: if (d->mode & MODE_REC) {
1.51 ratchov 263: dbg_puts("hw recording ");
1.57 ratchov 264: aparams_dbg(&d->ipar);
1.51 ratchov 265: dbg_puts("\n");
266: }
1.57 ratchov 267: if (d->mode & MODE_PLAY) {
1.51 ratchov 268: dbg_puts("hw playing ");
1.57 ratchov 269: aparams_dbg(&d->opar);
1.51 ratchov 270: dbg_puts("\n");
271: }
1.39 ratchov 272: }
273: #endif
1.57 ratchov 274: if (d->mode & MODE_REC) {
275: d->rec = rsio_new(f);
276: d->rec->refs++;
277: }
278: if (d->mode & MODE_PLAY) {
279: d->play = wsio_new(f);
280: d->play->refs++;
1.51 ratchov 281: }
1.3 ratchov 282: }
1.11 ratchov 283:
284: /*
1.51 ratchov 285: * Create the midi control end, or a simple thru box
286: * if there's no device
287: */
1.57 ratchov 288: d->midi = (d->mode == 0) ? thru_new("thru") : ctl_new("ctl", d);
289: d->midi->refs++;
1.51 ratchov 290:
291: /*
292: * Create mixer, demuxer and monitor
1.1 ratchov 293: */
1.57 ratchov 294: if (d->mode & MODE_PLAY) {
295: d->mix = mix_new("play", d->bufsz, d->round);
296: d->mix->refs++;
297: d->mix->u.mix.ctl = d->midi;
298: }
299: if (d->mode & MODE_REC) {
300: d->sub = sub_new("rec", d->bufsz, d->round);
301: d->sub->refs++;
1.51 ratchov 302: /*
303: * If not playing, use the record end as clock source
304: */
1.57 ratchov 305: if (!(d->mode & MODE_PLAY))
306: d->sub->u.sub.ctl = d->midi;
1.51 ratchov 307: }
1.57 ratchov 308: if (d->mode & MODE_LOOP) {
1.51 ratchov 309: /*
310: * connect mixer out to demuxer in
311: */
1.57 ratchov 312: buf = abuf_new(d->bufsz, &d->opar);
313: aproc_setout(d->mix, buf);
314: aproc_setin(d->sub, buf);
315:
316: d->mix->flags |= APROC_QUIT;
317: d->sub->flags |= APROC_QUIT;
318: d->rate = d->opar.rate;
1.51 ratchov 319: }
1.57 ratchov 320: if (d->rec) {
321: aparams_init(&par, d->ipar.cmin, d->ipar.cmax, d->rate);
1.51 ratchov 322:
1.1 ratchov 323: /*
1.51 ratchov 324: * Create device <-> demuxer buffer
1.1 ratchov 325: */
1.57 ratchov 326: buf = abuf_new(d->bufsz, &d->ipar);
327: aproc_setout(d->rec, buf);
1.1 ratchov 328:
329: /*
1.51 ratchov 330: * Insert a converter, if needed.
1.1 ratchov 331: */
1.57 ratchov 332: if (!aparams_eqenc(&d->ipar, &par)) {
333: conv = dec_new("rec", &d->ipar);
1.1 ratchov 334: aproc_setin(conv, buf);
1.57 ratchov 335: buf = abuf_new(d->round, &par);
1.1 ratchov 336: aproc_setout(conv, buf);
337: }
1.57 ratchov 338: d->ipar = par;
339: aproc_setin(d->sub, buf);
1.1 ratchov 340: }
1.57 ratchov 341: if (d->play) {
342: aparams_init(&par, d->opar.cmin, d->opar.cmax, d->rate);
1.1 ratchov 343:
344: /*
1.51 ratchov 345: * Create device <-> mixer buffer
1.1 ratchov 346: */
1.57 ratchov 347: buf = abuf_new(d->bufsz, &d->opar);
348: aproc_setin(d->play, buf);
1.25 ratchov 349:
1.1 ratchov 350: /*
1.27 ratchov 351: * Append a converter, if needed.
1.1 ratchov 352: */
1.57 ratchov 353: if (!aparams_eqenc(&par, &d->opar)) {
354: conv = enc_new("play", &d->opar);
1.1 ratchov 355: aproc_setout(conv, buf);
1.57 ratchov 356: buf = abuf_new(d->round, &par);
1.1 ratchov 357: aproc_setin(conv, buf);
358: }
1.57 ratchov 359: d->opar = par;
360: aproc_setout(d->mix, buf);
1.1 ratchov 361: }
1.57 ratchov 362: if (d->mode & MODE_MON) {
363: d->mon = mon_new("mon", d->bufsz);
364: d->mon->refs++;
365: buf = abuf_new(d->bufsz, &d->opar);
366: aproc_setout(d->mon, buf);
1.46 ratchov 367:
368: /*
369: * Append a "sub" to which clients will connect.
370: */
1.57 ratchov 371: d->submon = sub_new("mon", d->bufsz, d->round);
372: d->submon->refs++;
373: aproc_setin(d->submon, buf);
1.46 ratchov 374:
375: /*
1.51 ratchov 376: * Attach to the mixer
1.46 ratchov 377: */
1.57 ratchov 378: d->mix->u.mix.mon = d->mon;
379: d->mon->refs++;
1.46 ratchov 380: }
1.39 ratchov 381: #ifdef DEBUG
1.51 ratchov 382: if (debug_level >= 2) {
1.57 ratchov 383: if (d->mode & (MODE_PLAY | MODE_RECMASK)) {
1.51 ratchov 384: dbg_puts("device block size is ");
1.57 ratchov 385: dbg_putu(d->round);
1.51 ratchov 386: dbg_puts(" frames, using ");
1.57 ratchov 387: dbg_putu(d->bufsz / d->round);
1.51 ratchov 388: dbg_puts(" blocks\n");
389: }
1.39 ratchov 390: }
391: #endif
1.57 ratchov 392: d->pstate = DEV_INIT;
1.26 ratchov 393: return 1;
1.1 ratchov 394: }
395:
396: /*
1.27 ratchov 397: * Cleanly stop and drain everything and close the device
398: * once both play chain and record chain are gone.
1.1 ratchov 399: */
400: void
1.57 ratchov 401: dev_close(struct dev *d)
1.1 ratchov 402: {
403: struct file *f;
404:
1.50 ratchov 405: /*
406: * if the device is starting, ensure it actually starts
407: * so buffers are drained, else clear any buffers
408: */
1.57 ratchov 409: switch (d->pstate) {
1.50 ratchov 410: case DEV_START:
411: #ifdef DEBUG
412: if (debug_level >= 3)
413: dbg_puts("draining device\n");
414: #endif
1.57 ratchov 415: dev_start(d);
1.50 ratchov 416: break;
417: case DEV_INIT:
418: #ifdef DEBUG
419: if (debug_level >= 3)
420: dbg_puts("flushing device\n");
421: #endif
1.57 ratchov 422: dev_clear(d);
1.50 ratchov 423: break;
424: }
1.39 ratchov 425: #ifdef DEBUG
426: if (debug_level >= 2)
1.51 ratchov 427: dbg_puts("closing device\n");
1.39 ratchov 428: #endif
1.51 ratchov 429:
1.57 ratchov 430: if (d->mix) {
1.3 ratchov 431: /*
1.32 ratchov 432: * Put the mixer in ``autoquit'' state and generate
433: * EOF on all inputs connected it. Once buffers are
434: * drained the mixer will terminate and shutdown the
435: * device.
1.3 ratchov 436: *
437: * NOTE: since file_eof() can destroy the file and
438: * reorder the file_list, we have to restart the loop
1.27 ratchov 439: * after each call to file_eof().
1.3 ratchov 440: */
1.57 ratchov 441: if (APROC_OK(d->mix))
442: mix_quit(d->mix);
1.51 ratchov 443:
444: /*
445: * XXX: handle this in mix_done()
446: */
1.57 ratchov 447: if (APROC_OK(d->mix->u.mix.mon)) {
448: d->mix->u.mix.mon->refs--;
449: aproc_del(d->mix->u.mix.mon);
450: d->mix->u.mix.mon = NULL;
1.46 ratchov 451: }
1.32 ratchov 452: restart_mix:
1.3 ratchov 453: LIST_FOREACH(f, &file_list, entry) {
1.32 ratchov 454: if (f->rproc != NULL &&
1.57 ratchov 455: aproc_depend(d->mix, f->rproc)) {
1.3 ratchov 456: file_eof(f);
1.32 ratchov 457: goto restart_mix;
1.3 ratchov 458: }
459: }
1.59 ratchov 460: } else if (d->sub) {
1.3 ratchov 461: /*
1.32 ratchov 462: * Same as above, but since there's no mixer,
463: * we generate EOF on the record-end of the
464: * device.
465: */
466: restart_sub:
467: LIST_FOREACH(f, &file_list, entry) {
468: if (f->rproc != NULL &&
1.59 ratchov 469: aproc_depend(d->sub, f->rproc)) {
1.32 ratchov 470: file_eof(f);
471: goto restart_sub;
1.59 ratchov 472: }
473: }
474: } else if (d->submon) {
475: /*
476: * Same as above
477: */
478: restart_submon:
479: LIST_FOREACH(f, &file_list, entry) {
480: if (f->rproc != NULL &&
481: aproc_depend(d->submon, f->rproc)) {
482: file_eof(f);
483: goto restart_submon;
1.23 ratchov 484: }
1.32 ratchov 485: }
486: }
1.57 ratchov 487: if (d->midi) {
488: d->midi->flags |= APROC_QUIT;
489: if (LIST_EMPTY(&d->midi->ins))
490: aproc_del(d->midi);
1.36 ratchov 491: restart_midi:
492: LIST_FOREACH(f, &file_list, entry) {
493: if (f->rproc &&
1.57 ratchov 494: aproc_depend(d->midi, f->rproc)) {
1.36 ratchov 495: file_eof(f);
496: goto restart_midi;
497: }
498: }
499: }
1.57 ratchov 500: if (d->mix) {
501: if (--d->mix->refs == 0 && (d->mix->flags & APROC_ZOMB))
502: aproc_del(d->mix);
503: d->mix = NULL;
504: }
505: if (d->play) {
506: if (--d->play->refs == 0 && (d->play->flags & APROC_ZOMB))
507: aproc_del(d->play);
508: d->play = NULL;
509: }
510: if (d->sub) {
511: if (--d->sub->refs == 0 && (d->sub->flags & APROC_ZOMB))
512: aproc_del(d->sub);
513: d->sub = NULL;
514: }
515: if (d->rec) {
516: if (--d->rec->refs == 0 && (d->rec->flags & APROC_ZOMB))
517: aproc_del(d->rec);
518: d->rec = NULL;
519: }
520: if (d->submon) {
521: if (--d->submon->refs == 0 && (d->submon->flags & APROC_ZOMB))
522: aproc_del(d->submon);
523: d->submon = NULL;
524: }
525: if (d->mon) {
526: if (--d->mon->refs == 0 && (d->mon->flags & APROC_ZOMB))
527: aproc_del(d->mon);
528: d->mon = NULL;
529: }
530: if (d->midi) {
531: if (--d->midi->refs == 0 && (d->midi->flags & APROC_ZOMB))
532: aproc_del(d->midi);
533: d->midi = NULL;
1.32 ratchov 534: }
1.57 ratchov 535: d->pstate = DEV_CLOSED;
1.51 ratchov 536: }
537:
538: /*
1.60 ratchov 539: * Unless the device is already in process of closing, request it to close
540: */
541: void
542: dev_drain(struct dev *d)
543: {
544: if (d->pstate != DEV_CLOSED)
545: dev_close(d);
546: }
547:
548: /*
1.51 ratchov 549: * Free the device
550: */
551: void
1.57 ratchov 552: dev_del(struct dev *d)
1.51 ratchov 553: {
1.57 ratchov 554: struct dev **p;
555:
1.60 ratchov 556: dev_drain(d);
1.57 ratchov 557: for (p = &dev_list; *p != d; p = &(*p)->next) {
558: #ifdef DEBUG
559: if (*p == NULL) {
560: dbg_puts("device to delete not on the list\n");
561: dbg_panic();
562: }
563: #endif
564: }
565: *p = d->next;
566: free(d);
1.51 ratchov 567: }
568:
569: /*
570: * Open a MIDI device and connect it to the thru box
571: */
572: int
1.57 ratchov 573: dev_thruadd(struct dev *d, char *name, int in, int out)
1.51 ratchov 574: {
575: struct file *f;
576: struct abuf *rbuf = NULL, *wbuf = NULL;
577: struct aproc *rproc, *wproc;
578:
1.57 ratchov 579: if (!dev_ref(d))
1.51 ratchov 580: return 0;
581: f = (struct file *)miofile_new(&miofile_ops, name, in, out);
582: if (f == NULL)
583: return 0;
584: if (in) {
585: rproc = rfile_new(f);
586: rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
587: aproc_setout(rproc, rbuf);
588: }
589: if (out) {
590: wproc = wfile_new(f);
591: wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
592: aproc_setin(wproc, wbuf);
593: }
1.57 ratchov 594: dev_midiattach(d, rbuf, wbuf);
1.51 ratchov 595: return 1;
596: }
597:
598: /*
599: * Attach a bi-directional MIDI stream to the MIDI device
600: */
601: void
1.57 ratchov 602: dev_midiattach(struct dev *d, struct abuf *ibuf, struct abuf *obuf)
1.51 ratchov 603: {
604: if (ibuf)
1.57 ratchov 605: aproc_setin(d->midi, ibuf);
1.51 ratchov 606: if (obuf) {
1.57 ratchov 607: aproc_setout(d->midi, obuf);
1.51 ratchov 608: if (ibuf) {
609: ibuf->duplex = obuf;
610: obuf->duplex = ibuf;
611: }
1.1 ratchov 612: }
613: }
614:
1.51 ratchov 615: unsigned
1.57 ratchov 616: dev_roundof(struct dev *d, unsigned newrate)
1.51 ratchov 617: {
1.57 ratchov 618: return (d->round * newrate + d->rate / 2) / d->rate;
1.51 ratchov 619: }
620:
1.1 ratchov 621: /*
1.27 ratchov 622: * Start the (paused) device. By default it's paused.
1.1 ratchov 623: */
624: void
1.57 ratchov 625: dev_start(struct dev *d)
1.1 ratchov 626: {
1.22 ratchov 627: struct file *f;
628:
1.46 ratchov 629: #ifdef DEBUG
630: if (debug_level >= 2)
1.51 ratchov 631: dbg_puts("starting device\n");
1.46 ratchov 632: #endif
1.57 ratchov 633: d->pstate = DEV_RUN;
634: if (d->mode & MODE_LOOP)
1.52 ratchov 635: return;
1.57 ratchov 636: if (APROC_OK(d->mix))
637: d->mix->flags |= APROC_DROP;
638: if (APROC_OK(d->sub))
639: d->sub->flags |= APROC_DROP;
640: if (APROC_OK(d->submon))
641: d->submon->flags |= APROC_DROP;
642: if (APROC_OK(d->play) && d->play->u.io.file) {
643: f = d->play->u.io.file;
1.22 ratchov 644: f->ops->start(f);
1.57 ratchov 645: } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
646: f = d->rec->u.io.file;
1.22 ratchov 647: f->ops->start(f);
648: }
1.1 ratchov 649: }
650:
651: /*
1.46 ratchov 652: * Pause the device. This may trigger context switches,
653: * so it shouldn't be called from aproc methods
1.1 ratchov 654: */
655: void
1.57 ratchov 656: dev_stop(struct dev *d)
1.1 ratchov 657: {
1.22 ratchov 658: struct file *f;
659:
1.52 ratchov 660: #ifdef DEBUG
661: if (debug_level >= 2)
1.57 ratchov 662: dbg_puts("device stopped\n");
1.52 ratchov 663: #endif
1.57 ratchov 664: d->pstate = DEV_INIT;
665: if (d->mode & MODE_LOOP)
1.52 ratchov 666: return;
1.57 ratchov 667: if (APROC_OK(d->play) && d->play->u.io.file) {
668: f = d->play->u.io.file;
1.22 ratchov 669: f->ops->stop(f);
1.57 ratchov 670: } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
671: f = d->rec->u.io.file;
1.22 ratchov 672: f->ops->stop(f);
673: }
1.57 ratchov 674: if (APROC_OK(d->mix))
675: d->mix->flags &= ~APROC_DROP;
676: if (APROC_OK(d->sub))
677: d->sub->flags &= ~APROC_DROP;
678: if (APROC_OK(d->submon))
679: d->submon->flags &= ~APROC_DROP;
1.51 ratchov 680: }
681:
682: int
1.57 ratchov 683: dev_ref(struct dev *d)
1.51 ratchov 684: {
685: #ifdef DEBUG
686: if (debug_level >= 3)
687: dbg_puts("device requested\n");
688: #endif
1.57 ratchov 689: if (d->pstate == DEV_CLOSED && !dev_open(d)) {
690: if (d->hold)
691: dev_del(d);
1.51 ratchov 692: return 0;
1.57 ratchov 693: }
694: d->refcnt++;
1.51 ratchov 695: return 1;
696: }
697:
698: void
1.57 ratchov 699: dev_unref(struct dev *d)
1.51 ratchov 700: {
701: #ifdef DEBUG
702: if (debug_level >= 3)
703: dbg_puts("device released\n");
704: #endif
1.57 ratchov 705: d->refcnt--;
706: if (d->refcnt == 0 && d->pstate == DEV_INIT && !d->hold)
707: dev_close(d);
1.51 ratchov 708: }
709:
710: /*
711: * There are actions (like start/stop/close ... ) that may trigger aproc
712: * operations, a thus cannot be started from aproc context.
713: * To avoid problems, aprocs only change the s!tate of the device,
714: * and actual operations are triggered from the main loop,
715: * outside the aproc code path.
716: *
717: * The following routine invokes pending actions, returns 0
718: * on fatal error
719: */
720: int
1.57 ratchov 721: dev_run(struct dev *d)
1.51 ratchov 722: {
1.57 ratchov 723: if (d->pstate == DEV_CLOSED)
1.51 ratchov 724: return 1;
725: /*
726: * check if device isn't gone
727: */
1.57 ratchov 728: if (((d->mode & MODE_PLAY) && !APROC_OK(d->mix)) ||
729: ((d->mode & MODE_REC) && !APROC_OK(d->sub)) ||
730: ((d->mode & MODE_MON) && !APROC_OK(d->submon))) {
1.51 ratchov 731: #ifdef DEBUG
732: if (debug_level >= 1)
733: dbg_puts("device disappeared\n");
734: #endif
1.57 ratchov 735: if (d->hold) {
736: dev_del(d);
737: return 0;
738: }
739: dev_close(d);
740: return 1;
1.51 ratchov 741: }
1.57 ratchov 742: switch (d->pstate) {
1.51 ratchov 743: case DEV_INIT:
744: /* nothing */
745: break;
746: case DEV_START:
1.57 ratchov 747: dev_start(d);
1.51 ratchov 748: /* PASSTHROUGH */
749: case DEV_RUN:
750: /*
751: * if the device is not used, then stop it
752: */
1.57 ratchov 753: if ((!APROC_OK(d->mix) ||
754: d->mix->u.mix.idle > 2 * d->bufsz) &&
755: (!APROC_OK(d->sub) ||
756: d->sub->u.sub.idle > 2 * d->bufsz) &&
757: (!APROC_OK(d->submon) ||
758: d->submon->u.sub.idle > 2 * d->bufsz) &&
759: (!APROC_OK(d->midi) ||
760: d->midi->u.ctl.tstate != CTL_RUN)) {
1.51 ratchov 761: #ifdef DEBUG
762: if (debug_level >= 3)
763: dbg_puts("device idle, suspending\n");
1.46 ratchov 764: #endif
1.57 ratchov 765: dev_stop(d);
766: if (d->refcnt == 0 && !d->hold)
767: dev_close(d);
1.58 ratchov 768: else
1.57 ratchov 769: dev_clear(d);
1.51 ratchov 770: }
771: break;
772: }
773: return 1;
774: }
775:
776: /*
1.58 ratchov 777: * If the device is paused, then resume it.
1.51 ratchov 778: * This routine can be called from aproc context.
779: */
780: void
1.57 ratchov 781: dev_wakeup(struct dev *d)
1.51 ratchov 782: {
1.57 ratchov 783: if (d->pstate == DEV_INIT)
784: d->pstate = DEV_START;
1.1 ratchov 785: }
786:
787: /*
1.27 ratchov 788: * Find the end points connected to the mix/sub.
1.14 ratchov 789: */
790: int
1.57 ratchov 791: dev_getep(struct dev *d,
792: unsigned mode, struct abuf **sibuf, struct abuf **sobuf)
1.14 ratchov 793: {
794: struct abuf *ibuf, *obuf;
795:
1.46 ratchov 796: if (mode & MODE_PLAY) {
1.57 ratchov 797: if (!APROC_OK(d->mix))
1.46 ratchov 798: return 0;
1.14 ratchov 799: ibuf = *sibuf;
800: for (;;) {
801: if (!ibuf || !ibuf->rproc) {
1.39 ratchov 802: #ifdef DEBUG
803: if (debug_level >= 3) {
804: abuf_dbg(*sibuf);
805: dbg_puts(": not connected to device\n");
806: }
807: #endif
1.14 ratchov 808: return 0;
809: }
1.57 ratchov 810: if (ibuf->rproc == d->mix)
1.14 ratchov 811: break;
1.49 ratchov 812: ibuf = LIST_FIRST(&ibuf->rproc->outs);
1.14 ratchov 813: }
1.21 ratchov 814: *sibuf = ibuf;
1.14 ratchov 815: }
1.46 ratchov 816: if (mode & MODE_REC) {
1.57 ratchov 817: if (!APROC_OK(d->sub))
1.46 ratchov 818: return 0;
1.14 ratchov 819: obuf = *sobuf;
820: for (;;) {
821: if (!obuf || !obuf->wproc) {
1.39 ratchov 822: #ifdef DEBUG
823: if (debug_level >= 3) {
824: abuf_dbg(*sobuf);
825: dbg_puts(": not connected to device\n");
826: }
827: #endif
1.14 ratchov 828: return 0;
829: }
1.57 ratchov 830: if (obuf->wproc == d->sub)
1.14 ratchov 831: break;
1.49 ratchov 832: obuf = LIST_FIRST(&obuf->wproc->ins);
1.14 ratchov 833: }
1.21 ratchov 834: *sobuf = obuf;
1.14 ratchov 835: }
1.46 ratchov 836: if (mode & MODE_MON) {
1.57 ratchov 837: if (!APROC_OK(d->submon))
1.46 ratchov 838: return 0;
839: obuf = *sobuf;
840: for (;;) {
841: if (!obuf || !obuf->wproc) {
842: #ifdef DEBUG
843: if (debug_level >= 3) {
844: abuf_dbg(*sobuf);
845: dbg_puts(": not connected to device\n");
846: }
847: #endif
848: return 0;
849: }
1.57 ratchov 850: if (obuf->wproc == d->submon)
1.46 ratchov 851: break;
1.49 ratchov 852: obuf = LIST_FIRST(&obuf->wproc->ins);
1.46 ratchov 853: }
854: *sobuf = obuf;
855: }
1.14 ratchov 856: return 1;
857: }
858:
859: /*
1.27 ratchov 860: * Sync play buffer to rec buffer (for instance when one of
861: * them underruns/overruns).
1.1 ratchov 862: */
863: void
1.57 ratchov 864: dev_sync(struct dev *d, unsigned mode, struct abuf *ibuf, struct abuf *obuf)
1.1 ratchov 865: {
1.53 ratchov 866: int delta, offs;
1.57 ratchov 867: struct abuf *mbuf = NULL;
1.3 ratchov 868:
1.57 ratchov 869: if (!dev_getep(d, mode, &ibuf, &obuf))
1.3 ratchov 870: return;
871: /*
1.27 ratchov 872: * Calculate delta, the number of frames the play chain is ahead
1.3 ratchov 873: * of the record chain. It's necessary to schedule silences (or
874: * drops) in order to start playback and record in sync.
875: */
1.53 ratchov 876: offs = 0;
877: delta = 0;
1.57 ratchov 878: if (APROC_OK(d->mix)) {
879: mbuf = LIST_FIRST(&d->mix->outs);
1.53 ratchov 880: offs += mbuf->w.mix.todo;
1.57 ratchov 881: delta += d->mix->u.mix.lat;
1.53 ratchov 882: }
1.57 ratchov 883: if (APROC_OK(d->sub))
884: delta += d->sub->u.sub.lat;
1.39 ratchov 885: #ifdef DEBUG
886: if (debug_level >= 3) {
1.53 ratchov 887: dbg_puts("syncing device");
1.57 ratchov 888: if (APROC_OK(d->mix)) {
1.51 ratchov 889: dbg_puts(", ");
1.57 ratchov 890: aproc_dbg(d->mix);
1.53 ratchov 891: dbg_puts(": todo = ");
892: dbg_putu(mbuf->w.mix.todo);
893: dbg_puts(": lat = ");
1.57 ratchov 894: dbg_putu(d->mix->u.mix.lat);
1.46 ratchov 895: }
1.57 ratchov 896: if (APROC_OK(d->sub)) {
1.51 ratchov 897: dbg_puts(", ");
1.57 ratchov 898: aproc_dbg(d->sub);
1.53 ratchov 899: dbg_puts(": lat = ");
1.57 ratchov 900: dbg_putu(d->sub->u.sub.lat);
1.46 ratchov 901: }
1.39 ratchov 902: dbg_puts("\n");
903: }
904: #endif
1.53 ratchov 905: if (mode & MODE_PLAY)
906: mix_drop(ibuf, -offs);
907: if (mode & MODE_RECMASK)
908: sub_silence(obuf, -(offs + delta));
1.36 ratchov 909: }
910:
911: /*
912: * return the current latency (in frames), ie the latency that
913: * a stream would have if dev_attach() is called on it.
914: */
915: int
1.57 ratchov 916: dev_getpos(struct dev *d)
1.36 ratchov 917: {
1.53 ratchov 918: struct abuf *mbuf = NULL;
1.36 ratchov 919:
1.57 ratchov 920: if (APROC_OK(d->mix)) {
921: mbuf = LIST_FIRST(&d->mix->outs);
922: return -(mbuf->w.mix.todo + d->mix->u.mix.lat);
1.54 ratchov 923: } else
924: return 0;
1.1 ratchov 925: }
926:
927: /*
1.27 ratchov 928: * Attach the given input and output buffers to the mixer and the
1.1 ratchov 929: * multiplexer respectively. The operation is done synchronously, so
930: * both buffers enter in sync. If buffers do not match play
1.27 ratchov 931: * and rec.
1.1 ratchov 932: */
933: void
1.57 ratchov 934: dev_attach(struct dev *d, char *name, unsigned mode,
1.48 ratchov 935: struct abuf *ibuf, struct aparams *sipar, unsigned inch,
936: struct abuf *obuf, struct aparams *sopar, unsigned onch,
1.46 ratchov 937: unsigned xrun, int vol)
1.1 ratchov 938: {
939: struct abuf *pbuf = NULL, *rbuf = NULL;
1.12 ratchov 940: struct aparams ipar, opar;
1.1 ratchov 941: struct aproc *conv;
1.48 ratchov 942: unsigned round, nblk, nch;
1.20 ratchov 943:
1.46 ratchov 944: #ifdef DEBUG
1.57 ratchov 945: if ((!APROC_OK(d->mix) && (mode & MODE_PLAY)) ||
946: (!APROC_OK(d->sub) && (mode & MODE_REC)) ||
947: (!APROC_OK(d->submon) && (mode & MODE_MON))) {
1.46 ratchov 948: dbg_puts("mode beyond device mode, not attaching\n");
949: return;
950: }
951: #endif
952: if (mode & MODE_PLAY) {
1.12 ratchov 953: ipar = *sipar;
1.57 ratchov 954: pbuf = LIST_FIRST(&d->mix->outs);
955: nblk = (d->bufsz / d->round + 3) / 4;
956: round = dev_roundof(d, ipar.rate);
1.48 ratchov 957: nch = ipar.cmax - ipar.cmin + 1;
1.57 ratchov 958: if (!aparams_eqenc(&ipar, &d->opar)) {
1.10 ratchov 959: conv = dec_new(name, &ipar);
1.57 ratchov 960: ipar.bps = d->opar.bps;
961: ipar.bits = d->opar.bits;
962: ipar.sig = d->opar.sig;
963: ipar.le = d->opar.le;
964: ipar.msb = d->opar.msb;
1.25 ratchov 965: aproc_setin(conv, ibuf);
1.20 ratchov 966: ibuf = abuf_new(nblk * round, &ipar);
1.9 ratchov 967: aproc_setout(conv, ibuf);
1.8 ratchov 968: }
1.48 ratchov 969: if (inch > 0 && nch >= inch * 2) {
970: conv = join_new(name);
971: aproc_setin(conv, ibuf);
972: ipar.cmax = ipar.cmin + inch - 1;
973: ibuf = abuf_new(nblk * round, &ipar);
974: aproc_setout(conv, ibuf);
975: }
1.57 ratchov 976: if (!aparams_eqrate(&ipar, &d->opar)) {
977: conv = resamp_new(name, round, d->round);
978: ipar.rate = d->opar.rate;
979: round = d->round;
1.5 ratchov 980: aproc_setin(conv, ibuf);
1.20 ratchov 981: ibuf = abuf_new(nblk * round, &ipar);
1.5 ratchov 982: aproc_setout(conv, ibuf);
1.1 ratchov 983: }
1.48 ratchov 984: if (inch > 0 && nch * 2 <= inch) {
985: conv = join_new(name);
986: aproc_setin(conv, ibuf);
987: ipar.cmax = ipar.cmin + inch - 1;
988: ibuf = abuf_new(nblk * round, &ipar);
989: aproc_setout(conv, ibuf);
990: }
1.57 ratchov 991: aproc_setin(d->mix, ibuf);
1.46 ratchov 992: ibuf->r.mix.xrun = xrun;
1.31 ratchov 993: ibuf->r.mix.maxweight = vol;
1.57 ratchov 994: mix_setmaster(d->mix);
1.1 ratchov 995: }
1.46 ratchov 996: if (mode & MODE_REC) {
1.12 ratchov 997: opar = *sopar;
1.57 ratchov 998: rbuf = LIST_FIRST(&d->sub->ins);
999: round = dev_roundof(d, opar.rate);
1000: nblk = (d->bufsz / d->round + 3) / 4;
1.48 ratchov 1001: nch = opar.cmax - opar.cmin + 1;
1.57 ratchov 1002: if (!aparams_eqenc(&opar, &d->ipar)) {
1.10 ratchov 1003: conv = enc_new(name, &opar);
1.57 ratchov 1004: opar.bps = d->ipar.bps;
1005: opar.bits = d->ipar.bits;
1006: opar.sig = d->ipar.sig;
1007: opar.le = d->ipar.le;
1008: opar.msb = d->ipar.msb;
1.9 ratchov 1009: aproc_setout(conv, obuf);
1.20 ratchov 1010: obuf = abuf_new(nblk * round, &opar);
1.9 ratchov 1011: aproc_setin(conv, obuf);
1.8 ratchov 1012: }
1.48 ratchov 1013: if (onch > 0 && nch >= onch * 2) {
1014: conv = join_new(name);
1015: aproc_setout(conv, obuf);
1016: opar.cmax = opar.cmin + onch - 1;
1017: obuf = abuf_new(nblk * round, &opar);
1018: aproc_setin(conv, obuf);
1019: }
1.57 ratchov 1020: if (!aparams_eqrate(&opar, &d->ipar)) {
1021: conv = resamp_new(name, d->round, round);
1022: opar.rate = d->ipar.rate;
1023: round = d->round;
1.1 ratchov 1024: aproc_setout(conv, obuf);
1.20 ratchov 1025: obuf = abuf_new(nblk * round, &opar);
1.1 ratchov 1026: aproc_setin(conv, obuf);
1027: }
1.48 ratchov 1028: if (onch > 0 && nch * 2 <= onch) {
1029: conv = join_new(name);
1030: aproc_setout(conv, obuf);
1031: opar.cmax = opar.cmin + onch - 1;
1032: obuf = abuf_new(nblk * round, &opar);
1033: aproc_setin(conv, obuf);
1034: }
1.57 ratchov 1035: aproc_setout(d->sub, obuf);
1.46 ratchov 1036: obuf->w.sub.xrun = xrun;
1037: }
1038: if (mode & MODE_MON) {
1039: opar = *sopar;
1.57 ratchov 1040: rbuf = LIST_FIRST(&d->submon->ins);
1041: round = dev_roundof(d, opar.rate);
1042: nblk = (d->bufsz / d->round + 3) / 4;
1.48 ratchov 1043: nch = opar.cmax - opar.cmin + 1;
1.57 ratchov 1044: if (!aparams_eqenc(&opar, &d->opar)) {
1.46 ratchov 1045: conv = enc_new(name, &opar);
1.57 ratchov 1046: opar.bps = d->opar.bps;
1047: opar.bits = d->opar.bits;
1048: opar.sig = d->opar.sig;
1049: opar.le = d->opar.le;
1050: opar.msb = d->opar.msb;
1.46 ratchov 1051: aproc_setout(conv, obuf);
1052: obuf = abuf_new(nblk * round, &opar);
1053: aproc_setin(conv, obuf);
1054: }
1.48 ratchov 1055: if (onch > 0 && nch >= onch * 2) {
1056: conv = join_new(name);
1057: aproc_setout(conv, obuf);
1058: opar.cmax = opar.cmin + onch - 1;
1059: obuf = abuf_new(nblk * round, &opar);
1060: aproc_setin(conv, obuf);
1061: }
1.57 ratchov 1062: if (!aparams_eqrate(&opar, &d->opar)) {
1063: conv = resamp_new(name, d->round, round);
1064: opar.rate = d->opar.rate;
1065: round = d->round;
1.46 ratchov 1066: aproc_setout(conv, obuf);
1.48 ratchov 1067: obuf = abuf_new(nblk * round, &opar);
1068: aproc_setin(conv, obuf);
1069: }
1070: if (onch > 0 && nch * 2 <= onch) {
1071: conv = join_new(name);
1072: aproc_setout(conv, obuf);
1073: opar.cmax = opar.cmin + onch - 1;
1.46 ratchov 1074: obuf = abuf_new(nblk * round, &opar);
1075: aproc_setin(conv, obuf);
1076: }
1.57 ratchov 1077: aproc_setout(d->submon, obuf);
1.46 ratchov 1078: obuf->w.sub.xrun = xrun;
1.1 ratchov 1079: }
1080:
1081: /*
1.27 ratchov 1082: * Sync play to record.
1.1 ratchov 1083: */
1.46 ratchov 1084: if ((mode & MODE_PLAY) && (mode & MODE_RECMASK)) {
1.3 ratchov 1085: ibuf->duplex = obuf;
1086: obuf->duplex = ibuf;
1.13 ratchov 1087: }
1.57 ratchov 1088: dev_sync(d, mode, ibuf, obuf);
1.14 ratchov 1089: }
1090:
1091: /*
1.27 ratchov 1092: * Change the playback volume of the given stream.
1.14 ratchov 1093: */
1094: void
1.57 ratchov 1095: dev_setvol(struct dev *d, struct abuf *ibuf, int vol)
1.14 ratchov 1096: {
1.39 ratchov 1097: #ifdef DEBUG
1098: if (debug_level >= 3) {
1099: abuf_dbg(ibuf);
1100: dbg_puts(": setting volume to ");
1101: dbg_putu(vol);
1102: dbg_puts("\n");
1103: }
1104: #endif
1.57 ratchov 1105: if (!dev_getep(d, MODE_PLAY, &ibuf, NULL)) {
1.14 ratchov 1106: return;
1.16 ratchov 1107: }
1.31 ratchov 1108: ibuf->r.mix.vol = vol;
1.13 ratchov 1109: }
1110:
1111: /*
1.27 ratchov 1112: * Clear buffers of the play and record chains so that when the device
1113: * is started, playback and record start in sync.
1.13 ratchov 1114: */
1115: void
1.57 ratchov 1116: dev_clear(struct dev *d)
1.13 ratchov 1117: {
1118: struct abuf *buf;
1119:
1.57 ratchov 1120: if (APROC_OK(d->mix)) {
1.39 ratchov 1121: #ifdef DEBUG
1.57 ratchov 1122: if (!LIST_EMPTY(&d->mix->ins)) {
1.39 ratchov 1123: dbg_puts("play end not idle, can't clear device\n");
1124: dbg_panic();
1125: }
1126: #endif
1.57 ratchov 1127: buf = LIST_FIRST(&d->mix->outs);
1.13 ratchov 1128: while (buf) {
1129: abuf_clear(buf);
1.49 ratchov 1130: buf = LIST_FIRST(&buf->rproc->outs);
1.13 ratchov 1131: }
1.57 ratchov 1132: mix_clear(d->mix);
1.13 ratchov 1133: }
1.57 ratchov 1134: if (APROC_OK(d->sub)) {
1.39 ratchov 1135: #ifdef DEBUG
1.57 ratchov 1136: if (!LIST_EMPTY(&d->sub->outs)) {
1.39 ratchov 1137: dbg_puts("record end not idle, can't clear device\n");
1138: dbg_panic();
1139: }
1140: #endif
1.57 ratchov 1141: buf = LIST_FIRST(&d->sub->ins);
1.13 ratchov 1142: while (buf) {
1143: abuf_clear(buf);
1.49 ratchov 1144: buf = LIST_FIRST(&buf->wproc->ins);
1.13 ratchov 1145: }
1.57 ratchov 1146: sub_clear(d->sub);
1.40 ratchov 1147: }
1.57 ratchov 1148: if (APROC_OK(d->submon)) {
1.46 ratchov 1149: #ifdef DEBUG
1150: dbg_puts("clearing monitor\n");
1.57 ratchov 1151: if (!LIST_EMPTY(&d->submon->outs)) {
1.46 ratchov 1152: dbg_puts("monitoring end not idle, can't clear device\n");
1153: dbg_panic();
1154: }
1155: #endif
1.57 ratchov 1156: buf = LIST_FIRST(&d->submon->ins);
1.46 ratchov 1157: while (buf) {
1158: abuf_clear(buf);
1.49 ratchov 1159: buf = LIST_FIRST(&buf->wproc->ins);
1.46 ratchov 1160: }
1.57 ratchov 1161: sub_clear(d->submon);
1162: mon_clear(d->mon);
1.1 ratchov 1163: }
1164: }