diff options
Diffstat (limited to 'drivers/usb/gadget/function/f_midi.c')
-rw-r--r-- | drivers/usb/gadget/function/f_midi.c | 364 |
1 files changed, 274 insertions, 90 deletions
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index 807b31c0edc3..a90440300735 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c | |||
@@ -20,6 +20,7 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/module.h> | ||
23 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
24 | #include <linux/device.h> | 25 | #include <linux/device.h> |
25 | 26 | ||
@@ -33,6 +34,7 @@ | |||
33 | #include <linux/usb/midi.h> | 34 | #include <linux/usb/midi.h> |
34 | 35 | ||
35 | #include "u_f.h" | 36 | #include "u_f.h" |
37 | #include "u_midi.h" | ||
36 | 38 | ||
37 | MODULE_AUTHOR("Ben Williamson"); | 39 | MODULE_AUTHOR("Ben Williamson"); |
38 | MODULE_LICENSE("GPL v2"); | 40 | MODULE_LICENSE("GPL v2"); |
@@ -99,7 +101,7 @@ DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); | |||
99 | DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16); | 101 | DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16); |
100 | 102 | ||
101 | /* B.3.1 Standard AC Interface Descriptor */ | 103 | /* B.3.1 Standard AC Interface Descriptor */ |
102 | static struct usb_interface_descriptor ac_interface_desc __initdata = { | 104 | static struct usb_interface_descriptor ac_interface_desc = { |
103 | .bLength = USB_DT_INTERFACE_SIZE, | 105 | .bLength = USB_DT_INTERFACE_SIZE, |
104 | .bDescriptorType = USB_DT_INTERFACE, | 106 | .bDescriptorType = USB_DT_INTERFACE, |
105 | /* .bInterfaceNumber = DYNAMIC */ | 107 | /* .bInterfaceNumber = DYNAMIC */ |
@@ -110,7 +112,7 @@ static struct usb_interface_descriptor ac_interface_desc __initdata = { | |||
110 | }; | 112 | }; |
111 | 113 | ||
112 | /* B.3.2 Class-Specific AC Interface Descriptor */ | 114 | /* B.3.2 Class-Specific AC Interface Descriptor */ |
113 | static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = { | 115 | static struct uac1_ac_header_descriptor_1 ac_header_desc = { |
114 | .bLength = UAC_DT_AC_HEADER_SIZE(1), | 116 | .bLength = UAC_DT_AC_HEADER_SIZE(1), |
115 | .bDescriptorType = USB_DT_CS_INTERFACE, | 117 | .bDescriptorType = USB_DT_CS_INTERFACE, |
116 | .bDescriptorSubtype = USB_MS_HEADER, | 118 | .bDescriptorSubtype = USB_MS_HEADER, |
@@ -121,7 +123,7 @@ static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = { | |||
121 | }; | 123 | }; |
122 | 124 | ||
123 | /* B.4.1 Standard MS Interface Descriptor */ | 125 | /* B.4.1 Standard MS Interface Descriptor */ |
124 | static struct usb_interface_descriptor ms_interface_desc __initdata = { | 126 | static struct usb_interface_descriptor ms_interface_desc = { |
125 | .bLength = USB_DT_INTERFACE_SIZE, | 127 | .bLength = USB_DT_INTERFACE_SIZE, |
126 | .bDescriptorType = USB_DT_INTERFACE, | 128 | .bDescriptorType = USB_DT_INTERFACE, |
127 | /* .bInterfaceNumber = DYNAMIC */ | 129 | /* .bInterfaceNumber = DYNAMIC */ |
@@ -132,7 +134,7 @@ static struct usb_interface_descriptor ms_interface_desc __initdata = { | |||
132 | }; | 134 | }; |
133 | 135 | ||
134 | /* B.4.2 Class-Specific MS Interface Descriptor */ | 136 | /* B.4.2 Class-Specific MS Interface Descriptor */ |
135 | static struct usb_ms_header_descriptor ms_header_desc __initdata = { | 137 | static struct usb_ms_header_descriptor ms_header_desc = { |
136 | .bLength = USB_DT_MS_HEADER_SIZE, | 138 | .bLength = USB_DT_MS_HEADER_SIZE, |
137 | .bDescriptorType = USB_DT_CS_INTERFACE, | 139 | .bDescriptorType = USB_DT_CS_INTERFACE, |
138 | .bDescriptorSubtype = USB_MS_HEADER, | 140 | .bDescriptorSubtype = USB_MS_HEADER, |
@@ -387,29 +389,6 @@ static void f_midi_disable(struct usb_function *f) | |||
387 | usb_ep_disable(midi->out_ep); | 389 | usb_ep_disable(midi->out_ep); |
388 | } | 390 | } |
389 | 391 | ||
390 | static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) | ||
391 | { | ||
392 | struct usb_composite_dev *cdev = f->config->cdev; | ||
393 | struct f_midi *midi = func_to_midi(f); | ||
394 | struct snd_card *card; | ||
395 | |||
396 | DBG(cdev, "unbind\n"); | ||
397 | |||
398 | /* just to be sure */ | ||
399 | f_midi_disable(f); | ||
400 | |||
401 | card = midi->card; | ||
402 | midi->card = NULL; | ||
403 | if (card) | ||
404 | snd_card_free(card); | ||
405 | |||
406 | kfree(midi->id); | ||
407 | midi->id = NULL; | ||
408 | |||
409 | usb_free_all_descriptors(f); | ||
410 | kfree(midi); | ||
411 | } | ||
412 | |||
413 | static int f_midi_snd_free(struct snd_device *device) | 392 | static int f_midi_snd_free(struct snd_device *device) |
414 | { | 393 | { |
415 | return 0; | 394 | return 0; |
@@ -654,6 +633,14 @@ static struct snd_rawmidi_ops gmidi_out_ops = { | |||
654 | .trigger = f_midi_out_trigger | 633 | .trigger = f_midi_out_trigger |
655 | }; | 634 | }; |
656 | 635 | ||
636 | static inline void f_midi_unregister_card(struct f_midi *midi) | ||
637 | { | ||
638 | if (midi->card) { | ||
639 | snd_card_free(midi->card); | ||
640 | midi->card = NULL; | ||
641 | } | ||
642 | } | ||
643 | |||
657 | /* register as a sound "card" */ | 644 | /* register as a sound "card" */ |
658 | static int f_midi_register_card(struct f_midi *midi) | 645 | static int f_midi_register_card(struct f_midi *midi) |
659 | { | 646 | { |
@@ -715,17 +702,13 @@ static int f_midi_register_card(struct f_midi *midi) | |||
715 | return 0; | 702 | return 0; |
716 | 703 | ||
717 | fail: | 704 | fail: |
718 | if (midi->card) { | 705 | f_midi_unregister_card(midi); |
719 | snd_card_free(midi->card); | ||
720 | midi->card = NULL; | ||
721 | } | ||
722 | return err; | 706 | return err; |
723 | } | 707 | } |
724 | 708 | ||
725 | /* MIDI function driver setup/binding */ | 709 | /* MIDI function driver setup/binding */ |
726 | 710 | ||
727 | static int __init | 711 | static int f_midi_bind(struct usb_configuration *c, struct usb_function *f) |
728 | f_midi_bind(struct usb_configuration *c, struct usb_function *f) | ||
729 | { | 712 | { |
730 | struct usb_descriptor_header **midi_function; | 713 | struct usb_descriptor_header **midi_function; |
731 | struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS]; | 714 | struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS]; |
@@ -734,15 +717,23 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f) | |||
734 | struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc[MAX_PORTS]; | 717 | struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc[MAX_PORTS]; |
735 | struct usb_composite_dev *cdev = c->cdev; | 718 | struct usb_composite_dev *cdev = c->cdev; |
736 | struct f_midi *midi = func_to_midi(f); | 719 | struct f_midi *midi = func_to_midi(f); |
720 | struct usb_string *us; | ||
737 | int status, n, jack = 1, i = 0; | 721 | int status, n, jack = 1, i = 0; |
738 | 722 | ||
723 | midi->gadget = cdev->gadget; | ||
724 | tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); | ||
725 | status = f_midi_register_card(midi); | ||
726 | if (status < 0) | ||
727 | goto fail_register; | ||
728 | |||
739 | /* maybe allocate device-global string ID */ | 729 | /* maybe allocate device-global string ID */ |
740 | if (midi_string_defs[0].id == 0) { | 730 | us = usb_gstrings_attach(c->cdev, midi_strings, |
741 | status = usb_string_id(c->cdev); | 731 | ARRAY_SIZE(midi_string_defs)); |
742 | if (status < 0) | 732 | if (IS_ERR(us)) { |
743 | goto fail; | 733 | status = PTR_ERR(us); |
744 | midi_string_defs[0].id = status; | 734 | goto fail; |
745 | } | 735 | } |
736 | ac_interface_desc.iInterface = us[STRING_FUNC_IDX].id; | ||
746 | 737 | ||
747 | /* We have two interfaces, AudioControl and MIDIStreaming */ | 738 | /* We have two interfaces, AudioControl and MIDIStreaming */ |
748 | status = usb_interface_id(c, f); | 739 | status = usb_interface_id(c, f); |
@@ -892,6 +883,8 @@ fail_f_midi: | |||
892 | kfree(midi_function); | 883 | kfree(midi_function); |
893 | usb_free_descriptors(f->hs_descriptors); | 884 | usb_free_descriptors(f->hs_descriptors); |
894 | fail: | 885 | fail: |
886 | f_midi_unregister_card(midi); | ||
887 | fail_register: | ||
895 | /* we might as well release our claims on endpoints */ | 888 | /* we might as well release our claims on endpoints */ |
896 | if (midi->out_ep) | 889 | if (midi->out_ep) |
897 | midi->out_ep->driver_data = NULL; | 890 | midi->out_ep->driver_data = NULL; |
@@ -903,42 +896,235 @@ fail: | |||
903 | return status; | 896 | return status; |
904 | } | 897 | } |
905 | 898 | ||
906 | /** | 899 | static inline struct f_midi_opts *to_f_midi_opts(struct config_item *item) |
907 | * f_midi_bind_config - add USB MIDI function to a configuration | 900 | { |
908 | * @c: the configuration to supcard the USB audio function | 901 | return container_of(to_config_group(item), struct f_midi_opts, |
909 | * @index: the soundcard index to use for the ALSA device creation | 902 | func_inst.group); |
910 | * @id: the soundcard id to use for the ALSA device creation | 903 | } |
911 | * @buflen: the buffer length to use | 904 | |
912 | * @qlen the number of read requests to pre-allocate | 905 | CONFIGFS_ATTR_STRUCT(f_midi_opts); |
913 | * Context: single threaded during gadget setup | 906 | CONFIGFS_ATTR_OPS(f_midi_opts); |
914 | * | 907 | |
915 | * Returns zero on success, else negative errno. | 908 | static void midi_attr_release(struct config_item *item) |
916 | */ | 909 | { |
917 | int __init f_midi_bind_config(struct usb_configuration *c, | 910 | struct f_midi_opts *opts = to_f_midi_opts(item); |
918 | int index, char *id, | 911 | |
919 | unsigned int in_ports, | 912 | usb_put_function_instance(&opts->func_inst); |
920 | unsigned int out_ports, | 913 | } |
921 | unsigned int buflen, | 914 | |
922 | unsigned int qlen) | 915 | static struct configfs_item_operations midi_item_ops = { |
916 | .release = midi_attr_release, | ||
917 | .show_attribute = f_midi_opts_attr_show, | ||
918 | .store_attribute = f_midi_opts_attr_store, | ||
919 | }; | ||
920 | |||
921 | #define F_MIDI_OPT(name, test_limit, limit) \ | ||
922 | static ssize_t f_midi_opts_##name##_show(struct f_midi_opts *opts, char *page) \ | ||
923 | { \ | ||
924 | int result; \ | ||
925 | \ | ||
926 | mutex_lock(&opts->lock); \ | ||
927 | result = sprintf(page, "%d\n", opts->name); \ | ||
928 | mutex_unlock(&opts->lock); \ | ||
929 | \ | ||
930 | return result; \ | ||
931 | } \ | ||
932 | \ | ||
933 | static ssize_t f_midi_opts_##name##_store(struct f_midi_opts *opts, \ | ||
934 | const char *page, size_t len) \ | ||
935 | { \ | ||
936 | int ret; \ | ||
937 | u32 num; \ | ||
938 | \ | ||
939 | mutex_lock(&opts->lock); \ | ||
940 | if (opts->refcnt) { \ | ||
941 | ret = -EBUSY; \ | ||
942 | goto end; \ | ||
943 | } \ | ||
944 | \ | ||
945 | ret = kstrtou32(page, 0, &num); \ | ||
946 | if (ret) \ | ||
947 | goto end; \ | ||
948 | \ | ||
949 | if (test_limit && num > limit) { \ | ||
950 | ret = -EINVAL; \ | ||
951 | goto end; \ | ||
952 | } \ | ||
953 | opts->name = num; \ | ||
954 | ret = len; \ | ||
955 | \ | ||
956 | end: \ | ||
957 | mutex_unlock(&opts->lock); \ | ||
958 | return ret; \ | ||
959 | } \ | ||
960 | \ | ||
961 | static struct f_midi_opts_attribute f_midi_opts_##name = \ | ||
962 | __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, f_midi_opts_##name##_show, \ | ||
963 | f_midi_opts_##name##_store) | ||
964 | |||
965 | F_MIDI_OPT(index, true, SNDRV_CARDS); | ||
966 | F_MIDI_OPT(buflen, false, 0); | ||
967 | F_MIDI_OPT(qlen, false, 0); | ||
968 | F_MIDI_OPT(in_ports, true, MAX_PORTS); | ||
969 | F_MIDI_OPT(out_ports, true, MAX_PORTS); | ||
970 | |||
971 | static ssize_t f_midi_opts_id_show(struct f_midi_opts *opts, char *page) | ||
972 | { | ||
973 | int result; | ||
974 | |||
975 | mutex_lock(&opts->lock); | ||
976 | result = strlcpy(page, opts->id, PAGE_SIZE); | ||
977 | mutex_unlock(&opts->lock); | ||
978 | |||
979 | return result; | ||
980 | } | ||
981 | |||
982 | static ssize_t f_midi_opts_id_store(struct f_midi_opts *opts, | ||
983 | const char *page, size_t len) | ||
984 | { | ||
985 | int ret; | ||
986 | char *c; | ||
987 | |||
988 | mutex_lock(&opts->lock); | ||
989 | if (opts->refcnt) { | ||
990 | ret = -EBUSY; | ||
991 | goto end; | ||
992 | } | ||
993 | |||
994 | c = kstrndup(page, len, GFP_KERNEL); | ||
995 | if (!c) { | ||
996 | ret = -ENOMEM; | ||
997 | goto end; | ||
998 | } | ||
999 | if (opts->id_allocated) | ||
1000 | kfree(opts->id); | ||
1001 | opts->id = c; | ||
1002 | opts->id_allocated = true; | ||
1003 | ret = len; | ||
1004 | end: | ||
1005 | mutex_unlock(&opts->lock); | ||
1006 | return ret; | ||
1007 | } | ||
1008 | |||
1009 | static struct f_midi_opts_attribute f_midi_opts_id = | ||
1010 | __CONFIGFS_ATTR(id, S_IRUGO | S_IWUSR, f_midi_opts_id_show, | ||
1011 | f_midi_opts_id_store); | ||
1012 | |||
1013 | static struct configfs_attribute *midi_attrs[] = { | ||
1014 | &f_midi_opts_index.attr, | ||
1015 | &f_midi_opts_buflen.attr, | ||
1016 | &f_midi_opts_qlen.attr, | ||
1017 | &f_midi_opts_in_ports.attr, | ||
1018 | &f_midi_opts_out_ports.attr, | ||
1019 | &f_midi_opts_id.attr, | ||
1020 | NULL, | ||
1021 | }; | ||
1022 | |||
1023 | static struct config_item_type midi_func_type = { | ||
1024 | .ct_item_ops = &midi_item_ops, | ||
1025 | .ct_attrs = midi_attrs, | ||
1026 | .ct_owner = THIS_MODULE, | ||
1027 | }; | ||
1028 | |||
1029 | static void f_midi_free_inst(struct usb_function_instance *f) | ||
1030 | { | ||
1031 | struct f_midi_opts *opts; | ||
1032 | |||
1033 | opts = container_of(f, struct f_midi_opts, func_inst); | ||
1034 | |||
1035 | if (opts->id_allocated) | ||
1036 | kfree(opts->id); | ||
1037 | |||
1038 | kfree(opts); | ||
1039 | } | ||
1040 | |||
1041 | static struct usb_function_instance *f_midi_alloc_inst(void) | ||
1042 | { | ||
1043 | struct f_midi_opts *opts; | ||
1044 | |||
1045 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | ||
1046 | if (!opts) | ||
1047 | return ERR_PTR(-ENOMEM); | ||
1048 | |||
1049 | mutex_init(&opts->lock); | ||
1050 | opts->func_inst.free_func_inst = f_midi_free_inst; | ||
1051 | opts->index = SNDRV_DEFAULT_IDX1; | ||
1052 | opts->id = SNDRV_DEFAULT_STR1; | ||
1053 | opts->buflen = 256; | ||
1054 | opts->qlen = 32; | ||
1055 | opts->in_ports = 1; | ||
1056 | opts->out_ports = 1; | ||
1057 | |||
1058 | config_group_init_type_name(&opts->func_inst.group, "", | ||
1059 | &midi_func_type); | ||
1060 | |||
1061 | return &opts->func_inst; | ||
1062 | } | ||
1063 | |||
1064 | static void f_midi_free(struct usb_function *f) | ||
1065 | { | ||
1066 | struct f_midi *midi; | ||
1067 | struct f_midi_opts *opts; | ||
1068 | int i; | ||
1069 | |||
1070 | midi = func_to_midi(f); | ||
1071 | opts = container_of(f->fi, struct f_midi_opts, func_inst); | ||
1072 | kfree(midi->id); | ||
1073 | mutex_lock(&opts->lock); | ||
1074 | for (i = opts->in_ports - 1; i >= 0; --i) | ||
1075 | kfree(midi->in_port[i]); | ||
1076 | kfree(midi); | ||
1077 | --opts->refcnt; | ||
1078 | mutex_unlock(&opts->lock); | ||
1079 | } | ||
1080 | |||
1081 | static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f) | ||
1082 | { | ||
1083 | struct usb_composite_dev *cdev = f->config->cdev; | ||
1084 | struct f_midi *midi = func_to_midi(f); | ||
1085 | struct snd_card *card; | ||
1086 | |||
1087 | DBG(cdev, "unbind\n"); | ||
1088 | |||
1089 | /* just to be sure */ | ||
1090 | f_midi_disable(f); | ||
1091 | |||
1092 | card = midi->card; | ||
1093 | midi->card = NULL; | ||
1094 | if (card) | ||
1095 | snd_card_free(card); | ||
1096 | |||
1097 | usb_free_all_descriptors(f); | ||
1098 | } | ||
1099 | |||
1100 | static struct usb_function *f_midi_alloc(struct usb_function_instance *fi) | ||
923 | { | 1101 | { |
924 | struct f_midi *midi; | 1102 | struct f_midi *midi; |
1103 | struct f_midi_opts *opts; | ||
925 | int status, i; | 1104 | int status, i; |
926 | 1105 | ||
1106 | opts = container_of(fi, struct f_midi_opts, func_inst); | ||
1107 | |||
1108 | mutex_lock(&opts->lock); | ||
927 | /* sanity check */ | 1109 | /* sanity check */ |
928 | if (in_ports > MAX_PORTS || out_ports > MAX_PORTS) | 1110 | if (opts->in_ports > MAX_PORTS || opts->out_ports > MAX_PORTS) { |
929 | return -EINVAL; | 1111 | mutex_unlock(&opts->lock); |
1112 | return ERR_PTR(-EINVAL); | ||
1113 | } | ||
930 | 1114 | ||
931 | /* allocate and initialize one new instance */ | 1115 | /* allocate and initialize one new instance */ |
932 | midi = kzalloc(sizeof *midi, GFP_KERNEL); | 1116 | midi = kzalloc(sizeof(*midi), GFP_KERNEL); |
933 | if (!midi) { | 1117 | if (!midi) { |
934 | status = -ENOMEM; | 1118 | mutex_unlock(&opts->lock); |
935 | goto fail; | 1119 | return ERR_PTR(-ENOMEM); |
936 | } | 1120 | } |
937 | 1121 | ||
938 | for (i = 0; i < in_ports; i++) { | 1122 | for (i = 0; i < opts->in_ports; i++) { |
939 | struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL); | 1123 | struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL); |
1124 | |||
940 | if (!port) { | 1125 | if (!port) { |
941 | status = -ENOMEM; | 1126 | status = -ENOMEM; |
1127 | mutex_unlock(&opts->lock); | ||
942 | goto setup_fail; | 1128 | goto setup_fail; |
943 | } | 1129 | } |
944 | 1130 | ||
@@ -948,39 +1134,37 @@ int __init f_midi_bind_config(struct usb_configuration *c, | |||
948 | midi->in_port[i] = port; | 1134 | midi->in_port[i] = port; |
949 | } | 1135 | } |
950 | 1136 | ||
951 | midi->gadget = c->cdev->gadget; | ||
952 | tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); | ||
953 | |||
954 | /* set up ALSA midi devices */ | 1137 | /* set up ALSA midi devices */ |
955 | midi->in_ports = in_ports; | 1138 | midi->id = kstrdup(opts->id, GFP_KERNEL); |
956 | midi->out_ports = out_ports; | 1139 | if (opts->id && !midi->id) { |
957 | status = f_midi_register_card(midi); | 1140 | status = -ENOMEM; |
958 | if (status < 0) | 1141 | mutex_unlock(&opts->lock); |
959 | goto setup_fail; | 1142 | goto kstrdup_fail; |
960 | 1143 | } | |
961 | midi->func.name = "gmidi function"; | 1144 | midi->in_ports = opts->in_ports; |
962 | midi->func.strings = midi_strings; | 1145 | midi->out_ports = opts->out_ports; |
963 | midi->func.bind = f_midi_bind; | 1146 | midi->index = opts->index; |
964 | midi->func.unbind = f_midi_unbind; | 1147 | midi->buflen = opts->buflen; |
965 | midi->func.set_alt = f_midi_set_alt; | 1148 | midi->qlen = opts->qlen; |
966 | midi->func.disable = f_midi_disable; | 1149 | ++opts->refcnt; |
967 | 1150 | mutex_unlock(&opts->lock); | |
968 | midi->id = kstrdup(id, GFP_KERNEL); | 1151 | |
969 | midi->index = index; | 1152 | midi->func.name = "gmidi function"; |
970 | midi->buflen = buflen; | 1153 | midi->func.bind = f_midi_bind; |
971 | midi->qlen = qlen; | 1154 | midi->func.unbind = f_midi_unbind; |
972 | 1155 | midi->func.set_alt = f_midi_set_alt; | |
973 | status = usb_add_function(c, &midi->func); | 1156 | midi->func.disable = f_midi_disable; |
974 | if (status) | 1157 | midi->func.free_func = f_midi_free; |
975 | goto setup_fail; | 1158 | |
976 | 1159 | return &midi->func; | |
977 | return 0; | 1160 | |
978 | 1161 | kstrdup_fail: | |
1162 | f_midi_unregister_card(midi); | ||
979 | setup_fail: | 1163 | setup_fail: |
980 | for (--i; i >= 0; i--) | 1164 | for (--i; i >= 0; i--) |
981 | kfree(midi->in_port[i]); | 1165 | kfree(midi->in_port[i]); |
982 | kfree(midi); | 1166 | kfree(midi); |
983 | fail: | 1167 | return ERR_PTR(status); |
984 | return status; | ||
985 | } | 1168 | } |
986 | 1169 | ||
1170 | DECLARE_USB_FUNCTION_INIT(midi, f_midi_alloc_inst, f_midi_alloc); | ||