sbc.c revision 108064
1/* 2 * Copyright (c) 1999 Seigo Tanimura 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <dev/sound/chip.h> 28#include <dev/sound/pcm/sound.h> 29#include <dev/sound/isa/sb.h> 30 31SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/isa/sbc.c 108064 2002-12-18 22:53:24Z semenu $"); 32 33#define IO_MAX 3 34#define IRQ_MAX 1 35#define DRQ_MAX 2 36#define INTR_MAX 2 37 38struct sbc_softc; 39 40struct sbc_ihl { 41 driver_intr_t *intr[INTR_MAX]; 42 void *intr_arg[INTR_MAX]; 43 struct sbc_softc *parent; 44}; 45 46/* Here is the parameter structure per a device. */ 47struct sbc_softc { 48 device_t dev; /* device */ 49 device_t child_pcm, child_midi1, child_midi2; 50 51 int io_rid[IO_MAX]; /* io port rids */ 52 struct resource *io[IO_MAX]; /* io port resources */ 53 int io_alloced[IO_MAX]; /* io port alloc flag */ 54 55 int irq_rid[IRQ_MAX]; /* irq rids */ 56 struct resource *irq[IRQ_MAX]; /* irq resources */ 57 int irq_alloced[IRQ_MAX]; /* irq alloc flag */ 58 59 int drq_rid[DRQ_MAX]; /* drq rids */ 60 struct resource *drq[DRQ_MAX]; /* drq resources */ 61 int drq_alloced[DRQ_MAX]; /* drq alloc flag */ 62 63 struct sbc_ihl ihl[IRQ_MAX]; 64 65 void *ih[IRQ_MAX]; 66 67 struct mtx *lock; 68 69 u_int32_t bd_ver; 70}; 71 72static int sbc_probe(device_t dev); 73static int sbc_attach(device_t dev); 74static void sbc_intr(void *p); 75 76static struct resource *sbc_alloc_resource(device_t bus, device_t child, int type, int *rid, 77 u_long start, u_long end, u_long count, u_int flags); 78static int sbc_release_resource(device_t bus, device_t child, int type, int rid, 79 struct resource *r); 80static int sbc_setup_intr(device_t dev, device_t child, struct resource *irq, 81 int flags, driver_intr_t *intr, void *arg, 82 void **cookiep); 83static int sbc_teardown_intr(device_t dev, device_t child, struct resource *irq, 84 void *cookie); 85 86static int alloc_resource(struct sbc_softc *scp); 87static int release_resource(struct sbc_softc *scp); 88 89static devclass_t sbc_devclass; 90 91static int io_range[3] = {0x10, 0x2, 0x4}; 92 93#ifdef PC98 /* I/O address table for PC98 */ 94static bus_addr_t pcm_iat[] = { 95 0x000, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 96 0x800, 0x900, 0xa00, 0xb00, 0xc00, 0xd00, 0xe00, 0xf00 97}; 98static bus_addr_t midi_iat[] = { 99 0x000, 0x100 100}; 101static bus_addr_t opl_iat[] = { 102 0x000, 0x100, 0x200, 0x300 103}; 104static bus_addr_t *sb_iat[] = { pcm_iat, midi_iat, opl_iat }; 105#endif 106 107static int sb_rd(struct resource *io, int reg); 108static void sb_wr(struct resource *io, int reg, u_int8_t val); 109static int sb_dspready(struct resource *io); 110static int sb_cmd(struct resource *io, u_char val); 111static u_int sb_get_byte(struct resource *io); 112static void sb_setmixer(struct resource *io, u_int port, u_int value); 113 114static void 115sbc_lockinit(struct sbc_softc *scp) 116{ 117 scp->lock = snd_mtxcreate(device_get_nameunit(scp->dev), "sound softc"); 118} 119 120static void 121sbc_lockdestroy(struct sbc_softc *scp) 122{ 123 snd_mtxfree(scp->lock); 124} 125 126void 127sbc_lock(struct sbc_softc *scp) 128{ 129 snd_mtxlock(scp->lock); 130} 131 132void 133sbc_unlock(struct sbc_softc *scp) 134{ 135 snd_mtxunlock(scp->lock); 136} 137 138static int 139sb_rd(struct resource *io, int reg) 140{ 141 return bus_space_read_1(rman_get_bustag(io), 142 rman_get_bushandle(io), 143 reg); 144} 145 146static void 147sb_wr(struct resource *io, int reg, u_int8_t val) 148{ 149 bus_space_write_1(rman_get_bustag(io), 150 rman_get_bushandle(io), 151 reg, val); 152} 153 154static int 155sb_dspready(struct resource *io) 156{ 157 return ((sb_rd(io, SBDSP_STATUS) & 0x80) == 0); 158} 159 160static int 161sb_dspwr(struct resource *io, u_char val) 162{ 163 int i; 164 165 for (i = 0; i < 1000; i++) { 166 if (sb_dspready(io)) { 167 sb_wr(io, SBDSP_CMD, val); 168 return 1; 169 } 170 if (i > 10) DELAY((i > 100)? 1000 : 10); 171 } 172 printf("sb_dspwr(0x%02x) timed out.\n", val); 173 return 0; 174} 175 176static int 177sb_cmd(struct resource *io, u_char val) 178{ 179 return sb_dspwr(io, val); 180} 181 182static void 183sb_setmixer(struct resource *io, u_int port, u_int value) 184{ 185 u_long flags; 186 187 flags = spltty(); 188 sb_wr(io, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 189 DELAY(10); 190 sb_wr(io, SB_MIX_DATA, (u_char) (value & 0xff)); 191 DELAY(10); 192 splx(flags); 193} 194 195static u_int 196sb_get_byte(struct resource *io) 197{ 198 int i; 199 200 for (i = 1000; i > 0; i--) { 201 if (sb_rd(io, DSP_DATA_AVAIL) & 0x80) 202 return sb_rd(io, DSP_READ); 203 else 204 DELAY(20); 205 } 206 return 0xffff; 207} 208 209static int 210sb_reset_dsp(struct resource *io) 211{ 212 sb_wr(io, SBDSP_RST, 3); 213 DELAY(100); 214 sb_wr(io, SBDSP_RST, 0); 215 return (sb_get_byte(io) == 0xAA)? 0 : ENXIO; 216} 217 218static int 219sb_identify_board(struct resource *io) 220{ 221 int ver, essver, rev; 222 223 sb_cmd(io, DSP_CMD_GETVER); /* Get version */ 224 ver = (sb_get_byte(io) << 8) | sb_get_byte(io); 225 if (ver < 0x100 || ver > 0x4ff) return 0; 226 if (ver == 0x0301) { 227 /* Try to detect ESS chips. */ 228 sb_cmd(io, DSP_CMD_GETID); /* Return ident. bytes. */ 229 essver = (sb_get_byte(io) << 8) | sb_get_byte(io); 230 rev = essver & 0x000f; 231 essver &= 0xfff0; 232 if (essver == 0x4880) ver |= 0x1000; 233 else if (essver == 0x6880) ver = 0x0500 | rev; 234 } 235 return ver; 236} 237 238static struct isa_pnp_id sbc_ids[] = { 239 {0x01008c0e, "Creative ViBRA16C"}, /* CTL0001 */ 240 {0x31008c0e, "Creative SB16/SB32"}, /* CTL0031 */ 241 {0x41008c0e, "Creative SB16/SB32"}, /* CTL0041 */ 242 {0x42008c0e, "Creative SB AWE64"}, /* CTL0042 */ 243 {0x43008c0e, "Creative ViBRA16X"}, /* CTL0043 */ 244 {0x44008c0e, "Creative SB AWE64 Gold"}, /* CTL0044 */ 245 {0x45008c0e, "Creative SB AWE64"}, /* CTL0045 */ 246 {0x46008c0e, "Creative SB AWE64"}, /* CTL0046 */ 247 248 {0x01000000, "Avance Logic ALS100+"}, /* @@@0001 - ViBRA16X clone */ 249 {0x01100000, "Avance Asound 110"}, /* @@@1001 */ 250 {0x01200000, "Avance Logic ALS120"}, /* @@@2001 - ViBRA16X clone */ 251 252 {0x81167316, "ESS ES1681"}, /* ESS1681 */ 253 {0x02017316, "ESS ES1688"}, /* ESS1688 */ 254 {0x68187316, "ESS ES1868"}, /* ESS1868 */ 255 {0x03007316, "ESS ES1869"}, /* ESS1869 */ 256 {0x69187316, "ESS ES1869"}, /* ESS1869 */ 257 {0xabb0110e, "ESS ES1869 (Compaq OEM)"}, /* CPQb0ab */ 258 {0xacb0110e, "ESS ES1869 (Compaq OEM)"}, /* CPQb0ac */ 259 {0x78187316, "ESS ES1878"}, /* ESS1878 */ 260 {0x79187316, "ESS ES1879"}, /* ESS1879 */ 261 {0x88187316, "ESS ES1888"}, /* ESS1888 */ 262 {0x07017316, "ESS ES1888 (DEC OEM)"}, /* ESS0107 */ 263 {0x06017316, "ESS ES1888 (Dell OEM)"}, /* ESS0106 */ 264 {0} 265}; 266 267static int 268sbc_probe(device_t dev) 269{ 270 char *s = NULL; 271 u_int32_t lid, vid; 272 273 lid = isa_get_logicalid(dev); 274 vid = isa_get_vendorid(dev); 275 if (lid) { 276 if (lid == 0x01000000 && vid != 0x01009305) /* ALS0001 */ 277 return ENXIO; 278 /* Check pnp ids */ 279 return ISA_PNP_PROBE(device_get_parent(dev), dev, sbc_ids); 280 } else { 281 int rid = 0, ver; 282 struct resource *io; 283 284#ifdef PC98 285 io = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, 286 pcm_iat, 16, RF_ACTIVE); 287#else 288 io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 289 0, ~0, 16, RF_ACTIVE); 290#endif 291 if (!io) goto bad; 292#ifdef PC98 293 isa_load_resourcev(io, pcm_iat, 16); 294#endif 295 if (sb_reset_dsp(io)) goto bad2; 296 ver = sb_identify_board(io); 297 if (ver == 0) goto bad2; 298 switch ((ver & 0x00000f00) >> 8) { 299 case 1: 300 device_set_desc(dev, "SoundBlaster 1.0 (not supported)"); 301 s = NULL; 302 break; 303 304 case 2: 305 s = "SoundBlaster 2.0"; 306 break; 307 308 case 3: 309 s = (ver & 0x0000f000)? "ESS 488" : "SoundBlaster Pro"; 310 break; 311 312 case 4: 313 s = "SoundBlaster 16"; 314 break; 315 316 case 5: 317 s = (ver & 0x00000008)? "ESS 688" : "ESS 1688"; 318 break; 319 } 320 if (s) device_set_desc(dev, s); 321bad2: bus_release_resource(dev, SYS_RES_IOPORT, rid, io); 322bad: return s? 0 : ENXIO; 323 } 324} 325 326static int 327sbc_attach(device_t dev) 328{ 329 char *err = NULL; 330 struct sbc_softc *scp; 331 struct sndcard_func *func; 332 u_int32_t logical_id = isa_get_logicalid(dev); 333 int flags = device_get_flags(dev); 334 int f, dh, dl, x, irq, i; 335 336 if (!logical_id && (flags & DV_F_DUAL_DMA)) { 337 bus_set_resource(dev, SYS_RES_DRQ, 1, 338 flags & DV_F_DRQ_MASK, 1); 339 } 340 341 scp = device_get_softc(dev); 342 bzero(scp, sizeof(*scp)); 343 scp->dev = dev; 344 sbc_lockinit(scp); 345 err = "alloc_resource"; 346 if (alloc_resource(scp)) goto bad; 347 348 err = "sb_reset_dsp"; 349 if (sb_reset_dsp(scp->io[0])) goto bad; 350 err = "sb_identify_board"; 351 scp->bd_ver = sb_identify_board(scp->io[0]) & 0x00000fff; 352 if (scp->bd_ver == 0) goto bad; 353 f = 0; 354 if (logical_id == 0x01200000 && scp->bd_ver < 0x0400) scp->bd_ver = 0x0499; 355 switch ((scp->bd_ver & 0x0f00) >> 8) { 356 case 1: /* old sound blaster has nothing... */ 357 break; 358 359 case 2: 360 f |= BD_F_DUP_MIDI; 361 if (scp->bd_ver > 0x200) f |= BD_F_MIX_CT1335; 362 break; 363 364 case 5: 365 f |= BD_F_ESS; 366 scp->bd_ver = 0x0301; 367 case 3: 368 f |= BD_F_DUP_MIDI | BD_F_MIX_CT1345; 369 break; 370 371 case 4: 372 f |= BD_F_SB16 | BD_F_MIX_CT1745; 373 if (scp->drq[0]) dl = rman_get_start(scp->drq[0]); else dl = -1; 374 if (scp->drq[1]) dh = rman_get_start(scp->drq[1]); else dh = dl; 375 if (!logical_id && (dh < dl)) { 376 struct resource *r; 377 r = scp->drq[0]; 378 scp->drq[0] = scp->drq[1]; 379 scp->drq[1] = r; 380 dl = rman_get_start(scp->drq[0]); 381 dh = rman_get_start(scp->drq[1]); 382 } 383 /* soft irq/dma configuration */ 384 x = -1; 385 irq = rman_get_start(scp->irq[0]); 386#ifdef PC98 387 /* SB16 in PC98 use different IRQ table */ 388 if (irq == 3) x = 1; 389 else if (irq == 5) x = 8; 390 else if (irq == 10) x = 2; 391 else if (irq == 12) x = 4; 392 if (x == -1) { 393 err = "bad irq (3/5/10/12 valid)"; 394 goto bad; 395 } 396 else sb_setmixer(scp->io[0], IRQ_NR, x); 397 /* SB16 in PC98 use different dma setting */ 398 sb_setmixer(scp->io[0], DMA_NR, dh == 0 ? 1 : 2); 399#else 400 if (irq == 5) x = 2; 401 else if (irq == 7) x = 4; 402 else if (irq == 9) x = 1; 403 else if (irq == 10) x = 8; 404 if (x == -1) { 405 err = "bad irq (5/7/9/10 valid)"; 406 goto bad; 407 } 408 else sb_setmixer(scp->io[0], IRQ_NR, x); 409 sb_setmixer(scp->io[0], DMA_NR, (1 << dh) | (1 << dl)); 410#endif 411 if (bootverbose) { 412 device_printf(dev, "setting card to irq %d, drq %d", irq, dl); 413 if (dl != dh) printf(", %d", dh); 414 printf("\n"); 415 } 416 break; 417 } 418 419 switch (logical_id) { 420 case 0x43008c0e: /* CTL0043 */ 421 case 0x01200000: 422 case 0x01000000: 423 f |= BD_F_SB16X; 424 break; 425 } 426 scp->bd_ver |= f << 16; 427 428 err = "setup_intr"; 429 for (i = 0; i < IRQ_MAX; i++) { 430 scp->ihl[i].parent = scp; 431 if (snd_setup_intr(dev, scp->irq[i], INTR_MPSAFE, sbc_intr, &scp->ihl[i], &scp->ih[i])) 432 goto bad; 433 } 434 435 /* PCM Audio */ 436 func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); 437 if (func == NULL) goto bad; 438 func->func = SCF_PCM; 439 scp->child_pcm = device_add_child(dev, "pcm", -1); 440 device_set_ivars(scp->child_pcm, func); 441 442 /* Midi Interface */ 443 func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); 444 if (func == NULL) goto bad; 445 func->func = SCF_MIDI; 446 scp->child_midi1 = device_add_child(dev, "midi", -1); 447 device_set_ivars(scp->child_midi1, func); 448 449 /* OPL FM Synthesizer */ 450 func = malloc(sizeof(struct sndcard_func), M_DEVBUF, M_NOWAIT | M_ZERO); 451 if (func == NULL) goto bad; 452 func->func = SCF_SYNTH; 453 scp->child_midi2 = device_add_child(dev, "midi", -1); 454 device_set_ivars(scp->child_midi2, func); 455 456 /* probe/attach kids */ 457 bus_generic_attach(dev); 458 459 return (0); 460 461bad: if (err) device_printf(dev, "%s\n", err); 462 release_resource(scp); 463 return (ENXIO); 464} 465 466static int 467sbc_detach(device_t dev) 468{ 469 struct sbc_softc *scp = device_get_softc(dev); 470 471 sbc_lock(scp); 472 device_delete_child(dev, scp->child_midi2); 473 device_delete_child(dev, scp->child_midi1); 474 device_delete_child(dev, scp->child_pcm); 475 release_resource(scp); 476 sbc_lockdestroy(scp); 477 return bus_generic_detach(dev); 478} 479 480static void 481sbc_intr(void *p) 482{ 483 struct sbc_ihl *ihl = p; 484 int i; 485 486 /* sbc_lock(ihl->parent); */ 487 i = 0; 488 while (i < INTR_MAX) { 489 if (ihl->intr[i] != NULL) ihl->intr[i](ihl->intr_arg[i]); 490 i++; 491 } 492 /* sbc_unlock(ihl->parent); */ 493} 494 495static int 496sbc_setup_intr(device_t dev, device_t child, struct resource *irq, 497 int flags, driver_intr_t *intr, void *arg, 498 void **cookiep) 499{ 500 struct sbc_softc *scp = device_get_softc(dev); 501 struct sbc_ihl *ihl = NULL; 502 int i, ret; 503 504 sbc_lock(scp); 505 i = 0; 506 while (i < IRQ_MAX) { 507 if (irq == scp->irq[i]) ihl = &scp->ihl[i]; 508 i++; 509 } 510 ret = 0; 511 if (ihl == NULL) ret = EINVAL; 512 i = 0; 513 while ((ret == 0) && (i < INTR_MAX)) { 514 if (ihl->intr[i] == NULL) { 515 ihl->intr[i] = intr; 516 ihl->intr_arg[i] = arg; 517 *cookiep = &ihl->intr[i]; 518 ret = -1; 519 } else i++; 520 } 521 sbc_unlock(scp); 522 return (ret > 0)? EINVAL : 0; 523} 524 525static int 526sbc_teardown_intr(device_t dev, device_t child, struct resource *irq, 527 void *cookie) 528{ 529 struct sbc_softc *scp = device_get_softc(dev); 530 struct sbc_ihl *ihl = NULL; 531 int i, ret; 532 533 sbc_lock(scp); 534 i = 0; 535 while (i < IRQ_MAX) { 536 if (irq == scp->irq[i]) ihl = &scp->ihl[i]; 537 i++; 538 } 539 ret = 0; 540 if (ihl == NULL) ret = EINVAL; 541 i = 0; 542 while ((ret == 0) && (i < INTR_MAX)) { 543 if (cookie == &ihl->intr[i]) { 544 ihl->intr[i] = NULL; 545 ihl->intr_arg[i] = NULL; 546 return 0; 547 } else i++; 548 } 549 sbc_unlock(scp); 550 return (ret > 0)? EINVAL : 0; 551} 552 553static struct resource * 554sbc_alloc_resource(device_t bus, device_t child, int type, int *rid, 555 u_long start, u_long end, u_long count, u_int flags) 556{ 557 struct sbc_softc *scp; 558 int *alloced, rid_max, alloced_max; 559 struct resource **res; 560#ifdef PC98 561 int i; 562#endif 563 564 scp = device_get_softc(bus); 565 switch (type) { 566 case SYS_RES_IOPORT: 567 alloced = scp->io_alloced; 568 res = scp->io; 569#ifdef PC98 570 rid_max = 0; 571 for (i = 0; i < IO_MAX; i++) 572 rid_max += io_range[i]; 573#else 574 rid_max = IO_MAX - 1; 575#endif 576 alloced_max = 1; 577 break; 578 case SYS_RES_DRQ: 579 alloced = scp->drq_alloced; 580 res = scp->drq; 581 rid_max = DRQ_MAX - 1; 582 alloced_max = 1; 583 break; 584 case SYS_RES_IRQ: 585 alloced = scp->irq_alloced; 586 res = scp->irq; 587 rid_max = IRQ_MAX - 1; 588 alloced_max = INTR_MAX; /* pcm and mpu may share the irq. */ 589 break; 590 default: 591 return (NULL); 592 } 593 594 if (*rid > rid_max || alloced[*rid] == alloced_max) 595 return (NULL); 596 597 alloced[*rid]++; 598 return (res[*rid]); 599} 600 601static int 602sbc_release_resource(device_t bus, device_t child, int type, int rid, 603 struct resource *r) 604{ 605 struct sbc_softc *scp; 606 int *alloced, rid_max; 607 608 scp = device_get_softc(bus); 609 switch (type) { 610 case SYS_RES_IOPORT: 611 alloced = scp->io_alloced; 612 rid_max = IO_MAX - 1; 613 break; 614 case SYS_RES_DRQ: 615 alloced = scp->drq_alloced; 616 rid_max = DRQ_MAX - 1; 617 break; 618 case SYS_RES_IRQ: 619 alloced = scp->irq_alloced; 620 rid_max = IRQ_MAX - 1; 621 break; 622 default: 623 return (1); 624 } 625 626 if (rid > rid_max || alloced[rid] == 0) 627 return (1); 628 629 alloced[rid]--; 630 return (0); 631} 632 633static int 634sbc_read_ivar(device_t bus, device_t dev, int index, uintptr_t * result) 635{ 636 struct sbc_softc *scp = device_get_softc(bus); 637 struct sndcard_func *func = device_get_ivars(dev); 638 639 switch (index) { 640 case 0: 641 *result = func->func; 642 break; 643 644 case 1: 645 *result = scp->bd_ver; 646 break; 647 648 default: 649 return ENOENT; 650 } 651 652 return 0; 653} 654 655static int 656sbc_write_ivar(device_t bus, device_t dev, 657 int index, uintptr_t value) 658{ 659 switch (index) { 660 case 0: 661 case 1: 662 return EINVAL; 663 664 default: 665 return (ENOENT); 666 } 667} 668 669static int 670alloc_resource(struct sbc_softc *scp) 671{ 672 int i; 673 674 for (i = 0 ; i < IO_MAX ; i++) { 675 if (scp->io[i] == NULL) { 676#ifdef PC98 677 scp->io_rid[i] = i > 0 ? 678 scp->io_rid[i - 1] + io_range[i - 1] : 0; 679 scp->io[i] = isa_alloc_resourcev(scp->dev, 680 SYS_RES_IOPORT, 681 &scp->io_rid[i], 682 sb_iat[i], 683 io_range[i], 684 RF_ACTIVE); 685 if (scp->io[i] != NULL) 686 isa_load_resourcev(scp->io[i], sb_iat[i], 687 io_range[i]); 688#else 689 scp->io_rid[i] = i; 690 scp->io[i] = bus_alloc_resource(scp->dev, SYS_RES_IOPORT, &scp->io_rid[i], 691 0, ~0, io_range[i], RF_ACTIVE); 692#endif 693 if (i == 0 && scp->io[i] == NULL) 694 return (1); 695 scp->io_alloced[i] = 0; 696 } 697 } 698 for (i = 0 ; i < DRQ_MAX ; i++) { 699 if (scp->drq[i] == NULL) { 700 scp->drq_rid[i] = i; 701 scp->drq[i] = bus_alloc_resource(scp->dev, SYS_RES_DRQ, &scp->drq_rid[i], 702 0, ~0, 1, RF_ACTIVE); 703 if (i == 0 && scp->drq[i] == NULL) 704 return (1); 705 scp->drq_alloced[i] = 0; 706 } 707 } 708 for (i = 0 ; i < IRQ_MAX ; i++) { 709 if (scp->irq[i] == NULL) { 710 scp->irq_rid[i] = i; 711 scp->irq[i] = bus_alloc_resource(scp->dev, SYS_RES_IRQ, &scp->irq_rid[i], 712 0, ~0, 1, RF_ACTIVE); 713 if (i == 0 && scp->irq[i] == NULL) 714 return (1); 715 scp->irq_alloced[i] = 0; 716 } 717 } 718 return (0); 719} 720 721static int 722release_resource(struct sbc_softc *scp) 723{ 724 int i; 725 726 for (i = 0 ; i < IO_MAX ; i++) { 727 if (scp->io[i] != NULL) { 728 bus_release_resource(scp->dev, SYS_RES_IOPORT, scp->io_rid[i], scp->io[i]); 729 scp->io[i] = NULL; 730 } 731 } 732 for (i = 0 ; i < DRQ_MAX ; i++) { 733 if (scp->drq[i] != NULL) { 734 bus_release_resource(scp->dev, SYS_RES_DRQ, scp->drq_rid[i], scp->drq[i]); 735 scp->drq[i] = NULL; 736 } 737 } 738 for (i = 0 ; i < IRQ_MAX ; i++) { 739 if (scp->irq[i] != NULL) { 740 if (scp->ih[i] != NULL) 741 bus_teardown_intr(scp->dev, scp->irq[i], scp->ih[i]); 742 scp->ih[i] = NULL; 743 bus_release_resource(scp->dev, SYS_RES_IRQ, scp->irq_rid[i], scp->irq[i]); 744 scp->irq[i] = NULL; 745 } 746 } 747 return (0); 748} 749 750static device_method_t sbc_methods[] = { 751 /* Device interface */ 752 DEVMETHOD(device_probe, sbc_probe), 753 DEVMETHOD(device_attach, sbc_attach), 754 DEVMETHOD(device_detach, sbc_detach), 755 DEVMETHOD(device_shutdown, bus_generic_shutdown), 756 DEVMETHOD(device_suspend, bus_generic_suspend), 757 DEVMETHOD(device_resume, bus_generic_resume), 758 759 /* Bus interface */ 760 DEVMETHOD(bus_read_ivar, sbc_read_ivar), 761 DEVMETHOD(bus_write_ivar, sbc_write_ivar), 762 DEVMETHOD(bus_print_child, bus_generic_print_child), 763 DEVMETHOD(bus_alloc_resource, sbc_alloc_resource), 764 DEVMETHOD(bus_release_resource, sbc_release_resource), 765 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 766 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 767 DEVMETHOD(bus_setup_intr, sbc_setup_intr), 768 DEVMETHOD(bus_teardown_intr, sbc_teardown_intr), 769 770 { 0, 0 } 771}; 772 773static driver_t sbc_driver = { 774 "sbc", 775 sbc_methods, 776 sizeof(struct sbc_softc), 777}; 778 779/* sbc can be attached to an isa bus. */ 780DRIVER_MODULE(snd_sbc, isa, sbc_driver, sbc_devclass, 0, 0); 781MODULE_DEPEND(snd_sbc, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 782MODULE_VERSION(snd_sbc, 1); 783