Bug Summary

File:dev/pci/auixp.c
Warning:line 1435, column 3
Value stored to 'value' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name auixp.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/dev/pci/auixp.c
1/* $OpenBSD: auixp.c,v 1.44 2022/01/09 05:42:45 jsg Exp $ */
2/* $NetBSD: auixp.c,v 1.9 2005/06/27 21:13:09 thorpej Exp $ */
3
4/*
5 * Copyright (c) 2004, 2005 Reinoud Zandijk <reinoud@netbsd.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28/*
29 * Audio driver for ATI IXP-{150,200,...} audio driver hardware.
30 *
31 * Recording and playback has been tested OK on various sample rates and
32 * encodings.
33 *
34 * Known problems and issues :
35 * - SPDIF is untested and needs some work still (LED stays off)
36 * - 32 bit audio playback failed last time i tried but that might an AC'97
37 * codec support problem.
38 * - 32 bit recording works but can't try out playing: see above.
39 * - no suspend/resume support yet.
40 * - multiple codecs are `supported' but not tested; the implementation needs
41 * some cleaning up.
42 */
43
44/*#define DEBUG_AUIXP*/
45
46#include <sys/param.h>
47#include <sys/errno.h>
48#include <sys/systm.h>
49#include <sys/malloc.h>
50#include <sys/device.h>
51#include <sys/conf.h>
52#include <sys/exec.h>
53#include <sys/selinfo.h>
54#include <sys/audioio.h>
55#include <sys/queue.h>
56
57#include <machine/bus.h>
58
59#include <dev/pci/pcidevs.h>
60#include <dev/pci/pcivar.h>
61
62#include <dev/audio_if.h>
63#include <dev/ic/ac97.h>
64
65#include <dev/pci/auixpreg.h>
66#include <dev/pci/auixpvar.h>
67
68/* codec detection constant indicating the interrupt flags */
69#define ALL_CODECS_NOT_READY((1U<<10) | (1U<<11) | (1U<<12)) \
70 (ATI_REG_ISR_CODEC0_NOT_READY(1U<<10) | ATI_REG_ISR_CODEC1_NOT_READY(1U<<11) |\
71 ATI_REG_ISR_CODEC2_NOT_READY(1U<<12))
72#define CODEC_CHECK_BITS(((1U<<10) | (1U<<11) | (1U<<12))|(1U<<
13))
(ALL_CODECS_NOT_READY((1U<<10) | (1U<<11) | (1U<<12))|ATI_REG_ISR_NEW_FRAME(1U<<13))
73
74/* why isn't this base address register not in the headerfile? */
75#define PCI_CBIO0x10 0x10
76
77/* macro's used */
78#define KERNADDR(p)((void *)((p)->addr)) ((void *)((p)->addr))
79#define DMAADDR(p)((p)->map->dm_segs[0].ds_addr) ((p)->map->dm_segs[0].ds_addr)
80
81const struct pci_matchid auixp_pci_devices[] = {
82 { PCI_VENDOR_ATI0x1002, PCI_PRODUCT_ATI_SB200_AUDIO0x4341 },
83 { PCI_VENDOR_ATI0x1002, PCI_PRODUCT_ATI_SB300_AUDIO0x4361 },
84 { PCI_VENDOR_ATI0x1002, PCI_PRODUCT_ATI_SB400_AUDIO0x4370 },
85 { PCI_VENDOR_ATI0x1002, PCI_PRODUCT_ATI_SB600_AUDIO0x4382 }
86};
87
88struct cfdriver auixp_cd = {
89 NULL((void *)0), "auixp", DV_DULL
90};
91
92int auixp_match( struct device *, void *, void *);
93void auixp_attach(struct device *, struct device *, void *);
94int auixp_detach(struct device *, int);
95
96int auixp_activate(struct device *, int);
97
98struct cfattach auixp_ca = {
99 sizeof(struct auixp_softc), auixp_match, auixp_attach,
100 NULL((void *)0), auixp_activate
101};
102
103int auixp_open(void *v, int flags);
104void auixp_close(void *v);
105int auixp_set_params(void *, int, int, struct audio_params *,
106 struct audio_params *);
107int auixp_commit_settings(void *);
108int auixp_round_blocksize(void *, int);
109int auixp_trigger_output(void *, void *, void *, int,
110 void (*)(void *), void *, struct audio_params *);
111int auixp_trigger_input(void *, void *, void *, int,
112 void (*)(void *), void *, struct audio_params *);
113int auixp_halt_output(void *);
114int auixp_halt_input(void *);
115int auixp_set_port(void *, mixer_ctrl_t *);
116int auixp_get_port(void *, mixer_ctrl_t *);
117int auixp_query_devinfo(void *, mixer_devinfo_t *);
118void * auixp_malloc(void *, int, size_t, int, int);
119void auixp_free(void *, void *, int);
120int auixp_get_props(void *);
121int auixp_intr(void *);
122int auixp_allocmem(struct auixp_softc *, size_t, size_t,
123 struct auixp_dma *);
124int auixp_freemem(struct auixp_softc *, struct auixp_dma *);
125
126/* Supporting subroutines */
127int auixp_init(struct auixp_softc *);
128void auixp_autodetect_codecs(struct auixp_softc *);
129void auixp_post_config(struct device *);
130
131void auixp_reset_aclink(struct auixp_softc *);
132int auixp_attach_codec(void *, struct ac97_codec_if *);
133int auixp_read_codec(void *, u_int8_t, u_int16_t *);
134int auixp_write_codec(void *, u_int8_t, u_int16_t);
135int auixp_wait_for_codecs(struct auixp_softc *, const char *);
136void auixp_reset_codec(void *);
137enum ac97_host_flags auixp_flags_codec(void *);
138
139void auixp_enable_dma(struct auixp_softc *, struct auixp_dma *);
140void auixp_disable_dma(struct auixp_softc *, struct auixp_dma *);
141void auixp_enable_interrupts(struct auixp_softc *);
142void auixp_disable_interrupts(struct auixp_softc *);
143
144void auixp_link_daisychain(struct auixp_softc *,
145 struct auixp_dma *, struct auixp_dma *, int, int);
146int auixp_allocate_dma_chain(struct auixp_softc *, struct auixp_dma **);
147void auixp_program_dma_chain(struct auixp_softc *, struct auixp_dma *);
148void auixp_dma_update(struct auixp_softc *, struct auixp_dma *);
149void auixp_update_busbusy(struct auixp_softc *);
150
151#ifdef DEBUG_AUIXP
152#define DPRINTF(x) printf x;
153#else
154#define DPRINTF(x)
155#endif
156
157struct audio_hw_if auixp_hw_if = {
158 auixp_open,
159 auixp_close,
160 auixp_set_params,
161 auixp_round_blocksize,
162 auixp_commit_settings,
163 NULL((void *)0), /* init_output */
164 NULL((void *)0), /* init_input */
165 NULL((void *)0), /* start_output */
166 NULL((void *)0), /* start_input */
167 auixp_halt_output,
168 auixp_halt_input,
169 NULL((void *)0), /* speaker_ctl */
170 NULL((void *)0), /* getfd */
171 auixp_set_port,
172 auixp_get_port,
173 auixp_query_devinfo,
174 auixp_malloc,
175 auixp_free,
176 NULL((void *)0), /* round_buffersize */
177 auixp_get_props,
178 auixp_trigger_output,
179 auixp_trigger_input
180};
181
182int
183auixp_open(void *v, int flags)
184{
185
186 return 0;
187}
188
189void
190auixp_close(void *v)
191{
192}
193
194/* commit setting and program ATI IXP chip */
195int
196auixp_commit_settings(void *hdl)
197{
198 struct auixp_codec *co;
199 struct auixp_softc *sc;
200 bus_space_tag_t iot;
201 bus_space_handle_t ioh;
202 struct audio_params *params;
203 u_int32_t value;
204
205 /* XXX would it be better to stop interrupts first? XXX */
206 co = (struct auixp_codec *) hdl;
207 sc = co->sc;
208 iot = sc->sc_iot;
209 ioh = sc->sc_ioh;
210
211 /* process input settings */
212 params = &sc->sc_play_params;
213
214 /* set input interleaving (precision) */
215 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
216 value &= ~ATI_REG_CMD_INTERLEAVE_IN(1U<<21);
217 if (params->precision <= 16)
218 value |= ATI_REG_CMD_INTERLEAVE_IN(1U<<21);
219 bus_space_write_4(iot, ioh, ATI_REG_CMD, value)((iot)->write_4((ioh), (0x08), (value)));
220
221 /* process output settings */
222 params = &sc->sc_play_params;
223
224 value = bus_space_read_4(iot, ioh, ATI_REG_OUT_DMA_SLOT)((iot)->read_4((ioh), (0x34)));
225 value &= ~ATI_REG_OUT_DMA_SLOT_MASK0x1ff;
226
227 /* TODO SPDIF case for 8 channels */
228 switch (params->channels) {
229 case 6:
230 value |= ATI_REG_OUT_DMA_SLOT_BIT(7)(1U << ((7) - 3)) |
231 ATI_REG_OUT_DMA_SLOT_BIT(8)(1U << ((8) - 3));
232 /* FALLTHROUGH */
233 case 4:
234 value |= ATI_REG_OUT_DMA_SLOT_BIT(6)(1U << ((6) - 3)) |
235 ATI_REG_OUT_DMA_SLOT_BIT(9)(1U << ((9) - 3));
236 /* FALLTHROUGH */
237 default:
238 value |= ATI_REG_OUT_DMA_SLOT_BIT(3)(1U << ((3) - 3)) |
239 ATI_REG_OUT_DMA_SLOT_BIT(4)(1U << ((4) - 3));
240 break;
241 }
242 /* set output threshold */
243 value |= 0x04 << ATI_REG_OUT_DMA_THRESHOLD_SHIFT11;
244 bus_space_write_4(iot, ioh, ATI_REG_OUT_DMA_SLOT, value)((iot)->write_4((ioh), (0x34), (value)));
245
246 /* set output interleaving (precision) */
247 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
248 value &= ~ATI_REG_CMD_INTERLEAVE_OUT(1U<<22);
249 if (params->precision <= 16)
250 value |= ATI_REG_CMD_INTERLEAVE_OUT(1U<<22);
251 bus_space_write_4(iot, ioh, ATI_REG_CMD, value)((iot)->write_4((ioh), (0x08), (value)));
252
253 /* enable 6 channel reordering */
254 value = bus_space_read_4(iot, ioh, ATI_REG_6CH_REORDER)((iot)->read_4((ioh), (0x84)));
255 value &= ~ATI_REG_6CH_REORDER_EN(1U<<0);
256 if (params->channels == 6)
257 value |= ATI_REG_6CH_REORDER_EN(1U<<0);
258 bus_space_write_4(iot, ioh, ATI_REG_6CH_REORDER, value)((iot)->write_4((ioh), (0x84), (value)));
259
260 if (sc->has_spdif) {
261 /* set SPDIF (if present) */
262 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
263 value &= ~ATI_REG_CMD_SPDF_CONFIG_MASK(7U<<12);
264 value |= ATI_REG_CMD_SPDF_CONFIG_34(1U<<12); /* NetBSD AC'97 default */
265
266 /* XXX this is probably not necessary unless splitted XXX */
267 value &= ~ATI_REG_CMD_INTERLEAVE_SPDF(1U<<16);
268 if (params->precision <= 16)
269 value |= ATI_REG_CMD_INTERLEAVE_SPDF(1U<<16);
270 bus_space_write_4(iot, ioh, ATI_REG_CMD, value)((iot)->write_4((ioh), (0x08), (value)));
271 }
272
273 return 0;
274}
275
276
277/* set audio properties in desired setting */
278int
279auixp_set_params(void *hdl, int setmode, int usemode,
280 struct audio_params *play, struct audio_params *rec)
281{
282 struct auixp_codec *co;
283 int error;
284 u_int temprate;
285
286 co = (struct auixp_codec *) hdl;
287 if (setmode & AUMODE_PLAY0x01) {
288 play->channels = 2;
289 play->precision = 16;
290 switch(play->encoding) {
291 case AUDIO_ENCODING_SLINEAR_LE6:
292 break;
293 default:
294 return (EINVAL22);
295 }
296 play->bps = AUDIO_BPS(play->precision)(play->precision) <= 8 ? 1 : ((play->precision) <=
16 ? 2 : 4)
;
297 play->msb = 1;
298
299 temprate = play->sample_rate;
300 error = ac97_set_rate(co->codec_if,
301 AC97_REG_PCM_LFE_DAC_RATE0x30, &play->sample_rate);
302 if (error)
303 return (error);
304
305 play->sample_rate = temprate;
306 error = ac97_set_rate(co->codec_if,
307 AC97_REG_PCM_SURR_DAC_RATE0x2e, &play->sample_rate);
308 if (error)
309 return (error);
310
311 play->sample_rate = temprate;
312 error = ac97_set_rate(co->codec_if,
313 AC97_REG_PCM_FRONT_DAC_RATE0x2c, &play->sample_rate);
314 if (error)
315 return (error);
316
317 }
318
319 if (setmode & AUMODE_RECORD0x02) {
320 rec->channels = 2;
321 rec->precision = 16;
322 switch(rec->encoding) {
323 case AUDIO_ENCODING_SLINEAR_LE6:
324 break;
325 default:
326 return (EINVAL22);
327 }
328 rec->bps = AUDIO_BPS(rec->precision)(rec->precision) <= 8 ? 1 : ((rec->precision) <= 16
? 2 : 4)
;
329 rec->msb = 1;
330
331 error = ac97_set_rate(co->codec_if, AC97_REG_PCM_LR_ADC_RATE0x32,
332 &rec->sample_rate);
333 if (error)
334 return (error);
335 }
336
337 return (0);
338}
339
340
341/* called to translate a requested blocksize to a hw-possible one */
342int
343auixp_round_blocksize(void *v, int blk)
344{
345
346 blk = (blk + 0x1f) & ~0x1f;
347 /* Be conservative; align to 32 bytes and maximise it to 64 kb */
348 if (blk > 0x10000)
349 blk = 0x10000;
350
351 return blk;
352}
353
354
355/*
356 * allocate dma capable memory and record its information for later retrieval
357 * when we program the dma chain itself. The trigger routines passes on the
358 * kernel virtual address we return here as a reference to the mapping.
359 */
360void *
361auixp_malloc(void *hdl, int direction, size_t size, int pool, int flags)
362{
363 struct auixp_codec *co;
364 struct auixp_softc *sc;
365 struct auixp_dma *dma;
366 int error;
367
368 co = (struct auixp_codec *) hdl;
369 sc = co->sc;
370 /* get us a auixp_dma structure */
371 dma = malloc(sizeof(*dma), pool, flags);
372 if (!dma)
373 return NULL((void *)0);
374
375 /* get us a dma buffer itself */
376 error = auixp_allocmem(sc, size, 16, dma);
377 if (error) {
378 free(dma, pool, sizeof(*dma));
379 printf("%s: auixp_malloc: not enough memory\n",
380 sc->sc_dev.dv_xname);
381 return NULL((void *)0);
382 }
383 SLIST_INSERT_HEAD(&sc->sc_dma_list, dma, dma_chain)do { (dma)->dma_chain.sle_next = (&sc->sc_dma_list)
->slh_first; (&sc->sc_dma_list)->slh_first = (dma
); } while (0)
;
384
385 DPRINTF(("auixp_malloc: returning kern %p, hw 0x%08x for %d bytes "
386 "in %d segs\n", KERNADDR(dma), (u_int32_t) DMAADDR(dma), dma->size,
387 dma->nsegs)
388 );
389
390 return KERNADDR(dma)((void *)((dma)->addr));
391}
392
393/*
394 * free and release dma capable memory we allocated before and remove its
395 * recording
396 */
397void
398auixp_free(void *hdl, void *addr, int pool)
399{
400 struct auixp_codec *co;
401 struct auixp_softc *sc;
402 struct auixp_dma *dma;
403
404 co = (struct auixp_codec *) hdl;
405 sc = co->sc;
406 SLIST_FOREACH(dma, &sc->sc_dma_list, dma_chain)for((dma) = ((&sc->sc_dma_list)->slh_first); (dma) !=
((void *)0); (dma) = ((dma)->dma_chain.sle_next))
{
407 if (KERNADDR(dma)((void *)((dma)->addr)) == addr) {
408 SLIST_REMOVE(&sc->sc_dma_list, dma, auixp_dma,do { if ((&sc->sc_dma_list)->slh_first == (dma)) { do
{ ((&sc->sc_dma_list))->slh_first = ((&sc->
sc_dma_list))->slh_first->dma_chain.sle_next; } while (
0); } else { struct auixp_dma *curelm = (&sc->sc_dma_list
)->slh_first; while (curelm->dma_chain.sle_next != (dma
)) curelm = curelm->dma_chain.sle_next; curelm->dma_chain
.sle_next = curelm->dma_chain.sle_next->dma_chain.sle_next
; } ((dma)->dma_chain.sle_next) = ((void *)-1); } while (0
)
409 dma_chain)do { if ((&sc->sc_dma_list)->slh_first == (dma)) { do
{ ((&sc->sc_dma_list))->slh_first = ((&sc->
sc_dma_list))->slh_first->dma_chain.sle_next; } while (
0); } else { struct auixp_dma *curelm = (&sc->sc_dma_list
)->slh_first; while (curelm->dma_chain.sle_next != (dma
)) curelm = curelm->dma_chain.sle_next; curelm->dma_chain
.sle_next = curelm->dma_chain.sle_next->dma_chain.sle_next
; } ((dma)->dma_chain.sle_next) = ((void *)-1); } while (0
)
;
410 auixp_freemem(sc, dma);
411 free(dma, pool, sizeof(*dma));
412 return;
413 }
414 }
415}
416
417/* pass request to AC'97 codec code */
418int
419auixp_set_port(void *hdl, mixer_ctrl_t *mc)
420{
421 struct auixp_codec *co;
422
423 co = (struct auixp_codec *) hdl;
424 return co->codec_if->vtbl->mixer_set_port(co->codec_if, mc);
425}
426
427
428/* pass request to AC'97 codec code */
429int
430auixp_get_port(void *hdl, mixer_ctrl_t *mc)
431{
432 struct auixp_codec *co;
433
434 co = (struct auixp_codec *) hdl;
435 return co->codec_if->vtbl->mixer_get_port(co->codec_if, mc);
436}
437
438/* pass request to AC'97 codec code */
439int
440auixp_query_devinfo(void *hdl, mixer_devinfo_t *di)
441{
442 struct auixp_codec *co;
443
444 co = (struct auixp_codec *) hdl;
445 return co->codec_if->vtbl->query_devinfo(co->codec_if, di);
446}
447
448int
449auixp_get_props(void *hdl)
450{
451
452 return AUDIO_PROP_MMAP0x02 | AUDIO_PROP_INDEPENDENT0x04 | AUDIO_PROP_FULLDUPLEX0x01;
453}
454
455
456/*
457 * A dma descriptor has dma->nsegs segments defined in dma->segs set up when
458 * we claimed the memory.
459 *
460 * Due to our demand for one contiguous DMA area, we only have one segment. A
461 * c_dma structure is about 3 kb for the 256 entries we maximally program
462 * -arbitrary limit AFAIK- so all is most likely to be in one segment/page
463 * anyway.
464 *
465 * XXX ought to implement fragmented dma area XXX
466 *
467 * Note that _v variables depict kernel virtual addresses, _p variables depict
468 * physical addresses.
469 */
470void
471auixp_link_daisychain(struct auixp_softc *sc,
472 struct auixp_dma *c_dma, struct auixp_dma *s_dma,
473 int blksize, int blocks)
474{
475 atiixp_dma_desc_t *caddr_v, *next_caddr_v;
476 u_int32_t caddr_p, next_caddr_p, saddr_p;
477 int i;
478
479 /* just make sure we are not changing when its running */
480 auixp_disable_dma(sc, c_dma);
481
482 /* setup dma chain start addresses */
483 caddr_v = KERNADDR(c_dma)((void *)((c_dma)->addr));
484 caddr_p = DMAADDR(c_dma)((c_dma)->map->dm_segs[0].ds_addr);
485 saddr_p = DMAADDR(s_dma)((s_dma)->map->dm_segs[0].ds_addr);
486
487 /* program the requested number of blocks */
488 for (i = 0; i < blocks; i++) {
489 /* clear the block just in case */
490 bzero(caddr_v, sizeof(atiixp_dma_desc_t))__builtin_bzero((caddr_v), (sizeof(atiixp_dma_desc_t)));
491
492 /* round robin the chain dma addresses for its successor */
493 next_caddr_v = caddr_v + 1;
494 next_caddr_p = caddr_p + sizeof(atiixp_dma_desc_t);
495
496 if (i == blocks-1) {
497 next_caddr_v = KERNADDR(c_dma)((void *)((c_dma)->addr));
498 next_caddr_p = DMAADDR(c_dma)((c_dma)->map->dm_segs[0].ds_addr);
499 }
500
501 /* fill in the hardware dma chain descriptor in little-endian */
502 caddr_v->addr = htole32(saddr_p)((__uint32_t)(saddr_p));
503 caddr_v->status = htole16(0)((__uint16_t)(0));
504 caddr_v->size = htole16((blksize >> 2))((__uint16_t)((blksize >> 2))); /* in dwords (!!!) */
505 caddr_v->next = htole32(next_caddr_p)((__uint32_t)(next_caddr_p));
506
507 /* advance slot */
508 saddr_p += blksize; /* XXX assuming contiguous XXX */
509 caddr_v = next_caddr_v;
510 caddr_p = next_caddr_p;
511 }
512}
513
514
515int
516auixp_allocate_dma_chain(struct auixp_softc *sc, struct auixp_dma **dmap)
517{
518 struct auixp_dma *dma;
519 int error;
520
521 /* allocate keeper of dma area */
522 *dmap = NULL((void *)0);
523 dma = malloc(sizeof(*dma), M_DEVBUF2, M_NOWAIT0x0002 | M_ZERO0x0008);
524 if (!dma)
525 return ENOMEM12;
526
527 /* allocate for daisychain of IXP hardware-dma descriptors */
528 error = auixp_allocmem(sc, DMA_DESC_CHAIN255 * sizeof(atiixp_dma_desc_t),
529 16, dma);
530 if (error) {
531 printf("%s: can't malloc dma descriptor chain\n",
532 sc->sc_dev.dv_xname);
533 free(dma, M_DEVBUF2, sizeof(*dma));
534 return ENOMEM12;
535 }
536
537 /* return info and initialise structure */
538 dma->intr = NULL((void *)0);
539 dma->intrarg = NULL((void *)0);
540
541 *dmap = dma;
542 return 0;
543}
544
545
546/* program dma chain in its link address descriptor */
547void
548auixp_program_dma_chain(struct auixp_softc *sc, struct auixp_dma *dma)
549{
550 bus_space_tag_t iot;
551 bus_space_handle_t ioh;
552 u_int32_t value;
553
554 iot = sc->sc_iot;
555 ioh = sc->sc_ioh;
556 /* get hardware start address of DMA chain and set valid-flag in it */
557 /* XXX always at start? XXX */
558 value = DMAADDR(dma)((dma)->map->dm_segs[0].ds_addr);
559 value = value | ATI_REG_LINKPTR_EN(1U<<0);
560
561 /* reset linkpointer */
562 bus_space_write_4(iot, ioh, dma->linkptr, 0)((iot)->write_4((ioh), (dma->linkptr), (0)));
563
564 /* reset this DMA engine */
565 auixp_disable_dma(sc, dma);
566 auixp_enable_dma(sc, dma);
567
568 /* program new DMA linkpointer */
569 bus_space_write_4(iot, ioh, dma->linkptr, value)((iot)->write_4((ioh), (dma->linkptr), (value)));
570}
571
572
573/* called from interrupt code to signal end of one dma-slot */
574void
575auixp_dma_update(struct auixp_softc *sc, struct auixp_dma *dma)
576{
577
578 /* be very paranoid */
579 if (!dma)
580 panic("auixp: update: dma = NULL");
581 if (!dma->intr)
582 panic("auixp: update: dma->intr = NULL");
583
584 /* request more input from upper layer */
585 (*dma->intr)(dma->intrarg);
586}
587
588
589/*
590 * The magic `busbusy' bit that needs to be set when dma is active; allowing
591 * busmastering?
592 */
593void
594auixp_update_busbusy(struct auixp_softc *sc)
595{
596 bus_space_tag_t iot;
597 bus_space_handle_t ioh;
598 u_int32_t value;
599 int running;
600
601 iot = sc->sc_iot;
602 ioh = sc->sc_ioh;
603 /* set bus-busy flag when either recording or playing is performed */
604 value = bus_space_read_4(iot, ioh, ATI_REG_IER)((iot)->read_4((ioh), (0x04)));
605 value &= ~ATI_REG_IER_SET_BUS_BUSY(1U<<14);
606
607 running = ((sc->sc_output_dma->running) || (sc->sc_input_dma->running));
608 if (running)
609 value |= ATI_REG_IER_SET_BUS_BUSY(1U<<14);
610
611 bus_space_write_4(iot, ioh, ATI_REG_IER, value)((iot)->write_4((ioh), (0x04), (value)));
612
613}
614
615
616/*
617 * Called from upper audio layer to request playing audio, only called once;
618 * audio is refilled by calling the intr() function when space is available
619 * again.
620 */
621/* XXX almost literally a copy of trigger-input; could be factorised XXX */
622int
623auixp_trigger_output(void *hdl, void *start, void *end, int blksize,
624 void (*intr)(void *), void *intrarg, struct audio_params *param)
625{
626 struct auixp_codec *co;
627 struct auixp_softc *sc;
628 struct auixp_dma *chain_dma;
629 struct auixp_dma *sound_dma;
630 u_int32_t blocks;
631
632 co = (struct auixp_codec *) hdl;
633 sc = co->sc;
634 chain_dma = sc->sc_output_dma;
635 /* add functions to call back */
636 chain_dma->intr = intr;
637 chain_dma->intrarg = intrarg;
638
639 /*
640 * Program output DMA chain with blocks from [start...end] with
641 * blksize fragments.
642 *
643 * NOTE, we can assume its in one block since we asked for it to be in
644 * one contiguous blob; XXX change this? XXX
645 */
646 blocks = (size_t) (((caddr_t) end) - ((caddr_t) start)) / blksize;
647
648 /* lookup `start' address in our list of DMA area's */
649 SLIST_FOREACH(sound_dma, &sc->sc_dma_list, dma_chain)for((sound_dma) = ((&sc->sc_dma_list)->slh_first); (
sound_dma) != ((void *)0); (sound_dma) = ((sound_dma)->dma_chain
.sle_next))
{
650 if (KERNADDR(sound_dma)((void *)((sound_dma)->addr)) == start)
651 break;
652 }
653
654 /* not ours ? then bail out */
655 if (!sound_dma) {
656 printf("%s: auixp_trigger_output: bad sound addr %p\n",
657 sc->sc_dev.dv_xname, start);
658 return EINVAL22;
659 }
660
661 /* link round-robin daisychain and program hardware */
662 auixp_link_daisychain(sc, chain_dma, sound_dma, blksize, blocks);
663 auixp_program_dma_chain(sc, chain_dma);
664
665 /* mark we are now able to run now */
666 mtx_enter(&audio_lock);
667 chain_dma->running = 1;
668
669 /* update bus-flags; XXX programs more flags XXX */
670 auixp_update_busbusy(sc);
671 mtx_leave(&audio_lock);
672
673 /* callbacks happen in interrupt routine */
674 return 0;
675}
676
677
678/* halt output of audio, just disable its dma and update bus state */
679int
680auixp_halt_output(void *hdl)
681{
682 struct auixp_codec *co;
683 struct auixp_softc *sc;
684 struct auixp_dma *dma;
685
686 mtx_enter(&audio_lock);
687 co = (struct auixp_codec *) hdl;
688 sc = co->sc;
689 dma = sc->sc_output_dma;
690 auixp_disable_dma(sc, dma);
691
692 dma->running = 0;
693 auixp_update_busbusy(sc);
694 mtx_leave(&audio_lock);
695 return 0;
696}
697
698
699/* XXX almost literally a copy of trigger-output; could be factorised XXX */
700int
701auixp_trigger_input(void *hdl, void *start, void *end, int blksize,
702 void (*intr)(void *), void *intrarg, struct audio_params *param)
703{
704 struct auixp_codec *co;
705 struct auixp_softc *sc;
706 struct auixp_dma *chain_dma;
707 struct auixp_dma *sound_dma;
708 u_int32_t blocks;
709
710 co = (struct auixp_codec *) hdl;
711 sc = co->sc;
712 chain_dma = sc->sc_input_dma;
713 /* add functions to call back */
714 chain_dma->intr = intr;
715 chain_dma->intrarg = intrarg;
716
717 /*
718 * Program output DMA chain with blocks from [start...end] with
719 * blksize fragments.
720 *
721 * NOTE, we can assume its in one block since we asked for it to be in
722 * one contiguous blob; XXX change this? XXX
723 */
724 blocks = (size_t) (((caddr_t) end) - ((caddr_t) start)) / blksize;
725
726 /* lookup `start' address in our list of DMA area's */
727 SLIST_FOREACH(sound_dma, &sc->sc_dma_list, dma_chain)for((sound_dma) = ((&sc->sc_dma_list)->slh_first); (
sound_dma) != ((void *)0); (sound_dma) = ((sound_dma)->dma_chain
.sle_next))
{
728 if (KERNADDR(sound_dma)((void *)((sound_dma)->addr)) == start)
729 break;
730 }
731
732 /* not ours ? then bail out */
733 if (!sound_dma) {
734 printf("%s: auixp_trigger_input: bad sound addr %p\n",
735 sc->sc_dev.dv_xname, start);
736 return EINVAL22;
737 }
738
739 /* link round-robin daisychain and program hardware */
740 auixp_link_daisychain(sc, chain_dma, sound_dma, blksize, blocks);
741 auixp_program_dma_chain(sc, chain_dma);
742
743 /* mark we are now able to run now */
744 mtx_enter(&audio_lock);
745 chain_dma->running = 1;
746
747 /* update bus-flags; XXX programs more flags XXX */
748 auixp_update_busbusy(sc);
749 mtx_leave(&audio_lock);
750
751 /* callbacks happen in interrupt routine */
752 return 0;
753}
754
755
756/* halt sampling audio, just disable its dma and update bus state */
757int
758auixp_halt_input(void *hdl)
759{
760 struct auixp_codec *co;
761 struct auixp_softc *sc;
762 struct auixp_dma *dma;
763
764 mtx_enter(&audio_lock);
765 co = (struct auixp_codec *) hdl;
766 sc = co->sc;
767 dma = sc->sc_input_dma;
768 auixp_disable_dma(sc, dma);
769
770 dma->running = 0;
771 auixp_update_busbusy(sc);
772
773 mtx_leave(&audio_lock);
774 return 0;
775}
776
777
778/*
779 * IXP audio interrupt handler
780 *
781 * note that we return the number of bits handled; the return value is not
782 * documented but I saw it implemented in other drivers. Probably returning a
783 * value > 0 means "I've dealt with it"
784 *
785 */
786int
787auixp_intr(void *softc)
788{
789 struct auixp_softc *sc;
790 bus_space_tag_t iot;
791 bus_space_handle_t ioh;
792 u_int32_t status, enable, detected_codecs;
793 int ret;
794
795 mtx_enter(&audio_lock);
796 sc = softc;
797 iot = sc->sc_iot;
798 ioh = sc->sc_ioh;
799 ret = 0;
800 /* get status from the interrupt status register */
801 status = bus_space_read_4(iot, ioh, ATI_REG_ISR)((iot)->read_4((ioh), (0x00)));
802
803 if (status == 0) {
804 mtx_leave(&audio_lock);
805 return 0;
806 }
807
808 DPRINTF(("%s: (status = %x)\n", sc->sc_dev.dv_xname, status));
809
810 /* check DMA UPDATE flags for input & output */
811 if (status & ATI_REG_ISR_IN_STATUS(1U<<1)) {
812 ret++; DPRINTF(("IN_STATUS\n"));
813 auixp_dma_update(sc, sc->sc_input_dma);
814 }
815 if (status & ATI_REG_ISR_OUT_STATUS(1U<<3)) {
816 ret++; DPRINTF(("OUT_STATUS\n"));
817 auixp_dma_update(sc, sc->sc_output_dma);
818 }
819
820 /* XXX XRUN flags not used/needed yet; should i implement it? XXX */
821 /* acknowledge the interrupts nevertheless */
822 if (status & ATI_REG_ISR_IN_XRUN(1U<<0)) {
823 ret++; DPRINTF(("IN_XRUN\n"));
824 /* auixp_dma_xrun(sc, sc->sc_input_dma); */
825 }
826 if (status & ATI_REG_ISR_OUT_XRUN(1U<<2)) {
827 ret++; DPRINTF(("OUT_XRUN\n"));
828 /* auixp_dma_xrun(sc, sc->sc_output_dma); */
829 }
830
831 /* check if we are looking for codec detection */
832 if (status & CODEC_CHECK_BITS(((1U<<10) | (1U<<11) | (1U<<12))|(1U<<
13))
) {
833 ret++;
834 /* mark missing codecs as not ready */
835 detected_codecs = status & CODEC_CHECK_BITS(((1U<<10) | (1U<<11) | (1U<<12))|(1U<<
13))
;
836 sc->sc_codec_not_ready_bits |= detected_codecs;
837
838 /* disable detected interrupt sources */
839 enable = bus_space_read_4(iot, ioh, ATI_REG_IER)((iot)->read_4((ioh), (0x04)));
840 enable &= ~detected_codecs;
841 bus_space_write_4(iot, ioh, ATI_REG_IER, enable)((iot)->write_4((ioh), (0x04), (enable)));
842 }
843
844 /* acknowledge interrupt sources */
845 bus_space_write_4(iot, ioh, ATI_REG_ISR, status)((iot)->write_4((ioh), (0x00), (status)));
846 mtx_leave(&audio_lock);
847 return ret;
848}
849
850
851/* allocate memory for dma purposes; on failure of any of the steps, roll back */
852int
853auixp_allocmem(struct auixp_softc *sc, size_t size,
854 size_t align, struct auixp_dma *dma)
855{
856 int error;
857
858 /* remember size */
859 dma->size = size;
860
861 /* allocate DMA safe memory but in just one segment for now :( */
862 error = bus_dmamem_alloc(sc->sc_dmat, dma->size, align, 0,(*(sc->sc_dmat)->_dmamem_alloc)((sc->sc_dmat), (dma->
size), (align), (0), (dma->segs), (sizeof(dma->segs) / sizeof
(dma->segs[0])), (&dma->nsegs), (0x0001))
863 dma->segs, sizeof(dma->segs) / sizeof(dma->segs[0]), &dma->nsegs,(*(sc->sc_dmat)->_dmamem_alloc)((sc->sc_dmat), (dma->
size), (align), (0), (dma->segs), (sizeof(dma->segs) / sizeof
(dma->segs[0])), (&dma->nsegs), (0x0001))
864 BUS_DMA_NOWAIT)(*(sc->sc_dmat)->_dmamem_alloc)((sc->sc_dmat), (dma->
size), (align), (0), (dma->segs), (sizeof(dma->segs) / sizeof
(dma->segs[0])), (&dma->nsegs), (0x0001))
;
865 if (error)
866 return error;
867
868 /*
869 * map allocated memory into kernel virtual address space and keep it
870 * coherent with the CPU.
871 */
872 error = bus_dmamem_map(sc->sc_dmat, dma->segs, dma->nsegs, dma->size,(*(sc->sc_dmat)->_dmamem_map)((sc->sc_dmat), (dma->
segs), (dma->nsegs), (dma->size), (&dma->addr), (
0x0001 | 0x0004))
873 &dma->addr, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)(*(sc->sc_dmat)->_dmamem_map)((sc->sc_dmat), (dma->
segs), (dma->nsegs), (dma->size), (&dma->addr), (
0x0001 | 0x0004))
;
874 if (error)
875 goto free;
876
877 /* allocate associated dma handle and initialize it. */
878 error = bus_dmamap_create(sc->sc_dmat, dma->size, 1, dma->size, 0,(*(sc->sc_dmat)->_dmamap_create)((sc->sc_dmat), (dma
->size), (1), (dma->size), (0), (0x0001), (&dma->
map))
879 BUS_DMA_NOWAIT, &dma->map)(*(sc->sc_dmat)->_dmamap_create)((sc->sc_dmat), (dma
->size), (1), (dma->size), (0), (0x0001), (&dma->
map))
;
880 if (error)
881 goto unmap;
882
883 /*
884 * load the dma handle with mappings for a dma transfer; all pages
885 * need to be wired.
886 */
887 error = bus_dmamap_load(sc->sc_dmat, dma->map, dma->addr, dma->size, NULL,(*(sc->sc_dmat)->_dmamap_load)((sc->sc_dmat), (dma->
map), (dma->addr), (dma->size), (((void *)0)), (0x0001)
)
888 BUS_DMA_NOWAIT)(*(sc->sc_dmat)->_dmamap_load)((sc->sc_dmat), (dma->
map), (dma->addr), (dma->size), (((void *)0)), (0x0001)
)
;
889 if (error)
890 goto destroy;
891
892 return 0;
893
894destroy:
895 bus_dmamap_destroy(sc->sc_dmat, dma->map)(*(sc->sc_dmat)->_dmamap_destroy)((sc->sc_dmat), (dma
->map))
;
896unmap:
897 bus_dmamem_unmap(sc->sc_dmat, dma->addr, dma->size)(*(sc->sc_dmat)->_dmamem_unmap)((sc->sc_dmat), (dma->
addr), (dma->size))
;
898free:
899 bus_dmamem_free(sc->sc_dmat, dma->segs, dma->nsegs)(*(sc->sc_dmat)->_dmamem_free)((sc->sc_dmat), (dma->
segs), (dma->nsegs))
;
900
901 return error;
902}
903
904
905/* undo dma mapping and release memory allocated */
906int
907auixp_freemem(struct auixp_softc *sc, struct auixp_dma *p)
908{
909
910 bus_dmamap_unload(sc->sc_dmat, p->map)(*(sc->sc_dmat)->_dmamap_unload)((sc->sc_dmat), (p->
map))
;
911 bus_dmamap_destroy(sc->sc_dmat, p->map)(*(sc->sc_dmat)->_dmamap_destroy)((sc->sc_dmat), (p->
map))
;
912 bus_dmamem_unmap(sc->sc_dmat, p->addr, p->size)(*(sc->sc_dmat)->_dmamem_unmap)((sc->sc_dmat), (p->
addr), (p->size))
;
913 bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs)(*(sc->sc_dmat)->_dmamem_free)((sc->sc_dmat), (p->
segs), (p->nsegs))
;
914
915 return 0;
916}
917
918int
919auixp_match(struct device *dev, void *match, void *aux)
920{
921 return (pci_matchbyid((struct pci_attach_args *)aux, auixp_pci_devices,
922 sizeof(auixp_pci_devices)/sizeof(auixp_pci_devices[0])));
923}
924
925int
926auixp_activate(struct device *self, int act)
927{
928 struct auixp_softc *sc = (struct auixp_softc *)self;
929 int rv = 0;
930
931 switch (act) {
932 case DVACT_SUSPEND3:
933 auixp_disable_interrupts(sc);
934 break;
935 case DVACT_RESUME4:
936 auixp_init(sc);
937 ac97_resume(&sc->sc_codec.host_if, sc->sc_codec.codec_if);
938 rv = config_activate_children(self, act);
939 break;
940 default:
941 rv = config_activate_children(self, act);
942 break;
943 }
944 return (rv);
945}
946
947void
948auixp_attach(struct device *parent, struct device *self, void *aux)
949{
950 struct auixp_softc *sc;
951 struct pci_attach_args *pa;
952 pcitag_t tag;
953 pci_chipset_tag_t pc;
954 pci_intr_handle_t ih;
955 const char *intrstr;
956
957 sc = (struct auixp_softc *)self;
958 pa = (struct pci_attach_args *)aux;
959 tag = pa->pa_tag;
960 pc = pa->pa_pc;
961
962 /* map memory; its not sized -> what is the size? max PCI slot size? */
963 if (pci_mapreg_map(pa, PCI_CBIO0x10, PCI_MAPREG_TYPE_MEM0x00000000, 0,
964 &sc->sc_iot, &sc->sc_ioh, &sc->sc_iob, &sc->sc_ios, 0)) {
965 printf(": can't map mem space\n");
966 return;
967 }
968
969 /* Initialize softc */
970 sc->sc_tag = tag;
971 sc->sc_pct = pc;
972 sc->sc_dmat = pa->pa_dmat;
973 SLIST_INIT(&sc->sc_dma_list){ ((&sc->sc_dma_list)->slh_first) = ((void *)0); };
974
975 /* get us the auixp_dma structures */
976 auixp_allocate_dma_chain(sc, &sc->sc_output_dma);
977 auixp_allocate_dma_chain(sc, &sc->sc_input_dma);
978
979 /* when that fails we are dead in the water */
980 if (!sc->sc_output_dma || !sc->sc_input_dma)
981 return;
982
983#if 0
984 /* could preliminary program DMA chain */
985 auixp_program_dma_chain(sc, sc->sc_output_dma);
986 auixp_program_dma_chain(sc, sc->sc_input_dma);
987#endif
988
989 if (pci_intr_map(pa, &ih)) {
990 printf(": can't map interrupt\n");
991 return;
992 }
993 intrstr = pci_intr_string(pc, ih);
994 sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO0xb | IPL_MPSAFE0x100,
995 auixp_intr, sc, sc->sc_dev.dv_xname);
996 if (sc->sc_ih == NULL((void *)0)) {
997 printf(": can't establish interrupt");
998 if (intrstr != NULL((void *)0))
999 printf(" at %s", intrstr);
1000 printf("\n");
1001 return;
1002 }
1003 printf(": %s\n", intrstr);
1004
1005 /* power up chip */
1006 pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D00x0000);
1007
1008 /* init chip */
1009 if (auixp_init(sc) == -1) {
1010 printf("%s: auixp_attach: unable to initialize the card\n",
1011 sc->sc_dev.dv_xname);
1012 return;
1013 }
1014
1015 /*
1016 * delay further configuration of codecs and audio after interrupts
1017 * are enabled.
1018 */
1019 config_mountroot(self, auixp_post_config);
1020}
1021
1022/* called from autoconfigure system when interrupts are enabled */
1023void
1024auixp_post_config(struct device *self)
1025{
1026 struct auixp_softc *sc = (struct auixp_softc *)self;
1027
1028 /* detect the AC97 codecs */
1029 auixp_autodetect_codecs(sc);
1030
1031 /* Bail if no codecs attached. */
1032 if (!sc->sc_codec.present) {
1033 printf("%s: no codecs detected or initialised\n",
1034 sc->sc_dev.dv_xname);
1035 return;
1036 }
1037
1038 audio_attach_mi(&auixp_hw_if, &sc->sc_codec, &sc->sc_dev);
1039
1040 if (sc->has_spdif)
1041 sc->has_spdif = 0;
1042
1043 /* fill in the missing details about the dma channels. */
1044 /* for output */
1045 sc->sc_output_dma->linkptr = ATI_REG_OUT_DMA_LINKPTR0x38;
1046 sc->sc_output_dma->dma_enable_bit = ATI_REG_CMD_OUT_DMA_EN(1U<<9) |
1047 ATI_REG_CMD_SEND_EN(1U<<2);
1048 /* have spdif? then this too! XXX not seeing LED yet! XXX */
1049 if (sc->has_spdif)
1050 sc->sc_output_dma->dma_enable_bit |= ATI_REG_CMD_SPDF_OUT_EN(1U<<4);
1051
1052 /* and for input */
1053 sc->sc_input_dma->linkptr = ATI_REG_IN_DMA_LINKPTR0x20;
1054 sc->sc_input_dma->dma_enable_bit = ATI_REG_CMD_IN_DMA_EN(1U<<8) |
1055 ATI_REG_CMD_RECEIVE_EN(1U<<1);
1056
1057 /* done! now enable all interrupts we can service */
1058 auixp_enable_interrupts(sc);
1059}
1060
1061void
1062auixp_enable_interrupts(struct auixp_softc *sc)
1063{
1064 bus_space_tag_t iot;
1065 bus_space_handle_t ioh;
1066 u_int32_t value;
1067
1068 iot = sc->sc_iot;
1069 ioh = sc->sc_ioh;
1070 /* clear all pending */
1071 bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff)((iot)->write_4((ioh), (0x00), (0xffffffff)));
1072
1073 /* enable all relevant interrupt sources we can handle */
1074 value = bus_space_read_4(iot, ioh, ATI_REG_IER)((iot)->read_4((ioh), (0x04)));
1075
1076 value |= ATI_REG_IER_IO_STATUS_EN(1U<<1);
1077
1078 bus_space_write_4(iot, ioh, ATI_REG_IER, value)((iot)->write_4((ioh), (0x04), (value)));
1079}
1080
1081void
1082auixp_disable_interrupts(struct auixp_softc *sc)
1083{
1084 bus_space_tag_t iot;
1085 bus_space_handle_t ioh;
1086
1087 iot = sc->sc_iot;
1088 ioh = sc->sc_ioh;
1089 /* disable all interrupt sources */
1090 bus_space_write_4(iot, ioh, ATI_REG_IER, 0)((iot)->write_4((ioh), (0x04), (0)));
1091
1092 /* clear all pending */
1093 bus_space_write_4(iot, ioh, ATI_REG_ISR, 0xffffffff)((iot)->write_4((ioh), (0x00), (0xffffffff)));
1094}
1095
1096/* dismantle what we've set up by undoing setup */
1097int
1098auixp_detach(struct device *self, int flags)
1099{
1100 struct auixp_softc *sc;
1101
1102 sc = (struct auixp_softc *)self;
1103 /* XXX shouldn't we just reset the chip? XXX */
1104 /*
1105 * should we explicitly disable interrupt generation and acknowledge
1106 * what's left on? better be safe than sorry.
1107 */
1108 auixp_disable_interrupts(sc);
1109
1110 /* tear down .... */
1111 config_detach(&sc->sc_dev, flags); /* XXX OK? XXX */
1112
1113 if (sc->sc_ih != NULL((void *)0))
1114 pci_intr_disestablish(sc->sc_pct, sc->sc_ih);
1115 if (sc->sc_ios)
1116 bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
1117 return 0;
1118}
1119
1120
1121/*
1122 * codec handling
1123 *
1124 * IXP audio support can have upto 3 codecs! are they chained ? or
1125 * alternative outlets with the same audio feed i.e. with different mixer
1126 * settings? XXX does NetBSD support more than one audio codec? XXX
1127 */
1128
1129
1130int
1131auixp_attach_codec(void *aux, struct ac97_codec_if *codec_if)
1132{
1133 struct auixp_codec *ixp_codec;
1134
1135 ixp_codec = aux;
1136 ixp_codec->codec_if = codec_if;
1137
1138 return 0;
1139}
1140
1141int
1142auixp_read_codec(void *aux, u_int8_t reg, u_int16_t *result)
1143{
1144 struct auixp_codec *co;
1145 struct auixp_softc *sc;
1146 bus_space_tag_t iot;
1147 bus_space_handle_t ioh;
1148 u_int32_t data;
1149 int timeout;
1150
1151 co = aux;
1152 sc = co->sc;
1153 iot = sc->sc_iot;
1154 ioh = sc->sc_ioh;
1155 if (auixp_wait_for_codecs(sc, "read_codec"))
1156 return 0xffff;
1157
1158 /* build up command for reading codec register */
1159 data = (reg << ATI_REG_PHYS_OUT_ADDR_SHIFT9) |
1160 ATI_REG_PHYS_OUT_ADDR_EN(1U<<8) |
1161 ATI_REG_PHYS_OUT_RW(1U<<2) |
1162 co->codec_nr;
1163
1164 bus_space_write_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR, data)((iot)->write_4((ioh), (0x0c), (data)));
1165
1166 if (auixp_wait_for_codecs(sc, "read_codec"))
1167 return 0xffff;
1168
1169 /* wait until codec info is clocked in */
1170 timeout = 500; /* 500*2 usec -> 0.001 sec */
1171 do {
1172 data = bus_space_read_4(iot, ioh, ATI_REG_PHYS_IN_ADDR)((iot)->read_4((ioh), (0x10)));
1173 if (data & ATI_REG_PHYS_IN_READ_FLAG(1U<<8)) {
1174 DPRINTF(("read ac'97 codec reg 0x%x = 0x%08x\n",
1175 reg, data >> ATI_REG_PHYS_IN_DATA_SHIFT));
1176 *result = data >> ATI_REG_PHYS_IN_DATA_SHIFT16;
1177 return 0;
1178 }
1179 DELAY(2)(*delay_func)(2);
1180 timeout--;
1181 } while (timeout > 0);
1182
1183 if (reg < 0x7c)
1184 printf("%s: codec read timeout! (reg %x)\n",
1185 sc->sc_dev.dv_xname, reg);
1186
1187 return 0xffff;
1188}
1189
1190int
1191auixp_write_codec(void *aux, u_int8_t reg, u_int16_t data)
1192{
1193 struct auixp_codec *co;
1194 struct auixp_softc *sc;
1195 bus_space_tag_t iot;
1196 bus_space_handle_t ioh;
1197 u_int32_t value;
1198
1199 DPRINTF(("write ac'97 codec reg 0x%x = 0x%08x\n", reg, data));
1200 co = aux;
1201 sc = co->sc;
1202 iot = sc->sc_iot;
1203 ioh = sc->sc_ioh;
1204 if (auixp_wait_for_codecs(sc, "write_codec"))
1205 return -1;
1206
1207 /* build up command for writing codec register */
1208 value = (((u_int32_t) data) << ATI_REG_PHYS_OUT_DATA_SHIFT16) |
1209 (((u_int32_t) reg) << ATI_REG_PHYS_OUT_ADDR_SHIFT9) |
1210 ATI_REG_PHYS_OUT_ADDR_EN(1U<<8) |
1211 co->codec_nr;
1212
1213 bus_space_write_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR, value)((iot)->write_4((ioh), (0x0c), (value)));
1214
1215 return 0;
1216}
1217
1218void
1219auixp_reset_codec(void *aux)
1220{
1221
1222 /* nothing to be done? */
1223}
1224
1225enum ac97_host_flags
1226auixp_flags_codec(void *aux)
1227{
1228 struct auixp_codec *ixp_codec;
1229
1230 ixp_codec = aux;
1231 return ixp_codec->codec_flags;
1232}
1233
1234int
1235auixp_wait_for_codecs(struct auixp_softc *sc, const char *func)
1236{
1237 bus_space_tag_t iot;
1238 bus_space_handle_t ioh;
1239 u_int32_t value;
1240 int timeout;
1241
1242 iot = sc->sc_iot;
1243 ioh = sc->sc_ioh;
1244 /* wait until all codec transfers are done */
1245 timeout = 500; /* 500*2 usec -> 0.001 sec */
1246 do {
1247 value = bus_space_read_4(iot, ioh, ATI_REG_PHYS_OUT_ADDR)((iot)->read_4((ioh), (0x0c)));
1248 if ((value & ATI_REG_PHYS_OUT_ADDR_EN(1U<<8)) == 0)
1249 return 0;
1250
1251 DELAY(2)(*delay_func)(2);
1252 timeout--;
1253 } while (timeout > 0);
1254
1255 printf("%s: %s: timed out\n", func, sc->sc_dev.dv_xname);
1256 return -1;
1257}
1258
1259void
1260auixp_autodetect_codecs(struct auixp_softc *sc)
1261{
1262 bus_space_tag_t iot;
1263 bus_space_handle_t ioh;
1264 pcireg_t subdev;
1265 struct auixp_codec *codec;
1266 int timeout;
1267
1268 iot = sc->sc_iot;
1269 ioh = sc->sc_ioh;
1270 subdev = pci_conf_read(sc->sc_pct, sc->sc_tag, PCI_SUBSYS_ID_REG0x2c);
1271
1272 /* ATI IXP can have upto 3 codecs; mark all codecs as not existing */
1273 sc->sc_codec_not_ready_bits = 0;
1274
1275 /* enable all codecs to interrupt as well as the new frame interrupt */
1276 bus_space_write_4(iot, ioh, ATI_REG_IER, CODEC_CHECK_BITS)((iot)->write_4((ioh), (0x04), ((((1U<<10) | (1U<<
11) | (1U<<12))|(1U<<13)))))
;
1277
1278 /* wait for the interrupts to happen */
1279 timeout = 100; /* 100.000 usec -> 0.1 sec */
1280
1281 while (timeout > 0) {
1282 DELAY(1000)(*delay_func)(1000);
1283 if (sc->sc_codec_not_ready_bits)
1284 break;
1285 timeout--;
1286 }
1287
1288 if (timeout == 0)
1289 printf("%s: WARNING: timeout during codec detection; "
1290 "codecs might be present but haven't interrupted\n",
1291 sc->sc_dev.dv_xname);
1292
1293 /* disable all interrupts for now */
1294 auixp_disable_interrupts(sc);
1295
1296 /* Attach AC97 host interfaces */
1297 codec = &sc->sc_codec;
1298 bzero(codec, sizeof(struct auixp_codec))__builtin_bzero((codec), (sizeof(struct auixp_codec)));
1299
1300 codec->sc = sc;
1301
1302 codec->host_if.arg = codec;
1303 codec->host_if.attach = auixp_attach_codec;
1304 codec->host_if.read = auixp_read_codec;
1305 codec->host_if.write = auixp_write_codec;
1306 codec->host_if.reset = auixp_reset_codec;
1307 codec->host_if.flags = auixp_flags_codec;
1308 switch (subdev) {
1309 case 0x1311462: /* MSI S270 */
1310 case 0x1611462: /* LG K1 Express */
1311 case 0x3511462: /* MSI L725 */
1312 case 0x4711462: /* MSI L720 */
1313 case 0x0611462: /* MSI S250 */
1314 codec->codec_flags = AC97_HOST_ALC650_PIN47_IS_EAPD;
1315 break;
1316 }
1317
1318 if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC0_NOT_READY(1U<<10))) {
1319 /* codec 0 present */
1320 DPRINTF(("auixp : YAY! codec 0 present!\n"));
1321 if (ac97_attach(&sc->sc_codec.host_if) == 0) {
1322 sc->sc_codec.codec_nr = 0;
1323 sc->sc_codec.present = 1;
1324 return;
1325 }
1326 }
1327
1328 if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC1_NOT_READY(1U<<11))) {
1329 /* codec 1 present */
1330 DPRINTF(("auixp : YAY! codec 1 present!\n"));
1331 if (ac97_attach(&sc->sc_codec.host_if) == 0) {
1332 sc->sc_codec.codec_nr = 1;
1333 sc->sc_codec.present = 1;
1334 return;
1335 }
1336 }
1337
1338 if (!(sc->sc_codec_not_ready_bits & ATI_REG_ISR_CODEC2_NOT_READY(1U<<12))) {
1339 /* codec 2 present */
1340 DPRINTF(("auixp : YAY! codec 2 present!\n"));
1341 if (ac97_attach(&sc->sc_codec.host_if) == 0) {
1342 sc->sc_codec.codec_nr = 2;
1343 sc->sc_codec.present = 1;
1344 return;
1345 }
1346 }
1347}
1348
1349void
1350auixp_disable_dma(struct auixp_softc *sc, struct auixp_dma *dma)
1351{
1352 bus_space_tag_t iot;
1353 bus_space_handle_t ioh;
1354 u_int32_t value;
1355
1356 iot = sc->sc_iot;
1357 ioh = sc->sc_ioh;
1358 /* lets not stress the DMA engine more than necessary */
1359 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
1360 if (value & dma->dma_enable_bit) {
1361 value &= ~dma->dma_enable_bit;
1362 bus_space_write_4(iot, ioh, ATI_REG_CMD, value)((iot)->write_4((ioh), (0x08), (value)));
1363 }
1364}
1365
1366void
1367auixp_enable_dma(struct auixp_softc *sc, struct auixp_dma *dma)
1368{
1369 bus_space_tag_t iot;
1370 bus_space_handle_t ioh;
1371 u_int32_t value;
1372
1373 iot = sc->sc_iot;
1374 ioh = sc->sc_ioh;
1375 /* lets not stress the DMA engine more than necesssary */
1376 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
1377 if (!(value & dma->dma_enable_bit)) {
1378 value |= dma->dma_enable_bit;
1379 bus_space_write_4(iot, ioh, ATI_REG_CMD, value)((iot)->write_4((ioh), (0x08), (value)));
1380 }
1381}
1382
1383void
1384auixp_reset_aclink(struct auixp_softc *sc)
1385{
1386 bus_space_tag_t iot;
1387 bus_space_handle_t ioh;
1388 u_int32_t value, timeout;
1389
1390 iot = sc->sc_iot;
1391 ioh = sc->sc_ioh;
1392
1393 /* if power is down, power it up */
1394 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
1395 if (value & ATI_REG_CMD_POWERDOWN(1U<<0)) {
1396 printf("%s: powering up\n", sc->sc_dev.dv_xname);
1397
1398 /* explicitly enable power */
1399 value &= ~ATI_REG_CMD_POWERDOWN(1U<<0);
1400 bus_space_write_4(iot, ioh, ATI_REG_CMD, value)((iot)->write_4((ioh), (0x08), (value)));
1401
1402 /* have to wait at least 10 usec for it to initialise */
1403 DELAY(20)(*delay_func)(20);
1404 };
1405
1406 printf("%s: soft resetting aclink\n", sc->sc_dev.dv_xname);
1407
1408 /* perform a soft reset */
1409 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
1410 value |= ATI_REG_CMD_AC_SOFT_RESET(1U<<29);
1411 bus_space_write_4(iot, ioh, ATI_REG_CMD, value)((iot)->write_4((ioh), (0x08), (value)));
1412
1413 /* need to read the CMD reg and wait aprox. 10 usec to init */
1414 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
1415 DELAY(20)(*delay_func)(20);
1416
1417 /* clear soft reset flag again */
1418 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
1419 value &= ~ATI_REG_CMD_AC_SOFT_RESET(1U<<29);
1420 bus_space_write_4(iot, ioh, ATI_REG_CMD, value)((iot)->write_4((ioh), (0x08), (value)));
1421
1422 /* check if the ac-link is working; reset device otherwise */
1423 timeout = 10;
1424 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
1425 while (!(value & ATI_REG_CMD_ACLINK_ACTIVE(1U<<28))) {
1426 printf("%s: not up; resetting aclink hardware\n",
1427 sc->sc_dev.dv_xname);
1428
1429 /* dip aclink reset but keep the acsync */
1430 value &= ~ATI_REG_CMD_AC_RESET(1U<<31);
1431 value |= ATI_REG_CMD_AC_SYNC(1U<<30);
1432 bus_space_write_4(iot, ioh, ATI_REG_CMD, value)((iot)->write_4((ioh), (0x08), (value)));
1433
1434 /* need to read CMD again and wait again (clocking in issue?) */
1435 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
Value stored to 'value' is never read
1436 DELAY(20)(*delay_func)(20);
1437
1438 /* assert aclink reset again */
1439 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
1440 value |= ATI_REG_CMD_AC_RESET(1U<<31);
1441 bus_space_write_4(iot, ioh, ATI_REG_CMD, value)((iot)->write_4((ioh), (0x08), (value)));
1442
1443 /* check if its active now */
1444 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
1445
1446 timeout--;
1447 if (timeout == 0) break;
1448 };
1449
1450 if (timeout == 0) {
1451 printf("%s: giving up aclink reset\n", sc->sc_dev.dv_xname);
1452 };
1453 if (timeout != 10) {
1454 printf("%s: aclink hardware reset successful\n",
1455 sc->sc_dev.dv_xname);
1456 };
1457
1458 /* assert reset and sync for safety */
1459 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
1460 value |= ATI_REG_CMD_AC_SYNC(1U<<30) | ATI_REG_CMD_AC_RESET(1U<<31);
1461 bus_space_write_4(iot, ioh, ATI_REG_CMD, value)((iot)->write_4((ioh), (0x08), (value)));
1462}
1463
1464/* chip hard init */
1465int
1466auixp_init(struct auixp_softc *sc)
1467{
1468 bus_space_tag_t iot;
1469 bus_space_handle_t ioh;
1470 u_int32_t value;
1471
1472 iot = sc->sc_iot;
1473 ioh = sc->sc_ioh;
1474 /* disable all interrupts and clear all sources */
1475 auixp_disable_interrupts(sc);
1476
1477 /* clear all DMA enables (preserving rest of settings) */
1478 value = bus_space_read_4(iot, ioh, ATI_REG_CMD)((iot)->read_4((ioh), (0x08)));
1479 value &= ~( ATI_REG_CMD_IN_DMA_EN(1U<<8) |
1480 ATI_REG_CMD_OUT_DMA_EN(1U<<9) |
1481 ATI_REG_CMD_SPDF_OUT_EN(1U<<4) );
1482 bus_space_write_4(iot, ioh, ATI_REG_CMD, value)((iot)->write_4((ioh), (0x08), (value)));
1483
1484 /* Reset AC-link */
1485 auixp_reset_aclink(sc);
1486
1487 /*
1488 * codecs get auto-detected later
1489 *
1490 * note: we are NOT enabling interrupts yet, no codecs have been
1491 * detected yet nor is anything else set up
1492 */
1493
1494 return 0;
1495}