neo.c revision 1.4.2.2 1 1.4.2.2 bouyer /* $NetBSD: neo.c,v 1.4.2.2 2000/11/22 16:04:11 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 * Power management (neoactivate)
113 1.4.2.2 bouyer *
114 1.4.2.2 bouyer * Figure out how to shrink that huge table neo-coeff.h
115 1.4.2.2 bouyer */
116 1.4.2.2 bouyer
117 1.4.2.2 bouyer #define NM_BUFFSIZE 16384
118 1.4.2.2 bouyer
119 1.4.2.2 bouyer /* device private data */
120 1.4.2.2 bouyer struct neo_softc {
121 1.4.2.2 bouyer struct device dev;
122 1.4.2.2 bouyer
123 1.4.2.2 bouyer bus_space_tag_t bufiot;
124 1.4.2.2 bouyer bus_space_handle_t bufioh;
125 1.4.2.2 bouyer
126 1.4.2.2 bouyer bus_space_tag_t regiot;
127 1.4.2.2 bouyer bus_space_handle_t regioh;
128 1.4.2.2 bouyer
129 1.4.2.2 bouyer u_int32_t type;
130 1.4.2.2 bouyer void *ih;
131 1.4.2.2 bouyer
132 1.4.2.2 bouyer void (*pintr)(void *); /* dma completion intr handler */
133 1.4.2.2 bouyer void *parg; /* arg for intr() */
134 1.4.2.2 bouyer
135 1.4.2.2 bouyer void (*rintr)(void *); /* dma completion intr handler */
136 1.4.2.2 bouyer void *rarg; /* arg for intr() */
137 1.4.2.2 bouyer
138 1.4.2.2 bouyer vaddr_t buf_vaddr;
139 1.4.2.2 bouyer vaddr_t rbuf_vaddr;
140 1.4.2.2 bouyer vaddr_t pbuf_vaddr;
141 1.4.2.2 bouyer int pbuf_allocated;
142 1.4.2.2 bouyer int rbuf_allocated;
143 1.4.2.2 bouyer
144 1.4.2.2 bouyer bus_addr_t buf_pciaddr;
145 1.4.2.2 bouyer bus_addr_t rbuf_pciaddr;
146 1.4.2.2 bouyer bus_addr_t pbuf_pciaddr;
147 1.4.2.2 bouyer
148 1.4.2.2 bouyer u_int32_t ac97_base, ac97_status, ac97_busy;
149 1.4.2.2 bouyer u_int32_t buftop, pbuf, rbuf, cbuf, acbuf;
150 1.4.2.2 bouyer u_int32_t playint, recint, misc1int, misc2int;
151 1.4.2.2 bouyer u_int32_t irsz, badintr;
152 1.4.2.2 bouyer
153 1.4.2.2 bouyer u_int32_t pbufsize;
154 1.4.2.2 bouyer u_int32_t rbufsize;
155 1.4.2.2 bouyer
156 1.4.2.2 bouyer u_int32_t pblksize;
157 1.4.2.2 bouyer u_int32_t rblksize;
158 1.4.2.2 bouyer
159 1.4.2.2 bouyer u_int32_t pwmark;
160 1.4.2.2 bouyer u_int32_t rwmark;
161 1.4.2.2 bouyer
162 1.4.2.2 bouyer struct ac97_codec_if *codec_if;
163 1.4.2.2 bouyer struct ac97_host_if host_if;
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.2 bouyer
208 1.4.2.2 bouyer struct cfattach neo_ca = {
209 1.4.2.2 bouyer sizeof(struct neo_softc), neo_match, neo_attach
210 1.4.2.2 bouyer };
211 1.4.2.2 bouyer
212 1.4.2.2 bouyer struct audio_device neo_device = {
213 1.4.2.2 bouyer "NeoMagic 256",
214 1.4.2.2 bouyer "",
215 1.4.2.2 bouyer "neo"
216 1.4.2.2 bouyer };
217 1.4.2.2 bouyer
218 1.4.2.2 bouyer /* The actual rates supported by the card. */
219 1.4.2.2 bouyer static const int samplerates[9] = {
220 1.4.2.2 bouyer 8000,
221 1.4.2.2 bouyer 11025,
222 1.4.2.2 bouyer 16000,
223 1.4.2.2 bouyer 22050,
224 1.4.2.2 bouyer 24000,
225 1.4.2.2 bouyer 32000,
226 1.4.2.2 bouyer 44100,
227 1.4.2.2 bouyer 48000,
228 1.4.2.2 bouyer 99999999
229 1.4.2.2 bouyer };
230 1.4.2.2 bouyer
231 1.4.2.2 bouyer /* -------------------------------------------------------------------- */
232 1.4.2.2 bouyer
233 1.4.2.2 bouyer struct audio_hw_if neo_hw_if = {
234 1.4.2.2 bouyer neo_open,
235 1.4.2.2 bouyer neo_close,
236 1.4.2.2 bouyer NULL, /* drain */
237 1.4.2.2 bouyer neo_query_encoding,
238 1.4.2.2 bouyer neo_set_params,
239 1.4.2.2 bouyer neo_round_blocksize,
240 1.4.2.2 bouyer NULL, /* commit_setting */
241 1.4.2.2 bouyer NULL, /* init_output */
242 1.4.2.2 bouyer NULL, /* init_input */
243 1.4.2.2 bouyer NULL, /* start_output */
244 1.4.2.2 bouyer NULL, /* start_input */
245 1.4.2.2 bouyer neo_halt_output,
246 1.4.2.2 bouyer neo_halt_input,
247 1.4.2.2 bouyer NULL, /* speaker_ctl */
248 1.4.2.2 bouyer neo_getdev,
249 1.4.2.2 bouyer NULL, /* getfd */
250 1.4.2.2 bouyer neo_mixer_set_port,
251 1.4.2.2 bouyer neo_mixer_get_port,
252 1.4.2.2 bouyer neo_query_devinfo,
253 1.4.2.2 bouyer neo_malloc,
254 1.4.2.2 bouyer neo_free,
255 1.4.2.2 bouyer neo_round_buffersize,
256 1.4.2.2 bouyer neo_mappage,
257 1.4.2.2 bouyer neo_get_props,
258 1.4.2.2 bouyer neo_trigger_output,
259 1.4.2.2 bouyer neo_trigger_input,
260 1.4.2.2 bouyer };
261 1.4.2.2 bouyer
262 1.4.2.2 bouyer /* -------------------------------------------------------------------- */
263 1.4.2.2 bouyer
264 1.4.2.2 bouyer #define nm_rd_1(sc, regno) \
265 1.4.2.2 bouyer bus_space_read_1((sc)->regiot, (sc)->regioh, (regno))
266 1.4.2.2 bouyer
267 1.4.2.2 bouyer #define nm_rd_2(sc, regno) \
268 1.4.2.2 bouyer bus_space_read_2((sc)->regiot, (sc)->regioh, (regno))
269 1.4.2.2 bouyer
270 1.4.2.2 bouyer #define nm_rd_4(sc, regno) \
271 1.4.2.2 bouyer bus_space_read_4((sc)->regiot, (sc)->regioh, (regno))
272 1.4.2.2 bouyer
273 1.4.2.2 bouyer #define nm_wr_1(sc, regno, val) \
274 1.4.2.2 bouyer bus_space_write_1((sc)->regiot, (sc)->regioh, (regno), (val))
275 1.4.2.2 bouyer
276 1.4.2.2 bouyer #define nm_wr_2(sc, regno, val) \
277 1.4.2.2 bouyer bus_space_write_2((sc)->regiot, (sc)->regioh, (regno), (val))
278 1.4.2.2 bouyer
279 1.4.2.2 bouyer #define nm_wr_4(sc, regno, val) \
280 1.4.2.2 bouyer bus_space_write_4((sc)->regiot, (sc)->regioh, (regno), (val))
281 1.4.2.2 bouyer
282 1.4.2.2 bouyer #define nm_rdbuf_4(sc, regno) \
283 1.4.2.2 bouyer bus_space_read_4((sc)->bufiot, (sc)->bufioh, (regno))
284 1.4.2.2 bouyer
285 1.4.2.2 bouyer #define nm_wrbuf_1(sc, regno, val) \
286 1.4.2.2 bouyer bus_space_write_1((sc)->bufiot, (sc)->bufioh, (regno), (val))
287 1.4.2.2 bouyer
288 1.4.2.2 bouyer /* ac97 codec */
289 1.4.2.2 bouyer static int
290 1.4.2.2 bouyer nm_waitcd(struct neo_softc *sc)
291 1.4.2.2 bouyer {
292 1.4.2.2 bouyer int cnt = 10;
293 1.4.2.2 bouyer int fail = 1;
294 1.4.2.2 bouyer
295 1.4.2.2 bouyer while (cnt-- > 0) {
296 1.4.2.2 bouyer if (nm_rd_2(sc, sc->ac97_status) & sc->ac97_busy)
297 1.4.2.2 bouyer DELAY(100);
298 1.4.2.2 bouyer else {
299 1.4.2.2 bouyer fail = 0;
300 1.4.2.2 bouyer break;
301 1.4.2.2 bouyer }
302 1.4.2.2 bouyer }
303 1.4.2.2 bouyer return (fail);
304 1.4.2.2 bouyer }
305 1.4.2.2 bouyer
306 1.4.2.2 bouyer
307 1.4.2.2 bouyer static void
308 1.4.2.2 bouyer nm_ackint(struct neo_softc *sc, u_int32_t num)
309 1.4.2.2 bouyer {
310 1.4.2.2 bouyer
311 1.4.2.2 bouyer switch (sc->type) {
312 1.4.2.2 bouyer case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
313 1.4.2.2 bouyer nm_wr_2(sc, NM_INT_REG, num << 1);
314 1.4.2.2 bouyer break;
315 1.4.2.2 bouyer
316 1.4.2.2 bouyer case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
317 1.4.2.2 bouyer nm_wr_4(sc, NM_INT_REG, num);
318 1.4.2.2 bouyer break;
319 1.4.2.2 bouyer }
320 1.4.2.2 bouyer }
321 1.4.2.2 bouyer
322 1.4.2.2 bouyer static int
323 1.4.2.2 bouyer nm_loadcoeff(struct neo_softc *sc, int dir, int num)
324 1.4.2.2 bouyer {
325 1.4.2.2 bouyer int ofs, sz, i;
326 1.4.2.2 bouyer u_int32_t addr;
327 1.4.2.2 bouyer
328 1.4.2.2 bouyer addr = (dir == AUMODE_PLAY)? 0x01c : 0x21c;
329 1.4.2.2 bouyer if (dir == AUMODE_RECORD)
330 1.4.2.2 bouyer num += 8;
331 1.4.2.2 bouyer sz = coefficientSizes[num];
332 1.4.2.2 bouyer ofs = 0;
333 1.4.2.2 bouyer while (num-- > 0)
334 1.4.2.2 bouyer ofs+= coefficientSizes[num];
335 1.4.2.2 bouyer for (i = 0; i < sz; i++)
336 1.4.2.2 bouyer nm_wrbuf_1(sc, sc->cbuf + i, coefficients[ofs + i]);
337 1.4.2.2 bouyer nm_wr_4(sc, addr, sc->cbuf);
338 1.4.2.2 bouyer if (dir == AUMODE_PLAY)
339 1.4.2.2 bouyer sz--;
340 1.4.2.2 bouyer nm_wr_4(sc, addr + 4, sc->cbuf + sz);
341 1.4.2.2 bouyer return 0;
342 1.4.2.2 bouyer }
343 1.4.2.2 bouyer
344 1.4.2.2 bouyer /* The interrupt handler */
345 1.4.2.2 bouyer int
346 1.4.2.2 bouyer neo_intr(void *p)
347 1.4.2.2 bouyer {
348 1.4.2.2 bouyer struct neo_softc *sc = (struct neo_softc *)p;
349 1.4.2.2 bouyer int status, x, active;
350 1.4.2.2 bouyer int rv = 0;
351 1.4.2.2 bouyer
352 1.4.2.2 bouyer active = (sc->pintr || sc->rintr);
353 1.4.2.2 bouyer status = (sc->irsz == 2) ?
354 1.4.2.2 bouyer nm_rd_2(sc, NM_INT_REG) :
355 1.4.2.2 bouyer nm_rd_4(sc, NM_INT_REG);
356 1.4.2.2 bouyer
357 1.4.2.2 bouyer if (status & sc->playint) {
358 1.4.2.2 bouyer status &= ~sc->playint;
359 1.4.2.2 bouyer
360 1.4.2.2 bouyer sc->pwmark += sc->pblksize;
361 1.4.2.2 bouyer sc->pwmark %= sc->pbufsize;
362 1.4.2.2 bouyer
363 1.4.2.2 bouyer nm_wr_4(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pwmark);
364 1.4.2.2 bouyer
365 1.4.2.2 bouyer nm_ackint(sc, sc->playint);
366 1.4.2.2 bouyer
367 1.4.2.2 bouyer if (sc->pintr)
368 1.4.2.2 bouyer (*sc->pintr)(sc->parg);
369 1.4.2.2 bouyer
370 1.4.2.2 bouyer rv = 1;
371 1.4.2.2 bouyer }
372 1.4.2.2 bouyer if (status & sc->recint) {
373 1.4.2.2 bouyer status &= ~sc->recint;
374 1.4.2.2 bouyer
375 1.4.2.2 bouyer sc->rwmark += sc->rblksize;
376 1.4.2.2 bouyer sc->rwmark %= sc->rbufsize;
377 1.4.2.2 bouyer
378 1.4.2.2 bouyer nm_ackint(sc, sc->recint);
379 1.4.2.2 bouyer if (sc->rintr)
380 1.4.2.2 bouyer (*sc->rintr)(sc->rarg);
381 1.4.2.2 bouyer
382 1.4.2.2 bouyer rv = 1;
383 1.4.2.2 bouyer }
384 1.4.2.2 bouyer if (status & sc->misc1int) {
385 1.4.2.2 bouyer status &= ~sc->misc1int;
386 1.4.2.2 bouyer nm_ackint(sc, sc->misc1int);
387 1.4.2.2 bouyer x = nm_rd_1(sc, 0x400);
388 1.4.2.2 bouyer nm_wr_1(sc, 0x400, x | 2);
389 1.4.2.2 bouyer printf("%s: misc int 1\n", sc->dev.dv_xname);
390 1.4.2.2 bouyer rv = 1;
391 1.4.2.2 bouyer }
392 1.4.2.2 bouyer if (status & sc->misc2int) {
393 1.4.2.2 bouyer status &= ~sc->misc2int;
394 1.4.2.2 bouyer nm_ackint(sc, sc->misc2int);
395 1.4.2.2 bouyer x = nm_rd_1(sc, 0x400);
396 1.4.2.2 bouyer nm_wr_1(sc, 0x400, x & ~2);
397 1.4.2.2 bouyer printf("%s: misc int 2\n", sc->dev.dv_xname);
398 1.4.2.2 bouyer rv = 1;
399 1.4.2.2 bouyer }
400 1.4.2.2 bouyer if (status) {
401 1.4.2.2 bouyer status &= ~sc->misc2int;
402 1.4.2.2 bouyer nm_ackint(sc, sc->misc2int);
403 1.4.2.2 bouyer printf("%s: unknown int\n", sc->dev.dv_xname);
404 1.4.2.2 bouyer rv = 1;
405 1.4.2.2 bouyer }
406 1.4.2.2 bouyer
407 1.4.2.2 bouyer return (rv);
408 1.4.2.2 bouyer }
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 * Probe and attach the card
414 1.4.2.2 bouyer */
415 1.4.2.2 bouyer
416 1.4.2.2 bouyer static int
417 1.4.2.2 bouyer nm_init(struct neo_softc *sc)
418 1.4.2.2 bouyer {
419 1.4.2.2 bouyer u_int32_t ofs, i;
420 1.4.2.2 bouyer
421 1.4.2.2 bouyer switch (sc->type) {
422 1.4.2.2 bouyer case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
423 1.4.2.2 bouyer sc->ac97_base = NM_MIXER_OFFSET;
424 1.4.2.2 bouyer sc->ac97_status = NM_MIXER_STATUS_OFFSET;
425 1.4.2.2 bouyer sc->ac97_busy = NM_MIXER_READY_MASK;
426 1.4.2.2 bouyer
427 1.4.2.2 bouyer sc->buftop = 2560 * 1024;
428 1.4.2.2 bouyer
429 1.4.2.2 bouyer sc->irsz = 2;
430 1.4.2.2 bouyer sc->playint = NM_PLAYBACK_INT;
431 1.4.2.2 bouyer sc->recint = NM_RECORD_INT;
432 1.4.2.2 bouyer sc->misc1int = NM_MISC_INT_1;
433 1.4.2.2 bouyer sc->misc2int = NM_MISC_INT_2;
434 1.4.2.2 bouyer break;
435 1.4.2.2 bouyer
436 1.4.2.2 bouyer case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
437 1.4.2.2 bouyer sc->ac97_base = NM_MIXER_OFFSET;
438 1.4.2.2 bouyer sc->ac97_status = NM2_MIXER_STATUS_OFFSET;
439 1.4.2.2 bouyer sc->ac97_busy = NM2_MIXER_READY_MASK;
440 1.4.2.2 bouyer
441 1.4.2.2 bouyer sc->buftop = (nm_rd_2(sc, 0xa0b) ? 6144 : 4096) * 1024;
442 1.4.2.2 bouyer
443 1.4.2.2 bouyer sc->irsz = 4;
444 1.4.2.2 bouyer sc->playint = NM2_PLAYBACK_INT;
445 1.4.2.2 bouyer sc->recint = NM2_RECORD_INT;
446 1.4.2.2 bouyer sc->misc1int = NM2_MISC_INT_1;
447 1.4.2.2 bouyer sc->misc2int = NM2_MISC_INT_2;
448 1.4.2.2 bouyer break;
449 1.4.2.2 bouyer #ifdef DIAGNOSTIC
450 1.4.2.2 bouyer default:
451 1.4.2.2 bouyer panic("nm_init: impossible");
452 1.4.2.2 bouyer #endif
453 1.4.2.2 bouyer }
454 1.4.2.2 bouyer
455 1.4.2.2 bouyer sc->badintr = 0;
456 1.4.2.2 bouyer ofs = sc->buftop - 0x0400;
457 1.4.2.2 bouyer sc->buftop -= 0x1400;
458 1.4.2.2 bouyer
459 1.4.2.2 bouyer if ((nm_rdbuf_4(sc, ofs) & NM_SIG_MASK) == NM_SIGNATURE) {
460 1.4.2.2 bouyer i = nm_rdbuf_4(sc, ofs + 4);
461 1.4.2.2 bouyer if (i != 0 && i != 0xffffffff)
462 1.4.2.2 bouyer sc->buftop = i;
463 1.4.2.2 bouyer }
464 1.4.2.2 bouyer
465 1.4.2.2 bouyer sc->cbuf = sc->buftop - NM_MAX_COEFFICIENT;
466 1.4.2.2 bouyer sc->rbuf = sc->cbuf - NM_BUFFSIZE;
467 1.4.2.2 bouyer sc->pbuf = sc->rbuf - NM_BUFFSIZE;
468 1.4.2.2 bouyer sc->acbuf = sc->pbuf - (NM_TOTAL_COEFF_COUNT * 4);
469 1.4.2.2 bouyer
470 1.4.2.2 bouyer sc->buf_vaddr = (vaddr_t) bus_space_vaddr(sc->bufiot, sc->bufioh);
471 1.4.2.2 bouyer sc->rbuf_vaddr = sc->buf_vaddr + sc->rbuf;
472 1.4.2.2 bouyer sc->pbuf_vaddr = sc->buf_vaddr + sc->pbuf;
473 1.4.2.2 bouyer
474 1.4.2.2 bouyer sc->rbuf_pciaddr = sc->buf_pciaddr + sc->rbuf;
475 1.4.2.2 bouyer sc->pbuf_pciaddr = sc->buf_pciaddr + sc->pbuf;
476 1.4.2.2 bouyer
477 1.4.2.2 bouyer nm_wr_1(sc, 0, 0x11);
478 1.4.2.2 bouyer nm_wr_1(sc, NM_RECORD_ENABLE_REG, 0);
479 1.4.2.2 bouyer nm_wr_2(sc, 0x214, 0);
480 1.4.2.2 bouyer
481 1.4.2.2 bouyer return 0;
482 1.4.2.2 bouyer }
483 1.4.2.2 bouyer
484 1.4.2.2 bouyer int
485 1.4.2.2 bouyer neo_match(struct device *parent, struct cfdata *match, void *aux)
486 1.4.2.2 bouyer {
487 1.4.2.2 bouyer struct pci_attach_args *pa = aux;
488 1.4.2.2 bouyer pcireg_t subdev;
489 1.4.2.2 bouyer
490 1.4.2.2 bouyer if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NEOMAGIC)
491 1.4.2.2 bouyer return (0);
492 1.4.2.2 bouyer
493 1.4.2.2 bouyer subdev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
494 1.4.2.2 bouyer
495 1.4.2.2 bouyer switch (PCI_PRODUCT(pa->pa_id)) {
496 1.4.2.2 bouyer case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
497 1.4.2.2 bouyer /*
498 1.4.2.2 bouyer * We have to weed-out the non-AC'97 versions of
499 1.4.2.2 bouyer * the chip (i.e. the ones that are known to work
500 1.4.2.2 bouyer * in WSS emulation mode), as they won't work with
501 1.4.2.2 bouyer * this driver.
502 1.4.2.2 bouyer */
503 1.4.2.2 bouyer switch (PCI_VENDOR(subdev)) {
504 1.4.2.2 bouyer case PCI_VENDOR_DELL:
505 1.4.2.2 bouyer switch (PCI_PRODUCT(subdev)) {
506 1.4.2.2 bouyer case 0x008f:
507 1.4.2.2 bouyer return (0);
508 1.4.2.2 bouyer }
509 1.4.2.2 bouyer break;
510 1.4.2.2 bouyer
511 1.4.2.2 bouyer case PCI_VENDOR_HP:
512 1.4.2.2 bouyer switch (PCI_PRODUCT(subdev)) {
513 1.4.2.2 bouyer case 0x0007:
514 1.4.2.2 bouyer return (0);
515 1.4.2.2 bouyer }
516 1.4.2.2 bouyer }
517 1.4.2.2 bouyer return (1);
518 1.4.2.2 bouyer
519 1.4.2.2 bouyer case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
520 1.4.2.2 bouyer return (1);
521 1.4.2.2 bouyer }
522 1.4.2.2 bouyer
523 1.4.2.2 bouyer return (0);
524 1.4.2.2 bouyer }
525 1.4.2.2 bouyer
526 1.4.2.2 bouyer void
527 1.4.2.2 bouyer neo_attach(struct device *parent, struct device *self, void *aux)
528 1.4.2.2 bouyer {
529 1.4.2.2 bouyer struct neo_softc *sc = (struct neo_softc *)self;
530 1.4.2.2 bouyer struct pci_attach_args *pa = (struct pci_attach_args *)aux;
531 1.4.2.2 bouyer pci_chipset_tag_t pc = pa->pa_pc;
532 1.4.2.2 bouyer char const *intrstr;
533 1.4.2.2 bouyer pci_intr_handle_t ih;
534 1.4.2.2 bouyer pcireg_t csr;
535 1.4.2.2 bouyer int error;
536 1.4.2.2 bouyer
537 1.4.2.2 bouyer sc->type = PCI_PRODUCT(pa->pa_id);
538 1.4.2.2 bouyer
539 1.4.2.2 bouyer printf(": NeoMagic 256%s audio\n",
540 1.4.2.2 bouyer sc->type == PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU ? "AV" : "ZX");
541 1.4.2.2 bouyer
542 1.4.2.2 bouyer /* Map I/O register */
543 1.4.2.2 bouyer if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM, 0,
544 1.4.2.2 bouyer &sc->bufiot, &sc->bufioh, &sc->buf_pciaddr, NULL)) {
545 1.4.2.2 bouyer printf("%s: can't map buffer\n", sc->dev.dv_xname);
546 1.4.2.2 bouyer return;
547 1.4.2.2 bouyer }
548 1.4.2.2 bouyer
549 1.4.2.2 bouyer if (pci_mapreg_map(pa, PCI_MAPREG_START + 4, PCI_MAPREG_TYPE_MEM, 0,
550 1.4.2.2 bouyer &sc->regiot, &sc->regioh, NULL, NULL)) {
551 1.4.2.2 bouyer printf("%s: can't map registers\n", sc->dev.dv_xname);
552 1.4.2.2 bouyer return;
553 1.4.2.2 bouyer }
554 1.4.2.2 bouyer
555 1.4.2.2 bouyer /* Map and establish the interrupt. */
556 1.4.2.2 bouyer if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
557 1.4.2.2 bouyer pa->pa_intrline, &ih)) {
558 1.4.2.2 bouyer printf("%s: couldn't map interrupt\n", sc->dev.dv_xname);
559 1.4.2.2 bouyer return;
560 1.4.2.2 bouyer }
561 1.4.2.2 bouyer
562 1.4.2.2 bouyer intrstr = pci_intr_string(pc, ih);
563 1.4.2.2 bouyer sc->ih = pci_intr_establish(pc, ih, IPL_AUDIO, neo_intr, sc);
564 1.4.2.2 bouyer
565 1.4.2.2 bouyer if (sc->ih == NULL) {
566 1.4.2.2 bouyer printf("%s: couldn't establish interrupt",
567 1.4.2.2 bouyer sc->dev.dv_xname);
568 1.4.2.2 bouyer if (intrstr != NULL)
569 1.4.2.2 bouyer printf(" at %s", intrstr);
570 1.4.2.2 bouyer printf("\n");
571 1.4.2.2 bouyer return;
572 1.4.2.2 bouyer }
573 1.4.2.2 bouyer printf("%s: interruping at %s\n", sc->dev.dv_xname, intrstr);
574 1.4.2.2 bouyer
575 1.4.2.2 bouyer if ((error = nm_init(sc)) != 0)
576 1.4.2.2 bouyer return;
577 1.4.2.2 bouyer
578 1.4.2.2 bouyer /* Enable the device. */
579 1.4.2.2 bouyer csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
580 1.4.2.2 bouyer pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
581 1.4.2.2 bouyer csr | PCI_COMMAND_MASTER_ENABLE);
582 1.4.2.2 bouyer
583 1.4.2.2 bouyer sc->host_if.arg = sc;
584 1.4.2.2 bouyer
585 1.4.2.2 bouyer sc->host_if.attach = neo_attach_codec;
586 1.4.2.2 bouyer sc->host_if.read = neo_read_codec;
587 1.4.2.2 bouyer sc->host_if.write = neo_write_codec;
588 1.4.2.2 bouyer sc->host_if.reset = neo_reset_codec;
589 1.4.2.2 bouyer sc->host_if.flags = neo_flags_codec;
590 1.4.2.2 bouyer
591 1.4.2.2 bouyer if ((error = ac97_attach(&sc->host_if)) != 0)
592 1.4.2.2 bouyer return;
593 1.4.2.2 bouyer
594 1.4.2.2 bouyer audio_attach_mi(&neo_hw_if, sc, &sc->dev);
595 1.4.2.2 bouyer }
596 1.4.2.2 bouyer
597 1.4.2.2 bouyer int
598 1.4.2.2 bouyer neo_read_codec(void *v, u_int8_t a, u_int16_t *d)
599 1.4.2.2 bouyer {
600 1.4.2.2 bouyer struct neo_softc *sc = v;
601 1.4.2.2 bouyer
602 1.4.2.2 bouyer if (!nm_waitcd(sc)) {
603 1.4.2.2 bouyer *d = nm_rd_2(sc, sc->ac97_base + a);
604 1.4.2.2 bouyer DELAY(1000);
605 1.4.2.2 bouyer return 0;
606 1.4.2.2 bouyer }
607 1.4.2.2 bouyer
608 1.4.2.2 bouyer return (ENXIO);
609 1.4.2.2 bouyer }
610 1.4.2.2 bouyer
611 1.4.2.2 bouyer
612 1.4.2.2 bouyer int
613 1.4.2.2 bouyer neo_write_codec(void *v, u_int8_t a, u_int16_t d)
614 1.4.2.2 bouyer {
615 1.4.2.2 bouyer struct neo_softc *sc = v;
616 1.4.2.2 bouyer int cnt = 3;
617 1.4.2.2 bouyer
618 1.4.2.2 bouyer if (!nm_waitcd(sc)) {
619 1.4.2.2 bouyer while (cnt-- > 0) {
620 1.4.2.2 bouyer nm_wr_2(sc, sc->ac97_base + a, d);
621 1.4.2.2 bouyer if (!nm_waitcd(sc)) {
622 1.4.2.2 bouyer DELAY(1000);
623 1.4.2.2 bouyer return (0);
624 1.4.2.2 bouyer }
625 1.4.2.2 bouyer }
626 1.4.2.2 bouyer }
627 1.4.2.2 bouyer
628 1.4.2.2 bouyer return (ENXIO);
629 1.4.2.2 bouyer }
630 1.4.2.2 bouyer
631 1.4.2.2 bouyer int
632 1.4.2.2 bouyer neo_attach_codec(void *v, struct ac97_codec_if *codec_if)
633 1.4.2.2 bouyer {
634 1.4.2.2 bouyer struct neo_softc *sc = v;
635 1.4.2.2 bouyer
636 1.4.2.2 bouyer sc->codec_if = codec_if;
637 1.4.2.2 bouyer return (0);
638 1.4.2.2 bouyer }
639 1.4.2.2 bouyer
640 1.4.2.2 bouyer void
641 1.4.2.2 bouyer neo_reset_codec(void *v)
642 1.4.2.2 bouyer {
643 1.4.2.2 bouyer struct neo_softc *sc = v;
644 1.4.2.2 bouyer
645 1.4.2.2 bouyer nm_wr_1(sc, 0x6c0, 0x01);
646 1.4.2.2 bouyer nm_wr_1(sc, 0x6cc, 0x87);
647 1.4.2.2 bouyer nm_wr_1(sc, 0x6cc, 0x80);
648 1.4.2.2 bouyer nm_wr_1(sc, 0x6cc, 0x00);
649 1.4.2.2 bouyer }
650 1.4.2.2 bouyer
651 1.4.2.2 bouyer enum ac97_host_flags
652 1.4.2.2 bouyer neo_flags_codec(void *v)
653 1.4.2.2 bouyer {
654 1.4.2.2 bouyer
655 1.4.2.2 bouyer return (AC97_HOST_DONT_READ);
656 1.4.2.2 bouyer }
657 1.4.2.2 bouyer
658 1.4.2.2 bouyer int
659 1.4.2.2 bouyer neo_open(void *addr, int flags)
660 1.4.2.2 bouyer {
661 1.4.2.2 bouyer
662 1.4.2.2 bouyer return (0);
663 1.4.2.2 bouyer }
664 1.4.2.2 bouyer
665 1.4.2.2 bouyer /*
666 1.4.2.2 bouyer * Close function is called at splaudio().
667 1.4.2.2 bouyer */
668 1.4.2.2 bouyer void
669 1.4.2.2 bouyer neo_close(void *addr)
670 1.4.2.2 bouyer {
671 1.4.2.2 bouyer struct neo_softc *sc = addr;
672 1.4.2.2 bouyer
673 1.4.2.2 bouyer neo_halt_output(sc);
674 1.4.2.2 bouyer neo_halt_input(sc);
675 1.4.2.2 bouyer
676 1.4.2.2 bouyer sc->pintr = 0;
677 1.4.2.2 bouyer sc->rintr = 0;
678 1.4.2.2 bouyer }
679 1.4.2.2 bouyer
680 1.4.2.2 bouyer int
681 1.4.2.2 bouyer neo_query_encoding(void *addr, struct audio_encoding *fp)
682 1.4.2.2 bouyer {
683 1.4.2.2 bouyer
684 1.4.2.2 bouyer switch (fp->index) {
685 1.4.2.2 bouyer case 0:
686 1.4.2.2 bouyer strcpy(fp->name, AudioEulinear);
687 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_ULINEAR;
688 1.4.2.2 bouyer fp->precision = 8;
689 1.4.2.2 bouyer fp->flags = 0;
690 1.4.2.2 bouyer return (0);
691 1.4.2.2 bouyer case 1:
692 1.4.2.2 bouyer strcpy(fp->name, AudioEmulaw);
693 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_ULAW;
694 1.4.2.2 bouyer fp->precision = 8;
695 1.4.2.2 bouyer fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
696 1.4.2.2 bouyer return (0);
697 1.4.2.2 bouyer case 2:
698 1.4.2.2 bouyer strcpy(fp->name, AudioEalaw);
699 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_ALAW;
700 1.4.2.2 bouyer fp->precision = 8;
701 1.4.2.2 bouyer fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
702 1.4.2.2 bouyer return (0);
703 1.4.2.2 bouyer case 3:
704 1.4.2.2 bouyer strcpy(fp->name, AudioEslinear);
705 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_SLINEAR;
706 1.4.2.2 bouyer fp->precision = 8;
707 1.4.2.2 bouyer fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
708 1.4.2.2 bouyer return (0);
709 1.4.2.2 bouyer case 4:
710 1.4.2.2 bouyer strcpy(fp->name, AudioEslinear_le);
711 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
712 1.4.2.2 bouyer fp->precision = 16;
713 1.4.2.2 bouyer fp->flags = 0;
714 1.4.2.2 bouyer return (0);
715 1.4.2.2 bouyer case 5:
716 1.4.2.2 bouyer strcpy(fp->name, AudioEulinear_le);
717 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
718 1.4.2.2 bouyer fp->precision = 16;
719 1.4.2.2 bouyer fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
720 1.4.2.2 bouyer return (0);
721 1.4.2.2 bouyer case 6:
722 1.4.2.2 bouyer strcpy(fp->name, AudioEslinear_be);
723 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
724 1.4.2.2 bouyer fp->precision = 16;
725 1.4.2.2 bouyer fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
726 1.4.2.2 bouyer return (0);
727 1.4.2.2 bouyer case 7:
728 1.4.2.2 bouyer strcpy(fp->name, AudioEulinear_be);
729 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
730 1.4.2.2 bouyer fp->precision = 16;
731 1.4.2.2 bouyer fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
732 1.4.2.2 bouyer return (0);
733 1.4.2.2 bouyer default:
734 1.4.2.2 bouyer return (EINVAL);
735 1.4.2.2 bouyer }
736 1.4.2.2 bouyer }
737 1.4.2.2 bouyer
738 1.4.2.2 bouyer /* Todo: don't commit settings to card until we've verified all parameters */
739 1.4.2.2 bouyer int
740 1.4.2.2 bouyer neo_set_params(void *addr, int setmode, int usemode, struct audio_params *play,
741 1.4.2.2 bouyer struct audio_params *rec)
742 1.4.2.2 bouyer {
743 1.4.2.2 bouyer struct neo_softc *sc = addr;
744 1.4.2.2 bouyer u_int32_t base;
745 1.4.2.2 bouyer u_int8_t x;
746 1.4.2.2 bouyer int mode;
747 1.4.2.2 bouyer struct audio_params *p;
748 1.4.2.2 bouyer
749 1.4.2.2 bouyer for (mode = AUMODE_RECORD; mode != -1;
750 1.4.2.2 bouyer mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
751 1.4.2.2 bouyer if ((setmode & mode) == 0)
752 1.4.2.2 bouyer continue;
753 1.4.2.2 bouyer
754 1.4.2.2 bouyer p = mode == AUMODE_PLAY ? play : rec;
755 1.4.2.2 bouyer
756 1.4.2.2 bouyer if (p == NULL) continue;
757 1.4.2.2 bouyer
758 1.4.2.2 bouyer for (x = 0; x < 8; x++) {
759 1.4.2.2 bouyer if (p->sample_rate <
760 1.4.2.2 bouyer (samplerates[x] + samplerates[x + 1]) / 2)
761 1.4.2.2 bouyer break;
762 1.4.2.2 bouyer }
763 1.4.2.2 bouyer if (x == 8)
764 1.4.2.2 bouyer return (EINVAL);
765 1.4.2.2 bouyer
766 1.4.2.2 bouyer p->sample_rate = samplerates[x];
767 1.4.2.2 bouyer nm_loadcoeff(sc, mode, x);
768 1.4.2.2 bouyer
769 1.4.2.2 bouyer x <<= 4;
770 1.4.2.2 bouyer x &= NM_RATE_MASK;
771 1.4.2.2 bouyer if (p->precision == 16)
772 1.4.2.2 bouyer x |= NM_RATE_BITS_16;
773 1.4.2.2 bouyer if (p->channels == 2)
774 1.4.2.2 bouyer x |= NM_RATE_STEREO;
775 1.4.2.2 bouyer
776 1.4.2.2 bouyer base = (mode == AUMODE_PLAY)?
777 1.4.2.2 bouyer NM_PLAYBACK_REG_OFFSET : NM_RECORD_REG_OFFSET;
778 1.4.2.2 bouyer nm_wr_1(sc, base + NM_RATE_REG_OFFSET, x);
779 1.4.2.2 bouyer
780 1.4.2.2 bouyer p->factor = 1;
781 1.4.2.2 bouyer p->sw_code = 0;
782 1.4.2.2 bouyer switch (p->encoding) {
783 1.4.2.2 bouyer case AUDIO_ENCODING_SLINEAR_BE:
784 1.4.2.2 bouyer if (p->precision == 16)
785 1.4.2.2 bouyer p->sw_code = swap_bytes;
786 1.4.2.2 bouyer else
787 1.4.2.2 bouyer p->sw_code = change_sign8;
788 1.4.2.2 bouyer break;
789 1.4.2.2 bouyer case AUDIO_ENCODING_SLINEAR_LE:
790 1.4.2.2 bouyer if (p->precision != 16)
791 1.4.2.2 bouyer p->sw_code = change_sign8;
792 1.4.2.2 bouyer break;
793 1.4.2.2 bouyer case AUDIO_ENCODING_ULINEAR_BE:
794 1.4.2.2 bouyer if (p->precision == 16) {
795 1.4.2.2 bouyer if (mode == AUMODE_PLAY)
796 1.4.2.2 bouyer p->sw_code =
797 1.4.2.2 bouyer swap_bytes_change_sign16_le;
798 1.4.2.2 bouyer else
799 1.4.2.2 bouyer p->sw_code =
800 1.4.2.2 bouyer change_sign16_swap_bytes_le;
801 1.4.2.2 bouyer }
802 1.4.2.2 bouyer break;
803 1.4.2.2 bouyer case AUDIO_ENCODING_ULINEAR_LE:
804 1.4.2.2 bouyer if (p->precision == 16)
805 1.4.2.2 bouyer p->sw_code = change_sign16_le;
806 1.4.2.2 bouyer break;
807 1.4.2.2 bouyer case AUDIO_ENCODING_ULAW:
808 1.4.2.2 bouyer if (mode == AUMODE_PLAY) {
809 1.4.2.2 bouyer p->factor = 2;
810 1.4.2.2 bouyer p->sw_code = mulaw_to_slinear16_le;
811 1.4.2.2 bouyer } else
812 1.4.2.2 bouyer p->sw_code = ulinear8_to_mulaw;
813 1.4.2.2 bouyer break;
814 1.4.2.2 bouyer case AUDIO_ENCODING_ALAW:
815 1.4.2.2 bouyer if (mode == AUMODE_PLAY) {
816 1.4.2.2 bouyer p->factor = 2;
817 1.4.2.2 bouyer p->sw_code = alaw_to_slinear16_le;
818 1.4.2.2 bouyer } else
819 1.4.2.2 bouyer p->sw_code = ulinear8_to_alaw;
820 1.4.2.2 bouyer break;
821 1.4.2.2 bouyer default:
822 1.4.2.2 bouyer return (EINVAL);
823 1.4.2.2 bouyer }
824 1.4.2.2 bouyer }
825 1.4.2.2 bouyer
826 1.4.2.2 bouyer
827 1.4.2.2 bouyer return (0);
828 1.4.2.2 bouyer }
829 1.4.2.2 bouyer
830 1.4.2.2 bouyer int
831 1.4.2.2 bouyer neo_round_blocksize(void *addr, int blk)
832 1.4.2.2 bouyer {
833 1.4.2.2 bouyer
834 1.4.2.2 bouyer return (NM_BUFFSIZE / 2);
835 1.4.2.2 bouyer }
836 1.4.2.2 bouyer
837 1.4.2.2 bouyer int
838 1.4.2.2 bouyer neo_trigger_output(void *addr, void *start, void *end, int blksize,
839 1.4.2.2 bouyer void (*intr)(void *), void *arg, struct audio_params *param)
840 1.4.2.2 bouyer {
841 1.4.2.2 bouyer struct neo_softc *sc = addr;
842 1.4.2.2 bouyer int ssz;
843 1.4.2.2 bouyer
844 1.4.2.2 bouyer sc->pintr = intr;
845 1.4.2.2 bouyer sc->parg = arg;
846 1.4.2.2 bouyer
847 1.4.2.2 bouyer ssz = (param->precision * param->factor == 16) ? 2 : 1;
848 1.4.2.2 bouyer if (param->channels == 2)
849 1.4.2.2 bouyer ssz <<= 1;
850 1.4.2.2 bouyer
851 1.4.2.2 bouyer sc->pbufsize = ((char*)end - (char *)start);
852 1.4.2.2 bouyer sc->pblksize = blksize;
853 1.4.2.2 bouyer sc->pwmark = blksize;
854 1.4.2.2 bouyer
855 1.4.2.2 bouyer nm_wr_4(sc, NM_PBUFFER_START, sc->pbuf);
856 1.4.2.2 bouyer nm_wr_4(sc, NM_PBUFFER_END, sc->pbuf + sc->pbufsize - ssz);
857 1.4.2.2 bouyer nm_wr_4(sc, NM_PBUFFER_CURRP, sc->pbuf);
858 1.4.2.2 bouyer nm_wr_4(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pwmark);
859 1.4.2.2 bouyer nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, NM_PLAYBACK_FREERUN |
860 1.4.2.2 bouyer NM_PLAYBACK_ENABLE_FLAG);
861 1.4.2.2 bouyer nm_wr_2(sc, NM_AUDIO_MUTE_REG, 0);
862 1.4.2.2 bouyer
863 1.4.2.2 bouyer return (0);
864 1.4.2.2 bouyer }
865 1.4.2.2 bouyer
866 1.4.2.2 bouyer int
867 1.4.2.2 bouyer neo_trigger_input(void *addr, void *start, void *end, int blksize,
868 1.4.2.2 bouyer void (*intr)(void *), void *arg, struct audio_params *param)
869 1.4.2.2 bouyer {
870 1.4.2.2 bouyer struct neo_softc *sc = addr;
871 1.4.2.2 bouyer int ssz;
872 1.4.2.2 bouyer
873 1.4.2.2 bouyer sc->rintr = intr;
874 1.4.2.2 bouyer sc->rarg = arg;
875 1.4.2.2 bouyer
876 1.4.2.2 bouyer ssz = (param->precision * param->factor == 16) ? 2 : 1;
877 1.4.2.2 bouyer if (param->channels == 2)
878 1.4.2.2 bouyer ssz <<= 1;
879 1.4.2.2 bouyer
880 1.4.2.2 bouyer sc->rbufsize = ((char*)end - (char *)start);
881 1.4.2.2 bouyer sc->rblksize = blksize;
882 1.4.2.2 bouyer sc->rwmark = blksize;
883 1.4.2.2 bouyer
884 1.4.2.2 bouyer nm_wr_4(sc, NM_RBUFFER_START, sc->rbuf);
885 1.4.2.2 bouyer nm_wr_4(sc, NM_RBUFFER_END, sc->rbuf + sc->rbufsize);
886 1.4.2.2 bouyer nm_wr_4(sc, NM_RBUFFER_CURRP, sc->rbuf);
887 1.4.2.2 bouyer nm_wr_4(sc, NM_RBUFFER_WMARK, sc->rbuf + sc->rwmark);
888 1.4.2.2 bouyer nm_wr_1(sc, NM_RECORD_ENABLE_REG, NM_RECORD_FREERUN |
889 1.4.2.2 bouyer NM_RECORD_ENABLE_FLAG);
890 1.4.2.2 bouyer
891 1.4.2.2 bouyer return (0);
892 1.4.2.2 bouyer }
893 1.4.2.2 bouyer
894 1.4.2.2 bouyer int
895 1.4.2.2 bouyer neo_halt_output(void *addr)
896 1.4.2.2 bouyer {
897 1.4.2.2 bouyer struct neo_softc *sc = (struct neo_softc *)addr;
898 1.4.2.2 bouyer
899 1.4.2.2 bouyer nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, 0);
900 1.4.2.2 bouyer nm_wr_2(sc, NM_AUDIO_MUTE_REG, NM_AUDIO_MUTE_BOTH);
901 1.4.2.2 bouyer
902 1.4.2.2 bouyer return (0);
903 1.4.2.2 bouyer }
904 1.4.2.2 bouyer
905 1.4.2.2 bouyer int
906 1.4.2.2 bouyer neo_halt_input(void *addr)
907 1.4.2.2 bouyer {
908 1.4.2.2 bouyer struct neo_softc *sc = (struct neo_softc *)addr;
909 1.4.2.2 bouyer
910 1.4.2.2 bouyer nm_wr_1(sc, NM_RECORD_ENABLE_REG, 0);
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_getdev(void *addr, struct audio_device *retp)
917 1.4.2.2 bouyer {
918 1.4.2.2 bouyer
919 1.4.2.2 bouyer *retp = neo_device;
920 1.4.2.2 bouyer return (0);
921 1.4.2.2 bouyer }
922 1.4.2.2 bouyer
923 1.4.2.2 bouyer int
924 1.4.2.2 bouyer neo_mixer_set_port(void *addr, mixer_ctrl_t *cp)
925 1.4.2.2 bouyer {
926 1.4.2.2 bouyer struct neo_softc *sc = addr;
927 1.4.2.2 bouyer
928 1.4.2.2 bouyer return ((sc->codec_if->vtbl->mixer_set_port)(sc->codec_if, cp));
929 1.4.2.2 bouyer }
930 1.4.2.2 bouyer
931 1.4.2.2 bouyer int
932 1.4.2.2 bouyer neo_mixer_get_port(void *addr, mixer_ctrl_t *cp)
933 1.4.2.2 bouyer {
934 1.4.2.2 bouyer struct neo_softc *sc = addr;
935 1.4.2.2 bouyer
936 1.4.2.2 bouyer return ((sc->codec_if->vtbl->mixer_get_port)(sc->codec_if, cp));
937 1.4.2.2 bouyer }
938 1.4.2.2 bouyer
939 1.4.2.2 bouyer int
940 1.4.2.2 bouyer neo_query_devinfo(void *addr, mixer_devinfo_t *dip)
941 1.4.2.2 bouyer {
942 1.4.2.2 bouyer struct neo_softc *sc = addr;
943 1.4.2.2 bouyer
944 1.4.2.2 bouyer return ((sc->codec_if->vtbl->query_devinfo)(sc->codec_if, dip));
945 1.4.2.2 bouyer }
946 1.4.2.2 bouyer
947 1.4.2.2 bouyer void *
948 1.4.2.2 bouyer neo_malloc(void *addr, int direction, size_t size, int pool, int flags)
949 1.4.2.2 bouyer {
950 1.4.2.2 bouyer struct neo_softc *sc = addr;
951 1.4.2.2 bouyer void *rv = NULL;
952 1.4.2.2 bouyer
953 1.4.2.2 bouyer switch (direction) {
954 1.4.2.2 bouyer case AUMODE_PLAY:
955 1.4.2.2 bouyer if (sc->pbuf_allocated == 0) {
956 1.4.2.2 bouyer rv = (void *) sc->pbuf_vaddr;
957 1.4.2.2 bouyer sc->pbuf_allocated = 1;
958 1.4.2.2 bouyer }
959 1.4.2.2 bouyer break;
960 1.4.2.2 bouyer
961 1.4.2.2 bouyer case AUMODE_RECORD:
962 1.4.2.2 bouyer if (sc->rbuf_allocated == 0) {
963 1.4.2.2 bouyer rv = (void *) sc->rbuf_vaddr;
964 1.4.2.2 bouyer sc->rbuf_allocated = 1;
965 1.4.2.2 bouyer }
966 1.4.2.2 bouyer break;
967 1.4.2.2 bouyer }
968 1.4.2.2 bouyer
969 1.4.2.2 bouyer return (rv);
970 1.4.2.2 bouyer }
971 1.4.2.2 bouyer
972 1.4.2.2 bouyer void
973 1.4.2.2 bouyer neo_free(void *addr, void *ptr, int pool)
974 1.4.2.2 bouyer {
975 1.4.2.2 bouyer struct neo_softc *sc = addr;
976 1.4.2.2 bouyer vaddr_t v = (vaddr_t) ptr;
977 1.4.2.2 bouyer
978 1.4.2.2 bouyer if (v == sc->pbuf_vaddr)
979 1.4.2.2 bouyer sc->pbuf_allocated = 0;
980 1.4.2.2 bouyer else if (v == sc->rbuf_vaddr)
981 1.4.2.2 bouyer sc->rbuf_allocated = 0;
982 1.4.2.2 bouyer else
983 1.4.2.2 bouyer printf("neo_free: bad address %p\n", ptr);
984 1.4.2.2 bouyer }
985 1.4.2.2 bouyer
986 1.4.2.2 bouyer size_t
987 1.4.2.2 bouyer neo_round_buffersize(void *addr, int direction, size_t size)
988 1.4.2.2 bouyer {
989 1.4.2.2 bouyer
990 1.4.2.2 bouyer return (NM_BUFFSIZE);
991 1.4.2.2 bouyer }
992 1.4.2.2 bouyer
993 1.4.2.2 bouyer paddr_t
994 1.4.2.2 bouyer neo_mappage(void *addr, void *mem, off_t off, int prot)
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) mem;
998 1.4.2.2 bouyer bus_addr_t pciaddr;
999 1.4.2.2 bouyer
1000 1.4.2.2 bouyer /* XXX Need new mapping code. */
1001 1.4.2.2 bouyer
1002 1.4.2.2 bouyer if (v == sc->pbuf_vaddr)
1003 1.4.2.2 bouyer pciaddr = sc->pbuf_pciaddr;
1004 1.4.2.2 bouyer else if (v == sc->rbuf_vaddr)
1005 1.4.2.2 bouyer pciaddr = sc->rbuf_pciaddr;
1006 1.4.2.2 bouyer else
1007 1.4.2.2 bouyer return (-1);
1008 1.4.2.2 bouyer
1009 1.4.2.2 bouyer #ifdef __i386__
1010 1.4.2.2 bouyer return (i386_btop(pciaddr + off));
1011 1.4.2.2 bouyer #else
1012 1.4.2.2 bouyer return (-1);
1013 1.4.2.2 bouyer #endif
1014 1.4.2.2 bouyer }
1015 1.4.2.2 bouyer
1016 1.4.2.2 bouyer int
1017 1.4.2.2 bouyer neo_get_props(void *addr)
1018 1.4.2.2 bouyer {
1019 1.4.2.2 bouyer
1020 1.4.2.2 bouyer return (AUDIO_PROP_INDEPENDENT | AUDIO_PROP_MMAP |
1021 1.4.2.2 bouyer AUDIO_PROP_FULLDUPLEX);
1022 1.4.2.2 bouyer }
1023