diff options
Diffstat (limited to 'sys/dev/sound')
| -rw-r--r-- | sys/dev/sound/pci/fm801.c | 728 | ||||
| -rw-r--r-- | sys/dev/sound/pci/maestro.c | 1188 | ||||
| -rw-r--r-- | sys/dev/sound/pci/maestro_reg.h | 345 | ||||
| -rw-r--r-- | sys/dev/sound/pci/via82c686.c | 689 | ||||
| -rw-r--r-- | sys/dev/sound/pci/via82c686.h | 108 |
5 files changed, 0 insertions, 3058 deletions
diff --git a/sys/dev/sound/pci/fm801.c b/sys/dev/sound/pci/fm801.c deleted file mode 100644 index 2173c0a8519f..000000000000 --- a/sys/dev/sound/pci/fm801.c +++ /dev/null @@ -1,728 +0,0 @@ -/* - * Copyright (c) 2000 Dmitry Dicky diwil@dataart.com - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. - * - * $FreeBSD$ - */ - -#include <dev/sound/pcm/sound.h> -#include <dev/sound/pcm/ac97.h> -#include <pci/pcireg.h> -#include <pci/pcivar.h> - -#define PCI_VENDOR_FORTEMEDIA 0x1319 -#define PCI_DEVICE_FORTEMEDIA1 0x08011319 -#define PCI_DEVICE_FORTEMEDIA2 0x08021319 /* ??? have no idea what's this... */ - -#define FM_PCM_VOLUME 0x00 -#define FM_FM_VOLUME 0x02 -#define FM_I2S_VOLUME 0x04 -#define FM_RECORD_SOURCE 0x06 - -#define FM_PLAY_CTL 0x08 -#define FM_PLAY_RATE_MASK 0x0f00 -#define FM_PLAY_BUF1_LAST 0x0001 -#define FM_PLAY_BUF2_LAST 0x0002 -#define FM_PLAY_START 0x0020 -#define FM_PLAY_PAUSE 0x0040 -#define FM_PLAY_STOPNOW 0x0080 -#define FM_PLAY_16BIT 0x4000 -#define FM_PLAY_STEREO 0x8000 - -#define FM_PLAY_DMALEN 0x0a -#define FM_PLAY_DMABUF1 0x0c -#define FM_PLAY_DMABUF2 0x10 - - -#define FM_REC_CTL 0x14 -#define FM_REC_RATE_MASK 0x0f00 -#define FM_REC_BUF1_LAST 0x0001 -#define FM_REC_BUF2_LAST 0x0002 -#define FM_REC_START 0x0020 -#define FM_REC_PAUSE 0x0040 -#define FM_REC_STOPNOW 0x0080 -#define FM_REC_16BIT 0x4000 -#define FM_REC_STEREO 0x8000 - - -#define FM_REC_DMALEN 0x16 -#define FM_REC_DMABUF1 0x18 -#define FM_REC_DMABUF2 0x1c - -#define FM_CODEC_CTL 0x22 -#define FM_VOLUME 0x26 -#define FM_VOLUME_MUTE 0x8000 - -#define FM_CODEC_CMD 0x2a -#define FM_CODEC_CMD_READ 0x0080 -#define FM_CODEC_CMD_VALID 0x0100 -#define FM_CODEC_CMD_BUSY 0x0200 - -#define FM_CODEC_DATA 0x2c - -#define FM_IO_CTL 0x52 -#define FM_CARD_CTL 0x54 - -#define FM_INTMASK 0x56 -#define FM_INTMASK_PLAY 0x0001 -#define FM_INTMASK_REC 0x0002 -#define FM_INTMASK_VOL 0x0040 -#define FM_INTMASK_MPU 0x0080 - -#define FM_INTSTATUS 0x5a -#define FM_INTSTATUS_PLAY 0x0100 -#define FM_INTSTATUS_REC 0x0200 -#define FM_INTSTATUS_VOL 0x4000 -#define FM_INTSTATUS_MPU 0x8000 - -#define FM801_BUFFSIZE 1024*4 /* Other values do not work!!! */ - -/* debug purposes */ -#define DPRINT if(0) printf - - -/* channel interface */ -static void *fm801ch_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir); -static int fm801ch_setformat(void *data, u_int32_t format); -static int fm801ch_setspeed(void *data, u_int32_t speed); -static int fm801ch_setblocksize(void *data, u_int32_t blocksize); -static int fm801ch_trigger(void *data, int go); -static int fm801ch_getptr(void *data); -static pcmchan_caps *fm801ch_getcaps(void *data); -/* -static int fm801ch_setup(pcm_channel *c); -*/ - -static u_int32_t fmts[] = { - AFMT_U8, - AFMT_STEREO | AFMT_U8, - AFMT_S16_LE, - AFMT_STEREO | AFMT_S16_LE, - 0 -}; - -static pcmchan_caps fm801ch_caps = { - 4000, 48000, - fmts, 0 -}; - -static pcm_channel fm801_chantemplate = { - fm801ch_init, - NULL, /* setdir */ - fm801ch_setformat, - fm801ch_setspeed, - fm801ch_setblocksize, - fm801ch_trigger, - fm801ch_getptr, - fm801ch_getcaps, - NULL, /* free */ - NULL, /* nop1 */ - NULL, /* nop2 */ - NULL, /* nop3 */ - NULL, /* nop4 */ - NULL, /* nop5 */ - NULL, /* nop6 */ - NULL, /* nop7 */ -}; - -struct fm801_info; - -struct fm801_chinfo { - struct fm801_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; - u_int32_t spd, dir, fmt; /* speed, direction, format */ - u_int32_t shift; -}; - -struct fm801_info { - int type; - bus_space_tag_t st; - bus_space_handle_t sh; - bus_dma_tag_t parent_dmat; - - device_t dev; - int num; - u_int32_t unit; - - struct resource *reg, *irq; - int regtype, regid, irqid; - void *ih; - - u_int32_t play_flip, - play_nextblk, - play_start, - play_blksize, - play_fmt, - play_shift, - play_size; - - u_int32_t rec_flip, - rec_nextblk, - rec_start, - rec_blksize, - rec_fmt, - rec_shift, - rec_size; - - struct fm801_chinfo pch, rch; -}; - -/* Bus Read / Write routines */ -static u_int32_t -fm801_rd(struct fm801_info *fm801, int regno, int size) -{ - switch(size) { - case 1: - return (bus_space_read_1(fm801->st, fm801->sh, regno)); - case 2: - return (bus_space_read_2(fm801->st, fm801->sh, regno)); - case 4: - return (bus_space_read_4(fm801->st, fm801->sh, regno)); - default: - return 0xffffffff; - } -} - -static void -fm801_wr(struct fm801_info *fm801, int regno, u_int32_t data, int size) -{ - switch(size) { - case 1: - return bus_space_write_1(fm801->st, fm801->sh, regno, data); - case 2: - return bus_space_write_2(fm801->st, fm801->sh, regno, data); - case 4: - return bus_space_write_4(fm801->st, fm801->sh, regno, data); - default: - return; - } -} - -/* - * ac97 codec routines - */ -#define TIMO 50 -static u_int32_t -fm801_rdcd(void *devinfo, int regno) -{ - struct fm801_info *fm801 = (struct fm801_info *)devinfo; - int i; - - for (i = 0; i < TIMO && fm801_rd(fm801,FM_CODEC_CMD,2) & FM_CODEC_CMD_BUSY; i++) { - DELAY(10000); - DPRINT("fm801 rdcd: 1 - DELAY\n"); - } - if (i >= TIMO) { - printf("fm801 rdcd: codec busy\n"); - return 0; - } - - fm801_wr(fm801,FM_CODEC_CMD, regno|FM_CODEC_CMD_READ,2); - - for (i = 0; i < TIMO && !(fm801_rd(fm801,FM_CODEC_CMD,2) & FM_CODEC_CMD_VALID); i++) - { - DELAY(10000); - DPRINT("fm801 rdcd: 2 - DELAY\n"); - } - if (i >= TIMO) { - printf("fm801 rdcd: write codec invalid\n"); - return 0; - } - - return fm801_rd(fm801,FM_CODEC_DATA,2); -} - -static void -fm801_wrcd(void *devinfo, int regno, u_int32_t data) -{ - struct fm801_info *fm801 = (struct fm801_info *)devinfo; - int i; - - DPRINT("fm801_wrcd reg 0x%x val 0x%x\n",regno, data); -/* - if(regno == AC97_REG_RECSEL) return; -*/ - /* Poll until codec is ready */ - for (i = 0; i < TIMO && fm801_rd(fm801,FM_CODEC_CMD,2) & FM_CODEC_CMD_BUSY; i++) { - DELAY(10000); - DPRINT("fm801 rdcd: 1 - DELAY\n"); - } - if (i >= TIMO) { - printf("fm801 wrcd: read codec busy\n"); - return; - } - - fm801_wr(fm801,FM_CODEC_DATA,data, 2); - fm801_wr(fm801,FM_CODEC_CMD, regno,2); - - /* wait until codec is ready */ - for (i = 0; i < TIMO && fm801_rd(fm801,FM_CODEC_CMD,2) & FM_CODEC_CMD_BUSY; i++) { - DELAY(10000); - DPRINT("fm801 wrcd: 2 - DELAY\n"); - } - if (i >= TIMO) { - printf("fm801 wrcd: read codec busy\n"); - return; - } - DPRINT("fm801 wrcd release reg 0x%x val 0x%x\n",regno, data); - return; -} - -/* - * The interrupt handler - */ -static void -fm801_intr(void *p) -{ - struct fm801_info *fm801 = (struct fm801_info *)p; - u_int32_t intsrc = fm801_rd(fm801, FM_INTSTATUS, 2); - struct fm801_chinfo *ch = &(fm801->pch); - snd_dbuf *b = ch->buffer; - - DPRINT("\nfm801_intr intsrc 0x%x ", intsrc); - DPRINT("rp %d, rl %d, fp %d fl %d, size=%d\n", - b->rp,b->rl, b->fp,b->fl, b->blksz); - - if(intsrc & FM_INTSTATUS_PLAY) { - fm801->play_flip++; - if(fm801->play_flip & 1) { - fm801_wr(fm801, FM_PLAY_DMABUF1, fm801->play_start,4); - } else - fm801_wr(fm801, FM_PLAY_DMABUF2, fm801->play_nextblk,4); - chn_intr(fm801->pch.channel); - } - - if(intsrc & FM_INTSTATUS_REC) { - fm801->rec_flip++; - if(fm801->rec_flip & 1) { - fm801_wr(fm801, FM_REC_DMABUF1, fm801->rec_start,4); - } else - fm801_wr(fm801, FM_REC_DMABUF2, fm801->rec_nextblk,4); - chn_intr(fm801->rch.channel); - } - - if ( intsrc & FM_INTSTATUS_MPU ) { - /* This is a TODOish thing... */ - fm801_wr(fm801, FM_INTSTATUS, intsrc & FM_INTSTATUS_MPU,2); - } - - if ( intsrc & FM_INTSTATUS_VOL ) { - /* This is a TODOish thing... */ - fm801_wr(fm801, FM_INTSTATUS, intsrc & FM_INTSTATUS_VOL,2); - } - - DPRINT("fm801_intr clear\n\n"); - fm801_wr(fm801, FM_INTSTATUS, intsrc & (FM_INTSTATUS_PLAY | FM_INTSTATUS_REC), 2); -} - -/* - * Init routine is taken from an original NetBSD driver - */ -static int -fm801_init(struct fm801_info *fm801) -{ - u_int32_t k1; - - /* reset codec */ - fm801_wr(fm801, FM_CODEC_CTL, 0x0020,2); - DELAY(100000); - fm801_wr(fm801, FM_CODEC_CTL, 0x0000,2); - DELAY(100000); - - fm801_wr(fm801, FM_PCM_VOLUME, 0x0808,2); - fm801_wr(fm801, FM_FM_VOLUME, 0x0808,2); - fm801_wr(fm801, FM_I2S_VOLUME, 0x0808,2); - fm801_wr(fm801, 0x40,0x107f,2); /* enable legacy audio */ - - fm801_wr((void *)fm801, FM_RECORD_SOURCE, 0x0000,2); - - /* Unmask playback, record and mpu interrupts, mask the rest */ - k1 = fm801_rd((void *)fm801, FM_INTMASK,2); - fm801_wr(fm801, FM_INTMASK, - (k1 & ~(FM_INTMASK_PLAY | FM_INTMASK_REC | FM_INTMASK_MPU)) | - FM_INTMASK_VOL,2); - fm801_wr(fm801, FM_INTSTATUS, - FM_INTSTATUS_PLAY | FM_INTSTATUS_REC | FM_INTSTATUS_MPU | - FM_INTSTATUS_VOL,2); - - DPRINT("FM801 init Ok\n"); - return 0; -} - -static int -fm801_pci_attach(device_t dev) -{ - u_int32_t data; - struct ac97_info *codec = 0; - struct fm801_info *fm801; - int i; - int mapped = 0; - char status[SND_STATUSLEN]; - - if ((fm801 = (struct fm801_info *)malloc(sizeof(*fm801),M_DEVBUF, M_NOWAIT)) == NULL) { - device_printf(dev, "cannot allocate softc\n"); - return ENXIO; - } - - bzero(fm801, sizeof(*fm801)); - fm801->type = pci_get_devid(dev); - - data = pci_read_config(dev, PCIR_COMMAND, 2); - data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); - pci_write_config(dev, PCIR_COMMAND, data, 2); - data = pci_read_config(dev, PCIR_COMMAND, 2); - - for (i = 0; (mapped == 0) && (i < PCI_MAXMAPS_0); i++) { - fm801->regid = PCIR_MAPS + i*4; - fm801->regtype = SYS_RES_MEMORY; - fm801->reg = bus_alloc_resource(dev, fm801->regtype, &fm801->regid, - 0, ~0, 1, RF_ACTIVE); - if(!fm801->reg) - { - fm801->regtype = SYS_RES_IOPORT; - fm801->reg = bus_alloc_resource(dev, fm801->regtype, &fm801->regid, - 0, ~0, 1, RF_ACTIVE); - } - - if(fm801->reg) { - fm801->st = rman_get_bustag(fm801->reg); - fm801->sh = rman_get_bushandle(fm801->reg); - mapped++; - } - } - - if (mapped == 0) { - device_printf(dev, "unable to map register space\n"); - goto oops; - } - - fm801_init(fm801); - - codec = ac97_create(dev, (void *)fm801, NULL, fm801_rdcd, fm801_wrcd); - if (codec == NULL) goto oops; - - if (mixer_init(dev, &ac97_mixer, codec) == -1) goto oops; - - fm801->irqid = 0; - fm801->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &fm801->irqid, - 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); - if (!fm801->irq || - bus_setup_intr(dev, fm801->irq, INTR_TYPE_TTY, - fm801_intr, fm801, &fm801->ih)) { - device_printf(dev, "unable to map interrupt\n"); - goto oops; - } - - if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - /*maxsize*/FM801_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff, - /*flags*/0, &fm801->parent_dmat) != 0) { - device_printf(dev, "unable to create dma tag\n"); - goto oops; - } - - snprintf(status, 64, "at %s 0x%lx irq %ld", - (fm801->regtype == SYS_RES_IOPORT)? "io" : "memory", - rman_get_start(fm801->reg), rman_get_start(fm801->irq)); - -#define FM801_MAXPLAYCH 1 - if (pcm_register(dev, fm801, FM801_MAXPLAYCH, 1)) goto oops; - pcm_addchan(dev, PCMDIR_PLAY, &fm801_chantemplate, fm801); - pcm_addchan(dev, PCMDIR_REC, &fm801_chantemplate, fm801); - pcm_setstatus(dev, status); - - return 0; - -oops: - if (codec) ac97_destroy(codec); - if (fm801->reg) bus_release_resource(dev, fm801->regtype, fm801->regid, fm801->reg); - if (fm801->ih) bus_teardown_intr(dev, fm801->irq, fm801->ih); - if (fm801->irq) bus_release_resource(dev, SYS_RES_IRQ, fm801->irqid, fm801->irq); - if (fm801->parent_dmat) bus_dma_tag_destroy(fm801->parent_dmat); - free(fm801, M_DEVBUF); - return ENXIO; -} - -static int -fm801_pci_detach(device_t dev) -{ - int r; - struct fm801_info *fm801; - - DPRINT("Forte Media FM801 detach\n"); - - r = pcm_unregister(dev); - if (r) - return r; - - fm801 = pcm_getdevinfo(dev); - bus_release_resource(dev, fm801->regtype, fm801->regid, fm801->reg); - bus_teardown_intr(dev, fm801->irq, fm801->ih); - bus_release_resource(dev, SYS_RES_IRQ, fm801->irqid, fm801->irq); - bus_dma_tag_destroy(fm801->parent_dmat); - free(fm801, M_DEVBUF); - return 0; -} - -static int -fm801_pci_probe( device_t dev ) -{ - int id; - if ((id = pci_get_devid(dev)) == PCI_DEVICE_FORTEMEDIA1 ) { - device_set_desc(dev, "Forte Media FM801 Audio Controller"); - return 0; - } -/* - if ((id = pci_get_devid(dev)) == PCI_DEVICE_FORTEMEDIA2 ) { - device_set_desc(dev, "Forte Media FM801 Joystick (Not Supported)"); - return ENXIO; - } -*/ - return ENXIO; -} - - - -/* channel interface */ -static void * -fm801ch_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) -{ - struct fm801_info *fm801 = (struct fm801_info *)devinfo; - struct fm801_chinfo *ch = (dir == PCMDIR_PLAY)? &fm801->pch : &fm801->rch; - - DPRINT("fm801ch_init, direction = %d\n", dir); - ch->parent = fm801; - ch->channel = c; - ch->buffer = b; - ch->buffer->bufsize = FM801_BUFFSIZE; - ch->dir = dir; - if( chn_allocbuf(ch->buffer, fm801->parent_dmat) == -1) return NULL; - return (void *)ch; -} - -static int -fm801ch_setformat(void *data, u_int32_t format) -{ - struct fm801_chinfo *ch = data; - struct fm801_info *fm801 = ch->parent; - - DPRINT("fm801ch_setformat 0x%x : %s, %s, %s, %s\n", format, - (format & AFMT_STEREO)?"stereo":"mono", - (format & (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)) ? "16bit":"8bit", - (format & AFMT_SIGNED)? "signed":"unsigned", - (format & AFMT_BIGENDIAN)?"bigendiah":"littleendian" ); - - if(ch->dir == PCMDIR_PLAY) { - fm801->play_fmt = (format & AFMT_STEREO)? FM_PLAY_STEREO : 0; - fm801->play_fmt |= (format & AFMT_16BIT) ? FM_PLAY_16BIT : 0; - return 0; - } - - if(ch->dir == PCMDIR_REC ) { - fm801->rec_fmt = (format & AFMT_STEREO)? FM_REC_STEREO:0; - fm801->rec_fmt |= (format & AFMT_16BIT) ? FM_PLAY_16BIT : 0; - return 0; - } - - return 0; -} - -struct { - int limit; - int rate; -} fm801_rates[11] = { - { 6600, 5500 }, - { 8750, 8000 }, - { 10250, 9600 }, - { 13200, 11025 }, - { 17500, 16000 }, - { 20500, 19200 }, - { 26500, 22050 }, - { 35000, 32000 }, - { 41000, 38400 }, - { 46000, 44100 }, - { 48000, 48000 }, -/* anything above -> 48000 */ -}; - -static int -fm801ch_setspeed(void *data, u_int32_t speed) -{ - struct fm801_chinfo *ch = data; - struct fm801_info *fm801 = ch->parent; - register int i; - - - for (i = 0; i < 10 && fm801_rates[i].limit <= speed; i++) ; - - if(ch->dir == PCMDIR_PLAY) { - fm801->pch.spd = fm801_rates[i].rate; - fm801->play_shift = (i<<8); - fm801->play_shift &= FM_PLAY_RATE_MASK; - } - - if(ch->dir == PCMDIR_REC ) { - fm801->rch.spd = fm801_rates[i].rate; - fm801->rec_shift = (i<<8); - fm801->rec_shift &= FM_REC_RATE_MASK; - } - - ch->spd = fm801_rates[i].rate; - - return fm801_rates[i].rate; -} - -static int -fm801ch_setblocksize(void *data, u_int32_t blocksize) -{ - struct fm801_chinfo *ch = data; - struct fm801_info *fm801 = ch->parent; - - if(ch->dir == PCMDIR_PLAY) { - if(fm801->play_flip) return fm801->play_blksize; - fm801->play_blksize = blocksize; - } - - if(ch->dir == PCMDIR_REC) { - if(fm801->rec_flip) return fm801->rec_blksize; - fm801->rec_blksize = blocksize; - } - - DPRINT("fm801ch_setblocksize %d (dir %d)\n",blocksize, ch->dir); - - return blocksize; -} - -static int -fm801ch_trigger(void *data, int go) -{ - struct fm801_chinfo *ch = data; - struct fm801_info *fm801 = ch->parent; - u_int32_t baseaddr = vtophys(ch->buffer->buf); - snd_dbuf *b = ch->buffer; - u_int32_t k1; - - DPRINT("fm801ch_trigger go %d , ", go); - DPRINT("rp %d, rl %d, fp %d fl %d, dl %d, blksize=%d\n", - b->rp,b->rl, b->fp,b->fl, b->dl, b->blksz); - - if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) { - return 0; - } - - if (ch->dir == PCMDIR_PLAY) { - if (go == PCMTRIG_START) { - - fm801->play_start = baseaddr; - fm801->play_nextblk = fm801->play_start + fm801->play_blksize; - fm801->play_flip = 0; - fm801_wr(fm801, FM_PLAY_DMALEN, fm801->play_blksize - 1, 2); - fm801_wr(fm801, FM_PLAY_DMABUF1,fm801->play_start,4); - fm801_wr(fm801, FM_PLAY_DMABUF2,fm801->play_nextblk,4); - fm801_wr(fm801, FM_PLAY_CTL, - FM_PLAY_START | FM_PLAY_STOPNOW | fm801->play_fmt | fm801->play_shift, - 2 ); - } else { - fm801->play_flip = 0; - k1 = fm801_rd(fm801, FM_PLAY_CTL,2); - fm801_wr(fm801, FM_PLAY_CTL, - (k1 & ~(FM_PLAY_STOPNOW | FM_PLAY_START)) | - FM_PLAY_BUF1_LAST | FM_PLAY_BUF2_LAST, 2 ); - } - } else if(ch->dir == PCMDIR_REC) { - if (go == PCMTRIG_START) { - fm801->rec_start = baseaddr; - fm801->rec_nextblk = fm801->rec_start + fm801->rec_blksize; - fm801->rec_flip = 0; - fm801_wr(fm801, FM_REC_DMALEN, fm801->rec_blksize - 1, 2); - fm801_wr(fm801, FM_REC_DMABUF1,fm801->rec_start,4); - fm801_wr(fm801, FM_REC_DMABUF2,fm801->rec_nextblk,4); - fm801_wr(fm801, FM_REC_CTL, - FM_REC_START | FM_REC_STOPNOW | fm801->rec_fmt | fm801->rec_shift, - 2 ); - } else { - fm801->rec_flip = 0; - k1 = fm801_rd(fm801, FM_REC_CTL,2); - fm801_wr(fm801, FM_REC_CTL, - (k1 & ~(FM_REC_STOPNOW | FM_REC_START)) | - FM_REC_BUF1_LAST | FM_REC_BUF2_LAST, 2); - } - } - - return 0; -} - -/* Almost ALSA copy */ -static int -fm801ch_getptr(void *data) -{ - struct fm801_chinfo *ch = data; - struct fm801_info *fm801 = ch->parent; - int result = 0; - snd_dbuf *b = ch->buffer; - - if (ch->dir == PCMDIR_PLAY) { - result = fm801_rd(fm801, - (fm801->play_flip&1) ? - FM_PLAY_DMABUF2:FM_PLAY_DMABUF1, 4) - fm801->play_start; - } - - if (ch->dir == PCMDIR_REC) { - result = fm801_rd(fm801, - (fm801->rec_flip&1) ? - FM_REC_DMABUF2:FM_REC_DMABUF1, 4) - fm801->rec_start; - } - - DPRINT("fm801ch_getptr:%d, rp %d, rl %d, fp %d fl %d\n", - result, b->rp,b->rl, b->fp,b->fl); - - return result; -} - -static pcmchan_caps * -fm801ch_getcaps(void *data) -{ - return &fm801ch_caps; -} - -static device_method_t fm801_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, fm801_pci_probe), - DEVMETHOD(device_attach, fm801_pci_attach), - DEVMETHOD(device_detach, fm801_pci_detach), - { 0, 0} -}; - -static driver_t fm801_driver = { - "pcm", - fm801_methods, - sizeof(snddev_info), -}; - -static devclass_t pcm_devclass; - -DRIVER_MODULE(fm801, pci, fm801_driver, pcm_devclass, 0, 0); diff --git a/sys/dev/sound/pci/maestro.c b/sys/dev/sound/pci/maestro.c deleted file mode 100644 index a465d5c33533..000000000000 --- a/sys/dev/sound/pci/maestro.c +++ /dev/null @@ -1,1188 +0,0 @@ -/*- - * Copyright (c) 2000 Taku YAMAMOTO <taku@cent.saitama-u.ac.jp> - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. - * - * $Id: maestro.c,v 1.12 2000/09/06 03:32:34 taku Exp $ - * $FreeBSD$ - */ - -/* - * Credits: - * - * Part of this code (especially in many magic numbers) was heavily inspired - * by the Linux driver originally written by - * Alan Cox <alan.cox@linux.org>, modified heavily by - * Zach Brown <zab@zabbo.net>. - * - * busdma()-ize and buffer size reduction were suggested by - * Cameron Grant <gandalf@vilnya.demon.co.uk>. - * Also he showed me the way to use busdma() suite. - * - * Internal speaker problems on NEC VersaPro's and Dell Inspiron 7500 - * were looked at by - * Munehiro Matsuda <haro@tk.kubota.co.jp>, - * who brought patches based on the Linux driver with some simplification. - */ - -#include <dev/sound/pcm/sound.h> -#include <dev/sound/pcm/ac97.h> -#include <pci/pcireg.h> -#include <pci/pcivar.h> - -#include <dev/sound/pci/maestro_reg.h> - -#define inline __inline - -/* - * PCI IDs of supported chips: - * - * MAESTRO-1 0x01001285 - * MAESTRO-2 0x1968125d - * MAESTRO-2E 0x1978125d - */ - -#define MAESTRO_1_PCI_ID 0x01001285 -#define MAESTRO_2_PCI_ID 0x1968125d -#define MAESTRO_2E_PCI_ID 0x1978125d - -#define NEC_SUBID1 0x80581033 /* Taken from Linux driver */ -#define NEC_SUBID2 0x803c1033 /* NEC VersaProNX VA26D */ - -#ifndef AGG_MAXPLAYCH -# define AGG_MAXPLAYCH 4 -#endif - -#define AGG_BUFSIZ 4096 - - -/* ----------------------------- - * Data structures. - */ -struct agg_chinfo { - struct agg_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; - bus_addr_t offset; - u_int32_t blocksize; - int dir; - u_int num; - u_int16_t aputype; - u_int16_t wcreg_tpl; -}; - -struct agg_info { - device_t dev; - struct resource *reg; - int regid; - - bus_space_tag_t st; - bus_space_handle_t sh; - bus_dma_tag_t parent_dmat; - - struct resource *irq; - int irqid; - void *ih; - - u_int8_t *stat; - bus_addr_t baseaddr; - - struct ac97_info *codec; - - u_int playchns, active; - struct agg_chinfo pch[AGG_MAXPLAYCH]; - struct agg_chinfo rch; -}; - - -static u_int32_t agg_rdcodec(void *, int); -static void agg_wrcodec(void *, int, u_int32_t); - -static inline void ringbus_setdest(struct agg_info*, int, int); - -static inline u_int16_t wp_rdreg(struct agg_info*, u_int16_t); -static inline void wp_wrreg(struct agg_info*, u_int16_t, u_int16_t); -static inline u_int16_t wp_rdapu(struct agg_info*, int, u_int16_t); -static inline void wp_wrapu(struct agg_info*, int, u_int16_t, u_int16_t); -static inline void wp_settimer(struct agg_info*, u_int); -static inline void wp_starttimer(struct agg_info*); -static inline void wp_stoptimer(struct agg_info*); - -static inline u_int16_t wc_rdreg(struct agg_info*, u_int16_t); -static inline void wc_wrreg(struct agg_info*, u_int16_t, u_int16_t); -static inline u_int16_t wc_rdchctl(struct agg_info*, int); -static inline void wc_wrchctl(struct agg_info*, int, u_int16_t); - -static inline void agg_power(struct agg_info*, int); - -static void agg_init(struct agg_info*); -static u_int32_t agg_ac97_init(void *); - -static void aggch_start_dac(struct agg_chinfo*); -static void aggch_stop_dac(struct agg_chinfo*); - -static inline void suppress_jitter(struct agg_chinfo*); - -static inline u_int calc_timer_freq(struct agg_chinfo*); -static void set_timer(struct agg_info*); - -static pcmchan_init_t aggch_init; -static pcmchan_free_t aggch_free; -static pcmchan_setformat_t aggch_setplayformat; -static pcmchan_setspeed_t aggch_setspeed; -static pcmchan_setblocksize_t aggch_setblocksize; -static pcmchan_trigger_t aggch_trigger; -static pcmchan_getptr_t aggch_getplayptr; -static pcmchan_getcaps_t aggch_getcaps; - -static void agg_intr(void *); -static int agg_probe(device_t); -static int agg_attach(device_t); -static int agg_detach(device_t); -static int agg_suspend(device_t); -static int agg_resume(device_t); -static int agg_shutdown(device_t); - -static void *dma_malloc(struct agg_info*, u_int32_t, bus_addr_t*); -static void dma_free(struct agg_info*, void *); - -/* ----------------------------- - * Subsystems. - */ - -/* Codec/Ringbus */ - -static u_int32_t -agg_rdcodec(void *sc, int regno) -{ - struct agg_info *ess = sc; - unsigned t; - - /* We have to wait for a SAFE time to write addr/data */ - for (t = 0; t < 20; t++) { - if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) - & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS) - break; - DELAY(2); /* 20.8us / 13 */ - } - if (t == 20) - device_printf(ess->dev, "agg_rdcodec() PROGLESS timed out.\n"); - - bus_space_write_1(ess->st, ess->sh, PORT_CODEC_CMD, - CODEC_CMD_READ | regno); - DELAY(21); /* AC97 cycle = 20.8usec */ - - /* Wait for data retrieve */ - for (t = 0; t < 20; t++) { - if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) - & CODEC_STAT_MASK) == CODEC_STAT_RW_DONE) - break; - DELAY(2); /* 20.8us / 13 */ - } - if (t == 20) - /* Timed out, but perform dummy read. */ - device_printf(ess->dev, "agg_rdcodec() RW_DONE timed out.\n"); - - return bus_space_read_2(ess->st, ess->sh, PORT_CODEC_REG); -} - -static void -agg_wrcodec(void *sc, int regno, u_int32_t data) -{ - unsigned t; - struct agg_info *ess = sc; - - /* We have to wait for a SAFE time to write addr/data */ - for (t = 0; t < 20; t++) { - if ((bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) - & CODEC_STAT_MASK) != CODEC_STAT_PROGLESS) - break; - DELAY(2); /* 20.8us / 13 */ - } - if (t == 20) { - /* Timed out. Abort writing. */ - device_printf(ess->dev, "agg_wrcodec() PROGLESS timed out.\n"); - return; - } - - bus_space_write_2(ess->st, ess->sh, PORT_CODEC_REG, data); - bus_space_write_1(ess->st, ess->sh, PORT_CODEC_CMD, - CODEC_CMD_WRITE | regno); -} - -static inline void -ringbus_setdest(struct agg_info *ess, int src, int dest) -{ - u_int32_t data; - - data = bus_space_read_4(ess->st, ess->sh, PORT_RINGBUS_CTRL); - data &= ~(0xfU << src); - data |= (0xfU & dest) << src; - bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, data); -} - -/* Wave Processor */ - -static inline u_int16_t -wp_rdreg(struct agg_info *ess, u_int16_t reg) -{ - bus_space_write_2(ess->st, ess->sh, PORT_DSP_INDEX, reg); - return bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA); -} - -static inline void -wp_wrreg(struct agg_info *ess, u_int16_t reg, u_int16_t data) -{ - bus_space_write_2(ess->st, ess->sh, PORT_DSP_INDEX, reg); - bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, data); -} - -static inline void -apu_setindex(struct agg_info *ess, u_int16_t reg) -{ - int t; - - wp_wrreg(ess, WPREG_CRAM_PTR, reg); - /* Sometimes WP fails to set apu register index. */ - for (t = 0; t < 1000; t++) { - if (bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA) == reg) - break; - bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, reg); - } - if (t == 1000) - device_printf(ess->dev, "apu_setindex() timed out.\n"); -} - -static inline u_int16_t -wp_rdapu(struct agg_info *ess, int ch, u_int16_t reg) -{ - u_int16_t ret; - - apu_setindex(ess, ((unsigned)ch << 4) + reg); - ret = wp_rdreg(ess, WPREG_DATA_PORT); - return ret; -} - -static inline void -wp_wrapu(struct agg_info *ess, int ch, u_int16_t reg, u_int16_t data) -{ - int t; - - apu_setindex(ess, ((unsigned)ch << 4) + reg); - wp_wrreg(ess, WPREG_DATA_PORT, data); - for (t = 0; t < 1000; t++) { - if (bus_space_read_2(ess->st, ess->sh, PORT_DSP_DATA) == data) - break; - bus_space_write_2(ess->st, ess->sh, PORT_DSP_DATA, data); - } - if (t == 1000) - device_printf(ess->dev, "wp_wrapu() timed out.\n"); -} - -static inline void -wp_settimer(struct agg_info *ess, u_int freq) -{ - u_int clock = 48000 << 2; - u_int prescale = 0, divide = (freq != 0) ? (clock / freq) : ~0; - - RANGE(divide, 4, 32 << 8); - - for (; divide > 32 << 1; divide >>= 1) - prescale++; - divide = (divide + 1) >> 1; - - for (; prescale < 7 && divide > 2 && !(divide & 1); divide >>= 1) - prescale++; - - wp_wrreg(ess, WPREG_TIMER_ENABLE, 0); - wp_wrreg(ess, WPREG_TIMER_FREQ, - (prescale << WP_TIMER_FREQ_PRESCALE_SHIFT) | (divide - 1)); - wp_wrreg(ess, WPREG_TIMER_ENABLE, 1); -} - -static inline void -wp_starttimer(struct agg_info *ess) -{ - wp_wrreg(ess, WPREG_TIMER_START, 1); -} - -static inline void -wp_stoptimer(struct agg_info *ess) -{ - wp_wrreg(ess, WPREG_TIMER_START, 0); - bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1); -} - -/* WaveCache */ - -static inline u_int16_t -wc_rdreg(struct agg_info *ess, u_int16_t reg) -{ - bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_INDEX, reg); - return bus_space_read_2(ess->st, ess->sh, PORT_WAVCACHE_DATA); -} - -static inline void -wc_wrreg(struct agg_info *ess, u_int16_t reg, u_int16_t data) -{ - bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_INDEX, reg); - bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_DATA, data); -} - -static inline u_int16_t -wc_rdchctl(struct agg_info *ess, int ch) -{ - return wc_rdreg(ess, ch << 3); -} - -static inline void -wc_wrchctl(struct agg_info *ess, int ch, u_int16_t data) -{ - wc_wrreg(ess, ch << 3, data); -} - -/* Power management */ - -static inline void -agg_power(struct agg_info *ess, int status) -{ - u_int8_t data; - - data = pci_read_config(ess->dev, CONF_PM_PTR, 1); - if (pci_read_config(ess->dev, data, 1) == PPMI_CID) - pci_write_config(ess->dev, data + PM_CTRL, status, 1); -} - - -/* ----------------------------- - * Controller. - */ - -static inline void -agg_initcodec(struct agg_info* ess) -{ - u_int16_t data; - - if (bus_space_read_4(ess->st, ess->sh, PORT_RINGBUS_CTRL) - & RINGBUS_CTRL_ACLINK_ENABLED) { - bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); - DELAY(104); /* 20.8us * (4 + 1) */ - } - /* XXX - 2nd codec should be looked at. */ - bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, - RINGBUS_CTRL_AC97_SWRESET); - DELAY(2); - bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, - RINGBUS_CTRL_ACLINK_ENABLED); - DELAY(21); - - agg_rdcodec(ess, 0); - if (bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) - & CODEC_STAT_MASK) { - bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); - DELAY(21); - - /* Try cold reset. */ - device_printf(ess->dev, "will perform cold reset.\n"); - data = bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR); - if (pci_read_config(ess->dev, 0x58, 2) & 1) - data |= 0x10; - data |= 0x009 & - ~bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DATA); - bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 0xff6); - bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, - data | 0x009); - bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x000); - DELAY(2); - bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x001); - DELAY(1); - bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x009); - DELAY(500000); - bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, data); - DELAY(84); /* 20.8us * 4 */ - bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, - RINGBUS_CTRL_ACLINK_ENABLED); - DELAY(21); - } -} - -static void -agg_init(struct agg_info* ess) -{ - u_int32_t data; - - /* Setup PCI config registers. */ - - /* Disable all legacy emulations. */ - data = pci_read_config(ess->dev, CONF_LEGACY, 2); - data |= LEGACY_DISABLED; - pci_write_config(ess->dev, CONF_LEGACY, data, 2); - - /* Disconnect from CHI. (Makes Dell inspiron 7500 work?) - * Enable posted write. - * Prefer PCI timing rather than that of ISA. - * Don't swap L/R. */ - data = pci_read_config(ess->dev, CONF_MAESTRO, 4); - data |= MAESTRO_CHIBUS | MAESTRO_POSTEDWRITE | MAESTRO_DMA_PCITIMING; - data &= ~MAESTRO_SWAP_LR; - pci_write_config(ess->dev, CONF_MAESTRO, data, 4); - - /* Reset direct sound. */ - bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, - HOSTINT_CTRL_DSOUND_RESET); - DELAY(10000); /* XXX - too long? */ - bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); - DELAY(10000); - - /* Enable direct sound interruption. */ - bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, - HOSTINT_CTRL_DSOUND_INT_ENABLED); - - /* Setup Wave Processor. */ - - /* Enable WaveCache, set DMA base address. */ - wp_wrreg(ess, WPREG_WAVE_ROMRAM, - WP_WAVE_VIRTUAL_ENABLED | WP_WAVE_DRAM_ENABLED); - bus_space_write_2(ess->st, ess->sh, PORT_WAVCACHE_CTRL, - WAVCACHE_ENABLED | WAVCACHE_WTSIZE_4MB); - - for (data = WAVCACHE_PCMBAR; data < WAVCACHE_PCMBAR + 4; data++) - wc_wrreg(ess, data, ess->baseaddr >> WAVCACHE_BASEADDR_SHIFT); - - /* Setup Codec/Ringbus. */ - agg_initcodec(ess); - bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, - RINGBUS_CTRL_RINGBUS_ENABLED | RINGBUS_CTRL_ACLINK_ENABLED); - - wp_wrreg(ess, WPREG_BASE, 0x8500); /* Parallel I/O */ - ringbus_setdest(ess, RINGBUS_SRC_ADC, - RINGBUS_DEST_STEREO | RINGBUS_DEST_DSOUND_IN); - ringbus_setdest(ess, RINGBUS_SRC_DSOUND, - RINGBUS_DEST_STEREO | RINGBUS_DEST_DAC); - - /* Setup ASSP. Needed for Dell Inspiron 7500? */ - bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_B, 0x00); - bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_A, 0x03); - bus_space_write_1(ess->st, ess->sh, PORT_ASSP_CTRL_C, 0x00); - - /* - * Setup GPIO. - * There seems to be speciality with NEC systems. - */ - switch (pci_get_subvendor(ess->dev) - | (pci_get_subdevice(ess->dev) << 16)) { - case NEC_SUBID1: - case NEC_SUBID2: - /* Matthew Braithwaite <matt@braithwaite.net> reported that - * NEC Versa LX doesn't need GPIO operation. */ - bus_space_write_2(ess->st, ess->sh, PORT_GPIO_MASK, 0x9ff); - bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DIR, - bus_space_read_2(ess->st, ess->sh, PORT_GPIO_DIR) | 0x600); - bus_space_write_2(ess->st, ess->sh, PORT_GPIO_DATA, 0x200); - break; - } -} - -/* Channel controller. */ - -static void -aggch_start_dac(struct agg_chinfo *ch) -{ - u_int wpwa = APU_USE_SYSMEM | (ch->offset >> 9); - u_int size = AGG_BUFSIZ >> 1; - u_int speed = ch->channel->speed; - u_int offset = ch->offset >> 1; - u_int cp = ch->buffer->rp >> 1; - u_int16_t apuch = ch->num << 1; - u_int dv; - int pan = 0; - - switch (ch->aputype) { - case APUTYPE_16BITSTEREO: - wpwa >>= 1; - size >>= 1; - offset >>= 1; - cp >>= 1; - /* FALLTHROUGH */ - case APUTYPE_8BITSTEREO: - pan = 8; - apuch++; - break; - case APUTYPE_8BITLINEAR: - speed >>= 1; - break; - } - - dv = (((speed % 48000) << 16) + 24000) / 48000 - + ((speed / 48000) << 16); - - do { - wp_wrapu(ch->parent, apuch, APUREG_WAVESPACE, wpwa & 0xff00); - wp_wrapu(ch->parent, apuch, APUREG_CURPTR, offset + cp); - wp_wrapu(ch->parent, apuch, APUREG_ENDPTR, offset + size); - wp_wrapu(ch->parent, apuch, APUREG_LOOPLEN, size); - wp_wrapu(ch->parent, apuch, APUREG_AMPLITUDE, 0xe800); - wp_wrapu(ch->parent, apuch, APUREG_POSITION, 0x8f00 - | (RADIUS_CENTERCIRCLE << APU_RADIUS_SHIFT) - | ((PAN_FRONT + pan) << APU_PAN_SHIFT)); - wp_wrapu(ch->parent, apuch, APUREG_FREQ_LOBYTE, APU_plus6dB - | ((dv & 0xff) << APU_FREQ_LOBYTE_SHIFT)); - wp_wrapu(ch->parent, apuch, APUREG_FREQ_HIWORD, dv >> 8); - - if (ch->aputype == APUTYPE_16BITSTEREO) - wpwa |= APU_STEREO >> 1; - pan = -pan; - } while (pan < 0 && apuch--); - - wc_wrchctl(ch->parent, apuch, ch->wcreg_tpl); - wc_wrchctl(ch->parent, apuch + 1, ch->wcreg_tpl); - - wp_wrapu(ch->parent, apuch, APUREG_APUTYPE, - (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf); - if (ch->wcreg_tpl & WAVCACHE_CHCTL_STEREO) - wp_wrapu(ch->parent, apuch + 1, APUREG_APUTYPE, - (ch->aputype << APU_APUTYPE_SHIFT) | APU_DMA_ENABLED | 0xf); -} - -static void -aggch_stop_dac(struct agg_chinfo *ch) -{ - wp_wrapu(ch->parent, (ch->num << 1), APUREG_APUTYPE, - APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); - wp_wrapu(ch->parent, (ch->num << 1) + 1, APUREG_APUTYPE, - APUTYPE_INACTIVE << APU_APUTYPE_SHIFT); -} - -/* - * Stereo jitter suppressor. - * Sometimes playback pointers differ in stereo-paired channels. - * Calling this routine within intr fixes the problem. - */ -static inline void -suppress_jitter(struct agg_chinfo *ch) -{ - if (ch->wcreg_tpl & WAVCACHE_CHCTL_STEREO) { - int cp, diff, halfsize = AGG_BUFSIZ >> 2; - - if (ch->aputype == APUTYPE_16BITSTEREO) - halfsize >>= 1; - cp = wp_rdapu(ch->parent, (ch->num << 1), APUREG_CURPTR); - diff = wp_rdapu(ch->parent, (ch->num << 1) + 1, APUREG_CURPTR); - diff -= cp; - if (diff >> 1 && diff > -halfsize && diff < halfsize) - bus_space_write_2(ch->parent->st, ch->parent->sh, - PORT_DSP_DATA, cp); - } -} - -static inline u_int -calc_timer_freq(struct agg_chinfo *ch) -{ - u_int ss = 2; - - if (ch->aputype == APUTYPE_16BITSTEREO) - ss <<= 1; - if (ch->aputype == APUTYPE_8BITLINEAR) - ss >>= 1; - - return (ch->channel->speed * ss + ch->blocksize - 1) / ch->blocksize; -} - -static void -set_timer(struct agg_info *ess) -{ - int i; - u_int freq = 0; - - for (i = 0; i < ess->playchns; i++) - if ((ess->active & (1 << i)) && - (freq < calc_timer_freq(ess->pch + i))) - freq = calc_timer_freq(ess->pch + i); - - wp_settimer(ess, freq); -} - - -/* ----------------------------- - * Newpcm glue. - */ - -static u_int32_t -agg_ac97_init(void *sc) -{ - struct agg_info *ess = sc; - - return (bus_space_read_1(ess->st, ess->sh, PORT_CODEC_STAT) & CODEC_STAT_MASK)? 0 : 1; -} - -static void * -aggch_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) -{ - struct agg_info *ess = devinfo; - struct agg_chinfo *ch; - bus_addr_t physaddr; - - ch = (dir == PCMDIR_PLAY)? ess->pch + ess->playchns : &ess->rch; - - ch->parent = ess; - ch->channel = c; - ch->buffer = b; - ch->num = ess->playchns; - ch->dir = dir; - - b->buf = dma_malloc(ess, AGG_BUFSIZ, &physaddr); - if (b->buf == NULL) - return NULL; - - ch->offset = physaddr - ess->baseaddr; - if (physaddr < ess->baseaddr || ch->offset > WPWA_MAXADDR) { - device_printf(ess->dev, - "offset %#x exceeds limit. ", ch->offset); - dma_free(ess, b->buf); - b->buf = NULL; - return NULL; - } - - b->bufsize = AGG_BUFSIZ; - ch->wcreg_tpl = (physaddr - 16) & WAVCACHE_CHCTL_ADDRTAG_MASK; - - if (dir == PCMDIR_PLAY) { - ess->playchns++; - if (bootverbose) - device_printf(ess->dev, "pch[%d].offset = %#x\n", ch->num, ch->offset); - } else if (bootverbose) - device_printf(ess->dev, "rch.offset = %#x\n", ch->offset); - - return ch; -} - -static int -aggch_free(void *data) -{ - struct agg_chinfo *ch = data; - struct agg_info *ess = ch->parent; - - /* free up buffer - called after channel stopped */ - dma_free(ess, ch->buffer->buf); - - /* return 0 if ok */ - return 0; -} - -static int -aggch_setplayformat(void *data, u_int32_t format) -{ - struct agg_chinfo *ch = data; - u_int16_t wcreg_tpl; - u_int16_t aputype = APUTYPE_16BITLINEAR; - - wcreg_tpl = ch->wcreg_tpl & WAVCACHE_CHCTL_ADDRTAG_MASK; - - if (format & AFMT_STEREO) { - wcreg_tpl |= WAVCACHE_CHCTL_STEREO; - aputype += 1; - } - if (format & AFMT_U8 || format & AFMT_S8) { - aputype += 2; - if (format & AFMT_U8) - wcreg_tpl |= WAVCACHE_CHCTL_U8; - } - if (format & AFMT_BIGENDIAN || format & AFMT_U16_LE) { - format &= ~AFMT_BIGENDIAN & ~AFMT_U16_LE; - format |= AFMT_S16_LE; - } - ch->wcreg_tpl = wcreg_tpl; - ch->aputype = aputype; - return format; -} - -static int -aggch_setspeed(void *data, u_int32_t speed) -{ - return speed; -} - -static int -aggch_setblocksize(void *data, u_int32_t blocksize) -{ - return ((struct agg_chinfo*)data)->blocksize = blocksize; -} - -static int -aggch_trigger(void *data, int go) -{ - struct agg_chinfo *ch = data; - - switch (go) { - case PCMTRIG_EMLDMAWR: - return 0; - case PCMTRIG_START: - ch->parent->active |= (1 << ch->num); - if (ch->dir == PCMDIR_PLAY) - aggch_start_dac(ch); -#if 0 /* XXX - RECORDING */ - else - aggch_start_adc(ch); -#endif - break; - case PCMTRIG_ABORT: - case PCMTRIG_STOP: - ch->parent->active &= ~(1 << ch->num); - if (ch->dir == PCMDIR_PLAY) - aggch_stop_dac(ch); -#if 0 /* XXX - RECORDING */ - else - aggch_stop_adc(ch); -#endif - break; - } - - if (ch->parent->active) { - set_timer(ch->parent); - wp_starttimer(ch->parent); - } else - wp_stoptimer(ch->parent); - - return 0; -} - -static int -aggch_getplayptr(void *data) -{ - struct agg_chinfo *ch = data; - u_int cp; - - cp = wp_rdapu(ch->parent, (ch->num << 1), APUREG_CURPTR); - if (ch->aputype == APUTYPE_16BITSTEREO) - cp = (0xffff << 2) & ((cp << 2) - ch->offset); - else - cp = (0xffff << 1) & ((cp << 1) - ch->offset); - - return cp; -} - -static pcmchan_caps * -aggch_getcaps(void *data) -{ - static u_int32_t playfmt[] = { - AFMT_U8, - AFMT_STEREO | AFMT_U8, - AFMT_S8, - AFMT_STEREO | AFMT_S8, - AFMT_S16_LE, - AFMT_STEREO | AFMT_S16_LE, - 0 - }; - static pcmchan_caps playcaps = {2000, 96000, playfmt, 0}; - - static u_int32_t recfmt[] = { - AFMT_S8, - AFMT_STEREO | AFMT_S8, - AFMT_S16_LE, - AFMT_STEREO | AFMT_S16_LE, - 0 - }; - static pcmchan_caps reccaps = {4000, 48000, recfmt, 0}; - - return (((struct agg_chinfo*)data)->dir == PCMDIR_PLAY)? - &playcaps : &reccaps; -} - - -/* ----------------------------- - * Bus space. - */ - -static void -agg_intr(void *sc) -{ - struct agg_info* ess = sc; - u_int16_t status; - int i; - - status = bus_space_read_1(ess->st, ess->sh, PORT_HOSTINT_STAT); - if (!status) - return; - - /* Acknowledge all. */ - bus_space_write_2(ess->st, ess->sh, PORT_INT_STAT, 1); - bus_space_write_1(ess->st, ess->sh, PORT_HOSTINT_STAT, 0); -#if 0 /* XXX - HWVOL */ - if (status & HOSTINT_STAT_HWVOL) { - u_int delta; - delta = bus_space_read_1(ess->st, ess->sh, PORT_HWVOL_MASTER) - - 0x88; - if (delta & 0x11) - mixer_set(device_get_softc(ess->dev), - SOUND_MIXER_VOLUME, 0); - else { - mixer_set(device_get_softc(ess->dev), - SOUND_MIXER_VOLUME, - mixer_get(device_get_softc(ess->dev), - SOUND_MIXER_VOLUME) - + ((delta >> 5) & 0x7) - 4 - + ((delta << 7) & 0x700) - 0x400); - } - bus_space_write_1(ess->st, ess->sh, PORT_HWVOL_MASTER, 0x88); - } -#endif /* XXX - HWVOL */ - - for (i = 0; i < ess->playchns; i++) - if (ess->active & (1 << i)) { - suppress_jitter(ess->pch + i); - chn_intr(ess->pch[i].channel); - } -#if 0 /* XXX - RECORDING */ - if (ess->active & (1 << i)) - chn_intr(ess->rch.channel); -#endif -} - -static void -setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - bus_addr_t *phys = arg; - - *phys = error? 0 : segs->ds_addr; - - if (bootverbose) { - printf("setmap (%lx, %lx), nseg=%d, error=%d\n", - (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len, - nseg, error); - } -} - -static void * -dma_malloc(struct agg_info *sc, u_int32_t sz, bus_addr_t *phys) -{ - void *buf; - bus_dmamap_t map; - - if (bus_dmamem_alloc(sc->parent_dmat, &buf, BUS_DMA_NOWAIT, &map)) - return NULL; - if (bus_dmamap_load(sc->parent_dmat, map, buf, sz, setmap, phys, 0) - || !*phys) { - bus_dmamem_free(sc->parent_dmat, buf, map); - return NULL; - } - return buf; -} - -static void -dma_free(struct agg_info *sc, void *buf) -{ - bus_dmamem_free(sc->parent_dmat, buf, NULL); -} - -static int -agg_probe(device_t dev) -{ - char *s = NULL; - - switch (pci_get_devid(dev)) { - case MAESTRO_1_PCI_ID: - s = "ESS Technology Maestro-1"; - break; - - case MAESTRO_2_PCI_ID: - s = "ESS Technology Maestro-2"; - break; - - case MAESTRO_2E_PCI_ID: - s = "ESS Technology Maestro-2E"; - break; - } - - if (s != NULL && pci_get_class(dev) == PCIC_MULTIMEDIA) { - device_set_desc(dev, s); - return 0; - } - return ENXIO; -} - -static int -agg_attach(device_t dev) -{ - struct agg_info *ess = NULL; - u_int32_t data; - int mapped = 0; - int regid = PCIR_MAPS; - struct resource *reg = NULL; - struct ac97_info *codec = NULL; - int irqid = 0; - struct resource *irq = NULL; - void *ih = NULL; - char status[SND_STATUSLEN]; - static pcm_channel agg_pchtpl = { - aggch_init, - NULL, /* setdir */ - aggch_setplayformat, - aggch_setspeed, - aggch_setblocksize, - aggch_trigger, - aggch_getplayptr, - aggch_getcaps, - aggch_free, /* free */ - NULL, /* nop1 */ - NULL, /* nop2 */ - NULL, /* nop3 */ - NULL, /* nop4 */ - NULL, /* nop5 */ - NULL, /* nop6 */ - NULL, /* nop7 */ - }; - - if ((ess = malloc(sizeof *ess, M_DEVBUF, M_NOWAIT)) == NULL) { - device_printf(dev, "cannot allocate softc\n"); - return ENXIO; - } - bzero(ess, sizeof *ess); - ess->dev = dev; - - if (bus_dma_tag_create(/*parent*/NULL, - /*alignment*/1 << WAVCACHE_BASEADDR_SHIFT, - /*boundary*/WPWA_MAXADDR + 1, - /*lowaddr*/MAESTRO_MAXADDR, /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - /*maxsize*/AGG_BUFSIZ * 2, /*nsegments*/1, /*maxsegz*/0x3ffff, - /*flags*/0, &ess->parent_dmat) != 0) { - device_printf(dev, "unable to create dma tag\n"); - goto bad; - } - - ess->stat = dma_malloc(ess, AGG_BUFSIZ, &ess->baseaddr); - if (ess->stat == NULL) { - device_printf(dev, "cannot allocate status buffer\n"); - goto bad; - } - if (bootverbose) - device_printf(dev, "Maestro DMA base: %#x\n", ess->baseaddr); - - agg_power(ess, PPMI_D0); - DELAY(100000); - - data = pci_read_config(dev, PCIR_COMMAND, 2); - data |= (PCIM_CMD_PORTEN|PCIM_CMD_BUSMASTEREN); - pci_write_config(dev, PCIR_COMMAND, data, 2); - data = pci_read_config(dev, PCIR_COMMAND, 2); - - if (data & PCIM_CMD_PORTEN) { - reg = bus_alloc_resource(dev, SYS_RES_IOPORT, ®id, - 0, BUS_SPACE_UNRESTRICTED, 256, RF_ACTIVE); - if (reg != NULL) { - ess->reg = reg; - ess->regid = regid; - ess->st = rman_get_bustag(reg); - ess->sh = rman_get_bushandle(reg); - mapped++; - } - } - if (mapped == 0) { - device_printf(dev, "unable to map register space\n"); - goto bad; - } - - agg_init(ess); - if (agg_rdcodec(ess, 0) == 0x80) { - device_printf(dev, "PT101 codec detected!\n"); - goto bad; - } - codec = ac97_create(dev, ess, agg_ac97_init, agg_rdcodec, agg_wrcodec); - if (codec == NULL) - goto bad; - if (mixer_init(dev, &ac97_mixer, codec) == -1) - goto bad; - ess->codec = codec; - - irq = bus_alloc_resource(dev, SYS_RES_IRQ, &irqid, - 0, BUS_SPACE_UNRESTRICTED, 1, RF_ACTIVE | RF_SHAREABLE); - if (irq == NULL - || bus_setup_intr(dev, irq, INTR_TYPE_TTY, agg_intr, ess, &ih)) { - device_printf(dev, "unable to map interrupt\n"); - goto bad; - } - ess->irq = irq; - ess->irqid = irqid; - ess->ih = ih; - - snprintf(status, SND_STATUSLEN, "at I/O port 0x%lx irq %ld", - rman_get_start(reg), rman_get_start(irq)); - - if (pcm_register(dev, ess, AGG_MAXPLAYCH, 1)) - goto bad; - - for (data = 0; data < AGG_MAXPLAYCH; data++) - pcm_addchan(dev, PCMDIR_PLAY, &agg_pchtpl, ess); -#if 0 /* XXX - RECORDING */ - pcm_addchan(dev, PCMDIR_REC, &agg_rchtpl, ess); -#endif - pcm_setstatus(dev, status); - - return 0; - - bad: - if (codec != NULL) - ac97_destroy(codec); - if (ih != NULL) - bus_teardown_intr(dev, irq, ih); - if (irq != NULL) - bus_release_resource(dev, SYS_RES_IRQ, irqid, irq); - if (reg != NULL) - bus_release_resource(dev, SYS_RES_IOPORT, regid, reg); - if (ess != NULL) { - agg_power(ess, PPMI_D3); - if (ess->stat != NULL) - dma_free(ess, ess->stat); - if (ess->parent_dmat != NULL) - bus_dma_tag_destroy(ess->parent_dmat); - free(ess, M_DEVBUF); - } - - return ENXIO; -} - -static int -agg_detach(device_t dev) -{ - struct agg_info *ess = pcm_getdevinfo(dev); - int r; - - r = pcm_unregister(dev); - if (r) - return r; - - ess = pcm_getdevinfo(dev); - dma_free(ess, ess->stat); - - /* Power down everything except clock and vref. */ - agg_wrcodec(ess, AC97_REG_POWER, 0xd700); - DELAY(20); - bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); - agg_power(ess, PPMI_D3); - - bus_teardown_intr(dev, ess->irq, ess->ih); - bus_release_resource(dev, SYS_RES_IRQ, ess->irqid, ess->irq); - bus_release_resource(dev, SYS_RES_IOPORT, ess->regid, ess->reg); - bus_dma_tag_destroy(ess->parent_dmat); - free(ess, M_DEVBUF); - return 0; -} - -static int -agg_suspend(device_t dev) -{ - struct agg_info *ess = pcm_getdevinfo(dev); - int i, x; - - x = spltty(); - wp_stoptimer(ess); - bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); - - for (i = 0; i < ess->playchns; i++) - aggch_stop_dac(ess->pch + i); - -#if 0 /* XXX - RECORDING */ - aggch_stop_adc(&ess->rch); -#endif - splx(x); - /* Power down everything except clock. */ - agg_wrcodec(ess, AC97_REG_POWER, 0xdf00); - DELAY(20); - bus_space_write_4(ess->st, ess->sh, PORT_RINGBUS_CTRL, 0); - DELAY(1); - agg_power(ess, PPMI_D3); - - return 0; -} - -static int -agg_resume(device_t dev) -{ - int i, x; - struct agg_info *ess = pcm_getdevinfo(dev); - - agg_power(ess, PPMI_D0); - DELAY(100000); - agg_init(ess); - if (mixer_reinit(dev)) { - device_printf(dev, "unable to reinitialize the mixer\n"); - return ENXIO; - } - - x = spltty(); - for (i = 0; i < ess->playchns; i++) - if (ess->active & (1 << i)) - aggch_start_dac(ess->pch + i); -#if 0 /* XXX - RECORDING */ - if (ess->active & (1 << i)) - aggch_start_adc(&ess->rch); -#endif - if (ess->active) { - set_timer(ess); - wp_starttimer(ess); - } - splx(x); - return 0; -} - -static int -agg_shutdown(device_t dev) -{ - struct agg_info *ess = pcm_getdevinfo(dev); - int i; - - wp_stoptimer(ess); - bus_space_write_2(ess->st, ess->sh, PORT_HOSTINT_CTRL, 0); - - for (i = 0; i < ess->playchns; i++) - aggch_stop_dac(ess->pch + i); - -#if 0 /* XXX - RECORDING */ - aggch_stop_adc(&ess->rch); -#endif - return 0; -} - - -static device_method_t agg_methods[] = { - DEVMETHOD(device_probe, agg_probe), - DEVMETHOD(device_attach, agg_attach), - DEVMETHOD(device_detach, agg_detach), - DEVMETHOD(device_suspend, agg_suspend), - DEVMETHOD(device_resume, agg_resume), - DEVMETHOD(device_shutdown, agg_shutdown), - - { 0, 0 } -}; - -static driver_t agg_driver = { - "pcm", - agg_methods, - sizeof(snddev_info), -}; - -static devclass_t pcm_devclass; - -DRIVER_MODULE(snd_maestro, pci, agg_driver, pcm_devclass, 0, 0); -MODULE_DEPEND(snd_maestro, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); -MODULE_VERSION(snd_maestro, 1); diff --git a/sys/dev/sound/pci/maestro_reg.h b/sys/dev/sound/pci/maestro_reg.h deleted file mode 100644 index 579723388d8e..000000000000 --- a/sys/dev/sound/pci/maestro_reg.h +++ /dev/null @@ -1,345 +0,0 @@ -/*- - * Copyright (c) 1999-2000 Taku YAMAMOTO <taku@cent.saitama-u.ac.jp> - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. - * - * $Id: maestro_reg.h,v 1.10 2000/08/29 17:27:29 taku Exp $ - * $FreeBSD$ - */ - -#ifndef MAESTRO_REG_H_INCLUDED -#define MAESTRO_REG_H_INCLUDED - -/* ----------------------------- - * PCI config registers - */ - -/* Legacy emulation */ -#define CONF_LEGACY 0x40 - -#define LEGACY_DISABLED 0x8000 - -/* Chip configurations */ -#define CONF_MAESTRO 0x50 -#define MAESTRO_CHIBUS 0x00100000 -#define MAESTRO_POSTEDWRITE 0x00000080 -#define MAESTRO_DMA_PCITIMING 0x00000040 -#define MAESTRO_SWAP_LR 0x00000010 - -/* ACPI configurations */ -#define CONF_ACPI_STOPCLOCK 0x54 -#define ACPI_PART_2ndC_CLOCK 15 -#define ACPI_PART_CODEC_CLOCK 14 -#define ACPI_PART_978 13 /* Docking station or something */ -#define ACPI_PART_SPDIF 12 -#define ACPI_PART_GLUE 11 /* What? */ -#define ACPI_PART_DAA 10 -#define ACPI_PART_PCI_IF 9 -#define ACPI_PART_HW_VOL 8 -#define ACPI_PART_GPIO 7 -#define ACPI_PART_ASSP 6 -#define ACPI_PART_SB 5 -#define ACPI_PART_FM 4 -#define ACPI_PART_RINGBUS 3 -#define ACPI_PART_MIDI 2 -#define ACPI_PART_GAME_PORT 1 -#define ACPI_PART_WP 0 - -/* Power management */ -#define CONF_PM_PTR 0x34 /* BYTE R */ -#define PM_CID 0 /* BYTE R */ -#define PPMI_CID 1 -#define PM_CTRL 4 /* BYTE RW */ -#define PPMI_D0 0 /* Full power */ -#define PPMI_D1 1 /* Medium power */ -#define PPMI_D2 2 /* Low power */ -#define PPMI_D3 3 /* Turned off */ - - -/* ----------------------------- - * I/O ports - */ - -/* Direct Sound Processor (aka WP) */ -#define PORT_DSP_DATA 0x00 /* WORD RW */ -#define PORT_DSP_INDEX 0x02 /* WORD RW */ -#define PORT_INT_STAT 0x04 /* WORD RW */ -#define PORT_SAMPLE_CNT 0x06 /* WORD RO */ - -/* WaveCache */ -#define PORT_WAVCACHE_INDEX 0x10 /* WORD RW */ -#define PORT_WAVCACHE_DATA 0x12 /* WORD RW */ -#define WAVCACHE_PCMBAR 0x1fc -#define WAVCACHE_WTBAR 0x1f0 -#define WAVCACHE_BASEADDR_SHIFT 12 - -#define WAVCACHE_CHCTL_ADDRTAG_MASK 0xfff8 -#define WAVCACHE_CHCTL_U8 0x0004 -#define WAVCACHE_CHCTL_STEREO 0x0002 -#define WAVCACHE_CHCTL_DECREMENTAL 0x0001 - -#define PORT_WAVCACHE_CTRL 0x14 /* WORD RW */ -#define WAVCACHE_EXTRA_CH_ENABLED 0x0200 -#define WAVCACHE_ENABLED 0x0100 -#define WAVCACHE_CH_60_ENABLED 0x0080 -#define WAVCACHE_WTSIZE_MASK 0x0060 -#define WAVCACHE_WTSIZE_1MB 0x0000 -#define WAVCACHE_WTSIZE_2MB 0x0020 -#define WAVCACHE_WTSIZE_4MB 0x0040 -#define WAVCACHE_WTSIZE_8MB 0x0060 -#define WAVCACHE_SGC_MASK 0x000c -#define WAVCACHE_SGC_DISABLED 0x0000 -#define WAVCACHE_SGC_40_47 0x0004 -#define WAVCACHE_SGC_32_47 0x0008 -#define WAVCACHE_TESTMODE 0x0001 - -/* Host Interruption */ -#define PORT_HOSTINT_CTRL 0x18 /* WORD RW */ -#define HOSTINT_CTRL_SOFT_RESET 0x8000 -#define HOSTINT_CTRL_DSOUND_RESET 0x4000 -#define HOSTINT_CTRL_HW_VOL_TO_PME 0x0400 -#define HOSTINT_CTRL_CLKRUN_ENABLED 0x0100 -#define HOSTINT_CTRL_HWVOL_ENABLED 0x0040 -#define HOSTINT_CTRL_ASSP_INT_ENABLED 0x0010 -#define HOSTINT_CTRL_ISDN_INT_ENABLED 0x0008 -#define HOSTINT_CTRL_DSOUND_INT_ENABLED 0x0004 -#define HOSTINT_CTRL_MPU401_INT_ENABLED 0x0002 -#define HOSTINT_CTRL_SB_INT_ENABLED 0x0001 - -#define PORT_HOSTINT_STAT 0x1a /* BYTE RW */ -#define HOSTINT_STAT_HWVOL 0x40 -#define HOSTINT_STAT_ASSP 0x10 -#define HOSTINT_STAT_ISDN 0x08 -#define HOSTINT_STAT_DSOUND 0x04 -#define HOSTINT_STAT_MPU401 0x02 -#define HOSTINT_STAT_SB 0x01 - -/* Hardware volume */ -#define PORT_HWVOL_VOICE_SHADOW 0x1c /* BYTE RW */ -#define PORT_HWVOL_VOICE 0x1d /* BYTE RW */ -#define PORT_HWVOL_MASTER_SHADOW 0x1e /* BYTE RW */ -#define PORT_HWVOL_MASTER 0x1f /* BYTE RW */ - -/* CODEC */ -#define PORT_CODEC_CMD 0x30 /* BYTE W */ -#define CODEC_CMD_READ 0x80 -#define CODEC_CMD_WRITE 0x00 -#define CODEC_CMD_ADDR_MASK 0x7f - -#define PORT_CODEC_STAT 0x30 /* BYTE R */ -#define CODEC_STAT_MASK 0x01 -#define CODEC_STAT_RW_DONE 0x00 -#define CODEC_STAT_PROGLESS 0x01 - -#define PORT_CODEC_REG 0x32 /* WORD RW */ - -/* Ring bus control */ -#define PORT_RINGBUS_CTRL 0x34 /* DWORD RW */ -#define RINGBUS_CTRL_I2S_ENABLED 0x80000000 -#define RINGBUS_CTRL_RINGBUS_ENABLED 0x20000000 -#define RINGBUS_CTRL_ACLINK_ENABLED 0x10000000 -#define RINGBUS_CTRL_AC97_SWRESET 0x08000000 -#define RINGBUS_CTRL_IODMA_PLAYBACK_ENABLED 0x04000000 -#define RINGBUS_CTRL_IODMA_RECORD_ENABLED 0x02000000 - -#define RINGBUS_SRC_MIC 20 -#define RINGBUS_SRC_I2S 16 -#define RINGBUS_SRC_ADC 12 -#define RINGBUS_SRC_MODEM 8 -#define RINGBUS_SRC_DSOUND 4 -#define RINGBUS_SRC_ASSP 0 - -#define RINGBUS_DEST_MONORAL 000 -#define RINGBUS_DEST_STEREO 010 -#define RINGBUS_DEST_NONE 0 -#define RINGBUS_DEST_DAC 1 -#define RINGBUS_DEST_MODEM_IN 2 -#define RINGBUS_DEST_RESERVED3 3 -#define RINGBUS_DEST_DSOUND_IN 4 -#define RINGBUS_DEST_ASSP_IN 5 - -/* General Purpose I/O */ -#define PORT_GPIO_DATA 0x60 /* WORD RW */ -#define PORT_GPIO_MASK 0x64 /* WORD RW */ -#define PORT_GPIO_DIR 0x68 /* WORD RW */ - -/* Application Specific Signal Processor */ -#define PORT_ASSP_MEM_INDEX 0x80 /* DWORD RW */ -#define PORT_ASSP_MEM_DATA 0x84 /* WORD RW */ -#define PORT_ASSP_CTRL_A 0xa2 /* BYTE RW */ -#define PORT_ASSP_CTRL_B 0xa4 /* BYTE RW */ -#define PORT_ASSP_CTRL_C 0xa6 /* BYTE RW */ -#define PORT_ASSP_HOST_WR_INDEX 0xa8 /* BYTE W */ -#define PORT_ASSP_HOST_WR_DATA 0xaa /* BYTE RW */ -#define PORT_ASSP_INT_STAT 0xac /* BYTE RW */ - - -/* ----------------------------- - * Wave Processor Indexed Data Registers. - */ - -#define WPREG_DATA_PORT 0 -#define WPREG_CRAM_PTR 1 -#define WPREG_CRAM_DATA 2 -#define WPREG_WAVE_DATA 3 -#define WPREG_WAVE_PTR_LOW 4 -#define WPREG_WAVE_PTR_HIGH 5 - -#define WPREG_TIMER_FREQ 6 -#define WP_TIMER_FREQ_PRESCALE_MASK 0x00e0 /* actual - 9 */ -#define WP_TIMER_FREQ_PRESCALE_SHIFT 5 -#define WP_TIMER_FREQ_DIVIDE_MASK 0x001f -#define WP_TIMER_FREQ_DIVIDE_SHIFT 0 - -#define WPREG_WAVE_ROMRAM 7 -#define WP_WAVE_VIRTUAL_ENABLED 0x0400 -#define WP_WAVE_8BITRAM_ENABLED 0x0200 -#define WP_WAVE_DRAM_ENABLED 0x0100 -#define WP_WAVE_RAMSPLIT_MASK 0x00ff -#define WP_WAVE_RAMSPLIT_SHIFT 0 - -#define WPREG_BASE 12 -#define WP_PARAOUT_BASE_MASK 0xf000 -#define WP_PARAOUT_BASE_SHIFT 12 -#define WP_PARAIN_BASE_MASK 0x0f00 -#define WP_PARAIN_BASE_SHIFT 8 -#define WP_SERIAL0_BASE_MASK 0x00f0 -#define WP_SERIAL0_BASE_SHIFT 4 -#define WP_SERIAL1_BASE_MASK 0x000f -#define WP_SERIAL1_BASE_SHIFT 0 - -#define WPREG_TIMER_ENABLE 17 -#define WPREG_TIMER_START 23 - - -/* ----------------------------- - * Audio Processing Unit. - */ -#define APUREG_APUTYPE 0 -#define APU_DMA_ENABLED 0x4000 -#define APU_INT_ON_LOOP 0x2000 -#define APU_ENDCURVE 0x1000 -#define APU_APUTYPE_MASK 0x00f0 -#define APU_FILTERTYPE_MASK 0x000c -#define APU_FILTERQ_MASK 0x0003 - -/* APU types */ -#define APU_APUTYPE_SHIFT 4 - -#define APUTYPE_INACTIVE 0 -#define APUTYPE_16BITLINEAR 1 -#define APUTYPE_16BITSTEREO 2 -#define APUTYPE_8BITLINEAR 3 -#define APUTYPE_8BITSTEREO 4 -#define APUTYPE_8BITDIFF 5 -#define APUTYPE_DIGITALDELAY 6 -#define APUTYPE_DUALTAP_READER 7 -#define APUTYPE_CORRELATOR 8 -#define APUTYPE_INPUTMIXER 9 -#define APUTYPE_WAVETABLE 10 -#define APUTYPE_RATECONV 11 -#define APUTYPE_16BITPINGPONG 12 -/* APU type 13 through 15 are reserved. */ - -/* Filter types */ -#define APU_FILTERTYPE_SHIFT 2 - -#define FILTERTYPE_2POLE_LOPASS 0 -#define FILTERTYPE_2POLE_BANDPASS 1 -#define FILTERTYPE_2POLE_HIPASS 2 -#define FILTERTYPE_1POLE_LOPASS 3 -#define FILTERTYPE_1POLE_HIPASS 4 -#define FILTERTYPE_PASSTHROUGH 5 - -/* Filter Q */ -#define APU_FILTERQ_SHIFT 0 - -#define FILTERQ_LESSQ 0 -#define FILTERQ_MOREQ 3 - -/* APU register 2 */ -#define APUREG_FREQ_LOBYTE 2 -#define APU_FREQ_LOBYTE_MASK 0xff00 -#define APU_plus6dB 0x0010 - -/* APU register 3 */ -#define APUREG_FREQ_HIWORD 3 -#define APU_FREQ_HIWORD_MASK 0x0fff - -/* Frequency */ -#define APU_FREQ_LOBYTE_SHIFT 8 -#define APU_FREQ_HIWORD_SHIFT 0 -#define FREQ_Hz2DIV(freq) (((u_int64_t)(freq) << 16) / 48000) - -/* APU register 4 */ -#define APUREG_WAVESPACE 4 -#define APU_STEREO 0x8000 -#define APU_USE_SYSMEM 0x4000 -#define APU_PCMBAR_MASK 0x6000 -#define APU_64KPAGE_MASK 0xff00 - -/* PCM Base Address Register selection */ -#define APU_PCMBAR_SHIFT 13 - -/* 64KW (==128KB) Page */ -#define APU_64KPAGE_SHIFT 8 - -/* APU register 5 - 7 */ -#define APUREG_CURPTR 5 -#define APUREG_ENDPTR 6 -#define APUREG_LOOPLEN 7 - -/* APU register 9 */ -#define APUREG_AMPLITUDE 9 -#define APU_AMPLITUDE_NOW_MASK 0xff00 -#define APU_AMPLITUDE_DEST_MASK 0x00ff - -/* Amplitude now? */ -#define APU_AMPLITUDE_NOW_SHIFT 8 - -/* APU register 10 */ -#define APUREG_POSITION 10 -#define APU_RADIUS_MASK 0x00c0 -#define APU_PAN_MASK 0x003f - -/* Radius control. */ -#define APU_RADIUS_SHIFT 6 -#define RADIUS_CENTERCIRCLE 0 -#define RADIUS_MIDDLE 1 -#define RADIUS_OUTSIDE 2 - -/* Polar pan. */ -#define APU_PAN_SHIFT 0 -#define PAN_RIGHT 0x00 -#define PAN_FRONT 0x08 -#define PAN_LEFT 0x10 - - -/* ----------------------------- - * Limits. - */ -#define WPWA_MAX ((1 << 22) - 1) -#define WPWA_MAXADDR ((1 << 23) - 1) -#define MAESTRO_MAXADDR ((1 << 28) - 1) - -#endif /* MAESTRO_REG_H_INCLUDED */ diff --git a/sys/dev/sound/pci/via82c686.c b/sys/dev/sound/pci/via82c686.c deleted file mode 100644 index df721366c3cf..000000000000 --- a/sys/dev/sound/pci/via82c686.c +++ /dev/null @@ -1,689 +0,0 @@ -/* - * Copyright (c) 2000 David Jones <dej@ox.org> - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. - * - * $FreeBSD$ - */ - -#include <dev/sound/pcm/sound.h> -#include <dev/sound/pcm/ac97.h> - -#include <pci/pcireg.h> -#include <pci/pcivar.h> -#include <sys/sysctl.h> - -#include <dev/sound/pci/via82c686.h> - -#define VIA_PCI_ID 0x30581106 -#define NSEGS 16 /* Number of segments in SGD table */ - -#define SEGS_PER_CHAN (NSEGS/2) - -#undef DEB -#define DEB(x) - -struct via_info; - -struct via_chinfo { - struct via_info *parent; - pcm_channel *channel; - snd_dbuf *buffer; - int dir; -}; - -struct via_info { - bus_space_tag_t st; - bus_space_handle_t sh; - bus_dma_tag_t parent_dmat; - bus_dma_tag_t sgd_dmat; - - struct resource *reg, *irq; - int regid, irqid; - void *ih; - - struct via_chinfo pch, rch; - struct via_dma_op *sgd_table; - u_int16_t codec_caps; -}; - -static u_int32_t via_rd(struct via_info *via, int regno, int size); -static void via_wr(struct via_info *, int regno, u_int32_t data, int size); - -int via_waitready_codec(struct via_info *via); -int via_waitvalid_codec(struct via_info *via); -u_int32_t via_read_codec(void *addr, int reg); -void via_write_codec(void *addr, int reg, u_int32_t val); - -static void via_intr(void *); -bus_dmamap_callback_t dma_cb; - - -/* channel interface */ -static void *viachan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir); -static int viachan_setdir(void *data, int dir); -static int viachan_setformat(void *data, u_int32_t format); -static int viachan_setspeed(void *data, u_int32_t speed); -static int viachan_setblocksize(void *data, u_int32_t blocksize); -static int viachan_trigger(void *data, int go); -static int viachan_getptr(void *data); -static pcmchan_caps *viachan_getcaps(void *data); - -static u_int32_t via_playfmt[] = { - AFMT_U8, - AFMT_STEREO | AFMT_U8, - AFMT_S16_LE, - AFMT_STEREO | AFMT_S16_LE, - 0 -}; -static pcmchan_caps via_playcaps = {4000, 48000, via_playfmt, 0}; - -static u_int32_t via_recfmt[] = { - AFMT_U8, - AFMT_STEREO | AFMT_U8, - AFMT_S16_LE, - AFMT_STEREO | AFMT_S16_LE, - 0 -}; -static pcmchan_caps via_reccaps = {4000, 48000, via_recfmt, 0}; - -static pcm_channel via_chantemplate = { - viachan_init, - viachan_setdir, - viachan_setformat, - viachan_setspeed, - viachan_setblocksize, - viachan_trigger, - viachan_getptr, - viachan_getcaps, - NULL, /* free */ - NULL, /* nop1 */ - NULL, /* nop2 */ - NULL, /* nop3 */ - NULL, /* nop4 */ - NULL, /* nop5 */ - NULL, /* nop6 */ - NULL, /* nop7 */ -}; - - -/* - * Probe and attach the card - */ -static int -via_probe(device_t dev) -{ - if (pci_get_devid(dev) == VIA_PCI_ID) { - device_set_desc(dev, "VIA VT82C686A AC'97 Audio"); - return 0; - } - return ENXIO; -} - - -void dma_cb(void *p, bus_dma_segment_t *bds, int a, int b) -{ -} - - -static int -via_attach(device_t dev) -{ - struct via_info *via = 0; - struct ac97_info *codec = 0; - char status[SND_STATUSLEN]; - - u_int32_t data; - - u_int16_t v; - bus_dmamap_t sgd_dma_map; - - if ((via = malloc(sizeof *via, M_DEVBUF, M_NOWAIT)) == NULL) { - device_printf(dev, "cannot allocate softc\n"); - return ENXIO; - } - bzero(via, sizeof *via); - - /* Get resources */ - data = pci_read_config(dev, PCIR_COMMAND, 2); - data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN); - pci_write_config(dev, PCIR_COMMAND, data, 2); - data = pci_read_config(dev, PCIR_COMMAND, 2); - - pci_write_config(dev, VIA_PCICONF_MISC, - VIA_PCICONF_ACLINKENAB | VIA_PCICONF_ACSGD | - VIA_PCICONF_ACNOTRST | VIA_PCICONF_ACVSR, 1); - - via->regid = PCIR_MAPS; - via->reg = bus_alloc_resource(dev, SYS_RES_IOPORT, &via->regid, - 0, ~0, 1, RF_ACTIVE); - if (!via->reg) { - device_printf(dev, "via: Cannot allocate bus resource."); - goto bad; - } - via->st = rman_get_bustag(via->reg); - via->sh = rman_get_bushandle(via->reg); - - via->irqid = 0; - via->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &via->irqid, - 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); - if (!via->irq - || bus_setup_intr(dev, via->irq, INTR_TYPE_TTY, via_intr, via, &via->ih)){ - device_printf(dev, "unable to map interrupt\n"); - goto bad; - } - - via_wr(via, VIA_PLAY_MODE, - VIA_RPMODE_AUTOSTART | - VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1); - via_wr(via, VIA_RECORD_MODE, - VIA_RPMODE_AUTOSTART | - VIA_RPMODE_INTR_FLAG | VIA_RPMODE_INTR_EOL, 1); - - codec = ac97_create(dev, via, NULL, - via_read_codec, via_write_codec); - if (!codec) goto bad; - - mixer_init(dev, &ac97_mixer, codec); - - /* - * The mixer init resets the codec. So enabling VRA must be done - * afterwards. - */ - v = via_read_codec(via, AC97_REG_EXT_AUDIO_ID); - v &= (AC97_ENAB_VRA | AC97_ENAB_MICVRA); - via_write_codec(via, AC97_REG_EXT_AUDIO_STAT, v); - via->codec_caps = v; - { - v = via_read_codec(via, AC97_REG_EXT_AUDIO_STAT); - DEB(printf("init: codec stat: %d\n", v)); - } - - if (!(v & AC97_CODEC_DOES_VRA)) { - /* no VRA => can do only 48 kbps */ - via_playcaps.minspeed = 48000; - via_reccaps.minspeed = 48000; - } - - /* DMA tag for buffers */ - if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - /*maxsize*/VIA_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff, - /*flags*/0, &via->parent_dmat) != 0) { - device_printf(dev, "unable to create dma tag\n"); - goto bad; - } - - /* - * DMA tag for SGD table. The 686 uses scatter/gather DMA and - * requires a list in memory of work to do. We need only 16 bytes - * for this list, and it is wasteful to allocate 16K. - */ - if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - /*maxsize*/NSEGS * sizeof(struct via_dma_op), - /*nsegments*/1, /*maxsegz*/0x3ffff, - /*flags*/0, &via->sgd_dmat) != 0) { - device_printf(dev, "unable to create dma tag\n"); - goto bad; - } - - if (bus_dmamem_alloc(via->sgd_dmat, (void **)&via->sgd_table, - BUS_DMA_NOWAIT, &sgd_dma_map) == -1) goto bad; - if (bus_dmamap_load(via->sgd_dmat, sgd_dma_map, via->sgd_table, - NSEGS * sizeof(struct via_dma_op), dma_cb, 0, 0)) goto bad; - - snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld", - rman_get_start(via->reg), rman_get_start(via->irq)); - - /* Register */ - if (pcm_register(dev, via, 1, 1)) goto bad; - pcm_addchan(dev, PCMDIR_PLAY, &via_chantemplate, via); - pcm_addchan(dev, PCMDIR_REC, &via_chantemplate, via); - pcm_setstatus(dev, status); - return 0; -bad: - if (codec) ac97_destroy(codec); - if (via->reg) bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg); - if (via->ih) bus_teardown_intr(dev, via->irq, via->ih); - if (via->irq) bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq); - if (via->parent_dmat) bus_dma_tag_destroy(via->parent_dmat); - if (via->sgd_dmat) bus_dma_tag_destroy(via->sgd_dmat); - if (via) free(via, M_DEVBUF); - return ENXIO; -} - -static int -via_detach(device_t dev) -{ - int r; - struct via_info *via = 0; - - r = pcm_unregister(dev); - if (r) - return r; - - via = pcm_getdevinfo(dev); - bus_release_resource(dev, SYS_RES_IOPORT, via->regid, via->reg); - bus_teardown_intr(dev, via->irq, via->ih); - bus_release_resource(dev, SYS_RES_IRQ, via->irqid, via->irq); - bus_dma_tag_destroy(via->parent_dmat); - bus_dma_tag_destroy(via->sgd_dmat); - free(via, M_DEVBUF); - return 0; -} - - -static device_method_t via_methods[] = { - DEVMETHOD(device_probe, via_probe), - DEVMETHOD(device_attach, via_attach), - DEVMETHOD(device_detach, via_detach), - { 0, 0} -}; - -static driver_t via_driver = { - "pcm", - via_methods, - sizeof(snddev_info), -}; - -static devclass_t pcm_devclass; - -DRIVER_MODULE(via, pci, via_driver, pcm_devclass, 0, 0); -MODULE_DEPEND(via, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); -MODULE_VERSION(via, 1); - - -static u_int32_t -via_rd(struct via_info *via, int regno, int size) -{ - - switch (size) { - case 1: - return bus_space_read_1(via->st, via->sh, regno); - case 2: - return bus_space_read_2(via->st, via->sh, regno); - case 4: - return bus_space_read_4(via->st, via->sh, regno); - default: - return 0xFFFFFFFF; - } -} - - -static void -via_wr(struct via_info *via, int regno, u_int32_t data, int size) -{ - - switch (size) { - case 1: - bus_space_write_1(via->st, via->sh, regno, data); - break; - case 2: - bus_space_write_2(via->st, via->sh, regno, data); - break; - case 4: - bus_space_write_4(via->st, via->sh, regno, data); - break; - } -} - - -/* Codec interface */ -int -via_waitready_codec(struct via_info *via) -{ - int i; - - /* poll until codec not busy */ - for (i = 0; (i < TIMEOUT) && - (via_rd(via, VIA_CODEC_CTL, 4) & VIA_CODEC_BUSY); i++) - DELAY(1); - if (i >= TIMEOUT) { - printf("via: codec busy\n"); - return 1; - } - - return 0; -} - - -int -via_waitvalid_codec(struct via_info *via) -{ - int i; - - /* poll until codec valid */ - for (i = 0; (i < TIMEOUT) && - !(via_rd(via, VIA_CODEC_CTL, 4) & VIA_CODEC_PRIVALID); i++) - DELAY(1); - if (i >= TIMEOUT) { - printf("via: codec invalid\n"); - return 1; - } - - return 0; -} - - -void -via_write_codec(void *addr, int reg, u_int32_t val) -{ - struct via_info *via = addr; - - if (via_waitready_codec(via)) return; - - via_wr(via, VIA_CODEC_CTL, - VIA_CODEC_PRIVALID | VIA_CODEC_INDEX(reg) | val, 4); -} - - -u_int32_t -via_read_codec(void *addr, int reg) -{ - struct via_info *via = addr; - - if (via_waitready_codec(via)) - return 1; - - via_wr(via, VIA_CODEC_CTL, - VIA_CODEC_PRIVALID | VIA_CODEC_READ | VIA_CODEC_INDEX(reg),4); - - if (via_waitready_codec(via)) - return 1; - - if (via_waitvalid_codec(via)) - return 1; - - return via_rd(via, VIA_CODEC_CTL, 2); -} - - -/* channel interface */ -static void * -viachan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) -{ - struct via_info *via = devinfo; - struct via_chinfo *ch = (dir == PCMDIR_PLAY) ? &via->pch : &via->rch; - - ch->parent = via; - ch->channel = c; - ch->buffer = b; - b->bufsize = VIA_BUFFSIZE; - - if (chn_allocbuf(ch->buffer, via->parent_dmat) == -1) return NULL; - return ch; -} - -static int -viachan_setdir(void *data, int dir) -{ - struct via_chinfo *ch = data; - struct via_info *via = ch->parent; - struct via_dma_op *ado; - int i, chunk_size; - int phys_addr, flag; - - ch->dir = dir; - /* - * Build the scatter/gather DMA (SGD) table. - * There are four slots in the table: two for play, two for record. - * This creates two half-buffers, one of which is playing; the other - * is feeding. - */ - ado = via->sgd_table; - chunk_size = ch->buffer->bufsize / SEGS_PER_CHAN; - - if (dir == PCMDIR_REC) { - ado += SEGS_PER_CHAN; - } - -DEB(printf("SGD table located at va %p\n", ado)); - phys_addr = vtophys(ch->buffer->buf); - for (i = 0; i < SEGS_PER_CHAN; i++) { - ado->ptr = phys_addr; - flag = (i == SEGS_PER_CHAN-1) ? - VIA_DMAOP_EOL : VIA_DMAOP_FLAG; - ado->flags = flag | chunk_size; -DEB(printf("ado->ptr/flags = %x/%x\n", phys_addr, flag)); - phys_addr += chunk_size; - ado++; - } - return 0; -} - -static int -viachan_setformat(void *data, u_int32_t format) -{ - struct via_chinfo *ch = data; - struct via_info *via = ch->parent; - int mode, mode_set; - - mode_set = 0; - if (format & AFMT_STEREO) - mode_set |= VIA_RPMODE_STEREO; - if (format & AFMT_S16_LE) - mode_set |= VIA_RPMODE_16BIT; - - /* Set up for output format */ - if (ch->dir == PCMDIR_PLAY) { -DEB(printf("set play format: %x\n", format)); - mode = via_rd(via, VIA_PLAY_MODE, 1); - mode &= ~(VIA_RPMODE_16BIT | VIA_RPMODE_STEREO); - mode |= mode_set; - via_wr(via, VIA_PLAY_MODE, mode, 1); - } - else { -DEB(printf("set record format: %x\n", format)); - mode = via_rd(via, VIA_RECORD_MODE, 1); - mode &= ~(VIA_RPMODE_16BIT | VIA_RPMODE_STEREO); - mode |= mode_set; - via_wr(via, VIA_RECORD_MODE, mode, 1); - } - - return 0; -} - -static int -viachan_setspeed(void *data, u_int32_t speed) -{ - struct via_chinfo *ch = data; - struct via_info *via = ch->parent; - - /* - * Basic AC'97 defines a 48 kHz sample rate only. For other rates, - * upsampling is required. - * - * The VT82C686A does not perform upsampling, and neither do we. - * If the codec supports variable-rate audio (i.e. does the upsampling - * itself), then negotiate the rate with the codec. Otherwise, - * return 48 kHz cuz that's all you got. - */ - if (ch->dir == PCMDIR_PLAY) { -DEB(printf("requested play speed: %d\n", speed)); - if (via->codec_caps & AC97_CODEC_DOES_VRA) { - via_write_codec(via, AC97_REG_EXT_DAC_RATE, speed); - speed = via_read_codec(via, AC97_REG_EXT_DAC_RATE); - } - else { -DEB(printf("VRA not supported!\n")); - speed = 48000; - } -DEB(printf("obtained play speed: %d\n", speed)); - } - else { -DEB(printf("requested record speed: %d\n", speed)); - if (via->codec_caps & AC97_CODEC_DOES_VRA) { - via_write_codec(via, AC97_REG_EXT_ADC_RATE, speed); - speed = via_read_codec(via, AC97_REG_EXT_ADC_RATE); - } - else { -DEB(printf("VRA not supported!\n")); - speed = 48000; - } -DEB(printf("obtained record speed: %d\n", speed)); - } - return speed; -} - -static int -viachan_setblocksize(void *data, u_int32_t blocksize) -{ - struct via_chinfo *ch = data; - - return ch->buffer->bufsize / 2; -} - -static int -viachan_trigger(void *data, int go) -{ - struct via_chinfo *ch = data; - struct via_info *via = ch->parent; - struct via_dma_op *ado; - - if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) return 0; - if (ch->dir == PCMDIR_PLAY) { - if (go == PCMTRIG_START) { - ado = &via->sgd_table[0]; -DEB(printf("ado located at va=%p pa=%x\n", ado, vtophys(ado))); - via_wr(via, VIA_PLAY_DMAOPS_BASE, vtophys(ado),4); - via_wr(via, VIA_PLAY_CONTROL, - VIA_RPCTRL_START, 1); - } - else { - /* Stop DMA */ - via_wr(via, VIA_PLAY_CONTROL, - VIA_RPCTRL_TERMINATE, 1); - } - } else { - if (go == PCMTRIG_START) { - ado = &via->sgd_table[SEGS_PER_CHAN]; -DEB(printf("ado located at va=%p pa=%x\n", ado, vtophys(ado))); - via_wr(via, VIA_RECORD_DMAOPS_BASE, - vtophys(ado),4); - via_wr(via, VIA_RECORD_CONTROL, - VIA_RPCTRL_START, 1); - } - else { - /* Stop DMA */ - via_wr(via, VIA_RECORD_CONTROL, - VIA_RPCTRL_TERMINATE, 1); - } - } - -DEB(printf("viachan_trigger: go=%d\n", go)); - return 0; -} - -static int -viachan_getptr(void *data) -{ - struct via_chinfo *ch = data; - struct via_info *via = ch->parent; - struct via_dma_op *ado; - int ptr, base, len, seg; - int base1; - - if (ch->dir == PCMDIR_PLAY) { - ado = &via->sgd_table[0]; - base1 = via_rd(via, VIA_PLAY_DMAOPS_BASE, 4); - len = via_rd(via, VIA_PLAY_DMAOPS_COUNT, 4); - base = via_rd(via, VIA_PLAY_DMAOPS_BASE, 4); - if (base != base1) { /* Avoid race hazzard */ - len = via_rd(via, VIA_PLAY_DMAOPS_COUNT, 4); - } -DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base)); - - /* Base points to SGD segment to do, one past current */ - - /* Determine how many segments have been done */ - seg = (base - vtophys(ado)) / sizeof(struct via_dma_op); - if (seg == 0) seg = SEGS_PER_CHAN; - - /* Now work out offset: seg less count */ - ptr = seg * ch->buffer->bufsize / SEGS_PER_CHAN - len; -DEB(printf("return ptr=%d\n", ptr)); - return ptr; - } - else { - base1 = via_rd(via, VIA_RECORD_DMAOPS_BASE, 4); - ado = &via->sgd_table[SEGS_PER_CHAN]; - len = via_rd(via, VIA_RECORD_DMAOPS_COUNT, 4); - base = via_rd(via, VIA_RECORD_DMAOPS_BASE, 4); - if (base != base1) { /* Avoid race hazzard */ - len = via_rd(via, VIA_RECORD_DMAOPS_COUNT, 4); - } -DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base)); - - /* Base points to next block to do, one past current */ - - /* Determine how many segments have been done */ - seg = (base - vtophys(ado)) / sizeof(struct via_dma_op); - if (seg == 0) seg = SEGS_PER_CHAN; - - /* Now work out offset: seg less count */ - ptr = seg * ch->buffer->bufsize / SEGS_PER_CHAN - len; - - /* DMA appears to operate on memory 'lines' of 32 bytes */ - /* so don't return any part line - it isn't in RAM yet */ - ptr = ptr & ~0x1f; -DEB(printf("return ptr=%d\n", ptr)); - return ptr; - } - return 0; -} - -static pcmchan_caps * -viachan_getcaps(void *data) -{ - struct via_chinfo *ch = data; - return (ch->dir == PCMDIR_PLAY) ? &via_playcaps : &via_reccaps; -} - -static void -via_intr(void *p) -{ - struct via_info *via = p; - int st; - -DEB(printf("viachan_intr\n")); - /* Read channel */ - st = via_rd(via, VIA_PLAY_STAT, 1); - if (st & VIA_RPSTAT_INTR) { - via_wr(via, VIA_PLAY_STAT, VIA_RPSTAT_INTR, 1); - chn_intr(via->pch.channel); - } - - /* Write channel */ - st = via_rd(via, VIA_RECORD_STAT, 1); - if (st & VIA_RPSTAT_INTR) { - via_wr(via, VIA_RECORD_STAT, VIA_RPSTAT_INTR, 1); - chn_intr(via->rch.channel); - } -} - - diff --git a/sys/dev/sound/pci/via82c686.h b/sys/dev/sound/pci/via82c686.h deleted file mode 100644 index 1d85c9b14898..000000000000 --- a/sys/dev/sound/pci/via82c686.h +++ /dev/null @@ -1,108 +0,0 @@ -/*- - * Copyright (c) 2000 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Tyler C. Sarna. - * - * 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 NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. - * - * $FreeBSD$ - */ - -#ifndef _VIA_H -#define _VIA_H - -/* - * VIA Technologies VT82C686A Southbridge Audio Driver - * - * Documentation links: - * - * ftp://ftp.alsa-project.org/pub/manuals/via/686a.pdf - * ftp://ftp.alsa-project.org/pub/manuals/general/ac97r21.pdf - * ftp://ftp.alsa-project.org/pub/manuals/ad/AD1881_0.pdf (example AC'97 codec) - */ - -struct via_dma_op { - u_int32_t ptr; - u_int32_t flags; -#define VIA_DMAOP_EOL 0x80000000 -#define VIA_DMAOP_FLAG 0x40000000 -#define VIA_DMAOP_STOP 0x20000000 -#define VIA_DMAOP_COUNT(x) ((x)&0x00FFFFFF) -}; - -#define VIA_PCICONF_MISC 0x41 -#define VIA_PCICONF_ACLINKENAB 0x80 /* ac link enab */ -#define VIA_PCICONF_ACNOTRST 0x40 /* ~(ac reset) */ -#define VIA_PCICONF_ACSYNC 0x20 /* ac sync */ -#define VIA_PCICONF_ACVSR 0x08 /* var. samp. rate */ -#define VIA_PCICONF_ACSGD 0x04 /* SGD enab */ -#define VIA_PCICONF_ACFM 0x02 /* FM enab */ -#define VIA_PCICONF_ACSB 0x01 /* SB enab */ -#define VIA_PCICONF_FUNC_EN 0x42 - -#define VIA_PLAY_STAT 0x00 -#define VIA_RECORD_STAT 0x10 -#define VIA_RPSTAT_INTR 0x03 -#define VIA_PLAY_CONTROL 0x01 -#define VIA_RECORD_CONTROL 0x11 -#define VIA_RPCTRL_START 0x80 -#define VIA_RPCTRL_TERMINATE 0x40 -#define VIA_PLAY_MODE 0x02 -#define VIA_RECORD_MODE 0x12 -#define VIA_RPMODE_INTR_FLAG 0x01 -#define VIA_RPMODE_INTR_EOL 0x02 -#define VIA_RPMODE_STEREO 0x10 -#define VIA_RPMODE_16BIT 0x20 -#define VIA_RPMODE_AUTOSTART 0x80 -#define VIA_PLAY_DMAOPS_BASE 0x04 -#define VIA_RECORD_DMAOPS_BASE 0x14 -#define VIA_PLAY_DMAOPS_COUNT 0x0C -#define VIA_RECORD_DMAOPS_COUNT 0x1C - -#define VIA_CODEC_CTL 0x80 -#define VIA_CODEC_READ 0x00800000 -#define VIA_CODEC_BUSY 0x01000000 -#define VIA_CODEC_PRIVALID 0x02000000 -#define VIA_CODEC_INDEX(x) ((x)<<16) - -#define AC97_REG_EXT_AUDIO_ID 0x28 -#define AC97_CODEC_DOES_VRA 0x0001 -#define AC97_CODEC_DOES_MICVRA 0x0008 -#define AC97_REG_EXT_AUDIO_STAT 0x2A -#define AC97_ENAB_VRA 0x0001 -#define AC97_ENAB_MICVRA 0x0008 -#define AC97_REG_EXT_DAC_RATE 0x2C -#define AC97_REG_EXT_ADC_RATE 0x32 - -#define TIMEOUT 50 -#define VIA_BUFFSIZE 0x4000 - -#endif /* _VIA_H */ |
