cs4281.c revision 119690
172017Scg/* 272017Scg * Copyright (c) 2000 Orion Hodson <O.Hodson@cs.ucl.ac.uk> 372017Scg * All rights reserved. 472017Scg * 572017Scg * Redistribution and use in source and binary forms, with or without 672017Scg * modification, are permitted provided that the following conditions 772017Scg * are met: 872017Scg * 1. Redistributions of source code must retain the above copyright 972017Scg * notice, this list of conditions and the following disclaimer. 1072017Scg * 2. Redistributions in binary form must reproduce the above copyright 1172017Scg * notice, this list of conditions and the following disclaimer in the 1272017Scg * documentation and/or other materials provided with the distribution. 1372017Scg * 1472017Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1572017Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1672017Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1772017Scg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1872017Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1972017Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2072017Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2172017Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 2272017Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2372017Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 2472017Scg * SUCH DAMAGE. 2572017Scg * 2672017Scg * The order of pokes in the initiation sequence is based on Linux 2772017Scg * driver by Thomas Sailer, gw boynton (wesb@crystal.cirrus.com), tom 2872455Scg * woller (twoller@crystal.cirrus.com). Shingo Watanabe (nabe@nabechan.org) 2972455Scg * contributed towards power management. 3072455Scg */ 3172017Scg 3272017Scg#include <dev/sound/pcm/sound.h> 3372017Scg#include <dev/sound/pcm/ac97.h> 3472017Scg 35119287Simp#include <dev/pci/pcireg.h> 36119287Simp#include <dev/pci/pcivar.h> 3772017Scg 3872017Scg#include <dev/sound/pci/cs4281.h> 3972017Scg 4082180ScgSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/cs4281.c 119690 2003-09-02 17:30:40Z jhb $"); 4182180Scg 4284771Sorion#define CS4281_DEFAULT_BUFSZ 16384 4372017Scg 4472017Scg/* Max fifo size for full duplex is 64 */ 4572017Scg#define CS4281_FIFO_SIZE 15 4672017Scg 4772017Scg/* DMA Engine Indices */ 4872017Scg#define CS4281_DMA_PLAY 0 4972017Scg#define CS4281_DMA_REC 1 5072017Scg 5172017Scg/* Misc */ 5272017Scg 5372017Scg#define inline __inline 5472017Scg 5572017Scg#ifndef DEB 5672017Scg#define DEB(x) /* x */ 5772017Scg#endif /* DEB */ 5872017Scg 5972017Scg/* ------------------------------------------------------------------------- */ 6072017Scg/* Structures */ 6172017Scg 6272017Scgstruct sc_info; 6372017Scg 6472017Scg/* channel registers */ 6572017Scgstruct sc_chinfo { 6672017Scg struct sc_info *parent; 6772017Scg 6874763Scg struct snd_dbuf *buffer; 6974763Scg struct pcm_channel *channel; 7072017Scg 7172455Scg u_int32_t spd, fmt, bps, blksz; 7272455Scg 7372455Scg int dma_setup, dma_active, dma_chan; 7472017Scg}; 7572017Scg 7672017Scg/* device private data */ 7772017Scgstruct sc_info { 7872017Scg device_t dev; 7972017Scg u_int32_t type; 8072017Scg 8172017Scg bus_space_tag_t st; 8272017Scg bus_space_handle_t sh; 8372017Scg bus_dma_tag_t parent_dmat; 8472017Scg 8572017Scg struct resource *reg, *irq, *mem; 8672017Scg int regtype, regid, irqid, memid; 8772017Scg void *ih; 8872017Scg 8972017Scg int power; 9084771Sorion unsigned long bufsz; 9172017Scg struct sc_chinfo pch; 9272017Scg struct sc_chinfo rch; 9372017Scg}; 9472017Scg 9572017Scg/* -------------------------------------------------------------------- */ 9672017Scg/* prototypes */ 9772017Scg 9872017Scg/* ADC/DAC control */ 9972017Scgstatic u_int32_t adcdac_go(struct sc_chinfo *ch, u_int32_t go); 10072017Scgstatic void adcdac_prog(struct sc_chinfo *ch); 10172017Scg 10272455Scg/* power management and interrupt control */ 10372017Scgstatic void cs4281_intr(void *); 10472017Scgstatic int cs4281_power(struct sc_info *, int); 10572017Scgstatic int cs4281_init(struct sc_info *); 10672017Scg 10772017Scg/* talk to the card */ 10872017Scgstatic u_int32_t cs4281_rd(struct sc_info *, int); 10972017Scgstatic void cs4281_wr(struct sc_info *, int, u_int32_t); 11072017Scg 11172017Scg/* misc */ 11272017Scgstatic u_int8_t cs4281_rate_to_rv(u_int32_t); 11372017Scgstatic u_int32_t cs4281_format_to_dmr(u_int32_t); 11472017Scgstatic u_int32_t cs4281_format_to_bps(u_int32_t); 11572017Scg 11672017Scg/* -------------------------------------------------------------------- */ 11772017Scg/* formats (do not add formats without editing cs_fmt_tab) */ 11872017Scg 11972017Scgstatic u_int32_t cs4281_fmts[] = { 12072017Scg AFMT_U8, 12172017Scg AFMT_U8 | AFMT_STEREO, 12272017Scg AFMT_S8, 12372017Scg AFMT_S8 | AFMT_STEREO, 12472017Scg AFMT_S16_LE, 12572017Scg AFMT_S16_LE | AFMT_STEREO, 12672017Scg AFMT_U16_LE, 12772017Scg AFMT_U16_LE | AFMT_STEREO, 12872017Scg AFMT_S16_BE, 12972017Scg AFMT_S16_BE | AFMT_STEREO, 13072017Scg AFMT_U16_BE, 13172017Scg AFMT_U16_BE | AFMT_STEREO, 13272017Scg 0 13372017Scg}; 13472017Scg 13574763Scgstatic struct pcmchan_caps cs4281_caps = {6024, 48000, cs4281_fmts, 0}; 13672017Scg 13772017Scg/* -------------------------------------------------------------------- */ 13872017Scg/* Hardware */ 13972017Scg 14072017Scgstatic inline u_int32_t 14172017Scgcs4281_rd(struct sc_info *sc, int regno) 14272017Scg{ 14372017Scg return bus_space_read_4(sc->st, sc->sh, regno); 14472017Scg} 14572017Scg 14672017Scgstatic inline void 14772017Scgcs4281_wr(struct sc_info *sc, int regno, u_int32_t data) 14872017Scg{ 14972017Scg bus_space_write_4(sc->st, sc->sh, regno, data); 15072017Scg DELAY(100); 15172017Scg} 15272017Scg 15372017Scgstatic inline void 15472017Scgcs4281_clr4(struct sc_info *sc, int regno, u_int32_t mask) 15572017Scg{ 15672017Scg u_int32_t r; 15772017Scg r = cs4281_rd(sc, regno); 15872017Scg cs4281_wr(sc, regno, r & ~mask); 15972017Scg} 16072017Scg 16172017Scgstatic inline void 16272017Scgcs4281_set4(struct sc_info *sc, int regno, u_int32_t mask) 16372017Scg{ 16472017Scg u_int32_t v; 16572017Scg v = cs4281_rd(sc, regno); 16672017Scg cs4281_wr(sc, regno, v | mask); 16772017Scg} 16872017Scg 16972017Scgstatic int 17072017Scgcs4281_waitset(struct sc_info *sc, int regno, u_int32_t mask, int tries) 17172017Scg{ 17272017Scg u_int32_t v; 17372017Scg 17472017Scg while(tries > 0) { 17572017Scg DELAY(100); 17672017Scg v = cs4281_rd(sc, regno); 17772017Scg if ((v & mask) == mask) break; 17872017Scg tries --; 17972017Scg } 18072017Scg return tries; 18172017Scg} 18272017Scg 18372017Scgstatic int 18472017Scgcs4281_waitclr(struct sc_info *sc, int regno, u_int32_t mask, int tries) 18572017Scg{ 18672017Scg u_int32_t v; 18772017Scg 18872017Scg while(tries > 0) { 18972017Scg DELAY(100); 19072017Scg v = ~ cs4281_rd(sc, regno); 19172017Scg if (v & mask) break; 19272017Scg tries --; 19372017Scg } 19472017Scg return tries; 19572017Scg} 19672017Scg 19772017Scg/* ------------------------------------------------------------------------- */ 19872017Scg/* Register value mapping functions */ 19972017Scg 20072017Scgstatic u_int32_t cs4281_rates[] = {48000, 44100, 22050, 16000, 11025, 8000}; 20172017Scg#define CS4281_NUM_RATES sizeof(cs4281_rates)/sizeof(cs4281_rates[0]) 20272017Scg 20372455Scgstatic u_int8_t 20472017Scgcs4281_rate_to_rv(u_int32_t rate) 20572017Scg{ 20672017Scg u_int32_t v; 20772017Scg 20872017Scg for (v = 0; v < CS4281_NUM_RATES; v++) { 20972017Scg if (rate == cs4281_rates[v]) return v; 21072017Scg } 21172017Scg 21272017Scg v = 1536000 / rate; 21372017Scg if (v > 255 || v < 32) v = 5; /* default to 8k */ 21472017Scg return v; 21572017Scg} 21672017Scg 21772017Scgstatic u_int32_t 21872017Scgcs4281_rv_to_rate(u_int8_t rv) 21972017Scg{ 22072017Scg u_int32_t r; 22172017Scg 22272017Scg if (rv < CS4281_NUM_RATES) return cs4281_rates[rv]; 22372017Scg r = 1536000 / rv; 22472017Scg return r; 22572017Scg} 22672017Scg 22772017Scgstatic inline u_int32_t 22872455Scgcs4281_format_to_dmr(u_int32_t format) 22972017Scg{ 23072017Scg u_int32_t dmr = 0; 23172017Scg if (AFMT_8BIT & format) dmr |= CS4281PCI_DMR_SIZE8; 23272017Scg if (!(AFMT_STEREO & format)) dmr |= CS4281PCI_DMR_MONO; 23372017Scg if (AFMT_BIGENDIAN & format) dmr |= CS4281PCI_DMR_BEND; 23472017Scg if (!(AFMT_SIGNED & format)) dmr |= CS4281PCI_DMR_USIGN; 23572017Scg return dmr; 23672455Scg} 23772017Scg 23872017Scgstatic inline u_int32_t 23972455Scgcs4281_format_to_bps(u_int32_t format) 24072017Scg{ 24172017Scg return ((AFMT_8BIT & format) ? 1 : 2) * ((AFMT_STEREO & format) ? 2 : 1); 24272017Scg} 24372017Scg 24472017Scg/* -------------------------------------------------------------------- */ 24572017Scg/* ac97 codec */ 24672017Scg 24772017Scgstatic u_int32_t 24872017Scgcs4281_rdcd(kobj_t obj, void *devinfo, int regno) 24972017Scg{ 25072017Scg struct sc_info *sc = (struct sc_info *)devinfo; 25172017Scg int codecno; 25272455Scg 25372017Scg codecno = regno >> 8; 25472017Scg regno &= 0xff; 25572017Scg 25672017Scg /* Remove old state */ 25772455Scg cs4281_rd(sc, CS4281PCI_ACSDA); 25872017Scg 25972017Scg /* Fill in AC97 register value request form */ 26072017Scg cs4281_wr(sc, CS4281PCI_ACCAD, regno); 26172017Scg cs4281_wr(sc, CS4281PCI_ACCDA, 0); 26272455Scg cs4281_wr(sc, CS4281PCI_ACCTL, CS4281PCI_ACCTL_ESYN | 26372455Scg CS4281PCI_ACCTL_VFRM | CS4281PCI_ACCTL_DCV | 26472017Scg CS4281PCI_ACCTL_CRW); 26572017Scg 26672017Scg /* Wait for read to complete */ 26772017Scg if (cs4281_waitclr(sc, CS4281PCI_ACCTL, CS4281PCI_ACCTL_DCV, 250) == 0) { 26872017Scg device_printf(sc->dev, "cs4281_rdcd: DCV did not go\n"); 26972017Scg return 0xffffffff; 27072017Scg } 27172017Scg 27272017Scg /* Wait for valid status */ 27372017Scg if (cs4281_waitset(sc, CS4281PCI_ACSTS, CS4281PCI_ACSTS_VSTS, 250) == 0) { 27472017Scg device_printf(sc->dev,"cs4281_rdcd: VSTS did not come\n"); 27572017Scg return 0xffffffff; 27672017Scg } 27772455Scg 27872455Scg return cs4281_rd(sc, CS4281PCI_ACSDA); 27972017Scg} 28072017Scg 28172017Scgstatic void 28272017Scgcs4281_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) 28372017Scg{ 28472017Scg struct sc_info *sc = (struct sc_info *)devinfo; 28572017Scg int codecno; 28672455Scg 28772017Scg codecno = regno >> 8; 28872017Scg regno &= 0xff; 28972017Scg 29072017Scg cs4281_wr(sc, CS4281PCI_ACCAD, regno); 29172017Scg cs4281_wr(sc, CS4281PCI_ACCDA, data); 29272455Scg cs4281_wr(sc, CS4281PCI_ACCTL, CS4281PCI_ACCTL_ESYN | 29372017Scg CS4281PCI_ACCTL_VFRM | CS4281PCI_ACCTL_DCV); 29472455Scg 29572017Scg if (cs4281_waitclr(sc, CS4281PCI_ACCTL, CS4281PCI_ACCTL_DCV, 250) == 0) { 29672017Scg device_printf(sc->dev,"cs4281_wrcd: DCV did not go\n"); 29772017Scg } 29872017Scg} 29972017Scg 30072017Scgstatic kobj_method_t cs4281_ac97_methods[] = { 30172017Scg KOBJMETHOD(ac97_read, cs4281_rdcd), 30272017Scg KOBJMETHOD(ac97_write, cs4281_wrcd), 30372017Scg { 0, 0 } 30472017Scg}; 30572017ScgAC97_DECLARE(cs4281_ac97); 30672017Scg 30772017Scg/* ------------------------------------------------------------------------- */ 30872017Scg/* shared rec/play channel interface */ 30972017Scg 31072017Scgstatic void * 31174763Scgcs4281chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 31272017Scg{ 31372017Scg struct sc_info *sc = devinfo; 31472017Scg struct sc_chinfo *ch = (dir == PCMDIR_PLAY) ? &sc->pch : &sc->rch; 31572017Scg 31672017Scg ch->buffer = b; 31784771Sorion if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) != 0) { 31872017Scg return NULL; 31972017Scg } 32072017Scg ch->parent = sc; 32172017Scg ch->channel = c; 32272017Scg 32372017Scg ch->fmt = AFMT_U8; 32472017Scg ch->spd = DSP_DEFAULT_SPEED; 32572017Scg ch->bps = 1; 32672455Scg ch->blksz = sndbuf_getsize(ch->buffer); 32772017Scg 32872017Scg ch->dma_chan = (dir == PCMDIR_PLAY) ? CS4281_DMA_PLAY : CS4281_DMA_REC; 32972017Scg ch->dma_setup = 0; 33072017Scg 33172017Scg adcdac_go(ch, 0); 33272017Scg adcdac_prog(ch); 33372017Scg 33472017Scg return ch; 33572017Scg} 33672017Scg 33772017Scgstatic int 33872017Scgcs4281chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 33972017Scg{ 34072017Scg struct sc_chinfo *ch = data; 34184771Sorion struct sc_info *sc = ch->parent; 34272455Scg u_int32_t go; 34372017Scg 34472017Scg go = adcdac_go(ch, 0); 34572017Scg 34672017Scg /* 2 interrupts are possible and used in buffer (half-empty,empty), 34772017Scg * hence factor of 2. */ 34884771Sorion ch->blksz = MIN(blocksize, sc->bufsz / 2); 34972455Scg sndbuf_resize(ch->buffer, 2, ch->blksz); 35072017Scg ch->dma_setup = 0; 35172017Scg adcdac_prog(ch); 35272017Scg adcdac_go(ch, go); 35372017Scg 35484771Sorion DEB(printf("cs4281chan_setblocksize: blksz %d Setting %d\n", blocksize, ch->blksz)); 35572017Scg 35682837Sorion return ch->blksz; 35772017Scg} 35872017Scg 35972017Scgstatic int 36072017Scgcs4281chan_setspeed(kobj_t obj, void *data, u_int32_t speed) 36172017Scg{ 36272017Scg struct sc_chinfo *ch = data; 36372017Scg struct sc_info *sc = ch->parent; 36472017Scg u_int32_t go, v, r; 36572017Scg 36672017Scg go = adcdac_go(ch, 0); /* pause */ 36772017Scg r = (ch->dma_chan == CS4281_DMA_PLAY) ? CS4281PCI_DACSR : CS4281PCI_ADCSR; 36872017Scg v = cs4281_rate_to_rv(speed); 36972017Scg cs4281_wr(sc, r, v); 37072017Scg adcdac_go(ch, go); /* unpause */ 37172017Scg 37272017Scg ch->spd = cs4281_rv_to_rate(v); 37372017Scg return ch->spd; 37472017Scg} 37572017Scg 37672017Scgstatic int 37772017Scgcs4281chan_setformat(kobj_t obj, void *data, u_int32_t format) 37872017Scg{ 37972017Scg struct sc_chinfo *ch = data; 38072017Scg struct sc_info *sc = ch->parent; 38172017Scg u_int32_t v, go; 38272017Scg 38372017Scg go = adcdac_go(ch, 0); /* pause */ 38472017Scg 38572017Scg if (ch->dma_chan == CS4281_DMA_PLAY) 38672017Scg v = CS4281PCI_DMR_TR_PLAY; 38772455Scg else 38872017Scg v = CS4281PCI_DMR_TR_REC; 38972017Scg v |= CS4281PCI_DMR_DMA | CS4281PCI_DMR_AUTO; 39072017Scg v |= cs4281_format_to_dmr(format); 39172017Scg cs4281_wr(sc, CS4281PCI_DMR(ch->dma_chan), v); 39272017Scg 39372017Scg adcdac_go(ch, go); /* unpause */ 39472017Scg 39572017Scg ch->fmt = format; 39672017Scg ch->bps = cs4281_format_to_bps(format); 39772017Scg ch->dma_setup = 0; 39872017Scg 39972017Scg return 0; 40072017Scg} 40172017Scg 40272017Scgstatic int 40372017Scgcs4281chan_getptr(kobj_t obj, void *data) 40472017Scg{ 40572017Scg struct sc_chinfo *ch = data; 40672017Scg struct sc_info *sc = ch->parent; 40772017Scg u_int32_t dba, dca, ptr; 40872017Scg int sz; 40972017Scg 41072017Scg sz = sndbuf_getsize(ch->buffer); 41172017Scg dba = cs4281_rd(sc, CS4281PCI_DBA(ch->dma_chan)); 41272017Scg dca = cs4281_rd(sc, CS4281PCI_DCA(ch->dma_chan)); 41372017Scg ptr = (dca - dba + sz) % sz; 41472017Scg 41572017Scg return ptr; 41672017Scg} 41772017Scg 41872017Scgstatic int 41972017Scgcs4281chan_trigger(kobj_t obj, void *data, int go) 42072017Scg{ 42172017Scg struct sc_chinfo *ch = data; 42272017Scg 42372017Scg switch(go) { 42472017Scg case PCMTRIG_START: 42572017Scg adcdac_prog(ch); 42672017Scg adcdac_go(ch, 1); 42772017Scg break; 42872017Scg case PCMTRIG_ABORT: 42972017Scg adcdac_go(ch, 0); 43072017Scg break; 43172017Scg default: 43272017Scg break; 43372017Scg } 43472017Scg 43572017Scg /* return 0 if ok */ 43672017Scg return 0; 43772017Scg} 43872017Scg 43974763Scgstatic struct pcmchan_caps * 44072017Scgcs4281chan_getcaps(kobj_t obj, void *data) 44172017Scg{ 44272017Scg return &cs4281_caps; 44372017Scg} 44472017Scg 44572017Scgstatic kobj_method_t cs4281chan_methods[] = { 44672017Scg KOBJMETHOD(channel_init, cs4281chan_init), 44772017Scg KOBJMETHOD(channel_setformat, cs4281chan_setformat), 44872017Scg KOBJMETHOD(channel_setspeed, cs4281chan_setspeed), 44972017Scg KOBJMETHOD(channel_setblocksize, cs4281chan_setblocksize), 45072017Scg KOBJMETHOD(channel_trigger, cs4281chan_trigger), 45172017Scg KOBJMETHOD(channel_getptr, cs4281chan_getptr), 45272017Scg KOBJMETHOD(channel_getcaps, cs4281chan_getcaps), 45372017Scg { 0, 0 } 45472017Scg}; 45572017ScgCHANNEL_DECLARE(cs4281chan); 45672017Scg 45772017Scg/* -------------------------------------------------------------------- */ 45872017Scg/* ADC/DAC control */ 45972017Scg 46072017Scg/* adcdac_go enables/disable DMA channel, returns non-zero if DMA was 46172017Scg * active before call */ 46272017Scg 46372017Scgstatic u_int32_t 46472017Scgadcdac_go(struct sc_chinfo *ch, u_int32_t go) 46572017Scg{ 46672017Scg struct sc_info *sc = ch->parent; 46772017Scg u_int32_t going; 46872455Scg 46972017Scg going = !(cs4281_rd(sc, CS4281PCI_DCR(ch->dma_chan)) & CS4281PCI_DCR_MSK); 47072017Scg 47172455Scg if (go) 47272017Scg cs4281_clr4(sc, CS4281PCI_DCR(ch->dma_chan), CS4281PCI_DCR_MSK); 47372455Scg else 47472017Scg cs4281_set4(sc, CS4281PCI_DCR(ch->dma_chan), CS4281PCI_DCR_MSK); 47572017Scg 47672017Scg cs4281_wr(sc, CS4281PCI_HICR, CS4281PCI_HICR_EOI); 47772017Scg 47872017Scg return going; 47972017Scg} 48072017Scg 48172017Scgstatic void 48272455Scgadcdac_prog(struct sc_chinfo *ch) 48372017Scg{ 48472017Scg struct sc_info *sc = ch->parent; 48572017Scg u_int32_t go; 48672017Scg 48772017Scg if (!ch->dma_setup) { 48872017Scg go = adcdac_go(ch, 0); 48972017Scg cs4281_wr(sc, CS4281PCI_DBA(ch->dma_chan), 490111183Scognet sndbuf_getbufaddr(ch->buffer)); 49172455Scg cs4281_wr(sc, CS4281PCI_DBC(ch->dma_chan), 49272017Scg sndbuf_getsize(ch->buffer) / ch->bps - 1); 49372017Scg ch->dma_setup = 1; 49472017Scg adcdac_go(ch, go); 49572017Scg } 49672017Scg} 49772017Scg 49872017Scg/* -------------------------------------------------------------------- */ 49972017Scg/* The interrupt handler */ 50072017Scg 50172017Scgstatic void 50272017Scgcs4281_intr(void *p) 50372017Scg{ 50472017Scg struct sc_info *sc = (struct sc_info *)p; 50572017Scg u_int32_t hisr; 50672017Scg 50772017Scg hisr = cs4281_rd(sc, CS4281PCI_HISR); 50872455Scg 50972017Scg if (hisr == 0) return; 51072017Scg 51172017Scg if (hisr & CS4281PCI_HISR_DMA(CS4281_DMA_PLAY)) { 51272017Scg chn_intr(sc->pch.channel); 51372017Scg cs4281_rd(sc, CS4281PCI_HDSR(CS4281_DMA_PLAY)); /* Clear interrupt */ 51472017Scg } 51572017Scg 51672017Scg if (hisr & CS4281PCI_HISR_DMA(CS4281_DMA_REC)) { 51772017Scg chn_intr(sc->rch.channel); 51872017Scg cs4281_rd(sc, CS4281PCI_HDSR(CS4281_DMA_REC)); /* Clear interrupt */ 51972017Scg } 52072017Scg 52172017Scg /* Signal End-of-Interrupt */ 52272455Scg cs4281_wr(sc, CS4281PCI_HICR, CS4281PCI_HICR_EOI); 52372017Scg} 52472017Scg 52572017Scg/* -------------------------------------------------------------------- */ 52672455Scg/* power management related */ 52772017Scg 52872017Scgstatic int 52972017Scgcs4281_power(struct sc_info *sc, int state) 53072017Scg{ 53172455Scg 53272017Scg switch (state) { 53372455Scg case 0: 53472455Scg /* Permit r/w access to all BA0 registers */ 53572455Scg cs4281_wr(sc, CS4281PCI_CWPR, CS4281PCI_CWPR_MAGIC); 53672455Scg /* Power on */ 53772455Scg cs4281_clr4(sc, CS4281PCI_EPPMC, CS4281PCI_EPPMC_FPDN); 53872017Scg break; 53972455Scg case 3: 54072455Scg /* Power off card and codec */ 54172455Scg cs4281_set4(sc, CS4281PCI_EPPMC, CS4281PCI_EPPMC_FPDN); 54272455Scg cs4281_clr4(sc, CS4281PCI_SPMC, CS4281PCI_SPMC_RSTN); 54372017Scg break; 54472017Scg } 54572455Scg 54672455Scg DEB(printf("cs4281_power %d -> %d\n", sc->power, state)); 54772017Scg sc->power = state; 54872017Scg 54972017Scg return 0; 55072017Scg} 55172017Scg 55272017Scgstatic int 55372017Scgcs4281_init(struct sc_info *sc) 55472017Scg{ 55572017Scg u_int32_t i, v; 55672017Scg 55772017Scg /* (0) Blast clock register and serial port */ 55872017Scg cs4281_wr(sc, CS4281PCI_CLKCR1, 0); 55972017Scg cs4281_wr(sc, CS4281PCI_SERMC, 0); 56072455Scg 56172017Scg /* (1) Make ESYN 0 to turn sync pulse on AC97 link */ 56272017Scg cs4281_wr(sc, CS4281PCI_ACCTL, 0); 56372017Scg DELAY(50); 56472017Scg 56572017Scg /* (2) Effect Reset */ 56672017Scg cs4281_wr(sc, CS4281PCI_SPMC, 0); 56772017Scg DELAY(100); 56872017Scg cs4281_wr(sc, CS4281PCI_SPMC, CS4281PCI_SPMC_RSTN); 56972017Scg /* Wait 50ms for ABITCLK to become stable */ 57072455Scg DELAY(50000); 57172017Scg 57272017Scg /* (3) Enable Sound System Clocks */ 57372455Scg cs4281_wr(sc, CS4281PCI_CLKCR1, CS4281PCI_CLKCR1_DLLP); 57472017Scg DELAY(50000); /* Wait for PLL to stabilize */ 57572455Scg cs4281_wr(sc, CS4281PCI_CLKCR1, 57672455Scg CS4281PCI_CLKCR1_DLLP | CS4281PCI_CLKCR1_SWCE); 57772017Scg 57872017Scg /* (4) Power Up - this combination is essential. */ 57972455Scg cs4281_set4(sc, CS4281PCI_SSPM, 58072017Scg CS4281PCI_SSPM_ACLEN | CS4281PCI_SSPM_PSRCEN | 58172017Scg CS4281PCI_SSPM_CSRCEN | CS4281PCI_SSPM_MIXEN); 58272017Scg 58372017Scg /* (5) Wait for clock stabilization */ 58472455Scg if (cs4281_waitset(sc, 58572455Scg CS4281PCI_CLKCR1, 58672455Scg CS4281PCI_CLKCR1_DLLRDY, 58772017Scg 250) == 0) { 58872017Scg device_printf(sc->dev, "Clock stabilization failed\n"); 58972017Scg return -1; 59072017Scg } 59172017Scg 59272017Scg /* (6) Enable ASYNC generation. */ 59372455Scg cs4281_wr(sc, CS4281PCI_ACCTL,CS4281PCI_ACCTL_ESYN); 59472017Scg 59572017Scg /* Wait to allow AC97 to start generating clock bit */ 59672017Scg DELAY(50000); 59772017Scg 59872017Scg /* Set AC97 timing */ 59972017Scg cs4281_wr(sc, CS4281PCI_SERMC, CS4281PCI_SERMC_PTC_AC97); 60072017Scg 60172017Scg /* (7) Wait for AC97 ready signal */ 60272017Scg if (cs4281_waitset(sc, CS4281PCI_ACSTS, CS4281PCI_ACSTS_CRDY, 250) == 0) { 60372017Scg device_printf(sc->dev, "codec did not avail\n"); 60472017Scg return -1; 60572455Scg } 60672017Scg 60772017Scg /* (8) Assert valid frame signal to begin sending commands to 60872017Scg * AC97 codec */ 60972455Scg cs4281_wr(sc, 61072455Scg CS4281PCI_ACCTL, 61172017Scg CS4281PCI_ACCTL_VFRM | CS4281PCI_ACCTL_ESYN); 61272017Scg 61372017Scg /* (9) Wait for codec calibration */ 61472017Scg for(i = 0 ; i < 1000; i++) { 61572017Scg DELAY(10000); 61672017Scg v = cs4281_rdcd(0, sc, AC97_REG_POWER); 61772017Scg if ((v & 0x0f) == 0x0f) { 61872017Scg break; 61972017Scg } 62072017Scg } 62172017Scg if (i == 1000) { 62272017Scg device_printf(sc->dev, "codec failed to calibrate\n"); 62372017Scg return -1; 62472017Scg } 62572017Scg 62672017Scg /* (10) Set AC97 timing */ 62772017Scg cs4281_wr(sc, CS4281PCI_SERMC, CS4281PCI_SERMC_PTC_AC97); 62872017Scg 62972017Scg /* (11) Wait for valid data to arrive */ 63072455Scg if (cs4281_waitset(sc, 63172455Scg CS4281PCI_ACISV, 63272455Scg CS4281PCI_ACISV_ISV(3) | CS4281PCI_ACISV_ISV(4), 63372017Scg 10000) == 0) { 63472017Scg device_printf(sc->dev, "cs4281 never got valid data\n"); 63572017Scg return -1; 63672455Scg } 63772017Scg 63872017Scg /* (12) Start digital data transfer of audio data to codec */ 63972455Scg cs4281_wr(sc, 64072455Scg CS4281PCI_ACOSV, 64172017Scg CS4281PCI_ACOSV_SLV(3) | CS4281PCI_ACOSV_SLV(4)); 64272017Scg 64372017Scg /* Set Master and headphone to max */ 644102302Sorion cs4281_wrcd(0, sc, AC97_MIX_AUXOUT, 0); 64572017Scg cs4281_wrcd(0, sc, AC97_MIX_MASTER, 0); 64672017Scg 64772017Scg /* Power on the DAC */ 64872017Scg v = cs4281_rdcd(0, sc, AC97_REG_POWER) & 0xfdff; 64972455Scg cs4281_wrcd(0, sc, AC97_REG_POWER, v); 65072017Scg 65172017Scg /* Wait until DAC state ready */ 65272017Scg for(i = 0; i < 320; i++) { 65372017Scg DELAY(100); 65472017Scg v = cs4281_rdcd(0, sc, AC97_REG_POWER); 65572017Scg if (v & 0x02) break; 65672017Scg } 65772017Scg 65872017Scg /* Power on the ADC */ 65972017Scg v = cs4281_rdcd(0, sc, AC97_REG_POWER) & 0xfeff; 66072455Scg cs4281_wrcd(0, sc, AC97_REG_POWER, v); 66172017Scg 66272017Scg /* Wait until ADC state ready */ 66372017Scg for(i = 0; i < 320; i++) { 66472017Scg DELAY(100); 66572017Scg v = cs4281_rdcd(0, sc, AC97_REG_POWER); 66672017Scg if (v & 0x01) break; 66772017Scg } 66872017Scg 66972017Scg /* FIFO configuration (driver is DMA orientated, implicit FIFO) */ 67072017Scg /* Play FIFO */ 67172017Scg 67272017Scg v = CS4281PCI_FCR_RS(CS4281PCI_RPCM_PLAY_SLOT) | 67372017Scg CS4281PCI_FCR_LS(CS4281PCI_LPCM_PLAY_SLOT) | 67472017Scg CS4281PCI_FCR_SZ(CS4281_FIFO_SIZE)| 67572017Scg CS4281PCI_FCR_OF(0); 67672017Scg cs4281_wr(sc, CS4281PCI_FCR(CS4281_DMA_PLAY), v); 67772017Scg 67872017Scg cs4281_wr(sc, CS4281PCI_FCR(CS4281_DMA_PLAY), v | CS4281PCI_FCR_FEN); 67972017Scg 68072017Scg /* Record FIFO */ 68172017Scg v = CS4281PCI_FCR_RS(CS4281PCI_RPCM_REC_SLOT) | 68272017Scg CS4281PCI_FCR_LS(CS4281PCI_LPCM_REC_SLOT) | 68372017Scg CS4281PCI_FCR_SZ(CS4281_FIFO_SIZE)| 68472017Scg CS4281PCI_FCR_OF(CS4281_FIFO_SIZE + 1); 68572017Scg cs4281_wr(sc, CS4281PCI_FCR(CS4281_DMA_REC), v | CS4281PCI_FCR_PSH); 68672017Scg cs4281_wr(sc, CS4281PCI_FCR(CS4281_DMA_REC), v | CS4281PCI_FCR_FEN); 68772017Scg 68872017Scg /* Match AC97 slots to FIFOs */ 68972017Scg v = CS4281PCI_SRCSA_PLSS(CS4281PCI_LPCM_PLAY_SLOT) | 69072017Scg CS4281PCI_SRCSA_PRSS(CS4281PCI_RPCM_PLAY_SLOT) | 69172017Scg CS4281PCI_SRCSA_CLSS(CS4281PCI_LPCM_REC_SLOT) | 69272017Scg CS4281PCI_SRCSA_CRSS(CS4281PCI_RPCM_REC_SLOT); 69372017Scg cs4281_wr(sc, CS4281PCI_SRCSA, v); 69472017Scg 69572017Scg /* Set Auto-Initialize and set directions */ 69672017Scg cs4281_wr(sc, 69772017Scg CS4281PCI_DMR(CS4281_DMA_PLAY), 69872017Scg CS4281PCI_DMR_DMA | 69972017Scg CS4281PCI_DMR_AUTO | 70072017Scg CS4281PCI_DMR_TR_PLAY); 70172017Scg cs4281_wr(sc, 70272017Scg CS4281PCI_DMR(CS4281_DMA_REC), 70372017Scg CS4281PCI_DMR_DMA | 70472017Scg CS4281PCI_DMR_AUTO | 70572017Scg CS4281PCI_DMR_TR_REC); 70672017Scg 70772017Scg /* Enable half and empty buffer interrupts keeping DMA paused */ 70872017Scg cs4281_wr(sc, 70972017Scg CS4281PCI_DCR(CS4281_DMA_PLAY), 71072017Scg CS4281PCI_DCR_TCIE | CS4281PCI_DCR_HTCIE | CS4281PCI_DCR_MSK); 71172017Scg cs4281_wr(sc, 71272017Scg CS4281PCI_DCR(CS4281_DMA_REC), 71372017Scg CS4281PCI_DCR_TCIE | CS4281PCI_DCR_HTCIE | CS4281PCI_DCR_MSK); 71472455Scg 71572017Scg /* Enable Interrupts */ 71672455Scg cs4281_clr4(sc, 71772455Scg CS4281PCI_HIMR, 71872017Scg CS4281PCI_HIMR_DMAI | 71972017Scg CS4281PCI_HIMR_DMA(CS4281_DMA_PLAY) | 72072017Scg CS4281PCI_HIMR_DMA(CS4281_DMA_REC)); 72172017Scg 72272017Scg /* Set playback volume */ 72372017Scg cs4281_wr(sc, CS4281PCI_PPLVC, 7); 72472017Scg cs4281_wr(sc, CS4281PCI_PPRVC, 7); 72572017Scg 72672017Scg return 0; 72772017Scg} 72872017Scg 72972017Scg/* -------------------------------------------------------------------- */ 73072017Scg/* Probe and attach the card */ 73172017Scg 73272017Scgstatic int 73372017Scgcs4281_pci_probe(device_t dev) 73472017Scg{ 73572017Scg char *s = NULL; 73672017Scg 73772017Scg switch (pci_get_devid(dev)) { 73872017Scg case CS4281_PCI_ID: 73972017Scg s = "Crystal Semiconductor CS4281"; 74072017Scg break; 74172017Scg } 74272017Scg 74372017Scg if (s) 74472017Scg device_set_desc(dev, s); 74572455Scg return s ? 0 : ENXIO; 74672017Scg} 74772017Scg 74872017Scgstatic int 74972017Scgcs4281_pci_attach(device_t dev) 75072017Scg{ 75172017Scg struct sc_info *sc; 75272017Scg struct ac97_info *codec = NULL; 75372017Scg u_int32_t data; 75472017Scg char status[SND_STATUSLEN]; 75572017Scg 75678564Sgreid if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) { 75772017Scg device_printf(dev, "cannot allocate softc\n"); 75872017Scg return ENXIO; 75972017Scg } 76072017Scg 76172017Scg sc->dev = dev; 76272017Scg sc->type = pci_get_devid(dev); 76372017Scg 76472017Scg data = pci_read_config(dev, PCIR_COMMAND, 2); 76572017Scg data |= (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN); 76672017Scg pci_write_config(dev, PCIR_COMMAND, data, 2); 76772017Scg 76873770Scg#if __FreeBSD_version > 500000 76972455Scg if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 77072455Scg /* Reset the power state. */ 77172455Scg device_printf(dev, "chip is in D%d power mode " 77272455Scg "-- setting to D0\n", pci_get_powerstate(dev)); 77372455Scg 77472455Scg pci_set_powerstate(dev, PCI_POWERSTATE_D0); 77572455Scg } 77675702Sorion#else 77775702Sorion data = pci_read_config(dev, CS4281PCI_PMCS_OFFSET, 4); 77875702Sorion if (data & CS4281PCI_PMCS_PS_MASK) { 77975702Sorion /* Reset the power state. */ 78075702Sorion device_printf(dev, "chip is in D%d power mode " 78178362Scg "-- setting to D0\n", 78275702Sorion data & CS4281PCI_PMCS_PS_MASK); 78375702Sorion pci_write_config(dev, CS4281PCI_PMCS_OFFSET, 78475702Sorion data & ~CS4281PCI_PMCS_PS_MASK, 4); 78575702Sorion } 78673770Scg#endif 78775702Sorion 788119690Sjhb sc->regid = PCIR_BAR(0); 78972017Scg sc->regtype = SYS_RES_MEMORY; 79072017Scg sc->reg = bus_alloc_resource(dev, sc->regtype, &sc->regid, 79172017Scg 0, ~0, CS4281PCI_BA0_SIZE, RF_ACTIVE); 79272017Scg if (!sc->reg) { 79372017Scg sc->regtype = SYS_RES_IOPORT; 79472017Scg sc->reg = bus_alloc_resource(dev, sc->regtype, &sc->regid, 79572017Scg 0, ~0, CS4281PCI_BA0_SIZE, RF_ACTIVE); 79672017Scg if (!sc->reg) { 79772017Scg device_printf(dev, "unable to allocate register space\n"); 79872017Scg goto bad; 79972017Scg } 80072017Scg } 80172017Scg sc->st = rman_get_bustag(sc->reg); 80272017Scg sc->sh = rman_get_bushandle(sc->reg); 80372017Scg 804119690Sjhb sc->memid = PCIR_BAR(1); 80572455Scg sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->memid, 0, 80672017Scg ~0, CS4281PCI_BA1_SIZE, RF_ACTIVE); 80772017Scg if (sc->mem == NULL) { 80872017Scg device_printf(dev, "unable to allocate fifo space\n"); 80972017Scg goto bad; 81072017Scg } 81172017Scg 81272017Scg sc->irqid = 0; 81372017Scg sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid, 81472017Scg 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 81572017Scg if (!sc->irq) { 81672017Scg device_printf(dev, "unable to allocate interrupt\n"); 81772017Scg goto bad; 81872017Scg } 81972017Scg 82074763Scg if (snd_setup_intr(dev, sc->irq, 0, cs4281_intr, sc, &sc->ih)) { 82172017Scg device_printf(dev, "unable to setup interrupt\n"); 82272017Scg goto bad; 82372017Scg } 82472017Scg 82584771Sorion sc->bufsz = pcm_getbuffersize(dev, 4096, CS4281_DEFAULT_BUFSZ, 65536); 82684771Sorion 82772017Scg if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 82872017Scg /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 82972017Scg /*highaddr*/BUS_SPACE_MAXADDR, 83072017Scg /*filter*/NULL, /*filterarg*/NULL, 83184771Sorion /*maxsize*/sc->bufsz, /*nsegments*/1, 83272017Scg /*maxsegz*/0x3ffff, 833117126Sscottl /*flags*/0, /*lockfunc*/busdma_lock_mutex, 834117126Sscottl /*lockarg*/&Giant, &sc->parent_dmat) != 0) { 83572017Scg device_printf(dev, "unable to create dma tag\n"); 83672017Scg goto bad; 83772017Scg } 83872017Scg 83972017Scg /* power up */ 84072017Scg cs4281_power(sc, 0); 84172017Scg 84272017Scg /* init chip */ 84372017Scg if (cs4281_init(sc) == -1) { 84472017Scg device_printf(dev, "unable to initialize the card\n"); 84572017Scg goto bad; 84672017Scg } 84772017Scg 84872017Scg /* create/init mixer */ 84972017Scg codec = AC97_CREATE(dev, sc, cs4281_ac97); 85072017Scg if (codec == NULL) 85172017Scg goto bad; 85272017Scg 85372017Scg mixer_init(dev, ac97_getmixerclass(), codec); 85472017Scg 85572017Scg if (pcm_register(dev, sc, 1, 1)) 85672017Scg goto bad; 85772017Scg 85872017Scg pcm_addchan(dev, PCMDIR_PLAY, &cs4281chan_class, sc); 85972017Scg pcm_addchan(dev, PCMDIR_REC, &cs4281chan_class, sc); 86072017Scg 86172017Scg snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld", 86272017Scg (sc->regtype == SYS_RES_IOPORT)? "io" : "memory", 86372017Scg rman_get_start(sc->reg), rman_get_start(sc->irq)); 86472017Scg pcm_setstatus(dev, status); 86572017Scg 86672017Scg return 0; 86772017Scg 86872017Scg bad: 86972017Scg if (codec) 87072017Scg ac97_destroy(codec); 87172017Scg if (sc->reg) 87272017Scg bus_release_resource(dev, sc->regtype, sc->regid, sc->reg); 87372017Scg if (sc->mem) 87472017Scg bus_release_resource(dev, SYS_RES_MEMORY, sc->memid, sc->mem); 87572017Scg if (sc->ih) 87672017Scg bus_teardown_intr(dev, sc->irq, sc->ih); 87772017Scg if (sc->irq) 87872017Scg bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 87972017Scg if (sc->parent_dmat) 88072017Scg bus_dma_tag_destroy(sc->parent_dmat); 88172017Scg free(sc, M_DEVBUF); 88272017Scg 88372017Scg return ENXIO; 88472017Scg} 88572017Scg 88672017Scgstatic int 88772017Scgcs4281_pci_detach(device_t dev) 88872017Scg{ 88972017Scg int r; 89072017Scg struct sc_info *sc; 89172017Scg 89272017Scg r = pcm_unregister(dev); 89372017Scg if (r) 89472017Scg return r; 89572017Scg 89672017Scg sc = pcm_getdevinfo(dev); 89772017Scg 89872017Scg /* power off */ 89972017Scg cs4281_power(sc, 3); 90072017Scg 90172017Scg bus_release_resource(dev, sc->regtype, sc->regid, sc->reg); 90272017Scg bus_release_resource(dev, SYS_RES_MEMORY, sc->memid, sc->mem); 90372017Scg bus_teardown_intr(dev, sc->irq, sc->ih); 90472017Scg bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 90572017Scg bus_dma_tag_destroy(sc->parent_dmat); 90672017Scg free(sc, M_DEVBUF); 90772017Scg 90872017Scg return 0; 90972017Scg} 91072017Scg 91172017Scgstatic int 91272017Scgcs4281_pci_suspend(device_t dev) 91372017Scg{ 91472017Scg struct sc_info *sc; 91572017Scg 91672017Scg sc = pcm_getdevinfo(dev); 91772017Scg 91872455Scg sc->rch.dma_active = adcdac_go(&sc->rch, 0); 91972455Scg sc->pch.dma_active = adcdac_go(&sc->pch, 0); 92072017Scg 92172455Scg cs4281_power(sc, 3); 92272455Scg 92372017Scg return 0; 92472017Scg} 92572017Scg 92672017Scgstatic int 92772017Scgcs4281_pci_resume(device_t dev) 92872017Scg{ 92972017Scg struct sc_info *sc; 93072017Scg 93172017Scg sc = pcm_getdevinfo(dev); 93272017Scg 93372017Scg /* power up */ 93472455Scg cs4281_power(sc, 0); 93572017Scg 93672455Scg /* initialize chip */ 93772455Scg if (cs4281_init(sc) == -1) { 93872455Scg device_printf(dev, "unable to reinitialize the card\n"); 93972455Scg return ENXIO; 94072017Scg } 94172017Scg 94272017Scg /* restore mixer state */ 94372017Scg if (mixer_reinit(dev) == -1) { 94472017Scg device_printf(dev, "unable to reinitialize the mixer\n"); 94572017Scg return ENXIO; 94672017Scg } 94772017Scg 94872455Scg /* restore chip state */ 94972455Scg cs4281chan_setspeed(NULL, &sc->rch, sc->rch.spd); 95072455Scg cs4281chan_setblocksize(NULL, &sc->rch, sc->rch.blksz); 95172455Scg cs4281chan_setformat(NULL, &sc->rch, sc->rch.fmt); 95272455Scg adcdac_go(&sc->rch, sc->rch.dma_active); 95372455Scg 95472455Scg cs4281chan_setspeed(NULL, &sc->pch, sc->pch.spd); 95572455Scg cs4281chan_setblocksize(NULL, &sc->pch, sc->pch.blksz); 95672455Scg cs4281chan_setformat(NULL, &sc->pch, sc->pch.fmt); 95772455Scg adcdac_go(&sc->pch, sc->pch.dma_active); 95872455Scg 95972017Scg return 0; 96072017Scg} 96172017Scg 96272017Scgstatic device_method_t cs4281_methods[] = { 96372017Scg /* Device interface */ 96472017Scg DEVMETHOD(device_probe, cs4281_pci_probe), 96572017Scg DEVMETHOD(device_attach, cs4281_pci_attach), 96672017Scg DEVMETHOD(device_detach, cs4281_pci_detach), 96772017Scg DEVMETHOD(device_suspend, cs4281_pci_suspend), 96872017Scg DEVMETHOD(device_resume, cs4281_pci_resume), 96972017Scg { 0, 0 } 97072017Scg}; 97172017Scg 97272017Scgstatic driver_t cs4281_driver = { 97372017Scg "pcm", 97472017Scg cs4281_methods, 97582180Scg PCM_SOFTC_SIZE, 97672017Scg}; 97772017Scg 97872017ScgDRIVER_MODULE(snd_cs4281, pci, cs4281_driver, pcm_devclass, 0, 0); 97972017ScgMODULE_DEPEND(snd_cs4281, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 98072017ScgMODULE_VERSION(snd_cs4281, 1); 981