1 /* $NetBSD: cs428x.c,v 1.14 2007/10/19 12:00:41 ad Exp $ */
4 * Copyright (c) 2000 Tatoku Ogaito. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Tatoku Ogaito
17 * for the NetBSD Project.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 /* Common functions for CS4280 and CS4281 */
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: cs428x.c,v 1.14 2007/10/19 12:00:41 ad Exp $");
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 #include <sys/device.h>
44 #include <dev/pci/pcidevs.h>
45 #include <dev/pci/pcivar.h>
47 #include <sys/audioio.h>
48 #include <dev/audio_if.h>
49 #include <dev/midi_if.h>
50 #include <dev/mulaw.h>
51 #include <dev/auconv.h>
53 #include <dev/ic/ac97reg.h>
54 #include <dev/ic/ac97var.h>
58 #include <dev/pci/cs428xreg.h>
59 #include <dev/pci/cs428x.h>
61 #if defined(CS4280_DEBUG) || defined(CS4281_DEBUG)
66 cs428x_round_blocksize(void *addr
, int blk
,
67 int mode
, const audio_params_t
*param
)
69 struct cs428x_softc
*sc
;
72 DPRINTFN(5,("cs428x_round_blocksize blk=%d -> ", blk
));
75 if (blk
< sc
->hw_blocksize
)
76 retval
= sc
->hw_blocksize
;
78 retval
= blk
& -(sc
->hw_blocksize
);
80 DPRINTFN(5,("%d\n", retval
));
86 cs428x_mixer_set_port(void *addr
, mixer_ctrl_t
*cp
)
88 struct cs428x_softc
*sc
;
92 val
= sc
->codec_if
->vtbl
->mixer_set_port(sc
->codec_if
, cp
);
93 DPRINTFN(3,("mixer_set_port: val=%d\n", val
));
98 cs428x_mixer_get_port(void *addr
, mixer_ctrl_t
*cp
)
100 struct cs428x_softc
*sc
;
103 return (sc
->codec_if
->vtbl
->mixer_get_port(sc
->codec_if
, cp
));
107 cs428x_query_devinfo(void *addr
, mixer_devinfo_t
*dip
)
109 struct cs428x_softc
*sc
;
112 return (sc
->codec_if
->vtbl
->query_devinfo(sc
->codec_if
, dip
));
116 cs428x_malloc(void *addr
, int direction
, size_t size
,
117 struct malloc_type
*pool
, int flags
)
119 struct cs428x_softc
*sc
;
120 struct cs428x_dma
*p
;
125 p
= malloc(sizeof(*p
), pool
, flags
);
129 error
= cs428x_allocmem(sc
, size
, pool
, flags
, p
);
136 p
->next
= sc
->sc_dmas
;
142 cs428x_free(void *addr
, void *ptr
, struct malloc_type
*pool
)
144 struct cs428x_softc
*sc
;
145 struct cs428x_dma
**pp
, *p
;
148 for (pp
= &sc
->sc_dmas
; (p
= *pp
) != NULL
; pp
= &p
->next
) {
149 if (BUFADDR(p
) == ptr
) {
150 bus_dmamap_unload(sc
->sc_dmatag
, p
->map
);
151 bus_dmamap_destroy(sc
->sc_dmatag
, p
->map
);
152 bus_dmamem_unmap(sc
->sc_dmatag
, p
->addr
, p
->size
);
153 bus_dmamem_free(sc
->sc_dmatag
, p
->segs
, p
->nsegs
);
163 cs428x_round_buffersize(void *addr
, int direction
,
166 /* The real DMA buffersize are 4KB for CS4280
167 * and 64kB/MAX_CHANNELS for CS4281.
168 * But they are too small for high quality audio,
169 * let the upper layer(audio) use a larger buffer.
170 * (originally suggested by Lennart Augustsson.)
176 cs428x_mappage(void *addr
, void *mem
, off_t off
, int prot
)
178 struct cs428x_softc
*sc
;
179 struct cs428x_dma
*p
;
186 for (p
= sc
->sc_dmas
; p
&& BUFADDR(p
) != mem
; p
= p
->next
)
190 DPRINTF(("cs428x_mappage: bad buffer address\n"));
194 return (bus_dmamem_mmap(sc
->sc_dmatag
, p
->segs
, p
->nsegs
,
195 off
, prot
, BUS_DMA_WAITOK
));
199 cs428x_get_props(void *addr
)
203 retval
= AUDIO_PROP_INDEPENDENT
| AUDIO_PROP_FULLDUPLEX
;
205 /* How can I mmap ? */
206 retval
|= AUDIO_PROP_MMAP
;
213 cs428x_attach_codec(void *addr
, struct ac97_codec_if
*codec_if
)
215 struct cs428x_softc
*sc
;
217 DPRINTF(("cs428x_attach_codec:\n"));
219 sc
->codec_if
= codec_if
;
224 cs428x_read_codec(void *addr
, uint8_t ac97_addr
, uint16_t *ac97_data
)
226 struct cs428x_softc
*sc
;
232 DPRINTFN(5,("read_codec: add=0x%02x ", ac97_addr
));
234 * Make sure that there is not data sitting around from a previous
235 * uncompleted access.
237 BA0READ4(sc
, CS428X_ACSDA
);
239 /* Set up AC97 control registers. */
240 BA0WRITE4(sc
, CS428X_ACCAD
, ac97_addr
);
241 BA0WRITE4(sc
, CS428X_ACCDA
, 0);
243 acctl
= ACCTL_ESYN
| ACCTL_VFRM
| ACCTL_CRW
| ACCTL_DCV
;
244 if (sc
->type
== TYPE_CS4280
)
246 BA0WRITE4(sc
, CS428X_ACCTL
, acctl
);
248 if (cs428x_src_wait(sc
) < 0) {
249 printf("%s: AC97 read prob. (DCV!=0) for add=0x%0x\n",
250 device_xname(&sc
->sc_dev
), ac97_addr
);
254 /* wait for valid status bit is active */
256 while ((BA0READ4(sc
, CS428X_ACSTS
) & ACSTS_VSTS
) == 0) {
259 printf("%s: AC97 read fail (VSTS==0) for add=0x%0x\n",
260 device_xname(&sc
->sc_dev
), ac97_addr
);
264 *ac97_data
= BA0READ4(sc
, CS428X_ACSDA
);
265 DPRINTFN(5,("data=0x%04x\n", *ac97_data
));
270 cs428x_write_codec(void *addr
, uint8_t ac97_addr
, uint16_t ac97_data
)
272 struct cs428x_softc
*sc
;
277 DPRINTFN(5,("write_codec: add=0x%02x data=0x%04x\n", ac97_addr
, ac97_data
));
278 BA0WRITE4(sc
, CS428X_ACCAD
, ac97_addr
);
279 BA0WRITE4(sc
, CS428X_ACCDA
, ac97_data
);
281 acctl
= ACCTL_ESYN
| ACCTL_VFRM
| ACCTL_DCV
;
282 if (sc
->type
== TYPE_CS4280
)
284 BA0WRITE4(sc
, CS428X_ACCTL
, acctl
);
286 if (cs428x_src_wait(sc
) < 0) {
287 printf("%s: AC97 write fail (DCV!=0) for add=0x%02x data="
288 "0x%04x\n", device_xname(&sc
->sc_dev
), ac97_addr
, ac97_data
);
294 /* Internal functions */
296 cs428x_allocmem(struct cs428x_softc
*sc
,
297 size_t size
, struct malloc_type
*pool
, int flags
,
298 struct cs428x_dma
*p
)
303 align
= sc
->dma_align
;
304 p
->size
= sc
->dma_size
;
305 /* allocate memory for upper audio driver */
306 p
->dum
= malloc(size
, pool
, flags
);
310 error
= bus_dmamem_alloc(sc
->sc_dmatag
, p
->size
, align
, 0,
311 p
->segs
, sizeof(p
->segs
)/sizeof(p
->segs
[0]),
312 &p
->nsegs
, BUS_DMA_NOWAIT
);
314 aprint_error_dev(&sc
->sc_dev
, "unable to allocate DMA. error=%d\n",
319 error
= bus_dmamem_map(sc
->sc_dmatag
, p
->segs
, p
->nsegs
, p
->size
,
320 &p
->addr
, BUS_DMA_NOWAIT
|BUS_DMA_COHERENT
);
322 aprint_error_dev(&sc
->sc_dev
, "unable to map DMA, error=%d\n",
327 error
= bus_dmamap_create(sc
->sc_dmatag
, p
->size
, 1, p
->size
,
328 0, BUS_DMA_NOWAIT
, &p
->map
);
330 aprint_error_dev(&sc
->sc_dev
, "unable to create DMA map, error=%d\n",
335 error
= bus_dmamap_load(sc
->sc_dmatag
, p
->map
, p
->addr
, p
->size
, NULL
,
338 aprint_error_dev(&sc
->sc_dev
, "unable to load DMA map, error=%d\n",
345 bus_dmamap_destroy(sc
->sc_dmatag
, p
->map
);
347 bus_dmamem_unmap(sc
->sc_dmatag
, p
->addr
, p
->size
);
349 bus_dmamem_free(sc
->sc_dmatag
, p
->segs
, p
->nsegs
);
357 cs428x_src_wait(struct cs428x_softc
*sc
)
362 while ((BA0READ4(sc
, CS428X_ACCTL
) & ACCTL_DCV
)) {
365 printf("cs428x_src_wait: 0x%08x\n",
366 BA0READ4(sc
, CS428X_ACCTL
));