xref: /illumos-gate/usr/src/uts/common/io/audio/drv/audiocmihd/audiocmihd.c (revision b6805bf78d2bbbeeaea8909a05623587b42d58b3)
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 CMedia 8788 sound card
29  */
30 /*
31  *
32  * Copyright (C) 4Front Technologies 1996-2011.
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/sysmacros.h>
47 #include <sys/note.h>
48 #include <sys/audio/audio_driver.h>
49 #include <sys/audio/ac97.h>
50 
51 #include "audiocmihd.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_buf = {
66 	DMA_ATTR_V0,		/* version number */
67 	0x0,			/* dma_attr_addr_lo */
68 	0xffffffffU,		/* dma_attr_addr_hi */
69 	0x3ffff,		/* dma_attr_count_max */
70 	0x8,			/* dma_attr_align */
71 	0x7f,			/* dma_attr_burstsizes */
72 	0x1,			/* dma_attr_minxfer */
73 	0x3ffff,		/* dma_attr_maxxfer */
74 	0x3ffff,		/* dma_attr_seg */
75 	0x1,			/* dma_attr_sgllen */
76 	0x1,			/* dma_attr_granular */
77 	0			/* dma_attr_flags */
78 };
79 
80 
81 static int cmediahd_attach(dev_info_t *);
82 static int cmediahd_resume(dev_info_t *);
83 static int cmediahd_detach(cmediahd_devc_t *);
84 static int cmediahd_suspend(cmediahd_devc_t *);
85 
86 static int cmediahd_open(void *, int, unsigned *, caddr_t *);
87 static void cmediahd_close(void *);
88 static int cmediahd_start(void *);
89 static void cmediahd_stop(void *);
90 static int cmediahd_format(void *);
91 static int cmediahd_channels(void *);
92 static int cmediahd_rate(void *);
93 static uint64_t cmediahd_count(void *);
94 static void cmediahd_sync(void *, unsigned);
95 static void cmediahd_chinfo(void *, int, unsigned *, unsigned *);
96 
97 
98 static uint16_t cmediahd_read_ac97(void *, uint8_t);
99 static void cmediahd_write_ac97(void *, uint8_t, uint16_t);
100 static int cmediahd_alloc_port(cmediahd_devc_t *, int);
101 static void cmediahd_reset_port(cmediahd_portc_t *);
102 static void cmediahd_destroy(cmediahd_devc_t *);
103 static void cmediahd_hwinit(cmediahd_devc_t *);
104 static void cmediahd_refresh_mixer(cmediahd_devc_t *devc);
105 static uint32_t mix_scale(uint32_t, int8_t);
106 static void cmediahd_ac97_hwinit(cmediahd_devc_t *);
107 static void cmediahd_del_controls(cmediahd_devc_t *);
108 
109 
110 static audio_engine_ops_t cmediahd_engine_ops = {
111 	AUDIO_ENGINE_VERSION,
112 	cmediahd_open,
113 	cmediahd_close,
114 	cmediahd_start,
115 	cmediahd_stop,
116 	cmediahd_count,
117 	cmediahd_format,
118 	cmediahd_channels,
119 	cmediahd_rate,
120 	cmediahd_sync,
121 	NULL, 	/* qlen */
122 	cmediahd_chinfo,
123 	NULL	/* playahead */
124 };
125 
126 #define	PLAYCTL (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_PLAY)
127 #define	RECCTL  (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_REC)
128 #define	MONCTL  (AUDIO_CTRL_FLAG_RW | AUDIO_CTRL_FLAG_MONITOR)
129 #define	PCMVOL  (PLAYCTL | AUDIO_CTRL_FLAG_PCMVOL)
130 #define	MAINVOL (PLAYCTL | AUDIO_CTRL_FLAG_MAINVOL)
131 #define	RECVOL  (RECCTL | AUDIO_CTRL_FLAG_RECVOL)
132 
133 static const char mix_cvt[101] = {
134 	0, 0, 3, 7, 10, 13, 16, 19,
135 	21, 23, 26, 28, 30, 32, 34, 35,
136 	37, 39, 40, 42,	43, 45, 46, 47,
137 	49, 50, 51, 52, 53, 55, 56, 57,
138 	58, 59, 60, 61, 62, 63, 64, 65,
139 	65, 66, 67, 68, 69, 70, 70, 71,
140 	72, 73, 73, 74, 75, 75, 76, 77,
141 	77, 78, 79, 79, 80, 81, 81, 82,
142 	82, 83, 84, 84, 85, 85, 86, 86,
143 	87, 87, 88, 88, 89, 89, 90, 90,
144 	91, 91, 92, 92, 93, 93, 94, 94,
145 	95, 95, 96, 96, 96, 97, 97, 98,
146 	98, 98, 99, 99, 100
147 };
148 
149 static uint32_t
150 mix_scale(uint32_t vol, int8_t bits)
151 {
152 	vol = mix_cvt[vol];
153 	vol = (vol * ((1 << bits) - 1)) / 100;
154 	return (vol);
155 }
156 
157 static uint16_t
158 cmediahd_read_ac97(void *arg, uint8_t reg)
159 {
160 	cmediahd_devc_t *devc = arg;
161 	uint32_t val;
162 	uint16_t data;
163 
164 	mutex_enter(&devc->low_mutex);
165 	val = 0L;
166 	val |= reg << 16;
167 	val |= 0 << 24;			/* codec 0 or codec 1 */
168 	val |= 1 << 23;			/* ac97 read the reg address */
169 	OUTL(devc, val, AC97_CMD_DATA);
170 	drv_usecwait(100);
171 	data = INL(devc, AC97_CMD_DATA) & 0xFFFF;
172 	mutex_exit(&devc->low_mutex);
173 	return (data);
174 }
175 
176 static void
177 cmediahd_write_ac97(void *arg, uint8_t reg, uint16_t data)
178 {
179 	cmediahd_devc_t *devc = arg;
180 	uint32_t val;
181 
182 	mutex_enter(&devc->low_mutex);
183 	val = 0L;
184 	val |= reg << 16;
185 	val |= data & 0xFFFF;
186 	val |= 0 << 24;			/* on board codec or frontpanel */
187 	val |= 0 << 23;			/* ac97 write operation */
188 	OUTL(devc, val, AC97_CMD_DATA);
189 	drv_usecwait(100);
190 	mutex_exit(&devc->low_mutex);
191 }
192 
193 #if 0	/* Front Panel AC'97 not supported yet */
194 static uint16_t
195 cmediahd_read_fp_ac97(void *arg, uint8_t reg)
196 {
197 	cmediahd_devc_t *devc = arg;
198 	uint32_t val;
199 	uint16_t data;
200 
201 	mutex_enter(&devc->low_mutex);
202 	val = 0L;
203 	val |= 1 << 24;			/* front panel */
204 	val |= 1 << 23;			/* ac97 read the reg address */
205 	val |= reg << 16;
206 	OUTL(devc, val, AC97_CMD_DATA);
207 	drv_usecwait(100);
208 	data = INL(devc, AC97_CMD_DATA) & 0xFFFF;
209 	mutex_exit(&devc->low_mutex);
210 
211 	return (data);
212 }
213 
214 static void
215 cmediahd_write_fp_ac97(void *arg, uint8_t reg, uint16_t data)
216 {
217 	cmediahd_devc_t *devc = arg;
218 	uint32_t val;
219 
220 	mutex_enter(&devc->low_mutex);
221 	val = 0L;
222 	val |= 1 << 24;			/* frontpanel */
223 	val |= 0 << 23;			/* ac97 write operation */
224 	val |= reg << 16;
225 	val |= data & 0xFFFF;
226 	OUTL(devc, val, AC97_CMD_DATA);
227 	drv_usecwait(100);
228 	mutex_exit(&devc->low_mutex);
229 }
230 #endif
231 
232 static void
233 spi_write(void *arg, int codec_num, unsigned char reg, int val)
234 {
235 	cmediahd_devc_t *devc = arg;
236 	unsigned int tmp;
237 	int latch, shift, count;
238 
239 	mutex_enter(&devc->low_mutex);
240 
241 	/* check if SPI is busy */
242 	count = 10;
243 	while ((INB(devc, SPI_CONTROL) & 0x1) && count-- > 0) {
244 		drv_usecwait(10);
245 	}
246 
247 	if (devc->model == SUBID_XONAR_DS) {
248 		shift = 9;
249 		latch = 0;
250 	} else {
251 		shift = 8;
252 		latch = 0x80;
253 	}
254 
255 	/* 2 byte data/reg info to be written */
256 	tmp = val;
257 	tmp |= (reg << shift);
258 
259 	/* write 2-byte data values */
260 	OUTB(devc, tmp & 0xff, SPI_DATA + 0);
261 	OUTB(devc, (tmp >> 8) & 0xff, SPI_DATA + 1);
262 
263 	/* Latch high, clock=160, Len=2byte, mode=write */
264 	tmp = (INB(devc, SPI_CONTROL) & ~0x7E) | latch | 0x1;
265 
266 	/* now address which codec you want to send the data to */
267 	tmp |= (codec_num << 4);
268 
269 	/* send the command to write the data */
270 	OUTB(devc, tmp, SPI_CONTROL);
271 
272 	mutex_exit(&devc->low_mutex);
273 }
274 
275 static void
276 i2c_write(void *arg, unsigned char codec_num, unsigned char reg,
277     unsigned char data)
278 {
279 	cmediahd_devc_t *devc = arg;
280 	int count = 50;
281 
282 	/* Wait for it to stop being busy */
283 	mutex_enter(&devc->low_mutex);
284 	while ((INW(devc, TWO_WIRE_CTRL) & 0x1) && (count > 0)) {
285 		drv_usecwait(10);
286 		count--;
287 	}
288 
289 	if (count == 0) {
290 		audio_dev_warn(devc->adev, "Time out on Two-Wire interface");
291 		mutex_exit(&devc->low_mutex);
292 		return;
293 	}
294 
295 	/* first write the Register Address into the MAP register */
296 	OUTB(devc, reg, TWO_WIRE_MAP);
297 
298 	/* now write the data */
299 	OUTB(devc, data, TWO_WIRE_DATA);
300 
301 	/* select the codec number to address */
302 	OUTB(devc, codec_num, TWO_WIRE_ADDR);
303 
304 	mutex_exit(&devc->low_mutex);
305 }
306 
307 static void
308 cs4398_init(void *arg, int codec)
309 {
310 	cmediahd_devc_t *devc = arg;
311 
312 	/* Fast Two-Wire. Reduces the wire ready time. */
313 	OUTW(devc, 0x0100, TWO_WIRE_CTRL);
314 
315 	/* Power down, enable control mode. */
316 	i2c_write(devc, codec, CS4398_MISC_CTRL,
317 	    CS4398_CPEN | CS4398_POWER_DOWN);
318 	/*
319 	 * Left justified PCM (DAC and 8788 support I2S, but doesn't work.
320 	 * Setting it introduces clipping like hell).
321 	 */
322 	i2c_write(devc, codec, CS4398_MODE_CTRL, 0x00);
323 	i2c_write(devc, codec, 3, 0x09);
324 	i2c_write(devc, codec, 4, 0x82);	/* PCM Automute */
325 	i2c_write(devc, codec, 5, 0x80); 	/* Vol A+B to -64dB */
326 	i2c_write(devc, codec, 6, 0x80);
327 	i2c_write(devc, codec, 7, 0xf0);	/* soft ramping on */
328 
329 	/* remove the powerdown flag */
330 	i2c_write(devc, codec, CS4398_MISC_CTRL, CS4398_CPEN);
331 }
332 
333 
334 static void
335 cs4362a_init(void *arg, int codec)
336 {
337 
338 	cmediahd_devc_t *devc = arg;
339 
340 	OUTW(devc, 0x0100, TWO_WIRE_CTRL);
341 
342 	/* Power down and enable control port. */
343 	i2c_write(devc, codec, CS4362A_MODE1_CTRL,
344 	    CS4362A_CPEN | CS4362A_POWER_DOWN);
345 	/* Left-justified PCM */
346 	i2c_write(devc, codec, CS4362A_MODE2_CTRL, CS4362A_DIF_LJUST);
347 	/* Ramp & Automute, re-set DAC defaults. */
348 	i2c_write(devc, codec, CS4362A_MODE3_CTRL, 0x84);
349 	/* Filter control, DAC defs. */
350 	i2c_write(devc, codec, CS4362A_FILTER_CTRL, 0);
351 	/* Invert control, DAC defs. */
352 	i2c_write(devc, codec, CS4362A_INVERT_CTRL, 0);
353 	/* Mixing control, DAC defs. */
354 	i2c_write(devc, codec, CS4362A_MIX1_CTRL, 0x24);
355 	i2c_write(devc, codec, CS4362A_MIX2_CTRL, 0x24);
356 	i2c_write(devc, codec, CS4362A_MIX3_CTRL, 0x24);
357 	/* Volume to -64dB. */
358 	i2c_write(devc, codec, CS4362A_VOLA_1, 0x40);
359 	i2c_write(devc, codec, CS4362A_VOLB_1, 0x40);
360 	i2c_write(devc, codec, CS4362A_VOLA_2, 0x40);
361 	i2c_write(devc, codec, CS4362A_VOLB_2, 0x40);
362 	i2c_write(devc, codec, CS4362A_VOLA_3, 0x40);
363 	i2c_write(devc, codec, CS4362A_VOLB_3, 0x40);
364 	/* Power up. */
365 	i2c_write(devc, codec, CS4362A_MODE1_CTRL, CS4362A_CPEN);
366 }
367 
368 
369 static void
370 cmediahd_generic_set_play_volume(cmediahd_devc_t *devc, int codec_id,
371     int left, int right)
372 
373 {
374 	spi_write(devc, codec_id, AK4396_LchATTCtl | 0x20, mix_scale(left, 8));
375 	spi_write(devc, codec_id, AK4396_RchATTCtl | 0x20, mix_scale(right, 8));
376 }
377 
378 static void
379 xonar_d1_set_play_volume(cmediahd_devc_t *devc, int codec_id,
380     int left, int right)
381 {
382 	switch (codec_id) {
383 	case 0:
384 		i2c_write(devc, XONAR_DX_FRONTDAC, CS4398_VOLA,
385 		    CS4398_VOL(left));
386 		i2c_write(devc, XONAR_DX_FRONTDAC, CS4398_VOLB,
387 		    CS4398_VOL(right));
388 		break;
389 	case 1:
390 		i2c_write(devc, XONAR_DX_SURRDAC, CS4362A_VOLA_1,
391 		    CS4362A_VOL(left));
392 		i2c_write(devc, XONAR_DX_SURRDAC, CS4362A_VOLB_1,
393 		    CS4362A_VOL(right));
394 		break;
395 	case 2:
396 		i2c_write(devc, XONAR_DX_SURRDAC, CS4362A_VOLA_2,
397 		    CS4362A_VOL(left));
398 		i2c_write(devc, XONAR_DX_SURRDAC, CS4362A_VOLB_2,
399 		    CS4362A_VOL(right));
400 		break;
401 	case 3:
402 		i2c_write(devc, XONAR_DX_SURRDAC, CS4362A_VOLA_3,
403 		    CS4362A_VOL(left));
404 		i2c_write(devc, XONAR_DX_SURRDAC, CS4362A_VOLB_3,
405 		    CS4362A_VOL(right));
406 		break;
407 	}
408 }
409 
410 static void
411 xonar_d2_set_play_volume(cmediahd_devc_t *devc, int codec_id,
412     int left, int right)
413 {
414 	spi_write(devc, xd2_codec_map[codec_id], 16, mix_scale(left, 8));
415 	spi_write(devc, xd2_codec_map[codec_id], 17, mix_scale(right, 8));
416 }
417 
418 static void
419 xonar_stx_set_play_volume(cmediahd_devc_t *devc, int codec_id,
420     int left, int right)
421 {
422 	if (codec_id == 0) {
423 		i2c_write(devc, XONAR_STX_FRONTDAC, 16, mix_scale(left, 8));
424 		i2c_write(devc, XONAR_STX_FRONTDAC, 17, mix_scale(right, 8));
425 	}
426 }
427 
428 static void
429 xonar_ds_set_play_volume(cmediahd_devc_t *devc, int codec_id,
430     int left, int right)
431 {
432 	switch (codec_id) {
433 	case 0:		/* front */
434 		spi_write(devc, XONAR_DS_FRONTDAC, 0,
435 		    mix_scale(left, 7) | 0x180);
436 		spi_write(devc, XONAR_DS_FRONTDAC, 1,
437 		    mix_scale(right, 7) | 0x180);
438 		spi_write(devc, XONAR_DS_FRONTDAC, 3,
439 		    mix_scale(left, 7) |0x180);
440 		spi_write(devc, XONAR_DS_FRONTDAC, 4,
441 		    mix_scale(right, 7) | 0x180);
442 		break;
443 
444 	case 1:		/* side */
445 		spi_write(devc, XONAR_DS_SURRDAC, 0,
446 		    mix_scale(left, 7) | 0x180);
447 		spi_write(devc, XONAR_DS_SURRDAC, 1,
448 		    mix_scale(right, 7) | 0x180);
449 		break;
450 	case 2:		/* rear */
451 		spi_write(devc, XONAR_DS_SURRDAC, 4,
452 		    mix_scale(left, 7) | 0x180);
453 		spi_write(devc, XONAR_DS_SURRDAC, 5,
454 		    mix_scale(right, 7) | 0x180);
455 		break;
456 	case 3:		/* center */
457 		spi_write(devc, XONAR_DS_SURRDAC, 6,
458 		    mix_scale(left, 7) | 0x180);
459 		spi_write(devc, XONAR_DS_SURRDAC, 7,
460 		    mix_scale(right, 7) | 0x180);
461 		break;
462 	}
463 }
464 
465 static void
466 cmediahd_set_rec_volume(cmediahd_devc_t *devc, int value)
467 {
468 	unsigned char left, right;
469 
470 	left = (value >> 8) & 0xff;
471 	right = value & 0xff;
472 
473 	if (left > 100)
474 		left = 100;
475 	if (right > 100)
476 		right = 100;
477 
478 	spi_write(devc, XONAR_DS_FRONTDAC, 0xe, mix_scale(left, 8));
479 	spi_write(devc, XONAR_DS_FRONTDAC, 0xf, mix_scale(right, 8));
480 }
481 
482 static void
483 cmediahd_set_play_volume(cmediahd_devc_t *devc, int codec_id, int value)
484 {
485 	int left, right;
486 
487 	left = (value >> 8) & 0xFF;
488 	right = (value & 0xFF);
489 
490 	if (left > 100)
491 		left = 100;
492 	if (right > 100)
493 		right = 100;
494 
495 	switch (devc->model) {
496 	case SUBID_XONAR_D1:
497 	case SUBID_XONAR_DX:
498 		xonar_d1_set_play_volume(devc, codec_id, left, right);
499 		break;
500 	case SUBID_XONAR_D2:
501 	case SUBID_XONAR_D2X:
502 		xonar_d2_set_play_volume(devc, codec_id, left, right);
503 		break;
504 	case SUBID_XONAR_STX:
505 		xonar_stx_set_play_volume(devc, codec_id, left, right);
506 		break;
507 	case SUBID_XONAR_DS:
508 		xonar_ds_set_play_volume(devc, codec_id, left, right);
509 		break;
510 	default:
511 		cmediahd_generic_set_play_volume(devc, codec_id, left, right);
512 		break;
513 	}
514 }
515 
516 /*
517  * Audio routines
518  */
519 
520 int
521 cmediahd_open(void *arg, int flag, unsigned *nframesp, caddr_t *bufp)
522 {
523 	cmediahd_portc_t *portc = arg;
524 
525         _NOTE(ARGUNUSED(flag));
526 
527 	portc->count = 0;
528 
529 	*nframesp = portc->nframes;
530 	*bufp = portc->kaddr;
531 
532 	return (0);
533 }
534 
535 void
536 cmediahd_close(void *arg)
537 {
538         _NOTE(ARGUNUSED(arg));
539 }
540 
541 int
542 cmediahd_start(void *arg)
543 {
544 	cmediahd_portc_t	*portc = arg;
545 	cmediahd_devc_t		*devc = portc->devc;
546 
547 	mutex_enter(&devc->mutex);
548 	portc->offset = 0;
549 
550 	cmediahd_reset_port(portc);
551 
552 	switch (portc->direction) {
553 	case CMEDIAHD_PLAY:
554 		/* enable the dma */
555 		OUTW(devc, INW(devc, DMA_START) | 0x10, DMA_START);
556 		break;
557 
558 	case CMEDIAHD_REC:
559 		/* enable the channel */
560 		OUTW(devc, INW(devc, DMA_START) | (1<<devc->rec_eng.chan),
561 		    DMA_START);
562 		break;
563 	}
564 
565 	mutex_exit(&devc->mutex);
566 	return (0);
567 }
568 
569 void
570 cmediahd_stop(void *arg)
571 {
572 	cmediahd_portc_t	*portc = arg;
573 	cmediahd_devc_t		*devc = portc->devc;
574 
575 	mutex_enter(&devc->mutex);
576 	switch (portc->direction) {
577 	case CMEDIAHD_PLAY:
578 		/* disable dma */
579 		OUTW(devc, INW(devc, DMA_START) & ~0x10, DMA_START);
580 		break;
581 
582 	case CMEDIAHD_REC:
583 		/* disable dma */
584 		OUTW(devc, INW(devc, DMA_START) & ~(1<<devc->rec_eng.chan),
585 		    DMA_START);
586 		break;
587 	}
588 	mutex_exit(&devc->mutex);
589 }
590 
591 int
592 cmediahd_format(void *arg)
593 {
594 	_NOTE(ARGUNUSED(arg));
595 
596 	return (AUDIO_FORMAT_S16_LE);
597 }
598 
599 int
600 cmediahd_channels(void *arg)
601 {
602 	cmediahd_portc_t	*portc = arg;
603 
604 	return (portc->chans);
605 }
606 
607 int
608 cmediahd_rate(void *arg)
609 {
610 	_NOTE(ARGUNUSED(arg));
611 
612 	return (48000);
613 }
614 
615 void
616 cmediahd_sync(void *arg, unsigned nframes)
617 {
618 	cmediahd_portc_t *portc = arg;
619 	_NOTE(ARGUNUSED(nframes));
620 
621 	(void) ddi_dma_sync(portc->buf_dmah, 0, 0, portc->syncdir);
622 }
623 
624 static void
625 cmediahd_chinfo(void *arg, int chan, unsigned *offset, unsigned *incr)
626 {
627 	cmediahd_portc_t *portc = arg;
628 	static const int map8ch[] = { 0, 1, 4, 5, 2, 3, 6, 7 };
629 	static const int map4ch[] = { 0, 1, 2, 3 };
630 
631 	if (portc->chans <= 4) {
632 		*offset = map4ch[chan];
633 	} else {
634 		*offset = map8ch[chan];
635 	}
636 	*incr = portc->chans;
637 }
638 
639 uint64_t
640 cmediahd_count(void *arg)
641 {
642 	cmediahd_portc_t	*portc = arg;
643 	cmediahd_devc_t	*devc = portc->devc;
644 	uint64_t	count;
645 	uint32_t	offset;
646 
647 	mutex_enter(&devc->mutex);
648 
649 	if (portc->direction == CMEDIAHD_PLAY)
650 		offset = portc->bufsz/4 - INL(devc, MULTICH_SIZE) + 1;
651 	else
652 		offset = portc->bufsz/4 - INW(devc, devc->rec_eng.size) + 1;
653 
654 	/* check for wrap */
655 	if (offset < portc->offset) {
656 		count = ((portc->bufsz/4) - portc->offset) + offset;
657 	} else {
658 		count = offset - portc->offset;
659 	}
660 	portc->count += count;
661 	portc->offset = offset;
662 
663 	/* convert from 16-bit stereo */
664 	count = portc->count / (portc->chans/2);
665 	mutex_exit(&devc->mutex);
666 
667 	return (count);
668 }
669 
670 /* private implementation bits */
671 
672 
673 void
674 cmediahd_reset_port(cmediahd_portc_t *portc)
675 {
676 	cmediahd_devc_t *devc = portc->devc;
677 	int channels;
678 
679 	if (devc->suspended)
680 		return;
681 
682 	portc->offset = 0;
683 
684 	switch (portc->direction) {
685 
686 	case CMEDIAHD_PLAY:
687 		/* reset channel */
688 		OUTB(devc, INB(devc, CHAN_RESET)|0x10, CHAN_RESET);
689 		drv_usecwait(10);
690 		OUTB(devc, INB(devc, CHAN_RESET) & ~0x10, CHAN_RESET);
691 		drv_usecwait(10);
692 
693 		OUTL(devc, portc->paddr,  MULTICH_ADDR);
694 		OUTL(devc, (portc->bufsz/4) - 1, MULTICH_SIZE);
695 		OUTL(devc, (portc->bufsz/4) - 1, MULTICH_FRAG);
696 
697 		switch (portc->chans) {
698 		case 2:
699 			channels = 0;
700 			break;
701 		case 4:
702 			channels = 1;
703 			break;
704 		case 6:
705 			channels = 2;
706 			break;
707 		case 8:
708 			channels = 3;
709 			break;
710 		}
711 		OUTB(devc, (INB(devc, MULTICH_MODE) & ~0x3) | channels,
712 		    MULTICH_MODE);
713 
714 		/* set the format bits in play format register */
715 		OUTB(devc, (INB(devc, PLAY_FORMAT) & ~0xC) | 0x0, PLAY_FORMAT);
716 		break;
717 
718 	case CMEDIAHD_REC:
719 		OUTB(devc, INB(devc, CHAN_RESET) | (1 << devc->rec_eng.chan),
720 		    CHAN_RESET);
721 		drv_usecwait(10);
722 		OUTB(devc, INB(devc, CHAN_RESET) & ~(1 << devc->rec_eng.chan),
723 		    CHAN_RESET);
724 		drv_usecwait(10);
725 
726 		OUTL(devc, portc->paddr,  devc->rec_eng.addr);
727 		OUTW(devc, (portc->bufsz/4) - 1, devc->rec_eng.size);
728 		OUTW(devc, (portc->bufsz/4) - 1, devc->rec_eng.frag);
729 
730 
731 		switch (portc->chans) {
732 		case 2:
733 			channels = 0x0;
734 			break;
735 		case 4:
736 			channels = 0x1;
737 			break;
738 		case 6:
739 			channels = 0x2;
740 			break;
741 		case 8:
742 			channels = 0x4;
743 			break;
744 		default:
745 			/* Stereo - boomer only supports stereo */
746 			channels = 0x0;
747 			break;
748 		}
749 
750 		OUTB(devc, (INB(devc, REC_MODE) & ~0x3) | channels, REC_MODE);
751 		OUTB(devc, (INB(devc, REC_FORMAT) & ~0x3) | 0x0, REC_FORMAT);
752 
753 	}
754 }
755 
756 int
757 cmediahd_alloc_port(cmediahd_devc_t *devc, int num)
758 {
759 	cmediahd_portc_t	*portc;
760 	size_t			len;
761 	ddi_dma_cookie_t	cookie;
762 	uint_t			count;
763 	int			dir;
764 	unsigned		caps;
765 	audio_dev_t		*adev;
766 
767 	adev = devc->adev;
768 	portc = kmem_zalloc(sizeof (*portc), KM_SLEEP);
769 	devc->portc[num] = portc;
770 	portc->devc = devc;
771 	portc->direction = num;
772 
773 	switch (num) {
774 	case CMEDIAHD_REC:
775 		portc->syncdir = DDI_DMA_SYNC_FORKERNEL;
776 		portc->chans = 2;
777 		caps = ENGINE_INPUT_CAP;
778 		dir = DDI_DMA_READ;
779 		break;
780 	case CMEDIAHD_PLAY:
781 		portc->syncdir = DDI_DMA_SYNC_FORDEV;
782 		portc->chans = 8;
783 		caps = ENGINE_OUTPUT_CAP;
784 		dir = DDI_DMA_WRITE;
785 		break;
786 	default:
787 		return (DDI_FAILURE);
788 	}
789 
790 	/*
791 	 * Calculate buffer size and frames
792 	 */
793 	portc->nframes = 2048;
794 	portc->bufsz = portc->nframes * portc->chans * 2;
795 
796 	/* Alloc buffers */
797 	if (ddi_dma_alloc_handle(devc->dip, &dma_attr_buf, DDI_DMA_SLEEP, NULL,
798 	    &portc->buf_dmah) != DDI_SUCCESS) {
799 		audio_dev_warn(adev, "failed to allocate BUF handle");
800 		return (DDI_FAILURE);
801 	}
802 
803 	if (ddi_dma_mem_alloc(portc->buf_dmah, CMEDIAHD_BUF_LEN,
804 	    &buf_attr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
805 	    &portc->kaddr, &len, &portc->buf_acch) != DDI_SUCCESS) {
806 		audio_dev_warn(adev, "failed to allocate BUF memory");
807 		return (DDI_FAILURE);
808 	}
809 
810 	bzero(portc->kaddr, len);
811 
812 	if (ddi_dma_addr_bind_handle(portc->buf_dmah, NULL, portc->kaddr,
813 	    len, DDI_DMA_CONSISTENT | dir, DDI_DMA_SLEEP, NULL, &cookie,
814 	    &count) != DDI_SUCCESS) {
815 		audio_dev_warn(adev, "failed binding BUF DMA handle");
816 		return (DDI_FAILURE);
817 	}
818 	portc->paddr = cookie.dmac_address;
819 
820 	portc->engine = audio_engine_alloc(&cmediahd_engine_ops, caps);
821 	if (portc->engine == NULL) {
822 		audio_dev_warn(adev, "audio_engine_alloc failed");
823 		return (DDI_FAILURE);
824 	}
825 
826 	audio_engine_set_private(portc->engine, portc);
827 	audio_dev_add_engine(adev, portc->engine);
828 
829 	return (DDI_SUCCESS);
830 }
831 
832 void
833 cmediahd_destroy(cmediahd_devc_t *devc)
834 {
835 	mutex_destroy(&devc->mutex);
836 	mutex_destroy(&devc->low_mutex);
837 
838 	for (int i = 0; i < CMEDIAHD_NUM_PORTC; i++) {
839 		cmediahd_portc_t *portc = devc->portc[i];
840 		if (!portc)
841 			continue;
842 		if (portc->engine) {
843 			audio_dev_remove_engine(devc->adev, portc->engine);
844 			audio_engine_free(portc->engine);
845 		}
846 		if (portc->paddr) {
847 			(void) ddi_dma_unbind_handle(portc->buf_dmah);
848 		}
849 		if (portc->buf_acch) {
850 			ddi_dma_mem_free(&portc->buf_acch);
851 		}
852 		if (portc->buf_dmah) {
853 			ddi_dma_free_handle(&portc->buf_dmah);
854 		}
855 		kmem_free(portc, sizeof (*portc));
856 	}
857 
858 	if (devc->ac97) {
859 		ac97_free(devc->ac97);
860 	}
861 
862 	cmediahd_del_controls(devc);
863 
864 	if (devc->adev != NULL) {
865 		audio_dev_free(devc->adev);
866 	}
867 	if (devc->regsh != NULL) {
868 		ddi_regs_map_free(&devc->regsh);
869 	}
870 	if (devc->pcih != NULL) {
871 		pci_config_teardown(&devc->pcih);
872 	}
873 	kmem_free(devc, sizeof (*devc));
874 }
875 
876 void
877 cmediahd_ac97_hwinit(cmediahd_devc_t *devc)
878 {
879 	/* GPIO #0 programmed as output, set CMI9780 Reg0x70 */
880 	cmediahd_write_ac97(devc, 0x70, 0x100);
881 
882 	/* LI2LI,MIC2MIC; let them always on, FOE on, ROE/BKOE/CBOE off */
883 	cmediahd_write_ac97(devc, 0x62, 0x180F);
884 
885 	/* unmute Master Volume */
886 	cmediahd_write_ac97(devc, 0x02, 0x0);
887 
888 	/* change PCBeep path, set Mix2FR on, option for quality issue */
889 	cmediahd_write_ac97(devc, 0x64, 0x8043);
890 
891 	/* mute PCBeep, option for quality issues */
892 	cmediahd_write_ac97(devc, 0x0A, 0x8000);
893 
894 	/* Record Select Control Register (Index 1Ah) */
895 	cmediahd_write_ac97(devc, 0x1A, 0x0000);
896 
897 	/* set Mic Volume Register 0x0Eh umute and enable micboost */
898 	cmediahd_write_ac97(devc, 0x0E, 0x0848);
899 
900 	/* set Line in Volume Register 0x10h mute */
901 	cmediahd_write_ac97(devc, 0x10, 0x8808);
902 
903 	/* set CD Volume Register 0x12h mute */
904 	cmediahd_write_ac97(devc, 0x12, 0x8808);
905 
906 	/* set AUX Volume Register 0x16h max */
907 	cmediahd_write_ac97(devc, 0x16, 0x0808);
908 
909 	/* set record gain Register 0x1Ch to max */
910 	cmediahd_write_ac97(devc, 0x1C, 0x0F0F);
911 
912 	/* GPIO status  register enable GPO0 */
913 	cmediahd_write_ac97(devc, 0x72, 0x0001);
914 }
915 void
916 cmediahd_hwinit(cmediahd_devc_t *devc)
917 {
918 
919 	unsigned short sVal;
920 	unsigned short i2s_fmt;
921 	unsigned char bVal;
922 	int i, count;
923 
924 	/* setup the default rec DMA engines to REC_A */
925 	devc->rec_eng.addr = RECA_ADDR;
926 	devc->rec_eng.size = RECA_SIZE;
927 	devc->rec_eng.frag = RECA_FRAG;
928 	devc->rec_eng.i2s = I2S_ADC1;
929 	devc->rec_eng.chan = REC_A;
930 
931 	/* setup GPIOs to 0 */
932 	devc->gpio_mic = 0;
933 	devc->gpio_out = 0;
934 	devc->gpio_codec = 0;
935 	devc->gpio_alt = 0;
936 
937 	/* Init CMI Controller */
938 	sVal = INW(devc, CTRL_VERSION);
939 	if (!(sVal & 0x0008)) {
940 		bVal = INB(devc, MISC_REG);
941 		bVal |= 0x20;
942 		OUTB(devc, bVal, MISC_REG);
943 	}
944 
945 	bVal = INB(devc, FUNCTION);
946 	bVal |= 0x02; /* Reset codec */
947 	OUTB(devc, bVal, FUNCTION);
948 
949 	/* Cold reset onboard AC97 */
950 	OUTW(devc, 0x1, AC97_CTRL);
951 	count = 100;
952 	while ((INW(devc, AC97_CTRL) & 0x2) && (count--)) {
953 		OUTW(devc, (INW(devc, AC97_CTRL) & ~0x2) | 0x2, AC97_CTRL);
954 		drv_usecwait(100);
955 	}
956 
957 	if (!count)
958 		audio_dev_warn(devc->adev, "CMI8788 AC97 not ready");
959 
960 	sVal = INW(devc, AC97_CTRL);
961 	/* check if there's an onboard AC97 codec (CODEC 0) */
962 	if (sVal & 0x10) {
963 		/* disable CODEC0 OUTPUT */
964 		OUTW(devc, INW(devc, AC97_OUT_CHAN_CONFIG) & ~0xFF00,
965 		    AC97_OUT_CHAN_CONFIG);
966 
967 		/* enable CODEC0 INPUT */
968 		OUTW(devc, INW(devc, AC97_IN_CHAN_CONFIG) | 0x0300,
969 		    AC97_IN_CHAN_CONFIG);
970 
971 		devc->has_ac97 = 1;
972 	}
973 
974 	/* check if there's an front panel AC97 codec (CODEC1) */
975 	if (sVal & 0x20) {
976 		/* enable CODEC1 OUTPUT */
977 		OUTW(devc, INW(devc, AC97_OUT_CHAN_CONFIG) | 0x0033,
978 		    AC97_OUT_CHAN_CONFIG);
979 		/* enable CODEC1 INPUT */
980 		OUTW(devc, INW(devc, AC97_IN_CHAN_CONFIG) | 0x0033,
981 		    AC97_IN_CHAN_CONFIG);
982 
983 		devc->has_fp_ac97 = 1;
984 	}
985 
986 	/* Disable AC97 interrupts and initialize AC97 */
987 	OUTB(devc, 0x0, AC97_INTR_MASK);
988 	OUTW(devc, INW(devc, IRQ_MASK) & ~0x4000, IRQ_MASK);
989 
990 	/* I2S to 16bit/48Khz/Master, see below. */
991 	i2s_fmt = 0x011A;
992 
993 	/* Setup I2S to use 16bit instead of 24Bit */
994 	OUTW(devc, i2s_fmt, I2S_MULTICH_DAC);
995 	OUTW(devc, i2s_fmt, I2S_ADC1);
996 	OUTW(devc, i2s_fmt, I2S_ADC2);
997 	OUTW(devc, i2s_fmt, I2S_ADC3);
998 
999 	/* setup Routing regs (default vals) */
1000 	OUTW(devc, 0xE400, PLAY_ROUTING);
1001 	OUTB(devc, 0x00, REC_ROUTING); /* default routing set to I2S */
1002 	OUTB(devc, 0x00, REC_MONITOR); /* monitor through MULTICH_PLAY */
1003 	OUTB(devc, 0xE4, MONITOR_ROUTING); /* default monitor routing */
1004 
1005 
1006 	/* Enable Xonar output */
1007 	switch (devc->model) {
1008 	case SUBID_XONAR_D1:
1009 	case SUBID_XONAR_DX:
1010 		/* GPIO8 = 0x100 controls mic/line-in */
1011 		/* GPIO0 = 0x001controls output */
1012 		/* GPIO2/3 = 0x00C codec output control */
1013 
1014 		devc->rec_eng.addr = RECB_ADDR;
1015 		devc->rec_eng.size = RECB_SIZE;
1016 		devc->rec_eng.frag = RECB_FRAG;
1017 		devc->rec_eng.i2s = I2S_ADC2;
1018 		devc->rec_eng.chan = REC_B;
1019 
1020 		/* disable AC97 mixer - not used */
1021 		devc->has_ac97 = 0;
1022 
1023 		/* setup for 2wire communication mode */
1024 		OUTB(devc, INB(devc, FUNCTION) | 0x40, FUNCTION);
1025 
1026 		/* setup GPIO direction */
1027 		OUTW(devc, INW(devc, GPIO_CONTROL) | 0x10D, GPIO_CONTROL);
1028 		/* setup GPIO pins */
1029 		OUTW(devc, INW(devc, GPIO_DATA) | 0x101, GPIO_DATA);
1030 
1031 		/* init the front and rear dacs */
1032 		cs4398_init(devc, XONAR_DX_FRONTDAC);
1033 		cs4362a_init(devc, XONAR_DX_SURRDAC);
1034 		break;
1035 
1036 	case SUBID_XONAR_D2:
1037 	case SUBID_XONAR_D2X:
1038 		/* GPIO7 = 0x0080 controls mic/line-in */
1039 		/* GPIO8 = 0x0100 controls output */
1040 		/* GPIO2/3 = 0x000C codec output control */
1041 
1042 		devc->rec_eng.addr = RECB_ADDR;
1043 		devc->rec_eng.size = RECB_SIZE;
1044 		devc->rec_eng.frag = RECB_FRAG;
1045 		devc->rec_eng.i2s = I2S_ADC2;
1046 		devc->rec_eng.chan = REC_B;
1047 
1048 		/* disable the AC97 mixer - it's not useful */
1049 		devc->has_ac97 = 0;
1050 
1051 		/* setup for spi communication mode */
1052 		OUTB(devc, (INB(devc, FUNCTION) & ~0x40) | 0x80, FUNCTION);
1053 		/* setup the GPIO direction */
1054 		OUTW(devc, INW(devc, GPIO_CONTROL) | 0x18c, GPIO_CONTROL);
1055 
1056 		/* setup GPIO Pins */
1057 		OUTW(devc, INW(devc, GPIO_DATA) | 0x100,  GPIO_DATA);
1058 
1059 		/* for all 4 codecs: unmute, set to 24Bit SPI */
1060 		for (i = 0; i < 4; ++i) {
1061 			/* left vol */
1062 			spi_write(devc, i, 16, mix_scale(75, 8));
1063 			/* right vol */
1064 			spi_write(devc, i, 17, mix_scale(75, 8));
1065 			/* unmute/24LSB/ATLD */
1066 			spi_write(devc, i, 18, 0x30 | 0x80);
1067 		}
1068 		break;
1069 
1070 	case SUBID_XONAR_STX:
1071 		devc->rec_eng.addr = RECB_ADDR;
1072 		devc->rec_eng.size = RECB_SIZE;
1073 		devc->rec_eng.frag = RECB_FRAG;
1074 		devc->rec_eng.i2s = I2S_ADC2;
1075 		devc->rec_eng.chan = REC_B;
1076 
1077 		/* disable the AC97 mixer - it's not useful */
1078 		devc->has_ac97 = 0;
1079 
1080 		/* setup for spi communication mode */
1081 		OUTB(devc, (INB(devc, FUNCTION) & ~0x40) | 0x80, FUNCTION);
1082 		/* setup the GPIO direction */
1083 		OUTW(devc, INW(devc, GPIO_CONTROL) | 0x18F, GPIO_CONTROL);
1084 		/* setup GPIO Pins */
1085 		OUTW(devc, INW(devc, GPIO_DATA) | 0x111, GPIO_DATA);
1086 
1087 		/* init front DAC */
1088 		/* left vol */
1089 		i2c_write(devc, XONAR_STX_FRONTDAC, 16, mix_scale(75, 8));
1090 		/* right vol */
1091 		i2c_write(devc, XONAR_STX_FRONTDAC, 17, mix_scale(75, 8));
1092 		/* unmute/24LSB/ATLD */
1093 		i2c_write(devc, XONAR_STX_FRONTDAC, 18, 0x30 | 0x80);
1094 		i2c_write(devc, XONAR_STX_FRONTDAC, 19, 0); /* ATS1/FLT_SHARP */
1095 		i2c_write(devc, XONAR_STX_FRONTDAC, 20, 0); /* OS_64 */
1096 		i2c_write(devc, XONAR_STX_FRONTDAC, 21, 0);
1097 		break;
1098 
1099 	case SUBID_XONAR_DS:
1100 		/* GPIO 8 = 1 output enabled 0 mute */
1101 		/* GPIO 7 = 1 lineout enabled 0 mute */
1102 		/* GPIO 6 = 1 mic select 0 line-in select */
1103 		/* GPIO 4 = 1 FP Headphone plugged in */
1104 		/* GPIO 3 = 1 FP Mic plugged in */
1105 
1106 		devc->rec_eng.addr = RECA_ADDR;
1107 		devc->rec_eng.size = RECA_SIZE;
1108 		devc->rec_eng.frag = RECA_FRAG;
1109 		devc->rec_eng.i2s = I2S_ADC1;
1110 		devc->rec_eng.chan = REC_A;
1111 
1112 		/* disable the AC97 mixer - it's not useful */
1113 		devc->has_ac97 = 0;
1114 
1115 		/* setup for spi communication mode */
1116 		OUTB(devc, (INB(devc, FUNCTION) & ~0x40) | 0x80, FUNCTION);
1117 		/* setup the GPIO direction */
1118 		OUTW(devc, INW(devc, GPIO_CONTROL) | 0x1D0, GPIO_CONTROL);
1119 		/* setup GPIO Pins */
1120 		OUTW(devc, INW(devc, GPIO_DATA) | 0x1D0, GPIO_DATA);
1121 		spi_write(devc, XONAR_DS_FRONTDAC, 0x17, 0x1); /* reset */
1122 		spi_write(devc, XONAR_DS_FRONTDAC, 0x7, 0x90); /* dac control */
1123 		spi_write(devc, XONAR_DS_FRONTDAC, 0x8, 0); /* unmute */
1124 		/* powerdown hp */
1125 		spi_write(devc, XONAR_DS_FRONTDAC, 0xC, 0x22);
1126 		spi_write(devc, XONAR_DS_FRONTDAC, 0xD, 0x8); /* powerdown hp */
1127 		spi_write(devc, XONAR_DS_FRONTDAC, 0xA, 0x1); /* LJust/16bit */
1128 		spi_write(devc, XONAR_DS_FRONTDAC, 0xB, 0x1); /* LJust/16bit */
1129 		spi_write(devc, XONAR_DS_SURRDAC, 0x1f, 1); /* reset */
1130 		/* LJust/24bit */
1131 		spi_write(devc, XONAR_DS_SURRDAC, 0x3, 0x1|0x20);
1132 		break;
1133 
1134 
1135 	default:
1136 		/* SPI default for anything else, including the */
1137 		OUTB(devc, (INB(devc, FUNCTION) & ~0x40) | 0x80, FUNCTION);
1138 		OUTB(devc, 0x18, REC_ROUTING); /* default routing set to I2S */
1139 		break;
1140 	}
1141 
1142 	/* only initialize AC97 if not defined */
1143 	if (devc->has_ac97)
1144 		cmediahd_ac97_hwinit(devc);
1145 }
1146 
1147 static int
1148 cmediahd_set_control(void *arg, uint64_t val)
1149 {
1150 	cmediahd_ctrl_t	*pc = arg;
1151 	cmediahd_devc_t	*devc = pc->devc;
1152 
1153 	mutex_enter(&devc->mutex);
1154 
1155 	pc->val = val;
1156 
1157 	switch (pc->num) {
1158 
1159 	case CTL_VOLUME:
1160 	case CTL_FRONT:
1161 		cmediahd_set_play_volume(devc, 0, val);
1162 		break;
1163 
1164 	case CTL_REAR:
1165 		cmediahd_set_play_volume(devc, 1, val);
1166 		break;
1167 
1168 	case CTL_CENTER:
1169 		val &= 0xff;
1170 		val |= ((devc->controls[CTL_LFE].val) << 8);
1171 		cmediahd_set_play_volume(devc, 2, val);
1172 		break;
1173 
1174 	case CTL_LFE:
1175 		val &= 0xff;
1176 		val <<= 8;
1177 		val |= (devc->controls[CTL_CENTER].val);
1178 		cmediahd_set_play_volume(devc, 2, val);
1179 		break;
1180 
1181 	case CTL_SURROUND:
1182 		cmediahd_set_play_volume(devc, 3, val);
1183 		break;
1184 
1185 	case CTL_MONITOR:
1186 		/* enable recording  monitor rec 1 and rec2 */
1187 		if (val)
1188 			OUTB(devc, INB(devc, REC_MONITOR) | 0xF, REC_MONITOR);
1189 		else
1190 			OUTB(devc, INB(devc, REC_MONITOR) & ~0xF, REC_MONITOR);
1191 		break;
1192 
1193 	case CTL_RECSRC:
1194 		switch (val) {
1195 		case 1: /* Line */
1196 			if (devc->model == SUBID_XONAR_DS)
1197 				OUTW(devc, INW(devc, GPIO_DATA) & ~0x40,
1198 				    GPIO_DATA);
1199 
1200 			if (devc->model == SUBID_XONAR_D1 ||
1201 			    devc->model == SUBID_XONAR_DX)
1202 				OUTW(devc, INW(devc, GPIO_DATA) &
1203 				    ~devc->gpio_mic, GPIO_DATA);
1204 			cmediahd_write_ac97(devc, 0x72,
1205 			    cmediahd_read_ac97(devc, 0x72) & ~0x1);
1206 			cmediahd_write_ac97(devc, 0x1A, 0x0404);
1207 			break;
1208 
1209 		case 2:  /* Mic */
1210 			if (devc->model == SUBID_XONAR_DS)
1211 				OUTW(devc, INW(devc, GPIO_DATA) | 0x40,
1212 				    GPIO_DATA);
1213 
1214 			if (devc->model == SUBID_XONAR_D1 ||
1215 			    devc->model == SUBID_XONAR_DX)
1216 				OUTW(devc, INW(devc, GPIO_DATA) |
1217 				    devc->gpio_mic, GPIO_DATA);
1218 			cmediahd_write_ac97(devc, 0x72,
1219 			    cmediahd_read_ac97(devc, 0x72) | 0x1);
1220 			/* Unmute Mic */
1221 			cmediahd_write_ac97(devc, 0xE,
1222 			    cmediahd_read_ac97(devc, 0xE) & ~0x8000);
1223 			/* Mute AUX and Video */
1224 			cmediahd_write_ac97(devc, 0x12,
1225 			    cmediahd_read_ac97(devc, 0x12) | 0x8000);
1226 			cmediahd_write_ac97(devc, 0x16,
1227 			    cmediahd_read_ac97(devc, 0x16) | 0x8000);
1228 			cmediahd_write_ac97(devc, 0x1A, 0x0000);
1229 			break;
1230 
1231 		case 4: /* AUX */
1232 			if (devc->model == SUBID_XONAR_D1 ||
1233 			    devc->model == SUBID_XONAR_DX)
1234 				OUTW(devc, INW(devc, GPIO_DATA) |
1235 				    devc->gpio_mic, GPIO_DATA);
1236 			cmediahd_write_ac97(devc, 0x72,
1237 			    cmediahd_read_ac97(devc, 0x72) | 0x1);
1238 			/* Unmute AUX */
1239 			cmediahd_write_ac97(devc, 0x16,
1240 			    cmediahd_read_ac97(devc, 0x16) & ~0x8000);
1241 			/* Mute CD and Mic */
1242 			cmediahd_write_ac97(devc, 0x14,
1243 			    cmediahd_read_ac97(devc, 0x14) | 0x8000);
1244 			cmediahd_write_ac97(devc, 0x0E,
1245 			    cmediahd_read_ac97(devc, 0x0E) | 0x8000);
1246 			cmediahd_write_ac97(devc, 0x1A, 0x0303);
1247 			break;
1248 
1249 		case 8: /* Video (CD) */
1250 			if (devc->model == SUBID_XONAR_D1 ||
1251 			    devc->model == SUBID_XONAR_DX)
1252 				OUTW(devc, INW(devc, GPIO_DATA) |
1253 				    devc->gpio_mic, GPIO_DATA);
1254 			cmediahd_write_ac97(devc, 0x72,
1255 			    cmediahd_read_ac97(devc, 0x72) | 0x1);
1256 			/* Unmute Video (CD) */
1257 			cmediahd_write_ac97(devc, 0x14,
1258 			    cmediahd_read_ac97(devc, 0x14) & ~0x8000);
1259 			/* Mute AUX and Mic */
1260 			cmediahd_write_ac97(devc, 0x16,
1261 			    cmediahd_read_ac97(devc, 0x16) | 0x8000);
1262 			cmediahd_write_ac97(devc, 0x0E,
1263 			    cmediahd_read_ac97(devc, 0x0E) | 0x8000);
1264 			/* set input to video */
1265 			cmediahd_write_ac97(devc, 0x1A, 0x0202);
1266 			break;
1267 		}
1268 		break;
1269 
1270 	case CTL_LOOP:
1271 		if (val)
1272 			OUTW(devc, INW(devc, GPIO_DATA) | devc->gpio_alt,
1273 			    GPIO_DATA);
1274 		else
1275 			OUTW(devc, (INW(devc, GPIO_DATA) & ~devc->gpio_alt),
1276 			    GPIO_DATA);
1277 		break;
1278 
1279 	case CTL_SPREAD:
1280 		if (val)
1281 			OUTW(devc, INW(devc, PLAY_ROUTING) & 0x00FF,
1282 			    PLAY_ROUTING);
1283 		else
1284 			OUTW(devc, (INW(devc, PLAY_ROUTING) & 0x00FF) |
1285 			    0xE400, PLAY_ROUTING);
1286 		break;
1287 
1288 	case CTL_RECGAIN:
1289 		cmediahd_set_rec_volume(devc, val);
1290 		break;
1291 
1292 	case CTL_MICVOL:
1293 		if (val)
1294 			cmediahd_write_ac97(devc, 0x0E,
1295 			    (0x40 | mix_scale(val, -5)) & ~0x8000);
1296 		else
1297 			cmediahd_write_ac97(devc, 0x0E, 0x8000);
1298 		break;
1299 
1300 	case CTL_AUXVOL:
1301 		if (val)
1302 			cmediahd_write_ac97(devc, 0x16,
1303 			    mix_scale(val, -5) & ~0x8000);
1304 		else
1305 			cmediahd_write_ac97(devc, 0x16, 0x8000);
1306 		break;
1307 
1308 
1309 	case CTL_CDVOL:
1310 		if (val)
1311 			cmediahd_write_ac97(devc, 0x14,
1312 			    mix_scale(val, -5) & ~0x8000);
1313 		else
1314 			cmediahd_write_ac97(devc, 0x14, 0x8000);
1315 		break;
1316 	}
1317 
1318 	mutex_exit(&devc->mutex);
1319 	return (0);
1320 }
1321 
1322 static int
1323 cmediahd_get_control(void *arg, uint64_t *val)
1324 {
1325 	cmediahd_ctrl_t	*pc = arg;
1326 	cmediahd_devc_t	*devc = pc->devc;
1327 
1328 	mutex_enter(&devc->mutex);
1329 	*val = pc->val;
1330 	mutex_exit(&devc->mutex);
1331 	return (0);
1332 }
1333 
1334 static void
1335 cmediahd_alloc_ctrl(cmediahd_devc_t *devc, uint32_t num, uint64_t val)
1336 {
1337 	audio_ctrl_desc_t	desc;
1338 	cmediahd_ctrl_t		*pc;
1339 
1340 	bzero(&desc, sizeof (desc));
1341 
1342 	pc = &devc->controls[num];
1343 	pc->num = num;
1344 	pc->devc = devc;
1345 
1346 
1347 	switch (num) {
1348 
1349 	case CTL_VOLUME:
1350 		desc.acd_name = AUDIO_CTRL_ID_VOLUME;
1351 		desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
1352 		desc.acd_minvalue = 0;
1353 		desc.acd_maxvalue = 100;
1354 		desc.acd_flags = PCMVOL;
1355 		break;
1356 
1357 	case CTL_FRONT:
1358 		desc.acd_name = AUDIO_CTRL_ID_FRONT;
1359 		desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
1360 		desc.acd_minvalue = 0;
1361 		desc.acd_maxvalue = 100;
1362 		desc.acd_flags = PCMVOL;
1363 		break;
1364 
1365 	case CTL_REAR:
1366 		desc.acd_name = AUDIO_CTRL_ID_REAR;
1367 		desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
1368 		desc.acd_minvalue = 0;
1369 		desc.acd_maxvalue = 100;
1370 		desc.acd_flags = PCMVOL;
1371 		break;
1372 
1373 	case CTL_SURROUND:
1374 		desc.acd_name = AUDIO_CTRL_ID_SURROUND;
1375 		desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
1376 		desc.acd_minvalue = 0;
1377 		desc.acd_maxvalue = 100;
1378 		desc.acd_flags = PCMVOL;
1379 		break;
1380 
1381 	case CTL_CENTER:
1382 		desc.acd_name = AUDIO_CTRL_ID_CENTER;
1383 		desc.acd_type = AUDIO_CTRL_TYPE_MONO;
1384 		desc.acd_minvalue = 0;
1385 		desc.acd_maxvalue = 100;
1386 		desc.acd_flags = PCMVOL;
1387 		break;
1388 
1389 	case CTL_LFE:
1390 		desc.acd_name = AUDIO_CTRL_ID_LFE;
1391 		desc.acd_type = AUDIO_CTRL_TYPE_MONO;
1392 		desc.acd_minvalue = 0;
1393 		desc.acd_maxvalue = 100;
1394 		desc.acd_flags = PCMVOL;
1395 		break;
1396 
1397 	case CTL_MONITOR:
1398 		desc.acd_name = AUDIO_CTRL_ID_MONSRC;
1399 		desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
1400 		desc.acd_minvalue = 0;
1401 		desc.acd_maxvalue = 1;
1402 		desc.acd_flags = RECCTL;
1403 		break;
1404 
1405 	case CTL_RECSRC:
1406 		desc.acd_name = AUDIO_CTRL_ID_RECSRC;
1407 		desc.acd_type = AUDIO_CTRL_TYPE_ENUM;
1408 		desc.acd_flags = RECCTL;
1409 		desc.acd_enum[0] = AUDIO_PORT_LINEIN;
1410 		desc.acd_enum[1] = AUDIO_PORT_MIC;
1411 
1412 		if (devc->model == SUBID_XONAR_D2 ||
1413 		    devc->model == SUBID_XONAR_D2X) {
1414 			desc.acd_minvalue = 0xF;
1415 			desc.acd_maxvalue = 0xF;
1416 			desc.acd_enum[2] = AUDIO_PORT_AUX1IN;
1417 			desc.acd_enum[3] = AUDIO_PORT_CD;
1418 		} else {
1419 			desc.acd_minvalue = 0x3;
1420 			desc.acd_maxvalue = 0x3;
1421 		}
1422 		break;
1423 
1424 	case CTL_LOOP:
1425 		desc.acd_name = AUDIO_CTRL_ID_LOOPBACK;
1426 		desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
1427 		desc.acd_minvalue = 0;
1428 		desc.acd_maxvalue = 1;
1429 		desc.acd_flags = RECCTL;
1430 		break;
1431 
1432 	case CTL_SPREAD:
1433 		desc.acd_name = AUDIO_CTRL_ID_SPREAD;
1434 		desc.acd_type = AUDIO_CTRL_TYPE_BOOLEAN;
1435 		desc.acd_minvalue = 0;
1436 		desc.acd_maxvalue = 1;
1437 		desc.acd_flags = PLAYCTL;
1438 		break;
1439 
1440 	case CTL_RECGAIN:
1441 		desc.acd_name = AUDIO_CTRL_ID_RECGAIN;
1442 		desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
1443 		desc.acd_minvalue = 0;
1444 		desc.acd_maxvalue = 100;
1445 		desc.acd_flags = RECVOL;
1446 		break;
1447 
1448 	case CTL_MICVOL:
1449 		desc.acd_name = AUDIO_CTRL_ID_MIC;
1450 		desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
1451 		desc.acd_minvalue = 0;
1452 		desc.acd_maxvalue = 100;
1453 		desc.acd_flags = RECVOL;
1454 		break;
1455 
1456 	case CTL_AUXVOL:
1457 		desc.acd_name = AUDIO_CTRL_ID_AUX1IN;
1458 		desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
1459 		desc.acd_minvalue = 0;
1460 		desc.acd_maxvalue = 100;
1461 		desc.acd_flags = RECVOL;
1462 		break;
1463 	case CTL_CDVOL:
1464 		desc.acd_name = AUDIO_CTRL_ID_CD;
1465 		desc.acd_type = AUDIO_CTRL_TYPE_STEREO;
1466 		desc.acd_minvalue = 0;
1467 		desc.acd_maxvalue = 100;
1468 		desc.acd_flags = RECVOL;
1469 		break;
1470 
1471 	}
1472 
1473 	pc->val = val;
1474 	pc->ctrl = audio_dev_add_control(devc->adev, &desc,
1475 	    cmediahd_get_control, cmediahd_set_control, pc);
1476 }
1477 
1478 static void
1479 cmediahd_refresh_mixer(cmediahd_devc_t *devc)
1480 {
1481 	int ctl;
1482 
1483 	for (ctl = 0; ctl < CTL_NUM; ctl++) {
1484 		if (devc->controls[ctl].ctrl == NULL)
1485 			continue;
1486 		(void) cmediahd_set_control(&devc->controls[ctl],
1487 		    devc->controls[ctl].val);
1488 	}
1489 }
1490 
1491 static void
1492 cmediahd_add_controls(cmediahd_devc_t *devc)
1493 {
1494 	cmediahd_alloc_ctrl(devc, CTL_VOLUME, 80 | (80 << 8));
1495 	cmediahd_alloc_ctrl(devc, CTL_FRONT, 80 | (80<<8));
1496 	cmediahd_alloc_ctrl(devc, CTL_REAR, 80 | (80<<8));
1497 	cmediahd_alloc_ctrl(devc, CTL_CENTER, 80);
1498 	cmediahd_alloc_ctrl(devc, CTL_LFE, 80);
1499 	cmediahd_alloc_ctrl(devc, CTL_SURROUND, 80 | (80<<8));
1500 	cmediahd_alloc_ctrl(devc, CTL_SPREAD, 0);
1501 	cmediahd_alloc_ctrl(devc, CTL_MONITOR, 0);
1502 	cmediahd_alloc_ctrl(devc, CTL_LOOP, 0);
1503 	cmediahd_alloc_ctrl(devc, CTL_RECSRC, 2);
1504 
1505 	switch (devc->model) {
1506 	case SUBID_XONAR_DS:
1507 		cmediahd_alloc_ctrl(devc, CTL_RECGAIN, 80|80<<8);
1508 		break;
1509 	case SUBID_XONAR_D2:
1510 	case SUBID_XONAR_D2X:
1511 		cmediahd_alloc_ctrl(devc, CTL_MICVOL, 80|80<<8);
1512 		cmediahd_alloc_ctrl(devc, CTL_AUXVOL, 80|80<<8);
1513 		cmediahd_alloc_ctrl(devc, CTL_CDVOL, 80|80<<8);
1514 		break;
1515 	}
1516 
1517 	cmediahd_refresh_mixer(devc);
1518 }
1519 
1520 void
1521 cmediahd_del_controls(cmediahd_devc_t *dev)
1522 {
1523 	for (int i = 0; i < CTL_NUM; i++) {
1524 		if (dev->controls[i].ctrl) {
1525 			audio_dev_del_control(dev->controls[i].ctrl);
1526 			dev->controls[i].ctrl = NULL;
1527 		}
1528 	}
1529 }
1530 
1531 int
1532 cmediahd_attach(dev_info_t *dip)
1533 {
1534 	uint16_t	pci_command, vendor, device, subvendor, subdevice;
1535 	cmediahd_devc_t	*devc;
1536 	ddi_acc_handle_t pcih;
1537 
1538 	devc = kmem_zalloc(sizeof (*devc), KM_SLEEP);
1539 	devc->dip = dip;
1540 	ddi_set_driver_private(dip, devc);
1541 
1542 	mutex_init(&devc->mutex, NULL, MUTEX_DRIVER, NULL);
1543 	mutex_init(&devc->low_mutex, NULL, MUTEX_DRIVER, NULL);
1544 
1545 	if ((devc->adev = audio_dev_alloc(dip, 0)) == NULL) {
1546 		cmn_err(CE_WARN, "audio_dev_alloc failed");
1547 		goto error;
1548 	}
1549 
1550 	if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
1551 		audio_dev_warn(devc->adev, "pci_config_setup failed");
1552 		goto error;
1553 	}
1554 	devc->pcih = pcih;
1555 
1556 	vendor = pci_config_get16(pcih, PCI_CONF_VENID);
1557 	device = pci_config_get16(pcih, PCI_CONF_DEVID);
1558 	subvendor = pci_config_get16(pcih, PCI_CONF_SUBVENID);
1559 	subdevice = pci_config_get16(pcih, PCI_CONF_SUBSYSID);
1560 	if (vendor != PCI_VENDOR_ID_CMEDIA ||
1561 	    device != PCI_DEVICE_ID_CMEDIAHD) {
1562 		audio_dev_warn(devc->adev, "Hardware not recognized "
1563 		    "(vendor=%x, dev=%x)", vendor, device);
1564 		goto error;
1565 	}
1566 
1567 
1568 	pci_command = pci_config_get16(pcih, PCI_CONF_COMM);
1569 	pci_command |= PCI_COMM_ME | PCI_COMM_IO;
1570 	pci_config_put16(pcih, PCI_CONF_COMM, pci_command);
1571 
1572 	if ((ddi_regs_map_setup(dip, 1, &devc->base, 0, 0, &dev_attr,
1573 	    &devc->regsh)) != DDI_SUCCESS) {
1574 		audio_dev_warn(devc->adev, "failed to map registers");
1575 		goto error;
1576 	}
1577 
1578 	audio_dev_set_description(devc->adev, "CMedia 8788");
1579 
1580 	/* Detect Xonar device */
1581 	if (subvendor == ASUS_VENDOR_ID) {
1582 		switch (subdevice) {
1583 		case SUBID_XONAR_D1:
1584 			audio_dev_set_description(devc->adev,
1585 			    "Asus Xonar D1 (AV100)");
1586 			break;
1587 		case SUBID_XONAR_DX:
1588 			audio_dev_set_description(devc->adev,
1589 			    "Asus Xonar DX (AV100)");
1590 			break;
1591 		case SUBID_XONAR_D2:
1592 			audio_dev_set_description(devc->adev,
1593 			    "Asus Xonar D2 (AV200)");
1594 			break;
1595 		case SUBID_XONAR_D2X:
1596 			audio_dev_set_description(devc->adev,
1597 			    "Asus Xonar D2X (AV200)");
1598 			break;
1599 		case SUBID_XONAR_STX:
1600 			audio_dev_set_description(devc->adev,
1601 			    "Asus Xonar STX (AV100)");
1602 			break;
1603 		case SUBID_XONAR_DS:
1604 			audio_dev_set_description(devc->adev,
1605 			    "Asus Xonar DS (AV66)");
1606 			break;
1607 		default:
1608 			audio_dev_set_description(devc->adev,
1609 			    "Asus Xonar Unknown Model");
1610 			subdevice = SUBID_GENERIC;
1611 			break;
1612 		}
1613 		devc->model = subdevice;
1614 	}
1615 
1616 	cmediahd_hwinit(devc);
1617 
1618 	if (cmediahd_alloc_port(devc, CMEDIAHD_PLAY) != DDI_SUCCESS)
1619 		goto error;
1620 	if (cmediahd_alloc_port(devc, CMEDIAHD_REC) != DDI_SUCCESS)
1621 		goto error;
1622 
1623 	/* Add the AC97 Mixer if there is an onboard AC97 device */
1624 	if (devc->has_ac97) {
1625 		devc->ac97 = ac97_alloc(dip, cmediahd_read_ac97,
1626 		    cmediahd_write_ac97, devc);
1627 		if (ac97_init(devc->ac97, devc->adev) != DDI_SUCCESS) {
1628 			audio_dev_warn(devc->adev, "failed to init ac97");
1629 			goto error;
1630 		}
1631 	}
1632 #if 0
1633 	/* Add the front panel AC97 device if one exists */
1634 	if (devc->has_fp_ac97) {
1635 		devc->fp_ac97 = ac97_alloc(dip, cmediahd_read_fp_ac97,
1636 		    cmediahd_write_fp_ac97, devc);
1637 		if (ac97_init(devc->fp_ac97, devc->adev) != DDI_SUCCESS) {
1638 			audio_dev_warn(devc->adev, "failed to init fp_ac97");
1639 			goto error;
1640 		}
1641 	}
1642 #endif
1643 	/* Add the standard CMI8788 Mixer panel */
1644 	cmediahd_add_controls(devc);
1645 
1646 	if (audio_dev_register(devc->adev) != DDI_SUCCESS) {
1647 		audio_dev_warn(devc->adev, "unable to register with framework");
1648 		goto error;
1649 	}
1650 
1651 	ddi_report_dev(dip);
1652 
1653 	return (DDI_SUCCESS);
1654 
1655 error:
1656 	cmediahd_destroy(devc);
1657 	return (DDI_FAILURE);
1658 }
1659 
1660 int
1661 cmediahd_resume(dev_info_t *dip)
1662 {
1663 	cmediahd_devc_t *devc;
1664 
1665 	devc = ddi_get_driver_private(dip);
1666 
1667 	cmediahd_hwinit(devc);
1668 
1669 	if (devc->ac97)
1670 		ac97_reset(devc->ac97);
1671 
1672 	cmediahd_refresh_mixer(devc);
1673 
1674 	audio_dev_resume(devc->adev);
1675 
1676 	return (DDI_SUCCESS);
1677 }
1678 
1679 int
1680 cmediahd_detach(cmediahd_devc_t *devc)
1681 {
1682 	if (audio_dev_unregister(devc->adev) != DDI_SUCCESS)
1683 		return (DDI_FAILURE);
1684 
1685 	cmediahd_destroy(devc);
1686 	return (DDI_SUCCESS);
1687 }
1688 
1689 int
1690 cmediahd_suspend(cmediahd_devc_t *devc)
1691 {
1692 	audio_dev_suspend(devc->adev);
1693 	return (DDI_SUCCESS);
1694 }
1695 
1696 static int cmediahd_ddi_attach(dev_info_t *, ddi_attach_cmd_t);
1697 static int cmediahd_ddi_detach(dev_info_t *, ddi_detach_cmd_t);
1698 static int cmediahd_ddi_quiesce(dev_info_t *);
1699 
1700 static struct dev_ops cmediahd_dev_ops = {
1701 	DEVO_REV,		/* rev */
1702 	0,			/* refcnt */
1703 	NULL,			/* getinfo */
1704 	nulldev,		/* identify */
1705 	nulldev,		/* probe */
1706 	cmediahd_ddi_attach,	/* attach */
1707 	cmediahd_ddi_detach,	/* detach */
1708 	nodev,			/* reset */
1709 	NULL,			/* cb_ops */
1710 	NULL,			/* bus_ops */
1711 	NULL,			/* power */
1712 	cmediahd_ddi_quiesce,	/* quiesce */
1713 };
1714 
1715 static struct modldrv cmediahd_modldrv = {
1716 	&mod_driverops,			/* drv_modops */
1717 	"CMedia 8788",			/* linkinfo */
1718 	&cmediahd_dev_ops,		/* dev_ops */
1719 };
1720 
1721 static struct modlinkage modlinkage = {
1722 	MODREV_1,
1723 	{ &cmediahd_modldrv, NULL }
1724 };
1725 
1726 int
1727 _init(void)
1728 {
1729 	int	rv;
1730 
1731 	audio_init_ops(&cmediahd_dev_ops, CMEDIAHD_NAME);
1732 	if ((rv = mod_install(&modlinkage)) != 0) {
1733 		audio_fini_ops(&cmediahd_dev_ops);
1734 	}
1735 	return (rv);
1736 }
1737 
1738 int
1739 _fini(void)
1740 {
1741 	int	rv;
1742 
1743 	if ((rv = mod_remove(&modlinkage)) == 0) {
1744 		audio_fini_ops(&cmediahd_dev_ops);
1745 	}
1746 	return (rv);
1747 }
1748 
1749 int
1750 _info(struct modinfo *modinfop)
1751 {
1752 	return (mod_info(&modlinkage, modinfop));
1753 }
1754 
1755 int
1756 cmediahd_ddi_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1757 {
1758 	switch (cmd) {
1759 	case DDI_ATTACH:
1760 		return (cmediahd_attach(dip));
1761 
1762 	case DDI_RESUME:
1763 		return (cmediahd_resume(dip));
1764 
1765 	default:
1766 		return (DDI_FAILURE);
1767 	}
1768 }
1769 
1770 int
1771 cmediahd_ddi_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1772 {
1773 	cmediahd_devc_t *devc;
1774 
1775 	devc = ddi_get_driver_private(dip);
1776 
1777 	switch (cmd) {
1778 	case DDI_DETACH:
1779 		return (cmediahd_detach(devc));
1780 
1781 	case DDI_SUSPEND:
1782 		return (cmediahd_suspend(devc));
1783 
1784 	default:
1785 		return (DDI_FAILURE);
1786 	}
1787 }
1788 
1789 int
1790 cmediahd_ddi_quiesce(dev_info_t *dip)
1791 {
1792 	cmediahd_devc_t	*devc;
1793 
1794 	devc = ddi_get_driver_private(dip);
1795 
1796 	OUTW(devc, 0x0, DMA_START);
1797 
1798 	/*
1799 	 * Turn off the hardware
1800 	 */
1801 
1802 
1803 	return (DDI_SUCCESS);
1804 }
1805