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