Commit c4eeeab4 authored by Jaroslav Kysela's avatar Jaroslav Kysela Committed by Jaroslav Kysela

[PATCH] ALSA update [8/12] - 2002/09/06

  - VIA686 and VIA8233 driver merge to VIA82xx
  - ioctl32 fixes
  - fixed OOPS in snd_pcm_sgbuf_delete (not initialized)
  - I2C - call hw_stop() before returning at the error pointer
  - AC'97 codec - added more AC97 IDs by Laszlo Melis
  - CS46xx - mutex initialization fix
  - ENS1371 - added one more card to S/PDIF capabilities
  - intel8x0
    - fixed secondary and third codec indexes
  - PPC Keywest - initialize MCS in loop until it succeeds
  - PPC Tumbler - the initial support for snapper (TAS3004) on some tibook
  - USB Audio - mixer fixes
parent e2094b53
......@@ -113,7 +113,7 @@ static inline int _snd_magic_bad(void *obj, unsigned long magic)
#define intel8x0_t_magic 0xa15a2a01
#define es1968_t_magic 0xa15a2b01
#define esschan_t_magic 0xa15a2b02
#define via686a_t_magic 0xa15a2c01
#define via82xx_t_magic 0xa15a2c01
#define pdplus_t_magic 0xa15a2d01
#define cmipci_t_magic 0xa15a2e01
#define ymfpci_t_magic 0xa15a2f01
......@@ -126,7 +126,6 @@ static inline int _snd_magic_bad(void *obj, unsigned long magic)
#define m3_dma_t_magic 0xa15a3202
#define nm256_t_magic 0xa15a3301
#define nm256_dma_t_magic 0xa15a3302
#define via8233_t_magic 0xa15a3401
#define pmac_t_magic 0xa15a3501
#define ali_t_magic 0xa15a3601
#define mtpav_t_magic 0xa15a3701
......
/* include/version.h. Generated automatically by configure. */
#define CONFIG_SND_VERSION "0.9.0rc3"
#define CONFIG_SND_DATE " (Mon Aug 26 16:28:35 2002 UTC)"
#define CONFIG_SND_DATE " (Fri Sep 06 15:06:56 2002 UTC)"
......@@ -78,8 +78,7 @@ obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_RME32) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_RME96) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_SONICVIBES) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
obj-$(CONFIG_SND_VIA686) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_VIA8233) += snd-pcm.o snd-timer.o snd.o
obj-$(CONFIG_SND_VIA82XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_ALI5451) += snd.o snd-rawmidi.o snd-timer.o snd-pcm.o
obj-$(CONFIG_SND_CS46XX) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o
obj-$(CONFIG_SND_EMU10K1) += snd-pcm.o snd-timer.o snd.o snd-rawmidi.o snd-hwdep.o
......
......@@ -28,7 +28,5 @@
struct ioctl32_mapper hwdep_mappers[] = {
{ SNDRV_HWDEP_IOCTL_PVERSION, NULL },
{ SNDRV_HWDEP_IOCTL_INFO, NULL },
{ SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE, NULL },
{ SNDRV_CTL_IOCTL_HWDEP_INFO, NULL },
{ 0 },
};
......@@ -47,13 +47,9 @@ int snd_ioctl32_register(struct ioctl32_mapper *mappers)
int err;
struct ioctl32_mapper *m;
lock_kernel();
for (m = mappers; m->cmd; m++) {
err = register_ioctl32_conversion(m->cmd, m->handler);
if (err < 0) {
unlock_kernel();
return err;
}
if (err >= 0)
m->registered++;
}
return 0;
......@@ -63,14 +59,12 @@ void snd_ioctl32_unregister(struct ioctl32_mapper *mappers)
{
struct ioctl32_mapper *m;
lock_kernel();
for (m = mappers; m->cmd; m++) {
if (m->registered) {
unregister_ioctl32_conversion(m->cmd);
m->registered = 0;
}
}
unlock_kernel();
}
......@@ -100,36 +94,32 @@ static int _snd_ioctl32_ctl_elem_list(unsigned int fd, unsigned int cmd, unsigne
{
struct sndrv_ctl_elem_list32 data32;
struct sndrv_ctl_elem_list data;
mm_segment_t oldseg = get_fs();
mm_segment_t oldseg;
int err;
set_fs(KERNEL_DS);
if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
err = -EFAULT;
goto __err;
}
if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
return -EFAULT;
memset(&data, 0, sizeof(data));
data.offset = data32.offset;
data.space = data32.space;
data.used = data32.used;
data.count = data32.count;
data.pids = A(data32.pids);
oldseg = get_fs();
set_fs(KERNEL_DS);
err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
set_fs(oldseg);
if (err < 0)
goto __err;
return err;
/* copy the result */
data32.offset = data.offset;
data32.space = data.space;
data32.used = data.used;
data32.count = data.count;
//data.pids = data.pids;
if (copy_to_user((void*)arg, &data32, sizeof(data32))) {
err = -EFAULT;
goto __err;
}
__err:
set_fs(oldseg);
return err;
if (copy_to_user((void*)arg, &data32, sizeof(data32)))
return -EFAULT;
return 0;
}
DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_list, ctl_elem_list, SNDRV_CTL_IOCTL_ELEM_LIST);
......@@ -171,22 +161,22 @@ static int _snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigne
struct sndrv_ctl_elem_info data;
struct sndrv_ctl_elem_info32 data32;
int err;
mm_segment_t oldseg = get_fs();
mm_segment_t oldseg;
set_fs(KERNEL_DS);
if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
err = -EFAULT;
goto __err;
}
if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
return -EFAULT;
memset(&data, 0, sizeof(data));
data.id = data32.id;
/* we need to copy the item index.
* hope this doesn't break anything..
*/
data.value.enumerated.item = data32.value.enumerated.item;
oldseg = get_fs();
set_fs(KERNEL_DS);
err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
set_fs(oldseg);
if (err < 0)
goto __err;
return err;
/* restore info to 32bit */
data32.id = data.id;
data32.type = data.type;
......@@ -215,10 +205,8 @@ static int _snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigne
break;
}
if (copy_to_user((void*)arg, &data32, sizeof(data32)))
err = -EFAULT;
__err:
set_fs(oldseg);
return err;
return -EFAULT;
return 0;
}
DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_info, ctl_elem_info, SNDRV_CTL_IOCTL_ELEM_INFO);
......@@ -281,26 +269,20 @@ static int _snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsign
struct sndrv_ctl_elem_value32 data32;
int err, i;
int type;
mm_segment_t oldseg = get_fs();
set_fs(KERNEL_DS);
mm_segment_t oldseg;
/* FIXME: check the sane ioctl.. */
if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
err = -EFAULT;
goto __err;
}
if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
return -EFAULT;
memset(&data, 0, sizeof(data));
data.id = data32.id;
data.indirect = data32.indirect;
if (data.indirect) /* FIXME: this is not correct for long arrays */
data.value.integer.value_ptr = (void*)TO_PTR(data32.value.integer.value_ptr);
type = get_ctl_type(file, &data.id);
if (type < 0) {
err = type;
goto __err;
}
if (type < 0)
return type;
if (! data.indirect) {
switch (type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
......@@ -329,9 +311,12 @@ static int _snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsign
}
}
oldseg = get_fs();
set_fs(KERNEL_DS);
err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
set_fs(oldseg);
if (err < 0)
goto __err;
return err;
/* restore info to 32bit */
if (! data.indirect) {
switch (type) {
......@@ -360,10 +345,8 @@ static int _snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsign
}
}
if (copy_to_user((void*)arg, &data32, sizeof(data32)))
err = -EFAULT;
__err:
set_fs(oldseg);
return err;
return -EFAULT;
return 0;
}
DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_read, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_READ);
......@@ -392,6 +375,7 @@ static struct ioctl32_mapper control_mappers[] = {
{ SNDRV_CTL_IOCTL_ELEM_LOCK, NULL },
{ SNDRV_CTL_IOCTL_ELEM_UNLOCK, NULL },
{ SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS, NULL },
{ SNDRV_CTL_IOCTL_HWDEP_INFO, NULL },
{ SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE, NULL },
{ SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE, NULL },
{ SNDRV_CTL_IOCTL_PCM_INFO, NULL },
......@@ -427,37 +411,13 @@ static void snd_ioctl32_done(void)
static int __init snd_ioctl32_init(void)
{
int err;
err = snd_ioctl32_register(control_mappers);
if (err < 0)
return err;
err = snd_ioctl32_register(pcm_mappers);
if (err < 0) {
snd_ioctl32_done();
return err;
}
err = snd_ioctl32_register(rawmidi_mappers);
if (err < 0) {
snd_ioctl32_done();
return err;
}
err = snd_ioctl32_register(timer_mappers);
if (err < 0) {
snd_ioctl32_done();
return err;
}
err = snd_ioctl32_register(hwdep_mappers);
if (err < 0) {
snd_ioctl32_done();
return err;
}
snd_ioctl32_register(control_mappers);
snd_ioctl32_register(pcm_mappers);
snd_ioctl32_register(rawmidi_mappers);
snd_ioctl32_register(timer_mappers);
snd_ioctl32_register(hwdep_mappers);
#ifdef CONFIG_SND_SEQUENCER
err = snd_ioctl32_register(seq_mappers);
if (err < 0) {
snd_ioctl32_done();
return err;
}
snd_ioctl32_register(seq_mappers);
#endif
return 0;
}
......
......@@ -60,27 +60,23 @@ static int _snd_ioctl32_##type(unsigned int fd, unsigned int cmd, unsigned long
{\
struct sndrv_##type##32 data32;\
struct sndrv_##type data;\
mm_segment_t oldseg = get_fs();\
mm_segment_t oldseg;\
int err;\
set_fs(KERNEL_DS);\
if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {\
err = -EFAULT;\
goto __err;\
}\
if (copy_from_user(&data32, (void*)arg, sizeof(data32)))\
return -EFAULT;\
memset(&data, 0, sizeof(data));\
convert_from_32(type, &data, &data32);\
oldseg = get_fs();\
set_fs(KERNEL_DS);\
err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);\
if (err < 0) \
goto __err;\
return err;\
if (native_ctl & (_IOC_READ << _IOC_DIRSHIFT)) {\
convert_to_32(type, &data32, &data);\
if (copy_to_user((void*)arg, &data32, sizeof(data32))) {\
err = -EFAULT;\
goto __err;\
}\
if (copy_to_user((void*)arg, &data32, sizeof(data32)))\
return -EFAULT;\
}\
__err: set_fs(oldseg);\
return err;\
return 0;\
}
#define DEFINE_ALSA_IOCTL_ENTRY(name,type,native_ctl) \
......
......@@ -189,30 +189,26 @@ static int _snd_ioctl32_xferi(unsigned int fd, unsigned int cmd, unsigned long a
{
struct sndrv_xferi32 data32;
struct sndrv_xferi data;
mm_segment_t oldseg = get_fs();
mm_segment_t oldseg;
int err;
set_fs(KERNEL_DS);
if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
err = -EFAULT;
goto __err;
}
if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
return -EFAULT;
memset(&data, 0, sizeof(data));
data.result = data32.result;
data.buf = A(data32.buf);
data.frames = data32.frames;
oldseg = get_fs();
set_fs(KERNEL_DS);
err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
set_fs(oldseg);
if (err < 0)
goto __err;
return err;
/* copy the result */
data32.result = data.result;
if (copy_to_user((void*)arg, &data32, sizeof(data32))) {
err = -EFAULT;
goto __err;
}
__err:
set_fs(oldseg);
return err;
if (copy_to_user((void*)arg, &data32, sizeof(data32)))
return -EFAULT;
return 0;
}
......@@ -237,9 +233,7 @@ static int _snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long a
void *bufs[128];
int err = 0, ch, i;
u32 *bufptr;
mm_segment_t oldseg = get_fs();
set_fs(KERNEL_DS);
mm_segment_t oldseg;
/* FIXME: need to check whether fop->ioctl is sane */
......@@ -250,41 +244,31 @@ static int _snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long a
/* check validty of the command */
switch (native_ctl) {
case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) {
err = -EINVAL;
goto __err;
}
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
err = -EBADFD;
goto __err;
}
if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
return -EINVAL;
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
break;
case SNDRV_PCM_IOCTL_READN_FRAMES:
if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) {
err = -EINVAL;
goto __err;
}
if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
return -EINVAL;
break;
}
if ((ch = substream->runtime->channels) > 128) {
err = -EINVAL;
goto __err;
}
if (get_user(data32.frames, &srcptr->frames)) {
err = -EFAULT;
goto __err;
}
if ((ch = substream->runtime->channels) > 128)
return -EINVAL;
if (get_user(data32.frames, &srcptr->frames))
return -EFAULT;
__get_user(data32.bufs, &srcptr->bufs);
bufptr = (u32*)TO_PTR(data32.bufs);
for (i = 0; i < ch; i++) {
u32 ptr;
if (get_user(ptr, bufptr)) {
err = -EFAULT;
goto __err;
}
if (get_user(ptr, bufptr))
return -EFAULT;
bufs[ch] = (void*)TO_PTR(ptr);
bufptr++;
}
oldseg = get_fs();
set_fs(KERNEL_DS);
switch (native_ctl) {
case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
err = snd_pcm_lib_writev(substream, bufs, data32.frames);
......@@ -293,14 +277,12 @@ static int _snd_ioctl32_xfern(unsigned int fd, unsigned int cmd, unsigned long a
err = snd_pcm_lib_readv(substream, bufs, data32.frames);
break;
}
set_fs(oldseg);
if (err < 0)
goto __err;
return err;
if (put_user(err, &srcptr->result))
err = -EFAULT;
__err:
set_fs(oldseg);
return err < 0 ? err : 0;
return -EFAULT;
return 0;
}
......@@ -363,24 +345,22 @@ static int _snd_ioctl32_pcm_hw_params_old(unsigned int fd, unsigned int cmd, uns
{
struct sndrv_pcm_hw_params_old32 data32;
struct sndrv_pcm_hw_params data;
mm_segment_t oldseg = get_fs();
mm_segment_t oldseg;
int err;
set_fs(KERNEL_DS);
if (copy_from_user(&data32, (void*)arg, sizeof(data32))) {
err = -EFAULT;
goto __err;
}
if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
return -EFAULT;
snd_pcm_hw_convert_from_old_params(&data, &data32);
oldseg = get_fs();
set_fs(KERNEL_DS);
err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
set_fs(oldseg);
if (err < 0)
goto __err;
snd_pcm_hw_convert_to_old_params(&data32, &data);
if (copy_to_user((void*)arg, &data32, sizeof(data32))) {
err = -EFAULT;
goto __err;
}
__err: set_fs(oldseg);
return err;
snd_pcm_hw_convert_to_old_params(&data32, &data);
if (copy_to_user((void*)arg, &data32, sizeof(data32)))
return -EFAULT;
return 0;
}
......@@ -451,9 +431,5 @@ struct ioctl32_mapper pcm_mappers[] = {
{ SNDRV_PCM_IOCTL_LINK, NULL },
{ SNDRV_PCM_IOCTL_UNLINK, NULL },
{ SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE, NULL },
{ SNDRV_CTL_IOCTL_PCM_INFO, NULL },
{ SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE, NULL },
{ 0 },
};
......@@ -1169,10 +1169,14 @@ static int snd_mixer_oss_notify_handler(snd_card_t * card, int free_flag)
return err;
}
mixer->card = card;
if (*card->mixername) {
strncpy(mixer->name, card->mixername, sizeof(mixer->name) - 1);
mixer->name[sizeof(mixer->name)-1] = 0;
} else
strcpy(mixer->name, name);
snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
card->number,
name);
mixer->name);
for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++)
mixer->slots[idx].number = idx;
card->mixer_oss = mixer;
......
......@@ -80,6 +80,9 @@ int snd_pcm_sgbuf_delete(snd_pcm_substream_t *substream)
{
struct snd_sg_buf *sgbuf;
/* return in case, when sgbuf is not initialized */
if (substream->dma_private == NULL)
return -EINVAL;
sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
sgbuf_shrink(sgbuf, 0);
if (sgbuf->table)
......
......@@ -67,7 +67,7 @@ obj-$(CONFIG_SND_FM801) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-mid
obj-$(CONFIG_SND_ICE1712) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_INTEL8X0) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_SONICVIBES) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-instr.o
obj-$(CONFIG_SND_VIA686) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_VIA82XX) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_ALI5451) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_CS46XX) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o
obj-$(CONFIG_SND_EMU10K1) += snd-seq-midi.o snd-seq.o snd-seq-device.o snd-seq-midi-event.o snd-seq-midi-emul.o snd-seq-virmidi.o
......
......@@ -146,6 +146,8 @@ snd_seq_oss_synth_register(snd_seq_device_t *dev)
debug_printk(("synth %s registered %d\n", rec->name, i));
spin_unlock_irqrestore(&register_lock, flags);
dev->driver_data = rec;
if (i < SNDRV_CARDS)
snd_oss_info_register(SNDRV_OSS_INFO_DEV_SYNTH, i, rec->name);
return 0;
}
......@@ -176,6 +178,8 @@ snd_seq_oss_synth_unregister(snd_seq_device_t *dev)
max_synth_devs = index + 1;
}
spin_unlock_irqrestore(&register_lock, flags);
if (rec->seq_device < SNDRV_CARDS)
snd_oss_info_register(SNDRV_OSS_INFO_DEV_SYNTH, rec->seq_device, NULL);
snd_use_lock_sync(&rec->use_lock);
kfree(rec);
......
......@@ -35,7 +35,7 @@ obj-$(CONFIG_SND_FM801) += snd-mpu401-uart.o
obj-$(CONFIG_SND_ICE1712) += snd-mpu401-uart.o
obj-$(CONFIG_SND_INTEL8X0) += snd-mpu401-uart.o
obj-$(CONFIG_SND_SONICVIBES) += snd-mpu401-uart.o
obj-$(CONFIG_SND_VIA686) += snd-mpu401-uart.o
obj-$(CONFIG_SND_VIA82XX) += snd-mpu401-uart.o
obj-$(CONFIG_SND_ALI5451) += snd-mpu401-uart.o
obj-$(CONFIG_SND_TRIDENT) += snd-mpu401-uart.o
obj-$(CONFIG_SND_YMFPCI) += snd-mpu401-uart.o
......
......@@ -260,11 +260,15 @@ static int snd_i2c_bit_sendbytes(snd_i2c_device_t *device, unsigned char *bytes,
if (device->flags & SND_I2C_DEVICE_ADDRTEN)
return -EIO; /* not yet implemented */
snd_i2c_bit_start(bus);
if ((err = snd_i2c_bit_sendbyte(bus, device->addr << 1)) < 0)
if ((err = snd_i2c_bit_sendbyte(bus, device->addr << 1)) < 0) {
snd_i2c_bit_hw_stop(bus);
return err;
}
while (count-- > 0) {
if ((err = snd_i2c_bit_sendbyte(bus, *bytes++)) < 0)
if ((err = snd_i2c_bit_sendbyte(bus, *bytes++)) < 0) {
snd_i2c_bit_hw_stop(bus);
return err;
}
res++;
}
snd_i2c_bit_stop(bus);
......@@ -279,11 +283,15 @@ static int snd_i2c_bit_readbytes(snd_i2c_device_t *device, unsigned char *bytes,
if (device->flags & SND_I2C_DEVICE_ADDRTEN)
return -EIO; /* not yet implemented */
snd_i2c_bit_start(bus);
if ((err = snd_i2c_bit_sendbyte(bus, (device->addr << 1) | 1)) < 0)
if ((err = snd_i2c_bit_sendbyte(bus, (device->addr << 1) | 1)) < 0) {
snd_i2c_bit_hw_stop(bus);
return err;
}
while (count-- > 0) {
if ((err = snd_i2c_bit_readbyte(bus, count == 0)) < 0)
if ((err = snd_i2c_bit_readbyte(bus, count == 0)) < 0) {
snd_i2c_bit_hw_stop(bus);
return err;
}
*bytes++ = (unsigned char)err;
res++;
}
......@@ -300,10 +308,9 @@ static int snd_i2c_bit_probeaddr(snd_i2c_bus_t *bus, unsigned short addr)
if (addr & 0x7f80) /* invalid address */
return -EINVAL;
snd_i2c_bit_start(bus);
if ((err = snd_i2c_bit_sendbyte(bus, addr << 1)) < 0)
return err;
err = snd_i2c_bit_sendbyte(bus, addr << 1);
snd_i2c_bit_stop(bus);
return 1; /* present */
return err;
}
EXPORT_SYMBOL(snd_i2c_bus_create);
......
......@@ -82,8 +82,5 @@ CONFIG_SND_INTEL8X0
CONFIG_SND_SONICVIBES
Say 'Y' or 'M' to include support for S3 SonicVibes based soundcards.
CONFIG_SND_VIA686
Say 'Y' or 'M' to include support for VIA VT82C686A/B South Bridge.
CONFIG_SND_VIA8233
Say 'Y' or 'M' to include support for VIA VT8233 South Bridge.
CONFIG_SND_VIA82XX
Say 'Y' or 'M' to include support for VIA VT82C686A/B, VT8233 South Bridge.
......@@ -27,8 +27,7 @@ dep_tristate 'ForteMedia FM801' CONFIG_SND_FM801 $CONFIG_SND
dep_tristate 'ICEnsemble ICE1712 (Envy24)' CONFIG_SND_ICE1712 $CONFIG_SND
dep_tristate 'Intel i810/i820/i830/i840/MX440 integrated audio' CONFIG_SND_INTEL8X0 $CONFIG_SND
dep_tristate 'S3 SonicVibes' CONFIG_SND_SONICVIBES $CONFIG_SND
dep_tristate 'VIA 82C686A/B South Bridge' CONFIG_SND_VIA686 $CONFIG_SND
dep_tristate 'VIA 8233 South Bridge' CONFIG_SND_VIA8233 $CONFIG_SND
dep_tristate 'VIA 82C686A/B, 8233 South Bridge' CONFIG_SND_VIA82XX $CONFIG_SND
# define gameport if necessary
if [ "$CONFIG_INPUT_GAMEPORT" != "n" ]; then
......
......@@ -17,8 +17,7 @@ snd-maestro3-objs := maestro3.o
snd-rme32-objs := rme32.o
snd-rme96-objs := rme96.o
snd-sonicvibes-objs := sonicvibes.o
snd-via686-objs := via686.o
snd-via8233-objs := via8233.o
snd-via82xx-objs := via82xx.o
# Toplevel Module Dependency
obj-$(CONFIG_SND_ALS4000) += snd-als4000.o
......@@ -35,8 +34,7 @@ obj-$(CONFIG_SND_MAESTRO3) += snd-maestro3.o
obj-$(CONFIG_SND_RME32) += snd-rme32.o
obj-$(CONFIG_SND_RME96) += snd-rme96.o
obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o
obj-$(CONFIG_SND_VIA686) += snd-via686.o
obj-$(CONFIG_SND_VIA8233) += snd-via8233.o
obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o
obj-$(CONFIG_SND) += ac97/ ali5451/ cs46xx/ emu10k1/ korg1212/ nm256/ rme9652/ trident/ ymfpci/
......
......@@ -17,8 +17,7 @@ obj-$(CONFIG_SND_FM801) += snd-ac97-codec.o
obj-$(CONFIG_SND_ICE1712) += snd-ac97-codec.o
obj-$(CONFIG_SND_INTEL8X0) += snd-ac97-codec.o
obj-$(CONFIG_SND_MAESTRO3) += snd-ac97-codec.o
obj-$(CONFIG_SND_VIA686) += snd-ac97-codec.o
obj-$(CONFIG_SND_VIA8233) += snd-ac97-codec.o
obj-$(CONFIG_SND_VIA82XX) += snd-ac97-codec.o
obj-$(CONFIG_SND_ALI5451) += snd-ac97-codec.o
obj-$(CONFIG_SND_CS46XX) += snd-ac97-codec.o
obj-$(CONFIG_SND_EMU10K1) += snd-ac97-codec.o
......
......@@ -65,6 +65,7 @@ static const ac97_codec_id_t snd_ac97_codec_id_vendors[] = {
{ 0x41445300, 0xffffff00, "Analog Devices", NULL },
{ 0x414c4300, 0xffffff00, "Realtek", NULL },
{ 0x414c4700, 0xffffff00, "Avance Logic", NULL },
{ 0x434d4900, 0xffffff00, "C-Media Electronics", NULL },
{ 0x43525900, 0xffffff00, "Cirrus Logic", NULL },
{ 0x43585400, 0xffffff00, "Conexant", NULL },
{ 0x45838300, 0xffffff00, "ESS Technology", NULL },
......@@ -95,6 +96,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x41445360, 0xffffffff, "AD1885", patch_ad1885 },
{ 0x41445361, 0xffffffff, "AD1886", patch_ad1886 },
{ 0x41445362, 0xffffffff, "AD1887", patch_ad1881 },
{ 0x41445363, 0xffffffff, "AD1886A", patch_ad1881 },
{ 0x41445372, 0xffffffff, "AD1981A", patch_ad1881 },
{ 0x414c4300, 0xfffffff0, "RL5306", NULL },
{ 0x414c4310, 0xfffffff0, "RL5382", NULL },
......@@ -104,6 +106,8 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x414c4730, 0xffffffff, "ALC101", NULL },
{ 0x414c4740, 0xfffffff0, "ALC202", NULL },
{ 0x414c4750, 0xfffffff0, "ALC250", NULL },
{ 0x434d4941, 0xffffffff, "CMI9738", NULL },
{ 0x434d4961, 0xffffffff, "CMI9739", NULL },
{ 0x43525900, 0xfffffff8, "CS4297", NULL },
{ 0x43525910, 0xfffffff8, "CS4297A", patch_cirrus_spdif },
{ 0x43525920, 0xfffffff8, "CS4294/4298", NULL },
......@@ -122,6 +126,8 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x4e534331, 0xffffffff, "LM4549", NULL },
{ 0x53494c22, 0xffffffff, "Si3036", NULL },
{ 0x53494c23, 0xffffffff, "Si3038", NULL },
{ 0x54524102, 0xffffffff, "TR28022", NULL },
{ 0x54524106, 0xffffffff, "TR28026", NULL },
{ 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028 }, // added by xin jin [07/09/99]
{ 0x54524123, 0xffffffff, "TR28602", NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
{ 0x54584e20, 0xffffffff, "TLC320AD9xC", NULL },
......@@ -130,14 +136,19 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
{ 0x574d4c00, 0xffffffff, "WM9701A", patch_wolfson00 },
{ 0x574d4c03, 0xffffffff, "WM9703/9707", patch_wolfson03 },
{ 0x574d4c04, 0xffffffff, "WM9704 (quad)", patch_wolfson04 },
{ 0x574d4c05, 0xffffffff, "WM9705", NULL }, // patch?
{ 0x594d4800, 0xffffffff, "YMF743", NULL },
{ 0x594d4802, 0xffffffff, "YMF752", NULL },
{ 0x594d4803, 0xffffffff, "YMF753", NULL },
{ 0x83847600, 0xffffffff, "STAC9700/83/84", NULL },
{ 0x83847604, 0xffffffff, "STAC9701/3/4/5", NULL },
{ 0x83847605, 0xffffffff, "STAC9704", NULL },
{ 0x83847608, 0xffffffff, "STAC9708/11", patch_sigmatel_stac9708 },
{ 0x83847609, 0xffffffff, "STAC9721/23", patch_sigmatel_stac9721 },
{ 0x83847644, 0xffffffff, "STAC9744", patch_sigmatel_stac9744 },
{ 0x83847650, 0xffffffff, "STAC9750/51", NULL }, // patch?
{ 0x83847656, 0xffffffff, "STAC9756/57", patch_sigmatel_stac9756 },
{ 0x83847666, 0xffffffff, "STAC9766/67", NULL }, // patch?
{ 0, 0, NULL, NULL }
};
......@@ -201,6 +212,7 @@ static int snd_ac97_valid_reg(ac97_t *ac97, unsigned short reg)
return 1;
case AC97_ID_AD1885: /* AD1885 */
case AC97_ID_AD1886: /* AD1886 */
case AC97_ID_AD1886A: /* AD1886A - !!verify!! --jk */
case AC97_ID_AD1887: /* AD1887 - !!verify!! --jk */
if (reg == 0x5a)
return 1;
......
......@@ -30,6 +30,7 @@
#define AC97_ID_AD1885 0x41445360
#define AC97_ID_AD1886 0x41445361
#define AC97_ID_AD1887 0x41445362
#define AC97_ID_AD1886A 0x41445363
#define AC97_ID_TR28028 0x54524108
#define AC97_ID_STAC9700 0x83847600
#define AC97_ID_STAC9704 0x83847604
......
......@@ -629,6 +629,9 @@ static unsigned short snd_cs4281_ac97_read(ac97_t *ac97,
cs4281_t *chip = snd_magic_cast(cs4281_t, ac97->private_data, return -ENXIO);
int count;
unsigned short result;
// FIXME: volatile is necessary in the following due to a bug of
// some gcc versions
volatile int ac97_num = ((volatile ac97_t *)ac97)->num;
/*
* 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
......@@ -639,7 +642,7 @@ static unsigned short snd_cs4281_ac97_read(ac97_t *ac97,
* 6. Read ACSTS = Status Register = 464h, check VSTS bit
*/
snd_cs4281_peekBA0(chip, ac97->num ? BA0_ACSDA2 : BA0_ACSDA);
snd_cs4281_peekBA0(chip, ac97_num ? BA0_ACSDA2 : BA0_ACSDA);
/*
* Setup the AC97 control registers on the CS461x to send the
......@@ -658,7 +661,7 @@ static unsigned short snd_cs4281_ac97_read(ac97_t *ac97,
snd_cs4281_pokeBA0(chip, BA0_ACCDA, 0);
snd_cs4281_pokeBA0(chip, BA0_ACCTL, BA0_ACCTL_DCV | BA0_ACCTL_CRW |
BA0_ACCTL_VFRM | BA0_ACCTL_ESYN |
(ac97->num ? BA0_ACCTL_TC : 0));
(ac97_num ? BA0_ACCTL_TC : 0));
/*
......@@ -691,7 +694,7 @@ static unsigned short snd_cs4281_ac97_read(ac97_t *ac97,
* ACSTS = Status Register = 464h
* VSTS - Valid Status
*/
if (snd_cs4281_peekBA0(chip, ac97->num ? BA0_ACSTS2 : BA0_ACSTS) & BA0_ACSTS_VSTS)
if (snd_cs4281_peekBA0(chip, ac97_num ? BA0_ACSTS2 : BA0_ACSTS) & BA0_ACSTS_VSTS)
goto __ok2;
udelay(10);
}
......@@ -705,7 +708,7 @@ static unsigned short snd_cs4281_ac97_read(ac97_t *ac97,
* Read the data returned from the AC97 register.
* ACSDA = Status Data Register = 474h
*/
result = snd_cs4281_peekBA0(chip, ac97->num ? BA0_ACSDA2 : BA0_ACSDA);
result = snd_cs4281_peekBA0(chip, ac97_num ? BA0_ACSDA2 : BA0_ACSDA);
__end:
return result;
......@@ -2107,6 +2110,7 @@ static void cs4281_suspend(cs4281_t *chip)
/* remember the status registers */
for (i = 0; number_of(saved_regs); i++)
if (saved_regs[i])
chip->suspend_regs[i] = snd_cs4281_peekBA0(chip, saved_regs[i]);
/* Turn off the serial ports. */
......@@ -2150,6 +2154,7 @@ static void cs4281_resume(cs4281_t *chip)
/* restore the status registers */
for (i = 0; number_of(saved_regs); i++)
if (saved_regs[i])
snd_cs4281_pokeBA0(chip, saved_regs[i], chip->suspend_regs[i]);
if (chip->ac97)
......
......@@ -3239,6 +3239,9 @@ int __devinit snd_cs46xx_create(snd_card_t * card,
if (chip == NULL)
return -ENOMEM;
spin_lock_init(&chip->reg_lock);
#ifdef CONFIG_SND_CS46XX_NEW_DSP
init_MUTEX(&chip->spos_mutex);
#endif
chip->card = card;
chip->pci = pci;
chip->capt.hw_size = PAGE_SIZE;
......
......@@ -1298,6 +1298,7 @@ static struct {
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_ES1371, .rev = ES1371REV_CT5880_A },
{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_ES1371, .rev = ES1371REV_ES1373_8 },
{ .vid = PCI_ANY_ID, .did = PCI_ANY_ID }
};
......
/*
* Driver for ESS Solo-1 (ES1938, ES1946) soundcard
* Driver for ESS Solo-1 (ES1938, ES1946, ES1969) soundcard
* Copyright (c) by Jaromir Koutek <miri@punknet.cz>,
* Jaroslav Kysela <perex@suse.cz>,
* Thomas Sailer <sailer@ife.ee.ethz.ch>,
......@@ -70,6 +70,8 @@ MODULE_DESCRIPTION("ESS Solo-1");
MODULE_LICENSE("GPL");
MODULE_CLASSES("{sound}");
MODULE_DEVICES("{{ESS,ES1938},"
"{ESS,ES1946},"
"{ESS,ES1969},"
"{TerraTec,128i PCI}}");
#ifndef PCI_VENDOR_ID_ESS
......
......@@ -2501,11 +2501,13 @@ static int snd_es1968_set_power_state(snd_card_t *card, unsigned int power_state
static int snd_es1968_free(es1968_t *chip)
{
if (chip->res_io_port)
snd_es1968_reset(chip);
snd_es1968_set_acpi(chip, ACPI_D3);
chip->master_switch = NULL;
chip->master_volume = NULL;
if (chip->res_io_port) {
snd_es1968_reset(chip);
release_resource(chip->res_io_port);
kfree_nocheck(chip->res_io_port);
}
......
......@@ -414,7 +414,8 @@ MODULE_PARM_SYNTAX(snd_omni, SNDRV_ENABLED "," SNDRV_ENABLE_DESC);
#define ICE1712_6FIRE_TX2 0x40 /* MIDI2 */
#define ICE1712_6FIRE_RX2 0x80 /* MIDI2 */
#define ICE1712_6FIRE_CS8427_ADDR (0x22>>1) /* ?? */
#define ICE1712_6FIRE_PCF9554_ADDR (0x40>>1)
#define ICE1712_6FIRE_CS8427_ADDR (0x22>>1)
/*
* DMA mode values
......@@ -509,7 +510,7 @@ struct _snd_ice1712 {
snd_i2c_device_t *cs8404; /* CS8404A I2C device */
snd_i2c_device_t *cs8427; /* CS8427 I2C device */
snd_i2c_device_t *pcf8574[2]; /* PCF8574 Output/Input (EWS88MT) */
snd_i2c_device_t *pcf8575; /* PCF8575 (EWS88D) */
snd_i2c_device_t *pcf8575; /* PCF8575 (EWS88D) / PCF9554 (6Fire) */
unsigned char cs8403_spdif_bits;
unsigned char cs8403_spdif_stream_bits;
......@@ -2411,15 +2412,14 @@ static int __devinit snd_ice1712_ac97_mixer(ice1712_t * ice)
ac97.read = snd_ice1712_ac97_read;
ac97.private_data = ice;
ac97.private_free = snd_ice1712_mixer_free_ac97;
if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) {
if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0)
printk(KERN_WARNING "ice1712: cannot initialize ac97 for consumer, skipped\n");
// return err;
} else {
else {
if ((err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice))) < 0)
return err;
}
return 0;
}
}
/* hmm.. can we have both consumer and pro ac97 mixers? */
if (! (ice->eeprom.aclink & ICE1712_CFG_PRO_I2S)) {
ac97_t ac97;
......@@ -2428,10 +2428,9 @@ static int __devinit snd_ice1712_ac97_mixer(ice1712_t * ice)
ac97.read = snd_ice1712_pro_ac97_read;
ac97.private_data = ice;
ac97.private_free = snd_ice1712_mixer_free_ac97;
if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0) {
if ((err = snd_ac97_mixer(ice->card, &ac97, &ice->ac97)) < 0)
printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n");
// return err;
}
else
return 0;
}
/* I2S mixer only */
......@@ -3111,7 +3110,7 @@ static snd_kcontrol_new_t snd_ice1712_mixer_pro_peak __devinitdata = {
static int snd_ice1712_ewx_io_sense_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo){
static char *texts[4] = {
static char *texts[2] = {
"+4dBu", "-10dBV",
};
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
......@@ -3354,26 +3353,32 @@ static snd_kcontrol_new_t snd_ice1712_ews88d_controls[] __devinitdata = {
* DMX 6Fire controls
*/
#if 0 // XXX not working yet
static int snd_ice1712_6fire_read_pca(ice1712_t *ice)
#define PCF9554_REG_INPUT 0
#define PCF9554_REG_OUTPUT 1
#define PCF9554_REG_POLARITY 2
#define PCF9554_REG_CONFIG 3
static int snd_ice1712_6fire_read_pca(ice1712_t *ice, unsigned char reg)
{
unsigned char byte;
snd_i2c_lock(ice->i2c);
byte = 0; /* read port */
byte = reg;
snd_i2c_sendbytes(ice->pcf8575, &byte, 1);
byte = 0;
if (snd_i2c_readbytes(ice->pcf8575, &byte, 1) != 1) {
snd_i2c_unlock(ice->i2c);
printk("cannot read pca\n");
return -EIO;
}
snd_i2c_unlock(ice->i2c);
return byte;
}
static int snd_ice1712_6fire_write_pca(ice1712_t *ice, unsigned char data)
static int snd_ice1712_6fire_write_pca(ice1712_t *ice, unsigned char reg, unsigned char data)
{
unsigned char bytes[2];
snd_i2c_lock(ice->i2c);
bytes[0] = 1; /* write port */
bytes[0] = reg;
bytes[1] = data;
if (snd_i2c_sendbytes(ice->pcf8575, bytes, 2) != 2) {
snd_i2c_unlock(ice->i2c);
......@@ -3399,7 +3404,7 @@ static int snd_ice1712_6fire_control_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_
int invert = (kcontrol->private_value >> 8) & 1;
int data;
if ((data = snd_ice1712_6fire_read_pca(ice)) < 0)
if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0)
return data;
data = (data >> shift) & 1;
if (invert)
......@@ -3415,7 +3420,7 @@ static int snd_ice1712_6fire_control_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_
int invert = (kcontrol->private_value >> 8) & 1;
int data, ndata;
if ((data = snd_ice1712_6fire_read_pca(ice)) < 0)
if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0)
return data;
ndata = data & ~(1 << shift);
if (ucontrol->value.integer.value[0])
......@@ -3423,27 +3428,77 @@ static int snd_ice1712_6fire_control_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_
if (invert)
ndata ^= (1 << shift);
if (data != ndata) {
snd_ice1712_6fire_write_pca(ice, (unsigned char)ndata);
snd_ice1712_6fire_write_pca(ice, PCF9554_REG_OUTPUT, (unsigned char)ndata);
return 1;
}
return 0;
}
#define DMX6FIRE_CONTROL(xiface, xname, xshift, xinvert, xaccess) \
{ .iface = xiface,\
static int snd_ice1712_6fire_select_input_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
static char *texts[4] = {
"Internal", "Front Input", "Rear Input", "Wave Table"
};
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = 4;
if (uinfo->value.enumerated.item >= 4)
uinfo->value.enumerated.item = 1;
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
return 0;
}
static int snd_ice1712_6fire_select_input_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
ice1712_t *ice = snd_kcontrol_chip(kcontrol);
int data;
if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0)
return data;
ucontrol->value.integer.value[0] = data & 3;
return 0;
}
static int snd_ice1712_6fire_select_input_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
ice1712_t *ice = snd_kcontrol_chip(kcontrol);
int data, ndata;
if ((data = snd_ice1712_6fire_read_pca(ice, PCF9554_REG_OUTPUT)) < 0)
return data;
ndata = data & ~3;
ndata |= (ucontrol->value.integer.value[0] & 3);
if (data != ndata) {
snd_ice1712_6fire_write_pca(ice, PCF9554_REG_OUTPUT, (unsigned char)ndata);
return 1;
}
return 0;
}
#define DMX6FIRE_CONTROL(xname, xshift, xinvert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
.name = xname,\
.access = xaccess,\
.info = snd_ice1712_6fire_control_info,\
.get = snd_ice1712_6fire_control_get,\
.put = snd_ice1712_6fire_control_put,\
.private_value = xshift | (xinvert << 8),\
}
static snd_kcontrol_new_t snd_ice1712_6fire_led __devinitdata =
DMX6FIRE_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "Breakbox LED", 6, 0, 0);
#endif // XXX not working yet
static snd_kcontrol_new_t snd_ice1712_6fire_controls[] __devinitdata = {
{
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Analog Input Select",
.info = snd_ice1712_6fire_select_input_info,
.get = snd_ice1712_6fire_select_input_get,
.put = snd_ice1712_6fire_select_input_put,
},
DMX6FIRE_CONTROL("Front Digital Input Switch", 2, 0),
// DMX6FIRE_CONTROL("Master Clock Select", 3, 0),
DMX6FIRE_CONTROL("Optical Digital Input Switch", 4, 0),
DMX6FIRE_CONTROL("Phono Analog Input Switch", 5, 0),
DMX6FIRE_CONTROL("Breakbox LED", 6, 0),
};
/*
*
......@@ -3808,14 +3863,16 @@ static int __devinit snd_ice1712_chip_init(ice1712_t *ice)
}
break;
case ICE1712_SUBDEVICE_DMX6FIRE:
#if 0 // XXX not working yet
if ((err = snd_i2c_device_create(ice->i2c, "PCF9554", 0x40>>1, &ice->pcf8575)) < 0)
if ((err = snd_i2c_device_create(ice->i2c, "PCF9554", ICE1712_6FIRE_PCF9554_ADDR, &ice->pcf8575)) < 0) {
snd_printk("PCF9554 initialization failed\n");
return err;
if ((err = snd_cs8427_create(ice->i2c, 0x11, &ice->cs8427)) < 0) {
}
#if 0 // XXX not working...
if ((err = snd_cs8427_create(ice->i2c, ICE1712_6FIRE_CS8427_ADDR, &ice->cs8427)) < 0) {
snd_printk("CS8427 initialization failed\n");
return err;
}
#endif // XXX not working yet
#endif
break;
case ICE1712_SUBDEVICE_EWS88MT:
if ((err = snd_i2c_device_create(ice->i2c, "CS8404", ICE1712_EWS88MT_CS8404_ADDR, &ice->cs8404)) < 0)
......@@ -4052,11 +4109,11 @@ static int __init snd_ice1712_build_controls(ice1712_t *ice)
}
break;
case ICE1712_SUBDEVICE_DMX6FIRE:
#if 0 // XXX not working yet
err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_6fire_led, ice));
for (idx = 0; idx < sizeof(snd_ice1712_6fire_controls)/sizeof(snd_ice1712_6fire_controls[0]); idx++) {
err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_6fire_controls[idx], ice));
if (err < 0)
return err;
#endif
}
break;
}
......
......@@ -326,10 +326,6 @@ struct _snd_intel8x0 {
char ac97_name[32];
char ctrl_name[32];
unsigned long dma_playback_size;
unsigned long dma_capture_size;
unsigned long dma_mic_size;
int irq;
unsigned int mmio;
......@@ -428,7 +424,7 @@ static void iputbyte(intel8x0_t *chip, u32 offset, u8 val)
if (chip->bm_mmio)
writeb(val, chip->remap_bmaddr + offset);
else
return outb(val, chip->bmaddr + offset);
outb(val, chip->bmaddr + offset);
}
static void iputword(intel8x0_t *chip, u32 offset, u16 val)
......@@ -436,7 +432,7 @@ static void iputword(intel8x0_t *chip, u32 offset, u16 val)
if (chip->bm_mmio)
writew(val, chip->remap_bmaddr + offset);
else
return outw(val, chip->bmaddr + offset);
outw(val, chip->bmaddr + offset);
}
static void iputdword(intel8x0_t *chip, u32 offset, u32 val)
......@@ -444,7 +440,7 @@ static void iputdword(intel8x0_t *chip, u32 offset, u32 val)
if (chip->bm_mmio)
writel(val, chip->remap_bmaddr + offset);
else
return outl(val, chip->bmaddr + offset);
outl(val, chip->bmaddr + offset);
}
/*
......@@ -464,7 +460,7 @@ static void iaputword(intel8x0_t *chip, u32 offset, u16 val)
if (chip->mmio)
writew(val, chip->remap_addr + offset);
else
return outw(val, chip->addr + offset);
outw(val, chip->addr + offset);
}
/*
......@@ -1583,6 +1579,7 @@ static int __devinit snd_intel8x0_mixer(intel8x0_t *chip, int ac97_clock)
if (codecs < 2)
goto __skip_secondary;
for (i = 1; i < codecs; i++) {
ac97.num = i;
if ((err = snd_ac97_mixer(chip->card, &ac97, &x97)) < 0)
return err;
chip->ac97[i] = x97;
......@@ -1995,7 +1992,13 @@ static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip)
snd_intel8x0_setup_periods(chip, ichdev);
port = ichdev->reg_offset;
spin_lock_irqsave(&chip->reg_lock, flags);
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE | ICH_STARTBM); /* trigger */
/* trigger */
if (chip->device_type != DEVICE_ALI)
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE | ICH_STARTBM);
else {
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);
iputbyte(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
}
do_gettimeofday(&start_time);
spin_unlock_irqrestore(&chip->reg_lock, flags);
#if 0
......@@ -2014,7 +2017,10 @@ static void __devinit intel8x0_measure_ac97_clock(intel8x0_t *chip)
pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << 1;
pos += ichdev->position;
do_gettimeofday(&stop_time);
iputbyte(chip, port + ICH_REG_OFF_CR, 0); /* stop */
/* stop */
if (chip->device_type == DEVICE_ALI)
iputbyte(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 8));
iputbyte(chip, port + ICH_REG_OFF_CR, 0);
/* reset whole DMA things */
while (!(igetbyte(chip, port + ichdev->roff_sr) & ICH_DCH))
;
......@@ -2279,6 +2285,7 @@ static struct shortname_table {
{ PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia NForce" },
{ 0x746d, "AMD AMD8111" },
{ 0x7445, "AMD AMD768" },
{ 0x5455, "ALi M5455" },
{ 0, 0 },
};
......
......@@ -1517,10 +1517,8 @@ static int
snd_rme32_info_inputtype_control(snd_kcontrol_t * kcontrol,
snd_ctl_elem_info_t * uinfo)
{
static char *_texts[5] =
{ "Optical", "Coaxial", "Internal", "XLR" };
rme32_t *rme32 = _snd_kcontrol_chip(kcontrol);
char *texts[4] = { _texts[0], _texts[1], _texts[2], _texts[3] };
static char *texts[4] = { "Optical", "Coaxial", "Internal", "XLR" };
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
......@@ -1614,8 +1612,8 @@ snd_rme32_info_clockmode_control(snd_kcontrol_t * kcontrol,
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
uinfo->count = 1;
uinfo->value.enumerated.items = 4;
if (uinfo->value.enumerated.item > 4) {
uinfo->value.enumerated.item = 4;
if (uinfo->value.enumerated.item > 3) {
uinfo->value.enumerated.item = 3;
}
strcpy(uinfo->value.enumerated.name,
texts[uinfo->value.enumerated.item]);
......
/*
* ALSA driver for VIA VT8233 (South Bridge)
*
* Copyright (c) 2000 Tjeerd.Mulder@fujitsu-siemens.com
* This driver is based on VIA686 code by Jaroslav Kysela <perex@suse.cz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <sound/driver.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_sgbuf.h>
#include <sound/pcm_params.h>
#include <sound/info.h>
#include <sound/ac97_codec.h>
#include <sound/mpu401.h>
#define SNDRV_GET_ID
#include <sound/initval.h>
MODULE_AUTHOR("Tjeerd.Mulder@fujitsu-siemens.com");
MODULE_DESCRIPTION("VIA VT8233");
MODULE_LICENSE("GPL");
MODULE_CLASSES("{sound}");
MODULE_DEVICES("{{VIA,VT8233,pci}}");
static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
static int snd_ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000};
MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_index, "Index value for VIA 8233 bridge.");
MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
MODULE_PARM_DESC(snd_id, "ID string for VIA 8233 bridge.");
MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_enable, "Enable audio part of VIA 8233 bridge.");
MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
MODULE_PARM(snd_ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
MODULE_PARM_DESC(snd_ac97_clock, "AC'97 codec clock (default 48000Hz).");
MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000");
/*
* Direct registers
*/
#ifndef PCI_DEVICE_ID_VIA_8233_5
#define PCI_DEVICE_ID_VIA_8233_5 0x3059
#endif
/* revision numbers */
#define VIA_REV_PRE_8233 0x10 /* not in market */
#define VIA_REV_8233C 0x20 /* 2 rec, 4 pb, 1 multi-pb */
#define VIA_REV_8233 0x30 /* 2 rec, 4 pb, 1 multi-pb, spdif */
#define VIA_REV_8233A 0x40 /* 1 rec, 1 multi-pb, spdf */
#define VIA_REV_8235 0x50 /* 2 rec, 4 pb, 1 multi-pb, spdif */
#define VIAREG(via, x) ((via)->port + VIA_REG_##x)
/* offsets */
#define VIA_REG_OFFSET_STATUS 0x00 /* byte - channel status */
#define VIA_REG_STAT_ACTIVE 0x80 /* RO */
#define VIA_REG_STAT_TRIGGER_QUEUED 0x08 /* RO */
#define VIA_REG_STAT_STOPPED 0x04 /* RWC */
#define VIA_REG_STAT_EOL 0x02 /* RWC */
#define VIA_REG_STAT_FLAG 0x01 /* RWC */
#define VIA_REG_OFFSET_CONTROL 0x01 /* byte - channel control */
#define VIA_REG_CTRL_START 0x80 /* WO */
#define VIA_REG_CTRL_TERMINATE 0x40 /* WO */
#define VIA_REG_CTRL_AUTOSTART 0x20
#define VIA_REG_CTRL_PAUSE 0x08 /* RW */
#define VIA_REG_CTRL_INT_STOP 0x04
#define VIA_REG_CTRL_INT_EOL 0x02
#define VIA_REG_CTRL_INT_FLAG 0x01
#define VIA_REG_CTRL_INT (VIA_REG_CTRL_INT_FLAG | VIA_REG_CTRL_INT_EOL | VIA_REG_CTRL_AUTOSTART)
#define VIA_REG_OFFSET_TABLE_PTR 0x04 /* dword - channel table pointer */
#define VIA_REG_OFFSET_CURR_PTR 0x04 /* dword - channel current pointer */
#define VIA_REG_OFFSET_STOP_IDX 0x08 /* dword - stop index, channel type, sample rate */
#define VIA_REG_TYPE_16BIT 0x00200000 /* RW */
#define VIA_REG_TYPE_STEREO 0x00100000 /* RW */
#define VIA_REG_OFFSET_CURR_COUNT 0x0c /* dword - channel current count (24 bit) */
#define VIA_REG_OFFSET_CURR_INDEX 0x0f /* byte - channel current index */
#define VIA_NUM_OF_DMA_CHANNELS 2
/* playback block (VT8233/8233C) - channels 0-3 (0-0x3f) */
#define VIA_REG_PLAYBACK_STATUS 0x00 /* byte - channel status */
#define VIA_REG_PLAYBACK_CONTROL 0x01 /* byte - channel control */
#define VIA_REG_PLAYBACK_VOLUME_L 0x02 /* byte */
#define VIA_REG_PLAYBACK_VOLUME_R 0x03 /* byte */
#define VIA_REG_PLAYBACK_TABLE_PTR 0x04 /* dword - channel table pointer */
#define VIA_REG_PLAYBACK_CURR_PTR 0x04 /* dword - channel current pointer */
#define VIA_REG_PLAYBACK_STOP_IDX 0x08 /* dword - stop index, channel type, sample rate */
#define VIA_REG_PLAYBACK_CURR_COUNT 0x0c /* dword - channel current count (24 bit) */
#define VIA_REG_PLAYBACK_CURR_INDEX 0x0f /* byte - channel current index */
/* multi-channel playback */
#define VIA_REG_MULTPLAY_STATUS 0x40 /* byte - channel status */
#define VIA_REG_MULTPLAY_CONTROL 0x41 /* byte - channel control */
#define VIA_REG_MULTPLAY_FORMAT 0x42 /* byte - format and channels */
#define VIA_REG_MULTPLAY_FMT_8BIT 0x00
#define VIA_REG_MULTPLAY_FMT_16BIT 0x80
#define VIA_REG_MULTPLAY_FMT_CH_MASK 0x70 /* # channels << 4 (valid = 1,2,4,6) */
#define VIA_REG_MULTPLAY_SCRATCH 0x43 /* byte - nop */
#define VIA_REG_MULTPLAY_TABLE_PTR 0x44 /* dword - channel table pointer */
#define VIA_REG_MULTPLAY_CURR_PTR 0x44 /* dword - channel current pointer */
#define VIA_REG_MULTPLAY_STOP_IDX 0x48 /* dword - stop index, slots */
#define VIA_REG_MULTPLAY_CURR_COUNT 0x4c /* dword - channel current count (24 bit) */
#define VIA_REG_MULTIPLAY_CURR_INDEX 0x4f /* byte - channel current index */
/* capture block */
#define VIA_REG_CAPTURE_STATUS 0x60 /* byte - channel status */
#define VIA_REG_CAPTURE_CONTROL 0x61 /* byte - channel control */
#define VIA_REG_CAPTURE_FIFO 0x62 /* byte - bit 6 = fifo enable */
#define VIA_REG_CAPTURE_FIFO_ENABLE 0x40
#define VIA_REG_CAPTURE_CHANNEL 0x63 /* byte - input select */
#define VIA_REG_CAPTURE_CHANNEL_MIC 0x4
#define VIA_REG_CAPTURE_CHANNEL_LINE 0
#define VIA_REG_CAPTURE_SELECT_CODEC 0x03 /* recording source codec (0 = primary) */
#define VIA_REG_CAPTURE_TABLE_PTR 0x64 /* dword - channel table pointer */
#define VIA_REG_CAPTURE_CURR_PTR 0x64 /* dword - channel current pointer */
#define VIA_REG_CAPTURE_STOP_IDX 0x68 /* dword - stop index */
#define VIA_REG_CAPTURE_CURR_COUNT 0x6c /* dword - channel current count (24 bit) */
#define VIA_REG_CAPTURE_CURR_INDEX 0x6f /* byte - channel current index */
/* AC'97 */
#define VIA_REG_AC97 0x80 /* dword */
#define VIA_REG_AC97_CODEC_ID_MASK (3<<30)
#define VIA_REG_AC97_CODEC_ID_SHIFT 30
#define VIA_REG_AC97_SECONDARY_VALID (1<<27)
#define VIA_REG_AC97_PRIMARY_VALID (1<<25)
#define VIA_REG_AC97_ANY_VALID (VIA_REG_AC97_PRIMARY_VALID | VIA_REG_AC97_SECONDARY_VALID | (1<<28)| (1<<29))
#define VIA_REG_AC97_BUSY (1<<24)
#define VIA_REG_AC97_READ (1<<23)
#define VIA_REG_AC97_CMD_SHIFT 16
#define VIA_REG_AC97_CMD_MASK 0x7e
#define VIA_REG_AC97_DATA_SHIFT 0
#define VIA_REG_AC97_DATA_MASK 0xffff
#define VIA_REG_SGD_SHADOW 0x84 /* dword */
#define VIA_TBL_BIT_FLAG 0x40000000
#define VIA_TBL_BIT_EOL 0x80000000
/*
*
*/
typedef struct {
unsigned long reg_offset;
snd_pcm_substream_t *substream;
int running;
unsigned int size;
unsigned int fragsize;
unsigned int frags;
unsigned int page_per_frag;
unsigned int curidx;
unsigned int tbl_entries; /* number of descriptor table entries */
unsigned int tbl_size; /* size of a table entry */
u32 *table; /* physical address + flag */
dma_addr_t table_addr;
} viadev_t;
static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
struct pci_dev *pci)
{
int i, size;
struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
if (dev->table) {
snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
dev->table = NULL;
}
/* allocate buffer descriptor lists */
if (dev->fragsize < PAGE_SIZE) {
dev->tbl_size = dev->fragsize;
dev->tbl_entries = dev->frags;
dev->page_per_frag = 1;
} else {
dev->tbl_size = PAGE_SIZE;
dev->tbl_entries = sgbuf->pages;
dev->page_per_frag = dev->fragsize >> PAGE_SHIFT;
}
/* the start of each lists must be aligned to 8 bytes,
* but the kernel pages are much bigger, so we don't care
*/
dev->table = (u32*)snd_malloc_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), &dev->table_addr);
if (! dev->table)
return -ENOMEM;
if (dev->tbl_size < PAGE_SIZE) {
for (i = 0; i < dev->tbl_entries; i++)
dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[0].addr + dev->fragsize * i);
} else {
for (i = 0; i < dev->tbl_entries; i++)
dev->table[i << 1] = cpu_to_le32((u32)sgbuf->table[i].addr);
}
size = dev->size;
for (i = 0; i < dev->tbl_entries - 1; i++) {
dev->table[(i << 1) + 1] = cpu_to_le32(VIA_TBL_BIT_FLAG | dev->tbl_size);
size -= dev->tbl_size;
}
dev->table[(dev->tbl_entries << 1) - 1] = cpu_to_le32(VIA_TBL_BIT_EOL | size);
return 0;
}
static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
struct pci_dev *pci)
{
if (dev->table) {
snd_free_pci_pages(pci, PAGE_ALIGN(dev->tbl_entries * 8), dev->table, dev->table_addr);
dev->table = NULL;
}
}
/*
*/
typedef struct _snd_via8233 via8233_t;
#define chip_t via8233_t
struct _snd_via8233 {
int irq;
unsigned long port;
struct resource *res_port;
unsigned char revision;
struct pci_dev *pci;
snd_card_t *card;
snd_pcm_t *pcm;
viadev_t playback;
viadev_t capture;
ac97_t *ac97;
unsigned int ac97_clock;
spinlock_t reg_lock;
snd_info_entry_t *proc_entry;
};
static struct pci_device_id snd_via8233_ids[] __devinitdata = {
{ 0x1106, 0x3059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* VT8233 */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, snd_via8233_ids);
/*
* Basic I/O
*/
static inline unsigned int snd_via8233_codec_xread(via8233_t *chip)
{
/* this acces should be atomic */
return inl(VIAREG(chip, AC97));
}
static inline void snd_via8233_codec_xwrite(via8233_t *chip, unsigned int val)
{
/* this acces should be atomic */
outl(val, VIAREG(chip, AC97));
}
static int snd_via8233_codec_ready(via8233_t *chip, int secondary)
{
int time;
time = 1000;
do {
udelay(1);
if ((snd_via8233_codec_xread(chip) & VIA_REG_AC97_BUSY) == 0)
return 0;
} while (time--);
snd_printk("codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_via8233_codec_xread(chip));
return -EIO;
}
static void snd_via8233_codec_write(ac97_t *ac97,
unsigned short reg,
unsigned short val)
{
via8233_t *chip = snd_magic_cast(via8233_t, ac97->private_data, return);
unsigned int xval;
xval = (ac97->num) << VIA_REG_AC97_CODEC_ID_SHIFT;
xval |= ac97->num ? VIA_REG_AC97_SECONDARY_VALID : VIA_REG_AC97_PRIMARY_VALID;
xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
xval |= val << VIA_REG_AC97_DATA_SHIFT;
spin_lock(&chip->reg_lock);
snd_via8233_codec_ready(chip, ac97->num);
snd_via8233_codec_xwrite(chip, xval);
snd_via8233_codec_ready(chip, ac97->num);
spin_unlock(&chip->reg_lock);
}
static unsigned short snd_via8233_codec_read(ac97_t *ac97, unsigned short reg)
{
via8233_t *chip = snd_magic_cast(via8233_t, ac97->private_data, return ~0);
unsigned int val;
int valid = ac97->num ? VIA_REG_AC97_SECONDARY_VALID : VIA_REG_AC97_PRIMARY_VALID;
int i;
val = (ac97->num) << VIA_REG_AC97_CODEC_ID_SHIFT;
val |= valid;
val |= VIA_REG_AC97_READ;
val |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
spin_lock(&chip->reg_lock);
snd_via8233_codec_ready(chip, ac97->num);
snd_via8233_codec_xwrite(chip, val);
snd_via8233_codec_ready(chip, ac97->num);
for (i=1000; i--;) {
val = snd_via8233_codec_xread(chip);
if (val & valid) {
spin_unlock(&chip->reg_lock);
return (unsigned short)val;
}
}
spin_unlock(&chip->reg_lock);
snd_printk("codec_read: codec %i is not valid [0x%x]\n", ac97->num, val);
/* have to return some value, this is better then 0 */
return ~0;
}
#if 0
static void snd_via8233_channel_print(via8233_t *chip, viadev_t *viadev)
{
unsigned long port = chip->port + viadev->reg_offset;
printk("[0x%x] status = 0x%x, control = 0x%x, type = 0x%x, ptr = 0x%x, count = 0x%x\n",
port,
inb(port + VIA_REG_OFFSET_STATUS),
inb(port + VIA_REG_OFFSET_CONTROL),
inl(port + VIA_REG_OFFSET_STOP_IDX),
inl(port + VIA_REG_OFFSET_CURR_PTR),
inl(port + VIA_REG_OFFSET_CURR_COUNT));
}
#endif
static void snd_via8233_channel_reset(via8233_t *chip, viadev_t *viadev)
{
unsigned long port = chip->port + viadev->reg_offset;
outb(VIA_REG_CTRL_TERMINATE, port + VIA_REG_OFFSET_CONTROL);
udelay(50);
/* disable interrupts */
outb(0, port + VIA_REG_OFFSET_CONTROL);
/* clear interrupts */
outb(0x3, port + VIA_REG_OFFSET_STATUS);
}
static int snd_via8233_trigger(via8233_t *chip, viadev_t *viadev, int cmd)
{
unsigned char val;
unsigned long port = chip->port + viadev->reg_offset;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
val = VIA_REG_CTRL_INT | VIA_REG_CTRL_START;
viadev->running = 1;
break;
case SNDRV_PCM_TRIGGER_STOP:
val = VIA_REG_CTRL_TERMINATE;
viadev->running = 0;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
val = VIA_REG_CTRL_INT | VIA_REG_CTRL_PAUSE;
viadev->running = 1;
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
val = VIA_REG_CTRL_INT;
viadev->running = 0;
break;
default:
return -EINVAL;
}
outb(val, port + VIA_REG_OFFSET_CONTROL);
if (cmd == SNDRV_PCM_TRIGGER_STOP)
snd_via8233_channel_reset(chip, viadev);
return 0;
}
static int snd_via8233_setup_periods(via8233_t *chip, viadev_t *viadev,
snd_pcm_substream_t *substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
unsigned long port = chip->port + viadev->reg_offset;
int v, err;
viadev->size = snd_pcm_lib_buffer_bytes(substream);
viadev->fragsize = snd_pcm_lib_period_bytes(substream);
viadev->frags = runtime->periods;
viadev->curidx = 0;
/* the period size must be in power of 2 */
v = ld2(viadev->fragsize);
if (viadev->fragsize != (1 << v)) {
snd_printd(KERN_ERR "invalid fragment size %d\n", viadev->fragsize);
return -EINVAL;
}
snd_via8233_channel_reset(chip, viadev);
err = build_via_table(viadev, substream, chip->pci);
if (err < 0)
return err;
runtime->dma_bytes = viadev->size;
outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
if (viadev->reg_offset == VIA_REG_MULTPLAY_STATUS) {
unsigned int slots;
int fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
fmt |= runtime->channels << 4;
outb(fmt, chip->port + VIA_REG_MULTPLAY_FORMAT);
/* set sample number to slot 3, 4, 7, 8, 6, 9 */
switch (runtime->channels) {
case 1: slots = (1<<0) | (1<<4); break;
case 2: slots = (1<<0) | (2<<4); break;
case 4: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12); break;
case 6: slots = (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20); break;
default: slots = 0; break;
}
/* STOP index is never reached */
outl(0xff000000 | slots, chip->port + VIA_REG_MULTPLAY_STOP_IDX);
} else {
outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA_REG_TYPE_16BIT : 0) |
(runtime->channels > 1 ? VIA_REG_TYPE_STEREO : 0) |
0xff000000, /* STOP index is never reached */
port + VIA_REG_OFFSET_STOP_IDX);
}
return 0;
}
/*
* Interrupt handler
*/
static inline void snd_via8233_update(via8233_t *chip, viadev_t *viadev)
{
outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset);
if (viadev->substream && viadev->running) {
viadev->curidx++;
if (viadev->curidx >= viadev->page_per_frag) {
viadev->curidx = 0;
spin_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(viadev->substream);
spin_lock(&chip->reg_lock);
}
}
}
static void snd_via8233_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
via8233_t *chip = snd_magic_cast(via8233_t, dev_id, return);
spin_lock(&chip->reg_lock);
if (inb(chip->port + chip->playback.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via8233_update(chip, &chip->playback);
if (inb(chip->port + chip->capture.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via8233_update(chip, &chip->capture);
spin_unlock(&chip->reg_lock);
}
/*
* PCM part
*/
static int snd_via8233_playback_trigger(snd_pcm_substream_t * substream,
int cmd)
{
via8233_t *chip = snd_pcm_substream_chip(substream);
return snd_via8233_trigger(chip, &chip->playback, cmd);
}
static int snd_via8233_capture_trigger(snd_pcm_substream_t * substream,
int cmd)
{
via8233_t *chip = snd_pcm_substream_chip(substream);
return snd_via8233_trigger(chip, &chip->capture, cmd);
}
static int snd_via8233_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params)
{
return snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
}
static int snd_via8233_hw_free(snd_pcm_substream_t * substream)
{
return 0;
}
static int snd_via8233_playback_prepare(snd_pcm_substream_t * substream)
{
via8233_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
if (chip->playback.reg_offset != VIA_REG_MULTPLAY_STATUS) {
unsigned int tmp;
/* I don't understand this stuff but its from the documentation and this way it works */
outb(0 , VIAREG(chip, PLAYBACK_VOLUME_L));
outb(0 , VIAREG(chip, PLAYBACK_VOLUME_R));
tmp = inl(VIAREG(chip, PLAYBACK_STOP_IDX)) & ~0xfffff;
outl(tmp | (0xffff * runtime->rate)/(48000/16), VIAREG(chip, PLAYBACK_STOP_IDX));
}
return snd_via8233_setup_periods(chip, &chip->playback, substream);
}
static int snd_via8233_capture_prepare(snd_pcm_substream_t * substream)
{
via8233_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
outb(VIA_REG_CAPTURE_CHANNEL_LINE, VIAREG(chip, CAPTURE_CHANNEL));
outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIAREG(chip, CAPTURE_FIFO));
return snd_via8233_setup_periods(chip, &chip->capture, substream);
}
static inline unsigned int snd_via8233_cur_ptr(via8233_t *chip, viadev_t *viadev)
{
unsigned int val, count;
count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset) & 0xffffff;
/* The via686a does not have this current index register,
* this register makes life easier for us here. */
val = inb(VIAREG(chip, OFFSET_CURR_INDEX) + viadev->reg_offset) % viadev->tbl_entries;
if (val < viadev->tbl_entries - 1) {
val *= viadev->tbl_size;
val += viadev->tbl_size - count;
} else {
val *= viadev->tbl_size;
val += (viadev->size % viadev->tbl_size) + 1 - count;
}
// printk("pointer: ptr = 0x%x, count = 0x%x, val = 0x%x\n", ptr, count, val);
return val;
}
static snd_pcm_uframes_t snd_via8233_playback_pointer(snd_pcm_substream_t * substream)
{
via8233_t *chip = snd_pcm_substream_chip(substream);
return bytes_to_frames(substream->runtime, snd_via8233_cur_ptr(chip, &chip->playback));
}
static snd_pcm_uframes_t snd_via8233_capture_pointer(snd_pcm_substream_t * substream)
{
via8233_t *chip = snd_pcm_substream_chip(substream);
return bytes_to_frames(substream->runtime, snd_via8233_cur_ptr(chip, &chip->capture));
}
static snd_pcm_hardware_t snd_via8233_playback =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
.rates = 0,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 6,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 128 * 1024,
.periods_min = 2,
.periods_max = 128,
.fifo_size = 0,
};
static snd_pcm_hardware_t snd_via8233_capture =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID),
.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE,
.rates = 0,
.rate_min = 8000,
.rate_max = 48000,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 128 * 1024,
.period_bytes_min = 32,
.period_bytes_max = 128 * 1024,
.periods_min = 2,
.periods_max = 128,
.fifo_size = 0,
};
static unsigned int channels[] = {
1, 2, 4, 6
};
#define CHANNELS sizeof(channels) / sizeof(channels[0])
static snd_pcm_hw_constraint_list_t hw_constraints_channels = {
.count = CHANNELS,
.list = channels,
.mask = 0,
};
static int snd_via8233_playback_open(snd_pcm_substream_t * substream)
{
via8233_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
chip->playback.substream = substream;
runtime->hw = snd_via8233_playback;
runtime->hw.rates = chip->ac97->rates[AC97_RATES_FRONT_DAC];
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
return 0;
}
static int snd_via8233_capture_open(snd_pcm_substream_t * substream)
{
via8233_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
chip->capture.substream = substream;
runtime->hw = snd_via8233_capture;
runtime->hw.rates = chip->ac97->rates[AC97_RATES_ADC];
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
if ((err = snd_pcm_sgbuf_init(substream, chip->pci, 32)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err;
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
return 0;
}
static int snd_via8233_playback_close(snd_pcm_substream_t * substream)
{
via8233_t *chip = snd_pcm_substream_chip(substream);
snd_via8233_channel_reset(chip, &chip->playback);
clean_via_table(&chip->playback, substream, chip->pci);
snd_pcm_sgbuf_delete(substream);
chip->playback.substream = NULL;
return 0;
}
static int snd_via8233_capture_close(snd_pcm_substream_t * substream)
{
via8233_t *chip = snd_pcm_substream_chip(substream);
snd_via8233_channel_reset(chip, &chip->capture);
clean_via_table(&chip->capture, substream, chip->pci);
snd_pcm_sgbuf_delete(substream);
chip->capture.substream = NULL;
return 0;
}
static snd_pcm_ops_t snd_via8233_playback_ops = {
.open = snd_via8233_playback_open,
.close = snd_via8233_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_via8233_hw_params,
.hw_free = snd_via8233_hw_free,
.prepare = snd_via8233_playback_prepare,
.trigger = snd_via8233_playback_trigger,
.pointer = snd_via8233_playback_pointer,
.copy = snd_pcm_sgbuf_ops_copy_playback,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
static snd_pcm_ops_t snd_via8233_capture_ops = {
.open = snd_via8233_capture_open,
.close = snd_via8233_capture_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_via8233_hw_params,
.hw_free = snd_via8233_hw_free,
.prepare = snd_via8233_capture_prepare,
.trigger = snd_via8233_capture_trigger,
.pointer = snd_via8233_capture_pointer,
.copy = snd_pcm_sgbuf_ops_copy_capture,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
static void snd_via8233_pcm_free(snd_pcm_t *pcm)
{
via8233_t *chip = snd_magic_cast(via8233_t, pcm->private_data, return);
chip->pcm = NULL;
}
static int __devinit snd_via8233_pcm(via8233_t *chip, int device, snd_pcm_t ** rpcm)
{
snd_pcm_t *pcm;
int err;
if (rpcm)
*rpcm = NULL;
err = snd_pcm_new(chip->card, "VIA 8233", device, 1, 1, &pcm);
if (err < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via8233_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via8233_capture_ops);
pcm->private_data = chip;
pcm->private_free = snd_via8233_pcm_free;
pcm->info_flags = 0;
strcpy(pcm->name, "VIA 8233");
chip->pcm = pcm;
if (rpcm)
*rpcm = NULL;
return 0;
}
/*
* Mixer part
*/
static void snd_via8233_mixer_free_ac97(ac97_t *ac97)
{
via8233_t *chip = snd_magic_cast(via8233_t, ac97->private_data, return);
chip->ac97 = NULL;
}
static int __devinit snd_via8233_mixer(via8233_t *chip)
{
ac97_t ac97;
int err;
memset(&ac97, 0, sizeof(ac97));
ac97.write = snd_via8233_codec_write;
ac97.read = snd_via8233_codec_read;
ac97.private_data = chip;
ac97.private_free = snd_via8233_mixer_free_ac97;
ac97.clock = chip->ac97_clock;
if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0)
return err;
return 0;
}
/*
*
*/
static int __devinit snd_via8233_chip_init(via8233_t *chip)
{
ac97_t ac97;
unsigned char stat;
int i;
memset(&ac97, 0, sizeof(ac97));
ac97.private_data = chip;
/* deassert ACLink reset */
pci_write_config_byte(chip->pci, 0x41, 0x40);
udelay(100);
/* deassert ACLink reset, force SYNC (warm AC'97 reset) */
pci_write_config_byte(chip->pci, 0x41, 0x60);
udelay(2);
/* ACLink on, deassert ACLink reset, VSR, SGD data out */
pci_write_config_byte(chip->pci, 0x41, 0xcc);
/* Wait for codec ready to be accessed. */
for (i=HZ; i--; ) {
pci_read_config_byte(chip->pci, 0x40, &stat);
if (stat & 1)
break;
if (!i) {
snd_printk("chip_init: failed to access primary codec.\n");
return ~0;
}
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
}
snd_via8233_codec_ready(chip, 0);
snd_via8233_codec_write(&ac97, AC97_RESET, 0x0000);
snd_via8233_codec_read(&ac97, 0);
/* disable interrupts */
snd_via8233_channel_reset(chip, &chip->playback);
snd_via8233_channel_reset(chip, &chip->capture);
return 0;
}
static int snd_via8233_free(via8233_t *chip)
{
if (chip->irq < 0)
goto __end_hw;
/* disable interrupts */
snd_via8233_channel_reset(chip, &chip->playback);
snd_via8233_channel_reset(chip, &chip->capture);
/* --- */
synchronize_irq(chip->irq);
__end_hw:
if (chip->res_port) {
release_resource(chip->res_port);
kfree_nocheck(chip->res_port);
}
if (chip->irq >= 0)
free_irq(chip->irq, (void *)chip);
snd_magic_kfree(chip);
return 0;
}
static int snd_via8233_dev_free(snd_device_t *device)
{
via8233_t *chip = snd_magic_cast(via8233_t, device->device_data, return -ENXIO);
return snd_via8233_free(chip);
}
static int __devinit snd_via8233_create(snd_card_t * card,
struct pci_dev *pci,
unsigned int ac97_clock,
via8233_t ** r_via)
{
via8233_t *chip;
int err;
static snd_device_ops_t ops = {
.dev_free = snd_via8233_dev_free,
};
if ((err = pci_enable_device(pci)) < 0)
return err;
if ((chip = snd_magic_kcalloc(via8233_t, 0, GFP_KERNEL)) == NULL)
return -ENOMEM;
spin_lock_init(&chip->reg_lock);
chip->card = card;
chip->pci = pci;
chip->irq = -1;
chip->port = pci_resource_start(pci, 0);
if ((chip->res_port = request_region(chip->port, 256, "VIA8233")) == NULL) {
snd_via8233_free(chip);
snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->port, chip->port + 256 - 1);
return -EBUSY;
}
if (request_irq(pci->irq, snd_via8233_interrupt, SA_INTERRUPT|SA_SHIRQ, "VIA8233", (void *)chip)) {
snd_via8233_free(chip);
snd_printk("unable to grab IRQ %d\n", chip->irq);
return -EBUSY;
}
chip->irq = pci->irq;
if (ac97_clock >= 8000 && ac97_clock <= 48000)
chip->ac97_clock = ac97_clock;
pci_read_config_byte(pci, PCI_REVISION_ID, &chip->revision);
synchronize_irq(chip->irq);
/* initialize offsets */
#if 0
chip->playback.reg_offset = VIA_REG_PLAYBACK_STATUS; /* this doesn't work on VIA8233A */
#endif
/* we use multi-channel playback mode, since this mode is supported
* by all VIA8233 models (and obviously suitable for our purpose).
*/
chip->playback.reg_offset = VIA_REG_MULTPLAY_STATUS;
chip->capture.reg_offset = VIA_REG_CAPTURE_STATUS;
if ((err = snd_via8233_chip_init(chip)) < 0) {
snd_via8233_free(chip);
return err;
}
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_via8233_free(chip);
return err;
}
/* The 8233 ac97 controller does not implement the master bit
* in the pci command register. IMHO this is a violation of the PCI spec.
* We call pci_set_master here because it does not hurt. */
pci_set_master(pci);
*r_via = chip;
return 0;
}
static int __devinit snd_via8233_probe(struct pci_dev *pci,
const struct pci_device_id *id)
{
static int dev;
snd_card_t *card;
via8233_t *chip;
int pcm_dev = 0;
int err;
if (dev >= SNDRV_CARDS)
return -ENODEV;
if (!snd_enable[dev]) {
dev++;
return -ENOENT;
}
card = snd_card_new(snd_index[dev], snd_id[dev], THIS_MODULE, 0);
if (card == NULL)
return -ENOMEM;
if ((err = snd_via8233_create(card,
pci,
snd_ac97_clock[dev],
&chip)) < 0) {
snd_card_free(card);
return err;
}
if (snd_via8233_mixer(chip) < 0) {
snd_card_free(card);
return err;
}
if (snd_via8233_pcm(chip, pcm_dev++, NULL) < 0) {
snd_card_free(card);
return err;
}
strcpy(card->driver, "VIA8233");
strcpy(card->shortname, "VIA 8233");
sprintf(card->longname, "%s at 0x%lx, irq %d",
card->shortname, chip->port, chip->irq);
if ((err = snd_card_register(card)) < 0) {
snd_card_free(card);
return err;
}
pci_set_drvdata(pci, card);
dev++;
return 0;
}
static void __devexit snd_via8233_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
pci_set_drvdata(pci, NULL);
}
static struct pci_driver driver = {
.name = "VIA 8233",
.id_table = snd_via8233_ids,
.probe = snd_via8233_probe,
.remove = __devexit_p(snd_via8233_remove),
};
static int __init alsa_card_via8233_init(void)
{
int err;
if ((err = pci_module_init(&driver)) < 0) {
#ifdef MODULE
printk(KERN_ERR "VIA 8233 soundcard not found or device busy\n");
#endif
return err;
}
return 0;
}
static void __exit alsa_card_via8233_exit(void)
{
pci_unregister_driver(&driver);
}
module_init(alsa_card_via8233_init)
module_exit(alsa_card_via8233_exit)
#ifndef MODULE
/* format is: snd-via8233=snd_enable,snd_index,snd_id,snd_ac97_clock */
static int __init alsa_card_via8233_setup(char *str)
{
static unsigned __initdata nr_dev = 0;
if (nr_dev >= SNDRV_CARDS)
return 0;
(void)(get_option(&str,&snd_enable[nr_dev]) == 2 &&
get_option(&str,&snd_index[nr_dev]) == 2 &&
get_id(&str,&snd_id[nr_dev]) == 2 &&
get_option(&str,&snd_ac97_clock[nr_dev]) == 2);
nr_dev++;
return 1;
}
__setup("snd-via8233=", alsa_card_via8233_setup);
#endif /* ifndef MODULE */
/*
* ALSA driver for VIA VT82C686A (South Bridge)
* ALSA driver for VIA VT82xx (South Bridge)
*
* VT82C686A/B/C, VT8233A/C, VT8235
*
* Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
* Tjeerd.Mulder <Tjeerd.Mulder@fujitsu-siemens.com>
* 2002 Takashi Iwai <tiwai@suse.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -37,10 +41,10 @@
#include <sound/initval.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
MODULE_DESCRIPTION("VIA VT82C686A");
MODULE_DESCRIPTION("VIA VT82xx audio");
MODULE_LICENSE("GPL");
MODULE_CLASSES("{sound}");
MODULE_DEVICES("{{VIA,VT82C686A,pci},{VIA,VT82C686B}}");
MODULE_DEVICES("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/B/C}}");
static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
......@@ -49,13 +53,13 @@ static long snd_mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1};
static int snd_ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000};
MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_index, "Index value for VIA 82C686A bridge.");
MODULE_PARM_DESC(snd_index, "Index value for VIA 82xx bridge.");
MODULE_PARM_SYNTAX(snd_index, SNDRV_INDEX_DESC);
MODULE_PARM(snd_id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
MODULE_PARM_DESC(snd_id, "ID string for VIA 82C686A bridge.");
MODULE_PARM_DESC(snd_id, "ID string for VIA 82xx bridge.");
MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_enable, "Enable audio part of VIA 82C686A bridge.");
MODULE_PARM_DESC(snd_enable, "Enable audio part of VIA 82xx bridge.");
MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
MODULE_PARM(snd_mpu_port, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
MODULE_PARM_DESC(snd_mpu_port, "MPU-401 port.");
......@@ -64,17 +68,29 @@ MODULE_PARM(snd_ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "l");
MODULE_PARM_DESC(snd_ac97_clock, "AC'97 codec clock (default 48000Hz).");
MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000");
/*
* Direct registers
*/
/* pci ids */
#ifndef PCI_DEVICE_ID_VIA_82C686_5
#define PCI_DEVICE_ID_VIA_82C686_5 0x3058
#endif
#ifndef PCI_DEVICE_ID_VIA_8233_5
#define PCI_DEVICE_ID_VIA_8233_5 0x3059
#endif
/* revision numbers for via8233 */
#define VIA_REV_PRE_8233 0x10 /* not in market */
#define VIA_REV_8233C 0x20 /* 2 rec, 4 pb, 1 multi-pb */
#define VIA_REV_8233 0x30 /* 2 rec, 4 pb, 1 multi-pb, spdif */
#define VIA_REV_8233A 0x40 /* 1 rec, 1 multi-pb, spdf */
#define VIA_REV_8235 0x50 /* 2 rec, 4 pb, 1 multi-pb, spdif */
/*
* Direct registers
*/
#define VIAREG(via, x) ((via)->port + VIA_REG_##x)
/* offsets */
/* common offsets */
#define VIA_REG_OFFSET_STATUS 0x00 /* byte - channel status */
#define VIA_REG_STAT_ACTIVE 0x80 /* RO */
#define VIA_REG_STAT_PAUSED 0x40 /* RO */
......@@ -85,9 +101,14 @@ MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000");
#define VIA_REG_OFFSET_CONTROL 0x01 /* byte - channel control */
#define VIA_REG_CTRL_START 0x80 /* WO */
#define VIA_REG_CTRL_TERMINATE 0x40 /* WO */
#define VIA_REG_CTRL_AUTOSTART 0x20
#define VIA_REG_CTRL_PAUSE 0x08 /* RW */
#define VIA_REG_CTRL_INT_STOP 0x04
#define VIA_REG_CTRL_INT_EOL 0x02
#define VIA_REG_CTRL_INT_FLAG 0x01
#define VIA_REG_CTRL_RESET 0x01 /* RW - probably reset? undocumented */
#define VIA_REG_OFFSET_TYPE 0x02 /* byte - channel type */
#define VIA_REG_CTRL_INT (VIA_REG_CTRL_INT_FLAG | VIA_REG_CTRL_INT_EOL | VIA_REG_CTRL_AUTOSTART)
#define VIA_REG_OFFSET_TYPE 0x02 /* byte - channel type (686 only) */
#define VIA_REG_TYPE_AUTOSTART 0x80 /* RW - autostart at EOL */
#define VIA_REG_TYPE_16BIT 0x20 /* RW */
#define VIA_REG_TYPE_STEREO 0x10 /* RW */
......@@ -99,28 +120,28 @@ MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000");
#define VIA_REG_TYPE_INT_FLAG 0x01
#define VIA_REG_OFFSET_TABLE_PTR 0x04 /* dword - channel table pointer */
#define VIA_REG_OFFSET_CURR_PTR 0x04 /* dword - channel current pointer */
#define VIA_REG_OFFSET_CURR_COUNT 0x0c /* dword - channel current count */
#define VIA_REG_OFFSET_STOP_IDX 0x08 /* dword - stop index, channel type, sample rate */
#define VIA8233_REG_TYPE_16BIT 0x00200000 /* RW */
#define VIA8233_REG_TYPE_STEREO 0x00100000 /* RW */
#define VIA_REG_OFFSET_CURR_COUNT 0x0c /* dword - channel current count (24 bit) */
#define VIA_REG_OFFSET_CURR_INDEX 0x0f /* byte - channel current index */
#define DEFINE_VIA_REGSET(name,val) \
enum {\
VIA_REG_##name##_STATUS = (val),\
VIA_REG_##name##_CONTROL = (val) + 0x01,\
VIA_REG_##name##_TYPE = (val) + 0x02,\
VIA_REG_##name##_TABLE_PTR = (val) + 0x04,\
VIA_REG_##name##_CURR_PTR = (val) + 0x04,\
VIA_REG_##name##_STOP_IDX = (val) + 0x08,\
VIA_REG_##name##_CURR_COUNT = (val) + 0x0c,\
}
/* playback block */
#define VIA_REG_PLAYBACK_STATUS 0x00 /* byte - channel status */
#define VIA_REG_PLAYBACK_CONTROL 0x01 /* byte - channel control */
#define VIA_REG_PLAYBACK_TYPE 0x02 /* byte - channel type */
#define VIA_REG_PLAYBACK_TABLE_PTR 0x04 /* dword - channel table pointer */
#define VIA_REG_PLAYBACK_CURR_PTR 0x04 /* dword - channel current pointer */
#define VIA_REG_PLAYBACK_CURR_COUNT 0x0c /* dword - channel current count */
/* capture block */
#define VIA_REG_CAPTURE_STATUS 0x10 /* byte - channel status */
#define VIA_REG_CAPTURE_CONTROL 0x11 /* byte - channel control */
#define VIA_REG_CAPTURE_TYPE 0x12 /* byte - channel type */
#define VIA_REG_CAPTURE_TABLE_PTR 0x14 /* dword - channel table pointer */
#define VIA_REG_CAPTURE_CURR_PTR 0x14 /* dword - channel current pointer */
#define VIA_REG_CAPTURE_CURR_COUNT 0x1c /* dword - channel current count */
/* FM block */
#define VIA_REG_FM_STATUS 0x20 /* byte - channel status */
#define VIA_REG_FM_CONTROL 0x21 /* byte - channel control */
#define VIA_REG_FM_TYPE 0x22 /* byte - channel type */
#define VIA_REG_FM_TABLE_PTR 0x24 /* dword - channel table pointer */
#define VIA_REG_FM_CURR_PTR 0x24 /* dword - channel current pointer */
#define VIA_REG_FM_CURR_COUNT 0x2c /* dword - channel current count */
DEFINE_VIA_REGSET(PLAYBACK, 0x00);
DEFINE_VIA_REGSET(CAPTURE, 0x10);
DEFINE_VIA_REGSET(FM, 0x20);
/* AC'97 */
#define VIA_REG_AC97 0x80 /* dword */
#define VIA_REG_AC97_CODEC_ID_MASK (3<<30)
......@@ -137,6 +158,24 @@ MODULE_PARM_SYNTAX(snd_ac97_clock, SNDRV_ENABLED ",default:48000");
#define VIA_REG_AC97_DATA_MASK 0xffff
#define VIA_REG_SGD_SHADOW 0x84 /* dword */
/* multi-channel and capture registers for via8233 */
DEFINE_VIA_REGSET(MULTPLAY, 0x20);
DEFINE_VIA_REGSET(CAPTURE_8233, 0x10);
/* via8233-specific registers */
#define VIA_REG_PLAYBACK_VOLUME_L 0x02 /* byte */
#define VIA_REG_PLAYBACK_VOLUME_R 0x03 /* byte */
#define VIA_REG_MULTPLAY_FORMAT 0x42 /* byte - format and channels */
#define VIA_REG_MULTPLAY_FMT_8BIT 0x00
#define VIA_REG_MULTPLAY_FMT_16BIT 0x80
#define VIA_REG_MULTPLAY_FMT_CH_MASK 0x70 /* # channels << 4 (valid = 1,2,4,6) */
#define VIA_REG_CAPTURE_FIFO 0x62 /* byte - bit 6 = fifo enable */
#define VIA_REG_CAPTURE_FIFO_ENABLE 0x40
#define VIA_REG_CAPTURE_CHANNEL 0x63 /* byte - input select */
#define VIA_REG_CAPTURE_CHANNEL_MIC 0x4
#define VIA_REG_CAPTURE_CHANNEL_LINE 0
#define VIA_REG_CAPTURE_SELECT_CODEC 0x03 /* recording source codec (0 = primary) */
#define VIA_TBL_BIT_FLAG 0x40000000
#define VIA_TBL_BIT_EOL 0x80000000
......@@ -221,14 +260,17 @@ static void clean_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
/*
*/
typedef struct _snd_via686a via686a_t;
#define chip_t via686a_t
enum { TYPE_VIA686, TYPE_VIA8233 };
struct _snd_via686a {
typedef struct _snd_via82xx via82xx_t;
#define chip_t via82xx_t
struct _snd_via82xx {
int irq;
unsigned long port;
struct resource *res_port;
int chip_type;
unsigned char revision;
unsigned char old_legacy;
......@@ -238,10 +280,8 @@ struct _snd_via686a {
snd_card_t *card;
snd_pcm_t *pcm;
/*snd_pcm_t *pcm_fm;*/
viadev_t playback;
viadev_t capture;
/*viadev_t playback_fm;*/
snd_rawmidi_t *rmidi;
......@@ -250,45 +290,47 @@ struct _snd_via686a {
unsigned int ac97_secondary; /* secondary AC'97 codec is present */
spinlock_t reg_lock;
spinlock_t ac97_lock;
snd_info_entry_t *proc_entry;
};
static struct pci_device_id snd_via686a_ids[] __devinitdata = {
static struct pci_device_id snd_via82xx_ids[] __devinitdata = {
{ 0x1106, 0x3058, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 686A */
{ 0x1106, 0x3059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* VT8233 */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, snd_via686a_ids);
MODULE_DEVICE_TABLE(pci, snd_via82xx_ids);
/*
* Basic I/O
*/
static inline unsigned int snd_via686a_codec_xread(via686a_t *chip)
static inline unsigned int snd_via82xx_codec_xread(via82xx_t *chip)
{
return inl(VIAREG(chip, AC97));
}
static inline void snd_via686a_codec_xwrite(via686a_t *chip, unsigned int val)
static inline void snd_via82xx_codec_xwrite(via82xx_t *chip, unsigned int val)
{
outl(val, VIAREG(chip, AC97));
}
static int snd_via686a_codec_ready(via686a_t *chip, int secondary)
static int snd_via82xx_codec_ready(via82xx_t *chip, int secondary)
{
unsigned int timeout = 1000; /* 1ms */
unsigned int val;
while (timeout-- > 0) {
udelay(1);
if (!((val = snd_via686a_codec_xread(chip)) & VIA_REG_AC97_BUSY))
if (!((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY))
return val & 0xffff;
}
snd_printk("codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_via686a_codec_xread(chip));
snd_printk("codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_via82xx_codec_xread(chip));
return -EIO;
}
static int snd_via686a_codec_valid(via686a_t *chip, int secondary)
static int snd_via82xx_codec_valid(via82xx_t *chip, int secondary)
{
unsigned int timeout = 1000; /* 1ms */
unsigned int val;
......@@ -297,130 +339,119 @@ static int snd_via686a_codec_valid(via686a_t *chip, int secondary)
while (timeout-- > 0) {
udelay(1);
if ((val = snd_via686a_codec_xread(chip)) & stat)
if ((val = snd_via82xx_codec_xread(chip)) & stat)
return val & 0xffff;
}
snd_printk("codec_valid: codec %i is not valid [0x%x]\n", secondary, snd_via686a_codec_xread(chip));
snd_printk("codec_valid: codec %i is not valid [0x%x]\n", secondary, snd_via82xx_codec_xread(chip));
return -EIO;
}
static void snd_via686a_codec_wait(ac97_t *ac97)
static void snd_via82xx_codec_wait(ac97_t *ac97)
{
via686a_t *chip = snd_magic_cast(via686a_t, ac97->private_data, return);
via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return);
int err;
err = snd_via686a_codec_ready(chip, ac97->num);
err = snd_via82xx_codec_ready(chip, ac97->num);
/* here we need to wait fairly for long time.. */
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(HZ/2);
}
static void snd_via686a_codec_write(ac97_t *ac97,
static void snd_via82xx_codec_write(ac97_t *ac97,
unsigned short reg,
unsigned short val)
{
via686a_t *chip = snd_magic_cast(via686a_t, ac97->private_data, return);
via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return);
unsigned int xval;
xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY;
xval <<= VIA_REG_AC97_CODEC_ID_SHIFT;
xval |= reg << VIA_REG_AC97_CMD_SHIFT;
xval |= val << VIA_REG_AC97_DATA_SHIFT;
spin_lock(&chip->reg_lock);
snd_via686a_codec_xwrite(chip, xval);
snd_via686a_codec_ready(chip, ac97->num);
spin_unlock(&chip->reg_lock);
spin_lock(&chip->ac97_lock);
snd_via82xx_codec_xwrite(chip, xval);
snd_via82xx_codec_ready(chip, ac97->num);
spin_unlock(&chip->ac97_lock);
}
static unsigned short snd_via686a_codec_read(ac97_t *ac97, unsigned short reg)
static unsigned short snd_via82xx_codec_read(ac97_t *ac97, unsigned short reg)
{
via686a_t *chip = snd_magic_cast(via686a_t, ac97->private_data, return ~0);
via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return ~0);
unsigned int xval, val = 0xffff;
int again = 0;
xval = !ac97->num ? VIA_REG_AC97_CODEC_ID_PRIMARY : VIA_REG_AC97_CODEC_ID_SECONDARY;
xval <<= VIA_REG_AC97_CODEC_ID_SHIFT;
xval = (!ac97->num ? VIA_REG_AC97_PRIMARY_VALID : VIA_REG_AC97_SECONDARY_VALID);
xval = ac97->num << VIA_REG_AC97_CODEC_ID_SHIFT;
xval |= ac97->num ? VIA_REG_AC97_SECONDARY_VALID : VIA_REG_AC97_PRIMARY_VALID;
xval |= VIA_REG_AC97_READ;
xval |= reg << VIA_REG_AC97_CMD_SHIFT;
spin_lock(&chip->reg_lock);
xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT;
spin_lock(&chip->ac97_lock);
while (1) {
if (again++ > 3) {
spin_unlock(&chip->reg_lock);
spin_unlock(&chip->ac97_lock);
return 0xffff;
}
snd_via686a_codec_xwrite(chip, xval);
if (snd_via686a_codec_ready(chip, ac97->num) < 0)
snd_via82xx_codec_xwrite(chip, xval);
if (snd_via82xx_codec_ready(chip, ac97->num) < 0)
continue;
if (snd_via686a_codec_valid(chip, ac97->num) >= 0) {
if (snd_via82xx_codec_valid(chip, ac97->num) >= 0) {
udelay(25);
val = snd_via686a_codec_xread(chip);
val = snd_via82xx_codec_xread(chip);
break;
}
}
spin_unlock(&chip->reg_lock);
spin_unlock(&chip->ac97_lock);
return val & 0xffff;
}
#if 0
static void snd_via686a_channel_print(via686a_t *chip, viadev_t *viadev)
{
unsigned long port = chip->port + viadev->reg_offset;
printk("[0x%x] status = 0x%x, control = 0x%x, type = 0x%x, ptr = 0x%x, count = 0x%x\n",
port,
inb(port + VIA_REG_OFFSET_STATUS),
inb(port + VIA_REG_OFFSET_CONTROL),
inb(port + VIA_REG_OFFSET_TYPE),
inl(port + VIA_REG_OFFSET_CURR_PTR),
inl(port + VIA_REG_OFFSET_CURR_COUNT));
}
#endif
static void snd_via686a_channel_reset(via686a_t *chip, viadev_t *viadev)
static void snd_via82xx_channel_reset(via82xx_t *chip, viadev_t *viadev)
{
unsigned long port = chip->port + viadev->reg_offset;
outb(VIA_REG_CTRL_PAUSE | VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET, port + VIA_REG_OFFSET_CONTROL);
udelay(50);
/* disable interrupts */
outb(0x00, port + VIA_REG_OFFSET_CONTROL);
outb(0xff, port + VIA_REG_OFFSET_STATUS);
outb(0x00, port + VIA_REG_OFFSET_TYPE);
/* clear interrupts */
outb(0x03, port + VIA_REG_OFFSET_STATUS);
outb(0x00, port + VIA_REG_OFFSET_TYPE); /* for via686 */
outl(0, port + VIA_REG_OFFSET_CURR_PTR);
}
static int snd_via686a_trigger(via686a_t *chip, viadev_t *viadev, int cmd)
static int snd_via82xx_trigger(via82xx_t *chip, viadev_t *viadev, int cmd)
{
unsigned char val = 0;
unsigned char val;
unsigned long port = chip->port + viadev->reg_offset;
if (chip->chip_type == TYPE_VIA8233)
val = VIA_REG_CTRL_INT;
else
val = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
val = VIA_REG_CTRL_START;
val |= VIA_REG_CTRL_START;
viadev->running = 1;
break;
case SNDRV_PCM_TRIGGER_STOP:
val = VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET;
val = VIA_REG_CTRL_TERMINATE;
viadev->running = 0;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
val = VIA_REG_CTRL_PAUSE;
viadev->running = 1;
val |= VIA_REG_CTRL_PAUSE;
viadev->running = 0;
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
val = 0;
viadev->running = 0;
viadev->running = 1;
break;
default:
return -EINVAL;
}
outb(val, port + VIA_REG_OFFSET_CONTROL);
if (cmd == SNDRV_PCM_TRIGGER_STOP)
snd_via686a_channel_reset(chip, viadev);
snd_via82xx_channel_reset(chip, viadev);
return 0;
}
static int snd_via686a_setup_periods(via686a_t *chip, viadev_t *viadev,
static int snd_via82xx_setup_periods(via82xx_t *chip, viadev_t *viadev,
snd_pcm_substream_t *substream)
{
snd_pcm_runtime_t *runtime = substream->runtime;
......@@ -441,7 +472,7 @@ static int snd_via686a_setup_periods(via686a_t *chip, viadev_t *viadev,
return -EINVAL;
}
snd_via686a_channel_reset(chip, viadev);
snd_via82xx_channel_reset(chip, viadev);
err = build_via_table(viadev, substream, chip->pci);
if (err < 0)
......@@ -449,12 +480,39 @@ static int snd_via686a_setup_periods(via686a_t *chip, viadev_t *viadev,
runtime->dma_bytes = viadev->size;
outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
switch (chip->chip_type) {
case TYPE_VIA686:
outb(VIA_REG_TYPE_AUTOSTART |
(runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA_REG_TYPE_16BIT : 0) |
(runtime->channels > 1 ? VIA_REG_TYPE_STEREO : 0) |
((viadev->reg_offset & 0x10) == 0 ? VIA_REG_TYPE_INT_LSAMPLE : 0) |
VIA_REG_TYPE_INT_EOL |
VIA_REG_TYPE_INT_FLAG, port + VIA_REG_OFFSET_TYPE);
break;
case TYPE_VIA8233:
if (viadev->reg_offset == VIA_REG_MULTPLAY_STATUS) {
unsigned int slots;
int fmt = (runtime->format == SNDRV_PCM_FORMAT_S16_LE) ? VIA_REG_MULTPLAY_FMT_16BIT : VIA_REG_MULTPLAY_FMT_8BIT;
fmt |= runtime->channels << 4;
outb(fmt, port + VIA_REG_OFFSET_TYPE);
/* set sample number to slot 3, 4, 7, 8, 6, 9 */
switch (runtime->channels) {
case 1: slots = (1<<0) | (1<<4); break;
case 2: slots = (1<<0) | (2<<4); break;
case 4: slots = (1<<0) | (2<<4) | (3<<8) | (4<<12); break;
case 6: slots = (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20); break;
default: slots = 0; break;
}
/* STOP index is never reached */
outl(0xff000000 | slots, port + VIA_REG_OFFSET_STOP_IDX);
} else {
outl((runtime->format == SNDRV_PCM_FORMAT_S16_LE ? VIA8233_REG_TYPE_16BIT : 0) |
(runtime->channels > 1 ? VIA8233_REG_TYPE_STEREO : 0) |
0xff000000, /* STOP index is never reached */
port + VIA_REG_OFFSET_STOP_IDX);
}
break;
}
return 0;
}
......@@ -462,7 +520,7 @@ static int snd_via686a_setup_periods(via686a_t *chip, viadev_t *viadev,
* Interrupt handler
*/
static inline void snd_via686a_update(via686a_t *chip, viadev_t *viadev)
static inline void snd_via82xx_update(via82xx_t *chip, viadev_t *viadev)
{
outb(VIA_REG_STAT_FLAG | VIA_REG_STAT_EOL, VIAREG(chip, OFFSET_STATUS) + viadev->reg_offset);
if (viadev->substream && viadev->running) {
......@@ -476,26 +534,27 @@ static inline void snd_via686a_update(via686a_t *chip, viadev_t *viadev)
}
}
static void snd_via686a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void snd_via82xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
via686a_t *chip = snd_magic_cast(via686a_t, dev_id, return);
via82xx_t *chip = snd_magic_cast(via82xx_t, dev_id, return);
unsigned int status;
spin_lock(&chip->reg_lock);
if (chip->chip_type == TYPE_VIA686) {
/* check mpu401 interrupt */
status = inl(VIAREG(chip, SGD_SHADOW));
if ((status & 0x00000077) == 0) {
spin_unlock(&chip->reg_lock);
if (chip->rmidi != NULL) {
if (chip->rmidi != NULL)
snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
}
return;
}
if (inb(VIAREG(chip, PLAYBACK_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via686a_update(chip, &chip->playback);
if (inb(VIAREG(chip, CAPTURE_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via686a_update(chip, &chip->capture);
/*if (inb(VIAREG(chip, FM_STATUS)) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via686a_update(chip, &chip->playback_fm);*/
}
/* check status for each stream */
if (inb(chip->port + chip->playback.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via82xx_update(chip, &chip->playback);
if (inb(chip->port + chip->capture.reg_offset) & (VIA_REG_STAT_EOL|VIA_REG_STAT_FLAG))
snd_via82xx_update(chip, &chip->capture);
spin_unlock(&chip->reg_lock);
}
......@@ -503,56 +562,71 @@ static void snd_via686a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* PCM part
*/
static int snd_via686a_playback_trigger(snd_pcm_substream_t * substream,
static int snd_via82xx_playback_trigger(snd_pcm_substream_t * substream,
int cmd)
{
via686a_t *chip = snd_pcm_substream_chip(substream);
via82xx_t *chip = snd_pcm_substream_chip(substream);
return snd_via686a_trigger(chip, &chip->playback, cmd);
return snd_via82xx_trigger(chip, &chip->playback, cmd);
}
static int snd_via686a_capture_trigger(snd_pcm_substream_t * substream,
static int snd_via82xx_capture_trigger(snd_pcm_substream_t * substream,
int cmd)
{
via686a_t *chip = snd_pcm_substream_chip(substream);
via82xx_t *chip = snd_pcm_substream_chip(substream);
return snd_via686a_trigger(chip, &chip->capture, cmd);
return snd_via82xx_trigger(chip, &chip->capture, cmd);
}
static int snd_via686a_hw_params(snd_pcm_substream_t * substream,
static int snd_via82xx_hw_params(snd_pcm_substream_t * substream,
snd_pcm_hw_params_t * hw_params)
{
return snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
}
static int snd_via686a_hw_free(snd_pcm_substream_t * substream)
static int snd_via82xx_hw_free(snd_pcm_substream_t * substream)
{
return 0;
}
static int snd_via686a_playback_prepare(snd_pcm_substream_t * substream)
static int snd_via82xx_playback_prepare(snd_pcm_substream_t * substream)
{
via686a_t *chip = snd_pcm_substream_chip(substream);
via82xx_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
return snd_via686a_setup_periods(chip, &chip->playback, substream);
if (chip->chip_type == TYPE_VIA8233 &&
chip->playback.reg_offset != VIA_REG_MULTPLAY_STATUS) {
unsigned int tmp;
/* I don't understand this stuff but its from the documentation and this way it works */
outb(0 , VIAREG(chip, PLAYBACK_VOLUME_L));
outb(0 , VIAREG(chip, PLAYBACK_VOLUME_R));
tmp = inl(VIAREG(chip, PLAYBACK_STOP_IDX)) & ~0xfffff;
outl(tmp | (0xffff * runtime->rate)/(48000/16), VIAREG(chip, PLAYBACK_STOP_IDX));
}
return snd_via82xx_setup_periods(chip, &chip->playback, substream);
}
static int snd_via686a_capture_prepare(snd_pcm_substream_t * substream)
static int snd_via82xx_capture_prepare(snd_pcm_substream_t * substream)
{
via686a_t *chip = snd_pcm_substream_chip(substream);
via82xx_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
return snd_via686a_setup_periods(chip, &chip->capture, substream);
if (chip->chip_type == TYPE_VIA8233) {
outb(VIA_REG_CAPTURE_CHANNEL_LINE, VIAREG(chip, CAPTURE_CHANNEL));
outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIAREG(chip, CAPTURE_FIFO));
}
return snd_via82xx_setup_periods(chip, &chip->capture, substream);
}
static inline unsigned int snd_via686a_cur_ptr(via686a_t *chip, viadev_t *viadev)
static inline unsigned int snd_via82xx_cur_ptr(via82xx_t *chip, viadev_t *viadev)
{
unsigned int val, ptr, count;
ptr = inl(VIAREG(chip, OFFSET_CURR_PTR) + viadev->reg_offset);
ptr = inl(VIAREG(chip, OFFSET_CURR_PTR) + viadev->reg_offset)/* & 0xffffff*/;
switch (chip->chip_type) {
case TYPE_VIA686:
count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset);
if (ptr == viadev->lastptr && count > viadev->lastcount)
ptr += 8;
......@@ -564,6 +638,20 @@ static inline unsigned int snd_via686a_cur_ptr(via686a_t *chip, viadev_t *viadev
val = 0;
else
val = ((ptr - (unsigned int)viadev->table_addr) / 8 - 1) % viadev->tbl_entries;
viadev->lastptr = ptr;
viadev->lastcount = count;
break;
case TYPE_VIA8233:
default:
count = inl(VIAREG(chip, OFFSET_CURR_COUNT) + viadev->reg_offset) & 0xffffff;
/* The via686a does not have this current index register,
* this register makes life easier for us here. */
val = inb(VIAREG(chip, OFFSET_CURR_INDEX) + viadev->reg_offset) % viadev->tbl_entries;
break;
}
/* convert to the linear position */
if (val < viadev->tbl_entries - 1) {
val *= viadev->tbl_size;
val += viadev->tbl_size - count;
......@@ -571,25 +659,23 @@ static inline unsigned int snd_via686a_cur_ptr(via686a_t *chip, viadev_t *viadev
val *= viadev->tbl_size;
val += (viadev->size % viadev->tbl_size) + 1 - count;
}
viadev->lastptr = ptr;
viadev->lastcount = count;
// printk("pointer: ptr = 0x%x (%i), count = 0x%x, val = 0x%x\n", ptr, count, val);
return val;
}
static snd_pcm_uframes_t snd_via686a_playback_pointer(snd_pcm_substream_t * substream)
static snd_pcm_uframes_t snd_via82xx_playback_pointer(snd_pcm_substream_t * substream)
{
via686a_t *chip = snd_pcm_substream_chip(substream);
return bytes_to_frames(substream->runtime, snd_via686a_cur_ptr(chip, &chip->playback));
via82xx_t *chip = snd_pcm_substream_chip(substream);
return bytes_to_frames(substream->runtime, snd_via82xx_cur_ptr(chip, &chip->playback));
}
static snd_pcm_uframes_t snd_via686a_capture_pointer(snd_pcm_substream_t * substream)
static snd_pcm_uframes_t snd_via82xx_capture_pointer(snd_pcm_substream_t * substream)
{
via686a_t *chip = snd_pcm_substream_chip(substream);
return bytes_to_frames(substream->runtime, snd_via686a_cur_ptr(chip, &chip->capture));
via82xx_t *chip = snd_pcm_substream_chip(substream);
return bytes_to_frames(substream->runtime, snd_via82xx_cur_ptr(chip, &chip->capture));
}
static snd_pcm_hardware_t snd_via686a_playback =
static snd_pcm_hardware_t snd_via82xx_playback =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
......@@ -609,7 +695,7 @@ static snd_pcm_hardware_t snd_via686a_playback =
.fifo_size = 0,
};
static snd_pcm_hardware_t snd_via686a_capture =
static snd_pcm_hardware_t snd_via82xx_capture =
{
.info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
......@@ -628,14 +714,26 @@ static snd_pcm_hardware_t snd_via686a_capture =
.fifo_size = 0,
};
static int snd_via686a_playback_open(snd_pcm_substream_t * substream)
static unsigned int channels[] = {
1, 2, 4, 6
};
#define CHANNELS sizeof(channels) / sizeof(channels[0])
static snd_pcm_hw_constraint_list_t hw_constraints_channels = {
.count = CHANNELS,
.list = channels,
.mask = 0,
};
static int snd_via82xx_playback_open(snd_pcm_substream_t * substream)
{
via686a_t *chip = snd_pcm_substream_chip(substream);
via82xx_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
chip->playback.substream = substream;
runtime->hw = snd_via686a_playback;
runtime->hw = snd_via82xx_playback;
runtime->hw.rates = chip->ac97->rates[AC97_RATES_FRONT_DAC];
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
......@@ -645,19 +743,29 @@ static int snd_via686a_playback_open(snd_pcm_substream_t * substream)
return err;
/* we may remove following constaint when we modify table entries
in interrupt */
#if 0
/* applying the following constraint together with the power-of-2 rule
* above may result in too narrow space.
* this one is not strictly necessary, so let's disable it.
*/
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
#endif
if (chip->chip_type == TYPE_VIA8233) {
runtime->hw.channels_max = 6;
snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, &hw_constraints_channels);
}
return 0;
}
static int snd_via686a_capture_open(snd_pcm_substream_t * substream)
static int snd_via82xx_capture_open(snd_pcm_substream_t * substream)
{
via686a_t *chip = snd_pcm_substream_chip(substream);
via82xx_t *chip = snd_pcm_substream_chip(substream);
snd_pcm_runtime_t *runtime = substream->runtime;
int err;
chip->capture.substream = substream;
runtime->hw = snd_via686a_capture;
runtime->hw = snd_via82xx_capture;
runtime->hw.rates = chip->ac97->rates[AC97_RATES_ADC];
if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000))
runtime->hw.rate_min = 48000;
......@@ -665,14 +773,16 @@ static int snd_via686a_capture_open(snd_pcm_substream_t * substream)
return err;
if ((err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES)) < 0)
return err;
#if 0
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
#endif
return 0;
}
static int snd_via686a_playback_close(snd_pcm_substream_t * substream)
static int snd_via82xx_playback_close(snd_pcm_substream_t * substream)
{
via686a_t *chip = snd_pcm_substream_chip(substream);
via82xx_t *chip = snd_pcm_substream_chip(substream);
clean_via_table(&chip->playback, substream, chip->pci);
snd_pcm_sgbuf_delete(substream);
......@@ -680,9 +790,9 @@ static int snd_via686a_playback_close(snd_pcm_substream_t * substream)
return 0;
}
static int snd_via686a_capture_close(snd_pcm_substream_t * substream)
static int snd_via82xx_capture_close(snd_pcm_substream_t * substream)
{
via686a_t *chip = snd_pcm_substream_chip(substream);
via82xx_t *chip = snd_pcm_substream_chip(substream);
clean_via_table(&chip->capture, substream, chip->pci);
snd_pcm_sgbuf_delete(substream);
......@@ -690,58 +800,58 @@ static int snd_via686a_capture_close(snd_pcm_substream_t * substream)
return 0;
}
static snd_pcm_ops_t snd_via686a_playback_ops = {
.open = snd_via686a_playback_open,
.close = snd_via686a_playback_close,
static snd_pcm_ops_t snd_via82xx_playback_ops = {
.open = snd_via82xx_playback_open,
.close = snd_via82xx_playback_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_via686a_hw_params,
.hw_free = snd_via686a_hw_free,
.prepare = snd_via686a_playback_prepare,
.trigger = snd_via686a_playback_trigger,
.pointer = snd_via686a_playback_pointer,
.hw_params = snd_via82xx_hw_params,
.hw_free = snd_via82xx_hw_free,
.prepare = snd_via82xx_playback_prepare,
.trigger = snd_via82xx_playback_trigger,
.pointer = snd_via82xx_playback_pointer,
.copy = snd_pcm_sgbuf_ops_copy_playback,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
static snd_pcm_ops_t snd_via686a_capture_ops = {
.open = snd_via686a_capture_open,
.close = snd_via686a_capture_close,
static snd_pcm_ops_t snd_via82xx_capture_ops = {
.open = snd_via82xx_capture_open,
.close = snd_via82xx_capture_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = snd_via686a_hw_params,
.hw_free = snd_via686a_hw_free,
.prepare = snd_via686a_capture_prepare,
.trigger = snd_via686a_capture_trigger,
.pointer = snd_via686a_capture_pointer,
.hw_params = snd_via82xx_hw_params,
.hw_free = snd_via82xx_hw_free,
.prepare = snd_via82xx_capture_prepare,
.trigger = snd_via82xx_capture_trigger,
.pointer = snd_via82xx_capture_pointer,
.copy = snd_pcm_sgbuf_ops_copy_capture,
.silence = snd_pcm_sgbuf_ops_silence,
.page = snd_pcm_sgbuf_ops_page,
};
static void snd_via686a_pcm_free(snd_pcm_t *pcm)
static void snd_via82xx_pcm_free(snd_pcm_t *pcm)
{
via686a_t *chip = snd_magic_cast(via686a_t, pcm->private_data, return);
via82xx_t *chip = snd_magic_cast(via82xx_t, pcm->private_data, return);
chip->pcm = NULL;
}
static int __devinit snd_via686a_pcm(via686a_t *chip, int device, snd_pcm_t ** rpcm)
static int __devinit snd_via82xx_pcm(via82xx_t *chip, int device, snd_pcm_t ** rpcm)
{
snd_pcm_t *pcm;
int err;
if (rpcm)
*rpcm = NULL;
err = snd_pcm_new(chip->card, "VIA 82C686A", device, 1, 1, &pcm);
err = snd_pcm_new(chip->card, chip->card->shortname, device, 1, 1, &pcm);
if (err < 0)
return err;
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via686a_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via686a_capture_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_via82xx_playback_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_via82xx_capture_ops);
pcm->private_data = chip;
pcm->private_free = snd_via686a_pcm_free;
pcm->private_free = snd_via82xx_pcm_free;
pcm->info_flags = 0;
strcpy(pcm->name, "VIA 82C686A");
strcpy(pcm->name, chip->card->shortname);
chip->pcm = pcm;
if (rpcm)
......@@ -754,23 +864,23 @@ static int __devinit snd_via686a_pcm(via686a_t *chip, int device, snd_pcm_t ** r
* Mixer part
*/
static void snd_via686a_mixer_free_ac97(ac97_t *ac97)
static void snd_via82xx_mixer_free_ac97(ac97_t *ac97)
{
via686a_t *chip = snd_magic_cast(via686a_t, ac97->private_data, return);
via82xx_t *chip = snd_magic_cast(via82xx_t, ac97->private_data, return);
chip->ac97 = NULL;
}
static int __devinit snd_via686a_mixer(via686a_t *chip)
static int __devinit snd_via82xx_mixer(via82xx_t *chip)
{
ac97_t ac97;
int err;
memset(&ac97, 0, sizeof(ac97));
ac97.write = snd_via686a_codec_write;
ac97.read = snd_via686a_codec_read;
ac97.wait = snd_via686a_codec_wait;
ac97.write = snd_via82xx_codec_write;
ac97.read = snd_via82xx_codec_read;
ac97.wait = snd_via82xx_codec_wait;
ac97.private_data = chip;
ac97.private_free = snd_via686a_mixer_free_ac97;
ac97.private_free = snd_via82xx_mixer_free_ac97;
ac97.clock = chip->ac97_clock;
if ((err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97)) < 0)
return err;
......@@ -781,7 +891,7 @@ static int __devinit snd_via686a_mixer(via686a_t *chip)
* joystick
*/
static int snd_via686a_joystick_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
static int snd_via82xx_joystick_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->count = 1;
......@@ -790,9 +900,9 @@ static int snd_via686a_joystick_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info
return 0;
}
static int snd_via686a_joystick_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
static int snd_via82xx_joystick_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
via686a_t *chip = snd_kcontrol_chip(kcontrol);
via82xx_t *chip = snd_kcontrol_chip(kcontrol);
u16 val;
pci_read_config_word(chip->pci, 0x42, &val);
......@@ -800,9 +910,9 @@ static int snd_via686a_joystick_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value
return 0;
}
static int snd_via686a_joystick_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
static int snd_via82xx_joystick_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
via686a_t *chip = snd_kcontrol_chip(kcontrol);
via82xx_t *chip = snd_kcontrol_chip(kcontrol);
u16 val, oval;
pci_read_config_word(chip->pci, 0x42, &oval);
......@@ -816,19 +926,19 @@ static int snd_via686a_joystick_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value
return 0;
}
static snd_kcontrol_new_t snd_via686a_joystick_control __devinitdata = {
static snd_kcontrol_new_t snd_via82xx_joystick_control __devinitdata = {
.name = "Joystick",
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
.info = snd_via686a_joystick_info,
.get = snd_via686a_joystick_get,
.put = snd_via686a_joystick_put,
.info = snd_via82xx_joystick_info,
.get = snd_via82xx_joystick_get,
.put = snd_via82xx_joystick_put,
};
/*
*
*/
static int __devinit snd_via686a_chip_init(via686a_t *chip)
static int __devinit snd_via82xx_chip_init(via82xx_t *chip)
{
ac97_t ac97;
unsigned int val;
......@@ -839,23 +949,24 @@ static int __devinit snd_via686a_chip_init(via686a_t *chip)
ac97.private_data = chip;
#if 0 /* broken on K7M? */
if (chip->chip_type == TYPE_VIA686)
/* disable all legacy ports */
pci_write_config_byte(chip->pci, 0x42, 0);
#endif
/* cold reset only when link is down */
pci_read_config_byte(chip->pci, 0x40, &pval);
if ((pval & 0x01) == 0) {
/* deassert ACLink reset, force SYNC */
pci_write_config_byte(chip->pci, 0x41, 0xe0);
udelay(100);
pci_write_config_byte(chip->pci, 0x41, 0x00);
/* deassert ACLink reset, force SYNC (warm AC'97 reset) */
pci_write_config_byte(chip->pci, 0x41, 0x60);
udelay(2);
/* pci_write_config_byte(chip->pci, 0x41, 0x00);
udelay(100);
*/
/* ACLink on, deassert ACLink reset, VSR, SGD data out */
/* note - FM data out has trouble with non VRA codecs !! */
pci_write_config_byte(chip->pci, 0x41, 0xcc);
udelay(100);
}
/* Make sure VRA is enabled, in case we didn't do a
* complete codec reset, above */
......@@ -877,36 +988,24 @@ static int __devinit snd_via686a_chip_init(via686a_t *chip)
schedule_timeout(1);
} while (--max_count > 0);
if ((val = snd_via686a_codec_xread(chip)) & VIA_REG_AC97_BUSY)
if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)
snd_printk("AC'97 codec is not ready [0x%x]\n", val);
/* and then reset codec.. */
snd_via686a_codec_write(&ac97, AC97_RESET, 0x0000);
snd_via82xx_codec_ready(chip, 0);
snd_via82xx_codec_write(&ac97, AC97_RESET, 0x0000);
snd_via82xx_codec_read(&ac97, 0);
/* check the primary codec */
snd_via686a_codec_xwrite(chip, VIA_REG_AC97_READ |
VIA_REG_AC97_PRIMARY_VALID |
(VIA_REG_AC97_CODEC_ID_PRIMARY << VIA_REG_AC97_CODEC_ID_SHIFT));
max_count = ((3 * HZ) / 4) + 1;
do {
if ((val = snd_via686a_codec_xread(chip)) & VIA_REG_AC97_PRIMARY_VALID)
goto __ac97_ok1;
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
} while (--max_count > 0);
snd_printk("Primary AC'97 codec is not valid [0x%x]\n", val);
__ac97_ok1:
#if 0 /* FIXME: we don't support the second codec yet so skip the detection now.. */
snd_via686a_codec_xwrite(chip, VIA_REG_AC97_READ |
snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
VIA_REG_AC97_SECONDARY_VALID |
(VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
max_count = ((3 * HZ) / 4) + 1;
snd_via686a_codec_xwrite(chip, VIA_REG_AC97_READ |
snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ |
VIA_REG_AC97_SECONDARY_VALID |
(VIA_REG_AC97_CODEC_ID_SECONDARY << VIA_REG_AC97_CODEC_ID_SHIFT));
do {
if ((val = snd_via686a_codec_xread(chip)) & VIA_REG_AC97_SECONDARY_VALID) {
if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_SECONDARY_VALID) {
chip->ac97_secondary = 1;
goto __ac97_ok2;
}
......@@ -918,44 +1017,26 @@ static int __devinit snd_via686a_chip_init(via686a_t *chip)
__ac97_ok2:
#endif
#if 0
{
unsigned char cmdb;
pci_read_config_byte(chip->pci, 0x40, &cmdb);
printk("PCI[0x40] = 0x%x\n", cmdb);
pci_read_config_byte(chip->pci, 0x42, &cmdb);
printk("PCI[0x42] = 0x%x\n", cmdb);
pci_read_config_byte(chip->pci, 0x43, &cmdb);
printk("PCI[0x43] = 0x%x\n", cmdb);
pci_read_config_byte(chip->pci, 0x44, &cmdb);
printk("PCI[0x44] = 0x%x\n", cmdb);
pci_read_config_byte(chip->pci, 0x48, &cmdb);
printk("PCI[0x48] = 0x%x\n", cmdb);
}
#endif
if (chip->chip_type == TYPE_VIA686) {
/* route FM trap to IRQ, disable FM trap */
pci_write_config_byte(chip->pci, 0x48, 0);
/* disable all GPI interrupts */
outl(0, chip->port + 0x8c);
}
/* disable interrupts */
snd_via686a_channel_reset(chip, &chip->playback);
snd_via686a_channel_reset(chip, &chip->capture);
/*snd_via686a_channel_reset(chip, &chip->playback_fm);*/
snd_via82xx_channel_reset(chip, &chip->playback);
snd_via82xx_channel_reset(chip, &chip->capture);
return 0;
}
static int snd_via686a_free(via686a_t *chip)
static int snd_via82xx_free(via82xx_t *chip)
{
if (chip->irq < 0)
goto __end_hw;
/* disable interrupts */
snd_via686a_channel_reset(chip, &chip->playback);
snd_via686a_channel_reset(chip, &chip->capture);
/*snd_via686a_channel_reset(chip, &chip->playback_fm);*/
snd_via82xx_channel_reset(chip, &chip->playback);
snd_via82xx_channel_reset(chip, &chip->capture);
/* --- */
synchronize_irq(chip->irq);
__end_hw:
......@@ -965,52 +1046,58 @@ static int snd_via686a_free(via686a_t *chip)
}
if (chip->irq >= 0)
free_irq(chip->irq, (void *)chip);
if (chip->chip_type == TYPE_VIA686) {
pci_write_config_byte(chip->pci, 0x42, chip->old_legacy);
pci_write_config_byte(chip->pci, 0x43, chip->old_legacy_cfg);
}
snd_magic_kfree(chip);
return 0;
}
static int snd_via686a_dev_free(snd_device_t *device)
static int snd_via82xx_dev_free(snd_device_t *device)
{
via686a_t *chip = snd_magic_cast(via686a_t, device->device_data, return -ENXIO);
return snd_via686a_free(chip);
via82xx_t *chip = snd_magic_cast(via82xx_t, device->device_data, return -ENXIO);
return snd_via82xx_free(chip);
}
static int __devinit snd_via686a_create(snd_card_t * card,
static int __devinit snd_via82xx_create(snd_card_t * card,
struct pci_dev *pci,
int chip_type,
unsigned int ac97_clock,
unsigned char old_legacy,
unsigned char old_legacy_cfg,
via686a_t ** r_via)
via82xx_t ** r_via)
{
via686a_t *chip;
via82xx_t *chip;
int err;
static snd_device_ops_t ops = {
.dev_free = snd_via686a_dev_free,
.dev_free = snd_via82xx_dev_free,
};
if ((err = pci_enable_device(pci)) < 0)
return err;
if ((chip = snd_magic_kcalloc(via686a_t, 0, GFP_KERNEL)) == NULL)
if ((chip = snd_magic_kcalloc(via82xx_t, 0, GFP_KERNEL)) == NULL)
return -ENOMEM;
chip->old_legacy = old_legacy;
chip->old_legacy_cfg = old_legacy_cfg;
chip->chip_type = chip_type;
spin_lock_init(&chip->reg_lock);
spin_lock_init(&chip->ac97_lock);
chip->card = card;
chip->pci = pci;
chip->irq = -1;
pci_read_config_byte(pci, 0x42, &chip->old_legacy);
pci_read_config_byte(pci, 0x43, &chip->old_legacy_cfg);
chip->port = pci_resource_start(pci, 0);
if ((chip->res_port = request_region(chip->port, 256, "VIA686A")) == NULL) {
snd_via686a_free(chip);
if ((chip->res_port = request_region(chip->port, 256, card->driver)) == NULL) {
snd_via82xx_free(chip);
snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->port, chip->port + 256 - 1);
return -EBUSY;
}
if (request_irq(pci->irq, snd_via686a_interrupt, SA_INTERRUPT|SA_SHIRQ, "VIA686A", (void *)chip)) {
snd_via686a_free(chip);
if (request_irq(pci->irq, snd_via82xx_interrupt, SA_INTERRUPT|SA_SHIRQ,
card->driver, (void *)chip)) {
snd_via82xx_free(chip);
snd_printk("unable to grab IRQ %d\n", chip->irq);
return -EBUSY;
}
......@@ -1021,34 +1108,48 @@ static int __devinit snd_via686a_create(snd_card_t * card,
synchronize_irq(chip->irq);
/* initialize offsets */
switch (chip->chip_type) {
case TYPE_VIA686:
chip->playback.reg_offset = VIA_REG_PLAYBACK_STATUS;
chip->capture.reg_offset = VIA_REG_CAPTURE_STATUS;
/*chip->playback_fm.reg_offset = VIA_REG_FM_STATUS;*/
break;
case TYPE_VIA8233:
/* we use multi-channel playback mode, since this mode is supported
* by all VIA8233 models (and obviously suitable for our purpose).
*/
chip->playback.reg_offset = VIA_REG_MULTPLAY_STATUS;
chip->capture.reg_offset = VIA_REG_CAPTURE_8233_STATUS;
break;
}
if ((err = snd_via686a_chip_init(chip)) < 0) {
snd_via686a_free(chip);
if ((err = snd_via82xx_chip_init(chip)) < 0) {
snd_via82xx_free(chip);
return err;
}
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_via686a_free(chip);
snd_via82xx_free(chip);
return err;
}
/* The 8233 ac97 controller does not implement the master bit
* in the pci command register. IMHO this is a violation of the PCI spec.
* We call pci_set_master here because it does not hurt. */
pci_set_master(pci);
*r_via = chip;
return 0;
}
static int __devinit snd_via686a_probe(struct pci_dev *pci,
static int __devinit snd_via82xx_probe(struct pci_dev *pci,
const struct pci_device_id *id)
{
static int dev;
snd_card_t *card;
via686a_t *chip;
via82xx_t *chip;
int pcm_dev = 0;
unsigned char legacy;
unsigned char legacy_cfg;
int rev_h = 0, err;
int chip_type;
int err;
if (dev >= SNDRV_CARDS)
return -ENODEV;
......@@ -1061,35 +1162,48 @@ static int __devinit snd_via686a_probe(struct pci_dev *pci,
if (card == NULL)
return -ENOMEM;
pci_read_config_byte(pci, 0x42, &legacy);
pci_read_config_byte(pci, 0x43, &legacy_cfg);
chip_type = id->driver_data;
switch (chip_type) {
case TYPE_VIA686:
strcpy(card->driver, "VIA686A");
strcpy(card->shortname, "VIA 82C686A/B");
break;
case TYPE_VIA8233:
strcpy(card->driver, "VIA8233");
strcpy(card->shortname, "VIA 8233A/C");
break;
default:
snd_printk(KERN_ERR "invalid chip type %d\n", chip_type);
snd_card_free(card);
return -EINVAL;
}
if ((err = snd_via686a_create(card,
pci,
snd_ac97_clock[dev],
legacy,
legacy_cfg,
&chip)) < 0) {
if ((err = snd_via82xx_create(card, pci, chip_type, snd_ac97_clock[dev], &chip)) < 0) {
snd_card_free(card);
return err;
}
if (snd_via686a_mixer(chip) < 0) {
if (snd_via82xx_mixer(chip) < 0) {
snd_card_free(card);
return err;
}
if (snd_via686a_pcm(chip, pcm_dev++, NULL) < 0) {
if (snd_via82xx_pcm(chip, pcm_dev++, NULL) < 0) {
snd_card_free(card);
return err;
}
#if 0
if (snd_via686a_pcm_fm(chip, pcm_dev++, NULL) < 0) {
if (snd_via82xx_pcm_fm(chip, pcm_dev++, NULL) < 0) {
snd_card_free(card);
return err;
}
#endif
if (chip->chip_type == TYPE_VIA686) {
unsigned char legacy, legacy_cfg;
int rev_h = 0;
legacy = chip->old_legacy;
legacy_cfg = chip->old_legacy_cfg;
legacy |= 0x40; /* disable MIDI */
legacy &= ~0x08; /* disable joystick */
if (chip->revision >= 0x20) {
......@@ -1152,14 +1266,12 @@ static int __devinit snd_via686a_probe(struct pci_dev *pci,
}
/* card switches */
err = snd_ctl_add(card, snd_ctl_new1(&snd_via686a_joystick_control, chip));
err = snd_ctl_add(card, snd_ctl_new1(&snd_via82xx_joystick_control, chip));
if (err < 0) {
snd_card_free(card);
return err;
}
strcpy(card->driver, "VIA686A");
strcpy(card->shortname, "VIA 82C686A/B");
}
sprintf(card->longname, "%s at 0x%lx, irq %d",
card->shortname, chip->port, chip->irq);
......@@ -1173,46 +1285,46 @@ static int __devinit snd_via686a_probe(struct pci_dev *pci,
return 0;
}
static void __devexit snd_via686a_remove(struct pci_dev *pci)
static void __devexit snd_via82xx_remove(struct pci_dev *pci)
{
snd_card_free(pci_get_drvdata(pci));
pci_set_drvdata(pci, NULL);
}
static struct pci_driver driver = {
.name = "VIA 82C686A/B",
.id_table = snd_via686a_ids,
.probe = snd_via686a_probe,
.remove = __devexit_p(snd_via686a_remove),
.name = "VIA 82xx Audio",
.id_table = snd_via82xx_ids,
.probe = snd_via82xx_probe,
.remove = __devexit_p(snd_via82xx_remove),
};
static int __init alsa_card_via686a_init(void)
static int __init alsa_card_via82xx_init(void)
{
int err;
if ((err = pci_module_init(&driver)) < 0) {
#ifdef MODULE
printk(KERN_ERR "VIA 82C686A soundcard not found or device busy\n");
printk(KERN_ERR "VIA 82xx soundcard not found or device busy\n");
#endif
return err;
}
return 0;
}
static void __exit alsa_card_via686a_exit(void)
static void __exit alsa_card_via82xx_exit(void)
{
pci_unregister_driver(&driver);
}
module_init(alsa_card_via686a_init)
module_exit(alsa_card_via686a_exit)
module_init(alsa_card_via82xx_init)
module_exit(alsa_card_via82xx_exit)
#ifndef MODULE
/* format is: snd-via686a=snd_enable,snd_index,snd_id,
/* format is: snd-via82xx=snd_enable,snd_index,snd_id,
snd_mpu_port,snd_ac97_clock */
static int __init alsa_card_via686a_setup(char *str)
static int __init alsa_card_via82xx_setup(char *str)
{
static unsigned __initdata nr_dev = 0;
......@@ -1227,6 +1339,7 @@ static int __init alsa_card_via686a_setup(char *str)
return 1;
}
__setup("snd-via686a=", alsa_card_via686a_setup);
__setup("snd-via82xx=", alsa_card_via82xx_setup);
#endif /* ifndef MODULE */
......@@ -74,11 +74,14 @@ static int keywest_attach_adapter(struct i2c_adapter *adapter)
new_client->id = keywest_ctx->id++; /* Automatically unique */
keywest_ctx->client = new_client;
if ((err = keywest_ctx->init_client(keywest_ctx)) < 0)
if ((err = keywest_ctx->init_client(keywest_ctx)) < 0) {
snd_printk(KERN_ERR "tumbler: cannot initialize the MCS\n");
goto __err;
}
/* Tell the i2c layer a new client has arrived */
if (i2c_attach_client(new_client)) {
snd_printk(KERN_ERR "tumbler: cannot attach i2c client\n");
err = -ENODEV;
goto __err;
}
......
......@@ -1170,8 +1170,7 @@ static int __init snd_pmac_detect(pmac_t *chip)
// chip->can_byte_swap = 0; /* FIXME: check this */
chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
}
if (device_is_compatible(sound, "tumbler") ||
device_is_compatible(sound, "snapper")) {
if (device_is_compatible(sound, "tumbler")) {
chip->model = PMAC_TUMBLER;
chip->can_capture = 0; /* no capture */
chip->can_duplex = 0;
......@@ -1180,6 +1179,15 @@ static int __init snd_pmac_detect(pmac_t *chip)
chip->freq_table = tumbler_freqs;
chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
}
if (device_is_compatible(sound, "snapper")) {
chip->model = PMAC_SNAPPER;
chip->can_capture = 0; /* no capture */
chip->can_duplex = 0;
// chip->can_byte_swap = 0; /* FIXME: check this */
chip->num_freqs = 2;
chip->freq_table = tumbler_freqs;
chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
}
prop = (unsigned int *)get_property(sound, "device-id", 0);
if (prop)
chip->device_id = *prop;
......
......@@ -40,6 +40,7 @@
#endif
#endif
#include <linux/nvram.h>
#include <linux/tty.h>
#include <linux/vt_kern.h>
#include <asm/dbdma.h>
#include <asm/prom.h>
......@@ -115,7 +116,7 @@ struct snd_pmac_beep {
*/
enum snd_pmac_model {
PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER
PMAC_AWACS, PMAC_SCREAMER, PMAC_BURGUNDY, PMAC_DACA, PMAC_TUMBLER, PMAC_SNAPPER
};
struct snd_pmac {
......
......@@ -94,8 +94,10 @@ static int __init snd_pmac_probe(void)
goto __error;
break;
case PMAC_TUMBLER:
strcpy(card->driver, "PMac Tumbler");
strcpy(card->shortname, "PowerMac Tumbler");
case PMAC_SNAPPER:
name_ext = chip->model == PMAC_TUMBLER ? "Tumbler" : "Snapper";
sprintf(card->driver, "PMac %s", name_ext);
sprintf(card->shortname, "PowerMac %s", name_ext);
sprintf(card->longname, "%s (Dev %d) Sub-frame %d",
card->shortname, chip->device_id, chip->subframe);
if ((err = snd_pmac_tumbler_init(chip)) < 0)
......
/*
* PMac Tumbler lowlevel functions
* PMac Tumbler/Snapper lowlevel functions
*
* Copyright (c) by Takashi Iwai <tiwai@suse.de>
*
......@@ -46,17 +46,27 @@
#define TAS_REG_VOL 0x04
#define TAS_REG_TREBLE 0x05
#define TAS_REG_BASS 0x06
#define TAS_REG_INPUT1 0x07 /* pcm */
#define TAS_REG_INPUT2 0x08 /* ??? */
#define TAS_REG_INPUT1 0x07
#define TAS_REG_INPUT2 0x08
/* tas3001c */
#define TAS_REG_PCM TAS_REG_INPUT1
#define TAS_MIXER_VOL_MAX 200
/* tas3004 */
#define TAS_REG_LMIX TAS_REG_INPUT1
#define TAS_REG_RMIX TAS_REG_INPUT2
/* mono volumes for tas3001c/tas3004 */
enum {
VOL_IDX_PCM, VOL_IDX_BASS, VOL_IDX_TREBLE,
//VOL_IDX_ALTPCM,
VOL_IDX_LAST
VOL_IDX_PCM_MONO, /* tas3001c only */
VOL_IDX_BASS, VOL_IDX_TREBLE,
VOL_IDX_LAST_MONO
};
/* stereo volumes for tas3004 */
enum {
VOL_IDX_PCM, VOL_IDX_PCM2, VOL_IDX_ADC,
VOL_IDX_LAST_MIX
};
typedef struct pmac_gpio {
......@@ -77,7 +87,8 @@ typedef struct pmac_tumber_t {
int headphone_irq;
unsigned int master_vol[2];
unsigned int master_switch[2];
unsigned int mono_vol[VOL_IDX_LAST];
unsigned int mono_vol[VOL_IDX_LAST_MONO];
unsigned int mix_vol[VOL_IDX_LAST_MIX][2]; /* stereo volumes for tas3004 */
int drc_range;
int drc_enable;
} pmac_tumbler_t;
......@@ -90,9 +101,16 @@ typedef struct pmac_tumber_t {
static int tumbler_init_client(pmac_keywest_t *i2c)
{
int err, count = 10;
do {
/* normal operation, SCLK=64fps, i2s output, i2s input, 16bit width */
return snd_pmac_keywest_write_byte(i2c, TAS_REG_MCS,
err = snd_pmac_keywest_write_byte(i2c, TAS_REG_MCS,
(1<<6)+(2<<4)+(2<<2)+0);
if (err >= 0)
return err;
mdelay(10);
} while (count--);
return -ENXIO;
}
......@@ -245,8 +263,11 @@ static int tumbler_put_master_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_valu
/*
* dynamic range compression
* TAS3001c dynamic range compression
*/
#define TAS3001_DRC_MAX 0x5f
static int tumbler_set_drc(pmac_tumbler_t *mix)
{
unsigned char val[2];
......@@ -256,7 +277,7 @@ static int tumbler_set_drc(pmac_tumbler_t *mix)
if (mix->drc_enable) {
val[0] = 0xc1; /* enable, 3:1 compression */
if (mix->drc_range > 0x5f)
if (mix->drc_range > TAS3001_DRC_MAX)
val[1] = 0xf0;
else if (mix->drc_range < 0)
val[1] = 0x91;
......@@ -274,12 +295,49 @@ static int tumbler_set_drc(pmac_tumbler_t *mix)
return 0;
}
/*
* TAS3004
*/
#define TAS3004_DRC_MAX 0xef
static int snapper_set_drc(pmac_tumbler_t *mix)
{
unsigned char val[6];
if (! mix->i2c.client)
return -ENODEV;
if (mix->drc_enable)
val[0] = 0x50; /* 3:1 above threshold */
else
val[0] = 0x51; /* disabled */
val[1] = 0x02; /* 1:1 below threshold */
if (mix->drc_range > 0xef)
val[2] = 0xef;
else if (mix->drc_range < 0)
val[2] = 0x00;
else
val[2] = mix->drc_range;
val[3] = 0xb0;
val[4] = 0x60;
val[5] = 0xa0;
if (snd_pmac_keywest_write(&mix->i2c, TAS_REG_DRC, 6, val) < 0) {
snd_printk("failed to set DRC\n");
return -EINVAL;
}
return 0;
}
static int tumbler_info_drc_value(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
pmac_t *chip = snd_kcontrol_chip(kcontrol);
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 1;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 0x5f;
uinfo->value.integer.max =
chip->model == PMAC_TUMBLER ? TAS3001_DRC_MAX : TAS3004_DRC_MAX;
return 0;
}
......@@ -304,7 +362,10 @@ static int tumbler_put_drc_value(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
change = mix->drc_range != ucontrol->value.integer.value[0];
if (change) {
mix->drc_range = ucontrol->value.integer.value[0];
if (chip->model == PMAC_TUMBLER)
tumbler_set_drc(mix);
else
snapper_set_drc(mix);
}
return change;
}
......@@ -330,7 +391,10 @@ static int tumbler_put_drc_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
change = mix->drc_enable != ucontrol->value.integer.value[0];
if (change) {
mix->drc_enable = !!ucontrol->value.integer.value[0];
if (chip->model == PMAC_TUMBLER)
tumbler_set_drc(mix);
else
snapper_set_drc(mix);
}
return change;
}
......@@ -409,24 +473,15 @@ static int tumbler_put_mono(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucon
return change;
}
/* TAS3001c mono volumes */
static struct tumbler_mono_vol tumbler_pcm_vol_info = {
.index = VOL_IDX_PCM,
.index = VOL_IDX_PCM_MONO,
.reg = TAS_REG_PCM,
.bytes = 3,
.max = number_of(mixer_volume_table),
.table = mixer_volume_table,
};
#if 0 // for what?
static struct tumbler_mono_vol tumbler_altpcm_vol_info = {
.index = VOL_IDX_ALTPCM,
.reg = TAS_REG_INPUT2,
.bytes = 3,
.max = number_of(mixer_volume_table),
.table = mixer_volume_table,
};
#endif
static struct tumbler_mono_vol tumbler_bass_vol_info = {
.index = VOL_IDX_BASS,
.reg = TAS_REG_BASS,
......@@ -443,6 +498,24 @@ static struct tumbler_mono_vol tumbler_treble_vol_info = {
.table = treble_volume_table,
};
/* TAS3004 mono volumes */
static struct tumbler_mono_vol snapper_bass_vol_info = {
.index = VOL_IDX_BASS,
.reg = TAS_REG_BASS,
.bytes = 1,
.max = number_of(snapper_bass_volume_table),
.table = snapper_bass_volume_table,
};
static struct tumbler_mono_vol snapper_treble_vol_info = {
.index = VOL_IDX_TREBLE,
.reg = TAS_REG_TREBLE,
.bytes = 1,
.max = number_of(snapper_treble_volume_table),
.table = snapper_treble_volume_table,
};
#define DEFINE_MONO(xname,type) { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
.name = xname, \
......@@ -452,6 +525,95 @@ static struct tumbler_mono_vol tumbler_treble_vol_info = {
.private_value = (unsigned long)(&tumbler_##type##_vol_info), \
}
#define DEFINE_SNAPPER_MONO(xname,type) { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
.name = xname, \
.info = tumbler_info_mono, \
.get = tumbler_get_mono, \
.put = tumbler_put_mono, \
.private_value = (unsigned long)(&snapper_##type##_vol_info), \
}
/*
* snapper mixer volumes
*/
static int snapper_set_mix_vol1(pmac_tumbler_t *mix, int idx, int ch, int reg)
{
int i, j, vol;
unsigned char block[9];
vol = mix->mix_vol[idx][ch];
if (vol >= number_of(mixer_volume_table)) {
vol = number_of(mixer_volume_table) - 1;
mix->mix_vol[idx][ch] = vol;
}
for (i = 0; i < 3; i++) {
vol = mix->mix_vol[i][ch];
vol = mixer_volume_table[vol];
for (j = 0; j < 3; j++)
block[i * 3 + j] = (vol >> ((2 - j) * 8)) & 0xff;
}
if (snd_pmac_keywest_write(&mix->i2c, reg, 9, block) < 0) {
snd_printk("failed to set mono volume %d\n", reg);
return -EINVAL;
}
return 0;
}
static int snapper_set_mix_vol(pmac_tumbler_t *mix, int idx)
{
if (! mix->i2c.client)
return -ENODEV;
if (snapper_set_mix_vol1(mix, idx, 0, TAS_REG_LMIX) < 0 ||
snapper_set_mix_vol1(mix, idx, 1, TAS_REG_RMIX) < 0)
return -EINVAL;
return 0;
}
static int snapper_info_mix(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
{
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = number_of(mixer_volume_table) - 1;
return 0;
}
static int snapper_get_mix(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
int idx = (int)kcontrol->private_value;
pmac_t *chip = snd_kcontrol_chip(kcontrol);
pmac_tumbler_t *mix;
if (! (mix = chip->mixer_data))
return -ENODEV;
ucontrol->value.integer.value[0] = mix->mix_vol[idx][0];
ucontrol->value.integer.value[1] = mix->mix_vol[idx][1];
return 0;
}
static int snapper_put_mix(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
{
int idx = (int)kcontrol->private_value;
pmac_t *chip = snd_kcontrol_chip(kcontrol);
pmac_tumbler_t *mix;
int change;
if (! (mix = chip->mixer_data))
return -ENODEV;
change = mix->mix_vol[idx][0] != ucontrol->value.integer.value[0] ||
mix->mix_vol[idx][1] != ucontrol->value.integer.value[1];
if (change) {
mix->mix_vol[idx][0] = ucontrol->value.integer.value[0];
mix->mix_vol[idx][1] = ucontrol->value.integer.value[1];
snapper_set_mix_vol(mix, idx);
}
return change;
}
/*
* mute switches
*/
......@@ -487,6 +649,16 @@ static int tumbler_put_mute_switch(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_
return 0;
}
#define DEFINE_SNAPPER_MIX(xname,idx,ofs) { \
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\
.name = xname, \
.info = snapper_info_mix, \
.get = snapper_get_mix, \
.put = snapper_put_mix, \
.index = idx,\
.private_value = ofs, \
}
/*
*/
......@@ -506,7 +678,38 @@ static snd_kcontrol_new_t tumbler_mixers[] __initdata = {
DEFINE_MONO("Tone Control - Bass", bass),
DEFINE_MONO("Tone Control - Treble", treble),
DEFINE_MONO("PCM Playback Volume", pcm),
// DEFINE_MONO("Mixer2 Playback Volume", altpcm),
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "DRC Switch",
.info = snd_pmac_boolean_mono_info,
.get = tumbler_get_drc_switch,
.put = tumbler_put_drc_switch
},
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "DRC Range",
.info = tumbler_info_drc_value,
.get = tumbler_get_drc_value,
.put = tumbler_put_drc_value
},
};
static snd_kcontrol_new_t snapper_mixers[] __initdata = {
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Volume",
.info = tumbler_info_master_volume,
.get = tumbler_get_master_volume,
.put = tumbler_put_master_volume
},
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Master Playback Switch",
.info = snd_pmac_boolean_stereo_info,
.get = tumbler_get_master_switch,
.put = tumbler_put_master_switch
},
DEFINE_SNAPPER_MIX("PCM Playback Volume", 0, VOL_IDX_PCM),
DEFINE_SNAPPER_MIX("PCM Playback Volume", 1, VOL_IDX_PCM2),
DEFINE_SNAPPER_MIX("Monitor Mix Volume", 0, VOL_IDX_ADC),
DEFINE_SNAPPER_MONO("Tone Control - Bass", bass),
DEFINE_SNAPPER_MONO("Tone Control - Treble", treble),
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "DRC Switch",
.info = snd_pmac_boolean_mono_info,
......@@ -675,10 +878,17 @@ static void tumbler_resume(pmac_t *chip)
tumbler_reset_audio(chip);
if (mix->i2c.client)
tumbler_init_client(&mix->i2c);
if (chip->model == PMAC_TUMBLER) {
tumbler_set_mono_volume(mix, &tumbler_pcm_vol_info);
tumbler_set_mono_volume(mix, &tumbler_bass_vol_info);
tumbler_set_mono_volume(mix, &tumbler_treble_vol_info);
// tumbler_set_mono_volume(mix, &tumbler_altpcm_vol_info);
} else {
snapper_set_mix_vol(mix, VOL_IDX_PCM);
snapper_set_mix_vol(mix, VOL_IDX_PCM2);
snapper_set_mix_vol(mix, VOL_IDX_ADC);
tumbler_set_mono_volume(mix, &tumbler_bass_vol_info);
tumbler_set_mono_volume(mix, &tumbler_treble_vol_info);
}
tumbler_set_drc(mix);
tumbler_set_master_volume(mix);
if (chip->update_automute)
......@@ -741,6 +951,7 @@ int __init snd_pmac_tumbler_init(pmac_t *chip)
pmac_tumbler_t *mix;
u32 *paddr;
struct device_node *tas_node;
char *chipname;
#ifdef CONFIG_KMOD
request_module("i2c-keywest");
......@@ -770,19 +981,33 @@ int __init snd_pmac_tumbler_init(pmac_t *chip)
mix->i2c.addr = TAS_I2C_ADDR;
mix->i2c.init_client = tumbler_init_client;
if (chip->model == PMAC_TUMBLER) {
mix->i2c.name = "TAS3001c";
chipname = "Tumbler";
} else {
mix->i2c.name = "TAS3004";
chipname = "Snapper";
}
if ((err = snd_pmac_keywest_init(&mix->i2c)) < 0)
return err;
/*
* build mixers
*/
strcpy(chip->card->mixername, "PowerMac Tumbler");
sprintf(chip->card->mixername, "PowerMac %s", chipname);
if (chip->model == PMAC_TUMBLER) {
for (i = 0; i < number_of(tumbler_mixers); i++) {
if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&tumbler_mixers[i], chip))) < 0)
return err;
}
} else {
for (i = 0; i < number_of(snapper_mixers); i++) {
if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snapper_mixers[i], chip))) < 0)
return err;
}
}
chip->master_sw_ctl = snd_ctl_new1(&tumbler_hp_sw, chip);
if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)
return err;
......
......@@ -63,7 +63,7 @@ static unsigned int master_volume_table[] = {
0x00071457, 0x00077fbb, 0x0007f17b,
};
/* treble table */
/* treble table for TAS3001c */
/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
static unsigned int treble_volume_table[] = {
0x96, 0x95, 0x94,
......@@ -93,7 +93,7 @@ static unsigned int treble_volume_table[] = {
0x01,
};
/* bass table */
/* bass table for TAS3001c */
/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
static unsigned int bass_volume_table[] = {
0x86, 0x82, 0x7f,
......@@ -186,3 +186,65 @@ static unsigned int mixer_volume_table[] = {
0x5f4e52, 0x64f403, 0x6aef5d,
0x714575, 0x77fbaa, 0x7f17af,
};
/* treble table for TAS3004 */
/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
static unsigned int snapper_treble_volume_table[] = {
0x96, 0x95, 0x94,
0x93, 0x92, 0x91,
0x90, 0x8f, 0x8e,
0x8d, 0x8c, 0x8b,
0x8a, 0x89, 0x88,
0x87, 0x86, 0x85,
0x84, 0x83, 0x82,
0x81, 0x80, 0x7f,
0x7e, 0x7d, 0x7c,
0x7b, 0x7a, 0x79,
0x78, 0x77, 0x76,
0x75, 0x74, 0x73,
0x72, 0x71, 0x70,
0x6f, 0x6d, 0x6c,
0x6b, 0x69, 0x68,
0x67, 0x65, 0x63,
0x62, 0x60, 0x5d,
0x5b, 0x59, 0x56,
0x53, 0x51, 0x4d,
0x4a, 0x47, 0x43,
0x3f, 0x3b, 0x36,
0x31, 0x2c, 0x26,
0x20, 0x1a, 0x13,
0x08, 0x04, 0x01,
0x01,
};
/* bass table for TAS3004 */
/* 0 = -18 dB, 72 = 18 dB in 0.5 dB step */
static unsigned int snapper_bass_volume_table[] = {
0x96, 0x95, 0x94,
0x93, 0x92, 0x91,
0x90, 0x8f, 0x8e,
0x8d, 0x8c, 0x8b,
0x8a, 0x89, 0x88,
0x87, 0x86, 0x85,
0x84, 0x83, 0x82,
0x81, 0x80, 0x7f,
0x7e, 0x7d, 0x7c,
0x7b, 0x7a, 0x79,
0x78, 0x77, 0x76,
0x75, 0x74, 0x73,
0x72, 0x71, 0x6f,
0x6e, 0x6d, 0x6b,
0x6a, 0x69, 0x67,
0x66, 0x65, 0x63,
0x62, 0x61, 0x5f,
0x5d, 0x5b, 0x58,
0x55, 0x52, 0x4f,
0x4c, 0x49, 0x46,
0x43, 0x3f, 0x3b,
0x37, 0x33, 0x2e,
0x29, 0x24, 0x1e,
0x18, 0x11, 0x0a,
0x01,
};
......@@ -53,6 +53,8 @@ MODULE_DEVICES("{{Generic,USB Audio}}");
static int snd_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *snd_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int snd_enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
static int snd_vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */
static int snd_pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */
MODULE_PARM(snd_index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_index, "Index value for the USB audio adapter.");
......@@ -63,6 +65,27 @@ MODULE_PARM_SYNTAX(snd_id, SNDRV_ID_DESC);
MODULE_PARM(snd_enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_enable, "Enable USB audio adapter.");
MODULE_PARM_SYNTAX(snd_enable, SNDRV_ENABLE_DESC);
MODULE_PARM(snd_vid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_vid, "Vendor ID for the USB audio device.");
MODULE_PARM_SYNTAX(snd_vid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
MODULE_PARM(snd_pid, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
MODULE_PARM_DESC(snd_pid, "Product ID for the USB audio device.");
MODULE_PARM_SYNTAX(snd_pid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16");
/*
* for using ASYNC unlink mode, define the following.
* this will make the driver quicker response for request to STOP-trigger,
* but it may cause oops by some unknown reason (bug of usb driver?),
* so turning off might be sure.
*/
/* #define SND_USE_ASYNC_UNLINK */
#ifdef SND_USB_ASYNC_UNLINK
#define UNLINK_FLAGS USB_ASYNC_UNLINK
#else
#define UNLINK_FLAGS 0
#endif
/*
......@@ -528,6 +551,10 @@ static int deactivate_urbs(snd_usb_substream_t *subs)
subs->running = 0;
#ifndef SND_USB_ASYNC_UNLINK
if (in_interrupt())
return 0;
#endif
alive = 0;
for (i = 0; i < subs->nurbs; i++) {
if (test_bit(i, &subs->active_mask)) {
......@@ -545,7 +572,11 @@ static int deactivate_urbs(snd_usb_substream_t *subs)
}
}
}
#ifdef SND_USB_ASYNC_UNLINK
return alive;
#else
return 0;
#endif
}
......@@ -803,7 +834,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *run
}
u->urb->dev = subs->dev;
u->urb->pipe = subs->datapipe;
u->urb->transfer_flags = USB_ISO_ASAP | USB_ASYNC_UNLINK;
u->urb->transfer_flags = USB_ISO_ASAP | UNLINK_FLAGS;
u->urb->number_of_packets = u->packets;
u->urb->context = u;
u->urb->complete = snd_complete_urb;
......@@ -825,7 +856,7 @@ static int init_substream_urbs(snd_usb_substream_t *subs, snd_pcm_runtime_t *run
u->urb->transfer_buffer_length = NRPACKS * 3;
u->urb->dev = subs->dev;
u->urb->pipe = subs->syncpipe;
u->urb->transfer_flags = USB_ISO_ASAP | USB_ASYNC_UNLINK;
u->urb->transfer_flags = USB_ISO_ASAP | UNLINK_FLAGS;
u->urb->number_of_packets = u->packets;
u->urb->context = u;
u->urb->complete = snd_complete_sync_urb;
......@@ -2043,7 +2074,9 @@ static void *usb_audio_probe(struct usb_device *dev, unsigned int ifnum,
* now look for an empty slot and create a new card instance
*/
for (i = 0; i < SNDRV_CARDS; i++)
if (snd_enable[i] && ! usb_chip[i]) {
if (snd_enable[i] && ! usb_chip[i] &&
(snd_vid[i] == -1 || snd_vid[i] == dev->descriptor.idVendor) &&
(snd_pid[i] == -1 || snd_pid[i] == dev->descriptor.idProduct)) {
card = snd_card_new(snd_index[i], snd_id[i], THIS_MODULE, 0);
if (card == NULL) {
snd_printk(KERN_ERR "cannot create a card instance %d\n", i);
......
......@@ -73,6 +73,7 @@ struct usb_mixer_elem_info {
int channels;
int val_type;
int min, max;
unsigned int initialized: 1;
};
......@@ -498,6 +499,23 @@ static int mixer_ctl_feature_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t
uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1;
} else {
if (! cval->initialized) {
int minchn = 0;
if (cval->cmask) {
int i;
for (i = 0; i < MAX_CHANNELS; i++)
if (cval->cmask & (1 << i)) {
minchn = i + 1;
break;
}
}
if (get_ctl_value(cval, GET_MAX, ((cval->control+1) << 8) | minchn, &cval->max) < 0 ||
get_ctl_value(cval, GET_MIN, ((cval->control+1) << 8) | minchn, &cval->min) < 0) {
snd_printk(KERN_ERR "%d:%d: cannot get min/max values for control %d\n", cval->id, cval->ctrlif, cval->control);
return -EINVAL;
}
cval->initialized = 1;
}
uinfo->value.integer.min = 0;
uinfo->value.integer.max = cval->max - cval->min;
}
......@@ -515,8 +533,10 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
for (c = 0; c < MAX_CHANNELS; c++) {
if (cval->cmask & (1 << c)) {
err = get_cur_mix_value(cval, c + 1, &val);
if (err < 0)
if (err < 0) {
printk("cannot get current value for control %d ch %d: err = %d\n", cval->control, c + 1, err);
return err;
}
val = get_relative_value(cval, val);
ucontrol->value.integer.value[cnt] = val;
cnt++;
......@@ -525,8 +545,10 @@ static int mixer_ctl_feature_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t
} else {
/* master channel */
err = get_cur_mix_value(cval, 0, &val);
if (err < 0)
if (err < 0) {
printk("cannot get current value for control %d master ch: err = %d\n", cval->control, err);
return err;
}
val = get_relative_value(cval, val);
ucontrol->value.integer.value[0] = val;
}
......@@ -592,6 +614,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc,
int nameid = desc[desc[0] - 1];
snd_kcontrol_t *kctl;
usb_mixer_elem_info_t *cval;
int minchn = 0;
if (control == USB_FEATURE_GEQ) {
/* FIXME: not supported yet */
......@@ -614,22 +637,25 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc,
else {
int i, c = 0;
for (i = 0; i < 16; i++)
if (ctl_mask & (1 << i))
if (ctl_mask & (1 << i)) {
if (! minchn)
minchn = i + 1;
c++;
}
cval->channels = c;
}
/* get min/max values */
if (cval->val_type == USB_MIXER_BOOLEAN ||
cval->val_type == USB_MIXER_INV_BOOLEAN)
cval->val_type == USB_MIXER_INV_BOOLEAN) {
cval->max = 1;
else {
if (get_ctl_value(cval, GET_MAX, ((cval->control+1) << 8) | (ctl_mask ? 1 : 0), &cval->max) < 0 ||
get_ctl_value(cval, GET_MIN, ((cval->control+1) << 8) | (ctl_mask ? 1 : 0), &cval->min) < 0) {
cval->initialized = 1;
} else {
if (get_ctl_value(cval, GET_MAX, ((cval->control+1) << 8) | minchn, &cval->max) < 0 ||
get_ctl_value(cval, GET_MIN, ((cval->control+1) << 8) | minchn, &cval->min) < 0)
snd_printk(KERN_ERR "%d:%d: cannot get min/max values for control %d\n", cval->id, cval->ctrlif, control);
snd_magic_kfree(cval);
return;
}
else
cval->initialized = 1;
}
kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
......@@ -759,6 +785,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc,
int i, len;
snd_kcontrol_t *kctl;
usb_audio_term_t iterm;
int minchn = 0;
cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL);
if (! cval)
......@@ -776,16 +803,17 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc,
if (check_matrix_bitmap(desc + 9 + num_ins, in_ch, i, num_outs)) {
cval->cmask |= (1 << i);
cval->channels++;
if (! minchn)
minchn = i + 1;
}
}
/* get min/max values */
if (get_ctl_value(cval, GET_MAX, ((in_ch+1) << 8) | 1, &cval->max) < 0 ||
get_ctl_value(cval, GET_MIN, ((in_ch+1) << 8) | 1, &cval->min) < 0) {
if (get_ctl_value(cval, GET_MAX, ((in_ch+1) << 8) | minchn, &cval->max) < 0 ||
get_ctl_value(cval, GET_MIN, ((in_ch+1) << 8) | minchn, &cval->min) < 0)
snd_printk(KERN_ERR "cannot get min/max values for mixer\n");
snd_magic_kfree(cval);
return;
}
else
cval->initialized = 1;
kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
if (! kctl) {
......@@ -994,11 +1022,10 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char
/* get min/max values */
if (get_ctl_value(cval, GET_MAX, cval->control, &cval->max) < 0 ||
get_ctl_value(cval, GET_MIN, cval->control, &cval->min) < 0) {
get_ctl_value(cval, GET_MIN, cval->control, &cval->min) < 0)
snd_printk(KERN_ERR "cannot get min/max values for proc/ext unit\n");
snd_magic_kfree(cval);
continue;
}
else
cval->initialized = 1;
kctl = snd_ctl_new1(&mixer_procunit_ctl, cval);
if (! kctl) {
......@@ -1158,6 +1185,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned
cval->channels = 1;
cval->min = 1;
cval->max = num_ins;
cval->initialized = 1;
namelist = kmalloc(sizeof(char *) * num_ins, GFP_KERNEL);
if (! namelist) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment