FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/ad1848.c
1 /* $NetBSD: ad1848.c,v 1.20 2005/01/15 15:19:52 kent Exp $ */
2
3 /*-
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Ken Hornstein and John Kohl.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38 /*
39 * Copyright (c) 1994 John Brezak
40 * Copyright (c) 1991-1993 Regents of the University of California.
41 * All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by the Computer Systems
54 * Engineering Group at Lawrence Berkeley Laboratory.
55 * 4. Neither the name of the University nor of the Laboratory may be used
56 * to endorse or promote products derived from this software without
57 * specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * SUCH DAMAGE.
70 *
71 */
72
73 /*
74 * Copyright by Hannu Savolainen 1994
75 *
76 * Redistribution and use in source and binary forms, with or without
77 * modification, are permitted provided that the following conditions are
78 * met: 1. Redistributions of source code must retain the above copyright
79 * notice, this list of conditions and the following disclaimer. 2.
80 * Redistributions in binary form must reproduce the above copyright notice,
81 * this list of conditions and the following disclaimer in the documentation
82 * and/or other materials provided with the distribution.
83 *
84 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
85 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
86 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
87 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
88 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
89 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
90 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
91 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
92 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
93 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
94 * SUCH DAMAGE.
95 *
96 */
97 /*
98 * Portions of this code are from the VOXware support for the ad1848
99 * by Hannu Savolainen <hannu@voxware.pp.fi>
100 *
101 * Portions also supplied from the SoundBlaster driver for NetBSD.
102 */
103
104 #include <sys/cdefs.h>
105 __KERNEL_RCSID(0, "$NetBSD: ad1848.c,v 1.20 2005/01/15 15:19:52 kent Exp $");
106
107 #include <sys/param.h>
108 #include <sys/systm.h>
109 #include <sys/errno.h>
110 #include <sys/ioctl.h>
111 #include <sys/device.h>
112 #include <sys/fcntl.h>
113 /*#include <sys/syslog.h>*/
114 /*#include <sys/proc.h>*/
115
116 #include <machine/cpu.h>
117 #include <machine/bus.h>
118
119 #include <sys/audioio.h>
120
121 #include <dev/audio_if.h>
122 #include <dev/auconv.h>
123
124 #include <dev/ic/ad1848reg.h>
125 #include <dev/ic/cs4231reg.h>
126 #include <dev/ic/cs4237reg.h>
127 #include <dev/ic/ad1848var.h>
128 #if 0
129 #include <dev/isa/cs4231var.h>
130 #endif
131
132 /*
133 * AD1845 on some machines don't match the AD1845 doc
134 * and defining AD1845_HACK to 1 works around the problems.
135 * options AD1845_HACK=0 should work if you have ``correct'' one.
136 */
137 #ifndef AD1845_HACK
138 #define AD1845_HACK 1 /* weird mixer, can't play slinear_be */
139 #endif
140
141 #ifdef AUDIO_DEBUG
142 #define DPRINTF(x) if (ad1848debug) printf x
143 int ad1848debug = 0;
144 #else
145 #define DPRINTF(x)
146 #endif
147
148 /*
149 * Initial values for the indirect registers of CS4248/AD1848.
150 */
151 static const int ad1848_init_values[] = {
152 GAIN_12|INPUT_MIC_GAIN_ENABLE, /* Left Input Control */
153 GAIN_12|INPUT_MIC_GAIN_ENABLE, /* Right Input Control */
154 ATTEN_12, /* Left Aux #1 Input Control */
155 ATTEN_12, /* Right Aux #1 Input Control */
156 ATTEN_12, /* Left Aux #2 Input Control */
157 ATTEN_12, /* Right Aux #2 Input Control */
158 /* bits 5-0 are attenuation select */
159 ATTEN_12, /* Left DAC output Control */
160 ATTEN_12, /* Right DAC output Control */
161 CLOCK_XTAL1|FMT_PCM8, /* Clock and Data Format */
162 SINGLE_DMA|AUTO_CAL_ENABLE, /* Interface Config */
163 INTERRUPT_ENABLE, /* Pin control */
164 0x00, /* Test and Init */
165 MODE2, /* Misc control */
166 ATTEN_0<<2, /* Digital Mix Control */
167 0, /* Upper base Count */
168 0, /* Lower base Count */
169
170 /* These are for CS4231 &c. only (additional registers): */
171 0, /* Alt feature 1 */
172 0, /* Alt feature 2 */
173 ATTEN_12, /* Left line in */
174 ATTEN_12, /* Right line in */
175 0, /* Timer low */
176 0, /* Timer high */
177 0, /* unused */
178 0, /* unused */
179 0, /* IRQ status */
180 0, /* unused */
181 /* Mono input (a.k.a speaker) (mic) Control */
182 MONO_INPUT_MUTE|ATTEN_6, /* mute speaker by default */
183 0, /* unused */
184 0, /* record format */
185 0, /* Crystal Clock Select */
186 0, /* upper record count */
187 0 /* lower record count */
188 };
189
190
191 int
192 ad1848_to_vol(mixer_ctrl_t *cp, struct ad1848_volume *vol)
193 {
194
195 if (cp->un.value.num_channels == 1) {
196 vol->left =
197 vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
198 return 1;
199 }
200 else if (cp->un.value.num_channels == 2) {
201 vol->left = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
202 vol->right = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
203 return 1;
204 }
205 return 0;
206 }
207
208 int
209 ad1848_from_vol(mixer_ctrl_t *cp, struct ad1848_volume *vol)
210 {
211
212 if (cp->un.value.num_channels == 1) {
213 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = vol->left;
214 return 1;
215 }
216 else if (cp->un.value.num_channels == 2) {
217 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = vol->left;
218 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = vol->right;
219 return 1;
220 }
221 return 0;
222 }
223
224
225 __inline int
226 ad_read(struct ad1848_softc *sc, int reg)
227 {
228 int x;
229
230 ADWRITE(sc, AD1848_IADDR, (reg & 0xff) | sc->MCE_bit);
231 x = ADREAD(sc, AD1848_IDATA);
232 /* printf("(%02x<-%02x) ", reg|sc->MCE_bit, x); */
233 return x;
234 }
235
236 __inline void
237 ad_write(struct ad1848_softc *sc, int reg, int data)
238 {
239
240 ADWRITE(sc, AD1848_IADDR, (reg & 0xff) | sc->MCE_bit);
241 ADWRITE(sc, AD1848_IDATA, data & 0xff);
242 /* printf("(%02x->%02x) ", reg|sc->MCE_bit, data); */
243 }
244
245 /*
246 * extended registers (mode 3) require an additional level of
247 * indirection through CS_XREG (I23).
248 */
249
250 __inline int
251 ad_xread(struct ad1848_softc *sc, int reg)
252 {
253 int x;
254
255 ADWRITE(sc, AD1848_IADDR, CS_XREG | sc->MCE_bit);
256 ADWRITE(sc, AD1848_IDATA, (reg | ALT_F3_XRAE) & 0xff);
257 x = ADREAD(sc, AD1848_IDATA);
258
259 return x;
260 }
261
262 __inline void
263 ad_xwrite(struct ad1848_softc *sc, int reg, int val)
264 {
265
266 ADWRITE(sc, AD1848_IADDR, CS_XREG | sc->MCE_bit);
267 ADWRITE(sc, AD1848_IDATA, (reg | ALT_F3_XRAE) & 0xff);
268 ADWRITE(sc, AD1848_IDATA, val & 0xff);
269 }
270
271 static void
272 ad_set_MCE(struct ad1848_softc *sc, int state)
273 {
274
275 if (state)
276 sc->MCE_bit = MODE_CHANGE_ENABLE;
277 else
278 sc->MCE_bit = 0;
279 ADWRITE(sc, AD1848_IADDR, sc->MCE_bit);
280 }
281
282 static void
283 wait_for_calibration(struct ad1848_softc *sc)
284 {
285 int timeout;
286
287 DPRINTF(("ad1848: Auto calibration started.\n"));
288 /*
289 * Wait until the auto calibration process has finished.
290 *
291 * 1) Wait until the chip becomes ready (reads don't return 0x80).
292 * 2) Wait until the ACI bit of I11 gets on and then off.
293 * Because newer chips are fast we may never see the ACI
294 * bit go on. Just delay a little instead.
295 */
296 timeout = 10000;
297 while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) {
298 delay(10);
299 timeout--;
300 }
301 if (timeout <= 0)
302 DPRINTF(("ad1848: Auto calibration timed out(1).\n"));
303
304 /* Set register addr */
305 ADWRITE(sc, AD1848_IADDR, SP_TEST_AND_INIT);
306 /* Wait for address to appear when read back. */
307 timeout = 100000;
308 while (timeout > 0 &&
309 (ADREAD(sc, AD1848_IADDR)&SP_IADDR_MASK) != SP_TEST_AND_INIT) {
310 delay(10);
311 timeout--;
312 }
313 if (timeout <= 0)
314 DPRINTF(("ad1848: Auto calibration timed out(1.5).\n"));
315
316 if (!(ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG)) {
317 if (sc->mode > 1) {
318 /* A new chip, just delay a little. */
319 delay(100); /* XXX what should it be? */
320 } else {
321 timeout = 10000;
322 while (timeout > 0 &&
323 !(ad_read(sc, SP_TEST_AND_INIT) &
324 AUTO_CAL_IN_PROG)) {
325 delay(10);
326 timeout--;
327 }
328 if (timeout <= 0)
329 DPRINTF(("ad1848: Auto calibration timed out(2).\n"));
330 }
331 }
332
333 timeout = 10000;
334 while (timeout > 0 &&
335 ad_read(sc, SP_TEST_AND_INIT) & AUTO_CAL_IN_PROG) {
336 delay(10);
337 timeout--;
338 }
339 if (timeout <= 0)
340 DPRINTF(("ad1848: Auto calibration timed out(3).\n"));
341 }
342
343 #ifdef AUDIO_DEBUG
344 void
345 ad1848_dump_regs(struct ad1848_softc *sc)
346 {
347 int i;
348 u_char r;
349
350 printf("ad1848 status=%02x", ADREAD(sc, AD1848_STATUS));
351 printf(" regs: ");
352 for (i = 0; i < 16; i++) {
353 r = ad_read(sc, i);
354 printf("%02x ", r);
355 }
356 if (sc->mode >= 2) {
357 for (i = 16; i < 32; i++) {
358 r = ad_read(sc, i);
359 printf("%02x ", r);
360 }
361 }
362 printf("\n");
363 }
364 #endif /* AUDIO_DEBUG */
365
366
367 /*
368 * Attach hardware to driver, attach hardware driver to audio
369 * pseudo-device driver .
370 */
371 void
372 ad1848_attach(struct ad1848_softc *sc)
373 {
374 static struct ad1848_volume vol_mid = {220, 220};
375 static struct ad1848_volume vol_0 = {0, 0};
376 int i;
377 int timeout;
378
379 /* Initialize the ad1848... */
380 for (i = 0; i < 0x10; i++) {
381 ad_write(sc, i, ad1848_init_values[i]);
382 timeout = 100000;
383 while (timeout > 0 && ADREAD(sc, AD1848_IADDR) & SP_IN_INIT)
384 timeout--;
385 }
386 /* ...and additional CS4231 stuff too */
387 if (sc->mode >= 2) {
388 ad_write(sc, SP_INTERFACE_CONFIG, 0); /* disable SINGLE_DMA */
389 for (i = 0x10; i < 0x20; i++)
390 if (ad1848_init_values[i] != 0) {
391 ad_write(sc, i, ad1848_init_values[i]);
392 timeout = 100000;
393 while (timeout > 0 &&
394 ADREAD(sc, AD1848_IADDR) & SP_IN_INIT)
395 timeout--;
396 }
397 }
398 ad1848_reset(sc);
399
400 /* Set default gains */
401 ad1848_set_rec_gain(sc, &vol_mid);
402 ad1848_set_channel_gain(sc, AD1848_DAC_CHANNEL, &vol_mid);
403 ad1848_set_channel_gain(sc, AD1848_MONITOR_CHANNEL, &vol_0);
404 ad1848_set_channel_gain(sc, AD1848_AUX1_CHANNEL, &vol_mid); /* CD volume */
405 sc->mute[AD1848_MONITOR_CHANNEL] = MUTE_ALL;
406 if (sc->mode >= 2
407 #if AD1845_HACK
408 && sc->is_ad1845 == 0
409 #endif
410 ) {
411 ad1848_set_channel_gain(sc, AD1848_AUX2_CHANNEL, &vol_mid); /* CD volume */
412 ad1848_set_channel_gain(sc, AD1848_LINE_CHANNEL, &vol_mid);
413 ad1848_set_channel_gain(sc, AD1848_MONO_CHANNEL, &vol_0);
414 sc->mute[AD1848_MONO_CHANNEL] = MUTE_ALL;
415 } else
416 ad1848_set_channel_gain(sc, AD1848_AUX2_CHANNEL, &vol_0);
417
418 /* Set default port */
419 ad1848_set_rec_port(sc, MIC_IN_PORT);
420
421 printf(": %s", sc->chip_name);
422 }
423
424 /*
425 * Various routines to interface to higher level audio driver
426 */
427 static const struct ad1848_mixerinfo {
428 int left_reg;
429 int right_reg;
430 int atten_bits;
431 int atten_mask;
432 } mixer_channel_info[] =
433 {
434 { SP_LEFT_AUX2_CONTROL, SP_RIGHT_AUX2_CONTROL, AUX_INPUT_ATTEN_BITS,
435 AUX_INPUT_ATTEN_MASK },
436 { SP_LEFT_AUX1_CONTROL, SP_RIGHT_AUX1_CONTROL, AUX_INPUT_ATTEN_BITS,
437 AUX_INPUT_ATTEN_MASK },
438 { SP_LEFT_OUTPUT_CONTROL, SP_RIGHT_OUTPUT_CONTROL,
439 OUTPUT_ATTEN_BITS, OUTPUT_ATTEN_MASK },
440 { CS_LEFT_LINE_CONTROL, CS_RIGHT_LINE_CONTROL, LINE_INPUT_ATTEN_BITS,
441 LINE_INPUT_ATTEN_MASK },
442 { CS_MONO_IO_CONTROL, 0, MONO_INPUT_ATTEN_BITS, MONO_INPUT_ATTEN_MASK },
443 { CS_MONO_IO_CONTROL, 0, 0, 0 },
444 { SP_DIGITAL_MIX, 0, OUTPUT_ATTEN_BITS, MIX_ATTEN_MASK }
445 };
446
447 /*
448 * This function doesn't set the mute flags but does use them.
449 * The mute flags reflect the mutes that have been applied by the user.
450 * However, the driver occasionally wants to mute devices (e.g. when chaing
451 * sampling rate). These operations should not affect the mute flags.
452 */
453
454 void
455 ad1848_mute_channel(struct ad1848_softc *sc, int device, int mute)
456 {
457 u_char reg;
458
459 reg = ad_read(sc, mixer_channel_info[device].left_reg);
460
461 if (mute & MUTE_LEFT) {
462 if (device == AD1848_MONITOR_CHANNEL) {
463 if (sc->open_mode & FREAD)
464 ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 0);
465 ad_write(sc, mixer_channel_info[device].left_reg,
466 reg & ~DIGITAL_MIX1_ENABLE);
467 } else if (device == AD1848_OUT_CHANNEL)
468 ad_write(sc, mixer_channel_info[device].left_reg,
469 reg | MONO_OUTPUT_MUTE);
470 else
471 ad_write(sc, mixer_channel_info[device].left_reg,
472 reg | 0x80);
473 } else if (!(sc->mute[device] & MUTE_LEFT)) {
474 if (device == AD1848_MONITOR_CHANNEL) {
475 ad_write(sc, mixer_channel_info[device].left_reg,
476 reg | DIGITAL_MIX1_ENABLE);
477 if (sc->open_mode & FREAD)
478 ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 1);
479 } else if (device == AD1848_OUT_CHANNEL)
480 ad_write(sc, mixer_channel_info[device].left_reg,
481 reg & ~MONO_OUTPUT_MUTE);
482 else
483 ad_write(sc, mixer_channel_info[device].left_reg,
484 reg & ~0x80);
485 }
486
487 if (!mixer_channel_info[device].right_reg)
488 return;
489
490 reg = ad_read(sc, mixer_channel_info[device].right_reg);
491
492 if (mute & MUTE_RIGHT) {
493 ad_write(sc, mixer_channel_info[device].right_reg, reg | 0x80);
494 } else if (!(sc->mute[device] & MUTE_RIGHT)) {
495 ad_write(sc, mixer_channel_info[device].right_reg, reg &~0x80);
496 }
497 }
498
499 int
500 ad1848_set_channel_gain(struct ad1848_softc *sc, int device,
501 struct ad1848_volume *gp)
502 {
503 const struct ad1848_mixerinfo *info;
504 u_char reg;
505 u_int atten;
506
507 info = &mixer_channel_info[device];
508 sc->gains[device] = *gp;
509
510 atten = (AUDIO_MAX_GAIN - gp->left) * (info->atten_bits + 1) /
511 (AUDIO_MAX_GAIN + 1);
512
513 reg = ad_read(sc, info->left_reg) & (info->atten_mask);
514 if (device == AD1848_MONITOR_CHANNEL)
515 reg |= ((atten & info->atten_bits) << 2);
516 else
517 reg |= ((atten & info->atten_bits));
518
519 ad_write(sc, info->left_reg, reg);
520
521 if (!info->right_reg)
522 return 0;
523
524 atten = (AUDIO_MAX_GAIN - gp->right) * (info->atten_bits + 1) /
525 (AUDIO_MAX_GAIN + 1);
526 reg = ad_read(sc, info->right_reg);
527 reg &= info->atten_mask;
528 ad_write(sc, info->right_reg, (atten & info->atten_bits) | reg);
529
530 return 0;
531 }
532
533 int
534 ad1848_get_device_gain(struct ad1848_softc *sc, int device,
535 struct ad1848_volume *gp)
536 {
537
538 *gp = sc->gains[device];
539 return 0;
540 }
541
542 int
543 ad1848_get_rec_gain(struct ad1848_softc *sc, struct ad1848_volume *gp)
544 {
545
546 *gp = sc->rec_gain;
547 return 0;
548 }
549
550 int
551 ad1848_set_rec_gain(struct ad1848_softc *sc, struct ad1848_volume *gp)
552 {
553 u_char reg, gain;
554
555 DPRINTF(("ad1848_set_rec_gain: %d:%d\n", gp->left, gp->right));
556
557 sc->rec_gain = *gp;
558
559 gain = (gp->left * (GAIN_22_5 + 1)) / (AUDIO_MAX_GAIN + 1);
560 reg = ad_read(sc, SP_LEFT_INPUT_CONTROL);
561 reg &= INPUT_GAIN_MASK;
562 ad_write(sc, SP_LEFT_INPUT_CONTROL, (gain & 0x0f) | reg);
563
564 gain = (gp->right * (GAIN_22_5 + 1)) / (AUDIO_MAX_GAIN + 1);
565 reg = ad_read(sc, SP_RIGHT_INPUT_CONTROL);
566 reg &= INPUT_GAIN_MASK;
567 ad_write(sc, SP_RIGHT_INPUT_CONTROL, (gain & 0x0f) | reg);
568
569 return 0;
570 }
571
572 void
573 ad1848_mute_wave_output(struct ad1848_softc *sc, int mute, int set)
574 {
575 int m;
576
577 DPRINTF(("ad1848_mute_wave_output: %d, %d\n", mute, set));
578
579 if (mute == WAVE_MUTE2_INIT) {
580 sc->wave_mute_status = 0;
581 mute = WAVE_MUTE2;
582 }
583 if (set)
584 m = sc->wave_mute_status |= mute;
585 else
586 m = sc->wave_mute_status &= ~mute;
587
588 if (m & WAVE_MUTE0 || ((m & WAVE_UNMUTE1) == 0 && m & WAVE_MUTE2))
589 ad1848_mute_channel(sc, AD1848_DAC_CHANNEL, MUTE_ALL);
590 else
591 ad1848_mute_channel(sc, AD1848_DAC_CHANNEL,
592 sc->mute[AD1848_DAC_CHANNEL]);
593 }
594
595 int
596 ad1848_set_mic_gain(struct ad1848_softc *sc, struct ad1848_volume *gp)
597 {
598 u_char reg;
599
600 DPRINTF(("cs4231_set_mic_gain: %d\n", gp->left));
601
602 if (gp->left > AUDIO_MAX_GAIN/2) {
603 sc->mic_gain_on = 1;
604 reg = ad_read(sc, SP_LEFT_INPUT_CONTROL);
605 ad_write(sc, SP_LEFT_INPUT_CONTROL,
606 reg | INPUT_MIC_GAIN_ENABLE);
607 } else {
608 sc->mic_gain_on = 0;
609 reg = ad_read(sc, SP_LEFT_INPUT_CONTROL);
610 ad_write(sc, SP_LEFT_INPUT_CONTROL,
611 reg & ~INPUT_MIC_GAIN_ENABLE);
612 }
613
614 return 0;
615 }
616
617 int
618 ad1848_get_mic_gain(struct ad1848_softc *sc, struct ad1848_volume *gp)
619 {
620 if (sc->mic_gain_on)
621 gp->left = gp->right = AUDIO_MAX_GAIN;
622 else
623 gp->left = gp->right = AUDIO_MIN_GAIN;
624 return 0;
625 }
626
627 static ad1848_devmap_t *
628 ad1848_mixer_find_dev(ad1848_devmap_t *map, int cnt, mixer_ctrl_t *cp)
629 {
630 int i;
631
632 for (i = 0; i < cnt; i++) {
633 if (map[i].id == cp->dev) {
634 return (&map[i]);
635 }
636 }
637 return 0;
638 }
639
640 int
641 ad1848_mixer_get_port(struct ad1848_softc *ac, struct ad1848_devmap *map,
642 int cnt, mixer_ctrl_t *cp)
643 {
644 ad1848_devmap_t *entry;
645 struct ad1848_volume vol;
646 int error;
647 int dev;
648
649 error = EINVAL;
650 if (!(entry = ad1848_mixer_find_dev(map, cnt, cp)))
651 return ENXIO;
652
653 dev = entry->dev;
654
655 switch (entry->kind) {
656 case AD1848_KIND_LVL:
657 if (cp->type != AUDIO_MIXER_VALUE)
658 break;
659
660 if (dev < AD1848_AUX2_CHANNEL ||
661 dev > AD1848_MONITOR_CHANNEL)
662 break;
663
664 if (cp->un.value.num_channels != 1 &&
665 mixer_channel_info[dev].right_reg == 0)
666 break;
667
668 error = ad1848_get_device_gain(ac, dev, &vol);
669 if (!error)
670 ad1848_from_vol(cp, &vol);
671
672 break;
673
674 case AD1848_KIND_MUTE:
675 if (cp->type != AUDIO_MIXER_ENUM) break;
676
677 cp->un.ord = ac->mute[dev] ? 1 : 0;
678 error = 0;
679 break;
680
681 case AD1848_KIND_RECORDGAIN:
682 if (cp->type != AUDIO_MIXER_VALUE) break;
683
684 error = ad1848_get_rec_gain(ac, &vol);
685 if (!error)
686 ad1848_from_vol(cp, &vol);
687
688 break;
689
690 case AD1848_KIND_MICGAIN:
691 if (cp->type != AUDIO_MIXER_VALUE) break;
692
693 error = ad1848_get_mic_gain(ac, &vol);
694 if (!error)
695 ad1848_from_vol(cp, &vol);
696
697 break;
698
699 case AD1848_KIND_RECORDSOURCE:
700 if (cp->type != AUDIO_MIXER_ENUM) break;
701 cp->un.ord = ad1848_get_rec_port(ac);
702 error = 0;
703 break;
704
705 default:
706 printf ("Invalid kind\n");
707 break;
708 }
709
710 return error;
711 }
712
713 int
714 ad1848_mixer_set_port(struct ad1848_softc *ac, struct ad1848_devmap *map,
715 int cnt, mixer_ctrl_t *cp)
716 {
717 ad1848_devmap_t *entry;
718 struct ad1848_volume vol;
719 int error;
720 int dev;
721
722 error = EINVAL;
723 if (!(entry = ad1848_mixer_find_dev(map, cnt, cp)))
724 return ENXIO;
725
726 dev = entry->dev;
727
728 switch (entry->kind) {
729 case AD1848_KIND_LVL:
730 if (cp->type != AUDIO_MIXER_VALUE)
731 break;
732
733 if (dev < AD1848_AUX2_CHANNEL ||
734 dev > AD1848_MONITOR_CHANNEL)
735 break;
736
737 if (cp->un.value.num_channels != 1 &&
738 mixer_channel_info[dev].right_reg == 0)
739 break;
740
741 ad1848_to_vol(cp, &vol);
742 error = ad1848_set_channel_gain(ac, dev, &vol);
743 break;
744
745 case AD1848_KIND_MUTE:
746 if (cp->type != AUDIO_MIXER_ENUM) break;
747
748 ac->mute[dev] = (cp->un.ord ? MUTE_ALL : 0);
749 ad1848_mute_channel(ac, dev, ac->mute[dev]);
750 error = 0;
751 break;
752
753 case AD1848_KIND_RECORDGAIN:
754 if (cp->type != AUDIO_MIXER_VALUE) break;
755
756 ad1848_to_vol(cp, &vol);
757 error = ad1848_set_rec_gain(ac, &vol);
758 break;
759
760 case AD1848_KIND_MICGAIN:
761 if (cp->type != AUDIO_MIXER_VALUE) break;
762
763 ad1848_to_vol(cp, &vol);
764 error = ad1848_set_mic_gain(ac, &vol);
765 break;
766
767 case AD1848_KIND_RECORDSOURCE:
768 if (cp->type != AUDIO_MIXER_ENUM) break;
769
770 error = ad1848_set_rec_port(ac, cp->un.ord);
771 break;
772
773 default:
774 printf ("Invalid kind\n");
775 break;
776 }
777
778 return error;
779 }
780
781 int
782 ad1848_query_encoding(void *addr, struct audio_encoding *fp)
783 {
784 struct ad1848_softc *sc;
785
786 sc = addr;
787 switch (fp->index) {
788 case 0:
789 strcpy(fp->name, AudioEmulaw);
790 fp->encoding = AUDIO_ENCODING_ULAW;
791 fp->precision = 8;
792 fp->flags = 0;
793 break;
794 case 1:
795 strcpy(fp->name, AudioEalaw);
796 fp->encoding = AUDIO_ENCODING_ALAW;
797 fp->precision = 8;
798 fp->flags = 0;
799 break;
800 case 2:
801 strcpy(fp->name, AudioEslinear_le);
802 fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
803 fp->precision = 16;
804 fp->flags = 0;
805 break;
806 case 3:
807 strcpy(fp->name, AudioEulinear);
808 fp->encoding = AUDIO_ENCODING_ULINEAR;
809 fp->precision = 8;
810 fp->flags = 0;
811 break;
812
813 case 4: /* only on CS4231 */
814 strcpy(fp->name, AudioEslinear_be);
815 fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
816 fp->precision = 16;
817 fp->flags = sc->mode == 1
818 #if AD1845_HACK
819 || sc->is_ad1845
820 #endif
821 ? AUDIO_ENCODINGFLAG_EMULATED : 0;
822 break;
823
824 /* emulate some modes */
825 case 5:
826 strcpy(fp->name, AudioEslinear);
827 fp->encoding = AUDIO_ENCODING_SLINEAR;
828 fp->precision = 8;
829 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
830 break;
831 case 6:
832 strcpy(fp->name, AudioEulinear_le);
833 fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
834 fp->precision = 16;
835 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
836 break;
837 case 7:
838 strcpy(fp->name, AudioEulinear_be);
839 fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
840 fp->precision = 16;
841 fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
842 break;
843
844 case 8: /* only on CS4231 */
845 if (sc->mode == 1 || sc->is_ad1845)
846 return EINVAL;
847 strcpy(fp->name, AudioEadpcm);
848 fp->encoding = AUDIO_ENCODING_ADPCM;
849 fp->precision = 4;
850 fp->flags = 0;
851 break;
852 default:
853 return EINVAL;
854 /*NOTREACHED*/
855 }
856 return 0;
857 }
858
859 int
860 ad1848_set_params(void *addr, int setmode, int usemode, audio_params_t *p,
861 audio_params_t *r, stream_filter_list_t *pfil, stream_filter_list_t *rfil)
862 {
863 audio_params_t phw, rhw;
864 struct ad1848_softc *sc;
865 int error, bits, enc;
866 stream_filter_factory_t *pswcode;
867 stream_filter_factory_t *rswcode;
868
869 DPRINTF(("ad1848_set_params: %u %u %u %u\n",
870 p->encoding, p->precision, p->channels, p->sample_rate));
871
872 sc = addr;
873 enc = p->encoding;
874 pswcode = rswcode = 0;
875 phw = *p;
876 rhw = *r;
877 switch (enc) {
878 case AUDIO_ENCODING_SLINEAR_LE:
879 if (p->precision == 8) {
880 enc = AUDIO_ENCODING_ULINEAR_LE;
881 phw.encoding = AUDIO_ENCODING_ULINEAR_LE;
882 rhw.encoding = AUDIO_ENCODING_ULINEAR_LE;
883 pswcode = rswcode = change_sign8;
884 }
885 break;
886 case AUDIO_ENCODING_SLINEAR_BE:
887 if (p->precision == 16 && (sc->mode == 1
888 #if AD1845_HACK
889 || sc->is_ad1845
890 #endif
891 )) {
892 enc = AUDIO_ENCODING_SLINEAR_LE;
893 phw.encoding = AUDIO_ENCODING_SLINEAR_LE;
894 rhw.encoding = AUDIO_ENCODING_SLINEAR_LE;
895 pswcode = rswcode = swap_bytes;
896 }
897 break;
898 case AUDIO_ENCODING_ULINEAR_LE:
899 if (p->precision == 16) {
900 enc = AUDIO_ENCODING_SLINEAR_LE;
901 phw.encoding = AUDIO_ENCODING_SLINEAR_LE;
902 rhw.encoding = AUDIO_ENCODING_SLINEAR_LE;
903 pswcode = rswcode = change_sign16;
904 }
905 break;
906 case AUDIO_ENCODING_ULINEAR_BE:
907 if (p->precision == 16) {
908 if (sc->mode == 1
909 #if AD1845_HACK
910 || sc->is_ad1845
911 #endif
912 ) {
913 enc = AUDIO_ENCODING_SLINEAR_LE;
914 phw.encoding = AUDIO_ENCODING_SLINEAR_LE;
915 rhw.encoding = AUDIO_ENCODING_SLINEAR_LE;
916 pswcode = swap_bytes_change_sign16;
917 rswcode = swap_bytes_change_sign16;
918 } else {
919 enc = AUDIO_ENCODING_SLINEAR_BE;
920 phw.encoding = AUDIO_ENCODING_SLINEAR_BE;
921 rhw.encoding = AUDIO_ENCODING_SLINEAR_BE;
922 pswcode = rswcode = change_sign16;
923 }
924 }
925 break;
926 }
927 switch (enc) {
928 case AUDIO_ENCODING_ULAW:
929 bits = FMT_ULAW >> 5;
930 break;
931 case AUDIO_ENCODING_ALAW:
932 bits = FMT_ALAW >> 5;
933 break;
934 case AUDIO_ENCODING_ADPCM:
935 bits = FMT_ADPCM >> 5;
936 break;
937 case AUDIO_ENCODING_SLINEAR_LE:
938 if (p->precision == 16)
939 bits = FMT_TWOS_COMP >> 5;
940 else
941 return EINVAL;
942 break;
943 case AUDIO_ENCODING_SLINEAR_BE:
944 if (p->precision == 16)
945 bits = FMT_TWOS_COMP_BE >> 5;
946 else
947 return EINVAL;
948 break;
949 case AUDIO_ENCODING_ULINEAR_LE:
950 if (p->precision == 8)
951 bits = FMT_PCM8 >> 5;
952 else
953 return EINVAL;
954 break;
955 default:
956 return EINVAL;
957 }
958
959 if (p->channels < 1 || p->channels > 2)
960 return EINVAL;
961
962 error = ad1848_set_speed(sc, &p->sample_rate);
963 if (error)
964 return error;
965 phw.sample_rate = p->sample_rate;
966
967 if (pswcode != NULL)
968 pfil->append(pfil, pswcode, &phw);
969 if (rswcode != NULL)
970 rfil->append(rfil, rswcode, &rhw);
971
972 sc->format_bits = bits;
973 sc->channels = p->channels;
974 sc->precision = p->precision;
975 sc->need_commit = 1;
976
977 DPRINTF(("ad1848_set_params succeeded, bits=%x\n", bits));
978 return 0;
979 }
980
981 int
982 ad1848_set_rec_port(struct ad1848_softc *sc, int port)
983 {
984 u_char inp, reg;
985
986 DPRINTF(("ad1848_set_rec_port: 0x%x\n", port));
987
988 if (port == MIC_IN_PORT)
989 inp = MIC_INPUT;
990 else if (port == LINE_IN_PORT)
991 inp = LINE_INPUT;
992 else if (port == DAC_IN_PORT)
993 inp = MIXED_DAC_INPUT;
994 else if (sc->mode >= 2 && port == AUX1_IN_PORT)
995 inp = AUX_INPUT;
996 else
997 return EINVAL;
998
999 reg = ad_read(sc, SP_LEFT_INPUT_CONTROL);
1000 reg &= INPUT_SOURCE_MASK;
1001 ad_write(sc, SP_LEFT_INPUT_CONTROL, (inp|reg));
1002
1003 reg = ad_read(sc, SP_RIGHT_INPUT_CONTROL);
1004 reg &= INPUT_SOURCE_MASK;
1005 ad_write(sc, SP_RIGHT_INPUT_CONTROL, (inp|reg));
1006
1007 sc->rec_port = port;
1008
1009 return 0;
1010 }
1011
1012 int
1013 ad1848_get_rec_port(struct ad1848_softc *sc)
1014 {
1015 return sc->rec_port;
1016 }
1017
1018 int
1019 ad1848_round_blocksize(void *addr, int blk,
1020 int mode, const audio_params_t *param)
1021 {
1022
1023 /* Round to a multiple of the biggest sample size. */
1024 return blk &= -4;
1025 }
1026
1027 int
1028 ad1848_open(void *addr, int flags)
1029 {
1030 struct ad1848_softc *sc;
1031 u_char reg;
1032
1033 sc = addr;
1034 DPRINTF(("ad1848_open: sc=%p\n", sc));
1035
1036 sc->open_mode = flags;
1037
1038 /* Enable interrupts */
1039 DPRINTF(("ad1848_open: enable intrs\n"));
1040 reg = ad_read(sc, SP_PIN_CONTROL);
1041 ad_write(sc, SP_PIN_CONTROL, reg | INTERRUPT_ENABLE);
1042
1043 /* If recording && monitoring, the playback part is also used. */
1044 if (flags & FREAD && sc->mute[AD1848_MONITOR_CHANNEL] == 0)
1045 ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 1);
1046
1047 #ifdef AUDIO_DEBUG
1048 if (ad1848debug)
1049 ad1848_dump_regs(sc);
1050 #endif
1051
1052 return 0;
1053 }
1054
1055 /*
1056 * Close function is called at splaudio().
1057 */
1058 void
1059 ad1848_close(void *addr)
1060 {
1061 struct ad1848_softc *sc;
1062 u_char reg;
1063
1064 sc = addr;
1065 sc->open_mode = 0;
1066
1067 ad1848_mute_wave_output(sc, WAVE_UNMUTE1, 0);
1068
1069 /* Disable interrupts */
1070 DPRINTF(("ad1848_close: disable intrs\n"));
1071 reg = ad_read(sc, SP_PIN_CONTROL);
1072 ad_write(sc, SP_PIN_CONTROL, reg & ~INTERRUPT_ENABLE);
1073
1074 #ifdef AUDIO_DEBUG
1075 if (ad1848debug)
1076 ad1848_dump_regs(sc);
1077 #endif
1078 }
1079
1080 /*
1081 * Lower-level routines
1082 */
1083 int
1084 ad1848_commit_settings(void *addr)
1085 {
1086 struct ad1848_softc *sc;
1087 int timeout;
1088 u_char fs;
1089 int s;
1090
1091 sc = addr;
1092 if (!sc->need_commit)
1093 return 0;
1094
1095 s = splaudio();
1096
1097 ad1848_mute_wave_output(sc, WAVE_MUTE0, 1);
1098
1099 ad_set_MCE(sc, 1); /* Enables changes to the format select reg */
1100
1101 fs = sc->speed_bits | (sc->format_bits << 5);
1102
1103 if (sc->channels == 2)
1104 fs |= FMT_STEREO;
1105
1106 /*
1107 * OPL3-SA2 (YMF711) is sometimes busy here.
1108 * Wait until it becomes ready.
1109 */
1110 for (timeout = 0;
1111 timeout < 1000 && ADREAD(sc, AD1848_IADDR) & SP_IN_INIT; timeout++)
1112 delay(10);
1113
1114 ad_write(sc, SP_CLOCK_DATA_FORMAT, fs);
1115
1116 /*
1117 * If mode >= 2 (CS4231), set I28 also.
1118 * It's the capture format register.
1119 */
1120 if (sc->mode >= 2) {
1121 /*
1122 * Gravis Ultrasound MAX SDK sources says something about
1123 * errata sheets, with the implication that these inb()s
1124 * are necessary.
1125 */
1126 (void)ADREAD(sc, AD1848_IDATA);
1127 (void)ADREAD(sc, AD1848_IDATA);
1128 /* Write to I8 starts resynchronization. Wait for completion. */
1129 timeout = 100000;
1130 while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT)
1131 timeout--;
1132
1133 ad_write(sc, CS_REC_FORMAT, fs);
1134 (void)ADREAD(sc, AD1848_IDATA);
1135 (void)ADREAD(sc, AD1848_IDATA);
1136 /* Now wait for resync for capture side of the house */
1137 }
1138 /*
1139 * Write to I8 starts resynchronization. Wait until it completes.
1140 */
1141 timeout = 100000;
1142 while (timeout > 0 && ADREAD(sc, AD1848_IADDR) == SP_IN_INIT) {
1143 delay(10);
1144 timeout--;
1145 }
1146
1147 if (ADREAD(sc, AD1848_IADDR) == SP_IN_INIT)
1148 printf("ad1848_commit: Auto calibration timed out\n");
1149
1150 /*
1151 * Starts the calibration process and
1152 * enters playback mode after it.
1153 */
1154 ad_set_MCE(sc, 0);
1155 wait_for_calibration(sc);
1156
1157 ad1848_mute_wave_output(sc, WAVE_MUTE0, 0);
1158
1159 splx(s);
1160
1161 sc->need_commit = 0;
1162 return 0;
1163 }
1164
1165 void
1166 ad1848_reset(struct ad1848_softc *sc)
1167 {
1168 u_char r;
1169
1170 DPRINTF(("ad1848_reset\n"));
1171
1172 /* Clear the PEN and CEN bits */
1173 r = ad_read(sc, SP_INTERFACE_CONFIG);
1174 r &= ~(CAPTURE_ENABLE | PLAYBACK_ENABLE);
1175 ad_write(sc, SP_INTERFACE_CONFIG, r);
1176
1177 if (sc->mode >= 2) {
1178 ADWRITE(sc, AD1848_IADDR, CS_IRQ_STATUS);
1179 ADWRITE(sc, AD1848_IDATA, 0);
1180 }
1181 /* Clear interrupt status */
1182 ADWRITE(sc, AD1848_STATUS, 0);
1183 #ifdef AUDIO_DEBUG
1184 if (ad1848debug)
1185 ad1848_dump_regs(sc);
1186 #endif
1187 }
1188
1189 int
1190 ad1848_set_speed(struct ad1848_softc *sc, u_int *argp)
1191 {
1192 /*
1193 * The sampling speed is encoded in the least significant nible of I8.
1194 * The LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and
1195 * other three bits select the divisor (indirectly):
1196 *
1197 * The available speeds are in the following table. Keep the speeds in
1198 * the increasing order.
1199 */
1200 typedef struct {
1201 int speed;
1202 u_char bits;
1203 } speed_struct;
1204 u_long arg;
1205
1206 static const speed_struct speed_table[] = {
1207 {5510, (0 << 1) | 1},
1208 {5510, (0 << 1) | 1},
1209 {6620, (7 << 1) | 1},
1210 {8000, (0 << 1) | 0},
1211 {9600, (7 << 1) | 0},
1212 {11025, (1 << 1) | 1},
1213 {16000, (1 << 1) | 0},
1214 {18900, (2 << 1) | 1},
1215 {22050, (3 << 1) | 1},
1216 {27420, (2 << 1) | 0},
1217 {32000, (3 << 1) | 0},
1218 {33075, (6 << 1) | 1},
1219 {37800, (4 << 1) | 1},
1220 {44100, (5 << 1) | 1},
1221 {48000, (6 << 1) | 0}
1222 };
1223
1224 int i, n, selected;
1225
1226 arg = *argp;
1227 selected = -1;
1228 n = sizeof(speed_table) / sizeof(speed_struct);
1229
1230 if (arg < speed_table[0].speed)
1231 selected = 0;
1232 if (arg > speed_table[n - 1].speed)
1233 selected = n - 1;
1234
1235 for (i = 1 /*really*/ ; selected == -1 && i < n; i++)
1236 if (speed_table[i].speed == arg)
1237 selected = i;
1238 else if (speed_table[i].speed > arg) {
1239 int diff1, diff2;
1240
1241 diff1 = arg - speed_table[i - 1].speed;
1242 diff2 = speed_table[i].speed - arg;
1243
1244 if (diff1 < diff2)
1245 selected = i - 1;
1246 else
1247 selected = i;
1248 }
1249
1250 if (selected == -1) {
1251 printf("ad1848: Can't find speed???\n");
1252 selected = 3;
1253 }
1254
1255 sc->speed_bits = speed_table[selected].bits;
1256 sc->need_commit = 1;
1257 *argp = speed_table[selected].speed;
1258
1259 return 0;
1260 }
1261
1262 /*
1263 * Halt I/O
1264 */
1265 int
1266 ad1848_halt_output(void *addr)
1267 {
1268 struct ad1848_softc *sc;
1269 u_char reg;
1270
1271 DPRINTF(("ad1848: ad1848_halt_output\n"));
1272 sc = addr;
1273 reg = ad_read(sc, SP_INTERFACE_CONFIG);
1274 ad_write(sc, SP_INTERFACE_CONFIG, reg & ~PLAYBACK_ENABLE);
1275
1276 return 0;
1277 }
1278
1279 int
1280 ad1848_halt_input(void *addr)
1281 {
1282 struct ad1848_softc *sc;
1283 u_char reg;
1284
1285 DPRINTF(("ad1848: ad1848_halt_input\n"));
1286 sc = addr;
1287 reg = ad_read(sc, SP_INTERFACE_CONFIG);
1288 ad_write(sc, SP_INTERFACE_CONFIG, reg & ~CAPTURE_ENABLE);
1289
1290 return 0;
1291 }
Cache object: fa4361b4c0f61e506944dc52b069de3f
|