diff options
Diffstat (limited to 'drivers/usb/gadget/f_obex.c')
-rw-r--r-- | drivers/usb/gadget/f_obex.c | 226 |
1 files changed, 180 insertions, 46 deletions
diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c index 36a004563b82..29a348a2a294 100644 --- a/drivers/usb/gadget/f_obex.c +++ b/drivers/usb/gadget/f_obex.c | |||
@@ -72,7 +72,7 @@ static struct usb_gadget_strings *obex_strings[] = { | |||
72 | 72 | ||
73 | /*-------------------------------------------------------------------------*/ | 73 | /*-------------------------------------------------------------------------*/ |
74 | 74 | ||
75 | static struct usb_interface_descriptor obex_control_intf __initdata = { | 75 | static struct usb_interface_descriptor obex_control_intf = { |
76 | .bLength = sizeof(obex_control_intf), | 76 | .bLength = sizeof(obex_control_intf), |
77 | .bDescriptorType = USB_DT_INTERFACE, | 77 | .bDescriptorType = USB_DT_INTERFACE, |
78 | .bInterfaceNumber = 0, | 78 | .bInterfaceNumber = 0, |
@@ -83,7 +83,7 @@ static struct usb_interface_descriptor obex_control_intf __initdata = { | |||
83 | .bInterfaceSubClass = USB_CDC_SUBCLASS_OBEX, | 83 | .bInterfaceSubClass = USB_CDC_SUBCLASS_OBEX, |
84 | }; | 84 | }; |
85 | 85 | ||
86 | static struct usb_interface_descriptor obex_data_nop_intf __initdata = { | 86 | static struct usb_interface_descriptor obex_data_nop_intf = { |
87 | .bLength = sizeof(obex_data_nop_intf), | 87 | .bLength = sizeof(obex_data_nop_intf), |
88 | .bDescriptorType = USB_DT_INTERFACE, | 88 | .bDescriptorType = USB_DT_INTERFACE, |
89 | .bInterfaceNumber = 1, | 89 | .bInterfaceNumber = 1, |
@@ -93,7 +93,7 @@ static struct usb_interface_descriptor obex_data_nop_intf __initdata = { | |||
93 | .bInterfaceClass = USB_CLASS_CDC_DATA, | 93 | .bInterfaceClass = USB_CLASS_CDC_DATA, |
94 | }; | 94 | }; |
95 | 95 | ||
96 | static struct usb_interface_descriptor obex_data_intf __initdata = { | 96 | static struct usb_interface_descriptor obex_data_intf = { |
97 | .bLength = sizeof(obex_data_intf), | 97 | .bLength = sizeof(obex_data_intf), |
98 | .bDescriptorType = USB_DT_INTERFACE, | 98 | .bDescriptorType = USB_DT_INTERFACE, |
99 | .bInterfaceNumber = 2, | 99 | .bInterfaceNumber = 2, |
@@ -103,14 +103,14 @@ static struct usb_interface_descriptor obex_data_intf __initdata = { | |||
103 | .bInterfaceClass = USB_CLASS_CDC_DATA, | 103 | .bInterfaceClass = USB_CLASS_CDC_DATA, |
104 | }; | 104 | }; |
105 | 105 | ||
106 | static struct usb_cdc_header_desc obex_cdc_header_desc __initdata = { | 106 | static struct usb_cdc_header_desc obex_cdc_header_desc = { |
107 | .bLength = sizeof(obex_cdc_header_desc), | 107 | .bLength = sizeof(obex_cdc_header_desc), |
108 | .bDescriptorType = USB_DT_CS_INTERFACE, | 108 | .bDescriptorType = USB_DT_CS_INTERFACE, |
109 | .bDescriptorSubType = USB_CDC_HEADER_TYPE, | 109 | .bDescriptorSubType = USB_CDC_HEADER_TYPE, |
110 | .bcdCDC = cpu_to_le16(0x0120), | 110 | .bcdCDC = cpu_to_le16(0x0120), |
111 | }; | 111 | }; |
112 | 112 | ||
113 | static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = { | 113 | static struct usb_cdc_union_desc obex_cdc_union_desc = { |
114 | .bLength = sizeof(obex_cdc_union_desc), | 114 | .bLength = sizeof(obex_cdc_union_desc), |
115 | .bDescriptorType = USB_DT_CS_INTERFACE, | 115 | .bDescriptorType = USB_DT_CS_INTERFACE, |
116 | .bDescriptorSubType = USB_CDC_UNION_TYPE, | 116 | .bDescriptorSubType = USB_CDC_UNION_TYPE, |
@@ -118,7 +118,7 @@ static struct usb_cdc_union_desc obex_cdc_union_desc __initdata = { | |||
118 | .bSlaveInterface0 = 2, | 118 | .bSlaveInterface0 = 2, |
119 | }; | 119 | }; |
120 | 120 | ||
121 | static struct usb_cdc_obex_desc obex_desc __initdata = { | 121 | static struct usb_cdc_obex_desc obex_desc = { |
122 | .bLength = sizeof(obex_desc), | 122 | .bLength = sizeof(obex_desc), |
123 | .bDescriptorType = USB_DT_CS_INTERFACE, | 123 | .bDescriptorType = USB_DT_CS_INTERFACE, |
124 | .bDescriptorSubType = USB_CDC_OBEX_TYPE, | 124 | .bDescriptorSubType = USB_CDC_OBEX_TYPE, |
@@ -127,7 +127,7 @@ static struct usb_cdc_obex_desc obex_desc __initdata = { | |||
127 | 127 | ||
128 | /* High-Speed Support */ | 128 | /* High-Speed Support */ |
129 | 129 | ||
130 | static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = { | 130 | static struct usb_endpoint_descriptor obex_hs_ep_out_desc = { |
131 | .bLength = USB_DT_ENDPOINT_SIZE, | 131 | .bLength = USB_DT_ENDPOINT_SIZE, |
132 | .bDescriptorType = USB_DT_ENDPOINT, | 132 | .bDescriptorType = USB_DT_ENDPOINT, |
133 | 133 | ||
@@ -136,7 +136,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_out_desc __initdata = { | |||
136 | .wMaxPacketSize = cpu_to_le16(512), | 136 | .wMaxPacketSize = cpu_to_le16(512), |
137 | }; | 137 | }; |
138 | 138 | ||
139 | static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = { | 139 | static struct usb_endpoint_descriptor obex_hs_ep_in_desc = { |
140 | .bLength = USB_DT_ENDPOINT_SIZE, | 140 | .bLength = USB_DT_ENDPOINT_SIZE, |
141 | .bDescriptorType = USB_DT_ENDPOINT, | 141 | .bDescriptorType = USB_DT_ENDPOINT, |
142 | 142 | ||
@@ -145,7 +145,7 @@ static struct usb_endpoint_descriptor obex_hs_ep_in_desc __initdata = { | |||
145 | .wMaxPacketSize = cpu_to_le16(512), | 145 | .wMaxPacketSize = cpu_to_le16(512), |
146 | }; | 146 | }; |
147 | 147 | ||
148 | static struct usb_descriptor_header *hs_function[] __initdata = { | 148 | static struct usb_descriptor_header *hs_function[] = { |
149 | (struct usb_descriptor_header *) &obex_control_intf, | 149 | (struct usb_descriptor_header *) &obex_control_intf, |
150 | (struct usb_descriptor_header *) &obex_cdc_header_desc, | 150 | (struct usb_descriptor_header *) &obex_cdc_header_desc, |
151 | (struct usb_descriptor_header *) &obex_desc, | 151 | (struct usb_descriptor_header *) &obex_desc, |
@@ -160,7 +160,7 @@ static struct usb_descriptor_header *hs_function[] __initdata = { | |||
160 | 160 | ||
161 | /* Full-Speed Support */ | 161 | /* Full-Speed Support */ |
162 | 162 | ||
163 | static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = { | 163 | static struct usb_endpoint_descriptor obex_fs_ep_in_desc = { |
164 | .bLength = USB_DT_ENDPOINT_SIZE, | 164 | .bLength = USB_DT_ENDPOINT_SIZE, |
165 | .bDescriptorType = USB_DT_ENDPOINT, | 165 | .bDescriptorType = USB_DT_ENDPOINT, |
166 | 166 | ||
@@ -168,7 +168,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_in_desc __initdata = { | |||
168 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 168 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
169 | }; | 169 | }; |
170 | 170 | ||
171 | static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = { | 171 | static struct usb_endpoint_descriptor obex_fs_ep_out_desc = { |
172 | .bLength = USB_DT_ENDPOINT_SIZE, | 172 | .bLength = USB_DT_ENDPOINT_SIZE, |
173 | .bDescriptorType = USB_DT_ENDPOINT, | 173 | .bDescriptorType = USB_DT_ENDPOINT, |
174 | 174 | ||
@@ -176,7 +176,7 @@ static struct usb_endpoint_descriptor obex_fs_ep_out_desc __initdata = { | |||
176 | .bmAttributes = USB_ENDPOINT_XFER_BULK, | 176 | .bmAttributes = USB_ENDPOINT_XFER_BULK, |
177 | }; | 177 | }; |
178 | 178 | ||
179 | static struct usb_descriptor_header *fs_function[] __initdata = { | 179 | static struct usb_descriptor_header *fs_function[] = { |
180 | (struct usb_descriptor_header *) &obex_control_intf, | 180 | (struct usb_descriptor_header *) &obex_control_intf, |
181 | (struct usb_descriptor_header *) &obex_cdc_header_desc, | 181 | (struct usb_descriptor_header *) &obex_cdc_header_desc, |
182 | (struct usb_descriptor_header *) &obex_desc, | 182 | (struct usb_descriptor_header *) &obex_desc, |
@@ -290,14 +290,43 @@ static void obex_disconnect(struct gserial *g) | |||
290 | 290 | ||
291 | /*-------------------------------------------------------------------------*/ | 291 | /*-------------------------------------------------------------------------*/ |
292 | 292 | ||
293 | static int __init | 293 | /* Some controllers can't support CDC OBEX ... */ |
294 | obex_bind(struct usb_configuration *c, struct usb_function *f) | 294 | static inline bool can_support_obex(struct usb_configuration *c) |
295 | { | ||
296 | /* Since the first interface is a NOP, we can ignore the | ||
297 | * issue of multi-interface support on most controllers. | ||
298 | * | ||
299 | * Altsettings are mandatory, however... | ||
300 | */ | ||
301 | if (!gadget_supports_altsettings(c->cdev->gadget)) | ||
302 | return false; | ||
303 | |||
304 | /* everything else is *probably* fine ... */ | ||
305 | return true; | ||
306 | } | ||
307 | |||
308 | static int obex_bind(struct usb_configuration *c, struct usb_function *f) | ||
295 | { | 309 | { |
296 | struct usb_composite_dev *cdev = c->cdev; | 310 | struct usb_composite_dev *cdev = c->cdev; |
297 | struct f_obex *obex = func_to_obex(f); | 311 | struct f_obex *obex = func_to_obex(f); |
298 | int status; | 312 | int status; |
299 | struct usb_ep *ep; | 313 | struct usb_ep *ep; |
300 | 314 | ||
315 | if (!can_support_obex(c)) | ||
316 | return -EINVAL; | ||
317 | |||
318 | if (obex_string_defs[OBEX_CTRL_IDX].id == 0) { | ||
319 | status = usb_string_ids_tab(c->cdev, obex_string_defs); | ||
320 | if (status < 0) | ||
321 | return status; | ||
322 | obex_control_intf.iInterface = | ||
323 | obex_string_defs[OBEX_CTRL_IDX].id; | ||
324 | |||
325 | status = obex_string_defs[OBEX_DATA_IDX].id; | ||
326 | obex_data_nop_intf.iInterface = status; | ||
327 | obex_data_intf.iInterface = status; | ||
328 | } | ||
329 | |||
301 | /* allocate instance-specific interface IDs, and patch descriptors */ | 330 | /* allocate instance-specific interface IDs, and patch descriptors */ |
302 | 331 | ||
303 | status = usb_interface_id(c, f); | 332 | status = usb_interface_id(c, f); |
@@ -376,29 +405,16 @@ fail: | |||
376 | return status; | 405 | return status; |
377 | } | 406 | } |
378 | 407 | ||
408 | #ifdef USBF_OBEX_INCLUDED | ||
409 | |||
379 | static void | 410 | static void |
380 | obex_unbind(struct usb_configuration *c, struct usb_function *f) | 411 | obex_old_unbind(struct usb_configuration *c, struct usb_function *f) |
381 | { | 412 | { |
382 | obex_string_defs[OBEX_CTRL_IDX].id = 0; | 413 | obex_string_defs[OBEX_CTRL_IDX].id = 0; |
383 | usb_free_all_descriptors(f); | 414 | usb_free_all_descriptors(f); |
384 | kfree(func_to_obex(f)); | 415 | kfree(func_to_obex(f)); |
385 | } | 416 | } |
386 | 417 | ||
387 | /* Some controllers can't support CDC OBEX ... */ | ||
388 | static inline bool can_support_obex(struct usb_configuration *c) | ||
389 | { | ||
390 | /* Since the first interface is a NOP, we can ignore the | ||
391 | * issue of multi-interface support on most controllers. | ||
392 | * | ||
393 | * Altsettings are mandatory, however... | ||
394 | */ | ||
395 | if (!gadget_supports_altsettings(c->cdev->gadget)) | ||
396 | return false; | ||
397 | |||
398 | /* everything else is *probably* fine ... */ | ||
399 | return true; | ||
400 | } | ||
401 | |||
402 | /** | 418 | /** |
403 | * obex_bind_config - add a CDC OBEX function to a configuration | 419 | * obex_bind_config - add a CDC OBEX function to a configuration |
404 | * @c: the configuration to support the CDC OBEX instance | 420 | * @c: the configuration to support the CDC OBEX instance |
@@ -412,21 +428,6 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num) | |||
412 | struct f_obex *obex; | 428 | struct f_obex *obex; |
413 | int status; | 429 | int status; |
414 | 430 | ||
415 | if (!can_support_obex(c)) | ||
416 | return -EINVAL; | ||
417 | |||
418 | if (obex_string_defs[OBEX_CTRL_IDX].id == 0) { | ||
419 | status = usb_string_ids_tab(c->cdev, obex_string_defs); | ||
420 | if (status < 0) | ||
421 | return status; | ||
422 | obex_control_intf.iInterface = | ||
423 | obex_string_defs[OBEX_CTRL_IDX].id; | ||
424 | |||
425 | status = obex_string_defs[OBEX_DATA_IDX].id; | ||
426 | obex_data_nop_intf.iInterface = status; | ||
427 | obex_data_intf.iInterface = status; | ||
428 | } | ||
429 | |||
430 | /* allocate and initialize one new instance */ | 431 | /* allocate and initialize one new instance */ |
431 | obex = kzalloc(sizeof *obex, GFP_KERNEL); | 432 | obex = kzalloc(sizeof *obex, GFP_KERNEL); |
432 | if (!obex) | 433 | if (!obex) |
@@ -441,7 +442,7 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num) | |||
441 | obex->port.func.strings = obex_strings; | 442 | obex->port.func.strings = obex_strings; |
442 | /* descriptors are per-instance copies */ | 443 | /* descriptors are per-instance copies */ |
443 | obex->port.func.bind = obex_bind; | 444 | obex->port.func.bind = obex_bind; |
444 | obex->port.func.unbind = obex_unbind; | 445 | obex->port.func.unbind = obex_old_unbind; |
445 | obex->port.func.set_alt = obex_set_alt; | 446 | obex->port.func.set_alt = obex_set_alt; |
446 | obex->port.func.get_alt = obex_get_alt; | 447 | obex->port.func.get_alt = obex_get_alt; |
447 | obex->port.func.disable = obex_disable; | 448 | obex->port.func.disable = obex_disable; |
@@ -453,5 +454,138 @@ int __init obex_bind_config(struct usb_configuration *c, u8 port_num) | |||
453 | return status; | 454 | return status; |
454 | } | 455 | } |
455 | 456 | ||
457 | #else | ||
458 | |||
459 | static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item) | ||
460 | { | ||
461 | return container_of(to_config_group(item), struct f_serial_opts, | ||
462 | func_inst.group); | ||
463 | } | ||
464 | |||
465 | CONFIGFS_ATTR_STRUCT(f_serial_opts); | ||
466 | static ssize_t f_obex_attr_show(struct config_item *item, | ||
467 | struct configfs_attribute *attr, | ||
468 | char *page) | ||
469 | { | ||
470 | struct f_serial_opts *opts = to_f_serial_opts(item); | ||
471 | struct f_serial_opts_attribute *f_serial_opts_attr = | ||
472 | container_of(attr, struct f_serial_opts_attribute, attr); | ||
473 | ssize_t ret = 0; | ||
474 | |||
475 | if (f_serial_opts_attr->show) | ||
476 | ret = f_serial_opts_attr->show(opts, page); | ||
477 | |||
478 | return ret; | ||
479 | } | ||
480 | |||
481 | static void obex_attr_release(struct config_item *item) | ||
482 | { | ||
483 | struct f_serial_opts *opts = to_f_serial_opts(item); | ||
484 | |||
485 | usb_put_function_instance(&opts->func_inst); | ||
486 | } | ||
487 | |||
488 | static struct configfs_item_operations obex_item_ops = { | ||
489 | .release = obex_attr_release, | ||
490 | .show_attribute = f_obex_attr_show, | ||
491 | }; | ||
492 | |||
493 | static ssize_t f_obex_port_num_show(struct f_serial_opts *opts, char *page) | ||
494 | { | ||
495 | return sprintf(page, "%u\n", opts->port_num); | ||
496 | } | ||
497 | |||
498 | static struct f_serial_opts_attribute f_obex_port_num = | ||
499 | __CONFIGFS_ATTR_RO(port_num, f_obex_port_num_show); | ||
500 | |||
501 | static struct configfs_attribute *acm_attrs[] = { | ||
502 | &f_obex_port_num.attr, | ||
503 | NULL, | ||
504 | }; | ||
505 | |||
506 | static struct config_item_type obex_func_type = { | ||
507 | .ct_item_ops = &obex_item_ops, | ||
508 | .ct_attrs = acm_attrs, | ||
509 | .ct_owner = THIS_MODULE, | ||
510 | }; | ||
511 | |||
512 | static void obex_free_inst(struct usb_function_instance *f) | ||
513 | { | ||
514 | struct f_serial_opts *opts; | ||
515 | |||
516 | opts = container_of(f, struct f_serial_opts, func_inst); | ||
517 | gserial_free_line(opts->port_num); | ||
518 | kfree(opts); | ||
519 | } | ||
520 | |||
521 | static struct usb_function_instance *obex_alloc_inst(void) | ||
522 | { | ||
523 | struct f_serial_opts *opts; | ||
524 | int ret; | ||
525 | |||
526 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | ||
527 | if (!opts) | ||
528 | return ERR_PTR(-ENOMEM); | ||
529 | |||
530 | opts->func_inst.free_func_inst = obex_free_inst; | ||
531 | ret = gserial_alloc_line(&opts->port_num); | ||
532 | if (ret) { | ||
533 | kfree(opts); | ||
534 | return ERR_PTR(ret); | ||
535 | } | ||
536 | config_group_init_type_name(&opts->func_inst.group, "", | ||
537 | &obex_func_type); | ||
538 | |||
539 | return &opts->func_inst; | ||
540 | } | ||
541 | |||
542 | static void obex_free(struct usb_function *f) | ||
543 | { | ||
544 | struct f_obex *obex; | ||
545 | |||
546 | obex = func_to_obex(f); | ||
547 | kfree(obex); | ||
548 | } | ||
549 | |||
550 | static void obex_unbind(struct usb_configuration *c, struct usb_function *f) | ||
551 | { | ||
552 | obex_string_defs[OBEX_CTRL_IDX].id = 0; | ||
553 | usb_free_all_descriptors(f); | ||
554 | } | ||
555 | |||
556 | struct usb_function *obex_alloc(struct usb_function_instance *fi) | ||
557 | { | ||
558 | struct f_obex *obex; | ||
559 | struct f_serial_opts *opts; | ||
560 | |||
561 | /* allocate and initialize one new instance */ | ||
562 | obex = kzalloc(sizeof(*obex), GFP_KERNEL); | ||
563 | if (!obex) | ||
564 | return ERR_PTR(-ENOMEM); | ||
565 | |||
566 | opts = container_of(fi, struct f_serial_opts, func_inst); | ||
567 | |||
568 | obex->port_num = opts->port_num; | ||
569 | |||
570 | obex->port.connect = obex_connect; | ||
571 | obex->port.disconnect = obex_disconnect; | ||
572 | |||
573 | obex->port.func.name = "obex"; | ||
574 | obex->port.func.strings = obex_strings; | ||
575 | /* descriptors are per-instance copies */ | ||
576 | obex->port.func.bind = obex_bind; | ||
577 | obex->port.func.unbind = obex_unbind; | ||
578 | obex->port.func.set_alt = obex_set_alt; | ||
579 | obex->port.func.get_alt = obex_get_alt; | ||
580 | obex->port.func.disable = obex_disable; | ||
581 | obex->port.func.free_func = obex_free; | ||
582 | |||
583 | return &obex->port.func; | ||
584 | } | ||
585 | |||
586 | DECLARE_USB_FUNCTION_INIT(obex, obex_alloc_inst, obex_alloc); | ||
587 | |||
588 | #endif | ||
589 | |||
456 | MODULE_AUTHOR("Felipe Balbi"); | 590 | MODULE_AUTHOR("Felipe Balbi"); |
457 | MODULE_LICENSE("GPL"); | 591 | MODULE_LICENSE("GPL"); |