1139749Simp/*- 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. 25192919Sjoel */ 26192919Sjoel 27192919Sjoel/* 2872017Scg * The order of pokes in the initiation sequence is based on Linux 2972017Scg * driver by Thomas Sailer, gw boynton (wesb@crystal.cirrus.com), tom 3072455Scg * woller (twoller@crystal.cirrus.com). Shingo Watanabe (nabe@nabechan.org) 3172455Scg * contributed towards power management. 3272455Scg */ 3372017Scg 34193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 35193640Sariff#include "opt_snd.h" 36193640Sariff#endif 37193640Sariff 3872017Scg#include <dev/sound/pcm/sound.h> 3972017Scg#include <dev/sound/pcm/ac97.h> 4072017Scg 41119287Simp#include <dev/pci/pcireg.h> 42119287Simp#include <dev/pci/pcivar.h> 4372017Scg 4472017Scg#include <dev/sound/pci/cs4281.h> 4572017Scg 4682180ScgSND_DECLARE_FILE("$FreeBSD$"); 4782180Scg 4884771Sorion#define CS4281_DEFAULT_BUFSZ 16384 4972017Scg 5072017Scg/* Max fifo size for full duplex is 64 */ 5172017Scg#define CS4281_FIFO_SIZE 15 5272017Scg 5372017Scg/* DMA Engine Indices */ 5472017Scg#define CS4281_DMA_PLAY 0 5572017Scg#define CS4281_DMA_REC 1 5672017Scg 5772017Scg/* Misc */ 5872017Scg 5972017Scg#define inline __inline 6072017Scg 6172017Scg#ifndef DEB 6272017Scg#define DEB(x) /* x */ 6372017Scg#endif /* DEB */ 6472017Scg 6572017Scg/* ------------------------------------------------------------------------- */ 6672017Scg/* Structures */ 6772017Scg 6872017Scgstruct sc_info; 6972017Scg 7072017Scg/* channel registers */ 7172017Scgstruct sc_chinfo { 7272017Scg struct sc_info *parent; 7372017Scg 7474763Scg struct snd_dbuf *buffer; 7574763Scg struct pcm_channel *channel; 7672017Scg 7772455Scg u_int32_t spd, fmt, bps, blksz; 7872455Scg 7972455Scg int dma_setup, dma_active, dma_chan; 8072017Scg}; 8172017Scg 8272017Scg/* device private data */ 8372017Scgstruct sc_info { 8472017Scg device_t dev; 8572017Scg u_int32_t type; 8672017Scg 8772017Scg bus_space_tag_t st; 8872017Scg bus_space_handle_t sh; 8972017Scg bus_dma_tag_t parent_dmat; 9072017Scg 9172017Scg struct resource *reg, *irq, *mem; 9272017Scg int regtype, regid, irqid, memid; 9372017Scg void *ih; 9472017Scg 9572017Scg int power; 9684771Sorion unsigned long bufsz; 9772017Scg struct sc_chinfo pch; 9872017Scg struct sc_chinfo rch; 9972017Scg}; 10072017Scg 10172017Scg/* -------------------------------------------------------------------- */ 10272017Scg/* prototypes */ 10372017Scg 10472017Scg/* ADC/DAC control */ 10572017Scgstatic u_int32_t adcdac_go(struct sc_chinfo *ch, u_int32_t go); 10672017Scgstatic void adcdac_prog(struct sc_chinfo *ch); 10772017Scg 10872455Scg/* power management and interrupt control */ 10972017Scgstatic void cs4281_intr(void *); 11072017Scgstatic int cs4281_power(struct sc_info *, int); 11172017Scgstatic int cs4281_init(struct sc_info *); 11272017Scg 11372017Scg/* talk to the card */ 11472017Scgstatic u_int32_t cs4281_rd(struct sc_info *, int); 11572017Scgstatic void cs4281_wr(struct sc_info *, int, u_int32_t); 11672017Scg 11772017Scg/* misc */ 11872017Scgstatic u_int8_t cs4281_rate_to_rv(u_int32_t); 11972017Scgstatic u_int32_t cs4281_format_to_dmr(u_int32_t); 12072017Scgstatic u_int32_t cs4281_format_to_bps(u_int32_t); 12172017Scg 12272017Scg/* -------------------------------------------------------------------- */ 12372017Scg/* formats (do not add formats without editing cs_fmt_tab) */ 12472017Scg 12572017Scgstatic u_int32_t cs4281_fmts[] = { 126193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 127193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 128193640Sariff SND_FORMAT(AFMT_S8, 1, 0), 129193640Sariff SND_FORMAT(AFMT_S8, 2, 0), 130193640Sariff SND_FORMAT(AFMT_S16_LE, 1, 0), 131193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 132193640Sariff SND_FORMAT(AFMT_U16_LE, 1, 0), 133193640Sariff SND_FORMAT(AFMT_U16_LE, 2, 0), 134193640Sariff SND_FORMAT(AFMT_S16_BE, 1, 0), 135193640Sariff SND_FORMAT(AFMT_S16_BE, 2, 0), 136193640Sariff SND_FORMAT(AFMT_U16_BE, 1, 0), 137193640Sariff SND_FORMAT(AFMT_U16_BE, 2, 0), 13872017Scg 0 13972017Scg}; 14072017Scg 14174763Scgstatic struct pcmchan_caps cs4281_caps = {6024, 48000, cs4281_fmts, 0}; 14272017Scg 14372017Scg/* -------------------------------------------------------------------- */ 14472017Scg/* Hardware */ 14572017Scg 14672017Scgstatic inline u_int32_t 14772017Scgcs4281_rd(struct sc_info *sc, int regno) 14872017Scg{ 14972017Scg return bus_space_read_4(sc->st, sc->sh, regno); 15072017Scg} 15172017Scg 15272017Scgstatic inline void 15372017Scgcs4281_wr(struct sc_info *sc, int regno, u_int32_t data) 15472017Scg{ 15572017Scg bus_space_write_4(sc->st, sc->sh, regno, data); 15672017Scg DELAY(100); 15772017Scg} 15872017Scg 15972017Scgstatic inline void 16072017Scgcs4281_clr4(struct sc_info *sc, int regno, u_int32_t mask) 16172017Scg{ 16272017Scg u_int32_t r; 16372017Scg r = cs4281_rd(sc, regno); 16472017Scg cs4281_wr(sc, regno, r & ~mask); 16572017Scg} 16672017Scg 16772017Scgstatic inline void 16872017Scgcs4281_set4(struct sc_info *sc, int regno, u_int32_t mask) 16972017Scg{ 17072017Scg u_int32_t v; 17172017Scg v = cs4281_rd(sc, regno); 17272017Scg cs4281_wr(sc, regno, v | mask); 17372017Scg} 17472017Scg 17572017Scgstatic int 17672017Scgcs4281_waitset(struct sc_info *sc, int regno, u_int32_t mask, int tries) 17772017Scg{ 17872017Scg u_int32_t v; 17972017Scg 180193640Sariff while (tries > 0) { 18172017Scg DELAY(100); 18272017Scg v = cs4281_rd(sc, regno); 18372017Scg if ((v & mask) == mask) break; 18472017Scg tries --; 18572017Scg } 18672017Scg return tries; 18772017Scg} 18872017Scg 18972017Scgstatic int 19072017Scgcs4281_waitclr(struct sc_info *sc, int regno, u_int32_t mask, int tries) 19172017Scg{ 19272017Scg u_int32_t v; 19372017Scg 194193640Sariff while (tries > 0) { 19572017Scg DELAY(100); 19672017Scg v = ~ cs4281_rd(sc, regno); 19772017Scg if (v & mask) break; 19872017Scg tries --; 19972017Scg } 20072017Scg return tries; 20172017Scg} 20272017Scg 20372017Scg/* ------------------------------------------------------------------------- */ 20472017Scg/* Register value mapping functions */ 20572017Scg 20672017Scgstatic u_int32_t cs4281_rates[] = {48000, 44100, 22050, 16000, 11025, 8000}; 20772017Scg#define CS4281_NUM_RATES sizeof(cs4281_rates)/sizeof(cs4281_rates[0]) 20872017Scg 20972455Scgstatic u_int8_t 21072017Scgcs4281_rate_to_rv(u_int32_t rate) 21172017Scg{ 21272017Scg u_int32_t v; 21372017Scg 21472017Scg for (v = 0; v < CS4281_NUM_RATES; v++) { 21572017Scg if (rate == cs4281_rates[v]) return v; 21672017Scg } 21772017Scg 21872017Scg v = 1536000 / rate; 21972017Scg if (v > 255 || v < 32) v = 5; /* default to 8k */ 22072017Scg return v; 22172017Scg} 22272017Scg 22372017Scgstatic u_int32_t 22472017Scgcs4281_rv_to_rate(u_int8_t rv) 22572017Scg{ 22672017Scg u_int32_t r; 22772017Scg 22872017Scg if (rv < CS4281_NUM_RATES) return cs4281_rates[rv]; 22972017Scg r = 1536000 / rv; 23072017Scg return r; 23172017Scg} 23272017Scg 23372017Scgstatic inline u_int32_t 23472455Scgcs4281_format_to_dmr(u_int32_t format) 23572017Scg{ 23672017Scg u_int32_t dmr = 0; 23772017Scg if (AFMT_8BIT & format) dmr |= CS4281PCI_DMR_SIZE8; 238193640Sariff if (AFMT_CHANNEL(format) < 2) dmr |= CS4281PCI_DMR_MONO; 23972017Scg if (AFMT_BIGENDIAN & format) dmr |= CS4281PCI_DMR_BEND; 24072017Scg if (!(AFMT_SIGNED & format)) dmr |= CS4281PCI_DMR_USIGN; 24172017Scg return dmr; 24272455Scg} 24372017Scg 24472017Scgstatic inline u_int32_t 24572455Scgcs4281_format_to_bps(u_int32_t format) 24672017Scg{ 247193640Sariff return ((AFMT_8BIT & format) ? 1 : 2) * 248193640Sariff ((AFMT_CHANNEL(format) > 1) ? 2 : 1); 24972017Scg} 25072017Scg 25172017Scg/* -------------------------------------------------------------------- */ 25272017Scg/* ac97 codec */ 25372017Scg 254193640Sariffstatic int 25572017Scgcs4281_rdcd(kobj_t obj, void *devinfo, int regno) 25672017Scg{ 25772017Scg struct sc_info *sc = (struct sc_info *)devinfo; 25872017Scg int codecno; 25972455Scg 26072017Scg codecno = regno >> 8; 26172017Scg regno &= 0xff; 26272017Scg 26372017Scg /* Remove old state */ 26472455Scg cs4281_rd(sc, CS4281PCI_ACSDA); 26572017Scg 26672017Scg /* Fill in AC97 register value request form */ 26772017Scg cs4281_wr(sc, CS4281PCI_ACCAD, regno); 26872017Scg cs4281_wr(sc, CS4281PCI_ACCDA, 0); 26972455Scg cs4281_wr(sc, CS4281PCI_ACCTL, CS4281PCI_ACCTL_ESYN | 27072455Scg CS4281PCI_ACCTL_VFRM | CS4281PCI_ACCTL_DCV | 27172017Scg CS4281PCI_ACCTL_CRW); 27272017Scg 27372017Scg /* Wait for read to complete */ 27472017Scg if (cs4281_waitclr(sc, CS4281PCI_ACCTL, CS4281PCI_ACCTL_DCV, 250) == 0) { 27572017Scg device_printf(sc->dev, "cs4281_rdcd: DCV did not go\n"); 276193640Sariff return -1; 27772017Scg } 27872017Scg 27972017Scg /* Wait for valid status */ 28072017Scg if (cs4281_waitset(sc, CS4281PCI_ACSTS, CS4281PCI_ACSTS_VSTS, 250) == 0) { 28172017Scg device_printf(sc->dev,"cs4281_rdcd: VSTS did not come\n"); 282193640Sariff return -1; 28372017Scg } 28472455Scg 28572455Scg return cs4281_rd(sc, CS4281PCI_ACSDA); 28672017Scg} 28772017Scg 288193640Sariffstatic int 28972017Scgcs4281_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) 29072017Scg{ 29172017Scg struct sc_info *sc = (struct sc_info *)devinfo; 29272017Scg int codecno; 29372455Scg 29472017Scg codecno = regno >> 8; 29572017Scg regno &= 0xff; 29672017Scg 29772017Scg cs4281_wr(sc, CS4281PCI_ACCAD, regno); 29872017Scg cs4281_wr(sc, CS4281PCI_ACCDA, data); 29972455Scg cs4281_wr(sc, CS4281PCI_ACCTL, CS4281PCI_ACCTL_ESYN | 30072017Scg CS4281PCI_ACCTL_VFRM | CS4281PCI_ACCTL_DCV); 30172455Scg 30272017Scg if (cs4281_waitclr(sc, CS4281PCI_ACCTL, CS4281PCI_ACCTL_DCV, 250) == 0) { 30372017Scg device_printf(sc->dev,"cs4281_wrcd: DCV did not go\n"); 30472017Scg } 305193640Sariff 306193640Sariff return 0; 30772017Scg} 30872017Scg 30972017Scgstatic kobj_method_t cs4281_ac97_methods[] = { 31072017Scg KOBJMETHOD(ac97_read, cs4281_rdcd), 31172017Scg KOBJMETHOD(ac97_write, cs4281_wrcd), 312193640Sariff KOBJMETHOD_END 31372017Scg}; 31472017ScgAC97_DECLARE(cs4281_ac97); 31572017Scg 31672017Scg/* ------------------------------------------------------------------------- */ 31772017Scg/* shared rec/play channel interface */ 31872017Scg 31972017Scgstatic void * 32074763Scgcs4281chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 32172017Scg{ 32272017Scg struct sc_info *sc = devinfo; 32372017Scg struct sc_chinfo *ch = (dir == PCMDIR_PLAY) ? &sc->pch : &sc->rch; 32472017Scg 32572017Scg ch->buffer = b; 326168847Sariff if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0) { 32772017Scg return NULL; 32872017Scg } 32972017Scg ch->parent = sc; 33072017Scg ch->channel = c; 33172017Scg 332193640Sariff ch->fmt = SND_FORMAT(AFMT_U8, 1, 0); 33372017Scg ch->spd = DSP_DEFAULT_SPEED; 33472017Scg ch->bps = 1; 33572455Scg ch->blksz = sndbuf_getsize(ch->buffer); 33672017Scg 33772017Scg ch->dma_chan = (dir == PCMDIR_PLAY) ? CS4281_DMA_PLAY : CS4281_DMA_REC; 33872017Scg ch->dma_setup = 0; 33972017Scg 34072017Scg adcdac_go(ch, 0); 34172017Scg adcdac_prog(ch); 34272017Scg 34372017Scg return ch; 34472017Scg} 34572017Scg 346193640Sariffstatic u_int32_t 34772017Scgcs4281chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 34872017Scg{ 34972017Scg struct sc_chinfo *ch = data; 35084771Sorion struct sc_info *sc = ch->parent; 35172455Scg u_int32_t go; 35272017Scg 35372017Scg go = adcdac_go(ch, 0); 35472017Scg 35572017Scg /* 2 interrupts are possible and used in buffer (half-empty,empty), 35672017Scg * hence factor of 2. */ 35784771Sorion ch->blksz = MIN(blocksize, sc->bufsz / 2); 35872455Scg sndbuf_resize(ch->buffer, 2, ch->blksz); 35972017Scg ch->dma_setup = 0; 36072017Scg adcdac_prog(ch); 36172017Scg adcdac_go(ch, go); 36272017Scg 36384771Sorion DEB(printf("cs4281chan_setblocksize: blksz %d Setting %d\n", blocksize, ch->blksz)); 36472017Scg 36582837Sorion return ch->blksz; 36672017Scg} 36772017Scg 368193640Sariffstatic u_int32_t 36972017Scgcs4281chan_setspeed(kobj_t obj, void *data, u_int32_t speed) 37072017Scg{ 37172017Scg struct sc_chinfo *ch = data; 37272017Scg struct sc_info *sc = ch->parent; 37372017Scg u_int32_t go, v, r; 37472017Scg 37572017Scg go = adcdac_go(ch, 0); /* pause */ 37672017Scg r = (ch->dma_chan == CS4281_DMA_PLAY) ? CS4281PCI_DACSR : CS4281PCI_ADCSR; 37772017Scg v = cs4281_rate_to_rv(speed); 37872017Scg cs4281_wr(sc, r, v); 37972017Scg adcdac_go(ch, go); /* unpause */ 38072017Scg 38172017Scg ch->spd = cs4281_rv_to_rate(v); 38272017Scg return ch->spd; 38372017Scg} 38472017Scg 38572017Scgstatic int 38672017Scgcs4281chan_setformat(kobj_t obj, void *data, u_int32_t format) 38772017Scg{ 38872017Scg struct sc_chinfo *ch = data; 38972017Scg struct sc_info *sc = ch->parent; 39072017Scg u_int32_t v, go; 39172017Scg 39272017Scg go = adcdac_go(ch, 0); /* pause */ 39372017Scg 39472017Scg if (ch->dma_chan == CS4281_DMA_PLAY) 39572017Scg v = CS4281PCI_DMR_TR_PLAY; 39672455Scg else 39772017Scg v = CS4281PCI_DMR_TR_REC; 39872017Scg v |= CS4281PCI_DMR_DMA | CS4281PCI_DMR_AUTO; 39972017Scg v |= cs4281_format_to_dmr(format); 40072017Scg cs4281_wr(sc, CS4281PCI_DMR(ch->dma_chan), v); 40172017Scg 40272017Scg adcdac_go(ch, go); /* unpause */ 40372017Scg 40472017Scg ch->fmt = format; 40572017Scg ch->bps = cs4281_format_to_bps(format); 40672017Scg ch->dma_setup = 0; 40772017Scg 40872017Scg return 0; 40972017Scg} 41072017Scg 411193640Sariffstatic u_int32_t 41272017Scgcs4281chan_getptr(kobj_t obj, void *data) 41372017Scg{ 41472017Scg struct sc_chinfo *ch = data; 41572017Scg struct sc_info *sc = ch->parent; 41672017Scg u_int32_t dba, dca, ptr; 41772017Scg int sz; 41872017Scg 41972017Scg sz = sndbuf_getsize(ch->buffer); 42072017Scg dba = cs4281_rd(sc, CS4281PCI_DBA(ch->dma_chan)); 42172017Scg dca = cs4281_rd(sc, CS4281PCI_DCA(ch->dma_chan)); 42272017Scg ptr = (dca - dba + sz) % sz; 42372017Scg 42472017Scg return ptr; 42572017Scg} 42672017Scg 42772017Scgstatic int 42872017Scgcs4281chan_trigger(kobj_t obj, void *data, int go) 42972017Scg{ 43072017Scg struct sc_chinfo *ch = data; 43172017Scg 43272017Scg switch(go) { 43372017Scg case PCMTRIG_START: 43472017Scg adcdac_prog(ch); 43572017Scg adcdac_go(ch, 1); 43672017Scg break; 437170521Sariff case PCMTRIG_STOP: 43872017Scg case PCMTRIG_ABORT: 43972017Scg adcdac_go(ch, 0); 44072017Scg break; 44172017Scg default: 44272017Scg break; 44372017Scg } 44472017Scg 44572017Scg /* return 0 if ok */ 44672017Scg return 0; 44772017Scg} 44872017Scg 44974763Scgstatic struct pcmchan_caps * 45072017Scgcs4281chan_getcaps(kobj_t obj, void *data) 45172017Scg{ 45272017Scg return &cs4281_caps; 45372017Scg} 45472017Scg 45572017Scgstatic kobj_method_t cs4281chan_methods[] = { 45672017Scg KOBJMETHOD(channel_init, cs4281chan_init), 45772017Scg KOBJMETHOD(channel_setformat, cs4281chan_setformat), 45872017Scg KOBJMETHOD(channel_setspeed, cs4281chan_setspeed), 45972017Scg KOBJMETHOD(channel_setblocksize, cs4281chan_setblocksize), 46072017Scg KOBJMETHOD(channel_trigger, cs4281chan_trigger), 46172017Scg KOBJMETHOD(channel_getptr, cs4281chan_getptr), 46272017Scg KOBJMETHOD(channel_getcaps, cs4281chan_getcaps), 463193640Sariff KOBJMETHOD_END 46472017Scg}; 46572017ScgCHANNEL_DECLARE(cs4281chan); 46672017Scg 46772017Scg/* -------------------------------------------------------------------- */ 46872017Scg/* ADC/DAC control */ 46972017Scg 47072017Scg/* adcdac_go enables/disable DMA channel, returns non-zero if DMA was 47172017Scg * active before call */ 47272017Scg 47372017Scgstatic u_int32_t 47472017Scgadcdac_go(struct sc_chinfo *ch, u_int32_t go) 47572017Scg{ 47672017Scg struct sc_info *sc = ch->parent; 47772017Scg u_int32_t going; 47872455Scg 47972017Scg going = !(cs4281_rd(sc, CS4281PCI_DCR(ch->dma_chan)) & CS4281PCI_DCR_MSK); 48072017Scg 48172455Scg if (go) 48272017Scg cs4281_clr4(sc, CS4281PCI_DCR(ch->dma_chan), CS4281PCI_DCR_MSK); 48372455Scg else 48472017Scg cs4281_set4(sc, CS4281PCI_DCR(ch->dma_chan), CS4281PCI_DCR_MSK); 48572017Scg 48672017Scg cs4281_wr(sc, CS4281PCI_HICR, CS4281PCI_HICR_EOI); 48772017Scg 48872017Scg return going; 48972017Scg} 49072017Scg 49172017Scgstatic void 49272455Scgadcdac_prog(struct sc_chinfo *ch) 49372017Scg{ 49472017Scg struct sc_info *sc = ch->parent; 49572017Scg u_int32_t go; 49672017Scg 49772017Scg if (!ch->dma_setup) { 49872017Scg go = adcdac_go(ch, 0); 49972017Scg cs4281_wr(sc, CS4281PCI_DBA(ch->dma_chan), 500111183Scognet sndbuf_getbufaddr(ch->buffer)); 50172455Scg cs4281_wr(sc, CS4281PCI_DBC(ch->dma_chan), 50272017Scg sndbuf_getsize(ch->buffer) / ch->bps - 1); 50372017Scg ch->dma_setup = 1; 50472017Scg adcdac_go(ch, go); 50572017Scg } 50672017Scg} 50772017Scg 50872017Scg/* -------------------------------------------------------------------- */ 50972017Scg/* The interrupt handler */ 51072017Scg 51172017Scgstatic void 51272017Scgcs4281_intr(void *p) 51372017Scg{ 51472017Scg struct sc_info *sc = (struct sc_info *)p; 51572017Scg u_int32_t hisr; 51672017Scg 51772017Scg hisr = cs4281_rd(sc, CS4281PCI_HISR); 51872455Scg 51972017Scg if (hisr == 0) return; 52072017Scg 52172017Scg if (hisr & CS4281PCI_HISR_DMA(CS4281_DMA_PLAY)) { 52272017Scg chn_intr(sc->pch.channel); 52372017Scg cs4281_rd(sc, CS4281PCI_HDSR(CS4281_DMA_PLAY)); /* Clear interrupt */ 52472017Scg } 52572017Scg 52672017Scg if (hisr & CS4281PCI_HISR_DMA(CS4281_DMA_REC)) { 52772017Scg chn_intr(sc->rch.channel); 52872017Scg cs4281_rd(sc, CS4281PCI_HDSR(CS4281_DMA_REC)); /* Clear interrupt */ 52972017Scg } 53072017Scg 53172017Scg /* Signal End-of-Interrupt */ 53272455Scg cs4281_wr(sc, CS4281PCI_HICR, CS4281PCI_HICR_EOI); 53372017Scg} 53472017Scg 53572017Scg/* -------------------------------------------------------------------- */ 53672455Scg/* power management related */ 53772017Scg 53872017Scgstatic int 53972017Scgcs4281_power(struct sc_info *sc, int state) 54072017Scg{ 54172455Scg 54272017Scg switch (state) { 54372455Scg case 0: 54472455Scg /* Permit r/w access to all BA0 registers */ 54572455Scg cs4281_wr(sc, CS4281PCI_CWPR, CS4281PCI_CWPR_MAGIC); 54672455Scg /* Power on */ 54772455Scg cs4281_clr4(sc, CS4281PCI_EPPMC, CS4281PCI_EPPMC_FPDN); 54872017Scg break; 54972455Scg case 3: 55072455Scg /* Power off card and codec */ 55172455Scg cs4281_set4(sc, CS4281PCI_EPPMC, CS4281PCI_EPPMC_FPDN); 55272455Scg cs4281_clr4(sc, CS4281PCI_SPMC, CS4281PCI_SPMC_RSTN); 55372017Scg break; 55472017Scg } 55572455Scg 55672455Scg DEB(printf("cs4281_power %d -> %d\n", sc->power, state)); 55772017Scg sc->power = state; 55872017Scg 55972017Scg return 0; 56072017Scg} 56172017Scg 56272017Scgstatic int 56372017Scgcs4281_init(struct sc_info *sc) 56472017Scg{ 56572017Scg u_int32_t i, v; 56672017Scg 56772017Scg /* (0) Blast clock register and serial port */ 56872017Scg cs4281_wr(sc, CS4281PCI_CLKCR1, 0); 56972017Scg cs4281_wr(sc, CS4281PCI_SERMC, 0); 57072455Scg 57172017Scg /* (1) Make ESYN 0 to turn sync pulse on AC97 link */ 57272017Scg cs4281_wr(sc, CS4281PCI_ACCTL, 0); 57372017Scg DELAY(50); 57472017Scg 57572017Scg /* (2) Effect Reset */ 57672017Scg cs4281_wr(sc, CS4281PCI_SPMC, 0); 57772017Scg DELAY(100); 57872017Scg cs4281_wr(sc, CS4281PCI_SPMC, CS4281PCI_SPMC_RSTN); 57972017Scg /* Wait 50ms for ABITCLK to become stable */ 58072455Scg DELAY(50000); 58172017Scg 58272017Scg /* (3) Enable Sound System Clocks */ 58372455Scg cs4281_wr(sc, CS4281PCI_CLKCR1, CS4281PCI_CLKCR1_DLLP); 58472017Scg DELAY(50000); /* Wait for PLL to stabilize */ 58572455Scg cs4281_wr(sc, CS4281PCI_CLKCR1, 58672455Scg CS4281PCI_CLKCR1_DLLP | CS4281PCI_CLKCR1_SWCE); 58772017Scg 58872017Scg /* (4) Power Up - this combination is essential. */ 58972455Scg cs4281_set4(sc, CS4281PCI_SSPM, 59072017Scg CS4281PCI_SSPM_ACLEN | CS4281PCI_SSPM_PSRCEN | 59172017Scg CS4281PCI_SSPM_CSRCEN | CS4281PCI_SSPM_MIXEN); 59272017Scg 59372017Scg /* (5) Wait for clock stabilization */ 59472455Scg if (cs4281_waitset(sc, 59572455Scg CS4281PCI_CLKCR1, 59672455Scg CS4281PCI_CLKCR1_DLLRDY, 59772017Scg 250) == 0) { 59872017Scg device_printf(sc->dev, "Clock stabilization failed\n"); 59972017Scg return -1; 60072017Scg } 60172017Scg 60272017Scg /* (6) Enable ASYNC generation. */ 60372455Scg cs4281_wr(sc, CS4281PCI_ACCTL,CS4281PCI_ACCTL_ESYN); 60472017Scg 60572017Scg /* Wait to allow AC97 to start generating clock bit */ 60672017Scg DELAY(50000); 60772017Scg 60872017Scg /* Set AC97 timing */ 60972017Scg cs4281_wr(sc, CS4281PCI_SERMC, CS4281PCI_SERMC_PTC_AC97); 61072017Scg 61172017Scg /* (7) Wait for AC97 ready signal */ 61272017Scg if (cs4281_waitset(sc, CS4281PCI_ACSTS, CS4281PCI_ACSTS_CRDY, 250) == 0) { 61372017Scg device_printf(sc->dev, "codec did not avail\n"); 61472017Scg return -1; 61572455Scg } 61672017Scg 61772017Scg /* (8) Assert valid frame signal to begin sending commands to 61872017Scg * AC97 codec */ 61972455Scg cs4281_wr(sc, 62072455Scg CS4281PCI_ACCTL, 62172017Scg CS4281PCI_ACCTL_VFRM | CS4281PCI_ACCTL_ESYN); 62272017Scg 62372017Scg /* (9) Wait for codec calibration */ 62472017Scg for(i = 0 ; i < 1000; i++) { 62572017Scg DELAY(10000); 62672017Scg v = cs4281_rdcd(0, sc, AC97_REG_POWER); 62772017Scg if ((v & 0x0f) == 0x0f) { 62872017Scg break; 62972017Scg } 63072017Scg } 63172017Scg if (i == 1000) { 63272017Scg device_printf(sc->dev, "codec failed to calibrate\n"); 63372017Scg return -1; 63472017Scg } 63572017Scg 63672017Scg /* (10) Set AC97 timing */ 63772017Scg cs4281_wr(sc, CS4281PCI_SERMC, CS4281PCI_SERMC_PTC_AC97); 63872017Scg 63972017Scg /* (11) Wait for valid data to arrive */ 64072455Scg if (cs4281_waitset(sc, 64172455Scg CS4281PCI_ACISV, 64272455Scg CS4281PCI_ACISV_ISV(3) | CS4281PCI_ACISV_ISV(4), 64372017Scg 10000) == 0) { 64472017Scg device_printf(sc->dev, "cs4281 never got valid data\n"); 64572017Scg return -1; 64672455Scg } 64772017Scg 64872017Scg /* (12) Start digital data transfer of audio data to codec */ 64972455Scg cs4281_wr(sc, 65072455Scg CS4281PCI_ACOSV, 65172017Scg CS4281PCI_ACOSV_SLV(3) | CS4281PCI_ACOSV_SLV(4)); 65272017Scg 65372017Scg /* Set Master and headphone to max */ 654102302Sorion cs4281_wrcd(0, sc, AC97_MIX_AUXOUT, 0); 65572017Scg cs4281_wrcd(0, sc, AC97_MIX_MASTER, 0); 65672017Scg 65772017Scg /* Power on the DAC */ 65872017Scg v = cs4281_rdcd(0, sc, AC97_REG_POWER) & 0xfdff; 65972455Scg cs4281_wrcd(0, sc, AC97_REG_POWER, v); 66072017Scg 66172017Scg /* Wait until DAC state ready */ 66272017Scg for(i = 0; i < 320; i++) { 66372017Scg DELAY(100); 66472017Scg v = cs4281_rdcd(0, sc, AC97_REG_POWER); 66572017Scg if (v & 0x02) break; 66672017Scg } 66772017Scg 66872017Scg /* Power on the ADC */ 66972017Scg v = cs4281_rdcd(0, sc, AC97_REG_POWER) & 0xfeff; 67072455Scg cs4281_wrcd(0, sc, AC97_REG_POWER, v); 67172017Scg 67272017Scg /* Wait until ADC state ready */ 67372017Scg for(i = 0; i < 320; i++) { 67472017Scg DELAY(100); 67572017Scg v = cs4281_rdcd(0, sc, AC97_REG_POWER); 67672017Scg if (v & 0x01) break; 67772017Scg } 67872017Scg 67972017Scg /* FIFO configuration (driver is DMA orientated, implicit FIFO) */ 68072017Scg /* Play FIFO */ 68172017Scg 68272017Scg v = CS4281PCI_FCR_RS(CS4281PCI_RPCM_PLAY_SLOT) | 68372017Scg CS4281PCI_FCR_LS(CS4281PCI_LPCM_PLAY_SLOT) | 68472017Scg CS4281PCI_FCR_SZ(CS4281_FIFO_SIZE)| 68572017Scg CS4281PCI_FCR_OF(0); 68672017Scg cs4281_wr(sc, CS4281PCI_FCR(CS4281_DMA_PLAY), v); 68772017Scg 68872017Scg cs4281_wr(sc, CS4281PCI_FCR(CS4281_DMA_PLAY), v | CS4281PCI_FCR_FEN); 68972017Scg 69072017Scg /* Record FIFO */ 69172017Scg v = CS4281PCI_FCR_RS(CS4281PCI_RPCM_REC_SLOT) | 69272017Scg CS4281PCI_FCR_LS(CS4281PCI_LPCM_REC_SLOT) | 69372017Scg CS4281PCI_FCR_SZ(CS4281_FIFO_SIZE)| 69472017Scg CS4281PCI_FCR_OF(CS4281_FIFO_SIZE + 1); 69572017Scg cs4281_wr(sc, CS4281PCI_FCR(CS4281_DMA_REC), v | CS4281PCI_FCR_PSH); 69672017Scg cs4281_wr(sc, CS4281PCI_FCR(CS4281_DMA_REC), v | CS4281PCI_FCR_FEN); 69772017Scg 69872017Scg /* Match AC97 slots to FIFOs */ 69972017Scg v = CS4281PCI_SRCSA_PLSS(CS4281PCI_LPCM_PLAY_SLOT) | 70072017Scg CS4281PCI_SRCSA_PRSS(CS4281PCI_RPCM_PLAY_SLOT) | 70172017Scg CS4281PCI_SRCSA_CLSS(CS4281PCI_LPCM_REC_SLOT) | 70272017Scg CS4281PCI_SRCSA_CRSS(CS4281PCI_RPCM_REC_SLOT); 70372017Scg cs4281_wr(sc, CS4281PCI_SRCSA, v); 70472017Scg 70572017Scg /* Set Auto-Initialize and set directions */ 70672017Scg cs4281_wr(sc, 70772017Scg CS4281PCI_DMR(CS4281_DMA_PLAY), 70872017Scg CS4281PCI_DMR_DMA | 70972017Scg CS4281PCI_DMR_AUTO | 71072017Scg CS4281PCI_DMR_TR_PLAY); 71172017Scg cs4281_wr(sc, 71272017Scg CS4281PCI_DMR(CS4281_DMA_REC), 71372017Scg CS4281PCI_DMR_DMA | 71472017Scg CS4281PCI_DMR_AUTO | 71572017Scg CS4281PCI_DMR_TR_REC); 71672017Scg 71772017Scg /* Enable half and empty buffer interrupts keeping DMA paused */ 71872017Scg cs4281_wr(sc, 71972017Scg CS4281PCI_DCR(CS4281_DMA_PLAY), 72072017Scg CS4281PCI_DCR_TCIE | CS4281PCI_DCR_HTCIE | CS4281PCI_DCR_MSK); 72172017Scg cs4281_wr(sc, 72272017Scg CS4281PCI_DCR(CS4281_DMA_REC), 72372017Scg CS4281PCI_DCR_TCIE | CS4281PCI_DCR_HTCIE | CS4281PCI_DCR_MSK); 72472455Scg 72572017Scg /* Enable Interrupts */ 72672455Scg cs4281_clr4(sc, 72772455Scg CS4281PCI_HIMR, 72872017Scg CS4281PCI_HIMR_DMAI | 72972017Scg CS4281PCI_HIMR_DMA(CS4281_DMA_PLAY) | 73072017Scg CS4281PCI_HIMR_DMA(CS4281_DMA_REC)); 73172017Scg 73272017Scg /* Set playback volume */ 73372017Scg cs4281_wr(sc, CS4281PCI_PPLVC, 7); 73472017Scg cs4281_wr(sc, CS4281PCI_PPRVC, 7); 73572017Scg 73672017Scg return 0; 73772017Scg} 73872017Scg 73972017Scg/* -------------------------------------------------------------------- */ 74072017Scg/* Probe and attach the card */ 74172017Scg 74272017Scgstatic int 74372017Scgcs4281_pci_probe(device_t dev) 74472017Scg{ 74572017Scg char *s = NULL; 74672017Scg 74772017Scg switch (pci_get_devid(dev)) { 74872017Scg case CS4281_PCI_ID: 74972017Scg s = "Crystal Semiconductor CS4281"; 75072017Scg break; 75172017Scg } 75272017Scg 75372017Scg if (s) 75472017Scg device_set_desc(dev, s); 755142890Simp return s ? BUS_PROBE_DEFAULT : ENXIO; 75672017Scg} 75772017Scg 75872017Scgstatic int 75972017Scgcs4281_pci_attach(device_t dev) 76072017Scg{ 76172017Scg struct sc_info *sc; 76272017Scg struct ac97_info *codec = NULL; 76372017Scg char status[SND_STATUSLEN]; 76472017Scg 765170873Sariff sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 76672017Scg sc->dev = dev; 76772017Scg sc->type = pci_get_devid(dev); 76872017Scg 769254306Sscottl pci_enable_busmaster(dev); 77072017Scg 77173770Scg#if __FreeBSD_version > 500000 77272455Scg if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 77372455Scg /* Reset the power state. */ 77472455Scg device_printf(dev, "chip is in D%d power mode " 77572455Scg "-- setting to D0\n", pci_get_powerstate(dev)); 77672455Scg 77772455Scg pci_set_powerstate(dev, PCI_POWERSTATE_D0); 77872455Scg } 77975702Sorion#else 78075702Sorion data = pci_read_config(dev, CS4281PCI_PMCS_OFFSET, 4); 78175702Sorion if (data & CS4281PCI_PMCS_PS_MASK) { 78275702Sorion /* Reset the power state. */ 78375702Sorion device_printf(dev, "chip is in D%d power mode " 78478362Scg "-- setting to D0\n", 78575702Sorion data & CS4281PCI_PMCS_PS_MASK); 78675702Sorion pci_write_config(dev, CS4281PCI_PMCS_OFFSET, 78775702Sorion data & ~CS4281PCI_PMCS_PS_MASK, 4); 78875702Sorion } 78973770Scg#endif 79075702Sorion 791119690Sjhb sc->regid = PCIR_BAR(0); 79272017Scg sc->regtype = SYS_RES_MEMORY; 79372017Scg sc->reg = bus_alloc_resource(dev, sc->regtype, &sc->regid, 79472017Scg 0, ~0, CS4281PCI_BA0_SIZE, RF_ACTIVE); 79572017Scg if (!sc->reg) { 79672017Scg sc->regtype = SYS_RES_IOPORT; 79772017Scg sc->reg = bus_alloc_resource(dev, sc->regtype, &sc->regid, 79872017Scg 0, ~0, CS4281PCI_BA0_SIZE, RF_ACTIVE); 79972017Scg if (!sc->reg) { 80072017Scg device_printf(dev, "unable to allocate register space\n"); 80172017Scg goto bad; 80272017Scg } 80372017Scg } 80472017Scg sc->st = rman_get_bustag(sc->reg); 80572017Scg sc->sh = rman_get_bushandle(sc->reg); 80672017Scg 807119690Sjhb sc->memid = PCIR_BAR(1); 80872455Scg sc->mem = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->memid, 0, 80972017Scg ~0, CS4281PCI_BA1_SIZE, RF_ACTIVE); 81072017Scg if (sc->mem == NULL) { 81172017Scg device_printf(dev, "unable to allocate fifo space\n"); 81272017Scg goto bad; 81372017Scg } 81472017Scg 81572017Scg sc->irqid = 0; 816127135Snjl sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 817127135Snjl RF_ACTIVE | RF_SHAREABLE); 81872017Scg if (!sc->irq) { 81972017Scg device_printf(dev, "unable to allocate interrupt\n"); 82072017Scg goto bad; 82172017Scg } 82272017Scg 82374763Scg if (snd_setup_intr(dev, sc->irq, 0, cs4281_intr, sc, &sc->ih)) { 82472017Scg device_printf(dev, "unable to setup interrupt\n"); 82572017Scg goto bad; 82672017Scg } 82772017Scg 82884771Sorion sc->bufsz = pcm_getbuffersize(dev, 4096, CS4281_DEFAULT_BUFSZ, 65536); 82984771Sorion 830166904Snetchild if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 831166904Snetchild /*boundary*/0, 83272017Scg /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 83372017Scg /*highaddr*/BUS_SPACE_MAXADDR, 83472017Scg /*filter*/NULL, /*filterarg*/NULL, 83584771Sorion /*maxsize*/sc->bufsz, /*nsegments*/1, 83672017Scg /*maxsegz*/0x3ffff, 837117126Sscottl /*flags*/0, /*lockfunc*/busdma_lock_mutex, 838117126Sscottl /*lockarg*/&Giant, &sc->parent_dmat) != 0) { 83972017Scg device_printf(dev, "unable to create dma tag\n"); 84072017Scg goto bad; 84172017Scg } 84272017Scg 84372017Scg /* power up */ 84472017Scg cs4281_power(sc, 0); 84572017Scg 84672017Scg /* init chip */ 84772017Scg if (cs4281_init(sc) == -1) { 84872017Scg device_printf(dev, "unable to initialize the card\n"); 84972017Scg goto bad; 85072017Scg } 85172017Scg 85272017Scg /* create/init mixer */ 85372017Scg codec = AC97_CREATE(dev, sc, cs4281_ac97); 85472017Scg if (codec == NULL) 85572017Scg goto bad; 85672017Scg 85772017Scg mixer_init(dev, ac97_getmixerclass(), codec); 85872017Scg 85972017Scg if (pcm_register(dev, sc, 1, 1)) 86072017Scg goto bad; 86172017Scg 86272017Scg pcm_addchan(dev, PCMDIR_PLAY, &cs4281chan_class, sc); 86372017Scg pcm_addchan(dev, PCMDIR_REC, &cs4281chan_class, sc); 86472017Scg 865126695Smatk snprintf(status, SND_STATUSLEN, "at %s 0x%lx irq %ld %s", 86672017Scg (sc->regtype == SYS_RES_IOPORT)? "io" : "memory", 867126695Smatk rman_get_start(sc->reg), rman_get_start(sc->irq),PCM_KLDSTRING(snd_cs4281)); 86872017Scg pcm_setstatus(dev, status); 86972017Scg 87072017Scg return 0; 87172017Scg 87272017Scg bad: 87372017Scg if (codec) 87472017Scg ac97_destroy(codec); 87572017Scg if (sc->reg) 87672017Scg bus_release_resource(dev, sc->regtype, sc->regid, sc->reg); 87772017Scg if (sc->mem) 87872017Scg bus_release_resource(dev, SYS_RES_MEMORY, sc->memid, sc->mem); 87972017Scg if (sc->ih) 88072017Scg bus_teardown_intr(dev, sc->irq, sc->ih); 88172017Scg if (sc->irq) 88272017Scg bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 88372017Scg if (sc->parent_dmat) 88472017Scg bus_dma_tag_destroy(sc->parent_dmat); 88572017Scg free(sc, M_DEVBUF); 88672017Scg 88772017Scg return ENXIO; 88872017Scg} 88972017Scg 89072017Scgstatic int 89172017Scgcs4281_pci_detach(device_t dev) 89272017Scg{ 89372017Scg int r; 89472017Scg struct sc_info *sc; 89572017Scg 89672017Scg r = pcm_unregister(dev); 89772017Scg if (r) 89872017Scg return r; 89972017Scg 90072017Scg sc = pcm_getdevinfo(dev); 90172017Scg 90272017Scg /* power off */ 90372017Scg cs4281_power(sc, 3); 90472017Scg 90572017Scg bus_release_resource(dev, sc->regtype, sc->regid, sc->reg); 90672017Scg bus_release_resource(dev, SYS_RES_MEMORY, sc->memid, sc->mem); 90772017Scg bus_teardown_intr(dev, sc->irq, sc->ih); 90872017Scg bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 90972017Scg bus_dma_tag_destroy(sc->parent_dmat); 91072017Scg free(sc, M_DEVBUF); 91172017Scg 91272017Scg return 0; 91372017Scg} 91472017Scg 91572017Scgstatic int 91672017Scgcs4281_pci_suspend(device_t dev) 91772017Scg{ 91872017Scg struct sc_info *sc; 91972017Scg 92072017Scg sc = pcm_getdevinfo(dev); 92172017Scg 92272455Scg sc->rch.dma_active = adcdac_go(&sc->rch, 0); 92372455Scg sc->pch.dma_active = adcdac_go(&sc->pch, 0); 92472017Scg 92572455Scg cs4281_power(sc, 3); 92672455Scg 92772017Scg return 0; 92872017Scg} 92972017Scg 93072017Scgstatic int 93172017Scgcs4281_pci_resume(device_t dev) 93272017Scg{ 93372017Scg struct sc_info *sc; 93472017Scg 93572017Scg sc = pcm_getdevinfo(dev); 93672017Scg 93772017Scg /* power up */ 93872455Scg cs4281_power(sc, 0); 93972017Scg 94072455Scg /* initialize chip */ 94172455Scg if (cs4281_init(sc) == -1) { 94272455Scg device_printf(dev, "unable to reinitialize the card\n"); 94372455Scg return ENXIO; 94472017Scg } 94572017Scg 94672017Scg /* restore mixer state */ 94772017Scg if (mixer_reinit(dev) == -1) { 94872017Scg device_printf(dev, "unable to reinitialize the mixer\n"); 94972017Scg return ENXIO; 95072017Scg } 95172017Scg 95272455Scg /* restore chip state */ 95372455Scg cs4281chan_setspeed(NULL, &sc->rch, sc->rch.spd); 95472455Scg cs4281chan_setblocksize(NULL, &sc->rch, sc->rch.blksz); 95572455Scg cs4281chan_setformat(NULL, &sc->rch, sc->rch.fmt); 95672455Scg adcdac_go(&sc->rch, sc->rch.dma_active); 95772455Scg 95872455Scg cs4281chan_setspeed(NULL, &sc->pch, sc->pch.spd); 95972455Scg cs4281chan_setblocksize(NULL, &sc->pch, sc->pch.blksz); 96072455Scg cs4281chan_setformat(NULL, &sc->pch, sc->pch.fmt); 96172455Scg adcdac_go(&sc->pch, sc->pch.dma_active); 96272455Scg 96372017Scg return 0; 96472017Scg} 96572017Scg 96672017Scgstatic device_method_t cs4281_methods[] = { 96772017Scg /* Device interface */ 96872017Scg DEVMETHOD(device_probe, cs4281_pci_probe), 96972017Scg DEVMETHOD(device_attach, cs4281_pci_attach), 97072017Scg DEVMETHOD(device_detach, cs4281_pci_detach), 97172017Scg DEVMETHOD(device_suspend, cs4281_pci_suspend), 97272017Scg DEVMETHOD(device_resume, cs4281_pci_resume), 97372017Scg { 0, 0 } 97472017Scg}; 97572017Scg 97672017Scgstatic driver_t cs4281_driver = { 97772017Scg "pcm", 97872017Scg cs4281_methods, 97982180Scg PCM_SOFTC_SIZE, 98072017Scg}; 98172017Scg 98272017ScgDRIVER_MODULE(snd_cs4281, pci, cs4281_driver, pcm_devclass, 0, 0); 983132236StanimuraMODULE_DEPEND(snd_cs4281, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 98472017ScgMODULE_VERSION(snd_cs4281, 1); 985