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 size_t p16x_qlen(void *); 108 static void p16x_chinfo(void *, int, unsigned *, unsigned *); 109 110 static uint16_t p16x_read_ac97(void *, uint8_t); 111 static void p16x_write_ac97(void *, uint8_t, uint16_t); 112 static int p16x_alloc_port(p16x_dev_t *, int); 113 static void p16x_update_port(p16x_port_t *); 114 static void p16x_start_port(p16x_port_t *); 115 static void p16x_stop_port(p16x_port_t *); 116 static void p16x_destroy(p16x_dev_t *); 117 static int p16x_setup_intrs(p16x_dev_t *); 118 static void p16x_hwinit(p16x_dev_t *); 119 static uint_t p16x_intr(caddr_t, caddr_t); 120 121 static audio_engine_ops_t p16x_engine_ops = { 122 AUDIO_ENGINE_VERSION, 123 p16x_open, 124 p16x_close, 125 p16x_start, 126 p16x_stop, 127 p16x_count, 128 p16x_format, 129 p16x_channels, 130 p16x_rate, 131 p16x_sync, 132 p16x_qlen, 133 p16x_chinfo, 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 size_t 372 p16x_qlen(void *arg) 373 { 374 _NOTE(ARGUNUSED(arg)); 375 return (0); 376 } 377 378 uint64_t 379 p16x_count(void *arg) 380 { 381 p16x_port_t *port = arg; 382 p16x_dev_t *dev = port->dev; 383 uint64_t val; 384 385 mutex_enter(&dev->mutex); 386 if (port->started && !dev->suspended) 387 p16x_update_port(port); 388 val = port->count; 389 mutex_exit(&dev->mutex); 390 391 return (val); 392 } 393 394 static void 395 p16x_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr) 396 { 397 p16x_port_t *port = arg; 398 unsigned mult; 399 400 if (port->port_num == P16X_PLAY) { 401 switch (chan) { 402 case 0: /* left front */ 403 case 1: /* right front */ 404 mult = 0; 405 break; 406 case 2: /* center */ 407 case 3: /* lfe */ 408 mult = 2; 409 break; 410 case 4: /* left surround */ 411 case 5: /* right surround */ 412 mult = 1; 413 break; 414 } 415 *offset = (port->buf_frames * 2 * mult) + (chan % 2); 416 *incr = 2; 417 } else { 418 *offset = chan; 419 *incr = 2; 420 } 421 } 422 423 /* private implementation bits */ 424 425 void 426 p16x_update_port(p16x_port_t *port) 427 { 428 p16x_dev_t *dev = port->dev; 429 uint32_t offset, n; 430 431 if (dev->suspended) 432 return; 433 434 if (port->port_num == P16X_PLAY) { 435 offset = read_reg(dev, CPFA, 0); 436 } else { 437 offset = read_reg(dev, CRFA, 0); 438 } 439 440 /* get the offset, and switch to frames */ 441 offset /= (2 * sizeof (uint16_t)); 442 443 if (offset >= port->offset) { 444 n = offset - port->offset; 445 } else { 446 n = offset + (port->buf_frames - port->offset); 447 } 448 port->offset = offset; 449 port->count += n; 450 } 451 452 void 453 p16x_start_port(p16x_port_t *port) 454 { 455 p16x_dev_t *dev = port->dev; 456 unsigned int tmp; 457 458 ASSERT(mutex_owned(&dev->mutex)); 459 460 if (dev->suspended) 461 return; 462 463 if (port->port_num == P16X_REC) { 464 /* Enable Rec Channel */ 465 tmp = read_reg(dev, SA, 0); 466 tmp |= 0x100; 467 write_reg(dev, SA, 0, tmp); 468 tmp = INL(dev, IE); 469 tmp |= INTR_REC; 470 OUTL(dev, tmp, IE); 471 } else { 472 /* Enable play channel and go */ 473 tmp = read_reg(dev, SA, 0); 474 tmp |= 7; 475 write_reg(dev, SA, 0, tmp); 476 tmp = INL(dev, IE); 477 tmp |= INTR_PLAY; 478 OUTL(dev, tmp, IE); 479 } 480 } 481 482 void 483 p16x_stop_port(p16x_port_t *port) 484 { 485 p16x_dev_t *dev = port->dev; 486 unsigned int tmp; 487 488 489 if (dev->suspended) 490 return; 491 492 if (port->port_num == P16X_REC) { 493 /* Disable rec channel */ 494 tmp = read_reg(dev, SA, 0); 495 tmp &= ~0x100; 496 write_reg(dev, SA, 0, tmp); 497 tmp = INL(dev, IE); 498 tmp &= ~INTR_REC; 499 OUTL(dev, tmp, IE); 500 501 } else { 502 /* Disable Play channel */ 503 tmp = read_reg(dev, SA, 0); 504 tmp &= ~7; 505 write_reg(dev, SA, 0, tmp); 506 tmp = INL(dev, IE); 507 tmp &= ~INTR_PLAY; 508 OUTL(dev, tmp, IE); 509 } 510 } 511 512 int 513 p16x_alloc_port(p16x_dev_t *dev, int num) 514 { 515 p16x_port_t *port; 516 size_t len; 517 ddi_dma_cookie_t cookie; 518 uint_t count; 519 int dir; 520 char *prop; 521 unsigned caps; 522 audio_dev_t *adev; 523 524 adev = dev->adev; 525 port = kmem_zalloc(sizeof (*port), KM_SLEEP); 526 dev->port[num] = port; 527 port->dev = dev; 528 port->started = B_FALSE; 529 530 switch (num) { 531 case P16X_REC: 532 prop = "record-interrupts"; 533 port->syncdir = DDI_DMA_SYNC_FORKERNEL; 534 caps = ENGINE_INPUT_CAP; 535 dir = DDI_DMA_READ; 536 port->port_num = P16X_REC; 537 port->nchan = 2; 538 break; 539 case P16X_PLAY: 540 prop = "play-interrupts"; 541 port->syncdir = DDI_DMA_SYNC_FORDEV; 542 caps = ENGINE_OUTPUT_CAP; 543 dir = DDI_DMA_WRITE; 544 port->port_num = P16X_PLAY; 545 port->nchan = 6; 546 break; 547 default: 548 return (DDI_FAILURE); 549 } 550 551 /* figure out fragment configuration */ 552 port->intrs = ddi_prop_get_int(DDI_DEV_T_ANY, dev->dip, 553 DDI_PROP_DONTPASS, prop, P16X_DEF_INTRS); 554 555 /* make sure the values are good */ 556 if (port->intrs < P16X_MIN_INTRS) { 557 audio_dev_warn(adev, "%s too low, %d, reset to %d", 558 prop, port->intrs, P16X_MIN_INTRS); 559 port->intrs = P16X_MIN_INTRS; 560 } else if (port->intrs > P16X_MAX_INTRS) { 561 audio_dev_warn(adev, "%s too high, %d, reset to %d", 562 prop, port->intrs, P16X_DEF_INTRS); 563 port->intrs = P16X_DEF_INTRS; 564 } 565 566 /* 567 * This needs the very latest Boomer changes. 568 */ 569 port->nfrags = 2; 570 port->fragfr = 48000 / port->intrs; 571 /* 572 * The device operates in pairs of dwords at a time, for 573 * performance reasons. So make sure that our buffer is 574 * arranged as a whole number of these. We could probably 575 * fine tune by just ensuring that the overall buffer was 128 576 * (64 for half and 64 for full), but this is simpler. 577 */ 578 port->fragfr = (port->fragfr + 63) & ~(63); 579 port->fragsz = port->fragfr * port->nchan * 2; /* 16 bit frames */ 580 port->buf_size = port->nfrags * port->fragsz; 581 port->buf_frames = port->fragfr * port->nfrags; 582 583 /* now allocate buffers */ 584 if (ddi_dma_alloc_handle(dev->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL, 585 &port->buf_dmah) != DDI_SUCCESS) { 586 audio_dev_warn(adev, "failed to allocate BUF handle"); 587 return (DDI_FAILURE); 588 } 589 590 if (ddi_dma_mem_alloc(port->buf_dmah, port->buf_size, 591 &buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 592 &port->buf_kaddr, &len, &port->buf_acch) != DDI_SUCCESS) { 593 audio_dev_warn(adev, "failed to allocate BUF memory"); 594 return (DDI_FAILURE); 595 } 596 597 if (ddi_dma_addr_bind_handle(port->buf_dmah, NULL, port->buf_kaddr, 598 len, DDI_DMA_CONSISTENT | dir, DDI_DMA_SLEEP, NULL, &cookie, 599 &count) != DDI_SUCCESS) { 600 audio_dev_warn(adev, "failed binding BUF DMA handle"); 601 return (DDI_FAILURE); 602 } 603 port->buf_paddr = cookie.dmac_address; 604 605 port->engine = audio_engine_alloc(&p16x_engine_ops, caps); 606 if (port->engine == NULL) { 607 audio_dev_warn(adev, "audio_engine_alloc failed"); 608 return (DDI_FAILURE); 609 } 610 611 audio_engine_set_private(port->engine, port); 612 audio_dev_add_engine(adev, port->engine); 613 614 return (DDI_SUCCESS); 615 } 616 617 void 618 p16x_destroy(p16x_dev_t *dev) 619 { 620 if (dev->ih != NULL) { 621 (void) ddi_intr_disable(dev->ih); 622 (void) ddi_intr_remove_handler(dev->ih); 623 (void) ddi_intr_free(dev->ih); 624 mutex_destroy(&dev->mutex); 625 mutex_destroy(&dev->low_mutex); 626 } 627 628 if (dev->ksp) { 629 kstat_delete(dev->ksp); 630 } 631 632 for (int i = 0; i < P16X_NUM_PORT; i++) { 633 p16x_port_t *port = dev->port[i]; 634 if (!port) 635 continue; 636 if (port->engine) { 637 audio_dev_remove_engine(dev->adev, port->engine); 638 audio_engine_free(port->engine); 639 } 640 if (port->buf_paddr) { 641 (void) ddi_dma_unbind_handle(port->buf_dmah); 642 } 643 if (port->buf_acch) { 644 ddi_dma_mem_free(&port->buf_acch); 645 } 646 if (port->buf_dmah) { 647 ddi_dma_free_handle(&port->buf_dmah); 648 } 649 kmem_free(port, sizeof (*port)); 650 } 651 652 if (dev->ac97 != NULL) { 653 ac97_free(dev->ac97); 654 } 655 if (dev->adev != NULL) { 656 audio_dev_free(dev->adev); 657 } 658 if (dev->regsh != NULL) { 659 ddi_regs_map_free(&dev->regsh); 660 } 661 if (dev->pcih != NULL) { 662 pci_config_teardown(&dev->pcih); 663 } 664 kmem_free(dev, sizeof (*dev)); 665 } 666 667 void 668 p16x_hwinit(p16x_dev_t *dev) 669 { 670 p16x_port_t *port; 671 uint32_t paddr; 672 uint32_t chunksz; 673 int i; 674 675 for (i = 0; i < 3; i++) { 676 write_reg(dev, PTBA, i, 0); 677 write_reg(dev, PTBS, i, 0); 678 write_reg(dev, PTCA, i, 0); 679 write_reg(dev, PFEA, i, 0); 680 write_reg(dev, CPFA, i, 0); 681 write_reg(dev, CPCAV, i, 0); 682 write_reg(dev, CRFA, i, 0); 683 write_reg(dev, CRCAV, i, 0); 684 } 685 write_reg(dev, SCS0, 0, 0x02108504); 686 write_reg(dev, SCS1, 0, 0x02108504); 687 write_reg(dev, SCS2, 0, 0x02108504); 688 689 /* set the spdif/analog combo jack to analog out */ 690 write_reg(dev, SPC, 0, 0x00000700); 691 write_reg(dev, EA_aux, 0, 0x0001003f); 692 693 port = dev->port[P16X_REC]; 694 /* Set physical address of the DMA buffer */ 695 write_reg(dev, RFBA, 0, port->buf_paddr); 696 write_reg(dev, RFBS, 0, (port->buf_size) << 16); 697 698 /* Set physical address of the DMA buffer */ 699 port = dev->port[P16X_PLAY]; 700 paddr = port->buf_paddr; 701 chunksz = port->buf_frames * 4; 702 write_reg(dev, PFBA, 0, paddr); 703 write_reg(dev, PFBS, 0, chunksz << 16); 704 paddr += chunksz; 705 write_reg(dev, PFBA, 1, paddr); 706 write_reg(dev, PFBS, 1, chunksz << 16); 707 paddr += chunksz; 708 write_reg(dev, PFBA, 2, paddr); 709 write_reg(dev, PFBS, 2, chunksz << 16); 710 711 OUTL(dev, 0x1080, GPIO); /* GPIO */ 712 /* Clear any pending interrupts */ 713 OUTL(dev, INTR_ALL, IP); 714 OUTL(dev, 0, IE); 715 OUTL(dev, 0x9, HC); /* Enable audio */ 716 } 717 718 int 719 p16x_setup_intrs(p16x_dev_t *dev) 720 { 721 uint_t ipri; 722 int actual; 723 int rv; 724 ddi_intr_handle_t ih[1]; 725 726 rv = ddi_intr_alloc(dev->dip, ih, DDI_INTR_TYPE_FIXED, 727 0, 1, &actual, DDI_INTR_ALLOC_STRICT); 728 if ((rv != DDI_SUCCESS) || (actual != 1)) { 729 audio_dev_warn(dev->adev, 730 "Can't alloc interrupt handle (rv %d actual %d)", 731 rv, actual); 732 return (DDI_FAILURE); 733 } 734 735 if (ddi_intr_get_pri(ih[0], &ipri) != DDI_SUCCESS) { 736 audio_dev_warn(dev->adev, "Can't get interrupt priority"); 737 (void) ddi_intr_free(ih[0]); 738 return (DDI_FAILURE); 739 } 740 741 if (ddi_intr_add_handler(ih[0], p16x_intr, dev, NULL) != 742 DDI_SUCCESS) { 743 audio_dev_warn(dev->adev, "Can't add interrupt handler"); 744 (void) ddi_intr_free(ih[0]); 745 return (DDI_FAILURE); 746 } 747 748 dev->ih = ih[0]; 749 mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri)); 750 mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(ipri)); 751 return (DDI_SUCCESS); 752 } 753 754 int 755 p16x_attach(dev_info_t *dip) 756 { 757 uint16_t vendor, device; 758 p16x_dev_t *dev; 759 ddi_acc_handle_t pcih; 760 761 dev = kmem_zalloc(sizeof (*dev), KM_SLEEP); 762 dev->dip = dip; 763 ddi_set_driver_private(dip, dev); 764 765 /* we don't support high level interrupts in the driver */ 766 if (ddi_intr_hilevel(dip, 0) != 0) { 767 cmn_err(CE_WARN, 768 "!%s%d: unsupported high level interrupt", 769 ddi_driver_name(dip), ddi_get_instance(dip)); 770 return (DDI_FAILURE); 771 } 772 773 if (ddi_get_iblock_cookie(dip, 0, &dev->iblock) != DDI_SUCCESS) { 774 cmn_err(CE_WARN, 775 "!%s%d: cannot get iblock cookie", 776 ddi_driver_name(dip), ddi_get_instance(dip)); 777 kmem_free(dev, sizeof (*dev)); 778 return (DDI_FAILURE); 779 } 780 mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, dev->iblock); 781 mutex_init(&dev->low_mutex, NULL, MUTEX_DRIVER, dev->iblock); 782 783 if ((dev->adev = audio_dev_alloc(dip, 0)) == NULL) { 784 cmn_err(CE_WARN, "audio_dev_alloc failed"); 785 goto error; 786 } 787 788 if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) { 789 audio_dev_warn(dev->adev, "pci_config_setup failed"); 790 goto error; 791 } 792 dev->pcih = pcih; 793 794 vendor = pci_config_get16(pcih, PCI_CONF_VENID); 795 device = pci_config_get16(pcih, PCI_CONF_DEVID); 796 if (vendor != CREATIVE_VENDOR_ID || 797 device != SB_P16X_ID) { 798 audio_dev_warn(dev->adev, "Hardware not recognized " 799 "(vendor=%x, dev=%x)", vendor, device); 800 goto error; 801 } 802 803 /* set PCI command register */ 804 pci_config_put16(pcih, PCI_CONF_COMM, 805 pci_config_get16(pcih, PCI_CONF_COMM) | 806 PCI_COMM_MAE | PCI_COMM_IO); 807 808 809 if ((ddi_regs_map_setup(dip, 1, &dev->base, 0, 0, &dev_attr, 810 &dev->regsh)) != DDI_SUCCESS) { 811 audio_dev_warn(dev->adev, "failed to map registers"); 812 goto error; 813 } 814 815 audio_dev_set_description(dev->adev, "Creative Sound Blaster Live!"); 816 audio_dev_set_version(dev->adev, "SBO200"); 817 818 if ((p16x_alloc_port(dev, P16X_PLAY) != DDI_SUCCESS) || 819 (p16x_alloc_port(dev, P16X_REC) != DDI_SUCCESS)) { 820 goto error; 821 } 822 823 p16x_hwinit(dev); 824 825 /* set up the interrupt handler */ 826 if (p16x_setup_intrs(dev) != DDI_SUCCESS) { 827 goto error; 828 } 829 830 /* Enable PCI interrupts */ 831 OUTL(dev, INTR_PCI, IE); 832 833 dev->ac97 = ac97_allocate(dev->adev, dip, 834 p16x_read_ac97, p16x_write_ac97, dev); 835 if (dev->ac97 == NULL) { 836 audio_dev_warn(dev->adev, "failed to allocate ac97 handle"); 837 goto error; 838 } 839 840 ac97_probe_controls(dev->ac97); 841 842 /* remove the AC'97 controls we don't want to expose */ 843 for (int i = 0; p16x_remove_ac97[i]; i++) { 844 ac97_ctrl_t *ctrl; 845 ctrl = ac97_control_find(dev->ac97, p16x_remove_ac97[i]); 846 if (ctrl != NULL) { 847 ac97_control_unregister(ctrl); 848 } 849 } 850 851 ac97_register_controls(dev->ac97); 852 853 /* set up kernel statistics */ 854 if ((dev->ksp = kstat_create(P16X_NAME, ddi_get_instance(dip), 855 P16X_NAME, "controller", KSTAT_TYPE_INTR, 1, 856 KSTAT_FLAG_PERSISTENT)) != NULL) { 857 kstat_install(dev->ksp); 858 } 859 860 if (audio_dev_register(dev->adev) != DDI_SUCCESS) { 861 audio_dev_warn(dev->adev, "unable to register with framework"); 862 goto error; 863 } 864 865 (void) ddi_intr_enable(dev->ih); 866 ddi_report_dev(dip); 867 868 return (DDI_SUCCESS); 869 870 error: 871 p16x_destroy(dev); 872 return (DDI_FAILURE); 873 } 874 875 int 876 p16x_resume(dev_info_t *dip) 877 { 878 p16x_dev_t *dev; 879 880 dev = ddi_get_driver_private(dip); 881 882 p16x_hwinit(dev); 883 884 /* allow ac97 operations again */ 885 ac97_resume(dev->ac97); 886 887 mutex_enter(&dev->mutex); 888 dev->suspended = B_FALSE; 889 890 for (int i = 0; i < P16X_NUM_PORT; i++) { 891 892 p16x_port_t *port = dev->port[i]; 893 894 if (port->engine != NULL) 895 audio_engine_reset(port->engine); 896 897 /* reset the port */ 898 p16x_init_port(port); 899 900 if (port->started) { 901 p16x_start_port(port); 902 } else { 903 p16x_stop_port(port); 904 } 905 } 906 mutex_exit(&dev->mutex); 907 return (DDI_SUCCESS); 908 } 909 910 int 911 p16x_detach(p16x_dev_t *dev) 912 { 913 if (audio_dev_unregister(dev->adev) != DDI_SUCCESS) 914 return (DDI_FAILURE); 915 916 p16x_destroy(dev); 917 return (DDI_SUCCESS); 918 } 919 920 int 921 p16x_suspend(p16x_dev_t *dev) 922 { 923 ac97_suspend(dev->ac97); 924 925 mutex_enter(&dev->mutex); 926 for (int i = 0; i < P16X_NUM_PORT; i++) { 927 928 p16x_port_t *port = dev->port[i]; 929 p16x_stop_port(port); 930 } 931 932 write_reg(dev, SA, 0, 0); 933 OUTL(dev, 0x00, IE); /* Interrupt disable */ 934 OUTL(dev, 0x01, HC); 935 936 dev->suspended = B_TRUE; 937 mutex_exit(&dev->mutex); 938 return (DDI_SUCCESS); 939 } 940 941 static int p16x_ddi_attach(dev_info_t *, ddi_attach_cmd_t); 942 static int p16x_ddi_detach(dev_info_t *, ddi_detach_cmd_t); 943 static int p16x_ddi_quiesce(dev_info_t *); 944 945 static struct dev_ops p16x_dev_ops = { 946 DEVO_REV, /* rev */ 947 0, /* refcnt */ 948 NULL, /* getinfo */ 949 nulldev, /* identify */ 950 nulldev, /* probe */ 951 p16x_ddi_attach, /* attach */ 952 p16x_ddi_detach, /* detach */ 953 nodev, /* reset */ 954 NULL, /* cb_ops */ 955 NULL, /* bus_ops */ 956 NULL, /* power */ 957 p16x_ddi_quiesce, /* quiesce */ 958 }; 959 960 static struct modldrv p16x_modldrv = { 961 &mod_driverops, /* drv_modops */ 962 "Creative P16X Audio", /* linkinfo */ 963 &p16x_dev_ops, /* dev_ops */ 964 }; 965 966 static struct modlinkage modlinkage = { 967 MODREV_1, 968 { &p16x_modldrv, NULL } 969 }; 970 971 int 972 _init(void) 973 { 974 int rv; 975 976 audio_init_ops(&p16x_dev_ops, P16X_NAME); 977 if ((rv = mod_install(&modlinkage)) != 0) { 978 audio_fini_ops(&p16x_dev_ops); 979 } 980 return (rv); 981 } 982 983 int 984 _fini(void) 985 { 986 int rv; 987 988 if ((rv = mod_remove(&modlinkage)) == 0) { 989 audio_fini_ops(&p16x_dev_ops); 990 } 991 return (rv); 992 } 993 994 int 995 _info(struct modinfo *modinfop) 996 { 997 return (mod_info(&modlinkage, modinfop)); 998 } 999 1000 int 1001 p16x_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1002 { 1003 switch (cmd) { 1004 case DDI_ATTACH: 1005 return (p16x_attach(dip)); 1006 1007 case DDI_RESUME: 1008 return (p16x_resume(dip)); 1009 1010 default: 1011 return (DDI_FAILURE); 1012 } 1013 } 1014 1015 int 1016 p16x_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 1017 { 1018 p16x_dev_t *dev; 1019 1020 dev = ddi_get_driver_private(dip); 1021 1022 switch (cmd) { 1023 case DDI_DETACH: 1024 return (p16x_detach(dev)); 1025 1026 case DDI_SUSPEND: 1027 return (p16x_suspend(dev)); 1028 1029 default: 1030 return (DDI_FAILURE); 1031 } 1032 } 1033 1034 int 1035 p16x_ddi_quiesce(dev_info_t *dip) 1036 { 1037 p16x_dev_t *dev; 1038 1039 dev = ddi_get_driver_private(dip); 1040 1041 for (int i = 0; i < P16X_NUM_PORT; i++) { 1042 1043 p16x_port_t *port = dev->port[i]; 1044 p16x_stop_port(port); 1045 } 1046 1047 write_reg(dev, SA, 0, 0); 1048 OUTL(dev, 0x00, IE); /* Interrupt disable */ 1049 OUTL(dev, 0x01, HC); 1050 1051 return (DDI_SUCCESS); 1052 } 1053