1139749Simp/*- 2119853Scg * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3166426Sjoel * Copyright (c) 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. 3029415Sjmg */ 3129415Sjmg 32193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 33193640Sariff#include "opt_snd.h" 34193640Sariff#endif 35193640Sariff 3653465Scg#include <dev/sound/pcm/sound.h> 3729415Sjmg 3853465Scg#include <dev/sound/isa/sb.h> 3953553Stanimura#include <dev/sound/chip.h> 4029415Sjmg 41110499Snyan#include <isa/isavar.h> 42110499Snyan 4370134Scg#include "mixer_if.h" 4470134Scg 4582180ScgSND_DECLARE_FILE("$FreeBSD$"); 4682180Scg 4767803Scg#define SB16_BUFFSIZE 4096 4855706Scg#define PLAIN_SB16(x) ((((x)->bd_flags) & (BD_F_SB16|BD_F_SB16X)) == BD_F_SB16) 4955254Scg 5067803Scgstatic u_int32_t sb16_fmt8[] = { 51193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 52193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 5364881Scg 0 5450723Scg}; 5574763Scgstatic struct pcmchan_caps sb16_caps8 = {5000, 45000, sb16_fmt8, 0}; 5629415Sjmg 5767803Scgstatic u_int32_t sb16_fmt16[] = { 58193640Sariff SND_FORMAT(AFMT_S16_LE, 1, 0), 59193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 6064881Scg 0 6150723Scg}; 6274763Scgstatic struct pcmchan_caps sb16_caps16 = {5000, 45000, sb16_fmt16, 0}; 6329415Sjmg 6464881Scgstatic u_int32_t sb16x_fmt[] = { 65193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 66193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 67193640Sariff SND_FORMAT(AFMT_S16_LE, 1, 0), 68193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 6964881Scg 0 7054462Scg}; 7174763Scgstatic struct pcmchan_caps sb16x_caps = {5000, 49000, sb16x_fmt, 0}; 7254462Scg 7350723Scgstruct sb_info; 7429415Sjmg 7550723Scgstruct sb_chinfo { 7650723Scg struct sb_info *parent; 7774763Scg struct pcm_channel *channel; 7874763Scg struct snd_dbuf *buffer; 7967803Scg int dir, run, dch; 8067803Scg u_int32_t fmt, spd, blksz; 8150723Scg}; 8229415Sjmg 8350723Scgstruct sb_info { 8450723Scg struct resource *io_base; /* I/O address for the board */ 8550723Scg struct resource *irq; 8654462Scg struct resource *drq1; 8754462Scg struct resource *drq2; 8865644Scg void *ih; 8955706Scg bus_dma_tag_t parent_dmat; 9029415Sjmg 9184111Scg unsigned int bufsize; 9250723Scg int bd_id; 9350723Scg u_long bd_flags; /* board-specific flags */ 9470291Scg int prio, prio16; 9550723Scg struct sb_chinfo pch, rch; 9674763Scg device_t parent_dev; 9750723Scg}; 9850723Scg 9984111Scg#if 0 10074763Scgstatic void sb_lock(struct sb_info *sb); 10174763Scgstatic void sb_unlock(struct sb_info *sb); 10250723Scgstatic int sb_rd(struct sb_info *sb, int reg); 10350723Scgstatic void sb_wr(struct sb_info *sb, int reg, u_int8_t val); 10450723Scgstatic int sb_cmd(struct sb_info *sb, u_char val); 10567803Scg/* static int sb_cmd1(struct sb_info *sb, u_char cmd, int val); */ 10650723Scgstatic int sb_cmd2(struct sb_info *sb, u_char cmd, int val); 10750723Scgstatic u_int sb_get_byte(struct sb_info *sb); 10850723Scgstatic void sb_setmixer(struct sb_info *sb, u_int port, u_int value); 10950723Scgstatic int sb_getmixer(struct sb_info *sb, u_int port); 11054462Scgstatic int sb_reset_dsp(struct sb_info *sb); 11129415Sjmg 11250723Scgstatic void sb_intr(void *arg); 11384111Scg#endif 11450723Scg 11529415Sjmg/* 11650723Scg * Common code for the midi and pcm functions 11729415Sjmg * 11850723Scg * sb_cmd write a single byte to the CMD port. 11950723Scg * sb_cmd1 write a CMD + 1 byte arg 12050723Scg * sb_cmd2 write a CMD + 2 byte arg 12150723Scg * sb_get_byte returns a single byte from the DSP data port 12229415Sjmg */ 12329415Sjmg 12484111Scgstatic void 12584111Scgsb_lock(struct sb_info *sb) { 12684111Scg 12784111Scg sbc_lock(device_get_softc(sb->parent_dev)); 12884111Scg} 12984111Scg 13084111Scgstatic void 131129180Struckmansb_lockassert(struct sb_info *sb) { 132129180Struckman 133129180Struckman sbc_lockassert(device_get_softc(sb->parent_dev)); 134129180Struckman} 135129180Struckman 136129180Struckmanstatic void 13784111Scgsb_unlock(struct sb_info *sb) { 13884111Scg 13984111Scg sbc_unlock(device_get_softc(sb->parent_dev)); 14084111Scg} 14184111Scg 14229415Sjmgstatic int 14350723Scgport_rd(struct resource *port, int off) 14429415Sjmg{ 14567803Scg return bus_space_read_1(rman_get_bustag(port), rman_get_bushandle(port), off); 14650723Scg} 14729415Sjmg 14850723Scgstatic void 14950723Scgport_wr(struct resource *port, int off, u_int8_t data) 15050723Scg{ 151108064Ssemenu bus_space_write_1(rman_get_bustag(port), rman_get_bushandle(port), off, data); 15229415Sjmg} 15329415Sjmg 15429415Sjmgstatic int 15550723Scgsb_rd(struct sb_info *sb, int reg) 15629415Sjmg{ 15750723Scg return port_rd(sb->io_base, reg); 15850723Scg} 15929415Sjmg 16050723Scgstatic void 16150723Scgsb_wr(struct sb_info *sb, int reg, u_int8_t val) 16250723Scg{ 16350723Scg port_wr(sb->io_base, reg, val); 16429415Sjmg} 16529415Sjmg 16650723Scgstatic int 16750723Scgsb_dspwr(struct sb_info *sb, u_char val) 16829415Sjmg{ 16950723Scg int i; 17029415Sjmg 17150723Scg for (i = 0; i < 1000; i++) { 17270134Scg if ((sb_rd(sb, SBDSP_STATUS) & 0x80)) 17370134Scg DELAY((i > 100)? 1000 : 10); 17470134Scg else { 17570134Scg sb_wr(sb, SBDSP_CMD, val); 17670134Scg return 1; 17750723Scg } 17850723Scg } 17979116Sgreen#if __FreeBSD_version > 500000 18083366Sjulian if (curthread->td_intr_nesting_level == 0) 18174797Scg printf("sb_dspwr(0x%02x) timed out.\n", val); 18279090Sgreen#endif 18350723Scg return 0; 18450723Scg} 18529415Sjmg 18650723Scgstatic int 18750723Scgsb_cmd(struct sb_info *sb, u_char val) 18850723Scg{ 18950723Scg#if 0 19050723Scg printf("sb_cmd: %x\n", val); 19150723Scg#endif 19250723Scg return sb_dspwr(sb, val); 19350723Scg} 19429415Sjmg 19567803Scg/* 19650723Scgstatic int 19750723Scgsb_cmd1(struct sb_info *sb, u_char cmd, int val) 19850723Scg{ 19950723Scg#if 0 20050723Scg printf("sb_cmd1: %x, %x\n", cmd, val); 20150723Scg#endif 20250723Scg if (sb_dspwr(sb, cmd)) { 20350723Scg return sb_dspwr(sb, val & 0xff); 20450723Scg } else return 0; 20550723Scg} 20667803Scg*/ 20729415Sjmg 20850723Scgstatic int 20950723Scgsb_cmd2(struct sb_info *sb, u_char cmd, int val) 21050723Scg{ 21184111Scg int r; 21284111Scg 21350723Scg#if 0 21450723Scg printf("sb_cmd2: %x, %x\n", cmd, val); 21550723Scg#endif 216135115Struckman sb_lockassert(sb); 21784111Scg r = 0; 21850723Scg if (sb_dspwr(sb, cmd)) { 21984111Scg if (sb_dspwr(sb, val & 0xff)) { 22084111Scg if (sb_dspwr(sb, (val >> 8) & 0xff)) { 22184111Scg r = 1; 22284111Scg } 22384111Scg } 22484111Scg } 22584111Scg 22684111Scg return r; 22750723Scg} 22829415Sjmg 22950723Scg/* 23050723Scg * in the SB, there is a set of indirect "mixer" registers with 23150723Scg * address at offset 4, data at offset 5 23250723Scg */ 23350723Scgstatic void 23450723Scgsb_setmixer(struct sb_info *sb, u_int port, u_int value) 23550723Scg{ 23674763Scg sb_lock(sb); 23750723Scg sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 23850723Scg DELAY(10); 23950723Scg sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff)); 24050723Scg DELAY(10); 24174763Scg sb_unlock(sb); 24250723Scg} 24331361Sjmg 24450723Scgstatic int 24550723Scgsb_getmixer(struct sb_info *sb, u_int port) 24650723Scg{ 24750723Scg int val; 24829415Sjmg 249135115Struckman sb_lockassert(sb); 25050723Scg sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 25150723Scg DELAY(10); 25250723Scg val = sb_rd(sb, SB_MIX_DATA); 25350723Scg DELAY(10); 25429415Sjmg 25550723Scg return val; 25650723Scg} 25729415Sjmg 25850723Scgstatic u_int 25950723Scgsb_get_byte(struct sb_info *sb) 26050723Scg{ 26150723Scg int i; 26229415Sjmg 26350723Scg for (i = 1000; i > 0; i--) { 26450723Scg if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80) 26550723Scg return sb_rd(sb, DSP_READ); 26650723Scg else 26750723Scg DELAY(20); 26850723Scg } 26950723Scg return 0xffff; 27050723Scg} 27129415Sjmg 27250723Scgstatic int 27350723Scgsb_reset_dsp(struct sb_info *sb) 27429415Sjmg{ 27574763Scg u_char b; 27674763Scg 277129180Struckman sb_lockassert(sb); 27850723Scg sb_wr(sb, SBDSP_RST, 3); 27950723Scg DELAY(100); 28050723Scg sb_wr(sb, SBDSP_RST, 0); 28174763Scg b = sb_get_byte(sb); 28274763Scg if (b != 0xAA) { 28350723Scg DEB(printf("sb_reset_dsp 0x%lx failed\n", 28489774Sscottl rman_get_start(sb->io_base))); 28550723Scg return ENXIO; /* Sorry */ 28650723Scg } 28750723Scg return 0; 28829415Sjmg} 28929415Sjmg 29067803Scg/************************************************************/ 29167803Scg 29267803Scgstruct sb16_mixent { 29367803Scg int reg; 29467803Scg int bits; 29567803Scg int ofs; 29667803Scg int stereo; 29767803Scg}; 29867803Scg 29967803Scgstatic const struct sb16_mixent sb16_mixtab[32] = { 30067803Scg [SOUND_MIXER_VOLUME] = { 0x30, 5, 3, 1 }, 30167803Scg [SOUND_MIXER_PCM] = { 0x32, 5, 3, 1 }, 30267803Scg [SOUND_MIXER_SYNTH] = { 0x34, 5, 3, 1 }, 30367803Scg [SOUND_MIXER_CD] = { 0x36, 5, 3, 1 }, 30467803Scg [SOUND_MIXER_LINE] = { 0x38, 5, 3, 1 }, 30567803Scg [SOUND_MIXER_MIC] = { 0x3a, 5, 3, 0 }, 30667803Scg [SOUND_MIXER_SPEAKER] = { 0x3b, 5, 3, 0 }, 30767803Scg [SOUND_MIXER_IGAIN] = { 0x3f, 2, 6, 1 }, 30867803Scg [SOUND_MIXER_OGAIN] = { 0x41, 2, 6, 1 }, 30967803Scg [SOUND_MIXER_TREBLE] = { 0x44, 4, 4, 1 }, 31067803Scg [SOUND_MIXER_BASS] = { 0x46, 4, 4, 1 }, 311100953Ssobomax [SOUND_MIXER_LINE1] = { 0x52, 5, 3, 1 } 31267803Scg}; 31367803Scg 31467803Scgstatic int 31574763Scgsb16mix_init(struct snd_mixer *m) 31667803Scg{ 31767803Scg struct sb_info *sb = mix_getdevinfo(m); 31867803Scg 31967803Scg mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | 32067803Scg SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | 321100953Ssobomax SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | SOUND_MASK_LINE1 | 32267803Scg SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE); 32367803Scg 32467803Scg mix_setrecdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_LINE | 325100953Ssobomax SOUND_MASK_LINE1 | SOUND_MASK_MIC | SOUND_MASK_CD); 32667803Scg 32767803Scg sb_setmixer(sb, 0x3c, 0x1f); /* make all output active */ 32867803Scg 32967803Scg sb_setmixer(sb, 0x3d, 0); /* make all inputs-l off */ 33067803Scg sb_setmixer(sb, 0x3e, 0); /* make all inputs-r off */ 33167803Scg 33267803Scg return 0; 33367803Scg} 33467803Scg 33567803Scgstatic int 336130472Sjosefrel2abs_volume(int x, int max) 337130472Sjosef{ 338130472Sjosef int temp; 339130472Sjosef 340130472Sjosef temp = ((x * max) + 50) / 100; 341130472Sjosef if (temp > max) 342130472Sjosef temp = max; 343130472Sjosef else if (temp < 0) 344130472Sjosef temp = 0; 345130472Sjosef return (temp); 346130472Sjosef} 347130472Sjosef 348130472Sjosefstatic int 34974763Scgsb16mix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 35067803Scg{ 35167803Scg struct sb_info *sb = mix_getdevinfo(m); 35267803Scg const struct sb16_mixent *e; 35367803Scg int max; 35467803Scg 35567803Scg e = &sb16_mixtab[dev]; 35667803Scg max = (1 << e->bits) - 1; 35767803Scg 358130472Sjosef left = rel2abs_volume(left, max); 359130472Sjosef right = rel2abs_volume(right, max); 36067803Scg 36167803Scg sb_setmixer(sb, e->reg, left << e->ofs); 36267803Scg if (e->stereo) 36368376Scg sb_setmixer(sb, e->reg + 1, right << e->ofs); 36467803Scg else 36567803Scg right = left; 36667803Scg 36767803Scg left = (left * 100) / max; 36867803Scg right = (right * 100) / max; 36967803Scg 37067803Scg return left | (right << 8); 37167803Scg} 37267803Scg 373193640Sariffstatic u_int32_t 37474763Scgsb16mix_setrecsrc(struct snd_mixer *m, u_int32_t src) 37567803Scg{ 37667803Scg struct sb_info *sb = mix_getdevinfo(m); 377152418Sariff u_char recdev_l, recdev_r; 37867803Scg 379152418Sariff recdev_l = 0; 380152418Sariff recdev_r = 0; 381152418Sariff if (src & SOUND_MASK_MIC) { 382152418Sariff recdev_l |= 0x01; /* mono mic */ 383152418Sariff recdev_r |= 0x01; 384152418Sariff } 38567803Scg 386152418Sariff if (src & SOUND_MASK_CD) { 387152418Sariff recdev_l |= 0x04; /* l cd */ 388152418Sariff recdev_r |= 0x02; /* r cd */ 389152418Sariff } 39067803Scg 391152418Sariff if (src & SOUND_MASK_LINE) { 392152418Sariff recdev_l |= 0x10; /* l line */ 393152418Sariff recdev_r |= 0x08; /* r line */ 394152418Sariff } 39567803Scg 396152418Sariff if (src & SOUND_MASK_SYNTH) { 397152418Sariff recdev_l |= 0x40; /* l midi */ 398152418Sariff recdev_r |= 0x20; /* r midi */ 399152418Sariff } 40067803Scg 401152418Sariff sb_setmixer(sb, SB16_IMASK_L, recdev_l); 402152418Sariff sb_setmixer(sb, SB16_IMASK_R, recdev_r); 40367803Scg 404100953Ssobomax /* Switch on/off FM tuner source */ 405100953Ssobomax if (src & SOUND_MASK_LINE1) 406100953Ssobomax sb_setmixer(sb, 0x4a, 0x0c); 407100953Ssobomax else 408100953Ssobomax sb_setmixer(sb, 0x4a, 0x00); 409100953Ssobomax 41067803Scg /* 41167803Scg * since the same volume controls apply to the input and 41267803Scg * output sections, the best approach to have a consistent 41367803Scg * behaviour among cards would be to disable the output path 41467803Scg * on devices which are used to record. 41567803Scg * However, since users like to have feedback, we only disable 41667803Scg * the mic -- permanently. 41767803Scg */ 41867803Scg sb_setmixer(sb, SB16_OMASK, 0x1f & ~1); 41967803Scg 42067803Scg return src; 42167803Scg} 42267803Scg 42370134Scgstatic kobj_method_t sb16mix_mixer_methods[] = { 42470134Scg KOBJMETHOD(mixer_init, sb16mix_init), 42570134Scg KOBJMETHOD(mixer_set, sb16mix_set), 42670134Scg KOBJMETHOD(mixer_setrecsrc, sb16mix_setrecsrc), 427193640Sariff KOBJMETHOD_END 42870134Scg}; 42970134ScgMIXER_DECLARE(sb16mix_mixer); 43070134Scg 43167803Scg/************************************************************/ 43267803Scg 43329415Sjmgstatic void 43467803Scgsb16_release_resources(struct sb_info *sb, device_t dev) 43529415Sjmg{ 43650723Scg if (sb->irq) { 43765644Scg if (sb->ih) 43865644Scg bus_teardown_intr(dev, sb->irq, sb->ih); 43965644Scg bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq); 44050723Scg sb->irq = 0; 44150723Scg } 44284111Scg if (sb->drq2) { 44384111Scg if (sb->drq2 != sb->drq1) { 44484111Scg isa_dma_release(rman_get_start(sb->drq2)); 44584111Scg bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2); 44684111Scg } 44770291Scg sb->drq2 = 0; 44870291Scg } 44970291Scg if (sb->drq1) { 45074364Scg isa_dma_release(rman_get_start(sb->drq1)); 45154462Scg bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1); 45250723Scg sb->drq1 = 0; 45350723Scg } 45470291Scg if (sb->io_base) { 45554462Scg bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base); 45650723Scg sb->io_base = 0; 45750723Scg } 45865644Scg if (sb->parent_dmat) { 45965644Scg bus_dma_tag_destroy(sb->parent_dmat); 46065644Scg sb->parent_dmat = 0; 46165644Scg } 46265644Scg free(sb, M_DEVBUF); 46350723Scg} 46429415Sjmg 46550723Scgstatic int 46667803Scgsb16_alloc_resources(struct sb_info *sb, device_t dev) 46750723Scg{ 46854462Scg int rid; 46954462Scg 47054462Scg rid = 0; 47150723Scg if (!sb->io_base) 472127135Snjl sb->io_base = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 473127135Snjl &rid, RF_ACTIVE); 47467803Scg 47554462Scg rid = 0; 47650723Scg if (!sb->irq) 477127135Snjl sb->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 478127135Snjl RF_ACTIVE); 47967803Scg 48054462Scg rid = 0; 48150723Scg if (!sb->drq1) 482127135Snjl sb->drq1 = bus_alloc_resource_any(dev, SYS_RES_DRQ, &rid, 483127135Snjl RF_ACTIVE); 48467803Scg 48554462Scg rid = 1; 48658756Scg if (!sb->drq2) 487127135Snjl sb->drq2 = bus_alloc_resource_any(dev, SYS_RES_DRQ, &rid, 488127135Snjl RF_ACTIVE); 48929415Sjmg 49050723Scg if (sb->io_base && sb->drq1 && sb->irq) { 49154462Scg isa_dma_acquire(rman_get_start(sb->drq1)); 49284111Scg isa_dmainit(rman_get_start(sb->drq1), sb->bufsize); 49329415Sjmg 49450723Scg if (sb->drq2) { 49554462Scg isa_dma_acquire(rman_get_start(sb->drq2)); 49684111Scg isa_dmainit(rman_get_start(sb->drq2), sb->bufsize); 49770291Scg } else { 49870291Scg sb->drq2 = sb->drq1; 49970291Scg pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 50054462Scg } 50150723Scg return 0; 50250723Scg } else return ENXIO; 50329415Sjmg} 50429415Sjmg 50574763Scg/* sbc does locking for us */ 50654462Scgstatic void 50767803Scgsb_intr(void *arg) 50829415Sjmg{ 50967803Scg struct sb_info *sb = (struct sb_info *)arg; 510149948Snetchild int reason, c; 51129415Sjmg 51267803Scg /* 51367803Scg * The Vibra16X has separate flags for 8 and 16 bit transfers, but 51467803Scg * I have no idea how to tell capture from playback interrupts... 51567803Scg */ 51629415Sjmg 51767803Scg reason = 0; 51874763Scg sb_lock(sb); 51967803Scg c = sb_getmixer(sb, IRQ_STAT); 52074763Scg if (c & 1) 52174763Scg sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */ 52241653Sbrian 52374763Scg if (c & 2) 52474763Scg sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */ 52574763Scg sb_unlock(sb); 52674763Scg 52767803Scg /* 52867803Scg * this tells us if the source is 8-bit or 16-bit dma. We 52967803Scg * have to check the io channel to map it to read or write... 53067803Scg */ 53129415Sjmg 53268414Scg if (sb->bd_flags & BD_F_SB16X) { 53368414Scg if (c & 1) { /* 8-bit format */ 53468414Scg if (sb->pch.fmt & AFMT_8BIT) 53568414Scg reason |= 1; 53668414Scg if (sb->rch.fmt & AFMT_8BIT) 53768414Scg reason |= 2; 53868414Scg } 53968414Scg if (c & 2) { /* 16-bit format */ 54068414Scg if (sb->pch.fmt & AFMT_16BIT) 54168414Scg reason |= 1; 54268414Scg if (sb->rch.fmt & AFMT_16BIT) 54368414Scg reason |= 2; 54468414Scg } 54568414Scg } else { 54668414Scg if (c & 1) { /* 8-bit dma */ 54770291Scg if (sb->pch.dch == 1) 54868414Scg reason |= 1; 54970291Scg if (sb->rch.dch == 1) 55068414Scg reason |= 2; 55168414Scg } 55268414Scg if (c & 2) { /* 16-bit dma */ 55370291Scg if (sb->pch.dch == 2) 55468414Scg reason |= 1; 55570291Scg if (sb->rch.dch == 2) 55668414Scg reason |= 2; 55768414Scg } 55868414Scg } 55950723Scg#if 0 56050723Scg printf("sb_intr: reason=%d c=0x%x\n", reason, c); 56150723Scg#endif 56267803Scg if ((reason & 1) && (sb->pch.run)) 56350723Scg chn_intr(sb->pch.channel); 56467803Scg 56567803Scg if ((reason & 2) && (sb->rch.run)) 56650723Scg chn_intr(sb->rch.channel); 56750723Scg} 56831361Sjmg 56950723Scgstatic int 57067803Scgsb_setup(struct sb_info *sb) 57150723Scg{ 57267803Scg struct sb_chinfo *ch; 57367803Scg u_int8_t v; 57467803Scg int l, pprio; 57529415Sjmg 57674763Scg sb_lock(sb); 57767803Scg if (sb->bd_flags & BD_F_DMARUN) 578110499Snyan sndbuf_dma(sb->pch.buffer, PCMTRIG_STOP); 57967803Scg if (sb->bd_flags & BD_F_DMARUN2) 580110499Snyan sndbuf_dma(sb->rch.buffer, PCMTRIG_STOP); 58167803Scg sb->bd_flags &= ~(BD_F_DMARUN | BD_F_DMARUN2); 58229415Sjmg 58367803Scg sb_reset_dsp(sb); 58429415Sjmg 58567803Scg if (sb->bd_flags & BD_F_SB16X) { 586149948Snetchild /* full-duplex doesn't work! */ 58768414Scg pprio = sb->pch.run? 1 : 0; 588149948Snetchild sndbuf_dmasetup(sb->pch.buffer, pprio? sb->drq1 : sb->drq2); 58970291Scg sb->pch.dch = pprio? 1 : 0; 590110499Snyan sndbuf_dmasetup(sb->rch.buffer, pprio? sb->drq2 : sb->drq1); 59170291Scg sb->rch.dch = pprio? 2 : 1; 59267803Scg } else { 59367803Scg if (sb->pch.run && sb->rch.run) { 59467803Scg pprio = (sb->rch.fmt & AFMT_16BIT)? 0 : 1; 595110499Snyan sndbuf_dmasetup(sb->pch.buffer, pprio? sb->drq2 : sb->drq1); 59670291Scg sb->pch.dch = pprio? 2 : 1; 597110499Snyan sndbuf_dmasetup(sb->rch.buffer, pprio? sb->drq1 : sb->drq2); 59870291Scg sb->rch.dch = pprio? 1 : 2; 59967803Scg } else { 60067803Scg if (sb->pch.run) { 601110499Snyan sndbuf_dmasetup(sb->pch.buffer, (sb->pch.fmt & AFMT_16BIT)? sb->drq2 : sb->drq1); 60270291Scg sb->pch.dch = (sb->pch.fmt & AFMT_16BIT)? 2 : 1; 603110499Snyan sndbuf_dmasetup(sb->rch.buffer, (sb->pch.fmt & AFMT_16BIT)? sb->drq1 : sb->drq2); 60470291Scg sb->rch.dch = (sb->pch.fmt & AFMT_16BIT)? 1 : 2; 60567803Scg } else if (sb->rch.run) { 606110499Snyan sndbuf_dmasetup(sb->pch.buffer, (sb->rch.fmt & AFMT_16BIT)? sb->drq1 : sb->drq2); 60770291Scg sb->pch.dch = (sb->rch.fmt & AFMT_16BIT)? 1 : 2; 608110499Snyan sndbuf_dmasetup(sb->rch.buffer, (sb->rch.fmt & AFMT_16BIT)? sb->drq2 : sb->drq1); 60970291Scg sb->rch.dch = (sb->rch.fmt & AFMT_16BIT)? 2 : 1; 61067803Scg } 61150723Scg } 61267803Scg } 61329415Sjmg 614110499Snyan sndbuf_dmasetdir(sb->pch.buffer, PCMDIR_PLAY); 615110499Snyan sndbuf_dmasetdir(sb->rch.buffer, PCMDIR_REC); 61629415Sjmg 61767803Scg /* 61868414Scg printf("setup: [pch = %d, pfmt = %d, pgo = %d] [rch = %d, rfmt = %d, rgo = %d]\n", 61968414Scg sb->pch.dch, sb->pch.fmt, sb->pch.run, sb->rch.dch, sb->rch.fmt, sb->rch.run); 62067803Scg */ 62155706Scg 62267803Scg ch = &sb->pch; 62367803Scg if (ch->run) { 62467803Scg l = ch->blksz; 62567803Scg if (ch->fmt & AFMT_16BIT) 62667803Scg l >>= 1; 62767803Scg l--; 62855706Scg 62967803Scg /* play speed */ 63067803Scg RANGE(ch->spd, 5000, 45000); 63167803Scg sb_cmd(sb, DSP_CMD_OUT16); 63267803Scg sb_cmd(sb, ch->spd >> 8); 63367803Scg sb_cmd(sb, ch->spd & 0xff); 63467803Scg 63567803Scg /* play format, length */ 63667803Scg v = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_F16_DAC; 63767803Scg v |= (ch->fmt & AFMT_16BIT)? DSP_DMA16 : DSP_DMA8; 63867803Scg sb_cmd(sb, v); 63967803Scg 640193640Sariff v = (AFMT_CHANNEL(ch->fmt) > 1)? DSP_F16_STEREO : 0; 64167803Scg v |= (ch->fmt & AFMT_SIGNED)? DSP_F16_SIGNED : 0; 64267803Scg sb_cmd2(sb, v, l); 643110499Snyan sndbuf_dma(ch->buffer, PCMTRIG_START); 64467803Scg sb->bd_flags |= BD_F_DMARUN; 64550723Scg } 64650723Scg 64767803Scg ch = &sb->rch; 64867803Scg if (ch->run) { 64967803Scg l = ch->blksz; 65067803Scg if (ch->fmt & AFMT_16BIT) 65167803Scg l >>= 1; 65267803Scg l--; 65329415Sjmg 65467803Scg /* record speed */ 65567803Scg RANGE(ch->spd, 5000, 45000); 65667803Scg sb_cmd(sb, DSP_CMD_IN16); 65767803Scg sb_cmd(sb, ch->spd >> 8); 65867803Scg sb_cmd(sb, ch->spd & 0xff); 65967803Scg 66067803Scg /* record format, length */ 66167803Scg v = DSP_F16_AUTO | DSP_F16_FIFO_ON | DSP_F16_ADC; 66267803Scg v |= (ch->fmt & AFMT_16BIT)? DSP_DMA16 : DSP_DMA8; 66367803Scg sb_cmd(sb, v); 66467803Scg 665193640Sariff v = (AFMT_CHANNEL(ch->fmt) > 1)? DSP_F16_STEREO : 0; 66667803Scg v |= (ch->fmt & AFMT_SIGNED)? DSP_F16_SIGNED : 0; 66767803Scg sb_cmd2(sb, v, l); 668110499Snyan sndbuf_dma(ch->buffer, PCMTRIG_START); 66967803Scg sb->bd_flags |= BD_F_DMARUN2; 67029415Sjmg } 67174763Scg sb_unlock(sb); 67267803Scg 67367803Scg return 0; 67450723Scg} 67529415Sjmg 67655706Scg/* channel interface */ 67755706Scgstatic void * 67874763Scgsb16chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 67955706Scg{ 68055706Scg struct sb_info *sb = devinfo; 68155706Scg struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch; 68255706Scg 68355706Scg ch->parent = sb; 68455706Scg ch->channel = c; 68555706Scg ch->buffer = b; 68667803Scg ch->dir = dir; 68767803Scg 688168847Sariff if (sndbuf_alloc(ch->buffer, sb->parent_dmat, 0, sb->bufsize) != 0) 68955706Scg return NULL; 69067803Scg 69155706Scg return ch; 69255706Scg} 69355706Scg 69455706Scgstatic int 69570134Scgsb16chan_setformat(kobj_t obj, void *data, u_int32_t format) 69655706Scg{ 69755706Scg struct sb_chinfo *ch = data; 69867803Scg struct sb_info *sb = ch->parent; 69955706Scg 70067803Scg ch->fmt = format; 70167803Scg sb->prio = ch->dir; 70267803Scg sb->prio16 = (ch->fmt & AFMT_16BIT)? 1 : 0; 70367803Scg 70455706Scg return 0; 70555706Scg} 70655706Scg 707193640Sariffstatic u_int32_t 70870134Scgsb16chan_setspeed(kobj_t obj, void *data, u_int32_t speed) 70955706Scg{ 71055706Scg struct sb_chinfo *ch = data; 71155706Scg 71267803Scg ch->spd = speed; 71367803Scg return speed; 71455706Scg} 71555706Scg 716193640Sariffstatic u_int32_t 71770134Scgsb16chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 71855706Scg{ 71955706Scg struct sb_chinfo *ch = data; 72055706Scg 72167803Scg ch->blksz = blocksize; 72270291Scg return ch->blksz; 72355706Scg} 72455706Scg 72555706Scgstatic int 72670134Scgsb16chan_trigger(kobj_t obj, void *data, int go) 72755706Scg{ 72855706Scg struct sb_chinfo *ch = data; 72967803Scg struct sb_info *sb = ch->parent; 73055706Scg 731170521Sariff if (!PCMTRIG_COMMON(go)) 73255706Scg return 0; 73355706Scg 73455706Scg if (go == PCMTRIG_START) 73567803Scg ch->run = 1; 73655706Scg else 73767803Scg ch->run = 0; 73868376Scg 73967803Scg sb_setup(sb); 74067803Scg 74155706Scg return 0; 74255706Scg} 74355706Scg 744193640Sariffstatic u_int32_t 74570134Scgsb16chan_getptr(kobj_t obj, void *data) 74655706Scg{ 74755706Scg struct sb_chinfo *ch = data; 74855706Scg 749110499Snyan return sndbuf_dmaptr(ch->buffer); 75055706Scg} 75155706Scg 75274763Scgstatic struct pcmchan_caps * 75370134Scgsb16chan_getcaps(kobj_t obj, void *data) 75455706Scg{ 75555706Scg struct sb_chinfo *ch = data; 75667803Scg struct sb_info *sb = ch->parent; 75755706Scg 75867803Scg if ((sb->prio == 0) || (sb->prio == ch->dir)) 75955706Scg return &sb16x_caps; 76055706Scg else 76167803Scg return sb->prio16? &sb16_caps8 : &sb16_caps16; 76255706Scg} 76355706Scg 76429415Sjmgstatic int 76570134Scgsb16chan_resetdone(kobj_t obj, void *data) 76629415Sjmg{ 76767803Scg struct sb_chinfo *ch = data; 76867803Scg struct sb_info *sb = ch->parent; 76931361Sjmg 77067803Scg sb->prio = 0; 77129415Sjmg 77267803Scg return 0; 77329415Sjmg} 77429415Sjmg 77570134Scgstatic kobj_method_t sb16chan_methods[] = { 77670134Scg KOBJMETHOD(channel_init, sb16chan_init), 77770134Scg KOBJMETHOD(channel_resetdone, sb16chan_resetdone), 77870134Scg KOBJMETHOD(channel_setformat, sb16chan_setformat), 77970134Scg KOBJMETHOD(channel_setspeed, sb16chan_setspeed), 78070134Scg KOBJMETHOD(channel_setblocksize, sb16chan_setblocksize), 78170134Scg KOBJMETHOD(channel_trigger, sb16chan_trigger), 78270134Scg KOBJMETHOD(channel_getptr, sb16chan_getptr), 78370134Scg KOBJMETHOD(channel_getcaps, sb16chan_getcaps), 784193640Sariff KOBJMETHOD_END 78570134Scg}; 78670134ScgCHANNEL_DECLARE(sb16chan); 78770134Scg 78867803Scg/************************************************************/ 78929415Sjmg 79029415Sjmgstatic int 79167803Scgsb16_probe(device_t dev) 79253553Stanimura{ 79354462Scg char buf[64]; 79455092Sdfr uintptr_t func, ver, r, f; 79553553Stanimura 79653553Stanimura /* The parent device has already been probed. */ 79754462Scg r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func); 79854462Scg if (func != SCF_PCM) 79953553Stanimura return (ENXIO); 80053553Stanimura 80154462Scg r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 80254791Scg f = (ver & 0xffff0000) >> 16; 80354462Scg ver &= 0x0000ffff; 80467803Scg if (f & BD_F_SB16) { 80567803Scg snprintf(buf, sizeof buf, "SB16 DSP %d.%02d%s", (int) ver >> 8, (int) ver & 0xff, 80667803Scg (f & BD_F_SB16X)? " (ViBRA16X)" : ""); 80767803Scg device_set_desc_copy(dev, buf); 80867803Scg return 0; 80967803Scg } else 81058756Scg return (ENXIO); 81153553Stanimura} 81253553Stanimura 81353553Stanimurastatic int 81467803Scgsb16_attach(device_t dev) 81553553Stanimura{ 81653553Stanimura struct sb_info *sb; 81755092Sdfr uintptr_t ver; 81884111Scg char status[SND_STATUSLEN], status2[SND_STATUSLEN]; 81953553Stanimura 820170873Sariff sb = malloc(sizeof(*sb), M_DEVBUF, M_WAITOK | M_ZERO); 82174763Scg sb->parent_dev = device_get_parent(dev); 82274763Scg BUS_READ_IVAR(sb->parent_dev, dev, 1, &ver); 82354462Scg sb->bd_id = ver & 0x0000ffff; 82454462Scg sb->bd_flags = (ver & 0xffff0000) >> 16; 82584111Scg sb->bufsize = pcm_getbuffersize(dev, 4096, SB16_BUFFSIZE, 65536); 82654462Scg 827129181Struckman if (sb16_alloc_resources(sb, dev)) 82867803Scg goto no; 829129180Struckman sb_lock(sb); 830129180Struckman if (sb_reset_dsp(sb)) { 831129180Struckman sb_unlock(sb); 83267803Scg goto no; 833129180Struckman } 834129180Struckman sb_unlock(sb); 83570134Scg if (mixer_init(dev, &sb16mix_mixer_class, sb)) 83667803Scg goto no; 837128232Sgreen if (snd_setup_intr(dev, sb->irq, 0, sb_intr, sb, &sb->ih)) 83867803Scg goto no; 83967803Scg 84070291Scg if (sb->bd_flags & BD_F_SB16X) 84167803Scg pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 84267803Scg 84367803Scg sb->prio = 0; 84467803Scg 845166904Snetchild if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 846166904Snetchild /*boundary*/0, 84767803Scg /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 84867803Scg /*highaddr*/BUS_SPACE_MAXADDR, 84967803Scg /*filter*/NULL, /*filterarg*/NULL, 85084111Scg /*maxsize*/sb->bufsize, /*nsegments*/1, 851117126Sscottl /*maxsegz*/0x3ffff, /*flags*/0, 852117126Sscottl /*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant, 853117126Sscottl &sb->parent_dmat) != 0) { 85467803Scg device_printf(dev, "unable to create dma tag\n"); 85567803Scg goto no; 85667803Scg } 85767803Scg 85870291Scg if (!(pcm_getflags(dev) & SD_F_SIMPLEX)) 85984111Scg snprintf(status2, SND_STATUSLEN, ":%ld", rman_get_start(sb->drq2)); 86084111Scg else 86184111Scg status2[0] = '\0'; 86267803Scg 863152418Sariff snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u %s", 86484111Scg rman_get_start(sb->io_base), rman_get_start(sb->irq), 865126695Smatk rman_get_start(sb->drq1), status2, sb->bufsize, 866126695Smatk PCM_KLDSTRING(snd_sb16)); 86784111Scg 86867803Scg if (pcm_register(dev, sb, 1, 1)) 86967803Scg goto no; 87070134Scg pcm_addchan(dev, PCMDIR_REC, &sb16chan_class, sb); 87170134Scg pcm_addchan(dev, PCMDIR_PLAY, &sb16chan_class, sb); 87267803Scg 87367803Scg pcm_setstatus(dev, status); 87467803Scg 87567803Scg return 0; 87667803Scg 87767803Scgno: 87867803Scg sb16_release_resources(sb, dev); 87967803Scg return ENXIO; 88053553Stanimura} 88153553Stanimura 88267803Scgstatic int 88367803Scgsb16_detach(device_t dev) 88467803Scg{ 88567803Scg int r; 88667803Scg struct sb_info *sb; 88767803Scg 88867803Scg r = pcm_unregister(dev); 88967803Scg if (r) 89067803Scg return r; 89167803Scg 89267803Scg sb = pcm_getdevinfo(dev); 89367803Scg sb16_release_resources(sb, dev); 89467803Scg return 0; 89567803Scg} 89667803Scg 89767803Scgstatic device_method_t sb16_methods[] = { 89853553Stanimura /* Device interface */ 89967803Scg DEVMETHOD(device_probe, sb16_probe), 90067803Scg DEVMETHOD(device_attach, sb16_attach), 90167803Scg DEVMETHOD(device_detach, sb16_detach), 90253553Stanimura 90353553Stanimura { 0, 0 } 90453553Stanimura}; 90553553Stanimura 90667803Scgstatic driver_t sb16_driver = { 90753553Stanimura "pcm", 90867803Scg sb16_methods, 90982180Scg PCM_SOFTC_SIZE, 91053553Stanimura}; 91153553Stanimura 91267803ScgDRIVER_MODULE(snd_sb16, sbc, sb16_driver, pcm_devclass, 0, 0); 913132236StanimuraMODULE_DEPEND(snd_sb16, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 91474763ScgMODULE_DEPEND(snd_sb16, snd_sbc, 1, 1, 1); 91567803ScgMODULE_VERSION(snd_sb16, 1); 916