sb16.c revision 54791
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 54791 1999-12-18 22:21:47Z cg $ 3229415Sjmg */ 3329415Sjmg 3453465Scg#include <dev/sound/pcm/sound.h> 3529415Sjmg 3653553Stanimura#include "sbc.h" 3753553Stanimura 3829415Sjmg#define __SB_MIXER_C__ /* XXX warning... */ 3953465Scg#include <dev/sound/isa/sb.h> 4053553Stanimura#include <dev/sound/chip.h> 4129415Sjmg 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 5250925Scg/* channel interface for ESS */ 5350925Scg#ifdef notyet 5450925Scgstatic void *esschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir); 5550925Scg#endif 5650925Scgstatic int esschan_setdir(void *data, int dir); 5750925Scgstatic int esschan_setformat(void *data, u_int32_t format); 5850925Scgstatic int esschan_setspeed(void *data, u_int32_t speed); 5950925Scgstatic int esschan_setblocksize(void *data, u_int32_t blocksize); 6050925Scgstatic int esschan_trigger(void *data, int go); 6150925Scgstatic int esschan_getptr(void *data); 6250925Scgstatic pcmchan_caps *esschan_getcaps(void *data); 6354462Scg 6450723Scgstatic pcmchan_caps sb_playcaps = { 6550723Scg 4000, 22050, 6650723Scg AFMT_U8, 6750723Scg AFMT_U8 6850723Scg}; 6929415Sjmg 7050723Scgstatic pcmchan_caps sb_reccaps = { 7150723Scg 4000, 13000, 7250723Scg AFMT_U8, 7350723Scg AFMT_U8 7450723Scg}; 7529415Sjmg 7650723Scgstatic pcmchan_caps sbpro_playcaps = { 7750723Scg 4000, 45000, 7850723Scg AFMT_STEREO | AFMT_U8, 7950723Scg AFMT_STEREO | AFMT_U8 8050723Scg}; 8129415Sjmg 8250723Scgstatic pcmchan_caps sbpro_reccaps = { 8350723Scg 4000, 15000, 8450723Scg AFMT_STEREO | AFMT_U8, 8550723Scg AFMT_STEREO | AFMT_U8 8650723Scg}; 8729415Sjmg 8854462Scgstatic pcmchan_caps sb16_hcaps = { 8950723Scg 5000, 45000, 9050723Scg AFMT_STEREO | AFMT_S16_LE, 9150723Scg AFMT_STEREO | AFMT_S16_LE 9250723Scg}; 9329415Sjmg 9454462Scgstatic pcmchan_caps sb16_lcaps = { 9550723Scg 5000, 45000, 9650723Scg AFMT_STEREO | AFMT_U8, 9750723Scg AFMT_STEREO | AFMT_U8 9850723Scg}; 9929415Sjmg 10054462Scgstatic pcmchan_caps sb16x_caps = { 10154462Scg 5000, 49000, 10254462Scg AFMT_STEREO | AFMT_U8 /* | AFMT_S16_LE */, 10354462Scg AFMT_STEREO | AFMT_U8 /* AFMT_S16_LE */ 10454462Scg}; 10554462Scg 10650723Scgstatic pcmchan_caps ess_playcaps = { 10750723Scg 5000, 49000, 10850723Scg AFMT_STEREO | AFMT_U8 | AFMT_S16_LE, 10950723Scg AFMT_STEREO | AFMT_S16_LE 11050723Scg}; 11129415Sjmg 11250723Scgstatic pcmchan_caps ess_reccaps = { 11350723Scg 5000, 49000, 11450723Scg AFMT_STEREO | AFMT_U8 | AFMT_S16_LE, 11550723Scg AFMT_STEREO | AFMT_S16_LE 11650723Scg}; 11729415Sjmg 11850723Scgstatic pcm_channel sb_chantemplate = { 11950723Scg sbchan_init, 12050723Scg sbchan_setdir, 12150723Scg sbchan_setformat, 12250723Scg sbchan_setspeed, 12350723Scg sbchan_setblocksize, 12450723Scg sbchan_trigger, 12550723Scg sbchan_getptr, 12650723Scg sbchan_getcaps, 12750723Scg}; 12829415Sjmg 12950925Scgstatic pcm_channel ess_chantemplate = { 13050925Scg sbchan_init, 13150925Scg esschan_setdir, 13250925Scg esschan_setformat, 13350925Scg esschan_setspeed, 13450925Scg esschan_setblocksize, 13550925Scg esschan_trigger, 13650925Scg esschan_getptr, 13750925Scg esschan_getcaps, 13850925Scg}; 13950723Scg#define PLAIN_SB16(x) ((((x)->bd_flags) & (BD_F_SB16|BD_F_SB16X)) == BD_F_SB16) 14029415Sjmg 14150723Scgstruct sb_info; 14229415Sjmg 14350723Scgstruct sb_chinfo { 14450723Scg struct sb_info *parent; 14550723Scg pcm_channel *channel; 14650723Scg snd_dbuf *buffer; 14750723Scg int dir; 14850723Scg u_int32_t fmt; 14950925Scg int ess_dma_started; 15050723Scg}; 15129415Sjmg 15250723Scgstruct sb_info { 15350723Scg struct resource *io_base; /* I/O address for the board */ 15450723Scg struct resource *irq; 15554462Scg struct resource *drq1; 15654462Scg struct resource *drq2; 15750723Scg bus_dma_tag_t parent_dmat; 15829415Sjmg 15950723Scg int bd_id; 16050723Scg u_long bd_flags; /* board-specific flags */ 16150723Scg struct sb_chinfo pch, rch; 16250723Scg}; 16350723Scg 16450723Scgstatic int sb_rd(struct sb_info *sb, int reg); 16550723Scgstatic void sb_wr(struct sb_info *sb, int reg, u_int8_t val); 16650723Scgstatic int sb_dspready(struct sb_info *sb); 16750723Scgstatic int sb_cmd(struct sb_info *sb, u_char val); 16850723Scgstatic int sb_cmd1(struct sb_info *sb, u_char cmd, int val); 16950723Scgstatic int sb_cmd2(struct sb_info *sb, u_char cmd, int val); 17050723Scgstatic u_int sb_get_byte(struct sb_info *sb); 17150723Scgstatic void sb_setmixer(struct sb_info *sb, u_int port, u_int value); 17250723Scgstatic int sb_getmixer(struct sb_info *sb, u_int port); 17354462Scgstatic int sb_reset_dsp(struct sb_info *sb); 17429415Sjmg 17550723Scgstatic void sb_intr(void *arg); 17650723Scgstatic int sb_format(struct sb_chinfo *ch, u_int32_t format); 17750723Scgstatic int sb_speed(struct sb_chinfo *ch, int speed); 17850723Scgstatic int sb_start(struct sb_chinfo *ch); 17950723Scgstatic int sb_stop(struct sb_chinfo *ch); 18050723Scg 18154462Scgstatic int ess_write(struct sb_info *sb, u_char reg, int val); 18254462Scgstatic int ess_read(struct sb_info *sb, u_char reg); 18354462Scgstatic void ess_intr(void *arg); 18450925Scgstatic int ess_format(struct sb_chinfo *ch, u_int32_t format); 18550925Scgstatic int ess_speed(struct sb_chinfo *ch, int speed); 18650925Scgstatic int ess_start(struct sb_chinfo *ch); 18750925Scgstatic int ess_stop(struct sb_chinfo *ch); 18850925Scgstatic int ess_abort(struct sb_chinfo *ch); 18954462Scg 19050723Scgstatic int sbmix_init(snd_mixer *m); 19150723Scgstatic int sbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right); 19250723Scgstatic int sbmix_setrecsrc(snd_mixer *m, u_int32_t src); 19350723Scg 19450723Scgstatic snd_mixer sb_mixer = { 19550723Scg "SoundBlaster mixer", 19650723Scg sbmix_init, 19750723Scg sbmix_set, 19850723Scg sbmix_setrecsrc, 19950723Scg}; 20050723Scg 20150723Scgstatic devclass_t pcm_devclass; 20250723Scg 20329415Sjmg/* 20450723Scg * Common code for the midi and pcm functions 20529415Sjmg * 20650723Scg * sb_cmd write a single byte to the CMD port. 20750723Scg * sb_cmd1 write a CMD + 1 byte arg 20850723Scg * sb_cmd2 write a CMD + 2 byte arg 20950723Scg * sb_get_byte returns a single byte from the DSP data port 21050723Scg * 21150723Scg * ess_write is actually sb_cmd1 21250723Scg * ess_read access ext. regs via sb_cmd(0xc0, reg) followed by sb_get_byte 21329415Sjmg */ 21429415Sjmg 21529415Sjmgstatic int 21650723Scgport_rd(struct resource *port, int off) 21729415Sjmg{ 21850723Scg return bus_space_read_1(rman_get_bustag(port), 21950723Scg rman_get_bushandle(port), 22050723Scg off); 22150723Scg} 22229415Sjmg 22350723Scgstatic void 22450723Scgport_wr(struct resource *port, int off, u_int8_t data) 22550723Scg{ 22650723Scg return bus_space_write_1(rman_get_bustag(port), 22750723Scg rman_get_bushandle(port), 22850723Scg off, data); 22929415Sjmg} 23029415Sjmg 23129415Sjmgstatic int 23250723Scgsb_rd(struct sb_info *sb, int reg) 23329415Sjmg{ 23450723Scg return port_rd(sb->io_base, reg); 23550723Scg} 23629415Sjmg 23750723Scgstatic void 23850723Scgsb_wr(struct sb_info *sb, int reg, u_int8_t val) 23950723Scg{ 24050723Scg port_wr(sb->io_base, reg, val); 24129415Sjmg} 24229415Sjmg 24350723Scgstatic int 24450723Scgsb_dspready(struct sb_info *sb) 24550723Scg{ 24650723Scg return ((sb_rd(sb, SBDSP_STATUS) & 0x80) == 0); 24750723Scg} 24829415Sjmg 24929415Sjmgstatic int 25050723Scgsb_dspwr(struct sb_info *sb, u_char val) 25129415Sjmg{ 25250723Scg int i; 25329415Sjmg 25450723Scg for (i = 0; i < 1000; i++) { 25550723Scg if (sb_dspready(sb)) { 25650723Scg sb_wr(sb, SBDSP_CMD, val); 25750723Scg return 1; 25850723Scg } 25950723Scg if (i > 10) DELAY((i > 100)? 1000 : 10); 26050723Scg } 26150723Scg printf("sb_dspwr(0x%02x) timed out.\n", val); 26250723Scg return 0; 26350723Scg} 26429415Sjmg 26550723Scgstatic int 26650723Scgsb_cmd(struct sb_info *sb, u_char val) 26750723Scg{ 26850723Scg#if 0 26950723Scg printf("sb_cmd: %x\n", val); 27050723Scg#endif 27150723Scg return sb_dspwr(sb, val); 27250723Scg} 27329415Sjmg 27450723Scgstatic int 27550723Scgsb_cmd1(struct sb_info *sb, u_char cmd, int val) 27650723Scg{ 27750723Scg#if 0 27850723Scg printf("sb_cmd1: %x, %x\n", cmd, val); 27950723Scg#endif 28050723Scg if (sb_dspwr(sb, cmd)) { 28150723Scg return sb_dspwr(sb, val & 0xff); 28250723Scg } else return 0; 28350723Scg} 28429415Sjmg 28550723Scgstatic int 28650723Scgsb_cmd2(struct sb_info *sb, u_char cmd, int val) 28750723Scg{ 28850723Scg#if 0 28950723Scg printf("sb_cmd2: %x, %x\n", cmd, val); 29050723Scg#endif 29150723Scg if (sb_dspwr(sb, cmd)) { 29250723Scg return sb_dspwr(sb, val & 0xff) && 29350723Scg sb_dspwr(sb, (val >> 8) & 0xff); 29450723Scg } else return 0; 29550723Scg} 29629415Sjmg 29750723Scg/* 29850723Scg * in the SB, there is a set of indirect "mixer" registers with 29950723Scg * address at offset 4, data at offset 5 30050723Scg */ 30150723Scgstatic void 30250723Scgsb_setmixer(struct sb_info *sb, u_int port, u_int value) 30350723Scg{ 30450723Scg u_long flags; 30529415Sjmg 30650723Scg flags = spltty(); 30750723Scg sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 30850723Scg DELAY(10); 30950723Scg sb_wr(sb, SB_MIX_DATA, (u_char) (value & 0xff)); 31050723Scg DELAY(10); 31150723Scg splx(flags); 31250723Scg} 31331361Sjmg 31450723Scgstatic int 31550723Scgsb_getmixer(struct sb_info *sb, u_int port) 31650723Scg{ 31750723Scg int val; 31850723Scg u_long flags; 31929415Sjmg 32050723Scg flags = spltty(); 32150723Scg sb_wr(sb, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 32250723Scg DELAY(10); 32350723Scg val = sb_rd(sb, SB_MIX_DATA); 32450723Scg DELAY(10); 32550723Scg splx(flags); 32629415Sjmg 32750723Scg return val; 32850723Scg} 32929415Sjmg 33050723Scgstatic u_int 33150723Scgsb_get_byte(struct sb_info *sb) 33250723Scg{ 33350723Scg int i; 33429415Sjmg 33550723Scg for (i = 1000; i > 0; i--) { 33650723Scg if (sb_rd(sb, DSP_DATA_AVAIL) & 0x80) 33750723Scg return sb_rd(sb, DSP_READ); 33850723Scg else 33950723Scg DELAY(20); 34050723Scg } 34150723Scg return 0xffff; 34250723Scg} 34329415Sjmg 34450723Scgstatic int 34550723Scgess_write(struct sb_info *sb, u_char reg, int val) 34650723Scg{ 34750723Scg return sb_cmd1(sb, reg, val); 34829415Sjmg} 34929415Sjmg 35029415Sjmgstatic int 35150723Scgess_read(struct sb_info *sb, u_char reg) 35229415Sjmg{ 35350723Scg return (sb_cmd(sb, 0xc0) && sb_cmd(sb, reg))? sb_get_byte(sb) : 0xffff; 35429415Sjmg} 35529415Sjmg 35629415Sjmgstatic int 35750723Scgsb_reset_dsp(struct sb_info *sb) 35829415Sjmg{ 35950723Scg sb_wr(sb, SBDSP_RST, 3); 36050723Scg DELAY(100); 36150723Scg sb_wr(sb, SBDSP_RST, 0); 36250723Scg if (sb_get_byte(sb) != 0xAA) { 36350723Scg DEB(printf("sb_reset_dsp 0x%lx failed\n", 36450723Scg rman_get_start(d->io_base))); 36550723Scg return ENXIO; /* Sorry */ 36650723Scg } 36750723Scg if (sb->bd_flags & BD_F_ESS) sb_cmd(sb, 0xc6); 36850723Scg return 0; 36929415Sjmg} 37029415Sjmg 37129415Sjmgstatic void 37250723Scgsb_release_resources(struct sb_info *sb, device_t dev) 37329415Sjmg{ 37450723Scg /* should we bus_teardown_intr here? */ 37550723Scg if (sb->irq) { 37654462Scg bus_release_resource(dev, SYS_RES_IRQ, 0, sb->irq); 37750723Scg sb->irq = 0; 37850723Scg } 37950723Scg if (sb->drq1) { 38054462Scg bus_release_resource(dev, SYS_RES_DRQ, 0, sb->drq1); 38150723Scg sb->drq1 = 0; 38250723Scg } 38350723Scg if (sb->drq2) { 38454462Scg bus_release_resource(dev, SYS_RES_DRQ, 1, sb->drq2); 38550723Scg sb->drq2 = 0; 38650723Scg } 38750723Scg if (sb->io_base) { 38854462Scg bus_release_resource(dev, SYS_RES_IOPORT, 0, sb->io_base); 38950723Scg sb->io_base = 0; 39050723Scg } 39150723Scg free(sb, M_DEVBUF); 39250723Scg} 39329415Sjmg 39450723Scgstatic int 39550723Scgsb_alloc_resources(struct sb_info *sb, device_t dev) 39650723Scg{ 39754462Scg int rid; 39854462Scg 39954462Scg rid = 0; 40050723Scg if (!sb->io_base) 40150723Scg sb->io_base = bus_alloc_resource(dev, SYS_RES_IOPORT, 40254462Scg &rid, 0, ~0, 1, 40350723Scg RF_ACTIVE); 40454462Scg rid = 0; 40550723Scg if (!sb->irq) 40650723Scg sb->irq = bus_alloc_resource(dev, SYS_RES_IRQ, 40754462Scg &rid, 0, ~0, 1, 40850723Scg RF_ACTIVE); 40954462Scg rid = 0; 41050723Scg if (!sb->drq1) 41150723Scg sb->drq1 = bus_alloc_resource(dev, SYS_RES_DRQ, 41254462Scg &rid, 0, ~0, 1, 41350723Scg RF_ACTIVE); 41454462Scg rid = 1; 41554462Scg if (!sb->drq2) 41650723Scg sb->drq2 = bus_alloc_resource(dev, SYS_RES_DRQ, 41754462Scg &rid, 0, ~0, 1, 41850723Scg RF_ACTIVE); 41929415Sjmg 42050723Scg if (sb->io_base && sb->drq1 && sb->irq) { 42154462Scg isa_dma_acquire(rman_get_start(sb->drq1)); 42254462Scg isa_dmainit(rman_get_start(sb->drq1), DSP_BUFFSIZE); 42329415Sjmg 42450723Scg if (sb->drq2) { 42554462Scg isa_dma_acquire(rman_get_start(sb->drq2)); 42654462Scg isa_dmainit(rman_get_start(sb->drq2), DSP_BUFFSIZE); 42754462Scg } 42850723Scg 42950723Scg return 0; 43050723Scg } else return ENXIO; 43129415Sjmg} 43229415Sjmg 43354462Scgstatic void 43454462Scgsb16_swap(void *v, int dir) 43529415Sjmg{ 43654462Scg struct sb_info *sb = v; 43754462Scg int pb = sb->pch.buffer->dl; 43854462Scg int rb = sb->rch.buffer->dl; 43954462Scg int pc = sb->pch.buffer->chan; 44054462Scg int rc = sb->rch.buffer->chan; 44154462Scg int swp = 0; 44229415Sjmg 44354462Scg if (!pb && !rb) { 44454462Scg if (dir == PCMDIR_PLAY && pc < 4) swp = 1; 44554462Scg else if (dir == PCMDIR_REC && rc < 4) swp = 1; 44654462Scg if (sb->bd_flags & BD_F_SB16X) swp = !swp; 44754462Scg if (swp) { 44854462Scg int t; 44929415Sjmg 45054462Scg t = sb->pch.buffer->chan; 45154462Scg sb->pch.buffer->chan = sb->rch.buffer->chan; 45254462Scg sb->rch.buffer->chan = t; 45354462Scg sb->pch.buffer->dir = B_WRITE; 45454462Scg sb->rch.buffer->dir = B_READ; 45531361Sjmg } 45654462Scg } 45750723Scg} 45841653Sbrian 45950723Scgstatic int 46050723Scgsb_doattach(device_t dev, struct sb_info *sb) 46129415Sjmg{ 46250723Scg snddev_info *d = device_get_softc(dev); 46350723Scg void *ih; 46450723Scg char status[SND_STATUSLEN]; 46529415Sjmg 46650723Scg if (sb_alloc_resources(sb, dev)) goto no; 46754462Scg if (sb_reset_dsp(sb)) goto no; 46854462Scg mixer_init(d, &sb_mixer, sb); 46929415Sjmg 47050925Scg if (sb->bd_flags & BD_F_ESS) 47150925Scg bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, ess_intr, sb, &ih); 47250925Scg else 47350925Scg bus_setup_intr(dev, sb->irq, INTR_TYPE_TTY, sb_intr, sb, &ih); 47454462Scg if ((sb->bd_flags & BD_F_SB16) && !(sb->bd_flags & BD_F_SB16X)) 47554462Scg pcm_setswap(dev, sb16_swap); 47654462Scg if (!sb->drq2) 47754462Scg pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 47829415Sjmg 47950723Scg if (bus_dma_tag_create(/*parent*/NULL, /*alignment*/2, /*boundary*/0, 48050723Scg /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 48150723Scg /*highaddr*/BUS_SPACE_MAXADDR, 48250723Scg /*filter*/NULL, /*filterarg*/NULL, 48350723Scg /*maxsize*/DSP_BUFFSIZE, /*nsegments*/1, 48450723Scg /*maxsegz*/0x3ffff, 48550723Scg /*flags*/0, &sb->parent_dmat) != 0) { 48650723Scg device_printf(dev, "unable to create dma tag\n"); 48750723Scg goto no; 48850723Scg } 48929415Sjmg 49054462Scg snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld", 49150723Scg rman_get_start(sb->io_base), rman_get_start(sb->irq), 49254462Scg rman_get_start(sb->drq1)); 49354462Scg if (sb->drq2) snprintf(status + strlen(status), SND_STATUSLEN - strlen(status), 49454462Scg ":%ld", rman_get_start(sb->drq2)); 49529415Sjmg 49650723Scg if (pcm_register(dev, sb, 1, 1)) goto no; 49750925Scg if (sb->bd_flags & BD_F_ESS) { 49850925Scg pcm_addchan(dev, PCMDIR_REC, &ess_chantemplate, sb); 49950925Scg pcm_addchan(dev, PCMDIR_PLAY, &ess_chantemplate, sb); 50050925Scg } else { 50150925Scg pcm_addchan(dev, PCMDIR_REC, &sb_chantemplate, sb); 50250925Scg pcm_addchan(dev, PCMDIR_PLAY, &sb_chantemplate, sb); 50350925Scg } 50450723Scg pcm_setstatus(dev, status); 50529415Sjmg 50650723Scg return 0; 50729415Sjmg 50850723Scgno: 50950723Scg sb_release_resources(sb, dev); 51050723Scg return ENXIO; 51150723Scg} 51229415Sjmg 51350723Scgstatic void 51450723Scgsb_intr(void *arg) 51550723Scg{ 51650723Scg struct sb_info *sb = (struct sb_info *)arg; 51750723Scg int reason = 3, c; 51829415Sjmg 51950723Scg /* 52050723Scg * SB < 4.0 is half duplex and has only 1 bit for int source, 52150723Scg * so we fake it. SB 4.x (SB16) has the int source in a separate 52250723Scg * register. 52350723Scg * The Vibra16X has separate flags for 8 and 16 bit transfers, but 52450723Scg * I have no idea how to tell capture from playback interrupts... 52550723Scg */ 52650723Scg if (sb->bd_flags & BD_F_SB16) { 52750723Scg c = sb_getmixer(sb, IRQ_STAT); 52850723Scg /* this tells us if the source is 8-bit or 16-bit dma. We 52950723Scg * have to check the io channel to map it to read or write... 53050723Scg */ 53150723Scg reason = 0; 53250723Scg if (c & 1) { /* 8-bit dma */ 53350723Scg if (sb->pch.fmt & AFMT_U8) reason |= 1; 53450723Scg if (sb->rch.fmt & AFMT_U8) reason |= 2; 53550723Scg } 53650723Scg if (c & 2) { /* 16-bit dma */ 53750723Scg if (sb->pch.fmt & AFMT_S16_LE) reason |= 1; 53850723Scg if (sb->rch.fmt & AFMT_S16_LE) reason |= 2; 53950723Scg } 54050723Scg } else c = 1; 54150723Scg#if 0 54250723Scg printf("sb_intr: reason=%d c=0x%x\n", reason, c); 54350723Scg#endif 54450723Scg if ((reason & 1) && (sb->pch.buffer->dl > 0)) 54550723Scg chn_intr(sb->pch.channel); 54650723Scg if ((reason & 2) && (sb->rch.buffer->dl > 0)) 54750723Scg chn_intr(sb->rch.channel); 54850723Scg if (c & 1) sb_rd(sb, DSP_DATA_AVAIL); /* 8-bit int ack */ 54950723Scg if (c & 2) sb_rd(sb, DSP_DATA_AVL16); /* 16-bit int ack */ 55050723Scg} 55131361Sjmg 55250925Scgstatic void 55350925Scgess_intr(void *arg) 55450925Scg{ 55550925Scg struct sb_info *sb = (struct sb_info *)arg; 55650925Scg sb_rd(sb, DSP_DATA_AVAIL); /* int ack */ 55750925Scg#ifdef notyet 55850925Scg /* 55950925Scg * XXX 56050925Scg * for full-duplex mode: 56150925Scg * should read port 0x6 to identify where interrupt came from. 56250925Scg */ 56350925Scg#endif 56450925Scg /* 56550925Scg * We are transferring data in DSP normal mode, 56650925Scg * so clear the dl to indicate the DMA is stopped. 56750925Scg */ 56850925Scg if (sb->pch.buffer->dl > 0) { 56950925Scg sb->pch.buffer->dl = -1; 57050925Scg chn_intr(sb->pch.channel); 57150925Scg } 57250925Scg if (sb->rch.buffer->dl > 0) { 57350925Scg sb->rch.buffer->dl = -1; 57450925Scg chn_intr(sb->rch.channel); 57550925Scg } 57650925Scg} 57751768Scg 57850723Scgstatic int 57950723Scgsb_format(struct sb_chinfo *ch, u_int32_t format) 58050723Scg{ 58150723Scg ch->fmt = format; 58250723Scg return 0; 58329415Sjmg} 58429415Sjmg 58550723Scgstatic int 58650723Scgsb_speed(struct sb_chinfo *ch, int speed) 58729415Sjmg{ 58850723Scg struct sb_info *sb = ch->parent; 58950723Scg int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 59050723Scg int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0; 59129415Sjmg 59250723Scg if (sb->bd_flags & BD_F_SB16) { 59350723Scg RANGE(speed, 5000, 45000); 59450723Scg sb_cmd(sb, 0x42 - play); 59550723Scg sb_cmd(sb, speed >> 8); 59650723Scg sb_cmd(sb, speed & 0xff); 59750723Scg } else { 59850723Scg u_char tconst; 59950723Scg int max_speed = 45000, tmp; 60050723Scg u_long flags; 60129415Sjmg 60250723Scg /* here enforce speed limitations - max 22050 on sb 1.x*/ 60350723Scg if (sb->bd_id <= 0x200) max_speed = 22050; 60429415Sjmg 60550723Scg /* 60650723Scg * SB models earlier than SB Pro have low limit for the 60750723Scg * input rate. Note that this is only for input, but since 60850723Scg * we do not support separate values for rec & play.... 60950723Scg */ 61050723Scg if (!play) { 61150723Scg if (sb->bd_id <= 0x200) max_speed = 13000; 61250723Scg else if (sb->bd_id < 0x300) max_speed = 15000; 61350723Scg } 61450723Scg RANGE(speed, 4000, max_speed); 61550723Scg if (stereo) speed <<= 1; 61629415Sjmg 61750723Scg /* 61850723Scg * Now the speed should be valid. Compute the value to be 61950723Scg * programmed into the board. 62050723Scg */ 62150723Scg if (speed > 22050) { /* High speed mode on 2.01/3.xx */ 62250723Scg tconst = (u_char) 62350723Scg ((65536 - ((256000000 + speed / 2) / speed)) 62450723Scg >> 8); 62550723Scg sb->bd_flags |= BD_F_HISPEED; 62650723Scg tmp = 65536 - (tconst << 8); 62750723Scg speed = (256000000 + tmp / 2) / tmp; 62850723Scg } else { 62950723Scg sb->bd_flags &= ~BD_F_HISPEED; 63050723Scg tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; 63150723Scg tmp = 256 - tconst; 63250723Scg speed = (1000000 + tmp / 2) / tmp; 63350723Scg } 63450723Scg flags = spltty(); 63550723Scg sb_cmd1(sb, 0x40, tconst); /* set time constant */ 63650723Scg splx(flags); 63750723Scg if (stereo) speed >>= 1; 63850723Scg } 63950723Scg return speed; 64029415Sjmg} 64129415Sjmg 64250723Scgstatic int 64350723Scgsb_start(struct sb_chinfo *ch) 64450723Scg{ 64550723Scg struct sb_info *sb = ch->parent; 64650723Scg int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 64750723Scg int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0; 64850723Scg int stereo = (ch->fmt & AFMT_STEREO)? 1 : 0; 64950723Scg int l = ch->buffer->dl; 65054462Scg int dh = ch->buffer->chan > 3; 65154791Scg u_char i1, i2; 65229415Sjmg 65354791Scg if (b16 || dh) l >>= 1; 65450723Scg l--; 65550723Scg if (play) sb_cmd(sb, DSP_CMD_SPKON); 65650723Scg if (sb->bd_flags & BD_F_SB16) { 65750723Scg i1 = DSP_F16_AUTO | DSP_F16_FIFO_ON | 65850723Scg (play? DSP_F16_DAC : DSP_F16_ADC); 65954462Scg i1 |= (b16 || dh)? DSP_DMA16 : DSP_DMA8; 66050723Scg i2 = (stereo? DSP_F16_STEREO : 0) | (b16? DSP_F16_SIGNED : 0); 66150723Scg sb_cmd(sb, i1); 66250723Scg sb_cmd2(sb, i2, l); 66350723Scg } else { 66450723Scg if (sb->bd_flags & BD_F_HISPEED) i1 = play? 0x90 : 0x98; 66550723Scg else i1 = play? 0x1c : 0x2c; 66650723Scg sb_setmixer(sb, 0x0e, stereo? 2 : 0); 66750723Scg /* an ESS extension -- they can do 16 bits */ 66850723Scg if (b16) i1 |= 1; 66950723Scg sb_cmd2(sb, 0x48, l); 67050723Scg sb_cmd(sb, i1); 67150723Scg } 67250723Scg sb->bd_flags |= BD_F_DMARUN << b16; 67350723Scg return 0; 67450723Scg} 67550723Scg 67650723Scgstatic int 67750723Scgsb_stop(struct sb_chinfo *ch) 67829415Sjmg{ 67950723Scg struct sb_info *sb = ch->parent; 68050723Scg int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 68150723Scg int b16 = (ch->fmt & AFMT_S16_LE)? 1 : 0; 68229415Sjmg 68350723Scg if (sb->bd_flags & BD_F_HISPEED) sb_reset_dsp(sb); 68450723Scg else { 68550723Scg sb_cmd(sb, b16? DSP_CMD_DMAPAUSE_16 : DSP_CMD_DMAPAUSE_8); 68650723Scg /* 68750723Scg * The above seems to have the undocumented side effect of 68850723Scg * blocking the other side as well. If the other 68950723Scg * channel was active (SB16) I have to re-enable it :( 69050723Scg */ 69150723Scg if (sb->bd_flags & (BD_F_DMARUN << (1 - b16))) 69250723Scg sb_cmd(sb, b16? 0xd4 : 0xd6 ); 69329415Sjmg } 69450723Scg if (play) sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */ 69550723Scg sb->bd_flags &= ~(BD_F_DMARUN << b16); 69650723Scg return 0; 69750723Scg} 69829415Sjmg 69950925Scg/* utility functions for ESS */ 70050925Scgstatic int 70150925Scgess_format(struct sb_chinfo *ch, u_int32_t format) 70250925Scg{ 70350925Scg struct sb_info *sb = ch->parent; 70450925Scg int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 70553126Sdfr int b16 = (format & AFMT_S16_LE)? 1 : 0; 70653126Sdfr int stereo = (format & AFMT_STEREO)? 1 : 0; 70750925Scg u_char c; 70850925Scg ch->fmt = format; 70950925Scg sb_reset_dsp(sb); 71050925Scg /* normal DMA mode */ 71150925Scg ess_write(sb, 0xb8, play ? 0x00 : 0x0a); 71250925Scg /* mono/stereo */ 71350925Scg c = (ess_read(sb, 0xa8) & ~0x03) | 1; 71450925Scg if (!stereo) c++; 71550925Scg ess_write(sb, 0xa8, c); 71650925Scg /* demand mode, 4 bytes/xfer */ 71750925Scg ess_write(sb, 0xb9, 2); 71850925Scg /* setup dac/adc */ 71950925Scg if (play) ess_write(sb, 0xb6, b16? 0x00 : 0x80); 72050925Scg ess_write(sb, 0xb7, 0x51 | (b16? 0x20 : 0x00)); 72150925Scg ess_write(sb, 0xb7, 0x98 + (b16? 0x24 : 0x00) + (stereo? 0x00 : 0x38)); 72250925Scg /* irq/drq control */ 72350925Scg ess_write(sb, 0xb1, (ess_read(sb, 0xb1) & 0x0f) | 0x50); 72450925Scg ess_write(sb, 0xb2, (ess_read(sb, 0xb2) & 0x0f) | 0x50); 72550925Scg return 0; 72650925Scg} 72750925Scg 72850925Scgstatic int 72950925Scgess_speed(struct sb_chinfo *ch, int speed) 73050925Scg{ 73150925Scg struct sb_info *sb = ch->parent; 73250925Scg int t; 73350925Scg RANGE (speed, 5000, 49000); 73450925Scg if (speed > 22000) { 73550925Scg t = (795500 + speed / 2) / speed; 73650925Scg speed = (795500 + t / 2) / t; 73753126Sdfr t = (256 - t ) | 0x80; 73850925Scg } else { 73950925Scg t = (397700 + speed / 2) / speed; 74050925Scg speed = (397700 + t / 2) / t; 74150925Scg t = 128 - t; 74250925Scg } 74350925Scg ess_write(sb, 0xa1, t); /* set time constant */ 74450925Scg#if 0 74550925Scg d->play_speed = d->rec_speed = speed; 74650925Scg speed = (speed * 9 ) / 20; 74750925Scg#endif 74850925Scg t = 256 - 7160000 / ((speed * 9 / 20) * 82); 74950925Scg ess_write(sb, 0xa2, t); 75050925Scg return speed; 75150925Scg} 75250925Scg 75350925Scgstatic int 75450925Scgess_start(struct sb_chinfo *ch) 75550925Scg{ 75650925Scg struct sb_info *sb = ch->parent; 75750925Scg int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 75850925Scg short c = - ch->buffer->dl; 75950925Scg u_char c1; 76050925Scg /* 76150925Scg * clear bit 0 of register B8h 76250925Scg */ 76350925Scg#if 1 76450925Scg c1 = play ? 0x00 : 0x0a; 76550925Scg ess_write(sb, 0xb8, c1++); 76650925Scg#else 76750925Scg c1 = ess_read(sb, 0xb8) & 0xfe; 76850925Scg ess_write(sb, 0xb8, c1++); 76950925Scg#endif 77050925Scg /* 77150925Scg * update ESS Transfer Count Register 77250925Scg */ 77350925Scg ess_write(sb, 0xa4, (u_char)((u_short)c & 0xff)); 77450925Scg ess_write(sb, 0xa5, (u_char)(((u_short)c >> 8) & 0xff)); 77550925Scg /* 77650925Scg * set bit 0 of register B8h 77750925Scg */ 77850925Scg ess_write(sb, 0xb8, c1); 77950925Scg if (play) 78050925Scg sb_cmd(sb, DSP_CMD_SPKON); 78150925Scg return 0; 78250925Scg} 78350925Scg 78450925Scgstatic int 78550925Scgess_stop(struct sb_chinfo *ch) 78650925Scg{ 78750925Scg struct sb_info *sb = ch->parent; 78850925Scg /* 78950925Scg * no need to send a stop command if the DMA has already stopped. 79050925Scg */ 79150925Scg if (ch->buffer->dl > 0) { 79250925Scg sb_cmd(sb, DSP_CMD_DMAPAUSE_8); /* pause dma. */ 79350925Scg } 79450925Scg return 0; 79550925Scg} 79650925Scg 79750925Scgstatic int 79850925Scgess_abort(struct sb_chinfo *ch) 79950925Scg{ 80050925Scg struct sb_info *sb = ch->parent; 80150925Scg int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 80250925Scg if (play) sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */ 80350925Scg sb_reset_dsp(sb); 80450925Scg ess_format(ch, ch->fmt); 80550925Scg ess_speed(ch, ch->channel->speed); 80650925Scg return 0; 80750925Scg} 80850925Scg 80950723Scg/* channel interface */ 81050723Scgstatic void * 81150723Scgsbchan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) 81250723Scg{ 81350723Scg struct sb_info *sb = devinfo; 81450723Scg struct sb_chinfo *ch = (dir == PCMDIR_PLAY)? &sb->pch : &sb->rch; 81554791Scg int dch, dl, dh; 81650723Scg 81750723Scg ch->parent = sb; 81850723Scg ch->channel = c; 81950723Scg ch->buffer = b; 82050723Scg ch->buffer->bufsize = DSP_BUFFSIZE; 82150723Scg if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1) return NULL; 82254791Scg dch = (dir == PCMDIR_PLAY)? 1 : 0; 82354791Scg if (sb->bd_flags & BD_F_SB16X) dch = !dch; 82454791Scg dl = rman_get_start(sb->drq1); 82554791Scg if (sb->drq2) dh = rman_get_start(sb->drq2); else dh = dl; 82654791Scg ch->buffer->chan = dch? dh : dl; 82750723Scg return ch; 82829415Sjmg} 82929415Sjmg 83050723Scgstatic int 83150723Scgsbchan_setdir(void *data, int dir) 83229415Sjmg{ 83350723Scg struct sb_chinfo *ch = data; 83450723Scg ch->dir = dir; 83529415Sjmg return 0; 83629415Sjmg} 83729415Sjmg 83850723Scgstatic int 83950723Scgsbchan_setformat(void *data, u_int32_t format) 84029415Sjmg{ 84150723Scg struct sb_chinfo *ch = data; 84250723Scg sb_format(ch, format); 84329415Sjmg return 0; 84429415Sjmg} 84529415Sjmg 84650723Scgstatic int 84750723Scgsbchan_setspeed(void *data, u_int32_t speed) 84829415Sjmg{ 84950723Scg struct sb_chinfo *ch = data; 85050723Scg return sb_speed(ch, speed); 85129415Sjmg} 85229415Sjmg 85350723Scgstatic int 85450723Scgsbchan_setblocksize(void *data, u_int32_t blocksize) 85550723Scg{ 85650723Scg return blocksize; 85750723Scg} 85829415Sjmg 85950723Scgstatic int 86050723Scgsbchan_trigger(void *data, int go) 86133474Sscrappy{ 86250723Scg struct sb_chinfo *ch = data; 86350723Scg buf_isadma(ch->buffer, go); 86450723Scg if (go == PCMTRIG_START) sb_start(ch); else sb_stop(ch); 86550723Scg return 0; 86633474Sscrappy} 86733474Sscrappy 86850723Scgstatic int 86950723Scgsbchan_getptr(void *data) 87039899Sluigi{ 87150723Scg struct sb_chinfo *ch = data; 87250723Scg return buf_isadmaptr(ch->buffer); 87339899Sluigi} 87433474Sscrappy 87550723Scgstatic pcmchan_caps * 87650723Scgsbchan_getcaps(void *data) 87739899Sluigi{ 87850723Scg struct sb_chinfo *ch = data; 87950723Scg int p = (ch->dir == PCMDIR_PLAY)? 1 : 0; 88054462Scg if (ch->parent->bd_id < 0x300) 88150723Scg return p? &sb_playcaps : &sb_reccaps; 88254462Scg else if (ch->parent->bd_id < 0x400) 88354462Scg return p? &sbpro_playcaps : &sbpro_reccaps; 88454462Scg else if (ch->parent->bd_flags & BD_F_SB16X) 88554462Scg return &sb16x_caps; 88650723Scg else 88754462Scg return (ch->buffer->chan >= 4)? &sb16_hcaps : &sb16_lcaps; 88839899Sluigi} 88950925Scg/* channel interface for ESS18xx */ 89050925Scg#ifdef notyet 89150925Scgstatic void * 89250925Scgesschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) 89350925Scg{ 89450925Scg /* the same as sbchan_init()? */ 89550925Scg} 89650925Scg#endif 89733474Sscrappy 89850925Scgstatic int 89950925Scgesschan_setdir(void *data, int dir) 90050925Scg{ 90150925Scg struct sb_chinfo *ch = data; 90250925Scg ch->dir = dir; 90350925Scg return 0; 90450925Scg} 90550925Scg 90650925Scgstatic int 90750925Scgesschan_setformat(void *data, u_int32_t format) 90850925Scg{ 90950925Scg struct sb_chinfo *ch = data; 91050925Scg ess_format(ch, format); 91150925Scg return 0; 91250925Scg} 91350925Scg 91450925Scgstatic int 91550925Scgesschan_setspeed(void *data, u_int32_t speed) 91650925Scg{ 91750925Scg struct sb_chinfo *ch = data; 91850925Scg return ess_speed(ch, speed); 91950925Scg} 92050925Scg 92150925Scgstatic int 92250925Scgesschan_setblocksize(void *data, u_int32_t blocksize) 92350925Scg{ 92450925Scg return blocksize; 92550925Scg} 92650925Scg 92750925Scgstatic int 92850925Scgesschan_trigger(void *data, int go) 92950925Scg{ 93050925Scg struct sb_chinfo *ch = data; 93150925Scg switch (go) { 93250925Scg case PCMTRIG_START: 93350925Scg if (!ch->ess_dma_started) 93450925Scg buf_isadma(ch->buffer, go); 93550925Scg ch->ess_dma_started = 1; 93650925Scg ess_start(ch); 93750925Scg break; 93850925Scg case PCMTRIG_STOP: 93950925Scg if (ch->buffer->dl >= 0) { 94050925Scg buf_isadma(ch->buffer, go); 94150925Scg ch->ess_dma_started = 0; 94250925Scg ess_stop(ch); 94350925Scg } 94450925Scg break; 94550925Scg case PCMTRIG_ABORT: 94650925Scg default: 94750925Scg ch->ess_dma_started = 0; 94850925Scg ess_abort(ch); 94950925Scg buf_isadma(ch->buffer, go); 95050925Scg break; 95150925Scg } 95250925Scg return 0; 95350925Scg} 95450925Scg 95550925Scgstatic int 95650925Scgesschan_getptr(void *data) 95750925Scg{ 95850925Scg struct sb_chinfo *ch = data; 95950925Scg return buf_isadmaptr(ch->buffer); 96050925Scg} 96150925Scg 96250925Scgstatic pcmchan_caps * 96350925Scgesschan_getcaps(void *data) 96450925Scg{ 96550925Scg struct sb_chinfo *ch = data; 96650925Scg return (ch->dir == PCMDIR_PLAY)? &ess_playcaps : &ess_reccaps; 96750925Scg} 96850925Scg 96950723Scg/************************************************************/ 97039899Sluigi 97129415Sjmgstatic int 97250723Scgsbmix_init(snd_mixer *m) 97329415Sjmg{ 97450723Scg struct sb_info *sb = mix_getdevinfo(m); 97529415Sjmg 97650723Scg switch (sb->bd_flags & BD_F_MIX_MASK) { 97750723Scg case BD_F_MIX_CT1345: /* SB 3.0 has 1345 mixer */ 97850723Scg mix_setdevs(m, SBPRO_MIXER_DEVICES); 97950723Scg mix_setrecdevs(m, SBPRO_RECORDING_DEVICES); 98050723Scg sb_setmixer(sb, 0, 1); /* reset mixer */ 98150723Scg sb_setmixer(sb, MIC_VOL, 0x6); /* mic volume max */ 98250723Scg sb_setmixer(sb, RECORD_SRC, 0x0); /* mic source */ 98350723Scg sb_setmixer(sb, FM_VOL, 0x0); /* no midi */ 98450723Scg break; 98531361Sjmg 98650723Scg case BD_F_MIX_CT1745: /* SB16 mixer ... */ 98750723Scg mix_setdevs(m, SB16_MIXER_DEVICES); 98850723Scg mix_setrecdevs(m, SB16_RECORDING_DEVICES); 98950723Scg sb_setmixer(sb, 0x3c, 0x1f); /* make all output active */ 99050723Scg sb_setmixer(sb, 0x3d, 0); /* make all inputs-l off */ 99150723Scg sb_setmixer(sb, 0x3e, 0); /* make all inputs-r off */ 99250723Scg } 99350723Scg return 0; 99450723Scg} 99531361Sjmg 99650723Scgstatic int 99750723Scgsbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) 99850723Scg{ 99950723Scg struct sb_info *sb = mix_getdevinfo(m); 100050723Scg int regoffs; 100150723Scg u_char val; 100250723Scg mixer_tab *iomap; 100329415Sjmg 100450723Scg switch (sb->bd_flags & BD_F_MIX_MASK) { 100550723Scg case BD_F_MIX_CT1345: 100653126Sdfr if (sb->bd_flags & BD_F_ESS) 100753126Sdfr iomap = &ess_mix; 100853126Sdfr else 100953126Sdfr iomap = &sbpro_mix; 101050723Scg break; 101129415Sjmg 101250723Scg case BD_F_MIX_CT1745: 101350723Scg iomap = &sb16_mix; 101450723Scg break; 101529415Sjmg 101650723Scg default: 101750723Scg return -1; 101850723Scg /* XXX how about the SG NX Pro, iomap = sgnxpro_mix */ 101950723Scg } 102053126Sdfr 102153126Sdfr /* Change left channel */ 102250723Scg regoffs = (*iomap)[dev][LEFT_CHN].regno; 102353126Sdfr if (regoffs != 0) { 102453126Sdfr val = sb_getmixer(sb, regoffs); 102553126Sdfr change_bits(iomap, &val, dev, LEFT_CHN, left); 102653126Sdfr sb_setmixer(sb, regoffs, val); 102753126Sdfr } 102853126Sdfr 102953126Sdfr /* Change right channel */ 103053126Sdfr regoffs = (*iomap)[dev][RIGHT_CHN].regno; 103153126Sdfr if (regoffs != 0) { 103253126Sdfr val = sb_getmixer(sb, regoffs); /* Read the new one */ 103353126Sdfr change_bits(iomap, &val, dev, RIGHT_CHN, right); 103453126Sdfr sb_setmixer(sb, regoffs, val); 103553126Sdfr } else 103653126Sdfr right = left; 103753126Sdfr 103850723Scg return left | (right << 8); 103929415Sjmg} 104029415Sjmg 104150723Scgstatic int 104250723Scgsbmix_setrecsrc(snd_mixer *m, u_int32_t src) 104329415Sjmg{ 104450723Scg struct sb_info *sb = mix_getdevinfo(m); 104550723Scg u_char recdev; 104629415Sjmg 104750723Scg switch (sb->bd_flags & BD_F_MIX_MASK) { 104850723Scg case BD_F_MIX_CT1345: 104950723Scg if (src == SOUND_MASK_LINE) recdev = 0x06; 105050723Scg else if (src == SOUND_MASK_CD) recdev = 0x02; 105150723Scg else { /* default: mic */ 105250723Scg src = SOUND_MASK_MIC; 105350723Scg recdev = 0; 105450723Scg } 105550723Scg sb_setmixer(sb, RECORD_SRC, recdev | 105650723Scg (sb_getmixer(sb, RECORD_SRC) & ~0x07)); 105750723Scg break; 105829415Sjmg 105950723Scg case BD_F_MIX_CT1745: /* sb16 */ 106050723Scg recdev = 0; 106150723Scg if (src & SOUND_MASK_MIC) recdev |= 0x01; /* mono mic */ 106250723Scg if (src & SOUND_MASK_CD) recdev |= 0x06; /* l+r cd */ 106350723Scg if (src & SOUND_MASK_LINE) recdev |= 0x18; /* l+r line */ 106450723Scg if (src & SOUND_MASK_SYNTH) recdev |= 0x60; /* l+r midi */ 106550723Scg sb_setmixer(sb, SB16_IMASK_L, recdev); 106650723Scg sb_setmixer(sb, SB16_IMASK_R, recdev); 106750723Scg /* 106850723Scg * since the same volume controls apply to the input and 106950723Scg * output sections, the best approach to have a consistent 107050723Scg * behaviour among cards would be to disable the output path 107150723Scg * on devices which are used to record. 107250723Scg * However, since users like to have feedback, we only disable 107350723Scg * the mic -- permanently. 107450723Scg */ 107550723Scg sb_setmixer(sb, SB16_OMASK, 0x1f & ~1); 107650723Scg break; 107751768Scg } 107850723Scg return src; 107929415Sjmg} 108029415Sjmg 108129415Sjmgstatic int 108253553Stanimurasbsbc_probe(device_t dev) 108353553Stanimura{ 108454462Scg char buf[64]; 108554791Scg u_int32_t func, ver, r, f; 108653553Stanimura 108753553Stanimura /* The parent device has already been probed. */ 108854462Scg r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func); 108954462Scg if (func != SCF_PCM) 109053553Stanimura return (ENXIO); 109153553Stanimura 109254462Scg r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 109354791Scg f = (ver & 0xffff0000) >> 16; 109454462Scg ver &= 0x0000ffff; 109554791Scg snprintf(buf, sizeof buf, "SB DSP %d.%02d%s", ver >> 8, ver & 0xff, 109654791Scg (f & BD_F_ESS)? " (ESS mode)" : ""); 109754462Scg device_set_desc_copy(dev, buf); 109853553Stanimura 109953553Stanimura return 0; 110053553Stanimura} 110153553Stanimura 110253553Stanimurastatic int 110353553Stanimurasbsbc_attach(device_t dev) 110453553Stanimura{ 110553553Stanimura struct sb_info *sb; 110654462Scg u_int32_t ver; 110753553Stanimura 110853553Stanimura sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT); 110953553Stanimura if (!sb) return ENXIO; 111053553Stanimura bzero(sb, sizeof *sb); 111153553Stanimura 111254462Scg BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 111354462Scg sb->bd_id = ver & 0x0000ffff; 111454462Scg sb->bd_flags = (ver & 0xffff0000) >> 16; 111554462Scg 111653553Stanimura return sb_doattach(dev, sb); 111753553Stanimura} 111853553Stanimura 111953553Stanimurastatic device_method_t sbsbc_methods[] = { 112053553Stanimura /* Device interface */ 112153553Stanimura DEVMETHOD(device_probe, sbsbc_probe), 112253553Stanimura DEVMETHOD(device_attach, sbsbc_attach), 112353553Stanimura 112453553Stanimura { 0, 0 } 112553553Stanimura}; 112653553Stanimura 112753553Stanimurastatic driver_t sbsbc_driver = { 112853553Stanimura "pcm", 112953553Stanimura sbsbc_methods, 113053553Stanimura sizeof(snddev_info), 113153553Stanimura}; 113253553Stanimura 113353553StanimuraDRIVER_MODULE(sbsbc, sbc, sbsbc_driver, pcm_devclass, 0, 0); 113453553Stanimura 113554462Scg 113654462Scg 1137