Deleted Added
sdiff udiff text old ( 54237 ) new ( 54462 )
full compact
1/*
2 * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
3 * Copyright 1997,1998 Luigi Rizzo.
4 *
5 * Derived from files in the Voxware 3.5 distribution,
6 * Copyright by Hannu Savolainen 1994, under the same copyright
7 * conditions.
8 * All rights reserved.

--- 14 unchanged lines hidden (view full) ---

23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * $FreeBSD: head/sys/dev/sound/isa/sb16.c 54462 1999-12-12 02:30:19Z cg $
32 */
33
34#include <dev/sound/pcm/sound.h>
35
36#include "sbc.h"
37
38#define __SB_MIXER_C__ /* XXX warning... */
39#include <dev/sound/isa/sb.h>

--- 15 unchanged lines hidden (view full) ---

55#endif
56static int esschan_setdir(void *data, int dir);
57static int esschan_setformat(void *data, u_int32_t format);
58static int esschan_setspeed(void *data, u_int32_t speed);
59static int esschan_setblocksize(void *data, u_int32_t blocksize);
60static int esschan_trigger(void *data, int go);
61static int esschan_getptr(void *data);
62static pcmchan_caps *esschan_getcaps(void *data);
63
64static pcmchan_caps sb_playcaps = {
65 4000, 22050,
66 AFMT_U8,
67 AFMT_U8
68};
69
70static pcmchan_caps sb_reccaps = {
71 4000, 13000,

--- 8 unchanged lines hidden (view full) ---

80};
81
82static pcmchan_caps sbpro_reccaps = {
83 4000, 15000,
84 AFMT_STEREO | AFMT_U8,
85 AFMT_STEREO | AFMT_U8
86};
87
88static pcmchan_caps sb16_hcaps = {
89 5000, 45000,
90 AFMT_STEREO | AFMT_S16_LE,
91 AFMT_STEREO | AFMT_S16_LE
92};
93
94static pcmchan_caps sb16_lcaps = {
95 5000, 45000,
96 AFMT_STEREO | AFMT_U8,
97 AFMT_STEREO | AFMT_U8
98};
99
100static pcmchan_caps sb16x_caps = {
101 5000, 49000,
102 AFMT_STEREO | AFMT_U8 /* | AFMT_S16_LE */,
103 AFMT_STEREO | AFMT_U8 /* AFMT_S16_LE */
104};
105
106static pcmchan_caps ess_playcaps = {
107 5000, 49000,
108 AFMT_STEREO | AFMT_U8 | AFMT_S16_LE,
109 AFMT_STEREO | AFMT_S16_LE
110};
111
112static pcmchan_caps ess_reccaps = {
113 5000, 49000,

--- 32 unchanged lines hidden (view full) ---

146 snd_dbuf *buffer;
147 int dir;
148 u_int32_t fmt;
149 int ess_dma_started;
150};
151
152struct sb_info {
153 struct resource *io_base; /* I/O address for the board */
154 struct resource *irq;
155 struct resource *drq1;
156 struct resource *drq2;
157 bus_dma_tag_t parent_dmat;
158
159 int bd_id;
160 u_long bd_flags; /* board-specific flags */
161 struct sb_chinfo pch, rch;
162};
163
164static int sb_rd(struct sb_info *sb, int reg);
165static void sb_wr(struct sb_info *sb, int reg, u_int8_t val);
166static int sb_dspready(struct sb_info *sb);
167static int sb_cmd(struct sb_info *sb, u_char val);
168static int sb_cmd1(struct sb_info *sb, u_char cmd, int val);
169static int sb_cmd2(struct sb_info *sb, u_char cmd, int val);
170static u_int sb_get_byte(struct sb_info *sb);
171static void sb_setmixer(struct sb_info *sb, u_int port, u_int value);
172static int sb_getmixer(struct sb_info *sb, u_int port);
173static int sb_reset_dsp(struct sb_info *sb);
174
175static void sb_intr(void *arg);
176static int sb_format(struct sb_chinfo *ch, u_int32_t format);
177static int sb_speed(struct sb_chinfo *ch, int speed);
178static int sb_start(struct sb_chinfo *ch);
179static int sb_stop(struct sb_chinfo *ch);
180
181static int ess_write(struct sb_info *sb, u_char reg, int val);
182static int ess_read(struct sb_info *sb, u_char reg);
183static void ess_intr(void *arg);
184static int ess_format(struct sb_chinfo *ch, u_int32_t format);
185static int ess_speed(struct sb_chinfo *ch, int speed);
186static int ess_start(struct sb_chinfo *ch);
187static int ess_stop(struct sb_chinfo *ch);
188static int ess_abort(struct sb_chinfo *ch);
189
190static int sbmix_init(snd_mixer *m);
191static int sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right);
192static int sbmix_setrecsrc(snd_mixer *m, u_int32_t src);
193
194static snd_mixer sb_mixer = {
195 "SoundBlaster mixer",
196 sbmix_init,
197 sbmix_set,

--- 170 unchanged lines hidden (view full) ---

368 return 0;
369}
370
371static void
372sb_release_resources(struct sb_info *sb, device_t dev)
373{
374 /* should we bus_teardown_intr here? */
375 if (sb->irq) {
376 bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq);
377 sb->irq = 0;
378 }
379 if (sb->drq1) {
380 bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1);
381 sb->drq1 = 0;
382 }
383 if (sb->drq2) {
384 bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2);
385 sb->drq2 = 0;
386 }
387 if (sb->io_base) {
388 bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base);
389 sb->io_base = 0;
390 }
391 free(sb, M_DEVBUF);
392}
393
394static int
395sb_alloc_resources(struct sb_info *sb, device_t dev)
396{
397 int rid;
398
399 rid = 0;
400 if (!sb->io_base)
401 sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT,
402 &rid, 0, ~0, 1,
403 RF_ACTIVE);
404 rid = 0;
405 if (!sb->irq)
406 sb->irq = bus_alloc_resource(dev, SYS_RES_IRQ,
407 &rid, 0, ~0, 1,
408 RF_ACTIVE);
409 rid = 0;
410 if (!sb->drq1)
411 sb->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ,
412 &rid, 0, ~0, 1,
413 RF_ACTIVE);
414 rid = 1;
415 if (!sb->drq2)
416 sb->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ,
417 &rid, 0, ~0, 1,
418 RF_ACTIVE);
419
420 if (sb->io_base && sb->drq1 && sb->irq) {
421 isa_dma_acquire(rman_get_start(sb->drq1));
422 isa_dmainit(rman_get_start(sb->drq1), DSP_BUFFSIZE);
423
424 if (sb->drq2) {
425 isa_dma_acquire(rman_get_start(sb->drq2));
426 isa_dmainit(rman_get_start(sb->drq2), DSP_BUFFSIZE);
427 }
428
429 return 0;
430 } else return ENXIO;
431}
432
433static void
434sb16_swap(void *v, int dir)
435{
436 struct sb_info *sb = v;
437 int pb = sb->pch.buffer->dl;
438 int rb = sb->rch.buffer->dl;
439 int pc = sb->pch.buffer->chan;
440 int rc = sb->rch.buffer->chan;
441 int swp = 0;
442
443 if (!pb && !rb) {
444 if (dir == PCMDIR_PLAY && pc < 4) swp = 1;
445 else if (dir == PCMDIR_REC && rc < 4) swp = 1;
446 if (sb->bd_flags & BD_F_SB16X) swp = !swp;
447 if (swp) {
448 int t;
449
450 t = sb->pch.buffer->chan;
451 sb->pch.buffer->chan = sb->rch.buffer->chan;
452 sb->rch.buffer->chan = t;
453 sb->pch.buffer->dir = B_WRITE;
454 sb->rch.buffer->dir = B_READ;
455 }
456 }
457}
458
459static int
460sb_doattach(device_t dev, struct sb_info *sb)
461{
462 snddev_info *d = device_get_softc(dev);
463 void *ih;
464 char status[SND_STATUSLEN];
465
466 if (sb_alloc_resources(sb, dev)) goto no;
467 if (sb_reset_dsp(sb)) goto no;
468 mixer_init(d, &sb_mixer, sb);
469
470 if (sb->bd_flags & BD_F_ESS)
471 bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, ess_intr, sb, &ih);
472 else
473 bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &ih);
474 if ((sb->bd_flags & BD_F_SB16) && !(sb->bd_flags & BD_F_SB16X))
475 pcm_setswap(dev, sb16_swap);
476 if (!sb->drq2)
477 pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX);
478
479 if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0,
480 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
481 /*highaddr*/BUS_SPACE_MAXADDR,
482 /*filter*/NULL, /*filterarg*/NULL,
483 /*maxsize*/DSP_BUFFSIZE, /*nsegments*/1,
484 /*maxsegz*/0x3ffff,
485 /*flags*/0, &sb->parent_dmat) != 0) {
486 device_printf(dev, "unable to create dma tag\n");
487 goto no;
488 }
489
490 snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld",
491 rman_get_start(sb->io_base), rman_get_start(sb->irq),
492 rman_get_start(sb->drq1));
493 if (sb->drq2) snprintf(status + strlen(status), SND_STATUSLEN - strlen(status),
494 ":%ld", rman_get_start(sb->drq2));
495
496 if (pcm_register(dev, sb, 1, 1)) goto no;
497 if (sb->bd_flags & BD_F_ESS) {
498 pcm_addchan(dev, PCMDIR_REC, &ess_chantemplate, sb);
499 pcm_addchan(dev, PCMDIR_PLAY, &ess_chantemplate, sb);
500 } else {
501 pcm_addchan(dev, PCMDIR_REC, &sb_chantemplate, sb);
502 pcm_addchan(dev, PCMDIR_PLAY, &sb_chantemplate, sb);
503 }
504 pcm_setstatus(dev, status);
505
506 return 0;
507
508no:
509 sb_release_resources(sb, dev);
510 return ENXIO;
511}
512
513static void
514sb_intr(void *arg)
515{
516 struct sb_info *sb = (struct sb_info *)arg;
517 int reason = 3, c;
518
519 /*
520 * SB < 4.0 is half duplex and has only 1 bit for int source,

--- 121 unchanged lines hidden (view full) ---

642static int
643sb_start(struct sb_chinfo *ch)
644{
645 struct sb_info *sb = ch->parent;
646 int play = (ch->dir == PCMDIR_PLAY)? 1 : 0;
647 int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0;
648 int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0;
649 int l = ch->buffer->dl;
650 int dh = ch->buffer->chan > 3;
651 u_char i1, i2 = 0;
652
653 if (b16) l >>= 1;
654 l--;
655 if (play) sb_cmd(sb, DSP_CMD_SPKON);
656 if (sb->bd_flags & BD_F_SB16) {
657 i1 = DSP_F16_AUTO | DSP_F16_FIFO_ON |
658 (play? DSP_F16_DAC : DSP_F16_ADC);
659 i1 |= (b16 || dh)? DSP_DMA16 : DSP_DMA8;
660 i2 = (stereo? DSP_F16_STEREO : 0) | (b16? DSP_F16_SIGNED : 0);
661 sb_cmd(sb, i1);
662 sb_cmd2(sb, i2, l);
663 } else {
664 if (sb->bd_flags & BD_F_HISPEED) i1 = play? 0x90 : 0x98;
665 else i1 = play? 0x1c : 0x2c;
666 sb_setmixer(sb, 0x0e, stereo? 2 : 0);
667 /* an ESS extension -- they can do 16 bits */

--- 145 unchanged lines hidden (view full) ---

813 struct sb_info *sb = devinfo;
814 struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch;
815
816 ch->parent = sb;
817 ch->channel = c;
818 ch->buffer = b;
819 ch->buffer->bufsize = DSP_BUFFSIZE;
820 if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1) return NULL;
821 ch->buffer->chan = (dir == PCMDIR_PLAY)? rman_get_start(sb->drq2)
822 : rman_get_start(sb->drq1);
823 return ch;
824}
825
826static int
827sbchan_setdir(void *data, int dir)
828{
829 struct sb_chinfo *ch = data;
830 ch->dir = dir;

--- 37 unchanged lines hidden (view full) ---

868 return buf_isadmaptr(ch->buffer);
869}
870
871static pcmchan_caps *
872sbchan_getcaps(void *data)
873{
874 struct sb_chinfo *ch = data;
875 int p = (ch->dir == PCMDIR_PLAY)? 1 : 0;
876 if (ch->parent->bd_id < 0x300)
877 return p? &sb_playcaps : &sb_reccaps;
878 else if (ch->parent->bd_id < 0x400)
879 return p? &sbpro_playcaps : &sbpro_reccaps;
880 else if (ch->parent->bd_flags & BD_F_SB16X)
881 return &sb16x_caps;
882 else
883 return (ch->buffer->chan >= 4)? &sb16_hcaps : &sb16_lcaps;
884}
885/* channel interface for ESS18xx */
886#ifdef notyet
887static void *
888esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir)
889{
890 /* the same as sbchan_init()? */
891}

