neo.c revision 1.53 1 1.53 isaki /* $NetBSD: neo.c,v 1.53 2019/05/08 13:40:19 isaki 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.11 lukem
34 1.11 lukem #include <sys/cdefs.h>
35 1.53 isaki __KERNEL_RCSID(0, "$NetBSD: neo.c,v 1.53 2019/05/08 13:40:19 isaki Exp $");
36 1.1 thorpej
37 1.1 thorpej #include <sys/param.h>
38 1.1 thorpej #include <sys/systm.h>
39 1.1 thorpej #include <sys/kernel.h>
40 1.46 jmcneill #include <sys/kmem.h>
41 1.1 thorpej #include <sys/device.h>
42 1.36 ad #include <sys/bus.h>
43 1.46 jmcneill #include <sys/audioio.h>
44 1.1 thorpej
45 1.53 isaki #include <dev/audio/audio_if.h>
46 1.1 thorpej
47 1.1 thorpej #include <dev/ic/ac97var.h>
48 1.1 thorpej
49 1.46 jmcneill #include <dev/pci/pcidevs.h>
50 1.46 jmcneill #include <dev/pci/pcivar.h>
51 1.46 jmcneill #include <dev/pci/neoreg.h>
52 1.46 jmcneill #include <dev/pci/neo-coeff.h>
53 1.1 thorpej
54 1.1 thorpej /* -------------------------------------------------------------------- */
55 1.27 perry /*
56 1.1 thorpej * As of 04/13/00, public documentation on the Neomagic 256 is not available.
57 1.1 thorpej * These comments were gleaned by looking at the driver carefully.
58 1.1 thorpej *
59 1.1 thorpej * The Neomagic 256 AV/ZX chips provide both video and audio capabilities
60 1.1 thorpej * on one chip. About 2-6 megabytes of memory are associated with
61 1.1 thorpej * the chip. Most of this goes to video frame buffers, but some is used for
62 1.1 thorpej * audio buffering
63 1.1 thorpej *
64 1.1 thorpej * Unlike most PCI audio chips, the Neomagic chip does not rely on DMA.
65 1.1 thorpej * Instead, the chip allows you to carve out two ring buffers out of its
66 1.1 thorpej * memory. However you carve this and how much you can carve seems to be
67 1.1 thorpej * voodoo. The algorithm is in nm_init.
68 1.1 thorpej *
69 1.27 perry * Most Neomagic audio chips use the AC-97 codec interface. However, there
70 1.1 thorpej * seem to be a select few chips 256AV chips that do not support AC-97.
71 1.1 thorpej * This driver does not support them but there are rumors that it
72 1.12 simonb * might work with wss isa drivers. This might require some playing around
73 1.1 thorpej * with your BIOS.
74 1.1 thorpej *
75 1.1 thorpej * The Neomagic 256 AV/ZX have 2 PCI I/O region descriptors. Both of
76 1.1 thorpej * them describe a memory region. The frame buffer is the first region
77 1.48 msaitoh * and the register set is the second region.
78 1.1 thorpej *
79 1.1 thorpej * The register manipulation logic is taken from the Linux driver,
80 1.1 thorpej * which is in the public domain.
81 1.1 thorpej *
82 1.1 thorpej * The Neomagic is even nice enough to map the AC-97 codec registers into
83 1.1 thorpej * the register space to allow direct manipulation. Watch out, accessing
84 1.1 thorpej * AC-97 registers on the Neomagic requires great delicateness, otherwise
85 1.1 thorpej * the thing will hang the PCI bus, rendering your system frozen.
86 1.1 thorpej *
87 1.1 thorpej * For one, it seems the Neomagic status register that reports AC-97
88 1.1 thorpej * readiness should NOT be polled more often than once each 1ms.
89 1.1 thorpej *
90 1.1 thorpej * Also, writes to the AC-97 register space may take order 40us to
91 1.1 thorpej * complete.
92 1.1 thorpej *
93 1.12 simonb * Unlike many sound engines, the Neomagic does not support (as far as
94 1.1 thorpej * we know :) the notion of interrupting every n bytes transferred,
95 1.1 thorpej * unlike many DMA engines. Instead, it allows you to specify one
96 1.1 thorpej * location in each ring buffer (called the watermark). When the chip
97 1.1 thorpej * passes that location while playing, it signals an interrupt.
98 1.27 perry *
99 1.1 thorpej * The ring buffer size is currently 16k. That is about 100ms of audio
100 1.18 tsutsui * at 44.1kHz/stero/16 bit. However, to keep the buffer full, interrupts
101 1.1 thorpej * are generated more often than that, so 20-40 interrupts per second
102 1.1 thorpej * should not be unexpected. Increasing BUFFSIZE should help minimize
103 1.1 thorpej * of glitches due to drivers that spend to much time looping at high
104 1.1 thorpej * privelege levels as well as the impact of badly written audio
105 1.1 thorpej * interface clients.
106 1.1 thorpej *
107 1.1 thorpej * TO-DO list:
108 1.1 thorpej * Figure out interaction with video stuff (look at Xfree86 driver?)
109 1.1 thorpej *
110 1.1 thorpej * Figure out how to shrink that huge table neo-coeff.h
111 1.1 thorpej */
112 1.1 thorpej
113 1.1 thorpej #define NM_BUFFSIZE 16384
114 1.1 thorpej
115 1.1 thorpej /* device private data */
116 1.1 thorpej struct neo_softc {
117 1.49 chs device_t dev;
118 1.46 jmcneill kmutex_t lock;
119 1.46 jmcneill kmutex_t intr_lock;
120 1.1 thorpej
121 1.1 thorpej bus_space_tag_t bufiot;
122 1.26 kent bus_space_handle_t bufioh;
123 1.1 thorpej
124 1.1 thorpej bus_space_tag_t regiot;
125 1.26 kent bus_space_handle_t regioh;
126 1.1 thorpej
127 1.26 kent uint32_t type;
128 1.26 kent void *ih;
129 1.1 thorpej
130 1.19 wiz void (*pintr)(void *); /* DMA completion intr handler */
131 1.1 thorpej void *parg; /* arg for intr() */
132 1.1 thorpej
133 1.19 wiz void (*rintr)(void *); /* DMA completion intr handler */
134 1.1 thorpej void *rarg; /* arg for intr() */
135 1.1 thorpej
136 1.1 thorpej vaddr_t buf_vaddr;
137 1.1 thorpej vaddr_t rbuf_vaddr;
138 1.1 thorpej vaddr_t pbuf_vaddr;
139 1.1 thorpej int pbuf_allocated;
140 1.1 thorpej int rbuf_allocated;
141 1.1 thorpej
142 1.3 thorpej bus_addr_t buf_pciaddr;
143 1.3 thorpej bus_addr_t rbuf_pciaddr;
144 1.3 thorpej bus_addr_t pbuf_pciaddr;
145 1.3 thorpej
146 1.26 kent uint32_t ac97_base, ac97_status, ac97_busy;
147 1.26 kent uint32_t buftop, pbuf, rbuf, cbuf, acbuf;
148 1.26 kent uint32_t playint, recint, misc1int, misc2int;
149 1.26 kent uint32_t irsz, badintr;
150 1.1 thorpej
151 1.26 kent uint32_t pbufsize;
152 1.26 kent uint32_t rbufsize;
153 1.1 thorpej
154 1.26 kent uint32_t pblksize;
155 1.26 kent uint32_t rblksize;
156 1.1 thorpej
157 1.26 kent uint32_t pwmark;
158 1.26 kent uint32_t rwmark;
159 1.1 thorpej
160 1.1 thorpej struct ac97_codec_if *codec_if;
161 1.5 sommerfe struct ac97_host_if host_if;
162 1.1 thorpej };
163 1.1 thorpej
164 1.1 thorpej /* -------------------------------------------------------------------- */
165 1.1 thorpej
166 1.1 thorpej /*
167 1.1 thorpej * prototypes
168 1.1 thorpej */
169 1.1 thorpej
170 1.26 kent static int nm_waitcd(struct neo_softc *);
171 1.26 kent static int nm_loadcoeff(struct neo_softc *, int, int);
172 1.1 thorpej static int nm_init(struct neo_softc *);
173 1.1 thorpej
174 1.41 cegger static int neo_match(device_t, cfdata_t, void *);
175 1.41 cegger static void neo_attach(device_t, device_t, void *);
176 1.29 thorpej static int neo_intr(void *);
177 1.53 isaki static int neo_rate2index(u_int);
178 1.29 thorpej
179 1.53 isaki static int neo_query_format(void *, audio_format_query_t *);
180 1.53 isaki static int neo_set_format(void *, int,
181 1.53 isaki const audio_params_t *, const audio_params_t *,
182 1.53 isaki audio_filter_reg_t *, audio_filter_reg_t *);
183 1.29 thorpej static int neo_round_blocksize(void *, int, int, const audio_params_t *);
184 1.29 thorpej static int neo_trigger_output(void *, void *, void *, int,
185 1.29 thorpej void (*)(void *), void *,
186 1.29 thorpej const audio_params_t *);
187 1.29 thorpej static int neo_trigger_input(void *, void *, void *, int,
188 1.29 thorpej void (*)(void *), void *,
189 1.29 thorpej const audio_params_t *);
190 1.29 thorpej static int neo_halt_output(void *);
191 1.29 thorpej static int neo_halt_input(void *);
192 1.29 thorpej static int neo_getdev(void *, struct audio_device *);
193 1.29 thorpej static int neo_mixer_set_port(void *, mixer_ctrl_t *);
194 1.29 thorpej static int neo_mixer_get_port(void *, mixer_ctrl_t *);
195 1.29 thorpej static int neo_attach_codec(void *, struct ac97_codec_if *);
196 1.29 thorpej static int neo_read_codec(void *, uint8_t, uint16_t *);
197 1.29 thorpej static int neo_write_codec(void *, uint8_t, uint16_t);
198 1.29 thorpej static int neo_reset_codec(void *);
199 1.29 thorpej static enum ac97_host_flags neo_flags_codec(void *);
200 1.29 thorpej static int neo_query_devinfo(void *, mixer_devinfo_t *);
201 1.46 jmcneill static void * neo_malloc(void *, int, size_t);
202 1.46 jmcneill static void neo_free(void *, void *, size_t);
203 1.29 thorpej static size_t neo_round_buffersize(void *, int, size_t);
204 1.29 thorpej static int neo_get_props(void *);
205 1.46 jmcneill static void neo_get_locks(void *, kmutex_t **, kmutex_t **);
206 1.1 thorpej
207 1.49 chs CFATTACH_DECL_NEW(neo, sizeof(struct neo_softc),
208 1.16 thorpej neo_match, neo_attach, NULL, NULL);
209 1.1 thorpej
210 1.29 thorpej static struct audio_device neo_device = {
211 1.1 thorpej "NeoMagic 256",
212 1.1 thorpej "",
213 1.1 thorpej "neo"
214 1.1 thorpej };
215 1.1 thorpej
216 1.53 isaki /*
217 1.53 isaki * The frequency list in this format is also referred from neo_rate2index().
218 1.53 isaki * So don't rearrange or delete entries.
219 1.53 isaki */
220 1.53 isaki static const struct audio_format neo_formats[] = {
221 1.53 isaki {
222 1.53 isaki .mode = AUMODE_PLAY | AUMODE_RECORD,
223 1.53 isaki .encoding = AUDIO_ENCODING_SLINEAR_LE,
224 1.53 isaki .validbits = 16,
225 1.53 isaki .precision = 16,
226 1.53 isaki .channels = 2,
227 1.53 isaki .channel_mask = AUFMT_STEREO,
228 1.53 isaki .frequency_type = 8,
229 1.53 isaki .frequency =
230 1.53 isaki { 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000 },
231 1.53 isaki },
232 1.25 kent };
233 1.53 isaki #define NEO_NFORMATS __arraycount(neo_formats)
234 1.25 kent
235 1.1 thorpej /* -------------------------------------------------------------------- */
236 1.1 thorpej
237 1.29 thorpej static const struct audio_hw_if neo_hw_if = {
238 1.53 isaki .query_format = neo_query_format,
239 1.53 isaki .set_format = neo_set_format,
240 1.52 isaki .round_blocksize = neo_round_blocksize,
241 1.52 isaki .halt_output = neo_halt_output,
242 1.52 isaki .halt_input = neo_halt_input,
243 1.52 isaki .getdev = neo_getdev,
244 1.52 isaki .set_port = neo_mixer_set_port,
245 1.52 isaki .get_port = neo_mixer_get_port,
246 1.52 isaki .query_devinfo = neo_query_devinfo,
247 1.52 isaki .allocm = neo_malloc,
248 1.52 isaki .freem = neo_free,
249 1.52 isaki .round_buffersize = neo_round_buffersize,
250 1.52 isaki .get_props = neo_get_props,
251 1.52 isaki .trigger_output = neo_trigger_output,
252 1.52 isaki .trigger_input = neo_trigger_input,
253 1.52 isaki .get_locks = neo_get_locks,
254 1.1 thorpej };
255 1.1 thorpej
256 1.1 thorpej /* -------------------------------------------------------------------- */
257 1.1 thorpej
258 1.1 thorpej #define nm_rd_1(sc, regno) \
259 1.1 thorpej bus_space_read_1((sc)->regiot, (sc)->regioh, (regno))
260 1.1 thorpej
261 1.1 thorpej #define nm_rd_2(sc, regno) \
262 1.1 thorpej bus_space_read_2((sc)->regiot, (sc)->regioh, (regno))
263 1.1 thorpej
264 1.1 thorpej #define nm_rd_4(sc, regno) \
265 1.1 thorpej bus_space_read_4((sc)->regiot, (sc)->regioh, (regno))
266 1.1 thorpej
267 1.1 thorpej #define nm_wr_1(sc, regno, val) \
268 1.1 thorpej bus_space_write_1((sc)->regiot, (sc)->regioh, (regno), (val))
269 1.1 thorpej
270 1.1 thorpej #define nm_wr_2(sc, regno, val) \
271 1.1 thorpej bus_space_write_2((sc)->regiot, (sc)->regioh, (regno), (val))
272 1.1 thorpej
273 1.1 thorpej #define nm_wr_4(sc, regno, val) \
274 1.1 thorpej bus_space_write_4((sc)->regiot, (sc)->regioh, (regno), (val))
275 1.1 thorpej
276 1.1 thorpej #define nm_rdbuf_4(sc, regno) \
277 1.1 thorpej bus_space_read_4((sc)->bufiot, (sc)->bufioh, (regno))
278 1.1 thorpej
279 1.1 thorpej #define nm_wrbuf_1(sc, regno, val) \
280 1.1 thorpej bus_space_write_1((sc)->bufiot, (sc)->bufioh, (regno), (val))
281 1.1 thorpej
282 1.1 thorpej /* ac97 codec */
283 1.1 thorpej static int
284 1.1 thorpej nm_waitcd(struct neo_softc *sc)
285 1.1 thorpej {
286 1.26 kent int cnt;
287 1.26 kent int fail;
288 1.1 thorpej
289 1.26 kent cnt = 10;
290 1.26 kent fail = 1;
291 1.1 thorpej while (cnt-- > 0) {
292 1.1 thorpej if (nm_rd_2(sc, sc->ac97_status) & sc->ac97_busy)
293 1.1 thorpej DELAY(100);
294 1.1 thorpej else {
295 1.26 kent fail = 0;
296 1.1 thorpej break;
297 1.1 thorpej }
298 1.1 thorpej }
299 1.26 kent return fail;
300 1.1 thorpej }
301 1.1 thorpej
302 1.1 thorpej static void
303 1.26 kent nm_ackint(struct neo_softc *sc, uint32_t num)
304 1.1 thorpej {
305 1.1 thorpej
306 1.1 thorpej switch (sc->type) {
307 1.1 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
308 1.1 thorpej nm_wr_2(sc, NM_INT_REG, num << 1);
309 1.1 thorpej break;
310 1.1 thorpej
311 1.1 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
312 1.1 thorpej nm_wr_4(sc, NM_INT_REG, num);
313 1.1 thorpej break;
314 1.1 thorpej }
315 1.1 thorpej }
316 1.1 thorpej
317 1.1 thorpej static int
318 1.1 thorpej nm_loadcoeff(struct neo_softc *sc, int dir, int num)
319 1.1 thorpej {
320 1.1 thorpej int ofs, sz, i;
321 1.26 kent uint32_t addr;
322 1.1 thorpej
323 1.1 thorpej addr = (dir == AUMODE_PLAY)? 0x01c : 0x21c;
324 1.1 thorpej if (dir == AUMODE_RECORD)
325 1.1 thorpej num += 8;
326 1.1 thorpej sz = coefficientSizes[num];
327 1.1 thorpej ofs = 0;
328 1.1 thorpej while (num-- > 0)
329 1.1 thorpej ofs+= coefficientSizes[num];
330 1.1 thorpej for (i = 0; i < sz; i++)
331 1.1 thorpej nm_wrbuf_1(sc, sc->cbuf + i, coefficients[ofs + i]);
332 1.1 thorpej nm_wr_4(sc, addr, sc->cbuf);
333 1.1 thorpej if (dir == AUMODE_PLAY)
334 1.1 thorpej sz--;
335 1.1 thorpej nm_wr_4(sc, addr + 4, sc->cbuf + sz);
336 1.1 thorpej return 0;
337 1.1 thorpej }
338 1.1 thorpej
339 1.1 thorpej /* The interrupt handler */
340 1.29 thorpej static int
341 1.1 thorpej neo_intr(void *p)
342 1.1 thorpej {
343 1.26 kent struct neo_softc *sc;
344 1.20 simonb int status, x;
345 1.26 kent int rv;
346 1.1 thorpej
347 1.26 kent sc = (struct neo_softc *)p;
348 1.46 jmcneill mutex_spin_enter(&sc->intr_lock);
349 1.46 jmcneill
350 1.26 kent rv = 0;
351 1.1 thorpej status = (sc->irsz == 2) ?
352 1.1 thorpej nm_rd_2(sc, NM_INT_REG) :
353 1.1 thorpej nm_rd_4(sc, NM_INT_REG);
354 1.1 thorpej
355 1.1 thorpej if (status & sc->playint) {
356 1.1 thorpej status &= ~sc->playint;
357 1.1 thorpej
358 1.1 thorpej sc->pwmark += sc->pblksize;
359 1.1 thorpej sc->pwmark %= sc->pbufsize;
360 1.1 thorpej
361 1.1 thorpej nm_wr_4(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pwmark);
362 1.1 thorpej
363 1.1 thorpej nm_ackint(sc, sc->playint);
364 1.1 thorpej
365 1.1 thorpej if (sc->pintr)
366 1.1 thorpej (*sc->pintr)(sc->parg);
367 1.1 thorpej
368 1.1 thorpej rv = 1;
369 1.1 thorpej }
370 1.1 thorpej if (status & sc->recint) {
371 1.1 thorpej status &= ~sc->recint;
372 1.1 thorpej
373 1.1 thorpej sc->rwmark += sc->rblksize;
374 1.1 thorpej sc->rwmark %= sc->rbufsize;
375 1.28 kent nm_wr_4(sc, NM_RBUFFER_WMARK, sc->rbuf + sc->rwmark);
376 1.1 thorpej nm_ackint(sc, sc->recint);
377 1.1 thorpej if (sc->rintr)
378 1.1 thorpej (*sc->rintr)(sc->rarg);
379 1.1 thorpej
380 1.1 thorpej rv = 1;
381 1.1 thorpej }
382 1.1 thorpej if (status & sc->misc1int) {
383 1.1 thorpej status &= ~sc->misc1int;
384 1.1 thorpej nm_ackint(sc, sc->misc1int);
385 1.1 thorpej x = nm_rd_1(sc, 0x400);
386 1.1 thorpej nm_wr_1(sc, 0x400, x | 2);
387 1.49 chs printf("%s: misc int 1\n", device_xname(sc->dev));
388 1.1 thorpej rv = 1;
389 1.1 thorpej }
390 1.1 thorpej if (status & sc->misc2int) {
391 1.1 thorpej status &= ~sc->misc2int;
392 1.1 thorpej nm_ackint(sc, sc->misc2int);
393 1.1 thorpej x = nm_rd_1(sc, 0x400);
394 1.1 thorpej nm_wr_1(sc, 0x400, x & ~2);
395 1.49 chs printf("%s: misc int 2\n", device_xname(sc->dev));
396 1.1 thorpej rv = 1;
397 1.1 thorpej }
398 1.1 thorpej if (status) {
399 1.1 thorpej status &= ~sc->misc2int;
400 1.1 thorpej nm_ackint(sc, sc->misc2int);
401 1.49 chs printf("%s: unknown int\n", device_xname(sc->dev));
402 1.1 thorpej rv = 1;
403 1.1 thorpej }
404 1.1 thorpej
405 1.46 jmcneill mutex_spin_exit(&sc->intr_lock);
406 1.26 kent return rv;
407 1.1 thorpej }
408 1.1 thorpej
409 1.1 thorpej /* -------------------------------------------------------------------- */
410 1.1 thorpej
411 1.1 thorpej /*
412 1.1 thorpej * Probe and attach the card
413 1.1 thorpej */
414 1.1 thorpej
415 1.1 thorpej static int
416 1.1 thorpej nm_init(struct neo_softc *sc)
417 1.1 thorpej {
418 1.26 kent uint32_t ofs, i;
419 1.1 thorpej
420 1.1 thorpej switch (sc->type) {
421 1.1 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
422 1.1 thorpej sc->ac97_base = NM_MIXER_OFFSET;
423 1.1 thorpej sc->ac97_status = NM_MIXER_STATUS_OFFSET;
424 1.1 thorpej sc->ac97_busy = NM_MIXER_READY_MASK;
425 1.1 thorpej
426 1.1 thorpej sc->buftop = 2560 * 1024;
427 1.1 thorpej
428 1.1 thorpej sc->irsz = 2;
429 1.1 thorpej sc->playint = NM_PLAYBACK_INT;
430 1.1 thorpej sc->recint = NM_RECORD_INT;
431 1.1 thorpej sc->misc1int = NM_MISC_INT_1;
432 1.1 thorpej sc->misc2int = NM_MISC_INT_2;
433 1.1 thorpej break;
434 1.1 thorpej
435 1.1 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
436 1.1 thorpej sc->ac97_base = NM_MIXER_OFFSET;
437 1.1 thorpej sc->ac97_status = NM2_MIXER_STATUS_OFFSET;
438 1.1 thorpej sc->ac97_busy = NM2_MIXER_READY_MASK;
439 1.1 thorpej
440 1.1 thorpej sc->buftop = (nm_rd_2(sc, 0xa0b) ? 6144 : 4096) * 1024;
441 1.1 thorpej
442 1.1 thorpej sc->irsz = 4;
443 1.1 thorpej sc->playint = NM2_PLAYBACK_INT;
444 1.1 thorpej sc->recint = NM2_RECORD_INT;
445 1.1 thorpej sc->misc1int = NM2_MISC_INT_1;
446 1.1 thorpej sc->misc2int = NM2_MISC_INT_2;
447 1.1 thorpej break;
448 1.1 thorpej #ifdef DIAGNOSTIC
449 1.1 thorpej default:
450 1.1 thorpej panic("nm_init: impossible");
451 1.1 thorpej #endif
452 1.1 thorpej }
453 1.1 thorpej
454 1.1 thorpej sc->badintr = 0;
455 1.1 thorpej ofs = sc->buftop - 0x0400;
456 1.1 thorpej sc->buftop -= 0x1400;
457 1.1 thorpej
458 1.26 kent if ((nm_rdbuf_4(sc, ofs) & NM_SIG_MASK) == NM_SIGNATURE) {
459 1.1 thorpej i = nm_rdbuf_4(sc, ofs + 4);
460 1.1 thorpej if (i != 0 && i != 0xffffffff)
461 1.1 thorpej sc->buftop = i;
462 1.1 thorpej }
463 1.1 thorpej
464 1.1 thorpej sc->cbuf = sc->buftop - NM_MAX_COEFFICIENT;
465 1.1 thorpej sc->rbuf = sc->cbuf - NM_BUFFSIZE;
466 1.1 thorpej sc->pbuf = sc->rbuf - NM_BUFFSIZE;
467 1.1 thorpej sc->acbuf = sc->pbuf - (NM_TOTAL_COEFF_COUNT * 4);
468 1.1 thorpej
469 1.1 thorpej sc->buf_vaddr = (vaddr_t) bus_space_vaddr(sc->bufiot, sc->bufioh);
470 1.1 thorpej sc->rbuf_vaddr = sc->buf_vaddr + sc->rbuf;
471 1.1 thorpej sc->pbuf_vaddr = sc->buf_vaddr + sc->pbuf;
472 1.1 thorpej
473 1.3 thorpej sc->rbuf_pciaddr = sc->buf_pciaddr + sc->rbuf;
474 1.3 thorpej sc->pbuf_pciaddr = sc->buf_pciaddr + sc->pbuf;
475 1.3 thorpej
476 1.1 thorpej nm_wr_1(sc, 0, 0x11);
477 1.1 thorpej nm_wr_1(sc, NM_RECORD_ENABLE_REG, 0);
478 1.1 thorpej nm_wr_2(sc, 0x214, 0);
479 1.1 thorpej
480 1.1 thorpej return 0;
481 1.1 thorpej }
482 1.1 thorpej
483 1.29 thorpej static int
484 1.41 cegger neo_match(device_t parent, cfdata_t match, void *aux)
485 1.2 thorpej {
486 1.26 kent struct pci_attach_args *pa;
487 1.2 thorpej pcireg_t subdev;
488 1.2 thorpej
489 1.26 kent pa = aux;
490 1.2 thorpej if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NEOMAGIC)
491 1.26 kent return 0;
492 1.2 thorpej
493 1.2 thorpej subdev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
494 1.2 thorpej
495 1.2 thorpej switch (PCI_PRODUCT(pa->pa_id)) {
496 1.2 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
497 1.2 thorpej /*
498 1.2 thorpej * We have to weed-out the non-AC'97 versions of
499 1.2 thorpej * the chip (i.e. the ones that are known to work
500 1.2 thorpej * in WSS emulation mode), as they won't work with
501 1.2 thorpej * this driver.
502 1.2 thorpej */
503 1.2 thorpej switch (PCI_VENDOR(subdev)) {
504 1.2 thorpej case PCI_VENDOR_DELL:
505 1.2 thorpej switch (PCI_PRODUCT(subdev)) {
506 1.2 thorpej case 0x008f:
507 1.26 kent return 0;
508 1.2 thorpej }
509 1.2 thorpej break;
510 1.2 thorpej
511 1.2 thorpej case PCI_VENDOR_HP:
512 1.2 thorpej switch (PCI_PRODUCT(subdev)) {
513 1.2 thorpej case 0x0007:
514 1.26 kent return 0;
515 1.2 thorpej }
516 1.8 drochner break;
517 1.8 drochner
518 1.8 drochner case PCI_VENDOR_IBM:
519 1.8 drochner switch (PCI_PRODUCT(subdev)) {
520 1.8 drochner case 0x00dd:
521 1.26 kent return 0;
522 1.8 drochner }
523 1.8 drochner break;
524 1.2 thorpej }
525 1.26 kent return 1;
526 1.2 thorpej
527 1.2 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
528 1.26 kent return 1;
529 1.2 thorpej }
530 1.2 thorpej
531 1.26 kent return 0;
532 1.2 thorpej }
533 1.2 thorpej
534 1.37 jmcneill static bool
535 1.45 dyoung neo_resume(device_t dv, const pmf_qual_t *qual)
536 1.5 sommerfe {
537 1.37 jmcneill struct neo_softc *sc = device_private(dv);
538 1.37 jmcneill
539 1.46 jmcneill mutex_enter(&sc->lock);
540 1.46 jmcneill mutex_spin_enter(&sc->intr_lock);
541 1.37 jmcneill nm_init(sc);
542 1.46 jmcneill mutex_spin_exit(&sc->intr_lock);
543 1.46 jmcneill sc->codec_if->vtbl->restore_ports(sc->codec_if);
544 1.46 jmcneill mutex_exit(&sc->lock);
545 1.5 sommerfe
546 1.37 jmcneill return true;
547 1.5 sommerfe }
548 1.5 sommerfe
549 1.29 thorpej static void
550 1.41 cegger neo_attach(device_t parent, device_t self, void *aux)
551 1.1 thorpej {
552 1.26 kent struct neo_softc *sc;
553 1.26 kent struct pci_attach_args *pa;
554 1.26 kent pci_chipset_tag_t pc;
555 1.1 thorpej char const *intrstr;
556 1.1 thorpej pci_intr_handle_t ih;
557 1.1 thorpej pcireg_t csr;
558 1.46 jmcneill int error;
559 1.50 christos char intrbuf[PCI_INTRSTR_LEN];
560 1.1 thorpej
561 1.42 cegger sc = device_private(self);
562 1.49 chs pa = aux;
563 1.26 kent pc = pa->pa_pc;
564 1.26 kent
565 1.1 thorpej sc->type = PCI_PRODUCT(pa->pa_id);
566 1.1 thorpej
567 1.1 thorpej printf(": NeoMagic 256%s audio\n",
568 1.1 thorpej sc->type == PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU ? "AV" : "ZX");
569 1.1 thorpej
570 1.1 thorpej /* Map I/O register */
571 1.1 thorpej if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM, 0,
572 1.3 thorpej &sc->bufiot, &sc->bufioh, &sc->buf_pciaddr, NULL)) {
573 1.49 chs aprint_error_dev(self, "can't map buffer\n");
574 1.1 thorpej return;
575 1.1 thorpej }
576 1.1 thorpej
577 1.13 thorpej if (pci_mapreg_map(pa, PCI_MAPREG_START + 4, PCI_MAPREG_TYPE_MEM,
578 1.13 thorpej BUS_SPACE_MAP_LINEAR, &sc->regiot, &sc->regioh, NULL, NULL)) {
579 1.49 chs aprint_error_dev(self, "can't map registers\n");
580 1.1 thorpej return;
581 1.1 thorpej }
582 1.1 thorpej
583 1.1 thorpej /* Map and establish the interrupt. */
584 1.7 sommerfe if (pci_intr_map(pa, &ih)) {
585 1.49 chs aprint_error_dev(self, "couldn't map interrupt\n");
586 1.1 thorpej return;
587 1.1 thorpej }
588 1.1 thorpej
589 1.46 jmcneill mutex_init(&sc->lock, MUTEX_DEFAULT, IPL_NONE);
590 1.47 mrg mutex_init(&sc->intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
591 1.46 jmcneill
592 1.50 christos intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf));
593 1.51 jdolecek sc->ih = pci_intr_establish_xname(pc, ih, IPL_AUDIO, neo_intr, sc,
594 1.51 jdolecek device_xname(self));
595 1.1 thorpej
596 1.1 thorpej if (sc->ih == NULL) {
597 1.49 chs aprint_error_dev(self, "couldn't establish interrupt");
598 1.1 thorpej if (intrstr != NULL)
599 1.43 njoly aprint_error(" at %s", intrstr);
600 1.43 njoly aprint_error("\n");
601 1.46 jmcneill mutex_destroy(&sc->lock);
602 1.46 jmcneill mutex_destroy(&sc->intr_lock);
603 1.1 thorpej return;
604 1.1 thorpej }
605 1.49 chs aprint_normal_dev(self, "interrupting at %s\n", intrstr);
606 1.1 thorpej
607 1.46 jmcneill mutex_spin_enter(&sc->intr_lock);
608 1.46 jmcneill error = nm_init(sc);
609 1.46 jmcneill mutex_spin_exit(&sc->intr_lock);
610 1.46 jmcneill if (error != 0) {
611 1.46 jmcneill mutex_destroy(&sc->lock);
612 1.46 jmcneill mutex_destroy(&sc->intr_lock);
613 1.1 thorpej return;
614 1.46 jmcneill }
615 1.1 thorpej
616 1.1 thorpej /* Enable the device. */
617 1.1 thorpej csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
618 1.1 thorpej pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
619 1.1 thorpej csr | PCI_COMMAND_MASTER_ENABLE);
620 1.1 thorpej
621 1.1 thorpej sc->host_if.arg = sc;
622 1.1 thorpej sc->host_if.attach = neo_attach_codec;
623 1.1 thorpej sc->host_if.read = neo_read_codec;
624 1.1 thorpej sc->host_if.write = neo_write_codec;
625 1.1 thorpej sc->host_if.reset = neo_reset_codec;
626 1.1 thorpej sc->host_if.flags = neo_flags_codec;
627 1.1 thorpej
628 1.46 jmcneill if (ac97_attach(&sc->host_if, self, &sc->lock) != 0) {
629 1.46 jmcneill mutex_destroy(&sc->lock);
630 1.46 jmcneill mutex_destroy(&sc->intr_lock);
631 1.1 thorpej return;
632 1.46 jmcneill }
633 1.5 sommerfe
634 1.37 jmcneill if (!pmf_device_register(self, NULL, neo_resume))
635 1.37 jmcneill aprint_error_dev(self, "couldn't establish power handler\n");
636 1.1 thorpej
637 1.49 chs audio_attach_mi(&neo_hw_if, sc, self);
638 1.1 thorpej }
639 1.1 thorpej
640 1.29 thorpej static int
641 1.26 kent neo_read_codec(void *v, uint8_t a, uint16_t *d)
642 1.1 thorpej {
643 1.26 kent struct neo_softc *sc;
644 1.26 kent
645 1.26 kent sc = v;
646 1.1 thorpej if (!nm_waitcd(sc)) {
647 1.1 thorpej *d = nm_rd_2(sc, sc->ac97_base + a);
648 1.1 thorpej DELAY(1000);
649 1.1 thorpej return 0;
650 1.1 thorpej }
651 1.1 thorpej
652 1.26 kent return ENXIO;
653 1.1 thorpej }
654 1.1 thorpej
655 1.1 thorpej
656 1.29 thorpej static int
657 1.1 thorpej neo_write_codec(void *v, u_int8_t a, u_int16_t d)
658 1.1 thorpej {
659 1.26 kent struct neo_softc *sc;
660 1.26 kent int cnt;
661 1.1 thorpej
662 1.26 kent sc = v;
663 1.26 kent cnt = 3;
664 1.1 thorpej if (!nm_waitcd(sc)) {
665 1.1 thorpej while (cnt-- > 0) {
666 1.1 thorpej nm_wr_2(sc, sc->ac97_base + a, d);
667 1.1 thorpej if (!nm_waitcd(sc)) {
668 1.1 thorpej DELAY(1000);
669 1.26 kent return 0;
670 1.1 thorpej }
671 1.1 thorpej }
672 1.1 thorpej }
673 1.1 thorpej
674 1.26 kent return ENXIO;
675 1.1 thorpej }
676 1.1 thorpej
677 1.29 thorpej static int
678 1.1 thorpej neo_attach_codec(void *v, struct ac97_codec_if *codec_if)
679 1.1 thorpej {
680 1.26 kent struct neo_softc *sc;
681 1.1 thorpej
682 1.26 kent sc = v;
683 1.1 thorpej sc->codec_if = codec_if;
684 1.26 kent return 0;
685 1.1 thorpej }
686 1.1 thorpej
687 1.29 thorpej static int
688 1.1 thorpej neo_reset_codec(void *v)
689 1.1 thorpej {
690 1.26 kent struct neo_softc *sc;
691 1.1 thorpej
692 1.26 kent sc = v;
693 1.1 thorpej nm_wr_1(sc, 0x6c0, 0x01);
694 1.1 thorpej nm_wr_1(sc, 0x6cc, 0x87);
695 1.1 thorpej nm_wr_1(sc, 0x6cc, 0x80);
696 1.1 thorpej nm_wr_1(sc, 0x6cc, 0x00);
697 1.23 kent return 0;
698 1.1 thorpej }
699 1.1 thorpej
700 1.29 thorpej static enum ac97_host_flags
701 1.35 christos neo_flags_codec(void *v)
702 1.1 thorpej {
703 1.1 thorpej
704 1.26 kent return AC97_HOST_DONT_READ;
705 1.1 thorpej }
706 1.1 thorpej
707 1.29 thorpej static int
708 1.53 isaki neo_query_format(void *addr, audio_format_query_t *afp)
709 1.53 isaki {
710 1.53 isaki
711 1.53 isaki return audio_query_format(neo_formats, NEO_NFORMATS, afp);
712 1.53 isaki }
713 1.53 isaki
714 1.53 isaki /* Return index number of sample_rate */
715 1.53 isaki static int
716 1.53 isaki neo_rate2index(u_int sample_rate)
717 1.1 thorpej {
718 1.53 isaki int i;
719 1.1 thorpej
720 1.53 isaki for (i = 0; i < neo_formats[0].frequency_type; i++) {
721 1.53 isaki if (sample_rate == neo_formats[0].frequency[i])
722 1.53 isaki return i;
723 1.1 thorpej }
724 1.53 isaki
725 1.53 isaki /* NOTREACHED */
726 1.53 isaki panic("neo_formats.frequency mismatch?");
727 1.1 thorpej }
728 1.1 thorpej
729 1.1 thorpej /* Todo: don't commit settings to card until we've verified all parameters */
730 1.29 thorpej static int
731 1.53 isaki neo_set_format(void *addr, int setmode,
732 1.53 isaki const audio_params_t *play, const audio_params_t *rec,
733 1.53 isaki audio_filter_reg_t *pfil, audio_filter_reg_t *rfil)
734 1.1 thorpej {
735 1.26 kent struct neo_softc *sc;
736 1.53 isaki const audio_params_t *p;
737 1.26 kent uint32_t base;
738 1.26 kent uint8_t x;
739 1.53 isaki int mode;
740 1.1 thorpej
741 1.26 kent sc = addr;
742 1.26 kent for (mode = AUMODE_RECORD; mode != -1;
743 1.1 thorpej mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
744 1.1 thorpej if ((setmode & mode) == 0)
745 1.1 thorpej continue;
746 1.1 thorpej
747 1.1 thorpej p = mode == AUMODE_PLAY ? play : rec;
748 1.1 thorpej
749 1.53 isaki x = neo_rate2index(p->sample_rate);
750 1.1 thorpej nm_loadcoeff(sc, mode, x);
751 1.1 thorpej
752 1.1 thorpej x <<= 4;
753 1.1 thorpej x &= NM_RATE_MASK;
754 1.53 isaki x |= NM_RATE_BITS_16;
755 1.53 isaki x |= NM_RATE_STEREO;
756 1.1 thorpej
757 1.26 kent base = (mode == AUMODE_PLAY)?
758 1.1 thorpej NM_PLAYBACK_REG_OFFSET : NM_RECORD_REG_OFFSET;
759 1.1 thorpej nm_wr_1(sc, base + NM_RATE_REG_OFFSET, x);
760 1.1 thorpej }
761 1.1 thorpej
762 1.26 kent return 0;
763 1.1 thorpej }
764 1.1 thorpej
765 1.29 thorpej static int
766 1.35 christos neo_round_blocksize(void *addr, int blk, int mode,
767 1.35 christos const audio_params_t *param)
768 1.1 thorpej {
769 1.1 thorpej
770 1.53 isaki /* The number of blocks must be 3 or greater. */
771 1.53 isaki return NM_BUFFSIZE / 4;
772 1.1 thorpej }
773 1.1 thorpej
774 1.29 thorpej static int
775 1.1 thorpej neo_trigger_output(void *addr, void *start, void *end, int blksize,
776 1.25 kent void (*intr)(void *), void *arg, const audio_params_t *param)
777 1.1 thorpej {
778 1.26 kent struct neo_softc *sc;
779 1.1 thorpej int ssz;
780 1.1 thorpej
781 1.26 kent sc = addr;
782 1.1 thorpej sc->pintr = intr;
783 1.1 thorpej sc->parg = arg;
784 1.1 thorpej
785 1.25 kent ssz = (param->precision == 16) ? 2 : 1;
786 1.1 thorpej if (param->channels == 2)
787 1.1 thorpej ssz <<= 1;
788 1.1 thorpej
789 1.1 thorpej sc->pbufsize = ((char*)end - (char *)start);
790 1.1 thorpej sc->pblksize = blksize;
791 1.1 thorpej sc->pwmark = blksize;
792 1.1 thorpej
793 1.1 thorpej nm_wr_4(sc, NM_PBUFFER_START, sc->pbuf);
794 1.26 kent nm_wr_4(sc, NM_PBUFFER_END, sc->pbuf + sc->pbufsize - ssz);
795 1.1 thorpej nm_wr_4(sc, NM_PBUFFER_CURRP, sc->pbuf);
796 1.1 thorpej nm_wr_4(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pwmark);
797 1.1 thorpej nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, NM_PLAYBACK_FREERUN |
798 1.1 thorpej NM_PLAYBACK_ENABLE_FLAG);
799 1.1 thorpej nm_wr_2(sc, NM_AUDIO_MUTE_REG, 0);
800 1.1 thorpej
801 1.26 kent return 0;
802 1.1 thorpej }
803 1.1 thorpej
804 1.29 thorpej static int
805 1.1 thorpej neo_trigger_input(void *addr, void *start, void *end, int blksize,
806 1.25 kent void (*intr)(void *), void *arg, const audio_params_t *param)
807 1.1 thorpej {
808 1.26 kent struct neo_softc *sc;
809 1.1 thorpej int ssz;
810 1.1 thorpej
811 1.26 kent sc = addr;
812 1.1 thorpej sc->rintr = intr;
813 1.1 thorpej sc->rarg = arg;
814 1.1 thorpej
815 1.25 kent ssz = (param->precision == 16) ? 2 : 1;
816 1.1 thorpej if (param->channels == 2)
817 1.1 thorpej ssz <<= 1;
818 1.1 thorpej
819 1.1 thorpej sc->rbufsize = ((char*)end - (char *)start);
820 1.1 thorpej sc->rblksize = blksize;
821 1.1 thorpej sc->rwmark = blksize;
822 1.1 thorpej
823 1.53 isaki /*
824 1.53 isaki * XXX Doesn't it need to subtract ssz from BUFFER_END like
825 1.53 isaki * trigger_output()?
826 1.53 isaki */
827 1.1 thorpej nm_wr_4(sc, NM_RBUFFER_START, sc->rbuf);
828 1.1 thorpej nm_wr_4(sc, NM_RBUFFER_END, sc->rbuf + sc->rbufsize);
829 1.1 thorpej nm_wr_4(sc, NM_RBUFFER_CURRP, sc->rbuf);
830 1.1 thorpej nm_wr_4(sc, NM_RBUFFER_WMARK, sc->rbuf + sc->rwmark);
831 1.1 thorpej nm_wr_1(sc, NM_RECORD_ENABLE_REG, NM_RECORD_FREERUN |
832 1.1 thorpej NM_RECORD_ENABLE_FLAG);
833 1.1 thorpej
834 1.26 kent return 0;
835 1.1 thorpej }
836 1.1 thorpej
837 1.29 thorpej static int
838 1.1 thorpej neo_halt_output(void *addr)
839 1.1 thorpej {
840 1.26 kent struct neo_softc *sc;
841 1.1 thorpej
842 1.26 kent sc = (struct neo_softc *)addr;
843 1.1 thorpej nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, 0);
844 1.1 thorpej nm_wr_2(sc, NM_AUDIO_MUTE_REG, NM_AUDIO_MUTE_BOTH);
845 1.22 mycroft sc->pintr = 0;
846 1.1 thorpej
847 1.26 kent return 0;
848 1.1 thorpej }
849 1.1 thorpej
850 1.29 thorpej static int
851 1.1 thorpej neo_halt_input(void *addr)
852 1.1 thorpej {
853 1.26 kent struct neo_softc *sc;
854 1.1 thorpej
855 1.26 kent sc = (struct neo_softc *)addr;
856 1.1 thorpej nm_wr_1(sc, NM_RECORD_ENABLE_REG, 0);
857 1.22 mycroft sc->rintr = 0;
858 1.1 thorpej
859 1.26 kent return 0;
860 1.1 thorpej }
861 1.1 thorpej
862 1.29 thorpej static int
863 1.35 christos neo_getdev(void *addr, struct audio_device *retp)
864 1.1 thorpej {
865 1.1 thorpej
866 1.1 thorpej *retp = neo_device;
867 1.26 kent return 0;
868 1.1 thorpej }
869 1.1 thorpej
870 1.29 thorpej static int
871 1.1 thorpej neo_mixer_set_port(void *addr, mixer_ctrl_t *cp)
872 1.1 thorpej {
873 1.26 kent struct neo_softc *sc;
874 1.1 thorpej
875 1.26 kent sc = addr;
876 1.26 kent return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
877 1.1 thorpej }
878 1.1 thorpej
879 1.29 thorpej static int
880 1.1 thorpej neo_mixer_get_port(void *addr, mixer_ctrl_t *cp)
881 1.1 thorpej {
882 1.26 kent struct neo_softc *sc;
883 1.1 thorpej
884 1.26 kent sc = addr;
885 1.26 kent return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
886 1.1 thorpej }
887 1.1 thorpej
888 1.29 thorpej static int
889 1.1 thorpej neo_query_devinfo(void *addr, mixer_devinfo_t *dip)
890 1.1 thorpej {
891 1.26 kent struct neo_softc *sc;
892 1.1 thorpej
893 1.26 kent sc = addr;
894 1.26 kent return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip);
895 1.1 thorpej }
896 1.1 thorpej
897 1.29 thorpej static void *
898 1.46 jmcneill neo_malloc(void *addr, int direction, size_t size)
899 1.1 thorpej {
900 1.26 kent struct neo_softc *sc;
901 1.26 kent void *rv;
902 1.1 thorpej
903 1.26 kent sc = addr;
904 1.26 kent rv = NULL;
905 1.1 thorpej switch (direction) {
906 1.1 thorpej case AUMODE_PLAY:
907 1.1 thorpej if (sc->pbuf_allocated == 0) {
908 1.1 thorpej rv = (void *) sc->pbuf_vaddr;
909 1.1 thorpej sc->pbuf_allocated = 1;
910 1.1 thorpej }
911 1.1 thorpej break;
912 1.1 thorpej
913 1.1 thorpej case AUMODE_RECORD:
914 1.1 thorpej if (sc->rbuf_allocated == 0) {
915 1.1 thorpej rv = (void *) sc->rbuf_vaddr;
916 1.1 thorpej sc->rbuf_allocated = 1;
917 1.1 thorpej }
918 1.1 thorpej break;
919 1.1 thorpej }
920 1.1 thorpej
921 1.26 kent return rv;
922 1.1 thorpej }
923 1.1 thorpej
924 1.29 thorpej static void
925 1.46 jmcneill neo_free(void *addr, void *ptr, size_t size)
926 1.1 thorpej {
927 1.26 kent struct neo_softc *sc;
928 1.26 kent vaddr_t v;
929 1.1 thorpej
930 1.26 kent sc = addr;
931 1.26 kent v = (vaddr_t)ptr;
932 1.1 thorpej if (v == sc->pbuf_vaddr)
933 1.1 thorpej sc->pbuf_allocated = 0;
934 1.1 thorpej else if (v == sc->rbuf_vaddr)
935 1.1 thorpej sc->rbuf_allocated = 0;
936 1.1 thorpej else
937 1.1 thorpej printf("neo_free: bad address %p\n", ptr);
938 1.1 thorpej }
939 1.1 thorpej
940 1.29 thorpej static size_t
941 1.46 jmcneill neo_round_buffersize(void *addr, int direction, size_t size)
942 1.1 thorpej {
943 1.1 thorpej
944 1.26 kent return NM_BUFFSIZE;
945 1.1 thorpej }
946 1.1 thorpej
947 1.29 thorpej static int
948 1.35 christos neo_get_props(void *addr)
949 1.1 thorpej {
950 1.1 thorpej
951 1.26 kent return AUDIO_PROP_INDEPENDENT | AUDIO_PROP_MMAP |
952 1.26 kent AUDIO_PROP_FULLDUPLEX;
953 1.1 thorpej }
954 1.46 jmcneill
955 1.46 jmcneill static void
956 1.46 jmcneill neo_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
957 1.46 jmcneill {
958 1.46 jmcneill struct neo_softc *sc;
959 1.46 jmcneill
960 1.46 jmcneill sc = addr;
961 1.46 jmcneill *intr = &sc->intr_lock;
962 1.46 jmcneill *thread = &sc->lock;
963 1.46 jmcneill }
964