sb16.c revision 65340
129415Sjmg/* 250723Scg * Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk> 339899Sluigi * Copyright 1997,1998 Luigi Rizzo. 429415Sjmg * 529415Sjmg * Derived from files in the Voxware 3.5 distribution, 629415Sjmg * Copyright by Hannu Savolainen 1994, under the same copyright 729415Sjmg * conditions. 850723Scg * All rights reserved. 950723Scg * 1029415Sjmg * Redistribution and use in source and binary forms, with or without 1129415Sjmg * modification, are permitted provided that the following conditions 1230869Sjmg * are met: 1330869Sjmg * 1. Redistributions of source code must retain the above copyright 1430869Sjmg * notice, this list of conditions and the following disclaimer. 1530869Sjmg * 2. Redistributions in binary form must reproduce the above copyright 1650723Scg * notice, this list of conditions and the following disclaimer in the 1750723Scg * documentation and/or other materials provided with the distribution. 1830869Sjmg * 1950723Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2050723Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2150723Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2250723Scg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2350723Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2450723Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2550723Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2650723Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2750723Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2850723Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2950723Scg * SUCH DAMAGE. 3050723Scg * 3150959Speter * $FreeBSD: head/sys/dev/sound/isa/sb16.c 65340 2000-09-01 20:09:24Z cg $ 3229415Sjmg */ 3329415Sjmg 3453465Scg#include <dev/sound/pcm/sound.h> 3529415Sjmg 3629415Sjmg#define __SB_MIXER_C__ /* XXX warning... */ 3753465Scg#include <dev/sound/isa/sb.h> 3853553Stanimura#include <dev/sound/chip.h> 3929415Sjmg 4055706Scg#define PLAIN_SB16(x) ((((x)->bd_flags) & (BD_F_SB16|BD_F_SB16X)) == BD_F_SB16) 4155254Scg 4250723Scg/* channel interface */ 4350723Scgstatic void *sbchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir); 4450723Scgstatic int sbchan_setdir(void *data, int dir); 4550723Scgstatic int sbchan_setformat(void *data, u_int32_t format); 4650723Scgstatic int sbchan_setspeed(void *data, u_int32_t speed); 4750723Scgstatic int sbchan_setblocksize(void *data, u_int32_t blocksize); 4850723Scgstatic int sbchan_trigger(void *data, int go); 4950723Scgstatic int sbchan_getptr(void *data); 5050723Scgstatic pcmchan_caps *sbchan_getcaps(void *data); 5129415Sjmg 5264881Scgstatic u_int32_t sb_playfmt[] = { 5350723Scg AFMT_U8, 5464881Scg 0 5550723Scg}; 5664881Scgstatic pcmchan_caps sb_playcaps = {4000, 22050, sb_playfmt, 0}; 5729415Sjmg 5864881Scgstatic u_int32_t sb_recfmt[] = { 5950723Scg AFMT_U8, 6064881Scg 0 6150723Scg}; 6264881Scgstatic pcmchan_caps sb_reccaps = {4000, 13000, sb_recfmt, 0}; 6329415Sjmg 6464881Scgstatic u_int32_t sbpro_playfmt[] = { 6564881Scg AFMT_U8, 6650723Scg AFMT_STEREO | AFMT_U8, 6764881Scg 0 6850723Scg}; 6964881Scgstatic pcmchan_caps sbpro_playcaps = {4000, 45000, sbpro_playfmt, 0}; 7029415Sjmg 7164881Scgstatic u_int32_t sbpro_recfmt[] = { 7264881Scg AFMT_U8, 7350723Scg AFMT_STEREO | AFMT_U8, 7464881Scg 0 7550723Scg}; 7664881Scgstatic pcmchan_caps sbpro_reccaps = {4000, 15000, sbpro_recfmt, 0}; 7729415Sjmg 7864881Scgstatic u_int32_t sb16_hfmt[] = { 7964881Scg AFMT_S16_LE, 8050723Scg AFMT_STEREO | AFMT_S16_LE, 8164881Scg 0 8250723Scg}; 8364881Scgstatic pcmchan_caps sb16_hcaps = {5000, 45000, sb16_hfmt, 0}; 8429415Sjmg 8564881Scgstatic u_int32_t sb16_lfmt[] = { 8664881Scg AFMT_U8, 8750723Scg AFMT_STEREO | AFMT_U8, 8864881Scg 0 8950723Scg}; 9064881Scgstatic pcmchan_caps sb16_lcaps = {5000, 45000, sb16_lfmt, 0}; 9129415Sjmg 9264881Scgstatic u_int32_t sb16x_fmt[] = { 9364881Scg AFMT_U8, 9464881Scg AFMT_STEREO | AFMT_U8, 9564881Scg AFMT_S16_LE, 9664881Scg AFMT_STEREO | AFMT_S16_LE, 9764881Scg 0 9854462Scg}; 9964881Scgstatic pcmchan_caps sb16x_caps = {5000, 49000, sb16x_fmt, 0}; 10054462Scg 10150723Scgstatic pcm_channel sb_chantemplate = { 10250723Scg sbchan_init, 10350723Scg sbchan_setdir, 10450723Scg sbchan_setformat, 10550723Scg sbchan_setspeed, 10650723Scg sbchan_setblocksize, 10750723Scg sbchan_trigger, 10850723Scg sbchan_getptr, 10950723Scg sbchan_getcaps, 11065340Scg NULL, /* free */ 11165340Scg NULL, /* nop1 */ 11265340Scg NULL, /* nop2 */ 11365340Scg NULL, /* nop3 */ 11465340Scg NULL, /* nop4 */ 11565340Scg NULL, /* nop5 */ 11665340Scg NULL, /* nop6 */ 11765340Scg NULL, /* nop7 */ 11850723Scg}; 11929415Sjmg 12050723Scgstruct sb_info; 12129415Sjmg 12250723Scgstruct sb_chinfo { 12350723Scg struct sb_info *parent; 12450723Scg pcm_channel *channel; 12550723Scg snd_dbuf *buffer; 12650723Scg int dir; 12755706Scg u_int32_t fmt, spd; 12850723Scg}; 12929415Sjmg 13050723Scgstruct sb_info { 13150723Scg struct resource *io_base; /* I/O address for the board */ 13250723Scg struct resource *irq; 13354462Scg struct resource *drq1; 13454462Scg struct resource *drq2; 13555706Scg bus_dma_tag_t parent_dmat; 13629415Sjmg 13750723Scg int bd_id; 13850723Scg u_long bd_flags; /* board-specific flags */ 13950723Scg struct sb_chinfo pch, rch; 14050723Scg}; 14150723Scg 14250723Scgstatic int sb_rd(struct sb_info *sb, int reg); 14350723Scgstatic void sb_wr(struct sb_info *sb, int reg, u_int8_t val); 14450723Scgstatic int sb_dspready(struct sb_info *sb); 14550723Scgstatic int sb_cmd(struct sb_info *sb, u_char val); 14650723Scgstatic int sb_cmd1(struct sb_info *sb, u_char cmd, int val); 14750723Scgstatic int sb_cmd2(struct sb_info *sb, u_char cmd, int val); 14850723Scgstatic u_int sb_get_byte(struct sb_info *sb); 14950723Scgstatic void sb_setmixer(struct sb_info *sb, u_int port, u_int value); 15050723Scgstatic int sb_getmixer(struct sb_info *sb, u_int port); 15154462Scgstatic int sb_reset_dsp(struct sb_info *sb); 15229415Sjmg 15350723Scgstatic void sb_intr(void *arg); 15455706Scgstatic int sb_speed(struct sb_chinfo *ch); 15550723Scgstatic int sb_start(struct sb_chinfo *ch); 15650723Scgstatic int sb_stop(struct sb_chinfo *ch); 15750723Scg 15850723Scgstatic int sbmix_init(snd_mixer *m); 15950723Scgstatic int sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right); 16050723Scgstatic int sbmix_setrecsrc(snd_mixer *m, u_int32_t src); 16150723Scg 16250723Scgstatic snd_mixer sb_mixer = { 16365340Scg "SoundBlaster mixer", 16465340Scg sbmix_init, 16565340Scg NULL, 16665340Scg sbmix_set, 16765340Scg sbmix_setrecsrc, 16850723Scg}; 16950723Scg 17050723Scgstatic devclass_t pcm_devclass; 17150723Scg 17229415Sjmg/* 17350723Scg * Common code for the midi and pcm functions 17429415Sjmg * 17550723Scg * sb_cmd write a single byte to the CMD port. 17650723Scg * sb_cmd1 write a CMD + 1 byte arg 17750723Scg * sb_cmd2 write a CMD + 2 byte arg 17850723Scg * sb_get_byte returns a single byte from the DSP data port 17950723Scg * 18050723Scg * ess_write is actually sb_cmd1 18150723Scg * ess_read access ext. regs via sb_cmd(0xc0, reg) followed by sb_get_byte 18229415Sjmg */ 18329415Sjmg 18429415Sjmgstatic int 18550723Scgport_rd(struct resource *port, int off) 18629415Sjmg{ 18750723Scg return bus_space_read_1(rman_get_bustag(port), 18850723Scg rman_get_bushandle(port), 18950723Scg off); 19050723Scg} 19129415Sjmg 19250723Scgstatic void 19350723Scgport_wr(struct resource *port, int off, u_int8_t data) 19450723Scg{ 19550723Scg return bus_space_write_1(rman_get_bustag(port), 19650723Scg rman_get_bushandle(port), 19750723Scg off, data); 19829415Sjmg} 19929415Sjmg 20029415Sjmgstatic int 20150723Scgsb_rd(struct sb_info *sb, int reg) 20229415Sjmg{ 20350723Scg return port_rd(sb->io_base, reg); 20450723Scg} 20529415Sjmg 20650723Scgstatic void 20750723Scgsb_wr(struct sb_info *sb, int reg, u_int8_t val) 20850723Scg{ 20950723Scg port_wr(sb->io_base, reg, val); 21029415Sjmg} 21129415Sjmg 21250723Scgstatic int 21350723Scgsb_dspready(struct sb_info *sb) 21450723Scg{ 21550723Scg return ((sb_rd(sb, SBDSP_STATUS) & 0x80) == 0); 21650723Scg} 21729415Sjmg 21829415Sjmgstatic int 21950723Scgsb_dspwr(struct sb_info *sb, u_char val) 22029415Sjmg{ 22150723Scg int i; 22229415Sjmg 22350723Scg for (i = 0; i < 1000; i++) { 22450723Scg if (sb_dspready(sb)) { 22550723Scg sb_wr(sb, SBDSP_CMD, val); 22650723Scg return 1; 22750723Scg } 22850723Scg if (i > 10) DELAY((i > 100)? 1000 : 10); 22950723Scg } 23050723Scg printf("sb_dspwr(0x%02x) timed out.\n", val); 23150723Scg return 0; 23250723Scg} 23329415Sjmg 23450723Scgstatic int 23550723Scgsb_cmd(struct sb_info *sb, u_char val) 23650723Scg{ 23750723Scg#if 0 23850723Scg printf("sb_cmd: %x\n", val); 23950723Scg#endif 24050723Scg return sb_dspwr(sb, val); 24150723Scg} 24229415Sjmg 24350723Scgstatic int 24450723Scgsb_cmd1(struct sb_info *sb, u_char cmd, int val) 24550723Scg{ 24650723Scg#if 0 24750723Scg printf("sb_cmd1: %x, %x\n", cmd, val); 24850723Scg#endif 24950723Scg if (sb_dspwr(sb, cmd)) { 25050723Scg return sb_dspwr(sb, val & 0xff); 25150723Scg } else return 0; 25250723Scg} 25329415Sjmg 25450723Scgstatic int 25550723Scgsb_cmd2(struct sb_info *sb, u_char cmd, int val) 25650723Scg{ 25750723Scg#if 0 25850723Scg printf("sb_cmd2: %x, %x\n", cmd, val); 25950723Scg#endif 26050723Scg if (sb_dspwr(sb, cmd)) { 26150723Scg return sb_dspwr(sb, val & 0xff) && 26250723Scg sb_dspwr(sb, (val >> 8) & 0xff); 26350723Scg } else return 0; 26450723Scg} 26529415Sjmg 26650723Scg/* 26750723Scg * in the SB, there is a set of indirect "mixer" registers with 26850723Scg * address at offset 4, data at offset 5 26950723Scg */ 27050723Scgstatic void 27150723Scgsb_setmixer(struct sb_info *sb, u_int port, u_int value) 27250723Scg{ 27350723Scg u_long flags; 27429415Sjmg 27550723Scg flags = spltty(); 27650723Scg sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 27750723Scg DELAY(10); 27850723Scg sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff)); 27950723Scg DELAY(10); 28050723Scg splx(flags); 28150723Scg} 28231361Sjmg 28350723Scgstatic int 28450723Scgsb_getmixer(struct sb_info *sb, u_int port) 28550723Scg{ 28650723Scg int val; 28750723Scg u_long flags; 28829415Sjmg 28950723Scg flags = spltty(); 29050723Scg sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 29150723Scg DELAY(10); 29250723Scg val = sb_rd(sb, SB_MIX_DATA); 29350723Scg DELAY(10); 29450723Scg splx(flags); 29529415Sjmg 29650723Scg return val; 29750723Scg} 29829415Sjmg 29950723Scgstatic u_int 30050723Scgsb_get_byte(struct sb_info *sb) 30150723Scg{ 30250723Scg int i; 30329415Sjmg 30450723Scg for (i = 1000; i > 0; i--) { 30550723Scg if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80) 30650723Scg return sb_rd(sb, DSP_READ); 30750723Scg else 30850723Scg DELAY(20); 30950723Scg } 31050723Scg return 0xffff; 31150723Scg} 31229415Sjmg 31350723Scgstatic int 31450723Scgsb_reset_dsp(struct sb_info *sb) 31529415Sjmg{ 31650723Scg sb_wr(sb, SBDSP_RST, 3); 31750723Scg DELAY(100); 31850723Scg sb_wr(sb, SBDSP_RST, 0); 31950723Scg if (sb_get_byte(sb) != 0xAA) { 32050723Scg DEB(printf("sb_reset_dsp 0x%lx failed\n", 32150723Scg rman_get_start(d->io_base))); 32250723Scg return ENXIO; /* Sorry */ 32350723Scg } 32455706Scg if (sb->bd_flags & BD_F_ESS) 32555706Scg sb_cmd(sb, 0xc6); 32650723Scg return 0; 32729415Sjmg} 32829415Sjmg 32929415Sjmgstatic void 33050723Scgsb_release_resources(struct sb_info *sb, device_t dev) 33129415Sjmg{ 33250723Scg /* should we bus_teardown_intr here? */ 33350723Scg if (sb->irq) { 33454462Scg bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq); 33550723Scg sb->irq = 0; 33650723Scg } 33750723Scg if (sb->drq1) { 33854462Scg bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1); 33950723Scg sb->drq1 = 0; 34050723Scg } 34150723Scg if (sb->drq2) { 34254462Scg bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2); 34350723Scg sb->drq2 = 0; 34450723Scg } 34550723Scg if (sb->io_base) { 34654462Scg bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base); 34750723Scg sb->io_base = 0; 34850723Scg } 34950723Scg free(sb, M_DEVBUF); 35050723Scg} 35129415Sjmg 35250723Scgstatic int 35350723Scgsb_alloc_resources(struct sb_info *sb, device_t dev) 35450723Scg{ 35554462Scg int rid; 35654462Scg 35754462Scg rid = 0; 35850723Scg if (!sb->io_base) 35950723Scg sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, 36054462Scg &rid, 0, ~0, 1, 36150723Scg RF_ACTIVE); 36254462Scg rid = 0; 36350723Scg if (!sb->irq) 36450723Scg sb->irq = bus_alloc_resource(dev, SYS_RES_IRQ, 36554462Scg &rid, 0, ~0, 1, 36650723Scg RF_ACTIVE); 36754462Scg rid = 0; 36850723Scg if (!sb->drq1) 36950723Scg sb->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ, 37054462Scg &rid, 0, ~0, 1, 37150723Scg RF_ACTIVE); 37254462Scg rid = 1; 37358756Scg if (!sb->drq2) 37450723Scg sb->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ, 37554462Scg &rid, 0, ~0, 1, 37650723Scg RF_ACTIVE); 37729415Sjmg 37850723Scg if (sb->io_base && sb->drq1 && sb->irq) { 37958756Scg int bs = DSP_BUFFSIZE; 38055424Scg 38154462Scg isa_dma_acquire(rman_get_start(sb->drq1)); 38255424Scg isa_dmainit(rman_get_start(sb->drq1), bs); 38329415Sjmg 38450723Scg if (sb->drq2) { 38554462Scg isa_dma_acquire(rman_get_start(sb->drq2)); 38655424Scg isa_dmainit(rman_get_start(sb->drq2), bs); 38754462Scg } 38850723Scg 38950723Scg return 0; 39050723Scg } else return ENXIO; 39129415Sjmg} 39229415Sjmg 39354462Scgstatic void 39454462Scgsb16_swap(void *v, int dir) 39529415Sjmg{ 39654462Scg struct sb_info *sb = v; 39754462Scg int pb = sb->pch.buffer->dl; 39854462Scg int rb = sb->rch.buffer->dl; 39954462Scg int pc = sb->pch.buffer->chan; 40054462Scg int rc = sb->rch.buffer->chan; 40154462Scg int swp = 0; 40229415Sjmg 40354462Scg if (!pb && !rb) { 40455706Scg if (dir == PCMDIR_PLAY && pc < 4) 40555706Scg swp = 1; 40655706Scg else 40755706Scg if (dir == PCMDIR_REC && rc < 4) 40855706Scg swp = 1; 40958756Scg if (swp) { 41054462Scg int t; 41129415Sjmg 41254462Scg t = sb->pch.buffer->chan; 41354462Scg sb->pch.buffer->chan = sb->rch.buffer->chan; 41454462Scg sb->rch.buffer->chan = t; 41557973Sphk sb->pch.buffer->dir = ISADMA_WRITE; 41657973Sphk sb->rch.buffer->dir = ISADMA_READ; 41731361Sjmg } 41854462Scg } 41950723Scg} 42041653Sbrian 42150723Scgstatic int 42250723Scgsb_doattach(device_t dev, struct sb_info *sb) 42329415Sjmg{ 42450723Scg void *ih; 42550723Scg char status[SND_STATUSLEN]; 42658756Scg int bs = DSP_BUFFSIZE; 42729415Sjmg 42855706Scg if (sb_alloc_resources(sb, dev)) 42955706Scg goto no; 43055706Scg if (sb_reset_dsp(sb)) 43155706Scg goto no; 43265340Scg mixer_init(dev, &sb_mixer, sb); 43329415Sjmg 43458756Scg bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &ih); 43554462Scg if ((sb->bd_flags & BD_F_SB16) && !(sb->bd_flags & BD_F_SB16X)) 43654462Scg pcm_setswap(dev, sb16_swap); 43754462Scg if (!sb->drq2) 43854462Scg pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 43929415Sjmg 44050723Scg if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 44150723Scg /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 44250723Scg /*highaddr*/BUS_SPACE_MAXADDR, 44350723Scg /*filter*/NULL, /*filterarg*/NULL, 44455428Scg /*maxsize*/bs, /*nsegments*/1, 44550723Scg /*maxsegz*/0x3ffff, 44650723Scg /*flags*/0, &sb->parent_dmat) != 0) { 44750723Scg device_printf(dev, "unable to create dma tag\n"); 44850723Scg goto no; 44950723Scg } 45029415Sjmg 45154462Scg snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld", 45250723Scg rman_get_start(sb->io_base), rman_get_start(sb->irq), 45354462Scg rman_get_start(sb->drq1)); 45455706Scg if (sb->drq2) 45555706Scg snprintf(status + strlen(status), SND_STATUSLEN - strlen(status), 45655706Scg ":%ld", rman_get_start(sb->drq2)); 45729415Sjmg 45855706Scg if (pcm_register(dev, sb, 1, 1)) 45955706Scg goto no; 46058756Scg pcm_addchan(dev, PCMDIR_REC, &sb_chantemplate, sb); 46158756Scg pcm_addchan(dev, PCMDIR_PLAY, &sb_chantemplate, sb); 46250723Scg pcm_setstatus(dev, status); 46329415Sjmg 46450723Scg return 0; 46529415Sjmg 46650723Scgno: 46750723Scg sb_release_resources(sb, dev); 46850723Scg return ENXIO; 46950723Scg} 47029415Sjmg 47150723Scgstatic void 47250723Scgsb_intr(void *arg) 47350723Scg{ 47450723Scg struct sb_info *sb = (struct sb_info *)arg; 47550723Scg int reason = 3, c; 47629415Sjmg 47750723Scg /* 47850723Scg * SB < 4.0 is half duplex and has only 1 bit for int source, 47950723Scg * so we fake it. SB 4.x (SB16) has the int source in a separate 48050723Scg * register. 48150723Scg * The Vibra16X has separate flags for 8 and 16 bit transfers, but 48250723Scg * I have no idea how to tell capture from playback interrupts... 48350723Scg */ 48450723Scg if (sb->bd_flags & BD_F_SB16) { 48550723Scg c = sb_getmixer(sb, IRQ_STAT); 48650723Scg /* this tells us if the source is 8-bit or 16-bit dma. We 48750723Scg * have to check the io channel to map it to read or write... 48850723Scg */ 48950723Scg reason = 0; 49050723Scg if (c & 1) { /* 8-bit dma */ 49155706Scg if (sb->pch.fmt & AFMT_U8) 49255706Scg reason |= 1; 49355706Scg if (sb->rch.fmt & AFMT_U8) 49455706Scg reason |= 2; 49550723Scg } 49650723Scg if (c & 2) { /* 16-bit dma */ 49755706Scg if (sb->pch.fmt & AFMT_S16_LE) 49855706Scg reason |= 1; 49955706Scg if (sb->rch.fmt & AFMT_S16_LE) 50055706Scg reason |= 2; 50150723Scg } 50250723Scg } else c = 1; 50350723Scg#if 0 50450723Scg printf("sb_intr: reason=%d c=0x%x\n", reason, c); 50550723Scg#endif 50650723Scg if ((reason & 1) && (sb->pch.buffer->dl > 0)) 50750723Scg chn_intr(sb->pch.channel); 50850723Scg if ((reason & 2) && (sb->rch.buffer->dl > 0)) 50950723Scg chn_intr(sb->rch.channel); 51055706Scg if (c & 1) 51155706Scg sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */ 51255706Scg if (c & 2) 51355706Scg sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */ 51450723Scg} 51531361Sjmg 51650723Scgstatic int 51755706Scgsb_speed(struct sb_chinfo *ch) 51850723Scg{ 51950723Scg struct sb_info *sb = ch->parent; 52050723Scg int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 52150723Scg int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0; 52255706Scg int speed = ch->spd; 52329415Sjmg 52450723Scg if (sb->bd_flags & BD_F_SB16) { 52550723Scg RANGE(speed, 5000, 45000); 52650723Scg sb_cmd(sb, 0x42 - play); 52750723Scg sb_cmd(sb, speed >> 8); 52850723Scg sb_cmd(sb, speed & 0xff); 52950723Scg } else { 53050723Scg u_char tconst; 53150723Scg int max_speed = 45000, tmp; 53250723Scg u_long flags; 53329415Sjmg 53450723Scg /* here enforce speed limitations - max 22050 on sb 1.x*/ 53555706Scg if (sb->bd_id <= 0x200) 53655706Scg max_speed = 22050; 53729415Sjmg 53850723Scg /* 53950723Scg * SB models earlier than SB Pro have low limit for the 54050723Scg * input rate. Note that this is only for input, but since 54150723Scg * we do not support separate values for rec & play.... 54250723Scg */ 54350723Scg if (!play) { 54455706Scg if (sb->bd_id <= 0x200) 54555706Scg max_speed = 13000; 54655706Scg else 54755706Scg if (sb->bd_id < 0x300) 54855706Scg max_speed = 15000; 54950723Scg } 55050723Scg RANGE(speed, 4000, max_speed); 55155706Scg if (stereo) 55255706Scg speed <<= 1; 55329415Sjmg 55450723Scg /* 55550723Scg * Now the speed should be valid. Compute the value to be 55650723Scg * programmed into the board. 55750723Scg */ 55850723Scg if (speed > 22050) { /* High speed mode on 2.01/3.xx */ 55950723Scg tconst = (u_char) 56050723Scg ((65536 - ((256000000 + speed / 2) / speed)) 56150723Scg >> 8); 56250723Scg sb->bd_flags |= BD_F_HISPEED; 56350723Scg tmp = 65536 - (tconst << 8); 56450723Scg speed = (256000000 + tmp / 2) / tmp; 56550723Scg } else { 56650723Scg sb->bd_flags &= ~BD_F_HISPEED; 56750723Scg tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; 56850723Scg tmp = 256 - tconst; 56950723Scg speed = (1000000 + tmp / 2) / tmp; 57050723Scg } 57150723Scg flags = spltty(); 57250723Scg sb_cmd1(sb, 0x40, tconst); /* set time constant */ 57350723Scg splx(flags); 57455706Scg if (stereo) 57555706Scg speed >>= 1; 57650723Scg } 57755706Scg ch->spd = speed; 57850723Scg return speed; 57929415Sjmg} 58029415Sjmg 58150723Scgstatic int 58250723Scgsb_start(struct sb_chinfo *ch) 58350723Scg{ 58450723Scg struct sb_info *sb = ch->parent; 58550723Scg int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 58650723Scg int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0; 58750723Scg int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0; 58850723Scg int l = ch->buffer->dl; 58954462Scg int dh = ch->buffer->chan > 3; 59054791Scg u_char i1, i2; 59129415Sjmg 59255706Scg if (b16 || dh) 59355706Scg l >>= 1; 59450723Scg l--; 59555706Scg 59655706Scg if (play) 59755706Scg sb_cmd(sb, DSP_CMD_SPKON); 59855706Scg 59950723Scg if (sb->bd_flags & BD_F_SB16) { 60055706Scg i1 = DSP_F16_AUTO | DSP_F16_FIFO_ON; 60155706Scg i1 |= play? DSP_F16_DAC : DSP_F16_ADC; 60255706Scg i1 |= (b16 || dh)? DSP_DMA16 : DSP_DMA8; 60355706Scg i2 = (stereo? DSP_F16_STEREO : 0) | (b16? DSP_F16_SIGNED : 0); 60455706Scg sb_cmd(sb, i1); 60555706Scg sb_cmd2(sb, i2, l); 60650723Scg } else { 60755706Scg if (sb->bd_flags & BD_F_HISPEED) 60855706Scg i1 = play? 0x90 : 0x98; 60955706Scg else 61055706Scg i1 = play? 0x1c : 0x2c; 61155706Scg sb_setmixer(sb, 0x0e, stereo? 2 : 0); 61255706Scg sb_cmd2(sb, 0x48, l); 61355706Scg sb_cmd(sb, i1); 61450723Scg } 61550723Scg sb->bd_flags |= BD_F_DMARUN << b16; 61650723Scg return 0; 61750723Scg} 61850723Scg 61950723Scgstatic int 62050723Scgsb_stop(struct sb_chinfo *ch) 62129415Sjmg{ 62250723Scg struct sb_info *sb = ch->parent; 62350723Scg int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 62450723Scg int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0; 62529415Sjmg 62655706Scg if (sb->bd_flags & BD_F_HISPEED) 62755706Scg sb_reset_dsp(sb); 62850723Scg else { 62950723Scg sb_cmd(sb, b16? DSP_CMD_DMAPAUSE_16 : DSP_CMD_DMAPAUSE_8); 63050723Scg /* 63150723Scg * The above seems to have the undocumented side effect of 63250723Scg * blocking the other side as well. If the other 63350723Scg * channel was active (SB16) I have to re-enable it :( 63450723Scg */ 63550723Scg if (sb->bd_flags & (BD_F_DMARUN << (1 - b16))) 63650723Scg sb_cmd(sb, b16? 0xd4 : 0xd6 ); 63729415Sjmg } 63855706Scg if (play) 63955706Scg sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */ 64050723Scg sb->bd_flags &= ~(BD_F_DMARUN << b16); 64150723Scg return 0; 64250723Scg} 64329415Sjmg 64455706Scg/* channel interface */ 64555706Scgstatic void * 64655706Scgsbchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) 64755706Scg{ 64855706Scg struct sb_info *sb = devinfo; 64955706Scg struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch; 65055706Scg int dch, dl, dh; 65155706Scg 65255706Scg ch->parent = sb; 65355706Scg ch->channel = c; 65455706Scg ch->buffer = b; 65555706Scg ch->buffer->bufsize = DSP_BUFFSIZE; 65655706Scg if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1) 65755706Scg return NULL; 65855706Scg dch = (dir == PCMDIR_PLAY)? 1 : 0; 65955706Scg if (sb->bd_flags & BD_F_SB16X) 66055706Scg dch = !dch; 66155706Scg dl = rman_get_start(sb->drq1); 66255706Scg dh = sb->drq2? rman_get_start(sb->drq2) : dl; 66355706Scg ch->buffer->chan = dch? dh : dl; 66455706Scg return ch; 66555706Scg} 66655706Scg 66755706Scgstatic int 66855706Scgsbchan_setdir(void *data, int dir) 66955706Scg{ 67055706Scg struct sb_chinfo *ch = data; 67155706Scg 67255706Scg ch->dir = dir; 67355706Scg return 0; 67455706Scg} 67555706Scg 67655706Scgstatic int 67755706Scgsbchan_setformat(void *data, u_int32_t format) 67855706Scg{ 67955706Scg struct sb_chinfo *ch = data; 68055706Scg 68155706Scg ch->fmt = format; 68255706Scg return 0; 68355706Scg} 68455706Scg 68555706Scgstatic int 68655706Scgsbchan_setspeed(void *data, u_int32_t speed) 68755706Scg{ 68855706Scg struct sb_chinfo *ch = data; 68955706Scg 69055706Scg ch->spd = speed; 69155706Scg return sb_speed(ch); 69255706Scg} 69355706Scg 69455706Scgstatic int 69555706Scgsbchan_setblocksize(void *data, u_int32_t blocksize) 69655706Scg{ 69755706Scg return blocksize; 69855706Scg} 69955706Scg 70055706Scgstatic int 70155706Scgsbchan_trigger(void *data, int go) 70255706Scg{ 70355706Scg struct sb_chinfo *ch = data; 70455706Scg 70560958Scg if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 70655706Scg return 0; 70755706Scg 70855706Scg buf_isadma(ch->buffer, go); 70955706Scg if (go == PCMTRIG_START) 71055706Scg sb_start(ch); 71155706Scg else 71255706Scg sb_stop(ch); 71355706Scg return 0; 71455706Scg} 71555706Scg 71655706Scgstatic int 71755706Scgsbchan_getptr(void *data) 71855706Scg{ 71955706Scg struct sb_chinfo *ch = data; 72055706Scg 72155706Scg return buf_isadmaptr(ch->buffer); 72255706Scg} 72355706Scg 72455706Scgstatic pcmchan_caps * 72555706Scgsbchan_getcaps(void *data) 72655706Scg{ 72755706Scg struct sb_chinfo *ch = data; 72855706Scg int p = (ch->dir == PCMDIR_PLAY)? 1 : 0; 72955706Scg 73055706Scg if (ch->parent->bd_id < 0x300) 73155706Scg return p? &sb_playcaps : &sb_reccaps; 73255706Scg else if (ch->parent->bd_id < 0x400) 73355706Scg return p? &sbpro_playcaps : &sbpro_reccaps; 73455706Scg else if (ch->parent->bd_flags & BD_F_SB16X) 73555706Scg return &sb16x_caps; 73655706Scg else 73755706Scg return (ch->buffer->chan >= 4)? &sb16_hcaps : &sb16_lcaps; 73855706Scg} 73955706Scg 74050723Scg/************************************************************/ 74139899Sluigi 74229415Sjmgstatic int 74350723Scgsbmix_init(snd_mixer *m) 74429415Sjmg{ 74550723Scg struct sb_info *sb = mix_getdevinfo(m); 74629415Sjmg 74750723Scg switch (sb->bd_flags & BD_F_MIX_MASK) { 74850723Scg case BD_F_MIX_CT1345: /* SB 3.0 has 1345 mixer */ 74950723Scg mix_setdevs(m, SBPRO_MIXER_DEVICES); 75050723Scg mix_setrecdevs(m, SBPRO_RECORDING_DEVICES); 75150723Scg sb_setmixer(sb, 0, 1); /* reset mixer */ 75258756Scg sb_setmixer(sb, MIC_VOL, 0x6); /* mic volume max */ 75350723Scg sb_setmixer(sb, RECORD_SRC, 0x0); /* mic source */ 75450723Scg sb_setmixer(sb, FM_VOL, 0x0); /* no midi */ 75550723Scg break; 75631361Sjmg 75750723Scg case BD_F_MIX_CT1745: /* SB16 mixer ... */ 75850723Scg mix_setdevs(m, SB16_MIXER_DEVICES); 75950723Scg mix_setrecdevs(m, SB16_RECORDING_DEVICES); 76050723Scg sb_setmixer(sb, 0x3c, 0x1f); /* make all output active */ 76150723Scg sb_setmixer(sb, 0x3d, 0); /* make all inputs-l off */ 76250723Scg sb_setmixer(sb, 0x3e, 0); /* make all inputs-r off */ 76350723Scg } 76450723Scg return 0; 76550723Scg} 76631361Sjmg 76750723Scgstatic int 76850723Scgsbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) 76950723Scg{ 77050723Scg struct sb_info *sb = mix_getdevinfo(m); 77150723Scg int regoffs; 77250723Scg u_char val; 77350723Scg mixer_tab *iomap; 77429415Sjmg 77550723Scg switch (sb->bd_flags & BD_F_MIX_MASK) { 77650723Scg case BD_F_MIX_CT1345: 77758756Scg iomap = &sbpro_mix; 77850723Scg break; 77929415Sjmg 78050723Scg case BD_F_MIX_CT1745: 78150723Scg iomap = &sb16_mix; 78250723Scg break; 78329415Sjmg 78450723Scg default: 78550723Scg return -1; 78650723Scg } 78753126Sdfr 78853126Sdfr /* Change left channel */ 78950723Scg regoffs = (*iomap)[dev][LEFT_CHN].regno; 79053126Sdfr if (regoffs != 0) { 79153126Sdfr val = sb_getmixer(sb, regoffs); 79253126Sdfr change_bits(iomap, &val, dev, LEFT_CHN, left); 79353126Sdfr sb_setmixer(sb, regoffs, val); 79453126Sdfr } 79553126Sdfr 79653126Sdfr /* Change right channel */ 79753126Sdfr regoffs = (*iomap)[dev][RIGHT_CHN].regno; 79853126Sdfr if (regoffs != 0) { 79953126Sdfr val = sb_getmixer(sb, regoffs); /* Read the new one */ 80053126Sdfr change_bits(iomap, &val, dev, RIGHT_CHN, right); 80153126Sdfr sb_setmixer(sb, regoffs, val); 80253126Sdfr } else 80353126Sdfr right = left; 80453126Sdfr 80550723Scg return left | (right << 8); 80629415Sjmg} 80729415Sjmg 80850723Scgstatic int 80950723Scgsbmix_setrecsrc(snd_mixer *m, u_int32_t src) 81029415Sjmg{ 81150723Scg struct sb_info *sb = mix_getdevinfo(m); 81250723Scg u_char recdev; 81329415Sjmg 81450723Scg switch (sb->bd_flags & BD_F_MIX_MASK) { 81550723Scg case BD_F_MIX_CT1345: 81655706Scg if (src == SOUND_MASK_LINE) 81755706Scg recdev = 0x06; 81855706Scg else if (src == SOUND_MASK_CD) 81955706Scg recdev = 0x02; 82050723Scg else { /* default: mic */ 82150723Scg src = SOUND_MASK_MIC; 82250723Scg recdev = 0; 82350723Scg } 82450723Scg sb_setmixer(sb, RECORD_SRC, recdev | 82550723Scg (sb_getmixer(sb, RECORD_SRC) & ~0x07)); 82650723Scg break; 82729415Sjmg 82850723Scg case BD_F_MIX_CT1745: /* sb16 */ 82950723Scg recdev = 0; 83055706Scg if (src & SOUND_MASK_MIC) 83155706Scg recdev |= 0x01; /* mono mic */ 83255706Scg if (src & SOUND_MASK_CD) 83355706Scg recdev |= 0x06; /* l+r cd */ 83455706Scg if (src & SOUND_MASK_LINE) 83555706Scg recdev |= 0x18; /* l+r line */ 83655706Scg if (src & SOUND_MASK_SYNTH) 83755706Scg recdev |= 0x60; /* l+r midi */ 83850723Scg sb_setmixer(sb, SB16_IMASK_L, recdev); 83950723Scg sb_setmixer(sb, SB16_IMASK_R, recdev); 84050723Scg /* 84150723Scg * since the same volume controls apply to the input and 84250723Scg * output sections, the best approach to have a consistent 84350723Scg * behaviour among cards would be to disable the output path 84450723Scg * on devices which are used to record. 84550723Scg * However, since users like to have feedback, we only disable 84650723Scg * the mic -- permanently. 84750723Scg */ 84850723Scg sb_setmixer(sb, SB16_OMASK, 0x1f & ~1); 84950723Scg break; 85051768Scg } 85150723Scg return src; 85229415Sjmg} 85329415Sjmg 85429415Sjmgstatic int 85553553Stanimurasbsbc_probe(device_t dev) 85653553Stanimura{ 85754462Scg char buf[64]; 85855092Sdfr uintptr_t func, ver, r, f; 85953553Stanimura 86053553Stanimura /* The parent device has already been probed. */ 86154462Scg r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func); 86254462Scg if (func != SCF_PCM) 86353553Stanimura return (ENXIO); 86453553Stanimura 86554462Scg r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 86654791Scg f = (ver & 0xffff0000) >> 16; 86754462Scg ver &= 0x0000ffff; 86858756Scg if (f & BD_F_ESS) 86958756Scg return (ENXIO); 87058756Scg 87158756Scg snprintf(buf, sizeof buf, "SB DSP %d.%02d%s", (int) ver >> 8, (int) ver & 0xff, 87254793Scg (f & BD_F_SB16X)? " (ViBRA16X)" : ""); 87354462Scg device_set_desc_copy(dev, buf); 87453553Stanimura 87553553Stanimura return 0; 87653553Stanimura} 87753553Stanimura 87853553Stanimurastatic int 87953553Stanimurasbsbc_attach(device_t dev) 88053553Stanimura{ 88153553Stanimura struct sb_info *sb; 88255092Sdfr uintptr_t ver; 88353553Stanimura 88453553Stanimura sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT); 88555706Scg if (!sb) 88655706Scg return ENXIO; 88753553Stanimura bzero(sb, sizeof *sb); 88853553Stanimura 88954462Scg BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 89054462Scg sb->bd_id = ver & 0x0000ffff; 89154462Scg sb->bd_flags = (ver & 0xffff0000) >> 16; 89254462Scg 89353553Stanimura return sb_doattach(dev, sb); 89453553Stanimura} 89553553Stanimura 89653553Stanimurastatic device_method_t sbsbc_methods[] = { 89753553Stanimura /* Device interface */ 89853553Stanimura DEVMETHOD(device_probe, sbsbc_probe), 89953553Stanimura DEVMETHOD(device_attach, sbsbc_attach), 90053553Stanimura 90153553Stanimura { 0, 0 } 90253553Stanimura}; 90353553Stanimura 90453553Stanimurastatic driver_t sbsbc_driver = { 90553553Stanimura "pcm", 90653553Stanimura sbsbc_methods, 90753553Stanimura sizeof(snddev_info), 90853553Stanimura}; 90953553Stanimura 91062483ScgDRIVER_MODULE(snd_sb, sbc, sbsbc_driver, pcm_devclass, 0, 0); 91162483ScgMODULE_DEPEND(snd_sb, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 91262483ScgMODULE_VERSION(snd_sb, 1); 91353553Stanimura 91454462Scg 91554462Scg 91662483Scg 917