diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-03-18 13:22:33 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-03-18 13:22:33 -0400 |
commit | 44c76a960a62fcc46cbcaa0a22a34e666a729329 (patch) | |
tree | d3887c858f6adffb6714da3cdc0059f93588344c /sound | |
parent | dbf117cbb9c89991727d42e3161e68b868a1b6ae (diff) | |
parent | c6b76d1f02e2ab1109d8549877a3a24c6a2b4587 (diff) |
Merge branch 'topic/misc' into for-linus
Diffstat (limited to 'sound')
30 files changed, 606 insertions, 190 deletions
diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c index 762af68c8996..270790d384e2 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/onyx.c | |||
@@ -1132,15 +1132,4 @@ static struct i2c_driver onyx_driver = { | |||
1132 | .id_table = onyx_i2c_id, | 1132 | .id_table = onyx_i2c_id, |
1133 | }; | 1133 | }; |
1134 | 1134 | ||
1135 | static int __init onyx_init(void) | 1135 | module_i2c_driver(onyx_driver); |
1136 | { | ||
1137 | return i2c_add_driver(&onyx_driver); | ||
1138 | } | ||
1139 | |||
1140 | static void __exit onyx_exit(void) | ||
1141 | { | ||
1142 | i2c_del_driver(&onyx_driver); | ||
1143 | } | ||
1144 | |||
1145 | module_init(onyx_init); | ||
1146 | module_exit(onyx_exit); | ||
diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c index fd2188c3df2b..8e63d1f35ce1 100644 --- a/sound/aoa/codecs/tas.c +++ b/sound/aoa/codecs/tas.c | |||
@@ -1026,15 +1026,4 @@ static struct i2c_driver tas_driver = { | |||
1026 | .id_table = tas_i2c_id, | 1026 | .id_table = tas_i2c_id, |
1027 | }; | 1027 | }; |
1028 | 1028 | ||
1029 | static int __init tas_init(void) | 1029 | module_i2c_driver(tas_driver); |
1030 | { | ||
1031 | return i2c_add_driver(&tas_driver); | ||
1032 | } | ||
1033 | |||
1034 | static void __exit tas_exit(void) | ||
1035 | { | ||
1036 | i2c_del_driver(&tas_driver); | ||
1037 | } | ||
1038 | |||
1039 | module_init(tas_init); | ||
1040 | module_exit(tas_exit); | ||
diff --git a/sound/core/control.c b/sound/core/control.c index 819a5c579a39..2487a6bb1c54 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -1313,7 +1313,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, | |||
1313 | err = -EPERM; | 1313 | err = -EPERM; |
1314 | goto __kctl_end; | 1314 | goto __kctl_end; |
1315 | } | 1315 | } |
1316 | err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); | 1316 | err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); |
1317 | if (err > 0) { | 1317 | if (err > 0) { |
1318 | up_read(&card->controls_rwsem); | 1318 | up_read(&card->controls_rwsem); |
1319 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); | 1319 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); |
diff --git a/sound/core/init.c b/sound/core/init.c index 3ac49b1b7cb8..068cf08d3ffb 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -480,74 +480,104 @@ int snd_card_free(struct snd_card *card) | |||
480 | 480 | ||
481 | EXPORT_SYMBOL(snd_card_free); | 481 | EXPORT_SYMBOL(snd_card_free); |
482 | 482 | ||
483 | static void snd_card_set_id_no_lock(struct snd_card *card, const char *nid) | 483 | /* retrieve the last word of shortname or longname */ |
484 | static const char *retrieve_id_from_card_name(const char *name) | ||
484 | { | 485 | { |
485 | int i, len, idx_flag = 0, loops = SNDRV_CARDS; | 486 | const char *spos = name; |
486 | const char *spos, *src; | 487 | |
487 | char *id; | 488 | while (*name) { |
488 | 489 | if (isspace(*name) && isalnum(name[1])) | |
489 | if (nid == NULL) { | 490 | spos = name + 1; |
490 | id = card->shortname; | 491 | name++; |
491 | spos = src = id; | ||
492 | while (*id != '\0') { | ||
493 | if (*id == ' ') | ||
494 | spos = id + 1; | ||
495 | id++; | ||
496 | } | ||
497 | } else { | ||
498 | spos = src = nid; | ||
499 | } | 492 | } |
500 | id = card->id; | 493 | return spos; |
501 | while (*spos != '\0' && !isalnum(*spos)) | 494 | } |
502 | spos++; | 495 | |
503 | if (isdigit(*spos)) | 496 | /* return true if the given id string doesn't conflict any other card ids */ |
504 | *id++ = isalpha(src[0]) ? src[0] : 'D'; | 497 | static bool card_id_ok(struct snd_card *card, const char *id) |
505 | while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) { | 498 | { |
506 | if (isalnum(*spos)) | 499 | int i; |
507 | *id++ = *spos; | 500 | if (!snd_info_check_reserved_words(id)) |
508 | spos++; | 501 | return false; |
502 | for (i = 0; i < snd_ecards_limit; i++) { | ||
503 | if (snd_cards[i] && snd_cards[i] != card && | ||
504 | !strcmp(snd_cards[i]->id, id)) | ||
505 | return false; | ||
509 | } | 506 | } |
510 | *id = '\0'; | 507 | return true; |
508 | } | ||
511 | 509 | ||
512 | id = card->id; | 510 | /* copy to card->id only with valid letters from nid */ |
511 | static void copy_valid_id_string(struct snd_card *card, const char *src, | ||
512 | const char *nid) | ||
513 | { | ||
514 | char *id = card->id; | ||
515 | |||
516 | while (*nid && !isalnum(*nid)) | ||
517 | nid++; | ||
518 | if (isdigit(*nid)) | ||
519 | *id++ = isalpha(*src) ? *src : 'D'; | ||
520 | while (*nid && (size_t)(id - card->id) < sizeof(card->id) - 1) { | ||
521 | if (isalnum(*nid)) | ||
522 | *id++ = *nid; | ||
523 | nid++; | ||
524 | } | ||
525 | *id = 0; | ||
526 | } | ||
527 | |||
528 | /* Set card->id from the given string | ||
529 | * If the string conflicts with other ids, add a suffix to make it unique. | ||
530 | */ | ||
531 | static void snd_card_set_id_no_lock(struct snd_card *card, const char *src, | ||
532 | const char *nid) | ||
533 | { | ||
534 | int len, loops; | ||
535 | bool with_suffix; | ||
536 | bool is_default = false; | ||
537 | char *id; | ||
513 | 538 | ||
514 | if (*id == '\0') | 539 | copy_valid_id_string(card, src, nid); |
540 | id = card->id; | ||
541 | |||
542 | again: | ||
543 | /* use "Default" for obviously invalid strings | ||
544 | * ("card" conflicts with proc directories) | ||
545 | */ | ||
546 | if (!*id || !strncmp(id, "card", 4)) { | ||
515 | strcpy(id, "Default"); | 547 | strcpy(id, "Default"); |
548 | is_default = true; | ||
549 | } | ||
516 | 550 | ||
517 | while (1) { | 551 | with_suffix = false; |
518 | if (loops-- == 0) { | 552 | for (loops = 0; loops < SNDRV_CARDS; loops++) { |
519 | snd_printk(KERN_ERR "unable to set card id (%s)\n", id); | 553 | if (card_id_ok(card, id)) |
520 | strcpy(card->id, card->proc_root->name); | 554 | return; /* OK */ |
521 | return; | ||
522 | } | ||
523 | if (!snd_info_check_reserved_words(id)) | ||
524 | goto __change; | ||
525 | for (i = 0; i < snd_ecards_limit; i++) { | ||
526 | if (snd_cards[i] && !strcmp(snd_cards[i]->id, id)) | ||
527 | goto __change; | ||
528 | } | ||
529 | break; | ||
530 | 555 | ||
531 | __change: | ||
532 | len = strlen(id); | 556 | len = strlen(id); |
533 | if (idx_flag) { | 557 | if (!with_suffix) { |
534 | if (id[len-1] != '9') | 558 | /* add the "_X" suffix */ |
535 | id[len-1]++; | 559 | char *spos = id + len; |
536 | else | 560 | if (len > sizeof(card->id) - 3) |
537 | id[len-1] = 'A'; | 561 | spos = id + sizeof(card->id) - 3; |
538 | } else if ((size_t)len <= sizeof(card->id) - 3) { | 562 | strcpy(spos, "_1"); |
539 | strcat(id, "_1"); | 563 | with_suffix = true; |
540 | idx_flag++; | ||
541 | } else { | 564 | } else { |
542 | spos = id + len - 2; | 565 | /* modify the existing suffix */ |
543 | if ((size_t)len <= sizeof(card->id) - 2) | 566 | if (id[len - 1] != '9') |
544 | spos++; | 567 | id[len - 1]++; |
545 | *(char *)spos++ = '_'; | 568 | else |
546 | *(char *)spos++ = '1'; | 569 | id[len - 1] = 'A'; |
547 | *(char *)spos++ = '\0'; | ||
548 | idx_flag++; | ||
549 | } | 570 | } |
550 | } | 571 | } |
572 | /* fallback to the default id */ | ||
573 | if (!is_default) { | ||
574 | *id = 0; | ||
575 | goto again; | ||
576 | } | ||
577 | /* last resort... */ | ||
578 | snd_printk(KERN_ERR "unable to set card id (%s)\n", id); | ||
579 | if (card->proc_root->name) | ||
580 | strcpy(card->id, card->proc_root->name); | ||
551 | } | 581 | } |
552 | 582 | ||
553 | /** | 583 | /** |
@@ -564,7 +594,7 @@ void snd_card_set_id(struct snd_card *card, const char *nid) | |||
564 | if (card->id[0] != '\0') | 594 | if (card->id[0] != '\0') |
565 | return; | 595 | return; |
566 | mutex_lock(&snd_card_mutex); | 596 | mutex_lock(&snd_card_mutex); |
567 | snd_card_set_id_no_lock(card, nid); | 597 | snd_card_set_id_no_lock(card, nid, nid); |
568 | mutex_unlock(&snd_card_mutex); | 598 | mutex_unlock(&snd_card_mutex); |
569 | } | 599 | } |
570 | EXPORT_SYMBOL(snd_card_set_id); | 600 | EXPORT_SYMBOL(snd_card_set_id); |
@@ -596,22 +626,12 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr, | |||
596 | memcpy(buf1, buf, copy); | 626 | memcpy(buf1, buf, copy); |
597 | buf1[copy] = '\0'; | 627 | buf1[copy] = '\0'; |
598 | mutex_lock(&snd_card_mutex); | 628 | mutex_lock(&snd_card_mutex); |
599 | if (!snd_info_check_reserved_words(buf1)) { | 629 | if (!card_id_ok(NULL, buf1)) { |
600 | __exist: | ||
601 | mutex_unlock(&snd_card_mutex); | 630 | mutex_unlock(&snd_card_mutex); |
602 | return -EEXIST; | 631 | return -EEXIST; |
603 | } | 632 | } |
604 | for (idx = 0; idx < snd_ecards_limit; idx++) { | ||
605 | if (snd_cards[idx] && !strcmp(snd_cards[idx]->id, buf1)) { | ||
606 | if (card == snd_cards[idx]) | ||
607 | goto __ok; | ||
608 | else | ||
609 | goto __exist; | ||
610 | } | ||
611 | } | ||
612 | strcpy(card->id, buf1); | 633 | strcpy(card->id, buf1); |
613 | snd_info_card_id_change(card); | 634 | snd_info_card_id_change(card); |
614 | __ok: | ||
615 | mutex_unlock(&snd_card_mutex); | 635 | mutex_unlock(&snd_card_mutex); |
616 | 636 | ||
617 | return count; | 637 | return count; |
@@ -665,7 +685,18 @@ int snd_card_register(struct snd_card *card) | |||
665 | mutex_unlock(&snd_card_mutex); | 685 | mutex_unlock(&snd_card_mutex); |
666 | return 0; | 686 | return 0; |
667 | } | 687 | } |
668 | snd_card_set_id_no_lock(card, card->id[0] == '\0' ? NULL : card->id); | 688 | if (*card->id) { |
689 | /* make a unique id name from the given string */ | ||
690 | char tmpid[sizeof(card->id)]; | ||
691 | memcpy(tmpid, card->id, sizeof(card->id)); | ||
692 | snd_card_set_id_no_lock(card, tmpid, tmpid); | ||
693 | } else { | ||
694 | /* create an id from either shortname or longname */ | ||
695 | const char *src; | ||
696 | src = *card->shortname ? card->shortname : card->longname; | ||
697 | snd_card_set_id_no_lock(card, src, | ||
698 | retrieve_id_from_card_name(src)); | ||
699 | } | ||
669 | snd_cards[card->number] = card; | 700 | snd_cards[card->number] = card; |
670 | mutex_unlock(&snd_card_mutex); | 701 | mutex_unlock(&snd_card_mutex); |
671 | init_info_for_card(card); | 702 | init_info_for_card(card); |
diff --git a/sound/core/misc.c b/sound/core/misc.c index 465f0ce772cb..768167925409 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c | |||
@@ -72,7 +72,7 @@ void __snd_printk(unsigned int level, const char *path, int line, | |||
72 | char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV"; | 72 | char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV"; |
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | #ifdef CONFIG_SND_DEBUG | 75 | #ifdef CONFIG_SND_DEBUG |
76 | if (debug < level) | 76 | if (debug < level) |
77 | return; | 77 | return; |
78 | #endif | 78 | #endif |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 3420bd3da5d7..4d18941178e6 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -1029,7 +1029,8 @@ static int snd_interval_ratden(struct snd_interval *i, | |||
1029 | * | 1029 | * |
1030 | * Returns non-zero if the value is changed, zero if not changed. | 1030 | * Returns non-zero if the value is changed, zero if not changed. |
1031 | */ | 1031 | */ |
1032 | int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask) | 1032 | int snd_interval_list(struct snd_interval *i, unsigned int count, |
1033 | const unsigned int *list, unsigned int mask) | ||
1033 | { | 1034 | { |
1034 | unsigned int k; | 1035 | unsigned int k; |
1035 | struct snd_interval list_range; | 1036 | struct snd_interval list_range; |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 25ed9fe41b89..3fe99e644eb8 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -1586,12 +1586,18 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd) | |||
1586 | struct file *file; | 1586 | struct file *file; |
1587 | struct snd_pcm_file *pcm_file; | 1587 | struct snd_pcm_file *pcm_file; |
1588 | struct snd_pcm_substream *substream1; | 1588 | struct snd_pcm_substream *substream1; |
1589 | struct snd_pcm_group *group; | ||
1589 | 1590 | ||
1590 | file = snd_pcm_file_fd(fd); | 1591 | file = snd_pcm_file_fd(fd); |
1591 | if (!file) | 1592 | if (!file) |
1592 | return -EBADFD; | 1593 | return -EBADFD; |
1593 | pcm_file = file->private_data; | 1594 | pcm_file = file->private_data; |
1594 | substream1 = pcm_file->substream; | 1595 | substream1 = pcm_file->substream; |
1596 | group = kmalloc(sizeof(*group), GFP_KERNEL); | ||
1597 | if (!group) { | ||
1598 | res = -ENOMEM; | ||
1599 | goto _nolock; | ||
1600 | } | ||
1595 | down_write(&snd_pcm_link_rwsem); | 1601 | down_write(&snd_pcm_link_rwsem); |
1596 | write_lock_irq(&snd_pcm_link_rwlock); | 1602 | write_lock_irq(&snd_pcm_link_rwlock); |
1597 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || | 1603 | 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) | |||
1604 | goto _end; | 1610 | goto _end; |
1605 | } | 1611 | } |
1606 | if (!snd_pcm_stream_linked(substream)) { | 1612 | if (!snd_pcm_stream_linked(substream)) { |
1607 | substream->group = kmalloc(sizeof(struct snd_pcm_group), GFP_ATOMIC); | 1613 | substream->group = group; |
1608 | if (substream->group == NULL) { | ||
1609 | res = -ENOMEM; | ||
1610 | goto _end; | ||
1611 | } | ||
1612 | spin_lock_init(&substream->group->lock); | 1614 | spin_lock_init(&substream->group->lock); |
1613 | INIT_LIST_HEAD(&substream->group->substreams); | 1615 | INIT_LIST_HEAD(&substream->group->substreams); |
1614 | list_add_tail(&substream->link_list, &substream->group->substreams); | 1616 | 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) | |||
1620 | _end: | 1622 | _end: |
1621 | write_unlock_irq(&snd_pcm_link_rwlock); | 1623 | write_unlock_irq(&snd_pcm_link_rwlock); |
1622 | up_write(&snd_pcm_link_rwsem); | 1624 | up_write(&snd_pcm_link_rwsem); |
1625 | _nolock: | ||
1623 | fput(file); | 1626 | fput(file); |
1627 | if (res < 0) | ||
1628 | kfree(group); | ||
1624 | return res; | 1629 | return res; |
1625 | } | 1630 | } |
1626 | 1631 | ||
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h index bb938153a964..466a5c8e8354 100644 --- a/sound/pci/au88x0/au88x0.h +++ b/sound/pci/au88x0/au88x0.h | |||
@@ -26,7 +26,7 @@ | |||
26 | #include <sound/mpu401.h> | 26 | #include <sound/mpu401.h> |
27 | #include <sound/hwdep.h> | 27 | #include <sound/hwdep.h> |
28 | #include <sound/ac97_codec.h> | 28 | #include <sound/ac97_codec.h> |
29 | 29 | #include <sound/tlv.h> | |
30 | #endif | 30 | #endif |
31 | 31 | ||
32 | #ifndef CHIP_AU8820 | 32 | #ifndef CHIP_AU8820 |
@@ -107,6 +107,14 @@ | |||
107 | #define NR_WTPB 0x20 /* WT channels per each bank. */ | 107 | #define NR_WTPB 0x20 /* WT channels per each bank. */ |
108 | #define NR_PCM 0x10 | 108 | #define NR_PCM 0x10 |
109 | 109 | ||
110 | struct pcm_vol { | ||
111 | struct snd_kcontrol *kctl; | ||
112 | int active; | ||
113 | int dma; | ||
114 | int mixin[4]; | ||
115 | int vol[4]; | ||
116 | }; | ||
117 | |||
110 | /* Structs */ | 118 | /* Structs */ |
111 | typedef struct { | 119 | typedef struct { |
112 | //int this_08; /* Still unknown */ | 120 | //int this_08; /* Still unknown */ |
@@ -168,6 +176,7 @@ struct snd_vortex { | |||
168 | /* Xtalk canceler */ | 176 | /* Xtalk canceler */ |
169 | int xt_mode; /* 1: speakers, 0:headphones. */ | 177 | int xt_mode; /* 1: speakers, 0:headphones. */ |
170 | #endif | 178 | #endif |
179 | struct pcm_vol pcm_vol[NR_PCM]; | ||
171 | 180 | ||
172 | int isquad; /* cache of extended ID codec flag. */ | 181 | int isquad; /* cache of extended ID codec flag. */ |
173 | 182 | ||
@@ -239,7 +248,7 @@ static int vortex_alsafmt_aspfmt(int alsafmt); | |||
239 | /* Connection stuff. */ | 248 | /* Connection stuff. */ |
240 | static void vortex_connect_default(vortex_t * vortex, int en); | 249 | static void vortex_connect_default(vortex_t * vortex, int en); |
241 | static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, | 250 | static int vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, |
242 | int dir, int type); | 251 | int dir, int type, int subdev); |
243 | static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, | 252 | static char vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, |
244 | int restype); | 253 | int restype); |
245 | #ifndef CHIP_AU8810 | 254 | #ifndef CHIP_AU8810 |
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 6933a27a5d76..525f881f0409 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c | |||
@@ -2050,8 +2050,6 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype) | |||
2050 | } | 2050 | } |
2051 | 2051 | ||
2052 | /* Default Connections */ | 2052 | /* Default Connections */ |
2053 | static int | ||
2054 | vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type); | ||
2055 | 2053 | ||
2056 | static void vortex_connect_default(vortex_t * vortex, int en) | 2054 | static void vortex_connect_default(vortex_t * vortex, int en) |
2057 | { | 2055 | { |
@@ -2111,15 +2109,13 @@ static void vortex_connect_default(vortex_t * vortex, int en) | |||
2111 | Return: Return allocated DMA or same DMA passed as "dma" when dma >= 0. | 2109 | Return: Return allocated DMA or same DMA passed as "dma" when dma >= 0. |
2112 | */ | 2110 | */ |
2113 | static int | 2111 | static int |
2114 | vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type) | 2112 | vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir, |
2113 | int type, int subdev) | ||
2115 | { | 2114 | { |
2116 | stream_t *stream; | 2115 | stream_t *stream; |
2117 | int i, en; | 2116 | int i, en; |
2117 | struct pcm_vol *p; | ||
2118 | 2118 | ||
2119 | if ((nr_ch == 3) | ||
2120 | || ((dir == SNDRV_PCM_STREAM_CAPTURE) && (nr_ch > 2))) | ||
2121 | return -EBUSY; | ||
2122 | |||
2123 | if (dma >= 0) { | 2119 | if (dma >= 0) { |
2124 | en = 0; | 2120 | en = 0; |
2125 | vortex_adb_checkinout(vortex, | 2121 | vortex_adb_checkinout(vortex, |
@@ -2250,6 +2246,14 @@ vortex_adb_allocroute(vortex_t * vortex, int dma, int nr_ch, int dir, int type) | |||
2250 | MIX_DEFIGAIN); | 2246 | MIX_DEFIGAIN); |
2251 | #endif | 2247 | #endif |
2252 | } | 2248 | } |
2249 | if (stream->type == VORTEX_PCM_ADB && en) { | ||
2250 | p = &vortex->pcm_vol[subdev]; | ||
2251 | p->dma = dma; | ||
2252 | for (i = 0; i < nr_ch; i++) | ||
2253 | p->mixin[i] = mix[i]; | ||
2254 | for (i = 0; i < ch_top; i++) | ||
2255 | p->vol[i] = 0; | ||
2256 | } | ||
2253 | } | 2257 | } |
2254 | #ifndef CHIP_AU8820 | 2258 | #ifndef CHIP_AU8820 |
2255 | else { | 2259 | else { |
@@ -2473,7 +2477,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) | |||
2473 | hwread(vortex->mmio, VORTEX_IRQ_STAT); | 2477 | hwread(vortex->mmio, VORTEX_IRQ_STAT); |
2474 | handled = 1; | 2478 | handled = 1; |
2475 | } | 2479 | } |
2476 | if (source & IRQ_MIDI) { | 2480 | if ((source & IRQ_MIDI) && vortex->rmidi) { |
2477 | snd_mpu401_uart_interrupt(vortex->irq, | 2481 | snd_mpu401_uart_interrupt(vortex->irq, |
2478 | vortex->rmidi->private_data); | 2482 | vortex->rmidi->private_data); |
2479 | handled = 1; | 2483 | handled = 1; |
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index 0ef2f9712208..e59f120742a4 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c | |||
@@ -122,6 +122,18 @@ static struct snd_pcm_hw_constraint_list hw_constraints_au8830_channels = { | |||
122 | .mask = 0, | 122 | .mask = 0, |
123 | }; | 123 | }; |
124 | #endif | 124 | #endif |
125 | |||
126 | static void vortex_notify_pcm_vol_change(struct snd_card *card, | ||
127 | struct snd_kcontrol *kctl, int activate) | ||
128 | { | ||
129 | if (activate) | ||
130 | kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
131 | else | ||
132 | kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
133 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE | | ||
134 | SNDRV_CTL_EVENT_MASK_INFO, &(kctl->id)); | ||
135 | } | ||
136 | |||
125 | /* open callback */ | 137 | /* open callback */ |
126 | static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) | 138 | static int snd_vortex_pcm_open(struct snd_pcm_substream *substream) |
127 | { | 139 | { |
@@ -230,12 +242,14 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, | |||
230 | if (stream != NULL) | 242 | if (stream != NULL) |
231 | vortex_adb_allocroute(chip, stream->dma, | 243 | vortex_adb_allocroute(chip, stream->dma, |
232 | stream->nr_ch, stream->dir, | 244 | stream->nr_ch, stream->dir, |
233 | stream->type); | 245 | stream->type, |
246 | substream->number); | ||
234 | /* Alloc routes. */ | 247 | /* Alloc routes. */ |
235 | dma = | 248 | dma = |
236 | vortex_adb_allocroute(chip, -1, | 249 | vortex_adb_allocroute(chip, -1, |
237 | params_channels(hw_params), | 250 | params_channels(hw_params), |
238 | substream->stream, type); | 251 | substream->stream, type, |
252 | substream->number); | ||
239 | if (dma < 0) { | 253 | if (dma < 0) { |
240 | spin_unlock_irq(&chip->lock); | 254 | spin_unlock_irq(&chip->lock); |
241 | return dma; | 255 | return dma; |
@@ -246,6 +260,11 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream, | |||
246 | vortex_adbdma_setbuffers(chip, dma, | 260 | vortex_adbdma_setbuffers(chip, dma, |
247 | params_period_bytes(hw_params), | 261 | params_period_bytes(hw_params), |
248 | params_periods(hw_params)); | 262 | params_periods(hw_params)); |
263 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { | ||
264 | chip->pcm_vol[substream->number].active = 1; | ||
265 | vortex_notify_pcm_vol_change(chip->card, | ||
266 | chip->pcm_vol[substream->number].kctl, 1); | ||
267 | } | ||
249 | } | 268 | } |
250 | #ifndef CHIP_AU8810 | 269 | #ifndef CHIP_AU8810 |
251 | else { | 270 | else { |
@@ -275,10 +294,18 @@ static int snd_vortex_pcm_hw_free(struct snd_pcm_substream *substream) | |||
275 | spin_lock_irq(&chip->lock); | 294 | spin_lock_irq(&chip->lock); |
276 | // Delete audio routes. | 295 | // Delete audio routes. |
277 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { | 296 | if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) { |
278 | if (stream != NULL) | 297 | if (stream != NULL) { |
298 | if (VORTEX_PCM_TYPE(substream->pcm) == VORTEX_PCM_ADB) { | ||
299 | chip->pcm_vol[substream->number].active = 0; | ||
300 | vortex_notify_pcm_vol_change(chip->card, | ||
301 | chip->pcm_vol[substream->number].kctl, | ||
302 | 0); | ||
303 | } | ||
279 | vortex_adb_allocroute(chip, stream->dma, | 304 | vortex_adb_allocroute(chip, stream->dma, |
280 | stream->nr_ch, stream->dir, | 305 | stream->nr_ch, stream->dir, |
281 | stream->type); | 306 | stream->type, |
307 | substream->number); | ||
308 | } | ||
282 | } | 309 | } |
283 | #ifndef CHIP_AU8810 | 310 | #ifndef CHIP_AU8810 |
284 | else { | 311 | else { |
@@ -506,6 +533,83 @@ static struct snd_kcontrol_new snd_vortex_mixer_spdif[] __devinitdata = { | |||
506 | }, | 533 | }, |
507 | }; | 534 | }; |
508 | 535 | ||
536 | /* subdevice PCM Volume control */ | ||
537 | |||
538 | static int snd_vortex_pcm_vol_info(struct snd_kcontrol *kcontrol, | ||
539 | struct snd_ctl_elem_info *uinfo) | ||
540 | { | ||
541 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | ||
542 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
543 | uinfo->count = (VORTEX_IS_QUAD(vortex) ? 4 : 2); | ||
544 | uinfo->value.integer.min = -128; | ||
545 | uinfo->value.integer.max = 32; | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static int snd_vortex_pcm_vol_get(struct snd_kcontrol *kcontrol, | ||
550 | struct snd_ctl_elem_value *ucontrol) | ||
551 | { | ||
552 | int i; | ||
553 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | ||
554 | int subdev = kcontrol->id.subdevice; | ||
555 | struct pcm_vol *p = &vortex->pcm_vol[subdev]; | ||
556 | int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); | ||
557 | for (i = 0; i < max_chn; i++) | ||
558 | ucontrol->value.integer.value[i] = p->vol[i]; | ||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol, | ||
563 | struct snd_ctl_elem_value *ucontrol) | ||
564 | { | ||
565 | int i; | ||
566 | int changed = 0; | ||
567 | int mixin; | ||
568 | unsigned char vol; | ||
569 | vortex_t *vortex = snd_kcontrol_chip(kcontrol); | ||
570 | int subdev = kcontrol->id.subdevice; | ||
571 | struct pcm_vol *p = &vortex->pcm_vol[subdev]; | ||
572 | int max_chn = (VORTEX_IS_QUAD(vortex) ? 4 : 2); | ||
573 | for (i = 0; i < max_chn; i++) { | ||
574 | if (p->vol[i] != ucontrol->value.integer.value[i]) { | ||
575 | p->vol[i] = ucontrol->value.integer.value[i]; | ||
576 | if (p->active) { | ||
577 | switch (vortex->dma_adb[p->dma].nr_ch) { | ||
578 | case 1: | ||
579 | mixin = p->mixin[0]; | ||
580 | break; | ||
581 | case 2: | ||
582 | default: | ||
583 | mixin = p->mixin[(i < 2) ? i : (i - 2)]; | ||
584 | break; | ||
585 | case 4: | ||
586 | mixin = p->mixin[i]; | ||
587 | break; | ||
588 | }; | ||
589 | vol = p->vol[i]; | ||
590 | vortex_mix_setinputvolumebyte(vortex, | ||
591 | vortex->mixplayb[i], mixin, vol); | ||
592 | } | ||
593 | changed = 1; | ||
594 | } | ||
595 | } | ||
596 | return changed; | ||
597 | } | ||
598 | |||
599 | static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400); | ||
600 | |||
601 | static struct snd_kcontrol_new snd_vortex_pcm_vol __devinitdata = { | ||
602 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
603 | .name = "PCM Playback Volume", | ||
604 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
605 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | ||
606 | SNDRV_CTL_ELEM_ACCESS_INACTIVE, | ||
607 | .info = snd_vortex_pcm_vol_info, | ||
608 | .get = snd_vortex_pcm_vol_get, | ||
609 | .put = snd_vortex_pcm_vol_put, | ||
610 | .tlv = { .p = vortex_pcm_vol_db_scale }, | ||
611 | }; | ||
612 | |||
509 | /* create a pcm device */ | 613 | /* create a pcm device */ |
510 | static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) | 614 | static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) |
511 | { | 615 | { |
@@ -555,5 +659,20 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) | |||
555 | return err; | 659 | return err; |
556 | } | 660 | } |
557 | } | 661 | } |
662 | if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_ADB) { | ||
663 | for (i = 0; i < NR_PCM; i++) { | ||
664 | chip->pcm_vol[i].active = 0; | ||
665 | chip->pcm_vol[i].dma = -1; | ||
666 | kctl = snd_ctl_new1(&snd_vortex_pcm_vol, chip); | ||
667 | if (!kctl) | ||
668 | return -ENOMEM; | ||
669 | chip->pcm_vol[i].kctl = kctl; | ||
670 | kctl->id.device = 0; | ||
671 | kctl->id.subdevice = i; | ||
672 | err = snd_ctl_add(chip->card, kctl); | ||
673 | if (err < 0) | ||
674 | return err; | ||
675 | } | ||
676 | } | ||
558 | return 0; | 677 | return 0; |
559 | } | 678 | } |
diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c index b78f3fc3c33c..6109490b83e8 100644 --- a/sound/pci/ctxfi/ctvmem.c +++ b/sound/pci/ctxfi/ctvmem.c | |||
@@ -36,7 +36,7 @@ get_vm_block(struct ct_vm *vm, unsigned int size) | |||
36 | 36 | ||
37 | size = CT_PAGE_ALIGN(size); | 37 | size = CT_PAGE_ALIGN(size); |
38 | if (size > vm->size) { | 38 | if (size > vm->size) { |
39 | printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural " | 39 | printk(KERN_ERR "ctxfi: Fail! No sufficient device virtual " |
40 | "memory space available!\n"); | 40 | "memory space available!\n"); |
41 | return NULL; | 41 | return NULL; |
42 | } | 42 | } |
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 92362973764d..812d10e43ae0 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
@@ -1013,6 +1013,25 @@ static int set_rate_constraints(struct snd_ice1712 *ice, | |||
1013 | ice->hw_rates); | 1013 | ice->hw_rates); |
1014 | } | 1014 | } |
1015 | 1015 | ||
1016 | /* if the card has the internal rate locked (is_pro_locked), limit runtime | ||
1017 | hw rates to the current internal rate only. | ||
1018 | */ | ||
1019 | static void constrain_rate_if_locked(struct snd_pcm_substream *substream) | ||
1020 | { | ||
1021 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); | ||
1022 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1023 | unsigned int rate; | ||
1024 | if (is_pro_rate_locked(ice)) { | ||
1025 | rate = ice->get_rate(ice); | ||
1026 | if (rate >= runtime->hw.rate_min | ||
1027 | && rate <= runtime->hw.rate_max) { | ||
1028 | runtime->hw.rate_min = rate; | ||
1029 | runtime->hw.rate_max = rate; | ||
1030 | } | ||
1031 | } | ||
1032 | } | ||
1033 | |||
1034 | |||
1016 | /* multi-channel playback needs alignment 8x32bit regardless of the channels | 1035 | /* multi-channel playback needs alignment 8x32bit regardless of the channels |
1017 | * actually used | 1036 | * actually used |
1018 | */ | 1037 | */ |
@@ -1046,6 +1065,7 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream) | |||
1046 | VT1724_BUFFER_ALIGN); | 1065 | VT1724_BUFFER_ALIGN); |
1047 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | 1066 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, |
1048 | VT1724_BUFFER_ALIGN); | 1067 | VT1724_BUFFER_ALIGN); |
1068 | constrain_rate_if_locked(substream); | ||
1049 | if (ice->pro_open) | 1069 | if (ice->pro_open) |
1050 | ice->pro_open(ice, substream); | 1070 | ice->pro_open(ice, substream); |
1051 | return 0; | 1071 | return 0; |
@@ -1066,6 +1086,7 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream) | |||
1066 | VT1724_BUFFER_ALIGN); | 1086 | VT1724_BUFFER_ALIGN); |
1067 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | 1087 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, |
1068 | VT1724_BUFFER_ALIGN); | 1088 | VT1724_BUFFER_ALIGN); |
1089 | constrain_rate_if_locked(substream); | ||
1069 | if (ice->pro_open) | 1090 | if (ice->pro_open) |
1070 | ice->pro_open(ice, substream); | 1091 | ice->pro_open(ice, substream); |
1071 | return 0; | 1092 | return 0; |
@@ -1215,6 +1236,7 @@ static int snd_vt1724_playback_spdif_open(struct snd_pcm_substream *substream) | |||
1215 | VT1724_BUFFER_ALIGN); | 1236 | VT1724_BUFFER_ALIGN); |
1216 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | 1237 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, |
1217 | VT1724_BUFFER_ALIGN); | 1238 | VT1724_BUFFER_ALIGN); |
1239 | constrain_rate_if_locked(substream); | ||
1218 | if (ice->spdif.ops.open) | 1240 | if (ice->spdif.ops.open) |
1219 | ice->spdif.ops.open(ice, substream); | 1241 | ice->spdif.ops.open(ice, substream); |
1220 | return 0; | 1242 | return 0; |
@@ -1251,6 +1273,7 @@ static int snd_vt1724_capture_spdif_open(struct snd_pcm_substream *substream) | |||
1251 | VT1724_BUFFER_ALIGN); | 1273 | VT1724_BUFFER_ALIGN); |
1252 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | 1274 | snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, |
1253 | VT1724_BUFFER_ALIGN); | 1275 | VT1724_BUFFER_ALIGN); |
1276 | constrain_rate_if_locked(substream); | ||
1254 | if (ice->spdif.ops.open) | 1277 | if (ice->spdif.ops.open) |
1255 | ice->spdif.ops.open(ice, substream); | 1278 | ice->spdif.ops.open(ice, substream); |
1256 | return 0; | 1279 | return 0; |
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 12a9a2b03387..a8159b81e9c4 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c | |||
@@ -2317,6 +2317,10 @@ int snd_ymfpci_suspend(struct pci_dev *pci, pm_message_t state) | |||
2317 | for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++) | 2317 | for (i = 0; i < YDSXGR_NUM_SAVED_REGS; i++) |
2318 | chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]); | 2318 | chip->saved_regs[i] = snd_ymfpci_readl(chip, saved_regs_index[i]); |
2319 | chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE); | 2319 | chip->saved_ydsxgr_mode = snd_ymfpci_readl(chip, YDSXGR_MODE); |
2320 | pci_read_config_word(chip->pci, PCIR_DSXG_LEGACY, | ||
2321 | &chip->saved_dsxg_legacy); | ||
2322 | pci_read_config_word(chip->pci, PCIR_DSXG_ELEGACY, | ||
2323 | &chip->saved_dsxg_elegacy); | ||
2320 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); | 2324 | snd_ymfpci_writel(chip, YDSXGR_NATIVEDACOUTVOL, 0); |
2321 | snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0); | 2325 | snd_ymfpci_writel(chip, YDSXGR_BUF441OUTVOL, 0); |
2322 | snd_ymfpci_disable_dsp(chip); | 2326 | snd_ymfpci_disable_dsp(chip); |
@@ -2351,6 +2355,11 @@ int snd_ymfpci_resume(struct pci_dev *pci) | |||
2351 | 2355 | ||
2352 | snd_ac97_resume(chip->ac97); | 2356 | snd_ac97_resume(chip->ac97); |
2353 | 2357 | ||
2358 | pci_write_config_word(chip->pci, PCIR_DSXG_LEGACY, | ||
2359 | chip->saved_dsxg_legacy); | ||
2360 | pci_write_config_word(chip->pci, PCIR_DSXG_ELEGACY, | ||
2361 | chip->saved_dsxg_elegacy); | ||
2362 | |||
2354 | /* start hw again */ | 2363 | /* start hw again */ |
2355 | if (chip->start_count > 0) { | 2364 | if (chip->start_count > 0) { |
2356 | spin_lock_irq(&chip->reg_lock); | 2365 | spin_lock_irq(&chip->reg_lock); |
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 4dd051bdf4fd..c6500d00053b 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c | |||
@@ -1112,17 +1112,7 @@ static struct spi_driver at73c213_driver = { | |||
1112 | .remove = __devexit_p(snd_at73c213_remove), | 1112 | .remove = __devexit_p(snd_at73c213_remove), |
1113 | }; | 1113 | }; |
1114 | 1114 | ||
1115 | static int __init at73c213_init(void) | 1115 | module_spi_driver(at73c213_driver); |
1116 | { | ||
1117 | return spi_register_driver(&at73c213_driver); | ||
1118 | } | ||
1119 | module_init(at73c213_init); | ||
1120 | |||
1121 | static void __exit at73c213_exit(void) | ||
1122 | { | ||
1123 | spi_unregister_driver(&at73c213_driver); | ||
1124 | } | ||
1125 | module_exit(at73c213_exit); | ||
1126 | 1116 | ||
1127 | MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>"); | 1117 | MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>"); |
1128 | MODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC"); | 1118 | MODULE_DESCRIPTION("Sound driver for AT73C213 with Atmel SSC"); |
diff --git a/sound/usb/6fire/chip.c b/sound/usb/6fire/chip.c index 8af92e3e9c18..fc8cc823e438 100644 --- a/sound/usb/6fire/chip.c +++ b/sound/usb/6fire/chip.c | |||
@@ -5,7 +5,6 @@ | |||
5 | * | 5 | * |
6 | * Author: Torsten Schenk <torsten.schenk@zoho.com> | 6 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
7 | * Created: Jan 01, 2011 | 7 | * Created: Jan 01, 2011 |
8 | * Version: 0.3.0 | ||
9 | * Copyright: (C) Torsten Schenk | 8 | * Copyright: (C) Torsten Schenk |
10 | * | 9 | * |
11 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
@@ -29,7 +28,7 @@ | |||
29 | #include <sound/initval.h> | 28 | #include <sound/initval.h> |
30 | 29 | ||
31 | MODULE_AUTHOR("Torsten Schenk <torsten.schenk@zoho.com>"); | 30 | MODULE_AUTHOR("Torsten Schenk <torsten.schenk@zoho.com>"); |
32 | MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver, version 0.3.0"); | 31 | MODULE_DESCRIPTION("TerraTec DMX 6Fire USB audio driver"); |
33 | MODULE_LICENSE("GPL v2"); | 32 | MODULE_LICENSE("GPL v2"); |
34 | MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}"); | 33 | MODULE_SUPPORTED_DEVICE("{{TerraTec, DMX 6Fire USB}}"); |
35 | 34 | ||
diff --git a/sound/usb/6fire/chip.h b/sound/usb/6fire/chip.h index d11e5cb520f0..bde02d105a51 100644 --- a/sound/usb/6fire/chip.h +++ b/sound/usb/6fire/chip.h | |||
@@ -3,7 +3,6 @@ | |||
3 | * | 3 | * |
4 | * Author: Torsten Schenk <torsten.schenk@zoho.com> | 4 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
5 | * Created: Jan 01, 2011 | 5 | * Created: Jan 01, 2011 |
6 | * Version: 0.3.0 | ||
7 | * Copyright: (C) Torsten Schenk | 6 | * Copyright: (C) Torsten Schenk |
8 | * | 7 | * |
9 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c index c994daa57af2..6c3d531a250e 100644 --- a/sound/usb/6fire/comm.c +++ b/sound/usb/6fire/comm.c | |||
@@ -5,7 +5,6 @@ | |||
5 | * | 5 | * |
6 | * Author: Torsten Schenk <torsten.schenk@zoho.com> | 6 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
7 | * Created: Jan 01, 2011 | 7 | * Created: Jan 01, 2011 |
8 | * Version: 0.3.0 | ||
9 | * Copyright: (C) Torsten Schenk | 8 | * Copyright: (C) Torsten Schenk |
10 | * | 9 | * |
11 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/usb/6fire/comm.h b/sound/usb/6fire/comm.h index edc5dc84b888..d2af0a5ddcf3 100644 --- a/sound/usb/6fire/comm.h +++ b/sound/usb/6fire/comm.h | |||
@@ -3,7 +3,6 @@ | |||
3 | * | 3 | * |
4 | * Author: Torsten Schenk <torsten.schenk@zoho.com> | 4 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
5 | * Created: Jan 01, 2011 | 5 | * Created: Jan 01, 2011 |
6 | * Version: 0.3.0 | ||
7 | * Copyright: (C) Torsten Schenk | 6 | * Copyright: (C) Torsten Schenk |
8 | * | 7 | * |
9 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/usb/6fire/common.h b/sound/usb/6fire/common.h index 7dbeb4a37831..b6eb03ed1c2c 100644 --- a/sound/usb/6fire/common.h +++ b/sound/usb/6fire/common.h | |||
@@ -3,7 +3,6 @@ | |||
3 | * | 3 | * |
4 | * Author: Torsten Schenk <torsten.schenk@zoho.com> | 4 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
5 | * Created: Jan 01, 2011 | 5 | * Created: Jan 01, 2011 |
6 | * Version: 0.3.0 | ||
7 | * Copyright: (C) Torsten Schenk | 6 | * Copyright: (C) Torsten Schenk |
8 | * | 7 | * |
9 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c index ac828eff1a63..07ed914d5e71 100644 --- a/sound/usb/6fire/control.c +++ b/sound/usb/6fire/control.c | |||
@@ -5,9 +5,12 @@ | |||
5 | * | 5 | * |
6 | * Author: Torsten Schenk <torsten.schenk@zoho.com> | 6 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
7 | * Created: Jan 01, 2011 | 7 | * Created: Jan 01, 2011 |
8 | * Version: 0.3.0 | ||
9 | * Copyright: (C) Torsten Schenk | 8 | * Copyright: (C) Torsten Schenk |
10 | * | 9 | * |
10 | * Thanks to: | ||
11 | * - Holger Ruckdeschel: he found out how to control individual channel | ||
12 | * volumes and introduced mute switch | ||
13 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | 14 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by | 15 | * it under the terms of the GNU General Public License as published by |
13 | * the Free Software Foundation; either version 2 of the License, or | 16 | * the Free Software Foundation; either version 2 of the License, or |
@@ -16,6 +19,7 @@ | |||
16 | 19 | ||
17 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
18 | #include <sound/control.h> | 21 | #include <sound/control.h> |
22 | #include <sound/tlv.h> | ||
19 | 23 | ||
20 | #include "control.h" | 24 | #include "control.h" |
21 | #include "comm.h" | 25 | #include "comm.h" |
@@ -25,26 +29,6 @@ static char *opt_coax_texts[2] = { "Optical", "Coax" }; | |||
25 | static char *line_phono_texts[2] = { "Line", "Phono" }; | 29 | static char *line_phono_texts[2] = { "Line", "Phono" }; |
26 | 30 | ||
27 | /* | 31 | /* |
28 | * calculated with $value\[i\] = 128 \cdot sqrt[3]{\frac{i}{128}}$ | ||
29 | * this is done because the linear values cause rapid degredation | ||
30 | * of volume in the uppermost region. | ||
31 | */ | ||
32 | static const u8 log_volume_table[128] = { | ||
33 | 0x00, 0x19, 0x20, 0x24, 0x28, 0x2b, 0x2e, 0x30, 0x32, 0x34, | ||
34 | 0x36, 0x38, 0x3a, 0x3b, 0x3d, 0x3e, 0x40, 0x41, 0x42, 0x43, | ||
35 | 0x44, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, | ||
36 | 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x53, 0x54, 0x55, 0x56, | ||
37 | 0x56, 0x57, 0x58, 0x58, 0x59, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, | ||
38 | 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, | ||
39 | 0x63, 0x63, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x68, | ||
40 | 0x68, 0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, | ||
41 | 0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, | ||
42 | 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, | ||
43 | 0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, | ||
44 | 0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, | ||
45 | 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f }; | ||
46 | |||
47 | /* | ||
48 | * data that needs to be sent to device. sets up card internal stuff. | 32 | * data that needs to be sent to device. sets up card internal stuff. |
49 | * values dumped from windows driver and filtered by trial'n'error. | 33 | * values dumped from windows driver and filtered by trial'n'error. |
50 | */ | 34 | */ |
@@ -59,7 +43,7 @@ init_data[] = { | |||
59 | { 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 }, | 43 | { 0x22, 0x03, 0x00 }, { 0x20, 0x03, 0x08 }, { 0x22, 0x04, 0x00 }, |
60 | { 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 }, | 44 | { 0x20, 0x04, 0x08 }, { 0x22, 0x05, 0x01 }, { 0x20, 0x05, 0x08 }, |
61 | { 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 }, | 45 | { 0x22, 0x04, 0x01 }, { 0x12, 0x04, 0x00 }, { 0x12, 0x05, 0x00 }, |
62 | { 0x12, 0x0d, 0x78 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, | 46 | { 0x12, 0x0d, 0x38 }, { 0x12, 0x21, 0x82 }, { 0x12, 0x22, 0x80 }, |
63 | { 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 }, | 47 | { 0x12, 0x23, 0x00 }, { 0x12, 0x06, 0x02 }, { 0x12, 0x03, 0x00 }, |
64 | { 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 }, | 48 | { 0x12, 0x02, 0x00 }, { 0x22, 0x03, 0x01 }, |
65 | { 0 } /* TERMINATING ENTRY */ | 49 | { 0 } /* TERMINATING ENTRY */ |
@@ -70,20 +54,47 @@ static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 }; | |||
70 | static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; | 54 | static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01}; |
71 | static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; | 55 | static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00}; |
72 | 56 | ||
57 | static DECLARE_TLV_DB_MINMAX(tlv_output, -9000, 0); | ||
58 | static DECLARE_TLV_DB_MINMAX(tlv_input, -1500, 1500); | ||
59 | |||
73 | enum { | 60 | enum { |
74 | DIGITAL_THRU_ONLY_SAMPLERATE = 3 | 61 | DIGITAL_THRU_ONLY_SAMPLERATE = 3 |
75 | }; | 62 | }; |
76 | 63 | ||
77 | static void usb6fire_control_master_vol_update(struct control_runtime *rt) | 64 | static void usb6fire_control_output_vol_update(struct control_runtime *rt) |
78 | { | 65 | { |
79 | struct comm_runtime *comm_rt = rt->chip->comm; | 66 | struct comm_runtime *comm_rt = rt->chip->comm; |
80 | if (comm_rt) { | 67 | int i; |
81 | /* set volume */ | 68 | |
82 | comm_rt->write8(comm_rt, 0x12, 0x0f, 0x7f - | 69 | if (comm_rt) |
83 | log_volume_table[rt->master_vol]); | 70 | for (i = 0; i < 6; i++) |
84 | /* unmute */ | 71 | if (!(rt->ovol_updated & (1 << i))) { |
85 | comm_rt->write8(comm_rt, 0x12, 0x0e, 0x00); | 72 | comm_rt->write8(comm_rt, 0x12, 0x0f + i, |
86 | } | 73 | 180 - rt->output_vol[i]); |
74 | rt->ovol_updated |= 1 << i; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | static void usb6fire_control_output_mute_update(struct control_runtime *rt) | ||
79 | { | ||
80 | struct comm_runtime *comm_rt = rt->chip->comm; | ||
81 | |||
82 | if (comm_rt) | ||
83 | comm_rt->write8(comm_rt, 0x12, 0x0e, ~rt->output_mute); | ||
84 | } | ||
85 | |||
86 | static void usb6fire_control_input_vol_update(struct control_runtime *rt) | ||
87 | { | ||
88 | struct comm_runtime *comm_rt = rt->chip->comm; | ||
89 | int i; | ||
90 | |||
91 | if (comm_rt) | ||
92 | for (i = 0; i < 2; i++) | ||
93 | if (!(rt->ivol_updated & (1 << i))) { | ||
94 | comm_rt->write8(comm_rt, 0x12, 0x1c + i, | ||
95 | rt->input_vol[i] & 0x3f); | ||
96 | rt->ivol_updated |= 1 << i; | ||
97 | } | ||
87 | } | 98 | } |
88 | 99 | ||
89 | static void usb6fire_control_line_phono_update(struct control_runtime *rt) | 100 | 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) | |||
165 | return -EINVAL; | 176 | return -EINVAL; |
166 | } | 177 | } |
167 | 178 | ||
168 | static int usb6fire_control_master_vol_info(struct snd_kcontrol *kcontrol, | 179 | static int usb6fire_control_output_vol_info(struct snd_kcontrol *kcontrol, |
169 | struct snd_ctl_elem_info *uinfo) | 180 | struct snd_ctl_elem_info *uinfo) |
170 | { | 181 | { |
171 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 182 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
172 | uinfo->count = 1; | 183 | uinfo->count = 2; |
173 | uinfo->value.integer.min = 0; | 184 | uinfo->value.integer.min = 0; |
174 | uinfo->value.integer.max = 127; | 185 | uinfo->value.integer.max = 180; |
175 | return 0; | 186 | return 0; |
176 | } | 187 | } |
177 | 188 | ||
178 | static int usb6fire_control_master_vol_put(struct snd_kcontrol *kcontrol, | 189 | static int usb6fire_control_output_vol_put(struct snd_kcontrol *kcontrol, |
179 | struct snd_ctl_elem_value *ucontrol) | 190 | struct snd_ctl_elem_value *ucontrol) |
180 | { | 191 | { |
181 | struct control_runtime *rt = snd_kcontrol_chip(kcontrol); | 192 | struct control_runtime *rt = snd_kcontrol_chip(kcontrol); |
193 | unsigned int ch = kcontrol->private_value; | ||
182 | int changed = 0; | 194 | int changed = 0; |
183 | if (rt->master_vol != ucontrol->value.integer.value[0]) { | 195 | |
184 | rt->master_vol = ucontrol->value.integer.value[0]; | 196 | if (ch > 4) { |
185 | usb6fire_control_master_vol_update(rt); | 197 | snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); |
198 | return -EINVAL; | ||
199 | } | ||
200 | |||
201 | if (rt->output_vol[ch] != ucontrol->value.integer.value[0]) { | ||
202 | rt->output_vol[ch] = ucontrol->value.integer.value[0]; | ||
203 | rt->ovol_updated &= ~(1 << ch); | ||
186 | changed = 1; | 204 | changed = 1; |
187 | } | 205 | } |
206 | if (rt->output_vol[ch + 1] != ucontrol->value.integer.value[1]) { | ||
207 | rt->output_vol[ch + 1] = ucontrol->value.integer.value[1]; | ||
208 | rt->ovol_updated &= ~(2 << ch); | ||
209 | changed = 1; | ||
210 | } | ||
211 | |||
212 | if (changed) | ||
213 | usb6fire_control_output_vol_update(rt); | ||
214 | |||
188 | return changed; | 215 | return changed; |
189 | } | 216 | } |
190 | 217 | ||
191 | static int usb6fire_control_master_vol_get(struct snd_kcontrol *kcontrol, | 218 | static int usb6fire_control_output_vol_get(struct snd_kcontrol *kcontrol, |
192 | struct snd_ctl_elem_value *ucontrol) | 219 | struct snd_ctl_elem_value *ucontrol) |
193 | { | 220 | { |
194 | struct control_runtime *rt = snd_kcontrol_chip(kcontrol); | 221 | struct control_runtime *rt = snd_kcontrol_chip(kcontrol); |
195 | ucontrol->value.integer.value[0] = rt->master_vol; | 222 | unsigned int ch = kcontrol->private_value; |
223 | |||
224 | if (ch > 4) { | ||
225 | snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | |||
229 | ucontrol->value.integer.value[0] = rt->output_vol[ch]; | ||
230 | ucontrol->value.integer.value[1] = rt->output_vol[ch + 1]; | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int usb6fire_control_output_mute_put(struct snd_kcontrol *kcontrol, | ||
235 | struct snd_ctl_elem_value *ucontrol) | ||
236 | { | ||
237 | struct control_runtime *rt = snd_kcontrol_chip(kcontrol); | ||
238 | unsigned int ch = kcontrol->private_value; | ||
239 | u8 old = rt->output_mute; | ||
240 | u8 value = 0; | ||
241 | |||
242 | if (ch > 4) { | ||
243 | snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); | ||
244 | return -EINVAL; | ||
245 | } | ||
246 | |||
247 | rt->output_mute &= ~(3 << ch); | ||
248 | if (ucontrol->value.integer.value[0]) | ||
249 | value |= 1; | ||
250 | if (ucontrol->value.integer.value[1]) | ||
251 | value |= 2; | ||
252 | rt->output_mute |= value << ch; | ||
253 | |||
254 | if (rt->output_mute != old) | ||
255 | usb6fire_control_output_mute_update(rt); | ||
256 | |||
257 | return rt->output_mute != old; | ||
258 | } | ||
259 | |||
260 | static int usb6fire_control_output_mute_get(struct snd_kcontrol *kcontrol, | ||
261 | struct snd_ctl_elem_value *ucontrol) | ||
262 | { | ||
263 | struct control_runtime *rt = snd_kcontrol_chip(kcontrol); | ||
264 | unsigned int ch = kcontrol->private_value; | ||
265 | u8 value = rt->output_mute >> ch; | ||
266 | |||
267 | if (ch > 4) { | ||
268 | snd_printk(KERN_ERR PREFIX "Invalid channel in volume control."); | ||
269 | return -EINVAL; | ||
270 | } | ||
271 | |||
272 | ucontrol->value.integer.value[0] = 1 & value; | ||
273 | value >>= 1; | ||
274 | ucontrol->value.integer.value[1] = 1 & value; | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static int usb6fire_control_input_vol_info(struct snd_kcontrol *kcontrol, | ||
280 | struct snd_ctl_elem_info *uinfo) | ||
281 | { | ||
282 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
283 | uinfo->count = 2; | ||
284 | uinfo->value.integer.min = 0; | ||
285 | uinfo->value.integer.max = 30; | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static int usb6fire_control_input_vol_put(struct snd_kcontrol *kcontrol, | ||
290 | struct snd_ctl_elem_value *ucontrol) | ||
291 | { | ||
292 | struct control_runtime *rt = snd_kcontrol_chip(kcontrol); | ||
293 | int changed = 0; | ||
294 | |||
295 | if (rt->input_vol[0] != ucontrol->value.integer.value[0]) { | ||
296 | rt->input_vol[0] = ucontrol->value.integer.value[0] - 15; | ||
297 | rt->ivol_updated &= ~(1 << 0); | ||
298 | changed = 1; | ||
299 | } | ||
300 | if (rt->input_vol[1] != ucontrol->value.integer.value[1]) { | ||
301 | rt->input_vol[1] = ucontrol->value.integer.value[1] - 15; | ||
302 | rt->ivol_updated &= ~(1 << 1); | ||
303 | changed = 1; | ||
304 | } | ||
305 | |||
306 | if (changed) | ||
307 | usb6fire_control_input_vol_update(rt); | ||
308 | |||
309 | return changed; | ||
310 | } | ||
311 | |||
312 | static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol, | ||
313 | struct snd_ctl_elem_value *ucontrol) | ||
314 | { | ||
315 | struct control_runtime *rt = snd_kcontrol_chip(kcontrol); | ||
316 | |||
317 | ucontrol->value.integer.value[0] = rt->input_vol[0] + 15; | ||
318 | ucontrol->value.integer.value[1] = rt->input_vol[1] + 15; | ||
319 | |||
196 | return 0; | 320 | return 0; |
197 | } | 321 | } |
198 | 322 | ||
@@ -287,18 +411,83 @@ static int usb6fire_control_digital_thru_get(struct snd_kcontrol *kcontrol, | |||
287 | return 0; | 411 | return 0; |
288 | } | 412 | } |
289 | 413 | ||
290 | static struct __devinitdata snd_kcontrol_new elements[] = { | 414 | static struct __devinitdata snd_kcontrol_new vol_elements[] = { |
291 | { | 415 | { |
292 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 416 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
293 | .name = "Master Playback Volume", | 417 | .name = "Analog Playback Volume", |
294 | .index = 0, | 418 | .index = 0, |
419 | .private_value = 0, | ||
420 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
421 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
422 | .info = usb6fire_control_output_vol_info, | ||
423 | .get = usb6fire_control_output_vol_get, | ||
424 | .put = usb6fire_control_output_vol_put, | ||
425 | .tlv = { .p = tlv_output } | ||
426 | }, | ||
427 | { | ||
428 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
429 | .name = "Analog Playback Volume", | ||
430 | .index = 1, | ||
431 | .private_value = 2, | ||
432 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
433 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
434 | .info = usb6fire_control_output_vol_info, | ||
435 | .get = usb6fire_control_output_vol_get, | ||
436 | .put = usb6fire_control_output_vol_put, | ||
437 | .tlv = { .p = tlv_output } | ||
438 | }, | ||
439 | { | ||
440 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
441 | .name = "Analog Playback Volume", | ||
442 | .index = 2, | ||
443 | .private_value = 4, | ||
444 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
445 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
446 | .info = usb6fire_control_output_vol_info, | ||
447 | .get = usb6fire_control_output_vol_get, | ||
448 | .put = usb6fire_control_output_vol_put, | ||
449 | .tlv = { .p = tlv_output } | ||
450 | }, | ||
451 | {} | ||
452 | }; | ||
453 | |||
454 | static struct __devinitdata snd_kcontrol_new mute_elements[] = { | ||
455 | { | ||
456 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
457 | .name = "Analog Playback Switch", | ||
458 | .index = 0, | ||
459 | .private_value = 0, | ||
460 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
461 | .info = snd_ctl_boolean_stereo_info, | ||
462 | .get = usb6fire_control_output_mute_get, | ||
463 | .put = usb6fire_control_output_mute_put, | ||
464 | }, | ||
465 | { | ||
466 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
467 | .name = "Analog Playback Switch", | ||
468 | .index = 1, | ||
469 | .private_value = 2, | ||
295 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | 470 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
296 | .info = usb6fire_control_master_vol_info, | 471 | .info = snd_ctl_boolean_stereo_info, |
297 | .get = usb6fire_control_master_vol_get, | 472 | .get = usb6fire_control_output_mute_get, |
298 | .put = usb6fire_control_master_vol_put | 473 | .put = usb6fire_control_output_mute_put, |
299 | }, | 474 | }, |
300 | { | 475 | { |
301 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 476 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
477 | .name = "Analog Playback Switch", | ||
478 | .index = 2, | ||
479 | .private_value = 4, | ||
480 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
481 | .info = snd_ctl_boolean_stereo_info, | ||
482 | .get = usb6fire_control_output_mute_get, | ||
483 | .put = usb6fire_control_output_mute_put, | ||
484 | }, | ||
485 | {} | ||
486 | }; | ||
487 | |||
488 | static struct __devinitdata snd_kcontrol_new elements[] = { | ||
489 | { | ||
490 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
302 | .name = "Line/Phono Capture Route", | 491 | .name = "Line/Phono Capture Route", |
303 | .index = 0, | 492 | .index = 0, |
304 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | 493 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
@@ -324,9 +513,54 @@ static struct __devinitdata snd_kcontrol_new elements[] = { | |||
324 | .get = usb6fire_control_digital_thru_get, | 513 | .get = usb6fire_control_digital_thru_get, |
325 | .put = usb6fire_control_digital_thru_put | 514 | .put = usb6fire_control_digital_thru_put |
326 | }, | 515 | }, |
516 | { | ||
517 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
518 | .name = "Analog Capture Volume", | ||
519 | .index = 0, | ||
520 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
521 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
522 | .info = usb6fire_control_input_vol_info, | ||
523 | .get = usb6fire_control_input_vol_get, | ||
524 | .put = usb6fire_control_input_vol_put, | ||
525 | .tlv = { .p = tlv_input } | ||
526 | }, | ||
327 | {} | 527 | {} |
328 | }; | 528 | }; |
329 | 529 | ||
530 | static int usb6fire_control_add_virtual( | ||
531 | struct control_runtime *rt, | ||
532 | struct snd_card *card, | ||
533 | char *name, | ||
534 | struct snd_kcontrol_new *elems) | ||
535 | { | ||
536 | int ret; | ||
537 | int i; | ||
538 | struct snd_kcontrol *vmaster = | ||
539 | snd_ctl_make_virtual_master(name, tlv_output); | ||
540 | struct snd_kcontrol *control; | ||
541 | |||
542 | if (!vmaster) | ||
543 | return -ENOMEM; | ||
544 | ret = snd_ctl_add(card, vmaster); | ||
545 | if (ret < 0) | ||
546 | return ret; | ||
547 | |||
548 | i = 0; | ||
549 | while (elems[i].name) { | ||
550 | control = snd_ctl_new1(&elems[i], rt); | ||
551 | if (!control) | ||
552 | return -ENOMEM; | ||
553 | ret = snd_ctl_add(card, control); | ||
554 | if (ret < 0) | ||
555 | return ret; | ||
556 | ret = snd_ctl_add_slave(vmaster, control); | ||
557 | if (ret < 0) | ||
558 | return ret; | ||
559 | i++; | ||
560 | } | ||
561 | return 0; | ||
562 | } | ||
563 | |||
330 | int __devinit usb6fire_control_init(struct sfire_chip *chip) | 564 | int __devinit usb6fire_control_init(struct sfire_chip *chip) |
331 | { | 565 | { |
332 | int i; | 566 | int i; |
@@ -352,9 +586,26 @@ int __devinit usb6fire_control_init(struct sfire_chip *chip) | |||
352 | 586 | ||
353 | usb6fire_control_opt_coax_update(rt); | 587 | usb6fire_control_opt_coax_update(rt); |
354 | usb6fire_control_line_phono_update(rt); | 588 | usb6fire_control_line_phono_update(rt); |
355 | usb6fire_control_master_vol_update(rt); | 589 | usb6fire_control_output_vol_update(rt); |
590 | usb6fire_control_output_mute_update(rt); | ||
591 | usb6fire_control_input_vol_update(rt); | ||
356 | usb6fire_control_streaming_update(rt); | 592 | usb6fire_control_streaming_update(rt); |
357 | 593 | ||
594 | ret = usb6fire_control_add_virtual(rt, chip->card, | ||
595 | "Master Playback Volume", vol_elements); | ||
596 | if (ret) { | ||
597 | snd_printk(KERN_ERR PREFIX "cannot add control.\n"); | ||
598 | kfree(rt); | ||
599 | return ret; | ||
600 | } | ||
601 | ret = usb6fire_control_add_virtual(rt, chip->card, | ||
602 | "Master Playback Switch", mute_elements); | ||
603 | if (ret) { | ||
604 | snd_printk(KERN_ERR PREFIX "cannot add control.\n"); | ||
605 | kfree(rt); | ||
606 | return ret; | ||
607 | } | ||
608 | |||
358 | i = 0; | 609 | i = 0; |
359 | while (elements[i].name) { | 610 | while (elements[i].name) { |
360 | ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt)); | 611 | ret = snd_ctl_add(chip->card, snd_ctl_new1(&elements[i], rt)); |
diff --git a/sound/usb/6fire/control.h b/sound/usb/6fire/control.h index 8f5aeead2e3d..9a596d95474a 100644 --- a/sound/usb/6fire/control.h +++ b/sound/usb/6fire/control.h | |||
@@ -3,7 +3,6 @@ | |||
3 | * | 3 | * |
4 | * Author: Torsten Schenk <torsten.schenk@zoho.com> | 4 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
5 | * Created: Jan 01, 2011 | 5 | * Created: Jan 01, 2011 |
6 | * Version: 0.3.0 | ||
7 | * Copyright: (C) Torsten Schenk | 6 | * Copyright: (C) Torsten Schenk |
8 | * | 7 | * |
9 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
@@ -44,7 +43,11 @@ struct control_runtime { | |||
44 | bool line_phono_switch; | 43 | bool line_phono_switch; |
45 | bool digital_thru_switch; | 44 | bool digital_thru_switch; |
46 | bool usb_streaming; | 45 | bool usb_streaming; |
47 | u8 master_vol; | 46 | u8 output_vol[6]; |
47 | u8 ovol_updated; | ||
48 | u8 output_mute; | ||
49 | s8 input_vol[2]; | ||
50 | u8 ivol_updated; | ||
48 | }; | 51 | }; |
49 | 52 | ||
50 | int __devinit usb6fire_control_init(struct sfire_chip *chip); | 53 | int __devinit usb6fire_control_init(struct sfire_chip *chip); |
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 3b5f517a3972..6f9715ab32fe 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c | |||
@@ -5,7 +5,6 @@ | |||
5 | * | 5 | * |
6 | * Author: Torsten Schenk <torsten.schenk@zoho.com> | 6 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
7 | * Created: Jan 01, 2011 | 7 | * Created: Jan 01, 2011 |
8 | * Version: 0.3.0 | ||
9 | * Copyright: (C) Torsten Schenk | 8 | * Copyright: (C) Torsten Schenk |
10 | * | 9 | * |
11 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/usb/6fire/midi.c b/sound/usb/6fire/midi.c index 13f4509dce2b..f0e5179b242b 100644 --- a/sound/usb/6fire/midi.c +++ b/sound/usb/6fire/midi.c | |||
@@ -5,7 +5,6 @@ | |||
5 | * | 5 | * |
6 | * Author: Torsten Schenk <torsten.schenk@zoho.com> | 6 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
7 | * Created: Jan 01, 2011 | 7 | * Created: Jan 01, 2011 |
8 | * Version: 0.3.0 | ||
9 | * Copyright: (C) Torsten Schenk | 8 | * Copyright: (C) Torsten Schenk |
10 | * | 9 | * |
11 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/usb/6fire/midi.h b/sound/usb/6fire/midi.h index 97a7bf669135..5114eccc1d8e 100644 --- a/sound/usb/6fire/midi.h +++ b/sound/usb/6fire/midi.h | |||
@@ -3,7 +3,6 @@ | |||
3 | * | 3 | * |
4 | * Author: Torsten Schenk <torsten.schenk@zoho.com> | 4 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
5 | * Created: Jan 01, 2011 | 5 | * Created: Jan 01, 2011 |
6 | * Version: 0.3.0 | ||
7 | * Copyright: (C) Torsten Schenk | 6 | * Copyright: (C) Torsten Schenk |
8 | * | 7 | * |
9 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c index d144cdb2f159..c97d05f0e966 100644 --- a/sound/usb/6fire/pcm.c +++ b/sound/usb/6fire/pcm.c | |||
@@ -5,7 +5,6 @@ | |||
5 | * | 5 | * |
6 | * Author: Torsten Schenk <torsten.schenk@zoho.com> | 6 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
7 | * Created: Jan 01, 2011 | 7 | * Created: Jan 01, 2011 |
8 | * Version: 0.3.0 | ||
9 | * Copyright: (C) Torsten Schenk | 8 | * Copyright: (C) Torsten Schenk |
10 | * | 9 | * |
11 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/usb/6fire/pcm.h b/sound/usb/6fire/pcm.h index 2bee81374002..3104301b257d 100644 --- a/sound/usb/6fire/pcm.h +++ b/sound/usb/6fire/pcm.h | |||
@@ -3,7 +3,6 @@ | |||
3 | * | 3 | * |
4 | * Author: Torsten Schenk <torsten.schenk@zoho.com> | 4 | * Author: Torsten Schenk <torsten.schenk@zoho.com> |
5 | * Created: Jan 01, 2011 | 5 | * Created: Jan 01, 2011 |
6 | * Version: 0.3.0 | ||
7 | * Copyright: (C) Torsten Schenk | 6 | * Copyright: (C) Torsten Schenk |
8 | * | 7 | * |
9 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 3efc21c3d67c..ff77b28f3da1 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
@@ -106,6 +106,7 @@ config SND_USB_6FIRE | |||
106 | select BITREVERSE | 106 | select BITREVERSE |
107 | select SND_RAWMIDI | 107 | select SND_RAWMIDI |
108 | select SND_PCM | 108 | select SND_PCM |
109 | select SND_VMASTER | ||
109 | help | 110 | help |
110 | Say Y here to include support for TerraTec 6fire DMX USB interface. | 111 | Say Y here to include support for TerraTec 6fire DMX USB interface. |
111 | 112 | ||
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 0220b0f335b9..0eed6115c2d4 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -695,6 +695,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, | |||
695 | struct snd_usb_substream *subs) | 695 | struct snd_usb_substream *subs) |
696 | { | 696 | { |
697 | struct audioformat *fp; | 697 | struct audioformat *fp; |
698 | int *rate_list; | ||
698 | int count = 0, needs_knot = 0; | 699 | int count = 0, needs_knot = 0; |
699 | int err; | 700 | int err; |
700 | 701 | ||
@@ -708,7 +709,8 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, | |||
708 | if (!needs_knot) | 709 | if (!needs_knot) |
709 | return 0; | 710 | return 0; |
710 | 711 | ||
711 | subs->rate_list.list = kmalloc(sizeof(int) * count, GFP_KERNEL); | 712 | subs->rate_list.list = rate_list = |
713 | kmalloc(sizeof(int) * count, GFP_KERNEL); | ||
712 | if (!subs->rate_list.list) | 714 | if (!subs->rate_list.list) |
713 | return -ENOMEM; | 715 | return -ENOMEM; |
714 | subs->rate_list.count = count; | 716 | subs->rate_list.count = count; |
@@ -717,7 +719,7 @@ static int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, | |||
717 | list_for_each_entry(fp, &subs->fmt_list, list) { | 719 | list_for_each_entry(fp, &subs->fmt_list, list) { |
718 | int i; | 720 | int i; |
719 | for (i = 0; i < fp->nr_rates; i++) | 721 | for (i = 0; i < fp->nr_rates; i++) |
720 | subs->rate_list.list[count++] = fp->rate_table[i]; | 722 | rate_list[count++] = fp->rate_table[i]; |
721 | } | 723 | } |
722 | err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 724 | err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
723 | &subs->rate_list); | 725 | &subs->rate_list); |
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 6ffb3713b60c..520ef96d7c75 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c | |||
@@ -80,7 +80,7 @@ static int usX2Y_urb_capt_retire(struct snd_usX2Y_substream *subs) | |||
80 | cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset; | 80 | cp = (unsigned char*)urb->transfer_buffer + urb->iso_frame_desc[i].offset; |
81 | if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ | 81 | if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ |
82 | snd_printk(KERN_ERR "active frame status %i. " | 82 | snd_printk(KERN_ERR "active frame status %i. " |
83 | "Most propably some hardware problem.\n", | 83 | "Most probably some hardware problem.\n", |
84 | urb->iso_frame_desc[i].status); | 84 | urb->iso_frame_desc[i].status); |
85 | return urb->iso_frame_desc[i].status; | 85 | return urb->iso_frame_desc[i].status; |
86 | } | 86 | } |
@@ -300,7 +300,7 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y, | |||
300 | { | 300 | { |
301 | snd_printk(KERN_ERR | 301 | snd_printk(KERN_ERR |
302 | "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" | 302 | "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" |
303 | "Most propably some urb of usb-frame %i is still missing.\n" | 303 | "Most probably some urb of usb-frame %i is still missing.\n" |
304 | "Cause could be too long delays in usb-hcd interrupt handling.\n", | 304 | "Cause could be too long delays in usb-hcd interrupt handling.\n", |
305 | usb_get_current_frame_number(usX2Y->dev), | 305 | usb_get_current_frame_number(usX2Y->dev), |
306 | subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", | 306 | subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", |
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index a51340f6f2db..8e40b6e67e9e 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c | |||
@@ -74,7 +74,7 @@ static int usX2Y_usbpcm_urb_capt_retire(struct snd_usX2Y_substream *subs) | |||
74 | } | 74 | } |
75 | for (i = 0; i < nr_of_packs(); i++) { | 75 | for (i = 0; i < nr_of_packs(); i++) { |
76 | if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ | 76 | if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */ |
77 | snd_printk(KERN_ERR "activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status); | 77 | snd_printk(KERN_ERR "active frame status %i. Most probably some hardware problem.\n", urb->iso_frame_desc[i].status); |
78 | return urb->iso_frame_desc[i].status; | 78 | return urb->iso_frame_desc[i].status; |
79 | } | 79 | } |
80 | lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride; | 80 | lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride; |