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 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 *, 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_destroy(p16x_dev_t *); 113 static void p16x_hwinit(p16x_dev_t *); 114 115 static audio_engine_ops_t p16x_engine_ops = { 116 AUDIO_ENGINE_VERSION, 117 p16x_open, 118 p16x_close, 119 p16x_start, 120 p16x_stop, 121 p16x_count, 122 p16x_format, 123 p16x_channels, 124 p16x_rate, 125 p16x_sync, 126 NULL, 127 p16x_chinfo, 128 NULL 129 }; 130 131 static unsigned int 132 read_reg(p16x_dev_t *dev, int reg, int chn) 133 { 134 unsigned int val; 135 136 mutex_enter(&dev->mutex); 137 OUTL(dev, (reg << 16) | (chn & 0xffff), PTR); /* Pointer */ 138 val = INL(dev, DR); /* Data */ 139 mutex_exit(&dev->mutex); 140 141 return (val); 142 } 143 144 static void 145 write_reg(p16x_dev_t *dev, int reg, int chn, unsigned int value) 146 { 147 148 mutex_enter(&dev->mutex); 149 OUTL(dev, (reg << 16) | (chn & 0xffff), PTR); /* Pointer */ 150 OUTL(dev, value, DR); /* Data */ 151 mutex_exit(&dev->mutex); 152 } 153 154 static void 155 set_reg_bits(p16x_dev_t *dev, int reg, int chn, unsigned int mask) 156 { 157 unsigned int val; 158 mutex_enter(&dev->mutex); 159 OUTL(dev, (reg << 16) | (chn & 0xffff), PTR); /* Pointer */ 160 val = INL(dev, DR); /* Data */ 161 val |= mask; 162 OUTL(dev, val, DR); /* Data */ 163 mutex_exit(&dev->mutex); 164 } 165 166 static void 167 clear_reg_bits(p16x_dev_t *dev, int reg, int chn, unsigned int mask) 168 { 169 unsigned int val; 170 mutex_enter(&dev->mutex); 171 OUTL(dev, (reg << 16) | (chn & 0xffff), PTR); /* Pointer */ 172 val = INL(dev, DR); /* Data */ 173 val &= ~(mask); 174 OUTL(dev, val, DR); /* Data */ 175 mutex_exit(&dev->mutex); 176 } 177 178 static uint16_t 179 p16x_read_ac97(void *arg, uint8_t index) 180 { 181 p16x_dev_t *dev = arg; 182 uint16_t value; 183 int i; 184 185 OUTB(dev, index, AC97A); 186 for (i = 0; i < 10000; i++) 187 if (INB(dev, AC97A) & 0x80) 188 break; 189 value = INW(dev, AC97D); 190 return (value); 191 } 192 193 static void 194 p16x_write_ac97(void *arg, uint8_t index, uint16_t data) 195 { 196 p16x_dev_t *dev = arg; 197 unsigned int i; 198 199 OUTB(dev, index, AC97A); 200 for (i = 0; i < 10000; i++) 201 if (INB(dev, AC97A) & 0x80) 202 break; 203 OUTW(dev, data, AC97D); 204 } 205 206 /* 207 * Audio routines 208 */ 209 210 int 211 p16x_open(void *arg, int flag, uint_t *nframes, caddr_t *bufp) 212 { 213 p16x_port_t *port = arg; 214 215 _NOTE(ARGUNUSED(flag)); 216 217 port->count = 0; 218 *nframes = port->buf_frames; 219 *bufp = port->buf_kaddr; 220 221 return (0); 222 } 223 224 void 225 p16x_close(void *arg) 226 { 227 _NOTE(ARGUNUSED(arg)); 228 } 229 230 int 231 p16x_start(void *arg) 232 { 233 p16x_port_t *port = arg; 234 p16x_dev_t *dev = port->dev; 235 236 port->offset = 0; 237 238 if (port->port_num == P16X_REC) { 239 write_reg(dev, CRFA, 0, 0); 240 write_reg(dev, CRCAV, 0, 0); 241 242 /* Enable rec channel */ 243 set_reg_bits(dev, SA, 0, 0x100); 244 } else { 245 for (int i = 0; i < 3; i++) { 246 write_reg(dev, PTBA, i, 0); 247 write_reg(dev, PTBS, i, 0); 248 write_reg(dev, PTCA, i, 0); 249 write_reg(dev, PFEA, i, 0); 250 write_reg(dev, CPFA, i, 0); 251 write_reg(dev, CPCAV, i, 0); 252 } 253 254 /* Enable play channel */ 255 set_reg_bits(dev, SA, 0, 0x7); 256 } 257 258 return (0); 259 } 260 261 void 262 p16x_stop(void *arg) 263 { 264 p16x_port_t *port = arg; 265 p16x_dev_t *dev = port->dev; 266 267 if (port->port_num == P16X_REC) { 268 /* Disable rec channel */ 269 clear_reg_bits(dev, SA, 0, 0x100); 270 271 } else { 272 /* Disable Play channel */ 273 clear_reg_bits(dev, SA, 0, 0x7); 274 } 275 } 276 277 int 278 p16x_format(void *arg) 279 { 280 _NOTE(ARGUNUSED(arg)); 281 282 return (AUDIO_FORMAT_S16_LE); 283 } 284 285 int 286 p16x_channels(void *arg) 287 { 288 p16x_port_t *port = arg; 289 290 return (port->nchan); 291 } 292 293 int 294 p16x_rate(void *arg) 295 { 296 _NOTE(ARGUNUSED(arg)); 297 298 return (48000); 299 } 300 301 void 302 p16x_sync(void *arg, unsigned nframes) 303 { 304 p16x_port_t *port = arg; 305 _NOTE(ARGUNUSED(nframes)); 306 307 (void) ddi_dma_sync(port->buf_dmah, 0, 0, port->syncdir); 308 } 309 310 uint64_t 311 p16x_count(void *arg) 312 { 313 p16x_port_t *port = arg; 314 p16x_dev_t *dev = port->dev; 315 uint64_t val; 316 uint32_t offset, n; 317 318 if (port->port_num == P16X_PLAY) { 319 offset = read_reg(dev, CPFA, 0); 320 } else { 321 offset = read_reg(dev, CRFA, 0); 322 } 323 324 /* get the offset, and switch to frames */ 325 offset /= (2 * sizeof (uint16_t)); 326 327 if (offset >= port->offset) { 328 n = offset - port->offset; 329 } else { 330 n = offset + (port->buf_frames - port->offset); 331 } 332 port->offset = offset; 333 port->count += n; 334 val = port->count; 335 336 return (val); 337 } 338 339 static void 340 p16x_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr) 341 { 342 p16x_port_t *port = arg; 343 unsigned mult; 344 345 if (port->port_num == P16X_PLAY) { 346 switch (chan) { 347 case 0: /* left front */ 348 case 1: /* right front */ 349 mult = 0; 350 break; 351 case 2: /* center */ 352 case 3: /* lfe */ 353 mult = 2; 354 break; 355 case 4: /* left surround */ 356 case 5: /* right surround */ 357 mult = 1; 358 break; 359 } 360 *offset = (port->buf_frames * 2 * mult) + (chan % 2); 361 *incr = 2; 362 } else { 363 *offset = chan; 364 *incr = 2; 365 } 366 } 367 368 /* private implementation bits */ 369 370 int 371 p16x_alloc_port(p16x_dev_t *dev, int num) 372 { 373 p16x_port_t *port; 374 size_t len; 375 ddi_dma_cookie_t cookie; 376 uint_t count; 377 int dir; 378 unsigned caps; 379 audio_dev_t *adev; 380 381 adev = dev->adev; 382 port = kmem_zalloc(sizeof (*port), KM_SLEEP); 383 dev->port[num] = port; 384 port->dev = dev; 385 386 switch (num) { 387 case P16X_REC: 388 port->syncdir = DDI_DMA_SYNC_FORKERNEL; 389 caps = ENGINE_INPUT_CAP; 390 dir = DDI_DMA_READ; 391 port->port_num = P16X_REC; 392 port->nchan = 2; 393 break; 394 case P16X_PLAY: 395 port->syncdir = DDI_DMA_SYNC_FORDEV; 396 caps = ENGINE_OUTPUT_CAP; 397 dir = DDI_DMA_WRITE; 398 port->port_num = P16X_PLAY; 399 port->nchan = 6; 400 break; 401 default: 402 return (DDI_FAILURE); 403 } 404 405 /* 406 * NB: The device operates in pairs of dwords at a time, for 407 * performance reasons. So make sure that our buffer is 408 * arranged as a whole number of these. The value below gives 409 * a reasonably large buffer so we can support a deep 410 * playahead if we need to (and we should avoid input 411 * overruns.) 412 */ 413 port->buf_frames = 4096; 414 port->buf_size = port->buf_frames * port->nchan * sizeof (uint16_t); 415 416 /* now allocate buffers */ 417 if (ddi_dma_alloc_handle(dev->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL, 418 &port->buf_dmah) != DDI_SUCCESS) { 419 audio_dev_warn(adev, "failed to allocate BUF handle"); 420 return (DDI_FAILURE); 421 } 422 423 if (ddi_dma_mem_alloc(port->buf_dmah, port->buf_size, 424 &buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL, 425 &port->buf_kaddr, &len, &port->buf_acch) != DDI_SUCCESS) { 426 audio_dev_warn(adev, "failed to allocate BUF memory"); 427 return (DDI_FAILURE); 428 } 429 430 if (ddi_dma_addr_bind_handle(port->buf_dmah, NULL, port->buf_kaddr, 431 len, DDI_DMA_CONSISTENT | dir, DDI_DMA_SLEEP, NULL, &cookie, 432 &count) != DDI_SUCCESS) { 433 audio_dev_warn(adev, "failed binding BUF DMA handle"); 434 return (DDI_FAILURE); 435 } 436 port->buf_paddr = cookie.dmac_address; 437 438 port->engine = audio_engine_alloc(&p16x_engine_ops, caps); 439 if (port->engine == NULL) { 440 audio_dev_warn(adev, "audio_engine_alloc failed"); 441 return (DDI_FAILURE); 442 } 443 444 audio_engine_set_private(port->engine, port); 445 audio_dev_add_engine(adev, port->engine); 446 447 return (DDI_SUCCESS); 448 } 449 450 void 451 p16x_destroy(p16x_dev_t *dev) 452 { 453 mutex_destroy(&dev->mutex); 454 455 for (int i = 0; i < P16X_NUM_PORT; i++) { 456 p16x_port_t *port = dev->port[i]; 457 if (!port) 458 continue; 459 if (port->engine) { 460 audio_dev_remove_engine(dev->adev, port->engine); 461 audio_engine_free(port->engine); 462 } 463 if (port->buf_paddr) { 464 (void) ddi_dma_unbind_handle(port->buf_dmah); 465 } 466 if (port->buf_acch) { 467 ddi_dma_mem_free(&port->buf_acch); 468 } 469 if (port->buf_dmah) { 470 ddi_dma_free_handle(&port->buf_dmah); 471 } 472 kmem_free(port, sizeof (*port)); 473 } 474 475 if (dev->ac97 != NULL) { 476 ac97_free(dev->ac97); 477 } 478 if (dev->adev != NULL) { 479 audio_dev_free(dev->adev); 480 } 481 if (dev->regsh != NULL) { 482 ddi_regs_map_free(&dev->regsh); 483 } 484 if (dev->pcih != NULL) { 485 pci_config_teardown(&dev->pcih); 486 } 487 kmem_free(dev, sizeof (*dev)); 488 } 489 490 void 491 p16x_hwinit(p16x_dev_t *dev) 492 { 493 p16x_port_t *port; 494 uint32_t paddr; 495 uint32_t chunksz; 496 int i; 497 498 for (i = 0; i < 3; i++) { 499 write_reg(dev, PTBA, i, 0); 500 write_reg(dev, PTBS, i, 0); 501 write_reg(dev, PTCA, i, 0); 502 write_reg(dev, PFEA, i, 0); 503 write_reg(dev, CPFA, i, 0); 504 write_reg(dev, CPCAV, i, 0); 505 write_reg(dev, CRFA, i, 0); 506 write_reg(dev, CRCAV, i, 0); 507 } 508 write_reg(dev, SCS0, 0, 0x02108504); 509 write_reg(dev, SCS1, 0, 0x02108504); 510 write_reg(dev, SCS2, 0, 0x02108504); 511 512 /* set the spdif/analog combo jack to analog out */ 513 write_reg(dev, SPC, 0, 0x00000700); 514 write_reg(dev, EA_aux, 0, 0x0001003f); 515 516 port = dev->port[P16X_REC]; 517 /* Set physical address of the DMA buffer */ 518 write_reg(dev, RFBA, 0, port->buf_paddr); 519 write_reg(dev, RFBS, 0, (port->buf_size) << 16); 520 521 /* Set physical address of the DMA buffer */ 522 port = dev->port[P16X_PLAY]; 523 paddr = port->buf_paddr; 524 chunksz = port->buf_frames * 4; 525 write_reg(dev, PFBA, 0, paddr); 526 write_reg(dev, PFBS, 0, chunksz << 16); 527 paddr += chunksz; 528 write_reg(dev, PFBA, 1, paddr); 529 write_reg(dev, PFBS, 1, chunksz << 16); 530 paddr += chunksz; 531 write_reg(dev, PFBA, 2, paddr); 532 write_reg(dev, PFBS, 2, chunksz << 16); 533 534 OUTL(dev, 0x1080, GPIO); /* GPIO */ 535 /* Clear any pending interrupts */ 536 OUTL(dev, INTR_ALL, IP); 537 OUTL(dev, 0, IE); 538 OUTL(dev, 0x9, HC); /* Enable audio */ 539 } 540 541 int 542 p16x_attach(dev_info_t *dip) 543 { 544 uint16_t vendor, device; 545 p16x_dev_t *dev; 546 ddi_acc_handle_t pcih; 547 548 dev = kmem_zalloc(sizeof (*dev), KM_SLEEP); 549 dev->dip = dip; 550 ddi_set_driver_private(dip, dev); 551 552 mutex_init(&dev->mutex, NULL, MUTEX_DRIVER, NULL); 553 554 if ((dev->adev = audio_dev_alloc(dip, 0)) == NULL) { 555 cmn_err(CE_WARN, "audio_dev_alloc failed"); 556 goto error; 557 } 558 559 if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) { 560 audio_dev_warn(dev->adev, "pci_config_setup failed"); 561 goto error; 562 } 563 dev->pcih = pcih; 564 565 vendor = pci_config_get16(pcih, PCI_CONF_VENID); 566 device = pci_config_get16(pcih, PCI_CONF_DEVID); 567 if (vendor != CREATIVE_VENDOR_ID || 568 device != SB_P16X_ID) { 569 audio_dev_warn(dev->adev, "Hardware not recognized " 570 "(vendor=%x, dev=%x)", vendor, device); 571 goto error; 572 } 573 574 /* set PCI command register */ 575 pci_config_put16(pcih, PCI_CONF_COMM, 576 pci_config_get16(pcih, PCI_CONF_COMM) | 577 PCI_COMM_MAE | PCI_COMM_IO); 578 579 580 if ((ddi_regs_map_setup(dip, 1, &dev->base, 0, 0, &dev_attr, 581 &dev->regsh)) != DDI_SUCCESS) { 582 audio_dev_warn(dev->adev, "failed to map registers"); 583 goto error; 584 } 585 586 audio_dev_set_description(dev->adev, "Creative Sound Blaster Live!"); 587 audio_dev_set_version(dev->adev, "SBO200"); 588 589 if ((p16x_alloc_port(dev, P16X_PLAY) != DDI_SUCCESS) || 590 (p16x_alloc_port(dev, P16X_REC) != DDI_SUCCESS)) { 591 goto error; 592 } 593 594 p16x_hwinit(dev); 595 596 dev->ac97 = ac97_allocate(dev->adev, dip, 597 p16x_read_ac97, p16x_write_ac97, dev); 598 if (dev->ac97 == NULL) { 599 audio_dev_warn(dev->adev, "failed to allocate ac97 handle"); 600 goto error; 601 } 602 603 ac97_probe_controls(dev->ac97); 604 605 /* remove the AC'97 controls we don't want to expose */ 606 for (int i = 0; p16x_remove_ac97[i]; i++) { 607 ac97_ctrl_t *ctrl; 608 ctrl = ac97_control_find(dev->ac97, p16x_remove_ac97[i]); 609 if (ctrl != NULL) { 610 ac97_control_unregister(ctrl); 611 } 612 } 613 614 ac97_register_controls(dev->ac97); 615 616 if (audio_dev_register(dev->adev) != DDI_SUCCESS) { 617 audio_dev_warn(dev->adev, "unable to register with framework"); 618 goto error; 619 } 620 621 ddi_report_dev(dip); 622 623 return (DDI_SUCCESS); 624 625 error: 626 p16x_destroy(dev); 627 return (DDI_FAILURE); 628 } 629 630 int 631 p16x_resume(dev_info_t *dip) 632 { 633 p16x_dev_t *dev; 634 635 dev = ddi_get_driver_private(dip); 636 637 p16x_hwinit(dev); 638 639 ac97_reset(dev->ac97); 640 641 audio_dev_resume(dev->adev); 642 643 return (DDI_SUCCESS); 644 } 645 646 int 647 p16x_detach(p16x_dev_t *dev) 648 { 649 if (audio_dev_unregister(dev->adev) != DDI_SUCCESS) 650 return (DDI_FAILURE); 651 652 p16x_destroy(dev); 653 return (DDI_SUCCESS); 654 } 655 656 int 657 p16x_suspend(p16x_dev_t *dev) 658 { 659 audio_dev_suspend(dev->adev); 660 661 return (DDI_SUCCESS); 662 } 663 664 static int p16x_ddi_attach(dev_info_t *, ddi_attach_cmd_t); 665 static int p16x_ddi_detach(dev_info_t *, ddi_detach_cmd_t); 666 static int p16x_ddi_quiesce(dev_info_t *); 667 668 static struct dev_ops p16x_dev_ops = { 669 DEVO_REV, /* rev */ 670 0, /* refcnt */ 671 NULL, /* getinfo */ 672 nulldev, /* identify */ 673 nulldev, /* probe */ 674 p16x_ddi_attach, /* attach */ 675 p16x_ddi_detach, /* detach */ 676 nodev, /* reset */ 677 NULL, /* cb_ops */ 678 NULL, /* bus_ops */ 679 NULL, /* power */ 680 p16x_ddi_quiesce, /* quiesce */ 681 }; 682 683 static struct modldrv p16x_modldrv = { 684 &mod_driverops, /* drv_modops */ 685 "Creative P16X Audio", /* linkinfo */ 686 &p16x_dev_ops, /* dev_ops */ 687 }; 688 689 static struct modlinkage modlinkage = { 690 MODREV_1, 691 { &p16x_modldrv, NULL } 692 }; 693 694 int 695 _init(void) 696 { 697 int rv; 698 699 audio_init_ops(&p16x_dev_ops, P16X_NAME); 700 if ((rv = mod_install(&modlinkage)) != 0) { 701 audio_fini_ops(&p16x_dev_ops); 702 } 703 return (rv); 704 } 705 706 int 707 _fini(void) 708 { 709 int rv; 710 711 if ((rv = mod_remove(&modlinkage)) == 0) { 712 audio_fini_ops(&p16x_dev_ops); 713 } 714 return (rv); 715 } 716 717 int 718 _info(struct modinfo *modinfop) 719 { 720 return (mod_info(&modlinkage, modinfop)); 721 } 722 723 int 724 p16x_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 725 { 726 switch (cmd) { 727 case DDI_ATTACH: 728 return (p16x_attach(dip)); 729 730 case DDI_RESUME: 731 return (p16x_resume(dip)); 732 733 default: 734 return (DDI_FAILURE); 735 } 736 } 737 738 int 739 p16x_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 740 { 741 p16x_dev_t *dev; 742 743 dev = ddi_get_driver_private(dip); 744 745 switch (cmd) { 746 case DDI_DETACH: 747 return (p16x_detach(dev)); 748 749 case DDI_SUSPEND: 750 return (p16x_suspend(dev)); 751 752 default: 753 return (DDI_FAILURE); 754 } 755 } 756 757 int 758 p16x_ddi_quiesce(dev_info_t *dip) 759 { 760 p16x_dev_t *dev; 761 762 dev = ddi_get_driver_private(dip); 763 764 write_reg(dev, SA, 0, 0); 765 OUTL(dev, 0x01, HC); 766 767 return (DDI_SUCCESS); 768 } 769