xref: /openbsd/sys/dev/ic/arcofi.c (revision d89ec533)
1 /*	$OpenBSD: arcofi.c,v 1.17 2016/09/19 22:21:09 kettenis Exp $	*/
2 
3 /*
4  * Copyright (c) 2011 Miodrag Vallat.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * Driver for the HP ``Audio1'' device, which is a FIFO layer around a
21  * Siemens PSB 2160 ``ARCOFI'' phone quality audio chip.
22  *
23  * It is known to exist in two flavours: on-board the HP9000/425e as a DIO
24  * device, an on-board the HP9000/{705,710,745,747} as a GIO device.
25  *
26  * The FIFO logic buffers up to 128 bytes. When using 8 bit samples and
27  * the logic set to interrupt every half FIFO, the device will interrupt
28  * 125 times per second.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/conf.h>
34 #include <sys/device.h>
35 #include <sys/kernel.h>
36 #include <sys/proc.h>
37 #include <sys/endian.h>
38 
39 #include <sys/audioio.h>
40 #include <dev/audio_if.h>
41 
42 #include <machine/autoconf.h>
43 #include <machine/bus.h>
44 #include <machine/intr.h>
45 
46 #include <dev/ic/arcofivar.h>
47 
48 #if 0
49 #define	ARCOFI_DEBUG
50 #endif
51 
52 /*
53  * Siemens PSB2160 registers
54  */
55 
56 /* CMDR */
57 #define	CMDR_AD		0x80	/* SP1/SP2 address convention */
58 #define	CMDR_READ	0x40
59 #define	CMDR_WRITE	0x00
60 #define	CMDR_PU		0x20	/* Power Up */
61 #define	CMDR_RCS	0x10	/* Receive and transmit in CH B2 */
62 #define	CMDR_MASK	0x0f
63 
64 	/* command	     length	data */
65 #define	SOP_0	0x00	/*	5	CR4 CR3 CR2 CR1 */
66 #define	COP_1	0x01	/*	5	t1_hi t1_lo f1_hi f1_lo */
67 #define	COP_2	0x02	/*	3	gr1 gr2 */
68 #define	COP_3	0x03	/*	3	t2_hi t2_lo f2_hi f2_lo */
69 #define	SOP_4	0x04	/*	2	CR1 */
70 #define	SOP_5	0x05	/*	2	CR2 */
71 #define	SOP_6	0x06	/*	2	CR3 */
72 #define	SOP_7	0x07	/*	2	CR4 */
73 #define	COP_8	0x08	/*	3	dtmf_hi dtmf_lo */
74 #define	COP_9	0x09	/*	5	gz a3 a2 a1 */
75 #define	COP_A	0x0a	/*	9	fx1 to fx8 */
76 #define	COP_B	0x0b	/*	3	gx1 gx2 */
77 #define	COP_C	0x0c	/*	9	fr1 to fr 8 */
78 #define	COP_D	0x0d	/*	5	fr9 fr10 fx9 fx10 */
79 #define	COP_E	0x0e	/*	5	t3_hi t3_lo f3_hi f3_lo */
80 
81 /* CR1 */
82 #define	CR1_GR		0x80	/* GR gain loaded from CRAM vs 0dB */
83 #define	CR1_GZ		0x40	/* Z gain loaded from CRAM vs -18dB */
84 #define	CR1_FX		0x20	/* X filter loaded from CRAM vs 0dB flat */
85 #define	CR1_FR		0x10	/* R filter loaded from CRAM vs 0dB flat */
86 #define	CR1_GX		0x08	/* GX gain loaded from CRAM vs 0dB */
87 #define	CR1_T_MASK	0x07	/* test mode */
88 #define	CR1_DLP		0x07	/* digital loopback via PCM registers */
89 #define	CR1_DLM		0x06	/* D/A output looped back to A/D input */
90 #define	CR1_DLS		0x05	/* digital loopback via converter registers */
91 #define	CR1_IDR		0x04	/* data RAM initialization */
92 #define	CR1_BYP		0x03	/* bypass analog frontend */
93 #define	CR1_ALM		0x02	/* analog loopback via MUX */
94 #define	CR1_ALS		0x01	/* analog loopback via converter registers */
95 
96 /* CR2 */
97 #define	CR2_SD		0x80	/* SD pin set to input vs output */
98 #define	CR2_SC		0x40	/* SC pin set to input vs output */
99 #define	CR2_SB		0x20	/* SB pin set to input vs output */
100 #define	CR2_SA		0x10	/* SA pin set to input vs output */
101 #define	CR2_ELS		0x08	/* non-input S pins tristate SIP vs sending 0 */
102 #define	CR2_AM		0x04	/* only one device on the SLD bus */
103 #define	CR2_TR		0x02	/* three party conferencing */
104 #define	CR2_EFC		0x01	/* enable feature control */
105 
106 /* CR3 */
107 #define	CR3_MIC_G_MASK	0xe0		/* MIC input analog gain  */
108 #define	CR3_MIC_X_INPUT		0xe0	/* MIC disabled, X input 15.1 dB */
109 #define	CR3_MIC_G_17		0xc0	/* 17 dB */
110 #define	CR3_MIC_G_22		0xa0	/* 22 dB */
111 #define	CR3_MIC_G_28		0x80	/* 28 dB */
112 #define	CR3_MIC_G_34		0x60	/* 34 dB */
113 #define	CR3_MIC_G_40		0x40	/* 40 dB */
114 #define	CR3_MIC_G_46		0x20	/* 46 dB */
115 #define	CR3_MIC_G_52		0x00	/* 52 dB (reset default) */
116 #define	CR3_AFEC_MASK	0x1c
117 #define	CR3_AFEC_MUTE		0x18	/* mute: Hout */
118 #define	CR3_AFEC_HFS		0x14	/* hands free: FHM, LS out */
119 #define	CR3_AFEC_LH3		0x10	/* loud hearing 3: MIC, H out, LS out */
120 #define	CR3_AFEC_LH2		0x0c	/* loud hearing 2: MIC, LS out */
121 #define	CR3_AFEC_LH1		0x08	/* loud hearing 1: LS out */
122 #define	CR3_AFEC_RDY		0x04	/* ready: MIC, H out */
123 #define	CR3_AFEC_POR		0x00	/* power on reset: all off */
124 #define	CR3_OPMODE_MASK	0x03
125 #define	CR3_OPMODE_LINEAR	0x02	/* linear (16 bit) */
126 #define	CR3_OPMODE_MIXED	0x01	/* mixed */
127 #define	CR3_OPMODE_NORMAL	0x00	/* normal (A/u-Law) */
128 
129 /* CR4 */
130 #define	CR4_DHF		0x80	/* TX digital high frequency enable */
131 #define	CR4_DTMF	0x40	/* DTMF generator enable */
132 #define	CR4_TG		0x20	/* tone ring enable */
133 #define	CR4_BT		0x10	/* beat tone generator enable */
134 #define	CR4_TM		0x08	/* incoming voice enable */
135 #define	CR4_BM		0x04	/* beat mode (3 tone vs 2 tone) */
136 #define	CR4_PM		0x02	/* tone sent to piezo vs loudspeaker */
137 #define	CR4_ULAW	0x01	/* u-Law vs A-Law */
138 
139 
140 /*
141  * Glue logic registers
142  * Note the register values here are symbolic, as actual addresses
143  * depend upon the particular bus the device is connected to.
144  */
145 
146 #define	ARCOFI_ID		0	/* id (r) and reset (w) register */
147 
148 #define	ARCOFI_CSR		1	/* status and control register */
149 #define	CSR_INTR_ENABLE			0x80
150 #define	CSR_INTR_REQUEST		0x40	/* unacknowledged interrupt */
151 /* 0x20 and 0x10 used in DIO flavours, to provide IPL */
152 #define	CSR_WIDTH_16			0x08	/* 16-bit samples */
153 #define	CSR_CTRL_FIFO_ENABLE		0x04	/* connect FIFO to CMDR */
154 #define	CSR_DATA_FIFO_ENABLE		0x01	/* connect FIFO to DU/DD */
155 
156 #define	ARCOFI_FIFO_IR		2	/* FIFO interrupt register */
157 #define	FIFO_IR_ENABLE(ev)		((ev) << 4)
158 #define	FIFO_IR_EVENT(ev)		(ev)
159 #define	FIFO_IR_OUT_EMPTY		0x08
160 #define	FIFO_IR_CTRL_EMPTY		0x04
161 #define	FIFO_IR_OUT_HALF_EMPTY		0x02
162 #define	FIFO_IR_IN_HALF_EMPTY		0x01
163 
164 #define	ARCOFI_FIFO_SR		3	/* FIFO status register (ro) */
165 #define	FIFO_SR_CTRL_FULL		0x20
166 #define	FIFO_SR_CTRL_EMPTY		0x10
167 #define	FIFO_SR_OUT_FULL		0x08
168 #define	FIFO_SR_OUT_EMPTY		0x04
169 #define	FIFO_SR_IN_FULL			0x02
170 #define	FIFO_SR_IN_EMPTY		0x01
171 
172 #define	ARCOFI_FIFO_DATA	4	/* data FIFO port */
173 
174 #define	ARCOFI_FIFO_CTRL	5	/* control FIFO port (wo) */
175 
176 #define	ARCOFI_FIFO_SIZE	128
177 
178 
179 struct cfdriver arcofi_cd = {
180 	NULL, "arcofi", DV_DULL
181 };
182 
183 #define	arcofi_read(sc, r) \
184 	bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (sc)->sc_reg[r])
185 #define	arcofi_write(sc, r, v) \
186 	bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (sc)->sc_reg[r], v)
187 
188 int	arcofi_cmd(struct arcofi_softc *, uint8_t, const uint8_t *);
189 int	arcofi_cr3_to_portmask(uint, int);
190 int	arcofi_gain_to_mi(uint);
191 uint	arcofi_mi_to_gain(int);
192 uint	arcofi_portmask_to_cr3(int);
193 int	arcofi_set_param(struct arcofi_softc *, int, int, int,
194 	    struct audio_params *);
195 
196 void	arcofi_close(void *);
197 int	arcofi_commit_settings(void *);
198 int	arcofi_get_port(void *, mixer_ctrl_t *);
199 int	arcofi_get_props(void *);
200 int	arcofi_halt_input(void *);
201 int	arcofi_halt_output(void *);
202 int	arcofi_open(void *, int);
203 int	arcofi_query_devinfo(void *, mixer_devinfo_t *);
204 int	arcofi_round_blocksize(void *, int);
205 int	arcofi_set_params(void *, int, int, struct audio_params *,
206 	    struct audio_params *);
207 int	arcofi_set_port(void *, mixer_ctrl_t *);
208 int	arcofi_start_input(void *, void *, int, void (*)(void *), void *);
209 int	arcofi_start_output(void *, void *, int, void (*)(void *), void *);
210 
211 /* const */ struct audio_hw_if arcofi_hw_if = {
212 	.open = arcofi_open,
213 	.close = arcofi_close,
214 	.set_params = arcofi_set_params,
215 	.round_blocksize = arcofi_round_blocksize,
216 	.commit_settings = arcofi_commit_settings,
217 	.start_output = arcofi_start_output,
218 	.start_input = arcofi_start_input,
219 	.halt_output = arcofi_halt_output,
220 	.halt_input = arcofi_halt_input,
221 	.set_port = arcofi_set_port,
222 	.get_port = arcofi_get_port,
223 	.query_devinfo = arcofi_query_devinfo,
224 	.get_props = arcofi_get_props,
225 };
226 
227 /* mixer items */
228 #define	ARCOFI_PORT_AUDIO_IN_VOLUME	0	/* line in volume (GR) */
229 #define	ARCOFI_PORT_AUDIO_OUT_VOLUME	1	/* line out volume (GX) */
230 #define	ARCOFI_PORT_AUDIO_SPKR_VOLUME	2	/* speaker volume (GX) */
231 #define	ARCOFI_PORT_AUDIO_IN_MUTE	3	/* line in mute (MIC) */
232 #define	ARCOFI_PORT_AUDIO_OUT_MUTE	4	/* line out mute (H out) */
233 #define	ARCOFI_PORT_AUDIO_SPKR_MUTE	5	/* line in mute (LS out) */
234 /* mixer classes */
235 #define	ARCOFI_CLASS_INPUT		6
236 #define	ARCOFI_CLASS_OUTPUT		7
237 
238 /*
239  * Gain programming formulae are a complete mystery to me, and of course
240  * no two chips are compatible - not even the PSB 2163 and PSB 2165
241  * later ARCOFI chips, from the same manufacturer as the PSB 2160!
242  *
243  * Of course, the PSB 2160 datasheet does not give any set of values.
244  * The following table is taken from the HP-UX audio driver (audio_shared.o
245  * private_audio_gain_tab).
246  */
247 
248 #define	NEGATIVE_GAINS	60
249 #define	POSITIVE_GAINS	14
250 static const uint16_t arcofi_gains[1 + NEGATIVE_GAINS + 1 + POSITIVE_GAINS] = {
251 	/* minus infinity */
252 	0x0988,
253 
254 	0xf8b8, 0xf8b8, 0xf8b8, 0xf8b8, 0x099f, 0x099f, 0x099f, 0x099f,
255 	0x09af, 0x09af, 0x09af, 0x09cf, 0x09cf, 0x09cf, 0xf8a9, 0xf83a,
256 	0xf83a, 0xf82b, 0xf82d, 0xf8a3, 0xf8b2, 0xf8a1, 0xe8aa, 0xe84b,
257 	0xe89e, 0xe8d3, 0xe891, 0xe8b1, 0xd8aa, 0xd8cb, 0xd8a6, 0xd8b3,
258 	0xd842, 0xd8b1, 0xc8aa, 0xc8bb, 0xc888, 0xc853, 0xc852, 0xc8b1,
259 	0xb8aa, 0xb8ab, 0xb896, 0xb892, 0xb842, 0xb8b1, 0xa8aa, 0xa8bb,
260 	0x199f, 0x195b, 0x29c1, 0x2923, 0x29aa, 0x392b, 0xf998, 0xb988,
261 	0x1aac, 0x3aa1, 0xbaa1, 0xbb88,
262 
263 	/* 0 */
264 	0x8888,
265 
266 	0xd388, 0x5288, 0xb1a1, 0x31a1, 0x1192, 0x11d0, 0x30c0, 0x2050,
267 	0x1021, 0x1020, 0x1000, 0x0001, 0x0010, 0x0000
268 };
269 
270 int
271 arcofi_open(void *v, int flags)
272 {
273 	struct arcofi_softc *sc = (struct arcofi_softc *)v;
274 
275 	if (sc->sc_open)
276 		return EBUSY;
277 	sc->sc_open = 1;
278 	KASSERT(sc->sc_mode == 0);
279 
280 	return 0;
281 }
282 
283 void
284 arcofi_close(void *v)
285 {
286 	struct arcofi_softc *sc = (struct arcofi_softc *)v;
287 
288 	arcofi_halt_input(v);
289 	arcofi_halt_output(v);
290 	sc->sc_open = 0;
291 }
292 
293 /*
294  * Compute proper sample and hardware settings. Invoked both for record
295  * and playback, as we don't support independent settings.
296  */
297 int
298 arcofi_set_param(struct arcofi_softc *sc, int set, int use, int mode,
299     struct audio_params *ap)
300 {
301 	if ((set & mode) == 0)
302 		return 0;
303 
304 #ifdef ARCOFI_DEBUG
305 	printf("%s: set_param, mode %d encoding %d precision %d\n",
306 	    sc->sc_dev.dv_xname, mode, ap->encoding, ap->precision);
307 #endif
308 	switch (ap->precision) {
309 	case 8:
310 		switch (ap->encoding) {
311 		case AUDIO_ENCODING_ULAW:
312 			sc->sc_shadow.cr4 |= CR4_ULAW;
313 			break;
314 		case AUDIO_ENCODING_ALAW:
315 			sc->sc_shadow.cr4 &= ~CR4_ULAW;
316 			break;
317 		default:
318 			return EINVAL;
319 		}
320 		sc->sc_shadow.cr3 = (sc->sc_shadow.cr3 & ~CR3_OPMODE_MASK) |
321 		    CR3_OPMODE_NORMAL;
322 		break;
323 	case 16:
324 		switch (ap->encoding) {
325 		case AUDIO_ENCODING_SLINEAR_BE:
326 			break;
327 		default:
328 			return EINVAL;
329 		}
330 		sc->sc_shadow.cr3 = (sc->sc_shadow.cr3 & ~CR3_OPMODE_MASK) |
331 		    CR3_OPMODE_LINEAR;
332 		break;
333 	default:
334 		return EINVAL;
335 	}
336 
337 	ap->bps = AUDIO_BPS(ap->precision);
338 	ap->msb = 1;
339 	ap->channels = 1;
340 	ap->sample_rate = 8000;
341 
342 	return 0;
343 }
344 
345 int
346 arcofi_set_params(void *v, int set, int use, struct audio_params *p,
347     struct audio_params *r)
348 {
349 	struct arcofi_softc *sc = (struct arcofi_softc *)v;
350 	int rc;
351 
352 	if (r != NULL) {
353 		rc = arcofi_set_param(sc, set, use, AUMODE_RECORD, r);
354 		if (rc != 0)
355 			return rc;
356 	}
357 
358 	if (p != NULL) {
359 		rc = arcofi_set_param(sc, set, use, AUMODE_PLAY, p);
360 		if (rc != 0)
361 			return rc;
362 	}
363 
364 	return 0;
365 }
366 
367 int
368 arcofi_round_blocksize(void *v, int blksz)
369 {
370 	/*
371 	 * Round the size up to a multiple of half the FIFO, to favour
372 	 * smooth interrupt operation.
373 	 */
374 	return roundup(blksz, ARCOFI_FIFO_SIZE / 2);
375 }
376 
377 int
378 arcofi_commit_settings(void *v)
379 {
380 	struct arcofi_softc *sc = (struct arcofi_softc *)v;
381 	int rc;
382 	uint8_t cmd[2], csr, ocsr;
383 
384 #ifdef ARCOFI_DEBUG
385 	printf("%s: commit_settings, gr %04x gx %04x cr3 %02x cr4 %02x mute %d\n",
386 	    sc->sc_dev.dv_xname,
387 	    arcofi_gains[sc->sc_shadow.gr_idx],
388 	    arcofi_gains[sc->sc_shadow.gx_idx],
389 	    sc->sc_shadow.cr3, sc->sc_shadow.cr4, sc->sc_shadow.output_mute);
390 #endif
391 
392 	if (bcmp(&sc->sc_active, &sc->sc_shadow, sizeof(sc->sc_active)) == 0)
393 		return 0;
394 
395 	mtx_enter(&audio_lock);
396 
397 	if (sc->sc_active.gr_idx != sc->sc_shadow.gr_idx) {
398 		cmd[0] = arcofi_gains[sc->sc_shadow.gr_idx] >> 8;
399 		cmd[1] = arcofi_gains[sc->sc_shadow.gr_idx];
400 		if ((rc = arcofi_cmd(sc, COP_2, cmd)) != 0)
401 			goto error;
402 		sc->sc_active.gr_idx = sc->sc_shadow.gr_idx;
403 	}
404 
405 	if (sc->sc_active.gx_idx != sc->sc_shadow.gx_idx ||
406 	    sc->sc_active.output_mute != sc->sc_shadow.output_mute) {
407 		if (sc->sc_shadow.output_mute) {
408 			cmd[0] = arcofi_gains[0] >> 8;
409 			cmd[1] = arcofi_gains[0];
410 		} else {
411 			cmd[0] = arcofi_gains[sc->sc_shadow.gx_idx] >> 8;
412 			cmd[1] = arcofi_gains[sc->sc_shadow.gx_idx];
413 		}
414 		if ((rc = arcofi_cmd(sc, COP_B, cmd)) != 0)
415 			goto error;
416 		sc->sc_active.gx_idx = sc->sc_shadow.gx_idx;
417 		sc->sc_active.output_mute = sc->sc_shadow.output_mute;
418 	}
419 
420 	if (sc->sc_active.cr3 != sc->sc_shadow.cr3) {
421 		cmd[0] = sc->sc_shadow.cr3;
422 		if ((rc = arcofi_cmd(sc, SOP_6, cmd)) != 0)
423 			goto error;
424 		sc->sc_active.cr3 = sc->sc_shadow.cr3;
425 
426 		ocsr = arcofi_read(sc, ARCOFI_CSR);
427 		if ((sc->sc_active.cr3 & CR3_OPMODE_MASK) != CR3_OPMODE_NORMAL)
428 			csr = ocsr | CSR_WIDTH_16;
429 		else
430 			csr = ocsr & ~CSR_WIDTH_16;
431 		if (csr != ocsr)
432 			arcofi_write(sc, ARCOFI_CSR, csr);
433 	}
434 
435 	if (sc->sc_active.cr4 != sc->sc_shadow.cr4) {
436 		cmd[0] = sc->sc_shadow.cr4;
437 		if ((rc = arcofi_cmd(sc, SOP_7, cmd)) != 0)
438 			goto error;
439 		sc->sc_active.cr4 = sc->sc_shadow.cr4;
440 	}
441 
442 	rc = 0;
443 error:
444 	mtx_leave(&audio_lock);
445 	return rc;
446 }
447 
448 int
449 arcofi_start_input(void *v, void *rbuf, int rsz, void (*cb)(void *),
450     void *cbarg)
451 {
452 	struct arcofi_softc *sc = (struct arcofi_softc *)v;
453 
454 #ifdef ARCOFI_DEBUG
455 	printf("%s: start_input, mode %d\n",
456 	    sc->sc_dev.dv_xname, sc->sc_mode);
457 #endif
458 
459 	/* enable data FIFO if becoming active */
460 	if (sc->sc_mode == 0)
461 		arcofi_write(sc, ARCOFI_CSR,
462 		    arcofi_read(sc, ARCOFI_CSR) | CSR_DATA_FIFO_ENABLE);
463 	sc->sc_mode |= AUMODE_RECORD;
464 
465 	sc->sc_recv.buf = (uint8_t *)rbuf;
466 	sc->sc_recv.past = (uint8_t *)rbuf + rsz;
467 	sc->sc_recv.cb = cb;
468 	sc->sc_recv.cbarg = cbarg;
469 
470 	/* enable input FIFO interrupts */
471 	arcofi_write(sc, ARCOFI_FIFO_IR, arcofi_read(sc, ARCOFI_FIFO_IR) |
472 	    FIFO_IR_ENABLE(FIFO_IR_IN_HALF_EMPTY));
473 
474 	return 0;
475 }
476 
477 int
478 arcofi_start_output(void *v, void *wbuf, int wsz, void (*cb)(void *),
479     void *cbarg)
480 {
481 	struct arcofi_softc *sc = (struct arcofi_softc *)v;
482 
483 #ifdef ARCOFI_DEBUG
484 	printf("%s: start_output, mode %d\n",
485 	    sc->sc_dev.dv_xname, sc->sc_mode);
486 #endif
487 
488 	/* enable data FIFO if becoming active */
489 	if (sc->sc_mode == 0)
490 		arcofi_write(sc, ARCOFI_CSR,
491 		    arcofi_read(sc, ARCOFI_CSR) | CSR_DATA_FIFO_ENABLE);
492 	sc->sc_mode |= AUMODE_PLAY;
493 
494 	sc->sc_xmit.buf = (uint8_t *)wbuf;
495 	sc->sc_xmit.past = (uint8_t *)wbuf + wsz;
496 	sc->sc_xmit.cb = cb;
497 	sc->sc_xmit.cbarg = cbarg;
498 
499 	/* enable output FIFO interrupts */
500 	arcofi_write(sc, ARCOFI_FIFO_IR, arcofi_read(sc, ARCOFI_FIFO_IR) |
501 	    FIFO_IR_ENABLE(FIFO_IR_OUT_HALF_EMPTY));
502 
503 	return 0;
504 }
505 
506 int
507 arcofi_halt_input(void *v)
508 {
509 	struct arcofi_softc *sc = (struct arcofi_softc *)v;
510 
511 	mtx_enter(&audio_lock);
512 
513 	/* disable input FIFO interrupts */
514 	arcofi_write(sc, ARCOFI_FIFO_IR, arcofi_read(sc, ARCOFI_FIFO_IR) &
515 	    ~FIFO_IR_ENABLE(FIFO_IR_IN_HALF_EMPTY));
516 	/* disable data FIFO if becoming idle */
517 	sc->sc_mode &= ~AUMODE_RECORD;
518 	if (sc->sc_mode == 0)
519 		arcofi_write(sc, ARCOFI_CSR,
520 		    arcofi_read(sc, ARCOFI_CSR) & ~CSR_DATA_FIFO_ENABLE);
521 
522 	mtx_leave(&audio_lock);
523 	return 0;
524 }
525 
526 int
527 arcofi_halt_output(void *v)
528 {
529 	struct arcofi_softc *sc = (struct arcofi_softc *)v;
530 
531 	mtx_enter(&audio_lock);
532 
533 	/* disable output FIFO interrupts */
534 	arcofi_write(sc, ARCOFI_FIFO_IR, arcofi_read(sc, ARCOFI_FIFO_IR) &
535 	    ~FIFO_IR_ENABLE(FIFO_IR_OUT_HALF_EMPTY));
536 	/* disable data FIFO if becoming idle */
537 	sc->sc_mode &= ~AUMODE_PLAY;
538 	if (sc->sc_mode == 0)
539 		arcofi_write(sc, ARCOFI_CSR,
540 		    arcofi_read(sc, ARCOFI_CSR) & ~CSR_DATA_FIFO_ENABLE);
541 
542 	mtx_leave(&audio_lock);
543 	return 0;
544 }
545 
546 /*
547  * Convert gain table index to AUDIO_MIN_GAIN..AUDIO_MAX_GAIN scale.
548  */
549 int
550 arcofi_gain_to_mi(uint idx)
551 {
552 	if (idx == 0)
553 		return AUDIO_MIN_GAIN;
554 	if (idx == nitems(arcofi_gains) - 1)
555 		return AUDIO_MAX_GAIN;
556 
557 	return ((idx - 1) * (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)) /
558 	    (nitems(arcofi_gains) - 1) + AUDIO_MIN_GAIN + 1;
559 }
560 
561 /*
562  * Convert AUDIO_MIN_GAIN..AUDIO_MAX_GAIN scale to gain table index.
563  */
564 uint
565 arcofi_mi_to_gain(int lvl)
566 {
567 	if (lvl <= AUDIO_MIN_GAIN)
568 		return 0;
569 	if (lvl >= AUDIO_MAX_GAIN)
570 		return nitems(arcofi_gains) - 1;
571 
572 	return ((lvl - AUDIO_MIN_GAIN - 1) * (nitems(arcofi_gains) - 1)) /
573 	    (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN);
574 }
575 
576 /*
577  * Input and output ports definition (used to be in <audioio.h>
578  */
579 #define	AUDIO_SPEAKER		0x01	/* built-in speaker */
580 #define	AUDIO_LINE_IN		0x02	/* line in	 */
581 #define	AUDIO_LINE_OUT		0x04	/* line out	 */
582 
583 /*
584  * The mapping between the available inputs and outputs, and CR3, is as
585  * follows:
586  * - the `line in' connector is the `MIC' input.
587  * - the `line out' connector is the `H out' (heaphones) output.
588  * - the internal `speaker' is the `LS out' (loudspeaker) output.
589  *
590  * Each of these can be enabled or disabled independently, except for
591  * MIC enabled with H out and LS out disabled, which is not allowed
592  * by the chip (and makes no sense for a chip which was intended to
593  * be used in phones, not voice recorders); we cheat by keeping one
594  * output source enabled, but with the output gain forced to minus
595  * infinity to mute it.
596  *
597  * The truth table is thus:
598  *
599  *	MIC	LS out	H out	AFEC
600  *	off	off	off	POR
601  *	off	off	on	MUTE
602  *	off	on	off	LH1
603  *	off	on	on	LH3, X input enabled
604  *	on	off	off	RDY, GX forced to minus infinity
605  *	on	off	on	RDY
606  *	on	on	off	LH2
607  *	on	on	on	LH3
608  */
609 
610 /*
611  * Convert logical port enable settings to a valid CR3 value.
612  */
613 uint
614 arcofi_portmask_to_cr3(int mask)
615 {
616 	switch (mask) {
617 	default:
618 	case 0:
619 		return CR3_MIC_G_17 | CR3_AFEC_POR;
620 	case AUDIO_LINE_OUT:
621 		return CR3_MIC_G_17 | CR3_AFEC_MUTE;
622 	case AUDIO_SPEAKER:
623 		return CR3_MIC_G_17 | CR3_AFEC_LH1;
624 	case AUDIO_SPEAKER | AUDIO_LINE_OUT:
625 		return CR3_MIC_X_INPUT | CR3_AFEC_LH3;
626 	case AUDIO_LINE_IN:
627 		/* since we can't do this, just... */
628 		/* FALLTHROUGH */
629 	case AUDIO_LINE_IN | AUDIO_LINE_OUT:
630 		return CR3_MIC_G_17 | CR3_AFEC_RDY;
631 	case AUDIO_LINE_IN | AUDIO_SPEAKER:
632 		return CR3_MIC_G_17 | CR3_AFEC_LH2;
633 	case AUDIO_LINE_IN | AUDIO_SPEAKER | AUDIO_LINE_OUT:
634 		return CR3_MIC_G_17 | CR3_AFEC_LH3;
635 	}
636 }
637 
638 /*
639  * Convert CR3 to an enabled ports mask.
640  */
641 int
642 arcofi_cr3_to_portmask(uint cr3, int output_mute)
643 {
644 	switch (cr3 & CR3_AFEC_MASK) {
645 	default:
646 	case CR3_AFEC_POR:
647 		return 0;
648 	case CR3_AFEC_RDY:
649 		return output_mute ?
650 		    AUDIO_LINE_IN : AUDIO_LINE_IN | AUDIO_LINE_OUT;
651 	case CR3_AFEC_HFS:
652 	case CR3_AFEC_LH1:
653 		return AUDIO_SPEAKER;
654 	case CR3_AFEC_LH2:
655 		return AUDIO_LINE_IN | AUDIO_SPEAKER;
656 	case CR3_AFEC_LH3:
657 		if ((cr3 & CR3_MIC_G_MASK) == CR3_MIC_X_INPUT)
658 			return AUDIO_SPEAKER | AUDIO_LINE_OUT;
659 		else
660 			return AUDIO_LINE_IN | AUDIO_SPEAKER | AUDIO_LINE_OUT;
661 	case CR3_AFEC_MUTE:
662 		return AUDIO_LINE_OUT;
663 	}
664 }
665 
666 int
667 arcofi_set_port(void *v, mixer_ctrl_t *mc)
668 {
669 	struct arcofi_softc *sc = (struct arcofi_softc *)v;
670 	int portmask;
671 
672 	/* check for proper type */
673 	switch (mc->dev) {
674 	/* volume settings */
675 	case ARCOFI_PORT_AUDIO_IN_VOLUME:
676 	case ARCOFI_PORT_AUDIO_OUT_VOLUME:
677 	case ARCOFI_PORT_AUDIO_SPKR_VOLUME:
678 		if (mc->un.value.num_channels != 1)
679 			return EINVAL;
680 		break;
681 	/* mute settings */
682 	case ARCOFI_PORT_AUDIO_IN_MUTE:
683 	case ARCOFI_PORT_AUDIO_OUT_MUTE:
684 	case ARCOFI_PORT_AUDIO_SPKR_MUTE:
685 		if (mc->type != AUDIO_MIXER_ENUM)
686 			return EINVAL;
687 		portmask = arcofi_cr3_to_portmask(sc->sc_shadow.cr3,
688 		    sc->sc_shadow.output_mute);
689 #ifdef ARCOFI_DEBUG
690 		printf("%s: set_port cr3 %02x -> mask %02x\n",
691 		    sc->sc_dev.dv_xname, sc->sc_shadow.cr3, portmask);
692 #endif
693 		break;
694 	default:
695 		return EINVAL;
696 	}
697 
698 	switch (mc->dev) {
699 	/* volume settings */
700 	case ARCOFI_PORT_AUDIO_IN_VOLUME:
701 		sc->sc_shadow.gr_idx =
702 		    arcofi_mi_to_gain(mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
703 		return 0;
704 	case ARCOFI_PORT_AUDIO_OUT_VOLUME:
705 	case ARCOFI_PORT_AUDIO_SPKR_VOLUME:
706 		sc->sc_shadow.gx_idx =
707 		    arcofi_mi_to_gain(mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
708 		return 0;
709 
710 	/* mute settings */
711 	case ARCOFI_PORT_AUDIO_IN_MUTE:
712 		if (mc->un.ord)
713 			portmask &= ~AUDIO_LINE_IN;
714 		else
715 			portmask |= AUDIO_LINE_IN;
716 		break;
717 	case ARCOFI_PORT_AUDIO_OUT_MUTE:
718 		if (mc->un.ord)
719 			portmask &= ~AUDIO_LINE_OUT;
720 		else
721 			portmask |= AUDIO_LINE_OUT;
722 		break;
723 	case ARCOFI_PORT_AUDIO_SPKR_MUTE:
724 		if (mc->un.ord)
725 			portmask &= ~AUDIO_SPEAKER;
726 		else
727 			portmask |= AUDIO_SPEAKER;
728 		break;
729 	}
730 
731 	sc->sc_shadow.cr3 = (sc->sc_shadow.cr3 & CR3_OPMODE_MASK) |
732 	    arcofi_portmask_to_cr3(portmask);
733 	sc->sc_shadow.output_mute = (portmask == AUDIO_LINE_IN);
734 #ifdef ARCOFI_DEBUG
735 	printf("%s: set_port mask %02x -> cr3 %02x m %d\n",
736 	    sc->sc_dev.dv_xname, portmask,
737 	    sc->sc_shadow.cr3, sc->sc_shadow.output_mute);
738 #endif
739 
740 	return 0;
741 }
742 
743 int
744 arcofi_get_port(void *v, mixer_ctrl_t *mc)
745 {
746 	struct arcofi_softc *sc = (struct arcofi_softc *)v;
747 	int portmask;
748 
749 	/* check for proper type */
750 	switch (mc->dev) {
751 	/* volume settings */
752 	case ARCOFI_PORT_AUDIO_IN_VOLUME:
753 	case ARCOFI_PORT_AUDIO_OUT_VOLUME:
754 	case ARCOFI_PORT_AUDIO_SPKR_VOLUME:
755 		if (mc->un.value.num_channels != 1)
756 			return EINVAL;
757 		break;
758 
759 	/* mute settings */
760 	case ARCOFI_PORT_AUDIO_IN_MUTE:
761 	case ARCOFI_PORT_AUDIO_OUT_MUTE:
762 	case ARCOFI_PORT_AUDIO_SPKR_MUTE:
763 		if (mc->type != AUDIO_MIXER_ENUM)
764 			return EINVAL;
765 		portmask = arcofi_cr3_to_portmask(sc->sc_shadow.cr3,
766 		    sc->sc_shadow.output_mute);
767 #ifdef ARCOFI_DEBUG
768 		printf("%s: get_port cr3 %02x -> mask %02x\n",
769 		    sc->sc_dev.dv_xname, sc->sc_shadow.cr3, portmask);
770 #endif
771 		break;
772 	default:
773 		return EINVAL;
774 	}
775 
776 	switch (mc->dev) {
777 	/* volume settings */
778 	case ARCOFI_PORT_AUDIO_IN_VOLUME:
779 		mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
780 		    arcofi_gain_to_mi(sc->sc_shadow.gr_idx);
781 		break;
782 	case ARCOFI_PORT_AUDIO_OUT_VOLUME:
783 	case ARCOFI_PORT_AUDIO_SPKR_VOLUME:
784 		mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
785 		    arcofi_gain_to_mi(sc->sc_shadow.gx_idx);
786 		break;
787 
788 	/* mute settings */
789 	case ARCOFI_PORT_AUDIO_IN_MUTE:
790 		mc->un.ord = portmask & AUDIO_LINE_IN ? 0 : 1;
791 		break;
792 	case ARCOFI_PORT_AUDIO_OUT_MUTE:
793 		mc->un.ord = portmask & AUDIO_LINE_OUT ? 0 : 1;
794 		break;
795 	case ARCOFI_PORT_AUDIO_SPKR_MUTE:
796 		mc->un.ord = portmask & AUDIO_SPEAKER ? 0 : 1;
797 		break;
798 	}
799 
800 	return 0;
801 }
802 
803 int
804 arcofi_query_devinfo(void *v, mixer_devinfo_t *md)
805 {
806 	switch (md->index) {
807 	default:
808 		return ENXIO;
809 
810 	/* items */
811 	case ARCOFI_PORT_AUDIO_IN_VOLUME:
812 		md->type = AUDIO_MIXER_VALUE;
813 		md->mixer_class = ARCOFI_CLASS_INPUT;
814 		md->prev = AUDIO_MIXER_LAST;
815 		md->next = ARCOFI_PORT_AUDIO_IN_MUTE;
816 		strlcpy(md->label.name, AudioNline,
817 		    sizeof md->label.name);
818 		goto mono_volume;
819 	case ARCOFI_PORT_AUDIO_OUT_VOLUME:
820 		md->type = AUDIO_MIXER_VALUE;
821 		md->mixer_class = ARCOFI_CLASS_OUTPUT;
822 		md->prev = AUDIO_MIXER_LAST;
823 		md->next = ARCOFI_PORT_AUDIO_OUT_MUTE;
824 		strlcpy(md->label.name, AudioNline,
825 		    sizeof md->label.name);
826 		goto mono_volume;
827 	case ARCOFI_PORT_AUDIO_SPKR_VOLUME:
828 		md->type = AUDIO_MIXER_VALUE;
829 		md->mixer_class = ARCOFI_CLASS_OUTPUT;
830 		md->prev = AUDIO_MIXER_LAST;
831 		md->next = ARCOFI_PORT_AUDIO_SPKR_MUTE;
832 		strlcpy(md->label.name, AudioNspeaker,
833 		    sizeof md->label.name);
834 		/* goto mono_volume; */
835 mono_volume:
836 		md->un.v.num_channels = 1;
837 		strlcpy(md->un.v.units.name, AudioNvolume,
838 		    sizeof md->un.v.units.name);
839 		break;
840 
841 	case ARCOFI_PORT_AUDIO_IN_MUTE:
842 		md->type = AUDIO_MIXER_ENUM;
843 		md->mixer_class = ARCOFI_CLASS_INPUT;
844 		md->prev = ARCOFI_PORT_AUDIO_IN_VOLUME;
845 		md->next = AUDIO_MIXER_LAST;
846 		goto mute;
847 	case ARCOFI_PORT_AUDIO_OUT_MUTE:
848 		md->type = AUDIO_MIXER_ENUM;
849 		md->mixer_class = ARCOFI_CLASS_OUTPUT;
850 		md->prev = ARCOFI_PORT_AUDIO_OUT_VOLUME;
851 		md->next = AUDIO_MIXER_LAST;
852 		goto mute;
853 	case ARCOFI_PORT_AUDIO_SPKR_MUTE:
854 		md->type = AUDIO_MIXER_ENUM;
855 		md->mixer_class = ARCOFI_CLASS_OUTPUT;
856 		md->prev = ARCOFI_PORT_AUDIO_SPKR_VOLUME;
857 		md->next = AUDIO_MIXER_LAST;
858 		/* goto mute; */
859 mute:
860 		strlcpy(md->label.name, AudioNmute, sizeof md->label.name);
861 		md->un.e.num_mem = 2;
862 		strlcpy(md->un.e.member[0].label.name, AudioNoff,
863 		    sizeof md->un.e.member[0].label.name);
864 		md->un.e.member[0].ord = 0;
865 		strlcpy(md->un.e.member[1].label.name, AudioNon,
866 		    sizeof md->un.e.member[1].label.name);
867 		md->un.e.member[1].ord = 1;
868 		break;
869 
870 	/* classes */
871 	case ARCOFI_CLASS_INPUT:
872 		md->type = AUDIO_MIXER_CLASS;
873 		md->mixer_class = ARCOFI_CLASS_INPUT;
874 		md->prev = AUDIO_MIXER_LAST;
875 		md->next = AUDIO_MIXER_LAST;
876 		strlcpy(md->label.name, AudioCinputs,
877 		    sizeof md->label.name);
878 		break;
879 	case ARCOFI_CLASS_OUTPUT:
880 		md->type = AUDIO_MIXER_CLASS;
881 		md->mixer_class = ARCOFI_CLASS_OUTPUT;
882 		md->prev = AUDIO_MIXER_LAST;
883 		md->next = AUDIO_MIXER_LAST;
884 		strlcpy(md->label.name, AudioCoutputs,
885 		    sizeof md->label.name);
886 		break;
887 	}
888 
889 	return 0;
890 }
891 
892 int
893 arcofi_get_props(void *v)
894 {
895 	return 0;
896 }
897 
898 int
899 arcofi_hwintr(void *v)
900 {
901 	struct arcofi_softc *sc = (struct arcofi_softc *)v;
902 	uint8_t *cur, *past;
903 	uint8_t csr, fir, data;
904 	int rc = 0;
905 
906 	csr = arcofi_read(sc, ARCOFI_CSR);
907 	if ((csr & CSR_INTR_REQUEST) == 0)
908 		return 0;
909 
910 	fir = arcofi_read(sc, ARCOFI_FIFO_IR);
911 
912 	/* receive */
913 	if (fir & FIFO_IR_EVENT(FIFO_IR_IN_HALF_EMPTY)) {
914 		rc = 1;
915 		cur = sc->sc_recv.buf;
916 		past = sc->sc_recv.past;
917 
918 		while ((arcofi_read(sc, ARCOFI_FIFO_SR) &
919 		    FIFO_SR_IN_EMPTY) == 0) {
920 			data = arcofi_read(sc, ARCOFI_FIFO_DATA);
921 			if (cur != NULL && cur != past) {
922 				*cur++ = data;
923 				if (cur == past) {
924 					softintr_schedule(sc->sc_sih);
925 					break;
926 				}
927 			}
928 		}
929 		sc->sc_recv.buf = cur;
930 
931 		if (cur == NULL || cur == past) {
932 			/* underrun, disable further interrupts */
933 			arcofi_write(sc, ARCOFI_FIFO_IR,
934 			    arcofi_read(sc, ARCOFI_FIFO_IR) &
935 			    ~FIFO_IR_ENABLE(FIFO_IR_IN_HALF_EMPTY));
936 		}
937 	}
938 
939 	/* xmit */
940 	if (fir & FIFO_IR_EVENT(FIFO_IR_OUT_HALF_EMPTY)) {
941 		rc = 1;
942 		cur = sc->sc_xmit.buf;
943 		past = sc->sc_xmit.past;
944 		if (cur != NULL) {
945 			while ((arcofi_read(sc, ARCOFI_FIFO_SR) &
946 			    FIFO_SR_OUT_FULL) == 0) {
947 				if (cur != past)
948 					arcofi_write(sc, ARCOFI_FIFO_DATA,
949 					    *cur++);
950 				if (cur == past) {
951 					softintr_schedule(sc->sc_sih);
952 					break;
953 				}
954 			}
955 		}
956 		if (cur == NULL || cur == past) {
957 			/* disable further interrupts */
958 			arcofi_write(sc, ARCOFI_FIFO_IR,
959 			    arcofi_read(sc, ARCOFI_FIFO_IR) &
960 			    ~FIFO_IR_ENABLE(FIFO_IR_OUT_HALF_EMPTY));
961 		}
962 		sc->sc_xmit.buf = cur;
963 	}
964 
965 	/* drain */
966 	if (fir & FIFO_IR_EVENT(FIFO_IR_OUT_EMPTY)) {
967 		rc = 1;
968 		arcofi_write(sc, ARCOFI_FIFO_IR,
969 		    arcofi_read(sc, ARCOFI_FIFO_IR) &
970 		    ~FIFO_IR_ENABLE(FIFO_IR_OUT_EMPTY));
971 		wakeup(&sc->sc_xmit);
972 	}
973 
974 #ifdef ARCOFI_DEBUG
975 	if (rc == 0)
976 		printf("%s: unclaimed interrupt, csr %02x fir %02x fsr %02x\n",
977 		    sc->sc_dev.dv_xname, csr, fir,
978 		    arcofi_read(sc, ARCOFI_FIFO_SR));
979 #endif
980 
981 	return rc;
982 }
983 
984 void
985 arcofi_swintr(void *v)
986 {
987 	struct arcofi_softc *sc = (struct arcofi_softc *)v;
988 	int action;
989 
990 	action = 0;
991 	mtx_enter(&audio_lock);
992 	if (sc->sc_recv.buf != NULL && sc->sc_recv.buf == sc->sc_recv.past)
993 		action |= AUMODE_RECORD;
994 	if (sc->sc_xmit.buf != NULL && sc->sc_xmit.buf == sc->sc_xmit.past)
995 		action |= AUMODE_PLAY;
996 
997 	if (action & AUMODE_RECORD) {
998 		if (sc->sc_recv.cb)
999 			sc->sc_recv.cb(sc->sc_recv.cbarg);
1000 	}
1001 	if (action & AUMODE_PLAY) {
1002 		if (sc->sc_xmit.cb)
1003 			sc->sc_xmit.cb(sc->sc_xmit.cbarg);
1004 	}
1005 	mtx_leave(&audio_lock);
1006 }
1007 
1008 int
1009 arcofi_cmd(struct arcofi_softc *sc, uint8_t cmd, const uint8_t *data)
1010 {
1011 	size_t len;
1012 	uint8_t csr;
1013 	int cnt;
1014 	static const uint8_t cmdlen[] = {
1015 	    [SOP_0] = 4,
1016 	    [COP_1] = 4,
1017 	    [COP_2] = 2,
1018 	    [COP_3] = 2,
1019 	    [SOP_4] = 1,
1020 	    [SOP_5] = 1,
1021 	    [SOP_6] = 1,
1022 	    [SOP_7] = 1,
1023 	    [COP_8] = 2,
1024 	    [COP_9] = 4,
1025 	    [COP_A] = 8,
1026 	    [COP_B] = 2,
1027 	    [COP_C] = 8,
1028 	    [COP_D] = 4,
1029 	    [COP_E] = 4
1030 	};
1031 
1032 	/*
1033 	 * Compute command length.
1034 	 */
1035 	if (cmd >= nitems(cmdlen))
1036 		return EINVAL;
1037 	len = cmdlen[cmd];
1038 
1039 	mtx_enter(&audio_lock);
1040 
1041 	/*
1042 	 * Disable all FIFO processing.
1043 	 */
1044 	csr = arcofi_read(sc, ARCOFI_CSR);
1045 	arcofi_write(sc, ARCOFI_CSR,
1046 	    csr & ~(CSR_DATA_FIFO_ENABLE | CSR_CTRL_FIFO_ENABLE));
1047 
1048 	/*
1049 	 * Fill the FIFO with the command bytes.
1050 	 */
1051 	arcofi_write(sc, ARCOFI_FIFO_CTRL, CMDR_PU | CMDR_WRITE | cmd);
1052 	for (; len != 0; len--)
1053 		arcofi_write(sc, ARCOFI_FIFO_CTRL, *data++);
1054 
1055 	/*
1056 	 * Enable command processing.
1057 	 */
1058 	arcofi_write(sc, ARCOFI_CSR,
1059 	    (csr & ~CSR_DATA_FIFO_ENABLE) | CSR_CTRL_FIFO_ENABLE);
1060 
1061 	/*
1062 	 * Wait for the command FIFO to be empty.
1063 	 */
1064 	cnt = 100;
1065 	while ((arcofi_read(sc, ARCOFI_FIFO_SR) & FIFO_SR_CTRL_EMPTY) == 0) {
1066 		if (cnt-- == 0) {
1067 			mtx_leave(&audio_lock);
1068 			return EBUSY;
1069 		}
1070 		delay(10);
1071 	}
1072 
1073 	arcofi_write(sc, ARCOFI_CSR, csr);
1074 
1075 	mtx_leave(&audio_lock);
1076 	return 0;
1077 }
1078 
1079 void
1080 arcofi_attach(struct arcofi_softc *sc, const char *version)
1081 {
1082 	int rc;
1083 	uint8_t cmd[4];
1084 
1085 	/*
1086 	 * Reset logic.
1087 	 */
1088 	arcofi_write(sc, ARCOFI_ID, 0);
1089 	delay(100000);
1090 	arcofi_write(sc, ARCOFI_CSR, 0);
1091 
1092 	/*
1093 	 * Initialize the chip to default settings (8 bit, u-Law).
1094 	 */
1095 	sc->sc_active.cr3 =
1096 	    arcofi_portmask_to_cr3(AUDIO_SPEAKER) | CR3_OPMODE_NORMAL;
1097 	sc->sc_active.cr4 = CR4_TM | CR4_ULAW;
1098 	sc->sc_active.gr_idx = sc->sc_active.gx_idx = 1 + NEGATIVE_GAINS;
1099 	sc->sc_active.output_mute = 0;
1100 	bcopy(&sc->sc_active, &sc->sc_shadow, sizeof(sc->sc_active));
1101 
1102 	/* clear CRAM */
1103 	cmd[0] = CR1_IDR;
1104 	if ((rc = arcofi_cmd(sc, SOP_4, cmd)) != 0)
1105 		goto error;
1106 	delay(1000);
1107 
1108 	/* set gain values before enabling them in CR1 */
1109 	cmd[0] = arcofi_gains[sc->sc_active.gr_idx] >> 8;
1110 	cmd[1] = arcofi_gains[sc->sc_active.gr_idx];
1111 	if ((rc = arcofi_cmd(sc, COP_2, cmd)) != 0)
1112 		goto error;
1113 	/* same value for gx... */
1114 	if ((rc = arcofi_cmd(sc, COP_B, cmd)) != 0)
1115 		goto error;
1116 
1117 	/* set all CR registers at once */
1118 	cmd[0] = sc->sc_active.cr4;
1119 	cmd[1] = sc->sc_active.cr3;
1120 	cmd[2] = CR2_SD | CR2_SC | CR2_SB | CR2_SA | CR2_ELS | CR2_AM | CR2_EFC;
1121 	cmd[3] = CR1_GR | CR1_GX;
1122 	if ((rc = arcofi_cmd(sc, SOP_0, cmd)) != 0)
1123 		goto error;
1124 
1125 	arcofi_write(sc, ARCOFI_FIFO_IR, 0);
1126 	arcofi_write(sc, ARCOFI_CSR, CSR_INTR_ENABLE);
1127 
1128 	audio_attach_mi(&arcofi_hw_if, sc, &sc->sc_dev);
1129 	return;
1130 
1131 error:
1132 	arcofi_write(sc, ARCOFI_ID, 0);
1133 	printf("%s: command failed, error %d\n", __func__, rc);
1134 }
1135