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