ds1.c revision 111183
1251881Speter/* 2251881Speter * Copyright (c) 2000 Cameron Grant <cg@freebsd.org> 3251881Speter * All rights reserved. 4251881Speter * 5251881Speter * Redistribution and use in source and binary forms, with or without 6251881Speter * modification, are permitted provided that the following conditions 7251881Speter * are met: 8251881Speter * 1. Redistributions of source code must retain the above copyright 9251881Speter * notice, this list of conditions and the following disclaimer. 10251881Speter * 2. Redistributions in binary form must reproduce the above copyright 11251881Speter * notice, this list of conditions and the following disclaimer in the 12251881Speter * documentation and/or other materials provided with the distribution. 13251881Speter * 14251881Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17251881Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 22251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 24251881Speter * SUCH DAMAGE. 25251881Speter */ 26251881Speter 27251881Speter#include <dev/sound/pcm/sound.h> 28251881Speter#include <dev/sound/pcm/ac97.h> 29251881Speter 30251881Speter#include <pci/pcireg.h> 31251881Speter#include <pci/pcivar.h> 32251881Speter 33251881Speter#include <dev/sound/pci/ds1.h> 34251881Speter#include <dev/sound/pci/ds1-fw.h> 35251881Speter 36251881SpeterSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/ds1.c 111183 2003-02-20 17:31:12Z cognet $"); 37251881Speter 38251881Speter/* -------------------------------------------------------------------- */ 39251881Speter 40251881Speter#define DS1_CHANS 4 41251881Speter#define DS1_RECPRIMARY 0 42251881Speter#define DS1_IRQHZ ((48000 << 8) / 256) 43251881Speter#define DS1_BUFFSIZE 4096 44251881Speter 45251881Speterstruct pbank { 46251881Speter volatile u_int32_t Format; 47251881Speter volatile u_int32_t LoopDefault; 48251881Speter volatile u_int32_t PgBase; 49251881Speter volatile u_int32_t PgLoop; 50251881Speter volatile u_int32_t PgLoopEnd; 51251881Speter volatile u_int32_t PgLoopFrac; 52251881Speter volatile u_int32_t PgDeltaEnd; 53251881Speter volatile u_int32_t LpfKEnd; 54251881Speter volatile u_int32_t EgGainEnd; 55251881Speter volatile u_int32_t LchGainEnd; 56251881Speter volatile u_int32_t RchGainEnd; 57251881Speter volatile u_int32_t Effect1GainEnd; 58251881Speter volatile u_int32_t Effect2GainEnd; 59251881Speter volatile u_int32_t Effect3GainEnd; 60251881Speter volatile u_int32_t LpfQ; 61251881Speter volatile u_int32_t Status; 62251881Speter volatile u_int32_t NumOfFrames; 63251881Speter volatile u_int32_t LoopCount; 64251881Speter volatile u_int32_t PgStart; 65251881Speter volatile u_int32_t PgStartFrac; 66251881Speter volatile u_int32_t PgDelta; 67251881Speter volatile u_int32_t LpfK; 68251881Speter volatile u_int32_t EgGain; 69251881Speter volatile u_int32_t LchGain; 70251881Speter volatile u_int32_t RchGain; 71251881Speter volatile u_int32_t Effect1Gain; 72251881Speter volatile u_int32_t Effect2Gain; 73251881Speter volatile u_int32_t Effect3Gain; 74251881Speter volatile u_int32_t LpfD1; 75251881Speter volatile u_int32_t LpfD2; 76251881Speter}; 77251881Speter 78251881Speterstruct rbank { 79251881Speter volatile u_int32_t PgBase; 80251881Speter volatile u_int32_t PgLoopEnd; 81251881Speter volatile u_int32_t PgStart; 82251881Speter volatile u_int32_t NumOfLoops; 83251881Speter}; 84251881Speter 85251881Speterstruct sc_info; 86251881Speter 87251881Speter/* channel registers */ 88251881Speterstruct sc_pchinfo { 89251881Speter int run, spd, dir, fmt; 90251881Speter struct snd_dbuf *buffer; 91251881Speter struct pcm_channel *channel; 92251881Speter volatile struct pbank *lslot, *rslot; 93251881Speter int lsnum, rsnum; 94251881Speter struct sc_info *parent; 95251881Speter}; 96251881Speter 97251881Speterstruct sc_rchinfo { 98251881Speter int run, spd, dir, fmt, num; 99251881Speter struct snd_dbuf *buffer; 100251881Speter struct pcm_channel *channel; 101251881Speter volatile struct rbank *slot; 102251881Speter struct sc_info *parent; 103251881Speter}; 104251881Speter 105251881Speter/* device private data */ 106251881Speterstruct sc_info { 107251881Speter device_t dev; 108251881Speter u_int32_t type, rev; 109251881Speter u_int32_t cd2id, ctrlbase; 110251881Speter 111251881Speter bus_space_tag_t st; 112251881Speter bus_space_handle_t sh; 113251881Speter bus_dma_tag_t buffer_dmat, control_dmat; 114251881Speter bus_dmamap_t map; 115251881Speter 116251881Speter struct resource *reg, *irq; 117251881Speter int regid, irqid; 118251881Speter void *ih; 119251881Speter struct mtx *lock; 120251881Speter 121251881Speter void *regbase; 122251881Speter u_int32_t *pbase, pbankbase, pbanksize; 123251881Speter volatile struct pbank *pbank[2 * 64]; 124251881Speter volatile struct rbank *rbank; 125251881Speter int pslotfree, currbank, pchn, rchn; 126251881Speter unsigned int bufsz; 127251881Speter 128251881Speter struct sc_pchinfo pch[DS1_CHANS]; 129251881Speter struct sc_rchinfo rch[2]; 130251881Speter}; 131251881Speter 132251881Speterstruct { 133251881Speter u_int32_t dev, subdev; 134251881Speter char *name; 135251881Speter u_int32_t *mcode; 136251881Speter} ds_devs[] = { 137251881Speter {0x00041073, 0, "Yamaha DS-1 (YMF724)", CntrlInst}, 138251881Speter {0x000d1073, 0, "Yamaha DS-1E (YMF724F)", CntrlInst1E}, 139251881Speter {0x00051073, 0, "Yamaha DS-1? (YMF734)", CntrlInst}, 140251881Speter {0x00081073, 0, "Yamaha DS-1? (YMF737)", CntrlInst}, 141251881Speter {0x00201073, 0, "Yamaha DS-1? (YMF738)", CntrlInst}, 142251881Speter {0x00061073, 0, "Yamaha DS-1? (YMF738_TEG)", CntrlInst}, 143251881Speter {0x000a1073, 0x00041073, "Yamaha DS-1 (YMF740)", CntrlInst}, 144251881Speter {0x000a1073, 0x000a1073, "Yamaha DS-1 (YMF740B)", CntrlInst}, 145251881Speter {0x000a1073, 0x53328086, "Yamaha DS-1 (YMF740I)", CntrlInst}, 146251881Speter {0x000a1073, 0, "Yamaha DS-1 (YMF740?)", CntrlInst}, 147251881Speter {0x000c1073, 0, "Yamaha DS-1E (YMF740C)", CntrlInst1E}, 148251881Speter {0x00101073, 0, "Yamaha DS-1E (YMF744)", CntrlInst1E}, 149251881Speter {0x00121073, 0, "Yamaha DS-1E (YMF754)", CntrlInst1E}, 150251881Speter {0, 0, NULL, NULL} 151251881Speter}; 152251881Speter 153251881Speter/* -------------------------------------------------------------------- */ 154251881Speter 155251881Speter/* 156251881Speter * prototypes 157251881Speter */ 158251881Speter 159251881Speter/* stuff */ 160251881Speterstatic int ds_init(struct sc_info *); 161251881Speterstatic void ds_intr(void *); 162251881Speter 163251881Speter/* talk to the card */ 164251881Speterstatic u_int32_t ds_rd(struct sc_info *, int, int); 165251881Speterstatic void ds_wr(struct sc_info *, int, u_int32_t, int); 166251881Speter 167251881Speter/* -------------------------------------------------------------------- */ 168251881Speter 169251881Speterstatic u_int32_t ds_recfmt[] = { 170251881Speter AFMT_U8, 171251881Speter AFMT_STEREO | AFMT_U8, 172251881Speter AFMT_S8, 173251881Speter AFMT_STEREO | AFMT_S8, 174251881Speter AFMT_S16_LE, 175251881Speter AFMT_STEREO | AFMT_S16_LE, 176251881Speter AFMT_U16_LE, 177251881Speter AFMT_STEREO | AFMT_U16_LE, 178251881Speter 0 179251881Speter}; 180251881Speterstatic struct pcmchan_caps ds_reccaps = {4000, 48000, ds_recfmt, 0}; 181251881Speter 182251881Speterstatic u_int32_t ds_playfmt[] = { 183251881Speter AFMT_U8, 184251881Speter AFMT_STEREO | AFMT_U8, 185251881Speter /* AFMT_S16_LE, */ 186251881Speter AFMT_STEREO | AFMT_S16_LE, 187251881Speter 0 188251881Speter}; 189251881Speterstatic struct pcmchan_caps ds_playcaps = {4000, 96000, ds_playfmt, 0}; 190251881Speter 191251881Speter/* -------------------------------------------------------------------- */ 192251881Speter/* Hardware */ 193251881Speterstatic u_int32_t 194251881Speterds_rd(struct sc_info *sc, int regno, int size) 195251881Speter{ 196251881Speter switch (size) { 197251881Speter case 1: 198251881Speter return bus_space_read_1(sc->st, sc->sh, regno); 199251881Speter case 2: 200251881Speter return bus_space_read_2(sc->st, sc->sh, regno); 201251881Speter case 4: 202251881Speter return bus_space_read_4(sc->st, sc->sh, regno); 203251881Speter default: 204251881Speter return 0xffffffff; 205251881Speter } 206251881Speter} 207251881Speter 208251881Speterstatic void 209251881Speterds_wr(struct sc_info *sc, int regno, u_int32_t data, int size) 210251881Speter{ 211251881Speter switch (size) { 212251881Speter case 1: 213251881Speter bus_space_write_1(sc->st, sc->sh, regno, data); 214251881Speter break; 215251881Speter case 2: 216251881Speter bus_space_write_2(sc->st, sc->sh, regno, data); 217251881Speter break; 218251881Speter case 4: 219251881Speter bus_space_write_4(sc->st, sc->sh, regno, data); 220251881Speter break; 221251881Speter } 222251881Speter} 223251881Speter 224251881Speterstatic void 225251881Speterwrl(struct sc_info *sc, u_int32_t *ptr, u_int32_t val) 226251881Speter{ 227251881Speter *(volatile u_int32_t *)ptr = val; 228251881Speter bus_space_barrier(sc->st, sc->sh, 0, 0, BUS_SPACE_BARRIER_WRITE); 229251881Speter} 230251881Speter 231251881Speter/* -------------------------------------------------------------------- */ 232251881Speter/* ac97 codec */ 233251881Speterstatic int 234251881Speterds_cdbusy(struct sc_info *sc, int sec) 235251881Speter{ 236251881Speter int i, reg; 237251881Speter 238251881Speter reg = sec? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR; 239251881Speter i = YDSXG_AC97TIMEOUT; 240251881Speter while (i > 0) { 241251881Speter if (!(ds_rd(sc, reg, 2) & 0x8000)) 242251881Speter return 0; 243251881Speter i--; 244251881Speter } 245251881Speter return ETIMEDOUT; 246251881Speter} 247251881Speter 248251881Speterstatic u_int32_t 249251881Speterds_initcd(kobj_t obj, void *devinfo) 250251881Speter{ 251251881Speter struct sc_info *sc = (struct sc_info *)devinfo; 252251881Speter u_int32_t x; 253251881Speter 254251881Speter x = pci_read_config(sc->dev, PCIR_DSXGCTRL, 1); 255251881Speter if (x & 0x03) { 256251881Speter pci_write_config(sc->dev, PCIR_DSXGCTRL, x & ~0x03, 1); 257251881Speter pci_write_config(sc->dev, PCIR_DSXGCTRL, x | 0x03, 1); 258251881Speter pci_write_config(sc->dev, PCIR_DSXGCTRL, x & ~0x03, 1); 259251881Speter /* 260251881Speter * The YMF740 on some Intel motherboards requires a pretty 261251881Speter * hefty delay after this reset for some reason... Otherwise: 262251881Speter * "pcm0: ac97 codec init failed" 263251881Speter * Maybe this is needed for all YMF740's? 264251881Speter * 400ms and 500ms here seem to work, 300ms does not. 265251881Speter * 266251881Speter * do it for all chips -cg 267251881Speter */ 268251881Speter DELAY(500000); 269251881Speter } 270251881Speter 271251881Speter return ds_cdbusy(sc, 0)? 0 : 1; 272251881Speter} 273251881Speter 274251881Speterstatic int 275251881Speterds_rdcd(kobj_t obj, void *devinfo, int regno) 276251881Speter{ 277251881Speter struct sc_info *sc = (struct sc_info *)devinfo; 278251881Speter int sec, cid, i; 279251881Speter u_int32_t cmd, reg; 280251881Speter 281251881Speter sec = regno & 0x100; 282251881Speter regno &= 0xff; 283251881Speter cid = sec? (sc->cd2id << 8) : 0; 284251881Speter reg = sec? YDSXGR_SECSTATUSDATA : YDSXGR_PRISTATUSDATA; 285251881Speter if (sec && cid == 0) 286251881Speter return 0xffffffff; 287251881Speter 288251881Speter cmd = YDSXG_AC97READCMD | cid | regno; 289251881Speter ds_wr(sc, YDSXGR_AC97CMDADR, cmd, 2); 290251881Speter 291251881Speter if (ds_cdbusy(sc, sec)) 292251881Speter return 0xffffffff; 293251881Speter 294251881Speter if (sc->type == 11 && sc->rev < 2) 295251881Speter for (i = 0; i < 600; i++) 296251881Speter ds_rd(sc, reg, 2); 297251881Speter 298251881Speter return ds_rd(sc, reg, 2); 299251881Speter} 300251881Speter 301251881Speterstatic int 302251881Speterds_wrcd(kobj_t obj, void *devinfo, int regno, u_int32_t data) 303251881Speter{ 304251881Speter struct sc_info *sc = (struct sc_info *)devinfo; 305251881Speter int sec, cid; 306251881Speter u_int32_t cmd; 307251881Speter 308251881Speter sec = regno & 0x100; 309251881Speter regno &= 0xff; 310251881Speter cid = sec? (sc->cd2id << 8) : 0; 311251881Speter if (sec && cid == 0) 312251881Speter return ENXIO; 313251881Speter 314251881Speter cmd = YDSXG_AC97WRITECMD | cid | regno; 315251881Speter cmd <<= 16; 316251881Speter cmd |= data; 317251881Speter ds_wr(sc, YDSXGR_AC97CMDDATA, cmd, 4); 318251881Speter 319251881Speter return ds_cdbusy(sc, sec); 320251881Speter} 321251881Speter 322251881Speterstatic kobj_method_t ds_ac97_methods[] = { 323251881Speter KOBJMETHOD(ac97_init, ds_initcd), 324251881Speter KOBJMETHOD(ac97_read, ds_rdcd), 325251881Speter KOBJMETHOD(ac97_write, ds_wrcd), 326251881Speter { 0, 0 } 327251881Speter}; 328251881SpeterAC97_DECLARE(ds_ac97); 329251881Speter 330251881Speter/* -------------------------------------------------------------------- */ 331251881Speter 332251881Speterstatic void 333251881Speterds_enadsp(struct sc_info *sc, int on) 334251881Speter{ 335251881Speter u_int32_t v, i; 336251881Speter 337251881Speter v = on? 1 : 0; 338251881Speter if (on) { 339251881Speter ds_wr(sc, YDSXGR_CONFIG, 0x00000001, 4); 340251881Speter } else { 341251881Speter if (ds_rd(sc, YDSXGR_CONFIG, 4)) 342251881Speter ds_wr(sc, YDSXGR_CONFIG, 0x00000000, 4); 343251881Speter i = YDSXG_WORKBITTIMEOUT; 344251881Speter while (i > 0) { 345251881Speter if (!(ds_rd(sc, YDSXGR_CONFIG, 4) & 0x00000002)) 346251881Speter break; 347251881Speter i--; 348251881Speter } 349251881Speter } 350251881Speter} 351251881Speter 352251881Speterstatic volatile struct pbank * 353251881Speterds_allocpslot(struct sc_info *sc) 354251881Speter{ 355251881Speter int slot; 356251881Speter 357251881Speter if (sc->pslotfree > 63) 358251881Speter return NULL; 359251881Speter slot = sc->pslotfree++; 360251881Speter return sc->pbank[slot * 2]; 361251881Speter} 362251881Speter 363251881Speterstatic int 364251881Speterds_initpbank(volatile struct pbank *pb, int ch, int b16, int stereo, u_int32_t rate, bus_addr_t base, u_int32_t len) 365251881Speter{ 366251881Speter u_int32_t lv[] = {1, 1, 0, 0, 0}; 367251881Speter u_int32_t rv[] = {1, 0, 1, 0, 0}; 368251881Speter u_int32_t e1[] = {0, 0, 0, 0, 0}; 369251881Speter u_int32_t e2[] = {1, 0, 0, 1, 0}; 370251881Speter u_int32_t e3[] = {1, 0, 0, 0, 1}; 371251881Speter int ss, i; 372251881Speter u_int32_t delta; 373251881Speter 374251881Speter struct { 375251881Speter int rate, fK, fQ; 376251881Speter } speedinfo[] = { 377251881Speter { 100, 0x00570000, 0x35280000}, 378251881Speter { 2000, 0x06aa0000, 0x34a70000}, 379251881Speter { 8000, 0x18b20000, 0x32020000}, 380251881Speter {11025, 0x20930000, 0x31770000}, 381251881Speter {16000, 0x2b9a0000, 0x31390000}, 382251881Speter {22050, 0x35a10000, 0x31c90000}, 383251881Speter {32000, 0x3eaa0000, 0x33d00000}, 384251881Speter/* {44100, 0x04646000, 0x370a0000}, 385251881Speter*/ {48000, 0x40000000, 0x40000000}, 386251881Speter }; 387251881Speter 388251881Speter ss = b16? 1 : 0; 389251881Speter ss += stereo? 1 : 0; 390251881Speter delta = (65536 * rate) / 48000; 391251881Speter i = 0; 392251881Speter while (i < 7 && speedinfo[i].rate < rate) 393251881Speter i++; 394251881Speter 395251881Speter pb->Format = stereo? 0x00010000 : 0; 396251881Speter pb->Format |= b16? 0 : 0x80000000; 397251881Speter pb->Format |= (stereo && (ch == 2 || ch == 4))? 0x00000001 : 0; 398251881Speter pb->LoopDefault = 0; 399251881Speter pb->PgBase = base? base : 0; 400251881Speter pb->PgLoop = 0; 401251881Speter pb->PgLoopEnd = len >> ss; 402251881Speter pb->PgLoopFrac = 0; 403251881Speter pb->Status = 0; 404251881Speter pb->NumOfFrames = 0; 405251881Speter pb->LoopCount = 0; 406251881Speter pb->PgStart = 0; 407251881Speter pb->PgStartFrac = 0; 408251881Speter pb->PgDelta = pb->PgDeltaEnd = delta << 12; 409251881Speter pb->LpfQ = speedinfo[i].fQ; 410251881Speter pb->LpfK = pb->LpfKEnd = speedinfo[i].fK; 411251881Speter pb->LpfD1 = pb->LpfD2 = 0; 412251881Speter pb->EgGain = pb->EgGainEnd = 0x40000000; 413251881Speter pb->LchGain = pb->LchGainEnd = lv[ch] * 0x40000000; 414251881Speter pb->RchGain = pb->RchGainEnd = rv[ch] * 0x40000000; 415251881Speter pb->Effect1Gain = pb->Effect1GainEnd = e1[ch] * 0x40000000; 416251881Speter pb->Effect2Gain = pb->Effect2GainEnd = e2[ch] * 0x40000000; 417251881Speter pb->Effect3Gain = pb->Effect3GainEnd = e3[ch] * 0x40000000; 418251881Speter 419251881Speter return 0; 420251881Speter} 421251881Speter 422251881Speterstatic void 423251881Speterds_enapslot(struct sc_info *sc, int slot, int go) 424251881Speter{ 425251881Speter wrl(sc, &sc->pbase[slot + 1], go? (sc->pbankbase + 2 * slot * sc->pbanksize) : 0); 426251881Speter /* printf("pbase[%d] = 0x%x\n", slot + 1, go? (sc->pbankbase + 2 * slot * sc->pbanksize) : 0); */ 427251881Speter} 428251881Speter 429251881Speterstatic void 430251881Speterds_setuppch(struct sc_pchinfo *ch) 431251881Speter{ 432251881Speter int stereo, b16, c, sz; 433251881Speter bus_addr_t addr; 434251881Speter 435251881Speter stereo = (ch->fmt & AFMT_STEREO)? 1 : 0; 436251881Speter b16 = (ch->fmt & AFMT_16BIT)? 1 : 0; 437251881Speter c = stereo? 1 : 0; 438251881Speter addr = sndbuf_getbufaddr(ch->buffer); 439251881Speter sz = sndbuf_getsize(ch->buffer); 440251881Speter 441251881Speter ds_initpbank(ch->lslot, c, stereo, b16, ch->spd, addr, sz); 442251881Speter ds_initpbank(ch->lslot + 1, c, stereo, b16, ch->spd, addr, sz); 443251881Speter ds_initpbank(ch->rslot, 2, stereo, b16, ch->spd, addr, sz); 444251881Speter ds_initpbank(ch->rslot + 1, 2, stereo, b16, ch->spd, addr, sz); 445251881Speter} 446251881Speter 447251881Speterstatic void 448251881Speterds_setuprch(struct sc_rchinfo *ch) 449251881Speter{ 450251881Speter struct sc_info *sc = ch->parent; 451251881Speter int stereo, b16, i, sz, pri; 452251881Speter u_int32_t x, y; 453251881Speter bus_addr_t addr; 454251881Speter 455251881Speter stereo = (ch->fmt & AFMT_STEREO)? 1 : 0; 456251881Speter b16 = (ch->fmt & AFMT_16BIT)? 1 : 0; 457251881Speter addr = sndbuf_getbufaddr(ch->buffer); 458251881Speter sz = sndbuf_getsize(ch->buffer); 459251881Speter pri = (ch->num == DS1_RECPRIMARY)? 1 : 0; 460251881Speter 461251881Speter for (i = 0; i < 2; i++) { 462251881Speter ch->slot[i].PgBase = addr; 463251881Speter ch->slot[i].PgLoopEnd = sz; 464251881Speter ch->slot[i].PgStart = 0; 465251881Speter ch->slot[i].NumOfLoops = 0; 466251881Speter } 467251881Speter x = (b16? 0x00 : 0x01) | (stereo? 0x02 : 0x00); 468251881Speter y = (48000 * 4096) / ch->spd; 469251881Speter y--; 470251881Speter /* printf("pri = %d, x = %d, y = %d\n", pri, x, y); */ 471251881Speter ds_wr(sc, pri? YDSXGR_ADCFORMAT : YDSXGR_RECFORMAT, x, 4); 472251881Speter ds_wr(sc, pri? YDSXGR_ADCSLOTSR : YDSXGR_RECSLOTSR, y, 4); 473251881Speter} 474251881Speter 475251881Speter/* -------------------------------------------------------------------- */ 476251881Speter/* play channel interface */ 477251881Speterstatic void * 478251881Speterds1pchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 479251881Speter{ 480251881Speter struct sc_info *sc = devinfo; 481251881Speter struct sc_pchinfo *ch; 482251881Speter 483251881Speter KASSERT(dir == PCMDIR_PLAY, ("ds1pchan_init: bad direction")); 484251881Speter 485251881Speter ch = &sc->pch[sc->pchn++]; 486 ch->buffer = b; 487 ch->parent = sc; 488 ch->channel = c; 489 ch->dir = dir; 490 ch->fmt = AFMT_U8; 491 ch->spd = 8000; 492 ch->run = 0; 493 if (sndbuf_alloc(ch->buffer, sc->buffer_dmat, sc->bufsz) == -1) 494 return NULL; 495 else { 496 ch->lsnum = sc->pslotfree; 497 ch->lslot = ds_allocpslot(sc); 498 ch->rsnum = sc->pslotfree; 499 ch->rslot = ds_allocpslot(sc); 500 ds_setuppch(ch); 501 return ch; 502 } 503} 504 505static int 506ds1pchan_setformat(kobj_t obj, void *data, u_int32_t format) 507{ 508 struct sc_pchinfo *ch = data; 509 510 ch->fmt = format; 511 512 return 0; 513} 514 515static int 516ds1pchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 517{ 518 struct sc_pchinfo *ch = data; 519 520 ch->spd = speed; 521 522 return speed; 523} 524 525static int 526ds1pchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 527{ 528 struct sc_pchinfo *ch = data; 529 int drate; 530 531 /* irq rate is fixed at 187.5hz */ 532 drate = ch->spd * sndbuf_getbps(ch->buffer); 533 blocksize = (drate << 8) / DS1_IRQHZ; 534 sndbuf_resize(ch->buffer, DS1_BUFFSIZE / blocksize, blocksize); 535 536 return blocksize; 537} 538 539/* semantic note: must start at beginning of buffer */ 540static int 541ds1pchan_trigger(kobj_t obj, void *data, int go) 542{ 543 struct sc_pchinfo *ch = data; 544 struct sc_info *sc = ch->parent; 545 int stereo; 546 547 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 548 return 0; 549 stereo = (ch->fmt & AFMT_STEREO)? 1 : 0; 550 if (go == PCMTRIG_START) { 551 ch->run = 1; 552 ds_setuppch(ch); 553 ds_enapslot(sc, ch->lsnum, 1); 554 ds_enapslot(sc, ch->rsnum, stereo); 555 snd_mtxlock(sc->lock); 556 ds_wr(sc, YDSXGR_MODE, 0x00000003, 4); 557 snd_mtxunlock(sc->lock); 558 } else { 559 ch->run = 0; 560 /* ds_setuppch(ch); */ 561 ds_enapslot(sc, ch->lsnum, 0); 562 ds_enapslot(sc, ch->rsnum, 0); 563 } 564 565 return 0; 566} 567 568static int 569ds1pchan_getptr(kobj_t obj, void *data) 570{ 571 struct sc_pchinfo *ch = data; 572 struct sc_info *sc = ch->parent; 573 volatile struct pbank *bank; 574 int ss; 575 u_int32_t ptr; 576 577 ss = (ch->fmt & AFMT_STEREO)? 1 : 0; 578 ss += (ch->fmt & AFMT_16BIT)? 1 : 0; 579 580 bank = ch->lslot + sc->currbank; 581 /* printf("getptr: %d\n", bank->PgStart << ss); */ 582 ptr = bank->PgStart; 583 ptr <<= ss; 584 return ptr; 585} 586 587static struct pcmchan_caps * 588ds1pchan_getcaps(kobj_t obj, void *data) 589{ 590 return &ds_playcaps; 591} 592 593static kobj_method_t ds1pchan_methods[] = { 594 KOBJMETHOD(channel_init, ds1pchan_init), 595 KOBJMETHOD(channel_setformat, ds1pchan_setformat), 596 KOBJMETHOD(channel_setspeed, ds1pchan_setspeed), 597 KOBJMETHOD(channel_setblocksize, ds1pchan_setblocksize), 598 KOBJMETHOD(channel_trigger, ds1pchan_trigger), 599 KOBJMETHOD(channel_getptr, ds1pchan_getptr), 600 KOBJMETHOD(channel_getcaps, ds1pchan_getcaps), 601 { 0, 0 } 602}; 603CHANNEL_DECLARE(ds1pchan); 604 605/* -------------------------------------------------------------------- */ 606/* record channel interface */ 607static void * 608ds1rchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 609{ 610 struct sc_info *sc = devinfo; 611 struct sc_rchinfo *ch; 612 613 KASSERT(dir == PCMDIR_REC, ("ds1rchan_init: bad direction")); 614 615 ch = &sc->rch[sc->rchn]; 616 ch->num = sc->rchn++; 617 ch->buffer = b; 618 ch->parent = sc; 619 ch->channel = c; 620 ch->dir = dir; 621 ch->fmt = AFMT_U8; 622 ch->spd = 8000; 623 if (sndbuf_alloc(ch->buffer, sc->buffer_dmat, sc->bufsz) == -1) 624 return NULL; 625 else { 626 ch->slot = (ch->num == DS1_RECPRIMARY)? sc->rbank + 2: sc->rbank; 627 ds_setuprch(ch); 628 return ch; 629 } 630} 631 632static int 633ds1rchan_setformat(kobj_t obj, void *data, u_int32_t format) 634{ 635 struct sc_rchinfo *ch = data; 636 637 ch->fmt = format; 638 639 return 0; 640} 641 642static int 643ds1rchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 644{ 645 struct sc_rchinfo *ch = data; 646 647 ch->spd = speed; 648 649 return speed; 650} 651 652static int 653ds1rchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 654{ 655 struct sc_rchinfo *ch = data; 656 int drate; 657 658 /* irq rate is fixed at 187.5hz */ 659 drate = ch->spd * sndbuf_getbps(ch->buffer); 660 blocksize = (drate << 8) / DS1_IRQHZ; 661 sndbuf_resize(ch->buffer, DS1_BUFFSIZE / blocksize, blocksize); 662 663 return blocksize; 664} 665 666/* semantic note: must start at beginning of buffer */ 667static int 668ds1rchan_trigger(kobj_t obj, void *data, int go) 669{ 670 struct sc_rchinfo *ch = data; 671 struct sc_info *sc = ch->parent; 672 u_int32_t x; 673 674 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 675 return 0; 676 if (go == PCMTRIG_START) { 677 ch->run = 1; 678 ds_setuprch(ch); 679 snd_mtxlock(sc->lock); 680 x = ds_rd(sc, YDSXGR_MAPOFREC, 4); 681 x |= (ch->num == DS1_RECPRIMARY)? 0x02 : 0x01; 682 ds_wr(sc, YDSXGR_MAPOFREC, x, 4); 683 ds_wr(sc, YDSXGR_MODE, 0x00000003, 4); 684 snd_mtxunlock(sc->lock); 685 } else { 686 ch->run = 0; 687 snd_mtxlock(sc->lock); 688 x = ds_rd(sc, YDSXGR_MAPOFREC, 4); 689 x &= ~((ch->num == DS1_RECPRIMARY)? 0x02 : 0x01); 690 ds_wr(sc, YDSXGR_MAPOFREC, x, 4); 691 snd_mtxunlock(sc->lock); 692 } 693 694 return 0; 695} 696 697static int 698ds1rchan_getptr(kobj_t obj, void *data) 699{ 700 struct sc_rchinfo *ch = data; 701 struct sc_info *sc = ch->parent; 702 703 return ch->slot[sc->currbank].PgStart; 704} 705 706static struct pcmchan_caps * 707ds1rchan_getcaps(kobj_t obj, void *data) 708{ 709 return &ds_reccaps; 710} 711 712static kobj_method_t ds1rchan_methods[] = { 713 KOBJMETHOD(channel_init, ds1rchan_init), 714 KOBJMETHOD(channel_setformat, ds1rchan_setformat), 715 KOBJMETHOD(channel_setspeed, ds1rchan_setspeed), 716 KOBJMETHOD(channel_setblocksize, ds1rchan_setblocksize), 717 KOBJMETHOD(channel_trigger, ds1rchan_trigger), 718 KOBJMETHOD(channel_getptr, ds1rchan_getptr), 719 KOBJMETHOD(channel_getcaps, ds1rchan_getcaps), 720 { 0, 0 } 721}; 722CHANNEL_DECLARE(ds1rchan); 723 724/* -------------------------------------------------------------------- */ 725/* The interrupt handler */ 726static void 727ds_intr(void *p) 728{ 729 struct sc_info *sc = (struct sc_info *)p; 730 u_int32_t i, x; 731 732 snd_mtxlock(sc->lock); 733 i = ds_rd(sc, YDSXGR_STATUS, 4); 734 if (i & 0x00008000) 735 device_printf(sc->dev, "timeout irq\n"); 736 if (i & 0x80008000) { 737 ds_wr(sc, YDSXGR_STATUS, i & 0x80008000, 4); 738 sc->currbank = ds_rd(sc, YDSXGR_CTRLSELECT, 4) & 0x00000001; 739 740 x = 0; 741 for (i = 0; i < DS1_CHANS; i++) { 742 if (sc->pch[i].run) { 743 x = 1; 744 chn_intr(sc->pch[i].channel); 745 } 746 } 747 for (i = 0; i < 2; i++) { 748 if (sc->rch[i].run) { 749 x = 1; 750 chn_intr(sc->rch[i].channel); 751 } 752 } 753 i = ds_rd(sc, YDSXGR_MODE, 4); 754 if (x) 755 ds_wr(sc, YDSXGR_MODE, i | 0x00000002, 4); 756 757 } 758 snd_mtxunlock(sc->lock); 759} 760 761/* -------------------------------------------------------------------- */ 762 763/* 764 * Probe and attach the card 765 */ 766 767static void 768ds_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 769{ 770 struct sc_info *sc = arg; 771 772 sc->ctrlbase = error? 0 : (u_int32_t)segs->ds_addr; 773 774 if (bootverbose) { 775 printf("ds1: setmap (%lx, %lx), nseg=%d, error=%d\n", 776 (unsigned long)segs->ds_addr, (unsigned long)segs->ds_len, 777 nseg, error); 778 } 779} 780 781static int 782ds_init(struct sc_info *sc) 783{ 784 int i; 785 u_int32_t *ci, r, pcs, rcs, ecs, ws, memsz, cb; 786 u_int8_t *t; 787 void *buf; 788 789 ci = ds_devs[sc->type].mcode; 790 791 ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x00000000, 4); 792 ds_enadsp(sc, 0); 793 ds_wr(sc, YDSXGR_MODE, 0x00010000, 4); 794 ds_wr(sc, YDSXGR_MODE, 0x00000000, 4); 795 ds_wr(sc, YDSXGR_MAPOFREC, 0x00000000, 4); 796 ds_wr(sc, YDSXGR_MAPOFEFFECT, 0x00000000, 4); 797 ds_wr(sc, YDSXGR_PLAYCTRLBASE, 0x00000000, 4); 798 ds_wr(sc, YDSXGR_RECCTRLBASE, 0x00000000, 4); 799 ds_wr(sc, YDSXGR_EFFCTRLBASE, 0x00000000, 4); 800 r = ds_rd(sc, YDSXGR_GLOBALCTRL, 2); 801 ds_wr(sc, YDSXGR_GLOBALCTRL, r & ~0x0007, 2); 802 803 for (i = 0; i < YDSXG_DSPLENGTH; i += 4) 804 ds_wr(sc, YDSXGR_DSPINSTRAM + i, DspInst[i >> 2], 4); 805 806 for (i = 0; i < YDSXG_CTRLLENGTH; i += 4) 807 ds_wr(sc, YDSXGR_CTRLINSTRAM + i, ci[i >> 2], 4); 808 809 ds_enadsp(sc, 1); 810 811 pcs = 0; 812 for (i = 100; i > 0; i--) { 813 pcs = ds_rd(sc, YDSXGR_PLAYCTRLSIZE, 4) << 2; 814 if (pcs == sizeof(struct pbank)) 815 break; 816 DELAY(1000); 817 } 818 if (pcs != sizeof(struct pbank)) { 819 device_printf(sc->dev, "preposterous playctrlsize (%d)\n", pcs); 820 return -1; 821 } 822 rcs = ds_rd(sc, YDSXGR_RECCTRLSIZE, 4) << 2; 823 ecs = ds_rd(sc, YDSXGR_EFFCTRLSIZE, 4) << 2; 824 ws = ds_rd(sc, YDSXGR_WORKSIZE, 4) << 2; 825 826 memsz = 64 * 2 * pcs + 2 * 2 * rcs + 5 * 2 * ecs + ws; 827 memsz += (64 + 1) * 4; 828 829 if (sc->regbase == NULL) { 830 if (bus_dma_tag_create(NULL, 2, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, 831 NULL, NULL, memsz, 1, 1, 0, &sc->control_dmat)) 832 return -1; 833 if (bus_dmamem_alloc(sc->control_dmat, &buf, BUS_DMA_NOWAIT, &sc->map)) 834 return -1; 835 if (bus_dmamap_load(sc->control_dmat, sc->map, buf, memsz, ds_setmap, sc, 0) || !sc->ctrlbase) { 836 device_printf(sc->dev, "pcs=%d, rcs=%d, ecs=%d, ws=%d, memsz=%d\n", 837 pcs, rcs, ecs, ws, memsz); 838 return -1; 839 } 840 sc->regbase = buf; 841 } else 842 buf = sc->regbase; 843 844 cb = 0; 845 t = buf; 846 ds_wr(sc, YDSXGR_WORKBASE, sc->ctrlbase + cb, 4); 847 cb += ws; 848 sc->pbase = (u_int32_t *)(t + cb); 849 /* printf("pbase = %p -> 0x%x\n", sc->pbase, sc->ctrlbase + cb); */ 850 ds_wr(sc, YDSXGR_PLAYCTRLBASE, sc->ctrlbase + cb, 4); 851 cb += (64 + 1) * 4; 852 sc->rbank = (struct rbank *)(t + cb); 853 ds_wr(sc, YDSXGR_RECCTRLBASE, sc->ctrlbase + cb, 4); 854 cb += 2 * 2 * rcs; 855 ds_wr(sc, YDSXGR_EFFCTRLBASE, sc->ctrlbase + cb, 4); 856 cb += 5 * 2 * ecs; 857 858 sc->pbankbase = sc->ctrlbase + cb; 859 sc->pbanksize = pcs; 860 for (i = 0; i < 64; i++) { 861 wrl(sc, &sc->pbase[i + 1], 0); 862 sc->pbank[i * 2] = (struct pbank *)(t + cb); 863 /* printf("pbank[%d] = %p -> 0x%x; ", i * 2, (struct pbank *)(t + cb), sc->ctrlbase + cb - vtophys(t + cb)); */ 864 cb += pcs; 865 sc->pbank[i * 2 + 1] = (struct pbank *)(t + cb); 866 /* printf("pbank[%d] = %p -> 0x%x\n", i * 2 + 1, (struct pbank *)(t + cb), sc->ctrlbase + cb - vtophys(t + cb)); */ 867 cb += pcs; 868 } 869 wrl(sc, &sc->pbase[0], DS1_CHANS * 2); 870 871 sc->pchn = sc->rchn = 0; 872 ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff, 4); 873 ds_wr(sc, YDSXGR_NATIVEADCINVOL, 0x3fff3fff, 4); 874 ds_wr(sc, YDSXGR_NATIVEDACINVOL, 0x3fff3fff, 4); 875 876 return 0; 877} 878 879static int 880ds_uninit(struct sc_info *sc) 881{ 882 ds_wr(sc, YDSXGR_NATIVEDACOUTVOL, 0x00000000, 4); 883 ds_wr(sc, YDSXGR_NATIVEADCINVOL, 0, 4); 884 ds_wr(sc, YDSXGR_NATIVEDACINVOL, 0, 4); 885 ds_enadsp(sc, 0); 886 ds_wr(sc, YDSXGR_MODE, 0x00010000, 4); 887 ds_wr(sc, YDSXGR_MAPOFREC, 0x00000000, 4); 888 ds_wr(sc, YDSXGR_MAPOFEFFECT, 0x00000000, 4); 889 ds_wr(sc, YDSXGR_PLAYCTRLBASE, 0x00000000, 4); 890 ds_wr(sc, YDSXGR_RECCTRLBASE, 0x00000000, 4); 891 ds_wr(sc, YDSXGR_EFFCTRLBASE, 0x00000000, 4); 892 ds_wr(sc, YDSXGR_GLOBALCTRL, 0, 2); 893 894 bus_dmamap_unload(sc->control_dmat, sc->map); 895 bus_dmamem_free(sc->control_dmat, sc->regbase, sc->map); 896 897 return 0; 898} 899 900static int 901ds_finddev(u_int32_t dev, u_int32_t subdev) 902{ 903 int i; 904 905 for (i = 0; ds_devs[i].dev; i++) { 906 if (ds_devs[i].dev == dev && 907 (ds_devs[i].subdev == subdev || ds_devs[i].subdev == 0)) 908 return i; 909 } 910 return -1; 911} 912 913static int 914ds_pci_probe(device_t dev) 915{ 916 int i; 917 u_int32_t subdev; 918 919 subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev); 920 i = ds_finddev(pci_get_devid(dev), subdev); 921 if (i >= 0) { 922 device_set_desc(dev, ds_devs[i].name); 923 return 0; 924 } else 925 return ENXIO; 926} 927 928static int 929ds_pci_attach(device_t dev) 930{ 931 u_int32_t data; 932 u_int32_t subdev, i; 933 struct sc_info *sc; 934 struct ac97_info *codec = NULL; 935 char status[SND_STATUSLEN]; 936 937 if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO)) == NULL) { 938 device_printf(dev, "cannot allocate softc\n"); 939 return ENXIO; 940 } 941 942 sc->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); 943 sc->dev = dev; 944 subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev); 945 sc->type = ds_finddev(pci_get_devid(dev), subdev); 946 sc->rev = pci_get_revid(dev); 947 948 data = pci_read_config(dev, PCIR_COMMAND, 2); 949 data |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN); 950 pci_write_config(dev, PCIR_COMMAND, data, 2); 951 data = pci_read_config(dev, PCIR_COMMAND, 2); 952 953 sc->regid = PCIR_MAPS; 954 sc->reg = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->regid, 955 0, ~0, 1, RF_ACTIVE); 956 if (!sc->reg) { 957 device_printf(dev, "unable to map register space\n"); 958 goto bad; 959 } 960 961 sc->st = rman_get_bustag(sc->reg); 962 sc->sh = rman_get_bushandle(sc->reg); 963 964 sc->bufsz = pcm_getbuffersize(dev, 4096, DS1_BUFFSIZE, 65536); 965 966 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 967 /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, 968 /*highaddr*/BUS_SPACE_MAXADDR, 969 /*filter*/NULL, /*filterarg*/NULL, 970 /*maxsize*/sc->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff, 971 /*flags*/0, &sc->buffer_dmat) != 0) { 972 device_printf(dev, "unable to create dma tag\n"); 973 goto bad; 974 } 975 976 sc->regbase = NULL; 977 if (ds_init(sc) == -1) { 978 device_printf(dev, "unable to initialize the card\n"); 979 goto bad; 980 } 981 982 codec = AC97_CREATE(dev, sc, ds_ac97); 983 if (codec == NULL) 984 goto bad; 985 mixer_init(dev, ac97_getmixerclass(), codec); 986 987 sc->irqid = 0; 988 sc->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->irqid, 989 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 990 if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ds_intr, sc, &sc->ih)) { 991 device_printf(dev, "unable to map interrupt\n"); 992 goto bad; 993 } 994 995 snprintf(status, SND_STATUSLEN, "at memory 0x%lx irq %ld", 996 rman_get_start(sc->reg), rman_get_start(sc->irq)); 997 998 if (pcm_register(dev, sc, DS1_CHANS, 2)) 999 goto bad; 1000 for (i = 0; i < DS1_CHANS; i++) 1001 pcm_addchan(dev, PCMDIR_PLAY, &ds1pchan_class, sc); 1002 for (i = 0; i < 2; i++) 1003 pcm_addchan(dev, PCMDIR_REC, &ds1rchan_class, sc); 1004 pcm_setstatus(dev, status); 1005 1006 return 0; 1007 1008bad: 1009 if (codec) 1010 ac97_destroy(codec); 1011 if (sc->reg) 1012 bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg); 1013 if (sc->ih) 1014 bus_teardown_intr(dev, sc->irq, sc->ih); 1015 if (sc->irq) 1016 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1017 if (sc->buffer_dmat) 1018 bus_dma_tag_destroy(sc->buffer_dmat); 1019 if (sc->control_dmat) 1020 bus_dma_tag_destroy(sc->control_dmat); 1021 if (sc->lock) 1022 snd_mtxfree(sc->lock); 1023 free(sc, M_DEVBUF); 1024 return ENXIO; 1025} 1026 1027static int 1028ds_pci_resume(device_t dev) 1029{ 1030 struct sc_info *sc; 1031 1032 sc = pcm_getdevinfo(dev); 1033 1034 if (ds_init(sc) == -1) { 1035 device_printf(dev, "unable to reinitialize the card\n"); 1036 return ENXIO; 1037 } 1038 if (mixer_reinit(dev) == -1) { 1039 device_printf(dev, "unable to reinitialize the mixer\n"); 1040 return ENXIO; 1041 } 1042 return 0; 1043} 1044 1045static int 1046ds_pci_detach(device_t dev) 1047{ 1048 int r; 1049 struct sc_info *sc; 1050 1051 r = pcm_unregister(dev); 1052 if (r) 1053 return r; 1054 1055 sc = pcm_getdevinfo(dev); 1056 ds_uninit(sc); 1057 bus_release_resource(dev, SYS_RES_MEMORY, sc->regid, sc->reg); 1058 bus_teardown_intr(dev, sc->irq, sc->ih); 1059 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 1060 bus_dma_tag_destroy(sc->buffer_dmat); 1061 bus_dma_tag_destroy(sc->control_dmat); 1062 snd_mtxfree(sc->lock); 1063 free(sc, M_DEVBUF); 1064 return 0; 1065} 1066 1067static device_method_t ds1_methods[] = { 1068 /* Device interface */ 1069 DEVMETHOD(device_probe, ds_pci_probe), 1070 DEVMETHOD(device_attach, ds_pci_attach), 1071 DEVMETHOD(device_detach, ds_pci_detach), 1072 DEVMETHOD(device_resume, ds_pci_resume), 1073 { 0, 0 } 1074}; 1075 1076static driver_t ds1_driver = { 1077 "pcm", 1078 ds1_methods, 1079 PCM_SOFTC_SIZE, 1080}; 1081 1082DRIVER_MODULE(snd_ds1, pci, ds1_driver, pcm_devclass, 0, 0); 1083MODULE_DEPEND(snd_ds1, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 1084MODULE_VERSION(snd_ds1, 1); 1085