diff options
| author | Oliver Neukum <oneukum@suse.com> | 2016-07-14 09:41:30 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-07-18 11:46:57 -0400 |
| commit | e4c6fb779498243ec001c5547b3504fe6b1993ec (patch) | |
| tree | f9cb73a1017afbd0962ee2c4fbd3c6179d17b744 /drivers/usb/core | |
| parent | a1ca2c6b2924a602bb19dce7390a6e9604dd45bf (diff) | |
usbnet: move the CDC parser into USB core
The dependencies were impossible to handle preventing
drivers for CDC devices not which are not network drivers
from using the common parser.
Signed-off-by: Oliver Neukum <ONeukum@suse.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core')
| -rw-r--r-- | drivers/usb/core/message.c | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index ea681f157368..0406a59f0551 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <linux/nls.h> | 12 | #include <linux/nls.h> |
| 13 | #include <linux/device.h> | 13 | #include <linux/device.h> |
| 14 | #include <linux/scatterlist.h> | 14 | #include <linux/scatterlist.h> |
| 15 | #include <linux/usb/cdc.h> | ||
| 15 | #include <linux/usb/quirks.h> | 16 | #include <linux/usb/quirks.h> |
| 16 | #include <linux/usb/hcd.h> /* for usbcore internals */ | 17 | #include <linux/usb/hcd.h> /* for usbcore internals */ |
| 17 | #include <asm/byteorder.h> | 18 | #include <asm/byteorder.h> |
| @@ -2023,3 +2024,155 @@ int usb_driver_set_configuration(struct usb_device *udev, int config) | |||
| 2023 | return 0; | 2024 | return 0; |
| 2024 | } | 2025 | } |
| 2025 | EXPORT_SYMBOL_GPL(usb_driver_set_configuration); | 2026 | EXPORT_SYMBOL_GPL(usb_driver_set_configuration); |
| 2027 | |||
| 2028 | /** | ||
| 2029 | * cdc_parse_cdc_header - parse the extra headers present in CDC devices | ||
| 2030 | * @hdr: the place to put the results of the parsing | ||
| 2031 | * @intf: the interface for which parsing is requested | ||
| 2032 | * @buffer: pointer to the extra headers to be parsed | ||
| 2033 | * @buflen: length of the extra headers | ||
| 2034 | * | ||
| 2035 | * This evaluates the extra headers present in CDC devices which | ||
| 2036 | * bind the interfaces for data and control and provide details | ||
| 2037 | * about the capabilities of the device. | ||
| 2038 | * | ||
| 2039 | * Return: number of descriptors parsed or -EINVAL | ||
| 2040 | * if the header is contradictory beyond salvage | ||
| 2041 | */ | ||
| 2042 | |||
| 2043 | int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr, | ||
| 2044 | struct usb_interface *intf, | ||
| 2045 | u8 *buffer, | ||
| 2046 | int buflen) | ||
| 2047 | { | ||
| 2048 | /* duplicates are ignored */ | ||
| 2049 | struct usb_cdc_union_desc *union_header = NULL; | ||
| 2050 | |||
| 2051 | /* duplicates are not tolerated */ | ||
| 2052 | struct usb_cdc_header_desc *header = NULL; | ||
| 2053 | struct usb_cdc_ether_desc *ether = NULL; | ||
| 2054 | struct usb_cdc_mdlm_detail_desc *detail = NULL; | ||
| 2055 | struct usb_cdc_mdlm_desc *desc = NULL; | ||
| 2056 | |||
| 2057 | unsigned int elength; | ||
| 2058 | int cnt = 0; | ||
| 2059 | |||
| 2060 | memset(hdr, 0x00, sizeof(struct usb_cdc_parsed_header)); | ||
| 2061 | hdr->phonet_magic_present = false; | ||
| 2062 | while (buflen > 0) { | ||
| 2063 | elength = buffer[0]; | ||
| 2064 | if (!elength) { | ||
| 2065 | dev_err(&intf->dev, "skipping garbage byte\n"); | ||
| 2066 | elength = 1; | ||
| 2067 | goto next_desc; | ||
| 2068 | } | ||
| 2069 | if (buffer[1] != USB_DT_CS_INTERFACE) { | ||
| 2070 | dev_err(&intf->dev, "skipping garbage\n"); | ||
| 2071 | goto next_desc; | ||
| 2072 | } | ||
| 2073 | |||
| 2074 | switch (buffer[2]) { | ||
| 2075 | case USB_CDC_UNION_TYPE: /* we've found it */ | ||
| 2076 | if (elength < sizeof(struct usb_cdc_union_desc)) | ||
| 2077 | goto next_desc; | ||
| 2078 | if (union_header) { | ||
| 2079 | dev_err(&intf->dev, "More than one union descriptor, skipping ...\n"); | ||
| 2080 | goto next_desc; | ||
| 2081 | } | ||
| 2082 | union_header = (struct usb_cdc_union_desc *)buffer; | ||
| 2083 | break; | ||
| 2084 | case USB_CDC_COUNTRY_TYPE: | ||
| 2085 | if (elength < sizeof(struct usb_cdc_country_functional_desc)) | ||
| 2086 | goto next_desc; | ||
| 2087 | hdr->usb_cdc_country_functional_desc = | ||
| 2088 | (struct usb_cdc_country_functional_desc *)buffer; | ||
| 2089 | break; | ||
| 2090 | case USB_CDC_HEADER_TYPE: | ||
| 2091 | if (elength != sizeof(struct usb_cdc_header_desc)) | ||
| 2092 | goto next_desc; | ||
| 2093 | if (header) | ||
| 2094 | return -EINVAL; | ||
| 2095 | header = (struct usb_cdc_header_desc *)buffer; | ||
| 2096 | break; | ||
| 2097 | case USB_CDC_ACM_TYPE: | ||
| 2098 | if (elength < sizeof(struct usb_cdc_acm_descriptor)) | ||
| 2099 | goto next_desc; | ||
| 2100 | hdr->usb_cdc_acm_descriptor = | ||
| 2101 | (struct usb_cdc_acm_descriptor *)buffer; | ||
| 2102 | break; | ||
| 2103 | case USB_CDC_ETHERNET_TYPE: | ||
| 2104 | if (elength != sizeof(struct usb_cdc_ether_desc)) | ||
| 2105 | goto next_desc; | ||
| 2106 | if (ether) | ||
| 2107 | return -EINVAL; | ||
| 2108 | ether = (struct usb_cdc_ether_desc *)buffer; | ||
| 2109 | break; | ||
| 2110 | case USB_CDC_CALL_MANAGEMENT_TYPE: | ||
| 2111 | if (elength < sizeof(struct usb_cdc_call_mgmt_descriptor)) | ||
| 2112 | goto next_desc; | ||
| 2113 | hdr->usb_cdc_call_mgmt_descriptor = | ||
| 2114 | (struct usb_cdc_call_mgmt_descriptor *)buffer; | ||
| 2115 | break; | ||
| 2116 | case USB_CDC_DMM_TYPE: | ||
| 2117 | if (elength < sizeof(struct usb_cdc_dmm_desc)) | ||
| 2118 | goto next_desc; | ||
| 2119 | hdr->usb_cdc_dmm_desc = | ||
| 2120 | (struct usb_cdc_dmm_desc *)buffer; | ||
| 2121 | break; | ||
| 2122 | case USB_CDC_MDLM_TYPE: | ||
| 2123 | if (elength < sizeof(struct usb_cdc_mdlm_desc *)) | ||
| 2124 | goto next_desc; | ||
| 2125 | if (desc) | ||
| 2126 | return -EINVAL; | ||
| 2127 | desc = (struct usb_cdc_mdlm_desc *)buffer; | ||
| 2128 | break; | ||
| 2129 | case USB_CDC_MDLM_DETAIL_TYPE: | ||
| 2130 | if (elength < sizeof(struct usb_cdc_mdlm_detail_desc *)) | ||
| 2131 | goto next_desc; | ||
| 2132 | if (detail) | ||
| 2133 | return -EINVAL; | ||
| 2134 | detail = (struct usb_cdc_mdlm_detail_desc *)buffer; | ||
| 2135 | break; | ||
| 2136 | case USB_CDC_NCM_TYPE: | ||
| 2137 | if (elength < sizeof(struct usb_cdc_ncm_desc)) | ||
| 2138 | goto next_desc; | ||
| 2139 | hdr->usb_cdc_ncm_desc = (struct usb_cdc_ncm_desc *)buffer; | ||
| 2140 | break; | ||
| 2141 | case USB_CDC_MBIM_TYPE: | ||
| 2142 | if (elength < sizeof(struct usb_cdc_mbim_desc)) | ||
| 2143 | goto next_desc; | ||
| 2144 | |||
| 2145 | hdr->usb_cdc_mbim_desc = (struct usb_cdc_mbim_desc *)buffer; | ||
| 2146 | break; | ||
| 2147 | case USB_CDC_MBIM_EXTENDED_TYPE: | ||
| 2148 | if (elength < sizeof(struct usb_cdc_mbim_extended_desc)) | ||
| 2149 | break; | ||
| 2150 | hdr->usb_cdc_mbim_extended_desc = | ||
| 2151 | (struct usb_cdc_mbim_extended_desc *)buffer; | ||
| 2152 | break; | ||
| 2153 | case CDC_PHONET_MAGIC_NUMBER: | ||
| 2154 | hdr->phonet_magic_present = true; | ||
| 2155 | break; | ||
| 2156 | default: | ||
| 2157 | /* | ||
| 2158 | * there are LOTS more CDC descriptors that | ||
| 2159 | * could legitimately be found here. | ||
| 2160 | */ | ||
| 2161 | dev_dbg(&intf->dev, "Ignoring descriptor: type %02x, length %ud\n", | ||
| 2162 | buffer[2], elength); | ||
| 2163 | goto next_desc; | ||
| 2164 | } | ||
| 2165 | cnt++; | ||
| 2166 | next_desc: | ||
| 2167 | buflen -= elength; | ||
| 2168 | buffer += elength; | ||
| 2169 | } | ||
| 2170 | hdr->usb_cdc_union_desc = union_header; | ||
| 2171 | hdr->usb_cdc_header_desc = header; | ||
| 2172 | hdr->usb_cdc_mdlm_detail_desc = detail; | ||
| 2173 | hdr->usb_cdc_mdlm_desc = desc; | ||
| 2174 | hdr->usb_cdc_ether_desc = ether; | ||
| 2175 | return cnt; | ||
| 2176 | } | ||
| 2177 | |||
| 2178 | EXPORT_SYMBOL(cdc_parse_cdc_header); | ||
