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 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Purpose: Driver for the VIA8233/8235 AC97 audio controller 29 */ 30 /* 31 * This file is part of Open Sound System 32 * 33 * Copyright (C) 4Front Technologies 1996-2008. 34 * 35 * This software is released under CDDL 1.0 source license. 36 * See the COPYING file included in the main directory of this source 37 * distribution for the license terms and conditions. 38 */ 39 40 #include <sys/types.h> 41 #include <sys/modctl.h> 42 #include <sys/kmem.h> 43 #include <sys/conf.h> 44 #include <sys/ddi.h> 45 #include <sys/sunddi.h> 46 #include <sys/pci.h> 47 #include <sys/note.h> 48 #include <sys/audio/audio_driver.h> 49 #include <sys/audio/ac97.h> 50 51 #include "audiovia823x.h" 52 53 static struct ddi_device_acc_attr dev_attr = { 54 DDI_DEVICE_ATTR_V0, 55 DDI_STRUCTURE_LE_ACC, 56 DDI_STRICTORDER_ACC 57 }; 58 59 static struct ddi_device_acc_attr buf_attr = { 60 DDI_DEVICE_ATTR_V0, 61 DDI_NEVERSWAP_ACC, 62 DDI_STRICTORDER_ACC 63 }; 64 65 static ddi_dma_attr_t dma_attr_sgd = { 66 DMA_ATTR_V0, /* version number */ 67 0x00000000, /* low DMA address range */ 68 0xffffffff, /* high DMA address range */ 69 0x0000ffff, /* DMA counter register */ 70 8, /* DMA address alignment */ 71 0x3c, /* DMA burstsizes */ 72 8, /* min effective DMA size */ 73 0xffffffff, /* max DMA xfer size */ 74 0x00000fff, /* segment boundary */ 75 1, /* s/g length */ 76 8, /* granularity of device */ 77 0 /* Bus specific DMA flags */ 78 }; 79 80 static ddi_dma_attr_t dma_attr_buf = { 81 DMA_ATTR_V0, /* version number */ 82 0x00000000, /* low DMA address range */ 83 0xffffffff, /* high DMA address range */ 84 0x0001fffe, /* DMA counter register */ 85 4, /* DMA address alignment */ 86 0x3c, /* DMA burstsizes */ 87 4, /* min effective DMA size */ 88 0x0001ffff, /* max DMA xfer size */ 89 0x0001ffff, /* segment boundary */ 90 1, /* s/g length */ 91 4, /* granularity of device */ 92 0 /* Bus specific DMA flags */ 93 }; 94 95 static int auvia_attach(dev_info_t *); 96 static int auvia_resume(dev_info_t *); 97 static int auvia_detach(auvia_devc_t *); 98 static int auvia_suspend(auvia_devc_t *); 99 100 static int auvia_open(void *, int, unsigned *, caddr_t *); 101 static void auvia_close(void *); 102 static int auvia_start(void *); 103 static void auvia_stop(void *); 104 static int auvia_format(void *); 105 static int auvia_channels(void *); 106 static int auvia_rate(void *); 107 static uint64_t auvia_count(void *); 108 static void auvia_sync(void *, unsigned); 109 110 static uint16_t auvia_read_ac97(void *, uint8_t); 111 static void auvia_write_ac97(void *, uint8_t, uint16_t); 112 static int auvia_alloc_port(auvia_devc_t *, int); 113 static void auvia_reset_input(auvia_portc_t *); 114 static void auvia_reset_output(auvia_portc_t *); 115 static void auvia_destroy(auvia_devc_t *); 116 static void auvia_hwinit(auvia_devc_t *); 117 118 static audio_engine_ops_t auvia_engine_ops = { 119 AUDIO_ENGINE_VERSION, 120 auvia_open, 121 auvia_close, 122 auvia_start, 123 auvia_stop, 124 auvia_count, 125 auvia_format, 126 auvia_channels, 127 auvia_rate, 128 auvia_sync, 129 NULL, 130 NULL, 131 NULL, 132 }; 133 134 static uint16_t 135 auvia_read_ac97(void *arg, uint8_t index) 136 { 137 auvia_devc_t *devc = arg; 138 uint32_t val = 0; 139 int i; 140 141 val = ((uint32_t)index << 16) | CODEC_RD; 142 OUTL(devc, devc->base + REG_CODEC, val); 143 drv_usecwait(100); 144 145 /* Check AC CODEC access time out */ 146 for (i = 0; i < CODEC_TIMEOUT_COUNT; i++) { 147 148 /* if send command over, break */ 149 if (INL(devc, devc->base + REG_CODEC) & CODEC_STA_VALID) 150 break; 151 drv_usecwait(50); 152 } 153 154 if (i == CODEC_TIMEOUT_COUNT) { 155 goto failed; 156 } 157 158 /* Check if Index still ours? If yes, return data, else return FAIL */ 159 val = INL(devc, devc->base + REG_CODEC); 160 OUTB(devc, devc->base + REG_CODEC + 3, 0x02); 161 if (((val & CODEC_INDEX) >> 16) == index) { 162 return (val & CODEC_DATA); 163 } 164 165 failed: 166 return (0xffff); 167 } 168 169 static void 170 auvia_write_ac97(void *arg, uint8_t index, uint16_t data) 171 { 172 auvia_devc_t *devc = arg; 173 uint32_t val = 0; 174 int i = 0; 175 176 val = ((uint32_t)index << 16) | data | CODEC_WR; 177 OUTL(devc, devc->base + REG_CODEC, val); 178 drv_usecwait(100); 179 180 /* Check AC CODEC access time out */ 181 for (i = 0; i < CODEC_TIMEOUT_COUNT; i++) { 182 /* if send command over, break */ 183 if (!(INL(devc, devc->base + REG_CODEC) & CODEC_IN_CMD)) 184 break; 185 drv_usecwait(50); 186 } 187 188 } 189 190 /* 191 * Audio routines 192 */ 193 194 int 195 auvia_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp) 196 { 197 auvia_portc_t *portc = arg; 198 199 _NOTE(ARGUNUSED(flag)); 200 201 portc->count = 0; 202 *nframesp = portc->nframes; 203 *bufp = portc->buf_kaddr; 204 205 return (0); 206 } 207 208 void 209 auvia_close(void *arg) 210 { 211 _NOTE(ARGUNUSED(arg)); 212 } 213 214 int 215 auvia_start(void *arg) 216 { 217 auvia_portc_t *portc = arg; 218 auvia_devc_t *devc = portc->devc; 219 220 portc->reset(portc); 221 OUTB(devc, portc->base + OFF_CTRL, CTRL_START | CTRL_AUTOSTART); 222 return (0); 223 } 224 225 void 226 auvia_stop(void *arg) 227 { 228 auvia_portc_t *portc = arg; 229 auvia_devc_t *devc = portc->devc; 230 231 OUTB(devc, portc->base + OFF_CTRL, CTRL_TERMINATE); 232 } 233 234 int 235 auvia_format(void *arg) 236 { 237 _NOTE(ARGUNUSED(arg)); 238 239 return (AUDIO_FORMAT_S16_LE); 240 } 241 242 int 243 auvia_channels(void *arg) 244 { 245 auvia_portc_t *portc = arg; 246 247 return (portc->nchan); 248 } 249 250 int 251 auvia_rate(void *arg) 252 { 253 _NOTE(ARGUNUSED(arg)); 254 255 return (48000); 256 } 257 258 void 259 auvia_sync(void *arg, unsigned nframes) 260 { 261 auvia_portc_t *portc = arg; 262 _NOTE(ARGUNUSED(nframes)); 263 264 (void) ddi_dma_sync(portc->buf_dmah, 0, 0, portc->syncdir); 265 } 266 267 uint64_t 268 auvia_count(void *arg) 269 { 270 auvia_portc_t *portc = arg; 271 auvia_devc_t *devc = portc->devc; 272 uint32_t pos; 273 uint32_t n; 274 275 pos = INL(devc, portc->base + OFF_COUNT); 276 pos &= 0xffffff; 277 pos /= (sizeof (int16_t) * portc->nchan); 278 279 if (pos >= portc->pos) { 280 n = portc->nframes - (pos - portc->pos); 281 } else { 282 n = portc->pos - pos; 283 } 284 portc->pos = pos; 285 portc->count += n; 286 287 return (portc->count); 288 } 289 290 291 /* private implementation bits */ 292 293 void 294 auvia_reset_output(auvia_portc_t *portc) 295 { 296 auvia_devc_t *devc = portc->devc; 297 uint32_t cmap; 298 299 portc->pos = 0; 300 301 OUTB(devc, portc->base + OFF_CTRL, CTRL_TERMINATE); /* Stop */ 302 OUTL(devc, portc->base + OFF_DMA, portc->sgd_paddr); 303 304 OUTB(devc, portc->base + OFF_PLAYFMT, 305 PLAYFMT_16BIT | (portc->nchan << 4)); 306 307 /* Select channel assignment - not valid for 8233A */ 308 if (devc->chip_type != CHIP_8233A) { 309 /* 310 * Undocumented slot mapping table: 311 * 312 * slot 3 = 1 (left) 313 * slot 4 = 2 (right) 314 * slot 6 = 5 (center) 315 * slot 9 = 6 (lfe) 316 * slot 7 = 3 (left rear) 317 * slot 8 = 4 (right rear) 318 */ 319 switch (portc->nchan) { 320 case 1: 321 cmap = (1 << 0) | (1 << 4); 322 break; 323 case 2: 324 cmap = (1 << 0) | (2 << 4); 325 break; 326 case 4: 327 cmap = (1 << 0) | (2 << 4) | (3 << 8) | (4 << 12); 328 break; 329 case 6: 330 cmap = (1 << 0) | (2 << 4) | 331 (5 << 8) | (6 << 12) | (3 << 16) | (4 << 20); 332 break; 333 default: 334 cmap = 0; 335 break; 336 } 337 OUTL(devc, portc->base + OFF_CHANNELS, cmap | 0xFF000000U); 338 } 339 } 340 341 static void 342 auvia_reset_input(auvia_portc_t *portc) 343 { 344 auvia_devc_t *devc = portc->devc; 345 uint32_t fmt; 346 347 portc->pos = 0; 348 349 OUTB(devc, portc->base + OFF_CTRL, CTRL_TERMINATE); /* Stop */ 350 OUTL(devc, portc->base + OFF_DMA, portc->sgd_paddr); 351 352 fmt = RECFMT_STEREO | RECFMT_16BIT; 353 354 if (devc->chip_type != CHIP_8233A) { 355 fmt |= RECFMT_48K; 356 } 357 fmt |= (0xffU << 24); 358 OUTB(devc, portc->base + OFF_RECFIFO, RECFIFO_ENABLE); 359 OUTL(devc, portc->base + OFF_RECFMT, fmt); 360 } 361 362 int 363 auvia_alloc_port(auvia_devc_t *devc, int num) 364 { 365 auvia_portc_t *portc; 366 size_t len; 367 ddi_dma_cookie_t cookie; 368 uint_t count; 369 int dir; 370 unsigned caps; 371 audio_dev_t *adev; 372 uint32_t *desc; 373 374 adev = devc->adev; 375 portc = kmem_zalloc(sizeof (*portc), KM_SLEEP); 376 devc->portc[num] = portc; 377 portc->devc = devc; 378 379 switch (num) { 380 case AUVIA_REC_SGD_NUM: 381 portc->base = devc->base + REG_RECBASE; 382 portc->syncdir = DDI_DMA_SYNC_FORKERNEL; 383 portc->nchan = 2; 384 portc->reset = auvia_reset_input; 385 caps = ENGINE_INPUT_CAP; 386 dir = DDI_DMA_READ; 387 break; 388 case AUVIA_PLAY_SGD_NUM: 389 portc->base = devc->base + REG_PLAYBASE; 390 portc->syncdir = DDI_DMA_SYNC_FORDEV; 391 portc->nchan = 6; 392 portc->reset = auvia_reset_output; 393 caps = ENGINE_OUTPUT_CAP; 394 dir = DDI_DMA_WRITE; 395 break; 396 default: 397 return (DDI_FAILURE); 398 } 399 400 /* make sure port is shut down */ 401 OUTB(portc->devc, portc->base + OFF_CTRL, CTRL_TERMINATE); 402 403 portc->nframes = 4096; 404 portc->buf_size = portc->nframes * portc->nchan * sizeof (int16_t); 405 406 /* first allocate up space for SGD list */ 407 if (ddi_dma_alloc_handle(devc->dip, &dma_attr_sgd, 408 DDI_DMA_SLEEP, NULL, &portc->sgd_dmah) != DDI_SUCCESS) { 409 audio_dev_warn(adev, "failed to allocate SGD handle"); 410 return (DDI_FAILURE); 411 } 412 413 if (ddi_dma_mem_alloc(portc->sgd_dmah, 2 * sizeof (uint32_t), &dev_attr, 414 DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, &portc->sgd_kaddr, 415 &len, &portc->sgd_acch) != DDI_SUCCESS) { 416 audio_dev_warn(adev, "failed to allocate SGD memory"); 417 return (DDI_FAILURE); 418 } 419 420 if (ddi_dma_addr_bind_handle(portc->sgd_dmah, NULL, 421 portc->sgd_kaddr, len, DDI_DMA_CONSISTENT | DDI_DMA_WRITE, 422 DDI_DMA_SLEEP, NULL, &cookie, &count) != DDI_SUCCESS) { 423 audio_dev_warn(adev, "failed binding SGD DMA handle"); 424 return (DDI_FAILURE); 425 } 426 portc->sgd_paddr = cookie.dmac_address; 427 428 /* now buffers */ 429 if (ddi_dma_alloc_handle(devc->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL, 430 &portc->buf_dmah) != DDI_SUCCESS) { 431 audio_dev_warn(adev, "failed to allocate BUF handle"); 432 return (DDI_FAILURE); 433 } 434 435 if (ddi_dma_mem_alloc(portc->buf_dmah, portc->buf_size, 436 &buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 437 &portc->buf_kaddr, &len, &portc->buf_acch) != DDI_SUCCESS) { 438 audio_dev_warn(adev, "failed to allocate BUF memory"); 439 return (DDI_FAILURE); 440 } 441 442 if (ddi_dma_addr_bind_handle(portc->buf_dmah, NULL, portc->buf_kaddr, 443 len, DDI_DMA_CONSISTENT | dir, DDI_DMA_SLEEP, NULL, &cookie, 444 &count) != DDI_SUCCESS) { 445 audio_dev_warn(adev, "failed binding BUF DMA handle"); 446 return (DDI_FAILURE); 447 } 448 portc->buf_paddr = cookie.dmac_address; 449 450 /* now wire up descriptor -- just one */ 451 desc = (void *)portc->sgd_kaddr; 452 453 ddi_put32(portc->sgd_acch, desc++, portc->buf_paddr); 454 ddi_put32(portc->sgd_acch, desc++, AUVIA_SGD_EOL | portc->buf_size); 455 456 (void) ddi_dma_sync(portc->sgd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV); 457 458 portc->engine = audio_engine_alloc(&auvia_engine_ops, caps); 459 if (portc->engine == NULL) { 460 audio_dev_warn(adev, "audio_engine_alloc failed"); 461 return (DDI_FAILURE); 462 } 463 464 audio_engine_set_private(portc->engine, portc); 465 audio_dev_add_engine(adev, portc->engine); 466 467 return (DDI_SUCCESS); 468 } 469 470 void 471 auvia_destroy(auvia_devc_t *devc) 472 { 473 for (int i = 0; i < AUVIA_NUM_PORTC; i++) { 474 auvia_portc_t *portc = devc->portc[i]; 475 if (!portc) 476 continue; 477 if (portc->engine) { 478 audio_dev_remove_engine(devc->adev, portc->engine); 479 audio_engine_free(portc->engine); 480 } 481 if (portc->sgd_paddr) { 482 (void) ddi_dma_unbind_handle(portc->sgd_dmah); 483 } 484 if (portc->sgd_acch) { 485 ddi_dma_mem_free(&portc->sgd_acch); 486 } 487 if (portc->sgd_dmah) { 488 ddi_dma_free_handle(&portc->sgd_dmah); 489 } 490 if (portc->buf_paddr) { 491 (void) ddi_dma_unbind_handle(portc->buf_dmah); 492 } 493 if (portc->buf_acch) { 494 ddi_dma_mem_free(&portc->buf_acch); 495 } 496 if (portc->buf_dmah) { 497 ddi_dma_free_handle(&portc->buf_dmah); 498 } 499 kmem_free(portc, sizeof (*portc)); 500 } 501 502 if (devc->ac97 != NULL) { 503 ac97_free(devc->ac97); 504 } 505 if (devc->adev != NULL) { 506 audio_dev_free(devc->adev); 507 } 508 if (devc->regsh != NULL) { 509 ddi_regs_map_free(&devc->regsh); 510 } 511 if (devc->pcih != NULL) { 512 pci_config_teardown(&devc->pcih); 513 } 514 kmem_free(devc, sizeof (*devc)); 515 } 516 517 void 518 auvia_hwinit(auvia_devc_t *devc) 519 { 520 ddi_acc_handle_t pcih = devc->pcih; 521 uint32_t val; 522 523 val = pci_config_get32(pcih, AUVIA_PCICFG); 524 /* we want to disable all legacy */ 525 val &= ~AUVIA_PCICFG_LEGACY; 526 val &= ~(AUVIA_PCICFG_FMEN | AUVIA_PCICFG_SBEN); 527 528 /* enable AC'97 link and clear the reset bit */ 529 val |= (AUVIA_PCICFG_ACLINKEN | AUVIA_PCICFG_NRST); 530 /* disable SRC (we won't use it) */ 531 val &= ~AUVIA_PCICFG_SRCEN; 532 /* enable the SGD engines */ 533 val |= AUVIA_PCICFG_SGDEN; 534 535 pci_config_put32(pcih, AUVIA_PCICFG, val); 536 537 drv_usecwait(10); 538 } 539 540 int 541 auvia_attach(dev_info_t *dip) 542 { 543 uint8_t pci_revision; 544 uint16_t pci_command, vendor, device; 545 auvia_devc_t *devc; 546 ddi_acc_handle_t pcih; 547 const char *version; 548 549 devc = kmem_zalloc(sizeof (*devc), KM_SLEEP); 550 devc->dip = dip; 551 ddi_set_driver_private(dip, devc); 552 553 if ((devc->adev = audio_dev_alloc(dip, 0)) == NULL) { 554 cmn_err(CE_WARN, "audio_dev_alloc failed"); 555 goto error; 556 } 557 558 if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) { 559 audio_dev_warn(devc->adev, "pci_config_setup failed"); 560 goto error; 561 } 562 devc->pcih = pcih; 563 564 vendor = pci_config_get16(pcih, PCI_CONF_VENID); 565 device = pci_config_get16(pcih, PCI_CONF_DEVID); 566 if ((vendor != VIA_VENDOR_ID) || (device != VIA_8233_ID && 567 device != VIA_8233A_ID)) { 568 audio_dev_warn(devc->adev, "Hardware not recognized " 569 "(vendor=%x, dev=%x)", vendor, device); 570 goto error; 571 } 572 573 devc->chip_type = CHIP_8233; 574 devc->chip_name = "VIA VT8233"; 575 version = "8233"; 576 577 pci_revision = pci_config_get8(pcih, PCI_CONF_REVID); 578 579 if (pci_revision == 0x50) { 580 devc->chip_name = "VIA VT8235"; 581 version = "8235"; 582 } 583 584 if (pci_revision == 0x60) { 585 devc->chip_name = "VIA VT8237"; 586 version = "8237"; 587 } 588 589 if ((device == VIA_8233A_ID) || 590 (device == VIA_8233_ID && pci_revision == 0x40)) { 591 devc->chip_type = CHIP_8233A; 592 devc->chip_name = "VIA VT8233A"; 593 version = "8233A"; 594 } 595 audio_dev_set_description(devc->adev, devc->chip_name); 596 audio_dev_set_version(devc->adev, version); 597 598 pci_command = pci_config_get16(pcih, PCI_CONF_COMM); 599 pci_command |= PCI_COMM_ME | PCI_COMM_IO | PCI_COMM_MAE; 600 pci_config_put16(pcih, PCI_CONF_COMM, pci_command); 601 602 if ((ddi_regs_map_setup(dip, 1, &devc->base, 0, 0, &dev_attr, 603 &devc->regsh)) != DDI_SUCCESS) { 604 audio_dev_warn(devc->adev, "failed to map registers"); 605 goto error; 606 } 607 608 auvia_hwinit(devc); 609 610 if ((auvia_alloc_port(devc, AUVIA_PLAY_SGD_NUM) != DDI_SUCCESS) || 611 (auvia_alloc_port(devc, AUVIA_REC_SGD_NUM) != DDI_SUCCESS)) { 612 goto error; 613 } 614 615 devc->ac97 = ac97_alloc(dip, auvia_read_ac97, auvia_write_ac97, devc); 616 if (devc->ac97 == NULL) { 617 audio_dev_warn(devc->adev, "failed to allocate ac97 handle"); 618 goto error; 619 } 620 621 if (ac97_init(devc->ac97, devc->adev) != DDI_SUCCESS) { 622 audio_dev_warn(devc->adev, "failed to init ac97"); 623 goto error; 624 } 625 626 if (audio_dev_register(devc->adev) != DDI_SUCCESS) { 627 audio_dev_warn(devc->adev, "unable to register with framework"); 628 goto error; 629 } 630 631 ddi_report_dev(dip); 632 633 return (DDI_SUCCESS); 634 635 error: 636 auvia_destroy(devc); 637 return (DDI_FAILURE); 638 } 639 640 int 641 auvia_resume(dev_info_t *dip) 642 { 643 auvia_devc_t *devc; 644 645 devc = ddi_get_driver_private(dip); 646 647 auvia_hwinit(devc); 648 649 ac97_reset(devc->ac97); 650 651 audio_dev_resume(devc->adev); 652 653 return (DDI_SUCCESS); 654 } 655 656 657 int 658 auvia_detach(auvia_devc_t *devc) 659 { 660 if (audio_dev_unregister(devc->adev) != DDI_SUCCESS) 661 return (DDI_FAILURE); 662 663 auvia_destroy(devc); 664 return (DDI_SUCCESS); 665 } 666 667 int 668 auvia_suspend(auvia_devc_t *devc) 669 { 670 audio_dev_suspend(devc->adev); 671 672 return (DDI_SUCCESS); 673 } 674 675 static int auvia_ddi_attach(dev_info_t *, ddi_attach_cmd_t); 676 static int auvia_ddi_detach(dev_info_t *, ddi_detach_cmd_t); 677 static int auvia_ddi_quiesce(dev_info_t *); 678 679 static struct dev_ops auvia_dev_ops = { 680 DEVO_REV, /* rev */ 681 0, /* refcnt */ 682 NULL, /* getinfo */ 683 nulldev, /* identify */ 684 nulldev, /* probe */ 685 auvia_ddi_attach, /* attach */ 686 auvia_ddi_detach, /* detach */ 687 nodev, /* reset */ 688 NULL, /* cb_ops */ 689 NULL, /* bus_ops */ 690 NULL, /* power */ 691 auvia_ddi_quiesce, /* quiesce */ 692 }; 693 694 static struct modldrv auvia_modldrv = { 695 &mod_driverops, /* drv_modops */ 696 "Via 823x Audio", /* linkinfo */ 697 &auvia_dev_ops, /* dev_ops */ 698 }; 699 700 static struct modlinkage modlinkage = { 701 MODREV_1, 702 { &auvia_modldrv, NULL } 703 }; 704 705 int 706 _init(void) 707 { 708 int rv; 709 710 audio_init_ops(&auvia_dev_ops, AUVIA_NAME); 711 if ((rv = mod_install(&modlinkage)) != 0) { 712 audio_fini_ops(&auvia_dev_ops); 713 } 714 return (rv); 715 } 716 717 int 718 _fini(void) 719 { 720 int rv; 721 722 if ((rv = mod_remove(&modlinkage)) == 0) { 723 audio_fini_ops(&auvia_dev_ops); 724 } 725 return (rv); 726 } 727 728 int 729 _info(struct modinfo *modinfop) 730 { 731 return (mod_info(&modlinkage, modinfop)); 732 } 733 734 int 735 auvia_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 736 { 737 switch (cmd) { 738 case DDI_ATTACH: 739 return (auvia_attach(dip)); 740 741 case DDI_RESUME: 742 return (auvia_resume(dip)); 743 744 default: 745 return (DDI_FAILURE); 746 } 747 } 748 749 int 750 auvia_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 751 { 752 auvia_devc_t *devc; 753 754 devc = ddi_get_driver_private(dip); 755 756 switch (cmd) { 757 case DDI_DETACH: 758 return (auvia_detach(devc)); 759 760 case DDI_SUSPEND: 761 return (auvia_suspend(devc)); 762 763 default: 764 return (DDI_FAILURE); 765 } 766 } 767 768 int 769 auvia_ddi_quiesce(dev_info_t *dip) 770 { 771 auvia_devc_t *devc; 772 773 devc = ddi_get_driver_private(dip); 774 775 for (int i = 0; i < AUVIA_NUM_PORTC; i++) { 776 777 auvia_portc_t *portc = devc->portc[i]; 778 OUTB(devc, portc->base + OFF_CTRL, CTRL_TERMINATE); 779 } 780 return (DDI_SUCCESS); 781 } 782