1 /* $NetBSD: auacer.c,v 1.25 2009/11/26 15:17:08 njoly Exp $ */
4 * Copyright (c) 2004 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Acer Labs M5455 audio driver
35 * Acer provides data sheets after signing an NDA, so this is guess work.
36 * The chip behaves somewhat like the Intel i8x0, so this driver
37 * is loosely based on the auich driver. Additional information taken from
38 * the ALSA intel8x0.c driver (which handles M5455 as well).
40 * As an historical note one can observe that the auich driver borrows
41 * lot from the first NetBSD PCI audio driver, the eap driver. But this
42 * is not attributed anywhere.
46 #include <sys/cdefs.h>
47 __KERNEL_RCSID(0, "$NetBSD: auacer.c,v 1.25 2009/11/26 15:17:08 njoly Exp $");
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/kernel.h>
52 #include <sys/malloc.h>
53 #include <sys/device.h>
54 #include <sys/fcntl.h>
57 #include <uvm/uvm_extern.h> /* for PAGE_SIZE */
59 #include <dev/pci/pcidevs.h>
60 #include <dev/pci/pcivar.h>
61 #include <dev/pci/auacerreg.h>
63 #include <sys/audioio.h>
64 #include <dev/audio_if.h>
65 #include <dev/mulaw.h>
66 #include <dev/auconv.h>
70 #include <dev/ic/ac97reg.h>
71 #include <dev/ic/ac97var.h>
76 bus_dma_segment_t segs
[1];
79 struct auacer_dma
*next
;
82 #define DMAADDR(p) ((p)->map->dm_segs[0].ds_addr)
83 #define KERNADDR(p) ((void *)((p)->addr))
86 struct auacer_dmalist ic_dmalist_pcmo
[ALI_DMALIST_MAX
];
91 uint32_t start
, p
, end
;
92 uint32_t blksize
, fifoe
;
95 struct auacer_dmalist
*dmalist
;
100 struct auacer_softc
{
101 struct device sc_dev
;
104 audio_device_t sc_audev
;
107 bus_space_handle_t mix_ioh
;
108 bus_space_handle_t aud_ioh
;
111 struct ac97_codec_if
*codec_if
;
112 struct ac97_host_if host_if
;
114 /* DMA scatter-gather lists. */
115 bus_dmamap_t sc_cddmamap
;
116 #define sc_cddma sc_cddmamap->dm_segs[0].ds_addr
118 struct auacer_cdata
*sc_cdata
;
120 struct auacer_chan sc_pcmo
;
122 struct auacer_dma
*sc_dmas
;
124 pci_chipset_tag_t sc_pc
;
129 #define AUACER_NFORMATS 3
130 struct audio_format sc_formats
[AUACER_NFORMATS
];
131 struct audio_encoding_set
*sc_encodings
;
134 #define READ1(sc, a) bus_space_read_1(sc->iot, sc->aud_ioh, a)
135 #define READ2(sc, a) bus_space_read_2(sc->iot, sc->aud_ioh, a)
136 #define READ4(sc, a) bus_space_read_4(sc->iot, sc->aud_ioh, a)
137 #define WRITE1(sc, a, v) bus_space_write_1(sc->iot, sc->aud_ioh, a, v)
138 #define WRITE2(sc, a, v) bus_space_write_2(sc->iot, sc->aud_ioh, a, v)
139 #define WRITE4(sc, a, v) bus_space_write_4(sc->iot, sc->aud_ioh, a, v)
143 #define DPRINTF(l,x) do { if (auacer_debug & (l)) printf x; } while(0)
144 int auacer_debug
= 0;
145 #define ALI_DEBUG_CODECIO 0x0001
146 #define ALI_DEBUG_DMA 0x0002
147 #define ALI_DEBUG_INTR 0x0004
148 #define ALI_DEBUG_API 0x0008
149 #define ALI_DEBUG_MIXERAPI 0x0010
151 #define DPRINTF(x,y) /* nothing */
154 static int auacer_intr(void *);
156 static int auacer_query_encoding(void *, struct audio_encoding
*);
157 static int auacer_set_params(void *, int, int, audio_params_t
*,
158 audio_params_t
*, stream_filter_list_t
*,
159 stream_filter_list_t
*);
160 static int auacer_round_blocksize(void *, int, int,
161 const audio_params_t
*);
162 static int auacer_halt_output(void *);
163 static int auacer_halt_input(void *);
164 static int auacer_getdev(void *, struct audio_device
*);
165 static int auacer_set_port(void *, mixer_ctrl_t
*);
166 static int auacer_get_port(void *, mixer_ctrl_t
*);
167 static int auacer_query_devinfo(void *, mixer_devinfo_t
*);
168 static void *auacer_allocm(void *, int, size_t, struct malloc_type
*, int);
169 static void auacer_freem(void *, void *, struct malloc_type
*);
170 static size_t auacer_round_buffersize(void *, int, size_t);
171 static paddr_t
auacer_mappage(void *, void *, off_t
, int);
172 static int auacer_get_props(void *);
173 static int auacer_trigger_output(void *, void *, void *, int,
174 void (*)(void *), void *,
175 const audio_params_t
*);
176 static int auacer_trigger_input(void *, void *, void *, int,
177 void (*)(void *), void *,
178 const audio_params_t
*);
180 static int auacer_alloc_cdata(struct auacer_softc
*);
182 static int auacer_allocmem(struct auacer_softc
*, size_t, size_t,
183 struct auacer_dma
*);
184 static int auacer_freemem(struct auacer_softc
*, struct auacer_dma
*);
186 static bool auacer_resume(device_t
, pmf_qual_t
);
187 static int auacer_set_rate(struct auacer_softc
*, int, u_int
);
189 static void auacer_reset(struct auacer_softc
*sc
);
191 static struct audio_hw_if auacer_hw_if
= {
195 auacer_query_encoding
,
197 auacer_round_blocksize
,
198 NULL
, /* commit_setting */
199 NULL
, /* init_output */
200 NULL
, /* init_input */
201 NULL
, /* start_output */
202 NULL
, /* start_input */
205 NULL
, /* speaker_ctl */
210 auacer_query_devinfo
,
213 auacer_round_buffersize
,
216 auacer_trigger_output
,
217 auacer_trigger_input
,
218 NULL
, /* dev_ioctl */
219 NULL
, /* powerstate */
222 #define AUACER_FORMATS_4CH 1
223 #define AUACER_FORMATS_6CH 2
224 static const struct audio_format auacer_formats
[AUACER_NFORMATS
] = {
225 {NULL
, AUMODE_PLAY
| AUMODE_RECORD
, AUDIO_ENCODING_SLINEAR_LE
, 16, 16,
226 2, AUFMT_STEREO
, 0, {8000, 48000}},
227 {NULL
, AUMODE_PLAY
, AUDIO_ENCODING_SLINEAR_LE
, 16, 16,
228 4, AUFMT_SURROUND4
, 0, {8000, 48000}},
229 {NULL
, AUMODE_PLAY
, AUDIO_ENCODING_SLINEAR_LE
, 16, 16,
230 6, AUFMT_DOLBY_5_1
, 0, {8000, 48000}},
233 static int auacer_attach_codec(void *, struct ac97_codec_if
*);
234 static int auacer_read_codec(void *, uint8_t, uint16_t *);
235 static int auacer_write_codec(void *, uint8_t, uint16_t);
236 static int auacer_reset_codec(void *);
239 auacer_match(device_t parent
, cfdata_t match
, void *aux
)
241 struct pci_attach_args
*pa
;
243 pa
= (struct pci_attach_args
*)aux
;
244 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_ALI
&&
245 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_ALI_M5455
)
251 auacer_attach(device_t parent
, device_t self
, void *aux
)
253 struct auacer_softc
*sc
;
254 struct pci_attach_args
*pa
;
255 pci_intr_handle_t ih
;
261 sc
= device_private(self
);
263 aprint_normal(": Acer Labs M5455 Audio controller\n");
265 if (pci_mapreg_map(pa
, 0x10, PCI_MAPREG_TYPE_IO
, 0, &sc
->iot
,
266 &sc
->aud_ioh
, NULL
, &aud_size
)) {
267 aprint_error(": can't map i/o space\n");
271 sc
->sc_pc
= pa
->pa_pc
;
272 sc
->sc_pt
= pa
->pa_tag
;
273 sc
->dmat
= pa
->pa_dmat
;
275 sc
->sc_dmamap_flags
= BUS_DMA_COHERENT
; /* XXX remove */
277 /* enable bus mastering */
278 v
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
);
279 pci_conf_write(pa
->pa_pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
,
280 v
| PCI_COMMAND_MASTER_ENABLE
);
282 /* Map and establish the interrupt. */
283 if (pci_intr_map(pa
, &ih
)) {
284 aprint_error_dev(&sc
->sc_dev
, "can't map interrupt\n");
287 intrstr
= pci_intr_string(pa
->pa_pc
, ih
);
288 sc
->sc_ih
= pci_intr_establish(pa
->pa_pc
, ih
, IPL_AUDIO
,
290 if (sc
->sc_ih
== NULL
) {
291 aprint_error_dev(&sc
->sc_dev
, "can't establish interrupt");
293 aprint_error(" at %s", intrstr
);
297 aprint_normal_dev(&sc
->sc_dev
, "interrupting at %s\n", intrstr
);
299 strlcpy(sc
->sc_audev
.name
, "M5455 AC97", MAX_AUDIO_DEV_LEN
);
300 snprintf(sc
->sc_audev
.version
, MAX_AUDIO_DEV_LEN
,
301 "0x%02x", PCI_REVISION(pa
->pa_class
));
302 strlcpy(sc
->sc_audev
.config
, device_xname(&sc
->sc_dev
), MAX_AUDIO_DEV_LEN
);
304 /* Set up DMA lists. */
305 auacer_alloc_cdata(sc
);
306 sc
->sc_pcmo
.dmalist
= sc
->sc_cdata
->ic_dmalist_pcmo
;
308 sc
->sc_pcmo
.port
= ALI_BASE_PO
;
310 DPRINTF(ALI_DEBUG_DMA
, ("auacer_attach: lists %p\n",
311 sc
->sc_pcmo
.dmalist
));
313 sc
->host_if
.arg
= sc
;
314 sc
->host_if
.attach
= auacer_attach_codec
;
315 sc
->host_if
.read
= auacer_read_codec
;
316 sc
->host_if
.write
= auacer_write_codec
;
317 sc
->host_if
.reset
= auacer_reset_codec
;
319 if (ac97_attach(&sc
->host_if
, self
) != 0)
322 /* setup audio_format */
323 memcpy(sc
->sc_formats
, auacer_formats
, sizeof(auacer_formats
));
324 if (!AC97_IS_4CH(sc
->codec_if
))
325 AUFMT_INVALIDATE(&sc
->sc_formats
[AUACER_FORMATS_4CH
]);
326 if (!AC97_IS_6CH(sc
->codec_if
))
327 AUFMT_INVALIDATE(&sc
->sc_formats
[AUACER_FORMATS_6CH
]);
328 if (AC97_IS_FIXED_RATE(sc
->codec_if
)) {
329 for (i
= 0; i
< AUACER_NFORMATS
; i
++) {
330 sc
->sc_formats
[i
].frequency_type
= 1;
331 sc
->sc_formats
[i
].frequency
[0] = 48000;
335 if (0 != auconv_create_encodings(sc
->sc_formats
, AUACER_NFORMATS
,
336 &sc
->sc_encodings
)) {
340 audio_attach_mi(&auacer_hw_if
, sc
, &sc
->sc_dev
);
344 if (!pmf_device_register(self
, NULL
, auacer_resume
))
345 aprint_error_dev(self
, "couldn't establish power handler\n");
348 CFATTACH_DECL(auacer
, sizeof(struct auacer_softc
),
349 auacer_match
, auacer_attach
, NULL
, NULL
);
352 auacer_ready_codec(struct auacer_softc
*sc
, int mask
)
356 for (count
= 0; count
< 0x7f; count
++) {
357 int val
= READ1(sc
, ALI_CSPSR
);
362 aprint_normal("auacer_ready_codec: AC97 codec ready timeout.\n");
367 auacer_sema_codec(struct auacer_softc
*sc
)
372 while (ttime
-- && (READ4(sc
, ALI_CAS
) & ALI_CAS_SEM_BUSY
))
375 aprint_normal("auacer_sema_codec: timeout\n");
376 return auacer_ready_codec(sc
, ALI_CSPSR_CODEC_READY
);
380 auacer_read_codec(void *v
, uint8_t reg
, uint16_t *val
)
382 struct auacer_softc
*sc
;
385 if (auacer_sema_codec(sc
))
388 reg
|= ALI_CPR_ADDR_READ
;
391 reg
|= ALI_CPR_ADDR_SECONDARY
;
393 WRITE2(sc
, ALI_CPR_ADDR
, reg
);
394 if (auacer_ready_codec(sc
, ALI_CSPSR_READ_OK
))
396 *val
= READ2(sc
, ALI_SPR
);
398 DPRINTF(ALI_DEBUG_CODECIO
, ("auacer_read_codec: reg=0x%x val=0x%x\n",
405 auacer_write_codec(void *v
, uint8_t reg
, uint16_t val
)
407 struct auacer_softc
*sc
;
409 DPRINTF(ALI_DEBUG_CODECIO
, ("auacer_write_codec: reg=0x%x val=0x%x\n",
412 if (auacer_sema_codec(sc
))
414 WRITE2(sc
, ALI_CPR
, val
);
417 reg
|= ALI_CPR_ADDR_SECONDARY
;
419 WRITE2(sc
, ALI_CPR_ADDR
, reg
);
420 auacer_ready_codec(sc
, ALI_CSPSR_WRITE_OK
);
425 auacer_attach_codec(void *v
, struct ac97_codec_if
*cif
)
427 struct auacer_softc
*sc
;
435 auacer_reset_codec(void *v
)
437 struct auacer_softc
*sc
;
443 reg
= READ4(sc
, ALI_SCR
);
444 if ((reg
& 2) == 0) /* Cold required */
448 reg
&= ~0x80000000; /* ACLink on */
449 WRITE4(sc
, ALI_SCR
, reg
);
452 if ((READ4(sc
, ALI_INTERRUPTSR
) & ALI_INT_GPIO
) == 0)
454 delay(50000); /* XXX */
461 for (i
= 0; i
< 10; i
++) {
462 reg
= READ4(sc
, ALI_RTSR
);
463 if (reg
& 0x80) /* primary codec */
465 WRITE4(sc
, ALI_RTSR
, reg
| 0x80);
466 delay(50000); /* XXX */
473 auacer_reset(struct auacer_softc
*sc
)
475 WRITE4(sc
, ALI_SCR
, ALI_SCR_RESET
);
476 WRITE4(sc
, ALI_FIFOCR1
, 0x83838383);
477 WRITE4(sc
, ALI_FIFOCR2
, 0x83838383);
478 WRITE4(sc
, ALI_FIFOCR3
, 0x83838383);
479 WRITE4(sc
, ALI_INTERFACECR
, ALI_IF_PO
); /* XXX pcm out only */
480 WRITE4(sc
, ALI_INTERRUPTCR
, 0x00000000);
481 WRITE4(sc
, ALI_INTERRUPTSR
, 0x00000000);
485 auacer_query_encoding(void *v
, struct audio_encoding
*aep
)
487 struct auacer_softc
*sc
;
489 DPRINTF(ALI_DEBUG_API
, ("auacer_query_encoding\n"));
491 return auconv_query_encoding(sc
->sc_encodings
, aep
);
495 auacer_set_rate(struct auacer_softc
*sc
, int mode
, u_int srate
)
500 DPRINTF(ALI_DEBUG_API
, ("auacer_set_rate: srate=%u\n", srate
));
503 if (mode
== AUMODE_RECORD
)
504 return sc
->codec_if
->vtbl
->set_rate(sc
->codec_if
,
505 AC97_REG_PCM_LR_ADC_RATE
, &ratetmp
);
506 ret
= sc
->codec_if
->vtbl
->set_rate(sc
->codec_if
,
507 AC97_REG_PCM_FRONT_DAC_RATE
, &ratetmp
);
511 ret
= sc
->codec_if
->vtbl
->set_rate(sc
->codec_if
,
512 AC97_REG_PCM_SURR_DAC_RATE
, &ratetmp
);
516 ret
= sc
->codec_if
->vtbl
->set_rate(sc
->codec_if
,
517 AC97_REG_PCM_LFE_DAC_RATE
, &ratetmp
);
522 auacer_set_params(void *v
, int setmode
, int usemode
,
523 audio_params_t
*play
, audio_params_t
*rec
, stream_filter_list_t
*pfil
,
524 stream_filter_list_t
*rfil
)
526 struct auacer_softc
*sc
;
527 struct audio_params
*p
;
528 stream_filter_list_t
*fil
;
532 DPRINTF(ALI_DEBUG_API
, ("auacer_set_params\n"));
534 for (mode
= AUMODE_RECORD
; mode
!= -1;
535 mode
= mode
== AUMODE_RECORD
? AUMODE_PLAY
: -1) {
536 if ((setmode
& mode
) == 0)
539 p
= mode
== AUMODE_PLAY
? play
: rec
;
543 if ((p
->sample_rate
!= 8000) &&
544 (p
->sample_rate
!= 11025) &&
545 (p
->sample_rate
!= 12000) &&
546 (p
->sample_rate
!= 16000) &&
547 (p
->sample_rate
!= 22050) &&
548 (p
->sample_rate
!= 24000) &&
549 (p
->sample_rate
!= 32000) &&
550 (p
->sample_rate
!= 44100) &&
551 (p
->sample_rate
!= 48000))
554 fil
= mode
== AUMODE_PLAY
? pfil
: rfil
;
555 index
= auconv_set_converter(sc
->sc_formats
, AUACER_NFORMATS
,
559 if (fil
->req_size
> 0)
560 p
= &fil
->filters
[0].param
;
561 /* p points HW encoding */
562 if (sc
->sc_formats
[index
].frequency_type
!= 1
563 && auacer_set_rate(sc
, mode
, p
->sample_rate
))
565 if (mode
== AUMODE_PLAY
) {
566 control
= READ4(sc
, ALI_SCR
);
567 control
&= ~ALI_SCR_PCM_246_MASK
;
568 if (p
->channels
== 4)
569 control
|= ALI_SCR_PCM_4
;
570 else if (p
->channels
== 6)
571 control
|= ALI_SCR_PCM_6
;
572 WRITE4(sc
, ALI_SCR
, control
);
580 auacer_round_blocksize(void *v
, int blk
, int mode
,
581 const audio_params_t
*param
)
584 return blk
& ~0x3f; /* keep good alignment */
588 auacer_halt(struct auacer_softc
*sc
, struct auacer_chan
*chan
)
595 DPRINTF(ALI_DEBUG_API
, ("auacer_halt: port=0x%x\n", port
));
598 slot
= ALI_PORT2SLOT(port
);
600 val
= READ4(sc
, ALI_DMACR
);
601 val
|= 1 << (slot
+16); /* pause */
602 val
&= ~(1 << slot
); /* no start */
603 WRITE4(sc
, ALI_DMACR
, val
);
604 WRITE1(sc
, port
+ ALI_OFF_CR
, 0);
605 while (READ1(sc
, port
+ ALI_OFF_CR
))
607 /* reset whole DMA things */
608 WRITE1(sc
, port
+ ALI_OFF_CR
, ALI_CR_RR
);
609 /* clear interrupts */
610 WRITE1(sc
, port
+ ALI_OFF_SR
, READ1(sc
, port
+ALI_OFF_SR
) | ALI_SR_W1TC
);
611 WRITE4(sc
, ALI_INTERRUPTSR
, ALI_PORT2INTR(port
));
615 auacer_halt_output(void *v
)
617 struct auacer_softc
*sc
;
619 DPRINTF(ALI_DEBUG_DMA
, ("auacer_halt_output\n"));
621 auacer_halt(sc
, &sc
->sc_pcmo
);
627 auacer_halt_input(void *v
)
629 DPRINTF(ALI_DEBUG_DMA
, ("auacer_halt_input\n"));
635 auacer_getdev(void *v
, struct audio_device
*adp
)
637 struct auacer_softc
*sc
;
639 DPRINTF(ALI_DEBUG_API
, ("auacer_getdev\n"));
646 auacer_set_port(void *v
, mixer_ctrl_t
*cp
)
648 struct auacer_softc
*sc
;
650 DPRINTF(ALI_DEBUG_MIXERAPI
, ("auacer_set_port\n"));
652 return sc
->codec_if
->vtbl
->mixer_set_port(sc
->codec_if
, cp
);
656 auacer_get_port(void *v
, mixer_ctrl_t
*cp
)
658 struct auacer_softc
*sc
;
660 DPRINTF(ALI_DEBUG_MIXERAPI
, ("auacer_get_port\n"));
662 return sc
->codec_if
->vtbl
->mixer_get_port(sc
->codec_if
, cp
);
666 auacer_query_devinfo(void *v
, mixer_devinfo_t
*dp
)
668 struct auacer_softc
*sc
;
670 DPRINTF(ALI_DEBUG_MIXERAPI
, ("auacer_query_devinfo\n"));
672 return sc
->codec_if
->vtbl
->query_devinfo(sc
->codec_if
, dp
);
676 auacer_allocm(void *v
, int direction
, size_t size
,
677 struct malloc_type
*pool
, int flags
)
679 struct auacer_softc
*sc
;
680 struct auacer_dma
*p
;
683 if (size
> (ALI_DMALIST_MAX
* ALI_DMASEG_MAX
))
686 p
= malloc(sizeof(*p
), pool
, flags
| M_ZERO
);
690 error
= auacer_allocmem(sc
, size
, 0, p
);
696 p
->next
= sc
->sc_dmas
;
703 auacer_freem(void *v
, void *ptr
, struct malloc_type
*pool
)
705 struct auacer_softc
*sc
;
706 struct auacer_dma
*p
, **pp
;
709 for (pp
= &sc
->sc_dmas
; (p
= *pp
) != NULL
; pp
= &p
->next
) {
710 if (KERNADDR(p
) == ptr
) {
711 auacer_freemem(sc
, p
);
720 auacer_round_buffersize(void *v
, int direction
, size_t size
)
723 if (size
> (ALI_DMALIST_MAX
* ALI_DMASEG_MAX
))
724 size
= ALI_DMALIST_MAX
* ALI_DMASEG_MAX
;
730 auacer_mappage(void *v
, void *mem
, off_t off
, int prot
)
732 struct auacer_softc
*sc
;
733 struct auacer_dma
*p
;
738 for (p
= sc
->sc_dmas
; p
&& KERNADDR(p
) != mem
; p
= p
->next
)
742 return bus_dmamem_mmap(sc
->dmat
, p
->segs
, p
->nsegs
,
743 off
, prot
, BUS_DMA_WAITOK
);
747 auacer_get_props(void *v
)
749 struct auacer_softc
*sc
;
753 props
= AUDIO_PROP_INDEPENDENT
| AUDIO_PROP_FULLDUPLEX
;
755 * Even if the codec is fixed-rate, set_param() succeeds for any sample
756 * rate because of aurateconv. Applications can't know what rate the
757 * device can process in the case of mmap().
759 if (!AC97_IS_FIXED_RATE(sc
->codec_if
))
760 props
|= AUDIO_PROP_MMAP
;
765 auacer_add_entry(struct auacer_chan
*chan
)
767 struct auacer_dmalist
*q
;
769 q
= &chan
->dmalist
[chan
->ptr
];
771 DPRINTF(ALI_DEBUG_INTR
,
772 ("auacer_add_entry: %p = %x @ 0x%x\n",
773 q
, chan
->blksize
/ 2, chan
->p
));
775 q
->base
= htole32(chan
->p
);
776 q
->len
= htole32((chan
->blksize
/ ALI_SAMPLE_SIZE
) | ALI_DMAF_IOC
);
777 chan
->p
+= chan
->blksize
;
778 if (chan
->p
>= chan
->end
)
779 chan
->p
= chan
->start
;
781 if (++chan
->ptr
>= ALI_DMALIST_MAX
)
786 auacer_upd_chan(struct auacer_softc
*sc
, struct auacer_chan
*chan
)
791 sts
= READ2(sc
, chan
->port
+ ALI_OFF_SR
);
793 WRITE2(sc
, chan
->port
+ ALI_OFF_SR
, sts
& ALI_SR_W1TC
);
794 WRITE4(sc
, ALI_INTERRUPTSR
, ALI_PORT2INTR(chan
->port
));
796 DPRINTF(ALI_DEBUG_INTR
, ("auacer_upd_chan: sts=0x%x\n", sts
));
798 if (sts
& ALI_SR_DMA_INT_FIFO
) {
799 printf("%s: fifo underrun # %u\n",
800 device_xname(&sc
->sc_dev
), ++chan
->fifoe
);
803 civ
= READ1(sc
, chan
->port
+ ALI_OFF_CIV
);
805 DPRINTF(ALI_DEBUG_INTR
,("auacer_intr: civ=%u ptr=%u\n",civ
,chan
->ptr
));
808 while (chan
->ptr
!= civ
) {
809 auacer_add_entry(chan
);
812 WRITE1(sc
, chan
->port
+ ALI_OFF_LVI
, (chan
->ptr
- 1) & ALI_LVI_MASK
);
814 while (chan
->ack
!= civ
) {
816 DPRINTF(ALI_DEBUG_INTR
,("auacer_upd_chan: callback\n"));
817 chan
->intr(chan
->arg
);
820 if (chan
->ack
>= ALI_DMALIST_MAX
)
828 struct auacer_softc
*sc
;
832 intrs
= READ4(sc
, ALI_INTERRUPTSR
);
833 DPRINTF(ALI_DEBUG_INTR
, ("auacer_intr: intrs=0x%x\n", intrs
));
836 if (intrs
& ALI_INT_PCMOUT
) {
837 auacer_upd_chan(sc
, &sc
->sc_pcmo
);
845 auacer_setup_chan(struct auacer_softc
*sc
, struct auacer_chan
*chan
,
846 uint32_t start
, uint32_t size
, uint32_t blksize
,
847 void (*intr
)(void *), void *arg
)
854 chan
->p
= chan
->start
;
855 chan
->end
= chan
->start
+ size
;
856 chan
->blksize
= blksize
;
861 auacer_add_entry(chan
);
862 auacer_add_entry(chan
);
865 slot
= ALI_PORT2SLOT(port
);
867 WRITE1(sc
, port
+ ALI_OFF_CIV
, 0);
868 WRITE1(sc
, port
+ ALI_OFF_LVI
, (chan
->ptr
- 1) & ALI_LVI_MASK
);
869 offs
= (char *)chan
->dmalist
- (char *)sc
->sc_cdata
;
870 WRITE4(sc
, port
+ ALI_OFF_BDBAR
, sc
->sc_cddma
+ offs
);
871 WRITE1(sc
, port
+ ALI_OFF_CR
,
872 ALI_CR_IOCE
| ALI_CR_FEIE
| ALI_CR_LVBIE
| ALI_CR_RPBM
);
873 val
= READ4(sc
, ALI_DMACR
);
874 val
&= ~(1 << (slot
+16)); /* no pause */
875 val
|= 1 << slot
; /* start */
876 WRITE4(sc
, ALI_DMACR
, val
);
880 auacer_trigger_output(void *v
, void *start
, void *end
, int blksize
,
881 void (*intr
)(void *), void *arg
, const audio_params_t
*param
)
883 struct auacer_softc
*sc
;
884 struct auacer_dma
*p
;
887 DPRINTF(ALI_DEBUG_DMA
,
888 ("auacer_trigger_output(%p, %p, %d, %p, %p, %p)\n",
889 start
, end
, blksize
, intr
, arg
, param
));
891 for (p
= sc
->sc_dmas
; p
&& KERNADDR(p
) != start
; p
= p
->next
)
894 printf("auacer_trigger_output: bad addr %p\n", start
);
898 size
= (char *)end
- (char *)start
;
899 auacer_setup_chan(sc
, &sc
->sc_pcmo
, DMAADDR(p
), size
, blksize
,
906 auacer_trigger_input(void *v
, void *start
, void *end
,
907 int blksize
, void (*intr
)(void *), void *arg
,
908 const audio_params_t
*param
)
914 auacer_allocmem(struct auacer_softc
*sc
, size_t size
, size_t align
,
915 struct auacer_dma
*p
)
920 error
= bus_dmamem_alloc(sc
->dmat
, p
->size
, align
, 0,
921 p
->segs
, sizeof(p
->segs
)/sizeof(p
->segs
[0]),
922 &p
->nsegs
, BUS_DMA_NOWAIT
);
926 error
= bus_dmamem_map(sc
->dmat
, p
->segs
, p
->nsegs
, p
->size
,
927 &p
->addr
, BUS_DMA_NOWAIT
|sc
->sc_dmamap_flags
);
931 error
= bus_dmamap_create(sc
->dmat
, p
->size
, 1, p
->size
,
932 0, BUS_DMA_NOWAIT
, &p
->map
);
936 error
= bus_dmamap_load(sc
->dmat
, p
->map
, p
->addr
, p
->size
, NULL
,
943 bus_dmamap_destroy(sc
->dmat
, p
->map
);
945 bus_dmamem_unmap(sc
->dmat
, p
->addr
, p
->size
);
947 bus_dmamem_free(sc
->dmat
, p
->segs
, p
->nsegs
);
952 auacer_freemem(struct auacer_softc
*sc
, struct auacer_dma
*p
)
955 bus_dmamap_unload(sc
->dmat
, p
->map
);
956 bus_dmamap_destroy(sc
->dmat
, p
->map
);
957 bus_dmamem_unmap(sc
->dmat
, p
->addr
, p
->size
);
958 bus_dmamem_free(sc
->dmat
, p
->segs
, p
->nsegs
);
963 auacer_alloc_cdata(struct auacer_softc
*sc
)
965 bus_dma_segment_t seg
;
969 * Allocate the control data structure, and create and load the
972 if ((error
= bus_dmamem_alloc(sc
->dmat
,
973 sizeof(struct auacer_cdata
),
974 PAGE_SIZE
, 0, &seg
, 1, &rseg
, 0)) != 0) {
975 aprint_error_dev(&sc
->sc_dev
, "unable to allocate control data, error = %d\n",
980 if ((error
= bus_dmamem_map(sc
->dmat
, &seg
, rseg
,
981 sizeof(struct auacer_cdata
),
982 (void **) &sc
->sc_cdata
,
983 sc
->sc_dmamap_flags
)) != 0) {
984 aprint_error_dev(&sc
->sc_dev
, "unable to map control data, error = %d\n",
989 if ((error
= bus_dmamap_create(sc
->dmat
, sizeof(struct auacer_cdata
), 1,
990 sizeof(struct auacer_cdata
), 0, 0,
991 &sc
->sc_cddmamap
)) != 0) {
992 aprint_error_dev(&sc
->sc_dev
, "unable to create control data DMA map, "
993 "error = %d\n", error
);
997 if ((error
= bus_dmamap_load(sc
->dmat
, sc
->sc_cddmamap
,
998 sc
->sc_cdata
, sizeof(struct auacer_cdata
),
1000 aprint_error_dev(&sc
->sc_dev
, "unable to load control data DMA map, "
1001 "error = %d\n", error
);
1008 bus_dmamap_destroy(sc
->dmat
, sc
->sc_cddmamap
);
1010 bus_dmamem_unmap(sc
->dmat
, (void *) sc
->sc_cdata
,
1011 sizeof(struct auacer_cdata
));
1013 bus_dmamem_free(sc
->dmat
, &seg
, rseg
);
1019 auacer_resume(device_t dv
, pmf_qual_t qual
)
1021 struct auacer_softc
*sc
= device_private(dv
);
1023 auacer_reset_codec(sc
);
1025 sc
->codec_if
->vtbl
->restore_ports(sc
->codec_if
);