1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Purpose: Driver for the Creative P16X AC97 audio controller 29 */ 30 /* 31 * 32 * Copyright (C) 4Front Technologies 1996-2009. 33 * 34 * This software is released under CDDL 1.0 source license. 35 * See the COPYING file included in the main directory of this source 36 * distribution for the license terms and conditions. 37 */ 38 39 #include <sys/types.h> 40 #include <sys/modctl.h> 41 #include <sys/kmem.h> 42 #include <sys/conf.h> 43 #include <sys/ddi.h> 44 #include <sys/sunddi.h> 45 #include <sys/pci.h> 46 #include <sys/note.h> 47 #include <sys/audio/audio_driver.h> 48 #include <sys/audio/ac97.h> 49 50 #include "audiop16x.h" 51 52 /* 53 * These boards use an AC'97 codec, but don't have all of the 54 * various outputs that the AC'97 codec can offer. We just 55 * suppress them for now. 56 */ 57 static char *p16x_remove_ac97[] = { 58 AUDIO_CTRL_ID_BEEP, 59 AUDIO_CTRL_ID_VIDEO, 60 AUDIO_CTRL_ID_MICSRC, 61 AUDIO_CTRL_ID_SPEAKER, 62 AUDIO_CTRL_ID_SPKSRC, 63 NULL 64 }; 65 66 static struct ddi_device_acc_attr dev_attr = { 67 DDI_DEVICE_ATTR_V0, 68 DDI_STRUCTURE_LE_ACC, 69 DDI_STRICTORDER_ACC 70 }; 71 72 static struct ddi_device_acc_attr buf_attr = { 73 DDI_DEVICE_ATTR_V0, 74 DDI_NEVERSWAP_ACC, 75 DDI_STRICTORDER_ACC 76 }; 77 78 static ddi_dma_attr_t dma_attr_buf = { 79 DMA_ATTR_V0, /* version number */ 80 0x00000000, /* low DMA address range */ 81 0xffffffff, /* high DMA address range */ 82 0xfffffffe, /* DMA counter register */ 83 4, /* DMA address alignment */ 84 0x3c, /* DMA burstsizes */ 85 4, /* min effective DMA size */ 86 0xffffffff, /* max DMA xfer size */ 87 0xffffffff, /* segment boundary */ 88 1, /* s/g length */ 89 4, /* granularity of device */ 90 0 /* Bus specific DMA flags */ 91 }; 92 93 static int p16x_attach(dev_info_t *); 94 static int p16x_resume(dev_info_t *); 95 static int p16x_detach(p16x_dev_t *); 96 static int p16x_suspend(p16x_dev_t *); 97 98 static int p16x_open(void *, int, unsigned *, unsigned *, caddr_t *); 99 static void p16x_close(void *); 100 static int p16x_start(void *); 101 static void p16x_stop(void *); 102 static int p16x_format(void *); 103 static int p16x_channels(void *); 104 static int p16x_rate(void *); 105 static uint64_t p16x_count(void *); 106 static void p16x_sync(void *, unsigned); 107 static void p16x_chinfo(void *, int, unsigned *, unsigned *); 108 109 static uint16_t p16x_read_ac97(void *, uint8_t); 110 static void p16x_write_ac97(void *, uint8_t, uint16_t); 111 static int p16x_alloc_port(p16x_dev_t *, int); 112 static void p16x_update_port(p16x_port_t *); 113 static void p16x_start_port(p16x_port_t *); 114 static void p16x_stop_port(p16x_port_t *); 115 static void p16x_destroy(p16x_dev_t *); 116 static int p16x_setup_intrs(p16x_dev_t *); 117 static void p16x_hwinit(p16x_dev_t *); 118 static uint_t p16x_intr(caddr_t, caddr_t); 119 120 static audio_engine_ops_t p16x_engine_ops = { 121 AUDIO_ENGINE_VERSION, 122 p16x_open, 123 p16x_close, 124 p16x_start, 125 p16x_stop, 126 p16x_count, 127 p16x_format, 128 p16x_channels, 129 p16x_rate, 130 p16x_sync, 131 NULL, 132 p16x_chinfo, 133 NULL 134 }; 135 136 static unsigned int 137 read_reg(p16x_dev_t *dev, int reg, int chn) 138 { 139 unsigned int val; 140 141 mutex_enter(&dev->low_mutex); 142 OUTL(dev, (reg << 16) | (chn & 0xffff), PTR); /* Pointer */ 143 val = INL(dev, DR); /* Data */ 144 mutex_exit(&dev->low_mutex); 145 146 return (val); 147 } 148 149 static void 150 write_reg(p16x_dev_t *dev, int reg, int chn, unsigned int value) 151 { 152 153 mutex_enter(&dev->low_mutex); 154 OUTL(dev, (reg << 16) | (chn & 0xffff), PTR); /* Pointer */ 155 OUTL(dev, value, DR); /* Data */ 156 mutex_exit(&dev->low_mutex); 157 } 158 159 static uint16_t 160 p16x_read_ac97(void *arg, uint8_t index) 161 { 162 p16x_dev_t *dev = arg; 163 uint16_t value; 164 int i; 165 166 mutex_enter(&dev->low_mutex); 167 OUTB(dev, index, AC97A); 168 for (i = 0; i < 10000; i++) 169 if (INB(dev, AC97A) & 0x80) 170 break; 171 value = INW(dev, AC97D); 172 mutex_exit(&dev->low_mutex); 173 return (value); 174 } 175 176 static void 177 p16x_write_ac97(void *arg, uint8_t index, uint16_t data) 178 { 179 p16x_dev_t *dev = arg; 180 unsigned int i; 181 182 mutex_enter(&dev->low_mutex); 183 OUTB(dev, index, AC97A); 184 for (i = 0; i < 10000; i++) 185 if (INB(dev, AC97A) & 0x80) 186 break; 187 OUTW(dev, data, AC97D); 188 mutex_exit(&dev->low_mutex); 189 } 190 191 static uint_t 192 p16x_intr(caddr_t argp, caddr_t nocare) 193 { 194 p16x_dev_t *dev = (void *)argp; 195 unsigned int status; 196 audio_engine_t *consume = NULL; 197 audio_engine_t *produce = NULL; 198 199 _NOTE(ARGUNUSED(nocare)); 200 201 mutex_enter(&dev->mutex); 202 if (dev->suspended) { 203 mutex_exit(&dev->mutex); 204 return (DDI_INTR_UNCLAIMED); 205 } 206 /* Read the interrupt status */ 207 status = INL(dev, IP); 208 OUTL(dev, status, IP); /* Acknowledge */ 209 210 if (!(status & INTR_ALL)) { 211 mutex_exit(&dev->mutex); 212 return (DDI_INTR_UNCLAIMED); 213 } 214 215 if (status & INTR_PCI) { 216 audio_dev_warn(dev->adev, "PCI error triggered, PCI status %x", 217 pci_config_get16(dev->pcih, PCI_CONF_STAT)); 218 } 219 220 if ((status & (INTR_PFF | INTR_PFH)) && 221 (dev->port[P16X_PLAY]->started)) { 222 consume = dev->port[P16X_PLAY]->engine; 223 } 224 225 if ((status & (INTR_RFF | INTR_RFH)) && 226 (dev->port[P16X_REC]->started)) { 227 produce = dev->port[P16X_REC]->engine; 228 } 229 230 mutex_exit(&dev->mutex); 231 232 if (consume) { 233 audio_engine_consume(consume); 234 } 235 236 if (produce) { 237 audio_engine_produce(produce); 238 } 239 240 return (DDI_INTR_CLAIMED); 241 } 242 243 /* 244 * Audio routines 245 */ 246 247 static void 248 p16x_init_port(p16x_port_t *port) 249 { 250 p16x_dev_t *dev = port->dev; 251 252 if (port->suspended) 253 return; 254 255 if (port->port_num == P16X_REC) { 256 write_reg(dev, CRFA, 0, 0); 257 write_reg(dev, CRCAV, 0, 0); 258 259 } else { 260 for (int i = 0; i < 3; i++) { 261 write_reg(dev, PTBA, i, 0); 262 write_reg(dev, PTBS, i, 0); 263 write_reg(dev, PTCA, i, 0); 264 write_reg(dev, PFEA, i, 0); 265 write_reg(dev, CPFA, i, 0); 266 write_reg(dev, CPCAV, i, 0); 267 } 268 269 } 270 } 271 272 273 static int 274 p16x_open(void *arg, int flag, uint_t *fragfrp, uint_t *nfp, caddr_t *bufp) 275 { 276 p16x_port_t *port = arg; 277 p16x_dev_t *dev = port->dev; 278 279 _NOTE(ARGUNUSED(flag)); 280 281 mutex_enter(&dev->mutex); 282 283 port->started = B_FALSE; 284 port->count = 0; 285 port->offset = 0; 286 287 p16x_init_port(port); 288 289 *fragfrp = port->fragfr; 290 *nfp = port->nfrags; 291 *bufp = port->buf_kaddr; 292 mutex_exit(&dev->mutex); 293 294 return (0); 295 } 296 297 void 298 p16x_close(void *arg) 299 { 300 p16x_port_t *port = arg; 301 p16x_dev_t *dev = port->dev; 302 303 mutex_enter(&dev->mutex); 304 p16x_stop_port(port); 305 port->started = B_FALSE; 306 mutex_exit(&dev->mutex); 307 } 308 309 int 310 p16x_start(void *arg) 311 { 312 p16x_port_t *port = arg; 313 p16x_dev_t *dev = port->dev; 314 315 mutex_enter(&dev->mutex); 316 if (!port->started) { 317 p16x_start_port(port); 318 port->started = B_TRUE; 319 } 320 mutex_exit(&dev->mutex); 321 return (0); 322 } 323 324 void 325 p16x_stop(void *arg) 326 { 327 p16x_port_t *port = arg; 328 p16x_dev_t *dev = port->dev; 329 330 mutex_enter(&dev->mutex); 331 if (port->started) { 332 p16x_stop_port(port); 333 port->started = B_FALSE; 334 } 335 mutex_exit(&dev->mutex); 336 } 337 338 int 339 p16x_format(void *arg) 340 { 341 _NOTE(ARGUNUSED(arg)); 342 343 return (AUDIO_FORMAT_S16_LE); 344 } 345 346 int 347 p16x_channels(void *arg) 348 { 349 p16x_port_t *port = arg; 350 351 return (port->nchan); 352 } 353 354 int 355 p16x_rate(void *arg) 356 { 357 _NOTE(ARGUNUSED(arg)); 358 359 return (48000); 360 } 361 362 void 363 p16x_sync(void *arg, unsigned nframes) 364 { 365 p16x_port_t *port = arg; 366 _NOTE(ARGUNUSED(nframes)); 367 368 (void) ddi_dma_sync(port->buf_dmah, 0, 0, port->syncdir); 369 } 370 371 uint64_t 372 p16x_count(void *arg) 373 { 374 p16x_port_t *port = arg; 375 p16x_dev_t *dev = port->dev; 376 uint64_t val; 377 378 mutex_enter(&dev->mutex); 379 if (port->started && !dev->suspended) 380 p16x_update_port(port); 381 val = port->count; 382 mutex_exit(&dev->mutex); 383 384 return (val); 385 } 386 387 static void 388 p16x_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr) 389 { 390 p16x_port_t *port = arg; 391 unsigned mult; 392 393 if (port->port_num == P16X_PLAY) { 394 switch (chan) { 395 case 0: /* left front */ 396 case 1: /* right front */ 397 mult = 0; 398 break; 399 case 2: /* center */ 400 case 3: /* lfe */ 401 mult = 2; 402 break; 403 case 4: /* left surround */ 404 case 5: /* right surround */ 405 mult = 1; 406 break; 407 } 408 *offset = (port->buf_frames * 2 * mult) + (chan % 2); 409 *incr = 2; 410 } else { 411 *offset = chan; 412 *incr = 2; 413 } 414 } 415 416 /* private implementation bits */ 417 418 void 419 p16x_update_port(p16x_port_t *port) 420 { 421 p16x_dev_t *dev = port->dev; 422 uint32_t offset, n; 423 424 if (dev->suspended) 425 return; 426 427 if (port->port_num == P16X_PLAY) { 428 offset = read_reg(dev, CPFA, 0); 429 } else { 430 offset = read_reg(dev, CRFA, 0); 431 } 432 433 /* get the offset, and switch to frames */ 434 offset /= (2 * sizeof (uint16_t)); 435 436 if (offset >= port->offset) { 437 n = offset - port->offset; 438 } else { 439 n = offset + (port->buf_frames - port->offset); 440 } 441 port->offset = offset; 442 port->count += n; 443 } 444 445 void 446 p16x_start_port(p16x_port_t *port) 447 { 448 p16x_dev_t *dev = port->dev; 449 unsigned int tmp; 450 451 ASSERT(mutex_owned(&dev->mutex)); 452 453 if (dev->suspended) 454 return; 455 456 if (port->port_num == P16X_REC) { 457 /* Enable Rec Channel */ 458 tmp = read_reg(dev, SA, 0); 459 tmp |= 0x100; 460 write_reg(dev, SA, 0, tmp); 461 tmp = INL(dev, IE); 462 tmp |= INTR_REC; 463 OUTL(dev, tmp, IE); 464 } else { 465 /* Enable play channel and go */ 466 tmp = read_reg(dev, SA, 0); 467 tmp |= 7; 468 write_reg(dev, SA, 0, tmp); 469 tmp = INL(dev, IE); 470 tmp |= INTR_PLAY; 471 OUTL(dev, tmp, IE); 472 } 473 } 474 475 void 476 p16x_stop_port(p16x_port_t *port) 477 { 478 p16x_dev_t *dev = port->dev; 479 unsigned int tmp; 480 481 482 if (dev->suspended) 483 return; 484 485 if (port->port_num == P16X_REC) { 486 /* Disable rec channel */ 487 tmp = read_reg(dev, SA, 0); 488 tmp &= ~0x100; 489 write_reg(dev, SA, 0, tmp); 490 tmp = INL(dev, IE); 491 tmp &= ~INTR_REC; 492 OUTL(dev, tmp, IE); 493 494 } else { 495 /* Disable Play channel */ 496 tmp = read_reg(dev, SA, 0); 497 tmp &= ~7; 498 write_reg(dev, SA, 0, tmp); 499 tmp = INL(dev, IE); 500 tmp &= ~INTR_PLAY; 501 OUTL(dev, tmp, IE); 502 } 503 } 504 505 int 506 p16x_alloc_port(p16x_dev_t *dev, int num) 507 { 508 p16x_port_t *port; 509 size_t len; 510 ddi_dma_cookie_t cookie; 511 uint_t count; 512 int dir; 513 char *prop; 514 unsigned caps; 515 audio_dev_t *adev; 516 517 adev = dev->adev; 518 port = kmem_zalloc(sizeof (*port), KM_SLEEP); 519 dev->port[num] = port; 520 port->dev = dev; 521 port->started = B_FALSE; 522 523 switch (num) { 524 case P16X_REC: 525 prop = "record-interrupts"; 526 port->syncdir = DDI_DMA_SYNC_FORKERNEL; 527 caps = ENGINE_INPUT_CAP; 528 dir = DDI_DMA_READ; 529 port->port_num = P16X_REC; 530 port->nchan = 2; 531 break; 532 case P16X_PLAY: 533 prop = "play-interrupts"; 534 port->syncdir = DDI_DMA_SYNC_FORDEV; 535 caps = ENGINE_OUTPUT_CAP; 536 dir = DDI_DMA_WRITE; 537 port->port_num = P16X_PLAY; 538 port->nchan = 6; 539 break; 540 default: 541 return (DDI_FAILURE); 542 } 543 544 /* figure out fragment configuration */ 545 port->intrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 546 DDI_PROP_DONTPASS, prop, P16X_DEF_INTRS); 547 548 /* make sure the values are good */ 549 if (port->intrs < P16X_MIN_INTRS) { 550 audio_dev_warn(adev, "%s too low, %d, reset to %d", 551 prop, port->intrs, P16X_MIN_INTRS); 552 port->intrs = P16X_MIN_INTRS; 553 } else if (port->intrs > P16X_MAX_INTRS) { 554 audio_dev_warn(adev, "%s too high, %d, reset to %d", 555 prop, port->intrs, P16X_DEF_INTRS); 556 port->intrs = P16X_DEF_INTRS; 557 } 558 559 /* 560 * This needs the very latest Boomer changes. 561 */ 562 port->nfrags = 2; 563 port->fragfr = 48000 / port->intrs; 564 /* 565 * The device operates in pairs of dwords at a time, for 566 * performance reasons. So make sure that our buffer is 567 * arranged as a whole number of these. We could probably 568 * fine tune by just ensuring that the overall buffer was 128 569 * (64 for half and 64 for full), but this is simpler. 570 */ 571 port->fragfr = (port->fragfr + 63) & ~(63); 572 port->fragsz = port->fragfr * port->nchan * 2; /* 16 bit frames */ 573 port->buf_size = port->nfrags * port->fragsz; 574 port->buf_frames = port->fragfr * port->nfrags; 575 576 /* now allocate buffers */ 577 if (ddi_dma_alloc_handle(dev->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL, 578 &port->buf_dmah) != DDI_SUCCESS) { 579 audio_dev_warn(adev, "failed to allocate BUF handle"); 580 return (DDI_FAILURE); 581 } 582 583 if (ddi_dma_mem_alloc(port->buf_dmah, port->buf_size, 584 &buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 585 &port->buf_kaddr, &len, &port->buf_acch) != DDI_SUCCESS) { 586 audio_dev_warn(adev, "failed to allocate BUF memory"); 587 return (DDI_FAILURE); 588 } 589 590 if (ddi_dma_addr_bind_handle(port->buf_dmah, NULL, port->buf_kaddr, 591 len, DDI_DMA_CONSISTENT | dir, DDI_DMA_SLEEP, NULL, &cookie, 592 &count) != DDI_SUCCESS) { 593 audio_dev_warn(adev, "failed binding BUF DMA handle"); 594 return (DDI_FAILURE); 595 } 596 port->buf_paddr = cookie.dmac_address; 597 598 port->engine = audio_engine_alloc(&p16x_engine_ops, caps); 599 if (port->engine == NULL) { 600 audio_dev_warn(adev, "audio_engine_alloc failed"); 601 return (DDI_FAILURE); 602 } 603 604 audio_engine_set_private(port->engine, port); 605 audio_dev_add_engine(adev, port->engine); 606 607 return (DDI_SUCCESS); 608 } 609 610 void 611 p16x_destroy(p16x_dev_t *dev) 612 { 613 if (dev->ih != NULL) { 614 (void) ddi_intr_disable(dev->ih); 615 (void) ddi_intr_remove_handler(dev->ih); 616 (void) ddi_intr_free(dev->ih); 617 mutex_destroy(&dev->mutex); 618 mutex_destroy(&dev->low_mutex); 619 } 620 621 if (dev->ksp) { 622 kstat_delete(dev->ksp); 623 } 624 625 for (int i = 0; i < P16X_NUM_PORT; i++) { 626 p16x_port_t *port = dev->port[i]; 627 if (!port) 628 continue; 629 if (port->engine) { 630 audio_dev_remove_engine(dev->adev, port->engine); 631 audio_engine_free(port->engine); 632 } 633 if (port->buf_paddr) { 634 (void) ddi_dma_unbind_handle(port->buf_dmah); 635 } 636 if (port->buf_acch) { 637 ddi_dma_mem_free(&port->buf_acch); 638 } 639 if (port->buf_dmah) { 640 ddi_dma_free_handle(&port->buf_dmah); 641 } 642 kmem_free(port, sizeof (*port)); 643 } 644 645 if (dev->ac97 != NULL) { 646 ac97_free(dev->ac97); 647 } 648 if (dev->adev != NULL) { 649 audio_dev_free(dev->adev); 650 } 651 if (dev->regsh != NULL) { 652 ddi_regs_map_free(&dev->regsh); 653 } 654 if (dev->pcih != NULL) { 655 pci_config_teardown(&dev->pcih); 656 } 657 kmem_free(dev, sizeof (*dev)); 658 } 659 660 void 661 p16x_hwinit(p16x_dev_t *dev) 662 { 663 p16x_port_t *port; 664 uint32_t paddr; 665 uint32_t chunksz; 666 int i; 667 668 for (i = 0; i < 3; i++) { 669 write_reg(dev, PTBA, i, 0); 670 write_reg(dev, PTBS, i, 0); 671 write_reg(dev, PTCA, i, 0); 672 write_reg(dev, PFEA, i, 0); 673 write_reg(dev, CPFA, i, 0); 674 write_reg(dev, CPCAV, i, 0); 675 write_reg(dev, CRFA, i, 0); 676 write_reg(dev, CRCAV, i, 0); 677 } 678 write_reg(dev, SCS0, 0, 0x02108504); 679 write_reg(dev, SCS1, 0, 0x02108504); 680 write_reg(dev, SCS2, 0, 0x02108504); 681 682 /* set the spdif/analog combo jack to analog out */ 683 write_reg(dev, SPC, 0, 0x00000700); 684 write_reg(dev, EA_aux, 0, 0x0001003f); 685 686 port = dev->port[P16X_REC]; 687 /* Set physical address of the DMA buffer */ 688 write_reg(dev, RFBA, 0, port->buf_paddr); 689 write_reg(dev, RFBS, 0, (port->buf_size) << 16); 690 691 /* Set physical address of the DMA buffer */ 692 port = dev->port[P16X_PLAY]; 693 paddr = port->buf_paddr; 694 chunksz = port->buf_frames * 4; 695 write_reg(dev, PFBA, 0, paddr); 696 write_reg(dev, PFBS, 0, chunksz << 16); 697 paddr += chunksz; 698 write_reg(dev, PFBA, 1, paddr); 699 write_reg(dev, PFBS, 1, chunksz << 16); 700 paddr += chunksz; 701 write_reg(dev, PFBA, 2, paddr); 702 write_reg(dev, PFBS, 2, chunksz << 16); 703 704 OUTL(dev, 0x1080, GPIO); /* GPIO */ 705 /* Clear any pending interrupts */ 706 OUTL(dev, INTR_ALL, IP); 707 OUTL(dev, 0, IE); 708 OUTL(dev, 0x9, HC); /* Enable audio */ 709 } 710 711 int 712 p16x_setup_intrs(p16x_dev_t *dev) 713 { 714 uint_t ipri; 715 int actual; 716 int rv; 717 ddi_intr_handle_t ih[1]; 718 719 rv = ddi_intr_alloc(dev->dip, ih, DDI_INTR_TYPE_FIXED, 720 0, 1, &actual, DDI_INTR_ALLOC_STRICT); 721 if ((rv != DDI_SUCCESS) || (actual != 1)) { 722 audio_dev_warn(dev->adev, 723 "Can't alloc interrupt handle (rv %d actual %d)", 724 rv, actual); 725 return (DDI_FAILURE); 726 } 727 728 if (ddi_intr_get_pri(ih[0], &ipri) != DDI_SUCCESS) { 729 audio_dev_warn(dev->adev, "Can't get interrupt priority"); 730 (void) ddi_intr_free(ih[0]); 731 return (DDI_FAILURE); 732 } 733 734 if (ddi_intr_add_handler(ih[0], p16x_intr, dev, NULL) != 735 DDI_SUCCESS) { 736 audio_dev_warn(dev->adev, "Can't add interrupt handler"); 737 (void) ddi_intr_free(ih[0]); 738 return (DDI_FAILURE); 739 } 740 741 dev->ih = ih[0]; 742 mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri)); 743 mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri)); 744 return (DDI_SUCCESS); 745 } 746 747 int 748 p16x_attach(dev_info_t *dip) 749 { 750 uint16_t vendor, device; 751 p16x_dev_t *dev; 752 ddi_acc_handle_t pcih; 753 754 dev = kmem_zalloc(sizeof (*dev), KM_SLEEP); 755 dev->dip = dip; 756 ddi_set_driver_private(dip, dev); 757 758 /* we don't support high level interrupts in the driver */ 759 if (ddi_intr_hilevel(dip, 0) != 0) { 760 cmn_err(CE_WARN, 761 "!%s%d: unsupported high level interrupt", 762 ddi_driver_name(dip), ddi_get_instance(dip)); 763 return (DDI_FAILURE); 764 } 765 766 if (ddi_get_iblock_cookie(dip, 0, &dev->iblock) != DDI_SUCCESS) { 767 cmn_err(CE_WARN, 768 "!%s%d: cannot get iblock cookie", 769 ddi_driver_name(dip), ddi_get_instance(dip)); 770 kmem_free(dev, sizeof (*dev)); 771 return (DDI_FAILURE); 772 } 773 mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, dev->iblock); 774 mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, dev->iblock); 775 776 if ((dev->adev = audio_dev_alloc(dip, 0)) == NULL) { 777 cmn_err(CE_WARN, "audio_dev_alloc failed"); 778 goto error; 779 } 780 781 if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) { 782 audio_dev_warn(dev->adev, "pci_config_setup failed"); 783 goto error; 784 } 785 dev->pcih = pcih; 786 787 vendor = pci_config_get16(pcih, PCI_CONF_VENID); 788 device = pci_config_get16(pcih, PCI_CONF_DEVID); 789 if (vendor != CREATIVE_VENDOR_ID || 790 device != SB_P16X_ID) { 791 audio_dev_warn(dev->adev, "Hardware not recognized " 792 "(vendor=%x, dev=%x)", vendor, device); 793 goto error; 794 } 795 796 /* set PCI command register */ 797 pci_config_put16(pcih, PCI_CONF_COMM, 798 pci_config_get16(pcih, PCI_CONF_COMM) | 799 PCI_COMM_MAE | PCI_COMM_IO); 800 801 802 if ((ddi_regs_map_setup(dip, 1, &dev->base, 0, 0, &dev_attr, 803 &dev->regsh)) != DDI_SUCCESS) { 804 audio_dev_warn(dev->adev, "failed to map registers"); 805 goto error; 806 } 807 808 audio_dev_set_description(dev->adev, "Creative Sound Blaster Live!"); 809 audio_dev_set_version(dev->adev, "SBO200"); 810 811 if ((p16x_alloc_port(dev, P16X_PLAY) != DDI_SUCCESS) || 812 (p16x_alloc_port(dev, P16X_REC) != DDI_SUCCESS)) { 813 goto error; 814 } 815 816 p16x_hwinit(dev); 817 818 /* set up the interrupt handler */ 819 if (p16x_setup_intrs(dev) != DDI_SUCCESS) { 820 goto error; 821 } 822 823 /* Enable PCI interrupts */ 824 OUTL(dev, INTR_PCI, IE); 825 826 dev->ac97 = ac97_allocate(dev->adev, dip, 827 p16x_read_ac97, p16x_write_ac97, dev); 828 if (dev->ac97 == NULL) { 829 audio_dev_warn(dev->adev, "failed to allocate ac97 handle"); 830 goto error; 831 } 832 833 ac97_probe_controls(dev->ac97); 834 835 /* remove the AC'97 controls we don't want to expose */ 836 for (int i = 0; p16x_remove_ac97[i]; i++) { 837 ac97_ctrl_t *ctrl; 838 ctrl = ac97_control_find(dev->ac97, p16x_remove_ac97[i]); 839 if (ctrl != NULL) { 840 ac97_control_unregister(ctrl); 841 } 842 } 843 844 ac97_register_controls(dev->ac97); 845 846 /* set up kernel statistics */ 847 if ((dev->ksp = kstat_create(P16X_NAME, ddi_get_instance(dip), 848 P16X_NAME, "controller", KSTAT_TYPE_INTR, 1, 849 KSTAT_FLAG_PERSISTENT)) != NULL) { 850 kstat_install(dev->ksp); 851 } 852 853 if (audio_dev_register(dev->adev) != DDI_SUCCESS) { 854 audio_dev_warn(dev->adev, "unable to register with framework"); 855 goto error; 856 } 857 858 (void) ddi_intr_enable(dev->ih); 859 ddi_report_dev(dip); 860 861 return (DDI_SUCCESS); 862 863 error: 864 p16x_destroy(dev); 865 return (DDI_FAILURE); 866 } 867 868 int 869 p16x_resume(dev_info_t *dip) 870 { 871 p16x_dev_t *dev; 872 873 dev = ddi_get_driver_private(dip); 874 875 p16x_hwinit(dev); 876 877 /* allow ac97 operations again */ 878 ac97_resume(dev->ac97); 879 880 mutex_enter(&dev->mutex); 881 dev->suspended = B_FALSE; 882 883 for (int i = 0; i < P16X_NUM_PORT; i++) { 884 885 p16x_port_t *port = dev->port[i]; 886 887 if (port->engine != NULL) 888 audio_engine_reset(port->engine); 889 890 /* reset the port */ 891 p16x_init_port(port); 892 893 if (port->started) { 894 p16x_start_port(port); 895 } else { 896 p16x_stop_port(port); 897 } 898 } 899 mutex_exit(&dev->mutex); 900 return (DDI_SUCCESS); 901 } 902 903 int 904 p16x_detach(p16x_dev_t *dev) 905 { 906 if (audio_dev_unregister(dev->adev) != DDI_SUCCESS) 907 return (DDI_FAILURE); 908 909 p16x_destroy(dev); 910 return (DDI_SUCCESS); 911 } 912 913 int 914 p16x_suspend(p16x_dev_t *dev) 915 { 916 ac97_suspend(dev->ac97); 917 918 mutex_enter(&dev->mutex); 919 for (int i = 0; i < P16X_NUM_PORT; i++) { 920 921 p16x_port_t *port = dev->port[i]; 922 p16x_stop_port(port); 923 } 924 925 write_reg(dev, SA, 0, 0); 926 OUTL(dev, 0x00, IE); /* Interrupt disable */ 927 OUTL(dev, 0x01, HC); 928 929 dev->suspended = B_TRUE; 930 mutex_exit(&dev->mutex); 931 return (DDI_SUCCESS); 932 } 933 934 static int p16x_ddi_attach(dev_info_t *, ddi_attach_cmd_t); 935 static int p16x_ddi_detach(dev_info_t *, ddi_detach_cmd_t); 936 static int p16x_ddi_quiesce(dev_info_t *); 937 938 static struct dev_ops p16x_dev_ops = { 939 DEVO_REV, /* rev */ 940 0, /* refcnt */ 941 NULL, /* getinfo */ 942 nulldev, /* identify */ 943 nulldev, /* probe */ 944 p16x_ddi_attach, /* attach */ 945 p16x_ddi_detach, /* detach */ 946 nodev, /* reset */ 947 NULL, /* cb_ops */ 948 NULL, /* bus_ops */ 949 NULL, /* power */ 950 p16x_ddi_quiesce, /* quiesce */ 951 }; 952 953 static struct modldrv p16x_modldrv = { 954 &mod_driverops, /* drv_modops */ 955 "Creative P16X Audio", /* linkinfo */ 956 &p16x_dev_ops, /* dev_ops */ 957 }; 958 959 static struct modlinkage modlinkage = { 960 MODREV_1, 961 { &p16x_modldrv, NULL } 962 }; 963 964 int 965 _init(void) 966 { 967 int rv; 968 969 audio_init_ops(&p16x_dev_ops, P16X_NAME); 970 if ((rv = mod_install(&modlinkage)) != 0) { 971 audio_fini_ops(&p16x_dev_ops); 972 } 973 return (rv); 974 } 975 976 int 977 _fini(void) 978 { 979 int rv; 980 981 if ((rv = mod_remove(&modlinkage)) == 0) { 982 audio_fini_ops(&p16x_dev_ops); 983 } 984 return (rv); 985 } 986 987 int 988 _info(struct modinfo *modinfop) 989 { 990 return (mod_info(&modlinkage, modinfop)); 991 } 992 993 int 994 p16x_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 995 { 996 switch (cmd) { 997 case DDI_ATTACH: 998 return (p16x_attach(dip)); 999 1000 case DDI_RESUME: 1001 return (p16x_resume(dip)); 1002 1003 default: 1004 return (DDI_FAILURE); 1005 } 1006 } 1007 1008 int 1009 p16x_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 1010 { 1011 p16x_dev_t *dev; 1012 1013 dev = ddi_get_driver_private(dip); 1014 1015 switch (cmd) { 1016 case DDI_DETACH: 1017 return (p16x_detach(dev)); 1018 1019 case DDI_SUSPEND: 1020 return (p16x_suspend(dev)); 1021 1022 default: 1023 return (DDI_FAILURE); 1024 } 1025 } 1026 1027 int 1028 p16x_ddi_quiesce(dev_info_t *dip) 1029 { 1030 p16x_dev_t *dev; 1031 1032 dev = ddi_get_driver_private(dip); 1033 1034 for (int i = 0; i < P16X_NUM_PORT; i++) { 1035 1036 p16x_port_t *port = dev->port[i]; 1037 p16x_stop_port(port); 1038 } 1039 1040 write_reg(dev, SA, 0, 0); 1041 OUTL(dev, 0x00, IE); /* Interrupt disable */ 1042 OUTL(dev, 0x01, HC); 1043 1044 return (DDI_SUCCESS); 1045 } 1046