42 43#define SB_DEFAULT_BUFSZ 4096 44 45static u_int32_t sb_fmt[] = { 46 AFMT_U8, 47 0 48}; 49static struct pcmchan_caps sb200_playcaps = {4000, 23000, sb_fmt, 0}; 50static struct pcmchan_caps sb200_reccaps = {4000, 13000, sb_fmt, 0}; 51static struct pcmchan_caps sb201_playcaps = {4000, 44100, sb_fmt, 0}; 52static struct pcmchan_caps sb201_reccaps = {4000, 15000, sb_fmt, 0}; 53 54static u_int32_t sbpro_fmt[] = { 55 AFMT_U8, 56 AFMT_STEREO | AFMT_U8, 57 0 58}; 59static struct pcmchan_caps sbpro_playcaps = {4000, 44100, sbpro_fmt, 0}; 60static struct pcmchan_caps sbpro_reccaps = {4000, 44100, sbpro_fmt, 0}; 61 62struct sb_info; 63 64struct sb_chinfo { 65 struct sb_info *parent; 66 struct pcm_channel *channel; 67 struct snd_dbuf *buffer; 68 int dir; 69 u_int32_t fmt, spd, blksz; 70}; 71 72struct sb_info { 73 device_t parent_dev; 74 struct resource *io_base; /* I/O address for the board */ 75 struct resource *irq; 76 struct resource *drq; 77 void *ih; 78 bus_dma_tag_t parent_dmat; 79 80 unsigned int bufsize; 81 int bd_id; 82 u_long bd_flags; /* board-specific flags */ 83 struct sb_chinfo pch, rch; 84}; 85 86static int sb_rd(struct sb_info *sb, int reg); 87static void sb_wr(struct sb_info *sb, int reg, u_int8_t val); 88static int sb_dspready(struct sb_info *sb); 89static int sb_cmd(struct sb_info *sb, u_char val); 90static int sb_cmd1(struct sb_info *sb, u_char cmd, int val); 91static int sb_cmd2(struct sb_info *sb, u_char cmd, int val); 92static u_int sb_get_byte(struct sb_info *sb); 93static void sb_setmixer(struct sb_info *sb, u_int port, u_int value); 94static int sb_getmixer(struct sb_info *sb, u_int port); 95static int sb_reset_dsp(struct sb_info *sb); 96 97static void sb_intr(void *arg); 98static int sb_speed(struct sb_chinfo *ch); 99static int sb_start(struct sb_chinfo *ch); 100static int sb_stop(struct sb_chinfo *ch); 101 102/* 103 * Common code for the midi and pcm functions 104 * 105 * sb_cmd write a single byte to the CMD port. 106 * sb_cmd1 write a CMD + 1 byte arg 107 * sb_cmd2 write a CMD + 2 byte arg 108 * sb_get_byte returns a single byte from the DSP data port 109 */ 110 111static void 112sb_lock(struct sb_info *sb) { 113 114 sbc_lock(device_get_softc(sb->parent_dev)); 115} 116 117static void 118sb_unlock(struct sb_info *sb) { 119 120 sbc_unlock(device_get_softc(sb->parent_dev)); 121} 122 123static int 124port_rd(struct resource *port, int off) 125{ 126 return bus_space_read_1(rman_get_bustag(port), rman_get_bushandle(port), off); 127} 128 129static void 130port_wr(struct resource *port, int off, u_int8_t data) 131{ 132 bus_space_write_1(rman_get_bustag(port), rman_get_bushandle(port), off, data); 133} 134 135static int 136sb_rd(struct sb_info *sb, int reg) 137{ 138 return port_rd(sb->io_base, reg); 139} 140 141static void 142sb_wr(struct sb_info *sb, int reg, u_int8_t val) 143{ 144 port_wr(sb->io_base, reg, val); 145} 146 147static int 148sb_dspready(struct sb_info *sb) 149{ 150 return ((sb_rd(sb, SBDSP_STATUS) & 0x80) == 0); 151} 152 153static int 154sb_dspwr(struct sb_info *sb, u_char val) 155{ 156 int i; 157 158 for (i = 0; i < 1000; i++) { 159 if (sb_dspready(sb)) { 160 sb_wr(sb, SBDSP_CMD, val); 161 return 1; 162 } 163 if (i > 10) DELAY((i > 100)? 1000 : 10); 164 } 165 printf("sb_dspwr(0x%02x) timed out.\n", val); 166 return 0; 167} 168 169static int 170sb_cmd(struct sb_info *sb, u_char val) 171{ 172#if 0 173 printf("sb_cmd: %x\n", val); 174#endif 175 return sb_dspwr(sb, val); 176} 177 178static int 179sb_cmd1(struct sb_info *sb, u_char cmd, int val) 180{ 181#if 0 182 printf("sb_cmd1: %x, %x\n", cmd, val); 183#endif 184 if (sb_dspwr(sb, cmd)) { 185 return sb_dspwr(sb, val & 0xff); 186 } else return 0; 187} 188 189static int 190sb_cmd2(struct sb_info *sb, u_char cmd, int val) 191{ 192#if 0 193 printf("sb_cmd2: %x, %x\n", cmd, val); 194#endif 195 if (sb_dspwr(sb, cmd)) { 196 return sb_dspwr(sb, val & 0xff) && 197 sb_dspwr(sb, (val >> 8) & 0xff); 198 } else return 0; 199} 200 201/* 202 * in the SB, there is a set of indirect "mixer" registers with 203 * address at offset 4, data at offset 5 204 * 205 * we don't need to interlock these, the mixer lock will suffice. 206 */ 207static void 208sb_setmixer(struct sb_info *sb, u_int port, u_int value) 209{ 210 sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 211 DELAY(10); 212 sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff)); 213 DELAY(10); 214} 215 216static int 217sb_getmixer(struct sb_info *sb, u_int port) 218{ 219 int val; 220 221 sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 222 DELAY(10); 223 val = sb_rd(sb, SB_MIX_DATA); 224 DELAY(10); 225 226 return val; 227} 228 229static u_int 230sb_get_byte(struct sb_info *sb) 231{ 232 int i; 233 234 for (i = 1000; i > 0; i--) { 235 if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80) 236 return sb_rd(sb, DSP_READ); 237 else 238 DELAY(20); 239 } 240 return 0xffff; 241} 242 243static int 244sb_reset_dsp(struct sb_info *sb) 245{ 246 sb_wr(sb, SBDSP_RST, 3); 247 DELAY(100); 248 sb_wr(sb, SBDSP_RST, 0); 249 if (sb_get_byte(sb) != 0xAA) { 250 DEB(printf("sb_reset_dsp 0x%lx failed\n", 251 rman_get_start(sb->io_base))); 252 return ENXIO; /* Sorry */ 253 } 254 return 0; 255} 256 257static void 258sb_release_resources(struct sb_info *sb, device_t dev) 259{ 260 if (sb->irq) { 261 if (sb->ih) 262 bus_teardown_intr(dev, sb->irq, sb->ih); 263 bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq); 264 sb->irq = 0; 265 } 266 if (sb->drq) { 267 isa_dma_release(rman_get_start(sb->drq)); 268 bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq); 269 sb->drq = 0; 270 } 271 if (sb->io_base) { 272 bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base); 273 sb->io_base = 0; 274 } 275 if (sb->parent_dmat) { 276 bus_dma_tag_destroy(sb->parent_dmat); 277 sb->parent_dmat = 0; 278 } 279 free(sb, M_DEVBUF); 280} 281 282static int 283sb_alloc_resources(struct sb_info *sb, device_t dev) 284{ 285 int rid; 286 287 rid = 0; 288 if (!sb->io_base) 289 sb->io_base = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 290 &rid, RF_ACTIVE); 291 rid = 0; 292 if (!sb->irq) 293 sb->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 294 &rid, RF_ACTIVE); 295 rid = 0; 296 if (!sb->drq) 297 sb->drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, 298 &rid, RF_ACTIVE); 299 300 if (sb->io_base && sb->drq && sb->irq) { 301 isa_dma_acquire(rman_get_start(sb->drq)); 302 isa_dmainit(rman_get_start(sb->drq), sb->bufsize); 303 304 return 0; 305 } else return ENXIO; 306} 307 308/************************************************************/ 309 310static int 311sbpromix_init(struct snd_mixer *m) 312{ 313 struct sb_info *sb = mix_getdevinfo(m); 314 315 mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | 316 SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME); 317 318 mix_setrecdevs(m, SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD); 319 320 sb_setmixer(sb, 0, 1); /* reset mixer */ 321 322 return 0; 323} 324 325static int 326sbpromix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 327{ 328 struct sb_info *sb = mix_getdevinfo(m); 329 int reg, max; 330 u_char val; 331 332 max = 7; 333 switch (dev) { 334 case SOUND_MIXER_PCM: 335 reg = 0x04; 336 break; 337 338 case SOUND_MIXER_MIC: 339 reg = 0x0a; 340 max = 3; 341 break; 342 343 case SOUND_MIXER_VOLUME: 344 reg = 0x22; 345 break; 346 347 case SOUND_MIXER_SYNTH: 348 reg = 0x26; 349 break; 350 351 case SOUND_MIXER_CD: 352 reg = 0x28; 353 break; 354 355 case SOUND_MIXER_LINE: 356 reg = 0x2e; 357 break; 358 359 default: 360 return -1; 361 } 362 363 left = (left * max) / 100; 364 right = (dev == SOUND_MIXER_MIC)? left : ((right * max) / 100); 365 366 val = (dev == SOUND_MIXER_MIC)? (left << 1) : (left << 5 | right << 1); 367 sb_setmixer(sb, reg, val); 368 369 left = (left * 100) / max; 370 right = (right * 100) / max; 371 372 return left | (right << 8); 373} 374 375static int 376sbpromix_setrecsrc(struct snd_mixer *m, u_int32_t src) 377{ 378 struct sb_info *sb = mix_getdevinfo(m); 379 u_char recdev; 380 381 if (src == SOUND_MASK_LINE) 382 recdev = 0x06; 383 else if (src == SOUND_MASK_CD) 384 recdev = 0x02; 385 else { /* default: mic */ 386 src = SOUND_MASK_MIC; 387 recdev = 0; 388 } 389 sb_setmixer(sb, RECORD_SRC, recdev | (sb_getmixer(sb, RECORD_SRC) & ~0x07)); 390 391 return src; 392} 393 394static kobj_method_t sbpromix_mixer_methods[] = { 395 KOBJMETHOD(mixer_init, sbpromix_init), 396 KOBJMETHOD(mixer_set, sbpromix_set), 397 KOBJMETHOD(mixer_setrecsrc, sbpromix_setrecsrc), 398 { 0, 0 } 399}; 400MIXER_DECLARE(sbpromix_mixer); 401 402/************************************************************/ 403 404static int 405sbmix_init(struct snd_mixer *m) 406{ 407 struct sb_info *sb = mix_getdevinfo(m); 408 409 mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_CD | SOUND_MASK_VOLUME); 410 411 mix_setrecdevs(m, 0); 412 413 sb_setmixer(sb, 0, 1); /* reset mixer */ 414 415 return 0; 416} 417 418static int 419sbmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 420{ 421 struct sb_info *sb = mix_getdevinfo(m); 422 int reg, max; 423 424 max = 7; 425 switch (dev) { 426 case SOUND_MIXER_VOLUME: 427 reg = 0x2; 428 break; 429 430 case SOUND_MIXER_SYNTH: 431 reg = 0x6; 432 break; 433 434 case SOUND_MIXER_CD: 435 reg = 0x8; 436 break; 437 438 case SOUND_MIXER_PCM: 439 reg = 0x0a; 440 max = 3; 441 break; 442 443 default: 444 return -1; 445 } 446 447 left = (left * max) / 100; 448 449 sb_setmixer(sb, reg, left << 1); 450 451 left = (left * 100) / max; 452 453 return left | (left << 8); 454} 455 456static int 457sbmix_setrecsrc(struct snd_mixer *m, u_int32_t src) 458{ 459 return 0; 460} 461 462static kobj_method_t sbmix_mixer_methods[] = { 463 KOBJMETHOD(mixer_init, sbmix_init), 464 KOBJMETHOD(mixer_set, sbmix_set), 465 KOBJMETHOD(mixer_setrecsrc, sbmix_setrecsrc), 466 { 0, 0 } 467}; 468MIXER_DECLARE(sbmix_mixer); 469 470/************************************************************/ 471 472static void 473sb_intr(void *arg) 474{ 475 struct sb_info *sb = (struct sb_info *)arg; 476 477 sb_lock(sb); 478 if (sndbuf_runsz(sb->pch.buffer) > 0) { 479 sb_unlock(sb); 480 chn_intr(sb->pch.channel); 481 sb_lock(sb); 482 } 483 484 if (sndbuf_runsz(sb->rch.buffer) > 0) { 485 sb_unlock(sb); 486 chn_intr(sb->rch.channel); 487 sb_lock(sb); 488 } 489 490 sb_rd(sb, DSP_DATA_AVAIL); /* int ack */ 491 sb_unlock(sb); 492} 493 494static int 495sb_speed(struct sb_chinfo *ch) 496{ 497 struct sb_info *sb = ch->parent; 498 int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 499 int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0; 500 int speed, tmp, thresh, max; 501 u_char tconst; 502 503 if (sb->bd_id >= 0x300) { 504 thresh = stereo? 11025 : 23000; 505 max = stereo? 22050 : 44100; 506 } else if (sb->bd_id > 0x200) { 507 thresh = play? 23000 : 13000; 508 max = play? 44100 : 15000; 509 } else { 510 thresh = 999999; 511 max = play? 23000 : 13000; 512 } 513 514 speed = ch->spd; 515 if (speed > max) 516 speed = max; 517 518 sb_lock(sb); 519 sb->bd_flags &= ~BD_F_HISPEED; 520 if (speed > thresh) 521 sb->bd_flags |= BD_F_HISPEED; 522 523 tmp = 65536 - (256000000 / (speed << stereo)); 524 tconst = tmp >> 8; 525 526 sb_cmd1(sb, 0x40, tconst); /* set time constant */ 527 528 speed = (256000000 / (65536 - tmp)) >> stereo; 529 530 ch->spd = speed; 531 sb_unlock(sb); 532 return speed; 533} 534 535static int 536sb_start(struct sb_chinfo *ch) 537{ 538 struct sb_info *sb = ch->parent; 539 int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 540 int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0; 541 int l = ch->blksz; 542 u_char i; 543 544 l--; 545 546 sb_lock(sb); 547 if (play) 548 sb_cmd(sb, DSP_CMD_SPKON); 549 550 if (sb->bd_flags & BD_F_HISPEED) 551 i = play? 0x90 : 0x98; 552 else 553 i = play? 0x1c : 0x2c; 554 555 sb_setmixer(sb, 0x0e, stereo? 2 : 0); 556 sb_cmd2(sb, 0x48, l); 557 sb_cmd(sb, i); 558 559 sb->bd_flags |= BD_F_DMARUN; 560 sb_unlock(sb); 561 return 0; 562} 563 564static int 565sb_stop(struct sb_chinfo *ch) 566{ 567 struct sb_info *sb = ch->parent; 568 int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 569 570 sb_lock(sb); 571 if (sb->bd_flags & BD_F_HISPEED) 572 sb_reset_dsp(sb); 573 else { 574#if 0 575 /* 576 * NOTE: DSP_CMD_DMAEXIT_8 does not work with old 577 * soundblaster. 578 */ 579 sb_cmd(sb, DSP_CMD_DMAEXIT_8); 580#endif 581 sb_reset_dsp(sb); 582 } 583 584 if (play) 585 sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */ 586 sb_unlock(sb); 587 sb->bd_flags &= ~BD_F_DMARUN; 588 return 0; 589} 590 591/* channel interface */ 592static void * 593sbchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 594{ 595 struct sb_info *sb = devinfo; 596 struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch; 597 598 ch->parent = sb; 599 ch->channel = c; 600 ch->dir = dir; 601 ch->buffer = b; 602 if (sndbuf_alloc(ch->buffer, sb->parent_dmat, 0, sb->bufsize) != 0) 603 return NULL; 604 sndbuf_dmasetup(ch->buffer, sb->drq); 605 return ch; 606} 607 608static int 609sbchan_setformat(kobj_t obj, void *data, u_int32_t format) 610{ 611 struct sb_chinfo *ch = data; 612 613 ch->fmt = format; 614 return 0; 615} 616 617static int 618sbchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 619{ 620 struct sb_chinfo *ch = data; 621 622 ch->spd = speed; 623 return sb_speed(ch); 624} 625 626static int 627sbchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 628{ 629 struct sb_chinfo *ch = data; 630 631 ch->blksz = blocksize; 632 return ch->blksz; 633} 634 635static int 636sbchan_trigger(kobj_t obj, void *data, int go) 637{ 638 struct sb_chinfo *ch = data; 639
| 42 43#define SB_DEFAULT_BUFSZ 4096 44 45static u_int32_t sb_fmt[] = { 46 AFMT_U8, 47 0 48}; 49static struct pcmchan_caps sb200_playcaps = {4000, 23000, sb_fmt, 0}; 50static struct pcmchan_caps sb200_reccaps = {4000, 13000, sb_fmt, 0}; 51static struct pcmchan_caps sb201_playcaps = {4000, 44100, sb_fmt, 0}; 52static struct pcmchan_caps sb201_reccaps = {4000, 15000, sb_fmt, 0}; 53 54static u_int32_t sbpro_fmt[] = { 55 AFMT_U8, 56 AFMT_STEREO | AFMT_U8, 57 0 58}; 59static struct pcmchan_caps sbpro_playcaps = {4000, 44100, sbpro_fmt, 0}; 60static struct pcmchan_caps sbpro_reccaps = {4000, 44100, sbpro_fmt, 0}; 61 62struct sb_info; 63 64struct sb_chinfo { 65 struct sb_info *parent; 66 struct pcm_channel *channel; 67 struct snd_dbuf *buffer; 68 int dir; 69 u_int32_t fmt, spd, blksz; 70}; 71 72struct sb_info { 73 device_t parent_dev; 74 struct resource *io_base; /* I/O address for the board */ 75 struct resource *irq; 76 struct resource *drq; 77 void *ih; 78 bus_dma_tag_t parent_dmat; 79 80 unsigned int bufsize; 81 int bd_id; 82 u_long bd_flags; /* board-specific flags */ 83 struct sb_chinfo pch, rch; 84}; 85 86static int sb_rd(struct sb_info *sb, int reg); 87static void sb_wr(struct sb_info *sb, int reg, u_int8_t val); 88static int sb_dspready(struct sb_info *sb); 89static int sb_cmd(struct sb_info *sb, u_char val); 90static int sb_cmd1(struct sb_info *sb, u_char cmd, int val); 91static int sb_cmd2(struct sb_info *sb, u_char cmd, int val); 92static u_int sb_get_byte(struct sb_info *sb); 93static void sb_setmixer(struct sb_info *sb, u_int port, u_int value); 94static int sb_getmixer(struct sb_info *sb, u_int port); 95static int sb_reset_dsp(struct sb_info *sb); 96 97static void sb_intr(void *arg); 98static int sb_speed(struct sb_chinfo *ch); 99static int sb_start(struct sb_chinfo *ch); 100static int sb_stop(struct sb_chinfo *ch); 101 102/* 103 * Common code for the midi and pcm functions 104 * 105 * sb_cmd write a single byte to the CMD port. 106 * sb_cmd1 write a CMD + 1 byte arg 107 * sb_cmd2 write a CMD + 2 byte arg 108 * sb_get_byte returns a single byte from the DSP data port 109 */ 110 111static void 112sb_lock(struct sb_info *sb) { 113 114 sbc_lock(device_get_softc(sb->parent_dev)); 115} 116 117static void 118sb_unlock(struct sb_info *sb) { 119 120 sbc_unlock(device_get_softc(sb->parent_dev)); 121} 122 123static int 124port_rd(struct resource *port, int off) 125{ 126 return bus_space_read_1(rman_get_bustag(port), rman_get_bushandle(port), off); 127} 128 129static void 130port_wr(struct resource *port, int off, u_int8_t data) 131{ 132 bus_space_write_1(rman_get_bustag(port), rman_get_bushandle(port), off, data); 133} 134 135static int 136sb_rd(struct sb_info *sb, int reg) 137{ 138 return port_rd(sb->io_base, reg); 139} 140 141static void 142sb_wr(struct sb_info *sb, int reg, u_int8_t val) 143{ 144 port_wr(sb->io_base, reg, val); 145} 146 147static int 148sb_dspready(struct sb_info *sb) 149{ 150 return ((sb_rd(sb, SBDSP_STATUS) & 0x80) == 0); 151} 152 153static int 154sb_dspwr(struct sb_info *sb, u_char val) 155{ 156 int i; 157 158 for (i = 0; i < 1000; i++) { 159 if (sb_dspready(sb)) { 160 sb_wr(sb, SBDSP_CMD, val); 161 return 1; 162 } 163 if (i > 10) DELAY((i > 100)? 1000 : 10); 164 } 165 printf("sb_dspwr(0x%02x) timed out.\n", val); 166 return 0; 167} 168 169static int 170sb_cmd(struct sb_info *sb, u_char val) 171{ 172#if 0 173 printf("sb_cmd: %x\n", val); 174#endif 175 return sb_dspwr(sb, val); 176} 177 178static int 179sb_cmd1(struct sb_info *sb, u_char cmd, int val) 180{ 181#if 0 182 printf("sb_cmd1: %x, %x\n", cmd, val); 183#endif 184 if (sb_dspwr(sb, cmd)) { 185 return sb_dspwr(sb, val & 0xff); 186 } else return 0; 187} 188 189static int 190sb_cmd2(struct sb_info *sb, u_char cmd, int val) 191{ 192#if 0 193 printf("sb_cmd2: %x, %x\n", cmd, val); 194#endif 195 if (sb_dspwr(sb, cmd)) { 196 return sb_dspwr(sb, val & 0xff) && 197 sb_dspwr(sb, (val >> 8) & 0xff); 198 } else return 0; 199} 200 201/* 202 * in the SB, there is a set of indirect "mixer" registers with 203 * address at offset 4, data at offset 5 204 * 205 * we don't need to interlock these, the mixer lock will suffice. 206 */ 207static void 208sb_setmixer(struct sb_info *sb, u_int port, u_int value) 209{ 210 sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 211 DELAY(10); 212 sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff)); 213 DELAY(10); 214} 215 216static int 217sb_getmixer(struct sb_info *sb, u_int port) 218{ 219 int val; 220 221 sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 222 DELAY(10); 223 val = sb_rd(sb, SB_MIX_DATA); 224 DELAY(10); 225 226 return val; 227} 228 229static u_int 230sb_get_byte(struct sb_info *sb) 231{ 232 int i; 233 234 for (i = 1000; i > 0; i--) { 235 if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80) 236 return sb_rd(sb, DSP_READ); 237 else 238 DELAY(20); 239 } 240 return 0xffff; 241} 242 243static int 244sb_reset_dsp(struct sb_info *sb) 245{ 246 sb_wr(sb, SBDSP_RST, 3); 247 DELAY(100); 248 sb_wr(sb, SBDSP_RST, 0); 249 if (sb_get_byte(sb) != 0xAA) { 250 DEB(printf("sb_reset_dsp 0x%lx failed\n", 251 rman_get_start(sb->io_base))); 252 return ENXIO; /* Sorry */ 253 } 254 return 0; 255} 256 257static void 258sb_release_resources(struct sb_info *sb, device_t dev) 259{ 260 if (sb->irq) { 261 if (sb->ih) 262 bus_teardown_intr(dev, sb->irq, sb->ih); 263 bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq); 264 sb->irq = 0; 265 } 266 if (sb->drq) { 267 isa_dma_release(rman_get_start(sb->drq)); 268 bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq); 269 sb->drq = 0; 270 } 271 if (sb->io_base) { 272 bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base); 273 sb->io_base = 0; 274 } 275 if (sb->parent_dmat) { 276 bus_dma_tag_destroy(sb->parent_dmat); 277 sb->parent_dmat = 0; 278 } 279 free(sb, M_DEVBUF); 280} 281 282static int 283sb_alloc_resources(struct sb_info *sb, device_t dev) 284{ 285 int rid; 286 287 rid = 0; 288 if (!sb->io_base) 289 sb->io_base = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 290 &rid, RF_ACTIVE); 291 rid = 0; 292 if (!sb->irq) 293 sb->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 294 &rid, RF_ACTIVE); 295 rid = 0; 296 if (!sb->drq) 297 sb->drq = bus_alloc_resource_any(dev, SYS_RES_DRQ, 298 &rid, RF_ACTIVE); 299 300 if (sb->io_base && sb->drq && sb->irq) { 301 isa_dma_acquire(rman_get_start(sb->drq)); 302 isa_dmainit(rman_get_start(sb->drq), sb->bufsize); 303 304 return 0; 305 } else return ENXIO; 306} 307 308/************************************************************/ 309 310static int 311sbpromix_init(struct snd_mixer *m) 312{ 313 struct sb_info *sb = mix_getdevinfo(m); 314 315 mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | 316 SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME); 317 318 mix_setrecdevs(m, SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD); 319 320 sb_setmixer(sb, 0, 1); /* reset mixer */ 321 322 return 0; 323} 324 325static int 326sbpromix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 327{ 328 struct sb_info *sb = mix_getdevinfo(m); 329 int reg, max; 330 u_char val; 331 332 max = 7; 333 switch (dev) { 334 case SOUND_MIXER_PCM: 335 reg = 0x04; 336 break; 337 338 case SOUND_MIXER_MIC: 339 reg = 0x0a; 340 max = 3; 341 break; 342 343 case SOUND_MIXER_VOLUME: 344 reg = 0x22; 345 break; 346 347 case SOUND_MIXER_SYNTH: 348 reg = 0x26; 349 break; 350 351 case SOUND_MIXER_CD: 352 reg = 0x28; 353 break; 354 355 case SOUND_MIXER_LINE: 356 reg = 0x2e; 357 break; 358 359 default: 360 return -1; 361 } 362 363 left = (left * max) / 100; 364 right = (dev == SOUND_MIXER_MIC)? left : ((right * max) / 100); 365 366 val = (dev == SOUND_MIXER_MIC)? (left << 1) : (left << 5 | right << 1); 367 sb_setmixer(sb, reg, val); 368 369 left = (left * 100) / max; 370 right = (right * 100) / max; 371 372 return left | (right << 8); 373} 374 375static int 376sbpromix_setrecsrc(struct snd_mixer *m, u_int32_t src) 377{ 378 struct sb_info *sb = mix_getdevinfo(m); 379 u_char recdev; 380 381 if (src == SOUND_MASK_LINE) 382 recdev = 0x06; 383 else if (src == SOUND_MASK_CD) 384 recdev = 0x02; 385 else { /* default: mic */ 386 src = SOUND_MASK_MIC; 387 recdev = 0; 388 } 389 sb_setmixer(sb, RECORD_SRC, recdev | (sb_getmixer(sb, RECORD_SRC) & ~0x07)); 390 391 return src; 392} 393 394static kobj_method_t sbpromix_mixer_methods[] = { 395 KOBJMETHOD(mixer_init, sbpromix_init), 396 KOBJMETHOD(mixer_set, sbpromix_set), 397 KOBJMETHOD(mixer_setrecsrc, sbpromix_setrecsrc), 398 { 0, 0 } 399}; 400MIXER_DECLARE(sbpromix_mixer); 401 402/************************************************************/ 403 404static int 405sbmix_init(struct snd_mixer *m) 406{ 407 struct sb_info *sb = mix_getdevinfo(m); 408 409 mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_CD | SOUND_MASK_VOLUME); 410 411 mix_setrecdevs(m, 0); 412 413 sb_setmixer(sb, 0, 1); /* reset mixer */ 414 415 return 0; 416} 417 418static int 419sbmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 420{ 421 struct sb_info *sb = mix_getdevinfo(m); 422 int reg, max; 423 424 max = 7; 425 switch (dev) { 426 case SOUND_MIXER_VOLUME: 427 reg = 0x2; 428 break; 429 430 case SOUND_MIXER_SYNTH: 431 reg = 0x6; 432 break; 433 434 case SOUND_MIXER_CD: 435 reg = 0x8; 436 break; 437 438 case SOUND_MIXER_PCM: 439 reg = 0x0a; 440 max = 3; 441 break; 442 443 default: 444 return -1; 445 } 446 447 left = (left * max) / 100; 448 449 sb_setmixer(sb, reg, left << 1); 450 451 left = (left * 100) / max; 452 453 return left | (left << 8); 454} 455 456static int 457sbmix_setrecsrc(struct snd_mixer *m, u_int32_t src) 458{ 459 return 0; 460} 461 462static kobj_method_t sbmix_mixer_methods[] = { 463 KOBJMETHOD(mixer_init, sbmix_init), 464 KOBJMETHOD(mixer_set, sbmix_set), 465 KOBJMETHOD(mixer_setrecsrc, sbmix_setrecsrc), 466 { 0, 0 } 467}; 468MIXER_DECLARE(sbmix_mixer); 469 470/************************************************************/ 471 472static void 473sb_intr(void *arg) 474{ 475 struct sb_info *sb = (struct sb_info *)arg; 476 477 sb_lock(sb); 478 if (sndbuf_runsz(sb->pch.buffer) > 0) { 479 sb_unlock(sb); 480 chn_intr(sb->pch.channel); 481 sb_lock(sb); 482 } 483 484 if (sndbuf_runsz(sb->rch.buffer) > 0) { 485 sb_unlock(sb); 486 chn_intr(sb->rch.channel); 487 sb_lock(sb); 488 } 489 490 sb_rd(sb, DSP_DATA_AVAIL); /* int ack */ 491 sb_unlock(sb); 492} 493 494static int 495sb_speed(struct sb_chinfo *ch) 496{ 497 struct sb_info *sb = ch->parent; 498 int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 499 int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0; 500 int speed, tmp, thresh, max; 501 u_char tconst; 502 503 if (sb->bd_id >= 0x300) { 504 thresh = stereo? 11025 : 23000; 505 max = stereo? 22050 : 44100; 506 } else if (sb->bd_id > 0x200) { 507 thresh = play? 23000 : 13000; 508 max = play? 44100 : 15000; 509 } else { 510 thresh = 999999; 511 max = play? 23000 : 13000; 512 } 513 514 speed = ch->spd; 515 if (speed > max) 516 speed = max; 517 518 sb_lock(sb); 519 sb->bd_flags &= ~BD_F_HISPEED; 520 if (speed > thresh) 521 sb->bd_flags |= BD_F_HISPEED; 522 523 tmp = 65536 - (256000000 / (speed << stereo)); 524 tconst = tmp >> 8; 525 526 sb_cmd1(sb, 0x40, tconst); /* set time constant */ 527 528 speed = (256000000 / (65536 - tmp)) >> stereo; 529 530 ch->spd = speed; 531 sb_unlock(sb); 532 return speed; 533} 534 535static int 536sb_start(struct sb_chinfo *ch) 537{ 538 struct sb_info *sb = ch->parent; 539 int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 540 int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0; 541 int l = ch->blksz; 542 u_char i; 543 544 l--; 545 546 sb_lock(sb); 547 if (play) 548 sb_cmd(sb, DSP_CMD_SPKON); 549 550 if (sb->bd_flags & BD_F_HISPEED) 551 i = play? 0x90 : 0x98; 552 else 553 i = play? 0x1c : 0x2c; 554 555 sb_setmixer(sb, 0x0e, stereo? 2 : 0); 556 sb_cmd2(sb, 0x48, l); 557 sb_cmd(sb, i); 558 559 sb->bd_flags |= BD_F_DMARUN; 560 sb_unlock(sb); 561 return 0; 562} 563 564static int 565sb_stop(struct sb_chinfo *ch) 566{ 567 struct sb_info *sb = ch->parent; 568 int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 569 570 sb_lock(sb); 571 if (sb->bd_flags & BD_F_HISPEED) 572 sb_reset_dsp(sb); 573 else { 574#if 0 575 /* 576 * NOTE: DSP_CMD_DMAEXIT_8 does not work with old 577 * soundblaster. 578 */ 579 sb_cmd(sb, DSP_CMD_DMAEXIT_8); 580#endif 581 sb_reset_dsp(sb); 582 } 583 584 if (play) 585 sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */ 586 sb_unlock(sb); 587 sb->bd_flags &= ~BD_F_DMARUN; 588 return 0; 589} 590 591/* channel interface */ 592static void * 593sbchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 594{ 595 struct sb_info *sb = devinfo; 596 struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch; 597 598 ch->parent = sb; 599 ch->channel = c; 600 ch->dir = dir; 601 ch->buffer = b; 602 if (sndbuf_alloc(ch->buffer, sb->parent_dmat, 0, sb->bufsize) != 0) 603 return NULL; 604 sndbuf_dmasetup(ch->buffer, sb->drq); 605 return ch; 606} 607 608static int 609sbchan_setformat(kobj_t obj, void *data, u_int32_t format) 610{ 611 struct sb_chinfo *ch = data; 612 613 ch->fmt = format; 614 return 0; 615} 616 617static int 618sbchan_setspeed(kobj_t obj, void *data, u_int32_t speed) 619{ 620 struct sb_chinfo *ch = data; 621 622 ch->spd = speed; 623 return sb_speed(ch); 624} 625 626static int 627sbchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 628{ 629 struct sb_chinfo *ch = data; 630 631 ch->blksz = blocksize; 632 return ch->blksz; 633} 634 635static int 636sbchan_trigger(kobj_t obj, void *data, int go) 637{ 638 struct sb_chinfo *ch = data; 639
|
641 return 0; 642 643 sndbuf_dma(ch->buffer, go); 644 if (go == PCMTRIG_START) 645 sb_start(ch); 646 else 647 sb_stop(ch); 648 return 0; 649} 650 651static int 652sbchan_getptr(kobj_t obj, void *data) 653{ 654 struct sb_chinfo *ch = data; 655 656 return sndbuf_dmaptr(ch->buffer); 657} 658 659static struct pcmchan_caps * 660sbchan_getcaps(kobj_t obj, void *data) 661{ 662 struct sb_chinfo *ch = data; 663 int p = (ch->dir == PCMDIR_PLAY)? 1 : 0; 664 665 if (ch->parent->bd_id == 0x200) 666 return p? &sb200_playcaps : &sb200_reccaps; 667 if (ch->parent->bd_id < 0x300) 668 return p? &sb201_playcaps : &sb201_reccaps; 669 return p? &sbpro_playcaps : &sbpro_reccaps; 670} 671 672static kobj_method_t sbchan_methods[] = { 673 KOBJMETHOD(channel_init, sbchan_init), 674 KOBJMETHOD(channel_setformat, sbchan_setformat), 675 KOBJMETHOD(channel_setspeed, sbchan_setspeed), 676 KOBJMETHOD(channel_setblocksize, sbchan_setblocksize), 677 KOBJMETHOD(channel_trigger, sbchan_trigger), 678 KOBJMETHOD(channel_getptr, sbchan_getptr), 679 KOBJMETHOD(channel_getcaps, sbchan_getcaps), 680 { 0, 0 } 681}; 682CHANNEL_DECLARE(sbchan); 683 684/************************************************************/ 685 686static int 687sb_probe(device_t dev) 688{ 689 char buf[64]; 690 uintptr_t func, ver, r, f; 691 692 /* The parent device has already been probed. */ 693 r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func); 694 if (func != SCF_PCM) 695 return (ENXIO); 696 697 r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 698 f = (ver & 0xffff0000) >> 16; 699 ver &= 0x0000ffff; 700 if ((f & BD_F_ESS) || (ver >= 0x400)) 701 return (ENXIO); 702 703 snprintf(buf, sizeof buf, "SB DSP %d.%02d", (int) ver >> 8, (int) ver & 0xff); 704 705 device_set_desc_copy(dev, buf); 706 707 return 0; 708} 709 710static int 711sb_attach(device_t dev) 712{ 713 struct sb_info *sb; 714 char status[SND_STATUSLEN]; 715 uintptr_t ver; 716 717 sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT | M_ZERO); 718 if (!sb) 719 return ENXIO; 720 721 sb->parent_dev = device_get_parent(dev); 722 BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 723 sb->bd_id = ver & 0x0000ffff; 724 sb->bd_flags = (ver & 0xffff0000) >> 16; 725 sb->bufsize = pcm_getbuffersize(dev, 4096, SB_DEFAULT_BUFSZ, 65536); 726 727 if (sb_alloc_resources(sb, dev)) 728 goto no; 729 if (sb_reset_dsp(sb)) 730 goto no; 731 if (mixer_init(dev, (sb->bd_id < 0x300)? &sbmix_mixer_class : &sbpromix_mixer_class, sb)) 732 goto no; 733 if (snd_setup_intr(dev, sb->irq, 0, sb_intr, sb, &sb->ih)) 734 goto no; 735 736 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 737 738 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 739 /*boundary*/0, 740 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 741 /*highaddr*/BUS_SPACE_MAXADDR, 742 /*filter*/NULL, /*filterarg*/NULL, 743 /*maxsize*/sb->bufsize, /*nsegments*/1, 744 /*maxsegz*/0x3ffff, /*flags*/0, 745 /*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant, 746 &sb->parent_dmat) != 0) { 747 device_printf(dev, "unable to create dma tag\n"); 748 goto no; 749 } 750 751 snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld bufsz %u %s", 752 rman_get_start(sb->io_base), rman_get_start(sb->irq), 753 rman_get_start(sb->drq), sb->bufsize, PCM_KLDSTRING(snd_sb8)); 754 755 if (pcm_register(dev, sb, 1, 1)) 756 goto no; 757 pcm_addchan(dev, PCMDIR_REC, &sbchan_class, sb); 758 pcm_addchan(dev, PCMDIR_PLAY, &sbchan_class, sb); 759 760 pcm_setstatus(dev, status); 761 762 return 0; 763 764no: 765 sb_release_resources(sb, dev); 766 return ENXIO; 767} 768 769static int 770sb_detach(device_t dev) 771{ 772 int r; 773 struct sb_info *sb; 774 775 r = pcm_unregister(dev); 776 if (r) 777 return r; 778 779 sb = pcm_getdevinfo(dev); 780 sb_release_resources(sb, dev); 781 return 0; 782} 783 784static device_method_t sb_methods[] = { 785 /* Device interface */ 786 DEVMETHOD(device_probe, sb_probe), 787 DEVMETHOD(device_attach, sb_attach), 788 DEVMETHOD(device_detach, sb_detach), 789 790 { 0, 0 } 791}; 792 793static driver_t sb_driver = { 794 "pcm", 795 sb_methods, 796 PCM_SOFTC_SIZE, 797}; 798 799DRIVER_MODULE(snd_sb8, sbc, sb_driver, pcm_devclass, 0, 0); 800MODULE_DEPEND(snd_sb8, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 801MODULE_DEPEND(snd_sb8, snd_sbc, 1, 1, 1); 802MODULE_VERSION(snd_sb8, 1); 803 804 805 806
| 641 return 0; 642 643 sndbuf_dma(ch->buffer, go); 644 if (go == PCMTRIG_START) 645 sb_start(ch); 646 else 647 sb_stop(ch); 648 return 0; 649} 650 651static int 652sbchan_getptr(kobj_t obj, void *data) 653{ 654 struct sb_chinfo *ch = data; 655 656 return sndbuf_dmaptr(ch->buffer); 657} 658 659static struct pcmchan_caps * 660sbchan_getcaps(kobj_t obj, void *data) 661{ 662 struct sb_chinfo *ch = data; 663 int p = (ch->dir == PCMDIR_PLAY)? 1 : 0; 664 665 if (ch->parent->bd_id == 0x200) 666 return p? &sb200_playcaps : &sb200_reccaps; 667 if (ch->parent->bd_id < 0x300) 668 return p? &sb201_playcaps : &sb201_reccaps; 669 return p? &sbpro_playcaps : &sbpro_reccaps; 670} 671 672static kobj_method_t sbchan_methods[] = { 673 KOBJMETHOD(channel_init, sbchan_init), 674 KOBJMETHOD(channel_setformat, sbchan_setformat), 675 KOBJMETHOD(channel_setspeed, sbchan_setspeed), 676 KOBJMETHOD(channel_setblocksize, sbchan_setblocksize), 677 KOBJMETHOD(channel_trigger, sbchan_trigger), 678 KOBJMETHOD(channel_getptr, sbchan_getptr), 679 KOBJMETHOD(channel_getcaps, sbchan_getcaps), 680 { 0, 0 } 681}; 682CHANNEL_DECLARE(sbchan); 683 684/************************************************************/ 685 686static int 687sb_probe(device_t dev) 688{ 689 char buf[64]; 690 uintptr_t func, ver, r, f; 691 692 /* The parent device has already been probed. */ 693 r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func); 694 if (func != SCF_PCM) 695 return (ENXIO); 696 697 r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 698 f = (ver & 0xffff0000) >> 16; 699 ver &= 0x0000ffff; 700 if ((f & BD_F_ESS) || (ver >= 0x400)) 701 return (ENXIO); 702 703 snprintf(buf, sizeof buf, "SB DSP %d.%02d", (int) ver >> 8, (int) ver & 0xff); 704 705 device_set_desc_copy(dev, buf); 706 707 return 0; 708} 709 710static int 711sb_attach(device_t dev) 712{ 713 struct sb_info *sb; 714 char status[SND_STATUSLEN]; 715 uintptr_t ver; 716 717 sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT | M_ZERO); 718 if (!sb) 719 return ENXIO; 720 721 sb->parent_dev = device_get_parent(dev); 722 BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 723 sb->bd_id = ver & 0x0000ffff; 724 sb->bd_flags = (ver & 0xffff0000) >> 16; 725 sb->bufsize = pcm_getbuffersize(dev, 4096, SB_DEFAULT_BUFSZ, 65536); 726 727 if (sb_alloc_resources(sb, dev)) 728 goto no; 729 if (sb_reset_dsp(sb)) 730 goto no; 731 if (mixer_init(dev, (sb->bd_id < 0x300)? &sbmix_mixer_class : &sbpromix_mixer_class, sb)) 732 goto no; 733 if (snd_setup_intr(dev, sb->irq, 0, sb_intr, sb, &sb->ih)) 734 goto no; 735 736 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 737 738 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 739 /*boundary*/0, 740 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 741 /*highaddr*/BUS_SPACE_MAXADDR, 742 /*filter*/NULL, /*filterarg*/NULL, 743 /*maxsize*/sb->bufsize, /*nsegments*/1, 744 /*maxsegz*/0x3ffff, /*flags*/0, 745 /*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant, 746 &sb->parent_dmat) != 0) { 747 device_printf(dev, "unable to create dma tag\n"); 748 goto no; 749 } 750 751 snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld bufsz %u %s", 752 rman_get_start(sb->io_base), rman_get_start(sb->irq), 753 rman_get_start(sb->drq), sb->bufsize, PCM_KLDSTRING(snd_sb8)); 754 755 if (pcm_register(dev, sb, 1, 1)) 756 goto no; 757 pcm_addchan(dev, PCMDIR_REC, &sbchan_class, sb); 758 pcm_addchan(dev, PCMDIR_PLAY, &sbchan_class, sb); 759 760 pcm_setstatus(dev, status); 761 762 return 0; 763 764no: 765 sb_release_resources(sb, dev); 766 return ENXIO; 767} 768 769static int 770sb_detach(device_t dev) 771{ 772 int r; 773 struct sb_info *sb; 774 775 r = pcm_unregister(dev); 776 if (r) 777 return r; 778 779 sb = pcm_getdevinfo(dev); 780 sb_release_resources(sb, dev); 781 return 0; 782} 783 784static device_method_t sb_methods[] = { 785 /* Device interface */ 786 DEVMETHOD(device_probe, sb_probe), 787 DEVMETHOD(device_attach, sb_attach), 788 DEVMETHOD(device_detach, sb_detach), 789 790 { 0, 0 } 791}; 792 793static driver_t sb_driver = { 794 "pcm", 795 sb_methods, 796 PCM_SOFTC_SIZE, 797}; 798 799DRIVER_MODULE(snd_sb8, sbc, sb_driver, pcm_devclass, 0, 0); 800MODULE_DEPEND(snd_sb8, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 801MODULE_DEPEND(snd_sb8, snd_sbc, 1, 1, 1); 802MODULE_VERSION(snd_sb8, 1); 803 804 805 806
|