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