1139749Simp/*- 2119853Scg * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 364064Scg * 464064Scg * Redistribution and use in source and binary forms, with or without 564064Scg * modification, are permitted provided that the following conditions 664064Scg * are met: 764064Scg * 1. Redistributions of source code must retain the above copyright 864064Scg * notice, this list of conditions and the following disclaimer. 964064Scg * 2. Redistributions in binary form must reproduce the above copyright 1064064Scg * notice, this list of conditions and the following disclaimer in the 1164064Scg * documentation and/or other materials provided with the distribution. 1264064Scg * 1364064Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1464064Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1564064Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1664064Scg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1764064Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1864064Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 1964064Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2064064Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2164064Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2264064Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2364064Scg * SUCH DAMAGE. 2464064Scg */ 2564064Scg 26193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 27193640Sariff#include "opt_snd.h" 28193640Sariff#endif 29193640Sariff 3064064Scg#include <dev/sound/pcm/sound.h> 3164064Scg 32119287Simp#include <dev/pci/pcireg.h> 33119287Simp#include <dev/pci/pcivar.h> 3464064Scg 3564064Scg#include <dev/sound/isa/sb.h> 3664064Scg#include <dev/sound/chip.h> 3764064Scg 3870134Scg#include "mixer_if.h" 3970134Scg 4082180ScgSND_DECLARE_FILE("$FreeBSD$"); 4182180Scg 4284658Scg#define SOLO_DEFAULT_BUFSZ 16384 4364064Scg#define ABS(x) (((x) < 0)? -(x) : (x)) 4464064Scg 4564163Snsayer/* if defined, playback always uses the 2nd channel and full duplex works */ 46154881Sariff#define ESS18XX_DUPLEX 1 4764064Scg 4864064Scg/* more accurate clocks and split audio1/audio2 rates */ 4964064Scg#define ESS18XX_NEWSPEED 5064064Scg 51154066Sariff/* 1 = INTR_MPSAFE, 0 = GIANT */ 52154066Sariff#define ESS18XX_MPSAFE 1 53154066Sariff 5464881Scgstatic u_int32_t ess_playfmt[] = { 55193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 56193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 57193640Sariff SND_FORMAT(AFMT_S8, 1, 0), 58193640Sariff SND_FORMAT(AFMT_S8, 2, 0), 59193640Sariff SND_FORMAT(AFMT_S16_LE, 1, 0), 60193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 61193640Sariff SND_FORMAT(AFMT_U16_LE, 1, 0), 62193640Sariff SND_FORMAT(AFMT_U16_LE, 2, 0), 6364881Scg 0 6464064Scg}; 65154024Sariffstatic struct pcmchan_caps ess_playcaps = {6000, 48000, ess_playfmt, 0}; 6664064Scg 6764163Snsayer/* 6864163Snsayer * Recording output is byte-swapped 6964163Snsayer */ 7064881Scgstatic u_int32_t ess_recfmt[] = { 71193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 72193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 73193640Sariff SND_FORMAT(AFMT_S8, 1, 0), 74193640Sariff SND_FORMAT(AFMT_S8, 2, 0), 75193640Sariff SND_FORMAT(AFMT_S16_BE, 1, 0), 76193640Sariff SND_FORMAT(AFMT_S16_BE, 2, 0), 77193640Sariff SND_FORMAT(AFMT_U16_BE, 1, 0), 78193640Sariff SND_FORMAT(AFMT_U16_BE, 2, 0), 7964881Scg 0 8064064Scg}; 81154024Sariffstatic struct pcmchan_caps ess_reccaps = {6000, 48000, ess_recfmt, 0}; 8264064Scg 8364064Scgstruct ess_info; 8464064Scg 8564064Scgstruct ess_chinfo { 8664064Scg struct ess_info *parent; 8774763Scg struct pcm_channel *channel; 8874763Scg struct snd_dbuf *buffer; 8964064Scg int dir, hwch, stopping; 9070291Scg u_int32_t fmt, spd, blksz; 9164064Scg}; 9264064Scg 9364064Scgstruct ess_info { 9464064Scg struct resource *io, *sb, *vc, *mpu, *gp; /* I/O address for the board */ 9564064Scg struct resource *irq; 9665644Scg void *ih; 9764064Scg bus_dma_tag_t parent_dmat; 9864064Scg 99170032Sariff int simplex_dir, type, dmasz[2]; 100170032Sariff unsigned int duplex:1, newspeed:1; 10184658Scg unsigned int bufsz; 10284658Scg 10364064Scg struct ess_chinfo pch, rch; 104154066Sariff#if ESS18XX_MPSAFE == 1 105154066Sariff struct mtx *lock; 106154066Sariff#endif 10764064Scg}; 10864064Scg 109154066Sariff#if ESS18XX_MPSAFE == 1 110154066Sariff#define ess_lock(_ess) snd_mtxlock((_ess)->lock) 111154066Sariff#define ess_unlock(_ess) snd_mtxunlock((_ess)->lock) 112154066Sariff#define ess_lock_assert(_ess) snd_mtxassert((_ess)->lock) 113154066Sariff#else 114154066Sariff#define ess_lock(_ess) 115154066Sariff#define ess_unlock(_ess) 116154066Sariff#define ess_lock_assert(_ess) 117154066Sariff#endif 118154066Sariff 11964064Scgstatic int ess_rd(struct ess_info *sc, int reg); 12064064Scgstatic void ess_wr(struct ess_info *sc, int reg, u_int8_t val); 12164064Scgstatic int ess_dspready(struct ess_info *sc); 12264064Scgstatic int ess_cmd(struct ess_info *sc, u_char val); 12364064Scgstatic int ess_cmd1(struct ess_info *sc, u_char cmd, int val); 12464064Scgstatic int ess_get_byte(struct ess_info *sc); 12564064Scgstatic void ess_setmixer(struct ess_info *sc, u_int port, u_int value); 12664064Scgstatic int ess_getmixer(struct ess_info *sc, u_int port); 12764064Scgstatic int ess_reset_dsp(struct ess_info *sc); 12864064Scg 12964064Scgstatic int ess_write(struct ess_info *sc, u_char reg, int val); 13064064Scgstatic int ess_read(struct ess_info *sc, u_char reg); 13164064Scg 13264064Scgstatic void ess_intr(void *arg); 13364064Scgstatic int ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int len); 13464064Scgstatic int ess_start(struct ess_chinfo *ch); 13564064Scgstatic int ess_stop(struct ess_chinfo *ch); 13664064Scg 13764064Scgstatic int ess_dmasetup(struct ess_info *sc, int ch, u_int32_t base, u_int16_t cnt, int dir); 13864064Scgstatic int ess_dmapos(struct ess_info *sc, int ch); 13964064Scgstatic int ess_dmatrigger(struct ess_info *sc, int ch, int go); 14064064Scg 14164064Scg/* 14264064Scg * Common code for the midi and pcm functions 14364064Scg * 14464064Scg * ess_cmd write a single byte to the CMD port. 14564064Scg * ess_cmd1 write a CMD + 1 byte arg 14664064Scg * ess_cmd2 write a CMD + 2 byte arg 14764064Scg * ess_get_byte returns a single byte from the DSP data port 14864064Scg * 14964064Scg * ess_write is actually ess_cmd1 15064064Scg * ess_read access ext. regs via ess_cmd(0xc0, reg) followed by ess_get_byte 15164064Scg */ 15264064Scg 15364064Scgstatic int 15464064Scgport_rd(struct resource *port, int regno, int size) 15564064Scg{ 15664064Scg bus_space_tag_t st = rman_get_bustag(port); 15764064Scg bus_space_handle_t sh = rman_get_bushandle(port); 15864064Scg 15964064Scg switch (size) { 16064064Scg case 1: 16164064Scg return bus_space_read_1(st, sh, regno); 16264064Scg case 2: 16364064Scg return bus_space_read_2(st, sh, regno); 16464064Scg case 4: 16564064Scg return bus_space_read_4(st, sh, regno); 16664064Scg default: 16764064Scg return 0xffffffff; 16864064Scg } 16964064Scg} 17064064Scg 17164064Scgstatic void 17264064Scgport_wr(struct resource *port, int regno, u_int32_t data, int size) 17364064Scg{ 17464064Scg bus_space_tag_t st = rman_get_bustag(port); 17564064Scg bus_space_handle_t sh = rman_get_bushandle(port); 17664064Scg 17764064Scg switch (size) { 17864064Scg case 1: 17964064Scg bus_space_write_1(st, sh, regno, data); 18064064Scg break; 18164064Scg case 2: 18264064Scg bus_space_write_2(st, sh, regno, data); 18364064Scg break; 18464064Scg case 4: 18564064Scg bus_space_write_4(st, sh, regno, data); 18664064Scg break; 18764064Scg } 18864064Scg} 18964064Scg 19064064Scgstatic int 19164064Scgess_rd(struct ess_info *sc, int reg) 19264064Scg{ 19364064Scg return port_rd(sc->sb, reg, 1); 19464064Scg} 19564064Scg 19664064Scgstatic void 19764064Scgess_wr(struct ess_info *sc, int reg, u_int8_t val) 19864064Scg{ 19964064Scg port_wr(sc->sb, reg, val, 1); 20064064Scg} 20164064Scg 20264064Scgstatic int 20364064Scgess_dspready(struct ess_info *sc) 20464064Scg{ 20564064Scg return ((ess_rd(sc, SBDSP_STATUS) & 0x80) == 0); 20664064Scg} 20764064Scg 20864064Scgstatic int 20964064Scgess_dspwr(struct ess_info *sc, u_char val) 21064064Scg{ 21164064Scg int i; 21264064Scg 21364064Scg for (i = 0; i < 1000; i++) { 21464064Scg if (ess_dspready(sc)) { 21564064Scg ess_wr(sc, SBDSP_CMD, val); 21664064Scg return 1; 21764064Scg } 21864064Scg if (i > 10) DELAY((i > 100)? 1000 : 10); 21964064Scg } 22064064Scg printf("ess_dspwr(0x%02x) timed out.\n", val); 22164064Scg return 0; 22264064Scg} 22364064Scg 22464064Scgstatic int 22564064Scgess_cmd(struct ess_info *sc, u_char val) 22664064Scg{ 22764140Snsayer DEB(printf("ess_cmd: %x\n", val)); 22864064Scg return ess_dspwr(sc, val); 22964064Scg} 23064064Scg 23164064Scgstatic int 23264064Scgess_cmd1(struct ess_info *sc, u_char cmd, int val) 23364064Scg{ 23464140Snsayer DEB(printf("ess_cmd1: %x, %x\n", cmd, val)); 23564064Scg if (ess_dspwr(sc, cmd)) { 23664064Scg return ess_dspwr(sc, val & 0xff); 23764064Scg } else return 0; 23864064Scg} 23964064Scg 24064064Scgstatic void 24164064Scgess_setmixer(struct ess_info *sc, u_int port, u_int value) 24264064Scg{ 24364064Scg DEB(printf("ess_setmixer: reg=%x, val=%x\n", port, value);) 24464064Scg ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 24564064Scg DELAY(10); 24664064Scg ess_wr(sc, SB_MIX_DATA, (u_char) (value & 0xff)); 24764064Scg DELAY(10); 24864064Scg} 24964064Scg 25064064Scgstatic int 25164064Scgess_getmixer(struct ess_info *sc, u_int port) 25264064Scg{ 25364064Scg int val; 25464064Scg 25564064Scg ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 25664064Scg DELAY(10); 25764064Scg val = ess_rd(sc, SB_MIX_DATA); 25864064Scg DELAY(10); 25964064Scg 26064064Scg return val; 26164064Scg} 26264064Scg 26364064Scgstatic int 26464064Scgess_get_byte(struct ess_info *sc) 26564064Scg{ 26664064Scg int i; 26764064Scg 26864064Scg for (i = 1000; i > 0; i--) { 26964447Snsayer if (ess_rd(sc, 0xc) & 0x40) 27064064Scg return ess_rd(sc, DSP_READ); 27164064Scg else 27264064Scg DELAY(20); 27364064Scg } 27464064Scg return -1; 27564064Scg} 27664064Scg 27764064Scgstatic int 27864064Scgess_write(struct ess_info *sc, u_char reg, int val) 27964064Scg{ 28064064Scg return ess_cmd1(sc, reg, val); 28164064Scg} 28264064Scg 28364064Scgstatic int 28464064Scgess_read(struct ess_info *sc, u_char reg) 28564064Scg{ 28664064Scg return (ess_cmd(sc, 0xc0) && ess_cmd(sc, reg))? ess_get_byte(sc) : -1; 28764064Scg} 28864064Scg 28964064Scgstatic int 29064064Scgess_reset_dsp(struct ess_info *sc) 29164064Scg{ 29264140Snsayer DEB(printf("ess_reset_dsp\n")); 29364064Scg ess_wr(sc, SBDSP_RST, 3); 29464064Scg DELAY(100); 29564064Scg ess_wr(sc, SBDSP_RST, 0); 29664064Scg if (ess_get_byte(sc) != 0xAA) { 29764140Snsayer DEB(printf("ess_reset_dsp failed\n")); 29864140Snsayer/* 29964064Scg rman_get_start(d->io_base))); 30064140Snsayer*/ 30164064Scg return ENXIO; /* Sorry */ 30264064Scg } 30364064Scg ess_cmd(sc, 0xc6); 30464064Scg return 0; 30564064Scg} 30664064Scg 30764064Scgstatic void 30864064Scgess_intr(void *arg) 30964064Scg{ 31064064Scg struct ess_info *sc = (struct ess_info *)arg; 31164163Snsayer int src, pirq = 0, rirq = 0; 31264064Scg 313154066Sariff ess_lock(sc); 31464064Scg src = 0; 31564064Scg if (ess_getmixer(sc, 0x7a) & 0x80) 31664064Scg src |= 2; 31764064Scg if (ess_rd(sc, 0x0c) & 0x01) 31864064Scg src |= 1; 31964064Scg 320160127Syongari if (src == 0) { 321160127Syongari ess_unlock(sc); 32264846Scg return; 323160127Syongari } 32464846Scg 32564163Snsayer if (sc->duplex) { 32664163Snsayer pirq = (src & sc->pch.hwch)? 1 : 0; 32764163Snsayer rirq = (src & sc->rch.hwch)? 1 : 0; 32864163Snsayer } else { 32964163Snsayer if (sc->simplex_dir == PCMDIR_PLAY) 33064163Snsayer pirq = 1; 33164163Snsayer if (sc->simplex_dir == PCMDIR_REC) 33264163Snsayer rirq = 1; 33364163Snsayer if (!pirq && !rirq) 33464163Snsayer printf("solo: IRQ neither playback nor rec!\n"); 33564163Snsayer } 33664064Scg 33764140Snsayer DEB(printf("ess_intr: pirq:%d rirq:%d\n",pirq,rirq)); 33864140Snsayer 33964064Scg if (pirq) { 34064064Scg if (sc->pch.stopping) { 34164064Scg ess_dmatrigger(sc, sc->pch.hwch, 0); 34264064Scg sc->pch.stopping = 0; 34364064Scg if (sc->pch.hwch == 1) 34464064Scg ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01); 34564064Scg else 34664064Scg ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x03); 34764064Scg } 348154066Sariff ess_unlock(sc); 34964064Scg chn_intr(sc->pch.channel); 350154066Sariff ess_lock(sc); 35164064Scg } 35264064Scg 35364064Scg if (rirq) { 35464064Scg if (sc->rch.stopping) { 35564064Scg ess_dmatrigger(sc, sc->rch.hwch, 0); 35664064Scg sc->rch.stopping = 0; 35764064Scg /* XXX: will this stop audio2? */ 35864064Scg ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01); 35964064Scg } 360154066Sariff ess_unlock(sc); 36164064Scg chn_intr(sc->rch.channel); 362154066Sariff ess_lock(sc); 36364064Scg } 36464064Scg 36564064Scg if (src & 2) 36664064Scg ess_setmixer(sc, 0x7a, ess_getmixer(sc, 0x7a) & ~0x80); 36764064Scg if (src & 1) 36864064Scg ess_rd(sc, DSP_DATA_AVAIL); 369154066Sariff 370154066Sariff ess_unlock(sc); 37164064Scg} 37264064Scg 37364064Scg/* utility functions for ESS */ 37464064Scgstatic u_int8_t 37564064Scgess_calcspeed8(int *spd) 37664064Scg{ 37764064Scg int speed = *spd; 37864064Scg u_int32_t t; 37964064Scg 38064064Scg if (speed > 22000) { 38164064Scg t = (795500 + speed / 2) / speed; 38264064Scg speed = (795500 + t / 2) / t; 38364064Scg t = (256 - t) | 0x80; 38464064Scg } else { 38564064Scg t = (397700 + speed / 2) / speed; 38664064Scg speed = (397700 + t / 2) / t; 38764064Scg t = 128 - t; 38864064Scg } 38964064Scg *spd = speed; 39064064Scg return t & 0x000000ff; 39164064Scg} 39264064Scg 39364064Scgstatic u_int8_t 39464064Scgess_calcspeed9(int *spd) 39564064Scg{ 39664064Scg int speed, s0, s1, use0; 39764064Scg u_int8_t t0, t1; 39864064Scg 39964064Scg /* rate = source / (256 - divisor) */ 40064064Scg /* divisor = 256 - (source / rate) */ 40164064Scg speed = *spd; 40264064Scg t0 = 128 - (793800 / speed); 40364064Scg s0 = 793800 / (128 - t0); 40464064Scg 40564064Scg t1 = 128 - (768000 / speed); 40664064Scg s1 = 768000 / (128 - t1); 40764064Scg t1 |= 0x80; 40864064Scg 40964064Scg use0 = (ABS(speed - s0) < ABS(speed - s1))? 1 : 0; 41064064Scg 41164064Scg *spd = use0? s0 : s1; 41264064Scg return use0? t0 : t1; 41364064Scg} 41464064Scg 41564064Scgstatic u_int8_t 41664064Scgess_calcfilter(int spd) 41764064Scg{ 41864064Scg int cutoff; 41964064Scg 42064064Scg /* cutoff = 7160000 / (256 - divisor) */ 42164064Scg /* divisor = 256 - (7160000 / cutoff) */ 42264064Scg cutoff = (spd * 9 * 82) / 20; 42364064Scg return (256 - (7160000 / cutoff)); 42464064Scg} 42564064Scg 42664064Scgstatic int 42764064Scgess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int len) 42864064Scg{ 42964064Scg int play = (dir == PCMDIR_PLAY)? 1 : 0; 43064064Scg int b16 = (fmt & AFMT_16BIT)? 1 : 0; 431193640Sariff int stereo = (AFMT_CHANNEL(fmt) > 1)? 1 : 0; 432193640Sariff int unsign = (!(fmt & AFMT_SIGNED))? 1 : 0; 43364064Scg u_int8_t spdval, fmtval; 43464064Scg 43564140Snsayer DEB(printf("ess_setupch\n")); 43664064Scg spdval = (sc->newspeed)? ess_calcspeed9(&spd) : ess_calcspeed8(&spd); 43764064Scg 43864163Snsayer sc->simplex_dir = play ? PCMDIR_PLAY : PCMDIR_REC ; 43964163Snsayer 44064064Scg if (ch == 1) { 44164064Scg KASSERT((dir == PCMDIR_PLAY) || (dir == PCMDIR_REC), ("ess_setupch: dir1 bad")); 44264064Scg len = -len; 44364064Scg /* transfer length low */ 44464064Scg ess_write(sc, 0xa4, len & 0x00ff); 44564064Scg /* transfer length high */ 44664064Scg ess_write(sc, 0xa5, (len & 0xff00) >> 8); 44764064Scg /* autoinit, dma dir */ 44864140Snsayer ess_write(sc, 0xb8, 0x04 | (play? 0x00 : 0x0a)); 44964064Scg /* mono/stereo */ 45064064Scg ess_write(sc, 0xa8, (ess_read(sc, 0xa8) & ~0x03) | (stereo? 0x01 : 0x02)); 45164064Scg /* demand mode, 4 bytes/xfer */ 45264064Scg ess_write(sc, 0xb9, 0x02); 45364064Scg /* sample rate */ 45464064Scg ess_write(sc, 0xa1, spdval); 45564064Scg /* filter cutoff */ 45664064Scg ess_write(sc, 0xa2, ess_calcfilter(spd)); 45764064Scg /* setup dac/adc */ 45864064Scg /* 45964064Scg if (play) 46064064Scg ess_write(sc, 0xb6, unsign? 0x80 : 0x00); 46164064Scg */ 46264064Scg /* mono, b16: signed, load signal */ 46364064Scg /* 46464064Scg ess_write(sc, 0xb7, 0x51 | (unsign? 0x00 : 0x20)); 46564064Scg */ 46664064Scg /* setup fifo */ 46764140Snsayer ess_write(sc, 0xb7, 0x91 | (unsign? 0x00 : 0x20) | 46864064Scg (b16? 0x04 : 0x00) | 46964064Scg (stereo? 0x08 : 0x40)); 47064064Scg /* irq control */ 47164064Scg ess_write(sc, 0xb1, (ess_read(sc, 0xb1) & 0x0f) | 0x50); 47264064Scg /* drq control */ 47364064Scg ess_write(sc, 0xb2, (ess_read(sc, 0xb2) & 0x0f) | 0x50); 47464064Scg } else if (ch == 2) { 47564064Scg KASSERT(dir == PCMDIR_PLAY, ("ess_setupch: dir2 bad")); 47664064Scg len >>= 1; 47764064Scg len = -len; 47864064Scg /* transfer length low */ 47964064Scg ess_setmixer(sc, 0x74, len & 0x00ff); 48064064Scg /* transfer length high */ 48164064Scg ess_setmixer(sc, 0x76, (len & 0xff00) >> 8); 48264064Scg /* autoinit, 4 bytes/req */ 48364064Scg ess_setmixer(sc, 0x78, 0x10); 48464083Snsayer fmtval = b16 | (stereo << 1) | ((!unsign) << 2); 48564064Scg /* enable irq, set format */ 48664064Scg ess_setmixer(sc, 0x7a, 0x40 | fmtval); 48764064Scg if (sc->newspeed) { 48864064Scg /* sample rate */ 48964064Scg ess_setmixer(sc, 0x70, spdval); 49064064Scg /* filter cutoff */ 49164064Scg ess_setmixer(sc, 0x72, ess_calcfilter(spd)); 49264064Scg } 49364064Scg 49464064Scg } 49564064Scg return 0; 49664064Scg} 49764064Scgstatic int 49864064Scgess_start(struct ess_chinfo *ch) 49964064Scg{ 50064064Scg struct ess_info *sc = ch->parent; 50164064Scg 50264140Snsayer DEB(printf("ess_start\n");); 50370291Scg ess_setupch(sc, ch->hwch, ch->dir, ch->spd, ch->fmt, ch->blksz); 50464064Scg ch->stopping = 0; 50564122Snsayer if (ch->hwch == 1) { 50664064Scg ess_write(sc, 0xb8, ess_read(sc, 0xb8) | 0x01); 50764122Snsayer if (ch->dir == PCMDIR_PLAY) { 50864447Snsayer#if 0 50964122Snsayer DELAY(100000); /* 100 ms */ 51064447Snsayer#endif 51164122Snsayer ess_cmd(sc, 0xd1); 51264122Snsayer } 51364122Snsayer } else 51464064Scg ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) | 0x03); 51564064Scg return 0; 51664064Scg} 51764064Scg 51864064Scgstatic int 51964064Scgess_stop(struct ess_chinfo *ch) 52064064Scg{ 52164064Scg struct ess_info *sc = ch->parent; 52264064Scg 52364140Snsayer DEB(printf("ess_stop\n")); 52464064Scg ch->stopping = 1; 52564064Scg if (ch->hwch == 1) 52664064Scg ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x04); 52764064Scg else 52864064Scg ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x10); 52964140Snsayer DEB(printf("done with stop\n")); 53064064Scg return 0; 53164064Scg} 53264064Scg 53370134Scg/* -------------------------------------------------------------------- */ 53464064Scg/* channel interface for ESS18xx */ 53564064Scgstatic void * 53674763Scgesschan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 53764064Scg{ 53864064Scg struct ess_info *sc = devinfo; 53964064Scg struct ess_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch; 54064064Scg 54164140Snsayer DEB(printf("esschan_init\n")); 54264064Scg ch->parent = sc; 54364064Scg ch->channel = c; 54464064Scg ch->buffer = b; 54565644Scg ch->dir = dir; 546168847Sariff if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsz) != 0) 54764064Scg return NULL; 54864064Scg ch->hwch = 1; 54964064Scg if ((dir == PCMDIR_PLAY) && (sc->duplex)) 55064064Scg ch->hwch = 2; 55164064Scg return ch; 55264064Scg} 55364064Scg 55464064Scgstatic int 55570134Scgesschan_setformat(kobj_t obj, void *data, u_int32_t format) 55664064Scg{ 55764064Scg struct ess_chinfo *ch = data; 55864064Scg 55964064Scg ch->fmt = format; 56064064Scg return 0; 56164064Scg} 56264064Scg 563193640Sariffstatic u_int32_t 56470134Scgesschan_setspeed(kobj_t obj, void *data, u_int32_t speed) 56564064Scg{ 56664064Scg struct ess_chinfo *ch = data; 56764064Scg struct ess_info *sc = ch->parent; 56864064Scg 56964064Scg ch->spd = speed; 57064064Scg if (sc->newspeed) 57164064Scg ess_calcspeed9(&ch->spd); 57264064Scg else 57364064Scg ess_calcspeed8(&ch->spd); 57464064Scg return ch->spd; 57564064Scg} 57664064Scg 577193640Sariffstatic u_int32_t 57870134Scgesschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 57964064Scg{ 58070291Scg struct ess_chinfo *ch = data; 58170291Scg 58270291Scg ch->blksz = blocksize; 58370291Scg return ch->blksz; 58464064Scg} 58564064Scg 58664064Scgstatic int 58770134Scgesschan_trigger(kobj_t obj, void *data, int go) 58864064Scg{ 58964064Scg struct ess_chinfo *ch = data; 59064064Scg struct ess_info *sc = ch->parent; 59164064Scg 592170521Sariff if (!PCMTRIG_COMMON(go)) 59364064Scg return 0; 59464064Scg 595170521Sariff DEB(printf("esschan_trigger: %d\n",go)); 596170521Sariff 597154066Sariff ess_lock(sc); 59864064Scg switch (go) { 59964064Scg case PCMTRIG_START: 600111183Scognet ess_dmasetup(sc, ch->hwch, sndbuf_getbufaddr(ch->buffer), sndbuf_getsize(ch->buffer), ch->dir); 60164064Scg ess_dmatrigger(sc, ch->hwch, 1); 60264064Scg ess_start(ch); 60364064Scg break; 60464064Scg 60564064Scg case PCMTRIG_STOP: 60664064Scg case PCMTRIG_ABORT: 60764064Scg default: 60864064Scg ess_stop(ch); 60964064Scg break; 61064064Scg } 611154066Sariff ess_unlock(sc); 61264064Scg return 0; 61364064Scg} 61464064Scg 615193640Sariffstatic u_int32_t 61670134Scgesschan_getptr(kobj_t obj, void *data) 61764064Scg{ 61864064Scg struct ess_chinfo *ch = data; 61964064Scg struct ess_info *sc = ch->parent; 620193640Sariff u_int32_t ret; 62164064Scg 622154066Sariff ess_lock(sc); 623154066Sariff ret = ess_dmapos(sc, ch->hwch); 624154066Sariff ess_unlock(sc); 625154066Sariff return ret; 62664064Scg} 62764064Scg 62874763Scgstatic struct pcmchan_caps * 62970134Scgesschan_getcaps(kobj_t obj, void *data) 63064064Scg{ 63164064Scg struct ess_chinfo *ch = data; 63264064Scg 63364064Scg return (ch->dir == PCMDIR_PLAY)? &ess_playcaps : &ess_reccaps; 63464064Scg} 63564064Scg 63670134Scgstatic kobj_method_t esschan_methods[] = { 63770134Scg KOBJMETHOD(channel_init, esschan_init), 63870134Scg KOBJMETHOD(channel_setformat, esschan_setformat), 63970134Scg KOBJMETHOD(channel_setspeed, esschan_setspeed), 64070134Scg KOBJMETHOD(channel_setblocksize, esschan_setblocksize), 64170134Scg KOBJMETHOD(channel_trigger, esschan_trigger), 64270134Scg KOBJMETHOD(channel_getptr, esschan_getptr), 64370134Scg KOBJMETHOD(channel_getcaps, esschan_getcaps), 644193640Sariff KOBJMETHOD_END 64570134Scg}; 64670134ScgCHANNEL_DECLARE(esschan); 64770134Scg 64864064Scg/************************************************************/ 64964064Scg 65064064Scgstatic int 65174763Scgessmix_init(struct snd_mixer *m) 65264064Scg{ 65364064Scg struct ess_info *sc = mix_getdevinfo(m); 65464064Scg 65564064Scg mix_setrecdevs(m, SOUND_MASK_CD | SOUND_MASK_MIC | SOUND_MASK_LINE | 65664064Scg SOUND_MASK_IMIX); 65764064Scg 65864064Scg mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | 65964064Scg SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME | 66064064Scg SOUND_MASK_LINE1); 66164064Scg 66264064Scg ess_setmixer(sc, 0, 0); /* reset */ 66364064Scg 66464064Scg return 0; 66564064Scg} 66664064Scg 66764064Scgstatic int 66874763Scgessmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 66964064Scg{ 67064064Scg struct ess_info *sc = mix_getdevinfo(m); 67164064Scg int preg = 0, rreg = 0, l, r; 67264064Scg 67364064Scg l = (left * 15) / 100; 67464064Scg r = (right * 15) / 100; 67564064Scg switch (dev) { 67664064Scg case SOUND_MIXER_SYNTH: 67764064Scg preg = 0x36; 67864064Scg rreg = 0x6b; 67964064Scg break; 68064064Scg 68164064Scg case SOUND_MIXER_PCM: 68264064Scg preg = 0x14; 68364064Scg rreg = 0x7c; 68464064Scg break; 68564064Scg 68664064Scg case SOUND_MIXER_LINE: 68764064Scg preg = 0x3e; 68864064Scg rreg = 0x6e; 68964064Scg break; 69064064Scg 69164064Scg case SOUND_MIXER_MIC: 69264064Scg preg = 0x1a; 69364064Scg rreg = 0x68; 69464064Scg break; 69564064Scg 69664064Scg case SOUND_MIXER_LINE1: 69764064Scg preg = 0x3a; 69864064Scg rreg = 0x6c; 69964064Scg break; 70064064Scg 70164064Scg case SOUND_MIXER_CD: 70264064Scg preg = 0x38; 70364064Scg rreg = 0x6a; 70464064Scg break; 70564064Scg 70664064Scg case SOUND_MIXER_VOLUME: 70764064Scg l = left? (left * 63) / 100 : 64; 70864064Scg r = right? (right * 63) / 100 : 64; 70964064Scg ess_setmixer(sc, 0x60, l); 71064064Scg ess_setmixer(sc, 0x62, r); 71164064Scg left = (l == 64)? 0 : (l * 100) / 63; 71264064Scg right = (r == 64)? 0 : (r * 100) / 63; 71364064Scg return left | (right << 8); 71464064Scg } 71564064Scg 71664064Scg if (preg) 71764064Scg ess_setmixer(sc, preg, (l << 4) | r); 71864064Scg if (rreg) 71964064Scg ess_setmixer(sc, rreg, (l << 4) | r); 72064064Scg 72164064Scg left = (l * 100) / 15; 72264064Scg right = (r * 100) / 15; 72364064Scg 72464064Scg return left | (right << 8); 72564064Scg} 72664064Scg 727193640Sariffstatic u_int32_t 72874763Scgessmix_setrecsrc(struct snd_mixer *m, u_int32_t src) 72964064Scg{ 73064064Scg struct ess_info *sc = mix_getdevinfo(m); 73164064Scg u_char recdev; 73264064Scg 73364064Scg switch (src) { 73464064Scg case SOUND_MASK_CD: 73564064Scg recdev = 0x02; 73664064Scg break; 73764064Scg 73864064Scg case SOUND_MASK_LINE: 73964064Scg recdev = 0x06; 74064064Scg break; 74164064Scg 74264064Scg case SOUND_MASK_IMIX: 74364064Scg recdev = 0x05; 74464064Scg break; 74564064Scg 74664064Scg case SOUND_MASK_MIC: 74764064Scg default: 74864064Scg recdev = 0x00; 74964064Scg src = SOUND_MASK_MIC; 75064064Scg break; 75164064Scg } 75264064Scg 75364064Scg ess_setmixer(sc, 0x1c, recdev); 75464064Scg 75564064Scg return src; 75664064Scg} 75764064Scg 75870134Scgstatic kobj_method_t solomixer_methods[] = { 75970134Scg KOBJMETHOD(mixer_init, essmix_init), 76070134Scg KOBJMETHOD(mixer_set, essmix_set), 76170134Scg KOBJMETHOD(mixer_setrecsrc, essmix_setrecsrc), 762193640Sariff KOBJMETHOD_END 76370134Scg}; 76470134ScgMIXER_DECLARE(solomixer); 76570134Scg 76664064Scg/************************************************************/ 76764064Scg 76864064Scgstatic int 76964064Scgess_dmasetup(struct ess_info *sc, int ch, u_int32_t base, u_int16_t cnt, int dir) 77064064Scg{ 77164064Scg KASSERT(ch == 1 || ch == 2, ("bad ch")); 77264064Scg sc->dmasz[ch - 1] = cnt; 77364064Scg if (ch == 1) { 77464122Snsayer port_wr(sc->vc, 0x8, 0xc4, 1); /* command */ 77564064Scg port_wr(sc->vc, 0xd, 0xff, 1); /* reset */ 77664064Scg port_wr(sc->vc, 0xf, 0x01, 1); /* mask */ 77764122Snsayer port_wr(sc->vc, 0xb, dir == PCMDIR_PLAY? 0x58 : 0x54, 1); /* mode */ 77864064Scg port_wr(sc->vc, 0x0, base, 4); 77964447Snsayer port_wr(sc->vc, 0x4, cnt - 1, 2); 78064064Scg 78164064Scg } else if (ch == 2) { 78264064Scg port_wr(sc->io, 0x6, 0x08, 1); /* autoinit */ 78364064Scg port_wr(sc->io, 0x0, base, 4); 78464064Scg port_wr(sc->io, 0x4, cnt, 2); 78564064Scg } 78664064Scg return 0; 78764064Scg} 78864064Scg 78964064Scgstatic int 79064064Scgess_dmapos(struct ess_info *sc, int ch) 79164064Scg{ 79264623Snsayer int p = 0, i = 0, j = 0; 79364064Scg 79464064Scg KASSERT(ch == 1 || ch == 2, ("bad ch")); 79564447Snsayer if (ch == 1) { 79664447Snsayer 79764447Snsayer/* 79864447Snsayer * During recording, this register is known to give back 79964447Snsayer * garbage if it's not quiescent while being read. That's 80064623Snsayer * why we spl, stop the DMA, and try over and over until 80164623Snsayer * adjacent reads are "close", in the right order and not 80264623Snsayer * bigger than is otherwise possible. 80364447Snsayer */ 80464447Snsayer ess_dmatrigger(sc, ch, 0); 80564623Snsayer DELAY(20); 80664623Snsayer do { 80764623Snsayer DELAY(10); 80864623Snsayer if (j > 1) 80964623Snsayer printf("DMA count reg bogus: %04x & %04x\n", 81064623Snsayer i, p); 81164623Snsayer i = port_rd(sc->vc, 0x4, 2) + 1; 81264623Snsayer p = port_rd(sc->vc, 0x4, 2) + 1; 81370291Scg } while ((p > sc->dmasz[ch - 1] || i < p || (p - i) > 0x8) && j++ < 1000); 81464447Snsayer ess_dmatrigger(sc, ch, 1); 81564447Snsayer } 81664064Scg else if (ch == 2) 81764064Scg p = port_rd(sc->io, 0x4, 2); 81864064Scg return sc->dmasz[ch - 1] - p; 81964064Scg} 82064064Scg 82164064Scgstatic int 82264064Scgess_dmatrigger(struct ess_info *sc, int ch, int go) 82364064Scg{ 82464064Scg KASSERT(ch == 1 || ch == 2, ("bad ch")); 82564064Scg if (ch == 1) 82664119Snsayer port_wr(sc->vc, 0xf, go? 0x00 : 0x01, 1); /* mask */ 82764064Scg else if (ch == 2) 82864064Scg port_wr(sc->io, 0x6, 0x08 | (go? 0x02 : 0x00), 1); /* autoinit */ 82964064Scg return 0; 83064064Scg} 83164064Scg 83264064Scgstatic void 83364064Scgess_release_resources(struct ess_info *sc, device_t dev) 83464064Scg{ 83564064Scg if (sc->irq) { 83665644Scg if (sc->ih) 83765644Scg bus_teardown_intr(dev, sc->irq, sc->ih); 83864064Scg bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 83964064Scg sc->irq = 0; 84064064Scg } 84164064Scg if (sc->io) { 842119690Sjhb bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(0), sc->io); 84364064Scg sc->io = 0; 84464064Scg } 84564064Scg 84664064Scg if (sc->sb) { 847119690Sjhb bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(1), sc->sb); 84864064Scg sc->sb = 0; 84964064Scg } 85064064Scg 85164064Scg if (sc->vc) { 852119690Sjhb bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(2), sc->vc); 85364064Scg sc->vc = 0; 85464064Scg } 85564064Scg 85664064Scg if (sc->mpu) { 857119690Sjhb bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(3), sc->mpu); 85864064Scg sc->mpu = 0; 85964064Scg } 86064064Scg 86164064Scg if (sc->gp) { 862119690Sjhb bus_release_resource(dev, SYS_RES_IOPORT, PCIR_BAR(4), sc->gp); 86364064Scg sc->gp = 0; 86464064Scg } 86564064Scg 86665644Scg if (sc->parent_dmat) { 86765644Scg bus_dma_tag_destroy(sc->parent_dmat); 86865644Scg sc->parent_dmat = 0; 86965644Scg } 87065644Scg 871154066Sariff#if ESS18XX_MPSAFE == 1 872154066Sariff if (sc->lock) { 873154066Sariff snd_mtxfree(sc->lock); 874154066Sariff sc->lock = NULL; 875154066Sariff } 876154066Sariff#endif 877154066Sariff 87864064Scg free(sc, M_DEVBUF); 87964064Scg} 88064064Scg 88164064Scgstatic int 88264064Scgess_alloc_resources(struct ess_info *sc, device_t dev) 88364064Scg{ 88464064Scg int rid; 88564064Scg 886119690Sjhb rid = PCIR_BAR(0); 887127135Snjl sc->io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 88864064Scg 889119690Sjhb rid = PCIR_BAR(1); 890127135Snjl sc->sb = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 89164064Scg 892119690Sjhb rid = PCIR_BAR(2); 893127135Snjl sc->vc = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 89464064Scg 895119690Sjhb rid = PCIR_BAR(3); 896127135Snjl sc->mpu = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 89764064Scg 898119690Sjhb rid = PCIR_BAR(4); 899127135Snjl sc->gp = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 90064064Scg 90164064Scg rid = 0; 902127135Snjl sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 903127135Snjl RF_ACTIVE | RF_SHAREABLE); 90464064Scg 905154066Sariff#if ESS18XX_MPSAFE == 1 906167608Sariff sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_solo softc"); 907154066Sariff 908154066Sariff return (sc->irq && sc->io && sc->sb && sc->vc && 909154066Sariff sc->mpu && sc->gp && sc->lock)? 0 : ENXIO; 910154066Sariff#else 91164064Scg return (sc->irq && sc->io && sc->sb && sc->vc && sc->mpu && sc->gp)? 0 : ENXIO; 912154066Sariff#endif 91364064Scg} 91464064Scg 91564064Scgstatic int 91664064Scgess_probe(device_t dev) 91764064Scg{ 91864064Scg char *s = NULL; 91964064Scg u_int32_t subdev; 92064064Scg 92164064Scg subdev = (pci_get_subdevice(dev) << 16) | pci_get_subvendor(dev); 92264064Scg switch (pci_get_devid(dev)) { 92364064Scg case 0x1969125d: 92464064Scg if (subdev == 0x8888125d) 92564064Scg s = "ESS Solo-1E"; 92664064Scg else if (subdev == 0x1818125d) 92764064Scg s = "ESS Solo-1"; 92864064Scg else 92964064Scg s = "ESS Solo-1 (unknown vendor)"; 93064064Scg break; 93164064Scg } 93264064Scg 93364064Scg if (s) 93464064Scg device_set_desc(dev, s); 935142890Simp return s ? BUS_PROBE_DEFAULT : ENXIO; 93664064Scg} 93764064Scg 938102390Sorion#define ESS_PCI_LEGACYCONTROL 0x40 939102390Sorion#define ESS_PCI_CONFIG 0x50 940102390Sorion#define ESS_PCI_DDMACONTROL 0x60 94164064Scg 942102390Sorionstatic int 943102390Sorioness_suspend(device_t dev) 944102390Sorion{ 945102390Sorion return 0; 946102390Sorion} 947102390Sorion 948102390Sorionstatic int 949102390Sorioness_resume(device_t dev) 950102390Sorion{ 951102390Sorion uint16_t ddma; 952102390Sorion struct ess_info *sc = pcm_getdevinfo(dev); 953102390Sorion 954154066Sariff ess_lock(sc); 955102390Sorion ddma = rman_get_start(sc->vc) | 1; 956102390Sorion pci_write_config(dev, ESS_PCI_LEGACYCONTROL, 0x805f, 2); 957102390Sorion pci_write_config(dev, ESS_PCI_DDMACONTROL, ddma, 2); 958102390Sorion pci_write_config(dev, ESS_PCI_CONFIG, 0, 2); 959102390Sorion 960154066Sariff if (ess_reset_dsp(sc)) { 961154066Sariff ess_unlock(sc); 962102390Sorion goto no; 963154066Sariff } 964154066Sariff ess_unlock(sc); 965102390Sorion if (mixer_reinit(dev)) 966102390Sorion goto no; 967154066Sariff ess_lock(sc); 968102390Sorion if (sc->newspeed) 969102390Sorion ess_setmixer(sc, 0x71, 0x2a); 970102390Sorion 971102390Sorion port_wr(sc->io, 0x7, 0xb0, 1); /* enable irqs */ 972154066Sariff ess_unlock(sc); 973102390Sorion 974102390Sorion return 0; 975102390Sorion no: 976102390Sorion return EIO; 977102390Sorion} 978102390Sorion 97964064Scgstatic int 98064064Scgess_attach(device_t dev) 98164064Scg{ 98264064Scg struct ess_info *sc; 98364064Scg char status[SND_STATUSLEN]; 98464064Scg u_int16_t ddma; 98564064Scg 986170873Sariff sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 987254306Sscottl pci_enable_busmaster(dev); 98864064Scg 98964064Scg if (ess_alloc_resources(sc, dev)) 99064064Scg goto no; 99164064Scg 99284658Scg sc->bufsz = pcm_getbuffersize(dev, 4096, SOLO_DEFAULT_BUFSZ, 65536); 99384658Scg 99464064Scg ddma = rman_get_start(sc->vc) | 1; 995102390Sorion pci_write_config(dev, ESS_PCI_LEGACYCONTROL, 0x805f, 2); 996102390Sorion pci_write_config(dev, ESS_PCI_DDMACONTROL, ddma, 2); 997102390Sorion pci_write_config(dev, ESS_PCI_CONFIG, 0, 2); 99864064Scg 99964064Scg port_wr(sc->io, 0x7, 0xb0, 1); /* enable irqs */ 100064163Snsayer#ifdef ESS18XX_DUPLEX 100164064Scg sc->duplex = 1; 100264163Snsayer#else 100364163Snsayer sc->duplex = 0; 100464163Snsayer#endif 100564163Snsayer 100664163Snsayer#ifdef ESS18XX_NEWSPEED 100764064Scg sc->newspeed = 1; 100864163Snsayer#else 100964163Snsayer sc->newspeed = 0; 101064163Snsayer#endif 1011154066Sariff if (snd_setup_intr(dev, sc->irq, 1012154066Sariff#if ESS18XX_MPSAFE == 1 1013154066Sariff INTR_MPSAFE 1014154066Sariff#else 1015154066Sariff 0 1016154066Sariff#endif 1017154066Sariff , ess_intr, sc, &sc->ih)) { 1018154066Sariff device_printf(dev, "unable to map interrupt\n"); 1019154066Sariff goto no; 1020154066Sariff } 102164064Scg 102264064Scg if (!sc->duplex) 102364064Scg pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 102464064Scg 1025154066Sariff#if 0 1026166904Snetchild if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/65536, /*boundary*/0, 1027154066Sariff#endif 1028166904Snetchild if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, /*boundary*/0, 102964064Scg /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 103064064Scg /*highaddr*/BUS_SPACE_MAXADDR, 103164064Scg /*filter*/NULL, /*filterarg*/NULL, 103284658Scg /*maxsize*/sc->bufsz, /*nsegments*/1, 103364064Scg /*maxsegz*/0x3ffff, 1034154066Sariff /*flags*/0, 1035154066Sariff#if ESS18XX_MPSAFE == 1 1036154066Sariff /*lockfunc*/NULL, /*lockarg*/NULL, 1037154066Sariff#else 1038154066Sariff /*lockfunc*/busdma_lock_mutex, /*lockarg*/&Giant, 1039154066Sariff#endif 1040154066Sariff &sc->parent_dmat) != 0) { 104164064Scg device_printf(dev, "unable to create dma tag\n"); 104264064Scg goto no; 104364064Scg } 104464064Scg 1045154066Sariff if (ess_reset_dsp(sc)) 1046154066Sariff goto no; 1047154066Sariff 1048154066Sariff if (sc->newspeed) 1049154066Sariff ess_setmixer(sc, 0x71, 0x2a); 1050154066Sariff 1051154066Sariff if (mixer_init(dev, &solomixer_class, sc)) 1052154066Sariff goto no; 1053154066Sariff 1054126695Smatk snprintf(status, SND_STATUSLEN, "at io 0x%lx,0x%lx,0x%lx irq %ld %s", 105564064Scg rman_get_start(sc->io), rman_get_start(sc->sb), rman_get_start(sc->vc), 1056126695Smatk rman_get_start(sc->irq),PCM_KLDSTRING(snd_solo)); 105764064Scg 105864064Scg if (pcm_register(dev, sc, 1, 1)) 105964064Scg goto no; 106070134Scg pcm_addchan(dev, PCMDIR_REC, &esschan_class, sc); 106170134Scg pcm_addchan(dev, PCMDIR_PLAY, &esschan_class, sc); 106264064Scg pcm_setstatus(dev, status); 106364064Scg 106464064Scg return 0; 106564064Scg 106664064Scgno: 106764064Scg ess_release_resources(sc, dev); 106864064Scg return ENXIO; 106964064Scg} 107064064Scg 107165644Scgstatic int 107265644Scgess_detach(device_t dev) 107365644Scg{ 107465644Scg int r; 107566012Scg struct ess_info *sc; 107665644Scg 107765644Scg r = pcm_unregister(dev); 107865644Scg if (r) 107965644Scg return r; 108065644Scg 108165644Scg sc = pcm_getdevinfo(dev); 108265644Scg ess_release_resources(sc, dev); 108365644Scg return 0; 108465644Scg} 108565644Scg 108664064Scgstatic device_method_t ess_methods[] = { 108764064Scg /* Device interface */ 108864064Scg DEVMETHOD(device_probe, ess_probe), 108964064Scg DEVMETHOD(device_attach, ess_attach), 109065644Scg DEVMETHOD(device_detach, ess_detach), 1091102390Sorion DEVMETHOD(device_resume, ess_resume), 1092102390Sorion DEVMETHOD(device_suspend, ess_suspend), 109364064Scg 109464064Scg { 0, 0 } 109564064Scg}; 109664064Scg 109764064Scgstatic driver_t ess_driver = { 109864064Scg "pcm", 109964064Scg ess_methods, 110082180Scg PCM_SOFTC_SIZE, 110164064Scg}; 110264064Scg 110364064ScgDRIVER_MODULE(snd_solo, pci, ess_driver, pcm_devclass, 0, 0); 1104132236StanimuraMODULE_DEPEND(snd_solo, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 110564064ScgMODULE_VERSION(snd_solo, 1); 110664064Scg 110764064Scg 110864064Scg 1109