auich.c revision 1.3.6.1 1 /* $NetBSD: auich.c,v 1.3.6.1 2001/10/11 00:02:08 fvdl Exp $ */
2
3 /*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
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 /*
40 * Copyright (c) 2000 Michael Shalayeff
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. The name of the author may not be used to endorse or promote products
52 * derived from this software without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
55 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
56 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
57 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
58 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
59 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
60 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
62 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
63 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
64 * THE POSSIBILITY OF SUCH DAMAGE.
65 *
66 * from OpenBSD: ich.c,v 1.3 2000/08/11 06:17:18 mickey Exp
67 */
68
69 /* #define ICH_DEBUG */
70 /*
71 * AC'97 audio found on Intel 810/820/440MX chipsets.
72 * http://developer.intel.com/design/chipsets/datashts/290655.htm
73 * http://developer.intel.com/design/chipsets/manuals/298028.htm
74 *
75 * TODO:
76 *
77 * - Probe codecs for supported sample rates.
78 *
79 * - Add support for the microphone input.
80 */
81
82 #include <sys/param.h>
83 #include <sys/systm.h>
84 #include <sys/kernel.h>
85 #include <sys/malloc.h>
86 #include <sys/device.h>
87 #include <sys/fcntl.h>
88 #include <sys/proc.h>
89
90 #include <uvm/uvm_extern.h> /* for PAGE_SIZE */
91
92 #include <dev/pci/pcidevs.h>
93 #include <dev/pci/pcivar.h>
94 #include <dev/pci/auichreg.h>
95
96 #include <sys/audioio.h>
97 #include <dev/audio_if.h>
98 #include <dev/mulaw.h>
99 #include <dev/auconv.h>
100
101 #include <machine/bus.h>
102
103 #include <dev/ic/ac97reg.h>
104 #include <dev/ic/ac97var.h>
105
106 struct auich_dma {
107 bus_dmamap_t map;
108 caddr_t addr;
109 bus_dma_segment_t segs[1];
110 int nsegs;
111 size_t size;
112 struct auich_dma *next;
113 };
114
115 #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
116 #define KERNADDR(p) ((void *)((p)->addr))
117
118 struct auich_cdata {
119 struct auich_dmalist ic_dmalist_pcmo[ICH_DMALIST_MAX];
120 struct auich_dmalist ic_dmalist_pcmi[ICH_DMALIST_MAX];
121 struct auich_dmalist ic_dmalist_mici[ICH_DMALIST_MAX];
122 };
123
124 #define ICH_CDOFF(x) offsetof(struct auich_cdata, x)
125 #define ICH_PCMO_OFF(x) ICH_CDOFF(ic_dmalist_pcmo[(x)])
126 #define ICH_PCMI_OFF(x) ICH_CDOFF(ic_dmalist_pcmi[(x)])
127 #define ICH_MICI_OFF(x) ICH_CDOFF(ic_dmalist_mici[(x)])
128
129 struct auich_softc {
130 struct device sc_dev;
131 void *sc_ih;
132
133 audio_device_t sc_audev;
134
135 bus_space_tag_t iot;
136 bus_space_handle_t mix_ioh;
137 bus_space_handle_t aud_ioh;
138 bus_dma_tag_t dmat;
139
140 struct ac97_codec_if *codec_if;
141 struct ac97_host_if host_if;
142
143 /* DMA scatter-gather lists. */
144 bus_dmamap_t sc_cddmamap;
145 #define sc_cddma sc_cddmamap->dm_segs[0].ds_addr
146
147 struct auich_cdata *sc_cdata;
148 #define dmalist_pcmo sc_cdata->ic_dmalist_pcmo
149 #define dmalist_pcmi sc_cdata->ic_dmalist_pcmi
150 #define dmalist_mici sc_cdata->ic_dmalist_mici
151
152 int ptr_pcmo,
153 ptr_pcmi,
154 ptr_mici;
155
156 /* i/o buffer pointers */
157 u_int32_t pcmo_start, pcmo_p, pcmo_end;
158 int pcmo_blksize, pcmo_fifoe;
159
160 u_int32_t pcmi_start, pcmi_p, pcmi_end;
161 int pcmi_blksize, pcmi_fifoe;
162
163 u_int32_t mici_start, mici_p, mici_end;
164 int mici_blksize, mici_fifoe;
165
166 struct auich_dma *sc_dmas;
167
168 void (*sc_pintr)(void *);
169 void *sc_parg;
170
171 void (*sc_rintr)(void *);
172 void *sc_rarg;
173 };
174
175 /* Debug */
176 #ifdef AUDIO_DEBUG
177 #define DPRINTF(l,x) do { if (auich_debug & (l)) printf x; } while(0)
178 int auich_debug = 0xfffe;
179 #define ICH_DEBUG_CODECIO 0x0001
180 #define ICH_DEBUG_DMA 0x0002
181 #define ICH_DEBUG_PARAM 0x0004
182 #else
183 #define DPRINTF(x,y) /* nothing */
184 #endif
185
186 int auich_match(struct device *, struct cfdata *, void *);
187 void auich_attach(struct device *, struct device *, void *);
188 int auich_intr(void *);
189
190 struct cfattach auich_ca = {
191 sizeof(struct auich_softc), auich_match, auich_attach
192 };
193
194 int auich_open(void *, int);
195 void auich_close(void *);
196 int auich_query_encoding(void *, struct audio_encoding *);
197 int auich_set_params(void *, int, int, struct audio_params *,
198 struct audio_params *);
199 int auich_round_blocksize(void *, int);
200 int auich_halt_output(void *);
201 int auich_halt_input(void *);
202 int auich_getdev(void *, struct audio_device *);
203 int auich_set_port(void *, mixer_ctrl_t *);
204 int auich_get_port(void *, mixer_ctrl_t *);
205 int auich_query_devinfo(void *, mixer_devinfo_t *);
206 void *auich_allocm(void *, int, size_t, int, int);
207 void auich_freem(void *, void *, int);
208 size_t auich_round_buffersize(void *, int, size_t);
209 paddr_t auich_mappage(void *, void *, off_t, int);
210 int auich_get_props(void *);
211 int auich_trigger_output(void *, void *, void *, int, void (*)(void *),
212 void *, struct audio_params *);
213 int auich_trigger_input(void *, void *, void *, int, void (*)(void *),
214 void *, struct audio_params *);
215
216 int auich_alloc_cdata(struct auich_softc *);
217
218 int auich_allocmem(struct auich_softc *, size_t, size_t,
219 struct auich_dma *);
220 int auich_freemem(struct auich_softc *, struct auich_dma *);
221
222 struct audio_hw_if auich_hw_if = {
223 auich_open,
224 auich_close,
225 NULL, /* drain */
226 auich_query_encoding,
227 auich_set_params,
228 auich_round_blocksize,
229 NULL, /* commit_setting */
230 NULL, /* init_output */
231 NULL, /* init_input */
232 NULL, /* start_output */
233 NULL, /* start_input */
234 auich_halt_output,
235 auich_halt_input,
236 NULL, /* speaker_ctl */
237 auich_getdev,
238 NULL, /* getfd */
239 auich_set_port,
240 auich_get_port,
241 auich_query_devinfo,
242 auich_allocm,
243 auich_freem,
244 auich_round_buffersize,
245 auich_mappage,
246 auich_get_props,
247 auich_trigger_output,
248 auich_trigger_input,
249 NULL, /* dev_ioctl */
250 };
251
252 int auich_attach_codec(void *, struct ac97_codec_if *);
253 int auich_read_codec(void *, u_int8_t, u_int16_t *);
254 int auich_write_codec(void *, u_int8_t, u_int16_t);
255 void auich_reset_codec(void *);
256
257 static const struct auich_devtype {
258 int product;
259 const char *name;
260 const char *shortname;
261 } auich_devices[] = {
262 { PCI_PRODUCT_INTEL_82801AA_ACA,
263 "i82801AA (ICH) AC-97 Audio", "ICH" },
264 { PCI_PRODUCT_INTEL_82801AB_ACA,
265 "i82801AB (ICH0) AC-97 Audio", "ICH0" },
266 { PCI_PRODUCT_INTEL_82801BA_ACA,
267 "i82801BA (ICH2) AC-97 Audio", "ICH2" },
268 { PCI_PRODUCT_INTEL_82440MX_ACA,
269 "i82440MX AC-97 Audio", "440MX" },
270
271 { 0,
272 NULL, NULL },
273 };
274
275 static const struct auich_devtype *
276 auich_lookup(struct pci_attach_args *pa)
277 {
278 const struct auich_devtype *d;
279
280 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL)
281 return (NULL);
282
283 for (d = auich_devices; d->name != NULL; d++) {
284 if (PCI_PRODUCT(pa->pa_id) == d->product)
285 return (d);
286 }
287
288 return (NULL);
289 }
290
291 int
292 auich_match(struct device *parent, struct cfdata *match, void *aux)
293 {
294 struct pci_attach_args *pa = aux;
295
296 if (auich_lookup(pa) != NULL)
297 return (1);
298
299 return (0);
300 }
301
302 void
303 auich_attach(struct device *parent, struct device *self, void *aux)
304 {
305 struct auich_softc *sc = (struct auich_softc *)self;
306 struct pci_attach_args *pa = aux;
307 pci_intr_handle_t ih;
308 bus_size_t mix_size, aud_size;
309 pcireg_t csr;
310 const char *intrstr;
311 const struct auich_devtype *d;
312
313 d = auich_lookup(pa);
314 if (d == NULL)
315 panic("auich_attach: impossible");
316
317 printf(": %s\n", d->name);
318
319 if (pci_mapreg_map(pa, ICH_NAMBAR, PCI_MAPREG_TYPE_IO, 0,
320 &sc->iot, &sc->mix_ioh, NULL, &mix_size)) {
321 printf("%s: can't map codec i/o space\n",
322 sc->sc_dev.dv_xname);
323 return;
324 }
325 if (pci_mapreg_map(pa, ICH_NABMBAR, PCI_MAPREG_TYPE_IO, 0,
326 &sc->iot, &sc->aud_ioh, NULL, &aud_size)) {
327 printf("%s: can't map device i/o space\n",
328 sc->sc_dev.dv_xname);
329 return;
330 }
331 sc->dmat = pa->pa_dmat;
332
333 /* enable bus mastering */
334 csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
335 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
336 csr | PCI_COMMAND_MASTER_ENABLE);
337
338 /* Map and establish the interrupt. */
339 if (pci_intr_map(pa, &ih)) {
340 printf("%s: can't map interrupt\n", sc->sc_dev.dv_xname);
341 return;
342 }
343 intrstr = pci_intr_string(pa->pa_pc, ih);
344 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO,
345 auich_intr, sc);
346 if (sc->sc_ih == NULL) {
347 printf("%s: can't establish interrupt", sc->sc_dev.dv_xname);
348 if (intrstr != NULL)
349 printf(" at %s", intrstr);
350 printf("\n");
351 return;
352 }
353 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
354
355 sprintf(sc->sc_audev.name, "%s AC97", d->shortname);
356 sprintf(sc->sc_audev.version, "0x%02x", PCI_REVISION(pa->pa_class));
357 strcpy(sc->sc_audev.config, sc->sc_dev.dv_xname);
358
359 /* Set up DMA lists. */
360 sc->ptr_pcmo = sc->ptr_pcmi = sc->ptr_mici = 0;
361 auich_alloc_cdata(sc);
362
363 DPRINTF(ICH_DEBUG_DMA, ("auich_attach: lists %p %p %p\n",
364 sc->dmalist_pcmo, sc->dmalist_pcmi, sc->dmalist_mici));
365
366 /* Reset codec and AC'97 */
367 auich_reset_codec(sc);
368
369 sc->host_if.arg = sc;
370 sc->host_if.attach = auich_attach_codec;
371 sc->host_if.read = auich_read_codec;
372 sc->host_if.write = auich_write_codec;
373 sc->host_if.reset = auich_reset_codec;
374
375 if (ac97_attach(&sc->host_if) != 0)
376 return;
377
378 audio_attach_mi(&auich_hw_if, sc, &sc->sc_dev);
379 }
380
381 int
382 auich_read_codec(void *v, u_int8_t reg, u_int16_t *val)
383 {
384 struct auich_softc *sc = v;
385 int i;
386
387 /* wait for an access semaphore */
388 for (i = ICH_SEMATIMO; i-- &&
389 bus_space_read_1(sc->iot, sc->aud_ioh, ICH_CAS) & 1; DELAY(1));
390
391 if (i > 0) {
392 *val = bus_space_read_2(sc->iot, sc->mix_ioh, reg);
393 DPRINTF(ICH_DEBUG_CODECIO,
394 ("auich_read_codec(%x, %x)\n", reg, *val));
395
396 return 0;
397 } else {
398 DPRINTF(ICH_DEBUG_CODECIO,
399 ("%s: read_codec timeout\n", sc->sc_dev.dv_xname));
400 return -1;
401 }
402 }
403
404 int
405 auich_write_codec(void *v, u_int8_t reg, u_int16_t val)
406 {
407 struct auich_softc *sc = v;
408 int i;
409
410 DPRINTF(ICH_DEBUG_CODECIO, ("auich_write_codec(%x, %x)\n", reg, val));
411
412 /* wait for an access semaphore */
413 for (i = ICH_SEMATIMO; i-- &&
414 bus_space_read_1(sc->iot, sc->aud_ioh, ICH_CAS) & 1; DELAY(1));
415
416 if (i > 0) {
417 bus_space_write_2(sc->iot, sc->mix_ioh, reg, val);
418 return 0;
419 } else {
420 DPRINTF(ICH_DEBUG_CODECIO,
421 ("%s: write_codec timeout\n", sc->sc_dev.dv_xname));
422 return -1;
423 }
424 }
425
426 int
427 auich_attach_codec(void *v, struct ac97_codec_if *cif)
428 {
429 struct auich_softc *sc = v;
430
431 sc->codec_if = cif;
432 return 0;
433 }
434
435 void
436 auich_reset_codec(void *v)
437 {
438 struct auich_softc *sc = v;
439
440 bus_space_write_4(sc->iot, sc->aud_ioh, ICH_GCTRL, 0);
441 DELAY(10);
442 bus_space_write_4(sc->iot, sc->aud_ioh, ICH_GCTRL, ICH_CRESET);
443 }
444
445 int
446 auich_open(void *v, int flags)
447 {
448
449 return 0;
450 }
451
452 void
453 auich_close(void *v)
454 {
455 struct auich_softc *sc = v;
456
457 auich_halt_output(sc);
458 auich_halt_input(sc);
459
460 sc->sc_pintr = NULL;
461 sc->sc_rintr = NULL;
462 }
463
464 int
465 auich_query_encoding(void *v, struct audio_encoding *aep)
466 {
467 switch (aep->index) {
468 #if 0 /* XXX Not until we emulate it. */
469 case 0:
470 strcpy(aep->name, AudioEulinear);
471 aep->encoding = AUDIO_ENCODING_ULINEAR;
472 aep->precision = 8;
473 aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
474 return (0);
475 #endif
476 case 1:
477 strcpy(aep->name, AudioEmulaw);
478 aep->encoding = AUDIO_ENCODING_ULAW;
479 aep->precision = 8;
480 aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
481 return (0);
482 case 2:
483 strcpy(aep->name, AudioEalaw);
484 aep->encoding = AUDIO_ENCODING_ALAW;
485 aep->precision = 8;
486 aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
487 return (0);
488 case 3:
489 strcpy(aep->name, AudioEslinear);
490 aep->encoding = AUDIO_ENCODING_SLINEAR;
491 aep->precision = 8;
492 aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
493 return (0);
494 case 4:
495 strcpy(aep->name, AudioEslinear_le);
496 aep->encoding = AUDIO_ENCODING_SLINEAR_LE;
497 aep->precision = 16;
498 aep->flags = 0;
499 return (0);
500 case 5:
501 strcpy(aep->name, AudioEulinear_le);
502 aep->encoding = AUDIO_ENCODING_ULINEAR_LE;
503 aep->precision = 16;
504 aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
505 return (0);
506 case 6:
507 strcpy(aep->name, AudioEslinear_be);
508 aep->encoding = AUDIO_ENCODING_SLINEAR_BE;
509 aep->precision = 16;
510 aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
511 return (0);
512 case 7:
513 strcpy(aep->name, AudioEulinear_be);
514 aep->encoding = AUDIO_ENCODING_ULINEAR_BE;
515 aep->precision = 16;
516 aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
517 return (0);
518 default:
519 return (EINVAL);
520 }
521 }
522
523 int
524 auich_set_params(void *v, int setmode, int usemode, struct audio_params *play,
525 struct audio_params *rec)
526 {
527 struct auich_softc *sc = v;
528 struct audio_params *p;
529 int mode;
530 u_int16_t val, rate, inout;
531
532 for (mode = AUMODE_RECORD; mode != -1;
533 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
534 if ((setmode & mode) == 0)
535 continue;
536
537 p = mode == AUMODE_PLAY ? play : rec;
538 if (p == NULL)
539 continue;
540
541 inout = mode == AUMODE_PLAY ? ICH_PM_PCMO : ICH_PM_PCMI;
542
543 /*
544 * XXX NEED TO DETERMINE WHICH RATES THE CODEC SUPPORTS!
545 */
546 if (p->sample_rate != 48000)
547 return (EINVAL);
548
549 p->factor = 1;
550 p->sw_code = NULL;
551 switch (p->encoding) {
552 case AUDIO_ENCODING_SLINEAR_BE:
553 if (p->precision == 16)
554 p->sw_code = swap_bytes;
555 else {
556 if (mode == AUMODE_PLAY)
557 p->sw_code = linear8_to_linear16_le;
558 else
559 p->sw_code = linear16_to_linear8_le;
560 }
561 break;
562
563 case AUDIO_ENCODING_SLINEAR_LE:
564 if (p->precision != 16) {
565 if (mode == AUMODE_PLAY)
566 p->sw_code = linear8_to_linear16_le;
567 else
568 p->sw_code = linear16_to_linear8_le;
569 }
570 break;
571
572 case AUDIO_ENCODING_ULINEAR_BE:
573 if (p->precision == 16) {
574 if (mode == AUMODE_PLAY)
575 p->sw_code =
576 swap_bytes_change_sign16_le;
577 else
578 p->sw_code =
579 change_sign16_swap_bytes_le;
580 } else {
581 /*
582 * XXX ulinear8_to_slinear16_le
583 */
584 return (EINVAL);
585 }
586 break;
587
588 case AUDIO_ENCODING_ULINEAR_LE:
589 if (p->precision == 16)
590 p->sw_code = change_sign16_le;
591 else {
592 /*
593 * XXX ulinear8_to_slinear16_le
594 */
595 return (EINVAL);
596 }
597 break;
598
599 case AUDIO_ENCODING_ULAW:
600 if (mode == AUMODE_PLAY) {
601 p->factor = 2;
602 p->sw_code = mulaw_to_slinear16_le;
603 } else {
604 /*
605 * XXX slinear16_le_to_mulaw
606 */
607 return (EINVAL);
608 }
609 break;
610
611 case AUDIO_ENCODING_ALAW:
612 if (mode == AUMODE_PLAY) {
613 p->factor = 2;
614 p->sw_code = alaw_to_slinear16_le;
615 } else {
616 /*
617 * XXX slinear16_le_to_alaw
618 */
619 return (EINVAL);
620 }
621 break;
622
623 default:
624 return (EINVAL);
625 }
626
627 auich_read_codec(sc, AC97_REG_POWER, &val);
628 auich_write_codec(sc, AC97_REG_POWER, val | inout);
629
630 auich_write_codec(sc, AC97_REG_PCM_FRONT_DAC_RATE,
631 p->sample_rate);
632 auich_read_codec(sc, AC97_REG_PCM_FRONT_DAC_RATE, &rate);
633 p->sample_rate = rate;
634
635 auich_write_codec(sc, AC97_REG_POWER, val);
636 }
637
638 return (0);
639 }
640
641 int
642 auich_round_blocksize(void *v, int blk)
643 {
644
645 return (blk & ~0x3f); /* keep good alignment */
646 }
647
648 int
649 auich_halt_output(void *v)
650 {
651 struct auich_softc *sc = v;
652
653 DPRINTF(ICH_DEBUG_DMA, ("%s: halt_output\n", sc->sc_dev.dv_xname));
654
655 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_CTRL, ICH_RR);
656
657 return (0);
658 }
659
660 int
661 auich_halt_input(void *v)
662 {
663 struct auich_softc *sc = v;
664
665 DPRINTF(ICH_DEBUG_DMA,
666 ("%s: halt_input\n", sc->sc_dev.dv_xname));
667
668 /* XXX halt both unless known otherwise */
669
670 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CTRL, ICH_RR);
671 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_MICI + ICH_CTRL, ICH_RR);
672
673 return (0);
674 }
675
676 int
677 auich_getdev(void *v, struct audio_device *adp)
678 {
679 struct auich_softc *sc = v;
680
681 *adp = sc->sc_audev;
682 return (0);
683 }
684
685 int
686 auich_set_port(void *v, mixer_ctrl_t *cp)
687 {
688 struct auich_softc *sc = v;
689
690 return (sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp));
691 }
692
693 int
694 auich_get_port(void *v, mixer_ctrl_t *cp)
695 {
696 struct auich_softc *sc = v;
697
698 return (sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp));
699 }
700
701 int
702 auich_query_devinfo(void *v, mixer_devinfo_t *dp)
703 {
704 struct auich_softc *sc = v;
705
706 return (sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp));
707 }
708
709 void *
710 auich_allocm(void *v, int direction, size_t size, int pool, int flags)
711 {
712 struct auich_softc *sc = v;
713 struct auich_dma *p;
714 int error;
715
716 if (size > (ICH_DMALIST_MAX * ICH_DMASEG_MAX))
717 return (NULL);
718
719 p = malloc(sizeof(*p), pool, flags);
720 if (p == NULL)
721 return (NULL);
722 memset(p, 0, sizeof(*p));
723
724 error = auich_allocmem(sc, size, 0, p);
725 if (error) {
726 free(p, pool);
727 return (NULL);
728 }
729
730 p->next = sc->sc_dmas;
731 sc->sc_dmas = p;
732
733 return (KERNADDR(p));
734 }
735
736 void
737 auich_freem(void *v, void *ptr, int pool)
738 {
739 struct auich_softc *sc = v;
740 struct auich_dma *p, **pp;
741
742 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) {
743 if (KERNADDR(p) == ptr) {
744 auich_freemem(sc, p);
745 *pp = p->next;
746 free(p, pool);
747 return;
748 }
749 }
750 }
751
752 size_t
753 auich_round_buffersize(void *v, int direction, size_t size)
754 {
755
756 if (size > (ICH_DMALIST_MAX * ICH_DMASEG_MAX))
757 size = ICH_DMALIST_MAX * ICH_DMASEG_MAX;
758
759 return size;
760 }
761
762 paddr_t
763 auich_mappage(void *v, void *mem, off_t off, int prot)
764 {
765 struct auich_softc *sc = v;
766 struct auich_dma *p;
767
768 if (off < 0)
769 return (-1);
770
771 for (p = sc->sc_dmas; p && KERNADDR(p) != mem; p = p->next)
772 ;
773 if (!p)
774 return (-1);
775 return (bus_dmamem_mmap(sc->dmat, p->segs, p->nsegs,
776 off, prot, BUS_DMA_WAITOK));
777 }
778
779 int
780 auich_get_props(void *v)
781 {
782
783 return (AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT |
784 AUDIO_PROP_FULLDUPLEX);
785 }
786
787 int
788 auich_intr(void *v)
789 {
790 struct auich_softc *sc = v;
791 int ret = 0, sts, gsts, i, qptr;
792
793 gsts = bus_space_read_2(sc->iot, sc->aud_ioh, ICH_GSTS);
794 DPRINTF(ICH_DEBUG_DMA, ("auich_intr: gsts=0x%x\n", gsts));
795
796 if (gsts & ICH_POINT) {
797 sts = bus_space_read_2(sc->iot, sc->aud_ioh, ICH_PCMO+ICH_STS);
798 DPRINTF(ICH_DEBUG_DMA,
799 ("auich_intr: osts=0x%x\n", sts));
800
801 if (sts & ICH_FIFOE) {
802 printf("%s: fifo underrun # %u\n",
803 sc->sc_dev.dv_xname, ++sc->pcmo_fifoe);
804 }
805
806 i = bus_space_read_1(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_CIV);
807 if (sts & (ICH_LVBCI | ICH_CELV)) {
808 struct auich_dmalist *q;
809
810 qptr = sc->ptr_pcmo;
811
812 while (qptr != i) {
813 q = &sc->dmalist_pcmo[qptr];
814
815 q->base = sc->pcmo_p;
816 q->len = (sc->pcmo_blksize / 2) | ICH_DMAF_IOC;
817 DPRINTF(ICH_DEBUG_DMA,
818 ("auich_intr: %p, %p = %x @ 0x%x\n",
819 &sc->dmalist_pcmo[i], q,
820 sc->pcmo_blksize / 2, sc->pcmo_p));
821
822 sc->pcmo_p += sc->pcmo_blksize;
823 if (sc->pcmo_p >= sc->pcmo_end)
824 sc->pcmo_p = sc->pcmo_start;
825
826 if (++qptr == ICH_DMALIST_MAX)
827 qptr = 0;
828 }
829
830 sc->ptr_pcmo = qptr;
831 bus_space_write_1(sc->iot, sc->aud_ioh,
832 ICH_PCMO + ICH_LVI,
833 (sc->ptr_pcmo - 1) & ICH_LVI_MASK);
834 }
835
836 if (sts & ICH_BCIS && sc->sc_pintr)
837 sc->sc_pintr(sc->sc_parg);
838
839 /* int ack */
840 bus_space_write_2(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_STS,
841 sts & (ICH_LVBCI | ICH_CELV | ICH_BCIS | ICH_FIFOE));
842 bus_space_write_2(sc->iot, sc->aud_ioh, ICH_GSTS, ICH_POINT);
843 ret++;
844 }
845
846 if (gsts & ICH_PIINT) {
847 sts = bus_space_read_2(sc->iot, sc->aud_ioh, ICH_PCMI+ICH_STS);
848 DPRINTF(ICH_DEBUG_DMA,
849 ("auich_intr: ists=0x%x\n", sts));
850
851 if (sts & ICH_FIFOE) {
852 printf("%s: fifo overrun # %u\n",
853 sc->sc_dev.dv_xname, ++sc->pcmi_fifoe);
854 }
855
856 i = bus_space_read_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CIV);
857 if (sts & (ICH_LVBCI | ICH_CELV)) {
858 struct auich_dmalist *q;
859
860 qptr = sc->ptr_pcmi;
861
862 while (qptr != i) {
863 q = &sc->dmalist_pcmi[qptr];
864
865 q->base = sc->pcmi_p;
866 q->len = (sc->pcmi_blksize / 2) | ICH_DMAF_IOC;
867 DPRINTF(ICH_DEBUG_DMA,
868 ("auich_intr: %p, %p = %x @ 0x%x\n",
869 &sc->dmalist_pcmi[i], q,
870 sc->pcmi_blksize / 2, sc->pcmi_p));
871
872 sc->pcmi_p += sc->pcmi_blksize;
873 if (sc->pcmi_p >= sc->pcmi_end)
874 sc->pcmi_p = sc->pcmi_start;
875
876 if (++qptr == ICH_DMALIST_MAX)
877 qptr = 0;
878 }
879
880 sc->ptr_pcmi = qptr;
881 bus_space_write_1(sc->iot, sc->aud_ioh,
882 ICH_PCMI + ICH_LVI,
883 (sc->ptr_pcmi - 1) & ICH_LVI_MASK);
884 }
885
886 if (sts & ICH_BCIS && sc->sc_rintr)
887 sc->sc_rintr(sc->sc_rarg);
888
889 /* int ack */
890 bus_space_write_2(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_STS,
891 sts & (ICH_LVBCI | ICH_CELV | ICH_BCIS | ICH_FIFOE));
892 bus_space_write_2(sc->iot, sc->aud_ioh, ICH_GSTS, ICH_POINT);
893 ret++;
894 }
895
896 if (gsts & ICH_MIINT) {
897 sts = bus_space_read_2(sc->iot, sc->aud_ioh, ICH_MICI+ICH_STS);
898 DPRINTF(ICH_DEBUG_DMA,
899 ("auich_intr: ists=0x%x\n", sts));
900 if (sts & ICH_FIFOE)
901 printf("%s: fifo overrun\n", sc->sc_dev.dv_xname);
902
903 /* TODO mic input dma */
904
905 bus_space_write_2(sc->iot, sc->aud_ioh, ICH_GSTS, ICH_MIINT);
906 }
907
908 return ret;
909 }
910
911 int
912 auich_trigger_output(void *v, void *start, void *end, int blksize,
913 void (*intr)(void *), void *arg, struct audio_params *param)
914 {
915 struct auich_softc *sc = v;
916 struct auich_dmalist *q;
917 struct auich_dma *p;
918 size_t size;
919
920 DPRINTF(ICH_DEBUG_DMA,
921 ("auich_trigger_output(%p, %p, %d, %p, %p, %p)\n",
922 start, end, blksize, intr, arg, param));
923
924 sc->sc_pintr = intr;
925 sc->sc_parg = arg;
926
927 for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
928 ;
929 if (!p) {
930 printf("auich_trigger_output: bad addr %p\n", start);
931 return (EINVAL);
932 }
933
934 size = (size_t)((caddr_t)end - (caddr_t)start);
935
936 /*
937 * The logic behind this is:
938 * setup one buffer to play, then LVI dump out the rest
939 * to the scatter-gather chain.
940 */
941 sc->pcmo_start = DMAADDR(p);
942 sc->pcmo_p = sc->pcmo_start + blksize;
943 sc->pcmo_end = sc->pcmo_start + size;
944 sc->pcmo_blksize = blksize;
945
946 sc->ptr_pcmo = 0;
947 q = &sc->dmalist_pcmo[sc->ptr_pcmo];
948 q->base = sc->pcmo_start;
949 q->len = (blksize / 2) | ICH_DMAF_IOC;
950 if (++sc->ptr_pcmo == ICH_DMALIST_MAX)
951 sc->ptr_pcmo = 0;
952
953 bus_space_write_4(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_BDBAR,
954 sc->sc_cddma + ICH_PCMO_OFF(0));
955 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_CTRL,
956 ICH_IOCE | ICH_FEIE | ICH_LVBIE | ICH_RPBM);
957 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMO + ICH_LVI,
958 (sc->ptr_pcmo - 1) & ICH_LVI_MASK);
959
960 return (0);
961 }
962
963 int
964 auich_trigger_input(v, start, end, blksize, intr, arg, param)
965 void *v;
966 void *start, *end;
967 int blksize;
968 void (*intr)(void *);
969 void *arg;
970 struct audio_params *param;
971 {
972 struct auich_softc *sc = v;
973 struct auich_dmalist *q;
974 struct auich_dma *p;
975 size_t size;
976
977 DPRINTF(ICH_DEBUG_DMA,
978 ("auich_trigger_input(%p, %p, %d, %p, %p, %p)\n",
979 start, end, blksize, intr, arg, param));
980
981 sc->sc_rintr = intr;
982 sc->sc_rarg = arg;
983
984 for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
985 ;
986 if (!p) {
987 printf("auich_trigger_input: bad addr %p\n", start);
988 return (EINVAL);
989 }
990
991 size = (size_t)((caddr_t)end - (caddr_t)start);
992
993 /*
994 * The logic behind this is:
995 * setup one buffer to play, then LVI dump out the rest
996 * to the scatter-gather chain.
997 */
998 sc->pcmi_start = DMAADDR(p);
999 sc->pcmi_p = sc->pcmi_start + blksize;
1000 sc->pcmi_end = sc->pcmi_start + size;
1001 sc->pcmi_blksize = blksize;
1002
1003 sc->ptr_pcmi = 0;
1004 q = &sc->dmalist_pcmi[sc->ptr_pcmi];
1005 q->base = sc->pcmi_start;
1006 q->len = (blksize / 2) | ICH_DMAF_IOC;
1007 if (++sc->ptr_pcmi == ICH_DMALIST_MAX)
1008 sc->ptr_pcmi = 0;
1009
1010 bus_space_write_4(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_BDBAR,
1011 sc->sc_cddma + ICH_PCMI_OFF(0));
1012 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_CTRL,
1013 ICH_IOCE | ICH_FEIE | ICH_LVBIE | ICH_RPBM);
1014 bus_space_write_1(sc->iot, sc->aud_ioh, ICH_PCMI + ICH_LVI,
1015 (sc->ptr_pcmi - 1) & ICH_LVI_MASK);
1016
1017 return (0);
1018 }
1019
1020 int
1021 auich_allocmem(struct auich_softc *sc, size_t size, size_t align,
1022 struct auich_dma *p)
1023 {
1024 int error;
1025
1026 p->size = size;
1027 error = bus_dmamem_alloc(sc->dmat, p->size, align, 0,
1028 p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
1029 &p->nsegs, BUS_DMA_NOWAIT);
1030 if (error)
1031 return (error);
1032
1033 error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size,
1034 &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
1035 if (error)
1036 goto free;
1037
1038 error = bus_dmamap_create(sc->dmat, p->size, 1, p->size,
1039 0, BUS_DMA_NOWAIT, &p->map);
1040 if (error)
1041 goto unmap;
1042
1043 error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL,
1044 BUS_DMA_NOWAIT);
1045 if (error)
1046 goto destroy;
1047 return (0);
1048
1049 destroy:
1050 bus_dmamap_destroy(sc->dmat, p->map);
1051 unmap:
1052 bus_dmamem_unmap(sc->dmat, p->addr, p->size);
1053 free:
1054 bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
1055 return (error);
1056 }
1057
1058 int
1059 auich_freemem(struct auich_softc *sc, struct auich_dma *p)
1060 {
1061
1062 bus_dmamap_unload(sc->dmat, p->map);
1063 bus_dmamap_destroy(sc->dmat, p->map);
1064 bus_dmamem_unmap(sc->dmat, p->addr, p->size);
1065 bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
1066 return (0);
1067 }
1068
1069 int
1070 auich_alloc_cdata(struct auich_softc *sc)
1071 {
1072 bus_dma_segment_t seg;
1073 int error, rseg;
1074
1075 /*
1076 * Allocate the control data structure, and create and load the
1077 * DMA map for it.
1078 */
1079 if ((error = bus_dmamem_alloc(sc->dmat,
1080 sizeof(struct auich_cdata),
1081 PAGE_SIZE, 0, &seg, 1, &rseg, 0)) != 0) {
1082 printf("%s: unable to allocate control data, error = %d\n",
1083 sc->sc_dev.dv_xname, error);
1084 goto fail_0;
1085 }
1086
1087 if ((error = bus_dmamem_map(sc->dmat, &seg, rseg,
1088 sizeof(struct auich_cdata),
1089 (caddr_t *) &sc->sc_cdata,
1090 BUS_DMA_COHERENT)) != 0) {
1091 printf("%s: unable to map control data, error = %d\n",
1092 sc->sc_dev.dv_xname, error);
1093 goto fail_1;
1094 }
1095
1096 if ((error = bus_dmamap_create(sc->dmat, sizeof(struct auich_cdata), 1,
1097 sizeof(struct auich_cdata), 0, 0,
1098 &sc->sc_cddmamap)) != 0) {
1099 printf("%s: unable to create control data DMA map, "
1100 "error = %d\n", sc->sc_dev.dv_xname, error);
1101 goto fail_2;
1102 }
1103
1104 if ((error = bus_dmamap_load(sc->dmat, sc->sc_cddmamap,
1105 sc->sc_cdata, sizeof(struct auich_cdata),
1106 NULL, 0)) != 0) {
1107 printf("%s: unable tp load control data DMA map, "
1108 "error = %d\n", sc->sc_dev.dv_xname, error);
1109 goto fail_3;
1110 }
1111
1112 return (0);
1113
1114 fail_3:
1115 bus_dmamap_destroy(sc->dmat, sc->sc_cddmamap);
1116 fail_2:
1117 bus_dmamem_unmap(sc->dmat, (caddr_t) sc->sc_cdata,
1118 sizeof(struct auich_cdata));
1119 fail_1:
1120 bus_dmamem_free(sc->dmat, &seg, rseg);
1121 fail_0:
1122 return (error);
1123 }
1124