1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2001 Orion Hodson <oho@acm.org> 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, WHETHERIN 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 THEPOSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * als4000.c - driver for the Avance Logic ALS 4000 chipset. 31 * 32 * The ALS4000 is effectively an SB16 with a PCI interface. 33 * 34 * This driver derives from ALS4000a.PDF, Bart Hartgers alsa driver, and 35 * SB16 register descriptions. 36 */ 37 38 #ifdef HAVE_KERNEL_OPTION_HEADERS 39 #include "opt_snd.h" 40 #endif 41 42 #include <dev/sound/pcm/sound.h> 43 #include <dev/sound/isa/sb.h> 44 #include <dev/sound/pci/als4000.h> 45 46 #include <dev/pci/pcireg.h> 47 #include <dev/pci/pcivar.h> 48 49 #include "mixer_if.h" 50 51 /* Debugging macro's */ 52 #undef DEB 53 #ifndef DEB 54 #define DEB(x) /* x */ 55 #endif /* DEB */ 56 57 #define ALS_DEFAULT_BUFSZ 16384 58 59 /* ------------------------------------------------------------------------- */ 60 /* Structures */ 61 62 struct sc_info; 63 64 struct sc_chinfo { 65 struct sc_info *parent; 66 struct pcm_channel *channel; 67 struct snd_dbuf *buffer; 68 u_int32_t format, speed, phys_buf, bps; 69 u_int32_t dma_active:1, dma_was_active:1; 70 u_int8_t gcr_fifo_status; 71 int dir; 72 }; 73 74 struct sc_info { 75 device_t dev; 76 bus_space_tag_t st; 77 bus_space_handle_t sh; 78 bus_dma_tag_t parent_dmat; 79 struct resource *reg, *irq; 80 int regid, irqid; 81 void *ih; 82 struct mtx *lock; 83 84 unsigned int bufsz; 85 struct sc_chinfo pch, rch; 86 }; 87 88 /* Channel caps */ 89 90 static u_int32_t als_format[] = { 91 SND_FORMAT(AFMT_U8, 1, 0), 92 SND_FORMAT(AFMT_U8, 2, 0), 93 SND_FORMAT(AFMT_S16_LE, 1, 0), 94 SND_FORMAT(AFMT_S16_LE, 2, 0), 95 0 96 }; 97 98 /* 99 * I don't believe this rotten soundcard can do 48k, really, 100 * trust me. 101 */ 102 static struct pcmchan_caps als_caps = { 4000, 44100, als_format, 0 }; 103 104 /* ------------------------------------------------------------------------- */ 105 /* Register Utilities */ 106 107 static u_int32_t 108 als_gcr_rd(struct sc_info *sc, int index) 109 { 110 bus_space_write_1(sc->st, sc->sh, ALS_GCR_INDEX, index); 111 return bus_space_read_4(sc->st, sc->sh, ALS_GCR_DATA); 112 } 113 114 static void 115 als_gcr_wr(struct sc_info *sc, int index, int data) 116 { 117 bus_space_write_1(sc->st, sc->sh, ALS_GCR_INDEX, index); 118 bus_space_write_4(sc->st, sc->sh, ALS_GCR_DATA, data); 119 } 120 121 static u_int8_t 122 als_intr_rd(struct sc_info *sc) 123 { 124 return bus_space_read_1(sc->st, sc->sh, ALS_SB_MPU_IRQ); 125 } 126 127 static void 128 als_intr_wr(struct sc_info *sc, u_int8_t data) 129 { 130 bus_space_write_1(sc->st, sc->sh, ALS_SB_MPU_IRQ, data); 131 } 132 133 static u_int8_t 134 als_mix_rd(struct sc_info *sc, u_int8_t index) 135 { 136 bus_space_write_1(sc->st, sc->sh, ALS_MIXER_INDEX, index); 137 return bus_space_read_1(sc->st, sc->sh, ALS_MIXER_DATA); 138 } 139 140 static void 141 als_mix_wr(struct sc_info *sc, u_int8_t index, u_int8_t data) 142 { 143 bus_space_write_1(sc->st, sc->sh, ALS_MIXER_INDEX, index); 144 bus_space_write_1(sc->st, sc->sh, ALS_MIXER_DATA, data); 145 } 146 147 static void 148 als_esp_wr(struct sc_info *sc, u_int8_t data) 149 { 150 u_int32_t tries, v; 151 152 tries = 1000; 153 do { 154 v = bus_space_read_1(sc->st, sc->sh, ALS_ESP_WR_STATUS); 155 if (~v & 0x80) 156 break; 157 DELAY(20); 158 } while (--tries != 0); 159 160 if (tries == 0) 161 device_printf(sc->dev, "als_esp_wr timeout"); 162 163 bus_space_write_1(sc->st, sc->sh, ALS_ESP_WR_DATA, data); 164 } 165 166 static int 167 als_esp_reset(struct sc_info *sc) 168 { 169 u_int32_t tries, u, v; 170 171 bus_space_write_1(sc->st, sc->sh, ALS_ESP_RST, 1); 172 DELAY(10); 173 bus_space_write_1(sc->st, sc->sh, ALS_ESP_RST, 0); 174 DELAY(30); 175 176 tries = 1000; 177 do { 178 u = bus_space_read_1(sc->st, sc->sh, ALS_ESP_RD_STATUS8); 179 if (u & 0x80) { 180 v = bus_space_read_1(sc->st, sc->sh, ALS_ESP_RD_DATA); 181 if (v == 0xaa) 182 return 0; 183 else 184 break; 185 } 186 DELAY(20); 187 } while (--tries != 0); 188 189 if (tries == 0) 190 device_printf(sc->dev, "als_esp_reset timeout"); 191 return 1; 192 } 193 194 static u_int8_t 195 als_ack_read(struct sc_info *sc, u_int8_t addr) 196 { 197 u_int8_t r = bus_space_read_1(sc->st, sc->sh, addr); 198 return r; 199 } 200 201 /* ------------------------------------------------------------------------- */ 202 /* Common pcm channel implementation */ 203 204 static void * 205 alschan_init(kobj_t obj, void *devinfo, 206 struct snd_dbuf *b, struct pcm_channel *c, int dir) 207 { 208 struct sc_info *sc = devinfo; 209 struct sc_chinfo *ch; 210 211 snd_mtxlock(sc->lock); 212 if (dir == PCMDIR_PLAY) { 213 ch = &sc->pch; 214 ch->gcr_fifo_status = ALS_GCR_FIFO0_STATUS; 215 } else { 216 ch = &sc->rch; 217 ch->gcr_fifo_status = ALS_GCR_FIFO1_STATUS; 218 } 219 ch->dir = dir; 220 ch->parent = sc; 221 ch->channel = c; 222 ch->bps = 1; 223 ch->format = SND_FORMAT(AFMT_U8, 1, 0); 224 ch->speed = DSP_DEFAULT_SPEED; 225 ch->buffer = b; 226 snd_mtxunlock(sc->lock); 227 228 if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0) 229 return NULL; 230 231 return ch; 232 } 233 234 static int 235 alschan_setformat(kobj_t obj, void *data, u_int32_t format) 236 { 237 struct sc_chinfo *ch = data; 238 239 ch->format = format; 240 return 0; 241 } 242 243 static u_int32_t 244 alschan_setspeed(kobj_t obj, void *data, u_int32_t speed) 245 { 246 struct sc_chinfo *ch = data, *other; 247 struct sc_info *sc = ch->parent; 248 249 other = (ch->dir == PCMDIR_PLAY) ? &sc->rch : &sc->pch; 250 251 /* Deny request if other dma channel is active */ 252 if (other->dma_active) { 253 ch->speed = other->speed; 254 return other->speed; 255 } 256 257 ch->speed = speed; 258 return speed; 259 } 260 261 static u_int32_t 262 alschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 263 { 264 struct sc_chinfo *ch = data; 265 struct sc_info *sc = ch->parent; 266 267 if (blocksize > sc->bufsz / 2) { 268 blocksize = sc->bufsz / 2; 269 } 270 sndbuf_resize(ch->buffer, 2, blocksize); 271 return blocksize; 272 } 273 274 static u_int32_t 275 alschan_getptr(kobj_t obj, void *data) 276 { 277 struct sc_chinfo *ch = data; 278 struct sc_info *sc = ch->parent; 279 int32_t pos, sz; 280 281 snd_mtxlock(sc->lock); 282 pos = als_gcr_rd(ch->parent, ch->gcr_fifo_status) & 0xffff; 283 snd_mtxunlock(sc->lock); 284 sz = sndbuf_getsize(ch->buffer); 285 return (2 * sz - pos - 1) % sz; 286 } 287 288 static struct pcmchan_caps* 289 alschan_getcaps(kobj_t obj, void *data) 290 { 291 return &als_caps; 292 } 293 294 static void 295 als_set_speed(struct sc_chinfo *ch) 296 { 297 struct sc_info *sc = ch->parent; 298 struct sc_chinfo *other; 299 300 other = (ch->dir == PCMDIR_PLAY) ? &sc->rch : &sc->pch; 301 if (other->dma_active == 0) { 302 als_esp_wr(sc, ALS_ESP_SAMPLE_RATE); 303 als_esp_wr(sc, ch->speed >> 8); 304 als_esp_wr(sc, ch->speed & 0xff); 305 } else { 306 DEB(printf("speed locked at %d (tried %d)\n", 307 other->speed, ch->speed)); 308 } 309 } 310 311 /* ------------------------------------------------------------------------- */ 312 /* Playback channel implementation */ 313 #define ALS_8BIT_CMD(x, y) { (x), (y), DSP_DMA8, DSP_CMD_DMAPAUSE_8 } 314 #define ALS_16BIT_CMD(x, y) { (x), (y), DSP_DMA16, DSP_CMD_DMAPAUSE_16 } 315 316 struct playback_command { 317 u_int32_t pcm_format; /* newpcm format */ 318 u_int8_t format_val; /* sb16 format value */ 319 u_int8_t dma_prog; /* sb16 dma program */ 320 u_int8_t dma_stop; /* sb16 stop register */ 321 } static const playback_cmds[] = { 322 ALS_8BIT_CMD(SND_FORMAT(AFMT_U8, 1, 0), DSP_MODE_U8MONO), 323 ALS_8BIT_CMD(SND_FORMAT(AFMT_U8, 2, 0), DSP_MODE_U8STEREO), 324 ALS_16BIT_CMD(SND_FORMAT(AFMT_S16_LE, 1, 0), DSP_MODE_S16MONO), 325 ALS_16BIT_CMD(SND_FORMAT(AFMT_S16_LE, 2, 0), DSP_MODE_S16STEREO), 326 }; 327 328 static const struct playback_command* 329 als_get_playback_command(u_int32_t format) 330 { 331 u_int32_t i, n; 332 333 n = sizeof(playback_cmds) / sizeof(playback_cmds[0]); 334 for (i = 0; i < n; i++) { 335 if (playback_cmds[i].pcm_format == format) { 336 return &playback_cmds[i]; 337 } 338 } 339 DEB(printf("als_get_playback_command: invalid format 0x%08x\n", 340 format)); 341 return &playback_cmds[0]; 342 } 343 344 static void 345 als_playback_start(struct sc_chinfo *ch) 346 { 347 const struct playback_command *p; 348 struct sc_info *sc = ch->parent; 349 u_int32_t buf, bufsz, count, dma_prog; 350 351 buf = sndbuf_getbufaddr(ch->buffer); 352 bufsz = sndbuf_getsize(ch->buffer); 353 count = bufsz / 2; 354 if (ch->format & AFMT_16BIT) 355 count /= 2; 356 count--; 357 358 als_esp_wr(sc, DSP_CMD_SPKON); 359 als_set_speed(ch); 360 361 als_gcr_wr(sc, ALS_GCR_DMA0_START, buf); 362 als_gcr_wr(sc, ALS_GCR_DMA0_MODE, (bufsz - 1) | 0x180000); 363 364 p = als_get_playback_command(ch->format); 365 dma_prog = p->dma_prog | DSP_F16_DAC | DSP_F16_AUTO | DSP_F16_FIFO_ON; 366 367 als_esp_wr(sc, dma_prog); 368 als_esp_wr(sc, p->format_val); 369 als_esp_wr(sc, count & 0xff); 370 als_esp_wr(sc, count >> 8); 371 372 ch->dma_active = 1; 373 } 374 375 static int 376 als_playback_stop(struct sc_chinfo *ch) 377 { 378 const struct playback_command *p; 379 struct sc_info *sc = ch->parent; 380 u_int32_t active; 381 382 active = ch->dma_active; 383 if (active) { 384 p = als_get_playback_command(ch->format); 385 als_esp_wr(sc, p->dma_stop); 386 } 387 ch->dma_active = 0; 388 return active; 389 } 390 391 static int 392 alspchan_trigger(kobj_t obj, void *data, int go) 393 { 394 struct sc_chinfo *ch = data; 395 struct sc_info *sc = ch->parent; 396 397 if (!PCMTRIG_COMMON(go)) 398 return 0; 399 400 snd_mtxlock(sc->lock); 401 switch(go) { 402 case PCMTRIG_START: 403 als_playback_start(ch); 404 break; 405 case PCMTRIG_STOP: 406 case PCMTRIG_ABORT: 407 als_playback_stop(ch); 408 break; 409 default: 410 break; 411 } 412 snd_mtxunlock(sc->lock); 413 return 0; 414 } 415 416 static kobj_method_t alspchan_methods[] = { 417 KOBJMETHOD(channel_init, alschan_init), 418 KOBJMETHOD(channel_setformat, alschan_setformat), 419 KOBJMETHOD(channel_setspeed, alschan_setspeed), 420 KOBJMETHOD(channel_setblocksize, alschan_setblocksize), 421 KOBJMETHOD(channel_trigger, alspchan_trigger), 422 KOBJMETHOD(channel_getptr, alschan_getptr), 423 KOBJMETHOD(channel_getcaps, alschan_getcaps), 424 KOBJMETHOD_END 425 }; 426 CHANNEL_DECLARE(alspchan); 427 428 /* ------------------------------------------------------------------------- */ 429 /* Capture channel implementation */ 430 431 static u_int8_t 432 als_get_fifo_format(struct sc_info *sc, u_int32_t format) 433 { 434 switch (format) { 435 case SND_FORMAT(AFMT_U8, 1, 0): 436 return ALS_FIFO1_8BIT; 437 case SND_FORMAT(AFMT_U8, 2, 0): 438 return ALS_FIFO1_8BIT | ALS_FIFO1_STEREO; 439 case SND_FORMAT(AFMT_S16_LE, 1, 0): 440 return ALS_FIFO1_SIGNED; 441 case SND_FORMAT(AFMT_S16_LE, 2, 0): 442 return ALS_FIFO1_SIGNED | ALS_FIFO1_STEREO; 443 } 444 device_printf(sc->dev, "format not found: 0x%08x\n", format); 445 return ALS_FIFO1_8BIT; 446 } 447 448 static void 449 als_capture_start(struct sc_chinfo *ch) 450 { 451 struct sc_info *sc = ch->parent; 452 u_int32_t buf, bufsz, count, dma_prog; 453 454 buf = sndbuf_getbufaddr(ch->buffer); 455 bufsz = sndbuf_getsize(ch->buffer); 456 count = bufsz / 2; 457 if (ch->format & AFMT_16BIT) 458 count /= 2; 459 count--; 460 461 als_esp_wr(sc, DSP_CMD_SPKON); 462 als_set_speed(ch); 463 464 als_gcr_wr(sc, ALS_GCR_FIFO1_START, buf); 465 als_gcr_wr(sc, ALS_GCR_FIFO1_COUNT, (bufsz - 1)); 466 467 als_mix_wr(sc, ALS_FIFO1_LENGTH_LO, count & 0xff); 468 als_mix_wr(sc, ALS_FIFO1_LENGTH_HI, count >> 8); 469 470 dma_prog = ALS_FIFO1_RUN | als_get_fifo_format(sc, ch->format); 471 als_mix_wr(sc, ALS_FIFO1_CONTROL, dma_prog); 472 473 ch->dma_active = 1; 474 } 475 476 static int 477 als_capture_stop(struct sc_chinfo *ch) 478 { 479 struct sc_info *sc = ch->parent; 480 u_int32_t active; 481 482 active = ch->dma_active; 483 if (active) { 484 als_mix_wr(sc, ALS_FIFO1_CONTROL, ALS_FIFO1_STOP); 485 } 486 ch->dma_active = 0; 487 return active; 488 } 489 490 static int 491 alsrchan_trigger(kobj_t obj, void *data, int go) 492 { 493 struct sc_chinfo *ch = data; 494 struct sc_info *sc = ch->parent; 495 496 snd_mtxlock(sc->lock); 497 switch(go) { 498 case PCMTRIG_START: 499 als_capture_start(ch); 500 break; 501 case PCMTRIG_STOP: 502 case PCMTRIG_ABORT: 503 als_capture_stop(ch); 504 break; 505 } 506 snd_mtxunlock(sc->lock); 507 return 0; 508 } 509 510 static kobj_method_t alsrchan_methods[] = { 511 KOBJMETHOD(channel_init, alschan_init), 512 KOBJMETHOD(channel_setformat, alschan_setformat), 513 KOBJMETHOD(channel_setspeed, alschan_setspeed), 514 KOBJMETHOD(channel_setblocksize, alschan_setblocksize), 515 KOBJMETHOD(channel_trigger, alsrchan_trigger), 516 KOBJMETHOD(channel_getptr, alschan_getptr), 517 KOBJMETHOD(channel_getcaps, alschan_getcaps), 518 KOBJMETHOD_END 519 }; 520 CHANNEL_DECLARE(alsrchan); 521 522 /* ------------------------------------------------------------------------- */ 523 /* Mixer related */ 524 525 /* 526 * ALS4000 has an sb16 mixer, with some additional controls that we do 527 * not yet a means to support. 528 */ 529 530 struct sb16props { 531 u_int8_t lreg; 532 u_int8_t rreg; 533 u_int8_t bits; 534 u_int8_t oselect; 535 u_int8_t iselect; /* left input mask */ 536 } static const amt[SOUND_MIXER_NRDEVICES] = { 537 [SOUND_MIXER_VOLUME] = { 0x30, 0x31, 5, 0x00, 0x00 }, 538 [SOUND_MIXER_PCM] = { 0x32, 0x33, 5, 0x00, 0x00 }, 539 [SOUND_MIXER_SYNTH] = { 0x34, 0x35, 5, 0x60, 0x40 }, 540 [SOUND_MIXER_CD] = { 0x36, 0x37, 5, 0x06, 0x04 }, 541 [SOUND_MIXER_LINE] = { 0x38, 0x39, 5, 0x18, 0x10 }, 542 [SOUND_MIXER_MIC] = { 0x3a, 0x00, 5, 0x01, 0x01 }, 543 [SOUND_MIXER_SPEAKER] = { 0x3b, 0x00, 2, 0x00, 0x00 }, 544 [SOUND_MIXER_IGAIN] = { 0x3f, 0x40, 2, 0x00, 0x00 }, 545 [SOUND_MIXER_OGAIN] = { 0x41, 0x42, 2, 0x00, 0x00 }, 546 /* The following have register values but no h/w implementation */ 547 [SOUND_MIXER_TREBLE] = { 0x44, 0x45, 4, 0x00, 0x00 }, 548 [SOUND_MIXER_BASS] = { 0x46, 0x47, 4, 0x00, 0x00 } 549 }; 550 551 static int 552 alsmix_init(struct snd_mixer *m) 553 { 554 u_int32_t i, v; 555 556 for (i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) { 557 if (amt[i].bits) v |= 1 << i; 558 } 559 mix_setdevs(m, v); 560 561 for (i = v = 0; i < SOUND_MIXER_NRDEVICES; i++) { 562 if (amt[i].iselect) v |= 1 << i; 563 } 564 mix_setrecdevs(m, v); 565 return 0; 566 } 567 568 static int 569 alsmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 570 { 571 struct sc_info *sc = mix_getdevinfo(m); 572 u_int32_t r, l, v, mask; 573 574 /* Fill upper n bits in mask with 1's */ 575 mask = ((1 << amt[dev].bits) - 1) << (8 - amt[dev].bits); 576 577 l = (left * mask / 100) & mask; 578 v = als_mix_rd(sc, amt[dev].lreg) & ~mask; 579 als_mix_wr(sc, amt[dev].lreg, l | v); 580 581 if (amt[dev].rreg) { 582 r = (right * mask / 100) & mask; 583 v = als_mix_rd(sc, amt[dev].rreg) & ~mask; 584 als_mix_wr(sc, amt[dev].rreg, r | v); 585 } else { 586 r = 0; 587 } 588 589 /* Zero gain does not mute channel from output, but this does. */ 590 v = als_mix_rd(sc, SB16_OMASK); 591 if (l == 0 && r == 0) { 592 v &= ~amt[dev].oselect; 593 } else { 594 v |= amt[dev].oselect; 595 } 596 als_mix_wr(sc, SB16_OMASK, v); 597 return 0; 598 } 599 600 static u_int32_t 601 alsmix_setrecsrc(struct snd_mixer *m, u_int32_t src) 602 { 603 struct sc_info *sc = mix_getdevinfo(m); 604 u_int32_t i, l, r; 605 606 for (i = l = r = 0; i < SOUND_MIXER_NRDEVICES; i++) { 607 if (src & (1 << i)) { 608 if (amt[i].iselect == 1) { /* microphone */ 609 l |= amt[i].iselect; 610 r |= amt[i].iselect; 611 } else { 612 l |= amt[i].iselect; 613 r |= amt[i].iselect >> 1; 614 } 615 } 616 } 617 618 als_mix_wr(sc, SB16_IMASK_L, l); 619 als_mix_wr(sc, SB16_IMASK_R, r); 620 return src; 621 } 622 623 static kobj_method_t als_mixer_methods[] = { 624 KOBJMETHOD(mixer_init, alsmix_init), 625 KOBJMETHOD(mixer_set, alsmix_set), 626 KOBJMETHOD(mixer_setrecsrc, alsmix_setrecsrc), 627 KOBJMETHOD_END 628 }; 629 MIXER_DECLARE(als_mixer); 630 631 /* ------------------------------------------------------------------------- */ 632 /* Interrupt Handler */ 633 634 static void 635 als_intr(void *p) 636 { 637 struct sc_info *sc = (struct sc_info *)p; 638 u_int8_t intr, sb_status; 639 640 snd_mtxlock(sc->lock); 641 intr = als_intr_rd(sc); 642 643 if (intr & 0x80) { 644 snd_mtxunlock(sc->lock); 645 chn_intr(sc->pch.channel); 646 snd_mtxlock(sc->lock); 647 } 648 649 if (intr & 0x40) { 650 snd_mtxunlock(sc->lock); 651 chn_intr(sc->rch.channel); 652 snd_mtxlock(sc->lock); 653 } 654 655 /* ACK interrupt in PCI core */ 656 als_intr_wr(sc, intr); 657 658 /* ACK interrupt in SB core */ 659 sb_status = als_mix_rd(sc, IRQ_STAT); 660 661 if (sb_status & ALS_IRQ_STATUS8) 662 als_ack_read(sc, ALS_ESP_RD_STATUS8); 663 if (sb_status & ALS_IRQ_STATUS16) 664 als_ack_read(sc, ALS_ESP_RD_STATUS16); 665 if (sb_status & ALS_IRQ_MPUIN) 666 als_ack_read(sc, ALS_MIDI_DATA); 667 if (sb_status & ALS_IRQ_CR1E) 668 als_ack_read(sc, ALS_CR1E_ACK_PORT); 669 670 snd_mtxunlock(sc->lock); 671 return; 672 } 673 674 /* ------------------------------------------------------------------------- */ 675 /* H/W initialization */ 676 677 static int 678 als_init(struct sc_info *sc) 679 { 680 u_int32_t i, v; 681 682 /* Reset Chip */ 683 if (als_esp_reset(sc)) { 684 return 1; 685 } 686 687 /* Enable write on DMA_SETUP register */ 688 v = als_mix_rd(sc, ALS_SB16_CONFIG); 689 als_mix_wr(sc, ALS_SB16_CONFIG, v | 0x80); 690 691 /* Select DMA0 */ 692 als_mix_wr(sc, ALS_SB16_DMA_SETUP, 0x01); 693 694 /* Disable write on DMA_SETUP register */ 695 als_mix_wr(sc, ALS_SB16_CONFIG, v & 0x7f); 696 697 /* Enable interrupts */ 698 v = als_gcr_rd(sc, ALS_GCR_MISC); 699 als_gcr_wr(sc, ALS_GCR_MISC, v | 0x28000); 700 701 /* Black out GCR DMA registers */ 702 for (i = 0x91; i <= 0x96; i++) { 703 als_gcr_wr(sc, i, 0); 704 } 705 706 /* Emulation mode */ 707 v = als_gcr_rd(sc, ALS_GCR_DMA_EMULATION); 708 als_gcr_wr(sc, ALS_GCR_DMA_EMULATION, v); 709 DEB(printf("GCR_DMA_EMULATION 0x%08x\n", v)); 710 return 0; 711 } 712 713 static void 714 als_uninit(struct sc_info *sc) 715 { 716 /* Disable interrupts */ 717 als_gcr_wr(sc, ALS_GCR_MISC, 0); 718 } 719 720 /* ------------------------------------------------------------------------- */ 721 /* Probe and attach card */ 722 723 static int 724 als_pci_probe(device_t dev) 725 { 726 if (pci_get_devid(dev) == ALS_PCI_ID0) { 727 device_set_desc(dev, "Avance Logic ALS4000"); 728 return BUS_PROBE_DEFAULT; 729 } 730 return ENXIO; 731 } 732 733 static void 734 als_resource_free(device_t dev, struct sc_info *sc) 735 { 736 if (sc->reg) { 737 bus_release_resource(dev, SYS_RES_IOPORT, sc->regid, sc->reg); 738 sc->reg = NULL; 739 } 740 if (sc->ih) { 741 bus_teardown_intr(dev, sc->irq, sc->ih); 742 sc->ih = NULL; 743 } 744 if (sc->irq) { 745 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 746 sc->irq = NULL; 747 } 748 if (sc->parent_dmat) { 749 bus_dma_tag_destroy(sc->parent_dmat); 750 sc->parent_dmat = 0; 751 } 752 if (sc->lock) { 753 snd_mtxfree(sc->lock); 754 sc->lock = NULL; 755 } 756 } 757 758 static int 759 als_resource_grab(device_t dev, struct sc_info *sc) 760 { 761 sc->regid = PCIR_BAR(0); 762 sc->reg = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->regid, 763 RF_ACTIVE); 764 if (sc->reg == NULL) { 765 device_printf(dev, "unable to allocate register space\n"); 766 goto bad; 767 } 768 sc->st = rman_get_bustag(sc->reg); 769 sc->sh = rman_get_bushandle(sc->reg); 770 771 sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid, 772 RF_ACTIVE | RF_SHAREABLE); 773 if (sc->irq == NULL) { 774 device_printf(dev, "unable to allocate interrupt\n"); 775 goto bad; 776 } 777 778 if (snd_setup_intr(dev, sc->irq, INTR_MPSAFE, als_intr, 779 sc, &sc->ih)) { 780 device_printf(dev, "unable to setup interrupt\n"); 781 goto bad; 782 } 783 784 sc->bufsz = pcm_getbuffersize(dev, 4096, ALS_DEFAULT_BUFSZ, 65536); 785 786 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), 787 /*alignment*/2, /*boundary*/0, 788 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 789 /*highaddr*/BUS_SPACE_MAXADDR, 790 /*filter*/NULL, /*filterarg*/NULL, 791 /*maxsize*/sc->bufsz, 792 /*nsegments*/1, /*maxsegz*/0x3ffff, 793 /*flags*/0, /*lockfunc*/NULL, 794 /*lockarg*/NULL, &sc->parent_dmat) != 0) { 795 device_printf(dev, "unable to create dma tag\n"); 796 goto bad; 797 } 798 return 0; 799 bad: 800 als_resource_free(dev, sc); 801 return ENXIO; 802 } 803 804 static int 805 als_pci_attach(device_t dev) 806 { 807 struct sc_info *sc; 808 char status[SND_STATUSLEN]; 809 810 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 811 sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_als4000 softc"); 812 sc->dev = dev; 813 814 pci_enable_busmaster(dev); 815 /* 816 * By default the power to the various components on the 817 * ALS4000 is entirely controlled by the pci powerstate. We 818 * could attempt finer grained control by setting GCR6.31. 819 */ 820 if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 821 /* Reset the power state. */ 822 device_printf(dev, "chip is in D%d power mode " 823 "-- setting to D0\n", pci_get_powerstate(dev)); 824 pci_set_powerstate(dev, PCI_POWERSTATE_D0); 825 } 826 827 if (als_resource_grab(dev, sc)) { 828 device_printf(dev, "failed to allocate resources\n"); 829 goto bad_attach; 830 } 831 832 if (als_init(sc)) { 833 device_printf(dev, "failed to initialize hardware\n"); 834 goto bad_attach; 835 } 836 837 if (mixer_init(dev, &als_mixer_class, sc)) { 838 device_printf(dev, "failed to initialize mixer\n"); 839 goto bad_attach; 840 } 841 842 if (pcm_register(dev, sc, 1, 1)) { 843 device_printf(dev, "failed to register pcm entries\n"); 844 goto bad_attach; 845 } 846 847 pcm_addchan(dev, PCMDIR_PLAY, &alspchan_class, sc); 848 pcm_addchan(dev, PCMDIR_REC, &alsrchan_class, sc); 849 850 snprintf(status, SND_STATUSLEN, "port 0x%jx irq %jd on %s", 851 rman_get_start(sc->reg), rman_get_start(sc->irq), 852 device_get_nameunit(device_get_parent(dev))); 853 pcm_setstatus(dev, status); 854 return 0; 855 856 bad_attach: 857 als_resource_free(dev, sc); 858 free(sc, M_DEVBUF); 859 return ENXIO; 860 } 861 862 static int 863 als_pci_detach(device_t dev) 864 { 865 struct sc_info *sc; 866 int r; 867 868 r = pcm_unregister(dev); 869 if (r) 870 return r; 871 872 sc = pcm_getdevinfo(dev); 873 als_uninit(sc); 874 als_resource_free(dev, sc); 875 free(sc, M_DEVBUF); 876 return 0; 877 } 878 879 static int 880 als_pci_suspend(device_t dev) 881 { 882 struct sc_info *sc = pcm_getdevinfo(dev); 883 884 snd_mtxlock(sc->lock); 885 sc->pch.dma_was_active = als_playback_stop(&sc->pch); 886 sc->rch.dma_was_active = als_capture_stop(&sc->rch); 887 als_uninit(sc); 888 snd_mtxunlock(sc->lock); 889 return 0; 890 } 891 892 static int 893 als_pci_resume(device_t dev) 894 { 895 struct sc_info *sc = pcm_getdevinfo(dev); 896 897 snd_mtxlock(sc->lock); 898 if (als_init(sc) != 0) { 899 device_printf(dev, "unable to reinitialize the card\n"); 900 snd_mtxunlock(sc->lock); 901 return ENXIO; 902 } 903 904 if (mixer_reinit(dev) != 0) { 905 device_printf(dev, "unable to reinitialize the mixer\n"); 906 snd_mtxunlock(sc->lock); 907 return ENXIO; 908 } 909 910 if (sc->pch.dma_was_active) { 911 als_playback_start(&sc->pch); 912 } 913 914 if (sc->rch.dma_was_active) { 915 als_capture_start(&sc->rch); 916 } 917 snd_mtxunlock(sc->lock); 918 919 return 0; 920 } 921 922 static device_method_t als_methods[] = { 923 /* Device interface */ 924 DEVMETHOD(device_probe, als_pci_probe), 925 DEVMETHOD(device_attach, als_pci_attach), 926 DEVMETHOD(device_detach, als_pci_detach), 927 DEVMETHOD(device_suspend, als_pci_suspend), 928 DEVMETHOD(device_resume, als_pci_resume), 929 { 0, 0 } 930 }; 931 932 static driver_t als_driver = { 933 "pcm", 934 als_methods, 935 PCM_SOFTC_SIZE, 936 }; 937 938 DRIVER_MODULE(snd_als4000, pci, als_driver, 0, 0); 939 MODULE_DEPEND(snd_als4000, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 940 MODULE_VERSION(snd_als4000, 1); 941