sb16.c revision 54462
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 54462 1999-12-12 02:30:19Z 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; 65150723Scg u_char i1, i2 = 0; 65229415Sjmg 65350723Scg if (b16) 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; 81550723Scg 81650723Scg ch->parent = sb; 81750723Scg ch->channel = c; 81850723Scg ch->buffer = b; 81950723Scg ch->buffer->bufsize = DSP_BUFFSIZE; 82050723Scg if (chn_allocbuf(ch->buffer, sb->parent_dmat) == -1) return NULL; 82154462Scg ch->buffer->chan = (dir == PCMDIR_PLAY)? rman_get_start(sb->drq2) 82254462Scg : rman_get_start(sb->drq1); 82350723Scg return ch; 82429415Sjmg} 82529415Sjmg 82650723Scgstatic int 82750723Scgsbchan_setdir(void *data, int dir) 82829415Sjmg{ 82950723Scg struct sb_chinfo *ch = data; 83050723Scg ch->dir = dir; 83129415Sjmg return 0; 83229415Sjmg} 83329415Sjmg 83450723Scgstatic int 83550723Scgsbchan_setformat(void *data, u_int32_t format) 83629415Sjmg{ 83750723Scg struct sb_chinfo *ch = data; 83850723Scg sb_format(ch, format); 83929415Sjmg return 0; 84029415Sjmg} 84129415Sjmg 84250723Scgstatic int 84350723Scgsbchan_setspeed(void *data, u_int32_t speed) 84429415Sjmg{ 84550723Scg struct sb_chinfo *ch = data; 84650723Scg return sb_speed(ch, speed); 84729415Sjmg} 84829415Sjmg 84950723Scgstatic int 85050723Scgsbchan_setblocksize(void *data, u_int32_t blocksize) 85150723Scg{ 85250723Scg return blocksize; 85350723Scg} 85429415Sjmg 85550723Scgstatic int 85650723Scgsbchan_trigger(void *data, int go) 85733474Sscrappy{ 85850723Scg struct sb_chinfo *ch = data; 85950723Scg buf_isadma(ch->buffer, go); 86050723Scg if (go == PCMTRIG_START) sb_start(ch); else sb_stop(ch); 86150723Scg return 0; 86233474Sscrappy} 86333474Sscrappy 86450723Scgstatic int 86550723Scgsbchan_getptr(void *data) 86639899Sluigi{ 86750723Scg struct sb_chinfo *ch = data; 86850723Scg return buf_isadmaptr(ch->buffer); 86939899Sluigi} 87033474Sscrappy 87150723Scgstatic pcmchan_caps * 87250723Scgsbchan_getcaps(void *data) 87339899Sluigi{ 87450723Scg struct sb_chinfo *ch = data; 87550723Scg int p = (ch->dir == PCMDIR_PLAY)? 1 : 0; 87654462Scg if (ch->parent->bd_id < 0x300) 87750723Scg return p? &sb_playcaps : &sb_reccaps; 87854462Scg else if (ch->parent->bd_id < 0x400) 87954462Scg return p? &sbpro_playcaps : &sbpro_reccaps; 88054462Scg else if (ch->parent->bd_flags & BD_F_SB16X) 88154462Scg return &sb16x_caps; 88250723Scg else 88354462Scg return (ch->buffer->chan >= 4)? &sb16_hcaps : &sb16_lcaps; 88439899Sluigi} 88550925Scg/* channel interface for ESS18xx */ 88650925Scg#ifdef notyet 88750925Scgstatic void * 88850925Scgesschan_init(void *devinfo, snd_dbuf *b, pcm_channel *c, int dir) 88950925Scg{ 89050925Scg /* the same as sbchan_init()? */ 89150925Scg} 89250925Scg#endif 89333474Sscrappy 89450925Scgstatic int 89550925Scgesschan_setdir(void *data, int dir) 89650925Scg{ 89750925Scg struct sb_chinfo *ch = data; 89850925Scg ch->dir = dir; 89950925Scg return 0; 90050925Scg} 90150925Scg 90250925Scgstatic int 90350925Scgesschan_setformat(void *data, u_int32_t format) 90450925Scg{ 90550925Scg struct sb_chinfo *ch = data; 90650925Scg ess_format(ch, format); 90750925Scg return 0; 90850925Scg} 90950925Scg 91050925Scgstatic int 91150925Scgesschan_setspeed(void *data, u_int32_t speed) 91250925Scg{ 91350925Scg struct sb_chinfo *ch = data; 91450925Scg return ess_speed(ch, speed); 91550925Scg} 91650925Scg 91750925Scgstatic int 91850925Scgesschan_setblocksize(void *data, u_int32_t blocksize) 91950925Scg{ 92050925Scg return blocksize; 92150925Scg} 92250925Scg 92350925Scgstatic int 92450925Scgesschan_trigger(void *data, int go) 92550925Scg{ 92650925Scg struct sb_chinfo *ch = data; 92750925Scg switch (go) { 92850925Scg case PCMTRIG_START: 92950925Scg if (!ch->ess_dma_started) 93050925Scg buf_isadma(ch->buffer, go); 93150925Scg ch->ess_dma_started = 1; 93250925Scg ess_start(ch); 93350925Scg break; 93450925Scg case PCMTRIG_STOP: 93550925Scg if (ch->buffer->dl >= 0) { 93650925Scg buf_isadma(ch->buffer, go); 93750925Scg ch->ess_dma_started = 0; 93850925Scg ess_stop(ch); 93950925Scg } 94050925Scg break; 94150925Scg case PCMTRIG_ABORT: 94250925Scg default: 94350925Scg ch->ess_dma_started = 0; 94450925Scg ess_abort(ch); 94550925Scg buf_isadma(ch->buffer, go); 94650925Scg break; 94750925Scg } 94850925Scg return 0; 94950925Scg} 95050925Scg 95150925Scgstatic int 95250925Scgesschan_getptr(void *data) 95350925Scg{ 95450925Scg struct sb_chinfo *ch = data; 95550925Scg return buf_isadmaptr(ch->buffer); 95650925Scg} 95750925Scg 95850925Scgstatic pcmchan_caps * 95950925Scgesschan_getcaps(void *data) 96050925Scg{ 96150925Scg struct sb_chinfo *ch = data; 96250925Scg return (ch->dir == PCMDIR_PLAY)? &ess_playcaps : &ess_reccaps; 96350925Scg} 96450925Scg 96550723Scg/************************************************************/ 96639899Sluigi 96729415Sjmgstatic int 96850723Scgsbmix_init(snd_mixer *m) 96929415Sjmg{ 97050723Scg struct sb_info *sb = mix_getdevinfo(m); 97129415Sjmg 97250723Scg switch (sb->bd_flags & BD_F_MIX_MASK) { 97350723Scg case BD_F_MIX_CT1345: /* SB 3.0 has 1345 mixer */ 97450723Scg mix_setdevs(m, SBPRO_MIXER_DEVICES); 97550723Scg mix_setrecdevs(m, SBPRO_RECORDING_DEVICES); 97650723Scg sb_setmixer(sb, 0, 1); /* reset mixer */ 97750723Scg sb_setmixer(sb, MIC_VOL, 0x6); /* mic volume max */ 97850723Scg sb_setmixer(sb, RECORD_SRC, 0x0); /* mic source */ 97950723Scg sb_setmixer(sb, FM_VOL, 0x0); /* no midi */ 98050723Scg break; 98131361Sjmg 98250723Scg case BD_F_MIX_CT1745: /* SB16 mixer ... */ 98350723Scg mix_setdevs(m, SB16_MIXER_DEVICES); 98450723Scg mix_setrecdevs(m, SB16_RECORDING_DEVICES); 98550723Scg sb_setmixer(sb, 0x3c, 0x1f); /* make all output active */ 98650723Scg sb_setmixer(sb, 0x3d, 0); /* make all inputs-l off */ 98750723Scg sb_setmixer(sb, 0x3e, 0); /* make all inputs-r off */ 98850723Scg } 98950723Scg return 0; 99050723Scg} 99131361Sjmg 99250723Scgstatic int 99350723Scgsbmix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right) 99450723Scg{ 99550723Scg struct sb_info *sb = mix_getdevinfo(m); 99650723Scg int regoffs; 99750723Scg u_char val; 99850723Scg mixer_tab *iomap; 99929415Sjmg 100050723Scg switch (sb->bd_flags & BD_F_MIX_MASK) { 100150723Scg case BD_F_MIX_CT1345: 100253126Sdfr if (sb->bd_flags & BD_F_ESS) 100353126Sdfr iomap = &ess_mix; 100453126Sdfr else 100553126Sdfr iomap = &sbpro_mix; 100650723Scg break; 100729415Sjmg 100850723Scg case BD_F_MIX_CT1745: 100950723Scg iomap = &sb16_mix; 101050723Scg break; 101129415Sjmg 101250723Scg default: 101350723Scg return -1; 101450723Scg /* XXX how about the SG NX Pro, iomap = sgnxpro_mix */ 101550723Scg } 101653126Sdfr 101753126Sdfr /* Change left channel */ 101850723Scg regoffs = (*iomap)[dev][LEFT_CHN].regno; 101953126Sdfr if (regoffs != 0) { 102053126Sdfr val = sb_getmixer(sb, regoffs); 102153126Sdfr change_bits(iomap, &val, dev, LEFT_CHN, left); 102253126Sdfr sb_setmixer(sb, regoffs, val); 102353126Sdfr } 102453126Sdfr 102553126Sdfr /* Change right channel */ 102653126Sdfr regoffs = (*iomap)[dev][RIGHT_CHN].regno; 102753126Sdfr if (regoffs != 0) { 102853126Sdfr val = sb_getmixer(sb, regoffs); /* Read the new one */ 102953126Sdfr change_bits(iomap, &val, dev, RIGHT_CHN, right); 103053126Sdfr sb_setmixer(sb, regoffs, val); 103153126Sdfr } else 103253126Sdfr right = left; 103353126Sdfr 103450723Scg return left | (right << 8); 103529415Sjmg} 103629415Sjmg 103750723Scgstatic int 103850723Scgsbmix_setrecsrc(snd_mixer *m, u_int32_t src) 103929415Sjmg{ 104050723Scg struct sb_info *sb = mix_getdevinfo(m); 104150723Scg u_char recdev; 104229415Sjmg 104350723Scg switch (sb->bd_flags & BD_F_MIX_MASK) { 104450723Scg case BD_F_MIX_CT1345: 104550723Scg if (src == SOUND_MASK_LINE) recdev = 0x06; 104650723Scg else if (src == SOUND_MASK_CD) recdev = 0x02; 104750723Scg else { /* default: mic */ 104850723Scg src = SOUND_MASK_MIC; 104950723Scg recdev = 0; 105050723Scg } 105150723Scg sb_setmixer(sb, RECORD_SRC, recdev | 105250723Scg (sb_getmixer(sb, RECORD_SRC) & ~0x07)); 105350723Scg break; 105429415Sjmg 105550723Scg case BD_F_MIX_CT1745: /* sb16 */ 105650723Scg recdev = 0; 105750723Scg if (src & SOUND_MASK_MIC) recdev |= 0x01; /* mono mic */ 105850723Scg if (src & SOUND_MASK_CD) recdev |= 0x06; /* l+r cd */ 105950723Scg if (src & SOUND_MASK_LINE) recdev |= 0x18; /* l+r line */ 106050723Scg if (src & SOUND_MASK_SYNTH) recdev |= 0x60; /* l+r midi */ 106150723Scg sb_setmixer(sb, SB16_IMASK_L, recdev); 106250723Scg sb_setmixer(sb, SB16_IMASK_R, recdev); 106350723Scg /* 106450723Scg * since the same volume controls apply to the input and 106550723Scg * output sections, the best approach to have a consistent 106650723Scg * behaviour among cards would be to disable the output path 106750723Scg * on devices which are used to record. 106850723Scg * However, since users like to have feedback, we only disable 106950723Scg * the mic -- permanently. 107050723Scg */ 107150723Scg sb_setmixer(sb, SB16_OMASK, 0x1f & ~1); 107250723Scg break; 107351768Scg } 107450723Scg return src; 107529415Sjmg} 107629415Sjmg 107729415Sjmgstatic int 107853553Stanimurasbsbc_probe(device_t dev) 107953553Stanimura{ 108054462Scg char buf[64]; 108154462Scg u_int32_t func, ver, r; 108253553Stanimura 108353553Stanimura /* The parent device has already been probed. */ 108454462Scg r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func); 108554462Scg if (func != SCF_PCM) 108653553Stanimura return (ENXIO); 108753553Stanimura 108854462Scg r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 108954462Scg ver &= 0x0000ffff; 109054462Scg snprintf(buf, sizeof buf, "SB DSP %d.%02d", ver >> 8, ver & 0xff); 109154462Scg device_set_desc_copy(dev, buf); 109253553Stanimura 109353553Stanimura return 0; 109453553Stanimura} 109553553Stanimura 109653553Stanimurastatic int 109753553Stanimurasbsbc_attach(device_t dev) 109853553Stanimura{ 109953553Stanimura struct sb_info *sb; 110054462Scg u_int32_t ver; 110153553Stanimura 110253553Stanimura sb = (struct sb_info *)malloc(sizeof *sb, M_DEVBUF, M_NOWAIT); 110353553Stanimura if (!sb) return ENXIO; 110453553Stanimura bzero(sb, sizeof *sb); 110553553Stanimura 110654462Scg BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 110754462Scg sb->bd_id = ver & 0x0000ffff; 110854462Scg sb->bd_flags = (ver & 0xffff0000) >> 16; 110954462Scg 111053553Stanimura return sb_doattach(dev, sb); 111153553Stanimura} 111253553Stanimura 111353553Stanimurastatic device_method_t sbsbc_methods[] = { 111453553Stanimura /* Device interface */ 111553553Stanimura DEVMETHOD(device_probe, sbsbc_probe), 111653553Stanimura DEVMETHOD(device_attach, sbsbc_attach), 111753553Stanimura 111853553Stanimura { 0, 0 } 111953553Stanimura}; 112053553Stanimura 112153553Stanimurastatic driver_t sbsbc_driver = { 112253553Stanimura "pcm", 112353553Stanimura sbsbc_methods, 112453553Stanimura sizeof(snddev_info), 112553553Stanimura}; 112653553Stanimura 112753553StanimuraDRIVER_MODULE(sbsbc, sbc, sbsbc_driver, pcm_devclass, 0, 0); 112853553Stanimura 112954462Scg 113054462Scg 1131