neo.c revision 1.19.2.8 1 1.19.2.8 skrll /* $NetBSD: neo.c,v 1.19.2.8 2005/11/10 14:06:02 skrll Exp $ */
2 1.1 thorpej
3 1.1 thorpej /*
4 1.1 thorpej * Copyright (c) 1999 Cameron Grant <gandalf (at) vilnya.demon.co.uk>
5 1.1 thorpej * All rights reserved.
6 1.1 thorpej *
7 1.1 thorpej * Derived from the public domain Linux driver
8 1.1 thorpej *
9 1.1 thorpej * Redistribution and use in source and binary forms, with or without
10 1.1 thorpej * modification, are permitted provided that the following conditions
11 1.1 thorpej * are met:
12 1.1 thorpej * 1. Redistributions of source code must retain the above copyright
13 1.1 thorpej * notice, this list of conditions and the following disclaimer.
14 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 thorpej * notice, this list of conditions and the following disclaimer in the
16 1.1 thorpej * documentation and/or other materials provided with the distribution.
17 1.1 thorpej *
18 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 1.1 thorpej * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 1.1 thorpej * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 1.1 thorpej * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 1.1 thorpej * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 1.1 thorpej * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 1.1 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT
26 1.1 thorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 1.1 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF
28 1.1 thorpej * SUCH DAMAGE.
29 1.1 thorpej *
30 1.1 thorpej * FreeBSD: src/sys/dev/sound/pci/neomagic.c,v 1.8 2000/03/20 15:30:50 cg Exp
31 1.1 thorpej * OpenBSD: neo.c,v 1.4 2000/07/19 09:04:37 csapuntz Exp
32 1.1 thorpej */
33 1.11 lukem
34 1.11 lukem #include <sys/cdefs.h>
35 1.19.2.8 skrll __KERNEL_RCSID(0, "$NetBSD: neo.c,v 1.19.2.8 2005/11/10 14:06:02 skrll Exp $");
36 1.1 thorpej
37 1.1 thorpej #include <sys/param.h>
38 1.1 thorpej #include <sys/systm.h>
39 1.1 thorpej #include <sys/kernel.h>
40 1.1 thorpej #include <sys/malloc.h>
41 1.1 thorpej #include <sys/device.h>
42 1.1 thorpej
43 1.1 thorpej #include <machine/bus.h>
44 1.1 thorpej
45 1.1 thorpej #include <dev/pci/pcidevs.h>
46 1.1 thorpej #include <dev/pci/pcivar.h>
47 1.1 thorpej
48 1.1 thorpej #include <dev/pci/neoreg.h>
49 1.1 thorpej #include <dev/pci/neo-coeff.h>
50 1.1 thorpej
51 1.1 thorpej #include <sys/audioio.h>
52 1.1 thorpej #include <dev/audio_if.h>
53 1.1 thorpej #include <dev/mulaw.h>
54 1.1 thorpej #include <dev/auconv.h>
55 1.1 thorpej
56 1.1 thorpej #include <dev/ic/ac97var.h>
57 1.1 thorpej
58 1.1 thorpej
59 1.1 thorpej /* -------------------------------------------------------------------- */
60 1.19.2.7 skrll /*
61 1.1 thorpej * As of 04/13/00, public documentation on the Neomagic 256 is not available.
62 1.1 thorpej * These comments were gleaned by looking at the driver carefully.
63 1.1 thorpej *
64 1.1 thorpej * The Neomagic 256 AV/ZX chips provide both video and audio capabilities
65 1.1 thorpej * on one chip. About 2-6 megabytes of memory are associated with
66 1.1 thorpej * the chip. Most of this goes to video frame buffers, but some is used for
67 1.1 thorpej * audio buffering
68 1.1 thorpej *
69 1.1 thorpej * Unlike most PCI audio chips, the Neomagic chip does not rely on DMA.
70 1.1 thorpej * Instead, the chip allows you to carve out two ring buffers out of its
71 1.1 thorpej * memory. However you carve this and how much you can carve seems to be
72 1.1 thorpej * voodoo. The algorithm is in nm_init.
73 1.1 thorpej *
74 1.19.2.7 skrll * Most Neomagic audio chips use the AC-97 codec interface. However, there
75 1.1 thorpej * seem to be a select few chips 256AV chips that do not support AC-97.
76 1.1 thorpej * This driver does not support them but there are rumors that it
77 1.12 simonb * might work with wss isa drivers. This might require some playing around
78 1.1 thorpej * with your BIOS.
79 1.1 thorpej *
80 1.1 thorpej * The Neomagic 256 AV/ZX have 2 PCI I/O region descriptors. Both of
81 1.1 thorpej * them describe a memory region. The frame buffer is the first region
82 1.1 thorpej * and the register set is the secodn region.
83 1.1 thorpej *
84 1.1 thorpej * The register manipulation logic is taken from the Linux driver,
85 1.1 thorpej * which is in the public domain.
86 1.1 thorpej *
87 1.1 thorpej * The Neomagic is even nice enough to map the AC-97 codec registers into
88 1.1 thorpej * the register space to allow direct manipulation. Watch out, accessing
89 1.1 thorpej * AC-97 registers on the Neomagic requires great delicateness, otherwise
90 1.1 thorpej * the thing will hang the PCI bus, rendering your system frozen.
91 1.1 thorpej *
92 1.1 thorpej * For one, it seems the Neomagic status register that reports AC-97
93 1.1 thorpej * readiness should NOT be polled more often than once each 1ms.
94 1.1 thorpej *
95 1.1 thorpej * Also, writes to the AC-97 register space may take order 40us to
96 1.1 thorpej * complete.
97 1.1 thorpej *
98 1.12 simonb * Unlike many sound engines, the Neomagic does not support (as far as
99 1.1 thorpej * we know :) the notion of interrupting every n bytes transferred,
100 1.1 thorpej * unlike many DMA engines. Instead, it allows you to specify one
101 1.1 thorpej * location in each ring buffer (called the watermark). When the chip
102 1.1 thorpej * passes that location while playing, it signals an interrupt.
103 1.19.2.7 skrll *
104 1.1 thorpej * The ring buffer size is currently 16k. That is about 100ms of audio
105 1.18 tsutsui * at 44.1kHz/stero/16 bit. However, to keep the buffer full, interrupts
106 1.1 thorpej * are generated more often than that, so 20-40 interrupts per second
107 1.1 thorpej * should not be unexpected. Increasing BUFFSIZE should help minimize
108 1.1 thorpej * of glitches due to drivers that spend to much time looping at high
109 1.1 thorpej * privelege levels as well as the impact of badly written audio
110 1.1 thorpej * interface clients.
111 1.1 thorpej *
112 1.1 thorpej * TO-DO list:
113 1.1 thorpej * Figure out interaction with video stuff (look at Xfree86 driver?)
114 1.1 thorpej *
115 1.1 thorpej * Figure out how to shrink that huge table neo-coeff.h
116 1.1 thorpej */
117 1.1 thorpej
118 1.1 thorpej #define NM_BUFFSIZE 16384
119 1.1 thorpej
120 1.1 thorpej /* device private data */
121 1.1 thorpej struct neo_softc {
122 1.19.2.6 skrll struct device dev;
123 1.1 thorpej
124 1.1 thorpej bus_space_tag_t bufiot;
125 1.19.2.6 skrll bus_space_handle_t bufioh;
126 1.1 thorpej
127 1.1 thorpej bus_space_tag_t regiot;
128 1.19.2.6 skrll bus_space_handle_t regioh;
129 1.1 thorpej
130 1.19.2.6 skrll uint32_t type;
131 1.19.2.6 skrll void *ih;
132 1.1 thorpej
133 1.19 wiz void (*pintr)(void *); /* DMA completion intr handler */
134 1.1 thorpej void *parg; /* arg for intr() */
135 1.1 thorpej
136 1.19 wiz void (*rintr)(void *); /* DMA completion intr handler */
137 1.1 thorpej void *rarg; /* arg for intr() */
138 1.1 thorpej
139 1.1 thorpej vaddr_t buf_vaddr;
140 1.1 thorpej vaddr_t rbuf_vaddr;
141 1.1 thorpej vaddr_t pbuf_vaddr;
142 1.1 thorpej int pbuf_allocated;
143 1.1 thorpej int rbuf_allocated;
144 1.1 thorpej
145 1.3 thorpej bus_addr_t buf_pciaddr;
146 1.3 thorpej bus_addr_t rbuf_pciaddr;
147 1.3 thorpej bus_addr_t pbuf_pciaddr;
148 1.3 thorpej
149 1.19.2.6 skrll uint32_t ac97_base, ac97_status, ac97_busy;
150 1.19.2.6 skrll uint32_t buftop, pbuf, rbuf, cbuf, acbuf;
151 1.19.2.6 skrll uint32_t playint, recint, misc1int, misc2int;
152 1.19.2.6 skrll uint32_t irsz, badintr;
153 1.1 thorpej
154 1.19.2.6 skrll uint32_t pbufsize;
155 1.19.2.6 skrll uint32_t rbufsize;
156 1.1 thorpej
157 1.19.2.6 skrll uint32_t pblksize;
158 1.19.2.6 skrll uint32_t rblksize;
159 1.1 thorpej
160 1.19.2.6 skrll uint32_t pwmark;
161 1.19.2.6 skrll uint32_t rwmark;
162 1.1 thorpej
163 1.1 thorpej struct ac97_codec_if *codec_if;
164 1.5 sommerfe struct ac97_host_if host_if;
165 1.5 sommerfe
166 1.5 sommerfe void *powerhook;
167 1.1 thorpej };
168 1.1 thorpej
169 1.1 thorpej /* -------------------------------------------------------------------- */
170 1.1 thorpej
171 1.1 thorpej /*
172 1.1 thorpej * prototypes
173 1.1 thorpej */
174 1.1 thorpej
175 1.19.2.6 skrll static int nm_waitcd(struct neo_softc *);
176 1.19.2.6 skrll static int nm_loadcoeff(struct neo_softc *, int, int);
177 1.1 thorpej static int nm_init(struct neo_softc *);
178 1.1 thorpej
179 1.19.2.8 skrll static int neo_match(struct device *, struct cfdata *, void *);
180 1.19.2.8 skrll static void neo_attach(struct device *, struct device *, void *);
181 1.19.2.8 skrll static int neo_intr(void *);
182 1.19.2.8 skrll
183 1.19.2.8 skrll static int neo_query_encoding(void *, struct audio_encoding *);
184 1.19.2.8 skrll static int neo_set_params(void *, int, int, audio_params_t *,
185 1.19.2.8 skrll audio_params_t *, stream_filter_list_t *,
186 1.19.2.8 skrll stream_filter_list_t *);
187 1.19.2.8 skrll static int neo_round_blocksize(void *, int, int, const audio_params_t *);
188 1.19.2.8 skrll static int neo_trigger_output(void *, void *, void *, int,
189 1.19.2.8 skrll void (*)(void *), void *,
190 1.19.2.8 skrll const audio_params_t *);
191 1.19.2.8 skrll static int neo_trigger_input(void *, void *, void *, int,
192 1.19.2.8 skrll void (*)(void *), void *,
193 1.19.2.8 skrll const audio_params_t *);
194 1.19.2.8 skrll static int neo_halt_output(void *);
195 1.19.2.8 skrll static int neo_halt_input(void *);
196 1.19.2.8 skrll static int neo_getdev(void *, struct audio_device *);
197 1.19.2.8 skrll static int neo_mixer_set_port(void *, mixer_ctrl_t *);
198 1.19.2.8 skrll static int neo_mixer_get_port(void *, mixer_ctrl_t *);
199 1.19.2.8 skrll static int neo_attach_codec(void *, struct ac97_codec_if *);
200 1.19.2.8 skrll static int neo_read_codec(void *, uint8_t, uint16_t *);
201 1.19.2.8 skrll static int neo_write_codec(void *, uint8_t, uint16_t);
202 1.19.2.8 skrll static int neo_reset_codec(void *);
203 1.19.2.8 skrll static enum ac97_host_flags neo_flags_codec(void *);
204 1.19.2.8 skrll static int neo_query_devinfo(void *, mixer_devinfo_t *);
205 1.19.2.8 skrll static void * neo_malloc(void *, int, size_t, struct malloc_type *, int);
206 1.19.2.8 skrll static void neo_free(void *, void *, struct malloc_type *);
207 1.19.2.8 skrll static size_t neo_round_buffersize(void *, int, size_t);
208 1.19.2.8 skrll static paddr_t neo_mappage(void *, void *, off_t, int);
209 1.19.2.8 skrll static int neo_get_props(void *);
210 1.19.2.8 skrll static void neo_power(int, void *);
211 1.1 thorpej
212 1.15 thorpej CFATTACH_DECL(neo, sizeof(struct neo_softc),
213 1.16 thorpej neo_match, neo_attach, NULL, NULL);
214 1.1 thorpej
215 1.19.2.8 skrll static struct audio_device neo_device = {
216 1.1 thorpej "NeoMagic 256",
217 1.1 thorpej "",
218 1.1 thorpej "neo"
219 1.1 thorpej };
220 1.1 thorpej
221 1.1 thorpej /* The actual rates supported by the card. */
222 1.1 thorpej static const int samplerates[9] = {
223 1.1 thorpej 8000,
224 1.1 thorpej 11025,
225 1.1 thorpej 16000,
226 1.1 thorpej 22050,
227 1.1 thorpej 24000,
228 1.1 thorpej 32000,
229 1.1 thorpej 44100,
230 1.1 thorpej 48000,
231 1.1 thorpej 99999999
232 1.1 thorpej };
233 1.1 thorpej
234 1.19.2.6 skrll #define NEO_NFORMATS 4
235 1.19.2.6 skrll static const struct audio_format neo_formats[NEO_NFORMATS] = {
236 1.19.2.6 skrll {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
237 1.19.2.6 skrll 2, AUFMT_STEREO, 8, {8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000}},
238 1.19.2.6 skrll {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
239 1.19.2.6 skrll 1, AUFMT_MONAURAL, 8, {8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000}},
240 1.19.2.6 skrll {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 8, 8,
241 1.19.2.6 skrll 2, AUFMT_STEREO, 8, {8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000}},
242 1.19.2.6 skrll {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 8, 8,
243 1.19.2.6 skrll 1, AUFMT_MONAURAL, 8, {8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000}},
244 1.19.2.6 skrll };
245 1.19.2.6 skrll
246 1.1 thorpej /* -------------------------------------------------------------------- */
247 1.1 thorpej
248 1.19.2.8 skrll static const struct audio_hw_if neo_hw_if = {
249 1.19.2.6 skrll NULL, /* open */
250 1.19.2.6 skrll NULL, /* close */
251 1.1 thorpej NULL, /* drain */
252 1.1 thorpej neo_query_encoding,
253 1.1 thorpej neo_set_params,
254 1.1 thorpej neo_round_blocksize,
255 1.1 thorpej NULL, /* commit_setting */
256 1.1 thorpej NULL, /* init_output */
257 1.1 thorpej NULL, /* init_input */
258 1.1 thorpej NULL, /* start_output */
259 1.1 thorpej NULL, /* start_input */
260 1.1 thorpej neo_halt_output,
261 1.1 thorpej neo_halt_input,
262 1.1 thorpej NULL, /* speaker_ctl */
263 1.1 thorpej neo_getdev,
264 1.1 thorpej NULL, /* getfd */
265 1.1 thorpej neo_mixer_set_port,
266 1.1 thorpej neo_mixer_get_port,
267 1.1 thorpej neo_query_devinfo,
268 1.1 thorpej neo_malloc,
269 1.1 thorpej neo_free,
270 1.1 thorpej neo_round_buffersize,
271 1.3 thorpej neo_mappage,
272 1.1 thorpej neo_get_props,
273 1.1 thorpej neo_trigger_output,
274 1.1 thorpej neo_trigger_input,
275 1.10 augustss NULL,
276 1.1 thorpej };
277 1.1 thorpej
278 1.1 thorpej /* -------------------------------------------------------------------- */
279 1.1 thorpej
280 1.1 thorpej #define nm_rd_1(sc, regno) \
281 1.1 thorpej bus_space_read_1((sc)->regiot, (sc)->regioh, (regno))
282 1.1 thorpej
283 1.1 thorpej #define nm_rd_2(sc, regno) \
284 1.1 thorpej bus_space_read_2((sc)->regiot, (sc)->regioh, (regno))
285 1.1 thorpej
286 1.1 thorpej #define nm_rd_4(sc, regno) \
287 1.1 thorpej bus_space_read_4((sc)->regiot, (sc)->regioh, (regno))
288 1.1 thorpej
289 1.1 thorpej #define nm_wr_1(sc, regno, val) \
290 1.1 thorpej bus_space_write_1((sc)->regiot, (sc)->regioh, (regno), (val))
291 1.1 thorpej
292 1.1 thorpej #define nm_wr_2(sc, regno, val) \
293 1.1 thorpej bus_space_write_2((sc)->regiot, (sc)->regioh, (regno), (val))
294 1.1 thorpej
295 1.1 thorpej #define nm_wr_4(sc, regno, val) \
296 1.1 thorpej bus_space_write_4((sc)->regiot, (sc)->regioh, (regno), (val))
297 1.1 thorpej
298 1.1 thorpej #define nm_rdbuf_4(sc, regno) \
299 1.1 thorpej bus_space_read_4((sc)->bufiot, (sc)->bufioh, (regno))
300 1.1 thorpej
301 1.1 thorpej #define nm_wrbuf_1(sc, regno, val) \
302 1.1 thorpej bus_space_write_1((sc)->bufiot, (sc)->bufioh, (regno), (val))
303 1.1 thorpej
304 1.1 thorpej /* ac97 codec */
305 1.1 thorpej static int
306 1.1 thorpej nm_waitcd(struct neo_softc *sc)
307 1.1 thorpej {
308 1.19.2.6 skrll int cnt;
309 1.19.2.6 skrll int fail;
310 1.1 thorpej
311 1.19.2.6 skrll cnt = 10;
312 1.19.2.6 skrll fail = 1;
313 1.1 thorpej while (cnt-- > 0) {
314 1.1 thorpej if (nm_rd_2(sc, sc->ac97_status) & sc->ac97_busy)
315 1.1 thorpej DELAY(100);
316 1.1 thorpej else {
317 1.19.2.6 skrll fail = 0;
318 1.1 thorpej break;
319 1.1 thorpej }
320 1.1 thorpej }
321 1.19.2.6 skrll return fail;
322 1.1 thorpej }
323 1.1 thorpej
324 1.1 thorpej static void
325 1.19.2.6 skrll nm_ackint(struct neo_softc *sc, uint32_t num)
326 1.1 thorpej {
327 1.1 thorpej
328 1.1 thorpej switch (sc->type) {
329 1.1 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
330 1.1 thorpej nm_wr_2(sc, NM_INT_REG, num << 1);
331 1.1 thorpej break;
332 1.1 thorpej
333 1.1 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
334 1.1 thorpej nm_wr_4(sc, NM_INT_REG, num);
335 1.1 thorpej break;
336 1.1 thorpej }
337 1.1 thorpej }
338 1.1 thorpej
339 1.1 thorpej static int
340 1.1 thorpej nm_loadcoeff(struct neo_softc *sc, int dir, int num)
341 1.1 thorpej {
342 1.1 thorpej int ofs, sz, i;
343 1.19.2.6 skrll uint32_t addr;
344 1.1 thorpej
345 1.1 thorpej addr = (dir == AUMODE_PLAY)? 0x01c : 0x21c;
346 1.1 thorpej if (dir == AUMODE_RECORD)
347 1.1 thorpej num += 8;
348 1.1 thorpej sz = coefficientSizes[num];
349 1.1 thorpej ofs = 0;
350 1.1 thorpej while (num-- > 0)
351 1.1 thorpej ofs+= coefficientSizes[num];
352 1.1 thorpej for (i = 0; i < sz; i++)
353 1.1 thorpej nm_wrbuf_1(sc, sc->cbuf + i, coefficients[ofs + i]);
354 1.1 thorpej nm_wr_4(sc, addr, sc->cbuf);
355 1.1 thorpej if (dir == AUMODE_PLAY)
356 1.1 thorpej sz--;
357 1.1 thorpej nm_wr_4(sc, addr + 4, sc->cbuf + sz);
358 1.1 thorpej return 0;
359 1.1 thorpej }
360 1.1 thorpej
361 1.1 thorpej /* The interrupt handler */
362 1.19.2.8 skrll static int
363 1.1 thorpej neo_intr(void *p)
364 1.1 thorpej {
365 1.19.2.6 skrll struct neo_softc *sc;
366 1.19.2.1 skrll int status, x;
367 1.19.2.6 skrll int rv;
368 1.1 thorpej
369 1.19.2.6 skrll sc = (struct neo_softc *)p;
370 1.19.2.6 skrll rv = 0;
371 1.1 thorpej status = (sc->irsz == 2) ?
372 1.1 thorpej nm_rd_2(sc, NM_INT_REG) :
373 1.1 thorpej nm_rd_4(sc, NM_INT_REG);
374 1.1 thorpej
375 1.1 thorpej if (status & sc->playint) {
376 1.1 thorpej status &= ~sc->playint;
377 1.1 thorpej
378 1.1 thorpej sc->pwmark += sc->pblksize;
379 1.1 thorpej sc->pwmark %= sc->pbufsize;
380 1.1 thorpej
381 1.1 thorpej nm_wr_4(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pwmark);
382 1.1 thorpej
383 1.1 thorpej nm_ackint(sc, sc->playint);
384 1.1 thorpej
385 1.1 thorpej if (sc->pintr)
386 1.1 thorpej (*sc->pintr)(sc->parg);
387 1.1 thorpej
388 1.1 thorpej rv = 1;
389 1.1 thorpej }
390 1.1 thorpej if (status & sc->recint) {
391 1.1 thorpej status &= ~sc->recint;
392 1.1 thorpej
393 1.1 thorpej sc->rwmark += sc->rblksize;
394 1.1 thorpej sc->rwmark %= sc->rbufsize;
395 1.19.2.8 skrll nm_wr_4(sc, NM_RBUFFER_WMARK, sc->rbuf + sc->rwmark);
396 1.1 thorpej nm_ackint(sc, sc->recint);
397 1.1 thorpej if (sc->rintr)
398 1.1 thorpej (*sc->rintr)(sc->rarg);
399 1.1 thorpej
400 1.1 thorpej rv = 1;
401 1.1 thorpej }
402 1.1 thorpej if (status & sc->misc1int) {
403 1.1 thorpej status &= ~sc->misc1int;
404 1.1 thorpej nm_ackint(sc, sc->misc1int);
405 1.1 thorpej x = nm_rd_1(sc, 0x400);
406 1.1 thorpej nm_wr_1(sc, 0x400, x | 2);
407 1.1 thorpej printf("%s: misc int 1\n", sc->dev.dv_xname);
408 1.1 thorpej rv = 1;
409 1.1 thorpej }
410 1.1 thorpej if (status & sc->misc2int) {
411 1.1 thorpej status &= ~sc->misc2int;
412 1.1 thorpej nm_ackint(sc, sc->misc2int);
413 1.1 thorpej x = nm_rd_1(sc, 0x400);
414 1.1 thorpej nm_wr_1(sc, 0x400, x & ~2);
415 1.1 thorpej printf("%s: misc int 2\n", sc->dev.dv_xname);
416 1.1 thorpej rv = 1;
417 1.1 thorpej }
418 1.1 thorpej if (status) {
419 1.1 thorpej status &= ~sc->misc2int;
420 1.1 thorpej nm_ackint(sc, sc->misc2int);
421 1.1 thorpej printf("%s: unknown int\n", sc->dev.dv_xname);
422 1.1 thorpej rv = 1;
423 1.1 thorpej }
424 1.1 thorpej
425 1.19.2.6 skrll return rv;
426 1.1 thorpej }
427 1.1 thorpej
428 1.1 thorpej /* -------------------------------------------------------------------- */
429 1.1 thorpej
430 1.1 thorpej /*
431 1.1 thorpej * Probe and attach the card
432 1.1 thorpej */
433 1.1 thorpej
434 1.1 thorpej static int
435 1.1 thorpej nm_init(struct neo_softc *sc)
436 1.1 thorpej {
437 1.19.2.6 skrll uint32_t ofs, i;
438 1.1 thorpej
439 1.1 thorpej switch (sc->type) {
440 1.1 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
441 1.1 thorpej sc->ac97_base = NM_MIXER_OFFSET;
442 1.1 thorpej sc->ac97_status = NM_MIXER_STATUS_OFFSET;
443 1.1 thorpej sc->ac97_busy = NM_MIXER_READY_MASK;
444 1.1 thorpej
445 1.1 thorpej sc->buftop = 2560 * 1024;
446 1.1 thorpej
447 1.1 thorpej sc->irsz = 2;
448 1.1 thorpej sc->playint = NM_PLAYBACK_INT;
449 1.1 thorpej sc->recint = NM_RECORD_INT;
450 1.1 thorpej sc->misc1int = NM_MISC_INT_1;
451 1.1 thorpej sc->misc2int = NM_MISC_INT_2;
452 1.1 thorpej break;
453 1.1 thorpej
454 1.1 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
455 1.1 thorpej sc->ac97_base = NM_MIXER_OFFSET;
456 1.1 thorpej sc->ac97_status = NM2_MIXER_STATUS_OFFSET;
457 1.1 thorpej sc->ac97_busy = NM2_MIXER_READY_MASK;
458 1.1 thorpej
459 1.1 thorpej sc->buftop = (nm_rd_2(sc, 0xa0b) ? 6144 : 4096) * 1024;
460 1.1 thorpej
461 1.1 thorpej sc->irsz = 4;
462 1.1 thorpej sc->playint = NM2_PLAYBACK_INT;
463 1.1 thorpej sc->recint = NM2_RECORD_INT;
464 1.1 thorpej sc->misc1int = NM2_MISC_INT_1;
465 1.1 thorpej sc->misc2int = NM2_MISC_INT_2;
466 1.1 thorpej break;
467 1.1 thorpej #ifdef DIAGNOSTIC
468 1.1 thorpej default:
469 1.1 thorpej panic("nm_init: impossible");
470 1.1 thorpej #endif
471 1.1 thorpej }
472 1.1 thorpej
473 1.1 thorpej sc->badintr = 0;
474 1.1 thorpej ofs = sc->buftop - 0x0400;
475 1.1 thorpej sc->buftop -= 0x1400;
476 1.1 thorpej
477 1.19.2.6 skrll if ((nm_rdbuf_4(sc, ofs) & NM_SIG_MASK) == NM_SIGNATURE) {
478 1.1 thorpej i = nm_rdbuf_4(sc, ofs + 4);
479 1.1 thorpej if (i != 0 && i != 0xffffffff)
480 1.1 thorpej sc->buftop = i;
481 1.1 thorpej }
482 1.1 thorpej
483 1.1 thorpej sc->cbuf = sc->buftop - NM_MAX_COEFFICIENT;
484 1.1 thorpej sc->rbuf = sc->cbuf - NM_BUFFSIZE;
485 1.1 thorpej sc->pbuf = sc->rbuf - NM_BUFFSIZE;
486 1.1 thorpej sc->acbuf = sc->pbuf - (NM_TOTAL_COEFF_COUNT * 4);
487 1.1 thorpej
488 1.1 thorpej sc->buf_vaddr = (vaddr_t) bus_space_vaddr(sc->bufiot, sc->bufioh);
489 1.1 thorpej sc->rbuf_vaddr = sc->buf_vaddr + sc->rbuf;
490 1.1 thorpej sc->pbuf_vaddr = sc->buf_vaddr + sc->pbuf;
491 1.1 thorpej
492 1.3 thorpej sc->rbuf_pciaddr = sc->buf_pciaddr + sc->rbuf;
493 1.3 thorpej sc->pbuf_pciaddr = sc->buf_pciaddr + sc->pbuf;
494 1.3 thorpej
495 1.1 thorpej nm_wr_1(sc, 0, 0x11);
496 1.1 thorpej nm_wr_1(sc, NM_RECORD_ENABLE_REG, 0);
497 1.1 thorpej nm_wr_2(sc, 0x214, 0);
498 1.1 thorpej
499 1.1 thorpej return 0;
500 1.1 thorpej }
501 1.1 thorpej
502 1.19.2.8 skrll static int
503 1.2 thorpej neo_match(struct device *parent, struct cfdata *match, void *aux)
504 1.2 thorpej {
505 1.19.2.6 skrll struct pci_attach_args *pa;
506 1.2 thorpej pcireg_t subdev;
507 1.2 thorpej
508 1.19.2.6 skrll pa = aux;
509 1.2 thorpej if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NEOMAGIC)
510 1.19.2.6 skrll return 0;
511 1.2 thorpej
512 1.2 thorpej subdev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
513 1.2 thorpej
514 1.2 thorpej switch (PCI_PRODUCT(pa->pa_id)) {
515 1.2 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
516 1.2 thorpej /*
517 1.2 thorpej * We have to weed-out the non-AC'97 versions of
518 1.2 thorpej * the chip (i.e. the ones that are known to work
519 1.2 thorpej * in WSS emulation mode), as they won't work with
520 1.2 thorpej * this driver.
521 1.2 thorpej */
522 1.2 thorpej switch (PCI_VENDOR(subdev)) {
523 1.2 thorpej case PCI_VENDOR_DELL:
524 1.2 thorpej switch (PCI_PRODUCT(subdev)) {
525 1.2 thorpej case 0x008f:
526 1.19.2.6 skrll return 0;
527 1.2 thorpej }
528 1.2 thorpej break;
529 1.2 thorpej
530 1.2 thorpej case PCI_VENDOR_HP:
531 1.2 thorpej switch (PCI_PRODUCT(subdev)) {
532 1.2 thorpej case 0x0007:
533 1.19.2.6 skrll return 0;
534 1.2 thorpej }
535 1.8 drochner break;
536 1.8 drochner
537 1.8 drochner case PCI_VENDOR_IBM:
538 1.8 drochner switch (PCI_PRODUCT(subdev)) {
539 1.8 drochner case 0x00dd:
540 1.19.2.6 skrll return 0;
541 1.8 drochner }
542 1.8 drochner break;
543 1.2 thorpej }
544 1.19.2.6 skrll return 1;
545 1.2 thorpej
546 1.2 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
547 1.19.2.6 skrll return 1;
548 1.2 thorpej }
549 1.2 thorpej
550 1.19.2.6 skrll return 0;
551 1.2 thorpej }
552 1.2 thorpej
553 1.19.2.8 skrll static void
554 1.5 sommerfe neo_power(int why, void *addr)
555 1.5 sommerfe {
556 1.19.2.6 skrll struct neo_softc *sc;
557 1.5 sommerfe
558 1.19.2.6 skrll sc = (struct neo_softc *)addr;
559 1.5 sommerfe if (why == PWR_RESUME) {
560 1.5 sommerfe nm_init(sc);
561 1.19.2.6 skrll sc->codec_if->vtbl->restore_ports(sc->codec_if);
562 1.5 sommerfe }
563 1.5 sommerfe }
564 1.5 sommerfe
565 1.19.2.8 skrll static void
566 1.1 thorpej neo_attach(struct device *parent, struct device *self, void *aux)
567 1.1 thorpej {
568 1.19.2.6 skrll struct neo_softc *sc;
569 1.19.2.6 skrll struct pci_attach_args *pa;
570 1.19.2.6 skrll pci_chipset_tag_t pc;
571 1.1 thorpej char const *intrstr;
572 1.1 thorpej pci_intr_handle_t ih;
573 1.1 thorpej pcireg_t csr;
574 1.1 thorpej
575 1.19.2.6 skrll sc = (struct neo_softc *)self;
576 1.19.2.6 skrll pa = (struct pci_attach_args *)aux;
577 1.19.2.6 skrll pc = pa->pa_pc;
578 1.19.2.6 skrll
579 1.1 thorpej sc->type = PCI_PRODUCT(pa->pa_id);
580 1.1 thorpej
581 1.1 thorpej printf(": NeoMagic 256%s audio\n",
582 1.1 thorpej sc->type == PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU ? "AV" : "ZX");
583 1.1 thorpej
584 1.1 thorpej /* Map I/O register */
585 1.1 thorpej if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM, 0,
586 1.3 thorpej &sc->bufiot, &sc->bufioh, &sc->buf_pciaddr, NULL)) {
587 1.1 thorpej printf("%s: can't map buffer\n", sc->dev.dv_xname);
588 1.1 thorpej return;
589 1.1 thorpej }
590 1.1 thorpej
591 1.13 thorpej if (pci_mapreg_map(pa, PCI_MAPREG_START + 4, PCI_MAPREG_TYPE_MEM,
592 1.13 thorpej BUS_SPACE_MAP_LINEAR, &sc->regiot, &sc->regioh, NULL, NULL)) {
593 1.1 thorpej printf("%s: can't map registers\n", sc->dev.dv_xname);
594 1.1 thorpej return;
595 1.1 thorpej }
596 1.1 thorpej
597 1.1 thorpej /* Map and establish the interrupt. */
598 1.7 sommerfe if (pci_intr_map(pa, &ih)) {
599 1.1 thorpej printf("%s: couldn't map interrupt\n", sc->dev.dv_xname);
600 1.1 thorpej return;
601 1.1 thorpej }
602 1.1 thorpej
603 1.1 thorpej intrstr = pci_intr_string(pc, ih);
604 1.1 thorpej sc->ih = pci_intr_establish(pc, ih, IPL_AUDIO, neo_intr, sc);
605 1.1 thorpej
606 1.1 thorpej if (sc->ih == NULL) {
607 1.1 thorpej printf("%s: couldn't establish interrupt",
608 1.1 thorpej sc->dev.dv_xname);
609 1.1 thorpej if (intrstr != NULL)
610 1.1 thorpej printf(" at %s", intrstr);
611 1.1 thorpej printf("\n");
612 1.1 thorpej return;
613 1.1 thorpej }
614 1.1 thorpej printf("%s: interruping at %s\n", sc->dev.dv_xname, intrstr);
615 1.1 thorpej
616 1.19.2.1 skrll if (nm_init(sc) != 0)
617 1.1 thorpej return;
618 1.1 thorpej
619 1.1 thorpej /* Enable the device. */
620 1.1 thorpej csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
621 1.1 thorpej pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
622 1.1 thorpej csr | PCI_COMMAND_MASTER_ENABLE);
623 1.1 thorpej
624 1.1 thorpej sc->host_if.arg = sc;
625 1.1 thorpej
626 1.1 thorpej sc->host_if.attach = neo_attach_codec;
627 1.1 thorpej sc->host_if.read = neo_read_codec;
628 1.1 thorpej sc->host_if.write = neo_write_codec;
629 1.1 thorpej sc->host_if.reset = neo_reset_codec;
630 1.1 thorpej sc->host_if.flags = neo_flags_codec;
631 1.1 thorpej
632 1.19.2.6 skrll if (ac97_attach(&sc->host_if, self) != 0)
633 1.1 thorpej return;
634 1.5 sommerfe
635 1.5 sommerfe sc->powerhook = powerhook_establish(neo_power, sc);
636 1.1 thorpej
637 1.1 thorpej audio_attach_mi(&neo_hw_if, sc, &sc->dev);
638 1.1 thorpej }
639 1.1 thorpej
640 1.19.2.8 skrll static int
641 1.19.2.6 skrll neo_read_codec(void *v, uint8_t a, uint16_t *d)
642 1.1 thorpej {
643 1.19.2.6 skrll struct neo_softc *sc;
644 1.19.2.6 skrll
645 1.19.2.6 skrll sc = v;
646 1.1 thorpej if (!nm_waitcd(sc)) {
647 1.1 thorpej *d = nm_rd_2(sc, sc->ac97_base + a);
648 1.1 thorpej DELAY(1000);
649 1.1 thorpej return 0;
650 1.1 thorpej }
651 1.1 thorpej
652 1.19.2.6 skrll return ENXIO;
653 1.1 thorpej }
654 1.1 thorpej
655 1.1 thorpej
656 1.19.2.8 skrll static int
657 1.1 thorpej neo_write_codec(void *v, u_int8_t a, u_int16_t d)
658 1.1 thorpej {
659 1.19.2.6 skrll struct neo_softc *sc;
660 1.19.2.6 skrll int cnt;
661 1.1 thorpej
662 1.19.2.6 skrll sc = v;
663 1.19.2.6 skrll cnt = 3;
664 1.1 thorpej if (!nm_waitcd(sc)) {
665 1.1 thorpej while (cnt-- > 0) {
666 1.1 thorpej nm_wr_2(sc, sc->ac97_base + a, d);
667 1.1 thorpej if (!nm_waitcd(sc)) {
668 1.1 thorpej DELAY(1000);
669 1.19.2.6 skrll return 0;
670 1.1 thorpej }
671 1.1 thorpej }
672 1.1 thorpej }
673 1.1 thorpej
674 1.19.2.6 skrll return ENXIO;
675 1.1 thorpej }
676 1.1 thorpej
677 1.19.2.8 skrll static int
678 1.1 thorpej neo_attach_codec(void *v, struct ac97_codec_if *codec_if)
679 1.1 thorpej {
680 1.19.2.6 skrll struct neo_softc *sc;
681 1.1 thorpej
682 1.19.2.6 skrll sc = v;
683 1.1 thorpej sc->codec_if = codec_if;
684 1.19.2.6 skrll return 0;
685 1.1 thorpej }
686 1.1 thorpej
687 1.19.2.8 skrll static int
688 1.1 thorpej neo_reset_codec(void *v)
689 1.1 thorpej {
690 1.19.2.6 skrll struct neo_softc *sc;
691 1.1 thorpej
692 1.19.2.6 skrll sc = v;
693 1.1 thorpej nm_wr_1(sc, 0x6c0, 0x01);
694 1.1 thorpej nm_wr_1(sc, 0x6cc, 0x87);
695 1.1 thorpej nm_wr_1(sc, 0x6cc, 0x80);
696 1.1 thorpej nm_wr_1(sc, 0x6cc, 0x00);
697 1.19.2.4 skrll return 0;
698 1.1 thorpej }
699 1.1 thorpej
700 1.19.2.8 skrll static enum ac97_host_flags
701 1.1 thorpej neo_flags_codec(void *v)
702 1.1 thorpej {
703 1.1 thorpej
704 1.19.2.6 skrll return AC97_HOST_DONT_READ;
705 1.1 thorpej }
706 1.1 thorpej
707 1.19.2.8 skrll static int
708 1.1 thorpej neo_query_encoding(void *addr, struct audio_encoding *fp)
709 1.1 thorpej {
710 1.1 thorpej
711 1.1 thorpej switch (fp->index) {
712 1.1 thorpej case 0:
713 1.1 thorpej strcpy(fp->name, AudioEulinear);
714 1.1 thorpej fp->encoding = AUDIO_ENCODING_ULINEAR;
715 1.1 thorpej fp->precision = 8;
716 1.1 thorpej fp->flags = 0;
717 1.19.2.6 skrll return 0;
718 1.1 thorpej case 1:
719 1.1 thorpej strcpy(fp->name, AudioEmulaw);
720 1.1 thorpej fp->encoding = AUDIO_ENCODING_ULAW;
721 1.1 thorpej fp->precision = 8;
722 1.1 thorpej fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
723 1.19.2.6 skrll return 0;
724 1.1 thorpej case 2:
725 1.1 thorpej strcpy(fp->name, AudioEalaw);
726 1.1 thorpej fp->encoding = AUDIO_ENCODING_ALAW;
727 1.1 thorpej fp->precision = 8;
728 1.1 thorpej fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
729 1.19.2.6 skrll return 0;
730 1.1 thorpej case 3:
731 1.1 thorpej strcpy(fp->name, AudioEslinear);
732 1.1 thorpej fp->encoding = AUDIO_ENCODING_SLINEAR;
733 1.1 thorpej fp->precision = 8;
734 1.1 thorpej fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
735 1.1 thorpej return (0);
736 1.1 thorpej case 4:
737 1.1 thorpej strcpy(fp->name, AudioEslinear_le);
738 1.1 thorpej fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
739 1.1 thorpej fp->precision = 16;
740 1.1 thorpej fp->flags = 0;
741 1.19.2.6 skrll return 0;
742 1.1 thorpej case 5:
743 1.1 thorpej strcpy(fp->name, AudioEulinear_le);
744 1.1 thorpej fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
745 1.1 thorpej fp->precision = 16;
746 1.1 thorpej fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
747 1.19.2.6 skrll return 0;
748 1.1 thorpej case 6:
749 1.1 thorpej strcpy(fp->name, AudioEslinear_be);
750 1.1 thorpej fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
751 1.1 thorpej fp->precision = 16;
752 1.1 thorpej fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
753 1.19.2.6 skrll return 0;
754 1.1 thorpej case 7:
755 1.1 thorpej strcpy(fp->name, AudioEulinear_be);
756 1.1 thorpej fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
757 1.1 thorpej fp->precision = 16;
758 1.1 thorpej fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
759 1.19.2.6 skrll return 0;
760 1.1 thorpej default:
761 1.19.2.6 skrll return EINVAL;
762 1.1 thorpej }
763 1.1 thorpej }
764 1.1 thorpej
765 1.1 thorpej /* Todo: don't commit settings to card until we've verified all parameters */
766 1.19.2.8 skrll static int
767 1.19.2.6 skrll neo_set_params(void *addr, int setmode, int usemode, audio_params_t *play,
768 1.19.2.6 skrll audio_params_t *rec, stream_filter_list_t *pfil, stream_filter_list_t *rfil)
769 1.1 thorpej {
770 1.19.2.6 skrll struct neo_softc *sc;
771 1.19.2.6 skrll audio_params_t *p;
772 1.19.2.6 skrll stream_filter_list_t *fil;
773 1.19.2.6 skrll uint32_t base;
774 1.19.2.6 skrll uint8_t x;
775 1.19.2.6 skrll int mode, i;
776 1.1 thorpej
777 1.19.2.6 skrll sc = addr;
778 1.19.2.6 skrll for (mode = AUMODE_RECORD; mode != -1;
779 1.1 thorpej mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
780 1.1 thorpej if ((setmode & mode) == 0)
781 1.1 thorpej continue;
782 1.1 thorpej
783 1.1 thorpej p = mode == AUMODE_PLAY ? play : rec;
784 1.1 thorpej
785 1.1 thorpej if (p == NULL) continue;
786 1.1 thorpej
787 1.1 thorpej for (x = 0; x < 8; x++) {
788 1.1 thorpej if (p->sample_rate <
789 1.1 thorpej (samplerates[x] + samplerates[x + 1]) / 2)
790 1.1 thorpej break;
791 1.1 thorpej }
792 1.1 thorpej if (x == 8)
793 1.19.2.6 skrll return EINVAL;
794 1.1 thorpej
795 1.1 thorpej p->sample_rate = samplerates[x];
796 1.1 thorpej nm_loadcoeff(sc, mode, x);
797 1.1 thorpej
798 1.1 thorpej x <<= 4;
799 1.1 thorpej x &= NM_RATE_MASK;
800 1.1 thorpej if (p->precision == 16)
801 1.1 thorpej x |= NM_RATE_BITS_16;
802 1.1 thorpej if (p->channels == 2)
803 1.1 thorpej x |= NM_RATE_STEREO;
804 1.1 thorpej
805 1.19.2.6 skrll base = (mode == AUMODE_PLAY)?
806 1.1 thorpej NM_PLAYBACK_REG_OFFSET : NM_RECORD_REG_OFFSET;
807 1.1 thorpej nm_wr_1(sc, base + NM_RATE_REG_OFFSET, x);
808 1.1 thorpej
809 1.19.2.6 skrll fil = mode == AUMODE_PLAY ? pfil : rfil;
810 1.19.2.6 skrll i = auconv_set_converter(neo_formats, NEO_NFORMATS,
811 1.19.2.6 skrll mode, p, FALSE, fil);
812 1.19.2.6 skrll if (i < 0)
813 1.19.2.6 skrll return EINVAL;
814 1.19.2.6 skrll }
815 1.1 thorpej
816 1.19.2.6 skrll return 0;
817 1.1 thorpej }
818 1.1 thorpej
819 1.19.2.8 skrll static int
820 1.19.2.6 skrll neo_round_blocksize(void *addr, int blk, int mode, const audio_params_t *param)
821 1.1 thorpej {
822 1.1 thorpej
823 1.19.2.6 skrll return NM_BUFFSIZE / 2;
824 1.1 thorpej }
825 1.1 thorpej
826 1.19.2.8 skrll static int
827 1.1 thorpej neo_trigger_output(void *addr, void *start, void *end, int blksize,
828 1.19.2.6 skrll void (*intr)(void *), void *arg, const audio_params_t *param)
829 1.1 thorpej {
830 1.19.2.6 skrll struct neo_softc *sc;
831 1.1 thorpej int ssz;
832 1.1 thorpej
833 1.19.2.6 skrll sc = addr;
834 1.1 thorpej sc->pintr = intr;
835 1.1 thorpej sc->parg = arg;
836 1.1 thorpej
837 1.19.2.6 skrll ssz = (param->precision == 16) ? 2 : 1;
838 1.1 thorpej if (param->channels == 2)
839 1.1 thorpej ssz <<= 1;
840 1.1 thorpej
841 1.1 thorpej sc->pbufsize = ((char*)end - (char *)start);
842 1.1 thorpej sc->pblksize = blksize;
843 1.1 thorpej sc->pwmark = blksize;
844 1.1 thorpej
845 1.1 thorpej nm_wr_4(sc, NM_PBUFFER_START, sc->pbuf);
846 1.19.2.6 skrll nm_wr_4(sc, NM_PBUFFER_END, sc->pbuf + sc->pbufsize - ssz);
847 1.1 thorpej nm_wr_4(sc, NM_PBUFFER_CURRP, sc->pbuf);
848 1.1 thorpej nm_wr_4(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pwmark);
849 1.1 thorpej nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, NM_PLAYBACK_FREERUN |
850 1.1 thorpej NM_PLAYBACK_ENABLE_FLAG);
851 1.1 thorpej nm_wr_2(sc, NM_AUDIO_MUTE_REG, 0);
852 1.1 thorpej
853 1.19.2.6 skrll return 0;
854 1.1 thorpej }
855 1.1 thorpej
856 1.19.2.8 skrll static int
857 1.1 thorpej neo_trigger_input(void *addr, void *start, void *end, int blksize,
858 1.19.2.6 skrll void (*intr)(void *), void *arg, const audio_params_t *param)
859 1.1 thorpej {
860 1.19.2.6 skrll struct neo_softc *sc;
861 1.1 thorpej int ssz;
862 1.1 thorpej
863 1.19.2.6 skrll sc = addr;
864 1.1 thorpej sc->rintr = intr;
865 1.1 thorpej sc->rarg = arg;
866 1.1 thorpej
867 1.19.2.6 skrll ssz = (param->precision == 16) ? 2 : 1;
868 1.1 thorpej if (param->channels == 2)
869 1.1 thorpej ssz <<= 1;
870 1.1 thorpej
871 1.1 thorpej sc->rbufsize = ((char*)end - (char *)start);
872 1.1 thorpej sc->rblksize = blksize;
873 1.1 thorpej sc->rwmark = blksize;
874 1.1 thorpej
875 1.1 thorpej nm_wr_4(sc, NM_RBUFFER_START, sc->rbuf);
876 1.1 thorpej nm_wr_4(sc, NM_RBUFFER_END, sc->rbuf + sc->rbufsize);
877 1.1 thorpej nm_wr_4(sc, NM_RBUFFER_CURRP, sc->rbuf);
878 1.1 thorpej nm_wr_4(sc, NM_RBUFFER_WMARK, sc->rbuf + sc->rwmark);
879 1.1 thorpej nm_wr_1(sc, NM_RECORD_ENABLE_REG, NM_RECORD_FREERUN |
880 1.1 thorpej NM_RECORD_ENABLE_FLAG);
881 1.1 thorpej
882 1.19.2.6 skrll return 0;
883 1.1 thorpej }
884 1.1 thorpej
885 1.19.2.8 skrll static int
886 1.1 thorpej neo_halt_output(void *addr)
887 1.1 thorpej {
888 1.19.2.6 skrll struct neo_softc *sc;
889 1.1 thorpej
890 1.19.2.6 skrll sc = (struct neo_softc *)addr;
891 1.1 thorpej nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, 0);
892 1.1 thorpej nm_wr_2(sc, NM_AUDIO_MUTE_REG, NM_AUDIO_MUTE_BOTH);
893 1.19.2.1 skrll sc->pintr = 0;
894 1.1 thorpej
895 1.19.2.6 skrll return 0;
896 1.1 thorpej }
897 1.1 thorpej
898 1.19.2.8 skrll static int
899 1.1 thorpej neo_halt_input(void *addr)
900 1.1 thorpej {
901 1.19.2.6 skrll struct neo_softc *sc;
902 1.1 thorpej
903 1.19.2.6 skrll sc = (struct neo_softc *)addr;
904 1.1 thorpej nm_wr_1(sc, NM_RECORD_ENABLE_REG, 0);
905 1.19.2.1 skrll sc->rintr = 0;
906 1.1 thorpej
907 1.19.2.6 skrll return 0;
908 1.1 thorpej }
909 1.1 thorpej
910 1.19.2.8 skrll static int
911 1.1 thorpej neo_getdev(void *addr, struct audio_device *retp)
912 1.1 thorpej {
913 1.1 thorpej
914 1.1 thorpej *retp = neo_device;
915 1.19.2.6 skrll return 0;
916 1.1 thorpej }
917 1.1 thorpej
918 1.19.2.8 skrll static int
919 1.1 thorpej neo_mixer_set_port(void *addr, mixer_ctrl_t *cp)
920 1.1 thorpej {
921 1.19.2.6 skrll struct neo_softc *sc;
922 1.1 thorpej
923 1.19.2.6 skrll sc = addr;
924 1.19.2.6 skrll return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
925 1.1 thorpej }
926 1.1 thorpej
927 1.19.2.8 skrll static int
928 1.1 thorpej neo_mixer_get_port(void *addr, mixer_ctrl_t *cp)
929 1.1 thorpej {
930 1.19.2.6 skrll struct neo_softc *sc;
931 1.1 thorpej
932 1.19.2.6 skrll sc = addr;
933 1.19.2.6 skrll return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
934 1.1 thorpej }
935 1.1 thorpej
936 1.19.2.8 skrll static int
937 1.1 thorpej neo_query_devinfo(void *addr, mixer_devinfo_t *dip)
938 1.1 thorpej {
939 1.19.2.6 skrll struct neo_softc *sc;
940 1.1 thorpej
941 1.19.2.6 skrll sc = addr;
942 1.19.2.6 skrll return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip);
943 1.1 thorpej }
944 1.1 thorpej
945 1.19.2.8 skrll static void *
946 1.17 thorpej neo_malloc(void *addr, int direction, size_t size, struct malloc_type *pool,
947 1.17 thorpej int flags)
948 1.1 thorpej {
949 1.19.2.6 skrll struct neo_softc *sc;
950 1.19.2.6 skrll void *rv;
951 1.1 thorpej
952 1.19.2.6 skrll sc = addr;
953 1.19.2.6 skrll rv = NULL;
954 1.1 thorpej switch (direction) {
955 1.1 thorpej case AUMODE_PLAY:
956 1.1 thorpej if (sc->pbuf_allocated == 0) {
957 1.1 thorpej rv = (void *) sc->pbuf_vaddr;
958 1.1 thorpej sc->pbuf_allocated = 1;
959 1.1 thorpej }
960 1.1 thorpej break;
961 1.1 thorpej
962 1.1 thorpej case AUMODE_RECORD:
963 1.1 thorpej if (sc->rbuf_allocated == 0) {
964 1.1 thorpej rv = (void *) sc->rbuf_vaddr;
965 1.1 thorpej sc->rbuf_allocated = 1;
966 1.1 thorpej }
967 1.1 thorpej break;
968 1.1 thorpej }
969 1.1 thorpej
970 1.19.2.6 skrll return rv;
971 1.1 thorpej }
972 1.1 thorpej
973 1.19.2.8 skrll static void
974 1.17 thorpej neo_free(void *addr, void *ptr, struct malloc_type *pool)
975 1.1 thorpej {
976 1.19.2.6 skrll struct neo_softc *sc;
977 1.19.2.6 skrll vaddr_t v;
978 1.1 thorpej
979 1.19.2.6 skrll sc = addr;
980 1.19.2.6 skrll v = (vaddr_t)ptr;
981 1.1 thorpej if (v == sc->pbuf_vaddr)
982 1.1 thorpej sc->pbuf_allocated = 0;
983 1.1 thorpej else if (v == sc->rbuf_vaddr)
984 1.1 thorpej sc->rbuf_allocated = 0;
985 1.1 thorpej else
986 1.1 thorpej printf("neo_free: bad address %p\n", ptr);
987 1.1 thorpej }
988 1.1 thorpej
989 1.19.2.8 skrll static size_t
990 1.1 thorpej neo_round_buffersize(void *addr, int direction, size_t size)
991 1.1 thorpej {
992 1.1 thorpej
993 1.19.2.6 skrll return NM_BUFFSIZE;
994 1.1 thorpej }
995 1.1 thorpej
996 1.19.2.8 skrll static paddr_t
997 1.3 thorpej neo_mappage(void *addr, void *mem, off_t off, int prot)
998 1.3 thorpej {
999 1.19.2.6 skrll struct neo_softc *sc;
1000 1.19.2.6 skrll vaddr_t v;
1001 1.3 thorpej bus_addr_t pciaddr;
1002 1.3 thorpej
1003 1.19.2.6 skrll sc = addr;
1004 1.19.2.6 skrll v = (vaddr_t)mem;
1005 1.3 thorpej if (v == sc->pbuf_vaddr)
1006 1.3 thorpej pciaddr = sc->pbuf_pciaddr;
1007 1.3 thorpej else if (v == sc->rbuf_vaddr)
1008 1.3 thorpej pciaddr = sc->rbuf_pciaddr;
1009 1.3 thorpej else
1010 1.19.2.6 skrll return -1;
1011 1.3 thorpej
1012 1.19.2.6 skrll return bus_space_mmap(sc->bufiot, pciaddr, off, prot,
1013 1.19.2.6 skrll BUS_SPACE_MAP_LINEAR);
1014 1.3 thorpej }
1015 1.1 thorpej
1016 1.19.2.8 skrll static int
1017 1.1 thorpej neo_get_props(void *addr)
1018 1.1 thorpej {
1019 1.1 thorpej
1020 1.19.2.6 skrll return AUDIO_PROP_INDEPENDENT | AUDIO_PROP_MMAP |
1021 1.19.2.6 skrll AUDIO_PROP_FULLDUPLEX;
1022 1.1 thorpej }
1023