diff options
author | Andrzej Pietrasiewicz <andrzej.p@samsung.com> | 2014-11-06 05:11:59 -0500 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2014-11-06 17:18:18 -0500 |
commit | cb382536052fcc7713988869b54a81137069e5a9 (patch) | |
tree | b47eb0c49597f56c9ee6d29ff2122fb7a13f6d0f | |
parent | 00896f66f5032e5f53874a76e02cdad09f7ff90b (diff) |
usb: gadget: f_hid: convert to new function interface with backward compatibility
Converting hid to the new function interface requires converting
the USB hid's function code and its users.
This patch converts the f_hid.c to the new function interface.
The file can now be compiled into a separate usb_f_hid.ko module.
The old function interface is provided by means of a preprocessor
conditional directives. After all users are converted, the old interface
can be removed.
Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | drivers/usb/gadget/Kconfig | 3 | ||||
-rw-r--r-- | drivers/usb/gadget/function/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/function/f_hid.c | 218 | ||||
-rw-r--r-- | drivers/usb/gadget/function/u_hid.h | 35 | ||||
-rw-r--r-- | drivers/usb/gadget/legacy/hid.c | 1 |
5 files changed, 227 insertions, 32 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 501c2a38d071..ea2d7706db6c 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig | |||
@@ -193,6 +193,9 @@ config USB_F_UVC | |||
193 | config USB_F_MIDI | 193 | config USB_F_MIDI |
194 | tristate | 194 | tristate |
195 | 195 | ||
196 | config USB_F_HID | ||
197 | tristate | ||
198 | |||
196 | choice | 199 | choice |
197 | tristate "USB Gadget Drivers" | 200 | tristate "USB Gadget Drivers" |
198 | default USB_ETH | 201 | default USB_ETH |
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile index 576eea5c0a8b..dd68091d92f0 100644 --- a/drivers/usb/gadget/function/Makefile +++ b/drivers/usb/gadget/function/Makefile | |||
@@ -40,3 +40,5 @@ usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o | |||
40 | obj-$(CONFIG_USB_F_UVC) += usb_f_uvc.o | 40 | obj-$(CONFIG_USB_F_UVC) += usb_f_uvc.o |
41 | usb_f_midi-y := f_midi.o | 41 | usb_f_midi-y := f_midi.o |
42 | obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o | 42 | obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o |
43 | usb_f_hid-y := f_hid.o | ||
44 | obj-$(CONFIG_USB_F_HID) += usb_f_hid.o | ||
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index ad538811c48b..f5dcf9480ba5 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/hid.h> | 14 | #include <linux/hid.h> |
15 | #include <linux/idr.h> | ||
15 | #include <linux/cdev.h> | 16 | #include <linux/cdev.h> |
16 | #include <linux/mutex.h> | 17 | #include <linux/mutex.h> |
17 | #include <linux/poll.h> | 18 | #include <linux/poll.h> |
@@ -21,9 +22,16 @@ | |||
21 | #include <linux/usb/g_hid.h> | 22 | #include <linux/usb/g_hid.h> |
22 | 23 | ||
23 | #include "u_f.h" | 24 | #include "u_f.h" |
25 | #include "u_hid.h" | ||
26 | |||
27 | #define HIDG_MINORS 4 | ||
24 | 28 | ||
25 | static int major, minors; | 29 | static int major, minors; |
26 | static struct class *hidg_class; | 30 | static struct class *hidg_class; |
31 | #ifndef USBF_HID_INCLUDED | ||
32 | static DEFINE_IDA(hidg_ida); | ||
33 | static DEFINE_MUTEX(hidg_ida_lock); /* protects access to hidg_ida */ | ||
34 | #endif | ||
27 | 35 | ||
28 | /*-------------------------------------------------------------------------*/ | 36 | /*-------------------------------------------------------------------------*/ |
29 | /* HID gadget struct */ | 37 | /* HID gadget struct */ |
@@ -161,6 +169,26 @@ static struct usb_descriptor_header *hidg_fs_descriptors[] = { | |||
161 | }; | 169 | }; |
162 | 170 | ||
163 | /*-------------------------------------------------------------------------*/ | 171 | /*-------------------------------------------------------------------------*/ |
172 | /* Strings */ | ||
173 | |||
174 | #define CT_FUNC_HID_IDX 0 | ||
175 | |||
176 | static struct usb_string ct_func_string_defs[] = { | ||
177 | [CT_FUNC_HID_IDX].s = "HID Interface", | ||
178 | {}, /* end of list */ | ||
179 | }; | ||
180 | |||
181 | static struct usb_gadget_strings ct_func_string_table = { | ||
182 | .language = 0x0409, /* en-US */ | ||
183 | .strings = ct_func_string_defs, | ||
184 | }; | ||
185 | |||
186 | static struct usb_gadget_strings *ct_func_strings[] = { | ||
187 | &ct_func_string_table, | ||
188 | NULL, | ||
189 | }; | ||
190 | |||
191 | /*-------------------------------------------------------------------------*/ | ||
164 | /* Char Device */ | 192 | /* Char Device */ |
165 | 193 | ||
166 | static ssize_t f_hidg_read(struct file *file, char __user *buffer, | 194 | static ssize_t f_hidg_read(struct file *file, char __user *buffer, |
@@ -552,7 +580,7 @@ const struct file_operations f_hidg_fops = { | |||
552 | .llseek = noop_llseek, | 580 | .llseek = noop_llseek, |
553 | }; | 581 | }; |
554 | 582 | ||
555 | static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) | 583 | static int hidg_bind(struct usb_configuration *c, struct usb_function *f) |
556 | { | 584 | { |
557 | struct usb_ep *ep; | 585 | struct usb_ep *ep; |
558 | struct f_hidg *hidg = func_to_hidg(f); | 586 | struct f_hidg *hidg = func_to_hidg(f); |
@@ -560,6 +588,15 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f) | |||
560 | int status; | 588 | int status; |
561 | dev_t dev; | 589 | dev_t dev; |
562 | 590 | ||
591 | /* maybe allocate device-global string IDs, and patch descriptors */ | ||
592 | if (ct_func_string_defs[CT_FUNC_HID_IDX].id == 0) { | ||
593 | status = usb_string_id(c->cdev); | ||
594 | if (status < 0) | ||
595 | return status; | ||
596 | ct_func_string_defs[CT_FUNC_HID_IDX].id = status; | ||
597 | hidg_interface_desc.iInterface = status; | ||
598 | } | ||
599 | |||
563 | /* allocate instance-specific interface IDs, and patch descriptors */ | 600 | /* allocate instance-specific interface IDs, and patch descriptors */ |
564 | status = usb_interface_id(c, f); | 601 | status = usb_interface_id(c, f); |
565 | if (status < 0) | 602 | if (status < 0) |
@@ -647,6 +684,7 @@ fail: | |||
647 | return status; | 684 | return status; |
648 | } | 685 | } |
649 | 686 | ||
687 | #ifdef USBF_HID_INCLUDED | ||
650 | static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) | 688 | static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) |
651 | { | 689 | { |
652 | struct f_hidg *hidg = func_to_hidg(f); | 690 | struct f_hidg *hidg = func_to_hidg(f); |
@@ -667,28 +705,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) | |||
667 | } | 705 | } |
668 | 706 | ||
669 | /*-------------------------------------------------------------------------*/ | 707 | /*-------------------------------------------------------------------------*/ |
670 | /* Strings */ | ||
671 | |||
672 | #define CT_FUNC_HID_IDX 0 | ||
673 | |||
674 | static struct usb_string ct_func_string_defs[] = { | ||
675 | [CT_FUNC_HID_IDX].s = "HID Interface", | ||
676 | {}, /* end of list */ | ||
677 | }; | ||
678 | |||
679 | static struct usb_gadget_strings ct_func_string_table = { | ||
680 | .language = 0x0409, /* en-US */ | ||
681 | .strings = ct_func_string_defs, | ||
682 | }; | ||
683 | |||
684 | static struct usb_gadget_strings *ct_func_strings[] = { | ||
685 | &ct_func_string_table, | ||
686 | NULL, | ||
687 | }; | ||
688 | |||
689 | /*-------------------------------------------------------------------------*/ | ||
690 | /* usb_configuration */ | 708 | /* usb_configuration */ |
691 | |||
692 | int __init hidg_bind_config(struct usb_configuration *c, | 709 | int __init hidg_bind_config(struct usb_configuration *c, |
693 | struct hidg_func_descriptor *fdesc, int index) | 710 | struct hidg_func_descriptor *fdesc, int index) |
694 | { | 711 | { |
@@ -698,15 +715,6 @@ int __init hidg_bind_config(struct usb_configuration *c, | |||
698 | if (index >= minors) | 715 | if (index >= minors) |
699 | return -ENOENT; | 716 | return -ENOENT; |
700 | 717 | ||
701 | /* maybe allocate device-global string IDs, and patch descriptors */ | ||
702 | if (ct_func_string_defs[CT_FUNC_HID_IDX].id == 0) { | ||
703 | status = usb_string_id(c->cdev); | ||
704 | if (status < 0) | ||
705 | return status; | ||
706 | ct_func_string_defs[CT_FUNC_HID_IDX].id = status; | ||
707 | hidg_interface_desc.iInterface = status; | ||
708 | } | ||
709 | |||
710 | /* allocate and initialize one new instance */ | 718 | /* allocate and initialize one new instance */ |
711 | hidg = kzalloc(sizeof *hidg, GFP_KERNEL); | 719 | hidg = kzalloc(sizeof *hidg, GFP_KERNEL); |
712 | if (!hidg) | 720 | if (!hidg) |
@@ -743,7 +751,153 @@ int __init hidg_bind_config(struct usb_configuration *c, | |||
743 | return status; | 751 | return status; |
744 | } | 752 | } |
745 | 753 | ||
746 | int __init ghid_setup(struct usb_gadget *g, int count) | 754 | #else |
755 | |||
756 | static inline int hidg_get_minor(void) | ||
757 | { | ||
758 | int ret; | ||
759 | |||
760 | ret = ida_simple_get(&hidg_ida, 0, 0, GFP_KERNEL); | ||
761 | |||
762 | return ret; | ||
763 | } | ||
764 | |||
765 | static inline void hidg_put_minor(int minor) | ||
766 | { | ||
767 | ida_simple_remove(&hidg_ida, minor); | ||
768 | } | ||
769 | |||
770 | static void hidg_free_inst(struct usb_function_instance *f) | ||
771 | { | ||
772 | struct f_hid_opts *opts; | ||
773 | |||
774 | opts = container_of(f, struct f_hid_opts, func_inst); | ||
775 | |||
776 | mutex_lock(&hidg_ida_lock); | ||
777 | |||
778 | hidg_put_minor(opts->minor); | ||
779 | if (idr_is_empty(&hidg_ida.idr)) | ||
780 | ghid_cleanup(); | ||
781 | |||
782 | mutex_unlock(&hidg_ida_lock); | ||
783 | |||
784 | if (opts->report_desc_alloc) | ||
785 | kfree(opts->report_desc); | ||
786 | |||
787 | kfree(opts); | ||
788 | } | ||
789 | |||
790 | static struct usb_function_instance *hidg_alloc_inst(void) | ||
791 | { | ||
792 | struct f_hid_opts *opts; | ||
793 | struct usb_function_instance *ret; | ||
794 | int status = 0; | ||
795 | |||
796 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | ||
797 | if (!opts) | ||
798 | return ERR_PTR(-ENOMEM); | ||
799 | |||
800 | opts->func_inst.free_func_inst = hidg_free_inst; | ||
801 | ret = &opts->func_inst; | ||
802 | |||
803 | mutex_lock(&hidg_ida_lock); | ||
804 | |||
805 | if (idr_is_empty(&hidg_ida.idr)) { | ||
806 | status = ghid_setup(NULL, HIDG_MINORS); | ||
807 | if (status) { | ||
808 | ret = ERR_PTR(status); | ||
809 | kfree(opts); | ||
810 | goto unlock; | ||
811 | } | ||
812 | } | ||
813 | |||
814 | opts->minor = hidg_get_minor(); | ||
815 | if (opts->minor < 0) { | ||
816 | ret = ERR_PTR(opts->minor); | ||
817 | kfree(opts); | ||
818 | if (idr_is_empty(&hidg_ida.idr)) | ||
819 | ghid_cleanup(); | ||
820 | } | ||
821 | |||
822 | unlock: | ||
823 | mutex_unlock(&hidg_ida_lock); | ||
824 | return ret; | ||
825 | } | ||
826 | |||
827 | static void hidg_free(struct usb_function *f) | ||
828 | { | ||
829 | struct f_hidg *hidg; | ||
830 | |||
831 | hidg = func_to_hidg(f); | ||
832 | kfree(hidg->report_desc); | ||
833 | kfree(hidg); | ||
834 | } | ||
835 | |||
836 | static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) | ||
837 | { | ||
838 | struct f_hidg *hidg = func_to_hidg(f); | ||
839 | |||
840 | device_destroy(hidg_class, MKDEV(major, hidg->minor)); | ||
841 | cdev_del(&hidg->cdev); | ||
842 | |||
843 | /* disable/free request and end point */ | ||
844 | usb_ep_disable(hidg->in_ep); | ||
845 | usb_ep_dequeue(hidg->in_ep, hidg->req); | ||
846 | kfree(hidg->req->buf); | ||
847 | usb_ep_free_request(hidg->in_ep, hidg->req); | ||
848 | |||
849 | usb_free_all_descriptors(f); | ||
850 | } | ||
851 | |||
852 | struct usb_function *hidg_alloc(struct usb_function_instance *fi) | ||
853 | { | ||
854 | struct f_hidg *hidg; | ||
855 | struct f_hid_opts *opts; | ||
856 | |||
857 | /* allocate and initialize one new instance */ | ||
858 | hidg = kzalloc(sizeof(*hidg), GFP_KERNEL); | ||
859 | if (!hidg) | ||
860 | return ERR_PTR(-ENOMEM); | ||
861 | |||
862 | opts = container_of(fi, struct f_hid_opts, func_inst); | ||
863 | |||
864 | hidg->minor = opts->minor; | ||
865 | hidg->bInterfaceSubClass = opts->subclass; | ||
866 | hidg->bInterfaceProtocol = opts->protocol; | ||
867 | hidg->report_length = opts->report_length; | ||
868 | hidg->report_desc_length = opts->report_desc_length; | ||
869 | if (opts->report_desc) { | ||
870 | hidg->report_desc = kmemdup(opts->report_desc, | ||
871 | opts->report_desc_length, | ||
872 | GFP_KERNEL); | ||
873 | if (!hidg->report_desc) { | ||
874 | kfree(hidg); | ||
875 | return ERR_PTR(-ENOMEM); | ||
876 | } | ||
877 | } | ||
878 | |||
879 | hidg->func.name = "hid"; | ||
880 | hidg->func.strings = ct_func_strings; | ||
881 | hidg->func.bind = hidg_bind; | ||
882 | hidg->func.unbind = hidg_unbind; | ||
883 | hidg->func.set_alt = hidg_set_alt; | ||
884 | hidg->func.disable = hidg_disable; | ||
885 | hidg->func.setup = hidg_setup; | ||
886 | hidg->func.free_func = hidg_free; | ||
887 | |||
888 | /* this could me made configurable at some point */ | ||
889 | hidg->qlen = 4; | ||
890 | |||
891 | return &hidg->func; | ||
892 | } | ||
893 | |||
894 | DECLARE_USB_FUNCTION_INIT(hid, hidg_alloc_inst, hidg_alloc); | ||
895 | MODULE_LICENSE("GPL"); | ||
896 | MODULE_AUTHOR("Fabien Chouteau"); | ||
897 | |||
898 | #endif | ||
899 | |||
900 | int ghid_setup(struct usb_gadget *g, int count) | ||
747 | { | 901 | { |
748 | int status; | 902 | int status; |
749 | dev_t dev; | 903 | dev_t dev; |
diff --git a/drivers/usb/gadget/function/u_hid.h b/drivers/usb/gadget/function/u_hid.h new file mode 100644 index 000000000000..3edfc9567ab7 --- /dev/null +++ b/drivers/usb/gadget/function/u_hid.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * u_hid.h | ||
3 | * | ||
4 | * Utility definitions for the hid function | ||
5 | * | ||
6 | * Copyright (c) 2014 Samsung Electronics Co., Ltd. | ||
7 | * http://www.samsung.com | ||
8 | * | ||
9 | * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #ifndef U_HID_H | ||
17 | #define U_HID_H | ||
18 | |||
19 | #include <linux/usb/composite.h> | ||
20 | |||
21 | struct f_hid_opts { | ||
22 | struct usb_function_instance func_inst; | ||
23 | int minor; | ||
24 | unsigned char subclass; | ||
25 | unsigned char protocol; | ||
26 | unsigned short report_length; | ||
27 | unsigned short report_desc_length; | ||
28 | unsigned char *report_desc; | ||
29 | bool report_desc_alloc; | ||
30 | }; | ||
31 | |||
32 | int ghid_setup(struct usb_gadget *g, int count); | ||
33 | void ghid_cleanup(void); | ||
34 | |||
35 | #endif /* U_HID_H */ | ||
diff --git a/drivers/usb/gadget/legacy/hid.c b/drivers/usb/gadget/legacy/hid.c index fba80a25260b..26cb4ea2aaf7 100644 --- a/drivers/usb/gadget/legacy/hid.c +++ b/drivers/usb/gadget/legacy/hid.c | |||
@@ -36,6 +36,7 @@ | |||
36 | * the runtime footprint, and giving us at least some parts of what | 36 | * the runtime footprint, and giving us at least some parts of what |
37 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. | 37 | * a "gcc --combine ... part1.c part2.c part3.c ... " build would. |
38 | */ | 38 | */ |
39 | #define USBF_HID_INCLUDED | ||
39 | #include "f_hid.c" | 40 | #include "f_hid.c" |
40 | 41 | ||
41 | 42 | ||