Revert "usb: gadget: Backport Android drivers from 2.6.35 for HD2 by tytung."
This reverts commit 70f8304d7a.
			
			
This commit is contained in:
		@@ -47,10 +47,6 @@ struct msm_hsusb_platform_data {
 | 
			
		||||
	/* 1 : uart, 0 : usb */
 | 
			
		||||
	void (*usb_uart_switch)(int);
 | 
			
		||||
	void (*config_usb_id_gpios)(bool enable);
 | 
			
		||||
	void (*usb_hub_enable)(bool);
 | 
			
		||||
	void (*serial_debug_gpios)(int);
 | 
			
		||||
	int (*china_ac_detect)(void);
 | 
			
		||||
	void (*disable_usb_charger)(void);
 | 
			
		||||
	/* val, reg pairs terminated by -1 */
 | 
			
		||||
	int *phy_init_seq;
 | 
			
		||||
 | 
			
		||||
@@ -80,11 +76,8 @@ struct msm_hsusb_platform_data {
 | 
			
		||||
#endif
 | 
			
		||||
	char *serial_number;
 | 
			
		||||
	int usb_id_pin_gpio;
 | 
			
		||||
	int dock_pin_gpio;
 | 
			
		||||
	int id_pin_irq;
 | 
			
		||||
	bool enable_car_kit_detect;
 | 
			
		||||
	__u8 accessory_detect;
 | 
			
		||||
	bool dock_detect;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int usb_get_connect_type(void);
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,59 @@ MODULE_VERSION("1.0");
 | 
			
		||||
 | 
			
		||||
static const char longname[] = "Gadget Android";
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	USB_FUNCTION_UMS = 0,
 | 
			
		||||
	USB_FUNCTION_ADB = 1,
 | 
			
		||||
	USB_FUNCTION_RNDIS,
 | 
			
		||||
	USB_FUNCTION_DIAG,
 | 
			
		||||
	USB_FUNCTION_SERIAL,
 | 
			
		||||
	USB_FUNCTION_PROJECTOR,
 | 
			
		||||
	USB_FUNCTION_FSYNC,
 | 
			
		||||
	USB_FUNCTION_MTP,
 | 
			
		||||
	USB_FUNCTION_MODEM,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_USB_ANDROID_MTP
 | 
			
		||||
#define MS_VENDOR_CODE	0x0b
 | 
			
		||||
#define FEATURE_DESC_SIZE	64
 | 
			
		||||
#define PID_MTP			0x0c93
 | 
			
		||||
#define PID_MTP_ADB		0x0ca8
 | 
			
		||||
struct ms_comp_feature_descriptor {
 | 
			
		||||
	__le32 dwLength;
 | 
			
		||||
	__le16 bcdVersion;
 | 
			
		||||
	__le16 wIndex;
 | 
			
		||||
	__u8 bCount;
 | 
			
		||||
	__u8 resv1[7];
 | 
			
		||||
	/* for MTP */
 | 
			
		||||
	__u8 bFirstInterfaceNumber;
 | 
			
		||||
	__u8 resv2;
 | 
			
		||||
	__u8 compatibleID[8];
 | 
			
		||||
	__u8 subCompatibleID[8];
 | 
			
		||||
	__u8 resv3[6];
 | 
			
		||||
	/* for adb */
 | 
			
		||||
	__u8 bFirstInterfaceNumber2;
 | 
			
		||||
	__u8 resv4;
 | 
			
		||||
	__u8 compatibleID2[8];
 | 
			
		||||
	__u8 subCompatibleID2[8];
 | 
			
		||||
	__u8 resv5[6];
 | 
			
		||||
} __attribute__ ((packed));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static struct ms_comp_feature_descriptor ms_comp_desc = {
 | 
			
		||||
	.dwLength = __constant_cpu_to_le32(FEATURE_DESC_SIZE),
 | 
			
		||||
	.bcdVersion = __constant_cpu_to_le16(0x0100),
 | 
			
		||||
	.wIndex = __constant_cpu_to_le16(0x0004),
 | 
			
		||||
	.bCount = 0x02,
 | 
			
		||||
	/* for MTP */
 | 
			
		||||
	.bFirstInterfaceNumber = 0,
 | 
			
		||||
	.resv2 = 1,
 | 
			
		||||
	.compatibleID = "MTP",
 | 
			
		||||
	/* for adb */
 | 
			
		||||
	.bFirstInterfaceNumber2 = 1,
 | 
			
		||||
	.resv4 = 1,
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Default vendor and product IDs, overridden by platform data */
 | 
			
		||||
#define VENDOR_ID		0x18D1
 | 
			
		||||
#define PRODUCT_ID		0x0001
 | 
			
		||||
@@ -109,6 +162,17 @@ static struct usb_device_descriptor device_desc = {
 | 
			
		||||
 | 
			
		||||
static struct list_head _functions = LIST_HEAD_INIT(_functions);
 | 
			
		||||
static int _registered_function_count = 0;
 | 
			
		||||
static int get_product_id(struct android_dev *dev);
 | 
			
		||||
 | 
			
		||||
void android_usb_set_connected(int connected)
 | 
			
		||||
{
 | 
			
		||||
	if (_android_dev && _android_dev->cdev && _android_dev->cdev->gadget) {
 | 
			
		||||
		if (connected)
 | 
			
		||||
			usb_gadget_connect(_android_dev->cdev->gadget);
 | 
			
		||||
		else
 | 
			
		||||
			usb_gadget_disconnect(_android_dev->cdev->gadget);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct android_usb_function *get_function(const char *name)
 | 
			
		||||
{
 | 
			
		||||
@@ -124,6 +188,7 @@ static void bind_functions(struct android_dev *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct android_usb_function	*f;
 | 
			
		||||
	char **functions = dev->functions;
 | 
			
		||||
	int	product_id;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < dev->num_functions; i++) {
 | 
			
		||||
@@ -134,9 +199,14 @@ static void bind_functions(struct android_dev *dev)
 | 
			
		||||
		else
 | 
			
		||||
			printk(KERN_ERR "function %s not found in bind_functions\n", name);
 | 
			
		||||
	}
 | 
			
		||||
	product_id = get_product_id(dev);
 | 
			
		||||
	printk(KERN_INFO "usb: product_id=0x%x\n", product_id);
 | 
			
		||||
	device_desc.idProduct = __constant_cpu_to_le16(product_id);
 | 
			
		||||
	if (dev->cdev)
 | 
			
		||||
		dev->cdev->desc.idProduct = device_desc.idProduct;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int android_bind_config(struct usb_configuration *c)
 | 
			
		||||
static int __init android_bind_config(struct usb_configuration *c)
 | 
			
		||||
{
 | 
			
		||||
	struct android_dev *dev = _android_dev;
 | 
			
		||||
 | 
			
		||||
@@ -167,7 +237,46 @@ static int android_setup_config(struct usb_configuration *c,
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int ret = -EOPNOTSUPP;
 | 
			
		||||
#ifdef CONFIG_USB_ANDROID_MTP
 | 
			
		||||
	struct usb_composite_dev *cdev = c->cdev;
 | 
			
		||||
	struct usb_request	*req = cdev->req;
 | 
			
		||||
	struct android_dev *dev = _android_dev;
 | 
			
		||||
	int product_id;
 | 
			
		||||
	u16 w_index = le16_to_cpu(ctrl->wIndex);
 | 
			
		||||
	u16 w_length = le16_to_cpu(ctrl->wLength);
 | 
			
		||||
	/* vendor request to GET OS feature descriptor */
 | 
			
		||||
	if (((ctrl->bRequestType << 8) | ctrl->bRequest) ==
 | 
			
		||||
		(((USB_DIR_IN | USB_TYPE_VENDOR) << 8) | MS_VENDOR_CODE)) {
 | 
			
		||||
 | 
			
		||||
		printk(KERN_DEBUG "usb: get OS feature descriptor\n");
 | 
			
		||||
		if (w_index != 0x0004 || w_length > FEATURE_DESC_SIZE)
 | 
			
		||||
			return ret;
 | 
			
		||||
 | 
			
		||||
		product_id = get_product_id(dev);
 | 
			
		||||
		printk(KERN_INFO "mtp: product_id = 0x%x\n", product_id);
 | 
			
		||||
		if (product_id == PID_MTP) {
 | 
			
		||||
			ms_comp_desc.bCount = 1;
 | 
			
		||||
			ms_comp_desc.dwLength =
 | 
			
		||||
				__constant_cpu_to_le32(40);
 | 
			
		||||
			ret = w_length;
 | 
			
		||||
		} else if (product_id == PID_MTP_ADB) {
 | 
			
		||||
			ms_comp_desc.bCount = 2;
 | 
			
		||||
			ms_comp_desc.dwLength =
 | 
			
		||||
				__constant_cpu_to_le32(64);
 | 
			
		||||
			ret = w_length;
 | 
			
		||||
		}
 | 
			
		||||
		/* respond with data transfer or status phase? */
 | 
			
		||||
		if (ret >= 0) {
 | 
			
		||||
			memcpy(req->buf, (char *)&ms_comp_desc, w_length);
 | 
			
		||||
			req->zero = 0;
 | 
			
		||||
			req->length = ret;
 | 
			
		||||
			ret = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
 | 
			
		||||
			if (ret < 0)
 | 
			
		||||
				ERROR(cdev, "get feature desc err %d\n", ret);
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	for (i = 0; i < android_config_driver.next_interface_id; i++) {
 | 
			
		||||
		if (android_config_driver.interface[i]->setup) {
 | 
			
		||||
			ret = android_config_driver.interface[i]->setup(
 | 
			
		||||
@@ -198,7 +307,7 @@ static int product_matches_functions(struct android_usb_product *p)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_function		*f;
 | 
			
		||||
	list_for_each_entry(f, &android_config_driver.functions, list) {
 | 
			
		||||
		if (product_has_function(p, f) == !!f->disabled)
 | 
			
		||||
		if (product_has_function(p, f) == !!f->hidden)
 | 
			
		||||
			return 0;
 | 
			
		||||
	}
 | 
			
		||||
	return 1;
 | 
			
		||||
@@ -220,7 +329,7 @@ static int get_product_id(struct android_dev *dev)
 | 
			
		||||
	return dev->product_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int android_bind(struct usb_composite_dev *cdev)
 | 
			
		||||
static int __init android_bind(struct usb_composite_dev *cdev)
 | 
			
		||||
{
 | 
			
		||||
	struct android_dev *dev = _android_dev;
 | 
			
		||||
	struct usb_gadget	*gadget = cdev->gadget;
 | 
			
		||||
@@ -249,6 +358,9 @@ static int android_bind(struct usb_composite_dev *cdev)
 | 
			
		||||
	strings_dev[STRING_SERIAL_IDX].id = id;
 | 
			
		||||
	device_desc.iSerialNumber = id;
 | 
			
		||||
 | 
			
		||||
	if (gadget->ops->wakeup)
 | 
			
		||||
		android_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 | 
			
		||||
 | 
			
		||||
	/* register our configuration */
 | 
			
		||||
	ret = usb_add_config(cdev, &android_config_driver);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
@@ -300,9 +412,84 @@ void android_register_function(struct android_usb_function *f)
 | 
			
		||||
	/* bind our functions if they have all registered
 | 
			
		||||
	 * and the main driver has bound.
 | 
			
		||||
	 */
 | 
			
		||||
	if (dev && dev->config && _registered_function_count == dev->num_functions)
 | 
			
		||||
	if (dev->config && _registered_function_count == dev->num_functions)
 | 
			
		||||
		bind_functions(dev);
 | 
			
		||||
}
 | 
			
		||||
int android_show_function(char *buf)
 | 
			
		||||
{
 | 
			
		||||
	unsigned length = 0;
 | 
			
		||||
	struct usb_function		*f;
 | 
			
		||||
	list_for_each_entry(f, &android_config_driver.functions, list) {
 | 
			
		||||
		length += sprintf(buf + length, "%s:%s\n", f->name,
 | 
			
		||||
			(f->hidden)?"disable":"enable");
 | 
			
		||||
	}
 | 
			
		||||
	return length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int android_switch_function(unsigned func)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_function		*f;
 | 
			
		||||
	struct android_dev *dev = _android_dev;
 | 
			
		||||
	int product_id;
 | 
			
		||||
	printk(KERN_INFO "%s: %u\n", __func__, func);
 | 
			
		||||
	list_for_each_entry(f, &android_config_driver.functions, list) {
 | 
			
		||||
		if ((func & (1 << USB_FUNCTION_UMS)) &&
 | 
			
		||||
			!strcmp(f->name, "usb_mass_storage"))
 | 
			
		||||
			f->hidden = 0;
 | 
			
		||||
		else if ((func & (1 << USB_FUNCTION_ADB)) &&
 | 
			
		||||
			!strcmp(f->name, "adb"))
 | 
			
		||||
			f->hidden = 0;
 | 
			
		||||
		else if ((func & (1 << USB_FUNCTION_RNDIS)) &&
 | 
			
		||||
			!strcmp(f->name, "rndis"))
 | 
			
		||||
			f->hidden = 0;
 | 
			
		||||
		else if ((func & (1 << USB_FUNCTION_DIAG)) &&
 | 
			
		||||
			!strcmp(f->name, "diag"))
 | 
			
		||||
			f->hidden = 0;
 | 
			
		||||
		else if ((func & (1 << USB_FUNCTION_MODEM)) &&
 | 
			
		||||
			!strcmp(f->name, "modem"))
 | 
			
		||||
			f->hidden = 0;
 | 
			
		||||
		else if ((func & (1 << USB_FUNCTION_SERIAL)) &&
 | 
			
		||||
			!strcmp(f->name, "serial"))
 | 
			
		||||
			f->hidden = 0;
 | 
			
		||||
		else if ((func & (1 << USB_FUNCTION_MTP)) &&
 | 
			
		||||
			!strcmp(f->name, "mtp"))
 | 
			
		||||
			f->hidden = 0;
 | 
			
		||||
		/* also enable adb with MTP function */
 | 
			
		||||
		else if ((func & (1 << USB_FUNCTION_MTP)) &&
 | 
			
		||||
			!strcmp(f->name, "adb"))
 | 
			
		||||
			f->hidden = 0;
 | 
			
		||||
		else if ((func & (1 << USB_FUNCTION_PROJECTOR)) &&
 | 
			
		||||
			!strcmp(f->name, "projector"))
 | 
			
		||||
			f->hidden = 0;
 | 
			
		||||
		else
 | 
			
		||||
			f->hidden = 1;
 | 
			
		||||
	}
 | 
			
		||||
	product_id = get_product_id(dev);
 | 
			
		||||
	device_desc.idProduct = __constant_cpu_to_le16(product_id);
 | 
			
		||||
	if (dev->cdev)
 | 
			
		||||
		dev->cdev->desc.idProduct = device_desc.idProduct;
 | 
			
		||||
 | 
			
		||||
	/* We need to specify the COMM class in the device descriptor
 | 
			
		||||
	* if we are using RNDIS.
 | 
			
		||||
	*/
 | 
			
		||||
	if (func & (1 << USB_FUNCTION_RNDIS))
 | 
			
		||||
		dev->cdev->desc.bDeviceClass = USB_CLASS_COMM;
 | 
			
		||||
	else
 | 
			
		||||
		dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_USB_GADGET_MSM_72K
 | 
			
		||||
	msm_hsusb_request_reset();
 | 
			
		||||
#else
 | 
			
		||||
	/* force reenumeration */
 | 
			
		||||
	if (dev->cdev && dev->cdev->gadget &&
 | 
			
		||||
			dev->cdev->gadget->speed != USB_SPEED_UNKNOWN) {
 | 
			
		||||
		usb_gadget_disconnect(dev->cdev->gadget);
 | 
			
		||||
		msleep(10);
 | 
			
		||||
		usb_gadget_connect(dev->cdev->gadget);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void android_enable_function(struct usb_function *f, int enable)
 | 
			
		||||
{
 | 
			
		||||
@@ -310,12 +497,12 @@ void android_enable_function(struct usb_function *f, int enable)
 | 
			
		||||
	int disable = !enable;
 | 
			
		||||
	int product_id;
 | 
			
		||||
 | 
			
		||||
	if (!!f->disabled != disable) {
 | 
			
		||||
		usb_function_set_enabled(f, !disable);
 | 
			
		||||
	if (!!f->hidden != disable) {
 | 
			
		||||
		f->hidden = disable;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_USB_ANDROID_RNDIS
 | 
			
		||||
		if (!strcmp(f->name, "rndis")) {
 | 
			
		||||
			struct usb_function    *func;
 | 
			
		||||
	struct usb_function		*func;
 | 
			
		||||
 | 
			
		||||
			/* We need to specify the COMM class in the device descriptor
 | 
			
		||||
			 * if we are using RNDIS.
 | 
			
		||||
@@ -330,12 +517,12 @@ void android_enable_function(struct usb_function *f, int enable)
 | 
			
		||||
				dev->cdev->desc.bDeviceClass = USB_CLASS_PER_INTERFACE;
 | 
			
		||||
 | 
			
		||||
			/* Windows does not support other interfaces when RNDIS is enabled,
 | 
			
		||||
			 * so we disable UMS and MTP when RNDIS is on.
 | 
			
		||||
			 * so we disable UMS when RNDIS is on.
 | 
			
		||||
			 */
 | 
			
		||||
			list_for_each_entry(func, &android_config_driver.functions, list) {
 | 
			
		||||
				if (!strcmp(func->name, "usb_mass_storage")
 | 
			
		||||
				  || !strcmp(func->name, "mtp")) {
 | 
			
		||||
					usb_function_set_enabled(func, !enable);
 | 
			
		||||
				if (!strcmp(func->name, "usb_mass_storage")) {
 | 
			
		||||
					func->hidden = enable;
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
@@ -345,10 +532,20 @@ void android_enable_function(struct usb_function *f, int enable)
 | 
			
		||||
		device_desc.idProduct = __constant_cpu_to_le16(product_id);
 | 
			
		||||
		if (dev->cdev)
 | 
			
		||||
			dev->cdev->desc.idProduct = device_desc.idProduct;
 | 
			
		||||
		usb_composite_force_reset(dev->cdev);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_USB_GADGET_MSM_72K
 | 
			
		||||
	msm_hsusb_request_reset();
 | 
			
		||||
#else
 | 
			
		||||
		/* force reenumeration */
 | 
			
		||||
		if (dev->cdev && dev->cdev->gadget &&
 | 
			
		||||
				dev->cdev->gadget->speed != USB_SPEED_UNKNOWN) {
 | 
			
		||||
			usb_gadget_disconnect(dev->cdev->gadget);
 | 
			
		||||
			msleep(10);
 | 
			
		||||
			usb_gadget_connect(dev->cdev->gadget);
 | 
			
		||||
		}
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void android_set_serialno(char *serialno)
 | 
			
		||||
{
 | 
			
		||||
	strings_dev[STRING_SERIAL_IDX].s = serialno;
 | 
			
		||||
@@ -360,7 +557,8 @@ int android_get_model_id(void)
 | 
			
		||||
	return dev->product_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int android_probe(struct platform_device *pdev)
 | 
			
		||||
 | 
			
		||||
static int __init android_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct android_usb_platform_data *pdata = pdev->dev.platform_data;
 | 
			
		||||
	struct android_dev *dev = _android_dev;
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* big enough to hold our biggest descriptor */
 | 
			
		||||
#define USB_BUFSIZ	1024
 | 
			
		||||
#define USB_BUFSIZ	512
 | 
			
		||||
 | 
			
		||||
static struct usb_composite_driver *composite;
 | 
			
		||||
 | 
			
		||||
@@ -75,7 +75,7 @@ static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
 | 
			
		||||
		char *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_function *f = dev_get_drvdata(dev);
 | 
			
		||||
	return sprintf(buf, "%d\n", !f->disabled);
 | 
			
		||||
	return sprintf(buf, "%d\n", !f->hidden);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t enable_store(
 | 
			
		||||
@@ -90,36 +90,13 @@ static ssize_t enable_store(
 | 
			
		||||
	if (driver->enable_function)
 | 
			
		||||
		driver->enable_function(f, value);
 | 
			
		||||
	else
 | 
			
		||||
		usb_function_set_enabled(f, value);
 | 
			
		||||
		f->hidden = !value;
 | 
			
		||||
 | 
			
		||||
	return size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
 | 
			
		||||
 | 
			
		||||
void usb_function_set_enabled(struct usb_function *f, int enabled)
 | 
			
		||||
{
 | 
			
		||||
	f->disabled = !enabled;
 | 
			
		||||
	kobject_uevent(&f->dev->kobj, KOBJ_CHANGE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void usb_composite_force_reset(struct usb_composite_dev *cdev)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long			flags;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&cdev->lock, flags);
 | 
			
		||||
	/* force reenumeration */
 | 
			
		||||
	if (cdev && cdev->gadget && cdev->gadget->speed != USB_SPEED_UNKNOWN) {
 | 
			
		||||
		spin_unlock_irqrestore(&cdev->lock, flags);
 | 
			
		||||
 | 
			
		||||
		usb_gadget_disconnect(cdev->gadget);
 | 
			
		||||
		msleep(10);
 | 
			
		||||
		usb_gadget_connect(cdev->gadget);
 | 
			
		||||
	} else {
 | 
			
		||||
		spin_unlock_irqrestore(&cdev->lock, flags);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * usb_add_function() - add a function to a configuration
 | 
			
		||||
@@ -135,7 +112,7 @@ void usb_composite_force_reset(struct usb_composite_dev *cdev)
 | 
			
		||||
 * This function returns the value of the function's bind(), which is
 | 
			
		||||
 * zero for success else a negative errno value.
 | 
			
		||||
 */
 | 
			
		||||
int usb_add_function(struct usb_configuration *config,
 | 
			
		||||
int __init usb_add_function(struct usb_configuration *config,
 | 
			
		||||
		struct usb_function *function)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_composite_dev	*cdev = config->cdev;
 | 
			
		||||
@@ -280,7 +257,7 @@ int usb_function_activate(struct usb_function *function)
 | 
			
		||||
 * Returns the interface ID which was allocated; or -ENODEV if no
 | 
			
		||||
 * more interface IDs can be allocated.
 | 
			
		||||
 */
 | 
			
		||||
int usb_interface_id(struct usb_configuration *config,
 | 
			
		||||
int __init usb_interface_id(struct usb_configuration *config,
 | 
			
		||||
		struct usb_function *function)
 | 
			
		||||
{
 | 
			
		||||
	unsigned id = config->next_interface_id;
 | 
			
		||||
@@ -293,6 +270,34 @@ int usb_interface_id(struct usb_configuration *config,
 | 
			
		||||
	return -ENODEV;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct usb_function *get_function_by_intf(struct usb_composite_dev *cdev,
 | 
			
		||||
		int intf)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_configuration *config = cdev->config;
 | 
			
		||||
	enum usb_device_speed	speed = cdev->gadget->speed;
 | 
			
		||||
	struct usb_function *f;
 | 
			
		||||
	struct usb_descriptor_header *descriptor;
 | 
			
		||||
	struct usb_interface_descriptor *intf_desc;
 | 
			
		||||
	int i;
 | 
			
		||||
	for (i = 0; i < MAX_CONFIG_INTERFACES; i++) {
 | 
			
		||||
		f = config->interface[i];
 | 
			
		||||
		if (!f)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		if (f->hidden)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (speed == USB_SPEED_HIGH)
 | 
			
		||||
			descriptor = *(f->hs_descriptors);
 | 
			
		||||
		else
 | 
			
		||||
			descriptor = *(f->descriptors);
 | 
			
		||||
		intf_desc = (struct usb_interface_descriptor *)descriptor;
 | 
			
		||||
		if (intf_desc->bDescriptorType == USB_DT_INTERFACE &&
 | 
			
		||||
			intf_desc->bInterfaceNumber == intf)
 | 
			
		||||
			return f;
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int config_buf(struct usb_configuration *config,
 | 
			
		||||
		enum usb_device_speed speed, void *buf, u8 type)
 | 
			
		||||
{
 | 
			
		||||
@@ -334,7 +339,7 @@ static int config_buf(struct usb_configuration *config,
 | 
			
		||||
			descriptors = f->hs_descriptors;
 | 
			
		||||
		else
 | 
			
		||||
			descriptors = f->descriptors;
 | 
			
		||||
		if (f->disabled  || !descriptors || descriptors[0] == NULL)
 | 
			
		||||
		if (f->hidden || !descriptors || descriptors[0] == NULL)
 | 
			
		||||
			continue;
 | 
			
		||||
		status = usb_descriptor_fillbuf(next, len,
 | 
			
		||||
			(const struct usb_descriptor_header **) descriptors);
 | 
			
		||||
@@ -346,11 +351,9 @@ static int config_buf(struct usb_configuration *config,
 | 
			
		||||
		while ((descriptor = *descriptors++) != NULL) {
 | 
			
		||||
			intf = (struct usb_interface_descriptor *)dest;
 | 
			
		||||
			if (intf->bDescriptorType == USB_DT_INTERFACE) {
 | 
			
		||||
				/* don't increment bInterfaceNumber for alternate settings */
 | 
			
		||||
				if (intf->bAlternateSetting == 0)
 | 
			
		||||
					intf->bInterfaceNumber = interfaceCount++;
 | 
			
		||||
				else
 | 
			
		||||
					intf->bInterfaceNumber = interfaceCount - 1;
 | 
			
		||||
				intf->bInterfaceNumber = interfaceCount;
 | 
			
		||||
				intf = (struct usb_interface_descriptor *)descriptor;
 | 
			
		||||
				intf->bInterfaceNumber = interfaceCount++;
 | 
			
		||||
			}
 | 
			
		||||
			dest += intf->bLength;
 | 
			
		||||
		}
 | 
			
		||||
@@ -457,8 +460,6 @@ static void reset_config(struct usb_composite_dev *cdev)
 | 
			
		||||
	list_for_each_entry(f, &cdev->config->functions, list) {
 | 
			
		||||
		if (f->disable)
 | 
			
		||||
			f->disable(f);
 | 
			
		||||
 | 
			
		||||
		bitmap_zero(f->endpoints, 32);
 | 
			
		||||
	}
 | 
			
		||||
	cdev->config = NULL;
 | 
			
		||||
}
 | 
			
		||||
@@ -504,36 +505,9 @@ static int set_config(struct usb_composite_dev *cdev,
 | 
			
		||||
	/* Initialize all interfaces by setting them to altsetting zero. */
 | 
			
		||||
	for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
 | 
			
		||||
		struct usb_function	*f = c->interface[tmp];
 | 
			
		||||
		struct usb_descriptor_header **descriptors;
 | 
			
		||||
 | 
			
		||||
		if (!f)
 | 
			
		||||
			break;
 | 
			
		||||
		if (f->disabled)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Record which endpoints are used by the function. This is used
 | 
			
		||||
		 * to dispatch control requests targeted at that endpoint to the
 | 
			
		||||
		 * function's setup callback instead of the current
 | 
			
		||||
		 * configuration's setup callback.
 | 
			
		||||
		 */
 | 
			
		||||
		if (gadget->speed == USB_SPEED_HIGH)
 | 
			
		||||
			descriptors = f->hs_descriptors;
 | 
			
		||||
		else
 | 
			
		||||
			descriptors = f->descriptors;
 | 
			
		||||
 | 
			
		||||
		for (; *descriptors; ++descriptors) {
 | 
			
		||||
			struct usb_endpoint_descriptor *ep;
 | 
			
		||||
			int addr;
 | 
			
		||||
 | 
			
		||||
			if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT)
 | 
			
		||||
				continue;
 | 
			
		||||
 | 
			
		||||
			ep = (struct usb_endpoint_descriptor *)*descriptors;
 | 
			
		||||
			addr = ((ep->bEndpointAddress & 0x80) >> 3)
 | 
			
		||||
			     |  (ep->bEndpointAddress & 0x0f);
 | 
			
		||||
			set_bit(addr, f->endpoints);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		result = f->set_alt(f, tmp, 0);
 | 
			
		||||
		if (result < 0) {
 | 
			
		||||
@@ -549,8 +523,6 @@ static int set_config(struct usb_composite_dev *cdev,
 | 
			
		||||
	power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;
 | 
			
		||||
done:
 | 
			
		||||
	usb_gadget_vbus_draw(gadget, power);
 | 
			
		||||
 | 
			
		||||
	schedule_work(&cdev->switch_work);
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -568,7 +540,7 @@ done:
 | 
			
		||||
 * assigns global resources including string IDs, and per-configuration
 | 
			
		||||
 * resources such as interface IDs and endpoints.
 | 
			
		||||
 */
 | 
			
		||||
int usb_add_config(struct usb_composite_dev *cdev,
 | 
			
		||||
int __init usb_add_config(struct usb_composite_dev *cdev,
 | 
			
		||||
		struct usb_configuration *config)
 | 
			
		||||
{
 | 
			
		||||
	int				status = -EINVAL;
 | 
			
		||||
@@ -765,7 +737,7 @@ static int get_string(struct usb_composite_dev *cdev,
 | 
			
		||||
 * ensure that for example different functions don't wrongly assign
 | 
			
		||||
 * different meanings to the same identifier.
 | 
			
		||||
 */
 | 
			
		||||
int usb_string_id(struct usb_composite_dev *cdev)
 | 
			
		||||
int __init usb_string_id(struct usb_composite_dev *cdev)
 | 
			
		||||
{
 | 
			
		||||
	if (cdev->next_string_id < 254) {
 | 
			
		||||
		/* string id 0 is reserved */
 | 
			
		||||
@@ -784,7 +756,6 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
 | 
			
		||||
				"setup complete --> %d, %d/%d\n",
 | 
			
		||||
				req->status, req->actual, req->length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The setup() callback implements all the ep0 functionality that's
 | 
			
		||||
 * not handled lower down, in hardware or the hardware driver(like
 | 
			
		||||
@@ -803,15 +774,6 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 | 
			
		||||
	u16				w_value = le16_to_cpu(ctrl->wValue);
 | 
			
		||||
	u16				w_length = le16_to_cpu(ctrl->wLength);
 | 
			
		||||
	struct usb_function		*f = NULL;
 | 
			
		||||
	u8        endp;
 | 
			
		||||
	unsigned long      flags;
 | 
			
		||||
 | 
			
		||||
  spin_lock_irqsave(&cdev->lock, flags);
 | 
			
		||||
  if (!cdev->connected) {
 | 
			
		||||
    cdev->connected = 1;
 | 
			
		||||
    schedule_work(&cdev->switch_work);
 | 
			
		||||
  }
 | 
			
		||||
  spin_unlock_irqrestore(&cdev->lock, flags);
 | 
			
		||||
 | 
			
		||||
	/* partial re-init of the response message; the function or the
 | 
			
		||||
	 * gadget might need to intercept e.g. a control-OUT completion
 | 
			
		||||
@@ -855,21 +817,6 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 | 
			
		||||
		case USB_DT_STRING:
 | 
			
		||||
			value = get_string(cdev, req->buf,
 | 
			
		||||
					w_index, w_value & 0xff);
 | 
			
		||||
 | 
			
		||||
			/* Allow functions to handle USB_DT_STRING.
 | 
			
		||||
			 * This is required for MTP.
 | 
			
		||||
			 */
 | 
			
		||||
			if (value < 0) {
 | 
			
		||||
				struct usb_configuration        *cfg;
 | 
			
		||||
				list_for_each_entry(cfg, &cdev->configs, list) {
 | 
			
		||||
					if (cfg && cfg->setup) {
 | 
			
		||||
						value = cfg->setup(cfg, ctrl);
 | 
			
		||||
						if (value >= 0)
 | 
			
		||||
							break;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (value >= 0)
 | 
			
		||||
				value = min(w_length, (u16) value);
 | 
			
		||||
			break;
 | 
			
		||||
@@ -910,7 +857,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 | 
			
		||||
			goto unknown;
 | 
			
		||||
		if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
 | 
			
		||||
			break;
 | 
			
		||||
		f = cdev->config->interface[intf];
 | 
			
		||||
		f = get_function_by_intf(cdev, intf);
 | 
			
		||||
		if (!f)
 | 
			
		||||
			break;
 | 
			
		||||
		if (w_value && !f->set_alt)
 | 
			
		||||
@@ -922,7 +869,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 | 
			
		||||
			goto unknown;
 | 
			
		||||
		if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES)
 | 
			
		||||
			break;
 | 
			
		||||
		f = cdev->config->interface[intf];
 | 
			
		||||
		f = get_function_by_intf(cdev, intf);
 | 
			
		||||
		if (!f)
 | 
			
		||||
			break;
 | 
			
		||||
		/* lots of interfaces only need altsetting zero... */
 | 
			
		||||
@@ -939,36 +886,26 @@ unknown:
 | 
			
		||||
			ctrl->bRequestType, ctrl->bRequest,
 | 
			
		||||
			w_value, w_index, w_length);
 | 
			
		||||
 | 
			
		||||
		/* functions always handle their interfaces and endpoints...
 | 
			
		||||
		 * punt other recipients (other, WUSB, ...) to the current
 | 
			
		||||
		/* functions always handle their interfaces ... punt other
 | 
			
		||||
		 * recipients (endpoint, other, WUSB, ...) to the current
 | 
			
		||||
		 * configuration code.
 | 
			
		||||
		 *
 | 
			
		||||
		 * REVISIT it could make sense to let the composite device
 | 
			
		||||
		 * take such requests too, if that's ever needed:  to work
 | 
			
		||||
		 * in config 0, etc.
 | 
			
		||||
		 */
 | 
			
		||||
		switch (ctrl->bRequestType & USB_RECIP_MASK) {
 | 
			
		||||
		case USB_RECIP_INTERFACE:
 | 
			
		||||
		if ((ctrl->bRequestType & USB_RECIP_MASK)
 | 
			
		||||
				== USB_RECIP_INTERFACE) {
 | 
			
		||||
			if (cdev->config == NULL)
 | 
			
		||||
				return value;
 | 
			
		||||
 | 
			
		||||
			f = cdev->config->interface[intf];
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case USB_RECIP_ENDPOINT:
 | 
			
		||||
			endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f);
 | 
			
		||||
			list_for_each_entry(f, &cdev->config->functions, list) {
 | 
			
		||||
				if (test_bit(endp, f->endpoints))
 | 
			
		||||
					break;
 | 
			
		||||
			}
 | 
			
		||||
			if (&f->list == &cdev->config->functions)
 | 
			
		||||
			f = get_function_by_intf(cdev, intf);
 | 
			
		||||
			if (f && f->setup)
 | 
			
		||||
				value = f->setup(f, ctrl);
 | 
			
		||||
			else
 | 
			
		||||
				f = NULL;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (f && f->setup)
 | 
			
		||||
			value = f->setup(f, ctrl);
 | 
			
		||||
		else {
 | 
			
		||||
		if (value < 0 && !f) {
 | 
			
		||||
			struct usb_configuration	*c;
 | 
			
		||||
 | 
			
		||||
			c = cdev->config;
 | 
			
		||||
@@ -1026,27 +963,13 @@ static void composite_disconnect(struct usb_gadget *gadget)
 | 
			
		||||
	spin_lock_irqsave(&cdev->lock, flags);
 | 
			
		||||
	if (cdev->config)
 | 
			
		||||
		reset_config(cdev);
 | 
			
		||||
 | 
			
		||||
  cdev->connected = 0;
 | 
			
		||||
  schedule_work(&cdev->switch_work);
 | 
			
		||||
	spin_unlock_irqrestore(&cdev->lock, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
static ssize_t composite_show_suspended(struct device *dev,
 | 
			
		||||
					struct device_attribute *attr,
 | 
			
		||||
					char *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_gadget *gadget = dev_to_usb_gadget(dev);
 | 
			
		||||
	struct usb_composite_dev *cdev = get_gadget_data(gadget);
 | 
			
		||||
 | 
			
		||||
	return sprintf(buf, "%d\n", cdev->suspended);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DEVICE_ATTR(suspended, 0444, composite_show_suspended, NULL);
 | 
			
		||||
 | 
			
		||||
static void composite_unbind(struct usb_gadget *gadget)
 | 
			
		||||
static void /* __init_or_exit */
 | 
			
		||||
composite_unbind(struct usb_gadget *gadget)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
 | 
			
		||||
 | 
			
		||||
@@ -1089,16 +1012,13 @@ static void composite_unbind(struct usb_gadget *gadget)
 | 
			
		||||
		kfree(cdev->req->buf);
 | 
			
		||||
		usb_ep_free_request(gadget->ep0, cdev->req);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	switch_dev_unregister(&cdev->sw_connected);
 | 
			
		||||
	switch_dev_unregister(&cdev->sw_config);
 | 
			
		||||
	kfree(cdev);
 | 
			
		||||
	set_gadget_data(gadget, NULL);
 | 
			
		||||
  device_remove_file(&gadget->dev, &dev_attr_suspended);
 | 
			
		||||
	composite = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s)
 | 
			
		||||
static void __init
 | 
			
		||||
string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_string		*str = tab->strings;
 | 
			
		||||
 | 
			
		||||
@@ -1110,7 +1030,8 @@ static void string_override_one(struct usb_gadget_strings *tab, u8 id, const cha
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void string_override(struct usb_gadget_strings **tab, u8 id, const char *s)
 | 
			
		||||
static void __init
 | 
			
		||||
string_override(struct usb_gadget_strings **tab, u8 id, const char *s)
 | 
			
		||||
{
 | 
			
		||||
	while (*tab) {
 | 
			
		||||
		string_override_one(*tab, id, s);
 | 
			
		||||
@@ -1118,30 +1039,7 @@ static void string_override(struct usb_gadget_strings **tab, u8 id, const char *
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void composite_switch_work(struct work_struct *data)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_composite_dev	*cdev =
 | 
			
		||||
		container_of(data, struct usb_composite_dev, switch_work);
 | 
			
		||||
	struct usb_configuration *config = cdev->config;
 | 
			
		||||
  int connected;
 | 
			
		||||
  unsigned long flags;
 | 
			
		||||
 | 
			
		||||
  spin_lock_irqsave(&cdev->lock, flags);
 | 
			
		||||
  if (cdev->connected != cdev->sw_connected.state) {
 | 
			
		||||
    connected = cdev->connected;
 | 
			
		||||
    spin_unlock_irqrestore(&cdev->lock, flags);
 | 
			
		||||
    switch_set_state(&cdev->sw_connected, connected);
 | 
			
		||||
  } else {
 | 
			
		||||
    spin_unlock_irqrestore(&cdev->lock, flags);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
	if (config)
 | 
			
		||||
		switch_set_state(&cdev->sw_config, config->bConfigurationValue);
 | 
			
		||||
	else
 | 
			
		||||
		switch_set_state(&cdev->sw_config, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int composite_bind(struct usb_gadget *gadget)
 | 
			
		||||
static int __init composite_bind(struct usb_gadget *gadget)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_composite_dev	*cdev;
 | 
			
		||||
	int				status = -ENOMEM;
 | 
			
		||||
@@ -1176,14 +1074,6 @@ static int composite_bind(struct usb_gadget *gadget)
 | 
			
		||||
	 */
 | 
			
		||||
	usb_ep_autoconfig_reset(cdev->gadget);
 | 
			
		||||
 | 
			
		||||
	/* standardized runtime overrides for device ID data */
 | 
			
		||||
	if (idVendor)
 | 
			
		||||
		cdev->desc.idVendor = cpu_to_le16(idVendor);
 | 
			
		||||
	if (idProduct)
 | 
			
		||||
		cdev->desc.idProduct = cpu_to_le16(idProduct);
 | 
			
		||||
	if (bcdDevice)
 | 
			
		||||
		cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
 | 
			
		||||
 | 
			
		||||
	/* composite gadget needs to assign strings for whole device (like
 | 
			
		||||
	 * serial number), register function drivers, potentially update
 | 
			
		||||
	 * power state and consumption, etc
 | 
			
		||||
@@ -1192,19 +1082,17 @@ static int composite_bind(struct usb_gadget *gadget)
 | 
			
		||||
	if (status < 0)
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
	cdev->sw_connected.name = "usb_connected";
 | 
			
		||||
	status = switch_dev_register(&cdev->sw_connected);
 | 
			
		||||
	if (status < 0)
 | 
			
		||||
    goto fail;
 | 
			
		||||
  cdev->sw_config.name = "usb_configuration";
 | 
			
		||||
  status = switch_dev_register(&cdev->sw_config);
 | 
			
		||||
	if (status < 0)
 | 
			
		||||
		goto fail;
 | 
			
		||||
	INIT_WORK(&cdev->switch_work, composite_switch_work);
 | 
			
		||||
 | 
			
		||||
	cdev->desc = *composite->dev;
 | 
			
		||||
	cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 | 
			
		||||
 | 
			
		||||
	/* standardized runtime overrides for device ID data */
 | 
			
		||||
	if (idVendor)
 | 
			
		||||
		cdev->desc.idVendor = cpu_to_le16(idVendor);
 | 
			
		||||
	if (idProduct)
 | 
			
		||||
		cdev->desc.idProduct = cpu_to_le16(idProduct);
 | 
			
		||||
	if (bcdDevice)
 | 
			
		||||
		cdev->desc.bcdDevice = cpu_to_le16(bcdDevice);
 | 
			
		||||
 | 
			
		||||
	/* strings can't be assigned before bind() allocates the
 | 
			
		||||
	 * releavnt identifiers
 | 
			
		||||
	 */
 | 
			
		||||
@@ -1218,10 +1106,6 @@ static int composite_bind(struct usb_gadget *gadget)
 | 
			
		||||
		string_override(composite->strings,
 | 
			
		||||
			cdev->desc.iSerialNumber, iSerialNumber);
 | 
			
		||||
 | 
			
		||||
	status = device_create_file(&gadget->dev, &dev_attr_suspended);
 | 
			
		||||
	if (status)
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
	INFO(cdev, "%s ready\n", composite->name);
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
@@ -1232,7 +1116,8 @@ fail:
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
static void composite_suspend(struct usb_gadget *gadget)
 | 
			
		||||
static void
 | 
			
		||||
composite_suspend(struct usb_gadget *gadget)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
 | 
			
		||||
	struct usb_function		*f;
 | 
			
		||||
@@ -1249,11 +1134,10 @@ static void composite_suspend(struct usb_gadget *gadget)
 | 
			
		||||
	}
 | 
			
		||||
	if (composite->suspend)
 | 
			
		||||
		composite->suspend(cdev);
 | 
			
		||||
 | 
			
		||||
	cdev->suspended = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void composite_resume(struct usb_gadget *gadget)
 | 
			
		||||
static void
 | 
			
		||||
composite_resume(struct usb_gadget *gadget)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
 | 
			
		||||
	struct usb_function		*f;
 | 
			
		||||
@@ -1270,24 +1154,6 @@ static void composite_resume(struct usb_gadget *gadget)
 | 
			
		||||
				f->resume(f);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  cdev->suspended = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int composite_uevent(struct device *dev, struct kobj_uevent_env *env)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_function *f = dev_get_drvdata(dev);
 | 
			
		||||
 | 
			
		||||
	if (!f) {
 | 
			
		||||
		/* this happens when the device is first created */
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (add_uevent_var(env, "FUNCTION=%s", f->name))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	if (add_uevent_var(env, "ENABLED=%d", !f->disabled))
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
@@ -1296,7 +1162,7 @@ static struct usb_gadget_driver composite_driver = {
 | 
			
		||||
	.speed		= USB_SPEED_HIGH,
 | 
			
		||||
 | 
			
		||||
	.bind		= composite_bind,
 | 
			
		||||
	.unbind		= composite_unbind,
 | 
			
		||||
	.unbind		= __exit_p(composite_unbind),
 | 
			
		||||
 | 
			
		||||
	.setup		= composite_setup,
 | 
			
		||||
	.disconnect	= composite_disconnect,
 | 
			
		||||
@@ -1324,7 +1190,7 @@ static struct usb_gadget_driver composite_driver = {
 | 
			
		||||
 * while it was binding.  That would usually be done in order to wait for
 | 
			
		||||
 * some userspace participation.
 | 
			
		||||
 */
 | 
			
		||||
int usb_composite_register(struct usb_composite_driver *driver)
 | 
			
		||||
int __init usb_composite_register(struct usb_composite_driver *driver)
 | 
			
		||||
{
 | 
			
		||||
	if (!driver || !driver->dev || !driver->bind || composite)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
@@ -1338,7 +1204,6 @@ int usb_composite_register(struct usb_composite_driver *driver)
 | 
			
		||||
	driver->class = class_create(THIS_MODULE, "usb_composite");
 | 
			
		||||
	if (IS_ERR(driver->class))
 | 
			
		||||
		return PTR_ERR(driver->class);
 | 
			
		||||
  driver->class->dev_uevent = composite_uevent;
 | 
			
		||||
 | 
			
		||||
	return usb_gadget_register_driver(&composite_driver);
 | 
			
		||||
}
 | 
			
		||||
@@ -1350,7 +1215,7 @@ int usb_composite_register(struct usb_composite_driver *driver)
 | 
			
		||||
 * This function is used to unregister drivers using the composite
 | 
			
		||||
 * driver framework.
 | 
			
		||||
 */
 | 
			
		||||
void usb_composite_unregister(struct usb_composite_driver *driver)
 | 
			
		||||
void __exit usb_composite_unregister(struct usb_composite_driver *driver)
 | 
			
		||||
{
 | 
			
		||||
	if (composite != driver)
 | 
			
		||||
		return;
 | 
			
		||||
 
 | 
			
		||||
@@ -71,6 +71,7 @@ static void TRACE(const char *tag, const void *_data, int len, int decode)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define HDLC_MAX 4096
 | 
			
		||||
#define SMD_MAX 8192
 | 
			
		||||
 | 
			
		||||
#define TX_REQ_BUF_SZ 8192
 | 
			
		||||
#define RX_REQ_BUF_SZ 8192
 | 
			
		||||
@@ -87,6 +88,8 @@ struct diag_context
 | 
			
		||||
	struct usb_ep *in;
 | 
			
		||||
	struct list_head tx_req_idle;
 | 
			
		||||
	struct list_head rx_req_idle;
 | 
			
		||||
	struct list_head rx_arm9_idle;
 | 
			
		||||
	struct list_head rx_arm9_done;
 | 
			
		||||
	spinlock_t req_lock;
 | 
			
		||||
#if ROUTE_TO_USERSPACE
 | 
			
		||||
	struct mutex user_lock;
 | 
			
		||||
@@ -103,12 +106,11 @@ struct diag_context
 | 
			
		||||
	unsigned char id_table[ID_TABLE_SZ];
 | 
			
		||||
#endif
 | 
			
		||||
	smd_channel_t *ch;
 | 
			
		||||
	struct mutex smd_lock;
 | 
			
		||||
	int in_busy;
 | 
			
		||||
#ifdef CONFIG_ARCH_QSD8X50
 | 
			
		||||
	smd_channel_t *ch_dsp;
 | 
			
		||||
	int in_busy_dsp;
 | 
			
		||||
#endif
 | 
			
		||||
	int online;
 | 
			
		||||
	int error;
 | 
			
		||||
	int init_done;
 | 
			
		||||
 | 
			
		||||
	/* assembly buffer for USB->A9 HDLC frames */
 | 
			
		||||
	unsigned char hdlc_buf[HDLC_MAX];
 | 
			
		||||
@@ -119,6 +121,22 @@ struct diag_context
 | 
			
		||||
	u64 rx_count; /* from smd */
 | 
			
		||||
 | 
			
		||||
	int function_enable;
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_MSM_N_WAY_SMD)
 | 
			
		||||
	smd_channel_t *chqdsp;
 | 
			
		||||
	struct list_head tx_qdsp_idle;
 | 
			
		||||
#endif
 | 
			
		||||
	/* for slate test */
 | 
			
		||||
	int is2ARM11;
 | 
			
		||||
	struct mutex diag2arm9_lock;
 | 
			
		||||
	struct mutex diag2arm9_read_lock;
 | 
			
		||||
	struct mutex diag2arm9_write_lock;
 | 
			
		||||
	bool diag2arm9_opened;
 | 
			
		||||
	unsigned char toARM9_buf[SMD_MAX];
 | 
			
		||||
	unsigned read_arm9_count;
 | 
			
		||||
	unsigned char *read_arm9_buf;
 | 
			
		||||
	wait_queue_head_t read_arm9_wq;
 | 
			
		||||
	struct usb_request *read_arm9_req;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_interface_descriptor diag_interface_desc = {
 | 
			
		||||
@@ -175,6 +193,23 @@ static struct usb_descriptor_header *hs_diag_descs[] = {
 | 
			
		||||
	NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* string descriptors: */
 | 
			
		||||
 | 
			
		||||
static struct usb_string diag_string_defs[] = {
 | 
			
		||||
	[0].s = "HTC DIAG",
 | 
			
		||||
	{  } /* end of list */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_gadget_strings diag_string_table = {
 | 
			
		||||
	.language =		0x0409,	/* en-us */
 | 
			
		||||
	.strings =		diag_string_defs,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_gadget_strings *diag_strings[] = {
 | 
			
		||||
	&diag_string_table,
 | 
			
		||||
	NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct diag_context _context;
 | 
			
		||||
 | 
			
		||||
static inline struct diag_context *func_to_dev(struct usb_function *f)
 | 
			
		||||
@@ -183,11 +218,42 @@ static inline struct diag_context *func_to_dev(struct usb_function *f)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void smd_try_to_send(struct diag_context *ctxt);
 | 
			
		||||
#ifdef CONFIG_ARCH_QSD8X50
 | 
			
		||||
static void dsp_try_to_send(struct diag_context *ctxt);
 | 
			
		||||
#endif
 | 
			
		||||
static void smd_diag_notify(void *priv, unsigned event);
 | 
			
		||||
 | 
			
		||||
static void diag_queue_out(struct diag_context *ctxt);
 | 
			
		||||
#if defined(CONFIG_MSM_N_WAY_SMD)
 | 
			
		||||
static void diag_qdsp_complete_in(struct usb_ep *ept,
 | 
			
		||||
	struct usb_request *req);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static struct usb_request *diag_req_new(unsigned len)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_request *req;
 | 
			
		||||
	if (len > SMD_MAX)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	req = kmalloc(sizeof(struct usb_request), GFP_KERNEL);
 | 
			
		||||
	if (!req)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	req->buf = kmalloc(len, GFP_KERNEL);
 | 
			
		||||
	if (!req->buf) {
 | 
			
		||||
		kfree(req);
 | 
			
		||||
		return NULL;
 | 
			
		||||
	}
 | 
			
		||||
	return req;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void diag_req_free(struct usb_request *req)
 | 
			
		||||
{
 | 
			
		||||
	if (!req)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	if (req->buf) {
 | 
			
		||||
		kfree(req->buf);
 | 
			
		||||
		req->buf = 0;
 | 
			
		||||
	}
 | 
			
		||||
	kfree(req);
 | 
			
		||||
	req = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* add a request to the tail of a list */
 | 
			
		||||
static void req_put(struct diag_context *ctxt, struct list_head *head,
 | 
			
		||||
@@ -227,29 +293,82 @@ static void reqs_free(struct diag_context *ctxt, struct usb_ep *ep,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void smd_diag_enable(char *src, int enable)
 | 
			
		||||
{
 | 
			
		||||
	struct diag_context *ctxt = &_context;
 | 
			
		||||
 | 
			
		||||
	printk(KERN_INFO "smd_try_open(%s): %d\n", src, enable);
 | 
			
		||||
	if (!ctxt->init_done)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&ctxt->smd_lock);
 | 
			
		||||
	if (enable) {
 | 
			
		||||
		if (!ctxt->ch)
 | 
			
		||||
			smd_open("SMD_DIAG", &ctxt->ch, ctxt, smd_diag_notify);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (ctxt->ch) {
 | 
			
		||||
			smd_close(ctxt->ch);
 | 
			
		||||
			ctxt->ch = NULL;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	mutex_unlock(&ctxt->smd_lock);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if ROUTE_TO_USERSPACE
 | 
			
		||||
#define USB_DIAG_IOC_MAGIC 0xFF
 | 
			
		||||
#define USB_DIAG_FUNC_IOC_REGISTER_SET _IOW(USB_DIAG_IOC_MAGIC, 3, char *)
 | 
			
		||||
#define USB_DIAG_FUNC_IOC_ENABLE_SET	_IOW(USB_DIAG_IOC_MAGIC, 1, int)
 | 
			
		||||
#define USB_DIAG_FUNC_IOC_ENABLE_GET	_IOR(USB_DIAG_IOC_MAGIC, 2, int)
 | 
			
		||||
#define USB_DIAG_FUNC_IOC_REGISTER_SET  _IOW(USB_DIAG_IOC_MAGIC, 3, char *)
 | 
			
		||||
#define USB_DIAG_FUNC_IOC_AMR_SET	_IOW(USB_DIAG_IOC_MAGIC, 4, int)
 | 
			
		||||
 | 
			
		||||
static long diag_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 | 
			
		||||
{
 | 
			
		||||
	struct diag_context *ctxt = &_context;
 | 
			
		||||
	void __user *argp = (void __user *)arg;
 | 
			
		||||
	int tmp_value;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	unsigned char temp_id_table[ID_TABLE_SZ];
 | 
			
		||||
 | 
			
		||||
	if (cmd != USB_DIAG_FUNC_IOC_REGISTER_SET) {
 | 
			
		||||
		pr_err("%s: invalid cmd %d\n", __func__, _IOC_NR(cmd));
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	printk(KERN_INFO "diag:diag_ioctl() cmd=%d\n", cmd);
 | 
			
		||||
 | 
			
		||||
	if (_IOC_TYPE(cmd) != USB_DIAG_IOC_MAGIC)
 | 
			
		||||
		return -ENOTTY;
 | 
			
		||||
 | 
			
		||||
	switch (cmd) {
 | 
			
		||||
	case USB_DIAG_FUNC_IOC_ENABLE_SET:
 | 
			
		||||
		if (copy_from_user(&tmp_value, argp, sizeof(int)))
 | 
			
		||||
			return -EFAULT;
 | 
			
		||||
		printk(KERN_INFO "diag: enable %d\n", tmp_value);
 | 
			
		||||
		android_enable_function(&_context.function, tmp_value);
 | 
			
		||||
		smd_diag_enable("diag_ioctl", tmp_value);
 | 
			
		||||
		/* force diag_read to return error when disable diag */
 | 
			
		||||
		if (tmp_value == 0)
 | 
			
		||||
			ctxt->error = 1;
 | 
			
		||||
		wake_up(&ctxt->read_wq);
 | 
			
		||||
	break;
 | 
			
		||||
	case USB_DIAG_FUNC_IOC_ENABLE_GET:
 | 
			
		||||
		tmp_value = !_context.function.hidden;
 | 
			
		||||
		if (copy_to_user(argp, &tmp_value, sizeof(tmp_value)))
 | 
			
		||||
			return -EFAULT;
 | 
			
		||||
	break;
 | 
			
		||||
 | 
			
		||||
	case USB_DIAG_FUNC_IOC_REGISTER_SET:
 | 
			
		||||
		if (copy_from_user(temp_id_table, (unsigned char *)argp, ID_TABLE_SZ))
 | 
			
		||||
			return -EFAULT;
 | 
			
		||||
		spin_lock_irqsave(&ctxt->req_lock, flags);
 | 
			
		||||
		memcpy(ctxt->id_table, temp_id_table, ID_TABLE_SZ);
 | 
			
		||||
		spin_unlock_irqrestore(&ctxt->req_lock, flags);
 | 
			
		||||
		break;
 | 
			
		||||
	case USB_DIAG_FUNC_IOC_AMR_SET:
 | 
			
		||||
		if (copy_from_user(&ctxt->is2ARM11, argp, sizeof(int)))
 | 
			
		||||
			return -EFAULT;
 | 
			
		||||
		printk(KERN_INFO "diag: is2ARM11 %d\n", ctxt->is2ARM11);
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		return -ENOTTY;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (copy_from_user(temp_id_table, (unsigned char *)argp, ID_TABLE_SZ))
 | 
			
		||||
		return -EFAULT;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&ctxt->req_lock, flags);
 | 
			
		||||
	memcpy(ctxt->id_table, temp_id_table, ID_TABLE_SZ);
 | 
			
		||||
	spin_unlock_irqrestore(&ctxt->req_lock, flags);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -260,6 +379,13 @@ static ssize_t diag_read(struct file *fp, char __user *buf,
 | 
			
		||||
	struct usb_request *req = 0;
 | 
			
		||||
	int ret = 0;
 | 
			
		||||
 | 
			
		||||
	/* we will block until we're online */
 | 
			
		||||
	if (!ctxt->online) {
 | 
			
		||||
		ret = wait_event_interruptible(ctxt->read_wq, (ctxt->online || ctxt->error));
 | 
			
		||||
		if (ret < 0 || ctxt->error)
 | 
			
		||||
			return -EFAULT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&ctxt->user_lock);
 | 
			
		||||
 | 
			
		||||
	if (ctxt->user_read_len && ctxt->user_readp) {
 | 
			
		||||
@@ -285,7 +411,7 @@ static ssize_t diag_read(struct file *fp, char __user *buf,
 | 
			
		||||
		goto end;
 | 
			
		||||
	}
 | 
			
		||||
	if (!ctxt->online) {
 | 
			
		||||
		pr_err("%s: offline\n", __func__);
 | 
			
		||||
		/* pr_err("%s: offline\n", __func__); */
 | 
			
		||||
		ret = -EIO;
 | 
			
		||||
		goto end;
 | 
			
		||||
	}
 | 
			
		||||
@@ -357,6 +483,8 @@ static ssize_t diag_write(struct file *fp, const char __user *buf,
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ret = req->length;
 | 
			
		||||
		/* zero this so we don't put it back to idle queue */
 | 
			
		||||
		req = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
end:
 | 
			
		||||
@@ -388,6 +516,8 @@ static int diag_open(struct inode *ip, struct file *fp)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	ctxt->opened = true;
 | 
			
		||||
	/* clear the error latch */
 | 
			
		||||
	ctxt->error = 0;
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	mutex_unlock(&ctxt->user_lock);
 | 
			
		||||
@@ -427,6 +557,174 @@ static struct miscdevice diag_device_fops = {
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int diag2arm9_open(struct inode *ip, struct file *fp)
 | 
			
		||||
{
 | 
			
		||||
	struct diag_context *ctxt = &_context;
 | 
			
		||||
	struct usb_request *req;
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
	int n;
 | 
			
		||||
	printk(KERN_INFO "%s\n", __func__);
 | 
			
		||||
	mutex_lock(&ctxt->diag2arm9_lock);
 | 
			
		||||
	if (ctxt->diag2arm9_opened) {
 | 
			
		||||
		pr_err("%s: already opened\n", __func__);
 | 
			
		||||
		rc = -EBUSY;
 | 
			
		||||
		goto done;
 | 
			
		||||
	}
 | 
			
		||||
	/* clear pending data if any */
 | 
			
		||||
	while ((req = req_get(ctxt, &ctxt->rx_arm9_done)))
 | 
			
		||||
		diag_req_free(req);
 | 
			
		||||
 | 
			
		||||
	for (n = 0; n < 4; n++) {
 | 
			
		||||
		req = diag_req_new(SMD_MAX);
 | 
			
		||||
		if (!req) {
 | 
			
		||||
			while ((req = req_get(ctxt, &ctxt->rx_arm9_idle)))
 | 
			
		||||
				diag_req_free(req);
 | 
			
		||||
			rc = -EFAULT;
 | 
			
		||||
			goto done;
 | 
			
		||||
		}
 | 
			
		||||
		req_put(ctxt, &ctxt->rx_arm9_idle, req);
 | 
			
		||||
	}
 | 
			
		||||
	ctxt->read_arm9_count = 0;
 | 
			
		||||
	ctxt->read_arm9_buf = 0;
 | 
			
		||||
	ctxt->read_arm9_req = 0;
 | 
			
		||||
	ctxt->diag2arm9_opened = true;
 | 
			
		||||
 | 
			
		||||
	smd_diag_enable("diag2arm9_open", 1);
 | 
			
		||||
done:
 | 
			
		||||
	mutex_unlock(&ctxt->diag2arm9_lock);
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int diag2arm9_release(struct inode *ip, struct file *fp)
 | 
			
		||||
{
 | 
			
		||||
	struct diag_context *ctxt = &_context;
 | 
			
		||||
	struct usb_request *req;
 | 
			
		||||
 | 
			
		||||
	printk(KERN_INFO "%s\n", __func__);
 | 
			
		||||
	mutex_lock(&ctxt->diag2arm9_lock);
 | 
			
		||||
	ctxt->diag2arm9_opened = false;
 | 
			
		||||
	wake_up(&ctxt->read_arm9_wq);
 | 
			
		||||
	mutex_lock(&ctxt->diag2arm9_read_lock);
 | 
			
		||||
	while ((req = req_get(ctxt, &ctxt->rx_arm9_idle)))
 | 
			
		||||
		diag_req_free(req);
 | 
			
		||||
	while ((req = req_get(ctxt, &ctxt->rx_arm9_done)))
 | 
			
		||||
		diag_req_free(req);
 | 
			
		||||
	if (ctxt->read_arm9_req)
 | 
			
		||||
		diag_req_free(ctxt->read_arm9_req);
 | 
			
		||||
	mutex_unlock(&ctxt->diag2arm9_read_lock);
 | 
			
		||||
 | 
			
		||||
	/*************************************
 | 
			
		||||
	* If smd is closed, it will  lead to slate can't be tested.
 | 
			
		||||
	* slate will open it for one time
 | 
			
		||||
	* but close it for several times and never open
 | 
			
		||||
	*************************************/
 | 
			
		||||
	/*smd_diag_enable("diag2arm9_release", 0);*/
 | 
			
		||||
	mutex_unlock(&ctxt->diag2arm9_lock);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t diag2arm9_write(struct file *fp, const char __user *buf,
 | 
			
		||||
			 size_t count, loff_t *pos)
 | 
			
		||||
{
 | 
			
		||||
	struct diag_context *ctxt = &_context;
 | 
			
		||||
	int r = count;
 | 
			
		||||
	int writed = 0;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&ctxt->diag2arm9_write_lock);
 | 
			
		||||
 | 
			
		||||
	while (count > 0) {
 | 
			
		||||
		writed = count > SMD_MAX ? SMD_MAX : count;
 | 
			
		||||
		if (copy_from_user(ctxt->toARM9_buf, buf, writed)) {
 | 
			
		||||
			r = -EFAULT;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		if (ctxt->ch == NULL) {
 | 
			
		||||
			printk(KERN_ERR "%s: ctxt->ch == NULL", __func__);
 | 
			
		||||
			r = -EFAULT;
 | 
			
		||||
			break;
 | 
			
		||||
		} else if (ctxt->toARM9_buf == NULL) {
 | 
			
		||||
			printk(KERN_ERR "%s: ctxt->toARM9_buf == NULL", __func__);
 | 
			
		||||
			r = -EFAULT;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		smd_write(ctxt->ch, ctxt->toARM9_buf, writed);
 | 
			
		||||
		buf += writed;
 | 
			
		||||
		count -= writed;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&ctxt->diag2arm9_write_lock);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t diag2arm9_read(struct file *fp, char __user *buf,
 | 
			
		||||
			size_t count, loff_t *pos)
 | 
			
		||||
{
 | 
			
		||||
	struct diag_context *ctxt = &_context;
 | 
			
		||||
	struct usb_request *req;
 | 
			
		||||
	int r = 0, xfer;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&ctxt->diag2arm9_read_lock);
 | 
			
		||||
 | 
			
		||||
	/* if we have data pending, give it to userspace */
 | 
			
		||||
	if (ctxt->read_arm9_count > 0)
 | 
			
		||||
		req = ctxt->read_arm9_req;
 | 
			
		||||
	else {
 | 
			
		||||
retry:
 | 
			
		||||
	/* get data from done queue */
 | 
			
		||||
		req = 0;
 | 
			
		||||
		ret = wait_event_interruptible(ctxt->read_arm9_wq,
 | 
			
		||||
				((req = req_get(ctxt, &ctxt->rx_arm9_done)) ||
 | 
			
		||||
				!ctxt->diag2arm9_opened));
 | 
			
		||||
		if (!ctxt->diag2arm9_opened) {
 | 
			
		||||
			if (req)
 | 
			
		||||
				req_put(ctxt, &ctxt->rx_arm9_idle, req);
 | 
			
		||||
			goto done;
 | 
			
		||||
		}
 | 
			
		||||
		if (ret < 0 || req == 0)
 | 
			
		||||
			goto done;
 | 
			
		||||
 | 
			
		||||
		if (req->actual == 0) {
 | 
			
		||||
			req_put(ctxt, &ctxt->rx_arm9_idle, req);
 | 
			
		||||
			goto retry;
 | 
			
		||||
		}
 | 
			
		||||
		ctxt->read_arm9_req = req;
 | 
			
		||||
		ctxt->read_arm9_count = req->actual;
 | 
			
		||||
		ctxt->read_arm9_buf = req->buf;
 | 
			
		||||
	}
 | 
			
		||||
	xfer = (ctxt->read_arm9_count < count) ? ctxt->read_arm9_count : count;
 | 
			
		||||
	if (copy_to_user(buf, ctxt->read_arm9_buf, xfer)) {
 | 
			
		||||
		printk(KERN_INFO "diag: copy_to_user fail\n");
 | 
			
		||||
		r = -EFAULT;
 | 
			
		||||
		goto done;
 | 
			
		||||
	}
 | 
			
		||||
	ctxt->read_arm9_buf += xfer;
 | 
			
		||||
	ctxt->read_arm9_count -= xfer;
 | 
			
		||||
	r += xfer;
 | 
			
		||||
	/* if we've emptied the buffer, release the request */
 | 
			
		||||
	if (ctxt->read_arm9_count == 0) {
 | 
			
		||||
		req_put(ctxt, &ctxt->rx_arm9_idle, ctxt->read_arm9_req);
 | 
			
		||||
		ctxt->read_arm9_req = 0;
 | 
			
		||||
	}
 | 
			
		||||
done:
 | 
			
		||||
	mutex_unlock(&ctxt->diag2arm9_read_lock);
 | 
			
		||||
	return r;
 | 
			
		||||
}
 | 
			
		||||
static struct file_operations diag2arm9_fops = {
 | 
			
		||||
	.owner =   THIS_MODULE,
 | 
			
		||||
	.open =    diag2arm9_open,
 | 
			
		||||
	.release = diag2arm9_release,
 | 
			
		||||
	.write = diag2arm9_write,
 | 
			
		||||
	.read = diag2arm9_read,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct miscdevice diag2arm9_device = {
 | 
			
		||||
	.minor = MISC_DYNAMIC_MINOR,
 | 
			
		||||
	.name = "diag_arm9",
 | 
			
		||||
	.fops = &diag2arm9_fops,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void diag_in_complete(struct usb_ep *ept, struct usb_request *req)
 | 
			
		||||
{
 | 
			
		||||
	struct diag_context *ctxt = req->context;
 | 
			
		||||
@@ -446,19 +744,7 @@ static void diag_in_complete(struct usb_ep *ept, struct usb_request *req)
 | 
			
		||||
	smd_try_to_send(ctxt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ARCH_QSD8X50
 | 
			
		||||
static void diag_dsp_in_complete(struct usb_ep *ept, struct usb_request *req)
 | 
			
		||||
{
 | 
			
		||||
	struct diag_context *ctxt = req->context;
 | 
			
		||||
 | 
			
		||||
	ctxt->in_busy_dsp = 0;
 | 
			
		||||
	req_put(ctxt, &ctxt->tx_req_idle, req);
 | 
			
		||||
	dsp_try_to_send(ctxt);
 | 
			
		||||
	wake_up(&ctxt->write_wq);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
#if !NO_HDLC
 | 
			
		||||
static void diag_process_hdlc(struct diag_context *ctxt, void *_data, unsigned len)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char *data = _data;
 | 
			
		||||
@@ -585,8 +871,27 @@ again:
 | 
			
		||||
		int r = smd_read_avail(ctxt->ch);
 | 
			
		||||
 | 
			
		||||
		if (r > TX_REQ_BUF_SZ) {
 | 
			
		||||
			printk(KERN_ERR "The SMD data is too large to send!!\n");
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (r > 0 && ctxt->is2ARM11) {
 | 
			
		||||
			/* to arm11 user space */
 | 
			
		||||
			struct usb_request *req;
 | 
			
		||||
			if (!ctxt->diag2arm9_opened)
 | 
			
		||||
				return;
 | 
			
		||||
			req = req_get(ctxt, &ctxt->rx_arm9_idle);
 | 
			
		||||
			if (!req) {
 | 
			
		||||
				printk(KERN_ERR "There is no enough request to ARM11!!\n");
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			smd_read(ctxt->ch, req->buf, r);
 | 
			
		||||
			req->actual = r;
 | 
			
		||||
			req_put(ctxt, &ctxt->rx_arm9_done, req);
 | 
			
		||||
			wake_up(&ctxt->read_arm9_wq);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (!ctxt->online)
 | 
			
		||||
			return;
 | 
			
		||||
		if (r > 0) {
 | 
			
		||||
			struct usb_request *req;
 | 
			
		||||
			req = req_get(ctxt, &ctxt->tx_req_idle);
 | 
			
		||||
@@ -626,55 +931,6 @@ static void smd_diag_notify(void *priv, unsigned event)
 | 
			
		||||
	smd_try_to_send(ctxt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ARCH_QSD8X50
 | 
			
		||||
static void dsp_try_to_send(struct diag_context *ctxt)
 | 
			
		||||
{
 | 
			
		||||
again:
 | 
			
		||||
	if (ctxt->ch_dsp && (!ctxt->in_busy_dsp)) {
 | 
			
		||||
		int r = smd_read_avail(ctxt->ch_dsp);
 | 
			
		||||
 | 
			
		||||
		if (r > TX_REQ_BUF_SZ) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (r > 0) {
 | 
			
		||||
			struct usb_request *req;
 | 
			
		||||
			req = req_get(ctxt, &ctxt->tx_req_idle);
 | 
			
		||||
			if (!req) {
 | 
			
		||||
				pr_err("%s: tx req queue is out of buffers\n",
 | 
			
		||||
					__func__);
 | 
			
		||||
				return;
 | 
			
		||||
			}
 | 
			
		||||
			smd_read(ctxt->ch_dsp, req->buf, r);
 | 
			
		||||
 | 
			
		||||
			if (!ctxt->online) {
 | 
			
		||||
//				printk("$$$ discard %d\n", r);
 | 
			
		||||
				req_put(ctxt, &ctxt->tx_req_idle, req);
 | 
			
		||||
				goto again;
 | 
			
		||||
			}
 | 
			
		||||
			req->complete = diag_dsp_in_complete;
 | 
			
		||||
			req->context = ctxt;
 | 
			
		||||
			req->length = r;
 | 
			
		||||
 | 
			
		||||
			TRACE("Q6>", req->buf, r, 1);
 | 
			
		||||
			ctxt->in_busy_dsp = 1;
 | 
			
		||||
			r = usb_ep_queue(ctxt->in, req, GFP_ATOMIC);
 | 
			
		||||
			if (r < 0) {
 | 
			
		||||
				pr_err("%s: usb_ep_queue failed: %d\n",
 | 
			
		||||
					__func__, r);
 | 
			
		||||
				req_put(ctxt, &ctxt->tx_req_idle, req);
 | 
			
		||||
				ctxt->in_busy_dsp = 0;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void dsp_diag_notify(void *priv, unsigned event)
 | 
			
		||||
{
 | 
			
		||||
	struct diag_context *ctxt = priv;
 | 
			
		||||
	dsp_try_to_send(ctxt);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int __init create_bulk_endpoints(struct diag_context *ctxt,
 | 
			
		||||
				struct usb_endpoint_descriptor *in_desc,
 | 
			
		||||
				struct usb_endpoint_descriptor *out_desc)
 | 
			
		||||
@@ -689,12 +945,14 @@ static int __init create_bulk_endpoints(struct diag_context *ctxt,
 | 
			
		||||
		DBG(cdev, "usb_ep_autoconfig for ep_in failed\n");
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	}
 | 
			
		||||
	ep->driver_data = ctxt;		/* claim the endpoint */
 | 
			
		||||
	ctxt->in = ep;
 | 
			
		||||
 | 
			
		||||
	ep = usb_ep_autoconfig(cdev->gadget, out_desc);
 | 
			
		||||
	if (!ep) {
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
	}
 | 
			
		||||
	ep->driver_data = ctxt;		/* claim the endpoint */
 | 
			
		||||
	ctxt->out = ep;
 | 
			
		||||
 | 
			
		||||
	ctxt->tx_count = ctxt->rx_count = 0;
 | 
			
		||||
@@ -733,8 +991,30 @@ static int __init create_bulk_endpoints(struct diag_context *ctxt,
 | 
			
		||||
		req_put(ctxt, &ctxt->tx_req_idle, req);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
#if defined(CONFIG_MSM_N_WAY_SMD)
 | 
			
		||||
	for (n = 0; n < TX_REQ_NUM; n++) {
 | 
			
		||||
		req = usb_ep_alloc_request(ctxt->in, GFP_KERNEL);
 | 
			
		||||
		if (!req) {
 | 
			
		||||
			DBG(cdev, "%s: usb_ep_alloc_request out of memory\n",
 | 
			
		||||
				__func__);
 | 
			
		||||
			goto qdsp_tx_fail;
 | 
			
		||||
		}
 | 
			
		||||
		req->buf = kmalloc(TX_REQ_BUF_SZ, GFP_KERNEL);
 | 
			
		||||
		if (!req->buf) {
 | 
			
		||||
			DBG(cdev, "%s: kmalloc out of memory\n", __func__);
 | 
			
		||||
			goto qdsp_tx_fail;
 | 
			
		||||
		}
 | 
			
		||||
		req->context = ctxt;
 | 
			
		||||
		req->complete = diag_qdsp_complete_in;
 | 
			
		||||
		req_put(ctxt, &ctxt->tx_qdsp_idle, req);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
#if defined(CONFIG_MSM_N_WAY_SMD)
 | 
			
		||||
qdsp_tx_fail:
 | 
			
		||||
	reqs_free(ctxt, ctxt->in, &ctxt->tx_qdsp_idle);
 | 
			
		||||
#endif
 | 
			
		||||
tx_fail:
 | 
			
		||||
	reqs_free(ctxt, ctxt->in, &ctxt->tx_req_idle);
 | 
			
		||||
rx_fail:
 | 
			
		||||
@@ -775,6 +1055,7 @@ diag_function_bind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
#if ROUTE_TO_USERSPACE
 | 
			
		||||
	misc_register(&diag_device_fops);
 | 
			
		||||
#endif
 | 
			
		||||
	misc_register(&diag2arm9_device);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -789,6 +1070,7 @@ diag_function_unbind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
#if ROUTE_TO_USERSPACE
 | 
			
		||||
	misc_deregister(&diag_device_fops);
 | 
			
		||||
#endif
 | 
			
		||||
	misc_deregister(&diag2arm9_device);
 | 
			
		||||
 | 
			
		||||
	ctxt->tx_count = ctxt->rx_count = 0;
 | 
			
		||||
}
 | 
			
		||||
@@ -817,7 +1099,7 @@ static int diag_function_set_alt(struct usb_function *f,
 | 
			
		||||
		usb_ep_disable(ctxt->in);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	ctxt->online = 1;
 | 
			
		||||
	ctxt->online = !ctxt->function.hidden;
 | 
			
		||||
 | 
			
		||||
#if ROUTE_TO_USERSPACE
 | 
			
		||||
	/* recycle unhandled rx reqs to user if any */
 | 
			
		||||
@@ -825,12 +1107,10 @@ static int diag_function_set_alt(struct usb_function *f,
 | 
			
		||||
		req_put(ctxt, &ctxt->rx_req_idle, req);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	diag_queue_out(ctxt);
 | 
			
		||||
	smd_try_to_send(ctxt);
 | 
			
		||||
#ifdef CONFIG_ARCH_QSD8X50
 | 
			
		||||
	dsp_try_to_send(ctxt);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if (ctxt->online) {
 | 
			
		||||
		diag_queue_out(ctxt);
 | 
			
		||||
		smd_try_to_send(ctxt);
 | 
			
		||||
	}
 | 
			
		||||
#if ROUTE_TO_USERSPACE
 | 
			
		||||
	wake_up(&ctxt->read_wq);
 | 
			
		||||
	wake_up(&ctxt->write_wq);
 | 
			
		||||
@@ -852,12 +1132,78 @@ static void diag_function_disable(struct usb_function *f)
 | 
			
		||||
	usb_ep_disable(ctxt->out);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_MSM_N_WAY_SMD)
 | 
			
		||||
static void diag_qdsp_send(struct diag_context *ctxt)
 | 
			
		||||
{
 | 
			
		||||
	int ret, r;
 | 
			
		||||
	struct usb_request *req;
 | 
			
		||||
	if (ctxt->chqdsp && ctxt->online) {
 | 
			
		||||
		r = smd_read_avail(ctxt->chqdsp);
 | 
			
		||||
		if (r > SMD_MAX || r <= 0)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		req = req_get(ctxt, &ctxt->tx_qdsp_idle);
 | 
			
		||||
		if (!req)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		smd_read(ctxt->chqdsp, req->buf, r);
 | 
			
		||||
		req->length = r;
 | 
			
		||||
 | 
			
		||||
		ret = usb_ep_queue(ctxt->in, req, GFP_ATOMIC);
 | 
			
		||||
		if (ret < 0) {
 | 
			
		||||
			printk(KERN_INFO "diag: failed to queue qdsp req %d\n",
 | 
			
		||||
				ret);
 | 
			
		||||
			req_put(ctxt, &ctxt->tx_qdsp_idle, req);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void diag_qdsp_complete_in(struct usb_ep *ept,
 | 
			
		||||
		struct usb_request *req)
 | 
			
		||||
{
 | 
			
		||||
	struct diag_context *ctxt = req->context;
 | 
			
		||||
 | 
			
		||||
	req_put(ctxt, &ctxt->tx_qdsp_idle, req);
 | 
			
		||||
	diag_qdsp_send(ctxt);
 | 
			
		||||
 | 
			
		||||
#if ROUTE_TO_USERSPACE
 | 
			
		||||
	wake_up(&ctxt->write_wq);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void diag_qdsp_notify(void *priv, unsigned event)
 | 
			
		||||
{
 | 
			
		||||
	struct diag_context *ctxt = priv;
 | 
			
		||||
	diag_qdsp_send(ctxt);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int msm_diag_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct diag_context *ctxt = &_context;
 | 
			
		||||
	printk(KERN_INFO "diag:msm_diag_probe(), pdev->id=0x%x\n", pdev->id);
 | 
			
		||||
 | 
			
		||||
	if (pdev->id == 1)
 | 
			
		||||
		smd_open("DSP_DIAG", &ctxt->chqdsp, ctxt, diag_qdsp_notify);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver msm_smd_qdsp_ch1_driver = {
 | 
			
		||||
	.probe = msm_diag_probe,
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name = "DSP_DIAG",
 | 
			
		||||
		.owner = THIS_MODULE,
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int diag_set_enabled(const char *val, struct kernel_param *kp)
 | 
			
		||||
{
 | 
			
		||||
	int enabled = simple_strtol(val, NULL, 0);
 | 
			
		||||
	if (_context.cdev)
 | 
			
		||||
		android_enable_function(&_context.function, enabled);
 | 
			
		||||
	_context.function_enable = !!enabled;
 | 
			
		||||
	smd_diag_enable("diag_set_enabled", enabled);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -872,7 +1218,7 @@ module_param_call(tx_rx_count, NULL, diag_get_tx_rx_count, NULL, 0444);
 | 
			
		||||
 | 
			
		||||
static int diag_get_enabled(char *buffer, struct kernel_param *kp)
 | 
			
		||||
{
 | 
			
		||||
	buffer[0] = '0' + !_context.function.disabled;
 | 
			
		||||
	buffer[0] = '0' + !_context.function.hidden;
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
module_param_call(enabled, diag_set_enabled, diag_get_enabled, NULL, 0664);
 | 
			
		||||
@@ -885,20 +1231,15 @@ int diag_bind_config(struct usb_configuration *c)
 | 
			
		||||
 | 
			
		||||
	printk(KERN_INFO "diag_bind_config\n");
 | 
			
		||||
 | 
			
		||||
	ret = smd_open("SMD_DIAG", &ctxt->ch, ctxt, smd_diag_notify);
 | 
			
		||||
	if (ret)
 | 
			
		||||
	ret = usb_string_id(c->cdev);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_ARCH_QSD8X50
 | 
			
		||||
	ret = smd_open("DSP_DIAG", &ctxt->ch_dsp, ctxt, dsp_diag_notify);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		pr_err("%s: smd_open failed (DSP_DIAG)\n", __func__);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	diag_string_defs[0].id = ret;
 | 
			
		||||
	diag_interface_desc.iInterface = ret;
 | 
			
		||||
 | 
			
		||||
	ctxt->cdev = c->cdev;
 | 
			
		||||
	ctxt->function.name = "diag";
 | 
			
		||||
	ctxt->function.strings = diag_strings;
 | 
			
		||||
	ctxt->function.descriptors = fs_diag_descs;
 | 
			
		||||
	ctxt->function.hs_descriptors = hs_diag_descs;
 | 
			
		||||
	ctxt->function.bind = diag_function_bind;
 | 
			
		||||
@@ -906,7 +1247,9 @@ int diag_bind_config(struct usb_configuration *c)
 | 
			
		||||
	ctxt->function.set_alt = diag_function_set_alt;
 | 
			
		||||
	ctxt->function.disable = diag_function_disable;
 | 
			
		||||
 | 
			
		||||
	ctxt->function.disabled = !_context.function_enable;
 | 
			
		||||
	ctxt->function.hidden = !_context.function_enable;
 | 
			
		||||
	if (!ctxt->function.hidden)
 | 
			
		||||
		smd_diag_enable("diag_bind_config", 1);
 | 
			
		||||
 | 
			
		||||
	return usb_add_function(c, &ctxt->function);
 | 
			
		||||
}
 | 
			
		||||
@@ -924,12 +1267,26 @@ static int __init init(void)
 | 
			
		||||
	spin_lock_init(&ctxt->req_lock);
 | 
			
		||||
	INIT_LIST_HEAD(&ctxt->rx_req_idle);
 | 
			
		||||
	INIT_LIST_HEAD(&ctxt->tx_req_idle);
 | 
			
		||||
	INIT_LIST_HEAD(&ctxt->rx_arm9_idle);
 | 
			
		||||
	INIT_LIST_HEAD(&ctxt->rx_arm9_done);
 | 
			
		||||
#if ROUTE_TO_USERSPACE
 | 
			
		||||
	mutex_init(&ctxt->user_lock);
 | 
			
		||||
	INIT_LIST_HEAD(&ctxt->rx_req_user);
 | 
			
		||||
	init_waitqueue_head(&ctxt->read_wq);
 | 
			
		||||
	init_waitqueue_head(&ctxt->write_wq);
 | 
			
		||||
#endif
 | 
			
		||||
	init_waitqueue_head(&ctxt->read_arm9_wq);
 | 
			
		||||
	mutex_init(&ctxt->diag2arm9_lock);
 | 
			
		||||
	mutex_init(&ctxt->diag2arm9_read_lock);
 | 
			
		||||
	mutex_init(&ctxt->diag2arm9_write_lock);
 | 
			
		||||
	mutex_init(&ctxt->smd_lock);
 | 
			
		||||
	ctxt->is2ARM11 = 0;
 | 
			
		||||
 | 
			
		||||
#if defined(CONFIG_MSM_N_WAY_SMD)
 | 
			
		||||
	INIT_LIST_HEAD(&ctxt->tx_qdsp_idle);
 | 
			
		||||
	platform_driver_register(&msm_smd_qdsp_ch1_driver);
 | 
			
		||||
#endif
 | 
			
		||||
	ctxt->init_done = 1;
 | 
			
		||||
 | 
			
		||||
	android_register_function(&diag_function);
 | 
			
		||||
	return 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -31,11 +31,13 @@
 | 
			
		||||
#include <linux/miscdevice.h>
 | 
			
		||||
 | 
			
		||||
#include <linux/usb/android_composite.h>
 | 
			
		||||
#include <mach/board.h>
 | 
			
		||||
 | 
			
		||||
#define BULK_BUFFER_SIZE           4096
 | 
			
		||||
 | 
			
		||||
/* number of tx requests to allocate */
 | 
			
		||||
#define TX_REQ_MAX 4
 | 
			
		||||
#define RX_REQ_MAX 32
 | 
			
		||||
 | 
			
		||||
static const char shortname[] = "android_adb";
 | 
			
		||||
 | 
			
		||||
@@ -55,11 +57,18 @@ struct adb_dev {
 | 
			
		||||
	atomic_t open_excl;
 | 
			
		||||
 | 
			
		||||
	struct list_head tx_idle;
 | 
			
		||||
	struct list_head rx_idle;
 | 
			
		||||
	struct list_head rx_done;
 | 
			
		||||
 | 
			
		||||
	wait_queue_head_t read_wq;
 | 
			
		||||
	wait_queue_head_t write_wq;
 | 
			
		||||
	struct usb_request *rx_req;
 | 
			
		||||
	int rx_done;
 | 
			
		||||
 | 
			
		||||
	/* the request we're currently reading from */
 | 
			
		||||
	struct usb_request *read_req;
 | 
			
		||||
	unsigned char *read_buf;
 | 
			
		||||
	unsigned read_count;
 | 
			
		||||
 | 
			
		||||
	int maxsize;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_interface_descriptor adb_interface_desc = {
 | 
			
		||||
@@ -116,6 +125,22 @@ static struct usb_descriptor_header *hs_adb_descs[] = {
 | 
			
		||||
	NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* string descriptors: */
 | 
			
		||||
 | 
			
		||||
static struct usb_string adb_string_defs[] = {
 | 
			
		||||
	[0].s = "ADB",
 | 
			
		||||
	{  } /* end of list */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_gadget_strings adb_string_table = {
 | 
			
		||||
	.language =		0x0409,	/* en-us */
 | 
			
		||||
	.strings =		adb_string_defs,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_gadget_strings *adb_strings[] = {
 | 
			
		||||
	&adb_string_table,
 | 
			
		||||
	NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* temporary variable used between adb_open() and adb_gadget_bind() */
 | 
			
		||||
static struct adb_dev *_adb_dev;
 | 
			
		||||
@@ -211,9 +236,11 @@ static void adb_complete_out(struct usb_ep *ep, struct usb_request *req)
 | 
			
		||||
{
 | 
			
		||||
	struct adb_dev *dev = _adb_dev;
 | 
			
		||||
 | 
			
		||||
	dev->rx_done = 1;
 | 
			
		||||
	if (req->status != 0)
 | 
			
		||||
	if (req->status != 0) {
 | 
			
		||||
		dev->error = 1;
 | 
			
		||||
		req_put(dev, &dev->rx_idle, req);
 | 
			
		||||
	} else
 | 
			
		||||
		req_put(dev, &dev->rx_done, req);
 | 
			
		||||
 | 
			
		||||
	wake_up(&dev->read_wq);
 | 
			
		||||
}
 | 
			
		||||
@@ -248,11 +275,13 @@ static int __init create_bulk_endpoints(struct adb_dev *dev,
 | 
			
		||||
	dev->ep_out = ep;
 | 
			
		||||
 | 
			
		||||
	/* now allocate requests for our endpoints */
 | 
			
		||||
	req = adb_request_new(dev->ep_out, BULK_BUFFER_SIZE);
 | 
			
		||||
	if (!req)
 | 
			
		||||
		goto fail;
 | 
			
		||||
	req->complete = adb_complete_out;
 | 
			
		||||
	dev->rx_req = req;
 | 
			
		||||
	for (i = 0; i < RX_REQ_MAX; i++) {
 | 
			
		||||
		req = adb_request_new(dev->ep_out, 512);
 | 
			
		||||
		if (!req)
 | 
			
		||||
			goto fail;
 | 
			
		||||
		req->complete = adb_complete_out;
 | 
			
		||||
		req_put(dev, &dev->rx_idle, req);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < TX_REQ_MAX; i++) {
 | 
			
		||||
		req = adb_request_new(dev->ep_in, BULK_BUFFER_SIZE);
 | 
			
		||||
@@ -300,40 +329,70 @@ static ssize_t adb_read(struct file *fp, char __user *buf,
 | 
			
		||||
		r = -EIO;
 | 
			
		||||
		goto done;
 | 
			
		||||
	}
 | 
			
		||||
	while (count > 0) {
 | 
			
		||||
		if (dev->error) {
 | 
			
		||||
			r = -EIO;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* if we have idle read requests, get them queued */
 | 
			
		||||
		while ((req = req_get(dev, &dev->rx_idle))) {
 | 
			
		||||
requeue_req:
 | 
			
		||||
	/* queue a request */
 | 
			
		||||
	req = dev->rx_req;
 | 
			
		||||
	req->length = count;
 | 
			
		||||
	dev->rx_done = 0;
 | 
			
		||||
	ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		DBG(cdev, "adb_read: failed to queue req %p (%d)\n", req, ret);
 | 
			
		||||
		r = -EIO;
 | 
			
		||||
		dev->error = 1;
 | 
			
		||||
		goto done;
 | 
			
		||||
	} else {
 | 
			
		||||
		DBG(cdev, "rx %p queue\n", req);
 | 
			
		||||
	}
 | 
			
		||||
			req->length = dev->maxsize?dev->maxsize:512;
 | 
			
		||||
			ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC);
 | 
			
		||||
			if (ret < 0) {
 | 
			
		||||
				printk(KERN_INFO "adb_read: failed to queue req (%d)\n", ret);
 | 
			
		||||
				r = -EIO;
 | 
			
		||||
				dev->error = 1;
 | 
			
		||||
				req_put(dev, &dev->rx_idle, req);
 | 
			
		||||
				goto done;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	/* wait for a request to complete */
 | 
			
		||||
	ret = wait_event_interruptible(dev->read_wq, dev->rx_done);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		dev->error = 1;
 | 
			
		||||
		r = ret;
 | 
			
		||||
		goto done;
 | 
			
		||||
	}
 | 
			
		||||
	if (!dev->error) {
 | 
			
		||||
		/* If we got a 0-len packet, throw it back and try again. */
 | 
			
		||||
		if (req->actual == 0)
 | 
			
		||||
			goto requeue_req;
 | 
			
		||||
		/* if we have data pending, give it to userspace */
 | 
			
		||||
		if (dev->read_count > 0) {
 | 
			
		||||
			xfer = (dev->read_count < count) ? dev->read_count : count;
 | 
			
		||||
 | 
			
		||||
		DBG(cdev, "rx %p %d\n", req, req->actual);
 | 
			
		||||
		xfer = (req->actual < count) ? req->actual : count;
 | 
			
		||||
		if (copy_to_user(buf, req->buf, xfer))
 | 
			
		||||
			r = -EFAULT;
 | 
			
		||||
	} else
 | 
			
		||||
		r = -EIO;
 | 
			
		||||
			if (copy_to_user(buf, dev->read_buf, xfer)) {
 | 
			
		||||
				r = -EFAULT;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
			dev->read_buf += xfer;
 | 
			
		||||
			dev->read_count -= xfer;
 | 
			
		||||
			buf += xfer;
 | 
			
		||||
			count -= xfer;
 | 
			
		||||
 | 
			
		||||
			/* if we've emptied the buffer, release the request */
 | 
			
		||||
			if (dev->read_count == 0) {
 | 
			
		||||
				req_put(dev, &dev->rx_idle, dev->read_req);
 | 
			
		||||
				dev->read_req = 0;
 | 
			
		||||
			}
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* wait for a request to complete */
 | 
			
		||||
		req = 0;
 | 
			
		||||
		ret = wait_event_interruptible(dev->read_wq,
 | 
			
		||||
				((req = req_get(dev, &dev->rx_done)) || dev->error));
 | 
			
		||||
 | 
			
		||||
		if (req != 0) {
 | 
			
		||||
			/* if we got a 0-len one we need to put it back into
 | 
			
		||||
			** service.  if we made it the current read req we'd
 | 
			
		||||
			** be stuck forever
 | 
			
		||||
			*/
 | 
			
		||||
			if (req->actual == 0)
 | 
			
		||||
				goto requeue_req;
 | 
			
		||||
 | 
			
		||||
			dev->read_req = req;
 | 
			
		||||
			dev->read_count = req->actual;
 | 
			
		||||
			dev->read_buf = req->buf;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (ret < 0) {
 | 
			
		||||
			r = ret;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
done:
 | 
			
		||||
	_unlock(&dev->read_excl);
 | 
			
		||||
@@ -521,7 +580,10 @@ adb_function_unbind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
 | 
			
		||||
	spin_lock_irq(&dev->lock);
 | 
			
		||||
 | 
			
		||||
	adb_request_free(dev->rx_req, dev->ep_out);
 | 
			
		||||
	while ((req = req_get(dev, &dev->rx_done)))
 | 
			
		||||
		adb_request_free(req, dev->ep_out);
 | 
			
		||||
	while ((req = req_get(dev, &dev->rx_idle)))
 | 
			
		||||
		adb_request_free(req, dev->ep_out);
 | 
			
		||||
	while ((req = req_get(dev, &dev->tx_idle)))
 | 
			
		||||
		adb_request_free(req, dev->ep_in);
 | 
			
		||||
 | 
			
		||||
@@ -541,6 +603,7 @@ static int adb_function_set_alt(struct usb_function *f,
 | 
			
		||||
	struct adb_dev	*dev = func_to_dev(f);
 | 
			
		||||
	struct usb_composite_dev *cdev = f->config->cdev;
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct usb_request *req;
 | 
			
		||||
 | 
			
		||||
	DBG(cdev, "adb_function_set_alt intf: %d alt: %d\n", intf, alt);
 | 
			
		||||
	ret = usb_ep_enable(dev->ep_in,
 | 
			
		||||
@@ -557,7 +620,17 @@ static int adb_function_set_alt(struct usb_function *f,
 | 
			
		||||
		usb_ep_disable(dev->ep_in);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
	dev->online = 1;
 | 
			
		||||
	if (cdev->gadget->speed == USB_SPEED_FULL)
 | 
			
		||||
		dev->maxsize = 64;
 | 
			
		||||
	else
 | 
			
		||||
		dev->maxsize = 512;
 | 
			
		||||
	printk(KERN_INFO "%s: maxsize = %d\n", __func__, dev->maxsize);
 | 
			
		||||
 | 
			
		||||
	/* retire any completed rx requests from previous session */
 | 
			
		||||
	while ((req = req_get(dev, &dev->rx_done)))
 | 
			
		||||
		req_put(dev, &dev->rx_idle, req);
 | 
			
		||||
 | 
			
		||||
	dev->online = !dev->function.hidden;
 | 
			
		||||
 | 
			
		||||
	/* readers may be blocked waiting for us to go online */
 | 
			
		||||
	wake_up(&dev->read_wq);
 | 
			
		||||
@@ -572,6 +645,7 @@ static void adb_function_disable(struct usb_function *f)
 | 
			
		||||
	DBG(cdev, "adb_function_disable\n");
 | 
			
		||||
	dev->online = 0;
 | 
			
		||||
	dev->error = 1;
 | 
			
		||||
	dev->maxsize = 0;
 | 
			
		||||
	usb_ep_disable(dev->ep_in);
 | 
			
		||||
	usb_ep_disable(dev->ep_out);
 | 
			
		||||
 | 
			
		||||
@@ -602,18 +676,27 @@ static int adb_bind_config(struct usb_configuration *c)
 | 
			
		||||
	atomic_set(&dev->write_excl, 0);
 | 
			
		||||
 | 
			
		||||
	INIT_LIST_HEAD(&dev->tx_idle);
 | 
			
		||||
	INIT_LIST_HEAD(&dev->rx_idle);
 | 
			
		||||
	INIT_LIST_HEAD(&dev->rx_done);
 | 
			
		||||
 | 
			
		||||
	ret = usb_string_id(c->cdev);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
	adb_string_defs[0].id = ret;
 | 
			
		||||
	adb_interface_desc.iInterface = ret;
 | 
			
		||||
	dev->cdev = c->cdev;
 | 
			
		||||
	dev->function.name = "adb";
 | 
			
		||||
	dev->function.strings = adb_strings;
 | 
			
		||||
	dev->function.descriptors = fs_adb_descs;
 | 
			
		||||
	dev->function.hs_descriptors = hs_adb_descs;
 | 
			
		||||
	dev->function.bind = adb_function_bind;
 | 
			
		||||
	dev->function.unbind = adb_function_unbind;
 | 
			
		||||
	dev->function.set_alt = adb_function_set_alt;
 | 
			
		||||
	dev->function.disable = adb_function_disable;
 | 
			
		||||
	dev->maxsize = 512;
 | 
			
		||||
 | 
			
		||||
	/* start disabled */
 | 
			
		||||
	dev->function.disabled = 1;
 | 
			
		||||
	if (board_mfg_mode() != 2)
 | 
			
		||||
		dev->function.hidden = 1;
 | 
			
		||||
 | 
			
		||||
	/* _adb_dev must be set before calling usb_gadget_register_driver */
 | 
			
		||||
	_adb_dev = dev;
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,53 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Gadget Function Driver for MTP
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2010 Google, Inc.
 | 
			
		||||
 * Author: Mike Lockwood <lockwood@android.com>
 | 
			
		||||
 *
 | 
			
		||||
 * This software is licensed under the terms of the GNU General Public
 | 
			
		||||
 * License version 2, as published by the Free Software Foundation, and
 | 
			
		||||
 * may be copied, distributed, and modified under those terms.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __LINUX_USB_F_MTP_H
 | 
			
		||||
#define __LINUX_USB_F_MTP_H
 | 
			
		||||
 | 
			
		||||
/* Constants for MTP_SET_INTERFACE_MODE */
 | 
			
		||||
#define MTP_INTERFACE_MODE_MTP  0
 | 
			
		||||
#define MTP_INTERFACE_MODE_PTP  1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct mtp_file_range {
 | 
			
		||||
	/* file descriptor for file to transfer */
 | 
			
		||||
	int			fd;
 | 
			
		||||
	/* offset in file for start of transfer */
 | 
			
		||||
	loff_t  	offset;
 | 
			
		||||
	/* number of bytes to transfer */
 | 
			
		||||
	int64_t		length;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct mtp_event {
 | 
			
		||||
	/* size of the event */
 | 
			
		||||
	size_t		length;
 | 
			
		||||
	/* event data to send */
 | 
			
		||||
	void  		*data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Sends the specified file range to the host */
 | 
			
		||||
#define MTP_SEND_FILE              _IOW('M', 0, struct mtp_file_range)
 | 
			
		||||
/* Receives data from the host and writes it to a file.
 | 
			
		||||
 * The file is created if it does not exist.
 | 
			
		||||
 */
 | 
			
		||||
#define MTP_RECEIVE_FILE           _IOW('M', 1, struct mtp_file_range)
 | 
			
		||||
/* Sets the driver mode to either MTP or PTP */
 | 
			
		||||
#define MTP_SET_INTERFACE_MODE     _IOW('M', 2, int)
 | 
			
		||||
/* Sends an event to the host via the interrupt endpoint */
 | 
			
		||||
#define MTP_SEND_EVENT             _IOW('M', 3, struct mtp_event)
 | 
			
		||||
 | 
			
		||||
#endif /* __LINUX_USB_F_MTP_H */
 | 
			
		||||
@@ -4,8 +4,6 @@
 | 
			
		||||
 * Copyright (C) 2003-2005,2008 David Brownell
 | 
			
		||||
 * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
 | 
			
		||||
 * Copyright (C) 2008 Nokia Corporation
 | 
			
		||||
 * Copyright (C) 2009 Samsung Electronics
 | 
			
		||||
 *                    Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
@@ -24,7 +22,6 @@
 | 
			
		||||
 | 
			
		||||
/* #define VERBOSE_DEBUG */
 | 
			
		||||
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/etherdevice.h>
 | 
			
		||||
@@ -123,7 +120,7 @@ static unsigned int bitrate(struct usb_gadget *g)
 | 
			
		||||
 | 
			
		||||
/* interface descriptor: */
 | 
			
		||||
 | 
			
		||||
static struct usb_interface_descriptor rndis_control_intf = {
 | 
			
		||||
static struct usb_interface_descriptor rndis_control_intf __initdata = {
 | 
			
		||||
	.bLength =		sizeof rndis_control_intf,
 | 
			
		||||
	.bDescriptorType =	USB_DT_INTERFACE,
 | 
			
		||||
 | 
			
		||||
@@ -133,7 +130,7 @@ static struct usb_interface_descriptor rndis_control_intf = {
 | 
			
		||||
#ifdef CONFIG_USB_ANDROID_RNDIS_WCEIS
 | 
			
		||||
	/* "Wireless" RNDIS; auto-detected by Windows */
 | 
			
		||||
	.bInterfaceClass =	USB_CLASS_WIRELESS_CONTROLLER,
 | 
			
		||||
	.bInterfaceSubClass = 1,
 | 
			
		||||
	.bInterfaceSubClass =   1,
 | 
			
		||||
	.bInterfaceProtocol =	3,
 | 
			
		||||
#else
 | 
			
		||||
	.bInterfaceClass =	USB_CLASS_COMM,
 | 
			
		||||
@@ -143,7 +140,7 @@ static struct usb_interface_descriptor rndis_control_intf = {
 | 
			
		||||
	/* .iInterface = DYNAMIC */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_cdc_header_desc header_desc = {
 | 
			
		||||
static struct usb_cdc_header_desc header_desc __initdata = {
 | 
			
		||||
	.bLength =		sizeof header_desc,
 | 
			
		||||
	.bDescriptorType =	USB_DT_CS_INTERFACE,
 | 
			
		||||
	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
 | 
			
		||||
@@ -151,7 +148,7 @@ static struct usb_cdc_header_desc header_desc = {
 | 
			
		||||
	.bcdCDC =		cpu_to_le16(0x0110),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
 | 
			
		||||
static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor __initdata = {
 | 
			
		||||
	.bLength =		sizeof call_mgmt_descriptor,
 | 
			
		||||
	.bDescriptorType =	USB_DT_CS_INTERFACE,
 | 
			
		||||
	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
 | 
			
		||||
@@ -160,15 +157,15 @@ static struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
 | 
			
		||||
	.bDataInterface =	0x01,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_cdc_acm_descriptor rndis_acm_descriptor = {
 | 
			
		||||
	.bLength =		sizeof rndis_acm_descriptor,
 | 
			
		||||
static struct usb_cdc_acm_descriptor acm_descriptor __initdata = {
 | 
			
		||||
	.bLength =		sizeof acm_descriptor,
 | 
			
		||||
	.bDescriptorType =	USB_DT_CS_INTERFACE,
 | 
			
		||||
	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
 | 
			
		||||
 | 
			
		||||
	.bmCapabilities =	0x00,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_cdc_union_desc rndis_union_desc = {
 | 
			
		||||
static struct usb_cdc_union_desc rndis_union_desc __initdata = {
 | 
			
		||||
	.bLength =		sizeof(rndis_union_desc),
 | 
			
		||||
	.bDescriptorType =	USB_DT_CS_INTERFACE,
 | 
			
		||||
	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
 | 
			
		||||
@@ -178,7 +175,7 @@ static struct usb_cdc_union_desc rndis_union_desc = {
 | 
			
		||||
 | 
			
		||||
/* the data interface has two bulk endpoints */
 | 
			
		||||
 | 
			
		||||
static struct usb_interface_descriptor rndis_data_intf = {
 | 
			
		||||
static struct usb_interface_descriptor rndis_data_intf __initdata = {
 | 
			
		||||
	.bLength =		sizeof rndis_data_intf,
 | 
			
		||||
	.bDescriptorType =	USB_DT_INTERFACE,
 | 
			
		||||
 | 
			
		||||
@@ -190,23 +187,9 @@ static struct usb_interface_descriptor rndis_data_intf = {
 | 
			
		||||
	/* .iInterface = DYNAMIC */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static struct usb_interface_assoc_descriptor
 | 
			
		||||
rndis_iad_descriptor = {
 | 
			
		||||
	.bLength =		sizeof rndis_iad_descriptor,
 | 
			
		||||
	.bDescriptorType =	USB_DT_INTERFACE_ASSOCIATION,
 | 
			
		||||
 | 
			
		||||
	.bFirstInterface =	0, /* XXX, hardcoded */
 | 
			
		||||
	.bInterfaceCount = 	2,	// control + data
 | 
			
		||||
	.bFunctionClass =	USB_CLASS_COMM,
 | 
			
		||||
	.bFunctionSubClass =	USB_CDC_SUBCLASS_ETHERNET,
 | 
			
		||||
	.bFunctionProtocol =	USB_CDC_PROTO_NONE,
 | 
			
		||||
	/* .iFunction = DYNAMIC */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* full speed support: */
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor fs_notify_desc = {
 | 
			
		||||
static struct usb_endpoint_descriptor fs_notify_desc __initdata = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
 | 
			
		||||
@@ -216,7 +199,7 @@ static struct usb_endpoint_descriptor fs_notify_desc = {
 | 
			
		||||
	.bInterval =		1 << LOG2_STATUS_INTERVAL_MSEC,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor fs_in_desc = {
 | 
			
		||||
static struct usb_endpoint_descriptor fs_in_desc __initdata = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
 | 
			
		||||
@@ -224,7 +207,7 @@ static struct usb_endpoint_descriptor fs_in_desc = {
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor fs_out_desc = {
 | 
			
		||||
static struct usb_endpoint_descriptor fs_out_desc __initdata = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
 | 
			
		||||
@@ -232,13 +215,12 @@ static struct usb_endpoint_descriptor fs_out_desc = {
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_descriptor_header *eth_fs_function[] = {
 | 
			
		||||
	(struct usb_descriptor_header *) &rndis_iad_descriptor,
 | 
			
		||||
static struct usb_descriptor_header *eth_fs_function[] __initdata = {
 | 
			
		||||
	/* control interface matches ACM, not Ethernet */
 | 
			
		||||
	(struct usb_descriptor_header *) &rndis_control_intf,
 | 
			
		||||
	(struct usb_descriptor_header *) &header_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &call_mgmt_descriptor,
 | 
			
		||||
	(struct usb_descriptor_header *) &rndis_acm_descriptor,
 | 
			
		||||
	(struct usb_descriptor_header *) &acm_descriptor,
 | 
			
		||||
	(struct usb_descriptor_header *) &rndis_union_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &fs_notify_desc,
 | 
			
		||||
	/* data interface has no altsetting */
 | 
			
		||||
@@ -250,7 +232,7 @@ static struct usb_descriptor_header *eth_fs_function[] = {
 | 
			
		||||
 | 
			
		||||
/* high speed support: */
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor hs_notify_desc = {
 | 
			
		||||
static struct usb_endpoint_descriptor hs_notify_desc __initdata = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
 | 
			
		||||
@@ -259,7 +241,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = {
 | 
			
		||||
	.wMaxPacketSize =	cpu_to_le16(STATUS_BYTECOUNT),
 | 
			
		||||
	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
 | 
			
		||||
};
 | 
			
		||||
static struct usb_endpoint_descriptor hs_in_desc = {
 | 
			
		||||
static struct usb_endpoint_descriptor hs_in_desc __initdata = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
 | 
			
		||||
@@ -268,7 +250,7 @@ static struct usb_endpoint_descriptor hs_in_desc = {
 | 
			
		||||
	.wMaxPacketSize =	cpu_to_le16(512),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor hs_out_desc = {
 | 
			
		||||
static struct usb_endpoint_descriptor hs_out_desc __initdata = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
 | 
			
		||||
@@ -277,13 +259,12 @@ static struct usb_endpoint_descriptor hs_out_desc = {
 | 
			
		||||
	.wMaxPacketSize =	cpu_to_le16(512),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_descriptor_header *eth_hs_function[] = {
 | 
			
		||||
	(struct usb_descriptor_header *) &rndis_iad_descriptor,
 | 
			
		||||
static struct usb_descriptor_header *eth_hs_function[] __initdata = {
 | 
			
		||||
	/* control interface matches ACM, not Ethernet */
 | 
			
		||||
	(struct usb_descriptor_header *) &rndis_control_intf,
 | 
			
		||||
	(struct usb_descriptor_header *) &header_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &call_mgmt_descriptor,
 | 
			
		||||
	(struct usb_descriptor_header *) &rndis_acm_descriptor,
 | 
			
		||||
	(struct usb_descriptor_header *) &acm_descriptor,
 | 
			
		||||
	(struct usb_descriptor_header *) &rndis_union_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &hs_notify_desc,
 | 
			
		||||
	/* data interface has no altsetting */
 | 
			
		||||
@@ -298,7 +279,6 @@ static struct usb_descriptor_header *eth_hs_function[] = {
 | 
			
		||||
static struct usb_string rndis_string_defs[] = {
 | 
			
		||||
	[0].s = "RNDIS Communications Control",
 | 
			
		||||
	[1].s = "RNDIS Ethernet Data",
 | 
			
		||||
	[2].s = "RNDIS",
 | 
			
		||||
	{  } /* end of list */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -606,7 +586,7 @@ static void rndis_close(struct gether *geth)
 | 
			
		||||
 | 
			
		||||
/* ethernet function driver setup/binding */
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
static int __init
 | 
			
		||||
rndis_bind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_composite_dev *cdev = c->cdev;
 | 
			
		||||
@@ -619,7 +599,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
	if (status < 0)
 | 
			
		||||
		goto fail;
 | 
			
		||||
	rndis->ctrl_id = status;
 | 
			
		||||
	rndis_iad_descriptor.bFirstInterface = status;
 | 
			
		||||
 | 
			
		||||
	rndis_control_intf.bInterfaceNumber = status;
 | 
			
		||||
	rndis_union_desc.bMasterInterface0 = status;
 | 
			
		||||
@@ -783,6 +762,10 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
/* Some controllers can't support RNDIS ... */
 | 
			
		||||
static inline bool can_support_rndis(struct usb_configuration *c)
 | 
			
		||||
{
 | 
			
		||||
	/* only two endpoints on sa1100 */
 | 
			
		||||
	if (gadget_is_sa1100(c->cdev->gadget))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	/* everything else is *presumably* fine */
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
@@ -799,8 +782,7 @@ static inline bool can_support_rndis(struct usb_configuration *c)
 | 
			
		||||
 * Caller must have called @gether_setup().  Caller is also responsible
 | 
			
		||||
 * for calling @gether_cleanup() before module unload.
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
 | 
			
		||||
int __init rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
 | 
			
		||||
{
 | 
			
		||||
	struct f_rndis	*rndis;
 | 
			
		||||
	int		status;
 | 
			
		||||
@@ -829,13 +811,6 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
 | 
			
		||||
			return status;
 | 
			
		||||
		rndis_string_defs[1].id = status;
 | 
			
		||||
		rndis_data_intf.iInterface = status;
 | 
			
		||||
 | 
			
		||||
		/* IAD iFunction label */
 | 
			
		||||
		status = usb_string_id(c->cdev);
 | 
			
		||||
		if (status < 0)
 | 
			
		||||
			return status;
 | 
			
		||||
		rndis_string_defs[2].id = status;
 | 
			
		||||
		rndis_iad_descriptor.iFunction = status;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* allocate and initialize one new instance */
 | 
			
		||||
@@ -865,7 +840,7 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_USB_ANDROID_RNDIS
 | 
			
		||||
	/* start disabled */
 | 
			
		||||
	rndis->port.func.disabled = 1;
 | 
			
		||||
	rndis->port.func.hidden = 1;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	status = usb_add_function(c, &rndis->port.func);
 | 
			
		||||
@@ -880,7 +855,7 @@ fail:
 | 
			
		||||
#ifdef CONFIG_USB_ANDROID_RNDIS
 | 
			
		||||
#include "rndis.c"
 | 
			
		||||
 | 
			
		||||
static int rndis_probe(struct platform_device *pdev)
 | 
			
		||||
static int __init rndis_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	rndis_pdata = pdev->dev.platform_data;
 | 
			
		||||
	return 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -10,14 +10,14 @@
 | 
			
		||||
 * either version 2 of that License or (at your option) any later version.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/device.h>
 | 
			
		||||
#include <linux/usb/android_composite.h>
 | 
			
		||||
 | 
			
		||||
#include "u_serial.h"
 | 
			
		||||
#include "gadget_chips.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define CONFIG_MODEM_SUPPORT
 | 
			
		||||
/*
 | 
			
		||||
 * This function packages a simple "generic serial" port with no real
 | 
			
		||||
 * control mechanisms, just raw data transfer over two bulk endpoints.
 | 
			
		||||
@@ -30,78 +30,187 @@
 | 
			
		||||
struct gser_descs {
 | 
			
		||||
	struct usb_endpoint_descriptor	*in;
 | 
			
		||||
	struct usb_endpoint_descriptor	*out;
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
	struct usb_endpoint_descriptor	*notify;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct f_gser {
 | 
			
		||||
	struct gserial			port;
 | 
			
		||||
	u8				data_id;
 | 
			
		||||
	u8				port_num;
 | 
			
		||||
	u8				disabled;
 | 
			
		||||
	u8				configured;
 | 
			
		||||
 | 
			
		||||
	struct gser_descs		fs;
 | 
			
		||||
	struct gser_descs		hs;
 | 
			
		||||
	u8				online;
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
	u8				pending;
 | 
			
		||||
	spinlock_t			lock;
 | 
			
		||||
	struct usb_ep			*notify;
 | 
			
		||||
	struct usb_endpoint_descriptor	*notify_desc;
 | 
			
		||||
	struct usb_request		*notify_req;
 | 
			
		||||
 | 
			
		||||
	struct usb_cdc_line_coding	port_line_coding;
 | 
			
		||||
 | 
			
		||||
	/* SetControlLineState request */
 | 
			
		||||
	u16				port_handshake_bits;
 | 
			
		||||
#define ACM_CTRL_RTS	(1 << 1)	/* unused with full duplex */
 | 
			
		||||
#define ACM_CTRL_DTR	(1 << 0)	/* host is ready for data r/w */
 | 
			
		||||
 | 
			
		||||
	/* SerialState notification */
 | 
			
		||||
	u16				serial_state;
 | 
			
		||||
#define ACM_CTRL_OVERRUN	(1 << 6)
 | 
			
		||||
#define ACM_CTRL_PARITY		(1 << 5)
 | 
			
		||||
#define ACM_CTRL_FRAMING	(1 << 4)
 | 
			
		||||
#define ACM_CTRL_RI		(1 << 3)
 | 
			
		||||
#define ACM_CTRL_BRK		(1 << 2)
 | 
			
		||||
#define ACM_CTRL_DSR		(1 << 1)
 | 
			
		||||
#define ACM_CTRL_DCD		(1 << 0)
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
static struct usb_function *modem_function;
 | 
			
		||||
static struct usb_function *serial_function;
 | 
			
		||||
 | 
			
		||||
static inline struct f_gser *func_to_gser(struct usb_function *f)
 | 
			
		||||
{
 | 
			
		||||
	return container_of(f, struct f_gser, port.func);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
static inline struct f_gser *port_to_gser(struct gserial *p)
 | 
			
		||||
{
 | 
			
		||||
	return container_of(p, struct f_gser, port);
 | 
			
		||||
}
 | 
			
		||||
#define GS_LOG2_NOTIFY_INTERVAL		5	/* 1 << 5 == 32 msec */
 | 
			
		||||
#define GS_NOTIFY_MAXPACKET		10	/* notification + 2 bytes */
 | 
			
		||||
#endif
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
/* interface descriptor: */
 | 
			
		||||
 | 
			
		||||
static struct usb_interface_descriptor gser_interface_desc __initdata = {
 | 
			
		||||
static struct usb_interface_descriptor gser_interface_desc = {
 | 
			
		||||
	.bLength =		USB_DT_INTERFACE_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_INTERFACE,
 | 
			
		||||
	/* .bInterfaceNumber = DYNAMIC */
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
	.bNumEndpoints =	3,
 | 
			
		||||
#else
 | 
			
		||||
	.bNumEndpoints =	2,
 | 
			
		||||
#endif
 | 
			
		||||
	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
 | 
			
		||||
	.bInterfaceSubClass =	0,
 | 
			
		||||
	.bInterfaceProtocol =	0,
 | 
			
		||||
	/* .iInterface = DYNAMIC */
 | 
			
		||||
};
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
static struct usb_cdc_header_desc gser_header_desc  = {
 | 
			
		||||
	.bLength =		sizeof(gser_header_desc),
 | 
			
		||||
	.bDescriptorType =	USB_DT_CS_INTERFACE,
 | 
			
		||||
	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
 | 
			
		||||
	.bcdCDC =		__constant_cpu_to_le16(0x0110),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_cdc_call_mgmt_descriptor
 | 
			
		||||
gser_call_mgmt_descriptor  = {
 | 
			
		||||
	.bLength =		sizeof(gser_call_mgmt_descriptor),
 | 
			
		||||
	.bDescriptorType =	USB_DT_CS_INTERFACE,
 | 
			
		||||
	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
 | 
			
		||||
	.bmCapabilities =	0,
 | 
			
		||||
	/* .bDataInterface = DYNAMIC */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_cdc_acm_descriptor gser_descriptor  = {
 | 
			
		||||
	.bLength =		sizeof(gser_descriptor),
 | 
			
		||||
	.bDescriptorType =	USB_DT_CS_INTERFACE,
 | 
			
		||||
	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
 | 
			
		||||
	.bmCapabilities =	USB_CDC_CAP_LINE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_cdc_union_desc gser_union_desc  = {
 | 
			
		||||
	.bLength =		sizeof(gser_union_desc),
 | 
			
		||||
	.bDescriptorType =	USB_DT_CS_INTERFACE,
 | 
			
		||||
	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
 | 
			
		||||
	/* .bMasterInterface0 =	DYNAMIC */
 | 
			
		||||
	/* .bSlaveInterface0 =	DYNAMIC */
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
/* full speed support: */
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
static struct usb_endpoint_descriptor gser_fs_notify_desc = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
	.bEndpointAddress =	USB_DIR_IN,
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_INT,
 | 
			
		||||
	.wMaxPacketSize =	__constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
 | 
			
		||||
	.bInterval =		1 << GS_LOG2_NOTIFY_INTERVAL,
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor gser_fs_in_desc __initdata = {
 | 
			
		||||
static struct usb_endpoint_descriptor gser_fs_in_desc  = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
	.bEndpointAddress =	USB_DIR_IN,
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor gser_fs_out_desc __initdata = {
 | 
			
		||||
static struct usb_endpoint_descriptor gser_fs_out_desc = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
	.bEndpointAddress =	USB_DIR_OUT,
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_descriptor_header *gser_fs_function[] __initdata = {
 | 
			
		||||
static struct usb_descriptor_header *gser_fs_function[] = {
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_interface_desc,
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_header_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_descriptor,
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_union_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_fs_notify_desc,
 | 
			
		||||
#endif
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_fs_in_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_fs_out_desc,
 | 
			
		||||
	NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* high speed support: */
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
static struct usb_endpoint_descriptor gser_hs_notify_desc  = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
	.bEndpointAddress =	USB_DIR_IN,
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_INT,
 | 
			
		||||
	.wMaxPacketSize =	__constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
 | 
			
		||||
	.bInterval =		GS_LOG2_NOTIFY_INTERVAL+4,
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor gser_hs_in_desc __initdata = {
 | 
			
		||||
static struct usb_endpoint_descriptor gser_hs_in_desc = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 | 
			
		||||
	.wMaxPacketSize =	cpu_to_le16(512),
 | 
			
		||||
	.wMaxPacketSize =	__constant_cpu_to_le16(512),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor gser_hs_out_desc __initdata = {
 | 
			
		||||
static struct usb_endpoint_descriptor gser_hs_out_desc = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 | 
			
		||||
	.wMaxPacketSize =	cpu_to_le16(512),
 | 
			
		||||
	.wMaxPacketSize =	__constant_cpu_to_le16(512),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_descriptor_header *gser_hs_function[] __initdata = {
 | 
			
		||||
static struct usb_descriptor_header *gser_hs_function[] = {
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_interface_desc,
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_header_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_call_mgmt_descriptor,
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_descriptor,
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_union_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_hs_notify_desc,
 | 
			
		||||
#endif
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_hs_in_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &gser_hs_out_desc,
 | 
			
		||||
	NULL,
 | 
			
		||||
@@ -109,64 +218,365 @@ static struct usb_descriptor_header *gser_hs_function[] __initdata = {
 | 
			
		||||
 | 
			
		||||
/* string descriptors: */
 | 
			
		||||
 | 
			
		||||
static struct usb_string gser_string_defs[] = {
 | 
			
		||||
	[0].s = "Generic Serial",
 | 
			
		||||
static struct usb_string modem_string_defs[] = {
 | 
			
		||||
	[0].s = "HTC Modem",
 | 
			
		||||
	{  } /* end of list */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_gadget_strings gser_string_table = {
 | 
			
		||||
static struct usb_gadget_strings modem_string_table = {
 | 
			
		||||
	.language =		0x0409,	/* en-us */
 | 
			
		||||
	.strings =		gser_string_defs,
 | 
			
		||||
	.strings =		modem_string_defs,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_gadget_strings *gser_strings[] = {
 | 
			
		||||
	&gser_string_table,
 | 
			
		||||
static struct usb_gadget_strings *modem_strings[] = {
 | 
			
		||||
	&modem_string_table,
 | 
			
		||||
	NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
static struct usb_string serial_string_defs[] = {
 | 
			
		||||
	[0].s = "HTC Serial",
 | 
			
		||||
	{  } /* end of list */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_gadget_strings serial_string_table = {
 | 
			
		||||
	.language =		0x0409,	/* en-us */
 | 
			
		||||
	.strings =		serial_string_defs,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_gadget_strings *serial_strings[] = {
 | 
			
		||||
	&serial_string_table,
 | 
			
		||||
	NULL,
 | 
			
		||||
};
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
static void gser_complete_set_line_coding(struct usb_ep *ep,
 | 
			
		||||
		struct usb_request *req)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser            *gser = ep->driver_data;
 | 
			
		||||
	struct usb_composite_dev *cdev = gser->port.func.config->cdev;
 | 
			
		||||
 | 
			
		||||
	if (req->status != 0) {
 | 
			
		||||
		DBG(cdev, "gser ttyGS%d completion, err %d\n",
 | 
			
		||||
				gser->port_num, req->status);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* normal completion */
 | 
			
		||||
	if (req->actual != sizeof(gser->port_line_coding)) {
 | 
			
		||||
		DBG(cdev, "gser ttyGS%d short resp, len %d\n",
 | 
			
		||||
				gser->port_num, req->actual);
 | 
			
		||||
		usb_ep_set_halt(ep);
 | 
			
		||||
	} else {
 | 
			
		||||
		struct usb_cdc_line_coding	*value = req->buf;
 | 
			
		||||
		gser->port_line_coding = *value;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
static int
 | 
			
		||||
gser_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser            *gser = func_to_gser(f);
 | 
			
		||||
	struct usb_composite_dev *cdev = f->config->cdev;
 | 
			
		||||
	struct usb_request	 *req = cdev->req;
 | 
			
		||||
	int			 value = -EOPNOTSUPP;
 | 
			
		||||
	u16			 w_index = le16_to_cpu(ctrl->wIndex);
 | 
			
		||||
	u16			 w_value = le16_to_cpu(ctrl->wValue);
 | 
			
		||||
	u16			 w_length = le16_to_cpu(ctrl->wLength);
 | 
			
		||||
 | 
			
		||||
	switch ((ctrl->bRequestType << 8) | ctrl->bRequest) {
 | 
			
		||||
 | 
			
		||||
	/* SET_LINE_CODING ... just read and save what the host sends */
 | 
			
		||||
	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 | 
			
		||||
			| USB_CDC_REQ_SET_LINE_CODING:
 | 
			
		||||
		if (w_length != sizeof(struct usb_cdc_line_coding)
 | 
			
		||||
				|| w_index != gser->data_id)
 | 
			
		||||
			goto invalid;
 | 
			
		||||
		value = w_length;
 | 
			
		||||
		cdev->gadget->ep0->driver_data = gser;
 | 
			
		||||
		req->complete = gser_complete_set_line_coding;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	/* GET_LINE_CODING ... return what host sent, or initial value */
 | 
			
		||||
	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 | 
			
		||||
			| USB_CDC_REQ_GET_LINE_CODING:
 | 
			
		||||
		if (w_index != gser->data_id)
 | 
			
		||||
			goto invalid;
 | 
			
		||||
 | 
			
		||||
		value = min_t(unsigned, w_length,
 | 
			
		||||
				sizeof(struct usb_cdc_line_coding));
 | 
			
		||||
		memcpy(req->buf, &gser->port_line_coding, value);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	/* SET_CONTROL_LINE_STATE ... save what the host sent */
 | 
			
		||||
	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8)
 | 
			
		||||
			| USB_CDC_REQ_SET_CONTROL_LINE_STATE:
 | 
			
		||||
		if (w_index != gser->data_id)
 | 
			
		||||
			goto invalid;
 | 
			
		||||
 | 
			
		||||
		value = 0;
 | 
			
		||||
		gser->port_handshake_bits = w_value;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
invalid:
 | 
			
		||||
		ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
 | 
			
		||||
			ctrl->bRequestType, ctrl->bRequest,
 | 
			
		||||
			w_value, w_index, w_length);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* respond with data transfer or status phase? */
 | 
			
		||||
	if (value >= 0) {
 | 
			
		||||
		DBG(cdev, "gser ttyGS%d req%02x.%02x v%04x i%04x l%d\n",
 | 
			
		||||
			gser->port_num, ctrl->bRequestType, ctrl->bRequest,
 | 
			
		||||
			w_value, w_index, w_length);
 | 
			
		||||
		req->zero = 0;
 | 
			
		||||
		req->length = value;
 | 
			
		||||
		value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
 | 
			
		||||
		if (value < 0)
 | 
			
		||||
			ERROR(cdev, "gser response on ttyGS%d, err %d\n",
 | 
			
		||||
					gser->port_num, value);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* device either stalls (value < 0) or reports success */
 | 
			
		||||
	return value;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser		*gser = func_to_gser(f);
 | 
			
		||||
	struct f_gser		 *gser = func_to_gser(f);
 | 
			
		||||
	struct usb_composite_dev *cdev = f->config->cdev;
 | 
			
		||||
	struct usb_interface_descriptor *desc;
 | 
			
		||||
 | 
			
		||||
	/* we know alt == 0, so this is an activation or a reset */
 | 
			
		||||
	if (cdev->gadget->speed == USB_SPEED_HIGH)
 | 
			
		||||
		desc = (struct usb_interface_descriptor *) *(f->hs_descriptors);
 | 
			
		||||
	else
 | 
			
		||||
		desc = (struct usb_interface_descriptor *) *(f->descriptors);
 | 
			
		||||
	gser->data_id = desc->bInterfaceNumber;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
#if 0
 | 
			
		||||
	if (gser->notify->driver_data) {
 | 
			
		||||
		DBG(cdev, "reset generic ttyGS%d\n", gser->port_num);
 | 
			
		||||
		usb_ep_disable(gser->notify);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	gser->notify_desc = ep_choose(cdev->gadget,
 | 
			
		||||
			gser->hs.notify,
 | 
			
		||||
			gser->fs.notify);
 | 
			
		||||
	usb_ep_enable(gser->notify, gser->notify_desc);
 | 
			
		||||
	gser->notify->driver_data = gser;
 | 
			
		||||
#endif
 | 
			
		||||
#if 0
 | 
			
		||||
	if (gser->port.in->driver_data) {
 | 
			
		||||
		DBG(cdev, "reset generic ttyGS%d\n", gser->port_num);
 | 
			
		||||
		gserial_disconnect(&gser->port);
 | 
			
		||||
	} else {
 | 
			
		||||
		DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
 | 
			
		||||
		gser->port.in_desc = ep_choose(cdev->gadget,
 | 
			
		||||
				gser->hs.in, gser->fs.in);
 | 
			
		||||
		gser->port.out_desc = ep_choose(cdev->gadget,
 | 
			
		||||
				gser->hs.out, gser->fs.out);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	gser->port.in_desc = ep_choose(cdev->gadget,
 | 
			
		||||
			gser->hs.in, gser->fs.in);
 | 
			
		||||
	gser->port.out_desc = ep_choose(cdev->gadget,
 | 
			
		||||
			gser->hs.out, gser->fs.out);
 | 
			
		||||
	gserial_connect(&gser->port, gser->port_num);
 | 
			
		||||
	gser->online = 1;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gser_disable(struct usb_function *f)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser	*gser = func_to_gser(f);
 | 
			
		||||
	struct f_gser	         *gser = func_to_gser(f);
 | 
			
		||||
	struct usb_composite_dev *cdev = f->config->cdev;
 | 
			
		||||
 | 
			
		||||
	DBG(cdev, "generic ttyGS%d deactivated\n", gser->port_num);
 | 
			
		||||
	gserial_disconnect(&gser->port);
 | 
			
		||||
#if 0
 | 
			
		||||
	/* disable endpoints, aborting down any active I/O */
 | 
			
		||||
	usb_ep_fifo_flush(gser->port.out);
 | 
			
		||||
	usb_ep_disable(gser->port.out);
 | 
			
		||||
	gser->port.out->driver_data = NULL;
 | 
			
		||||
 | 
			
		||||
	usb_ep_fifo_flush(gser->port.in);
 | 
			
		||||
	usb_ep_disable(gser->port.in);
 | 
			
		||||
	gser->port.in->driver_data = NULL;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
	usb_ep_fifo_flush(gser->notify);
 | 
			
		||||
	usb_ep_disable(gser->notify);
 | 
			
		||||
	gser->notify->driver_data = NULL;
 | 
			
		||||
#endif
 | 
			
		||||
	gser->online = 0;
 | 
			
		||||
}
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
static int gser_notify(struct f_gser *gser, u8 type, u16 value,
 | 
			
		||||
		void *data, unsigned length)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_ep			*ep = gser->notify;
 | 
			
		||||
	struct usb_request		*req;
 | 
			
		||||
	struct usb_cdc_notification	*notify;
 | 
			
		||||
	const unsigned			len = sizeof(*notify) + length;
 | 
			
		||||
	void				*buf;
 | 
			
		||||
	int				status;
 | 
			
		||||
	struct usb_composite_dev *cdev = gser->port.func.config->cdev;
 | 
			
		||||
 | 
			
		||||
	req = gser->notify_req;
 | 
			
		||||
	gser->notify_req = NULL;
 | 
			
		||||
	gser->pending = false;
 | 
			
		||||
 | 
			
		||||
	req->length = len;
 | 
			
		||||
	notify = req->buf;
 | 
			
		||||
	buf = notify + 1;
 | 
			
		||||
 | 
			
		||||
	notify->bmRequestType = USB_DIR_IN | USB_TYPE_CLASS
 | 
			
		||||
			| USB_RECIP_INTERFACE;
 | 
			
		||||
	notify->bNotificationType = type;
 | 
			
		||||
	notify->wValue = cpu_to_le16(value);
 | 
			
		||||
	notify->wIndex = cpu_to_le16(gser->data_id);
 | 
			
		||||
	notify->wLength = cpu_to_le16(length);
 | 
			
		||||
	memcpy(buf, data, length);
 | 
			
		||||
 | 
			
		||||
	status = usb_ep_queue(ep, req, GFP_ATOMIC);
 | 
			
		||||
	if (status < 0) {
 | 
			
		||||
		ERROR(cdev, "gser ttyGS%d can't notify serial state, %d\n",
 | 
			
		||||
				gser->port_num, status);
 | 
			
		||||
		gser->notify_req = req;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gser_notify_serial_state(struct f_gser *gser)
 | 
			
		||||
{
 | 
			
		||||
	int			 status;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	struct usb_composite_dev *cdev = gser->port.func.config->cdev;
 | 
			
		||||
	if (gser->disabled)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&gser->lock, flags);
 | 
			
		||||
	if (gser->notify_req) {
 | 
			
		||||
		DBG(cdev, "gser ttyGS%d serial state %04x\n",
 | 
			
		||||
				gser->port_num, gser->serial_state);
 | 
			
		||||
		status = gser_notify(gser, USB_CDC_NOTIFY_SERIAL_STATE,
 | 
			
		||||
				0, &gser->serial_state,
 | 
			
		||||
					sizeof(gser->serial_state));
 | 
			
		||||
	} else {
 | 
			
		||||
		gser->pending = true;
 | 
			
		||||
		status = 0;
 | 
			
		||||
	}
 | 
			
		||||
	spin_unlock_irqrestore(&gser->lock, flags);
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void gser_notify_complete(struct usb_ep *ep, struct usb_request *req)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser *gser = req->context;
 | 
			
		||||
	u8	      doit = false;
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
 | 
			
		||||
	/* on this call path we do NOT hold the port spinlock,
 | 
			
		||||
	 * which is why ACM needs its own spinlock
 | 
			
		||||
	 */
 | 
			
		||||
	spin_lock_irqsave(&gser->lock, flags);
 | 
			
		||||
	if (req->status != -ESHUTDOWN)
 | 
			
		||||
		doit = gser->pending;
 | 
			
		||||
	gser->notify_req = req;
 | 
			
		||||
	spin_unlock_irqrestore(&gser->lock, flags);
 | 
			
		||||
 | 
			
		||||
	if (doit && gser->online)
 | 
			
		||||
		gser_notify_serial_state(gser);
 | 
			
		||||
}
 | 
			
		||||
static void gser_connect(struct gserial *port)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser *gser = port_to_gser(port);
 | 
			
		||||
 | 
			
		||||
	gser->serial_state |= ACM_CTRL_DSR | ACM_CTRL_DCD;
 | 
			
		||||
	gser_notify_serial_state(gser);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int gser_get_dtr(struct gserial *port)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser *gser = port_to_gser(port);
 | 
			
		||||
 | 
			
		||||
	if (gser->port_handshake_bits & ACM_CTRL_DTR)
 | 
			
		||||
		return 1;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int gser_get_rts(struct gserial *port)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser *gser = port_to_gser(port);
 | 
			
		||||
 | 
			
		||||
	if (gser->port_handshake_bits & ACM_CTRL_RTS)
 | 
			
		||||
		return 1;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int gser_send_carrier_detect(struct gserial *port, unsigned int yes)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser *gser = port_to_gser(port);
 | 
			
		||||
	u16			state;
 | 
			
		||||
 | 
			
		||||
	state = gser->serial_state;
 | 
			
		||||
	state &= ~ACM_CTRL_DCD;
 | 
			
		||||
	if (yes)
 | 
			
		||||
		state |= ACM_CTRL_DCD;
 | 
			
		||||
 | 
			
		||||
	gser->serial_state = state;
 | 
			
		||||
	return gser_notify_serial_state(gser);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned int gser_send_ring_indicator(struct gserial *port, unsigned int yes)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser *gser = port_to_gser(port);
 | 
			
		||||
	u16			state;
 | 
			
		||||
 | 
			
		||||
	state = gser->serial_state;
 | 
			
		||||
	state &= ~ACM_CTRL_RI;
 | 
			
		||||
	if (yes)
 | 
			
		||||
		state |= ACM_CTRL_RI;
 | 
			
		||||
 | 
			
		||||
	gser->serial_state = state;
 | 
			
		||||
	return gser_notify_serial_state(gser);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
static void gser_disconnect(struct gserial *port)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser *gser = port_to_gser(port);
 | 
			
		||||
 | 
			
		||||
	gser->serial_state &= ~(ACM_CTRL_DSR | ACM_CTRL_DCD);
 | 
			
		||||
	gser_notify_serial_state(gser);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int gser_send_break(struct gserial *port, int duration)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser *gser = port_to_gser(port);
 | 
			
		||||
	u16			state;
 | 
			
		||||
 | 
			
		||||
	state = gser->serial_state;
 | 
			
		||||
	state &= ~ACM_CTRL_BRK;
 | 
			
		||||
	if (duration)
 | 
			
		||||
		state |= ACM_CTRL_BRK;
 | 
			
		||||
 | 
			
		||||
	gser->serial_state = state;
 | 
			
		||||
	return gser_notify_serial_state(gser);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
/* serial function driver setup/binding */
 | 
			
		||||
 | 
			
		||||
static int __init
 | 
			
		||||
static int
 | 
			
		||||
gser_bind(struct usb_configuration *c, 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;
 | 
			
		||||
	struct f_gser            *gser = func_to_gser(f);
 | 
			
		||||
	int			 status;
 | 
			
		||||
	struct usb_ep		 *ep;
 | 
			
		||||
	struct usb_gadget_strings	*s;
 | 
			
		||||
 | 
			
		||||
	/* allocate instance-specific interface IDs */
 | 
			
		||||
	status = usb_interface_id(c, f);
 | 
			
		||||
@@ -174,6 +584,10 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
		goto fail;
 | 
			
		||||
	gser->data_id = status;
 | 
			
		||||
	gser_interface_desc.bInterfaceNumber = status;
 | 
			
		||||
	if (f->strings) {
 | 
			
		||||
		s = *(f->strings);
 | 
			
		||||
		gser_interface_desc.iInterface = s->strings[0].id;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	status = -ENODEV;
 | 
			
		||||
 | 
			
		||||
@@ -182,13 +596,30 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
	if (!ep)
 | 
			
		||||
		goto fail;
 | 
			
		||||
	gser->port.in = ep;
 | 
			
		||||
	ep->driver_data = cdev;	/* claim */
 | 
			
		||||
	ep->driver_data = gser;	/* claim */
 | 
			
		||||
 | 
			
		||||
	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_out_desc);
 | 
			
		||||
	if (!ep)
 | 
			
		||||
		goto fail;
 | 
			
		||||
	gser->port.out = ep;
 | 
			
		||||
	ep->driver_data = cdev;	/* claim */
 | 
			
		||||
	ep->driver_data = gser;	/* claim */
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
	ep = usb_ep_autoconfig(cdev->gadget, &gser_fs_notify_desc);
 | 
			
		||||
	if (!ep)
 | 
			
		||||
		goto fail;
 | 
			
		||||
	gser->notify = ep;
 | 
			
		||||
	ep->driver_data = gser;	/* claim */
 | 
			
		||||
	/* allocate notification */
 | 
			
		||||
	gser->notify_req = gs_alloc_req(ep,
 | 
			
		||||
			sizeof(struct usb_cdc_notification) + 2,
 | 
			
		||||
			GFP_KERNEL);
 | 
			
		||||
	if (!gser->notify_req)
 | 
			
		||||
		goto fail;
 | 
			
		||||
 | 
			
		||||
	gser->notify_req->complete = gser_notify_complete;
 | 
			
		||||
	gser->notify_req->context = gser;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* copy descriptors, and track endpoint copies */
 | 
			
		||||
	f->descriptors = usb_copy_descriptors(gser_fs_function);
 | 
			
		||||
@@ -197,6 +628,10 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
			f->descriptors, &gser_fs_in_desc);
 | 
			
		||||
	gser->fs.out = usb_find_endpoint(gser_fs_function,
 | 
			
		||||
			f->descriptors, &gser_fs_out_desc);
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
	gser->fs.notify = usb_find_endpoint(gser_fs_function,
 | 
			
		||||
			f->descriptors, &gser_fs_notify_desc);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* support all relevant hardware speeds... we expect that when
 | 
			
		||||
@@ -208,6 +643,10 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
				gser_fs_in_desc.bEndpointAddress;
 | 
			
		||||
		gser_hs_out_desc.bEndpointAddress =
 | 
			
		||||
				gser_fs_out_desc.bEndpointAddress;
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
		gser_hs_notify_desc.bEndpointAddress =
 | 
			
		||||
				gser_fs_notify_desc.bEndpointAddress;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		/* copy descriptors, and track endpoint copies */
 | 
			
		||||
		f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
 | 
			
		||||
@@ -216,6 +655,10 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
				f->hs_descriptors, &gser_hs_in_desc);
 | 
			
		||||
		gser->hs.out = usb_find_endpoint(gser_hs_function,
 | 
			
		||||
				f->hs_descriptors, &gser_hs_out_desc);
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
		gser->hs.notify = usb_find_endpoint(gser_hs_function,
 | 
			
		||||
				f->hs_descriptors, &gser_hs_notify_desc);
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
 | 
			
		||||
@@ -225,6 +668,14 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
	if (gser->notify_req)
 | 
			
		||||
		gs_free_req(gser->notify, gser->notify_req);
 | 
			
		||||
 | 
			
		||||
	/* we might as well release our claims on endpoints */
 | 
			
		||||
	if (gser->notify)
 | 
			
		||||
		gser->notify->driver_data = NULL;
 | 
			
		||||
#endif
 | 
			
		||||
	/* we might as well release our claims on endpoints */
 | 
			
		||||
	if (gser->port.out)
 | 
			
		||||
		gser->port.out->driver_data = NULL;
 | 
			
		||||
@@ -239,9 +690,15 @@ fail:
 | 
			
		||||
static void
 | 
			
		||||
gser_unbind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
{
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
	struct f_gser *gser = func_to_gser(f);
 | 
			
		||||
#endif
 | 
			
		||||
	if (gadget_is_dualspeed(c->cdev->gadget))
 | 
			
		||||
		usb_free_descriptors(f->hs_descriptors);
 | 
			
		||||
	usb_free_descriptors(f->descriptors);
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
	gs_free_req(gser->notify, gser->notify_req);
 | 
			
		||||
#endif
 | 
			
		||||
	kfree(func_to_gser(f));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -257,9 +714,9 @@ gser_unbind(struct usb_configuration *c, struct usb_function *f)
 | 
			
		||||
 * handle all the ones it binds.  Caller is also responsible
 | 
			
		||||
 * for calling @gserial_cleanup() before module unload.
 | 
			
		||||
 */
 | 
			
		||||
int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
 | 
			
		||||
int gser_bind_config(struct usb_configuration *c, u8 port_num)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser	*gser;
 | 
			
		||||
	struct f_gser *gser;
 | 
			
		||||
	int		status;
 | 
			
		||||
 | 
			
		||||
	/* REVISIT might want instance-specific strings to help
 | 
			
		||||
@@ -267,29 +724,129 @@ int __init gser_bind_config(struct usb_configuration *c, u8 port_num)
 | 
			
		||||
	 */
 | 
			
		||||
 | 
			
		||||
	/* maybe allocate device-global string ID */
 | 
			
		||||
	if (gser_string_defs[0].id == 0) {
 | 
			
		||||
	if (modem_string_defs[0].id == 0 && port_num == 0) {
 | 
			
		||||
		status = usb_string_id(c->cdev);
 | 
			
		||||
		if (status < 0)
 | 
			
		||||
		if (status < 0) {
 | 
			
		||||
			printk(KERN_ERR "%s: return %d\n", __func__, status);
 | 
			
		||||
			return status;
 | 
			
		||||
		gser_string_defs[0].id = status;
 | 
			
		||||
		}
 | 
			
		||||
		modem_string_defs[0].id = status;
 | 
			
		||||
	}
 | 
			
		||||
	if (serial_string_defs[0].id == 0 && port_num == 2) {
 | 
			
		||||
		status = usb_string_id(c->cdev);
 | 
			
		||||
		if (status < 0) {
 | 
			
		||||
			printk(KERN_ERR "%s: return %d\n", __func__, status);
 | 
			
		||||
			return status;
 | 
			
		||||
		}
 | 
			
		||||
		serial_string_defs[0].id = status;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* allocate and initialize one new instance */
 | 
			
		||||
	gser = kzalloc(sizeof *gser, GFP_KERNEL);
 | 
			
		||||
	if (!gser)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
	spin_lock_init(&gser->lock);
 | 
			
		||||
#endif
 | 
			
		||||
	gser->port_num = port_num;
 | 
			
		||||
 | 
			
		||||
	gser->port.func.name = "gser";
 | 
			
		||||
	gser->port.func.strings = gser_strings;
 | 
			
		||||
	if (port_num == 0) {
 | 
			
		||||
		gser->port.func.name = "modem";
 | 
			
		||||
		gser->port.func.strings = modem_strings;
 | 
			
		||||
		modem_function = &gser->port.func;
 | 
			
		||||
	} else if (port_num == 2) {
 | 
			
		||||
		gser->port.func.name = "serial";
 | 
			
		||||
		gser->port.func.strings = serial_strings;
 | 
			
		||||
		serial_function = &gser->port.func;
 | 
			
		||||
	}
 | 
			
		||||
	gser->port.func.bind = gser_bind;
 | 
			
		||||
	gser->port.func.unbind = gser_unbind;
 | 
			
		||||
	gser->port.func.set_alt = gser_set_alt;
 | 
			
		||||
	gser->port.func.disable = gser_disable;
 | 
			
		||||
#ifdef CONFIG_MODEM_SUPPORT
 | 
			
		||||
	gser->port.func.setup = gser_setup;
 | 
			
		||||
	gser->port.connect = gser_connect;
 | 
			
		||||
	gser->port.get_dtr = gser_get_dtr;
 | 
			
		||||
	gser->port.get_rts = gser_get_rts;
 | 
			
		||||
	gser->port.send_carrier_detect = gser_send_carrier_detect;
 | 
			
		||||
	gser->port.send_ring_indicator = gser_send_ring_indicator;
 | 
			
		||||
	gser->port.disconnect = gser_disconnect;
 | 
			
		||||
	gser->port.send_break = gser_send_break;
 | 
			
		||||
#endif
 | 
			
		||||
	gser->port.func.hidden = 1;
 | 
			
		||||
	gser->disabled = 1;
 | 
			
		||||
 | 
			
		||||
	status = usb_add_function(c, &gser->port.func);
 | 
			
		||||
	if (status)
 | 
			
		||||
		kfree(gser);
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int modem_set_enabled(const char *val, struct kernel_param *kp)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser *gser;
 | 
			
		||||
	int enabled = simple_strtol(val, NULL, 0);
 | 
			
		||||
	printk(KERN_INFO "%s: %d\n", __func__, enabled);
 | 
			
		||||
	gser = func_to_gser(modem_function);
 | 
			
		||||
	if (!gser)
 | 
			
		||||
		return 0;
 | 
			
		||||
	gser->disabled = !enabled;
 | 
			
		||||
	android_enable_function(modem_function, enabled);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int modem_get_enabled(char *buffer, struct kernel_param *kp)
 | 
			
		||||
{
 | 
			
		||||
	buffer[0] = '0' + !modem_function->hidden;
 | 
			
		||||
	printk(KERN_INFO "%s: %d\n", __func__, buffer[0] - '0');
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
module_param_call(modem_enabled, modem_set_enabled, modem_get_enabled, NULL, 0664);
 | 
			
		||||
 | 
			
		||||
static int serial_set_enabled(const char *val, struct kernel_param *kp)
 | 
			
		||||
{
 | 
			
		||||
	struct f_gser *gser;
 | 
			
		||||
	int enabled = simple_strtol(val, NULL, 0);
 | 
			
		||||
	printk(KERN_INFO "%s: %d\n", __func__, enabled);
 | 
			
		||||
	gser = func_to_gser(serial_function);
 | 
			
		||||
	if (!gser)
 | 
			
		||||
		return 0;
 | 
			
		||||
	gser->disabled = !enabled;
 | 
			
		||||
	android_enable_function(serial_function, enabled);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int serial_get_enabled(char *buffer, struct kernel_param *kp)
 | 
			
		||||
{
 | 
			
		||||
	buffer[0] = '0' + !serial_function->hidden;
 | 
			
		||||
	printk(KERN_INFO "%s: %d\n", __func__, buffer[0] - '0');
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
module_param_call(serial_enabled, serial_set_enabled, serial_get_enabled, NULL, 0664);
 | 
			
		||||
 | 
			
		||||
static int serial_bind_config(struct usb_configuration *c)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	printk(KERN_INFO "serial_bind_config\n");
 | 
			
		||||
	ret = gser_bind_config(c, 0);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
	ret = gser_bind_config(c, 2);
 | 
			
		||||
	if (ret == 0)
 | 
			
		||||
		gserial_setup(c->cdev->gadget, 3);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct android_usb_function android_serial_function = {
 | 
			
		||||
	.name = "serial",
 | 
			
		||||
	.bind_config = serial_bind_config,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int __init init(void)
 | 
			
		||||
{
 | 
			
		||||
	printk(KERN_INFO "serial init\n");
 | 
			
		||||
	android_register_function(&android_serial_function);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
module_init(init);
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,6 @@
 | 
			
		||||
#ifdef CONFIG_USB_ACCESSORY_DETECT_BY_ADC
 | 
			
		||||
#include <mach/htc_headset_mgr.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <mach/clk.h>
 | 
			
		||||
 | 
			
		||||
static const char driver_name[] = "msm72k_udc";
 | 
			
		||||
 | 
			
		||||
@@ -82,14 +81,11 @@ static struct usb_info *the_usb_info;
 | 
			
		||||
static int vbus;
 | 
			
		||||
static int use_mfg_serialno;
 | 
			
		||||
static char mfg_df_serialno[16];
 | 
			
		||||
static int disable_charger;
 | 
			
		||||
 | 
			
		||||
#if defined (CONFIG_DOCK_ACCESSORY_DETECT) || defined(CONFIG_USB_ACCESSORY_DETECT)
 | 
			
		||||
#ifdef CONFIG_USB_ACCESSORY_DETECT
 | 
			
		||||
#ifdef CONFIG_USB_ACCESSORY_DETECT_BY_ADC
 | 
			
		||||
extern int htc_get_usb_accessory_adc_level(uint32_t *buffer);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static struct switch_dev dock_switch = {
 | 
			
		||||
	.name = "dock",
 | 
			
		||||
};
 | 
			
		||||
@@ -99,12 +95,6 @@ static struct switch_dev dock_switch = {
 | 
			
		||||
#define DOCK_STATE_CAR          (1 << 1)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <linux/wakelock.h>
 | 
			
		||||
#include <mach/perflock.h>
 | 
			
		||||
 | 
			
		||||
static struct wake_lock vbus_idle_wake_lock;
 | 
			
		||||
static struct perf_lock usb_perf_lock;
 | 
			
		||||
 | 
			
		||||
struct msm_request {
 | 
			
		||||
	struct usb_request req;
 | 
			
		||||
 | 
			
		||||
@@ -152,10 +142,8 @@ static void check_charger(struct work_struct *w);
 | 
			
		||||
#ifdef CONFIG_USB_ACCESSORY_DETECT
 | 
			
		||||
static void accessory_detect_work(struct work_struct *w);
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CONFIG_DOCK_ACCESSORY_DETECT
 | 
			
		||||
static void dock_detect_work(struct work_struct *w);
 | 
			
		||||
static void dock_detect_init(struct usb_info *ui);
 | 
			
		||||
#endif
 | 
			
		||||
extern int android_switch_function(unsigned func);
 | 
			
		||||
extern int android_show_function(char *buf);
 | 
			
		||||
extern void android_set_serialno(char *serialno);
 | 
			
		||||
 | 
			
		||||
#define USB_STATE_IDLE    0
 | 
			
		||||
@@ -212,10 +200,6 @@ struct usb_info {
 | 
			
		||||
	void (*phy_reset)(void);
 | 
			
		||||
	void (*hw_reset)(bool en);
 | 
			
		||||
	void (*usb_uart_switch)(int);
 | 
			
		||||
	void (*serial_debug_gpios)(int);
 | 
			
		||||
	void (*usb_hub_enable)(bool);
 | 
			
		||||
	int (*china_ac_detect)(void);
 | 
			
		||||
	void (*disable_usb_charger)(void);
 | 
			
		||||
 | 
			
		||||
	/* for notification when USB is connected or disconnected */
 | 
			
		||||
	void (*usb_connected)(int);
 | 
			
		||||
@@ -224,7 +208,6 @@ struct usb_info {
 | 
			
		||||
	struct work_struct work;
 | 
			
		||||
	struct delayed_work chg_work;
 | 
			
		||||
	struct work_struct detect_work;
 | 
			
		||||
	struct work_struct dock_work;
 | 
			
		||||
	struct work_struct notifier_work;
 | 
			
		||||
	unsigned phy_status;
 | 
			
		||||
	unsigned phy_fail_count;
 | 
			
		||||
@@ -249,13 +232,10 @@ struct usb_info {
 | 
			
		||||
	u8 in_lpm;
 | 
			
		||||
 | 
			
		||||
	/* for accessory detection */
 | 
			
		||||
	bool dock_detect;
 | 
			
		||||
	u8 accessory_detect;
 | 
			
		||||
	u8 mfg_usb_carkit_enable;
 | 
			
		||||
	int idpin_irq;
 | 
			
		||||
	int dockpin_irq;
 | 
			
		||||
	int usb_id_pin_gpio;
 | 
			
		||||
	int dock_pin_gpio;
 | 
			
		||||
	void (*config_usb_id_gpios)(bool output_enable);
 | 
			
		||||
	/* 0: none, 1: carkit, 2: usb headset */
 | 
			
		||||
	u8 accessory_type;
 | 
			
		||||
@@ -346,7 +326,7 @@ static int ulpi_write(struct usb_info *ui, unsigned val, unsigned reg)
 | 
			
		||||
	       USB_ULPI_VIEWPORT);
 | 
			
		||||
 | 
			
		||||
	/* wait for completion */
 | 
			
		||||
	while ((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout)) ;
 | 
			
		||||
	while((readl(USB_ULPI_VIEWPORT) & ULPI_RUN) && (--timeout)) ;
 | 
			
		||||
 | 
			
		||||
	if (timeout == 0) {
 | 
			
		||||
		printk(KERN_ERR "ulpi_write: timeout\n");
 | 
			
		||||
@@ -533,8 +513,6 @@ static void usb_ept_start(struct msm_endpoint *ept)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_info *ui = ept->ui;
 | 
			
		||||
	struct msm_request *req = ept->req;
 | 
			
		||||
	int i, cnt;
 | 
			
		||||
	unsigned n = 1 << ept->bit;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(req->live);
 | 
			
		||||
 | 
			
		||||
@@ -542,36 +520,14 @@ static void usb_ept_start(struct msm_endpoint *ept)
 | 
			
		||||
	ept->head->next = req->item_dma;
 | 
			
		||||
	ept->head->info = 0;
 | 
			
		||||
 | 
			
		||||
	/* during high throughput testing it is observed that
 | 
			
		||||
	 * ept stat bit is not set even thoguh all the data
 | 
			
		||||
	 * structures are updated properly and ept prime bit
 | 
			
		||||
	 * is set. To workaround the issue, try to check if
 | 
			
		||||
	 * ept stat bit otherwise try to re-prime the ept
 | 
			
		||||
	 */
 | 
			
		||||
	for (i = 0; i < 5; i++) {
 | 
			
		||||
		writel(n, USB_ENDPTPRIME);
 | 
			
		||||
		for (cnt = 0; cnt < 3000; cnt++) {
 | 
			
		||||
			if (!(readl(USB_ENDPTPRIME) & n) &&
 | 
			
		||||
					(readl(USB_ENDPTSTAT) & n))
 | 
			
		||||
				goto DONE;
 | 
			
		||||
			udelay(1);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	/* start the endpoint */
 | 
			
		||||
	writel(1 << ept->bit, USB_ENDPTPRIME);
 | 
			
		||||
 | 
			
		||||
	if (!(readl(USB_ENDPTSTAT) & n)) {
 | 
			
		||||
		pr_err("Unable to prime the ept%d%s\n",
 | 
			
		||||
				ept->num,
 | 
			
		||||
				ept->flags & EPT_FLAG_IN ? "in" : "out");
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
DONE:
 | 
			
		||||
	/* mark this chain of requests as live */
 | 
			
		||||
	while (req) {
 | 
			
		||||
		req->live = 1;
 | 
			
		||||
		req = req->next;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int usb_ept_queue_xfer(struct msm_endpoint *ept, struct usb_request *_req)
 | 
			
		||||
@@ -801,6 +757,7 @@ static void handle_setup(struct usb_info *ui)
 | 
			
		||||
			{
 | 
			
		||||
				u16 temp = 0;
 | 
			
		||||
 | 
			
		||||
				temp = 1 << USB_DEVICE_SELF_POWERED;
 | 
			
		||||
				temp |= (ui->remote_wakeup <<
 | 
			
		||||
						USB_DEVICE_REMOTE_WAKEUP);
 | 
			
		||||
				memcpy(req->buf, &temp, 2);
 | 
			
		||||
@@ -855,10 +812,6 @@ static void handle_setup(struct usb_info *ui)
 | 
			
		||||
				case J_TEST:
 | 
			
		||||
				case K_TEST:
 | 
			
		||||
				case SE0_NAK_TEST:
 | 
			
		||||
					if (!ui->test_mode) {
 | 
			
		||||
						disable_charger = 1;
 | 
			
		||||
						queue_delayed_work(ui->usb_wq, &ui->chg_work, 0);
 | 
			
		||||
					}
 | 
			
		||||
				case TST_PKT_TEST:
 | 
			
		||||
					ui->test_mode = ctl.wIndex;
 | 
			
		||||
					goto ack;
 | 
			
		||||
@@ -1160,6 +1113,30 @@ static ssize_t show_usb_cable_connect(struct device *dev,
 | 
			
		||||
 | 
			
		||||
static DEVICE_ATTR(usb_cable_connect, 0444, show_usb_cable_connect, NULL);
 | 
			
		||||
 | 
			
		||||
static ssize_t show_usb_function_switch(struct device *dev,
 | 
			
		||||
		struct device_attribute *attr, char *buf)
 | 
			
		||||
{
 | 
			
		||||
	return android_show_function(buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t store_usb_function_switch(struct device *dev,
 | 
			
		||||
	struct device_attribute *attr, const char *buf, size_t count)
 | 
			
		||||
{
 | 
			
		||||
	unsigned u;
 | 
			
		||||
	ssize_t  ret;
 | 
			
		||||
 | 
			
		||||
	u = simple_strtoul(buf, NULL, 10);
 | 
			
		||||
	ret = android_switch_function(u);
 | 
			
		||||
 | 
			
		||||
	if (ret == 0)
 | 
			
		||||
		return count;
 | 
			
		||||
	else
 | 
			
		||||
		return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DEVICE_ATTR(usb_function_switch, 0666,
 | 
			
		||||
	show_usb_function_switch, store_usb_function_switch);
 | 
			
		||||
 | 
			
		||||
static ssize_t show_usb_serial_number(struct device *dev,
 | 
			
		||||
	struct device_attribute *attr, char *buf)
 | 
			
		||||
{
 | 
			
		||||
@@ -1270,27 +1247,6 @@ static ssize_t show_USB_ID_status(struct device *dev,
 | 
			
		||||
static DEVICE_ATTR(USB_ID_status, 0444,
 | 
			
		||||
	show_USB_ID_status, NULL);
 | 
			
		||||
 | 
			
		||||
static ssize_t show_usb_car_kit_enable(struct device *dev,
 | 
			
		||||
			struct device_attribute *attr,
 | 
			
		||||
			char *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_info *ui = the_usb_info;
 | 
			
		||||
	int value = 1;
 | 
			
		||||
	unsigned length;
 | 
			
		||||
 | 
			
		||||
	if (!ui)
 | 
			
		||||
		return 0;
 | 
			
		||||
	if (ui->accessory_detect == 0) {
 | 
			
		||||
		value = 0;
 | 
			
		||||
	}
 | 
			
		||||
	printk(KERN_INFO "usb: USB_car_kit_enable %d\n", ui->accessory_detect);
 | 
			
		||||
	length = sprintf(buf, "%d", value);
 | 
			
		||||
	return length;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DEVICE_ATTR(usb_car_kit_enable, 0444,
 | 
			
		||||
	show_usb_car_kit_enable, NULL);/*for kar kit AP check if car kit enable*/
 | 
			
		||||
 | 
			
		||||
static ssize_t show_usb_phy_setting(struct device *dev,
 | 
			
		||||
				struct device_attribute *attr, char *buf)
 | 
			
		||||
{
 | 
			
		||||
@@ -1370,17 +1326,13 @@ static ssize_t store_mfg_carkit_enable(struct device *dev,
 | 
			
		||||
 | 
			
		||||
static DEVICE_ATTR(usb_mfg_carkit_enable, 0644,
 | 
			
		||||
	show_mfg_carkit_enable, store_mfg_carkit_enable);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined (CONFIG_DOCK_ACCESSORY_DETECT) || defined(CONFIG_USB_ACCESSORY_DETECT)
 | 
			
		||||
static ssize_t dock_status_show(struct device *dev,
 | 
			
		||||
	struct device_attribute *attr, char *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_info *ui = the_usb_info;
 | 
			
		||||
	if (ui->accessory_type == 1)
 | 
			
		||||
		return sprintf(buf, "online\n");
 | 
			
		||||
	else if (ui->accessory_type == 3) /*desk dock*/
 | 
			
		||||
		return sprintf(buf, "online\n");
 | 
			
		||||
	else
 | 
			
		||||
		return sprintf(buf, "offline\n");
 | 
			
		||||
}
 | 
			
		||||
@@ -1417,13 +1369,6 @@ static void usb_prepare(struct usb_info *ui)
 | 
			
		||||
#ifdef CONFIG_USB_ACCESSORY_DETECT
 | 
			
		||||
	INIT_WORK(&ui->detect_work, accessory_detect_work);
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CONFIG_DOCK_ACCESSORY_DETECT
 | 
			
		||||
	if (ui->dock_detect) {
 | 
			
		||||
		INIT_WORK(&ui->dock_work, dock_detect_work);
 | 
			
		||||
		dock_detect_init(ui);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	INIT_WORK(&ui->notifier_work, send_usb_connect_notify);
 | 
			
		||||
	INIT_DELAYED_WORK(&ui->chg_work, check_charger);
 | 
			
		||||
 | 
			
		||||
@@ -1432,6 +1377,11 @@ static void usb_prepare(struct usb_info *ui)
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		printk(KERN_WARNING "dev_attr_usb_cable_connect failed\n");
 | 
			
		||||
 | 
			
		||||
	ret = device_create_file(&ui->pdev->dev,
 | 
			
		||||
		&dev_attr_usb_function_switch);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		printk(KERN_WARNING "dev_attr_usb_function_switch failed\n");
 | 
			
		||||
 | 
			
		||||
	ret = device_create_file(&ui->pdev->dev,
 | 
			
		||||
		&dev_attr_usb_serial_number);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
@@ -1458,11 +1408,6 @@ static void usb_prepare(struct usb_info *ui)
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		printk(KERN_WARNING "dev_attr_usb_mfg_carkit_enable failed\n");
 | 
			
		||||
#endif
 | 
			
		||||
	ret = device_create_file(&ui->pdev->dev,
 | 
			
		||||
		&dev_attr_usb_car_kit_enable);/*for kar kit AP check if car kit enable*/
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		printk(KERN_WARNING "dev_attr_usb_car_kit_enable failed\n");
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int usb_wakeup_phy(struct usb_info *ui)
 | 
			
		||||
@@ -1605,18 +1550,6 @@ static void usb_start(struct usb_info *ui)
 | 
			
		||||
 | 
			
		||||
	spin_lock_irqsave(&ui->lock, flags);
 | 
			
		||||
	ui->flags |= USB_FLAG_START;
 | 
			
		||||
/*if msm_hsusb_set_vbus_state set 1, but usb did not init, the ui =NULL, */
 | 
			
		||||
/*it would cause reboot with usb, it did not swith to USB and ADB fail*/
 | 
			
		||||
/*So when USB start, check again*/
 | 
			
		||||
	if (vbus) {
 | 
			
		||||
		ui->flags |= USB_FLAG_VBUS_ONLINE;
 | 
			
		||||
	} else {
 | 
			
		||||
		ui->flags |= USB_FLAG_VBUS_OFFLINE;
 | 
			
		||||
	}
 | 
			
		||||
	/* online->switch to USB, offline->switch to uart */
 | 
			
		||||
	if (ui->usb_uart_switch)
 | 
			
		||||
		ui->usb_uart_switch(!vbus);
 | 
			
		||||
 | 
			
		||||
	queue_work(ui->usb_wq, &ui->work);
 | 
			
		||||
	spin_unlock_irqrestore(&ui->lock, flags);
 | 
			
		||||
}
 | 
			
		||||
@@ -1681,13 +1614,6 @@ static void usb_lpm_enter(struct usb_info *ui)
 | 
			
		||||
	clk_set_rate(ui->ebi1clk, 0);
 | 
			
		||||
	ui->in_lpm = 1;
 | 
			
		||||
	spin_unlock_irqrestore(&ui->lock, iflags);
 | 
			
		||||
 | 
			
		||||
	if (board_mfg_mode() == 1) {/*for MFG adb unstable in FROYO ROM*/
 | 
			
		||||
		printk(KERN_INFO "usb: idle_wake_unlock and perf unlock\n");
 | 
			
		||||
		wake_unlock(&vbus_idle_wake_lock);
 | 
			
		||||
		if (is_perf_lock_active(&usb_perf_lock))
 | 
			
		||||
			perf_unlock(&usb_perf_lock);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void usb_lpm_exit(struct usb_info *ui)
 | 
			
		||||
@@ -1705,86 +1631,8 @@ static void usb_lpm_exit(struct usb_info *ui)
 | 
			
		||||
		clk_enable(ui->otgclk);
 | 
			
		||||
	usb_wakeup_phy(ui);
 | 
			
		||||
	ui->in_lpm = 0;
 | 
			
		||||
 | 
			
		||||
	if (board_mfg_mode() == 1) {/*for MFG adb unstable in FROYO ROM*/
 | 
			
		||||
		printk(KERN_INFO "usb: idle_wake_lock and perf lock\n");
 | 
			
		||||
		wake_lock(&vbus_idle_wake_lock);
 | 
			
		||||
		if (!is_perf_lock_active(&usb_perf_lock))
 | 
			
		||||
			perf_lock(&usb_perf_lock);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_DOCK_ACCESSORY_DETECT
 | 
			
		||||
static irqreturn_t dock_interrupt(int irq, void *data)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_info *ui = data;
 | 
			
		||||
	disable_irq_nosync(ui->dockpin_irq);
 | 
			
		||||
	queue_work(ui->usb_wq, &ui->dock_work);
 | 
			
		||||
	return IRQ_HANDLED;
 | 
			
		||||
}
 | 
			
		||||
static void dock_detect_work(struct work_struct *w)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_info *ui = container_of(w, struct usb_info, dock_work);
 | 
			
		||||
	int value;
 | 
			
		||||
 | 
			
		||||
	value = gpio_get_value(ui->dock_pin_gpio);
 | 
			
		||||
 | 
			
		||||
	if (value == 0 && vbus) {
 | 
			
		||||
		set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_HIGH);
 | 
			
		||||
		switch_set_state(&dock_switch, DOCK_STATE_DESK);
 | 
			
		||||
		ui->accessory_type = 3;
 | 
			
		||||
		printk(KERN_INFO "usb:dock: set state %d\n", DOCK_STATE_DESK);
 | 
			
		||||
	} else {
 | 
			
		||||
		set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_LOW);
 | 
			
		||||
		switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED);
 | 
			
		||||
		ui->accessory_type = 0;
 | 
			
		||||
		printk(KERN_INFO "usb:dock: set state %d\n", DOCK_STATE_UNDOCKED);
 | 
			
		||||
	}
 | 
			
		||||
	enable_irq(ui->dockpin_irq);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
static void dock_detect_init(struct usb_info *ui)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (ui->dock_pin_gpio == 0)
 | 
			
		||||
		return;
 | 
			
		||||
	if (ui->dockpin_irq == 0)
 | 
			
		||||
		ui->dockpin_irq = gpio_to_irq(ui->dock_pin_gpio);
 | 
			
		||||
 | 
			
		||||
	ret = request_irq(ui->dockpin_irq, dock_interrupt,
 | 
			
		||||
				IRQF_TRIGGER_LOW,
 | 
			
		||||
				"dock_irq", ui);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		printk(KERN_ERR "%s: request_irq failed\n", __func__);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	printk(KERN_INFO "%s: dock irq %d\n", __func__,
 | 
			
		||||
		ui->dockpin_irq);
 | 
			
		||||
	ret = set_irq_wake(ui->dockpin_irq, 1);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		printk(KERN_ERR "%s: set_irq_wake failed\n", __func__);
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (switch_dev_register(&dock_switch) < 0) {
 | 
			
		||||
		printk(KERN_ERR "usb: fail to register dock switch!\n");
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = device_create_file(dock_switch.dev, &dev_attr_status);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		printk(KERN_WARNING "dev_attr_status failed\n");
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
 | 
			
		||||
err:
 | 
			
		||||
	free_irq(ui->dockpin_irq, 0);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_USB_ACCESSORY_DETECT
 | 
			
		||||
static void carkit_detect(struct usb_info *ui)
 | 
			
		||||
{
 | 
			
		||||
@@ -1842,7 +1690,7 @@ static void accessory_detect_by_adc(struct usb_info *ui)
 | 
			
		||||
		if (adc_value >= 0x2112 && adc_value <= 0x3D53) {
 | 
			
		||||
			printk(KERN_INFO "usb: headset inserted\n");
 | 
			
		||||
			ui->accessory_type = 2;
 | 
			
		||||
			headset_ext_detect(USB_AUDIO_OUT);
 | 
			
		||||
			headset_ext_detect(USB_HEADSET);
 | 
			
		||||
		} else if (adc_value >= 0x88A && adc_value <= 0x1E38) {
 | 
			
		||||
			printk(KERN_INFO "usb: carkit inserted\n");
 | 
			
		||||
			ui->accessory_type = 1;
 | 
			
		||||
@@ -1856,7 +1704,7 @@ static void accessory_detect_by_adc(struct usb_info *ui)
 | 
			
		||||
	} else {
 | 
			
		||||
		if (ui->accessory_type == 2) {
 | 
			
		||||
			printk(KERN_INFO "usb: headset removed\n");
 | 
			
		||||
			headset_ext_detect(USB_NO_HEADSET);
 | 
			
		||||
			headset_ext_detect(NO_DEVICE);
 | 
			
		||||
		} else if (ui->accessory_type == 1) {
 | 
			
		||||
			printk(KERN_INFO "usb: carkit removed\n");
 | 
			
		||||
			switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED);
 | 
			
		||||
@@ -1908,8 +1756,7 @@ static void accessory_detect_init(struct usb_info *ui)
 | 
			
		||||
 | 
			
		||||
	if (ui->usb_id_pin_gpio == 0)
 | 
			
		||||
		return;
 | 
			
		||||
	if (ui->idpin_irq == 0)
 | 
			
		||||
		ui->idpin_irq = gpio_to_irq(ui->usb_id_pin_gpio);
 | 
			
		||||
	ui->idpin_irq = gpio_to_irq(ui->usb_id_pin_gpio);
 | 
			
		||||
 | 
			
		||||
	ret = request_irq(ui->idpin_irq, usbid_interrupt,
 | 
			
		||||
				IRQF_TRIGGER_LOW,
 | 
			
		||||
@@ -1929,11 +1776,9 @@ static void accessory_detect_init(struct usb_info *ui)
 | 
			
		||||
		printk(KERN_ERR "usb: fail to register dock switch!\n");
 | 
			
		||||
		goto err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = device_create_file(dock_switch.dev, &dev_attr_status);
 | 
			
		||||
	if (ret != 0)
 | 
			
		||||
		printk(KERN_WARNING "dev_attr_status failed\n");
 | 
			
		||||
 | 
			
		||||
	return;
 | 
			
		||||
err:
 | 
			
		||||
	free_irq(ui->idpin_irq, 0);
 | 
			
		||||
@@ -1942,44 +1787,6 @@ err:
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DELAY_FOR_CHECK_CHG msecs_to_jiffies(300)
 | 
			
		||||
 | 
			
		||||
static void charger_detect_by_uart(struct usb_info *ui)
 | 
			
		||||
{
 | 
			
		||||
	int is_china_ac;
 | 
			
		||||
 | 
			
		||||
	/*UART*/
 | 
			
		||||
	if (ui->usb_uart_switch)
 | 
			
		||||
		ui->usb_uart_switch(1);
 | 
			
		||||
 | 
			
		||||
	is_china_ac = ui->china_ac_detect();
 | 
			
		||||
 | 
			
		||||
	if (is_china_ac) {
 | 
			
		||||
		ui->connect_type = CONNECT_TYPE_AC;
 | 
			
		||||
		queue_work(ui->usb_wq, &ui->notifier_work);
 | 
			
		||||
		usb_lpm_enter(ui);
 | 
			
		||||
		printk(KERN_INFO "usb: AC charger\n");
 | 
			
		||||
	} else {
 | 
			
		||||
		ui->connect_type = CONNECT_TYPE_UNKNOWN;
 | 
			
		||||
		queue_delayed_work(ui->usb_wq, &ui->chg_work,
 | 
			
		||||
			DELAY_FOR_CHECK_CHG);
 | 
			
		||||
		printk(KERN_INFO "usb: not AC charger\n");
 | 
			
		||||
 | 
			
		||||
		/*set uart to gpo*/
 | 
			
		||||
		if (ui->serial_debug_gpios)
 | 
			
		||||
			ui->serial_debug_gpios(0);
 | 
			
		||||
		/*turn on USB HUB*/
 | 
			
		||||
		if (ui->usb_hub_enable)
 | 
			
		||||
			ui->usb_hub_enable(1);
 | 
			
		||||
 | 
			
		||||
		/*USB*/
 | 
			
		||||
		if (ui->usb_uart_switch)
 | 
			
		||||
			ui->usb_uart_switch(0);
 | 
			
		||||
 | 
			
		||||
		usb_lpm_exit(ui);
 | 
			
		||||
		usb_reset(ui);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void charger_detect(struct usb_info *ui)
 | 
			
		||||
{
 | 
			
		||||
	if (!vbus)
 | 
			
		||||
@@ -2004,13 +1811,6 @@ static void charger_detect(struct usb_info *ui)
 | 
			
		||||
static void check_charger(struct work_struct *w)
 | 
			
		||||
{
 | 
			
		||||
	struct usb_info *ui = container_of(w, struct usb_info, chg_work.work);
 | 
			
		||||
	if (disable_charger) {
 | 
			
		||||
		printk(KERN_INFO "usb: disable charger\n");
 | 
			
		||||
		if (ui->disable_usb_charger)
 | 
			
		||||
			ui->disable_usb_charger();
 | 
			
		||||
		disable_charger = 0;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	/* unknown charger */
 | 
			
		||||
	if (vbus && ui->connect_type == CONNECT_TYPE_UNKNOWN)
 | 
			
		||||
		queue_work(ui->usb_wq, &ui->notifier_work);
 | 
			
		||||
@@ -2022,7 +1822,6 @@ static void usb_do_work(struct work_struct *w)
 | 
			
		||||
	unsigned long iflags;
 | 
			
		||||
	unsigned flags, _vbus;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	for (;;) {
 | 
			
		||||
		spin_lock_irqsave(&ui->lock, iflags);
 | 
			
		||||
		flags = ui->flags;
 | 
			
		||||
@@ -2037,15 +1836,9 @@ static void usb_do_work(struct work_struct *w)
 | 
			
		||||
		case USB_STATE_IDLE:
 | 
			
		||||
			if (flags & USB_FLAG_START) {
 | 
			
		||||
				pr_info("hsusb: IDLE -> ONLINE\n");
 | 
			
		||||
 | 
			
		||||
				if (ui->china_ac_detect)
 | 
			
		||||
					charger_detect_by_uart(ui);
 | 
			
		||||
				else {
 | 
			
		||||
					usb_lpm_exit(ui);
 | 
			
		||||
					usb_reset(ui);
 | 
			
		||||
 | 
			
		||||
					charger_detect(ui);
 | 
			
		||||
				}
 | 
			
		||||
				usb_lpm_exit(ui);
 | 
			
		||||
				usb_reset(ui);
 | 
			
		||||
				charger_detect(ui);
 | 
			
		||||
 | 
			
		||||
				ui->state = USB_STATE_ONLINE;
 | 
			
		||||
#ifdef CONFIG_USB_ACCESSORY_DETECT
 | 
			
		||||
@@ -2117,14 +1910,9 @@ static void usb_do_work(struct work_struct *w)
 | 
			
		||||
			 */
 | 
			
		||||
			if ((flags & USB_FLAG_VBUS_ONLINE) && _vbus) {
 | 
			
		||||
				pr_info("hsusb: OFFLINE -> ONLINE\n");
 | 
			
		||||
 | 
			
		||||
				if (ui->china_ac_detect)
 | 
			
		||||
					charger_detect_by_uart(ui);
 | 
			
		||||
				else {
 | 
			
		||||
					usb_lpm_exit(ui);
 | 
			
		||||
					usb_reset(ui);
 | 
			
		||||
					charger_detect(ui);
 | 
			
		||||
				}
 | 
			
		||||
				usb_lpm_exit(ui);
 | 
			
		||||
				usb_reset(ui);
 | 
			
		||||
				charger_detect(ui);
 | 
			
		||||
 | 
			
		||||
				ui->state = USB_STATE_ONLINE;
 | 
			
		||||
				usb_do_work_check_vbus(ui);
 | 
			
		||||
@@ -2154,33 +1942,9 @@ void msm_hsusb_set_vbus_state(int online)
 | 
			
		||||
			} else {
 | 
			
		||||
				ui->flags |= USB_FLAG_VBUS_OFFLINE;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (online) {
 | 
			
		||||
				/*USB*/
 | 
			
		||||
				if (ui->usb_uart_switch)
 | 
			
		||||
					ui->usb_uart_switch(0);
 | 
			
		||||
			} else {
 | 
			
		||||
				/*turn off USB HUB*/
 | 
			
		||||
				if (ui->usb_hub_enable)
 | 
			
		||||
					ui->usb_hub_enable(0);
 | 
			
		||||
 | 
			
		||||
				/*UART*/
 | 
			
		||||
				if (ui->usb_uart_switch)
 | 
			
		||||
					ui->usb_uart_switch(1);
 | 
			
		||||
				/*configure uart pin to alternate function*/
 | 
			
		||||
				if (ui->serial_debug_gpios)
 | 
			
		||||
					ui->serial_debug_gpios(1);
 | 
			
		||||
#ifdef CONFIG_DOCK_ACCESSORY_DETECT
 | 
			
		||||
				if (ui->accessory_type == 3) {
 | 
			
		||||
					set_irq_type(ui->dockpin_irq, IRQF_TRIGGER_LOW);
 | 
			
		||||
					switch_set_state(&dock_switch, DOCK_STATE_UNDOCKED);
 | 
			
		||||
					ui->accessory_type = 0;
 | 
			
		||||
					printk(KERN_INFO "usb:dock: vbus offline\n");
 | 
			
		||||
					enable_irq(ui->dockpin_irq);
 | 
			
		||||
				}
 | 
			
		||||
#endif
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/* online->switch to USB, offline->switch to uart */
 | 
			
		||||
			if (ui->usb_uart_switch)
 | 
			
		||||
				ui->usb_uart_switch(!online);
 | 
			
		||||
			queue_work(ui->usb_wq, &ui->work);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
@@ -2601,10 +2365,6 @@ static int msm72k_probe(struct platform_device *pdev)
 | 
			
		||||
		ui->phy_init_seq = pdata->phy_init_seq;
 | 
			
		||||
		ui->usb_connected = pdata->usb_connected;
 | 
			
		||||
		ui->usb_uart_switch = pdata->usb_uart_switch;
 | 
			
		||||
		ui->serial_debug_gpios = pdata->serial_debug_gpios;
 | 
			
		||||
		ui->usb_hub_enable = pdata->usb_hub_enable;
 | 
			
		||||
		ui->china_ac_detect = pdata->china_ac_detect;
 | 
			
		||||
		ui->disable_usb_charger = pdata->disable_usb_charger;
 | 
			
		||||
 | 
			
		||||
		ui->accessory_detect = pdata->accessory_detect;
 | 
			
		||||
		printk(KERN_INFO "usb: accessory detect %d\n",
 | 
			
		||||
@@ -2612,15 +2372,6 @@ static int msm72k_probe(struct platform_device *pdev)
 | 
			
		||||
		ui->usb_id_pin_gpio = pdata->usb_id_pin_gpio;
 | 
			
		||||
		printk(KERN_INFO "usb: id_pin_gpio %d\n",
 | 
			
		||||
			pdata->usb_id_pin_gpio);
 | 
			
		||||
 | 
			
		||||
		ui->dock_detect = pdata->dock_detect;
 | 
			
		||||
		printk(KERN_INFO "usb: dock detect %d\n",
 | 
			
		||||
			ui->dock_detect);
 | 
			
		||||
		ui->dock_pin_gpio = pdata->dock_pin_gpio;
 | 
			
		||||
		printk(KERN_INFO "usb: dock pin gpio %d\n",
 | 
			
		||||
			ui->dock_pin_gpio);
 | 
			
		||||
 | 
			
		||||
		ui->idpin_irq = pdata->id_pin_irq;
 | 
			
		||||
		if (pdata->config_usb_id_gpios)
 | 
			
		||||
			ui->config_usb_id_gpios = pdata->config_usb_id_gpios;
 | 
			
		||||
	}
 | 
			
		||||
@@ -2706,11 +2457,9 @@ static int msm72k_probe(struct platform_device *pdev)
 | 
			
		||||
 | 
			
		||||
	/* initialize mfg serial number */
 | 
			
		||||
 | 
			
		||||
	if (board_mfg_mode() == 1) {
 | 
			
		||||
	if (board_mfg_mode() == 1)
 | 
			
		||||
		use_mfg_serialno = 1;
 | 
			
		||||
		wake_lock_init(&vbus_idle_wake_lock, WAKE_LOCK_IDLE, "usb_idle_lock");
 | 
			
		||||
		perf_lock_init(&usb_perf_lock, PERF_LOCK_HIGHEST, "usb");
 | 
			
		||||
	} else
 | 
			
		||||
	else
 | 
			
		||||
		use_mfg_serialno = 0;
 | 
			
		||||
	strncpy(mfg_df_serialno, "000000000000", strlen("000000000000"));
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,6 @@
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/list.h>
 | 
			
		||||
#include <linux/proc_fs.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/seq_file.h>
 | 
			
		||||
#include <linux/netdevice.h>
 | 
			
		||||
 | 
			
		||||
@@ -292,13 +291,9 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 | 
			
		||||
	/* mandatory */
 | 
			
		||||
	case OID_GEN_VENDOR_DESCRIPTION:
 | 
			
		||||
		pr_debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__);
 | 
			
		||||
		if ( rndis_per_dev_params [configNr].vendorDescr ) {
 | 
			
		||||
			length = strlen (rndis_per_dev_params [configNr].vendorDescr);
 | 
			
		||||
			memcpy (outbuf,
 | 
			
		||||
				rndis_per_dev_params [configNr].vendorDescr, length);
 | 
			
		||||
		} else {
 | 
			
		||||
			outbuf[0] = 0;
 | 
			
		||||
		}
 | 
			
		||||
		length = strlen (rndis_per_dev_params [configNr].vendorDescr);
 | 
			
		||||
		memcpy (outbuf,
 | 
			
		||||
			rndis_per_dev_params [configNr].vendorDescr, length);
 | 
			
		||||
		retval = 0;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,784 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
 * storage_common.c -- Common definitions for mass storage functionality
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2003-2008 Alan Stern
 | 
			
		||||
 * Copyeight (C) 2009 Samsung Electronics
 | 
			
		||||
 * Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU General Public License as published by
 | 
			
		||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
 * (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU General Public License
 | 
			
		||||
 * along with this program; if not, write to the Free Software
 | 
			
		||||
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This file requires the following identifiers used in USB strings to
 | 
			
		||||
 * be defined (each of type pointer to char):
 | 
			
		||||
 *  - fsg_string_manufacturer -- name of the manufacturer
 | 
			
		||||
 *  - fsg_string_product      -- name of the product
 | 
			
		||||
 *  - fsg_string_serial       -- product's serial
 | 
			
		||||
 *  - fsg_string_config       -- name of the configuration
 | 
			
		||||
 *  - fsg_string_interface    -- name of the interface
 | 
			
		||||
 * The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS
 | 
			
		||||
 * macro is defined prior to including this file.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and
 | 
			
		||||
 * fsg_hs_intr_in_desc objects as well as
 | 
			
		||||
 * FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES
 | 
			
		||||
 * macros are not defined.
 | 
			
		||||
 *
 | 
			
		||||
 * When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER,
 | 
			
		||||
 * FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not
 | 
			
		||||
 * defined (as well as corresponding entries in string tables are
 | 
			
		||||
 * missing) and FSG_STRING_INTERFACE has value of zero.
 | 
			
		||||
 *
 | 
			
		||||
 * When FSG_NO_OTG is defined fsg_otg_desc won't be defined.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included
 | 
			
		||||
 * the fsg_buffhd structure's buf field will be an array of FSG_BUFLEN
 | 
			
		||||
 * characters rather then a pointer to void.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <asm/unaligned.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Thanks to NetChip Technologies for donating this product ID.
 | 
			
		||||
 *
 | 
			
		||||
 * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
 | 
			
		||||
 * Instead:  allocate your own, using normal USB-IF procedures. */
 | 
			
		||||
#define FSG_VENDOR_ID	0x0525	/* NetChip */
 | 
			
		||||
#define FSG_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef DEBUG
 | 
			
		||||
#undef VERBOSE_DEBUG
 | 
			
		||||
#undef DUMP_MSGS
 | 
			
		||||
#endif /* !DEBUG */
 | 
			
		||||
 | 
			
		||||
#ifdef VERBOSE_DEBUG
 | 
			
		||||
#define VLDBG	LDBG
 | 
			
		||||
#else
 | 
			
		||||
#define VLDBG(lun, fmt, args...) do { } while (0)
 | 
			
		||||
#endif /* VERBOSE_DEBUG */
 | 
			
		||||
 | 
			
		||||
#define LDBG(lun, fmt, args...)   dev_dbg (&(lun)->dev, fmt, ## args)
 | 
			
		||||
#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args)
 | 
			
		||||
#define LWARN(lun, fmt, args...)  dev_warn(&(lun)->dev, fmt, ## args)
 | 
			
		||||
#define LINFO(lun, fmt, args...)  dev_info(&(lun)->dev, fmt, ## args)
 | 
			
		||||
 | 
			
		||||
/* Keep those macros in sync with thos in
 | 
			
		||||
 * include/linux/ubs/composite.h or else GCC will complain.  If they
 | 
			
		||||
 * are identical (the same names of arguments, white spaces in the
 | 
			
		||||
 * same places) GCC will allow redefinition otherwise (even if some
 | 
			
		||||
 * white space is removed or added) warning will be issued.  No
 | 
			
		||||
 * checking if those symbols is defined is performed because warning
 | 
			
		||||
 * is desired when those macros were defined by someone else to mean
 | 
			
		||||
 * something else. */
 | 
			
		||||
#define DBG(d, fmt, args...)     dev_dbg(&(d)->gadget->dev , fmt , ## args)
 | 
			
		||||
#define VDBG(d, fmt, args...)    dev_vdbg(&(d)->gadget->dev , fmt , ## args)
 | 
			
		||||
#define ERROR(d, fmt, args...)   dev_err(&(d)->gadget->dev , fmt , ## args)
 | 
			
		||||
#define WARNING(d, fmt, args...) dev_warn(&(d)->gadget->dev , fmt , ## args)
 | 
			
		||||
#define INFO(d, fmt, args...)    dev_info(&(d)->gadget->dev , fmt , ## args)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef DUMP_MSGS
 | 
			
		||||
 | 
			
		||||
#  define dump_msg(fsg, /* const char * */ label,			\
 | 
			
		||||
		   /* const u8 * */ buf, /* unsigned */ length) do {	\
 | 
			
		||||
	if (length < 512) {						\
 | 
			
		||||
		DBG(fsg, "%s, length %u:\n", label, length);		\
 | 
			
		||||
		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,	\
 | 
			
		||||
			       16, 1, buf, length, 0);			\
 | 
			
		||||
	}								\
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#  define dump_cdb(fsg) do { } while (0)
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#  define dump_msg(fsg, /* const char * */ label, \
 | 
			
		||||
		   /* const u8 * */ buf, /* unsigned */ length) do { } while (0)
 | 
			
		||||
 | 
			
		||||
#  ifdef VERBOSE_DEBUG
 | 
			
		||||
 | 
			
		||||
#    define dump_cdb(fsg)						\
 | 
			
		||||
	print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,	\
 | 
			
		||||
		       16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0)		\
 | 
			
		||||
 | 
			
		||||
#  else
 | 
			
		||||
 | 
			
		||||
#    define dump_cdb(fsg) do { } while (0)
 | 
			
		||||
 | 
			
		||||
#  endif /* VERBOSE_DEBUG */
 | 
			
		||||
 | 
			
		||||
#endif /* DUMP_MSGS */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
/* SCSI device types */
 | 
			
		||||
#define TYPE_DISK	0x00
 | 
			
		||||
#define TYPE_CDROM	0x05
 | 
			
		||||
 | 
			
		||||
/* USB protocol value = the transport method */
 | 
			
		||||
#define USB_PR_CBI	0x00		/* Control/Bulk/Interrupt */
 | 
			
		||||
#define USB_PR_CB	0x01		/* Control/Bulk w/o interrupt */
 | 
			
		||||
#define USB_PR_BULK	0x50		/* Bulk-only */
 | 
			
		||||
 | 
			
		||||
/* USB subclass value = the protocol encapsulation */
 | 
			
		||||
#define USB_SC_RBC	0x01		/* Reduced Block Commands (flash) */
 | 
			
		||||
#define USB_SC_8020	0x02		/* SFF-8020i, MMC-2, ATAPI (CD-ROM) */
 | 
			
		||||
#define USB_SC_QIC	0x03		/* QIC-157 (tape) */
 | 
			
		||||
#define USB_SC_UFI	0x04		/* UFI (floppy) */
 | 
			
		||||
#define USB_SC_8070	0x05		/* SFF-8070i (removable) */
 | 
			
		||||
#define USB_SC_SCSI	0x06		/* Transparent SCSI */
 | 
			
		||||
 | 
			
		||||
/* Bulk-only data structures */
 | 
			
		||||
 | 
			
		||||
/* Command Block Wrapper */
 | 
			
		||||
struct fsg_bulk_cb_wrap {
 | 
			
		||||
	__le32	Signature;		/* Contains 'USBC' */
 | 
			
		||||
	u32	Tag;			/* Unique per command id */
 | 
			
		||||
	__le32	DataTransferLength;	/* Size of the data */
 | 
			
		||||
	u8	Flags;			/* Direction in bit 7 */
 | 
			
		||||
	u8	Lun;			/* LUN (normally 0) */
 | 
			
		||||
	u8	Length;			/* Of the CDB, <= MAX_COMMAND_SIZE */
 | 
			
		||||
	u8	CDB[16];		/* Command Data Block */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define USB_BULK_CB_WRAP_LEN	31
 | 
			
		||||
#define USB_BULK_CB_SIG		0x43425355	/* Spells out USBC */
 | 
			
		||||
#define USB_BULK_IN_FLAG	0x80
 | 
			
		||||
 | 
			
		||||
/* Command Status Wrapper */
 | 
			
		||||
struct bulk_cs_wrap {
 | 
			
		||||
	__le32	Signature;		/* Should = 'USBS' */
 | 
			
		||||
	u32	Tag;			/* Same as original command */
 | 
			
		||||
	__le32	Residue;		/* Amount not transferred */
 | 
			
		||||
	u8	Status;			/* See below */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define USB_BULK_CS_WRAP_LEN	13
 | 
			
		||||
#define USB_BULK_CS_SIG		0x53425355	/* Spells out 'USBS' */
 | 
			
		||||
#define USB_STATUS_PASS		0
 | 
			
		||||
#define USB_STATUS_FAIL		1
 | 
			
		||||
#define USB_STATUS_PHASE_ERROR	2
 | 
			
		||||
 | 
			
		||||
/* Bulk-only class specific requests */
 | 
			
		||||
#define USB_BULK_RESET_REQUEST		0xff
 | 
			
		||||
#define USB_BULK_GET_MAX_LUN_REQUEST	0xfe
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* CBI Interrupt data structure */
 | 
			
		||||
struct interrupt_data {
 | 
			
		||||
	u8	bType;
 | 
			
		||||
	u8	bValue;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define CBI_INTERRUPT_DATA_LEN		2
 | 
			
		||||
 | 
			
		||||
/* CBI Accept Device-Specific Command request */
 | 
			
		||||
#define USB_CBI_ADSC_REQUEST		0x00
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Length of a SCSI Command Data Block */
 | 
			
		||||
#define MAX_COMMAND_SIZE	16
 | 
			
		||||
 | 
			
		||||
/* SCSI commands that we recognize */
 | 
			
		||||
#define SC_FORMAT_UNIT			0x04
 | 
			
		||||
#define SC_INQUIRY			0x12
 | 
			
		||||
#define SC_MODE_SELECT_6		0x15
 | 
			
		||||
#define SC_MODE_SELECT_10		0x55
 | 
			
		||||
#define SC_MODE_SENSE_6			0x1a
 | 
			
		||||
#define SC_MODE_SENSE_10		0x5a
 | 
			
		||||
#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL	0x1e
 | 
			
		||||
#define SC_READ_6			0x08
 | 
			
		||||
#define SC_READ_10			0x28
 | 
			
		||||
#define SC_READ_12			0xa8
 | 
			
		||||
#define SC_READ_CAPACITY		0x25
 | 
			
		||||
#define SC_READ_FORMAT_CAPACITIES	0x23
 | 
			
		||||
#define SC_READ_HEADER			0x44
 | 
			
		||||
#define SC_READ_TOC			0x43
 | 
			
		||||
#define SC_RELEASE			0x17
 | 
			
		||||
#define SC_REQUEST_SENSE		0x03
 | 
			
		||||
#define SC_RESERVE			0x16
 | 
			
		||||
#define SC_SEND_DIAGNOSTIC		0x1d
 | 
			
		||||
#define SC_START_STOP_UNIT		0x1b
 | 
			
		||||
#define SC_SYNCHRONIZE_CACHE		0x35
 | 
			
		||||
#define SC_TEST_UNIT_READY		0x00
 | 
			
		||||
#define SC_VERIFY			0x2f
 | 
			
		||||
#define SC_WRITE_6			0x0a
 | 
			
		||||
#define SC_WRITE_10			0x2a
 | 
			
		||||
#define SC_WRITE_12			0xaa
 | 
			
		||||
 | 
			
		||||
/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
 | 
			
		||||
#define SS_NO_SENSE				0
 | 
			
		||||
#define SS_COMMUNICATION_FAILURE		0x040800
 | 
			
		||||
#define SS_INVALID_COMMAND			0x052000
 | 
			
		||||
#define SS_INVALID_FIELD_IN_CDB			0x052400
 | 
			
		||||
#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE	0x052100
 | 
			
		||||
#define SS_LOGICAL_UNIT_NOT_SUPPORTED		0x052500
 | 
			
		||||
#define SS_MEDIUM_NOT_PRESENT			0x023a00
 | 
			
		||||
#define SS_MEDIUM_REMOVAL_PREVENTED		0x055302
 | 
			
		||||
#define SS_NOT_READY_TO_READY_TRANSITION	0x062800
 | 
			
		||||
#define SS_RESET_OCCURRED			0x062900
 | 
			
		||||
#define SS_SAVING_PARAMETERS_NOT_SUPPORTED	0x053900
 | 
			
		||||
#define SS_UNRECOVERED_READ_ERROR		0x031100
 | 
			
		||||
#define SS_WRITE_ERROR				0x030c02
 | 
			
		||||
#define SS_WRITE_PROTECTED			0x072700
 | 
			
		||||
 | 
			
		||||
#define SK(x)		((u8) ((x) >> 16))	/* Sense Key byte, etc. */
 | 
			
		||||
#define ASC(x)		((u8) ((x) >> 8))
 | 
			
		||||
#define ASCQ(x)		((u8) (x))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct fsg_lun {
 | 
			
		||||
	struct file	*filp;
 | 
			
		||||
	loff_t		file_length;
 | 
			
		||||
	loff_t		num_sectors;
 | 
			
		||||
 | 
			
		||||
	unsigned int	initially_ro:1;
 | 
			
		||||
	unsigned int	ro:1;
 | 
			
		||||
	unsigned int	removable:1;
 | 
			
		||||
	unsigned int	cdrom:1;
 | 
			
		||||
	unsigned int	prevent_medium_removal:1;
 | 
			
		||||
	unsigned int	registered:1;
 | 
			
		||||
	unsigned int	info_valid:1;
 | 
			
		||||
 | 
			
		||||
	u32		sense_data;
 | 
			
		||||
	u32		sense_data_info;
 | 
			
		||||
	u32		unit_attention_data;
 | 
			
		||||
 | 
			
		||||
	struct device	dev;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define fsg_lun_is_open(curlun)	((curlun)->filp != NULL)
 | 
			
		||||
 | 
			
		||||
static struct fsg_lun *fsg_lun_from_dev(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	return container_of(dev, struct fsg_lun, dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Big enough to hold our biggest descriptor */
 | 
			
		||||
#define EP0_BUFSIZE	256
 | 
			
		||||
#define DELAYED_STATUS	(EP0_BUFSIZE + 999)	/* An impossibly large value */
 | 
			
		||||
 | 
			
		||||
/* Number of buffers we will use.  2 is enough for double-buffering */
 | 
			
		||||
#define FSG_NUM_BUFFERS	2
 | 
			
		||||
 | 
			
		||||
/* Default size of buffer length. */
 | 
			
		||||
#define FSG_BUFLEN	((u32)16384)
 | 
			
		||||
 | 
			
		||||
/* Maximal number of LUNs supported in mass storage function */
 | 
			
		||||
#define FSG_MAX_LUNS	8
 | 
			
		||||
 | 
			
		||||
enum fsg_buffer_state {
 | 
			
		||||
	BUF_STATE_EMPTY = 0,
 | 
			
		||||
	BUF_STATE_FULL,
 | 
			
		||||
	BUF_STATE_BUSY
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct fsg_buffhd {
 | 
			
		||||
#ifdef FSG_BUFFHD_STATIC_BUFFER
 | 
			
		||||
	char				buf[FSG_BUFLEN];
 | 
			
		||||
#else
 | 
			
		||||
	void				*buf;
 | 
			
		||||
#endif
 | 
			
		||||
	enum fsg_buffer_state		state;
 | 
			
		||||
	struct fsg_buffhd		*next;
 | 
			
		||||
 | 
			
		||||
	/* The NetChip 2280 is faster, and handles some protocol faults
 | 
			
		||||
	 * better, if we don't submit any short bulk-out read requests.
 | 
			
		||||
	 * So we will record the intended request length here. */
 | 
			
		||||
	unsigned int			bulk_out_intended_length;
 | 
			
		||||
 | 
			
		||||
	struct usb_request		*inreq;
 | 
			
		||||
	int				inreq_busy;
 | 
			
		||||
	struct usb_request		*outreq;
 | 
			
		||||
	int				outreq_busy;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum fsg_state {
 | 
			
		||||
	/* This one isn't used anywhere */
 | 
			
		||||
	FSG_STATE_COMMAND_PHASE = -10,
 | 
			
		||||
	FSG_STATE_DATA_PHASE,
 | 
			
		||||
	FSG_STATE_STATUS_PHASE,
 | 
			
		||||
 | 
			
		||||
	FSG_STATE_IDLE = 0,
 | 
			
		||||
	FSG_STATE_ABORT_BULK_OUT,
 | 
			
		||||
	FSG_STATE_RESET,
 | 
			
		||||
	FSG_STATE_INTERFACE_CHANGE,
 | 
			
		||||
	FSG_STATE_CONFIG_CHANGE,
 | 
			
		||||
	FSG_STATE_DISCONNECT,
 | 
			
		||||
	FSG_STATE_EXIT,
 | 
			
		||||
	FSG_STATE_TERMINATED
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum data_direction {
 | 
			
		||||
	DATA_DIR_UNKNOWN = 0,
 | 
			
		||||
	DATA_DIR_FROM_HOST,
 | 
			
		||||
	DATA_DIR_TO_HOST,
 | 
			
		||||
	DATA_DIR_NONE
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static inline u32 get_unaligned_be24(u8 *buf)
 | 
			
		||||
{
 | 
			
		||||
	return 0xffffff & (u32) get_unaligned_be32(buf - 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
#ifndef FSG_NO_DEVICE_STRINGS
 | 
			
		||||
	FSG_STRING_MANUFACTURER	= 1,
 | 
			
		||||
	FSG_STRING_PRODUCT,
 | 
			
		||||
	FSG_STRING_SERIAL,
 | 
			
		||||
	FSG_STRING_CONFIG,
 | 
			
		||||
#endif
 | 
			
		||||
	FSG_STRING_INTERFACE
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef FSG_NO_OTG
 | 
			
		||||
static struct usb_otg_descriptor
 | 
			
		||||
fsg_otg_desc = {
 | 
			
		||||
	.bLength =		sizeof fsg_otg_desc,
 | 
			
		||||
	.bDescriptorType =	USB_DT_OTG,
 | 
			
		||||
 | 
			
		||||
	.bmAttributes =		USB_OTG_SRP,
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* There is only one interface. */
 | 
			
		||||
 | 
			
		||||
static struct usb_interface_descriptor
 | 
			
		||||
fsg_intf_desc = {
 | 
			
		||||
	.bLength =		sizeof fsg_intf_desc,
 | 
			
		||||
	.bDescriptorType =	USB_DT_INTERFACE,
 | 
			
		||||
 | 
			
		||||
	.bNumEndpoints =	2,		/* Adjusted during fsg_bind() */
 | 
			
		||||
	.bInterfaceClass =	USB_CLASS_MASS_STORAGE,
 | 
			
		||||
	.bInterfaceSubClass =	USB_SC_SCSI,	/* Adjusted during fsg_bind() */
 | 
			
		||||
	.bInterfaceProtocol =	USB_PR_BULK,	/* Adjusted during fsg_bind() */
 | 
			
		||||
	.iInterface =		FSG_STRING_INTERFACE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Three full-speed endpoint descriptors: bulk-in, bulk-out,
 | 
			
		||||
 * and interrupt-in. */
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor
 | 
			
		||||
fsg_fs_bulk_in_desc = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
 | 
			
		||||
	.bEndpointAddress =	USB_DIR_IN,
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 | 
			
		||||
	/* wMaxPacketSize set by autoconfiguration */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor
 | 
			
		||||
fsg_fs_bulk_out_desc = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
 | 
			
		||||
	.bEndpointAddress =	USB_DIR_OUT,
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 | 
			
		||||
	/* wMaxPacketSize set by autoconfiguration */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifndef FSG_NO_INTR_EP
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor
 | 
			
		||||
fsg_fs_intr_in_desc = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
 | 
			
		||||
	.bEndpointAddress =	USB_DIR_IN,
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_INT,
 | 
			
		||||
	.wMaxPacketSize =	cpu_to_le16(2),
 | 
			
		||||
	.bInterval =		32,	/* frames -> 32 ms */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifndef FSG_NO_OTG
 | 
			
		||||
#  define FSG_FS_FUNCTION_PRE_EP_ENTRIES	2
 | 
			
		||||
#else
 | 
			
		||||
#  define FSG_FS_FUNCTION_PRE_EP_ENTRIES	1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static struct usb_descriptor_header *fsg_fs_function[] = {
 | 
			
		||||
#ifndef FSG_NO_OTG
 | 
			
		||||
	(struct usb_descriptor_header *) &fsg_otg_desc,
 | 
			
		||||
#endif
 | 
			
		||||
	(struct usb_descriptor_header *) &fsg_intf_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,
 | 
			
		||||
#ifndef FSG_NO_INTR_EP
 | 
			
		||||
	(struct usb_descriptor_header *) &fsg_fs_intr_in_desc,
 | 
			
		||||
#endif
 | 
			
		||||
	NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * USB 2.0 devices need to expose both high speed and full speed
 | 
			
		||||
 * descriptors, unless they only run at full speed.
 | 
			
		||||
 *
 | 
			
		||||
 * That means alternate endpoint descriptors (bigger packets)
 | 
			
		||||
 * and a "device qualifier" ... plus more construction options
 | 
			
		||||
 * for the config descriptor.
 | 
			
		||||
 */
 | 
			
		||||
static struct usb_endpoint_descriptor
 | 
			
		||||
fsg_hs_bulk_in_desc = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
 | 
			
		||||
	/* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 | 
			
		||||
	.wMaxPacketSize =	cpu_to_le16(512),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor
 | 
			
		||||
fsg_hs_bulk_out_desc = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
 | 
			
		||||
	/* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
 | 
			
		||||
	.wMaxPacketSize =	cpu_to_le16(512),
 | 
			
		||||
	.bInterval =		1,	/* NAK every 1 uframe */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifndef FSG_NO_INTR_EP
 | 
			
		||||
 | 
			
		||||
static struct usb_endpoint_descriptor
 | 
			
		||||
fsg_hs_intr_in_desc = {
 | 
			
		||||
	.bLength =		USB_DT_ENDPOINT_SIZE,
 | 
			
		||||
	.bDescriptorType =	USB_DT_ENDPOINT,
 | 
			
		||||
 | 
			
		||||
	/* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */
 | 
			
		||||
	.bmAttributes =		USB_ENDPOINT_XFER_INT,
 | 
			
		||||
	.wMaxPacketSize =	cpu_to_le16(2),
 | 
			
		||||
	.bInterval =		9,	/* 2**(9-1) = 256 uframes -> 32 ms */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifndef FSG_NO_OTG
 | 
			
		||||
#  define FSG_HS_FUNCTION_PRE_EP_ENTRIES	2
 | 
			
		||||
#else
 | 
			
		||||
#  define FSG_HS_FUNCTION_PRE_EP_ENTRIES	1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static struct usb_descriptor_header *fsg_hs_function[] = {
 | 
			
		||||
#ifndef FSG_NO_OTG
 | 
			
		||||
	(struct usb_descriptor_header *) &fsg_otg_desc,
 | 
			
		||||
#endif
 | 
			
		||||
	(struct usb_descriptor_header *) &fsg_intf_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,
 | 
			
		||||
	(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,
 | 
			
		||||
#ifndef FSG_NO_INTR_EP
 | 
			
		||||
	(struct usb_descriptor_header *) &fsg_hs_intr_in_desc,
 | 
			
		||||
#endif
 | 
			
		||||
	NULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Maxpacket and other transfer characteristics vary by speed. */
 | 
			
		||||
static struct usb_endpoint_descriptor *
 | 
			
		||||
fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
 | 
			
		||||
		struct usb_endpoint_descriptor *hs)
 | 
			
		||||
{
 | 
			
		||||
	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
 | 
			
		||||
		return hs;
 | 
			
		||||
	return fs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */
 | 
			
		||||
static struct usb_string		fsg_strings[] = {
 | 
			
		||||
#ifndef FSG_NO_DEVICE_STRINGS
 | 
			
		||||
	{FSG_STRING_MANUFACTURER,	fsg_string_manufacturer},
 | 
			
		||||
	{FSG_STRING_PRODUCT,		fsg_string_product},
 | 
			
		||||
	{FSG_STRING_SERIAL,		fsg_string_serial},
 | 
			
		||||
	{FSG_STRING_CONFIG,		fsg_string_config},
 | 
			
		||||
#endif
 | 
			
		||||
	{FSG_STRING_INTERFACE,		fsg_string_interface},
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static struct usb_gadget_strings	fsg_stringtab = {
 | 
			
		||||
	.language	= 0x0409,		/* en-us */
 | 
			
		||||
	.strings	= fsg_strings,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 /*-------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
/* If the next two routines are called while the gadget is registered,
 | 
			
		||||
 * the caller must own fsg->filesem for writing. */
 | 
			
		||||
 | 
			
		||||
static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
 | 
			
		||||
{
 | 
			
		||||
	int				ro;
 | 
			
		||||
	struct file			*filp = NULL;
 | 
			
		||||
	int				rc = -EINVAL;
 | 
			
		||||
	struct inode			*inode = NULL;
 | 
			
		||||
	loff_t				size;
 | 
			
		||||
	loff_t				num_sectors;
 | 
			
		||||
	loff_t				min_sectors;
 | 
			
		||||
 | 
			
		||||
	/* R/W if we can, R/O if we must */
 | 
			
		||||
	ro = curlun->initially_ro;
 | 
			
		||||
	if (!ro) {
 | 
			
		||||
		filp = filp_open(filename, O_RDWR | O_LARGEFILE, 0);
 | 
			
		||||
		if (-EROFS == PTR_ERR(filp))
 | 
			
		||||
			ro = 1;
 | 
			
		||||
	}
 | 
			
		||||
	if (ro)
 | 
			
		||||
		filp = filp_open(filename, O_RDONLY | O_LARGEFILE, 0);
 | 
			
		||||
	if (IS_ERR(filp)) {
 | 
			
		||||
		LINFO(curlun, "unable to open backing file: %s\n", filename);
 | 
			
		||||
		return PTR_ERR(filp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!(filp->f_mode & FMODE_WRITE))
 | 
			
		||||
		ro = 1;
 | 
			
		||||
 | 
			
		||||
	if (filp->f_path.dentry)
 | 
			
		||||
		inode = filp->f_path.dentry->d_inode;
 | 
			
		||||
	if (inode && S_ISBLK(inode->i_mode)) {
 | 
			
		||||
		if (bdev_read_only(inode->i_bdev))
 | 
			
		||||
			ro = 1;
 | 
			
		||||
	} else if (!inode || !S_ISREG(inode->i_mode)) {
 | 
			
		||||
		LINFO(curlun, "invalid file type: %s\n", filename);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* If we can't read the file, it's no good.
 | 
			
		||||
	 * If we can't write the file, use it read-only. */
 | 
			
		||||
	if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) {
 | 
			
		||||
		LINFO(curlun, "file not readable: %s\n", filename);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	if (!(filp->f_op->write || filp->f_op->aio_write))
 | 
			
		||||
		ro = 1;
 | 
			
		||||
 | 
			
		||||
	size = i_size_read(inode->i_mapping->host);
 | 
			
		||||
	if (size < 0) {
 | 
			
		||||
		LINFO(curlun, "unable to find file size: %s\n", filename);
 | 
			
		||||
		rc = (int) size;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	num_sectors = size >> 9;	/* File size in 512-byte blocks */
 | 
			
		||||
	min_sectors = 1;
 | 
			
		||||
	if (curlun->cdrom) {
 | 
			
		||||
		num_sectors &= ~3;	/* Reduce to a multiple of 2048 */
 | 
			
		||||
		min_sectors = 300*4;	/* Smallest track is 300 frames */
 | 
			
		||||
		if (num_sectors >= 256*60*75*4) {
 | 
			
		||||
			num_sectors = (256*60*75 - 1) * 4;
 | 
			
		||||
			LINFO(curlun, "file too big: %s\n", filename);
 | 
			
		||||
			LINFO(curlun, "using only first %d blocks\n",
 | 
			
		||||
					(int) num_sectors);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (num_sectors < min_sectors) {
 | 
			
		||||
		LINFO(curlun, "file too small: %s\n", filename);
 | 
			
		||||
		rc = -ETOOSMALL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get_file(filp);
 | 
			
		||||
	curlun->ro = ro;
 | 
			
		||||
	curlun->filp = filp;
 | 
			
		||||
	curlun->file_length = size;
 | 
			
		||||
	curlun->num_sectors = num_sectors;
 | 
			
		||||
	LDBG(curlun, "open backing file: %s\n", filename);
 | 
			
		||||
	rc = 0;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	filp_close(filp, current->files);
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static void fsg_lun_close(struct fsg_lun *curlun)
 | 
			
		||||
{
 | 
			
		||||
	if (curlun->filp) {
 | 
			
		||||
		LDBG(curlun, "close backing file\n");
 | 
			
		||||
		fput(curlun->filp);
 | 
			
		||||
		curlun->filp = NULL;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
/* Sync the file data, don't bother with the metadata.
 | 
			
		||||
 * This code was copied from fs/buffer.c:sys_fdatasync(). */
 | 
			
		||||
static int fsg_lun_fsync_sub(struct fsg_lun *curlun)
 | 
			
		||||
{
 | 
			
		||||
	struct file	*filp = curlun->filp;
 | 
			
		||||
 | 
			
		||||
	if (curlun->ro || !filp)
 | 
			
		||||
		return 0;
 | 
			
		||||
	return vfs_fsync(filp, filp->f_path.dentry, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void store_cdrom_address(u8 *dest, int msf, u32 addr)
 | 
			
		||||
{
 | 
			
		||||
	if (msf) {
 | 
			
		||||
		/* Convert to Minutes-Seconds-Frames */
 | 
			
		||||
		addr >>= 2;		/* Convert to 2048-byte frames */
 | 
			
		||||
		addr += 2*75;		/* Lead-in occupies 2 seconds */
 | 
			
		||||
		dest[3] = addr % 75;	/* Frames */
 | 
			
		||||
		addr /= 75;
 | 
			
		||||
		dest[2] = addr % 60;	/* Seconds */
 | 
			
		||||
		addr /= 60;
 | 
			
		||||
		dest[1] = addr;		/* Minutes */
 | 
			
		||||
		dest[0] = 0;		/* Reserved */
 | 
			
		||||
	} else {
 | 
			
		||||
		/* Absolute sector */
 | 
			
		||||
		put_unaligned_be32(addr, dest);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*-------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr,
 | 
			
		||||
			   char *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
 | 
			
		||||
 | 
			
		||||
	return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)
 | 
			
		||||
				  ? curlun->ro
 | 
			
		||||
				  : curlun->initially_ro);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
 | 
			
		||||
			     char *buf)
 | 
			
		||||
{
 | 
			
		||||
	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
 | 
			
		||||
	struct rw_semaphore	*filesem = dev_get_drvdata(dev);
 | 
			
		||||
	char		*p;
 | 
			
		||||
	ssize_t		rc;
 | 
			
		||||
 | 
			
		||||
	down_read(filesem);
 | 
			
		||||
	if (fsg_lun_is_open(curlun)) {	/* Get the complete pathname */
 | 
			
		||||
		p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1);
 | 
			
		||||
		if (IS_ERR(p))
 | 
			
		||||
			rc = PTR_ERR(p);
 | 
			
		||||
		else {
 | 
			
		||||
			rc = strlen(p);
 | 
			
		||||
			memmove(buf, p, rc);
 | 
			
		||||
			buf[rc] = '\n';		/* Add a newline */
 | 
			
		||||
			buf[++rc] = 0;
 | 
			
		||||
		}
 | 
			
		||||
	} else {				/* No file, return 0 bytes */
 | 
			
		||||
		*buf = 0;
 | 
			
		||||
		rc = 0;
 | 
			
		||||
	}
 | 
			
		||||
	up_read(filesem);
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
 | 
			
		||||
			    const char *buf, size_t count)
 | 
			
		||||
{
 | 
			
		||||
	ssize_t		rc = count;
 | 
			
		||||
	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
 | 
			
		||||
	struct rw_semaphore	*filesem = dev_get_drvdata(dev);
 | 
			
		||||
	int		i;
 | 
			
		||||
 | 
			
		||||
	if (sscanf(buf, "%d", &i) != 1)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	/* Allow the write-enable status to change only while the backing file
 | 
			
		||||
	 * is closed. */
 | 
			
		||||
	down_read(filesem);
 | 
			
		||||
	if (fsg_lun_is_open(curlun)) {
 | 
			
		||||
		LDBG(curlun, "read-only status change prevented\n");
 | 
			
		||||
		rc = -EBUSY;
 | 
			
		||||
	} else {
 | 
			
		||||
		curlun->ro = !!i;
 | 
			
		||||
		curlun->initially_ro = !!i;
 | 
			
		||||
		LDBG(curlun, "read-only status set to %d\n", curlun->ro);
 | 
			
		||||
	}
 | 
			
		||||
	up_read(filesem);
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
 | 
			
		||||
			      const char *buf, size_t count)
 | 
			
		||||
{
 | 
			
		||||
	struct fsg_lun	*curlun = fsg_lun_from_dev(dev);
 | 
			
		||||
	struct rw_semaphore	*filesem = dev_get_drvdata(dev);
 | 
			
		||||
	int		rc = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_USB_ANDROID_MASS_STORAGE
 | 
			
		||||
	/* disabled in android because we need to allow closing the backing file
 | 
			
		||||
	 * if the media was removed
 | 
			
		||||
	 */
 | 
			
		||||
	if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) {
 | 
			
		||||
		LDBG(curlun, "eject attempt prevented\n");
 | 
			
		||||
		return -EBUSY;				/* "Door is locked" */
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* Remove a trailing newline */
 | 
			
		||||
	if (count > 0 && buf[count-1] == '\n')
 | 
			
		||||
		((char *) buf)[count-1] = 0;		/* Ugh! */
 | 
			
		||||
 | 
			
		||||
	/* Eject current medium */
 | 
			
		||||
	down_write(filesem);
 | 
			
		||||
	if (fsg_lun_is_open(curlun)) {
 | 
			
		||||
		fsg_lun_close(curlun);
 | 
			
		||||
		curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Load new medium */
 | 
			
		||||
	if (count > 0 && buf[0]) {
 | 
			
		||||
		rc = fsg_lun_open(curlun, buf);
 | 
			
		||||
		if (rc == 0)
 | 
			
		||||
			curlun->unit_attention_data =
 | 
			
		||||
					SS_NOT_READY_TO_READY_TRANSITION;
 | 
			
		||||
	}
 | 
			
		||||
	up_write(filesem);
 | 
			
		||||
	return (rc < 0 ? rc : count);
 | 
			
		||||
}
 | 
			
		||||
@@ -93,6 +93,13 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
 | 
			
		||||
	if (!gadget_supports_altsettings(gadget))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	/* SA1100 can do ECM, *without* status endpoint ... but we'll
 | 
			
		||||
	 * only use it in non-ECM mode for backwards compatibility
 | 
			
		||||
	 * (and since we currently require a status endpoint)
 | 
			
		||||
	 */
 | 
			
		||||
	if (gadget_is_sa1100(gadget))
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	/* Everything else is *presumably* fine ... but this is a bit
 | 
			
		||||
	 * chancy, so be **CERTAIN** there are no hardware issues with
 | 
			
		||||
	 * your controller.  Add it above if it can't handle CDC.
 | 
			
		||||
@@ -105,7 +112,7 @@ int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
 | 
			
		||||
int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
 | 
			
		||||
int eem_bind_config(struct usb_configuration *c);
 | 
			
		||||
 | 
			
		||||
#if defined(USB_ETH_RNDIS) || defined(CONFIG_USB_ANDROID_RNDIS)
 | 
			
		||||
#if defined(CONFIG_USB_ETH_RNDIS) || defined(CONFIG_USB_ANDROID_RNDIS)
 | 
			
		||||
 | 
			
		||||
int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -70,11 +70,6 @@
 | 
			
		||||
#else
 | 
			
		||||
# define SLAB_NOTRACK		0x00000000UL
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CONFIG_FAILSLAB
 | 
			
		||||
# define SLAB_FAILSLAB		0x02000000UL	/* Fault injection mark */
 | 
			
		||||
#else
 | 
			
		||||
# define SLAB_FAILSLAB		0x00000000UL
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* The following flags affect the page allocator grouping pages by mobility */
 | 
			
		||||
#define SLAB_RECLAIM_ACCOUNT	0x00020000UL		/* Objects are reclaimable */
 | 
			
		||||
@@ -106,7 +101,6 @@ int kmem_cache_shrink(struct kmem_cache *);
 | 
			
		||||
void kmem_cache_free(struct kmem_cache *, void *);
 | 
			
		||||
unsigned int kmem_cache_size(struct kmem_cache *);
 | 
			
		||||
const char *kmem_cache_name(struct kmem_cache *);
 | 
			
		||||
int kern_ptr_validate(const void *ptr, unsigned long size);
 | 
			
		||||
int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,11 @@ struct android_usb_function {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct android_usb_product {
 | 
			
		||||
	/* Vendor ID for this set of functions.
 | 
			
		||||
	 * Default vendor_id in platform data will be used if this is zero.
 | 
			
		||||
	 */
 | 
			
		||||
	__u16 vendor_id;
 | 
			
		||||
 | 
			
		||||
	/* Default product ID. */
 | 
			
		||||
	__u16 product_id;
 | 
			
		||||
 | 
			
		||||
@@ -79,6 +84,9 @@ struct usb_mass_storage_platform_data {
 | 
			
		||||
 | 
			
		||||
	/* number of LUNS */
 | 
			
		||||
	int nluns;
 | 
			
		||||
 | 
			
		||||
	/* bitmap of lun to indicate cdrom disk*/
 | 
			
		||||
	int cdrom_lun;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Platform data for USB ethernet driver. */
 | 
			
		||||
@@ -88,9 +96,13 @@ struct usb_ether_platform_data {
 | 
			
		||||
	const char *vendorDescr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern void android_usb_set_connected(int on);
 | 
			
		||||
 | 
			
		||||
extern void android_register_function(struct android_usb_function *f);
 | 
			
		||||
 | 
			
		||||
extern void android_enable_function(struct usb_function *f, int enable);
 | 
			
		||||
 | 
			
		||||
extern int android_get_model_id(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif	/* __LINUX_USB_ANDROID_H */
 | 
			
		||||
 
 | 
			
		||||
@@ -36,10 +36,8 @@
 | 
			
		||||
 | 
			
		||||
#include <linux/usb/ch9.h>
 | 
			
		||||
#include <linux/usb/gadget.h>
 | 
			
		||||
#include <linux/switch.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct usb_composite_dev;
 | 
			
		||||
struct usb_configuration;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -102,9 +100,7 @@ struct usb_function {
 | 
			
		||||
	struct usb_descriptor_header	**hs_descriptors;
 | 
			
		||||
 | 
			
		||||
	struct usb_configuration	*config;
 | 
			
		||||
 | 
			
		||||
	/* disabled is zero if the function is enabled */
 | 
			
		||||
	int				disabled;
 | 
			
		||||
	int				hidden;
 | 
			
		||||
 | 
			
		||||
	/* REVISIT:  bind() functions can be marked __init, which
 | 
			
		||||
	 * makes trouble for section mismatch analysis.  See if
 | 
			
		||||
@@ -132,7 +128,6 @@ struct usb_function {
 | 
			
		||||
	/* private: */
 | 
			
		||||
	/* internals */
 | 
			
		||||
	struct list_head		list;
 | 
			
		||||
	DECLARE_BITMAP(endpoints, 32);
 | 
			
		||||
	struct device			*dev;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -143,9 +138,6 @@ int usb_function_activate(struct usb_function *);
 | 
			
		||||
 | 
			
		||||
int usb_interface_id(struct usb_configuration *, struct usb_function *);
 | 
			
		||||
 | 
			
		||||
void usb_function_set_enabled(struct usb_function *, int);
 | 
			
		||||
void usb_composite_force_reset(struct usb_composite_dev *);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ep_choose - select descriptor endpoint at current device speed
 | 
			
		||||
 * @g: gadget, connected and running at some speed
 | 
			
		||||
@@ -340,7 +332,6 @@ struct usb_composite_dev {
 | 
			
		||||
 | 
			
		||||
	/* private: */
 | 
			
		||||
	/* internals */
 | 
			
		||||
	unsigned int			suspended:1;
 | 
			
		||||
	struct usb_device_descriptor	desc;
 | 
			
		||||
	struct list_head		configs;
 | 
			
		||||
	struct usb_composite_driver	*driver;
 | 
			
		||||
@@ -353,15 +344,6 @@ struct usb_composite_dev {
 | 
			
		||||
 | 
			
		||||
	/* protects at least deactivation count */
 | 
			
		||||
	spinlock_t			lock;
 | 
			
		||||
 | 
			
		||||
	/* switch indicating connected/disconnected state */
 | 
			
		||||
	struct switch_dev    sw_connected;
 | 
			
		||||
  /* switch indicating current configuration */
 | 
			
		||||
  struct switch_dev    sw_config;
 | 
			
		||||
  /* current connected state for sw_connected */
 | 
			
		||||
  bool        connected;
 | 
			
		||||
 | 
			
		||||
	struct work_struct switch_work;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern int usb_string_id(struct usb_composite_dev *c);
 | 
			
		||||
 
 | 
			
		||||
@@ -15,8 +15,6 @@
 | 
			
		||||
#ifndef __LINUX_USB_GADGET_H
 | 
			
		||||
#define __LINUX_USB_GADGET_H
 | 
			
		||||
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
 | 
			
		||||
struct usb_ep;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -494,13 +492,9 @@ static inline void set_gadget_data(struct usb_gadget *gadget, void *data)
 | 
			
		||||
	{ dev_set_drvdata(&gadget->dev, data); }
 | 
			
		||||
static inline void *get_gadget_data(struct usb_gadget *gadget)
 | 
			
		||||
	{ return dev_get_drvdata(&gadget->dev); }
 | 
			
		||||
static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	return container_of(dev, struct usb_gadget, dev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */
 | 
			
		||||
#define gadget_for_each_ep(tmp, gadget) \
 | 
			
		||||
#define gadget_for_each_ep(tmp,gadget) \
 | 
			
		||||
	list_for_each_entry(tmp, &(gadget)->ep_list, ep_list)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user