neo.c revision 1.52 1 1.52 isaki /* $NetBSD: neo.c,v 1.52 2019/03/16 12:09:58 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.52 isaki __KERNEL_RCSID(0, "$NetBSD: neo.c,v 1.52 2019/03/16 12:09:58 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.1 thorpej #include <dev/audio_if.h>
46 1.1 thorpej #include <dev/mulaw.h>
47 1.1 thorpej #include <dev/auconv.h>
48 1.1 thorpej
49 1.1 thorpej #include <dev/ic/ac97var.h>
50 1.1 thorpej
51 1.46 jmcneill #include <dev/pci/pcidevs.h>
52 1.46 jmcneill #include <dev/pci/pcivar.h>
53 1.46 jmcneill #include <dev/pci/neoreg.h>
54 1.46 jmcneill #include <dev/pci/neo-coeff.h>
55 1.1 thorpej
56 1.1 thorpej /* -------------------------------------------------------------------- */
57 1.27 perry /*
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.27 perry * 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.12 simonb * might 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.48 msaitoh * and the register set is the second 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.12 simonb * Unlike many sound engines, the Neomagic does not support (as far 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.27 perry *
101 1.1 thorpej * The ring buffer size is currently 16k. That is about 100ms of audio
102 1.18 tsutsui * 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 * Figure out interaction with video stuff (look at Xfree86 driver?)
111 1.1 thorpej *
112 1.1 thorpej * Figure out how to shrink that huge table neo-coeff.h
113 1.1 thorpej */
114 1.1 thorpej
115 1.1 thorpej #define NM_BUFFSIZE 16384
116 1.1 thorpej
117 1.1 thorpej /* device private data */
118 1.1 thorpej struct neo_softc {
119 1.49 chs device_t dev;
120 1.46 jmcneill kmutex_t lock;
121 1.46 jmcneill kmutex_t intr_lock;
122 1.1 thorpej
123 1.1 thorpej bus_space_tag_t bufiot;
124 1.26 kent bus_space_handle_t bufioh;
125 1.1 thorpej
126 1.1 thorpej bus_space_tag_t regiot;
127 1.26 kent bus_space_handle_t regioh;
128 1.1 thorpej
129 1.26 kent uint32_t type;
130 1.26 kent void *ih;
131 1.1 thorpej
132 1.19 wiz void (*pintr)(void *); /* DMA completion intr handler */
133 1.1 thorpej void *parg; /* arg for intr() */
134 1.1 thorpej
135 1.19 wiz void (*rintr)(void *); /* DMA completion intr handler */
136 1.1 thorpej void *rarg; /* arg for intr() */
137 1.1 thorpej
138 1.1 thorpej vaddr_t buf_vaddr;
139 1.1 thorpej vaddr_t rbuf_vaddr;
140 1.1 thorpej vaddr_t pbuf_vaddr;
141 1.1 thorpej int pbuf_allocated;
142 1.1 thorpej int rbuf_allocated;
143 1.1 thorpej
144 1.3 thorpej bus_addr_t buf_pciaddr;
145 1.3 thorpej bus_addr_t rbuf_pciaddr;
146 1.3 thorpej bus_addr_t pbuf_pciaddr;
147 1.3 thorpej
148 1.26 kent uint32_t ac97_base, ac97_status, ac97_busy;
149 1.26 kent uint32_t buftop, pbuf, rbuf, cbuf, acbuf;
150 1.26 kent uint32_t playint, recint, misc1int, misc2int;
151 1.26 kent uint32_t irsz, badintr;
152 1.1 thorpej
153 1.26 kent uint32_t pbufsize;
154 1.26 kent uint32_t rbufsize;
155 1.1 thorpej
156 1.26 kent uint32_t pblksize;
157 1.26 kent uint32_t rblksize;
158 1.1 thorpej
159 1.26 kent uint32_t pwmark;
160 1.26 kent uint32_t rwmark;
161 1.1 thorpej
162 1.1 thorpej struct ac97_codec_if *codec_if;
163 1.5 sommerfe struct ac97_host_if host_if;
164 1.1 thorpej };
165 1.1 thorpej
166 1.1 thorpej /* -------------------------------------------------------------------- */
167 1.1 thorpej
168 1.1 thorpej /*
169 1.1 thorpej * prototypes
170 1.1 thorpej */
171 1.1 thorpej
172 1.26 kent static int nm_waitcd(struct neo_softc *);
173 1.26 kent static int nm_loadcoeff(struct neo_softc *, int, int);
174 1.1 thorpej static int nm_init(struct neo_softc *);
175 1.1 thorpej
176 1.41 cegger static int neo_match(device_t, cfdata_t, void *);
177 1.41 cegger static void neo_attach(device_t, device_t, void *);
178 1.29 thorpej static int neo_intr(void *);
179 1.29 thorpej
180 1.29 thorpej static int neo_query_encoding(void *, struct audio_encoding *);
181 1.29 thorpej static int neo_set_params(void *, int, int, audio_params_t *,
182 1.29 thorpej audio_params_t *, stream_filter_list_t *,
183 1.29 thorpej stream_filter_list_t *);
184 1.29 thorpej static int neo_round_blocksize(void *, int, int, const audio_params_t *);
185 1.29 thorpej static int neo_trigger_output(void *, void *, void *, int,
186 1.29 thorpej void (*)(void *), void *,
187 1.29 thorpej const audio_params_t *);
188 1.29 thorpej static int neo_trigger_input(void *, void *, void *, int,
189 1.29 thorpej void (*)(void *), void *,
190 1.29 thorpej const audio_params_t *);
191 1.29 thorpej static int neo_halt_output(void *);
192 1.29 thorpej static int neo_halt_input(void *);
193 1.29 thorpej static int neo_getdev(void *, struct audio_device *);
194 1.29 thorpej static int neo_mixer_set_port(void *, mixer_ctrl_t *);
195 1.29 thorpej static int neo_mixer_get_port(void *, mixer_ctrl_t *);
196 1.29 thorpej static int neo_attach_codec(void *, struct ac97_codec_if *);
197 1.29 thorpej static int neo_read_codec(void *, uint8_t, uint16_t *);
198 1.29 thorpej static int neo_write_codec(void *, uint8_t, uint16_t);
199 1.29 thorpej static int neo_reset_codec(void *);
200 1.29 thorpej static enum ac97_host_flags neo_flags_codec(void *);
201 1.29 thorpej static int neo_query_devinfo(void *, mixer_devinfo_t *);
202 1.46 jmcneill static void * neo_malloc(void *, int, size_t);
203 1.46 jmcneill static void neo_free(void *, void *, size_t);
204 1.29 thorpej static size_t neo_round_buffersize(void *, int, size_t);
205 1.29 thorpej static paddr_t neo_mappage(void *, void *, off_t, int);
206 1.29 thorpej static int neo_get_props(void *);
207 1.46 jmcneill static void neo_get_locks(void *, kmutex_t **, kmutex_t **);
208 1.1 thorpej
209 1.49 chs CFATTACH_DECL_NEW(neo, sizeof(struct neo_softc),
210 1.16 thorpej neo_match, neo_attach, NULL, NULL);
211 1.1 thorpej
212 1.29 thorpej static struct audio_device neo_device = {
213 1.1 thorpej "NeoMagic 256",
214 1.1 thorpej "",
215 1.1 thorpej "neo"
216 1.1 thorpej };
217 1.1 thorpej
218 1.1 thorpej /* The actual rates supported by the card. */
219 1.1 thorpej static const int samplerates[9] = {
220 1.1 thorpej 8000,
221 1.1 thorpej 11025,
222 1.1 thorpej 16000,
223 1.1 thorpej 22050,
224 1.1 thorpej 24000,
225 1.1 thorpej 32000,
226 1.1 thorpej 44100,
227 1.1 thorpej 48000,
228 1.1 thorpej 99999999
229 1.1 thorpej };
230 1.1 thorpej
231 1.25 kent #define NEO_NFORMATS 4
232 1.25 kent static const struct audio_format neo_formats[NEO_NFORMATS] = {
233 1.25 kent {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
234 1.25 kent 2, AUFMT_STEREO, 8, {8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000}},
235 1.25 kent {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_SLINEAR_LE, 16, 16,
236 1.25 kent 1, AUFMT_MONAURAL, 8, {8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000}},
237 1.25 kent {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 8, 8,
238 1.25 kent 2, AUFMT_STEREO, 8, {8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000}},
239 1.25 kent {NULL, AUMODE_PLAY | AUMODE_RECORD, AUDIO_ENCODING_ULINEAR_LE, 8, 8,
240 1.25 kent 1, AUFMT_MONAURAL, 8, {8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000}},
241 1.25 kent };
242 1.25 kent
243 1.1 thorpej /* -------------------------------------------------------------------- */
244 1.1 thorpej
245 1.29 thorpej static const struct audio_hw_if neo_hw_if = {
246 1.52 isaki .query_encoding = neo_query_encoding,
247 1.52 isaki .set_params = neo_set_params,
248 1.52 isaki .round_blocksize = neo_round_blocksize,
249 1.52 isaki .halt_output = neo_halt_output,
250 1.52 isaki .halt_input = neo_halt_input,
251 1.52 isaki .getdev = neo_getdev,
252 1.52 isaki .set_port = neo_mixer_set_port,
253 1.52 isaki .get_port = neo_mixer_get_port,
254 1.52 isaki .query_devinfo = neo_query_devinfo,
255 1.52 isaki .allocm = neo_malloc,
256 1.52 isaki .freem = neo_free,
257 1.52 isaki .round_buffersize = neo_round_buffersize,
258 1.52 isaki .mappage = neo_mappage,
259 1.52 isaki .get_props = neo_get_props,
260 1.52 isaki .trigger_output = neo_trigger_output,
261 1.52 isaki .trigger_input = neo_trigger_input,
262 1.52 isaki .get_locks = neo_get_locks,
263 1.1 thorpej };
264 1.1 thorpej
265 1.1 thorpej /* -------------------------------------------------------------------- */
266 1.1 thorpej
267 1.1 thorpej #define nm_rd_1(sc, regno) \
268 1.1 thorpej bus_space_read_1((sc)->regiot, (sc)->regioh, (regno))
269 1.1 thorpej
270 1.1 thorpej #define nm_rd_2(sc, regno) \
271 1.1 thorpej bus_space_read_2((sc)->regiot, (sc)->regioh, (regno))
272 1.1 thorpej
273 1.1 thorpej #define nm_rd_4(sc, regno) \
274 1.1 thorpej bus_space_read_4((sc)->regiot, (sc)->regioh, (regno))
275 1.1 thorpej
276 1.1 thorpej #define nm_wr_1(sc, regno, val) \
277 1.1 thorpej bus_space_write_1((sc)->regiot, (sc)->regioh, (regno), (val))
278 1.1 thorpej
279 1.1 thorpej #define nm_wr_2(sc, regno, val) \
280 1.1 thorpej bus_space_write_2((sc)->regiot, (sc)->regioh, (regno), (val))
281 1.1 thorpej
282 1.1 thorpej #define nm_wr_4(sc, regno, val) \
283 1.1 thorpej bus_space_write_4((sc)->regiot, (sc)->regioh, (regno), (val))
284 1.1 thorpej
285 1.1 thorpej #define nm_rdbuf_4(sc, regno) \
286 1.1 thorpej bus_space_read_4((sc)->bufiot, (sc)->bufioh, (regno))
287 1.1 thorpej
288 1.1 thorpej #define nm_wrbuf_1(sc, regno, val) \
289 1.1 thorpej bus_space_write_1((sc)->bufiot, (sc)->bufioh, (regno), (val))
290 1.1 thorpej
291 1.1 thorpej /* ac97 codec */
292 1.1 thorpej static int
293 1.1 thorpej nm_waitcd(struct neo_softc *sc)
294 1.1 thorpej {
295 1.26 kent int cnt;
296 1.26 kent int fail;
297 1.1 thorpej
298 1.26 kent cnt = 10;
299 1.26 kent fail = 1;
300 1.1 thorpej while (cnt-- > 0) {
301 1.1 thorpej if (nm_rd_2(sc, sc->ac97_status) & sc->ac97_busy)
302 1.1 thorpej DELAY(100);
303 1.1 thorpej else {
304 1.26 kent fail = 0;
305 1.1 thorpej break;
306 1.1 thorpej }
307 1.1 thorpej }
308 1.26 kent return fail;
309 1.1 thorpej }
310 1.1 thorpej
311 1.1 thorpej static void
312 1.26 kent nm_ackint(struct neo_softc *sc, uint32_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.26 kent uint32_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.29 thorpej static int
350 1.1 thorpej neo_intr(void *p)
351 1.1 thorpej {
352 1.26 kent struct neo_softc *sc;
353 1.20 simonb int status, x;
354 1.26 kent int rv;
355 1.1 thorpej
356 1.26 kent sc = (struct neo_softc *)p;
357 1.46 jmcneill mutex_spin_enter(&sc->intr_lock);
358 1.46 jmcneill
359 1.26 kent rv = 0;
360 1.1 thorpej status = (sc->irsz == 2) ?
361 1.1 thorpej nm_rd_2(sc, NM_INT_REG) :
362 1.1 thorpej nm_rd_4(sc, NM_INT_REG);
363 1.1 thorpej
364 1.1 thorpej if (status & sc->playint) {
365 1.1 thorpej status &= ~sc->playint;
366 1.1 thorpej
367 1.1 thorpej sc->pwmark += sc->pblksize;
368 1.1 thorpej sc->pwmark %= sc->pbufsize;
369 1.1 thorpej
370 1.1 thorpej nm_wr_4(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pwmark);
371 1.1 thorpej
372 1.1 thorpej nm_ackint(sc, sc->playint);
373 1.1 thorpej
374 1.1 thorpej if (sc->pintr)
375 1.1 thorpej (*sc->pintr)(sc->parg);
376 1.1 thorpej
377 1.1 thorpej rv = 1;
378 1.1 thorpej }
379 1.1 thorpej if (status & sc->recint) {
380 1.1 thorpej status &= ~sc->recint;
381 1.1 thorpej
382 1.1 thorpej sc->rwmark += sc->rblksize;
383 1.1 thorpej sc->rwmark %= sc->rbufsize;
384 1.28 kent nm_wr_4(sc, NM_RBUFFER_WMARK, sc->rbuf + sc->rwmark);
385 1.1 thorpej nm_ackint(sc, sc->recint);
386 1.1 thorpej if (sc->rintr)
387 1.1 thorpej (*sc->rintr)(sc->rarg);
388 1.1 thorpej
389 1.1 thorpej rv = 1;
390 1.1 thorpej }
391 1.1 thorpej if (status & sc->misc1int) {
392 1.1 thorpej status &= ~sc->misc1int;
393 1.1 thorpej nm_ackint(sc, sc->misc1int);
394 1.1 thorpej x = nm_rd_1(sc, 0x400);
395 1.1 thorpej nm_wr_1(sc, 0x400, x | 2);
396 1.49 chs printf("%s: misc int 1\n", device_xname(sc->dev));
397 1.1 thorpej rv = 1;
398 1.1 thorpej }
399 1.1 thorpej if (status & sc->misc2int) {
400 1.1 thorpej status &= ~sc->misc2int;
401 1.1 thorpej nm_ackint(sc, sc->misc2int);
402 1.1 thorpej x = nm_rd_1(sc, 0x400);
403 1.1 thorpej nm_wr_1(sc, 0x400, x & ~2);
404 1.49 chs printf("%s: misc int 2\n", device_xname(sc->dev));
405 1.1 thorpej rv = 1;
406 1.1 thorpej }
407 1.1 thorpej if (status) {
408 1.1 thorpej status &= ~sc->misc2int;
409 1.1 thorpej nm_ackint(sc, sc->misc2int);
410 1.49 chs printf("%s: unknown int\n", device_xname(sc->dev));
411 1.1 thorpej rv = 1;
412 1.1 thorpej }
413 1.1 thorpej
414 1.46 jmcneill mutex_spin_exit(&sc->intr_lock);
415 1.26 kent return rv;
416 1.1 thorpej }
417 1.1 thorpej
418 1.1 thorpej /* -------------------------------------------------------------------- */
419 1.1 thorpej
420 1.1 thorpej /*
421 1.1 thorpej * Probe and attach the card
422 1.1 thorpej */
423 1.1 thorpej
424 1.1 thorpej static int
425 1.1 thorpej nm_init(struct neo_softc *sc)
426 1.1 thorpej {
427 1.26 kent uint32_t ofs, i;
428 1.1 thorpej
429 1.1 thorpej switch (sc->type) {
430 1.1 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
431 1.1 thorpej sc->ac97_base = NM_MIXER_OFFSET;
432 1.1 thorpej sc->ac97_status = NM_MIXER_STATUS_OFFSET;
433 1.1 thorpej sc->ac97_busy = NM_MIXER_READY_MASK;
434 1.1 thorpej
435 1.1 thorpej sc->buftop = 2560 * 1024;
436 1.1 thorpej
437 1.1 thorpej sc->irsz = 2;
438 1.1 thorpej sc->playint = NM_PLAYBACK_INT;
439 1.1 thorpej sc->recint = NM_RECORD_INT;
440 1.1 thorpej sc->misc1int = NM_MISC_INT_1;
441 1.1 thorpej sc->misc2int = NM_MISC_INT_2;
442 1.1 thorpej break;
443 1.1 thorpej
444 1.1 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
445 1.1 thorpej sc->ac97_base = NM_MIXER_OFFSET;
446 1.1 thorpej sc->ac97_status = NM2_MIXER_STATUS_OFFSET;
447 1.1 thorpej sc->ac97_busy = NM2_MIXER_READY_MASK;
448 1.1 thorpej
449 1.1 thorpej sc->buftop = (nm_rd_2(sc, 0xa0b) ? 6144 : 4096) * 1024;
450 1.1 thorpej
451 1.1 thorpej sc->irsz = 4;
452 1.1 thorpej sc->playint = NM2_PLAYBACK_INT;
453 1.1 thorpej sc->recint = NM2_RECORD_INT;
454 1.1 thorpej sc->misc1int = NM2_MISC_INT_1;
455 1.1 thorpej sc->misc2int = NM2_MISC_INT_2;
456 1.1 thorpej break;
457 1.1 thorpej #ifdef DIAGNOSTIC
458 1.1 thorpej default:
459 1.1 thorpej panic("nm_init: impossible");
460 1.1 thorpej #endif
461 1.1 thorpej }
462 1.1 thorpej
463 1.1 thorpej sc->badintr = 0;
464 1.1 thorpej ofs = sc->buftop - 0x0400;
465 1.1 thorpej sc->buftop -= 0x1400;
466 1.1 thorpej
467 1.26 kent if ((nm_rdbuf_4(sc, ofs) & NM_SIG_MASK) == NM_SIGNATURE) {
468 1.1 thorpej i = nm_rdbuf_4(sc, ofs + 4);
469 1.1 thorpej if (i != 0 && i != 0xffffffff)
470 1.1 thorpej sc->buftop = i;
471 1.1 thorpej }
472 1.1 thorpej
473 1.1 thorpej sc->cbuf = sc->buftop - NM_MAX_COEFFICIENT;
474 1.1 thorpej sc->rbuf = sc->cbuf - NM_BUFFSIZE;
475 1.1 thorpej sc->pbuf = sc->rbuf - NM_BUFFSIZE;
476 1.1 thorpej sc->acbuf = sc->pbuf - (NM_TOTAL_COEFF_COUNT * 4);
477 1.1 thorpej
478 1.1 thorpej sc->buf_vaddr = (vaddr_t) bus_space_vaddr(sc->bufiot, sc->bufioh);
479 1.1 thorpej sc->rbuf_vaddr = sc->buf_vaddr + sc->rbuf;
480 1.1 thorpej sc->pbuf_vaddr = sc->buf_vaddr + sc->pbuf;
481 1.1 thorpej
482 1.3 thorpej sc->rbuf_pciaddr = sc->buf_pciaddr + sc->rbuf;
483 1.3 thorpej sc->pbuf_pciaddr = sc->buf_pciaddr + sc->pbuf;
484 1.3 thorpej
485 1.1 thorpej nm_wr_1(sc, 0, 0x11);
486 1.1 thorpej nm_wr_1(sc, NM_RECORD_ENABLE_REG, 0);
487 1.1 thorpej nm_wr_2(sc, 0x214, 0);
488 1.1 thorpej
489 1.1 thorpej return 0;
490 1.1 thorpej }
491 1.1 thorpej
492 1.29 thorpej static int
493 1.41 cegger neo_match(device_t parent, cfdata_t match, void *aux)
494 1.2 thorpej {
495 1.26 kent struct pci_attach_args *pa;
496 1.2 thorpej pcireg_t subdev;
497 1.2 thorpej
498 1.26 kent pa = aux;
499 1.2 thorpej if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_NEOMAGIC)
500 1.26 kent return 0;
501 1.2 thorpej
502 1.2 thorpej subdev = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG);
503 1.2 thorpej
504 1.2 thorpej switch (PCI_PRODUCT(pa->pa_id)) {
505 1.2 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU:
506 1.2 thorpej /*
507 1.2 thorpej * We have to weed-out the non-AC'97 versions of
508 1.2 thorpej * the chip (i.e. the ones that are known to work
509 1.2 thorpej * in WSS emulation mode), as they won't work with
510 1.2 thorpej * this driver.
511 1.2 thorpej */
512 1.2 thorpej switch (PCI_VENDOR(subdev)) {
513 1.2 thorpej case PCI_VENDOR_DELL:
514 1.2 thorpej switch (PCI_PRODUCT(subdev)) {
515 1.2 thorpej case 0x008f:
516 1.26 kent return 0;
517 1.2 thorpej }
518 1.2 thorpej break;
519 1.2 thorpej
520 1.2 thorpej case PCI_VENDOR_HP:
521 1.2 thorpej switch (PCI_PRODUCT(subdev)) {
522 1.2 thorpej case 0x0007:
523 1.26 kent return 0;
524 1.2 thorpej }
525 1.8 drochner break;
526 1.8 drochner
527 1.8 drochner case PCI_VENDOR_IBM:
528 1.8 drochner switch (PCI_PRODUCT(subdev)) {
529 1.8 drochner case 0x00dd:
530 1.26 kent return 0;
531 1.8 drochner }
532 1.8 drochner break;
533 1.2 thorpej }
534 1.26 kent return 1;
535 1.2 thorpej
536 1.2 thorpej case PCI_PRODUCT_NEOMAGIC_NMMM256ZX_AU:
537 1.26 kent return 1;
538 1.2 thorpej }
539 1.2 thorpej
540 1.26 kent return 0;
541 1.2 thorpej }
542 1.2 thorpej
543 1.37 jmcneill static bool
544 1.45 dyoung neo_resume(device_t dv, const pmf_qual_t *qual)
545 1.5 sommerfe {
546 1.37 jmcneill struct neo_softc *sc = device_private(dv);
547 1.37 jmcneill
548 1.46 jmcneill mutex_enter(&sc->lock);
549 1.46 jmcneill mutex_spin_enter(&sc->intr_lock);
550 1.37 jmcneill nm_init(sc);
551 1.46 jmcneill mutex_spin_exit(&sc->intr_lock);
552 1.46 jmcneill sc->codec_if->vtbl->restore_ports(sc->codec_if);
553 1.46 jmcneill mutex_exit(&sc->lock);
554 1.5 sommerfe
555 1.37 jmcneill return true;
556 1.5 sommerfe }
557 1.5 sommerfe
558 1.29 thorpej static void
559 1.41 cegger neo_attach(device_t parent, device_t self, void *aux)
560 1.1 thorpej {
561 1.26 kent struct neo_softc *sc;
562 1.26 kent struct pci_attach_args *pa;
563 1.26 kent pci_chipset_tag_t pc;
564 1.1 thorpej char const *intrstr;
565 1.1 thorpej pci_intr_handle_t ih;
566 1.1 thorpej pcireg_t csr;
567 1.46 jmcneill int error;
568 1.50 christos char intrbuf[PCI_INTRSTR_LEN];
569 1.1 thorpej
570 1.42 cegger sc = device_private(self);
571 1.49 chs pa = aux;
572 1.26 kent pc = pa->pa_pc;
573 1.26 kent
574 1.1 thorpej sc->type = PCI_PRODUCT(pa->pa_id);
575 1.1 thorpej
576 1.1 thorpej printf(": NeoMagic 256%s audio\n",
577 1.1 thorpej sc->type == PCI_PRODUCT_NEOMAGIC_NMMM256AV_AU ? "AV" : "ZX");
578 1.1 thorpej
579 1.1 thorpej /* Map I/O register */
580 1.1 thorpej if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_MEM, 0,
581 1.3 thorpej &sc->bufiot, &sc->bufioh, &sc->buf_pciaddr, NULL)) {
582 1.49 chs aprint_error_dev(self, "can't map buffer\n");
583 1.1 thorpej return;
584 1.1 thorpej }
585 1.1 thorpej
586 1.13 thorpej if (pci_mapreg_map(pa, PCI_MAPREG_START + 4, PCI_MAPREG_TYPE_MEM,
587 1.13 thorpej BUS_SPACE_MAP_LINEAR, &sc->regiot, &sc->regioh, NULL, NULL)) {
588 1.49 chs aprint_error_dev(self, "can't map registers\n");
589 1.1 thorpej return;
590 1.1 thorpej }
591 1.1 thorpej
592 1.1 thorpej /* Map and establish the interrupt. */
593 1.7 sommerfe if (pci_intr_map(pa, &ih)) {
594 1.49 chs aprint_error_dev(self, "couldn't map interrupt\n");
595 1.1 thorpej return;
596 1.1 thorpej }
597 1.1 thorpej
598 1.46 jmcneill mutex_init(&sc->lock, MUTEX_DEFAULT, IPL_NONE);
599 1.47 mrg mutex_init(&sc->intr_lock, MUTEX_DEFAULT, IPL_AUDIO);
600 1.46 jmcneill
601 1.50 christos intrstr = pci_intr_string(pc, ih, intrbuf, sizeof(intrbuf));
602 1.51 jdolecek sc->ih = pci_intr_establish_xname(pc, ih, IPL_AUDIO, neo_intr, sc,
603 1.51 jdolecek device_xname(self));
604 1.1 thorpej
605 1.1 thorpej if (sc->ih == NULL) {
606 1.49 chs aprint_error_dev(self, "couldn't establish interrupt");
607 1.1 thorpej if (intrstr != NULL)
608 1.43 njoly aprint_error(" at %s", intrstr);
609 1.43 njoly aprint_error("\n");
610 1.46 jmcneill mutex_destroy(&sc->lock);
611 1.46 jmcneill mutex_destroy(&sc->intr_lock);
612 1.1 thorpej return;
613 1.1 thorpej }
614 1.49 chs aprint_normal_dev(self, "interrupting at %s\n", intrstr);
615 1.1 thorpej
616 1.46 jmcneill mutex_spin_enter(&sc->intr_lock);
617 1.46 jmcneill error = nm_init(sc);
618 1.46 jmcneill mutex_spin_exit(&sc->intr_lock);
619 1.46 jmcneill if (error != 0) {
620 1.46 jmcneill mutex_destroy(&sc->lock);
621 1.46 jmcneill mutex_destroy(&sc->intr_lock);
622 1.1 thorpej return;
623 1.46 jmcneill }
624 1.1 thorpej
625 1.1 thorpej /* Enable the device. */
626 1.1 thorpej csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
627 1.1 thorpej pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
628 1.1 thorpej csr | PCI_COMMAND_MASTER_ENABLE);
629 1.1 thorpej
630 1.1 thorpej sc->host_if.arg = sc;
631 1.1 thorpej sc->host_if.attach = neo_attach_codec;
632 1.1 thorpej sc->host_if.read = neo_read_codec;
633 1.1 thorpej sc->host_if.write = neo_write_codec;
634 1.1 thorpej sc->host_if.reset = neo_reset_codec;
635 1.1 thorpej sc->host_if.flags = neo_flags_codec;
636 1.1 thorpej
637 1.46 jmcneill if (ac97_attach(&sc->host_if, self, &sc->lock) != 0) {
638 1.46 jmcneill mutex_destroy(&sc->lock);
639 1.46 jmcneill mutex_destroy(&sc->intr_lock);
640 1.1 thorpej return;
641 1.46 jmcneill }
642 1.5 sommerfe
643 1.37 jmcneill if (!pmf_device_register(self, NULL, neo_resume))
644 1.37 jmcneill aprint_error_dev(self, "couldn't establish power handler\n");
645 1.1 thorpej
646 1.49 chs audio_attach_mi(&neo_hw_if, sc, self);
647 1.1 thorpej }
648 1.1 thorpej
649 1.29 thorpej static int
650 1.26 kent neo_read_codec(void *v, uint8_t a, uint16_t *d)
651 1.1 thorpej {
652 1.26 kent struct neo_softc *sc;
653 1.26 kent
654 1.26 kent sc = v;
655 1.1 thorpej if (!nm_waitcd(sc)) {
656 1.1 thorpej *d = nm_rd_2(sc, sc->ac97_base + a);
657 1.1 thorpej DELAY(1000);
658 1.1 thorpej return 0;
659 1.1 thorpej }
660 1.1 thorpej
661 1.26 kent return ENXIO;
662 1.1 thorpej }
663 1.1 thorpej
664 1.1 thorpej
665 1.29 thorpej static int
666 1.1 thorpej neo_write_codec(void *v, u_int8_t a, u_int16_t d)
667 1.1 thorpej {
668 1.26 kent struct neo_softc *sc;
669 1.26 kent int cnt;
670 1.1 thorpej
671 1.26 kent sc = v;
672 1.26 kent cnt = 3;
673 1.1 thorpej if (!nm_waitcd(sc)) {
674 1.1 thorpej while (cnt-- > 0) {
675 1.1 thorpej nm_wr_2(sc, sc->ac97_base + a, d);
676 1.1 thorpej if (!nm_waitcd(sc)) {
677 1.1 thorpej DELAY(1000);
678 1.26 kent return 0;
679 1.1 thorpej }
680 1.1 thorpej }
681 1.1 thorpej }
682 1.1 thorpej
683 1.26 kent return ENXIO;
684 1.1 thorpej }
685 1.1 thorpej
686 1.29 thorpej static int
687 1.1 thorpej neo_attach_codec(void *v, struct ac97_codec_if *codec_if)
688 1.1 thorpej {
689 1.26 kent struct neo_softc *sc;
690 1.1 thorpej
691 1.26 kent sc = v;
692 1.1 thorpej sc->codec_if = codec_if;
693 1.26 kent return 0;
694 1.1 thorpej }
695 1.1 thorpej
696 1.29 thorpej static int
697 1.1 thorpej neo_reset_codec(void *v)
698 1.1 thorpej {
699 1.26 kent struct neo_softc *sc;
700 1.1 thorpej
701 1.26 kent sc = v;
702 1.1 thorpej nm_wr_1(sc, 0x6c0, 0x01);
703 1.1 thorpej nm_wr_1(sc, 0x6cc, 0x87);
704 1.1 thorpej nm_wr_1(sc, 0x6cc, 0x80);
705 1.1 thorpej nm_wr_1(sc, 0x6cc, 0x00);
706 1.23 kent return 0;
707 1.1 thorpej }
708 1.1 thorpej
709 1.29 thorpej static enum ac97_host_flags
710 1.35 christos neo_flags_codec(void *v)
711 1.1 thorpej {
712 1.1 thorpej
713 1.26 kent return AC97_HOST_DONT_READ;
714 1.1 thorpej }
715 1.1 thorpej
716 1.29 thorpej static int
717 1.35 christos neo_query_encoding(void *addr, struct audio_encoding *fp)
718 1.1 thorpej {
719 1.1 thorpej
720 1.1 thorpej switch (fp->index) {
721 1.1 thorpej case 0:
722 1.1 thorpej strcpy(fp->name, AudioEulinear);
723 1.1 thorpej fp->encoding = AUDIO_ENCODING_ULINEAR;
724 1.1 thorpej fp->precision = 8;
725 1.1 thorpej fp->flags = 0;
726 1.26 kent return 0;
727 1.1 thorpej case 1:
728 1.1 thorpej strcpy(fp->name, AudioEmulaw);
729 1.1 thorpej fp->encoding = AUDIO_ENCODING_ULAW;
730 1.1 thorpej fp->precision = 8;
731 1.1 thorpej fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
732 1.26 kent return 0;
733 1.1 thorpej case 2:
734 1.1 thorpej strcpy(fp->name, AudioEalaw);
735 1.1 thorpej fp->encoding = AUDIO_ENCODING_ALAW;
736 1.1 thorpej fp->precision = 8;
737 1.1 thorpej fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
738 1.26 kent return 0;
739 1.1 thorpej case 3:
740 1.1 thorpej strcpy(fp->name, AudioEslinear);
741 1.1 thorpej fp->encoding = AUDIO_ENCODING_SLINEAR;
742 1.1 thorpej fp->precision = 8;
743 1.1 thorpej fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
744 1.1 thorpej return (0);
745 1.1 thorpej case 4:
746 1.1 thorpej strcpy(fp->name, AudioEslinear_le);
747 1.1 thorpej fp->encoding = AUDIO_ENCODING_SLINEAR_LE;
748 1.1 thorpej fp->precision = 16;
749 1.1 thorpej fp->flags = 0;
750 1.26 kent return 0;
751 1.1 thorpej case 5:
752 1.1 thorpej strcpy(fp->name, AudioEulinear_le);
753 1.1 thorpej fp->encoding = AUDIO_ENCODING_ULINEAR_LE;
754 1.1 thorpej fp->precision = 16;
755 1.1 thorpej fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
756 1.26 kent return 0;
757 1.1 thorpej case 6:
758 1.1 thorpej strcpy(fp->name, AudioEslinear_be);
759 1.1 thorpej fp->encoding = AUDIO_ENCODING_SLINEAR_BE;
760 1.1 thorpej fp->precision = 16;
761 1.1 thorpej fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
762 1.26 kent return 0;
763 1.1 thorpej case 7:
764 1.1 thorpej strcpy(fp->name, AudioEulinear_be);
765 1.1 thorpej fp->encoding = AUDIO_ENCODING_ULINEAR_BE;
766 1.1 thorpej fp->precision = 16;
767 1.1 thorpej fp->flags = AUDIO_ENCODINGFLAG_EMULATED;
768 1.26 kent return 0;
769 1.1 thorpej default:
770 1.26 kent return EINVAL;
771 1.1 thorpej }
772 1.1 thorpej }
773 1.1 thorpej
774 1.1 thorpej /* Todo: don't commit settings to card until we've verified all parameters */
775 1.29 thorpej static int
776 1.35 christos neo_set_params(void *addr, int setmode, int usemode,
777 1.34 christos audio_params_t *play, audio_params_t *rec, stream_filter_list_t *pfil,
778 1.34 christos stream_filter_list_t *rfil)
779 1.1 thorpej {
780 1.26 kent struct neo_softc *sc;
781 1.25 kent audio_params_t *p;
782 1.25 kent stream_filter_list_t *fil;
783 1.26 kent uint32_t base;
784 1.26 kent uint8_t x;
785 1.25 kent int mode, i;
786 1.1 thorpej
787 1.26 kent sc = addr;
788 1.26 kent for (mode = AUMODE_RECORD; mode != -1;
789 1.1 thorpej mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
790 1.1 thorpej if ((setmode & mode) == 0)
791 1.1 thorpej continue;
792 1.1 thorpej
793 1.1 thorpej p = mode == AUMODE_PLAY ? play : rec;
794 1.1 thorpej
795 1.1 thorpej if (p == NULL) continue;
796 1.1 thorpej
797 1.1 thorpej for (x = 0; x < 8; x++) {
798 1.1 thorpej if (p->sample_rate <
799 1.1 thorpej (samplerates[x] + samplerates[x + 1]) / 2)
800 1.1 thorpej break;
801 1.1 thorpej }
802 1.1 thorpej if (x == 8)
803 1.26 kent return EINVAL;
804 1.1 thorpej
805 1.1 thorpej p->sample_rate = samplerates[x];
806 1.1 thorpej nm_loadcoeff(sc, mode, x);
807 1.1 thorpej
808 1.1 thorpej x <<= 4;
809 1.1 thorpej x &= NM_RATE_MASK;
810 1.1 thorpej if (p->precision == 16)
811 1.1 thorpej x |= NM_RATE_BITS_16;
812 1.1 thorpej if (p->channels == 2)
813 1.1 thorpej x |= NM_RATE_STEREO;
814 1.1 thorpej
815 1.26 kent base = (mode == AUMODE_PLAY)?
816 1.1 thorpej NM_PLAYBACK_REG_OFFSET : NM_RECORD_REG_OFFSET;
817 1.1 thorpej nm_wr_1(sc, base + NM_RATE_REG_OFFSET, x);
818 1.25 kent
819 1.25 kent fil = mode == AUMODE_PLAY ? pfil : rfil;
820 1.25 kent i = auconv_set_converter(neo_formats, NEO_NFORMATS,
821 1.25 kent mode, p, FALSE, fil);
822 1.25 kent if (i < 0)
823 1.25 kent return EINVAL;
824 1.1 thorpej }
825 1.1 thorpej
826 1.26 kent return 0;
827 1.1 thorpej }
828 1.1 thorpej
829 1.29 thorpej static int
830 1.35 christos neo_round_blocksize(void *addr, int blk, int mode,
831 1.35 christos const audio_params_t *param)
832 1.1 thorpej {
833 1.1 thorpej
834 1.26 kent return NM_BUFFSIZE / 2;
835 1.1 thorpej }
836 1.1 thorpej
837 1.29 thorpej static int
838 1.1 thorpej neo_trigger_output(void *addr, void *start, void *end, int blksize,
839 1.25 kent void (*intr)(void *), void *arg, const audio_params_t *param)
840 1.1 thorpej {
841 1.26 kent struct neo_softc *sc;
842 1.1 thorpej int ssz;
843 1.1 thorpej
844 1.26 kent sc = addr;
845 1.1 thorpej sc->pintr = intr;
846 1.1 thorpej sc->parg = arg;
847 1.1 thorpej
848 1.25 kent ssz = (param->precision == 16) ? 2 : 1;
849 1.1 thorpej if (param->channels == 2)
850 1.1 thorpej ssz <<= 1;
851 1.1 thorpej
852 1.1 thorpej sc->pbufsize = ((char*)end - (char *)start);
853 1.1 thorpej sc->pblksize = blksize;
854 1.1 thorpej sc->pwmark = blksize;
855 1.1 thorpej
856 1.1 thorpej nm_wr_4(sc, NM_PBUFFER_START, sc->pbuf);
857 1.26 kent nm_wr_4(sc, NM_PBUFFER_END, sc->pbuf + sc->pbufsize - ssz);
858 1.1 thorpej nm_wr_4(sc, NM_PBUFFER_CURRP, sc->pbuf);
859 1.1 thorpej nm_wr_4(sc, NM_PBUFFER_WMARK, sc->pbuf + sc->pwmark);
860 1.1 thorpej nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, NM_PLAYBACK_FREERUN |
861 1.1 thorpej NM_PLAYBACK_ENABLE_FLAG);
862 1.1 thorpej nm_wr_2(sc, NM_AUDIO_MUTE_REG, 0);
863 1.1 thorpej
864 1.26 kent return 0;
865 1.1 thorpej }
866 1.1 thorpej
867 1.29 thorpej static int
868 1.1 thorpej neo_trigger_input(void *addr, void *start, void *end, int blksize,
869 1.25 kent void (*intr)(void *), void *arg, const audio_params_t *param)
870 1.1 thorpej {
871 1.26 kent struct neo_softc *sc;
872 1.1 thorpej int ssz;
873 1.1 thorpej
874 1.26 kent sc = addr;
875 1.1 thorpej sc->rintr = intr;
876 1.1 thorpej sc->rarg = arg;
877 1.1 thorpej
878 1.25 kent ssz = (param->precision == 16) ? 2 : 1;
879 1.1 thorpej if (param->channels == 2)
880 1.1 thorpej ssz <<= 1;
881 1.1 thorpej
882 1.1 thorpej sc->rbufsize = ((char*)end - (char *)start);
883 1.1 thorpej sc->rblksize = blksize;
884 1.1 thorpej sc->rwmark = blksize;
885 1.1 thorpej
886 1.1 thorpej nm_wr_4(sc, NM_RBUFFER_START, sc->rbuf);
887 1.1 thorpej nm_wr_4(sc, NM_RBUFFER_END, sc->rbuf + sc->rbufsize);
888 1.1 thorpej nm_wr_4(sc, NM_RBUFFER_CURRP, sc->rbuf);
889 1.1 thorpej nm_wr_4(sc, NM_RBUFFER_WMARK, sc->rbuf + sc->rwmark);
890 1.1 thorpej nm_wr_1(sc, NM_RECORD_ENABLE_REG, NM_RECORD_FREERUN |
891 1.1 thorpej NM_RECORD_ENABLE_FLAG);
892 1.1 thorpej
893 1.26 kent return 0;
894 1.1 thorpej }
895 1.1 thorpej
896 1.29 thorpej static int
897 1.1 thorpej neo_halt_output(void *addr)
898 1.1 thorpej {
899 1.26 kent struct neo_softc *sc;
900 1.1 thorpej
901 1.26 kent sc = (struct neo_softc *)addr;
902 1.1 thorpej nm_wr_1(sc, NM_PLAYBACK_ENABLE_REG, 0);
903 1.1 thorpej nm_wr_2(sc, NM_AUDIO_MUTE_REG, NM_AUDIO_MUTE_BOTH);
904 1.22 mycroft sc->pintr = 0;
905 1.1 thorpej
906 1.26 kent return 0;
907 1.1 thorpej }
908 1.1 thorpej
909 1.29 thorpej static int
910 1.1 thorpej neo_halt_input(void *addr)
911 1.1 thorpej {
912 1.26 kent struct neo_softc *sc;
913 1.1 thorpej
914 1.26 kent sc = (struct neo_softc *)addr;
915 1.1 thorpej nm_wr_1(sc, NM_RECORD_ENABLE_REG, 0);
916 1.22 mycroft sc->rintr = 0;
917 1.1 thorpej
918 1.26 kent return 0;
919 1.1 thorpej }
920 1.1 thorpej
921 1.29 thorpej static int
922 1.35 christos neo_getdev(void *addr, struct audio_device *retp)
923 1.1 thorpej {
924 1.1 thorpej
925 1.1 thorpej *retp = neo_device;
926 1.26 kent return 0;
927 1.1 thorpej }
928 1.1 thorpej
929 1.29 thorpej static int
930 1.1 thorpej neo_mixer_set_port(void *addr, mixer_ctrl_t *cp)
931 1.1 thorpej {
932 1.26 kent struct neo_softc *sc;
933 1.1 thorpej
934 1.26 kent sc = addr;
935 1.26 kent return sc->codec_if->vtbl->mixer_set_port(sc->codec_if, cp);
936 1.1 thorpej }
937 1.1 thorpej
938 1.29 thorpej static int
939 1.1 thorpej neo_mixer_get_port(void *addr, mixer_ctrl_t *cp)
940 1.1 thorpej {
941 1.26 kent struct neo_softc *sc;
942 1.1 thorpej
943 1.26 kent sc = addr;
944 1.26 kent return sc->codec_if->vtbl->mixer_get_port(sc->codec_if, cp);
945 1.1 thorpej }
946 1.1 thorpej
947 1.29 thorpej static int
948 1.1 thorpej neo_query_devinfo(void *addr, mixer_devinfo_t *dip)
949 1.1 thorpej {
950 1.26 kent struct neo_softc *sc;
951 1.1 thorpej
952 1.26 kent sc = addr;
953 1.26 kent return sc->codec_if->vtbl->query_devinfo(sc->codec_if, dip);
954 1.1 thorpej }
955 1.1 thorpej
956 1.29 thorpej static void *
957 1.46 jmcneill neo_malloc(void *addr, int direction, size_t size)
958 1.1 thorpej {
959 1.26 kent struct neo_softc *sc;
960 1.26 kent void *rv;
961 1.1 thorpej
962 1.26 kent sc = addr;
963 1.26 kent rv = NULL;
964 1.1 thorpej switch (direction) {
965 1.1 thorpej case AUMODE_PLAY:
966 1.1 thorpej if (sc->pbuf_allocated == 0) {
967 1.1 thorpej rv = (void *) sc->pbuf_vaddr;
968 1.1 thorpej sc->pbuf_allocated = 1;
969 1.1 thorpej }
970 1.1 thorpej break;
971 1.1 thorpej
972 1.1 thorpej case AUMODE_RECORD:
973 1.1 thorpej if (sc->rbuf_allocated == 0) {
974 1.1 thorpej rv = (void *) sc->rbuf_vaddr;
975 1.1 thorpej sc->rbuf_allocated = 1;
976 1.1 thorpej }
977 1.1 thorpej break;
978 1.1 thorpej }
979 1.1 thorpej
980 1.26 kent return rv;
981 1.1 thorpej }
982 1.1 thorpej
983 1.29 thorpej static void
984 1.46 jmcneill neo_free(void *addr, void *ptr, size_t size)
985 1.1 thorpej {
986 1.26 kent struct neo_softc *sc;
987 1.26 kent vaddr_t v;
988 1.1 thorpej
989 1.26 kent sc = addr;
990 1.26 kent v = (vaddr_t)ptr;
991 1.1 thorpej if (v == sc->pbuf_vaddr)
992 1.1 thorpej sc->pbuf_allocated = 0;
993 1.1 thorpej else if (v == sc->rbuf_vaddr)
994 1.1 thorpej sc->rbuf_allocated = 0;
995 1.1 thorpej else
996 1.1 thorpej printf("neo_free: bad address %p\n", ptr);
997 1.1 thorpej }
998 1.1 thorpej
999 1.29 thorpej static size_t
1000 1.46 jmcneill neo_round_buffersize(void *addr, int direction, size_t size)
1001 1.1 thorpej {
1002 1.1 thorpej
1003 1.26 kent return NM_BUFFSIZE;
1004 1.1 thorpej }
1005 1.1 thorpej
1006 1.29 thorpej static paddr_t
1007 1.3 thorpej neo_mappage(void *addr, void *mem, off_t off, int prot)
1008 1.3 thorpej {
1009 1.26 kent struct neo_softc *sc;
1010 1.26 kent vaddr_t v;
1011 1.3 thorpej bus_addr_t pciaddr;
1012 1.3 thorpej
1013 1.26 kent sc = addr;
1014 1.26 kent v = (vaddr_t)mem;
1015 1.3 thorpej if (v == sc->pbuf_vaddr)
1016 1.3 thorpej pciaddr = sc->pbuf_pciaddr;
1017 1.3 thorpej else if (v == sc->rbuf_vaddr)
1018 1.3 thorpej pciaddr = sc->rbuf_pciaddr;
1019 1.3 thorpej else
1020 1.26 kent return -1;
1021 1.3 thorpej
1022 1.26 kent return bus_space_mmap(sc->bufiot, pciaddr, off, prot,
1023 1.26 kent BUS_SPACE_MAP_LINEAR);
1024 1.3 thorpej }
1025 1.1 thorpej
1026 1.29 thorpej static int
1027 1.35 christos neo_get_props(void *addr)
1028 1.1 thorpej {
1029 1.1 thorpej
1030 1.26 kent return AUDIO_PROP_INDEPENDENT | AUDIO_PROP_MMAP |
1031 1.26 kent AUDIO_PROP_FULLDUPLEX;
1032 1.1 thorpej }
1033 1.46 jmcneill
1034 1.46 jmcneill static void
1035 1.46 jmcneill neo_get_locks(void *addr, kmutex_t **intr, kmutex_t **thread)
1036 1.46 jmcneill {
1037 1.46 jmcneill struct neo_softc *sc;
1038 1.46 jmcneill
1039 1.46 jmcneill sc = addr;
1040 1.46 jmcneill *intr = &sc->intr_lock;
1041 1.46 jmcneill *thread = &sc->lock;
1042 1.46 jmcneill }
1043