summaryrefslogtreecommitdiff
path: root/chips/audio.c
diff options
context:
space:
mode:
Diffstat (limited to 'chips/audio.c')
-rw-r--r--chips/audio.c733
1 files changed, 0 insertions, 733 deletions
diff --git a/chips/audio.c b/chips/audio.c
deleted file mode 100644
index 00bf2be..0000000
--- a/chips/audio.c
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * Mach Operating System
- * Copyright (c) 1993 Carnegie Mellon University
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
- * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
-/*-
- * Copyright (c) 1991, 1992 The Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the Computer Systems
- * Engineering Group at Lawrence Berkeley Laboratory.
- * 4. The name of the Laboratory may not be used to endorse or promote
- * products derived from this software without specific prior written
- * permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <audio.h>
-#if NAUDIO > 0
-
-#include <mach_kdb.h>
-#include <platforms.h>
-
-#include <mach/std_types.h>
-#include <machine/machspl.h>
-#include <kern/kalloc.h>
-#include <kern/sched_prim.h>
-#include <chips/busses.h>
-
-#include <device/device_types.h>
-#include <device/io_req.h>
-#include <device/ds_routines.h>
-#include <device/audio_status.h> /* user interface */
-#include <chips/audio_defs.h> /* chip interface */
-#include <chips/audio_config.h> /* machdep config */
-
-#define private static
-
-/*
- * Exported functions and data structures
- * [see header file for listing]
- */
-int audio_blocksize = DEFBLKSIZE; /* patchable */
-int audio_backlog = 400; /* 50ms in samples */
-
-/*
- * Software state, per AMD79C30 audio chip.
- */
-private
-struct audio_softc {
- void *hw; /* chip status */
- audio_switch_t *ops; /* chip operations */
- au_io_t *sc_au; /* recv and xmit buffers, etc */
-
-
- unsigned int sc_wseek; /* timestamp of last frame written */
- unsigned int sc_rseek; /* timestamp of last frame read */
-#if 0
- struct selinfo sc_wsel; /* write selector */
- struct selinfo sc_rsel; /* read selector */
-#endif
-
-} audio_softc_data[NAUDIO];
-
-#define unit_to_softc(u) &audio_softc_data[u]
-
-
-/* forward declarations */
-private int audio_sleep (au_cb_t *cb, int thresh);
-private void audio_swintr (struct audio_softc *sc);
-
-/*
- * Audio chip found.
- */
-void
-audio_attach(
- void *hw, /* IN, chip status */
- audio_switch_t *ops,
- void **audio_status) /* OUT, audio status */
-{
- register struct audio_softc *sc;
- static int next = 0;
-
- if (next >= NAUDIO)
- panic("Please configure more than %d audio devices\n", NAUDIO);
- sc = &audio_softc_data[next++];
-
- printf(" audio");
-
- sc->hw = hw;
- sc->ops = ops;
-
- *audio_status = (void *)sc;
-}
-
-
-private int audio_setinfo (struct audio_softc *, audio_info_t *);
-private int audio_getinfo (struct audio_softc *, audio_info_t *);
-
-io_return_t
-audio_open(
- int unit,
- int mode,
- io_req_t req)
-{
- register struct audio_softc *sc;
- register au_io_t *au;
-
- sc = unit_to_softc(unit);
- if (unit > NAUDIO || (!sc->hw))
- return (D_NO_SUCH_DEVICE);
-
- if (!sc->sc_au) {
- sc->sc_au = (au_io_t *) kalloc(sizeof(au_io_t));
- bzero(sc->sc_au, sizeof(au_io_t));
- }
- au = sc->sc_au;
-
- au->au_lowat = audio_blocksize;
- au->au_hiwat = AUCB_SIZE - au->au_lowat;
- au->au_blksize = audio_blocksize;
- au->au_backlog = audio_backlog;
-
- /* set up read and write blocks and `dead sound' zero value. */
- AUCB_INIT(&au->au_rb);
- au->au_rb.cb_thresh = AUCB_SIZE;
- AUCB_INIT(&au->au_wb);
- au->au_wb.cb_thresh = -1;
-
- /* nothing read or written yet */
- sc->sc_rseek = 0;
- sc->sc_wseek = 0;
-
- (*sc->ops->init)(sc->hw);
-
- return (0);
-}
-
-private int
-audio_drain(
- register au_io_t *au)
-{
- register int error;
-
- while (!AUCB_EMPTY(&au->au_wb))
- if ((error = audio_sleep(&au->au_wb, 0)) != 0)
- return (error);
- return (0);
-}
-
-/*
- * Close an audio chip.
- */
-/* ARGSUSED */
-io_return_t
-audio_close(
- int unit)
-{
- register struct audio_softc *sc = unit_to_softc(unit);
- register au_cb_t *cb;
- register spl_t s;
-
- /*
- * Block until output drains, but allow ^C interrupt.
- */
- sc->sc_au->au_lowat = 0; /* avoid excessive wakeups */
-
- /*
- * If there is pending output, let it drain (unless
- * the output is paused).
- */
- cb = &sc->sc_au->au_wb;
- s = splaudio();
- if (!AUCB_EMPTY(cb) && !cb->cb_pause)
- (void)audio_drain(sc->sc_au);
- /*
- * Disable interrupts, and done.
- */
- (*sc->ops->close)(sc->hw);
- splx(s);
- return (D_SUCCESS);
-}
-
-private int
-audio_sleep(
- register au_cb_t *cb,
- register int thresh)
-{
- register spl_t s = splaudio();
-
- cb->cb_thresh = thresh;
- assert_wait((event_t)cb, TRUE);
- splx(s);
- thread_block((void (*)()) 0);
- return (0); /* XXXX */
-}
-
-io_return_t
-audio_read(
- int unit,
- io_req_t ior)
-{
- register struct audio_softc *sc = unit_to_softc(unit);
- register au_cb_t *cb;
- register int n, head, taildata;
- register int blocksize = sc->sc_au->au_blksize;
- io_return_t rc;
- unsigned char *data;
-
- /*
- * Allocate read buffer
- */
- rc = device_read_alloc(ior, (vm_size_t)ior->io_count);
- if (rc != KERN_SUCCESS)
- return rc;
- data = (unsigned char *) ior->io_data;
- ior->io_residual = ior->io_count;
-
- cb = &sc->sc_au->au_rb;
- cb->cb_drops = 0;
- sc->sc_rseek = sc->sc_au->au_stamp - AUCB_LEN(cb);
- do {
- while (AUCB_LEN(cb) < blocksize) {
-
- if (ior->io_mode & D_NODELAY)
- return (D_WOULD_BLOCK);
-
- if ((rc = audio_sleep(cb, blocksize)) != 0)
- return(rc);
- }
- /*
- * The space calculation can only err on the short
- * side if an interrupt occurs during processing:
- * only cb_tail is altered in the interrupt code.
- */
- head = cb->cb_head;
- if ((n = AUCB_LEN(cb)) > ior->io_residual)
- n = ior->io_residual;
- taildata = AUCB_SIZE - head;
-
- if (n > taildata) {
- bcopy(cb->cb_data + head, data, taildata);
- bcopy(cb->cb_data, data + taildata, n - taildata);
- } else
- bcopy(cb->cb_data + head, data, n);
- data += n;
- ior->io_residual -= n;
-
- head = AUCB_MOD(head + n);
- cb->cb_head = head;
- } while (ior->io_residual >= blocksize);
-
- return (rc);
-}
-
-io_return_t
-audio_write(
- int unit,
- io_req_t ior)
-{
- register struct audio_softc *sc = unit_to_softc(unit);
- register au_io_t *au = sc->sc_au;
- register au_cb_t *cb = &au->au_wb;
- register int n, tail, tailspace, first, watermark;
- io_return_t rc;
- unsigned char *data;
- vm_offset_t addr = 0;
-
- if (!(ior->io_op & IO_INBAND)) {
- /*
- * Copy out-of-line data into kernel address space.
- * Since data is copied as page list, it will be
- * accessible.
- */
- vm_map_copy_t copy = (vm_map_copy_t) ior->io_data;
- kern_return_t kr;
-
- kr = vm_map_copyout(device_io_map, &addr, copy);
- if (kr != KERN_SUCCESS)
- return kr;
- data = (unsigned char *) addr;
- } else
- data = (unsigned char *) ior->io_data;
- ior->io_residual = ior->io_count;
-
- rc = D_SUCCESS;
- first = 1;
- while (ior->io_residual > 0) {
- watermark = au->au_hiwat;
- while (AUCB_LEN(cb) > watermark) {
-
- if (ior->io_mode & D_NODELAY) {
- rc = D_WOULD_BLOCK;
- goto out;
- }
-
- if ((rc = audio_sleep(cb, watermark)) != 0)
- goto out;
-
- watermark = au->au_lowat;
- }
- /*
- * The only value that can change on an interrupt is
- * cb->cb_head. We only pull that out once to decide
- * how much to write into cb_data; if we lose a race
- * and cb_head changes, we will merely be overly
- * conservative. For a legitimate time stamp,
- * however, we need to synchronize the accesses to
- * au_stamp and cb_head at a high ipl below.
- */
- tail = cb->cb_tail;
- if ((n = (AUCB_SIZE - 1) - AUCB_LEN(cb)) > ior->io_residual) {
- n = ior->io_residual;
- if (cb->cb_head == tail &&
- n <= au->au_blksize &&
- au->au_stamp - sc->sc_wseek > 400) {
- /*
- * the write is 'small', the buffer is empty
- * and we have been silent for at least 50ms
- * so we might be dealing with an application
- * that writes frames synchronously with
- * reading them. If so, we need an output
- * backlog to cover scheduling delays or
- * there will be gaps in the sound output.
- * Also take this opportunity to reset the
- * buffer pointers in case we ended up on
- * a bad boundary (odd byte, blksize bytes
- * from end, etc.).
- */
- register unsigned long *ip;
- register unsigned long muzero;
- spl_t s;
- register int i;
-
- s = splaudio();
- cb->cb_head = cb->cb_tail = 0;
- splx(s);
-
- tail = au->au_backlog;
- ip = (unsigned long *)cb->cb_data;
- muzero = sample_rpt_long(0x7fL);
- for (i = tail / sizeof muzero; --i >= 0; )
- *ip++ = muzero;
- }
- }
- tailspace = AUCB_SIZE - tail;
- if (n > tailspace) {
- /* write first part at tail and rest at head */
- bcopy(data, cb->cb_data + tail, tailspace);
- bcopy(data + tailspace, cb->cb_data,
- n - tailspace);
- } else
- bcopy(data, cb->cb_data + tail, n);
- data += n;
- ior->io_residual -= n;
-
- tail = AUCB_MOD(tail + n);
- if (first) {
- register spl_t s = splaudio();
- sc->sc_wseek = AUCB_LEN(cb) + au->au_stamp + 1;
- /*
- * To guarantee that a write is contiguous in the
- * sample space, we clear the drop count the first
- * time through. If we later get drops, we will
- * break out of the loop below, before writing
- * a new frame.
- */
- cb->cb_drops = 0;
- cb->cb_tail = tail;
- splx(s);
- first = 0;
- } else {
-#if 0
- if (cb->cb_drops != 0)
- break;
-#endif
- cb->cb_tail = tail;
- }
- }
-out:
- if (!(ior->io_op & IO_INBAND))
- (void) vm_deallocate(device_io_map, addr, ior->io_count);
- return (rc);
-}
-
-#include <sys/ioctl.h>
-
-io_return_t
-audio_get_status(
- int unit,
- dev_flavor_t flavor,
- dev_status_t status,
- natural_t *status_count)
-{
- register struct audio_softc *sc = unit_to_softc(unit);
- register au_io_t *au = sc->sc_au;
- io_return_t rc = D_SUCCESS;
- spl_t s;
-
- switch (flavor) {
-
- case AUDIO_GETMAP:
- case AUDIOGETREG:
- rc = (*sc->ops->getstate)(sc->hw, flavor,
- (void *)status, status_count);
- break;
-
- /*
- * Number of read samples dropped. We don't know where or
- * when they were dropped.
- */
- case AUDIO_RERROR:
- *(int *)status = au->au_rb.cb_drops;
- *status_count = 1;
- break;
-
- case AUDIO_WERROR:
- *(int *)status = au->au_wb.cb_drops;
- *status_count = 1;
- break;
-
- /*
- * How many samples will elapse until mike hears the first
- * sample of what we last wrote?
- */
- case AUDIO_WSEEK:
- s = splaudio();
- *(unsigned int *)status = sc->sc_wseek - au->au_stamp
- + AUCB_LEN(&au->au_rb);
- splx(s);
- *status_count = 1;
- break;
-
- case AUDIO_GETINFO:
- rc = audio_getinfo(sc, (audio_info_t *)status);
- *status_count = sizeof(audio_info_t) / sizeof(int);
- break;
-
- default:
- rc = D_INVALID_OPERATION;
- break;
- }
- return (rc);
-}
-
-io_return_t
-audio_set_status(
- int unit,
- dev_flavor_t flavor,
- dev_status_t status,
- natural_t status_count)
-{
- register struct audio_softc *sc = unit_to_softc(unit);
- register au_io_t *au = sc->sc_au;
- io_return_t rc = D_SUCCESS;
- spl_t s;
-
- switch (flavor) {
-
- case AUDIO_SETMAP:
- case AUDIOSETREG:
- rc = (*sc->ops->setstate)(sc->hw, flavor,
- (void *)status, status_count);
- break;
-
- case AUDIO_FLUSH:
- s = splaudio();
- AUCB_INIT(&au->au_rb);
- AUCB_INIT(&au->au_wb);
- au->au_stamp = 0;
- splx(s);
- sc->sc_wseek = 0;
- sc->sc_rseek = 0;
- break;
-
- case AUDIO_SETINFO:
- rc = audio_setinfo(sc, (audio_info_t *)status);
- break;
-
- case AUDIO_DRAIN:
- rc = audio_drain(au);
- break;
-
- default:
- rc = D_INVALID_OPERATION;
- break;
- }
- return (rc);
-}
-
-
-/*
- * Interrupt routine
- */
-boolean_t
-audio_hwintr(
- void *status,
- unsigned int s_in,
- unsigned int *s_out)
-{
- register au_io_t *au = ((struct audio_softc *) status)->sc_au;
- register au_cb_t *cb;
- register int h, t, k;
- register boolean_t wakeit = FALSE;
-
- ++au->au_stamp;
-
- /* receive incoming data */
- cb = &au->au_rb;
- h = cb->cb_head;
- t = cb->cb_tail;
- k = AUCB_MOD(t + 1);
- if (h == k)
- cb->cb_drops++;
- else if (cb->cb_pause != 0)
- cb->cb_pdrops++;
- else {
- cb->cb_data[t] = s_in;
- cb->cb_tail = t = k;
- }
- if (AUCB_MOD(t - h) >= cb->cb_thresh) {
- cb->cb_thresh = AUCB_SIZE;
- cb->cb_waking = 1;
- wakeit = TRUE;
- }
- /* send outgoing data */
- cb = &au->au_wb;
- h = cb->cb_head;
- t = cb->cb_tail;
- k = 0;
- if (h == t)
- cb->cb_drops++;
- else if (cb->cb_pause != 0)
- cb->cb_pdrops++;
- else {
- cb->cb_head = h = AUCB_MOD(h + 1);
- *s_out = cb->cb_data[h];
- k = 1;
- }
- if (AUCB_MOD(t - h) <= cb->cb_thresh) {
- cb->cb_thresh = -1;
- cb->cb_waking = 1;
- wakeit = TRUE;
- }
- if (wakeit)
- audio_swintr((struct audio_softc *) status);
- return (k == 1);
-}
-
-private void
-audio_swintr(
- register struct audio_softc *sc)
-{
- register au_io_t *au = sc->sc_au;
-
- if (au->au_rb.cb_waking != 0) {
- au->au_rb.cb_waking = 0;
- wakeup(&au->au_rb);
- }
- if (au->au_wb.cb_waking != 0) {
- au->au_wb.cb_waking = 0;
- wakeup(&au->au_wb);
- }
-}
-
-private int
-audio_setinfo(
- struct audio_softc *sc,
- audio_info_t *ai)
-{
- struct audio_prinfo *r = &ai->record, *p = &ai->play;
- register int bsize;
- register au_io_t *au = sc->sc_au;
- spl_t s;
-
- (*sc->ops->setgains)(sc->hw, p->gain, r->gain, ai->monitor_gain );
-
- if (p->pause != (unsigned char)~0)
- au->au_wb.cb_pause = p->pause;
- if (r->pause != (unsigned char)~0)
- au->au_rb.cb_pause = r->pause;
-
- if (p->port != ~0)
- (*sc->ops->setport)(sc->hw, p->port);
-
- if (ai->blocksize != ~0) {
- if (ai->blocksize == 0)
- bsize = ai->blocksize = DEFBLKSIZE;
- else if (ai->blocksize > MAXBLKSIZE)
- bsize = ai->blocksize = MAXBLKSIZE;
- else
- bsize = ai->blocksize;
-
- s = splaudio();
- au->au_blksize = bsize;
- /* AUDIO_FLUSH */
- AUCB_INIT(&au->au_rb);
- AUCB_INIT(&au->au_wb);
- splx(s);
-
- }
- if (ai->hiwat != ~0 && (unsigned)ai->hiwat < AUCB_SIZE)
- au->au_hiwat = ai->hiwat;
- if (ai->lowat != ~0 && ai->lowat < AUCB_SIZE)
- au->au_lowat = ai->lowat;
- if (ai->backlog != ~0 && ai->backlog < (AUCB_SIZE/2))
- au->au_backlog = ai->backlog;
-
- return (0);
-}
-
-private int
-audio_getinfo(
- struct audio_softc *sc,
- audio_info_t *ai)
-{
- struct audio_prinfo *r = &ai->record, *p = &ai->play;
- register au_io_t *au = sc->sc_au;
-
- p->sample_rate = r->sample_rate = 8000;
- p->channels = r->channels = 1;
- p->precision = r->precision = 8;
- p->encoding = r->encoding = AUDIO_ENCODING_ULAW;
-
- (*sc->ops->getgains)(sc->hw, &p->gain, &r->gain, &ai->monitor_gain );
-
- r->port = AUDIO_MIKE;
- p->port = (*sc->ops->getport)(sc->hw);
-
- p->pause = au->au_wb.cb_pause;
- r->pause = au->au_rb.cb_pause;
- p->error = au->au_wb.cb_drops != 0;
- r->error = au->au_rb.cb_drops != 0;
-
- /* Now this is funny. If you got here it means you must have
- opened the device, so how could it possibly be closed ?
- Unless we upgrade the berkeley code to check if the chip
- is currently playing and/or recording... Later. */
- p->open = TRUE;
- r->open = TRUE;
-
- p->samples = au->au_stamp - au->au_wb.cb_pdrops;
- r->samples = au->au_stamp - au->au_rb.cb_pdrops;
-
- p->seek = sc->sc_wseek;
- r->seek = sc->sc_rseek;
-
- ai->blocksize = au->au_blksize;
- ai->hiwat = au->au_hiwat;
- ai->lowat = au->au_lowat;
- ai->backlog = au->au_backlog;
-
- return (0);
-}
-
-#if MACH_KDB
-#include <ddb/db_output.h>
-
-void audio_queue_status( au_cb_t *cb, char *logo)
-{
- db_printf("%s ring status:\n", logo);
- db_printf(" h %x t %x sh %x w %d p %d d %x pd %x\n",
- cb->cb_head, cb->cb_tail, cb->cb_thresh,
- cb->cb_waking, cb->cb_pause, (long)cb->cb_drops,
- (long)cb->cb_pdrops);
-}
-
-int audio_status(int unit)
-{
- struct audio_softc *sc = unit_to_softc(unit);
- au_io_t *au;
-
- if (!sc) {
- db_printf("No such thing\n");
- return 0;
- }
- db_printf("@%lx: wseek %d rseek %d, au @%lx\n",
- sc, sc->sc_wseek, sc->sc_rseek, sc->sc_au);
- if (!(au = sc->sc_au)) return 0;
-
- db_printf("au: stamp %x lo %x hi %x blk %x blg %x\n",
- au->au_stamp, au->au_lowat, au->au_hiwat,
- au->au_blksize, au->au_backlog);
- audio_queue_status(&au->au_rb, "read");
- audio_queue_status(&au->au_wb, "write");
-
- return 0;
-}
-#endif /* MACH_KDB */
-
-#endif /* NAUDIO > 0 */
-