Annotation of sys/dev/pci/auich.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: auich.c,v 1.64 2007/08/02 07:43:41 jakemsr Exp $ */
2:
3: /*
4: * Copyright (c) 2000,2001 Michael Shalayeff
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: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19: * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22: * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25: * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26: * THE POSSIBILITY OF SUCH DAMAGE.
27: */
28:
29: /* #define AUICH_DEBUG */
30: /*
31: * AC'97 audio found on Intel 810/815/820/440MX chipsets.
32: * http://developer.intel.com/design/chipsets/datashts/290655.htm
33: * http://developer.intel.com/design/chipsets/manuals/298028.htm
34: * http://www.intel.com/design/chipsets/datashts/290716.htm
35: * http://www.intel.com/design/chipsets/datashts/290744.htm
36: */
37:
38: #include <sys/param.h>
39: #include <sys/systm.h>
40: #include <sys/kernel.h>
41: #include <sys/malloc.h>
42: #include <sys/device.h>
43:
44: #include <dev/pci/pcidevs.h>
45: #include <dev/pci/pcivar.h>
46:
47: #include <sys/audioio.h>
48: #include <dev/audio_if.h>
49: #include <dev/mulaw.h>
50: #include <dev/auconv.h>
51:
52: #include <machine/bus.h>
53:
54: #include <dev/ic/ac97.h>
55:
56: /* 12.1.10 NAMBAR - native audio mixer base address register */
57: #define AUICH_NAMBAR 0x10
58: /* 12.1.11 NABMBAR - native audio bus mastering base address register */
59: #define AUICH_NABMBAR 0x14
60: #define AUICH_CFG 0x41
61: #define AUICH_CFG_IOSE 0x01
62: /* ICH4/ICH5/ICH6/ICH7 native audio mixer BAR */
63: #define AUICH_MMBAR 0x18
64: /* ICH4/ICH5/ICH6/ICH7 native bus mastering BAR */
65: #define AUICH_MBBAR 0x1c
66: #define AUICH_S2CR 0x10000000 /* tertiary codec ready */
67:
68: /* table 12-3. native audio bus master control registers */
69: #define AUICH_BDBAR 0x00 /* 8-byte aligned address */
70: #define AUICH_CIV 0x04 /* 5 bits current index value */
71: #define AUICH_LVI 0x05 /* 5 bits last valid index value */
72: #define AUICH_LVI_MASK 0x1f
73: #define AUICH_STS 0x06 /* 16 bits status */
74: #define AUICH_FIFOE 0x10 /* fifo error */
75: #define AUICH_BCIS 0x08 /* r- buf cmplt int sts; wr ack */
76: #define AUICH_LVBCI 0x04 /* r- last valid bci, wr ack */
77: #define AUICH_CELV 0x02 /* current equals last valid */
78: #define AUICH_DCH 0x01 /* dma halted */
79: #define AUICH_ISTS_BITS "\020\01dch\02celv\03lvbci\04bcis\05fifoe"
80: #define AUICH_PICB 0x08 /* 16 bits */
81: #define AUICH_PIV 0x0a /* 5 bits prefetched index value */
82: #define AUICH_CTRL 0x0b /* control */
83: #define AUICH_IOCE 0x10 /* int on completion enable */
84: #define AUICH_FEIE 0x08 /* fifo error int enable */
85: #define AUICH_LVBIE 0x04 /* last valid buf int enable */
86: #define AUICH_RR 0x02 /* 1 - reset regs */
87: #define AUICH_RPBM 0x01 /* 1 - run, 0 - pause */
88:
89: #define AUICH_PCMI 0x00
90: #define AUICH_PCMO 0x10
91: #define AUICH_MICI 0x20
92:
93: #define AUICH_GCTRL 0x2c
94: #define AUICH_SSM_78 0x40000000 /* S/PDIF slots 7 and 8 */
95: #define AUICH_SSM_69 0x80000000 /* S/PDIF slots 6 and 9 */
96: #define AUICH_SSM_1011 0xc0000000 /* S/PDIF slots 10 and 11 */
97: #define AUICH_POM16 0x000000 /* PCM out precision 16bit */
98: #define AUICH_POM20 0x400000 /* PCM out precision 20bit */
99: #define AUICH_PCM246_MASK 0x300000
100: #define AUICH_PCM2 0x000000 /* 2ch output */
101: #define AUICH_PCM4 0x100000 /* 4ch output */
102: #define AUICH_PCM6 0x200000 /* 6ch output */
103: #define AUICH_S2RIE 0x40 /* int when tertiary codec resume */
104: #define AUICH_SRIE 0x20 /* int when 2ndary codec resume */
105: #define AUICH_PRIE 0x10 /* int when primary codec resume */
106: #define AUICH_ACLSO 0x08 /* aclink shut off */
107: #define AUICH_WRESET 0x04 /* warm reset */
108: #define AUICH_CRESET 0x02 /* cold reset */
109: #define AUICH_GIE 0x01 /* gpi int enable */
110: #define AUICH_GSTS 0x30
111: #define AUICH_MD3 0x20000 /* pwr-dn semaphore for modem */
112: #define AUICH_AD3 0x10000 /* pwr-dn semaphore for audio */
113: #define AUICH_RCS 0x08000 /* read completion status */
114: #define AUICH_B3S12 0x04000 /* bit 3 of slot 12 */
115: #define AUICH_B2S12 0x02000 /* bit 2 of slot 12 */
116: #define AUICH_B1S12 0x01000 /* bit 1 of slot 12 */
117: #define AUICH_SRI 0x00800 /* secondary resume int */
118: #define AUICH_PRI 0x00400 /* primary resume int */
119: #define AUICH_SCR 0x00200 /* secondary codec ready */
120: #define AUICH_PCR 0x00100 /* primary codec ready */
121: #define AUICH_MINT 0x00080 /* mic in int */
122: #define AUICH_POINT 0x00040 /* pcm out int */
123: #define AUICH_PIINT 0x00020 /* pcm in int */
124: #define AUICH_MOINT 0x00004 /* modem out int */
125: #define AUICH_MIINT 0x00002 /* modem in int */
126: #define AUICH_GSCI 0x00001 /* gpi status change */
127: #define AUICH_GSTS_BITS "\020\01gsci\02miict\03moint\06piint\07point\010mint\011pcr\012scr\013pri\014sri\015b1s12\016b2s12\017b3s12\020rcs\021ad3\022md3"
128: #define AUICH_CAS 0x34 /* 1/8 bit */
129: #define AUICH_SEMATIMO 1000 /* us */
130: #define AUICH_RESETIMO 500000 /* us */
131:
132: #define ICH_SIS_NV_CTL 0x4c /* some SiS/NVIDIA register. From Linux */
133: #define ICH_SIS_CTL_UNMUTE 0x01 /* un-mute the output */
134:
135: /*
136: * according to the dev/audiovar.h AU_RING_SIZE is 2^16, what fits
137: * in our limits perfectly, i.e. setting it to higher value
138: * in your kernel config would improve perfomance, still 2^21 is the max
139: */
140: #define AUICH_DMALIST_MAX 32
141: #define AUICH_DMASEG_MAX (65536*2) /* 64k samples, 2x16 bit samples */
142: struct auich_dmalist {
143: u_int32_t base;
144: u_int32_t len;
145: #define AUICH_DMAF_IOC 0x80000000 /* 1-int on complete */
146: #define AUICH_DMAF_BUP 0x40000000 /* 0-retrans last, 1-transmit 0 */
147: };
148:
149: #define AUICH_FIXED_RATE 48000
150:
151: struct auich_dma {
152: bus_dmamap_t map;
153: caddr_t addr;
154: bus_dma_segment_t segs[AUICH_DMALIST_MAX];
155: int nsegs;
156: size_t size;
157: struct auich_dma *next;
158: };
159:
160: struct auich_softc {
161: struct device sc_dev;
162: void *sc_ih;
163:
164: audio_device_t sc_audev;
165:
166: bus_space_tag_t iot;
167: bus_space_tag_t iot_mix;
168: bus_space_handle_t mix_ioh;
169: bus_space_handle_t aud_ioh;
170: bus_dma_tag_t dmat;
171:
172: struct ac97_codec_if *codec_if;
173: struct ac97_host_if host_if;
174:
175: /* dma scatter-gather buffer lists, aligned to 8 bytes */
176: struct auich_dmalist *dmalist_pcmo, *dmap_pcmo;
177: struct auich_dmalist *dmalist_pcmi, *dmap_pcmi;
178: struct auich_dmalist *dmalist_mici, *dmap_mici;
179:
180: bus_dmamap_t dmalist_map;
181: bus_dma_segment_t dmalist_seg[2];
182: caddr_t dmalist_kva;
183: bus_addr_t dmalist_pcmo_pa;
184: bus_addr_t dmalist_pcmi_pa;
185: bus_addr_t dmalist_mici_pa;
186:
187: /* i/o buffer pointers */
188: u_int32_t pcmo_start, pcmo_p, pcmo_end;
189: int pcmo_blksize, pcmo_fifoe;
190: u_int32_t pcmi_start, pcmi_p, pcmi_end;
191: int pcmi_blksize, pcmi_fifoe;
192: u_int32_t mici_start, mici_p, mici_end;
193: int mici_blksize, mici_fifoe;
194: struct auich_dma *sc_dmas;
195:
196: void (*sc_pintr)(void *);
197: void *sc_parg;
198:
199: void (*sc_rintr)(void *);
200: void *sc_rarg;
201:
202: void *powerhook;
203: int suspend;
204: u_int16_t ext_ctrl;
205: int sc_sample_size;
206: int sc_sts_reg;
207: int sc_ignore_codecready;
208: int flags;
209: int sc_ac97rate;
210: };
211:
212: #ifdef AUICH_DEBUG
213: #define DPRINTF(l,x) do { if (auich_debug & (l)) printf x; } while(0)
214: int auich_debug = 0xfffe;
215: #define AUICH_DEBUG_CODECIO 0x0001
216: #define AUICH_DEBUG_DMA 0x0002
217: #define AUICH_DEBUG_PARAM 0x0004
218: #else
219: #define DPRINTF(x,y) /* nothing */
220: #endif
221:
222: struct cfdriver auich_cd = {
223: NULL, "auich", DV_DULL
224: };
225:
226: int auich_match(struct device *, void *, void *);
227: void auich_attach(struct device *, struct device *, void *);
228: int auich_intr(void *);
229:
230: struct cfattach auich_ca = {
231: sizeof(struct auich_softc), auich_match, auich_attach
232: };
233:
234: static const struct auich_devtype {
235: int vendor;
236: int product;
237: int options;
238: char name[8];
239: } auich_devices[] = {
240: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_ACA, 0, "ESB" },
241: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6321ESB_ACA, 0, "ESB2" },
242: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AA_ACA, 0, "ICH" },
243: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801AB_ACA, 0, "ICH0" },
244: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801BA_ACA, 0, "ICH2" },
245: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801CA_ACA, 0, "ICH3" },
246: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801DB_ACA, 0, "ICH4" },
247: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801EB_ACA, 0, "ICH5" },
248: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801FB_ACA, 0, "ICH6" },
249: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82801GB_ACA, 0, "ICH7" },
250: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82440MX_ACA, 0, "440MX" },
251: { PCI_VENDOR_SIS, PCI_PRODUCT_SIS_7012_ACA, 0, "SiS7012" },
252: { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE_ACA, 0, "nForce" },
253: { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_ACA, 0, "nForce2" },
254: { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE2_400_ACA,
255: 0, "nForce2" },
256: { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_ACA, 0, "nForce3" },
257: { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE3_250_ACA,
258: 0, "nForce3" },
259: { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_NFORCE4_AC, 0, "nForce4" },
260: { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP04_AC97, 0, "MCP04" },
261: { PCI_VENDOR_NVIDIA, PCI_PRODUCT_NVIDIA_MCP51_ACA, 0, "MCP51" },
262: { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_PBC768_ACA, 0, "AMD768" },
263: { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_8111_ACA, 0, "AMD8111" },
264: };
265:
266: int auich_open(void *, int);
267: void auich_close(void *);
268: int auich_query_encoding(void *, struct audio_encoding *);
269: int auich_set_params(void *, int, int, struct audio_params *,
270: struct audio_params *);
271: int auich_round_blocksize(void *, int);
272: int auich_halt_output(void *);
273: int auich_halt_input(void *);
274: int auich_getdev(void *, struct audio_device *);
275: int auich_set_port(void *, mixer_ctrl_t *);
276: int auich_get_port(void *, mixer_ctrl_t *);
277: int auich_query_devinfo(void *, mixer_devinfo_t *);
278: void *auich_allocm(void *, int, size_t, int, int);
279: void auich_freem(void *, void *, int);
280: size_t auich_round_buffersize(void *, int, size_t);
281: paddr_t auich_mappage(void *, void *, off_t, int);
282: int auich_get_props(void *);
283: int auich_trigger_output(void *, void *, void *, int, void (*)(void *),
284: void *, struct audio_params *);
285: int auich_trigger_input(void *, void *, void *, int, void (*)(void *),
286: void *, struct audio_params *);
287:
288: void auich_powerhook(int, void *);
289:
290: struct audio_hw_if auich_hw_if = {
291: auich_open,
292: auich_close,
293: NULL, /* drain */
294: auich_query_encoding,
295: auich_set_params,
296: auich_round_blocksize,
297: NULL, /* commit_setting */
298: NULL, /* init_output */
299: NULL, /* init_input */
300: NULL, /* start_output */
301: NULL, /* start_input */
302: auich_halt_output,
303: auich_halt_input,
304: NULL, /* speaker_ctl */
305: auich_getdev,
306: NULL, /* getfd */
307: auich_set_port,
308: auich_get_port,
309: auich_query_devinfo,
310: auich_allocm,
311: auich_freem,
312: auich_round_buffersize,
313: auich_mappage,
314: auich_get_props,
315: auich_trigger_output,
316: auich_trigger_input
317: };
318:
319: int auich_attach_codec(void *, struct ac97_codec_if *);
320: int auich_read_codec(void *, u_int8_t, u_int16_t *);
321: int auich_write_codec(void *, u_int8_t, u_int16_t);
322: void auich_reset_codec(void *);
323: enum ac97_host_flags auich_flags_codec(void *);
324: unsigned int auich_calibrate(struct auich_softc *);
325:
326: int
327: auich_match(parent, match, aux)
328: struct device *parent;
329: void *match;
330: void *aux;
331: {
332: struct pci_attach_args *pa = aux;
333: int i;
334:
335: for (i = sizeof(auich_devices)/sizeof(auich_devices[0]); i--;)
336: if (PCI_VENDOR(pa->pa_id) == auich_devices[i].vendor &&
337: PCI_PRODUCT(pa->pa_id) == auich_devices[i].product)
338: return 1;
339:
340: return 0;
341: }
342:
343: void
344: auich_attach(parent, self, aux)
345: struct device *parent, *self;
346: void *aux;
347: {
348: struct auich_softc *sc = (struct auich_softc *)self;
349: struct pci_attach_args *pa = aux;
350: pci_intr_handle_t ih;
351: bus_size_t mix_size, aud_size;
352: pcireg_t csr;
353: const char *intrstr;
354: u_int32_t status;
355: bus_size_t dmasz;
356: int i, segs;
357:
358: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL &&
359: (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801DB_ACA ||
360: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801EB_ACA ||
361: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801FB_ACA ||
362: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801GB_ACA)) {
363: /*
364: * Use native mode for ICH4/ICH5/ICH6/ICH7
365: */
366: if (pci_mapreg_map(pa, AUICH_MMBAR, PCI_MAPREG_TYPE_MEM, 0,
367: &sc->iot_mix, &sc->mix_ioh, NULL, &mix_size, 0)) {
368: csr = pci_conf_read(pa->pa_pc, pa->pa_tag, AUICH_CFG);
369: pci_conf_write(pa->pa_pc, pa->pa_tag, AUICH_CFG,
370: csr | AUICH_CFG_IOSE);
371: if (pci_mapreg_map(pa, AUICH_NAMBAR, PCI_MAPREG_TYPE_IO,
372: 0, &sc->iot_mix, &sc->mix_ioh, NULL, &mix_size, 0)) {
373: printf(": can't map codec mem/io space\n");
374: return;
375: }
376: }
377:
378: if (pci_mapreg_map(pa, AUICH_MBBAR, PCI_MAPREG_TYPE_MEM, 0,
379: &sc->iot, &sc->aud_ioh, NULL, &aud_size, 0)) {
380: csr = pci_conf_read(pa->pa_pc, pa->pa_tag, AUICH_CFG);
381: pci_conf_write(pa->pa_pc, pa->pa_tag, AUICH_CFG,
382: csr | AUICH_CFG_IOSE);
383: if (pci_mapreg_map(pa, AUICH_NABMBAR,
384: PCI_MAPREG_TYPE_IO, 0, &sc->iot,
385: &sc->aud_ioh, NULL, &aud_size, 0)) {
386: printf(": can't map device mem/io space\n");
387: bus_space_unmap(sc->iot_mix, sc->mix_ioh, mix_size);
388: return;
389: }
390: }
391: } else {
392: if (pci_mapreg_map(pa, AUICH_NAMBAR, PCI_MAPREG_TYPE_IO,
393: 0, &sc->iot_mix, &sc->mix_ioh, NULL, &mix_size, 0)) {
394: printf(": can't map codec i/o space\n");
395: return;
396: }
397:
398: if (pci_mapreg_map(pa, AUICH_NABMBAR, PCI_MAPREG_TYPE_IO,
399: 0, &sc->iot, &sc->aud_ioh, NULL, &aud_size, 0)) {
400: printf(": can't map device i/o space\n");
401: bus_space_unmap(sc->iot_mix, sc->mix_ioh, mix_size);
402: return;
403: }
404: }
405: sc->dmat = pa->pa_dmat;
406:
407: /* allocate dma memory */
408: dmasz = AUICH_DMALIST_MAX * 3 * sizeof(struct auich_dma);
409: segs = 1;
410: if (bus_dmamem_alloc(sc->dmat, dmasz, PAGE_SIZE, 0, sc->dmalist_seg,
411: segs, &segs, BUS_DMA_NOWAIT)) {
412: printf(": failed to alloc dmalist\n");
413: return;
414: }
415: if (bus_dmamem_map(sc->dmat, sc->dmalist_seg, segs, dmasz,
416: &sc->dmalist_kva, BUS_DMA_NOWAIT)) {
417: printf(": failed to map dmalist\n");
418: bus_dmamem_free(sc->dmat, sc->dmalist_seg, segs);
419: return;
420: }
421: if (bus_dmamap_create(sc->dmat, dmasz, segs, dmasz, 0, BUS_DMA_NOWAIT,
422: &sc->dmalist_map)) {
423: printf(": failed to create dmalist map\n");
424: bus_dmamem_unmap(sc->dmat, sc->dmalist_kva, dmasz);
425: bus_dmamem_free(sc->dmat, sc->dmalist_seg, segs);
426: return;
427: }
428: if (bus_dmamap_load_raw(sc->dmat, sc->dmalist_map, sc->dmalist_seg,
429: segs, dmasz, BUS_DMA_NOWAIT)) {
430: printf(": failed to load dmalist map: %d segs %lu size\n",
431: segs, (u_long)dmasz);
432: bus_dmamap_destroy(sc->dmat, sc->dmalist_map);
433: bus_dmamem_unmap(sc->dmat, sc->dmalist_kva, dmasz);
434: bus_dmamem_free(sc->dmat, sc->dmalist_seg, segs);
435: return;
436: }
437:
438: if (pci_intr_map(pa, &ih)) {
439: bus_space_unmap(sc->iot, sc->aud_ioh, aud_size);
440: bus_space_unmap(sc->iot_mix, sc->mix_ioh, mix_size);
441: return;
442: }
443: intrstr = pci_intr_string(pa->pa_pc, ih);
444: sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO, auich_intr,
445: sc, sc->sc_dev.dv_xname);
446: if (!sc->sc_ih) {
447: printf(": can't establish interrupt");
448: if (intrstr)
449: printf(" at %s", intrstr);
450: printf("\n");
451: bus_space_unmap(sc->iot, sc->aud_ioh, aud_size);
452: bus_space_unmap(sc->iot_mix, sc->mix_ioh, mix_size);
453: return;
454: }
455:
456: for (i = sizeof(auich_devices)/sizeof(auich_devices[0]); i--;)
457: if (PCI_PRODUCT(pa->pa_id) == auich_devices[i].product)
458: break;
459:
460: snprintf(sc->sc_audev.name, sizeof sc->sc_audev.name, "%s AC97",
461: auich_devices[i].name);
462: snprintf(sc->sc_audev.version, sizeof sc->sc_audev.version, "0x%02x",
463: PCI_REVISION(pa->pa_class));
464: strlcpy(sc->sc_audev.config, sc->sc_dev.dv_xname,
465: sizeof sc->sc_audev.config);
466:
467: printf(": %s, %s\n", intrstr, sc->sc_audev.name);
468:
469: /* SiS 7012 needs special handling */
470: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SIS &&
471: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SIS_7012_ACA) {
472: sc->sc_sts_reg = AUICH_PICB;
473: sc->sc_sample_size = 1;
474: /* un-mute output */
475: bus_space_write_4(sc->iot, sc->aud_ioh, ICH_SIS_NV_CTL,
476: bus_space_read_4(sc->iot, sc->aud_ioh, ICH_SIS_NV_CTL) |
477: ICH_SIS_CTL_UNMUTE);
478: } else {
479: sc->sc_sts_reg = AUICH_STS;
480: sc->sc_sample_size = 2;
481: }
482:
483: sc->dmalist_pcmo = (struct auich_dmalist *)(sc->dmalist_kva +
484: (0 * sizeof(struct auich_dmalist) + AUICH_DMALIST_MAX));
485: sc->dmalist_pcmo_pa = sc->dmalist_map->dm_segs[0].ds_addr +
486: (0 * sizeof(struct auich_dmalist) + AUICH_DMALIST_MAX);
487:
488: sc->dmalist_pcmi = (struct auich_dmalist *)(sc->dmalist_kva +
489: (1 * sizeof(struct auich_dmalist) + AUICH_DMALIST_MAX));
490: sc->dmalist_pcmi_pa = sc->dmalist_map->dm_segs[0].ds_addr +
491: (1 * sizeof(struct auich_dmalist) + AUICH_DMALIST_MAX);
492:
493: sc->dmalist_mici = (struct auich_dmalist *)(sc->dmalist_kva +
494: (2 * sizeof(struct auich_dmalist) + AUICH_DMALIST_MAX));
495: sc->dmalist_mici_pa = sc->dmalist_map->dm_segs[0].ds_addr +
496: (2 * sizeof(struct auich_dmalist) + AUICH_DMALIST_MAX);
497:
498: DPRINTF(AUICH_DEBUG_DMA, ("auich_attach: lists %p %p %p\n",
499: sc->dmalist_pcmo, sc->dmalist_pcmi, sc->dmalist_mici));
500:
501: /* Reset codec and AC'97 */
502: auich_reset_codec(sc);
503: status = bus_space_read_4(sc->iot, sc->aud_ioh, AUICH_GSTS);
504: if (!(status & AUICH_PCR)) { /* reset failure */
505: if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_INTEL &&
506: (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801DB_ACA ||
507: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801EB_ACA ||
508: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801FB_ACA ||
509: PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_INTEL_82801GB_ACA)) {
510: /* MSI 845G Max never return AUICH_PCR */
511: sc->sc_ignore_codecready = 1;
512: } else {
513: printf("%s: reset failed!\n", sc->sc_dev.dv_xname);
514: return;
515: }
516: }
517:
518: sc->host_if.arg = sc;
519: sc->host_if.attach = auich_attach_codec;
520: sc->host_if.read = auich_read_codec;
521: sc->host_if.write = auich_write_codec;
522: sc->host_if.reset = auich_reset_codec;
523: sc->host_if.flags = auich_flags_codec;
524: if (sc->sc_dev.dv_cfdata->cf_flags & 0x0001)
525: sc->flags = AC97_HOST_SWAPPED_CHANNELS;
526:
527: if (ac97_attach(&sc->host_if) != 0) {
528: pci_intr_disestablish(pa->pa_pc, sc->sc_ih);
529: bus_space_unmap(sc->iot, sc->aud_ioh, aud_size);
530: bus_space_unmap(sc->iot_mix, sc->mix_ioh, mix_size);
531: return;
532: }
533:
534: audio_attach_mi(&auich_hw_if, sc, &sc->sc_dev);
535:
536: /* Watch for power changes */
537: sc->suspend = PWR_RESUME;
538: sc->powerhook = powerhook_establish(auich_powerhook, sc);
539:
540: sc->sc_ac97rate = -1;
541: }
542:
543: int
544: auich_read_codec(v, reg, val)
545: void *v;
546: u_int8_t reg;
547: u_int16_t *val;
548: {
549: struct auich_softc *sc = v;
550: int i;
551:
552: /* wait for an access semaphore */
553: for (i = AUICH_SEMATIMO; i-- &&
554: bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_CAS) & 1; DELAY(1));
555:
556: if (!sc->sc_ignore_codecready && i < 0) {
557: DPRINTF(AUICH_DEBUG_CODECIO,
558: ("%s: read_codec timeout\n", sc->sc_dev.dv_xname));
559: return (-1);
560: }
561:
562: *val = bus_space_read_2(sc->iot_mix, sc->mix_ioh, reg);
563: DPRINTF(AUICH_DEBUG_CODECIO, ("%s: read_codec(%x, %x)\n",
564: sc->sc_dev.dv_xname, reg, *val));
565: return (0);
566: }
567:
568: int
569: auich_write_codec(v, reg, val)
570: void *v;
571: u_int8_t reg;
572: u_int16_t val;
573: {
574: struct auich_softc *sc = v;
575: int i;
576:
577: /* wait for an access semaphore */
578: for (i = AUICH_SEMATIMO; i-- &&
579: bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_CAS) & 1; DELAY(1));
580:
581: if (sc->sc_ignore_codecready || i >= 0) {
582: DPRINTF(AUICH_DEBUG_CODECIO, ("%s: write_codec(%x, %x)\n",
583: sc->sc_dev.dv_xname, reg, val));
584: bus_space_write_2(sc->iot_mix, sc->mix_ioh, reg, val);
585: return (0);
586: } else {
587: DPRINTF(AUICH_DEBUG_CODECIO,
588: ("%s: write_codec timeout\n", sc->sc_dev.dv_xname));
589: return (-1);
590: }
591: }
592:
593: int
594: auich_attach_codec(v, cif)
595: void *v;
596: struct ac97_codec_if *cif;
597: {
598: struct auich_softc *sc = v;
599:
600: sc->codec_if = cif;
601: return 0;
602: }
603:
604: void
605: auich_reset_codec(v)
606: void *v;
607: {
608: struct auich_softc *sc = v;
609: u_int32_t control;
610: int i;
611:
612: control = bus_space_read_4(sc->iot, sc->aud_ioh, AUICH_GCTRL);
613: control &= ~(AUICH_ACLSO | AUICH_PCM246_MASK);
614: control |= (control & AUICH_CRESET) ? AUICH_WRESET : AUICH_CRESET;
615: bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_GCTRL, control);
616:
617: for (i = AUICH_RESETIMO; i-- &&
618: !(bus_space_read_4(sc->iot, sc->aud_ioh, AUICH_GSTS) & AUICH_PCR);
619: DELAY(1));
620:
621: if (i < 0)
622: DPRINTF(AUICH_DEBUG_CODECIO,
623: ("%s: reset_codec timeout\n", sc->sc_dev.dv_xname));
624: }
625:
626: enum ac97_host_flags
627: auich_flags_codec(void *v)
628: {
629: struct auich_softc *sc = v;
630:
631: return (sc->flags);
632: }
633:
634: int
635: auich_open(v, flags)
636: void *v;
637: int flags;
638: {
639: struct auich_softc *sc = v;
640:
641: if (sc->sc_ac97rate == -1)
642: sc->sc_ac97rate = auich_calibrate(sc);
643: return 0;
644: }
645:
646: void
647: auich_close(v)
648: void *v;
649: {
650: }
651:
652: int
653: auich_query_encoding(v, aep)
654: void *v;
655: struct audio_encoding *aep;
656: {
657: switch (aep->index) {
658: case 0:
659: strlcpy(aep->name, AudioEulinear, sizeof aep->name);
660: aep->encoding = AUDIO_ENCODING_ULINEAR;
661: aep->precision = 8;
662: aep->flags = 0;
663: return (0);
664: case 1:
665: strlcpy(aep->name, AudioEmulaw, sizeof aep->name);
666: aep->encoding = AUDIO_ENCODING_ULAW;
667: aep->precision = 8;
668: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
669: return (0);
670: case 2:
671: strlcpy(aep->name, AudioEalaw, sizeof aep->name);
672: aep->encoding = AUDIO_ENCODING_ALAW;
673: aep->precision = 8;
674: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
675: return (0);
676: case 3:
677: strlcpy(aep->name, AudioEslinear, sizeof aep->name);
678: aep->encoding = AUDIO_ENCODING_SLINEAR;
679: aep->precision = 8;
680: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
681: return (0);
682: case 4:
683: strlcpy(aep->name, AudioEslinear_le, sizeof aep->name);
684: aep->encoding = AUDIO_ENCODING_SLINEAR_LE;
685: aep->precision = 16;
686: aep->flags = 0;
687: return (0);
688: case 5:
689: strlcpy(aep->name, AudioEulinear_le, sizeof aep->name);
690: aep->encoding = AUDIO_ENCODING_ULINEAR_LE;
691: aep->precision = 16;
692: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
693: return (0);
694: case 6:
695: strlcpy(aep->name, AudioEslinear_be, sizeof aep->name);
696: aep->encoding = AUDIO_ENCODING_SLINEAR_BE;
697: aep->precision = 16;
698: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
699: return (0);
700: case 7:
701: strlcpy(aep->name, AudioEulinear_be, sizeof aep->name);
702: aep->encoding = AUDIO_ENCODING_ULINEAR_BE;
703: aep->precision = 16;
704: aep->flags = AUDIO_ENCODINGFLAG_EMULATED;
705: return (0);
706: default:
707: return (EINVAL);
708: }
709: }
710:
711: int
712: auich_set_params(v, setmode, usemode, play, rec)
713: void *v;
714: int setmode, usemode;
715: struct audio_params *play, *rec;
716: {
717: struct auich_softc *sc = v;
718: int error;
719: u_int orate;
720: u_int adj_rate;
721:
722: if (setmode & AUMODE_PLAY) {
723: play->factor = 1;
724: play->sw_code = NULL;
725: switch(play->encoding) {
726: case AUDIO_ENCODING_ULAW:
727: switch (play->channels) {
728: case 1:
729: play->factor = 4;
730: play->sw_code = mulaw_to_slinear16_mts;
731: break;
732: case 2:
733: play->factor = 2;
734: play->sw_code = mulaw_to_slinear16;
735: break;
736: default:
737: return (EINVAL);
738: }
739: break;
740: case AUDIO_ENCODING_SLINEAR_LE:
741: switch (play->precision) {
742: case 8:
743: switch (play->channels) {
744: case 1:
745: play->factor = 4;
746: play->sw_code = linear8_to_linear16_mts;
747: break;
748: case 2:
749: play->factor = 2;
750: play->sw_code = linear8_to_linear16;
751: break;
752: default:
753: return (EINVAL);
754: }
755: break;
756: case 16:
757: switch (play->channels) {
758: case 1:
759: play->factor = 2;
760: play->sw_code = noswap_bytes_mts;
761: break;
762: case 2:
763: break;
764: default:
765: return (EINVAL);
766: }
767: break;
768: default:
769: return (EINVAL);
770: }
771: break;
772: case AUDIO_ENCODING_ULINEAR_LE:
773: switch (play->precision) {
774: case 8:
775: switch (play->channels) {
776: case 1:
777: play->factor = 4;
778: play->sw_code = ulinear8_to_linear16_mts;
779: break;
780: case 2:
781: play->factor = 2;
782: play->sw_code = ulinear8_to_linear16;
783: break;
784: default:
785: return (EINVAL);
786: }
787: break;
788: case 16:
789: switch (play->channels) {
790: case 1:
791: play->factor = 2;
792: play->sw_code = change_sign16_mts;
793: break;
794: case 2:
795: play->sw_code = change_sign16;
796: break;
797: default:
798: return (EINVAL);
799: }
800: break;
801: default:
802: return (EINVAL);
803: }
804: break;
805: case AUDIO_ENCODING_ALAW:
806: switch (play->channels) {
807: case 1:
808: play->factor = 4;
809: play->sw_code = alaw_to_slinear16_mts;
810: break;
811: case 2:
812: play->factor = 2;
813: play->sw_code = alaw_to_slinear16;
814: break;
815: default:
816: return (EINVAL);
817: }
818: break;
819: case AUDIO_ENCODING_SLINEAR_BE:
820: switch (play->precision) {
821: case 8:
822: switch (play->channels) {
823: case 1:
824: play->factor = 4;
825: play->sw_code = linear8_to_linear16_mts;
826: break;
827: case 2:
828: play->factor = 2;
829: play->sw_code = linear8_to_linear16;
830: break;
831: default:
832: return (EINVAL);
833: }
834: break;
835: case 16:
836: switch (play->channels) {
837: case 1:
838: play->factor = 2;
839: play->sw_code = swap_bytes_mts;
840: break;
841: case 2:
842: play->sw_code = swap_bytes;
843: break;
844: default:
845: return (EINVAL);
846: }
847: break;
848: default:
849: return (EINVAL);
850: }
851: break;
852: case AUDIO_ENCODING_ULINEAR_BE:
853: switch (play->precision) {
854: case 8:
855: switch (play->channels) {
856: case 1:
857: play->factor = 4;
858: play->sw_code = ulinear8_to_linear16_mts;
859: break;
860: case 2:
861: play->factor = 2;
862: play->sw_code = ulinear8_to_linear16;
863: break;
864: default:
865: return (EINVAL);
866: }
867: break;
868: case 16:
869: switch (play->channels) {
870: case 1:
871: play->factor = 2;
872: play->sw_code = change_sign16_swap_bytes_mts;
873: break;
874: case 2:
875: play->sw_code = change_sign16_swap_bytes;
876: break;
877: default:
878: return (EINVAL);
879: }
880: break;
881: default:
882: return (EINVAL);
883: }
884: break;
885: default:
886: return (EINVAL);
887: }
888:
889: orate = adj_rate = play->sample_rate;
890: if (sc->sc_ac97rate != 0)
891: adj_rate = orate * AUICH_FIXED_RATE / sc->sc_ac97rate;
892: play->sample_rate = adj_rate;
893: error = ac97_set_rate(sc->codec_if, play, AUMODE_PLAY);
894: if (play->sample_rate == adj_rate)
895: play->sample_rate = orate;
896: if (error)
897: return (error);
898: }
899:
900: if (setmode & AUMODE_RECORD) {
901: rec->factor = 1;
902: rec->sw_code = 0;
903: switch(rec->encoding) {
904: case AUDIO_ENCODING_ULAW:
905: rec->sw_code = slinear16_to_mulaw_le;
906: rec->factor = 2;
907: break;
908: case AUDIO_ENCODING_ALAW:
909: rec->sw_code = slinear16_to_alaw_le;
910: rec->factor = 2;
911: break;
912: case AUDIO_ENCODING_SLINEAR_LE:
913: switch (rec->precision) {
914: case 8:
915: rec->sw_code = linear16_to_linear8_le;
916: rec->factor = 2;
917: break;
918: case 16:
919: break;
920: default:
921: return (EINVAL);
922: }
923: break;
924: case AUDIO_ENCODING_ULINEAR_LE:
925: switch (rec->precision) {
926: case 8:
927: rec->sw_code = linear16_to_ulinear8_le;
928: rec->factor = 2;
929: break;
930: case 16:
931: rec->sw_code = change_sign16_le;
932: break;
933: default:
934: return (EINVAL);
935: }
936: break;
937: case AUDIO_ENCODING_SLINEAR_BE:
938: switch (rec->precision) {
939: case 8:
940: rec->sw_code = linear16_to_linear8_le;
941: rec->factor = 2;
942: break;
943: case 16:
944: rec->sw_code = swap_bytes;
945: break;
946: default:
947: return (EINVAL);
948: }
949: break;
950: case AUDIO_ENCODING_ULINEAR_BE:
951: switch (rec->precision) {
952: case 8:
953: rec->sw_code = linear16_to_ulinear8_le;
954: rec->factor = 2;
955: break;
956: case 16:
957: rec->sw_code = change_sign16_swap_bytes_le;
958: break;
959: default:
960: return (EINVAL);
961: }
962: break;
963: default:
964: return (EINVAL);
965: }
966:
967: orate = rec->sample_rate;
968: if (sc->sc_ac97rate != 0)
969: rec->sample_rate = orate * AUICH_FIXED_RATE /
970: sc->sc_ac97rate;
971: error = ac97_set_rate(sc->codec_if, rec, AUMODE_RECORD);
972: rec->sample_rate = orate;
973: if (error)
974: return (error);
975: }
976:
977: return (0);
978: }
979:
980: int
981: auich_round_blocksize(v, blk)
982: void *v;
983: int blk;
984: {
985: return (blk + 0x3f) & ~0x3f;
986: }
987:
988: int
989: auich_halt_output(v)
990: void *v;
991: {
992: struct auich_softc *sc = v;
993:
994: DPRINTF(AUICH_DEBUG_DMA, ("%s: halt_output\n", sc->sc_dev.dv_xname));
995:
996: bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CTRL, AUICH_RR);
997:
998: return 0;
999: }
1000:
1001: int
1002: auich_halt_input(v)
1003: void *v;
1004: {
1005: struct auich_softc *sc = v;
1006:
1007: DPRINTF(AUICH_DEBUG_DMA,
1008: ("%s: halt_input\n", sc->sc_dev.dv_xname));
1009:
1010: /* XXX halt both unless known otherwise */
1011:
1012: bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CTRL, AUICH_RR);
1013: bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_MICI + AUICH_CTRL, AUICH_RR);
1014:
1015: return 0;
1016: }
1017:
1018: int
1019: auich_getdev(v, adp)
1020: void *v;
1021: struct audio_device *adp;
1022: {
1023: struct auich_softc *sc = v;
1024: *adp = sc->sc_audev;
1025: return 0;
1026: }
1027:
1028: int
1029: auich_set_port(v, cp)
1030: void *v;
1031: mixer_ctrl_t *cp;
1032: {
1033: struct auich_softc *sc = v;
1034: return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
1035: }
1036:
1037: int
1038: auich_get_port(v, cp)
1039: void *v;
1040: mixer_ctrl_t *cp;
1041: {
1042: struct auich_softc *sc = v;
1043: return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
1044: }
1045:
1046: int
1047: auich_query_devinfo(v, dp)
1048: void *v;
1049: mixer_devinfo_t *dp;
1050: {
1051: struct auich_softc *sc = v;
1052: return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp);
1053: }
1054:
1055: void *
1056: auich_allocm(v, direction, size, pool, flags)
1057: void *v;
1058: int direction;
1059: size_t size;
1060: int pool, flags;
1061: {
1062: struct auich_softc *sc = v;
1063: struct auich_dma *p;
1064: int error;
1065:
1066: if (size > AUICH_DMALIST_MAX * AUICH_DMASEG_MAX)
1067: return NULL;
1068:
1069: p = malloc(sizeof(*p), pool, flags);
1070: if (!p)
1071: return NULL;
1072: bzero(p, sizeof(*p));
1073:
1074: p->size = size;
1075: if ((error = bus_dmamem_alloc(sc->dmat, p->size, NBPG, 0, p->segs,
1076: 1, &p->nsegs, BUS_DMA_NOWAIT)) != 0) {
1077: printf("%s: unable to allocate dma, error = %d\n",
1078: sc->sc_dev.dv_xname, error);
1079: free(p, pool);
1080: return NULL;
1081: }
1082:
1083: if ((error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size,
1084: &p->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
1085: printf("%s: unable to map dma, error = %d\n",
1086: sc->sc_dev.dv_xname, error);
1087: bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
1088: free(p, pool);
1089: return NULL;
1090: }
1091:
1092: if ((error = bus_dmamap_create(sc->dmat, p->size, 1,
1093: p->size, 0, BUS_DMA_NOWAIT, &p->map)) != 0) {
1094: printf("%s: unable to create dma map, error = %d\n",
1095: sc->sc_dev.dv_xname, error);
1096: bus_dmamem_unmap(sc->dmat, p->addr, size);
1097: bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
1098: free(p, pool);
1099: return NULL;
1100: }
1101:
1102: if ((error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size,
1103: NULL, BUS_DMA_NOWAIT)) != 0) {
1104: printf("%s: unable to load dma map, error = %d\n",
1105: sc->sc_dev.dv_xname, error);
1106: bus_dmamap_destroy(sc->dmat, p->map);
1107: bus_dmamem_unmap(sc->dmat, p->addr, size);
1108: bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
1109: free(p, pool);
1110: return NULL;
1111: }
1112:
1113: p->next = sc->sc_dmas;
1114: sc->sc_dmas = p;
1115:
1116: return p->addr;
1117: }
1118:
1119: void
1120: auich_freem(v, ptr, pool)
1121: void *v;
1122: void *ptr;
1123: int pool;
1124: {
1125: struct auich_softc *sc = v;
1126: struct auich_dma *p;
1127:
1128: for (p = sc->sc_dmas; p->addr != ptr; p = p->next)
1129: if (p->next == NULL) {
1130: printf("auich_freem: trying to free not allocated memory");
1131: return;
1132: }
1133:
1134: bus_dmamap_unload(sc->dmat, p->map);
1135: bus_dmamap_destroy(sc->dmat, p->map);
1136: bus_dmamem_unmap(sc->dmat, p->addr, p->size);
1137: bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
1138: free(p, pool);
1139: }
1140:
1141: size_t
1142: auich_round_buffersize(v, direction, size)
1143: void *v;
1144: int direction;
1145: size_t size;
1146: {
1147: if (size > AUICH_DMALIST_MAX * AUICH_DMASEG_MAX)
1148: size = AUICH_DMALIST_MAX * AUICH_DMASEG_MAX;
1149:
1150: return size;
1151: }
1152:
1153: paddr_t
1154: auich_mappage(v, mem, off, prot)
1155: void *v;
1156: void *mem;
1157: off_t off;
1158: int prot;
1159: {
1160: struct auich_softc *sc = v;
1161: struct auich_dma *p;
1162:
1163: if (off < 0)
1164: return -1;
1165:
1166: for (p = sc->sc_dmas; p && p->addr != mem; p = p->next);
1167: if (!p)
1168: return -1;
1169:
1170: return bus_dmamem_mmap(sc->dmat, p->segs, p->nsegs,
1171: off, prot, BUS_DMA_WAITOK);
1172: }
1173:
1174: int
1175: auich_get_props(v)
1176: void *v;
1177: {
1178: return AUDIO_PROP_MMAP | AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
1179: }
1180:
1181: int
1182: auich_intr(v)
1183: void *v;
1184: {
1185: struct auich_softc *sc = v;
1186: int ret = 0, sts, gsts, i;
1187:
1188: gsts = bus_space_read_2(sc->iot, sc->aud_ioh, AUICH_GSTS);
1189: DPRINTF(AUICH_DEBUG_DMA, ("auich_intr: gsts=%b\n", gsts, AUICH_GSTS_BITS));
1190:
1191: if (gsts & AUICH_POINT) {
1192: sts = bus_space_read_2(sc->iot, sc->aud_ioh,
1193: AUICH_PCMO + sc->sc_sts_reg);
1194: DPRINTF(AUICH_DEBUG_DMA,
1195: ("auich_intr: osts=%b\n", sts, AUICH_ISTS_BITS));
1196:
1197: #ifdef AUICH_DEBUG
1198: if (sts & AUICH_FIFOE) {
1199: printf("%s: fifo underrun # %u\n",
1200: sc->sc_dev.dv_xname, ++sc->pcmo_fifoe);
1201: }
1202: #endif
1203: i = bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CIV);
1204: if (sts & (AUICH_LVBCI | AUICH_CELV)) {
1205: struct auich_dmalist *q, *qe;
1206:
1207: q = sc->dmap_pcmo;
1208: qe = &sc->dmalist_pcmo[i];
1209:
1210: while (q != qe) {
1211:
1212: q->base = sc->pcmo_p;
1213: q->len = (sc->pcmo_blksize /
1214: sc->sc_sample_size) | AUICH_DMAF_IOC;
1215: DPRINTF(AUICH_DEBUG_DMA,
1216: ("auich_intr: %p, %p = %x @ %p\n",
1217: qe, q, sc->pcmo_blksize /
1218: sc->sc_sample_size, sc->pcmo_p));
1219:
1220: sc->pcmo_p += sc->pcmo_blksize;
1221: if (sc->pcmo_p >= sc->pcmo_end)
1222: sc->pcmo_p = sc->pcmo_start;
1223:
1224: if (++q == &sc->dmalist_pcmo[AUICH_DMALIST_MAX])
1225: q = sc->dmalist_pcmo;
1226: }
1227:
1228: sc->dmap_pcmo = q;
1229: bus_space_write_1(sc->iot, sc->aud_ioh,
1230: AUICH_PCMO + AUICH_LVI,
1231: (sc->dmap_pcmo - sc->dmalist_pcmo - 1) &
1232: AUICH_LVI_MASK);
1233: }
1234:
1235: if (sts & AUICH_BCIS && sc->sc_pintr)
1236: sc->sc_pintr(sc->sc_parg);
1237:
1238: /* int ack */
1239: bus_space_write_2(sc->iot, sc->aud_ioh,
1240: AUICH_PCMO + sc->sc_sts_reg, sts &
1241: (AUICH_LVBCI | AUICH_CELV | AUICH_BCIS | AUICH_FIFOE));
1242: bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_POINT);
1243: ret++;
1244: }
1245:
1246: if (gsts & AUICH_PIINT) {
1247: sts = bus_space_read_2(sc->iot, sc->aud_ioh,
1248: AUICH_PCMI + sc->sc_sts_reg);
1249: DPRINTF(AUICH_DEBUG_DMA,
1250: ("auich_intr: ists=%b\n", sts, AUICH_ISTS_BITS));
1251:
1252: #ifdef AUICH_DEBUG
1253: if (sts & AUICH_FIFOE) {
1254: printf("%s: in fifo overrun # %u\n",
1255: sc->sc_dev.dv_xname, ++sc->pcmi_fifoe);
1256: }
1257: #endif
1258: i = bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CIV);
1259: if (sts & (AUICH_LVBCI | AUICH_CELV)) {
1260: struct auich_dmalist *q, *qe;
1261:
1262: q = sc->dmap_pcmi;
1263: qe = &sc->dmalist_pcmi[i];
1264:
1265: while (q != qe) {
1266:
1267: q->base = sc->pcmi_p;
1268: q->len = (sc->pcmi_blksize /
1269: sc->sc_sample_size) | AUICH_DMAF_IOC;
1270: DPRINTF(AUICH_DEBUG_DMA,
1271: ("auich_intr: %p, %p = %x @ %p\n",
1272: qe, q, sc->pcmi_blksize /
1273: sc->sc_sample_size, sc->pcmi_p));
1274:
1275: sc->pcmi_p += sc->pcmi_blksize;
1276: if (sc->pcmi_p >= sc->pcmi_end)
1277: sc->pcmi_p = sc->pcmi_start;
1278:
1279: if (++q == &sc->dmalist_pcmi[AUICH_DMALIST_MAX])
1280: q = sc->dmalist_pcmi;
1281: }
1282:
1283: sc->dmap_pcmi = q;
1284: bus_space_write_1(sc->iot, sc->aud_ioh,
1285: AUICH_PCMI + AUICH_LVI,
1286: (sc->dmap_pcmi - sc->dmalist_pcmi - 1) &
1287: AUICH_LVI_MASK);
1288: }
1289:
1290: if (sts & AUICH_BCIS && sc->sc_rintr)
1291: sc->sc_rintr(sc->sc_rarg);
1292:
1293: /* int ack */
1294: bus_space_write_2(sc->iot, sc->aud_ioh,
1295: AUICH_PCMI + sc->sc_sts_reg, sts &
1296: (AUICH_LVBCI | AUICH_CELV | AUICH_BCIS | AUICH_FIFOE));
1297: bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_PIINT);
1298: ret++;
1299: }
1300:
1301: if (gsts & AUICH_MIINT) {
1302: sts = bus_space_read_2(sc->iot, sc->aud_ioh,
1303: AUICH_MICI + sc->sc_sts_reg);
1304: DPRINTF(AUICH_DEBUG_DMA,
1305: ("auich_intr: ists=%b\n", sts, AUICH_ISTS_BITS));
1306: #ifdef AUICH_DEBUG
1307: if (sts & AUICH_FIFOE)
1308: printf("%s: mic fifo overrun\n", sc->sc_dev.dv_xname);
1309: #endif
1310:
1311: /* TODO mic input dma */
1312:
1313: bus_space_write_2(sc->iot, sc->aud_ioh, AUICH_GSTS, AUICH_MIINT);
1314: }
1315:
1316: return ret;
1317: }
1318:
1319: int
1320: auich_trigger_output(v, start, end, blksize, intr, arg, param)
1321: void *v;
1322: void *start, *end;
1323: int blksize;
1324: void (*intr)(void *);
1325: void *arg;
1326: struct audio_params *param;
1327: {
1328: struct auich_softc *sc = v;
1329: struct auich_dmalist *q;
1330: struct auich_dma *p;
1331:
1332: DPRINTF(AUICH_DEBUG_DMA,
1333: ("auich_trigger_output(%x, %x, %d, %p, %p, %p)\n",
1334: start, end, blksize, intr, arg, param));
1335:
1336: for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1337: if (!p)
1338: return -1;
1339:
1340: sc->sc_pintr = intr;
1341: sc->sc_parg = arg;
1342:
1343: /*
1344: * The logic behind this is:
1345: * setup one buffer to play, then LVI dump out the rest
1346: * to the scatter-gather chain.
1347: */
1348: sc->pcmo_start = p->segs->ds_addr;
1349: sc->pcmo_p = sc->pcmo_start + blksize;
1350: sc->pcmo_end = sc->pcmo_start + ((char *)end - (char *)start);
1351: sc->pcmo_blksize = blksize;
1352:
1353: q = sc->dmap_pcmo = sc->dmalist_pcmo;
1354: q->base = sc->pcmo_start;
1355: q->len = (blksize / sc->sc_sample_size) | AUICH_DMAF_IOC;
1356: if (++q == &sc->dmalist_pcmo[AUICH_DMALIST_MAX])
1357: q = sc->dmalist_pcmo;
1358: sc->dmap_pcmo = q;
1359:
1360: bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_BDBAR,
1361: sc->dmalist_pcmo_pa);
1362: bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_CTRL,
1363: AUICH_IOCE | AUICH_FEIE | AUICH_LVBIE | AUICH_RPBM);
1364: bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMO + AUICH_LVI,
1365: (sc->dmap_pcmo - 1 - sc->dmalist_pcmo) & AUICH_LVI_MASK);
1366:
1367: return 0;
1368: }
1369:
1370: int
1371: auich_trigger_input(v, start, end, blksize, intr, arg, param)
1372: void *v;
1373: void *start, *end;
1374: int blksize;
1375: void (*intr)(void *);
1376: void *arg;
1377: struct audio_params *param;
1378: {
1379: struct auich_softc *sc = v;
1380: struct auich_dmalist *q;
1381: struct auich_dma *p;
1382:
1383: DPRINTF(AUICH_DEBUG_DMA,
1384: ("auich_trigger_input(%x, %x, %d, %p, %p, %p)\n",
1385: start, end, blksize, intr, arg, param));
1386:
1387: for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
1388: if (!p)
1389: return -1;
1390:
1391: sc->sc_rintr = intr;
1392: sc->sc_rarg = arg;
1393:
1394: /*
1395: * The logic behind this is:
1396: * setup one buffer to play, then LVI dump out the rest
1397: * to the scatter-gather chain.
1398: */
1399: sc->pcmi_start = p->segs->ds_addr;
1400: sc->pcmi_p = sc->pcmi_start + blksize;
1401: sc->pcmi_end = sc->pcmi_start + ((char *)end - (char *)start);
1402: sc->pcmi_blksize = blksize;
1403:
1404: q = sc->dmap_pcmi = sc->dmalist_pcmi;
1405: q->base = sc->pcmi_start;
1406: q->len = (blksize / sc->sc_sample_size) | AUICH_DMAF_IOC;
1407: if (++q == &sc->dmalist_pcmi[AUICH_DMALIST_MAX])
1408: q = sc->dmalist_pcmi;
1409: sc->dmap_pcmi = q;
1410:
1411: bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_BDBAR,
1412: sc->dmalist_pcmi_pa);
1413: bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CTRL,
1414: AUICH_IOCE | AUICH_FEIE | AUICH_LVBIE | AUICH_RPBM);
1415: bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_LVI,
1416: (sc->dmap_pcmi - 1 - sc->dmalist_pcmi) & AUICH_LVI_MASK);
1417:
1418: return 0;
1419: }
1420:
1421: void
1422: auich_powerhook(why, self)
1423: int why;
1424: void *self;
1425: {
1426: struct auich_softc *sc = (struct auich_softc *)self;
1427:
1428: if (why != PWR_RESUME) {
1429: /* Power down */
1430: DPRINTF(1, ("auich: power down\n"));
1431: sc->suspend = why;
1432: auich_read_codec(sc, AC97_REG_EXT_AUDIO_CTRL, &sc->ext_ctrl);
1433:
1434: } else {
1435: /* Wake up */
1436: DPRINTF(1, ("auich: power resume\n"));
1437: if (sc->suspend == PWR_RESUME) {
1438: printf("%s: resume without suspend?\n",
1439: sc->sc_dev.dv_xname);
1440: sc->suspend = why;
1441: return;
1442: }
1443: sc->suspend = why;
1444: auich_reset_codec(sc);
1445: DELAY(1000);
1446: (sc->codec_if->vtbl->restore_ports)(sc->codec_if);
1447: auich_write_codec(sc, AC97_REG_EXT_AUDIO_CTRL, sc->ext_ctrl);
1448: }
1449: }
1450:
1451:
1452:
1453: /* -------------------------------------------------------------------- */
1454: /* Calibrate card (some boards are overclocked and need scaling) */
1455:
1456: unsigned int
1457: auich_calibrate(struct auich_softc *sc)
1458: {
1459: struct timeval t1, t2;
1460: u_int8_t ociv, nciv;
1461: u_int32_t wait_us, actual_48k_rate, bytes, ac97rate;
1462: void *temp_buffer;
1463: struct auich_dma *p;
1464: int i;
1465:
1466: ac97rate = AUICH_FIXED_RATE;
1467: /*
1468: * Grab audio from input for fixed interval and compare how
1469: * much we actually get with what we expect. Interval needs
1470: * to be sufficiently short that no interrupts are
1471: * generated.
1472: */
1473:
1474: /* Setup a buffer */
1475: bytes = 16000;
1476: temp_buffer = auich_allocm(sc, AUMODE_RECORD, bytes, M_DEVBUF,
1477: M_NOWAIT);
1478: if (temp_buffer == NULL)
1479: return (ac97rate);
1480: for (p = sc->sc_dmas; p && p->addr != temp_buffer; p = p->next)
1481: ;
1482: if (p == NULL) {
1483: printf("auich_calibrate: bad address %p\n", temp_buffer);
1484: return (ac97rate);
1485: }
1486:
1487: for (i = 0; i < AUICH_DMALIST_MAX; i++) {
1488: sc->dmalist_pcmi[i].base = p->map->dm_segs[0].ds_addr;
1489: sc->dmalist_pcmi[i].len = bytes / sc->sc_sample_size;
1490: }
1491:
1492: /*
1493: * our data format is stereo, 16 bit so each sample is 4 bytes.
1494: * assuming we get 48000 samples per second, we get 192000 bytes/sec.
1495: * we're going to start recording with interrupts disabled and measure
1496: * the time taken for one block to complete. we know the block size,
1497: * we know the time in microseconds, we calculate the sample rate:
1498: *
1499: * actual_rate [bps] = bytes / (time [s] * 4)
1500: * actual_rate [bps] = (bytes * 1000000) / (time [us] * 4)
1501: * actual_rate [Hz] = (bytes * 250000) / time [us]
1502: */
1503:
1504: /* prepare */
1505: ociv = bus_space_read_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CIV);
1506: nciv = ociv;
1507: bus_space_write_4(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_BDBAR,
1508: sc->dmalist_pcmi_pa);
1509: bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_LVI,
1510: (0 - 1) & AUICH_LVI_MASK);
1511:
1512: /* start */
1513: microuptime(&t1);
1514: bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CTRL,
1515: AUICH_RPBM);
1516:
1517: /* wait */
1518: while (nciv == ociv) {
1519: microuptime(&t2);
1520: if (t2.tv_sec - t1.tv_sec > 1)
1521: break;
1522: nciv = bus_space_read_1(sc->iot, sc->aud_ioh,
1523: AUICH_PCMI + AUICH_CIV);
1524: }
1525: microuptime(&t2);
1526:
1527: /* reset */
1528: bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_PCMI + AUICH_CTRL, AUICH_RR);
1529: bus_space_write_1(sc->iot, sc->aud_ioh, AUICH_MICI + AUICH_CTRL, AUICH_RR);
1530: DELAY(100);
1531:
1532: /* turn time delta into us */
1533: wait_us = ((t2.tv_sec - t1.tv_sec) * 1000000) + t2.tv_usec - t1.tv_usec;
1534:
1535: #if 0
1536: auich_freem(sc, temp_buffer, M_DEVBUF);
1537: #endif
1538:
1539: if (nciv == ociv) {
1540: printf("%s: ac97 link rate calibration timed out after %d us\n",
1541: sc->sc_dev.dv_xname, wait_us);
1542: return (ac97rate);
1543: }
1544:
1545: actual_48k_rate = (bytes * 250000) / wait_us;
1546:
1547: if (actual_48k_rate <= 48500)
1548: ac97rate = AUICH_FIXED_RATE;
1549: else
1550: ac97rate = actual_48k_rate;
1551:
1552: printf("%s: measured ac97 link rate at %d Hz",
1553: sc->sc_dev.dv_xname, actual_48k_rate);
1554: if (ac97rate != actual_48k_rate)
1555: printf(", will use %d Hz", ac97rate);
1556: printf("\n");
1557:
1558: return (ac97rate);
1559: }
CVSweb