FreeBSD/Linux Kernel Cross Reference
sys/chips/audio.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: audio.c,v $
29 * Revision 2.4 93/05/15 19:39:53 mrt
30 * machparam.h -> machspl.h
31 *
32 * Revision 2.3 93/05/10 20:07:18 rvb
33 * GCC quiet.
34 * [93/05/06 09:53:58 af]
35 *
36 * Revision 2.2 93/03/18 10:36:56 mrt
37 * Backward compat include of sys/types.h since busses.h
38 * not fixed yet in this release.
39 * [93/03/18 01:21:22 af]
40 *
41 * Started, from Berkeley's driver.
42 * [93/03/09 af]
43 *
44 /*-
45 * Copyright (c) 1991, 1992 The Regents of the University of California.
46 * All rights reserved.
47 *
48 * Redistribution and use in source and binary forms, with or without
49 * modification, are permitted provided that the following conditions
50 * are met:
51 * 1. Redistributions of source code must retain the above copyright
52 * notice, this list of conditions and the following disclaimer.
53 * 2. Redistributions in binary form must reproduce the above copyright
54 * notice, this list of conditions and the following disclaimer in the
55 * documentation and/or other materials provided with the distribution.
56 * 3. All advertising materials mentioning features or use of this software
57 * must display the following acknowledgement:
58 * This product includes software developed by the Computer Systems
59 * Engineering Group at Lawrence Berkeley Laboratory.
60 * 4. The name of the Laboratory may not be used to endorse or promote
61 * products derived from this software without specific prior written
62 * permission.
63 *
64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74 * SUCH DAMAGE.
75 *
76 * $Header: audio.c,v 2.4 93/05/15 19:39:53 mrt Exp $ (LBL)
77 */
78
79 #include <audio.h>
80 #if NAUDIO > 0
81
82 #include <platforms.h>
83
84 #include <mach/std_types.h>
85 #include <machine/machspl.h>
86 #include <kern/kalloc.h>
87 #include <chips/busses.h>
88
89 #include <device/device_types.h>
90 #include <device/io_req.h>
91 #include <device/ds_routines.h>
92 #include <device/audio_status.h> /* user interface */
93 #include <chips/audio_defs.h> /* chip interface */
94 #include <chips/audio_config.h> /* machdep config */
95
96 #define private static
97
98 /*
99 * Exported functions and data structures
100 * [see header file for listing]
101 */
102 int audio_blocksize = DEFBLKSIZE; /* patchable */
103 int audio_backlog = 400; /* 50ms in samples */
104
105 /*
106 * Software state, per AMD79C30 audio chip.
107 */
108 private
109 struct audio_softc {
110 void *hw; /* chip status */
111 audio_switch_t *ops; /* chip operations */
112 au_io_t *sc_au; /* recv and xmit buffers, etc */
113
114
115 unsigned int sc_wseek; /* timestamp of last frame written */
116 unsigned int sc_rseek; /* timestamp of last frame read */
117 #if 0
118 struct selinfo sc_wsel; /* write selector */
119 struct selinfo sc_rsel; /* read selector */
120 #endif
121
122 } audio_softc_data[NAUDIO];
123
124 #define unit_to_softc(u) &audio_softc_data[u]
125
126
127 /* forward declarations */
128 private int audio_sleep (au_cb_t *cb, int thresh);
129 private void audio_swintr (struct audio_softc *sc);
130
131 /*
132 * Audio chip found.
133 */
134 void
135 audio_attach(
136 void *hw, /* IN, chip status */
137 audio_switch_t *ops,
138 void **audio_status) /* OUT, audio status */
139 {
140 register struct audio_softc *sc;
141 static int next = 0;
142
143 if (next >= NAUDIO)
144 panic("Please configure more than %d audio devices\n", NAUDIO);
145 sc = &audio_softc_data[next++];
146
147 printf(" audio");
148
149 sc->hw = hw;
150 sc->ops = ops;
151
152 *audio_status = (void *)sc;
153 }
154
155
156 private int audio_setinfo (struct audio_softc *, audio_info_t *);
157 private int audio_getinfo (struct audio_softc *, audio_info_t *);
158
159 io_return_t
160 audio_open(
161 int unit,
162 int mode,
163 io_req_t req)
164 {
165 register struct audio_softc *sc;
166 register au_io_t *au;
167
168 sc = unit_to_softc(unit);
169 if (unit > NAUDIO || (!sc->hw))
170 return (D_NO_SUCH_DEVICE);
171
172 if (!sc->sc_au) {
173 sc->sc_au = (au_io_t *) kalloc(sizeof(au_io_t));
174 bzero(sc->sc_au, sizeof(au_io_t));
175 }
176 au = sc->sc_au;
177
178 au->au_lowat = audio_blocksize;
179 au->au_hiwat = AUCB_SIZE - au->au_lowat;
180 au->au_blksize = audio_blocksize;
181 au->au_backlog = audio_backlog;
182
183 /* set up read and write blocks and `dead sound' zero value. */
184 AUCB_INIT(&au->au_rb);
185 au->au_rb.cb_thresh = AUCB_SIZE;
186 AUCB_INIT(&au->au_wb);
187 au->au_wb.cb_thresh = -1;
188
189 /* nothing read or written yet */
190 sc->sc_rseek = 0;
191 sc->sc_wseek = 0;
192
193 (*sc->ops->init)(sc->hw);
194
195 return (0);
196 }
197
198 private int
199 audio_drain(
200 register au_io_t *au)
201 {
202 register int error;
203
204 while (!AUCB_EMPTY(&au->au_wb))
205 if ((error = audio_sleep(&au->au_wb, 0)) != 0)
206 return (error);
207 return (0);
208 }
209
210 /*
211 * Close an audio chip.
212 */
213 /* ARGSUSED */
214 io_return_t
215 audio_close(
216 int unit)
217 {
218 register struct audio_softc *sc = unit_to_softc(unit);
219 register au_cb_t *cb;
220 register spl_t s;
221
222 /*
223 * Block until output drains, but allow ^C interrupt.
224 */
225 sc->sc_au->au_lowat = 0; /* avoid excessive wakeups */
226
227 /*
228 * If there is pending output, let it drain (unless
229 * the output is paused).
230 */
231 cb = &sc->sc_au->au_wb;
232 s = splaudio();
233 if (!AUCB_EMPTY(cb) && !cb->cb_pause)
234 (void)audio_drain(sc->sc_au);
235 /*
236 * Disable interrupts, and done.
237 */
238 (*sc->ops->close)(sc->hw);
239 splx(s);
240 return (D_SUCCESS);
241 }
242
243 private int
244 audio_sleep(cb, thresh)
245 register au_cb_t *cb;
246 register int thresh;
247 {
248 register int error;
249 register spl_t s = splaudio();
250
251 cb->cb_thresh = thresh;
252 assert_wait((event_t)cb, TRUE);
253 splx(s);
254 thread_block((void (*)()) 0);
255 return (0); /* XXXX */
256 }
257
258 io_return_t
259 audio_read(
260 int unit,
261 io_req_t ior)
262 {
263 register struct audio_softc *sc = unit_to_softc(unit);
264 register au_cb_t *cb;
265 register int n, head, taildata;
266 register int blocksize = sc->sc_au->au_blksize;
267 io_return_t rc;
268 unsigned char *data;
269
270 /*
271 * Allocate read buffer
272 */
273 rc = device_read_alloc(ior, (vm_size_t)ior->io_count);
274 if (rc != KERN_SUCCESS)
275 return rc;
276 data = (unsigned char *) ior->io_data;
277 ior->io_residual = ior->io_count;
278
279 cb = &sc->sc_au->au_rb;
280 cb->cb_drops = 0;
281 sc->sc_rseek = sc->sc_au->au_stamp - AUCB_LEN(cb);
282 do {
283 while (AUCB_LEN(cb) < blocksize) {
284
285 if (ior->io_mode & D_NODELAY)
286 return (D_WOULD_BLOCK);
287
288 if ((rc = audio_sleep(cb, blocksize)) != 0)
289 return(rc);
290 }
291 /*
292 * The space calculation can only err on the short
293 * side if an interrupt occurs during processing:
294 * only cb_tail is altered in the interrupt code.
295 */
296 head = cb->cb_head;
297 if ((n = AUCB_LEN(cb)) > ior->io_residual)
298 n = ior->io_residual;
299 taildata = AUCB_SIZE - head;
300
301 if (n > taildata) {
302 bcopy(cb->cb_data + head, data, taildata);
303 bcopy(cb->cb_data, data + taildata, n - taildata);
304 } else
305 bcopy(cb->cb_data + head, data, n);
306 data += n;
307 ior->io_residual -= n;
308
309 head = AUCB_MOD(head + n);
310 cb->cb_head = head;
311 } while (ior->io_residual >= blocksize);
312
313 return (rc);
314 }
315
316 io_return_t
317 audio_write(
318 int unit,
319 io_req_t ior)
320 {
321 register struct audio_softc *sc = unit_to_softc(unit);
322 register au_io_t *au = sc->sc_au;
323 register au_cb_t *cb = &au->au_wb;
324 register int n, tail, tailspace, first, watermark, drops;
325 io_return_t rc;
326 unsigned char *data;
327 vm_offset_t addr = 0;
328
329 if (!(ior->io_op & IO_INBAND)) {
330 /*
331 * Copy out-of-line data into kernel address space.
332 * Since data is copied as page list, it will be
333 * accessible.
334 */
335 vm_map_copy_t copy = (vm_map_copy_t) ior->io_data;
336 kern_return_t kr;
337
338 kr = vm_map_copyout(device_io_map, &addr, copy);
339 if (kr != KERN_SUCCESS)
340 return kr;
341 data = (unsigned char *) addr;
342 } else
343 data = (unsigned char *) ior->io_data;
344 ior->io_residual = ior->io_count;
345
346 rc = D_SUCCESS;
347 first = 1;
348 while (ior->io_residual > 0) {
349 watermark = au->au_hiwat;
350 while (AUCB_LEN(cb) > watermark) {
351
352 if (ior->io_mode & D_NODELAY) {
353 rc = D_WOULD_BLOCK;
354 goto out;
355 }
356
357 if ((rc = audio_sleep(cb, watermark)) != 0)
358 goto out;
359
360 watermark = au->au_lowat;
361 }
362 /*
363 * The only value that can change on an interrupt is
364 * cb->cb_head. We only pull that out once to decide
365 * how much to write into cb_data; if we lose a race
366 * and cb_head changes, we will merely be overly
367 * conservative. For a legitimate time stamp,
368 * however, we need to synchronize the accesses to
369 * au_stamp and cb_head at a high ipl below.
370 */
371 tail = cb->cb_tail;
372 if ((n = (AUCB_SIZE - 1) - AUCB_LEN(cb)) > ior->io_residual) {
373 n = ior->io_residual;
374 if (cb->cb_head == tail &&
375 n <= au->au_blksize &&
376 au->au_stamp - sc->sc_wseek > 400) {
377 /*
378 * the write is 'small', the buffer is empty
379 * and we have been silent for at least 50ms
380 * so we might be dealing with an application
381 * that writes frames synchronously with
382 * reading them. If so, we need an output
383 * backlog to cover scheduling delays or
384 * there will be gaps in the sound output.
385 * Also take this opportunity to reset the
386 * buffer pointers in case we ended up on
387 * a bad boundary (odd byte, blksize bytes
388 * from end, etc.).
389 */
390 register unsigned long *ip;
391 register unsigned long muzero;
392 spl_t s;
393 register int i;
394
395 s = splaudio();
396 cb->cb_head = cb->cb_tail = 0;
397 splx(s);
398
399 tail = au->au_backlog;
400 ip = (unsigned long *)cb->cb_data;
401 muzero = sample_rpt_long(0x7fL);
402 for (i = tail / sizeof muzero; --i >= 0; )
403 *ip++ = muzero;
404 }
405 }
406 tailspace = AUCB_SIZE - tail;
407 if (n > tailspace) {
408 /* write first part at tail and rest at head */
409 bcopy(data, cb->cb_data + tail, tailspace);
410 bcopy(data + tailspace, cb->cb_data,
411 n - tailspace);
412 } else
413 bcopy(data, cb->cb_data + tail, n);
414 data += n;
415 ior->io_residual -= n;
416
417 tail = AUCB_MOD(tail + n);
418 if (first) {
419 register spl_t s = splaudio();
420 sc->sc_wseek = AUCB_LEN(cb) + au->au_stamp + 1;
421 /*
422 * To guarantee that a write is contiguous in the
423 * sample space, we clear the drop count the first
424 * time through. If we later get drops, we will
425 * break out of the loop below, before writing
426 * a new frame.
427 */
428 cb->cb_drops = 0;
429 cb->cb_tail = tail;
430 splx(s);
431 first = 0;
432 } else {
433 if (cb->cb_drops != 0)
434 break;
435 cb->cb_tail = tail;
436 }
437 }
438 out:
439 if (!(ior->io_op & IO_INBAND))
440 (void) vm_deallocate(device_io_map, addr, ior->io_count);
441 return (rc);
442 }
443
444 #include <sys/ioctl.h>
445
446 io_return_t
447 audio_get_status(
448 int unit,
449 dev_flavor_t flavor,
450 dev_status_t status,
451 natural_t *status_count)
452 {
453 register struct audio_softc *sc = unit_to_softc(unit);
454 register au_io_t *au = sc->sc_au;
455 io_return_t rc = D_SUCCESS;
456 int i;
457 spl_t s;
458
459 switch (flavor) {
460
461 case AUDIO_GETMAP:
462 case AUDIOGETREG:
463 rc = (*sc->ops->getstate)(sc->hw, flavor,
464 (void *)status, status_count);
465 break;
466
467 /*
468 * Number of read samples dropped. We don't know where or
469 * when they were dropped.
470 */
471 case AUDIO_RERROR:
472 *(int *)status = au->au_rb.cb_drops;
473 *status_count = 1;
474 break;
475
476 case AUDIO_WERROR:
477 *(int *)status = au->au_wb.cb_drops;
478 *status_count = 1;
479 break;
480
481 /*
482 * How many samples will elapse until mike hears the first
483 * sample of what we last wrote?
484 */
485 case AUDIO_WSEEK:
486 s = splaudio();
487 *(unsigned int *)status = sc->sc_wseek - au->au_stamp
488 + AUCB_LEN(&au->au_rb);
489 splx(s);
490 *status_count = 1;
491 break;
492
493 case AUDIO_GETINFO:
494 rc = audio_getinfo(sc, (audio_info_t *)status);
495 *status_count = sizeof(audio_info_t) / sizeof(int);
496 break;
497
498 default:
499 rc = D_INVALID_OPERATION;
500 break;
501 }
502 return (rc);
503 }
504
505 io_return_t
506 audio_set_status(
507 int unit,
508 dev_flavor_t flavor,
509 dev_status_t status,
510 natural_t status_count)
511 {
512 register struct audio_softc *sc = unit_to_softc(unit);
513 register au_io_t *au = sc->sc_au;
514 int i;
515 io_return_t rc = D_SUCCESS;
516 spl_t s;
517
518 switch (flavor) {
519
520 case AUDIO_SETMAP:
521 case AUDIOSETREG:
522 rc = (*sc->ops->setstate)(sc->hw, flavor,
523 (void *)status, status_count);
524 break;
525
526 case AUDIO_FLUSH:
527 s = splaudio();
528 AUCB_INIT(&au->au_rb);
529 AUCB_INIT(&au->au_wb);
530 au->au_stamp = 0;
531 splx(s);
532 sc->sc_wseek = 0;
533 sc->sc_rseek = 0;
534 break;
535
536 case AUDIO_SETINFO:
537 rc = audio_setinfo(sc, (audio_info_t *)status);
538 break;
539
540 case AUDIO_DRAIN:
541 rc = audio_drain(au);
542 break;
543
544 default:
545 rc = D_INVALID_OPERATION;
546 break;
547 }
548 return (rc);
549 }
550
551
552 /*
553 * Interrupt routine
554 */
555 boolean_t
556 audio_hwintr(
557 void *status,
558 unsigned int s_in,
559 unsigned int *s_out)
560 {
561 register au_io_t *au = ((struct audio_softc *) status)->sc_au;
562 register au_cb_t *cb;
563 register int h, t, k;
564 register boolean_t wakeit = FALSE;
565
566 ++au->au_stamp;
567
568 /* receive incoming data */
569 cb = &au->au_rb;
570 h = cb->cb_head;
571 t = cb->cb_tail;
572 k = AUCB_MOD(t + 1);
573 if (h == k)
574 cb->cb_drops++;
575 else if (cb->cb_pause != 0)
576 cb->cb_pdrops++;
577 else {
578 cb->cb_data[t] = s_in;
579 cb->cb_tail = t = k;
580 }
581 if (AUCB_MOD(t - h) >= cb->cb_thresh) {
582 cb->cb_thresh = AUCB_SIZE;
583 cb->cb_waking = 1;
584 wakeit = TRUE;
585 }
586 /* send outgoing data */
587 cb = &au->au_wb;
588 h = cb->cb_head;
589 t = cb->cb_tail;
590 k = 0;
591 if (h == t)
592 cb->cb_drops++;
593 else if (cb->cb_pause != 0)
594 cb->cb_pdrops++;
595 else {
596 cb->cb_head = h = AUCB_MOD(h + 1);
597 *s_out = cb->cb_data[h];
598 k = 1;
599 }
600 if (AUCB_MOD(t - h) <= cb->cb_thresh) {
601 cb->cb_thresh = -1;
602 cb->cb_waking = 1;
603 wakeit = TRUE;
604 }
605 if (wakeit)
606 audio_swintr((struct audio_softc *) status);
607 return (k == 1);
608 }
609
610 private void
611 audio_swintr(
612 register struct audio_softc *sc)
613 {
614 register au_io_t *au = sc->sc_au;
615
616 if (au->au_rb.cb_waking != 0) {
617 au->au_rb.cb_waking = 0;
618 wakeup(&au->au_rb);
619 }
620 if (au->au_wb.cb_waking != 0) {
621 au->au_wb.cb_waking = 0;
622 wakeup(&au->au_wb);
623 }
624 }
625
626 private int
627 audio_setinfo(sc, ai)
628 struct audio_softc *sc;
629 audio_info_t *ai;
630 {
631 struct audio_prinfo *r = &ai->record, *p = &ai->play;
632 register int bsize;
633 register au_io_t *au = sc->sc_au;
634 spl_t s;
635
636 (*sc->ops->setgains)(sc->hw, p->gain, r->gain, ai->monitor_gain );
637
638 if (p->pause != (unsigned char)~0)
639 au->au_wb.cb_pause = p->pause;
640 if (r->pause != (unsigned char)~0)
641 au->au_rb.cb_pause = r->pause;
642
643 if (p->port != ~0)
644 (*sc->ops->setport)(sc->hw, p->port);
645
646 if (ai->blocksize != ~0) {
647 if (ai->blocksize == 0)
648 bsize = ai->blocksize = DEFBLKSIZE;
649 else if (ai->blocksize > MAXBLKSIZE)
650 bsize = ai->blocksize = MAXBLKSIZE;
651 else
652 bsize = ai->blocksize;
653
654 s = splaudio();
655 au->au_blksize = bsize;
656 /* AUDIO_FLUSH */
657 AUCB_INIT(&au->au_rb);
658 AUCB_INIT(&au->au_wb);
659 splx(s);
660
661 }
662 if (ai->hiwat != ~0 && (unsigned)ai->hiwat < AUCB_SIZE)
663 au->au_hiwat = ai->hiwat;
664 if (ai->lowat != ~0 && ai->lowat < AUCB_SIZE)
665 au->au_lowat = ai->lowat;
666 if (ai->backlog != ~0 && ai->backlog < (AUCB_SIZE/2))
667 au->au_backlog = ai->backlog;
668
669 return (0);
670 }
671
672 private int
673 audio_getinfo(sc, ai)
674 struct audio_softc *sc;
675 audio_info_t *ai;
676 {
677 struct audio_prinfo *r = &ai->record, *p = &ai->play;
678 register au_io_t *au = sc->sc_au;
679
680 p->sample_rate = r->sample_rate = 8000;
681 p->channels = r->channels = 1;
682 p->precision = r->precision = 8;
683 p->encoding = r->encoding = AUDIO_ENCODING_ULAW;
684
685 (*sc->ops->getgains)(sc->hw, &p->gain, &r->gain, &ai->monitor_gain );
686
687 r->port = AUDIO_MIKE;
688 p->port = (*sc->ops->getport)(sc->hw);
689
690 p->pause = au->au_wb.cb_pause;
691 r->pause = au->au_rb.cb_pause;
692 p->error = au->au_wb.cb_drops != 0;
693 r->error = au->au_rb.cb_drops != 0;
694
695 /* Now this is funny. If you got here it means you must have
696 opened the device, so how could it possibly be closed ?
697 Unless we upgrade the berkeley code to check if the chip
698 is currently playing and/or recording... Later. */
699 p->open = TRUE;
700 r->open = TRUE;
701
702 p->samples = au->au_stamp - au->au_wb.cb_pdrops;
703 r->samples = au->au_stamp - au->au_rb.cb_pdrops;
704
705 p->seek = sc->sc_wseek;
706 r->seek = sc->sc_rseek;
707
708 ai->blocksize = au->au_blksize;
709 ai->hiwat = au->au_hiwat;
710 ai->lowat = au->au_lowat;
711 ai->backlog = au->au_backlog;
712
713 return (0);
714 }
715
716 #if 1
717 audio_status(int unit)
718 {
719 struct audio_softc *sc = unit_to_softc(unit);
720 au_io_t *au;
721
722 if (!sc) {
723 db_printf("No such thing\n");
724 return 0;
725 }
726 db_printf("@%lx: wseek %d rseek %d, au @%lx\n",
727 sc, sc->sc_wseek, sc->sc_rseek, sc->sc_au);
728 if (!(au = sc->sc_au)) return 0;
729
730 db_printf("au: stamp %x lo %x hi %x blk %x blg %x\n",
731 au->au_stamp, au->au_lowat, au->au_hiwat,
732 au->au_blksize, au->au_backlog);
733 audio_queue_status(&au->au_rb, "read");
734 audio_queue_status(&au->au_wb, "write");
735 return 0;
736 }
737 audio_queue_status( au_cb_t *cb, char *logo)
738 {
739 db_printf("%s ring status:\n", logo);
740 db_printf(" h %x t %x sh %x w %d p %d d %x pd %x\n",
741 cb->cb_head, cb->cb_tail, cb->cb_thresh,
742 cb->cb_waking, cb->cb_pause, (long)cb->cb_drops,
743 (long)cb->cb_pdrops);
744 }
745
746 #endif
747
748 #endif /* NAUDIO > 0 */
749
Cache object: a8ab65fffcd0387b0669c5805eebe5d1
|