auacer.c revision 1.19 1 /* $NetBSD: auacer.c,v 1.19 2008/02/29 06:13:39 dyoung Exp $ */
2
3 /*-
4 * Copyright (c) 2004 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson.
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 * Acer Labs M5455 audio driver
41 *
42 * Acer provides data sheets after signing an NDA, so this is guess work.
43 * The chip behaves somewhat like the Intel i8x0, so this driver
44 * is loosely based on the auich driver. Additional information taken from
45 * the ALSA intel8x0.c driver (which handles M5455 as well).
46 *
47 * As an historical note one can observe that the auich driver borrows
48 * lot from the first NetBSD PCI audio driver, the eap driver. But this
49 * is not attributed anywhere.
50 */
51
52
53 #include <sys/cdefs.h>
54 __KERNEL_RCSID(0, "$NetBSD: auacer.c,v 1.19 2008/02/29 06:13:39 dyoung Exp $");
55
56 #include <sys/param.h>
57 #include <sys/systm.h>
58 #include <sys/kernel.h>
59 #include <sys/malloc.h>
60 #include <sys/device.h>
61 #include <sys/fcntl.h>
62 #include <sys/proc.h>
63
64 #include <uvm/uvm_extern.h> /* for PAGE_SIZE */
65
66 #include <dev/pci/pcidevs.h>
67 #include <dev/pci/pcivar.h>
68 #include <dev/pci/auacerreg.h>
69
70 #include <sys/audioio.h>
71 #include <dev/audio_if.h>
72 #include <dev/mulaw.h>
73 #include <dev/auconv.h>
74
75 #include <sys/bus.h>
76
77 #include <dev/ic/ac97reg.h>
78 #include <dev/ic/ac97var.h>
79
80 struct auacer_dma {
81 bus_dmamap_t map;
82 void *addr;
83 bus_dma_segment_t segs[1];
84 int nsegs;
85 size_t size;
86 struct auacer_dma *next;
87 };
88
89 #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
90 #define KERNADDR(p) ((void *)((p)->addr))
91
92 struct auacer_cdata {
93 struct auacer_dmalist ic_dmalist_pcmo[ALI_DMALIST_MAX];
94 };
95
96 struct auacer_chan {
97 uint32_t ptr;
98 uint32_t start, p, end;
99 uint32_t blksize, fifoe;
100 uint32_t ack;
101 uint32_t port;
102 struct auacer_dmalist *dmalist;
103 void (*intr)(void *);
104 void *arg;
105 };
106
107 struct auacer_softc {
108 struct device sc_dev;
109 void *sc_ih;
110
111 audio_device_t sc_audev;
112
113 bus_space_tag_t iot;
114 bus_space_handle_t mix_ioh;
115 bus_space_handle_t aud_ioh;
116 bus_dma_tag_t dmat;
117
118 struct ac97_codec_if *codec_if;
119 struct ac97_host_if host_if;
120
121 /* DMA scatter-gather lists. */
122 bus_dmamap_t sc_cddmamap;
123 #define sc_cddma sc_cddmamap->dm_segs[0].ds_addr
124
125 struct auacer_cdata *sc_cdata;
126
127 struct auacer_chan sc_pcmo;
128
129 struct auacer_dma *sc_dmas;
130
131 pci_chipset_tag_t sc_pc;
132 pcitag_t sc_pt;
133
134 int sc_dmamap_flags;
135
136 #define AUACER_NFORMATS 3
137 struct audio_format sc_formats[AUACER_NFORMATS];
138 struct audio_encoding_set *sc_encodings;
139 };
140
141 #define READ1(sc, a) bus_space_read_1(sc->iot, sc->aud_ioh, a)
142 #define READ2(sc, a) bus_space_read_2(sc->iot, sc->aud_ioh, a)
143 #define READ4(sc, a) bus_space_read_4(sc->iot, sc->aud_ioh, a)
144 #define WRITE1(sc, a, v) bus_space_write_1(sc->iot, sc->aud_ioh, a, v)
145 #define WRITE2(sc, a, v) bus_space_write_2(sc->iot, sc->aud_ioh, a, v)
146 #define WRITE4(sc, a, v) bus_space_write_4(sc->iot, sc->aud_ioh, a, v)
147
148 /* Debug */
149 #ifdef AUACER_DEBUG
150 #define DPRINTF(l,x) do { if (auacer_debug & (l)) printf x; } while(0)
151 int auacer_debug = 0;
152 #define ALI_DEBUG_CODECIO 0x0001
153 #define ALI_DEBUG_DMA 0x0002
154 #define ALI_DEBUG_INTR 0x0004
155 #define ALI_DEBUG_API 0x0008
156 #define ALI_DEBUG_MIXERAPI 0x0010
157 #else
158 #define DPRINTF(x,y) /* nothing */
159 #endif
160
161 static int auacer_intr(void *);
162
163 static int auacer_query_encoding(void *, struct audio_encoding *);
164 static int auacer_set_params(void *, int, int, audio_params_t *,
165 audio_params_t *, stream_filter_list_t *,
166 stream_filter_list_t *);
167 static int auacer_round_blocksize(void *, int, int,
168 const audio_params_t *);
169 static int auacer_halt_output(void *);
170 static int auacer_halt_input(void *);
171 static int auacer_getdev(void *, struct audio_device *);
172 static int auacer_set_port(void *, mixer_ctrl_t *);
173 static int auacer_get_port(void *, mixer_ctrl_t *);
174 static int auacer_query_devinfo(void *, mixer_devinfo_t *);
175 static void *auacer_allocm(void *, int, size_t, struct malloc_type *, int);
176 static void auacer_freem(void *, void *, struct malloc_type *);
177 static size_t auacer_round_buffersize(void *, int, size_t);
178 static paddr_t auacer_mappage(void *, void *, off_t, int);
179 static int auacer_get_props(void *);
180 static int auacer_trigger_output(void *, void *, void *, int,
181 void (*)(void *), void *,
182 const audio_params_t *);
183 static int auacer_trigger_input(void *, void *, void *, int,
184 void (*)(void *), void *,
185 const audio_params_t *);
186
187 static int auacer_alloc_cdata(struct auacer_softc *);
188
189 static int auacer_allocmem(struct auacer_softc *, size_t, size_t,
190 struct auacer_dma *);
191 static int auacer_freemem(struct auacer_softc *, struct auacer_dma *);
192
193 static bool auacer_resume(device_t PMF_FN_PROTO);
194 static int auacer_set_rate(struct auacer_softc *, int, u_int);
195
196 static void auacer_reset(struct auacer_softc *sc);
197
198 static struct audio_hw_if auacer_hw_if = {
199 NULL, /* open */
200 NULL, /* close */
201 NULL, /* drain */
202 auacer_query_encoding,
203 auacer_set_params,
204 auacer_round_blocksize,
205 NULL, /* commit_setting */
206 NULL, /* init_output */
207 NULL, /* init_input */
208 NULL, /* start_output */
209 NULL, /* start_input */
210 auacer_halt_output,
211 auacer_halt_input,
212 NULL, /* speaker_ctl */
213 auacer_getdev,
214 NULL, /* getfd */
215 auacer_set_port,
216 auacer_get_port,
217 auacer_query_devinfo,
218 auacer_allocm,
219 auacer_freem,
220 auacer_round_buffersize,
221 auacer_mappage,
222 auacer_get_props,
223 auacer_trigger_output,
224 auacer_trigger_input,
225 NULL, /* dev_ioctl */
226 NULL, /* powerstate */
227 };
228
229 #define AUACER_FORMATS_4CH 1
230 #define AUACER_FORMATS_6CH 2
231 static const struct audio_format auacer_formats[AUACER_NFORMATS] = {
232 {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
233 2, AUFMT_STEREO, 0, {8000, 48000}},
234 {NULL, AUMODE_PLAY, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
235 4, AUFMT_SURROUND4, 0, {8000, 48000}},
236 {NULL, AUMODE_PLAY, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
237 6, AUFMT_DOLBY_5_1, 0, {8000, 48000}},
238 };
239
240 static int auacer_attach_codec(void *, struct ac97_codec_if *);
241 static int auacer_read_codec(void *, uint8_t, uint16_t *);
242 static int auacer_write_codec(void *, uint8_t, uint16_t);
243 static int auacer_reset_codec(void *);
244
245 static int
246 auacer_match(struct device *parent, struct cfdata *match,
247 void *aux)
248 {
249 struct pci_attach_args *pa;
250
251 pa = (struct pci_attach_args *)aux;
252 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ALI &&
253 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ALI_M5455)
254 return 1;
255 return 0;
256 }
257
258 static void
259 auacer_attach(struct device *parent, struct device *self, void *aux)
260 {
261 struct auacer_softc *sc;
262 struct pci_attach_args *pa;
263 pci_intr_handle_t ih;
264 bus_size_t aud_size;
265 pcireg_t v;
266 const char *intrstr;
267 int i;
268
269 sc = (struct auacer_softc *)self;
270 pa = aux;
271 aprint_normal(": Acer Labs M5455 Audio controller\n");
272
273 if (pci_mapreg_map(pa, 0x10, PCI_MAPREG_TYPE_IO, 0, &sc->iot,
274 &sc->aud_ioh, NULL, &aud_size)) {
275 aprint_error(": can't map i/o space\n");
276 return;
277 }
278
279 sc->sc_pc = pa->pa_pc;
280 sc->sc_pt = pa->pa_tag;
281 sc->dmat = pa->pa_dmat;
282
283 sc->sc_dmamap_flags = BUS_DMA_COHERENT; /* XXX remove */
284
285 /* enable bus mastering */
286 v = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
287 pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
288 v | PCI_COMMAND_MASTER_ENABLE);
289
290 /* Map and establish the interrupt. */
291 if (pci_intr_map(pa, &ih)) {
292 aprint_error("%s: can't map interrupt\n", sc->sc_dev.dv_xname);
293 return;
294 }
295 intrstr = pci_intr_string(pa->pa_pc, ih);
296 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_AUDIO,
297 auacer_intr, sc);
298 if (sc->sc_ih == NULL) {
299 aprint_error("%s: can't establish interrupt",
300 sc->sc_dev.dv_xname);
301 if (intrstr != NULL)
302 aprint_normal(" at %s", intrstr);
303 aprint_normal("\n");
304 return;
305 }
306 aprint_normal("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
307
308 strlcpy(sc->sc_audev.name, "M5455 AC97", MAX_AUDIO_DEV_LEN);
309 snprintf(sc->sc_audev.version, MAX_AUDIO_DEV_LEN,
310 "0x%02x", PCI_REVISION(pa->pa_class));
311 strlcpy(sc->sc_audev.config, sc->sc_dev.dv_xname, MAX_AUDIO_DEV_LEN);
312
313 /* Set up DMA lists. */
314 auacer_alloc_cdata(sc);
315 sc->sc_pcmo.dmalist = sc->sc_cdata->ic_dmalist_pcmo;
316 sc->sc_pcmo.ptr = 0;
317 sc->sc_pcmo.port = ALI_BASE_PO;
318
319 DPRINTF(ALI_DEBUG_DMA, ("auacer_attach: lists %p\n",
320 sc->sc_pcmo.dmalist));
321
322 sc->host_if.arg = sc;
323 sc->host_if.attach = auacer_attach_codec;
324 sc->host_if.read = auacer_read_codec;
325 sc->host_if.write = auacer_write_codec;
326 sc->host_if.reset = auacer_reset_codec;
327
328 if (ac97_attach(&sc->host_if, self) != 0)
329 return;
330
331 /* setup audio_format */
332 memcpy(sc->sc_formats, auacer_formats, sizeof(auacer_formats));
333 if (!AC97_IS_4CH(sc->codec_if))
334 AUFMT_INVALIDATE(&sc->sc_formats[AUACER_FORMATS_4CH]);
335 if (!AC97_IS_6CH(sc->codec_if))
336 AUFMT_INVALIDATE(&sc->sc_formats[AUACER_FORMATS_6CH]);
337 if (AC97_IS_FIXED_RATE(sc->codec_if)) {
338 for (i = 0; i < AUACER_NFORMATS; i++) {
339 sc->sc_formats[i].frequency_type = 1;
340 sc->sc_formats[i].frequency[0] = 48000;
341 }
342 }
343
344 if (0 != auconv_create_encodings(sc->sc_formats, AUACER_NFORMATS,
345 &sc->sc_encodings)) {
346 return;
347 }
348
349 audio_attach_mi(&auacer_hw_if, sc, &sc->sc_dev);
350
351 auacer_reset(sc);
352
353 if (!pmf_device_register(self, NULL, auacer_resume))
354 aprint_error_dev(self, "couldn't establish power handler\n");
355 }
356
357 CFATTACH_DECL(auacer, sizeof(struct auacer_softc),
358 auacer_match, auacer_attach, NULL, NULL);
359
360 static int
361 auacer_ready_codec(struct auacer_softc *sc, int mask)
362 {
363 int count;
364
365 for (count = 0; count < 0x7f; count++) {
366 int val = READ1(sc, ALI_CSPSR);
367 if (val & mask)
368 return 0;
369 }
370
371 aprint_normal("auacer_ready_codec: AC97 codec ready timeout.\n");
372 return EBUSY;
373 }
374
375 static int
376 auacer_sema_codec(struct auacer_softc *sc)
377 {
378 int ttime;
379
380 ttime = 100;
381 while (ttime-- && (READ4(sc, ALI_CAS) & ALI_CAS_SEM_BUSY))
382 delay(1);
383 if (!ttime)
384 aprint_normal("auacer_sema_codec: timeout\n");
385 return auacer_ready_codec(sc, ALI_CSPSR_CODEC_READY);
386 }
387
388 static int
389 auacer_read_codec(void *v, uint8_t reg, uint16_t *val)
390 {
391 struct auacer_softc *sc;
392
393 sc = v;
394 if (auacer_sema_codec(sc))
395 return EIO;
396
397 reg |= ALI_CPR_ADDR_READ;
398 #if 0
399 if (ac97->num)
400 reg |= ALI_CPR_ADDR_SECONDARY;
401 #endif
402 WRITE2(sc, ALI_CPR_ADDR, reg);
403 if (auacer_ready_codec(sc, ALI_CSPSR_READ_OK))
404 return EIO;
405 *val = READ2(sc, ALI_SPR);
406
407 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_read_codec: reg=0x%x val=0x%x\n",
408 reg, *val));
409
410 return 0;
411 }
412
413 int
414 auacer_write_codec(void *v, uint8_t reg, uint16_t val)
415 {
416 struct auacer_softc *sc;
417
418 DPRINTF(ALI_DEBUG_CODECIO, ("auacer_write_codec: reg=0x%x val=0x%x\n",
419 reg, val));
420 sc = v;
421 if (auacer_sema_codec(sc))
422 return EIO;
423 WRITE2(sc, ALI_CPR, val);
424 #if 0
425 if (ac97->num)
426 reg |= ALI_CPR_ADDR_SECONDARY;
427 #endif
428 WRITE2(sc, ALI_CPR_ADDR, reg);
429 auacer_ready_codec(sc, ALI_CSPSR_WRITE_OK);
430 return 0;
431 }
432
433 static int
434 auacer_attach_codec(void *v, struct ac97_codec_if *cif)
435 {
436 struct auacer_softc *sc;
437
438 sc = v;
439 sc->codec_if = cif;
440 return 0;
441 }
442
443 static int
444 auacer_reset_codec(void *v)
445 {
446 struct auacer_softc *sc;
447 uint32_t reg;
448 int i;
449
450 sc = v;
451 i = 0;
452 reg = READ4(sc, ALI_SCR);
453 if ((reg & 2) == 0) /* Cold required */
454 reg |= 2;
455 else
456 reg |= 1; /* Warm */
457 reg &= ~0x80000000; /* ACLink on */
458 WRITE4(sc, ALI_SCR, reg);
459
460 while (i < 10) {
461 if ((READ4(sc, ALI_INTERRUPTSR) & ALI_INT_GPIO) == 0)
462 break;
463 delay(50000); /* XXX */
464 i++;
465 }
466 if (i == 10) {
467 return EIO;
468 }
469
470 for (i = 0; i < 10; i++) {
471 reg = READ4(sc, ALI_RTSR);
472 if (reg & 0x80) /* primary codec */
473 break;
474 WRITE4(sc, ALI_RTSR, reg | 0x80);
475 delay(50000); /* XXX */
476 }
477
478 return 0;
479 }
480
481 static void
482 auacer_reset(struct auacer_softc *sc)
483 {
484 WRITE4(sc, ALI_SCR, ALI_SCR_RESET);
485 WRITE4(sc, ALI_FIFOCR1, 0x83838383);
486 WRITE4(sc, ALI_FIFOCR2, 0x83838383);
487 WRITE4(sc, ALI_FIFOCR3, 0x83838383);
488 WRITE4(sc, ALI_INTERFACECR, ALI_IF_PO); /* XXX pcm out only */
489 WRITE4(sc, ALI_INTERRUPTCR, 0x00000000);
490 WRITE4(sc, ALI_INTERRUPTSR, 0x00000000);
491 }
492
493 static int
494 auacer_query_encoding(void *v, struct audio_encoding *aep)
495 {
496 struct auacer_softc *sc;
497
498 DPRINTF(ALI_DEBUG_API, ("auacer_query_encoding\n"));
499 sc = v;
500 return auconv_query_encoding(sc->sc_encodings, aep);
501 }
502
503 static int
504 auacer_set_rate(struct auacer_softc *sc, int mode, u_int srate)
505 {
506 int ret;
507 u_int ratetmp;
508
509 DPRINTF(ALI_DEBUG_API, ("auacer_set_rate: srate=%u\n", srate));
510
511 ratetmp = srate;
512 if (mode == AUMODE_RECORD)
513 return sc->codec_if->vtbl->set_rate(sc->codec_if,
514 AC97_REG_PCM_LR_ADC_RATE, &ratetmp);
515 ret = sc->codec_if->vtbl->set_rate(sc->codec_if,
516 AC97_REG_PCM_FRONT_DAC_RATE, &ratetmp);
517 if (ret)
518 return ret;
519 ratetmp = srate;
520 ret = sc->codec_if->vtbl->set_rate(sc->codec_if,
521 AC97_REG_PCM_SURR_DAC_RATE, &ratetmp);
522 if (ret)
523 return ret;
524 ratetmp = srate;
525 ret = sc->codec_if->vtbl->set_rate(sc->codec_if,
526 AC97_REG_PCM_LFE_DAC_RATE, &ratetmp);
527 return ret;
528 }
529
530 static int
531 auacer_set_params(void *v, int setmode, int usemode,
532 audio_params_t *play, audio_params_t *rec, stream_filter_list_t *pfil,
533 stream_filter_list_t *rfil)
534 {
535 struct auacer_softc *sc;
536 struct audio_params *p;
537 stream_filter_list_t *fil;
538 uint32_t control;
539 int mode, index;
540
541 DPRINTF(ALI_DEBUG_API, ("auacer_set_params\n"));
542 sc = v;
543 for (mode = AUMODE_RECORD; mode != -1;
544 mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
545 if ((setmode & mode) == 0)
546 continue;
547
548 p = mode == AUMODE_PLAY ? play : rec;
549 if (p == NULL)
550 continue;
551
552 if ((p->sample_rate != 8000) &&
553 (p->sample_rate != 11025) &&
554 (p->sample_rate != 12000) &&
555 (p->sample_rate != 16000) &&
556 (p->sample_rate != 22050) &&
557 (p->sample_rate != 24000) &&
558 (p->sample_rate != 32000) &&
559 (p->sample_rate != 44100) &&
560 (p->sample_rate != 48000))
561 return (EINVAL);
562
563 fil = mode == AUMODE_PLAY ? pfil : rfil;
564 index = auconv_set_converter(sc->sc_formats, AUACER_NFORMATS,
565 mode, p, TRUE, fil);
566 if (index < 0)
567 return EINVAL;
568 if (fil->req_size > 0)
569 p = &fil->filters[0].param;
570 /* p points HW encoding */
571 if (sc->sc_formats[index].frequency_type != 1
572 && auacer_set_rate(sc, mode, p->sample_rate))
573 return EINVAL;
574 if (mode == AUMODE_PLAY) {
575 control = READ4(sc, ALI_SCR);
576 control &= ~ALI_SCR_PCM_246_MASK;
577 if (p->channels == 4)
578 control |= ALI_SCR_PCM_4;
579 else if (p->channels == 6)
580 control |= ALI_SCR_PCM_6;
581 WRITE4(sc, ALI_SCR, control);
582 }
583 }
584
585 return (0);
586 }
587
588 static int
589 auacer_round_blocksize(void *v, int blk, int mode,
590 const audio_params_t *param)
591 {
592
593 return blk & ~0x3f; /* keep good alignment */
594 }
595
596 static void
597 auacer_halt(struct auacer_softc *sc, struct auacer_chan *chan)
598 {
599 uint32_t val;
600 uint8_t port;
601 uint32_t slot;
602
603 port = chan->port;
604 DPRINTF(ALI_DEBUG_API, ("auacer_halt: port=0x%x\n", port));
605 chan->intr = 0;
606
607 slot = ALI_PORT2SLOT(port);
608
609 val = READ4(sc, ALI_DMACR);
610 val |= 1 << (slot+16); /* pause */
611 val &= ~(1 << slot); /* no start */
612 WRITE4(sc, ALI_DMACR, val);
613 WRITE1(sc, port + ALI_OFF_CR, 0);
614 while (READ1(sc, port + ALI_OFF_CR))
615 ;
616 /* reset whole DMA things */
617 WRITE1(sc, port + ALI_OFF_CR, ALI_CR_RR);
618 /* clear interrupts */
619 WRITE1(sc, port + ALI_OFF_SR, READ1(sc, port+ALI_OFF_SR) | ALI_SR_W1TC);
620 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(port));
621 }
622
623 static int
624 auacer_halt_output(void *v)
625 {
626 struct auacer_softc *sc;
627
628 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_output\n"));
629 sc = v;
630 auacer_halt(sc, &sc->sc_pcmo);
631
632 return 0;
633 }
634
635 static int
636 auacer_halt_input(void *v)
637 {
638 DPRINTF(ALI_DEBUG_DMA, ("auacer_halt_input\n"));
639
640 return 0;
641 }
642
643 static int
644 auacer_getdev(void *v, struct audio_device *adp)
645 {
646 struct auacer_softc *sc;
647
648 DPRINTF(ALI_DEBUG_API, ("auacer_getdev\n"));
649 sc = v;
650 *adp = sc->sc_audev;
651 return 0;
652 }
653
654 static int
655 auacer_set_port(void *v, mixer_ctrl_t *cp)
656 {
657 struct auacer_softc *sc;
658
659 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_set_port\n"));
660 sc = v;
661 return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
662 }
663
664 static int
665 auacer_get_port(void *v, mixer_ctrl_t *cp)
666 {
667 struct auacer_softc *sc;
668
669 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_get_port\n"));
670 sc = v;
671 return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
672 }
673
674 static int
675 auacer_query_devinfo(void *v, mixer_devinfo_t *dp)
676 {
677 struct auacer_softc *sc;
678
679 DPRINTF(ALI_DEBUG_MIXERAPI, ("auacer_query_devinfo\n"));
680 sc = v;
681 return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dp);
682 }
683
684 static void *
685 auacer_allocm(void *v, int direction, size_t size,
686 struct malloc_type *pool, int flags)
687 {
688 struct auacer_softc *sc;
689 struct auacer_dma *p;
690 int error;
691
692 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX))
693 return NULL;
694
695 p = malloc(sizeof(*p), pool, flags | M_ZERO);
696 if (p == NULL)
697 return NULL;
698 sc = v;
699 error = auacer_allocmem(sc, size, 0, p);
700 if (error) {
701 free(p, pool);
702 return NULL;
703 }
704
705 p->next = sc->sc_dmas;
706 sc->sc_dmas = p;
707
708 return KERNADDR(p);
709 }
710
711 static void
712 auacer_freem(void *v, void *ptr, struct malloc_type *pool)
713 {
714 struct auacer_softc *sc;
715 struct auacer_dma *p, **pp;
716
717 sc = v;
718 for (pp = &sc->sc_dmas; (p = *pp) != NULL; pp = &p->next) {
719 if (KERNADDR(p) == ptr) {
720 auacer_freemem(sc, p);
721 *pp = p->next;
722 free(p, pool);
723 return;
724 }
725 }
726 }
727
728 static size_t
729 auacer_round_buffersize(void *v, int direction, size_t size)
730 {
731
732 if (size > (ALI_DMALIST_MAX * ALI_DMASEG_MAX))
733 size = ALI_DMALIST_MAX * ALI_DMASEG_MAX;
734
735 return size;
736 }
737
738 static paddr_t
739 auacer_mappage(void *v, void *mem, off_t off, int prot)
740 {
741 struct auacer_softc *sc;
742 struct auacer_dma *p;
743
744 if (off < 0)
745 return -1;
746 sc = v;
747 for (p = sc->sc_dmas; p && KERNADDR(p) != mem; p = p->next)
748 continue;
749 if (p == NULL)
750 return -1;
751 return bus_dmamem_mmap(sc->dmat, p->segs, p->nsegs,
752 off, prot, BUS_DMA_WAITOK);
753 }
754
755 static int
756 auacer_get_props(void *v)
757 {
758 struct auacer_softc *sc;
759 int props;
760
761 sc = v;
762 props = AUDIO_PROP_INDEPENDENT | AUDIO_PROP_FULLDUPLEX;
763 /*
764 * Even if the codec is fixed-rate, set_param() succeeds for any sample
765 * rate because of aurateconv. Applications can't know what rate the
766 * device can process in the case of mmap().
767 */
768 if (!AC97_IS_FIXED_RATE(sc->codec_if))
769 props |= AUDIO_PROP_MMAP;
770 return props;
771 }
772
773 static void
774 auacer_add_entry(struct auacer_chan *chan)
775 {
776 struct auacer_dmalist *q;
777
778 q = &chan->dmalist[chan->ptr];
779
780 DPRINTF(ALI_DEBUG_INTR,
781 ("auacer_add_entry: %p = %x @ 0x%x\n",
782 q, chan->blksize / 2, chan->p));
783
784 q->base = htole32(chan->p);
785 q->len = htole32((chan->blksize / ALI_SAMPLE_SIZE) | ALI_DMAF_IOC);
786 chan->p += chan->blksize;
787 if (chan->p >= chan->end)
788 chan->p = chan->start;
789
790 if (++chan->ptr >= ALI_DMALIST_MAX)
791 chan->ptr = 0;
792 }
793
794 static void
795 auacer_upd_chan(struct auacer_softc *sc, struct auacer_chan *chan)
796 {
797 uint32_t sts;
798 uint32_t civ;
799
800 sts = READ2(sc, chan->port + ALI_OFF_SR);
801 /* intr ack */
802 WRITE2(sc, chan->port + ALI_OFF_SR, sts & ALI_SR_W1TC);
803 WRITE4(sc, ALI_INTERRUPTSR, ALI_PORT2INTR(chan->port));
804
805 DPRINTF(ALI_DEBUG_INTR, ("auacer_upd_chan: sts=0x%x\n", sts));
806
807 if (sts & ALI_SR_DMA_INT_FIFO) {
808 printf("%s: fifo underrun # %u\n",
809 sc->sc_dev.dv_xname, ++chan->fifoe);
810 }
811
812 civ = READ1(sc, chan->port + ALI_OFF_CIV);
813
814 DPRINTF(ALI_DEBUG_INTR,("auacer_intr: civ=%u ptr=%u\n",civ,chan->ptr));
815
816 /* XXX */
817 while (chan->ptr != civ) {
818 auacer_add_entry(chan);
819 }
820
821 WRITE1(sc, chan->port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK);
822
823 while (chan->ack != civ) {
824 if (chan->intr) {
825 DPRINTF(ALI_DEBUG_INTR,("auacer_upd_chan: callback\n"));
826 chan->intr(chan->arg);
827 }
828 chan->ack++;
829 if (chan->ack >= ALI_DMALIST_MAX)
830 chan->ack = 0;
831 }
832 }
833
834 static int
835 auacer_intr(void *v)
836 {
837 struct auacer_softc *sc;
838 int ret, intrs;
839
840 sc = v;
841 intrs = READ4(sc, ALI_INTERRUPTSR);
842 DPRINTF(ALI_DEBUG_INTR, ("auacer_intr: intrs=0x%x\n", intrs));
843
844 ret = 0;
845 if (intrs & ALI_INT_PCMOUT) {
846 auacer_upd_chan(sc, &sc->sc_pcmo);
847 ret++;
848 }
849
850 return ret != 0;
851 }
852
853 static void
854 auacer_setup_chan(struct auacer_softc *sc, struct auacer_chan *chan,
855 uint32_t start, uint32_t size, uint32_t blksize,
856 void (*intr)(void *), void *arg)
857 {
858 uint32_t port, slot;
859 uint32_t offs, val;
860
861 chan->start = start;
862 chan->ptr = 0;
863 chan->p = chan->start;
864 chan->end = chan->start + size;
865 chan->blksize = blksize;
866 chan->ack = 0;
867 chan->intr = intr;
868 chan->arg = arg;
869
870 auacer_add_entry(chan);
871 auacer_add_entry(chan);
872
873 port = chan->port;
874 slot = ALI_PORT2SLOT(port);
875
876 WRITE1(sc, port + ALI_OFF_CIV, 0);
877 WRITE1(sc, port + ALI_OFF_LVI, (chan->ptr - 1) & ALI_LVI_MASK);
878 offs = (char *)chan->dmalist - (char *)sc->sc_cdata;
879 WRITE4(sc, port + ALI_OFF_BDBAR, sc->sc_cddma + offs);
880 WRITE1(sc, port + ALI_OFF_CR,
881 ALI_CR_IOCE | ALI_CR_FEIE | ALI_CR_LVBIE | ALI_CR_RPBM);
882 val = READ4(sc, ALI_DMACR);
883 val &= ~(1 << (slot+16)); /* no pause */
884 val |= 1 << slot; /* start */
885 WRITE4(sc, ALI_DMACR, val);
886 }
887
888 static int
889 auacer_trigger_output(void *v, void *start, void *end, int blksize,
890 void (*intr)(void *), void *arg, const audio_params_t *param)
891 {
892 struct auacer_softc *sc;
893 struct auacer_dma *p;
894 uint32_t size;
895
896 DPRINTF(ALI_DEBUG_DMA,
897 ("auacer_trigger_output(%p, %p, %d, %p, %p, %p)\n",
898 start, end, blksize, intr, arg, param));
899 sc = v;
900 for (p = sc->sc_dmas; p && KERNADDR(p) != start; p = p->next)
901 continue;
902 if (!p) {
903 printf("auacer_trigger_output: bad addr %p\n", start);
904 return (EINVAL);
905 }
906
907 size = (char *)end - (char *)start;
908 auacer_setup_chan(sc, &sc->sc_pcmo, DMAADDR(p), size, blksize,
909 intr, arg);
910
911 return 0;
912 }
913
914 static int
915 auacer_trigger_input(void *v, void *start, void *end,
916 int blksize, void (*intr)(void *), void *arg,
917 const audio_params_t *param)
918 {
919 return EINVAL;
920 }
921
922 static int
923 auacer_allocmem(struct auacer_softc *sc, size_t size, size_t align,
924 struct auacer_dma *p)
925 {
926 int error;
927
928 p->size = size;
929 error = bus_dmamem_alloc(sc->dmat, p->size, align, 0,
930 p->segs, sizeof(p->segs)/sizeof(p->segs[0]),
931 &p->nsegs, BUS_DMA_NOWAIT);
932 if (error)
933 return error;
934
935 error = bus_dmamem_map(sc->dmat, p->segs, p->nsegs, p->size,
936 &p->addr, BUS_DMA_NOWAIT|sc->sc_dmamap_flags);
937 if (error)
938 goto free;
939
940 error = bus_dmamap_create(sc->dmat, p->size, 1, p->size,
941 0, BUS_DMA_NOWAIT, &p->map);
942 if (error)
943 goto unmap;
944
945 error = bus_dmamap_load(sc->dmat, p->map, p->addr, p->size, NULL,
946 BUS_DMA_NOWAIT);
947 if (error)
948 goto destroy;
949 return (0);
950
951 destroy:
952 bus_dmamap_destroy(sc->dmat, p->map);
953 unmap:
954 bus_dmamem_unmap(sc->dmat, p->addr, p->size);
955 free:
956 bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
957 return error;
958 }
959
960 static int
961 auacer_freemem(struct auacer_softc *sc, struct auacer_dma *p)
962 {
963
964 bus_dmamap_unload(sc->dmat, p->map);
965 bus_dmamap_destroy(sc->dmat, p->map);
966 bus_dmamem_unmap(sc->dmat, p->addr, p->size);
967 bus_dmamem_free(sc->dmat, p->segs, p->nsegs);
968 return 0;
969 }
970
971 static int
972 auacer_alloc_cdata(struct auacer_softc *sc)
973 {
974 bus_dma_segment_t seg;
975 int error, rseg;
976
977 /*
978 * Allocate the control data structure, and create and load the
979 * DMA map for it.
980 */
981 if ((error = bus_dmamem_alloc(sc->dmat,
982 sizeof(struct auacer_cdata),
983 PAGE_SIZE, 0, &seg, 1, &rseg, 0)) != 0) {
984 printf("%s: unable to allocate control data, error = %d\n",
985 sc->sc_dev.dv_xname, error);
986 goto fail_0;
987 }
988
989 if ((error = bus_dmamem_map(sc->dmat, &seg, rseg,
990 sizeof(struct auacer_cdata),
991 (void **) &sc->sc_cdata,
992 sc->sc_dmamap_flags)) != 0) {
993 printf("%s: unable to map control data, error = %d\n",
994 sc->sc_dev.dv_xname, error);
995 goto fail_1;
996 }
997
998 if ((error = bus_dmamap_create(sc->dmat, sizeof(struct auacer_cdata), 1,
999 sizeof(struct auacer_cdata), 0, 0,
1000 &sc->sc_cddmamap)) != 0) {
1001 printf("%s: unable to create control data DMA map, "
1002 "error = %d\n", sc->sc_dev.dv_xname, error);
1003 goto fail_2;
1004 }
1005
1006 if ((error = bus_dmamap_load(sc->dmat, sc->sc_cddmamap,
1007 sc->sc_cdata, sizeof(struct auacer_cdata),
1008 NULL, 0)) != 0) {
1009 printf("%s: unable to load control data DMA map, "
1010 "error = %d\n", sc->sc_dev.dv_xname, error);
1011 goto fail_3;
1012 }
1013
1014 return 0;
1015
1016 fail_3:
1017 bus_dmamap_destroy(sc->dmat, sc->sc_cddmamap);
1018 fail_2:
1019 bus_dmamem_unmap(sc->dmat, (void *) sc->sc_cdata,
1020 sizeof(struct auacer_cdata));
1021 fail_1:
1022 bus_dmamem_free(sc->dmat, &seg, rseg);
1023 fail_0:
1024 return error;
1025 }
1026
1027 static bool
1028 auacer_resume(device_t dv PMF_FN_ARGS)
1029 {
1030 struct auacer_softc *sc = device_private(dv);
1031
1032 auacer_reset_codec(sc);
1033 delay(1000);
1034 sc->codec_if->vtbl->restore_ports(sc->codec_if);
1035
1036 return true;
1037 }
1038