Index: src/sys/dev/sound/pci/envy24.c =================================================================== RCS file: /home/ncvs/src/sys/dev/sound/pci/envy24.c,v retrieving revision 1.12 diff -u -r1.12 envy24.c --- src/sys/dev/sound/pci/envy24.c 19 May 2007 11:06:43 -0000 1.12 +++ src/sys/dev/sound/pci/envy24.c 21 May 2007 09:01:41 -0000 @@ -55,6 +55,9 @@ #define ENVY24_NAMELEN 32 +#define SDA_GPIO 0x10 +#define SCL_GPIO 0x20 + struct envy24_sample { volatile u_int32_t buffer; }; @@ -740,17 +743,121 @@ /* -------------------------------------------------------------------- */ -/* M-Audio Delta series AK4524 access interface routine */ +/* Envy24 I2C through GPIO bit-banging */ struct envy24_delta_ak4524_codec { - struct spicds_info *info; - struct sc_info *parent; - int dir; - int num; - int cs, cclk, cdti; + struct spicds_info *info; + struct sc_info *parent; + int dir; + int num; + int cs, cclk, cdti; }; static void +envy24_gpio_i2c_ctl(void *codec, unsigned int scl, unsigned int sda) +{ + u_int32_t data = 0; + struct envy24_delta_ak4524_codec *ptr = codec; +#if(0) + device_printf(ptr->parent->dev, "--> %d, %d\n", scl, sda); +#endif + data = envy24_gpiord(ptr->parent); + data &= ~(SDA_GPIO | SCL_GPIO); + if (scl) data += SCL_GPIO; + if (sda) data += SDA_GPIO; + envy24_gpiowr(ptr->parent, data); + return; +} + +static void +i2c_wrbit(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), int bit) +{ + struct envy24_delta_ak4524_codec *ptr = codec; + unsigned int sda; + + if (bit) + sda = 1; + else + sda = 0; + + ctrl(ptr, 0, sda); + DELAY(I2C_DELAY); + ctrl(ptr, 1, sda); + DELAY(I2C_DELAY); + ctrl(ptr, 0, sda); + DELAY(I2C_DELAY); +} + +static void +i2c_start(void *codec, void (*ctrl)(void*, unsigned int, unsigned int)) +{ + struct envy24_delta_ak4524_codec *ptr = codec; + + ctrl(ptr, 1, 1); + DELAY(I2C_DELAY); + ctrl(ptr, 1, 0); + DELAY(I2C_DELAY); + ctrl(ptr, 0, 0); + DELAY(I2C_DELAY); +} + +static void +i2c_stop(void *codec, void (*ctrl)(void*, unsigned int, unsigned int)) +{ + struct envy24_delta_ak4524_codec *ptr = codec; + + ctrl(ptr, 0, 0); + DELAY(I2C_DELAY); + ctrl(ptr, 1, 0); + DELAY(I2C_DELAY); + ctrl(ptr, 1, 1); + DELAY(I2C_DELAY); +} + +static void +i2c_ack(void *codec, void (*ctrl)(void*, unsigned int, unsigned int)) +{ + struct envy24_delta_ak4524_codec *ptr = codec; + + ctrl(ptr, 0, 1); + DELAY(I2C_DELAY); + ctrl(ptr, 1, 1); + DELAY(I2C_DELAY); + // dummy, need routine to change gpio direction + ctrl(ptr, 0, 1); + DELAY(I2C_DELAY); +} + +static void +i2c_wr(void *codec, void (*ctrl)(void*, unsigned int, unsigned int), u_int32_t dev, int reg, u_int8_t val) +{ + struct envy24_delta_ak4524_codec *ptr = codec; + int mask; + + i2c_start(ptr, ctrl); + + for (mask = 0x80; mask != 0; mask >>= 1) + i2c_wrbit(ptr, ctrl, dev & mask); + i2c_ack(ptr, ctrl); + + if (reg != 0xff) { + for (mask = 0x80; mask != 0; mask >>= 1) + i2c_wrbit(ptr, ctrl, reg & mask); + i2c_ack(ptr, ctrl); + } + + for (mask = 0x80; mask != 0; mask >>= 1) + i2c_wrbit(ptr, ctrl, val & mask); + i2c_ack(ptr, ctrl); + + i2c_stop(ptr, ctrl); +} + +/* -------------------------------------------------------------------- */ + +/* M-Audio Delta series AK4524 access interface routine */ + +static void envy24_delta_ak4524_ctl(void *codec, unsigned int cs, unsigned int cclk, unsigned int cdti) { u_int32_t data = 0; @@ -863,6 +970,18 @@ /* for the time being, init only first codec */ if (ptr->num == 0) spicds_init(ptr->info); + + /* 6fire rear input init test, set ptr->num to 1 for test */ + if (ptr->parent->cfg->subvendor == 0x153b && \ + ptr->parent->cfg->subdevice == 0x1138 && ptr->num == 100) { + ptr->cs = 0x02; + spicds_init(ptr->info); + device_printf(ptr->parent->dev, "6fire rear input init\n"); + i2c_wr(ptr, envy24_gpio_i2c_ctl, \ + PCA9554_I2CDEV, PCA9554_DIR, 0x80); + i2c_wr(ptr, envy24_gpio_i2c_ctl, \ + PCA9554_I2CDEV, PCA9554_OUT, 0x02); + } } static void @@ -1219,6 +1338,9 @@ device_printf(sc->dev, "envy24_route(): MT_RECORD-->0x%08x\n", reg); #endif envy24_wrmt(sc, ENVY24_MT_RECORD, reg, 4); + + /* 6fire rear input init test */ + envy24_wrmt(sc, ENVY24_MT_RECORD, 0x00, 4); } return 0; @@ -1664,6 +1786,7 @@ ch->emldma(ch); break; case PCMTRIG_ABORT: + if (ch->run) { #if(0) device_printf(sc->dev, "envy24chan_trigger(): abort\n"); #endif @@ -1688,6 +1811,7 @@ envy24_updintr(sc, ch->dir); } #endif + } break; } snd_mtxunlock(sc->lock); @@ -2411,16 +2535,15 @@ mixer_init(dev, &envy24mixer_class, sc); /* set channel information */ - err = pcm_register(dev, sc, sc->dacn, sc->adcn); + err = pcm_register(dev, sc, 5, 2 + sc->adcn); if (err) goto bad; - sc->chnum = ENVY24_CHAN_PLAY_DAC1; - for (i = 0; i < sc->dacn; i++) { + sc->chnum = 0; + for (i = 0; i < 5; i++) { pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc); sc->chnum++; } - sc->chnum = ENVY24_CHAN_REC_ADC1; - for (i = 0; i < sc->adcn; i++) { + for (i = 0; i < 2 + sc->adcn; i++) { pcm_addchan(dev, PCMDIR_REC, &envy24chan_class, sc); sc->chnum++; } Index: src/sys/dev/sound/pci/envy24.h =================================================================== RCS file: /home/ncvs/src/sys/dev/sound/pci/envy24.h,v retrieving revision 1.1 diff -u -r1.1 envy24.h --- src/sys/dev/sound/pci/envy24.h 17 Jun 2006 14:36:44 -0000 1.1 +++ src/sys/dev/sound/pci/envy24.h 21 May 2007 09:01:41 -0000 @@ -479,4 +479,17 @@ /* M-Audio Delta series parameter */ #define ENVY24_DELTA_AK4524_CIF 0 +#define I2C_DELAY 1000 + +/* PCA9554 registers */ +#define PCA9554_I2CDEV 0x40 /* I2C device address */ +#define PCA9554_IN 0x00 /* input port */ +#define PCA9554_OUT 0x01 /* output port */ +#define PCA9554_INVERT 0x02 /* polarity invert */ +#define PCA9554_DIR 0x03 /* port directions */ + +/* PCF8574 registers */ +#define PCF8574_I2CDEV_DAC 0x48 +#define PCF8574_SENSE_MASK 0x40 + /* end of file */ Index: src/sys/dev/sound/pci/envy24ht.c =================================================================== RCS file: /home/ncvs/src/sys/dev/sound/pci/envy24ht.c,v retrieving revision 1.12 diff -u -r1.12 envy24ht.c --- src/sys/dev/sound/pci/envy24ht.c 19 May 2007 11:06:43 -0000 1.12 +++ src/sys/dev/sound/pci/envy24ht.c 21 May 2007 09:01:41 -0000 @@ -26,6 +26,17 @@ * */ +/* + * Konstantin Dimitrov's thanks list: + * + * A huge thanks goes to Spas Filipov for his friendship, support and his + * generous gift - an 'Audiotrak Prodigy HD2' audio card! I also want to + * thank Keiichi Iwasaki and his parents, because they helped Spas to get + * the card from Japan! Having hardware sample of Prodigy HD2 made adding + * support for that great card very easy and real fun and pleasure. + * + */ + #include #include #include @@ -247,7 +258,7 @@ /* variable rate audio */ static u_int32_t envy24ht_speed[] = { - 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, + 192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 9600, 8000, 0 }; @@ -319,13 +330,22 @@ { "Envy24HT audio (AudioTrak Prodigy 7.1 LT)", 0x3132, 0x4154, - 0x0b, 0x80, 0xfc, 0xc3, + 0x4b, 0x80, 0xfc, 0xc3, 0x7ff8ff, 0x7fffff, 0x700, 0x400, 0x200, 0x100, 0x00, 0x02, 0, &spi_codec, }, { + "Envy24HT audio (AudioTrak Prodigy 7.1 XT)", + 0x3136, 0x4154, + 0x4b, 0x80, 0xfc, 0xc3, + 0x7ff8ff, 0x7fffff, 0x700, + 0x400, 0x200, 0x100, 0x00, 0x02, + 0, + &spi_codec, + }, + { "Envy24HT audio (M-Audio Revolution 7.1)", 0x1412, 0x3630, 0x43, 0x80, 0xf8, 0xc1, @@ -339,7 +359,7 @@ 0x1412, 0x3631, 0x42, 0x80, 0xf8, 0xc1, 0x3fff85, 0x72, 0x4000fa, - 0x08, 0x02, 0x20, 0x00, 0x03, + 0x08, 0x02, 0x10, 0x00, 0x03, 0, &spi_codec, }, @@ -352,6 +372,24 @@ 0, &spi_codec, }, + { + "Envy24HT audio (AudioTrak Prodigy HD2)", + 0x3137, 0x4154, + 0x68, 0x80, 0x78, 0xc3, + 0xfff8ff, 0x200700, 0xdfffff, + 0x400, 0x200, 0x100, 0x00, 0x05, + 0, + &spi_codec, + }, + { + "Envy24HT audio (ESI Juli@)", + 0x3031, 0x4553, + 0x20, 0x80, 0xf8, 0xc3, + 0x7fff9f, 0x8016, 0x7fff9f, + 0x08, 0x02, 0x10, 0x00, 0x03, + 0, + &spi_codec, + }, { "Envy24HT audio (Generic)", 0, 0, @@ -377,7 +415,7 @@ 0 }; -static struct pcmchan_caps envy24ht_playcaps = {8000, 96000, envy24ht_playfmt, 0}; +static struct pcmchan_caps envy24ht_playcaps = {8000, 192000, envy24ht_playfmt, 0}; struct envy24ht_emldma { u_int32_t format; @@ -505,7 +543,6 @@ return (int)data; } -#if 0 static int envy24ht_wri2c(struct sc_info *sc, u_int32_t dev, u_int32_t addr, u_int32_t data) { @@ -540,7 +577,6 @@ return 0; } -#endif static int envy24ht_rdrom(struct sc_info *sc, u_int32_t addr) @@ -572,7 +608,7 @@ device_printf(sc->dev, "envy24ht_rom2cfg(sc)\n"); #endif size = envy24ht_rdrom(sc, ENVY24HT_E2PROM_SIZE); - if (size < ENVY24HT_E2PROM_GPIOSTATE + 3) { + if ((size < ENVY24HT_E2PROM_GPIOSTATE + 3) || (size == 0x78)) { #if(0) device_printf(sc->dev, "envy24ht_rom2cfg(): ENVY24HT_E2PROM_SIZE-->%d\n", size); #endif @@ -816,7 +852,7 @@ static u_int32_t envy24ht_gpiogetdir(struct sc_info *sc) { - return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4; + return envy24ht_rdcs(sc, ENVY24HT_CCS_GPIO_CTLDIR, 4); } #endif @@ -982,17 +1018,19 @@ {16000, ENVY24HT_MT_RATE_16000}, {8000, ENVY24HT_MT_RATE_8000}, {96000, ENVY24HT_MT_RATE_96000}, + {192000, ENVY24HT_MT_RATE_192000}, {64000, ENVY24HT_MT_RATE_64000}, {44100, ENVY24HT_MT_RATE_44100}, {22050, ENVY24HT_MT_RATE_22050}, {11025, ENVY24HT_MT_RATE_11025}, {88200, ENVY24HT_MT_RATE_88200}, + {176400, ENVY24HT_MT_RATE_176400}, {0, 0x10} }; static int envy24ht_setspeed(struct sc_info *sc, u_int32_t speed) { - u_int32_t code; + u_int32_t code, i2sfmt; int i = 0; #if(0) @@ -1014,6 +1052,17 @@ #endif if (code < 0x10) { envy24ht_wrmt(sc, ENVY24HT_MT_RATE, code, 1); + if ((((sc->cfg->scfg & ENVY24HT_CCSM_SCFG_XIN2) == 0x00) && (code == ENVY24HT_MT_RATE_192000)) || \ + (code == ENVY24HT_MT_RATE_176400)) { + i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1); + i2sfmt |= ENVY24HT_MT_I2S_MLR128; + envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1); + } + else { + i2sfmt = envy24ht_rdmt(sc, ENVY24HT_MT_I2S, 1); + i2sfmt &= ~ENVY24HT_MT_I2S_MLR128; + envy24ht_wrmt(sc, ENVY24HT_MT_I2S, i2sfmt, 1); + } code = envy24ht_rdmt(sc, ENVY24HT_MT_RATE, 1); code &= ENVY24HT_MT_RATE_MASK; for (i = 0; envy24ht_speedtab[i].code < 0x10; i++) { @@ -1595,7 +1644,7 @@ else ch->blk *= ENVY24HT_REC_BUFUNIT / 4; /* set channel buffer information */ - /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */ + /* ch->size = ch->unit * ENVY24HT_SAMPLE_NUM; */ if (ch->dir == PCMDIR_PLAY) bsize = ch->blk * 4 / ENVY24HT_PLAY_BUFUNIT; else @@ -1684,6 +1733,7 @@ ch->emldma(ch); break; case PCMTRIG_ABORT: + if (ch->run) { #if(0) device_printf(sc->dev, "envy24htchan_trigger(): abort\n"); #endif @@ -1706,6 +1756,7 @@ if (ch->blk != sc->blk[slot]) envy24ht_updintr(sc, ch->dir); }*/ + } break; } snd_mtxunlock(sc->lock); @@ -1800,6 +1851,12 @@ mix_setdevs(m, ENVY24HT_MIX_MASK); mix_setrecdevs(m, ENVY24HT_MIX_REC_MASK); + + struct snddev_info *d = NULL; + d = device_get_softc(sc->dev); + if (d != NULL) + d->flags |= SD_F_SOFTPCMVOL; + snd_mtxunlock(sc->lock); return 0; @@ -2289,6 +2346,12 @@ envy24ht_gpiosetmask(sc, sc->cfg->gpiomask); envy24ht_gpiosetdir(sc, sc->cfg->gpiodir); envy24ht_gpiowr(sc, sc->cfg->gpiostate); + + if ((sc->cfg->subvendor == 0x3031) && (sc->cfg->subdevice == 0x4553)) { + envy24ht_wri2c(sc, 0x22, 0x00, 0x07); + envy24ht_wri2c(sc, 0x22, 0x04, 0x5f | 0x80); + envy24ht_wri2c(sc, 0x22, 0x05, 0x5f | 0x80); + } for (i = 0; i < sc->adcn; i++) { sc->adc[i] = sc->cfg->codec->create(sc->dev, sc, PCMDIR_REC, i); Index: src/sys/dev/sound/pci/envy24ht.h =================================================================== RCS file: /home/ncvs/src/sys/dev/sound/pci/envy24ht.h,v retrieving revision 1.4 diff -u -r1.4 envy24ht.h --- src/sys/dev/sound/pci/envy24ht.h 17 Dec 2006 16:06:45 -0000 1.4 +++ src/sys/dev/sound/pci/envy24ht.h 21 May 2007 09:01:41 -0000 @@ -108,13 +108,18 @@ #define ENVY24HT_MT_RATE_16000 0x05 #define ENVY24HT_MT_RATE_8000 0x06 #define ENVY24HT_MT_RATE_96000 0x07 +#define ENVY24HT_MT_RATE_192000 0x0e #define ENVY24HT_MT_RATE_64000 0x0f #define ENVY24HT_MT_RATE_44100 0x08 #define ENVY24HT_MT_RATE_22050 0x09 #define ENVY24HT_MT_RATE_11025 0x0a #define ENVY24HT_MT_RATE_88200 0x0b +#define ENVY24HT_MT_RATE_176400 0x0c #define ENVY24HT_MT_RATE_MASK 0x0f +#define ENVY24HT_MT_I2S 0x02 /* I2S Data Format Register */ +#define ENVY24HT_MT_I2S_MLR128 0x08 /* MCLK/LRCLK ratio 128x (or 256x) */ + #define ENVY24HT_MT_PADDR 0x10 /* Playback DMA Current/Base Address Register */ #define ENVY24HT_MT_PCNT 0x14 /* Playback DMA Current/Base Count Register */ #define ENVY24HT_MT_PTERM 0x1C /* Playback Current/Base Terminal Count Register */ Index: src/sys/dev/sound/pci/spicds.c =================================================================== RCS file: /home/ncvs/src/sys/dev/sound/pci/spicds.c,v retrieving revision 1.5 diff -u -r1.5 spicds.c --- src/sys/dev/sound/pci/spicds.c 14 Feb 2007 15:23:44 -0000 1.5 +++ src/sys/dev/sound/pci/spicds.c 21 May 2007 09:01:41 -0000 @@ -88,6 +88,12 @@ spicds_wrbit(codec, 0); spicds_wrbit(codec, 1); } + else if (codec->type == SPICDS_TYPE_AK4396) + { + /* AK4396 chip address */ + spicds_wrbit(codec, 0); + spicds_wrbit(codec, 0); + } else { /* chip address */ spicds_wrbit(codec, 1); @@ -229,6 +235,8 @@ spicds_wrcd(codec, 0x00, 0x07); /* I2S, 24bit, power-up */ if (codec->type == SPICDS_TYPE_AK4381) spicds_wrcd(codec, 0x00, 0x0f); /* I2S, 24bit, power-up */ + if (codec->type == SPICDS_TYPE_AK4396) + spicds_wrcd(codec, 0x00, 0x07); /* I2S, 24bit, power-up */ snd_mtxunlock(codec->lock); } @@ -261,7 +269,8 @@ #endif snd_mtxlock(codec->lock); if (left >= 100) - if (codec->type == SPICDS_TYPE_AK4381) + if ((codec->type == SPICDS_TYPE_AK4381) || \ + (codec->type == SPICDS_TYPE_AK4396)) left = 255; else left = 127; @@ -270,14 +279,15 @@ case SPICDS_TYPE_WM8770: left = left + 27; break; - case SPICDS_TYPE_AK4381: + case SPICDS_TYPE_AK4381 || SPICDS_TYPE_AK4396: left = left * 255 / 100; break; default: left = left * 127 / 100; } if (right >= 100) - if (codec->type == SPICDS_TYPE_AK4381) + if ((codec->type == SPICDS_TYPE_AK4381) || \ + (codec->type == SPICDS_TYPE_AK4396)) right = 255; else right = 127; @@ -286,7 +296,7 @@ case SPICDS_TYPE_WM8770: right = right + 27; break; - case SPICDS_TYPE_AK4381: + case SPICDS_TYPE_AK4381 || SPICDS_TYPE_AK4396: right = right * 255 / 100; break; default: @@ -335,6 +345,14 @@ spicds_wrcd(codec, AK4381_ROATT, right); } + if (dir == PCMDIR_PLAY && codec->type == SPICDS_TYPE_AK4396) { +#if(0) + device_printf(codec->dev, "spicds_set(): AK4396(PLAY) %d/%d\n", left, right); +#endif + spicds_wrcd(codec, AK4396_LOATT, left); + spicds_wrcd(codec, AK4396_ROATT, right); + } + snd_mtxunlock(codec->lock); } Index: src/sys/dev/sound/pci/spicds.h =================================================================== RCS file: /home/ncvs/src/sys/dev/sound/pci/spicds.h,v retrieving revision 1.3 diff -u -r1.3 spicds.h --- src/sys/dev/sound/pci/spicds.h 30 Sep 2006 16:53:40 -0000 1.3 +++ src/sys/dev/sound/pci/spicds.h 21 May 2007 09:01:41 -0000 @@ -33,6 +33,7 @@ #define SPICDS_TYPE_WM8770 2 #define SPICDS_TYPE_AK4358 3 #define SPICDS_TYPE_AK4381 4 +#define SPICDS_TYPE_AK4396 5 /* AK4524/AK4528 control registers */ #define AK4524_POWER 0x00 @@ -101,6 +102,10 @@ #define AK4381_LOATT 0x03 #define AK4381_ROATT 0x04 +/* AK4396 control registers */ +#define AK4396_LOATT 0x03 +#define AK4396_ROATT 0x04 + struct spicds_info; typedef void (*spicds_ctrl)(void *, unsigned int, unsigned int, unsigned int);