/* #define VERBOSE_DEBUG */
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) "["KBUILD_MODNAME"]" fmt
+
#include <linux/kallsyms.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/usb/composite.h>
#include <asm/unaligned.h>
+#include <linux/printk.h>
+
+
+
/*
* The code in this file is utility code, used to build a gadget driver
* from one or more "function" drivers, one or more "configuration"
struct usb_function *function)
{
int value = -EINVAL;
+
+ pr_debug("[XLOG_DEBUG][USB][COM]%s: \n", __func__);
- DBG(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
+ INFO(config->cdev, "adding '%s'/%p to config '%s'/%p\n",
function->name, function,
config->label, config);
done:
if (value)
- DBG(config->cdev, "adding '%s'/%p --> %d\n",
+ INFO(config->cdev, "adding '%s'/%p --> %d\n",
function->name, function, value);
return value;
}
void usb_remove_function(struct usb_configuration *c, struct usb_function *f)
{
- if (f->disable)
+ if (f->disable) {
+ INFO(c->cdev, "disable function '%s'/%p\n", f->name, f);
f->disable(f);
+ }
bitmap_zero(f->endpoints, 32);
list_del(&f->list);
- if (f->unbind)
+ if (f->unbind) {
+ INFO(c->cdev, "unbind function '%s'/%p\n", f->name, f);
f->unbind(c, f);
+ }
}
EXPORT_SYMBOL_GPL(usb_remove_function);
usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
- usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT | USB_BESL_SUPPORT);
+#ifdef CONFIG_USBIF_COMPLIANCE
+ usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT) | cpu_to_le32(USB_BESL_SUPPORT) ;
+#else
+ usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
+#endif
/*
* The Superspeed USB Capability descriptor shall be implemented by all
DBG(cdev, "reset config\n");
list_for_each_entry(f, &cdev->config->functions, list) {
+ INFO(cdev, "disable function '%s'/%p\n", f->name, f);
if (f->disable)
f->disable(f);
struct usb_function, list);
list_del(&f->list);
if (f->unbind) {
- DBG(cdev, "unbind function '%s'/%p\n",
+ INFO(cdev, "unbind function '%s'/%p\n",
f->name, f);
f->unbind(config, f);
/* may free memory for "f" */
}
}
list_del(&config->list);
+ pr_debug("[XLOG_DEBUG][USB][COM]bind fialed and the list should be init because there is one entry only");
config->cdev = NULL;
} else {
unsigned i;
- DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
+ INFO(cdev, "cfg %d/%p speeds:%s%s%s\n",
config->bConfigurationValue, config,
config->superspeed ? " super" : "",
config->highspeed ? " high" : "",
}
EXPORT_SYMBOL_GPL(usb_add_config);
-static void remove_config(struct usb_composite_dev *cdev,
+static void unbind_config(struct usb_composite_dev *cdev,
struct usb_configuration *config)
{
while (!list_empty(&config->functions)) {
struct usb_function, list);
list_del(&f->list);
if (f->unbind) {
- DBG(cdev, "unbind function '%s'/%p\n", f->name, f);
+ INFO(cdev, "unbind function '%s'/%p\n", f->name, f);
f->unbind(config, f);
/* may free memory for "f" */
}
}
- list_del(&config->list);
if (config->unbind) {
- DBG(cdev, "unbind config '%s'/%p\n", config->label, config);
+ INFO(cdev, "unbind config '%s'/%p\n", config->label, config);
config->unbind(config);
/* may free memory for "c" */
}
+
+ /* reset all driver data to prevent leakage of ep allocation */
+ usb_ep_autoconfig_reset(cdev->gadget);
}
/**
if (cdev->config == config)
reset_config(cdev);
+
+ if(config->cdev != NULL)
+ {
+ list_del(&config->list);
+ }else
+ {
+ DBG(cdev, "%s: config->list has been delete!! \n", __func__);
+ }
+
spin_unlock_irqrestore(&cdev->lock, flags);
- remove_config(cdev, config);
+ unbind_config(cdev, config);
}
/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*/
-static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
+void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
{
if (req->status || req->actual != req->length)
DBG((struct usb_composite_dev *) ep->driver_data,
req->status, req->actual, req->length);
}
+EXPORT_SYMBOL_GPL(composite_setup_complete);
+
/*
* The setup() callback implements all the ep0 functionality that's
* not handled lower down, in hardware or the hardware driver(like
struct usb_function *f = NULL;
u8 endp;
+ pr_debug("[XLOG_DEBUG][USB][COM]%s bRequest=0x%X\n",
+ __func__, ctrl->bRequest);
+
/* partial re-init of the response message; the function or the
* gadget might need to intercept e.g. a control-OUT completion
* when we delegate to it.
if (ctrl->bRequestType != USB_DIR_IN)
goto unknown;
switch (w_value >> 8) {
-
+#ifdef CONFIG_USBIF_COMPLIANCE
+ case USB_DT_OTG:
+ {
+ struct usb_otg_descriptor *otg_desc = req->buf;
+ otg_desc->bLength = sizeof(*otg_desc);
+ otg_desc->bDescriptorType = USB_DT_OTG;
+ otg_desc->bmAttributes = USB_OTG_SRP | USB_OTG_HNP;
+ otg_desc->bcdOTG = cpu_to_le16(0x0200);
+ value = min_t(int, w_length,sizeof(struct usb_otg_descriptor));
+ }
+ break;
+#endif
case USB_DT_DEVICE:
cdev->desc.bNumConfigurations =
count_configs(cdev, USB_DT_DEVICE);
value = min(w_length, (u16) sizeof cdev->desc);
memcpy(req->buf, &cdev->desc, value);
+ pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR: "
+ "USB_DT_DEVICE, value=%d\n",value);
break;
case USB_DT_DEVICE_QUALIFIER:
if (!gadget_is_dualspeed(gadget) ||
device_qual(cdev);
value = min_t(int, w_length,
sizeof(struct usb_qualifier_descriptor));
+ pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR: "
+ "USB_DT_DEVICE_QUALIFIER, value=%d\n",value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
+ pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR: "
+ "USB_DT_OTHER_SPEED_CONFIG\n");
if (!gadget_is_dualspeed(gadget) ||
gadget->speed >= USB_SPEED_SUPER)
break;
value = config_desc(cdev, w_value);
if (value >= 0)
value = min(w_length, (u16) value);
+ pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR: "
+ "USB_DT_CONFIG, value=%d\n",value);
break;
case USB_DT_STRING:
value = get_string(cdev, req->buf,
w_index, w_value & 0xff);
- if (value >= 0)
+ if (value >= 0) {
value = min(w_length, (u16) value);
+ pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR: "
+ "USB_DT_STRING, value=%d\n" ,value);
+ }
break;
case USB_DT_BOS:
if (gadget_is_superspeed(gadget)) {
value = bos_desc(cdev);
value = min(w_length, (u16) value);
}
+ pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR: "
+ "USB_DT_BOS, value=%d\n",value);
+ break;
+ default:
+ pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_DESCRIPTOR w_value=0x%X\n", w_value);
break;
}
break;
spin_lock(&cdev->lock);
value = set_config(cdev, ctrl, w_value);
spin_unlock(&cdev->lock);
+ pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_SET_CONFIGURATION: "
+ "value=%d\n",value);
break;
case USB_REQ_GET_CONFIGURATION:
if (ctrl->bRequestType != USB_DIR_IN)
goto unknown;
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
break;
- f = cdev->config->interface[intf];
+
+ if (cdev->config)
+ f = cdev->config->interface[intf];
+ else
+ pr_debug("%s: cdev->config = NULL \n", __func__);
+
if (!f)
break;
* interface of the function
*/
case USB_REQ_GET_STATUS:
+ pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_GET_STATUS\n");
if (!gadget_is_superspeed(gadget))
goto unknown;
if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
*/
case USB_REQ_CLEAR_FEATURE:
case USB_REQ_SET_FEATURE:
+ pr_debug("[XLOG_DEBUG][USB][COM]%s w_value=%d\n",
+ ((ctrl->bRequest==USB_REQ_SET_FEATURE)? "USB_REQ_SET_FEATURE" : "USB_REQ_CLEAR_FEATURE"), w_value);
if (!gadget_is_superspeed(gadget))
goto unknown;
if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
goto unknown;
switch (w_value) {
case USB_INTRF_FUNC_SUSPEND:
+ pr_debug("[COM]USB_INTRF_FUNC_SUSPEND\n");
if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
break;
f = cdev->config->interface[intf];
break;
}
break;
+ case USB_REQ_SET_SEL:
+ pr_debug("[XLOG_DEBUG][USB][COM]USB_REQ_SET_SEL Pretend success\n");
+ value = 0;
+ break;
default:
unknown:
VDBG(cdev,
}
done:
+ if(value < 0) {
+ pr_debug("[XLOG_DEBUG][USB][COM]composite_setup: value=%d,"
+ "bRequestType=0x%x, bRequest=0x%x, w_value=0x%x, w_length=0x%x \n", value,
+ ctrl->bRequestType, ctrl->bRequest, w_value, w_length);
+ }
/* device either stalls (value < 0) or reports success */
return value;
}
reset_config(cdev);
if (cdev->driver->disconnect)
cdev->driver->disconnect(cdev);
+
+ /* ALPS00235316 and ALPS00234976 */
+ /* reset the complet function */
+ if(cdev->req->complete) {
+ pr_debug("[XLOG_DEBUG][USB][COM]%s: reassign the complete function!!\n", __func__);
+ cdev->req->complete = composite_setup_complete;
+ }
+
spin_unlock_irqrestore(&cdev->lock, flags);
}
struct usb_configuration *c;
c = list_first_entry(&cdev->configs,
struct usb_configuration, list);
- remove_config(cdev, c);
+ list_del(&c->list);
+ unbind_config(cdev, c);
}
if (cdev->driver->unbind && unbind_driver)
cdev->driver->unbind(cdev);
if (!driver || !driver->dev || !driver->bind)
return -EINVAL;
+ pr_debug("[XLOG_DEBUG][USB][COM]%s: driver->name = %s", __func__, driver->name);
+
if (!driver->name)
driver->name = "composite";