ad1816.c revision 119853
1/* 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3 * Copyright Luigi Rizzo, 1997,1998 4 * Copyright by Hannu Savolainen 1994, 1995 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <dev/sound/pcm/sound.h> 30#include <dev/sound/isa/ad1816.h> 31 32#include <isa/isavar.h> 33 34#include "mixer_if.h" 35 36SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/isa/ad1816.c 119853 2003-09-07 16:28:03Z cg $"); 37 38struct ad1816_info; 39 40struct ad1816_chinfo { 41 struct ad1816_info *parent; 42 struct pcm_channel *channel; 43 struct snd_dbuf *buffer; 44 int dir, blksz; 45}; 46 47struct ad1816_info { 48 struct resource *io_base; /* primary I/O address for the board */ 49 int io_rid; 50 struct resource *irq; 51 int irq_rid; 52 struct resource *drq1; /* play */ 53 int drq1_rid; 54 struct resource *drq2; /* rec */ 55 int drq2_rid; 56 void *ih; 57 bus_dma_tag_t parent_dmat; 58 struct mtx *lock; 59 60 unsigned int bufsize; 61 struct ad1816_chinfo pch, rch; 62}; 63 64static u_int32_t ad1816_fmt[] = { 65 AFMT_U8, 66 AFMT_STEREO | AFMT_U8, 67 AFMT_S16_LE, 68 AFMT_STEREO | AFMT_S16_LE, 69 AFMT_MU_LAW, 70 AFMT_STEREO | AFMT_MU_LAW, 71 AFMT_A_LAW, 72 AFMT_STEREO | AFMT_A_LAW, 73 0 74}; 75 76static struct pcmchan_caps ad1816_caps = {4000, 55200, ad1816_fmt, 0}; 77 78#define AD1816_MUTE 31 /* value for mute */ 79 80static void 81ad1816_lock(struct ad1816_info *ad1816) 82{ 83 snd_mtxlock(ad1816->lock); 84} 85 86static void 87ad1816_unlock(struct ad1816_info *ad1816) 88{ 89 snd_mtxunlock(ad1816->lock); 90} 91 92static int 93port_rd(struct resource *port, int off) 94{ 95 if (port) 96 return bus_space_read_1(rman_get_bustag(port), 97 rman_get_bushandle(port), 98 off); 99 else 100 return -1; 101} 102 103static void 104port_wr(struct resource *port, int off, u_int8_t data) 105{ 106 if (port) 107 bus_space_write_1(rman_get_bustag(port), 108 rman_get_bushandle(port), 109 off, data); 110} 111 112static int 113io_rd(struct ad1816_info *ad1816, int reg) 114{ 115 return port_rd(ad1816->io_base, reg); 116} 117 118static void 119io_wr(struct ad1816_info *ad1816, int reg, u_int8_t data) 120{ 121 port_wr(ad1816->io_base, reg, data); 122} 123 124static void 125ad1816_intr(void *arg) 126{ 127 struct ad1816_info *ad1816 = (struct ad1816_info *)arg; 128 unsigned char c, served = 0; 129 130 ad1816_lock(ad1816); 131 /* get interupt status */ 132 c = io_rd(ad1816, AD1816_INT); 133 134 /* check for stray interupts */ 135 if (c & ~(AD1816_INTRCI | AD1816_INTRPI)) { 136 printf("pcm: stray int (%x)\n", c); 137 c &= AD1816_INTRCI | AD1816_INTRPI; 138 } 139 /* check for capture interupt */ 140 if (sndbuf_runsz(ad1816->rch.buffer) && (c & AD1816_INTRCI)) { 141 chn_intr(ad1816->rch.channel); 142 served |= AD1816_INTRCI; /* cp served */ 143 } 144 /* check for playback interupt */ 145 if (sndbuf_runsz(ad1816->pch.buffer) && (c & AD1816_INTRPI)) { 146 chn_intr(ad1816->pch.channel); 147 served |= AD1816_INTRPI; /* pb served */ 148 } 149 if (served == 0) { 150 /* this probably means this is not a (working) ad1816 chip, */ 151 /* or an error in dma handling */ 152 printf("pcm: int without reason (%x)\n", c); 153 c = 0; 154 } else c &= ~served; 155 io_wr(ad1816, AD1816_INT, c); 156 c = io_rd(ad1816, AD1816_INT); 157 if (c != 0) printf("pcm: int clear failed (%x)\n", c); 158 ad1816_unlock(ad1816); 159} 160 161static int 162ad1816_wait_init(struct ad1816_info *ad1816, int x) 163{ 164 int n = 0; /* to shut up the compiler... */ 165 166 for (; x--;) 167 if ((n = (io_rd(ad1816, AD1816_ALE) & AD1816_BUSY)) == 0) DELAY(10); 168 else return n; 169 printf("ad1816_wait_init failed 0x%02x.\n", n); 170 return -1; 171} 172 173static unsigned short 174ad1816_read(struct ad1816_info *ad1816, unsigned int reg) 175{ 176 u_short x = 0; 177 178 if (ad1816_wait_init(ad1816, 100) == -1) return 0; 179 io_wr(ad1816, AD1816_ALE, 0); 180 io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK)); 181 if (ad1816_wait_init(ad1816, 100) == -1) return 0; 182 x = (io_rd(ad1816, AD1816_HIGH) << 8) | io_rd(ad1816, AD1816_LOW); 183 return x; 184} 185 186static void 187ad1816_write(struct ad1816_info *ad1816, unsigned int reg, unsigned short data) 188{ 189 if (ad1816_wait_init(ad1816, 100) == -1) return; 190 io_wr(ad1816, AD1816_ALE, (reg & AD1816_ALEMASK)); 191 io_wr(ad1816, AD1816_LOW, (data & 0x000000ff)); 192 io_wr(ad1816, AD1816_HIGH, (data & 0x0000ff00) >> 8); 193} 194 195/* -------------------------------------------------------------------- */ 196 197static int 198ad1816mix_init(struct snd_mixer *m) 199{ 200 mix_setdevs(m, AD1816_MIXER_DEVICES); 201 mix_setrecdevs(m, AD1816_REC_DEVICES); 202 return 0; 203} 204 205static int 206ad1816mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 207{ 208 struct ad1816_info *ad1816 = mix_getdevinfo(m); 209 u_short reg = 0; 210 211 /* Scale volumes */ 212 left = AD1816_MUTE - (AD1816_MUTE * left) / 100; 213 right = AD1816_MUTE - (AD1816_MUTE * right) / 100; 214 215 reg = (left << 8) | right; 216 217 /* do channel selective muting if volume is zero */ 218 if (left == AD1816_MUTE) reg |= 0x8000; 219 if (right == AD1816_MUTE) reg |= 0x0080; 220 221 ad1816_lock(ad1816); 222 switch (dev) { 223 case SOUND_MIXER_VOLUME: /* Register 14 master volume */ 224 ad1816_write(ad1816, 14, reg); 225 break; 226 227 case SOUND_MIXER_CD: /* Register 15 cd */ 228 case SOUND_MIXER_LINE1: 229 ad1816_write(ad1816, 15, reg); 230 break; 231 232 case SOUND_MIXER_SYNTH: /* Register 16 synth */ 233 ad1816_write(ad1816, 16, reg); 234 break; 235 236 case SOUND_MIXER_PCM: /* Register 4 pcm */ 237 ad1816_write(ad1816, 4, reg); 238 break; 239 240 case SOUND_MIXER_LINE: 241 case SOUND_MIXER_LINE3: /* Register 18 line in */ 242 ad1816_write(ad1816, 18, reg); 243 break; 244 245 case SOUND_MIXER_MIC: /* Register 19 mic volume */ 246 ad1816_write(ad1816, 19, reg & ~0xff); /* mic is mono */ 247 break; 248 249 case SOUND_MIXER_IGAIN: 250 /* and now to something completely different ... */ 251 ad1816_write(ad1816, 20, ((ad1816_read(ad1816, 20) & ~0x0f0f) 252 | (((AD1816_MUTE - left) / 2) << 8) /* four bits of adc gain */ 253 | ((AD1816_MUTE - right) / 2))); 254 break; 255 256 default: 257 printf("ad1816_mixer_set(): unknown device.\n"); 258 break; 259 } 260 ad1816_unlock(ad1816); 261 262 left = ((AD1816_MUTE - left) * 100) / AD1816_MUTE; 263 right = ((AD1816_MUTE - right) * 100) / AD1816_MUTE; 264 265 return left | (right << 8); 266} 267 268static int 269ad1816mix_setrecsrc(struct snd_mixer *m, u_int32_t src) 270{ 271 struct ad1816_info *ad1816 = mix_getdevinfo(m); 272 int dev; 273 274 switch (src) { 275 case SOUND_MASK_LINE: 276 case SOUND_MASK_LINE3: 277 dev = 0x00; 278 break; 279 280 case SOUND_MASK_CD: 281 case SOUND_MASK_LINE1: 282 dev = 0x20; 283 break; 284 285 case SOUND_MASK_MIC: 286 default: 287 dev = 0x50; 288 src = SOUND_MASK_MIC; 289 } 290 291 dev |= dev << 8; 292 ad1816_lock(ad1816); 293 ad1816_write(ad1816, 20, (ad1816_read(ad1816, 20) & ~0x7070) | dev); 294 ad1816_unlock(ad1816); 295 return src; 296} 297 298static kobj_method_t ad1816mixer_methods[] = { 299 KOBJMETHOD(mixer_init, ad1816mix_init), 300 KOBJMETHOD(mixer_set, ad1816mix_set), 301 KOBJMETHOD(mixer_setrecsrc, ad1816mix_setrecsrc), 302 { 0, 0 } 303}; 304MIXER_DECLARE(ad1816mixer); 305 306/* -------------------------------------------------------------------- */ 307/* channel interface */ 308static void * 309ad1816chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 310{ 311 struct ad1816_info *ad1816 = devinfo; 312 struct ad1816_chinfo *ch = (dir == PCMDIR_PLAY)? &ad1816->pch : &ad1816->rch; 313 314 ch->parent = ad1816; 315 ch->channel = c; 316 ch->buffer = b; 317 if (sndbuf_alloc(ch->buffer, ad1816->parent_dmat, ad1816->bufsize) == -1) return NULL; 318 return ch; 319} 320 321static int 322ad1816chan_setdir(kobj_t obj, void *data, int dir) 323{ 324 struct ad1816_chinfo *ch = data; 325 struct ad1816_info *ad1816 = ch->parent; 326 327 sndbuf_dmasetup(ch->buffer, (dir == PCMDIR_PLAY)? ad1816->drq1 : ad1816->drq2); 328 ch->dir = dir; 329 return 0; 330} 331 332static int 333ad1816chan_setformat(kobj_t obj, void *data, u_int32_t format) 334{ 335 struct ad1816_chinfo *ch = data; 336 struct ad1816_info *ad1816 = ch->parent; 337 int fmt = AD1816_U8, reg; 338 339 ad1816_lock(ad1816); 340 if (ch->dir == PCMDIR_PLAY) { 341 reg = AD1816_PLAY; 342 ad1816_write(ad1816, 8, 0x0000); /* reset base and current counter */ 343 ad1816_write(ad1816, 9, 0x0000); /* for playback and capture */ 344 } else { 345 reg = AD1816_CAPT; 346 ad1816_write(ad1816, 10, 0x0000); 347 ad1816_write(ad1816, 11, 0x0000); 348 } 349 switch (format & ~AFMT_STEREO) { 350 case AFMT_A_LAW: 351 fmt = AD1816_ALAW; 352 break; 353 354 case AFMT_MU_LAW: 355 fmt = AD1816_MULAW; 356 break; 357 358 case AFMT_S16_LE: 359 fmt = AD1816_S16LE; 360 break; 361 362 case AFMT_S16_BE: 363 fmt = AD1816_S16BE; 364 break; 365 366 case AFMT_U8: 367 fmt = AD1816_U8; 368 break; 369 } 370 if (format & AFMT_STEREO) fmt |= AD1816_STEREO; 371 io_wr(ad1816, reg, fmt); 372 ad1816_unlock(ad1816); 373#if 0 374 return format; 375#else 376 return 0; 377#endif 378} 379 380static int 381ad1816chan_setspeed(kobj_t obj, void *data, u_int32_t speed) 382{ 383 struct ad1816_chinfo *ch = data; 384 struct ad1816_info *ad1816 = ch->parent; 385 386 RANGE(speed, 4000, 55200); 387 ad1816_lock(ad1816); 388 ad1816_write(ad1816, (ch->dir == PCMDIR_PLAY)? 2 : 3, speed); 389 ad1816_unlock(ad1816); 390 return speed; 391} 392 393static int 394ad1816chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 395{ 396 struct ad1816_chinfo *ch = data; 397 398 ch->blksz = blocksize; 399 return ch->blksz; 400} 401 402static int 403ad1816chan_trigger(kobj_t obj, void *data, int go) 404{ 405 struct ad1816_chinfo *ch = data; 406 struct ad1816_info *ad1816 = ch->parent; 407 int wr, reg; 408 409 if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 410 return 0; 411 412 sndbuf_dma(ch->buffer, go); 413 wr = (ch->dir == PCMDIR_PLAY); 414 reg = wr? AD1816_PLAY : AD1816_CAPT; 415 ad1816_lock(ad1816); 416 switch (go) { 417 case PCMTRIG_START: 418 /* start only if not already running */ 419 if (!(io_rd(ad1816, reg) & AD1816_ENABLE)) { 420 int cnt = ((ch->blksz) >> 2) - 1; 421 ad1816_write(ad1816, wr? 8 : 10, cnt); /* count */ 422 ad1816_write(ad1816, wr? 9 : 11, 0); /* reset cur cnt */ 423 ad1816_write(ad1816, 1, ad1816_read(ad1816, 1) | 424 (wr? 0x8000 : 0x4000)); /* enable int */ 425 /* enable playback */ 426 io_wr(ad1816, reg, io_rd(ad1816, reg) | AD1816_ENABLE); 427 if (!(io_rd(ad1816, reg) & AD1816_ENABLE)) 428 printf("ad1816: failed to start %s DMA!\n", 429 wr? "play" : "rec"); 430 } 431 break; 432 433 case PCMTRIG_STOP: 434 case PCMTRIG_ABORT: /* XXX check this... */ 435 /* we don't test here if it is running... */ 436 if (wr) { 437 ad1816_write(ad1816, 1, ad1816_read(ad1816, 1) & 438 ~(wr? 0x8000 : 0x4000)); 439 /* disable int */ 440 io_wr(ad1816, reg, io_rd(ad1816, reg) & ~AD1816_ENABLE); 441 /* disable playback */ 442 if (io_rd(ad1816, reg) & AD1816_ENABLE) 443 printf("ad1816: failed to stop %s DMA!\n", 444 wr? "play" : "rec"); 445 ad1816_write(ad1816, wr? 8 : 10, 0); /* reset base cnt */ 446 ad1816_write(ad1816, wr? 9 : 11, 0); /* reset cur cnt */ 447 } 448 break; 449 } 450 ad1816_unlock(ad1816); 451 return 0; 452} 453 454static int 455ad1816chan_getptr(kobj_t obj, void *data) 456{ 457 struct ad1816_chinfo *ch = data; 458 return sndbuf_dmaptr(ch->buffer); 459} 460 461static struct pcmchan_caps * 462ad1816chan_getcaps(kobj_t obj, void *data) 463{ 464 return &ad1816_caps; 465} 466 467static kobj_method_t ad1816chan_methods[] = { 468 KOBJMETHOD(channel_init, ad1816chan_init), 469 KOBJMETHOD(channel_setdir, ad1816chan_setdir), 470 KOBJMETHOD(channel_setformat, ad1816chan_setformat), 471 KOBJMETHOD(channel_setspeed, ad1816chan_setspeed), 472 KOBJMETHOD(channel_setblocksize, ad1816chan_setblocksize), 473 KOBJMETHOD(channel_trigger, ad1816chan_trigger), 474 KOBJMETHOD(channel_getptr, ad1816chan_getptr), 475 KOBJMETHOD(channel_getcaps, ad1816chan_getcaps), 476 { 0, 0 } 477}; 478CHANNEL_DECLARE(ad1816chan); 479 480/* -------------------------------------------------------------------- */ 481 482static void 483ad1816_release_resources(struct ad1816_info *ad1816, device_t dev) 484{ 485 if (ad1816->irq) { 486 if (ad1816->ih) 487 bus_teardown_intr(dev, ad1816->irq, ad1816->ih); 488 bus_release_resource(dev, SYS_RES_IRQ, ad1816->irq_rid, ad1816->irq); 489 ad1816->irq = 0; 490 } 491 if (ad1816->drq1) { 492 isa_dma_release(rman_get_start(ad1816->drq1)); 493 bus_release_resource(dev, SYS_RES_DRQ, ad1816->drq1_rid, ad1816->drq1); 494 ad1816->drq1 = 0; 495 } 496 if (ad1816->drq2) { 497 isa_dma_release(rman_get_start(ad1816->drq2)); 498 bus_release_resource(dev, SYS_RES_DRQ, ad1816->drq2_rid, ad1816->drq2); 499 ad1816->drq2 = 0; 500 } 501 if (ad1816->io_base) { 502 bus_release_resource(dev, SYS_RES_IOPORT, ad1816->io_rid, ad1816->io_base); 503 ad1816->io_base = 0; 504 } 505 if (ad1816->parent_dmat) { 506 bus_dma_tag_destroy(ad1816->parent_dmat); 507 ad1816->parent_dmat = 0; 508 } 509 if (ad1816->lock) 510 snd_mtxfree(ad1816->lock); 511 512 free(ad1816, M_DEVBUF); 513} 514 515static int 516ad1816_alloc_resources(struct ad1816_info *ad1816, device_t dev) 517{ 518 int ok = 1, pdma, rdma; 519 520 if (!ad1816->io_base) 521 ad1816->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &ad1816->io_rid, 522 0, ~0, 1, RF_ACTIVE); 523 if (!ad1816->irq) 524 ad1816->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &ad1816->irq_rid, 525 0, ~0, 1, RF_ACTIVE); 526 if (!ad1816->drq1) 527 ad1816->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ, &ad1816->drq1_rid, 528 0, ~0, 1, RF_ACTIVE); 529 if (!ad1816->drq2) 530 ad1816->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ, &ad1816->drq2_rid, 531 0, ~0, 1, RF_ACTIVE); 532 533 if (!ad1816->io_base || !ad1816->drq1 || !ad1816->irq) ok = 0; 534 535 if (ok) { 536 pdma = rman_get_start(ad1816->drq1); 537 isa_dma_acquire(pdma); 538 isa_dmainit(pdma, ad1816->bufsize); 539 if (ad1816->drq2) { 540 rdma = rman_get_start(ad1816->drq2); 541 isa_dma_acquire(rdma); 542 isa_dmainit(rdma, ad1816->bufsize); 543 } else 544 rdma = pdma; 545 if (pdma == rdma) 546 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 547 } 548 549 return ok; 550} 551 552static int 553ad1816_init(struct ad1816_info *ad1816, device_t dev) 554{ 555 ad1816_write(ad1816, 1, 0x2); /* disable interrupts */ 556 ad1816_write(ad1816, 32, 0x90F0); /* SoundSys Mode, split fmt */ 557 558 ad1816_write(ad1816, 5, 0x8080); /* FM volume mute */ 559 ad1816_write(ad1816, 6, 0x8080); /* I2S1 volume mute */ 560 ad1816_write(ad1816, 7, 0x8080); /* I2S0 volume mute */ 561 ad1816_write(ad1816, 17, 0x8888); /* VID Volume mute */ 562 ad1816_write(ad1816, 20, 0x5050); /* recsrc mic, agc off */ 563 /* adc gain is set to 0 */ 564 565 return 0; 566} 567 568static int 569ad1816_probe(device_t dev) 570{ 571 char *s = NULL; 572 u_int32_t logical_id = isa_get_logicalid(dev); 573 574 switch (logical_id) { 575 case 0x80719304: /* ADS7180 */ 576 s = "AD1816"; 577 break; 578 } 579 580 if (s) { 581 device_set_desc(dev, s); 582 return 0; 583 } 584 return ENXIO; 585} 586 587static int 588ad1816_attach(device_t dev) 589{ 590 struct ad1816_info *ad1816; 591 char status[SND_STATUSLEN], status2[SND_STATUSLEN]; 592 593 ad1816 = (struct ad1816_info *)malloc(sizeof *ad1816, M_DEVBUF, M_NOWAIT | M_ZERO); 594 if (!ad1816) return ENXIO; 595 596 ad1816->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc"); 597 ad1816->io_rid = 2; 598 ad1816->irq_rid = 0; 599 ad1816->drq1_rid = 0; 600 ad1816->drq2_rid = 1; 601 ad1816->bufsize = pcm_getbuffersize(dev, 4096, DSP_BUFFSIZE, 65536); 602 603 if (!ad1816_alloc_resources(ad1816, dev)) goto no; 604 ad1816_init(ad1816, dev); 605 if (mixer_init(dev, &ad1816mixer_class, ad1816)) goto no; 606 607 snd_setup_intr(dev, ad1816->irq, INTR_MPSAFE, ad1816_intr, ad1816, &ad1816->ih); 608 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 609 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 610 /*highaddr*/BUS_SPACE_MAXADDR, 611 /*filter*/NULL, /*filterarg*/NULL, 612 /*maxsize*/ad1816->bufsize, /*nsegments*/1, 613 /*maxsegz*/0x3ffff, 614 /*flags*/0, /*lockfunc*/busdma_lock_mutex, 615 /*lockarg*/ &Giant, &ad1816->parent_dmat) != 0) { 616 device_printf(dev, "unable to create dma tag\n"); 617 goto no; 618 } 619 if (ad1816->drq2) 620 snprintf(status2, SND_STATUSLEN, ":%ld", rman_get_start(ad1816->drq2)); 621 else 622 status2[0] = '\0'; 623 624 snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u", 625 rman_get_start(ad1816->io_base), 626 rman_get_start(ad1816->irq), 627 rman_get_start(ad1816->drq1), 628 status2, 629 ad1816->bufsize); 630 631 if (pcm_register(dev, ad1816, 1, 1)) goto no; 632 pcm_addchan(dev, PCMDIR_REC, &ad1816chan_class, ad1816); 633 pcm_addchan(dev, PCMDIR_PLAY, &ad1816chan_class, ad1816); 634 pcm_setstatus(dev, status); 635 636 return 0; 637no: 638 ad1816_release_resources(ad1816, dev); 639 640 return ENXIO; 641 642} 643 644static int 645ad1816_detach(device_t dev) 646{ 647 int r; 648 struct ad1816_info *ad1816; 649 650 r = pcm_unregister(dev); 651 if (r) 652 return r; 653 654 ad1816 = pcm_getdevinfo(dev); 655 ad1816_release_resources(ad1816, dev); 656 return 0; 657} 658 659static device_method_t ad1816_methods[] = { 660 /* Device interface */ 661 DEVMETHOD(device_probe, ad1816_probe), 662 DEVMETHOD(device_attach, ad1816_attach), 663 DEVMETHOD(device_detach, ad1816_detach), 664 665 { 0, 0 } 666}; 667 668static driver_t ad1816_driver = { 669 "pcm", 670 ad1816_methods, 671 PCM_SOFTC_SIZE, 672}; 673 674DRIVER_MODULE(snd_ad1816, isa, ad1816_driver, pcm_devclass, 0, 0); 675MODULE_DEPEND(snd_ad1816, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 676MODULE_VERSION(snd_ad1816, 1); 677 678 679