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