1139749Simp/*- 2119853Scg * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 350724Scg * All rights reserved. 450724Scg * 550724Scg * Redistribution and use in source and binary forms, with or without 650724Scg * modification, are permitted provided that the following conditions 750724Scg * are met: 850724Scg * 1. Redistributions of source code must retain the above copyright 950724Scg * notice, this list of conditions and the following disclaimer. 1050724Scg * 2. Redistributions in binary form must reproduce the above copyright 1150724Scg * notice, this list of conditions and the following disclaimer in the 1250724Scg * documentation and/or other materials provided with the distribution. 1350724Scg * 1450724Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1550724Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1650724Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1750724Scg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1850724Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1950724Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2050724Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2150724Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2250724Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2350724Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2450724Scg * SUCH DAMAGE. 2550724Scg */ 2650724Scg 27193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 28193640Sariff#include "opt_snd.h" 29193640Sariff#endif 30193640Sariff 3153465Scg#include <dev/sound/pcm/sound.h> 3253465Scg#include <dev/sound/pcm/ac97.h> 3353465Scg#include <dev/sound/pci/aureal.h> 3450724Scg 35119287Simp#include <dev/pci/pcireg.h> 36119287Simp#include <dev/pci/pcivar.h> 3750724Scg 3882180ScgSND_DECLARE_FILE("$FreeBSD$"); 3982180Scg 4050724Scg/* PCI IDs of supported chips */ 4150724Scg#define AU8820_PCI_ID 0x000112eb 4250724Scg 4350724Scg/* channel interface */ 4464881Scgstatic u_int32_t au_playfmt[] = { 45193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 46193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 47193640Sariff SND_FORMAT(AFMT_S16_LE, 1, 0), 48193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 4964881Scg 0 5050724Scg}; 5174763Scgstatic struct pcmchan_caps au_playcaps = {4000, 48000, au_playfmt, 0}; 5250724Scg 5364881Scgstatic u_int32_t au_recfmt[] = { 54193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 55193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 56193640Sariff SND_FORMAT(AFMT_S16_LE, 1, 0), 57193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 5864881Scg 0 5950724Scg}; 6074763Scgstatic struct pcmchan_caps au_reccaps = {4000, 48000, au_recfmt, 0}; 6150724Scg 6250724Scg/* -------------------------------------------------------------------- */ 6350724Scg 6450724Scgstruct au_info; 6550724Scg 6650724Scgstruct au_chinfo { 6750724Scg struct au_info *parent; 6874763Scg struct pcm_channel *channel; 6974763Scg struct snd_dbuf *buffer; 7050724Scg int dir; 7150724Scg}; 7250724Scg 7350724Scgstruct au_info { 7450724Scg int unit; 7550724Scg 7650724Scg bus_space_tag_t st[3]; 7750724Scg bus_space_handle_t sh[3]; 7850724Scg 7950724Scg bus_dma_tag_t parent_dmat; 80107285Scg struct mtx *lock; 8150724Scg 8250724Scg u_int32_t x[32], y[128]; 8350724Scg char z[128]; 8450724Scg u_int32_t routes[4], interrupts; 8550724Scg struct au_chinfo pch; 8650724Scg}; 8750724Scg 8850724Scgstatic int au_init(device_t dev, struct au_info *au); 8950724Scgstatic void au_intr(void *); 9050724Scg 9150724Scg/* -------------------------------------------------------------------- */ 9250724Scg 9350724Scgstatic u_int32_t 9450724Scgau_rd(struct au_info *au, int mapno, int regno, int size) 9550724Scg{ 9650724Scg switch(size) { 9750724Scg case 1: 9850724Scg return bus_space_read_1(au->st[mapno], au->sh[mapno], regno); 9950724Scg case 2: 10050724Scg return bus_space_read_2(au->st[mapno], au->sh[mapno], regno); 10150724Scg case 4: 10250724Scg return bus_space_read_4(au->st[mapno], au->sh[mapno], regno); 10350724Scg default: 10450724Scg return 0xffffffff; 10550724Scg } 10650724Scg} 10750724Scg 10850724Scgstatic void 10950724Scgau_wr(struct au_info *au, int mapno, int regno, u_int32_t data, int size) 11050724Scg{ 11150724Scg switch(size) { 11250724Scg case 1: 11350724Scg bus_space_write_1(au->st[mapno], au->sh[mapno], regno, data); 11450724Scg break; 11550724Scg case 2: 11650724Scg bus_space_write_2(au->st[mapno], au->sh[mapno], regno, data); 11750724Scg break; 11850724Scg case 4: 11950724Scg bus_space_write_4(au->st[mapno], au->sh[mapno], regno, data); 12050724Scg break; 12150724Scg } 12250724Scg} 12350724Scg 12470134Scg/* -------------------------------------------------------------------- */ 12570134Scg 12670134Scgstatic int 12770134Scgau_rdcd(kobj_t obj, void *arg, int regno) 12850724Scg{ 12950724Scg struct au_info *au = (struct au_info *)arg; 13050724Scg int i=0, j=0; 13150724Scg 13250724Scg regno<<=16; 13350724Scg au_wr(au, 0, AU_REG_CODECIO, regno, 4); 13450724Scg while (j<50) { 13550724Scg i=au_rd(au, 0, AU_REG_CODECIO, 4); 13650724Scg if ((i & 0x00ff0000) == (regno | 0x00800000)) break; 13750724Scg DELAY(j * 200 + 2000); 13850724Scg j++; 13950724Scg } 14050724Scg if (j==50) printf("pcm%d: codec timeout reading register %x (%x)\n", 14150724Scg au->unit, (regno & AU_CDC_REGMASK)>>16, i); 14250724Scg return i & AU_CDC_DATAMASK; 14350724Scg} 14450724Scg 14570134Scgstatic int 14670134Scgau_wrcd(kobj_t obj, void *arg, int regno, u_int32_t data) 14750724Scg{ 14850724Scg struct au_info *au = (struct au_info *)arg; 14950724Scg int i, j, tries; 15050724Scg i=j=tries=0; 15150724Scg do { 15250724Scg while (j<50 && (i & AU_CDC_WROK) == 0) { 15350724Scg i=au_rd(au, 0, AU_REG_CODECST, 4); 15450724Scg DELAY(2000); 15550724Scg j++; 15650724Scg } 15750724Scg if (j==50) printf("codec timeout during write of register %x, data %x\n", 15850724Scg regno, data); 15950724Scg au_wr(au, 0, AU_REG_CODECIO, (regno<<16) | AU_CDC_REGSET | data, 4); 16050724Scg/* DELAY(20000); 16150724Scg i=au_rdcd(au, regno); 16250724Scg*/ tries++; 16350724Scg } while (0); /* (i != data && tries < 3); */ 16450724Scg /* 16550724Scg if (tries == 3) printf("giving up writing 0x%4x to codec reg %2x\n", data, regno); 16650724Scg */ 16770134Scg 16870134Scg return 0; 16950724Scg} 17050724Scg 17170134Scgstatic kobj_method_t au_ac97_methods[] = { 17270134Scg KOBJMETHOD(ac97_read, au_rdcd), 17370134Scg KOBJMETHOD(ac97_write, au_wrcd), 174193640Sariff KOBJMETHOD_END 17570134Scg}; 17670134ScgAC97_DECLARE(au_ac97); 17770134Scg 17870134Scg/* -------------------------------------------------------------------- */ 17970134Scg 18050724Scgstatic void 18150724Scgau_setbit(u_int32_t *p, char bit, u_int32_t value) 18250724Scg{ 18350724Scg p += bit >> 5; 18450724Scg bit &= 0x1f; 18550724Scg *p &= ~ (1 << bit); 18650724Scg *p |= (value << bit); 18750724Scg} 18850724Scg 18950724Scgstatic void 19050724Scgau_addroute(struct au_info *au, int a, int b, int route) 19150724Scg{ 19250724Scg int j = 0x1099c+(a<<2); 19350724Scg if (au->x[a] != a+0x67) j = AU_REG_RTBASE+(au->x[a]<<2); 19450724Scg 19550724Scg au_wr(au, 0, AU_REG_RTBASE+(route<<2), 0xffffffff, 4); 19650724Scg au_wr(au, 0, j, route | (b<<7), 4); 19750724Scg au->y[route]=au->x[a]; 19850724Scg au->x[a]=route; 19950724Scg au->z[route]=a & 0x000000ff; 20050724Scg au_setbit(au->routes, route, 1); 20150724Scg} 20250724Scg 20350724Scgstatic void 20450724Scgau_delroute(struct au_info *au, int route) 20550724Scg{ 20650724Scg int i; 20750724Scg int j=au->z[route]; 20850724Scg 20950724Scg au_setbit(au->routes, route, 0); 21050724Scg au->z[route]=0x1f; 21150724Scg i=au_rd(au, 0, AU_REG_RTBASE+(route<<2), 4); 21250724Scg au_wr(au, 0, AU_REG_RTBASE+(au->y[route]<<2), i, 4); 21350724Scg au->y[i & 0x7f]=au->y[route]; 21450724Scg au_wr(au, 0, AU_REG_RTBASE+(route<<2), 0xfffffffe, 4); 21550724Scg if (au->x[j] == route) au->x[j]=au->y[route]; 21650724Scg au->y[route]=0x7f; 21750724Scg} 21850724Scg 21950724Scgstatic void 22050724Scgau_encodec(struct au_info *au, char channel) 22150724Scg{ 22250724Scg au_wr(au, 0, AU_REG_CODECEN, 22350724Scg au_rd(au, 0, AU_REG_CODECEN, 4) | (1 << (channel + 8)), 4); 22450724Scg} 22550724Scg 22650724Scgstatic void 22750724Scgau_clrfifo(struct au_info *au, u_int32_t c) 22850724Scg{ 22950724Scg u_int32_t i; 23050724Scg 23150724Scg for (i=0; i<32; i++) au_wr(au, 0, AU_REG_FIFOBASE+(c<<7)+(i<<2), 0, 4); 23250724Scg} 23350724Scg 23450724Scgstatic void 23550724Scgau_setadb(struct au_info *au, u_int32_t c, u_int32_t enable) 23650724Scg{ 23750724Scg int x; 23850724Scg 23950724Scg x = au_rd(au, 0, AU_REG_ADB, 4); 24050724Scg x &= ~(1 << c); 24150724Scg x |= (enable << c); 24250724Scg au_wr(au, 0, AU_REG_ADB, x, 4); 24350724Scg} 24450724Scg 24550724Scgstatic void 24650724Scgau_prepareoutput(struct au_chinfo *ch, u_int32_t format) 24750724Scg{ 24850724Scg struct au_info *au = ch->parent; 249193640Sariff int i, stereo = (AFMT_CHANNEL(format) > 1)? 1 : 0; 250111183Scognet u_int32_t baseaddr = sndbuf_getbufaddr(ch->buffer); 25150724Scg 25250724Scg au_wr(au, 0, 0x1061c, 0, 4); 25350724Scg au_wr(au, 0, 0x10620, 0, 4); 25450724Scg au_wr(au, 0, 0x10624, 0, 4); 255193640Sariff switch(AFMT_ENCODING(format)) { 25650724Scg case 1: 25750724Scg i=0xb000; 25850724Scg break; 25950724Scg case 2: 26050724Scg i=0xf000; 26150724Scg break; 26250724Scg case 8: 26350724Scg i=0x7000; 26450724Scg break; 26550724Scg case 16: 26650724Scg i=0x23000; 26750724Scg break; 26850724Scg default: 26950724Scg i=0x3000; 27050724Scg } 27150724Scg au_wr(au, 0, 0x10200, baseaddr, 4); 27250724Scg au_wr(au, 0, 0x10204, baseaddr+0x1000, 4); 27350724Scg au_wr(au, 0, 0x10208, baseaddr+0x2000, 4); 27450724Scg au_wr(au, 0, 0x1020c, baseaddr+0x3000, 4); 27550724Scg 27650724Scg au_wr(au, 0, 0x10400, 0xdeffffff, 4); 27750724Scg au_wr(au, 0, 0x10404, 0xfcffffff, 4); 27850724Scg 27950724Scg au_wr(au, 0, 0x10580, i, 4); 28050724Scg 28150724Scg au_wr(au, 0, 0x10210, baseaddr, 4); 28250724Scg au_wr(au, 0, 0x10214, baseaddr+0x1000, 4); 28350724Scg au_wr(au, 0, 0x10218, baseaddr+0x2000, 4); 28450724Scg au_wr(au, 0, 0x1021c, baseaddr+0x3000, 4); 28550724Scg 28650724Scg au_wr(au, 0, 0x10408, 0x00fff000 | 0x56000000 | 0x00000fff, 4); 28750724Scg au_wr(au, 0, 0x1040c, 0x00fff000 | 0x74000000 | 0x00000fff, 4); 28850724Scg 28950724Scg au_wr(au, 0, 0x10584, i, 4); 29050724Scg 29150724Scg au_wr(au, 0, 0x0f800, stereo? 0x00030032 : 0x00030030, 4); 29250724Scg au_wr(au, 0, 0x0f804, stereo? 0x00030032 : 0x00030030, 4); 29350724Scg 29450724Scg au_addroute(au, 0x11, 0, 0x58); 29550724Scg au_addroute(au, 0x11, stereo? 0 : 1, 0x59); 29650724Scg} 29750724Scg 29870134Scg/* -------------------------------------------------------------------- */ 29950724Scg/* channel interface */ 30050724Scgstatic void * 30174763Scgauchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 30250724Scg{ 30350724Scg struct au_info *au = devinfo; 30450724Scg struct au_chinfo *ch = (dir == PCMDIR_PLAY)? &au->pch : NULL; 30550724Scg 30650724Scg ch->parent = au; 30750724Scg ch->channel = c; 30850724Scg ch->buffer = b; 30970134Scg ch->dir = dir; 310168847Sariff if (sndbuf_alloc(ch->buffer, au->parent_dmat, 0, AU_BUFFSIZE) != 0) 311136469Syongari return NULL; 31250724Scg return ch; 31350724Scg} 31450724Scg 31550724Scgstatic int 31670134Scgauchan_setformat(kobj_t obj, void *data, u_int32_t format) 31750724Scg{ 31850724Scg struct au_chinfo *ch = data; 31950724Scg 32050724Scg if (ch->dir == PCMDIR_PLAY) au_prepareoutput(ch, format); 32150724Scg return 0; 32250724Scg} 32350724Scg 32450724Scgstatic int 32570134Scgauchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 32650724Scg{ 32750724Scg struct au_chinfo *ch = data; 32850724Scg if (ch->dir == PCMDIR_PLAY) { 32950724Scg } else { 33050724Scg } 33150724Scg return speed; 33250724Scg} 33350724Scg 33450724Scgstatic int 33570134Scgauchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 33650724Scg{ 33750724Scg return blocksize; 33850724Scg} 33950724Scg 34050724Scgstatic int 34170134Scgauchan_trigger(kobj_t obj, void *data, int go) 34250724Scg{ 34350724Scg struct au_chinfo *ch = data; 34450724Scg struct au_info *au = ch->parent; 34560958Scg 346170521Sariff if (!PCMTRIG_COMMON(go)) 34760958Scg return 0; 34860958Scg 34950724Scg if (ch->dir == PCMDIR_PLAY) { 35050724Scg au_setadb(au, 0x11, (go)? 1 : 0); 351170521Sariff if (go != PCMTRIG_START) { 35250724Scg au_wr(au, 0, 0xf800, 0, 4); 35350724Scg au_wr(au, 0, 0xf804, 0, 4); 35450724Scg au_delroute(au, 0x58); 35550724Scg au_delroute(au, 0x59); 35650724Scg } 35750724Scg } else { 35850724Scg } 35950724Scg return 0; 36050724Scg} 36150724Scg 36250724Scgstatic int 36370134Scgauchan_getptr(kobj_t obj, void *data) 36450724Scg{ 36550724Scg struct au_chinfo *ch = data; 36650724Scg struct au_info *au = ch->parent; 36750724Scg if (ch->dir == PCMDIR_PLAY) { 36850724Scg return au_rd(au, 0, AU_REG_UNK2, 4) & (AU_BUFFSIZE-1); 36950724Scg } else { 37050724Scg return 0; 37150724Scg } 37250724Scg} 37350724Scg 37474763Scgstatic struct pcmchan_caps * 37570134Scgauchan_getcaps(kobj_t obj, void *data) 37650724Scg{ 37750724Scg struct au_chinfo *ch = data; 37850724Scg return (ch->dir == PCMDIR_PLAY)? &au_playcaps : &au_reccaps; 37950724Scg} 38050724Scg 38170134Scgstatic kobj_method_t auchan_methods[] = { 38270134Scg KOBJMETHOD(channel_init, auchan_init), 38370134Scg KOBJMETHOD(channel_setformat, auchan_setformat), 38470134Scg KOBJMETHOD(channel_setspeed, auchan_setspeed), 38570134Scg KOBJMETHOD(channel_setblocksize, auchan_setblocksize), 38670134Scg KOBJMETHOD(channel_trigger, auchan_trigger), 38770134Scg KOBJMETHOD(channel_getptr, auchan_getptr), 38870134Scg KOBJMETHOD(channel_getcaps, auchan_getcaps), 389193640Sariff KOBJMETHOD_END 39070134Scg}; 39170134ScgCHANNEL_DECLARE(auchan); 39270134Scg 39370134Scg/* -------------------------------------------------------------------- */ 39450724Scg/* The interrupt handler */ 39550724Scgstatic void 39650724Scgau_intr (void *p) 39750724Scg{ 39850724Scg struct au_info *au = p; 39950724Scg u_int32_t intsrc, i; 40050724Scg 40150724Scg au->interrupts++; 40250724Scg intsrc=au_rd(au, 0, AU_REG_IRQSRC, 4); 40350724Scg printf("pcm%d: interrupt with src %x\n", au->unit, intsrc); 40450724Scg if (intsrc & AU_IRQ_FATAL) printf("pcm%d: fatal error irq\n", au->unit); 40550724Scg if (intsrc & AU_IRQ_PARITY) printf("pcm%d: parity error irq\n", au->unit); 40650724Scg if (intsrc & AU_IRQ_UNKNOWN) { 40750724Scg (void)au_rd(au, 0, AU_REG_UNK1, 4); 40850724Scg au_wr(au, 0, AU_REG_UNK1, 0, 4); 40950724Scg au_wr(au, 0, AU_REG_UNK1, 0x10000, 4); 41050724Scg } 41150724Scg if (intsrc & AU_IRQ_PCMOUT) { 41250724Scg i=au_rd(au, 0, AU_REG_UNK2, 4) & (AU_BUFFSIZE-1); 41350724Scg chn_intr(au->pch.channel); 41450724Scg (void)au_rd(au, 0, AU_REG_UNK3, 4); 41550724Scg (void)au_rd(au, 0, AU_REG_UNK4, 4); 41650724Scg (void)au_rd(au, 0, AU_REG_UNK5, 4); 41750724Scg } 41850724Scg/* don't support midi 41950724Scg if (intsrc & AU_IRQ_MIDI) { 42050724Scg i=au_rd(au, 0, 0x11004, 4); 42150724Scg j=10; 42250724Scg while (i & 0xff) { 42350724Scg if (j-- <= 0) break; 42450724Scg i=au_rd(au, 0, 0x11000, 4); 42550724Scg if ((au->midi_stat & 1) && (au->midi_out)) 42650724Scg au->midi_out(au->midi_devno, i); 42750724Scg i=au_rd(au, 0, 0x11004); 42850724Scg } 42950724Scg } 43050724Scg*/ 43150724Scg au_wr(au, 0, AU_REG_IRQSRC, intsrc & 0x7ff, 4); 43250724Scg au_rd(au, 0, AU_REG_IRQSRC, 4); 43350724Scg} 43450724Scg 43550724Scg 43650724Scg/* -------------------------------------------------------------------- */ 43750724Scg 43850724Scg/* Probe and attach the card */ 43950724Scg 44050724Scgstatic int 44150724Scgau_init(device_t dev, struct au_info *au) 44250724Scg{ 44350724Scg u_int32_t i, j; 44450724Scg 44550724Scg au_wr(au, 0, AU_REG_IRQGLOB, 0xffffffff, 4); 44650724Scg DELAY(100000); 44750724Scg 44850724Scg /* init codec */ 44950724Scg /* cold reset */ 45050724Scg for (i=0; i<32; i++) { 45150724Scg au_wr(au, 0, AU_REG_CODECCHN+(i<<2), 0, 4); 45250724Scg DELAY(10000); 45350724Scg } 45450724Scg if (1) { 45550724Scg au_wr(au, 0, AU_REG_CODECST, 0x8068, 4); 45650724Scg DELAY(10000); 45750724Scg au_wr(au, 0, AU_REG_CODECST, 0x00e8, 4); 45850724Scg DELAY(10000); 45950724Scg } else { 46050724Scg au_wr(au, 0, AU_REG_CODECST, 0x00a8, 4); 46150724Scg DELAY(100000); 46250724Scg au_wr(au, 0, AU_REG_CODECST, 0x80a8, 4); 46350724Scg DELAY(100000); 46450724Scg au_wr(au, 0, AU_REG_CODECST, 0x80e8, 4); 46550724Scg DELAY(100000); 46650724Scg au_wr(au, 0, AU_REG_CODECST, 0x80a8, 4); 46750724Scg DELAY(100000); 46850724Scg au_wr(au, 0, AU_REG_CODECST, 0x00a8, 4); 46950724Scg DELAY(100000); 47050724Scg au_wr(au, 0, AU_REG_CODECST, 0x00e8, 4); 47150724Scg DELAY(100000); 47250724Scg } 47350724Scg 47450724Scg /* init */ 47550724Scg for (i=0; i<32; i++) { 47650724Scg au_wr(au, 0, AU_REG_CODECCHN+(i<<2), 0, 4); 47750724Scg DELAY(10000); 47850724Scg } 47950724Scg au_wr(au, 0, AU_REG_CODECST, 0xe8, 4); 48050724Scg DELAY(10000); 48150724Scg au_wr(au, 0, AU_REG_CODECEN, 0, 4); 48250724Scg 48350724Scg /* setup codec */ 48450724Scg i=j=0; 48550724Scg while (j<100 && (i & AU_CDC_READY)==0) { 48650724Scg i=au_rd(au, 0, AU_REG_CODECST, 4); 48750724Scg DELAY(1000); 48850724Scg j++; 48950724Scg } 49050724Scg if (j==100) device_printf(dev, "codec not ready, status 0x%x\n", i); 49150724Scg 49250724Scg /* init adb */ 49350724Scg /*au->x5c=0;*/ 49450724Scg for (i=0; i<32; i++) au->x[i]=i+0x67; 49550724Scg for (i=0; i<128; i++) au->y[i]=0x7f; 49650724Scg for (i=0; i<128; i++) au->z[i]=0x1f; 49750724Scg au_wr(au, 0, AU_REG_ADB, 0, 4); 49850724Scg for (i=0; i<124; i++) au_wr(au, 0, AU_REG_RTBASE+(i<<2), 0xffffffff, 4); 49950724Scg 50050724Scg /* test */ 50150724Scg i=au_rd(au, 0, 0x107c0, 4); 50250724Scg if (i!=0xdeadbeef) device_printf(dev, "dma check failed: 0x%x\n", i); 50350724Scg 50450724Scg /* install mixer */ 50550724Scg au_wr(au, 0, AU_REG_IRQGLOB, 50650724Scg au_rd(au, 0, AU_REG_IRQGLOB, 4) | AU_IRQ_ENABLE, 4); 50750724Scg /* braindead but it's what the oss/linux driver does 50850724Scg * for (i=0; i<0x80000000; i++) au_wr(au, 0, i<<2, 0, 4); 50950724Scg */ 51050724Scg au->routes[0]=au->routes[1]=au->routes[2]=au->routes[3]=0; 51150724Scg /*au->x1e4=0;*/ 51250724Scg 51350724Scg /* attach channel */ 51450724Scg au_addroute(au, 0x11, 0x48, 0x02); 51550724Scg au_addroute(au, 0x11, 0x49, 0x03); 51650724Scg au_encodec(au, 0); 51750724Scg au_encodec(au, 1); 51850724Scg 51950724Scg for (i=0; i<48; i++) au_wr(au, 0, 0xf800+(i<<2), 0x20, 4); 52050724Scg for (i=2; i<6; i++) au_wr(au, 0, 0xf800+(i<<2), 0, 4); 52150724Scg au_wr(au, 0, 0xf8c0, 0x0843, 4); 52250724Scg for (i=0; i<4; i++) au_clrfifo(au, i); 52350724Scg 52450724Scg return (0); 52550724Scg} 52650724Scg 52750724Scgstatic int 52850724Scgau_testirq(struct au_info *au) 52950724Scg{ 53050724Scg au_wr(au, 0, AU_REG_UNK1, 0x80001000, 4); 53150724Scg au_wr(au, 0, AU_REG_IRQEN, 0x00001030, 4); 53250724Scg au_wr(au, 0, AU_REG_IRQSRC, 0x000007ff, 4); 53350724Scg DELAY(1000000); 53450724Scg if (au->interrupts==0) printf("pcm%d: irq test failed\n", au->unit); 53550724Scg /* this apparently generates an irq */ 53650724Scg return 0; 53750724Scg} 53850724Scg 53950724Scgstatic int 54050724Scgau_pci_probe(device_t dev) 54150724Scg{ 54250724Scg if (pci_get_devid(dev) == AU8820_PCI_ID) { 54350724Scg device_set_desc(dev, "Aureal Vortex 8820"); 544142890Simp return BUS_PROBE_DEFAULT; 54550724Scg } 54650724Scg 54750724Scg return ENXIO; 54850724Scg} 54950724Scg 55050724Scgstatic int 55150724Scgau_pci_attach(device_t dev) 55250724Scg{ 55350724Scg struct au_info *au; 55450724Scg int type[10]; 55550724Scg int regid[10]; 55650724Scg struct resource *reg[10]; 55750724Scg int i, j, mapped = 0; 55850724Scg int irqid; 55950724Scg struct resource *irq = 0; 56050724Scg void *ih = 0; 56150724Scg struct ac97_info *codec; 56250724Scg char status[SND_STATUSLEN]; 56350724Scg 564170873Sariff au = malloc(sizeof(*au), M_DEVBUF, M_WAITOK | M_ZERO); 56550724Scg au->unit = device_get_unit(dev); 56650724Scg 567254263Sscottl pci_enable_busmaster(dev); 56850724Scg 56950724Scg j=0; 57050724Scg /* XXX dfr: is this strictly necessary? */ 57150724Scg for (i=0; i<PCI_MAXMAPS_0; i++) { 57250724Scg#if 0 57350724Scg /* Slapped wrist: config_id and map are private structures */ 57450724Scg if (bootverbose) { 57550724Scg printf("pcm%d: map %d - allocating ", unit, i+1); 57650724Scg printf("0x%x bytes of ", 1<<config_id->map[i].ln2size); 57750724Scg printf("%s space ", (config_id->map[i].type & PCI_MAPPORT)? 57850724Scg "io" : "memory"); 57950724Scg printf("at 0x%x...", config_id->map[i].base); 58050724Scg } 58150724Scg#endif 582119690Sjhb regid[j] = PCIR_BAR(i); 58350724Scg type[j] = SYS_RES_MEMORY; 584127135Snjl reg[j] = bus_alloc_resource_any(dev, type[j], ®id[j], 585127135Snjl RF_ACTIVE); 58650724Scg if (!reg[j]) { 58750724Scg type[j] = SYS_RES_IOPORT; 588127135Snjl reg[j] = bus_alloc_resource_any(dev, type[j], 589127135Snjl ®id[j], RF_ACTIVE); 59050724Scg } 59150724Scg if (reg[j]) { 59250724Scg au->st[i] = rman_get_bustag(reg[j]); 59350724Scg au->sh[i] = rman_get_bushandle(reg[j]); 59450724Scg mapped++; 59550724Scg } 59650724Scg#if 0 59750724Scg if (bootverbose) printf("%s\n", mapped? "ok" : "failed"); 59850724Scg#endif 59950724Scg if (mapped) j++; 60050724Scg if (j == 10) { 60150724Scg /* XXX */ 60250724Scg device_printf(dev, "too many resources"); 60350724Scg goto bad; 60450724Scg } 60550724Scg } 60650724Scg 60750724Scg#if 0 60850724Scg if (j < config_id->nummaps) { 60950724Scg printf("pcm%d: unable to map a required resource\n", unit); 61050724Scg free(au, M_DEVBUF); 61150724Scg return; 61250724Scg } 61350724Scg#endif 61450724Scg 61550724Scg au_wr(au, 0, AU_REG_IRQEN, 0, 4); 61650724Scg 61750724Scg irqid = 0; 618127135Snjl irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &irqid, 619127135Snjl RF_ACTIVE | RF_SHAREABLE); 62074763Scg if (!irq || snd_setup_intr(dev, irq, 0, au_intr, au, &ih)) { 62150724Scg device_printf(dev, "unable to map interrupt\n"); 62250724Scg goto bad; 62350724Scg } 62450724Scg 62550724Scg if (au_testirq(au)) device_printf(dev, "irq test failed\n"); 62650724Scg 62750724Scg if (au_init(dev, au) == -1) { 62850724Scg device_printf(dev, "unable to initialize the card\n"); 62950724Scg goto bad; 63050724Scg } 63150724Scg 63270134Scg codec = AC97_CREATE(dev, au, au_ac97); 63350724Scg if (codec == NULL) goto bad; 63470134Scg if (mixer_init(dev, ac97_getmixerclass(), codec) == -1) goto bad; 63550724Scg 636166904Snetchild if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 637166904Snetchild /*boundary*/0, 63850724Scg /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 63950724Scg /*highaddr*/BUS_SPACE_MAXADDR, 64050724Scg /*filter*/NULL, /*filterarg*/NULL, 64150724Scg /*maxsize*/AU_BUFFSIZE, /*nsegments*/1, /*maxsegz*/0x3ffff, 642117126Sscottl /*flags*/0, /*lockfunc*/busdma_lock_mutex, 643117126Sscottl /*lockarg*/&Giant, &au->parent_dmat) != 0) { 64450724Scg device_printf(dev, "unable to create dma tag\n"); 64550724Scg goto bad; 64650724Scg } 64750724Scg 648126695Smatk snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s", 64950724Scg (type[0] == SYS_RES_IOPORT)? "io" : "memory", 650126695Smatk rman_get_start(reg[0]), rman_get_start(irq),PCM_KLDSTRING(snd_aureal)); 65150724Scg 65250724Scg if (pcm_register(dev, au, 1, 1)) goto bad; 65350724Scg /* pcm_addchan(dev, PCMDIR_REC, &au_chantemplate, au); */ 65470134Scg pcm_addchan(dev, PCMDIR_PLAY, &auchan_class, au); 65550724Scg pcm_setstatus(dev, status); 65650724Scg 65750724Scg return 0; 65850724Scg 65950724Scg bad: 66050724Scg if (au) free(au, M_DEVBUF); 66150724Scg for (i = 0; i < j; i++) 66250724Scg bus_release_resource(dev, type[i], regid[i], reg[i]); 66350724Scg if (ih) bus_teardown_intr(dev, irq, ih); 66450724Scg if (irq) bus_release_resource(dev, SYS_RES_IRQ, irqid, irq); 66550724Scg return ENXIO; 66650724Scg} 66750724Scg 66850724Scgstatic device_method_t au_methods[] = { 66950724Scg /* Device interface */ 67050724Scg DEVMETHOD(device_probe, au_pci_probe), 67150724Scg DEVMETHOD(device_attach, au_pci_attach), 67250724Scg 67350724Scg { 0, 0 } 67450724Scg}; 67550724Scg 67650724Scgstatic driver_t au_driver = { 67750724Scg "pcm", 67850724Scg au_methods, 67982180Scg PCM_SOFTC_SIZE, 68050724Scg}; 68150724Scg 68262483ScgDRIVER_MODULE(snd_aureal, pci, au_driver, pcm_devclass, 0, 0); 683132236StanimuraMODULE_DEPEND(snd_aureal, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 68462483ScgMODULE_VERSION(snd_aureal, 1); 685