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