diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2011-09-03 20:04:05 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2011-09-03 20:04:05 +0000 |
commit | ebad5b112be0543c366af0ecb97e46ccf0b5296c (patch) | |
tree | 6300f215de7caaa0dbcf4dc74a1c9d9a8d3a12a1 /sys/arch/sparc/dev | |
parent | e358ffe8c982bfe8f482720357793a2286399e90 (diff) |
Switch the sparc audioamd(4) code to the MI driver; tested on SPARCclassic
with and without option AUDIO_C_HANDLER.
Diffstat (limited to 'sys/arch/sparc/dev')
-rw-r--r-- | sys/arch/sparc/dev/amd7930.c | 872 | ||||
-rw-r--r-- | sys/arch/sparc/dev/amd7930var.h | 86 | ||||
-rw-r--r-- | sys/arch/sparc/dev/audioamd.c | 450 | ||||
-rw-r--r-- | sys/arch/sparc/dev/audioamdvar.h | 48 |
4 files changed, 498 insertions, 958 deletions
diff --git a/sys/arch/sparc/dev/amd7930.c b/sys/arch/sparc/dev/amd7930.c deleted file mode 100644 index e82dd265a00..00000000000 --- a/sys/arch/sparc/dev/amd7930.c +++ /dev/null @@ -1,872 +0,0 @@ -/* $OpenBSD: amd7930.c,v 1.34 2010/09/20 06:33:47 matthew Exp $ */ -/* $NetBSD: amd7930.c,v 1.37 1998/03/30 14:23:40 pk Exp $ */ - -/* - * Copyright (c) 1995 Rolf Grossmann - * 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 Rolf Grossmann. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <sys/param.h> -#include <sys/systm.h> -#include <sys/errno.h> -#include <sys/ioctl.h> -#include <sys/device.h> -#include <sys/proc.h> - -#include <machine/autoconf.h> -#include <machine/cpu.h> - -#include <sys/audioio.h> -#include <dev/audio_if.h> - -#include <dev/ic/am7930reg.h> -#include <sparc/dev/amd7930var.h> - -#define AUDIO_ROM_NAME "audio" - -#ifdef AUDIO_DEBUG -int amd7930debug = 0; -#define DPRINTF(x) if (amd7930debug) printf x -#else -#define DPRINTF(x) -#endif - -/* - * Define AUDIO_C_HANDLER to force using non-fast trap routines. - */ -/* #define AUDIO_C_HANDLER */ - -/* - * Software state, per AMD79C30 audio chip. - */ -struct amd7930_softc { - struct device sc_dev; /* base device */ - - int sc_open; /* single use device */ - int sc_locked; /* true when transferring data */ - struct mapreg sc_map; /* current contents of map registers */ - - u_char sc_rlevel; /* record level */ - u_char sc_plevel; /* play level */ - u_char sc_mlevel; /* monitor level */ - u_char sc_out_port; /* output port */ - - /* interfacing with the interrupt handlers */ - void (*sc_rintr)(void *); /* input completion intr handler */ - void *sc_rarg; /* arg for sc_rintr() */ - void (*sc_pintr)(void *); /* output completion intr handler */ - void *sc_parg; /* arg for sc_pintr() */ - - /* sc_au is special in that the hardware interrupt handler uses it */ - struct auio sc_au; /* recv and xmit buffers, etc */ -#define sc_hwih sc_au.au_ih /* hardware interrupt vector */ -#define sc_swih sc_au.au_swih /* software interrupt cookie */ -}; - -#ifndef AUDIO_C_HANDLER -struct auio *auiop; -#endif /* AUDIO_C_HANDLER */ -int amd7930hwintr(void *); -void amd7930swintr(void *); - -/* forward declarations */ -void audio_setmap(volatile struct amd7930 *, struct mapreg *); -static void init_amd(volatile struct amd7930 *); -int amd7930_shareintr(void *); - -/* autoconfiguration driver */ -void amd7930attach(struct device *, struct device *, void *); -int amd7930match(struct device *, void *, void *); - -struct cfattach audioamd_ca = { - sizeof(struct amd7930_softc), amd7930match, amd7930attach -}; - -struct cfdriver audioamd_cd = { - NULL, "audioamd", DV_DULL -}; - -struct audio_device amd7930_device = { - "amd7930", - "x", - "audioamd" -}; - -/* Write 16 bits of data from variable v to the data port of the audio chip */ -#define WAMD16(amd, v) ((amd)->dr = (v), (amd)->dr = (v) >> 8) - -/* The following tables stolen from former (4.4Lite's) sys/sparc/bsd_audio.c */ - -/* - * gx, gr & stg gains. this table must contain 256 elements with - * the 0th being "infinity" (the magic value 9008). The remaining - * elements match sun's gain curve (but with higher resolution): - * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps. - */ -static const u_short gx_coeff[256] = { - 0x9008, 0x8e7c, 0x8e51, 0x8e45, 0x8d42, 0x8d3b, 0x8c36, 0x8c33, - 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22, - 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b, - 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb, - 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a, - 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213, - 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231, - 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4, - 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2, - 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa, - 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b, - 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b, - 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd, - 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808, - 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243, - 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224, - 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb, - 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33, - 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32, - 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323, - 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a, - 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23, - 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1, - 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333, - 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227, - 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6, - 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2, - 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba, - 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033, - 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021, - 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012, - 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e, -}; - -/* - * second stage play gain. - */ -static const u_short ger_coeff[] = { - 0x431f, /* 5. dB */ - 0x331f, /* 5.5 dB */ - 0x40dd, /* 6. dB */ - 0x11dd, /* 6.5 dB */ - 0x440f, /* 7. dB */ - 0x411f, /* 7.5 dB */ - 0x311f, /* 8. dB */ - 0x5520, /* 8.5 dB */ - 0x10dd, /* 9. dB */ - 0x4211, /* 9.5 dB */ - 0x410f, /* 10. dB */ - 0x111f, /* 10.5 dB */ - 0x600b, /* 11. dB */ - 0x00dd, /* 11.5 dB */ - 0x4210, /* 12. dB */ - 0x110f, /* 13. dB */ - 0x7200, /* 14. dB */ - 0x2110, /* 15. dB */ - 0x2200, /* 15.9 dB */ - 0x000b, /* 16.9 dB */ - 0x000f /* 18. dB */ -#define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0])) -}; - -/* - * Define our interface to the higher level audio driver. - */ -int amd7930_open(void *, int); -void amd7930_close(void *); -int amd7930_query_encoding(void *, struct audio_encoding *); -int amd7930_set_params(void *, int, int, struct audio_params *, struct audio_params *); -int amd7930_round_blocksize(void *, int); -int amd7930_commit_settings(void *); -int amd7930_start_output(void *, void *, int, void (*)(void *), void *); -int amd7930_start_input(void *, void *, int, void (*)(void *), void *); -int amd7930_halt_output(void *); -int amd7930_halt_input(void *); -int amd7930_getdev(void *, struct audio_device *); -int amd7930_set_port(void *, mixer_ctrl_t *); -int amd7930_get_port(void *, mixer_ctrl_t *); -int amd7930_query_devinfo(void *, mixer_devinfo_t *); -int amd7930_get_props(void *); - -struct audio_hw_if sa_hw_if = { - amd7930_open, - amd7930_close, - NULL, - amd7930_query_encoding, - amd7930_set_params, - amd7930_round_blocksize, - amd7930_commit_settings, - NULL, - NULL, - amd7930_start_output, - amd7930_start_input, - amd7930_halt_output, - amd7930_halt_input, - NULL, - amd7930_getdev, - NULL, - amd7930_set_port, - amd7930_get_port, - amd7930_query_devinfo, - NULL, - NULL, - NULL, - NULL, - amd7930_get_props, - NULL, - NULL, - NULL -}; - -/* autoconfig routines */ - -int -amd7930match(parent, vcf, aux) - struct device *parent; - void *vcf, *aux; -{ - register struct confargs *ca = aux; - register struct romaux *ra = &ca->ca_ra; - - if (CPU_ISSUN4) - return (0); - return (strcmp(AUDIO_ROM_NAME, ra->ra_name) == 0); -} - -/* - * Audio chip found. - */ -void -amd7930attach(parent, self, args) - struct device *parent, *self; - void *args; -{ - register struct amd7930_softc *sc = (struct amd7930_softc *)self; - register struct confargs *ca = args; - register struct romaux *ra = &ca->ca_ra; - register volatile struct amd7930 *amd; - register int pri; - - if (ra->ra_nintr != 1) { - printf(": expected 1 interrupt, got %d\n", ra->ra_nintr); - return; - } - pri = ra->ra_intr[0].int_pri; - printf(" pri %d, softpri %d\n", pri, IPL_AUSOFT); - amd = (volatile struct amd7930 *)(ra->ra_vaddr ? - ra->ra_vaddr : mapiodev(ra->ra_reg, 0, sizeof (*amd))); - - sc->sc_map.mr_mmr1 = AMD_MMR1_GX | AMD_MMR1_GER | - AMD_MMR1_GR | AMD_MMR1_STG; - sc->sc_au.au_amd = amd; - /* set boot defaults */ - sc->sc_rlevel = 128; - sc->sc_plevel = 128; - sc->sc_mlevel = 0; - sc->sc_out_port = SUNAUDIO_SPEAKER; - - init_amd(amd); - - /* - * Register interrupt handlers. We'll prefer a fast trap (unless - * AUDIO_C_HANDLER is defined), with a sharing callback so that we - * can revert into a regular trap vector if necessary. - */ -#ifndef AUDIO_C_HANDLER - sc->sc_hwih.ih_vec = pri; - if (intr_fasttrap(pri, amd7930_trap, amd7930_shareintr, sc) == 0) { - auiop = &sc->sc_au; - evcount_attach(&sc->sc_hwih.ih_count, sc->sc_dev.dv_xname, - &sc->sc_hwih.ih_vec); - } else { -#ifdef AUDIO_DEBUG - printf("%s: unable to register fast trap handler\n", - self->dv_xname); -#endif -#else - { -#endif - sc->sc_hwih.ih_fun = amd7930hwintr; - sc->sc_hwih.ih_arg = &sc->sc_au; - intr_establish(pri, &sc->sc_hwih, IPL_AUHARD, - sc->sc_dev.dv_xname); - } - sc->sc_swih = softintr_establish(IPL_AUSOFT, amd7930swintr, sc); - - audio_attach_mi(&sa_hw_if, sc, &sc->sc_dev); - amd7930_commit_settings(sc); -} - -static void -init_amd(amd) - register volatile struct amd7930 *amd; -{ - /* disable interrupts */ - amd->cr = AMDR_INIT; - amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; - - /* - * Initialize the mux unit. We use MCR3 to route audio (MAP) - * through channel Bb. MCR1 and MCR2 are unused. - * Setting the INT enable bit in MCR4 will generate an interrupt - * on each converted audio sample. - */ - amd->cr = AMDR_MUX_1_4; - amd->dr = 0; - amd->dr = 0; - amd->dr = (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA; - amd->dr = AMD_MCR4_INT_ENABLE; -} - -int -amd7930_open(addr, flags) - void *addr; - int flags; -{ - struct amd7930_softc *sc = addr; - - DPRINTF(("sa_open: unit %p\n", sc)); - - if (sc->sc_open) - return (EBUSY); - sc->sc_open = 1; - sc->sc_locked = 0; - sc->sc_rintr = 0; - sc->sc_rarg = 0; - sc->sc_pintr = 0; - sc->sc_parg = 0; - - sc->sc_au.au_rdata = 0; - sc->sc_au.au_pdata = 0; - - DPRINTF(("saopen: ok -> sc=0x%x\n",sc)); - - return (0); -} - -void -amd7930_close(addr) - void *addr; -{ - register struct amd7930_softc *sc = addr; - - DPRINTF(("sa_close: sc=0x%x\n", sc)); - /* - * halt i/o, clear open flag, and done. - */ - amd7930_halt_input(sc); - amd7930_halt_output(sc); - sc->sc_open = 0; - - DPRINTF(("sa_close: closed.\n")); -} - -int -amd7930_set_params(addr, setmode, usemode, p, r) - void *addr; - int setmode, usemode; - struct audio_params *p, *r; -{ - p->encoding = AUDIO_ENCODING_ULAW; - p->precision = 8; - p->bps = 1; - p->msb = 1; - p->channels = 1; - /* no other rates supported by amd chip */ - p->sample_rate = 8000; - - return (0); -} - -int -amd7930_query_encoding(addr, fp) - void *addr; - struct audio_encoding *fp; -{ - switch (fp->index) { - case 0: - strlcpy(fp->name, AudioEmulaw, sizeof fp->name); - fp->encoding = AUDIO_ENCODING_ULAW; - fp->precision = 8; - fp->bps = 1; - fp->msb = 1; - fp->flags = 0; - break; - default: - return (EINVAL); - /*NOTREACHED*/ - } - return (0); -} - -int -amd7930_round_blocksize(addr, blk) - void *addr; - int blk; -{ - return (blk); -} - -int -amd7930_commit_settings(addr) - void *addr; -{ - register struct amd7930_softc *sc = addr; - register struct mapreg *map; - register volatile struct amd7930 *amd; - register int s, level; - - DPRINTF(("sa_commit.\n")); - - map = &sc->sc_map; - amd = sc->sc_au.au_amd; - - map->mr_gx = gx_coeff[sc->sc_rlevel]; - map->mr_stgr = gx_coeff[sc->sc_mlevel]; - - level = (sc->sc_plevel * (256 + NGER)) >> 8; - if (level >= 256) { - map->mr_ger = ger_coeff[level - 256]; - map->mr_gr = gx_coeff[255]; - } else { - map->mr_ger = ger_coeff[0]; - map->mr_gr = gx_coeff[level]; - } - - if (sc->sc_out_port == SUNAUDIO_SPEAKER) - map->mr_mmr2 |= AMD_MMR2_LS; - else - map->mr_mmr2 &= ~AMD_MMR2_LS; - - s = splaudio(); - - amd->cr = AMDR_MAP_MMR1; - amd->dr = map->mr_mmr1; - amd->cr = AMDR_MAP_GX; - WAMD16(amd, map->mr_gx); - amd->cr = AMDR_MAP_STG; - WAMD16(amd, map->mr_stgr); - amd->cr = AMDR_MAP_GR; - WAMD16(amd, map->mr_gr); - amd->cr = AMDR_MAP_GER; - WAMD16(amd, map->mr_ger); - amd->cr = AMDR_MAP_MMR2; - amd->dr = map->mr_mmr2; - - splx(s); - return (0); -} - -int -amd7930_start_output(addr, p, cc, intr, arg) - void *addr; - void *p; - int cc; - void (*intr)(void *); - void *arg; -{ - register struct amd7930_softc *sc = addr; - -#ifdef AUDIO_DEBUG - if (amd7930debug > 1) - printf("sa_start_output: cc=%d 0x%x (0x%x)\n", cc, intr, arg); -#endif - - if (!sc->sc_locked) { - register volatile struct amd7930 *amd; - - amd = sc->sc_au.au_amd; - amd->cr = AMDR_INIT; - amd->dr = AMD_INIT_PMS_ACTIVE; - sc->sc_locked = 1; - DPRINTF(("sa_start_output: started intrs.\n")); - } - sc->sc_pintr = intr; - sc->sc_parg = arg; - sc->sc_au.au_pdata = p; - sc->sc_au.au_pend = p + cc - 1; - return (0); -} - -/* ARGSUSED */ -int -amd7930_start_input(addr, p, cc, intr, arg) - void *addr; - void *p; - int cc; - void (*intr)(void *); - void *arg; -{ - register struct amd7930_softc *sc = addr; - -#ifdef AUDIO_DEBUG - if (amd7930debug > 1) - printf("sa_start_input: cc=%d 0x%x (0x%x)\n", cc, intr, arg); -#endif - - if (!sc->sc_locked) { - register volatile struct amd7930 *amd; - - amd = sc->sc_au.au_amd; - amd->cr = AMDR_INIT; - amd->dr = AMD_INIT_PMS_ACTIVE; - sc->sc_locked = 1; - DPRINTF(("sa_start_input: started intrs.\n")); - } - sc->sc_rintr = intr; - sc->sc_rarg = arg; - sc->sc_au.au_rdata = p; - sc->sc_au.au_rend = p + cc -1; - return (0); -} - -int -amd7930_halt_output(addr) - void *addr; -{ - register struct amd7930_softc *sc = addr; - register volatile struct amd7930 *amd; - - /* XXX only halt, if input is also halted ?? */ - amd = sc->sc_au.au_amd; - amd->cr = AMDR_INIT; - amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; - sc->sc_locked = 0; - - return (0); -} - -int -amd7930_halt_input(addr) - void *addr; -{ - register struct amd7930_softc *sc = addr; - register volatile struct amd7930 *amd; - - /* XXX only halt, if output is also halted ?? */ - amd = sc->sc_au.au_amd; - amd->cr = AMDR_INIT; - amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; - sc->sc_locked = 0; - - return (0); -} - -int -amd7930_getdev(addr, retp) - void *addr; - struct audio_device *retp; -{ - *retp = amd7930_device; - return (0); -} - -int -amd7930_set_port(addr, cp) - void *addr; - mixer_ctrl_t *cp; -{ - register struct amd7930_softc *sc = addr; - - DPRINTF(("amd7930_set_port: port=%d type=%d\n", cp->dev, cp->type)); - - if (cp->dev == SUNAUDIO_SOURCE || cp->dev == SUNAUDIO_OUTPUT) { - if (cp->type != AUDIO_MIXER_ENUM) - return (EINVAL); - } - else if (cp->type != AUDIO_MIXER_VALUE || - cp->un.value.num_channels != 1) - return (EINVAL); - - switch(cp->dev) { - case SUNAUDIO_MIC_PORT: - sc->sc_rlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; - break; - case SUNAUDIO_SPEAKER: - case SUNAUDIO_HEADPHONES: - sc->sc_plevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; - break; - case SUNAUDIO_MONITOR: - sc->sc_mlevel = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO]; - break; - case SUNAUDIO_SOURCE: - if (cp->un.ord != SUNAUDIO_MIC_PORT) - return (EINVAL); - break; - case SUNAUDIO_OUTPUT: - if (cp->un.ord != SUNAUDIO_SPEAKER && - cp->un.ord != SUNAUDIO_HEADPHONES) - return (EINVAL); - sc->sc_out_port = cp->un.ord; - break; - default: - return (EINVAL); - /* NOTREACHED */ - } - return (0); -} - -int -amd7930_get_port(addr, cp) - void *addr; - mixer_ctrl_t *cp; -{ - register struct amd7930_softc *sc = addr; - - DPRINTF(("amd7930_get_port: port=%d type=%d\n", cp->dev, cp->type)); - - if (cp->dev == SUNAUDIO_SOURCE || cp->dev == SUNAUDIO_OUTPUT) { - if (cp->type != AUDIO_MIXER_ENUM) - return (EINVAL); - } - else if (cp->type != AUDIO_MIXER_VALUE || - cp->un.value.num_channels != 1) - return (EINVAL); - - switch(cp->dev) { - case SUNAUDIO_MIC_PORT: - cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_rlevel; - break; - case SUNAUDIO_SPEAKER: - case SUNAUDIO_HEADPHONES: - cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_plevel; - break; - case SUNAUDIO_MONITOR: - cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_mlevel; - break; - case SUNAUDIO_SOURCE: - cp->un.ord = SUNAUDIO_MIC_PORT; - break; - case SUNAUDIO_OUTPUT: - cp->un.ord = sc->sc_out_port; - break; - default: - return (EINVAL); - /* NOTREACHED */ - } - return (0); -} - -int -amd7930_get_props(addr) - void *addr; -{ - return (AUDIO_PROP_FULLDUPLEX); -} - -int -amd7930_query_devinfo(addr, dip) - void *addr; - register mixer_devinfo_t *dip; -{ - switch(dip->index) { - case SUNAUDIO_MIC_PORT: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = SUNAUDIO_INPUT_CLASS; - dip->prev = dip->next = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioNmicrophone, sizeof dip->label.name); - dip->un.v.num_channels = 1; - strlcpy(dip->un.v.units.name, AudioNvolume, - sizeof dip->un.v.units.name); - break; - case SUNAUDIO_SPEAKER: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = SUNAUDIO_OUTPUT_CLASS; - dip->prev = dip->next = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioNspeaker, sizeof dip->label.name); - dip->un.v.num_channels = 1; - strlcpy(dip->un.v.units.name, AudioNvolume, - sizeof dip->un.v.units.name); - break; - case SUNAUDIO_HEADPHONES: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = SUNAUDIO_OUTPUT_CLASS; - dip->prev = dip->next = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioNheadphone, sizeof dip->label.name); - dip->un.v.num_channels = 1; - strlcpy(dip->un.v.units.name, AudioNvolume, - sizeof dip->label.name); - break; - case SUNAUDIO_MONITOR: - dip->type = AUDIO_MIXER_VALUE; - dip->mixer_class = SUNAUDIO_OUTPUT_CLASS; - dip->next = dip->prev = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioNmonitor, sizeof dip->label.name); - dip->un.v.num_channels = 1; - strlcpy(dip->un.v.units.name, AudioNvolume, - sizeof dip->label.name); - break; - case SUNAUDIO_SOURCE: - dip->type = AUDIO_MIXER_ENUM; - dip->mixer_class = SUNAUDIO_RECORD_CLASS; - dip->prev = dip->next = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name); - dip->un.e.num_mem = 1; - strlcpy(dip->un.e.member[0].label.name, AudioNmicrophone, - sizeof dip->un.e.member[0].label.name); - dip->un.e.member[0].ord = SUNAUDIO_MIC_PORT; - break; - case SUNAUDIO_OUTPUT: - dip->type = AUDIO_MIXER_ENUM; - dip->mixer_class = SUNAUDIO_MONITOR_CLASS; - dip->prev = dip->next = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioNoutput, sizeof dip->label.name); - dip->un.e.num_mem = 2; - strlcpy(dip->un.e.member[0].label.name, AudioNspeaker, - sizeof dip->un.e.member[0].label.name); - dip->un.e.member[0].ord = SUNAUDIO_SPEAKER; - strlcpy(dip->un.e.member[1].label.name, AudioNheadphone, - sizeof dip->un.e.member[0].label.name); - dip->un.e.member[1].ord = SUNAUDIO_HEADPHONES; - break; - case SUNAUDIO_INPUT_CLASS: - dip->type = AUDIO_MIXER_CLASS; - dip->mixer_class = SUNAUDIO_INPUT_CLASS; - dip->next = dip->prev = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioCinputs, sizeof dip->label.name); - break; - case SUNAUDIO_OUTPUT_CLASS: - dip->type = AUDIO_MIXER_CLASS; - dip->mixer_class = SUNAUDIO_OUTPUT_CLASS; - dip->next = dip->prev = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioCoutputs, sizeof dip->label.name); - break; - case SUNAUDIO_RECORD_CLASS: - dip->type = AUDIO_MIXER_CLASS; - dip->mixer_class = SUNAUDIO_RECORD_CLASS; - dip->next = dip->prev = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioCrecord, sizeof dip->label.name); - break; - case SUNAUDIO_MONITOR_CLASS: - dip->type = AUDIO_MIXER_CLASS; - dip->mixer_class = SUNAUDIO_MONITOR_CLASS; - dip->next = dip->prev = AUDIO_MIXER_LAST; - strlcpy(dip->label.name, AudioCmonitor, sizeof dip->label.name); - break; - default: - return (ENXIO); - /*NOTREACHED*/ - } - - DPRINTF(("AUDIO_MIXER_DEVINFO: name=%s\n", dip->label.name)); - - return (0); -} - -int -amd7930hwintr(au0) - void *au0; -{ - register struct auio *au = au0; - register volatile struct amd7930 *amd = au->au_amd; - register u_char *d, *e; - register int k; - - k = amd->ir; /* clear interrupt */ - - /* receive incoming data */ - d = au->au_rdata; - e = au->au_rend; - if (d && d <= e) { - *d = amd->bbrb; - au->au_rdata++; - if (d == e) { -#ifdef AUDIO_DEBUG - if (amd7930debug > 1) - printf("amd7930hwintr: swintr(r) requested"); -#endif - softintr_schedule(au->au_swih); - } - } - - /* send outgoing data */ - d = au->au_pdata; - e = au->au_pend; - if (d && d <= e) { - amd->bbtb = *d; - au->au_pdata++; - if (d == e) { -#ifdef AUDIO_DEBUG - if (amd7930debug > 1) - printf("amd7930hwintr: swintr(p) requested"); -#endif - softintr_schedule(au->au_swih); - } - } - - return (-1); -} - -void -amd7930swintr(sc0) - void *sc0; -{ - struct amd7930_softc *sc = sc0; - struct auio *au; - int s; - -#ifdef AUDIO_DEBUG - if (amd7930debug > 1) - printf("audiointr: sc=0x%x\n",sc); -#endif - - au = &sc->sc_au; - s = splaudio(); - if (au->au_rdata > au->au_rend && sc->sc_rintr != NULL) { - splx(s); - (*sc->sc_rintr)(sc->sc_rarg); - s = splaudio(); - } - if (au->au_pdata > au->au_pend && sc->sc_pintr != NULL) { - splx(s); - (*sc->sc_pintr)(sc->sc_parg); - } else - splx(s); -} - -#ifndef AUDIO_C_HANDLER -int -amd7930_shareintr(void *arg) -{ - struct amd7930_softc *sc = arg; - - /* - * We are invoked at splhigh(), so there is no need to prevent the chip - * from interrupting while we are messing with the handlers. We - * however need to properly untie the event counter from the chain, - * since it will be reused immediately by intr_establish()... - */ - - intr_fastuntrap(sc->sc_hwih.ih_vec); - evcount_detach(&sc->sc_hwih.ih_count); - - sc->sc_hwih.ih_fun = amd7930hwintr; - sc->sc_hwih.ih_arg = &sc->sc_au; - intr_establish(sc->sc_hwih.ih_vec, &sc->sc_hwih, IPL_AUHARD, - sc->sc_dev.dv_xname); - - return (0); -} -#endif diff --git a/sys/arch/sparc/dev/amd7930var.h b/sys/arch/sparc/dev/amd7930var.h deleted file mode 100644 index 91ce71c2122..00000000000 --- a/sys/arch/sparc/dev/amd7930var.h +++ /dev/null @@ -1,86 +0,0 @@ -/* $OpenBSD: amd7930var.h,v 1.8 2009/04/10 20:53:51 miod Exp $ */ -/* $NetBSD: amd7930var.h,v 1.3 1996/02/01 22:32:25 mycroft Exp $ */ - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Lawrence Berkeley Laboratory. - * - * 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. Neither the name of the University nor the names of its contributors - * may 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. - * - * @(#)bsd_audiovar.h 8.1 (Berkeley) 6/11/93 - */ - -#ifndef _LOCORE - -/* XXX I think these defines should go into some other header file */ -#define SUNAUDIO_MIC_PORT 0 -#define SUNAUDIO_SPEAKER 1 -#define SUNAUDIO_HEADPHONES 2 -#define SUNAUDIO_MONITOR 3 -#define SUNAUDIO_SOURCE 4 -#define SUNAUDIO_OUTPUT 5 -#define SUNAUDIO_INPUT_CLASS 6 -#define SUNAUDIO_OUTPUT_CLASS 7 -#define SUNAUDIO_RECORD_CLASS 8 -#define SUNAUDIO_MONITOR_CLASS 9 - -struct auio { - volatile struct amd7930 *au_amd;/* chip registers */ - - u_char *au_rdata; /* record data */ - u_char *au_rend; /* end of record data */ - u_char *au_pdata; /* play data */ - u_char *au_pend; /* end of play data */ - - struct intrhand au_ih; - void *au_swih; /* software interrupt cookie */ -}; - -/* - * Chip interface - */ -struct mapreg { - u_short mr_x[8]; - u_short mr_r[8]; - u_short mr_gx; - u_short mr_gr; - u_short mr_ger; - u_short mr_stgr; - u_short mr_ftgr; - u_short mr_atgr; - u_char mr_mmr1; - u_char mr_mmr2; -}; - -#endif /* !_LOCORE */ diff --git a/sys/arch/sparc/dev/audioamd.c b/sys/arch/sparc/dev/audioamd.c new file mode 100644 index 00000000000..90915cc19f9 --- /dev/null +++ b/sys/arch/sparc/dev/audioamd.c @@ -0,0 +1,450 @@ +/* $OpenBSD: audioamd.c,v 1.1 2011/09/03 20:04:02 miod Exp $ */ +/* $NetBSD: audioamd.c,v 1.26 2011/06/04 01:27:57 tsutsui Exp $ */ + +/* + * Copyright (c) 1995 Rolf Grossmann + * 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 Rolf Grossmann. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/errno.h> +#include <sys/ioctl.h> +#include <sys/device.h> +#include <sys/proc.h> + +#include <machine/autoconf.h> +#include <machine/cpu.h> + +#include <sys/audioio.h> +#include <dev/audio_if.h> + +#include <dev/ic/am7930reg.h> +#include <dev/ic/am7930var.h> +#include <sparc/dev/audioamdvar.h> + +#define AUDIO_ROM_NAME "audio" + +#ifdef AUDIO_DEBUG +#define DPRINTF(x) if (am7930debug) printf x +#define DPRINTFN(n,x) if (am7930debug>(n)) printf x +#else +#define DPRINTF(x) +#define DPRINTFN(n,x) +#endif /* AUDIO_DEBUG */ + +/* + * Define AUDIO_C_HANDLER to force using non-fast trap routines. + */ +/* #define AUDIO_C_HANDLER */ + +struct audioamd_softc { + struct am7930_softc sc_am7930; /* glue to MI code */ + + void (*sc_rintr)(void*); /* input completion intr handler */ + void *sc_rarg; /* arg for sc_rintr() */ + void (*sc_pintr)(void*); /* output completion intr handler */ + void *sc_parg; /* arg for sc_pintr() */ + + /* sc_au is special in that the hardware interrupt handler uses it */ + struct auio sc_au; /* recv and xmit buffers, etc */ +#define sc_hwih sc_au.au_ih /* hardware interrupt vector */ +#define sc_swih sc_au.au_swih /* software interrupt cookie */ +}; + +void audioamd_attach(struct device *, struct device *, void *); +int audioamd_match(struct device *, void *, void *); + +struct cfdriver audioamd_cd = { + NULL, "audioamd", DV_DULL +}; + +const struct cfattach audioamd_ca = { + sizeof(struct audioamd_softc), audioamd_match, audioamd_attach +}; + +/* + * Define our interface into the am7930 MI driver. + */ + +uint8_t audioamd_codec_iread(struct am7930_softc *, int); +uint16_t audioamd_codec_iread16(struct am7930_softc *, int); +uint8_t audioamd_codec_dread(struct audioamd_softc *, int); +void audioamd_codec_iwrite(struct am7930_softc *, int, uint8_t); +void audioamd_codec_iwrite16(struct am7930_softc *, int, uint16_t); +void audioamd_codec_dwrite(struct audioamd_softc *, int, uint8_t); +void audioamd_onopen(struct am7930_softc *); +void audioamd_onclose(struct am7930_softc *); + +struct am7930_glue audioamd_glue = { + audioamd_codec_iread, + audioamd_codec_iwrite, + audioamd_codec_iread16, + audioamd_codec_iwrite16, + audioamd_onopen, + audioamd_onclose +}; + +/* + * Define our interface to the higher level audio driver. + */ +int audioamd_start_output(void *, void *, int, void (*)(void *), void *); +int audioamd_start_input(void *, void *, int, void (*)(void *), void *); +int audioamd_getdev(void *, struct audio_device *); + +struct audio_hw_if sa_hw_if = { + am7930_open, + am7930_close, + NULL, + am7930_query_encoding, + am7930_set_params, + am7930_round_blocksize, + am7930_commit_settings, + NULL, + NULL, + audioamd_start_output, + audioamd_start_input, + am7930_halt_output, + am7930_halt_input, + NULL, + audioamd_getdev, + NULL, + am7930_set_port, + am7930_get_port, + am7930_query_devinfo, + NULL, + NULL, + NULL, + NULL, + am7930_get_props, + NULL, + NULL, + NULL +}; + +struct audio_device audioamd_device = { + "am7930", + "x", + "audioamd" +}; + +/* forward declarations */ +int amd7930_shareintr(void *); +#ifndef AUDIO_C_HANDLER +struct auio *auiop; +#endif /* AUDIO_C_HANDLER */ +int am7930hwintr(void *); +void am7930swintr(void *); + +int +audioamd_match(struct device *parent, void *vcf, void *aux) +{ + struct confargs *ca = aux; + struct romaux *ra = &ca->ca_ra; + + if (CPU_ISSUN4) + return 0; + return strcmp(AUDIO_ROM_NAME, ra->ra_name) == 0; +} + +void +audioamd_attach(struct device *parent, struct device *self, void *aux) +{ + struct audioamd_softc *sc = (struct audioamd_softc *)self; + struct confargs *ca = aux; + struct romaux *ra = &ca->ca_ra; + int pri; + + if (ra->ra_nintr != 1) { + printf(": expected 1 interrupt, got %d\n", ra->ra_nintr); + return; + } + pri = ra->ra_intr[0].int_pri; + printf(" pri %d, softpri %d\n", pri, IPL_AUSOFT); + sc->sc_au.au_sc = sc; + sc->sc_au.au_amd = (volatile uint8_t *)(ra->ra_vaddr ? + ra->ra_vaddr : mapiodev(ra->ra_reg, 0, AM7930_DREG_SIZE)); + + /* + * Set up glue for MI code early; we use some of it here. + */ + sc->sc_am7930.sc_glue = &audioamd_glue; + am7930_init(&sc->sc_am7930, AUDIOAMD_POLL_MODE); + + /* + * Register interrupt handlers. We'll prefer a fast trap (unless + * AUDIO_C_HANDLER is defined), with a sharing callback so that we + * can revert into a regular trap vector if necessary. + */ +#ifndef AUDIO_C_HANDLER + sc->sc_hwih.ih_vec = pri; + if (intr_fasttrap(pri, amd7930_trap, amd7930_shareintr, sc) == 0) { + auiop = &sc->sc_au; + evcount_attach(&sc->sc_hwih.ih_count, self->dv_xname, + &sc->sc_hwih.ih_vec); + } else { +#ifdef AUDIO_DEBUG + printf("%s: unable to register fast trap handler\n", + self->dv_xname); +#endif +#else + { +#endif + sc->sc_hwih.ih_fun = am7930hwintr; + sc->sc_hwih.ih_arg = &sc->sc_au; + intr_establish(pri, &sc->sc_hwih, IPL_AUHARD, self->dv_xname); + } + + sc->sc_swih = softintr_establish(IPL_AUSOFT, am7930swintr, sc); + + audio_attach_mi(&sa_hw_if, sc, self); +} + +void +audioamd_onopen(struct am7930_softc *sc) +{ + struct audioamd_softc *ausc = (struct audioamd_softc *)sc; + + /* reset pdma state */ + ausc->sc_rintr = NULL; + ausc->sc_rarg = 0; + ausc->sc_pintr = NULL; + ausc->sc_parg = 0; + + ausc->sc_au.au_rdata = NULL; + ausc->sc_au.au_pdata = NULL; +} + + +void +audioamd_onclose(struct am7930_softc *sc) +{ + /* On sparc, just do the chipset-level halt. */ + am7930_halt_input(sc); + am7930_halt_output(sc); +} + +int +audioamd_start_output(void *addr, void *p, int cc, + void (*intr)(void *), void *arg) +{ + struct audioamd_softc *sc = addr; + + DPRINTFN(1, ("sa_start_output: cc=%d %p (%p)\n", cc, intr, arg)); + + if (!sc->sc_am7930.sc_locked) { + audioamd_codec_iwrite(&sc->sc_am7930, + AM7930_IREG_INIT, AM7930_INIT_PMS_ACTIVE); + sc->sc_am7930.sc_locked = 1; + DPRINTF(("sa_start_output: started intrs.\n")); + } + sc->sc_pintr = intr; + sc->sc_parg = arg; + sc->sc_au.au_pdata = p; + sc->sc_au.au_pend = (char *)p + cc - 1; + return 0; +} + +int +audioamd_start_input(void *addr, void *p, int cc, + void (*intr)(void *), void *arg) +{ + struct audioamd_softc *sc = addr; + + DPRINTFN(1, ("sa_start_input: cc=%d %p (%p)\n", cc, intr, arg)); + + if (!sc->sc_am7930.sc_locked) { + audioamd_codec_iwrite(&sc->sc_am7930, + AM7930_IREG_INIT, AM7930_INIT_PMS_ACTIVE); + sc->sc_am7930.sc_locked = 1; + DPRINTF(("sa_start_input: started intrs.\n")); + } + sc->sc_rintr = intr; + sc->sc_rarg = arg; + sc->sc_au.au_rdata = p; + sc->sc_au.au_rend = (char *)p + cc -1; + return 0; +} + +/* + * Pseudo-DMA support: either C or locore assember. + */ + +int +am7930hwintr(void *v) +{ + struct auio *au = v; + struct audioamd_softc *sc = au->au_sc; + uint8_t *d, *e; + int k; + + /* clear interrupt */ + k = audioamd_codec_dread(sc, AM7930_DREG_IR); + if ((k & (AM7930_IR_DTTHRSH | AM7930_IR_DRTHRSH | AM7930_IR_DSRI | + AM7930_IR_DERI | AM7930_IR_BBUFF)) == 0) + return 0; + + /* receive incoming data */ + d = au->au_rdata; + e = au->au_rend; + if (d != NULL && d <= e) { + *d = audioamd_codec_dread(sc, AM7930_DREG_BBRB); + au->au_rdata++; + if (d == e) { + DPRINTFN(1, ("am7930hwintr: swintr(r) requested")); + softintr_schedule(au->au_swih); + } + } + + /* send outgoing data */ + d = au->au_pdata; + e = au->au_pend; + if (d != NULL && d <= e) { + audioamd_codec_dwrite(sc, AM7930_DREG_BBTB, *d); + au->au_pdata++; + if (d == e) { + DPRINTFN(1, ("am7930hwintr: swintr(p) requested")); + softintr_schedule(au->au_swih); + } + } + + return 1; +} + +void +am7930swintr(void *v) +{ + struct audioamd_softc *sc = v; + struct auio *au; + int s, dor, dow; + + DPRINTFN(1, ("audiointr: sc=%p\n", sc);); + + au = &sc->sc_au; + dor = dow = 0; + s = splaudio(); + if (au->au_rdata > au->au_rend && sc->sc_rintr != NULL) + dor = 1; + if (au->au_pdata > au->au_pend && sc->sc_pintr != NULL) + dow = 1; + splx(s); + + if (dor != 0) + (*sc->sc_rintr)(sc->sc_rarg); + if (dow != 0) + (*sc->sc_pintr)(sc->sc_parg); +} + +#ifndef AUDIO_C_HANDLER +int +amd7930_shareintr(void *arg) +{ + struct audioamd_softc *sc = arg; + + /* + * We are invoked at splhigh(), so there is no need to prevent the chip + * from interrupting while we are messing with the handlers. We + * however need to properly untie the event counter from the chain, + * since it will be reused immediately by intr_establish()... + */ + + intr_fastuntrap(sc->sc_hwih.ih_vec); + evcount_detach(&sc->sc_hwih.ih_count); + + sc->sc_hwih.ih_fun = am7930hwintr; + sc->sc_hwih.ih_arg = &sc->sc_au; + intr_establish(sc->sc_hwih.ih_vec, &sc->sc_hwih, IPL_AUHARD, + sc->sc_am7930.sc_dev.dv_xname); + + return 0; +} +#endif + +/* indirect write */ +void +audioamd_codec_iwrite(struct am7930_softc *sc, int reg, uint8_t val) +{ + struct audioamd_softc *ausc = (struct audioamd_softc *)sc; + + audioamd_codec_dwrite(ausc, AM7930_DREG_CR, reg); + audioamd_codec_dwrite(ausc, AM7930_DREG_DR, val); +} + +void +audioamd_codec_iwrite16(struct am7930_softc *sc, int reg, uint16_t val) +{ + struct audioamd_softc *ausc = (struct audioamd_softc *)sc; + + audioamd_codec_dwrite(ausc, AM7930_DREG_CR, reg); + audioamd_codec_dwrite(ausc, AM7930_DREG_DR, val); + audioamd_codec_dwrite(ausc, AM7930_DREG_DR, val >> 8); +} + + +/* indirect read */ +uint8_t +audioamd_codec_iread(struct am7930_softc *sc, int reg) +{ + struct audioamd_softc *ausc = (struct audioamd_softc *)sc; + + audioamd_codec_dwrite(ausc, AM7930_DREG_CR, reg); + return audioamd_codec_dread(ausc, AM7930_DREG_DR); +} + +uint16_t +audioamd_codec_iread16(struct am7930_softc *sc, int reg) +{ + struct audioamd_softc *ausc = (struct audioamd_softc *)sc; + uint lo, hi; + + audioamd_codec_dwrite(ausc, AM7930_DREG_CR, reg); + lo = audioamd_codec_dread(ausc, AM7930_DREG_DR); + hi = audioamd_codec_dread(ausc, AM7930_DREG_DR); + return (hi << 8) | lo; +} + +/* direct read */ +uint8_t +audioamd_codec_dread(struct audioamd_softc *sc, int reg) +{ + return sc->sc_au.au_amd[reg]; +} + +/* direct write */ +void +audioamd_codec_dwrite(struct audioamd_softc *sc, int reg, uint8_t val) +{ + sc->sc_au.au_amd[reg] = val; +} + +int +audioamd_getdev(void *addr, struct audio_device *retp) +{ + *retp = audioamd_device; + return 0; +} diff --git a/sys/arch/sparc/dev/audioamdvar.h b/sys/arch/sparc/dev/audioamdvar.h new file mode 100644 index 00000000000..3e27e3e7f08 --- /dev/null +++ b/sys/arch/sparc/dev/audioamdvar.h @@ -0,0 +1,48 @@ +/* $OpenBSD: audioamdvar.h,v 1.1 2011/09/03 20:04:02 miod Exp $ */ +/* $NetBSD: audioamdvar.h,v 1.4 2005/12/11 12:19:05 christos Exp $ */ + +/* + * Copyright (c) 1995 Rolf Grossmann + * 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 Rolf Grossmann. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * pdma state + */ +struct auio { + volatile uint8_t *au_amd; /* chip registers */ + + uint8_t *au_rdata; /* record data */ + uint8_t *au_rend; /* end of record data */ + uint8_t *au_pdata; /* play data */ + uint8_t *au_pend; /* end of play data */ + + void *au_sc; + struct intrhand au_ih; + void *au_swih; /* software interrupt cookie */ +}; |