Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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