Merge branch 'topic/misc' into for-linus
This commit is contained in:
commit
44c76a960a
|
@ -264,7 +264,7 @@ struct snd_pcm_hw_constraint_ratdens {
|
|||
|
||||
struct snd_pcm_hw_constraint_list {
|
||||
unsigned int count;
|
||||
unsigned int *list;
|
||||
const unsigned int *list;
|
||||
unsigned int mask;
|
||||
};
|
||||
|
||||
|
@ -781,7 +781,8 @@ void snd_interval_muldivk(const struct snd_interval *a, const struct snd_interva
|
|||
unsigned int k, struct snd_interval *c);
|
||||
void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
|
||||
const struct snd_interval *b, struct snd_interval *c);
|
||||
int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask);
|
||||
int snd_interval_list(struct snd_interval *i, unsigned int count,
|
||||
const unsigned int *list, unsigned int mask);
|
||||
int snd_interval_ratnum(struct snd_interval *i,
|
||||
unsigned int rats_count, struct snd_ratnum *rats,
|
||||
unsigned int *nump, unsigned int *denp);
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
/* include/version.h */
|
||||
#define CONFIG_SND_VERSION "1.0.24"
|
||||
#define CONFIG_SND_VERSION "1.0.25"
|
||||
#define CONFIG_SND_DATE ""
|
||||
|
|
|
@ -366,6 +366,8 @@ struct snd_ymfpci {
|
|||
#ifdef CONFIG_PM
|
||||
u32 *saved_regs;
|
||||
u32 saved_ydsxgr_mode;
|
||||
u16 saved_dsxg_legacy;
|
||||
u16 saved_dsxg_elegacy;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
@ -1132,15 +1132,4 @@ static struct i2c_driver onyx_driver = {
|
|||
.id_table = onyx_i2c_id,
|
||||
};
|
||||
|
||||
static int __init onyx_init(void)
|
||||
{
|
||||
return i2c_add_driver(&onyx_driver);
|
||||
}
|
||||
|
||||
static void __exit onyx_exit(void)
|
||||
{
|
||||
i2c_del_driver(&onyx_driver);
|
||||
}
|
||||
|
||||
module_init(onyx_init);
|
||||
module_exit(onyx_exit);
|
||||
module_i2c_driver(onyx_driver);
|
||||
|
|
|
@ -1026,15 +1026,4 @@ static struct i2c_driver tas_driver = {
|
|||
.id_table = tas_i2c_id,
|
||||
};
|
||||
|
||||
static int __init tas_init(void)
|
||||
{
|
||||
return i2c_add_driver(&tas_driver);
|
||||
}
|
||||
|
||||
static void __exit tas_exit(void)
|
||||
{
|
||||
i2c_del_driver(&tas_driver);
|
||||
}
|
||||
|
||||
module_init(tas_init);
|
||||
module_exit(tas_exit);
|
||||
module_i2c_driver(tas_driver);
|
||||
|
|
|
@ -1313,7 +1313,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
|
|||
err = -EPERM;
|
||||
goto __kctl_end;
|
||||
}
|
||||
err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
|
||||
err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
|
||||
if (err > 0) {
|
||||
up_read(&card->controls_rwsem);
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id);
|
||||
|
|
|
@ -480,74 +480,104 @@ int snd_card_free(struct snd_card *card)
|
|||
|
||||
EXPORT_SYMBOL(snd_card_free);
|
||||
|
||||
static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid)
|
||||
/* retrieve the last word of shortname or longname */
|
||||
static const char *retrieve_id_from_card_name(const char *name)
|
||||
{
|
||||
int i, len, idx_flag = 0, loops = SNDRV_CARDS;
|
||||
const char *spos, *src;
|
||||
const char *spos = name;
|
||||
|
||||
while (*name) {
|
||||
if (isspace(*name) && isalnum(name[1]))
|
||||
spos = name + 1;
|
||||
name++;
|
||||
}
|
||||
return spos;
|
||||
}
|
||||
|
||||
/* return true if the given id string doesn't conflict any other card ids */
|
||||
static bool card_id_ok(struct snd_card *card, const char *id)
|
||||
{
|
||||
int i;
|
||||
if (!snd_info_check_reserved_words(id))
|
||||
return false;
|
||||
for (i = 0; i < snd_ecards_limit; i++) {
|
||||
if (snd_cards[i] && snd_cards[i] != card &&
|
||||
!strcmp(snd_cards[i]->id, id))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* copy to card->id only with valid letters from nid */
|
||||
static void copy_valid_id_string(struct snd_card *card, const char *src,
|
||||
const char *nid)
|
||||
{
|
||||
char *id = card->id;
|
||||
|
||||
while (*nid && !isalnum(*nid))
|
||||
nid++;
|
||||
if (isdigit(*nid))
|
||||
*id++ = isalpha(*src) ? *src : 'D';
|
||||
while (*nid && (size_t)(id - card->id) < sizeof(card->id) - 1) {
|
||||
if (isalnum(*nid))
|
||||
*id++ = *nid;
|
||||
nid++;
|
||||
}
|
||||
*id = 0;
|
||||
}
|
||||
|
||||
/* Set card->id from the given string
|
||||
* If the string conflicts with other ids, add a suffix to make it unique.
|
||||
*/
|
||||
static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
|
||||
const char *nid)
|
||||
{
|
||||
int len, loops;
|
||||
bool with_suffix;
|
||||
bool is_default = false;
|
||||
char *id;
|
||||
|
||||
if (nid == NULL) {
|
||||
id = card->shortname;
|
||||
spos = src = id;
|
||||
while (*id != '\0') {
|
||||
if (*id == ' ')
|
||||
spos = id + 1;
|
||||
id++;
|
||||
}
|
||||
} else {
|
||||
spos = src = nid;
|
||||
}
|
||||
copy_valid_id_string(card, src, nid);
|
||||
id = card->id;
|
||||
while (*spos != '\0' && !isalnum(*spos))
|
||||
spos++;
|
||||
if (isdigit(*spos))
|
||||
*id++ = isalpha(src[0]) ? src[0] : 'D';
|
||||
while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) {
|
||||
if (isalnum(*spos))
|
||||
*id++ = *spos;
|
||||
spos++;
|
||||
}
|
||||
*id = '\0';
|
||||
|
||||
id = card->id;
|
||||
|
||||
if (*id == '\0')
|
||||
again:
|
||||
/* use "Default" for obviously invalid strings
|
||||
* ("card" conflicts with proc directories)
|
||||
*/
|
||||
if (!*id || !strncmp(id, "card", 4)) {
|
||||
strcpy(id, "Default");
|
||||
is_default = true;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (loops-- == 0) {
|
||||
snd_printk(KERN_ERR "unable to set card id (%s)\n", id);
|
||||
strcpy(card->id, card->proc_root->name);
|
||||
return;
|
||||
}
|
||||
if (!snd_info_check_reserved_words(id))
|
||||
goto __change;
|
||||
for (i = 0; i < snd_ecards_limit; i++) {
|
||||
if (snd_cards[i] && !strcmp(snd_cards[i]->id, id))
|
||||
goto __change;
|
||||
}
|
||||
break;
|
||||
with_suffix = false;
|
||||
for (loops = 0; loops < SNDRV_CARDS; loops++) {
|
||||
if (card_id_ok(card, id))
|
||||
return; /* OK */
|
||||
|
||||
__change:
|
||||
len = strlen(id);
|
||||
if (idx_flag) {
|
||||
if (id[len-1] != '9')
|
||||
id[len-1]++;
|
||||
else
|
||||
id[len-1] = 'A';
|
||||
} else if ((size_t)len <= sizeof(card->id) - 3) {
|
||||
strcat(id, "_1");
|
||||
idx_flag++;
|
||||
if (!with_suffix) {
|
||||
/* add the "_X" suffix */
|
||||
char *spos = id + len;
|
||||
if (len > sizeof(card->id) - 3)
|
||||
spos = id + sizeof(card->id) - 3;
|
||||
strcpy(spos, "_1");
|
||||
with_suffix = true;
|
||||
} else {
|
||||
spos = id + len - 2;
|
||||
if ((size_t)len <= sizeof(card->id) - 2)
|
||||
spos++;
|
||||
*(char *)spos++ = '_';
|
||||
*(char *)spos++ = '1';
|
||||
*(char *)spos++ = '\0';
|
||||
idx_flag++;
|
||||
/* modify the existing suffix */
|
||||
if (id[len - 1] != '9')
|
||||
id[len - 1]++;
|
||||
else
|
||||
id[len - 1] = 'A';
|
||||
}
|
||||
}
|
||||
/* fallback to the default id */
|
||||
if (!is_default) {
|
||||
*id = 0;
|
||||
goto again;
|
||||
}
|
||||
/* last resort... */
|
||||
snd_printk(KERN_ERR "unable to set card id (%s)\n", id);
|
||||
if (card->proc_root->name)
|
||||
strcpy(card->id, card->proc_root->name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -564,7 +594,7 @@ void snd_card_set_id(struct snd_card *card, const char *nid)
|
|||
if (card->id[0] != '\0')
|
||||
return;
|
||||
mutex_lock(&snd_card_mutex);
|
||||
snd_card_set_id_no_lock(card, nid);
|
||||
snd_card_set_id_no_lock(card, nid, nid);
|
||||
mutex_unlock(&snd_card_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(snd_card_set_id);
|
||||
|
@ -596,22 +626,12 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr,
|
|||
memcpy(buf1, buf, copy);
|
||||
buf1[copy] = '\0';
|
||||
mutex_lock(&snd_card_mutex);
|
||||
if (!snd_info_check_reserved_words(buf1)) {
|
||||
__exist:
|
||||
if (!card_id_ok(NULL, buf1)) {
|
||||
mutex_unlock(&snd_card_mutex);
|
||||
return -EEXIST;
|
||||
}
|
||||
for (idx = 0; idx < snd_ecards_limit; idx++) {
|
||||
if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) {
|
||||
if (card == snd_cards[idx])
|
||||
goto __ok;
|
||||
else
|
||||
goto __exist;
|
||||
}
|
||||
}
|
||||
strcpy(card->id, buf1);
|
||||
snd_info_card_id_change(card);
|
||||
__ok:
|
||||
mutex_unlock(&snd_card_mutex);
|
||||
|
||||
return count;
|
||||
|
@ -665,7 +685,18 @@ int snd_card_register(struct snd_card *card)
|
|||
mutex_unlock(&snd_card_mutex);
|
||||
return 0;
|
||||
}
|
||||
snd_card_set_id_no_lock(card, card->id[0] == '\0' ? NULL : card->id);
|
||||
if (*card->id) {
|
||||
/* make a unique id name from the given string */
|
||||
char tmpid[sizeof(card->id)];
|
||||
memcpy(tmpid, card->id, sizeof(card->id));
|
||||
snd_card_set_id_no_lock(card, tmpid, tmpid);
|
||||
} else {
|
||||
/* create an id from either shortname or longname */
|
||||
const char *src;
|
||||
src = *card->shortname ? card->shortname : card->longname;
|
||||
snd_card_set_id_no_lock(card, src,
|
||||
retrieve_id_from_card_name(src));
|
||||
}
|
||||
snd_cards[card->number] = card;
|
||||
mutex_unlock(&snd_card_mutex);
|
||||
init_info_for_card(card);
|
||||
|
|
|
@ -72,7 +72,7 @@ void __snd_printk(unsigned int level, const char *path, int line,
|
|||
char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV";
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
#ifdef CONFIG_SND_DEBUG
|
||||
if (debug < level)
|
||||
return;
|
||||
#endif
|
||||
|
|
|
@ -1029,7 +1029,8 @@ static int snd_interval_ratden(struct snd_interval *i,
|
|||
*
|
||||
* Returns non-zero if the value is changed, zero if not changed.
|
||||
*/
|
||||
int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask)
|
||||
int snd_interval_list(struct snd_interval *i, unsigned int count,
|
||||
const unsigned int *list, unsigned int mask)
|
||||
{
|
||||
unsigned int k;
|
||||
struct snd_interval list_range;
|
||||
|
|
|
@ -1586,12 +1586,18 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
|
|||
struct file *file;
|
||||
struct snd_pcm_file *pcm_file;
|
||||
struct snd_pcm_substream *substream1;
|
||||
struct snd_pcm_group *group;
|
||||
|
||||
file = snd_pcm_file_fd(fd);
|
||||
if (!file)
|
||||
return -EBADFD;
|
||||
pcm_file = file->private_data;
|
||||
substream1 = pcm_file->substream;
|
||||
group = kmalloc(sizeof(*group), GFP_KERNEL);
|
||||
if (!group) {
|
||||
res = -ENOMEM;
|
||||
goto _nolock;
|
||||
}
|
||||
down_write(&snd_pcm_link_rwsem);
|
||||
write_lock_irq(&snd_pcm_link_rwlock);
|
||||
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
|
||||
|
@ -1604,11 +1610,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
|
|||
goto _end;
|
||||
}
|
||||
if (!snd_pcm_stream_linked(substream)) {
|
||||
substream->group = kmalloc(sizeof(struct snd_pcm_group), GFP_ATOMIC);
|
||||
if (substream->group == NULL) {
|
||||
res = -ENOMEM;
|
||||
goto _end;
|
||||
}
|
||||
substream->group = group;
|
||||
spin_lock_init(&substream->group->lock);
|
||||
INIT_LIST_HEAD(&substream->group->substreams);
|
||||
list_add_tail(&substream->link_list, &substream->group->substreams);
|
||||
|
@ -1620,7 +1622,10 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
|
|||
_end:
|
||||
write_unlock_irq(&snd_pcm_link_rwlock);
|
||||
up_write(&snd_pcm_link_rwsem);
|
||||
_nolock:
|
||||
fput(file);
|
||||
if (res < 0)
|
||||
kfree(group);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <sound/mpu401.h>
|
||||
#include <sound/hwdep.h>
|
||||
#include <sound/ac97_codec.h>
|
||||
|
||||
#include <sound/tlv.h>
|
||||
#endif
|
||||
|
||||
#ifndef CHIP_AU8820
|
||||
|
@ -107,6 +107,14 @@
|
|||
#define NR_WTPB 0x20 /* WT channels per each bank. */
|
||||
#define NR_PCM 0x10
|
||||
|
||||
struct pcm_vol {
|
||||
struct snd_kcontrol *kctl;
|
||||
int active;
|
||||
int dma;
|
||||
int mixin[4];
|
||||
int vol[4];
|
||||
};
|
||||
|
||||
/* Structs */
|
||||
typedef struct {
|
||||
//int this_08; /* Still unknown */
|
||||
|
@ -168,6 +176,7 @@ struct snd_vortex {
|
|||
/* Xtalk canceler */
|
||||
int xt_mode; /* 1: speakers, 0:headphones. */
|
||||
#endif
|
||||
struct pcm_vol pcm_vol[NR_PCM];
|
||||
|
||||
int isquad; /* cache of extended ID codec flag. */
|
||||
|
||||
|
@ -239,7 +248,7 @@ static int vortex_alsafmt_aspfmt(int alsafmt);
|
|||
/* Connection stuff. */
|
||||
static void vortex_connect_default(vortex_t * vortex, int en);
|
||||
static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch,
|
||||
int dir, int type);
|
||||
int dir, int type, int subdev);
|
||||
static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out,
|
||||
int restype);
|
||||
#ifndef CHIP_AU8810
|
||||
|
|
|
@ -2050,8 +2050,6 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype)
|
|||
}
|
||||
|
||||
/* Default Connections */
|
||||
static int
|
||||
vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type);
|
||||
|
||||
static void vortex_connect_default(vortex_t * vortex, int en)
|
||||
{
|
||||
|
@ -2111,15 +2109,13 @@ static void vortex_connect_default(vortex_t * vortex, int en)
|
|||
Return: Return allocated DMA or same DMA passed as "dma" when dma >= 0.
|
||||
*/
|
||||
static int
|
||||
vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type)
|
||||
vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir,
|
||||
int type, int subdev)
|
||||
{
|
||||
stream_t *stream;
|
||||
int i, en;
|
||||
struct pcm_vol *p;
|
||||
|
||||
if ((nr_ch == 3)
|
||||
|| ((dir == SNDRV_PCM_STREAM_CAPTURE) && (nr_ch > 2)))
|
||||
return -EBUSY;
|
||||
|
||||
if (dma >= 0) {
|
||||
en = 0;
|
||||
vortex_adb_checkinout(vortex,
|
||||
|
@ -2250,6 +2246,14 @@ vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type)
|
|||
MIX_DEFIGAIN);
|
||||
#endif
|
||||
}
|
||||
if (stream->type == VORTEX_PCM_ADB && en) {
|
||||
p = &vortex->pcm_vol[subdev];
|
||||
p->dma = dma;
|
||||
for (i = 0; i < nr_ch; i++)
|
||||
p->mixin[i] = mix[i];
|
||||
for (i = 0; i < ch_top; i++)
|
||||
p->vol[i] = 0;
|
||||
}
|
||||
}
|
||||
#ifndef CHIP_AU8820
|
||||
else {
|
||||
|
@ -2473,7 +2477,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id)
|
|||
hwread(vortex->mmio, VORTEX_IRQ_STAT);
|
||||
handled = 1;
|
||||
}
|
||||
if (source & IRQ_MIDI) {
|
||||
if ((source & IRQ_MIDI) && vortex->rmidi) {
|
||||
snd_mpu401_uart_interrupt(vortex->irq,
|
||||
vortex->rmidi->private_data);
|
||||
handled = 1;
|
||||
|
|
|
@ -122,6 +122,18 @@ static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = {
|
|||
.mask = 0,
|
||||
};
|
||||
#endif
|
||||
|
||||
static void vortex_notify_pcm_vol_change(struct snd_card *card,
|
||||
struct snd_kcontrol *kctl, int activate)
|
||||
{
|
||||
if (activate)
|
||||
kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
||||
else
|
||||
kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE |
|
||||
SNDRV_CTL_EVENT_MASK_INFO, &(kctl->id));
|
||||
}
|
||||
|
||||
/* open callback */
|
||||
static int snd_vortex_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
|
@ -230,12 +242,14 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
if (stream != NULL)
|
||||
vortex_adb_allocroute(chip, stream->dma,
|
||||
stream->nr_ch, stream->dir,
|
||||
stream->type);
|
||||
stream->type,
|
||||
substream->number);
|
||||
/* Alloc routes. */
|
||||
dma =
|
||||
vortex_adb_allocroute(chip, -1,
|
||||
params_channels(hw_params),
|
||||
substream->stream, type);
|
||||
substream->stream, type,
|
||||
substream->number);
|
||||
if (dma < 0) {
|
||||
spin_unlock_irq(&chip->lock);
|
||||
return dma;
|
||||
|
@ -246,6 +260,11 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
|
|||
vortex_adbdma_setbuffers(chip, dma,
|
||||
params_period_bytes(hw_params),
|
||||
params_periods(hw_params));
|
||||
if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
|
||||
chip->pcm_vol[substream->number].active = 1;
|
||||
vortex_notify_pcm_vol_change(chip->card,
|
||||
chip->pcm_vol[substream->number].kctl, 1);
|
||||
}
|
||||
}
|
||||
#ifndef CHIP_AU8810
|
||||
else {
|
||||
|
@ -275,10 +294,18 @@ static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream)
|
|||
spin_lock_irq(&chip->lock);
|
||||
// Delete audio routes.
|
||||
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
|
||||
if (stream != NULL)
|
||||
if (stream != NULL) {
|
||||
if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) {
|
||||
chip->pcm_vol[substream->number].active = 0;
|
||||
vortex_notify_pcm_vol_change(chip->card,
|
||||
chip->pcm_vol[substream->number].kctl,
|
||||
0);
|
||||
}
|
||||
vortex_adb_allocroute(chip, stream->dma,
|
||||
stream->nr_ch, stream->dir,
|
||||
stream->type);
|
||||
stream->type,
|
||||
substream->number);
|
||||
}
|
||||
}
|
||||
#ifndef CHIP_AU8810
|
||||
else {
|
||||
|
@ -506,6 +533,83 @@ static struct snd_kcontrol_new snd_vortex_mixer_spdif[] __devinitdata = {
|
|||
},
|
||||
};
|
||||
|
||||
/* subdevice PCM Volume control */
|
||||
|
||||
static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
vortex_t *vortex = snd_kcontrol_chip(kcontrol);
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
|
||||
uinfo->value.integer.min = -128;
|
||||
uinfo->value.integer.max = 32;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
int i;
|
||||
vortex_t *vortex = snd_kcontrol_chip(kcontrol);
|
||||
int subdev = kcontrol->id.subdevice;
|
||||
struct pcm_vol *p = &vortex->pcm_vol[subdev];
|
||||
int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
|
||||
for (i = 0; i < max_chn; i++)
|
||||
ucontrol->value.integer.value[i] = p->vol[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
int i;
|
||||
int changed = 0;
|
||||
int mixin;
|
||||
unsigned char vol;
|
||||
vortex_t *vortex = snd_kcontrol_chip(kcontrol);
|
||||
int subdev = kcontrol->id.subdevice;
|
||||
struct pcm_vol *p = &vortex->pcm_vol[subdev];
|
||||
int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2);
|
||||
for (i = 0; i < max_chn; i++) {
|
||||
if (p->vol[i] != ucontrol->value.integer.value[i]) {
|
||||
p->vol[i] = ucontrol->value.integer.value[i];
|
||||
if (p->active) {
|
||||
switch (vortex->dma_adb[p->dma].nr_ch) {
|
||||
case 1:
|
||||
mixin = p->mixin[0];
|
||||
break;
|
||||
case 2:
|
||||
default:
|
||||
mixin = p->mixin[(i < 2) ? i : (i - 2)];
|
||||
break;
|
||||
case 4:
|
||||
mixin = p->mixin[i];
|
||||
break;
|
||||
};
|
||||
vol = p->vol[i];
|
||||
vortex_mix_setinputvolumebyte(vortex,
|
||||
vortex->mixplayb[i], mixin, vol);
|
||||
}
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400);
|
||||
|
||||
static struct snd_kcontrol_new snd_vortex_pcm_vol __devinitdata = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
||||
.name = "PCM Playback Volume",
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_READ |
|
||||
SNDRV_CTL_ELEM_ACCESS_INACTIVE,
|
||||
.info = snd_vortex_pcm_vol_info,
|
||||
.get = snd_vortex_pcm_vol_get,
|
||||
.put = snd_vortex_pcm_vol_put,
|
||||
.tlv = { .p = vortex_pcm_vol_db_scale },
|
||||
};
|
||||
|
||||
/* create a pcm device */
|
||||
static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
|
||||
{
|
||||
|
@ -555,5 +659,20 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr)
|
|||
return err;
|
||||
}
|
||||
}
|
||||
if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) {
|
||||
for (i = 0; i < NR_PCM; i++) {
|
||||
chip->pcm_vol[i].active = 0;
|
||||
chip->pcm_vol[i].dma = -1;
|
||||
kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip);
|
||||
if (!kctl)
|
||||
return -ENOMEM;
|
||||
chip->pcm_vol[i].kctl = kctl;
|
||||
kctl->id.device = 0;
|
||||
kctl->id.subdevice = i;
|
||||
err = snd_ctl_add(chip->card, kctl);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ get_vm_block(struct ct_vm *vm, unsigned int size)
|
|||
|
||||
size = CT_PAGE_ALIGN(size);
|
||||
if (size > vm->size) {
|
||||
printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural "
|
||||
printk(KERN_ERR "ctxfi: Fail! No sufficient device virtual "
|
||||
"memory space available!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -1013,6 +1013,25 @@ static int set_rate_constraints(struct snd_ice1712 *ice,
|
|||
ice->hw_rates);
|
||||
}
|
||||
|
||||
/* if the card has the internal rate locked (is_pro_locked), limit runtime
|
||||
hw rates to the current internal rate only.
|
||||
*/
|
||||
static void constrain_rate_if_locked(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
unsigned int rate;
|
||||
if (is_pro_rate_locked(ice)) {
|
||||
rate = ice->get_rate(ice);
|
||||
if (rate >= runtime->hw.rate_min
|
||||
&& rate <= runtime->hw.rate_max) {
|
||||
runtime->hw.rate_min = rate;
|
||||
runtime->hw.rate_max = rate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* multi-channel playback needs alignment 8x32bit regardless of the channels
|
||||
* actually used
|
||||
*/
|
||||
|
@ -1046,6 +1065,7 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream)
|
|||
VT1724_BUFFER_ALIGN);
|
||||
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
|
||||
VT1724_BUFFER_ALIGN);
|
||||
constrain_rate_if_locked(substream);
|
||||
if (ice->pro_open)
|
||||
ice->pro_open(ice, substream);
|
||||
return 0;
|
||||
|
@ -1066,6 +1086,7 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream)
|
|||
VT1724_BUFFER_ALIGN);
|
||||
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
|
||||
VT1724_BUFFER_ALIGN);
|
||||
constrain_rate_if_locked(substream);
|
||||
if (ice->pro_open)
|
||||
ice->pro_open(ice, substream);
|
||||
return 0;
|
||||
|
@ -1215,6 +1236,7 @@ static int snd_vt1724_playback_spdif_open(struct snd_pcm_substream *substream)
|
|||
VT1724_BUFFER_ALIGN);
|
||||
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
|
||||
VT1724_BUFFER_ALIGN);
|
||||
constrain_rate_if_locked(substream);
|
||||
if (ice->spdif.ops.open)
|
||||
ice->spdif.ops.open(ice, substream);
|
||||
return 0;
|
||||
|
@ -1251,6 +1273,7 @@ static int snd_vt1724_capture_spdif_open(struct snd_pcm_substream *substream)
|
|||
VT1724_BUFFER_ALIGN);
|
||||
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
|
||||
VT1724_BUFFER_ALIGN);
|
||||
constrain_rate_if_locked(substream);
|
||||
if (ice->spdif.ops.open)
|
||||
ice->spdif.ops.open(ice, substream);
|
||||
return 0;
|
||||
|
|
|
@ -2317,6 +2317,10 @@ int snd_ymfpci_suspend(struct pci_dev *pci, pm_message_t state)
|
|||
for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++)
|
||||
chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]);
|
||||
chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE);
|
||||
pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY,
|
||||
&chip->saved_dsxg_legacy);
|
||||
pci_read_config_word(chip->pci, PCIR_DSXG_ELEGACY,
|
||||
&chip->saved_dsxg_elegacy);
|
||||
snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0);
|
||||
snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0);
|
||||
snd_ymfpci_disable_dsp(chip);
|
||||
|
@ -2351,6 +2355,11 @@ int snd_ymfpci_resume(struct pci_dev *pci)
|
|||
|
||||
snd_ac97_resume(chip->ac97);
|
||||
|
||||
pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY,
|
||||
chip->saved_dsxg_legacy);
|
||||
pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY,
|
||||
chip->saved_dsxg_elegacy);
|
||||
|
||||
/* start hw again */
|
||||
if (chip->start_count > 0) {
|
||||
spin_lock_irq(&chip->reg_lock);
|
||||
|
|
|
@ -1112,17 +1112,7 @@ static struct spi_driver at73c213_driver = {
|
|||
.remove = __devexit_p(snd_at73c213_remove),
|
||||
};
|
||||
|
||||
static int __init at73c213_init(void)
|
||||
{
|
||||
return spi_register_driver(&at73c213_driver);
|
||||
}
|
||||
module_init(at73c213_init);
|
||||
|
||||
static void __exit at73c213_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&at73c213_driver);
|
||||
}
|
||||
module_exit(at73c213_exit);
|
||||
module_spi_driver(at73c213_driver);
|
||||
|
||||
MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
|
||||
MODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC");
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*
|
||||
* Author: Torsten Schenk <torsten.schenk@zoho.com>
|
||||
* Created: Jan 01, 2011
|
||||
* Version: 0.3.0
|
||||
* Copyright: (C) Torsten Schenk
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -29,7 +28,7 @@
|
|||
#include <sound/initval.h>
|
||||
|
||||
MODULE_AUTHOR("Torsten Schenk <torsten.schenk@zoho.com>");
|
||||
MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver, version 0.3.0");
|
||||
MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}");
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
*
|
||||
* Author: Torsten Schenk <torsten.schenk@zoho.com>
|
||||
* Created: Jan 01, 2011
|
||||
* Version: 0.3.0
|
||||
* Copyright: (C) Torsten Schenk
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*
|
||||
* Author: Torsten Schenk <torsten.schenk@zoho.com>
|
||||
* Created: Jan 01, 2011
|
||||
* Version: 0.3.0
|
||||
* Copyright: (C) Torsten Schenk
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
*
|
||||
* Author: Torsten Schenk <torsten.schenk@zoho.com>
|
||||
* Created: Jan 01, 2011
|
||||
* Version: 0.3.0
|
||||
* Copyright: (C) Torsten Schenk
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
*
|
||||
* Author: Torsten Schenk <torsten.schenk@zoho.com>
|
||||
* Created: Jan 01, 2011
|
||||
* Version: 0.3.0
|
||||
* Copyright: (C) Torsten Schenk
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -5,9 +5,12 @@
|
|||
*
|
||||
* Author: Torsten Schenk <torsten.schenk@zoho.com>
|
||||
* Created: Jan 01, 2011
|
||||
* Version: 0.3.0
|
||||
* Copyright: (C) Torsten Schenk
|
||||
*
|
||||
* Thanks to:
|
||||
* - Holger Ruckdeschel: he found out how to control individual channel
|
||||
* volumes and introduced mute switch
|
||||
*
|
||||
* 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
|
||||
|
@ -16,6 +19,7 @@
|
|||
|
||||
#include <linux/interrupt.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/tlv.h>
|
||||
|
||||
#include "control.h"
|
||||
#include "comm.h"
|
||||
|
@ -24,26 +28,6 @@
|
|||
static char *opt_coax_texts[2] = { "Optical", "Coax" };
|
||||
static char *line_phono_texts[2] = { "Line", "Phono" };
|
||||
|
||||
/*
|
||||
* calculated with $value\[i\] = 128 \cdot sqrt[3]{\frac{i}{128}}$
|
||||
* this is done because the linear values cause rapid degredation
|
||||
* of volume in the uppermost region.
|
||||
*/
|
||||
static const u8 log_volume_table[128] = {
|
||||
0x00, 0x19, 0x20, 0x24, 0x28, 0x2b, 0x2e, 0x30, 0x32, 0x34,
|
||||
0x36, 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x41, 0x42, 0x43,
|
||||
0x44, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e,
|
||||
0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x53, 0x54, 0x55, 0x56,
|
||||
0x56, 0x57, 0x58, 0x58, 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c,
|
||||
0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62,
|
||||
0x63, 0x63, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68,
|
||||
0x68, 0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c,
|
||||
0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71,
|
||||
0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75,
|
||||
0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79,
|
||||
0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c,
|
||||
0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f };
|
||||
|
||||
/*
|
||||
* data that needs to be sent to device. sets up card internal stuff.
|
||||
* values dumped from windows driver and filtered by trial'n'error.
|
||||
|
@ -59,7 +43,7 @@ init_data[] = {
|
|||
{ 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 },
|
||||
{ 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 },
|
||||
{ 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 },
|
||||
{ 0x12, 0x0d, 0x78 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 },
|
||||
{ 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 },
|
||||
{ 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 },
|
||||
{ 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 },
|
||||
{ 0 } /* TERMINATING ENTRY */
|
||||
|
@ -70,20 +54,47 @@ static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
|
|||
static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
|
||||
static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
|
||||
|
||||
static DECLARE_TLV_DB_MINMAX(tlv_output, -9000, 0);
|
||||
static DECLARE_TLV_DB_MINMAX(tlv_input, -1500, 1500);
|
||||
|
||||
enum {
|
||||
DIGITAL_THRU_ONLY_SAMPLERATE = 3
|
||||
};
|
||||
|
||||
static void usb6fire_control_master_vol_update(struct control_runtime *rt)
|
||||
static void usb6fire_control_output_vol_update(struct control_runtime *rt)
|
||||
{
|
||||
struct comm_runtime *comm_rt = rt->chip->comm;
|
||||
if (comm_rt) {
|
||||
/* set volume */
|
||||
comm_rt->write8(comm_rt, 0x12, 0x0f, 0x7f -
|
||||
log_volume_table[rt->master_vol]);
|
||||
/* unmute */
|
||||
comm_rt->write8(comm_rt, 0x12, 0x0e, 0x00);
|
||||
}
|
||||
int i;
|
||||
|
||||
if (comm_rt)
|
||||
for (i = 0; i < 6; i++)
|
||||
if (!(rt->ovol_updated & (1 << i))) {
|
||||
comm_rt->write8(comm_rt, 0x12, 0x0f + i,
|
||||
180 - rt->output_vol[i]);
|
||||
rt->ovol_updated |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
static void usb6fire_control_output_mute_update(struct control_runtime *rt)
|
||||
{
|
||||
struct comm_runtime *comm_rt = rt->chip->comm;
|
||||
|
||||
if (comm_rt)
|
||||
comm_rt->write8(comm_rt, 0x12, 0x0e, ~rt->output_mute);
|
||||
}
|
||||
|
||||
static void usb6fire_control_input_vol_update(struct control_runtime *rt)
|
||||
{
|
||||
struct comm_runtime *comm_rt = rt->chip->comm;
|
||||
int i;
|
||||
|
||||
if (comm_rt)
|
||||
for (i = 0; i < 2; i++)
|
||||
if (!(rt->ivol_updated & (1 << i))) {
|
||||
comm_rt->write8(comm_rt, 0x12, 0x1c + i,
|
||||
rt->input_vol[i] & 0x3f);
|
||||
rt->ivol_updated |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
static void usb6fire_control_line_phono_update(struct control_runtime *rt)
|
||||
|
@ -165,34 +176,147 @@ static int usb6fire_control_streaming_update(struct control_runtime *rt)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol,
|
||||
static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 1;
|
||||
uinfo->count = 2;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 127;
|
||||
uinfo->value.integer.max = 180;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb6fire_control_master_vol_put(struct snd_kcontrol *kcontrol,
|
||||
static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
|
||||
unsigned int ch = kcontrol->private_value;
|
||||
int changed = 0;
|
||||
|
||||
if (ch > 4) {
|
||||
snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) {
|
||||
rt->output_vol[ch] = ucontrol->value.integer.value[0];
|
||||
rt->ovol_updated &= ~(1 << ch);
|
||||
changed = 1;
|
||||
}
|
||||
if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) {
|
||||
rt->output_vol[ch + 1] = ucontrol->value.integer.value[1];
|
||||
rt->ovol_updated &= ~(2 << ch);
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
usb6fire_control_output_vol_update(rt);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
|
||||
unsigned int ch = kcontrol->private_value;
|
||||
|
||||
if (ch > 4) {
|
||||
snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ucontrol->value.integer.value[0] = rt->output_vol[ch];
|
||||
ucontrol->value.integer.value[1] = rt->output_vol[ch + 1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
|
||||
unsigned int ch = kcontrol->private_value;
|
||||
u8 old = rt->output_mute;
|
||||
u8 value = 0;
|
||||
|
||||
if (ch > 4) {
|
||||
snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rt->output_mute &= ~(3 << ch);
|
||||
if (ucontrol->value.integer.value[0])
|
||||
value |= 1;
|
||||
if (ucontrol->value.integer.value[1])
|
||||
value |= 2;
|
||||
rt->output_mute |= value << ch;
|
||||
|
||||
if (rt->output_mute != old)
|
||||
usb6fire_control_output_mute_update(rt);
|
||||
|
||||
return rt->output_mute != old;
|
||||
}
|
||||
|
||||
static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
|
||||
unsigned int ch = kcontrol->private_value;
|
||||
u8 value = rt->output_mute >> ch;
|
||||
|
||||
if (ch > 4) {
|
||||
snd_printk(KERN_ERR PREFIX "Invalid channel in volume control.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ucontrol->value.integer.value[0] = 1 & value;
|
||||
value >>= 1;
|
||||
ucontrol->value.integer.value[1] = 1 & value;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb6fire_control_input_vol_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 2;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 30;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
|
||||
int changed = 0;
|
||||
if (rt->master_vol != ucontrol->value.integer.value[0]) {
|
||||
rt->master_vol = ucontrol->value.integer.value[0];
|
||||
usb6fire_control_master_vol_update(rt);
|
||||
|
||||
if (rt->input_vol[0] != ucontrol->value.integer.value[0]) {
|
||||
rt->input_vol[0] = ucontrol->value.integer.value[0] - 15;
|
||||
rt->ivol_updated &= ~(1 << 0);
|
||||
changed = 1;
|
||||
}
|
||||
if (rt->input_vol[1] != ucontrol->value.integer.value[1]) {
|
||||
rt->input_vol[1] = ucontrol->value.integer.value[1] - 15;
|
||||
rt->ivol_updated &= ~(1 << 1);
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
usb6fire_control_input_vol_update(rt);
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int usb6fire_control_master_vol_get(struct snd_kcontrol *kcontrol,
|
||||
static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct control_runtime *rt = snd_kcontrol_chip(kcontrol);
|
||||
ucontrol->value.integer.value[0] = rt->master_vol;
|
||||
|
||||
ucontrol->value.integer.value[0] = rt->input_vol[0] + 15;
|
||||
ucontrol->value.integer.value[1] = rt->input_vol[1] + 15;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -287,16 +411,81 @@ static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static struct __devinitdata snd_kcontrol_new elements[] = {
|
||||
static struct __devinitdata snd_kcontrol_new vol_elements[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Master Playback Volume",
|
||||
.name = "Analog Playback Volume",
|
||||
.index = 0,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = usb6fire_control_master_vol_info,
|
||||
.get = usb6fire_control_master_vol_get,
|
||||
.put = usb6fire_control_master_vol_put
|
||||
.private_value = 0,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
|
||||
.info = usb6fire_control_output_vol_info,
|
||||
.get = usb6fire_control_output_vol_get,
|
||||
.put = usb6fire_control_output_vol_put,
|
||||
.tlv = { .p = tlv_output }
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Analog Playback Volume",
|
||||
.index = 1,
|
||||
.private_value = 2,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
|
||||
.info = usb6fire_control_output_vol_info,
|
||||
.get = usb6fire_control_output_vol_get,
|
||||
.put = usb6fire_control_output_vol_put,
|
||||
.tlv = { .p = tlv_output }
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Analog Playback Volume",
|
||||
.index = 2,
|
||||
.private_value = 4,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
|
||||
.info = usb6fire_control_output_vol_info,
|
||||
.get = usb6fire_control_output_vol_get,
|
||||
.put = usb6fire_control_output_vol_put,
|
||||
.tlv = { .p = tlv_output }
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct __devinitdata snd_kcontrol_new mute_elements[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Analog Playback Switch",
|
||||
.index = 0,
|
||||
.private_value = 0,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = snd_ctl_boolean_stereo_info,
|
||||
.get = usb6fire_control_output_mute_get,
|
||||
.put = usb6fire_control_output_mute_put,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Analog Playback Switch",
|
||||
.index = 1,
|
||||
.private_value = 2,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = snd_ctl_boolean_stereo_info,
|
||||
.get = usb6fire_control_output_mute_get,
|
||||
.put = usb6fire_control_output_mute_put,
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Analog Playback Switch",
|
||||
.index = 2,
|
||||
.private_value = 4,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = snd_ctl_boolean_stereo_info,
|
||||
.get = usb6fire_control_output_mute_get,
|
||||
.put = usb6fire_control_output_mute_put,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct __devinitdata snd_kcontrol_new elements[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Line/Phono Capture Route",
|
||||
|
@ -324,9 +513,54 @@ static struct __devinitdata snd_kcontrol_new elements[] = {
|
|||
.get = usb6fire_control_digital_thru_get,
|
||||
.put = usb6fire_control_digital_thru_put
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Analog Capture Volume",
|
||||
.index = 0,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
|
||||
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
|
||||
.info = usb6fire_control_input_vol_info,
|
||||
.get = usb6fire_control_input_vol_get,
|
||||
.put = usb6fire_control_input_vol_put,
|
||||
.tlv = { .p = tlv_input }
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static int usb6fire_control_add_virtual(
|
||||
struct control_runtime *rt,
|
||||
struct snd_card *card,
|
||||
char *name,
|
||||
struct snd_kcontrol_new *elems)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
struct snd_kcontrol *vmaster =
|
||||
snd_ctl_make_virtual_master(name, tlv_output);
|
||||
struct snd_kcontrol *control;
|
||||
|
||||
if (!vmaster)
|
||||
return -ENOMEM;
|
||||
ret = snd_ctl_add(card, vmaster);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
i = 0;
|
||||
while (elems[i].name) {
|
||||
control = snd_ctl_new1(&elems[i], rt);
|
||||
if (!control)
|
||||
return -ENOMEM;
|
||||
ret = snd_ctl_add(card, control);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = snd_ctl_add_slave(vmaster, control);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __devinit usb6fire_control_init(struct sfire_chip *chip)
|
||||
{
|
||||
int i;
|
||||
|
@ -352,9 +586,26 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip)
|
|||
|
||||
usb6fire_control_opt_coax_update(rt);
|
||||
usb6fire_control_line_phono_update(rt);
|
||||
usb6fire_control_master_vol_update(rt);
|
||||
usb6fire_control_output_vol_update(rt);
|
||||
usb6fire_control_output_mute_update(rt);
|
||||
usb6fire_control_input_vol_update(rt);
|
||||
usb6fire_control_streaming_update(rt);
|
||||
|
||||
ret = usb6fire_control_add_virtual(rt, chip->card,
|
||||
"Master Playback Volume", vol_elements);
|
||||
if (ret) {
|
||||
snd_printk(KERN_ERR PREFIX "cannot add control.\n");
|
||||
kfree(rt);
|
||||
return ret;
|
||||
}
|
||||
ret = usb6fire_control_add_virtual(rt, chip->card,
|
||||
"Master Playback Switch", mute_elements);
|
||||
if (ret) {
|
||||
snd_printk(KERN_ERR PREFIX "cannot add control.\n");
|
||||
kfree(rt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (elements[i].name) {
|
||||
ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt));
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
*
|
||||
* Author: Torsten Schenk <torsten.schenk@zoho.com>
|
||||
* Created: Jan 01, 2011
|
||||
* Version: 0.3.0
|
||||
* Copyright: (C) Torsten Schenk
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -44,7 +43,11 @@ struct control_runtime {
|
|||
bool line_phono_switch;
|
||||
bool digital_thru_switch;
|
||||
bool usb_streaming;
|
||||
u8 master_vol;
|
||||
u8 output_vol[6];
|
||||
u8 ovol_updated;
|
||||
u8 output_mute;
|
||||
s8 input_vol[2];
|
||||
u8 ivol_updated;
|
||||
};
|
||||
|
||||
int __devinit usb6fire_control_init(struct sfire_chip *chip);
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*
|
||||
* Author: Torsten Schenk <torsten.schenk@zoho.com>
|
||||
* Created: Jan 01, 2011
|
||||
* Version: 0.3.0
|
||||
* Copyright: (C) Torsten Schenk
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*
|
||||
* Author: Torsten Schenk <torsten.schenk@zoho.com>
|
||||
* Created: Jan 01, 2011
|
||||
* Version: 0.3.0
|
||||
* Copyright: (C) Torsten Schenk
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
*
|
||||
* Author: Torsten Schenk <torsten.schenk@zoho.com>
|
||||
* Created: Jan 01, 2011
|
||||
* Version: 0.3.0
|
||||
* Copyright: (C) Torsten Schenk
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
*
|
||||
* Author: Torsten Schenk <torsten.schenk@zoho.com>
|
||||
* Created: Jan 01, 2011
|
||||
* Version: 0.3.0
|
||||
* Copyright: (C) Torsten Schenk
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
*
|
||||
* Author: Torsten Schenk <torsten.schenk@zoho.com>
|
||||
* Created: Jan 01, 2011
|
||||
* Version: 0.3.0
|
||||
* Copyright: (C) Torsten Schenk
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
|
|
@ -106,6 +106,7 @@ config SND_USB_6FIRE
|
|||
select BITREVERSE
|
||||
select SND_RAWMIDI
|
||||
select SND_PCM
|
||||
select SND_VMASTER
|
||||
help
|
||||
Say Y here to include support for TerraTec 6fire DMX USB interface.
|
||||
|
||||
|
|
|
@ -695,6 +695,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
|
|||
struct snd_usb_substream *subs)
|
||||
{
|
||||
struct audioformat *fp;
|
||||
int *rate_list;
|
||||
int count = 0, needs_knot = 0;
|
||||
int err;
|
||||
|
||||
|
@ -708,7 +709,8 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
|
|||
if (!needs_knot)
|
||||
return 0;
|
||||
|
||||
subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL);
|
||||
subs->rate_list.list = rate_list =
|
||||
kmalloc(sizeof(int) * count, GFP_KERNEL);
|
||||
if (!subs->rate_list.list)
|
||||
return -ENOMEM;
|
||||
subs->rate_list.count = count;
|
||||
|
@ -717,7 +719,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime,
|
|||
list_for_each_entry(fp, &subs->fmt_list, list) {
|
||||
int i;
|
||||
for (i = 0; i < fp->nr_rates; i++)
|
||||
subs->rate_list.list[count++] = fp->rate_table[i];
|
||||
rate_list[count++] = fp->rate_table[i];
|
||||
}
|
||||
err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
&subs->rate_list);
|
||||
|
|
|
@ -80,7 +80,7 @@ static int usX2Y_urb_capt_retire(struct snd_usX2Y_substream *subs)
|
|||
cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset;
|
||||
if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
|
||||
snd_printk(KERN_ERR "active frame status %i. "
|
||||
"Most propably some hardware problem.\n",
|
||||
"Most probably some hardware problem.\n",
|
||||
urb->iso_frame_desc[i].status);
|
||||
return urb->iso_frame_desc[i].status;
|
||||
}
|
||||
|
@ -300,7 +300,7 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y,
|
|||
{
|
||||
snd_printk(KERN_ERR
|
||||
"Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n"
|
||||
"Most propably some urb of usb-frame %i is still missing.\n"
|
||||
"Most probably some urb of usb-frame %i is still missing.\n"
|
||||
"Cause could be too long delays in usb-hcd interrupt handling.\n",
|
||||
usb_get_current_frame_number(usX2Y->dev),
|
||||
subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out",
|
||||
|
|
|
@ -74,7 +74,7 @@ static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs)
|
|||
}
|
||||
for (i = 0; i < nr_of_packs(); i++) {
|
||||
if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
|
||||
snd_printk(KERN_ERR "activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status);
|
||||
snd_printk(KERN_ERR "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status);
|
||||
return urb->iso_frame_desc[i].status;
|
||||
}
|
||||
lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride;
|
||||
|
|
Loading…
Reference in New Issue