aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2007-01-19 12:34:47 -0500
committerJaroslav Kysela <perex@suse.cz>2007-02-09 03:03:06 -0500
commitf7ba7fc6173a9fb6d8a5bc02bf335cc358f21a09 (patch)
tree3ce618119c72cd6706bd83a02958fef92e24425d /sound/pci
parent7ed07a740b886930a299d438947ad322272eece1 (diff)
[ALSA] emu10k1 - Fix ABI for older ld10k1
Fix ABI for older ld10k1. When no EMU10K1_PVERSION ioctl is issued, the driver accepts ioctls with the old struct size without TLV information. Also, changed the struct field to make the conversion easier from the old to the new structs. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
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)