Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1325342 > unrolled thread
| Started by | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| First post | 2016-02-03 13:50 +0100 |
| Last post | 2016-02-03 14:00 +0100 |
| Articles | 20 on this page of 44 — 2 participants |
Back to article view | Back to linux.kernel
[PATCH v4 00/43] usb: gadget: composite: introduce new function API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 10/43] usb: gadget: composite: handle vendor descs Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 16/43] usb: gadget: composite: add usb_function_get_ep() function Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 24/43] usb: gadget: f_rndis: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 18/43] usb: gadget: composite: usb_get_endpoint_address() function Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 06/43] usb: gadget: composite: introduce new descriptors format Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
Re: [PATCH v4 06/43] usb: gadget: composite: introduce new descriptors format kbuild test robot <lkp@intel.com> - 2016-02-04 06:20 +0100
[PATCH v4 15/43] usb: gadget: composite: handle get_alt() automatically Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 04/43] usb: gadget: configfs: fix error path Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 37/43] usb: gadget: f_mass_storage: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 23/43] usb: gadget: f_ecm: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 02/43] usb: gadget: f_sourcesink: free requests in sourcesink_disable() Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 13/43] usb: gadget: composite: enable eps before calling set_alt() callback Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 32/43] usb: gadget: f_obex: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 20/43] usb: gadget: configfs: add new composite API support Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 27/43] usb: gadget: f_acm: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 26/43] usb: gadget: f_hid: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 30/43] usb: gadget: f_printer: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 08/43] usb: gadget: composite: introduce new USB function ops Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 35/43] usb: gadget: f_uac1: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 31/43] usb: gadget: f_serial: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 42/43] Documentation: update uvc configfs interface description Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 43/43] usb: gadget: f_uvc: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 25/43] usb: gadget: f_hid: handle requests lifetime properly Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 03/43] usb: gadget: f_loopback: free requests in loopback_disable() Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 38/43] usb: gadget: u_serial: remove usb_ep_enable()/usb_ep_disable() Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 34/43] usb: gadget: f_subset: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 29/43] usb: gadget: f_ncm: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 22/43] usb: gadget: f_sourcesink: convert to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 39/43] usb: gadget: u_ether: remove usb_ep_enable()/usb_ep_disable() Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 40/43] usb: gadget: uvc: fix typo in UVCG_OPTS_ATTR() macro Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 36/43] usb: gadget: f_uac2: conversion to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 41/43] usb: gadget: uvc: simplify descriptors generation Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 13:50 +0100
[PATCH v4 09/43] usb: gadget: composite: handle function bind Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 14:00 +0100
Re: [PATCH v4 09/43] usb: gadget: composite: handle function bind kbuild test robot <lkp@intel.com> - 2016-02-04 06:50 +0100
[PATCH v4 01/43] usb: gadget: f_sourcesink: make ISO altset user-selectable Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 14:00 +0100
[PATCH v4 12/43] usb: gadget: composite: disable eps before calling disable() callback Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 14:00 +0100
[PATCH v4 17/43] usb: gadget: composite: add usb_get_interface_id() function Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 14:00 +0100
[PATCH v4 19/43] usb: gadget: composite: enable adding USB functions using new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 14:00 +0100
[PATCH v4 05/43] usb: gadget: composite: fix recursive spinlock locking Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 14:00 +0100
[PATCH v4 21/43] usb: gadget: f_loopback: convert to new API Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 14:00 +0100
[PATCH v4 14/43] usb: gadget: composite: introduce clear_alt() operation Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 14:00 +0100
[PATCH v4 11/43] usb: gadget: composite: generate old descs for compatibility Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 14:00 +0100
[PATCH v4 07/43] usb: gadget: composite: add functions for descriptors handling Robert Baldyga <r.baldyga@samsung.com> - 2016-02-03 14:00 +0100
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 13:50 +0100 |
| Subject | [PATCH v4 31/43] usb: gadget: f_serial: conversion to new API |
| Message-ID | <qY52I-212-63@gated-at.bofh.it> |
| In reply to | #1325342 |
Generate descriptors in new format and attach them to USB function in
prep_descs(). Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/function/f_serial.c | 122 +++++++--------------------------
1 file changed, 25 insertions(+), 97 deletions(-)
diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c
index 6bb44d61..526e664 100644
--- a/drivers/usb/gadget/function/f_serial.c
+++ b/drivers/usb/gadget/function/f_serial.c
@@ -69,13 +69,6 @@ static struct usb_endpoint_descriptor gser_fs_out_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_descriptor_header *gser_fs_function[] = {
- (struct usb_descriptor_header *) &gser_interface_desc,
- (struct usb_descriptor_header *) &gser_fs_in_desc,
- (struct usb_descriptor_header *) &gser_fs_out_desc,
- NULL,
-};
-
/* high speed support: */
static struct usb_endpoint_descriptor gser_hs_in_desc = {
@@ -92,13 +85,6 @@ static struct usb_endpoint_descriptor gser_hs_out_desc = {
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_descriptor_header *gser_hs_function[] = {
- (struct usb_descriptor_header *) &gser_interface_desc,
- (struct usb_descriptor_header *) &gser_hs_in_desc,
- (struct usb_descriptor_header *) &gser_hs_out_desc,
- NULL,
-};
-
static struct usb_endpoint_descriptor gser_ss_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -118,14 +104,16 @@ static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc = {
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
};
-static struct usb_descriptor_header *gser_ss_function[] = {
- (struct usb_descriptor_header *) &gser_interface_desc,
- (struct usb_descriptor_header *) &gser_ss_in_desc,
- (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
- (struct usb_descriptor_header *) &gser_ss_out_desc,
- (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
- NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_in, &gser_fs_in_desc, &gser_hs_in_desc,
+ &gser_ss_in_desc, &gser_ss_bulk_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_out, &gser_fs_out_desc, &gser_hs_out_desc,
+ &gser_ss_out_desc, &gser_ss_bulk_comp_desc);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &gser_interface_desc, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+
+USB_COMPOSITE_DESCRIPTORS(serial_descs, &intf0);
/* string descriptors: */
@@ -151,28 +139,21 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
struct f_gser *gser = func_to_gser(f);
struct usb_composite_dev *cdev = f->config->cdev;
- /* we know alt == 0, so this is an activation or a reset */
-
- if (gser->port.in->enabled) {
- dev_dbg(&cdev->gadget->dev,
- "reset generic ttyGS%d\n", gser->port_num);
- gserial_disconnect(&gser->port);
- }
- if (!gser->port.in->desc || !gser->port.out->desc) {
- dev_dbg(&cdev->gadget->dev,
+ dev_dbg(&cdev->gadget->dev,
"activate generic ttyGS%d\n", gser->port_num);
- if (config_ep_by_speed(cdev->gadget, f, gser->port.in) ||
- config_ep_by_speed(cdev->gadget, f, gser->port.out)) {
- gser->port.in->desc = NULL;
- gser->port.out->desc = NULL;
- return -EINVAL;
- }
- }
+
+ gser->port.in = usb_function_get_ep(f, intf, 0);
+ if (!gser->port.in)
+ return -ENODEV;
+ gser->port.out = usb_function_get_ep(f, intf, 0);
+ if (!gser->port.out)
+ return -ENODEV;
+
gserial_connect(&gser->port, gser->port_num);
return 0;
}
-static void gser_disable(struct usb_function *f)
+static void gser_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct f_gser *gser = func_to_gser(f);
struct usb_composite_dev *cdev = f->config->cdev;
@@ -186,12 +167,9 @@ static void gser_disable(struct usb_function *f)
/* serial function driver setup/binding */
-static int gser_bind(struct usb_configuration *c, struct usb_function *f)
+static int gser_prep_descs(struct usb_function *f)
{
- struct usb_composite_dev *cdev = c->cdev;
- struct f_gser *gser = func_to_gser(f);
int status;
- struct usb_ep *ep;
/* REVISIT might want instance-specific strings to help
* distinguish instances ...
@@ -199,57 +177,13 @@ static int gser_bind(struct usb_configuration *c, struct usb_function *f)
/* maybe allocate device-global string ID */
if (gser_string_defs[0].id == 0) {
- status = usb_string_id(c->cdev);
+ status = usb_string_id(f->config->cdev);
if (status < 0)
return status;
gser_string_defs[0].id = status;
}
- /* allocate instance-specific interface IDs */
- status = usb_interface_id(c, f);
- if (status < 0)
- goto fail;
- gser->data_id = status;
- gser_interface_desc.bInterfaceNumber = status;
-
- status = -ENODEV;
-
- /* allocate instance-specific endpoints */
- ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_in_desc);
- if (!ep)
- goto fail;
- gser->port.in = ep;
-
- ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
- if (!ep)
- goto fail;
- gser->port.out = ep;
-
- /* support all relevant hardware speeds... we expect that when
- * hardware is dual speed, all bulk-capable endpoints work at
- * both speeds
- */
- gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
- gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
-
- gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
- gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
-
- status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function,
- gser_ss_function);
- if (status)
- goto fail;
- dev_dbg(&cdev->gadget->dev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
- gser->port_num,
- gadget_is_superspeed(c->cdev->gadget) ? "super" :
- gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
- gser->port.in->name, gser->port.out->name);
- return 0;
-
-fail:
- ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
-
- return status;
+ return usb_function_set_descs(f, &serial_descs);
}
static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
@@ -325,11 +259,6 @@ static void gser_free(struct usb_function *f)
kfree(serial);
}
-static void gser_unbind(struct usb_configuration *c, struct usb_function *f)
-{
- usb_free_all_descriptors(f);
-}
-
static struct usb_function *gser_alloc(struct usb_function_instance *fi)
{
struct f_gser *gser;
@@ -346,10 +275,9 @@ static struct usb_function *gser_alloc(struct usb_function_instance *fi)
gser->port.func.name = "gser";
gser->port.func.strings = gser_strings;
- gser->port.func.bind = gser_bind;
- gser->port.func.unbind = gser_unbind;
+ gser->port.func.prep_descs = gser_prep_descs;
gser->port.func.set_alt = gser_set_alt;
- gser->port.func.disable = gser_disable;
+ gser->port.func.clear_alt = gser_clear_alt;
gser->port.func.free_func = gser_free;
return &gser->port.func;
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 13:50 +0100 |
| Subject | [PATCH v4 42/43] Documentation: update uvc configfs interface description |
| Message-ID | <qY52I-212-61@gated-at.bofh.it> |
| In reply to | #1325342 |
Update documentation to reflect changes in UVC configfs interface. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> --- Documentation/ABI/testing/configfs-usb-gadget-uvc | 39 ++++------------------- Documentation/usb/gadget-testing.txt | 18 +++-------- 2 files changed, 12 insertions(+), 45 deletions(-) diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index 2f4a005..a765437 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -12,20 +12,10 @@ Date: Dec 2014 KernelVersion: 3.20 Description: Control descriptors -What: /config/usb-gadget/gadget/functions/uvc.name/control/class -Date: Dec 2014 -KernelVersion: 3.20 -Description: Class descriptors - -What: /config/usb-gadget/gadget/functions/uvc.name/control/class/ss -Date: Dec 2014 -KernelVersion: 3.20 -Description: Super speed control class descriptors - -What: /config/usb-gadget/gadget/functions/uvc.name/control/class/fs -Date: Dec 2014 -KernelVersion: 3.20 -Description: Full speed control class descriptors +What: /config/usb-gadget/gadget/functions/uvc.name/control/desc +Date: Jan 2015 +KernelVersion: 4.4 +Description: Control class descriptors What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal Date: Dec 2014 @@ -109,26 +99,11 @@ Date: Dec 2014 KernelVersion: 3.20 Description: Streaming descriptors -What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class -Date: Dec 2014 -KernelVersion: 3.20 +What: /config/usb-gadget/gadget/functions/uvc.name/streaming/desc +Date: Jan 2015 +KernelVersion: 4,4 Description: Streaming class descriptors -What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/ss -Date: Dec 2014 -KernelVersion: 3.20 -Description: Super speed streaming class descriptors - -What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/hs -Date: Dec 2014 -KernelVersion: 3.20 -Description: High speed streaming class descriptors - -What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/fs -Date: Dec 2014 -KernelVersion: 3.20 -Description: Full speed streaming class descriptors - What: /config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching Date: Dec 2014 KernelVersion: 3.20 diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt index 5819605..5643719 100644 --- a/Documentation/usb/gadget-testing.txt +++ b/Documentation/usb/gadget-testing.txt @@ -674,11 +674,8 @@ There are also "control" and "streaming" subdirectories, each of which contain a number of their subdirectories. There are some sane defaults provided, but the user must provide the following: - control header - create in control/header, link from control/class/fs - and/or control/class/ss - streaming header - create in streaming/header, link from - streaming/class/fs and/or streaming/class/hs and/or - streaming/class/ss + control header - create in control/header, link from control/desc + streaming header - create in streaming/header, link from streaming/desc format description - create in streaming/mjpeg and/or streaming/uncompressed frame description - create in streaming/mjpeg/<format> and/or in @@ -690,8 +687,7 @@ in each line. The rules stated above are best illustrated with an example: # mkdir functions/uvc.usb0/control/header/h # cd functions/uvc.usb0/control/header/h -# ln -s header/h class/fs -# ln -s header/h class/ss +# ln -s header/h desc # mkdir -p functions/uvc.usb0/streaming/uncompressed/u/360p # cat <<EOF > functions/uvc.usb0/streaming/uncompressed/u/360p/dwFrameInterval 666666 @@ -702,12 +698,8 @@ EOF # mkdir functions/uvc.usb0/streaming/header/h # cd functions/uvc.usb0/streaming/header/h # ln -s ../../uncompressed/u -# cd ../../class/fs -# ln -s ../../header/h -# cd ../../class/hs -# ln -s ../../header/h -# cd ../../class/ss -# ln -s ../../header/h +# cd ../../desc +# ln -s ../header/h Testing the UVC function -- 1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 13:50 +0100 |
| Subject | [PATCH v4 43/43] usb: gadget: f_uvc: conversion to new API |
| Message-ID | <qY52I-212-65@gated-at.bofh.it> |
| In reply to | #1325342 |
Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Get rid of get_alt() callback, as now USB_REQ_GET_INTERFACE
is handled automatically by composite framwework. Remove boilerplate
code.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/function/f_uvc.c | 478 ++++++++++++------------------------
drivers/usb/gadget/function/uvc.h | 3 -
2 files changed, 160 insertions(+), 321 deletions(-)
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 0f554c4..04ca1f9 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -179,24 +179,19 @@ static struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = {
*/
};
-static const struct usb_descriptor_header * const uvc_fs_streaming[] = {
- (struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
- (struct usb_descriptor_header *) &uvc_fs_streaming_ep,
- NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_control, &uvc_control_ep, &uvc_control_ep,
+ &uvc_control_ep, &uvc_ss_control_comp);
+USB_COMPOSITE_ENDPOINT(ep_streaming, &uvc_fs_streaming_ep, &uvc_hs_streaming_ep,
+ &uvc_ss_streaming_ep, &uvc_ss_streaming_comp);
-static const struct usb_descriptor_header * const uvc_hs_streaming[] = {
- (struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
- (struct usb_descriptor_header *) &uvc_hs_streaming_ep,
- NULL,
-};
+USB_COMPOSITE_ALTSETTING(intf0alt0, &uvc_control_intf, &ep_control);
+USB_COMPOSITE_ALTSETTING(intf1alt0, &uvc_streaming_intf_alt0);
+USB_COMPOSITE_ALTSETTING(intf1alt1, &uvc_streaming_intf_alt1, &ep_streaming);
-static const struct usb_descriptor_header * const uvc_ss_streaming[] = {
- (struct usb_descriptor_header *) &uvc_streaming_intf_alt1,
- (struct usb_descriptor_header *) &uvc_ss_streaming_ep,
- (struct usb_descriptor_header *) &uvc_ss_streaming_comp,
- NULL,
-};
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+USB_COMPOSITE_INTERFACE(intf1, &intf1alt0, &intf1alt1);
+
+USB_COMPOSITE_DESCRIPTORS(uvc_descs, &intf0, &intf1);
void uvc_set_trace_param(unsigned int trace)
{
@@ -269,43 +264,34 @@ void uvc_function_setup_continue(struct uvc_device *uvc)
}
static int
-uvc_function_get_alt(struct usb_function *f, unsigned interface)
-{
- struct uvc_device *uvc = to_uvc(f);
-
- INFO(f->config->cdev, "uvc_function_get_alt(%u)\n", interface);
-
- if (interface == uvc->control_intf)
- return 0;
- else if (interface != uvc->streaming_intf)
- return -EINVAL;
- else
- return uvc->video.ep->enabled ? 1 : 0;
-}
-
-static int
uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
{
struct uvc_device *uvc = to_uvc(f);
struct usb_composite_dev *cdev = f->config->cdev;
struct v4l2_event v4l2_event;
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
- int ret;
INFO(cdev, "uvc_function_set_alt(%u, %u)\n", interface, alt);
- if (interface == uvc->control_intf) {
- if (alt)
- return -EINVAL;
-
- INFO(cdev, "reset UVC Control\n");
- usb_ep_disable(uvc->control_ep);
-
- if (!uvc->control_ep->desc)
- if (config_ep_by_speed(cdev->gadget, f, uvc->control_ep))
- return -EINVAL;
+ if (interface == 0) {
+ uvc->control_ep = usb_function_get_ep(f, interface, 0);
+ if (!uvc->control_ep)
+ return -ENODEV;
+
+ uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0,
+ GFP_KERNEL);
+ if (!uvc->control_req)
+ return -ENOMEM;
+ uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL);
+ if (!uvc->control_buf) {
+ usb_ep_free_request(cdev->gadget->ep0,
+ uvc->control_req);
+ return -ENOMEM;
+ }
- usb_ep_enable(uvc->control_ep);
+ uvc->control_req->buf = uvc->control_buf;
+ uvc->control_req->complete = uvc_function_ep0_complete;
+ uvc->control_req->context = uvc;
if (uvc->state == UVC_STATE_DISCONNECTED) {
memset(&v4l2_event, 0, sizeof(v4l2_event));
@@ -315,75 +301,59 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
uvc->state = UVC_STATE_CONNECTED;
}
+ } else if (interface == 1) {
+ /* TODO
+ * if (usb_endpoint_xfer_bulk(&uvc->desc.vs_ep))
+ * return alt ? -EINVAL : 0;
+ */
- return 0;
- }
+ switch (alt) {
+ case 0:
+ if (uvc->state != UVC_STATE_STREAMING)
+ return 0;
- if (interface != uvc->streaming_intf)
- return -EINVAL;
-
- /* TODO
- if (usb_endpoint_xfer_bulk(&uvc->desc.vs_ep))
- return alt ? -EINVAL : 0;
- */
-
- switch (alt) {
- case 0:
- if (uvc->state != UVC_STATE_STREAMING)
- return 0;
-
- if (uvc->video.ep)
- usb_ep_disable(uvc->video.ep);
-
- memset(&v4l2_event, 0, sizeof(v4l2_event));
- v4l2_event.type = UVC_EVENT_STREAMOFF;
- v4l2_event_queue(&uvc->vdev, &v4l2_event);
-
- uvc->state = UVC_STATE_CONNECTED;
- return 0;
+ memset(&v4l2_event, 0, sizeof(v4l2_event));
+ v4l2_event.type = UVC_EVENT_STREAMOFF;
+ v4l2_event_queue(&uvc->vdev, &v4l2_event);
- case 1:
- if (uvc->state != UVC_STATE_CONNECTED)
+ uvc->state = UVC_STATE_CONNECTED;
return 0;
- if (!uvc->video.ep)
- return -EINVAL;
-
- INFO(cdev, "reset UVC\n");
- usb_ep_disable(uvc->video.ep);
-
- ret = config_ep_by_speed(f->config->cdev->gadget,
- &(uvc->func), uvc->video.ep);
- if (ret)
- return ret;
- usb_ep_enable(uvc->video.ep);
+ case 1:
+ if (uvc->state != UVC_STATE_CONNECTED)
+ return 0;
- memset(&v4l2_event, 0, sizeof(v4l2_event));
- v4l2_event.type = UVC_EVENT_STREAMON;
- v4l2_event_queue(&uvc->vdev, &v4l2_event);
- return USB_GADGET_DELAYED_STATUS;
+ uvc->video.ep = usb_function_get_ep(f, interface, 0);
+ if (!uvc->video.ep)
+ return -ENODEV;
- default:
- return -EINVAL;
+ memset(&v4l2_event, 0, sizeof(v4l2_event));
+ v4l2_event.type = UVC_EVENT_STREAMON;
+ v4l2_event_queue(&uvc->vdev, &v4l2_event);
+ return USB_GADGET_DELAYED_STATUS;
+ }
}
+
+ return 0;
}
static void
-uvc_function_disable(struct usb_function *f)
+uvc_function_clear_alt(struct usb_function *f, unsigned interface, unsigned alt)
{
struct uvc_device *uvc = to_uvc(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
struct v4l2_event v4l2_event;
- INFO(f->config->cdev, "uvc_function_disable\n");
-
- memset(&v4l2_event, 0, sizeof(v4l2_event));
- v4l2_event.type = UVC_EVENT_DISCONNECT;
- v4l2_event_queue(&uvc->vdev, &v4l2_event);
+ if (interface == 0) {
+ usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
+ kfree(uvc->control_buf);
- uvc->state = UVC_STATE_DISCONNECTED;
+ memset(&v4l2_event, 0, sizeof(v4l2_event));
+ v4l2_event.type = UVC_EVENT_DISCONNECT;
+ v4l2_event_queue(&uvc->vdev, &v4l2_event);
- usb_ep_disable(uvc->video.ep);
- usb_ep_disable(uvc->control_ep);
+ uvc->state = UVC_STATE_DISCONNECTED;
+ }
}
/* --------------------------------------------------------------------------
@@ -433,142 +403,14 @@ uvc_register_video(struct uvc_device *uvc)
return video_register_device(&uvc->vdev, VFL_TYPE_GRABBER, -1);
}
-#define UVC_COPY_DESCRIPTOR(mem, dst, desc) \
- do { \
- memcpy(mem, desc, (desc)->bLength); \
- *(dst)++ = mem; \
- mem += (desc)->bLength; \
- } while (0);
-
-#define UVC_COPY_DESCRIPTORS(mem, dst, src) \
- do { \
- const struct usb_descriptor_header * const *__src; \
- for (__src = src; *__src; ++__src) { \
- memcpy(mem, *__src, (*__src)->bLength); \
- *dst++ = mem; \
- mem += (*__src)->bLength; \
- } \
- } while (0)
-
-static struct usb_descriptor_header **
-uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
+static int uvc_function_prep_descs(struct usb_function *f)
{
- struct uvc_input_header_descriptor *uvc_streaming_header;
- struct uvc_header_descriptor *uvc_control_header;
- const struct uvc_descriptor_header * const *uvc_control_desc;
- const struct uvc_descriptor_header * const *uvc_streaming_cls;
- const struct usb_descriptor_header * const *uvc_streaming_std;
- const struct usb_descriptor_header * const *src;
- struct usb_descriptor_header **dst;
- struct usb_descriptor_header **hdr;
- unsigned int control_size;
- unsigned int streaming_size;
- unsigned int n_desc;
- unsigned int bytes;
- void *mem;
-
- uvc_control_desc = uvc->desc.control;
- uvc_streaming_cls = uvc->desc.streaming;
- uvc_streaming_std = uvc_ss_streaming;
-
- if (!uvc_control_desc || !uvc_streaming_cls)
- return ERR_PTR(-ENODEV);
-
- /* Descriptors layout
- *
- * uvc_iad
- * uvc_control_intf
- * Class-specific UVC control descriptors
- * uvc_control_ep
- * uvc_control_cs_ep
- * uvc_ss_control_comp (for SS only)
- * uvc_streaming_intf_alt0
- * Class-specific UVC streaming descriptors
- * uvc_{fs|hs}_streaming
- */
-
- /* Count descriptors and compute their size. */
- control_size = 0;
- streaming_size = 0;
- bytes = uvc_iad.bLength + uvc_control_intf.bLength
- + uvc_control_ep.bLength + uvc_control_cs_ep.bLength
- + uvc_streaming_intf_alt0.bLength;
-
- if (speed == USB_SPEED_SUPER) {
- bytes += uvc_ss_control_comp.bLength;
- n_desc = 6;
- } else {
- n_desc = 5;
- }
-
- for (src = (const struct usb_descriptor_header **)uvc_control_desc;
- *src; ++src) {
- control_size += (*src)->bLength;
- bytes += (*src)->bLength;
- n_desc++;
- }
- for (src = (const struct usb_descriptor_header **)uvc_streaming_cls;
- *src; ++src) {
- streaming_size += (*src)->bLength;
- bytes += (*src)->bLength;
- n_desc++;
- }
- for (src = uvc_streaming_std; *src; ++src) {
- bytes += (*src)->bLength;
- n_desc++;
- }
-
- mem = kmalloc((n_desc + 1) * sizeof(*src) + bytes, GFP_KERNEL);
- if (mem == NULL)
- return NULL;
-
- hdr = mem;
- dst = mem;
- mem += (n_desc + 1) * sizeof(*src);
-
- /* Copy the descriptors. */
- UVC_COPY_DESCRIPTOR(mem, dst, &uvc_iad);
- UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_intf);
-
- uvc_control_header = mem;
- UVC_COPY_DESCRIPTORS(mem, dst,
- (const struct usb_descriptor_header **)uvc_control_desc);
- uvc_control_header->wTotalLength = cpu_to_le16(control_size);
- uvc_control_header->bInCollection = 1;
- uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf;
-
- UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep);
- if (speed == USB_SPEED_SUPER)
- UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp);
-
- UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep);
- UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0);
-
- uvc_streaming_header = mem;
- UVC_COPY_DESCRIPTORS(mem, dst,
- (const struct usb_descriptor_header**)uvc_streaming_cls);
- uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size);
- uvc_streaming_header->bEndpointAddress = uvc->video.ep->address;
-
- UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std);
-
- *dst = NULL;
- return hdr;
-}
-
-static int
-uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
-{
- struct usb_composite_dev *cdev = c->cdev;
- struct uvc_device *uvc = to_uvc(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
struct usb_string *us;
unsigned int max_packet_mult;
unsigned int max_packet_size;
- struct usb_ep *ep;
struct f_uvc_opts *opts;
- int ret = -EINVAL;
-
- INFO(cdev, "uvc_function_bind\n");
+ int ret;
opts = fi_to_f_uvc_opts(f->fi);
/* Sanity check the streaming endpoint module parameters.
@@ -610,96 +452,107 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
cpu_to_le16(max_packet_size * max_packet_mult *
opts->streaming_maxburst);
- /* Allocate endpoints. */
- ep = usb_ep_autoconfig(cdev->gadget, &uvc_control_ep);
- if (!ep) {
- INFO(cdev, "Unable to allocate control EP\n");
- goto error;
- }
- uvc->control_ep = ep;
-
- if (gadget_is_superspeed(c->cdev->gadget))
- ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep,
- &uvc_ss_streaming_comp);
- else if (gadget_is_dualspeed(cdev->gadget))
- ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep);
- else
- ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep);
-
- if (!ep) {
- INFO(cdev, "Unable to allocate streaming EP\n");
- goto error;
- }
- uvc->video.ep = ep;
-
- uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
- uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address;
- uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address;
-
us = usb_gstrings_attach(cdev, uvc_function_strings,
ARRAY_SIZE(uvc_en_us_strings));
- if (IS_ERR(us)) {
- ret = PTR_ERR(us);
- goto error;
- }
+ if (IS_ERR(us))
+ return PTR_ERR(us);
uvc_iad.iFunction = us[UVC_STRING_CONTROL_IDX].id;
uvc_control_intf.iInterface = us[UVC_STRING_CONTROL_IDX].id;
ret = us[UVC_STRING_STREAMING_IDX].id;
uvc_streaming_intf_alt0.iInterface = ret;
uvc_streaming_intf_alt1.iInterface = ret;
- /* Allocate interface IDs. */
- if ((ret = usb_interface_id(c, f)) < 0)
- goto error;
- uvc_iad.bFirstInterface = ret;
- uvc_control_intf.bInterfaceNumber = ret;
- uvc->control_intf = ret;
+ return usb_function_set_descs(f, &uvc_descs);
+}
- if ((ret = usb_interface_id(c, f)) < 0)
- goto error;
- uvc_streaming_intf_alt0.bInterfaceNumber = ret;
- uvc_streaming_intf_alt1.bInterfaceNumber = ret;
- uvc->streaming_intf = ret;
-
- /* Copy descriptors */
- f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
- if (IS_ERR(f->fs_descriptors)) {
- ret = PTR_ERR(f->fs_descriptors);
- f->fs_descriptors = NULL;
- goto error;
- }
- if (gadget_is_dualspeed(cdev->gadget)) {
- f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
- if (IS_ERR(f->hs_descriptors)) {
- ret = PTR_ERR(f->hs_descriptors);
- f->hs_descriptors = NULL;
- goto error;
- }
- }
- if (gadget_is_superspeed(c->cdev->gadget)) {
- f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
- if (IS_ERR(f->ss_descriptors)) {
- ret = PTR_ERR(f->ss_descriptors);
- f->ss_descriptors = NULL;
- goto error;
- }
- }
+static int uvc_function_prep_vendor_descs(struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct uvc_device *uvc = to_uvc(f);
+ const struct usb_descriptor_header * const *uvc_control_desc;
+ const struct usb_descriptor_header * const *uvc_streaming_cls;
+ const struct usb_descriptor_header * const *desc;
+ struct uvc_input_header_descriptor uvc_streaming_header;
+ struct uvc_header_descriptor uvc_control_header;
+ unsigned int control_size;
+ unsigned int streaming_size;
+ int intf0_id, intf1_id;
+ int ret = -EINVAL;
- /* Preallocate control endpoint request. */
- uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
- uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL);
- if (uvc->control_req == NULL || uvc->control_buf == NULL) {
- ret = -ENOMEM;
- goto error;
- }
+ intf0_id = usb_get_interface_id(f, 0);
+ intf1_id = usb_get_interface_id(f, 1);
+
+ uvc_iad.bFirstInterface = intf0_id;
+
+ uvc_control_desc = (const struct usb_descriptor_header * const *)
+ uvc->desc.control;
+ uvc_streaming_cls = (const struct usb_descriptor_header * const *)
+ uvc->desc.streaming;
+
+ if (!uvc_control_desc || !uvc_streaming_cls)
+ return -ENODEV;
+
+ /* Descriptors layout
+ *
+ * uvc_iad
+ * uvc_control_intf
+ * Class-specific UVC control descriptors
+ * uvc_control_ep
+ * uvc_control_cs_ep
+ * uvc_ss_control_comp (for SS only)
+ * uvc_streaming_intf_alt0
+ * Class-specific UVC streaming descriptors
+ * uvc_{fs|hs}_streaming
+ */
+
+ /* Count descriptors and compute their size. */
+ control_size = 0;
+ streaming_size = 0;
+
+ for (desc = uvc_control_desc; *desc; ++desc)
+ control_size += (*desc)->bLength;
+ for (desc = uvc_streaming_cls; *desc; ++desc)
+ streaming_size += (*desc)->bLength;
+
+ usb_function_add_vendor_desc(f,
+ (struct usb_descriptor_header *)&uvc_iad);
+
+ /* uvc_control_intf */
+
+ memcpy(&uvc_control_header, uvc_control_desc[0],
+ uvc_control_desc[0]->bLength);
+ uvc_control_header.wTotalLength = cpu_to_le16(control_size);
+ uvc_control_header.bInCollection = 1;
+ uvc_control_header.baInterfaceNr[0] = intf1_id;
+
+ usb_altset_add_vendor_desc(f, 0, 0,
+ (struct usb_descriptor_header *)&uvc_control_header);
+
+ for (desc = uvc_control_desc + 1; *desc; ++desc)
+ usb_altset_add_vendor_desc(f, 0, 0, *desc);
+
+ usb_ep_add_vendor_desc(f, 0, 0, 0,
+ (struct usb_descriptor_header *)&uvc_control_cs_ep);
+
+ /* uvc_streaming_intf_alt0 */
- uvc->control_req->buf = uvc->control_buf;
- uvc->control_req->complete = uvc_function_ep0_complete;
- uvc->control_req->context = uvc;
+ memcpy(&uvc_streaming_header, uvc_streaming_cls[0],
+ uvc_streaming_cls[0]->bLength);
+ uvc_streaming_header.wTotalLength = cpu_to_le16(streaming_size);
+ uvc_streaming_header.bEndpointAddress =
+ usb_get_endpoint_address(f, 1, 1, 0);
- if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) {
+ usb_altset_add_vendor_desc(f, 1, 0,
+ (struct usb_descriptor_header *)&uvc_streaming_header);
+
+ for (desc = uvc_streaming_cls + 1; *desc; ++desc)
+ usb_altset_add_vendor_desc(f, 1, 0, *desc);
+
+
+ ret = v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev);
+ if (ret < 0) {
printk(KERN_INFO "v4l2_device_register failed\n");
- goto error;
+ return ret;
}
/* Initialise video. */
@@ -715,15 +568,9 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
}
return 0;
-
error:
v4l2_device_unregister(&uvc->v4l2_dev);
- if (uvc->control_req)
- usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
- kfree(uvc->control_buf);
-
- usb_free_all_descriptors(f);
return ret;
}
@@ -800,7 +647,7 @@ static struct usb_function_instance *uvc_alloc_inst(void)
md->bTransferCharacteristics = 1;
md->bMatrixCoefficients = 4;
- /* Prepare hs control class descriptors for configfs-based gadgets */
+ /* Prepare control class descriptors for configfs-based gadgets */
ctl_cls = opts->uvc_control_cls;
ctl_cls[0] = NULL; /* assigned elsewhere by configfs */
ctl_cls[1] = (struct uvc_descriptor_header *)cd;
@@ -835,11 +682,6 @@ static void uvc_unbind(struct usb_configuration *c, struct usb_function *f)
video_unregister_device(&uvc->vdev);
v4l2_device_unregister(&uvc->v4l2_dev);
-
- usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
- kfree(uvc->control_buf);
-
- usb_free_all_descriptors(f);
}
static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
@@ -870,11 +712,11 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
/* Register the function. */
uvc->func.name = "uvc";
- uvc->func.bind = uvc_function_bind;
+ uvc->func.prep_descs = uvc_function_prep_descs;
+ uvc->func.prep_vendor_descs = uvc_function_prep_vendor_descs;
uvc->func.unbind = uvc_unbind;
- uvc->func.get_alt = uvc_function_get_alt;
uvc->func.set_alt = uvc_function_set_alt;
- uvc->func.disable = uvc_function_disable;
+ uvc->func.clear_alt = uvc_function_clear_alt;
uvc->func.setup = uvc_function_setup;
uvc->func.free_func = uvc_free;
uvc->func.bind_deactivated = true;
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index bccdda2..ec69535 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -155,13 +155,10 @@ struct uvc_device
const struct uvc_descriptor_header * const *streaming;
} desc;
- unsigned int control_intf;
struct usb_ep *control_ep;
struct usb_request *control_req;
void *control_buf;
- unsigned int streaming_intf;
-
/* Events */
unsigned int event_length;
unsigned int event_setup_out : 1;
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 13:50 +0100 |
| Subject | [PATCH v4 25/43] usb: gadget: f_hid: handle requests lifetime properly |
| Message-ID | <qY52I-212-69@gated-at.bofh.it> |
| In reply to | #1325342 |
So far USB requests allocated in hidg_set_alt() were not freed. Now we
free them in case of hidg_set_alt() failure (when we are not able to
allocate and enqueue all the requests) or in hidg_disable() function.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/function/f_hid.c | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index 99285b4..0456a53 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -59,6 +59,7 @@ struct f_hidg {
bool write_pending;
wait_queue_head_t write_queue;
struct usb_request *req;
+ struct usb_request **out_reqs;
int minor;
struct cdev cdev;
@@ -490,6 +491,7 @@ static void hidg_disable(struct usb_function *f)
{
struct f_hidg *hidg = func_to_hidg(f);
struct f_hidg_req_list *list, *next;
+ int i;
usb_ep_disable(hidg->in_ep);
usb_ep_disable(hidg->out_ep);
@@ -498,6 +500,12 @@ static void hidg_disable(struct usb_function *f)
list_del(&list->list);
kfree(list);
}
+
+ for (i = 0; i < hidg->qlen; ++i) {
+ kfree(hidg->out_reqs[i]->buf);
+ kfree(hidg->out_reqs[i]);
+ }
+ kfree(hidg->out_reqs);
}
static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
@@ -547,11 +555,14 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
/*
* allocate a bunch of read buffers and queue them all at once.
*/
+ hidg->out_reqs = kzalloc(hidg->qlen *
+ sizeof(*hidg->out_reqs), GFP_KERNEL);
for (i = 0; i < hidg->qlen && status == 0; i++) {
struct usb_request *req =
hidg_alloc_ep_req(hidg->out_ep,
hidg->report_length);
if (req) {
+ hidg->out_reqs[i] = req;
req->complete = hidg_set_report_complete;
req->context = hidg;
status = usb_ep_queue(hidg->out_ep, req,
@@ -562,11 +573,20 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
} else {
usb_ep_disable(hidg->out_ep);
status = -ENOMEM;
- goto fail;
+ goto free_req;
}
}
}
+free_req:
+ if (status < 0) {
+ while (i--) {
+ kfree(hidg->out_reqs[i]->buf);
+ kfree(hidg->out_reqs[i]);
+ }
+ kfree(hidg->out_reqs);
+ }
+
fail:
return status;
}
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 13:50 +0100 |
| Subject | [PATCH v4 03/43] usb: gadget: f_loopback: free requests in loopback_disable() |
| Message-ID | <qY52I-212-71@gated-at.bofh.it> |
| In reply to | #1325342 |
USB requests in Loopback function are allocated in loopback_get_alt()
function, so we prefer to free them rather in loopback_disable() than
in loopback_complete() when request is completed with error. It provides
better symetry in resource management and improves code readability.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/function/f_loopback.c | 58 +++++++++++++-------------------
1 file changed, 23 insertions(+), 35 deletions(-)
diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c
index ddc3aad..f985107 100644
--- a/drivers/usb/gadget/function/f_loopback.c
+++ b/drivers/usb/gadget/function/f_loopback.c
@@ -35,6 +35,9 @@ struct f_loopback {
struct usb_ep *in_ep;
struct usb_ep *out_ep;
+ struct usb_request *in_req;
+ struct usb_request *out_req;
+
unsigned qlen;
unsigned buflen;
};
@@ -249,30 +252,25 @@ static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
* We received some data from the host so let's
* queue it so host can read the from our in ep
*/
- struct usb_request *in_req = req->context;
-
- in_req->zero = (req->actual < req->length);
- in_req->length = req->actual;
+ loop->in_req->zero = (req->actual < req->length);
+ loop->in_req->length = req->actual;
+ req = loop->in_req;
ep = loop->in_ep;
- req = in_req;
} else {
/*
* We have just looped back a bunch of data
* to host. Now let's wait for some more data.
*/
- req = req->context;
+ req = loop->out_req;
ep = loop->out_ep;
}
/* queue the buffer back to host or for next bunch of data */
status = usb_ep_queue(ep, req, GFP_ATOMIC);
- if (status == 0) {
- return;
- } else {
+ if (status < 0)
ERROR(cdev, "Unable to loop back buffer to %s: %d\n",
ep->name, status);
- goto free_req;
- }
+ break;
/* "should never get here" */
default:
@@ -280,20 +278,10 @@ static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
status, req->actual, req->length);
/* FALLTHROUGH */
- /* NOTE: since this driver doesn't maintain an explicit record
- * of requests it submitted (just maintains qlen count), we
- * rely on the hardware driver to clean up on disconnect or
- * endpoint disable.
- */
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
-free_req:
- usb_ep_free_request(ep == loop->in_ep ?
- loop->out_ep : loop->in_ep,
- req->context);
- free_ep_req(ep, req);
- return;
+ break;
}
}
@@ -316,7 +304,6 @@ static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len)
static int alloc_requests(struct usb_composite_dev *cdev,
struct f_loopback *loop)
{
- struct usb_request *in_req, *out_req;
int i;
int result = 0;
@@ -329,23 +316,21 @@ static int alloc_requests(struct usb_composite_dev *cdev,
for (i = 0; i < loop->qlen && result == 0; i++) {
result = -ENOMEM;
- in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC);
- if (!in_req)
+ loop->in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC);
+ if (!loop->in_req)
goto fail;
- out_req = lb_alloc_ep_req(loop->out_ep, 0);
- if (!out_req)
+ loop->out_req = lb_alloc_ep_req(loop->out_ep, 0);
+ if (!loop->out_req)
goto fail_in;
- in_req->complete = loopback_complete;
- out_req->complete = loopback_complete;
+ loop->in_req->complete = loopback_complete;
+ loop->out_req->complete = loopback_complete;
- in_req->buf = out_req->buf;
+ loop->in_req->buf = loop->out_req->buf;
/* length will be set in complete routine */
- in_req->context = out_req;
- out_req->context = in_req;
- result = usb_ep_queue(loop->out_ep, out_req, GFP_ATOMIC);
+ result = usb_ep_queue(loop->out_ep, loop->out_req, GFP_ATOMIC);
if (result) {
ERROR(cdev, "%s queue req --> %d\n",
loop->out_ep->name, result);
@@ -356,9 +341,9 @@ static int alloc_requests(struct usb_composite_dev *cdev,
return 0;
fail_out:
- free_ep_req(loop->out_ep, out_req);
+ free_ep_req(loop->out_ep, loop->out_req);
fail_in:
- usb_ep_free_request(loop->in_ep, in_req);
+ usb_ep_free_request(loop->in_ep, loop->in_req);
fail:
return result;
}
@@ -426,6 +411,9 @@ static void loopback_disable(struct usb_function *f)
struct f_loopback *loop = func_to_loop(f);
disable_loopback(loop);
+
+ free_ep_req(loop->out_ep, loop->out_req);
+ usb_ep_free_request(loop->in_ep, loop->in_req);
}
static struct usb_function *loopback_alloc(struct usb_function_instance *fi)
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 13:50 +0100 |
| Subject | [PATCH v4 38/43] usb: gadget: u_serial: remove usb_ep_enable()/usb_ep_disable() |
| Message-ID | <qY52I-212-75@gated-at.bofh.it> |
| In reply to | #1325342 |
As we have automatic endpoint state handling it's no longer needed. Signed-off-by: Robert Baldyga <r.baldyga@samsung.com> --- drivers/usb/gadget/function/u_serial.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 6af145f..73abdd9 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -1439,15 +1439,7 @@ int gserial_connect(struct gserial *gser, u8 port_num) return -EBUSY; } - /* activate the endpoints */ - status = usb_ep_enable(gser->in); - if (status < 0) - return status; gser->in->driver_data = port; - - status = usb_ep_enable(gser->out); - if (status < 0) - goto fail_out; gser->out->driver_data = port; /* then tell the tty glue that I/O can work */ @@ -1479,10 +1471,6 @@ int gserial_connect(struct gserial *gser, u8 port_num) spin_unlock_irqrestore(&port->port_lock, flags); return status; - -fail_out: - usb_ep_disable(gser->in); - return status; } EXPORT_SYMBOL_GPL(gserial_connect); /** @@ -1519,10 +1507,6 @@ void gserial_disconnect(struct gserial *gser) } spin_unlock_irqrestore(&port->port_lock, flags); - /* disable endpoints, aborting down any active I/O */ - usb_ep_disable(gser->out); - usb_ep_disable(gser->in); - /* finally, free any unused/unusable I/O buffers */ spin_lock_irqsave(&port->port_lock, flags); if (port->port.count == 0 && !port->openclose) -- 1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 13:50 +0100 |
| Subject | [PATCH v4 34/43] usb: gadget: f_subset: conversion to new API |
| Message-ID | <qY52I-212-67@gated-at.bofh.it> |
| In reply to | #1325342 |
Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/function/f_subset.c | 165 ++++++++++-----------------------
1 file changed, 47 insertions(+), 118 deletions(-)
diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/function/f_subset.c
index 829c78d..98324ca 100644
--- a/drivers/usb/gadget/function/f_subset.c
+++ b/drivers/usb/gadget/function/f_subset.c
@@ -154,17 +154,6 @@ static struct usb_endpoint_descriptor fs_subset_out_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_descriptor_header *fs_eth_function[] = {
- (struct usb_descriptor_header *) &subset_data_intf,
- (struct usb_descriptor_header *) &mdlm_header_desc,
- (struct usb_descriptor_header *) &mdlm_desc,
- (struct usb_descriptor_header *) &mdlm_detail_desc,
- (struct usb_descriptor_header *) ðer_desc,
- (struct usb_descriptor_header *) &fs_subset_in_desc,
- (struct usb_descriptor_header *) &fs_subset_out_desc,
- NULL,
-};
-
/* high speed support: */
static struct usb_endpoint_descriptor hs_subset_in_desc = {
@@ -183,17 +172,6 @@ static struct usb_endpoint_descriptor hs_subset_out_desc = {
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_descriptor_header *hs_eth_function[] = {
- (struct usb_descriptor_header *) &subset_data_intf,
- (struct usb_descriptor_header *) &mdlm_header_desc,
- (struct usb_descriptor_header *) &mdlm_desc,
- (struct usb_descriptor_header *) &mdlm_detail_desc,
- (struct usb_descriptor_header *) ðer_desc,
- (struct usb_descriptor_header *) &hs_subset_in_desc,
- (struct usb_descriptor_header *) &hs_subset_out_desc,
- NULL,
-};
-
/* super speed support: */
static struct usb_endpoint_descriptor ss_subset_in_desc = {
@@ -221,18 +199,16 @@ static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc = {
/* .bmAttributes = 0, */
};
-static struct usb_descriptor_header *ss_eth_function[] = {
- (struct usb_descriptor_header *) &subset_data_intf,
- (struct usb_descriptor_header *) &mdlm_header_desc,
- (struct usb_descriptor_header *) &mdlm_desc,
- (struct usb_descriptor_header *) &mdlm_detail_desc,
- (struct usb_descriptor_header *) ðer_desc,
- (struct usb_descriptor_header *) &ss_subset_in_desc,
- (struct usb_descriptor_header *) &ss_subset_bulk_comp_desc,
- (struct usb_descriptor_header *) &ss_subset_out_desc,
- (struct usb_descriptor_header *) &ss_subset_bulk_comp_desc,
- NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_in, &fs_subset_in_desc, &hs_subset_in_desc,
+ &ss_subset_in_desc, &ss_subset_bulk_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_out, &fs_subset_out_desc, &hs_subset_out_desc,
+ &ss_subset_out_desc, &ss_subset_bulk_comp_desc);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &subset_data_intf, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+
+USB_COMPOSITE_DESCRIPTORS(subset_descs, &intf0);
/* string descriptors: */
@@ -260,26 +236,20 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
struct usb_composite_dev *cdev = f->config->cdev;
struct net_device *net;
- /* we know alt == 0, so this is an activation or a reset */
-
- if (geth->port.in_ep->enabled) {
- DBG(cdev, "reset cdc subset\n");
- gether_disconnect(&geth->port);
- }
-
DBG(cdev, "init + activate cdc subset\n");
- if (config_ep_by_speed(cdev->gadget, f, geth->port.in_ep) ||
- config_ep_by_speed(cdev->gadget, f, geth->port.out_ep)) {
- geth->port.in_ep->desc = NULL;
- geth->port.out_ep->desc = NULL;
- return -EINVAL;
- }
+
+ geth->port.in_ep = usb_function_get_ep(f, intf, 0);
+ if (!geth->port.in_ep)
+ return -ENODEV;
+ geth->port.out_ep = usb_function_get_ep(f, intf, 1);
+ if (!geth->port.out_ep)
+ return -ENODEV;
net = gether_connect(&geth->port);
return PTR_ERR_OR_ZERO(net);
}
-static void geth_disable(struct usb_function *f)
+static void geth_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct f_gether *geth = func_to_geth(f);
struct usb_composite_dev *cdev = f->config->cdev;
@@ -292,14 +262,26 @@ static void geth_disable(struct usb_function *f)
/* serial function driver setup/binding */
-static int
-geth_bind(struct usb_configuration *c, struct usb_function *f)
+static int geth_prep_descs(struct usb_function *f)
{
- struct usb_composite_dev *cdev = c->cdev;
- struct f_gether *geth = func_to_geth(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
struct usb_string *us;
+
+ us = usb_gstrings_attach(cdev, geth_strings,
+ ARRAY_SIZE(geth_string_defs));
+ if (IS_ERR(us))
+ return PTR_ERR(us);
+
+ subset_data_intf.iInterface = us[0].id;
+ ether_desc.iMACAddress = us[1].id;
+
+ return usb_function_set_descs(f, &subset_descs);
+}
+
+static int geth_prep_vendor_descs(struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
int status;
- struct usb_ep *ep;
struct f_gether_opts *gether_opts;
@@ -322,63 +304,16 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
gether_opts->bound = true;
}
- us = usb_gstrings_attach(cdev, geth_strings,
- ARRAY_SIZE(geth_string_defs));
- if (IS_ERR(us))
- return PTR_ERR(us);
-
- subset_data_intf.iInterface = us[0].id;
- ether_desc.iMACAddress = us[1].id;
-
- /* allocate instance-specific interface IDs */
- status = usb_interface_id(c, f);
- if (status < 0)
- goto fail;
- subset_data_intf.bInterfaceNumber = status;
-
- status = -ENODEV;
-
- /* allocate instance-specific endpoints */
- ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_in_desc);
- if (!ep)
- goto fail;
- geth->port.in_ep = ep;
-
- ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_out_desc);
- if (!ep)
- goto fail;
- geth->port.out_ep = ep;
-
- /* support all relevant hardware speeds... we expect that when
- * hardware is dual speed, all bulk-capable endpoints work at
- * both speeds
- */
- hs_subset_in_desc.bEndpointAddress = fs_subset_in_desc.bEndpointAddress;
- hs_subset_out_desc.bEndpointAddress =
- fs_subset_out_desc.bEndpointAddress;
-
- ss_subset_in_desc.bEndpointAddress = fs_subset_in_desc.bEndpointAddress;
- ss_subset_out_desc.bEndpointAddress =
- fs_subset_out_desc.bEndpointAddress;
-
- status = usb_assign_descriptors(f, fs_eth_function, hs_eth_function,
- ss_eth_function);
- if (status)
- goto fail;
-
- /* NOTE: all that is done without knowing or caring about
- * the network link ... which is unavailable to this code
- * until we're activated via set_alt().
- */
-
- DBG(cdev, "CDC Subset: %s speed IN/%s OUT/%s\n",
- gadget_is_superspeed(c->cdev->gadget) ? "super" :
- gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
- geth->port.in_ep->name, geth->port.out_ep->name);
- return 0;
+ subset_data_intf.bInterfaceNumber = usb_get_interface_id(f, 0);
-fail:
- ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
+ usb_altset_add_vendor_desc(f, 0, 0,
+ (struct usb_descriptor_header *)&mdlm_header_desc);
+ usb_altset_add_vendor_desc(f, 0, 0,
+ (struct usb_descriptor_header *)&mdlm_desc);
+ usb_altset_add_vendor_desc(f, 0, 0,
+ (struct usb_descriptor_header *)&mdlm_detail_desc);
+ usb_altset_add_vendor_desc(f, 0, 0,
+ (struct usb_descriptor_header *)ðer_desc);
return status;
}
@@ -460,12 +395,6 @@ static void geth_free(struct usb_function *f)
kfree(eth);
}
-static void geth_unbind(struct usb_configuration *c, struct usb_function *f)
-{
- geth_string_defs[0].id = 0;
- usb_free_all_descriptors(f);
-}
-
static struct usb_function *geth_alloc(struct usb_function_instance *fi)
{
struct f_gether *geth;
@@ -496,10 +425,10 @@ static struct usb_function *geth_alloc(struct usb_function_instance *fi)
geth->port.cdc_filter = DEFAULT_FILTER;
geth->port.func.name = "cdc_subset";
- geth->port.func.bind = geth_bind;
- geth->port.func.unbind = geth_unbind;
+ geth->port.func.prep_descs = geth_prep_descs;
+ geth->port.func.prep_vendor_descs = geth_prep_vendor_descs;
geth->port.func.set_alt = geth_set_alt;
- geth->port.func.disable = geth_disable;
+ geth->port.func.clear_alt = geth_clear_alt;
geth->port.func.free_func = geth_free;
return &geth->port.func;
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 13:50 +0100 |
| Subject | [PATCH v4 29/43] usb: gadget: f_ncm: conversion to new API |
| Message-ID | <qY52J-212-79@gated-at.bofh.it> |
| In reply to | #1325342 |
Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/function/f_ncm.c | 320 ++++++++++++------------------------
1 file changed, 105 insertions(+), 215 deletions(-)
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index 7ad798a..a681895 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -32,8 +32,7 @@
* NCM is intended to be used with high-speed network attachments.
*
* Note that NCM requires the use of "alternate settings" for its data
- * interface. This means that the set_alt() method has real work to do,
- * and also means that a get_alt() method is required.
+ * interface.
*/
/* to trigger crc/non-crc ndp signature */
@@ -270,23 +269,6 @@ static struct usb_endpoint_descriptor fs_ncm_out_desc = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_descriptor_header *ncm_fs_function[] = {
- (struct usb_descriptor_header *) &ncm_iad_desc,
- /* CDC NCM control descriptors */
- (struct usb_descriptor_header *) &ncm_control_intf,
- (struct usb_descriptor_header *) &ncm_header_desc,
- (struct usb_descriptor_header *) &ncm_union_desc,
- (struct usb_descriptor_header *) &ecm_desc,
- (struct usb_descriptor_header *) &ncm_desc,
- (struct usb_descriptor_header *) &fs_ncm_notify_desc,
- /* data interface, altsettings 0 and 1 */
- (struct usb_descriptor_header *) &ncm_data_nop_intf,
- (struct usb_descriptor_header *) &ncm_data_intf,
- (struct usb_descriptor_header *) &fs_ncm_in_desc,
- (struct usb_descriptor_header *) &fs_ncm_out_desc,
- NULL,
-};
-
/* high speed support: */
static struct usb_endpoint_descriptor hs_ncm_notify_desc = {
@@ -316,22 +298,21 @@ static struct usb_endpoint_descriptor hs_ncm_out_desc = {
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_descriptor_header *ncm_hs_function[] = {
- (struct usb_descriptor_header *) &ncm_iad_desc,
- /* CDC NCM control descriptors */
- (struct usb_descriptor_header *) &ncm_control_intf,
- (struct usb_descriptor_header *) &ncm_header_desc,
- (struct usb_descriptor_header *) &ncm_union_desc,
- (struct usb_descriptor_header *) &ecm_desc,
- (struct usb_descriptor_header *) &ncm_desc,
- (struct usb_descriptor_header *) &hs_ncm_notify_desc,
- /* data interface, altsettings 0 and 1 */
- (struct usb_descriptor_header *) &ncm_data_nop_intf,
- (struct usb_descriptor_header *) &ncm_data_intf,
- (struct usb_descriptor_header *) &hs_ncm_in_desc,
- (struct usb_descriptor_header *) &hs_ncm_out_desc,
- NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_notify, &fs_ncm_notify_desc,
+ &hs_ncm_notify_desc, NULL, NULL);
+USB_COMPOSITE_ENDPOINT(ep_in, &fs_ncm_in_desc,
+ &hs_ncm_in_desc, NULL, NULL);
+USB_COMPOSITE_ENDPOINT(ep_out, &fs_ncm_out_desc,
+ &hs_ncm_out_desc, NULL, NULL);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &ncm_control_intf, &ep_notify);
+USB_COMPOSITE_ALTSETTING(intf1alt0, &ncm_data_nop_intf);
+USB_COMPOSITE_ALTSETTING(intf1alt1, &ncm_data_intf, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+USB_COMPOSITE_INTERFACE(intf1, &intf1alt0, &intf1alt1);
+
+USB_COMPOSITE_DESCRIPTORS(ncm_descs, &intf0, &intf1);
/* string descriptors: */
@@ -792,6 +773,8 @@ invalid:
return value;
}
+static void ncm_tx_tasklet(unsigned long data);
+static enum hrtimer_restart ncm_tx_timeout(struct hrtimer *data);
static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
@@ -799,52 +782,44 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
struct usb_composite_dev *cdev = f->config->cdev;
/* Control interface has only altsetting 0 */
- if (intf == ncm->ctrl_id) {
- if (alt != 0)
- goto fail;
-
+ if (intf == 0) {
DBG(cdev, "reset ncm control %d\n", intf);
- usb_ep_disable(ncm->notify);
- if (!(ncm->notify->desc)) {
- DBG(cdev, "init ncm ctrl %d\n", intf);
- if (config_ep_by_speed(cdev->gadget, f, ncm->notify))
- goto fail;
+ ncm->notify = usb_function_get_ep(f, intf, 0);
+ if (!ncm->notify)
+ return -ENODEV;
+
+ /* allocate notification request and buffer */
+ ncm->notify_req = usb_ep_alloc_request(ncm->notify, GFP_KERNEL);
+ if (!ncm->notify_req)
+ return -ENOMEM;
+ ncm->notify_req->buf = kmalloc(NCM_STATUS_BYTECOUNT, GFP_KERNEL);
+ if (!ncm->notify_req->buf) {
+ usb_ep_free_request(ncm->notify, ncm->notify_req);
+ return -ENOMEM;
}
- usb_ep_enable(ncm->notify);
- /* Data interface has two altsettings, 0 and 1 */
- } else if (intf == ncm->data_id) {
- if (alt > 1)
- goto fail;
-
- if (ncm->port.in_ep->enabled) {
- DBG(cdev, "reset ncm\n");
- ncm->timer_stopping = true;
- ncm->netdev = NULL;
- gether_disconnect(&ncm->port);
- ncm_reset_values(ncm);
- }
+ ncm->notify_req->context = ncm;
+ ncm->notify_req->complete = ncm_notify_complete;
+ tasklet_init(&ncm->tx_tasklet, ncm_tx_tasklet, (unsigned long) ncm);
+ hrtimer_init(&ncm->task_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ ncm->task_timer.function = ncm_tx_timeout;
+
+ /* Data interface has two altsettings, 0 and 1 */
+ } else if (intf == 1) {
/*
* CDC Network only sends data in non-default altsettings.
* Changing altsettings resets filters, statistics, etc.
*/
if (alt == 1) {
struct net_device *net;
-
- if (!ncm->port.in_ep->desc ||
- !ncm->port.out_ep->desc) {
- DBG(cdev, "init ncm\n");
- if (config_ep_by_speed(cdev->gadget, f,
- ncm->port.in_ep) ||
- config_ep_by_speed(cdev->gadget, f,
- ncm->port.out_ep)) {
- ncm->port.in_ep->desc = NULL;
- ncm->port.out_ep->desc = NULL;
- goto fail;
- }
- }
+ ncm->port.in_ep = usb_function_get_ep(f, intf, 0);
+ if (!ncm->port.in_ep)
+ return -ENODEV;
+ ncm->port.out_ep = usb_function_get_ep(f, intf, 1);
+ if (!ncm->port.out_ep)
+ return -ENODEV;
/* TODO */
/* Enable zlps by default for NCM conformance;
@@ -864,25 +839,28 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
spin_lock(&ncm->lock);
ncm_notify(ncm);
spin_unlock(&ncm->lock);
- } else
- goto fail;
+ }
return 0;
-fail:
- return -EINVAL;
}
-/*
- * Because the data interface supports multiple altsettings,
- * this NCM function *MUST* implement a get_alt() method.
- */
-static int ncm_get_alt(struct usb_function *f, unsigned intf)
+static void ncm_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct f_ncm *ncm = func_to_ncm(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
- if (intf == ncm->ctrl_id)
- return 0;
- return ncm->port.in_ep->enabled ? 1 : 0;
+ if (intf == 0) {
+ hrtimer_cancel(&ncm->task_timer);
+ tasklet_kill(&ncm->tx_tasklet);
+ kfree(ncm->notify_req->buf);
+ usb_ep_free_request(ncm->notify, ncm->notify_req);
+ } else if (intf == 1 && alt == 1) {
+ DBG(cdev, "reset ncm\n");
+ ncm->timer_stopping = true;
+ ncm->netdev = NULL;
+ gether_disconnect(&ncm->port);
+ ncm_reset_values(ncm);
+ }
}
static struct sk_buff *package_for_tx(struct f_ncm *ncm)
@@ -1266,25 +1244,6 @@ err:
return ret;
}
-static void ncm_disable(struct usb_function *f)
-{
- struct f_ncm *ncm = func_to_ncm(f);
- struct usb_composite_dev *cdev = f->config->cdev;
-
- DBG(cdev, "ncm deactivated\n");
-
- if (ncm->port.in_ep->enabled) {
- ncm->timer_stopping = true;
- ncm->netdev = NULL;
- gether_disconnect(&ncm->port);
- }
-
- if (ncm->notify->enabled) {
- usb_ep_disable(ncm->notify);
- ncm->notify->desc = NULL;
- }
-}
-
/*-------------------------------------------------------------------------*/
/*
@@ -1333,18 +1292,34 @@ static void ncm_close(struct gether *geth)
/* ethernet function driver setup/binding */
-static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
+static int ncm_prep_descs(struct usb_function *f)
{
- struct usb_composite_dev *cdev = c->cdev;
- struct f_ncm *ncm = func_to_ncm(f);
+ struct usb_composite_dev *cdev = f->config->cdev;
struct usb_string *us;
- int status;
- struct usb_ep *ep;
- struct f_ncm_opts *ncm_opts;
if (!can_support_ecm(cdev->gadget))
return -EINVAL;
+ us = usb_gstrings_attach(cdev, ncm_strings,
+ ARRAY_SIZE(ncm_string_defs));
+ if (IS_ERR(us))
+ return PTR_ERR(us);
+ ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id;
+ ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id;
+ ncm_data_intf.iInterface = us[STRING_DATA_IDX].id;
+ ecm_desc.iMACAddress = us[STRING_MAC_IDX].id;
+ ncm_iad_desc.iFunction = us[STRING_IAD_IDX].id;
+
+ return usb_function_set_descs(f, &ncm_descs);
+}
+
+static int ncm_prep_vendor_descs(struct usb_function *f)
+{
+ struct usb_composite_dev *cdev = f->config->cdev;
+ struct f_ncm *ncm = func_to_ncm(f);
+ struct f_ncm_opts *ncm_opts;
+ int status, intf0_id, intf1_id;
+
ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst);
/*
* in drivers/usb/gadget/configfs.c:configfs_composite_bind()
@@ -1362,79 +1337,29 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
return status;
ncm_opts->bound = true;
}
- us = usb_gstrings_attach(cdev, ncm_strings,
- ARRAY_SIZE(ncm_string_defs));
- if (IS_ERR(us))
- return PTR_ERR(us);
- ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id;
- ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id;
- ncm_data_intf.iInterface = us[STRING_DATA_IDX].id;
- ecm_desc.iMACAddress = us[STRING_MAC_IDX].id;
- ncm_iad_desc.iFunction = us[STRING_IAD_IDX].id;
- /* allocate instance-specific interface IDs */
- status = usb_interface_id(c, f);
- if (status < 0)
- goto fail;
- ncm->ctrl_id = status;
- ncm_iad_desc.bFirstInterface = status;
-
- ncm_control_intf.bInterfaceNumber = status;
- ncm_union_desc.bMasterInterface0 = status;
-
- status = usb_interface_id(c, f);
- if (status < 0)
- goto fail;
- ncm->data_id = status;
-
- ncm_data_nop_intf.bInterfaceNumber = status;
- ncm_data_intf.bInterfaceNumber = status;
- ncm_union_desc.bSlaveInterface0 = status;
-
- status = -ENODEV;
-
- /* allocate instance-specific endpoints */
- ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_in_desc);
- if (!ep)
- goto fail;
- ncm->port.in_ep = ep;
-
- ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_out_desc);
- if (!ep)
- goto fail;
- ncm->port.out_ep = ep;
-
- ep = usb_ep_autoconfig(cdev->gadget, &fs_ncm_notify_desc);
- if (!ep)
- goto fail;
- ncm->notify = ep;
-
- status = -ENOMEM;
-
- /* allocate notification request and buffer */
- ncm->notify_req = usb_ep_alloc_request(ep, GFP_KERNEL);
- if (!ncm->notify_req)
- goto fail;
- ncm->notify_req->buf = kmalloc(NCM_STATUS_BYTECOUNT, GFP_KERNEL);
- if (!ncm->notify_req->buf)
- goto fail;
- ncm->notify_req->context = ncm;
- ncm->notify_req->complete = ncm_notify_complete;
+ intf0_id = usb_get_interface_id(f, 0);
+ intf1_id = usb_get_interface_id(f, 1);
- /*
- * support all relevant hardware speeds... we expect that when
- * hardware is dual speed, all bulk-capable endpoints work at
- * both speeds
- */
- hs_ncm_in_desc.bEndpointAddress = fs_ncm_in_desc.bEndpointAddress;
- hs_ncm_out_desc.bEndpointAddress = fs_ncm_out_desc.bEndpointAddress;
- hs_ncm_notify_desc.bEndpointAddress =
- fs_ncm_notify_desc.bEndpointAddress;
+ ncm->ctrl_id = intf0_id;
+ ncm->data_id = intf1_id;
+
+ ncm_iad_desc.bFirstInterface = intf0_id;
+
+ ncm_union_desc.bMasterInterface0 = intf0_id;
+ ncm_union_desc.bSlaveInterface0 = intf1_id;
- status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function,
- NULL);
- if (status)
- goto fail;
+ usb_function_add_vendor_desc(f,
+ (struct usb_descriptor_header *)&ncm_iad_desc);
+
+ usb_altset_add_vendor_desc(f, 0, 0,
+ (struct usb_descriptor_header *)&ncm_header_desc);
+ usb_altset_add_vendor_desc(f, 0, 0,
+ (struct usb_descriptor_header *)&ncm_union_desc);
+ usb_altset_add_vendor_desc(f, 0, 0,
+ (struct usb_descriptor_header *)&ecm_desc);
+ usb_altset_add_vendor_desc(f, 0, 0,
+ (struct usb_descriptor_header *)&ncm_desc);
/*
* NOTE: all that is done without knowing or caring about
@@ -1445,25 +1370,7 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f)
ncm->port.open = ncm_open;
ncm->port.close = ncm_close;
- tasklet_init(&ncm->tx_tasklet, ncm_tx_tasklet, (unsigned long) ncm);
- hrtimer_init(&ncm->task_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- ncm->task_timer.function = ncm_tx_timeout;
-
- DBG(cdev, "CDC Network: %s speed IN/%s OUT/%s NOTIFY/%s\n",
- gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
- ncm->port.in_ep->name, ncm->port.out_ep->name,
- ncm->notify->name);
return 0;
-
-fail:
- if (ncm->notify_req) {
- kfree(ncm->notify_req->buf);
- usb_ep_free_request(ncm->notify, ncm->notify_req);
- }
-
- ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
-
- return status;
}
static inline struct f_ncm_opts *to_f_ncm_opts(struct config_item *item)
@@ -1547,22 +1454,6 @@ static void ncm_free(struct usb_function *f)
mutex_unlock(&opts->lock);
}
-static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)
-{
- struct f_ncm *ncm = func_to_ncm(f);
-
- DBG(c->cdev, "ncm unbind\n");
-
- hrtimer_cancel(&ncm->task_timer);
- tasklet_kill(&ncm->tx_tasklet);
-
- ncm_string_defs[0].id = 0;
- usb_free_all_descriptors(f);
-
- kfree(ncm->notify_req->buf);
- usb_ep_free_request(ncm->notify, ncm->notify_req);
-}
-
static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
{
struct f_ncm *ncm;
@@ -1597,12 +1488,11 @@ static struct usb_function *ncm_alloc(struct usb_function_instance *fi)
ncm->port.func.name = "cdc_network";
/* descriptors are per-instance copies */
- ncm->port.func.bind = ncm_bind;
- ncm->port.func.unbind = ncm_unbind;
+ ncm->port.func.prep_descs = ncm_prep_descs;
+ ncm->port.func.prep_vendor_descs = ncm_prep_vendor_descs;
ncm->port.func.set_alt = ncm_set_alt;
- ncm->port.func.get_alt = ncm_get_alt;
+ ncm->port.func.clear_alt = ncm_clear_alt;
ncm->port.func.setup = ncm_setup;
- ncm->port.func.disable = ncm_disable;
ncm->port.func.free_func = ncm_free;
ncm->port.wrap = ncm_wrap_ntb;
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 13:50 +0100 |
| Subject | [PATCH v4 22/43] usb: gadget: f_sourcesink: convert to new API |
| Message-ID | <qY52J-212-85@gated-at.bofh.it> |
| In reply to | #1325342 |
Generate descriptors in new format and attach them to USB function in
prep_descs(). Change set_alt() implementation and implement clear_alt()
operation. Get rid of get_alt() callback, as now USB_REQ_GET_INTERFACE
is handled automatically by composite framwework. Remove unnecessary
boilerplate code.
Call usb_config_do_bind() in legacy gadget zero, because it uses
usb_add_config_only() instead of usb_add_config() and prepares
configuration manually.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/function/f_sourcesink.c | 314 ++++++-----------------------
drivers/usb/gadget/function/g_zero.h | 3 -
drivers/usb/gadget/legacy/zero.c | 3 +
3 files changed, 65 insertions(+), 255 deletions(-)
diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index 6193b47..262dae8 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -42,7 +42,6 @@ struct f_sourcesink {
struct usb_ep *out_ep;
struct usb_ep *iso_in_ep;
struct usb_ep *iso_out_ep;
- int cur_alt;
struct usb_request **in_reqs;
struct usb_request **out_reqs;
@@ -125,19 +124,6 @@ static struct usb_endpoint_descriptor fs_iso_sink_desc = {
.bInterval = 4,
};
-static struct usb_descriptor_header *fs_source_sink_descs[] = {
- (struct usb_descriptor_header *) &source_sink_intf_alt0,
- (struct usb_descriptor_header *) &fs_sink_desc,
- (struct usb_descriptor_header *) &fs_source_desc,
- (struct usb_descriptor_header *) &source_sink_intf_alt1,
-#define FS_ALT_IFC_1_OFFSET 3
- (struct usb_descriptor_header *) &fs_sink_desc,
- (struct usb_descriptor_header *) &fs_source_desc,
- (struct usb_descriptor_header *) &fs_iso_sink_desc,
- (struct usb_descriptor_header *) &fs_iso_source_desc,
- NULL,
-};
-
/* high speed support: */
static struct usb_endpoint_descriptor hs_source_desc = {
@@ -174,19 +160,6 @@ static struct usb_endpoint_descriptor hs_iso_sink_desc = {
.bInterval = 4,
};
-static struct usb_descriptor_header *hs_source_sink_descs[] = {
- (struct usb_descriptor_header *) &source_sink_intf_alt0,
- (struct usb_descriptor_header *) &hs_source_desc,
- (struct usb_descriptor_header *) &hs_sink_desc,
- (struct usb_descriptor_header *) &source_sink_intf_alt1,
-#define HS_ALT_IFC_1_OFFSET 3
- (struct usb_descriptor_header *) &hs_source_desc,
- (struct usb_descriptor_header *) &hs_sink_desc,
- (struct usb_descriptor_header *) &hs_iso_source_desc,
- (struct usb_descriptor_header *) &hs_iso_sink_desc,
- NULL,
-};
-
/* super speed support: */
static struct usb_endpoint_descriptor ss_source_desc = {
@@ -259,24 +232,24 @@ static struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {
.wBytesPerInterval = cpu_to_le16(1024),
};
-static struct usb_descriptor_header *ss_source_sink_descs[] = {
- (struct usb_descriptor_header *) &source_sink_intf_alt0,
- (struct usb_descriptor_header *) &ss_source_desc,
- (struct usb_descriptor_header *) &ss_source_comp_desc,
- (struct usb_descriptor_header *) &ss_sink_desc,
- (struct usb_descriptor_header *) &ss_sink_comp_desc,
- (struct usb_descriptor_header *) &source_sink_intf_alt1,
-#define SS_ALT_IFC_1_OFFSET 5
- (struct usb_descriptor_header *) &ss_source_desc,
- (struct usb_descriptor_header *) &ss_source_comp_desc,
- (struct usb_descriptor_header *) &ss_sink_desc,
- (struct usb_descriptor_header *) &ss_sink_comp_desc,
- (struct usb_descriptor_header *) &ss_iso_source_desc,
- (struct usb_descriptor_header *) &ss_iso_source_comp_desc,
- (struct usb_descriptor_header *) &ss_iso_sink_desc,
- (struct usb_descriptor_header *) &ss_iso_sink_comp_desc,
- NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_source, &fs_source_desc, &hs_source_desc,
+ &ss_source_desc, &ss_source_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_sink, &fs_sink_desc, &hs_sink_desc,
+ &ss_sink_desc, &ss_sink_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_iso_source, &fs_iso_source_desc, &hs_iso_source_desc,
+ &ss_iso_source_desc, &ss_iso_source_comp_desc);
+USB_COMPOSITE_ENDPOINT(ep_iso_sink, &fs_iso_sink_desc, &hs_iso_sink_desc,
+ &ss_iso_sink_desc, &ss_iso_sink_comp_desc);
+
+USB_COMPOSITE_ALTSETTING(altset0, &source_sink_intf_alt0, &ep_source, &ep_sink);
+USB_COMPOSITE_ALTSETTING(altset1, &source_sink_intf_alt1, &ep_source, &ep_sink,
+ &ep_iso_source, &ep_iso_sink);
+
+USB_COMPOSITE_INTERFACE(intf0, &altset0, &altset1);
+USB_COMPOSITE_INTERFACE(intf0_no_iso, &altset0);
+
+USB_COMPOSITE_DESCRIPTORS(source_sink_descs, &intf0);
+USB_COMPOSITE_DESCRIPTORS(source_sink_descs_no_iso, &intf0_no_iso);
/* function-specific strings: */
@@ -304,65 +277,12 @@ static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)
return alloc_ep_req(ep, len, ss->buflen);
}
-static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep)
-{
- int value;
-
- value = usb_ep_disable(ep);
- if (value < 0)
- DBG(cdev, "disable %s --> %d\n", ep->name, value);
-}
-
-void disable_endpoints(struct usb_composite_dev *cdev,
- struct usb_ep *in, struct usb_ep *out,
- struct usb_ep *iso_in, struct usb_ep *iso_out)
-{
- disable_ep(cdev, in);
- disable_ep(cdev, out);
- if (iso_in)
- disable_ep(cdev, iso_in);
- if (iso_out)
- disable_ep(cdev, iso_out);
-}
-
-static int
-sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
+static int sourcesink_prep_descs(struct usb_function *f)
{
- struct usb_composite_dev *cdev = c->cdev;
struct f_sourcesink *ss = func_to_ss(f);
- int id;
- int ret;
- /* allocate interface ID(s) */
- id = usb_interface_id(c, f);
- if (id < 0)
- return id;
- source_sink_intf_alt0.bInterfaceNumber = id;
- source_sink_intf_alt1.bInterfaceNumber = id;
-
- /* allocate bulk endpoints */
- ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
- if (!ss->in_ep)
- goto autoconf_fail;
-
- ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
- if (!ss->out_ep)
- goto autoconf_fail;
-
- /* support high speed hardware */
- hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
- hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
-
- /* support super speed hardware */
- ss_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
- ss_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
-
- if (!ss->isoc_enabled) {
- fs_source_sink_descs[FS_ALT_IFC_1_OFFSET] = NULL;
- hs_source_sink_descs[HS_ALT_IFC_1_OFFSET] = NULL;
- ss_source_sink_descs[SS_ALT_IFC_1_OFFSET] = NULL;
- goto no_iso;
- }
+ if (!ss->isoc_enabled)
+ return usb_function_set_descs(f, &source_sink_descs_no_iso);
/* sanity check the isoc module parameters */
if (ss->isoc_interval < 1)
@@ -382,15 +302,6 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
1023 : ss->isoc_maxpacket;
fs_iso_sink_desc.bInterval = ss->isoc_interval;
- /* allocate iso endpoints */
- ss->iso_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_source_desc);
- if (!ss->iso_in_ep)
- goto autoconf_fail;
-
- ss->iso_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_sink_desc);
- if (!ss->iso_out_ep)
- goto autoconf_fail;
-
if (ss->isoc_maxpacket > 1024)
ss->isoc_maxpacket = 1024;
/*
@@ -401,14 +312,10 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
hs_iso_source_desc.wMaxPacketSize = ss->isoc_maxpacket;
hs_iso_source_desc.wMaxPacketSize |= ss->isoc_mult << 11;
hs_iso_source_desc.bInterval = ss->isoc_interval;
- hs_iso_source_desc.bEndpointAddress =
- fs_iso_source_desc.bEndpointAddress;
hs_iso_sink_desc.wMaxPacketSize = ss->isoc_maxpacket;
hs_iso_sink_desc.wMaxPacketSize |= ss->isoc_mult << 11;
hs_iso_sink_desc.bInterval = ss->isoc_interval;
- hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
-
/*
* Fill in the SS isoc descriptors from the module parameters.
* We assume that the user knows what they are doing and won't
@@ -420,8 +327,6 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
ss_iso_source_comp_desc.bMaxBurst = ss->isoc_maxburst;
ss_iso_source_comp_desc.wBytesPerInterval = ss->isoc_maxpacket *
(ss->isoc_mult + 1) * (ss->isoc_maxburst + 1);
- ss_iso_source_desc.bEndpointAddress =
- fs_iso_source_desc.bEndpointAddress;
ss_iso_sink_desc.wMaxPacketSize = ss->isoc_maxpacket;
ss_iso_sink_desc.bInterval = ss->isoc_interval;
@@ -429,26 +334,8 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
ss_iso_sink_comp_desc.bMaxBurst = ss->isoc_maxburst;
ss_iso_sink_comp_desc.wBytesPerInterval = ss->isoc_maxpacket *
(ss->isoc_mult + 1) * (ss->isoc_maxburst + 1);
- ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
-no_iso:
- ret = usb_assign_descriptors(f, fs_source_sink_descs,
- hs_source_sink_descs, ss_source_sink_descs);
- if (ret)
- return ret;
-
- DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
- (gadget_is_superspeed(c->cdev->gadget) ? "super" :
- (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
- f->name, ss->in_ep->name, ss->out_ep->name,
- ss->iso_in_ep ? ss->iso_in_ep->name : "<none>",
- ss->iso_out_ep ? ss->iso_out_ep->name : "<none>");
- return 0;
-
-autoconf_fail:
- ERROR(cdev, "%s: can't autoconfigure on %s\n",
- f->name, cdev->gadget->name);
- return -ENODEV;
+ return usb_function_set_descs(f, &source_sink_descs);
}
static void
@@ -462,7 +349,6 @@ sourcesink_free_func(struct usb_function *f)
opts->refcnt--;
mutex_unlock(&opts->lock);
- usb_free_all_descriptors(f);
kfree(func_to_ss(f));
}
@@ -658,138 +544,63 @@ err:
return status;
}
-static void disable_source_sink(struct f_sourcesink *ss)
-{
- struct usb_composite_dev *cdev;
-
- cdev = ss->function.config->cdev;
- disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep,
- ss->iso_out_ep);
- VDBG(cdev, "%s disabled\n", ss->function.name);
-}
-
-static int
-enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss,
- int alt)
-{
- int result = 0;
- int speed = cdev->gadget->speed;
- struct usb_ep *ep;
-
- /* one bulk endpoint writes (sources) zeroes IN (to the host) */
- ep = ss->in_ep;
- result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
- if (result)
- return result;
- result = usb_ep_enable(ep);
- if (result < 0)
- return result;
- ep->driver_data = ss;
-
- result = source_sink_start_ep(ss, true, false, speed);
- if (result < 0) {
-fail:
- ep = ss->in_ep;
- usb_ep_disable(ep);
- return result;
- }
-
- /* one bulk endpoint reads (sinks) anything OUT (from the host) */
- ep = ss->out_ep;
- result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
- if (result)
- goto fail;
- result = usb_ep_enable(ep);
- if (result < 0)
- goto fail;
- ep->driver_data = ss;
-
- result = source_sink_start_ep(ss, false, false, speed);
- if (result < 0) {
-fail2:
- ep = ss->out_ep;
- usb_ep_disable(ep);
- goto fail;
- }
-
- if (alt == 0)
- goto out;
-
- /* one iso endpoint writes (sources) zeroes IN (to the host) */
- ep = ss->iso_in_ep;
- if (ep) {
- result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
- if (result)
- goto fail2;
- result = usb_ep_enable(ep);
- if (result < 0)
- goto fail2;
- ep->driver_data = ss;
-
- result = source_sink_start_ep(ss, true, true, speed);
- if (result < 0) {
-fail3:
- ep = ss->iso_in_ep;
- if (ep)
- usb_ep_disable(ep);
- goto fail2;
- }
- }
-
- /* one iso endpoint reads (sinks) anything OUT (from the host) */
- ep = ss->iso_out_ep;
- if (ep) {
- result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
- if (result)
- goto fail3;
- result = usb_ep_enable(ep);
- if (result < 0)
- goto fail3;
- ep->driver_data = ss;
-
- result = source_sink_start_ep(ss, false, true, speed);
- if (result < 0) {
- usb_ep_disable(ep);
- goto fail3;
- }
- }
-out:
- ss->cur_alt = alt;
-
- DBG(cdev, "%s enabled, alt intf %d\n", ss->function.name, alt);
- return result;
-}
-
static int sourcesink_set_alt(struct usb_function *f,
unsigned intf, unsigned alt)
{
struct f_sourcesink *ss = func_to_ss(f);
struct usb_composite_dev *cdev = f->config->cdev;
+ int speed = cdev->gadget->speed;
+ int ret;
- disable_source_sink(ss);
- return enable_source_sink(cdev, ss, alt);
-}
+ ss->in_ep = usb_function_get_ep(f, intf, 0);
+ if (!ss->in_ep)
+ return -ENODEV;
+ ss->in_ep->driver_data = ss;
+ ret = source_sink_start_ep(ss, true, false, speed);
+ if (ret < 0)
+ return ret;
-static int sourcesink_get_alt(struct usb_function *f, unsigned intf)
-{
- struct f_sourcesink *ss = func_to_ss(f);
+ ss->out_ep = usb_function_get_ep(f, intf, 1);
+ if (!ss->out_ep)
+ return -ENODEV;
+ ss->out_ep->driver_data = ss;
+ ret = source_sink_start_ep(ss, false, false, speed);
+ if (ret < 0)
+ return ret;
+
+ if (alt == 1) {
+ ss->iso_in_ep = usb_function_get_ep(f, intf, 2);
+ if (!ss->iso_in_ep)
+ return -ENODEV;
+ ss->iso_in_ep->driver_data = ss;
+ ret = source_sink_start_ep(ss, true, true, speed);
+ if (ret < 0)
+ return ret;
+
+ ss->iso_out_ep = usb_function_get_ep(f, intf, 3);
+ if (!ss->iso_out_ep)
+ return -ENODEV;
+ ss->iso_out_ep->driver_data = ss;
+ ret = source_sink_start_ep(ss, false, true, speed);
+ if (ret < 0)
+ return ret;
+ }
- return ss->cur_alt;
+ return 0;
}
-static void sourcesink_disable(struct usb_function *f)
+static void sourcesink_clear_alt(struct usb_function *f,
+ unsigned intf, unsigned alt)
{
struct f_sourcesink *ss = func_to_ss(f);
int i;
- disable_source_sink(ss);
-
for (i = 0; i < ss->bulk_qlen; ++i) {
free_ep_req(ss->in_ep, ss->in_reqs[i]);
free_ep_req(ss->out_ep, ss->out_reqs[i]);
}
- if (ss->iso_in_ep) {
+ if (alt == 1) {
for (i = 0; i < ss->iso_qlen; ++i) {
free_ep_req(ss->iso_in_ep, ss->iso_in_reqs[i]);
free_ep_req(ss->iso_out_ep, ss->iso_out_reqs[i]);
@@ -898,10 +709,9 @@ static struct usb_function *source_sink_alloc_func(
ss->iso_qlen = ss_opts->iso_qlen;
ss->function.name = "source/sink";
- ss->function.bind = sourcesink_bind;
+ ss->function.prep_descs = sourcesink_prep_descs;
ss->function.set_alt = sourcesink_set_alt;
- ss->function.get_alt = sourcesink_get_alt;
- ss->function.disable = sourcesink_disable;
+ ss->function.clear_alt = sourcesink_clear_alt;
ss->function.setup = sourcesink_setup;
ss->function.strings = sourcesink_strings;
diff --git a/drivers/usb/gadget/function/g_zero.h b/drivers/usb/gadget/function/g_zero.h
index ae03278..e8d832d 100644
--- a/drivers/usb/gadget/function/g_zero.h
+++ b/drivers/usb/gadget/function/g_zero.h
@@ -68,8 +68,5 @@ void lb_modexit(void);
int lb_modinit(void);
/* common utilities */
-void disable_endpoints(struct usb_composite_dev *cdev,
- struct usb_ep *in, struct usb_ep *out,
- struct usb_ep *iso_in, struct usb_ep *iso_out);
#endif /* __G_ZERO_H */
diff --git a/drivers/usb/gadget/legacy/zero.c b/drivers/usb/gadget/legacy/zero.c
index 781ca94..4c52b4a 100644
--- a/drivers/usb/gadget/legacy/zero.c
+++ b/drivers/usb/gadget/legacy/zero.c
@@ -373,6 +373,9 @@ static int zero_bind(struct usb_composite_dev *cdev)
status = usb_add_function(&sourcesink_driver, func_ss);
if (status)
goto err_free_otg_desc;
+ status = usb_config_do_bind(&sourcesink_driver);
+ if (status)
+ goto err_free_otg_desc;
usb_ep_autoconfig_reset(cdev->gadget);
status = usb_add_function(&loopback_driver, func_lb);
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 13:50 +0100 |
| Subject | [PATCH v4 39/43] usb: gadget: u_ether: remove usb_ep_enable()/usb_ep_disable() |
| Message-ID | <qY52J-212-87@gated-at.bofh.it> |
| In reply to | #1325342 |
As we have automatic endpoint state handling it's no longer needed.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/function/u_ether.c | 28 ++--------------------------
1 file changed, 2 insertions(+), 26 deletions(-)
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 637809e..9d23842 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -1041,20 +1041,7 @@ struct net_device *gether_connect(struct gether *link)
return ERR_PTR(-EINVAL);
link->in_ep->driver_data = dev;
- result = usb_ep_enable(link->in_ep);
- if (result != 0) {
- DBG(dev, "enable %s --> %d\n",
- link->in_ep->name, result);
- goto fail0;
- }
-
link->out_ep->driver_data = dev;
- result = usb_ep_enable(link->out_ep);
- if (result != 0) {
- DBG(dev, "enable %s --> %d\n",
- link->out_ep->name, result);
- goto fail1;
- }
if (result == 0)
result = alloc_requests(dev, link, qlen(dev->gadget,
@@ -1082,14 +1069,8 @@ struct net_device *gether_connect(struct gether *link)
netif_carrier_on(dev->net);
if (netif_running(dev->net))
eth_start(dev, GFP_ATOMIC);
-
- /* on error, disable any endpoints */
- } else {
- (void) usb_ep_disable(link->out_ep);
-fail1:
- (void) usb_ep_disable(link->in_ep);
}
-fail0:
+
/* caller is responsible for cleanup on error */
if (result < 0)
return ERR_PTR(result);
@@ -1123,11 +1104,7 @@ void gether_disconnect(struct gether *link)
netif_stop_queue(dev->net);
netif_carrier_off(dev->net);
- /* disable endpoints, forcing (synchronous) completion
- * of all pending i/o. then free the request objects
- * and forget about the endpoints.
- */
- usb_ep_disable(link->in_ep);
+ /* free the request objects and forget about the endpoints. */
spin_lock(&dev->req_lock);
while (!list_empty(&dev->tx_reqs)) {
req = container_of(dev->tx_reqs.next,
@@ -1141,7 +1118,6 @@ void gether_disconnect(struct gether *link)
spin_unlock(&dev->req_lock);
link->in_ep->desc = NULL;
- usb_ep_disable(link->out_ep);
spin_lock(&dev->req_lock);
while (!list_empty(&dev->rx_reqs)) {
req = container_of(dev->rx_reqs.next,
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 13:50 +0100 |
| Subject | [PATCH v4 40/43] usb: gadget: uvc: fix typo in UVCG_OPTS_ATTR() macro |
| Message-ID | <qY52J-212-89@gated-at.bofh.it> |
| In reply to | #1325342 |
Fixes: 76e0da34c7cec5a7dc94667326a948de2e9c8c8d
("usb-gadget/uvc: use per-attribute show and store methods")
s/aname/cname - 'cname' was originally used as an attribute name,
because UVCG_OPTS_ATTR() macro doesn't have 'aname' parameter.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/function/uvc_configfs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index ad8c9b0..56ab61e 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -2245,7 +2245,7 @@ end: \
return ret; \
} \
\
-UVC_ATTR(f_uvc_opts_, cname, aname)
+UVC_ATTR(f_uvc_opts_, cname, cname)
#define identity_conv(x) (x)
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 13:50 +0100 |
| Subject | [PATCH v4 36/43] usb: gadget: f_uac2: conversion to new API |
| Message-ID | <qY52J-212-95@gated-at.bofh.it> |
| In reply to | #1325342 |
Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Remove boilerplate code.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/function/f_uac2.c | 360 ++++++++++++-----------------------
1 file changed, 121 insertions(+), 239 deletions(-)
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 044ca79..f5a184d 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -63,7 +63,6 @@ struct uac2_req {
struct uac2_rtd_params {
struct snd_uac2_chip *uac2; /* parent chip */
- bool ep_enabled; /* if the ep is enabled */
/* Size of the ring buffer */
size_t dma_bytes;
unsigned char *dma_area;
@@ -119,10 +118,6 @@ static struct snd_pcm_hardware uac2_pcm_hardware = {
};
struct audio_dev {
- u8 ac_intf, ac_alt;
- u8 as_out_intf, as_out_alt;
- u8 as_in_intf, as_in_alt;
-
struct usb_ep *in_ep, *out_ep;
struct usb_function func;
@@ -180,10 +175,6 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req)
struct uac2_rtd_params *prm = ur->pp;
struct snd_uac2_chip *uac2 = prm->uac2;
- /* i/f shutting down */
- if (!prm->ep_enabled || req->status == -ESHUTDOWN)
- return;
-
/*
* We can't really do much about bad xfers.
* Afterall, the ISOCH xfers could fail legitimately.
@@ -880,65 +871,20 @@ static struct uac2_iso_endpoint_descriptor as_iso_in_desc = {
.wLockDelay = 0,
};
-static struct usb_descriptor_header *fs_audio_desc[] = {
- (struct usb_descriptor_header *)&iad_desc,
- (struct usb_descriptor_header *)&std_ac_if_desc,
-
- (struct usb_descriptor_header *)&ac_hdr_desc,
- (struct usb_descriptor_header *)&in_clk_src_desc,
- (struct usb_descriptor_header *)&out_clk_src_desc,
- (struct usb_descriptor_header *)&usb_out_it_desc,
- (struct usb_descriptor_header *)&io_in_it_desc,
- (struct usb_descriptor_header *)&usb_in_ot_desc,
- (struct usb_descriptor_header *)&io_out_ot_desc,
-
- (struct usb_descriptor_header *)&std_as_out_if0_desc,
- (struct usb_descriptor_header *)&std_as_out_if1_desc,
-
- (struct usb_descriptor_header *)&as_out_hdr_desc,
- (struct usb_descriptor_header *)&as_out_fmt1_desc,
- (struct usb_descriptor_header *)&fs_epout_desc,
- (struct usb_descriptor_header *)&as_iso_out_desc,
-
- (struct usb_descriptor_header *)&std_as_in_if0_desc,
- (struct usb_descriptor_header *)&std_as_in_if1_desc,
-
- (struct usb_descriptor_header *)&as_in_hdr_desc,
- (struct usb_descriptor_header *)&as_in_fmt1_desc,
- (struct usb_descriptor_header *)&fs_epin_desc,
- (struct usb_descriptor_header *)&as_iso_in_desc,
- NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_out, &fs_epout_desc, &hs_epout_desc, NULL, NULL);
+USB_COMPOSITE_ENDPOINT(ep_in, &fs_epin_desc, &hs_epin_desc, NULL, NULL);
-static struct usb_descriptor_header *hs_audio_desc[] = {
- (struct usb_descriptor_header *)&iad_desc,
- (struct usb_descriptor_header *)&std_ac_if_desc,
-
- (struct usb_descriptor_header *)&ac_hdr_desc,
- (struct usb_descriptor_header *)&in_clk_src_desc,
- (struct usb_descriptor_header *)&out_clk_src_desc,
- (struct usb_descriptor_header *)&usb_out_it_desc,
- (struct usb_descriptor_header *)&io_in_it_desc,
- (struct usb_descriptor_header *)&usb_in_ot_desc,
- (struct usb_descriptor_header *)&io_out_ot_desc,
-
- (struct usb_descriptor_header *)&std_as_out_if0_desc,
- (struct usb_descriptor_header *)&std_as_out_if1_desc,
-
- (struct usb_descriptor_header *)&as_out_hdr_desc,
- (struct usb_descriptor_header *)&as_out_fmt1_desc,
- (struct usb_descriptor_header *)&hs_epout_desc,
- (struct usb_descriptor_header *)&as_iso_out_desc,
-
- (struct usb_descriptor_header *)&std_as_in_if0_desc,
- (struct usb_descriptor_header *)&std_as_in_if1_desc,
-
- (struct usb_descriptor_header *)&as_in_hdr_desc,
- (struct usb_descriptor_header *)&as_in_fmt1_desc,
- (struct usb_descriptor_header *)&hs_epin_desc,
- (struct usb_descriptor_header *)&as_iso_in_desc,
- NULL,
-};
+USB_COMPOSITE_ALTSETTING(intf0alt0, &std_ac_if_desc);
+USB_COMPOSITE_ALTSETTING(intf1alt0, &std_as_out_if0_desc);
+USB_COMPOSITE_ALTSETTING(intf1alt1, &std_as_out_if1_desc, &ep_out);
+USB_COMPOSITE_ALTSETTING(intf2alt0, &std_as_in_if0_desc);
+USB_COMPOSITE_ALTSETTING(intf2alt1, &std_as_in_if1_desc, &ep_in);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+USB_COMPOSITE_INTERFACE(intf1, &intf1alt0, &intf1alt1);
+USB_COMPOSITE_INTERFACE(intf2, &intf2alt0, &intf2alt1);
+
+USB_COMPOSITE_DESCRIPTORS(uac2_descs, &intf0, &intf1, &intf2);
struct cntrl_cur_lay3 {
__u32 dCUR;
@@ -957,11 +903,6 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
struct snd_uac2_chip *uac2 = prm->uac2;
int i;
- if (!prm->ep_enabled)
- return;
-
- prm->ep_enabled = false;
-
for (i = 0; i < USB_XFERS; i++) {
if (prm->ureq[i].req) {
usb_ep_dequeue(ep, prm->ureq[i].req);
@@ -969,10 +910,6 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
prm->ureq[i].req = NULL;
}
}
-
- if (usb_ep_disable(ep))
- dev_err(&uac2->pdev.dev,
- "%s:%d Error!\n", __func__, __LINE__);
}
static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
@@ -998,18 +935,13 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
le16_to_cpu(ep_desc->wMaxPacketSize)));
}
-static int
-afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
+static int afunc_prep_descs(struct usb_function *fn)
{
struct audio_dev *agdev = func_to_agdev(fn);
- struct snd_uac2_chip *uac2 = &agdev->uac2;
- struct usb_composite_dev *cdev = cfg->cdev;
- struct usb_gadget *gadget = cdev->gadget;
- struct device *dev = &uac2->pdev.dev;
+ struct usb_composite_dev *cdev = fn->config->cdev;
struct uac2_rtd_params *prm;
struct f_uac2_opts *uac2_opts;
struct usb_string *us;
- int ret;
uac2_opts = container_of(fn->fi, struct f_uac2_opts, func_inst);
@@ -1029,6 +961,28 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
std_as_in_if0_desc.iInterface = us[STR_AS_IN_ALT0].id;
std_as_in_if1_desc.iInterface = us[STR_AS_IN_ALT1].id;
+ /* Calculate wMaxPacketSize according to audio bandwidth */
+ set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true);
+ set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false);
+ set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true);
+ set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false);
+
+ prm = &agdev->uac2.c_prm;
+ prm->max_psize = hs_epout_desc.wMaxPacketSize;
+
+ prm = &agdev->uac2.p_prm;
+ prm->max_psize = hs_epin_desc.wMaxPacketSize;
+
+ return usb_function_set_descs(fn, &uac2_descs);
+}
+
+static int afunc_prep_vendor_descs(struct usb_function *fn)
+{
+ struct audio_dev *agdev = func_to_agdev(fn);
+ struct f_uac2_opts *uac2_opts;
+ int ret;
+
+ uac2_opts = container_of(fn->fi, struct f_uac2_opts, func_inst);
/* Initialize the configurable parameters */
usb_out_it_desc.bNrChannels = num_channels(uac2_opts->c_chmask);
@@ -1047,135 +1001,78 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
snprintf(clksrc_in, sizeof(clksrc_in), "%uHz", uac2_opts->p_srate);
snprintf(clksrc_out, sizeof(clksrc_out), "%uHz", uac2_opts->c_srate);
- ret = usb_interface_id(cfg, fn);
- if (ret < 0) {
- dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
- return ret;
- }
- std_ac_if_desc.bInterfaceNumber = ret;
- agdev->ac_intf = ret;
- agdev->ac_alt = 0;
-
- ret = usb_interface_id(cfg, fn);
- if (ret < 0) {
- dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
- return ret;
- }
- std_as_out_if0_desc.bInterfaceNumber = ret;
- std_as_out_if1_desc.bInterfaceNumber = ret;
- agdev->as_out_intf = ret;
- agdev->as_out_alt = 0;
-
- ret = usb_interface_id(cfg, fn);
- if (ret < 0) {
- dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
- return ret;
- }
- std_as_in_if0_desc.bInterfaceNumber = ret;
- std_as_in_if1_desc.bInterfaceNumber = ret;
- agdev->as_in_intf = ret;
- agdev->as_in_alt = 0;
-
- agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
- if (!agdev->out_ep) {
- dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
- goto err;
- }
-
- agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
- if (!agdev->in_ep) {
- dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
- goto err;
- }
-
- uac2->p_prm.uac2 = uac2;
- uac2->c_prm.uac2 = uac2;
-
- /* Calculate wMaxPacketSize according to audio bandwidth */
- set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true);
- set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false);
- set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true);
- set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false);
-
- hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
- hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
-
- ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL);
- if (ret)
- goto err;
-
- prm = &agdev->uac2.c_prm;
- prm->max_psize = hs_epout_desc.wMaxPacketSize;
- prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
- if (!prm->rbuf) {
- prm->max_psize = 0;
- goto err_free_descs;
- }
-
- prm = &agdev->uac2.p_prm;
- prm->max_psize = hs_epin_desc.wMaxPacketSize;
- prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
- if (!prm->rbuf) {
- prm->max_psize = 0;
- goto err_free_descs;
- }
+ usb_function_add_vendor_desc(fn,
+ (struct usb_descriptor_header *)&iad_desc);
+
+ usb_altset_add_vendor_desc(fn, 0, 0,
+ (struct usb_descriptor_header *)&ac_hdr_desc);
+ usb_altset_add_vendor_desc(fn, 0, 0,
+ (struct usb_descriptor_header *)&in_clk_src_desc);
+ usb_altset_add_vendor_desc(fn, 0, 0,
+ (struct usb_descriptor_header *)&out_clk_src_desc);
+ usb_altset_add_vendor_desc(fn, 0, 0,
+ (struct usb_descriptor_header *)&usb_out_it_desc);
+ usb_altset_add_vendor_desc(fn, 0, 0,
+ (struct usb_descriptor_header *)&io_in_it_desc);
+ usb_altset_add_vendor_desc(fn, 0, 0,
+ (struct usb_descriptor_header *)&usb_in_ot_desc);
+ usb_altset_add_vendor_desc(fn, 0, 0,
+ (struct usb_descriptor_header *)&io_out_ot_desc);
+
+ usb_altset_add_vendor_desc(fn, 1, 1,
+ (struct usb_descriptor_header *)&as_out_hdr_desc);
+ usb_altset_add_vendor_desc(fn, 1, 1,
+ (struct usb_descriptor_header *)&as_out_fmt1_desc);
+ usb_ep_add_vendor_desc(fn, 1, 1, 0,
+ (struct usb_descriptor_header *)&as_iso_out_desc);
+
+ usb_altset_add_vendor_desc(fn, 2, 1,
+ (struct usb_descriptor_header *)&as_in_hdr_desc);
+ usb_altset_add_vendor_desc(fn, 2, 1,
+ (struct usb_descriptor_header *)&as_in_fmt1_desc);
+ usb_ep_add_vendor_desc(fn, 2, 1, 0,
+ (struct usb_descriptor_header *)&as_iso_in_desc);
ret = alsa_uac2_init(agdev);
if (ret)
- goto err_free_descs;
- return 0;
+ return ret;
-err_free_descs:
- usb_free_all_descriptors(fn);
-err:
- kfree(agdev->uac2.p_prm.rbuf);
- kfree(agdev->uac2.c_prm.rbuf);
- return -EINVAL;
+ return 0;
}
-static int
-afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
+static int afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
{
struct usb_composite_dev *cdev = fn->config->cdev;
struct audio_dev *agdev = func_to_agdev(fn);
struct snd_uac2_chip *uac2 = &agdev->uac2;
struct usb_gadget *gadget = cdev->gadget;
struct device *dev = &uac2->pdev.dev;
+ struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev);
+ struct usb_endpoint_descriptor *ep_desc;
struct usb_request *req;
struct usb_ep *ep;
struct uac2_rtd_params *prm;
- int req_len, i;
+ unsigned int factor, rate;
+ int ret, req_len, i;
- /* No i/f has more than 2 alt settings */
- if (alt > 1) {
- dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
- return -EINVAL;
- }
-
- if (intf == agdev->ac_intf) {
- /* Control I/f has only 1 AltSetting - 0 */
- if (alt) {
- dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
- return -EINVAL;
- }
+ if (alt == 0)
return 0;
- }
- if (intf == agdev->as_out_intf) {
- ep = agdev->out_ep;
+ switch (intf) {
+ case 1:
+ ep = agdev->out_ep = usb_function_get_ep(fn, intf, 0);
prm = &uac2->c_prm;
- config_ep_by_speed(gadget, fn, ep);
- agdev->as_out_alt = alt;
+ prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
+ if (!prm->rbuf)
+ return -ENOMEM;
req_len = prm->max_psize;
- } else if (intf == agdev->as_in_intf) {
- struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev);
- unsigned int factor, rate;
- struct usb_endpoint_descriptor *ep_desc;
-
- ep = agdev->in_ep;
+ break;
+ case 2:
+ ep = agdev->in_ep = usb_function_get_ep(fn, intf, 0);
prm = &uac2->p_prm;
- config_ep_by_speed(gadget, fn, ep);
- agdev->as_in_alt = alt;
+ prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
+ if (!prm->rbuf)
+ return -ENOMEM;
/* pre-calculate the playback endpoint's interval */
if (gadget->speed == USB_SPEED_FULL) {
@@ -1201,24 +1098,18 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
req_len = uac2->p_pktsize;
uac2->p_residue = 0;
- } else {
- dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
- return -EINVAL;
- }
-
- if (alt == 0) {
- free_ep(prm, ep);
+ break;
+ default:
return 0;
}
- prm->ep_enabled = true;
- usb_ep_enable(ep);
-
for (i = 0; i < USB_XFERS; i++) {
if (!prm->ureq[i].req) {
req = usb_ep_alloc_request(ep, GFP_ATOMIC);
- if (req == NULL)
- return -ENOMEM;
+ if (req == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
prm->ureq[i].req = req;
prm->ureq[i].pp = prm;
@@ -1235,39 +1126,31 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
}
return 0;
-}
-
-static int
-afunc_get_alt(struct usb_function *fn, unsigned intf)
-{
- struct audio_dev *agdev = func_to_agdev(fn);
- struct snd_uac2_chip *uac2 = &agdev->uac2;
- if (intf == agdev->ac_intf)
- return agdev->ac_alt;
- else if (intf == agdev->as_out_intf)
- return agdev->as_out_alt;
- else if (intf == agdev->as_in_intf)
- return agdev->as_in_alt;
- else
- dev_err(&uac2->pdev.dev,
- "%s:%d Invalid Interface %d!\n",
- __func__, __LINE__, intf);
-
- return -EINVAL;
+err:
+ kfree(prm->rbuf);
+ return ret;
}
static void
-afunc_disable(struct usb_function *fn)
+afunc_clear_alt(struct usb_function *fn, unsigned intf, unsigned alt)
{
struct audio_dev *agdev = func_to_agdev(fn);
struct snd_uac2_chip *uac2 = &agdev->uac2;
- free_ep(&uac2->p_prm, agdev->in_ep);
- agdev->as_in_alt = 0;
+ if (alt == 0)
+ return;
- free_ep(&uac2->c_prm, agdev->out_ep);
- agdev->as_out_alt = 0;
+ switch (intf) {
+ case 1:
+ free_ep(&uac2->c_prm, agdev->out_ep);
+ kfree(agdev->uac2.c_prm.rbuf);
+ break;
+ case 2:
+ free_ep(&uac2->p_prm, agdev->in_ep);
+ kfree(agdev->uac2.p_prm.rbuf);
+ break;
+ }
}
static int
@@ -1386,7 +1269,7 @@ setup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr)
u16 w_index = le16_to_cpu(cr->wIndex);
u8 intf = w_index & 0xff;
- if (intf != agdev->ac_intf) {
+ if (intf != usb_get_interface_id(fn, 0)) {
dev_err(&uac2->pdev.dev,
"%s:%d Error!\n", __func__, __LINE__);
return -EOPNOTSUPP;
@@ -1552,6 +1435,8 @@ static void afunc_free(struct usb_function *f)
agdev = func_to_agdev(f);
opts = container_of(f->fi, struct f_uac2_opts, func_inst);
+
+ alsa_uac2_exit(agdev);
kfree(agdev);
mutex_lock(&opts->lock);
--opts->refcnt;
@@ -1561,21 +1446,14 @@ static void afunc_free(struct usb_function *f)
static void afunc_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct audio_dev *agdev = func_to_agdev(f);
- struct uac2_rtd_params *prm;
alsa_uac2_exit(agdev);
-
- prm = &agdev->uac2.p_prm;
- kfree(prm->rbuf);
-
- prm = &agdev->uac2.c_prm;
- kfree(prm->rbuf);
- usb_free_all_descriptors(f);
}
static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
{
struct audio_dev *agdev;
+ struct snd_uac2_chip *uac2;
struct f_uac2_opts *opts;
agdev = kzalloc(sizeof(*agdev), GFP_KERNEL);
@@ -1588,14 +1466,18 @@ static struct usb_function *afunc_alloc(struct usb_function_instance *fi)
mutex_unlock(&opts->lock);
agdev->func.name = "uac2_func";
- agdev->func.bind = afunc_bind;
+ agdev->func.prep_descs = afunc_prep_descs;
+ agdev->func.prep_vendor_descs = afunc_prep_vendor_descs;
agdev->func.unbind = afunc_unbind;
agdev->func.set_alt = afunc_set_alt;
- agdev->func.get_alt = afunc_get_alt;
- agdev->func.disable = afunc_disable;
+ agdev->func.clear_alt = afunc_clear_alt;
agdev->func.setup = afunc_setup;
agdev->func.free_func = afunc_free;
+ uac2 = &agdev->uac2;
+ uac2->p_prm.uac2 = uac2;
+ uac2->c_prm.uac2 = uac2;
+
return &agdev->func;
}
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 13:50 +0100 |
| Subject | [PATCH v4 41/43] usb: gadget: uvc: simplify descriptors generation |
| Message-ID | <qY52J-212-97@gated-at.bofh.it> |
| In reply to | #1325342 |
As we don't need distinction between interface descriptors for different
speeds, we can remove some amount of unnecessary code. Additionally we
simplify configfs interface of UVC function.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/function/f_uvc.c | 60 ++++-------------------
drivers/usb/gadget/function/u_uvc.h | 14 ++----
drivers/usb/gadget/function/uvc.h | 7 +--
drivers/usb/gadget/function/uvc_configfs.c | 79 +++++-------------------------
drivers/usb/gadget/legacy/webcam.c | 43 ++--------------
5 files changed, 32 insertions(+), 171 deletions(-)
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 29b41b5..0f554c4 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -467,26 +467,9 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
unsigned int bytes;
void *mem;
- switch (speed) {
- case USB_SPEED_SUPER:
- uvc_control_desc = uvc->desc.ss_control;
- uvc_streaming_cls = uvc->desc.ss_streaming;
- uvc_streaming_std = uvc_ss_streaming;
- break;
-
- case USB_SPEED_HIGH:
- uvc_control_desc = uvc->desc.fs_control;
- uvc_streaming_cls = uvc->desc.hs_streaming;
- uvc_streaming_std = uvc_hs_streaming;
- break;
-
- case USB_SPEED_FULL:
- default:
- uvc_control_desc = uvc->desc.fs_control;
- uvc_streaming_cls = uvc->desc.fs_streaming;
- uvc_streaming_std = uvc_fs_streaming;
- break;
- }
+ uvc_control_desc = uvc->desc.control;
+ uvc_streaming_cls = uvc->desc.streaming;
+ uvc_streaming_std = uvc_ss_streaming;
if (!uvc_control_desc || !uvc_streaming_cls)
return ERR_PTR(-ENODEV);
@@ -817,24 +800,14 @@ static struct usb_function_instance *uvc_alloc_inst(void)
md->bTransferCharacteristics = 1;
md->bMatrixCoefficients = 4;
- /* Prepare fs control class descriptors for configfs-based gadgets */
- ctl_cls = opts->uvc_fs_control_cls;
- ctl_cls[0] = NULL; /* assigned elsewhere by configfs */
- ctl_cls[1] = (struct uvc_descriptor_header *)cd;
- ctl_cls[2] = (struct uvc_descriptor_header *)pd;
- ctl_cls[3] = (struct uvc_descriptor_header *)od;
- ctl_cls[4] = NULL; /* NULL-terminate */
- opts->fs_control =
- (const struct uvc_descriptor_header * const *)ctl_cls;
-
/* Prepare hs control class descriptors for configfs-based gadgets */
- ctl_cls = opts->uvc_ss_control_cls;
+ ctl_cls = opts->uvc_control_cls;
ctl_cls[0] = NULL; /* assigned elsewhere by configfs */
ctl_cls[1] = (struct uvc_descriptor_header *)cd;
ctl_cls[2] = (struct uvc_descriptor_header *)pd;
ctl_cls[3] = (struct uvc_descriptor_header *)od;
ctl_cls[4] = NULL; /* NULL-terminate */
- opts->ss_control =
+ opts->control =
(const struct uvc_descriptor_header * const *)ctl_cls;
opts->streaming_interval = 1;
@@ -884,27 +857,14 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
opts = fi_to_f_uvc_opts(fi);
mutex_lock(&opts->lock);
- if (opts->uvc_fs_streaming_cls) {
- strm_cls = opts->uvc_fs_streaming_cls;
- opts->fs_streaming =
- (const struct uvc_descriptor_header * const *)strm_cls;
- }
- if (opts->uvc_hs_streaming_cls) {
- strm_cls = opts->uvc_hs_streaming_cls;
- opts->hs_streaming =
- (const struct uvc_descriptor_header * const *)strm_cls;
- }
- if (opts->uvc_ss_streaming_cls) {
- strm_cls = opts->uvc_ss_streaming_cls;
- opts->ss_streaming =
+ if (opts->uvc_streaming_cls) {
+ strm_cls = opts->uvc_streaming_cls;
+ opts->streaming =
(const struct uvc_descriptor_header * const *)strm_cls;
}
- uvc->desc.fs_control = opts->fs_control;
- uvc->desc.ss_control = opts->ss_control;
- uvc->desc.fs_streaming = opts->fs_streaming;
- uvc->desc.hs_streaming = opts->hs_streaming;
- uvc->desc.ss_streaming = opts->ss_streaming;
+ uvc->desc.control = opts->control;
+ uvc->desc.streaming = opts->streaming;
++opts->refcnt;
mutex_unlock(&opts->lock);
diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h
index 4676b60..0068203 100644
--- a/drivers/usb/gadget/function/u_uvc.h
+++ b/drivers/usb/gadget/function/u_uvc.h
@@ -34,8 +34,7 @@ struct f_uvc_opts {
* uvc_ss_control_cls arrays respectively. Legacy gadgets must
* override them in their gadget bind callback.
*/
- const struct uvc_descriptor_header * const *fs_control;
- const struct uvc_descriptor_header * const *ss_control;
+ const struct uvc_descriptor_header * const *control;
/*
* Streaming descriptors array pointers for full-speed, high-speed and
@@ -43,9 +42,7 @@ struct f_uvc_opts {
* for configfs-based gadgets. Legacy gadgets must initialize them in
* their gadget bind callback.
*/
- const struct uvc_descriptor_header * const *fs_streaming;
- const struct uvc_descriptor_header * const *hs_streaming;
- const struct uvc_descriptor_header * const *ss_streaming;
+ const struct uvc_descriptor_header * const *streaming;
/* Default control descriptors for configfs-based gadgets. */
struct uvc_camera_terminal_descriptor uvc_camera_terminal;
@@ -60,8 +57,7 @@ struct f_uvc_opts {
* descriptors. Used by configfs only, must not be touched by legacy
* gadgets.
*/
- struct uvc_descriptor_header *uvc_fs_control_cls[5];
- struct uvc_descriptor_header *uvc_ss_control_cls[5];
+ struct uvc_descriptor_header *uvc_control_cls[5];
/*
* Streaming descriptors for full-speed, high-speed and super-speed.
@@ -69,9 +65,7 @@ struct f_uvc_opts {
* arrays are allocated at runtime as the number of descriptors isn't
* known in advance.
*/
- struct uvc_descriptor_header **uvc_fs_streaming_cls;
- struct uvc_descriptor_header **uvc_hs_streaming_cls;
- struct uvc_descriptor_header **uvc_ss_streaming_cls;
+ struct uvc_descriptor_header **uvc_streaming_cls;
/*
* Read/write access to configfs attributes is handled by configfs.
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index 7d3bb62..bccdda2 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -151,11 +151,8 @@ struct uvc_device
/* Descriptors */
struct {
- const struct uvc_descriptor_header * const *fs_control;
- const struct uvc_descriptor_header * const *ss_control;
- const struct uvc_descriptor_header * const *fs_streaming;
- const struct uvc_descriptor_header * const *hs_streaming;
- const struct uvc_descriptor_header * const *ss_streaming;
+ const struct uvc_descriptor_header * const *control;
+ const struct uvc_descriptor_header * const *streaming;
} desc;
unsigned int control_intf;
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 56ab61e..7d8e588 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -509,7 +509,7 @@ static struct config_item_type uvcg_terminal_grp_type = {
/* control/class/{fs} */
static struct uvcg_control_class {
struct config_group group;
-} uvcg_control_class_fs, uvcg_control_class_ss;
+} uvcg_control_class;
static inline struct uvc_descriptor_header
@@ -518,11 +518,8 @@ static inline struct uvc_descriptor_header
struct uvcg_control_class *cl = container_of(to_config_group(i),
struct uvcg_control_class, group);
- if (cl == &uvcg_control_class_fs)
- return o->uvc_fs_control_cls;
-
- if (cl == &uvcg_control_class_ss)
- return o->uvc_ss_control_cls;
+ if (cl == &uvcg_control_class)
+ return o->uvc_control_cls;
return NULL;
}
@@ -619,26 +616,12 @@ static struct config_item_type uvcg_control_class_type = {
.ct_owner = THIS_MODULE,
};
-static struct config_group *uvcg_control_class_default_groups[] = {
- &uvcg_control_class_fs.group,
- &uvcg_control_class_ss.group,
- NULL,
-};
-
/* control/class */
-static struct uvcg_control_class_grp {
- struct config_group group;
-} uvcg_control_class_grp;
-
-static struct config_item_type uvcg_control_class_grp_type = {
- .ct_owner = THIS_MODULE,
-};
-
static struct config_group *uvcg_control_default_groups[] = {
&uvcg_control_header_grp.group,
&uvcg_processing_grp.group,
&uvcg_terminal_grp.group,
- &uvcg_control_class_grp.group,
+ &uvcg_control_class.group,
NULL,
};
@@ -1797,7 +1780,7 @@ static struct config_item_type uvcg_color_matching_grp_type = {
/* streaming/class/{fs|hs|ss} */
static struct uvcg_streaming_class {
struct config_group group;
-} uvcg_streaming_class_fs, uvcg_streaming_class_hs, uvcg_streaming_class_ss;
+} uvcg_streaming_class;
static inline struct uvc_descriptor_header
@@ -1806,14 +1789,8 @@ static inline struct uvc_descriptor_header
struct uvcg_streaming_class *cl = container_of(to_config_group(i),
struct uvcg_streaming_class, group);
- if (cl == &uvcg_streaming_class_fs)
- return &o->uvc_fs_streaming_cls;
-
- if (cl == &uvcg_streaming_class_hs)
- return &o->uvc_hs_streaming_cls;
-
- if (cl == &uvcg_streaming_class_ss)
- return &o->uvc_ss_streaming_cls;
+ if (cl == &uvcg_streaming_class)
+ return &o->uvc_streaming_cls;
return NULL;
}
@@ -2145,28 +2122,13 @@ static struct config_item_type uvcg_streaming_class_type = {
.ct_owner = THIS_MODULE,
};
-static struct config_group *uvcg_streaming_class_default_groups[] = {
- &uvcg_streaming_class_fs.group,
- &uvcg_streaming_class_hs.group,
- &uvcg_streaming_class_ss.group,
- NULL,
-};
-
/* streaming/class */
-static struct uvcg_streaming_class_grp {
- struct config_group group;
-} uvcg_streaming_class_grp;
-
-static struct config_item_type uvcg_streaming_class_grp_type = {
- .ct_owner = THIS_MODULE,
-};
-
static struct config_group *uvcg_streaming_default_groups[] = {
&uvcg_streaming_header_grp.group,
&uvcg_uncompressed_grp.group,
&uvcg_mjpeg_grp.group,
&uvcg_color_matching_grp.group,
- &uvcg_streaming_class_grp.group,
+ &uvcg_streaming_class.group,
NULL,
};
@@ -2312,16 +2274,9 @@ int uvcg_attach_configfs(struct f_uvc_opts *opts)
uvcg_terminal_default_groups,
"terminal",
&uvcg_terminal_grp_type);
- config_group_init_type_name(&uvcg_control_class_fs.group,
- "fs",
- &uvcg_control_class_type);
- config_group_init_type_name(&uvcg_control_class_ss.group,
- "ss",
+ config_group_init_type_name(&uvcg_control_class.group,
+ "desc",
&uvcg_control_class_type);
- uvcg_init_group(&uvcg_control_class_grp.group,
- uvcg_control_class_default_groups,
- "class",
- &uvcg_control_class_grp_type);
uvcg_init_group(&uvcg_control_grp.group,
uvcg_control_default_groups,
"control",
@@ -2342,19 +2297,9 @@ int uvcg_attach_configfs(struct f_uvc_opts *opts)
uvcg_color_matching_default_groups,
"color_matching",
&uvcg_color_matching_grp_type);
- config_group_init_type_name(&uvcg_streaming_class_fs.group,
- "fs",
- &uvcg_streaming_class_type);
- config_group_init_type_name(&uvcg_streaming_class_hs.group,
- "hs",
- &uvcg_streaming_class_type);
- config_group_init_type_name(&uvcg_streaming_class_ss.group,
- "ss",
+ config_group_init_type_name(&uvcg_streaming_class.group,
+ "desc",
&uvcg_streaming_class_type);
- uvcg_init_group(&uvcg_streaming_class_grp.group,
- uvcg_streaming_class_default_groups,
- "class",
- &uvcg_streaming_class_grp_type);
uvcg_init_group(&uvcg_streaming_grp.group,
uvcg_streaming_default_groups,
"streaming",
diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c
index f9661cd..ffe5ef4 100644
--- a/drivers/usb/gadget/legacy/webcam.c
+++ b/drivers/usb/gadget/legacy/webcam.c
@@ -278,7 +278,7 @@ static const struct uvc_color_matching_descriptor uvc_color_matching = {
.bMatrixCoefficients = 4,
};
-static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
+static const struct uvc_descriptor_header * const uvc_control_cls[] = {
(const struct uvc_descriptor_header *) &uvc_control_header,
(const struct uvc_descriptor_header *) &uvc_camera_terminal,
(const struct uvc_descriptor_header *) &uvc_processing,
@@ -286,39 +286,7 @@ static const struct uvc_descriptor_header * const uvc_fs_control_cls[] = {
NULL,
};
-static const struct uvc_descriptor_header * const uvc_ss_control_cls[] = {
- (const struct uvc_descriptor_header *) &uvc_control_header,
- (const struct uvc_descriptor_header *) &uvc_camera_terminal,
- (const struct uvc_descriptor_header *) &uvc_processing,
- (const struct uvc_descriptor_header *) &uvc_output_terminal,
- NULL,
-};
-
-static const struct uvc_descriptor_header * const uvc_fs_streaming_cls[] = {
- (const struct uvc_descriptor_header *) &uvc_input_header,
- (const struct uvc_descriptor_header *) &uvc_format_yuv,
- (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
- (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
- (const struct uvc_descriptor_header *) &uvc_format_mjpg,
- (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
- (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
- (const struct uvc_descriptor_header *) &uvc_color_matching,
- NULL,
-};
-
-static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
- (const struct uvc_descriptor_header *) &uvc_input_header,
- (const struct uvc_descriptor_header *) &uvc_format_yuv,
- (const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
- (const struct uvc_descriptor_header *) &uvc_frame_yuv_720p,
- (const struct uvc_descriptor_header *) &uvc_format_mjpg,
- (const struct uvc_descriptor_header *) &uvc_frame_mjpg_360p,
- (const struct uvc_descriptor_header *) &uvc_frame_mjpg_720p,
- (const struct uvc_descriptor_header *) &uvc_color_matching,
- NULL,
-};
-
-static const struct uvc_descriptor_header * const uvc_ss_streaming_cls[] = {
+static const struct uvc_descriptor_header * const uvc_streaming_cls[] = {
(const struct uvc_descriptor_header *) &uvc_input_header,
(const struct uvc_descriptor_header *) &uvc_format_yuv,
(const struct uvc_descriptor_header *) &uvc_frame_yuv_360p,
@@ -385,11 +353,8 @@ webcam_bind(struct usb_composite_dev *cdev)
uvc_opts->streaming_maxburst = streaming_maxburst;
uvc_set_trace_param(trace);
- uvc_opts->fs_control = uvc_fs_control_cls;
- uvc_opts->ss_control = uvc_ss_control_cls;
- uvc_opts->fs_streaming = uvc_fs_streaming_cls;
- uvc_opts->hs_streaming = uvc_hs_streaming_cls;
- uvc_opts->ss_streaming = uvc_ss_streaming_cls;
+ uvc_opts->control = uvc_control_cls;
+ uvc_opts->streaming = uvc_streaming_cls;
/* Allocate string descriptor numbers ... note that string contents
* can be overridden by the composite_dev glue.
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 14:00 +0100 |
| Subject | [PATCH v4 09/43] usb: gadget: composite: handle function bind |
| Message-ID | <qY5cm-24p-5@gated-at.bofh.it> |
| In reply to | #1325342 |
As now USB function supplies entity descriptors to composite in
prep_descs() callback, we can perform bind inside composite framework
without involving bind() callback (which now is unused and will be
removed after converting all functions in kernel to new API).
For now we bind each configuration when it's added, because we have
to support functions based on old API, but after completing conversion
of functions, we will be able to do bind after adding all configurations.
Also more sophisticated autoconfig solver will be provided to improve
utilization of available hardware endpoints.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/composite.c | 162 +++++++++++++++++++++++++++++++++++++++++
include/linux/usb/composite.h | 3 +
2 files changed, 165 insertions(+)
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 3f9cad8..f196bb6 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -327,6 +327,21 @@ int usb_function_activate(struct usb_function *function)
EXPORT_SYMBOL_GPL(usb_function_activate);
/**
+ * usb_function_is_new_api - checks if USB function uses new API
+ * @f: USB function
+ *
+ * This function is added temporarily to allow both old and new function API
+ * to coexist. It function will be removed after converting all USB functions
+ * in kernel to new API.
+ *
+ * Returns true if function uses new API.
+ */
+static inline bool usb_function_is_new_api(struct usb_function *f)
+{
+ return !!f->prep_descs;
+}
+
+/**
* usb_function_set_descs - assing descriptors to USB function
* @f: USB function
* @descs: USB descriptors to be assigned to function
@@ -1108,6 +1123,12 @@ int usb_add_config(struct usb_composite_dev *cdev,
goto done;
status = bind(config);
+ if (status < 0)
+ goto out;
+
+ status = usb_config_do_bind(config);
+
+out:
if (status < 0) {
while (!list_empty(&config->functions)) {
struct usb_function *f;
@@ -2403,6 +2424,147 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)
device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
}
+/**
+ * usb_cmp_ep_descs - compare descriptors of two endpoints
+ *
+ * As currently during autoconfig procedure we take into consideration only
+ * FullSpeed and SuperSpeed Companion descriptors, we need to compare only
+ * these descriptors. It they are the same, endpoints are identical from
+ * autoconfig point of view.
+ */
+static int usb_cmp_ep_descs(struct usb_composite_ep *ep1,
+ struct usb_composite_ep *ep2)
+{
+ if (ep1->fs.desc->bLength != ep2->fs.desc->bLength)
+ return 0;
+ if (usb_endpoint_dir_in(ep1->fs.desc) ^
+ usb_endpoint_dir_in(ep2->fs.desc))
+ return 0;
+ if (ep1->fs.desc->bmAttributes != ep2->fs.desc->bmAttributes)
+ return 0;
+ if (ep1->fs.desc->wMaxPacketSize != ep2->fs.desc->wMaxPacketSize)
+ return 0;
+ if (ep1->fs.desc->bInterval != ep2->fs.desc->bInterval)
+ return 0;
+
+ if (ep1->fs.desc->bLength != USB_DT_ENDPOINT_AUDIO_SIZE)
+ goto ss_comp;
+
+ if (ep1->fs.desc->bRefresh != ep2->fs.desc->bRefresh)
+ return 0;
+ if (ep1->fs.desc->bSynchAddress != ep2->fs.desc->bSynchAddress)
+ return 0;
+
+ss_comp:
+ if (!ep1->ss_comp.desc ^ !ep2->ss_comp.desc)
+ return 0;
+ if (!ep1->ss_comp.desc)
+ return 1;
+
+ if (ep1->ss_comp.desc->bMaxBurst != ep2->ss_comp.desc->bMaxBurst)
+ return 0;
+ if (ep1->ss_comp.desc->bmAttributes != ep2->ss_comp.desc->bmAttributes)
+ return 0;
+ if (ep1->ss_comp.desc->wBytesPerInterval !=
+ ep2->ss_comp.desc->wBytesPerInterval)
+ return 0;
+
+ return 1;
+}
+
+/**
+ * ep_update_address() - update endpoint address in descriptors
+ * @ep: composite endpoint with assigned hardware ep
+ *
+ * This function should be called after setting ep->ep to endpoint obtained
+ * from usb_ep_autoconfig_ss(), to update endpoint address in descriptors for
+ * all supported speeds.
+ */
+static inline void ep_update_address(struct usb_composite_ep *ep)
+{
+ if (ep->fs.desc)
+ ep->hs.desc->bEndpointAddress = ep->ep->address;
+ if (ep->hs.desc)
+ ep->hs.desc->bEndpointAddress = ep->ep->address;
+ if (ep->ss.desc)
+ ep->ss.desc->bEndpointAddress = ep->ep->address;
+}
+
+/**
+ * interface_do_bind() - bind interface to UDC
+ * @c: USB configuration
+ * @f: USB function in configuration c
+ * @intf: USB interface in function f
+ *
+ * For now we use only simple interface-level ep aucoconfig solver.
+ * We share endpoints between altsettings where it's possible.
+ */
+static int interface_do_bind(struct usb_configuration *c,
+ struct usb_function *f, struct usb_composite_intf *intf)
+{
+ struct usb_composite_altset *alt, *altx;
+ struct usb_composite_ep *ep, *epx;
+ int a, e, ax, ex;
+
+ intf->id = usb_interface_id(c, f);
+ intf->cur_altset = -1;
+
+ for (a = 0; a < intf->altsets_num; ++a) {
+ alt = intf->altsets[a];
+ alt->alt.desc->bInterfaceNumber = intf->id;
+ for (e = 0; e < alt->eps_num; ++e) {
+ ep = alt->eps[e];
+ if (ep->ep)
+ continue;
+ ep->ep = usb_ep_autoconfig_ss(c->cdev->gadget,
+ ep->fs.desc, ep->ss_comp.desc);
+ if (!ep->ep)
+ return -ENODEV;
+ ep_update_address(ep);
+ /* Try endpoint for other altsets */
+ for (ax = a + 1; ax < intf->altsets_num; ++ax) {
+ altx = intf->altsets[ax];
+ for (ex = 0; ex < altx->eps_num; ++ex) {
+ epx = altx->eps[ex];
+ if (usb_cmp_ep_descs(ep, epx)) {
+ epx->ep = ep->ep;
+ ep_update_address(epx);
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * config_do_bind() - bind configuration to UDC
+ * @c: USB configuration
+ *
+ * Bind the all functions in configuration to UDC.
+ */
+int usb_config_do_bind(struct usb_configuration *c)
+{
+ struct usb_function *f;
+ struct usb_composite_intf *intf;
+ int i, ret;
+
+ list_for_each_entry(f, &c->functions, list) {
+ if (!usb_function_is_new_api(f))
+ continue;
+ for (i = 0; i < f->descs->intfs_num; ++i) {
+ intf = f->descs->intfs[i];
+ ret = interface_do_bind(c, f, intf);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_config_do_bind);
+
static int composite_bind(struct usb_gadget *gadget,
struct usb_gadget_driver *gdriver)
{
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 7ede101..0a0ff4c 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -420,6 +420,7 @@ int usb_altset_add_vendor_desc(struct usb_function *f, int i, int a,
int usb_ep_add_vendor_desc(struct usb_function *f, int i, int a, int e,
const struct usb_descriptor_header *desc);
+
int usb_interface_id(struct usb_configuration *, struct usb_function *);
int config_ep_by_speed(struct usb_gadget *g, struct usb_function *f,
@@ -510,6 +511,8 @@ int usb_add_config(struct usb_composite_dev *,
void usb_remove_config(struct usb_composite_dev *,
struct usb_configuration *);
+int usb_config_do_bind(struct usb_configuration *c);
+
/* predefined index for usb_composite_driver */
enum {
USB_GADGET_MANUFACTURER_IDX = 0,
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | kbuild test robot <lkp@intel.com> |
|---|---|
| Date | 2016-02-04 06:50 +0100 |
| Subject | Re: [PATCH v4 09/43] usb: gadget: composite: handle function bind |
| Message-ID | <qYkXM-4pW-11@gated-at.bofh.it> |
| In reply to | #1325379 |
[Multipart message — attachments visible in raw view] — view raw
Hi Robert,
[auto build test WARNING on usb/usb-testing]
[also build test WARNING on v4.5-rc2 next-20160203]
[if your patch is applied to the wrong git tree, please drop us a note to help improving the system]
url: https://github.com/0day-ci/linux/commits/Robert-Baldyga/usb-gadget-composite-introduce-new-function-API/20160203-205850
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
reproduce: make htmldocs
All warnings (new ones prefixed by >>):
include/linux/usb/gadget.h:227: warning: No description found for parameter 'claimed'
include/linux/usb/gadget.h:227: warning: No description found for parameter 'enabled'
include/linux/usb/gadget.h:652: warning: No description found for parameter 'quirk_altset_not_supp'
include/linux/usb/gadget.h:652: warning: No description found for parameter 'quirk_stall_not_supp'
include/linux/usb/gadget.h:652: warning: No description found for parameter 'quirk_zlp_not_supp'
include/linux/usb/composite.h:114: warning: No description found for parameter 'ss_comp'
include/linux/usb/composite.h:141: warning: No description found for parameter 'alt'
include/linux/usb/composite.h:691: warning: Excess struct/union/enum/typedef member 'setup_pending' description in 'usb_composite_dev'
include/linux/usb/composite.h:691: warning: Excess struct/union/enum/typedef member 'os_desc_pending' description in 'usb_composite_dev'
>> drivers/usb/gadget/composite.c:2437: warning: No description found for parameter 'ep1'
>> drivers/usb/gadget/composite.c:2437: warning: No description found for parameter 'ep2'
drivers/usb/gadget/function/f_acm.c:1: warning: no structured comments found
drivers/usb/gadget/function/f_ecm.c:1: warning: no structured comments found
drivers/usb/gadget/function/f_subset.c:1: warning: no structured comments found
drivers/usb/gadget/function/f_obex.c:1: warning: no structured comments found
drivers/usb/gadget/function/f_serial.c:1: warning: no structured comments found
vim +/ep1 +2437 drivers/usb/gadget/composite.c
2421 usb_ep_free_request(cdev->gadget->ep0, cdev->req);
2422 }
2423 cdev->next_string_id = 0;
2424 device_remove_file(&cdev->gadget->dev, &dev_attr_suspended);
2425 }
2426
2427 /**
2428 * usb_cmp_ep_descs - compare descriptors of two endpoints
2429 *
2430 * As currently during autoconfig procedure we take into consideration only
2431 * FullSpeed and SuperSpeed Companion descriptors, we need to compare only
2432 * these descriptors. It they are the same, endpoints are identical from
2433 * autoconfig point of view.
2434 */
2435 static int usb_cmp_ep_descs(struct usb_composite_ep *ep1,
2436 struct usb_composite_ep *ep2)
> 2437 {
2438 if (ep1->fs.desc->bLength != ep2->fs.desc->bLength)
2439 return 0;
2440 if (usb_endpoint_dir_in(ep1->fs.desc) ^
2441 usb_endpoint_dir_in(ep2->fs.desc))
2442 return 0;
2443 if (ep1->fs.desc->bmAttributes != ep2->fs.desc->bmAttributes)
2444 return 0;
2445 if (ep1->fs.desc->wMaxPacketSize != ep2->fs.desc->wMaxPacketSize)
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 14:00 +0100 |
| Subject | [PATCH v4 01/43] usb: gadget: f_sourcesink: make ISO altset user-selectable |
| Message-ID | <qY5cn-24p-19@gated-at.bofh.it> |
| In reply to | #1325342 |
So far it was decided during the bind process whether is iso altsetting
included to f_sourcesink function or not. This decision was based on
availability of isochronous endpoints.
Since we can assemble gadget driver using composite framework and configfs
from many different functions, availability of given type of endpoint
can depend on selected components or even on their order in given
configuration.
This can result with non-obvious behavior - even small, seemingly unrelated
change in gadget configuration can decide if we have second altsetting with
iso endpoints in given sourcesink function instance or not.
Because of this it's way better to have additional parameter allowing user
to decide if he/she wants to have iso altsetting, and if iso altsetting is
included, and there are no iso endpoints available, function bind will fail
instead of silently allowing to have non-complete function bound.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/function/f_sourcesink.c | 98 ++++++++++++++++++++----------
drivers/usb/gadget/function/g_zero.h | 3 +
drivers/usb/gadget/legacy/zero.c | 6 ++
3 files changed, 76 insertions(+), 31 deletions(-)
diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index 242ba5c..e950031 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -49,6 +49,7 @@ struct f_sourcesink {
unsigned isoc_maxpacket;
unsigned isoc_mult;
unsigned isoc_maxburst;
+ unsigned isoc_enabled;
unsigned buflen;
unsigned bulk_qlen;
unsigned iso_qlen;
@@ -336,17 +337,28 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
/* allocate bulk endpoints */
ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc);
- if (!ss->in_ep) {
-autoconf_fail:
- ERROR(cdev, "%s: can't autoconfigure on %s\n",
- f->name, cdev->gadget->name);
- return -ENODEV;
- }
+ if (!ss->in_ep)
+ goto autoconf_fail;
ss->out_ep = usb_ep_autoconfig(cdev->gadget, &fs_sink_desc);
if (!ss->out_ep)
goto autoconf_fail;
+ /* support high speed hardware */
+ hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
+ hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
+
+ /* support super speed hardware */
+ ss_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
+ ss_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
+
+ if (!ss->isoc_enabled) {
+ fs_source_sink_descs[FS_ALT_IFC_1_OFFSET] = NULL;
+ hs_source_sink_descs[HS_ALT_IFC_1_OFFSET] = NULL;
+ ss_source_sink_descs[SS_ALT_IFC_1_OFFSET] = NULL;
+ goto no_iso;
+ }
+
/* sanity check the isoc module parameters */
if (ss->isoc_interval < 1)
ss->isoc_interval = 1;
@@ -368,30 +380,14 @@ autoconf_fail:
/* allocate iso endpoints */
ss->iso_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_source_desc);
if (!ss->iso_in_ep)
- goto no_iso;
+ goto autoconf_fail;
ss->iso_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_sink_desc);
- if (!ss->iso_out_ep) {
- usb_ep_autoconfig_release(ss->iso_in_ep);
- ss->iso_in_ep = NULL;
-no_iso:
- /*
- * We still want to work even if the UDC doesn't have isoc
- * endpoints, so null out the alt interface that contains
- * them and continue.
- */
- fs_source_sink_descs[FS_ALT_IFC_1_OFFSET] = NULL;
- hs_source_sink_descs[HS_ALT_IFC_1_OFFSET] = NULL;
- ss_source_sink_descs[SS_ALT_IFC_1_OFFSET] = NULL;
- }
+ if (!ss->iso_out_ep)
+ goto autoconf_fail;
if (ss->isoc_maxpacket > 1024)
ss->isoc_maxpacket = 1024;
-
- /* support high speed hardware */
- hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
- hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
-
/*
* Fill in the HS isoc descriptors from the module parameters.
* We assume that the user knows what they are doing and won't
@@ -408,12 +404,6 @@ no_iso:
hs_iso_sink_desc.bInterval = ss->isoc_interval;
hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
- /* support super speed hardware */
- ss_source_desc.bEndpointAddress =
- fs_source_desc.bEndpointAddress;
- ss_sink_desc.bEndpointAddress =
- fs_sink_desc.bEndpointAddress;
-
/*
* Fill in the SS isoc descriptors from the module parameters.
* We assume that the user knows what they are doing and won't
@@ -436,6 +426,7 @@ no_iso:
(ss->isoc_mult + 1) * (ss->isoc_maxburst + 1);
ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
+no_iso:
ret = usb_assign_descriptors(f, fs_source_sink_descs,
hs_source_sink_descs, ss_source_sink_descs);
if (ret)
@@ -448,6 +439,11 @@ no_iso:
ss->iso_in_ep ? ss->iso_in_ep->name : "<none>",
ss->iso_out_ep ? ss->iso_out_ep->name : "<none>");
return 0;
+
+autoconf_fail:
+ ERROR(cdev, "%s: can't autoconfigure on %s\n",
+ f->name, cdev->gadget->name);
+ return -ENODEV;
}
static void
@@ -857,6 +853,7 @@ static struct usb_function *source_sink_alloc_func(
ss->isoc_maxpacket = ss_opts->isoc_maxpacket;
ss->isoc_mult = ss_opts->isoc_mult;
ss->isoc_maxburst = ss_opts->isoc_maxburst;
+ ss->isoc_enabled = ss_opts->isoc_enabled;
ss->buflen = ss_opts->bulk_buflen;
ss->bulk_qlen = ss_opts->bulk_qlen;
ss->iso_qlen = ss_opts->iso_qlen;
@@ -1106,6 +1103,44 @@ end:
CONFIGFS_ATTR(f_ss_opts_, isoc_maxburst);
+static ssize_t f_ss_opts_isoc_enabled_show(struct config_item *item, char *page)
+{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
+ int result;
+
+ mutex_lock(&opts->lock);
+ result = sprintf(page, "%u\n", opts->isoc_enabled);
+ mutex_unlock(&opts->lock);
+
+ return result;
+}
+
+static ssize_t f_ss_opts_isoc_enabled_store(struct config_item *item,
+ const char *page, size_t len)
+{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
+ int ret;
+ bool enabled;
+
+ mutex_lock(&opts->lock);
+ if (opts->refcnt) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ ret = strtobool(page, &enabled);
+ if (ret)
+ goto end;
+
+ opts->isoc_enabled = enabled;
+ ret = len;
+end:
+ mutex_unlock(&opts->lock);
+ return ret;
+}
+
+CONFIGFS_ATTR(f_ss_opts_, isoc_enabled);
+
static ssize_t f_ss_opts_bulk_buflen_show(struct config_item *item, char *page)
{
struct f_ss_opts *opts = to_f_ss_opts(item);
@@ -1226,6 +1261,7 @@ static struct configfs_attribute *ss_attrs[] = {
&f_ss_opts_attr_isoc_maxpacket,
&f_ss_opts_attr_isoc_mult,
&f_ss_opts_attr_isoc_maxburst,
+ &f_ss_opts_attr_isoc_enabled,
&f_ss_opts_attr_bulk_buflen,
&f_ss_opts_attr_bulk_qlen,
&f_ss_opts_attr_iso_qlen,
diff --git a/drivers/usb/gadget/function/g_zero.h b/drivers/usb/gadget/function/g_zero.h
index 492924d0..ae03278 100644
--- a/drivers/usb/gadget/function/g_zero.h
+++ b/drivers/usb/gadget/function/g_zero.h
@@ -10,6 +10,7 @@
#define GZERO_QLEN 32
#define GZERO_ISOC_INTERVAL 4
#define GZERO_ISOC_MAXPACKET 1024
+#define GZERO_ISOC_ENABLED 1
#define GZERO_SS_BULK_QLEN 1
#define GZERO_SS_ISO_QLEN 8
@@ -19,6 +20,7 @@ struct usb_zero_options {
unsigned isoc_maxpacket;
unsigned isoc_mult;
unsigned isoc_maxburst;
+ unsigned isoc_enabled;
unsigned bulk_buflen;
unsigned qlen;
unsigned ss_bulk_qlen;
@@ -32,6 +34,7 @@ struct f_ss_opts {
unsigned isoc_maxpacket;
unsigned isoc_mult;
unsigned isoc_maxburst;
+ unsigned isoc_enabled;
unsigned bulk_buflen;
unsigned bulk_qlen;
unsigned iso_qlen;
diff --git a/drivers/usb/gadget/legacy/zero.c b/drivers/usb/gadget/legacy/zero.c
index d02e2ce..6adfc88 100644
--- a/drivers/usb/gadget/legacy/zero.c
+++ b/drivers/usb/gadget/legacy/zero.c
@@ -66,6 +66,7 @@ module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
static struct usb_zero_options gzero_options = {
.isoc_interval = GZERO_ISOC_INTERVAL,
.isoc_maxpacket = GZERO_ISOC_MAXPACKET,
+ .isoc_enabled = GZERO_ISOC_ENABLED,
.bulk_buflen = GZERO_BULK_BUFLEN,
.qlen = GZERO_QLEN,
.ss_bulk_qlen = GZERO_SS_BULK_QLEN,
@@ -251,6 +252,10 @@ module_param_named(isoc_maxburst, gzero_options.isoc_maxburst, uint,
S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)");
+module_param_named(isoc_enabled, gzero_options.isoc_enabled, uint,
+ S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(isoc_enabled, "0 - disabled, 1 - enabled");
+
static struct usb_function *func_lb;
static struct usb_function_instance *func_inst_lb;
@@ -294,6 +299,7 @@ static int zero_bind(struct usb_composite_dev *cdev)
ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket;
ss_opts->isoc_mult = gzero_options.isoc_mult;
ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;
+ ss_opts->isoc_enabled = gzero_options.isoc_enabled;
ss_opts->bulk_buflen = gzero_options.bulk_buflen;
ss_opts->bulk_qlen = gzero_options.ss_bulk_qlen;
ss_opts->iso_qlen = gzero_options.ss_iso_qlen;
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 14:00 +0100 |
| Subject | [PATCH v4 12/43] usb: gadget: composite: disable eps before calling disable() callback |
| Message-ID | <qY5cn-24p-17@gated-at.bofh.it> |
| In reply to | #1325342 |
Changes meaning of disable() operation for functions using new API.
Before calling disable() callback composite automatically disables
endpoints of active altsettings of given USB function. This reduces
amount of boilerplate code in USB functions.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/composite.c | 51 ++++++++++++++++++++++++++++++++++++------
1 file changed, 44 insertions(+), 7 deletions(-)
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index c34725b..f2c08b3 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -246,12 +246,12 @@ done:
}
EXPORT_SYMBOL_GPL(usb_add_function);
+static void disable_function(struct usb_function *f);
+
void usb_remove_function(struct usb_configuration *c, struct usb_function *f)
{
- if (f->disable)
- f->disable(f);
+ disable_function(f);
- bitmap_zero(f->endpoints, 32);
list_del(&f->list);
if (f->unbind)
f->unbind(c, f);
@@ -942,6 +942,46 @@ static void device_qual(struct usb_composite_dev *cdev)
/*-------------------------------------------------------------------------*/
+/**
+ * disable_interface - disable all endpoints in given interface
+ * @f: USB function
+ * @i: interface index in function
+ */
+static void disable_interface(struct usb_function *f, unsigned i)
+{
+ struct usb_composite_intf *intf;
+ struct usb_composite_altset *alt;
+ int e;
+
+ intf = f->descs->intfs[i];
+ if (intf->cur_altset < 0)
+ return;
+
+ alt = intf->altsets[intf->cur_altset];
+ for (e = 0; e < alt->eps_num; ++e)
+ usb_ep_disable(alt->eps[e]->ep);
+
+ intf->cur_altset = -1;
+}
+
+/**
+ * disable_function - disable all endpoints in given function
+ * @f: USB function
+ */
+static void disable_function(struct usb_function *f)
+{
+ int i;
+
+ if (usb_function_is_new_api(f))
+ for (i = 0; i < f->descs->intfs_num; ++i)
+ disable_interface(f, i);
+
+ if (f->disable)
+ f->disable(f);
+
+ bitmap_zero(f->endpoints, 32);
+}
+
static void reset_config(struct usb_composite_dev *cdev)
{
struct usb_function *f;
@@ -949,10 +989,7 @@ static void reset_config(struct usb_composite_dev *cdev)
DBG(cdev, "reset config\n");
list_for_each_entry(f, &cdev->config->functions, list) {
- if (f->disable)
- f->disable(f);
-
- bitmap_zero(f->endpoints, 32);
+ disable_function(f);
}
cdev->config = NULL;
cdev->delayed_status = 0;
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 14:00 +0100 |
| Subject | [PATCH v4 17/43] usb: gadget: composite: add usb_get_interface_id() function |
| Message-ID | <qY5cn-24p-27@gated-at.bofh.it> |
| In reply to | #1325342 |
Introduce function returning id of interface at given index in function.
The id value is equal bInterfaceNumber field in interface descriptor.
This value can be useful during preparation of class or vendor specific
descriptors in prep_vendor_descs() callback. It can be also necessary
to handle some class or vendor specific setup requests.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/composite.c | 19 +++++++++++++++++++
include/linux/usb/composite.h | 2 ++
2 files changed, 21 insertions(+)
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 452294e..7e3721d 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -670,6 +670,25 @@ static int usb_interface_id_to_index(struct usb_function *f, u8 id)
}
/**
+ * usb_get_interface_id - get id number of interface at given index in
+ * USB function
+ * @f: USB function
+ * @i: index of interface in function
+ *
+ * Returns interface id on success, else negative errno.
+ */
+int usb_get_interface_id(struct usb_function *f, int i)
+{
+ if (!f->descs)
+ return -ENODEV;
+ if (f->descs->intfs_num <= i)
+ return -ENODEV;
+
+ return f->descs->intfs[i]->id;
+}
+EXPORT_SYMBOL_GPL(usb_get_interface_id);
+
+/**
* usb_function_get_ep - obtains endpoint of given index from active
* altsetting of given interface
* @f: USB function
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 2e646e3..b2fb260 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -425,6 +425,8 @@ int usb_ep_add_vendor_desc(struct usb_function *f, int i, int a, int e,
const struct usb_descriptor_header *desc);
+int usb_get_interface_id(struct usb_function *f, int i);
+
struct usb_ep *usb_function_get_ep(struct usb_function *f, int intf, int ep);
int usb_interface_id(struct usb_configuration *, struct usb_function *);
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 14:00 +0100 |
| Subject | [PATCH v4 19/43] usb: gadget: composite: enable adding USB functions using new API |
| Message-ID | <qY5cn-24p-29@gated-at.bofh.it> |
| In reply to | #1325342 |
Enable adding USB functions which use new API. Check if all necessary
function ops are supplied and call prep_descs() to allow function register
it's entity descriptors. Notice that bind() function is not called for
USB functions using new API, as now bind procedure is handled for them
in composite framework.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/composite.c | 49 ++++++++++++++++++++++++++++++++++--------
1 file changed, 40 insertions(+), 9 deletions(-)
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 417e2f9..0afb54c 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -181,6 +181,8 @@ ep_found:
}
EXPORT_SYMBOL_GPL(config_ep_by_speed);
+static inline bool usb_function_is_new_api(struct usb_function *f);
+
/**
* usb_add_function() - add a function to a configuration
* @config: the configuration
@@ -198,15 +200,12 @@ EXPORT_SYMBOL_GPL(config_ep_by_speed);
int usb_add_function(struct usb_configuration *config,
struct usb_function *function)
{
- int value = -EINVAL;
+ int value;
DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
function->name, function,
config->label, config);
- if (!function->set_alt || !function->disable)
- goto done;
-
function->config = config;
list_add_tail(&function->list, &config->functions);
@@ -216,13 +215,22 @@ int usb_add_function(struct usb_configuration *config,
goto done;
}
+ value = -EINVAL;
+
+ if (!function->set_alt)
+ goto done;
+
+ if (usb_function_is_new_api(function))
+ goto new_api;
+
+ if (!function->disable)
+ goto done;
+
/* REVISIT *require* function->bind? */
if (function->bind) {
value = function->bind(config, function);
- if (value < 0) {
- list_del(&function->list);
- function->config = NULL;
- }
+ if (value < 0)
+ goto done;
} else
value = 0;
@@ -238,10 +246,33 @@ int usb_add_function(struct usb_configuration *config,
if (!config->superspeed && function->ss_descriptors)
config->superspeed = true;
-done:
+ goto done;
+
+new_api:
+ if (!function->prep_descs)
+ goto done;
+
+ if (!function->clear_alt)
+ goto done;
+
+ value = function->prep_descs(function);
if (value)
+ goto done;
+
+ if (!config->fullspeed && function->descs->fullspeed)
+ config->fullspeed = true;
+ if (!config->highspeed && function->descs->highspeed)
+ config->highspeed = true;
+ if (!config->superspeed && function->descs->superspeed)
+ config->superspeed = true;
+
+done:
+ if (value) {
+ list_del(&function->list);
+ function->config = NULL;
DBG(config->cdev, "adding '%s'/%p --> %d\n",
function->name, function, value);
+ }
return value;
}
EXPORT_SYMBOL_GPL(usb_add_function);
--
1.9.1
[toc] | [prev] | [next] | [standalone]
| From | Robert Baldyga <r.baldyga@samsung.com> |
|---|---|
| Date | 2016-02-03 14:00 +0100 |
| Subject | [PATCH v4 05/43] usb: gadget: composite: fix recursive spinlock locking |
| Message-ID | <qY5co-24p-37@gated-at.bofh.it> |
| In reply to | #1325342 |
Avoid recursive spinlock locking, which could occur during
usb_gadget_deactivate() call. At it's execution path it could call
composite_disconnect() function which locks cdev->lock, previously
locked in usb_function_deactivate() to protect deactivation counter.
To fix this we introduce additional spinlock protecting deactivation
counter.
Signed-off-by: Robert Baldyga <r.baldyga@samsung.com>
---
drivers/usb/gadget/composite.c | 9 +++++----
include/linux/usb/composite.h | 1 +
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 8b14c2a..65abc24 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -283,14 +283,14 @@ int usb_function_deactivate(struct usb_function *function)
unsigned long flags;
int status = 0;
- spin_lock_irqsave(&cdev->lock, flags);
+ spin_lock_irqsave(&cdev->deactivation_lock, flags);
if (cdev->deactivations == 0)
status = usb_gadget_deactivate(cdev->gadget);
if (status == 0)
cdev->deactivations++;
- spin_unlock_irqrestore(&cdev->lock, flags);
+ spin_unlock_irqrestore(&cdev->deactivation_lock, flags);
return status;
}
EXPORT_SYMBOL_GPL(usb_function_deactivate);
@@ -311,7 +311,7 @@ int usb_function_activate(struct usb_function *function)
unsigned long flags;
int status = 0;
- spin_lock_irqsave(&cdev->lock, flags);
+ spin_lock_irqsave(&cdev->deactivation_lock, flags);
if (WARN_ON(cdev->deactivations == 0))
status = -EINVAL;
@@ -321,7 +321,7 @@ int usb_function_activate(struct usb_function *function)
status = usb_gadget_activate(cdev->gadget);
}
- spin_unlock_irqrestore(&cdev->lock, flags);
+ spin_unlock_irqrestore(&cdev->deactivation_lock, flags);
return status;
}
EXPORT_SYMBOL_GPL(usb_function_activate);
@@ -2072,6 +2072,7 @@ static int composite_bind(struct usb_gadget *gadget,
return status;
spin_lock_init(&cdev->lock);
+ spin_lock_init(&cdev->deactivation_lock);
cdev->gadget = gadget;
set_gadget_data(gadget, cdev);
INIT_LIST_HEAD(&cdev->configs);
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 1074b89..9911c29 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -487,6 +487,7 @@ struct usb_composite_dev {
* while the deactivation count is nonzero.
*/
unsigned deactivations;
+ spinlock_t deactivation_lock;
/* the composite driver won't complete the control transfer's
* data/status stages till delayed_status is zero.
--
1.9.1
[toc] | [prev] | [next] | [standalone]
Page 2 of 3 — ← Prev page 1 [2] 3 Next page →
Back to top | Article view | linux.kernel
csiph-web