1205859Sjoel/*- 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 23188480Snetchild * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24159687Snetchild * SUCH DAMAGE. 25159687Snetchild * 26159687Snetchild */ 27159687Snetchild 28193640Sariff#ifdef HAVE_KERNEL_OPTION_HEADERS 29193640Sariff#include "opt_snd.h" 30193640Sariff#endif 31193640Sariff 32159687Snetchild#include <dev/sound/pcm/sound.h> 33159687Snetchild#include <dev/sound/pcm/ac97.h> 34162876Snetchild#include <dev/sound/pci/spicds.h> 35159687Snetchild#include <dev/sound/pci/envy24.h> 36159687Snetchild 37159689Snetchild#include <dev/pci/pcireg.h> 38159689Snetchild#include <dev/pci/pcivar.h> 39159687Snetchild 40159687Snetchild#include "mixer_if.h" 41159687Snetchild 42165306SariffSND_DECLARE_FILE("$FreeBSD$"); 43165306Sariff 44227293Sedstatic MALLOC_DEFINE(M_ENVY24, "envy24", "envy24 audio"); 45159687Snetchild 46159687Snetchild/* -------------------------------------------------------------------- */ 47159687Snetchild 48159687Snetchildstruct sc_info; 49159687Snetchild 50159687Snetchild#define ENVY24_PLAY_CHNUM 10 51159687Snetchild#define ENVY24_REC_CHNUM 12 52159687Snetchild#define ENVY24_PLAY_BUFUNIT (4 /* byte/sample */ * 10 /* channel */) 53159687Snetchild#define ENVY24_REC_BUFUNIT (4 /* byte/sample */ * 12 /* channel */) 54159687Snetchild#define ENVY24_SAMPLE_NUM 4096 55159687Snetchild 56159687Snetchild#define ENVY24_TIMEOUT 1000 57159687Snetchild 58193640Sariff#define ENVY24_DEFAULT_FORMAT SND_FORMAT(AFMT_S16_LE, 2, 0) 59159687Snetchild 60159687Snetchild#define ENVY24_NAMELEN 32 61159687Snetchild 62170031Sjoel#define SDA_GPIO 0x10 63170031Sjoel#define SCL_GPIO 0x20 64170031Sjoel 65159689Snetchildstruct envy24_sample { 66159689Snetchild volatile u_int32_t buffer; 67159689Snetchild}; 68159687Snetchild 69159689Snetchildtypedef struct envy24_sample sample32_t; 70159689Snetchild 71159687Snetchild/* channel registers */ 72159687Snetchildstruct sc_chinfo { 73159687Snetchild struct snd_dbuf *buffer; 74159687Snetchild struct pcm_channel *channel; 75159687Snetchild struct sc_info *parent; 76159687Snetchild int dir; 77159687Snetchild unsigned num; /* hw channel number */ 78159687Snetchild 79159687Snetchild /* channel information */ 80159687Snetchild u_int32_t format; 81159687Snetchild u_int32_t speed; 82159687Snetchild u_int32_t blk; /* hw block size(dword) */ 83159687Snetchild 84159687Snetchild /* format conversion structure */ 85159687Snetchild u_int8_t *data; 86159687Snetchild unsigned int size; /* data buffer size(byte) */ 87159687Snetchild int unit; /* sample size(byte) */ 88159687Snetchild unsigned int offset; /* samples number offset */ 89159687Snetchild void (*emldma)(struct sc_chinfo *); 90159687Snetchild 91159687Snetchild /* flags */ 92159687Snetchild int run; 93159687Snetchild}; 94159687Snetchild 95159687Snetchild/* codec interface entrys */ 96159687Snetchildstruct codec_entry { 97159687Snetchild void *(*create)(device_t dev, void *devinfo, int dir, int num); 98159687Snetchild void (*destroy)(void *codec); 99159687Snetchild void (*init)(void *codec); 100159687Snetchild void (*reinit)(void *codec); 101159687Snetchild void (*setvolume)(void *codec, int dir, unsigned int left, unsigned int right); 102159687Snetchild void (*setrate)(void *codec, int which, int rate); 103159687Snetchild}; 104159687Snetchild 105159687Snetchild/* system configuration information */ 106159687Snetchildstruct cfg_info { 107159687Snetchild char *name; 108159687Snetchild u_int16_t subvendor, subdevice; 109159687Snetchild u_int8_t scfg, acl, i2s, spdif; 110159687Snetchild u_int8_t gpiomask, gpiostate, gpiodir; 111159689Snetchild u_int8_t cdti, cclk, cs, cif, type; 112159687Snetchild u_int8_t free; 113159687Snetchild struct codec_entry *codec; 114159687Snetchild}; 115159687Snetchild 116159687Snetchild/* device private data */ 117159687Snetchildstruct sc_info { 118159687Snetchild device_t dev; 119166713Sariff struct mtx *lock; 120159687Snetchild 121159687Snetchild /* Control/Status registor */ 122159687Snetchild struct resource *cs; 123159687Snetchild int csid; 124159687Snetchild bus_space_tag_t cst; 125159687Snetchild bus_space_handle_t csh; 126159687Snetchild /* DDMA registor */ 127159687Snetchild struct resource *ddma; 128159687Snetchild int ddmaid; 129159687Snetchild bus_space_tag_t ddmat; 130159687Snetchild bus_space_handle_t ddmah; 131159687Snetchild /* Consumer Section DMA Channel Registers */ 132159687Snetchild struct resource *ds; 133159687Snetchild int dsid; 134159687Snetchild bus_space_tag_t dst; 135159687Snetchild bus_space_handle_t dsh; 136159687Snetchild /* MultiTrack registor */ 137159687Snetchild struct resource *mt; 138159687Snetchild int mtid; 139159687Snetchild bus_space_tag_t mtt; 140159687Snetchild bus_space_handle_t mth; 141159687Snetchild /* DMA tag */ 142159687Snetchild bus_dma_tag_t dmat; 143159687Snetchild /* IRQ resource */ 144159687Snetchild struct resource *irq; 145159687Snetchild int irqid; 146159687Snetchild void *ih; 147159687Snetchild 148159687Snetchild /* system configuration data */ 149159687Snetchild struct cfg_info *cfg; 150159687Snetchild 151159687Snetchild /* ADC/DAC number and info */ 152159687Snetchild int adcn, dacn; 153159687Snetchild void *adc[4], *dac[4]; 154159687Snetchild 155159687Snetchild /* mixer control data */ 156159687Snetchild u_int32_t src; 157159687Snetchild u_int8_t left[ENVY24_CHAN_NUM]; 158159687Snetchild u_int8_t right[ENVY24_CHAN_NUM]; 159159687Snetchild 160159687Snetchild /* Play/Record DMA fifo */ 161159687Snetchild sample32_t *pbuf; 162159687Snetchild sample32_t *rbuf; 163159687Snetchild u_int32_t psize, rsize; /* DMA buffer size(byte) */ 164159687Snetchild u_int16_t blk[2]; /* transfer check blocksize(dword) */ 165159687Snetchild bus_dmamap_t pmap, rmap; 166159687Snetchild 167159687Snetchild /* current status */ 168159687Snetchild u_int32_t speed; 169159687Snetchild int run[2]; 170159687Snetchild u_int16_t intr[2]; 171159687Snetchild struct pcmchan_caps caps[2]; 172159687Snetchild 173159687Snetchild /* channel info table */ 174159687Snetchild unsigned chnum; 175159687Snetchild struct sc_chinfo chan[11]; 176159687Snetchild}; 177159687Snetchild 178159687Snetchild/* -------------------------------------------------------------------- */ 179159687Snetchild 180159687Snetchild/* 181159687Snetchild * prototypes 182159687Snetchild */ 183159687Snetchild 184159687Snetchild/* DMA emulator */ 185159687Snetchildstatic void envy24_p8u(struct sc_chinfo *); 186159687Snetchildstatic void envy24_p16sl(struct sc_chinfo *); 187159687Snetchildstatic void envy24_p32sl(struct sc_chinfo *); 188159687Snetchildstatic void envy24_r16sl(struct sc_chinfo *); 189159687Snetchildstatic void envy24_r32sl(struct sc_chinfo *); 190159687Snetchild 191159687Snetchild/* channel interface */ 192159687Snetchildstatic void *envy24chan_init(kobj_t, void *, struct snd_dbuf *, struct pcm_channel *, int); 193159687Snetchildstatic int envy24chan_setformat(kobj_t, void *, u_int32_t); 194193640Sariffstatic u_int32_t envy24chan_setspeed(kobj_t, void *, u_int32_t); 195193640Sariffstatic u_int32_t envy24chan_setblocksize(kobj_t, void *, u_int32_t); 196159687Snetchildstatic int envy24chan_trigger(kobj_t, void *, int); 197193640Sariffstatic u_int32_t envy24chan_getptr(kobj_t, void *); 198159687Snetchildstatic struct pcmchan_caps *envy24chan_getcaps(kobj_t, void *); 199159687Snetchild 200159687Snetchild/* mixer interface */ 201159687Snetchildstatic int envy24mixer_init(struct snd_mixer *); 202159687Snetchildstatic int envy24mixer_reinit(struct snd_mixer *); 203159687Snetchildstatic int envy24mixer_uninit(struct snd_mixer *); 204159687Snetchildstatic int envy24mixer_set(struct snd_mixer *, unsigned, unsigned, unsigned); 205159687Snetchildstatic u_int32_t envy24mixer_setrecsrc(struct snd_mixer *, u_int32_t); 206159687Snetchild 207159687Snetchild/* M-Audio Delta series AK4524 access interface */ 208159687Snetchildstatic void *envy24_delta_ak4524_create(device_t, void *, int, int); 209159687Snetchildstatic void envy24_delta_ak4524_destroy(void *); 210159687Snetchildstatic void envy24_delta_ak4524_init(void *); 211159687Snetchildstatic void envy24_delta_ak4524_reinit(void *); 212159687Snetchildstatic void envy24_delta_ak4524_setvolume(void *, int, unsigned int, unsigned int); 213159687Snetchild 214159687Snetchild/* -------------------------------------------------------------------- */ 215159687Snetchild 216159687Snetchild/* 217159687Snetchild system constant tables 218159687Snetchild*/ 219159687Snetchild 220159687Snetchild/* API -> hardware channel map */ 221159687Snetchildstatic unsigned envy24_chanmap[ENVY24_CHAN_NUM] = { 222159687Snetchild ENVY24_CHAN_PLAY_SPDIF, /* 0 */ 223159687Snetchild ENVY24_CHAN_PLAY_DAC1, /* 1 */ 224159687Snetchild ENVY24_CHAN_PLAY_DAC2, /* 2 */ 225159687Snetchild ENVY24_CHAN_PLAY_DAC3, /* 3 */ 226159687Snetchild ENVY24_CHAN_PLAY_DAC4, /* 4 */ 227159687Snetchild ENVY24_CHAN_REC_MIX, /* 5 */ 228159687Snetchild ENVY24_CHAN_REC_SPDIF, /* 6 */ 229159687Snetchild ENVY24_CHAN_REC_ADC1, /* 7 */ 230159687Snetchild ENVY24_CHAN_REC_ADC2, /* 8 */ 231159687Snetchild ENVY24_CHAN_REC_ADC3, /* 9 */ 232159687Snetchild ENVY24_CHAN_REC_ADC4, /* 10 */ 233159687Snetchild}; 234159687Snetchild 235159687Snetchild/* mixer -> API channel map. see above */ 236159687Snetchildstatic int envy24_mixmap[] = { 237159687Snetchild -1, /* Master output level. It is depend on codec support */ 238159687Snetchild -1, /* Treble level of all output channels */ 239159687Snetchild -1, /* Bass level of all output channels */ 240159687Snetchild -1, /* Volume of synthesier input */ 241159687Snetchild 0, /* Output level for the audio device */ 242159687Snetchild -1, /* Output level for the PC speaker */ 243159687Snetchild 7, /* line in jack */ 244159687Snetchild -1, /* microphone jack */ 245159687Snetchild -1, /* CD audio input */ 246159687Snetchild -1, /* Recording monitor */ 247159687Snetchild 1, /* alternative codec */ 248159687Snetchild -1, /* global recording level */ 249159687Snetchild -1, /* Input gain */ 250159687Snetchild -1, /* Output gain */ 251159687Snetchild 8, /* Input source 1 */ 252159687Snetchild 9, /* Input source 2 */ 253159687Snetchild 10, /* Input source 3 */ 254159687Snetchild 6, /* Digital (input) 1 */ 255159687Snetchild -1, /* Digital (input) 2 */ 256159687Snetchild -1, /* Digital (input) 3 */ 257159687Snetchild -1, /* Phone input */ 258159687Snetchild -1, /* Phone output */ 259159687Snetchild -1, /* Video/TV (audio) in */ 260159687Snetchild -1, /* Radio in */ 261159687Snetchild -1, /* Monitor volume */ 262159687Snetchild}; 263159687Snetchild 264159687Snetchild/* variable rate audio */ 265159687Snetchildstatic u_int32_t envy24_speed[] = { 266159687Snetchild 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 267159687Snetchild 12000, 11025, 9600, 8000, 0 268159687Snetchild}; 269159687Snetchild 270159687Snetchild/* known boards configuration */ 271159687Snetchildstatic struct codec_entry delta_codec = { 272159687Snetchild envy24_delta_ak4524_create, 273159687Snetchild envy24_delta_ak4524_destroy, 274159687Snetchild envy24_delta_ak4524_init, 275159687Snetchild envy24_delta_ak4524_reinit, 276159687Snetchild envy24_delta_ak4524_setvolume, 277159687Snetchild NULL, /* setrate */ 278159687Snetchild}; 279159687Snetchild 280159687Snetchildstatic struct cfg_info cfg_table[] = { 281159687Snetchild { 282159689Snetchild "Envy24 audio (M Audio Delta Dio 2496)", 283159687Snetchild 0x1412, 0xd631, 284159687Snetchild 0x10, 0x80, 0xf0, 0x03, 285188480Snetchild 0x02, 0xc0, 0xfd, 286159689Snetchild 0x10, 0x20, 0x40, 0x00, 0x00, 287159689Snetchild 0x00, 288159687Snetchild &delta_codec, 289159687Snetchild }, 290159687Snetchild { 291159689Snetchild "Envy24 audio (Terratec DMX 6fire)", 292159689Snetchild 0x153b, 0x1138, 293159689Snetchild 0x2f, 0x80, 0xf0, 0x03, 294159689Snetchild 0xc0, 0xff, 0x7f, 295159689Snetchild 0x10, 0x20, 0x01, 0x01, 0x00, 296159689Snetchild 0x00, 297159689Snetchild &delta_codec, 298159689Snetchild }, 299159689Snetchild { 300159689Snetchild "Envy24 audio (M Audio Audiophile 2496)", 301159689Snetchild 0x1412, 0xd634, 302159689Snetchild 0x10, 0x80, 0x72, 0x03, 303159689Snetchild 0x04, 0xfe, 0xfb, 304159689Snetchild 0x08, 0x02, 0x20, 0x00, 0x01, 305159689Snetchild 0x00, 306159689Snetchild &delta_codec, 307159689Snetchild }, 308188480Snetchild { 309188480Snetchild "Envy24 audio (M Audio Delta 66)", 310188480Snetchild 0x1412, 0xd632, 311188480Snetchild 0x15, 0x80, 0xf0, 0x03, 312188480Snetchild 0x02, 0xc0, 0xfd, 313188480Snetchild 0x10, 0x20, 0x40, 0x00, 0x00, 314188480Snetchild 0x00, 315188480Snetchild &delta_codec, 316188480Snetchild }, 317188480Snetchild { 318188480Snetchild "Envy24 audio (M Audio Delta 44)", 319188480Snetchild 0x1412, 0xd633, 320188480Snetchild 0x15, 0x80, 0xf0, 0x00, 321188480Snetchild 0x02, 0xc0, 0xfd, 322188480Snetchild 0x10, 0x20, 0x40, 0x00, 0x00, 323188480Snetchild 0x00, 324188480Snetchild &delta_codec, 325188480Snetchild }, 326188480Snetchild { 327188480Snetchild "Envy24 audio (M Audio Delta 1010)", 328188480Snetchild 0x1412, 0xd630, 329188480Snetchild 0x1f, 0x80, 0xf0, 0x03, 330188480Snetchild 0x22, 0xd0, 0xdd, 331188480Snetchild 0x10, 0x20, 0x40, 0x00, 0x00, 332188480Snetchild 0x00, 333188480Snetchild &delta_codec, 334188480Snetchild }, 335188480Snetchild { 336188480Snetchild "Envy24 audio (M Audio Delta 1010LT)", 337188480Snetchild 0x1412, 0xd63b, 338188480Snetchild 0x1f, 0x80, 0x72, 0x03, 339188480Snetchild 0x04, 0x7e, 0xfb, 340188480Snetchild 0x08, 0x02, 0x70, 0x00, 0x00, 341188480Snetchild 0x00, 342188480Snetchild &delta_codec, 343188480Snetchild }, 344188480Snetchild { 345188480Snetchild "Envy24 audio (Terratec EWX 2496)", 346188480Snetchild 0x153b, 0x1130, 347188480Snetchild 0x10, 0x80, 0xf0, 0x03, 348188480Snetchild 0xc0, 0x3f, 0x3f, 349188480Snetchild 0x10, 0x20, 0x01, 0x01, 0x00, 350188480Snetchild 0x00, 351188480Snetchild &delta_codec, 352188480Snetchild }, 353159689Snetchild { 354159689Snetchild "Envy24 audio (Generic)", 355159687Snetchild 0, 0, 356159687Snetchild 0x0f, 0x00, 0x01, 0x03, 357159687Snetchild 0xff, 0x00, 0x00, 358159689Snetchild 0x10, 0x20, 0x40, 0x00, 0x00, 359159689Snetchild 0x00, 360159687Snetchild &delta_codec, /* default codec routines */ 361159687Snetchild } 362159687Snetchild}; 363159687Snetchild 364159687Snetchildstatic u_int32_t envy24_recfmt[] = { 365193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 366193640Sariff SND_FORMAT(AFMT_S32_LE, 2, 0), 367159687Snetchild 0 368159687Snetchild}; 369159687Snetchildstatic struct pcmchan_caps envy24_reccaps = {8000, 96000, envy24_recfmt, 0}; 370159687Snetchild 371159687Snetchildstatic u_int32_t envy24_playfmt[] = { 372193640Sariff SND_FORMAT(AFMT_U8, 2, 0), 373193640Sariff SND_FORMAT(AFMT_S16_LE, 2, 0), 374193640Sariff SND_FORMAT(AFMT_S32_LE, 2, 0), 375159687Snetchild 0 376159687Snetchild}; 377159687Snetchild 378159687Snetchildstatic struct pcmchan_caps envy24_playcaps = {8000, 96000, envy24_playfmt, 0}; 379159687Snetchild 380159687Snetchildstruct envy24_emldma { 381159687Snetchild u_int32_t format; 382159687Snetchild void (*emldma)(struct sc_chinfo *); 383159687Snetchild int unit; 384159687Snetchild}; 385159687Snetchild 386159687Snetchildstatic struct envy24_emldma envy24_pemltab[] = { 387193640Sariff {SND_FORMAT(AFMT_U8, 2, 0), envy24_p8u, 2}, 388193640Sariff {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24_p16sl, 4}, 389193640Sariff {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24_p32sl, 8}, 390159687Snetchild {0, NULL, 0} 391159687Snetchild}; 392159687Snetchild 393159687Snetchildstatic struct envy24_emldma envy24_remltab[] = { 394193640Sariff {SND_FORMAT(AFMT_S16_LE, 2, 0), envy24_r16sl, 4}, 395193640Sariff {SND_FORMAT(AFMT_S32_LE, 2, 0), envy24_r32sl, 8}, 396159687Snetchild {0, NULL, 0} 397159687Snetchild}; 398159687Snetchild 399159687Snetchild/* -------------------------------------------------------------------- */ 400159687Snetchild 401159687Snetchild/* common routines */ 402159687Snetchildstatic u_int32_t 403159687Snetchildenvy24_rdcs(struct sc_info *sc, int regno, int size) 404159687Snetchild{ 405159687Snetchild switch (size) { 406159687Snetchild case 1: 407159687Snetchild return bus_space_read_1(sc->cst, sc->csh, regno); 408159687Snetchild case 2: 409159687Snetchild return bus_space_read_2(sc->cst, sc->csh, regno); 410159687Snetchild case 4: 411159687Snetchild return bus_space_read_4(sc->cst, sc->csh, regno); 412159687Snetchild default: 413159687Snetchild return 0xffffffff; 414159687Snetchild } 415159687Snetchild} 416159687Snetchild 417159687Snetchildstatic void 418159687Snetchildenvy24_wrcs(struct sc_info *sc, int regno, u_int32_t data, int size) 419159687Snetchild{ 420159687Snetchild switch (size) { 421159687Snetchild case 1: 422159687Snetchild bus_space_write_1(sc->cst, sc->csh, regno, data); 423159687Snetchild break; 424159687Snetchild case 2: 425159687Snetchild bus_space_write_2(sc->cst, sc->csh, regno, data); 426159687Snetchild break; 427159687Snetchild case 4: 428159687Snetchild bus_space_write_4(sc->cst, sc->csh, regno, data); 429159687Snetchild break; 430159687Snetchild } 431159687Snetchild} 432159687Snetchild 433159687Snetchildstatic u_int32_t 434159687Snetchildenvy24_rdmt(struct sc_info *sc, int regno, int size) 435159687Snetchild{ 436159687Snetchild switch (size) { 437159687Snetchild case 1: 438159687Snetchild return bus_space_read_1(sc->mtt, sc->mth, regno); 439159687Snetchild case 2: 440159687Snetchild return bus_space_read_2(sc->mtt, sc->mth, regno); 441159687Snetchild case 4: 442159687Snetchild return bus_space_read_4(sc->mtt, sc->mth, regno); 443159687Snetchild default: 444159687Snetchild return 0xffffffff; 445159687Snetchild } 446159687Snetchild} 447159687Snetchild 448159687Snetchildstatic void 449159687Snetchildenvy24_wrmt(struct sc_info *sc, int regno, u_int32_t data, int size) 450159687Snetchild{ 451159687Snetchild switch (size) { 452159687Snetchild case 1: 453159687Snetchild bus_space_write_1(sc->mtt, sc->mth, regno, data); 454159687Snetchild break; 455159687Snetchild case 2: 456159687Snetchild bus_space_write_2(sc->mtt, sc->mth, regno, data); 457159687Snetchild break; 458159687Snetchild case 4: 459159687Snetchild bus_space_write_4(sc->mtt, sc->mth, regno, data); 460159687Snetchild break; 461159687Snetchild } 462159687Snetchild} 463159687Snetchild 464159687Snetchildstatic u_int32_t 465159687Snetchildenvy24_rdci(struct sc_info *sc, int regno) 466159687Snetchild{ 467159687Snetchild envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1); 468159687Snetchild return envy24_rdcs(sc, ENVY24_CCS_DATA, 1); 469159687Snetchild} 470159687Snetchild 471159687Snetchildstatic void 472159687Snetchildenvy24_wrci(struct sc_info *sc, int regno, u_int32_t data) 473159687Snetchild{ 474159687Snetchild envy24_wrcs(sc, ENVY24_CCS_INDEX, regno, 1); 475159687Snetchild envy24_wrcs(sc, ENVY24_CCS_DATA, data, 1); 476159687Snetchild} 477159687Snetchild 478159687Snetchild/* -------------------------------------------------------------------- */ 479159687Snetchild 480159687Snetchild/* I2C port/E2PROM access routines */ 481159687Snetchild 482159687Snetchildstatic int 483159687Snetchildenvy24_rdi2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr) 484159687Snetchild{ 485159687Snetchild u_int32_t data; 486159687Snetchild int i; 487159687Snetchild 488159687Snetchild#if(0) 489159687Snetchild device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr); 490159687Snetchild#endif 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 envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1); 501159687Snetchild envy24_wrcs(sc, ENVY24_CCS_I2CDEV, 502159687Snetchild (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_RD, 1); 503159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 504159687Snetchild data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 505159687Snetchild if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0) 506159687Snetchild break; 507159687Snetchild DELAY(32); /* 31.25kHz */ 508159687Snetchild } 509159687Snetchild if (i == ENVY24_TIMEOUT) { 510159687Snetchild return -1; 511159687Snetchild } 512159687Snetchild data = envy24_rdcs(sc, ENVY24_CCS_I2CDATA, 1); 513159687Snetchild 514159687Snetchild#if(0) 515159687Snetchild device_printf(sc->dev, "envy24_rdi2c(): return 0x%x\n", data); 516159687Snetchild#endif 517159687Snetchild return (int)data; 518159687Snetchild} 519159687Snetchild 520159689Snetchild#if 0 521159687Snetchildstatic int 522159687Snetchildenvy24_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data) 523159687Snetchild{ 524159687Snetchild u_int32_t tmp; 525159687Snetchild int i; 526159687Snetchild 527159687Snetchild#if(0) 528159687Snetchild device_printf(sc->dev, "envy24_rdi2c(sc, 0x%02x, 0x%02x)\n", dev, addr); 529159687Snetchild#endif 530159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 531159687Snetchild tmp = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 532159687Snetchild if ((tmp & ENVY24_CCS_I2CSTAT_BSY) == 0) 533159687Snetchild break; 534159687Snetchild DELAY(32); /* 31.25kHz */ 535159687Snetchild } 536159687Snetchild if (i == ENVY24_TIMEOUT) { 537159687Snetchild return -1; 538159687Snetchild } 539159687Snetchild envy24_wrcs(sc, ENVY24_CCS_I2CADDR, addr, 1); 540159687Snetchild envy24_wrcs(sc, ENVY24_CCS_I2CDATA, data, 1); 541159687Snetchild envy24_wrcs(sc, ENVY24_CCS_I2CDEV, 542159687Snetchild (dev & ENVY24_CCS_I2CDEV_ADDR) | ENVY24_CCS_I2CDEV_WR, 1); 543159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 544159687Snetchild data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 545159687Snetchild if ((data & ENVY24_CCS_I2CSTAT_BSY) == 0) 546159687Snetchild break; 547159687Snetchild DELAY(32); /* 31.25kHz */ 548159687Snetchild } 549159687Snetchild if (i == ENVY24_TIMEOUT) { 550159687Snetchild return -1; 551159687Snetchild } 552159687Snetchild 553159687Snetchild return 0; 554159687Snetchild} 555159689Snetchild#endif 556159687Snetchild 557159687Snetchildstatic int 558159687Snetchildenvy24_rdrom(struct sc_info *sc, u_int32_t addr) 559159687Snetchild{ 560159687Snetchild u_int32_t data; 561159687Snetchild 562159687Snetchild#if(0) 563159687Snetchild device_printf(sc->dev, "envy24_rdrom(sc, 0x%02x)\n", addr); 564159687Snetchild#endif 565159687Snetchild data = envy24_rdcs(sc, ENVY24_CCS_I2CSTAT, 1); 566159687Snetchild if ((data & ENVY24_CCS_I2CSTAT_ROM) == 0) { 567159687Snetchild#if(0) 568159687Snetchild device_printf(sc->dev, "envy24_rdrom(): E2PROM not presented\n"); 569159687Snetchild#endif 570159687Snetchild return -1; 571159687Snetchild } 572159687Snetchild 573159687Snetchild return envy24_rdi2c(sc, ENVY24_CCS_I2CDEV_ROM, addr); 574159687Snetchild} 575159687Snetchild 576159687Snetchildstatic struct cfg_info * 577159687Snetchildenvy24_rom2cfg(struct sc_info *sc) 578159687Snetchild{ 579159687Snetchild struct cfg_info *buff; 580159687Snetchild int size; 581159687Snetchild int i; 582159687Snetchild 583159687Snetchild#if(0) 584159687Snetchild device_printf(sc->dev, "envy24_rom2cfg(sc)\n"); 585159687Snetchild#endif 586159687Snetchild size = envy24_rdrom(sc, ENVY24_E2PROM_SIZE); 587159687Snetchild if (size < ENVY24_E2PROM_GPIODIR + 1) { 588159687Snetchild#if(0) 589159687Snetchild device_printf(sc->dev, "envy24_rom2cfg(): ENVY24_E2PROM_SIZE-->%d\n", size); 590159687Snetchild#endif 591159687Snetchild return NULL; 592159687Snetchild } 593159687Snetchild buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT); 594159687Snetchild if (buff == NULL) { 595159687Snetchild#if(0) 596159687Snetchild device_printf(sc->dev, "envy24_rom2cfg(): malloc()\n"); 597159687Snetchild#endif 598159687Snetchild return NULL; 599159687Snetchild } 600159687Snetchild buff->free = 1; 601159687Snetchild 602159687Snetchild buff->subvendor = envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR) << 8; 603159687Snetchild buff->subvendor += envy24_rdrom(sc, ENVY24_E2PROM_SUBVENDOR + 1); 604159687Snetchild buff->subdevice = envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE) << 8; 605159687Snetchild buff->subdevice += envy24_rdrom(sc, ENVY24_E2PROM_SUBDEVICE + 1); 606159687Snetchild buff->scfg = envy24_rdrom(sc, ENVY24_E2PROM_SCFG); 607159687Snetchild buff->acl = envy24_rdrom(sc, ENVY24_E2PROM_ACL); 608159687Snetchild buff->i2s = envy24_rdrom(sc, ENVY24_E2PROM_I2S); 609159687Snetchild buff->spdif = envy24_rdrom(sc, ENVY24_E2PROM_SPDIF); 610159687Snetchild buff->gpiomask = envy24_rdrom(sc, ENVY24_E2PROM_GPIOMASK); 611159687Snetchild buff->gpiostate = envy24_rdrom(sc, ENVY24_E2PROM_GPIOSTATE); 612159687Snetchild buff->gpiodir = envy24_rdrom(sc, ENVY24_E2PROM_GPIODIR); 613159687Snetchild 614159687Snetchild for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) 615159687Snetchild if (cfg_table[i].subvendor == buff->subvendor && 616159687Snetchild cfg_table[i].subdevice == buff->subdevice) 617159687Snetchild break; 618159687Snetchild buff->name = cfg_table[i].name; 619159687Snetchild buff->codec = cfg_table[i].codec; 620159687Snetchild 621159687Snetchild return buff; 622159687Snetchild} 623159687Snetchild 624159687Snetchildstatic void 625159687Snetchildenvy24_cfgfree(struct cfg_info *cfg) { 626159687Snetchild if (cfg == NULL) 627159687Snetchild return; 628159687Snetchild if (cfg->free) 629159687Snetchild free(cfg, M_ENVY24); 630159687Snetchild return; 631159687Snetchild} 632159687Snetchild 633159687Snetchild/* -------------------------------------------------------------------- */ 634159687Snetchild 635159687Snetchild/* AC'97 codec access routines */ 636159687Snetchild 637159689Snetchild#if 0 638159687Snetchildstatic int 639159687Snetchildenvy24_coldcd(struct sc_info *sc) 640159687Snetchild{ 641159687Snetchild u_int32_t data; 642159687Snetchild int i; 643159687Snetchild 644159687Snetchild#if(0) 645159687Snetchild device_printf(sc->dev, "envy24_coldcd()\n"); 646159687Snetchild#endif 647159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_CLD, 1); 648159687Snetchild DELAY(10); 649159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1); 650159687Snetchild DELAY(1000); 651159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 652159687Snetchild data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1); 653159687Snetchild if (data & ENVY24_MT_AC97CMD_RDY) { 654159687Snetchild return 0; 655159687Snetchild } 656159687Snetchild } 657159687Snetchild 658159687Snetchild return -1; 659159687Snetchild} 660159689Snetchild#endif 661159687Snetchild 662159687Snetchildstatic int 663159687Snetchildenvy24_slavecd(struct sc_info *sc) 664159687Snetchild{ 665159687Snetchild u_int32_t data; 666159687Snetchild int i; 667159687Snetchild 668159687Snetchild#if(0) 669159687Snetchild device_printf(sc->dev, "envy24_slavecd()\n"); 670159687Snetchild#endif 671159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97CMD, 672159687Snetchild ENVY24_MT_AC97CMD_CLD | ENVY24_MT_AC97CMD_WRM, 1); 673159687Snetchild DELAY(10); 674159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97CMD, 0, 1); 675159687Snetchild DELAY(1000); 676159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 677159687Snetchild data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1); 678159687Snetchild if (data & ENVY24_MT_AC97CMD_RDY) { 679159687Snetchild return 0; 680159687Snetchild } 681159687Snetchild } 682159687Snetchild 683159687Snetchild return -1; 684159687Snetchild} 685159687Snetchild 686159689Snetchild#if 0 687159687Snetchildstatic int 688159687Snetchildenvy24_rdcd(kobj_t obj, void *devinfo, int regno) 689159687Snetchild{ 690159687Snetchild struct sc_info *sc = (struct sc_info *)devinfo; 691159687Snetchild u_int32_t data; 692159687Snetchild int i; 693159687Snetchild 694159687Snetchild#if(0) 695159687Snetchild device_printf(sc->dev, "envy24_rdcd(obj, sc, 0x%02x)\n", regno); 696159687Snetchild#endif 697159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1); 698159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_RD, 1); 699159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 700159687Snetchild data = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1); 701159687Snetchild if ((data & ENVY24_MT_AC97CMD_RD) == 0) 702159687Snetchild break; 703159687Snetchild } 704159687Snetchild data = envy24_rdmt(sc, ENVY24_MT_AC97DLO, 2); 705159687Snetchild 706159687Snetchild#if(0) 707159687Snetchild device_printf(sc->dev, "envy24_rdcd(): return 0x%x\n", data); 708159687Snetchild#endif 709159687Snetchild return (int)data; 710159687Snetchild} 711159687Snetchild 712159687Snetchildstatic int 713159687Snetchildenvy24_wrcd(kobj_t obj, void *devinfo, int regno, u_int16_t data) 714159687Snetchild{ 715159687Snetchild struct sc_info *sc = (struct sc_info *)devinfo; 716159687Snetchild u_int32_t cmd; 717159687Snetchild int i; 718159687Snetchild 719159687Snetchild#if(0) 720159687Snetchild device_printf(sc->dev, "envy24_wrcd(obj, sc, 0x%02x, 0x%04x)\n", regno, data); 721159687Snetchild#endif 722159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97IDX, (u_int32_t)regno, 1); 723159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97DLO, (u_int32_t)data, 2); 724159687Snetchild envy24_wrmt(sc, ENVY24_MT_AC97CMD, ENVY24_MT_AC97CMD_WR, 1); 725159687Snetchild for (i = 0; i < ENVY24_TIMEOUT; i++) { 726159687Snetchild cmd = envy24_rdmt(sc, ENVY24_MT_AC97CMD, 1); 727159687Snetchild if ((cmd & ENVY24_MT_AC97CMD_WR) == 0) 728159687Snetchild break; 729159687Snetchild } 730159687Snetchild 731159687Snetchild return 0; 732159687Snetchild} 733159687Snetchild 734159687Snetchildstatic kobj_method_t envy24_ac97_methods[] = { 735159687Snetchild KOBJMETHOD(ac97_read, envy24_rdcd), 736159687Snetchild KOBJMETHOD(ac97_write, envy24_wrcd), 737193640Sariff KOBJMETHOD_END 738159687Snetchild}; 739159687SnetchildAC97_DECLARE(envy24_ac97); 740159689Snetchild#endif 741159687Snetchild 742159687Snetchild/* -------------------------------------------------------------------- */ 743159687Snetchild 744159687Snetchild/* GPIO access routines */ 745159687Snetchild 746159687Snetchildstatic u_int32_t 747159687Snetchildenvy24_gpiord(struct sc_info *sc) 748159687Snetchild{ 749159687Snetchild return envy24_rdci(sc, ENVY24_CCI_GPIODAT); 750159687Snetchild} 751159687Snetchild 752159687Snetchildstatic void 753159687Snetchildenvy24_gpiowr(struct sc_info *sc, u_int32_t data) 754159687Snetchild{ 755159687Snetchild#if(0) 756159687Snetchild device_printf(sc->dev, "envy24_gpiowr(sc, 0x%02x)\n", data & 0xff); 757159687Snetchild return; 758159687Snetchild#endif 759159687Snetchild envy24_wrci(sc, ENVY24_CCI_GPIODAT, data); 760159687Snetchild return; 761159687Snetchild} 762159687Snetchild 763159689Snetchild#if 0 764159687Snetchildstatic u_int32_t 765159687Snetchildenvy24_gpiogetmask(struct sc_info *sc) 766159687Snetchild{ 767159687Snetchild return envy24_rdci(sc, ENVY24_CCI_GPIOMASK); 768159687Snetchild} 769159689Snetchild#endif 770159687Snetchild 771159687Snetchildstatic void 772159687Snetchildenvy24_gpiosetmask(struct sc_info *sc, u_int32_t mask) 773159687Snetchild{ 774159687Snetchild envy24_wrci(sc, ENVY24_CCI_GPIOMASK, mask); 775159687Snetchild return; 776159687Snetchild} 777159687Snetchild 778159689Snetchild#if 0 779159687Snetchildstatic u_int32_t 780159687Snetchildenvy24_gpiogetdir(struct sc_info *sc) 781159687Snetchild{ 782159687Snetchild return envy24_rdci(sc, ENVY24_CCI_GPIOCTL); 783159687Snetchild} 784159689Snetchild#endif 785159687Snetchild 786159687Snetchildstatic void 787159687Snetchildenvy24_gpiosetdir(struct sc_info *sc, u_int32_t dir) 788159687Snetchild{ 789159687Snetchild envy24_wrci(sc, ENVY24_CCI_GPIOCTL, dir); 790159687Snetchild return; 791159687Snetchild} 792159687Snetchild 793159687Snetchild/* -------------------------------------------------------------------- */ 794159687Snetchild 795170031Sjoel/* Envy24 I2C through GPIO bit-banging */ 796159687Snetchild 797159687Snetchildstruct envy24_delta_ak4524_codec { 798162876Snetchild struct spicds_info *info; 799159687Snetchild struct sc_info *parent; 800159687Snetchild int dir; 801159687Snetchild int num; 802159687Snetchild int cs, cclk, cdti; 803159687Snetchild}; 804159687Snetchild 805159687Snetchildstatic void 806170031Sjoelenvy24_gpio_i2c_ctl(void *codec, unsigned int scl, unsigned int sda) 807170031Sjoel{ 808170031Sjoel u_int32_t data = 0; 809170031Sjoel struct envy24_delta_ak4524_codec *ptr = codec; 810170031Sjoel#if(0) 811170031Sjoel device_printf(ptr->parent->dev, "--> %d, %d\n", scl, sda); 812170031Sjoel#endif 813170031Sjoel data = envy24_gpiord(ptr->parent); 814170031Sjoel data &= ~(SDA_GPIO | SCL_GPIO); 815170031Sjoel if (scl) data += SCL_GPIO; 816170031Sjoel if (sda) data += SDA_GPIO; 817170031Sjoel envy24_gpiowr(ptr->parent, data); 818170031Sjoel return; 819170031Sjoel} 820170031Sjoel 821170031Sjoelstatic void 822170031Sjoeli2c_wrbit(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), int bit) 823170031Sjoel{ 824170031Sjoel struct envy24_delta_ak4524_codec *ptr = codec; 825170031Sjoel unsigned int sda; 826170031Sjoel 827170031Sjoel if (bit) 828170031Sjoel sda = 1; 829170031Sjoel else 830170031Sjoel sda = 0; 831170031Sjoel 832170031Sjoel ctrl(ptr, 0, sda); 833170031Sjoel DELAY(I2C_DELAY); 834170031Sjoel ctrl(ptr, 1, sda); 835170031Sjoel DELAY(I2C_DELAY); 836170031Sjoel ctrl(ptr, 0, sda); 837170031Sjoel DELAY(I2C_DELAY); 838170031Sjoel} 839170031Sjoel 840170031Sjoelstatic void 841170031Sjoeli2c_start(void *codec, void (*ctrl)(void*, unsigned int, unsigned int)) 842170031Sjoel{ 843170031Sjoel struct envy24_delta_ak4524_codec *ptr = codec; 844170031Sjoel 845170031Sjoel ctrl(ptr, 1, 1); 846170031Sjoel DELAY(I2C_DELAY); 847170031Sjoel ctrl(ptr, 1, 0); 848170031Sjoel DELAY(I2C_DELAY); 849170031Sjoel ctrl(ptr, 0, 0); 850170031Sjoel DELAY(I2C_DELAY); 851170031Sjoel} 852170031Sjoel 853170031Sjoelstatic void 854170031Sjoeli2c_stop(void *codec, void (*ctrl)(void*, unsigned int, unsigned int)) 855170031Sjoel{ 856170031Sjoel struct envy24_delta_ak4524_codec *ptr = codec; 857170031Sjoel 858170031Sjoel ctrl(ptr, 0, 0); 859170031Sjoel DELAY(I2C_DELAY); 860170031Sjoel ctrl(ptr, 1, 0); 861170031Sjoel DELAY(I2C_DELAY); 862170031Sjoel ctrl(ptr, 1, 1); 863170031Sjoel DELAY(I2C_DELAY); 864170031Sjoel} 865170031Sjoel 866170031Sjoelstatic void 867170031Sjoeli2c_ack(void *codec, void (*ctrl)(void*, unsigned int, unsigned int)) 868170031Sjoel{ 869170031Sjoel struct envy24_delta_ak4524_codec *ptr = codec; 870170031Sjoel 871170031Sjoel ctrl(ptr, 0, 1); 872170031Sjoel DELAY(I2C_DELAY); 873170031Sjoel ctrl(ptr, 1, 1); 874170031Sjoel DELAY(I2C_DELAY); 875170031Sjoel /* dummy, need routine to change gpio direction */ 876170031Sjoel ctrl(ptr, 0, 1); 877170031Sjoel DELAY(I2C_DELAY); 878170031Sjoel} 879170031Sjoel 880170031Sjoelstatic void 881170031Sjoeli2c_wr(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), u_int32_t dev, int reg, u_int8_t val) 882170031Sjoel{ 883170031Sjoel struct envy24_delta_ak4524_codec *ptr = codec; 884170031Sjoel int mask; 885170031Sjoel 886170031Sjoel i2c_start(ptr, ctrl); 887170031Sjoel 888170031Sjoel for (mask = 0x80; mask != 0; mask >>= 1) 889170031Sjoel i2c_wrbit(ptr, ctrl, dev & mask); 890170031Sjoel i2c_ack(ptr, ctrl); 891170031Sjoel 892170031Sjoel if (reg != 0xff) { 893170031Sjoel for (mask = 0x80; mask != 0; mask >>= 1) 894170031Sjoel i2c_wrbit(ptr, ctrl, reg & mask); 895170031Sjoel i2c_ack(ptr, ctrl); 896170031Sjoel } 897170031Sjoel 898170031Sjoel for (mask = 0x80; mask != 0; mask >>= 1) 899170031Sjoel i2c_wrbit(ptr, ctrl, val & mask); 900170031Sjoel i2c_ack(ptr, ctrl); 901170031Sjoel 902170031Sjoel i2c_stop(ptr, ctrl); 903170031Sjoel} 904170031Sjoel 905170031Sjoel/* -------------------------------------------------------------------- */ 906170031Sjoel 907170031Sjoel/* M-Audio Delta series AK4524 access interface routine */ 908170031Sjoel 909170031Sjoelstatic void 910159687Snetchildenvy24_delta_ak4524_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti) 911159687Snetchild{ 912159687Snetchild u_int32_t data = 0; 913159687Snetchild struct envy24_delta_ak4524_codec *ptr = codec; 914159687Snetchild 915159687Snetchild#if(0) 916159687Snetchild device_printf(ptr->parent->dev, "--> %d, %d, %d\n", cs, cclk, cdti); 917159687Snetchild#endif 918159687Snetchild data = envy24_gpiord(ptr->parent); 919159687Snetchild data &= ~(ptr->cs | ptr->cclk | ptr->cdti); 920159687Snetchild if (cs) data += ptr->cs; 921159687Snetchild if (cclk) data += ptr->cclk; 922159687Snetchild if (cdti) data += ptr->cdti; 923159687Snetchild envy24_gpiowr(ptr->parent, data); 924159687Snetchild return; 925159687Snetchild} 926159687Snetchild 927159687Snetchildstatic void * 928159687Snetchildenvy24_delta_ak4524_create(device_t dev, void *info, int dir, int num) 929159687Snetchild{ 930159687Snetchild struct sc_info *sc = info; 931159687Snetchild struct envy24_delta_ak4524_codec *buff = NULL; 932159687Snetchild 933159687Snetchild#if(0) 934159687Snetchild device_printf(sc->dev, "envy24_delta_ak4524_create(dev, sc, %d, %d)\n", dir, num); 935159687Snetchild#endif 936159687Snetchild 937159687Snetchild buff = malloc(sizeof(*buff), M_ENVY24, M_NOWAIT); 938159687Snetchild if (buff == NULL) 939159687Snetchild return NULL; 940159687Snetchild 941160796Snetchild if (dir == PCMDIR_REC && sc->adc[num] != NULL) 942159687Snetchild buff->info = ((struct envy24_delta_ak4524_codec *)sc->adc[num])->info; 943160796Snetchild else if (dir == PCMDIR_PLAY && sc->dac[num] != NULL) 944159687Snetchild buff->info = ((struct envy24_delta_ak4524_codec *)sc->dac[num])->info; 945159687Snetchild else 946162876Snetchild buff->info = spicds_create(dev, buff, num, envy24_delta_ak4524_ctl); 947159687Snetchild if (buff->info == NULL) { 948159687Snetchild free(buff, M_ENVY24); 949159687Snetchild return NULL; 950159687Snetchild } 951159687Snetchild 952159687Snetchild buff->parent = sc; 953159687Snetchild buff->dir = dir; 954159687Snetchild buff->num = num; 955159687Snetchild 956159687Snetchild return (void *)buff; 957159687Snetchild} 958159687Snetchild 959159687Snetchildstatic void 960159687Snetchildenvy24_delta_ak4524_destroy(void *codec) 961159687Snetchild{ 962159687Snetchild struct envy24_delta_ak4524_codec *ptr = codec; 963159687Snetchild if (ptr == NULL) 964159687Snetchild return; 965159687Snetchild#if(0) 966159687Snetchild device_printf(ptr->parent->dev, "envy24_delta_ak4524_destroy()\n"); 967159687Snetchild#endif 968159687Snetchild 969159687Snetchild if (ptr->dir == PCMDIR_PLAY) { 970162876Snetchild if (ptr->parent->dac[ptr->num] != NULL) 971162876Snetchild spicds_destroy(ptr->info); 972159687Snetchild } 973159687Snetchild else { 974162876Snetchild if (ptr->parent->adc[ptr->num] != NULL) 975162876Snetchild spicds_destroy(ptr->info); 976159687Snetchild } 977159687Snetchild 978159687Snetchild free(codec, M_ENVY24); 979159687Snetchild} 980159687Snetchild 981159687Snetchildstatic void 982159687Snetchildenvy24_delta_ak4524_init(void *codec) 983159687Snetchild{ 984159689Snetchild#if 0 985159687Snetchild u_int32_t gpiomask, gpiodir; 986159689Snetchild#endif 987159687Snetchild struct envy24_delta_ak4524_codec *ptr = codec; 988159687Snetchild if (ptr == NULL) 989159687Snetchild return; 990159687Snetchild#if(0) 991159687Snetchild device_printf(ptr->parent->dev, "envy24_delta_ak4524_init()\n"); 992159687Snetchild#endif 993159687Snetchild 994159687Snetchild /* 995159687Snetchild gpiomask = envy24_gpiogetmask(ptr->parent); 996159687Snetchild gpiomask &= ~(ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1); 997159687Snetchild envy24_gpiosetmask(ptr->parent, gpiomask); 998159687Snetchild gpiodir = envy24_gpiogetdir(ptr->parent); 999159687Snetchild gpiodir |= ENVY24_GPIO_AK4524_CDTI | ENVY24_GPIO_AK4524_CCLK | ENVY24_GPIO_AK4524_CS0 | ENVY24_GPIO_AK4524_CS1; 1000159687Snetchild envy24_gpiosetdir(ptr->parent, gpiodir); 1001159687Snetchild */ 1002159689Snetchild ptr->cs = ptr->parent->cfg->cs; 1003159689Snetchild#if 0 1004159687Snetchild envy24_gpiosetmask(ptr->parent, ENVY24_GPIO_CS8414_STATUS); 1005159687Snetchild envy24_gpiosetdir(ptr->parent, ~ENVY24_GPIO_CS8414_STATUS); 1006159687Snetchild if (ptr->num == 0) 1007159687Snetchild ptr->cs = ENVY24_GPIO_AK4524_CS0; 1008159687Snetchild else 1009159687Snetchild ptr->cs = ENVY24_GPIO_AK4524_CS1; 1010159687Snetchild ptr->cclk = ENVY24_GPIO_AK4524_CCLK; 1011159689Snetchild#endif 1012159689Snetchild ptr->cclk = ptr->parent->cfg->cclk; 1013159689Snetchild ptr->cdti = ptr->parent->cfg->cdti; 1014162876Snetchild spicds_settype(ptr->info, ptr->parent->cfg->type); 1015162876Snetchild spicds_setcif(ptr->info, ptr->parent->cfg->cif); 1016162876Snetchild spicds_setformat(ptr->info, 1017159687Snetchild AK452X_FORMAT_I2S | AK452X_FORMAT_256FSN | AK452X_FORMAT_1X); 1018169745Sjoel spicds_setdvc(ptr->info, AK452X_DVC_DEMOFF); 1019162876Snetchild /* for the time being, init only first codec */ 1020162876Snetchild if (ptr->num == 0) 1021162876Snetchild spicds_init(ptr->info); 1022170031Sjoel 1023170031Sjoel /* 6fire rear input init test, set ptr->num to 1 for test */ 1024170031Sjoel if (ptr->parent->cfg->subvendor == 0x153b && \ 1025170031Sjoel ptr->parent->cfg->subdevice == 0x1138 && ptr->num == 100) { 1026170031Sjoel ptr->cs = 0x02; 1027170031Sjoel spicds_init(ptr->info); 1028170031Sjoel device_printf(ptr->parent->dev, "6fire rear input init\n"); 1029170031Sjoel i2c_wr(ptr, envy24_gpio_i2c_ctl, \ 1030170031Sjoel PCA9554_I2CDEV, PCA9554_DIR, 0x80); 1031170031Sjoel i2c_wr(ptr, envy24_gpio_i2c_ctl, \ 1032170031Sjoel PCA9554_I2CDEV, PCA9554_OUT, 0x02); 1033170031Sjoel } 1034159687Snetchild} 1035159687Snetchild 1036159687Snetchildstatic void 1037159687Snetchildenvy24_delta_ak4524_reinit(void *codec) 1038159687Snetchild{ 1039159687Snetchild struct envy24_delta_ak4524_codec *ptr = codec; 1040159687Snetchild if (ptr == NULL) 1041159687Snetchild return; 1042159687Snetchild#if(0) 1043159687Snetchild device_printf(ptr->parent->dev, "envy24_delta_ak4524_reinit()\n"); 1044159687Snetchild#endif 1045159687Snetchild 1046162876Snetchild spicds_reinit(ptr->info); 1047159687Snetchild} 1048159687Snetchild 1049159687Snetchildstatic void 1050159687Snetchildenvy24_delta_ak4524_setvolume(void *codec, int dir, unsigned int left, unsigned int right) 1051159687Snetchild{ 1052159687Snetchild struct envy24_delta_ak4524_codec *ptr = codec; 1053159687Snetchild if (ptr == NULL) 1054159687Snetchild return; 1055159687Snetchild#if(0) 1056159687Snetchild device_printf(ptr->parent->dev, "envy24_delta_ak4524_set()\n"); 1057159687Snetchild#endif 1058159687Snetchild 1059162876Snetchild spicds_set(ptr->info, dir, left, right); 1060159687Snetchild} 1061159687Snetchild 1062159687Snetchild/* 1063159687Snetchild There is no need for AK452[48] codec to set sample rate 1064159687Snetchild static void 1065159687Snetchild envy24_delta_ak4524_setrate(struct envy24_delta_ak4524_codec *codec, int which, int rate) 1066159687Snetchild { 1067159687Snetchild } 1068159687Snetchild*/ 1069159687Snetchild 1070159687Snetchild/* -------------------------------------------------------------------- */ 1071159687Snetchild 1072159687Snetchild/* hardware access routeines */ 1073159687Snetchild 1074159687Snetchildstatic struct { 1075159687Snetchild u_int32_t speed; 1076159687Snetchild u_int32_t code; 1077159687Snetchild} envy24_speedtab[] = { 1078159687Snetchild {48000, ENVY24_MT_RATE_48000}, 1079159687Snetchild {24000, ENVY24_MT_RATE_24000}, 1080159687Snetchild {12000, ENVY24_MT_RATE_12000}, 1081159687Snetchild {9600, ENVY24_MT_RATE_9600}, 1082159687Snetchild {32000, ENVY24_MT_RATE_32000}, 1083159687Snetchild {16000, ENVY24_MT_RATE_16000}, 1084159687Snetchild {8000, ENVY24_MT_RATE_8000}, 1085159687Snetchild {96000, ENVY24_MT_RATE_96000}, 1086159687Snetchild {64000, ENVY24_MT_RATE_64000}, 1087159687Snetchild {44100, ENVY24_MT_RATE_44100}, 1088159687Snetchild {22050, ENVY24_MT_RATE_22050}, 1089159687Snetchild {11025, ENVY24_MT_RATE_11025}, 1090159687Snetchild {88200, ENVY24_MT_RATE_88200}, 1091159687Snetchild {0, 0x10} 1092159687Snetchild}; 1093159687Snetchild 1094193640Sariffstatic u_int32_t 1095159687Snetchildenvy24_setspeed(struct sc_info *sc, u_int32_t speed) { 1096159687Snetchild u_int32_t code; 1097159687Snetchild int i = 0; 1098159687Snetchild 1099159687Snetchild#if(0) 1100159687Snetchild device_printf(sc->dev, "envy24_setspeed(sc, %d)\n", speed); 1101159687Snetchild#endif 1102159687Snetchild if (speed == 0) { 1103159687Snetchild code = ENVY24_MT_RATE_SPDIF; /* external master clock */ 1104159687Snetchild envy24_slavecd(sc); 1105159687Snetchild } 1106159687Snetchild else { 1107159687Snetchild for (i = 0; envy24_speedtab[i].speed != 0; i++) { 1108159687Snetchild if (envy24_speedtab[i].speed == speed) 1109159687Snetchild break; 1110159687Snetchild } 1111159687Snetchild code = envy24_speedtab[i].code; 1112159687Snetchild } 1113159687Snetchild#if(0) 1114159687Snetchild device_printf(sc->dev, "envy24_setspeed(): speed %d/code 0x%04x\n", envy24_speedtab[i].speed, code); 1115159687Snetchild#endif 1116159687Snetchild if (code < 0x10) { 1117159687Snetchild envy24_wrmt(sc, ENVY24_MT_RATE, code, 1); 1118159687Snetchild code = envy24_rdmt(sc, ENVY24_MT_RATE, 1); 1119159687Snetchild code &= ENVY24_MT_RATE_MASK; 1120159687Snetchild for (i = 0; envy24_speedtab[i].code < 0x10; i++) { 1121159687Snetchild if (envy24_speedtab[i].code == code) 1122159687Snetchild break; 1123159687Snetchild } 1124159687Snetchild speed = envy24_speedtab[i].speed; 1125159687Snetchild } 1126159687Snetchild else 1127159687Snetchild speed = 0; 1128159687Snetchild 1129159687Snetchild#if(0) 1130159687Snetchild device_printf(sc->dev, "envy24_setspeed(): return %d\n", speed); 1131159687Snetchild#endif 1132159687Snetchild return speed; 1133159687Snetchild} 1134159687Snetchild 1135159687Snetchildstatic void 1136159687Snetchildenvy24_setvolume(struct sc_info *sc, unsigned ch) 1137159687Snetchild{ 1138159687Snetchild#if(0) 1139159687Snetchild device_printf(sc->dev, "envy24_setvolume(sc, %d)\n", ch); 1140159687Snetchild#endif 1141159689Snetchildif (sc->cfg->subvendor==0x153b && sc->cfg->subdevice==0x1138 ) { 1142159689Snetchild envy24_wrmt(sc, ENVY24_MT_VOLIDX, 16, 1); 1143159689Snetchild envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2); 1144159689Snetchild envy24_wrmt(sc, ENVY24_MT_VOLIDX, 17, 1); 1145159689Snetchild envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f7f, 2); 1146159689Snetchild } 1147159689Snetchild 1148159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1); 1149159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLUME, 0x7f00 | sc->left[ch], 2); 1150159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1); 1151159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLUME, (sc->right[ch] << 8) | 0x7f, 2); 1152159687Snetchild} 1153159687Snetchild 1154159687Snetchildstatic void 1155159687Snetchildenvy24_mutevolume(struct sc_info *sc, unsigned ch) 1156159687Snetchild{ 1157159687Snetchild u_int32_t vol; 1158159687Snetchild 1159159687Snetchild#if(0) 1160159687Snetchild device_printf(sc->dev, "envy24_mutevolume(sc, %d)\n", ch); 1161159687Snetchild#endif 1162159687Snetchild vol = ENVY24_VOL_MUTE << 8 | ENVY24_VOL_MUTE; 1163159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2, 1); 1164159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2); 1165159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLIDX, ch * 2 + 1, 1); 1166159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLUME, vol, 2); 1167159687Snetchild} 1168159687Snetchild 1169159687Snetchildstatic u_int32_t 1170159687Snetchildenvy24_gethwptr(struct sc_info *sc, int dir) 1171159687Snetchild{ 1172159687Snetchild int unit, regno; 1173159687Snetchild u_int32_t ptr, rtn; 1174159687Snetchild 1175159687Snetchild#if(0) 1176159687Snetchild device_printf(sc->dev, "envy24_gethwptr(sc, %d)\n", dir); 1177159687Snetchild#endif 1178159687Snetchild if (dir == PCMDIR_PLAY) { 1179159687Snetchild rtn = sc->psize / 4; 1180159687Snetchild unit = ENVY24_PLAY_BUFUNIT / 4; 1181159687Snetchild regno = ENVY24_MT_PCNT; 1182159687Snetchild } 1183159687Snetchild else { 1184159687Snetchild rtn = sc->rsize / 4; 1185159687Snetchild unit = ENVY24_REC_BUFUNIT / 4; 1186159687Snetchild regno = ENVY24_MT_RCNT; 1187159687Snetchild } 1188159687Snetchild 1189159687Snetchild ptr = envy24_rdmt(sc, regno, 2); 1190159687Snetchild rtn -= (ptr + 1); 1191159687Snetchild rtn /= unit; 1192159687Snetchild 1193159687Snetchild#if(0) 1194159687Snetchild device_printf(sc->dev, "envy24_gethwptr(): return %d\n", rtn); 1195159687Snetchild#endif 1196159687Snetchild return rtn; 1197159687Snetchild} 1198159687Snetchild 1199159687Snetchildstatic void 1200159687Snetchildenvy24_updintr(struct sc_info *sc, int dir) 1201159687Snetchild{ 1202159687Snetchild int regptr, regintr; 1203159687Snetchild u_int32_t mask, intr; 1204159687Snetchild u_int32_t ptr, size, cnt; 1205159687Snetchild u_int16_t blk; 1206159687Snetchild 1207159687Snetchild#if(0) 1208159687Snetchild device_printf(sc->dev, "envy24_updintr(sc, %d)\n", dir); 1209159687Snetchild#endif 1210159687Snetchild if (dir == PCMDIR_PLAY) { 1211159687Snetchild blk = sc->blk[0]; 1212159687Snetchild size = sc->psize / 4; 1213159687Snetchild regptr = ENVY24_MT_PCNT; 1214159687Snetchild regintr = ENVY24_MT_PTERM; 1215159687Snetchild mask = ~ENVY24_MT_INT_PMASK; 1216159687Snetchild } 1217159687Snetchild else { 1218159687Snetchild blk = sc->blk[1]; 1219159687Snetchild size = sc->rsize / 4; 1220159687Snetchild regptr = ENVY24_MT_RCNT; 1221159687Snetchild regintr = ENVY24_MT_RTERM; 1222159687Snetchild mask = ~ENVY24_MT_INT_RMASK; 1223159687Snetchild } 1224159687Snetchild 1225159687Snetchild ptr = size - envy24_rdmt(sc, regptr, 2) - 1; 1226159687Snetchild /* 1227159687Snetchild cnt = blk - ptr % blk - 1; 1228159687Snetchild if (cnt == 0) 1229159687Snetchild cnt = blk - 1; 1230159687Snetchild */ 1231159687Snetchild cnt = blk - 1; 1232159687Snetchild#if(0) 1233159687Snetchild device_printf(sc->dev, "envy24_updintr():ptr = %d, blk = %d, cnt = %d\n", ptr, blk, cnt); 1234159687Snetchild#endif 1235159687Snetchild envy24_wrmt(sc, regintr, cnt, 2); 1236159687Snetchild intr = envy24_rdmt(sc, ENVY24_MT_INT, 1); 1237159687Snetchild#if(0) 1238159687Snetchild device_printf(sc->dev, "envy24_updintr():intr = 0x%02x, mask = 0x%02x\n", intr, mask); 1239159687Snetchild#endif 1240159687Snetchild envy24_wrmt(sc, ENVY24_MT_INT, intr & mask, 1); 1241159687Snetchild#if(0) 1242159687Snetchild device_printf(sc->dev, "envy24_updintr():INT-->0x%02x\n", 1243159687Snetchild envy24_rdmt(sc, ENVY24_MT_INT, 1)); 1244159687Snetchild#endif 1245159687Snetchild 1246159687Snetchild return; 1247159687Snetchild} 1248159687Snetchild 1249159689Snetchild#if 0 1250159687Snetchildstatic void 1251159687Snetchildenvy24_maskintr(struct sc_info *sc, int dir) 1252159687Snetchild{ 1253159687Snetchild u_int32_t mask, intr; 1254159687Snetchild 1255159687Snetchild#if(0) 1256159687Snetchild device_printf(sc->dev, "envy24_maskintr(sc, %d)\n", dir); 1257159687Snetchild#endif 1258159687Snetchild if (dir == PCMDIR_PLAY) 1259159687Snetchild mask = ENVY24_MT_INT_PMASK; 1260159687Snetchild else 1261159687Snetchild mask = ENVY24_MT_INT_RMASK; 1262159687Snetchild intr = envy24_rdmt(sc, ENVY24_MT_INT, 1); 1263159687Snetchild envy24_wrmt(sc, ENVY24_MT_INT, intr | mask, 1); 1264159687Snetchild 1265159687Snetchild return; 1266159687Snetchild} 1267159689Snetchild#endif 1268159687Snetchild 1269159687Snetchildstatic int 1270159687Snetchildenvy24_checkintr(struct sc_info *sc, int dir) 1271159687Snetchild{ 1272159687Snetchild u_int32_t mask, stat, intr, rtn; 1273159687Snetchild 1274159687Snetchild#if(0) 1275159687Snetchild device_printf(sc->dev, "envy24_checkintr(sc, %d)\n", dir); 1276159687Snetchild#endif 1277159687Snetchild intr = envy24_rdmt(sc, ENVY24_MT_INT, 1); 1278159687Snetchild if (dir == PCMDIR_PLAY) { 1279159687Snetchild if ((rtn = intr & ENVY24_MT_INT_PSTAT) != 0) { 1280159687Snetchild mask = ~ENVY24_MT_INT_RSTAT; 1281159687Snetchild stat = ENVY24_MT_INT_PSTAT | ENVY24_MT_INT_PMASK; 1282159687Snetchild envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1); 1283159687Snetchild } 1284159687Snetchild } 1285159687Snetchild else { 1286159687Snetchild if ((rtn = intr & ENVY24_MT_INT_RSTAT) != 0) { 1287159687Snetchild mask = ~ENVY24_MT_INT_PSTAT; 1288159687Snetchild stat = ENVY24_MT_INT_RSTAT | ENVY24_MT_INT_RMASK; 1289159687Snetchild envy24_wrmt(sc, ENVY24_MT_INT, (intr & mask) | stat, 1); 1290159687Snetchild } 1291159687Snetchild } 1292159687Snetchild 1293159687Snetchild return rtn; 1294159687Snetchild} 1295159687Snetchild 1296159687Snetchildstatic void 1297159687Snetchildenvy24_start(struct sc_info *sc, int dir) 1298159687Snetchild{ 1299159687Snetchild u_int32_t stat, sw; 1300159687Snetchild 1301159687Snetchild#if(0) 1302159687Snetchild device_printf(sc->dev, "envy24_start(sc, %d)\n", dir); 1303159687Snetchild#endif 1304159687Snetchild if (dir == PCMDIR_PLAY) 1305159687Snetchild sw = ENVY24_MT_PCTL_PSTART; 1306159687Snetchild else 1307159687Snetchild sw = ENVY24_MT_PCTL_RSTART; 1308159687Snetchild 1309159687Snetchild stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1); 1310159687Snetchild envy24_wrmt(sc, ENVY24_MT_PCTL, stat | sw, 1); 1311159687Snetchild#if(0) 1312159687Snetchild DELAY(100); 1313159687Snetchild device_printf(sc->dev, "PADDR:0x%08x\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4)); 1314159687Snetchild device_printf(sc->dev, "PCNT:%ld\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2)); 1315159687Snetchild#endif 1316159687Snetchild 1317159687Snetchild return; 1318159687Snetchild} 1319159687Snetchild 1320159687Snetchildstatic void 1321159687Snetchildenvy24_stop(struct sc_info *sc, int dir) 1322159687Snetchild{ 1323159687Snetchild u_int32_t stat, sw; 1324159687Snetchild 1325159687Snetchild#if(0) 1326159687Snetchild device_printf(sc->dev, "envy24_stop(sc, %d)\n", dir); 1327159687Snetchild#endif 1328159687Snetchild if (dir == PCMDIR_PLAY) 1329159687Snetchild sw = ~ENVY24_MT_PCTL_PSTART; 1330159687Snetchild else 1331159687Snetchild sw = ~ENVY24_MT_PCTL_RSTART; 1332159687Snetchild 1333159687Snetchild stat = envy24_rdmt(sc, ENVY24_MT_PCTL, 1); 1334159687Snetchild envy24_wrmt(sc, ENVY24_MT_PCTL, stat & sw, 1); 1335159687Snetchild 1336159687Snetchild return; 1337159687Snetchild} 1338159687Snetchild 1339159687Snetchildstatic int 1340159687Snetchildenvy24_route(struct sc_info *sc, int dac, int class, int adc, int rev) 1341159687Snetchild{ 1342159687Snetchild u_int32_t reg, mask; 1343159687Snetchild u_int32_t left, right; 1344159687Snetchild 1345159687Snetchild#if(0) 1346159687Snetchild device_printf(sc->dev, "envy24_route(sc, %d, %d, %d, %d)\n", 1347159687Snetchild dac, class, adc, rev); 1348159687Snetchild#endif 1349159687Snetchild /* parameter pattern check */ 1350159687Snetchild if (dac < 0 || ENVY24_ROUTE_DAC_SPDIF < dac) 1351159687Snetchild return -1; 1352159687Snetchild if (class == ENVY24_ROUTE_CLASS_MIX && 1353159687Snetchild (dac != ENVY24_ROUTE_DAC_1 && dac != ENVY24_ROUTE_DAC_SPDIF)) 1354159687Snetchild return -1; 1355159687Snetchild if (rev) { 1356159687Snetchild left = ENVY24_ROUTE_RIGHT; 1357159687Snetchild right = ENVY24_ROUTE_LEFT; 1358159687Snetchild } 1359159687Snetchild else { 1360159687Snetchild left = ENVY24_ROUTE_LEFT; 1361159687Snetchild right = ENVY24_ROUTE_RIGHT; 1362159687Snetchild } 1363159687Snetchild 1364159687Snetchild if (dac == ENVY24_ROUTE_DAC_SPDIF) { 1365159687Snetchild reg = class | class << 2 | 1366159687Snetchild ((adc << 1 | left) | left << 3) << 8 | 1367159687Snetchild ((adc << 1 | right) | right << 3) << 12; 1368159687Snetchild#if(0) 1369159687Snetchild device_printf(sc->dev, "envy24_route(): MT_SPDOUT-->0x%04x\n", reg); 1370159687Snetchild#endif 1371159687Snetchild envy24_wrmt(sc, ENVY24_MT_SPDOUT, reg, 2); 1372159687Snetchild } 1373159687Snetchild else { 1374159687Snetchild mask = ~(0x0303 << dac * 2); 1375159687Snetchild reg = envy24_rdmt(sc, ENVY24_MT_PSDOUT, 2); 1376159687Snetchild reg = (reg & mask) | ((class | class << 8) << dac * 2); 1377159687Snetchild#if(0) 1378159687Snetchild device_printf(sc->dev, "envy24_route(): MT_PSDOUT-->0x%04x\n", reg); 1379159687Snetchild#endif 1380159687Snetchild envy24_wrmt(sc, ENVY24_MT_PSDOUT, reg, 2); 1381159687Snetchild mask = ~(0xff << dac * 8); 1382159687Snetchild reg = envy24_rdmt(sc, ENVY24_MT_RECORD, 4); 1383159687Snetchild reg = (reg & mask) | 1384159687Snetchild (((adc << 1 | left) | left << 3) | 1385159687Snetchild ((adc << 1 | right) | right << 3) << 4) << dac * 8; 1386159687Snetchild#if(0) 1387159687Snetchild device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg); 1388159687Snetchild#endif 1389159687Snetchild envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4); 1390170031Sjoel 1391170031Sjoel /* 6fire rear input init test */ 1392170031Sjoel envy24_wrmt(sc, ENVY24_MT_RECORD, 0x00, 4); 1393159687Snetchild } 1394159687Snetchild 1395159687Snetchild return 0; 1396159687Snetchild} 1397159687Snetchild 1398159687Snetchild/* -------------------------------------------------------------------- */ 1399159687Snetchild 1400159687Snetchild/* buffer copy routines */ 1401159687Snetchildstatic void 1402159687Snetchildenvy24_p32sl(struct sc_chinfo *ch) 1403159687Snetchild{ 1404159687Snetchild int length; 1405159687Snetchild sample32_t *dmabuf; 1406159687Snetchild u_int32_t *data; 1407159687Snetchild int src, dst, ssize, dsize, slot; 1408159687Snetchild int i; 1409159687Snetchild 1410159687Snetchild length = sndbuf_getready(ch->buffer) / 8; 1411159687Snetchild dmabuf = ch->parent->pbuf; 1412159687Snetchild data = (u_int32_t *)ch->data; 1413159687Snetchild src = sndbuf_getreadyptr(ch->buffer) / 4; 1414159687Snetchild dst = src / 2 + ch->offset; 1415159687Snetchild ssize = ch->size / 4; 1416159687Snetchild dsize = ch->size / 8; 1417159687Snetchild slot = ch->num * 2; 1418159687Snetchild 1419159687Snetchild for (i = 0; i < length; i++) { 1420159689Snetchild dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = data[src]; 1421159689Snetchild dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = data[src + 1]; 1422159687Snetchild dst++; 1423159687Snetchild dst %= dsize; 1424159687Snetchild src += 2; 1425159687Snetchild src %= ssize; 1426159687Snetchild } 1427159687Snetchild 1428159687Snetchild return; 1429159687Snetchild} 1430159687Snetchild 1431159687Snetchildstatic void 1432159687Snetchildenvy24_p16sl(struct sc_chinfo *ch) 1433159687Snetchild{ 1434159687Snetchild int length; 1435159687Snetchild sample32_t *dmabuf; 1436159687Snetchild u_int16_t *data; 1437159687Snetchild int src, dst, ssize, dsize, slot; 1438159687Snetchild int i; 1439159687Snetchild 1440159687Snetchild#if(0) 1441159687Snetchild device_printf(ch->parent->dev, "envy24_p16sl()\n"); 1442159687Snetchild#endif 1443159687Snetchild length = sndbuf_getready(ch->buffer) / 4; 1444159687Snetchild dmabuf = ch->parent->pbuf; 1445159687Snetchild data = (u_int16_t *)ch->data; 1446159687Snetchild src = sndbuf_getreadyptr(ch->buffer) / 2; 1447159687Snetchild dst = src / 2 + ch->offset; 1448159687Snetchild ssize = ch->size / 2; 1449159687Snetchild dsize = ch->size / 4; 1450159687Snetchild slot = ch->num * 2; 1451159687Snetchild#if(0) 1452159687Snetchild device_printf(ch->parent->dev, "envy24_p16sl():%lu-->%lu(%lu)\n", src, dst, length); 1453159687Snetchild#endif 1454159687Snetchild 1455159687Snetchild for (i = 0; i < length; i++) { 1456159689Snetchild dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = (u_int32_t)data[src] << 16; 1457159689Snetchild dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = (u_int32_t)data[src + 1] << 16; 1458159687Snetchild#if(0) 1459159687Snetchild if (i < 16) { 1460159687Snetchild printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot]); 1461159687Snetchild printf("%08x", dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1]); 1462159687Snetchild } 1463159687Snetchild#endif 1464159687Snetchild dst++; 1465159687Snetchild dst %= dsize; 1466159687Snetchild src += 2; 1467159687Snetchild src %= ssize; 1468159687Snetchild } 1469159687Snetchild#if(0) 1470159687Snetchild printf("\n"); 1471159687Snetchild#endif 1472159687Snetchild 1473159687Snetchild return; 1474159687Snetchild} 1475159687Snetchild 1476159687Snetchildstatic void 1477159687Snetchildenvy24_p8u(struct sc_chinfo *ch) 1478159687Snetchild{ 1479159687Snetchild int length; 1480159687Snetchild sample32_t *dmabuf; 1481159687Snetchild u_int8_t *data; 1482159687Snetchild int src, dst, ssize, dsize, slot; 1483159687Snetchild int i; 1484159687Snetchild 1485159687Snetchild length = sndbuf_getready(ch->buffer) / 2; 1486159687Snetchild dmabuf = ch->parent->pbuf; 1487159687Snetchild data = (u_int8_t *)ch->data; 1488159687Snetchild src = sndbuf_getreadyptr(ch->buffer); 1489159687Snetchild dst = src / 2 + ch->offset; 1490159687Snetchild ssize = ch->size; 1491159687Snetchild dsize = ch->size / 4; 1492159687Snetchild slot = ch->num * 2; 1493159687Snetchild 1494159687Snetchild for (i = 0; i < length; i++) { 1495159689Snetchild dmabuf[dst * ENVY24_PLAY_CHNUM + slot].buffer = ((u_int32_t)data[src] ^ 0x80) << 24; 1496159689Snetchild dmabuf[dst * ENVY24_PLAY_CHNUM + slot + 1].buffer = ((u_int32_t)data[src + 1] ^ 0x80) << 24; 1497159687Snetchild dst++; 1498159687Snetchild dst %= dsize; 1499159687Snetchild src += 2; 1500159687Snetchild src %= ssize; 1501159687Snetchild } 1502159687Snetchild 1503159687Snetchild return; 1504159687Snetchild} 1505159687Snetchild 1506159687Snetchildstatic void 1507159687Snetchildenvy24_r32sl(struct sc_chinfo *ch) 1508159687Snetchild{ 1509159687Snetchild int length; 1510159687Snetchild sample32_t *dmabuf; 1511159687Snetchild u_int32_t *data; 1512159687Snetchild int src, dst, ssize, dsize, slot; 1513159687Snetchild int i; 1514159687Snetchild 1515159687Snetchild length = sndbuf_getfree(ch->buffer) / 8; 1516159687Snetchild dmabuf = ch->parent->rbuf; 1517159687Snetchild data = (u_int32_t *)ch->data; 1518159687Snetchild dst = sndbuf_getfreeptr(ch->buffer) / 4; 1519159687Snetchild src = dst / 2 + ch->offset; 1520159687Snetchild dsize = ch->size / 4; 1521159687Snetchild ssize = ch->size / 8; 1522159687Snetchild slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2; 1523159687Snetchild 1524159687Snetchild for (i = 0; i < length; i++) { 1525159689Snetchild data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer; 1526159689Snetchild data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer; 1527159687Snetchild dst += 2; 1528159687Snetchild dst %= dsize; 1529159687Snetchild src++; 1530159687Snetchild src %= ssize; 1531159687Snetchild } 1532159687Snetchild 1533159687Snetchild return; 1534159687Snetchild} 1535159687Snetchild 1536159687Snetchildstatic void 1537159687Snetchildenvy24_r16sl(struct sc_chinfo *ch) 1538159687Snetchild{ 1539159687Snetchild int length; 1540159687Snetchild sample32_t *dmabuf; 1541159689Snetchild u_int16_t *data; 1542159687Snetchild int src, dst, ssize, dsize, slot; 1543159687Snetchild int i; 1544159687Snetchild 1545159687Snetchild length = sndbuf_getfree(ch->buffer) / 4; 1546159687Snetchild dmabuf = ch->parent->rbuf; 1547159687Snetchild data = (u_int16_t *)ch->data; 1548159687Snetchild dst = sndbuf_getfreeptr(ch->buffer) / 2; 1549159687Snetchild src = dst / 2 + ch->offset; 1550159687Snetchild dsize = ch->size / 2; 1551159687Snetchild ssize = ch->size / 8; 1552159687Snetchild slot = (ch->num - ENVY24_CHAN_REC_ADC1) * 2; 1553159687Snetchild 1554159687Snetchild for (i = 0; i < length; i++) { 1555159689Snetchild data[dst] = dmabuf[src * ENVY24_REC_CHNUM + slot].buffer; 1556159689Snetchild data[dst + 1] = dmabuf[src * ENVY24_REC_CHNUM + slot + 1].buffer; 1557159687Snetchild dst += 2; 1558159687Snetchild dst %= dsize; 1559159687Snetchild src++; 1560159687Snetchild src %= ssize; 1561159687Snetchild } 1562159687Snetchild 1563159687Snetchild return; 1564159687Snetchild} 1565159687Snetchild 1566159687Snetchild/* -------------------------------------------------------------------- */ 1567159687Snetchild 1568159687Snetchild/* channel interface */ 1569159687Snetchildstatic void * 1570159687Snetchildenvy24chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c, int dir) 1571159687Snetchild{ 1572159687Snetchild struct sc_info *sc = (struct sc_info *)devinfo; 1573159687Snetchild struct sc_chinfo *ch; 1574159687Snetchild unsigned num; 1575159687Snetchild 1576159687Snetchild#if(0) 1577159687Snetchild device_printf(sc->dev, "envy24chan_init(obj, devinfo, b, c, %d)\n", dir); 1578159687Snetchild#endif 1579159687Snetchild snd_mtxlock(sc->lock); 1580159687Snetchild if ((sc->chnum > ENVY24_CHAN_PLAY_SPDIF && dir != PCMDIR_REC) || 1581159687Snetchild (sc->chnum < ENVY24_CHAN_REC_ADC1 && dir != PCMDIR_PLAY)) { 1582159687Snetchild snd_mtxunlock(sc->lock); 1583159687Snetchild return NULL; 1584159687Snetchild } 1585159687Snetchild num = sc->chnum; 1586159687Snetchild 1587159687Snetchild ch = &sc->chan[num]; 1588159687Snetchild ch->size = 8 * ENVY24_SAMPLE_NUM; 1589159687Snetchild ch->data = malloc(ch->size, M_ENVY24, M_NOWAIT); 1590159687Snetchild if (ch->data == NULL) { 1591159687Snetchild ch->size = 0; 1592159687Snetchild ch = NULL; 1593159687Snetchild } 1594159687Snetchild else { 1595159687Snetchild ch->buffer = b; 1596159687Snetchild ch->channel = c; 1597159687Snetchild ch->parent = sc; 1598159687Snetchild ch->dir = dir; 1599159687Snetchild /* set channel map */ 1600159687Snetchild ch->num = envy24_chanmap[num]; 1601165306Sariff snd_mtxunlock(sc->lock); 1602159687Snetchild sndbuf_setup(ch->buffer, ch->data, ch->size); 1603165306Sariff snd_mtxlock(sc->lock); 1604159687Snetchild /* these 2 values are dummy */ 1605159687Snetchild ch->unit = 4; 1606159687Snetchild ch->blk = 10240; 1607159687Snetchild } 1608159687Snetchild snd_mtxunlock(sc->lock); 1609159687Snetchild 1610159687Snetchild return ch; 1611159687Snetchild} 1612159687Snetchild 1613159687Snetchildstatic int 1614159687Snetchildenvy24chan_free(kobj_t obj, void *data) 1615159687Snetchild{ 1616159687Snetchild struct sc_chinfo *ch = data; 1617159687Snetchild struct sc_info *sc = ch->parent; 1618159687Snetchild 1619159687Snetchild#if(0) 1620159687Snetchild device_printf(sc->dev, "envy24chan_free()\n"); 1621159687Snetchild#endif 1622159687Snetchild snd_mtxlock(sc->lock); 1623159687Snetchild if (ch->data != NULL) { 1624159687Snetchild free(ch->data, M_ENVY24); 1625159687Snetchild ch->data = NULL; 1626159687Snetchild } 1627159687Snetchild snd_mtxunlock(sc->lock); 1628159687Snetchild 1629159687Snetchild return 0; 1630159687Snetchild} 1631159687Snetchild 1632159687Snetchildstatic int 1633159687Snetchildenvy24chan_setformat(kobj_t obj, void *data, u_int32_t format) 1634159687Snetchild{ 1635159687Snetchild struct sc_chinfo *ch = data; 1636159687Snetchild struct sc_info *sc = ch->parent; 1637159687Snetchild struct envy24_emldma *emltab; 1638165306Sariff /* unsigned int bcnt, bsize; */ 1639159687Snetchild int i; 1640159687Snetchild 1641159687Snetchild#if(0) 1642159687Snetchild device_printf(sc->dev, "envy24chan_setformat(obj, data, 0x%08x)\n", format); 1643159687Snetchild#endif 1644159687Snetchild snd_mtxlock(sc->lock); 1645159687Snetchild /* check and get format related information */ 1646159687Snetchild if (ch->dir == PCMDIR_PLAY) 1647159687Snetchild emltab = envy24_pemltab; 1648159687Snetchild else 1649159687Snetchild emltab = envy24_remltab; 1650159687Snetchild if (emltab == NULL) { 1651159687Snetchild snd_mtxunlock(sc->lock); 1652159687Snetchild return -1; 1653159687Snetchild } 1654159687Snetchild for (i = 0; emltab[i].format != 0; i++) 1655159687Snetchild if (emltab[i].format == format) 1656159687Snetchild break; 1657159687Snetchild if (emltab[i].format == 0) { 1658159687Snetchild snd_mtxunlock(sc->lock); 1659159687Snetchild return -1; 1660159687Snetchild } 1661159687Snetchild 1662159687Snetchild /* set format information */ 1663159687Snetchild ch->format = format; 1664159687Snetchild ch->emldma = emltab[i].emldma; 1665159687Snetchild if (ch->unit > emltab[i].unit) 1666159687Snetchild ch->blk *= ch->unit / emltab[i].unit; 1667159687Snetchild else 1668159687Snetchild ch->blk /= emltab[i].unit / ch->unit; 1669159687Snetchild ch->unit = emltab[i].unit; 1670159687Snetchild 1671159687Snetchild /* set channel buffer information */ 1672159687Snetchild ch->size = ch->unit * ENVY24_SAMPLE_NUM; 1673165306Sariff#if 0 1674159687Snetchild if (ch->dir == PCMDIR_PLAY) 1675159687Snetchild bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT; 1676159687Snetchild else 1677159687Snetchild bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT; 1678159687Snetchild bsize *= ch->unit; 1679159687Snetchild bcnt = ch->size / bsize; 1680159687Snetchild sndbuf_resize(ch->buffer, bcnt, bsize); 1681165306Sariff#endif 1682159687Snetchild snd_mtxunlock(sc->lock); 1683159687Snetchild 1684159687Snetchild#if(0) 1685159687Snetchild device_printf(sc->dev, "envy24chan_setformat(): return 0x%08x\n", 0); 1686159687Snetchild#endif 1687159687Snetchild return 0; 1688159687Snetchild} 1689159687Snetchild 1690159687Snetchild/* 1691159687Snetchild IMPLEMENT NOTICE: In this driver, setspeed function only do setting 1692159687Snetchild of speed information value. And real hardware speed setting is done 1693159687Snetchild at start triggered(see envy24chan_trigger()). So, at this function 1694159687Snetchild is called, any value that ENVY24 can use is able to set. But, at 1695159687Snetchild start triggerd, some other channel is running, and that channel's 1696159687Snetchild speed isn't same with, then trigger function will fail. 1697159687Snetchild*/ 1698193640Sariffstatic u_int32_t 1699159687Snetchildenvy24chan_setspeed(kobj_t obj, void *data, u_int32_t speed) 1700159687Snetchild{ 1701159687Snetchild struct sc_chinfo *ch = data; 1702159687Snetchild u_int32_t val, prev; 1703159687Snetchild int i; 1704159687Snetchild 1705159687Snetchild#if(0) 1706159687Snetchild device_printf(ch->parent->dev, "envy24chan_setspeed(obj, data, %d)\n", speed); 1707159687Snetchild#endif 1708159687Snetchild prev = 0x7fffffff; 1709159687Snetchild for (i = 0; (val = envy24_speed[i]) != 0; i++) { 1710159687Snetchild if (abs(val - speed) < abs(prev - speed)) 1711159687Snetchild prev = val; 1712159687Snetchild else 1713159687Snetchild break; 1714159687Snetchild } 1715159687Snetchild ch->speed = prev; 1716159687Snetchild 1717159687Snetchild#if(0) 1718159687Snetchild device_printf(ch->parent->dev, "envy24chan_setspeed(): return %d\n", ch->speed); 1719159687Snetchild#endif 1720159687Snetchild return ch->speed; 1721159687Snetchild} 1722159687Snetchild 1723193640Sariffstatic u_int32_t 1724159687Snetchildenvy24chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize) 1725159687Snetchild{ 1726159687Snetchild struct sc_chinfo *ch = data; 1727165306Sariff /* struct sc_info *sc = ch->parent; */ 1728159687Snetchild u_int32_t size, prev; 1729165306Sariff unsigned int bcnt, bsize; 1730159687Snetchild 1731159687Snetchild#if(0) 1732159687Snetchild device_printf(sc->dev, "envy24chan_setblocksize(obj, data, %d)\n", blocksize); 1733159687Snetchild#endif 1734159687Snetchild prev = 0x7fffffff; 1735165306Sariff /* snd_mtxlock(sc->lock); */ 1736159687Snetchild for (size = ch->size / 2; size > 0; size /= 2) { 1737159687Snetchild if (abs(size - blocksize) < abs(prev - blocksize)) 1738159687Snetchild prev = size; 1739159687Snetchild else 1740159687Snetchild break; 1741159687Snetchild } 1742159687Snetchild 1743159687Snetchild ch->blk = prev / ch->unit; 1744159687Snetchild if (ch->dir == PCMDIR_PLAY) 1745159687Snetchild ch->blk *= ENVY24_PLAY_BUFUNIT / 4; 1746159687Snetchild else 1747159687Snetchild ch->blk *= ENVY24_REC_BUFUNIT / 4; 1748165306Sariff /* set channel buffer information */ 1749165306Sariff /* ch->size = ch->unit * ENVY24_SAMPLE_NUM; */ 1750165306Sariff if (ch->dir == PCMDIR_PLAY) 1751165306Sariff bsize = ch->blk * 4 / ENVY24_PLAY_BUFUNIT; 1752165306Sariff else 1753165306Sariff bsize = ch->blk * 4 / ENVY24_REC_BUFUNIT; 1754165306Sariff bsize *= ch->unit; 1755165306Sariff bcnt = ch->size / bsize; 1756165306Sariff sndbuf_resize(ch->buffer, bcnt, bsize); 1757165306Sariff /* snd_mtxunlock(sc->lock); */ 1758159687Snetchild 1759159687Snetchild#if(0) 1760159687Snetchild device_printf(sc->dev, "envy24chan_setblocksize(): return %d\n", prev); 1761159687Snetchild#endif 1762159687Snetchild return prev; 1763159687Snetchild} 1764159687Snetchild 1765159687Snetchild/* semantic note: must start at beginning of buffer */ 1766159687Snetchildstatic int 1767159687Snetchildenvy24chan_trigger(kobj_t obj, void *data, int go) 1768159687Snetchild{ 1769159687Snetchild struct sc_chinfo *ch = data; 1770159687Snetchild struct sc_info *sc = ch->parent; 1771159687Snetchild u_int32_t ptr; 1772159687Snetchild int slot; 1773191308Sstas int error = 0; 1774160796Snetchild#if 0 1775159687Snetchild int i; 1776159687Snetchild 1777159687Snetchild device_printf(sc->dev, "envy24chan_trigger(obj, data, %d)\n", go); 1778159687Snetchild#endif 1779159687Snetchild snd_mtxlock(sc->lock); 1780159687Snetchild if (ch->dir == PCMDIR_PLAY) 1781159687Snetchild slot = 0; 1782159687Snetchild else 1783159687Snetchild slot = 1; 1784159687Snetchild switch (go) { 1785159687Snetchild case PCMTRIG_START: 1786159687Snetchild#if(0) 1787159687Snetchild device_printf(sc->dev, "envy24chan_trigger(): start\n"); 1788159687Snetchild#endif 1789159687Snetchild /* check or set channel speed */ 1790159687Snetchild if (sc->run[0] == 0 && sc->run[1] == 0) { 1791159687Snetchild sc->speed = envy24_setspeed(sc, ch->speed); 1792159687Snetchild sc->caps[0].minspeed = sc->caps[0].maxspeed = sc->speed; 1793159687Snetchild sc->caps[1].minspeed = sc->caps[1].maxspeed = sc->speed; 1794159687Snetchild } 1795191308Sstas else if (ch->speed != 0 && ch->speed != sc->speed) { 1796191308Sstas error = -1; 1797191308Sstas goto fail; 1798191308Sstas } 1799159687Snetchild if (ch->speed == 0) 1800159687Snetchild ch->channel->speed = sc->speed; 1801159687Snetchild /* start or enable channel */ 1802159687Snetchild sc->run[slot]++; 1803159687Snetchild if (sc->run[slot] == 1) { 1804159687Snetchild /* first channel */ 1805159687Snetchild ch->offset = 0; 1806159687Snetchild sc->blk[slot] = ch->blk; 1807159687Snetchild } 1808159687Snetchild else { 1809159687Snetchild ptr = envy24_gethwptr(sc, ch->dir); 1810159687Snetchild ch->offset = ((ptr / ch->blk + 1) * ch->blk % 1811159687Snetchild (ch->size / 4)) * 4 / ch->unit; 1812159687Snetchild if (ch->blk < sc->blk[slot]) 1813159687Snetchild sc->blk[slot] = ch->blk; 1814159687Snetchild } 1815159687Snetchild if (ch->dir == PCMDIR_PLAY) { 1816159687Snetchild ch->emldma(ch); 1817159687Snetchild envy24_setvolume(sc, ch->num); 1818159687Snetchild } 1819159687Snetchild envy24_updintr(sc, ch->dir); 1820159687Snetchild if (sc->run[slot] == 1) 1821159687Snetchild envy24_start(sc, ch->dir); 1822159687Snetchild ch->run = 1; 1823159687Snetchild break; 1824159687Snetchild case PCMTRIG_EMLDMAWR: 1825159687Snetchild#if(0) 1826159687Snetchild device_printf(sc->dev, "envy24chan_trigger(): emldmawr\n"); 1827159687Snetchild#endif 1828191308Sstas if (ch->run != 1) { 1829191308Sstas error = -1; 1830191308Sstas goto fail; 1831191308Sstas } 1832159687Snetchild ch->emldma(ch); 1833159687Snetchild break; 1834159687Snetchild case PCMTRIG_EMLDMARD: 1835159687Snetchild#if(0) 1836159687Snetchild device_printf(sc->dev, "envy24chan_trigger(): emldmard\n"); 1837159687Snetchild#endif 1838191308Sstas if (ch->run != 1) { 1839191308Sstas error = -1; 1840191308Sstas goto fail; 1841191308Sstas } 1842159687Snetchild ch->emldma(ch); 1843159687Snetchild break; 1844159687Snetchild case PCMTRIG_ABORT: 1845170031Sjoel if (ch->run) { 1846159687Snetchild#if(0) 1847159687Snetchild device_printf(sc->dev, "envy24chan_trigger(): abort\n"); 1848159687Snetchild#endif 1849159687Snetchild ch->run = 0; 1850159687Snetchild sc->run[slot]--; 1851159687Snetchild if (ch->dir == PCMDIR_PLAY) 1852159687Snetchild envy24_mutevolume(sc, ch->num); 1853159687Snetchild if (sc->run[slot] == 0) { 1854159687Snetchild envy24_stop(sc, ch->dir); 1855159687Snetchild sc->intr[slot] = 0; 1856159687Snetchild } 1857160796Snetchild#if 0 1858159687Snetchild else if (ch->blk == sc->blk[slot]) { 1859159687Snetchild sc->blk[slot] = ENVY24_SAMPLE_NUM / 2; 1860159687Snetchild for (i = 0; i < ENVY24_CHAN_NUM; i++) { 1861159687Snetchild if (sc->chan[i].dir == ch->dir && 1862159687Snetchild sc->chan[i].run == 1 && 1863159687Snetchild sc->chan[i].blk < sc->blk[slot]) 1864159687Snetchild sc->blk[slot] = sc->chan[i].blk; 1865159687Snetchild } 1866159687Snetchild if (ch->blk != sc->blk[slot]) 1867159687Snetchild envy24_updintr(sc, ch->dir); 1868159687Snetchild } 1869160796Snetchild#endif 1870170031Sjoel } 1871159687Snetchild break; 1872159687Snetchild } 1873191308Sstasfail: 1874159687Snetchild snd_mtxunlock(sc->lock); 1875191308Sstas return (error); 1876159687Snetchild} 1877159687Snetchild 1878193640Sariffstatic u_int32_t 1879159687Snetchildenvy24chan_getptr(kobj_t obj, void *data) 1880159687Snetchild{ 1881159687Snetchild struct sc_chinfo *ch = data; 1882159687Snetchild struct sc_info *sc = ch->parent; 1883193640Sariff u_int32_t ptr, rtn; 1884159687Snetchild 1885159687Snetchild#if(0) 1886159687Snetchild device_printf(sc->dev, "envy24chan_getptr()\n"); 1887159687Snetchild#endif 1888159687Snetchild snd_mtxlock(sc->lock); 1889159687Snetchild ptr = envy24_gethwptr(sc, ch->dir); 1890159687Snetchild rtn = ptr * ch->unit; 1891159687Snetchild snd_mtxunlock(sc->lock); 1892159687Snetchild 1893159687Snetchild#if(0) 1894159687Snetchild device_printf(sc->dev, "envy24chan_getptr(): return %d\n", 1895159687Snetchild rtn); 1896159687Snetchild#endif 1897159687Snetchild return rtn; 1898159687Snetchild} 1899159687Snetchild 1900159687Snetchildstatic struct pcmchan_caps * 1901159687Snetchildenvy24chan_getcaps(kobj_t obj, void *data) 1902159687Snetchild{ 1903159687Snetchild struct sc_chinfo *ch = data; 1904159687Snetchild struct sc_info *sc = ch->parent; 1905159687Snetchild struct pcmchan_caps *rtn; 1906159687Snetchild 1907159687Snetchild#if(0) 1908159687Snetchild device_printf(sc->dev, "envy24chan_getcaps()\n"); 1909159687Snetchild#endif 1910159687Snetchild snd_mtxlock(sc->lock); 1911159687Snetchild if (ch->dir == PCMDIR_PLAY) { 1912159687Snetchild if (sc->run[0] == 0) 1913159687Snetchild rtn = &envy24_playcaps; 1914159687Snetchild else 1915159687Snetchild rtn = &sc->caps[0]; 1916159687Snetchild } 1917159687Snetchild else { 1918159687Snetchild if (sc->run[1] == 0) 1919159687Snetchild rtn = &envy24_reccaps; 1920159687Snetchild else 1921159687Snetchild rtn = &sc->caps[1]; 1922159687Snetchild } 1923159687Snetchild snd_mtxunlock(sc->lock); 1924159687Snetchild 1925159687Snetchild return rtn; 1926159687Snetchild} 1927159687Snetchild 1928159687Snetchildstatic kobj_method_t envy24chan_methods[] = { 1929159687Snetchild KOBJMETHOD(channel_init, envy24chan_init), 1930159687Snetchild KOBJMETHOD(channel_free, envy24chan_free), 1931159687Snetchild KOBJMETHOD(channel_setformat, envy24chan_setformat), 1932159687Snetchild KOBJMETHOD(channel_setspeed, envy24chan_setspeed), 1933159687Snetchild KOBJMETHOD(channel_setblocksize, envy24chan_setblocksize), 1934159687Snetchild KOBJMETHOD(channel_trigger, envy24chan_trigger), 1935159687Snetchild KOBJMETHOD(channel_getptr, envy24chan_getptr), 1936159687Snetchild KOBJMETHOD(channel_getcaps, envy24chan_getcaps), 1937193640Sariff KOBJMETHOD_END 1938159687Snetchild}; 1939159687SnetchildCHANNEL_DECLARE(envy24chan); 1940159687Snetchild 1941159687Snetchild/* -------------------------------------------------------------------- */ 1942159687Snetchild 1943159687Snetchild/* mixer interface */ 1944159687Snetchild 1945159687Snetchildstatic int 1946159687Snetchildenvy24mixer_init(struct snd_mixer *m) 1947159687Snetchild{ 1948159687Snetchild struct sc_info *sc = mix_getdevinfo(m); 1949159687Snetchild 1950159687Snetchild#if(0) 1951159687Snetchild device_printf(sc->dev, "envy24mixer_init()\n"); 1952159687Snetchild#endif 1953159687Snetchild if (sc == NULL) 1954159687Snetchild return -1; 1955159687Snetchild 1956159687Snetchild /* set volume control rate */ 1957159687Snetchild snd_mtxlock(sc->lock); 1958159687Snetchild envy24_wrmt(sc, ENVY24_MT_VOLRATE, 0x30, 1); /* 0x30 is default value */ 1959159687Snetchild 1960159687Snetchild mix_setdevs(m, ENVY24_MIX_MASK); 1961159687Snetchild mix_setrecdevs(m, ENVY24_MIX_REC_MASK); 1962159687Snetchild snd_mtxunlock(sc->lock); 1963159687Snetchild 1964159687Snetchild return 0; 1965159687Snetchild} 1966159687Snetchild 1967159687Snetchildstatic int 1968159687Snetchildenvy24mixer_reinit(struct snd_mixer *m) 1969159687Snetchild{ 1970159687Snetchild struct sc_info *sc = mix_getdevinfo(m); 1971159687Snetchild 1972159687Snetchild if (sc == NULL) 1973159687Snetchild return -1; 1974159687Snetchild#if(0) 1975159687Snetchild device_printf(sc->dev, "envy24mixer_reinit()\n"); 1976159687Snetchild#endif 1977159687Snetchild 1978159687Snetchild return 0; 1979159687Snetchild} 1980159687Snetchild 1981159687Snetchildstatic int 1982159687Snetchildenvy24mixer_uninit(struct snd_mixer *m) 1983159687Snetchild{ 1984159687Snetchild struct sc_info *sc = mix_getdevinfo(m); 1985159687Snetchild 1986159687Snetchild if (sc == NULL) 1987159687Snetchild return -1; 1988159687Snetchild#if(0) 1989159687Snetchild device_printf(sc->dev, "envy24mixer_uninit()\n"); 1990159687Snetchild#endif 1991159687Snetchild 1992159687Snetchild return 0; 1993159687Snetchild} 1994159687Snetchild 1995159687Snetchildstatic int 1996159687Snetchildenvy24mixer_set(struct snd_mixer *m, unsigned dev, unsigned left, unsigned right) 1997159687Snetchild{ 1998159687Snetchild struct sc_info *sc = mix_getdevinfo(m); 1999159687Snetchild int ch = envy24_mixmap[dev]; 2000159687Snetchild int hwch; 2001159687Snetchild int i; 2002159687Snetchild 2003159687Snetchild if (sc == NULL) 2004159687Snetchild return -1; 2005159687Snetchild if (dev == 0 && sc->cfg->codec->setvolume == NULL) 2006159687Snetchild return -1; 2007159687Snetchild if (dev != 0 && ch == -1) 2008159687Snetchild return -1; 2009159687Snetchild hwch = envy24_chanmap[ch]; 2010159687Snetchild#if(0) 2011159687Snetchild device_printf(sc->dev, "envy24mixer_set(m, %d, %d, %d)\n", 2012159687Snetchild dev, left, right); 2013159687Snetchild#endif 2014159687Snetchild 2015159687Snetchild snd_mtxlock(sc->lock); 2016159687Snetchild if (dev == 0) { 2017159687Snetchild for (i = 0; i < sc->dacn; i++) { 2018159687Snetchild sc->cfg->codec->setvolume(sc->dac[i], PCMDIR_PLAY, left, right); 2019159687Snetchild } 2020159687Snetchild } 2021159687Snetchild else { 2022159687Snetchild /* set volume value for hardware */ 2023159687Snetchild if ((sc->left[hwch] = 100 - left) > ENVY24_VOL_MIN) 2024159687Snetchild sc->left[hwch] = ENVY24_VOL_MUTE; 2025159687Snetchild if ((sc->right[hwch] = 100 - right) > ENVY24_VOL_MIN) 2026159687Snetchild sc->right[hwch] = ENVY24_VOL_MUTE; 2027159687Snetchild 2028159687Snetchild /* set volume for record channel and running play channel */ 2029159687Snetchild if (hwch > ENVY24_CHAN_PLAY_SPDIF || sc->chan[ch].run) 2030159687Snetchild envy24_setvolume(sc, hwch); 2031159687Snetchild } 2032159687Snetchild snd_mtxunlock(sc->lock); 2033159687Snetchild 2034159687Snetchild return right << 8 | left; 2035159687Snetchild} 2036159687Snetchild 2037159687Snetchildstatic u_int32_t 2038159687Snetchildenvy24mixer_setrecsrc(struct snd_mixer *m, u_int32_t src) 2039159687Snetchild{ 2040159687Snetchild struct sc_info *sc = mix_getdevinfo(m); 2041159687Snetchild int ch = envy24_mixmap[src]; 2042159687Snetchild#if(0) 2043159687Snetchild device_printf(sc->dev, "envy24mixer_setrecsrc(m, %d)\n", src); 2044159687Snetchild#endif 2045159687Snetchild 2046159687Snetchild if (ch > ENVY24_CHAN_PLAY_SPDIF) 2047159687Snetchild sc->src = ch; 2048159687Snetchild return src; 2049159687Snetchild} 2050159687Snetchild 2051159687Snetchildstatic kobj_method_t envy24mixer_methods[] = { 2052159687Snetchild KOBJMETHOD(mixer_init, envy24mixer_init), 2053159687Snetchild KOBJMETHOD(mixer_reinit, envy24mixer_reinit), 2054159687Snetchild KOBJMETHOD(mixer_uninit, envy24mixer_uninit), 2055159687Snetchild KOBJMETHOD(mixer_set, envy24mixer_set), 2056159687Snetchild KOBJMETHOD(mixer_setrecsrc, envy24mixer_setrecsrc), 2057193640Sariff KOBJMETHOD_END 2058159687Snetchild}; 2059159687SnetchildMIXER_DECLARE(envy24mixer); 2060159687Snetchild 2061159687Snetchild/* -------------------------------------------------------------------- */ 2062159687Snetchild 2063159687Snetchild/* The interrupt handler */ 2064159687Snetchildstatic void 2065159687Snetchildenvy24_intr(void *p) 2066159687Snetchild{ 2067159687Snetchild struct sc_info *sc = (struct sc_info *)p; 2068159687Snetchild struct sc_chinfo *ch; 2069159687Snetchild u_int32_t ptr, dsize, feed; 2070159687Snetchild int i; 2071159687Snetchild 2072159687Snetchild#if(0) 2073159687Snetchild device_printf(sc->dev, "envy24_intr()\n"); 2074159687Snetchild#endif 2075159687Snetchild snd_mtxlock(sc->lock); 2076159687Snetchild if (envy24_checkintr(sc, PCMDIR_PLAY)) { 2077159687Snetchild#if(0) 2078159687Snetchild device_printf(sc->dev, "envy24_intr(): play\n"); 2079159687Snetchild#endif 2080159687Snetchild dsize = sc->psize / 4; 2081159687Snetchild ptr = dsize - envy24_rdmt(sc, ENVY24_MT_PCNT, 2) - 1; 2082159687Snetchild#if(0) 2083159687Snetchild device_printf(sc->dev, "envy24_intr(): ptr = %d-->", ptr); 2084159687Snetchild#endif 2085159687Snetchild ptr -= ptr % sc->blk[0]; 2086159687Snetchild feed = (ptr + dsize - sc->intr[0]) % dsize; 2087159687Snetchild#if(0) 2088159687Snetchild printf("%d intr = %d feed = %d\n", ptr, sc->intr[0], feed); 2089159687Snetchild#endif 2090159687Snetchild for (i = ENVY24_CHAN_PLAY_DAC1; i <= ENVY24_CHAN_PLAY_SPDIF; i++) { 2091159687Snetchild ch = &sc->chan[i]; 2092159687Snetchild#if(0) 2093159687Snetchild if (ch->run) 2094159687Snetchild device_printf(sc->dev, "envy24_intr(): chan[%d].blk = %d\n", i, ch->blk); 2095159687Snetchild#endif 2096165306Sariff if (ch->run && ch->blk <= feed) { 2097165306Sariff snd_mtxunlock(sc->lock); 2098159687Snetchild chn_intr(ch->channel); 2099165306Sariff snd_mtxlock(sc->lock); 2100165306Sariff } 2101159687Snetchild } 2102159687Snetchild sc->intr[0] = ptr; 2103159687Snetchild envy24_updintr(sc, PCMDIR_PLAY); 2104159687Snetchild } 2105159687Snetchild if (envy24_checkintr(sc, PCMDIR_REC)) { 2106159687Snetchild#if(0) 2107159687Snetchild device_printf(sc->dev, "envy24_intr(): rec\n"); 2108159687Snetchild#endif 2109159687Snetchild dsize = sc->rsize / 4; 2110159687Snetchild ptr = dsize - envy24_rdmt(sc, ENVY24_MT_RCNT, 2) - 1; 2111159687Snetchild ptr -= ptr % sc->blk[1]; 2112159687Snetchild feed = (ptr + dsize - sc->intr[1]) % dsize; 2113159687Snetchild for (i = ENVY24_CHAN_REC_ADC1; i <= ENVY24_CHAN_REC_SPDIF; i++) { 2114159687Snetchild ch = &sc->chan[i]; 2115165306Sariff if (ch->run && ch->blk <= feed) { 2116165306Sariff snd_mtxunlock(sc->lock); 2117159687Snetchild chn_intr(ch->channel); 2118165306Sariff snd_mtxlock(sc->lock); 2119165306Sariff } 2120159687Snetchild } 2121159687Snetchild sc->intr[1] = ptr; 2122159687Snetchild envy24_updintr(sc, PCMDIR_REC); 2123159687Snetchild } 2124159687Snetchild snd_mtxunlock(sc->lock); 2125159687Snetchild 2126159687Snetchild return; 2127159687Snetchild} 2128159687Snetchild 2129159687Snetchild/* 2130159687Snetchild * Probe and attach the card 2131159687Snetchild */ 2132159687Snetchild 2133159687Snetchildstatic int 2134159687Snetchildenvy24_pci_probe(device_t dev) 2135159687Snetchild{ 2136159687Snetchild u_int16_t sv, sd; 2137159687Snetchild int i; 2138159687Snetchild 2139159687Snetchild#if(0) 2140159687Snetchild printf("envy24_pci_probe()\n"); 2141159687Snetchild#endif 2142159687Snetchild if (pci_get_device(dev) == PCID_ENVY24 && 2143159687Snetchild pci_get_vendor(dev) == PCIV_ENVY24) { 2144159687Snetchild sv = pci_get_subvendor(dev); 2145159687Snetchild sd = pci_get_subdevice(dev); 2146159687Snetchild for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2147159687Snetchild if (cfg_table[i].subvendor == sv && 2148159687Snetchild cfg_table[i].subdevice == sd) { 2149159687Snetchild break; 2150159687Snetchild } 2151159687Snetchild } 2152159687Snetchild device_set_desc(dev, cfg_table[i].name); 2153159687Snetchild#if(0) 2154159687Snetchild printf("envy24_pci_probe(): return 0\n"); 2155159687Snetchild#endif 2156159687Snetchild return 0; 2157159687Snetchild } 2158159687Snetchild else { 2159159687Snetchild#if(0) 2160159687Snetchild printf("envy24_pci_probe(): return ENXIO\n"); 2161159687Snetchild#endif 2162159687Snetchild return ENXIO; 2163159687Snetchild } 2164159687Snetchild} 2165159687Snetchild 2166159687Snetchildstatic void 2167159687Snetchildenvy24_dmapsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2168159687Snetchild{ 2169165306Sariff /* struct sc_info *sc = (struct sc_info *)arg; */ 2170159687Snetchild 2171159687Snetchild#if(0) 2172159687Snetchild device_printf(sc->dev, "envy24_dmapsetmap()\n"); 2173159687Snetchild if (bootverbose) { 2174159687Snetchild printf("envy24(play): setmap %lx, %lx; ", 2175159687Snetchild (unsigned long)segs->ds_addr, 2176159687Snetchild (unsigned long)segs->ds_len); 2177159687Snetchild printf("%p -> %lx\n", sc->pmap, (unsigned long)vtophys(sc->pmap)); 2178159687Snetchild } 2179165306Sariff#endif 2180159687Snetchild} 2181159687Snetchild 2182159687Snetchildstatic void 2183159687Snetchildenvy24_dmarsetmap(void *arg, bus_dma_segment_t *segs, int nseg, int error) 2184159687Snetchild{ 2185165306Sariff /* struct sc_info *sc = (struct sc_info *)arg; */ 2186159687Snetchild 2187159687Snetchild#if(0) 2188159687Snetchild device_printf(sc->dev, "envy24_dmarsetmap()\n"); 2189159687Snetchild if (bootverbose) { 2190159687Snetchild printf("envy24(record): setmap %lx, %lx; ", 2191159687Snetchild (unsigned long)segs->ds_addr, 2192159687Snetchild (unsigned long)segs->ds_len); 2193159687Snetchild printf("%p -> %lx\n", sc->rmap, (unsigned long)vtophys(sc->pmap)); 2194159687Snetchild } 2195165306Sariff#endif 2196159687Snetchild} 2197159687Snetchild 2198159687Snetchildstatic void 2199159687Snetchildenvy24_dmafree(struct sc_info *sc) 2200159687Snetchild{ 2201159687Snetchild#if(0) 2202159687Snetchild device_printf(sc->dev, "envy24_dmafree():"); 2203159687Snetchild if (sc->rmap) printf(" sc->rmap(0x%08x)", (u_int32_t)sc->rmap); 2204159687Snetchild else printf(" sc->rmap(null)"); 2205159687Snetchild if (sc->pmap) printf(" sc->pmap(0x%08x)", (u_int32_t)sc->pmap); 2206159687Snetchild else printf(" sc->pmap(null)"); 2207159687Snetchild if (sc->rbuf) printf(" sc->rbuf(0x%08x)", (u_int32_t)sc->rbuf); 2208159687Snetchild else printf(" sc->rbuf(null)"); 2209159687Snetchild if (sc->pbuf) printf(" sc->pbuf(0x%08x)\n", (u_int32_t)sc->pbuf); 2210159687Snetchild else printf(" sc->pbuf(null)\n"); 2211159687Snetchild#endif 2212159687Snetchild#if(0) 2213159687Snetchild if (sc->rmap) 2214159687Snetchild bus_dmamap_unload(sc->dmat, sc->rmap); 2215159687Snetchild if (sc->pmap) 2216159687Snetchild bus_dmamap_unload(sc->dmat, sc->pmap); 2217159687Snetchild if (sc->rbuf) 2218159687Snetchild bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2219159687Snetchild if (sc->pbuf) 2220159687Snetchild bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2221159687Snetchild#else 2222159687Snetchild bus_dmamap_unload(sc->dmat, sc->rmap); 2223159687Snetchild bus_dmamap_unload(sc->dmat, sc->pmap); 2224159687Snetchild bus_dmamem_free(sc->dmat, sc->rbuf, sc->rmap); 2225159687Snetchild bus_dmamem_free(sc->dmat, sc->pbuf, sc->pmap); 2226159687Snetchild#endif 2227159687Snetchild 2228159687Snetchild sc->rmap = sc->pmap = NULL; 2229159687Snetchild sc->pbuf = NULL; 2230159687Snetchild sc->rbuf = NULL; 2231159687Snetchild 2232159687Snetchild return; 2233159687Snetchild} 2234159687Snetchild 2235159687Snetchildstatic int 2236159687Snetchildenvy24_dmainit(struct sc_info *sc) 2237159687Snetchild{ 2238159687Snetchild u_int32_t addr; 2239159687Snetchild 2240159687Snetchild#if(0) 2241159687Snetchild device_printf(sc->dev, "envy24_dmainit()\n"); 2242159687Snetchild#endif 2243159687Snetchild /* init values */ 2244159687Snetchild sc->psize = ENVY24_PLAY_BUFUNIT * ENVY24_SAMPLE_NUM; 2245159687Snetchild sc->rsize = ENVY24_REC_BUFUNIT * ENVY24_SAMPLE_NUM; 2246159687Snetchild sc->pbuf = NULL; 2247159687Snetchild sc->rbuf = NULL; 2248159687Snetchild sc->pmap = sc->rmap = NULL; 2249159687Snetchild sc->blk[0] = sc->blk[1] = 0; 2250159687Snetchild 2251159687Snetchild /* allocate DMA buffer */ 2252159687Snetchild#if(0) 2253159687Snetchild device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->pbuf\n"); 2254159687Snetchild#endif 2255159687Snetchild if (bus_dmamem_alloc(sc->dmat, (void **)&sc->pbuf, BUS_DMA_NOWAIT, &sc->pmap)) 2256159687Snetchild goto bad; 2257159687Snetchild#if(0) 2258159687Snetchild device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_alloc(): sc->rbuf\n"); 2259159687Snetchild#endif 2260159687Snetchild if (bus_dmamem_alloc(sc->dmat, (void **)&sc->rbuf, BUS_DMA_NOWAIT, &sc->rmap)) 2261159687Snetchild goto bad; 2262159687Snetchild#if(0) 2263159687Snetchild device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->pmap\n"); 2264159687Snetchild#endif 2265159687Snetchild if (bus_dmamap_load(sc->dmat, sc->pmap, sc->pbuf, sc->psize, envy24_dmapsetmap, sc, 0)) 2266159687Snetchild goto bad; 2267159687Snetchild#if(0) 2268159687Snetchild device_printf(sc->dev, "envy24_dmainit(): bus_dmamem_load(): sc->rmap\n"); 2269159687Snetchild#endif 2270159687Snetchild if (bus_dmamap_load(sc->dmat, sc->rmap, sc->rbuf, sc->rsize, envy24_dmarsetmap, sc, 0)) 2271159687Snetchild goto bad; 2272159687Snetchild bzero(sc->pbuf, sc->psize); 2273159687Snetchild bzero(sc->rbuf, sc->rsize); 2274159687Snetchild 2275159687Snetchild /* set values to register */ 2276159687Snetchild addr = vtophys(sc->pbuf); 2277159687Snetchild#if(0) 2278159687Snetchild device_printf(sc->dev, "pbuf(0x%08x)\n", addr); 2279159687Snetchild#endif 2280159687Snetchild envy24_wrmt(sc, ENVY24_MT_PADDR, addr, 4); 2281159687Snetchild#if(0) 2282159687Snetchild device_printf(sc->dev, "PADDR-->(0x%08x)\n", envy24_rdmt(sc, ENVY24_MT_PADDR, 4)); 2283159687Snetchild device_printf(sc->dev, "psize(%ld)\n", sc->psize / 4 - 1); 2284159687Snetchild#endif 2285159687Snetchild envy24_wrmt(sc, ENVY24_MT_PCNT, sc->psize / 4 - 1, 2); 2286159687Snetchild#if(0) 2287159687Snetchild device_printf(sc->dev, "PCNT-->(%ld)\n", envy24_rdmt(sc, ENVY24_MT_PCNT, 2)); 2288159687Snetchild#endif 2289159687Snetchild addr = vtophys(sc->rbuf); 2290159687Snetchild envy24_wrmt(sc, ENVY24_MT_RADDR, addr, 4); 2291159687Snetchild envy24_wrmt(sc, ENVY24_MT_RCNT, sc->rsize / 4 - 1, 2); 2292159687Snetchild 2293159687Snetchild return 0; 2294159687Snetchild bad: 2295159687Snetchild envy24_dmafree(sc); 2296159687Snetchild return ENOSPC; 2297159687Snetchild} 2298159687Snetchild 2299159687Snetchildstatic void 2300159687Snetchildenvy24_putcfg(struct sc_info *sc) 2301159687Snetchild{ 2302159689Snetchild device_printf(sc->dev, "system configuration\n"); 2303159687Snetchild printf(" SubVendorID: 0x%04x, SubDeviceID: 0x%04x\n", 2304159687Snetchild sc->cfg->subvendor, sc->cfg->subdevice); 2305159687Snetchild printf(" XIN2 Clock Source: "); 2306159687Snetchild switch (sc->cfg->scfg & PCIM_SCFG_XIN2) { 2307159687Snetchild case 0x00: 2308159687Snetchild printf("22.5792MHz(44.1kHz*512)\n"); 2309159687Snetchild break; 2310159687Snetchild case 0x40: 2311159687Snetchild printf("16.9344MHz(44.1kHz*384)\n"); 2312159687Snetchild break; 2313159687Snetchild case 0x80: 2314159687Snetchild printf("from external clock synthesizer chip\n"); 2315159687Snetchild break; 2316159687Snetchild default: 2317159687Snetchild printf("illeagal system setting\n"); 2318159687Snetchild } 2319159687Snetchild printf(" MPU-401 UART(s) #: "); 2320159687Snetchild if (sc->cfg->scfg & PCIM_SCFG_MPU) 2321159687Snetchild printf("2\n"); 2322159687Snetchild else 2323159687Snetchild printf("1\n"); 2324159687Snetchild printf(" AC'97 codec: "); 2325159687Snetchild if (sc->cfg->scfg & PCIM_SCFG_AC97) 2326159687Snetchild printf("not exist\n"); 2327159687Snetchild else 2328159687Snetchild printf("exist\n"); 2329159687Snetchild printf(" ADC #: "); 2330159687Snetchild printf("%d\n", sc->adcn); 2331159687Snetchild printf(" DAC #: "); 2332159687Snetchild printf("%d\n", sc->dacn); 2333159687Snetchild printf(" Multi-track converter type: "); 2334159687Snetchild if ((sc->cfg->acl & PCIM_ACL_MTC) == 0) { 2335159687Snetchild printf("AC'97(SDATA_OUT:"); 2336159687Snetchild if (sc->cfg->acl & PCIM_ACL_OMODE) 2337159687Snetchild printf("packed"); 2338159687Snetchild else 2339159687Snetchild printf("split"); 2340159687Snetchild printf("|SDATA_IN:"); 2341159687Snetchild if (sc->cfg->acl & PCIM_ACL_IMODE) 2342159687Snetchild printf("packed"); 2343159687Snetchild else 2344159687Snetchild printf("split"); 2345159687Snetchild printf(")\n"); 2346159687Snetchild } 2347159687Snetchild else { 2348159687Snetchild printf("I2S("); 2349159687Snetchild if (sc->cfg->i2s & PCIM_I2S_VOL) 2350159687Snetchild printf("with volume, "); 2351159687Snetchild if (sc->cfg->i2s & PCIM_I2S_96KHZ) 2352159687Snetchild printf("96KHz support, "); 2353159687Snetchild switch (sc->cfg->i2s & PCIM_I2S_RES) { 2354159687Snetchild case PCIM_I2S_16BIT: 2355159687Snetchild printf("16bit resolution, "); 2356159687Snetchild break; 2357159687Snetchild case PCIM_I2S_18BIT: 2358159687Snetchild printf("18bit resolution, "); 2359159687Snetchild break; 2360159687Snetchild case PCIM_I2S_20BIT: 2361159687Snetchild printf("20bit resolution, "); 2362159687Snetchild break; 2363159687Snetchild case PCIM_I2S_24BIT: 2364159687Snetchild printf("24bit resolution, "); 2365159687Snetchild break; 2366159687Snetchild } 2367159687Snetchild printf("ID#0x%x)\n", sc->cfg->i2s & PCIM_I2S_ID); 2368159687Snetchild } 2369159687Snetchild printf(" S/PDIF(IN/OUT): "); 2370159687Snetchild if (sc->cfg->spdif & PCIM_SPDIF_IN) 2371159687Snetchild printf("1/"); 2372159687Snetchild else 2373159687Snetchild printf("0/"); 2374159687Snetchild if (sc->cfg->spdif & PCIM_SPDIF_OUT) 2375159687Snetchild printf("1 "); 2376159687Snetchild else 2377159687Snetchild printf("0 "); 2378159687Snetchild if (sc->cfg->spdif & (PCIM_SPDIF_IN | PCIM_SPDIF_OUT)) 2379159687Snetchild printf("ID# 0x%02x\n", (sc->cfg->spdif & PCIM_SPDIF_ID) >> 2); 2380159687Snetchild printf(" GPIO(mask/dir/state): 0x%02x/0x%02x/0x%02x\n", 2381159687Snetchild sc->cfg->gpiomask, sc->cfg->gpiodir, sc->cfg->gpiostate); 2382159687Snetchild} 2383159687Snetchild 2384159687Snetchildstatic int 2385159687Snetchildenvy24_init(struct sc_info *sc) 2386159687Snetchild{ 2387159687Snetchild u_int32_t data; 2388159687Snetchild#if(0) 2389159687Snetchild int rtn; 2390159687Snetchild#endif 2391159687Snetchild int i; 2392159687Snetchild u_int32_t sv, sd; 2393159687Snetchild 2394159687Snetchild 2395159687Snetchild#if(0) 2396159687Snetchild device_printf(sc->dev, "envy24_init()\n"); 2397159687Snetchild#endif 2398159687Snetchild 2399159687Snetchild /* reset chip */ 2400159687Snetchild envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_RESET | ENVY24_CCS_CTL_NATIVE, 1); 2401159687Snetchild DELAY(200); 2402159687Snetchild envy24_wrcs(sc, ENVY24_CCS_CTL, ENVY24_CCS_CTL_NATIVE, 1); 2403159687Snetchild DELAY(200); 2404159687Snetchild 2405159687Snetchild /* legacy hardware disable */ 2406159687Snetchild data = pci_read_config(sc->dev, PCIR_LAC, 2); 2407159687Snetchild data |= PCIM_LAC_DISABLE; 2408159687Snetchild pci_write_config(sc->dev, PCIR_LAC, data, 2); 2409159687Snetchild 2410159687Snetchild /* check system configuration */ 2411159687Snetchild sc->cfg = NULL; 2412159687Snetchild for (i = 0; cfg_table[i].subvendor != 0 || cfg_table[i].subdevice != 0; i++) { 2413159687Snetchild /* 1st: search configuration from table */ 2414159687Snetchild sv = pci_get_subvendor(sc->dev); 2415159687Snetchild sd = pci_get_subdevice(sc->dev); 2416159687Snetchild if (sv == cfg_table[i].subvendor && sd == cfg_table[i].subdevice) { 2417159687Snetchild#if(0) 2418159687Snetchild device_printf(sc->dev, "Set configuration from table\n"); 2419159687Snetchild#endif 2420159687Snetchild sc->cfg = &cfg_table[i]; 2421159687Snetchild break; 2422159687Snetchild } 2423159687Snetchild } 2424159687Snetchild if (sc->cfg == NULL) { 2425159687Snetchild /* 2nd: read configuration from table */ 2426159687Snetchild sc->cfg = envy24_rom2cfg(sc); 2427159687Snetchild } 2428159687Snetchild sc->adcn = ((sc->cfg->scfg & PCIM_SCFG_ADC) >> 2) + 1; 2429159687Snetchild sc->dacn = (sc->cfg->scfg & PCIM_SCFG_DAC) + 1; 2430159687Snetchild 2431159687Snetchild if (1 /* bootverbose */) { 2432159687Snetchild envy24_putcfg(sc); 2433159687Snetchild } 2434159687Snetchild 2435159687Snetchild /* set system configuration */ 2436159687Snetchild pci_write_config(sc->dev, PCIR_SCFG, sc->cfg->scfg, 1); 2437159687Snetchild pci_write_config(sc->dev, PCIR_ACL, sc->cfg->acl, 1); 2438159687Snetchild pci_write_config(sc->dev, PCIR_I2S, sc->cfg->i2s, 1); 2439159687Snetchild pci_write_config(sc->dev, PCIR_SPDIF, sc->cfg->spdif, 1); 2440159687Snetchild envy24_gpiosetmask(sc, sc->cfg->gpiomask); 2441159687Snetchild envy24_gpiosetdir(sc, sc->cfg->gpiodir); 2442159687Snetchild envy24_gpiowr(sc, sc->cfg->gpiostate); 2443159687Snetchild for (i = 0; i < sc->adcn; i++) { 2444159687Snetchild sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i); 2445159687Snetchild sc->cfg->codec->init(sc->adc[i]); 2446159687Snetchild } 2447159687Snetchild for (i = 0; i < sc->dacn; i++) { 2448159687Snetchild sc->dac[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_PLAY, i); 2449159687Snetchild sc->cfg->codec->init(sc->dac[i]); 2450159687Snetchild } 2451159687Snetchild 2452159687Snetchild /* initialize DMA buffer */ 2453159687Snetchild#if(0) 2454159687Snetchild device_printf(sc->dev, "envy24_init(): initialize DMA buffer\n"); 2455159687Snetchild#endif 2456159687Snetchild if (envy24_dmainit(sc)) 2457159687Snetchild return ENOSPC; 2458159687Snetchild 2459159687Snetchild /* initialize status */ 2460159687Snetchild sc->run[0] = sc->run[1] = 0; 2461159687Snetchild sc->intr[0] = sc->intr[1] = 0; 2462159687Snetchild sc->speed = 0; 2463159687Snetchild sc->caps[0].fmtlist = envy24_playfmt; 2464159687Snetchild sc->caps[1].fmtlist = envy24_recfmt; 2465159687Snetchild 2466159687Snetchild /* set channel router */ 2467159687Snetchild envy24_route(sc, ENVY24_ROUTE_DAC_1, ENVY24_ROUTE_CLASS_MIX, 0, 0); 2468159687Snetchild envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_DMA, 0, 0); 2469159687Snetchild /* envy24_route(sc, ENVY24_ROUTE_DAC_SPDIF, ENVY24_ROUTE_CLASS_MIX, 0, 0); */ 2470159687Snetchild 2471159687Snetchild /* set macro interrupt mask */ 2472159687Snetchild data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1); 2473159687Snetchild envy24_wrcs(sc, ENVY24_CCS_IMASK, data & ~ENVY24_CCS_IMASK_PMT, 1); 2474159687Snetchild data = envy24_rdcs(sc, ENVY24_CCS_IMASK, 1); 2475159687Snetchild#if(0) 2476159687Snetchild device_printf(sc->dev, "envy24_init(): CCS_IMASK-->0x%02x\n", data); 2477159687Snetchild#endif 2478159687Snetchild 2479159687Snetchild return 0; 2480159687Snetchild} 2481159687Snetchild 2482159687Snetchildstatic int 2483166919Sariffenvy24_alloc_resource(struct sc_info *sc) 2484159687Snetchild{ 2485159687Snetchild /* allocate I/O port resource */ 2486159687Snetchild sc->csid = PCIR_CCS; 2487159687Snetchild sc->cs = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2488159687Snetchild &sc->csid, 0, ~0, 1, RF_ACTIVE); 2489159687Snetchild sc->ddmaid = PCIR_DDMA; 2490159687Snetchild sc->ddma = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2491159687Snetchild &sc->ddmaid, 0, ~0, 1, RF_ACTIVE); 2492159687Snetchild sc->dsid = PCIR_DS; 2493159687Snetchild sc->ds = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2494159687Snetchild &sc->dsid, 0, ~0, 1, RF_ACTIVE); 2495159687Snetchild sc->mtid = PCIR_MT; 2496159687Snetchild sc->mt = bus_alloc_resource(sc->dev, SYS_RES_IOPORT, 2497159687Snetchild &sc->mtid, 0, ~0, 1, RF_ACTIVE); 2498159687Snetchild if (!sc->cs || !sc->ddma || !sc->ds || !sc->mt) { 2499159687Snetchild device_printf(sc->dev, "unable to map IO port space\n"); 2500159687Snetchild return ENXIO; 2501159687Snetchild } 2502159687Snetchild sc->cst = rman_get_bustag(sc->cs); 2503159687Snetchild sc->csh = rman_get_bushandle(sc->cs); 2504159687Snetchild sc->ddmat = rman_get_bustag(sc->ddma); 2505159687Snetchild sc->ddmah = rman_get_bushandle(sc->ddma); 2506159687Snetchild sc->dst = rman_get_bustag(sc->ds); 2507159687Snetchild sc->dsh = rman_get_bushandle(sc->ds); 2508159687Snetchild sc->mtt = rman_get_bustag(sc->mt); 2509159687Snetchild sc->mth = rman_get_bushandle(sc->mt); 2510159687Snetchild#if(0) 2511159687Snetchild device_printf(sc->dev, 2512159687Snetchild "IO port register values\nCCS: 0x%lx\nDDMA: 0x%lx\nDS: 0x%lx\nMT: 0x%lx\n", 2513159687Snetchild pci_read_config(sc->dev, PCIR_CCS, 4), 2514159687Snetchild pci_read_config(sc->dev, PCIR_DDMA, 4), 2515159687Snetchild pci_read_config(sc->dev, PCIR_DS, 4), 2516159687Snetchild pci_read_config(sc->dev, PCIR_MT, 4)); 2517159687Snetchild#endif 2518159687Snetchild 2519172568Skevlo /* allocate interrupt resource */ 2520159687Snetchild sc->irqid = 0; 2521159687Snetchild sc->irq = bus_alloc_resource(sc->dev, SYS_RES_IRQ, &sc->irqid, 2522159687Snetchild 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); 2523159687Snetchild if (!sc->irq || 2524159687Snetchild snd_setup_intr(sc->dev, sc->irq, INTR_MPSAFE, envy24_intr, sc, &sc->ih)) { 2525159687Snetchild device_printf(sc->dev, "unable to map interrupt\n"); 2526159687Snetchild return ENXIO; 2527159687Snetchild } 2528159687Snetchild 2529159687Snetchild /* allocate DMA resource */ 2530166919Sariff if (bus_dma_tag_create(/*parent*/bus_get_dma_tag(sc->dev), 2531166919Sariff /*alignment*/4, 2532166904Snetchild /*boundary*/0, 2533159687Snetchild /*lowaddr*/BUS_SPACE_MAXADDR_ENVY24, 2534159687Snetchild /*highaddr*/BUS_SPACE_MAXADDR_ENVY24, 2535159687Snetchild /*filter*/NULL, /*filterarg*/NULL, 2536159687Snetchild /*maxsize*/BUS_SPACE_MAXSIZE_ENVY24, 2537159687Snetchild /*nsegments*/1, /*maxsegsz*/0x3ffff, 2538159689Snetchild /*flags*/0, /*lockfunc*/busdma_lock_mutex, 2539159689Snetchild /*lockarg*/&Giant, &sc->dmat) != 0) { 2540159687Snetchild device_printf(sc->dev, "unable to create dma tag\n"); 2541159687Snetchild return ENXIO; 2542159687Snetchild } 2543159687Snetchild 2544159687Snetchild return 0; 2545159687Snetchild} 2546159687Snetchild 2547159687Snetchildstatic int 2548159687Snetchildenvy24_pci_attach(device_t dev) 2549159687Snetchild{ 2550159687Snetchild struct sc_info *sc; 2551159687Snetchild char status[SND_STATUSLEN]; 2552159687Snetchild int err = 0; 2553159687Snetchild int i; 2554159687Snetchild 2555159687Snetchild#if(0) 2556159687Snetchild device_printf(dev, "envy24_pci_attach()\n"); 2557159687Snetchild#endif 2558159687Snetchild /* get sc_info data area */ 2559159687Snetchild if ((sc = malloc(sizeof(*sc), M_ENVY24, M_NOWAIT)) == NULL) { 2560159687Snetchild device_printf(dev, "cannot allocate softc\n"); 2561159687Snetchild return ENXIO; 2562159687Snetchild } 2563159687Snetchild 2564159687Snetchild bzero(sc, sizeof(*sc)); 2565167608Sariff sc->lock = snd_mtxcreate(device_get_nameunit(dev), "snd_envy24 softc"); 2566159687Snetchild sc->dev = dev; 2567159687Snetchild 2568159687Snetchild /* initialize PCI interface */ 2569254263Sscottl pci_enable_busmaster(dev); 2570159687Snetchild 2571159687Snetchild /* allocate resources */ 2572166919Sariff err = envy24_alloc_resource(sc); 2573159689Snetchild if (err) { 2574159687Snetchild device_printf(dev, "unable to allocate system resources\n"); 2575159687Snetchild goto bad; 2576159687Snetchild } 2577159687Snetchild 2578159687Snetchild /* initialize card */ 2579159689Snetchild err = envy24_init(sc); 2580159689Snetchild if (err) { 2581159687Snetchild device_printf(dev, "unable to initialize the card\n"); 2582159687Snetchild goto bad; 2583159687Snetchild } 2584159687Snetchild 2585159687Snetchild /* set multi track mixer */ 2586159687Snetchild mixer_init(dev, &envy24mixer_class, sc); 2587159687Snetchild 2588159687Snetchild /* set channel information */ 2589170031Sjoel err = pcm_register(dev, sc, 5, 2 + sc->adcn); 2590159689Snetchild if (err) 2591159687Snetchild goto bad; 2592170031Sjoel sc->chnum = 0; 2593170031Sjoel for (i = 0; i < 5; i++) { 2594159687Snetchild pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc); 2595159687Snetchild sc->chnum++; 2596159687Snetchild } 2597170031Sjoel for (i = 0; i < 2 + sc->adcn; i++) { 2598159687Snetchild pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc); 2599159687Snetchild sc->chnum++; 2600159687Snetchild } 2601159687Snetchild 2602159687Snetchild /* set status iformation */ 2603159687Snetchild snprintf(status, SND_STATUSLEN, 2604159687Snetchild "at io 0x%lx:%ld,0x%lx:%ld,0x%lx:%ld,0x%lx:%ld irq %ld", 2605159687Snetchild rman_get_start(sc->cs), 2606159687Snetchild rman_get_end(sc->cs) - rman_get_start(sc->cs) + 1, 2607159687Snetchild rman_get_start(sc->ddma), 2608159687Snetchild rman_get_end(sc->ddma) - rman_get_start(sc->ddma) + 1, 2609159687Snetchild rman_get_start(sc->ds), 2610159687Snetchild rman_get_end(sc->ds) - rman_get_start(sc->ds) + 1, 2611159687Snetchild rman_get_start(sc->mt), 2612159687Snetchild rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1, 2613159687Snetchild rman_get_start(sc->irq)); 2614159687Snetchild pcm_setstatus(dev, status); 2615159687Snetchild 2616159687Snetchild return 0; 2617159687Snetchild 2618159687Snetchildbad: 2619159687Snetchild if (sc->ih) 2620159687Snetchild bus_teardown_intr(dev, sc->irq, sc->ih); 2621159687Snetchild if (sc->irq) 2622159687Snetchild bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2623159687Snetchild envy24_dmafree(sc); 2624159687Snetchild if (sc->dmat) 2625159687Snetchild bus_dma_tag_destroy(sc->dmat); 2626160796Snetchild if (sc->cfg->codec->destroy != NULL) { 2627160796Snetchild for (i = 0; i < sc->adcn; i++) 2628160796Snetchild sc->cfg->codec->destroy(sc->adc[i]); 2629160796Snetchild for (i = 0; i < sc->dacn; i++) 2630160796Snetchild sc->cfg->codec->destroy(sc->dac[i]); 2631160796Snetchild } 2632159687Snetchild envy24_cfgfree(sc->cfg); 2633159687Snetchild if (sc->cs) 2634159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2635159687Snetchild if (sc->ddma) 2636159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma); 2637159687Snetchild if (sc->ds) 2638159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds); 2639159687Snetchild if (sc->mt) 2640159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2641159687Snetchild if (sc->lock) 2642159687Snetchild snd_mtxfree(sc->lock); 2643159687Snetchild free(sc, M_ENVY24); 2644159687Snetchild return err; 2645159687Snetchild} 2646159687Snetchild 2647159687Snetchildstatic int 2648159687Snetchildenvy24_pci_detach(device_t dev) 2649159687Snetchild{ 2650159687Snetchild struct sc_info *sc; 2651159687Snetchild int r; 2652159687Snetchild int i; 2653159687Snetchild 2654159687Snetchild#if(0) 2655159687Snetchild device_printf(dev, "envy24_pci_detach()\n"); 2656159687Snetchild#endif 2657159687Snetchild sc = pcm_getdevinfo(dev); 2658159687Snetchild if (sc == NULL) 2659159687Snetchild return 0; 2660159687Snetchild r = pcm_unregister(dev); 2661159687Snetchild if (r) 2662159687Snetchild return r; 2663159687Snetchild 2664159687Snetchild envy24_dmafree(sc); 2665159687Snetchild if (sc->cfg->codec->destroy != NULL) { 2666159687Snetchild for (i = 0; i < sc->adcn; i++) 2667159687Snetchild sc->cfg->codec->destroy(sc->adc[i]); 2668159687Snetchild for (i = 0; i < sc->dacn; i++) 2669159687Snetchild sc->cfg->codec->destroy(sc->dac[i]); 2670159687Snetchild } 2671159687Snetchild envy24_cfgfree(sc->cfg); 2672159687Snetchild bus_dma_tag_destroy(sc->dmat); 2673159687Snetchild bus_teardown_intr(dev, sc->irq, sc->ih); 2674159687Snetchild bus_release_resource(dev, SYS_RES_IRQ, sc->irqid, sc->irq); 2675159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->csid, sc->cs); 2676159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->ddmaid, sc->ddma); 2677159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->dsid, sc->ds); 2678159687Snetchild bus_release_resource(dev, SYS_RES_IOPORT, sc->mtid, sc->mt); 2679159687Snetchild snd_mtxfree(sc->lock); 2680159687Snetchild free(sc, M_ENVY24); 2681159687Snetchild return 0; 2682159687Snetchild} 2683159687Snetchild 2684159687Snetchildstatic device_method_t envy24_methods[] = { 2685159687Snetchild /* Device interface */ 2686159687Snetchild DEVMETHOD(device_probe, envy24_pci_probe), 2687159687Snetchild DEVMETHOD(device_attach, envy24_pci_attach), 2688159687Snetchild DEVMETHOD(device_detach, envy24_pci_detach), 2689159687Snetchild { 0, 0 } 2690159687Snetchild}; 2691159687Snetchild 2692159687Snetchildstatic driver_t envy24_driver = { 2693159687Snetchild "pcm", 2694159687Snetchild envy24_methods, 2695159687Snetchild#if __FreeBSD_version > 500000 2696159687Snetchild PCM_SOFTC_SIZE, 2697159687Snetchild#else 2698159687Snetchild sizeof(struct snddev_info), 2699159687Snetchild#endif 2700159687Snetchild}; 2701159687Snetchild 2702159687SnetchildDRIVER_MODULE(snd_envy24, pci, envy24_driver, pcm_devclass, 0, 0); 2703159689SnetchildMODULE_DEPEND(snd_envy24, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); 2704168883SariffMODULE_DEPEND(snd_envy24, snd_spicds, 1, 1, 1); 2705159687SnetchildMODULE_VERSION(snd_envy24, 1); 2706