neo.c revision 1.4.2.3 1 1.4.2.3 bouyer /* $NetBSD: neo.c,v 1.4.2.3 2000/12/08 09:12:32 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.2 bouyer }
518 1.4.2.2 bouyer return (1);
519 1.4.2.2 bouyer
520 1.4.2.2 bouyer case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
521 1.4.2.2 bouyer return (1);
522 1.4.2.2 bouyer }
523 1.4.2.2 bouyer
524 1.4.2.2 bouyer return (0);
525 1.4.2.2 bouyer }
526 1.4.2.2 bouyer
527 1.4.2.2 bouyer void
528 1.4.2.3 bouyer neo_power(int why, void *addr)
529 1.4.2.3 bouyer {
530 1.4.2.3 bouyer struct neo_softc *sc = (struct neo_softc *)addr;
531 1.4.2.3 bouyer
532 1.4.2.3 bouyer if (why == PWR_RESUME) {
533 1.4.2.3 bouyer nm_init(sc);
534 1.4.2.3 bouyer (sc->codec_if->vtbl->restore_ports)(sc->codec_if);
535 1.4.2.3 bouyer }
536 1.4.2.3 bouyer }
537 1.4.2.3 bouyer
538 1.4.2.3 bouyer void
539 1.4.2.2 bouyer neo_attach(struct device *parent, struct device *self, void *aux)
540 1.4.2.2 bouyer {
541 1.4.2.2 bouyer struct neo_softc *sc = (struct neo_softc *)self;
542 1.4.2.2 bouyer struct pci_attach_args *pa = (struct pci_attach_args *)aux;
543 1.4.2.2 bouyer pci_chipset_tag_t pc = pa->pa_pc;
544 1.4.2.2 bouyer char const *intrstr;
545 1.4.2.2 bouyer pci_intr_handle_t ih;
546 1.4.2.2 bouyer pcireg_t csr;
547 1.4.2.2 bouyer int error;
548 1.4.2.2 bouyer
549 1.4.2.2 bouyer sc->type = PCI_PRODUCT(pa->pa_id);
550 1.4.2.2 bouyer
551 1.4.2.2 bouyer printf(": NeoMagic 256%s audio\n",
552 1.4.2.2 bouyer sc->type == PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU ? "AV" : "ZX");
553 1.4.2.2 bouyer
554 1.4.2.2 bouyer /* Map I/O register */
555 1.4.2.2 bouyer if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM, 0,
556 1.4.2.2 bouyer &sc->bufiot, &sc->bufioh, &sc->buf_pciaddr, NULL)) {
557 1.4.2.2 bouyer printf("%s: can't map buffer\n", sc->dev.dv_xname);
558 1.4.2.2 bouyer return;
559 1.4.2.2 bouyer }
560 1.4.2.2 bouyer
561 1.4.2.2 bouyer if (pci_mapreg_map(pa, PCI_MAPREG_START + 4, PCI_MAPREG_TYPE_MEM, 0,
562 1.4.2.2 bouyer &sc->regiot, &sc->regioh, NULL, NULL)) {
563 1.4.2.2 bouyer printf("%s: can't map registers\n", sc->dev.dv_xname);
564 1.4.2.2 bouyer return;
565 1.4.2.2 bouyer }
566 1.4.2.2 bouyer
567 1.4.2.2 bouyer /* Map and establish the interrupt. */
568 1.4.2.2 bouyer if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
569 1.4.2.2 bouyer pa->pa_intrline, &ih)) {
570 1.4.2.2 bouyer printf("%s: couldn't map interrupt\n", sc->dev.dv_xname);
571 1.4.2.2 bouyer return;
572 1.4.2.2 bouyer }
573 1.4.2.2 bouyer
574 1.4.2.2 bouyer intrstr = pci_intr_string(pc, ih);
575 1.4.2.2 bouyer sc->ih = pci_intr_establish(pc, ih, IPL_AUDIO, neo_intr, sc);
576 1.4.2.2 bouyer
577 1.4.2.2 bouyer if (sc->ih == NULL) {
578 1.4.2.2 bouyer printf("%s: couldn't establish interrupt",
579 1.4.2.2 bouyer sc->dev.dv_xname);
580 1.4.2.2 bouyer if (intrstr != NULL)
581 1.4.2.2 bouyer printf(" at %s", intrstr);
582 1.4.2.2 bouyer printf("\n");
583 1.4.2.2 bouyer return;
584 1.4.2.2 bouyer }
585 1.4.2.2 bouyer printf("%s: interruping at %s\n", sc->dev.dv_xname, intrstr);
586 1.4.2.2 bouyer
587 1.4.2.2 bouyer if ((error = nm_init(sc)) != 0)
588 1.4.2.2 bouyer return;
589 1.4.2.2 bouyer
590 1.4.2.2 bouyer /* Enable the device. */
591 1.4.2.2 bouyer csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
592 1.4.2.2 bouyer pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
593 1.4.2.2 bouyer csr | PCI_COMMAND_MASTER_ENABLE);
594 1.4.2.2 bouyer
595 1.4.2.2 bouyer sc->host_if.arg = sc;
596 1.4.2.2 bouyer
597 1.4.2.2 bouyer sc->host_if.attach = neo_attach_codec;
598 1.4.2.2 bouyer sc->host_if.read = neo_read_codec;
599 1.4.2.2 bouyer sc->host_if.write = neo_write_codec;
600 1.4.2.2 bouyer sc->host_if.reset = neo_reset_codec;
601 1.4.2.2 bouyer sc->host_if.flags = neo_flags_codec;
602 1.4.2.2 bouyer
603 1.4.2.2 bouyer if ((error = ac97_attach(&sc->host_if)) != 0)
604 1.4.2.2 bouyer return;
605 1.4.2.2 bouyer
606 1.4.2.3 bouyer sc->powerhook = powerhook_establish(neo_power, sc);
607 1.4.2.3 bouyer
608 1.4.2.2 bouyer audio_attach_mi(&neo_hw_if, sc, &sc->dev);
609 1.4.2.2 bouyer }
610 1.4.2.2 bouyer
611 1.4.2.2 bouyer int
612 1.4.2.2 bouyer neo_read_codec(void *v, u_int8_t a, u_int16_t *d)
613 1.4.2.2 bouyer {
614 1.4.2.2 bouyer struct neo_softc *sc = v;
615 1.4.2.2 bouyer
616 1.4.2.2 bouyer if (!nm_waitcd(sc)) {
617 1.4.2.2 bouyer *d = nm_rd_2(sc, sc->ac97_base + a);
618 1.4.2.2 bouyer DELAY(1000);
619 1.4.2.2 bouyer return 0;
620 1.4.2.2 bouyer }
621 1.4.2.2 bouyer
622 1.4.2.2 bouyer return (ENXIO);
623 1.4.2.2 bouyer }
624 1.4.2.2 bouyer
625 1.4.2.2 bouyer
626 1.4.2.2 bouyer int
627 1.4.2.2 bouyer neo_write_codec(void *v, u_int8_t a, u_int16_t d)
628 1.4.2.2 bouyer {
629 1.4.2.2 bouyer struct neo_softc *sc = v;
630 1.4.2.2 bouyer int cnt = 3;
631 1.4.2.2 bouyer
632 1.4.2.2 bouyer if (!nm_waitcd(sc)) {
633 1.4.2.2 bouyer while (cnt-- > 0) {
634 1.4.2.2 bouyer nm_wr_2(sc, sc->ac97_base + a, d);
635 1.4.2.2 bouyer if (!nm_waitcd(sc)) {
636 1.4.2.2 bouyer DELAY(1000);
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 }
641 1.4.2.2 bouyer
642 1.4.2.2 bouyer return (ENXIO);
643 1.4.2.2 bouyer }
644 1.4.2.2 bouyer
645 1.4.2.2 bouyer int
646 1.4.2.2 bouyer neo_attach_codec(void *v, struct ac97_codec_if *codec_if)
647 1.4.2.2 bouyer {
648 1.4.2.2 bouyer struct neo_softc *sc = v;
649 1.4.2.2 bouyer
650 1.4.2.2 bouyer sc->codec_if = codec_if;
651 1.4.2.2 bouyer return (0);
652 1.4.2.2 bouyer }
653 1.4.2.2 bouyer
654 1.4.2.2 bouyer void
655 1.4.2.2 bouyer neo_reset_codec(void *v)
656 1.4.2.2 bouyer {
657 1.4.2.2 bouyer struct neo_softc *sc = v;
658 1.4.2.2 bouyer
659 1.4.2.2 bouyer nm_wr_1(sc, 0x6c0, 0x01);
660 1.4.2.2 bouyer nm_wr_1(sc, 0x6cc, 0x87);
661 1.4.2.2 bouyer nm_wr_1(sc, 0x6cc, 0x80);
662 1.4.2.2 bouyer nm_wr_1(sc, 0x6cc, 0x00);
663 1.4.2.2 bouyer }
664 1.4.2.2 bouyer
665 1.4.2.2 bouyer enum ac97_host_flags
666 1.4.2.2 bouyer neo_flags_codec(void *v)
667 1.4.2.2 bouyer {
668 1.4.2.2 bouyer
669 1.4.2.2 bouyer return (AC97_HOST_DONT_READ);
670 1.4.2.2 bouyer }
671 1.4.2.2 bouyer
672 1.4.2.2 bouyer int
673 1.4.2.2 bouyer neo_open(void *addr, int flags)
674 1.4.2.2 bouyer {
675 1.4.2.2 bouyer
676 1.4.2.2 bouyer return (0);
677 1.4.2.2 bouyer }
678 1.4.2.2 bouyer
679 1.4.2.2 bouyer /*
680 1.4.2.2 bouyer * Close function is called at splaudio().
681 1.4.2.2 bouyer */
682 1.4.2.2 bouyer void
683 1.4.2.2 bouyer neo_close(void *addr)
684 1.4.2.2 bouyer {
685 1.4.2.2 bouyer struct neo_softc *sc = addr;
686 1.4.2.2 bouyer
687 1.4.2.2 bouyer neo_halt_output(sc);
688 1.4.2.2 bouyer neo_halt_input(sc);
689 1.4.2.2 bouyer
690 1.4.2.2 bouyer sc->pintr = 0;
691 1.4.2.2 bouyer sc->rintr = 0;
692 1.4.2.2 bouyer }
693 1.4.2.2 bouyer
694 1.4.2.2 bouyer int
695 1.4.2.2 bouyer neo_query_encoding(void *addr, struct audio_encoding *fp)
696 1.4.2.2 bouyer {
697 1.4.2.2 bouyer
698 1.4.2.2 bouyer switch (fp->index) {
699 1.4.2.2 bouyer case 0:
700 1.4.2.2 bouyer strcpy(fp->name, AudioEulinear);
701 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_ULINEAR;
702 1.4.2.2 bouyer fp->precision = 8;
703 1.4.2.2 bouyer fp->flags = 0;
704 1.4.2.2 bouyer return (0);
705 1.4.2.2 bouyer case 1:
706 1.4.2.2 bouyer strcpy(fp->name, AudioEmulaw);
707 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_ULAW;
708 1.4.2.2 bouyer fp->precision = 8;
709 1.4.2.2 bouyer fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
710 1.4.2.2 bouyer return (0);
711 1.4.2.2 bouyer case 2:
712 1.4.2.2 bouyer strcpy(fp->name, AudioEalaw);
713 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_ALAW;
714 1.4.2.2 bouyer fp->precision = 8;
715 1.4.2.2 bouyer fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
716 1.4.2.2 bouyer return (0);
717 1.4.2.2 bouyer case 3:
718 1.4.2.2 bouyer strcpy(fp->name, AudioEslinear);
719 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_SLINEAR;
720 1.4.2.2 bouyer fp->precision = 8;
721 1.4.2.2 bouyer fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
722 1.4.2.2 bouyer return (0);
723 1.4.2.2 bouyer case 4:
724 1.4.2.2 bouyer strcpy(fp->name, AudioEslinear_le);
725 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
726 1.4.2.2 bouyer fp->precision = 16;
727 1.4.2.2 bouyer fp->flags = 0;
728 1.4.2.2 bouyer return (0);
729 1.4.2.2 bouyer case 5:
730 1.4.2.2 bouyer strcpy(fp->name, AudioEulinear_le);
731 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
732 1.4.2.2 bouyer fp->precision = 16;
733 1.4.2.2 bouyer fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
734 1.4.2.2 bouyer return (0);
735 1.4.2.2 bouyer case 6:
736 1.4.2.2 bouyer strcpy(fp->name, AudioEslinear_be);
737 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
738 1.4.2.2 bouyer fp->precision = 16;
739 1.4.2.2 bouyer fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
740 1.4.2.2 bouyer return (0);
741 1.4.2.2 bouyer case 7:
742 1.4.2.2 bouyer strcpy(fp->name, AudioEulinear_be);
743 1.4.2.2 bouyer fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
744 1.4.2.2 bouyer fp->precision = 16;
745 1.4.2.2 bouyer fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
746 1.4.2.2 bouyer return (0);
747 1.4.2.2 bouyer default:
748 1.4.2.2 bouyer return (EINVAL);
749 1.4.2.2 bouyer }
750 1.4.2.2 bouyer }
751 1.4.2.2 bouyer
752 1.4.2.2 bouyer /* Todo: don't commit settings to card until we've verified all parameters */
753 1.4.2.2 bouyer int
754 1.4.2.2 bouyer neo_set_params(void *addr, int setmode, int usemode, struct audio_params *play,
755 1.4.2.2 bouyer struct audio_params *rec)
756 1.4.2.2 bouyer {
757 1.4.2.2 bouyer struct neo_softc *sc = addr;
758 1.4.2.2 bouyer u_int32_t base;
759 1.4.2.2 bouyer u_int8_t x;
760 1.4.2.2 bouyer int mode;
761 1.4.2.2 bouyer struct audio_params *p;
762 1.4.2.2 bouyer
763 1.4.2.2 bouyer for (mode = AUMODE_RECORD; mode != -1;
764 1.4.2.2 bouyer mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
765 1.4.2.2 bouyer if ((setmode & mode) == 0)
766 1.4.2.2 bouyer continue;
767 1.4.2.2 bouyer
768 1.4.2.2 bouyer p = mode == AUMODE_PLAY ? play : rec;
769 1.4.2.2 bouyer
770 1.4.2.2 bouyer if (p == NULL) continue;
771 1.4.2.2 bouyer
772 1.4.2.2 bouyer for (x = 0; x < 8; x++) {
773 1.4.2.2 bouyer if (p->sample_rate <
774 1.4.2.2 bouyer (samplerates[x] + samplerates[x + 1]) / 2)
775 1.4.2.2 bouyer break;
776 1.4.2.2 bouyer }
777 1.4.2.2 bouyer if (x == 8)
778 1.4.2.2 bouyer return (EINVAL);
779 1.4.2.2 bouyer
780 1.4.2.2 bouyer p->sample_rate = samplerates[x];
781 1.4.2.2 bouyer nm_loadcoeff(sc, mode, x);
782 1.4.2.2 bouyer
783 1.4.2.2 bouyer x <<= 4;
784 1.4.2.2 bouyer x &= NM_RATE_MASK;
785 1.4.2.2 bouyer if (p->precision == 16)
786 1.4.2.2 bouyer x |= NM_RATE_BITS_16;
787 1.4.2.2 bouyer if (p->channels == 2)
788 1.4.2.2 bouyer x |= NM_RATE_STEREO;
789 1.4.2.2 bouyer
790 1.4.2.2 bouyer base = (mode == AUMODE_PLAY)?
791 1.4.2.2 bouyer NM_PLAYBACK_REG_OFFSET : NM_RECORD_REG_OFFSET;
792 1.4.2.2 bouyer nm_wr_1(sc, base + NM_RATE_REG_OFFSET, x);
793 1.4.2.2 bouyer
794 1.4.2.2 bouyer p->factor = 1;
795 1.4.2.2 bouyer p->sw_code = 0;
796 1.4.2.2 bouyer switch (p->encoding) {
797 1.4.2.2 bouyer case AUDIO_ENCODING_SLINEAR_BE:
798 1.4.2.2 bouyer if (p->precision == 16)
799 1.4.2.2 bouyer p->sw_code = swap_bytes;
800 1.4.2.2 bouyer else
801 1.4.2.2 bouyer p->sw_code = change_sign8;
802 1.4.2.2 bouyer break;
803 1.4.2.2 bouyer case AUDIO_ENCODING_SLINEAR_LE:
804 1.4.2.2 bouyer if (p->precision != 16)
805 1.4.2.2 bouyer p->sw_code = change_sign8;
806 1.4.2.2 bouyer break;
807 1.4.2.2 bouyer case AUDIO_ENCODING_ULINEAR_BE:
808 1.4.2.2 bouyer if (p->precision == 16) {
809 1.4.2.2 bouyer if (mode == AUMODE_PLAY)
810 1.4.2.2 bouyer p->sw_code =
811 1.4.2.2 bouyer swap_bytes_change_sign16_le;
812 1.4.2.2 bouyer else
813 1.4.2.2 bouyer p->sw_code =
814 1.4.2.2 bouyer change_sign16_swap_bytes_le;
815 1.4.2.2 bouyer }
816 1.4.2.2 bouyer break;
817 1.4.2.2 bouyer case AUDIO_ENCODING_ULINEAR_LE:
818 1.4.2.2 bouyer if (p->precision == 16)
819 1.4.2.2 bouyer p->sw_code = change_sign16_le;
820 1.4.2.2 bouyer break;
821 1.4.2.2 bouyer case AUDIO_ENCODING_ULAW:
822 1.4.2.2 bouyer if (mode == AUMODE_PLAY) {
823 1.4.2.2 bouyer p->factor = 2;
824 1.4.2.2 bouyer p->sw_code = mulaw_to_slinear16_le;
825 1.4.2.2 bouyer } else
826 1.4.2.2 bouyer p->sw_code = ulinear8_to_mulaw;
827 1.4.2.2 bouyer break;
828 1.4.2.2 bouyer case AUDIO_ENCODING_ALAW:
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 = alaw_to_slinear16_le;
832 1.4.2.2 bouyer } else
833 1.4.2.2 bouyer p->sw_code = ulinear8_to_alaw;
834 1.4.2.2 bouyer break;
835 1.4.2.2 bouyer default:
836 1.4.2.2 bouyer return (EINVAL);
837 1.4.2.2 bouyer }
838 1.4.2.2 bouyer }
839 1.4.2.2 bouyer
840 1.4.2.2 bouyer
841 1.4.2.2 bouyer return (0);
842 1.4.2.2 bouyer }
843 1.4.2.2 bouyer
844 1.4.2.2 bouyer int
845 1.4.2.2 bouyer neo_round_blocksize(void *addr, int blk)
846 1.4.2.2 bouyer {
847 1.4.2.2 bouyer
848 1.4.2.2 bouyer return (NM_BUFFSIZE / 2);
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_trigger_output(void *addr, void *start, void *end, int blksize,
853 1.4.2.2 bouyer void (*intr)(void *), void *arg, struct audio_params *param)
854 1.4.2.2 bouyer {
855 1.4.2.2 bouyer struct neo_softc *sc = addr;
856 1.4.2.2 bouyer int ssz;
857 1.4.2.2 bouyer
858 1.4.2.2 bouyer sc->pintr = intr;
859 1.4.2.2 bouyer sc->parg = arg;
860 1.4.2.2 bouyer
861 1.4.2.2 bouyer ssz = (param->precision * param->factor == 16) ? 2 : 1;
862 1.4.2.2 bouyer if (param->channels == 2)
863 1.4.2.2 bouyer ssz <<= 1;
864 1.4.2.2 bouyer
865 1.4.2.2 bouyer sc->pbufsize = ((char*)end - (char *)start);
866 1.4.2.2 bouyer sc->pblksize = blksize;
867 1.4.2.2 bouyer sc->pwmark = blksize;
868 1.4.2.2 bouyer
869 1.4.2.2 bouyer nm_wr_4(sc, NM_PBUFFER_START, sc->pbuf);
870 1.4.2.2 bouyer nm_wr_4(sc, NM_PBUFFER_END, sc->pbuf + sc->pbufsize - ssz);
871 1.4.2.2 bouyer nm_wr_4(sc, NM_PBUFFER_CURRP, sc->pbuf);
872 1.4.2.2 bouyer nm_wr_4(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pwmark);
873 1.4.2.2 bouyer nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, NM_PLAYBACK_FREERUN |
874 1.4.2.2 bouyer NM_PLAYBACK_ENABLE_FLAG);
875 1.4.2.2 bouyer nm_wr_2(sc, NM_AUDIO_MUTE_REG, 0);
876 1.4.2.2 bouyer
877 1.4.2.2 bouyer return (0);
878 1.4.2.2 bouyer }
879 1.4.2.2 bouyer
880 1.4.2.2 bouyer int
881 1.4.2.2 bouyer neo_trigger_input(void *addr, void *start, void *end, int blksize,
882 1.4.2.2 bouyer void (*intr)(void *), void *arg, struct audio_params *param)
883 1.4.2.2 bouyer {
884 1.4.2.2 bouyer struct neo_softc *sc = addr;
885 1.4.2.2 bouyer int ssz;
886 1.4.2.2 bouyer
887 1.4.2.2 bouyer sc->rintr = intr;
888 1.4.2.2 bouyer sc->rarg = arg;
889 1.4.2.2 bouyer
890 1.4.2.2 bouyer ssz = (param->precision * param->factor == 16) ? 2 : 1;
891 1.4.2.2 bouyer if (param->channels == 2)
892 1.4.2.2 bouyer ssz <<= 1;
893 1.4.2.2 bouyer
894 1.4.2.2 bouyer sc->rbufsize = ((char*)end - (char *)start);
895 1.4.2.2 bouyer sc->rblksize = blksize;
896 1.4.2.2 bouyer sc->rwmark = blksize;
897 1.4.2.2 bouyer
898 1.4.2.2 bouyer nm_wr_4(sc, NM_RBUFFER_START, sc->rbuf);
899 1.4.2.2 bouyer nm_wr_4(sc, NM_RBUFFER_END, sc->rbuf + sc->rbufsize);
900 1.4.2.2 bouyer nm_wr_4(sc, NM_RBUFFER_CURRP, sc->rbuf);
901 1.4.2.2 bouyer nm_wr_4(sc, NM_RBUFFER_WMARK, sc->rbuf + sc->rwmark);
902 1.4.2.2 bouyer nm_wr_1(sc, NM_RECORD_ENABLE_REG, NM_RECORD_FREERUN |
903 1.4.2.2 bouyer NM_RECORD_ENABLE_FLAG);
904 1.4.2.2 bouyer
905 1.4.2.2 bouyer return (0);
906 1.4.2.2 bouyer }
907 1.4.2.2 bouyer
908 1.4.2.2 bouyer int
909 1.4.2.2 bouyer neo_halt_output(void *addr)
910 1.4.2.2 bouyer {
911 1.4.2.2 bouyer struct neo_softc *sc = (struct neo_softc *)addr;
912 1.4.2.2 bouyer
913 1.4.2.2 bouyer nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, 0);
914 1.4.2.2 bouyer nm_wr_2(sc, NM_AUDIO_MUTE_REG, NM_AUDIO_MUTE_BOTH);
915 1.4.2.2 bouyer
916 1.4.2.2 bouyer return (0);
917 1.4.2.2 bouyer }
918 1.4.2.2 bouyer
919 1.4.2.2 bouyer int
920 1.4.2.2 bouyer neo_halt_input(void *addr)
921 1.4.2.2 bouyer {
922 1.4.2.2 bouyer struct neo_softc *sc = (struct neo_softc *)addr;
923 1.4.2.2 bouyer
924 1.4.2.2 bouyer nm_wr_1(sc, NM_RECORD_ENABLE_REG, 0);
925 1.4.2.2 bouyer
926 1.4.2.2 bouyer return (0);
927 1.4.2.2 bouyer }
928 1.4.2.2 bouyer
929 1.4.2.2 bouyer int
930 1.4.2.2 bouyer neo_getdev(void *addr, struct audio_device *retp)
931 1.4.2.2 bouyer {
932 1.4.2.2 bouyer
933 1.4.2.2 bouyer *retp = neo_device;
934 1.4.2.2 bouyer return (0);
935 1.4.2.2 bouyer }
936 1.4.2.2 bouyer
937 1.4.2.2 bouyer int
938 1.4.2.2 bouyer neo_mixer_set_port(void *addr, mixer_ctrl_t *cp)
939 1.4.2.2 bouyer {
940 1.4.2.2 bouyer struct neo_softc *sc = addr;
941 1.4.2.2 bouyer
942 1.4.2.2 bouyer return ((sc->codec_if->vtbl->mixer_set_port)(sc->codec_if, cp));
943 1.4.2.2 bouyer }
944 1.4.2.2 bouyer
945 1.4.2.2 bouyer int
946 1.4.2.2 bouyer neo_mixer_get_port(void *addr, mixer_ctrl_t *cp)
947 1.4.2.2 bouyer {
948 1.4.2.2 bouyer struct neo_softc *sc = addr;
949 1.4.2.2 bouyer
950 1.4.2.2 bouyer return ((sc->codec_if->vtbl->mixer_get_port)(sc->codec_if, cp));
951 1.4.2.2 bouyer }
952 1.4.2.2 bouyer
953 1.4.2.2 bouyer int
954 1.4.2.2 bouyer neo_query_devinfo(void *addr, mixer_devinfo_t *dip)
955 1.4.2.2 bouyer {
956 1.4.2.2 bouyer struct neo_softc *sc = addr;
957 1.4.2.2 bouyer
958 1.4.2.2 bouyer return ((sc->codec_if->vtbl->query_devinfo)(sc->codec_if, dip));
959 1.4.2.2 bouyer }
960 1.4.2.2 bouyer
961 1.4.2.2 bouyer void *
962 1.4.2.2 bouyer neo_malloc(void *addr, int direction, size_t size, int pool, int flags)
963 1.4.2.2 bouyer {
964 1.4.2.2 bouyer struct neo_softc *sc = addr;
965 1.4.2.2 bouyer void *rv = NULL;
966 1.4.2.2 bouyer
967 1.4.2.2 bouyer switch (direction) {
968 1.4.2.2 bouyer case AUMODE_PLAY:
969 1.4.2.2 bouyer if (sc->pbuf_allocated == 0) {
970 1.4.2.2 bouyer rv = (void *) sc->pbuf_vaddr;
971 1.4.2.2 bouyer sc->pbuf_allocated = 1;
972 1.4.2.2 bouyer }
973 1.4.2.2 bouyer break;
974 1.4.2.2 bouyer
975 1.4.2.2 bouyer case AUMODE_RECORD:
976 1.4.2.2 bouyer if (sc->rbuf_allocated == 0) {
977 1.4.2.2 bouyer rv = (void *) sc->rbuf_vaddr;
978 1.4.2.2 bouyer sc->rbuf_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
983 1.4.2.2 bouyer return (rv);
984 1.4.2.2 bouyer }
985 1.4.2.2 bouyer
986 1.4.2.2 bouyer void
987 1.4.2.2 bouyer neo_free(void *addr, void *ptr, int pool)
988 1.4.2.2 bouyer {
989 1.4.2.2 bouyer struct neo_softc *sc = addr;
990 1.4.2.2 bouyer vaddr_t v = (vaddr_t) ptr;
991 1.4.2.2 bouyer
992 1.4.2.2 bouyer if (v == sc->pbuf_vaddr)
993 1.4.2.2 bouyer sc->pbuf_allocated = 0;
994 1.4.2.2 bouyer else if (v == sc->rbuf_vaddr)
995 1.4.2.2 bouyer sc->rbuf_allocated = 0;
996 1.4.2.2 bouyer else
997 1.4.2.2 bouyer printf("neo_free: bad address %p\n", ptr);
998 1.4.2.2 bouyer }
999 1.4.2.2 bouyer
1000 1.4.2.2 bouyer size_t
1001 1.4.2.2 bouyer neo_round_buffersize(void *addr, int direction, size_t size)
1002 1.4.2.2 bouyer {
1003 1.4.2.2 bouyer
1004 1.4.2.2 bouyer return (NM_BUFFSIZE);
1005 1.4.2.2 bouyer }
1006 1.4.2.2 bouyer
1007 1.4.2.2 bouyer paddr_t
1008 1.4.2.2 bouyer neo_mappage(void *addr, void *mem, off_t off, int prot)
1009 1.4.2.2 bouyer {
1010 1.4.2.2 bouyer struct neo_softc *sc = addr;
1011 1.4.2.2 bouyer vaddr_t v = (vaddr_t) mem;
1012 1.4.2.2 bouyer bus_addr_t pciaddr;
1013 1.4.2.2 bouyer
1014 1.4.2.2 bouyer /* XXX Need new mapping code. */
1015 1.4.2.2 bouyer
1016 1.4.2.2 bouyer if (v == sc->pbuf_vaddr)
1017 1.4.2.2 bouyer pciaddr = sc->pbuf_pciaddr;
1018 1.4.2.2 bouyer else if (v == sc->rbuf_vaddr)
1019 1.4.2.2 bouyer pciaddr = sc->rbuf_pciaddr;
1020 1.4.2.2 bouyer else
1021 1.4.2.2 bouyer return (-1);
1022 1.4.2.2 bouyer
1023 1.4.2.2 bouyer #ifdef __i386__
1024 1.4.2.2 bouyer return (i386_btop(pciaddr + off));
1025 1.4.2.2 bouyer #else
1026 1.4.2.2 bouyer return (-1);
1027 1.4.2.2 bouyer #endif
1028 1.4.2.2 bouyer }
1029 1.4.2.2 bouyer
1030 1.4.2.2 bouyer int
1031 1.4.2.2 bouyer neo_get_props(void *addr)
1032 1.4.2.2 bouyer {
1033 1.4.2.2 bouyer
1034 1.4.2.2 bouyer return (AUDIO_PROP_INDEPENDENT | AUDIO_PROP_MMAP |
1035 1.4.2.2 bouyer AUDIO_PROP_FULLDUPLEX);
1036 1.4.2.2 bouyer }
1037