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