aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/emu10k1/emufx.c100
1 files changed, 79 insertions, 21 deletions
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index d8e8db89535f..7b173c496953 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -655,13 +655,66 @@ snd_emu10k1_look_for_ctl(struct snd_emu10k1 *emu, struct snd_ctl_elem_id *id)
655 return NULL; 655 return NULL;
656} 656}
657 657
658#define MAX_TLV_SIZE 256
659
660static unsigned int *copy_tlv(unsigned int __user *_tlv)
661{
662 unsigned int data[2];
663 unsigned int *tlv;
664
665 if (!_tlv)
666 return NULL;
667 if (copy_from_user(data, _tlv, sizeof(data)))
668 return NULL;
669 if (data[1] >= MAX_TLV_SIZE)
670 return NULL;
671 tlv = kmalloc(data[1] * 4 + sizeof(data), GFP_KERNEL);
672 if (!tlv)
673 return NULL;
674 memcpy(tlv, data, sizeof(data));
675 if (copy_from_user(tlv + 2, _tlv + 2, data[1])) {
676 kfree(tlv);
677 return NULL;
678 }
679 return tlv;
680}
681
682static int copy_gctl(struct snd_emu10k1 *emu,
683 struct snd_emu10k1_fx8010_control_gpr *gctl,
684 struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
685 int idx)
686{
687 struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
688
689 if (emu->support_tlv)
690 return copy_from_user(gctl, &_gctl[idx], sizeof(*gctl));
691 octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
692 if (copy_from_user(gctl, &octl[idx], sizeof(*octl)))
693 return -EFAULT;
694 gctl->tlv = NULL;
695 return 0;
696}
697
698static int copy_gctl_to_user(struct snd_emu10k1 *emu,
699 struct snd_emu10k1_fx8010_control_gpr __user *_gctl,
700 struct snd_emu10k1_fx8010_control_gpr *gctl,
701 int idx)
702{
703 struct snd_emu10k1_fx8010_control_old_gpr __user *octl;
704
705 if (emu->support_tlv)
706 return copy_to_user(&_gctl[idx], gctl, sizeof(*gctl));
707
708 octl = (struct snd_emu10k1_fx8010_control_old_gpr __user *)_gctl;
709 return copy_to_user(&octl[idx], gctl, sizeof(*octl));
710}
711
658static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu, 712static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
659 struct snd_emu10k1_fx8010_code *icode) 713 struct snd_emu10k1_fx8010_code *icode)
660{ 714{
661 unsigned int i; 715 unsigned int i;
662 struct snd_ctl_elem_id __user *_id; 716 struct snd_ctl_elem_id __user *_id;
663 struct snd_ctl_elem_id id; 717 struct snd_ctl_elem_id id;
664 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
665 struct snd_emu10k1_fx8010_control_gpr *gctl; 718 struct snd_emu10k1_fx8010_control_gpr *gctl;
666 int err; 719 int err;
667 720
@@ -676,9 +729,8 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
676 if (! gctl) 729 if (! gctl)
677 return -ENOMEM; 730 return -ENOMEM;
678 err = 0; 731 err = 0;
679 for (i = 0, _gctl = icode->gpr_add_controls; 732 for (i = 0; i < icode->gpr_add_control_count; i++) {
680 i < icode->gpr_add_control_count; i++, _gctl++) { 733 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
681 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
682 err = -EFAULT; 734 err = -EFAULT;
683 goto __error; 735 goto __error;
684 } 736 }
@@ -697,10 +749,9 @@ static int snd_emu10k1_verify_controls(struct snd_emu10k1 *emu,
697 goto __error; 749 goto __error;
698 } 750 }
699 } 751 }
700 for (i = 0, _gctl = icode->gpr_list_controls; 752 for (i = 0; i < icode->gpr_list_control_count; i++) {
701 i < icode->gpr_list_control_count; i++, _gctl++) {
702 /* FIXME: we need to check the WRITE access */ 753 /* FIXME: we need to check the WRITE access */
703 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) { 754 if (copy_gctl(emu, gctl, icode->gpr_list_controls, i)) {
704 err = -EFAULT; 755 err = -EFAULT;
705 goto __error; 756 goto __error;
706 } 757 }
@@ -718,13 +769,14 @@ static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
718 kctl->private_value = 0; 769 kctl->private_value = 0;
719 list_del(&ctl->list); 770 list_del(&ctl->list);
720 kfree(ctl); 771 kfree(ctl);
772 if (kctl->tlv.p)
773 kfree(kctl->tlv.p);
721} 774}
722 775
723static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu, 776static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
724 struct snd_emu10k1_fx8010_code *icode) 777 struct snd_emu10k1_fx8010_code *icode)
725{ 778{
726 unsigned int i, j; 779 unsigned int i, j;
727 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
728 struct snd_emu10k1_fx8010_control_gpr *gctl; 780 struct snd_emu10k1_fx8010_control_gpr *gctl;
729 struct snd_emu10k1_fx8010_ctl *ctl, *nctl; 781 struct snd_emu10k1_fx8010_ctl *ctl, *nctl;
730 struct snd_kcontrol_new knew; 782 struct snd_kcontrol_new knew;
@@ -740,9 +792,8 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
740 goto __error; 792 goto __error;
741 } 793 }
742 794
743 for (i = 0, _gctl = icode->gpr_add_controls; 795 for (i = 0; i < icode->gpr_add_control_count; i++) {
744 i < icode->gpr_add_control_count; i++, _gctl++) { 796 if (copy_gctl(emu, gctl, icode->gpr_add_controls, i)) {
745 if (copy_from_user(gctl, _gctl, sizeof(*gctl))) {
746 err = -EFAULT; 797 err = -EFAULT;
747 goto __error; 798 goto __error;
748 } 799 }
@@ -763,11 +814,10 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
763 knew.device = gctl->id.device; 814 knew.device = gctl->id.device;
764 knew.subdevice = gctl->id.subdevice; 815 knew.subdevice = gctl->id.subdevice;
765 knew.info = snd_emu10k1_gpr_ctl_info; 816 knew.info = snd_emu10k1_gpr_ctl_info;
766 if (gctl->tlv.p) { 817 knew.tlv.p = copy_tlv(gctl->tlv);
767 knew.tlv.p = gctl->tlv.p; 818 if (knew.tlv.p)
768 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 819 knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
769 SNDRV_CTL_ELEM_ACCESS_TLV_READ; 820 SNDRV_CTL_ELEM_ACCESS_TLV_READ;
770 }
771 knew.get = snd_emu10k1_gpr_ctl_get; 821 knew.get = snd_emu10k1_gpr_ctl_get;
772 knew.put = snd_emu10k1_gpr_ctl_put; 822 knew.put = snd_emu10k1_gpr_ctl_put;
773 memset(nctl, 0, sizeof(*nctl)); 823 memset(nctl, 0, sizeof(*nctl));
@@ -785,12 +835,14 @@ static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
785 ctl = kmalloc(sizeof(*ctl), GFP_KERNEL); 835 ctl = kmalloc(sizeof(*ctl), GFP_KERNEL);
786 if (ctl == NULL) { 836 if (ctl == NULL) {
787 err = -ENOMEM; 837 err = -ENOMEM;
838 kfree(knew.tlv.p);
788 goto __error; 839 goto __error;
789 } 840 }
790 knew.private_value = (unsigned long)ctl; 841 knew.private_value = (unsigned long)ctl;
791 *ctl = *nctl; 842 *ctl = *nctl;
792 if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) { 843 if ((err = snd_ctl_add(emu->card, kctl = snd_ctl_new1(&knew, emu))) < 0) {
793 kfree(ctl); 844 kfree(ctl);
845 kfree(knew.tlv.p);
794 goto __error; 846 goto __error;
795 } 847 }
796 kctl->private_free = snd_emu10k1_ctl_private_free; 848 kctl->private_free = snd_emu10k1_ctl_private_free;
@@ -841,7 +893,6 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
841 unsigned int i = 0, j; 893 unsigned int i = 0, j;
842 unsigned int total = 0; 894 unsigned int total = 0;
843 struct snd_emu10k1_fx8010_control_gpr *gctl; 895 struct snd_emu10k1_fx8010_control_gpr *gctl;
844 struct snd_emu10k1_fx8010_control_gpr __user *_gctl;
845 struct snd_emu10k1_fx8010_ctl *ctl; 896 struct snd_emu10k1_fx8010_ctl *ctl;
846 struct snd_ctl_elem_id *id; 897 struct snd_ctl_elem_id *id;
847 struct list_head *list; 898 struct list_head *list;
@@ -850,11 +901,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
850 if (! gctl) 901 if (! gctl)
851 return -ENOMEM; 902 return -ENOMEM;
852 903
853 _gctl = icode->gpr_list_controls;
854 list_for_each(list, &emu->fx8010.gpr_ctl) { 904 list_for_each(list, &emu->fx8010.gpr_ctl) {
855 ctl = emu10k1_gpr_ctl(list); 905 ctl = emu10k1_gpr_ctl(list);
856 total++; 906 total++;
857 if (_gctl && i < icode->gpr_list_control_count) { 907 if (icode->gpr_list_controls &&
908 i < icode->gpr_list_control_count) {
858 memset(gctl, 0, sizeof(*gctl)); 909 memset(gctl, 0, sizeof(*gctl));
859 id = &ctl->kcontrol->id; 910 id = &ctl->kcontrol->id;
860 gctl->id.iface = id->iface; 911 gctl->id.iface = id->iface;
@@ -871,11 +922,11 @@ static int snd_emu10k1_list_controls(struct snd_emu10k1 *emu,
871 gctl->min = ctl->min; 922 gctl->min = ctl->min;
872 gctl->max = ctl->max; 923 gctl->max = ctl->max;
873 gctl->translation = ctl->translation; 924 gctl->translation = ctl->translation;
874 if (copy_to_user(_gctl, gctl, sizeof(*gctl))) { 925 if (copy_gctl_to_user(emu, icode->gpr_list_controls,
926 gctl, i)) {
875 kfree(gctl); 927 kfree(gctl);
876 return -EFAULT; 928 return -EFAULT;
877 } 929 }
878 _gctl++;
879 i++; 930 i++;
880 } 931 }
881 } 932 }
@@ -1026,7 +1077,7 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1026 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval; 1077 ctl->gpr[0] = gpr + 0; ctl->value[0] = defval;
1027 ctl->min = 0; 1078 ctl->min = 0;
1028 ctl->max = 100; 1079 ctl->max = 100;
1029 ctl->tlv.p = snd_emu10k1_db_scale1; 1080 ctl->tlv = snd_emu10k1_db_scale1;
1030 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; 1081 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1031} 1082}
1032 1083
@@ -1041,7 +1092,7 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl,
1041 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval; 1092 ctl->gpr[1] = gpr + 1; ctl->value[1] = defval;
1042 ctl->min = 0; 1093 ctl->min = 0;
1043 ctl->max = 100; 1094 ctl->max = 100;
1044 ctl->tlv.p = snd_emu10k1_db_scale1; 1095 ctl->tlv = snd_emu10k1_db_scale1;
1045 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100; 1096 ctl->translation = EMU10K1_GPR_TRANSLATION_TABLE100;
1046} 1097}
1047 1098
@@ -1566,7 +1617,9 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
1566 seg = snd_enter_user(); 1617 seg = snd_enter_user();
1567 icode->gpr_add_control_count = nctl; 1618 icode->gpr_add_control_count = nctl;
1568 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; 1619 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
1620 emu->support_tlv = 1; /* support TLV */
1569 err = snd_emu10k1_icode_poke(emu, icode); 1621 err = snd_emu10k1_icode_poke(emu, icode);
1622 emu->support_tlv = 0; /* clear again */
1570 snd_leave_user(seg); 1623 snd_leave_user(seg);
1571 1624
1572 __err: 1625 __err:
@@ -2183,7 +2236,9 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
2183 seg = snd_enter_user(); 2236 seg = snd_enter_user();
2184 icode->gpr_add_control_count = i; 2237 icode->gpr_add_control_count = i;
2185 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls; 2238 icode->gpr_add_controls = (struct snd_emu10k1_fx8010_control_gpr __user *)controls;
2239 emu->support_tlv = 1; /* support TLV */
2186 err = snd_emu10k1_icode_poke(emu, icode); 2240 err = snd_emu10k1_icode_poke(emu, icode);
2241 emu->support_tlv = 0; /* clear again */
2187 snd_leave_user(seg); 2242 snd_leave_user(seg);
2188 if (err >= 0) 2243 if (err >= 0)
2189 err = snd_emu10k1_ipcm_poke(emu, ipcm); 2244 err = snd_emu10k1_ipcm_poke(emu, ipcm);
@@ -2327,6 +2382,9 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un
2327 int res; 2382 int res;
2328 2383
2329 switch (cmd) { 2384 switch (cmd) {
2385 case SNDRV_EMU10K1_IOCTL_PVERSION:
2386 emu->support_tlv = 1;
2387 return put_user(SNDRV_EMU10K1_VERSION, (int __user *)argp);
2330 case SNDRV_EMU10K1_IOCTL_INFO: 2388 case SNDRV_EMU10K1_IOCTL_INFO:
2331 info = kmalloc(sizeof(*info), GFP_KERNEL); 2389 info = kmalloc(sizeof(*info), GFP_KERNEL);
2332 if (!info) 2390 if (!info)