--- 178 unchanged lines hidden (view full) ---

1070 */
1071 sb_setmixer(sb, SB16_OMASK, 0x1f & ~1);
1072 break;
1073 }
1074 return src;
1075}
1076
1077static int
1078sbsbc_probe(device_t dev)
1079{
1080 char buf[64];
1081 u_int32_t func, ver, r;
1082
1083 /* The parent device has already been probed. */
1084 r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func);
1085 if (func != SCF_PCM)
1086 return (ENXIO);
1087
1088 r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
1089 ver &= 0x0000ffff;
1090 snprintf(buf, sizeof buf, "SB DSP %d.%02d", ver >> 8, ver & 0xff);
1091 device_set_desc_copy(dev, buf);
1092
1093 return 0;
1094}
1095
1096static int
1097sbsbc_attach(device_t dev)
1098{
1099 struct sb_info *sb;
1100 u_int32_t ver;
1101
1102 sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT);
1103 if (!sb) return ENXIO;
1104 bzero(sb, sizeof *sb);
1105
1106 BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver);
1107 sb->bd_id = ver & 0x0000ffff;
1108 sb->bd_flags = (ver & 0xffff0000) >> 16;
1109
1110 return sb_doattach(dev, sb);
1111}
1112
1113static device_method_t sbsbc_methods[] = {
1114 /* Device interface */
1115 DEVMETHOD(device_probe, sbsbc_probe),
1116 DEVMETHOD(device_attach, sbsbc_attach),
1117
1118 { 0, 0 }
1119};
1120
1121static driver_t sbsbc_driver = {
1122 "pcm",
1123 sbsbc_methods,
1124 sizeof(snddev_info),
1125};
1126
1127DRIVER_MODULE(sbsbc, sbc, sbsbc_driver, pcm_devclass, 0, 0);
1128
1129
1130