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