Index: sys/conf/files =================================================================== RCS file: /home/ncvs/src/sys/conf/files,v retrieving revision 1.790 diff -u -u -r1.790 files --- sys/conf/files 11 May 2003 06:37:52 -0000 1.790 +++ sys/conf/files 20 May 2003 14:22:01 -0000 @@ -691,6 +691,7 @@ dev/sound/midi/sequencer.c optional seq midi dev/sound/midi/timer.c optional seq midi dev/sound/pci/als4000.c optional pcm pci +dev/sound/pci/au88x0.c optional pcm pci dev/sound/pci/cmi.c optional pcm pci dev/sound/pci/cs4281.c optional pcm pci dev/sound/pci/csa.c optional csa pci Index: sys/dev/sound/pci/au88x0.c =================================================================== RCS file: sys/dev/sound/pci/au88x0.c diff -N sys/dev/sound/pci/au88x0.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/dev/sound/pci/au88x0.c 23 May 2003 03:03:52 -0000 @@ -0,0 +1,457 @@ +/*- + * Copyright (c) 2003 Dag-Erling Coïdan Smørgrav + * 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 + * in this position and unchanged. + * 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. 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. + * + * $FreeBSD$ + */ + +#include +#include +#include + +#include + +#include +#include + +struct au88x0_info { + /* the device we're associated with */ + device_t aui_dev; + uint32_t aui_model; + + /* parameters */ + bus_size_t aui_bufsize; + + /* bus_space tag and handle */ + bus_space_tag_t aui_spct; + bus_space_handle_t aui_spch; + + /* register space */ + int aui_regtype; + int aui_regid; + struct resource *aui_reg; + + /* irq */ + int aui_irqtype; + int aui_irqid; + struct resource *aui_irq; + void *aui_irqh; + + /* dma */ + bus_dma_tag_t aui_dmat; + + /* codec */ + struct ac97_info *aui_ac97i; +}; + +/* + * Read from the au88x0 register space + */ +static uint32_t +au88x0_read(struct au88x0_info *aui, int reg, int size) +{ + uint32_t data; + + switch (size) { + case 1: + data = bus_space_read_1(aui->aui_spct, aui->aui_spch, reg); + break; + case 2: + data = bus_space_read_2(aui->aui_spct, aui->aui_spch, reg); + break; + case 4: + data = bus_space_read_4(aui->aui_spct, aui->aui_spch, reg); + break; + default: + panic("unsupported read size %d", size); + } + return (data); +} + +/* + * Write to the au88x0 register space + */ +static void +au88x0_write(struct au88x0_info *aui, int reg, uint32_t data, int size) +{ + + switch (size) { + case 1: + bus_space_write_1(aui->aui_spct, aui->aui_spch, reg, data); + break; + case 2: + bus_space_write_2(aui->aui_spct, aui->aui_spch, reg, data); + break; + case 4: + bus_space_write_4(aui->aui_spct, aui->aui_spch, reg, data); + break; + default: + panic("unsupported write size %d", size); + } +} + +/* + * Reset and initialize the codec + */ +static void +au88x0_codec_init(struct au88x0_info *aui) +{ + int i; + + /* wave that chicken */ + au88x0_write(aui, AU88X0_CODEC_CONTROL, 0x8068, 4); + DELAY(1000); + au88x0_write(aui, AU88X0_CODEC_CONTROL, 0x00e8, 4); + DELAY(1000); + for (i = 0; i < 32; ++i) { + au88x0_write(aui, AU88X0_CODEC_CHANNEL + i * 4, 0, 4); + DELAY(1000); + } + au88x0_write(aui, AU88X0_CODEC_CONTROL, 0x00e8, 4); + DELAY(1000); + + /* disable all channels for now */ + au88x0_write(aui, AU88X0_CODEC_ENABLE, 0, 4); +} + +/* + * Wait for the codec to get ready to accept a register write + * Should be called at spltty + */ +static int +au88x0_codec_wait(struct au88x0_info *aui) +{ + uint32_t data; + int i; + + for (i = 0; i < AU88X0_CODEC_POLL_COUNT; ++i) { + data = au88x0_read(aui, AU88X0_CODEC_CONTROL, 4); + if (data & AU88X0_CDCTL_WROK) + return (0); + DELAY(AU88X0_CODEC_POLL_DELAY); + } + device_printf(aui->aui_dev, "timeout while waiting for codec\n"); + return (-1); +} + +/* + * Read from the ac97 codec + */ +static int +au88x0_codec_read(kobj_t obj, void *arg, int reg) +{ + struct au88x0_info *aui = arg; + uint32_t data; + int sl; + + sl = spltty(); + au88x0_codec_wait(aui); + au88x0_write(aui, AU88X0_CODEC_IO, AU88X0_CDIO_READ(reg), 4); + DELAY(1000); + data = au88x0_read(aui, AU88X0_CODEC_IO, 4); + splx(sl); + data &= AU88X0_CDIO_DATA_MASK; + data >>= AU88X0_CDIO_DATA_SHIFT; + return (data); +} + +/* + * Write to the ac97 codec + */ +static int +au88x0_codec_write(kobj_t obj, void *arg, int reg, uint32_t data) +{ + struct au88x0_info *aui = arg; + int sl; + + sl = spltty(); + au88x0_codec_wait(aui); + au88x0_write(aui, AU88X0_CODEC_IO, AU88X0_CDIO_WRITE(reg, data), 4); + splx(sl); + return 0; +} + +/* + * ac97 driver glue + */ +static kobj_method_t au88x0_ac97_methods[] = { + KOBJMETHOD(ac97_read, au88x0_codec_read), + KOBJMETHOD(ac97_write, au88x0_codec_write), + { 0, 0 } +}; +AC97_DECLARE(au88x0_ac97); + +/* + * Interrupt handler + */ +static void +au88x0_intr(void *arg) +{ + struct au88x0_info *aui = arg; + int pending, source; + + pending = au88x0_read(aui, AU88X0_IRQ_PENDING, 4); + if ((pending & AU88X0_IRQ_PENDING_BIT) == 0) + return; + source = au88x0_read(aui, AU88X0_IRQ_SOURCE, 4); + if (source & AU88X0_IRQ_FATAL) + device_printf(aui->aui_dev, + "fatal error interrupt received\n"); + if (source & AU88X0_IRQ_PARITY) + device_printf(aui->aui_dev, + "parity error interrupt received\n"); + /* XXX handle the others... */ + + /* acknowledge the interrupts we just handled */ + au88x0_write(aui, AU88X0_IRQ_SOURCE, source, 4); + au88x0_read(aui, AU88X0_IRQ_SOURCE, 4); +} + +/* + * Hardware initialization + */ +static void +au88x0_init(struct au88x0_info *aui) +{ + + /* reset the chip */ + au88x0_write(aui, AU88X0_CONTROL, 0xffffffff, 4); + DELAY(10000); + + /* clear all interrupts */ + au88x0_write(aui, AU88X0_IRQ_SOURCE, 0xffffffff, 4); + au88x0_read(aui, AU88X0_IRQ_SOURCE, 4); + au88x0_read(aui, AU88X0_IRQ_STATUS, 4); + + /* initialize the codec */ + au88x0_codec_init(aui); +} + +/* + * Probe + */ +static int +au88x0_pci_probe(device_t dev) +{ + + switch (pci_get_devid(dev)) { + case AUREAL_VORTEX_2: + device_set_desc(dev, "Aureal Vortex 2"); + return (0); + case AUREAL_VORTEX_ADVANTAGE: + device_set_desc(dev, "Aureal Vortex Advantage"); + return (0); + default: + return (ENXIO); + } + return (0); +} + +/* + * Construct and set status string + */ +static void +au88x0_set_status(device_t dev) +{ + char status[SND_STATUSLEN]; + struct au88x0_info *aui; + + aui = pcm_getdevinfo(dev); + snprintf(status, sizeof status, "at %s 0x%lx irq %ld", + (aui->aui_regtype == SYS_RES_IOPORT)? "io" : "memory", + rman_get_start(aui->aui_reg), rman_get_start(aui->aui_irq)); + pcm_setstatus(dev, status); +} + +/* + * Attach + */ +static int +au88x0_pci_attach(device_t dev) +{ + struct au88x0_info *aui = NULL; + uint32_t config; + int error; + + if ((aui = malloc(sizeof *aui, M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) { + device_printf(dev, "failed to allocate softc\n"); + return (ENXIO); + } + aui->aui_dev = dev; + + /* */ + aui->aui_model = pci_get_devid(dev); + switch (aui->aui_model) { + case AUREAL_VORTEX_1: + aui->aui_bufsize = 0x4000; + break; + case AUREAL_VORTEX_2: + case AUREAL_VORTEX_ADVANTAGE: + aui->aui_bufsize = 0x2000; /* ??? */ + break; + default: + panic("%s() called for non-au88x0 device", __func__); + } + + /* enable pio, mmio, bus-mastering dma */ + config = pci_read_config(dev, PCIR_COMMAND, 2); + config |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); + pci_write_config(dev, PCIR_COMMAND, config, 2); + + /* register mapping */ + config = pci_read_config(dev, PCIR_COMMAND, 2); + if (config & PCIM_CMD_MEMEN) { + /* try memory-mapped I/O */ + aui->aui_regid = PCIR_MAPS; + aui->aui_regtype = SYS_RES_MEMORY; + aui->aui_reg = bus_alloc_resource(dev, aui->aui_regtype, + &aui->aui_regid, 0, ~0, 1, RF_ACTIVE); + } + if (aui->aui_reg == NULL && (config & PCIM_CMD_PORTEN)) { + /* fall back on port I/O */ + aui->aui_regid = PCIR_MAPS; + aui->aui_regtype = SYS_RES_IOPORT; + aui->aui_reg = bus_alloc_resource(dev, aui->aui_regtype, + &aui->aui_regid, 0, ~0, 1, RF_ACTIVE); + } + if (aui->aui_reg == NULL) { + /* both mmio and pio failed... */ + device_printf(dev, "failed to map registers\n"); + goto failed; + } + aui->aui_spct = rman_get_bustag(aui->aui_reg); + aui->aui_spch = rman_get_bushandle(aui->aui_reg); + + /* IRQ mapping */ + aui->aui_irqid = 0; + aui->aui_irqtype = SYS_RES_IRQ; + aui->aui_irq = bus_alloc_resource(dev, aui->aui_irqtype, + &aui->aui_irqid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); + if (aui->aui_irq == 0) { + device_printf(dev, "failed to map IRQ\n"); + goto failed; + } + + /* install interrupt handler */ + error = snd_setup_intr(dev, aui->aui_irq, 0, au88x0_intr, + aui, &aui->aui_irqh); + if (error != 0) { + device_printf(dev, "failed to install interrupt handler\n"); + goto failed; + } + + /* DMA mapping */ + error = bus_dma_tag_create(NULL, + 2, 0, /* 16-bit alignment, no boundary */ + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, /* no restrictions */ + NULL, NULL, /* no filter */ + aui->aui_bufsize, 1, aui->aui_bufsize - 1, + 0, &aui->aui_dmat); + if (error != 0) { + device_printf(dev, "failed to create DMA tag\n"); + goto failed; + } + + /* initialize the hardware */ + au88x0_init(aui); + + /* initialize the ac97 codec and mixer */ + if ((aui->aui_ac97i = AC97_CREATE(dev, aui, au88x0_ac97)) == NULL) { + device_printf(dev, "failed to initialize ac97 codec\n"); + goto failed; + } + if (mixer_init(dev, ac97_getmixerclass(), aui->aui_ac97i) != 0) { + device_printf(dev, "failed to initialize ac97 mixer\n"); + goto failed; + } + + /* register with the pcm driver */ + if (pcm_register(dev, aui, 0, 0)) + goto failed; + au88x0_set_status(dev); + + return (0); +failed: + if (aui->aui_ac97i != NULL) + ac97_destroy(aui->aui_ac97i); + if (aui->aui_dmat) + bus_dma_tag_destroy(aui->aui_dmat); + if (aui->aui_irqh != NULL) + bus_teardown_intr(dev, aui->aui_irq, aui->aui_irqh); + if (aui->aui_irq) + bus_release_resource(dev, aui->aui_irqtype, + aui->aui_irqid, aui->aui_irq); + if (aui->aui_reg) + bus_release_resource(dev, aui->aui_regtype, + aui->aui_regid, aui->aui_reg); + free(aui, M_DEVBUF); + return (ENXIO); +} + +/* + * Detach + */ +static int +au88x0_pci_detach(device_t dev) +{ + struct au88x0_info *aui; + int error; + + aui = pcm_getdevinfo(dev); + if ((error = pcm_unregister(dev)) != 0) + return (error); + + /* release resources in reverse order */ + bus_dma_tag_destroy(aui->aui_dmat); + bus_teardown_intr(dev, aui->aui_irq, aui->aui_irqh); + bus_release_resource(dev, aui->aui_irqtype, + aui->aui_irqid, aui->aui_irq); + bus_release_resource(dev, aui->aui_regtype, + aui->aui_regid, aui->aui_reg); + free(aui, M_DEVBUF); + + return (0); +} + +/* + * Driver glue + */ +static device_method_t au88x0_methods[] = { + DEVMETHOD(device_probe, au88x0_pci_probe), + DEVMETHOD(device_attach, au88x0_pci_attach), + DEVMETHOD(device_detach, au88x0_pci_detach), + { 0, 0 } +}; + +static driver_t au88x0_driver = { + "pcm", + au88x0_methods, + PCM_SOFTC_SIZE, +}; + +DRIVER_MODULE(snd_au88x0, pci, au88x0_driver, pcm_devclass, 0, 0); +MODULE_DEPEND(snd_au88x0, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); +MODULE_VERSION(snd_au88x0, 1); Index: sys/dev/sound/pci/au88x0.h =================================================================== RCS file: sys/dev/sound/pci/au88x0.h diff -N sys/dev/sound/pci/au88x0.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/dev/sound/pci/au88x0.h 22 May 2003 21:27:01 -0000 @@ -0,0 +1,102 @@ +/*- + * Copyright (c) 2003 Dag-Erling Coïdan Smørgrav + * 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 + * in this position and unchanged. + * 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. 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. + * + * $FreeBSD$ + */ + +#ifndef _AU88X0_H_INCLUDED +#define _AU88X0_H_INCLUDED + +/* + * PCI IDs of supported cards + */ +#define AUREAL_VORTEX_1 0x000112eb /* 8820 (not supported) */ +#define AUREAL_VORTEX_2 0x000212eb /* 8830 */ +#define AUREAL_VORTEX_ADVANTAGE 0x000312eb /* 8810 */ + +/* + * CONTROL REGISTERS + */ +#define AU88X0_CONTROL 0x2a00c +#define AU88X0_CTL_MIDI_ENABLE 0x0001 +#define AU88X0_CTL_GAME_ENABLE 0x0008 +#define AU88X0_CTL_IRQ_ENABLE 0x4000 + +#define AU88X0_IRQ_SOURCE 0x2a000 +#define AU88X0_IRQ_MASK 0x2a004 +#define AU88X0_IRQ_FATAL 0x0001 +#define AU88X0_IRQ_PARITY 0x0002 +#define AU88X0_IRQ_PCMOUT 0x0020 +#define AU88X0_IRQ_TIMER 0x1000 +#define AU88X0_IRQ_MIDI 0x2000 +#define AU88X0_IRQ_MODEM 0x4000 +#define AU88X0_IRQ_ALL 0x7023 +#define AU88X0_IRQ_PENDING 0x2a008 +#define AU88X0_IRQ_PENDING_BIT 0x0001 +#define AU88X0_IRQ_STATUS 0x2919c + +/* + * CODEC REGISTERS + * + * These are the registers we use to converse with the AC'97 codec. + * + * AU88X0_CODEC_CHANNEL array of 32 32-bit words + * + * AU88X0_CODEC_CONTROL control register + * + * bit 16 ready + * + * AU88X0_CODEC_IO I/O register + * + * bits 0-15 contents of codec register + * bits 16-22 address of codec register + * bit 23 0 for read, 1 for write + */ +#define AU88X0_CODEC_CHANNEL 0x29080 +#define AU88X0_CODEC_CONTROL 0x29184 +#define AU88X0_CDCTL_WROK 0x00000100 +#define AU88X0_CODEC_IO 0x29188 +#define AU88X0_CDIO_DATA_SHIFT 0 +#define AU88X0_CDIO_DATA_MASK 0x0000ffff +#define AU88X0_CDIO_ADDR_SHIFT 16 +#define AU88X0_CDIO_ADDR_MASK 0x007f0000 +#define AU88X0_CDIO_RDBIT 0x00000000 +#define AU88X0_CDIO_WRBIT 0x00800000 +#define AU88X0_CDIO_READ(a) (AU88X0_CDIO_RDBIT | \ + (((a) << AU88X0_CDIO_ADDR_SHIFT) & AU88X0_CDIO_ADDR_MASK)) +#define AU88X0_CDIO_WRITE(a, d) (AU88X0_CDIO_WRBIT | \ + (((a) << AU88X0_CDIO_ADDR_SHIFT) & AU88X0_CDIO_ADDR_MASK) | \ + (((d) << AU88X0_CDIO_DATA_SHIFT) & AU88X0_CDIO_DATA_MASK)) +#define AU88X0_CODEC_ENABLE 0x29190 + +/* + * These constants control codec polling + */ +#define AU88X0_CODEC_POLL_COUNT 100 +#define AU88X0_CODEC_POLL_DELAY 2000 + +#endif Index: sys/modules/sound/driver/Makefile =================================================================== RCS file: /home/ncvs/src/sys/modules/sound/driver/Makefile,v retrieving revision 1.15 diff -u -u -r1.15 Makefile --- sys/modules/sound/driver/Makefile 17 Aug 2002 16:23:44 -0000 1.15 +++ sys/modules/sound/driver/Makefile 23 May 2003 03:04:29 -0000 @@ -1,6 +1,6 @@ # $FreeBSD: src/sys/modules/sound/driver/Makefile,v 1.15 2002/08/17 16:23:44 orion Exp $ -SUBDIR = als4000 ad1816 cmi cs4281 csa ds1 emu10k1 es137x ess +SUBDIR = als4000 ad1816 au88x0 cmi cs4281 csa ds1 emu10k1 es137x ess SUBDIR += fm801 ich maestro maestro3 mss neomagic sb16 sb8 sbc solo SUBDIR += t4dwave via8233 via82c686 vibes SUBDIR += driver uaudio Index: sys/modules/sound/driver/au88x0/Makefile =================================================================== RCS file: sys/modules/sound/driver/au88x0/Makefile diff -N sys/modules/sound/driver/au88x0/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ sys/modules/sound/driver/au88x0/Makefile 20 May 2003 14:22:38 -0000 @@ -0,0 +1,9 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../../../../dev/sound/pci + +KMOD= snd_au88x0 +SRCS= device_if.h bus_if.h pci_if.h +SRCS+= au88x0.c + +.include