Annotation of src/sys/dev/pci/gcscaudio.c, Revision 1.18
1.18 ! isaki 1: /* $NetBSD: gcscaudio.c,v 1.17 2019/05/08 13:40:19 isaki Exp $ */
1.1 jmcneill 2:
3: /*-
4: * Copyright (c) 2008 SHIMIZU Ryo <ryo@nerv.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: *
16: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26: * POSSIBILITY OF SUCH DAMAGE.
27: */
28:
29: #include <sys/cdefs.h>
1.18 ! isaki 30: __KERNEL_RCSID(0, "$NetBSD: gcscaudio.c,v 1.17 2019/05/08 13:40:19 isaki Exp $");
1.1 jmcneill 31:
32: #include <sys/param.h>
33: #include <sys/systm.h>
1.8 jmcneill 34: #include <sys/kmem.h>
1.1 jmcneill 35: #include <sys/device.h>
36: #include <sys/queue.h>
37:
38: #include <dev/pci/pcidevs.h>
39: #include <dev/pci/pcivar.h>
40:
41: #include <sys/audioio.h>
1.17 isaki 42: #include <dev/audio/audio_if.h>
43:
1.1 jmcneill 44: #include <dev/ic/ac97reg.h>
45: #include <dev/ic/ac97var.h>
46:
47: #include <dev/pci/gcscaudioreg.h>
48:
49:
50: #define GCSCAUDIO_NPRDTABLE 256 /* including a JMP-PRD for loop */
51: #define GCSCAUDIO_PRD_SIZE_MAX 65532 /* limited by CS5536 Controller */
52: #define GCSCAUDIO_BUFSIZE_MAX (GCSCAUDIO_PRD_SIZE_MAX * (GCSCAUDIO_NPRDTABLE - 1))
53:
54: struct gcscaudio_prd {
55: /* PRD table for play/rec */
56: struct gcscaudio_prdtables {
57: #define PRD_TABLE_FRONT 0
58: #define PRD_TABLE_SURR 1
59: #define PRD_TABLE_CENTER 2
60: #define PRD_TABLE_LFE 3
61: #define PRD_TABLE_REC 4
62: #define PRD_TABLE_MAX 5
63: struct acc_prd prdtbl[PRD_TABLE_MAX][GCSCAUDIO_NPRDTABLE];
64: } *p_prdtables;
65: bus_dmamap_t p_prdmap;
66: bus_dma_segment_t p_prdsegs[1];
67: int p_prdnseg;
68: };
69:
70: struct gcscaudio_dma {
71: LIST_ENTRY(gcscaudio_dma) list;
72: bus_dmamap_t map;
73: void *addr;
74: size_t size;
75: bus_dma_segment_t segs[1];
76: int nseg;
77: };
78:
79: struct gcscaudio_softc_ch {
80: void (*ch_intr)(void *);
81: void *ch_intr_arg;
82: struct audio_params ch_params;
83: };
84:
85: struct gcscaudio_softc {
1.12 nonaka 86: device_t sc_dev;
1.8 jmcneill 87: kmutex_t sc_lock;
88: kmutex_t sc_intr_lock;
1.1 jmcneill 89: pci_chipset_tag_t sc_pc;
90: pcitag_t sc_pt;
91: void *sc_ih;
92: bus_space_tag_t sc_iot;
93: bus_space_handle_t sc_ioh;
94: bus_size_t sc_ios;
95: bus_dma_tag_t sc_dmat;
96:
97: /* allocated DMA buffer list */
98: LIST_HEAD(, gcscaudio_dma) sc_dmalist;
99:
100: #define GCSCAUDIO_MAXFORMATS 4
101: struct audio_format sc_formats[GCSCAUDIO_MAXFORMATS];
102: int sc_nformats;
103:
104: /* AC97 codec */
105: struct ac97_host_if host_if;
106: struct ac97_codec_if *codec_if;
107:
108: /* input, output channels */
109: struct gcscaudio_softc_ch sc_play;
110: struct gcscaudio_softc_ch sc_rec;
111: struct gcscaudio_prd sc_prd;
112:
113: /* multi channel splitter work; {4,6}ch stream to {2,4} DMA buffers */
114: void *sc_mch_split_buf;
115: void *sc_mch_split_start;
116: int sc_mch_split_off;
117: int sc_mch_split_size;
118: int sc_mch_split_blksize;
119: void (*sc_mch_splitter)(void *, void *, int, int);
120: bool sc_spdif;
121: };
122:
123: /* for cfattach */
1.2 cegger 124: static int gcscaudio_match(device_t, cfdata_t, void *);
1.1 jmcneill 125: static void gcscaudio_attach(device_t, device_t, void *);
126:
127: /* for audio_hw_if */
128: static int gcscaudio_open(void *, int);
129: static void gcscaudio_close(void *);
1.17 isaki 130: static int gcscaudio_query_format(void *, audio_format_query_t *);
131: static int gcscaudio_set_format(void *, int,
132: const audio_params_t *, const audio_params_t *,
133: audio_filter_reg_t *, audio_filter_reg_t *);
1.1 jmcneill 134: static int gcscaudio_round_blocksize(void *, int, int, const audio_params_t *);
135: static int gcscaudio_halt_output(void *);
136: static int gcscaudio_halt_input(void *);
137: static int gcscaudio_getdev(void *, struct audio_device *);
138: static int gcscaudio_set_port(void *, mixer_ctrl_t *);
139: static int gcscaudio_get_port(void *, mixer_ctrl_t *);
140: static int gcscaudio_query_devinfo(void *, mixer_devinfo_t *);
1.8 jmcneill 141: static void *gcscaudio_malloc(void *, int, size_t);
142: static void gcscaudio_free(void *, void *, size_t);
1.1 jmcneill 143: static size_t gcscaudio_round_buffersize(void *, int, size_t);
144: static int gcscaudio_get_props(void *);
145: static int gcscaudio_trigger_output(void *, void *, void *, int,
146: void (*)(void *), void *,
147: const audio_params_t *);
148: static int gcscaudio_trigger_input(void *, void *, void *, int,
149: void (*)(void *), void *,
150: const audio_params_t *);
1.8 jmcneill 151: static void gcscaudio_get_locks(void *, kmutex_t **, kmutex_t **);
1.5 dyoung 152: static bool gcscaudio_resume(device_t, const pmf_qual_t *);
1.1 jmcneill 153: static int gcscaudio_intr(void *);
154:
155: /* for codec_if */
156: static int gcscaudio_attach_codec(void *, struct ac97_codec_if *);
157: static int gcscaudio_write_codec(void *, uint8_t, uint16_t);
158: static int gcscaudio_read_codec(void *, uint8_t, uint16_t *);
159: static int gcscaudio_reset_codec(void *);
160: static void gcscaudio_spdif_event_codec(void *, bool);
161:
162: /* misc */
163: static int gcscaudio_append_formats(struct gcscaudio_softc *,
164: const struct audio_format *);
165: static int gcscaudio_wait_ready_codec(struct gcscaudio_softc *sc, const char *);
166: static int gcscaudio_allocate_dma(struct gcscaudio_softc *, size_t, void **,
167: bus_dma_segment_t *, int, int *,
1.8 jmcneill 168: bus_dmamap_t *);
1.1 jmcneill 169:
170:
1.12 nonaka 171: CFATTACH_DECL_NEW(gcscaudio, sizeof (struct gcscaudio_softc),
1.1 jmcneill 172: gcscaudio_match, gcscaudio_attach, NULL, NULL);
173:
174:
175: static struct audio_device gcscaudio_device = {
176: "AMD Geode CS5536",
177: "",
178: "gcscaudio"
179: };
180:
181: static const struct audio_hw_if gcscaudio_hw_if = {
182: .open = gcscaudio_open,
183: .close = gcscaudio_close,
1.17 isaki 184: .query_format = gcscaudio_query_format,
185: .set_format = gcscaudio_set_format,
1.1 jmcneill 186: .round_blocksize = gcscaudio_round_blocksize,
187: .commit_settings = NULL,
188: .init_output = NULL,
189: .init_input = NULL,
190: .start_output = NULL,
191: .start_input = NULL,
192: .halt_output = gcscaudio_halt_output,
193: .halt_input = gcscaudio_halt_input,
194: .speaker_ctl = NULL,
195: .getdev = gcscaudio_getdev,
196: .set_port = gcscaudio_set_port,
197: .get_port = gcscaudio_get_port,
198: .query_devinfo = gcscaudio_query_devinfo,
199: .allocm = gcscaudio_malloc,
200: .freem = gcscaudio_free,
201: .round_buffersize = gcscaudio_round_buffersize,
202: .get_props = gcscaudio_get_props,
203: .trigger_output = gcscaudio_trigger_output,
204: .trigger_input = gcscaudio_trigger_input,
205: .dev_ioctl = NULL,
1.8 jmcneill 206: .get_locks = gcscaudio_get_locks,
1.1 jmcneill 207: };
208:
1.17 isaki 209: #define GCSCAUDIO_FORMAT(aumode, ch, chmask) \
210: { \
211: .mode = (aumode), \
212: .encoding = AUDIO_ENCODING_SLINEAR_LE, \
213: .validbits = 16, \
214: .precision = 16, \
215: .channels = (ch), \
216: .channel_mask = (chmask), \
217: .frequency_type = 0, \
218: .frequency = { 8000, 48000 }, \
219: }
220: static const struct audio_format gcscaudio_formats_2ch =
221: GCSCAUDIO_FORMAT(AUMODE_PLAY | AUMODE_RECORD, 2, AUFMT_STEREO);
1.1 jmcneill 222:
1.17 isaki 223: static const struct audio_format gcscaudio_formats_4ch =
224: GCSCAUDIO_FORMAT(AUMODE_PLAY , 4, AUFMT_SURROUND4);
1.1 jmcneill 225:
1.17 isaki 226: static const struct audio_format gcscaudio_formats_6ch =
227: GCSCAUDIO_FORMAT(AUMODE_PLAY , 6, AUFMT_DOLBY_5_1);
1.1 jmcneill 228:
229: static int
1.2 cegger 230: gcscaudio_match(device_t parent, cfdata_t match, void *aux)
1.1 jmcneill 231: {
232: struct pci_attach_args *pa;
233:
234: pa = (struct pci_attach_args *)aux;
235: if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD) &&
236: (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_CS5536_AUDIO))
237: return 1;
238:
239: return 0;
240: }
241:
242: static int
243: gcscaudio_append_formats(struct gcscaudio_softc *sc,
244: const struct audio_format *format)
245: {
246: if (sc->sc_nformats >= GCSCAUDIO_MAXFORMATS) {
1.12 nonaka 247: aprint_error_dev(sc->sc_dev, "too many formats\n");
1.1 jmcneill 248: return EINVAL;
249: }
250: sc->sc_formats[sc->sc_nformats++] = *format;
251: return 0;
252: }
253:
254: static void
255: gcscaudio_attach(device_t parent, device_t self, void *aux)
256: {
257: struct gcscaudio_softc *sc;
258: struct pci_attach_args *pa;
259: const char *intrstr;
260: pci_intr_handle_t ih;
261: int rc, i;
1.14 christos 262: char intrbuf[PCI_INTRSTR_LEN];
1.1 jmcneill 263:
264: sc = device_private(self);
265:
1.12 nonaka 266: sc->sc_dev = self;
267:
1.1 jmcneill 268: aprint_naive(": Audio controller\n");
269:
270: pa = aux;
271: sc->sc_pc = pa->pa_pc;
272: sc->sc_pt = pa->pa_tag;
273: sc->sc_dmat = pa->pa_dmat;
274: LIST_INIT(&sc->sc_dmalist);
275: sc->sc_mch_split_buf = NULL;
1.8 jmcneill 276: mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
1.9 mrg 277: mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
1.1 jmcneill 278:
279: aprint_normal(": AMD Geode CS5536 Audio\n");
280:
281: if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0,
282: &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_ios)) {
1.12 nonaka 283: aprint_error_dev(sc->sc_dev, "can't map i/o space\n");
1.1 jmcneill 284: return;
285: }
286:
287: if (pci_intr_map(pa, &ih)) {
1.12 nonaka 288: aprint_error_dev(sc->sc_dev, "couldn't map interrupt\n");
1.1 jmcneill 289: goto attach_failure_unmap;
290: }
1.14 christos 291: intrstr = pci_intr_string(sc->sc_pc, ih, intrbuf, sizeof(intrbuf));
1.1 jmcneill 292:
1.16 jdolecek 293: sc->sc_ih = pci_intr_establish_xname(sc->sc_pc, ih, IPL_AUDIO,
294: gcscaudio_intr, sc, device_xname(self));
1.1 jmcneill 295: if (sc->sc_ih == NULL) {
1.12 nonaka 296: aprint_error_dev(sc->sc_dev, "couldn't establish interrupt");
1.1 jmcneill 297: if (intrstr != NULL)
1.3 njoly 298: aprint_error(" at %s", intrstr);
299: aprint_error("\n");
1.1 jmcneill 300: goto attach_failure_unmap;
301: }
302:
1.12 nonaka 303: aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr);
1.1 jmcneill 304:
305:
306: if (gcscaudio_allocate_dma(sc, sizeof(*sc->sc_prd.p_prdtables),
307: (void **)&(sc->sc_prd.p_prdtables), sc->sc_prd.p_prdsegs, 1,
1.8 jmcneill 308: &(sc->sc_prd.p_prdnseg), &(sc->sc_prd.p_prdmap)) != 0)
1.1 jmcneill 309: goto attach_failure_intr;
310:
311: sc->host_if.arg = sc;
312: sc->host_if.attach = gcscaudio_attach_codec;
313: sc->host_if.read = gcscaudio_read_codec;
314: sc->host_if.write = gcscaudio_write_codec;
315: sc->host_if.reset = gcscaudio_reset_codec;
316: sc->host_if.spdif_event = gcscaudio_spdif_event_codec;
317:
1.8 jmcneill 318: if ((rc = ac97_attach(&sc->host_if, self, &sc->sc_lock)) != 0) {
1.12 nonaka 319: aprint_error_dev(sc->sc_dev,
1.1 jmcneill 320: "can't attach codec (error=%d)\n", rc);
321: goto attach_failure_intr;
322: }
323:
324: if (!pmf_device_register(self, NULL, gcscaudio_resume))
325: aprint_error_dev(self, "couldn't establish power handler\n");
326:
327:
328: sc->sc_nformats = 0;
329: gcscaudio_append_formats(sc, &gcscaudio_formats_2ch);
1.10 jmcneill 330:
331: mutex_enter(&sc->sc_lock);
1.1 jmcneill 332: if (AC97_IS_4CH(sc->codec_if))
333: gcscaudio_append_formats(sc, &gcscaudio_formats_4ch);
334: if (AC97_IS_6CH(sc->codec_if))
335: gcscaudio_append_formats(sc, &gcscaudio_formats_6ch);
336: if (AC97_IS_FIXED_RATE(sc->codec_if)) {
337: for (i = 0; i < sc->sc_nformats; i++) {
338: sc->sc_formats[i].frequency_type = 1;
339: sc->sc_formats[i].frequency[0] = 48000;
340: }
341: }
1.10 jmcneill 342: mutex_exit(&sc->sc_lock);
1.1 jmcneill 343:
1.12 nonaka 344: audio_attach_mi(&gcscaudio_hw_if, sc, sc->sc_dev);
1.1 jmcneill 345: return;
346:
347: attach_failure_intr:
348: pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
349: attach_failure_unmap:
350: bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
351: return;
352: }
353:
354: static int
355: gcscaudio_attach_codec(void *arg, struct ac97_codec_if *codec_if)
356: {
357: struct gcscaudio_softc *sc;
358:
359: sc = (struct gcscaudio_softc *)arg;
360: sc->codec_if = codec_if;
361: return 0;
362: }
363:
364: static int
365: gcscaudio_reset_codec(void *arg)
366: {
367: struct gcscaudio_softc *sc;
368: sc = (struct gcscaudio_softc *)arg;
369:
370: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL,
371: ACC_CODEC_CNTL_LNK_WRM_RST |
372: ACC_CODEC_CNTL_CMD_NEW);
373:
374: if (gcscaudio_wait_ready_codec(sc, "reset timeout\n"))
375: return 1;
376:
377: return 0;
378: }
379:
380: static void
381: gcscaudio_spdif_event_codec(void *arg, bool flag)
382: {
383: struct gcscaudio_softc *sc;
384:
385: sc = (struct gcscaudio_softc *)arg;
386: sc->sc_spdif = flag;
387: }
388:
389: static int
390: gcscaudio_wait_ready_codec(struct gcscaudio_softc *sc, const char *timeout_msg)
391: {
392: int i;
393:
394: #define GCSCAUDIO_WAIT_READY_CODEC_TIMEOUT 500
395: for (i = GCSCAUDIO_WAIT_READY_CODEC_TIMEOUT; (i >= 0) &&
396: (bus_space_read_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL) &
397: ACC_CODEC_CNTL_CMD_NEW); i--)
398: delay(1);
399:
400: if (i < 0) {
1.12 nonaka 401: aprint_error_dev(sc->sc_dev, "%s", timeout_msg);
1.1 jmcneill 402: return 1;
403: }
404:
405: return 0;
406: }
407:
408: static int
409: gcscaudio_write_codec(void *arg, uint8_t reg, uint16_t val)
410: {
411: struct gcscaudio_softc *sc;
412:
413: sc = (struct gcscaudio_softc *)arg;
414:
415: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL,
416: ACC_CODEC_CNTL_WRITE_CMD |
417: ACC_CODEC_CNTL_CMD_NEW |
418: ACC_CODEC_REG2ADDR(reg) |
419: (val & ACC_CODEC_CNTL_CMD_DATA_MASK));
420:
421: if (gcscaudio_wait_ready_codec(sc, "codec write timeout\n"))
422: return 1;
423:
424: #ifdef GCSCAUDIO_CODEC_DEBUG
1.12 nonaka 425: aprint_error_dev(sc->sc_dev, "codec write: reg=0x%02x, val=0x%04x\n",
1.1 jmcneill 426: reg, val);
427: #endif
428:
429: return 0;
430: }
431:
432: static int
433: gcscaudio_read_codec(void *arg, uint8_t reg, uint16_t *val)
434: {
435: struct gcscaudio_softc *sc;
436: uint32_t v;
437: int i;
438:
439: sc = (struct gcscaudio_softc *)arg;
440: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_CNTL,
441: ACC_CODEC_CNTL_READ_CMD | ACC_CODEC_CNTL_CMD_NEW |
442: ACC_CODEC_REG2ADDR(reg));
443:
444: if (gcscaudio_wait_ready_codec(sc, "codec write timeout for reading"))
445: return 1;
446:
447: #define GCSCAUDIO_READ_CODEC_TIMEOUT 50
448: for (i = GCSCAUDIO_READ_CODEC_TIMEOUT; i >= 0; i--) {
449: v = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ACC_CODEC_STATUS);
450: if ((v & ACC_CODEC_STATUS_STS_NEW) &&
451: (ACC_CODEC_ADDR2REG(v) == reg))
452: break;
453:
454: delay(10);
455: }
456:
457: if (i < 0) {
1.12 nonaka 458: aprint_error_dev(sc->sc_dev, "codec read timeout\n");
1.1 jmcneill 459: return 1;
460: }
461:
462: #ifdef GCSCAUDIO_CODEC_DEBUG
1.12 nonaka 463: aprint_error_dev(sc->sc_dev, "codec read: reg=0x%02x, val=0x%04x\n",
1.1 jmcneill 464: reg, v & ACC_CODEC_STATUS_STS_DATA_MASK);
465: #endif
466:
467: *val = v;
468: return 0;
469: }
470:
471: static int
472: gcscaudio_open(void *arg, int flags)
473: {
474: struct gcscaudio_softc *sc;
475:
476: sc = (struct gcscaudio_softc *)arg;
477: sc->codec_if->vtbl->lock(sc->codec_if);
478: return 0;
479: }
480:
481: static void
482: gcscaudio_close(void *arg)
483: {
484: struct gcscaudio_softc *sc;
485:
486: sc = (struct gcscaudio_softc *)arg;
487: sc->codec_if->vtbl->unlock(sc->codec_if);
488: }
489:
490: static int
1.17 isaki 491: gcscaudio_query_format(void *arg, audio_format_query_t *afp)
1.1 jmcneill 492: {
493: struct gcscaudio_softc *sc;
494:
495: sc = (struct gcscaudio_softc *)arg;
1.17 isaki 496: return audio_query_format(sc->sc_formats, sc->sc_nformats, afp);
1.1 jmcneill 497: }
498:
499: static int
1.17 isaki 500: gcscaudio_set_format(void *arg, int setmode,
501: const audio_params_t *play, const audio_params_t *rec,
502: audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
1.1 jmcneill 503: {
1.17 isaki 504: struct gcscaudio_softc *sc;
505: int rate;
506: int error;
1.1 jmcneill 507:
1.17 isaki 508: sc = (struct gcscaudio_softc *)arg;
1.1 jmcneill 509:
1.17 isaki 510: if (setmode & AUMODE_PLAY) {
1.1 jmcneill 511: if (!AC97_IS_FIXED_RATE(sc->codec_if)) {
1.13 ryo 512: /* setup rate of DAC */
1.17 isaki 513: rate = play->sample_rate;
1.1 jmcneill 514: if ((error = sc->codec_if->vtbl->set_rate(sc->codec_if,
1.17 isaki 515: AC97_REG_PCM_FRONT_DAC_RATE, &rate)) != 0)
1.1 jmcneill 516: return error;
517:
518: /* additional rate of DAC for Surround */
1.17 isaki 519: rate = play->sample_rate;
520: if ((play->channels >= 4) &&
1.1 jmcneill 521: (error = sc->codec_if->vtbl->set_rate(sc->codec_if,
1.17 isaki 522: AC97_REG_PCM_SURR_DAC_RATE, &rate)) != 0)
1.1 jmcneill 523: return error;
524:
525: /* additional rate of DAC for LowFrequencyEffect */
1.17 isaki 526: rate = play->sample_rate;
527: if ((play->channels == 6) &&
1.1 jmcneill 528: (error = sc->codec_if->vtbl->set_rate(sc->codec_if,
1.17 isaki 529: AC97_REG_PCM_LFE_DAC_RATE, &rate)) != 0)
1.1 jmcneill 530: return error;
531: }
1.17 isaki 532: sc->sc_play.ch_params = *rec;
1.1 jmcneill 533: }
1.17 isaki 534: if (setmode & AUMODE_RECORD) {
1.1 jmcneill 535: if (!AC97_IS_FIXED_RATE(sc->codec_if)) {
1.13 ryo 536: /* setup rate of ADC */
1.17 isaki 537: rate = rec->sample_rate;
1.1 jmcneill 538: if ((error = sc->codec_if->vtbl->set_rate(sc->codec_if,
1.17 isaki 539: AC97_REG_PCM_LR_ADC_RATE, &rate)) != 0)
1.1 jmcneill 540: return error;
541: }
1.17 isaki 542: sc->sc_rec.ch_params = *rec;
1.1 jmcneill 543: }
544:
545: return 0;
546: }
547:
548: static int
549: gcscaudio_round_blocksize(void *arg, int blk, int mode,
550: const audio_params_t *param)
551: {
552: blk &= -4;
553: if (blk > GCSCAUDIO_PRD_SIZE_MAX)
554: blk = GCSCAUDIO_PRD_SIZE_MAX;
555:
556: return blk;
557: }
558:
559: static int
560: gcscaudio_halt_output(void *arg)
561: {
562: struct gcscaudio_softc *sc;
563:
564: sc = (struct gcscaudio_softc *)arg;
565: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD,
566: ACC_BMx_CMD_BM_CTL_DISABLE);
567: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM4_CMD,
568: ACC_BMx_CMD_BM_CTL_DISABLE);
569: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM6_CMD,
570: ACC_BMx_CMD_BM_CTL_DISABLE);
571: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM7_CMD,
572: ACC_BMx_CMD_BM_CTL_DISABLE);
573: sc->sc_play.ch_intr = NULL;
574:
575: /* channel splitter */
576: sc->sc_mch_splitter = NULL;
577: if (sc->sc_mch_split_buf)
1.8 jmcneill 578: gcscaudio_free(sc, sc->sc_mch_split_buf, sc->sc_mch_split_size);
1.1 jmcneill 579: sc->sc_mch_split_buf = NULL;
580:
581: return 0;
582: }
583:
584: static int
585: gcscaudio_halt_input(void *arg)
586: {
587: struct gcscaudio_softc *sc;
588:
589: sc = (struct gcscaudio_softc *)arg;
590: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM1_CMD,
591: ACC_BMx_CMD_BM_CTL_DISABLE);
592: sc->sc_rec.ch_intr = NULL;
593: return 0;
594: }
595:
596: static int
597: gcscaudio_getdev(void *addr, struct audio_device *retp)
598: {
599: *retp = gcscaudio_device;
600: return 0;
601: }
602:
603: static int
604: gcscaudio_set_port(void *addr, mixer_ctrl_t *cp)
605: {
606: struct gcscaudio_softc *sc;
607:
608: sc = addr;
609: return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
610: }
611:
612: static int
613: gcscaudio_get_port(void *addr, mixer_ctrl_t *cp)
614: {
615: struct gcscaudio_softc *sc;
616:
617: sc = addr;
618: return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
619: }
620:
621: static int
622: gcscaudio_query_devinfo(void *addr, mixer_devinfo_t *dip)
623: {
624: struct gcscaudio_softc *sc;
625:
626: sc = addr;
627: return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip);
628: }
629:
630: static void *
1.8 jmcneill 631: gcscaudio_malloc(void *arg, int direction, size_t size)
1.1 jmcneill 632: {
633: struct gcscaudio_softc *sc;
634: struct gcscaudio_dma *p;
635: int error;
636:
637: sc = (struct gcscaudio_softc *)arg;
638:
1.8 jmcneill 639: p = kmem_alloc(sizeof(*p), KM_SLEEP);
1.1 jmcneill 640: p->size = size;
641:
642: error = gcscaudio_allocate_dma(sc, size, &p->addr,
1.8 jmcneill 643: p->segs, sizeof(p->segs)/sizeof(p->segs[0]), &p->nseg, &p->map);
1.1 jmcneill 644: if (error) {
1.8 jmcneill 645: kmem_free(p, sizeof(*p));
1.1 jmcneill 646: return NULL;
647: }
648:
649: LIST_INSERT_HEAD(&sc->sc_dmalist, p, list);
650: return p->addr;
651: }
652:
653: static void
1.8 jmcneill 654: gcscaudio_free(void *arg, void *ptr, size_t size)
1.1 jmcneill 655: {
656: struct gcscaudio_softc *sc;
657: struct gcscaudio_dma *p;
658:
659: sc = (struct gcscaudio_softc *)arg;
660:
661: LIST_FOREACH(p, &sc->sc_dmalist, list) {
662: if (p->addr == ptr) {
663: bus_dmamap_unload(sc->sc_dmat, p->map);
664: bus_dmamap_destroy(sc->sc_dmat, p->map);
665: bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size);
666: bus_dmamem_free(sc->sc_dmat, p->segs, p->nseg);
667:
668: LIST_REMOVE(p, list);
1.8 jmcneill 669: kmem_free(p, sizeof(*p));
1.1 jmcneill 670: break;
671: }
672: }
673: }
674:
675: static size_t
676: gcscaudio_round_buffersize(void *addr, int direction, size_t size)
677: {
678: if (size > GCSCAUDIO_BUFSIZE_MAX)
679: size = GCSCAUDIO_BUFSIZE_MAX;
680:
681: return size;
682: }
683:
684: static int
685: gcscaudio_get_props(void *addr)
686: {
687:
1.18 ! isaki 688: return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE |
! 689: AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
1.1 jmcneill 690: }
691:
692: static int
693: build_prdtables(struct gcscaudio_softc *sc, int prdidx,
694: void *addr, size_t size, int blksize, int blklen, int blkoff)
695: {
696: struct gcscaudio_dma *p;
697: struct acc_prd *prdp;
698: bus_addr_t paddr;
699: int i;
700:
701: /* get physical address of start */
702: paddr = (bus_addr_t)0;
703: LIST_FOREACH(p, &sc->sc_dmalist, list) {
704: if (p->addr == addr) {
705: paddr = p->map->dm_segs[0].ds_addr;
706: break;
707: }
708: }
709: if (!paddr) {
1.12 nonaka 710: aprint_error_dev(sc->sc_dev, "bad addr %p\n", addr);
1.1 jmcneill 711: return EINVAL;
712: }
713:
714: #define PRDADDR(prdidx,idx) \
715: (sc->sc_prd.p_prdmap->dm_segs[0].ds_addr) + sizeof(struct acc_prd) * \
716: (((prdidx) * GCSCAUDIO_NPRDTABLE) + (idx))
717:
718: /*
719: * build PRD table
720: * prdtbl[] = <PRD0>, <PRD1>, <PRD2>, ..., <PRDn>, <jmp to PRD0>
721: */
722: prdp = sc->sc_prd.p_prdtables->prdtbl[prdidx];
723: for (i = 0; size > 0; size -= blksize, i++) {
724: prdp[i].address = paddr + blksize * i + blkoff;
725: prdp[i].ctrlsize =
726: (size < blklen ? size : blklen) | ACC_BMx_PRD_CTRL_EOP;
727: }
728: prdp[i].address = PRDADDR(prdidx, 0);
729: prdp[i].ctrlsize = ACC_BMx_PRD_CTRL_JMP;
730:
731: bus_dmamap_sync(sc->sc_dmat, sc->sc_prd.p_prdmap, 0,
732: sizeof(struct acc_prd) * i, BUS_DMASYNC_PREWRITE);
733:
734: return 0;
735: }
736:
737: static void
738: split_buffer_4ch(void *dst, void *src, int size, int blksize)
739: {
740: int left, i;
741: uint16_t *s, *d;
742:
743: /*
744: * src[blk0]: L,R,SL,SR,L,R,SL,SR,L,R,SL,SR,....
745: * src[blk1]: L,R,SL,SR,L,R,SL,SR,L,R,SL,SR,....
746: * src[blk2]: L,R,SL,SR,L,R,SL,SR,L,R,SL,SR,....
747: * :
748: *
749: * rearrange to
750: *
751: * src[blk0]: L,R,L,R,L,R,L,R,..
752: * src[blk1]: L,R,L,R,L,R,L,R,..
753: * src[blk2]: L,R,L,R,L,R,L,R,..
754: * :
755: * dst[blk0]: SL,SR,SL,SR,SL,SR,SL,SR,..
756: * dst[blk1]: SL,SR,SL,SR,SL,SR,SL,SR,..
757: * dst[blk2]: SL,SR,SL,SR,SL,SR,SL,SR,..
758: * :
759: */
760: for (left = size; left > 0; left -= blksize) {
761: s = (uint16_t *)src;
762: d = (uint16_t *)dst;
763: for (i = 0; i < blksize / sizeof(uint16_t) / 4; i++) {
764: /* L,R,SL,SR -> SL,SR */
765: s++;
766: s++;
767: *d++ = *s++;
768: *d++ = *s++;
769: }
770:
771: s = (uint16_t *)src;
772: d = (uint16_t *)src;
773: for (i = 0; i < blksize / sizeof(uint16_t) / 2 / 2; i++) {
774: /* L,R,SL,SR -> L,R */
775: *d++ = *s++;
776: *d++ = *s++;
777: s++;
778: s++;
779: }
780:
781: src = (char *)src + blksize;
782: dst = (char *)dst + blksize;
783: }
784: }
785:
786: static void
787: split_buffer_6ch(void *dst, void *src, int size, int blksize)
788: {
789: int left, i;
790: uint16_t *s, *d, *dc, *dl;
791:
792: /*
793: * by default, treat as WAV style 5.1ch order
794: * 5.1ch(WAV): L R C LFE SL SR
795: * 5.1ch(AAC): C L R SL SR LFE
796: * :
797: */
798:
799: /*
800: * src[blk0]: L,R,C,LFE,SL,SR,L,R,C,LFE,SL,SR,...
801: * src[blk1]: L,R,C,LFE,SL,SR,L,R,C,LFE,SL,SR,...
802: * src[blk2]: L,R,C,LFE,SL,SR,L,R,C,LFE,SL,SR,...
803: * :
804: * src[N-1] : L,R,C,LFE,SL,SR,L,R,C,LFE,SL,SR,...
805: *
806: * rearrange to
807: *
808: * src[blk0]: L,R,L,R,..
809: * src[blk1]: L,R,L,R,..
810: * src[blk2]: L,R,L,R,..
811: * :
812: *
813: * dst[blk0]: SL,SR,SL,SR,..
814: * dst[blk1]: SL,SR,SL,SR,..
815: * dst[blk2]: SL,SR,SL,SR,..
816: * :
817: *
818: * dst[N/2+0]: C,C,C,..
819: * dst[N/2+1]: C,C,C,..
820: * :
821: *
822: * dst[N/2+N/4+0]: LFE,LFE,LFE,..
823: * dst[N/2+N/4+1]: LFE,LFE,LFE,..
824: * :
825: */
826:
827: for (left = size; left > 0; left -= blksize) {
828: s = (uint16_t *)src;
829: d = (uint16_t *)dst;
830: dc = (uint16_t *)((char *)dst + blksize / 2);
831: dl = (uint16_t *)((char *)dst + blksize / 2 + blksize / 4);
832: for (i = 0; i < blksize / sizeof(uint16_t) / 6; i++) {
833: #ifdef GCSCAUDIO_5_1CH_AAC_ORDER
834: /*
835: * AAC: [C,L,R,SL,SR,LFE]
836: * => [SL,SR]
837: * => [C]
838: * => [LFE]
839: */
840: *dc++ = s[0]; /* C */
841: *dl++ = s[5]; /* LFE */
842: *d++ = s[3]; /* SL */
843: *d++ = s[4]; /* SR */
844: #else
845: /*
846: * WAV: [L,R,C,LFE,SL,SR]
847: * => [SL,SR]
848: * => [C]
849: * => [LFE]
850: */
851: *dc++ = s[2]; /* C */
852: *dl++ = s[3]; /* LFE */
853: *d++ = s[4]; /* SL */
854: *d++ = s[5]; /* SR */
855: #endif
856: s += 6;
857: }
858:
859: s = (uint16_t *)src;
860: d = (uint16_t *)src;
861: for (i = 0; i < blksize / sizeof(uint16_t) / 2 / 2; i++) {
862: #ifdef GCSCAUDIO_5_1CH_AAC_ORDER
863: /* AAC: [C,L,R,SL,SR,LFE] => [L,R] */
864: *d++ = s[1];
865: *d++ = s[2];
866: #else
867: /* WAV: [L,R,C,LFE,SL,SR] => [L,R] */
868: *d++ = s[0];
869: *d++ = s[1];
870: #endif
871: s += 6;
872: }
873:
874: src = (char *)src + blksize;
875: dst = (char *)dst + blksize;
876: }
877: }
878:
879: static void
880: channel_splitter(struct gcscaudio_softc *sc)
881: {
882: int splitsize, left;
883: void *src, *dst;
884:
885: if (sc->sc_mch_splitter == NULL)
886: return;
887:
888: left = sc->sc_mch_split_size - sc->sc_mch_split_off;
889: splitsize = sc->sc_mch_split_blksize;
890: if (left < splitsize)
891: splitsize = left;
892:
893: src = (char *)sc->sc_mch_split_start + sc->sc_mch_split_off;
894: dst = (char *)sc->sc_mch_split_buf + sc->sc_mch_split_off;
895:
896: sc->sc_mch_splitter(dst, src, splitsize, sc->sc_mch_split_blksize);
897:
898: sc->sc_mch_split_off += sc->sc_mch_split_blksize;
899: if (sc->sc_mch_split_off >= sc->sc_mch_split_size)
900: sc->sc_mch_split_off = 0;
901: }
902:
903: static int
904: gcscaudio_trigger_output(void *addr, void *start, void *end, int blksize,
905: void (*intr)(void *), void *arg,
906: const audio_params_t *param)
907: {
908: struct gcscaudio_softc *sc;
909: size_t size;
910:
911: sc = (struct gcscaudio_softc *)addr;
912: sc->sc_play.ch_intr = intr;
913: sc->sc_play.ch_intr_arg = arg;
914: size = (char *)end - (char *)start;
915:
916: switch (sc->sc_play.ch_params.channels) {
917: case 2:
918: if (build_prdtables(sc, PRD_TABLE_FRONT, start, size, blksize,
919: blksize, 0))
920: return EINVAL;
921:
922: if (!AC97_IS_4CH(sc->codec_if)) {
923: /*
924: * output 2ch PCM to FRONT.LR(BM0)
925: *
926: * 2ch: L,R,L,R,L,R,L,R,... => BM0: L,R,L,R,L,R,L,R,...
927: *
928: */
929: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM0_PRD,
930: PRDADDR(PRD_TABLE_FRONT, 0));
931:
932: /* start DMA transfer */
933: bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD,
934: ACC_BMx_CMD_WRITE |
935: ACC_BMx_CMD_BYTE_ORD_EL |
936: ACC_BMx_CMD_BM_CTL_ENABLE);
937: } else {
938: /*
939: * output same PCM to FRONT.LR(BM0) and SURROUND.LR(BM6).
940: * CENTER(BM4) and LFE(BM7) doesn't sound.
941: *
942: * 2ch: L,R,L,R,L,R,L,R,... => BM0: L,R,L,R,L,R,L,R,...
943: * BM6: (same of BM0)
944: * BM4: none
945: * BM7: none
946: */
947: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM0_PRD,
948: PRDADDR(PRD_TABLE_FRONT, 0));
949: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM6_PRD,
950: PRDADDR(PRD_TABLE_FRONT, 0));
951:
952: /* start DMA transfer */
953: bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD,
954: ACC_BMx_CMD_WRITE |
955: ACC_BMx_CMD_BYTE_ORD_EL |
956: ACC_BMx_CMD_BM_CTL_ENABLE);
957: bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM6_CMD,
958: ACC_BMx_CMD_WRITE |
959: ACC_BMx_CMD_BYTE_ORD_EL |
960: ACC_BMx_CMD_BM_CTL_ENABLE);
961: }
962: break;
963: case 4:
964: /*
965: * output 4ch PCM split to FRONT.LR(BM0) and SURROUND.LR(BM6).
966: * CENTER(BM4) and LFE(BM7) doesn't sound.
967: *
968: * rearrange ordered channel to continuous per channel
969: *
970: * 4ch: L,R,SL,SR,L,R,SL,SR,... => BM0: L,R,L,R,...
971: * BM6: SL,SR,SL,SR,...
972: * BM4: none
973: * BM7: none
974: */
975: if (sc->sc_mch_split_buf)
1.8 jmcneill 976: gcscaudio_free(sc, sc->sc_mch_split_buf,
977: sc->sc_mch_split_size);
1.1 jmcneill 978:
979: if ((sc->sc_mch_split_buf = gcscaudio_malloc(sc, AUMODE_PLAY,
1.8 jmcneill 980: size)) == NULL)
1.1 jmcneill 981: return ENOMEM;
982:
983: /*
984: * 1st and 2nd blocks are split immediately.
985: * Other blocks will be split synchronous with intr.
986: */
987: split_buffer_4ch(sc->sc_mch_split_buf, start, blksize * 2,
988: blksize);
989:
990: sc->sc_mch_split_start = start;
991: sc->sc_mch_split_size = size;
992: sc->sc_mch_split_blksize = blksize;
993: sc->sc_mch_split_off = (blksize * 2) % size;
994: sc->sc_mch_splitter = split_buffer_4ch; /* split function */
995:
996: if (build_prdtables(sc, PRD_TABLE_FRONT, start, size, blksize,
997: blksize / 2, 0))
998: return EINVAL;
999: if (build_prdtables(sc, PRD_TABLE_SURR, sc->sc_mch_split_buf,
1000: size, blksize, blksize / 2, 0))
1001: return EINVAL;
1002:
1003: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM0_PRD,
1004: PRDADDR(PRD_TABLE_FRONT, 0));
1005: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM6_PRD,
1006: PRDADDR(PRD_TABLE_SURR, 0));
1007:
1008: /* start DMA transfer */
1009: bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD,
1010: ACC_BMx_CMD_WRITE |
1011: ACC_BMx_CMD_BYTE_ORD_EL |
1012: ACC_BMx_CMD_BM_CTL_ENABLE);
1013: bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM6_CMD,
1014: ACC_BMx_CMD_WRITE |
1015: ACC_BMx_CMD_BYTE_ORD_EL |
1016: ACC_BMx_CMD_BM_CTL_ENABLE);
1017: break;
1018: case 6:
1019: /*
1020: * output 6ch PCM split to
1021: * FRONT.LR(BM0), SURROUND.LR(BM6), CENTER(BM4) and LFE(BM7)
1022: *
1023: * rearrange ordered channel to continuous per channel
1024: *
1025: * 5.1ch: L,R,C,LFE,SL,SR,... => BM0: L,R,...
1026: * BM4: C,...
1027: * BM6: SL,SR,...
1028: * BM7: LFE,...
1029: *
1030: */
1031: if (sc->sc_mch_split_buf)
1.8 jmcneill 1032: gcscaudio_free(sc, sc->sc_mch_split_buf,
1033: sc->sc_mch_split_size);
1.1 jmcneill 1034:
1035: if ((sc->sc_mch_split_buf = gcscaudio_malloc(sc, AUMODE_PLAY,
1.8 jmcneill 1036: size)) == NULL)
1.1 jmcneill 1037: return ENOMEM;
1038:
1039: /*
1040: * 1st and 2nd blocks are split immediately.
1041: * Other block will be split synchronous with intr.
1042: */
1043: split_buffer_6ch(sc->sc_mch_split_buf, start, blksize * 2,
1044: blksize);
1045:
1046: sc->sc_mch_split_start = start;
1047: sc->sc_mch_split_size = size;
1048: sc->sc_mch_split_blksize = blksize;
1049: sc->sc_mch_split_off = (blksize * 2) % size;
1050: sc->sc_mch_splitter = split_buffer_6ch; /* split function */
1051:
1052: if (build_prdtables(sc, PRD_TABLE_FRONT, start, size, blksize,
1053: blksize / 3, 0))
1054: return EINVAL;
1055: if (build_prdtables(sc, PRD_TABLE_CENTER, sc->sc_mch_split_buf,
1056: size, blksize, blksize / 3, blksize / 2))
1057: return EINVAL;
1058: if (build_prdtables(sc, PRD_TABLE_SURR, sc->sc_mch_split_buf,
1059: size, blksize, blksize / 3, 0))
1060: return EINVAL;
1061: if (build_prdtables(sc, PRD_TABLE_LFE, sc->sc_mch_split_buf,
1062: size, blksize, blksize / 3, blksize / 2 + blksize / 4))
1063: return EINVAL;
1064:
1065: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM0_PRD,
1066: PRDADDR(PRD_TABLE_FRONT, 0));
1067: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM4_PRD,
1068: PRDADDR(PRD_TABLE_CENTER, 0));
1069: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM6_PRD,
1070: PRDADDR(PRD_TABLE_SURR, 0));
1071: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM7_PRD,
1072: PRDADDR(PRD_TABLE_LFE, 0));
1073:
1074: /* start DMA transfer */
1075: bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_CMD,
1076: ACC_BMx_CMD_WRITE | ACC_BMx_CMD_BYTE_ORD_EL |
1077: ACC_BMx_CMD_BM_CTL_ENABLE);
1078: bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM4_CMD,
1079: ACC_BMx_CMD_WRITE | ACC_BMx_CMD_BYTE_ORD_EL |
1080: ACC_BMx_CMD_BM_CTL_ENABLE);
1081: bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM6_CMD,
1082: ACC_BMx_CMD_WRITE | ACC_BMx_CMD_BYTE_ORD_EL |
1083: ACC_BMx_CMD_BM_CTL_ENABLE);
1084: bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM7_CMD,
1085: ACC_BMx_CMD_WRITE | ACC_BMx_CMD_BYTE_ORD_EL |
1086: ACC_BMx_CMD_BM_CTL_ENABLE);
1087: break;
1088: }
1089:
1090: return 0;
1091: }
1092:
1093: static int
1094: gcscaudio_trigger_input(void *addr, void *start, void *end, int blksize,
1095: void (*intr)(void *), void *arg,
1096: const audio_params_t *param)
1097: {
1098: struct gcscaudio_softc *sc;
1099: size_t size;
1100:
1101: sc = (struct gcscaudio_softc *)addr;
1102: sc->sc_rec.ch_intr = intr;
1103: sc->sc_rec.ch_intr_arg = arg;
1104: size = (char *)end - (char *)start;
1105:
1106: if (build_prdtables(sc, PRD_TABLE_REC, start, size, blksize, blksize, 0))
1107: return EINVAL;
1108:
1109: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ACC_BM1_PRD,
1110: PRDADDR(PRD_TABLE_REC, 0));
1111:
1112: /* start transfer */
1113: bus_space_write_1(sc->sc_iot, sc->sc_ioh, ACC_BM1_CMD,
1114: ACC_BMx_CMD_READ |
1115: ACC_BMx_CMD_BYTE_ORD_EL |
1116: ACC_BMx_CMD_BM_CTL_ENABLE);
1117:
1118: return 0;
1119: }
1120:
1.8 jmcneill 1121: static void
1122: gcscaudio_get_locks(void *arg, kmutex_t **intr, kmutex_t **thread)
1123: {
1124: struct gcscaudio_softc *sc;
1125:
1126: sc = (struct gcscaudio_softc *)arg;
1127:
1128: *intr = &sc->sc_intr_lock;
1129: *thread = &sc->sc_lock;
1130: }
1131:
1.1 jmcneill 1132: static int
1133: gcscaudio_intr(void *arg)
1134: {
1135: struct gcscaudio_softc *sc;
1136: uint16_t intr;
1137: uint8_t bmstat;
1138: int nintr;
1139:
1140: nintr = 0;
1141: sc = (struct gcscaudio_softc *)arg;
1.8 jmcneill 1142:
1143: mutex_spin_enter(&sc->sc_intr_lock);
1144:
1.1 jmcneill 1145: intr = bus_space_read_2(sc->sc_iot, sc->sc_ioh, ACC_IRQ_STATUS);
1146: if (intr == 0)
1.8 jmcneill 1147: goto done;
1.1 jmcneill 1148:
1149: /* Front output */
1150: if (intr & ACC_IRQ_STATUS_BM0_IRQ_STS) {
1151: bmstat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ACC_BM0_STATUS);
1152: if (bmstat & ACC_BMx_STATUS_BM_EOP_ERR)
1.12 nonaka 1153: aprint_normal_dev(sc->sc_dev, "BM0: Bus Master Error\n");
1.1 jmcneill 1154: if (!(bmstat & ACC_BMx_STATUS_EOP))
1.12 nonaka 1155: aprint_normal_dev(sc->sc_dev, "BM0: NO End of Page?\n");
1.1 jmcneill 1156:
1157: if (sc->sc_play.ch_intr) {
1158: sc->sc_play.ch_intr(sc->sc_play.ch_intr_arg);
1159: channel_splitter(sc);
1160: }
1161: nintr++;
1162: }
1163:
1164: /* Center output */
1165: if (intr & ACC_IRQ_STATUS_BM4_IRQ_STS) {
1166: bmstat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ACC_BM4_STATUS);
1167: if (bmstat & ACC_BMx_STATUS_BM_EOP_ERR)
1.12 nonaka 1168: aprint_normal_dev(sc->sc_dev, "BM4: Bus Master Error\n");
1.1 jmcneill 1169: if (!(bmstat & ACC_BMx_STATUS_EOP))
1.12 nonaka 1170: aprint_normal_dev(sc->sc_dev, "BM4: NO End of Page?\n");
1.1 jmcneill 1171:
1172: nintr++;
1173: }
1174:
1175: /* Surround output */
1176: if (intr & ACC_IRQ_STATUS_BM6_IRQ_STS) {
1177: bmstat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ACC_BM6_STATUS);
1178: if (bmstat & ACC_BMx_STATUS_BM_EOP_ERR)
1.12 nonaka 1179: aprint_normal_dev(sc->sc_dev, "BM6: Bus Master Error\n");
1.1 jmcneill 1180: if (!(bmstat & ACC_BMx_STATUS_EOP))
1.12 nonaka 1181: aprint_normal_dev(sc->sc_dev, "BM6: NO End of Page?\n");
1.1 jmcneill 1182:
1183: nintr++;
1184: }
1185:
1186: /* LowFrequencyEffect output */
1187: if (intr & ACC_IRQ_STATUS_BM7_IRQ_STS) {
1188: bmstat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ACC_BM7_STATUS);
1189: if (bmstat & ACC_BMx_STATUS_BM_EOP_ERR)
1.12 nonaka 1190: aprint_normal_dev(sc->sc_dev, "BM7: Bus Master Error\n");
1.1 jmcneill 1191: if (!(bmstat & ACC_BMx_STATUS_EOP))
1.12 nonaka 1192: aprint_normal_dev(sc->sc_dev, "BM7: NO End of Page?\n");
1.1 jmcneill 1193:
1194: nintr++;
1195: }
1196:
1197: /* record */
1198: if (intr & ACC_IRQ_STATUS_BM1_IRQ_STS) {
1199: bmstat = bus_space_read_1(sc->sc_iot, sc->sc_ioh, ACC_BM1_STATUS);
1200: if (bmstat & ACC_BMx_STATUS_BM_EOP_ERR)
1.12 nonaka 1201: aprint_normal_dev(sc->sc_dev, "BM1: Bus Master Error\n");
1.1 jmcneill 1202: if (!(bmstat & ACC_BMx_STATUS_EOP))
1.12 nonaka 1203: aprint_normal_dev(sc->sc_dev, "BM1: NO End of Page?\n");
1.1 jmcneill 1204:
1205: if (sc->sc_rec.ch_intr) {
1206: sc->sc_rec.ch_intr(sc->sc_rec.ch_intr_arg);
1207: }
1208: nintr++;
1209: }
1210:
1211: #ifdef GCSCAUDIO_DEBUG
1212: if (intr & ACC_IRQ_STATUS_IRQ_STS)
1.12 nonaka 1213: aprint_normal_dev(sc->sc_dev, "Codec GPIO IRQ Status\n");
1.1 jmcneill 1214: if (intr & ACC_IRQ_STATUS_WU_IRQ_STS)
1.12 nonaka 1215: aprint_normal_dev(sc->sc_dev, "Codec GPIO Wakeup IRQ Status\n");
1.1 jmcneill 1216: if (intr & ACC_IRQ_STATUS_BM2_IRQ_STS)
1.12 nonaka 1217: aprint_normal_dev(sc->sc_dev, "Audio Bus Master 2 IRQ Status\n");
1.1 jmcneill 1218: if (intr & ACC_IRQ_STATUS_BM3_IRQ_STS)
1.12 nonaka 1219: aprint_normal_dev(sc->sc_dev, "Audio Bus Master 3 IRQ Status\n");
1.1 jmcneill 1220: if (intr & ACC_IRQ_STATUS_BM5_IRQ_STS)
1.12 nonaka 1221: aprint_normal_dev(sc->sc_dev, "Audio Bus Master 5 IRQ Status\n");
1.1 jmcneill 1222: #endif
1223:
1.8 jmcneill 1224: done:
1225: mutex_spin_exit(&sc->sc_intr_lock);
1226:
1.1 jmcneill 1227: return nintr ? 1 : 0;
1228: }
1229:
1230: static bool
1.5 dyoung 1231: gcscaudio_resume(device_t dv, const pmf_qual_t *qual)
1.1 jmcneill 1232: {
1233: struct gcscaudio_softc *sc = device_private(dv);
1234:
1235: gcscaudio_reset_codec(sc);
1236: DELAY(1000);
1237: (sc->codec_if->vtbl->restore_ports)(sc->codec_if);
1238:
1239: return true;
1240: }
1241:
1242: static int
1243: gcscaudio_allocate_dma(struct gcscaudio_softc *sc, size_t size, void **addrp,
1244: bus_dma_segment_t *seglist, int nseg, int *rsegp,
1.8 jmcneill 1245: bus_dmamap_t *mapp)
1.1 jmcneill 1246: {
1247: int error;
1248:
1249: if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, seglist,
1.8 jmcneill 1250: nseg, rsegp, BUS_DMA_WAITOK)) != 0) {
1.12 nonaka 1251: aprint_error_dev(sc->sc_dev,
1.1 jmcneill 1252: "unable to allocate DMA buffer, error=%d\n", error);
1253: goto fail_alloc;
1254: }
1255:
1256: if ((error = bus_dmamem_map(sc->sc_dmat, seglist, nseg, size, addrp,
1.8 jmcneill 1257: BUS_DMA_WAITOK | BUS_DMA_COHERENT)) != 0) {
1.12 nonaka 1258: aprint_error_dev(sc->sc_dev,
1.1 jmcneill 1259: "unable to map DMA buffer, error=%d\n",
1260: error);
1261: goto fail_map;
1262: }
1263:
1264: if ((error = bus_dmamap_create(sc->sc_dmat, size, nseg, size, 0,
1.8 jmcneill 1265: BUS_DMA_WAITOK, mapp)) != 0) {
1.12 nonaka 1266: aprint_error_dev(sc->sc_dev,
1.1 jmcneill 1267: "unable to create DMA map, error=%d\n", error);
1268: goto fail_create;
1269: }
1270:
1271: if ((error = bus_dmamap_load(sc->sc_dmat, *mapp, *addrp, size, NULL,
1.8 jmcneill 1272: BUS_DMA_WAITOK)) != 0) {
1.12 nonaka 1273: aprint_error_dev(sc->sc_dev,
1.1 jmcneill 1274: "unable to load DMA map, error=%d\n", error);
1275: goto fail_load;
1276: }
1277:
1278: return 0;
1279:
1280: fail_load:
1281: bus_dmamap_destroy(sc->sc_dmat, *mapp);
1282: fail_create:
1283: bus_dmamem_unmap(sc->sc_dmat, *addrp, size);
1284: fail_map:
1285: bus_dmamem_free(sc->sc_dmat, seglist, nseg);
1286: fail_alloc:
1287: return error;
1288: }
CVSweb <webmaster@jp.NetBSD.org>