1 /* 2 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 /* 27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 /* 32 * Copyright (C) 4Front Technologies 1996-2008. 33 */ 34 35 #include <sys/audio/audio_driver.h> 36 #include <sys/note.h> 37 #include <sys/pci.h> 38 #include <sys/stdbool.h> 39 40 41 /* 42 * NB: The Solo-1 is a bit schizophrenic compared to most devices. 43 * It has two separate DMA engines for PCM data. The first can do 44 * either capture or playback, and supports various Sound Blaster 45 * compatibility features. The second is dedicated to playback. The 46 * two engines have very little in common when it comes to programming 47 * them. 48 * 49 * We configure engine 1 for record, and engine 2 for playback. Both 50 * are configured for 48 kHz stereo 16-bit signed PCM. 51 */ 52 53 /* 54 * ESS Solo-1 only implements the low 24-bits on Audio1, and requires 55 * 64KB alignment. For Audio2, it implements the full 32-bit address 56 * space, but requires a 1MB address boundary. Audio1 is used for 57 * recording, and Audio2 is used for playback. 58 */ 59 static struct ddi_dma_attr dma_attr_audio1 = { 60 DMA_ATTR_VERSION, /* dma_attr_version */ 61 0x0, /* dma_attr_addr_lo */ 62 0x00ffffffU, /* dma_attr_addr_hi */ 63 0xffff, /* dma_attr_count_max */ 64 0x10000, /* dma_attr_align */ 65 0x7f, /* dma_attr_burstsizes */ 66 0x4, /* dma_attr_minxfer */ 67 0xffff, /* dma_attr_maxxfer */ 68 0xffff, /* dma_attr_seg */ 69 0x1, /* dma_attr_sgllen */ 70 0x1, /* dma_attr_granular */ 71 0 /* dma_attr_flags */ 72 }; 73 74 static struct ddi_dma_attr dma_attr_audio2 = { 75 DMA_ATTR_VERSION, /* dma_attr_version */ 76 0x0, /* dma_attr_addr_lo */ 77 0xffffffffU, /* dma_attr_addr_hi */ 78 0xfff0, /* dma_attr_count_max */ 79 0x100000, /* dma_attr_align */ 80 0x7f, /* dma_attr_burstsizes */ 81 0x4, /* dma_attr_minxfer */ 82 0xfff0, /* dma_attr_maxxfer */ 83 0xffff, /* dma_attr_seg */ 84 0x1, /* dma_attr_sgllen */ 85 0x1, /* dma_attr_granular */ 86 0 /* dma_attr_flags */ 87 }; 88 89 static ddi_device_acc_attr_t acc_attr = { 90 DDI_DEVICE_ATTR_V0, 91 DDI_STRUCTURE_LE_ACC, 92 DDI_STRICTORDER_ACC 93 }; 94 95 static ddi_device_acc_attr_t buf_attr = { 96 DDI_DEVICE_ATTR_V0, 97 DDI_NEVERSWAP_ACC, 98 DDI_STRICTORDER_ACC 99 }; 100 101 102 /* 103 * For the sake of simplicity, this driver fixes a few parameters with 104 * constants. If you want these values to be tunable, upgrade to a 105 * nicer and newer device. This is all tuned for 100 Hz (10 106 * millisecs) latency. 107 */ 108 #define SOLO_RATE 48000 109 #define SOLO_INTRS 100 110 #define SOLO_FRAGFR (SOLO_RATE / SOLO_INTRS) 111 #define SOLO_NFRAGS 8 112 #define SOLO_NCHAN 2 113 #define SOLO_SAMPSZ 2 114 #define SOLO_FRAGSZ (SOLO_FRAGFR * (SOLO_NCHAN * SOLO_SAMPSZ)) 115 #define SOLO_BUFFR (SOLO_NFRAGS * SOLO_FRAGFR) 116 #define SOLO_BUFSZ (SOLO_NFRAGS * SOLO_FRAGSZ) 117 118 #define INPUT_MIC 0 119 #define INPUT_LINE 1 120 #define INPUT_CD 2 121 #define INPUT_AUX 3 122 #define INPUT_MONO 4 123 #define INSRCS 0x1f /* bits 0-4 */ 124 125 #define DRVNAME "audiosolo" 126 127 static const char *solo_insrcs[] = { 128 AUDIO_PORT_MIC, 129 AUDIO_PORT_LINEIN, 130 AUDIO_PORT_CD, 131 AUDIO_PORT_AUX1IN, 132 AUDIO_PORT_AUX2IN, /* this is really mono-in */ 133 NULL 134 }; 135 136 typedef struct solo_regs { 137 ddi_acc_handle_t acch; 138 caddr_t base; 139 } solo_regs_t; 140 141 typedef struct solo_engine { 142 struct solo_dev *dev; 143 audio_engine_t *engine; 144 ddi_dma_handle_t dmah; 145 ddi_acc_handle_t acch; 146 caddr_t kaddr; 147 uint32_t paddr; 148 149 bool started; 150 uint64_t count; 151 uint16_t offset; 152 int syncdir; 153 int format; 154 bool swapped; 155 156 void (*start)(struct solo_engine *); 157 void (*stop)(struct solo_engine *); 158 void (*update)(struct solo_engine *); 159 } solo_engine_t; 160 161 typedef enum { 162 CTL_FRONT = 0, 163 CTL_VOLUME, 164 CTL_MIC, 165 CTL_LINE, 166 CTL_CD, 167 CTL_AUX, 168 CTL_MONO, 169 CTL_MICBOOST, 170 CTL_RECGAIN, 171 CTL_RECSRC, 172 CTL_MONSRC, 173 CTL_SPEAKER, 174 CTL_LOOPBACK, 175 CTL_NUM, /* must be last */ 176 } solo_ctrl_num_t; 177 178 typedef struct solo_ctrl { 179 struct solo_dev *dev; 180 audio_ctrl_t *ctrl; 181 solo_ctrl_num_t num; 182 uint64_t val; 183 } solo_ctrl_t; 184 185 typedef struct solo_dev { 186 dev_info_t *dip; 187 audio_dev_t *adev; 188 kmutex_t mutex; 189 ddi_intr_handle_t ihandle; 190 191 bool suspended; 192 193 /* 194 * Audio engines 195 */ 196 solo_engine_t rec; 197 solo_engine_t play; 198 uint32_t last_capture; 199 200 /* 201 * Controls. 202 */ 203 solo_ctrl_t ctrls[CTL_NUM]; 204 205 /* 206 * Mapped registers 207 */ 208 ddi_acc_handle_t pcih; 209 solo_regs_t io; 210 solo_regs_t sb; 211 solo_regs_t vc; 212 213 } solo_dev_t; 214 215 /* 216 * Common code for the pcm function 217 * 218 * solo_cmd write a single byte to the CMD port. 219 * solo_cmd1 write a CMD + 1 byte arg 220 * ess_get_byte returns a single byte from the DSP data port 221 * 222 * solo_write is actually solo_cmd1 223 * solo_read access ext. regs via solo_cmd(0xc0, reg) followed by solo_get_byte 224 */ 225 226 #define PORT_RD8(port, regno) \ 227 ddi_get8(port.acch, (void *)(port.base + (regno))) 228 #define PORT_RD16(port, regno) \ 229 ddi_get16(port.acch, (void *)(port.base + (regno))) 230 #define PORT_RD32(port, regno) \ 231 ddi_get32(port.acch, (void *)(port.base + (regno))) 232 #define PORT_WR8(port, regno, data) \ 233 ddi_put8(port.acch, (void *)(port.base + (regno)), data) 234 #define PORT_WR16(port, regno, data) \ 235 ddi_put16(port.acch, (void *)(port.base + (regno)), data) 236 #define PORT_WR32(port, regno, data) \ 237 ddi_put32(port.acch, (void *)(port.base + (regno)), data) 238 239 static bool 240 solo_dspready(solo_dev_t *dev) 241 { 242 return ((PORT_RD8(dev->sb, 0xc) & 0x80) == 0 ? true : false); 243 } 244 245 static bool 246 solo_dspwr(solo_dev_t *dev, uint8_t val) 247 { 248 int i; 249 250 for (i = 0; i < 1000; i++) { 251 if (solo_dspready(dev)) { 252 PORT_WR8(dev->sb, 0xc, val); 253 return (true); 254 } 255 if (i > 10) 256 drv_usecwait((i > 100)? 1000 : 10); 257 } 258 audio_dev_warn(dev->adev, "solo_dspwr(0x%02x) timed out", val); 259 return (false); 260 } 261 262 static bool 263 solo_cmd(solo_dev_t *dev, uint8_t val) 264 { 265 return (solo_dspwr(dev, val)); 266 } 267 268 static void 269 solo_cmd1(solo_dev_t *dev, uint8_t cmd, uint8_t val) 270 { 271 if (solo_dspwr(dev, cmd)) { 272 (void) solo_dspwr(dev, val); 273 } 274 } 275 276 static void 277 solo_setmixer(solo_dev_t *dev, uint8_t port, uint8_t value) 278 { 279 PORT_WR8(dev->sb, 0x4, port); /* Select register */ 280 drv_usecwait(10); 281 PORT_WR8(dev->sb, 0x5, value); 282 drv_usecwait(10); 283 } 284 285 static uint8_t 286 solo_getmixer(solo_dev_t *dev, uint8_t port) 287 { 288 uint8_t val; 289 290 PORT_WR8(dev->sb, 0x4, port); /* Select register */ 291 drv_usecwait(10); 292 val = PORT_RD8(dev->sb, 0x5); 293 drv_usecwait(10); 294 295 return (val); 296 } 297 298 static uint8_t 299 solo_get_byte(solo_dev_t *dev) 300 { 301 for (int i = 1000; i > 0; i--) { 302 if (PORT_RD8(dev->sb, 0xc) & 0x40) 303 return (PORT_RD8(dev->sb, 0xa)); 304 else 305 drv_usecwait(20); 306 } 307 audio_dev_warn(dev->adev, "timeout waiting to read DSP port"); 308 return (0xff); 309 } 310 311 static void 312 solo_write(solo_dev_t *dev, uint8_t reg, uint8_t val) 313 { 314 solo_cmd1(dev, reg, val); 315 } 316 317 static uint8_t 318 solo_read(solo_dev_t *dev, uint8_t reg) 319 { 320 if (solo_cmd(dev, 0xc0) && solo_cmd(dev, reg)) { 321 return (solo_get_byte(dev)); 322 } 323 return (0xff); 324 } 325 326 static bool 327 solo_reset_dsp(solo_dev_t *dev) 328 { 329 PORT_WR8(dev->sb, 0x6, 3); 330 drv_usecwait(100); 331 PORT_WR8(dev->sb, 0x6, 0); 332 if (solo_get_byte(dev) != 0xAA) { 333 audio_dev_warn(dev->adev, "solo_reset_dsp failed"); 334 return (false); /* Sorry */ 335 } 336 return (true); 337 } 338 339 static uint_t 340 solo_intr(caddr_t arg1, caddr_t arg2) 341 { 342 solo_dev_t *dev = (void *)arg1; 343 audio_engine_t *prod = NULL; 344 audio_engine_t *cons = NULL; 345 uint8_t status; 346 uint_t rv = DDI_INTR_UNCLAIMED; 347 348 _NOTE(ARGUNUSED(arg2)); 349 350 mutex_enter(&dev->mutex); 351 352 if (dev->suspended) { 353 mutex_exit(&dev->mutex); 354 return (rv); 355 } 356 357 status = PORT_RD8(dev->io, 0x7); 358 if (status & 0x20) { 359 rv = DDI_INTR_CLAIMED; 360 cons = dev->play.engine; 361 /* ack the interrupt */ 362 solo_setmixer(dev, 0x7a, solo_getmixer(dev, 0x7a) & ~0x80); 363 } 364 365 if (status & 0x10) { 366 rv = DDI_INTR_CLAIMED; 367 prod = dev->rec.engine; 368 /* ack the interrupt */ 369 (void) PORT_RD8(dev->sb, 0xe); 370 } 371 mutex_exit(&dev->mutex); 372 373 if (cons) { 374 audio_engine_consume(cons); 375 } 376 377 if (prod) { 378 audio_engine_produce(prod); 379 } 380 381 return (rv); 382 } 383 384 static uint8_t 385 solo_mixer_scale(solo_dev_t *dev, solo_ctrl_num_t num) 386 { 387 uint32_t l, r; 388 uint64_t value = dev->ctrls[num].val; 389 390 l = (value >> 8) & 0xff; 391 r = value & 0xff; 392 393 l = (l * 15) / 100; 394 r = (r * 15) / 100; 395 return ((uint8_t)((l << 4) | (r))); 396 } 397 398 static void 399 solo_configure_mixer(solo_dev_t *dev) 400 { 401 uint32_t v; 402 uint32_t mon, rec; 403 404 /* 405 * We disable hardware volume control (i.e. async updates to volume). 406 * We could in theory support this, but making it work right can be 407 * tricky, and we doubt it is widely used. 408 */ 409 solo_setmixer(dev, 0x64, solo_getmixer(dev, 0x64) | 0xc); 410 solo_setmixer(dev, 0x66, 0); 411 412 /* master volume has 6 bits per channel, bit 6 indicates mute */ 413 /* left */ 414 v = (dev->ctrls[CTL_FRONT].val >> 8) & 0xff; 415 v = v ? (v * 63) / 100 : 64; 416 solo_setmixer(dev, 0x60, v & 0xff); 417 418 /* right */ 419 v = dev->ctrls[CTL_FRONT].val & 0xff; 420 v = v ? (v * 63) / 100 : 64; 421 solo_setmixer(dev, 0x62, v & 0xff); 422 423 v = solo_mixer_scale(dev, CTL_VOLUME); 424 v = v | (v << 4); 425 solo_setmixer(dev, 0x7c, v & 0xff); 426 solo_setmixer(dev, 0x14, v & 0xff); 427 428 mon = dev->ctrls[CTL_MONSRC].val; 429 rec = dev->ctrls[CTL_RECSRC].val; 430 431 /* 432 * The Solo-1 has dual stereo mixers (one for input and one for output), 433 * with separate volume controls for each. 434 */ 435 v = solo_mixer_scale(dev, CTL_MIC); 436 solo_setmixer(dev, 0x68, rec & (1 << INPUT_MIC) ? v : 0); 437 solo_setmixer(dev, 0x1a, mon & (1 << INPUT_MIC) ? v : 0); 438 439 v = solo_mixer_scale(dev, CTL_LINE); 440 solo_setmixer(dev, 0x6e, rec & (1 << INPUT_LINE) ? v : 0); 441 solo_setmixer(dev, 0x3e, mon & (1 << INPUT_LINE) ? v : 0); 442 443 v = solo_mixer_scale(dev, CTL_CD); 444 solo_setmixer(dev, 0x6a, rec & (1 << INPUT_CD) ? v : 0); 445 solo_setmixer(dev, 0x38, mon & (1 << INPUT_CD) ? v : 0); 446 447 v = solo_mixer_scale(dev, CTL_AUX); 448 solo_setmixer(dev, 0x6c, rec & (1 << INPUT_AUX) ? v : 0); 449 solo_setmixer(dev, 0x3a, mon & (1 << INPUT_AUX) ? v : 0); 450 451 v = solo_mixer_scale(dev, CTL_MONO); 452 v = v | (v << 4); 453 solo_setmixer(dev, 0x6f, rec & (1 << INPUT_MONO) ? v : 0); 454 solo_setmixer(dev, 0x6d, mon & (1 << INPUT_MONO) ? v : 0); 455 456 if (dev->ctrls[CTL_MICBOOST].val) { 457 solo_setmixer(dev, 0x7d, solo_getmixer(dev, 0x7d) | 0x8); 458 } else { 459 solo_setmixer(dev, 0x7d, solo_getmixer(dev, 0x7d) & ~(0x8)); 460 } 461 462 v = solo_mixer_scale(dev, CTL_RECGAIN); 463 v = v | (v << 4); 464 solo_write(dev, 0xb4, v & 0xff); 465 466 v = dev->ctrls[CTL_SPEAKER].val & 0xff; 467 v = (v * 7) / 100; 468 solo_setmixer(dev, 0x3c, v & 0xff); 469 470 if (dev->ctrls[CTL_LOOPBACK].val) { 471 /* record-what-you-hear mode */ 472 solo_setmixer(dev, 0x1c, 0x3); 473 } else { 474 /* use record mixer */ 475 solo_setmixer(dev, 0x1c, 0x5); 476 } 477 478 } 479 480 static int 481 solo_set_mixsrc(void *arg, uint64_t val) 482 { 483 solo_ctrl_t *pc = arg; 484 solo_dev_t *dev = pc->dev; 485 486 if ((val & ~INSRCS) != 0) 487 return (EINVAL); 488 489 mutex_enter(&dev->mutex); 490 pc->val = val; 491 if (!dev->suspended) 492 solo_configure_mixer(dev); 493 mutex_exit(&dev->mutex); 494 return (0); 495 } 496 497 static int 498 solo_set_mono(void *arg, uint64_t val) 499 { 500 solo_ctrl_t *pc = arg; 501 solo_dev_t *dev = pc->dev; 502 503 val &= 0xff; 504 if (val > 100) 505 return (EINVAL); 506 507 val = (val & 0xff) | ((val & 0xff) << 8); 508 509 mutex_enter(&dev->mutex); 510 pc->val = val; 511 if (!dev->suspended) 512 solo_configure_mixer(dev); 513 mutex_exit(&dev->mutex); 514 return (0); 515 } 516 517 static int 518 solo_set_stereo(void *arg, uint64_t val) 519 { 520 solo_ctrl_t *pc = arg; 521 solo_dev_t *dev = pc->dev; 522 uint8_t l; 523 uint8_t r; 524 525 l = (val & 0xff00) >> 8; 526 r = val & 0xff; 527 528 if ((l > 100) || (r > 100)) 529 return (EINVAL); 530 531 mutex_enter(&dev->mutex); 532 pc->val = val; 533 if (!dev->suspended) 534 solo_configure_mixer(dev); 535 mutex_exit(&dev->mutex); 536 return (0); 537 } 538 539 static int 540 solo_set_bool(void *arg, uint64_t val) 541 { 542 solo_ctrl_t *pc = arg; 543 solo_dev_t *dev = pc->dev; 544 545 mutex_enter(&dev->mutex); 546 pc->val = val; 547 if (!dev->suspended) 548 solo_configure_mixer(dev); 549 mutex_exit(&dev->mutex); 550 return (0); 551 } 552 553 static int 554 solo_get_value(void *arg, uint64_t *val) 555 { 556 solo_ctrl_t *pc = arg; 557 solo_dev_t *dev = pc->dev; 558 559 mutex_enter(&dev->mutex); 560 *val = pc->val; 561 mutex_exit(&dev->mutex); 562 return (0); 563 } 564 565 #define PLAYCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_PLAY) 566 #define RECCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC) 567 #define MONCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_MONITOR) 568 #define PCMVOL (PLAYCTL | AUDIO_CTRL_FLAG_PCMVOL) 569 #define MAINVOL (PLAYCTL | AUDIO_CTRL_FLAG_MAINVOL) 570 #define RECVOL (RECCTL | AUDIO_CTRL_FLAG_RECVOL) 571 572 static void 573 solo_alloc_ctrl(solo_dev_t *dev, uint32_t num, uint64_t val) 574 { 575 audio_ctrl_desc_t desc; 576 audio_ctrl_wr_t fn; 577 solo_ctrl_t *pc; 578 579 bzero(&desc, sizeof (desc)); 580 581 pc = &dev->ctrls[num]; 582 pc->num = num; 583 pc->dev = dev; 584 585 switch (num) { 586 case CTL_VOLUME: 587 desc.acd_name = AUDIO_CTRL_ID_VOLUME; 588 desc.acd_type = AUDIO_CTRL_TYPE_MONO; 589 desc.acd_minvalue = 0; 590 desc.acd_maxvalue = 100; 591 desc.acd_flags = PCMVOL; 592 fn = solo_set_mono; 593 break; 594 595 case CTL_FRONT: 596 desc.acd_name = AUDIO_CTRL_ID_LINEOUT; 597 desc.acd_type = AUDIO_CTRL_TYPE_STEREO; 598 desc.acd_minvalue = 0; 599 desc.acd_maxvalue = 100; 600 desc.acd_flags = MAINVOL; 601 fn = solo_set_stereo; 602 break; 603 604 case CTL_SPEAKER: 605 desc.acd_name = AUDIO_CTRL_ID_SPEAKER; 606 desc.acd_type = AUDIO_CTRL_TYPE_MONO; 607 desc.acd_minvalue = 0; 608 desc.acd_maxvalue = 100; 609 desc.acd_flags = MAINVOL; 610 fn = solo_set_mono; 611 break; 612 613 case CTL_MIC: 614 desc.acd_name = AUDIO_CTRL_ID_MIC; 615 desc.acd_type = AUDIO_CTRL_TYPE_STEREO; 616 desc.acd_minvalue = 0; 617 desc.acd_maxvalue = 100; 618 desc.acd_flags = RECVOL; 619 fn = solo_set_stereo; 620 break; 621 622 case CTL_LINE: 623 desc.acd_name = AUDIO_CTRL_ID_LINEIN; 624 desc.acd_type = AUDIO_CTRL_TYPE_STEREO; 625 desc.acd_minvalue = 0; 626 desc.acd_maxvalue = 100; 627 desc.acd_flags = RECVOL; 628 fn = solo_set_stereo; 629 break; 630 631 case CTL_CD: 632 desc.acd_name = AUDIO_CTRL_ID_CD; 633 desc.acd_type = AUDIO_CTRL_TYPE_STEREO; 634 desc.acd_minvalue = 0; 635 desc.acd_maxvalue = 100; 636 desc.acd_flags = RECVOL; 637 fn = solo_set_stereo; 638 break; 639 640 case CTL_AUX: 641 desc.acd_name = AUDIO_CTRL_ID_AUX1IN; 642 desc.acd_type = AUDIO_CTRL_TYPE_STEREO; 643 desc.acd_minvalue = 0; 644 desc.acd_maxvalue = 100; 645 desc.acd_flags = RECVOL; 646 fn = solo_set_stereo; 647 break; 648 649 case CTL_MONO: 650 desc.acd_name = AUDIO_CTRL_ID_AUX2IN; 651 desc.acd_type = AUDIO_CTRL_TYPE_MONO; 652 desc.acd_minvalue = 0; 653 desc.acd_maxvalue = 100; 654 desc.acd_flags = RECVOL; 655 fn = solo_set_mono; 656 break; 657 658 case CTL_RECSRC: 659 desc.acd_name = AUDIO_CTRL_ID_RECSRC; 660 desc.acd_type = AUDIO_CTRL_TYPE_ENUM; 661 desc.acd_minvalue = INSRCS; 662 desc.acd_maxvalue = INSRCS; 663 desc.acd_flags = RECCTL | AUDIO_CTRL_FLAG_MULTI; 664 for (int i = 0; solo_insrcs[i]; i++) { 665 desc.acd_enum[i] = solo_insrcs[i]; 666 } 667 fn = solo_set_mixsrc; 668 break; 669 670 case CTL_MONSRC: 671 desc.acd_name = AUDIO_CTRL_ID_MONSRC; 672 desc.acd_type = AUDIO_CTRL_TYPE_ENUM; 673 desc.acd_minvalue = INSRCS; 674 desc.acd_maxvalue = INSRCS; 675 desc.acd_flags = MONCTL | AUDIO_CTRL_FLAG_MULTI; 676 for (int i = 0; solo_insrcs[i]; i++) { 677 desc.acd_enum[i] = solo_insrcs[i]; 678 } 679 fn = solo_set_mixsrc; 680 break; 681 682 case CTL_MICBOOST: 683 desc.acd_name = AUDIO_CTRL_ID_MICBOOST; 684 desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN; 685 desc.acd_minvalue = 0; 686 desc.acd_maxvalue = 1; 687 desc.acd_flags = RECCTL; 688 fn = solo_set_bool; 689 break; 690 691 case CTL_LOOPBACK: 692 desc.acd_name = AUDIO_CTRL_ID_LOOPBACK; 693 desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN; 694 desc.acd_minvalue = 0; 695 desc.acd_maxvalue = 1; 696 desc.acd_flags = RECCTL; 697 fn = solo_set_bool; 698 break; 699 700 case CTL_RECGAIN: 701 desc.acd_name = AUDIO_CTRL_ID_RECGAIN; 702 desc.acd_type = AUDIO_CTRL_TYPE_STEREO; 703 desc.acd_minvalue = 0; 704 desc.acd_maxvalue = 100; 705 desc.acd_flags = RECCTL; 706 fn = solo_set_stereo; 707 break; 708 } 709 710 pc->val = val; 711 pc->ctrl = audio_dev_add_control(dev->adev, &desc, 712 solo_get_value, fn, pc); 713 } 714 715 static bool 716 solo_add_controls(solo_dev_t *dev) 717 { 718 solo_alloc_ctrl(dev, CTL_VOLUME, 0x4b); 719 solo_alloc_ctrl(dev, CTL_FRONT, 0x5a5a); 720 solo_alloc_ctrl(dev, CTL_SPEAKER, 0x4b); 721 solo_alloc_ctrl(dev, CTL_MIC, 0x3232); 722 solo_alloc_ctrl(dev, CTL_LINE, 0x4b4b); 723 solo_alloc_ctrl(dev, CTL_CD, 0x4b4b); 724 solo_alloc_ctrl(dev, CTL_AUX, 0); 725 solo_alloc_ctrl(dev, CTL_MONO, 0); 726 solo_alloc_ctrl(dev, CTL_RECSRC, (1U << INPUT_MIC)); 727 solo_alloc_ctrl(dev, CTL_MONSRC, 0); 728 solo_alloc_ctrl(dev, CTL_RECGAIN, 0x4b4b); 729 solo_alloc_ctrl(dev, CTL_MICBOOST, 1); 730 solo_alloc_ctrl(dev, CTL_LOOPBACK, 0); 731 732 return (true); 733 } 734 735 736 /* utility functions for ESS */ 737 static uint8_t 738 solo_calcfilter(int spd) 739 { 740 int cutoff; 741 742 cutoff = (spd * 9 * 82) / 20; 743 return (256 - (7160000 / cutoff)); 744 } 745 746 static void 747 solo_aud1_update(solo_engine_t *e) 748 { 749 solo_dev_t *dev = e->dev; 750 uint16_t offset, n; 751 uint32_t ptr; 752 uint32_t count; 753 uint32_t diff; 754 755 ASSERT(mutex_owned(&dev->mutex)); 756 757 /* 758 * During recording, this register is known to give back 759 * garbage if it's not quiescent while being read. This hack 760 * attempts to work around it. 761 */ 762 ptr = PORT_RD32(dev->vc, 0); 763 count = PORT_RD16(dev->vc, 4); 764 diff = e->paddr + SOLO_BUFSZ - ptr - count; 765 if ((diff > 3) || (ptr < e->paddr) || 766 (ptr >= (e->paddr + SOLO_BUFSZ))) { 767 ptr = dev->last_capture; 768 } else { 769 dev->last_capture = ptr; 770 } 771 offset = ptr - e->paddr; 772 offset /= (SOLO_NCHAN * SOLO_SAMPSZ); 773 774 n = offset >= e->offset ? 775 offset - e->offset : 776 offset + SOLO_BUFSZ - e->offset; 777 778 e->offset = offset; 779 e->count += n / (SOLO_NCHAN * SOLO_SAMPSZ); 780 } 781 782 static void 783 solo_aud1_start(solo_engine_t *e) 784 { 785 solo_dev_t *dev = e->dev; 786 int len; 787 uint32_t v; 788 789 ASSERT(mutex_owned(&dev->mutex)); 790 791 len = SOLO_FRAGSZ / 2; 792 len = -len; 793 794 /* sample rate - 48 kHz */ 795 solo_write(dev, 0xa1, 0xf0); 796 /* filter cutoff */ 797 solo_write(dev, 0xa2, solo_calcfilter(SOLO_RATE)); 798 799 800 /* mono/stereo - bit 0 set, bit 1 clear */ 801 solo_write(dev, 0xa8, (solo_read(dev, 0xa8) & ~0x03) | 1); 802 803 (void) solo_cmd(dev, 0xd3); /* turn off DAC1 output */ 804 805 /* setup fifo for signed 16-bit stereo */ 806 solo_write(dev, 0xb7, 0x71); 807 solo_write(dev, 0xb7, 0xbc); 808 809 v = solo_mixer_scale(dev, CTL_RECGAIN); 810 v = v | (v << 4); 811 solo_write(dev, 0xb4, v & 0xff); 812 813 PORT_WR8(dev->vc, 0x8, 0xc4); /* command */ 814 PORT_WR8(dev->vc, 0xd, 0xff); /* clear DMA */ 815 PORT_WR8(dev->vc, 0xf, 0x01); /* stop DMA */ 816 817 PORT_WR8(dev->vc, 0xd, 0xff); /* reset */ 818 PORT_WR8(dev->vc, 0xf, 0x01); /* mask */ 819 PORT_WR8(dev->vc, 0xb, 0x14); /* mode */ 820 821 PORT_WR32(dev->vc, 0x0, e->paddr); 822 PORT_WR16(dev->vc, 0x4, SOLO_BUFSZ - 1); 823 824 /* transfer length low, high */ 825 solo_write(dev, 0xa4, len & 0x00ff); 826 solo_write(dev, 0xa5, (len & 0xff00) >> 8); 827 828 /* autoinit, dma dir, go for it */ 829 solo_write(dev, 0xb8, 0x0f); 830 PORT_WR8(dev->vc, 0xf, 0); /* start DMA */ 831 832 dev->last_capture = e->paddr; 833 } 834 835 static void 836 solo_aud1_stop(solo_engine_t *e) 837 { 838 solo_dev_t *dev = e->dev; 839 840 /* NB: We might be in quiesce, without a lock held */ 841 solo_write(dev, 0xb8, solo_read(dev, 0xb8) & ~0x01); 842 } 843 844 static void 845 solo_aud2_update(solo_engine_t *e) 846 { 847 solo_dev_t *dev = e->dev; 848 uint16_t offset = 0, n; 849 850 ASSERT(mutex_owned(&dev->mutex)); 851 852 offset = SOLO_BUFSZ - PORT_RD16(dev->io, 0x4); 853 offset /= (SOLO_NCHAN * SOLO_SAMPSZ); 854 855 n = offset >= e->offset ? 856 offset - e->offset : 857 offset + SOLO_BUFFR - e->offset; 858 859 e->offset = offset; 860 e->count += n; 861 } 862 863 static void 864 solo_aud2_start(solo_engine_t *e) 865 { 866 solo_dev_t *dev = e->dev; 867 int len; 868 uint32_t v; 869 870 ASSERT(mutex_owned(&dev->mutex)); 871 872 len = SOLO_FRAGSZ / 2; 873 len = -len; 874 875 /* program transfer type */ 876 solo_setmixer(dev, 0x78, 0x10); 877 /* sample rate - 48 kHz */ 878 solo_setmixer(dev, 0x70, 0xf0); 879 solo_setmixer(dev, 0x72, solo_calcfilter(SOLO_RATE)); 880 /* transfer length low & high */ 881 solo_setmixer(dev, 0x74, len & 0x00ff); 882 solo_setmixer(dev, 0x76, (len & 0xff00) >> 8); 883 /* enable irq, set signed 16-bit stereo format */ 884 solo_setmixer(dev, 0x7a, 0x47); 885 886 PORT_WR8(dev->io, 0x6, 0); 887 PORT_WR32(dev->io, 0x0, e->paddr); 888 PORT_WR16(dev->io, 0x4, SOLO_BUFSZ); 889 890 /* this crazy initialization appears to help with fifo weirdness */ 891 /* start the engine running */ 892 solo_setmixer(dev, 0x78, 0x92); 893 drv_usecwait(10); 894 solo_setmixer(dev, 0x78, 0x93); 895 896 PORT_WR8(dev->io, 0x6, 0x0a); /* autoinit, enable */ 897 898 v = solo_mixer_scale(dev, CTL_VOLUME); 899 v = v | (v << 4); 900 solo_setmixer(dev, 0x7c, v & 0xff); 901 } 902 903 static void 904 solo_aud2_stop(solo_engine_t *e) 905 { 906 solo_dev_t *dev = e->dev; 907 908 /* NB: We might be in quiesce, without a lock held */ 909 PORT_WR8(dev->io, 0x6, 0); 910 solo_setmixer(dev, 0x78, solo_getmixer(dev, 0x78) & ~0x03); 911 } 912 913 /* 914 * Audio entry points. 915 */ 916 static int 917 solo_format(void *arg) 918 { 919 solo_engine_t *e = arg; 920 return (e->format); 921 } 922 923 static int 924 solo_channels(void *arg) 925 { 926 _NOTE(ARGUNUSED(arg)); 927 return (SOLO_NCHAN); 928 } 929 930 static int 931 solo_rate(void *arg) 932 { 933 _NOTE(ARGUNUSED(arg)); 934 return (SOLO_RATE); 935 } 936 937 static size_t 938 solo_qlen(void *arg) 939 { 940 _NOTE(ARGUNUSED(arg)); 941 return (0); 942 } 943 944 static void 945 solo_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr) 946 { 947 solo_engine_t *e = arg; 948 949 if (e->swapped) { 950 *offset = !chan; 951 } else { 952 *offset = chan; 953 } 954 *incr = 2; 955 } 956 957 static void 958 solo_sync(void *arg, unsigned nframes) 959 { 960 solo_engine_t *e = arg; 961 962 _NOTE(ARGUNUSED(nframes)); 963 964 (void) ddi_dma_sync(e->dmah, 0, 0, e->syncdir); 965 } 966 967 968 static uint64_t 969 solo_count(void *arg) 970 { 971 solo_engine_t *e = arg; 972 solo_dev_t *dev = e->dev; 973 uint64_t count; 974 975 mutex_enter(&dev->mutex); 976 if (!dev->suspended) 977 e->update(e); 978 count = e->count; 979 mutex_exit(&dev->mutex); 980 981 return (count); 982 } 983 984 static int 985 solo_open(void *arg, int f, unsigned *ffr, unsigned *nfr, caddr_t *buf) 986 { 987 solo_engine_t *e = arg; 988 solo_dev_t *dev = e->dev; 989 990 _NOTE(ARGUNUSED(f)); 991 992 /* NB: For simplicity, we just fix the interrupt rate at 100 Hz */ 993 *ffr = SOLO_FRAGFR; 994 *nfr = SOLO_NFRAGS; 995 *buf = e->kaddr; 996 997 mutex_enter(&dev->mutex); 998 e->started = false; 999 e->count = 0; 1000 mutex_exit(&dev->mutex); 1001 1002 return (0); 1003 } 1004 1005 void 1006 solo_close(void *arg) 1007 { 1008 solo_engine_t *e = arg; 1009 solo_dev_t *dev = e->dev; 1010 1011 mutex_enter(&dev->mutex); 1012 if (!dev->suspended) 1013 e->stop(e); 1014 e->started = false; 1015 mutex_exit(&dev->mutex); 1016 } 1017 1018 1019 static int 1020 solo_start(void *arg) 1021 { 1022 solo_engine_t *e = arg; 1023 solo_dev_t *dev = e->dev; 1024 1025 mutex_enter(&dev->mutex); 1026 if (!e->started) { 1027 if (!dev->suspended) 1028 e->start(e); 1029 e->started = true; 1030 } 1031 mutex_exit(&dev->mutex); 1032 1033 return (0); 1034 } 1035 1036 static void 1037 solo_stop(void *arg) 1038 { 1039 solo_engine_t *e = arg; 1040 solo_dev_t *dev = e->dev; 1041 1042 mutex_enter(&dev->mutex); 1043 if (e->started) { 1044 if (!dev->suspended) 1045 e->stop(e); 1046 e->started = false; 1047 } 1048 mutex_exit(&dev->mutex); 1049 1050 } 1051 1052 static audio_engine_ops_t solo_engine_ops = { 1053 AUDIO_ENGINE_VERSION, 1054 solo_open, 1055 solo_close, 1056 solo_start, 1057 solo_stop, 1058 solo_count, 1059 solo_format, 1060 solo_channels, 1061 solo_rate, 1062 solo_sync, 1063 solo_qlen, 1064 solo_chinfo, 1065 }; 1066 1067 static void 1068 solo_release_resources(solo_dev_t *dev) 1069 { 1070 if (dev->ihandle != NULL) { 1071 (void) ddi_intr_disable(dev->ihandle); 1072 (void) ddi_intr_remove_handler(dev->ihandle); 1073 (void) ddi_intr_free(dev->ihandle); 1074 mutex_destroy(&dev->mutex); 1075 } 1076 1077 if (dev->io.acch != NULL) { 1078 ddi_regs_map_free(&dev->io.acch); 1079 } 1080 1081 if (dev->sb.acch != NULL) { 1082 ddi_regs_map_free(&dev->sb.acch); 1083 } 1084 1085 if (dev->vc.acch != NULL) { 1086 ddi_regs_map_free(&dev->vc.acch); 1087 } 1088 1089 if (dev->pcih != NULL) { 1090 pci_config_teardown(&dev->pcih); 1091 } 1092 1093 /* release play resources */ 1094 if (dev->play.paddr != 0) 1095 (void) ddi_dma_unbind_handle(dev->play.dmah); 1096 if (dev->play.acch != NULL) 1097 ddi_dma_mem_free(&dev->play.acch); 1098 if (dev->play.dmah != NULL) 1099 ddi_dma_free_handle(&dev->play.dmah); 1100 1101 if (dev->play.engine != NULL) { 1102 audio_dev_remove_engine(dev->adev, dev->play.engine); 1103 audio_engine_free(dev->play.engine); 1104 } 1105 1106 /* release record resources */ 1107 if (dev->rec.paddr != 0) 1108 (void) ddi_dma_unbind_handle(dev->rec.dmah); 1109 if (dev->rec.acch != NULL) 1110 ddi_dma_mem_free(&dev->rec.acch); 1111 if (dev->rec.dmah != NULL) 1112 ddi_dma_free_handle(&dev->rec.dmah); 1113 1114 if (dev->rec.engine != NULL) { 1115 audio_dev_remove_engine(dev->adev, dev->rec.engine); 1116 audio_engine_free(dev->rec.engine); 1117 } 1118 1119 if (dev->adev != NULL) { 1120 audio_dev_free(dev->adev); 1121 } 1122 1123 kmem_free(dev, sizeof (*dev)); 1124 } 1125 1126 static bool 1127 solo_setup_interrupts(solo_dev_t *dev) 1128 { 1129 int actual; 1130 uint_t ipri; 1131 1132 if ((ddi_intr_alloc(dev->dip, &dev->ihandle, DDI_INTR_TYPE_FIXED, 1133 0, 1, &actual, DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) || 1134 (actual != 1)) { 1135 audio_dev_warn(dev->adev, "can't alloc intr handle"); 1136 return (false); 1137 } 1138 1139 if (ddi_intr_get_pri(dev->ihandle, &ipri) != DDI_SUCCESS) { 1140 audio_dev_warn(dev->adev, "can't determine intr priority"); 1141 (void) ddi_intr_free(dev->ihandle); 1142 dev->ihandle = NULL; 1143 return (false); 1144 } 1145 1146 if (ddi_intr_add_handler(dev->ihandle, solo_intr, dev, 1147 NULL) != DDI_SUCCESS) { 1148 audio_dev_warn(dev->adev, "can't add intr handler"); 1149 (void) ddi_intr_free(dev->ihandle); 1150 dev->ihandle = NULL; 1151 return (false); 1152 } 1153 1154 mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri)); 1155 1156 return (true); 1157 } 1158 1159 static bool 1160 solo_map_registers(solo_dev_t *dev) 1161 { 1162 dev_info_t *dip = dev->dip; 1163 1164 /* map registers */ 1165 if (ddi_regs_map_setup(dip, 1, &dev->io.base, 0, 0, &acc_attr, 1166 &dev->io.acch) != DDI_SUCCESS) { 1167 audio_dev_warn(dev->adev, "can't map IO registers"); 1168 return (false); 1169 } 1170 if (ddi_regs_map_setup(dip, 2, &dev->sb.base, 0, 0, &acc_attr, 1171 &dev->sb.acch) != DDI_SUCCESS) { 1172 audio_dev_warn(dev->adev, "can't map SB registers"); 1173 return (false); 1174 } 1175 if (ddi_regs_map_setup(dip, 3, &dev->vc.base, 0, 0, &acc_attr, 1176 &dev->vc.acch) != DDI_SUCCESS) { 1177 audio_dev_warn(dev->adev, "can't map VC registers"); 1178 return (false); 1179 } 1180 1181 return (true); 1182 } 1183 1184 #define ESS_PCI_LEGACYCONTROL 0x40 1185 #define ESS_PCI_CONFIG 0x50 1186 #define ESS_PCI_DDMACONTROL 0x60 1187 1188 static bool 1189 solo_init_hw(solo_dev_t *dev) 1190 { 1191 uint32_t data; 1192 1193 /* 1194 * Legacy audio register -- disable legacy audio. We also 1195 * arrange for 16-bit I/O address decoding. 1196 */ 1197 /* this version disables the MPU, FM synthesis (Adlib), and Game Port */ 1198 pci_config_put16(dev->pcih, ESS_PCI_LEGACYCONTROL, 0x8041); 1199 1200 /* 1201 * Note that Solo-1 uses I/O space for all BARs, and hardwires 1202 * the upper 32-bits to zero. 1203 */ 1204 data = pci_config_get32(dev->pcih, PCI_CONF_BASE2); 1205 data |= 1; 1206 pci_config_put16(dev->pcih, ESS_PCI_DDMACONTROL, data & 0xffff); 1207 1208 /* 1209 * Make sure that legacy IRQ and DRQ are disbled. We disable most 1210 * other legacy features too. 1211 */ 1212 pci_config_put16(dev->pcih, ESS_PCI_CONFIG, 0); 1213 1214 if (!solo_reset_dsp(dev)) 1215 return (false); 1216 1217 /* enable extended mode */ 1218 (void) solo_cmd(dev, 0xc6); 1219 1220 1221 PORT_WR8(dev->io, 0x7, 0x30); /* enable audio irqs */ 1222 1223 /* demand mode, 4 bytes/xfer */ 1224 solo_write(dev, 0xb9, 0x01); 1225 1226 /* 1227 * This sets Audio 2 (playback) to use its own independent 1228 * rate control, and gives us 48 kHz compatible divisors. It 1229 * also bypasses the switched capacitor filter. 1230 */ 1231 solo_setmixer(dev, 0x71, 0x2a); 1232 1233 /* irq control */ 1234 solo_write(dev, 0xb1, (solo_read(dev, 0xb1) & 0x0f) | 0x50); 1235 /* drq control */ 1236 solo_write(dev, 0xb2, (solo_read(dev, 0xb2) & 0x0f) | 0x50); 1237 1238 solo_setmixer(dev, 0, 0); /* reset mixer settings */ 1239 1240 solo_configure_mixer(dev); 1241 return (true); 1242 } 1243 1244 static bool 1245 solo_alloc_engine(solo_dev_t *dev, int engno) 1246 { 1247 size_t rlen; 1248 ddi_dma_attr_t *dattr; 1249 ddi_dma_cookie_t c; 1250 unsigned ccnt; 1251 unsigned caps; 1252 unsigned dflags; 1253 const char *desc; 1254 solo_engine_t *e; 1255 1256 ASSERT((engno == 1) || (engno = 2)); 1257 1258 switch (engno) { 1259 case 1: /* record */ 1260 e = &dev->rec; 1261 desc = "record"; 1262 dattr = &dma_attr_audio1; 1263 caps = ENGINE_INPUT_CAP; 1264 dflags = DDI_DMA_READ | DDI_DMA_CONSISTENT; 1265 e->syncdir = DDI_DMA_SYNC_FORKERNEL; 1266 e->update = solo_aud1_update; 1267 e->start = solo_aud1_start; 1268 e->stop = solo_aud1_stop; 1269 e->format = AUDIO_FORMAT_S16_BE; 1270 e->swapped = true; 1271 break; 1272 1273 case 2: /* playback */ 1274 e = &dev->play; 1275 desc = "playback"; 1276 dattr = &dma_attr_audio2; 1277 caps = ENGINE_OUTPUT_CAP; 1278 dflags = DDI_DMA_WRITE | DDI_DMA_CONSISTENT; 1279 e->syncdir = DDI_DMA_SYNC_FORDEV; 1280 e->update = solo_aud2_update; 1281 e->start = solo_aud2_start; 1282 e->stop = solo_aud2_stop; 1283 e->format = AUDIO_FORMAT_S16_LE; 1284 e->swapped = false; 1285 break; 1286 1287 default: 1288 audio_dev_warn(dev->adev, "bad engine number!"); 1289 return (false); 1290 } 1291 1292 printf("%s %sswapped!", desc, e->swapped ? "" : "not "); 1293 e->dev = dev; 1294 1295 if (ddi_dma_alloc_handle(dev->dip, dattr, DDI_DMA_SLEEP, NULL, 1296 &e->dmah) != DDI_SUCCESS) { 1297 audio_dev_warn(dev->adev, "%s dma handle alloc failed", desc); 1298 return (false); 1299 } 1300 if (ddi_dma_mem_alloc(e->dmah, SOLO_BUFSZ, &buf_attr, 1301 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &e->kaddr, 1302 &rlen, &e->acch) != DDI_SUCCESS) { 1303 audio_dev_warn(dev->adev, "%s dma memory alloc failed", desc); 1304 return (false); 1305 } 1306 /* ensure that the buffer is zeroed out properly */ 1307 bzero(e->kaddr, rlen); 1308 if (ddi_dma_addr_bind_handle(e->dmah, NULL, e->kaddr, SOLO_BUFSZ, 1309 dflags, DDI_DMA_SLEEP, NULL, &c, &ccnt) != DDI_DMA_MAPPED) { 1310 audio_dev_warn(dev->adev, "%s dma binding failed", desc); 1311 return (false); 1312 } 1313 e->paddr = c.dmac_address; 1314 1315 /* 1316 * Allocate and configure audio engine. 1317 */ 1318 e->engine = audio_engine_alloc(&solo_engine_ops, caps); 1319 if (e->engine == NULL) { 1320 audio_dev_warn(dev->adev, "record audio_engine_alloc failed"); 1321 return (false); 1322 } 1323 1324 audio_engine_set_private(e->engine, e); 1325 audio_dev_add_engine(dev->adev, e->engine); 1326 1327 return (true); 1328 } 1329 1330 1331 static int 1332 solo_suspend(solo_dev_t *dev) 1333 { 1334 mutex_enter(&dev->mutex); 1335 /* play */ 1336 solo_aud2_stop(&dev->play); 1337 solo_aud2_update(&dev->play); 1338 /* record */ 1339 solo_aud1_stop(&dev->rec); 1340 solo_aud1_update(&dev->rec); 1341 1342 dev->suspended = true; 1343 mutex_exit(&dev->mutex); 1344 1345 return (DDI_SUCCESS); 1346 } 1347 1348 static int 1349 solo_resume(solo_dev_t *dev) 1350 { 1351 solo_engine_t *e; 1352 audio_engine_t *prod = NULL; 1353 audio_engine_t *cons = NULL; 1354 1355 audio_engine_reset(dev->rec.engine); 1356 audio_engine_reset(dev->play.engine); 1357 1358 mutex_enter(&dev->mutex); 1359 if (!solo_init_hw(dev)) { 1360 /* yikes! */ 1361 audio_dev_warn(dev->adev, "unable to resume audio!"); 1362 audio_dev_warn(dev->adev, "reboot or reload driver to reset"); 1363 mutex_exit(&dev->mutex); 1364 return (DDI_SUCCESS); 1365 } 1366 dev->suspended = false; 1367 1368 /* record - audio 1 */ 1369 e = &dev->rec; 1370 if (e->started) { 1371 e->start(e); 1372 prod = e->engine; 1373 } 1374 1375 /* play - audio 2 */ 1376 e = &dev->play; 1377 if (e->started) { 1378 e->start(e); 1379 cons = e->engine; 1380 } 1381 1382 mutex_exit(&dev->mutex); 1383 1384 if (cons) 1385 audio_engine_consume(cons); 1386 if (prod) 1387 audio_engine_produce(prod); 1388 1389 return (DDI_SUCCESS); 1390 } 1391 1392 static int 1393 solo_attach(dev_info_t *dip) 1394 { 1395 solo_dev_t *dev; 1396 uint32_t data; 1397 1398 dev = kmem_zalloc(sizeof (*dev), KM_SLEEP); 1399 dev->dip = dip; 1400 ddi_set_driver_private(dip, dev); 1401 1402 dev->adev = audio_dev_alloc(dip, 0); 1403 if (dev->adev == NULL) 1404 goto no; 1405 1406 audio_dev_set_description(dev->adev, "ESS Solo-1 PCI AudioDrive"); 1407 audio_dev_set_version(dev->adev, "ES1938"); 1408 1409 if (pci_config_setup(dip, &dev->pcih) != DDI_SUCCESS) { 1410 audio_dev_warn(NULL, "pci_config_setup failed"); 1411 goto no; 1412 } 1413 1414 data = pci_config_get16(dev->pcih, PCI_CONF_COMM); 1415 data |= PCI_COMM_ME | PCI_COMM_IO; 1416 pci_config_put16(dev->pcih, PCI_CONF_COMM, data); 1417 1418 if ((!solo_map_registers(dev)) || 1419 (!solo_setup_interrupts(dev)) || 1420 (!solo_alloc_engine(dev, 1)) || 1421 (!solo_alloc_engine(dev, 2)) || 1422 (!solo_add_controls(dev)) || 1423 (!solo_init_hw(dev))) { 1424 goto no; 1425 } 1426 1427 if (audio_dev_register(dev->adev) != DDI_SUCCESS) { 1428 audio_dev_warn(dev->adev, 1429 "unable to register with audio framework"); 1430 goto no; 1431 } 1432 1433 (void) ddi_intr_enable(dev->ihandle); 1434 ddi_report_dev(dip); 1435 1436 return (DDI_SUCCESS); 1437 1438 no: 1439 solo_release_resources(dev); 1440 return (DDI_FAILURE); 1441 } 1442 1443 static int 1444 solo_detach(solo_dev_t *dev) 1445 { 1446 if (audio_dev_unregister(dev->adev) != DDI_SUCCESS) { 1447 return (DDI_FAILURE); 1448 } 1449 1450 solo_release_resources(dev); 1451 return (DDI_SUCCESS); 1452 } 1453 1454 static int 1455 solo_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1456 { 1457 solo_dev_t *dev; 1458 1459 switch (cmd) { 1460 case DDI_ATTACH: 1461 return (solo_attach(dip)); 1462 1463 case DDI_RESUME: 1464 if ((dev = ddi_get_driver_private(dip)) == NULL) { 1465 return (DDI_FAILURE); 1466 } 1467 return (solo_resume(dev)); 1468 1469 default: 1470 return (DDI_FAILURE); 1471 } 1472 } 1473 1474 static int 1475 solo_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 1476 { 1477 solo_dev_t *dev; 1478 1479 if ((dev = ddi_get_driver_private(dip)) == NULL) { 1480 return (DDI_FAILURE); 1481 } 1482 1483 switch (cmd) { 1484 case DDI_DETACH: 1485 return (solo_detach(dev)); 1486 1487 case DDI_SUSPEND: 1488 return (solo_suspend(dev)); 1489 default: 1490 return (DDI_FAILURE); 1491 } 1492 } 1493 1494 static int 1495 solo_quiesce(dev_info_t *dip) 1496 { 1497 solo_dev_t *dev; 1498 1499 dev = ddi_get_driver_private(dip); 1500 1501 solo_aud1_stop(&dev->rec); 1502 solo_aud2_stop(&dev->play); 1503 1504 solo_setmixer(dev, 0, 0); 1505 PORT_WR8(dev->io, 0x7, 0); /* disable all irqs */ 1506 return (0); 1507 } 1508 1509 struct dev_ops solo_dev_ops = { 1510 DEVO_REV, /* rev */ 1511 0, /* refcnt */ 1512 NULL, /* getinfo */ 1513 nulldev, /* identify */ 1514 nulldev, /* probe */ 1515 solo_ddi_attach, /* attach */ 1516 solo_ddi_detach, /* detach */ 1517 nodev, /* reset */ 1518 NULL, /* cb_ops */ 1519 NULL, /* bus_ops */ 1520 NULL, /* power */ 1521 solo_quiesce, /* quiesce */ 1522 }; 1523 1524 static struct modldrv solo_modldrv = { 1525 &mod_driverops, /* drv_modops */ 1526 "ESS Solo-1 Audio", /* linkinfo */ 1527 &solo_dev_ops, /* dev_ops */ 1528 }; 1529 1530 static struct modlinkage modlinkage = { 1531 MODREV_1, 1532 { &solo_modldrv, NULL } 1533 }; 1534 1535 int 1536 _init(void) 1537 { 1538 int rv; 1539 1540 audio_init_ops(&solo_dev_ops, DRVNAME); 1541 if ((rv = mod_install(&modlinkage)) != 0) { 1542 audio_fini_ops(&solo_dev_ops); 1543 } 1544 return (rv); 1545 } 1546 1547 int 1548 _fini(void) 1549 { 1550 int rv; 1551 1552 if ((rv = mod_remove(&modlinkage)) == 0) { 1553 audio_fini_ops(&solo_dev_ops); 1554 } 1555 return (rv); 1556 } 1557 1558 int 1559 _info(struct modinfo *modinfop) 1560 { 1561 return (mod_info(&modlinkage, modinfop)); 1562 } 1563