sb16.c revision 68376
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 68376 2000-11-06 02:47:43Z cg $ 3229415Sjmg */ 3329415Sjmg 3453465Scg#include <dev/sound/pcm/sound.h> 3529415Sjmg 3653465Scg#include <dev/sound/isa/sb.h> 3753553Stanimura#include <dev/sound/chip.h> 3829415Sjmg 3967803Scg#define SB16_BUFFSIZE 4096 4055706Scg#define PLAIN_SB16(x) ((((x)->bd_flags) & (BD_F_SB16|BD_F_SB16X)) == BD_F_SB16) 4155254Scg 4250723Scg/* channel interface */ 4367803Scgstatic void *sb16chan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir); 4467803Scgstatic int sb16chan_setformat(void *data, u_int32_t format); 4567803Scgstatic int sb16chan_setspeed(void *data, u_int32_t speed); 4667803Scgstatic int sb16chan_setblocksize(void *data, u_int32_t blocksize); 4767803Scgstatic int sb16chan_trigger(void *data, int go); 4867803Scgstatic int sb16chan_getptr(void *data); 4967803Scgstatic pcmchan_caps *sb16chan_getcaps(void *data); 5067803Scgstatic int sb16chan_reset(void *data); 5167803Scgstatic int sb16chan_resetdone(void *data); 5229415Sjmg 5367803Scgstatic u_int32_t sb16_fmt8[] = { 5450723Scg AFMT_U8, 5550723Scg AFMT_STEREO | AFMT_U8, 5664881Scg 0 5750723Scg}; 5867803Scgstatic pcmchan_caps sb16_caps8 = {5000, 45000, sb16_fmt8, 0}; 5929415Sjmg 6067803Scgstatic u_int32_t sb16_fmt16[] = { 6164881Scg AFMT_S16_LE, 6250723Scg AFMT_STEREO | AFMT_S16_LE, 6364881Scg 0 6450723Scg}; 6567803Scgstatic pcmchan_caps sb16_caps16 = {5000, 45000, sb16_fmt16, 0}; 6629415Sjmg 6764881Scgstatic u_int32_t sb16x_fmt[] = { 6864881Scg AFMT_U8, 6964881Scg AFMT_STEREO | AFMT_U8, 7064881Scg AFMT_S16_LE, 7164881Scg AFMT_STEREO | AFMT_S16_LE, 7264881Scg 0 7354462Scg}; 7464881Scgstatic pcmchan_caps sb16x_caps = {5000, 49000, sb16x_fmt, 0}; 7554462Scg 7650723Scgstatic pcm_channel sb_chantemplate = { 7767803Scg sb16chan_init, 7867803Scg NULL, 7967803Scg sb16chan_setformat, 8067803Scg sb16chan_setspeed, 8167803Scg sb16chan_setblocksize, 8267803Scg sb16chan_trigger, 8367803Scg sb16chan_getptr, 8467803Scg sb16chan_getcaps, 8565340Scg NULL, /* free */ 8667803Scg sb16chan_reset, /* reset */ 8767803Scg sb16chan_resetdone, /* resetdone */ 8865340Scg NULL, /* nop3 */ 8965340Scg NULL, /* nop4 */ 9065340Scg NULL, /* nop5 */ 9165340Scg NULL, /* nop6 */ 9265340Scg NULL, /* nop7 */ 9350723Scg}; 9429415Sjmg 9550723Scgstruct sb_info; 9629415Sjmg 9750723Scgstruct sb_chinfo { 9850723Scg struct sb_info *parent; 9950723Scg pcm_channel *channel; 10050723Scg snd_dbuf *buffer; 10167803Scg int dir, run, dch; 10267803Scg u_int32_t fmt, spd, blksz; 10350723Scg}; 10429415Sjmg 10550723Scgstruct sb_info { 10650723Scg struct resource *io_base; /* I/O address for the board */ 10750723Scg struct resource *irq; 10854462Scg struct resource *drq1; 10954462Scg struct resource *drq2; 11065644Scg void *ih; 11155706Scg bus_dma_tag_t parent_dmat; 11229415Sjmg 11350723Scg int bd_id; 11450723Scg u_long bd_flags; /* board-specific flags */ 11567803Scg int dl, dh, prio, prio16; 11650723Scg struct sb_chinfo pch, rch; 11750723Scg}; 11850723Scg 11950723Scgstatic int sb_rd(struct sb_info *sb, int reg); 12050723Scgstatic void sb_wr(struct sb_info *sb, int reg, u_int8_t val); 12150723Scgstatic int sb_dspready(struct sb_info *sb); 12250723Scgstatic int sb_cmd(struct sb_info *sb, u_char val); 12367803Scg/* static int sb_cmd1(struct sb_info *sb, u_char cmd, int val); */ 12450723Scgstatic int sb_cmd2(struct sb_info *sb, u_char cmd, int val); 12550723Scgstatic u_int sb_get_byte(struct sb_info *sb); 12650723Scgstatic void sb_setmixer(struct sb_info *sb, u_int port, u_int value); 12750723Scgstatic int sb_getmixer(struct sb_info *sb, u_int port); 12854462Scgstatic int sb_reset_dsp(struct sb_info *sb); 12929415Sjmg 13050723Scgstatic void sb_intr(void *arg); 13150723Scg 13267803Scgstatic int sb16mix_init(snd_mixer *m); 13367803Scgstatic int sb16mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right); 13467803Scgstatic int sb16mix_setrecsrc(snd_mixer *m, u_int32_t src); 13550723Scg 13667803Scgstatic snd_mixer sb16_mixer = { 13767803Scg "SoundBlaster 16 mixer", 13867803Scg sb16mix_init, 13965340Scg NULL, 14067652Scg NULL, 14167803Scg sb16mix_set, 14267803Scg sb16mix_setrecsrc, 14350723Scg}; 14450723Scg 14550723Scgstatic devclass_t pcm_devclass; 14650723Scg 14729415Sjmg/* 14850723Scg * Common code for the midi and pcm functions 14929415Sjmg * 15050723Scg * sb_cmd write a single byte to the CMD port. 15150723Scg * sb_cmd1 write a CMD + 1 byte arg 15250723Scg * sb_cmd2 write a CMD + 2 byte arg 15350723Scg * sb_get_byte returns a single byte from the DSP data port 15429415Sjmg */ 15529415Sjmg 15629415Sjmgstatic int 15750723Scgport_rd(struct resource *port, int off) 15829415Sjmg{ 15967803Scg return bus_space_read_1(rman_get_bustag(port), rman_get_bushandle(port), off); 16050723Scg} 16129415Sjmg 16250723Scgstatic void 16350723Scgport_wr(struct resource *port, int off, u_int8_t data) 16450723Scg{ 16567803Scg return bus_space_write_1(rman_get_bustag(port), rman_get_bushandle(port), off, data); 16629415Sjmg} 16729415Sjmg 16829415Sjmgstatic int 16950723Scgsb_rd(struct sb_info *sb, int reg) 17029415Sjmg{ 17150723Scg return port_rd(sb->io_base, reg); 17250723Scg} 17329415Sjmg 17450723Scgstatic void 17550723Scgsb_wr(struct sb_info *sb, int reg, u_int8_t val) 17650723Scg{ 17750723Scg port_wr(sb->io_base, reg, val); 17829415Sjmg} 17929415Sjmg 18050723Scgstatic int 18150723Scgsb_dspready(struct sb_info *sb) 18250723Scg{ 18350723Scg return ((sb_rd(sb, SBDSP_STATUS) & 0x80) == 0); 18450723Scg} 18529415Sjmg 18629415Sjmgstatic int 18750723Scgsb_dspwr(struct sb_info *sb, u_char val) 18829415Sjmg{ 18950723Scg int i; 19029415Sjmg 19150723Scg for (i = 0; i < 1000; i++) { 19250723Scg if (sb_dspready(sb)) { 19350723Scg sb_wr(sb, SBDSP_CMD, val); 19450723Scg return 1; 19550723Scg } 19650723Scg if (i > 10) DELAY((i > 100)? 1000 : 10); 19750723Scg } 19850723Scg printf("sb_dspwr(0x%02x) timed out.\n", val); 19950723Scg return 0; 20050723Scg} 20129415Sjmg 20250723Scgstatic int 20350723Scgsb_cmd(struct sb_info *sb, u_char val) 20450723Scg{ 20550723Scg#if 0 20650723Scg printf("sb_cmd: %x\n", val); 20750723Scg#endif 20850723Scg return sb_dspwr(sb, val); 20950723Scg} 21029415Sjmg 21167803Scg/* 21250723Scgstatic int 21350723Scgsb_cmd1(struct sb_info *sb, u_char cmd, int val) 21450723Scg{ 21550723Scg#if 0 21650723Scg printf("sb_cmd1: %x, %x\n", cmd, val); 21750723Scg#endif 21850723Scg if (sb_dspwr(sb, cmd)) { 21950723Scg return sb_dspwr(sb, val & 0xff); 22050723Scg } else return 0; 22150723Scg} 22267803Scg*/ 22329415Sjmg 22450723Scgstatic int 22550723Scgsb_cmd2(struct sb_info *sb, u_char cmd, int val) 22650723Scg{ 22750723Scg#if 0 22850723Scg printf("sb_cmd2: %x, %x\n", cmd, val); 22950723Scg#endif 23050723Scg if (sb_dspwr(sb, cmd)) { 23150723Scg return sb_dspwr(sb, val & 0xff) && 23250723Scg sb_dspwr(sb, (val >> 8) & 0xff); 23350723Scg } else return 0; 23450723Scg} 23529415Sjmg 23650723Scg/* 23750723Scg * in the SB, there is a set of indirect "mixer" registers with 23850723Scg * address at offset 4, data at offset 5 23950723Scg */ 24050723Scgstatic void 24150723Scgsb_setmixer(struct sb_info *sb, u_int port, u_int value) 24250723Scg{ 24350723Scg u_long flags; 24429415Sjmg 24550723Scg flags = spltty(); 24650723Scg sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 24750723Scg DELAY(10); 24850723Scg sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff)); 24950723Scg DELAY(10); 25050723Scg splx(flags); 25150723Scg} 25231361Sjmg 25350723Scgstatic int 25450723Scgsb_getmixer(struct sb_info *sb, u_int port) 25550723Scg{ 25650723Scg int val; 25750723Scg u_long flags; 25829415Sjmg 25950723Scg flags = spltty(); 26050723Scg sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 26150723Scg DELAY(10); 26250723Scg val = sb_rd(sb, SB_MIX_DATA); 26350723Scg DELAY(10); 26450723Scg splx(flags); 26529415Sjmg 26650723Scg return val; 26750723Scg} 26829415Sjmg 26950723Scgstatic u_int 27050723Scgsb_get_byte(struct sb_info *sb) 27150723Scg{ 27250723Scg int i; 27329415Sjmg 27450723Scg for (i = 1000; i > 0; i--) { 27550723Scg if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80) 27650723Scg return sb_rd(sb, DSP_READ); 27750723Scg else 27850723Scg DELAY(20); 27950723Scg } 28050723Scg return 0xffff; 28150723Scg} 28229415Sjmg 28350723Scgstatic int 28450723Scgsb_reset_dsp(struct sb_info *sb) 28529415Sjmg{ 28650723Scg sb_wr(sb, SBDSP_RST, 3); 28750723Scg DELAY(100); 28850723Scg sb_wr(sb, SBDSP_RST, 0); 28950723Scg if (sb_get_byte(sb) != 0xAA) { 29050723Scg DEB(printf("sb_reset_dsp 0x%lx failed\n", 29150723Scg rman_get_start(d->io_base))); 29250723Scg return ENXIO; /* Sorry */ 29350723Scg } 29450723Scg return 0; 29529415Sjmg} 29629415Sjmg 29767803Scg/************************************************************/ 29867803Scg 29967803Scgstruct sb16_mixent { 30067803Scg int reg; 30167803Scg int bits; 30267803Scg int ofs; 30367803Scg int stereo; 30467803Scg}; 30567803Scg 30667803Scgstatic const struct sb16_mixent sb16_mixtab[32] = { 30767803Scg [SOUND_MIXER_VOLUME] = { 0x30, 5, 3, 1 }, 30867803Scg [SOUND_MIXER_PCM] = { 0x32, 5, 3, 1 }, 30967803Scg [SOUND_MIXER_SYNTH] = { 0x34, 5, 3, 1 }, 31067803Scg [SOUND_MIXER_CD] = { 0x36, 5, 3, 1 }, 31167803Scg [SOUND_MIXER_LINE] = { 0x38, 5, 3, 1 }, 31267803Scg [SOUND_MIXER_MIC] = { 0x3a, 5, 3, 0 }, 31367803Scg [SOUND_MIXER_SPEAKER] = { 0x3b, 5, 3, 0 }, 31467803Scg [SOUND_MIXER_IGAIN] = { 0x3f, 2, 6, 1 }, 31567803Scg [SOUND_MIXER_OGAIN] = { 0x41, 2, 6, 1 }, 31667803Scg [SOUND_MIXER_TREBLE] = { 0x44, 4, 4, 1 }, 31767803Scg [SOUND_MIXER_BASS] = { 0x46, 4, 4, 1 }, 31867803Scg}; 31967803Scg 32067803Scgstatic int 32167803Scgsb16mix_init(snd_mixer *m) 32267803Scg{ 32367803Scg struct sb_info *sb = mix_getdevinfo(m); 32467803Scg 32567803Scg mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | 32667803Scg SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | 32767803Scg SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | 32867803Scg SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE); 32967803Scg 33067803Scg mix_setrecdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_LINE | 33167803Scg SOUND_MASK_MIC | SOUND_MASK_CD); 33267803Scg 33367803Scg sb_setmixer(sb, 0x3c, 0x1f); /* make all output active */ 33467803Scg 33567803Scg sb_setmixer(sb, 0x3d, 0); /* make all inputs-l off */ 33667803Scg sb_setmixer(sb, 0x3e, 0); /* make all inputs-r off */ 33767803Scg 33867803Scg return 0; 33967803Scg} 34067803Scg 34167803Scgstatic int 34267803Scgsb16mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) 34367803Scg{ 34467803Scg struct sb_info *sb = mix_getdevinfo(m); 34567803Scg const struct sb16_mixent *e; 34667803Scg int max; 34767803Scg 34867803Scg e = &sb16_mixtab[dev]; 34967803Scg max = (1 << e->bits) - 1; 35067803Scg 35167803Scg left = (left * max) / 100; 35267803Scg right = (right * max) / 100; 35367803Scg 35467803Scg sb_setmixer(sb, e->reg, left << e->ofs); 35567803Scg if (e->stereo) 35668376Scg sb_setmixer(sb, e->reg + 1, right << e->ofs); 35767803Scg else 35867803Scg right = left; 35967803Scg 36067803Scg left = (left * 100) / max; 36167803Scg right = (right * 100) / max; 36267803Scg 36367803Scg return left | (right << 8); 36467803Scg} 36567803Scg 36667803Scgstatic int 36767803Scgsb16mix_setrecsrc(snd_mixer *m, u_int32_t src) 36867803Scg{ 36967803Scg struct sb_info *sb = mix_getdevinfo(m); 37067803Scg u_char recdev; 37167803Scg 37267803Scg recdev = 0; 37367803Scg if (src & SOUND_MASK_MIC) 37467803Scg recdev |= 0x01; /* mono mic */ 37567803Scg 37667803Scg if (src & SOUND_MASK_CD) 37767803Scg recdev |= 0x06; /* l+r cd */ 37867803Scg 37967803Scg if (src & SOUND_MASK_LINE) 38067803Scg recdev |= 0x18; /* l+r line */ 38167803Scg 38267803Scg if (src & SOUND_MASK_SYNTH) 38367803Scg recdev |= 0x60; /* l+r midi */ 38467803Scg 38567803Scg sb_setmixer(sb, SB16_IMASK_L, recdev); 38667803Scg sb_setmixer(sb, SB16_IMASK_R, recdev); 38767803Scg 38867803Scg /* 38967803Scg * since the same volume controls apply to the input and 39067803Scg * output sections, the best approach to have a consistent 39167803Scg * behaviour among cards would be to disable the output path 39267803Scg * on devices which are used to record. 39367803Scg * However, since users like to have feedback, we only disable 39467803Scg * the mic -- permanently. 39567803Scg */ 39667803Scg sb_setmixer(sb, SB16_OMASK, 0x1f & ~1); 39767803Scg 39867803Scg return src; 39967803Scg} 40067803Scg 40167803Scg/************************************************************/ 40267803Scg 40329415Sjmgstatic void 40467803Scgsb16_release_resources(struct sb_info *sb, device_t dev) 40529415Sjmg{ 40650723Scg if (sb->irq) { 40765644Scg if (sb->ih) 40865644Scg bus_teardown_intr(dev, sb->irq, sb->ih); 40965644Scg bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq); 41050723Scg sb->irq = 0; 41150723Scg } 41250723Scg if (sb->drq1) { 41354462Scg bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1); 41450723Scg sb->drq1 = 0; 41550723Scg } 41650723Scg if (sb->drq2) { 41754462Scg bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2); 41850723Scg sb->drq2 = 0; 41950723Scg } 42050723Scg if (sb->io_base) { 42154462Scg bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base); 42250723Scg sb->io_base = 0; 42350723Scg } 42465644Scg if (sb->parent_dmat) { 42565644Scg bus_dma_tag_destroy(sb->parent_dmat); 42665644Scg sb->parent_dmat = 0; 42765644Scg } 42865644Scg free(sb, M_DEVBUF); 42950723Scg} 43029415Sjmg 43150723Scgstatic int 43267803Scgsb16_alloc_resources(struct sb_info *sb, device_t dev) 43350723Scg{ 43454462Scg int rid; 43554462Scg 43654462Scg rid = 0; 43750723Scg if (!sb->io_base) 43867803Scg sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 1, RF_ACTIVE); 43967803Scg 44054462Scg rid = 0; 44150723Scg if (!sb->irq) 44267803Scg sb->irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, RF_ACTIVE); 44367803Scg 44454462Scg rid = 0; 44550723Scg if (!sb->drq1) 44667803Scg sb->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ, &rid, 0, ~0, 1, RF_ACTIVE); 44767803Scg 44854462Scg rid = 1; 44958756Scg if (!sb->drq2) 45067803Scg sb->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ, &rid, 0, ~0, 1, RF_ACTIVE); 45129415Sjmg 45250723Scg if (sb->io_base && sb->drq1 && sb->irq) { 45367803Scg int bs = SB16_BUFFSIZE; 45455424Scg 45554462Scg isa_dma_acquire(rman_get_start(sb->drq1)); 45655424Scg isa_dmainit(rman_get_start(sb->drq1), bs); 45729415Sjmg 45850723Scg if (sb->drq2) { 45954462Scg isa_dma_acquire(rman_get_start(sb->drq2)); 46055424Scg isa_dmainit(rman_get_start(sb->drq2), bs); 46154462Scg } 46250723Scg return 0; 46350723Scg } else return ENXIO; 46429415Sjmg} 46529415Sjmg 46654462Scgstatic void 46767803Scgsb_intr(void *arg) 46829415Sjmg{ 46967803Scg struct sb_info *sb = (struct sb_info *)arg; 47067803Scg int reason = 3, c; 47129415Sjmg 47267803Scg /* 47367803Scg * The Vibra16X has separate flags for 8 and 16 bit transfers, but 47467803Scg * I have no idea how to tell capture from playback interrupts... 47567803Scg */ 47629415Sjmg 47767803Scg reason = 0; 47867803Scg c = sb_getmixer(sb, IRQ_STAT); 47941653Sbrian 48067803Scg /* 48167803Scg * this tells us if the source is 8-bit or 16-bit dma. We 48267803Scg * have to check the io channel to map it to read or write... 48367803Scg */ 48429415Sjmg 48567803Scg if (c & 1) { /* 8-bit dma */ 48667803Scg if (sb->pch.dch == sb->dl) 48767803Scg reason |= 1; 48867803Scg if (sb->rch.dch == sb->dl) 48967803Scg reason |= 2; 49067803Scg } 49129415Sjmg 49267803Scg if (c & 2) { /* 16-bit dma */ 49367803Scg if (sb->pch.dch == sb->dh) 49467803Scg reason |= 1; 49567803Scg if (sb->rch.dch == sb->dh) 49667803Scg reason |= 2; 49750723Scg } 49850723Scg#if 0 49950723Scg printf("sb_intr: reason=%d c=0x%x\n", reason, c); 50050723Scg#endif 50167803Scg if ((reason & 1) && (sb->pch.run)) 50250723Scg chn_intr(sb->pch.channel); 50367803Scg 50467803Scg if ((reason & 2) && (sb->rch.run)) 50550723Scg chn_intr(sb->rch.channel); 50667803Scg 50755706Scg if (c & 1) 50855706Scg sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */ 50967803Scg 51055706Scg if (c & 2) 51155706Scg sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */ 51250723Scg} 51331361Sjmg 51450723Scgstatic int 51567803Scgsb_setup(struct sb_info *sb) 51650723Scg{ 51767803Scg struct sb_chinfo *ch; 51867803Scg u_int8_t v; 51967803Scg int l, pprio; 52029415Sjmg 52167803Scg if (sb->bd_flags & BD_F_DMARUN) 52267803Scg buf_isadma(sb->pch.buffer, PCMTRIG_STOP); 52367803Scg if (sb->bd_flags & BD_F_DMARUN2) 52467803Scg buf_isadma(sb->rch.buffer, PCMTRIG_STOP); 52567803Scg sb->bd_flags &= ~(BD_F_DMARUN | BD_F_DMARUN2); 52629415Sjmg 52767803Scg sb_reset_dsp(sb); 52829415Sjmg 52967803Scg if (sb->bd_flags & BD_F_SB16X) { 53067803Scg sb->pch.buffer->chan = sb->dl; 53167803Scg sb->rch.buffer->chan = sb->dh; 53267803Scg } else { 53367803Scg if (sb->pch.run && sb->rch.run) { 53467803Scg pprio = (sb->rch.fmt & AFMT_16BIT)? 0 : 1; 53567803Scg sb->pch.buffer->chan = pprio? sb->dh : sb->dl; 53667803Scg sb->rch.buffer->chan = pprio? sb->dl : sb->dh; 53767803Scg } else { 53867803Scg if (sb->pch.run) { 53967803Scg sb->pch.buffer->chan = (sb->pch.fmt & AFMT_16BIT)? sb->dh : sb->dl; 54067803Scg sb->rch.buffer->chan = (sb->pch.fmt & AFMT_16BIT)? sb->dl : sb->dh; 54167803Scg } else if (sb->rch.run) { 54267803Scg sb->pch.buffer->chan = (sb->rch.fmt & AFMT_16BIT)? sb->dl : sb->dh; 54367803Scg sb->rch.buffer->chan = (sb->rch.fmt & AFMT_16BIT)? sb->dh : sb->dl; 54467803Scg } 54550723Scg } 54667803Scg } 54729415Sjmg 54867803Scg sb->pch.dch = sb->pch.buffer->chan; 54967803Scg sb->rch.dch = sb->rch.buffer->chan; 55029415Sjmg 55167803Scg sb->pch.buffer->dir = ISADMA_WRITE; 55267803Scg sb->rch.buffer->dir = ISADMA_READ; 55329415Sjmg 55467803Scg /* 55567803Scg printf("setup: pch = %d, pfmt = %d, rch = %d, rfmt = %d\n", 55667803Scg sb->pch.dch, sb->pch.fmt, sb->rch.dch, sb->rch.fmt); 55767803Scg */ 55855706Scg 55967803Scg ch = &sb->pch; 56067803Scg if (ch->run) { 56167803Scg l = ch->blksz; 56267803Scg if (ch->fmt & AFMT_16BIT) 56367803Scg l >>= 1; 56467803Scg l--; 56555706Scg 56667803Scg /* play speed */ 56767803Scg RANGE(ch->spd, 5000, 45000); 56867803Scg sb_cmd(sb, DSP_CMD_OUT16); 56967803Scg sb_cmd(sb, ch->spd >> 8); 57067803Scg sb_cmd(sb, ch->spd & 0xff); 57167803Scg 57267803Scg /* play format, length */ 57367803Scg v = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_F16_DAC; 57467803Scg v |= (ch->fmt & AFMT_16BIT)? DSP_DMA16 : DSP_DMA8; 57567803Scg sb_cmd(sb, v); 57667803Scg 57767803Scg v = (ch->fmt & AFMT_STEREO)? DSP_F16_STEREO : 0; 57867803Scg v |= (ch->fmt & AFMT_SIGNED)? DSP_F16_SIGNED : 0; 57967803Scg sb_cmd2(sb, v, l); 58067803Scg buf_isadma(ch->buffer, PCMTRIG_START); 58167803Scg sb->bd_flags |= BD_F_DMARUN; 58250723Scg } 58350723Scg 58467803Scg ch = &sb->rch; 58567803Scg if (ch->run) { 58667803Scg l = ch->blksz; 58767803Scg if (ch->fmt & AFMT_16BIT) 58867803Scg l >>= 1; 58967803Scg l--; 59029415Sjmg 59167803Scg /* record speed */ 59267803Scg RANGE(ch->spd, 5000, 45000); 59367803Scg sb_cmd(sb, DSP_CMD_IN16); 59467803Scg sb_cmd(sb, ch->spd >> 8); 59567803Scg sb_cmd(sb, ch->spd & 0xff); 59667803Scg 59767803Scg /* record format, length */ 59867803Scg v = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_F16_ADC; 59967803Scg v |= (ch->fmt & AFMT_16BIT)? DSP_DMA16 : DSP_DMA8; 60067803Scg sb_cmd(sb, v); 60167803Scg 60267803Scg v = (ch->fmt & AFMT_STEREO)? DSP_F16_STEREO : 0; 60367803Scg v |= (ch->fmt & AFMT_SIGNED)? DSP_F16_SIGNED : 0; 60467803Scg sb_cmd2(sb, v, l); 60567803Scg buf_isadma(ch->buffer, PCMTRIG_START); 60667803Scg sb->bd_flags |= BD_F_DMARUN2; 60729415Sjmg } 60867803Scg 60967803Scg return 0; 61050723Scg} 61129415Sjmg 61255706Scg/* channel interface */ 61355706Scgstatic void * 61467803Scgsb16chan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) 61555706Scg{ 61655706Scg struct sb_info *sb = devinfo; 61755706Scg struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch; 61855706Scg 61955706Scg ch->parent = sb; 62055706Scg ch->channel = c; 62155706Scg ch->buffer = b; 62267803Scg ch->buffer->bufsize = SB16_BUFFSIZE; 62367803Scg ch->dir = dir; 62467803Scg 62555706Scg if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1) 62655706Scg return NULL; 62767803Scg 62855706Scg return ch; 62955706Scg} 63055706Scg 63155706Scgstatic int 63267803Scgsb16chan_setformat(void *data, u_int32_t format) 63355706Scg{ 63455706Scg struct sb_chinfo *ch = data; 63567803Scg struct sb_info *sb = ch->parent; 63655706Scg 63767803Scg ch->fmt = format; 63867803Scg sb->prio = ch->dir; 63967803Scg sb->prio16 = (ch->fmt & AFMT_16BIT)? 1 : 0; 64067803Scg 64155706Scg return 0; 64255706Scg} 64355706Scg 64455706Scgstatic int 64567803Scgsb16chan_setspeed(void *data, u_int32_t speed) 64655706Scg{ 64755706Scg struct sb_chinfo *ch = data; 64855706Scg 64967803Scg ch->spd = speed; 65067803Scg return speed; 65155706Scg} 65255706Scg 65355706Scgstatic int 65467803Scgsb16chan_setblocksize(void *data, u_int32_t blocksize) 65555706Scg{ 65655706Scg struct sb_chinfo *ch = data; 65755706Scg 65867803Scg ch->blksz = blocksize; 65955706Scg return blocksize; 66055706Scg} 66155706Scg 66255706Scgstatic int 66367803Scgsb16chan_trigger(void *data, int go) 66455706Scg{ 66555706Scg struct sb_chinfo *ch = data; 66667803Scg struct sb_info *sb = ch->parent; 66755706Scg 66860958Scg if (go == PCMTRIG_EMLDMAWR || go == PCMTRIG_EMLDMARD) 66955706Scg return 0; 67055706Scg 67155706Scg if (go == PCMTRIG_START) 67267803Scg ch->run = 1; 67355706Scg else 67467803Scg ch->run = 0; 67568376Scg 67667803Scg sb_setup(sb); 67767803Scg 67855706Scg return 0; 67955706Scg} 68055706Scg 68155706Scgstatic int 68267803Scgsb16chan_getptr(void *data) 68355706Scg{ 68455706Scg struct sb_chinfo *ch = data; 68555706Scg 68655706Scg return buf_isadmaptr(ch->buffer); 68755706Scg} 68855706Scg 68955706Scgstatic pcmchan_caps * 69067803Scgsb16chan_getcaps(void *data) 69155706Scg{ 69255706Scg struct sb_chinfo *ch = data; 69367803Scg struct sb_info *sb = ch->parent; 69455706Scg 69567803Scg if ((sb->prio == 0) || (sb->prio == ch->dir)) 69655706Scg return &sb16x_caps; 69755706Scg else 69867803Scg return sb->prio16? &sb16_caps8 : &sb16_caps16; 69955706Scg} 70055706Scg 70129415Sjmgstatic int 70267803Scgsb16chan_reset(void *data) 70329415Sjmg{ 70467803Scg/* 70567803Scg struct sb_chinfo *ch = data; 70667803Scg struct sb_info *sb = ch->parent; 70767803Scg*/ 70867803Scg return 0; 70950723Scg} 71031361Sjmg 71150723Scgstatic int 71267803Scgsb16chan_resetdone(void *data) 71350723Scg{ 71467803Scg struct sb_chinfo *ch = data; 71567803Scg struct sb_info *sb = ch->parent; 71629415Sjmg 71767803Scg sb->prio = 0; 71829415Sjmg 71967803Scg return 0; 72029415Sjmg} 72129415Sjmg 72267803Scg/************************************************************/ 72329415Sjmg 72429415Sjmgstatic int 72567803Scgsb16_probe(device_t dev) 72653553Stanimura{ 72754462Scg char buf[64]; 72855092Sdfr uintptr_t func, ver, r, f; 72953553Stanimura 73053553Stanimura /* The parent device has already been probed. */ 73154462Scg r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func); 73254462Scg if (func != SCF_PCM) 73353553Stanimura return (ENXIO); 73453553Stanimura 73554462Scg r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 73654791Scg f = (ver & 0xffff0000) >> 16; 73754462Scg ver &= 0x0000ffff; 73867803Scg if (f & BD_F_SB16) { 73967803Scg snprintf(buf, sizeof buf, "SB16 DSP %d.%02d%s", (int) ver >> 8, (int) ver & 0xff, 74067803Scg (f & BD_F_SB16X)? " (ViBRA16X)" : ""); 74167803Scg device_set_desc_copy(dev, buf); 74267803Scg return 0; 74367803Scg } else 74458756Scg return (ENXIO); 74553553Stanimura} 74653553Stanimura 74753553Stanimurastatic int 74867803Scgsb16_attach(device_t dev) 74953553Stanimura{ 75053553Stanimura struct sb_info *sb; 75155092Sdfr uintptr_t ver; 75267803Scg char status[SND_STATUSLEN]; 75367803Scg int bs = SB16_BUFFSIZE; 75453553Stanimura 75553553Stanimura sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT); 75655706Scg if (!sb) 75755706Scg return ENXIO; 75853553Stanimura bzero(sb, sizeof *sb); 75953553Stanimura 76054462Scg BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 76154462Scg sb->bd_id = ver & 0x0000ffff; 76254462Scg sb->bd_flags = (ver & 0xffff0000) >> 16; 76354462Scg 76467803Scg if (sb16_alloc_resources(sb, dev)) 76567803Scg goto no; 76667803Scg if (sb_reset_dsp(sb)) 76767803Scg goto no; 76867803Scg if (mixer_init(dev, &sb16_mixer, sb)) 76967803Scg goto no; 77067803Scg if (bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &sb->ih)) 77167803Scg goto no; 77267803Scg 77367803Scg if (!sb->drq2) 77467803Scg pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 77567803Scg 77667803Scg sb->dl = rman_get_start(sb->drq1); 77767803Scg sb->dh = sb->drq2? rman_get_start(sb->drq2) : sb->dl; 77867803Scg sb->prio = 0; 77967803Scg 78067803Scg if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 78167803Scg /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 78267803Scg /*highaddr*/BUS_SPACE_MAXADDR, 78367803Scg /*filter*/NULL, /*filterarg*/NULL, 78467803Scg /*maxsize*/bs, /*nsegments*/1, 78567803Scg /*maxsegz*/0x3ffff, 78667803Scg /*flags*/0, &sb->parent_dmat) != 0) { 78767803Scg device_printf(dev, "unable to create dma tag\n"); 78867803Scg goto no; 78967803Scg } 79067803Scg 79167803Scg snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld", 79267803Scg rman_get_start(sb->io_base), rman_get_start(sb->irq), 79367803Scg rman_get_start(sb->drq1)); 79467803Scg if (sb->drq2) 79567803Scg snprintf(status + strlen(status), SND_STATUSLEN - strlen(status), 79667803Scg ":%ld", rman_get_start(sb->drq2)); 79767803Scg 79867803Scg if (pcm_register(dev, sb, 1, 1)) 79967803Scg goto no; 80067803Scg pcm_addchan(dev, PCMDIR_REC, &sb_chantemplate, sb); 80167803Scg pcm_addchan(dev, PCMDIR_PLAY, &sb_chantemplate, sb); 80267803Scg 80367803Scg pcm_setstatus(dev, status); 80467803Scg 80567803Scg return 0; 80667803Scg 80767803Scgno: 80867803Scg sb16_release_resources(sb, dev); 80967803Scg return ENXIO; 81053553Stanimura} 81153553Stanimura 81267803Scgstatic int 81367803Scgsb16_detach(device_t dev) 81467803Scg{ 81567803Scg int r; 81667803Scg struct sb_info *sb; 81767803Scg 81867803Scg r = pcm_unregister(dev); 81967803Scg if (r) 82067803Scg return r; 82167803Scg 82267803Scg sb = pcm_getdevinfo(dev); 82367803Scg sb16_release_resources(sb, dev); 82467803Scg return 0; 82567803Scg} 82667803Scg 82767803Scgstatic device_method_t sb16_methods[] = { 82853553Stanimura /* Device interface */ 82967803Scg DEVMETHOD(device_probe, sb16_probe), 83067803Scg DEVMETHOD(device_attach, sb16_attach), 83167803Scg DEVMETHOD(device_detach, sb16_detach), 83253553Stanimura 83353553Stanimura { 0, 0 } 83453553Stanimura}; 83553553Stanimura 83667803Scgstatic driver_t sb16_driver = { 83753553Stanimura "pcm", 83867803Scg sb16_methods, 83953553Stanimura sizeof(snddev_info), 84053553Stanimura}; 84153553Stanimura 84267803ScgDRIVER_MODULE(snd_sb16, sbc, sb16_driver, pcm_devclass, 0, 0); 84367803ScgMODULE_DEPEND(snd_sb16, snd_pcm, PCM_MINVER, PCM_PREFVER, PCM_MAXVER); 84467803ScgMODULE_VERSION(snd_sb16, 1); 84553553Stanimura 84654462Scg 84754462Scg 84862483Scg 849