FreeBSD kernel sound device code
sb16.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1999 Cameron Grant <cg@freebsd.org>
5 * Copyright (c) 1997,1998 Luigi Rizzo
6 *
7 * Derived from files in the Voxware 3.5 distribution,
8 * Copyright by Hannu Savolainen 1994, under the same copyright
9 * conditions.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#ifdef HAVE_KERNEL_OPTION_HEADERS
35#include "opt_snd.h"
36#endif
37
38#include <dev/sound/pcm/sound.h>
39
40#include <dev/sound/isa/sb.h>
41#include <dev/sound/chip.h>
42
43#include <isa/isavar.h>
44
45#include "mixer_if.h"
46
47SND_DECLARE_FILE("$FreeBSD$");
48
49#define SB16_BUFFSIZE 4096
50#define PLAIN_SB16(x) ((((x)->bd_flags) & (BD_F_SB16|BD_F_SB16X)) == BD_F_SB16)
51
52static u_int32_t sb16_fmt8[] = {
53 SND_FORMAT(AFMT_U8, 1, 0),
54 SND_FORMAT(AFMT_U8, 2, 0),
55 0
56};
57static struct pcmchan_caps sb16_caps8 = {5000, 45000, sb16_fmt8, 0};
58
59static u_int32_t sb16_fmt16[] = {
60 SND_FORMAT(AFMT_S16_LE, 1, 0),
61 SND_FORMAT(AFMT_S16_LE, 2, 0),
62 0
63};
64static struct pcmchan_caps sb16_caps16 = {5000, 45000, sb16_fmt16, 0};
65
66static u_int32_t sb16x_fmt[] = {
67 SND_FORMAT(AFMT_U8, 1, 0),
68 SND_FORMAT(AFMT_U8, 2, 0),
69 SND_FORMAT(AFMT_S16_LE, 1, 0),
70 SND_FORMAT(AFMT_S16_LE, 2, 0),
71 0
72};
73static struct pcmchan_caps sb16x_caps = {5000, 49000, sb16x_fmt, 0};
74
75struct sb_info;
76
77struct sb_chinfo {
78 struct sb_info *parent;
81 int dir, run, dch;
82 u_int32_t fmt, spd, blksz;
83};
84
85struct sb_info {
86 struct resource *io_base; /* I/O address for the board */
87 struct resource *irq;
88 struct resource *drq1;
89 struct resource *drq2;
90 void *ih;
91 bus_dma_tag_t parent_dmat;
92
93 unsigned int bufsize;
94 int bd_id;
95 u_long bd_flags; /* board-specific flags */
97 struct sb_chinfo pch, rch;
98 device_t parent_dev;
99};
100
101#if 0
102static void sb_lock(struct sb_info *sb);
103static void sb_unlock(struct sb_info *sb);
104static int sb_rd(struct sb_info *sb, int reg);
105static void sb_wr(struct sb_info *sb, int reg, u_int8_t val);
106static int sb_cmd(struct sb_info *sb, u_char val);
107/* static int sb_cmd1(struct sb_info *sb, u_char cmd, int val); */
108static int sb_cmd2(struct sb_info *sb, u_char cmd, int val);
109static u_int sb_get_byte(struct sb_info *sb);
110static void sb_setmixer(struct sb_info *sb, u_int port, u_int value);
111static int sb_getmixer(struct sb_info *sb, u_int port);
112static int sb_reset_dsp(struct sb_info *sb);
113
114static void sb_intr(void *arg);
115#endif
116
117/*
118 * Common code for the midi and pcm functions
119 *
120 * sb_cmd write a single byte to the CMD port.
121 * sb_cmd1 write a CMD + 1 byte arg
122 * sb_cmd2 write a CMD + 2 byte arg
123 * sb_get_byte returns a single byte from the DSP data port
124 */
125
126static void
127sb_lock(struct sb_info *sb) {
128 sbc_lock(device_get_softc(sb->parent_dev));
129}
130
131static void
133 sbc_lockassert(device_get_softc(sb->parent_dev));
134}
135
136static void
137sb_unlock(struct sb_info *sb) {
138 sbc_unlock(device_get_softc(sb->parent_dev));
139}
140
141static int
142port_rd(struct resource *port, int off)
143{
144 return bus_space_read_1(rman_get_bustag(port), rman_get_bushandle(port), off);
145}
146
147static void
148port_wr(struct resource *port, int off, u_int8_t data)
149{
150 bus_space_write_1(rman_get_bustag(port), rman_get_bushandle(port), off, data);
151}
152
153static int
154sb_rd(struct sb_info *sb, int reg)
155{
156 return port_rd(sb->io_base, reg);
157}
158
159static void
160sb_wr(struct sb_info *sb, int reg, u_int8_t val)
161{
162 port_wr(sb->io_base, reg, val);
163}
164
165static int
166sb_dspwr(struct sb_info *sb, u_char val)
167{
168 int i;
169
170 for (i = 0; i < 1000; i++) {
171 if ((sb_rd(sb, SBDSP_STATUS) & 0x80))
172 DELAY((i > 100)? 1000 : 10);
173 else {
174 sb_wr(sb, SBDSP_CMD, val);
175 return 1;
176 }
177 }
178 if (curthread->td_intr_nesting_level == 0)
179 printf("sb_dspwr(0x%02x) timed out.\n", val);
180 return 0;
181}
182
183static int
184sb_cmd(struct sb_info *sb, u_char val)
185{
186#if 0
187 printf("sb_cmd: %x\n", val);
188#endif
189 return sb_dspwr(sb, val);
190}
191
192/*
193static int
194sb_cmd1(struct sb_info *sb, u_char cmd, int val)
195{
196#if 0
197 printf("sb_cmd1: %x, %x\n", cmd, val);
198#endif
199 if (sb_dspwr(sb, cmd)) {
200 return sb_dspwr(sb, val & 0xff);
201 } else return 0;
202}
203*/
204
205static int
206sb_cmd2(struct sb_info *sb, u_char cmd, int val)
207{
208 int r;
209
210#if 0
211 printf("sb_cmd2: %x, %x\n", cmd, val);
212#endif
213 sb_lockassert(sb);
214 r = 0;
215 if (sb_dspwr(sb, cmd)) {
216 if (sb_dspwr(sb, val & 0xff)) {
217 if (sb_dspwr(sb, (val >> 8) & 0xff)) {
218 r = 1;
219 }
220 }
221 }
222
223 return r;
224}
225
226/*
227 * in the SB, there is a set of indirect "mixer" registers with
228 * address at offset 4, data at offset 5
229 */
230static void
231sb_setmixer(struct sb_info *sb, u_int port, u_int value)
232{
233 sb_lock(sb);
234 sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
235 DELAY(10);
236 sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff));
237 DELAY(10);
238 sb_unlock(sb);
239}
240
241static int
242sb_getmixer(struct sb_info *sb, u_int port)
243{
244 int val;
245
246 sb_lockassert(sb);
247 sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */
248 DELAY(10);
249 val = sb_rd(sb, SB_MIX_DATA);
250 DELAY(10);
251
252 return val;
253}
254
255static u_int
257{
258 int i;
259
260 for (i = 1000; i > 0; i--) {
261 if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80)
262 return sb_rd(sb, DSP_READ);
263 else
264 DELAY(20);
265 }
266 return 0xffff;
267}
268
269static int
271{
272 u_char b;
273
274 sb_lockassert(sb);
275 sb_wr(sb, SBDSP_RST, 3);
276 DELAY(100);
277 sb_wr(sb, SBDSP_RST, 0);
278 b = sb_get_byte(sb);
279 if (b != 0xAA) {
280 DEB(printf("sb_reset_dsp 0x%lx failed\n",
281 rman_get_start(sb->io_base)));
282 return ENXIO; /* Sorry */
283 }
284 return 0;
285}
286
287/************************************************************/
288
290 int reg;
291 int bits;
292 int ofs;
294};
295
296static const struct sb16_mixent sb16_mixtab[32] = {
297 [SOUND_MIXER_VOLUME] = { 0x30, 5, 3, 1 },
298 [SOUND_MIXER_PCM] = { 0x32, 5, 3, 1 },
299 [SOUND_MIXER_SYNTH] = { 0x34, 5, 3, 1 },
300 [SOUND_MIXER_CD] = { 0x36, 5, 3, 1 },
301 [SOUND_MIXER_LINE] = { 0x38, 5, 3, 1 },
302 [SOUND_MIXER_MIC] = { 0x3a, 5, 3, 0 },
303 [SOUND_MIXER_SPEAKER] = { 0x3b, 5, 3, 0 },
304 [SOUND_MIXER_IGAIN] = { 0x3f, 2, 6, 1 },
305 [SOUND_MIXER_OGAIN] = { 0x41, 2, 6, 1 },
306 [SOUND_MIXER_TREBLE] = { 0x44, 4, 4, 1 },
307 [SOUND_MIXER_BASS] = { 0x46, 4, 4, 1 },
308 [SOUND_MIXER_LINE1] = { 0x52, 5, 3, 1 }
309};
310
311static int
313{
314 struct sb_info *sb = mix_getdevinfo(m);
315
316 mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER |
317 SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD |
318 SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
319 SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE);
320
321 mix_setrecdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_LINE |
322 SOUND_MASK_LINE1 | SOUND_MASK_MIC | SOUND_MASK_CD);
323
324 sb_setmixer(sb, 0x3c, 0x1f); /* make all output active */
325
326 sb_setmixer(sb, 0x3d, 0); /* make all inputs-l off */
327 sb_setmixer(sb, 0x3e, 0); /* make all inputs-r off */
328
329 return 0;
330}
331
332static int
334{
335 int temp;
336
337 temp = ((x * max) + 50) / 100;
338 if (temp > max)
339 temp = max;
340 else if (temp < 0)
341 temp = 0;
342 return (temp);
343}
344
345static int
346sb16mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
347{
348 struct sb_info *sb = mix_getdevinfo(m);
349 const struct sb16_mixent *e;
350 int max;
351
352 e = &sb16_mixtab[dev];
353 max = (1 << e->bits) - 1;
354
357
358 sb_setmixer(sb, e->reg, left << e->ofs);
359 if (e->stereo)
360 sb_setmixer(sb, e->reg + 1, right << e->ofs);
361 else
362 right = left;
363
364 left = (left * 100) / max;
365 right = (right * 100) / max;
366
367 return left | (right << 8);
368}
369
370static u_int32_t
371sb16mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
372{
373 struct sb_info *sb = mix_getdevinfo(m);
374 u_char recdev_l, recdev_r;
375
376 recdev_l = 0;
377 recdev_r = 0;
378 if (src & SOUND_MASK_MIC) {
379 recdev_l |= 0x01; /* mono mic */
380 recdev_r |= 0x01;
381 }
382
383 if (src & SOUND_MASK_CD) {
384 recdev_l |= 0x04; /* l cd */
385 recdev_r |= 0x02; /* r cd */
386 }
387
388 if (src & SOUND_MASK_LINE) {
389 recdev_l |= 0x10; /* l line */
390 recdev_r |= 0x08; /* r line */
391 }
392
393 if (src & SOUND_MASK_SYNTH) {
394 recdev_l |= 0x40; /* l midi */
395 recdev_r |= 0x20; /* r midi */
396 }
397
398 sb_setmixer(sb, SB16_IMASK_L, recdev_l);
399 sb_setmixer(sb, SB16_IMASK_R, recdev_r);
400
401 /* Switch on/off FM tuner source */
402 if (src & SOUND_MASK_LINE1)
403 sb_setmixer(sb, 0x4a, 0x0c);
404 else
405 sb_setmixer(sb, 0x4a, 0x00);
406
407 /*
408 * since the same volume controls apply to the input and
409 * output sections, the best approach to have a consistent
410 * behaviour among cards would be to disable the output path
411 * on devices which are used to record.
412 * However, since users like to have feedback, we only disable
413 * the mic -- permanently.
414 */
415 sb_setmixer(sb, SB16_OMASK, 0x1f & ~1);
416
417 return src;
418}
419
420static kobj_method_t sb16mix_mixer_methods[] = {
421 KOBJMETHOD(mixer_init, sb16mix_init),
422 KOBJMETHOD(mixer_set, sb16mix_set),
425};
426MIXER_DECLARE(sb16mix_mixer);
427
428/************************************************************/
429
430static void
431sb16_release_resources(struct sb_info *sb, device_t dev)
432{
433 if (sb->irq) {
434 if (sb->ih)
435 bus_teardown_intr(dev, sb->irq, sb->ih);
436 bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq);
437 sb->irq = NULL;
438 }
439 if (sb->drq2) {
440 if (sb->drq2 != sb->drq1) {
441 isa_dma_release(rman_get_start(sb->drq2));
442 bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2);
443 }
444 sb->drq2 = NULL;
445 }
446 if (sb->drq1) {
447 isa_dma_release(rman_get_start(sb->drq1));
448 bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1);
449 sb->drq1 = NULL;
450 }
451 if (sb->io_base) {
452 bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base);
453 sb->io_base = NULL;
454 }
455 if (sb->parent_dmat) {
456 bus_dma_tag_destroy(sb->parent_dmat);
457 sb->parent_dmat = 0;
458 }
459 free(sb, M_DEVBUF);
460}
461
462static int
463sb16_alloc_resources(struct sb_info *sb, device_t dev)
464{
465 int rid;
466
467 rid = 0;
468 if (!sb->io_base)
469 sb->io_base = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
470 &rid, RF_ACTIVE);
471
472 rid = 0;
473 if (!sb->irq)
474 sb->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
475 RF_ACTIVE);
476
477 rid = 0;
478 if (!sb->drq1)
479 sb->drq1 = bus_alloc_resource_any(dev, SYS_RES_DRQ, &rid,
480 RF_ACTIVE);
481
482 rid = 1;
483 if (!sb->drq2)
484 sb->drq2 = bus_alloc_resource_any(dev, SYS_RES_DRQ, &rid,
485 RF_ACTIVE);
486
487 if (sb->io_base && sb->drq1 && sb->irq) {
488 isa_dma_acquire(rman_get_start(sb->drq1));
489 isa_dmainit(rman_get_start(sb->drq1), sb->bufsize);
490
491 if (sb->drq2) {
492 isa_dma_acquire(rman_get_start(sb->drq2));
493 isa_dmainit(rman_get_start(sb->drq2), sb->bufsize);
494 } else {
495 sb->drq2 = sb->drq1;
497 }
498 return 0;
499 } else return ENXIO;
500}
501
502/* sbc does locking for us */
503static void
504sb_intr(void *arg)
505{
506 struct sb_info *sb = (struct sb_info *)arg;
507 int reason, c;
508
509 /*
510 * The Vibra16X has separate flags for 8 and 16 bit transfers, but
511 * I have no idea how to tell capture from playback interrupts...
512 */
513
514 reason = 0;
515 sb_lock(sb);
516 c = sb_getmixer(sb, IRQ_STAT);
517 if (c & 1)
518 sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */
519
520 if (c & 2)
521 sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */
522 sb_unlock(sb);
523
524 /*
525 * this tells us if the source is 8-bit or 16-bit dma. We
526 * have to check the io channel to map it to read or write...
527 */
528
529 if (sb->bd_flags & BD_F_SB16X) {
530 if (c & 1) { /* 8-bit format */
531 if (sb->pch.fmt & AFMT_8BIT)
532 reason |= 1;
533 if (sb->rch.fmt & AFMT_8BIT)
534 reason |= 2;
535 }
536 if (c & 2) { /* 16-bit format */
537 if (sb->pch.fmt & AFMT_16BIT)
538 reason |= 1;
539 if (sb->rch.fmt & AFMT_16BIT)
540 reason |= 2;
541 }
542 } else {
543 if (c & 1) { /* 8-bit dma */
544 if (sb->pch.dch == 1)
545 reason |= 1;
546 if (sb->rch.dch == 1)
547 reason |= 2;
548 }
549 if (c & 2) { /* 16-bit dma */
550 if (sb->pch.dch == 2)
551 reason |= 1;
552 if (sb->rch.dch == 2)
553 reason |= 2;
554 }
555 }
556#if 0
557 printf("sb_intr: reason=%d c=0x%x\n", reason, c);
558#endif
559 if ((reason & 1) && (sb->pch.run))
560 chn_intr(sb->pch.channel);
561
562 if ((reason & 2) && (sb->rch.run))
563 chn_intr(sb->rch.channel);
564}
565
566static int
567sb_setup(struct sb_info *sb)
568{
569 struct sb_chinfo *ch;
570 u_int8_t v;
571 int l, pprio;
572
573 sb_lock(sb);
574 if (sb->bd_flags & BD_F_DMARUN)
575 sndbuf_dma(sb->pch.buffer, PCMTRIG_STOP);
576 if (sb->bd_flags & BD_F_DMARUN2)
579
580 sb_reset_dsp(sb);
581
582 if (sb->bd_flags & BD_F_SB16X) {
583 /* full-duplex doesn't work! */
584 pprio = sb->pch.run? 1 : 0;
585 sndbuf_dmasetup(sb->pch.buffer, pprio? sb->drq1 : sb->drq2);
586 sb->pch.dch = pprio? 1 : 0;
587 sndbuf_dmasetup(sb->rch.buffer, pprio? sb->drq2 : sb->drq1);
588 sb->rch.dch = pprio? 2 : 1;
589 } else {
590 if (sb->pch.run && sb->rch.run) {
591 pprio = (sb->rch.fmt & AFMT_16BIT)? 0 : 1;
592 sndbuf_dmasetup(sb->pch.buffer, pprio? sb->drq2 : sb->drq1);
593 sb->pch.dch = pprio? 2 : 1;
594 sndbuf_dmasetup(sb->rch.buffer, pprio? sb->drq1 : sb->drq2);
595 sb->rch.dch = pprio? 1 : 2;
596 } else {
597 if (sb->pch.run) {
598 sndbuf_dmasetup(sb->pch.buffer, (sb->pch.fmt & AFMT_16BIT)? sb->drq2 : sb->drq1);
599 sb->pch.dch = (sb->pch.fmt & AFMT_16BIT)? 2 : 1;
600 sndbuf_dmasetup(sb->rch.buffer, (sb->pch.fmt & AFMT_16BIT)? sb->drq1 : sb->drq2);
601 sb->rch.dch = (sb->pch.fmt & AFMT_16BIT)? 1 : 2;
602 } else if (sb->rch.run) {
603 sndbuf_dmasetup(sb->pch.buffer, (sb->rch.fmt & AFMT_16BIT)? sb->drq1 : sb->drq2);
604 sb->pch.dch = (sb->rch.fmt & AFMT_16BIT)? 1 : 2;
605 sndbuf_dmasetup(sb->rch.buffer, (sb->rch.fmt & AFMT_16BIT)? sb->drq2 : sb->drq1);
606 sb->rch.dch = (sb->rch.fmt & AFMT_16BIT)? 2 : 1;
607 }
608 }
609 }
610
611 sndbuf_dmasetdir(sb->pch.buffer, PCMDIR_PLAY);
613
614 /*
615 printf("setup: [pch = %d, pfmt = %d, pgo = %d] [rch = %d, rfmt = %d, rgo = %d]\n",
616 sb->pch.dch, sb->pch.fmt, sb->pch.run, sb->rch.dch, sb->rch.fmt, sb->rch.run);
617 */
618
619 ch = &sb->pch;
620 if (ch->run) {
621 l = ch->blksz;
622 if (ch->fmt & AFMT_16BIT)
623 l >>= 1;
624 l--;
625
626 /* play speed */
627 RANGE(ch->spd, 5000, 45000);
629 sb_cmd(sb, ch->spd >> 8);
630 sb_cmd(sb, ch->spd & 0xff);
631
632 /* play format, length */
634 v |= (ch->fmt & AFMT_16BIT)? DSP_DMA16 : DSP_DMA8;
635 sb_cmd(sb, v);
636
637 v = (AFMT_CHANNEL(ch->fmt) > 1)? DSP_F16_STEREO : 0;
638 v |= (ch->fmt & AFMT_SIGNED)? DSP_F16_SIGNED : 0;
639 sb_cmd2(sb, v, l);
641 sb->bd_flags |= BD_F_DMARUN;
642 }
643
644 ch = &sb->rch;
645 if (ch->run) {
646 l = ch->blksz;
647 if (ch->fmt & AFMT_16BIT)
648 l >>= 1;
649 l--;
650
651 /* record speed */
652 RANGE(ch->spd, 5000, 45000);
653 sb_cmd(sb, DSP_CMD_IN16);
654 sb_cmd(sb, ch->spd >> 8);
655 sb_cmd(sb, ch->spd & 0xff);
656
657 /* record format, length */
659 v |= (ch->fmt & AFMT_16BIT)? DSP_DMA16 : DSP_DMA8;
660 sb_cmd(sb, v);
661
662 v = (AFMT_CHANNEL(ch->fmt) > 1)? DSP_F16_STEREO : 0;
663 v |= (ch->fmt & AFMT_SIGNED)? DSP_F16_SIGNED : 0;
664 sb_cmd2(sb, v, l);
666 sb->bd_flags |= BD_F_DMARUN2;
667 }
668 sb_unlock(sb);
669
670 return 0;
671}
672
673/* channel interface */
674static void *
675sb16chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
676{
677 struct sb_info *sb = devinfo;
678 struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch;
679
680 ch->parent = sb;
681 ch->channel = c;
682 ch->buffer = b;
683 ch->dir = dir;
684
685 if (sndbuf_alloc(ch->buffer, sb->parent_dmat, 0, sb->bufsize) != 0)
686 return NULL;
687
688 return ch;
689}
690
691static int
692sb16chan_setformat(kobj_t obj, void *data, u_int32_t format)
693{
694 struct sb_chinfo *ch = data;
695 struct sb_info *sb = ch->parent;
696
697 ch->fmt = format;
698 sb->prio = ch->dir;
699 sb->prio16 = (ch->fmt & AFMT_16BIT)? 1 : 0;
700
701 return 0;
702}
703
704static u_int32_t
705sb16chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
706{
707 struct sb_chinfo *ch = data;
708
709 ch->spd = speed;
710 return speed;
711}
712
713static u_int32_t
714sb16chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
715{
716 struct sb_chinfo *ch = data;
717
718 ch->blksz = blocksize;
719 return ch->blksz;
720}
721
722static int
723sb16chan_trigger(kobj_t obj, void *data, int go)
724{
725 struct sb_chinfo *ch = data;
726 struct sb_info *sb = ch->parent;
727
728 if (!PCMTRIG_COMMON(go))
729 return 0;
730
731 if (go == PCMTRIG_START)
732 ch->run = 1;
733 else
734 ch->run = 0;
735
736 sb_setup(sb);
737
738 return 0;
739}
740
741static u_int32_t
742sb16chan_getptr(kobj_t obj, void *data)
743{
744 struct sb_chinfo *ch = data;
745
746 return sndbuf_dmaptr(ch->buffer);
747}
748
749static struct pcmchan_caps *
750sb16chan_getcaps(kobj_t obj, void *data)
751{
752 struct sb_chinfo *ch = data;
753 struct sb_info *sb = ch->parent;
754
755 if ((sb->prio == 0) || (sb->prio == ch->dir))
756 return &sb16x_caps;
757 else
758 return sb->prio16? &sb16_caps8 : &sb16_caps16;
759}
760
761static int
762sb16chan_resetdone(kobj_t obj, void *data)
763{
764 struct sb_chinfo *ch = data;
765 struct sb_info *sb = ch->parent;
766
767 sb->prio = 0;
768
769 return 0;
770}
771
772static kobj_method_t sb16chan_methods[] = {
773 KOBJMETHOD(channel_init, sb16chan_init),
774 KOBJMETHOD(channel_resetdone, sb16chan_resetdone),
775 KOBJMETHOD(channel_setformat, sb16chan_setformat),
776 KOBJMETHOD(channel_setspeed, sb16chan_setspeed),
777 KOBJMETHOD(channel_setblocksize, sb16chan_setblocksize),
778 KOBJMETHOD(channel_trigger, sb16chan_trigger),
779 KOBJMETHOD(channel_getptr, sb16chan_getptr),
780 KOBJMETHOD(channel_getcaps, sb16chan_getcaps),
782};
784
785/************************************************************/
786
787static int
789{
790 char buf[64];
791 uintptr_t func, ver, r, f;
792
793 /* The parent device has already been probed. */
794 r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func);
795 if (func != SCF_PCM)
796 return (ENXIO);
797
798 r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
799 f = (ver & 0xffff0000) >> 16;
800 ver &= 0x0000ffff;
801 if (f & BD_F_SB16) {
802 snprintf(buf, sizeof buf, "SB16 DSP %d.%02d%s", (int) ver >> 8, (int) ver & 0xff,
803 (f & BD_F_SB16X)? " (ViBRA16X)" : "");
804 device_set_desc_copy(dev, buf);
805 return 0;
806 } else
807 return (ENXIO);
808}
809
810static int
812{
813 struct sb_info *sb;
814 uintptr_t ver;
815 char status[SND_STATUSLEN], status2[SND_STATUSLEN];
816
817 gone_in_dev(dev, 14, "ISA sound driver");
818 sb = malloc(sizeof(*sb), M_DEVBUF, M_WAITOK | M_ZERO);
819 sb->parent_dev = device_get_parent(dev);
820 BUS_READ_IVAR(sb->parent_dev, dev, 1, &ver);
821 sb->bd_id = ver & 0x0000ffff;
822 sb->bd_flags = (ver & 0xffff0000) >> 16;
823 sb->bufsize = pcm_getbuffersize(dev, 4096, SB16_BUFFSIZE, 65536);
824
825 if (sb16_alloc_resources(sb, dev))
826 goto no;
827 sb_lock(sb);
828 if (sb_reset_dsp(sb)) {
829 sb_unlock(sb);
830 goto no;
831 }
832 sb_unlock(sb);
833 if (mixer_init(dev, &sb16mix_mixer_class, sb))
834 goto no;
835 if (snd_setup_intr(dev, sb->irq, 0, sb_intr, sb, &sb->ih))
836 goto no;
837
838 if (sb->bd_flags & BD_F_SB16X)
840
841 sb->prio = 0;
842
843 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2,
844 /*boundary*/0,
845 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
846 /*highaddr*/BUS_SPACE_MAXADDR,
847 /*filter*/NULL, /*filterarg*/NULL,
848 /*maxsize*/sb->bufsize, /*nsegments*/1,
849 /*maxsegz*/0x3ffff, /*flags*/0,
850 /*lockfunc*/NULL, /*lockarg*/NULL,
851 &sb->parent_dmat) != 0) {
852 device_printf(dev, "unable to create dma tag\n");
853 goto no;
854 }
855
856 if (!(pcm_getflags(dev) & SD_F_SIMPLEX))
857 snprintf(status2, SND_STATUSLEN, ":%jd", rman_get_start(sb->drq2));
858 else
859 status2[0] = '\0';
860
861 snprintf(status, SND_STATUSLEN, "at io 0x%jx irq %jd drq %jd%s bufsz %u %s",
862 rman_get_start(sb->io_base), rman_get_start(sb->irq),
863 rman_get_start(sb->drq1), status2, sb->bufsize,
864 PCM_KLDSTRING(snd_sb16));
865
866 if (pcm_register(dev, sb, 1, 1))
867 goto no;
868 pcm_addchan(dev, PCMDIR_REC, &sb16chan_class, sb);
869 pcm_addchan(dev, PCMDIR_PLAY, &sb16chan_class, sb);
870
872
873 return 0;
874
875no:
877 return ENXIO;
878}
879
880static int
882{
883 int r;
884 struct sb_info *sb;
885
887 if (r)
888 return r;
889
890 sb = pcm_getdevinfo(dev);
892 return 0;
893}
894
895static device_method_t sb16_methods[] = {
896 /* Device interface */
897 DEVMETHOD(device_probe, sb16_probe),
898 DEVMETHOD(device_attach, sb16_attach),
899 DEVMETHOD(device_detach, sb16_detach),
900 { 0, 0 }
901};
902
903static driver_t sb16_driver = {
904 "pcm",
907};
908
911MODULE_DEPEND(snd_sb16, snd_sbc, 1, 1, 1);
912MODULE_VERSION(snd_sb16, 1);
u_int32_t data
Definition: ac97_if.m:60
void * devinfo
Definition: ac97_if.m:47
#define DEB(x)
Definition: als4000.c:56
uint32_t format
Definition: audio_dai_if.m:39
uint32_t speed
Definition: audio_dai_if.m:86
int go
Definition: audio_dai_if.m:64
int sndbuf_alloc(struct snd_dbuf *b, bus_dma_tag_t dmatag, int dmaflags, unsigned int size)
Definition: buffer.c:93
void chn_intr(struct pcm_channel *c)
Definition: channel.c:660
#define PCMDIR_PLAY
Definition: channel.h:339
#define PCMTRIG_START
Definition: channel.h:344
#define PCMTRIG_STOP
Definition: channel.h:347
#define PCMDIR_REC
Definition: channel.h:341
#define PCMTRIG_COMMON(x)
Definition: channel.h:350
struct pcm_channel * c
Definition: channel_if.m:106
METHOD int free
Definition: channel_if.m:110
u_int32_t blocksize
Definition: channel_if.m:140
struct pcmchan_matrix * m
Definition: channel_if.m:232
struct snd_dbuf * b
Definition: channel_if.m:105
@ SCF_PCM
Definition: chip.h:36
int max
Definition: dsp.c:392
unsigned right
Definition: es137x.c:261
unsigned left
Definition: es137x.c:260
uint32_t value
Definition: hdaa.c:58
uint8_t reg
Definition: hdac.c:211
int dir
Definition: hdac_if.m:45
bus_addr_t buf
Definition: hdac_if.m:63
uint8_t r
#define KOBJMETHOD_END
Definition: midi.c:76
static int mixer_setrecsrc(struct snd_mixer *mixer, u_int32_t src)
Definition: mixer.c:373
int mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
Definition: mixer.c:725
static int mixer_set(struct snd_mixer *m, u_int dev, u_int32_t muted, u_int lev)
Definition: mixer.c:247
void mix_setdevs(struct snd_mixer *m, u_int32_t v)
Definition: mixer.c:489
void * mix_getdevinfo(struct snd_mixer *m)
Definition: mixer.c:645
void mix_setrecdevs(struct snd_mixer *m, u_int32_t v)
Record mask of available recording devices.
Definition: mixer.c:529
unsigned dev
Definition: mixer_if.m:59
u_int32_t src
Definition: mixer_if.m:66
bool * status
uint16_t rid
u_int32_t val
u_int func
static int sb_reset_dsp(struct sb_info *sb)
Definition: sb16.c:270
MODULE_DEPEND(snd_sb16, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER)
static void sb_intr(void *arg)
Definition: sb16.c:504
CHANNEL_DECLARE(sb16chan)
static int rel2abs_volume(int x, int max)
Definition: sb16.c:333
static void sb_lock(struct sb_info *sb)
Definition: sb16.c:127
static device_method_t sb16_methods[]
Definition: sb16.c:895
static int port_rd(struct resource *port, int off)
Definition: sb16.c:142
static u_int32_t sb16chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
Definition: sb16.c:714
static int sb16mix_init(struct snd_mixer *m)
Definition: sb16.c:312
static u_int sb_get_byte(struct sb_info *sb)
Definition: sb16.c:256
#define SB16_BUFFSIZE
Definition: sb16.c:49
static int sb16mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right)
Definition: sb16.c:346
static struct pcmchan_caps sb16_caps8
Definition: sb16.c:57
static int sb16chan_setformat(kobj_t obj, void *data, u_int32_t format)
Definition: sb16.c:692
static u_int32_t sb16_fmt16[]
Definition: sb16.c:59
static const struct sb16_mixent sb16_mixtab[32]
Definition: sb16.c:296
static void sb_setmixer(struct sb_info *sb, u_int port, u_int value)
Definition: sb16.c:231
static void sb_wr(struct sb_info *sb, int reg, u_int8_t val)
Definition: sb16.c:160
static int sb16chan_trigger(kobj_t obj, void *data, int go)
Definition: sb16.c:723
static int sb_cmd2(struct sb_info *sb, u_char cmd, int val)
Definition: sb16.c:206
SND_DECLARE_FILE("$FreeBSD$")
static kobj_method_t sb16chan_methods[]
Definition: sb16.c:772
static u_int32_t sb16chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
Definition: sb16.c:705
static void port_wr(struct resource *port, int off, u_int8_t data)
Definition: sb16.c:148
static int sb16_attach(device_t dev)
Definition: sb16.c:811
static u_int32_t sb16chan_getptr(kobj_t obj, void *data)
Definition: sb16.c:742
static int sb_getmixer(struct sb_info *sb, u_int port)
Definition: sb16.c:242
static int sb_cmd(struct sb_info *sb, u_char val)
Definition: sb16.c:184
static u_int32_t sb16_fmt8[]
Definition: sb16.c:52
static kobj_method_t sb16mix_mixer_methods[]
Definition: sb16.c:420
static int sb16_detach(device_t dev)
Definition: sb16.c:881
static u_int32_t sb16x_fmt[]
Definition: sb16.c:66
static int sb16_alloc_resources(struct sb_info *sb, device_t dev)
Definition: sb16.c:463
static int sb_rd(struct sb_info *sb, int reg)
Definition: sb16.c:154
static struct pcmchan_caps * sb16chan_getcaps(kobj_t obj, void *data)
Definition: sb16.c:750
static void sb_lockassert(struct sb_info *sb)
Definition: sb16.c:132
static struct pcmchan_caps sb16_caps16
Definition: sb16.c:64
static int sb16_probe(device_t dev)
Definition: sb16.c:788
static int sb_setup(struct sb_info *sb)
Definition: sb16.c:567
static driver_t sb16_driver
Definition: sb16.c:903
static void sb_unlock(struct sb_info *sb)
Definition: sb16.c:137
static void * sb16chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir)
Definition: sb16.c:675
static u_int32_t sb16mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
Definition: sb16.c:371
static int sb_dspwr(struct sb_info *sb, u_char val)
Definition: sb16.c:166
MIXER_DECLARE(sb16mix_mixer)
DRIVER_MODULE(snd_sb16, sbc, sb16_driver, pcm_devclass, 0, 0)
static int sb16chan_resetdone(kobj_t obj, void *data)
Definition: sb16.c:762
static struct pcmchan_caps sb16x_caps
Definition: sb16.c:73
static void sb16_release_resources(struct sb_info *sb, device_t dev)
Definition: sb16.c:431
MODULE_VERSION(snd_sb16, 1)
#define DSP_DMA8
Definition: sb.h:131
#define BD_F_DMARUN2
Definition: sb.h:176
void sbc_unlock(struct sbc_softc *)
Definition: sbc.c:136
#define DSP_CMD_OUT16
Definition: sb.h:115
#define DSP_READ
Definition: sb.h:44
void sbc_lock(struct sbc_softc *)
Definition: sbc.c:124
#define SBDSP_RST
Definition: sb.h:43
#define SB_MIX_ADDR
Definition: sb.h:51
#define DSP_CMD_IN16
Definition: sb.h:116
#define SB16_OMASK
Definition: sb.h:215
#define BD_F_SB16
Definition: sb.h:169
#define DSP_F16_ADC
Definition: sb.h:133
#define DSP_F16_AUTO
Definition: sb.h:134
#define SBDSP_STATUS
Definition: sb.h:47
void sbc_lockassert(struct sbc_softc *)
Definition: sbc.c:130
#define BD_F_SB16X
Definition: sb.h:170
#define DSP_DMA16
Definition: sb.h:130
#define DSP_F16_FIFO_ON
Definition: sb.h:135
#define BD_F_DMARUN
Definition: sb.h:175
#define SBDSP_CMD
Definition: sb.h:46
#define SB_MIX_DATA
Definition: sb.h:52
#define DSP_F16_DAC
Definition: sb.h:132
#define DSP_DATA_AVL16
Definition: sb.h:49
#define DSP_F16_STEREO
Definition: sb.h:140
#define DSP_DATA_AVAIL
Definition: sb.h:48
#define SB16_IMASK_L
Definition: sb.h:213
#define DSP_F16_SIGNED
Definition: sb.h:141
#define SB16_IMASK_R
Definition: sb.h:214
#define IRQ_STAT
Definition: sb.h:193
#define RANGE(var, low, high)
Definition: sequencer.h:45
int sndbuf_dmasetup(struct snd_dbuf *b, struct resource *drq)
Definition: sndbuf_dma.c:40
void sndbuf_dma(struct snd_dbuf *b, int go)
Definition: sndbuf_dma.c:63
int sndbuf_dmaptr(struct snd_dbuf *b)
Definition: sndbuf_dma.c:88
int sndbuf_dmasetdir(struct snd_dbuf *b, int dir)
Definition: sndbuf_dma.c:53
void pcm_setflags(device_t dev, uint32_t val)
Definition: sound.c:824
void * pcm_getdevinfo(device_t dev)
Definition: sound.c:832
uint32_t pcm_getflags(device_t dev)
Definition: sound.c:816
int pcm_setstatus(device_t dev, char *str)
Definition: sound.c:766
devclass_t pcm_devclass
Definition: sound.c:49
int pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo)
Definition: sound.c:692
int pcm_unregister(device_t dev)
Definition: sound.c:1170
int pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
Definition: sound.c:1080
int snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep)
Definition: sound.c:117
unsigned int pcm_getbuffersize(device_t dev, unsigned int minbufsz, unsigned int deflt, unsigned int maxbufsz)
Definition: sound.c:840
#define PCM_KLDSTRING(a)
Definition: sound.h:619
#define SND_FORMAT(f, c, e)
Definition: sound.h:238
#define SOUND_PREFVER
Definition: sound.h:103
#define SOUND_MAXVER
Definition: sound.h:104
#define AFMT_CHANNEL(v)
Definition: sound.h:227
#define SD_F_SIMPLEX
Definition: sound.h:132
#define AFMT_8BIT
Definition: sound.h:193
#define SOUND_MINVER
Definition: sound.h:102
#define PCM_SOFTC_SIZE
Definition: sound.h:96
#define AFMT_SIGNED
Definition: sound.h:194
#define SND_STATUSLEN
Definition: sound.h:98
#define AFMT_16BIT
Definition: sound.h:191
int stereo
Definition: sb16.c:293
int reg
Definition: sb16.c:290
int ofs
Definition: sb16.c:292
int bits
Definition: sb16.c:291
Definition: sb16.c:77
int run
Definition: sb16.c:81
int dir
Definition: sb16.c:81
struct pcm_channel * channel
Definition: sb16.c:79
u_int32_t fmt
Definition: sb16.c:82
int dch
Definition: sb16.c:81
u_int32_t spd
Definition: sb16.c:82
struct sb_info * parent
Definition: sb16.c:78
u_int32_t blksz
Definition: sb16.c:82
struct snd_dbuf * buffer
Definition: sb16.c:80
Definition: sb16.c:85
unsigned int bufsize
Definition: sb16.c:93
struct resource * drq1
Definition: sb16.c:88
int prio
Definition: sb16.c:96
struct resource * io_base
Definition: sb16.c:86
bus_dma_tag_t parent_dmat
Definition: sb16.c:91
struct sb_chinfo pch rch
Definition: sb16.c:97
void * ih
Definition: sb16.c:90
int bd_id
Definition: sb16.c:94
u_long bd_flags
Definition: sb16.c:95
int prio16
Definition: sb16.c:96
device_t parent_dev
Definition: sb16.c:98
struct resource * drq2
Definition: sb16.c:89
struct resource * irq
Definition: sb16.c:87