FreeBSD/Linux Kernel Cross Reference
sys/dev/pcmcia/esl.c
1 /* $NetBSD: esl.c,v 1.10 2003/05/16 23:55:32 kristerw Exp $ */
2
3 /*
4 * Copyright (c) 2001 Jared D. McNeill <jmcneill@invisible.yi.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Jared D. McNeill.
18 * 4. Neither the name of the author nor the names of any contributors may
19 * be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: esl.c,v 1.10 2003/05/16 23:55:32 kristerw Exp $");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/errno.h>
42 #include <sys/ioctl.h>
43 #include <sys/syslog.h>
44 #include <sys/device.h>
45 #include <sys/proc.h>
46 #include <sys/kernel.h>
47 #include <sys/audioio.h>
48
49 #include <machine/cpu.h>
50 #include <machine/intr.h>
51 #include <machine/bus.h>
52 #include <machine/pio.h>
53
54 #include <dev/audio_if.h>
55 #include <dev/auconv.h>
56 #include <dev/mulaw.h>
57
58 #include <dev/pcmcia/pcmciavar.h>
59
60 #include <dev/isa/essreg.h>
61 #include <dev/pcmcia/eslvar.h>
62
63 int esl_open(void *, int);
64 void esl_close(void *);
65 int esl_query_encoding(void *, struct audio_encoding *);
66 int esl_set_params(void *, int, int, struct audio_params *,
67 struct audio_params *);
68 int esl_round_blocksize(void *, int);
69 int esl_halt_output(void *);
70 int esl_halt_input(void *);
71 int esl_speaker_ctl(void *, int);
72 int esl_getdev(void *, struct audio_device *);
73 int esl_set_port(void *, mixer_ctrl_t *);
74 int esl_get_port(void *, mixer_ctrl_t *);
75 int esl_query_devinfo(void *, mixer_devinfo_t *);
76 int esl_get_props(void *);
77 int esl_trigger_output(void *, void *, void *, int, void (*)(void *),
78 void *, struct audio_params *);
79
80 /* Supporting subroutines */
81 int esl_reset(struct esl_pcmcia_softc *);
82 void esl_setup(struct esl_pcmcia_softc *);
83 void esl_set_gain(struct esl_pcmcia_softc *, int, int);
84 void esl_speaker_on(struct esl_pcmcia_softc *);
85 void esl_speaker_off(struct esl_pcmcia_softc *);
86 int esl_identify(struct esl_pcmcia_softc *);
87 int esl_rdsp(struct esl_pcmcia_softc *);
88 int esl_wdsp(struct esl_pcmcia_softc *, u_char);
89 u_char esl_dsp_read_ready(struct esl_pcmcia_softc *);
90 u_char esl_dsp_write_ready(struct esl_pcmcia_softc *);
91 u_char esl_get_dsp_status(struct esl_pcmcia_softc *);
92 u_char esl_read_x_reg(struct esl_pcmcia_softc *, u_char);
93 int esl_write_x_reg(struct esl_pcmcia_softc *, u_char, u_char);
94 void esl_clear_xreg_bits(struct esl_pcmcia_softc *, u_char, u_char);
95 void esl_set_xreg_bits(struct esl_pcmcia_softc *, u_char, u_char);
96 u_char esl_read_mix_reg(struct esl_pcmcia_softc *, u_char);
97 void esl_write_mix_reg(struct esl_pcmcia_softc *, u_char, u_char);
98 void esl_clear_mreg_bits(struct esl_pcmcia_softc *, u_char, u_char);
99 void esl_set_mreg_bits(struct esl_pcmcia_softc *, u_char, u_char);
100 void esl_read_multi_mix_reg(struct esl_pcmcia_softc *, u_char,
101 u_int8_t *, bus_size_t);
102 u_int esl_srtotc(u_int);
103 u_int esl_srtofc(u_int);
104
105 struct audio_device esl_device = {
106 "AudioDrive",
107 "",
108 "esl"
109 };
110
111 struct audio_hw_if esl_hw_if = {
112 esl_open,
113 esl_close,
114 NULL,
115 esl_query_encoding,
116 esl_set_params,
117 esl_round_blocksize,
118 NULL,
119 NULL,
120 NULL,
121 NULL,
122 NULL,
123 esl_halt_output,
124 esl_halt_input,
125 esl_speaker_ctl,
126 esl_getdev,
127 NULL,
128 esl_set_port,
129 esl_get_port,
130 esl_query_devinfo,
131 NULL,
132 NULL,
133 NULL,
134 NULL,
135 esl_get_props,
136 esl_trigger_output,
137 NULL,
138 NULL,
139 };
140
141 static char *eslmodel[] = {
142 "1688",
143 "688",
144 };
145
146 int
147 esl_open(void *hdl, int flags)
148 {
149
150 struct esl_pcmcia_softc *sc = hdl;
151 int i;
152
153 if (sc->sc_esl.sc_open != 0)
154 return (EBUSY);
155
156 if ((*sc->sc_enable)(sc))
157 return (ENXIO);
158
159 if (esl_reset(sc) != 0) {
160 printf("%s: esl_open: esl_reset failed\n",
161 sc->sc_esl.sc_dev.dv_xname);
162 return (ENXIO);
163 }
164
165 /* because we did a reset */
166 esl_setup(sc);
167
168 /* Set all mixer controls to sane values (since we just did a reset) */
169 for (i = 0; i < ESS_MAX_NDEVS; i++)
170 esl_set_gain(sc, i, 1);
171
172 sc->sc_esl.sc_open = 1;
173
174 /* XXX: Delay a bit */
175 delay(10000);
176
177 return (0);
178 }
179
180
181 void
182 esl_close(void *hdl)
183 {
184 struct esl_pcmcia_softc *sc = hdl;
185
186 esl_speaker_off(sc);
187
188 (*sc->sc_disable)(sc);
189
190 sc->sc_esl.sc_open = 0;
191
192 return;
193 }
194
195 int
196 esl_query_encoding(void *hdl, struct audio_encoding *ae)
197 {
198
199 switch (ae->index) {
200 case 0:
201 strcpy(ae->name, AudioEulinear);
202 ae->encoding = AUDIO_ENCODING_ULINEAR;
203 ae->precision = 8;
204 ae->flags = 0;
205 return (0);
206 case 1:
207 strcpy(ae->name, AudioEmulaw);
208 ae->encoding = AUDIO_ENCODING_ULAW;
209 ae->precision = 8;
210 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
211 return (0);
212 case 2:
213 strcpy(ae->name, AudioEalaw);
214 ae->encoding = AUDIO_ENCODING_ALAW;
215 ae->precision = 8;
216 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
217 return (0);
218 case 3:
219 strcpy(ae->name, AudioEslinear);
220 ae->encoding = AUDIO_ENCODING_SLINEAR;
221 ae->precision = 8;
222 ae->flags = 0;
223 return (0);
224 case 4:
225 strcpy(ae->name, AudioEslinear_le);
226 ae->encoding = AUDIO_ENCODING_SLINEAR_LE;
227 ae->precision = 16;
228 ae->flags = 0;
229 return (0);
230 case 5:
231 strcpy(ae->name, AudioEulinear_le);
232 ae->encoding = AUDIO_ENCODING_ULINEAR_LE;
233 ae->precision = 16;
234 ae->flags = 0;
235 return (0);
236 case 6:
237 strcpy(ae->name, AudioEslinear_be);
238 ae->encoding = AUDIO_ENCODING_SLINEAR_BE;
239 ae->precision = 16;
240 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
241 return (0);
242 case 7:
243 strcpy(ae->name, AudioEulinear_be);
244 ae->encoding = AUDIO_ENCODING_ULINEAR_BE;
245 ae->precision = 16;
246 ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
247 return (0);
248 default:
249 return EINVAL;
250 }
251 return (0);
252 }
253
254 int
255 esl_set_params(void *hdl, int setmode, int usemode,
256 struct audio_params *play, struct audio_params *rec)
257 {
258 struct esl_pcmcia_softc *sc = hdl;
259 int rate;
260
261 if (play->sample_rate < ESS_MINRATE ||
262 play->sample_rate > ESS_MAXRATE ||
263 (play->precision != 8 && play->precision != 16) ||
264 (play->channels != 1 && play->channels != 2))
265 return (EINVAL);
266
267 play->factor = 1;
268 play->sw_code = NULL;
269 switch (play->encoding) {
270 case AUDIO_ENCODING_SLINEAR_BE:
271 case AUDIO_ENCODING_ULINEAR_BE:
272 if (play->precision == 16)
273 play->sw_code = swap_bytes;
274 break;
275 case AUDIO_ENCODING_SLINEAR_LE:
276 case AUDIO_ENCODING_ULINEAR_LE:
277 break;
278 case AUDIO_ENCODING_ULAW:
279 play->factor = 2;
280 play->sw_code = mulaw_to_ulinear16_le;
281 break;
282 case AUDIO_ENCODING_ALAW:
283 play->factor = 2;
284 play->sw_code = alaw_to_ulinear16_le;
285 break;
286 default:
287 return (EINVAL);
288 }
289
290 rate = play->sample_rate;
291
292 esl_write_x_reg(sc, ESS_XCMD_SAMPLE_RATE, esl_srtotc(rate));
293 esl_write_x_reg(sc, ESS_XCMD_FILTER_CLOCK, esl_srtofc(rate));
294
295 return (0);
296 }
297
298 int
299 esl_round_blocksize(void *hdl, int bs)
300 {
301
302 return ((bs / 128) * 128);
303 }
304
305
306 int
307 esl_halt_output(void *hdl)
308 {
309 struct esl_pcmcia_softc *sc = hdl;
310
311 if (sc->sc_esl.active) {
312 esl_clear_xreg_bits(sc, ESS_XCMD_AUDIO1_CTRL2,
313 ESS_AUDIO1_CTRL2_FIFO_ENABLE);
314 sc->sc_esl.active = 0;
315 }
316
317 return (0);
318 }
319
320 int
321 esl_halt_input(void *hdl)
322 {
323
324 return (0);
325 }
326
327 int
328 esl_speaker_ctl(void *hdl, int on)
329 {
330
331 return (0);
332 }
333
334 int
335 esl_getdev(void *hdl, struct audio_device *ret)
336 {
337
338 *ret = esl_device;
339 return (0);
340 }
341
342 int
343 esl_set_port(void *hdl, mixer_ctrl_t *mc)
344 {
345 struct esl_pcmcia_softc *sc = hdl;
346 int lgain, rgain;
347
348 switch(mc->dev) {
349 case ESS_MASTER_VOL:
350 case ESS_DAC_PLAY_VOL:
351 case ESS_SYNTH_PLAY_VOL:
352 if (mc->type != AUDIO_MIXER_VALUE)
353 return (EINVAL);
354
355 switch(mc->un.value.num_channels) {
356 case 1:
357 lgain = rgain = ESS_4BIT_GAIN(
358 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO]);
359 break;
360 case 2:
361 lgain = ESS_4BIT_GAIN(
362 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT]);
363 rgain = ESS_4BIT_GAIN(
364 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT]);
365 break;
366 default:
367 return (EINVAL);
368 }
369 sc->sc_esl.gain[mc->dev][ESS_LEFT] = lgain;
370 sc->sc_esl.gain[mc->dev][ESS_RIGHT] = rgain;
371 esl_set_gain(sc, mc->dev, 1);
372 return (0);
373 break;
374 default:
375 break;
376 }
377
378 return (EINVAL);
379 }
380
381 int
382 esl_get_port(void *hdl, mixer_ctrl_t *mc)
383 {
384 struct esl_pcmcia_softc *sc = hdl;
385
386 switch(mc->dev) {
387 case ESS_MASTER_VOL:
388 case ESS_DAC_PLAY_VOL:
389 case ESS_SYNTH_PLAY_VOL:
390 switch(mc->un.value.num_channels) {
391 case 1:
392 mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
393 sc->sc_esl.gain[mc->dev][ESS_LEFT];
394 break;
395 case 2:
396 mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] =
397 sc->sc_esl.gain[mc->dev][ESS_LEFT];
398 mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] =
399 sc->sc_esl.gain[mc->dev][ESS_RIGHT];
400 break;
401 default:
402 return (EINVAL);
403 }
404 return (0);
405 default:
406 break;
407 }
408
409 return (EINVAL);
410 }
411
412 int
413 esl_query_devinfo(void *hdl, mixer_devinfo_t *di)
414 {
415
416 switch(di->index) {
417 case ESS_DAC_PLAY_VOL:
418 di->mixer_class = ESS_INPUT_CLASS;
419 di->next = di->prev = AUDIO_MIXER_LAST;
420 strcpy(di->label.name, AudioNdac);
421 di->type = AUDIO_MIXER_VALUE;
422 di->un.v.num_channels = 2;
423 strcpy(di->un.v.units.name, AudioNvolume);
424 return (0);
425 case ESS_SYNTH_PLAY_VOL:
426 di->mixer_class = ESS_INPUT_CLASS;
427 di->next = di->prev = AUDIO_MIXER_LAST;
428 strcpy(di->label.name, AudioNfmsynth);
429 di->type = AUDIO_MIXER_VALUE;
430 di->un.v.num_channels = 2;
431 strcpy(di->un.v.units.name, AudioNvolume);
432 return (0);
433 case ESS_INPUT_CLASS:
434 di->mixer_class = ESS_INPUT_CLASS;
435 di->next = di->prev = AUDIO_MIXER_LAST;
436 strcpy(di->label.name, AudioCinputs);
437 di->type = AUDIO_MIXER_CLASS;
438 return (0);
439 case ESS_MASTER_VOL:
440 di->mixer_class = ESS_OUTPUT_CLASS;
441 di->next = di->prev = AUDIO_MIXER_LAST;
442 strcpy(di->label.name, AudioNmaster);
443 di->type = AUDIO_MIXER_VALUE;
444 di->un.v.num_channels = 2;
445 strcpy(di->un.v.units.name, AudioNvolume);
446 return (0);
447 case ESS_OUTPUT_CLASS:
448 di->mixer_class = ESS_OUTPUT_CLASS;
449 di->next = di->prev = AUDIO_MIXER_LAST;
450 strcpy(di->label.name, AudioCoutputs);
451 di->type = AUDIO_MIXER_CLASS;
452 return (0);
453 default:
454 break;
455 }
456
457 return (ENXIO);
458 }
459
460 int
461 esl_get_props(void *hdl)
462 {
463
464 return (AUDIO_PROP_MMAP);
465 }
466
467 int
468 esl_trigger_output(void *hdl, void *start, void *end, int blksize,
469 void (*intr)(void *), void *intrarg,
470 struct audio_params *param)
471 {
472 struct esl_pcmcia_softc *sc = hdl;
473 bus_space_tag_t iot = sc->sc_pcioh.iot;
474 bus_space_handle_t ioh = sc->sc_pcioh.ioh;
475 int bs;
476 int cnt;
477 u_int8_t reg;
478
479 if (sc->sc_esl.active) {
480 printf("%s: esl_trigger_output: already running\n",
481 sc->sc_esl.sc_dev.dv_xname);
482 return (1);
483 }
484
485 sc->sc_esl.active = 1;
486 sc->sc_esl.intr = intr;
487 sc->sc_esl.arg = intrarg;
488
489 /* Stereo or Mono selection */
490 reg = esl_read_x_reg(sc, ESS_XCMD_AUDIO_CTRL);
491 if (param->channels == 2) {
492 reg &= ~ESS_AUDIO_CTRL_MONO;
493 reg |= ESS_AUDIO_CTRL_STEREO;
494 } else {
495 reg |= ESS_AUDIO_CTRL_MONO;
496 reg &= ~ESS_AUDIO_CTRL_STEREO;
497 }
498 esl_write_x_reg(sc, ESS_XCMD_AUDIO_CTRL, reg);
499
500 /* Program the FIFO (16-bit/8-bit, signed/unsigned, stereo/mono) */
501 reg = esl_read_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1);
502 if (param->precision * param->factor == 16)
503 reg |= ESS_AUDIO1_CTRL1_FIFO_SIZE;
504 else
505 reg &= ~ESS_AUDIO1_CTRL1_FIFO_SIZE;
506 if (param->channels == 2)
507 reg |= ESS_AUDIO1_CTRL1_FIFO_STEREO;
508 else
509 reg &= ~ESS_AUDIO1_CTRL1_FIFO_STEREO;
510 if (param->encoding == AUDIO_ENCODING_SLINEAR_BE ||
511 param->encoding == AUDIO_ENCODING_SLINEAR_LE)
512 reg |= ESS_AUDIO1_CTRL1_FIFO_SIGNED;
513 else
514 reg &= ~ESS_AUDIO1_CTRL1_FIFO_SIGNED;
515 reg |= ESS_AUDIO1_CTRL1_FIFO_CONNECT;
516 esl_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL1, reg);
517
518 /* Program transfer count registers with 2s complement of count */
519 bs = -blksize;
520 esl_write_x_reg(sc, ESS_XCMD_XFER_COUNTLO, bs);
521 esl_write_x_reg(sc, ESS_XCMD_XFER_COUNTHI, bs >> 8);
522
523 esl_wdsp(sc, ESS_ACMD_ENABLE_SPKR);
524 reg = esl_read_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2);
525 reg &= ~(ESS_AUDIO1_CTRL2_DMA_READ | ESS_AUDIO1_CTRL2_ADC_ENABLE);
526 reg |= ESS_AUDIO1_CTRL2_FIFO_ENABLE | ESS_AUDIO1_CTRL2_AUTO_INIT;
527 esl_write_x_reg(sc, ESS_XCMD_AUDIO1_CTRL2, reg);
528 cnt = (char *)end - (char *)start;
529 if (cnt == 0)
530 printf("%s: no count left\n", sc->sc_esl.sc_dev.dv_xname);
531
532 sc->sc_esl.sc_dmaaddr = sc->sc_esl.sc_dmastart = start;
533 sc->sc_esl.sc_dmaend = end;
534 sc->sc_esl.sc_blksize = blksize;
535 sc->sc_esl.sc_blkpos = 0;
536
537 /* XXX: Delay a bit */
538 delay(10000);
539
540 /* Prime the FIFO */
541 bus_space_write_multi_1(iot, ioh, ESS_FIFO_WRITE, start, ESS_FIFO_SIZE);
542 sc->sc_esl.sc_dmaaddr += ESS_FIFO_SIZE;
543 sc->sc_esl.sc_blkpos += ESS_FIFO_SIZE;
544
545 return (0);
546 }
547
548 /* Additional subroutines used by the above (NOT required by audio(9)) */
549
550 int
551 esl_init(struct esl_pcmcia_softc *sc)
552 {
553 const int ENABLE[] = { 0x0, 0x9, 0xb };
554 const int ENABLE_ORDER[] = { 1, 1, 1, 2, 1, 2, 1, 1, 2, 1, 0, -1 };
555 struct audio_attach_args aa;
556 int i;
557 int model;
558 bus_space_tag_t iot = sc->sc_pcioh.iot;
559 bus_space_handle_t ioh = sc->sc_pcioh.ioh;
560
561 sc->sc_esl.sc_open = 0;
562
563 /* Initialization sequence */
564 for (i = 0; ENABLE_ORDER[i] != -1; i++)
565 bus_space_read_1(iot, ioh, ENABLE[i]);
566 if (esl_reset(sc)) {
567 printf("%s: esl_init: esl_reset failed\n",
568 sc->sc_esl.sc_dev.dv_xname);
569 return (1);
570 }
571
572 if (esl_identify(sc)) {
573 printf("%s: esl_init: esl_identify failed\n",
574 sc->sc_esl.sc_dev.dv_xname);
575 return (1);
576 }
577
578 if (!sc->sc_esl.sc_version)
579 return (1); /* Probably a Sound Blaster */
580
581 model = ESS_UNSUPPORTED;
582
583 switch (sc->sc_esl.sc_version & 0xfff0) {
584 case 0x6880:
585 if ((sc->sc_esl.sc_version & 0x0f) >= 8) {
586 model = ESS_1688;
587 } else {
588 model = ESS_688;
589 }
590 break;
591 }
592
593 if (model == ESS_UNSUPPORTED) {
594 printf("%s: unknown model 0x%04x\n",
595 sc->sc_esl.sc_dev.dv_xname, sc->sc_esl.sc_version);
596 return (1);
597 }
598
599 printf("%s: ESS AudioDrive %s [version 0x%04x]\n",
600 sc->sc_esl.sc_dev.dv_xname, eslmodel[model],
601 sc->sc_esl.sc_version);
602
603 /* Set volumes to 50% */
604 for (i = 0; i < ESS_MAX_NDEVS; i++) {
605 sc->sc_esl.gain[i][ESS_LEFT] =
606 sc->sc_esl.gain[i][ESS_RIGHT] =
607 ESS_4BIT_GAIN(AUDIO_MAX_GAIN / 2);
608 esl_set_gain(sc, i, 1);
609 }
610
611 sc->sc_audiodev = audio_attach_mi(&esl_hw_if, sc, &sc->sc_esl.sc_dev);
612
613 /* Attach the OPL device */
614 aa.type = AUDIODEV_TYPE_OPL;
615 aa.hwif = 0;
616 aa.hdl = 0;
617
618 sc->sc_opldev = config_found(&sc->sc_esl.sc_dev, &aa, audioprint);
619
620 /* Disable speaker until device is opened */
621 esl_speaker_off(sc);
622
623 sc->sc_esl.sc_open = 0;
624
625 return (0);
626 }
627
628 int
629 esl_intr(void *hdl)
630 {
631 struct esl_pcmcia_softc *sc = hdl;
632 bus_space_tag_t iot = sc->sc_pcioh.iot;
633 bus_space_handle_t ioh = sc->sc_pcioh.ioh;
634 u_int8_t reg;
635 u_char *pos;
636
637 /* Clear interrupt */
638 reg = bus_space_read_1(iot, ioh, ESS_CLEAR_INTR);
639
640 if (sc->sc_esl.active) {
641 reg = bus_space_read_1(iot, ioh, ESS_DSP_RW_STATUS);
642 while (reg & ESS_DSP_READ_HALF) {
643 pos = sc->sc_esl.sc_dmaaddr;
644 bus_space_write_multi_1(iot, ioh, ESS_FIFO_WRITE, pos,
645 ESS_FIFO_SIZE / 2);
646
647 sc->sc_esl.sc_blkpos += (ESS_FIFO_SIZE / 2);
648 if (sc->sc_esl.sc_blkpos >= sc->sc_esl.sc_blksize) {
649 (*sc->sc_esl.intr)(sc->sc_esl.arg);
650 sc->sc_esl.sc_blkpos -= sc->sc_esl.sc_blksize;
651 }
652 pos += (ESS_FIFO_SIZE / 2);
653 if (pos >= sc->sc_esl.sc_dmaend)
654 pos = sc->sc_esl.sc_dmastart;
655
656 sc->sc_esl.sc_dmaaddr = pos;
657 reg = bus_space_read_1(iot, ioh, ESS_DSP_RW_STATUS);
658 }
659 }
660
661 return (1);
662 }
663
664 int
665 esl_reset(struct esl_pcmcia_softc *sc)
666 {
667 bus_space_tag_t iot = sc->sc_pcioh.iot;
668 bus_space_handle_t ioh = sc->sc_pcioh.ioh;
669
670 bus_space_write_1(iot, ioh, ESS_DSP_RESET, ESS_RESET_EXT);
671 delay(10000); /* XXX: Ugly, but ess.c does this too */
672 bus_space_write_1(iot, ioh, ESS_DSP_RESET, 0);
673 if (esl_rdsp(sc) != ESS_MAGIC)
674 return (1);
675
676 /* Enable access to the extended command set */
677 esl_wdsp(sc, ESS_ACMD_ENABLE_EXT);
678
679 return (0);
680 }
681
682 void
683 esl_setup(struct esl_pcmcia_softc *sc)
684 {
685 u_char reg;
686
687 /*
688 * Configure IRQ. Set bit 5 of B1h high to enable interrupt on
689 * FIFOHE, and keep bit 6 low.
690 */
691 reg = ESS_IRQ_CTRL_MASK | 0x20 | ESS_IRQ_CTRL_INTRA;
692 esl_write_x_reg(sc, ESS_XCMD_IRQ_CTRL, reg);
693
694 /*
695 * "Config DRQ", well not really. Instead of configuring a DRQ,
696 * we leave bits 7 and 5 of B2h low.
697 */
698 reg = 0x10 | 0x40;
699 esl_write_x_reg(sc, ESS_XCMD_DRQ_CTRL, reg);
700
701 return;
702 }
703
704 void
705 esl_set_gain(struct esl_pcmcia_softc *sc, int port, int on)
706 {
707 int gain, left, right;
708 int src;
709
710 switch(port) {
711 case ESS_MASTER_VOL:
712 src = ESS_MREG_VOLUME_MASTER;
713 break;
714 case ESS_DAC_PLAY_VOL:
715 src = ESS_MREG_VOLUME_VOICE;
716 break;
717 case ESS_SYNTH_PLAY_VOL:
718 src = ESS_MREG_VOLUME_SYNTH;
719 break;
720 default:
721 return;
722 }
723
724 if (on) {
725 left = sc->sc_esl.gain[port][ESS_LEFT];
726 right = sc->sc_esl.gain[port][ESS_RIGHT];
727 } else
728 left = right = 0;
729
730 gain = ESS_STEREO_GAIN(left, right);
731
732 esl_write_mix_reg(sc, src, gain);
733
734 return;
735 }
736
737 void
738 esl_speaker_on(struct esl_pcmcia_softc *sc)
739 {
740
741 /* Unmute the DAC */
742 esl_set_gain(sc, ESS_DAC_PLAY_VOL, 1);
743
744 return;
745 }
746
747 void
748 esl_speaker_off(struct esl_pcmcia_softc *sc)
749 {
750
751 /* Mute the DAC */
752 esl_set_gain(sc, ESS_DAC_PLAY_VOL, 0);
753
754 return;
755 }
756
757 int
758 esl_identify(struct esl_pcmcia_softc *sc)
759 {
760 u_char reg1, reg2;
761 int i;
762
763 esl_wdsp(sc, ESS_ACMD_LEGACY_ID);
764 for (i = 1000, reg1 = reg2 = 0; i; i--)
765 if (esl_dsp_read_ready(sc)) {
766 if (reg1 == 0)
767 reg1 = esl_rdsp(sc);
768 else
769 reg2 = esl_rdsp(sc);
770 }
771
772 sc->sc_esl.sc_version = (reg1 << 8) + reg2;
773
774 return (0);
775 }
776
777 /* Read a byte from the DSP */
778 int
779 esl_rdsp(struct esl_pcmcia_softc *sc)
780 {
781 bus_space_tag_t iot = sc->sc_pcioh.iot;
782 bus_space_handle_t ioh = sc->sc_pcioh.ioh;
783 int i;
784
785 for (i = ESS_READ_TIMEOUT; i > 0; --i) {
786 if (esl_dsp_read_ready(sc)) {
787 i = bus_space_read_1(iot, ioh, ESS_DSP_READ);
788 return (i);
789 } else
790 delay(10);
791 }
792
793 printf("esl_rdsp: timed out\n");
794 return (-1);
795 }
796
797 /* Write a byte to the DSP */
798 int
799 esl_wdsp(struct esl_pcmcia_softc *sc, u_char v)
800 {
801 bus_space_tag_t iot = sc->sc_pcioh.iot;
802 bus_space_handle_t ioh = sc->sc_pcioh.ioh;
803 int i;
804
805 for (i = ESS_WRITE_TIMEOUT; i > 0; --i) {
806 if (esl_dsp_write_ready(sc)) {
807 bus_space_write_1(iot, ioh, ESS_DSP_WRITE, v);
808 return (0);
809 } else
810 delay(10);
811 }
812
813 printf("esl_wdsp(0x%02x): timed out\n", v);
814 return (-1);
815 }
816
817 /* Get the read status of the DSP: 1 == Ready, 0 == Not Ready */
818 u_char
819 esl_dsp_read_ready(struct esl_pcmcia_softc *sc)
820 {
821
822 return ((esl_get_dsp_status(sc) & ESS_DSP_READ_READY) ? 1 : 0);
823 }
824
825 /* Get the write status of the DSP: 1 == Ready, 0 == Not Ready */
826 u_char
827 esl_dsp_write_ready(struct esl_pcmcia_softc *sc)
828 {
829
830 return ((esl_get_dsp_status(sc) & ESS_DSP_WRITE_BUSY) ? 0 : 1);
831 }
832
833 /* Return the status of the DSP */
834 u_char
835 esl_get_dsp_status(struct esl_pcmcia_softc *sc)
836 {
837
838 return (bus_space_read_1(sc->sc_pcioh.iot, sc->sc_pcioh.ioh,
839 ESS_DSP_RW_STATUS));
840 }
841
842 /* Read a value from one of the extended registers */
843 u_char
844 esl_read_x_reg(struct esl_pcmcia_softc *sc, u_char reg)
845 {
846 int error;
847
848 if ((error = esl_wdsp(sc, 0xC0)) == 0)
849 error = esl_wdsp(sc, reg);
850 if (error)
851 printf("esl_read_x_reg: error reading 0x%02x\n", reg);
852 return (esl_rdsp(sc));
853 }
854
855 /* Write a value to one of the extended registers */
856 int
857 esl_write_x_reg(struct esl_pcmcia_softc *sc, u_char reg, u_char val)
858 {
859 int error;
860
861 if ((error = esl_wdsp(sc, reg)) == 0)
862 error = esl_wdsp(sc, val);
863
864 return (error);
865 }
866
867 void
868 esl_clear_xreg_bits(struct esl_pcmcia_softc *sc, u_char reg, u_char mask)
869 {
870
871 esl_write_x_reg(sc, reg, esl_read_x_reg(sc, reg) & ~mask);
872
873 return;
874 }
875
876 void
877 esl_set_xreg_bits(struct esl_pcmcia_softc *sc, u_char reg, u_char mask)
878 {
879
880 esl_write_x_reg(sc, reg, esl_read_x_reg(sc, reg) | mask);
881 }
882
883 u_char
884 esl_read_mix_reg(struct esl_pcmcia_softc *sc, u_char reg)
885 {
886 bus_space_tag_t iot = sc->sc_pcioh.iot;
887 bus_space_handle_t ioh = sc->sc_pcioh.ioh;
888 #if 0
889 int s;
890 #endif
891 u_char val;
892
893 #if 0
894 s = splaudio();
895 #endif
896 bus_space_write_1(iot, ioh, ESS_MIX_REG_SELECT, reg);
897 val = bus_space_read_1(iot, ioh, ESS_MIX_REG_DATA);
898 #if 0
899 splx(s);
900 #endif
901
902 return (val);
903 }
904
905 void
906 esl_write_mix_reg(struct esl_pcmcia_softc *sc, u_char reg, u_char val)
907 {
908 bus_space_tag_t iot = sc->sc_pcioh.iot;
909 bus_space_handle_t ioh = sc->sc_pcioh.ioh;
910 #if 0
911 int s;
912 #endif
913
914 #if 0
915 s = splaudio();
916 #endif
917 bus_space_write_1(iot, ioh, ESS_MIX_REG_SELECT, reg);
918 bus_space_write_1(iot, ioh, ESS_MIX_REG_DATA, val);
919 #if 0
920 splx(s);
921 #endif
922
923 return;
924 }
925
926 void
927 esl_clear_mreg_bits(struct esl_pcmcia_softc *sc, u_char reg, u_char mask)
928 {
929
930 esl_write_mix_reg(sc, reg, esl_read_mix_reg(sc, reg) & ~mask);
931
932 return;
933 }
934
935 void
936 esl_set_mreg_bits(struct esl_pcmcia_softc *sc, u_char reg, u_char mask)
937 {
938
939 esl_write_mix_reg(sc, reg, esl_read_mix_reg(sc, reg) | mask);
940
941 return;
942 }
943
944 void
945 esl_read_multi_mix_reg(struct esl_pcmcia_softc *sc, u_char reg,
946 u_int8_t *datap, bus_size_t count)
947 {
948 bus_space_tag_t iot = sc->sc_pcioh.iot;
949 bus_space_handle_t ioh = sc->sc_pcioh.ioh;
950 #if 0
951 int s;
952 #endif
953
954 #if 0
955 s = splaudio();
956 #endif
957 bus_space_write_1(iot, ioh, ESS_MIX_REG_SELECT, reg);
958 bus_space_read_multi_1(iot, ioh, ESS_MIX_REG_DATA, datap, count);
959 #if 0
960 splx(s);
961 #endif
962
963 return;
964 }
965
966 /* Calculate the time constant for the requested sampling rate */
967 u_int
968 esl_srtotc(u_int rate)
969 {
970 u_int tc;
971
972 /* The following formulas are from the ESS data sheet. */
973 if (rate <= 22050)
974 tc = 128 - 397700L / rate;
975 else
976 tc = 256 - 795500L / rate;
977
978 return (tc);
979 }
980
981 /* Calculate the filter constant for the requested sampling rate */
982 u_int
983 esl_srtofc(u_int rate)
984 {
985
986 /* From dev/isa/ess.c:ess_srtofc() rev 1.53 */
987 return (256 - 200279L / rate);
988 }
Cache object: bfd6f7d906bf1a33ea6b359b4f2fd5a3
|