1139749Simp/*- 2119853Scg * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3166426Sjoel * Copyright (c) 1997,1998 Luigi Rizzo 458756Scg * 558756Scg * Derived from files in the Voxware 3.5 distribution, 658756Scg * Copyright by Hannu Savolainen 1994, under the same copyright 758756Scg * conditions. 858756Scg * All rights reserved. 958756Scg * 1058756Scg * Redistribution and use in source and binary forms, with or without 1158756Scg * modification, are permitted provided that the following conditions 1258756Scg * are met: 1358756Scg * 1. Redistributions of source code must retain the above copyright 1458756Scg * notice, this list of conditions and the following disclaimer. 1558756Scg * 2. Redistributions in binary form must reproduce the above copyright 1658756Scg * notice, this list of conditions and the following disclaimer in the 1758756Scg * documentation and/or other materials provided with the distribution. 1858756Scg * 1958756Scg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2058756Scg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2158756Scg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2258756Scg * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2358756Scg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2458756Scg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2558756Scg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2658756Scg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2758756Scg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2858756Scg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2958756Scg * SUCH DAMAGE. 3058756Scg */ 3158756Scg 32193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 33193640Sariff#include "opt_snd.h" 34193640Sariff#endif 35193640Sariff 3658756Scg#include <dev/sound/pcm/sound.h> 3758756Scg 3858756Scg#include <dev/sound/isa/sb.h> 3958756Scg#include <dev/sound/chip.h> 4058756Scg 41110499Snyan#include <isa/isavar.h> 42110499Snyan 4370134Scg#include "mixer_if.h" 4470134Scg 4582180ScgSND_DECLARE_FILE("$FreeBSD$"); 4682180Scg 4759323Scg#define ESS_BUFFSIZE (4096) 4858756Scg#define ABS(x) (((x) < 0)? -(x) : (x)) 4958756Scg 5058756Scg/* audio2 never generates irqs and sounds very noisy */ 5158756Scg#undef ESS18XX_DUPLEX 5258756Scg 5358756Scg/* more accurate clocks and split audio1/audio2 rates */ 5458756Scg#define ESS18XX_NEWSPEED 5558756Scg 5664881Scgstatic u_int32_t ess_pfmt[] = { 57193640Sariff SND_FORMAT(AFMT_U8, 1, 0), 58193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 59193640Sariff SND_FORMAT(AFMT_S8, 1, 0), 60193640Sariff SND_FORMAT(AFMT_S8, 2, 0), 61193640Sariff SND_FORMAT(AFMT_S16_LE, 1, 0), 62193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 63193640Sariff SND_FORMAT(AFMT_U16_LE, 1, 0), 64193640Sariff SND_FORMAT(AFMT_U16_LE, 2, 0), 6564881Scg 0 6658756Scg}; 6758756Scg 68154438Sariffstatic struct pcmchan_caps ess_playcaps = {6000, 48000, ess_pfmt, 0}; 6964881Scg 7064881Scgstatic u_int32_t ess_rfmt[] = { 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_LE, 1, 0), 76193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 77193640Sariff SND_FORMAT(AFMT_U16_LE, 1, 0), 78193640Sariff SND_FORMAT(AFMT_U16_LE, 2, 0), 7964881Scg 0 8058756Scg}; 8158756Scg 82154438Sariffstatic struct pcmchan_caps ess_reccaps = {6000, 48000, ess_rfmt, 0}; 8364881Scg 8458756Scgstruct ess_info; 8558756Scg 8658756Scgstruct ess_chinfo { 8758756Scg struct ess_info *parent; 8874763Scg struct pcm_channel *channel; 8974763Scg struct snd_dbuf *buffer; 9070134Scg int dir, hwch, stopping, run; 9170291Scg u_int32_t fmt, spd, blksz; 9258756Scg}; 9358756Scg 9458756Scgstruct ess_info { 9574763Scg device_t parent_dev; 9658756Scg struct resource *io_base; /* I/O address for the board */ 9758756Scg struct resource *irq; 9858756Scg struct resource *drq1; 9958756Scg struct resource *drq2; 10065644Scg void *ih; 10158756Scg bus_dma_tag_t parent_dmat; 10258756Scg 10384111Scg unsigned int bufsize; 104170032Sariff int type; 105170032Sariff unsigned int duplex:1, newspeed:1; 10658756Scg u_long bd_flags; /* board-specific flags */ 10758756Scg struct ess_chinfo pch, rch; 10858756Scg}; 10958756Scg 11084111Scg#if 0 11158756Scgstatic int ess_rd(struct ess_info *sc, int reg); 11258756Scgstatic void ess_wr(struct ess_info *sc, int reg, u_int8_t val); 11358756Scgstatic int ess_dspready(struct ess_info *sc); 11458756Scgstatic int ess_cmd(struct ess_info *sc, u_char val); 11558756Scgstatic int ess_cmd1(struct ess_info *sc, u_char cmd, int val); 11658756Scgstatic int ess_get_byte(struct ess_info *sc); 11758756Scgstatic void ess_setmixer(struct ess_info *sc, u_int port, u_int value); 11858756Scgstatic int ess_getmixer(struct ess_info *sc, u_int port); 11958756Scgstatic int ess_reset_dsp(struct ess_info *sc); 12058756Scg 12158756Scgstatic int ess_write(struct ess_info *sc, u_char reg, int val); 12258756Scgstatic int ess_read(struct ess_info *sc, u_char reg); 12358756Scg 12458756Scgstatic void ess_intr(void *arg); 12558756Scgstatic int ess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int len); 12658756Scgstatic int ess_start(struct ess_chinfo *ch); 12758756Scgstatic int ess_stop(struct ess_chinfo *ch); 12884111Scg#endif 12958756Scg 13058756Scg/* 13158756Scg * Common code for the midi and pcm functions 13258756Scg * 13358756Scg * ess_cmd write a single byte to the CMD port. 13458756Scg * ess_cmd1 write a CMD + 1 byte arg 13558756Scg * ess_cmd2 write a CMD + 2 byte arg 13658756Scg * ess_get_byte returns a single byte from the DSP data port 13758756Scg * 13858756Scg * ess_write is actually ess_cmd1 13958756Scg * ess_read access ext. regs via ess_cmd(0xc0, reg) followed by ess_get_byte 14058756Scg */ 14158756Scg 14274763Scgstatic void 14374763Scgess_lock(struct ess_info *sc) { 14474763Scg 14574763Scg sbc_lock(device_get_softc(sc->parent_dev)); 14674763Scg} 14774763Scg 14874763Scgstatic void 14974763Scgess_unlock(struct ess_info *sc) { 15074763Scg 15174763Scg sbc_unlock(device_get_softc(sc->parent_dev)); 15274763Scg} 15374763Scg 15458756Scgstatic int 15558756Scgport_rd(struct resource *port, int off) 15658756Scg{ 15758756Scg return bus_space_read_1(rman_get_bustag(port), 15858756Scg rman_get_bushandle(port), 15958756Scg off); 16058756Scg} 16158756Scg 16258756Scgstatic void 16358756Scgport_wr(struct resource *port, int off, u_int8_t data) 16458756Scg{ 165108064Ssemenu bus_space_write_1(rman_get_bustag(port), 166108064Ssemenu rman_get_bushandle(port), 167108064Ssemenu off, data); 16858756Scg} 16958756Scg 17058756Scgstatic int 17158756Scgess_rd(struct ess_info *sc, int reg) 17258756Scg{ 17358756Scg return port_rd(sc->io_base, reg); 17458756Scg} 17558756Scg 17658756Scgstatic void 17758756Scgess_wr(struct ess_info *sc, int reg, u_int8_t val) 17858756Scg{ 17958756Scg port_wr(sc->io_base, reg, val); 18058756Scg} 18158756Scg 18258756Scgstatic int 18358756Scgess_dspready(struct ess_info *sc) 18458756Scg{ 18558756Scg return ((ess_rd(sc, SBDSP_STATUS) & 0x80) == 0); 18658756Scg} 18758756Scg 18858756Scgstatic int 18958756Scgess_dspwr(struct ess_info *sc, u_char val) 19058756Scg{ 19158756Scg int i; 19258756Scg 19358756Scg for (i = 0; i < 1000; i++) { 19458756Scg if (ess_dspready(sc)) { 19558756Scg ess_wr(sc, SBDSP_CMD, val); 19658756Scg return 1; 19758756Scg } 19858756Scg if (i > 10) DELAY((i > 100)? 1000 : 10); 19958756Scg } 20058756Scg printf("ess_dspwr(0x%02x) timed out.\n", val); 20158756Scg return 0; 20258756Scg} 20358756Scg 20458756Scgstatic int 20558756Scgess_cmd(struct ess_info *sc, u_char val) 20658756Scg{ 20758756Scg#if 0 20858756Scg printf("ess_cmd: %x\n", val); 20958756Scg#endif 21058756Scg return ess_dspwr(sc, val); 21158756Scg} 21258756Scg 21358756Scgstatic int 21458756Scgess_cmd1(struct ess_info *sc, u_char cmd, int val) 21558756Scg{ 21658756Scg#if 0 21758756Scg printf("ess_cmd1: %x, %x\n", cmd, val); 21858756Scg#endif 21958756Scg if (ess_dspwr(sc, cmd)) { 22058756Scg return ess_dspwr(sc, val & 0xff); 22158756Scg } else return 0; 22258756Scg} 22358756Scg 22458756Scgstatic void 22558756Scgess_setmixer(struct ess_info *sc, u_int port, u_int value) 22658756Scg{ 22758756Scg DEB(printf("ess_setmixer: reg=%x, val=%x\n", port, value);) 22858756Scg ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 22958756Scg DELAY(10); 23058756Scg ess_wr(sc, SB_MIX_DATA, (u_char) (value & 0xff)); 23158756Scg DELAY(10); 23258756Scg} 23358756Scg 23458756Scgstatic int 23558756Scgess_getmixer(struct ess_info *sc, u_int port) 23658756Scg{ 23758756Scg int val; 23858756Scg ess_wr(sc, SB_MIX_ADDR, (u_char) (port & 0xff)); /* Select register */ 23958756Scg DELAY(10); 24058756Scg val = ess_rd(sc, SB_MIX_DATA); 24158756Scg DELAY(10); 24258756Scg 24358756Scg return val; 24458756Scg} 24558756Scg 24658756Scgstatic int 24758756Scgess_get_byte(struct ess_info *sc) 24858756Scg{ 24958756Scg int i; 25058756Scg 25158756Scg for (i = 1000; i > 0; i--) { 25258756Scg if (ess_rd(sc, DSP_DATA_AVAIL) & 0x80) 25358756Scg return ess_rd(sc, DSP_READ); 25458756Scg else 25558756Scg DELAY(20); 25658756Scg } 25758756Scg return -1; 25858756Scg} 25958756Scg 26058756Scgstatic int 26158756Scgess_write(struct ess_info *sc, u_char reg, int val) 26258756Scg{ 26358756Scg return ess_cmd1(sc, reg, val); 26458756Scg} 26558756Scg 26658756Scgstatic int 26758756Scgess_read(struct ess_info *sc, u_char reg) 26858756Scg{ 26958756Scg return (ess_cmd(sc, 0xc0) && ess_cmd(sc, reg))? ess_get_byte(sc) : -1; 27058756Scg} 27158756Scg 27258756Scgstatic int 27358756Scgess_reset_dsp(struct ess_info *sc) 27458756Scg{ 27558756Scg ess_wr(sc, SBDSP_RST, 3); 27658756Scg DELAY(100); 27758756Scg ess_wr(sc, SBDSP_RST, 0); 27858756Scg if (ess_get_byte(sc) != 0xAA) { 27958756Scg DEB(printf("ess_reset_dsp 0x%lx failed\n", 28089774Sscottl rman_get_start(sc->io_base))); 28158756Scg return ENXIO; /* Sorry */ 28258756Scg } 28358756Scg ess_cmd(sc, 0xc6); 28458756Scg return 0; 28558756Scg} 28658756Scg 28758756Scgstatic void 28858756Scgess_release_resources(struct ess_info *sc, device_t dev) 28958756Scg{ 29058756Scg if (sc->irq) { 29165644Scg if (sc->ih) 29265644Scg bus_teardown_intr(dev, sc->irq, sc->ih); 29358756Scg bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq); 29458756Scg sc->irq = 0; 29558756Scg } 29658756Scg if (sc->drq1) { 29784111Scg isa_dma_release(rman_get_start(sc->drq1)); 29858756Scg bus_release_resource(dev, SYS_RES_DRQ, 0, sc->drq1); 29958756Scg sc->drq1 = 0; 30058756Scg } 30158756Scg if (sc->drq2) { 30284111Scg isa_dma_release(rman_get_start(sc->drq2)); 30358756Scg bus_release_resource(dev, SYS_RES_DRQ, 1, sc->drq2); 30458756Scg sc->drq2 = 0; 30558756Scg } 30658756Scg if (sc->io_base) { 30758756Scg bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->io_base); 30858756Scg sc->io_base = 0; 30958756Scg } 31065644Scg if (sc->parent_dmat) { 31165644Scg bus_dma_tag_destroy(sc->parent_dmat); 31265644Scg sc->parent_dmat = 0; 31365644Scg } 31465644Scg free(sc, M_DEVBUF); 31558756Scg} 31658756Scg 31758756Scgstatic int 31858756Scgess_alloc_resources(struct ess_info *sc, device_t dev) 31958756Scg{ 32058756Scg int rid; 32158756Scg 32258756Scg rid = 0; 32358756Scg if (!sc->io_base) 324127135Snjl sc->io_base = bus_alloc_resource_any(dev, SYS_RES_IOPORT, 325127135Snjl &rid, RF_ACTIVE); 32658756Scg rid = 0; 32758756Scg if (!sc->irq) 328127135Snjl sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 329127135Snjl &rid, RF_ACTIVE); 33058756Scg rid = 0; 33158756Scg if (!sc->drq1) 332127135Snjl sc->drq1 = bus_alloc_resource_any(dev, SYS_RES_DRQ, 333127135Snjl &rid, RF_ACTIVE); 33458756Scg rid = 1; 33558756Scg if (!sc->drq2) 336127135Snjl sc->drq2 = bus_alloc_resource_any(dev, SYS_RES_DRQ, 337127135Snjl &rid, RF_ACTIVE); 33858756Scg 33958756Scg if (sc->io_base && sc->drq1 && sc->irq) { 34058756Scg isa_dma_acquire(rman_get_start(sc->drq1)); 34184111Scg isa_dmainit(rman_get_start(sc->drq1), sc->bufsize); 34258756Scg 34358756Scg if (sc->drq2) { 34458756Scg isa_dma_acquire(rman_get_start(sc->drq2)); 34584111Scg isa_dmainit(rman_get_start(sc->drq2), sc->bufsize); 34658756Scg } 34758756Scg 34858756Scg return 0; 34958756Scg } else return ENXIO; 35058756Scg} 35158756Scg 35258756Scgstatic void 35358756Scgess_intr(void *arg) 35458756Scg{ 35558756Scg struct ess_info *sc = (struct ess_info *)arg; 35658756Scg int src, pirq, rirq; 35758756Scg 35874763Scg ess_lock(sc); 35958756Scg src = 0; 36058756Scg if (ess_getmixer(sc, 0x7a) & 0x80) 36158756Scg src |= 2; 36258756Scg if (ess_rd(sc, 0x0c) & 0x01) 36358756Scg src |= 1; 36458756Scg 36558756Scg pirq = (src & sc->pch.hwch)? 1 : 0; 36658756Scg rirq = (src & sc->rch.hwch)? 1 : 0; 36758756Scg 36858756Scg if (pirq) { 369148598Snetchild if (sc->pch.run) { 370148598Snetchild ess_unlock(sc); 37170392Scg chn_intr(sc->pch.channel); 372148598Snetchild ess_lock(sc); 373148598Snetchild } 37458756Scg if (sc->pch.stopping) { 37570134Scg sc->pch.run = 0; 376110499Snyan sndbuf_dma(sc->pch.buffer, PCMTRIG_STOP); 37758756Scg sc->pch.stopping = 0; 37858756Scg if (sc->pch.hwch == 1) 37958756Scg ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01); 38058756Scg else 38158756Scg ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x03); 38258756Scg } 38358756Scg } 38458756Scg 38558756Scg if (rirq) { 386148598Snetchild if (sc->rch.run) { 387148598Snetchild ess_unlock(sc); 38870392Scg chn_intr(sc->rch.channel); 389148598Snetchild ess_lock(sc); 390148598Snetchild } 39158756Scg if (sc->rch.stopping) { 39270134Scg sc->rch.run = 0; 393110499Snyan sndbuf_dma(sc->rch.buffer, PCMTRIG_STOP); 39458756Scg sc->rch.stopping = 0; 39558756Scg /* XXX: will this stop audio2? */ 39658756Scg ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x01); 39758756Scg } 39858756Scg } 39958756Scg 40058756Scg if (src & 2) 40158756Scg ess_setmixer(sc, 0x7a, ess_getmixer(sc, 0x7a) & ~0x80); 40258756Scg if (src & 1) 40358756Scg ess_rd(sc, DSP_DATA_AVAIL); 40474763Scg ess_unlock(sc); 40558756Scg} 40658756Scg 40758756Scg/* utility functions for ESS */ 40858756Scgstatic u_int8_t 40958756Scgess_calcspeed8(int *spd) 41058756Scg{ 41158756Scg int speed = *spd; 41258756Scg u_int32_t t; 41358756Scg 41458756Scg if (speed > 22000) { 41558756Scg t = (795500 + speed / 2) / speed; 41658756Scg speed = (795500 + t / 2) / t; 41758756Scg t = (256 - t) | 0x80; 41858756Scg } else { 41958756Scg t = (397700 + speed / 2) / speed; 42058756Scg speed = (397700 + t / 2) / t; 42158756Scg t = 128 - t; 42258756Scg } 42358756Scg *spd = speed; 42458756Scg return t & 0x000000ff; 42558756Scg} 42658756Scg 42758756Scgstatic u_int8_t 42858756Scgess_calcspeed9(int *spd) 42958756Scg{ 43058756Scg int speed, s0, s1, use0; 43158756Scg u_int8_t t0, t1; 43258756Scg 43358756Scg /* rate = source / (256 - divisor) */ 43458756Scg /* divisor = 256 - (source / rate) */ 43558756Scg speed = *spd; 43660571Scg t0 = 128 - (793800 / speed); 43760571Scg s0 = 793800 / (128 - t0); 43858756Scg 43960571Scg t1 = 128 - (768000 / speed); 44060571Scg s1 = 768000 / (128 - t1); 44160571Scg t1 |= 0x80; 44258756Scg 44358756Scg use0 = (ABS(speed - s0) < ABS(speed - s1))? 1 : 0; 44458756Scg 44558756Scg *spd = use0? s0 : s1; 44658756Scg return use0? t0 : t1; 44758756Scg} 44858756Scg 44958756Scgstatic u_int8_t 45058756Scgess_calcfilter(int spd) 45158756Scg{ 45258756Scg int cutoff; 45358756Scg 45458756Scg /* cutoff = 7160000 / (256 - divisor) */ 45558756Scg /* divisor = 256 - (7160000 / cutoff) */ 45658756Scg cutoff = (spd * 9 * 82) / 20; 45758756Scg return (256 - (7160000 / cutoff)); 45858756Scg} 45958756Scg 46058756Scgstatic int 46158756Scgess_setupch(struct ess_info *sc, int ch, int dir, int spd, u_int32_t fmt, int len) 46258756Scg{ 46358756Scg int play = (dir == PCMDIR_PLAY)? 1 : 0; 46458756Scg int b16 = (fmt & AFMT_16BIT)? 1 : 0; 465193640Sariff int stereo = (AFMT_CHANNEL(fmt) > 1)? 1 : 0; 46658756Scg int unsign = (fmt == AFMT_U8 || fmt == AFMT_U16_LE)? 1 : 0; 46758756Scg u_int8_t spdval, fmtval; 46858756Scg 46958756Scg 47058756Scg spdval = (sc->newspeed)? ess_calcspeed9(&spd) : ess_calcspeed8(&spd); 47158756Scg len = -len; 47258756Scg 47358756Scg if (ch == 1) { 47458756Scg KASSERT((dir == PCMDIR_PLAY) || (dir == PCMDIR_REC), ("ess_setupch: dir1 bad")); 47558756Scg /* transfer length low */ 47658756Scg ess_write(sc, 0xa4, len & 0x00ff); 47758756Scg /* transfer length high */ 47858756Scg ess_write(sc, 0xa5, (len & 0xff00) >> 8); 47958756Scg /* autoinit, dma dir */ 48058756Scg ess_write(sc, 0xb8, 0x04 | (play? 0x00 : 0x0a)); 48158756Scg /* mono/stereo */ 48258756Scg ess_write(sc, 0xa8, (ess_read(sc, 0xa8) & ~0x03) | (stereo? 0x01 : 0x02)); 48358756Scg /* demand mode, 4 bytes/xfer */ 48458756Scg ess_write(sc, 0xb9, 0x02); 48558756Scg /* sample rate */ 48658756Scg ess_write(sc, 0xa1, spdval); 48758756Scg /* filter cutoff */ 48858756Scg ess_write(sc, 0xa2, ess_calcfilter(spd)); 48958756Scg /* setup dac/adc */ 49058756Scg if (play) 49158756Scg ess_write(sc, 0xb6, unsign? 0x80 : 0x00); 49258756Scg /* mono, b16: signed, load signal */ 49358756Scg ess_write(sc, 0xb7, 0x51 | (unsign? 0x00 : 0x20)); 49458756Scg /* setup fifo */ 49558756Scg ess_write(sc, 0xb7, 0x90 | (unsign? 0x00 : 0x20) | 49658756Scg (b16? 0x04 : 0x00) | 49758756Scg (stereo? 0x08 : 0x40)); 49858756Scg /* irq control */ 49958756Scg ess_write(sc, 0xb1, (ess_read(sc, 0xb1) & 0x0f) | 0x50); 50058756Scg /* drq control */ 50158756Scg ess_write(sc, 0xb2, (ess_read(sc, 0xb2) & 0x0f) | 0x50); 50258756Scg } else if (ch == 2) { 50358756Scg KASSERT(dir == PCMDIR_PLAY, ("ess_setupch: dir2 bad")); 50458756Scg /* transfer length low */ 50558756Scg ess_setmixer(sc, 0x74, len & 0x00ff); 50658756Scg /* transfer length high */ 50758756Scg ess_setmixer(sc, 0x76, (len & 0xff00) >> 8); 50858756Scg /* autoinit, 4 bytes/req */ 50958756Scg ess_setmixer(sc, 0x78, 0x90); 51058756Scg fmtval = b16 | (stereo << 1) | (unsign << 2); 51158756Scg /* enable irq, set format */ 51258756Scg ess_setmixer(sc, 0x7a, 0x40 | fmtval); 51358756Scg if (sc->newspeed) { 51458756Scg /* sample rate */ 51558756Scg ess_setmixer(sc, 0x70, spdval); 51658756Scg /* filter cutoff */ 51758756Scg ess_setmixer(sc, 0x72, ess_calcfilter(spd)); 51858756Scg } 51974763Scg } 52058756Scg 52158756Scg return 0; 52258756Scg} 52358756Scgstatic int 52458756Scgess_start(struct ess_chinfo *ch) 52558756Scg{ 52658756Scg struct ess_info *sc = ch->parent; 52758756Scg int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 52858756Scg 52974763Scg ess_lock(sc); 53070291Scg ess_setupch(sc, ch->hwch, ch->dir, ch->spd, ch->fmt, ch->blksz); 53158756Scg ch->stopping = 0; 53258756Scg if (ch->hwch == 1) 53358756Scg ess_write(sc, 0xb8, ess_read(sc, 0xb8) | 0x01); 53458756Scg else 53558756Scg ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) | 0x03); 53658756Scg if (play) 53758756Scg ess_cmd(sc, DSP_CMD_SPKON); 53874763Scg ess_unlock(sc); 53958756Scg return 0; 54058756Scg} 54158756Scg 54258756Scgstatic int 54358756Scgess_stop(struct ess_chinfo *ch) 54458756Scg{ 54558756Scg struct ess_info *sc = ch->parent; 54658756Scg int play = (ch->dir == PCMDIR_PLAY)? 1 : 0; 54758756Scg 54874763Scg ess_lock(sc); 54958756Scg ch->stopping = 1; 55058756Scg if (ch->hwch == 1) 55158756Scg ess_write(sc, 0xb8, ess_read(sc, 0xb8) & ~0x04); 55258756Scg else 55358756Scg ess_setmixer(sc, 0x78, ess_getmixer(sc, 0x78) & ~0x10); 55458756Scg if (play) 55558756Scg ess_cmd(sc, DSP_CMD_SPKOFF); 55674763Scg ess_unlock(sc); 55758756Scg return 0; 55858756Scg} 55958756Scg 56070134Scg/* -------------------------------------------------------------------- */ 56158756Scg/* channel interface for ESS18xx */ 56258756Scgstatic void * 56374763Scgesschan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 56458756Scg{ 56558756Scg struct ess_info *sc = devinfo; 56658756Scg struct ess_chinfo *ch = (dir == PCMDIR_PLAY)? &sc->pch : &sc->rch; 56758756Scg 56858756Scg ch->parent = sc; 56958756Scg ch->channel = c; 57058756Scg ch->buffer = b; 571168847Sariff if (sndbuf_alloc(ch->buffer, sc->parent_dmat, 0, sc->bufsize) != 0) 57258756Scg return NULL; 57365644Scg ch->dir = dir; 57458756Scg ch->hwch = 1; 57558756Scg if ((dir == PCMDIR_PLAY) && (sc->duplex)) 57658756Scg ch->hwch = 2; 577110499Snyan sndbuf_dmasetup(ch->buffer, (ch->hwch == 1)? sc->drq1 : sc->drq2); 57858756Scg return ch; 57958756Scg} 58058756Scg 58158756Scgstatic int 58270134Scgesschan_setformat(kobj_t obj, void *data, u_int32_t format) 58358756Scg{ 58458756Scg struct ess_chinfo *ch = data; 58558756Scg 58658756Scg ch->fmt = format; 58758756Scg return 0; 58858756Scg} 58958756Scg 590193640Sariffstatic u_int32_t 59170134Scgesschan_setspeed(kobj_t obj, void *data, u_int32_t speed) 59258756Scg{ 59358756Scg struct ess_chinfo *ch = data; 59458756Scg struct ess_info *sc = ch->parent; 59558756Scg 59658756Scg ch->spd = speed; 59758756Scg if (sc->newspeed) 59858756Scg ess_calcspeed9(&ch->spd); 59958756Scg else 60058756Scg ess_calcspeed8(&ch->spd); 60158756Scg return ch->spd; 60258756Scg} 60358756Scg 604193640Sariffstatic u_int32_t 60570134Scgesschan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 60658756Scg{ 60770291Scg struct ess_chinfo *ch = data; 60870291Scg 60970291Scg ch->blksz = blocksize; 61070291Scg return ch->blksz; 61158756Scg} 61258756Scg 61358756Scgstatic int 61470134Scgesschan_trigger(kobj_t obj, void *data, int go) 61558756Scg{ 61658756Scg struct ess_chinfo *ch = data; 61758756Scg 618170521Sariff if (!PCMTRIG_COMMON(go)) 61958756Scg return 0; 62058756Scg 62158756Scg switch (go) { 62258756Scg case PCMTRIG_START: 62370134Scg ch->run = 1; 624110499Snyan sndbuf_dma(ch->buffer, go); 62558756Scg ess_start(ch); 62658756Scg break; 62758756Scg 62858756Scg case PCMTRIG_STOP: 62958756Scg case PCMTRIG_ABORT: 63058756Scg default: 63158756Scg ess_stop(ch); 63258756Scg break; 63358756Scg } 63458756Scg return 0; 63558756Scg} 63658756Scg 637193640Sariffstatic u_int32_t 63870134Scgesschan_getptr(kobj_t obj, void *data) 63958756Scg{ 64058756Scg struct ess_chinfo *ch = data; 64158756Scg 642110499Snyan return sndbuf_dmaptr(ch->buffer); 64358756Scg} 64458756Scg 64574763Scgstatic struct pcmchan_caps * 64670134Scgesschan_getcaps(kobj_t obj, void *data) 64758756Scg{ 64858756Scg struct ess_chinfo *ch = data; 64958756Scg 65058756Scg return (ch->dir == PCMDIR_PLAY)? &ess_playcaps : &ess_reccaps; 65158756Scg} 65258756Scg 65370134Scgstatic kobj_method_t esschan_methods[] = { 65470134Scg KOBJMETHOD(channel_init, esschan_init), 65570134Scg KOBJMETHOD(channel_setformat, esschan_setformat), 65670134Scg KOBJMETHOD(channel_setspeed, esschan_setspeed), 65770134Scg KOBJMETHOD(channel_setblocksize, esschan_setblocksize), 65870134Scg KOBJMETHOD(channel_trigger, esschan_trigger), 65970134Scg KOBJMETHOD(channel_getptr, esschan_getptr), 66070134Scg KOBJMETHOD(channel_getcaps, esschan_getcaps), 661193640Sariff KOBJMETHOD_END 66270134Scg}; 66370134ScgCHANNEL_DECLARE(esschan); 66470134Scg 66558756Scg/************************************************************/ 66658756Scg 66758756Scgstatic int 66874763Scgessmix_init(struct snd_mixer *m) 66958756Scg{ 67058756Scg struct ess_info *sc = mix_getdevinfo(m); 67158756Scg 67258756Scg mix_setrecdevs(m, SOUND_MASK_CD | SOUND_MASK_MIC | SOUND_MASK_LINE | 67358756Scg SOUND_MASK_IMIX); 67458756Scg 67558756Scg mix_setdevs(m, SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | 67658756Scg SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME | 67773151Scg SOUND_MASK_LINE1 | SOUND_MASK_SPEAKER); 67858756Scg 67958756Scg ess_setmixer(sc, 0, 0); /* reset */ 68058756Scg 68158756Scg return 0; 68258756Scg} 68358756Scg 68458756Scgstatic int 68574763Scgessmix_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 68658756Scg{ 68758756Scg struct ess_info *sc = mix_getdevinfo(m); 68858756Scg int preg = 0, rreg = 0, l, r; 68958756Scg 69058756Scg l = (left * 15) / 100; 69158756Scg r = (right * 15) / 100; 69258756Scg switch (dev) { 69358756Scg case SOUND_MIXER_SYNTH: 69458756Scg preg = 0x36; 69558756Scg rreg = 0x6b; 69658756Scg break; 69758756Scg 69858756Scg case SOUND_MIXER_PCM: 69958756Scg preg = 0x14; 70058756Scg rreg = 0x7c; 70158756Scg break; 70258756Scg 70358756Scg case SOUND_MIXER_LINE: 70458756Scg preg = 0x3e; 70558756Scg rreg = 0x6e; 70658756Scg break; 70758756Scg 70858756Scg case SOUND_MIXER_MIC: 70958756Scg preg = 0x1a; 71058756Scg rreg = 0x68; 71158756Scg break; 71258756Scg 71358756Scg case SOUND_MIXER_LINE1: 71458756Scg preg = 0x3a; 71558756Scg rreg = 0x6c; 71658756Scg break; 71758756Scg 71858756Scg case SOUND_MIXER_CD: 71958756Scg preg = 0x38; 72058756Scg rreg = 0x6a; 72158756Scg break; 72258756Scg 72373151Scg case SOUND_MIXER_SPEAKER: 72473151Scg preg = 0x3c; 72573151Scg break; 72673151Scg 72773151Scg case SOUND_MIXER_VOLUME: 72858756Scg l = left? (left * 63) / 100 : 64; 72958756Scg r = right? (right * 63) / 100 : 64; 73058756Scg ess_setmixer(sc, 0x60, l); 73158756Scg ess_setmixer(sc, 0x62, r); 73258756Scg left = (l == 64)? 0 : (l * 100) / 63; 73358756Scg right = (r == 64)? 0 : (r * 100) / 63; 73458756Scg return left | (right << 8); 73558756Scg } 73658756Scg 73758756Scg if (preg) 73858756Scg ess_setmixer(sc, preg, (l << 4) | r); 73958756Scg if (rreg) 74058756Scg ess_setmixer(sc, rreg, (l << 4) | r); 74158756Scg 74258756Scg left = (l * 100) / 15; 74358756Scg right = (r * 100) / 15; 74458756Scg 74558756Scg return left | (right << 8); 74658756Scg} 74758756Scg 748193640Sariffstatic u_int32_t 74974763Scgessmix_setrecsrc(struct snd_mixer *m, u_int32_t src) 75058756Scg{ 75158756Scg struct ess_info *sc = mix_getdevinfo(m); 75258756Scg u_char recdev; 75358756Scg 75458756Scg switch (src) { 75558756Scg case SOUND_MASK_CD: 75658756Scg recdev = 0x02; 75758756Scg break; 75858756Scg 75958756Scg case SOUND_MASK_LINE: 76058756Scg recdev = 0x06; 76158756Scg break; 76258756Scg 76358756Scg case SOUND_MASK_IMIX: 76458756Scg recdev = 0x05; 76558756Scg break; 76658756Scg 76758756Scg case SOUND_MASK_MIC: 76858756Scg default: 76958756Scg recdev = 0x00; 77058756Scg src = SOUND_MASK_MIC; 77158756Scg break; 77258756Scg } 77358756Scg 77458756Scg ess_setmixer(sc, 0x1c, recdev); 77558756Scg 77658756Scg return src; 77758756Scg} 77858756Scg 77970134Scgstatic kobj_method_t essmixer_methods[] = { 78070134Scg KOBJMETHOD(mixer_init, essmix_init), 78170134Scg KOBJMETHOD(mixer_set, essmix_set), 78270134Scg KOBJMETHOD(mixer_setrecsrc, essmix_setrecsrc), 783193640Sariff KOBJMETHOD_END 78470134Scg}; 78570134ScgMIXER_DECLARE(essmixer); 78670134Scg 78770134Scg/************************************************************/ 78870134Scg 78958756Scgstatic int 79058756Scgess_probe(device_t dev) 79158756Scg{ 79258756Scg uintptr_t func, ver, r, f; 79358756Scg 79458756Scg /* The parent device has already been probed. */ 79558756Scg r = BUS_READ_IVAR(device_get_parent(dev), dev, 0, &func); 79658756Scg if (func != SCF_PCM) 79758756Scg return (ENXIO); 79858756Scg 79958756Scg r = BUS_READ_IVAR(device_get_parent(dev), dev, 1, &ver); 80058756Scg f = (ver & 0xffff0000) >> 16; 80158756Scg if (!(f & BD_F_ESS)) 80258756Scg return (ENXIO); 80358756Scg 80458756Scg device_set_desc(dev, "ESS 18xx DSP"); 80558756Scg 80658756Scg return 0; 80758756Scg} 80858756Scg 80958756Scgstatic int 81058756Scgess_attach(device_t dev) 81158756Scg{ 81258756Scg struct ess_info *sc; 81370134Scg char status[SND_STATUSLEN], buf[64]; 81470134Scg int ver; 81558756Scg 816170873Sariff sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 81774763Scg sc->parent_dev = device_get_parent(dev); 81884111Scg sc->bufsize = pcm_getbuffersize(dev, 4096, ESS_BUFFSIZE, 65536); 81970134Scg if (ess_alloc_resources(sc, dev)) 82070134Scg goto no; 82170134Scg if (ess_reset_dsp(sc)) 82270134Scg goto no; 82370134Scg if (mixer_init(dev, &essmixer_class, sc)) 82470134Scg goto no; 82570134Scg 82670134Scg sc->duplex = 0; 82770134Scg sc->newspeed = 0; 82870134Scg ver = (ess_getmixer(sc, 0x40) << 8) | ess_rd(sc, SB_MIX_DATA); 82970134Scg snprintf(buf, sizeof buf, "ESS %x DSP", ver); 83070134Scg device_set_desc_copy(dev, buf); 83170134Scg if (bootverbose) 83270134Scg device_printf(dev, "ESS%x detected", ver); 83370134Scg 83470134Scg switch (ver) { 83570134Scg case 0x1869: 83670134Scg case 0x1879: 83770134Scg#ifdef ESS18XX_DUPLEX 83870134Scg sc->duplex = sc->drq2? 1 : 0; 83970134Scg#endif 84070134Scg#ifdef ESS18XX_NEWSPEED 84170134Scg sc->newspeed = 1; 84270134Scg#endif 84370134Scg break; 84470134Scg } 84570134Scg if (bootverbose) 84670134Scg printf("%s%s\n", sc->duplex? ", duplex" : "", 84770134Scg sc->newspeed? ", newspeed" : ""); 84870134Scg 84970134Scg if (sc->newspeed) 85070134Scg ess_setmixer(sc, 0x71, 0x22); 85170134Scg 852128232Sgreen snd_setup_intr(dev, sc->irq, 0, ess_intr, sc, &sc->ih); 85370134Scg if (!sc->duplex) 85470134Scg pcm_setflags(dev, pcm_getflags(dev) | SD_F_SIMPLEX); 85570134Scg 856166904Snetchild if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(dev), /*alignment*/2, 857166904Snetchild /*boundary*/0, 85870134Scg /*lowaddr*/BUS_SPACE_MAXADDR_24BIT, 85970134Scg /*highaddr*/BUS_SPACE_MAXADDR, 86070134Scg /*filter*/NULL, /*filterarg*/NULL, 86184111Scg /*maxsize*/sc->bufsize, /*nsegments*/1, 86270134Scg /*maxsegz*/0x3ffff, 863117126Sscottl /*flags*/0, /*lockfunc*/busdma_lock_mutex, 864117126Sscottl /*lockarg*/&Giant, &sc->parent_dmat) != 0) { 86570134Scg device_printf(dev, "unable to create dma tag\n"); 86670134Scg goto no; 86770134Scg } 86870134Scg 86970134Scg if (sc->drq2) 87084111Scg snprintf(buf, SND_STATUSLEN, ":%ld", rman_get_start(sc->drq2)); 87184111Scg else 87284111Scg buf[0] = '\0'; 87370134Scg 874126695Smatk snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u %s", 87584111Scg rman_get_start(sc->io_base), rman_get_start(sc->irq), 876126695Smatk rman_get_start(sc->drq1), buf, sc->bufsize, 877126695Smatk PCM_KLDSTRING(snd_ess)); 87884111Scg 87970134Scg if (pcm_register(dev, sc, 1, 1)) 88070134Scg goto no; 88170134Scg pcm_addchan(dev, PCMDIR_REC, &esschan_class, sc); 88270134Scg pcm_addchan(dev, PCMDIR_PLAY, &esschan_class, sc); 88370134Scg pcm_setstatus(dev, status); 88470134Scg 88570134Scg return 0; 88670134Scg 88770134Scgno: 88870134Scg ess_release_resources(sc, dev); 88970134Scg return ENXIO; 89058756Scg} 89158756Scg 89270134Scgstatic int 89370134Scgess_detach(device_t dev) 89470134Scg{ 89570134Scg int r; 89670134Scg struct ess_info *sc; 89770134Scg 89870134Scg r = pcm_unregister(dev); 89970134Scg if (r) 90070134Scg return r; 90170134Scg 90270134Scg sc = pcm_getdevinfo(dev); 90370134Scg ess_release_resources(sc, dev); 90470134Scg return 0; 90570134Scg} 90670134Scg 90775326Sgreidstatic int 90875326Sgreidess_resume(device_t dev) 90975326Sgreid{ 91075326Sgreid struct ess_info *sc; 91175326Sgreid 91275326Sgreid sc = pcm_getdevinfo(dev); 91375326Sgreid 91475326Sgreid if (ess_reset_dsp(sc)) { 91575326Sgreid device_printf(dev, "unable to reset DSP at resume\n"); 91675326Sgreid return ENXIO; 91775326Sgreid } 91875326Sgreid 91975326Sgreid if (mixer_reinit(dev)) { 92075326Sgreid device_printf(dev, "unable to reinitialize mixer at resume\n"); 92175326Sgreid return ENXIO; 92275326Sgreid } 92375326Sgreid 92475326Sgreid return 0; 92575326Sgreid} 92675326Sgreid 92758756Scgstatic device_method_t ess_methods[] = { 92858756Scg /* Device interface */ 92958756Scg DEVMETHOD(device_probe, ess_probe), 93058756Scg DEVMETHOD(device_attach, ess_attach), 93165644Scg DEVMETHOD(device_detach, ess_detach), 93275326Sgreid DEVMETHOD(device_resume, ess_resume), 93358756Scg 93458756Scg { 0, 0 } 93558756Scg}; 93658756Scg 93758756Scgstatic driver_t ess_driver = { 93858756Scg "pcm", 93958756Scg ess_methods, 94082180Scg PCM_SOFTC_SIZE, 94158756Scg}; 94258756Scg 94362483ScgDRIVER_MODULE(snd_ess, sbc, ess_driver, pcm_devclass, 0, 0); 944132236StanimuraMODULE_DEPEND(snd_ess, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 94574763ScgMODULE_DEPEND(snd_ess, snd_sbc, 1, 1, 1); 94662483ScgMODULE_VERSION(snd_ess, 1); 94758756Scg 94870134Scg/************************************************************/ 94962483Scg 95058756Scgstatic devclass_t esscontrol_devclass; 95158756Scg 95258756Scgstatic struct isa_pnp_id essc_ids[] = { 95358756Scg {0x06007316, "ESS Control"}, 95458756Scg {0} 95558756Scg}; 95658756Scg 95758756Scgstatic int 95858756Scgesscontrol_probe(device_t dev) 95958756Scg{ 96071932Scg int i; 96171932Scg 96271932Scg i = ISA_PNP_PROBE(device_get_parent(dev), dev, essc_ids); 96371932Scg if (i == 0) 96471932Scg device_quiet(dev); 96571932Scg return i; 96658756Scg} 96758756Scg 96858756Scgstatic int 96958756Scgesscontrol_attach(device_t dev) 97058756Scg{ 97158756Scg#ifdef notyet 97258756Scg struct resource *io; 97358756Scg int rid, i, x; 97458756Scg 97558756Scg rid = 0; 976127135Snjl io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 97758756Scg x = 0; 97858756Scg for (i = 0; i < 0x100; i++) { 97958756Scg port_wr(io, 0, i); 98058756Scg x = port_rd(io, 1); 98158756Scg if ((i & 0x0f) == 0) 98258756Scg printf("%3.3x: ", i); 98358756Scg printf("%2.2x ", x); 98458756Scg if ((i & 0x0f) == 0x0f) 98558756Scg printf("\n"); 98658756Scg } 98758756Scg bus_release_resource(dev, SYS_RES_IOPORT, 0, io); 98858756Scg io = NULL; 98958756Scg#endif 99058756Scg 99158756Scg return 0; 99258756Scg} 99358756Scg 99465644Scgstatic int 99565644Scgesscontrol_detach(device_t dev) 99665644Scg{ 99765644Scg return 0; 99865644Scg} 99965644Scg 100058756Scgstatic device_method_t esscontrol_methods[] = { 100158756Scg /* Device interface */ 100258756Scg DEVMETHOD(device_probe, esscontrol_probe), 100358756Scg DEVMETHOD(device_attach, esscontrol_attach), 100465644Scg DEVMETHOD(device_detach, esscontrol_detach), 100558756Scg 100658756Scg { 0, 0 } 100758756Scg}; 100858756Scg 100958756Scgstatic driver_t esscontrol_driver = { 101058756Scg "esscontrol", 101158756Scg esscontrol_methods, 101282180Scg 1, 101358756Scg}; 101458756Scg 101558756ScgDRIVER_MODULE(esscontrol, isa, esscontrol_driver, esscontrol_devclass, 0, 0); 1016136410SnjlDRIVER_MODULE(esscontrol, acpi, esscontrol_driver, esscontrol_devclass, 0, 0); 1017