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