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