diff options
Diffstat (limited to 'drivers/usb')
114 files changed, 2160 insertions, 3737 deletions
diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index d92ca325b10..4ab83e98219 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -17,5 +17,5 @@ ifneq ($(CONFIG_PCI),)  endif  ifneq ($(CONFIG_OF_DEVICE),) -	obj-$(CONFIG_USB_CHIPIDEA)	+= ci13xxx_imx.o usbmisc_imx6q.o +	obj-$(CONFIG_USB_CHIPIDEA)	+= ci13xxx_imx.o usbmisc_imx.o  endif diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index e25d1263da1..b0a6bce064c 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -21,6 +21,7 @@  /******************************************************************************   * DEFINE   *****************************************************************************/ +#define TD_PAGE_COUNT      5  #define CI13XXX_PAGE_SIZE  4096ul /* page size for TD's */  #define ENDPT_MAX          32 @@ -129,6 +130,7 @@ struct hw_bank {   * @vbus_active: is VBUS active   * @transceiver: pointer to USB PHY, if any   * @hcd: pointer to usb_hcd for ehci host driver + * @debugfs: root dentry for this controller in debugfs   */  struct ci13xxx {  	struct device			*dev; @@ -139,7 +141,6 @@ struct ci13xxx {  	enum ci_role			role;  	bool				is_otg;  	struct work_struct		work; -	struct work_struct		vbus_work;  	struct workqueue_struct		*wq;  	struct dma_pool			*qh_pool; @@ -165,6 +166,7 @@ struct ci13xxx {  	bool				global_phy;  	struct usb_phy			*transceiver;  	struct usb_hcd			*hcd; +	struct dentry			*debugfs;  };  static inline struct ci_role_driver *ci_role(struct ci13xxx *ci) @@ -234,19 +236,6 @@ enum ci13xxx_regs {  };  /** - * ffs_nr: find first (least significant) bit set - * @x: the word to search - * - * This function returns bit number (instead of position) - */ -static inline int ffs_nr(u32 x) -{ -	int n = ffs(x); - -	return n ? n-1 : 32; -} - -/**   * hw_read: reads from a hw register   * @reg:  register index   * @mask: bitfield mask @@ -304,7 +293,7 @@ static inline u32 hw_test_and_write(struct ci13xxx *ci, enum ci13xxx_regs reg,  	u32 val = hw_read(ci, reg, ~0);  	hw_write(ci, reg, mask, data); -	return (val & mask) >> ffs_nr(mask); +	return (val & mask) >> __ffs(mask);  }  int hw_device_reset(struct ci13xxx *ci, u32 mode); diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c index 8c291220be7..8faec9dbbb8 100644 --- a/drivers/usb/chipidea/ci13xxx_imx.c +++ b/drivers/usb/chipidea/ci13xxx_imx.c @@ -79,6 +79,9 @@ int usbmisc_get_init_data(struct device *dev, struct usbmisc_usb_device *usbdev)  	if (of_find_property(np, "disable-over-current", NULL))  		usbdev->disable_oc = 1; +	if (of_find_property(np, "external-vbus-divider", NULL)) +		usbdev->evdo = 1; +  	return 0;  }  EXPORT_SYMBOL_GPL(usbmisc_get_init_data); @@ -202,6 +205,15 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)  		goto err;  	} +	if (usbmisc_ops && usbmisc_ops->post) { +		ret = usbmisc_ops->post(&pdev->dev); +		if (ret) { +			dev_err(&pdev->dev, +				"usbmisc post failed, ret=%d\n", ret); +			goto put_np; +		} +	} +  	data->ci_pdev = plat_ci;  	platform_set_drvdata(pdev, data); diff --git a/drivers/usb/chipidea/ci13xxx_imx.h b/drivers/usb/chipidea/ci13xxx_imx.h index 9cd2e910b1c..550bfa45762 100644 --- a/drivers/usb/chipidea/ci13xxx_imx.h +++ b/drivers/usb/chipidea/ci13xxx_imx.h @@ -13,6 +13,8 @@  struct usbmisc_ops {  	/* It's called once when probe a usb device */  	int (*init)(struct device *dev); +	/* It's called once after adding a usb device */ +	int (*post)(struct device *dev);  };  struct usbmisc_usb_device { @@ -20,6 +22,7 @@ struct usbmisc_usb_device {  	int index;  	unsigned int disable_oc:1; /* over current detect disabled */ +	unsigned int evdo:1; /* set external vbus divider option */  };  int usbmisc_set_ops(const struct usbmisc_ops *ops); diff --git a/drivers/usb/chipidea/ci13xxx_pci.c b/drivers/usb/chipidea/ci13xxx_pci.c index 9b227e39299..4e1fc61b9d9 100644 --- a/drivers/usb/chipidea/ci13xxx_pci.c +++ b/drivers/usb/chipidea/ci13xxx_pci.c @@ -23,17 +23,17 @@  /******************************************************************************   * PCI block   *****************************************************************************/ -struct ci13xxx_platform_data pci_platdata = { +static struct ci13xxx_platform_data pci_platdata = {  	.name		= UDC_DRIVER_NAME,  	.capoffset	= DEF_CAPOFFSET,  }; -struct ci13xxx_platform_data langwell_pci_platdata = { +static struct ci13xxx_platform_data langwell_pci_platdata = {  	.name		= UDC_DRIVER_NAME,  	.capoffset	= 0,  }; -struct ci13xxx_platform_data penwell_pci_platdata = { +static struct ci13xxx_platform_data penwell_pci_platdata = {  	.name		= UDC_DRIVER_NAME,  	.capoffset	= 0,  	.power_budget	= 200, diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 57cae1f897b..450107e5f65 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -51,15 +51,12 @@   */  #include <linux/delay.h>  #include <linux/device.h> -#include <linux/dmapool.h>  #include <linux/dma-mapping.h> -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/module.h>  #include <linux/idr.h>  #include <linux/interrupt.h>  #include <linux/io.h> -#include <linux/irq.h>  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/pm_runtime.h> @@ -158,7 +155,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)  	if (mode > TEST_MODE_MAX)  		return -EINVAL; -	hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC)); +	hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << __ffs(PORTSC_PTC));  	return 0;  } @@ -169,7 +166,7 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode)   */  u8 hw_port_test_get(struct ci13xxx *ci)  { -	return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC); +	return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC);  }  static int hw_device_init(struct ci13xxx *ci, void __iomem *base) @@ -181,11 +178,11 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)  	ci->hw_bank.cap = ci->hw_bank.abs;  	ci->hw_bank.cap += ci->platdata->capoffset; -	ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap); +	ci->hw_bank.op = ci->hw_bank.cap + (ioread32(ci->hw_bank.cap) & 0xff);  	hw_alloc_regmap(ci, false);  	reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >> -		ffs_nr(HCCPARAMS_LEN); +		__ffs(HCCPARAMS_LEN);  	ci->hw_bank.lpm  = reg;  	hw_alloc_regmap(ci, !!reg);  	ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs; @@ -193,7 +190,7 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)  	ci->hw_bank.size /= sizeof(u32);  	reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >> -		ffs_nr(DCCPARAMS_DEN); +		__ffs(DCCPARAMS_DEN);  	ci->hw_ep_max = reg * 2;   /* cache hw ENDPT_MAX */  	if (ci->hw_ep_max > ENDPT_MAX) @@ -283,38 +280,6 @@ static void ci_role_work(struct work_struct *work)  	}  } -static ssize_t show_role(struct device *dev, struct device_attribute *attr, -			 char *buf) -{ -	struct ci13xxx *ci = dev_get_drvdata(dev); - -	return sprintf(buf, "%s\n", ci_role(ci)->name); -} - -static ssize_t store_role(struct device *dev, struct device_attribute *attr, -			  const char *buf, size_t count) -{ -	struct ci13xxx *ci = dev_get_drvdata(dev); -	enum ci_role role; -	int ret; - -	for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++) -		if (ci->roles[role] && !strcmp(buf, ci->roles[role]->name)) -			break; - -	if (role == CI_ROLE_END || role == ci->role) -		return -EINVAL; - -	ci_role_stop(ci); -	ret = ci_role_start(ci, role); -	if (ret) -		return ret; - -	return count; -} - -static DEVICE_ATTR(role, S_IRUSR | S_IWUSR, show_role, store_role); -  static irqreturn_t ci_irq(int irq, void *data)  {  	struct ci13xxx *ci = data; @@ -410,11 +375,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)  		return -ENODEV;  	} -	base = devm_request_and_ioremap(dev, res); -	if (!base) { -		dev_err(dev, "can't request and ioremap resource\n"); -		return -ENOMEM; -	} +	base = devm_ioremap_resource(dev, res); +	if (IS_ERR(base)) +		return PTR_ERR(base);  	ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL);  	if (!ci) { @@ -489,17 +452,14 @@ static int ci_hdrc_probe(struct platform_device *pdev)  	if (ret)  		goto stop; -	ret = device_create_file(dev, &dev_attr_role); -	if (ret) -		goto rm_attr; -  	if (ci->is_otg)  		hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE); -	return ret; +	ret = dbg_create_files(ci); +	if (!ret) +		return 0; -rm_attr: -	device_remove_file(dev, &dev_attr_role); +	free_irq(ci->irq, ci);  stop:  	ci_role_stop(ci);  rm_wq: @@ -513,9 +473,9 @@ static int ci_hdrc_remove(struct platform_device *pdev)  {  	struct ci13xxx *ci = platform_get_drvdata(pdev); +	dbg_remove_files(ci);  	flush_workqueue(ci->wq);  	destroy_workqueue(ci->wq); -	device_remove_file(ci->dev, &dev_attr_role);  	free_irq(ci->irq, ci);  	ci_role_stop(ci); diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index a62c4a47d52..36a7063a6cb 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -1,801 +1,301 @@ -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/dmapool.h> -#include <linux/dma-mapping.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irq.h>  #include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/pm_runtime.h> +#include <linux/device.h> +#include <linux/types.h> +#include <linux/spinlock.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/uaccess.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h> -#include <linux/usb/otg.h> -#include <linux/usb/chipidea.h>  #include "ci.h"  #include "udc.h"  #include "bits.h"  #include "debug.h" -/* Interrupt statistics */ -#define ISR_MASK   0x1F -static struct isr_statistics { -	u32 test; -	u32 ui; -	u32 uei; -	u32 pci; -	u32 uri; -	u32 sli; -	u32 none; -	struct { -		u32 cnt; -		u32 buf[ISR_MASK+1]; -		u32 idx; -	} hndl; -} isr_statistics; - -void dbg_interrupt(u32 intmask) -{ -	if (!intmask) { -		isr_statistics.none++; -		return; -	} - -	isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intmask; -	isr_statistics.hndl.idx &= ISR_MASK; -	isr_statistics.hndl.cnt++; - -	if (USBi_URI & intmask) -		isr_statistics.uri++; -	if (USBi_PCI & intmask) -		isr_statistics.pci++; -	if (USBi_UEI & intmask) -		isr_statistics.uei++; -	if (USBi_UI  & intmask) -		isr_statistics.ui++; -	if (USBi_SLI & intmask) -		isr_statistics.sli++; -} - -/** - * hw_register_read: reads all device registers (execute without interruption) - * @buf:  destination buffer - * @size: buffer size - * - * This function returns number of registers read - */ -static size_t hw_register_read(struct ci13xxx *ci, u32 *buf, size_t size) -{ -	unsigned i; - -	if (size > ci->hw_bank.size) -		size = ci->hw_bank.size; - -	for (i = 0; i < size; i++) -		buf[i] = hw_read(ci, i * sizeof(u32), ~0); - -	return size; -} - -/** - * hw_register_write: writes to register - * @addr: register address - * @data: register value - * - * This function returns an error code - */ -static int hw_register_write(struct ci13xxx *ci, u16 addr, u32 data) -{ -	/* align */ -	addr /= sizeof(u32); - -	if (addr >= ci->hw_bank.size) -		return -EINVAL; - -	/* align */ -	addr *= sizeof(u32); - -	hw_write(ci, addr, ~0, data); -	return 0; -} -  /** - * hw_intr_clear: disables interrupt & clears interrupt status (execute without - *                interruption) - * @n: interrupt bit - * - * This function returns an error code + * ci_device_show: prints information about device capabilities and status   */ -static int hw_intr_clear(struct ci13xxx *ci, int n) +static int ci_device_show(struct seq_file *s, void *data)  { -	if (n >= REG_BITS) -		return -EINVAL; - -	hw_write(ci, OP_USBINTR, BIT(n), 0); -	hw_write(ci, OP_USBSTS,  BIT(n), BIT(n)); -	return 0; -} - -/** - * hw_intr_force: enables interrupt & forces interrupt status (execute without - *                interruption) - * @n: interrupt bit - * - * This function returns an error code - */ -static int hw_intr_force(struct ci13xxx *ci, int n) -{ -	if (n >= REG_BITS) -		return -EINVAL; - -	hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE); -	hw_write(ci, OP_USBINTR,  BIT(n), BIT(n)); -	hw_write(ci, OP_USBSTS,   BIT(n), BIT(n)); -	hw_write(ci, CAP_TESTMODE, TESTMODE_FORCE, 0); -	return 0; -} - -/** - * show_device: prints information about device capabilities and status - * - * Check "device.h" for details - */ -static ssize_t show_device(struct device *dev, struct device_attribute *attr, -			   char *buf) -{ -	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); +	struct ci13xxx *ci = s->private;  	struct usb_gadget *gadget = &ci->gadget; -	int n = 0; - -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "[%s] EINVAL\n", __func__); -		return 0; -	} -	n += scnprintf(buf + n, PAGE_SIZE - n, "speed             = %d\n", -		       gadget->speed); -	n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed         = %d\n", -		       gadget->max_speed); -	n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg            = %d\n", -		       gadget->is_otg); -	n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral   = %d\n", -		       gadget->is_a_peripheral); -	n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable      = %d\n", -		       gadget->b_hnp_enable); -	n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support     = %d\n", -		       gadget->a_hnp_support); -	n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n", -		       gadget->a_alt_hnp_support); -	n += scnprintf(buf + n, PAGE_SIZE - n, "name              = %s\n", -		       (gadget->name ? gadget->name : "")); - -	return n; -} -static DEVICE_ATTR(device, S_IRUSR, show_device, NULL); +	seq_printf(s, "speed             = %d\n", gadget->speed); +	seq_printf(s, "max_speed         = %d\n", gadget->max_speed); +	seq_printf(s, "is_otg            = %d\n", gadget->is_otg); +	seq_printf(s, "is_a_peripheral   = %d\n", gadget->is_a_peripheral); +	seq_printf(s, "b_hnp_enable      = %d\n", gadget->b_hnp_enable); +	seq_printf(s, "a_hnp_support     = %d\n", gadget->a_hnp_support); +	seq_printf(s, "a_alt_hnp_support = %d\n", gadget->a_alt_hnp_support); +	seq_printf(s, "name              = %s\n", +		   (gadget->name ? gadget->name : "")); -/** - * show_driver: prints information about attached gadget (if any) - * - * Check "device.h" for details - */ -static ssize_t show_driver(struct device *dev, struct device_attribute *attr, -			   char *buf) -{ -	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); -	struct usb_gadget_driver *driver = ci->driver; -	int n = 0; - -	if (attr == NULL || buf == NULL) { -		dev_err(dev, "[%s] EINVAL\n", __func__); +	if (!ci->driver)  		return 0; -	} - -	if (driver == NULL) -		return scnprintf(buf, PAGE_SIZE, -				 "There is no gadget attached!\n"); -	n += scnprintf(buf + n, PAGE_SIZE - n, "function  = %s\n", -		       (driver->function ? driver->function : "")); -	n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n", -		       driver->max_speed); +	seq_printf(s, "gadget function   = %s\n", +		       (ci->driver->function ? ci->driver->function : "")); +	seq_printf(s, "gadget max speed  = %d\n", ci->driver->max_speed); -	return n; +	return 0;  } -static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL); - -/* Maximum event message length */ -#define DBG_DATA_MSG   64UL - -/* Maximum event messages */ -#define DBG_DATA_MAX   128UL - -/* Event buffer descriptor */ -static struct { -	char     (buf[DBG_DATA_MAX])[DBG_DATA_MSG];   /* buffer */ -	unsigned idx;   /* index */ -	unsigned tty;   /* print to console? */ -	rwlock_t lck;   /* lock */ -} dbg_data = { -	.idx = 0, -	.tty = 0, -	.lck = __RW_LOCK_UNLOCKED(dbg_data.lck) -}; -/** - * dbg_dec: decrements debug event index - * @idx: buffer index - */ -static void dbg_dec(unsigned *idx) +static int ci_device_open(struct inode *inode, struct file *file)  { -	*idx = (*idx - 1) & (DBG_DATA_MAX-1); +	return single_open(file, ci_device_show, inode->i_private);  } -/** - * dbg_inc: increments debug event index - * @idx: buffer index - */ -static void dbg_inc(unsigned *idx) -{ -	*idx = (*idx + 1) & (DBG_DATA_MAX-1); -} +static const struct file_operations ci_device_fops = { +	.open		= ci_device_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +};  /** - * dbg_print:  prints the common part of the event - * @addr:   endpoint address - * @name:   event name - * @status: status - * @extra:  extra information + * ci_port_test_show: reads port test mode   */ -static void dbg_print(u8 addr, const char *name, int status, const char *extra) +static int ci_port_test_show(struct seq_file *s, void *data)  { -	struct timeval tval; -	unsigned int stamp; +	struct ci13xxx *ci = s->private;  	unsigned long flags; +	unsigned mode; -	write_lock_irqsave(&dbg_data.lck, flags); - -	do_gettimeofday(&tval); -	stamp = tval.tv_sec & 0xFFFF;	/* 2^32 = 4294967296. Limit to 4096s */ -	stamp = stamp * 1000000 + tval.tv_usec; - -	scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG, -		  "%04X\t? %02X %-7.7s %4i ?\t%s\n", -		  stamp, addr, name, status, extra); - -	dbg_inc(&dbg_data.idx); - -	write_unlock_irqrestore(&dbg_data.lck, flags); - -	if (dbg_data.tty != 0) -		pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n", -			  stamp, addr, name, status, extra); -} - -/** - * dbg_done: prints a DONE event - * @addr:   endpoint address - * @td:     transfer descriptor - * @status: status - */ -void dbg_done(u8 addr, const u32 token, int status) -{ -	char msg[DBG_DATA_MSG]; - -	scnprintf(msg, sizeof(msg), "%d %02X", -		  (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES), -		  (int)(token & TD_STATUS)      >> ffs_nr(TD_STATUS)); -	dbg_print(addr, "DONE", status, msg); -} - -/** - * dbg_event: prints a generic event - * @addr:   endpoint address - * @name:   event name - * @status: status - */ -void dbg_event(u8 addr, const char *name, int status) -{ -	if (name != NULL) -		dbg_print(addr, name, status, ""); -} - -/* - * dbg_queue: prints a QUEUE event - * @addr:   endpoint address - * @req:    USB request - * @status: status - */ -void dbg_queue(u8 addr, const struct usb_request *req, int status) -{ -	char msg[DBG_DATA_MSG]; - -	if (req != NULL) { -		scnprintf(msg, sizeof(msg), -			  "%d %d", !req->no_interrupt, req->length); -		dbg_print(addr, "QUEUE", status, msg); -	} -} +	spin_lock_irqsave(&ci->lock, flags); +	mode = hw_port_test_get(ci); +	spin_unlock_irqrestore(&ci->lock, flags); -/** - * dbg_setup: prints a SETUP event - * @addr: endpoint address - * @req:  setup request - */ -void dbg_setup(u8 addr, const struct usb_ctrlrequest *req) -{ -	char msg[DBG_DATA_MSG]; +	seq_printf(s, "mode = %u\n", mode); -	if (req != NULL) { -		scnprintf(msg, sizeof(msg), -			  "%02X %02X %04X %04X %d", req->bRequestType, -			  req->bRequest, le16_to_cpu(req->wValue), -			  le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength)); -		dbg_print(addr, "SETUP", 0, msg); -	} +	return 0;  }  /** - * show_events: displays the event buffer - * - * Check "device.h" for details + * ci_port_test_write: writes port test mode   */ -static ssize_t show_events(struct device *dev, struct device_attribute *attr, -			   char *buf) +static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf, +				  size_t count, loff_t *ppos)  { +	struct seq_file *s = file->private_data; +	struct ci13xxx *ci = s->private;  	unsigned long flags; -	unsigned i, j, n = 0; - -	if (attr == NULL || buf == NULL) { -		dev_err(dev->parent, "[%s] EINVAL\n", __func__); -		return 0; -	} +	unsigned mode; +	char buf[32]; +	int ret; -	read_lock_irqsave(&dbg_data.lck, flags); +	if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) +		return -EFAULT; -	i = dbg_data.idx; -	for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) { -		n += strlen(dbg_data.buf[i]); -		if (n >= PAGE_SIZE) { -			n -= strlen(dbg_data.buf[i]); -			break; -		} -	} -	for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i)) -		j += scnprintf(buf + j, PAGE_SIZE - j, -			       "%s", dbg_data.buf[i]); +	if (sscanf(buf, "%u", &mode) != 1) +		return -EINVAL; -	read_unlock_irqrestore(&dbg_data.lck, flags); +	spin_lock_irqsave(&ci->lock, flags); +	ret = hw_port_test_set(ci, mode); +	spin_unlock_irqrestore(&ci->lock, flags); -	return n; +	return ret ? ret : count;  } -/** - * store_events: configure if events are going to be also printed to console - * - * Check "device.h" for details - */ -static ssize_t store_events(struct device *dev, struct device_attribute *attr, -			    const char *buf, size_t count) +static int ci_port_test_open(struct inode *inode, struct file *file)  { -	unsigned tty; - -	if (attr == NULL || buf == NULL) { -		dev_err(dev, "[%s] EINVAL\n", __func__); -		goto done; -	} - -	if (sscanf(buf, "%u", &tty) != 1 || tty > 1) { -		dev_err(dev, "<1|0>: enable|disable console log\n"); -		goto done; -	} - -	dbg_data.tty = tty; -	dev_info(dev, "tty = %u", dbg_data.tty); - - done: -	return count; +	return single_open(file, ci_port_test_show, inode->i_private);  } -static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events); + +static const struct file_operations ci_port_test_fops = { +	.open		= ci_port_test_open, +	.write		= ci_port_test_write, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +};  /** - * show_inters: interrupt status, enable status and historic - * - * Check "device.h" for details + * ci_qheads_show: DMA contents of all queue heads   */ -static ssize_t show_inters(struct device *dev, struct device_attribute *attr, -			   char *buf) +static int ci_qheads_show(struct seq_file *s, void *data)  { -	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); +	struct ci13xxx *ci = s->private;  	unsigned long flags; -	u32 intr; -	unsigned i, j, n = 0; +	unsigned i, j; -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "[%s] EINVAL\n", __func__); +	if (ci->role != CI_ROLE_GADGET) { +		seq_printf(s, "not in gadget mode\n");  		return 0;  	}  	spin_lock_irqsave(&ci->lock, flags); - -	/*n += scnprintf(buf + n, PAGE_SIZE - n, -		       "status = %08x\n", hw_read_intr_status(ci)); -	n += scnprintf(buf + n, PAGE_SIZE - n, -	"enable = %08x\n", hw_read_intr_enable(ci));*/ - -	n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n", -		       isr_statistics.test); -	n += scnprintf(buf + n, PAGE_SIZE - n, "? ui  = %d\n", -		       isr_statistics.ui); -	n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n", -		       isr_statistics.uei); -	n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n", -		       isr_statistics.pci); -	n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n", -		       isr_statistics.uri); -	n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n", -		       isr_statistics.sli); -	n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n", -		       isr_statistics.none); -	n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n", -		       isr_statistics.hndl.cnt); - -	for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) { -		i   &= ISR_MASK; -		intr = isr_statistics.hndl.buf[i]; - -		if (USBi_UI  & intr) -			n += scnprintf(buf + n, PAGE_SIZE - n, "ui  "); -		intr &= ~USBi_UI; -		if (USBi_UEI & intr) -			n += scnprintf(buf + n, PAGE_SIZE - n, "uei "); -		intr &= ~USBi_UEI; -		if (USBi_PCI & intr) -			n += scnprintf(buf + n, PAGE_SIZE - n, "pci "); -		intr &= ~USBi_PCI; -		if (USBi_URI & intr) -			n += scnprintf(buf + n, PAGE_SIZE - n, "uri "); -		intr &= ~USBi_URI; -		if (USBi_SLI & intr) -			n += scnprintf(buf + n, PAGE_SIZE - n, "sli "); -		intr &= ~USBi_SLI; -		if (intr) -			n += scnprintf(buf + n, PAGE_SIZE - n, "??? "); -		if (isr_statistics.hndl.buf[i]) -			n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); +	for (i = 0; i < ci->hw_ep_max/2; i++) { +		struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i]; +		struct ci13xxx_ep *mEpTx = +			&ci->ci13xxx_ep[i + ci->hw_ep_max/2]; +		seq_printf(s, "EP=%02i: RX=%08X TX=%08X\n", +			   i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma); +		for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) +			seq_printf(s, " %04X:    %08X    %08X\n", j, +				   *((u32 *)mEpRx->qh.ptr + j), +				   *((u32 *)mEpTx->qh.ptr + j));  	} -  	spin_unlock_irqrestore(&ci->lock, flags); -	return n; +	return 0;  } -/** - * store_inters: enable & force or disable an individual interrutps - *                   (to be used for test purposes only) - * - * Check "device.h" for details - */ -static ssize_t store_inters(struct device *dev, struct device_attribute *attr, -			    const char *buf, size_t count) +static int ci_qheads_open(struct inode *inode, struct file *file)  { -	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); -	unsigned long flags; -	unsigned en, bit; - -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "EINVAL\n"); -		goto done; -	} - -	if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) { -		dev_err(ci->dev, "<1|0> <bit>: enable|disable interrupt\n"); -		goto done; -	} - -	spin_lock_irqsave(&ci->lock, flags); -	if (en) { -		if (hw_intr_force(ci, bit)) -			dev_err(dev, "invalid bit number\n"); -		else -			isr_statistics.test++; -	} else { -		if (hw_intr_clear(ci, bit)) -			dev_err(dev, "invalid bit number\n"); -	} -	spin_unlock_irqrestore(&ci->lock, flags); - - done: -	return count; +	return single_open(file, ci_qheads_show, inode->i_private);  } -static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters); + +static const struct file_operations ci_qheads_fops = { +	.open		= ci_qheads_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +};  /** - * show_port_test: reads port test mode - * - * Check "device.h" for details + * ci_requests_show: DMA contents of all requests currently queued (all endpts)   */ -static ssize_t show_port_test(struct device *dev, -			      struct device_attribute *attr, char *buf) +static int ci_requests_show(struct seq_file *s, void *data)  { -	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); +	struct ci13xxx *ci = s->private;  	unsigned long flags; -	unsigned mode; +	struct list_head   *ptr = NULL; +	struct ci13xxx_req *req = NULL; +	unsigned i, j, qsize = sizeof(struct ci13xxx_td)/sizeof(u32); -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "EINVAL\n"); +	if (ci->role != CI_ROLE_GADGET) { +		seq_printf(s, "not in gadget mode\n");  		return 0;  	}  	spin_lock_irqsave(&ci->lock, flags); -	mode = hw_port_test_get(ci); -	spin_unlock_irqrestore(&ci->lock, flags); - -	return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode); -} - -/** - * store_port_test: writes port test mode - * - * Check "device.h" for details - */ -static ssize_t store_port_test(struct device *dev, -			       struct device_attribute *attr, -			       const char *buf, size_t count) -{ -	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); -	unsigned long flags; -	unsigned mode; +	for (i = 0; i < ci->hw_ep_max; i++) +		list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue) { +			req = list_entry(ptr, struct ci13xxx_req, queue); -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "[%s] EINVAL\n", __func__); -		goto done; -	} +			seq_printf(s, "EP=%02i: TD=%08X %s\n", +				   i % (ci->hw_ep_max / 2), (u32)req->dma, +				   ((i < ci->hw_ep_max/2) ? "RX" : "TX")); -	if (sscanf(buf, "%u", &mode) != 1) { -		dev_err(ci->dev, "<mode>: set port test mode"); -		goto done; -	} - -	spin_lock_irqsave(&ci->lock, flags); -	if (hw_port_test_set(ci, mode)) -		dev_err(ci->dev, "invalid mode\n"); +			for (j = 0; j < qsize; j++) +				seq_printf(s, " %04X:    %08X\n", j, +					   *((u32 *)req->ptr + j)); +		}  	spin_unlock_irqrestore(&ci->lock, flags); - done: -	return count; +	return 0;  } -static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR, -		   show_port_test, store_port_test); -/** - * show_qheads: DMA contents of all queue heads - * - * Check "device.h" for details - */ -static ssize_t show_qheads(struct device *dev, struct device_attribute *attr, -			   char *buf) +static int ci_requests_open(struct inode *inode, struct file *file)  { -	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); -	unsigned long flags; -	unsigned i, j, n = 0; +	return single_open(file, ci_requests_show, inode->i_private); +} -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "[%s] EINVAL\n", __func__); -		return 0; -	} +static const struct file_operations ci_requests_fops = { +	.open		= ci_requests_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +}; -	spin_lock_irqsave(&ci->lock, flags); -	for (i = 0; i < ci->hw_ep_max/2; i++) { -		struct ci13xxx_ep *mEpRx = &ci->ci13xxx_ep[i]; -		struct ci13xxx_ep *mEpTx = -			&ci->ci13xxx_ep[i + ci->hw_ep_max/2]; -		n += scnprintf(buf + n, PAGE_SIZE - n, -			       "EP=%02i: RX=%08X TX=%08X\n", -			       i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma); -		for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) { -			n += scnprintf(buf + n, PAGE_SIZE - n, -				       " %04X:    %08X    %08X\n", j, -				       *((u32 *)mEpRx->qh.ptr + j), -				       *((u32 *)mEpTx->qh.ptr + j)); -		} -	} -	spin_unlock_irqrestore(&ci->lock, flags); +static int ci_role_show(struct seq_file *s, void *data) +{ +	struct ci13xxx *ci = s->private; -	return n; +	seq_printf(s, "%s\n", ci_role(ci)->name); + +	return 0;  } -static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL); -/** - * show_registers: dumps all registers - * - * Check "device.h" for details - */ -#define DUMP_ENTRIES	512 -static ssize_t show_registers(struct device *dev, -			      struct device_attribute *attr, char *buf) +static ssize_t ci_role_write(struct file *file, const char __user *ubuf, +			     size_t count, loff_t *ppos)  { -	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); -	unsigned long flags; -	u32 *dump; -	unsigned i, k, n = 0; +	struct seq_file *s = file->private_data; +	struct ci13xxx *ci = s->private; +	enum ci_role role; +	char buf[8]; +	int ret; -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "[%s] EINVAL\n", __func__); -		return 0; -	} +	if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) +		return -EFAULT; -	dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL); -	if (!dump) { -		dev_err(ci->dev, "%s: out of memory\n", __func__); -		return 0; -	} +	for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++) +		if (ci->roles[role] && +		    !strncmp(buf, ci->roles[role]->name, +			     strlen(ci->roles[role]->name))) +			break; -	spin_lock_irqsave(&ci->lock, flags); -	k = hw_register_read(ci, dump, DUMP_ENTRIES); -	spin_unlock_irqrestore(&ci->lock, flags); +	if (role == CI_ROLE_END || role == ci->role) +		return -EINVAL; -	for (i = 0; i < k; i++) { -		n += scnprintf(buf + n, PAGE_SIZE - n, -			       "reg[0x%04X] = 0x%08X\n", -			       i * (unsigned)sizeof(u32), dump[i]); -	} -	kfree(dump); +	ci_role_stop(ci); +	ret = ci_role_start(ci, role); -	return n; +	return ret ? ret : count;  } -/** - * store_registers: writes value to register address - * - * Check "device.h" for details - */ -static ssize_t store_registers(struct device *dev, -			       struct device_attribute *attr, -			       const char *buf, size_t count) +static int ci_role_open(struct inode *inode, struct file *file)  { -	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); -	unsigned long addr, data, flags; - -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "[%s] EINVAL\n", __func__); -		goto done; -	} - -	if (sscanf(buf, "%li %li", &addr, &data) != 2) { -		dev_err(ci->dev, -			"<addr> <data>: write data to register address\n"); -		goto done; -	} - -	spin_lock_irqsave(&ci->lock, flags); -	if (hw_register_write(ci, addr, data)) -		dev_err(ci->dev, "invalid address range\n"); -	spin_unlock_irqrestore(&ci->lock, flags); - - done: -	return count; +	return single_open(file, ci_role_show, inode->i_private);  } -static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR, -		   show_registers, store_registers); + +static const struct file_operations ci_role_fops = { +	.open		= ci_role_open, +	.write		= ci_role_write, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +};  /** - * show_requests: DMA contents of all requests currently queued (all endpts) + * dbg_create_files: initializes the attribute interface + * @ci: device   * - * Check "device.h" for details + * This function returns an error code   */ -static ssize_t show_requests(struct device *dev, struct device_attribute *attr, -			     char *buf) +int dbg_create_files(struct ci13xxx *ci)  { -	struct ci13xxx *ci = container_of(dev, struct ci13xxx, gadget.dev); -	unsigned long flags; -	struct list_head   *ptr = NULL; -	struct ci13xxx_req *req = NULL; -	unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32); +	struct dentry *dent; -	if (attr == NULL || buf == NULL) { -		dev_err(ci->dev, "[%s] EINVAL\n", __func__); -		return 0; -	} +	ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL); +	if (!ci->debugfs) +		return -ENOMEM; -	spin_lock_irqsave(&ci->lock, flags); -	for (i = 0; i < ci->hw_ep_max; i++) -		list_for_each(ptr, &ci->ci13xxx_ep[i].qh.queue) -		{ -			req = list_entry(ptr, struct ci13xxx_req, queue); +	dent = debugfs_create_file("device", S_IRUGO, ci->debugfs, ci, +				   &ci_device_fops); +	if (!dent) +		goto err; -			n += scnprintf(buf + n, PAGE_SIZE - n, -					"EP=%02i: TD=%08X %s\n", -					i % ci->hw_ep_max/2, (u32)req->dma, -					((i < ci->hw_ep_max/2) ? "RX" : "TX")); +	dent = debugfs_create_file("port_test", S_IRUGO | S_IWUSR, ci->debugfs, +				   ci, &ci_port_test_fops); +	if (!dent) +		goto err; -			for (j = 0; j < qSize; j++) -				n += scnprintf(buf + n, PAGE_SIZE - n, -						" %04X:    %08X\n", j, -						*((u32 *)req->ptr + j)); -		} -	spin_unlock_irqrestore(&ci->lock, flags); +	dent = debugfs_create_file("qheads", S_IRUGO, ci->debugfs, ci, +				   &ci_qheads_fops); +	if (!dent) +		goto err; -	return n; -} -static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL); +	dent = debugfs_create_file("requests", S_IRUGO, ci->debugfs, ci, +				   &ci_requests_fops); +	if (!dent) +		goto err; -/** - * dbg_create_files: initializes the attribute interface - * @dev: device - * - * This function returns an error code - */ -int dbg_create_files(struct device *dev) -{ -	int retval = 0; - -	if (dev == NULL) -		return -EINVAL; -	retval = device_create_file(dev, &dev_attr_device); -	if (retval) -		goto done; -	retval = device_create_file(dev, &dev_attr_driver); -	if (retval) -		goto rm_device; -	retval = device_create_file(dev, &dev_attr_events); -	if (retval) -		goto rm_driver; -	retval = device_create_file(dev, &dev_attr_inters); -	if (retval) -		goto rm_events; -	retval = device_create_file(dev, &dev_attr_port_test); -	if (retval) -		goto rm_inters; -	retval = device_create_file(dev, &dev_attr_qheads); -	if (retval) -		goto rm_port_test; -	retval = device_create_file(dev, &dev_attr_registers); -	if (retval) -		goto rm_qheads; -	retval = device_create_file(dev, &dev_attr_requests); -	if (retval) -		goto rm_registers; -	return 0; - - rm_registers: -	device_remove_file(dev, &dev_attr_registers); - rm_qheads: -	device_remove_file(dev, &dev_attr_qheads); - rm_port_test: -	device_remove_file(dev, &dev_attr_port_test); - rm_inters: -	device_remove_file(dev, &dev_attr_inters); - rm_events: -	device_remove_file(dev, &dev_attr_events); - rm_driver: -	device_remove_file(dev, &dev_attr_driver); - rm_device: -	device_remove_file(dev, &dev_attr_device); - done: -	return retval; +	dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci, +				   &ci_role_fops); +	if (dent) +		return 0; +err: +	debugfs_remove_recursive(ci->debugfs); +	return -ENOMEM;  }  /**   * dbg_remove_files: destroys the attribute interface - * @dev: device - * - * This function returns an error code + * @ci: device   */ -int dbg_remove_files(struct device *dev) +void dbg_remove_files(struct ci13xxx *ci)  { -	if (dev == NULL) -		return -EINVAL; -	device_remove_file(dev, &dev_attr_requests); -	device_remove_file(dev, &dev_attr_registers); -	device_remove_file(dev, &dev_attr_qheads); -	device_remove_file(dev, &dev_attr_port_test); -	device_remove_file(dev, &dev_attr_inters); -	device_remove_file(dev, &dev_attr_events); -	device_remove_file(dev, &dev_attr_driver); -	device_remove_file(dev, &dev_attr_device); -	return 0; +	debugfs_remove_recursive(ci->debugfs);  } diff --git a/drivers/usb/chipidea/debug.h b/drivers/usb/chipidea/debug.h index 80d96865775..7ca6ca0a24a 100644 --- a/drivers/usb/chipidea/debug.h +++ b/drivers/usb/chipidea/debug.h @@ -14,42 +14,16 @@  #define __DRIVERS_USB_CHIPIDEA_DEBUG_H  #ifdef CONFIG_USB_CHIPIDEA_DEBUG -void dbg_interrupt(u32 intmask); -void dbg_done(u8 addr, const u32 token, int status); -void dbg_event(u8 addr, const char *name, int status); -void dbg_queue(u8 addr, const struct usb_request *req, int status); -void dbg_setup(u8 addr, const struct usb_ctrlrequest *req); -int dbg_create_files(struct device *dev); -int dbg_remove_files(struct device *dev); +int dbg_create_files(struct ci13xxx *ci); +void dbg_remove_files(struct ci13xxx *ci);  #else -static inline void dbg_interrupt(u32 intmask) -{ -} - -static inline void dbg_done(u8 addr, const u32 token, int status) -{ -} - -static inline void dbg_event(u8 addr, const char *name, int status) -{ -} - -static inline void dbg_queue(u8 addr, const struct usb_request *req, int status) -{ -} - -static inline void dbg_setup(u8 addr, const struct usb_ctrlrequest *req) -{ -} - -static inline int dbg_create_files(struct device *dev) +static inline int dbg_create_files(struct ci13xxx *ci)  {  	return 0;  } -static inline int dbg_remove_files(struct device *dev) +static inline void dbg_remove_files(struct ci13xxx *ci)  { -	return 0;  }  #endif diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 9bddf3f633f..519ead2443c 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -13,14 +13,8 @@  #include <linux/delay.h>  #include <linux/device.h>  #include <linux/dmapool.h> -#include <linux/dma-mapping.h>  #include <linux/err.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irq.h> +#include <linux/irqreturn.h>  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/pm_runtime.h> @@ -146,7 +140,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)  	if (dir) {  		mask  = ENDPTCTRL_TXT;  /* type    */ -		data  = type << ffs_nr(mask); +		data  = type << __ffs(mask);  		mask |= ENDPTCTRL_TXS;  /* unstall */  		mask |= ENDPTCTRL_TXR;  /* reset data toggle */ @@ -155,7 +149,7 @@ static int hw_ep_enable(struct ci13xxx *ci, int num, int dir, int type)  		data |= ENDPTCTRL_TXE;  	} else {  		mask  = ENDPTCTRL_RXT;  /* type    */ -		data  = type << ffs_nr(mask); +		data  = type << __ffs(mask);  		mask |= ENDPTCTRL_RXS;  /* unstall */  		mask |= ENDPTCTRL_RXR;  /* reset data toggle */ @@ -305,18 +299,6 @@ static u32 hw_test_and_clear_intr_active(struct ci13xxx *ci)  	return reg;  } -static void hw_enable_vbus_intr(struct ci13xxx *ci) -{ -	hw_write(ci, OP_OTGSC, OTGSC_AVVIS, OTGSC_AVVIS); -	hw_write(ci, OP_OTGSC, OTGSC_AVVIE, OTGSC_AVVIE); -	queue_work(ci->wq, &ci->vbus_work); -} - -static void hw_disable_vbus_intr(struct ci13xxx *ci) -{ -	hw_write(ci, OP_OTGSC, OTGSC_AVVIE, 0); -} -  /**   * hw_test_and_clear_setup_guard: test & clear setup guard (execute without   *                                interruption) @@ -349,7 +331,7 @@ static int hw_test_and_set_setup_guard(struct ci13xxx *ci)  static void hw_usb_set_address(struct ci13xxx *ci, u8 value)  {  	hw_write(ci, OP_DEVICEADDR, DEVICEADDR_USBADR, -		 value << ffs_nr(DEVICEADDR_USBADR)); +		 value << __ffs(DEVICEADDR_USBADR));  }  /** @@ -383,16 +365,6 @@ static int hw_usb_reset(struct ci13xxx *ci)  	return 0;  } -static void vbus_work(struct work_struct *work) -{ -	struct ci13xxx *ci = container_of(work, struct ci13xxx, vbus_work); - -	if (hw_read(ci, OP_OTGSC, OTGSC_AVV)) -		usb_gadget_vbus_connect(&ci->gadget); -	else -		usb_gadget_vbus_disconnect(&ci->gadget); -} -  /******************************************************************************   * UTIL block   *****************************************************************************/ @@ -432,10 +404,10 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)  			return -ENOMEM;  		memset(mReq->zptr, 0, sizeof(*mReq->zptr)); -		mReq->zptr->next    = TD_TERMINATE; -		mReq->zptr->token   = TD_STATUS_ACTIVE; +		mReq->zptr->next    = cpu_to_le32(TD_TERMINATE); +		mReq->zptr->token   = cpu_to_le32(TD_STATUS_ACTIVE);  		if (!mReq->req.no_interrupt) -			mReq->zptr->token   |= TD_IOC; +			mReq->zptr->token   |= cpu_to_le32(TD_IOC);  	}  	ret = usb_gadget_map_request(&ci->gadget, &mReq->req, mEp->dir);  	if (ret) @@ -446,32 +418,37 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)  	 * TODO - handle requests which spawns into several TDs  	 */  	memset(mReq->ptr, 0, sizeof(*mReq->ptr)); -	mReq->ptr->token    = length << ffs_nr(TD_TOTAL_BYTES); -	mReq->ptr->token   &= TD_TOTAL_BYTES; -	mReq->ptr->token   |= TD_STATUS_ACTIVE; +	mReq->ptr->token    = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES)); +	mReq->ptr->token   &= cpu_to_le32(TD_TOTAL_BYTES); +	mReq->ptr->token   |= cpu_to_le32(TD_STATUS_ACTIVE);  	if (mReq->zptr) { -		mReq->ptr->next    = mReq->zdma; +		mReq->ptr->next    = cpu_to_le32(mReq->zdma);  	} else { -		mReq->ptr->next    = TD_TERMINATE; +		mReq->ptr->next    = cpu_to_le32(TD_TERMINATE);  		if (!mReq->req.no_interrupt) -			mReq->ptr->token  |= TD_IOC; +			mReq->ptr->token  |= cpu_to_le32(TD_IOC); +	} +	mReq->ptr->page[0]  = cpu_to_le32(mReq->req.dma); +	for (i = 1; i < TD_PAGE_COUNT; i++) { +		u32 page = mReq->req.dma + i * CI13XXX_PAGE_SIZE; +		page &= ~TD_RESERVED_MASK; +		mReq->ptr->page[i] = cpu_to_le32(page);  	} -	mReq->ptr->page[0]  = mReq->req.dma; -	for (i = 1; i < 5; i++) -		mReq->ptr->page[i] = -			(mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK; + +	wmb();  	if (!list_empty(&mEp->qh.queue)) {  		struct ci13xxx_req *mReqPrev;  		int n = hw_ep_bit(mEp->num, mEp->dir);  		int tmp_stat; +		u32 next = mReq->dma & TD_ADDR_MASK;  		mReqPrev = list_entry(mEp->qh.queue.prev,  				struct ci13xxx_req, queue);  		if (mReqPrev->zptr) -			mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK; +			mReqPrev->zptr->next = cpu_to_le32(next);  		else -			mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK; +			mReqPrev->ptr->next = cpu_to_le32(next);  		wmb();  		if (hw_read(ci, OP_ENDPTPRIME, BIT(n)))  			goto done; @@ -485,9 +462,9 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)  	}  	/*  QH configuration */ -	mEp->qh.ptr->td.next   = mReq->dma;    /* TERMINATE = 0 */ -	mEp->qh.ptr->td.token &= ~TD_STATUS;   /* clear status */ -	mEp->qh.ptr->cap |=  QH_ZLT; +	mEp->qh.ptr->td.next   = cpu_to_le32(mReq->dma);    /* TERMINATE = 0 */ +	mEp->qh.ptr->td.token &= +		cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE));  	wmb();   /* synchronize before ep prime */ @@ -506,14 +483,16 @@ done:   */  static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)  { +	u32 tmptoken = le32_to_cpu(mReq->ptr->token); +  	if (mReq->req.status != -EALREADY)  		return -EINVAL; -	if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0) +	if ((TD_STATUS_ACTIVE & tmptoken) != 0)  		return -EBUSY;  	if (mReq->zptr) { -		if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0) +		if ((cpu_to_le32(TD_STATUS_ACTIVE) & mReq->zptr->token) != 0)  			return -EBUSY;  		dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma);  		mReq->zptr = NULL; @@ -523,7 +502,7 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)  	usb_gadget_unmap_request(&mEp->ci->gadget, &mReq->req, mEp->dir); -	mReq->req.status = mReq->ptr->token & TD_STATUS; +	mReq->req.status = tmptoken & TD_STATUS;  	if ((TD_STATUS_HALTED & mReq->req.status) != 0)  		mReq->req.status = -1;  	else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0) @@ -531,8 +510,8 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq)  	else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0)  		mReq->req.status = -1; -	mReq->req.actual   = mReq->ptr->token & TD_TOTAL_BYTES; -	mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES); +	mReq->req.actual   = tmptoken & TD_TOTAL_BYTES; +	mReq->req.actual >>= __ffs(TD_TOTAL_BYTES);  	mReq->req.actual   = mReq->req.length - mReq->req.actual;  	mReq->req.actual   = mReq->req.status ? 0 : mReq->req.actual; @@ -561,6 +540,12 @@ __acquires(mEp->lock)  		struct ci13xxx_req *mReq = \  			list_entry(mEp->qh.queue.next,  				   struct ci13xxx_req, queue); + +		if (mReq->zptr) { +			dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma); +			mReq->zptr = NULL; +		} +  		list_del_init(&mReq->queue);  		mReq->req.status = -ESHUTDOWN; @@ -629,8 +614,6 @@ __acquires(ci->lock)  {  	int retval; -	dbg_event(0xFF, "BUS RST", 0); -  	spin_unlock(&ci->lock);  	retval = _gadget_stop_activity(&ci->gadget);  	if (retval) @@ -668,6 +651,59 @@ static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req)  }  /** + * _ep_queue: queues (submits) an I/O request to an endpoint + * + * Caller must hold lock + */ +static int _ep_queue(struct usb_ep *ep, struct usb_request *req, +		    gfp_t __maybe_unused gfp_flags) +{ +	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep); +	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); +	struct ci13xxx *ci = mEp->ci; +	int retval = 0; + +	if (ep == NULL || req == NULL || mEp->ep.desc == NULL) +		return -EINVAL; + +	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { +		if (req->length) +			mEp = (ci->ep0_dir == RX) ? +			       ci->ep0out : ci->ep0in; +		if (!list_empty(&mEp->qh.queue)) { +			_ep_nuke(mEp); +			retval = -EOVERFLOW; +			dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n", +				 _usb_addr(mEp)); +		} +	} + +	/* first nuke then test link, e.g. previous status has not sent */ +	if (!list_empty(&mReq->queue)) { +		dev_err(mEp->ci->dev, "request already in queue\n"); +		return -EBUSY; +	} + +	if (req->length > (TD_PAGE_COUNT - 1) * CI13XXX_PAGE_SIZE) { +		dev_err(mEp->ci->dev, "request bigger than one td\n"); +		return -EMSGSIZE; +	} + +	/* push request */ +	mReq->req.status = -EINPROGRESS; +	mReq->req.actual = 0; + +	retval = _hardware_enqueue(mEp, mReq); + +	if (retval == -EALREADY) +		retval = 0; +	if (!retval) +		list_add_tail(&mReq->queue, &mEp->qh.queue); + +	return retval; +} + +/**   * isr_get_status_response: get_status request response   * @ci: ci struct   * @setup: setup request packet @@ -714,9 +750,7 @@ __acquires(mEp->lock)  	}  	/* else do nothing; reserved for future use */ -	spin_unlock(mEp->lock); -	retval = usb_ep_queue(&mEp->ep, req, gfp_flags); -	spin_lock(mEp->lock); +	retval = _ep_queue(&mEp->ep, req, gfp_flags);  	if (retval)  		goto err_free_buf; @@ -763,8 +797,6 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)   * This function returns an error code   */  static int isr_setup_status_phase(struct ci13xxx *ci) -__releases(mEp->lock) -__acquires(mEp->lock)  {  	int retval;  	struct ci13xxx_ep *mEp; @@ -773,9 +805,7 @@ __acquires(mEp->lock)  	ci->status->context = ci;  	ci->status->complete = isr_setup_status_complete; -	spin_unlock(mEp->lock); -	retval = usb_ep_queue(&mEp->ep, ci->status, GFP_ATOMIC); -	spin_lock(mEp->lock); +	retval = _ep_queue(&mEp->ep, ci->status, GFP_ATOMIC);  	return retval;  } @@ -801,7 +831,6 @@ __acquires(mEp->lock)  		if (retval < 0)  			break;  		list_del_init(&mReq->queue); -		dbg_done(_usb_addr(mEp), mReq->ptr->token, retval);  		if (mReq->req.complete != NULL) {  			spin_unlock(mEp->lock);  			if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) && @@ -814,8 +843,6 @@ __acquires(mEp->lock)  	if (retval == -EBUSY)  		retval = 0; -	if (retval < 0) -		dbg_event(_usb_addr(mEp), "DONE", retval);  	return retval;  } @@ -847,8 +874,6 @@ __acquires(ci->lock)  				if (err > 0)   /* needs status phase */  					err = isr_setup_status_phase(ci);  				if (err < 0) { -					dbg_event(_usb_addr(mEp), -						  "ERROR", err);  					spin_unlock(&ci->lock);  					if (usb_ep_set_halt(&mEp->ep))  						dev_err(ci->dev, @@ -884,8 +909,6 @@ __acquires(ci->lock)  		ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX; -		dbg_setup(_usb_addr(mEp), &req); -  		switch (req.bRequest) {  		case USB_REQ_CLEAR_FEATURE:  			if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && @@ -997,8 +1020,6 @@ delegate:  		}  		if (err < 0) { -			dbg_event(_usb_addr(mEp), "ERROR", err); -  			spin_unlock(&ci->lock);  			if (usb_ep_set_halt(&mEp->ep))  				dev_err(ci->dev, "error: ep_set_halt\n"); @@ -1021,6 +1042,7 @@ static int ep_enable(struct usb_ep *ep,  	struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep);  	int retval = 0;  	unsigned long flags; +	u32 cap = 0;  	if (ep == NULL || desc == NULL)  		return -EINVAL; @@ -1040,20 +1062,15 @@ static int ep_enable(struct usb_ep *ep,  	mEp->ep.maxpacket = usb_endpoint_maxp(desc); -	dbg_event(_usb_addr(mEp), "ENABLE", 0); - -	mEp->qh.ptr->cap = 0; -  	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) -		mEp->qh.ptr->cap |=  QH_IOS; -	else if (mEp->type == USB_ENDPOINT_XFER_ISOC) -		mEp->qh.ptr->cap &= ~QH_MULT; -	else -		mEp->qh.ptr->cap &= ~QH_ZLT; +		cap |= QH_IOS; +	if (mEp->num) +		cap |= QH_ZLT; +	cap |= (mEp->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT; + +	mEp->qh.ptr->cap = cpu_to_le32(cap); -	mEp->qh.ptr->cap |= -		(mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT; -	mEp->qh.ptr->td.next |= TD_TERMINATE;   /* needed? */ +	mEp->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE);   /* needed? */  	/*  	 * Enable endpoints in the HW other than ep0 as ep0 @@ -1088,8 +1105,6 @@ static int ep_disable(struct usb_ep *ep)  	direction = mEp->dir;  	do { -		dbg_event(_usb_addr(mEp), "DISABLE", 0); -  		retval |= _ep_nuke(mEp);  		retval |= hw_ep_disable(mEp->ci, mEp->num, mEp->dir); @@ -1129,8 +1144,6 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags)  		}  	} -	dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL); -  	return (mReq == NULL) ? NULL : &mReq->req;  } @@ -1158,8 +1171,6 @@ static void ep_free_request(struct usb_ep *ep, struct usb_request *req)  		dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma);  	kfree(mReq); -	dbg_event(_usb_addr(mEp), "FREE", 0); -  	spin_unlock_irqrestore(mEp->lock, flags);  } @@ -1172,8 +1183,6 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,  		    gfp_t __maybe_unused gfp_flags)  {  	struct ci13xxx_ep  *mEp  = container_of(ep,  struct ci13xxx_ep, ep); -	struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); -	struct ci13xxx *ci = mEp->ci;  	int retval = 0;  	unsigned long flags; @@ -1181,48 +1190,7 @@ static int ep_queue(struct usb_ep *ep, struct usb_request *req,  		return -EINVAL;  	spin_lock_irqsave(mEp->lock, flags); - -	if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { -		if (req->length) -			mEp = (ci->ep0_dir == RX) ? -			       ci->ep0out : ci->ep0in; -		if (!list_empty(&mEp->qh.queue)) { -			_ep_nuke(mEp); -			retval = -EOVERFLOW; -			dev_warn(mEp->ci->dev, "endpoint ctrl %X nuked\n", -				 _usb_addr(mEp)); -		} -	} - -	/* first nuke then test link, e.g. previous status has not sent */ -	if (!list_empty(&mReq->queue)) { -		retval = -EBUSY; -		dev_err(mEp->ci->dev, "request already in queue\n"); -		goto done; -	} - -	if (req->length > 4 * CI13XXX_PAGE_SIZE) { -		req->length = 4 * CI13XXX_PAGE_SIZE; -		retval = -EMSGSIZE; -		dev_warn(mEp->ci->dev, "request length truncated\n"); -	} - -	dbg_queue(_usb_addr(mEp), req, retval); - -	/* push request */ -	mReq->req.status = -EINPROGRESS; -	mReq->req.actual = 0; - -	retval = _hardware_enqueue(mEp, mReq); - -	if (retval == -EALREADY) { -		dbg_event(_usb_addr(mEp), "QUEUE", retval); -		retval = 0; -	} -	if (!retval) -		list_add_tail(&mReq->queue, &mEp->qh.queue); - - done: +	retval = _ep_queue(ep, req, gfp_flags);  	spin_unlock_irqrestore(mEp->lock, flags);  	return retval;  } @@ -1245,8 +1213,6 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)  	spin_lock_irqsave(mEp->lock, flags); -	dbg_event(_usb_addr(mEp), "DEQUEUE", 0); -  	hw_ep_flush(mEp->ci, mEp->num, mEp->dir);  	/* pop request */ @@ -1293,7 +1259,6 @@ static int ep_set_halt(struct usb_ep *ep, int value)  	direction = mEp->dir;  	do { -		dbg_event(_usb_addr(mEp), "HALT", value);  		retval |= hw_ep_set_halt(mEp->ci, mEp->num, mEp->dir, value);  		if (!value) @@ -1322,10 +1287,7 @@ static int ep_set_wedge(struct usb_ep *ep)  		return -EINVAL;  	spin_lock_irqsave(mEp->lock, flags); - -	dbg_event(_usb_addr(mEp), "WEDGE", 0);  	mEp->wedge = 1; -  	spin_unlock_irqrestore(mEp->lock, flags);  	return usb_ep_set_halt(ep); @@ -1348,7 +1310,6 @@ static void ep_fifo_flush(struct usb_ep *ep)  	spin_lock_irqsave(mEp->lock, flags); -	dbg_event(_usb_addr(mEp), "FFLUSH", 0);  	hw_ep_flush(mEp->ci, mEp->num, mEp->dir);  	spin_unlock_irqrestore(mEp->lock, flags); @@ -1392,7 +1353,6 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)  		if (is_active) {  			pm_runtime_get_sync(&_gadget->dev);  			hw_device_reset(ci, USBMODE_CM_DC); -			hw_enable_vbus_intr(ci);  			hw_device_state(ci, ci->ep0out->qh.dma);  		} else {  			hw_device_state(ci, 0); @@ -1567,10 +1527,8 @@ static int ci13xxx_start(struct usb_gadget *gadget,  	pm_runtime_get_sync(&ci->gadget.dev);  	if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) {  		if (ci->vbus_active) { -			if (ci->platdata->flags & CI13XXX_REGS_SHARED) { +			if (ci->platdata->flags & CI13XXX_REGS_SHARED)  				hw_device_reset(ci, USBMODE_CM_DC); -				hw_enable_vbus_intr(ci); -			}  		} else {  			pm_runtime_put_sync(&ci->gadget.dev);  			goto done; @@ -1642,7 +1600,6 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)  		}  	}  	intr = hw_test_and_clear_intr_active(ci); -	dbg_interrupt(intr);  	if (intr) {  		/* order defines priority - do NOT change it */ @@ -1676,13 +1633,6 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)  	} else {  		retval = IRQ_NONE;  	} - -	intr = hw_read(ci, OP_OTGSC, ~0); -	hw_write(ci, OP_OTGSC, ~0, intr); - -	if (intr & (OTGSC_AVVIE & OTGSC_AVVIS)) -		queue_work(ci->wq, &ci->vbus_work); -  	spin_unlock(&ci->lock);  	return retval; @@ -1742,18 +1692,13 @@ static int udc_start(struct ci13xxx *ci)  		retval = hw_device_reset(ci, USBMODE_CM_DC);  		if (retval)  			goto put_transceiver; -		hw_enable_vbus_intr(ci);  	} -	retval = dbg_create_files(ci->dev); -	if (retval) -		goto put_transceiver; -  	if (!IS_ERR_OR_NULL(ci->transceiver)) {  		retval = otg_set_peripheral(ci->transceiver->otg,  						&ci->gadget);  		if (retval) -			goto remove_dbg; +			goto put_transceiver;  	}  	retval = usb_add_gadget_udc(dev, &ci->gadget); @@ -1773,8 +1718,6 @@ remove_trans:  	}  	dev_err(dev, "error = %i\n", retval); -remove_dbg: -	dbg_remove_files(ci->dev);  put_transceiver:  	if (!IS_ERR_OR_NULL(ci->transceiver) && ci->global_phy)  		usb_put_phy(ci->transceiver); @@ -1797,9 +1740,6 @@ static void udc_stop(struct ci13xxx *ci)  	if (ci == NULL)  		return; -	hw_disable_vbus_intr(ci); -	cancel_work_sync(&ci->vbus_work); -  	usb_del_gadget_udc(&ci->gadget);  	destroy_eps(ci); @@ -1812,7 +1752,6 @@ static void udc_stop(struct ci13xxx *ci)  		if (ci->global_phy)  			usb_put_phy(ci->transceiver);  	} -	dbg_remove_files(ci->dev);  	/* my kobject is dynamic, I swear! */  	memset(&ci->gadget, 0, sizeof(ci->gadget));  } @@ -1839,7 +1778,6 @@ int ci_hdrc_gadget_init(struct ci13xxx *ci)  	rdrv->irq	= udc_irq;  	rdrv->name	= "gadget";  	ci->roles[CI_ROLE_GADGET] = rdrv; -	INIT_WORK(&ci->vbus_work, vbus_work);  	return 0;  } diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h index 4ff2384d7ca..d12e8b59b11 100644 --- a/drivers/usb/chipidea/udc.h +++ b/drivers/usb/chipidea/udc.h @@ -40,7 +40,7 @@ struct ci13xxx_td {  #define TD_CURR_OFFSET        (0x0FFFUL <<  0)  #define TD_FRAME_NUM          (0x07FFUL <<  0)  #define TD_RESERVED_MASK      (0x0FFFUL <<  0) -} __attribute__ ((packed)); +} __attribute__ ((packed, aligned(4)));  /* DMA layout of queue heads */  struct ci13xxx_qh { @@ -57,7 +57,7 @@ struct ci13xxx_qh {  	/* 9 */  	u32 RESERVED;  	struct usb_ctrlrequest   setup; -} __attribute__ ((packed)); +} __attribute__ ((packed, aligned(4)));  /**   * struct ci13xxx_req - usb request representation diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c new file mode 100644 index 00000000000..714a6bd810e --- /dev/null +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -0,0 +1,261 @@ +/* + * Copyright 2012 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +#include <linux/module.h> +#include <linux/of_platform.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/delay.h> + +#include "ci13xxx_imx.h" + +#define USB_DEV_MAX 4 + +#define MX25_USB_PHY_CTRL_OFFSET	0x08 +#define MX25_BM_EXTERNAL_VBUS_DIVIDER	BIT(23) + +#define MX53_USB_OTG_PHY_CTRL_0_OFFSET	0x08 +#define MX53_USB_UH2_CTRL_OFFSET	0x14 +#define MX53_USB_UH3_CTRL_OFFSET	0x18 +#define MX53_BM_OVER_CUR_DIS_H1		BIT(5) +#define MX53_BM_OVER_CUR_DIS_OTG	BIT(8) +#define MX53_BM_OVER_CUR_DIS_UHx	BIT(30) + +#define MX6_BM_OVER_CUR_DIS		BIT(7) + +struct imx_usbmisc { +	void __iomem *base; +	spinlock_t lock; +	struct clk *clk; +	struct usbmisc_usb_device usbdev[USB_DEV_MAX]; +	const struct usbmisc_ops *ops; +}; + +static struct imx_usbmisc *usbmisc; + +static struct usbmisc_usb_device *get_usbdev(struct device *dev) +{ +	int i, ret; + +	for (i = 0; i < USB_DEV_MAX; i++) { +		if (usbmisc->usbdev[i].dev == dev) +			return &usbmisc->usbdev[i]; +		else if (!usbmisc->usbdev[i].dev) +			break; +	} + +	if (i >= USB_DEV_MAX) +		return ERR_PTR(-EBUSY); + +	ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]); +	if (ret) +		return ERR_PTR(ret); + +	return &usbmisc->usbdev[i]; +} + +static int usbmisc_imx25_post(struct device *dev) +{ +	struct usbmisc_usb_device *usbdev; +	void __iomem *reg; +	unsigned long flags; +	u32 val; + +	usbdev = get_usbdev(dev); +	if (IS_ERR(usbdev)) +		return PTR_ERR(usbdev); + +	reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET; + +	if (usbdev->evdo) { +		spin_lock_irqsave(&usbmisc->lock, flags); +		val = readl(reg); +		writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg); +		spin_unlock_irqrestore(&usbmisc->lock, flags); +		usleep_range(5000, 10000); /* needed to stabilize voltage */ +	} + +	return 0; +} + +static int usbmisc_imx53_init(struct device *dev) +{ +	struct usbmisc_usb_device *usbdev; +	void __iomem *reg = NULL; +	unsigned long flags; +	u32 val = 0; + +	usbdev = get_usbdev(dev); +	if (IS_ERR(usbdev)) +		return PTR_ERR(usbdev); + +	if (usbdev->disable_oc) { +		spin_lock_irqsave(&usbmisc->lock, flags); +		switch (usbdev->index) { +		case 0: +			reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; +			val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; +			break; +		case 1: +			reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; +			val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1; +			break; +		case 2: +			reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET; +			val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; +			break; +		case 3: +			reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET; +			val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; +			break; +		} +		if (reg && val) +			writel(val, reg); +		spin_unlock_irqrestore(&usbmisc->lock, flags); +	} + +	return 0; +} + +static int usbmisc_imx6q_init(struct device *dev) +{ + +	struct usbmisc_usb_device *usbdev; +	unsigned long flags; +	u32 reg; + +	usbdev = get_usbdev(dev); +	if (IS_ERR(usbdev)) +		return PTR_ERR(usbdev); + +	if (usbdev->disable_oc) { +		spin_lock_irqsave(&usbmisc->lock, flags); +		reg = readl(usbmisc->base + usbdev->index * 4); +		writel(reg | MX6_BM_OVER_CUR_DIS, +			usbmisc->base + usbdev->index * 4); +		spin_unlock_irqrestore(&usbmisc->lock, flags); +	} + +	return 0; +} + +static const struct usbmisc_ops imx25_usbmisc_ops = { +	.post = usbmisc_imx25_post, +}; + +static const struct usbmisc_ops imx53_usbmisc_ops = { +	.init = usbmisc_imx53_init, +}; + +static const struct usbmisc_ops imx6q_usbmisc_ops = { +	.init = usbmisc_imx6q_init, +}; + +static const struct of_device_id usbmisc_imx_dt_ids[] = { +	{ +		.compatible = "fsl,imx25-usbmisc", +		.data = &imx25_usbmisc_ops, +	}, +	{ +		.compatible = "fsl,imx53-usbmisc", +		.data = &imx53_usbmisc_ops, +	}, +	{ +		.compatible = "fsl,imx6q-usbmisc", +		.data = &imx6q_usbmisc_ops, +	}, +	{ /* sentinel */ } +}; + +static int usbmisc_imx_probe(struct platform_device *pdev) +{ +	struct resource	*res; +	struct imx_usbmisc *data; +	int ret; +	struct of_device_id *tmp_dev; + +	if (usbmisc) +		return -EBUSY; + +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); +	if (!data) +		return -ENOMEM; + +	spin_lock_init(&data->lock); + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	data->base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(data->base)) +		return PTR_ERR(data->base); + +	data->clk = devm_clk_get(&pdev->dev, NULL); +	if (IS_ERR(data->clk)) { +		dev_err(&pdev->dev, +			"failed to get clock, err=%ld\n", PTR_ERR(data->clk)); +		return PTR_ERR(data->clk); +	} + +	ret = clk_prepare_enable(data->clk); +	if (ret) { +		dev_err(&pdev->dev, +			"clk_prepare_enable failed, err=%d\n", ret); +		return ret; +	} + +	tmp_dev = (struct of_device_id *) +		of_match_device(usbmisc_imx_dt_ids, &pdev->dev); +	data->ops = (const struct usbmisc_ops *)tmp_dev->data; +	usbmisc = data; +	ret = usbmisc_set_ops(data->ops); +	if (ret) { +		usbmisc = NULL; +		clk_disable_unprepare(data->clk); +		return ret; +	} + +	return 0; +} + +static int usbmisc_imx_remove(struct platform_device *pdev) +{ +	usbmisc_unset_ops(usbmisc->ops); +	clk_disable_unprepare(usbmisc->clk); +	usbmisc = NULL; +	return 0; +} + +static struct platform_driver usbmisc_imx_driver = { +	.probe = usbmisc_imx_probe, +	.remove = usbmisc_imx_remove, +	.driver = { +		.name = "usbmisc_imx", +		.owner = THIS_MODULE, +		.of_match_table = usbmisc_imx_dt_ids, +	 }, +}; + +int usbmisc_imx_drv_init(void) +{ +	return platform_driver_register(&usbmisc_imx_driver); +} +subsys_initcall(usbmisc_imx_drv_init); + +void usbmisc_imx_drv_exit(void) +{ +	platform_driver_unregister(&usbmisc_imx_driver); +} +module_exit(usbmisc_imx_drv_exit); + +MODULE_ALIAS("platform:usbmisc-imx"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("driver for imx usb non-core registers"); +MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); diff --git a/drivers/usb/chipidea/usbmisc_imx6q.c b/drivers/usb/chipidea/usbmisc_imx6q.c deleted file mode 100644 index a1bce391e82..00000000000 --- a/drivers/usb/chipidea/usbmisc_imx6q.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2012 Freescale Semiconductor, Inc. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -#include <linux/module.h> -#include <linux/of_platform.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/io.h> - -#include "ci13xxx_imx.h" - -#define USB_DEV_MAX 4 - -#define BM_OVER_CUR_DIS		BIT(7) - -struct imx6q_usbmisc { -	void __iomem *base; -	spinlock_t lock; -	struct clk *clk; -	struct usbmisc_usb_device usbdev[USB_DEV_MAX]; -}; - -static struct imx6q_usbmisc *usbmisc; - -static struct usbmisc_usb_device *get_usbdev(struct device *dev) -{ -	int i, ret; - -	for (i = 0; i < USB_DEV_MAX; i++) { -		if (usbmisc->usbdev[i].dev == dev) -			return &usbmisc->usbdev[i]; -		else if (!usbmisc->usbdev[i].dev) -			break; -	} - -	if (i >= USB_DEV_MAX) -		return ERR_PTR(-EBUSY); - -	ret = usbmisc_get_init_data(dev, &usbmisc->usbdev[i]); -	if (ret) -		return ERR_PTR(ret); - -	return &usbmisc->usbdev[i]; -} - -static int usbmisc_imx6q_init(struct device *dev) -{ - -	struct usbmisc_usb_device *usbdev; -	unsigned long flags; -	u32 reg; - -	usbdev = get_usbdev(dev); -	if (IS_ERR(usbdev)) -		return PTR_ERR(usbdev); - -	if (usbdev->disable_oc) { -		spin_lock_irqsave(&usbmisc->lock, flags); -		reg = readl(usbmisc->base + usbdev->index * 4); -		writel(reg | BM_OVER_CUR_DIS, -			usbmisc->base + usbdev->index * 4); -		spin_unlock_irqrestore(&usbmisc->lock, flags); -	} - -	return 0; -} - -static const struct usbmisc_ops imx6q_usbmisc_ops = { -	.init = usbmisc_imx6q_init, -}; - -static const struct of_device_id usbmisc_imx6q_dt_ids[] = { -	{ .compatible = "fsl,imx6q-usbmisc"}, -	{ /* sentinel */ } -}; - -static int usbmisc_imx6q_probe(struct platform_device *pdev) -{ -	struct resource	*res; -	struct imx6q_usbmisc *data; -	int ret; - -	if (usbmisc) -		return -EBUSY; - -	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); -	if (!data) -		return -ENOMEM; - -	spin_lock_init(&data->lock); - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	data->base = devm_ioremap_resource(&pdev->dev, res); -	if (IS_ERR(data->base)) -		return PTR_ERR(data->base); - -	data->clk = devm_clk_get(&pdev->dev, NULL); -	if (IS_ERR(data->clk)) { -		dev_err(&pdev->dev, -			"failed to get clock, err=%ld\n", PTR_ERR(data->clk)); -		return PTR_ERR(data->clk); -	} - -	ret = clk_prepare_enable(data->clk); -	if (ret) { -		dev_err(&pdev->dev, -			"clk_prepare_enable failed, err=%d\n", ret); -		return ret; -	} - -	ret = usbmisc_set_ops(&imx6q_usbmisc_ops); -	if (ret) { -		clk_disable_unprepare(data->clk); -		return ret; -	} - -	usbmisc = data; - -	return 0; -} - -static int usbmisc_imx6q_remove(struct platform_device *pdev) -{ -	usbmisc_unset_ops(&imx6q_usbmisc_ops); -	clk_disable_unprepare(usbmisc->clk); -	return 0; -} - -static struct platform_driver usbmisc_imx6q_driver = { -	.probe = usbmisc_imx6q_probe, -	.remove = usbmisc_imx6q_remove, -	.driver = { -		.name = "usbmisc_imx6q", -		.owner = THIS_MODULE, -		.of_match_table = usbmisc_imx6q_dt_ids, -	 }, -}; - -int __init usbmisc_imx6q_drv_init(void) -{ -	return platform_driver_register(&usbmisc_imx6q_driver); -} -subsys_initcall(usbmisc_imx6q_drv_init); - -void __exit usbmisc_imx6q_drv_exit(void) -{ -	platform_driver_unregister(&usbmisc_imx6q_driver); -} -module_exit(usbmisc_imx6q_drv_exit); - -MODULE_ALIAS("platform:usbmisc-imx6q"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("driver for imx6q usb non-core registers"); -MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>"); diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 8ac25adf31b..6d4e0b96f89 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -593,7 +593,6 @@ static void acm_port_destruct(struct tty_port *port)  	dev_dbg(&acm->control->dev, "%s\n", __func__); -	tty_unregister_device(acm_tty_driver, acm->minor);  	acm_release_minor(acm);  	usb_put_intf(acm->control);  	kfree(acm->country_codes); @@ -840,14 +839,6 @@ static int acm_tty_ioctl(struct tty_struct *tty,  	return rv;  } -static const __u32 acm_tty_speed[] = { -	0, 50, 75, 110, 134, 150, 200, 300, 600, -	1200, 1800, 2400, 4800, 9600, 19200, 38400, -	57600, 115200, 230400, 460800, 500000, 576000, -	921600, 1000000, 1152000, 1500000, 2000000, -	2500000, 3000000, 3500000, 4000000 -}; -  static void acm_tty_set_termios(struct tty_struct *tty,  						struct ktermios *termios_old)  { @@ -977,6 +968,8 @@ static int acm_probe(struct usb_interface *intf,  	int num_rx_buf;  	int i;  	int combined_interfaces = 0; +	struct device *tty_dev; +	int rv = -ENOMEM;  	/* normal quirks */  	quirks = (unsigned long)id->driver_info; @@ -1339,11 +1332,24 @@ skip_countries:  	usb_set_intfdata(data_interface, acm);  	usb_get_intf(control_interface); -	tty_port_register_device(&acm->port, acm_tty_driver, minor, +	tty_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor,  			&control_interface->dev); +	if (IS_ERR(tty_dev)) { +		rv = PTR_ERR(tty_dev); +		goto alloc_fail8; +	}  	return 0; +alloc_fail8: +	if (acm->country_codes) { +		device_remove_file(&acm->control->dev, +				&dev_attr_wCountryCodes); +		device_remove_file(&acm->control->dev, +				&dev_attr_iCountryCodeRelDate); +	} +	device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);  alloc_fail7: +	usb_set_intfdata(intf, NULL);  	for (i = 0; i < ACM_NW; i++)  		usb_free_urb(acm->wb[i].urb);  alloc_fail6: @@ -1359,7 +1365,7 @@ alloc_fail2:  	acm_release_minor(acm);  	kfree(acm);  alloc_fail: -	return -ENOMEM; +	return rv;  }  static void stop_data_traffic(struct acm *acm) @@ -1411,6 +1417,8 @@ static void acm_disconnect(struct usb_interface *intf)  	stop_data_traffic(acm); +	tty_unregister_device(acm_tty_driver, acm->minor); +  	usb_free_urb(acm->ctrlurb);  	for (i = 0; i < ACM_NW; i++)  		usb_free_urb(acm->wb[i].urb); diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 122d056d96d..8a230f0ef77 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -13,6 +13,7 @@   */  #include <linux/kernel.h>  #include <linux/errno.h> +#include <linux/ioctl.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/mutex.h> @@ -644,6 +645,22 @@ static int wdm_release(struct inode *inode, struct file *file)  	return 0;  } +static long wdm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ +	struct wdm_device *desc = file->private_data; +	int rv = 0; + +	switch (cmd) { +	case IOCTL_WDM_MAX_COMMAND: +		if (copy_to_user((void __user *)arg, &desc->wMaxCommand, sizeof(desc->wMaxCommand))) +			rv = -EFAULT; +		break; +	default: +		rv = -ENOTTY; +	} +	return rv; +} +  static const struct file_operations wdm_fops = {  	.owner =	THIS_MODULE,  	.read =		wdm_read, @@ -652,6 +669,8 @@ static const struct file_operations wdm_fops = {  	.flush =	wdm_flush,  	.release =	wdm_release,  	.poll =		wdm_poll, +	.unlocked_ioctl = wdm_ioctl, +	.compat_ioctl = wdm_ioctl,  	.llseek =	noop_llseek,  }; diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index f70c1a1694a..7b7305e3abc 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -27,6 +27,22 @@ config USB_ANNOUNCE_NEW_DEVICES  comment "Miscellaneous USB options"  	depends on USB +config USB_DEFAULT_PERSIST +	bool "Enable USB persist by default" +	depends on USB +	default y +	help +	  Say N here if you don't want USB power session persistance +	  enabled by default.  If you say N it will make suspended USB +	  devices that lose power get reenumerated as if they had been +	  unplugged, causing any mounted filesystems to be lost.  The +	  persist feature can still be enabled for individual devices +	  through the power/persist sysfs node. See +	  Documentation/usb/persist.txt for more info. + +	  If you have any questions about this, say Y here, only say N +	  if you know exactly what you are doing. +  config USB_DYNAMIC_MINORS  	bool "Dynamic USB minor allocation"  	depends on USB @@ -38,22 +54,6 @@ config USB_DYNAMIC_MINORS  	  If you are unsure about this, say N here. -config USB_SUSPEND -	bool "USB runtime power management (autosuspend) and wakeup" -	depends on USB && PM_RUNTIME -	help -	  If you say Y here, you can use driver calls or the sysfs -	  "power/control" file to enable or disable autosuspend for -	  individual USB peripherals (see -	  Documentation/usb/power-management.txt for more details). - -	  Also, USB "remote wakeup" signaling is supported, whereby some -	  USB devices (like keyboards and network adapters) can wake up -	  their parent hub.  That wakeup cascades up the USB tree, and -	  could wake the system from states like suspend-to-RAM. - -	  If you are unsure about this, say N here. -  config USB_OTG  	bool "OTG support"  	depends on USB diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index d938b2b99e3..6eab440e154 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1196,9 +1196,14 @@ done:   *   * This is the central routine for suspending USB devices.  It calls the   * suspend methods for all the interface drivers in @udev and then calls - * the suspend method for @udev itself.  If an error occurs at any stage, - * all the interfaces which were suspended are resumed so that they remain - * in the same state as the device. + * the suspend method for @udev itself.  When the routine is called in + * autosuspend, if an error occurs at any stage, all the interfaces + * which were suspended are resumed so that they remain in the same + * state as the device, but when called from system sleep, all error + * from suspend methods of interfaces and the non-root-hub device itself + * are simply ignored, so all suspended interfaces are only resumed + * to the device's state when @udev is root-hub and its suspend method + * returns failure.   *   * Autosuspend requests originating from a child device or an interface   * driver may be made without the protection of @udev's device lock, but @@ -1248,10 +1253,12 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)  	/* If the suspend failed, resume interfaces that did get suspended */  	if (status != 0) { -		msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME); -		while (++i < n) { -			intf = udev->actconfig->interface[i]; -			usb_resume_interface(udev, intf, msg, 0); +		if (udev->actconfig) { +			msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME); +			while (++i < n) { +				intf = udev->actconfig->interface[i]; +				usb_resume_interface(udev, intf, msg, 0); +			}  		}  	/* If the suspend succeeded then prevent any more URB submissions @@ -1407,7 +1414,7 @@ int usb_resume(struct device *dev, pm_message_t msg)  #endif /* CONFIG_PM */ -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  /**   * usb_enable_autosuspend - allow a USB device to be autosuspended @@ -1775,7 +1782,7 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)  	return ret;  } -#endif /* CONFIG_USB_SUSPEND */ +#endif /* CONFIG_PM_RUNTIME */  struct bus_type usb_bus_type = {  	.name =		"usb", diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index 271e761f563..acbfeb0a011 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -169,7 +169,7 @@ static int generic_probe(struct usb_device *udev)  		c = usb_choose_configuration(udev);  		if (c >= 0) {  			err = usb_set_configuration(udev, c); -			if (err) { +			if (err && err != -ENODEV) {  				dev_err(&udev->dev, "can't set config #%d, error %d\n",  					c, err);  				/* This need not be fatal.  The user can try to diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index 622b4a48e73..caeb8d6d39f 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -37,119 +37,123 @@  /* PCI-based HCs are common, but plenty of non-PCI HCs are used too */ -#ifdef CONFIG_PM_SLEEP - -/* Coordinate handoffs between EHCI and companion controllers - * during system resume +/* + * Coordinate handoffs between EHCI and companion controllers + * during EHCI probing and system resume.   */ -static DEFINE_MUTEX(companions_mutex); +static DECLARE_RWSEM(companions_rwsem);  #define CL_UHCI		PCI_CLASS_SERIAL_USB_UHCI  #define CL_OHCI		PCI_CLASS_SERIAL_USB_OHCI  #define CL_EHCI		PCI_CLASS_SERIAL_USB_EHCI -enum companion_action { -	SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS -}; +static inline int is_ohci_or_uhci(struct pci_dev *pdev) +{ +	return pdev->class == CL_OHCI || pdev->class == CL_UHCI; +} + +typedef void (*companion_fn)(struct pci_dev *pdev, struct usb_hcd *hcd, +		struct pci_dev *companion, struct usb_hcd *companion_hcd); -static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd, -		enum companion_action action) +/* Iterate over PCI devices in the same slot as pdev and call fn for each */ +static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd, +		companion_fn fn)  {  	struct pci_dev		*companion;  	struct usb_hcd		*companion_hcd;  	unsigned int		slot = PCI_SLOT(pdev->devfn); -	/* Iterate through other PCI functions in the same slot. -	 * If pdev is OHCI or UHCI then we are looking for EHCI, and -	 * vice versa. +	/* +	 * Iterate through other PCI functions in the same slot. +	 * If the function's drvdata isn't set then it isn't bound to +	 * a USB host controller driver, so skip it.  	 */  	companion = NULL;  	for_each_pci_dev(companion) {  		if (companion->bus != pdev->bus ||  				PCI_SLOT(companion->devfn) != slot)  			continue; -  		companion_hcd = pci_get_drvdata(companion);  		if (!companion_hcd)  			continue; - -		/* For SET_HS_COMPANION, store a pointer to the EHCI bus in -		 * the OHCI/UHCI companion bus structure. -		 * For CLEAR_HS_COMPANION, clear the pointer to the EHCI bus -		 * in the OHCI/UHCI companion bus structure. -		 * For WAIT_FOR_COMPANIONS, wait until the OHCI/UHCI -		 * companion controllers have fully resumed. -		 */ - -		if ((pdev->class == CL_OHCI || pdev->class == CL_UHCI) && -				companion->class == CL_EHCI) { -			/* action must be SET_HS_COMPANION */ -			dev_dbg(&companion->dev, "HS companion for %s\n", -					dev_name(&pdev->dev)); -			hcd->self.hs_companion = &companion_hcd->self; - -		} else if (pdev->class == CL_EHCI && -				(companion->class == CL_OHCI || -				companion->class == CL_UHCI)) { -			switch (action) { -			case SET_HS_COMPANION: -				dev_dbg(&pdev->dev, "HS companion for %s\n", -						dev_name(&companion->dev)); -				companion_hcd->self.hs_companion = &hcd->self; -				break; -			case CLEAR_HS_COMPANION: -				companion_hcd->self.hs_companion = NULL; -				break; -			case WAIT_FOR_COMPANIONS: -				device_pm_wait_for_dev(&pdev->dev, -						&companion->dev); -				break; -			} -		} +		fn(pdev, hcd, companion, companion_hcd);  	}  } -static void set_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd) +/* + * We're about to add an EHCI controller, which will unceremoniously grab + * all the port connections away from its companions.  To prevent annoying + * error messages, lock the companion's root hub and gracefully unconfigure + * it beforehand.  Leave it locked until the EHCI controller is all set. + */ +static void ehci_pre_add(struct pci_dev *pdev, struct usb_hcd *hcd, +		struct pci_dev *companion, struct usb_hcd *companion_hcd)  { -	mutex_lock(&companions_mutex); -	dev_set_drvdata(&pdev->dev, hcd); -	companion_common(pdev, hcd, SET_HS_COMPANION); -	mutex_unlock(&companions_mutex); +	struct usb_device *udev; + +	if (is_ohci_or_uhci(companion)) { +		udev = companion_hcd->self.root_hub; +		usb_lock_device(udev); +		usb_set_configuration(udev, 0); +	}  } -static void clear_hs_companion(struct pci_dev *pdev, struct usb_hcd *hcd) +/* + * Adding the EHCI controller has either succeeded or failed.  Set the + * companion pointer accordingly, and in either case, reconfigure and + * unlock the root hub. + */ +static void ehci_post_add(struct pci_dev *pdev, struct usb_hcd *hcd, +		struct pci_dev *companion, struct usb_hcd *companion_hcd)  { -	mutex_lock(&companions_mutex); -	dev_set_drvdata(&pdev->dev, NULL); +	struct usb_device *udev; -	/* If pdev is OHCI or UHCI, just clear its hs_companion pointer */ -	if (pdev->class == CL_OHCI || pdev->class == CL_UHCI) -		hcd->self.hs_companion = NULL; +	if (is_ohci_or_uhci(companion)) { +		if (dev_get_drvdata(&pdev->dev)) {	/* Succeeded */ +			dev_dbg(&pdev->dev, "HS companion for %s\n", +					dev_name(&companion->dev)); +			companion_hcd->self.hs_companion = &hcd->self; +		} +		udev = companion_hcd->self.root_hub; +		usb_set_configuration(udev, 1); +		usb_unlock_device(udev); +	} +} -	/* Otherwise search for companion buses and clear their pointers */ -	else -		companion_common(pdev, hcd, CLEAR_HS_COMPANION); -	mutex_unlock(&companions_mutex); +/* + * We just added a non-EHCI controller.  Find the EHCI controller to + * which it is a companion, and store a pointer to the bus structure. + */ +static void non_ehci_add(struct pci_dev *pdev, struct usb_hcd *hcd, +		struct pci_dev *companion, struct usb_hcd *companion_hcd) +{ +	if (is_ohci_or_uhci(pdev) && companion->class == CL_EHCI) { +		dev_dbg(&pdev->dev, "FS/LS companion for %s\n", +				dev_name(&companion->dev)); +		hcd->self.hs_companion = &companion_hcd->self; +	}  } -static void wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd) +/* We are removing an EHCI controller.  Clear the companions' pointers. */ +static void ehci_remove(struct pci_dev *pdev, struct usb_hcd *hcd, +		struct pci_dev *companion, struct usb_hcd *companion_hcd)  { -	/* Only EHCI controllers need to wait. -	 * No locking is needed because a controller cannot be resumed -	 * while one of its companions is getting unbound. -	 */ -	if (pdev->class == CL_EHCI) -		companion_common(pdev, hcd, WAIT_FOR_COMPANIONS); +	if (is_ohci_or_uhci(companion)) +		companion_hcd->self.hs_companion = NULL;  } -#else /* !CONFIG_PM_SLEEP */ +#ifdef	CONFIG_PM -static inline void set_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} -static inline void clear_hs_companion(struct pci_dev *d, struct usb_hcd *h) {} -static inline void wait_for_companions(struct pci_dev *d, struct usb_hcd *h) {} +/* An EHCI controller must wait for its companions before resuming. */ +static void ehci_wait_for_companions(struct pci_dev *pdev, struct usb_hcd *hcd, +		struct pci_dev *companion, struct usb_hcd *companion_hcd) +{ +	if (is_ohci_or_uhci(companion)) +		device_pm_wait_for_dev(&pdev->dev, &companion->dev); +} -#endif /* !CONFIG_PM_SLEEP */ +#endif	/* CONFIG_PM */  /*-------------------------------------------------------------------------*/ @@ -173,6 +177,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  	struct hc_driver	*driver;  	struct usb_hcd		*hcd;  	int			retval; +	int			hcd_irq = 0;  	if (usb_disabled())  		return -ENODEV; @@ -187,15 +192,19 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  		return -ENODEV;  	dev->current_state = PCI_D0; -	/* The xHCI driver supports MSI and MSI-X, -	 * so don't fail if the BIOS doesn't provide a legacy IRQ. +	/* +	 * The xHCI driver has its own irq management +	 * make sure irq setup is not touched for xhci in generic hcd code  	 */ -	if (!dev->irq && (driver->flags & HCD_MASK) != HCD_USB3) { -		dev_err(&dev->dev, -			"Found HC with no IRQ.  Check BIOS/PCI %s setup!\n", -			pci_name(dev)); -		retval = -ENODEV; -		goto disable_pci; +	if ((driver->flags & HCD_MASK) != HCD_USB3) { +		if (!dev->irq) { +			dev_err(&dev->dev, +			"Found HC with no IRQ. Check BIOS/PCI %s setup!\n", +				pci_name(dev)); +			retval = -ENODEV; +			goto disable_pci; +		} +		hcd_irq = dev->irq;  	}  	hcd = usb_create_hcd(driver, &dev->dev, pci_name(dev)); @@ -212,7 +221,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  				driver->description)) {  			dev_dbg(&dev->dev, "controller already in use\n");  			retval = -EBUSY; -			goto clear_companion; +			goto put_hcd;  		}  		hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);  		if (hcd->regs == NULL) { @@ -239,16 +248,35 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  		if (region == PCI_ROM_RESOURCE) {  			dev_dbg(&dev->dev, "no i/o regions available\n");  			retval = -EBUSY; -			goto clear_companion; +			goto put_hcd;  		}  	}  	pci_set_master(dev); -	retval = usb_add_hcd(hcd, dev->irq, IRQF_SHARED); +	/* Note: dev_set_drvdata must be called while holding the rwsem */ +	if (dev->class == CL_EHCI) { +		down_write(&companions_rwsem); +		dev_set_drvdata(&dev->dev, hcd); +		for_each_companion(dev, hcd, ehci_pre_add); +		retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED); +		if (retval != 0) +			dev_set_drvdata(&dev->dev, NULL); +		for_each_companion(dev, hcd, ehci_post_add); +		up_write(&companions_rwsem); +	} else { +		down_read(&companions_rwsem); +		dev_set_drvdata(&dev->dev, hcd); +		retval = usb_add_hcd(hcd, hcd_irq, IRQF_SHARED); +		if (retval != 0) +			dev_set_drvdata(&dev->dev, NULL); +		else +			for_each_companion(dev, hcd, non_ehci_add); +		up_read(&companions_rwsem); +	} +  	if (retval != 0)  		goto unmap_registers; -	set_hs_companion(dev, hcd);  	if (pci_dev_run_wake(dev))  		pm_runtime_put_noidle(&dev->dev); @@ -261,8 +289,7 @@ release_mem_region:  		release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	} else  		release_region(hcd->rsrc_start, hcd->rsrc_len); -clear_companion: -	clear_hs_companion(dev, hcd); +put_hcd:  	usb_put_hcd(hcd);  disable_pci:  	pci_disable_device(dev); @@ -305,14 +332,29 @@ void usb_hcd_pci_remove(struct pci_dev *dev)  	usb_hcd_irq(0, hcd);  	local_irq_enable(); -	usb_remove_hcd(hcd); +	/* Note: dev_set_drvdata must be called while holding the rwsem */ +	if (dev->class == CL_EHCI) { +		down_write(&companions_rwsem); +		for_each_companion(dev, hcd, ehci_remove); +		usb_remove_hcd(hcd); +		dev_set_drvdata(&dev->dev, NULL); +		up_write(&companions_rwsem); +	} else { +		/* Not EHCI; just clear the companion pointer */ +		down_read(&companions_rwsem); +		hcd->self.hs_companion = NULL; +		usb_remove_hcd(hcd); +		dev_set_drvdata(&dev->dev, NULL); +		up_read(&companions_rwsem); +	} +  	if (hcd->driver->flags & HCD_MEMORY) {  		iounmap(hcd->regs);  		release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	} else {  		release_region(hcd->rsrc_start, hcd->rsrc_len);  	} -	clear_hs_companion(dev, hcd); +  	usb_put_hcd(hcd);  	pci_disable_device(dev);  } @@ -458,8 +500,15 @@ static int resume_common(struct device *dev, int event)  	pci_set_master(pci_dev);  	if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) { -		if (event != PM_EVENT_AUTO_RESUME) -			wait_for_companions(pci_dev, hcd); + +		/* +		 * Only EHCI controllers have to wait for their companions. +		 * No locking is needed because PCI controller drivers do not +		 * get unbound during system resume. +		 */ +		if (pci_dev->class == CL_EHCI && event != PM_EVENT_AUTO_RESUME) +			for_each_companion(pci_dev, hcd, +					ehci_wait_for_companions);  		retval = hcd->driver->pci_resume(hcd,  				event == PM_EVENT_RESTORE); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 99b34a30354..d53547d2e4c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2125,7 +2125,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)  #endif	/* CONFIG_PM */ -#ifdef	CONFIG_USB_SUSPEND +#ifdef	CONFIG_PM_RUNTIME  /* Workqueue routine for root-hub remote wakeup */  static void hcd_resume_work(struct work_struct *work) @@ -2160,7 +2160,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)  }  EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); -#endif	/* CONFIG_USB_SUSPEND */ +#endif	/* CONFIG_PM_RUNTIME */  /*-------------------------------------------------------------------------*/ @@ -2336,7 +2336,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,  	init_timer(&hcd->rh_timer);  	hcd->rh_timer.function = rh_timer_func;  	hcd->rh_timer.data = (unsigned long) hcd; -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  	INIT_WORK(&hcd->wakeup_work, hcd_resume_work);  #endif @@ -2412,6 +2412,14 @@ int usb_hcd_is_primary_hcd(struct usb_hcd *hcd)  }  EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd); +int usb_hcd_find_raw_port_number(struct usb_hcd *hcd, int port1) +{ +	if (!hcd->driver->find_raw_port_number) +		return port1; + +	return hcd->driver->find_raw_port_number(hcd, port1); +} +  static int usb_hcd_request_irqs(struct usb_hcd *hcd,  		unsigned int irqnum, unsigned long irqflags)  { @@ -2582,7 +2590,7 @@ error_create_attr_group:  	hcd->rh_registered = 0;  	spin_unlock_irq(&hcd_root_hub_lock); -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  	cancel_work_sync(&hcd->wakeup_work);  #endif  	mutex_lock(&usb_bus_list_lock); @@ -2637,7 +2645,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)  	hcd->rh_registered = 0;  	spin_unlock_irq (&hcd_root_hub_lock); -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  	cancel_work_sync(&hcd->wakeup_work);  #endif diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 5480352f984..feef9351463 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -555,8 +555,9 @@ static int hub_port_status(struct usb_hub *hub, int port1,  	mutex_lock(&hub->status_mutex);  	ret = get_port_status(hub->hdev, port1, &hub->status->port);  	if (ret < 4) { -		dev_err(hub->intfdev, -			"%s failed (err = %d)\n", __func__, ret); +		if (ret != -ENODEV) +			dev_err(hub->intfdev, +				"%s failed (err = %d)\n", __func__, ret);  		if (ret >= 0)  			ret = -EIO;  	} else { @@ -699,7 +700,7 @@ static void hub_tt_work(struct work_struct *work)  		/* drop lock so HCD can concurrently report other TT errors */  		spin_unlock_irqrestore (&hub->tt.lock, flags);  		status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt); -		if (status) +		if (status && status != -ENODEV)  			dev_err (&hdev->dev,  				"clear tt %d (%04x) error %d\n",  				clear->tt, clear->devinfo, status); @@ -837,10 +838,11 @@ static int hub_hub_status(struct usb_hub *hub,  	mutex_lock(&hub->status_mutex);  	ret = get_hub_status(hub->hdev, &hub->status->hub); -	if (ret < 0) -		dev_err (hub->intfdev, -			"%s failed (err = %d)\n", __func__, ret); -	else { +	if (ret < 0) { +		if (ret != -ENODEV) +			dev_err(hub->intfdev, +				"%s failed (err = %d)\n", __func__, ret); +	} else {  		*status = le16_to_cpu(hub->status->hub.wHubStatus);  		*change = le16_to_cpu(hub->status->hub.wHubChange);   		ret = 0; @@ -877,11 +879,8 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1)  		return -EINVAL;  	ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED); -	if (ret) { -		dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", -				port1, ret); +	if (ret)  		return ret; -	}  	/* Wait for the link to enter the disabled state. */  	for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) { @@ -918,7 +917,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)  			ret = usb_clear_port_feature(hdev, port1,  					USB_PORT_FEAT_ENABLE);  	} -	if (ret) +	if (ret && ret != -ENODEV)  		dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",  				port1, ret);  	return ret; @@ -1317,6 +1316,10 @@ static int hub_configure(struct usb_hub *hub,  		message = "hub has too many ports!";  		ret = -ENODEV;  		goto fail; +	} else if (hub->descriptor->bNbrPorts == 0) { +		message = "hub doesn't have any ports!"; +		ret = -ENODEV; +		goto fail;  	}  	hdev->maxchild = hub->descriptor->bNbrPorts; @@ -2192,8 +2195,9 @@ static int usb_enumerate_device(struct usb_device *udev)  	if (udev->config == NULL) {  		err = usb_get_configuration(udev);  		if (err < 0) { -			dev_err(&udev->dev, "can't read configurations, error %d\n", -				err); +			if (err != -ENODEV) +				dev_err(&udev->dev, "can't read configurations, error %d\n", +						err);  			return err;  		}  	} @@ -2640,14 +2644,16 @@ static int hub_port_reset(struct usb_hub *hub, int port1,  		status = set_port_feature(hub->hdev, port1, (warm ?  					USB_PORT_FEAT_BH_PORT_RESET :  					USB_PORT_FEAT_RESET)); -		if (status) { +		if (status == -ENODEV) { +			;	/* The hub is gone */ +		} else if (status) {  			dev_err(hub->intfdev,  					"cannot %sreset port %d (err = %d)\n",  					warm ? "warm " : "", port1, status);  		} else {  			status = hub_port_wait_reset(hub, port1, udev, delay,  								warm); -			if (status && status != -ENOTCONN) +			if (status && status != -ENOTCONN && status != -ENODEV)  				dev_dbg(hub->intfdev,  						"port_wait_reset: err = %d\n",  						status); @@ -2821,7 +2827,7 @@ void usb_enable_ltm(struct usb_device *udev)  }  EXPORT_SYMBOL_GPL(usb_enable_ltm); -#ifdef	CONFIG_USB_SUSPEND +#ifdef	CONFIG_PM  /*   * usb_disable_function_remotewakeup - disable usb3.0   * device's function remote wakeup @@ -2880,9 +2886,11 @@ static int usb_disable_function_remotewakeup(struct usb_device *udev)   * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd   * timer, no SRP, no requests through sysfs.   * - * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when - * the root hub for their bus goes into global suspend ... so we don't - * (falsely) update the device power state to say it suspended. + * If Runtime PM isn't enabled or used, non-SuperSpeed devices really get + * suspended only when their bus goes into global suspend (i.e., the root + * hub is suspended).  Nevertheless, we change @udev->state to + * USB_STATE_SUSPENDED as this is the device's "logical" state.  The actual + * upstream port setting is stored in @udev->port_is_suspended.   *   * Returns 0 on success, else negative errno.   */ @@ -2893,6 +2901,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  	enum pm_qos_flags_status pm_qos_stat;  	int		port1 = udev->portnum;  	int		status; +	bool		really_suspend = true;  	/* enable remote wakeup when appropriate; this lets the device  	 * wake up the upstream hub (including maybe the root hub). @@ -2949,9 +2958,19 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  	/* see 7.1.7.6 */  	if (hub_is_superspeed(hub->hdev))  		status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U3); -	else +	else if (PMSG_IS_AUTO(msg))  		status = set_port_feature(hub->hdev, port1,  						USB_PORT_FEAT_SUSPEND); +	/* +	 * For system suspend, we do not need to enable the suspend feature +	 * on individual USB-2 ports.  The devices will automatically go +	 * into suspend a few ms after the root hub stops sending packets. +	 * The USB 2.0 spec calls this "global suspend". +	 */ +	else { +		really_suspend = false; +		status = 0; +	}  	if (status) {  		dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",  				port1, status); @@ -2987,8 +3006,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  				(PMSG_IS_AUTO(msg) ? "auto-" : ""),  				udev->do_remote_wakeup);  		usb_set_device_state(udev, USB_STATE_SUSPENDED); -		udev->port_is_suspended = 1; -		msleep(10); +		if (really_suspend) { +			udev->port_is_suspended = 1; +			msleep(10); +		}  	}  	/* @@ -3226,6 +3247,10 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  	return status;  } +#endif	/* CONFIG_PM */ + +#ifdef	CONFIG_PM_RUNTIME +  /* caller has locked udev */  int usb_remote_wakeup(struct usb_device *udev)  { @@ -3242,38 +3267,6 @@ int usb_remote_wakeup(struct usb_device *udev)  	return status;  } -#else	/* CONFIG_USB_SUSPEND */ - -/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */ - -int usb_port_suspend(struct usb_device *udev, pm_message_t msg) -{ -	return 0; -} - -/* However we may need to do a reset-resume */ - -int usb_port_resume(struct usb_device *udev, pm_message_t msg) -{ -	struct usb_hub	*hub = usb_hub_to_struct_hub(udev->parent); -	int		port1 = udev->portnum; -	int		status; -	u16		portchange, portstatus; - -	status = hub_port_status(hub, port1, &portstatus, &portchange); -	status = check_port_resume_type(udev, -			hub, port1, status, portchange, portstatus); - -	if (status) { -		dev_dbg(&udev->dev, "can't resume, status %d\n", status); -		hub_port_logical_disconnect(hub, port1); -	} else if (udev->reset_resume) { -		dev_dbg(&udev->dev, "reset-resume\n"); -		status = usb_reset_and_verify_device(udev); -	} -	return status; -} -  #endif  static int check_ports_changed(struct usb_hub *hub) @@ -4090,9 +4083,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  				goto fail;  			}  			if (r) { -				dev_err(&udev->dev, -					"device descriptor read/64, error %d\n", -					r); +				if (r != -ENODEV) +					dev_err(&udev->dev, "device descriptor read/64, error %d\n", +							r);  				retval = -EMSGSIZE;  				continue;  			} @@ -4112,9 +4105,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  				msleep(200);  			}  			if (retval < 0) { -				dev_err(&udev->dev, -					"device not accepting address %d, error %d\n", -					devnum, retval); +				if (retval != -ENODEV) +					dev_err(&udev->dev, "device not accepting address %d, error %d\n", +							devnum, retval);  				goto fail;  			}  			if (udev->speed == USB_SPEED_SUPER) { @@ -4136,7 +4129,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  		retval = usb_get_device_descriptor(udev, 8);  		if (retval < 8) { -			dev_err(&udev->dev, +			if (retval != -ENODEV) +				dev_err(&udev->dev,  					"device descriptor read/8, error %d\n",  					retval);  			if (retval >= 0) @@ -4190,8 +4184,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  	retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);  	if (retval < (signed)sizeof(udev->descriptor)) { -		dev_err(&udev->dev, "device descriptor read/all, error %d\n", -			retval); +		if (retval != -ENODEV) +			dev_err(&udev->dev, "device descriptor read/all, error %d\n", +					retval);  		if (retval >= 0)  			retval = -ENOMSG;  		goto fail; @@ -4333,7 +4328,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		if (portstatus & USB_PORT_STAT_ENABLE) {  			status = 0;		/* Nothing to do */ -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  		} else if (udev->state == USB_STATE_SUSPENDED &&  				udev->persist_enabled) {  			/* For a suspended device, treat this as a @@ -4373,7 +4368,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  				USB_PORT_STAT_C_ENABLE)) {  		status = hub_port_debounce_be_stable(hub, port1);  		if (status < 0) { -			if (printk_ratelimit()) +			if (status != -ENODEV && printk_ratelimit())  				dev_err(hub_dev, "connect-debounce failed, "  						"port %d disabled\n", port1);  			portstatus &= ~USB_PORT_STAT_CONNECTION; @@ -4402,6 +4397,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  	else  		unit_load = 100; +	status = 0;  	for (i = 0; i < SET_CONFIG_TRIES; i++) {  		/* reallocate for each attempt, since references @@ -4526,9 +4522,11 @@ loop:  	}  	if (hub->hdev->parent ||  			!hcd->driver->port_handed_over || -			!(hcd->driver->port_handed_over)(hcd, port1)) -		dev_err(hub_dev, "unable to enumerate USB device on port %d\n", -				port1); +			!(hcd->driver->port_handed_over)(hcd, port1)) { +		if (status != -ENOTCONN && status != -ENODEV) +			dev_err(hub_dev, "unable to enumerate USB device on port %d\n", +					port1); +	}  done:  	hub_port_disable(hub, port1, 1); diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 797f9d51473..06c4894bf18 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -71,7 +71,7 @@ static void usb_port_device_release(struct device *dev)  	kfree(port_dev);  } -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  static int usb_port_runtime_resume(struct device *dev)  {  	struct usb_port *port_dev = to_usb_port(dev); @@ -139,7 +139,7 @@ static int usb_port_runtime_suspend(struct device *dev)  #endif  static const struct dev_pm_ops usb_port_pm_ops = { -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  	.runtime_suspend =	usb_port_runtime_suspend,  	.runtime_resume =	usb_port_runtime_resume,  	.runtime_idle =		pm_generic_runtime_idle, diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 3113c1d7144..ab5638d9c70 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -201,20 +201,14 @@ void usb_detect_quirks(struct usb_device *udev)  		dev_dbg(&udev->dev, "USB quirks for this device: %x\n",  			udev->quirks); -	/* For the present, all devices default to USB-PERSIST enabled */ -#if 0		/* was: #ifdef CONFIG_PM */ -	/* Hubs are automatically enabled for USB-PERSIST */ -	if (udev->descriptor.bDeviceClass == USB_CLASS_HUB) +#ifdef CONFIG_USB_DEFAULT_PERSIST +	if (!(udev->quirks & USB_QUIRK_RESET))  		udev->persist_enabled = 1; -  #else -	/* In the absence of PM, we can safely enable USB-PERSIST -	 * for all devices.  It will affect things like hub resets -	 * and EMF-related port disables. -	 */ -	if (!(udev->quirks & USB_QUIRK_RESET)) +	/* Hubs are automatically enabled for USB-PERSIST */ +	if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)  		udev->persist_enabled = 1; -#endif	/* CONFIG_PM */ +#endif	/* CONFIG_USB_DEFAULT_PERSIST */  }  void usb_detect_interface_quirks(struct usb_device *udev) diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 3f81a3dc686..aa38db44818 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -338,7 +338,7 @@ static void remove_persist_attributes(struct device *dev)  #endif	/* CONFIG_PM */ -#ifdef	CONFIG_USB_SUSPEND +#ifdef	CONFIG_PM_RUNTIME  static ssize_t  show_connected_duration(struct device *dev, struct device_attribute *attr, @@ -544,7 +544,7 @@ static void remove_power_attributes(struct device *dev)  #define add_power_attributes(dev)	0  #define remove_power_attributes(dev)	do {} while (0) -#endif	/* CONFIG_USB_SUSPEND */ +#endif	/* CONFIG_PM_RUNTIME */  /* Descriptor fields */ diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index e0d9d948218..16927fa88fb 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -683,10 +683,13 @@ EXPORT_SYMBOL_GPL(usb_kill_urb);  void usb_poison_urb(struct urb *urb)  {  	might_sleep(); -	if (!(urb && urb->dev && urb->ep)) +	if (!urb)  		return;  	atomic_inc(&urb->reject); +	if (!urb->dev || !urb->ep) +		return; +  	usb_hcd_unlink_urb(urb, -ENOENT);  	wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);  } diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index b6f4bad3f75..255c14464bf 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -15,6 +15,7 @@  #include <linux/kernel.h>  #include <linux/acpi.h>  #include <linux/pci.h> +#include <linux/usb/hcd.h>  #include <acpi/acpi_bus.h>  #include "usb.h" @@ -188,8 +189,13 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)  		 * connected to.  		 */  		if (!udev->parent) { -			*handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev), +			struct usb_hcd *hcd = bus_to_hcd(udev->bus); +			int raw_port_num; + +			raw_port_num = usb_hcd_find_raw_port_number(hcd,  				port_num); +			*handle = acpi_get_child(DEVICE_ACPI_HANDLE(&udev->dev), +				raw_port_num);  			if (!*handle)  				return -ENODEV;  		} else { diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index f81b9257273..03eb7ae8fc1 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -49,7 +49,7 @@ const char *usbcore_name = "usbcore";  static bool nousb;	/* Disable USB when built into kernel image */ -#ifdef	CONFIG_USB_SUSPEND +#ifdef	CONFIG_PM_RUNTIME  static int usb_autosuspend_delay = 2;		/* Default delay value,  						 * in seconds */  module_param_named(autosuspend, usb_autosuspend_delay, int, 0644); @@ -307,7 +307,7 @@ static const struct dev_pm_ops usb_device_pm_ops = {  	.thaw =		usb_dev_thaw,  	.poweroff =	usb_dev_poweroff,  	.restore =	usb_dev_restore, -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  	.runtime_suspend =	usb_runtime_suspend,  	.runtime_resume =	usb_runtime_resume,  	.runtime_idle =		usb_runtime_idle, diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index a7f20bde0e5..823857767a1 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -93,7 +93,7 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)  #endif -#ifdef CONFIG_USB_SUSPEND +#ifdef CONFIG_PM_RUNTIME  extern void usb_autosuspend_device(struct usb_device *udev);  extern int usb_autoresume_device(struct usb_device *udev); diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 86d5d804f1e..a61d981cbd1 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -145,6 +145,7 @@ config USB_LPC32XX  	tristate "LPC32XX USB Peripheral Controller"  	depends on ARCH_LPC32XX  	select USB_ISP1301 +	select USB_OTG_UTILS  	help  	   This option selects the USB device controller in the LPC32xx SoC. diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 970c9057757..36e8c44d8e5 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -447,14 +447,13 @@ static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req)  static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req)  {  	struct f_rndis			*rndis = req->context; -	struct usb_composite_dev	*cdev = rndis->port.func.config->cdev;  	int				status;  	/* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */  //	spin_lock(&dev->lock);  	status = rndis_msg_parser(rndis->config, (u8 *) req->buf);  	if (status < 0) -		ERROR(cdev, "RNDIS command error %d, %d/%d\n", +		pr_err("RNDIS command error %d, %d/%d\n",  			status, req->actual, req->length);  //	spin_unlock(&dev->lock);  } diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index a07dd177e84..787a78e92aa 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -363,7 +363,7 @@ static int gfs_bind(struct usb_composite_dev *cdev)  		goto error;  	gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id; -	for (i = func_num; --i; ) { +	for (i = func_num; i--; ) {  		ret = functionfs_bind(ffs_tab[i].ffs_data, cdev);  		if (unlikely(ret < 0)) {  			while (++i < func_num) @@ -419,7 +419,7 @@ static int gfs_unbind(struct usb_composite_dev *cdev)  		gether_cleanup(the_dev);  	gfs_ether_setup = false; -	for (i = func_num; --i; ) +	for (i = func_num; i--; )  		if (ffs_tab[i].ffs_data)  			functionfs_unbind(ffs_tab[i].ffs_data); diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index ce450a18aa1..f1e50a3e322 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -58,7 +58,7 @@ static const char * const ep_name[] = {  	"ep-a", "ep-b", "ep-c",  }; -#ifdef CONFIG_USB_GADGET_NET2272_DMA +#ifdef CONFIG_USB_NET2272_DMA  /*   * use_dma: the NET2272 can use an external DMA controller.   * Note that since there is no generic DMA api, some functions, @@ -1492,6 +1492,13 @@ stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver)  	for (i = 0; i < 4; ++i)  		net2272_dequeue_all(&dev->ep[i]); +	/* report disconnect; the driver is already quiesced */ +	if (driver) { +		spin_unlock(&dev->lock); +		driver->disconnect(&dev->gadget); +		spin_lock(&dev->lock); +	} +  	net2272_usb_reinit(dev);  } diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index e869188bc2b..fbd006ab31d 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1920,7 +1920,6 @@ static int net2280_start(struct usb_gadget *_gadget,  err_func:  	device_remove_file (&dev->pdev->dev, &dev_attr_function);  err_unbind: -	driver->unbind (&dev->gadget);  	dev->driver = NULL;  	return retval;  } @@ -1941,6 +1940,13 @@ stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)  	for (i = 0; i < 7; i++)  		nuke (&dev->ep [i]); +	/* report disconnect; the driver is already quiesced */ +	if (driver) { +		spin_unlock(&dev->lock); +		driver->disconnect(&dev->gadget); +		spin_lock(&dev->lock); +	} +  	usb_reinit (dev);  } diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index c5034d9c946..b369292d4b9 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -136,7 +136,7 @@ static struct portmaster {  	pr_debug(fmt, ##arg)  #endif /* pr_vdebug */  #else -#ifndef pr_vdebig +#ifndef pr_vdebug  #define pr_vdebug(fmt, arg...) \  	({ if (0) pr_debug(fmt, ##arg); })  #endif /* pr_vdebug */ diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index c6c2b5611b4..ffd8fa54110 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -271,7 +271,7 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)  	usb_gadget_disconnect(udc->gadget);  	udc->driver->disconnect(udc->gadget);  	udc->driver->unbind(udc->gadget); -	usb_gadget_udc_stop(udc->gadget, udc->driver); +	usb_gadget_udc_stop(udc->gadget, NULL);  	udc->driver = NULL;  	udc->dev.driver = NULL; diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 1b58587b7be..f7af0984743 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -155,8 +155,9 @@ config USB_EHCI_MXC  	  Variation of ARC USB block used in some Freescale chips.  config USB_EHCI_HCD_OMAP -	bool "EHCI support for OMAP3 and later chips" +	tristate "EHCI support for OMAP3 and later chips"  	depends on USB_EHCI_HCD && ARCH_OMAP +	select NOP_USB_XCEIV  	default y  	---help---  	  Enables support for the on-chip EHCI controller on diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 001fbff2fde..56de4106c8b 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_USB_EHCI_HCD)	+= ehci-hcd.o  obj-$(CONFIG_USB_EHCI_PCI)	+= ehci-pci.o  obj-$(CONFIG_USB_EHCI_HCD_PLATFORM)	+= ehci-platform.o  obj-$(CONFIG_USB_EHCI_MXC)	+= ehci-mxc.o +obj-$(CONFIG_USB_EHCI_HCD_OMAP)	+= ehci-omap.o  obj-$(CONFIG_USB_OXU210HP_HCD)	+= oxu210hp-hcd.o  obj-$(CONFIG_USB_ISP116X_HCD)	+= isp116x-hcd.o diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 70b496dc18a..5429d2645bb 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -510,14 +510,16 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)  	spin_lock_irqsave (&ehci->lock, flags);  	for (qh = ehci->async->qh_next.qh; size > 0 && qh; qh = qh->qh_next.qh)  		qh_lines (ehci, qh, &next, &size); -	if (ehci->async_unlink && size > 0) { +	if (!list_empty(&ehci->async_unlink) && size > 0) {  		temp = scnprintf(next, size, "\nunlink =\n");  		size -= temp;  		next += temp; -		for (qh = ehci->async_unlink; size > 0 && qh; -				qh = qh->unlink_next) -			qh_lines (ehci, qh, &next, &size); +		list_for_each_entry(qh, &ehci->async_unlink, unlink_node) { +			if (size <= 0) +				break; +			qh_lines(ehci, qh, &next, &size); +		}  	}  	spin_unlock_irqrestore (&ehci->lock, flags); @@ -814,9 +816,10 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)  		}  	} -	if (ehci->async_unlink) { +	if (!list_empty(&ehci->async_unlink)) {  		temp = scnprintf(next, size, "async unlink qh %p\n", -				ehci->async_unlink); +				list_first_entry(&ehci->async_unlink, +						struct ehci_qh, unlink_node));  		size -= temp;  		next += temp;  	} diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index d81d2fcbff1..3be3df233a0 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -370,6 +370,15 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)  	/* EHCI registers start at offset 0x100 */  	ehci->caps = hcd->regs + 0x100; +#ifdef CONFIG_PPC_83xx +	/* +	 * Deal with MPC834X that need port power to be cycled after the power +	 * fault condition is removed. Otherwise the state machine does not +	 * reflect PORTSC[CSC] correctly. +	 */ +	ehci->need_oc_pp_cycle = 1; +#endif +  	hcd->has_tt = 1;  	retval = ehci_setup(hcd); diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 5726cb144ab..b12b97d2cca 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -302,6 +302,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)  static void end_unlink_async(struct ehci_hcd *ehci);  static void unlink_empty_async(struct ehci_hcd *ehci); +static void unlink_empty_async_suspended(struct ehci_hcd *ehci);  static void ehci_work(struct ehci_hcd *ehci);  static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh);  static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh); @@ -481,6 +482,9 @@ static int ehci_init(struct usb_hcd *hcd)  	 * periodic_size can shrink by USBCMD update if hcc_params allows.  	 */  	ehci->periodic_size = DEFAULT_I_TDPS; +	INIT_LIST_HEAD(&ehci->async_unlink); +	INIT_LIST_HEAD(&ehci->async_idle); +	INIT_LIST_HEAD(&ehci->intr_unlink);  	INIT_LIST_HEAD(&ehci->intr_qh_list);  	INIT_LIST_HEAD(&ehci->cached_itd_list);  	INIT_LIST_HEAD(&ehci->cached_sitd_list); @@ -748,7 +752,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)  		/* guard against (alleged) silicon errata */  		if (cmd & CMD_IAAD)  			ehci_dbg(ehci, "IAA with IAAD still set?\n"); -		if (ehci->async_iaa) +		if (ehci->iaa_in_progress)  			COUNT(ehci->stats.iaa);  		end_unlink_async(ehci);  	} @@ -756,7 +760,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)  	/* remote wakeup [4.3.1] */  	if (status & STS_PCD) {  		unsigned	i = HCS_N_PORTS (ehci->hcs_params); -		u32		ppcd = 0; +		u32		ppcd = ~0;  		/* kick root hub later */  		pcd_status = status; @@ -773,7 +777,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)  			int pstatus;  			/* leverage per-port change bits feature */ -			if (ehci->has_ppcd && !(ppcd & (1 << i))) +			if (!(ppcd & (1 << i)))  				continue;  			pstatus = ehci_readl(ehci,  					 &ehci->regs->port_status[i]); @@ -895,17 +899,24 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  	if (rc)  		goto done; -	switch (usb_pipetype (urb->pipe)) { -	// case PIPE_CONTROL: -	// case PIPE_BULK: -	default: +	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { +		/* +		 * We don't expedite dequeue for isochronous URBs. +		 * Just wait until they complete normally or their +		 * time slot expires. +		 */ +	} else {  		qh = (struct ehci_qh *) urb->hcpriv; -		if (!qh) -			break; +		qh->exception = 1;  		switch (qh->qh_state) {  		case QH_STATE_LINKED: +			if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) +				start_unlink_intr(ehci, qh); +			else +				start_unlink_async(ehci, qh); +			break;  		case QH_STATE_COMPLETING: -			start_unlink_async(ehci, qh); +			qh->dequeue_during_giveback = 1;  			break;  		case QH_STATE_UNLINK:  		case QH_STATE_UNLINK_WAIT: @@ -916,33 +927,6 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  			qh_completions(ehci, qh);  			break;  		} -		break; - -	case PIPE_INTERRUPT: -		qh = (struct ehci_qh *) urb->hcpriv; -		if (!qh) -			break; -		switch (qh->qh_state) { -		case QH_STATE_LINKED: -		case QH_STATE_COMPLETING: -			start_unlink_intr(ehci, qh); -			break; -		case QH_STATE_IDLE: -			qh_completions (ehci, qh); -			break; -		default: -			ehci_dbg (ehci, "bogus qh %p state %d\n", -					qh, qh->qh_state); -			goto done; -		} -		break; - -	case PIPE_ISOCHRONOUS: -		// itd or sitd ... - -		// wait till next completion, do it then. -		// completion irqs can wait up to 1024 msec, -		break;  	}  done:  	spin_unlock_irqrestore (&ehci->lock, flags); @@ -983,6 +967,7 @@ rescan:  		goto done;  	} +	qh->exception = 1;  	if (ehci->rh_state < EHCI_RH_RUNNING)  		qh->qh_state = QH_STATE_IDLE;  	switch (qh->qh_state) { @@ -1051,13 +1036,12 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)  		usb_settoggle(qh->dev, epnum, is_out, 0);  		if (!list_empty(&qh->qtd_list)) {  			WARN_ONCE(1, "clear_halt for a busy endpoint\n"); -		} else if (qh->qh_state == QH_STATE_LINKED || -				qh->qh_state == QH_STATE_COMPLETING) { - +		} else {  			/* The toggle value in the QH can't be updated  			 * while the QH is active.  Unlink it now;  			 * re-linking will call qh_refresh().  			 */ +			qh->exception = 1;  			if (eptype == USB_ENDPOINT_XFER_BULK)  				start_unlink_async(ehci, qh);  			else @@ -1250,11 +1234,6 @@ MODULE_LICENSE ("GPL");  #define PLATFORM_DRIVER		ehci_hcd_sh_driver  #endif -#ifdef CONFIG_USB_EHCI_HCD_OMAP -#include "ehci-omap.c" -#define        PLATFORM_DRIVER         ehci_hcd_omap_driver -#endif -  #ifdef CONFIG_PPC_PS3  #include "ehci-ps3.c"  #define	PS3_SYSTEM_BUS_DRIVER	ps3_ehci_driver @@ -1290,11 +1269,6 @@ MODULE_LICENSE ("GPL");  #define PLATFORM_DRIVER		ehci_octeon_driver  #endif -#ifdef CONFIG_ARCH_VT8500 -#include "ehci-vt8500.c" -#define	PLATFORM_DRIVER		vt8500_ehci_driver -#endif -  #ifdef CONFIG_PLAT_SPEAR  #include "ehci-spear.c"  #define PLATFORM_DRIVER		spear_ehci_hcd_driver @@ -1344,6 +1318,7 @@ MODULE_LICENSE ("GPL");  	!IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) && \  	!IS_ENABLED(CONFIG_USB_CHIPIDEA_HOST) && \  	!IS_ENABLED(CONFIG_USB_EHCI_MXC) && \ +	!IS_ENABLED(CONFIG_USB_EHCI_HCD_OMAP) && \  	!defined(PLATFORM_DRIVER) && \  	!defined(PS3_SYSTEM_BUS_DRIVER) && \  	!defined(OF_PLATFORM_DRIVER) && \ diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 4d3b294f203..9ab4a4d9768 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -328,7 +328,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)  	ehci->rh_state = EHCI_RH_SUSPENDED;  	end_unlink_async(ehci); -	unlink_empty_async(ehci); +	unlink_empty_async_suspended(ehci);  	ehci_handle_intr_unlinks(ehci);  	end_free_itds(ehci); @@ -464,7 +464,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)  	while (i--) {  		temp = ehci_readl(ehci, &ehci->regs->port_status [i]);  		if (test_bit(i, &resume_needed)) { -			temp &= ~(PORT_RWC_BITS | PORT_RESUME); +			temp &= ~(PORT_RWC_BITS | PORT_SUSPEND | PORT_RESUME);  			ehci_writel(ehci, temp, &ehci->regs->port_status [i]);  			ehci_vdbg (ehci, "resumed port %d\n", i + 1);  		} @@ -590,7 +590,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)  	u32		mask;  	int		ports, i, retval = 1;  	unsigned long	flags; -	u32		ppcd = 0; +	u32		ppcd = ~0;  	/* init status to no-changes */  	buf [0] = 0; @@ -628,9 +628,10 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)  	for (i = 0; i < ports; i++) {  		/* leverage per-port change bits feature */ -		if (ehci->has_ppcd && !(ppcd & (1 << i))) -			continue; -		temp = ehci_readl(ehci, &ehci->regs->port_status [i]); +		if (ppcd & (1 << i)) +			temp = ehci_readl(ehci, &ehci->regs->port_status[i]); +		else +			temp = 0;  		/*  		 * Return status information even for ports with OWNER set. @@ -839,7 +840,8 @@ static int ehci_hub_control (  			 * power switching; they're allowed to just limit the  			 * current.  khubd will turn the power back on.  			 */ -			if ((temp & PORT_OC) && HCS_PPC(ehci->hcs_params)) { +			if (((temp & PORT_OC) || (ehci->need_oc_pp_cycle)) +					&& HCS_PPC(ehci->hcs_params)) {  				ehci_writel(ehci,  					temp & ~(PORT_RWC_BITS | PORT_POWER),  					status_reg); @@ -870,10 +872,9 @@ static int ehci_hub_control (  				usb_hcd_end_port_resume(&hcd->self, wIndex);  				/* stop resume signaling */ -				temp = ehci_readl(ehci, status_reg); -				ehci_writel(ehci, -					temp & ~(PORT_RWC_BITS | PORT_RESUME), -					status_reg); +				temp &= ~(PORT_RWC_BITS | +						PORT_SUSPEND | PORT_RESUME); +				ehci_writel(ehci, temp, status_reg);  				clear_bit(wIndex, &ehci->resuming_ports);  				retval = handshake(ehci, status_reg,  					   PORT_RESUME, 0, 2000 /* 2msec */); @@ -883,7 +884,7 @@ static int ehci_hub_control (  						wIndex + 1, retval);  					goto error;  				} -				temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10)); +				temp = ehci_readl(ehci, status_reg);  			}  		} diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index 6bad41af1c4..402062973f0 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -210,7 +210,7 @@ static int mv_ehci_probe(struct platform_device *pdev)  		(void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset);  	hcd->rsrc_start = r->start; -	hcd->rsrc_len = r->end - r->start + 1; +	hcd->rsrc_len = resource_size(r);  	hcd->regs = ehci_mv->op_regs;  	hcd->irq = platform_get_irq(pdev, 0); diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index e9301fb97ea..a38c8c8e5b0 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -28,11 +28,7 @@  #include <linux/slab.h>  #include <linux/usb.h>  #include <linux/usb/hcd.h> -  #include <linux/platform_data/usb-ehci-mxc.h> - -#include <asm/mach-types.h> -  #include "ehci.h"  #define DRIVER_DESC "Freescale On-Chip EHCI Host driver" @@ -61,8 +57,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)  	struct device *dev = &pdev->dev;  	struct ehci_hcd *ehci; -	dev_info(&pdev->dev, "initializing i.MX USB Controller\n"); -  	if (!pdata) {  		dev_err(dev, "No platform data given, bailing out.\n");  		return -EINVAL; @@ -178,7 +172,7 @@ err_alloc:  	return ret;  } -static int __exit ehci_mxc_drv_remove(struct platform_device *pdev) +static int ehci_mxc_drv_remove(struct platform_device *pdev)  {  	struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;  	struct usb_hcd *hcd = platform_get_drvdata(pdev); diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 0555ee42d7c..5de3e43ded5 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -4,10 +4,11 @@   * Bus Glue for the EHCI controllers in OMAP3/4   * Tested on several OMAP3 boards, and OMAP4 Pandaboard   * - * Copyright (C) 2007-2011 Texas Instruments, Inc. + * Copyright (C) 2007-2013 Texas Instruments, Inc.   *	Author: Vikram Pandita <vikram.pandita@ti.com>   *	Author: Anand Gadiyar <gadiyar@ti.com>   *	Author: Keshava Munegowda <keshava_mgowda@ti.com> + *	Author: Roger Quadros <rogerq@ti.com>   *   * Copyright (C) 2009 Nokia Corporation   *	Contact: Felipe Balbi <felipe.balbi@nokia.com> @@ -28,21 +29,23 @@   * along with this program; if not, write to the Free Software   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA   * - * TODO (last updated Feb 27, 2010): - *	- add kernel-doc - *	- enable AUTOIDLE - *	- add suspend/resume - *	- add HSIC and TLL support - *	- convert to use hwmod and runtime PM   */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/io.h>  #include <linux/platform_device.h>  #include <linux/slab.h>  #include <linux/usb/ulpi.h> -#include <linux/regulator/consumer.h>  #include <linux/pm_runtime.h>  #include <linux/gpio.h>  #include <linux/clk.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/of.h> +#include <linux/dma-mapping.h> + +#include "ehci.h"  #include <linux/platform_data/usb-omap.h> @@ -57,10 +60,16 @@  #define	EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT		8  #define	EHCI_INSNREG05_ULPI_WRDATA_SHIFT		0 -/*-------------------------------------------------------------------------*/ +#define DRIVER_DESC "OMAP-EHCI Host Controller driver" + +static const char hcd_name[] = "ehci-omap"; -static const struct hc_driver ehci_omap_hc_driver; +/*-------------------------------------------------------------------------*/ +struct omap_hcd { +	struct usb_phy *phy[OMAP3_HS_USB_PORTS]; /* one PHY for each port */ +	int nports; +};  static inline void ehci_write(void __iomem *base, u32 reg, u32 val)  { @@ -72,99 +81,16 @@ static inline u32 ehci_read(void __iomem *base, u32 reg)  	return __raw_readl(base + reg);  } +/* configure so an HC device and id are always provided */ +/* always called with process context; sleeping is OK */ -static void omap_ehci_soft_phy_reset(struct usb_hcd *hcd, u8 port) -{ -	unsigned long timeout = jiffies + msecs_to_jiffies(1000); -	unsigned reg = 0; - -	reg = ULPI_FUNC_CTRL_RESET -		/* FUNCTION_CTRL_SET register */ -		| (ULPI_SET(ULPI_FUNC_CTRL) << EHCI_INSNREG05_ULPI_REGADD_SHIFT) -		/* Write */ -		| (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT) -		/* PORTn */ -		| ((port + 1) << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT) -		/* start ULPI access*/ -		| (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT); - -	ehci_write(hcd->regs, EHCI_INSNREG05_ULPI, reg); - -	/* Wait for ULPI access completion */ -	while ((ehci_read(hcd->regs, EHCI_INSNREG05_ULPI) -			& (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) { -		cpu_relax(); - -		if (time_after(jiffies, timeout)) { -			dev_dbg(hcd->self.controller, -					"phy reset operation timed out\n"); -			break; -		} -	} -} - -static int omap_ehci_init(struct usb_hcd *hcd) -{ -	struct ehci_hcd		*ehci = hcd_to_ehci(hcd); -	int			rc; -	struct usbhs_omap_platform_data	*pdata; - -	pdata = hcd->self.controller->platform_data; - -	/* Hold PHYs in reset while initializing EHCI controller */ -	if (pdata->phy_reset) { -		if (gpio_is_valid(pdata->reset_gpio_port[0])) -			gpio_set_value_cansleep(pdata->reset_gpio_port[0], 0); - -		if (gpio_is_valid(pdata->reset_gpio_port[1])) -			gpio_set_value_cansleep(pdata->reset_gpio_port[1], 0); - -		/* Hold the PHY in RESET for enough time till DIR is high */ -		udelay(10); -	} - -	/* Soft reset the PHY using PHY reset command over ULPI */ -	if (pdata->port_mode[0] == OMAP_EHCI_PORT_MODE_PHY) -		omap_ehci_soft_phy_reset(hcd, 0); -	if (pdata->port_mode[1] == OMAP_EHCI_PORT_MODE_PHY) -		omap_ehci_soft_phy_reset(hcd, 1); - -	/* we know this is the memory we want, no need to ioremap again */ -	ehci->caps = hcd->regs; - -	rc = ehci_setup(hcd); - -	if (pdata->phy_reset) { -		/* Hold the PHY in RESET for enough time till -		 * PHY is settled and ready -		 */ -		udelay(10); - -		if (gpio_is_valid(pdata->reset_gpio_port[0])) -			gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1); - -		if (gpio_is_valid(pdata->reset_gpio_port[1])) -			gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1); -	} - -	return rc; -} - -static void disable_put_regulator( -		struct usbhs_omap_platform_data *pdata) -{ -	int i; +static struct hc_driver __read_mostly ehci_omap_hc_driver; -	for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { -		if (pdata->regulator[i]) { -			regulator_disable(pdata->regulator[i]); -			regulator_put(pdata->regulator[i]); -		} -	} -} +static const struct ehci_driver_overrides ehci_omap_overrides __initdata = { +	.extra_priv_size = sizeof(struct omap_hcd), +}; -/* configure so an HC device and id are always provided */ -/* always called with process context; sleeping is OK */ +static u64 omap_ehci_dma_mask = DMA_BIT_MASK(32);  /**   * ehci_hcd_omap_probe - initialize TI-based HCDs @@ -175,15 +101,15 @@ static void disable_put_regulator(   */  static int ehci_hcd_omap_probe(struct platform_device *pdev)  { -	struct device				*dev = &pdev->dev; -	struct usbhs_omap_platform_data		*pdata = dev->platform_data; -	struct resource				*res; -	struct usb_hcd				*hcd; -	void __iomem				*regs; -	int					ret = -ENODEV; -	int					irq; -	int					i; -	char					supply[7]; +	struct device *dev = &pdev->dev; +	struct usbhs_omap_platform_data *pdata = dev->platform_data; +	struct resource	*res; +	struct usb_hcd	*hcd; +	void __iomem *regs; +	int ret = -ENODEV; +	int irq; +	int i; +	struct omap_hcd	*omap;  	if (usb_disabled())  		return -ENODEV; @@ -193,52 +119,74 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)  		return -ENODEV;  	} -	irq = platform_get_irq_byname(pdev, "ehci-irq"); -	if (irq < 0) { -		dev_err(dev, "EHCI irq failed\n"); -		return -ENODEV; +	/* For DT boot, get platform data from parent. i.e. usbhshost */ +	if (dev->of_node) { +		pdata = dev->parent->platform_data; +		dev->platform_data = pdata;  	} -	res =  platform_get_resource_byname(pdev, -				IORESOURCE_MEM, "ehci"); -	if (!res) { -		dev_err(dev, "UHH EHCI get resource failed\n"); +	if (!pdata) { +		dev_err(dev, "Missing platform data\n");  		return -ENODEV;  	} -	regs = ioremap(res->start, resource_size(res)); -	if (!regs) { -		dev_err(dev, "UHH EHCI ioremap failed\n"); -		return -ENOMEM; +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) { +		dev_err(dev, "EHCI irq failed\n"); +		return -ENODEV;  	} +	res =  platform_get_resource(pdev, IORESOURCE_MEM, 0); +	regs = devm_ioremap_resource(dev, res); +	if (IS_ERR(regs)) +		return PTR_ERR(regs); + +	/* +	 * Right now device-tree probed devices don't get dma_mask set. +	 * Since shared usb code relies on it, set it here for now. +	 * Once we have dma capability bindings this can go away. +	 */ +	if (!pdev->dev.dma_mask) +		pdev->dev.dma_mask = &omap_ehci_dma_mask; +  	hcd = usb_create_hcd(&ehci_omap_hc_driver, dev,  			dev_name(dev));  	if (!hcd) { -		dev_err(dev, "failed to create hcd with err %d\n", ret); -		ret = -ENOMEM; -		goto err_io; +		dev_err(dev, "Failed to create HCD\n"); +		return -ENOMEM;  	}  	hcd->rsrc_start = res->start;  	hcd->rsrc_len = resource_size(res);  	hcd->regs = regs; +	hcd_to_ehci(hcd)->caps = regs; -	/* get ehci regulator and enable */ -	for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) { -		if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) { -			pdata->regulator[i] = NULL; -			continue; -		} -		snprintf(supply, sizeof(supply), "hsusb%d", i); -		pdata->regulator[i] = regulator_get(dev, supply); -		if (IS_ERR(pdata->regulator[i])) { -			pdata->regulator[i] = NULL; -			dev_dbg(dev, -			"failed to get ehci port%d regulator\n", i); -		} else { -			regulator_enable(pdata->regulator[i]); +	omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv; +	omap->nports = pdata->nports; + +	platform_set_drvdata(pdev, hcd); + +	/* get the PHY devices if needed */ +	for (i = 0 ; i < omap->nports ; i++) { +		struct usb_phy *phy; + +		/* get the PHY device */ +		if (dev->of_node) +			phy = devm_usb_get_phy_by_phandle(dev, "phys", i); +		else +			phy = devm_usb_get_phy_dev(dev, i); +		if (IS_ERR(phy) || !phy) { +			/* Don't bail out if PHY is not absolutely necessary */ +			if (pdata->port_mode[i] != OMAP_EHCI_PORT_MODE_PHY) +				continue; + +			ret = IS_ERR(phy) ? PTR_ERR(phy) : -ENODEV; +			dev_err(dev, "Can't get PHY device for port %d: %d\n", +					i, ret); +			goto err_phy;  		} + +		omap->phy[i] = phy;  	}  	pm_runtime_enable(dev); @@ -262,16 +210,34 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)  		goto err_pm_runtime;  	} +	/* +	 * Bring PHYs out of reset. +	 * Even though HSIC mode is a PHY-less mode, the reset +	 * line exists between the chips and can be modelled +	 * as a PHY device for reset control. +	 */ +	for (i = 0; i < omap->nports; i++) { +		if (!omap->phy[i]) +			continue; + +		usb_phy_init(omap->phy[i]); +		/* bring PHY out of suspend */ +		usb_phy_set_suspend(omap->phy[i], 0); +	}  	return 0;  err_pm_runtime: -	disable_put_regulator(pdata);  	pm_runtime_put_sync(dev); + +err_phy: +	for (i = 0; i < omap->nports; i++) { +		if (omap->phy[i]) +			usb_phy_shutdown(omap->phy[i]); +	} +  	usb_put_hcd(hcd); -err_io: -	iounmap(regs);  	return ret;  } @@ -286,14 +252,19 @@ err_io:   */  static int ehci_hcd_omap_remove(struct platform_device *pdev)  { -	struct device *dev				= &pdev->dev; -	struct usb_hcd *hcd				= dev_get_drvdata(dev); +	struct device *dev = &pdev->dev; +	struct usb_hcd *hcd = dev_get_drvdata(dev); +	struct omap_hcd *omap = (struct omap_hcd *)hcd_to_ehci(hcd)->priv; +	int i;  	usb_remove_hcd(hcd); -	disable_put_regulator(dev->platform_data); -	iounmap(hcd->regs); -	usb_put_hcd(hcd); +	for (i = 0; i < omap->nports; i++) { +		if (omap->phy[i]) +			usb_phy_shutdown(omap->phy[i]); +	} + +	usb_put_hcd(hcd);  	pm_runtime_put_sync(dev);  	pm_runtime_disable(dev); @@ -308,6 +279,13 @@ static void ehci_hcd_omap_shutdown(struct platform_device *pdev)  		hcd->driver->shutdown(hcd);  } +static const struct of_device_id omap_ehci_dt_ids[] = { +	{ .compatible = "ti,ehci-omap" }, +	{ } +}; + +MODULE_DEVICE_TABLE(of, omap_ehci_dt_ids); +  static struct platform_driver ehci_hcd_omap_driver = {  	.probe			= ehci_hcd_omap_probe,  	.remove			= ehci_hcd_omap_remove, @@ -315,56 +293,35 @@ static struct platform_driver ehci_hcd_omap_driver = {  	/*.suspend		= ehci_hcd_omap_suspend, */  	/*.resume		= ehci_hcd_omap_resume, */  	.driver = { -		.name		= "ehci-omap", +		.name		= hcd_name, +		.of_match_table = of_match_ptr(omap_ehci_dt_ids),  	}  };  /*-------------------------------------------------------------------------*/ -static const struct hc_driver ehci_omap_hc_driver = { -	.description		= hcd_name, -	.product_desc		= "OMAP-EHCI Host Controller", -	.hcd_priv_size		= sizeof(struct ehci_hcd), - -	/* -	 * generic hardware linkage -	 */ -	.irq			= ehci_irq, -	.flags			= HCD_MEMORY | HCD_USB2, - -	/* -	 * basic lifecycle operations -	 */ -	.reset			= omap_ehci_init, -	.start			= ehci_run, -	.stop			= ehci_stop, -	.shutdown		= ehci_shutdown, - -	/* -	 * managing i/o requests and associated device resources -	 */ -	.urb_enqueue		= ehci_urb_enqueue, -	.urb_dequeue		= ehci_urb_dequeue, -	.endpoint_disable	= ehci_endpoint_disable, -	.endpoint_reset		= ehci_endpoint_reset, +static int __init ehci_omap_init(void) +{ +	if (usb_disabled()) +		return -ENODEV; -	/* -	 * scheduling support -	 */ -	.get_frame_number	= ehci_get_frame, +	pr_info("%s: " DRIVER_DESC "\n", hcd_name); -	/* -	 * root hub support -	 */ -	.hub_status_data	= ehci_hub_status_data, -	.hub_control		= ehci_hub_control, -	.bus_suspend		= ehci_bus_suspend, -	.bus_resume		= ehci_bus_resume, +	ehci_init_driver(&ehci_omap_hc_driver, &ehci_omap_overrides); +	return platform_driver_register(&ehci_hcd_omap_driver); +} +module_init(ehci_omap_init); -	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; +static void __exit ehci_omap_cleanup(void) +{ +	platform_driver_unregister(&ehci_hcd_omap_driver); +} +module_exit(ehci_omap_cleanup);  MODULE_ALIAS("platform:ehci-omap");  MODULE_AUTHOR("Texas Instruments, Inc.");  MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>"); +MODULE_AUTHOR("Roger Quadros <rogerq@ti.com>"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index 914a3ecfb5d..38c45fb3357 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -305,7 +305,7 @@ err1:  	return err;  } -static int __exit ehci_orion_drv_remove(struct platform_device *pdev) +static int ehci_orion_drv_remove(struct platform_device *pdev)  {  	struct usb_hcd *hcd = platform_get_drvdata(pdev);  	struct clk *clk; @@ -333,7 +333,7 @@ MODULE_DEVICE_TABLE(of, ehci_orion_dt_ids);  static struct platform_driver ehci_orion_driver = {  	.probe		= ehci_orion_drv_probe, -	.remove		= __exit_p(ehci_orion_drv_remove), +	.remove		= ehci_orion_drv_remove,  	.shutdown	= usb_hcd_platform_shutdown,  	.driver = {  		.name	= "orion-ehci", diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 170b9399e09..a573d5ff9ad 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -292,17 +292,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)  		}  	} -#ifdef	CONFIG_USB_SUSPEND -	/* REVISIT: the controller works fine for wakeup iff the root hub -	 * itself is "globally" suspended, but usbcore currently doesn't -	 * understand such things. -	 * -	 * System suspend currently expects to be able to suspend the entire -	 * device tree, device-at-a-time.  If we failed selective suspend -	 * reports, system suspend would fail; so the root hub code must claim -	 * success.  That's lying to usbcore, and it matters for runtime -	 * PM scenarios with selective suspend and remote wakeup... -	 */ +#ifdef	CONFIG_PM_RUNTIME  	if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))  		ehci_warn(ehci, "selective suspend/wakeup unavailable\n");  #endif diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index ca750639054..cda0fa9613e 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -18,11 +18,13 @@   *   * Licensed under the GNU/GPL. See COPYING for details.   */ +#include <linux/dma-mapping.h>  #include <linux/err.h>  #include <linux/kernel.h>  #include <linux/hrtimer.h>  #include <linux/io.h>  #include <linux/module.h> +#include <linux/of.h>  #include <linux/platform_device.h>  #include <linux/usb.h>  #include <linux/usb/hcd.h> @@ -62,22 +64,32 @@ static const struct ehci_driver_overrides platform_overrides __initdata = {  	.reset =	ehci_platform_reset,  }; +static struct usb_ehci_pdata ehci_platform_defaults; +  static int ehci_platform_probe(struct platform_device *dev)  {  	struct usb_hcd *hcd;  	struct resource *res_mem; -	struct usb_ehci_pdata *pdata = dev->dev.platform_data; +	struct usb_ehci_pdata *pdata;  	int irq;  	int err = -ENOMEM; -	if (!pdata) { -		WARN_ON(1); -		return -ENODEV; -	} -  	if (usb_disabled())  		return -ENODEV; +	/* +	 * use reasonable defaults so platforms don't have to provide these. +	 * with DT probing on ARM, none of these are set. +	 */ +	if (!dev->dev.platform_data) +		dev->dev.platform_data = &ehci_platform_defaults; +	if (!dev->dev.dma_mask) +		dev->dev.dma_mask = &dev->dev.coherent_dma_mask; +	if (!dev->dev.coherent_dma_mask) +		dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + +	pdata = dev->dev.platform_data; +  	irq = platform_get_irq(dev, 0);  	if (irq < 0) {  		dev_err(&dev->dev, "no irq provided"); @@ -139,6 +151,9 @@ static int ehci_platform_remove(struct platform_device *dev)  	if (pdata->power_off)  		pdata->power_off(dev); +	if (pdata == &ehci_platform_defaults) +		dev->dev.platform_data = NULL; +  	return 0;  } @@ -183,6 +198,12 @@ static int ehci_platform_resume(struct device *dev)  #define ehci_platform_resume	NULL  #endif /* CONFIG_PM */ +static const struct of_device_id vt8500_ehci_ids[] = { +	{ .compatible = "via,vt8500-ehci", }, +	{ .compatible = "wm,prizm-ehci", }, +	{} +}; +  static const struct platform_device_id ehci_platform_table[] = {  	{ "ehci-platform", 0 },  	{ } @@ -203,6 +224,7 @@ static struct platform_driver ehci_platform_driver = {  		.owner	= THIS_MODULE,  		.name	= "ehci-platform",  		.pm	= &ehci_platform_pm_ops, +		.of_match_table = of_match_ptr(vt8500_ehci_ids),  	}  }; diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index df5925a4f0d..fd983771b02 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -221,7 +221,6 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev)  	tmp = hcd->irq; -	ehci_shutdown(hcd);  	usb_remove_hcd(hcd);  	ps3_system_bus_set_drvdata(dev, NULL); diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 5464665f0b6..d34b399b78e 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -90,7 +90,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)  	struct ehci_qh_hw *hw = qh->hw;  	/* writes to an active overlay are unsafe */ -	BUG_ON(qh->qh_state != QH_STATE_IDLE); +	WARN_ON(qh->qh_state != QH_STATE_IDLE);  	hw->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);  	hw->hw_alt_next = EHCI_LIST_END(ehci); @@ -123,26 +123,19 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)  {  	struct ehci_qtd *qtd; -	if (list_empty (&qh->qtd_list)) -		qtd = qh->dummy; -	else { -		qtd = list_entry (qh->qtd_list.next, -				struct ehci_qtd, qtd_list); -		/* -		 * first qtd may already be partially processed. -		 * If we come here during unlink, the QH overlay region -		 * might have reference to the just unlinked qtd. The -		 * qtd is updated in qh_completions(). Update the QH -		 * overlay here. -		 */ -		if (qh->hw->hw_token & ACTIVE_BIT(ehci)) { -			qh->hw->hw_qtd_next = qtd->hw_next; -			qtd = NULL; -		} -	} +	qtd = list_entry(qh->qtd_list.next, struct ehci_qtd, qtd_list); -	if (qtd) -		qh_update (ehci, qh, qtd); +	/* +	 * first qtd may already be partially processed. +	 * If we come here during unlink, the QH overlay region +	 * might have reference to the just unlinked qtd. The +	 * qtd is updated in qh_completions(). Update the QH +	 * overlay here. +	 */ +	if (qh->hw->hw_token & ACTIVE_BIT(ehci)) +		qh->hw->hw_qtd_next = qtd->hw_next; +	else +		qh_update(ehci, qh, qtd);  }  /*-------------------------------------------------------------------------*/ @@ -299,8 +292,8 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);  /*   * Process and free completed qtds for a qh, returning URBs to drivers. - * Chases up to qh->hw_current.  Returns number of completions called, - * indicating how much "real" work we did. + * Chases up to qh->hw_current.  Returns nonzero if the caller should + * unlink qh.   */  static unsigned  qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) @@ -309,13 +302,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)  	struct list_head	*entry, *tmp;  	int			last_status;  	int			stopped; -	unsigned		count = 0;  	u8			state;  	struct ehci_qh_hw	*hw = qh->hw; -	if (unlikely (list_empty (&qh->qtd_list))) -		return count; -  	/* completions (or tasks on other cpus) must never clobber HALT  	 * till we've gone through and cleaned everything up, even when  	 * they add urbs to this qh's queue or mark them for unlinking. @@ -333,7 +322,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)   rescan:  	last = NULL;  	last_status = -EINPROGRESS; -	qh->needs_rescan = 0; +	qh->dequeue_during_giveback = 0;  	/* remove de-activated QTDs from front of queue.  	 * after faults (including short reads), cleanup this urb @@ -352,7 +341,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)  		if (last) {  			if (likely (last->urb != urb)) {  				ehci_urb_done(ehci, last->urb, last_status); -				count++;  				last_status = -EINPROGRESS;  			}  			ehci_qtd_free (ehci, last); @@ -526,23 +514,16 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)  	/* last urb's completion might still need calling */  	if (likely (last != NULL)) {  		ehci_urb_done(ehci, last->urb, last_status); -		count++;  		ehci_qtd_free (ehci, last);  	}  	/* Do we need to rescan for URBs dequeued during a giveback? */ -	if (unlikely(qh->needs_rescan)) { +	if (unlikely(qh->dequeue_during_giveback)) {  		/* If the QH is already unlinked, do the rescan now. */  		if (state == QH_STATE_IDLE)  			goto rescan; -		/* Otherwise we have to wait until the QH is fully unlinked. -		 * Our caller will start an unlink if qh->needs_rescan is -		 * set.  But if an unlink has already started, nothing needs -		 * to be done. -		 */ -		if (state != QH_STATE_LINKED) -			qh->needs_rescan = 0; +		/* Otherwise the caller must unlink the QH. */  	}  	/* restore original state; caller must unlink or relink */ @@ -551,33 +532,23 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)  	/* be sure the hardware's done with the qh before refreshing  	 * it after fault cleanup, or recovering from silicon wrongly  	 * overlaying the dummy qtd (which reduces DMA chatter). +	 * +	 * We won't refresh a QH that's linked (after the HC +	 * stopped the queue).  That avoids a race: +	 *  - HC reads first part of QH; +	 *  - CPU updates that first part and the token; +	 *  - HC reads rest of that QH, including token +	 * Result:  HC gets an inconsistent image, and then +	 * DMAs to/from the wrong memory (corrupting it). +	 * +	 * That should be rare for interrupt transfers, +	 * except maybe high bandwidth ...  	 */ -	if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) { -		switch (state) { -		case QH_STATE_IDLE: -			qh_refresh(ehci, qh); -			break; -		case QH_STATE_LINKED: -			/* We won't refresh a QH that's linked (after the HC -			 * stopped the queue).  That avoids a race: -			 *  - HC reads first part of QH; -			 *  - CPU updates that first part and the token; -			 *  - HC reads rest of that QH, including token -			 * Result:  HC gets an inconsistent image, and then -			 * DMAs to/from the wrong memory (corrupting it). -			 * -			 * That should be rare for interrupt transfers, -			 * except maybe high bandwidth ... -			 */ - -			/* Tell the caller to start an unlink */ -			qh->needs_rescan = 1; -			break; -		/* otherwise, unlink already started */ -		} -	} +	if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) +		qh->exception = 1; -	return count; +	/* Let the caller know if the QH needs to be unlinked. */ +	return qh->exception;  }  /*-------------------------------------------------------------------------*/ @@ -957,14 +928,13 @@ done:  	/* NOTE:  if (PIPE_INTERRUPT) { scheduler sets s-mask } */ -	/* init as live, toggle clear, advance to dummy */ +	/* init as live, toggle clear */  	qh->qh_state = QH_STATE_IDLE;  	hw = qh->hw;  	hw->hw_info1 = cpu_to_hc32(ehci, info1);  	hw->hw_info2 = cpu_to_hc32(ehci, info2);  	qh->is_out = !is_input;  	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); -	qh_refresh (ehci, qh);  	return qh;  } @@ -988,8 +958,9 @@ static void disable_async(struct ehci_hcd *ehci)  	if (--ehci->async_count)  		return; -	/* The async schedule and async_unlink list are supposed to be empty */ -	WARN_ON(ehci->async->qh_next.qh || ehci->async_unlink); +	/* The async schedule and unlink lists are supposed to be empty */ +	WARN_ON(ehci->async->qh_next.qh || !list_empty(&ehci->async_unlink) || +			!list_empty(&ehci->async_idle));  	/* Don't turn off the schedule until ASS is 1 */  	ehci_poll_ASS(ehci); @@ -1020,8 +991,9 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)  	head->qh_next.qh = qh;  	head->hw->hw_next = dma; -	qh->xacterrs = 0;  	qh->qh_state = QH_STATE_LINKED; +	qh->xacterrs = 0; +	qh->exception = 0;  	/* qtd completions reported later by interrupt */  	enable_async(ehci); @@ -1179,11 +1151,7 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)  	/* Add to the end of the list of QHs waiting for the next IAAD */  	qh->qh_state = QH_STATE_UNLINK_WAIT; -	if (ehci->async_unlink) -		ehci->async_unlink_last->unlink_next = qh; -	else -		ehci->async_unlink = qh; -	ehci->async_unlink_last = qh; +	list_add_tail(&qh->unlink_node, &ehci->async_unlink);  	/* Unlink it from the schedule */  	prev = ehci->async; @@ -1196,44 +1164,19 @@ static void single_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)  		ehci->qh_scan_next = qh->qh_next.qh;  } -static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested) +static void start_iaa_cycle(struct ehci_hcd *ehci)  { -	/* -	 * Do nothing if an IAA cycle is already running or -	 * if one will be started shortly. -	 */ -	if (ehci->async_iaa || ehci->async_unlinking) +	/* Do nothing if an IAA cycle is already running */ +	if (ehci->iaa_in_progress)  		return; +	ehci->iaa_in_progress = true;  	/* If the controller isn't running, we don't have to wait for it */  	if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) { - -		/* Do all the waiting QHs */ -		ehci->async_iaa = ehci->async_unlink; -		ehci->async_unlink = NULL; - -		if (!nested)		/* Avoid recursion */ -			end_unlink_async(ehci); +		end_unlink_async(ehci);  	/* Otherwise start a new IAA cycle */  	} else if (likely(ehci->rh_state == EHCI_RH_RUNNING)) { -		struct ehci_qh		*qh; - -		/* Do only the first waiting QH (nVidia bug?) */ -		qh = ehci->async_unlink; - -		/* -		 * Intel (?) bug: The HC can write back the overlay region -		 * even after the IAA interrupt occurs.  In self-defense, -		 * always go through two IAA cycles for each QH. -		 */ -		if (qh->qh_state == QH_STATE_UNLINK_WAIT) { -			qh->qh_state = QH_STATE_UNLINK; -		} else { -			ehci->async_iaa = qh; -			ehci->async_unlink = qh->unlink_next; -			qh->unlink_next = NULL; -		}  		/* Make sure the unlinks are all visible to the hardware */  		wmb(); @@ -1250,36 +1193,73 @@ static void start_iaa_cycle(struct ehci_hcd *ehci, bool nested)  static void end_unlink_async(struct ehci_hcd *ehci)  {  	struct ehci_qh		*qh; +	bool			early_exit;  	if (ehci->has_synopsys_hc_bug)  		ehci_writel(ehci, (u32) ehci->async->qh_dma,  			    &ehci->regs->async_next); +	/* The current IAA cycle has ended */ +	ehci->iaa_in_progress = false; + +	if (list_empty(&ehci->async_unlink)) +		return; +	qh = list_first_entry(&ehci->async_unlink, struct ehci_qh, +			unlink_node);	/* QH whose IAA cycle just ended */ + +	/* +	 * If async_unlinking is set then this routine is already running, +	 * either on the stack or on another CPU. +	 */ +	early_exit = ehci->async_unlinking; + +	/* If the controller isn't running, process all the waiting QHs */ +	if (ehci->rh_state < EHCI_RH_RUNNING) +		list_splice_tail_init(&ehci->async_unlink, &ehci->async_idle); + +	/* +	 * Intel (?) bug: The HC can write back the overlay region even +	 * after the IAA interrupt occurs.  In self-defense, always go +	 * through two IAA cycles for each QH. +	 */ +	else if (qh->qh_state == QH_STATE_UNLINK_WAIT) { +		qh->qh_state = QH_STATE_UNLINK; +		early_exit = true; +	} + +	/* Otherwise process only the first waiting QH (NVIDIA bug?) */ +	else +		list_move_tail(&qh->unlink_node, &ehci->async_idle); + +	/* Start a new IAA cycle if any QHs are waiting for it */ +	if (!list_empty(&ehci->async_unlink)) +		start_iaa_cycle(ehci); + +	/* +	 * Don't allow nesting or concurrent calls, +	 * or wait for the second IAA cycle for the next QH. +	 */ +	if (early_exit) +		return; +  	/* Process the idle QHs */ - restart:  	ehci->async_unlinking = true; -	while (ehci->async_iaa) { -		qh = ehci->async_iaa; -		ehci->async_iaa = qh->unlink_next; -		qh->unlink_next = NULL; +	while (!list_empty(&ehci->async_idle)) { +		qh = list_first_entry(&ehci->async_idle, struct ehci_qh, +				unlink_node); +		list_del(&qh->unlink_node);  		qh->qh_state = QH_STATE_IDLE;  		qh->qh_next.qh = NULL; -		qh_completions(ehci, qh); +		if (!list_empty(&qh->qtd_list)) +			qh_completions(ehci, qh);  		if (!list_empty(&qh->qtd_list) &&  				ehci->rh_state == EHCI_RH_RUNNING)  			qh_link_async(ehci, qh);  		disable_async(ehci);  	}  	ehci->async_unlinking = false; - -	/* Start a new IAA cycle if any QHs are waiting for it */ -	if (ehci->async_unlink) { -		start_iaa_cycle(ehci, true); -		if (unlikely(ehci->rh_state < EHCI_RH_RUNNING)) -			goto restart; -	}  }  static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh); @@ -1288,7 +1268,6 @@ static void unlink_empty_async(struct ehci_hcd *ehci)  {  	struct ehci_qh		*qh;  	struct ehci_qh		*qh_to_unlink = NULL; -	bool			check_unlinks_later = false;  	int			count = 0;  	/* Find the last async QH which has been empty for a timer cycle */ @@ -1296,15 +1275,13 @@ static void unlink_empty_async(struct ehci_hcd *ehci)  		if (list_empty(&qh->qtd_list) &&  				qh->qh_state == QH_STATE_LINKED) {  			++count; -			if (qh->unlink_cycle == ehci->async_unlink_cycle) -				check_unlinks_later = true; -			else +			if (qh->unlink_cycle != ehci->async_unlink_cycle)  				qh_to_unlink = qh;  		}  	}  	/* If nothing else is being unlinked, unlink the last empty QH */ -	if (!ehci->async_iaa && !ehci->async_unlink && qh_to_unlink) { +	if (list_empty(&ehci->async_unlink) && qh_to_unlink) {  		start_unlink_async(ehci, qh_to_unlink);  		--count;  	} @@ -1316,24 +1293,30 @@ static void unlink_empty_async(struct ehci_hcd *ehci)  	}  } +/* The root hub is suspended; unlink all the async QHs */ +static void __maybe_unused unlink_empty_async_suspended(struct ehci_hcd *ehci) +{ +	struct ehci_qh		*qh; + +	while (ehci->async->qh_next.qh) { +		qh = ehci->async->qh_next.qh; +		WARN_ON(!list_empty(&qh->qtd_list)); +		single_unlink_async(ehci, qh); +	} +	start_iaa_cycle(ehci); +} +  /* makes sure the async qh will become idle */  /* caller must own ehci->lock */  static void start_unlink_async(struct ehci_hcd *ehci, struct ehci_qh *qh)  { -	/* -	 * If the QH isn't linked then there's nothing we can do -	 * unless we were called during a giveback, in which case -	 * qh_completions() has to deal with it. -	 */ -	if (qh->qh_state != QH_STATE_LINKED) { -		if (qh->qh_state == QH_STATE_COMPLETING) -			qh->needs_rescan = 1; +	/* If the QH isn't linked then there's nothing we can do. */ +	if (qh->qh_state != QH_STATE_LINKED)  		return; -	}  	single_unlink_async(ehci, qh); -	start_iaa_cycle(ehci, false); +	start_iaa_cycle(ehci);  }  /*-------------------------------------------------------------------------*/ @@ -1347,7 +1330,7 @@ static void scan_async (struct ehci_hcd *ehci)  	while (ehci->qh_scan_next) {  		qh = ehci->qh_scan_next;  		ehci->qh_scan_next = qh->qh_next.qh; - rescan: +  		/* clean any finished work for this qh */  		if (!list_empty(&qh->qtd_list)) {  			int temp; @@ -1360,14 +1343,13 @@ static void scan_async (struct ehci_hcd *ehci)  			 * in single_unlink_async().  			 */  			temp = qh_completions(ehci, qh); -			if (qh->needs_rescan) { +			if (unlikely(temp)) {  				start_unlink_async(ehci, qh);  			} else if (list_empty(&qh->qtd_list)  					&& qh->qh_state == QH_STATE_LINKED) {  				qh->unlink_cycle = ehci->async_unlink_cycle;  				check_unlinks_later = true; -			} else if (temp != 0) -				goto rescan; +			}  		}  	} diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index 867a92390ef..43a2a16732f 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -92,20 +92,21 @@ static void s5p_ehci_phy_disable(struct s5p_ehci_hcd *s5p_ehci)  static void s5p_setup_vbus_gpio(struct platform_device *pdev)  { +	struct device *dev = &pdev->dev;  	int err;  	int gpio; -	if (!pdev->dev.of_node) +	if (!dev->of_node)  		return; -	gpio = of_get_named_gpio(pdev->dev.of_node, -			"samsung,vbus-gpio", 0); +	gpio = of_get_named_gpio(dev->of_node, "samsung,vbus-gpio", 0);  	if (!gpio_is_valid(gpio))  		return; -	err = gpio_request_one(gpio, GPIOF_OUT_INIT_HIGH, "ehci_vbus_gpio"); +	err = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH, +				    "ehci_vbus_gpio");  	if (err) -		dev_err(&pdev->dev, "can't request ehci vbus gpio %d", gpio); +		dev_err(dev, "can't request ehci vbus gpio %d", gpio);  }  static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index b476daf49f6..acff5b8f6e8 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -539,6 +539,7 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)  	}  	qh->qh_state = QH_STATE_LINKED;  	qh->xacterrs = 0; +	qh->exception = 0;  	/* update per-qh bandwidth for usbfs */  	ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period @@ -602,15 +603,9 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)  static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)  { -	/* If the QH isn't linked then there's nothing we can do -	 * unless we were called during a giveback, in which case -	 * qh_completions() has to deal with it. -	 */ -	if (qh->qh_state != QH_STATE_LINKED) { -		if (qh->qh_state == QH_STATE_COMPLETING) -			qh->needs_rescan = 1; +	/* If the QH isn't linked then there's nothing we can do. */ +	if (qh->qh_state != QH_STATE_LINKED)  		return; -	}  	qh_unlink_periodic (ehci, qh); @@ -625,17 +620,13 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)  	qh->unlink_cycle = ehci->intr_unlink_cycle;  	/* New entries go at the end of the intr_unlink list */ -	if (ehci->intr_unlink) -		ehci->intr_unlink_last->unlink_next = qh; -	else -		ehci->intr_unlink = qh; -	ehci->intr_unlink_last = qh; +	list_add_tail(&qh->unlink_node, &ehci->intr_unlink);  	if (ehci->intr_unlinking)  		;	/* Avoid recursive calls */  	else if (ehci->rh_state < EHCI_RH_RUNNING)  		ehci_handle_intr_unlinks(ehci); -	else if (ehci->intr_unlink == qh) { +	else if (ehci->intr_unlink.next == &qh->unlink_node) {  		ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);  		++ehci->intr_unlink_cycle;  	} @@ -649,7 +640,8 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)  	qh->qh_state = QH_STATE_IDLE;  	hw->hw_next = EHCI_LIST_END(ehci); -	qh_completions(ehci, qh); +	if (!list_empty(&qh->qtd_list)) +		qh_completions(ehci, qh);  	/* reschedule QH iff another request is queued */  	if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) { @@ -792,7 +784,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)  	unsigned	frame;		/* 0..(qh->period - 1), or NO_FRAME */  	struct ehci_qh_hw	*hw = qh->hw; -	qh_refresh(ehci, qh);  	hw->hw_next = EHCI_LIST_END(ehci);  	frame = qh->start; @@ -844,8 +835,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)  	} else  		ehci_dbg (ehci, "reused qh %p schedule\n", qh); -	/* stuff into the periodic schedule */ -	qh_link_periodic(ehci, qh);  done:  	return status;  } @@ -891,6 +880,12 @@ static int intr_submit (  	qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);  	BUG_ON (qh == NULL); +	/* stuff into the periodic schedule */ +	if (qh->qh_state == QH_STATE_IDLE) { +		qh_refresh(ehci, qh); +		qh_link_periodic(ehci, qh); +	} +  	/* ... update usbfs periodic stats */  	ehci_to_hcd(ehci)->self.bandwidth_int_reqs++; @@ -911,7 +906,7 @@ static void scan_intr(struct ehci_hcd *ehci)  	list_for_each_entry_safe(qh, ehci->qh_scan_next, &ehci->intr_qh_list,  			intr_node) { - rescan: +  		/* clean any finished work for this qh */  		if (!list_empty(&qh->qtd_list)) {  			int temp; @@ -924,12 +919,9 @@ static void scan_intr(struct ehci_hcd *ehci)  			 * in qh_unlink_periodic().  			 */  			temp = qh_completions(ehci, qh); -			if (unlikely(qh->needs_rescan || -					(list_empty(&qh->qtd_list) && -						qh->qh_state == QH_STATE_LINKED))) +			if (unlikely(temp || (list_empty(&qh->qtd_list) && +					qh->qh_state == QH_STATE_LINKED)))  				start_unlink_intr(ehci, qh); -			else if (temp != 0) -				goto rescan;  		}  	}  } @@ -1214,6 +1206,7 @@ itd_urb_transaction (  		memset (itd, 0, sizeof *itd);  		itd->itd_dma = itd_dma; +		itd->frame = 9999;		/* an invalid value */  		list_add (&itd->itd_list, &sched->td_list);  	}  	spin_unlock_irqrestore (&ehci->lock, flags); @@ -1915,6 +1908,7 @@ sitd_urb_transaction (  		memset (sitd, 0, sizeof *sitd);  		sitd->sitd_dma = sitd_dma; +		sitd->frame = 9999;		/* an invalid value */  		list_add (&sitd->sitd_list, &iso_sched->td_list);  	} diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c index 3565a300f40..b44d716ddc8 100644 --- a/drivers/usb/host/ehci-sh.c +++ b/drivers/usb/host/ehci-sh.c @@ -77,7 +77,6 @@ static const struct hc_driver ehci_sh_hc_driver = {  static int ehci_hcd_sh_probe(struct platform_device *pdev)  { -	const struct hc_driver *driver = &ehci_sh_hc_driver;  	struct resource *res;  	struct ehci_sh_priv *priv;  	struct ehci_sh_platdata *pdata; @@ -170,7 +169,7 @@ fail_create_hcd:  	return ret;  } -static int __exit ehci_hcd_sh_remove(struct platform_device *pdev) +static int ehci_hcd_sh_remove(struct platform_device *pdev)  {  	struct ehci_sh_priv *priv = platform_get_drvdata(pdev);  	struct usb_hcd *hcd = priv->hcd; @@ -196,7 +195,7 @@ static void ehci_hcd_sh_shutdown(struct platform_device *pdev)  static struct platform_driver ehci_hcd_sh_driver = {  	.probe		= ehci_hcd_sh_probe, -	.remove		= __exit_p(ehci_hcd_sh_remove), +	.remove		= ehci_hcd_sh_remove,  	.shutdown	= ehci_hcd_sh_shutdown,  	.driver		= {  		.name	= "sh_ehci", diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index 466c1bb5b96..210bb676f22 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -78,7 +78,7 @@ static const struct hc_driver ehci_spear_hc_driver = {  	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete,  }; -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int ehci_spear_drv_suspend(struct device *dev)  {  	struct usb_hcd *hcd = dev_get_drvdata(dev); @@ -94,7 +94,7 @@ static int ehci_spear_drv_resume(struct device *dev)  	ehci_resume(hcd, false);  	return 0;  } -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */  static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend,  		ehci_spear_drv_resume); diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 1d2488cc55f..ed201ae879c 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -28,6 +28,7 @@  #include <linux/pm_runtime.h>  #include <linux/usb/ehci_def.h>  #include <linux/usb/tegra_usb_phy.h> +#include <linux/clk/tegra.h>  #define TEGRA_USB_BASE			0xC5000000  #define TEGRA_USB2_BASE			0xC5004000 @@ -691,6 +692,10 @@ static int tegra_ehci_probe(struct platform_device *pdev)  	if (err)  		goto fail_clk; +	tegra_periph_reset_assert(tegra->clk); +	udelay(1); +	tegra_periph_reset_deassert(tegra->clk); +  	tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node,  		"nvidia,needs-double-reset"); @@ -755,7 +760,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)  	err = usb_phy_set_suspend(hcd->phy, 0);  	if (err) {  		dev_err(&pdev->dev, "Failed to power on the phy\n"); -		goto fail; +		goto fail_phy;  	}  	tegra->host_resumed = 1; @@ -765,7 +770,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)  	if (!irq) {  		dev_err(&pdev->dev, "Failed to get IRQ\n");  		err = -ENODEV; -		goto fail; +		goto fail_phy;  	}  	if (pdata->operating_mode == TEGRA_USB_OTG) { @@ -773,6 +778,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)  			devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);  		if (!IS_ERR(tegra->transceiver))  			otg_set_host(tegra->transceiver->otg, &hcd->self); +	} else { +		tegra->transceiver = ERR_PTR(-ENODEV);  	}  	err = usb_add_hcd(hcd, irq, IRQF_SHARED); @@ -794,6 +801,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)  fail:  	if (!IS_ERR(tegra->transceiver))  		otg_set_host(tegra->transceiver->otg, NULL); +fail_phy:  	usb_phy_shutdown(hcd->phy);  fail_io:  	clk_disable_unprepare(tegra->clk); diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c index 20dbdcbe9b0..11e5b32f73e 100644 --- a/drivers/usb/host/ehci-timer.c +++ b/drivers/usb/host/ehci-timer.c @@ -113,8 +113,8 @@ static void ehci_poll_ASS(struct ehci_hcd *ehci)  	if (want != actual) { -		/* Poll again later, but give up after about 20 ms */ -		if (ehci->ASS_poll_count++ < 20) { +		/* Poll again later, but give up after about 2-4 ms */ +		if (ehci->ASS_poll_count++ < 2) {  			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_ASS, true);  			return;  		} @@ -159,8 +159,8 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci)  	if (want != actual) { -		/* Poll again later, but give up after about 20 ms */ -		if (ehci->PSS_poll_count++ < 20) { +		/* Poll again later, but give up after about 2-4 ms */ +		if (ehci->PSS_poll_count++ < 2) {  			ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);  			return;  		} @@ -229,18 +229,19 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)  	 * process all the QHs on the list.  	 */  	ehci->intr_unlinking = true; -	while (ehci->intr_unlink) { -		struct ehci_qh	*qh = ehci->intr_unlink; +	while (!list_empty(&ehci->intr_unlink)) { +		struct ehci_qh	*qh; +		qh = list_first_entry(&ehci->intr_unlink, struct ehci_qh, +				unlink_node);  		if (!stopped && qh->unlink_cycle == ehci->intr_unlink_cycle)  			break; -		ehci->intr_unlink = qh->unlink_next; -		qh->unlink_next = NULL; +		list_del(&qh->unlink_node);  		end_unlink_intr(ehci, qh);  	}  	/* Handle remaining entries later */ -	if (ehci->intr_unlink) { +	if (!list_empty(&ehci->intr_unlink)) {  		ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);  		++ehci->intr_unlink_cycle;  	} @@ -295,8 +296,7 @@ static void end_free_itds(struct ehci_hcd *ehci)  /* Handle lost (or very late) IAA interrupts */  static void ehci_iaa_watchdog(struct ehci_hcd *ehci)  { -	if (ehci->rh_state != EHCI_RH_RUNNING) -		return; +	u32 cmd, status;  	/*  	 * Lost IAA irqs wedge things badly; seen first with a vt8235. @@ -304,34 +304,32 @@ static void ehci_iaa_watchdog(struct ehci_hcd *ehci)  	 * (a) SMP races against real IAA firing and retriggering, and  	 * (b) clean HC shutdown, when IAA watchdog was pending.  	 */ -	if (ehci->async_iaa) { -		u32 cmd, status; - -		/* If we get here, IAA is *REALLY* late.  It's barely -		 * conceivable that the system is so busy that CMD_IAAD -		 * is still legitimately set, so let's be sure it's -		 * clear before we read STS_IAA.  (The HC should clear -		 * CMD_IAAD when it sets STS_IAA.) -		 */ -		cmd = ehci_readl(ehci, &ehci->regs->command); +	if (!ehci->iaa_in_progress || ehci->rh_state != EHCI_RH_RUNNING) +		return; -		/* -		 * If IAA is set here it either legitimately triggered -		 * after the watchdog timer expired (_way_ late, so we'll -		 * still count it as lost) ... or a silicon erratum: -		 * - VIA seems to set IAA without triggering the IRQ; -		 * - IAAD potentially cleared without setting IAA. -		 */ -		status = ehci_readl(ehci, &ehci->regs->status); -		if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { -			COUNT(ehci->stats.lost_iaa); -			ehci_writel(ehci, STS_IAA, &ehci->regs->status); -		} +	/* If we get here, IAA is *REALLY* late.  It's barely +	 * conceivable that the system is so busy that CMD_IAAD +	 * is still legitimately set, so let's be sure it's +	 * clear before we read STS_IAA.  (The HC should clear +	 * CMD_IAAD when it sets STS_IAA.) +	 */ +	cmd = ehci_readl(ehci, &ehci->regs->command); -		ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", -				status, cmd); -		end_unlink_async(ehci); +	/* +	 * If IAA is set here it either legitimately triggered +	 * after the watchdog timer expired (_way_ late, so we'll +	 * still count it as lost) ... or a silicon erratum: +	 * - VIA seems to set IAA without triggering the IRQ; +	 * - IAAD potentially cleared without setting IAA. +	 */ +	status = ehci_readl(ehci, &ehci->regs->status); +	if ((status & STS_IAA) || !(cmd & CMD_IAAD)) { +		COUNT(ehci->stats.lost_iaa); +		ehci_writel(ehci, STS_IAA, &ehci->regs->status);  	} + +	ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd); +	end_unlink_async(ehci);  } diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c deleted file mode 100644 index 7ecf709610b..00000000000 --- a/drivers/usb/host/ehci-vt8500.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * drivers/usb/host/ehci-vt8500.c - * - * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> - * - * Based on ehci-au1xxx.c - * - * 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. - * - */ - -#include <linux/err.h> -#include <linux/of.h> -#include <linux/platform_device.h> - -static const struct hc_driver vt8500_ehci_hc_driver = { -	.description		= hcd_name, -	.product_desc		= "VT8500 EHCI", -	.hcd_priv_size		= sizeof(struct ehci_hcd), - -	/* -	 * generic hardware linkage -	 */ -	.irq			= ehci_irq, -	.flags			= HCD_MEMORY | HCD_USB2, - -	/* -	 * basic lifecycle operations -	 */ -	.reset			= ehci_setup, -	.start			= ehci_run, -	.stop			= ehci_stop, -	.shutdown		= ehci_shutdown, - -	/* -	 * managing i/o requests and associated device resources -	 */ -	.urb_enqueue		= ehci_urb_enqueue, -	.urb_dequeue		= ehci_urb_dequeue, -	.endpoint_disable	= ehci_endpoint_disable, -	.endpoint_reset		= ehci_endpoint_reset, - -	/* -	 * scheduling support -	 */ -	.get_frame_number	= ehci_get_frame, - -	/* -	 * root hub support -	 */ -	.hub_status_data	= ehci_hub_status_data, -	.hub_control		= ehci_hub_control, -	.bus_suspend		= ehci_bus_suspend, -	.bus_resume		= ehci_bus_resume, -	.relinquish_port	= ehci_relinquish_port, -	.port_handed_over	= ehci_port_handed_over, - -	.clear_tt_buffer_complete	= ehci_clear_tt_buffer_complete, -}; - -static u64 vt8500_ehci_dma_mask = DMA_BIT_MASK(32); - -static int vt8500_ehci_drv_probe(struct platform_device *pdev) -{ -	struct usb_hcd *hcd; -	struct ehci_hcd *ehci; -	struct resource *res; -	int ret; - -	if (usb_disabled()) -		return -ENODEV; - -	/* -	 * Right now device-tree probed devices don't get dma_mask set. -	 * Since shared usb code relies on it, set it here for now. -	 * Once we have dma capability bindings this can go away. -	 */ -	if (!pdev->dev.dma_mask) -		pdev->dev.dma_mask = &vt8500_ehci_dma_mask; - -	if (pdev->resource[1].flags != IORESOURCE_IRQ) { -		pr_debug("resource[1] is not IORESOURCE_IRQ"); -		return -ENOMEM; -	} -	hcd = usb_create_hcd(&vt8500_ehci_hc_driver, &pdev->dev, "VT8500"); -	if (!hcd) -		return -ENOMEM; - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	hcd->rsrc_start = res->start; -	hcd->rsrc_len = resource_size(res); - -	hcd->regs = devm_ioremap_resource(&pdev->dev, res); -	if (IS_ERR(hcd->regs)) { -		ret = PTR_ERR(hcd->regs); -		goto err1; -	} - -	ehci = hcd_to_ehci(hcd); -	ehci->caps = hcd->regs; - -	ret = usb_add_hcd(hcd, pdev->resource[1].start, -			  IRQF_SHARED); -	if (ret == 0) { -		platform_set_drvdata(pdev, hcd); -		return ret; -	} - -err1: -	usb_put_hcd(hcd); -	return ret; -} - -static int vt8500_ehci_drv_remove(struct platform_device *pdev) -{ -	struct usb_hcd *hcd = platform_get_drvdata(pdev); - -	usb_remove_hcd(hcd); -	usb_put_hcd(hcd); -	platform_set_drvdata(pdev, NULL); - -	return 0; -} - -static const struct of_device_id vt8500_ehci_ids[] = { -	{ .compatible = "via,vt8500-ehci", }, -	{ .compatible = "wm,prizm-ehci", }, -	{} -}; - -static struct platform_driver vt8500_ehci_driver = { -	.probe		= vt8500_ehci_drv_probe, -	.remove		= vt8500_ehci_drv_remove, -	.shutdown	= usb_hcd_platform_shutdown, -	.driver = { -		.name	= "vt8500-ehci", -		.owner	= THIS_MODULE, -		.of_match_table = of_match_ptr(vt8500_ehci_ids), -	} -}; - -MODULE_ALIAS("platform:vt8500-ehci"); -MODULE_DEVICE_TABLE(of, vt8500_ehci_ids); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 36c3a821059..7c978b23520 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -121,6 +121,7 @@ struct ehci_hcd {			/* one per controller */  	bool			scanning:1;  	bool			need_rescan:1;  	bool			intr_unlinking:1; +	bool			iaa_in_progress:1;  	bool			async_unlinking:1;  	bool			shutdown:1;  	struct ehci_qh		*qh_scan_next; @@ -128,9 +129,8 @@ struct ehci_hcd {			/* one per controller */  	/* async schedule support */  	struct ehci_qh		*async;  	struct ehci_qh		*dummy;		/* For AMD quirk use */ -	struct ehci_qh		*async_unlink; -	struct ehci_qh		*async_unlink_last; -	struct ehci_qh		*async_iaa; +	struct list_head	async_unlink; +	struct list_head	async_idle;  	unsigned		async_unlink_cycle;  	unsigned		async_count;	/* async activity count */ @@ -143,8 +143,7 @@ struct ehci_hcd {			/* one per controller */  	unsigned		i_thresh;	/* uframes HC might cache */  	union ehci_shadow	*pshadow;	/* mirror hw periodic table */ -	struct ehci_qh		*intr_unlink; -	struct ehci_qh		*intr_unlink_last; +	struct list_head	intr_unlink;  	unsigned		intr_unlink_cycle;  	unsigned		now_frame;	/* frame from HC hardware */  	unsigned		last_iso_frame;	/* last frame scanned for iso */ @@ -200,6 +199,7 @@ struct ehci_hcd {			/* one per controller */  	unsigned		use_dummy_qh:1;	/* AMD Frame List table quirk*/  	unsigned		has_synopsys_hc_bug:1; /* Synopsys HC */  	unsigned		frame_index_bug:1; /* MosChip (AKA NetMos) */ +	unsigned		need_oc_pp_cycle:1; /* MPC834X port power */  	/* required for usb32 quirk */  	#define OHCI_CTRL_HCFS          (3 << 6) @@ -380,11 +380,10 @@ struct ehci_qh {  	struct list_head	qtd_list;	/* sw qtd list */  	struct list_head	intr_node;	/* list of intr QHs */  	struct ehci_qtd		*dummy; -	struct ehci_qh		*unlink_next;	/* next on unlink list */ +	struct list_head	unlink_node;  	unsigned		unlink_cycle; -	u8			needs_rescan;	/* Dequeue during giveback */  	u8			qh_state;  #define	QH_STATE_LINKED		1		/* HC sees this */  #define	QH_STATE_UNLINK		2		/* HC may still see this */ @@ -407,6 +406,9 @@ struct ehci_qh {  	struct usb_device	*dev;		/* access to TT */  	unsigned		is_out:1;	/* bulk or intr OUT */  	unsigned		clearing_tt:1;	/* Clear-TT-Buf in progress */ +	unsigned		dequeue_during_giveback:1; +	unsigned		exception:1;	/* got a fault, or an unlink +						   was requested */  };  /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index db09dae7b55..60ff4220e8b 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -580,14 +580,8 @@ static int ohci_start_port_reset (struct usb_hcd *hcd, unsigned port)  /* See usb 7.1.7.5:  root hubs must issue at least 50 msec reset signaling,   * not necessarily continuous ... to guard against resume signaling. - * The short timeout is safe for non-root hubs, and is backward-compatible - * with earlier Linux hosts.   */ -#ifdef	CONFIG_USB_SUSPEND  #define	PORT_RESET_MSEC		50 -#else -#define	PORT_RESET_MSEC		10 -#endif  /* this timer value might be vendor-specific ... */  #define	PORT_RESET_HW_MSEC	10 diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c index eb35d963023..ddfc31427bc 100644 --- a/drivers/usb/host/ohci-omap3.c +++ b/drivers/usb/host/ohci-omap3.c @@ -31,6 +31,8 @@  #include <linux/platform_device.h>  #include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/dma-mapping.h>  /*-------------------------------------------------------------------------*/ @@ -112,6 +114,8 @@ static const struct hc_driver ohci_omap3_hc_driver = {  /*-------------------------------------------------------------------------*/ +static u64 omap_ohci_dma_mask = DMA_BIT_MASK(32); +  /*   * configure so an HC device and id are always provided   * always called with process context; sleeping is OK @@ -141,14 +145,13 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev)  		return -ENODEV;  	} -	irq = platform_get_irq_byname(pdev, "ohci-irq"); +	irq = platform_get_irq(pdev, 0);  	if (irq < 0) {  		dev_err(dev, "OHCI irq failed\n");  		return -ENODEV;  	} -	res = platform_get_resource_byname(pdev, -				IORESOURCE_MEM, "ohci"); +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!res) {  		dev_err(dev, "UHH OHCI get resource failed\n");  		return -ENOMEM; @@ -160,6 +163,13 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev)  		return -ENOMEM;  	} +	/* +	 * Right now device-tree probed devices don't get dma_mask set. +	 * Since shared usb code relies on it, set it here for now. +	 * Once we have dma capability bindings this can go away. +	 */ +	if (!pdev->dev.dma_mask) +		pdev->dev.dma_mask = &omap_ohci_dma_mask;  	hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev,  			dev_name(dev)); @@ -229,12 +239,20 @@ static void ohci_hcd_omap3_shutdown(struct platform_device *pdev)  		hcd->driver->shutdown(hcd);  } +static const struct of_device_id omap_ohci_dt_ids[] = { +	{ .compatible = "ti,ohci-omap3" }, +	{ } +}; + +MODULE_DEVICE_TABLE(of, omap_ohci_dt_ids); +  static struct platform_driver ohci_hcd_omap3_driver = {  	.probe		= ohci_hcd_omap3_probe,  	.remove		= ohci_hcd_omap3_remove,  	.shutdown	= ohci_hcd_omap3_shutdown,  	.driver		= {  		.name	= "ohci-omap3", +		.of_match_table = of_match_ptr(omap_ohci_dt_ids),  	},  }; diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index d62f0404baa..15ed7e8d887 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1755,7 +1755,7 @@ sl811h_probe(struct platform_device *dev)  /* for this device there's no useful distinction between the controller   * and its root hub, except that the root hub only gets direct PM calls - * when CONFIG_USB_SUSPEND is enabled. + * when CONFIG_PM_RUNTIME is enabled.   */  static int diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 5efdffe3236..5c124bf5d01 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -3141,10 +3141,11 @@ static int u132_probe(struct platform_device *pdev)  #ifdef CONFIG_PM -/* for this device there's no useful distinction between the controller -* and its root hub, except that the root hub only gets direct PM calls -* when CONFIG_USB_SUSPEND is enabled. -*/ +/* + * for this device there's no useful distinction between the controller + * and its root hub, except that the root hub only gets direct PM calls + * when CONFIG_PM_RUNTIME is enabled. + */  static int u132_suspend(struct platform_device *pdev, pm_message_t state)  {  	struct usb_hcd *hcd = platform_get_drvdata(pdev); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 68914429482..187a3ec1069 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1075,7 +1075,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)  			set_bit(port_index, &bus_state->bus_suspended);  		}  		/* USB core sets remote wake mask for USB 3.0 hubs, -		 * including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND +		 * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME  		 * is enabled, so also enable remote wake here.  		 */  		if (hcd->self.root_hub->do_remote_wakeup) { diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 35616ffbe3a..6dc238c592b 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1022,44 +1022,24 @@ void xhci_copy_ep0_dequeue_into_input_ctx(struct xhci_hcd *xhci,   * is attached to (or the roothub port its ancestor hub is attached to).  All we   * know is the index of that port under either the USB 2.0 or the USB 3.0   * roothub, but that doesn't give us the real index into the HW port status - * registers.  Scan through the xHCI roothub port array, looking for the Nth - * entry of the correct port speed.  Return the port number of that entry. + * registers. Call xhci_find_raw_port_number() to get real index.   */  static u32 xhci_find_real_port_number(struct xhci_hcd *xhci,  		struct usb_device *udev)  {  	struct usb_device *top_dev; -	unsigned int num_similar_speed_ports; -	unsigned int faked_port_num; -	int i; +	struct usb_hcd *hcd; + +	if (udev->speed == USB_SPEED_SUPER) +		hcd = xhci->shared_hcd; +	else +		hcd = xhci->main_hcd;  	for (top_dev = udev; top_dev->parent && top_dev->parent->parent;  			top_dev = top_dev->parent)  		/* Found device below root hub */; -	faked_port_num = top_dev->portnum; -	for (i = 0, num_similar_speed_ports = 0; -			i < HCS_MAX_PORTS(xhci->hcs_params1); i++) { -		u8 port_speed = xhci->port_array[i]; - -		/* -		 * Skip ports that don't have known speeds, or have duplicate -		 * Extended Capabilities port speed entries. -		 */ -		if (port_speed == 0 || port_speed == DUPLICATE_ENTRY) -			continue; -		/* -		 * USB 3.0 ports are always under a USB 3.0 hub.  USB 2.0 and -		 * 1.1 ports are under the USB 2.0 hub.  If the port speed -		 * matches the device speed, it's a similar speed port. -		 */ -		if ((port_speed == 0x03) == (udev->speed == USB_SPEED_SUPER)) -			num_similar_speed_ports++; -		if (num_similar_speed_ports == faked_port_num) -			/* Roothub ports are numbered from 1 to N */ -			return i+1; -	} -	return 0; +	return	xhci_find_raw_port_number(hcd, top_dev->portnum);  }  /* Setup an xHCI virtual device for a Set Address command */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index af259e0ec17..1a30c380043 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -313,6 +313,7 @@ static const struct hc_driver xhci_pci_hc_driver = {  	.set_usb2_hw_lpm =	xhci_set_usb2_hardware_lpm,  	.enable_usb3_lpm_timeout =	xhci_enable_usb3_lpm_timeout,  	.disable_usb3_lpm_timeout =	xhci_disable_usb3_lpm_timeout, +	.find_raw_port_number =	xhci_find_raw_port_number,  };  /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 88287546530..1969c001b3f 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1599,14 +1599,20 @@ static void handle_port_status(struct xhci_hcd *xhci,  	max_ports = HCS_MAX_PORTS(xhci->hcs_params1);  	if ((port_id <= 0) || (port_id > max_ports)) {  		xhci_warn(xhci, "Invalid port id %d\n", port_id); -		bogus_port_status = true; -		goto cleanup; +		inc_deq(xhci, xhci->event_ring); +		return;  	}  	/* Figure out which usb_hcd this port is attached to:  	 * is it a USB 3.0 port or a USB 2.0/1.1 port?  	 */  	major_revision = xhci->port_array[port_id - 1]; + +	/* Find the right roothub. */ +	hcd = xhci_to_hcd(xhci); +	if ((major_revision == 0x03) != (hcd->speed == HCD_USB3)) +		hcd = xhci->shared_hcd; +  	if (major_revision == 0) {  		xhci_warn(xhci, "Event for port %u not in "  				"Extended Capabilities, ignoring.\n", @@ -1629,10 +1635,6 @@ static void handle_port_status(struct xhci_hcd *xhci,  	 * into the index into the ports on the correct split roothub, and the  	 * correct bus_state structure.  	 */ -	/* Find the right roothub. */ -	hcd = xhci_to_hcd(xhci); -	if ((major_revision == 0x03) != (hcd->speed == HCD_USB3)) -		hcd = xhci->shared_hcd;  	bus_state = &xhci->bus_state[hcd_index(hcd)];  	if (hcd->speed == HCD_USB3)  		port_array = xhci->usb3_ports; @@ -2027,8 +2029,8 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,  		if (event_trb != ep_ring->dequeue &&  				event_trb != td->last_trb)  			td->urb->actual_length = -				td->urb->transfer_buffer_length -				- TRB_LEN(le32_to_cpu(event->transfer_len)); +				td->urb->transfer_buffer_length - +				EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));  		else  			td->urb->actual_length = 0; @@ -2060,7 +2062,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,  		/* Maybe the event was for the data stage? */  			td->urb->actual_length =  				td->urb->transfer_buffer_length - -				TRB_LEN(le32_to_cpu(event->transfer_len)); +				EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));  			xhci_dbg(xhci, "Waiting for status "  					"stage event\n");  			return 0; @@ -2096,7 +2098,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,  	/* handle completion code */  	switch (trb_comp_code) {  	case COMP_SUCCESS: -		if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) { +		if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) {  			frame->status = 0;  			break;  		} @@ -2141,7 +2143,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,  				len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2]));  		}  		len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - -			TRB_LEN(le32_to_cpu(event->transfer_len)); +			EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));  		if (trb_comp_code != COMP_STOP_INVAL) {  			frame->actual_length = len; @@ -2199,7 +2201,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,  	case COMP_SUCCESS:  		/* Double check that the HW transferred everything. */  		if (event_trb != td->last_trb || -				TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { +		    EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {  			xhci_warn(xhci, "WARN Successful completion "  					"on short TX\n");  			if (td->urb->transfer_flags & URB_SHORT_NOT_OK) @@ -2227,18 +2229,18 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,  				"%d bytes untransferred\n",  				td->urb->ep->desc.bEndpointAddress,  				td->urb->transfer_buffer_length, -				TRB_LEN(le32_to_cpu(event->transfer_len))); +				EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)));  	/* Fast path - was this the last TRB in the TD for this URB? */  	if (event_trb == td->last_trb) { -		if (TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { +		if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) {  			td->urb->actual_length =  				td->urb->transfer_buffer_length - -				TRB_LEN(le32_to_cpu(event->transfer_len)); +				EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));  			if (td->urb->transfer_buffer_length <  					td->urb->actual_length) {  				xhci_warn(xhci, "HC gave bad length "  						"of %d bytes left\n", -					  TRB_LEN(le32_to_cpu(event->transfer_len))); +					  EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)));  				td->urb->actual_length = 0;  				if (td->urb->transfer_flags & URB_SHORT_NOT_OK)  					*status = -EREMOTEIO; @@ -2280,7 +2282,7 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,  		if (trb_comp_code != COMP_STOP_INVAL)  			td->urb->actual_length +=  				TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) - -				TRB_LEN(le32_to_cpu(event->transfer_len)); +				EVENT_TRB_LEN(le32_to_cpu(event->transfer_len));  	}  	return finish_td(xhci, td, event_trb, event, ep, status, false); @@ -2368,7 +2370,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,  	 * transfer type  	 */  	case COMP_SUCCESS: -		if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) +		if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0)  			break;  		if (xhci->quirks & XHCI_TRUST_TX_LENGTH)  			trb_comp_code = COMP_SHORT_TX; @@ -2461,14 +2463,21 @@ static int handle_tx_event(struct xhci_hcd *xhci,  		 * TD list.  		 */  		if (list_empty(&ep_ring->td_list)) { -			xhci_warn(xhci, "WARN Event TRB for slot %d ep %d " -					"with no TDs queued?\n", -				  TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), -				  ep_index); -			xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", -				 (le32_to_cpu(event->flags) & -				  TRB_TYPE_BITMASK)>>10); -			xhci_print_trb_offsets(xhci, (union xhci_trb *) event); +			/* +			 * A stopped endpoint may generate an extra completion +			 * event if the device was suspended.  Don't print +			 * warnings. +			 */ +			if (!(trb_comp_code == COMP_STOP || +						trb_comp_code == COMP_STOP_INVAL)) { +				xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", +						TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), +						ep_index); +				xhci_dbg(xhci, "Event TRB with TRB type ID %u\n", +						(le32_to_cpu(event->flags) & +						 TRB_TYPE_BITMASK)>>10); +				xhci_print_trb_offsets(xhci, (union xhci_trb *) event); +			}  			if (ep->skip) {  				ep->skip = false;  				xhci_dbg(xhci, "td_list is empty while skip " diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index f1f01a834ba..5156b720a53 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -350,7 +350,7 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)  	 * generate interrupts.  Don't even try to enable MSI.  	 */  	if (xhci->quirks & XHCI_BROKEN_MSI) -		return 0; +		goto legacy_irq;  	/* unregister the legacy interrupt */  	if (hcd->irq) @@ -371,6 +371,7 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)  		return -EINVAL;  	} + legacy_irq:  	/* fall back to legacy interrupt*/  	ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,  			hcd->irq_descr, hcd); @@ -3778,7 +3779,29 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)  	return 0;  } -#ifdef CONFIG_USB_SUSPEND +/* + * Transfer the port index into real index in the HW port status + * registers. Caculate offset between the port's PORTSC register + * and port status base. Divide the number of per port register + * to get the real index. The raw port number bases 1. + */ +int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1) +{ +	struct xhci_hcd *xhci = hcd_to_xhci(hcd); +	__le32 __iomem *base_addr = &xhci->op_regs->port_status_base; +	__le32 __iomem *addr; +	int raw_port; + +	if (hcd->speed != HCD_USB3) +		addr = xhci->usb2_ports[port1 - 1]; +	else +		addr = xhci->usb3_ports[port1 - 1]; + +	raw_port = (addr - base_addr)/NUM_PORT_REGS + 1; +	return raw_port; +} + +#ifdef CONFIG_PM_RUNTIME  /* BESL to HIRD Encoding array for USB2 LPM */  static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000, @@ -4028,7 +4051,7 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)  	return 0;  } -#endif /* CONFIG_USB_SUSPEND */ +#endif /* CONFIG_PM_RUNTIME */  /*---------------------- USB 3.0 Link PM functions ------------------------*/ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f791bd0aee6..63582719e0f 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -206,8 +206,8 @@ struct xhci_op_regs {  /* bits 12:31 are reserved (and should be preserved on writes). */  /* IMAN - Interrupt Management Register */ -#define IMAN_IP		(1 << 1) -#define IMAN_IE		(1 << 0) +#define IMAN_IE		(1 << 1) +#define IMAN_IP		(1 << 0)  /* USBSTS - USB status - status bitmasks */  /* HC not running - set to 1 when run/stop bit is cleared. */ @@ -972,6 +972,10 @@ struct xhci_transfer_event {  	__le32	flags;  }; +/* Transfer event TRB length bit mask */ +/* bits 0:23 */ +#define	EVENT_TRB_LEN(p)		((p) & 0xffffff) +  /** Transfer Event bit fields **/  #define	TRB_TO_EP_ID(p)	(((p) >> 16) & 0x1f) @@ -1829,6 +1833,7 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,  int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,  		char *buf, u16 wLength);  int xhci_hub_status_data(struct usb_hcd *hcd, char *buf); +int xhci_find_raw_port_number(struct usb_hcd *hcd, int port1);  #ifdef CONFIG_PM  int xhci_bus_suspend(struct usb_hcd *hcd); diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 0fc6e5fc745..ba6a5d6e618 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -63,6 +63,7 @@ static const struct usb_device_id appledisplay_table[] = {  	{ APPLEDISPLAY_DEVICE(0x9219) },  	{ APPLEDISPLAY_DEVICE(0x921c) },  	{ APPLEDISPLAY_DEVICE(0x921d) }, +	{ APPLEDISPLAY_DEVICE(0x9236) },  	/* Terminating entry */  	{ } diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index dd573abd2d1..c21386ec5d3 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3084,7 +3084,7 @@ static int sisusb_probe(struct usb_interface *intf,  	/* Allocate memory for our private */  	if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) { -		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n"); +		dev_err(&dev->dev, "Failed to allocate memory for private data\n");  		return -ENOMEM;  	}  	kref_init(&sisusb->kref); diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index f713f6aeb6e..d3a1cce1bf9 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -307,18 +307,7 @@ static struct i2c_driver usb3503_driver = {  	.id_table	= usb3503_id,  }; -static int __init usb3503_init(void) -{ -	return i2c_add_driver(&usb3503_driver); -} - -static void __exit usb3503_exit(void) -{ -	i2c_del_driver(&usb3503_driver); -} - -module_init(usb3503_init); -module_exit(usb3503_exit); +module_i2c_driver(usb3503_driver);  MODULE_AUTHOR("Dongjin Kim <tobetter@gmail.com>");  MODULE_DESCRIPTION("USB3503 USB HUB driver"); diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index ea7e591093e..b903b744a22 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -327,7 +327,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)  		u8 devctl = musb_readb(mregs, MUSB_DEVCTL);  		int err; -		err = musb->int_usb & USB_INTR_VBUSERROR; +		err = musb->int_usb & MUSB_INTR_VBUSERROR;  		if (err) {  			/*  			 * The Mentor core doesn't debounce VBUS as needed diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 4be48651b5a..ba7092349fa 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -99,7 +99,9 @@ static inline void map_dma_buffer(struct musb_request *request,  static inline void unmap_dma_buffer(struct musb_request *request,  				struct musb *musb)  { -	if (!is_buffer_mapped(request)) +	struct musb_ep *musb_ep = request->ep; + +	if (!is_buffer_mapped(request) || !musb_ep->dma)  		return;  	if (request->request.dma == DMA_ADDR_INVALID) { @@ -153,7 +155,10 @@ __acquires(ep->musb->lock)  	ep->busy = 1;  	spin_unlock(&musb->lock); -	unmap_dma_buffer(req, musb); + +	if (!dma_mapping_error(&musb->g.dev, request->dma)) +		unmap_dma_buffer(req, musb); +  	if (request->status == 0)  		dev_dbg(musb->controller, "%s done request %p,  %d/%d\n",  				ep->end_point.name, request, diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 372db48fa26..3a7fec957ca 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -139,6 +139,7 @@ config USB_ISP1301  	tristate "NXP ISP1301 USB transceiver support"  	depends on USB || USB_GADGET  	depends on I2C +	select USB_OTG_UTILS  	help  	  Say Y here to add support for the NXP ISP1301 USB transceiver driver.  	  This chip is typically used as USB transceiver for USB host, gadget diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c index 8fe0c3b9526..ae481afcb3e 100644 --- a/drivers/usb/phy/phy-isp1301-omap.c +++ b/drivers/usb/phy/phy-isp1301-omap.c @@ -1212,7 +1212,7 @@ static void isp1301_release(struct device *dev)  static struct isp1301 *the_transceiver; -static int __exit isp1301_remove(struct i2c_client *i2c) +static int isp1301_remove(struct i2c_client *i2c)  {  	struct isp1301	*isp; @@ -1634,7 +1634,7 @@ static struct i2c_driver isp1301_driver = {  		.name	= "isp1301_omap",  	},  	.probe		= isp1301_probe, -	.remove		= __exit_p(isp1301_remove), +	.remove		= isp1301_remove,  	.id_table	= isp1301_id,  }; diff --git a/drivers/usb/phy/phy-mv-u3d-usb.c b/drivers/usb/phy/phy-mv-u3d-usb.c index cb7e70f1770..f7838a43347 100644 --- a/drivers/usb/phy/phy-mv-u3d-usb.c +++ b/drivers/usb/phy/phy-mv-u3d-usb.c @@ -313,7 +313,7 @@ err:  	return ret;  } -static int __exit mv_u3d_phy_remove(struct platform_device *pdev) +static int mv_u3d_phy_remove(struct platform_device *pdev)  {  	struct mv_u3d_phy *mv_u3d_phy = platform_get_drvdata(pdev); diff --git a/drivers/usb/phy/phy-twl4030-usb.c b/drivers/usb/phy/phy-twl4030-usb.c index 13e17ae5ecd..8f78d2d4072 100644 --- a/drivers/usb/phy/phy-twl4030-usb.c +++ b/drivers/usb/phy/phy-twl4030-usb.c @@ -727,7 +727,7 @@ static int twl4030_usb_probe(struct platform_device *pdev)  	return 0;  } -static int __exit twl4030_usb_remove(struct platform_device *pdev) +static int twl4030_usb_remove(struct platform_device *pdev)  {  	struct twl4030_usb *twl = platform_get_drvdata(pdev);  	int val; @@ -768,7 +768,7 @@ MODULE_DEVICE_TABLE(of, twl4030_usb_id_table);  static struct platform_driver twl4030_usb_driver = {  	.probe		= twl4030_usb_probe, -	.remove		= __exit_p(twl4030_usb_remove), +	.remove		= twl4030_usb_remove,  	.driver		= {  		.name	= "twl4030_usb",  		.owner	= THIS_MODULE, diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index e841474d07b..9de7ada90a8 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -400,7 +400,7 @@ static int twl6030_usb_probe(struct platform_device *pdev)  	return 0;  } -static int __exit twl6030_usb_remove(struct platform_device *pdev) +static int twl6030_usb_remove(struct platform_device *pdev)  {  	struct twl6030_usb *twl = platform_get_drvdata(pdev); @@ -427,7 +427,7 @@ MODULE_DEVICE_TABLE(of, twl6030_usb_id_table);  static struct platform_driver twl6030_usb_driver = {  	.probe		= twl6030_usb_probe, -	.remove		= __exit_p(twl6030_usb_remove), +	.remove		= twl6030_usb_remove,  	.driver		= {  		.name	= "twl6030_usb",  		.owner	= THIS_MODULE, diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index cbd904b8fba..3b16118cbf6 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -62,8 +62,6 @@ static int is_irda(struct usb_serial *serial)  }  struct ark3116_private { -	wait_queue_head_t       delta_msr_wait; -	struct async_icount	icount;  	int			irda;	/* 1 for irda device */  	/* protects hw register updates */ @@ -146,7 +144,6 @@ static int ark3116_port_probe(struct usb_serial_port *port)  	if (!priv)  		return -ENOMEM; -	init_waitqueue_head(&priv->delta_msr_wait);  	mutex_init(&priv->hw_lock);  	spin_lock_init(&priv->status_lock); @@ -343,18 +340,15 @@ static void ark3116_close(struct usb_serial_port *port)  {  	struct usb_serial *serial = port->serial; -	if (serial->dev) { -		/* disable DMA */ -		ark3116_write_reg(serial, UART_FCR, 0); - -		/* deactivate interrupts */ -		ark3116_write_reg(serial, UART_IER, 0); +	/* disable DMA */ +	ark3116_write_reg(serial, UART_FCR, 0); -		usb_serial_generic_close(port); -		if (serial->num_interrupt_in) -			usb_kill_urb(port->interrupt_in_urb); -	} +	/* deactivate interrupts */ +	ark3116_write_reg(serial, UART_IER, 0); +	usb_serial_generic_close(port); +	if (serial->num_interrupt_in) +		usb_kill_urb(port->interrupt_in_urb);  }  static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -407,31 +401,10 @@ err_out:  	return result;  } -static int ark3116_get_icount(struct tty_struct *tty, -					struct serial_icounter_struct *icount) -{ -	struct usb_serial_port *port = tty->driver_data; -	struct ark3116_private *priv = usb_get_serial_port_data(port); -	struct async_icount cnow = priv->icount; -	icount->cts = cnow.cts; -	icount->dsr = cnow.dsr; -	icount->rng = cnow.rng; -	icount->dcd = cnow.dcd; -	icount->rx = cnow.rx; -	icount->tx = cnow.tx; -	icount->frame = cnow.frame; -	icount->overrun = cnow.overrun; -	icount->parity = cnow.parity; -	icount->brk = cnow.brk; -	icount->buf_overrun = cnow.buf_overrun; -	return 0; -} -  static int ark3116_ioctl(struct tty_struct *tty,  			 unsigned int cmd, unsigned long arg)  {  	struct usb_serial_port *port = tty->driver_data; -	struct ark3116_private *priv = usb_get_serial_port_data(port);  	struct serial_struct serstruct;  	void __user *user_arg = (void __user *)arg; @@ -453,29 +426,6 @@ static int ark3116_ioctl(struct tty_struct *tty,  		if (copy_from_user(&serstruct, user_arg, sizeof(serstruct)))  			return -EFAULT;  		return 0; -	case TIOCMIWAIT: -		for (;;) { -			struct async_icount prev = priv->icount; -			interruptible_sleep_on(&priv->delta_msr_wait); -			/* see if a signal did it */ -			if (signal_pending(current)) -				return -ERESTARTSYS; -			if ((prev.rng == priv->icount.rng) && -			    (prev.dsr == priv->icount.dsr) && -			    (prev.dcd == priv->icount.dcd) && -			    (prev.cts == priv->icount.cts)) -				return -EIO; -			if ((arg & TIOCM_RNG && -			     (prev.rng != priv->icount.rng)) || -			    (arg & TIOCM_DSR && -			     (prev.dsr != priv->icount.dsr)) || -			    (arg & TIOCM_CD  && -			     (prev.dcd != priv->icount.dcd)) || -			    (arg & TIOCM_CTS && -			     (prev.cts != priv->icount.cts))) -				return 0; -		} -		break;  	}  	return -ENOIOCTLCMD; @@ -573,14 +523,14 @@ static void ark3116_update_msr(struct usb_serial_port *port, __u8 msr)  	if (msr & UART_MSR_ANY_DELTA) {  		/* update input line counters */  		if (msr & UART_MSR_DCTS) -			priv->icount.cts++; +			port->icount.cts++;  		if (msr & UART_MSR_DDSR) -			priv->icount.dsr++; +			port->icount.dsr++;  		if (msr & UART_MSR_DDCD) -			priv->icount.dcd++; +			port->icount.dcd++;  		if (msr & UART_MSR_TERI) -			priv->icount.rng++; -		wake_up_interruptible(&priv->delta_msr_wait); +			port->icount.rng++; +		wake_up_interruptible(&port->port.delta_msr_wait);  	}  } @@ -596,13 +546,13 @@ static void ark3116_update_lsr(struct usb_serial_port *port, __u8 lsr)  	if (lsr&UART_LSR_BRK_ERROR_BITS) {  		if (lsr & UART_LSR_BI) -			priv->icount.brk++; +			port->icount.brk++;  		if (lsr & UART_LSR_FE) -			priv->icount.frame++; +			port->icount.frame++;  		if (lsr & UART_LSR_PE) -			priv->icount.parity++; +			port->icount.parity++;  		if (lsr & UART_LSR_OE) -			priv->icount.overrun++; +			port->icount.overrun++;  	}  } @@ -720,7 +670,8 @@ static struct usb_serial_driver ark3116_device = {  	.ioctl =		ark3116_ioctl,  	.tiocmget =		ark3116_tiocmget,  	.tiocmset =		ark3116_tiocmset, -	.get_icount =		ark3116_get_icount, +	.tiocmiwait =		usb_serial_generic_tiocmiwait, +	.get_icount =		usb_serial_generic_get_icount,  	.open =			ark3116_open,  	.close =		ark3116_close,  	.break_ctl = 		ark3116_break_ctl, diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 37decb13d7e..3c4db6d196c 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -106,14 +106,15 @@ static int usb_serial_device_remove(struct device *dev)  	/* make sure suspend/resume doesn't race against port_remove */  	usb_autopm_get_interface(port->serial->interface); +	minor = port->number; +	tty_unregister_device(usb_serial_tty_driver, minor); +  	device_remove_file(&port->dev, &dev_attr_port_number);  	driver = port->serial->type;  	if (driver->port_remove)  		retval = driver->port_remove(port); -	minor = port->number; -	tty_unregister_device(usb_serial_tty_driver, minor);  	dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",  		 driver->description, minor); diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index d255f66e708..c2a4171ab9c 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -80,7 +80,6 @@ MODULE_DEVICE_TABLE(usb, id_table);  struct ch341_private {  	spinlock_t lock; /* access lock */ -	wait_queue_head_t delta_msr_wait; /* wait queue for modem status */  	unsigned baud_rate; /* set baud rate */  	u8 line_control; /* set line control value RTS/DTR */  	u8 line_status; /* active status of modem control inputs */ @@ -252,7 +251,6 @@ static int ch341_port_probe(struct usb_serial_port *port)  		return -ENOMEM;  	spin_lock_init(&priv->lock); -	init_waitqueue_head(&priv->delta_msr_wait);  	priv->baud_rate = DEFAULT_BAUD_RATE;  	priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR; @@ -298,7 +296,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on)  		priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR);  	spin_unlock_irqrestore(&priv->lock, flags);  	ch341_set_handshake(port->serial->dev, priv->line_control); -	wake_up_interruptible(&priv->delta_msr_wait);  }  static void ch341_close(struct usb_serial_port *port) @@ -491,7 +488,7 @@ static void ch341_read_int_callback(struct urb *urb)  			tty_kref_put(tty);  		} -		wake_up_interruptible(&priv->delta_msr_wait); +		wake_up_interruptible(&port->port.delta_msr_wait);  	}  exit: @@ -502,8 +499,9 @@ exit:  			__func__, status);  } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) +static int ch341_tiocmiwait(struct tty_struct *tty, unsigned long arg)  { +	struct usb_serial_port *port = tty->driver_data;  	struct ch341_private *priv = usb_get_serial_port_data(port);  	unsigned long flags;  	u8 prevstatus; @@ -517,11 +515,14 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)  	spin_unlock_irqrestore(&priv->lock, flags);  	while (!multi_change) { -		interruptible_sleep_on(&priv->delta_msr_wait); +		interruptible_sleep_on(&port->port.delta_msr_wait);  		/* see if a signal did it */  		if (signal_pending(current))  			return -ERESTARTSYS; +		if (port->serial->disconnected) +			return -EIO; +  		spin_lock_irqsave(&priv->lock, flags);  		status = priv->line_status;  		multi_change = priv->multi_status_change; @@ -541,26 +542,6 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)  	return 0;  } -static int ch341_ioctl(struct tty_struct *tty, -			unsigned int cmd, unsigned long arg) -{ -	struct usb_serial_port *port = tty->driver_data; - -	dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, port->number, cmd); - -	switch (cmd) { -	case TIOCMIWAIT: -		dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,  port->number); -		return wait_modem_info(port, arg); - -	default: -		dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd); -		break; -	} - -	return -ENOIOCTLCMD; -} -  static int ch341_tiocmget(struct tty_struct *tty)  {  	struct usb_serial_port *port = tty->driver_data; @@ -610,11 +591,11 @@ static struct usb_serial_driver ch341_device = {  	.dtr_rts	   = ch341_dtr_rts,  	.carrier_raised	   = ch341_carrier_raised,  	.close             = ch341_close, -	.ioctl             = ch341_ioctl,  	.set_termios       = ch341_set_termios,  	.break_ctl         = ch341_break_ctl,  	.tiocmget          = ch341_tiocmget,  	.tiocmset          = ch341_tiocmset, +	.tiocmiwait        = ch341_tiocmiwait,  	.read_int_callback = ch341_read_int_callback,  	.port_probe        = ch341_port_probe,  	.port_remove       = ch341_port_remove, diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 4747d1c328f..2c659553c07 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -462,11 +462,7 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)  static void cp210x_close(struct usb_serial_port *port)  {  	usb_serial_generic_close(port); - -	mutex_lock(&port->serial->disc_mutex); -	if (!port->serial->disconnected) -		cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE); -	mutex_unlock(&port->serial->disc_mutex); +	cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);  }  /* diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 629bd289450..781426230d6 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -51,7 +51,6 @@  #define CYBERJACK_PRODUCT_ID	0x0100  /* Function prototypes */ -static void cyberjack_disconnect(struct usb_serial *serial);  static int cyberjack_port_probe(struct usb_serial_port *port);  static int cyberjack_port_remove(struct usb_serial_port *port);  static int  cyberjack_open(struct tty_struct *tty, @@ -79,7 +78,6 @@ static struct usb_serial_driver cyberjack_device = {  	.description =		"Reiner SCT Cyberjack USB card reader",  	.id_table =		id_table,  	.num_ports =		1, -	.disconnect =		cyberjack_disconnect,  	.port_probe =		cyberjack_port_probe,  	.port_remove =		cyberjack_port_remove,  	.open =			cyberjack_open, @@ -130,20 +128,14 @@ static int cyberjack_port_remove(struct usb_serial_port *port)  {  	struct cyberjack_private *priv; +	usb_kill_urb(port->interrupt_in_urb); +  	priv = usb_get_serial_port_data(port);  	kfree(priv);  	return 0;  } -static void cyberjack_disconnect(struct usb_serial *serial) -{ -	int i; - -	for (i = 0; i < serial->num_ports; ++i) -		usb_kill_urb(serial->port[i]->interrupt_in_urb); -} -  static int  cyberjack_open(struct tty_struct *tty,  					struct usb_serial_port *port)  { @@ -166,11 +158,8 @@ static int  cyberjack_open(struct tty_struct *tty,  static void cyberjack_close(struct usb_serial_port *port)  { -	if (port->serial->dev) { -		/* shutdown any bulk reads that might be going on */ -		usb_kill_urb(port->write_urb); -		usb_kill_urb(port->read_urb); -	} +	usb_kill_urb(port->write_urb); +	usb_kill_urb(port->read_urb);  }  static int cyberjack_write(struct tty_struct *tty, diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 8efa19d0e9f..d341555d37d 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -111,7 +111,6 @@ struct cypress_private {  	int baud_rate;			   /* stores current baud rate in  					      integer form */  	int isthrottled;		   /* if throttled, discard reads */ -	wait_queue_head_t delta_msr_wait;  /* used for TIOCMIWAIT */  	char prev_status, diff_status;	   /* used for TIOCMIWAIT */  	/* we pass a pointer to this as the argument sent to  	   cypress_set_termios old_termios */ @@ -130,13 +129,12 @@ static int  cypress_write(struct tty_struct *tty, struct usb_serial_port *port,  			const unsigned char *buf, int count);  static void cypress_send(struct usb_serial_port *port);  static int  cypress_write_room(struct tty_struct *tty); -static int  cypress_ioctl(struct tty_struct *tty, -			unsigned int cmd, unsigned long arg);  static void cypress_set_termios(struct tty_struct *tty,  			struct usb_serial_port *port, struct ktermios *old);  static int  cypress_tiocmget(struct tty_struct *tty);  static int  cypress_tiocmset(struct tty_struct *tty,  			unsigned int set, unsigned int clear); +static int  cypress_tiocmiwait(struct tty_struct *tty, unsigned long arg);  static int  cypress_chars_in_buffer(struct tty_struct *tty);  static void cypress_throttle(struct tty_struct *tty);  static void cypress_unthrottle(struct tty_struct *tty); @@ -159,10 +157,10 @@ static struct usb_serial_driver cypress_earthmate_device = {  	.dtr_rts =			cypress_dtr_rts,  	.write =			cypress_write,  	.write_room =			cypress_write_room, -	.ioctl =			cypress_ioctl,  	.set_termios =			cypress_set_termios,  	.tiocmget =			cypress_tiocmget,  	.tiocmset =			cypress_tiocmset, +	.tiocmiwait =			cypress_tiocmiwait,  	.chars_in_buffer =		cypress_chars_in_buffer,  	.throttle =		 	cypress_throttle,  	.unthrottle =			cypress_unthrottle, @@ -185,10 +183,10 @@ static struct usb_serial_driver cypress_hidcom_device = {  	.dtr_rts =			cypress_dtr_rts,  	.write =			cypress_write,  	.write_room =			cypress_write_room, -	.ioctl =			cypress_ioctl,  	.set_termios =			cypress_set_termios,  	.tiocmget =			cypress_tiocmget,  	.tiocmset =			cypress_tiocmset, +	.tiocmiwait =			cypress_tiocmiwait,  	.chars_in_buffer =		cypress_chars_in_buffer,  	.throttle =			cypress_throttle,  	.unthrottle =			cypress_unthrottle, @@ -211,10 +209,10 @@ static struct usb_serial_driver cypress_ca42v2_device = {  	.dtr_rts =			cypress_dtr_rts,  	.write =			cypress_write,  	.write_room =			cypress_write_room, -	.ioctl =			cypress_ioctl,  	.set_termios =			cypress_set_termios,  	.tiocmget =			cypress_tiocmget,  	.tiocmset =			cypress_tiocmset, +	.tiocmiwait =			cypress_tiocmiwait,  	.chars_in_buffer =		cypress_chars_in_buffer,  	.throttle =			cypress_throttle,  	.unthrottle =			cypress_unthrottle, @@ -449,7 +447,6 @@ static int cypress_generic_port_probe(struct usb_serial_port *port)  		kfree(priv);  		return -ENOMEM;  	} -	init_waitqueue_head(&priv->delta_msr_wait);  	usb_reset_configuration(serial->dev); @@ -635,12 +632,6 @@ static void cypress_close(struct usb_serial_port *port)  	struct cypress_private *priv = usb_get_serial_port_data(port);  	unsigned long flags; -	/* writing is potentially harmful, lock must be taken */ -	mutex_lock(&port->serial->disc_mutex); -	if (port->serial->disconnected) { -		mutex_unlock(&port->serial->disc_mutex); -		return; -	}  	spin_lock_irqsave(&priv->lock, flags);  	kfifo_reset_out(&priv->write_fifo);  	spin_unlock_irqrestore(&priv->lock, flags); @@ -652,7 +643,6 @@ static void cypress_close(struct usb_serial_port *port)  	if (stats)  		dev_info(&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n",  			priv->bytes_in, priv->bytes_out, priv->cmd_count); -	mutex_unlock(&port->serial->disc_mutex);  } /* cypress_close */ @@ -857,51 +847,43 @@ static int cypress_tiocmset(struct tty_struct *tty,  } -static int cypress_ioctl(struct tty_struct *tty, -					unsigned int cmd, unsigned long arg) +static int cypress_tiocmiwait(struct tty_struct *tty, unsigned long arg)  {  	struct usb_serial_port *port = tty->driver_data;  	struct cypress_private *priv = usb_get_serial_port_data(port); +	char diff; -	dev_dbg(&port->dev, "%s - port %d, cmd 0x%.4x\n", __func__, port->number, cmd); +	for (;;) { +		interruptible_sleep_on(&port->port.delta_msr_wait); +		/* see if a signal did it */ +		if (signal_pending(current)) +			return -ERESTARTSYS; -	switch (cmd) { -	/* This code comes from drivers/char/serial.c and ftdi_sio.c */ -	case TIOCMIWAIT: -		while (priv != NULL) { -			interruptible_sleep_on(&priv->delta_msr_wait); -			/* see if a signal did it */ -			if (signal_pending(current)) -				return -ERESTARTSYS; -			else { -				char diff = priv->diff_status; -				if (diff == 0) -					return -EIO; /* no change => error */ +		if (port->serial->disconnected) +			return -EIO; -				/* consume all events */ -				priv->diff_status = 0; +		diff = priv->diff_status; +		if (diff == 0) +			return -EIO; /* no change => error */ -				/* return 0 if caller wanted to know about -				   these bits */ -				if (((arg & TIOCM_RNG) && (diff & UART_RI)) || -				    ((arg & TIOCM_DSR) && (diff & UART_DSR)) || -				    ((arg & TIOCM_CD) && (diff & UART_CD)) || -				    ((arg & TIOCM_CTS) && (diff & UART_CTS))) -					return 0; -				/* otherwise caller can't care less about what -				 * happened, and so we continue to wait for -				 * more events. -				 */ -			} -		} -		return 0; -	default: -		break; +		/* consume all events */ +		priv->diff_status = 0; + +		/* return 0 if caller wanted to know about +		   these bits */ +		if (((arg & TIOCM_RNG) && (diff & UART_RI))  || +			((arg & TIOCM_DSR) && (diff & UART_DSR)) || +			((arg & TIOCM_CD)  && (diff & UART_CD))  || +			((arg & TIOCM_CTS) && (diff & UART_CTS))) +			return 0; +		/* otherwise caller can't care less about what +		 * happened, and so we continue to wait for +		 * more events. +		 */  	} -	dev_dbg(&port->dev, "%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h\n", __func__, cmd); -	return -ENOIOCTLCMD; -} /* cypress_ioctl */ +	return 0; +}  static void cypress_set_termios(struct tty_struct *tty,  	struct usb_serial_port *port, struct ktermios *old_termios) @@ -1187,7 +1169,7 @@ static void cypress_read_int_callback(struct urb *urb)  	if (priv->current_status != priv->prev_status) {  		priv->diff_status |= priv->current_status ^  			priv->prev_status; -		wake_up_interruptible(&priv->delta_msr_wait); +		wake_up_interruptible(&port->port.delta_msr_wait);  		priv->prev_status = priv->current_status;  	}  	spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index ebe45fa0ed5..32873b40640 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -196,7 +196,6 @@ struct digi_port {  	unsigned char dp_out_buf[DIGI_OUT_BUF_SIZE];  	int dp_write_urb_in_use;  	unsigned int dp_modem_signals; -	wait_queue_head_t dp_modem_change_wait;  	int dp_transmit_idle;  	wait_queue_head_t dp_transmit_idle_wait;  	int dp_throttled; @@ -1149,53 +1148,51 @@ static void digi_close(struct usb_serial_port *port)  	if (port->serial->disconnected)  		goto exit; -	if (port->serial->dev) { -		/* FIXME: Transmit idle belongs in the wait_unti_sent path */ -		digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT); +	/* FIXME: Transmit idle belongs in the wait_unti_sent path */ +	digi_transmit_idle(port, DIGI_CLOSE_TIMEOUT); -		/* disable input flow control */ -		buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; -		buf[1] = priv->dp_port_num; -		buf[2] = DIGI_DISABLE; -		buf[3] = 0; - -		/* disable output flow control */ -		buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; -		buf[5] = priv->dp_port_num; -		buf[6] = DIGI_DISABLE; -		buf[7] = 0; +	/* disable input flow control */ +	buf[0] = DIGI_CMD_SET_INPUT_FLOW_CONTROL; +	buf[1] = priv->dp_port_num; +	buf[2] = DIGI_DISABLE; +	buf[3] = 0; -		/* disable reading modem signals automatically */ -		buf[8] = DIGI_CMD_READ_INPUT_SIGNALS; -		buf[9] = priv->dp_port_num; -		buf[10] = DIGI_DISABLE; -		buf[11] = 0; +	/* disable output flow control */ +	buf[4] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; +	buf[5] = priv->dp_port_num; +	buf[6] = DIGI_DISABLE; +	buf[7] = 0; -		/* disable receive */ -		buf[12] = DIGI_CMD_RECEIVE_ENABLE; -		buf[13] = priv->dp_port_num; -		buf[14] = DIGI_DISABLE; -		buf[15] = 0; +	/* disable reading modem signals automatically */ +	buf[8] = DIGI_CMD_READ_INPUT_SIGNALS; +	buf[9] = priv->dp_port_num; +	buf[10] = DIGI_DISABLE; +	buf[11] = 0; -		/* flush fifos */ -		buf[16] = DIGI_CMD_IFLUSH_FIFO; -		buf[17] = priv->dp_port_num; -		buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; -		buf[19] = 0; +	/* disable receive */ +	buf[12] = DIGI_CMD_RECEIVE_ENABLE; +	buf[13] = priv->dp_port_num; +	buf[14] = DIGI_DISABLE; +	buf[15] = 0; -		ret = digi_write_oob_command(port, buf, 20, 0); -		if (ret != 0) -			dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n", ret); +	/* flush fifos */ +	buf[16] = DIGI_CMD_IFLUSH_FIFO; +	buf[17] = priv->dp_port_num; +	buf[18] = DIGI_FLUSH_TX | DIGI_FLUSH_RX; +	buf[19] = 0; -		/* wait for final commands on oob port to complete */ -		prepare_to_wait(&priv->dp_flush_wait, &wait, -							TASK_INTERRUPTIBLE); -		schedule_timeout(DIGI_CLOSE_TIMEOUT); -		finish_wait(&priv->dp_flush_wait, &wait); +	ret = digi_write_oob_command(port, buf, 20, 0); +	if (ret != 0) +		dev_dbg(&port->dev, "digi_close: write oob failed, ret=%d\n", +									ret); +	/* wait for final commands on oob port to complete */ +	prepare_to_wait(&priv->dp_flush_wait, &wait, +			TASK_INTERRUPTIBLE); +	schedule_timeout(DIGI_CLOSE_TIMEOUT); +	finish_wait(&priv->dp_flush_wait, &wait); -		/* shutdown any outstanding bulk writes */ -		usb_kill_urb(port->write_urb); -	} +	/* shutdown any outstanding bulk writes */ +	usb_kill_urb(port->write_urb);  exit:  	spin_lock_irq(&priv->dp_port_lock);  	priv->dp_write_urb_in_use = 0; @@ -1252,7 +1249,6 @@ static int digi_port_init(struct usb_serial_port *port, unsigned port_num)  	spin_lock_init(&priv->dp_port_lock);  	priv->dp_port_num = port_num; -	init_waitqueue_head(&priv->dp_modem_change_wait);  	init_waitqueue_head(&priv->dp_transmit_idle_wait);  	init_waitqueue_head(&priv->dp_flush_wait);  	init_waitqueue_head(&priv->dp_close_wait); @@ -1543,7 +1539,6 @@ static int digi_read_oob_callback(struct urb *urb)  			else  				priv->dp_modem_signals &= ~TIOCM_CD; -			wake_up_interruptible(&priv->dp_modem_change_wait);  			spin_unlock(&priv->dp_port_lock);  		} else if (opcode == DIGI_CMD_TRANSMIT_IDLE) {  			spin_lock(&priv->dp_port_lock); diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index b1b2dc64b50..090b411d893 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -47,7 +47,6 @@ MODULE_DEVICE_TABLE(usb, id_table);  struct f81232_private {  	spinlock_t lock; -	wait_queue_head_t delta_msr_wait;  	u8 line_control;  	u8 line_status;  }; @@ -111,7 +110,7 @@ static void f81232_process_read_urb(struct urb *urb)  	line_status = priv->line_status;  	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;  	spin_unlock_irqrestore(&priv->lock, flags); -	wake_up_interruptible(&priv->delta_msr_wait); +	wake_up_interruptible(&port->port.delta_msr_wait);  	if (!urb->actual_length)  		return; @@ -243,8 +242,9 @@ static int f81232_carrier_raised(struct usb_serial_port *port)  	return 0;  } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) +static int f81232_tiocmiwait(struct tty_struct *tty, unsigned long arg)  { +	struct usb_serial_port *port = tty->driver_data;  	struct f81232_private *priv = usb_get_serial_port_data(port);  	unsigned long flags;  	unsigned int prevstatus; @@ -256,11 +256,14 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)  	spin_unlock_irqrestore(&priv->lock, flags);  	while (1) { -		interruptible_sleep_on(&priv->delta_msr_wait); +		interruptible_sleep_on(&port->port.delta_msr_wait);  		/* see if a signal did it */  		if (signal_pending(current))  			return -ERESTARTSYS; +		if (port->serial->disconnected) +			return -EIO; +  		spin_lock_irqsave(&priv->lock, flags);  		status = priv->line_status;  		spin_unlock_irqrestore(&priv->lock, flags); @@ -300,11 +303,6 @@ static int f81232_ioctl(struct tty_struct *tty,  			return -EFAULT;  		return 0; - -	case TIOCMIWAIT: -		dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, -			port->number); -		return wait_modem_info(port, arg);  	default:  		dev_dbg(&port->dev, "%s not supported = 0x%04x\n",  			__func__, cmd); @@ -322,7 +320,6 @@ static int f81232_port_probe(struct usb_serial_port *port)  		return -ENOMEM;  	spin_lock_init(&priv->lock); -	init_waitqueue_head(&priv->delta_msr_wait);  	usb_set_serial_port_data(port, priv); @@ -357,6 +354,7 @@ static struct usb_serial_driver f81232_device = {  	.set_termios =		f81232_set_termios,  	.tiocmget =		f81232_tiocmget,  	.tiocmset =		f81232_tiocmset, +	.tiocmiwait =		f81232_tiocmiwait,  	.process_read_urb =	f81232_process_read_urb,  	.read_int_callback =	f81232_read_int_callback,  	.port_probe =		f81232_port_probe, diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index edd162df49c..778c54dd3df 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1,7 +1,7 @@  /*   * USB FTDI SIO driver   * - *	Copyright (C) 2009 - 2010 + *	Copyright (C) 2009 - 2013   *	    Johan Hovold (jhovold@gmail.com)   *	Copyright (C) 1999 - 2001   *	    Greg Kroah-Hartman (greg@kroah.com) @@ -55,7 +55,6 @@ static __u16 vendor = FTDI_VID;  static __u16 product;  struct ftdi_private { -	struct kref kref;  	enum ftdi_chip_type chip_type;  				/* type of device, either SIO or FT8U232AM */  	int baud_base;		/* baud base clock for divisor setting */ @@ -68,10 +67,7 @@ struct ftdi_private {  				 */  	int flags;		/* some ASYNC_xxxx flags are supported */  	unsigned long last_dtr_rts;	/* saved modem control outputs */ -	struct async_icount	icount; -	wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */  	char prev_status;        /* Used for TIOCMIWAIT */ -	bool dev_gone;        /* Used to abort TIOCMIWAIT */  	char transmit_empty;	/* If transmitter is empty or not */  	__u16 interface;	/* FT2232C, FT2232H or FT4232H port interface  				   (0 for FT232/245) */ @@ -642,6 +638,7 @@ static struct usb_device_id id_table_combined [] = {  	{ USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },  	{ USB_DEVICE(ACTON_VID, ACTON_SPECTRAPRO_PID) },  	{ USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) }, +	{ USB_DEVICE(MITSUBISHI_VID, MITSUBISHI_FXUSB_PID) },  	{ USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },  	{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },  	{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) }, @@ -912,7 +909,6 @@ static int  ftdi_sio_probe(struct usb_serial *serial,  static int  ftdi_sio_port_probe(struct usb_serial_port *port);  static int  ftdi_sio_port_remove(struct usb_serial_port *port);  static int  ftdi_open(struct tty_struct *tty, struct usb_serial_port *port); -static void ftdi_close(struct usb_serial_port *port);  static void ftdi_dtr_rts(struct usb_serial_port *port, int on);  static void ftdi_process_read_urb(struct urb *urb);  static int ftdi_prepare_write_buffer(struct usb_serial_port *port, @@ -922,8 +918,6 @@ static void ftdi_set_termios(struct tty_struct *tty,  static int  ftdi_tiocmget(struct tty_struct *tty);  static int  ftdi_tiocmset(struct tty_struct *tty,  			unsigned int set, unsigned int clear); -static int ftdi_get_icount(struct tty_struct *tty, -			   struct serial_icounter_struct *icount);  static int  ftdi_ioctl(struct tty_struct *tty,  			unsigned int cmd, unsigned long arg);  static void ftdi_break_ctl(struct tty_struct *tty, int break_state); @@ -952,7 +946,6 @@ static struct usb_serial_driver ftdi_sio_device = {  	.port_probe =		ftdi_sio_port_probe,  	.port_remove =		ftdi_sio_port_remove,  	.open =			ftdi_open, -	.close =		ftdi_close,  	.dtr_rts =		ftdi_dtr_rts,  	.throttle =		usb_serial_generic_throttle,  	.unthrottle =		usb_serial_generic_unthrottle, @@ -960,7 +953,8 @@ static struct usb_serial_driver ftdi_sio_device = {  	.prepare_write_buffer =	ftdi_prepare_write_buffer,  	.tiocmget =		ftdi_tiocmget,  	.tiocmset =		ftdi_tiocmset, -	.get_icount =           ftdi_get_icount, +	.tiocmiwait =		usb_serial_generic_tiocmiwait, +	.get_icount =           usb_serial_generic_get_icount,  	.ioctl =		ftdi_ioctl,  	.set_termios =		ftdi_set_termios,  	.break_ctl =		ftdi_break_ctl, @@ -1689,12 +1683,9 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)  		return -ENOMEM;  	} -	kref_init(&priv->kref);  	mutex_init(&priv->cfg_lock); -	init_waitqueue_head(&priv->delta_msr_wait);  	priv->flags = ASYNC_LOW_LATENCY; -	priv->dev_gone = false;  	if (quirk && quirk->port_probe)  		quirk->port_probe(priv); @@ -1829,23 +1820,13 @@ static int ftdi_mtxorb_hack_setup(struct usb_serial *serial)  	return 0;  } -static void ftdi_sio_priv_release(struct kref *k) -{ -	struct ftdi_private *priv = container_of(k, struct ftdi_private, kref); - -	kfree(priv); -} -  static int ftdi_sio_port_remove(struct usb_serial_port *port)  {  	struct ftdi_private *priv = usb_get_serial_port_data(port); -	priv->dev_gone = true; -	wake_up_interruptible_all(&priv->delta_msr_wait); -  	remove_sysfs_attrs(port); -	kref_put(&priv->kref, ftdi_sio_priv_release); +	kfree(priv);  	return 0;  } @@ -1855,7 +1836,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)  	struct ktermios dummy;  	struct usb_device *dev = port->serial->dev;  	struct ftdi_private *priv = usb_get_serial_port_data(port); -	int result;  	/* No error checking for this (will get errors later anyway) */  	/* See ftdi_sio.h for description of what is reset */ @@ -1874,12 +1854,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)  		ftdi_set_termios(tty, port, &dummy);  	} -	/* Start reading from the device */ -	result = usb_serial_generic_open(tty, port); -	if (!result) -		kref_get(&priv->kref); - -	return result; +	return usb_serial_generic_open(tty, port);  }  static void ftdi_dtr_rts(struct usb_serial_port *port, int on) @@ -1904,19 +1879,6 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)  		clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);  } -/* - * usbserial:__serial_close  only calls ftdi_close if the point is open - * - *   This only gets called when it is the last close - */ -static void ftdi_close(struct usb_serial_port *port) -{ -	struct ftdi_private *priv = usb_get_serial_port_data(port); - -	usb_serial_generic_close(port); -	kref_put(&priv->kref, ftdi_sio_priv_release); -} -  /* The SIO requires the first byte to have:   *  B0 1   *  B1 0 @@ -1944,7 +1906,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port,  			c = kfifo_out(&port->write_fifo, &buffer[i + 1], len);  			if (!c)  				break; -			priv->icount.tx += c; +			port->icount.tx += c;  			buffer[i] = (c << 2) + 1;  			count += c + 1;  		} @@ -1952,7 +1914,7 @@ static int ftdi_prepare_write_buffer(struct usb_serial_port *port,  	} else {  		count = kfifo_out_locked(&port->write_fifo, dest, size,  								&port->lock); -		priv->icount.tx += count; +		port->icount.tx += count;  	}  	return count; @@ -1981,15 +1943,15 @@ static int ftdi_process_packet(struct usb_serial_port *port,  		char diff_status = status ^ priv->prev_status;  		if (diff_status & FTDI_RS0_CTS) -			priv->icount.cts++; +			port->icount.cts++;  		if (diff_status & FTDI_RS0_DSR) -			priv->icount.dsr++; +			port->icount.dsr++;  		if (diff_status & FTDI_RS0_RI) -			priv->icount.rng++; +			port->icount.rng++;  		if (diff_status & FTDI_RS0_RLSD) -			priv->icount.dcd++; +			port->icount.dcd++; -		wake_up_interruptible_all(&priv->delta_msr_wait); +		wake_up_interruptible(&port->port.delta_msr_wait);  		priv->prev_status = status;  	} @@ -1999,18 +1961,18 @@ static int ftdi_process_packet(struct usb_serial_port *port,  		 * over framing errors */  		if (packet[1] & FTDI_RS_BI) {  			flag = TTY_BREAK; -			priv->icount.brk++; +			port->icount.brk++;  			usb_serial_handle_break(port);  		} else if (packet[1] & FTDI_RS_PE) {  			flag = TTY_PARITY; -			priv->icount.parity++; +			port->icount.parity++;  		} else if (packet[1] & FTDI_RS_FE) {  			flag = TTY_FRAME; -			priv->icount.frame++; +			port->icount.frame++;  		}  		/* Overrun is special, not associated with a char */  		if (packet[1] & FTDI_RS_OE) { -			priv->icount.overrun++; +			port->icount.overrun++;  			tty_insert_flip_char(&port->port, 0, TTY_OVERRUN);  		}  	} @@ -2024,7 +1986,7 @@ static int ftdi_process_packet(struct usb_serial_port *port,  	len -= 2;  	if (!len)  		return 0;	/* status only */ -	priv->icount.rx += len; +	port->icount.rx += len;  	ch = packet + 2;  	if (port->port.console && port->sysrq) { @@ -2388,34 +2350,10 @@ static int ftdi_tiocmset(struct tty_struct *tty,  	return update_mctrl(port, set, clear);  } -static int ftdi_get_icount(struct tty_struct *tty, -				struct serial_icounter_struct *icount) -{ -	struct usb_serial_port *port = tty->driver_data; -	struct ftdi_private *priv = usb_get_serial_port_data(port); -	struct async_icount *ic = &priv->icount; - -	icount->cts = ic->cts; -	icount->dsr = ic->dsr; -	icount->rng = ic->rng; -	icount->dcd = ic->dcd; -	icount->tx = ic->tx; -	icount->rx = ic->rx; -	icount->frame = ic->frame; -	icount->parity = ic->parity; -	icount->overrun = ic->overrun; -	icount->brk = ic->brk; -	icount->buf_overrun = ic->buf_overrun; -	return 0; -} -  static int ftdi_ioctl(struct tty_struct *tty,  					unsigned int cmd, unsigned long arg)  {  	struct usb_serial_port *port = tty->driver_data; -	struct ftdi_private *priv = usb_get_serial_port_data(port); -	struct async_icount cnow; -	struct async_icount cprev;  	dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd); @@ -2429,33 +2367,6 @@ static int ftdi_ioctl(struct tty_struct *tty,  	case TIOCSSERIAL: /* sets serial port data */  		return set_serial_info(tty, port,  					(struct serial_struct __user *) arg); - -	/* -	 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change -	 * - mask passed in arg for lines of interest -	 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) -	 * Caller should use TIOCGICOUNT to see which one it was. -	 * -	 * This code is borrowed from linux/drivers/char/serial.c -	 */ -	case TIOCMIWAIT: -		cprev = priv->icount; -		while (!priv->dev_gone) { -			interruptible_sleep_on(&priv->delta_msr_wait); -			/* see if a signal did it */ -			if (signal_pending(current)) -				return -ERESTARTSYS; -			cnow = priv->icount; -			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || -			    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || -			    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) || -			    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { -				return 0; -			} -			cprev = cnow; -		} -		return -EIO; -		break;  	case TIOCSERGETLSR:  		return get_lsr_info(port, (struct serial_struct __user *)arg);  		break; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 9d359e189a6..e79861eeed4 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -584,6 +584,13 @@  #define CONTEC_COM1USBH_PID	0x8311	/* COM-1(USB)H */  /* + * Mitsubishi Electric Corp. (http://www.meau.com) + * Submitted by Konstantin Holoborodko + */ +#define MITSUBISHI_VID		0x06D3 +#define MITSUBISHI_FXUSB_PID	0x0284 /* USB/RS422 converters: FX-USB-AW/-BD */ + +/*   * Definitions for B&B Electronics products.   */  #define BANDB_VID		0x0856	/* B&B Electronics Vendor ID */ diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 1a07b12ef34..b110c573ea8 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -946,20 +946,13 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port)  static void garmin_close(struct usb_serial_port *port)  { -	struct usb_serial *serial = port->serial;  	struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);  	dev_dbg(&port->dev, "%s - port %d - mode=%d state=%d flags=0x%X\n",  		__func__, port->number, garmin_data_p->mode,  		garmin_data_p->state, garmin_data_p->flags); -	if (!serial) -		return; - -	mutex_lock(&port->serial->disc_mutex); - -	if (!port->serial->disconnected) -		garmin_clear(garmin_data_p); +	garmin_clear(garmin_data_p);  	/* shutdown our urbs */  	usb_kill_urb(port->read_urb); @@ -968,8 +961,6 @@ static void garmin_close(struct usb_serial_port *port)  	/* keep reset state so we know that we must start a new session */  	if (garmin_data_p->state != STATE_RESET)  		garmin_data_p->state = STATE_DISCONNECTED; - -	mutex_unlock(&port->serial->disc_mutex);  } @@ -1190,17 +1181,11 @@ static void garmin_read_bulk_callback(struct urb *urb)  {  	unsigned long flags;  	struct usb_serial_port *port = urb->context; -	struct usb_serial *serial =  port->serial;  	struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);  	unsigned char *data = urb->transfer_buffer;  	int status = urb->status;  	int retval; -	if (!serial) { -		dev_dbg(&urb->dev->dev, "%s - bad serial pointer, exiting\n", __func__); -		return; -	} -  	if (status) {  		dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n",  			__func__, status); diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 4c5c23f1cae..297665fdd16 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -1,7 +1,7 @@  /*   * USB Serial Converter Generic functions   * - * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com) + * Copyright (C) 2010 - 2013 Johan Hovold (jhovold@gmail.com)   * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)   *   *	This program is free software; you can redistribute it and/or @@ -45,8 +45,6 @@ struct usb_serial_driver usb_serial_generic_device = {  	},  	.id_table =		generic_device_ids,  	.num_ports =		1, -	.disconnect =		usb_serial_generic_disconnect, -	.release =		usb_serial_generic_release,  	.throttle =		usb_serial_generic_throttle,  	.unthrottle =		usb_serial_generic_unthrottle,  	.resume =		usb_serial_generic_resume, @@ -102,32 +100,23 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port  }  EXPORT_SYMBOL_GPL(usb_serial_generic_open); -static void generic_cleanup(struct usb_serial_port *port) +void usb_serial_generic_close(struct usb_serial_port *port)  { -	struct usb_serial *serial = port->serial;  	unsigned long flags;  	int i; -	if (serial->dev) { -		/* shutdown any bulk transfers that might be going on */ -		if (port->bulk_out_size) { -			for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) -				usb_kill_urb(port->write_urbs[i]); +	if (port->bulk_out_size) { +		for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) +			usb_kill_urb(port->write_urbs[i]); -			spin_lock_irqsave(&port->lock, flags); -			kfifo_reset_out(&port->write_fifo); -			spin_unlock_irqrestore(&port->lock, flags); -		} -		if (port->bulk_in_size) { -			for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) -				usb_kill_urb(port->read_urbs[i]); -		} +		spin_lock_irqsave(&port->lock, flags); +		kfifo_reset_out(&port->write_fifo); +		spin_unlock_irqrestore(&port->lock, flags); +	} +	if (port->bulk_in_size) { +		for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) +			usb_kill_urb(port->read_urbs[i]);  	} -} - -void usb_serial_generic_close(struct usb_serial_port *port) -{ -	generic_cleanup(port);  }  EXPORT_SYMBOL_GPL(usb_serial_generic_close); @@ -272,8 +261,7 @@ static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,  	if (!test_and_clear_bit(index, &port->read_urbs_free))  		return 0; -	dev_dbg(&port->dev, "%s - port %d, urb %d\n", __func__, -		port->number, index); +	dev_dbg(&port->dev, "%s - urb %d\n", __func__, index);  	res = usb_submit_urb(port->read_urbs[index], mem_flags);  	if (res) { @@ -347,8 +335,8 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)  	}  	set_bit(i, &port->read_urbs_free); -	dev_dbg(&port->dev, "%s - port %d, urb %d, len %d\n", -		__func__, port->number, i, urb->actual_length); +	dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i, +							urb->actual_length);  	if (urb->status) {  		dev_dbg(&port->dev, "%s - non-zero urb status: %d\n", @@ -430,6 +418,91 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)  }  EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); +static bool usb_serial_generic_msr_changed(struct tty_struct *tty, +				unsigned long arg, struct async_icount *cprev) +{ +	struct usb_serial_port *port = tty->driver_data; +	struct async_icount cnow; +	unsigned long flags; +	bool ret; + +	/* +	 * Use tty-port initialised flag to detect all hangups including the +	 * one generated at USB-device disconnect. +	 * +	 * FIXME: Remove hupping check once tty_port_hangup calls shutdown +	 *        (which clears the initialised flag) before wake up. +	 */ +	if (test_bit(TTY_HUPPING, &tty->flags)) +		return true; +	if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) +		return true; + +	spin_lock_irqsave(&port->lock, flags); +	cnow = port->icount;				/* atomic copy*/ +	spin_unlock_irqrestore(&port->lock, flags); + +	ret =	((arg & TIOCM_RNG) && (cnow.rng != cprev->rng)) || +		((arg & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || +		((arg & TIOCM_CD)  && (cnow.dcd != cprev->dcd)) || +		((arg & TIOCM_CTS) && (cnow.cts != cprev->cts)); + +	*cprev = cnow; + +	return ret; +} + +int usb_serial_generic_tiocmiwait(struct tty_struct *tty, unsigned long arg) +{ +	struct usb_serial_port *port = tty->driver_data; +	struct async_icount cnow; +	unsigned long flags; +	int ret; + +	spin_lock_irqsave(&port->lock, flags); +	cnow = port->icount;				/* atomic copy */ +	spin_unlock_irqrestore(&port->lock, flags); + +	ret = wait_event_interruptible(port->port.delta_msr_wait, +			usb_serial_generic_msr_changed(tty, arg, &cnow)); +	if (!ret) { +		if (test_bit(TTY_HUPPING, &tty->flags)) +			ret = -EIO; +		if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) +			ret = -EIO; +	} + +	return ret; +} +EXPORT_SYMBOL_GPL(usb_serial_generic_tiocmiwait); + +int usb_serial_generic_get_icount(struct tty_struct *tty, +					struct serial_icounter_struct *icount) +{ +	struct usb_serial_port *port = tty->driver_data; +	struct async_icount cnow; +	unsigned long flags; + +	spin_lock_irqsave(&port->lock, flags); +	cnow = port->icount;				/* atomic copy */ +	spin_unlock_irqrestore(&port->lock, flags); + +	icount->cts = cnow.cts; +	icount->dsr = cnow.dsr; +	icount->rng = cnow.rng; +	icount->dcd = cnow.dcd; +	icount->tx = cnow.tx; +	icount->rx = cnow.rx; +	icount->frame = cnow.frame; +	icount->parity = cnow.parity; +	icount->overrun = cnow.overrun; +	icount->brk = cnow.brk; +	icount->buf_overrun = cnow.buf_overrun; + +	return 0; +} +EXPORT_SYMBOL_GPL(usb_serial_generic_get_icount); +  #ifdef CONFIG_MAGIC_SYSRQ  int usb_serial_handle_sysrq_char(struct usb_serial_port *port, unsigned int ch)  { @@ -473,8 +546,7 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,  {  	struct tty_port *port = &usb_port->port; -	dev_dbg(&usb_port->dev, "%s - port %d, status %d\n", __func__, -		usb_port->number, status); +	dev_dbg(&usb_port->dev, "%s - status %d\n", __func__, status);  	if (status)  		wake_up_interruptible(&port->open_wait); @@ -510,17 +582,3 @@ int usb_serial_generic_resume(struct usb_serial *serial)  	return c ? -EIO : 0;  }  EXPORT_SYMBOL_GPL(usb_serial_generic_resume); - -void usb_serial_generic_disconnect(struct usb_serial *serial) -{ -	int i; - -	/* stop reads and writes on all ports */ -	for (i = 0; i < serial->num_ports; ++i) -		generic_cleanup(serial->port[i]); -} -EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect); - -void usb_serial_generic_release(struct usb_serial *serial) -{ -} diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index b00e5cbf741..ff9a6ef8477 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -110,9 +110,7 @@ struct edgeport_port {  	wait_queue_head_t	wait_chase;		/* for handling sleeping while waiting for chase to finish */  	wait_queue_head_t	wait_open;		/* for handling sleeping while waiting for open to finish */  	wait_queue_head_t	wait_command;		/* for handling sleeping while waiting for command to finish */ -	wait_queue_head_t	delta_msr_wait;		/* for handling sleeping while waiting for msr change to happen */ -	struct async_icount	icount;  	struct usb_serial_port	*port;			/* loop back to the owner of this object */  }; @@ -216,8 +214,6 @@ static void edge_break(struct tty_struct *tty, int break_state);  static int  edge_tiocmget(struct tty_struct *tty);  static int  edge_tiocmset(struct tty_struct *tty,  					unsigned int set, unsigned int clear); -static int  edge_get_icount(struct tty_struct *tty, -				struct serial_icounter_struct *icount);  static int  edge_startup(struct usb_serial *serial);  static void edge_disconnect(struct usb_serial *serial);  static void edge_release(struct usb_serial *serial); @@ -884,12 +880,8 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)  	/* initialize our wait queues */  	init_waitqueue_head(&edge_port->wait_open);  	init_waitqueue_head(&edge_port->wait_chase); -	init_waitqueue_head(&edge_port->delta_msr_wait);  	init_waitqueue_head(&edge_port->wait_command); -	/* initialize our icount structure */ -	memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount)); -  	/* initialize our port settings */  	edge_port->txCredits = 0;	/* Can't send any data yet */  	/* Must always set this bit to enable ints! */ @@ -1316,7 +1308,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,  	/* decrement the number of credits we have by the number we just sent */  	edge_port->txCredits -= count; -	edge_port->icount.tx += count; +	edge_port->port->icount.tx += count;  	status = usb_submit_urb(urb, GFP_ATOMIC);  	if (status) { @@ -1328,7 +1320,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,  		/* revert the credits as something bad happened. */  		edge_port->txCredits += count; -		edge_port->icount.tx -= count; +		edge_port->port->icount.tx -= count;  	}  	dev_dbg(dev, "%s wrote %d byte(s) TxCredit %d, Fifo %d\n",  		__func__, count, edge_port->txCredits, fifo->count); @@ -1590,31 +1582,6 @@ static int edge_tiocmget(struct tty_struct *tty)  	return result;  } -static int edge_get_icount(struct tty_struct *tty, -				struct serial_icounter_struct *icount) -{ -	struct usb_serial_port *port = tty->driver_data; -	struct edgeport_port *edge_port = usb_get_serial_port_data(port); -	struct async_icount cnow; -	cnow = edge_port->icount; - -	icount->cts = cnow.cts; -	icount->dsr = cnow.dsr; -	icount->rng = cnow.rng; -	icount->dcd = cnow.dcd; -	icount->rx = cnow.rx; -	icount->tx = cnow.tx; -	icount->frame = cnow.frame; -	icount->overrun = cnow.overrun; -	icount->parity = cnow.parity; -	icount->brk = cnow.brk; -	icount->buf_overrun = cnow.buf_overrun; - -	dev_dbg(&port->dev, "%s (%d) TIOCGICOUNT RX=%d, TX=%d\n", __func__, -		port->number, icount->rx, icount->tx); -	return 0; -} -  static int get_serial_info(struct edgeport_port *edge_port,  				struct serial_struct __user *retinfo)  { @@ -1651,8 +1618,6 @@ static int edge_ioctl(struct tty_struct *tty,  	struct usb_serial_port *port = tty->driver_data;  	DEFINE_WAIT(wait);  	struct edgeport_port *edge_port = usb_get_serial_port_data(port); -	struct async_icount cnow; -	struct async_icount cprev;  	dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd); @@ -1664,33 +1629,6 @@ static int edge_ioctl(struct tty_struct *tty,  	case TIOCGSERIAL:  		dev_dbg(&port->dev, "%s (%d) TIOCGSERIAL\n", __func__,  port->number);  		return get_serial_info(edge_port, (struct serial_struct __user *) arg); - -	case TIOCMIWAIT: -		dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__,  port->number); -		cprev = edge_port->icount; -		while (1) { -			prepare_to_wait(&edge_port->delta_msr_wait, -						&wait, TASK_INTERRUPTIBLE); -			schedule(); -			finish_wait(&edge_port->delta_msr_wait, &wait); -			/* see if a signal did it */ -			if (signal_pending(current)) -				return -ERESTARTSYS; -			cnow = edge_port->icount; -			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && -			    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) -				return -EIO; /* no change => error */ -			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || -			    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || -			    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) || -			    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { -				return 0; -			} -			cprev = cnow; -		} -		/* NOTREACHED */ -		break; -  	}  	return -ENOIOCTLCMD;  } @@ -1864,7 +1802,7 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial,  						edge_serial->rxPort);  					edge_tty_recv(edge_port->port, buffer,  							rxLen); -					edge_port->icount.rx += rxLen; +					edge_port->port->icount.rx += rxLen;  				}  				buffer += rxLen;  			} @@ -2040,7 +1978,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)  	if (newMsr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR |  			EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) { -		icount = &edge_port->icount; +		icount = &edge_port->port->icount;  		/* update input line counters */  		if (newMsr & EDGEPORT_MSR_DELTA_CTS) @@ -2051,7 +1989,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 newMsr)  			icount->dcd++;  		if (newMsr & EDGEPORT_MSR_DELTA_RI)  			icount->rng++; -		wake_up_interruptible(&edge_port->delta_msr_wait); +		wake_up_interruptible(&edge_port->port->port.delta_msr_wait);  	}  	/* Save the new modem status */ @@ -2086,7 +2024,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, __u8 lsrData,  		edge_tty_recv(edge_port->port, &data, 1);  	/* update input line counters */ -	icount = &edge_port->icount; +	icount = &edge_port->port->icount;  	if (newLsr & LSR_BREAK)  		icount->brk++;  	if (newLsr & LSR_OVER_ERR) diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index 1511dd0ad32..ae5fac5656c 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -116,7 +116,8 @@ static struct usb_serial_driver edgeport_2port_device = {  	.set_termios		= edge_set_termios,  	.tiocmget		= edge_tiocmget,  	.tiocmset		= edge_tiocmset, -	.get_icount		= edge_get_icount, +	.tiocmiwait		= usb_serial_generic_tiocmiwait, +	.get_icount		= usb_serial_generic_get_icount,  	.write			= edge_write,  	.write_room		= edge_write_room,  	.chars_in_buffer	= edge_chars_in_buffer, @@ -147,7 +148,8 @@ static struct usb_serial_driver edgeport_4port_device = {  	.set_termios		= edge_set_termios,  	.tiocmget		= edge_tiocmget,  	.tiocmset		= edge_tiocmset, -	.get_icount		= edge_get_icount, +	.tiocmiwait		= usb_serial_generic_tiocmiwait, +	.get_icount		= usb_serial_generic_get_icount,  	.write			= edge_write,  	.write_room		= edge_write_room,  	.chars_in_buffer	= edge_chars_in_buffer, @@ -178,7 +180,8 @@ static struct usb_serial_driver edgeport_8port_device = {  	.set_termios		= edge_set_termios,  	.tiocmget		= edge_tiocmget,  	.tiocmset		= edge_tiocmset, -	.get_icount		= edge_get_icount, +	.tiocmiwait		= usb_serial_generic_tiocmiwait, +	.get_icount		= usb_serial_generic_get_icount,  	.write			= edge_write,  	.write_room		= edge_write_room,  	.chars_in_buffer	= edge_chars_in_buffer, @@ -209,7 +212,8 @@ static struct usb_serial_driver epic_device = {  	.set_termios		= edge_set_termios,  	.tiocmget		= edge_tiocmget,  	.tiocmset		= edge_tiocmset, -	.get_icount		= edge_get_icount, +	.tiocmiwait		= usb_serial_generic_tiocmiwait, +	.get_icount		= usb_serial_generic_get_icount,  	.write			= edge_write,  	.write_room		= edge_write_room,  	.chars_in_buffer	= edge_chars_in_buffer, diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index c23776679f7..0ccc4225d59 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -86,10 +86,7 @@ struct edgeport_port {  	int baud_rate;  	int close_pending;  	int lsr_event; -	struct async_icount	icount; -	wait_queue_head_t	delta_msr_wait;	/* for handling sleeping while -						   waiting for msr change to -						   happen */ +  	struct edgeport_serial	*edge_serial;  	struct usb_serial_port	*port;  	__u8 bUartMode;		/* Port type, 0: RS232, etc. */ @@ -1448,7 +1445,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)  	if (msr & (EDGEPORT_MSR_DELTA_CTS | EDGEPORT_MSR_DELTA_DSR |  			EDGEPORT_MSR_DELTA_RI | EDGEPORT_MSR_DELTA_CD)) { -		icount = &edge_port->icount; +		icount = &edge_port->port->icount;  		/* update input line counters */  		if (msr & EDGEPORT_MSR_DELTA_CTS) @@ -1459,7 +1456,7 @@ static void handle_new_msr(struct edgeport_port *edge_port, __u8 msr)  			icount->dcd++;  		if (msr & EDGEPORT_MSR_DELTA_RI)  			icount->rng++; -		wake_up_interruptible(&edge_port->delta_msr_wait); +		wake_up_interruptible(&edge_port->port->port.delta_msr_wait);  	}  	/* Save the new modem status */ @@ -1501,7 +1498,7 @@ static void handle_new_lsr(struct edgeport_port *edge_port, int lsr_data,  		edge_tty_recv(edge_port->port, &data, 1);  	/* update input line counters */ -	icount = &edge_port->icount; +	icount = &edge_port->port->icount;  	if (new_lsr & LSR_BREAK)  		icount->brk++;  	if (new_lsr & LSR_OVER_ERR) @@ -1660,7 +1657,7 @@ static void edge_bulk_in_callback(struct urb *urb)  		else  			edge_tty_recv(edge_port->port, data,  					urb->actual_length); -		edge_port->icount.rx += urb->actual_length; +		edge_port->port->icount.rx += urb->actual_length;  	}  exit: @@ -1753,9 +1750,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)  	dev = port->serial->dev; -	memset(&(edge_port->icount), 0x00, sizeof(edge_port->icount)); -	init_waitqueue_head(&edge_port->delta_msr_wait); -  	/* turn off loopback */  	status = ti_do_config(edge_port, UMPC_SET_CLR_LOOPBACK, 0);  	if (status) { @@ -1913,21 +1907,10 @@ static void edge_close(struct usb_serial_port *port)  	kfifo_reset_out(&edge_port->write_fifo);  	spin_unlock_irqrestore(&edge_port->ep_lock, flags); -	/* assuming we can still talk to the device, -	 * send a close port command to it */  	dev_dbg(&port->dev, "%s - send umpc_close_port\n", __func__);  	port_number = port->number - port->serial->minor; - -	mutex_lock(&serial->disc_mutex); -	if (!serial->disconnected) { -		send_cmd(serial->dev, -				     UMPC_CLOSE_PORT, -				     (__u8)(UMPM_UART1_PORT + port_number), -				     0, -				     NULL, -				     0); -	} -	mutex_unlock(&serial->disc_mutex); +	send_cmd(serial->dev, UMPC_CLOSE_PORT, +		     (__u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0);  	mutex_lock(&edge_serial->es_lock);  	--edge_port->edge_serial->num_ports_open; @@ -2003,7 +1986,7 @@ static void edge_send(struct tty_struct *tty)  		edge_port->ep_write_urb_in_use = 0;  		/* TODO: reschedule edge_send */  	} else -		edge_port->icount.tx += count; +		edge_port->port->icount.tx += count;  	/* wakeup any process waiting for writes to complete */  	/* there is now more room in the buffer for new writes */ @@ -2364,27 +2347,6 @@ static int edge_tiocmget(struct tty_struct *tty)  	return result;  } -static int edge_get_icount(struct tty_struct *tty, -				struct serial_icounter_struct *icount) -{ -	struct usb_serial_port *port = tty->driver_data; -	struct edgeport_port *edge_port = usb_get_serial_port_data(port); -	struct async_icount *ic = &edge_port->icount; - -	icount->cts = ic->cts; -	icount->dsr = ic->dsr; -	icount->rng = ic->rng; -	icount->dcd = ic->dcd; -	icount->tx = ic->tx; -        icount->rx = ic->rx; -        icount->frame = ic->frame; -        icount->parity = ic->parity; -        icount->overrun = ic->overrun; -        icount->brk = ic->brk; -        icount->buf_overrun = ic->buf_overrun; -	return 0; -} -  static int get_serial_info(struct edgeport_port *edge_port,  				struct serial_struct __user *retinfo)  { @@ -2420,8 +2382,6 @@ static int edge_ioctl(struct tty_struct *tty,  {  	struct usb_serial_port *port = tty->driver_data;  	struct edgeport_port *edge_port = usb_get_serial_port_data(port); -	struct async_icount cnow; -	struct async_icount cprev;  	dev_dbg(&port->dev, "%s - port %d, cmd = 0x%x\n", __func__, port->number, cmd); @@ -2430,28 +2390,6 @@ static int edge_ioctl(struct tty_struct *tty,  		dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__);  		return get_serial_info(edge_port,  				(struct serial_struct __user *) arg); -	case TIOCMIWAIT: -		dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__); -		cprev = edge_port->icount; -		while (1) { -			interruptible_sleep_on(&edge_port->delta_msr_wait); -			/* see if a signal did it */ -			if (signal_pending(current)) -				return -ERESTARTSYS; -			cnow = edge_port->icount; -			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && -			    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) -				return -EIO; /* no change => error */ -			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || -			    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || -			    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) || -			    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { -				return 0; -			} -			cprev = cnow; -		} -		/* not reached */ -		break;  	}  	return -ENOIOCTLCMD;  } @@ -2546,7 +2484,6 @@ static int edge_port_remove(struct usb_serial_port *port)  	struct edgeport_port *edge_port;  	edge_port = usb_get_serial_port_data(port); -  	edge_remove_sysfs_attrs(port);  	kfifo_free(&edge_port->write_fifo);  	kfree(edge_port); @@ -2618,7 +2555,8 @@ static struct usb_serial_driver edgeport_1port_device = {  	.set_termios		= edge_set_termios,  	.tiocmget		= edge_tiocmget,  	.tiocmset		= edge_tiocmset, -	.get_icount		= edge_get_icount, +	.tiocmiwait		= usb_serial_generic_tiocmiwait, +	.get_icount		= usb_serial_generic_get_icount,  	.write			= edge_write,  	.write_room		= edge_write_room,  	.chars_in_buffer	= edge_chars_in_buffer, @@ -2649,6 +2587,8 @@ static struct usb_serial_driver edgeport_2port_device = {  	.set_termios		= edge_set_termios,  	.tiocmget		= edge_tiocmget,  	.tiocmset		= edge_tiocmset, +	.tiocmiwait		= usb_serial_generic_tiocmiwait, +	.get_icount		= usb_serial_generic_get_icount,  	.write			= edge_write,  	.write_room		= edge_write_room,  	.chars_in_buffer	= edge_chars_in_buffer, diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index ff77027160a..9d74c278b7b 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -55,7 +55,6 @@ static void read_rxcmd_callback(struct urb *urb);  struct iuu_private {  	spinlock_t lock;	/* store irq state */ -	wait_queue_head_t delta_msr_wait;  	u8 line_status;  	int tiostatus;		/* store IUART SIGNAL for tiocmget call */  	u8 reset;		/* if 1 reset is needed */ @@ -94,7 +93,6 @@ static int iuu_port_probe(struct usb_serial_port *port)  	priv->vcc = vcc_default;  	spin_lock_init(&priv->lock); -	init_waitqueue_head(&priv->delta_msr_wait);  	usb_set_serial_port_data(port, priv); @@ -944,22 +942,13 @@ static void iuu_set_termios(struct tty_struct *tty,  static void iuu_close(struct usb_serial_port *port)  {  	/* iuu_led (port,255,0,0,0); */ -	struct usb_serial *serial; - -	serial = port->serial; -	if (!serial) -		return;  	iuu_uart_off(port); -	if (serial->dev) { -		/* free writebuf */ -		/* shutdown our urbs */ -		dev_dbg(&port->dev, "%s - shutting down urbs\n", __func__); -		usb_kill_urb(port->write_urb); -		usb_kill_urb(port->read_urb); -		usb_kill_urb(port->interrupt_in_urb); -		iuu_led(port, 0, 0, 0xF000, 0xFF); -	} + +	usb_kill_urb(port->write_urb); +	usb_kill_urb(port->read_urb); + +	iuu_led(port, 0, 0, 0xF000, 0xFF);  }  static void iuu_init_termios(struct tty_struct *tty) diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 1fd1935c831..025310bc358 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -726,45 +726,45 @@ static void usa49wg_indat_callback(struct urb *urb)  	i = 0;  	len = 0; -	if (urb->actual_length) { -		while (i < urb->actual_length) { +	while (i < urb->actual_length) { -			/* Check port number from message*/ -			if (data[i] >= serial->num_ports) { -				dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", -					__func__, data[i]); -				return; -			} -			port = serial->port[data[i++]]; -			len = data[i++]; +		/* Check port number from message */ +		if (data[i] >= serial->num_ports) { +			dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", +				__func__, data[i]); +			return; +		} +		port = serial->port[data[i++]]; +		len = data[i++]; -			/* 0x80 bit is error flag */ -			if ((data[i] & 0x80) == 0) { -				/* no error on any byte */ -				i++; -				for (x = 1; x < len ; ++x) -					tty_insert_flip_char(&port->port, -							data[i++], 0); -			} else { -				/* -				 * some bytes had errors, every byte has status -				 */ -				for (x = 0; x + 1 < len; x += 2) { -					int stat = data[i], flag = 0; -					if (stat & RXERROR_OVERRUN) -						flag |= TTY_OVERRUN; -					if (stat & RXERROR_FRAMING) -						flag |= TTY_FRAME; -					if (stat & RXERROR_PARITY) -						flag |= TTY_PARITY; -					/* XXX should handle break (0x10) */ -					tty_insert_flip_char(&port->port, -							data[i+1], flag); -					i += 2; -				} +		/* 0x80 bit is error flag */ +		if ((data[i] & 0x80) == 0) { +			/* no error on any byte */ +			i++; +			for (x = 1; x < len && i < urb->actual_length; ++x) +				tty_insert_flip_char(&port->port, +						data[i++], 0); +		} else { +			/* +			 * some bytes had errors, every byte has status +			 */ +			for (x = 0; x + 1 < len && +				    i + 1 < urb->actual_length; x += 2) { +				int stat = data[i], flag = 0; + +				if (stat & RXERROR_OVERRUN) +					flag |= TTY_OVERRUN; +				if (stat & RXERROR_FRAMING) +					flag |= TTY_FRAME; +				if (stat & RXERROR_PARITY) +					flag |= TTY_PARITY; +				/* XXX should handle break (0x10) */ +				tty_insert_flip_char(&port->port, data[i+1], +						     flag); +				i += 2;  			} -			tty_flip_buffer_push(&port->port);  		} +		tty_flip_buffer_push(&port->port);  	}  	/* Resubmit urb so we continue receiving */ @@ -1115,7 +1115,6 @@ static void keyspan_dtr_rts(struct usb_serial_port *port, int on)  static void keyspan_close(struct usb_serial_port *port)  {  	int			i; -	struct usb_serial	*serial = port->serial;  	struct keyspan_port_private 	*p_priv;  	p_priv = usb_get_serial_port_data(port); @@ -1123,28 +1122,17 @@ static void keyspan_close(struct usb_serial_port *port)  	p_priv->rts_state = 0;  	p_priv->dtr_state = 0; -	if (serial->dev) { -		keyspan_send_setup(port, 2); -		/* pilot-xfer seems to work best with this delay */ -		mdelay(100); -		/* keyspan_set_termios(port, NULL); */ -	} - -	/*while (p_priv->outcont_urb->status == -EINPROGRESS) { -		dev_dbg(&port->dev, "%s - urb in progress\n", __func__); -	}*/ +	keyspan_send_setup(port, 2); +	/* pilot-xfer seems to work best with this delay */ +	mdelay(100);  	p_priv->out_flip = 0;  	p_priv->in_flip = 0; -	if (serial->dev) { -		/* Stop reading/writing urbs */ -		stop_urb(p_priv->inack_urb); -		/* stop_urb(p_priv->outcont_urb); */ -		for (i = 0; i < 2; i++) { -			stop_urb(p_priv->in_urbs[i]); -			stop_urb(p_priv->out_urbs[i]); -		} +	stop_urb(p_priv->inack_urb); +	for (i = 0; i < 2; i++) { +		stop_urb(p_priv->in_urbs[i]); +		stop_urb(p_priv->out_urbs[i]);  	}  } diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 3b17d5d13dc..da3b29eb605 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -595,12 +595,10 @@ static void keyspan_pda_dtr_rts(struct usb_serial_port *port, int on)  {  	struct usb_serial *serial = port->serial; -	if (serial->dev) { -		if (on) -			keyspan_pda_set_modem_info(serial, (1<<7) | (1<< 2)); -		else -			keyspan_pda_set_modem_info(serial, 0); -	} +	if (on) +		keyspan_pda_set_modem_info(serial, (1 << 7) | (1 << 2)); +	else +		keyspan_pda_set_modem_info(serial, 0);  } @@ -651,13 +649,8 @@ error:  }  static void keyspan_pda_close(struct usb_serial_port *port)  { -	struct usb_serial *serial = port->serial; - -	if (serial->dev) { -		/* shutdown our bulk reads and writes */ -		usb_kill_urb(port->write_urb); -		usb_kill_urb(port->interrupt_in_urb); -	} +	usb_kill_urb(port->write_urb); +	usb_kill_urb(port->interrupt_in_urb);  } diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 769d910ae0a..1b4054fe52a 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -341,28 +341,20 @@ static void klsi_105_close(struct usb_serial_port *port)  {  	int rc; -	mutex_lock(&port->serial->disc_mutex); -	if (!port->serial->disconnected) { -		/* send READ_OFF */ -		rc = usb_control_msg(port->serial->dev, -				     usb_sndctrlpipe(port->serial->dev, 0), -				     KL5KUSB105A_SIO_CONFIGURE, -				     USB_TYPE_VENDOR | USB_DIR_OUT, -				     KL5KUSB105A_SIO_CONFIGURE_READ_OFF, -				     0, /* index */ -				     NULL, 0, -				     KLSI_TIMEOUT); -		if (rc < 0) -			dev_err(&port->dev, -				"Disabling read failed (error = %d)\n", rc); -	} -	mutex_unlock(&port->serial->disc_mutex); +	/* send READ_OFF */ +	rc = usb_control_msg(port->serial->dev, +			     usb_sndctrlpipe(port->serial->dev, 0), +			     KL5KUSB105A_SIO_CONFIGURE, +			     USB_TYPE_VENDOR | USB_DIR_OUT, +			     KL5KUSB105A_SIO_CONFIGURE_READ_OFF, +			     0, /* index */ +			     NULL, 0, +			     KLSI_TIMEOUT); +	if (rc < 0) +		dev_err(&port->dev, "failed to disable read: %d\n", rc);  	/* shutdown our bulk reads and writes */  	usb_serial_generic_close(port); - -	/* wgg - do I need this? I think so. */ -	usb_kill_urb(port->interrupt_in_urb);  }  /* We need to write a complete 64-byte data block and encode the diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index a64d420f687..3353c9ed772 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -35,7 +35,6 @@  #include <linux/usb.h>  #include <linux/usb/serial.h>  #include <linux/serial.h> -#include <linux/ioctl.h>  #include "mct_u232.h"  #define DRIVER_AUTHOR "Wolfgang Grandegger <wolfgang@ces.ch>" @@ -57,10 +56,6 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state);  static int  mct_u232_tiocmget(struct tty_struct *tty);  static int  mct_u232_tiocmset(struct tty_struct *tty,  			unsigned int set, unsigned int clear); -static int  mct_u232_ioctl(struct tty_struct *tty, -			unsigned int cmd, unsigned long arg); -static int  mct_u232_get_icount(struct tty_struct *tty, -			struct serial_icounter_struct *icount);  static void mct_u232_throttle(struct tty_struct *tty);  static void mct_u232_unthrottle(struct tty_struct *tty); @@ -95,11 +90,11 @@ static struct usb_serial_driver mct_u232_device = {  	.break_ctl =	     mct_u232_break_ctl,  	.tiocmget =	     mct_u232_tiocmget,  	.tiocmset =	     mct_u232_tiocmset, +	.tiocmiwait =        usb_serial_generic_tiocmiwait,  	.attach =	     mct_u232_startup,  	.port_probe =        mct_u232_port_probe,  	.port_remove =       mct_u232_port_remove, -	.ioctl =             mct_u232_ioctl, -	.get_icount =        mct_u232_get_icount, +	.get_icount =        usb_serial_generic_get_icount,  };  static struct usb_serial_driver * const serial_drivers[] = { @@ -113,9 +108,6 @@ struct mct_u232_private {  	unsigned char	     last_lsr;      /* Line Status Register */  	unsigned char	     last_msr;      /* Modem Status Register */  	unsigned int	     rx_flags;      /* Throttling flags */ -	struct async_icount  icount; -	wait_queue_head_t    msr_wait;	/* for handling sleeping while waiting -						for msr change to happen */  };  #define THROTTLED		0x01 @@ -409,7 +401,6 @@ static int mct_u232_port_probe(struct usb_serial_port *port)  		return -ENOMEM;  	spin_lock_init(&priv->lock); -	init_waitqueue_head(&priv->msr_wait);  	usb_set_serial_port_data(port, priv); @@ -573,7 +564,7 @@ static void mct_u232_read_int_callback(struct urb *urb)  	/* Record Control Line states */  	mct_u232_msr_to_state(port, &priv->control_state, priv->last_msr); -	mct_u232_msr_to_icount(&priv->icount, priv->last_msr); +	mct_u232_msr_to_icount(&port->icount, priv->last_msr);  #if 0  	/* Not yet handled. See belkin_sa.c for further information */ @@ -601,7 +592,7 @@ static void mct_u232_read_int_callback(struct urb *urb)  		tty_kref_put(tty);  	}  #endif -	wake_up_interruptible(&priv->msr_wait); +	wake_up_interruptible(&port->port.delta_msr_wait);  	spin_unlock_irqrestore(&priv->lock, flags);  exit:  	retval = usb_submit_urb(urb, GFP_ATOMIC); @@ -789,82 +780,6 @@ static void mct_u232_unthrottle(struct tty_struct *tty)  	}  } -static int  mct_u232_ioctl(struct tty_struct *tty, -			unsigned int cmd, unsigned long arg) -{ -	DEFINE_WAIT(wait); -	struct usb_serial_port *port = tty->driver_data; -	struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port); -	struct async_icount cnow, cprev; -	unsigned long flags; - -	dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd); - -	switch (cmd) { - -	case TIOCMIWAIT: - -		dev_dbg(&port->dev, "%s TIOCMIWAIT", __func__); - -		spin_lock_irqsave(&mct_u232_port->lock, flags); -		cprev = mct_u232_port->icount; -		spin_unlock_irqrestore(&mct_u232_port->lock, flags); -		for ( ; ; ) { -			prepare_to_wait(&mct_u232_port->msr_wait, -					&wait, TASK_INTERRUPTIBLE); -			schedule(); -			finish_wait(&mct_u232_port->msr_wait, &wait); -			/* see if a signal did it */ -			if (signal_pending(current)) -				return -ERESTARTSYS; -			spin_lock_irqsave(&mct_u232_port->lock, flags); -			cnow = mct_u232_port->icount; -			spin_unlock_irqrestore(&mct_u232_port->lock, flags); -			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && -			    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) -				return -EIO; /* no change => error */ -			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || -			    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || -			    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) || -			    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { -				return 0; -			} -			cprev = cnow; -		} - -	} -	return -ENOIOCTLCMD; -} - -static int  mct_u232_get_icount(struct tty_struct *tty, -			struct serial_icounter_struct *icount) -{ -	struct usb_serial_port *port = tty->driver_data; -	struct mct_u232_private *mct_u232_port = usb_get_serial_port_data(port); -	struct async_icount *ic = &mct_u232_port->icount; -	unsigned long flags; - -	spin_lock_irqsave(&mct_u232_port->lock, flags); - -	icount->cts = ic->cts; -	icount->dsr = ic->dsr; -	icount->rng = ic->rng; -	icount->dcd = ic->dcd; -	icount->rx = ic->rx; -	icount->tx = ic->tx; -	icount->frame = ic->frame; -	icount->overrun = ic->overrun; -	icount->parity = ic->parity; -	icount->brk = ic->brk; -	icount->buf_overrun = ic->buf_overrun; - -	spin_unlock_irqrestore(&mct_u232_port->lock, flags); - -	dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", -		__func__,  icount->rx, icount->tx); -	return 0; -} -  module_usb_serial_driver(serial_drivers, id_table);  MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index bf3c7a23553..47e247759eb 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -177,10 +177,7 @@ static void metrousb_cleanup(struct usb_serial_port *port)  	usb_unlink_urb(port->interrupt_in_urb);  	usb_kill_urb(port->interrupt_in_urb); -	mutex_lock(&port->serial->disc_mutex); -	if (!port->serial->disconnected) -		metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port); -	mutex_unlock(&port->serial->disc_mutex); +	metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port);  }  static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index e0ebec3b5d6..fc506bb7131 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -62,7 +62,6 @@ struct moschip_port {  	__u8	shadowMCR;		/* last MCR value received */  	__u8	shadowMSR;		/* last MSR value received */  	char			open; -	struct async_icount	icount;  	struct usb_serial_port	*port;	/* loop back to the owner */  	struct urb		*write_urb_pool[NUM_URBS];  }; @@ -1075,9 +1074,6 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)  		dev_err(&port->dev, "%s - Error %d submitting read urb\n",  							__func__, response); -	/* initialize our icount structure */ -	memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount)); -  	/* initialize our port settings */  	mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */ @@ -1144,16 +1140,9 @@ static void mos7720_close(struct usb_serial_port *port)  	usb_kill_urb(port->write_urb);  	usb_kill_urb(port->read_urb); -	mutex_lock(&serial->disc_mutex); -	/* these commands must not be issued if the device has -	 * been disconnected */ -	if (!serial->disconnected) { -		write_mos_reg(serial, port->number - port->serial->minor, -			      MCR, 0x00); -		write_mos_reg(serial, port->number - port->serial->minor, -			      IER, 0x00); -	} -	mutex_unlock(&serial->disc_mutex); +	write_mos_reg(serial, port->number - port->serial->minor, MCR, 0x00); +	write_mos_reg(serial, port->number - port->serial->minor, IER, 0x00); +  	mos7720_port->open = 0;  } @@ -1803,33 +1792,6 @@ static int mos7720_tiocmset(struct tty_struct *tty,  	return 0;  } -static int mos7720_get_icount(struct tty_struct *tty, -				struct serial_icounter_struct *icount) -{ -	struct usb_serial_port *port = tty->driver_data; -	struct moschip_port *mos7720_port; -	struct async_icount cnow; - -	mos7720_port = usb_get_serial_port_data(port); -	cnow = mos7720_port->icount; - -	icount->cts = cnow.cts; -	icount->dsr = cnow.dsr; -	icount->rng = cnow.rng; -	icount->dcd = cnow.dcd; -	icount->rx = cnow.rx; -	icount->tx = cnow.tx; -	icount->frame = cnow.frame; -	icount->overrun = cnow.overrun; -	icount->parity = cnow.parity; -	icount->brk = cnow.brk; -	icount->buf_overrun = cnow.buf_overrun; - -	dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__, -		icount->rx, icount->tx); -	return 0; -} -  static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,  			  unsigned int __user *value)  { @@ -1905,8 +1867,6 @@ static int mos7720_ioctl(struct tty_struct *tty,  {  	struct usb_serial_port *port = tty->driver_data;  	struct moschip_port *mos7720_port; -	struct async_icount cnow; -	struct async_icount cprev;  	mos7720_port = usb_get_serial_port_data(port);  	if (mos7720_port == NULL) @@ -1931,27 +1891,6 @@ static int mos7720_ioctl(struct tty_struct *tty,  		dev_dbg(&port->dev, "%s TIOCGSERIAL\n", __func__);  		return get_serial_info(mos7720_port,  				       (struct serial_struct __user *)arg); - -	case TIOCMIWAIT: -		dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__); -		cprev = mos7720_port->icount; -		while (1) { -			if (signal_pending(current)) -				return -ERESTARTSYS; -			cnow = mos7720_port->icount; -			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && -			    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) -				return -EIO; /* no change => error */ -			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || -			    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || -			    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) || -			    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { -				return 0; -			} -			cprev = cnow; -		} -		/* NOTREACHED */ -		break;  	}  	return -ENOIOCTLCMD; @@ -2107,7 +2046,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {  	.ioctl			= mos7720_ioctl,  	.tiocmget		= mos7720_tiocmget,  	.tiocmset		= mos7720_tiocmset, -	.get_icount		= mos7720_get_icount,  	.set_termios		= mos7720_set_termios,  	.write			= mos7720_write,  	.write_room		= mos7720_write_room, diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 809fb329eca..f0b4e5c01e1 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -219,9 +219,6 @@ struct moschip_port {  	char open;  	char open_ports;  	wait_queue_head_t wait_chase;	/* for handling sleeping while waiting for chase to finish */ -	wait_queue_head_t delta_msr_wait;	/* for handling sleeping while waiting for msr change to happen */ -	int delta_msr_cond; -	struct async_icount icount;  	struct usb_serial_port *port;	/* loop back to the owner of this object */  	/* Offsets */ @@ -400,29 +397,22 @@ static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)  	struct moschip_port *mos7840_port;  	struct async_icount *icount;  	mos7840_port = port; -	icount = &mos7840_port->icount;  	if (new_msr &  	    (MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI |  	     MOS_MSR_DELTA_CD)) { -		icount = &mos7840_port->icount; +		icount = &mos7840_port->port->icount;  		/* update input line counters */ -		if (new_msr & MOS_MSR_DELTA_CTS) { +		if (new_msr & MOS_MSR_DELTA_CTS)  			icount->cts++; -			smp_wmb(); -		} -		if (new_msr & MOS_MSR_DELTA_DSR) { +		if (new_msr & MOS_MSR_DELTA_DSR)  			icount->dsr++; -			smp_wmb(); -		} -		if (new_msr & MOS_MSR_DELTA_CD) { +		if (new_msr & MOS_MSR_DELTA_CD)  			icount->dcd++; -			smp_wmb(); -		} -		if (new_msr & MOS_MSR_DELTA_RI) { +		if (new_msr & MOS_MSR_DELTA_RI)  			icount->rng++; -			smp_wmb(); -		} + +		wake_up_interruptible(&port->port->port.delta_msr_wait);  	}  } @@ -440,23 +430,15 @@ static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)  	}  	/* update input line counters */ -	icount = &port->icount; -	if (new_lsr & SERIAL_LSR_BI) { +	icount = &port->port->icount; +	if (new_lsr & SERIAL_LSR_BI)  		icount->brk++; -		smp_wmb(); -	} -	if (new_lsr & SERIAL_LSR_OE) { +	if (new_lsr & SERIAL_LSR_OE)  		icount->overrun++; -		smp_wmb(); -	} -	if (new_lsr & SERIAL_LSR_PE) { +	if (new_lsr & SERIAL_LSR_PE)  		icount->parity++; -		smp_wmb(); -	} -	if (new_lsr & SERIAL_LSR_FE) { +	if (new_lsr & SERIAL_LSR_FE)  		icount->frame++; -		smp_wmb(); -	}  }  /************************************************************************/ @@ -775,9 +757,8 @@ static void mos7840_bulk_in_callback(struct urb *urb)  		struct tty_port *tport = &mos7840_port->port->port;  		tty_insert_flip_string(tport, data, urb->actual_length);  		tty_flip_buffer_push(tport); -		mos7840_port->icount.rx += urb->actual_length; -		smp_wmb(); -		dev_dbg(&port->dev, "mos7840_port->icount.rx is %d:\n", mos7840_port->icount.rx); +		port->icount.rx += urb->actual_length; +		dev_dbg(&port->dev, "icount.rx is %d:\n", port->icount.rx);  	}  	if (!mos7840_port->read_urb) { @@ -1127,10 +1108,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)  	/* initialize our wait queues */  	init_waitqueue_head(&mos7840_port->wait_chase); -	init_waitqueue_head(&mos7840_port->delta_msr_wait); - -	/* initialize our icount structure */ -	memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount));  	/* initialize our port settings */  	/* Must set to enable ints! */ @@ -1138,8 +1115,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)  	/* send a open port command */  	mos7840_port->open = 1;  	/* mos7840_change_port_settings(mos7840_port,old_termios); */ -	mos7840_port->icount.tx = 0; -	mos7840_port->icount.rx = 0;  	return 0;  } @@ -1222,25 +1197,10 @@ static void mos7840_close(struct usb_serial_port *port)  		}  	} -	/* While closing port, shutdown all bulk read, write  * -	 * and interrupt read if they exists                  */ -	if (serial->dev) { -		if (mos7840_port->write_urb) { -			dev_dbg(&port->dev, "%s", "Shutdown bulk write\n"); -			usb_kill_urb(mos7840_port->write_urb); -		} -		if (mos7840_port->read_urb) { -			dev_dbg(&port->dev, "%s", "Shutdown bulk read\n"); -			usb_kill_urb(mos7840_port->read_urb); -			mos7840_port->read_urb_busy = false; -		} -		if ((&mos7840_port->control_urb)) { -			dev_dbg(&port->dev, "%s", "Shutdown control read\n"); -			/*/      usb_kill_urb (mos7840_port->control_urb); */ -		} -	} -/*      if(mos7840_port->ctrl_buf != NULL) */ -/*              kfree(mos7840_port->ctrl_buf); */ +	usb_kill_urb(mos7840_port->write_urb); +	usb_kill_urb(mos7840_port->read_urb); +	mos7840_port->read_urb_busy = false; +  	port0->open_ports--;  	dev_dbg(&port->dev, "%s in close%d:in port%d\n", __func__, port0->open_ports, port->number);  	if (port0->open_ports == 0) { @@ -1252,8 +1212,7 @@ static void mos7840_close(struct usb_serial_port *port)  	if (mos7840_port->write_urb) {  		/* if this urb had a transfer buffer already (old tx) free it */ -		if (mos7840_port->write_urb->transfer_buffer != NULL) -			kfree(mos7840_port->write_urb->transfer_buffer); +		kfree(mos7840_port->write_urb->transfer_buffer);  		usb_free_urb(mos7840_port->write_urb);  	} @@ -1330,9 +1289,8 @@ static void mos7840_break(struct tty_struct *tty, int break_state)  	if (mos7840_port == NULL)  		return; -	if (serial->dev) -		/* flush and block until tx is empty */ -		mos7840_block_until_chase_response(tty, mos7840_port); +	/* flush and block until tx is empty */ +	mos7840_block_until_chase_response(tty, mos7840_port);  	if (break_state == -1)  		data = mos7840_port->shadowLCR | LCR_SET_BREAK; @@ -1522,9 +1480,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,  		goto exit;  	}  	bytes_sent = transfer_size; -	mos7840_port->icount.tx += transfer_size; -	smp_wmb(); -	dev_dbg(&port->dev, "mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx); +	port->icount.tx += transfer_size; +	dev_dbg(&port->dev, "icount.tx is %d:\n", port->icount.tx);  exit:  	return bytes_sent; @@ -2017,8 +1974,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty,  			mos7840_port->read_urb_busy = false;  		}  	} -	wake_up(&mos7840_port->delta_msr_wait); -	mos7840_port->delta_msr_cond = 1;  	dev_dbg(&port->dev, "%s - mos7840_port->shadowLCR is End %x\n", __func__,  		mos7840_port->shadowLCR);  } @@ -2145,34 +2100,6 @@ static int mos7840_get_serial_info(struct moschip_port *mos7840_port,  	return 0;  } -static int mos7840_get_icount(struct tty_struct *tty, -			struct serial_icounter_struct *icount) -{ -	struct usb_serial_port *port = tty->driver_data; -	struct moschip_port *mos7840_port; -	struct async_icount cnow; - -	mos7840_port = mos7840_get_port_private(port); -	cnow = mos7840_port->icount; - -	smp_rmb(); -	icount->cts = cnow.cts; -	icount->dsr = cnow.dsr; -	icount->rng = cnow.rng; -	icount->dcd = cnow.dcd; -	icount->rx = cnow.rx; -	icount->tx = cnow.tx; -	icount->frame = cnow.frame; -	icount->overrun = cnow.overrun; -	icount->parity = cnow.parity; -	icount->brk = cnow.brk; -	icount->buf_overrun = cnow.buf_overrun; - -	dev_dbg(&port->dev, "%s TIOCGICOUNT RX=%d, TX=%d\n", __func__, -		icount->rx, icount->tx); -	return 0; -} -  /*****************************************************************************   * SerialIoctl   *	this function handles any ioctl calls to the driver @@ -2185,9 +2112,6 @@ static int mos7840_ioctl(struct tty_struct *tty,  	void __user *argp = (void __user *)arg;  	struct moschip_port *mos7840_port; -	struct async_icount cnow; -	struct async_icount cprev; -  	if (mos7840_port_paranoia_check(port, __func__))  		return -1; @@ -2212,36 +2136,6 @@ static int mos7840_ioctl(struct tty_struct *tty,  	case TIOCSSERIAL:  		dev_dbg(&port->dev, "%s TIOCSSERIAL\n", __func__);  		break; - -	case TIOCMIWAIT: -		dev_dbg(&port->dev, "%s  TIOCMIWAIT\n", __func__); -		cprev = mos7840_port->icount; -		while (1) { -			/* interruptible_sleep_on(&mos7840_port->delta_msr_wait); */ -			mos7840_port->delta_msr_cond = 0; -			wait_event_interruptible(mos7840_port->delta_msr_wait, -						 (mos7840_port-> -						  delta_msr_cond == 1)); - -			/* see if a signal did it */ -			if (signal_pending(current)) -				return -ERESTARTSYS; -			cnow = mos7840_port->icount; -			smp_rmb(); -			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && -			    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) -				return -EIO;	/* no change => error */ -			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || -			    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || -			    ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || -			    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { -				return 0; -			} -			cprev = cnow; -		} -		/* NOTREACHED */ -		break; -  	default:  		break;  	} @@ -2588,7 +2482,8 @@ static struct usb_serial_driver moschip7840_4port_device = {  	.break_ctl = mos7840_break,  	.tiocmget = mos7840_tiocmget,  	.tiocmset = mos7840_tiocmset, -	.get_icount = mos7840_get_icount, +	.tiocmiwait = usb_serial_generic_tiocmiwait, +	.get_icount = usb_serial_generic_get_icount,  	.port_probe = mos7840_port_probe,  	.port_remove = mos7840_port_remove,  	.read_bulk_callback = mos7840_bulk_in_callback, diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index e13e1a4d3e1..5f4b0cd0f6e 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -120,7 +120,10 @@ static int send_control_msg(struct usb_serial_port *port, u8 requesttype,  				0, 0, buffer, 1, 0);  	kfree(buffer); -	return retval; +	if (retval < 0) +		return retval; + +	return 0;  }  static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -306,7 +309,6 @@ static int opticon_tiocmset(struct tty_struct *tty,  			   unsigned int set, unsigned int clear)  {  	struct usb_serial_port *port = tty->driver_data; -	struct usb_serial *serial = port->serial;  	struct opticon_private *priv = usb_get_serial_port_data(port);  	unsigned long flags;  	bool rts; @@ -327,15 +329,11 @@ static int opticon_tiocmset(struct tty_struct *tty,  	if (!changed)  		return 0; -	/* Send the new RTS state to the connected device */ -	mutex_lock(&serial->disc_mutex); -	if (!serial->disconnected) -		ret = send_control_msg(port, CONTROL_RTS, !rts); -	else -		ret = -ENODEV; -	mutex_unlock(&serial->disc_mutex); +	ret = send_control_msg(port, CONTROL_RTS, !rts); +	if (ret) +		return usb_translate_errors(ret); -	return ret; +	return 0;  }  static int get_serial_info(struct usb_serial_port *port, diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index a958fd41b5b..7e3e0782e51 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -124,8 +124,6 @@ static void oti6858_close(struct usb_serial_port *port);  static void oti6858_set_termios(struct tty_struct *tty,  			struct usb_serial_port *port, struct ktermios *old);  static void oti6858_init_termios(struct tty_struct *tty); -static int oti6858_ioctl(struct tty_struct *tty, -			unsigned int cmd, unsigned long arg);  static void oti6858_read_int_callback(struct urb *urb);  static void oti6858_read_bulk_callback(struct urb *urb);  static void oti6858_write_bulk_callback(struct urb *urb); @@ -136,6 +134,7 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty);  static int oti6858_tiocmget(struct tty_struct *tty);  static int oti6858_tiocmset(struct tty_struct *tty,  				unsigned int set, unsigned int clear); +static int oti6858_tiocmiwait(struct tty_struct *tty, unsigned long arg);  static int oti6858_port_probe(struct usb_serial_port *port);  static int oti6858_port_remove(struct usb_serial_port *port); @@ -150,11 +149,11 @@ static struct usb_serial_driver oti6858_device = {  	.open =			oti6858_open,  	.close =		oti6858_close,  	.write =		oti6858_write, -	.ioctl =		oti6858_ioctl,  	.set_termios =		oti6858_set_termios,  	.init_termios = 	oti6858_init_termios,  	.tiocmget =		oti6858_tiocmget,  	.tiocmset =		oti6858_tiocmset, +	.tiocmiwait =		oti6858_tiocmiwait,  	.read_bulk_callback =	oti6858_read_bulk_callback,  	.read_int_callback =	oti6858_read_int_callback,  	.write_bulk_callback =	oti6858_write_bulk_callback, @@ -188,7 +187,6 @@ struct oti6858_private {  	u8 setup_done;  	struct delayed_work delayed_setup_work; -	wait_queue_head_t intr_wait;  	struct usb_serial_port *port;   /* USB port with which associated */  }; @@ -339,7 +337,6 @@ static int oti6858_port_probe(struct usb_serial_port *port)  		return -ENOMEM;  	spin_lock_init(&priv->lock); -	init_waitqueue_head(&priv->intr_wait);  	priv->port = port;  	INIT_DELAYED_WORK(&priv->delayed_setup_work, setup_line);  	INIT_DELAYED_WORK(&priv->delayed_write_work, send_data); @@ -652,8 +649,9 @@ static int oti6858_tiocmget(struct tty_struct *tty)  	return result;  } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) +static int oti6858_tiocmiwait(struct tty_struct *tty, unsigned long arg)  { +	struct usb_serial_port *port = tty->driver_data;  	struct oti6858_private *priv = usb_get_serial_port_data(port);  	unsigned long flags;  	unsigned int prev, status; @@ -664,11 +662,15 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)  	spin_unlock_irqrestore(&priv->lock, flags);  	while (1) { -		wait_event_interruptible(priv->intr_wait, +		wait_event_interruptible(port->port.delta_msr_wait, +					port->serial->disconnected ||  					priv->status.pin_state != prev);  		if (signal_pending(current))  			return -ERESTARTSYS; +		if (port->serial->disconnected) +			return -EIO; +  		spin_lock_irqsave(&priv->lock, flags);  		status = priv->status.pin_state & PIN_MASK;  		spin_unlock_irqrestore(&priv->lock, flags); @@ -687,24 +689,6 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)  	return 0;  } -static int oti6858_ioctl(struct tty_struct *tty, -			unsigned int cmd, unsigned long arg) -{ -	struct usb_serial_port *port = tty->driver_data; - -	dev_dbg(&port->dev, "%s(cmd = 0x%04x, arg = 0x%08lx)\n", __func__, cmd, arg); - -	switch (cmd) { -	case TIOCMIWAIT: -		dev_dbg(&port->dev, "%s(): TIOCMIWAIT\n", __func__); -		return wait_modem_info(port, arg); -	default: -		dev_dbg(&port->dev, "%s(): 0x%04x not supported\n", __func__, cmd); -		break; -	} -	return -ENOIOCTLCMD; -} -  static void oti6858_read_int_callback(struct urb *urb)  {  	struct usb_serial_port *port =  urb->context; @@ -763,7 +747,7 @@ static void oti6858_read_int_callback(struct urb *urb)  		if (!priv->transient) {  			if (xs->pin_state != priv->status.pin_state) -				wake_up_interruptible(&priv->intr_wait); +				wake_up_interruptible(&port->port.delta_msr_wait);  			memcpy(&priv->status, xs, OTI6858_CTRL_PKT_SIZE);  		} diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 54adc9125e5..7151659367a 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -139,7 +139,6 @@ struct pl2303_serial_private {  struct pl2303_private {  	spinlock_t lock; -	wait_queue_head_t delta_msr_wait;  	u8 line_control;  	u8 line_status;  }; @@ -150,7 +149,7 @@ static int pl2303_vendor_read(__u16 value, __u16 index,  	int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),  			VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE,  			value, index, buf, 1, 100); -	dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x  %d - %x\n", +	dev_dbg(&serial->interface->dev, "0x%x:0x%x:0x%x:0x%x  %d - %x\n",  		VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index,  		res, buf[0]);  	return res; @@ -162,7 +161,7 @@ static int pl2303_vendor_write(__u16 value, __u16 index,  	int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),  			VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE,  			value, index, NULL, 0, 100); -	dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x  %d\n", +	dev_dbg(&serial->interface->dev, "0x%x:0x%x:0x%x:0x%x  %d\n",  		VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index,  		res);  	return res; @@ -233,7 +232,6 @@ static int pl2303_port_probe(struct usb_serial_port *port)  		return -ENOMEM;  	spin_lock_init(&priv->lock); -	init_waitqueue_head(&priv->delta_msr_wait);  	usb_set_serial_port_data(port, priv); @@ -250,14 +248,15 @@ static int pl2303_port_remove(struct usb_serial_port *port)  	return 0;  } -static int set_control_lines(struct usb_device *dev, u8 value) +static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)  { +	struct usb_device *dev = port->serial->dev;  	int retval;  	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),  				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,  				 value, 0, NULL, 0, 100); -	dev_dbg(&dev->dev, "%s - value = %d, retval = %d\n", __func__, +	dev_dbg(&port->dev, "%s - value = %d, retval = %d\n", __func__,  		value, retval);  	return retval;  } @@ -439,7 +438,7 @@ static void pl2303_set_termios(struct tty_struct *tty,  	if (control != priv->line_control) {  		control = priv->line_control;  		spin_unlock_irqrestore(&priv->lock, flags); -		set_control_lines(serial->dev, control); +		pl2303_set_control_lines(port, control);  	} else {  		spin_unlock_irqrestore(&priv->lock, flags);  	} @@ -482,7 +481,7 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on)  		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);  	control = priv->line_control;  	spin_unlock_irqrestore(&priv->lock, flags); -	set_control_lines(port->serial->dev, control); +	pl2303_set_control_lines(port, control);  }  static void pl2303_close(struct usb_serial_port *port) @@ -532,7 +531,6 @@ static int pl2303_tiocmset(struct tty_struct *tty,  			   unsigned int set, unsigned int clear)  {  	struct usb_serial_port *port = tty->driver_data; -	struct usb_serial *serial = port->serial;  	struct pl2303_private *priv = usb_get_serial_port_data(port);  	unsigned long flags;  	u8 control; @@ -550,14 +548,11 @@ static int pl2303_tiocmset(struct tty_struct *tty,  	control = priv->line_control;  	spin_unlock_irqrestore(&priv->lock, flags); -	mutex_lock(&serial->disc_mutex); -	if (!serial->disconnected) -		ret = set_control_lines(serial->dev, control); -	else -		ret = -ENODEV; -	mutex_unlock(&serial->disc_mutex); +	ret = pl2303_set_control_lines(port, control); +	if (ret) +		return usb_translate_errors(ret); -	return ret; +	return 0;  }  static int pl2303_tiocmget(struct tty_struct *tty) @@ -594,8 +589,9 @@ static int pl2303_carrier_raised(struct usb_serial_port *port)  	return 0;  } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) +static int pl2303_tiocmiwait(struct tty_struct *tty, unsigned long arg)  { +	struct usb_serial_port *port = tty->driver_data;  	struct pl2303_private *priv = usb_get_serial_port_data(port);  	unsigned long flags;  	unsigned int prevstatus; @@ -607,11 +603,14 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)  	spin_unlock_irqrestore(&priv->lock, flags);  	while (1) { -		interruptible_sleep_on(&priv->delta_msr_wait); +		interruptible_sleep_on(&port->port.delta_msr_wait);  		/* see if a signal did it */  		if (signal_pending(current))  			return -ERESTARTSYS; +		if (port->serial->disconnected) +			return -EIO; +  		spin_lock_irqsave(&priv->lock, flags);  		status = priv->line_status;  		spin_unlock_irqrestore(&priv->lock, flags); @@ -650,10 +649,6 @@ static int pl2303_ioctl(struct tty_struct *tty,  			return -EFAULT;  		return 0; - -	case TIOCMIWAIT: -		dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__); -		return wait_modem_info(port, arg);  	default:  		dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);  		break; @@ -719,7 +714,7 @@ static void pl2303_update_line_status(struct usb_serial_port *port,  	spin_unlock_irqrestore(&priv->lock, flags);  	if (priv->line_status & UART_BREAK_ERROR)  		usb_serial_handle_break(port); -	wake_up_interruptible(&priv->delta_msr_wait); +	wake_up_interruptible(&port->port.delta_msr_wait);  	tty = tty_port_tty_get(&port->port);  	if (!tty) @@ -783,7 +778,7 @@ static void pl2303_process_read_urb(struct urb *urb)  	line_status = priv->line_status;  	priv->line_status &= ~UART_STATE_TRANSIENT_MASK;  	spin_unlock_irqrestore(&priv->lock, flags); -	wake_up_interruptible(&priv->delta_msr_wait); +	wake_up_interruptible(&port->port.delta_msr_wait);  	if (!urb->actual_length)  		return; @@ -834,6 +829,7 @@ static struct usb_serial_driver pl2303_device = {  	.set_termios =		pl2303_set_termios,  	.tiocmget =		pl2303_tiocmget,  	.tiocmset =		pl2303_tiocmset, +	.tiocmiwait =		pl2303_tiocmiwait,  	.process_read_urb =	pl2303_process_read_urb,  	.read_int_callback =	pl2303_read_int_callback,  	.attach =		pl2303_startup, diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index d643a4d4d77..3c278521f7e 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -128,9 +128,6 @@ struct qt2_port_private {  	u8          shadowLSR;  	u8          shadowMSR; -	wait_queue_head_t   delta_msr_wait; /* Used for TIOCMIWAIT */ -	struct async_icount icount; -  	struct usb_serial_port *port;  }; @@ -425,12 +422,6 @@ static void qt2_close(struct usb_serial_port *port)  	port_priv->urb_in_use = false;  	spin_unlock_irqrestore(&port_priv->urb_lock, flags); -	mutex_lock(&port->serial->disc_mutex); -	if (port->serial->disconnected) { -		mutex_unlock(&port->serial->disc_mutex); -		return; -	} -  	/* flush the port transmit buffer */  	i = usb_control_msg(serial->dev,  			    usb_rcvctrlpipe(serial->dev, 0), @@ -461,8 +452,6 @@ static void qt2_close(struct usb_serial_port *port)  	if (i < 0)  		dev_err(&port->dev, "%s - close port failed %i\n",  			__func__, i); - -	mutex_unlock(&port->serial->disc_mutex);  }  static void qt2_disconnect(struct usb_serial *serial) @@ -495,67 +484,6 @@ static int get_serial_info(struct usb_serial_port *port,  	return 0;  } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ -	struct qt2_port_private *priv = usb_get_serial_port_data(port); -	struct async_icount prev, cur; -	unsigned long flags; - -	spin_lock_irqsave(&priv->lock, flags); -	prev = priv->icount; -	spin_unlock_irqrestore(&priv->lock, flags); - -	while (1) { -		wait_event_interruptible(priv->delta_msr_wait, -					 ((priv->icount.rng != prev.rng) || -					  (priv->icount.dsr != prev.dsr) || -					  (priv->icount.dcd != prev.dcd) || -					  (priv->icount.cts != prev.cts))); - -		if (signal_pending(current)) -			return -ERESTARTSYS; - -		spin_lock_irqsave(&priv->lock, flags); -		cur = priv->icount; -		spin_unlock_irqrestore(&priv->lock, flags); - -		if ((prev.rng == cur.rng) && -		    (prev.dsr == cur.dsr) && -		    (prev.dcd == cur.dcd) && -		    (prev.cts == cur.cts)) -			return -EIO; - -		if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) || -		    (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) || -		    (arg & TIOCM_CD && (prev.dcd != cur.dcd)) || -		    (arg & TIOCM_CTS && (prev.cts != cur.cts))) -			return 0; -	} -	return 0; -} - -static int qt2_get_icount(struct tty_struct *tty, -			  struct serial_icounter_struct *icount) -{ -	struct usb_serial_port *port = tty->driver_data; -	struct qt2_port_private *priv = usb_get_serial_port_data(port); -	struct async_icount cnow = priv->icount; - -	icount->cts = cnow.cts; -	icount->dsr = cnow.dsr; -	icount->rng = cnow.rng; -	icount->dcd = cnow.dcd; -	icount->rx = cnow.rx; -	icount->tx = cnow.tx; -	icount->frame = cnow.frame; -	icount->overrun = cnow.overrun; -	icount->parity = cnow.parity; -	icount->brk = cnow.brk; -	icount->buf_overrun = cnow.buf_overrun; - -	return 0; -} -  static int qt2_ioctl(struct tty_struct *tty,  		     unsigned int cmd, unsigned long arg)  { @@ -565,10 +493,6 @@ static int qt2_ioctl(struct tty_struct *tty,  	case TIOCGSERIAL:  		return get_serial_info(port,  				       (struct serial_struct __user *)arg); - -	case TIOCMIWAIT: -		return wait_modem_info(port, arg); -  	default:  		break;  	} @@ -661,9 +585,7 @@ void qt2_process_read_urb(struct urb *urb)  						 __func__);  					break;  				} - -				if (port_priv->is_open) -					tty_flip_buffer_push(&port->port); +				tty_flip_buffer_push(&port->port);  				newport = *(ch + 3); @@ -706,8 +628,7 @@ void qt2_process_read_urb(struct urb *urb)  		tty_insert_flip_string(&port->port, ch, 1);  	} -	if (port_priv->is_open) -		tty_flip_buffer_push(&port->port); +	tty_flip_buffer_push(&port->port);  }  static void qt2_write_bulk_callback(struct urb *urb) @@ -827,7 +748,6 @@ static int qt2_port_probe(struct usb_serial_port *port)  	spin_lock_init(&port_priv->lock);  	spin_lock_init(&port_priv->urb_lock); -	init_waitqueue_head(&port_priv->delta_msr_wait);  	port_priv->port = port;  	port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL); @@ -959,18 +879,15 @@ static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch)  	if (newMSR & UART_MSR_ANY_DELTA) {  		/* update input line counters */  		if (newMSR & UART_MSR_DCTS) -			port_priv->icount.cts++; - +			port->icount.cts++;  		if (newMSR & UART_MSR_DDSR) -			port_priv->icount.dsr++; - +			port->icount.dsr++;  		if (newMSR & UART_MSR_DDCD) -			port_priv->icount.dcd++; - +			port->icount.dcd++;  		if (newMSR & UART_MSR_TERI) -			port_priv->icount.rng++; +			port->icount.rng++; -		wake_up_interruptible(&port_priv->delta_msr_wait); +		wake_up_interruptible(&port->port.delta_msr_wait);  	}  } @@ -990,7 +907,7 @@ static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch)  	port_priv->shadowLSR = newLSR;  	spin_unlock_irqrestore(&port_priv->lock, flags); -	icount = &port_priv->icount; +	icount = &port->icount;  	if (newLSR & UART_LSR_BRK_ERROR_BITS) { @@ -1100,7 +1017,8 @@ static struct usb_serial_driver qt2_device = {  	.break_ctl           = qt2_break_ctl,  	.tiocmget            = qt2_tiocmget,  	.tiocmset            = qt2_tiocmset, -	.get_icount	     = qt2_get_icount, +	.tiocmiwait          = usb_serial_generic_tiocmiwait, +	.get_icount	     = usb_serial_generic_get_icount,  	.ioctl               = qt2_ioctl,  	.set_termios         = qt2_set_termios,  }; diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index c13f6e74774..2b06481dc85 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -778,30 +778,25 @@ static void sierra_close(struct usb_serial_port *port)  	portdata->rts_state = 0;  	portdata->dtr_state = 0; -	if (serial->dev) { -		mutex_lock(&serial->disc_mutex); -		if (!serial->disconnected) { -			serial->interface->needs_remote_wakeup = 0; -			/* odd error handling due to pm counters */ -			if (!usb_autopm_get_interface(serial->interface)) -				sierra_send_setup(port); -			else -				usb_autopm_get_interface_no_resume(serial->interface); -				 -		} -		mutex_unlock(&serial->disc_mutex); -		spin_lock_irq(&intfdata->susp_lock); -		portdata->opened = 0; -		spin_unlock_irq(&intfdata->susp_lock); +	mutex_lock(&serial->disc_mutex); +	if (!serial->disconnected) { +		serial->interface->needs_remote_wakeup = 0; +		/* odd error handling due to pm counters */ +		if (!usb_autopm_get_interface(serial->interface)) +			sierra_send_setup(port); +		else +			usb_autopm_get_interface_no_resume(serial->interface); +	} +	mutex_unlock(&serial->disc_mutex); +	spin_lock_irq(&intfdata->susp_lock); +	portdata->opened = 0; +	spin_unlock_irq(&intfdata->susp_lock); -		/* Stop reading urbs */ -		sierra_stop_rx_urbs(port); -		/* .. and release them */ -		for (i = 0; i < portdata->num_in_urbs; i++) { -			sierra_release_urb(portdata->in_urbs[i]); -			portdata->in_urbs[i] = NULL; -		} +	sierra_stop_rx_urbs(port); +	for (i = 0; i < portdata->num_in_urbs; i++) { +		sierra_release_urb(portdata->in_urbs[i]); +		portdata->in_urbs[i] = NULL;  	}  } diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 91ff8e3bddb..cf3df793c2b 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -1,7 +1,7 @@  /*   * spcp8x5 USB to serial adaptor driver   * - * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) + * Copyright (C) 2010-2013 Johan Hovold (jhovold@gmail.com)   * Copyright (C) 2006 Linxb (xubin.lin@worldplus.com.cn)   * Copyright (C) 2006 S1 Corp.   * @@ -13,8 +13,6 @@   *	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. - * - *   */  #include <linux/kernel.h>  #include <linux/errno.h> @@ -28,7 +26,10 @@  #include <linux/usb.h>  #include <linux/usb/serial.h> -#define DRIVER_DESC 	"SPCP8x5 USB to serial adaptor driver" +#define DRIVER_DESC	"SPCP8x5 USB to serial adaptor driver" + +#define SPCP825_QUIRK_NO_UART_STATUS	0x01 +#define SPCP825_QUIRK_NO_WORK_MODE	0x02  #define SPCP8x5_007_VID		0x04FC  #define SPCP8x5_007_PID		0x0201 @@ -46,13 +47,15 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)},  	{ USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)},  	{ USB_DEVICE(SPCP8x5_008_VID, SPCP8x5_008_PID)}, -	{ USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID)}, +	{ USB_DEVICE(SPCP8x5_007_VID, SPCP8x5_007_PID), +	  .driver_info = SPCP825_QUIRK_NO_UART_STATUS | +				SPCP825_QUIRK_NO_WORK_MODE },  	{ }					/* Terminating entry */  };  MODULE_DEVICE_TABLE(usb, id_table);  struct spcp8x5_usb_ctrl_arg { -	u8 	type; +	u8	type;  	u8	cmd;  	u8	cmd_type;  	u16	value; @@ -138,51 +141,33 @@ struct spcp8x5_usb_ctrl_arg {  #define UART_OVERRUN_ERROR		0x40  #define UART_CTS			0x80 -enum spcp8x5_type { -	SPCP825_007_TYPE, -	SPCP825_008_TYPE, -	SPCP825_PHILIP_TYPE, -	SPCP825_INTERMATIC_TYPE, -	SPCP835_TYPE, -}; -  struct spcp8x5_private { -	spinlock_t 	lock; -	enum spcp8x5_type	type; -	wait_queue_head_t	delta_msr_wait; -	u8 			line_control; -	u8 			line_status; +	unsigned		quirks; +	spinlock_t		lock; +	u8			line_control;  }; +static int spcp8x5_probe(struct usb_serial *serial, +						const struct usb_device_id *id) +{ +	usb_set_serial_data(serial, (void *)id); + +	return 0; +} +  static int spcp8x5_port_probe(struct usb_serial_port *port)  { -	struct usb_serial *serial = port->serial; +	const struct usb_device_id *id = usb_get_serial_data(port->serial);  	struct spcp8x5_private *priv; -	enum spcp8x5_type type = SPCP825_007_TYPE; -	u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); - -	if (product == 0x0201) -		type = SPCP825_007_TYPE; -	else if (product == 0x0231) -		type = SPCP835_TYPE; -	else if (product == 0x0235) -		type = SPCP825_008_TYPE; -	else if (product == 0x0204) -		type = SPCP825_INTERMATIC_TYPE; -	else if (product == 0x0471 && -		 serial->dev->descriptor.idVendor == cpu_to_le16(0x081e)) -		type = SPCP825_PHILIP_TYPE; -	dev_dbg(&serial->dev->dev, "device type = %d\n", (int)type);  	priv = kzalloc(sizeof(*priv), GFP_KERNEL);  	if (!priv)  		return -ENOMEM;  	spin_lock_init(&priv->lock); -	init_waitqueue_head(&priv->delta_msr_wait); -	priv->type = type; +	priv->quirks = id->driver_info; -	usb_set_serial_port_data(port , priv); +	usb_set_serial_port_data(port, priv);  	return 0;  } @@ -197,86 +182,79 @@ static int spcp8x5_port_remove(struct usb_serial_port *port)  	return 0;  } -/* set the modem control line of the device. - * NOTE spcp825-007 not supported this */ -static int spcp8x5_set_ctrlLine(struct usb_device *dev, u8 value, -				enum spcp8x5_type type) +static int spcp8x5_set_ctrl_line(struct usb_serial_port *port, u8 mcr)  { +	struct spcp8x5_private *priv = usb_get_serial_port_data(port); +	struct usb_device *dev = port->serial->dev;  	int retval; -	u8 mcr = 0 ; -	if (type == SPCP825_007_TYPE) +	if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS)  		return -EPERM; -	mcr = (unsigned short)value;  	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),  				 SET_UART_STATUS_TYPE, SET_UART_STATUS,  				 mcr, 0x04, NULL, 0, 100); -	if (retval != 0) -		dev_dbg(&dev->dev, "usb_control_msg return %#x\n", retval); +	if (retval != 0) { +		dev_err(&port->dev, "failed to set control lines: %d\n", +								retval); +	}  	return retval;  } -/* get the modem status register of the device - * NOTE spcp825-007 not supported this */ -static int spcp8x5_get_msr(struct usb_device *dev, u8 *status, -			   enum spcp8x5_type type) +static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status)  { -	u8 *status_buffer; +	struct spcp8x5_private *priv = usb_get_serial_port_data(port); +	struct usb_device *dev = port->serial->dev; +	u8 *buf;  	int ret; -	/* I return Permited not support here but seem inval device -	 * is more fix */ -	if (type == SPCP825_007_TYPE) +	if (priv->quirks & SPCP825_QUIRK_NO_UART_STATUS)  		return -EPERM; -	if (status == NULL) -		return -EINVAL; -	status_buffer = kmalloc(1, GFP_KERNEL); -	if (!status_buffer) +	buf = kzalloc(1, GFP_KERNEL); +	if (!buf)  		return -ENOMEM; -	status_buffer[0] = status[0];  	ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),  			      GET_UART_STATUS, GET_UART_STATUS_TYPE, -			      0, GET_UART_STATUS_MSR, status_buffer, 1, 100); +			      0, GET_UART_STATUS_MSR, buf, 1, 100);  	if (ret < 0) -		dev_dbg(&dev->dev, "Get MSR = 0x%p failed (error = %d)", -			status_buffer, ret); +		dev_err(&port->dev, "failed to get modem status: %d", ret); -	dev_dbg(&dev->dev, "0xc0:0x22:0:6  %d - 0x%p ", ret, status_buffer); -	status[0] = status_buffer[0]; -	kfree(status_buffer); +	dev_dbg(&port->dev, "0xc0:0x22:0:6  %d - 0x02%x", ret, *buf); +	*status = *buf; +	kfree(buf);  	return ret;  } -/* select the work mode. - * NOTE this function not supported by spcp825-007 */ -static void spcp8x5_set_workMode(struct usb_device *dev, u16 value, -				 u16 index, enum spcp8x5_type type) +static void spcp8x5_set_work_mode(struct usb_serial_port *port, u16 value, +								 u16 index)  { +	struct spcp8x5_private *priv = usb_get_serial_port_data(port); +	struct usb_device *dev = port->serial->dev;  	int ret; -	/* I return Permited not support here but seem inval device -	 * is more fix */ -	if (type == SPCP825_007_TYPE) +	if (priv->quirks & SPCP825_QUIRK_NO_WORK_MODE)  		return;  	ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),  			      SET_WORKING_MODE_TYPE, SET_WORKING_MODE,  			      value, index, NULL, 0, 100); -	dev_dbg(&dev->dev, "value = %#x , index = %#x\n", value, index); +	dev_dbg(&port->dev, "value = %#x , index = %#x\n", value, index);  	if (ret < 0) -		dev_dbg(&dev->dev, -			"RTSCTS usb_control_msg(enable flowctrl) = %d\n", ret); +		dev_err(&port->dev, "failed to set work mode: %d\n", ret);  }  static int spcp8x5_carrier_raised(struct usb_serial_port *port)  { -	struct spcp8x5_private *priv = usb_get_serial_port_data(port); -	if (priv->line_status & MSR_STATUS_LINE_DCD) +	u8 msr; +	int ret; + +	ret = spcp8x5_get_msr(port, &msr); +	if (ret || msr & MSR_STATUS_LINE_DCD)  		return 1; +  	return 0;  } @@ -295,20 +273,17 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on)  						| MCR_CONTROL_LINE_RTS);  	control = priv->line_control;  	spin_unlock_irqrestore(&priv->lock, flags); -	spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type); +	spcp8x5_set_ctrl_line(port, control);  }  static void spcp8x5_init_termios(struct tty_struct *tty)  { -	/* for the 1st time call this function */  	tty->termios = tty_std_termios;  	tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;  	tty->termios.c_ispeed = 115200;  	tty->termios.c_ospeed = 115200;  } -/* set the serial param for transfer. we should check if we really need to - * transfer. if we set flow control we should do this too. */  static void spcp8x5_set_termios(struct tty_struct *tty,  		struct usb_serial_port *port, struct ktermios *old_termios)  { @@ -323,7 +298,6 @@ static void spcp8x5_set_termios(struct tty_struct *tty,  	int i;  	u8 control; -  	/* check that they really want us to change something */  	if (!tty_termios_hw_change(&tty->termios, old_termios))  		return; @@ -339,7 +313,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,  	if (control != priv->line_control) {  		control = priv->line_control;  		spin_unlock_irqrestore(&priv->lock, flags); -		spcp8x5_set_ctrlLine(serial->dev, control , priv->type); +		spcp8x5_set_ctrl_line(port, control);  	} else {  		spin_unlock_irqrestore(&priv->lock, flags);  	} @@ -399,9 +373,9 @@ static void spcp8x5_set_termios(struct tty_struct *tty,  	if (cflag & PARENB) {  		buf[1] |= (cflag & PARODD) ?  		SET_UART_FORMAT_PAR_ODD : SET_UART_FORMAT_PAR_EVEN ; -	} else +	} else {  		buf[1] |= SET_UART_FORMAT_PAR_NONE; - +	}  	uartdata = buf[0] | buf[1]<<8;  	i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), @@ -414,22 +388,16 @@ static void spcp8x5_set_termios(struct tty_struct *tty,  	if (cflag & CRTSCTS) {  		/* enable hardware flow control */ -		spcp8x5_set_workMode(serial->dev, 0x000a, -				     SET_WORKING_MODE_U2C, priv->type); +		spcp8x5_set_work_mode(port, 0x000a, SET_WORKING_MODE_U2C);  	}  } -/* open the serial port. do some usb system call. set termios and get the line - * status of the device. */  static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)  {  	struct ktermios tmp_termios;  	struct usb_serial *serial = port->serial;  	struct spcp8x5_private *priv = usb_get_serial_port_data(port);  	int ret; -	unsigned long flags; -	u8 status = 0x30; -	/* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */  	usb_clear_halt(serial->dev, port->write_urb->pipe);  	usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -440,139 +408,16 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port)  	if (ret)  		return ret; -	spcp8x5_set_ctrlLine(serial->dev, priv->line_control , priv->type); +	spcp8x5_set_ctrl_line(port, priv->line_control); -	/* Setup termios */  	if (tty)  		spcp8x5_set_termios(tty, port, &tmp_termios); -	spcp8x5_get_msr(serial->dev, &status, priv->type); - -	/* may be we should update uart status here but now we did not do */ -	spin_lock_irqsave(&priv->lock, flags); -	priv->line_status = status & 0xf0 ; -	spin_unlock_irqrestore(&priv->lock, flags); -  	port->port.drain_delay = 256;  	return usb_serial_generic_open(tty, port);  } -static void spcp8x5_process_read_urb(struct urb *urb) -{ -	struct usb_serial_port *port = urb->context; -	struct spcp8x5_private *priv = usb_get_serial_port_data(port); -	unsigned char *data = urb->transfer_buffer; -	unsigned long flags; -	u8 status; -	char tty_flag; - -	/* get tty_flag from status */ -	tty_flag = TTY_NORMAL; - -	spin_lock_irqsave(&priv->lock, flags); -	status = priv->line_status; -	priv->line_status &= ~UART_STATE_TRANSIENT_MASK; -	spin_unlock_irqrestore(&priv->lock, flags); -	/* wake up the wait for termios */ -	wake_up_interruptible(&priv->delta_msr_wait); - -	if (!urb->actual_length) -		return; - - -	if (status & UART_STATE_TRANSIENT_MASK) { -		/* break takes precedence over parity, which takes precedence -		 * over framing errors */ -		if (status & UART_BREAK_ERROR) -			tty_flag = TTY_BREAK; -		else if (status & UART_PARITY_ERROR) -			tty_flag = TTY_PARITY; -		else if (status & UART_FRAME_ERROR) -			tty_flag = TTY_FRAME; -		dev_dbg(&port->dev, "tty_flag = %d\n", tty_flag); - -		/* overrun is special, not associated with a char */ -		if (status & UART_OVERRUN_ERROR) -			tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); - -		if (status & UART_DCD) { -			struct tty_struct *tty = tty_port_tty_get(&port->port); -			if (tty) { -				usb_serial_handle_dcd_change(port, tty, -				       priv->line_status & MSR_STATUS_LINE_DCD); -				tty_kref_put(tty); -			} -		} -	} - -	tty_insert_flip_string_fixed_flag(&port->port, data, tty_flag, -							urb->actual_length); -	tty_flip_buffer_push(&port->port); -} - -static int spcp8x5_wait_modem_info(struct usb_serial_port *port, -				   unsigned int arg) -{ -	struct spcp8x5_private *priv = usb_get_serial_port_data(port); -	unsigned long flags; -	unsigned int prevstatus; -	unsigned int status; -	unsigned int changed; - -	spin_lock_irqsave(&priv->lock, flags); -	prevstatus = priv->line_status; -	spin_unlock_irqrestore(&priv->lock, flags); - -	while (1) { -		/* wake up in bulk read */ -		interruptible_sleep_on(&priv->delta_msr_wait); - -		/* see if a signal did it */ -		if (signal_pending(current)) -			return -ERESTARTSYS; - -		spin_lock_irqsave(&priv->lock, flags); -		status = priv->line_status; -		spin_unlock_irqrestore(&priv->lock, flags); - -		changed = prevstatus^status; - -		if (((arg & TIOCM_RNG) && (changed & MSR_STATUS_LINE_RI)) || -		    ((arg & TIOCM_DSR) && (changed & MSR_STATUS_LINE_DSR)) || -		    ((arg & TIOCM_CD)  && (changed & MSR_STATUS_LINE_DCD)) || -		    ((arg & TIOCM_CTS) && (changed & MSR_STATUS_LINE_CTS))) -			return 0; - -		prevstatus = status; -	} -	/* NOTREACHED */ -	return 0; -} - -static int spcp8x5_ioctl(struct tty_struct *tty, -			 unsigned int cmd, unsigned long arg) -{ -	struct usb_serial_port *port = tty->driver_data; - -	dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, -		port->number, cmd); - -	switch (cmd) { -	case TIOCMIWAIT: -		dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, -			port->number); -		return spcp8x5_wait_modem_info(port, arg); - -	default: -		dev_dbg(&port->dev, "%s not supported = 0x%04x", __func__, -			cmd); -		break; -	} - -	return -ENOIOCTLCMD; -} -  static int spcp8x5_tiocmset(struct tty_struct *tty,  			    unsigned int set, unsigned int clear)  { @@ -593,7 +438,7 @@ static int spcp8x5_tiocmset(struct tty_struct *tty,  	control = priv->line_control;  	spin_unlock_irqrestore(&priv->lock, flags); -	return spcp8x5_set_ctrlLine(port->serial->dev, control , priv->type); +	return spcp8x5_set_ctrl_line(port, control);  }  static int spcp8x5_tiocmget(struct tty_struct *tty) @@ -602,12 +447,15 @@ static int spcp8x5_tiocmget(struct tty_struct *tty)  	struct spcp8x5_private *priv = usb_get_serial_port_data(port);  	unsigned long flags;  	unsigned int mcr; -	unsigned int status; +	u8 status;  	unsigned int result; +	result = spcp8x5_get_msr(port, &status); +	if (result) +		return result; +  	spin_lock_irqsave(&priv->lock, flags);  	mcr = priv->line_control; -	status = priv->line_status;  	spin_unlock_irqrestore(&priv->lock, flags);  	result = ((mcr & MCR_DTR)			? TIOCM_DTR : 0) @@ -620,7 +468,6 @@ static int spcp8x5_tiocmget(struct tty_struct *tty)  	return result;  } -/* All of the device info needed for the spcp8x5 SIO serial converter */  static struct usb_serial_driver spcp8x5_device = {  	.driver = {  		.owner =	THIS_MODULE, @@ -628,17 +475,16 @@ static struct usb_serial_driver spcp8x5_device = {  	},  	.id_table		= id_table,  	.num_ports		= 1, -	.open 			= spcp8x5_open, +	.open			= spcp8x5_open,  	.dtr_rts		= spcp8x5_dtr_rts,  	.carrier_raised		= spcp8x5_carrier_raised, -	.set_termios 		= spcp8x5_set_termios, +	.set_termios		= spcp8x5_set_termios,  	.init_termios		= spcp8x5_init_termios, -	.ioctl 			= spcp8x5_ioctl, -	.tiocmget 		= spcp8x5_tiocmget, -	.tiocmset 		= spcp8x5_tiocmset, +	.tiocmget		= spcp8x5_tiocmget, +	.tiocmset		= spcp8x5_tiocmset, +	.probe			= spcp8x5_probe,  	.port_probe		= spcp8x5_port_probe,  	.port_remove		= spcp8x5_port_remove, -	.process_read_urb	= spcp8x5_process_read_urb,  };  static struct usb_serial_driver * const serial_drivers[] = { diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index b57cf841c5b..5b62dbbdf99 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -61,8 +61,6 @@ struct ssu100_port_private {  	spinlock_t status_lock;  	u8 shadowLSR;  	u8 shadowMSR; -	wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ -	struct async_icount icount;  };  static inline int ssu100_control_msg(struct usb_device *dev, @@ -316,11 +314,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)  	return usb_serial_generic_open(tty, port);  } -static void ssu100_close(struct usb_serial_port *port) -{ -	usb_serial_generic_close(port); -} -  static int get_serial_info(struct usb_serial_port *port,  			   struct serial_struct __user *retinfo)  { @@ -344,69 +337,6 @@ static int get_serial_info(struct usb_serial_port *port,  	return 0;  } -static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) -{ -	struct ssu100_port_private *priv = usb_get_serial_port_data(port); -	struct async_icount prev, cur; -	unsigned long flags; - -	spin_lock_irqsave(&priv->status_lock, flags); -	prev = priv->icount; -	spin_unlock_irqrestore(&priv->status_lock, flags); - -	while (1) { -		wait_event_interruptible(priv->delta_msr_wait, -					 ((priv->icount.rng != prev.rng) || -					  (priv->icount.dsr != prev.dsr) || -					  (priv->icount.dcd != prev.dcd) || -					  (priv->icount.cts != prev.cts))); - -		if (signal_pending(current)) -			return -ERESTARTSYS; - -		spin_lock_irqsave(&priv->status_lock, flags); -		cur = priv->icount; -		spin_unlock_irqrestore(&priv->status_lock, flags); - -		if ((prev.rng == cur.rng) && -		    (prev.dsr == cur.dsr) && -		    (prev.dcd == cur.dcd) && -		    (prev.cts == cur.cts)) -			return -EIO; - -		if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) || -		    (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) || -		    (arg & TIOCM_CD  && (prev.dcd != cur.dcd)) || -		    (arg & TIOCM_CTS && (prev.cts != cur.cts))) -			return 0; -	} -	return 0; -} - -static int ssu100_get_icount(struct tty_struct *tty, -			struct serial_icounter_struct *icount) -{ -	struct usb_serial_port *port = tty->driver_data; -	struct ssu100_port_private *priv = usb_get_serial_port_data(port); -	struct async_icount cnow = priv->icount; - -	icount->cts = cnow.cts; -	icount->dsr = cnow.dsr; -	icount->rng = cnow.rng; -	icount->dcd = cnow.dcd; -	icount->rx = cnow.rx; -	icount->tx = cnow.tx; -	icount->frame = cnow.frame; -	icount->overrun = cnow.overrun; -	icount->parity = cnow.parity; -	icount->brk = cnow.brk; -	icount->buf_overrun = cnow.buf_overrun; - -	return 0; -} - - -  static int ssu100_ioctl(struct tty_struct *tty,  		    unsigned int cmd, unsigned long arg)  { @@ -418,10 +348,6 @@ static int ssu100_ioctl(struct tty_struct *tty,  	case TIOCGSERIAL:  		return get_serial_info(port,  				       (struct serial_struct __user *) arg); - -	case TIOCMIWAIT: -		return wait_modem_info(port, arg); -  	default:  		break;  	} @@ -445,7 +371,6 @@ static int ssu100_port_probe(struct usb_serial_port *port)  		return -ENOMEM;  	spin_lock_init(&priv->status_lock); -	init_waitqueue_head(&priv->delta_msr_wait);  	usb_set_serial_port_data(port, priv); @@ -530,14 +455,14 @@ static void ssu100_update_msr(struct usb_serial_port *port, u8 msr)  	if (msr & UART_MSR_ANY_DELTA) {  		/* update input line counters */  		if (msr & UART_MSR_DCTS) -			priv->icount.cts++; +			port->icount.cts++;  		if (msr & UART_MSR_DDSR) -			priv->icount.dsr++; +			port->icount.dsr++;  		if (msr & UART_MSR_DDCD) -			priv->icount.dcd++; +			port->icount.dcd++;  		if (msr & UART_MSR_TERI) -			priv->icount.rng++; -		wake_up_interruptible(&priv->delta_msr_wait); +			port->icount.rng++; +		wake_up_interruptible(&port->port.delta_msr_wait);  	}  } @@ -556,22 +481,22 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr,  		/* we always want to update icount, but we only want to  		 * update tty_flag for one case */  		if (lsr & UART_LSR_BI) { -			priv->icount.brk++; +			port->icount.brk++;  			*tty_flag = TTY_BREAK;  			usb_serial_handle_break(port);  		}  		if (lsr & UART_LSR_PE) { -			priv->icount.parity++; +			port->icount.parity++;  			if (*tty_flag == TTY_NORMAL)  				*tty_flag = TTY_PARITY;  		}  		if (lsr & UART_LSR_FE) { -			priv->icount.frame++; +			port->icount.frame++;  			if (*tty_flag == TTY_NORMAL)  				*tty_flag = TTY_FRAME;  		}  		if (lsr & UART_LSR_OE){ -			priv->icount.overrun++; +			port->icount.overrun++;  			if (*tty_flag == TTY_NORMAL)  				*tty_flag = TTY_OVERRUN;  		} @@ -628,7 +553,6 @@ static struct usb_serial_driver ssu100_device = {  	.id_table	     = id_table,  	.num_ports	     = 1,  	.open		     = ssu100_open, -	.close		     = ssu100_close,  	.attach              = ssu100_attach,  	.port_probe          = ssu100_port_probe,  	.port_remove         = ssu100_port_remove, @@ -636,10 +560,10 @@ static struct usb_serial_driver ssu100_device = {  	.process_read_urb    = ssu100_process_read_urb,  	.tiocmget            = ssu100_tiocmget,  	.tiocmset            = ssu100_tiocmset, -	.get_icount	     = ssu100_get_icount, +	.tiocmiwait          = usb_serial_generic_tiocmiwait, +	.get_icount	     = usb_serial_generic_get_icount,  	.ioctl               = ssu100_ioctl,  	.set_termios         = ssu100_set_termios, -	.disconnect          = usb_serial_generic_disconnect,  };  static struct usb_serial_driver * const serial_drivers[] = { diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 39cb9b807c3..07268591b0d 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -73,8 +73,6 @@ struct ti_port {  	unsigned int		tp_uart_base_addr;  	int			tp_flags;  	int			tp_closing_wait;/* in .01 secs */ -	struct async_icount	tp_icount; -	wait_queue_head_t	tp_msr_wait;	/* wait for msr change */  	wait_queue_head_t	tp_write_wait;  	struct ti_device	*tp_tdev;  	struct usb_serial_port	*tp_port; @@ -109,8 +107,6 @@ static void ti_throttle(struct tty_struct *tty);  static void ti_unthrottle(struct tty_struct *tty);  static int ti_ioctl(struct tty_struct *tty,  		unsigned int cmd, unsigned long arg); -static int ti_get_icount(struct tty_struct *tty, -		struct serial_icounter_struct *icount);  static void ti_set_termios(struct tty_struct *tty,  		struct usb_serial_port *port, struct ktermios *old_termios);  static int ti_tiocmget(struct tty_struct *tty); @@ -236,7 +232,8 @@ static struct usb_serial_driver ti_1port_device = {  	.set_termios		= ti_set_termios,  	.tiocmget		= ti_tiocmget,  	.tiocmset		= ti_tiocmset, -	.get_icount		= ti_get_icount, +	.tiocmiwait		= usb_serial_generic_tiocmiwait, +	.get_icount		= usb_serial_generic_get_icount,  	.break_ctl		= ti_break,  	.read_int_callback	= ti_interrupt_callback,  	.read_bulk_callback	= ti_bulk_in_callback, @@ -266,7 +263,8 @@ static struct usb_serial_driver ti_2port_device = {  	.set_termios		= ti_set_termios,  	.tiocmget		= ti_tiocmget,  	.tiocmset		= ti_tiocmset, -	.get_icount		= ti_get_icount, +	.tiocmiwait		= usb_serial_generic_tiocmiwait, +	.get_icount		= usb_serial_generic_get_icount,  	.break_ctl		= ti_break,  	.read_int_callback	= ti_interrupt_callback,  	.read_bulk_callback	= ti_bulk_in_callback, @@ -432,7 +430,6 @@ static int ti_port_probe(struct usb_serial_port *port)  	else  		tport->tp_uart_base_addr = TI_UART2_BASE_ADDR;  	tport->tp_closing_wait = closing_wait; -	init_waitqueue_head(&tport->tp_msr_wait);  	init_waitqueue_head(&tport->tp_write_wait);  	if (kfifo_alloc(&tport->write_fifo, TI_WRITE_BUF_SIZE, GFP_KERNEL)) {  		kfree(tport); @@ -482,8 +479,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)  	port_number = port->number - port->serial->minor; -	memset(&(tport->tp_icount), 0x00, sizeof(tport->tp_icount)); -  	tport->tp_msr = 0;  	tport->tp_shadow_mcr |= (TI_MCR_RTS | TI_MCR_DTR); @@ -733,38 +728,11 @@ static void ti_unthrottle(struct tty_struct *tty)  	}  } -static int ti_get_icount(struct tty_struct *tty, -		struct serial_icounter_struct *icount) -{ -	struct usb_serial_port *port = tty->driver_data; -	struct ti_port *tport = usb_get_serial_port_data(port); -	struct async_icount cnow = tport->tp_icount; - -	dev_dbg(&port->dev, "%s - TIOCGICOUNT RX=%d, TX=%d\n", __func__, -		cnow.rx, cnow.tx); - -	icount->cts = cnow.cts; -	icount->dsr = cnow.dsr; -	icount->rng = cnow.rng; -	icount->dcd = cnow.dcd; -	icount->rx = cnow.rx; -	icount->tx = cnow.tx; -	icount->frame = cnow.frame; -	icount->overrun = cnow.overrun; -	icount->parity = cnow.parity; -	icount->brk = cnow.brk; -	icount->buf_overrun = cnow.buf_overrun; - -	return 0; -} -  static int ti_ioctl(struct tty_struct *tty,  	unsigned int cmd, unsigned long arg)  {  	struct usb_serial_port *port = tty->driver_data;  	struct ti_port *tport = usb_get_serial_port_data(port); -	struct async_icount cnow; -	struct async_icount cprev;  	dev_dbg(&port->dev, "%s - cmd = 0x%04X\n", __func__, cmd); @@ -780,25 +748,6 @@ static int ti_ioctl(struct tty_struct *tty,  		dev_dbg(&port->dev, "%s - TIOCSSERIAL\n", __func__);  		return ti_set_serial_info(tty, tport,  				(struct serial_struct __user *)arg); -	case TIOCMIWAIT: -		dev_dbg(&port->dev, "%s - TIOCMIWAIT\n", __func__); -		cprev = tport->tp_icount; -		while (1) { -			interruptible_sleep_on(&tport->tp_msr_wait); -			if (signal_pending(current)) -				return -ERESTARTSYS; -			cnow = tport->tp_icount; -			if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && -			    cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) -				return -EIO; /* no change => error */ -			if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || -			    ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || -			    ((arg & TIOCM_CD)  && (cnow.dcd != cprev.dcd)) || -			    ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) -				return 0; -			cprev = cnow; -		} -		break;  	}  	return -ENOIOCTLCMD;  } @@ -1154,7 +1103,7 @@ static void ti_bulk_in_callback(struct urb *urb)  		else  			ti_recv(port, urb->transfer_buffer, urb->actual_length);  		spin_lock(&tport->tp_lock); -		tport->tp_icount.rx += urb->actual_length; +		port->icount.rx += urb->actual_length;  		spin_unlock(&tport->tp_lock);  	} @@ -1263,7 +1212,7 @@ static void ti_send(struct ti_port *tport)  		/* TODO: reschedule ti_send */  	} else {  		spin_lock_irqsave(&tport->tp_lock, flags); -		tport->tp_icount.tx += count; +		port->icount.tx += count;  		spin_unlock_irqrestore(&tport->tp_lock, flags);  	} @@ -1383,7 +1332,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)  	if (msr & TI_MSR_DELTA_MASK) {  		spin_lock_irqsave(&tport->tp_lock, flags); -		icount = &tport->tp_icount; +		icount = &tport->tp_port->icount;  		if (msr & TI_MSR_DELTA_CTS)  			icount->cts++;  		if (msr & TI_MSR_DELTA_DSR) @@ -1392,7 +1341,7 @@ static void ti_handle_new_msr(struct ti_port *tport, __u8 msr)  			icount->dcd++;  		if (msr & TI_MSR_DELTA_RI)  			icount->rng++; -		wake_up_interruptible(&tport->tp_msr_wait); +		wake_up_interruptible(&tport->tp_port->port.delta_msr_wait);  		spin_unlock_irqrestore(&tport->tp_lock, flags);  	} diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index a19ed74d770..5eb96df8de0 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1,6 +1,7 @@  /*   * USB Serial Converter driver   * + * Copyright (C) 2009 - 2013 Johan Hovold (jhovold@gmail.com)   * Copyright (C) 1999 - 2012 Greg Kroah-Hartman (greg@kroah.com)   * Copyright (C) 2000 Peter Berger (pberger@brimson.com)   * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com) @@ -14,7 +15,6 @@   *   * See Documentation/usb/usb-serial.txt for more information on using this   * driver - *   */  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -49,7 +49,6 @@     drivers depend on it.  */ -/* initially all NULL */  static struct usb_serial *serial_table[SERIAL_TTY_MINORS];  static DEFINE_MUTEX(table_lock);  static LIST_HEAD(usb_serial_driver_list); @@ -139,7 +138,7 @@ static void destroy_serial(struct kref *kref)  	if (serial->minor != SERIAL_TTY_NO_MINOR)  		return_serial(serial); -	if (serial->attached) +	if (serial->attached && serial->type->release)  		serial->type->release(serial);  	/* Now that nothing is using the ports, they can be freed */ @@ -151,6 +150,7 @@ static void destroy_serial(struct kref *kref)  		}  	} +	usb_put_intf(serial->interface);  	usb_put_dev(serial->dev);  	kfree(serial);  } @@ -224,7 +224,7 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)  	return retval;  } -static int serial_activate(struct tty_port *tport, struct tty_struct *tty) +static int serial_port_activate(struct tty_port *tport, struct tty_struct *tty)  {  	struct usb_serial_port *port =  		container_of(tport, struct usb_serial_port, port); @@ -248,30 +248,27 @@ static int serial_open(struct tty_struct *tty, struct file *filp)  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); +	dev_dbg(tty->dev, "%s\n", __func__); +  	return tty_port_open(&port->port, tty, filp);  }  /** - * serial_down - shut down hardware + * serial_port_shutdown - shut down hardware   * @tport: tty port to shut down   * - * Shut down a USB serial port unless it is the console.  We never - * shut down the console hardware as it will always be in use. Serialized - * against activate by the tport mutex and kept to matching open/close pairs + * Shut down a USB serial port. Serialized against activate by the + * tport mutex and kept to matching open/close pairs   * of calls by the ASYNCB_INITIALIZED flag. + * + * Not called if tty is console.   */ -static void serial_down(struct tty_port *tport) +static void serial_port_shutdown(struct tty_port *tport)  {  	struct usb_serial_port *port =  		container_of(tport, struct usb_serial_port, port);  	struct usb_serial_driver *drv = port->serial->type; -	/* -	 * The console is magical.  Do not hang up the console hardware -	 * or there will be tears. -	 */ -	if (port->port.console) -		return; +  	if (drv->close)  		drv->close(port);  } @@ -280,7 +277,8 @@ static void serial_hangup(struct tty_struct *tty)  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); +	dev_dbg(tty->dev, "%s\n", __func__); +  	tty_port_hangup(&port->port);  } @@ -288,7 +286,8 @@ static void serial_close(struct tty_struct *tty, struct file *filp)  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); +	dev_dbg(tty->dev, "%s\n", __func__); +  	tty_port_close(&port->port, tty, filp);  } @@ -307,14 +306,14 @@ static void serial_cleanup(struct tty_struct *tty)  	struct usb_serial *serial;  	struct module *owner; +	dev_dbg(tty->dev, "%s\n", __func__); +  	/* The console is magical.  Do not hang up the console hardware  	 * or there will be tears.  	 */  	if (port->port.console)  		return; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); -  	tty->driver_data = NULL;  	serial = port->serial; @@ -338,10 +337,8 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf,  	if (port->serial->dev->state == USB_STATE_NOTATTACHED)  		goto exit; -	dev_dbg(tty->dev, "%s - port %d, %d byte(s)\n", __func__, -		port->number, count); +	dev_dbg(tty->dev, "%s - %d byte(s)\n", __func__, count); -	/* pass on to the driver specific version of this function */  	retval = port->serial->type->write(tty, port, buf, count);  	if (retval < 0)  		retval = usb_translate_errors(retval); @@ -353,8 +350,8 @@ static int serial_write_room(struct tty_struct *tty)  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); -	/* pass on to the driver specific version of this function */ +	dev_dbg(tty->dev, "%s\n", __func__); +  	return port->serial->type->write_room(tty);  } @@ -364,7 +361,7 @@ static int serial_chars_in_buffer(struct tty_struct *tty)  	struct usb_serial *serial = port->serial;  	int count = 0; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); +	dev_dbg(tty->dev, "%s\n", __func__);  	mutex_lock(&serial->disc_mutex);  	/* if the device was unplugged then any remaining characters @@ -382,9 +379,8 @@ static void serial_throttle(struct tty_struct *tty)  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); +	dev_dbg(tty->dev, "%s\n", __func__); -	/* pass on to the driver specific version of this function */  	if (port->serial->type->throttle)  		port->serial->type->throttle(tty);  } @@ -393,9 +389,8 @@ static void serial_unthrottle(struct tty_struct *tty)  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); +	dev_dbg(tty->dev, "%s\n", __func__); -	/* pass on to the driver specific version of this function */  	if (port->serial->type->unthrottle)  		port->serial->type->unthrottle(tty);  } @@ -406,15 +401,20 @@ static int serial_ioctl(struct tty_struct *tty,  	struct usb_serial_port *port = tty->driver_data;  	int retval = -ENODEV; -	dev_dbg(tty->dev, "%s - port %d, cmd 0x%.4x\n", __func__, -		port->number, cmd); +	dev_dbg(tty->dev, "%s - cmd 0x%.4x\n", __func__, cmd); + +	switch (cmd) { +	case TIOCMIWAIT: +		if (port->serial->type->tiocmiwait) +			retval = port->serial->type->tiocmiwait(tty, arg); +		break; +	default: +		if (port->serial->type->ioctl) +			retval = port->serial->type->ioctl(tty, cmd, arg); +		else +			retval = -ENOIOCTLCMD; +	} -	/* pass on to the driver specific version of this function -	   if it is available */ -	if (port->serial->type->ioctl) { -		retval = port->serial->type->ioctl(tty, cmd, arg); -	} else -		retval = -ENOIOCTLCMD;  	return retval;  } @@ -422,10 +422,8 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); +	dev_dbg(tty->dev, "%s\n", __func__); -	/* pass on to the driver specific version of this function -	   if it is available */  	if (port->serial->type->set_termios)  		port->serial->type->set_termios(tty, port, old);  	else @@ -436,12 +434,11 @@ static int serial_break(struct tty_struct *tty, int break_state)  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); +	dev_dbg(tty->dev, "%s\n", __func__); -	/* pass on to the driver specific version of this function -	   if it is available */  	if (port->serial->type->break_ctl)  		port->serial->type->break_ctl(tty, break_state); +  	return 0;  } @@ -495,7 +492,7 @@ static int serial_tiocmget(struct tty_struct *tty)  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); +	dev_dbg(tty->dev, "%s\n", __func__);  	if (port->serial->type->tiocmget)  		return port->serial->type->tiocmget(tty); @@ -507,7 +504,7 @@ static int serial_tiocmset(struct tty_struct *tty,  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); +	dev_dbg(tty->dev, "%s\n", __func__);  	if (port->serial->type->tiocmset)  		return port->serial->type->tiocmset(tty, set, clear); @@ -519,7 +516,7 @@ static int serial_get_icount(struct tty_struct *tty,  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); +	dev_dbg(tty->dev, "%s\n", __func__);  	if (port->serial->type->get_icount)  		return port->serial->type->get_icount(tty, icount); @@ -547,49 +544,45 @@ static void usb_serial_port_work(struct work_struct *work)  	if (!tty)  		return; -	dev_dbg(tty->dev, "%s - port %d\n", __func__, port->number); +	dev_dbg(tty->dev, "%s\n", __func__);  	tty_wakeup(tty);  	tty_kref_put(tty);  } -static void kill_traffic(struct usb_serial_port *port) +static void usb_serial_port_poison_urbs(struct usb_serial_port *port)  {  	int i;  	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) -		usb_kill_urb(port->read_urbs[i]); +		usb_poison_urb(port->read_urbs[i]);  	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) -		usb_kill_urb(port->write_urbs[i]); -	/* -	 * This is tricky. -	 * Some drivers submit the read_urb in the -	 * handler for the write_urb or vice versa -	 * this order determines the order in which -	 * usb_kill_urb() must be used to reliably -	 * kill the URBs. As it is unknown here, -	 * both orders must be used in turn. -	 * The call below is not redundant. -	 */ -	usb_kill_urb(port->read_urb); -	usb_kill_urb(port->interrupt_in_urb); -	usb_kill_urb(port->interrupt_out_urb); +		usb_poison_urb(port->write_urbs[i]); + +	usb_poison_urb(port->interrupt_in_urb); +	usb_poison_urb(port->interrupt_out_urb);  } -static void port_release(struct device *dev) +static void usb_serial_port_unpoison_urbs(struct usb_serial_port *port) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) +		usb_unpoison_urb(port->read_urbs[i]); +	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) +		usb_unpoison_urb(port->write_urbs[i]); + +	usb_unpoison_urb(port->interrupt_in_urb); +	usb_unpoison_urb(port->interrupt_out_urb); +} + +static void usb_serial_port_release(struct device *dev)  {  	struct usb_serial_port *port = to_usb_serial_port(dev);  	int i;  	dev_dbg(dev, "%s\n", __func__); -	/* -	 * Stop all the traffic before cancelling the work, so that -	 * nobody will restart it by calling usb_serial_port_softint. -	 */ -	kill_traffic(port); -	cancel_work_sync(&port->work); -  	usb_free_urb(port->interrupt_in_urb);  	usb_free_urb(port->interrupt_out_urb);  	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { @@ -614,13 +607,11 @@ static struct usb_serial *create_serial(struct usb_device *dev,  	struct usb_serial *serial;  	serial = kzalloc(sizeof(*serial), GFP_KERNEL); -	if (!serial) { -		dev_err(&dev->dev, "%s - out of memory\n", __func__); +	if (!serial)  		return NULL; -	}  	serial->dev = usb_get_dev(dev);  	serial->type = driver; -	serial->interface = interface; +	serial->interface = usb_get_intf(interface);  	kref_init(&serial->kref);  	mutex_init(&serial->disc_mutex);  	serial->minor = SERIAL_TTY_NO_MINOR; @@ -680,7 +671,7 @@ static struct usb_serial_driver *search_serial_device(  	return NULL;  } -static int serial_carrier_raised(struct tty_port *port) +static int serial_port_carrier_raised(struct tty_port *port)  {  	struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);  	struct usb_serial_driver *drv = p->serial->type; @@ -691,7 +682,7 @@ static int serial_carrier_raised(struct tty_port *port)  	return 1;  } -static void serial_dtr_rts(struct tty_port *port, int on) +static void serial_port_dtr_rts(struct tty_port *port, int on)  {  	struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);  	struct usb_serial *serial = p->serial; @@ -711,10 +702,10 @@ static void serial_dtr_rts(struct tty_port *port, int on)  }  static const struct tty_port_operations serial_port_ops = { -	.carrier_raised = serial_carrier_raised, -	.dtr_rts = serial_dtr_rts, -	.activate = serial_activate, -	.shutdown = serial_down, +	.carrier_raised		= serial_port_carrier_raised, +	.dtr_rts		= serial_port_dtr_rts, +	.activate		= serial_port_activate, +	.shutdown		= serial_port_shutdown,  };  static int usb_serial_probe(struct usb_interface *interface, @@ -761,7 +752,6 @@ static int usb_serial_probe(struct usb_interface *interface,  	serial = create_serial(dev, interface, type);  	if (!serial) {  		module_put(type->driver.owner); -		dev_err(ddev, "%s - out of memory\n", __func__);  		return -ENOMEM;  	} @@ -909,7 +899,7 @@ static int usb_serial_probe(struct usb_interface *interface,  		port->dev.parent = &interface->dev;  		port->dev.driver = NULL;  		port->dev.bus = &usb_serial_bus_type; -		port->dev.release = &port_release; +		port->dev.release = &usb_serial_port_release;  		device_initialize(&port->dev);  	} @@ -925,16 +915,12 @@ static int usb_serial_probe(struct usb_interface *interface,  		for (j = 0; j < ARRAY_SIZE(port->read_urbs); ++j) {  			set_bit(j, &port->read_urbs_free);  			port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); -			if (!port->read_urbs[j]) { -				dev_err(ddev, "No free urbs available\n"); +			if (!port->read_urbs[j])  				goto probe_error; -			}  			port->bulk_in_buffers[j] = kmalloc(buffer_size,  								GFP_KERNEL); -			if (!port->bulk_in_buffers[j]) { -				dev_err(ddev, "Couldn't allocate bulk_in_buffer\n"); +			if (!port->bulk_in_buffers[j])  				goto probe_error; -			}  			usb_fill_bulk_urb(port->read_urbs[j], dev,  					usb_rcvbulkpipe(dev,  						endpoint->bEndpointAddress), @@ -961,16 +947,12 @@ static int usb_serial_probe(struct usb_interface *interface,  		for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) {  			set_bit(j, &port->write_urbs_free);  			port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); -			if (!port->write_urbs[j]) { -				dev_err(ddev, "No free urbs available\n"); +			if (!port->write_urbs[j])  				goto probe_error; -			}  			port->bulk_out_buffers[j] = kmalloc(buffer_size,  								GFP_KERNEL); -			if (!port->bulk_out_buffers[j]) { -				dev_err(ddev, "Couldn't allocate bulk_out_buffer\n"); +			if (!port->bulk_out_buffers[j])  				goto probe_error; -			}  			usb_fill_bulk_urb(port->write_urbs[j], dev,  					usb_sndbulkpipe(dev,  						endpoint->bEndpointAddress), @@ -988,19 +970,15 @@ static int usb_serial_probe(struct usb_interface *interface,  			endpoint = interrupt_in_endpoint[i];  			port = serial->port[i];  			port->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); -			if (!port->interrupt_in_urb) { -				dev_err(ddev, "No free urbs available\n"); +			if (!port->interrupt_in_urb)  				goto probe_error; -			}  			buffer_size = usb_endpoint_maxp(endpoint);  			port->interrupt_in_endpointAddress =  						endpoint->bEndpointAddress;  			port->interrupt_in_buffer = kmalloc(buffer_size,  								GFP_KERNEL); -			if (!port->interrupt_in_buffer) { -				dev_err(ddev, "Couldn't allocate interrupt_in_buffer\n"); +			if (!port->interrupt_in_buffer)  				goto probe_error; -			}  			usb_fill_int_urb(port->interrupt_in_urb, dev,  				usb_rcvintpipe(dev,  						endpoint->bEndpointAddress), @@ -1017,20 +995,16 @@ static int usb_serial_probe(struct usb_interface *interface,  			endpoint = interrupt_out_endpoint[i];  			port = serial->port[i];  			port->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); -			if (!port->interrupt_out_urb) { -				dev_err(ddev, "No free urbs available\n"); +			if (!port->interrupt_out_urb)  				goto probe_error; -			}  			buffer_size = usb_endpoint_maxp(endpoint);  			port->interrupt_out_size = buffer_size;  			port->interrupt_out_endpointAddress =  						endpoint->bEndpointAddress;  			port->interrupt_out_buffer = kmalloc(buffer_size,  								GFP_KERNEL); -			if (!port->interrupt_out_buffer) { -				dev_err(ddev, "Couldn't allocate interrupt_out_buffer\n"); +			if (!port->interrupt_out_buffer)  				goto probe_error; -			}  			usb_fill_int_urb(port->interrupt_out_urb, dev,  				usb_sndintpipe(dev,  						  endpoint->bEndpointAddress), @@ -1119,13 +1093,15 @@ static void usb_serial_disconnect(struct usb_interface *interface)  				tty_vhangup(tty);  				tty_kref_put(tty);  			} -			kill_traffic(port); +			usb_serial_port_poison_urbs(port); +			wake_up_interruptible(&port->port.delta_msr_wait);  			cancel_work_sync(&port->work);  			if (device_is_registered(&port->dev))  				device_del(&port->dev);  		}  	} -	serial->type->disconnect(serial); +	if (serial->type->disconnect) +		serial->type->disconnect(serial);  	/* let the last holder of this object cause it to be cleaned up */  	usb_serial_put(serial); @@ -1140,6 +1116,11 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)  	serial->suspending = 1; +	/* +	 * serial->type->suspend() MUST return 0 in system sleep context, +	 * otherwise, the resume callback has to recover device from +	 * previous suspend failure. +	 */  	if (serial->type->suspend) {  		r = serial->type->suspend(serial, message);  		if (r < 0) { @@ -1151,7 +1132,7 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)  	for (i = 0; i < serial->num_ports; ++i) {  		port = serial->port[i];  		if (port) -			kill_traffic(port); +			usb_serial_port_poison_urbs(port);  	}  err_out: @@ -1159,11 +1140,25 @@ err_out:  }  EXPORT_SYMBOL(usb_serial_suspend); +static void usb_serial_unpoison_port_urbs(struct usb_serial *serial) +{ +	struct usb_serial_port *port; +	int i; + +	for (i = 0; i < serial->num_ports; ++i) { +		port = serial->port[i]; +		if (port) +			usb_serial_port_unpoison_urbs(port); +	} +} +  int usb_serial_resume(struct usb_interface *intf)  {  	struct usb_serial *serial = usb_get_intfdata(intf);  	int rv; +	usb_serial_unpoison_port_urbs(serial); +  	serial->suspending = 0;  	if (serial->type->resume)  		rv = serial->type->resume(serial); @@ -1179,6 +1174,8 @@ static int usb_serial_reset_resume(struct usb_interface *intf)  	struct usb_serial *serial = usb_get_intfdata(intf);  	int rv; +	usb_serial_unpoison_port_urbs(serial); +  	serial->suspending = 0;  	if (serial->type->reset_resume)  		rv = serial->type->reset_resume(serial); @@ -1315,12 +1312,12 @@ module_exit(usb_serial_exit);  	do {								\  		if (!type->function) {					\  			type->function = usb_serial_generic_##function;	\ -			pr_debug("Had to override the " #function	\ -				" usb serial operation with the generic one.");\ -			}						\ +			pr_debug("%s: using generic " #function	"\n",	\ +						type->driver.name);	\ +		}							\  	} while (0) -static void fixup_generic(struct usb_serial_driver *device) +static void usb_serial_operations_init(struct usb_serial_driver *device)  {  	set_to_generic_if_null(device, open);  	set_to_generic_if_null(device, write); @@ -1329,8 +1326,6 @@ static void fixup_generic(struct usb_serial_driver *device)  	set_to_generic_if_null(device, chars_in_buffer);  	set_to_generic_if_null(device, read_bulk_callback);  	set_to_generic_if_null(device, write_bulk_callback); -	set_to_generic_if_null(device, disconnect); -	set_to_generic_if_null(device, release);  	set_to_generic_if_null(device, process_read_urb);  	set_to_generic_if_null(device, prepare_write_buffer);  } @@ -1342,8 +1337,6 @@ static int usb_serial_register(struct usb_serial_driver *driver)  	if (usb_disabled())  		return -ENODEV; -	fixup_generic(driver); -  	if (!driver->description)  		driver->description = driver->driver.name;  	if (!driver->usb_driver) { @@ -1352,6 +1345,8 @@ static int usb_serial_register(struct usb_serial_driver *driver)  		return -EINVAL;  	} +	usb_serial_operations_init(driver); +  	/* Add this device to our list of devices */  	mutex_lock(&table_lock);  	list_add(&driver->driver_list, &usb_serial_driver_list); @@ -1469,7 +1464,6 @@ void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_driver  }  EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers); -/* Module information */  MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 571965aa1cc..ece326ef63a 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -421,20 +421,19 @@ void usb_wwan_close(struct usb_serial_port *port)  	portdata = usb_get_serial_port_data(port); -	if (serial->dev) { -		/* Stop reading/writing urbs */ -		spin_lock_irq(&intfdata->susp_lock); -		portdata->opened = 0; -		spin_unlock_irq(&intfdata->susp_lock); +	/* Stop reading/writing urbs */ +	spin_lock_irq(&intfdata->susp_lock); +	portdata->opened = 0; +	spin_unlock_irq(&intfdata->susp_lock); -		for (i = 0; i < N_IN_URB; i++) -			usb_kill_urb(portdata->in_urbs[i]); -		for (i = 0; i < N_OUT_URB; i++) -			usb_kill_urb(portdata->out_urbs[i]); -		/* balancing - important as an error cannot be handled*/ -		usb_autopm_get_interface_no_resume(serial->interface); -		serial->interface->needs_remote_wakeup = 0; -	} +	for (i = 0; i < N_IN_URB; i++) +		usb_kill_urb(portdata->in_urbs[i]); +	for (i = 0; i < N_OUT_URB; i++) +		usb_kill_urb(portdata->out_urbs[i]); + +	/* balancing - important as an error cannot be handled*/ +	usb_autopm_get_interface_no_resume(serial->interface); +	serial->interface->needs_remote_wakeup = 0;  }  EXPORT_SYMBOL(usb_wwan_close); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 1129aa73c23..7573ec8a084 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -257,24 +257,18 @@ static void visor_close(struct usb_serial_port *port)  {  	unsigned char *transfer_buffer; -	/* shutdown our urbs */  	usb_serial_generic_close(port);  	usb_kill_urb(port->interrupt_in_urb); -	mutex_lock(&port->serial->disc_mutex); -	if (!port->serial->disconnected) { -		/* Try to send shutdown message, unless the device is gone */ -		transfer_buffer =  kmalloc(0x12, GFP_KERNEL); -		if (transfer_buffer) { -			usb_control_msg(port->serial->dev, +	transfer_buffer = kmalloc(0x12, GFP_KERNEL); +	if (!transfer_buffer) +		return; +	usb_control_msg(port->serial->dev,  					 usb_rcvctrlpipe(port->serial->dev, 0),  					 VISOR_CLOSE_NOTIFICATION, 0xc2,  					 0x0000, 0x0000,  					 transfer_buffer, 0x12, 300); -			kfree(transfer_buffer); -		} -	} -	mutex_unlock(&port->serial->disc_mutex); +	kfree(transfer_buffer);  }  static void visor_read_int_callback(struct urb *urb) diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c index ecea4787736..06a3d22db68 100644 --- a/drivers/usb/storage/isd200.c +++ b/drivers/usb/storage/isd200.c @@ -1457,8 +1457,7 @@ static int isd200_init_info(struct us_data *us)  		retStatus = ISD200_ERROR;  	else {  		info->id = kzalloc(ATA_ID_WORDS * 2, GFP_KERNEL); -		info->RegsBuf = (unsigned char *) -				kmalloc(sizeof(info->ATARegs), GFP_KERNEL); +		info->RegsBuf = kmalloc(sizeof(info->ATARegs), GFP_KERNEL);  		info->srb.sense_buffer =  				kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);  		if (!info->id || !info->RegsBuf || !info->srb.sense_buffer) { diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index cb79de61f4c..26964895c88 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -195,6 +195,7 @@ static int onetouch_connect_input(struct us_data *ss)  	pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);  	maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); +	maxp = min(maxp, ONETOUCH_PKT_LEN);  	onetouch = kzalloc(sizeof(struct usb_onetouch), GFP_KERNEL);  	input_dev = input_allocate_device(); @@ -245,8 +246,7 @@ static int onetouch_connect_input(struct us_data *ss)  	input_dev->open = usb_onetouch_open;  	input_dev->close = usb_onetouch_close; -	usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, -			 (maxp > 8 ? 8 : maxp), +	usb_fill_int_urb(onetouch->irq, udev, pipe, onetouch->data, maxp,  			 usb_onetouch_irq, onetouch, endpoint->bInterval);  	onetouch->irq->transfer_dma = onetouch->data_dma;  	onetouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index da04a074e79..1799335288b 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -496,6 +496,13 @@ UNUSUAL_DEV(  0x04e8, 0x5122, 0x0000, 0x9999,  		USB_SC_DEVICE, USB_PR_DEVICE, NULL,  		US_FL_MAX_SECTORS_64 | US_FL_BULK_IGNORE_TAG), +/* Added by Dmitry Artamonow <mad_soft@inbox.ru> */ +UNUSUAL_DEV(  0x04e8, 0x5136, 0x0000, 0x9999, +		"Samsung", +		"YP-Z3", +		USB_SC_DEVICE, USB_PR_DEVICE, NULL, +		US_FL_MAX_SECTORS_64), +  /* Entry and supporting patch by Theodore Kilgore <kilgota@auburn.edu>.   * Device uses standards-violating 32-byte Bulk Command Block Wrappers and   * reports itself as "Proprietary SCSI Bulk." Cf. device entry 0x084d:0x0011. diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index ce310170829..7ed3b039dbe 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -61,11 +61,10 @@ struct usb_skel {  	__u8			bulk_out_endpointAddr;	/* the address of the bulk out endpoint */  	int			errors;			/* the last request tanked */  	bool			ongoing_read;		/* a read is going on */ -	bool			processed_urb;		/* indicates we haven't processed the urb */  	spinlock_t		err_lock;		/* lock for errors */  	struct kref		kref;  	struct mutex		io_mutex;		/* synchronize I/O with disconnect */ -	struct completion	bulk_in_completion;	/* to wait for an ongoing read */ +	wait_queue_head_t	bulk_in_wait;		/* to wait for an ongoing read */  };  #define to_skel_dev(d) container_of(d, struct usb_skel, kref) @@ -185,7 +184,7 @@ static void skel_read_bulk_callback(struct urb *urb)  	dev->ongoing_read = 0;  	spin_unlock(&dev->err_lock); -	complete(&dev->bulk_in_completion); +	wake_up_interruptible(&dev->bulk_in_wait);  }  static int skel_do_read_io(struct usb_skel *dev, size_t count) @@ -206,13 +205,16 @@ static int skel_do_read_io(struct usb_skel *dev, size_t count)  	dev->ongoing_read = 1;  	spin_unlock_irq(&dev->err_lock); +	/* submit bulk in urb, which means no data to deliver */ +	dev->bulk_in_filled = 0; +	dev->bulk_in_copied = 0; +  	/* do it */  	rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);  	if (rv < 0) {  		dev_err(&dev->interface->dev,  			"%s - failed submitting read urb, error %d\n",  			__func__, rv); -		dev->bulk_in_filled = 0;  		rv = (rv == -ENOMEM) ? rv : -EIO;  		spin_lock_irq(&dev->err_lock);  		dev->ongoing_read = 0; @@ -261,25 +263,9 @@ retry:  		 * IO may take forever  		 * hence wait in an interruptible state  		 */ -		rv = wait_for_completion_interruptible(&dev->bulk_in_completion); +		rv = wait_event_interruptible(dev->bulk_in_wait, (!dev->ongoing_read));  		if (rv < 0)  			goto exit; -		/* -		 * by waiting we also semiprocessed the urb -		 * we must finish now -		 */ -		dev->bulk_in_copied = 0; -		dev->processed_urb = 1; -	} - -	if (!dev->processed_urb) { -		/* -		 * the URB hasn't been processed -		 * do it now -		 */ -		wait_for_completion(&dev->bulk_in_completion); -		dev->bulk_in_copied = 0; -		dev->processed_urb = 1;  	}  	/* errors must be reported */ @@ -289,8 +275,6 @@ retry:  		dev->errors = 0;  		/* to preserve notifications about reset */  		rv = (rv == -EPIPE) ? rv : -EIO; -		/* no data to deliver */ -		dev->bulk_in_filled = 0;  		/* report it */  		goto exit;  	} @@ -526,7 +510,7 @@ static int skel_probe(struct usb_interface *interface,  	mutex_init(&dev->io_mutex);  	spin_lock_init(&dev->err_lock);  	init_usb_anchor(&dev->submitted); -	init_completion(&dev->bulk_in_completion); +	init_waitqueue_head(&dev->bulk_in_wait);  	dev->udev = usb_get_dev(interface_to_usbdev(interface));  	dev->interface = interface;  |