diff options
Diffstat (limited to 'drivers/usb/gadget/f_rndis.c')
-rw-r--r-- | drivers/usb/gadget/f_rndis.c | 101 |
1 files changed, 98 insertions, 3 deletions
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index b324efa07733..8f3eae90919f 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c | |||
@@ -95,10 +95,12 @@ static inline struct f_rndis *func_to_rndis(struct usb_function *f) | |||
95 | /* peak (theoretical) bulk transfer rate in bits-per-second */ | 95 | /* peak (theoretical) bulk transfer rate in bits-per-second */ |
96 | static unsigned int bitrate(struct usb_gadget *g) | 96 | static unsigned int bitrate(struct usb_gadget *g) |
97 | { | 97 | { |
98 | if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) | 98 | if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER) |
99 | return 13 * 1024 * 8 * 1000 * 8; | ||
100 | else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) | ||
99 | return 13 * 512 * 8 * 1000 * 8; | 101 | return 13 * 512 * 8 * 1000 * 8; |
100 | else | 102 | else |
101 | return 19 * 64 * 1 * 1000 * 8; | 103 | return 19 * 64 * 1 * 1000 * 8; |
102 | } | 104 | } |
103 | 105 | ||
104 | /*-------------------------------------------------------------------------*/ | 106 | /*-------------------------------------------------------------------------*/ |
@@ -216,6 +218,7 @@ static struct usb_endpoint_descriptor fs_out_desc = { | |||
216 | 218 | ||
217 | static struct usb_descriptor_header *eth_fs_function[] = { | 219 | static struct usb_descriptor_header *eth_fs_function[] = { |
218 | (struct usb_descriptor_header *) &rndis_iad_descriptor, | 220 | (struct usb_descriptor_header *) &rndis_iad_descriptor, |
221 | |||
219 | /* control interface matches ACM, not Ethernet */ | 222 | /* control interface matches ACM, not Ethernet */ |
220 | (struct usb_descriptor_header *) &rndis_control_intf, | 223 | (struct usb_descriptor_header *) &rndis_control_intf, |
221 | (struct usb_descriptor_header *) &header_desc, | 224 | (struct usb_descriptor_header *) &header_desc, |
@@ -223,6 +226,7 @@ static struct usb_descriptor_header *eth_fs_function[] = { | |||
223 | (struct usb_descriptor_header *) &rndis_acm_descriptor, | 226 | (struct usb_descriptor_header *) &rndis_acm_descriptor, |
224 | (struct usb_descriptor_header *) &rndis_union_desc, | 227 | (struct usb_descriptor_header *) &rndis_union_desc, |
225 | (struct usb_descriptor_header *) &fs_notify_desc, | 228 | (struct usb_descriptor_header *) &fs_notify_desc, |
229 | |||
226 | /* data interface has no altsetting */ | 230 | /* data interface has no altsetting */ |
227 | (struct usb_descriptor_header *) &rndis_data_intf, | 231 | (struct usb_descriptor_header *) &rndis_data_intf, |
228 | (struct usb_descriptor_header *) &fs_in_desc, | 232 | (struct usb_descriptor_header *) &fs_in_desc, |
@@ -241,6 +245,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = { | |||
241 | .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), | 245 | .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), |
242 | .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, | 246 | .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, |
243 | }; | 247 | }; |
248 | |||
244 | static struct usb_endpoint_descriptor hs_in_desc = { | 249 | static struct usb_endpoint_descriptor hs_in_desc = { |
245 | .bLength = USB_DT_ENDPOINT_SIZE, | 250 | .bLength = USB_DT_ENDPOINT_SIZE, |
246 | .bDescriptorType = USB_DT_ENDPOINT, | 251 | .bDescriptorType = USB_DT_ENDPOINT, |
@@ -261,6 +266,7 @@ static struct usb_endpoint_descriptor hs_out_desc = { | |||
261 | 266 | ||
262 | static struct usb_descriptor_header *eth_hs_function[] = { | 267 | static struct usb_descriptor_header *eth_hs_function[] = { |
263 | (struct usb_descriptor_header *) &rndis_iad_descriptor, | 268 | (struct usb_descriptor_header *) &rndis_iad_descriptor, |
269 | |||
264 | /* control interface matches ACM, not Ethernet */ | 270 | /* control interface matches ACM, not Ethernet */ |
265 | (struct usb_descriptor_header *) &rndis_control_intf, | 271 | (struct usb_descriptor_header *) &rndis_control_intf, |
266 | (struct usb_descriptor_header *) &header_desc, | 272 | (struct usb_descriptor_header *) &header_desc, |
@@ -268,6 +274,7 @@ static struct usb_descriptor_header *eth_hs_function[] = { | |||
268 | (struct usb_descriptor_header *) &rndis_acm_descriptor, | 274 | (struct usb_descriptor_header *) &rndis_acm_descriptor, |
269 | (struct usb_descriptor_header *) &rndis_union_desc, | 275 | (struct usb_descriptor_header *) &rndis_union_desc, |
270 | (struct usb_descriptor_header *) &hs_notify_desc, | 276 | (struct usb_descriptor_header *) &hs_notify_desc, |
277 | |||
271 | /* data interface has no altsetting */ | 278 | /* data interface has no altsetting */ |
272 | (struct usb_descriptor_header *) &rndis_data_intf, | 279 | (struct usb_descriptor_header *) &rndis_data_intf, |
273 | (struct usb_descriptor_header *) &hs_in_desc, | 280 | (struct usb_descriptor_header *) &hs_in_desc, |
@@ -275,6 +282,76 @@ static struct usb_descriptor_header *eth_hs_function[] = { | |||
275 | NULL, | 282 | NULL, |
276 | }; | 283 | }; |
277 | 284 | ||
285 | /* super speed support: */ | ||
286 | |||
287 | static struct usb_endpoint_descriptor ss_notify_desc = { | ||
288 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
289 | .bDescriptorType = USB_DT_ENDPOINT, | ||
290 | |||
291 | .bEndpointAddress = USB_DIR_IN, | ||
292 | .bmAttributes = USB_ENDPOINT_XFER_INT, | ||
293 | .wMaxPacketSize = cpu_to_le16(STATUS_BYTECOUNT), | ||
294 | .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, | ||
295 | }; | ||
296 | |||
297 | static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = { | ||
298 | .bLength = sizeof ss_intr_comp_desc, | ||
299 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, | ||
300 | |||
301 | /* the following 3 values can be tweaked if necessary */ | ||
302 | /* .bMaxBurst = 0, */ | ||
303 | /* .bmAttributes = 0, */ | ||
304 | .wBytesPerInterval = cpu_to_le16(STATUS_BYTECOUNT), | ||
305 | }; | ||
306 | |||
307 | static struct usb_endpoint_descriptor ss_in_desc = { | ||
308 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
309 | .bDescriptorType = USB_DT_ENDPOINT, | ||
310 | |||
311 | .bEndpointAddress = USB_DIR_IN, | ||
312 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
313 | .wMaxPacketSize = cpu_to_le16(1024), | ||
314 | }; | ||
315 | |||
316 | static struct usb_endpoint_descriptor ss_out_desc = { | ||
317 | .bLength = USB_DT_ENDPOINT_SIZE, | ||
318 | .bDescriptorType = USB_DT_ENDPOINT, | ||
319 | |||
320 | .bEndpointAddress = USB_DIR_OUT, | ||
321 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | ||
322 | .wMaxPacketSize = cpu_to_le16(1024), | ||
323 | }; | ||
324 | |||
325 | static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = { | ||
326 | .bLength = sizeof ss_bulk_comp_desc, | ||
327 | .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, | ||
328 | |||
329 | /* the following 2 values can be tweaked if necessary */ | ||
330 | /* .bMaxBurst = 0, */ | ||
331 | /* .bmAttributes = 0, */ | ||
332 | }; | ||
333 | |||
334 | static struct usb_descriptor_header *eth_ss_function[] = { | ||
335 | (struct usb_descriptor_header *) &rndis_iad_descriptor, | ||
336 | |||
337 | /* control interface matches ACM, not Ethernet */ | ||
338 | (struct usb_descriptor_header *) &rndis_control_intf, | ||
339 | (struct usb_descriptor_header *) &header_desc, | ||
340 | (struct usb_descriptor_header *) &call_mgmt_descriptor, | ||
341 | (struct usb_descriptor_header *) &rndis_acm_descriptor, | ||
342 | (struct usb_descriptor_header *) &rndis_union_desc, | ||
343 | (struct usb_descriptor_header *) &ss_notify_desc, | ||
344 | (struct usb_descriptor_header *) &ss_intr_comp_desc, | ||
345 | |||
346 | /* data interface has no altsetting */ | ||
347 | (struct usb_descriptor_header *) &rndis_data_intf, | ||
348 | (struct usb_descriptor_header *) &ss_in_desc, | ||
349 | (struct usb_descriptor_header *) &ss_bulk_comp_desc, | ||
350 | (struct usb_descriptor_header *) &ss_out_desc, | ||
351 | (struct usb_descriptor_header *) &ss_bulk_comp_desc, | ||
352 | NULL, | ||
353 | }; | ||
354 | |||
278 | /* string descriptors: */ | 355 | /* string descriptors: */ |
279 | 356 | ||
280 | static struct usb_string rndis_string_defs[] = { | 357 | static struct usb_string rndis_string_defs[] = { |
@@ -670,11 +747,24 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) | |||
670 | 747 | ||
671 | /* copy descriptors, and track endpoint copies */ | 748 | /* copy descriptors, and track endpoint copies */ |
672 | f->hs_descriptors = usb_copy_descriptors(eth_hs_function); | 749 | f->hs_descriptors = usb_copy_descriptors(eth_hs_function); |
673 | |||
674 | if (!f->hs_descriptors) | 750 | if (!f->hs_descriptors) |
675 | goto fail; | 751 | goto fail; |
676 | } | 752 | } |
677 | 753 | ||
754 | if (gadget_is_superspeed(c->cdev->gadget)) { | ||
755 | ss_in_desc.bEndpointAddress = | ||
756 | fs_in_desc.bEndpointAddress; | ||
757 | ss_out_desc.bEndpointAddress = | ||
758 | fs_out_desc.bEndpointAddress; | ||
759 | ss_notify_desc.bEndpointAddress = | ||
760 | fs_notify_desc.bEndpointAddress; | ||
761 | |||
762 | /* copy descriptors, and track endpoint copies */ | ||
763 | f->ss_descriptors = usb_copy_descriptors(eth_ss_function); | ||
764 | if (!f->ss_descriptors) | ||
765 | goto fail; | ||
766 | } | ||
767 | |||
678 | rndis->port.open = rndis_open; | 768 | rndis->port.open = rndis_open; |
679 | rndis->port.close = rndis_close; | 769 | rndis->port.close = rndis_close; |
680 | 770 | ||
@@ -699,12 +789,15 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) | |||
699 | */ | 789 | */ |
700 | 790 | ||
701 | DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n", | 791 | DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n", |
792 | gadget_is_superspeed(c->cdev->gadget) ? "super" : | ||
702 | gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", | 793 | gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full", |
703 | rndis->port.in_ep->name, rndis->port.out_ep->name, | 794 | rndis->port.in_ep->name, rndis->port.out_ep->name, |
704 | rndis->notify->name); | 795 | rndis->notify->name); |
705 | return 0; | 796 | return 0; |
706 | 797 | ||
707 | fail: | 798 | fail: |
799 | if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors) | ||
800 | usb_free_descriptors(f->ss_descriptors); | ||
708 | if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors) | 801 | if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors) |
709 | usb_free_descriptors(f->hs_descriptors); | 802 | usb_free_descriptors(f->hs_descriptors); |
710 | if (f->descriptors) | 803 | if (f->descriptors) |
@@ -736,6 +829,8 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f) | |||
736 | rndis_deregister(rndis->config); | 829 | rndis_deregister(rndis->config); |
737 | rndis_exit(); | 830 | rndis_exit(); |
738 | 831 | ||
832 | if (gadget_is_superspeed(c->cdev->gadget)) | ||
833 | usb_free_descriptors(f->ss_descriptors); | ||
739 | if (gadget_is_dualspeed(c->cdev->gadget)) | 834 | if (gadget_is_dualspeed(c->cdev->gadget)) |
740 | usb_free_descriptors(f->hs_descriptors); | 835 | usb_free_descriptors(f->hs_descriptors); |
741 | usb_free_descriptors(f->descriptors); | 836 | usb_free_descriptors(f->descriptors); |