envy24.c revision 167608
178189Sbrian/* 278189Sbrian * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp> 378189Sbrian * All rights reserved. 478189Sbrian * 578189Sbrian * Redistribution and use in source and binary forms, with or without 66059Samurai * modification, are permitted provided that the following conditions 778189Sbrian * are met: 878189Sbrian * 1. Redistributions of source code must retain the above copyright 978189Sbrian * notice, this list of conditions and the following disclaimer. 1078189Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1178189Sbrian * notice, this list of conditions and the following disclaimer in the 1278189Sbrian * documentation and/or other materials provided with the distribution. 1378189Sbrian * 1478189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 156059Samurai * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1678189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1778189Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1878189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1978189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2078189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2178189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 2278189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2378189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 2478189Sbrian * SUCH DAMAGE. 2578189Sbrian * 2678189Sbrian */ 276059Samurai 2850479Speter#include <dev/sound/pcm/sound.h> 296059Samurai#include <dev/sound/pcm/ac97.h> 3078189Sbrian#include <dev/sound/pci/spicds.h> 3143313Sbrian#include <dev/sound/pci/envy24.h> 3231195Sbrian 3330715Sbrian#include <dev/pci/pcireg.h> 346059Samurai#include <dev/pci/pcivar.h> 356059Samurai 3681634Sbrian#include "mixer_if.h" 3781634Sbrian 3881634SbrianSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/envy24.c 167608 2007-03-15 16:41:27Z ariff $"); 3981634Sbrian 406059SamuraiMALLOC_DEFINE(M_ENVY24, "envy24", "envy24 audio"); 416059Samurai 426059Samurai/* -------------------------------------------------------------------- */ 4313389Sphk 4436285Sbrianstruct sc_info; 4530715Sbrian 4630092Sbrian#define ENVY24_PLAY_CHNUM 10 4781634Sbrian#define ENVY24_REC_CHNUM 12 4830715Sbrian#define ENVY24_PLAY_BUFUNIT (4 /* byte/sample */ * 10 /* channel */) 4981634Sbrian#define ENVY24_REC_BUFUNIT (4 /* byte/sample */ * 12 /* channel */) 5030715Sbrian#define ENVY24_SAMPLE_NUM 4096 5146686Sbrian 5230715Sbrian#define ENVY24_TIMEOUT 1000 5330715Sbrian 5446686Sbrian#define ENVY24_DEFAULT_FORMAT (AFMT_STEREO | AFMT_S16_LE) 5546686Sbrian 5630715Sbrian#define ENVY24_NAMELEN 32 5730715Sbrian 5830715Sbrianstruct envy24_sample { 5930715Sbrian volatile u_int32_t buffer; 6030715Sbrian}; 6136285Sbrian 6230715Sbriantypedef struct envy24_sample sample32_t; 6336285Sbrian 6436285Sbrian/* channel registers */ 6536285Sbrianstruct sc_chinfo { 6681634Sbrian struct snd_dbuf *buffer; 6781634Sbrian struct pcm_channel *channel; 6836285Sbrian struct sc_info *parent; 696059Samurai int dir; 7036285Sbrian unsigned num; /* hw channel number */ 7136285Sbrian 7236285Sbrian /* channel information */ 7336285Sbrian u_int32_t format; 7436285Sbrian u_int32_t speed; 7543313Sbrian u_int32_t blk; /* hw block size(dword) */ 7643313Sbrian 7743313Sbrian /* format conversion structure */ 7881634Sbrian u_int8_t *data; 7981634Sbrian unsigned int size; /* data buffer size(byte) */ 8036285Sbrian int unit; /* sample size(byte) */ 8131195Sbrian unsigned int offset; /* samples number offset */ 826059Samurai void (*emldma)(struct sc_chinfo *); 8358033Sbrian 8458033Sbrian /* flags */ 8558033Sbrian int run; 8658033Sbrian}; 8758033Sbrian 8858033Sbrian/* codec interface entrys */ 8958033Sbrianstruct codec_entry { 9058033Sbrian void *(*create)(device_t dev, void *devinfo, int dir, int num); 9158033Sbrian void (*destroy)(void *codec); 9258033Sbrian void (*init)(void *codec); 9358033Sbrian void (*reinit)(void *codec); 9458033Sbrian void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right); 9558033Sbrian void (*setrate)(void *codec, int which, int rate); 9658033Sbrian}; 9758033Sbrian 9858033Sbrian/* system configuration information */ 9958033Sbrianstruct cfg_info { 10058033Sbrian char *name; 10158033Sbrian u_int16_t subvendor, subdevice; 10255146Sbrian u_int8_t scfg, acl, i2s, spdif; 1036059Samurai u_int8_t gpiomask, gpiostate, gpiodir; 10458033Sbrian u_int8_t cdti, cclk, cs, cif, type; 10558033Sbrian u_int8_t free; 10658033Sbrian struct codec_entry *codec; 10758033Sbrian}; 10858033Sbrian 10958033Sbrian/* device private data */ 11058033Sbrianstruct sc_info { 11158033Sbrian device_t dev; 11258033Sbrian struct mtx *lock; 11358033Sbrian 11458033Sbrian /* Control/Status registor */ 11558033Sbrian struct resource *cs; 11658033Sbrian int csid; 11758033Sbrian bus_space_tag_t cst; 11858033Sbrian bus_space_handle_t csh; 11958033Sbrian /* DDMA registor */ 12058033Sbrian struct resource *ddma; 12158034Sbrian int ddmaid; 12258033Sbrian bus_space_tag_t ddmat; 12358033Sbrian bus_space_handle_t ddmah; 12458033Sbrian /* Consumer Section DMA Channel Registers */ 12558033Sbrian struct resource *ds; 12658033Sbrian int dsid; 12758033Sbrian bus_space_tag_t dst; 12858033Sbrian bus_space_handle_t dsh; 12958033Sbrian /* MultiTrack registor */ 13058033Sbrian struct resource *mt; 13158033Sbrian int mtid; 13258033Sbrian bus_space_tag_t mtt; 13358033Sbrian bus_space_handle_t mth; 13458033Sbrian /* DMA tag */ 13558033Sbrian bus_dma_tag_t dmat; 13658033Sbrian /* IRQ resource */ 13758033Sbrian struct resource *irq; 13858033Sbrian int irqid; 13958033Sbrian void *ih; 14058033Sbrian 14158033Sbrian /* system configuration data */ 14258033Sbrian struct cfg_info *cfg; 14358033Sbrian 14458033Sbrian /* ADC/DAC number and info */ 14558033Sbrian int adcn, dacn; 14658033Sbrian void *adc[4], *dac[4]; 14758033Sbrian 14858034Sbrian /* mixer control data */ 14958033Sbrian u_int32_t src; 15058033Sbrian u_int8_t left[ENVY24_CHAN_NUM]; 15149140Sbrian u_int8_t right[ENVY24_CHAN_NUM]; 15228679Sbrian 1536059Samurai /* Play/Record DMA fifo */ 1546059Samurai sample32_t *pbuf; 15549140Sbrian sample32_t *rbuf; 15662977Sbrian u_int32_t psize, rsize; /* DMA buffer size(byte) */ 1576059Samurai u_int16_t blk[2]; /* transfer check blocksize(dword) */ 15862977Sbrian bus_dmamap_t pmap, rmap; 1596059Samurai 16062977Sbrian /* current status */ 1616059Samurai u_int32_t speed; 16262977Sbrian int run[2]; 1636059Samurai u_int16_t intr[2]; 1646059Samurai struct pcmchan_caps caps[2]; 1656059Samurai 1666059Samurai /* channel info table */ 16781634Sbrian unsigned chnum; 16881634Sbrian struct sc_chinfo chan[11]; 16981634Sbrian}; 17081634Sbrian 17149140Sbrian/* -------------------------------------------------------------------- */ 17281634Sbrian 17381634Sbrian/* 17481634Sbrian * prototypes 17581634Sbrian */ 17681634Sbrian 1776059Samurai/* DMA emulator */ 17881634Sbrianstatic void envy24_p8u(struct sc_chinfo *); 17981634Sbrianstatic void envy24_p16sl(struct sc_chinfo *); 18081634Sbrianstatic void envy24_p32sl(struct sc_chinfo *); 1816059Samuraistatic void envy24_r16sl(struct sc_chinfo *); 18249140Sbrianstatic void envy24_r32sl(struct sc_chinfo *); 18381634Sbrian 18449140Sbrian/* channel interface */ 18549140Sbrianstatic void *envy24chan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int); 18649140Sbrianstatic int envy24chan_setformat(kobj_t, void *, u_int32_t); 18749140Sbrianstatic int envy24chan_setspeed(kobj_t, void *, u_int32_t); 18849140Sbrianstatic int envy24chan_setblocksize(kobj_t, void *, u_int32_t); 18949140Sbrianstatic int envy24chan_trigger(kobj_t, void *, int); 19081634Sbrianstatic int envy24chan_getptr(kobj_t, void *); 19149140Sbrianstatic struct pcmchan_caps *envy24chan_getcaps(kobj_t, void *); 19281634Sbrian 19381634Sbrian/* mixer interface */ 19481634Sbrianstatic int envy24mixer_init(struct snd_mixer *); 19581634Sbrianstatic int envy24mixer_reinit(struct snd_mixer *); 19681634Sbrianstatic int envy24mixer_uninit(struct snd_mixer *); 1976059Samuraistatic int envy24mixer_set(struct snd_mixer *, unsigned, unsigned, unsigned); 19849140Sbrianstatic u_int32_t envy24mixer_setrecsrc(struct snd_mixer *, u_int32_t); 19962977Sbrian 20036285Sbrian/* M-Audio Delta series AK4524 access interface */ 20181634Sbrianstatic void *envy24_delta_ak4524_create(device_t, void *, int, int); 20281634Sbrianstatic void envy24_delta_ak4524_destroy(void *); 20381634Sbrianstatic void envy24_delta_ak4524_init(void *); 20481634Sbrianstatic void envy24_delta_ak4524_reinit(void *); 20581634Sbrianstatic void envy24_delta_ak4524_setvolume(void *, int, unsigned int, unsigned int); 20681634Sbrian 20781738Sbrian/* -------------------------------------------------------------------- */ 20881738Sbrian 20981634Sbrian/* 21081634Sbrian system constant tables 21181634Sbrian*/ 21281634Sbrian 21381634Sbrian/* API -> hardware channel map */ 21481634Sbrianstatic unsigned envy24_chanmap[ENVY24_CHAN_NUM] = { 21581634Sbrian ENVY24_CHAN_PLAY_SPDIF, /* 0 */ 21681634Sbrian ENVY24_CHAN_PLAY_DAC1, /* 1 */ 21781634Sbrian ENVY24_CHAN_PLAY_DAC2, /* 2 */ 21881634Sbrian ENVY24_CHAN_PLAY_DAC3, /* 3 */ 21981634Sbrian ENVY24_CHAN_PLAY_DAC4, /* 4 */ 22081634Sbrian ENVY24_CHAN_REC_MIX, /* 5 */ 22181634Sbrian ENVY24_CHAN_REC_SPDIF, /* 6 */ 22281634Sbrian ENVY24_CHAN_REC_ADC1, /* 7 */ 22381634Sbrian ENVY24_CHAN_REC_ADC2, /* 8 */ 22481634Sbrian ENVY24_CHAN_REC_ADC3, /* 9 */ 22581634Sbrian ENVY24_CHAN_REC_ADC4, /* 10 */ 22681634Sbrian}; 22781634Sbrian 22881634Sbrian/* mixer -> API channel map. see above */ 22981634Sbrianstatic int envy24_mixmap[] = { 23081634Sbrian -1, /* Master output level. It is depend on codec support */ 23181634Sbrian -1, /* Treble level of all output channels */ 23281634Sbrian -1, /* Bass level of all output channels */ 23381634Sbrian -1, /* Volume of synthesier input */ 23481634Sbrian 0, /* Output level for the audio device */ 23565181Sbrian -1, /* Output level for the PC speaker */ 23681634Sbrian 7, /* line in jack */ 23781634Sbrian -1, /* microphone jack */ 23881634Sbrian -1, /* CD audio input */ 23981634Sbrian -1, /* Recording monitor */ 24081634Sbrian 1, /* alternative codec */ 24181634Sbrian -1, /* global recording level */ 24249140Sbrian -1, /* Input gain */ 24381634Sbrian -1, /* Output gain */ 24481634Sbrian 8, /* Input source 1 */ 24581634Sbrian 9, /* Input source 2 */ 24681634Sbrian 10, /* Input source 3 */ 24781634Sbrian 6, /* Digital (input) 1 */ 24881634Sbrian -1, /* Digital (input) 2 */ 24949140Sbrian -1, /* Digital (input) 3 */ 25081634Sbrian -1, /* Phone input */ 25149140Sbrian -1, /* Phone output */ 25249140Sbrian -1, /* Video/TV (audio) in */ 25349140Sbrian -1, /* Radio in */ 25449140Sbrian -1, /* Monitor volume */ 25549140Sbrian}; 25649140Sbrian 25736285Sbrian/* variable rate audio */ 25849140Sbrianstatic u_int32_t envy24_speed[] = { 25949140Sbrian 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 26049140Sbrian 12000, 11025, 9600, 8000, 0 26149140Sbrian}; 2626059Samurai 26349140Sbrian/* known boards configuration */ 26481634Sbrianstatic struct codec_entry delta_codec = { 26581634Sbrian envy24_delta_ak4524_create, 26681634Sbrian envy24_delta_ak4524_destroy, 26781634Sbrian envy24_delta_ak4524_init, 26881634Sbrian envy24_delta_ak4524_reinit, 26981634Sbrian envy24_delta_ak4524_setvolume, 27062977Sbrian NULL, /* setrate */ 27162977Sbrian}; 27262977Sbrian 27362977Sbrianstatic struct cfg_info cfg_table[] = { 27481634Sbrian { 27581634Sbrian "Envy24 audio (M Audio Delta Dio 2496)", 27681634Sbrian 0x1412, 0xd631, 27781634Sbrian 0x10, 0x80, 0xf0, 0x03, 27881634Sbrian 0xff, 0x00, 0x00, 27981634Sbrian 0x10, 0x20, 0x40, 0x00, 0x00, 28049140Sbrian 0x00, 28181634Sbrian &delta_codec, 28262977Sbrian }, 28381634Sbrian { 28481634Sbrian "Envy24 audio (Terratec DMX 6fire)", 28581634Sbrian 0x153b, 0x1138, 28681634Sbrian 0x2f, 0x80, 0xf0, 0x03, 28781634Sbrian 0xc0, 0xff, 0x7f, 28881634Sbrian 0x10, 0x20, 0x01, 0x01, 0x00, 28965181Sbrian 0x00, 29081634Sbrian &delta_codec, 29181634Sbrian }, 29281634Sbrian { 29381634Sbrian "Envy24 audio (M Audio Audiophile 2496)", 29481634Sbrian 0x1412, 0xd634, 29562977Sbrian 0x10, 0x80, 0x72, 0x03, 29662977Sbrian 0x04, 0xfe, 0xfb, 29762977Sbrian 0x08, 0x02, 0x20, 0x00, 0x01, 29881634Sbrian 0x00, 29981634Sbrian &delta_codec, 30062977Sbrian }, 30181634Sbrian { 30262977Sbrian "Envy24 audio (Generic)", 30381634Sbrian 0, 0, 30451809Sbrian 0x0f, 0x00, 0x01, 0x03, 30551809Sbrian 0xff, 0x00, 0x00, 30681634Sbrian 0x10, 0x20, 0x40, 0x00, 0x00, 30751809Sbrian 0x00, 30851809Sbrian &delta_codec, /* default codec routines */ 30949374Sbrian } 31062977Sbrian}; 31181634Sbrian 31262977Sbrianstatic u_int32_t envy24_recfmt[] = { 31349374Sbrian AFMT_STEREO | AFMT_S16_LE, 31481634Sbrian AFMT_STEREO | AFMT_S32_LE, 31581634Sbrian 0 31681634Sbrian}; 31765846Sbrianstatic struct pcmchan_caps envy24_reccaps = {8000, 96000, envy24_recfmt, 0}; 31881634Sbrian 31981634Sbrianstatic u_int32_t envy24_playfmt[] = { 32062977Sbrian AFMT_STEREO | AFMT_U8, 32181634Sbrian AFMT_STEREO | AFMT_S16_LE, 32281634Sbrian AFMT_STEREO | AFMT_S32_LE, 32362977Sbrian 0 32462977Sbrian}; 32562977Sbrian 32662977Sbrianstatic struct pcmchan_caps envy24_playcaps = {8000, 96000, envy24_playfmt, 0}; 32762977Sbrian 32862977Sbrianstruct envy24_emldma { 32981634Sbrian u_int32_t format; 33062977Sbrian void (*emldma)(struct sc_chinfo *); 33181634Sbrian int unit; 33281634Sbrian}; 33381634Sbrian 33462977Sbrianstatic struct envy24_emldma envy24_pemltab[] = { 33562977Sbrian {AFMT_STEREO | AFMT_U8, envy24_p8u, 2}, 33662977Sbrian {AFMT_STEREO | AFMT_S16_LE, envy24_p16sl, 4}, 33765181Sbrian {AFMT_STEREO | AFMT_S32_LE, envy24_p32sl, 8}, 33865181Sbrian {0, NULL, 0} 33962977Sbrian}; 34065181Sbrian 34162977Sbrianstatic struct envy24_emldma envy24_remltab[] = { 34262977Sbrian {AFMT_STEREO | AFMT_S16_LE, envy24_r16sl, 4}, 34362977Sbrian {AFMT_STEREO | AFMT_S32_LE, envy24_r32sl, 8}, 34462977Sbrian {0, NULL, 0} 34562977Sbrian}; 34662977Sbrian 34762977Sbrian/* -------------------------------------------------------------------- */ 34862977Sbrian 34962977Sbrian/* common routines */ 35062977Sbrianstatic u_int32_t 35162977Sbrianenvy24_rdcs(struct sc_info *sc, int regno, int size) 35262977Sbrian{ 35362977Sbrian switch (size) { 35462977Sbrian case 1: 35562977Sbrian return bus_space_read_1(sc->cst, sc->csh, regno); 35681634Sbrian case 2: 35762977Sbrian return bus_space_read_2(sc->cst, sc->csh, regno); 35826516Sbrian case 4: 35981634Sbrian return bus_space_read_4(sc->cst, sc->csh, regno); 36081634Sbrian default: 36181634Sbrian return 0xffffffff; 36281634Sbrian } 36381634Sbrian} 36481634Sbrian 36562977Sbrianstatic void 36662977Sbrianenvy24_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size) 36762977Sbrian{ 36862977Sbrian switch (size) { 36962977Sbrian case 1: 37062977Sbrian bus_space_write_1(sc->cst, sc->csh, regno, data); 37162977Sbrian break; 37281634Sbrian case 2: 37362977Sbrian bus_space_write_2(sc->cst, sc->csh, regno, data); 37462977Sbrian break; 37562977Sbrian case 4: 37681634Sbrian bus_space_write_4(sc->cst, sc->csh, regno, data); 37762977Sbrian break; 37862977Sbrian } 37962977Sbrian} 38062977Sbrian 38162977Sbrianstatic u_int32_t 38262977Sbrianenvy24_rdmt(struct sc_info *sc, int regno, int size) 38362977Sbrian{ 38462977Sbrian switch (size) { 38562977Sbrian case 1: 38662977Sbrian return bus_space_read_1(sc->mtt, sc->mth, regno); 38762977Sbrian case 2: 38862977Sbrian return bus_space_read_2(sc->mtt, sc->mth, regno); 38962977Sbrian case 4: 39049140Sbrian return bus_space_read_4(sc->mtt, sc->mth, regno); 39162977Sbrian default: 39281634Sbrian return 0xffffffff; 39381634Sbrian } 39462977Sbrian} 39549140Sbrian 39662977Sbrianstatic void 39762977Sbrianenvy24_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size) 39862977Sbrian{ 39962977Sbrian switch (size) { 40062977Sbrian case 1: 40162977Sbrian bus_space_write_1(sc->mtt, sc->mth, regno, data); 40262977Sbrian break; 40362977Sbrian case 2: 40462977Sbrian bus_space_write_2(sc->mtt, sc->mth, regno, data); 40562977Sbrian break; 40662977Sbrian case 4: 40749140Sbrian bus_space_write_4(sc->mtt, sc->mth, regno, data); 40862977Sbrian break; 40962977Sbrian } 41062977Sbrian} 41162977Sbrian 4126059Samuraistatic u_int32_t 41349140Sbrianenvy24_rdci(struct sc_info *sc, int regno) 41449140Sbrian{ 41549140Sbrian envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1); 41649140Sbrian return envy24_rdcs(sc, ENVY24_CCS_DATA, 1); 41749140Sbrian} 41849140Sbrian 41962977Sbrianstatic void 42065181Sbrianenvy24_wrci(struct sc_info *sc, int regno, u_int32_t data) 42162977Sbrian{ 42262977Sbrian envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1); 42362977Sbrian envy24_wrcs(sc, ENVY24_CCS_DATA, data, 1); 42465181Sbrian} 42565181Sbrian 42665181Sbrian/* -------------------------------------------------------------------- */ 42781634Sbrian 42865181Sbrian/* I2C port/E2PROM access routines */ 42981634Sbrian 43081634Sbrianstatic int 43165181Sbrianenvy24_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr) 43265181Sbrian{ 43362977Sbrian u_int32_t data; 43465181Sbrian int i; 43565181Sbrian 43681634Sbrian#if(0) 43765181Sbrian device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr); 43865181Sbrian#endif 43981634Sbrian for (i = 0; i < ENVY24_TIMEOUT; i++) { 44081634Sbrian data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 44165181Sbrian if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0) 44265181Sbrian break; 44381634Sbrian DELAY(32); /* 31.25kHz */ 44465181Sbrian } 44549140Sbrian if (i == ENVY24_TIMEOUT) { 44649140Sbrian return -1; 4476059Samurai } 4486059Samurai envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1); 4496059Samurai envy24_wrcs(sc, ENVY24_CCS_I2CDEV, 45065181Sbrian (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_RD, 1); 45165181Sbrian for (i = 0; i < ENVY24_TIMEOUT; i++) { 45281634Sbrian data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 45365181Sbrian if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0) 45465181Sbrian break; 45581634Sbrian DELAY(32); /* 31.25kHz */ 45681634Sbrian } 45765181Sbrian if (i == ENVY24_TIMEOUT) { 45865181Sbrian return -1; 45981634Sbrian } 4606059Samurai data = envy24_rdcs(sc, ENVY24_CCS_I2CDATA, 1); 4616059Samurai 4626059Samurai#if(0) 46358033Sbrian device_printf(sc->dev, "envy24_rdi2c(): return 0x%x\n", data); 46458033Sbrian#endif 46558033Sbrian return (int)data; 46658033Sbrian} 46758033Sbrian 46877487Sbrian#if 0 46958033Sbrianstatic int 47058033Sbrianenvy24_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data) 47158033Sbrian{ 47258033Sbrian u_int32_t tmp; 47358033Sbrian int i; 47458033Sbrian 47558033Sbrian#if(0) 47658033Sbrian device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr); 47758033Sbrian#endif 47858033Sbrian for (i = 0; i < ENVY24_TIMEOUT; i++) { 47958033Sbrian tmp = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 48058033Sbrian if ((tmp & ENVY24_CCS_I2CSTAT_BSY) == 0) 48158033Sbrian break; 48262977Sbrian DELAY(32); /* 31.25kHz */ 48358033Sbrian } 48458033Sbrian if (i == ENVY24_TIMEOUT) { 48558033Sbrian return -1; 48658033Sbrian } 48758033Sbrian envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1); 48874049Sbrian envy24_wrcs(sc, ENVY24_CCS_I2CDATA, data, 1); 48958033Sbrian envy24_wrcs(sc, ENVY24_CCS_I2CDEV, 49058033Sbrian (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_WR, 1); 49158033Sbrian for (i = 0; i < ENVY24_TIMEOUT; i++) { 49274049Sbrian data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 49358033Sbrian if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0) 49474049Sbrian break; 49574049Sbrian DELAY(32); /* 31.25kHz */ 49658033Sbrian } 49758033Sbrian if (i == ENVY24_TIMEOUT) { 49858033Sbrian return -1; 49958033Sbrian } 50074049Sbrian 50158033Sbrian return 0; 50258033Sbrian} 50358033Sbrian#endif 50458033Sbrian 50558033Sbrianstatic int 50658033Sbrianenvy24_rdrom(struct sc_info *sc, u_int32_t addr) 50758033Sbrian{ 50877487Sbrian u_int32_t data; 50977487Sbrian 51077487Sbrian#if(0) 51177487Sbrian device_printf(sc->dev, "envy24_rdrom(sc, 0x%02x)\n", addr); 51277487Sbrian#endif 51377487Sbrian data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 51477487Sbrian if ((data & ENVY24_CCS_I2CSTAT_ROM) == 0) { 51577487Sbrian#if(0) 51677487Sbrian device_printf(sc->dev, "envy24_rdrom(): E2PROM not presented\n"); 51758033Sbrian#endif 51858033Sbrian return -1; 51958033Sbrian } 5206059Samurai 52181634Sbrian return envy24_rdi2c(sc, ENVY24_CCS_I2CDEV_ROM, addr); 52281634Sbrian} 5236059Samurai 5246059Samuraistatic struct cfg_info * 52581634Sbrianenvy24_rom2cfg(struct sc_info *sc) 52681634Sbrian{ 52781634Sbrian struct cfg_info *buff; 5286059Samurai int size; 52958033Sbrian int i; 53058033Sbrian 53158033Sbrian#if(0) 53281634Sbrian device_printf(sc->dev, "envy24_rom2cfg(sc)\n"); 53381634Sbrian#endif 53481634Sbrian size = envy24_rdrom(sc, ENVY24_E2PROM_SIZE); 53581634Sbrian if (size < ENVY24_E2PROM_GPIODIR + 1) { 53681634Sbrian#if(0) 53781634Sbrian device_printf(sc->dev, "envy24_rom2cfg(): ENVY24_E2PROM_SIZE-->%d\n", size); 53881634Sbrian#endif 53981634Sbrian return NULL; 54081634Sbrian } 54137010Sbrian buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT); 54281634Sbrian if (buff == NULL) { 54381634Sbrian#if(0) 5446059Samurai device_printf(sc->dev, "envy24_rom2cfg(): malloc()\n"); 54558776Sbrian#endif 54658776Sbrian return NULL; 54726692Sbrian } 54858033Sbrian buff->free = 1; 5496059Samurai 55081634Sbrian buff->subvendor = envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR) << 8; 55181634Sbrian buff->subvendor += envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR + 1); 55281634Sbrian buff->subdevice = envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE) << 8; 55381634Sbrian buff->subdevice += envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE + 1); 55481634Sbrian buff->scfg = envy24_rdrom(sc, ENVY24_E2PROM_SCFG); 55581634Sbrian buff->acl = envy24_rdrom(sc, ENVY24_E2PROM_ACL); 55681634Sbrian buff->i2s = envy24_rdrom(sc, ENVY24_E2PROM_I2S); 55781634Sbrian buff->spdif = envy24_rdrom(sc, ENVY24_E2PROM_SPDIF); 55881634Sbrian buff->gpiomask = envy24_rdrom(sc, ENVY24_E2PROM_GPIOMASK); 55981738Sbrian buff->gpiostate = envy24_rdrom(sc, ENVY24_E2PROM_GPIOSTATE); 56081634Sbrian buff->gpiodir = envy24_rdrom(sc, ENVY24_E2PROM_GPIODIR); 56181634Sbrian 56281634Sbrian for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) 56381634Sbrian if (cfg_table[i].subvendor == buff->subvendor && 56481634Sbrian cfg_table[i].subdevice == buff->subdevice) 56581634Sbrian break; 56681634Sbrian buff->name = cfg_table[i].name; 56781634Sbrian buff->codec = cfg_table[i].codec; 56881634Sbrian 56981634Sbrian return buff; 57081634Sbrian} 57181634Sbrian 57281634Sbrianstatic void 57381634Sbrianenvy24_cfgfree(struct cfg_info *cfg) { 57481634Sbrian if (cfg == NULL) 57558033Sbrian return; 5768857Srgrimes if (cfg->free) 57726692Sbrian free(cfg, M_ENVY24); 57862778Sbrian return; 57962778Sbrian} 58062778Sbrian 58158776Sbrian/* -------------------------------------------------------------------- */ 58258776Sbrian 58358776Sbrian/* AC'97 codec access routines */ 58428679Sbrian 58526692Sbrian#if 0 5866059Samuraistatic int 58781634Sbrianenvy24_coldcd(struct sc_info *sc) 5886059Samurai{ 58926692Sbrian u_int32_t data; 59081634Sbrian int i; 59181634Sbrian 59228679Sbrian#if(0) 59381634Sbrian device_printf(sc->dev, "envy24_coldcd()\n"); 59428679Sbrian#endif 59528679Sbrian envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_CLD, 1); 59681634Sbrian DELAY(10); 59728679Sbrian envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1); 5986059Samurai DELAY(1000); 5996059Samurai for (i = 0; i < ENVY24_TIMEOUT; i++) { 60051048Sbrian data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1); 60181634Sbrian if (data & ENVY24_MT_AC97CMD_RDY) { 60281634Sbrian return 0; 60381634Sbrian } 60481634Sbrian } 60581634Sbrian 60681634Sbrian return -1; 60781634Sbrian} 60881634Sbrian#endif 60981634Sbrian 61081634Sbrianstatic int 61181634Sbrianenvy24_slavecd(struct sc_info *sc) 61281634Sbrian{ 61381634Sbrian u_int32_t data; 61481634Sbrian int i; 61581634Sbrian 6166059Samurai#if(0) 61781634Sbrian device_printf(sc->dev, "envy24_slavecd()\n"); 61881634Sbrian#endif 61951048Sbrian envy24_wrmt(sc, ENVY24_MT_AC97CMD, 62051048Sbrian ENVY24_MT_AC97CMD_CLD | ENVY24_MT_AC97CMD_WRM, 1); 62181634Sbrian DELAY(10); 62281634Sbrian envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1); 62351048Sbrian DELAY(1000); 62451048Sbrian for (i = 0; i < ENVY24_TIMEOUT; i++) { 62526692Sbrian data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1); 62681634Sbrian if (data & ENVY24_MT_AC97CMD_RDY) { 62728679Sbrian return 0; 62881634Sbrian } 62928679Sbrian } 63028679Sbrian 63181634Sbrian return -1; 63262977Sbrian} 63328679Sbrian 6346059Samurai#if 0 63562778Sbrianstatic int 63662778Sbrianenvy24_rdcd(kobj_t obj, void *devinfo, int regno) 63781634Sbrian{ 63881634Sbrian struct sc_info *sc = (struct sc_info *)devinfo; 63962778Sbrian u_int32_t data; 64062778Sbrian int i; 64162778Sbrian 64281634Sbrian#if(0) 64362778Sbrian device_printf(sc->dev, "envy24_rdcd(obj, sc, 0x%02x)\n", regno); 64462778Sbrian#endif 64562778Sbrian envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1); 64662778Sbrian envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_RD, 1); 64762778Sbrian for (i = 0; i < ENVY24_TIMEOUT; i++) { 64881634Sbrian data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1); 64981634Sbrian if ((data & ENVY24_MT_AC97CMD_RD) == 0) 65062977Sbrian break; 65162778Sbrian } 65262778Sbrian data = envy24_rdmt(sc, ENVY24_MT_AC97DLO, 2); 65362778Sbrian 65462778Sbrian#if(0) 65562778Sbrian device_printf(sc->dev, "envy24_rdcd(): return 0x%x\n", data); 65662778Sbrian#endif 65762778Sbrian return (int)data; 65862778Sbrian} 65962778Sbrian 66062778Sbrianstatic int 66162778Sbrianenvy24_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data) 66262778Sbrian{ 66362778Sbrian struct sc_info *sc = (struct sc_info *)devinfo; 66462778Sbrian u_int32_t cmd; 66562778Sbrian int i; 66662778Sbrian 66762778Sbrian#if(0) 66862778Sbrian device_printf(sc->dev, "envy24_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data); 66962778Sbrian#endif 67062778Sbrian envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1); 67162778Sbrian envy24_wrmt(sc, ENVY24_MT_AC97DLO, (u_int32_t)data, 2); 67262778Sbrian envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_WR, 1); 67362778Sbrian for (i = 0; i < ENVY24_TIMEOUT; i++) { 67462778Sbrian cmd = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1); 6756059Samurai if ((cmd & ENVY24_MT_AC97CMD_WR) == 0) 67651048Sbrian break; 67751809Sbrian } 67851809Sbrian 67951809Sbrian return 0; 68051809Sbrian} 68181634Sbrian 68251809Sbrianstatic kobj_method_t envy24_ac97_methods[] = { 68351809Sbrian KOBJMETHOD(ac97_read, envy24_rdcd), 68481634Sbrian KOBJMETHOD(ac97_write, envy24_wrcd), 68551809Sbrian {0, 0} 68651809Sbrian}; 68751809SbrianAC97_DECLARE(envy24_ac97); 68851809Sbrian#endif 68951809Sbrian 69049374Sbrian/* -------------------------------------------------------------------- */ 69149372Sbrian 69249372Sbrian/* GPIO access routines */ 69349372Sbrian 69481634Sbrianstatic u_int32_t 69549372Sbrianenvy24_gpiord(struct sc_info *sc) 69649372Sbrian{ 69781634Sbrian return envy24_rdci(sc, ENVY24_CCI_GPIODAT); 69849372Sbrian} 69949372Sbrian 70049372Sbrianstatic void 70149374Sbrianenvy24_gpiowr(struct sc_info *sc, u_int32_t data) 70251048Sbrian{ 70381634Sbrian#if(0) 70481634Sbrian device_printf(sc->dev, "envy24_gpiowr(sc, 0x%02x)\n", data & 0xff); 70581634Sbrian return; 70681634Sbrian#endif 70781634Sbrian envy24_wrci(sc, ENVY24_CCI_GPIODAT, data); 70881634Sbrian return; 70981634Sbrian} 71081634Sbrian 71181634Sbrian#if 0 71281634Sbrianstatic u_int32_t 71381634Sbrianenvy24_gpiogetmask(struct sc_info *sc) 71481634Sbrian{ 71581634Sbrian return envy24_rdci(sc, ENVY24_CCI_GPIOMASK); 71681634Sbrian} 71781634Sbrian#endif 71881634Sbrian 71981634Sbrianstatic void 72081634Sbrianenvy24_gpiosetmask(struct sc_info *sc, u_int32_t mask) 72181634Sbrian{ 72281634Sbrian envy24_wrci(sc, ENVY24_CCI_GPIOMASK, mask); 72381634Sbrian return; 72436961Sbrian} 72536961Sbrian 72636961Sbrian#if 0 72781634Sbrianstatic u_int32_t 72836961Sbrianenvy24_gpiogetdir(struct sc_info *sc) 72936961Sbrian{ 73081634Sbrian return envy24_rdci(sc, ENVY24_CCI_GPIOCTL); 73136961Sbrian} 73281634Sbrian#endif 73375894Sbrian 73481634Sbrianstatic void 73581634Sbrianenvy24_gpiosetdir(struct sc_info *sc, u_int32_t dir) 73681634Sbrian{ 73781634Sbrian envy24_wrci(sc, ENVY24_CCI_GPIOCTL, dir); 73881634Sbrian return; 73981634Sbrian} 74081634Sbrian 74136961Sbrian/* -------------------------------------------------------------------- */ 74236961Sbrian 74351048Sbrian/* M-Audio Delta series AK4524 access interface routine */ 74465846Sbrian 74565846Sbrianstruct envy24_delta_ak4524_codec { 74665846Sbrian struct spicds_info *info; 74781634Sbrian struct sc_info *parent; 74865846Sbrian int dir; 74971781Sbrian int num; 75081634Sbrian int cs, cclk, cdti; 75165846Sbrian}; 75265846Sbrian 75365846Sbrianstatic void 75465846Sbrianenvy24_delta_ak4524_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti) 75565846Sbrian{ 75665846Sbrian u_int32_t data = 0; 75765846Sbrian struct envy24_delta_ak4524_codec *ptr = codec; 75881634Sbrian 75965846Sbrian#if(0) 76071781Sbrian device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti); 76181634Sbrian#endif 76265846Sbrian data = envy24_gpiord(ptr->parent); 76365846Sbrian data &= ~(ptr->cs | ptr->cclk | ptr->cdti); 76465846Sbrian if (cs) data += ptr->cs; 76565846Sbrian if (cclk) data += ptr->cclk; 76636961Sbrian if (cdti) data += ptr->cdti; 76736961Sbrian envy24_gpiowr(ptr->parent, data); 76881634Sbrian return; 76936961Sbrian} 77081634Sbrian 77162977Sbrianstatic void * 77236961Sbrianenvy24_delta_ak4524_create(device_t dev, void *info, int dir, int num) 77336961Sbrian{ 77481634Sbrian struct sc_info *sc = info; 77536961Sbrian struct envy24_delta_ak4524_codec *buff = NULL; 77636961Sbrian 77736961Sbrian#if(0) 77851048Sbrian device_printf(sc->dev, "envy24_delta_ak4524_create(dev, sc, %d, %d)\n", dir, num); 7796059Samurai#endif 78081634Sbrian 78181634Sbrian buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT); 78250867Sbrian if (buff == NULL) 78351048Sbrian return NULL; 78481634Sbrian 78581634Sbrian if (dir == PCMDIR_REC && sc->adc[num] != NULL) 78650867Sbrian buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info; 78750867Sbrian else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL) 78826692Sbrian buff->info = ((struct envy24_delta_ak4524_codec *)sc->dac[num])->info; 78981634Sbrian else 79028679Sbrian buff->info = spicds_create(dev, buff, num, envy24_delta_ak4524_ctl); 79181634Sbrian if (buff->info == NULL) { 79228679Sbrian free(buff, M_ENVY24); 79328679Sbrian return NULL; 79481634Sbrian } 79528679Sbrian 7966059Samurai buff->parent = sc; 7976059Samurai buff->dir = dir; 79862977Sbrian buff->num = num; 79962977Sbrian 80062977Sbrian return (void *)buff; 80162977Sbrian} 80262977Sbrian 8036059Samuraistatic void 80428679Sbrianenvy24_delta_ak4524_destroy(void *codec) 80562977Sbrian{ 80662977Sbrian struct envy24_delta_ak4524_codec *ptr = codec; 80728679Sbrian if (ptr == NULL) 8086059Samurai return; 80981634Sbrian#if(0) 8106059Samurai device_printf(ptr->parent->dev, "envy24_delta_ak4524_destroy()\n"); 81181634Sbrian#endif 81262977Sbrian 81362977Sbrian if (ptr->dir == PCMDIR_PLAY) { 81462977Sbrian if (ptr->parent->dac[ptr->num] != NULL) 81562977Sbrian spicds_destroy(ptr->info); 81662977Sbrian } 8176059Samurai else { 8186059Samurai if (ptr->parent->adc[ptr->num] != NULL) 8196059Samurai spicds_destroy(ptr->info); 82062778Sbrian } 82162778Sbrian 82262778Sbrian free(codec, M_ENVY24); 82362778Sbrian} 82481634Sbrian 82581634Sbrianstatic void 82681634Sbrianenvy24_delta_ak4524_init(void *codec) 82781634Sbrian{ 82881634Sbrian#if 0 82981634Sbrian u_int32_t gpiomask, gpiodir; 83081634Sbrian#endif 83181634Sbrian struct envy24_delta_ak4524_codec *ptr = codec; 83281634Sbrian if (ptr == NULL) 83381634Sbrian return; 8346059Samurai#if(0) 83526692Sbrian device_printf(ptr->parent->dev, "envy24_delta_ak4524_init()\n"); 83681634Sbrian#endif 83731142Sbrian 83836285Sbrian /* 83958033Sbrian gpiomask = envy24_gpiogetmask(ptr->parent); 8406059Samurai gpiomask &= ~(ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1); 84136285Sbrian envy24_gpiosetmask(ptr->parent, gpiomask); 84258033Sbrian gpiodir = envy24_gpiogetdir(ptr->parent); 84362977Sbrian gpiodir |= ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1; 84462977Sbrian envy24_gpiosetdir(ptr->parent, gpiodir); 84562977Sbrian */ 84681634Sbrian ptr->cs = ptr->parent->cfg->cs; 84781634Sbrian#if 0 84836285Sbrian envy24_gpiosetmask(ptr->parent, ENVY24_GPIO_CS8414_STATUS); 84962977Sbrian envy24_gpiosetdir(ptr->parent, ~ENVY24_GPIO_CS8414_STATUS); 85062977Sbrian if (ptr->num == 0) 85162977Sbrian ptr->cs = ENVY24_GPIO_AK4524_CS0; 85262977Sbrian else 85362977Sbrian ptr->cs = ENVY24_GPIO_AK4524_CS1; 85462977Sbrian ptr->cclk = ENVY24_GPIO_AK4524_CCLK; 85562977Sbrian#endif 85662977Sbrian ptr->cclk = ptr->parent->cfg->cclk; 85762977Sbrian ptr->cdti = ptr->parent->cfg->cdti; 85862977Sbrian spicds_settype(ptr->info, ptr->parent->cfg->type); 85962977Sbrian spicds_setcif(ptr->info, ptr->parent->cfg->cif); 86062977Sbrian spicds_setformat(ptr->info, 8616735Samurai AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X); 86258033Sbrian spicds_setdvc(ptr->info, 0); 8636059Samurai /* for the time being, init only first codec */ 86458033Sbrian if (ptr->num == 0) 86558776Sbrian spicds_init(ptr->info); 86658033Sbrian} 86758033Sbrian 86858033Sbrianstatic void 8696059Samuraienvy24_delta_ak4524_reinit(void *codec) 8706059Samurai{ 87181634Sbrian struct envy24_delta_ak4524_codec *ptr = codec; 87281634Sbrian if (ptr == NULL) 87336285Sbrian return; 8746059Samurai#if(0) 87531343Sbrian device_printf(ptr->parent->dev, "envy24_delta_ak4524_reinit()\n"); 87656413Sbrian#endif 87762977Sbrian 8786059Samurai spicds_reinit(ptr->info); 87954912Sbrian} 88047168Sbrian 88147168Sbrianstatic void 88247168Sbrianenvy24_delta_ak4524_setvolume(void *codec, int dir, unsigned int left, unsigned int right) 88354912Sbrian{ 88481634Sbrian struct envy24_delta_ak4524_codec *ptr = codec; 88547168Sbrian if (ptr == NULL) 88646686Sbrian return; 88726031Sbrian#if(0) 88862977Sbrian device_printf(ptr->parent->dev, "envy24_delta_ak4524_set()\n"); 88981634Sbrian#endif 89081634Sbrian 89181634Sbrian spicds_set(ptr->info, dir, left, right); 89226031Sbrian} 89362977Sbrian 89481634Sbrian/* 89562977Sbrian There is no need for AK452[48] codec to set sample rate 89662977Sbrian static void 89762977Sbrian envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate) 89862977Sbrian { 89926031Sbrian } 90056413Sbrian*/ 90181634Sbrian 90256413Sbrian/* -------------------------------------------------------------------- */ 90356413Sbrian 90456413Sbrian/* hardware access routeines */ 90556413Sbrian 90656413Sbrianstatic struct { 90756413Sbrian u_int32_t speed; 90846686Sbrian u_int32_t code; 90946686Sbrian} envy24_speedtab[] = { 91047168Sbrian {48000, ENVY24_MT_RATE_48000}, 91147168Sbrian {24000, ENVY24_MT_RATE_24000}, 91246686Sbrian {12000, ENVY24_MT_RATE_12000}, 91347168Sbrian {9600, ENVY24_MT_RATE_9600}, 91446686Sbrian {32000, ENVY24_MT_RATE_32000}, 91536285Sbrian {16000, ENVY24_MT_RATE_16000}, 91681634Sbrian {8000, ENVY24_MT_RATE_8000}, 9176059Samurai {96000, ENVY24_MT_RATE_96000}, 9186059Samurai {64000, ENVY24_MT_RATE_64000}, 91981634Sbrian {44100, ENVY24_MT_RATE_44100}, 92081634Sbrian {22050, ENVY24_MT_RATE_22050}, 9216059Samurai {11025, ENVY24_MT_RATE_11025}, 92281634Sbrian {88200, ENVY24_MT_RATE_88200}, 9236059Samurai {0, 0x10} 92481634Sbrian}; 92581634Sbrian 92681634Sbrianstatic int 92781634Sbrianenvy24_setspeed(struct sc_info *sc, u_int32_t speed) { 92838557Sbrian u_int32_t code; 9296059Samurai int i = 0; 93081634Sbrian 93138544Sbrian#if(0) 93281634Sbrian device_printf(sc->dev, "envy24_setspeed(sc, %d)\n", speed); 93381634Sbrian#endif 93438544Sbrian if (speed == 0) { 93581634Sbrian code = ENVY24_MT_RATE_SPDIF; /* external master clock */ 9367001Samurai envy24_slavecd(sc); 9377001Samurai } 93881634Sbrian else { 93981634Sbrian for (i = 0; envy24_speedtab[i].speed != 0; i++) { 94081634Sbrian if (envy24_speedtab[i].speed == speed) 9416059Samurai break; 94281634Sbrian } 9436059Samurai code = envy24_speedtab[i].code; 94481634Sbrian } 94581634Sbrian#if(0) 94681634Sbrian device_printf(sc->dev, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab[i].speed, code); 94781634Sbrian#endif 94878411Sbrian if (code < 0x10) { 94978411Sbrian envy24_wrmt(sc, ENVY24_MT_RATE, code, 1); 95081634Sbrian code = envy24_rdmt(sc, ENVY24_MT_RATE, 1); 95136285Sbrian code &= ENVY24_MT_RATE_MASK; 95281634Sbrian for (i = 0; envy24_speedtab[i].code < 0x10; i++) { 95381634Sbrian if (envy24_speedtab[i].code == code) 95481634Sbrian break; 95581634Sbrian } 9566059Samurai speed = envy24_speedtab[i].speed; 95781634Sbrian } 958 else 959 speed = 0; 960 961#if(0) 962 device_printf(sc->dev, "envy24_setspeed(): return %d\n", speed); 963#endif 964 return speed; 965} 966 967static void 968envy24_setvolume(struct sc_info *sc, unsigned ch) 969{ 970#if(0) 971 device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch); 972#endif 973if (sc->cfg->subvendor==0x153b && sc->cfg->subdevice==0x1138 ) { 974 envy24_wrmt(sc, ENVY24_MT_VOLIDX, 16, 1); 975 envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2); 976 envy24_wrmt(sc, ENVY24_MT_VOLIDX, 17, 1); 977 envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2); 978 } 979 980 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1); 981 envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f00 | sc->left[ch], 2); 982 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1); 983 envy24_wrmt(sc, ENVY24_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2); 984} 985 986static void 987envy24_mutevolume(struct sc_info *sc, unsigned ch) 988{ 989 u_int32_t vol; 990 991#if(0) 992 device_printf(sc->dev, "envy24_mutevolume(sc, %d)\n", ch); 993#endif 994 vol = ENVY24_VOL_MUTE << 8 | ENVY24_VOL_MUTE; 995 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1); 996 envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2); 997 envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1); 998 envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2); 999} 1000 1001static u_int32_t 1002envy24_gethwptr(struct sc_info *sc, int dir) 1003{ 1004 int unit, regno; 1005 u_int32_t ptr, rtn; 1006 1007#if(0) 1008 device_printf(sc->dev, "envy24_gethwptr(sc, %d)\n", dir); 1009#endif 1010 if (dir == PCMDIR_PLAY) { 1011 rtn = sc->psize / 4; 1012 unit = ENVY24_PLAY_BUFUNIT / 4; 1013 regno = ENVY24_MT_PCNT; 1014 } 1015 else { 1016 rtn = sc->rsize / 4; 1017 unit = ENVY24_REC_BUFUNIT / 4; 1018 regno = ENVY24_MT_RCNT; 1019 } 1020 1021 ptr = envy24_rdmt(sc, regno, 2); 1022 rtn -= (ptr + 1); 1023 rtn /= unit; 1024 1025#if(0) 1026 device_printf(sc->dev, "envy24_gethwptr(): return %d\n", rtn); 1027#endif 1028 return rtn; 1029} 1030 1031static void 1032envy24_updintr(struct sc_info *sc, int dir) 1033{ 1034 int regptr, regintr; 1035 u_int32_t mask, intr; 1036 u_int32_t ptr, size, cnt; 1037 u_int16_t blk; 1038 1039#if(0) 1040 device_printf(sc->dev, "envy24_updintr(sc, %d)\n", dir); 1041#endif 1042 if (dir == PCMDIR_PLAY) { 1043 blk = sc->blk[0]; 1044 size = sc->psize / 4; 1045 regptr = ENVY24_MT_PCNT; 1046 regintr = ENVY24_MT_PTERM; 1047 mask = ~ENVY24_MT_INT_PMASK; 1048 } 1049 else { 1050 blk = sc->blk[1]; 1051 size = sc->rsize / 4; 1052 regptr = ENVY24_MT_RCNT; 1053 regintr = ENVY24_MT_RTERM; 1054 mask = ~ENVY24_MT_INT_RMASK; 1055 } 1056 1057 ptr = size - envy24_rdmt(sc, regptr, 2) - 1; 1058 /* 1059 cnt = blk - ptr % blk - 1; 1060 if (cnt == 0) 1061 cnt = blk - 1; 1062 */ 1063 cnt = blk - 1; 1064#if(0) 1065 device_printf(sc->dev, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt); 1066#endif 1067 envy24_wrmt(sc, regintr, cnt, 2); 1068 intr = envy24_rdmt(sc, ENVY24_MT_INT, 1); 1069#if(0) 1070 device_printf(sc->dev, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask); 1071#endif 1072 envy24_wrmt(sc, ENVY24_MT_INT, intr & mask, 1); 1073#if(0) 1074 device_printf(sc->dev, "envy24_updintr():INT-->0x%02x\n", 1075 envy24_rdmt(sc, ENVY24_MT_INT, 1)); 1076#endif 1077 1078 return; 1079} 1080 1081#if 0 1082static void 1083envy24_maskintr(struct sc_info *sc, int dir) 1084{ 1085 u_int32_t mask, intr; 1086 1087#if(0) 1088 device_printf(sc->dev, "envy24_maskintr(sc, %d)\n", dir); 1089#endif 1090 if (dir == PCMDIR_PLAY) 1091 mask = ENVY24_MT_INT_PMASK; 1092 else 1093 mask = ENVY24_MT_INT_RMASK; 1094 intr = envy24_rdmt(sc, ENVY24_MT_INT, 1); 1095 envy24_wrmt(sc, ENVY24_MT_INT, intr | mask, 1); 1096 1097 return; 1098} 1099#endif 1100 1101static int 1102envy24_checkintr(struct sc_info *sc, int dir) 1103{ 1104 u_int32_t mask, stat, intr, rtn; 1105 1106#if(0) 1107 device_printf(sc->dev, "envy24_checkintr(sc, %d)\n", dir); 1108#endif 1109 intr = envy24_rdmt(sc, ENVY24_MT_INT, 1); 1110 if (dir == PCMDIR_PLAY) { 1111 if ((rtn = intr & ENVY24_MT_INT_PSTAT) != 0) { 1112 mask = ~ENVY24_MT_INT_RSTAT; 1113 stat = ENVY24_MT_INT_PSTAT | ENVY24_MT_INT_PMASK; 1114 envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1); 1115 } 1116 } 1117 else { 1118 if ((rtn = intr & ENVY24_MT_INT_RSTAT) != 0) { 1119 mask = ~ENVY24_MT_INT_PSTAT; 1120 stat = ENVY24_MT_INT_RSTAT | ENVY24_MT_INT_RMASK; 1121 envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1); 1122 } 1123 } 1124 1125 return rtn; 1126} 1127 1128static void 1129envy24_start(struct sc_info *sc, int dir) 1130{ 1131 u_int32_t stat, sw; 1132 1133#if(0) 1134 device_printf(sc->dev, "envy24_start(sc, %d)\n", dir); 1135#endif 1136 if (dir == PCMDIR_PLAY) 1137 sw = ENVY24_MT_PCTL_PSTART; 1138 else 1139 sw = ENVY24_MT_PCTL_RSTART; 1140 1141 stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1); 1142 envy24_wrmt(sc, ENVY24_MT_PCTL, stat | sw, 1); 1143#if(0) 1144 DELAY(100); 1145 device_printf(sc->dev, "PADDR:0x%08x\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4)); 1146 device_printf(sc->dev, "PCNT:%ld\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2)); 1147#endif 1148 1149 return; 1150} 1151 1152static void 1153envy24_stop(struct sc_info *sc, int dir) 1154{ 1155 u_int32_t stat, sw; 1156 1157#if(0) 1158 device_printf(sc->dev, "envy24_stop(sc, %d)\n", dir); 1159#endif 1160 if (dir == PCMDIR_PLAY) 1161 sw = ~ENVY24_MT_PCTL_PSTART; 1162 else 1163 sw = ~ENVY24_MT_PCTL_RSTART; 1164 1165 stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1); 1166 envy24_wrmt(sc, ENVY24_MT_PCTL, stat & sw, 1); 1167 1168 return; 1169} 1170 1171static int 1172envy24_route(struct sc_info *sc, int dac, int class, int adc, int rev) 1173{ 1174 u_int32_t reg, mask; 1175 u_int32_t left, right; 1176 1177#if(0) 1178 device_printf(sc->dev, "envy24_route(sc, %d, %d, %d, %d)\n", 1179 dac, class, adc, rev); 1180#endif 1181 /* parameter pattern check */ 1182 if (dac < 0 || ENVY24_ROUTE_DAC_SPDIF < dac) 1183 return -1; 1184 if (class == ENVY24_ROUTE_CLASS_MIX && 1185 (dac != ENVY24_ROUTE_DAC_1 && dac != ENVY24_ROUTE_DAC_SPDIF)) 1186 return -1; 1187 if (rev) { 1188 left = ENVY24_ROUTE_RIGHT; 1189 right = ENVY24_ROUTE_LEFT; 1190 } 1191 else { 1192 left = ENVY24_ROUTE_LEFT; 1193 right = ENVY24_ROUTE_RIGHT; 1194 } 1195 1196 if (dac == ENVY24_ROUTE_DAC_SPDIF) { 1197 reg = class | class << 2 | 1198 ((adc << 1 | left) | left << 3) << 8 | 1199 ((adc << 1 | right) | right << 3) << 12; 1200#if(0) 1201 device_printf(sc->dev, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg); 1202#endif 1203 envy24_wrmt(sc, ENVY24_MT_SPDOUT, reg, 2); 1204 } 1205 else { 1206 mask = ~(0x0303 << dac * 2); 1207 reg = envy24_rdmt(sc, ENVY24_MT_PSDOUT, 2); 1208 reg = (reg & mask) | ((class | class << 8) << dac * 2); 1209#if(0) 1210 device_printf(sc->dev, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg); 1211#endif 1212 envy24_wrmt(sc, ENVY24_MT_PSDOUT, reg, 2); 1213 mask = ~(0xff << dac * 8); 1214 reg = envy24_rdmt(sc, ENVY24_MT_RECORD, 4); 1215 reg = (reg & mask) | 1216 (((adc << 1 | left) | left << 3) | 1217 ((adc << 1 | right) | right << 3) << 4) << dac * 8; 1218#if(0) 1219 device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg); 1220#endif 1221 envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4); 1222 } 1223 1224 return 0; 1225} 1226 1227/* -------------------------------------------------------------------- */ 1228 1229/* buffer copy routines */ 1230static void 1231envy24_p32sl(struct sc_chinfo *ch) 1232{ 1233 int length; 1234 sample32_t *dmabuf; 1235 u_int32_t *data; 1236 int src, dst, ssize, dsize, slot; 1237 int i; 1238 1239 length = sndbuf_getready(ch->buffer) / 8; 1240 dmabuf = ch->parent->pbuf; 1241 data = (u_int32_t *)ch->data; 1242 src = sndbuf_getreadyptr(ch->buffer) / 4; 1243 dst = src / 2 + ch->offset; 1244 ssize = ch->size / 4; 1245 dsize = ch->size / 8; 1246 slot = ch->num * 2; 1247 1248 for (i = 0; i < length; i++) { 1249 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = data[src]; 1250 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = data[src + 1]; 1251 dst++; 1252 dst %= dsize; 1253 src += 2; 1254 src %= ssize; 1255 } 1256 1257 return; 1258} 1259 1260static void 1261envy24_p16sl(struct sc_chinfo *ch) 1262{ 1263 int length; 1264 sample32_t *dmabuf; 1265 u_int16_t *data; 1266 int src, dst, ssize, dsize, slot; 1267 int i; 1268 1269#if(0) 1270 device_printf(ch->parent->dev, "envy24_p16sl()\n"); 1271#endif 1272 length = sndbuf_getready(ch->buffer) / 4; 1273 dmabuf = ch->parent->pbuf; 1274 data = (u_int16_t *)ch->data; 1275 src = sndbuf_getreadyptr(ch->buffer) / 2; 1276 dst = src / 2 + ch->offset; 1277 ssize = ch->size / 2; 1278 dsize = ch->size / 4; 1279 slot = ch->num * 2; 1280#if(0) 1281 device_printf(ch->parent->dev, "envy24_p16sl():%lu-->%lu(%lu)\n", src, dst, length); 1282#endif 1283 1284 for (i = 0; i < length; i++) { 1285 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16; 1286 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16; 1287#if(0) 1288 if (i < 16) { 1289 printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot]); 1290 printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1]); 1291 } 1292#endif 1293 dst++; 1294 dst %= dsize; 1295 src += 2; 1296 src %= ssize; 1297 } 1298#if(0) 1299 printf("\n"); 1300#endif 1301 1302 return; 1303} 1304 1305static void 1306envy24_p8u(struct sc_chinfo *ch) 1307{ 1308 int length; 1309 sample32_t *dmabuf; 1310 u_int8_t *data; 1311 int src, dst, ssize, dsize, slot; 1312 int i; 1313 1314 length = sndbuf_getready(ch->buffer) / 2; 1315 dmabuf = ch->parent->pbuf; 1316 data = (u_int8_t *)ch->data; 1317 src = sndbuf_getreadyptr(ch->buffer); 1318 dst = src / 2 + ch->offset; 1319 ssize = ch->size; 1320 dsize = ch->size / 4; 1321 slot = ch->num * 2; 1322 1323 for (i = 0; i < length; i++) { 1324 dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24; 1325 dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24; 1326 dst++; 1327 dst %= dsize; 1328 src += 2; 1329 src %= ssize; 1330 } 1331 1332 return; 1333} 1334 1335static void 1336envy24_r32sl(struct sc_chinfo *ch) 1337{ 1338 int length; 1339 sample32_t *dmabuf; 1340 u_int32_t *data; 1341 int src, dst, ssize, dsize, slot; 1342 int i; 1343 1344 length = sndbuf_getfree(ch->buffer) / 8; 1345 dmabuf = ch->parent->rbuf; 1346 data = (u_int32_t *)ch->data; 1347 dst = sndbuf_getfreeptr(ch->buffer) / 4; 1348 src = dst / 2 + ch->offset; 1349 dsize = ch->size / 4; 1350 ssize = ch->size / 8; 1351 slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2; 1352 1353 for (i = 0; i < length; i++) { 1354 data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer; 1355 data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer; 1356 dst += 2; 1357 dst %= dsize; 1358 src++; 1359 src %= ssize; 1360 } 1361 1362 return; 1363} 1364 1365static void 1366envy24_r16sl(struct sc_chinfo *ch) 1367{ 1368 int length; 1369 sample32_t *dmabuf; 1370 u_int16_t *data; 1371 int src, dst, ssize, dsize, slot; 1372 int i; 1373 1374 length = sndbuf_getfree(ch->buffer) / 4; 1375 dmabuf = ch->parent->rbuf; 1376 data = (u_int16_t *)ch->data; 1377 dst = sndbuf_getfreeptr(ch->buffer) / 2; 1378 src = dst / 2 + ch->offset; 1379 dsize = ch->size / 2; 1380 ssize = ch->size / 8; 1381 slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2; 1382 1383 for (i = 0; i < length; i++) { 1384 data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer; 1385 data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer; 1386 dst += 2; 1387 dst %= dsize; 1388 src++; 1389 src %= ssize; 1390 } 1391 1392 return; 1393} 1394 1395/* -------------------------------------------------------------------- */ 1396 1397/* channel interface */ 1398static void * 1399envy24chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 1400{ 1401 struct sc_info *sc = (struct sc_info *)devinfo; 1402 struct sc_chinfo *ch; 1403 unsigned num; 1404 1405#if(0) 1406 device_printf(sc->dev, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir); 1407#endif 1408 snd_mtxlock(sc->lock); 1409 if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) || 1410 (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) { 1411 snd_mtxunlock(sc->lock); 1412 return NULL; 1413 } 1414 num = sc->chnum; 1415 1416 ch = &sc->chan[num]; 1417 ch->size = 8 * ENVY24_SAMPLE_NUM; 1418 ch->data = malloc(ch->size, M_ENVY24, M_NOWAIT); 1419 if (ch->data == NULL) { 1420 ch->size = 0; 1421 ch = NULL; 1422 } 1423 else { 1424 ch->buffer = b; 1425 ch->channel = c; 1426 ch->parent = sc; 1427 ch->dir = dir; 1428 /* set channel map */ 1429 ch->num = envy24_chanmap[num]; 1430 snd_mtxunlock(sc->lock); 1431 sndbuf_setup(ch->buffer, ch->data, ch->size); 1432 snd_mtxlock(sc->lock); 1433 /* these 2 values are dummy */ 1434 ch->unit = 4; 1435 ch->blk = 10240; 1436 } 1437 snd_mtxunlock(sc->lock); 1438 1439 return ch; 1440} 1441 1442static int 1443envy24chan_free(kobj_t obj, void *data) 1444{ 1445 struct sc_chinfo *ch = data; 1446 struct sc_info *sc = ch->parent; 1447 1448#if(0) 1449 device_printf(sc->dev, "envy24chan_free()\n"); 1450#endif 1451 snd_mtxlock(sc->lock); 1452 if (ch->data != NULL) { 1453 free(ch->data, M_ENVY24); 1454 ch->data = NULL; 1455 } 1456 snd_mtxunlock(sc->lock); 1457 1458 return 0; 1459} 1460 1461static int 1462envy24chan_setformat(kobj_t obj, void *data, u_int32_t format) 1463{ 1464 struct sc_chinfo *ch = data; 1465 struct sc_info *sc = ch->parent; 1466 struct envy24_emldma *emltab; 1467 /* unsigned int bcnt, bsize; */ 1468 int i; 1469 1470#if(0) 1471 device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format); 1472#endif 1473 snd_mtxlock(sc->lock); 1474 /* check and get format related information */ 1475 if (ch->dir == PCMDIR_PLAY) 1476 emltab = envy24_pemltab; 1477 else 1478 emltab = envy24_remltab; 1479 if (emltab == NULL) { 1480 snd_mtxunlock(sc->lock); 1481 return -1; 1482 } 1483 for (i = 0; emltab[i].format != 0; i++) 1484 if (emltab[i].format == format) 1485 break; 1486 if (emltab[i].format == 0) { 1487 snd_mtxunlock(sc->lock); 1488 return -1; 1489 } 1490 1491 /* set format information */ 1492 ch->format = format; 1493 ch->emldma = emltab[i].emldma; 1494 if (ch->unit > emltab[i].unit) 1495 ch->blk *= ch->unit / emltab[i].unit; 1496 else 1497 ch->blk /= emltab[i].unit / ch->unit; 1498 ch->unit = emltab[i].unit; 1499 1500 /* set channel buffer information */ 1501 ch->size = ch->unit * ENVY24_SAMPLE_NUM; 1502#if 0 1503 if (ch->dir == PCMDIR_PLAY) 1504 bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT; 1505 else 1506 bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT; 1507 bsize *= ch->unit; 1508 bcnt = ch->size / bsize; 1509 sndbuf_resize(ch->buffer, bcnt, bsize); 1510#endif 1511 snd_mtxunlock(sc->lock); 1512 1513#if(0) 1514 device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0); 1515#endif 1516 return 0; 1517} 1518 1519/* 1520 IMPLEMENT NOTICE: In this driver, setspeed function only do setting 1521 of speed information value. And real hardware speed setting is done 1522 at start triggered(see envy24chan_trigger()). So, at this function 1523 is called, any value that ENVY24 can use is able to set. But, at 1524 start triggerd, some other channel is running, and that channel's 1525 speed isn't same with, then trigger function will fail. 1526*/ 1527static int 1528envy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed) 1529{ 1530 struct sc_chinfo *ch = data; 1531 u_int32_t val, prev; 1532 int i; 1533 1534#if(0) 1535 device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed); 1536#endif 1537 prev = 0x7fffffff; 1538 for (i = 0; (val = envy24_speed[i]) != 0; i++) { 1539 if (abs(val - speed) < abs(prev - speed)) 1540 prev = val; 1541 else 1542 break; 1543 } 1544 ch->speed = prev; 1545 1546#if(0) 1547 device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed); 1548#endif 1549 return ch->speed; 1550} 1551 1552static int 1553envy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 1554{ 1555 struct sc_chinfo *ch = data; 1556 /* struct sc_info *sc = ch->parent; */ 1557 u_int32_t size, prev; 1558 unsigned int bcnt, bsize; 1559 1560#if(0) 1561 device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize); 1562#endif 1563 prev = 0x7fffffff; 1564 /* snd_mtxlock(sc->lock); */ 1565 for (size = ch->size / 2; size > 0; size /= 2) { 1566 if (abs(size - blocksize) < abs(prev - blocksize)) 1567 prev = size; 1568 else 1569 break; 1570 } 1571 1572 ch->blk = prev / ch->unit; 1573 if (ch->dir == PCMDIR_PLAY) 1574 ch->blk *= ENVY24_PLAY_BUFUNIT / 4; 1575 else 1576 ch->blk *= ENVY24_REC_BUFUNIT / 4; 1577 /* set channel buffer information */ 1578 /* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */ 1579 if (ch->dir == PCMDIR_PLAY) 1580 bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT; 1581 else 1582 bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT; 1583 bsize *= ch->unit; 1584 bcnt = ch->size / bsize; 1585 sndbuf_resize(ch->buffer, bcnt, bsize); 1586 /* snd_mtxunlock(sc->lock); */ 1587 1588#if(0) 1589 device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev); 1590#endif 1591 return prev; 1592} 1593 1594/* semantic note: must start at beginning of buffer */ 1595static int 1596envy24chan_trigger(kobj_t obj, void *data, int go) 1597{ 1598 struct sc_chinfo *ch = data; 1599 struct sc_info *sc = ch->parent; 1600 u_int32_t ptr; 1601 int slot; 1602#if 0 1603 int i; 1604 1605 device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go); 1606#endif 1607 snd_mtxlock(sc->lock); 1608 if (ch->dir == PCMDIR_PLAY) 1609 slot = 0; 1610 else 1611 slot = 1; 1612 switch (go) { 1613 case PCMTRIG_START: 1614#if(0) 1615 device_printf(sc->dev, "envy24chan_trigger(): start\n"); 1616#endif 1617 /* check or set channel speed */ 1618 if (sc->run[0] == 0 && sc->run[1] == 0) { 1619 sc->speed = envy24_setspeed(sc, ch->speed); 1620 sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed; 1621 sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed; 1622 } 1623 else if (ch->speed != 0 && ch->speed != sc->speed) 1624 return -1; 1625 if (ch->speed == 0) 1626 ch->channel->speed = sc->speed; 1627 /* start or enable channel */ 1628 sc->run[slot]++; 1629 if (sc->run[slot] == 1) { 1630 /* first channel */ 1631 ch->offset = 0; 1632 sc->blk[slot] = ch->blk; 1633 } 1634 else { 1635 ptr = envy24_gethwptr(sc, ch->dir); 1636 ch->offset = ((ptr / ch->blk + 1) * ch->blk % 1637 (ch->size / 4)) * 4 / ch->unit; 1638 if (ch->blk < sc->blk[slot]) 1639 sc->blk[slot] = ch->blk; 1640 } 1641 if (ch->dir == PCMDIR_PLAY) { 1642 ch->emldma(ch); 1643 envy24_setvolume(sc, ch->num); 1644 } 1645 envy24_updintr(sc, ch->dir); 1646 if (sc->run[slot] == 1) 1647 envy24_start(sc, ch->dir); 1648 ch->run = 1; 1649 break; 1650 case PCMTRIG_EMLDMAWR: 1651#if(0) 1652 device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n"); 1653#endif 1654 if (ch->run != 1) 1655 return -1; 1656 ch->emldma(ch); 1657 break; 1658 case PCMTRIG_EMLDMARD: 1659#if(0) 1660 device_printf(sc->dev, "envy24chan_trigger(): emldmard\n"); 1661#endif 1662 if (ch->run != 1) 1663 return -1; 1664 ch->emldma(ch); 1665 break; 1666 case PCMTRIG_ABORT: 1667#if(0) 1668 device_printf(sc->dev, "envy24chan_trigger(): abort\n"); 1669#endif 1670 ch->run = 0; 1671 sc->run[slot]--; 1672 if (ch->dir == PCMDIR_PLAY) 1673 envy24_mutevolume(sc, ch->num); 1674 if (sc->run[slot] == 0) { 1675 envy24_stop(sc, ch->dir); 1676 sc->intr[slot] = 0; 1677 } 1678#if 0 1679 else if (ch->blk == sc->blk[slot]) { 1680 sc->blk[slot] = ENVY24_SAMPLE_NUM / 2; 1681 for (i = 0; i < ENVY24_CHAN_NUM; i++) { 1682 if (sc->chan[i].dir == ch->dir && 1683 sc->chan[i].run == 1 && 1684 sc->chan[i].blk < sc->blk[slot]) 1685 sc->blk[slot] = sc->chan[i].blk; 1686 } 1687 if (ch->blk != sc->blk[slot]) 1688 envy24_updintr(sc, ch->dir); 1689 } 1690#endif 1691 break; 1692 } 1693 snd_mtxunlock(sc->lock); 1694 1695 return 0; 1696} 1697 1698static int 1699envy24chan_getptr(kobj_t obj, void *data) 1700{ 1701 struct sc_chinfo *ch = data; 1702 struct sc_info *sc = ch->parent; 1703 u_int32_t ptr; 1704 int rtn; 1705 1706#if(0) 1707 device_printf(sc->dev, "envy24chan_getptr()\n"); 1708#endif 1709 snd_mtxlock(sc->lock); 1710 ptr = envy24_gethwptr(sc, ch->dir); 1711 rtn = ptr * ch->unit; 1712 snd_mtxunlock(sc->lock); 1713 1714#if(0) 1715 device_printf(sc->dev, "envy24chan_getptr(): return %d\n", 1716 rtn); 1717#endif 1718 return rtn; 1719} 1720 1721static struct pcmchan_caps * 1722envy24chan_getcaps(kobj_t obj, void *data) 1723{ 1724 struct sc_chinfo *ch = data; 1725 struct sc_info *sc = ch->parent; 1726 struct pcmchan_caps *rtn; 1727 1728#if(0) 1729 device_printf(sc->dev, "envy24chan_getcaps()\n"); 1730#endif 1731 snd_mtxlock(sc->lock); 1732 if (ch->dir == PCMDIR_PLAY) { 1733 if (sc->run[0] == 0) 1734 rtn = &envy24_playcaps; 1735 else 1736 rtn = &sc->caps[0]; 1737 } 1738 else { 1739 if (sc->run[1] == 0) 1740 rtn = &envy24_reccaps; 1741 else 1742 rtn = &sc->caps[1]; 1743 } 1744 snd_mtxunlock(sc->lock); 1745 1746 return rtn; 1747} 1748 1749static kobj_method_t envy24chan_methods[] = { 1750 KOBJMETHOD(channel_init, envy24chan_init), 1751 KOBJMETHOD(channel_free, envy24chan_free), 1752 KOBJMETHOD(channel_setformat, envy24chan_setformat), 1753 KOBJMETHOD(channel_setspeed, envy24chan_setspeed), 1754 KOBJMETHOD(channel_setblocksize, envy24chan_setblocksize), 1755 KOBJMETHOD(channel_trigger, envy24chan_trigger), 1756 KOBJMETHOD(channel_getptr, envy24chan_getptr), 1757 KOBJMETHOD(channel_getcaps, envy24chan_getcaps), 1758 { 0, 0 } 1759}; 1760CHANNEL_DECLARE(envy24chan); 1761 1762/* -------------------------------------------------------------------- */ 1763 1764/* mixer interface */ 1765 1766static int 1767envy24mixer_init(struct snd_mixer *m) 1768{ 1769 struct sc_info *sc = mix_getdevinfo(m); 1770 1771#if(0) 1772 device_printf(sc->dev, "envy24mixer_init()\n"); 1773#endif 1774 if (sc == NULL) 1775 return -1; 1776 1777 /* set volume control rate */ 1778 snd_mtxlock(sc->lock); 1779 envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */ 1780 1781 mix_setdevs(m, ENVY24_MIX_MASK); 1782 mix_setrecdevs(m, ENVY24_MIX_REC_MASK); 1783 snd_mtxunlock(sc->lock); 1784 1785 return 0; 1786} 1787 1788static int 1789envy24mixer_reinit(struct snd_mixer *m) 1790{ 1791 struct sc_info *sc = mix_getdevinfo(m); 1792 1793 if (sc == NULL) 1794 return -1; 1795#if(0) 1796 device_printf(sc->dev, "envy24mixer_reinit()\n"); 1797#endif 1798 1799 return 0; 1800} 1801 1802static int 1803envy24mixer_uninit(struct snd_mixer *m) 1804{ 1805 struct sc_info *sc = mix_getdevinfo(m); 1806 1807 if (sc == NULL) 1808 return -1; 1809#if(0) 1810 device_printf(sc->dev, "envy24mixer_uninit()\n"); 1811#endif 1812 1813 return 0; 1814} 1815 1816static int 1817envy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 1818{ 1819 struct sc_info *sc = mix_getdevinfo(m); 1820 int ch = envy24_mixmap[dev]; 1821 int hwch; 1822 int i; 1823 1824 if (sc == NULL) 1825 return -1; 1826 if (dev == 0 && sc->cfg->codec->setvolume == NULL) 1827 return -1; 1828 if (dev != 0 && ch == -1) 1829 return -1; 1830 hwch = envy24_chanmap[ch]; 1831#if(0) 1832 device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n", 1833 dev, left, right); 1834#endif 1835 1836 snd_mtxlock(sc->lock); 1837 if (dev == 0) { 1838 for (i = 0; i < sc->dacn; i++) { 1839 sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right); 1840 } 1841 } 1842 else { 1843 /* set volume value for hardware */ 1844 if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN) 1845 sc->left[hwch] = ENVY24_VOL_MUTE; 1846 if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN) 1847 sc->right[hwch] = ENVY24_VOL_MUTE; 1848 1849 /* set volume for record channel and running play channel */ 1850 if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run) 1851 envy24_setvolume(sc, hwch); 1852 } 1853 snd_mtxunlock(sc->lock); 1854 1855 return right << 8 | left; 1856} 1857 1858static u_int32_t 1859envy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src) 1860{ 1861 struct sc_info *sc = mix_getdevinfo(m); 1862 int ch = envy24_mixmap[src]; 1863#if(0) 1864 device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src); 1865#endif 1866 1867 if (ch > ENVY24_CHAN_PLAY_SPDIF) 1868 sc->src = ch; 1869 return src; 1870} 1871 1872static kobj_method_t envy24mixer_methods[] = { 1873 KOBJMETHOD(mixer_init, envy24mixer_init), 1874 KOBJMETHOD(mixer_reinit, envy24mixer_reinit), 1875 KOBJMETHOD(mixer_uninit, envy24mixer_uninit), 1876 KOBJMETHOD(mixer_set, envy24mixer_set), 1877 KOBJMETHOD(mixer_setrecsrc, envy24mixer_setrecsrc), 1878 { 0, 0 } 1879}; 1880MIXER_DECLARE(envy24mixer); 1881 1882/* -------------------------------------------------------------------- */ 1883 1884/* The interrupt handler */ 1885static void 1886envy24_intr(void *p) 1887{ 1888 struct sc_info *sc = (struct sc_info *)p; 1889 struct sc_chinfo *ch; 1890 u_int32_t ptr, dsize, feed; 1891 int i; 1892 1893#if(0) 1894 device_printf(sc->dev, "envy24_intr()\n"); 1895#endif 1896 snd_mtxlock(sc->lock); 1897 if (envy24_checkintr(sc, PCMDIR_PLAY)) { 1898#if(0) 1899 device_printf(sc->dev, "envy24_intr(): play\n"); 1900#endif 1901 dsize = sc->psize / 4; 1902 ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1; 1903#if(0) 1904 device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr); 1905#endif 1906 ptr -= ptr % sc->blk[0]; 1907 feed = (ptr + dsize - sc->intr[0]) % dsize; 1908#if(0) 1909 printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed); 1910#endif 1911 for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) { 1912 ch = &sc->chan[i]; 1913#if(0) 1914 if (ch->run) 1915 device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk); 1916#endif 1917 if (ch->run && ch->blk <= feed) { 1918 snd_mtxunlock(sc->lock); 1919 chn_intr(ch->channel); 1920 snd_mtxlock(sc->lock); 1921 } 1922 } 1923 sc->intr[0] = ptr; 1924 envy24_updintr(sc, PCMDIR_PLAY); 1925 } 1926 if (envy24_checkintr(sc, PCMDIR_REC)) { 1927#if(0) 1928 device_printf(sc->dev, "envy24_intr(): rec\n"); 1929#endif 1930 dsize = sc->rsize / 4; 1931 ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1; 1932 ptr -= ptr % sc->blk[1]; 1933 feed = (ptr + dsize - sc->intr[1]) % dsize; 1934 for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) { 1935 ch = &sc->chan[i]; 1936 if (ch->run && ch->blk <= feed) { 1937 snd_mtxunlock(sc->lock); 1938 chn_intr(ch->channel); 1939 snd_mtxlock(sc->lock); 1940 } 1941 } 1942 sc->intr[1] = ptr; 1943 envy24_updintr(sc, PCMDIR_REC); 1944 } 1945 snd_mtxunlock(sc->lock); 1946 1947 return; 1948} 1949 1950/* 1951 * Probe and attach the card 1952 */ 1953 1954static int 1955envy24_pci_probe(device_t dev) 1956{ 1957 u_int16_t sv, sd; 1958 int i; 1959 1960#if(0) 1961 printf("envy24_pci_probe()\n"); 1962#endif 1963 if (pci_get_device(dev) == PCID_ENVY24 && 1964 pci_get_vendor(dev) == PCIV_ENVY24) { 1965 sv = pci_get_subvendor(dev); 1966 sd = pci_get_subdevice(dev); 1967 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 1968 if (cfg_table[i].subvendor == sv && 1969 cfg_table[i].subdevice == sd) { 1970 break; 1971 } 1972 } 1973 device_set_desc(dev, cfg_table[i].name); 1974#if(0) 1975 printf("envy24_pci_probe(): return 0\n"); 1976#endif 1977 return 0; 1978 } 1979 else { 1980#if(0) 1981 printf("envy24_pci_probe(): return ENXIO\n"); 1982#endif 1983 return ENXIO; 1984 } 1985} 1986 1987static void 1988envy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1989{ 1990 /* struct sc_info *sc = (struct sc_info *)arg; */ 1991 1992#if(0) 1993 device_printf(sc->dev, "envy24_dmapsetmap()\n"); 1994 if (bootverbose) { 1995 printf("envy24(play): setmap %lx, %lx; ", 1996 (unsigned long)segs->ds_addr, 1997 (unsigned long)segs->ds_len); 1998 printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap)); 1999 } 2000#endif 2001} 2002 2003static void 2004envy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2005{ 2006 /* struct sc_info *sc = (struct sc_info *)arg; */ 2007 2008#if(0) 2009 device_printf(sc->dev, "envy24_dmarsetmap()\n"); 2010 if (bootverbose) { 2011 printf("envy24(record): setmap %lx, %lx; ", 2012 (unsigned long)segs->ds_addr, 2013 (unsigned long)segs->ds_len); 2014 printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap)); 2015 } 2016#endif 2017} 2018 2019static void 2020envy24_dmafree(struct sc_info *sc) 2021{ 2022#if(0) 2023 device_printf(sc->dev, "envy24_dmafree():"); 2024 if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap); 2025 else printf(" sc->rmap(null)"); 2026 if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap); 2027 else printf(" sc->pmap(null)"); 2028 if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf); 2029 else printf(" sc->rbuf(null)"); 2030 if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf); 2031 else printf(" sc->pbuf(null)\n"); 2032#endif 2033#if(0) 2034 if (sc->rmap) 2035 bus_dmamap_unload(sc->dmat, sc->rmap); 2036 if (sc->pmap) 2037 bus_dmamap_unload(sc->dmat, sc->pmap); 2038 if (sc->rbuf) 2039 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2040 if (sc->pbuf) 2041 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2042#else 2043 bus_dmamap_unload(sc->dmat, sc->rmap); 2044 bus_dmamap_unload(sc->dmat, sc->pmap); 2045 bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2046 bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2047#endif 2048 2049 sc->rmap = sc->pmap = NULL; 2050 sc->pbuf = NULL; 2051 sc->rbuf = NULL; 2052 2053 return; 2054} 2055 2056static int 2057envy24_dmainit(struct sc_info *sc) 2058{ 2059 u_int32_t addr; 2060 2061#if(0) 2062 device_printf(sc->dev, "envy24_dmainit()\n"); 2063#endif 2064 /* init values */ 2065 sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM; 2066 sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM; 2067 sc->pbuf = NULL; 2068 sc->rbuf = NULL; 2069 sc->pmap = sc->rmap = NULL; 2070 sc->blk[0] = sc->blk[1] = 0; 2071 2072 /* allocate DMA buffer */ 2073#if(0) 2074 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n"); 2075#endif 2076 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap)) 2077 goto bad; 2078#if(0) 2079 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n"); 2080#endif 2081 if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap)) 2082 goto bad; 2083#if(0) 2084 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n"); 2085#endif 2086 if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0)) 2087 goto bad; 2088#if(0) 2089 device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n"); 2090#endif 2091 if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0)) 2092 goto bad; 2093 bzero(sc->pbuf, sc->psize); 2094 bzero(sc->rbuf, sc->rsize); 2095 2096 /* set values to register */ 2097 addr = vtophys(sc->pbuf); 2098#if(0) 2099 device_printf(sc->dev, "pbuf(0x%08x)\n", addr); 2100#endif 2101 envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4); 2102#if(0) 2103 device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4)); 2104 device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1); 2105#endif 2106 envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2); 2107#if(0) 2108 device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2)); 2109#endif 2110 addr = vtophys(sc->rbuf); 2111 envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4); 2112 envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2); 2113 2114 return 0; 2115 bad: 2116 envy24_dmafree(sc); 2117 return ENOSPC; 2118} 2119 2120static void 2121envy24_putcfg(struct sc_info *sc) 2122{ 2123 device_printf(sc->dev, "system configuration\n"); 2124 printf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n", 2125 sc->cfg->subvendor, sc->cfg->subdevice); 2126 printf(" XIN2 Clock Source: "); 2127 switch (sc->cfg->scfg & PCIM_SCFG_XIN2) { 2128 case 0x00: 2129 printf("22.5792MHz(44.1kHz*512)\n"); 2130 break; 2131 case 0x40: 2132 printf("16.9344MHz(44.1kHz*384)\n"); 2133 break; 2134 case 0x80: 2135 printf("from external clock synthesizer chip\n"); 2136 break; 2137 default: 2138 printf("illeagal system setting\n"); 2139 } 2140 printf(" MPU-401 UART(s) #: "); 2141 if (sc->cfg->scfg & PCIM_SCFG_MPU) 2142 printf("2\n"); 2143 else 2144 printf("1\n"); 2145 printf(" AC'97 codec: "); 2146 if (sc->cfg->scfg & PCIM_SCFG_AC97) 2147 printf("not exist\n"); 2148 else 2149 printf("exist\n"); 2150 printf(" ADC #: "); 2151 printf("%d\n", sc->adcn); 2152 printf(" DAC #: "); 2153 printf("%d\n", sc->dacn); 2154 printf(" Multi-track converter type: "); 2155 if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) { 2156 printf("AC'97(SDATA_OUT:"); 2157 if (sc->cfg->acl & PCIM_ACL_OMODE) 2158 printf("packed"); 2159 else 2160 printf("split"); 2161 printf("|SDATA_IN:"); 2162 if (sc->cfg->acl & PCIM_ACL_IMODE) 2163 printf("packed"); 2164 else 2165 printf("split"); 2166 printf(")\n"); 2167 } 2168 else { 2169 printf("I2S("); 2170 if (sc->cfg->i2s & PCIM_I2S_VOL) 2171 printf("with volume, "); 2172 if (sc->cfg->i2s & PCIM_I2S_96KHZ) 2173 printf("96KHz support, "); 2174 switch (sc->cfg->i2s & PCIM_I2S_RES) { 2175 case PCIM_I2S_16BIT: 2176 printf("16bit resolution, "); 2177 break; 2178 case PCIM_I2S_18BIT: 2179 printf("18bit resolution, "); 2180 break; 2181 case PCIM_I2S_20BIT: 2182 printf("20bit resolution, "); 2183 break; 2184 case PCIM_I2S_24BIT: 2185 printf("24bit resolution, "); 2186 break; 2187 } 2188 printf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID); 2189 } 2190 printf(" S/PDIF(IN/OUT): "); 2191 if (sc->cfg->spdif & PCIM_SPDIF_IN) 2192 printf("1/"); 2193 else 2194 printf("0/"); 2195 if (sc->cfg->spdif & PCIM_SPDIF_OUT) 2196 printf("1 "); 2197 else 2198 printf("0 "); 2199 if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT)) 2200 printf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2); 2201 printf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n", 2202 sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate); 2203} 2204 2205static int 2206envy24_init(struct sc_info *sc) 2207{ 2208 u_int32_t data; 2209#if(0) 2210 int rtn; 2211#endif 2212 int i; 2213 u_int32_t sv, sd; 2214 2215 2216#if(0) 2217 device_printf(sc->dev, "envy24_init()\n"); 2218#endif 2219 2220 /* reset chip */ 2221 envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1); 2222 DELAY(200); 2223 envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1); 2224 DELAY(200); 2225 2226 /* legacy hardware disable */ 2227 data = pci_read_config(sc->dev, PCIR_LAC, 2); 2228 data |= PCIM_LAC_DISABLE; 2229 pci_write_config(sc->dev, PCIR_LAC, data, 2); 2230 2231 /* check system configuration */ 2232 sc->cfg = NULL; 2233 for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2234 /* 1st: search configuration from table */ 2235 sv = pci_get_subvendor(sc->dev); 2236 sd = pci_get_subdevice(sc->dev); 2237 if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) { 2238#if(0) 2239 device_printf(sc->dev, "Set configuration from table\n"); 2240#endif 2241 sc->cfg = &cfg_table[i]; 2242 break; 2243 } 2244 } 2245 if (sc->cfg == NULL) { 2246 /* 2nd: read configuration from table */ 2247 sc->cfg = envy24_rom2cfg(sc); 2248 } 2249 sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1; 2250 sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1; 2251 2252 if (1 /* bootverbose */) { 2253 envy24_putcfg(sc); 2254 } 2255 2256 /* set system configuration */ 2257 pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1); 2258 pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1); 2259 pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1); 2260 pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1); 2261 envy24_gpiosetmask(sc, sc->cfg->gpiomask); 2262 envy24_gpiosetdir(sc, sc->cfg->gpiodir); 2263 envy24_gpiowr(sc, sc->cfg->gpiostate); 2264 for (i = 0; i < sc->adcn; i++) { 2265 sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i); 2266 sc->cfg->codec->init(sc->adc[i]); 2267 } 2268 for (i = 0; i < sc->dacn; i++) { 2269 sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i); 2270 sc->cfg->codec->init(sc->dac[i]); 2271 } 2272 2273 /* initialize DMA buffer */ 2274#if(0) 2275 device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n"); 2276#endif 2277 if (envy24_dmainit(sc)) 2278 return ENOSPC; 2279 2280 /* initialize status */ 2281 sc->run[0] = sc->run[1] = 0; 2282 sc->intr[0] = sc->intr[1] = 0; 2283 sc->speed = 0; 2284 sc->caps[0].fmtlist = envy24_playfmt; 2285 sc->caps[1].fmtlist = envy24_recfmt; 2286 2287 /* set channel router */ 2288 envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0); 2289 envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0); 2290 /* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */ 2291 2292 /* set macro interrupt mask */ 2293 data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1); 2294 envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1); 2295 data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1); 2296#if(0) 2297 device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data); 2298#endif 2299 2300 return 0; 2301} 2302 2303static int 2304envy24_alloc_resource(struct sc_info *sc) 2305{ 2306 /* allocate I/O port resource */ 2307 sc->csid = PCIR_CCS; 2308 sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2309 &sc->csid, 0, ~0, 1, RF_ACTIVE); 2310 sc->ddmaid = PCIR_DDMA; 2311 sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2312 &sc->ddmaid, 0, ~0, 1, RF_ACTIVE); 2313 sc->dsid = PCIR_DS; 2314 sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2315 &sc->dsid, 0, ~0, 1, RF_ACTIVE); 2316 sc->mtid = PCIR_MT; 2317 sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2318 &sc->mtid, 0, ~0, 1, RF_ACTIVE); 2319 if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) { 2320 device_printf(sc->dev, "unable to map IO port space\n"); 2321 return ENXIO; 2322 } 2323 sc->cst = rman_get_bustag(sc->cs); 2324 sc->csh = rman_get_bushandle(sc->cs); 2325 sc->ddmat = rman_get_bustag(sc->ddma); 2326 sc->ddmah = rman_get_bushandle(sc->ddma); 2327 sc->dst = rman_get_bustag(sc->ds); 2328 sc->dsh = rman_get_bushandle(sc->ds); 2329 sc->mtt = rman_get_bustag(sc->mt); 2330 sc->mth = rman_get_bushandle(sc->mt); 2331#if(0) 2332 device_printf(sc->dev, 2333 "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n", 2334 pci_read_config(sc->dev, PCIR_CCS, 4), 2335 pci_read_config(sc->dev, PCIR_DDMA, 4), 2336 pci_read_config(sc->dev, PCIR_DS, 4), 2337 pci_read_config(sc->dev, PCIR_MT, 4)); 2338#endif 2339 2340 /* allocate interupt resource */ 2341 sc->irqid = 0; 2342 sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid, 2343 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 2344 if (!sc->irq || 2345 snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) { 2346 device_printf(sc->dev, "unable to map interrupt\n"); 2347 return ENXIO; 2348 } 2349 2350 /* allocate DMA resource */ 2351 if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev), 2352 /*alignment*/4, 2353 /*boundary*/0, 2354 /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24, 2355 /*highaddr*/BUS_SPACE_MAXADDR_ENVY24, 2356 /*filter*/NULL, /*filterarg*/NULL, 2357 /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24, 2358 /*nsegments*/1, /*maxsegsz*/0x3ffff, 2359 /*flags*/0, /*lockfunc*/busdma_lock_mutex, 2360 /*lockarg*/&Giant, &sc->dmat) != 0) { 2361 device_printf(sc->dev, "unable to create dma tag\n"); 2362 return ENXIO; 2363 } 2364 2365 return 0; 2366} 2367 2368static int 2369envy24_pci_attach(device_t dev) 2370{ 2371 u_int32_t data; 2372 struct sc_info *sc; 2373 char status[SND_STATUSLEN]; 2374 int err = 0; 2375 int i; 2376 2377#if(0) 2378 device_printf(dev, "envy24_pci_attach()\n"); 2379#endif 2380 /* get sc_info data area */ 2381 if ((sc = malloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) { 2382 device_printf(dev, "cannot allocate softc\n"); 2383 return ENXIO; 2384 } 2385 2386 bzero(sc, sizeof(*sc)); 2387 sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_envy24 softc"); 2388 sc->dev = dev; 2389 2390 /* initialize PCI interface */ 2391 data = pci_read_config(dev, PCIR_COMMAND, 2); 2392 data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN); 2393 pci_write_config(dev, PCIR_COMMAND, data, 2); 2394 data = pci_read_config(dev, PCIR_COMMAND, 2); 2395 2396 /* allocate resources */ 2397 err = envy24_alloc_resource(sc); 2398 if (err) { 2399 device_printf(dev, "unable to allocate system resources\n"); 2400 goto bad; 2401 } 2402 2403 /* initialize card */ 2404 err = envy24_init(sc); 2405 if (err) { 2406 device_printf(dev, "unable to initialize the card\n"); 2407 goto bad; 2408 } 2409 2410 /* set multi track mixer */ 2411 mixer_init(dev, &envy24mixer_class, sc); 2412 2413 /* set channel information */ 2414 err = pcm_register(dev, sc, sc->dacn, sc->adcn); 2415 if (err) 2416 goto bad; 2417 sc->chnum = ENVY24_CHAN_PLAY_DAC1; 2418 for (i = 0; i < sc->dacn; i++) { 2419 pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc); 2420 sc->chnum++; 2421 } 2422 sc->chnum = ENVY24_CHAN_REC_ADC1; 2423 for (i = 0; i < sc->adcn; i++) { 2424 pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc); 2425 sc->chnum++; 2426 } 2427 2428 /* set status iformation */ 2429 snprintf(status, SND_STATUSLEN, 2430 "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld", 2431 rman_get_start(sc->cs), 2432 rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1, 2433 rman_get_start(sc->ddma), 2434 rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1, 2435 rman_get_start(sc->ds), 2436 rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1, 2437 rman_get_start(sc->mt), 2438 rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1, 2439 rman_get_start(sc->irq)); 2440 pcm_setstatus(dev, status); 2441 2442 return 0; 2443 2444bad: 2445 if (sc->ih) 2446 bus_teardown_intr(dev, sc->irq, sc->ih); 2447 if (sc->irq) 2448 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2449 envy24_dmafree(sc); 2450 if (sc->dmat) 2451 bus_dma_tag_destroy(sc->dmat); 2452 if (sc->cfg->codec->destroy != NULL) { 2453 for (i = 0; i < sc->adcn; i++) 2454 sc->cfg->codec->destroy(sc->adc[i]); 2455 for (i = 0; i < sc->dacn; i++) 2456 sc->cfg->codec->destroy(sc->dac[i]); 2457 } 2458 envy24_cfgfree(sc->cfg); 2459 if (sc->cs) 2460 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2461 if (sc->ddma) 2462 bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma); 2463 if (sc->ds) 2464 bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds); 2465 if (sc->mt) 2466 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2467 if (sc->lock) 2468 snd_mtxfree(sc->lock); 2469 free(sc, M_ENVY24); 2470 return err; 2471} 2472 2473static int 2474envy24_pci_detach(device_t dev) 2475{ 2476 struct sc_info *sc; 2477 int r; 2478 int i; 2479 2480#if(0) 2481 device_printf(dev, "envy24_pci_detach()\n"); 2482#endif 2483 sc = pcm_getdevinfo(dev); 2484 if (sc == NULL) 2485 return 0; 2486 r = pcm_unregister(dev); 2487 if (r) 2488 return r; 2489 2490 envy24_dmafree(sc); 2491 if (sc->cfg->codec->destroy != NULL) { 2492 for (i = 0; i < sc->adcn; i++) 2493 sc->cfg->codec->destroy(sc->adc[i]); 2494 for (i = 0; i < sc->dacn; i++) 2495 sc->cfg->codec->destroy(sc->dac[i]); 2496 } 2497 envy24_cfgfree(sc->cfg); 2498 bus_dma_tag_destroy(sc->dmat); 2499 bus_teardown_intr(dev, sc->irq, sc->ih); 2500 bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2501 bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2502 bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma); 2503 bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds); 2504 bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2505 snd_mtxfree(sc->lock); 2506 free(sc, M_ENVY24); 2507 return 0; 2508} 2509 2510static device_method_t envy24_methods[] = { 2511 /* Device interface */ 2512 DEVMETHOD(device_probe, envy24_pci_probe), 2513 DEVMETHOD(device_attach, envy24_pci_attach), 2514 DEVMETHOD(device_detach, envy24_pci_detach), 2515 { 0, 0 } 2516}; 2517 2518static driver_t envy24_driver = { 2519 "pcm", 2520 envy24_methods, 2521#if __FreeBSD_version > 500000 2522 PCM_SOFTC_SIZE, 2523#else 2524 sizeof(struct snddev_info), 2525#endif 2526}; 2527 2528DRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0); 2529MODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2530MODULE_DEPEND(snd_envy24, snd_spicds, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2531MODULE_VERSION(snd_envy24, 1); 2532