1 /* $OpenBSD: sv.c,v 1.45 2024/06/22 10:22:29 jsg Exp $ */
2
3 /*
4 * Copyright (c) 1998 Constantine Paul Sapuntzakis
5 * All rights reserved
6 *
7 * Author: Constantine Paul Sapuntzakis (csapuntz@cvs.openbsd.org)
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The author's name or those of the contributors may be used to
18 * endorse or promote products derived from this software without
19 * specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * S3 SonicVibes driver
36 * Heavily based on the eap driver by Lennart Augustsson
37 */
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/malloc.h>
42 #include <sys/device.h>
43
44 #include <dev/pci/pcireg.h>
45 #include <dev/pci/pcivar.h>
46 #include <dev/pci/pcidevs.h>
47
48 #include <sys/audioio.h>
49 #include <dev/audio_if.h>
50
51 #include <dev/ic/i8237reg.h>
52 #include <dev/ic/s3_617.h>
53
54
55 #include <machine/bus.h>
56
57 struct cfdriver sv_cd = {
58 NULL, "sv", DV_DULL
59 };
60
61 #ifdef AUDIO_DEBUG
62 #define DPRINTF(x) if (svdebug) printf x
63 #define DPRINTFN(n,x) if (svdebug>(n)) printf x
64 static int svdebug = 100;
65 #else
66 #define DPRINTF(x)
67 #define DPRINTFN(n,x)
68 #endif
69
70 int sv_match(struct device *, void *, void *);
71 static void sv_attach(struct device *, struct device *, void *);
72 int sv_intr(void *);
73
74 struct sv_dma {
75 bus_dmamap_t map;
76 caddr_t addr;
77 bus_dma_segment_t segs[1];
78 int nsegs;
79 size_t size;
80 struct sv_dma *next;
81 };
82 #define DMAADDR(map) ((map)->segs[0].ds_addr)
83 #define KERNADDR(map) ((void *)((map)->addr))
84
85 enum {
86 SV_DMAA_CONFIGURED = 1,
87 SV_DMAC_CONFIGURED = 2,
88 SV_DMAA_TRIED_CONFIGURE = 4,
89 SV_DMAC_TRIED_CONFIGURE = 8
90 };
91
92 struct sv_softc {
93 struct device sc_dev; /* base device */
94 void *sc_ih; /* interrupt vectoring */
95
96 pci_chipset_tag_t sc_pci_chipset_tag;
97 pcitag_t sc_pci_tag;
98
99 bus_space_tag_t sc_iot;
100 bus_space_handle_t sc_ioh;
101 bus_space_handle_t sc_dmaa_ioh;
102 bus_space_handle_t sc_dmac_ioh;
103 bus_dma_tag_t sc_dmatag; /* DMA tag */
104
105 struct sv_dma *sc_dmas;
106
107 void (*sc_pintr)(void *); /* dma completion intr handler */
108 void *sc_parg; /* arg for sc_intr() */
109
110 void (*sc_rintr)(void *); /* dma completion intr handler */
111 void *sc_rarg; /* arg for sc_intr() */
112 char sc_enable;
113 char sc_trd;
114
115 char sc_dma_configured;
116 u_int sc_record_source; /* recording source mask */
117 };
118
119
120 const struct cfattach sv_ca = {
121 sizeof(struct sv_softc), sv_match, sv_attach
122 };
123
124 #define ARRAY_SIZE(foo) ((sizeof(foo)) / sizeof(foo[0]))
125
126 int sv_allocmem(struct sv_softc *, size_t, size_t, struct sv_dma *);
127 int sv_freemem(struct sv_softc *, struct sv_dma *);
128
129 int sv_open(void *, int);
130 void sv_close(void *);
131 int sv_set_params(void *, int, int, struct audio_params *, struct audio_params *);
132 int sv_round_blocksize(void *, int);
133 int sv_dma_init_output(void *, void *, int);
134 int sv_dma_init_input(void *, void *, int);
135 int sv_dma_output(void *, void *, int, void (*)(void *), void *);
136 int sv_dma_input(void *, void *, int, void (*)(void *), void *);
137 int sv_halt_in_dma(void *);
138 int sv_halt_out_dma(void *);
139 int sv_mixer_set_port(void *, mixer_ctrl_t *);
140 int sv_mixer_get_port(void *, mixer_ctrl_t *);
141 int sv_query_devinfo(void *, mixer_devinfo_t *);
142 void *sv_malloc(void *, int, size_t, int, int);
143 void sv_free(void *, void *, int);
144
145 void sv_dumpregs(struct sv_softc *sc);
146
147 const struct audio_hw_if sv_hw_if = {
148 .open = sv_open,
149 .close = sv_close,
150 .set_params = sv_set_params,
151 .round_blocksize = sv_round_blocksize,
152 .init_output = sv_dma_init_output,
153 .init_input = sv_dma_init_input,
154 .start_output = sv_dma_output,
155 .start_input = sv_dma_input,
156 .halt_output = sv_halt_out_dma,
157 .halt_input = sv_halt_in_dma,
158 .set_port = sv_mixer_set_port,
159 .get_port = sv_mixer_get_port,
160 .query_devinfo = sv_query_devinfo,
161 .allocm = sv_malloc,
162 .freem = sv_free,
163 };
164
165
166 static __inline__ u_int8_t sv_read(struct sv_softc *, u_int8_t);
167 static __inline__ u_int8_t sv_read_indirect(struct sv_softc *, u_int8_t);
168 static __inline__ void sv_write(struct sv_softc *, u_int8_t, u_int8_t );
169 static __inline__ void sv_write_indirect(struct sv_softc *, u_int8_t, u_int8_t );
170 static void sv_init_mixer(struct sv_softc *);
171
172 static __inline__ void
sv_write(struct sv_softc * sc,u_int8_t reg,u_int8_t val)173 sv_write(struct sv_softc *sc, u_int8_t reg, u_int8_t val)
174 {
175 bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, val);
176 }
177
178 static __inline__ u_int8_t
sv_read(struct sv_softc * sc,u_int8_t reg)179 sv_read(struct sv_softc *sc, u_int8_t reg)
180 {
181 return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg));
182 }
183
184 static __inline__ u_int8_t
sv_read_indirect(struct sv_softc * sc,u_int8_t reg)185 sv_read_indirect(struct sv_softc *sc, u_int8_t reg)
186 {
187 u_int8_t iaddr = 0;
188
189 if (sc->sc_trd > 0)
190 iaddr |= SV_IADDR_TRD;
191
192 iaddr |= (reg & SV_IADDR_MASK);
193 sv_write (sc, SV_CODEC_IADDR, iaddr);
194
195 return (sv_read(sc, SV_CODEC_IDATA));
196 }
197
198 static __inline__ void
sv_write_indirect(struct sv_softc * sc,u_int8_t reg,u_int8_t val)199 sv_write_indirect(struct sv_softc *sc, u_int8_t reg, u_int8_t val)
200 {
201 u_int8_t iaddr = 0;
202 #ifdef DIAGNOSTIC
203 if (reg > 0x3f) {
204 printf ("Invalid register\n");
205 return;
206 }
207 #endif
208
209 if (reg == SV_DMA_DATA_FORMAT)
210 iaddr |= SV_IADDR_MCE;
211
212 if (sc->sc_trd > 0)
213 iaddr |= SV_IADDR_TRD;
214
215 iaddr |= (reg & SV_IADDR_MASK);
216 sv_write (sc, SV_CODEC_IADDR, iaddr);
217 sv_write (sc, SV_CODEC_IDATA, val);
218 }
219
220 int
sv_match(struct device * parent,void * match,void * aux)221 sv_match(struct device *parent, void *match, void *aux)
222 {
223 struct pci_attach_args *pa = aux;
224
225 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_S3 &&
226 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_S3_SONICVIBES)
227 return (1);
228
229 return (0);
230 }
231
232 static void
sv_attach(struct device * parent,struct device * self,void * aux)233 sv_attach(struct device *parent, struct device *self, void *aux)
234 {
235 struct sv_softc *sc = (struct sv_softc *)self;
236 struct pci_attach_args *pa = aux;
237 pci_chipset_tag_t pc = pa->pa_pc;
238 pci_intr_handle_t ih;
239 bus_size_t iosize;
240 char const *intrstr;
241 u_int32_t dmareg, dmaio;
242 u_int8_t reg;
243
244 sc->sc_pci_chipset_tag = pc;
245 sc->sc_pci_tag = pa->pa_tag;
246
247 /* Map the enhanced port only */
248 if (pci_mapreg_map(pa, SV_ENHANCED_PORTBASE_SLOT, PCI_MAPREG_TYPE_IO, 0,
249 &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) {
250 printf (": Couldn't map enhanced synth I/O range\n");
251 return;
252 }
253
254 sc->sc_dmatag = pa->pa_dmat;
255
256 dmareg = pci_conf_read(pa->pa_pc, pa->pa_tag, SV_DMAA_CONFIG_OFF);
257 iosize = 0x10;
258 dmaio = dmareg & ~(iosize - 1);
259
260 if (dmaio) {
261 dmareg &= 0xF;
262
263 if (bus_space_map(sc->sc_iot, dmaio, iosize, 0, &sc->sc_dmaa_ioh)) {
264 /* The BIOS assigned us some bad I/O address! Make sure to clear
265 and disable this DMA before we enable the device */
266 pci_conf_write(pa->pa_pc, pa->pa_tag, SV_DMAA_CONFIG_OFF, 0);
267
268 printf (": can't map DMA i/o space\n");
269 goto enable;
270 }
271
272 pci_conf_write(pa->pa_pc, pa->pa_tag, SV_DMAA_CONFIG_OFF,
273 dmaio | dmareg |
274 SV_DMA_CHANNEL_ENABLE | SV_DMAA_EXTENDED_ADDR);
275 sc->sc_dma_configured |= SV_DMAA_CONFIGURED;
276 }
277
278 dmareg = pci_conf_read(pa->pa_pc, pa->pa_tag, SV_DMAC_CONFIG_OFF);
279 dmaio = dmareg & ~(iosize - 1);
280 if (dmaio) {
281 dmareg &= 0xF;
282
283 if (bus_space_map(sc->sc_iot, dmaio, iosize, 0, &sc->sc_dmac_ioh)) {
284 /* The BIOS assigned us some bad I/O address! Make sure to clear
285 and disable this DMA before we enable the device */
286 pci_conf_write (pa->pa_pc, pa->pa_tag, SV_DMAC_CONFIG_OFF,
287 dmareg & ~SV_DMA_CHANNEL_ENABLE);
288 printf (": can't map DMA i/o space\n");
289 goto enable;
290 }
291
292 pci_conf_write(pa->pa_pc, pa->pa_tag, SV_DMAC_CONFIG_OFF,
293 dmaio | dmareg | SV_DMA_CHANNEL_ENABLE);
294 sc->sc_dma_configured |= SV_DMAC_CONFIGURED;
295 }
296
297 /* Enable the device. */
298 enable:
299 sv_write_indirect(sc, SV_ANALOG_POWER_DOWN_CONTROL, 0);
300 sv_write_indirect(sc, SV_DIGITAL_POWER_DOWN_CONTROL, 0);
301
302 /* initialize codec registers */
303 reg = sv_read(sc, SV_CODEC_CONTROL);
304 reg |= SV_CTL_RESET;
305 sv_write(sc, SV_CODEC_CONTROL, reg);
306 delay(50);
307
308 reg = sv_read(sc, SV_CODEC_CONTROL);
309 reg &= ~SV_CTL_RESET;
310 reg |= SV_CTL_INTA | SV_CTL_ENHANCED;
311
312 /* This write clears the reset */
313 sv_write(sc, SV_CODEC_CONTROL, reg);
314 delay(50);
315
316 /* This write actually shoves the new values in */
317 sv_write(sc, SV_CODEC_CONTROL, reg);
318
319 DPRINTF (("reg: %x\n", sv_read(sc, SV_CODEC_CONTROL)));
320
321 /* Enable DMA interrupts */
322 reg = sv_read(sc, SV_CODEC_INTMASK);
323 reg &= ~(SV_INTMASK_DMAA | SV_INTMASK_DMAC);
324 reg |= SV_INTMASK_UD | SV_INTMASK_SINT | SV_INTMASK_MIDI;
325 sv_write(sc, SV_CODEC_INTMASK, reg);
326
327 sv_read(sc, SV_CODEC_STATUS);
328
329 sc->sc_trd = 0;
330 sc->sc_enable = 0;
331
332 /* Map and establish the interrupt. */
333 if (pci_intr_map(pa, &ih)) {
334 printf(": couldn't map interrupt\n");
335 return;
336 }
337 intrstr = pci_intr_string(pc, ih);
338 sc->sc_ih = pci_intr_establish(pc, ih, IPL_AUDIO | IPL_MPSAFE,
339 sv_intr, sc, sc->sc_dev.dv_xname);
340 if (sc->sc_ih == NULL) {
341 printf(": couldn't establish interrupt");
342 if (intrstr != NULL)
343 printf(" at %s", intrstr);
344 printf("\n");
345 return;
346 }
347 printf(": %s\n", intrstr);
348
349 sv_init_mixer(sc);
350
351 audio_attach_mi(&sv_hw_if, sc, NULL, &sc->sc_dev);
352 }
353
354 #ifdef AUDIO_DEBUG
355 void
sv_dumpregs(struct sv_softc * sc)356 sv_dumpregs(struct sv_softc *sc)
357 {
358 int idx;
359
360 { int idx;
361 for (idx = 0; idx < 0x50; idx += 4) {
362 printf ("%02x = %x\n", idx, pci_conf_read(sc->sc_pci_chipset_tag,
363 sc->sc_pci_tag, idx));
364 }
365 }
366
367 for (idx = 0; idx < 6; idx++) {
368 printf ("REG %02x = %02x\n", idx, sv_read(sc, idx));
369 }
370
371 for (idx = 0; idx < 0x32; idx++) {
372 printf ("IREG %02x = %02x\n", idx, sv_read_indirect(sc, idx));
373 }
374
375 for (idx = 0; idx < 0x10; idx++) {
376 printf ("DMA %02x = %02x\n", idx,
377 bus_space_read_1(sc->sc_iot, sc->sc_dmaa_ioh, idx));
378 }
379
380 return;
381 }
382 #endif
383
384 int
sv_intr(void * p)385 sv_intr(void *p)
386 {
387 struct sv_softc *sc = p;
388 u_int8_t intr;
389
390 mtx_enter(&audio_lock);
391 intr = sv_read(sc, SV_CODEC_STATUS);
392
393 if (!(intr & (SV_INTSTATUS_DMAA | SV_INTSTATUS_DMAC))) {
394 mtx_leave(&audio_lock);
395 return (0);
396 }
397
398 if (intr & SV_INTSTATUS_DMAA) {
399 if (sc->sc_pintr)
400 sc->sc_pintr(sc->sc_parg);
401 }
402
403 if (intr & SV_INTSTATUS_DMAC) {
404 if (sc->sc_rintr)
405 sc->sc_rintr(sc->sc_rarg);
406 }
407 mtx_leave(&audio_lock);
408 return (1);
409 }
410
411 int
sv_allocmem(struct sv_softc * sc,size_t size,size_t align,struct sv_dma * p)412 sv_allocmem(struct sv_softc *sc, size_t size, size_t align, struct sv_dma *p)
413 {
414 int error;
415
416 p->size = size;
417 error = bus_dmamem_alloc(sc->sc_dmatag, p->size, align, 0,
418 p->segs, ARRAY_SIZE(p->segs),
419 &p->nsegs, BUS_DMA_NOWAIT);
420 if (error)
421 return (error);
422
423 error = bus_dmamem_map(sc->sc_dmatag, p->segs, p->nsegs, p->size,
424 &p->addr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
425 if (error)
426 goto free;
427
428 error = bus_dmamap_create(sc->sc_dmatag, p->size, 1, p->size,
429 0, BUS_DMA_NOWAIT, &p->map);
430 if (error)
431 goto unmap;
432
433 error = bus_dmamap_load(sc->sc_dmatag, p->map, p->addr, p->size, NULL,
434 BUS_DMA_NOWAIT);
435 if (error)
436 goto destroy;
437 return (0);
438
439 destroy:
440 bus_dmamap_destroy(sc->sc_dmatag, p->map);
441 unmap:
442 bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
443 free:
444 bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
445 return (error);
446 }
447
448 int
sv_freemem(struct sv_softc * sc,struct sv_dma * p)449 sv_freemem(struct sv_softc *sc, struct sv_dma *p)
450 {
451 bus_dmamap_unload(sc->sc_dmatag, p->map);
452 bus_dmamap_destroy(sc->sc_dmatag, p->map);
453 bus_dmamem_unmap(sc->sc_dmatag, p->addr, p->size);
454 bus_dmamem_free(sc->sc_dmatag, p->segs, p->nsegs);
455 return (0);
456 }
457
458 int
sv_open(void * addr,int flags)459 sv_open(void *addr, int flags)
460 {
461
462 struct sv_softc *sc = addr;
463 int intr_mask = 0;
464 u_int8_t reg;
465
466 /* Map the DMA channels, if necessary */
467 if (!(sc->sc_dma_configured & SV_DMAA_CONFIGURED)) {
468 /* XXX - there seems to be no general way to find an
469 I/O range */
470 int dmaio;
471 int iosize = 0x10;
472
473 if (sc->sc_dma_configured & SV_DMAA_TRIED_CONFIGURE)
474 return (ENXIO);
475
476 for (dmaio = 0xa000; dmaio < 0xb000; dmaio += iosize) {
477 if (!bus_space_map(sc->sc_iot, dmaio, iosize, 0,
478 &sc->sc_dmaa_ioh)) {
479 goto found_dmaa;
480 }
481 }
482
483 sc->sc_dma_configured |= SV_DMAA_TRIED_CONFIGURE;
484 return (ENXIO);
485 found_dmaa:
486
487 pci_conf_write(sc->sc_pci_chipset_tag, sc->sc_pci_tag,
488 SV_DMAA_CONFIG_OFF,
489 dmaio | SV_DMA_CHANNEL_ENABLE
490 | SV_DMAA_EXTENDED_ADDR);
491
492 sc->sc_dma_configured |= SV_DMAA_CONFIGURED;
493 intr_mask = 1;
494 }
495
496 if (!(sc->sc_dma_configured & SV_DMAC_CONFIGURED)) {
497 /* XXX - there seems to be no general way to find an
498 I/O range */
499 int dmaio;
500 int iosize = 0x10;
501
502 if (sc->sc_dma_configured & SV_DMAC_TRIED_CONFIGURE)
503 return (ENXIO);
504
505 for (dmaio = 0xa000; dmaio < 0xb000; dmaio += iosize) {
506 if (!bus_space_map(sc->sc_iot, dmaio, iosize, 0,
507 &sc->sc_dmac_ioh)) {
508 goto found_dmac;
509 }
510 }
511
512 sc->sc_dma_configured |= SV_DMAC_TRIED_CONFIGURE;
513 return (ENXIO);
514 found_dmac:
515
516 pci_conf_write(sc->sc_pci_chipset_tag, sc->sc_pci_tag,
517 SV_DMAC_CONFIG_OFF,
518 dmaio | SV_DMA_CHANNEL_ENABLE);
519
520 sc->sc_dma_configured |= SV_DMAC_CONFIGURED;
521 intr_mask = 1;
522 }
523
524 /* Make sure DMA interrupts are enabled */
525 if (intr_mask) {
526 reg = sv_read(sc, SV_CODEC_INTMASK);
527 reg &= ~(SV_INTMASK_DMAA | SV_INTMASK_DMAC);
528 reg |= SV_INTMASK_UD | SV_INTMASK_SINT | SV_INTMASK_MIDI;
529 sv_write(sc, SV_CODEC_INTMASK, reg);
530 }
531
532 sc->sc_pintr = 0;
533 sc->sc_rintr = 0;
534
535 return (0);
536 }
537
538 /*
539 * Close function is called at splaudio().
540 */
541 void
sv_close(void * addr)542 sv_close(void *addr)
543 {
544 struct sv_softc *sc = addr;
545
546 sv_halt_in_dma(sc);
547 sv_halt_out_dma(sc);
548
549 sc->sc_pintr = 0;
550 sc->sc_rintr = 0;
551 }
552
553 int
sv_set_params(void * addr,int setmode,int usemode,struct audio_params * p,struct audio_params * r)554 sv_set_params(void *addr, int setmode, int usemode,
555 struct audio_params *p, struct audio_params *r)
556 {
557 struct sv_softc *sc = addr;
558 u_int32_t mode, val;
559 u_int8_t reg;
560
561 switch (p->encoding) {
562 case AUDIO_ENCODING_SLINEAR_LE:
563 if (p->precision != 16)
564 return EINVAL;
565 break;
566 case AUDIO_ENCODING_ULINEAR_BE:
567 case AUDIO_ENCODING_ULINEAR_LE:
568 if (p->precision != 8)
569 return EINVAL;
570 break;
571 default:
572 return (EINVAL);
573 }
574
575 if (p->precision == 16)
576 mode = SV_DMAA_FORMAT16 | SV_DMAC_FORMAT16;
577 else
578 mode = 0;
579 if (p->channels > 2)
580 p->channels = 2;
581 if (p->channels == 2)
582 mode |= SV_DMAA_STEREO | SV_DMAC_STEREO;
583 if (p->sample_rate < 2000)
584 p->sample_rate = 2000;
585 if (p->sample_rate > 48000)
586 p->sample_rate = 48000;
587
588 p->bps = AUDIO_BPS(p->precision);
589 r->bps = AUDIO_BPS(r->precision);
590 p->msb = r->msb = 1;
591
592 /* Set the encoding */
593 reg = sv_read_indirect(sc, SV_DMA_DATA_FORMAT);
594 reg &= ~(SV_DMAA_FORMAT16 | SV_DMAC_FORMAT16 | SV_DMAA_STEREO |
595 SV_DMAC_STEREO);
596 reg |= (mode);
597 sv_write_indirect(sc, SV_DMA_DATA_FORMAT, reg);
598
599 val = p->sample_rate * 65536 / 48000;
600
601 sv_write_indirect(sc, SV_PCM_SAMPLE_RATE_0, (val & 0xff));
602 sv_write_indirect(sc, SV_PCM_SAMPLE_RATE_1, (val >> 8));
603
604 #define F_REF 24576000
605
606 if (setmode & AUMODE_RECORD)
607 {
608 /* The ADC reference frequency (f_out) is 512 * the sample rate */
609
610 /* f_out is derived from the 24.576MHZ crystal by three values:
611 M & N & R. The equation is as follows:
612
613 f_out = (m + 2) * f_ref / ((n + 2) * (2 ^ a))
614
615 with the constraint that:
616
617 80 MHz < (m + 2) / (n + 2) * f_ref <= 150MHz
618 and n, m >= 1
619 */
620
621 int goal_f_out = 512 * r->sample_rate;
622 int a, n, m, best_n, best_m, best_error = 10000000;
623 int pll_sample;
624
625 for (a = 0; a < 8; a++) {
626 if ((goal_f_out * (1 << a)) >= 80000000)
627 break;
628 }
629
630 /* a != 8 because sample_rate >= 2000 */
631
632 for (n = 33; n > 2; n--) {
633 int error;
634
635 m = (goal_f_out * n * (1 << a)) / F_REF;
636
637 if ((m > 257) || (m < 3)) continue;
638
639 pll_sample = (m * F_REF) / (n * (1 << a));
640 pll_sample /= 512;
641
642 /* Threshold might be good here */
643 error = pll_sample - r->sample_rate;
644 error = abs(error);
645
646 if (error < best_error) {
647 best_error = error;
648 best_n = n;
649 best_m = m;
650 if (error == 0) break;
651 }
652 }
653
654
655 best_n -= 2;
656 best_m -= 2;
657
658 sv_write_indirect(sc, SV_ADC_PLL_M, best_m);
659 sv_write_indirect(sc, SV_ADC_PLL_N, best_n | (a << SV_PLL_R_SHIFT));
660 }
661 return (0);
662 }
663
664 int
sv_round_blocksize(void * addr,int blk)665 sv_round_blocksize(void *addr, int blk)
666 {
667 return ((blk + 31) & -32); /* keep good alignment */
668 }
669
670 int
sv_dma_init_input(void * addr,void * buf,int cc)671 sv_dma_init_input(void *addr, void *buf, int cc)
672 {
673 struct sv_softc *sc = addr;
674 struct sv_dma *p;
675 int dma_count;
676
677 DPRINTF(("sv_dma_init_input: dma start loop input addr=%p cc=%d\n",
678 buf, cc));
679 for (p = sc->sc_dmas; p && KERNADDR(p) != buf; p = p->next)
680 ;
681 if (!p) {
682 printf("sv_dma_init_input: bad addr %p\n", buf);
683 return (EINVAL);
684 }
685
686 dma_count = (cc >> 1) - 1;
687
688 bus_space_write_4(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_ADDR0,
689 DMAADDR(p));
690 bus_space_write_4(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_COUNT0,
691 dma_count);
692 bus_space_write_1(sc->sc_iot, sc->sc_dmac_ioh, SV_DMA_MODE,
693 DMA37MD_WRITE | DMA37MD_LOOP);
694
695 return (0);
696 }
697
698 int
sv_dma_init_output(void * addr,void * buf,int cc)699 sv_dma_init_output(void *addr, void *buf, int cc)
700 {
701 struct sv_softc *sc = addr;
702 struct sv_dma *p;
703 int dma_count;
704
705 DPRINTF(("sv: dma start loop output buf=%p cc=%d\n", buf, cc));
706 for (p = sc->sc_dmas; p && KERNADDR(p) != buf; p = p->next)
707 ;
708 if (!p) {
709 printf("sv_dma_init_output: bad addr %p\n", buf);
710 return (EINVAL);
711 }
712
713 dma_count = cc - 1;
714
715 bus_space_write_4(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_ADDR0,
716 DMAADDR(p));
717 bus_space_write_4(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_COUNT0,
718 dma_count);
719 bus_space_write_1(sc->sc_iot, sc->sc_dmaa_ioh, SV_DMA_MODE,
720 DMA37MD_READ | DMA37MD_LOOP);
721
722 return (0);
723 }
724
725 int
sv_dma_output(void * addr,void * p,int cc,void (* intr)(void *),void * arg)726 sv_dma_output(void *addr, void *p, int cc, void (*intr)(void *), void *arg)
727 {
728 struct sv_softc *sc = addr;
729 u_int8_t mode;
730
731 DPRINTFN(1,
732 ("sv_dma_output: sc=%p buf=%p cc=%d intr=%p(%p)\n",
733 addr, p, cc, intr, arg));
734 sc->sc_pintr = intr;
735 sc->sc_parg = arg;
736 if (!(sc->sc_enable & SV_PLAY_ENABLE)) {
737 int dma_count = cc - 1;
738
739 sv_write_indirect(sc, SV_DMAA_COUNT1, dma_count >> 8);
740 sv_write_indirect(sc, SV_DMAA_COUNT0, (dma_count & 0xFF));
741
742 mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE);
743 mode |= SV_PLAY_ENABLE;
744 sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode);
745 sc->sc_enable |= SV_PLAY_ENABLE;
746 }
747 return (0);
748 }
749
750 int
sv_dma_input(void * addr,void * p,int cc,void (* intr)(void *),void * arg)751 sv_dma_input(void *addr, void *p, int cc, void (*intr)(void *), void *arg)
752 {
753 struct sv_softc *sc = addr;
754 u_int8_t mode;
755
756 DPRINTFN(1, ("sv_dma_input: sc=%p buf=%p cc=%d intr=%p(%p)\n",
757 addr, p, cc, intr, arg));
758 sc->sc_rintr = intr;
759 sc->sc_rarg = arg;
760 if (!(sc->sc_enable & SV_RECORD_ENABLE)) {
761 int dma_count = (cc >> 1) - 1;
762
763 sv_write_indirect(sc, SV_DMAC_COUNT1, dma_count >> 8);
764 sv_write_indirect(sc, SV_DMAC_COUNT0, (dma_count & 0xFF));
765
766 mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE);
767 mode |= SV_RECORD_ENABLE;
768 sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode);
769 sc->sc_enable |= SV_RECORD_ENABLE;
770 }
771 return (0);
772 }
773
774 int
sv_halt_out_dma(void * addr)775 sv_halt_out_dma(void *addr)
776 {
777 struct sv_softc *sc = addr;
778 u_int8_t mode;
779
780 DPRINTF(("sv: sv_halt_out_dma\n"));
781 mtx_enter(&audio_lock);
782 mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE);
783 mode &= ~SV_PLAY_ENABLE;
784 sc->sc_enable &= ~SV_PLAY_ENABLE;
785 sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode);
786 mtx_leave(&audio_lock);
787 return (0);
788 }
789
790 int
sv_halt_in_dma(void * addr)791 sv_halt_in_dma(void *addr)
792 {
793 struct sv_softc *sc = addr;
794 u_int8_t mode;
795
796 DPRINTF(("sv: sv_halt_in_dma\n"));
797 mtx_enter(&audio_lock);
798 mode = sv_read_indirect(sc, SV_PLAY_RECORD_ENABLE);
799 mode &= ~SV_RECORD_ENABLE;
800 sc->sc_enable &= ~SV_RECORD_ENABLE;
801 sv_write_indirect(sc, SV_PLAY_RECORD_ENABLE, mode);
802 mtx_leave(&audio_lock);
803 return (0);
804 }
805
806 /*
807 * Mixer related code is here
808 *
809 */
810
811 #define SV_INPUT_CLASS 0
812 #define SV_OUTPUT_CLASS 1
813 #define SV_RECORD_CLASS 2
814
815 #define SV_LAST_CLASS 2
816
817 static const char *mixer_classes[] = { AudioCinputs, AudioCoutputs, AudioCrecord };
818
819 static const struct {
820 u_int8_t l_port;
821 u_int8_t r_port;
822 u_int8_t mask;
823 u_int8_t class;
824 const char *audio;
825 } ports[] = {
826 { SV_LEFT_AUX1_INPUT_CONTROL, SV_RIGHT_AUX1_INPUT_CONTROL, SV_AUX1_MASK,
827 SV_INPUT_CLASS, "aux1" },
828 { SV_LEFT_CD_INPUT_CONTROL, SV_RIGHT_CD_INPUT_CONTROL, SV_CD_MASK,
829 SV_INPUT_CLASS, AudioNcd },
830 { SV_LEFT_LINE_IN_INPUT_CONTROL, SV_RIGHT_LINE_IN_INPUT_CONTROL, SV_LINE_IN_MASK,
831 SV_INPUT_CLASS, AudioNline },
832 { SV_MIC_INPUT_CONTROL, 0, SV_MIC_MASK, SV_INPUT_CLASS, AudioNmicrophone },
833 { SV_LEFT_SYNTH_INPUT_CONTROL, SV_RIGHT_SYNTH_INPUT_CONTROL,
834 SV_SYNTH_MASK, SV_INPUT_CLASS, AudioNfmsynth },
835 { SV_LEFT_AUX2_INPUT_CONTROL, SV_RIGHT_AUX2_INPUT_CONTROL, SV_AUX2_MASK,
836 SV_INPUT_CLASS, "aux2" },
837 { SV_LEFT_PCM_INPUT_CONTROL, SV_RIGHT_PCM_INPUT_CONTROL, SV_PCM_MASK,
838 SV_INPUT_CLASS, AudioNdac },
839 { SV_LEFT_MIXER_OUTPUT_CONTROL, SV_RIGHT_MIXER_OUTPUT_CONTROL,
840 SV_MIXER_OUT_MASK, SV_OUTPUT_CLASS, AudioNmaster }
841 };
842
843
844 static const struct {
845 int idx;
846 const char *name;
847 } record_sources[] = {
848 { SV_REC_CD, AudioNcd },
849 { SV_REC_DAC, AudioNdac },
850 { SV_REC_AUX2, "aux2" },
851 { SV_REC_LINE, AudioNline },
852 { SV_REC_AUX1, "aux1" },
853 { SV_REC_MIC, AudioNmicrophone },
854 { SV_REC_MIXER, AudioNmixerout }
855 };
856
857
858 #define SV_DEVICES_PER_PORT 2
859 #define SV_FIRST_MIXER (SV_LAST_CLASS + 1)
860 #define SV_LAST_MIXER (SV_DEVICES_PER_PORT * (ARRAY_SIZE(ports)) + SV_LAST_CLASS)
861 #define SV_RECORD_SOURCE (SV_LAST_MIXER + 1)
862 #define SV_MIC_BOOST (SV_LAST_MIXER + 2)
863 #define SV_RECORD_GAIN (SV_LAST_MIXER + 3)
864 #define SV_SRS_MODE (SV_LAST_MIXER + 4)
865
866 int
sv_query_devinfo(void * addr,mixer_devinfo_t * dip)867 sv_query_devinfo(void *addr, mixer_devinfo_t *dip)
868 {
869
870 if (dip->index < 0)
871 return (ENXIO);
872
873 /* It's a class */
874 if (dip->index <= SV_LAST_CLASS) {
875 dip->type = AUDIO_MIXER_CLASS;
876 dip->mixer_class = dip->index;
877 dip->next = dip->prev = AUDIO_MIXER_LAST;
878 strlcpy(dip->label.name, mixer_classes[dip->index],
879 sizeof dip->label.name);
880 return (0);
881 }
882
883 if (dip->index >= SV_FIRST_MIXER &&
884 dip->index <= SV_LAST_MIXER) {
885 int off = dip->index - SV_FIRST_MIXER;
886 int mute = (off % SV_DEVICES_PER_PORT);
887 int idx = off / SV_DEVICES_PER_PORT;
888
889 dip->mixer_class = ports[idx].class;
890 strlcpy(dip->label.name, ports[idx].audio, sizeof dip->label.name);
891
892 if (!mute) {
893 dip->type = AUDIO_MIXER_VALUE;
894 dip->prev = AUDIO_MIXER_LAST;
895 dip->next = dip->index + 1;
896
897 if (ports[idx].r_port != 0)
898 dip->un.v.num_channels = 2;
899 else
900 dip->un.v.num_channels = 1;
901
902 strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
903
904 } else {
905 dip->type = AUDIO_MIXER_ENUM;
906 dip->prev = dip->index - 1;
907 dip->next = AUDIO_MIXER_LAST;
908
909 strlcpy(dip->label.name, AudioNmute, sizeof dip->label.name);
910 dip->un.e.num_mem = 2;
911 strlcpy(dip->un.e.member[0].label.name, AudioNoff,
912 sizeof dip->un.e.member[0].label.name);
913 dip->un.e.member[0].ord = 0;
914 strlcpy(dip->un.e.member[1].label.name, AudioNon,
915 sizeof dip->un.e.member[1].label.name);
916 dip->un.e.member[1].ord = 1;
917
918 }
919
920 return (0);
921 }
922
923 switch (dip->index) {
924 case SV_RECORD_SOURCE:
925 dip->mixer_class = SV_RECORD_CLASS;
926 dip->prev = AUDIO_MIXER_LAST;
927 dip->next = SV_RECORD_GAIN;
928 strlcpy(dip->label.name, AudioNsource, sizeof dip->label.name);
929 dip->type = AUDIO_MIXER_ENUM;
930
931 dip->un.e.num_mem = ARRAY_SIZE(record_sources);
932
933 {
934 int idx;
935 for (idx = 0; idx < ARRAY_SIZE(record_sources); idx++) {
936 strlcpy(dip->un.e.member[idx].label.name, record_sources[idx].name,
937 sizeof dip->un.e.member[idx].label.name);
938 dip->un.e.member[idx].ord = record_sources[idx].idx;
939 }
940 }
941 return (0);
942
943 case SV_RECORD_GAIN:
944 dip->mixer_class = SV_RECORD_CLASS;
945 dip->prev = SV_RECORD_SOURCE;
946 dip->next = AUDIO_MIXER_LAST;
947 strlcpy(dip->label.name, "gain", sizeof dip->label.name);
948 dip->type = AUDIO_MIXER_VALUE;
949 dip->un.v.num_channels = 1;
950 strlcpy(dip->un.v.units.name, AudioNvolume, sizeof dip->un.v.units.name);
951 return (0);
952
953 case SV_MIC_BOOST:
954 dip->mixer_class = SV_RECORD_CLASS;
955 dip->prev = AUDIO_MIXER_LAST;
956 dip->next = AUDIO_MIXER_LAST;
957 strlcpy(dip->label.name, "micboost", sizeof dip->label.name);
958 goto on_off;
959
960 case SV_SRS_MODE:
961 dip->mixer_class = SV_OUTPUT_CLASS;
962 dip->prev = dip->next = AUDIO_MIXER_LAST;
963 strlcpy(dip->label.name, AudioNspatial, sizeof dip->label.name);
964
965 on_off:
966 dip->type = AUDIO_MIXER_ENUM;
967 dip->un.e.num_mem = 2;
968 strlcpy(dip->un.e.member[0].label.name, AudioNoff,
969 sizeof dip->un.e.member[0].label.name);
970 dip->un.e.member[0].ord = 0;
971 strlcpy(dip->un.e.member[1].label.name, AudioNon,
972 sizeof dip->un.e.member[1].label.name);
973 dip->un.e.member[1].ord = 1;
974 return (0);
975 }
976
977 return (ENXIO);
978 }
979
980 int
sv_mixer_set_port(void * addr,mixer_ctrl_t * cp)981 sv_mixer_set_port(void *addr, mixer_ctrl_t *cp)
982 {
983 struct sv_softc *sc = addr;
984 u_int8_t reg;
985 int idx;
986
987 if (cp->dev >= SV_FIRST_MIXER &&
988 cp->dev <= SV_LAST_MIXER) {
989 int off = cp->dev - SV_FIRST_MIXER;
990 int mute = (off % SV_DEVICES_PER_PORT);
991 idx = off / SV_DEVICES_PER_PORT;
992
993 if (mute) {
994 if (cp->type != AUDIO_MIXER_ENUM)
995 return (EINVAL);
996
997 reg = sv_read_indirect(sc, ports[idx].l_port);
998 if (cp->un.ord)
999 reg |= SV_MUTE_BIT;
1000 else
1001 reg &= ~SV_MUTE_BIT;
1002 sv_write_indirect(sc, ports[idx].l_port, reg);
1003
1004 if (ports[idx].r_port) {
1005 reg = sv_read_indirect(sc, ports[idx].r_port);
1006 if (cp->un.ord)
1007 reg |= SV_MUTE_BIT;
1008 else
1009 reg &= ~SV_MUTE_BIT;
1010 sv_write_indirect(sc, ports[idx].r_port, reg);
1011 }
1012 } else {
1013 int lval, rval;
1014
1015 if (cp->type != AUDIO_MIXER_VALUE)
1016 return (EINVAL);
1017
1018 if (cp->un.value.num_channels != 1 &&
1019 cp->un.value.num_channels != 2)
1020 return (EINVAL);
1021
1022 if (ports[idx].r_port == 0) {
1023 if (cp->un.value.num_channels != 1)
1024 return (EINVAL);
1025 lval = cp->un.value.level[AUDIO_MIXER_LEVEL_MONO];
1026 } else {
1027 if (cp->un.value.num_channels != 2)
1028 return (EINVAL);
1029
1030 lval = cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
1031 rval = cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
1032 }
1033
1034 sc->sc_trd = 1;
1035
1036 reg = sv_read_indirect(sc, ports[idx].l_port);
1037 reg &= ~(ports[idx].mask);
1038 lval = ((AUDIO_MAX_GAIN - lval) * ports[idx].mask) / AUDIO_MAX_GAIN;
1039 reg |= lval;
1040 sv_write_indirect(sc, ports[idx].l_port, reg);
1041
1042 if (ports[idx].r_port != 0) {
1043 reg = sv_read_indirect(sc, ports[idx].r_port);
1044 reg &= ~(ports[idx].mask);
1045
1046 rval = ((AUDIO_MAX_GAIN - rval) * ports[idx].mask) / AUDIO_MAX_GAIN;
1047 reg |= rval;
1048
1049 sv_write_indirect(sc, ports[idx].r_port, reg);
1050 }
1051
1052 sc->sc_trd = 0;
1053 sv_read_indirect(sc, ports[idx].l_port);
1054 }
1055
1056 return (0);
1057 }
1058
1059
1060 switch (cp->dev) {
1061 case SV_RECORD_SOURCE:
1062 if (cp->type != AUDIO_MIXER_ENUM)
1063 return (EINVAL);
1064
1065 for (idx = 0; idx < ARRAY_SIZE(record_sources); idx++) {
1066 if (record_sources[idx].idx == cp->un.ord)
1067 goto found;
1068 }
1069
1070 return (EINVAL);
1071
1072 found:
1073 reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
1074 reg &= ~SV_REC_SOURCE_MASK;
1075 reg |= (((cp->un.ord) << SV_REC_SOURCE_SHIFT) & SV_REC_SOURCE_MASK);
1076 sv_write_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL, reg);
1077
1078 reg = sv_read_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL);
1079 reg &= ~SV_REC_SOURCE_MASK;
1080 reg |= (((cp->un.ord) << SV_REC_SOURCE_SHIFT) & SV_REC_SOURCE_MASK);
1081 sv_write_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL, reg);
1082 return (0);
1083
1084 case SV_RECORD_GAIN:
1085 {
1086 int val;
1087
1088 if (cp->type != AUDIO_MIXER_VALUE)
1089 return (EINVAL);
1090
1091 if (cp->un.value.num_channels != 1)
1092 return (EINVAL);
1093
1094 val = (cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] * SV_REC_GAIN_MASK)
1095 / AUDIO_MAX_GAIN;
1096
1097 reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
1098 reg &= ~SV_REC_GAIN_MASK;
1099 reg |= val;
1100 sv_write_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL, reg);
1101
1102 reg = sv_read_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL);
1103 reg &= ~SV_REC_GAIN_MASK;
1104 reg |= val;
1105 sv_write_indirect(sc, SV_RIGHT_ADC_INPUT_CONTROL, reg);
1106
1107 }
1108
1109 return (0);
1110
1111 case SV_MIC_BOOST:
1112 if (cp->type != AUDIO_MIXER_ENUM)
1113 return (EINVAL);
1114
1115 reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
1116 if (cp->un.ord) {
1117 reg |= SV_MIC_BOOST_BIT;
1118 } else {
1119 reg &= ~SV_MIC_BOOST_BIT;
1120 }
1121
1122 sv_write_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL, reg);
1123 return (0);
1124
1125 case SV_SRS_MODE:
1126 if (cp->type != AUDIO_MIXER_ENUM)
1127 return (EINVAL);
1128
1129 reg = sv_read_indirect(sc, SV_SRS_SPACE_CONTROL);
1130 if (cp->un.ord) {
1131 reg &= ~SV_SRS_SPACE_ONOFF;
1132 } else {
1133 reg |= SV_SRS_SPACE_ONOFF;
1134 }
1135
1136 sv_write_indirect(sc, SV_SRS_SPACE_CONTROL, reg);
1137 return (0);
1138 }
1139
1140 return (EINVAL);
1141 }
1142
1143 int
sv_mixer_get_port(void * addr,mixer_ctrl_t * cp)1144 sv_mixer_get_port(void *addr, mixer_ctrl_t *cp)
1145 {
1146 struct sv_softc *sc = addr;
1147 int val;
1148 u_int8_t reg;
1149
1150 if (cp->dev >= SV_FIRST_MIXER &&
1151 cp->dev <= SV_LAST_MIXER) {
1152 int off = cp->dev - SV_FIRST_MIXER;
1153 int mute = (off % 2);
1154 int idx = off / 2;
1155
1156 if (mute) {
1157 if (cp->type != AUDIO_MIXER_ENUM)
1158 return (EINVAL);
1159
1160 reg = sv_read_indirect(sc, ports[idx].l_port);
1161 cp->un.ord = ((reg & SV_MUTE_BIT) ? 1 : 0);
1162 } else {
1163 if (cp->type != AUDIO_MIXER_VALUE)
1164 return (EINVAL);
1165
1166 if (cp->un.value.num_channels != 1 &&
1167 cp->un.value.num_channels != 2)
1168 return (EINVAL);
1169
1170 if ((ports[idx].r_port == 0 &&
1171 cp->un.value.num_channels != 1) ||
1172 (ports[idx].r_port != 0 &&
1173 cp->un.value.num_channels != 2))
1174 return (EINVAL);
1175
1176 reg = sv_read_indirect(sc, ports[idx].l_port);
1177 reg &= ports[idx].mask;
1178
1179 val = AUDIO_MAX_GAIN - ((reg * AUDIO_MAX_GAIN) / ports[idx].mask);
1180
1181 if (ports[idx].r_port != 0) {
1182 cp->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = val;
1183
1184 reg = sv_read_indirect(sc, ports[idx].r_port);
1185 reg &= ports[idx].mask;
1186
1187 val = AUDIO_MAX_GAIN - ((reg * AUDIO_MAX_GAIN) / ports[idx].mask);
1188 cp->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = val;
1189 } else
1190 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] = val;
1191 }
1192
1193 return (0);
1194 }
1195
1196 switch (cp->dev) {
1197 case SV_RECORD_SOURCE:
1198 if (cp->type != AUDIO_MIXER_ENUM)
1199 return (EINVAL);
1200
1201 reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
1202 cp->un.ord = ((reg & SV_REC_SOURCE_MASK) >> SV_REC_SOURCE_SHIFT);
1203
1204 return (0);
1205
1206 case SV_RECORD_GAIN:
1207 if (cp->type != AUDIO_MIXER_VALUE)
1208 return (EINVAL);
1209
1210 if (cp->un.value.num_channels != 1)
1211 return (EINVAL);
1212
1213 reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL) & SV_REC_GAIN_MASK;
1214 cp->un.value.level[AUDIO_MIXER_LEVEL_MONO] =
1215 (((unsigned int)reg) * AUDIO_MAX_GAIN) / SV_REC_GAIN_MASK;
1216
1217 return (0);
1218
1219 case SV_MIC_BOOST:
1220 if (cp->type != AUDIO_MIXER_ENUM)
1221 return (EINVAL);
1222
1223 reg = sv_read_indirect(sc, SV_LEFT_ADC_INPUT_CONTROL);
1224 cp->un.ord = ((reg & SV_MIC_BOOST_BIT) ? 1 : 0);
1225
1226 return (0);
1227
1228
1229 case SV_SRS_MODE:
1230 if (cp->type != AUDIO_MIXER_ENUM)
1231 return (EINVAL);
1232
1233 reg = sv_read_indirect(sc, SV_SRS_SPACE_CONTROL);
1234
1235 cp->un.ord = ((reg & SV_SRS_SPACE_ONOFF) ? 0 : 1);
1236 return (0);
1237 }
1238
1239 return (EINVAL);
1240 }
1241
1242
1243 static void
sv_init_mixer(struct sv_softc * sc)1244 sv_init_mixer(struct sv_softc *sc)
1245 {
1246 mixer_ctrl_t cp;
1247 int idx;
1248
1249 cp.type = AUDIO_MIXER_ENUM;
1250 cp.dev = SV_SRS_MODE;
1251 cp.un.ord = 0;
1252
1253 sv_mixer_set_port(sc, &cp);
1254
1255 for (idx = 0; idx < ARRAY_SIZE(ports); idx++) {
1256 if (strcmp(ports[idx].audio, AudioNdac) == 0) {
1257 cp.type = AUDIO_MIXER_ENUM;
1258 cp.dev = SV_FIRST_MIXER + idx * SV_DEVICES_PER_PORT + 1;
1259 cp.un.ord = 0;
1260 sv_mixer_set_port(sc, &cp);
1261 break;
1262 }
1263 }
1264 }
1265
1266 void *
sv_malloc(void * addr,int direction,size_t size,int pool,int flags)1267 sv_malloc(void *addr, int direction, size_t size, int pool, int flags)
1268 {
1269 struct sv_softc *sc = addr;
1270 struct sv_dma *p;
1271 int error;
1272
1273 p = malloc(sizeof(*p), pool, flags);
1274 if (!p)
1275 return (0);
1276 error = sv_allocmem(sc, size, 16, p);
1277 if (error) {
1278 free(p, pool, sizeof(*p));
1279 return (0);
1280 }
1281 p->next = sc->sc_dmas;
1282 sc->sc_dmas = p;
1283 return (KERNADDR(p));
1284 }
1285
1286 void
sv_free(void * addr,void * ptr,int pool)1287 sv_free(void *addr, void *ptr, int pool)
1288 {
1289 struct sv_softc *sc = addr;
1290 struct sv_dma **p;
1291
1292 for (p = &sc->sc_dmas; *p; p = &(*p)->next) {
1293 if (KERNADDR(*p) == ptr) {
1294 sv_freemem(sc, *p);
1295 *p = (*p)->next;
1296 free(*p, pool, sizeof(**p));
1297 return;
1298 }
1299 }
1300 }
1301