envy24.c revision 168883
1159687Snetchild/* 2159687Snetchild * Copyright (c) 2001 Katsurajima Naoto <raven@katsurajima.seya.yokohama.jp> 3159687Snetchild * All rights reserved. 4159687Snetchild * 5159687Snetchild * Redistribution and use in source and binary forms, with or without 6159687Snetchild * modification, are permitted provided that the following conditions 7159687Snetchild * are met: 8159687Snetchild * 1. Redistributions of source code must retain the above copyright 9159687Snetchild * notice, this list of conditions and the following disclaimer. 10159687Snetchild * 2. Redistributions in binary form must reproduce the above copyright 11159687Snetchild * notice, this list of conditions and the following disclaimer in the 12159687Snetchild * documentation and/or other materials provided with the distribution. 13159687Snetchild * 14159687Snetchild * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15159687Snetchild * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16159687Snetchild * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17159687Snetchild * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18159687Snetchild * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19159687Snetchild * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20159687Snetchild * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21159687Snetchild * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHERIN CONTRACT, STRICT 22159687Snetchild * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23159687Snetchild * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THEPOSSIBILITY OF 24159687Snetchild * SUCH DAMAGE. 25159687Snetchild * 26159687Snetchild */ 27159687Snetchild 28159687Snetchild#include <dev/sound/pcm/sound.h> 29159687Snetchild#include <dev/sound/pcm/ac97.h> 30162876Snetchild#include <dev/sound/pci/spicds.h> 31159687Snetchild#include <dev/sound/pci/envy24.h> 32159687Snetchild 33159689Snetchild#include <dev/pci/pcireg.h> 34159689Snetchild#include <dev/pci/pcivar.h> 35159687Snetchild 36159687Snetchild#include "mixer_if.h" 37159687Snetchild 38165306SariffSND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/envy24.c 168883 2007-04-20 01:28:51Z ariff $"); 39165306Sariff 40159687SnetchildMALLOC_DEFINE(M_ENVY24, "envy24", "envy24 audio"); 41159687Snetchild 42159687Snetchild/* -------------------------------------------------------------------- */ 43159687Snetchild 44159687Snetchildstruct sc_info; 45159687Snetchild 46159687Snetchild#define ENVY24_PLAY_CHNUM 10 47159687Snetchild#define ENVY24_REC_CHNUM 12 48159687Snetchild#define ENVY24_PLAY_BUFUNIT (4 /* byte/sample */ * 10 /* channel */) 49159687Snetchild#define ENVY24_REC_BUFUNIT (4 /* byte/sample */ * 12 /* channel */) 50159687Snetchild#define ENVY24_SAMPLE_NUM 4096 51159687Snetchild 52159687Snetchild#define ENVY24_TIMEOUT 1000 53159687Snetchild 54159687Snetchild#define ENVY24_DEFAULT_FORMAT (AFMT_STEREO | AFMT_S16_LE) 55159687Snetchild 56159687Snetchild#define ENVY24_NAMELEN 32 57159687Snetchild 58159689Snetchildstruct envy24_sample { 59159689Snetchild volatile u_int32_t buffer; 60159689Snetchild}; 61159687Snetchild 62159689Snetchildtypedef struct envy24_sample sample32_t; 63159689Snetchild 64159687Snetchild/* channel registers */ 65159687Snetchildstruct sc_chinfo { 66159687Snetchild struct snd_dbuf *buffer; 67159687Snetchild struct pcm_channel *channel; 68159687Snetchild struct sc_info *parent; 69159687Snetchild int dir; 70159687Snetchild unsigned num; /* hw channel number */ 71159687Snetchild 72159687Snetchild /* channel information */ 73159687Snetchild u_int32_t format; 74159687Snetchild u_int32_t speed; 75159687Snetchild u_int32_t blk; /* hw block size(dword) */ 76159687Snetchild 77159687Snetchild /* format conversion structure */ 78159687Snetchild u_int8_t *data; 79159687Snetchild unsigned int size; /* data buffer size(byte) */ 80159687Snetchild int unit; /* sample size(byte) */ 81159687Snetchild unsigned int offset; /* samples number offset */ 82159687Snetchild void (*emldma)(struct sc_chinfo *); 83159687Snetchild 84159687Snetchild /* flags */ 85159687Snetchild int run; 86159687Snetchild}; 87159687Snetchild 88159687Snetchild/* codec interface entrys */ 89159687Snetchildstruct codec_entry { 90159687Snetchild void *(*create)(device_t dev, void *devinfo, int dir, int num); 91159687Snetchild void (*destroy)(void *codec); 92159687Snetchild void (*init)(void *codec); 93159687Snetchild void (*reinit)(void *codec); 94159687Snetchild void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right); 95159687Snetchild void (*setrate)(void *codec, int which, int rate); 96159687Snetchild}; 97159687Snetchild 98159687Snetchild/* system configuration information */ 99159687Snetchildstruct cfg_info { 100159687Snetchild char *name; 101159687Snetchild u_int16_t subvendor, subdevice; 102159687Snetchild u_int8_t scfg, acl, i2s, spdif; 103159687Snetchild u_int8_t gpiomask, gpiostate, gpiodir; 104159689Snetchild u_int8_t cdti, cclk, cs, cif, type; 105159687Snetchild u_int8_t free; 106159687Snetchild struct codec_entry *codec; 107159687Snetchild}; 108159687Snetchild 109159687Snetchild/* device private data */ 110159687Snetchildstruct sc_info { 111159687Snetchild device_t dev; 112166713Sariff struct mtx *lock; 113159687Snetchild 114159687Snetchild /* Control/Status registor */ 115159687Snetchild struct resource *cs; 116159687Snetchild int csid; 117159687Snetchild bus_space_tag_t cst; 118159687Snetchild bus_space_handle_t csh; 119159687Snetchild /* DDMA registor */ 120159687Snetchild struct resource *ddma; 121159687Snetchild int ddmaid; 122159687Snetchild bus_space_tag_t ddmat; 123159687Snetchild bus_space_handle_t ddmah; 124159687Snetchild /* Consumer Section DMA Channel Registers */ 125159687Snetchild struct resource *ds; 126159687Snetchild int dsid; 127159687Snetchild bus_space_tag_t dst; 128159687Snetchild bus_space_handle_t dsh; 129159687Snetchild /* MultiTrack registor */ 130159687Snetchild struct resource *mt; 131159687Snetchild int mtid; 132159687Snetchild bus_space_tag_t mtt; 133159687Snetchild bus_space_handle_t mth; 134159687Snetchild /* DMA tag */ 135159687Snetchild bus_dma_tag_t dmat; 136159687Snetchild /* IRQ resource */ 137159687Snetchild struct resource *irq; 138159687Snetchild int irqid; 139159687Snetchild void *ih; 140159687Snetchild 141159687Snetchild /* system configuration data */ 142159687Snetchild struct cfg_info *cfg; 143159687Snetchild 144159687Snetchild /* ADC/DAC number and info */ 145159687Snetchild int adcn, dacn; 146159687Snetchild void *adc[4], *dac[4]; 147159687Snetchild 148159687Snetchild /* mixer control data */ 149159687Snetchild u_int32_t src; 150159687Snetchild u_int8_t left[ENVY24_CHAN_NUM]; 151159687Snetchild u_int8_t right[ENVY24_CHAN_NUM]; 152159687Snetchild 153159687Snetchild /* Play/Record DMA fifo */ 154159687Snetchild sample32_t *pbuf; 155159687Snetchild sample32_t *rbuf; 156159687Snetchild u_int32_t psize, rsize; /* DMA buffer size(byte) */ 157159687Snetchild u_int16_t blk[2]; /* transfer check blocksize(dword) */ 158159687Snetchild bus_dmamap_t pmap, rmap; 159159687Snetchild 160159687Snetchild /* current status */ 161159687Snetchild u_int32_t speed; 162159687Snetchild int run[2]; 163159687Snetchild u_int16_t intr[2]; 164159687Snetchild struct pcmchan_caps caps[2]; 165159687Snetchild 166159687Snetchild /* channel info table */ 167159687Snetchild unsigned chnum; 168159687Snetchild struct sc_chinfo chan[11]; 169159687Snetchild}; 170159687Snetchild 171159687Snetchild/* -------------------------------------------------------------------- */ 172159687Snetchild 173159687Snetchild/* 174159687Snetchild * prototypes 175159687Snetchild */ 176159687Snetchild 177159687Snetchild/* DMA emulator */ 178159687Snetchildstatic void envy24_p8u(struct sc_chinfo *); 179159687Snetchildstatic void envy24_p16sl(struct sc_chinfo *); 180159687Snetchildstatic void envy24_p32sl(struct sc_chinfo *); 181159687Snetchildstatic void envy24_r16sl(struct sc_chinfo *); 182159687Snetchildstatic void envy24_r32sl(struct sc_chinfo *); 183159687Snetchild 184159687Snetchild/* channel interface */ 185159687Snetchildstatic void *envy24chan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int); 186159687Snetchildstatic int envy24chan_setformat(kobj_t, void *, u_int32_t); 187159687Snetchildstatic int envy24chan_setspeed(kobj_t, void *, u_int32_t); 188159687Snetchildstatic int envy24chan_setblocksize(kobj_t, void *, u_int32_t); 189159687Snetchildstatic int envy24chan_trigger(kobj_t, void *, int); 190159687Snetchildstatic int envy24chan_getptr(kobj_t, void *); 191159687Snetchildstatic struct pcmchan_caps *envy24chan_getcaps(kobj_t, void *); 192159687Snetchild 193159687Snetchild/* mixer interface */ 194159687Snetchildstatic int envy24mixer_init(struct snd_mixer *); 195159687Snetchildstatic int envy24mixer_reinit(struct snd_mixer *); 196159687Snetchildstatic int envy24mixer_uninit(struct snd_mixer *); 197159687Snetchildstatic int envy24mixer_set(struct snd_mixer *, unsigned, unsigned, unsigned); 198159687Snetchildstatic u_int32_t envy24mixer_setrecsrc(struct snd_mixer *, u_int32_t); 199159687Snetchild 200159687Snetchild/* M-Audio Delta series AK4524 access interface */ 201159687Snetchildstatic void *envy24_delta_ak4524_create(device_t, void *, int, int); 202159687Snetchildstatic void envy24_delta_ak4524_destroy(void *); 203159687Snetchildstatic void envy24_delta_ak4524_init(void *); 204159687Snetchildstatic void envy24_delta_ak4524_reinit(void *); 205159687Snetchildstatic void envy24_delta_ak4524_setvolume(void *, int, unsigned int, unsigned int); 206159687Snetchild 207159687Snetchild/* -------------------------------------------------------------------- */ 208159687Snetchild 209159687Snetchild/* 210159687Snetchild system constant tables 211159687Snetchild*/ 212159687Snetchild 213159687Snetchild/* API -> hardware channel map */ 214159687Snetchildstatic unsigned envy24_chanmap[ENVY24_CHAN_NUM] = { 215159687Snetchild ENVY24_CHAN_PLAY_SPDIF, /* 0 */ 216159687Snetchild ENVY24_CHAN_PLAY_DAC1, /* 1 */ 217159687Snetchild ENVY24_CHAN_PLAY_DAC2, /* 2 */ 218159687Snetchild ENVY24_CHAN_PLAY_DAC3, /* 3 */ 219159687Snetchild ENVY24_CHAN_PLAY_DAC4, /* 4 */ 220159687Snetchild ENVY24_CHAN_REC_MIX, /* 5 */ 221159687Snetchild ENVY24_CHAN_REC_SPDIF, /* 6 */ 222159687Snetchild ENVY24_CHAN_REC_ADC1, /* 7 */ 223159687Snetchild ENVY24_CHAN_REC_ADC2, /* 8 */ 224159687Snetchild ENVY24_CHAN_REC_ADC3, /* 9 */ 225159687Snetchild ENVY24_CHAN_REC_ADC4, /* 10 */ 226159687Snetchild}; 227159687Snetchild 228159687Snetchild/* mixer -> API channel map. see above */ 229159687Snetchildstatic int envy24_mixmap[] = { 230159687Snetchild -1, /* Master output level. It is depend on codec support */ 231159687Snetchild -1, /* Treble level of all output channels */ 232159687Snetchild -1, /* Bass level of all output channels */ 233159687Snetchild -1, /* Volume of synthesier input */ 234159687Snetchild 0, /* Output level for the audio device */ 235159687Snetchild -1, /* Output level for the PC speaker */ 236159687Snetchild 7, /* line in jack */ 237159687Snetchild -1, /* microphone jack */ 238159687Snetchild -1, /* CD audio input */ 239159687Snetchild -1, /* Recording monitor */ 240159687Snetchild 1, /* alternative codec */ 241159687Snetchild -1, /* global recording level */ 242159687Snetchild -1, /* Input gain */ 243159687Snetchild -1, /* Output gain */ 244159687Snetchild 8, /* Input source 1 */ 245159687Snetchild 9, /* Input source 2 */ 246159687Snetchild 10, /* Input source 3 */ 247159687Snetchild 6, /* Digital (input) 1 */ 248159687Snetchild -1, /* Digital (input) 2 */ 249159687Snetchild -1, /* Digital (input) 3 */ 250159687Snetchild -1, /* Phone input */ 251159687Snetchild -1, /* Phone output */ 252159687Snetchild -1, /* Video/TV (audio) in */ 253159687Snetchild -1, /* Radio in */ 254159687Snetchild -1, /* Monitor volume */ 255159687Snetchild}; 256159687Snetchild 257159687Snetchild/* variable rate audio */ 258159687Snetchildstatic u_int32_t envy24_speed[] = { 259159687Snetchild 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 260159687Snetchild 12000, 11025, 9600, 8000, 0 261159687Snetchild}; 262159687Snetchild 263159687Snetchild/* known boards configuration */ 264159687Snetchildstatic struct codec_entry delta_codec = { 265159687Snetchild envy24_delta_ak4524_create, 266159687Snetchild envy24_delta_ak4524_destroy, 267159687Snetchild envy24_delta_ak4524_init, 268159687Snetchild envy24_delta_ak4524_reinit, 269159687Snetchild envy24_delta_ak4524_setvolume, 270159687Snetchild NULL, /* setrate */ 271159687Snetchild}; 272159687Snetchild 273159687Snetchildstatic struct cfg_info cfg_table[] = { 274159687Snetchild { 275159689Snetchild "Envy24 audio (M Audio Delta Dio 2496)", 276159687Snetchild 0x1412, 0xd631, 277159687Snetchild 0x10, 0x80, 0xf0, 0x03, 278159687Snetchild 0xff, 0x00, 0x00, 279159689Snetchild 0x10, 0x20, 0x40, 0x00, 0x00, 280159689Snetchild 0x00, 281159687Snetchild &delta_codec, 282159687Snetchild }, 283159687Snetchild { 284159689Snetchild "Envy24 audio (Terratec DMX 6fire)", 285159689Snetchild 0x153b, 0x1138, 286159689Snetchild 0x2f, 0x80, 0xf0, 0x03, 287159689Snetchild 0xc0, 0xff, 0x7f, 288159689Snetchild 0x10, 0x20, 0x01, 0x01, 0x00, 289159689Snetchild 0x00, 290159689Snetchild &delta_codec, 291159689Snetchild }, 292159689Snetchild { 293159689Snetchild "Envy24 audio (M Audio Audiophile 2496)", 294159689Snetchild 0x1412, 0xd634, 295159689Snetchild 0x10, 0x80, 0x72, 0x03, 296159689Snetchild 0x04, 0xfe, 0xfb, 297159689Snetchild 0x08, 0x02, 0x20, 0x00, 0x01, 298159689Snetchild 0x00, 299159689Snetchild &delta_codec, 300159689Snetchild }, 301159689Snetchild { 302159689Snetchild "Envy24 audio (Generic)", 303159687Snetchild 0, 0, 304159687Snetchild 0x0f, 0x00, 0x01, 0x03, 305159687Snetchild 0xff, 0x00, 0x00, 306159689Snetchild 0x10, 0x20, 0x40, 0x00, 0x00, 307159689Snetchild 0x00, 308159687Snetchild &delta_codec, /* default codec routines */ 309159687Snetchild } 310159687Snetchild}; 311159687Snetchild 312159687Snetchildstatic u_int32_t envy24_recfmt[] = { 313159687Snetchild AFMT_STEREO | AFMT_S16_LE, 314159687Snetchild AFMT_STEREO | AFMT_S32_LE, 315159687Snetchild 0 316159687Snetchild}; 317159687Snetchildstatic struct pcmchan_caps envy24_reccaps = {8000, 96000, envy24_recfmt, 0}; 318159687Snetchild 319159687Snetchildstatic u_int32_t envy24_playfmt[] = { 320159687Snetchild AFMT_STEREO | AFMT_U8, 321159687Snetchild AFMT_STEREO | AFMT_S16_LE, 322159687Snetchild AFMT_STEREO | AFMT_S32_LE, 323159687Snetchild 0 324159687Snetchild}; 325159687Snetchild 326159687Snetchildstatic struct pcmchan_caps envy24_playcaps = {8000, 96000, envy24_playfmt, 0}; 327159687Snetchild 328159687Snetchildstruct envy24_emldma { 329159687Snetchild u_int32_t format; 330159687Snetchild void (*emldma)(struct sc_chinfo *); 331159687Snetchild int unit; 332159687Snetchild}; 333159687Snetchild 334159687Snetchildstatic struct envy24_emldma envy24_pemltab[] = { 335159687Snetchild {AFMT_STEREO | AFMT_U8, envy24_p8u, 2}, 336159687Snetchild {AFMT_STEREO | AFMT_S16_LE, envy24_p16sl, 4}, 337159687Snetchild {AFMT_STEREO | AFMT_S32_LE, envy24_p32sl, 8}, 338159687Snetchild {0, NULL, 0} 339159687Snetchild}; 340159687Snetchild 341159687Snetchildstatic struct envy24_emldma envy24_remltab[] = { 342159687Snetchild {AFMT_STEREO | AFMT_S16_LE, envy24_r16sl, 4}, 343159687Snetchild {AFMT_STEREO | AFMT_S32_LE, envy24_r32sl, 8}, 344159687Snetchild {0, NULL, 0} 345159687Snetchild}; 346159687Snetchild 347159687Snetchild/* -------------------------------------------------------------------- */ 348159687Snetchild 349159687Snetchild/* common routines */ 350159687Snetchildstatic u_int32_t 351159687Snetchildenvy24_rdcs(struct sc_info *sc, int regno, int size) 352159687Snetchild{ 353159687Snetchild switch (size) { 354159687Snetchild case 1: 355159687Snetchild return bus_space_read_1(sc->cst, sc->csh, regno); 356159687Snetchild case 2: 357159687Snetchild return bus_space_read_2(sc->cst, sc->csh, regno); 358159687Snetchild case 4: 359159687Snetchild return bus_space_read_4(sc->cst, sc->csh, regno); 360159687Snetchild default: 361159687Snetchild return 0xffffffff; 362159687Snetchild } 363159687Snetchild} 364159687Snetchild 365159687Snetchildstatic void 366159687Snetchildenvy24_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size) 367159687Snetchild{ 368159687Snetchild switch (size) { 369159687Snetchild case 1: 370159687Snetchild bus_space_write_1(sc->cst, sc->csh, regno, data); 371159687Snetchild break; 372159687Snetchild case 2: 373159687Snetchild bus_space_write_2(sc->cst, sc->csh, regno, data); 374159687Snetchild break; 375159687Snetchild case 4: 376159687Snetchild bus_space_write_4(sc->cst, sc->csh, regno, data); 377159687Snetchild break; 378159687Snetchild } 379159687Snetchild} 380159687Snetchild 381159687Snetchildstatic u_int32_t 382159687Snetchildenvy24_rdmt(struct sc_info *sc, int regno, int size) 383159687Snetchild{ 384159687Snetchild switch (size) { 385159687Snetchild case 1: 386159687Snetchild return bus_space_read_1(sc->mtt, sc->mth, regno); 387159687Snetchild case 2: 388159687Snetchild return bus_space_read_2(sc->mtt, sc->mth, regno); 389159687Snetchild case 4: 390159687Snetchild return bus_space_read_4(sc->mtt, sc->mth, regno); 391159687Snetchild default: 392159687Snetchild return 0xffffffff; 393159687Snetchild } 394159687Snetchild} 395159687Snetchild 396159687Snetchildstatic void 397159687Snetchildenvy24_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size) 398159687Snetchild{ 399159687Snetchild switch (size) { 400159687Snetchild case 1: 401159687Snetchild bus_space_write_1(sc->mtt, sc->mth, regno, data); 402159687Snetchild break; 403159687Snetchild case 2: 404159687Snetchild bus_space_write_2(sc->mtt, sc->mth, regno, data); 405159687Snetchild break; 406159687Snetchild case 4: 407159687Snetchild bus_space_write_4(sc->mtt, sc->mth, regno, data); 408159687Snetchild break; 409159687Snetchild } 410159687Snetchild} 411159687Snetchild 412159687Snetchildstatic u_int32_t 413159687Snetchildenvy24_rdci(struct sc_info *sc, int regno) 414159687Snetchild{ 415159687Snetchild envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1); 416159687Snetchild return envy24_rdcs(sc, ENVY24_CCS_DATA, 1); 417159687Snetchild} 418159687Snetchild 419159687Snetchildstatic void 420159687Snetchildenvy24_wrci(struct sc_info *sc, int regno, u_int32_t data) 421159687Snetchild{ 422159687Snetchild envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1); 423159687Snetchild envy24_wrcs(sc, ENVY24_CCS_DATA, data, 1); 424159687Snetchild} 425159687Snetchild 426159687Snetchild/* -------------------------------------------------------------------- */ 427159687Snetchild 428159687Snetchild/* I2C port/E2PROM access routines */ 429159687Snetchild 430159687Snetchildstatic int 431159687Snetchildenvy24_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr) 432159687Snetchild{ 433159687Snetchild u_int32_t data; 434159687Snetchild int i; 435159687Snetchild 436159687Snetchild#if(0) 437159687Snetchild device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr); 438159687Snetchild#endif 439159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 440159687Snetchild data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 441159687Snetchild if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0) 442159687Snetchild break; 443159687Snetchild DELAY(32); /* 31.25kHz */ 444159687Snetchild } 445159687Snetchild if (i == ENVY24_TIMEOUT) { 446159687Snetchild return -1; 447159687Snetchild } 448159687Snetchild envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1); 449159687Snetchild envy24_wrcs(sc, ENVY24_CCS_I2CDEV, 450159687Snetchild (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_RD, 1); 451159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 452159687Snetchild data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 453159687Snetchild if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0) 454159687Snetchild break; 455159687Snetchild DELAY(32); /* 31.25kHz */ 456159687Snetchild } 457159687Snetchild if (i == ENVY24_TIMEOUT) { 458159687Snetchild return -1; 459159687Snetchild } 460159687Snetchild data = envy24_rdcs(sc, ENVY24_CCS_I2CDATA, 1); 461159687Snetchild 462159687Snetchild#if(0) 463159687Snetchild device_printf(sc->dev, "envy24_rdi2c(): return 0x%x\n", data); 464159687Snetchild#endif 465159687Snetchild return (int)data; 466159687Snetchild} 467159687Snetchild 468159689Snetchild#if 0 469159687Snetchildstatic int 470159687Snetchildenvy24_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data) 471159687Snetchild{ 472159687Snetchild u_int32_t tmp; 473159687Snetchild int i; 474159687Snetchild 475159687Snetchild#if(0) 476159687Snetchild device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr); 477159687Snetchild#endif 478159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 479159687Snetchild tmp = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 480159687Snetchild if ((tmp & ENVY24_CCS_I2CSTAT_BSY) == 0) 481159687Snetchild break; 482159687Snetchild DELAY(32); /* 31.25kHz */ 483159687Snetchild } 484159687Snetchild if (i == ENVY24_TIMEOUT) { 485159687Snetchild return -1; 486159687Snetchild } 487159687Snetchild envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1); 488159687Snetchild envy24_wrcs(sc, ENVY24_CCS_I2CDATA, data, 1); 489159687Snetchild envy24_wrcs(sc, ENVY24_CCS_I2CDEV, 490159687Snetchild (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_WR, 1); 491159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 492159687Snetchild data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 493159687Snetchild if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0) 494159687Snetchild break; 495159687Snetchild DELAY(32); /* 31.25kHz */ 496159687Snetchild } 497159687Snetchild if (i == ENVY24_TIMEOUT) { 498159687Snetchild return -1; 499159687Snetchild } 500159687Snetchild 501159687Snetchild return 0; 502159687Snetchild} 503159689Snetchild#endif 504159687Snetchild 505159687Snetchildstatic int 506159687Snetchildenvy24_rdrom(struct sc_info *sc, u_int32_t addr) 507159687Snetchild{ 508159687Snetchild u_int32_t data; 509159687Snetchild 510159687Snetchild#if(0) 511159687Snetchild device_printf(sc->dev, "envy24_rdrom(sc, 0x%02x)\n", addr); 512159687Snetchild#endif 513159687Snetchild data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 514159687Snetchild if ((data & ENVY24_CCS_I2CSTAT_ROM) == 0) { 515159687Snetchild#if(0) 516159687Snetchild device_printf(sc->dev, "envy24_rdrom(): E2PROM not presented\n"); 517159687Snetchild#endif 518159687Snetchild return -1; 519159687Snetchild } 520159687Snetchild 521159687Snetchild return envy24_rdi2c(sc, ENVY24_CCS_I2CDEV_ROM, addr); 522159687Snetchild} 523159687Snetchild 524159687Snetchildstatic struct cfg_info * 525159687Snetchildenvy24_rom2cfg(struct sc_info *sc) 526159687Snetchild{ 527159687Snetchild struct cfg_info *buff; 528159687Snetchild int size; 529159687Snetchild int i; 530159687Snetchild 531159687Snetchild#if(0) 532159687Snetchild device_printf(sc->dev, "envy24_rom2cfg(sc)\n"); 533159687Snetchild#endif 534159687Snetchild size = envy24_rdrom(sc, ENVY24_E2PROM_SIZE); 535159687Snetchild if (size < ENVY24_E2PROM_GPIODIR + 1) { 536159687Snetchild#if(0) 537159687Snetchild device_printf(sc->dev, "envy24_rom2cfg(): ENVY24_E2PROM_SIZE-->%d\n", size); 538159687Snetchild#endif 539159687Snetchild return NULL; 540159687Snetchild } 541159687Snetchild buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT); 542159687Snetchild if (buff == NULL) { 543159687Snetchild#if(0) 544159687Snetchild device_printf(sc->dev, "envy24_rom2cfg(): malloc()\n"); 545159687Snetchild#endif 546159687Snetchild return NULL; 547159687Snetchild } 548159687Snetchild buff->free = 1; 549159687Snetchild 550159687Snetchild buff->subvendor = envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR) << 8; 551159687Snetchild buff->subvendor += envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR + 1); 552159687Snetchild buff->subdevice = envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE) << 8; 553159687Snetchild buff->subdevice += envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE + 1); 554159687Snetchild buff->scfg = envy24_rdrom(sc, ENVY24_E2PROM_SCFG); 555159687Snetchild buff->acl = envy24_rdrom(sc, ENVY24_E2PROM_ACL); 556159687Snetchild buff->i2s = envy24_rdrom(sc, ENVY24_E2PROM_I2S); 557159687Snetchild buff->spdif = envy24_rdrom(sc, ENVY24_E2PROM_SPDIF); 558159687Snetchild buff->gpiomask = envy24_rdrom(sc, ENVY24_E2PROM_GPIOMASK); 559159687Snetchild buff->gpiostate = envy24_rdrom(sc, ENVY24_E2PROM_GPIOSTATE); 560159687Snetchild buff->gpiodir = envy24_rdrom(sc, ENVY24_E2PROM_GPIODIR); 561159687Snetchild 562159687Snetchild for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) 563159687Snetchild if (cfg_table[i].subvendor == buff->subvendor && 564159687Snetchild cfg_table[i].subdevice == buff->subdevice) 565159687Snetchild break; 566159687Snetchild buff->name = cfg_table[i].name; 567159687Snetchild buff->codec = cfg_table[i].codec; 568159687Snetchild 569159687Snetchild return buff; 570159687Snetchild} 571159687Snetchild 572159687Snetchildstatic void 573159687Snetchildenvy24_cfgfree(struct cfg_info *cfg) { 574159687Snetchild if (cfg == NULL) 575159687Snetchild return; 576159687Snetchild if (cfg->free) 577159687Snetchild free(cfg, M_ENVY24); 578159687Snetchild return; 579159687Snetchild} 580159687Snetchild 581159687Snetchild/* -------------------------------------------------------------------- */ 582159687Snetchild 583159687Snetchild/* AC'97 codec access routines */ 584159687Snetchild 585159689Snetchild#if 0 586159687Snetchildstatic int 587159687Snetchildenvy24_coldcd(struct sc_info *sc) 588159687Snetchild{ 589159687Snetchild u_int32_t data; 590159687Snetchild int i; 591159687Snetchild 592159687Snetchild#if(0) 593159687Snetchild device_printf(sc->dev, "envy24_coldcd()\n"); 594159687Snetchild#endif 595159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_CLD, 1); 596159687Snetchild DELAY(10); 597159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1); 598159687Snetchild DELAY(1000); 599159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 600159687Snetchild data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1); 601159687Snetchild if (data & ENVY24_MT_AC97CMD_RDY) { 602159687Snetchild return 0; 603159687Snetchild } 604159687Snetchild } 605159687Snetchild 606159687Snetchild return -1; 607159687Snetchild} 608159689Snetchild#endif 609159687Snetchild 610159687Snetchildstatic int 611159687Snetchildenvy24_slavecd(struct sc_info *sc) 612159687Snetchild{ 613159687Snetchild u_int32_t data; 614159687Snetchild int i; 615159687Snetchild 616159687Snetchild#if(0) 617159687Snetchild device_printf(sc->dev, "envy24_slavecd()\n"); 618159687Snetchild#endif 619159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97CMD, 620159687Snetchild ENVY24_MT_AC97CMD_CLD | ENVY24_MT_AC97CMD_WRM, 1); 621159687Snetchild DELAY(10); 622159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1); 623159687Snetchild DELAY(1000); 624159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 625159687Snetchild data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1); 626159687Snetchild if (data & ENVY24_MT_AC97CMD_RDY) { 627159687Snetchild return 0; 628159687Snetchild } 629159687Snetchild } 630159687Snetchild 631159687Snetchild return -1; 632159687Snetchild} 633159687Snetchild 634159689Snetchild#if 0 635159687Snetchildstatic int 636159687Snetchildenvy24_rdcd(kobj_t obj, void *devinfo, int regno) 637159687Snetchild{ 638159687Snetchild struct sc_info *sc = (struct sc_info *)devinfo; 639159687Snetchild u_int32_t data; 640159687Snetchild int i; 641159687Snetchild 642159687Snetchild#if(0) 643159687Snetchild device_printf(sc->dev, "envy24_rdcd(obj, sc, 0x%02x)\n", regno); 644159687Snetchild#endif 645159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1); 646159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_RD, 1); 647159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 648159687Snetchild data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1); 649159687Snetchild if ((data & ENVY24_MT_AC97CMD_RD) == 0) 650159687Snetchild break; 651159687Snetchild } 652159687Snetchild data = envy24_rdmt(sc, ENVY24_MT_AC97DLO, 2); 653159687Snetchild 654159687Snetchild#if(0) 655159687Snetchild device_printf(sc->dev, "envy24_rdcd(): return 0x%x\n", data); 656159687Snetchild#endif 657159687Snetchild return (int)data; 658159687Snetchild} 659159687Snetchild 660159687Snetchildstatic int 661159687Snetchildenvy24_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data) 662159687Snetchild{ 663159687Snetchild struct sc_info *sc = (struct sc_info *)devinfo; 664159687Snetchild u_int32_t cmd; 665159687Snetchild int i; 666159687Snetchild 667159687Snetchild#if(0) 668159687Snetchild device_printf(sc->dev, "envy24_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data); 669159687Snetchild#endif 670159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1); 671159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97DLO, (u_int32_t)data, 2); 672159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_WR, 1); 673159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 674159687Snetchild cmd = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1); 675159687Snetchild if ((cmd & ENVY24_MT_AC97CMD_WR) == 0) 676159687Snetchild break; 677159687Snetchild } 678159687Snetchild 679159687Snetchild return 0; 680159687Snetchild} 681159687Snetchild 682159687Snetchildstatic kobj_method_t envy24_ac97_methods[] = { 683159687Snetchild KOBJMETHOD(ac97_read, envy24_rdcd), 684159687Snetchild KOBJMETHOD(ac97_write, envy24_wrcd), 685159687Snetchild {0, 0} 686159687Snetchild}; 687159687SnetchildAC97_DECLARE(envy24_ac97); 688159689Snetchild#endif 689159687Snetchild 690159687Snetchild/* -------------------------------------------------------------------- */ 691159687Snetchild 692159687Snetchild/* GPIO access routines */ 693159687Snetchild 694159687Snetchildstatic u_int32_t 695159687Snetchildenvy24_gpiord(struct sc_info *sc) 696159687Snetchild{ 697159687Snetchild return envy24_rdci(sc, ENVY24_CCI_GPIODAT); 698159687Snetchild} 699159687Snetchild 700159687Snetchildstatic void 701159687Snetchildenvy24_gpiowr(struct sc_info *sc, u_int32_t data) 702159687Snetchild{ 703159687Snetchild#if(0) 704159687Snetchild device_printf(sc->dev, "envy24_gpiowr(sc, 0x%02x)\n", data & 0xff); 705159687Snetchild return; 706159687Snetchild#endif 707159687Snetchild envy24_wrci(sc, ENVY24_CCI_GPIODAT, data); 708159687Snetchild return; 709159687Snetchild} 710159687Snetchild 711159689Snetchild#if 0 712159687Snetchildstatic u_int32_t 713159687Snetchildenvy24_gpiogetmask(struct sc_info *sc) 714159687Snetchild{ 715159687Snetchild return envy24_rdci(sc, ENVY24_CCI_GPIOMASK); 716159687Snetchild} 717159689Snetchild#endif 718159687Snetchild 719159687Snetchildstatic void 720159687Snetchildenvy24_gpiosetmask(struct sc_info *sc, u_int32_t mask) 721159687Snetchild{ 722159687Snetchild envy24_wrci(sc, ENVY24_CCI_GPIOMASK, mask); 723159687Snetchild return; 724159687Snetchild} 725159687Snetchild 726159689Snetchild#if 0 727159687Snetchildstatic u_int32_t 728159687Snetchildenvy24_gpiogetdir(struct sc_info *sc) 729159687Snetchild{ 730159687Snetchild return envy24_rdci(sc, ENVY24_CCI_GPIOCTL); 731159687Snetchild} 732159689Snetchild#endif 733159687Snetchild 734159687Snetchildstatic void 735159687Snetchildenvy24_gpiosetdir(struct sc_info *sc, u_int32_t dir) 736159687Snetchild{ 737159687Snetchild envy24_wrci(sc, ENVY24_CCI_GPIOCTL, dir); 738159687Snetchild return; 739159687Snetchild} 740159687Snetchild 741159687Snetchild/* -------------------------------------------------------------------- */ 742159687Snetchild 743159687Snetchild/* M-Audio Delta series AK4524 access interface routine */ 744159687Snetchild 745159687Snetchildstruct envy24_delta_ak4524_codec { 746162876Snetchild struct spicds_info *info; 747159687Snetchild struct sc_info *parent; 748159687Snetchild int dir; 749159687Snetchild int num; 750159687Snetchild int cs, cclk, cdti; 751159687Snetchild}; 752159687Snetchild 753159687Snetchildstatic void 754159687Snetchildenvy24_delta_ak4524_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti) 755159687Snetchild{ 756159687Snetchild u_int32_t data = 0; 757159687Snetchild struct envy24_delta_ak4524_codec *ptr = codec; 758159687Snetchild 759159687Snetchild#if(0) 760159687Snetchild device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti); 761159687Snetchild#endif 762159687Snetchild data = envy24_gpiord(ptr->parent); 763159687Snetchild data &= ~(ptr->cs | ptr->cclk | ptr->cdti); 764159687Snetchild if (cs) data += ptr->cs; 765159687Snetchild if (cclk) data += ptr->cclk; 766159687Snetchild if (cdti) data += ptr->cdti; 767159687Snetchild envy24_gpiowr(ptr->parent, data); 768159687Snetchild return; 769159687Snetchild} 770159687Snetchild 771159687Snetchildstatic void * 772159687Snetchildenvy24_delta_ak4524_create(device_t dev, void *info, int dir, int num) 773159687Snetchild{ 774159687Snetchild struct sc_info *sc = info; 775159687Snetchild struct envy24_delta_ak4524_codec *buff = NULL; 776159687Snetchild 777159687Snetchild#if(0) 778159687Snetchild device_printf(sc->dev, "envy24_delta_ak4524_create(dev, sc, %d, %d)\n", dir, num); 779159687Snetchild#endif 780159687Snetchild 781159687Snetchild buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT); 782159687Snetchild if (buff == NULL) 783159687Snetchild return NULL; 784159687Snetchild 785160796Snetchild if (dir == PCMDIR_REC && sc->adc[num] != NULL) 786159687Snetchild buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info; 787160796Snetchild else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL) 788159687Snetchild buff->info = ((struct envy24_delta_ak4524_codec *)sc->dac[num])->info; 789159687Snetchild else 790162876Snetchild buff->info = spicds_create(dev, buff, num, envy24_delta_ak4524_ctl); 791159687Snetchild if (buff->info == NULL) { 792159687Snetchild free(buff, M_ENVY24); 793159687Snetchild return NULL; 794159687Snetchild } 795159687Snetchild 796159687Snetchild buff->parent = sc; 797159687Snetchild buff->dir = dir; 798159687Snetchild buff->num = num; 799159687Snetchild 800159687Snetchild return (void *)buff; 801159687Snetchild} 802159687Snetchild 803159687Snetchildstatic void 804159687Snetchildenvy24_delta_ak4524_destroy(void *codec) 805159687Snetchild{ 806159687Snetchild struct envy24_delta_ak4524_codec *ptr = codec; 807159687Snetchild if (ptr == NULL) 808159687Snetchild return; 809159687Snetchild#if(0) 810159687Snetchild device_printf(ptr->parent->dev, "envy24_delta_ak4524_destroy()\n"); 811159687Snetchild#endif 812159687Snetchild 813159687Snetchild if (ptr->dir == PCMDIR_PLAY) { 814162876Snetchild if (ptr->parent->dac[ptr->num] != NULL) 815162876Snetchild spicds_destroy(ptr->info); 816159687Snetchild } 817159687Snetchild else { 818162876Snetchild if (ptr->parent->adc[ptr->num] != NULL) 819162876Snetchild spicds_destroy(ptr->info); 820159687Snetchild } 821159687Snetchild 822159687Snetchild free(codec, M_ENVY24); 823159687Snetchild} 824159687Snetchild 825159687Snetchildstatic void 826159687Snetchildenvy24_delta_ak4524_init(void *codec) 827159687Snetchild{ 828159689Snetchild#if 0 829159687Snetchild u_int32_t gpiomask, gpiodir; 830159689Snetchild#endif 831159687Snetchild struct envy24_delta_ak4524_codec *ptr = codec; 832159687Snetchild if (ptr == NULL) 833159687Snetchild return; 834159687Snetchild#if(0) 835159687Snetchild device_printf(ptr->parent->dev, "envy24_delta_ak4524_init()\n"); 836159687Snetchild#endif 837159687Snetchild 838159687Snetchild /* 839159687Snetchild gpiomask = envy24_gpiogetmask(ptr->parent); 840159687Snetchild gpiomask &= ~(ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1); 841159687Snetchild envy24_gpiosetmask(ptr->parent, gpiomask); 842159687Snetchild gpiodir = envy24_gpiogetdir(ptr->parent); 843159687Snetchild gpiodir |= ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1; 844159687Snetchild envy24_gpiosetdir(ptr->parent, gpiodir); 845159687Snetchild */ 846159689Snetchild ptr->cs = ptr->parent->cfg->cs; 847159689Snetchild#if 0 848159687Snetchild envy24_gpiosetmask(ptr->parent, ENVY24_GPIO_CS8414_STATUS); 849159687Snetchild envy24_gpiosetdir(ptr->parent, ~ENVY24_GPIO_CS8414_STATUS); 850159687Snetchild if (ptr->num == 0) 851159687Snetchild ptr->cs = ENVY24_GPIO_AK4524_CS0; 852159687Snetchild else 853159687Snetchild ptr->cs = ENVY24_GPIO_AK4524_CS1; 854159687Snetchild ptr->cclk = ENVY24_GPIO_AK4524_CCLK; 855159689Snetchild#endif 856159689Snetchild ptr->cclk = ptr->parent->cfg->cclk; 857159689Snetchild ptr->cdti = ptr->parent->cfg->cdti; 858162876Snetchild spicds_settype(ptr->info, ptr->parent->cfg->type); 859162876Snetchild spicds_setcif(ptr->info, ptr->parent->cfg->cif); 860162876Snetchild spicds_setformat(ptr->info, 861159687Snetchild AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X); 862162876Snetchild spicds_setdvc(ptr->info, 0); 863162876Snetchild /* for the time being, init only first codec */ 864162876Snetchild if (ptr->num == 0) 865162876Snetchild spicds_init(ptr->info); 866159687Snetchild} 867159687Snetchild 868159687Snetchildstatic void 869159687Snetchildenvy24_delta_ak4524_reinit(void *codec) 870159687Snetchild{ 871159687Snetchild struct envy24_delta_ak4524_codec *ptr = codec; 872159687Snetchild if (ptr == NULL) 873159687Snetchild return; 874159687Snetchild#if(0) 875159687Snetchild device_printf(ptr->parent->dev, "envy24_delta_ak4524_reinit()\n"); 876159687Snetchild#endif 877159687Snetchild 878162876Snetchild spicds_reinit(ptr->info); 879159687Snetchild} 880159687Snetchild 881159687Snetchildstatic void 882159687Snetchildenvy24_delta_ak4524_setvolume(void *codec, int dir, unsigned int left, unsigned int right) 883159687Snetchild{ 884159687Snetchild struct envy24_delta_ak4524_codec *ptr = codec; 885159687Snetchild if (ptr == NULL) 886159687Snetchild return; 887159687Snetchild#if(0) 888159687Snetchild device_printf(ptr->parent->dev, "envy24_delta_ak4524_set()\n"); 889159687Snetchild#endif 890159687Snetchild 891162876Snetchild spicds_set(ptr->info, dir, left, right); 892159687Snetchild} 893159687Snetchild 894159687Snetchild/* 895159687Snetchild There is no need for AK452[48] codec to set sample rate 896159687Snetchild static void 897159687Snetchild envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate) 898159687Snetchild { 899159687Snetchild } 900159687Snetchild*/ 901159687Snetchild 902159687Snetchild/* -------------------------------------------------------------------- */ 903159687Snetchild 904159687Snetchild/* hardware access routeines */ 905159687Snetchild 906159687Snetchildstatic struct { 907159687Snetchild u_int32_t speed; 908159687Snetchild u_int32_t code; 909159687Snetchild} envy24_speedtab[] = { 910159687Snetchild {48000, ENVY24_MT_RATE_48000}, 911159687Snetchild {24000, ENVY24_MT_RATE_24000}, 912159687Snetchild {12000, ENVY24_MT_RATE_12000}, 913159687Snetchild {9600, ENVY24_MT_RATE_9600}, 914159687Snetchild {32000, ENVY24_MT_RATE_32000}, 915159687Snetchild {16000, ENVY24_MT_RATE_16000}, 916159687Snetchild {8000, ENVY24_MT_RATE_8000}, 917159687Snetchild {96000, ENVY24_MT_RATE_96000}, 918159687Snetchild {64000, ENVY24_MT_RATE_64000}, 919159687Snetchild {44100, ENVY24_MT_RATE_44100}, 920159687Snetchild {22050, ENVY24_MT_RATE_22050}, 921159687Snetchild {11025, ENVY24_MT_RATE_11025}, 922159687Snetchild {88200, ENVY24_MT_RATE_88200}, 923159687Snetchild {0, 0x10} 924159687Snetchild}; 925159687Snetchild 926159687Snetchildstatic int 927159687Snetchildenvy24_setspeed(struct sc_info *sc, u_int32_t speed) { 928159687Snetchild u_int32_t code; 929159687Snetchild int i = 0; 930159687Snetchild 931159687Snetchild#if(0) 932159687Snetchild device_printf(sc->dev, "envy24_setspeed(sc, %d)\n", speed); 933159687Snetchild#endif 934159687Snetchild if (speed == 0) { 935159687Snetchild code = ENVY24_MT_RATE_SPDIF; /* external master clock */ 936159687Snetchild envy24_slavecd(sc); 937159687Snetchild } 938159687Snetchild else { 939159687Snetchild for (i = 0; envy24_speedtab[i].speed != 0; i++) { 940159687Snetchild if (envy24_speedtab[i].speed == speed) 941159687Snetchild break; 942159687Snetchild } 943159687Snetchild code = envy24_speedtab[i].code; 944159687Snetchild } 945159687Snetchild#if(0) 946159687Snetchild device_printf(sc->dev, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab[i].speed, code); 947159687Snetchild#endif 948159687Snetchild if (code < 0x10) { 949159687Snetchild envy24_wrmt(sc, ENVY24_MT_RATE, code, 1); 950159687Snetchild code = envy24_rdmt(sc, ENVY24_MT_RATE, 1); 951159687Snetchild code &= ENVY24_MT_RATE_MASK; 952159687Snetchild for (i = 0; envy24_speedtab[i].code < 0x10; i++) { 953159687Snetchild if (envy24_speedtab[i].code == code) 954159687Snetchild break; 955159687Snetchild } 956159687Snetchild speed = envy24_speedtab[i].speed; 957159687Snetchild } 958159687Snetchild else 959159687Snetchild speed = 0; 960159687Snetchild 961159687Snetchild#if(0) 962159687Snetchild device_printf(sc->dev, "envy24_setspeed(): return %d\n", speed); 963159687Snetchild#endif 964159687Snetchild return speed; 965159687Snetchild} 966159687Snetchild 967159687Snetchildstatic void 968159687Snetchildenvy24_setvolume(struct sc_info *sc, unsigned ch) 969159687Snetchild{ 970159687Snetchild#if(0) 971159687Snetchild device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch); 972159687Snetchild#endif 973159689Snetchildif (sc->cfg->subvendor==0x153b && sc->cfg->subdevice==0x1138 ) { 974159689Snetchild envy24_wrmt(sc, ENVY24_MT_VOLIDX, 16, 1); 975159689Snetchild envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2); 976159689Snetchild envy24_wrmt(sc, ENVY24_MT_VOLIDX, 17, 1); 977159689Snetchild envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2); 978159689Snetchild } 979159689Snetchild 980159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1); 981159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f00 | sc->left[ch], 2); 982159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1); 983159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2); 984159687Snetchild} 985159687Snetchild 986159687Snetchildstatic void 987159687Snetchildenvy24_mutevolume(struct sc_info *sc, unsigned ch) 988159687Snetchild{ 989159687Snetchild u_int32_t vol; 990159687Snetchild 991159687Snetchild#if(0) 992159687Snetchild device_printf(sc->dev, "envy24_mutevolume(sc, %d)\n", ch); 993159687Snetchild#endif 994159687Snetchild vol = ENVY24_VOL_MUTE << 8 | ENVY24_VOL_MUTE; 995159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1); 996159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2); 997159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1); 998159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2); 999159687Snetchild} 1000159687Snetchild 1001159687Snetchildstatic u_int32_t 1002159687Snetchildenvy24_gethwptr(struct sc_info *sc, int dir) 1003159687Snetchild{ 1004159687Snetchild int unit, regno; 1005159687Snetchild u_int32_t ptr, rtn; 1006159687Snetchild 1007159687Snetchild#if(0) 1008159687Snetchild device_printf(sc->dev, "envy24_gethwptr(sc, %d)\n", dir); 1009159687Snetchild#endif 1010159687Snetchild if (dir == PCMDIR_PLAY) { 1011159687Snetchild rtn = sc->psize / 4; 1012159687Snetchild unit = ENVY24_PLAY_BUFUNIT / 4; 1013159687Snetchild regno = ENVY24_MT_PCNT; 1014159687Snetchild } 1015159687Snetchild else { 1016159687Snetchild rtn = sc->rsize / 4; 1017159687Snetchild unit = ENVY24_REC_BUFUNIT / 4; 1018159687Snetchild regno = ENVY24_MT_RCNT; 1019159687Snetchild } 1020159687Snetchild 1021159687Snetchild ptr = envy24_rdmt(sc, regno, 2); 1022159687Snetchild rtn -= (ptr + 1); 1023159687Snetchild rtn /= unit; 1024159687Snetchild 1025159687Snetchild#if(0) 1026159687Snetchild device_printf(sc->dev, "envy24_gethwptr(): return %d\n", rtn); 1027159687Snetchild#endif 1028159687Snetchild return rtn; 1029159687Snetchild} 1030159687Snetchild 1031159687Snetchildstatic void 1032159687Snetchildenvy24_updintr(struct sc_info *sc, int dir) 1033159687Snetchild{ 1034159687Snetchild int regptr, regintr; 1035159687Snetchild u_int32_t mask, intr; 1036159687Snetchild u_int32_t ptr, size, cnt; 1037159687Snetchild u_int16_t blk; 1038159687Snetchild 1039159687Snetchild#if(0) 1040159687Snetchild device_printf(sc->dev, "envy24_updintr(sc, %d)\n", dir); 1041159687Snetchild#endif 1042159687Snetchild if (dir == PCMDIR_PLAY) { 1043159687Snetchild blk = sc->blk[0]; 1044159687Snetchild size = sc->psize / 4; 1045159687Snetchild regptr = ENVY24_MT_PCNT; 1046159687Snetchild regintr = ENVY24_MT_PTERM; 1047159687Snetchild mask = ~ENVY24_MT_INT_PMASK; 1048159687Snetchild } 1049159687Snetchild else { 1050159687Snetchild blk = sc->blk[1]; 1051159687Snetchild size = sc->rsize / 4; 1052159687Snetchild regptr = ENVY24_MT_RCNT; 1053159687Snetchild regintr = ENVY24_MT_RTERM; 1054159687Snetchild mask = ~ENVY24_MT_INT_RMASK; 1055159687Snetchild } 1056159687Snetchild 1057159687Snetchild ptr = size - envy24_rdmt(sc, regptr, 2) - 1; 1058159687Snetchild /* 1059159687Snetchild cnt = blk - ptr % blk - 1; 1060159687Snetchild if (cnt == 0) 1061159687Snetchild cnt = blk - 1; 1062159687Snetchild */ 1063159687Snetchild cnt = blk - 1; 1064159687Snetchild#if(0) 1065159687Snetchild device_printf(sc->dev, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt); 1066159687Snetchild#endif 1067159687Snetchild envy24_wrmt(sc, regintr, cnt, 2); 1068159687Snetchild intr = envy24_rdmt(sc, ENVY24_MT_INT, 1); 1069159687Snetchild#if(0) 1070159687Snetchild device_printf(sc->dev, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask); 1071159687Snetchild#endif 1072159687Snetchild envy24_wrmt(sc, ENVY24_MT_INT, intr & mask, 1); 1073159687Snetchild#if(0) 1074159687Snetchild device_printf(sc->dev, "envy24_updintr():INT-->0x%02x\n", 1075159687Snetchild envy24_rdmt(sc, ENVY24_MT_INT, 1)); 1076159687Snetchild#endif 1077159687Snetchild 1078159687Snetchild return; 1079159687Snetchild} 1080159687Snetchild 1081159689Snetchild#if 0 1082159687Snetchildstatic void 1083159687Snetchildenvy24_maskintr(struct sc_info *sc, int dir) 1084159687Snetchild{ 1085159687Snetchild u_int32_t mask, intr; 1086159687Snetchild 1087159687Snetchild#if(0) 1088159687Snetchild device_printf(sc->dev, "envy24_maskintr(sc, %d)\n", dir); 1089159687Snetchild#endif 1090159687Snetchild if (dir == PCMDIR_PLAY) 1091159687Snetchild mask = ENVY24_MT_INT_PMASK; 1092159687Snetchild else 1093159687Snetchild mask = ENVY24_MT_INT_RMASK; 1094159687Snetchild intr = envy24_rdmt(sc, ENVY24_MT_INT, 1); 1095159687Snetchild envy24_wrmt(sc, ENVY24_MT_INT, intr | mask, 1); 1096159687Snetchild 1097159687Snetchild return; 1098159687Snetchild} 1099159689Snetchild#endif 1100159687Snetchild 1101159687Snetchildstatic int 1102159687Snetchildenvy24_checkintr(struct sc_info *sc, int dir) 1103159687Snetchild{ 1104159687Snetchild u_int32_t mask, stat, intr, rtn; 1105159687Snetchild 1106159687Snetchild#if(0) 1107159687Snetchild device_printf(sc->dev, "envy24_checkintr(sc, %d)\n", dir); 1108159687Snetchild#endif 1109159687Snetchild intr = envy24_rdmt(sc, ENVY24_MT_INT, 1); 1110159687Snetchild if (dir == PCMDIR_PLAY) { 1111159687Snetchild if ((rtn = intr & ENVY24_MT_INT_PSTAT) != 0) { 1112159687Snetchild mask = ~ENVY24_MT_INT_RSTAT; 1113159687Snetchild stat = ENVY24_MT_INT_PSTAT | ENVY24_MT_INT_PMASK; 1114159687Snetchild envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1); 1115159687Snetchild } 1116159687Snetchild } 1117159687Snetchild else { 1118159687Snetchild if ((rtn = intr & ENVY24_MT_INT_RSTAT) != 0) { 1119159687Snetchild mask = ~ENVY24_MT_INT_PSTAT; 1120159687Snetchild stat = ENVY24_MT_INT_RSTAT | ENVY24_MT_INT_RMASK; 1121159687Snetchild envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1); 1122159687Snetchild } 1123159687Snetchild } 1124159687Snetchild 1125159687Snetchild return rtn; 1126159687Snetchild} 1127159687Snetchild 1128159687Snetchildstatic void 1129159687Snetchildenvy24_start(struct sc_info *sc, int dir) 1130159687Snetchild{ 1131159687Snetchild u_int32_t stat, sw; 1132159687Snetchild 1133159687Snetchild#if(0) 1134159687Snetchild device_printf(sc->dev, "envy24_start(sc, %d)\n", dir); 1135159687Snetchild#endif 1136159687Snetchild if (dir == PCMDIR_PLAY) 1137159687Snetchild sw = ENVY24_MT_PCTL_PSTART; 1138159687Snetchild else 1139159687Snetchild sw = ENVY24_MT_PCTL_RSTART; 1140159687Snetchild 1141159687Snetchild stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1); 1142159687Snetchild envy24_wrmt(sc, ENVY24_MT_PCTL, stat | sw, 1); 1143159687Snetchild#if(0) 1144159687Snetchild DELAY(100); 1145159687Snetchild device_printf(sc->dev, "PADDR:0x%08x\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4)); 1146159687Snetchild device_printf(sc->dev, "PCNT:%ld\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2)); 1147159687Snetchild#endif 1148159687Snetchild 1149159687Snetchild return; 1150159687Snetchild} 1151159687Snetchild 1152159687Snetchildstatic void 1153159687Snetchildenvy24_stop(struct sc_info *sc, int dir) 1154159687Snetchild{ 1155159687Snetchild u_int32_t stat, sw; 1156159687Snetchild 1157159687Snetchild#if(0) 1158159687Snetchild device_printf(sc->dev, "envy24_stop(sc, %d)\n", dir); 1159159687Snetchild#endif 1160159687Snetchild if (dir == PCMDIR_PLAY) 1161159687Snetchild sw = ~ENVY24_MT_PCTL_PSTART; 1162159687Snetchild else 1163159687Snetchild sw = ~ENVY24_MT_PCTL_RSTART; 1164159687Snetchild 1165159687Snetchild stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1); 1166159687Snetchild envy24_wrmt(sc, ENVY24_MT_PCTL, stat & sw, 1); 1167159687Snetchild 1168159687Snetchild return; 1169159687Snetchild} 1170159687Snetchild 1171159687Snetchildstatic int 1172159687Snetchildenvy24_route(struct sc_info *sc, int dac, int class, int adc, int rev) 1173159687Snetchild{ 1174159687Snetchild u_int32_t reg, mask; 1175159687Snetchild u_int32_t left, right; 1176159687Snetchild 1177159687Snetchild#if(0) 1178159687Snetchild device_printf(sc->dev, "envy24_route(sc, %d, %d, %d, %d)\n", 1179159687Snetchild dac, class, adc, rev); 1180159687Snetchild#endif 1181159687Snetchild /* parameter pattern check */ 1182159687Snetchild if (dac < 0 || ENVY24_ROUTE_DAC_SPDIF < dac) 1183159687Snetchild return -1; 1184159687Snetchild if (class == ENVY24_ROUTE_CLASS_MIX && 1185159687Snetchild (dac != ENVY24_ROUTE_DAC_1 && dac != ENVY24_ROUTE_DAC_SPDIF)) 1186159687Snetchild return -1; 1187159687Snetchild if (rev) { 1188159687Snetchild left = ENVY24_ROUTE_RIGHT; 1189159687Snetchild right = ENVY24_ROUTE_LEFT; 1190159687Snetchild } 1191159687Snetchild else { 1192159687Snetchild left = ENVY24_ROUTE_LEFT; 1193159687Snetchild right = ENVY24_ROUTE_RIGHT; 1194159687Snetchild } 1195159687Snetchild 1196159687Snetchild if (dac == ENVY24_ROUTE_DAC_SPDIF) { 1197159687Snetchild reg = class | class << 2 | 1198159687Snetchild ((adc << 1 | left) | left << 3) << 8 | 1199159687Snetchild ((adc << 1 | right) | right << 3) << 12; 1200159687Snetchild#if(0) 1201159687Snetchild device_printf(sc->dev, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg); 1202159687Snetchild#endif 1203159687Snetchild envy24_wrmt(sc, ENVY24_MT_SPDOUT, reg, 2); 1204159687Snetchild } 1205159687Snetchild else { 1206159687Snetchild mask = ~(0x0303 << dac * 2); 1207159687Snetchild reg = envy24_rdmt(sc, ENVY24_MT_PSDOUT, 2); 1208159687Snetchild reg = (reg & mask) | ((class | class << 8) << dac * 2); 1209159687Snetchild#if(0) 1210159687Snetchild device_printf(sc->dev, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg); 1211159687Snetchild#endif 1212159687Snetchild envy24_wrmt(sc, ENVY24_MT_PSDOUT, reg, 2); 1213159687Snetchild mask = ~(0xff << dac * 8); 1214159687Snetchild reg = envy24_rdmt(sc, ENVY24_MT_RECORD, 4); 1215159687Snetchild reg = (reg & mask) | 1216159687Snetchild (((adc << 1 | left) | left << 3) | 1217159687Snetchild ((adc << 1 | right) | right << 3) << 4) << dac * 8; 1218159687Snetchild#if(0) 1219159687Snetchild device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg); 1220159687Snetchild#endif 1221159687Snetchild envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4); 1222159687Snetchild } 1223159687Snetchild 1224159687Snetchild return 0; 1225159687Snetchild} 1226159687Snetchild 1227159687Snetchild/* -------------------------------------------------------------------- */ 1228159687Snetchild 1229159687Snetchild/* buffer copy routines */ 1230159687Snetchildstatic void 1231159687Snetchildenvy24_p32sl(struct sc_chinfo *ch) 1232159687Snetchild{ 1233159687Snetchild int length; 1234159687Snetchild sample32_t *dmabuf; 1235159687Snetchild u_int32_t *data; 1236159687Snetchild int src, dst, ssize, dsize, slot; 1237159687Snetchild int i; 1238159687Snetchild 1239159687Snetchild length = sndbuf_getready(ch->buffer) / 8; 1240159687Snetchild dmabuf = ch->parent->pbuf; 1241159687Snetchild data = (u_int32_t *)ch->data; 1242159687Snetchild src = sndbuf_getreadyptr(ch->buffer) / 4; 1243159687Snetchild dst = src / 2 + ch->offset; 1244159687Snetchild ssize = ch->size / 4; 1245159687Snetchild dsize = ch->size / 8; 1246159687Snetchild slot = ch->num * 2; 1247159687Snetchild 1248159687Snetchild for (i = 0; i < length; i++) { 1249159689Snetchild dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = data[src]; 1250159689Snetchild dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = data[src + 1]; 1251159687Snetchild dst++; 1252159687Snetchild dst %= dsize; 1253159687Snetchild src += 2; 1254159687Snetchild src %= ssize; 1255159687Snetchild } 1256159687Snetchild 1257159687Snetchild return; 1258159687Snetchild} 1259159687Snetchild 1260159687Snetchildstatic void 1261159687Snetchildenvy24_p16sl(struct sc_chinfo *ch) 1262159687Snetchild{ 1263159687Snetchild int length; 1264159687Snetchild sample32_t *dmabuf; 1265159687Snetchild u_int16_t *data; 1266159687Snetchild int src, dst, ssize, dsize, slot; 1267159687Snetchild int i; 1268159687Snetchild 1269159687Snetchild#if(0) 1270159687Snetchild device_printf(ch->parent->dev, "envy24_p16sl()\n"); 1271159687Snetchild#endif 1272159687Snetchild length = sndbuf_getready(ch->buffer) / 4; 1273159687Snetchild dmabuf = ch->parent->pbuf; 1274159687Snetchild data = (u_int16_t *)ch->data; 1275159687Snetchild src = sndbuf_getreadyptr(ch->buffer) / 2; 1276159687Snetchild dst = src / 2 + ch->offset; 1277159687Snetchild ssize = ch->size / 2; 1278159687Snetchild dsize = ch->size / 4; 1279159687Snetchild slot = ch->num * 2; 1280159687Snetchild#if(0) 1281159687Snetchild device_printf(ch->parent->dev, "envy24_p16sl():%lu-->%lu(%lu)\n", src, dst, length); 1282159687Snetchild#endif 1283159687Snetchild 1284159687Snetchild for (i = 0; i < length; i++) { 1285159689Snetchild dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16; 1286159689Snetchild dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16; 1287159687Snetchild#if(0) 1288159687Snetchild if (i < 16) { 1289159687Snetchild printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot]); 1290159687Snetchild printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1]); 1291159687Snetchild } 1292159687Snetchild#endif 1293159687Snetchild dst++; 1294159687Snetchild dst %= dsize; 1295159687Snetchild src += 2; 1296159687Snetchild src %= ssize; 1297159687Snetchild } 1298159687Snetchild#if(0) 1299159687Snetchild printf("\n"); 1300159687Snetchild#endif 1301159687Snetchild 1302159687Snetchild return; 1303159687Snetchild} 1304159687Snetchild 1305159687Snetchildstatic void 1306159687Snetchildenvy24_p8u(struct sc_chinfo *ch) 1307159687Snetchild{ 1308159687Snetchild int length; 1309159687Snetchild sample32_t *dmabuf; 1310159687Snetchild u_int8_t *data; 1311159687Snetchild int src, dst, ssize, dsize, slot; 1312159687Snetchild int i; 1313159687Snetchild 1314159687Snetchild length = sndbuf_getready(ch->buffer) / 2; 1315159687Snetchild dmabuf = ch->parent->pbuf; 1316159687Snetchild data = (u_int8_t *)ch->data; 1317159687Snetchild src = sndbuf_getreadyptr(ch->buffer); 1318159687Snetchild dst = src / 2 + ch->offset; 1319159687Snetchild ssize = ch->size; 1320159687Snetchild dsize = ch->size / 4; 1321159687Snetchild slot = ch->num * 2; 1322159687Snetchild 1323159687Snetchild for (i = 0; i < length; i++) { 1324159689Snetchild dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24; 1325159689Snetchild dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24; 1326159687Snetchild dst++; 1327159687Snetchild dst %= dsize; 1328159687Snetchild src += 2; 1329159687Snetchild src %= ssize; 1330159687Snetchild } 1331159687Snetchild 1332159687Snetchild return; 1333159687Snetchild} 1334159687Snetchild 1335159687Snetchildstatic void 1336159687Snetchildenvy24_r32sl(struct sc_chinfo *ch) 1337159687Snetchild{ 1338159687Snetchild int length; 1339159687Snetchild sample32_t *dmabuf; 1340159687Snetchild u_int32_t *data; 1341159687Snetchild int src, dst, ssize, dsize, slot; 1342159687Snetchild int i; 1343159687Snetchild 1344159687Snetchild length = sndbuf_getfree(ch->buffer) / 8; 1345159687Snetchild dmabuf = ch->parent->rbuf; 1346159687Snetchild data = (u_int32_t *)ch->data; 1347159687Snetchild dst = sndbuf_getfreeptr(ch->buffer) / 4; 1348159687Snetchild src = dst / 2 + ch->offset; 1349159687Snetchild dsize = ch->size / 4; 1350159687Snetchild ssize = ch->size / 8; 1351159687Snetchild slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2; 1352159687Snetchild 1353159687Snetchild for (i = 0; i < length; i++) { 1354159689Snetchild data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer; 1355159689Snetchild data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer; 1356159687Snetchild dst += 2; 1357159687Snetchild dst %= dsize; 1358159687Snetchild src++; 1359159687Snetchild src %= ssize; 1360159687Snetchild } 1361159687Snetchild 1362159687Snetchild return; 1363159687Snetchild} 1364159687Snetchild 1365159687Snetchildstatic void 1366159687Snetchildenvy24_r16sl(struct sc_chinfo *ch) 1367159687Snetchild{ 1368159687Snetchild int length; 1369159687Snetchild sample32_t *dmabuf; 1370159689Snetchild u_int16_t *data; 1371159687Snetchild int src, dst, ssize, dsize, slot; 1372159687Snetchild int i; 1373159687Snetchild 1374159687Snetchild length = sndbuf_getfree(ch->buffer) / 4; 1375159687Snetchild dmabuf = ch->parent->rbuf; 1376159687Snetchild data = (u_int16_t *)ch->data; 1377159687Snetchild dst = sndbuf_getfreeptr(ch->buffer) / 2; 1378159687Snetchild src = dst / 2 + ch->offset; 1379159687Snetchild dsize = ch->size / 2; 1380159687Snetchild ssize = ch->size / 8; 1381159687Snetchild slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2; 1382159687Snetchild 1383159687Snetchild for (i = 0; i < length; i++) { 1384159689Snetchild data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer; 1385159689Snetchild data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer; 1386159687Snetchild dst += 2; 1387159687Snetchild dst %= dsize; 1388159687Snetchild src++; 1389159687Snetchild src %= ssize; 1390159687Snetchild } 1391159687Snetchild 1392159687Snetchild return; 1393159687Snetchild} 1394159687Snetchild 1395159687Snetchild/* -------------------------------------------------------------------- */ 1396159687Snetchild 1397159687Snetchild/* channel interface */ 1398159687Snetchildstatic void * 1399159687Snetchildenvy24chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 1400159687Snetchild{ 1401159687Snetchild struct sc_info *sc = (struct sc_info *)devinfo; 1402159687Snetchild struct sc_chinfo *ch; 1403159687Snetchild unsigned num; 1404159687Snetchild 1405159687Snetchild#if(0) 1406159687Snetchild device_printf(sc->dev, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir); 1407159687Snetchild#endif 1408159687Snetchild snd_mtxlock(sc->lock); 1409159687Snetchild if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) || 1410159687Snetchild (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) { 1411159687Snetchild snd_mtxunlock(sc->lock); 1412159687Snetchild return NULL; 1413159687Snetchild } 1414159687Snetchild num = sc->chnum; 1415159687Snetchild 1416159687Snetchild ch = &sc->chan[num]; 1417159687Snetchild ch->size = 8 * ENVY24_SAMPLE_NUM; 1418159687Snetchild ch->data = malloc(ch->size, M_ENVY24, M_NOWAIT); 1419159687Snetchild if (ch->data == NULL) { 1420159687Snetchild ch->size = 0; 1421159687Snetchild ch = NULL; 1422159687Snetchild } 1423159687Snetchild else { 1424159687Snetchild ch->buffer = b; 1425159687Snetchild ch->channel = c; 1426159687Snetchild ch->parent = sc; 1427159687Snetchild ch->dir = dir; 1428159687Snetchild /* set channel map */ 1429159687Snetchild ch->num = envy24_chanmap[num]; 1430165306Sariff snd_mtxunlock(sc->lock); 1431159687Snetchild sndbuf_setup(ch->buffer, ch->data, ch->size); 1432165306Sariff snd_mtxlock(sc->lock); 1433159687Snetchild /* these 2 values are dummy */ 1434159687Snetchild ch->unit = 4; 1435159687Snetchild ch->blk = 10240; 1436159687Snetchild } 1437159687Snetchild snd_mtxunlock(sc->lock); 1438159687Snetchild 1439159687Snetchild return ch; 1440159687Snetchild} 1441159687Snetchild 1442159687Snetchildstatic int 1443159687Snetchildenvy24chan_free(kobj_t obj, void *data) 1444159687Snetchild{ 1445159687Snetchild struct sc_chinfo *ch = data; 1446159687Snetchild struct sc_info *sc = ch->parent; 1447159687Snetchild 1448159687Snetchild#if(0) 1449159687Snetchild device_printf(sc->dev, "envy24chan_free()\n"); 1450159687Snetchild#endif 1451159687Snetchild snd_mtxlock(sc->lock); 1452159687Snetchild if (ch->data != NULL) { 1453159687Snetchild free(ch->data, M_ENVY24); 1454159687Snetchild ch->data = NULL; 1455159687Snetchild } 1456159687Snetchild snd_mtxunlock(sc->lock); 1457159687Snetchild 1458159687Snetchild return 0; 1459159687Snetchild} 1460159687Snetchild 1461159687Snetchildstatic int 1462159687Snetchildenvy24chan_setformat(kobj_t obj, void *data, u_int32_t format) 1463159687Snetchild{ 1464159687Snetchild struct sc_chinfo *ch = data; 1465159687Snetchild struct sc_info *sc = ch->parent; 1466159687Snetchild struct envy24_emldma *emltab; 1467165306Sariff /* unsigned int bcnt, bsize; */ 1468159687Snetchild int i; 1469159687Snetchild 1470159687Snetchild#if(0) 1471159687Snetchild device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format); 1472159687Snetchild#endif 1473159687Snetchild snd_mtxlock(sc->lock); 1474159687Snetchild /* check and get format related information */ 1475159687Snetchild if (ch->dir == PCMDIR_PLAY) 1476159687Snetchild emltab = envy24_pemltab; 1477159687Snetchild else 1478159687Snetchild emltab = envy24_remltab; 1479159687Snetchild if (emltab == NULL) { 1480159687Snetchild snd_mtxunlock(sc->lock); 1481159687Snetchild return -1; 1482159687Snetchild } 1483159687Snetchild for (i = 0; emltab[i].format != 0; i++) 1484159687Snetchild if (emltab[i].format == format) 1485159687Snetchild break; 1486159687Snetchild if (emltab[i].format == 0) { 1487159687Snetchild snd_mtxunlock(sc->lock); 1488159687Snetchild return -1; 1489159687Snetchild } 1490159687Snetchild 1491159687Snetchild /* set format information */ 1492159687Snetchild ch->format = format; 1493159687Snetchild ch->emldma = emltab[i].emldma; 1494159687Snetchild if (ch->unit > emltab[i].unit) 1495159687Snetchild ch->blk *= ch->unit / emltab[i].unit; 1496159687Snetchild else 1497159687Snetchild ch->blk /= emltab[i].unit / ch->unit; 1498159687Snetchild ch->unit = emltab[i].unit; 1499159687Snetchild 1500159687Snetchild /* set channel buffer information */ 1501159687Snetchild ch->size = ch->unit * ENVY24_SAMPLE_NUM; 1502165306Sariff#if 0 1503159687Snetchild if (ch->dir == PCMDIR_PLAY) 1504159687Snetchild bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT; 1505159687Snetchild else 1506159687Snetchild bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT; 1507159687Snetchild bsize *= ch->unit; 1508159687Snetchild bcnt = ch->size / bsize; 1509159687Snetchild sndbuf_resize(ch->buffer, bcnt, bsize); 1510165306Sariff#endif 1511159687Snetchild snd_mtxunlock(sc->lock); 1512159687Snetchild 1513159687Snetchild#if(0) 1514159687Snetchild device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0); 1515159687Snetchild#endif 1516159687Snetchild return 0; 1517159687Snetchild} 1518159687Snetchild 1519159687Snetchild/* 1520159687Snetchild IMPLEMENT NOTICE: In this driver, setspeed function only do setting 1521159687Snetchild of speed information value. And real hardware speed setting is done 1522159687Snetchild at start triggered(see envy24chan_trigger()). So, at this function 1523159687Snetchild is called, any value that ENVY24 can use is able to set. But, at 1524159687Snetchild start triggerd, some other channel is running, and that channel's 1525159687Snetchild speed isn't same with, then trigger function will fail. 1526159687Snetchild*/ 1527159687Snetchildstatic int 1528159687Snetchildenvy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed) 1529159687Snetchild{ 1530159687Snetchild struct sc_chinfo *ch = data; 1531159687Snetchild u_int32_t val, prev; 1532159687Snetchild int i; 1533159687Snetchild 1534159687Snetchild#if(0) 1535159687Snetchild device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed); 1536159687Snetchild#endif 1537159687Snetchild prev = 0x7fffffff; 1538159687Snetchild for (i = 0; (val = envy24_speed[i]) != 0; i++) { 1539159687Snetchild if (abs(val - speed) < abs(prev - speed)) 1540159687Snetchild prev = val; 1541159687Snetchild else 1542159687Snetchild break; 1543159687Snetchild } 1544159687Snetchild ch->speed = prev; 1545159687Snetchild 1546159687Snetchild#if(0) 1547159687Snetchild device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed); 1548159687Snetchild#endif 1549159687Snetchild return ch->speed; 1550159687Snetchild} 1551159687Snetchild 1552159687Snetchildstatic int 1553159687Snetchildenvy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 1554159687Snetchild{ 1555159687Snetchild struct sc_chinfo *ch = data; 1556165306Sariff /* struct sc_info *sc = ch->parent; */ 1557159687Snetchild u_int32_t size, prev; 1558165306Sariff unsigned int bcnt, bsize; 1559159687Snetchild 1560159687Snetchild#if(0) 1561159687Snetchild device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize); 1562159687Snetchild#endif 1563159687Snetchild prev = 0x7fffffff; 1564165306Sariff /* snd_mtxlock(sc->lock); */ 1565159687Snetchild for (size = ch->size / 2; size > 0; size /= 2) { 1566159687Snetchild if (abs(size - blocksize) < abs(prev - blocksize)) 1567159687Snetchild prev = size; 1568159687Snetchild else 1569159687Snetchild break; 1570159687Snetchild } 1571159687Snetchild 1572159687Snetchild ch->blk = prev / ch->unit; 1573159687Snetchild if (ch->dir == PCMDIR_PLAY) 1574159687Snetchild ch->blk *= ENVY24_PLAY_BUFUNIT / 4; 1575159687Snetchild else 1576159687Snetchild ch->blk *= ENVY24_REC_BUFUNIT / 4; 1577165306Sariff /* set channel buffer information */ 1578165306Sariff /* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */ 1579165306Sariff if (ch->dir == PCMDIR_PLAY) 1580165306Sariff bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT; 1581165306Sariff else 1582165306Sariff bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT; 1583165306Sariff bsize *= ch->unit; 1584165306Sariff bcnt = ch->size / bsize; 1585165306Sariff sndbuf_resize(ch->buffer, bcnt, bsize); 1586165306Sariff /* snd_mtxunlock(sc->lock); */ 1587159687Snetchild 1588159687Snetchild#if(0) 1589159687Snetchild device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev); 1590159687Snetchild#endif 1591159687Snetchild return prev; 1592159687Snetchild} 1593159687Snetchild 1594159687Snetchild/* semantic note: must start at beginning of buffer */ 1595159687Snetchildstatic int 1596159687Snetchildenvy24chan_trigger(kobj_t obj, void *data, int go) 1597159687Snetchild{ 1598159687Snetchild struct sc_chinfo *ch = data; 1599159687Snetchild struct sc_info *sc = ch->parent; 1600159687Snetchild u_int32_t ptr; 1601159687Snetchild int slot; 1602160796Snetchild#if 0 1603159687Snetchild int i; 1604159687Snetchild 1605159687Snetchild device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go); 1606159687Snetchild#endif 1607159687Snetchild snd_mtxlock(sc->lock); 1608159687Snetchild if (ch->dir == PCMDIR_PLAY) 1609159687Snetchild slot = 0; 1610159687Snetchild else 1611159687Snetchild slot = 1; 1612159687Snetchild switch (go) { 1613159687Snetchild case PCMTRIG_START: 1614159687Snetchild#if(0) 1615159687Snetchild device_printf(sc->dev, "envy24chan_trigger(): start\n"); 1616159687Snetchild#endif 1617159687Snetchild /* check or set channel speed */ 1618159687Snetchild if (sc->run[0] == 0 && sc->run[1] == 0) { 1619159687Snetchild sc->speed = envy24_setspeed(sc, ch->speed); 1620159687Snetchild sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed; 1621159687Snetchild sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed; 1622159687Snetchild } 1623159687Snetchild else if (ch->speed != 0 && ch->speed != sc->speed) 1624159687Snetchild return -1; 1625159687Snetchild if (ch->speed == 0) 1626159687Snetchild ch->channel->speed = sc->speed; 1627159687Snetchild /* start or enable channel */ 1628159687Snetchild sc->run[slot]++; 1629159687Snetchild if (sc->run[slot] == 1) { 1630159687Snetchild /* first channel */ 1631159687Snetchild ch->offset = 0; 1632159687Snetchild sc->blk[slot] = ch->blk; 1633159687Snetchild } 1634159687Snetchild else { 1635159687Snetchild ptr = envy24_gethwptr(sc, ch->dir); 1636159687Snetchild ch->offset = ((ptr / ch->blk + 1) * ch->blk % 1637159687Snetchild (ch->size / 4)) * 4 / ch->unit; 1638159687Snetchild if (ch->blk < sc->blk[slot]) 1639159687Snetchild sc->blk[slot] = ch->blk; 1640159687Snetchild } 1641159687Snetchild if (ch->dir == PCMDIR_PLAY) { 1642159687Snetchild ch->emldma(ch); 1643159687Snetchild envy24_setvolume(sc, ch->num); 1644159687Snetchild } 1645159687Snetchild envy24_updintr(sc, ch->dir); 1646159687Snetchild if (sc->run[slot] == 1) 1647159687Snetchild envy24_start(sc, ch->dir); 1648159687Snetchild ch->run = 1; 1649159687Snetchild break; 1650159687Snetchild case PCMTRIG_EMLDMAWR: 1651159687Snetchild#if(0) 1652159687Snetchild device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n"); 1653159687Snetchild#endif 1654159687Snetchild if (ch->run != 1) 1655159687Snetchild return -1; 1656159687Snetchild ch->emldma(ch); 1657159687Snetchild break; 1658159687Snetchild case PCMTRIG_EMLDMARD: 1659159687Snetchild#if(0) 1660159687Snetchild device_printf(sc->dev, "envy24chan_trigger(): emldmard\n"); 1661159687Snetchild#endif 1662159687Snetchild if (ch->run != 1) 1663159687Snetchild return -1; 1664159687Snetchild ch->emldma(ch); 1665159687Snetchild break; 1666159687Snetchild case PCMTRIG_ABORT: 1667159687Snetchild#if(0) 1668159687Snetchild device_printf(sc->dev, "envy24chan_trigger(): abort\n"); 1669159687Snetchild#endif 1670159687Snetchild ch->run = 0; 1671159687Snetchild sc->run[slot]--; 1672159687Snetchild if (ch->dir == PCMDIR_PLAY) 1673159687Snetchild envy24_mutevolume(sc, ch->num); 1674159687Snetchild if (sc->run[slot] == 0) { 1675159687Snetchild envy24_stop(sc, ch->dir); 1676159687Snetchild sc->intr[slot] = 0; 1677159687Snetchild } 1678160796Snetchild#if 0 1679159687Snetchild else if (ch->blk == sc->blk[slot]) { 1680159687Snetchild sc->blk[slot] = ENVY24_SAMPLE_NUM / 2; 1681159687Snetchild for (i = 0; i < ENVY24_CHAN_NUM; i++) { 1682159687Snetchild if (sc->chan[i].dir == ch->dir && 1683159687Snetchild sc->chan[i].run == 1 && 1684159687Snetchild sc->chan[i].blk < sc->blk[slot]) 1685159687Snetchild sc->blk[slot] = sc->chan[i].blk; 1686159687Snetchild } 1687159687Snetchild if (ch->blk != sc->blk[slot]) 1688159687Snetchild envy24_updintr(sc, ch->dir); 1689159687Snetchild } 1690160796Snetchild#endif 1691159687Snetchild break; 1692159687Snetchild } 1693159687Snetchild snd_mtxunlock(sc->lock); 1694159687Snetchild 1695159687Snetchild return 0; 1696159687Snetchild} 1697159687Snetchild 1698159687Snetchildstatic int 1699159687Snetchildenvy24chan_getptr(kobj_t obj, void *data) 1700159687Snetchild{ 1701159687Snetchild struct sc_chinfo *ch = data; 1702159687Snetchild struct sc_info *sc = ch->parent; 1703159687Snetchild u_int32_t ptr; 1704159687Snetchild int rtn; 1705159687Snetchild 1706159687Snetchild#if(0) 1707159687Snetchild device_printf(sc->dev, "envy24chan_getptr()\n"); 1708159687Snetchild#endif 1709159687Snetchild snd_mtxlock(sc->lock); 1710159687Snetchild ptr = envy24_gethwptr(sc, ch->dir); 1711159687Snetchild rtn = ptr * ch->unit; 1712159687Snetchild snd_mtxunlock(sc->lock); 1713159687Snetchild 1714159687Snetchild#if(0) 1715159687Snetchild device_printf(sc->dev, "envy24chan_getptr(): return %d\n", 1716159687Snetchild rtn); 1717159687Snetchild#endif 1718159687Snetchild return rtn; 1719159687Snetchild} 1720159687Snetchild 1721159687Snetchildstatic struct pcmchan_caps * 1722159687Snetchildenvy24chan_getcaps(kobj_t obj, void *data) 1723159687Snetchild{ 1724159687Snetchild struct sc_chinfo *ch = data; 1725159687Snetchild struct sc_info *sc = ch->parent; 1726159687Snetchild struct pcmchan_caps *rtn; 1727159687Snetchild 1728159687Snetchild#if(0) 1729159687Snetchild device_printf(sc->dev, "envy24chan_getcaps()\n"); 1730159687Snetchild#endif 1731159687Snetchild snd_mtxlock(sc->lock); 1732159687Snetchild if (ch->dir == PCMDIR_PLAY) { 1733159687Snetchild if (sc->run[0] == 0) 1734159687Snetchild rtn = &envy24_playcaps; 1735159687Snetchild else 1736159687Snetchild rtn = &sc->caps[0]; 1737159687Snetchild } 1738159687Snetchild else { 1739159687Snetchild if (sc->run[1] == 0) 1740159687Snetchild rtn = &envy24_reccaps; 1741159687Snetchild else 1742159687Snetchild rtn = &sc->caps[1]; 1743159687Snetchild } 1744159687Snetchild snd_mtxunlock(sc->lock); 1745159687Snetchild 1746159687Snetchild return rtn; 1747159687Snetchild} 1748159687Snetchild 1749159687Snetchildstatic kobj_method_t envy24chan_methods[] = { 1750159687Snetchild KOBJMETHOD(channel_init, envy24chan_init), 1751159687Snetchild KOBJMETHOD(channel_free, envy24chan_free), 1752159687Snetchild KOBJMETHOD(channel_setformat, envy24chan_setformat), 1753159687Snetchild KOBJMETHOD(channel_setspeed, envy24chan_setspeed), 1754159687Snetchild KOBJMETHOD(channel_setblocksize, envy24chan_setblocksize), 1755159687Snetchild KOBJMETHOD(channel_trigger, envy24chan_trigger), 1756159687Snetchild KOBJMETHOD(channel_getptr, envy24chan_getptr), 1757159687Snetchild KOBJMETHOD(channel_getcaps, envy24chan_getcaps), 1758159687Snetchild { 0, 0 } 1759159687Snetchild}; 1760159687SnetchildCHANNEL_DECLARE(envy24chan); 1761159687Snetchild 1762159687Snetchild/* -------------------------------------------------------------------- */ 1763159687Snetchild 1764159687Snetchild/* mixer interface */ 1765159687Snetchild 1766159687Snetchildstatic int 1767159687Snetchildenvy24mixer_init(struct snd_mixer *m) 1768159687Snetchild{ 1769159687Snetchild struct sc_info *sc = mix_getdevinfo(m); 1770159687Snetchild 1771159687Snetchild#if(0) 1772159687Snetchild device_printf(sc->dev, "envy24mixer_init()\n"); 1773159687Snetchild#endif 1774159687Snetchild if (sc == NULL) 1775159687Snetchild return -1; 1776159687Snetchild 1777159687Snetchild /* set volume control rate */ 1778159687Snetchild snd_mtxlock(sc->lock); 1779159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */ 1780159687Snetchild 1781159687Snetchild mix_setdevs(m, ENVY24_MIX_MASK); 1782159687Snetchild mix_setrecdevs(m, ENVY24_MIX_REC_MASK); 1783159687Snetchild snd_mtxunlock(sc->lock); 1784159687Snetchild 1785159687Snetchild return 0; 1786159687Snetchild} 1787159687Snetchild 1788159687Snetchildstatic int 1789159687Snetchildenvy24mixer_reinit(struct snd_mixer *m) 1790159687Snetchild{ 1791159687Snetchild struct sc_info *sc = mix_getdevinfo(m); 1792159687Snetchild 1793159687Snetchild if (sc == NULL) 1794159687Snetchild return -1; 1795159687Snetchild#if(0) 1796159687Snetchild device_printf(sc->dev, "envy24mixer_reinit()\n"); 1797159687Snetchild#endif 1798159687Snetchild 1799159687Snetchild return 0; 1800159687Snetchild} 1801159687Snetchild 1802159687Snetchildstatic int 1803159687Snetchildenvy24mixer_uninit(struct snd_mixer *m) 1804159687Snetchild{ 1805159687Snetchild struct sc_info *sc = mix_getdevinfo(m); 1806159687Snetchild 1807159687Snetchild if (sc == NULL) 1808159687Snetchild return -1; 1809159687Snetchild#if(0) 1810159687Snetchild device_printf(sc->dev, "envy24mixer_uninit()\n"); 1811159687Snetchild#endif 1812159687Snetchild 1813159687Snetchild return 0; 1814159687Snetchild} 1815159687Snetchild 1816159687Snetchildstatic int 1817159687Snetchildenvy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 1818159687Snetchild{ 1819159687Snetchild struct sc_info *sc = mix_getdevinfo(m); 1820159687Snetchild int ch = envy24_mixmap[dev]; 1821159687Snetchild int hwch; 1822159687Snetchild int i; 1823159687Snetchild 1824159687Snetchild if (sc == NULL) 1825159687Snetchild return -1; 1826159687Snetchild if (dev == 0 && sc->cfg->codec->setvolume == NULL) 1827159687Snetchild return -1; 1828159687Snetchild if (dev != 0 && ch == -1) 1829159687Snetchild return -1; 1830159687Snetchild hwch = envy24_chanmap[ch]; 1831159687Snetchild#if(0) 1832159687Snetchild device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n", 1833159687Snetchild dev, left, right); 1834159687Snetchild#endif 1835159687Snetchild 1836159687Snetchild snd_mtxlock(sc->lock); 1837159687Snetchild if (dev == 0) { 1838159687Snetchild for (i = 0; i < sc->dacn; i++) { 1839159687Snetchild sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right); 1840159687Snetchild } 1841159687Snetchild } 1842159687Snetchild else { 1843159687Snetchild /* set volume value for hardware */ 1844159687Snetchild if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN) 1845159687Snetchild sc->left[hwch] = ENVY24_VOL_MUTE; 1846159687Snetchild if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN) 1847159687Snetchild sc->right[hwch] = ENVY24_VOL_MUTE; 1848159687Snetchild 1849159687Snetchild /* set volume for record channel and running play channel */ 1850159687Snetchild if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run) 1851159687Snetchild envy24_setvolume(sc, hwch); 1852159687Snetchild } 1853159687Snetchild snd_mtxunlock(sc->lock); 1854159687Snetchild 1855159687Snetchild return right << 8 | left; 1856159687Snetchild} 1857159687Snetchild 1858159687Snetchildstatic u_int32_t 1859159687Snetchildenvy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src) 1860159687Snetchild{ 1861159687Snetchild struct sc_info *sc = mix_getdevinfo(m); 1862159687Snetchild int ch = envy24_mixmap[src]; 1863159687Snetchild#if(0) 1864159687Snetchild device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src); 1865159687Snetchild#endif 1866159687Snetchild 1867159687Snetchild if (ch > ENVY24_CHAN_PLAY_SPDIF) 1868159687Snetchild sc->src = ch; 1869159687Snetchild return src; 1870159687Snetchild} 1871159687Snetchild 1872159687Snetchildstatic kobj_method_t envy24mixer_methods[] = { 1873159687Snetchild KOBJMETHOD(mixer_init, envy24mixer_init), 1874159687Snetchild KOBJMETHOD(mixer_reinit, envy24mixer_reinit), 1875159687Snetchild KOBJMETHOD(mixer_uninit, envy24mixer_uninit), 1876159687Snetchild KOBJMETHOD(mixer_set, envy24mixer_set), 1877159687Snetchild KOBJMETHOD(mixer_setrecsrc, envy24mixer_setrecsrc), 1878159687Snetchild { 0, 0 } 1879159687Snetchild}; 1880159687SnetchildMIXER_DECLARE(envy24mixer); 1881159687Snetchild 1882159687Snetchild/* -------------------------------------------------------------------- */ 1883159687Snetchild 1884159687Snetchild/* The interrupt handler */ 1885159687Snetchildstatic void 1886159687Snetchildenvy24_intr(void *p) 1887159687Snetchild{ 1888159687Snetchild struct sc_info *sc = (struct sc_info *)p; 1889159687Snetchild struct sc_chinfo *ch; 1890159687Snetchild u_int32_t ptr, dsize, feed; 1891159687Snetchild int i; 1892159687Snetchild 1893159687Snetchild#if(0) 1894159687Snetchild device_printf(sc->dev, "envy24_intr()\n"); 1895159687Snetchild#endif 1896159687Snetchild snd_mtxlock(sc->lock); 1897159687Snetchild if (envy24_checkintr(sc, PCMDIR_PLAY)) { 1898159687Snetchild#if(0) 1899159687Snetchild device_printf(sc->dev, "envy24_intr(): play\n"); 1900159687Snetchild#endif 1901159687Snetchild dsize = sc->psize / 4; 1902159687Snetchild ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1; 1903159687Snetchild#if(0) 1904159687Snetchild device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr); 1905159687Snetchild#endif 1906159687Snetchild ptr -= ptr % sc->blk[0]; 1907159687Snetchild feed = (ptr + dsize - sc->intr[0]) % dsize; 1908159687Snetchild#if(0) 1909159687Snetchild printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed); 1910159687Snetchild#endif 1911159687Snetchild for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) { 1912159687Snetchild ch = &sc->chan[i]; 1913159687Snetchild#if(0) 1914159687Snetchild if (ch->run) 1915159687Snetchild device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk); 1916159687Snetchild#endif 1917165306Sariff if (ch->run && ch->blk <= feed) { 1918165306Sariff snd_mtxunlock(sc->lock); 1919159687Snetchild chn_intr(ch->channel); 1920165306Sariff snd_mtxlock(sc->lock); 1921165306Sariff } 1922159687Snetchild } 1923159687Snetchild sc->intr[0] = ptr; 1924159687Snetchild envy24_updintr(sc, PCMDIR_PLAY); 1925159687Snetchild } 1926159687Snetchild if (envy24_checkintr(sc, PCMDIR_REC)) { 1927159687Snetchild#if(0) 1928159687Snetchild device_printf(sc->dev, "envy24_intr(): rec\n"); 1929159687Snetchild#endif 1930159687Snetchild dsize = sc->rsize / 4; 1931159687Snetchild ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1; 1932159687Snetchild ptr -= ptr % sc->blk[1]; 1933159687Snetchild feed = (ptr + dsize - sc->intr[1]) % dsize; 1934159687Snetchild for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) { 1935159687Snetchild ch = &sc->chan[i]; 1936165306Sariff if (ch->run && ch->blk <= feed) { 1937165306Sariff snd_mtxunlock(sc->lock); 1938159687Snetchild chn_intr(ch->channel); 1939165306Sariff snd_mtxlock(sc->lock); 1940165306Sariff } 1941159687Snetchild } 1942159687Snetchild sc->intr[1] = ptr; 1943159687Snetchild envy24_updintr(sc, PCMDIR_REC); 1944159687Snetchild } 1945159687Snetchild snd_mtxunlock(sc->lock); 1946159687Snetchild 1947159687Snetchild return; 1948159687Snetchild} 1949159687Snetchild 1950159687Snetchild/* 1951159687Snetchild * Probe and attach the card 1952159687Snetchild */ 1953159687Snetchild 1954159687Snetchildstatic int 1955159687Snetchildenvy24_pci_probe(device_t dev) 1956159687Snetchild{ 1957159687Snetchild u_int16_t sv, sd; 1958159687Snetchild int i; 1959159687Snetchild 1960159687Snetchild#if(0) 1961159687Snetchild printf("envy24_pci_probe()\n"); 1962159687Snetchild#endif 1963159687Snetchild if (pci_get_device(dev) == PCID_ENVY24 && 1964159687Snetchild pci_get_vendor(dev) == PCIV_ENVY24) { 1965159687Snetchild sv = pci_get_subvendor(dev); 1966159687Snetchild sd = pci_get_subdevice(dev); 1967159687Snetchild for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 1968159687Snetchild if (cfg_table[i].subvendor == sv && 1969159687Snetchild cfg_table[i].subdevice == sd) { 1970159687Snetchild break; 1971159687Snetchild } 1972159687Snetchild } 1973159687Snetchild device_set_desc(dev, cfg_table[i].name); 1974159687Snetchild#if(0) 1975159687Snetchild printf("envy24_pci_probe(): return 0\n"); 1976159687Snetchild#endif 1977159687Snetchild return 0; 1978159687Snetchild } 1979159687Snetchild else { 1980159687Snetchild#if(0) 1981159687Snetchild printf("envy24_pci_probe(): return ENXIO\n"); 1982159687Snetchild#endif 1983159687Snetchild return ENXIO; 1984159687Snetchild } 1985159687Snetchild} 1986159687Snetchild 1987159687Snetchildstatic void 1988159687Snetchildenvy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 1989159687Snetchild{ 1990165306Sariff /* struct sc_info *sc = (struct sc_info *)arg; */ 1991159687Snetchild 1992159687Snetchild#if(0) 1993159687Snetchild device_printf(sc->dev, "envy24_dmapsetmap()\n"); 1994159687Snetchild if (bootverbose) { 1995159687Snetchild printf("envy24(play): setmap %lx, %lx; ", 1996159687Snetchild (unsigned long)segs->ds_addr, 1997159687Snetchild (unsigned long)segs->ds_len); 1998159687Snetchild printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap)); 1999159687Snetchild } 2000165306Sariff#endif 2001159687Snetchild} 2002159687Snetchild 2003159687Snetchildstatic void 2004159687Snetchildenvy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2005159687Snetchild{ 2006165306Sariff /* struct sc_info *sc = (struct sc_info *)arg; */ 2007159687Snetchild 2008159687Snetchild#if(0) 2009159687Snetchild device_printf(sc->dev, "envy24_dmarsetmap()\n"); 2010159687Snetchild if (bootverbose) { 2011159687Snetchild printf("envy24(record): setmap %lx, %lx; ", 2012159687Snetchild (unsigned long)segs->ds_addr, 2013159687Snetchild (unsigned long)segs->ds_len); 2014159687Snetchild printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap)); 2015159687Snetchild } 2016165306Sariff#endif 2017159687Snetchild} 2018159687Snetchild 2019159687Snetchildstatic void 2020159687Snetchildenvy24_dmafree(struct sc_info *sc) 2021159687Snetchild{ 2022159687Snetchild#if(0) 2023159687Snetchild device_printf(sc->dev, "envy24_dmafree():"); 2024159687Snetchild if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap); 2025159687Snetchild else printf(" sc->rmap(null)"); 2026159687Snetchild if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap); 2027159687Snetchild else printf(" sc->pmap(null)"); 2028159687Snetchild if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf); 2029159687Snetchild else printf(" sc->rbuf(null)"); 2030159687Snetchild if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf); 2031159687Snetchild else printf(" sc->pbuf(null)\n"); 2032159687Snetchild#endif 2033159687Snetchild#if(0) 2034159687Snetchild if (sc->rmap) 2035159687Snetchild bus_dmamap_unload(sc->dmat, sc->rmap); 2036159687Snetchild if (sc->pmap) 2037159687Snetchild bus_dmamap_unload(sc->dmat, sc->pmap); 2038159687Snetchild if (sc->rbuf) 2039159687Snetchild bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2040159687Snetchild if (sc->pbuf) 2041159687Snetchild bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2042159687Snetchild#else 2043159687Snetchild bus_dmamap_unload(sc->dmat, sc->rmap); 2044159687Snetchild bus_dmamap_unload(sc->dmat, sc->pmap); 2045159687Snetchild bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2046159687Snetchild bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2047159687Snetchild#endif 2048159687Snetchild 2049159687Snetchild sc->rmap = sc->pmap = NULL; 2050159687Snetchild sc->pbuf = NULL; 2051159687Snetchild sc->rbuf = NULL; 2052159687Snetchild 2053159687Snetchild return; 2054159687Snetchild} 2055159687Snetchild 2056159687Snetchildstatic int 2057159687Snetchildenvy24_dmainit(struct sc_info *sc) 2058159687Snetchild{ 2059159687Snetchild u_int32_t addr; 2060159687Snetchild 2061159687Snetchild#if(0) 2062159687Snetchild device_printf(sc->dev, "envy24_dmainit()\n"); 2063159687Snetchild#endif 2064159687Snetchild /* init values */ 2065159687Snetchild sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM; 2066159687Snetchild sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM; 2067159687Snetchild sc->pbuf = NULL; 2068159687Snetchild sc->rbuf = NULL; 2069159687Snetchild sc->pmap = sc->rmap = NULL; 2070159687Snetchild sc->blk[0] = sc->blk[1] = 0; 2071159687Snetchild 2072159687Snetchild /* allocate DMA buffer */ 2073159687Snetchild#if(0) 2074159687Snetchild device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n"); 2075159687Snetchild#endif 2076159687Snetchild if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap)) 2077159687Snetchild goto bad; 2078159687Snetchild#if(0) 2079159687Snetchild device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n"); 2080159687Snetchild#endif 2081159687Snetchild if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap)) 2082159687Snetchild goto bad; 2083159687Snetchild#if(0) 2084159687Snetchild device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n"); 2085159687Snetchild#endif 2086159687Snetchild if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0)) 2087159687Snetchild goto bad; 2088159687Snetchild#if(0) 2089159687Snetchild device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n"); 2090159687Snetchild#endif 2091159687Snetchild if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0)) 2092159687Snetchild goto bad; 2093159687Snetchild bzero(sc->pbuf, sc->psize); 2094159687Snetchild bzero(sc->rbuf, sc->rsize); 2095159687Snetchild 2096159687Snetchild /* set values to register */ 2097159687Snetchild addr = vtophys(sc->pbuf); 2098159687Snetchild#if(0) 2099159687Snetchild device_printf(sc->dev, "pbuf(0x%08x)\n", addr); 2100159687Snetchild#endif 2101159687Snetchild envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4); 2102159687Snetchild#if(0) 2103159687Snetchild device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4)); 2104159687Snetchild device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1); 2105159687Snetchild#endif 2106159687Snetchild envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2); 2107159687Snetchild#if(0) 2108159687Snetchild device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2)); 2109159687Snetchild#endif 2110159687Snetchild addr = vtophys(sc->rbuf); 2111159687Snetchild envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4); 2112159687Snetchild envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2); 2113159687Snetchild 2114159687Snetchild return 0; 2115159687Snetchild bad: 2116159687Snetchild envy24_dmafree(sc); 2117159687Snetchild return ENOSPC; 2118159687Snetchild} 2119159687Snetchild 2120159687Snetchildstatic void 2121159687Snetchildenvy24_putcfg(struct sc_info *sc) 2122159687Snetchild{ 2123159689Snetchild device_printf(sc->dev, "system configuration\n"); 2124159687Snetchild printf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n", 2125159687Snetchild sc->cfg->subvendor, sc->cfg->subdevice); 2126159687Snetchild printf(" XIN2 Clock Source: "); 2127159687Snetchild switch (sc->cfg->scfg & PCIM_SCFG_XIN2) { 2128159687Snetchild case 0x00: 2129159687Snetchild printf("22.5792MHz(44.1kHz*512)\n"); 2130159687Snetchild break; 2131159687Snetchild case 0x40: 2132159687Snetchild printf("16.9344MHz(44.1kHz*384)\n"); 2133159687Snetchild break; 2134159687Snetchild case 0x80: 2135159687Snetchild printf("from external clock synthesizer chip\n"); 2136159687Snetchild break; 2137159687Snetchild default: 2138159687Snetchild printf("illeagal system setting\n"); 2139159687Snetchild } 2140159687Snetchild printf(" MPU-401 UART(s) #: "); 2141159687Snetchild if (sc->cfg->scfg & PCIM_SCFG_MPU) 2142159687Snetchild printf("2\n"); 2143159687Snetchild else 2144159687Snetchild printf("1\n"); 2145159687Snetchild printf(" AC'97 codec: "); 2146159687Snetchild if (sc->cfg->scfg & PCIM_SCFG_AC97) 2147159687Snetchild printf("not exist\n"); 2148159687Snetchild else 2149159687Snetchild printf("exist\n"); 2150159687Snetchild printf(" ADC #: "); 2151159687Snetchild printf("%d\n", sc->adcn); 2152159687Snetchild printf(" DAC #: "); 2153159687Snetchild printf("%d\n", sc->dacn); 2154159687Snetchild printf(" Multi-track converter type: "); 2155159687Snetchild if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) { 2156159687Snetchild printf("AC'97(SDATA_OUT:"); 2157159687Snetchild if (sc->cfg->acl & PCIM_ACL_OMODE) 2158159687Snetchild printf("packed"); 2159159687Snetchild else 2160159687Snetchild printf("split"); 2161159687Snetchild printf("|SDATA_IN:"); 2162159687Snetchild if (sc->cfg->acl & PCIM_ACL_IMODE) 2163159687Snetchild printf("packed"); 2164159687Snetchild else 2165159687Snetchild printf("split"); 2166159687Snetchild printf(")\n"); 2167159687Snetchild } 2168159687Snetchild else { 2169159687Snetchild printf("I2S("); 2170159687Snetchild if (sc->cfg->i2s & PCIM_I2S_VOL) 2171159687Snetchild printf("with volume, "); 2172159687Snetchild if (sc->cfg->i2s & PCIM_I2S_96KHZ) 2173159687Snetchild printf("96KHz support, "); 2174159687Snetchild switch (sc->cfg->i2s & PCIM_I2S_RES) { 2175159687Snetchild case PCIM_I2S_16BIT: 2176159687Snetchild printf("16bit resolution, "); 2177159687Snetchild break; 2178159687Snetchild case PCIM_I2S_18BIT: 2179159687Snetchild printf("18bit resolution, "); 2180159687Snetchild break; 2181159687Snetchild case PCIM_I2S_20BIT: 2182159687Snetchild printf("20bit resolution, "); 2183159687Snetchild break; 2184159687Snetchild case PCIM_I2S_24BIT: 2185159687Snetchild printf("24bit resolution, "); 2186159687Snetchild break; 2187159687Snetchild } 2188159687Snetchild printf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID); 2189159687Snetchild } 2190159687Snetchild printf(" S/PDIF(IN/OUT): "); 2191159687Snetchild if (sc->cfg->spdif & PCIM_SPDIF_IN) 2192159687Snetchild printf("1/"); 2193159687Snetchild else 2194159687Snetchild printf("0/"); 2195159687Snetchild if (sc->cfg->spdif & PCIM_SPDIF_OUT) 2196159687Snetchild printf("1 "); 2197159687Snetchild else 2198159687Snetchild printf("0 "); 2199159687Snetchild if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT)) 2200159687Snetchild printf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2); 2201159687Snetchild printf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n", 2202159687Snetchild sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate); 2203159687Snetchild} 2204159687Snetchild 2205159687Snetchildstatic int 2206159687Snetchildenvy24_init(struct sc_info *sc) 2207159687Snetchild{ 2208159687Snetchild u_int32_t data; 2209159687Snetchild#if(0) 2210159687Snetchild int rtn; 2211159687Snetchild#endif 2212159687Snetchild int i; 2213159687Snetchild u_int32_t sv, sd; 2214159687Snetchild 2215159687Snetchild 2216159687Snetchild#if(0) 2217159687Snetchild device_printf(sc->dev, "envy24_init()\n"); 2218159687Snetchild#endif 2219159687Snetchild 2220159687Snetchild /* reset chip */ 2221159687Snetchild envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1); 2222159687Snetchild DELAY(200); 2223159687Snetchild envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1); 2224159687Snetchild DELAY(200); 2225159687Snetchild 2226159687Snetchild /* legacy hardware disable */ 2227159687Snetchild data = pci_read_config(sc->dev, PCIR_LAC, 2); 2228159687Snetchild data |= PCIM_LAC_DISABLE; 2229159687Snetchild pci_write_config(sc->dev, PCIR_LAC, data, 2); 2230159687Snetchild 2231159687Snetchild /* check system configuration */ 2232159687Snetchild sc->cfg = NULL; 2233159687Snetchild for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2234159687Snetchild /* 1st: search configuration from table */ 2235159687Snetchild sv = pci_get_subvendor(sc->dev); 2236159687Snetchild sd = pci_get_subdevice(sc->dev); 2237159687Snetchild if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) { 2238159687Snetchild#if(0) 2239159687Snetchild device_printf(sc->dev, "Set configuration from table\n"); 2240159687Snetchild#endif 2241159687Snetchild sc->cfg = &cfg_table[i]; 2242159687Snetchild break; 2243159687Snetchild } 2244159687Snetchild } 2245159687Snetchild if (sc->cfg == NULL) { 2246159687Snetchild /* 2nd: read configuration from table */ 2247159687Snetchild sc->cfg = envy24_rom2cfg(sc); 2248159687Snetchild } 2249159687Snetchild sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1; 2250159687Snetchild sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1; 2251159687Snetchild 2252159687Snetchild if (1 /* bootverbose */) { 2253159687Snetchild envy24_putcfg(sc); 2254159687Snetchild } 2255159687Snetchild 2256159687Snetchild /* set system configuration */ 2257159687Snetchild pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1); 2258159687Snetchild pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1); 2259159687Snetchild pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1); 2260159687Snetchild pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1); 2261159687Snetchild envy24_gpiosetmask(sc, sc->cfg->gpiomask); 2262159687Snetchild envy24_gpiosetdir(sc, sc->cfg->gpiodir); 2263159687Snetchild envy24_gpiowr(sc, sc->cfg->gpiostate); 2264159687Snetchild for (i = 0; i < sc->adcn; i++) { 2265159687Snetchild sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i); 2266159687Snetchild sc->cfg->codec->init(sc->adc[i]); 2267159687Snetchild } 2268159687Snetchild for (i = 0; i < sc->dacn; i++) { 2269159687Snetchild sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i); 2270159687Snetchild sc->cfg->codec->init(sc->dac[i]); 2271159687Snetchild } 2272159687Snetchild 2273159687Snetchild /* initialize DMA buffer */ 2274159687Snetchild#if(0) 2275159687Snetchild device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n"); 2276159687Snetchild#endif 2277159687Snetchild if (envy24_dmainit(sc)) 2278159687Snetchild return ENOSPC; 2279159687Snetchild 2280159687Snetchild /* initialize status */ 2281159687Snetchild sc->run[0] = sc->run[1] = 0; 2282159687Snetchild sc->intr[0] = sc->intr[1] = 0; 2283159687Snetchild sc->speed = 0; 2284159687Snetchild sc->caps[0].fmtlist = envy24_playfmt; 2285159687Snetchild sc->caps[1].fmtlist = envy24_recfmt; 2286159687Snetchild 2287159687Snetchild /* set channel router */ 2288159687Snetchild envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0); 2289159687Snetchild envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0); 2290159687Snetchild /* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */ 2291159687Snetchild 2292159687Snetchild /* set macro interrupt mask */ 2293159687Snetchild data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1); 2294159687Snetchild envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1); 2295159687Snetchild data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1); 2296159687Snetchild#if(0) 2297159687Snetchild device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data); 2298159687Snetchild#endif 2299159687Snetchild 2300159687Snetchild return 0; 2301159687Snetchild} 2302159687Snetchild 2303159687Snetchildstatic int 2304166919Sariffenvy24_alloc_resource(struct sc_info *sc) 2305159687Snetchild{ 2306159687Snetchild /* allocate I/O port resource */ 2307159687Snetchild sc->csid = PCIR_CCS; 2308159687Snetchild sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2309159687Snetchild &sc->csid, 0, ~0, 1, RF_ACTIVE); 2310159687Snetchild sc->ddmaid = PCIR_DDMA; 2311159687Snetchild sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2312159687Snetchild &sc->ddmaid, 0, ~0, 1, RF_ACTIVE); 2313159687Snetchild sc->dsid = PCIR_DS; 2314159687Snetchild sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2315159687Snetchild &sc->dsid, 0, ~0, 1, RF_ACTIVE); 2316159687Snetchild sc->mtid = PCIR_MT; 2317159687Snetchild sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2318159687Snetchild &sc->mtid, 0, ~0, 1, RF_ACTIVE); 2319159687Snetchild if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) { 2320159687Snetchild device_printf(sc->dev, "unable to map IO port space\n"); 2321159687Snetchild return ENXIO; 2322159687Snetchild } 2323159687Snetchild sc->cst = rman_get_bustag(sc->cs); 2324159687Snetchild sc->csh = rman_get_bushandle(sc->cs); 2325159687Snetchild sc->ddmat = rman_get_bustag(sc->ddma); 2326159687Snetchild sc->ddmah = rman_get_bushandle(sc->ddma); 2327159687Snetchild sc->dst = rman_get_bustag(sc->ds); 2328159687Snetchild sc->dsh = rman_get_bushandle(sc->ds); 2329159687Snetchild sc->mtt = rman_get_bustag(sc->mt); 2330159687Snetchild sc->mth = rman_get_bushandle(sc->mt); 2331159687Snetchild#if(0) 2332159687Snetchild device_printf(sc->dev, 2333159687Snetchild "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n", 2334159687Snetchild pci_read_config(sc->dev, PCIR_CCS, 4), 2335159687Snetchild pci_read_config(sc->dev, PCIR_DDMA, 4), 2336159687Snetchild pci_read_config(sc->dev, PCIR_DS, 4), 2337159687Snetchild pci_read_config(sc->dev, PCIR_MT, 4)); 2338159687Snetchild#endif 2339159687Snetchild 2340159687Snetchild /* allocate interupt resource */ 2341159687Snetchild sc->irqid = 0; 2342159687Snetchild sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid, 2343159687Snetchild 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 2344159687Snetchild if (!sc->irq || 2345159687Snetchild snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) { 2346159687Snetchild device_printf(sc->dev, "unable to map interrupt\n"); 2347159687Snetchild return ENXIO; 2348159687Snetchild } 2349159687Snetchild 2350159687Snetchild /* allocate DMA resource */ 2351166919Sariff if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev), 2352166919Sariff /*alignment*/4, 2353166904Snetchild /*boundary*/0, 2354159687Snetchild /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24, 2355159687Snetchild /*highaddr*/BUS_SPACE_MAXADDR_ENVY24, 2356159687Snetchild /*filter*/NULL, /*filterarg*/NULL, 2357159687Snetchild /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24, 2358159687Snetchild /*nsegments*/1, /*maxsegsz*/0x3ffff, 2359159689Snetchild /*flags*/0, /*lockfunc*/busdma_lock_mutex, 2360159689Snetchild /*lockarg*/&Giant, &sc->dmat) != 0) { 2361159687Snetchild device_printf(sc->dev, "unable to create dma tag\n"); 2362159687Snetchild return ENXIO; 2363159687Snetchild } 2364159687Snetchild 2365159687Snetchild return 0; 2366159687Snetchild} 2367159687Snetchild 2368159687Snetchildstatic int 2369159687Snetchildenvy24_pci_attach(device_t dev) 2370159687Snetchild{ 2371159687Snetchild u_int32_t data; 2372159687Snetchild struct sc_info *sc; 2373159687Snetchild char status[SND_STATUSLEN]; 2374159687Snetchild int err = 0; 2375159687Snetchild int i; 2376159687Snetchild 2377159687Snetchild#if(0) 2378159687Snetchild device_printf(dev, "envy24_pci_attach()\n"); 2379159687Snetchild#endif 2380159687Snetchild /* get sc_info data area */ 2381159687Snetchild if ((sc = malloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) { 2382159687Snetchild device_printf(dev, "cannot allocate softc\n"); 2383159687Snetchild return ENXIO; 2384159687Snetchild } 2385159687Snetchild 2386159687Snetchild bzero(sc, sizeof(*sc)); 2387167608Sariff sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_envy24 softc"); 2388159687Snetchild sc->dev = dev; 2389159687Snetchild 2390159687Snetchild /* initialize PCI interface */ 2391159687Snetchild data = pci_read_config(dev, PCIR_COMMAND, 2); 2392159687Snetchild data |= (PCIM_CMD_PORTEN | PCIM_CMD_BUSMASTEREN); 2393159687Snetchild pci_write_config(dev, PCIR_COMMAND, data, 2); 2394159687Snetchild data = pci_read_config(dev, PCIR_COMMAND, 2); 2395159687Snetchild 2396159687Snetchild /* allocate resources */ 2397166919Sariff err = envy24_alloc_resource(sc); 2398159689Snetchild if (err) { 2399159687Snetchild device_printf(dev, "unable to allocate system resources\n"); 2400159687Snetchild goto bad; 2401159687Snetchild } 2402159687Snetchild 2403159687Snetchild /* initialize card */ 2404159689Snetchild err = envy24_init(sc); 2405159689Snetchild if (err) { 2406159687Snetchild device_printf(dev, "unable to initialize the card\n"); 2407159687Snetchild goto bad; 2408159687Snetchild } 2409159687Snetchild 2410159687Snetchild /* set multi track mixer */ 2411159687Snetchild mixer_init(dev, &envy24mixer_class, sc); 2412159687Snetchild 2413159687Snetchild /* set channel information */ 2414167220Sariff err = pcm_register(dev, sc, sc->dacn, sc->adcn); 2415159689Snetchild if (err) 2416159687Snetchild goto bad; 2417167220Sariff sc->chnum = ENVY24_CHAN_PLAY_DAC1; 2418167220Sariff for (i = 0; i < sc->dacn; i++) { 2419159687Snetchild pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc); 2420159687Snetchild sc->chnum++; 2421159687Snetchild } 2422167220Sariff sc->chnum = ENVY24_CHAN_REC_ADC1; 2423167220Sariff for (i = 0; i < sc->adcn; i++) { 2424159687Snetchild pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc); 2425159687Snetchild sc->chnum++; 2426159687Snetchild } 2427159687Snetchild 2428159687Snetchild /* set status iformation */ 2429159687Snetchild snprintf(status, SND_STATUSLEN, 2430159687Snetchild "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld", 2431159687Snetchild rman_get_start(sc->cs), 2432159687Snetchild rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1, 2433159687Snetchild rman_get_start(sc->ddma), 2434159687Snetchild rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1, 2435159687Snetchild rman_get_start(sc->ds), 2436159687Snetchild rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1, 2437159687Snetchild rman_get_start(sc->mt), 2438159687Snetchild rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1, 2439159687Snetchild rman_get_start(sc->irq)); 2440159687Snetchild pcm_setstatus(dev, status); 2441159687Snetchild 2442159687Snetchild return 0; 2443159687Snetchild 2444159687Snetchildbad: 2445159687Snetchild if (sc->ih) 2446159687Snetchild bus_teardown_intr(dev, sc->irq, sc->ih); 2447159687Snetchild if (sc->irq) 2448159687Snetchild bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2449159687Snetchild envy24_dmafree(sc); 2450159687Snetchild if (sc->dmat) 2451159687Snetchild bus_dma_tag_destroy(sc->dmat); 2452160796Snetchild if (sc->cfg->codec->destroy != NULL) { 2453160796Snetchild for (i = 0; i < sc->adcn; i++) 2454160796Snetchild sc->cfg->codec->destroy(sc->adc[i]); 2455160796Snetchild for (i = 0; i < sc->dacn; i++) 2456160796Snetchild sc->cfg->codec->destroy(sc->dac[i]); 2457160796Snetchild } 2458159687Snetchild envy24_cfgfree(sc->cfg); 2459159687Snetchild if (sc->cs) 2460159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2461159687Snetchild if (sc->ddma) 2462159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma); 2463159687Snetchild if (sc->ds) 2464159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds); 2465159687Snetchild if (sc->mt) 2466159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2467159687Snetchild if (sc->lock) 2468159687Snetchild snd_mtxfree(sc->lock); 2469159687Snetchild free(sc, M_ENVY24); 2470159687Snetchild return err; 2471159687Snetchild} 2472159687Snetchild 2473159687Snetchildstatic int 2474159687Snetchildenvy24_pci_detach(device_t dev) 2475159687Snetchild{ 2476159687Snetchild struct sc_info *sc; 2477159687Snetchild int r; 2478159687Snetchild int i; 2479159687Snetchild 2480159687Snetchild#if(0) 2481159687Snetchild device_printf(dev, "envy24_pci_detach()\n"); 2482159687Snetchild#endif 2483159687Snetchild sc = pcm_getdevinfo(dev); 2484159687Snetchild if (sc == NULL) 2485159687Snetchild return 0; 2486159687Snetchild r = pcm_unregister(dev); 2487159687Snetchild if (r) 2488159687Snetchild return r; 2489159687Snetchild 2490159687Snetchild envy24_dmafree(sc); 2491159687Snetchild if (sc->cfg->codec->destroy != NULL) { 2492159687Snetchild for (i = 0; i < sc->adcn; i++) 2493159687Snetchild sc->cfg->codec->destroy(sc->adc[i]); 2494159687Snetchild for (i = 0; i < sc->dacn; i++) 2495159687Snetchild sc->cfg->codec->destroy(sc->dac[i]); 2496159687Snetchild } 2497159687Snetchild envy24_cfgfree(sc->cfg); 2498159687Snetchild bus_dma_tag_destroy(sc->dmat); 2499159687Snetchild bus_teardown_intr(dev, sc->irq, sc->ih); 2500159687Snetchild bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2501159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2502159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma); 2503159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds); 2504159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2505159687Snetchild snd_mtxfree(sc->lock); 2506159687Snetchild free(sc, M_ENVY24); 2507159687Snetchild return 0; 2508159687Snetchild} 2509159687Snetchild 2510159687Snetchildstatic device_method_t envy24_methods[] = { 2511159687Snetchild /* Device interface */ 2512159687Snetchild DEVMETHOD(device_probe, envy24_pci_probe), 2513159687Snetchild DEVMETHOD(device_attach, envy24_pci_attach), 2514159687Snetchild DEVMETHOD(device_detach, envy24_pci_detach), 2515159687Snetchild { 0, 0 } 2516159687Snetchild}; 2517159687Snetchild 2518159687Snetchildstatic driver_t envy24_driver = { 2519159687Snetchild "pcm", 2520159687Snetchild envy24_methods, 2521159687Snetchild#if __FreeBSD_version > 500000 2522159687Snetchild PCM_SOFTC_SIZE, 2523159687Snetchild#else 2524159687Snetchild sizeof(struct snddev_info), 2525159687Snetchild#endif 2526159687Snetchild}; 2527159687Snetchild 2528159687SnetchildDRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0); 2529159689SnetchildMODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2530168883SariffMODULE_DEPEND(snd_envy24, snd_spicds, 1, 1, 1); 2531159687SnetchildMODULE_VERSION(snd_envy24, 1); 2532