diff options
author | Andrzej Pietrasiewicz <andrzej.p@samsung.com> | 2013-05-28 03:15:57 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-06-10 10:58:08 -0400 |
commit | f466c6353819326873fa48a02c6f2d7c903240d6 (patch) | |
tree | b478bb450e13710092e5808cd2c6b5335951cebc /drivers/usb/gadget/f_rndis.c | |
parent | 02832e56f88a981474ee4c7c141f46fc1b4454f4 (diff) |
usb: gadget: f_rndis: convert to new function interface with backward compatibility
Converting rndis to the new function interface requires converting
the USB rndis' function code and its users.
This patch converts the f_rndis.c to the new function interface.
The file is now compiled into a separate usb_f_rndis.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: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/f_rndis.c')
-rw-r--r-- | drivers/usb/gadget/f_rndis.c | 203 |
1 files changed, 175 insertions, 28 deletions
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 36e8c44d8e5e..437198b6d8fa 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c | |||
@@ -17,15 +17,16 @@ | |||
17 | 17 | ||
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/module.h> | ||
20 | #include <linux/device.h> | 21 | #include <linux/device.h> |
21 | #include <linux/etherdevice.h> | 22 | #include <linux/etherdevice.h> |
22 | 23 | ||
23 | #include <linux/atomic.h> | 24 | #include <linux/atomic.h> |
24 | 25 | ||
25 | #include "u_ether.h" | 26 | #include "u_ether.h" |
27 | #include "u_rndis.h" | ||
26 | #include "rndis.h" | 28 | #include "rndis.h" |
27 | 29 | ||
28 | |||
29 | /* | 30 | /* |
30 | * This function is an RNDIS Ethernet port -- a Microsoft protocol that's | 31 | * This function is an RNDIS Ethernet port -- a Microsoft protocol that's |
31 | * been promoted instead of the standard CDC Ethernet. The published RNDIS | 32 | * been promoted instead of the standard CDC Ethernet. The published RNDIS |
@@ -655,6 +656,13 @@ static void rndis_close(struct gether *geth) | |||
655 | 656 | ||
656 | /*-------------------------------------------------------------------------*/ | 657 | /*-------------------------------------------------------------------------*/ |
657 | 658 | ||
659 | /* Some controllers can't support RNDIS ... */ | ||
660 | static inline bool can_support_rndis(struct usb_configuration *c) | ||
661 | { | ||
662 | /* everything else is *presumably* fine */ | ||
663 | return true; | ||
664 | } | ||
665 | |||
658 | /* ethernet function driver setup/binding */ | 666 | /* ethernet function driver setup/binding */ |
659 | 667 | ||
660 | static int | 668 | static int |
@@ -665,6 +673,45 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) | |||
665 | int status; | 673 | int status; |
666 | struct usb_ep *ep; | 674 | struct usb_ep *ep; |
667 | 675 | ||
676 | #ifndef USB_FRNDIS_INCLUDED | ||
677 | struct f_rndis_opts *rndis_opts; | ||
678 | |||
679 | if (!can_support_rndis(c)) | ||
680 | return -EINVAL; | ||
681 | |||
682 | rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst); | ||
683 | |||
684 | /* | ||
685 | * in drivers/usb/gadget/configfs.c:configfs_composite_bind() | ||
686 | * configurations are bound in sequence with list_for_each_entry, | ||
687 | * in each configuration its functions are bound in sequence | ||
688 | * with list_for_each_entry, so we assume no race condition | ||
689 | * with regard to rndis_opts->bound access | ||
690 | */ | ||
691 | if (!rndis_opts->bound) { | ||
692 | gether_set_gadget(rndis_opts->net, cdev->gadget); | ||
693 | status = gether_register_netdev(rndis_opts->net); | ||
694 | if (status) | ||
695 | return status; | ||
696 | rndis_opts->bound = true; | ||
697 | } | ||
698 | #endif | ||
699 | |||
700 | if (rndis_string_defs[0].id == 0) { | ||
701 | /* ... and setup RNDIS itself */ | ||
702 | status = rndis_init(); | ||
703 | if (status < 0) | ||
704 | return status; | ||
705 | |||
706 | status = usb_string_ids_tab(c->cdev, rndis_string_defs); | ||
707 | if (status) | ||
708 | return status; | ||
709 | |||
710 | rndis_control_intf.iInterface = rndis_string_defs[0].id; | ||
711 | rndis_data_intf.iInterface = rndis_string_defs[1].id; | ||
712 | rndis_iad_descriptor.iFunction = rndis_string_defs[2].id; | ||
713 | } | ||
714 | |||
668 | /* allocate instance-specific interface IDs */ | 715 | /* allocate instance-specific interface IDs */ |
669 | status = usb_interface_id(c, f); | 716 | status = usb_interface_id(c, f); |
670 | if (status < 0) | 717 | if (status < 0) |
@@ -741,10 +788,12 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) | |||
741 | rndis->port.open = rndis_open; | 788 | rndis->port.open = rndis_open; |
742 | rndis->port.close = rndis_close; | 789 | rndis->port.close = rndis_close; |
743 | 790 | ||
791 | #ifdef USB_FRNDIS_INCLUDED | ||
744 | status = rndis_register(rndis_response_available, rndis); | 792 | status = rndis_register(rndis_response_available, rndis); |
745 | if (status < 0) | 793 | if (status < 0) |
746 | goto fail; | 794 | goto fail; |
747 | rndis->config = status; | 795 | rndis->config = status; |
796 | #endif | ||
748 | 797 | ||
749 | rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0); | 798 | rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0); |
750 | rndis_set_host_mac(rndis->config, rndis->ethaddr); | 799 | rndis_set_host_mac(rndis->config, rndis->ethaddr); |
@@ -787,8 +836,10 @@ fail: | |||
787 | return status; | 836 | return status; |
788 | } | 837 | } |
789 | 838 | ||
839 | #ifdef USB_FRNDIS_INCLUDED | ||
840 | |||
790 | static void | 841 | static void |
791 | rndis_unbind(struct usb_configuration *c, struct usb_function *f) | 842 | rndis_old_unbind(struct usb_configuration *c, struct usb_function *f) |
792 | { | 843 | { |
793 | struct f_rndis *rndis = func_to_rndis(f); | 844 | struct f_rndis *rndis = func_to_rndis(f); |
794 | 845 | ||
@@ -804,13 +855,6 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f) | |||
804 | kfree(rndis); | 855 | kfree(rndis); |
805 | } | 856 | } |
806 | 857 | ||
807 | /* Some controllers can't support RNDIS ... */ | ||
808 | static inline bool can_support_rndis(struct usb_configuration *c) | ||
809 | { | ||
810 | /* everything else is *presumably* fine */ | ||
811 | return true; | ||
812 | } | ||
813 | |||
814 | int | 858 | int |
815 | rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], | 859 | rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], |
816 | u32 vendorID, const char *manufacturer, struct eth_dev *dev) | 860 | u32 vendorID, const char *manufacturer, struct eth_dev *dev) |
@@ -818,24 +862,6 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], | |||
818 | struct f_rndis *rndis; | 862 | struct f_rndis *rndis; |
819 | int status; | 863 | int status; |
820 | 864 | ||
821 | if (!can_support_rndis(c) || !ethaddr) | ||
822 | return -EINVAL; | ||
823 | |||
824 | if (rndis_string_defs[0].id == 0) { | ||
825 | /* ... and setup RNDIS itself */ | ||
826 | status = rndis_init(); | ||
827 | if (status < 0) | ||
828 | return status; | ||
829 | |||
830 | status = usb_string_ids_tab(c->cdev, rndis_string_defs); | ||
831 | if (status) | ||
832 | return status; | ||
833 | |||
834 | rndis_control_intf.iInterface = rndis_string_defs[0].id; | ||
835 | rndis_data_intf.iInterface = rndis_string_defs[1].id; | ||
836 | rndis_iad_descriptor.iFunction = rndis_string_defs[2].id; | ||
837 | } | ||
838 | |||
839 | /* allocate and initialize one new instance */ | 865 | /* allocate and initialize one new instance */ |
840 | status = -ENOMEM; | 866 | status = -ENOMEM; |
841 | rndis = kzalloc(sizeof *rndis, GFP_KERNEL); | 867 | rndis = kzalloc(sizeof *rndis, GFP_KERNEL); |
@@ -859,7 +885,7 @@ rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], | |||
859 | rndis->port.func.strings = rndis_strings; | 885 | rndis->port.func.strings = rndis_strings; |
860 | /* descriptors are per-instance copies */ | 886 | /* descriptors are per-instance copies */ |
861 | rndis->port.func.bind = rndis_bind; | 887 | rndis->port.func.bind = rndis_bind; |
862 | rndis->port.func.unbind = rndis_unbind; | 888 | rndis->port.func.unbind = rndis_old_unbind; |
863 | rndis->port.func.set_alt = rndis_set_alt; | 889 | rndis->port.func.set_alt = rndis_set_alt; |
864 | rndis->port.func.setup = rndis_setup; | 890 | rndis->port.func.setup = rndis_setup; |
865 | rndis->port.func.disable = rndis_disable; | 891 | rndis->port.func.disable = rndis_disable; |
@@ -872,3 +898,124 @@ fail: | |||
872 | } | 898 | } |
873 | return status; | 899 | return status; |
874 | } | 900 | } |
901 | |||
902 | #else | ||
903 | |||
904 | void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net) | ||
905 | { | ||
906 | struct f_rndis_opts *opts; | ||
907 | |||
908 | opts = container_of(f, struct f_rndis_opts, func_inst); | ||
909 | if (opts->bound) | ||
910 | gether_cleanup(netdev_priv(opts->net)); | ||
911 | else | ||
912 | free_netdev(opts->net); | ||
913 | opts->borrowed_net = opts->bound = true; | ||
914 | opts->net = net; | ||
915 | } | ||
916 | EXPORT_SYMBOL(rndis_borrow_net); | ||
917 | |||
918 | static void rndis_free_inst(struct usb_function_instance *f) | ||
919 | { | ||
920 | struct f_rndis_opts *opts; | ||
921 | |||
922 | opts = container_of(f, struct f_rndis_opts, func_inst); | ||
923 | if (!opts->borrowed_net) { | ||
924 | if (opts->bound) | ||
925 | gether_cleanup(netdev_priv(opts->net)); | ||
926 | else | ||
927 | free_netdev(opts->net); | ||
928 | } | ||
929 | kfree(opts); | ||
930 | } | ||
931 | |||
932 | static struct usb_function_instance *rndis_alloc_inst(void) | ||
933 | { | ||
934 | struct f_rndis_opts *opts; | ||
935 | |||
936 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | ||
937 | if (!opts) | ||
938 | return ERR_PTR(-ENOMEM); | ||
939 | |||
940 | opts->func_inst.free_func_inst = rndis_free_inst; | ||
941 | opts->net = gether_setup_default(); | ||
942 | if (IS_ERR(opts->net)) | ||
943 | return ERR_CAST(opts->net); | ||
944 | |||
945 | return &opts->func_inst; | ||
946 | } | ||
947 | |||
948 | static void rndis_free(struct usb_function *f) | ||
949 | { | ||
950 | struct f_rndis *rndis; | ||
951 | |||
952 | rndis = func_to_rndis(f); | ||
953 | rndis_deregister(rndis->config); | ||
954 | kfree(rndis); | ||
955 | } | ||
956 | |||
957 | static void rndis_unbind(struct usb_configuration *c, struct usb_function *f) | ||
958 | { | ||
959 | struct f_rndis *rndis = func_to_rndis(f); | ||
960 | |||
961 | rndis_exit(); | ||
962 | rndis_string_defs[0].id = 0; | ||
963 | usb_free_all_descriptors(f); | ||
964 | |||
965 | kfree(rndis->notify_req->buf); | ||
966 | usb_ep_free_request(rndis->notify, rndis->notify_req); | ||
967 | } | ||
968 | |||
969 | static struct usb_function *rndis_alloc(struct usb_function_instance *fi) | ||
970 | { | ||
971 | struct f_rndis *rndis; | ||
972 | struct f_rndis_opts *opts; | ||
973 | int status; | ||
974 | |||
975 | /* allocate and initialize one new instance */ | ||
976 | rndis = kzalloc(sizeof(*rndis), GFP_KERNEL); | ||
977 | if (!rndis) { | ||
978 | rndis_exit(); | ||
979 | return ERR_PTR(-ENOMEM); | ||
980 | } | ||
981 | |||
982 | opts = container_of(fi, struct f_rndis_opts, func_inst); | ||
983 | |||
984 | gether_get_host_addr_u8(opts->net, rndis->ethaddr); | ||
985 | rndis->vendorID = opts->vendor_id; | ||
986 | rndis->manufacturer = opts->manufacturer; | ||
987 | |||
988 | rndis->port.ioport = netdev_priv(opts->net); | ||
989 | /* RNDIS activates when the host changes this filter */ | ||
990 | rndis->port.cdc_filter = 0; | ||
991 | |||
992 | /* RNDIS has special (and complex) framing */ | ||
993 | rndis->port.header_len = sizeof(struct rndis_packet_msg_type); | ||
994 | rndis->port.wrap = rndis_add_header; | ||
995 | rndis->port.unwrap = rndis_rm_hdr; | ||
996 | |||
997 | rndis->port.func.name = "rndis"; | ||
998 | rndis->port.func.strings = rndis_strings; | ||
999 | /* descriptors are per-instance copies */ | ||
1000 | rndis->port.func.bind = rndis_bind; | ||
1001 | rndis->port.func.unbind = rndis_unbind; | ||
1002 | rndis->port.func.set_alt = rndis_set_alt; | ||
1003 | rndis->port.func.setup = rndis_setup; | ||
1004 | rndis->port.func.disable = rndis_disable; | ||
1005 | rndis->port.func.free_func = rndis_free; | ||
1006 | |||
1007 | status = rndis_register(rndis_response_available, rndis); | ||
1008 | if (status < 0) { | ||
1009 | kfree(rndis); | ||
1010 | return ERR_PTR(status); | ||
1011 | } | ||
1012 | rndis->config = status; | ||
1013 | |||
1014 | return &rndis->port.func; | ||
1015 | } | ||
1016 | |||
1017 | DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc); | ||
1018 | MODULE_LICENSE("GPL"); | ||
1019 | MODULE_AUTHOR("David Brownell"); | ||
1020 | |||
1021 | #endif | ||