diff options
Diffstat (limited to 'drivers/usb')
433 files changed, 45735 insertions, 17617 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 2642b8a11e0..e0cad441808 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -2,10 +2,6 @@  # USB device configuration  # -# These are unused now, remove them once they are no longer selected -config USB_ARCH_HAS_OHCI -	bool -  config USB_OHCI_BIG_ENDIAN_DESC  	bool @@ -17,18 +13,12 @@ config USB_OHCI_LITTLE_ENDIAN  	default n if STB03xxx || PPC_MPC52xx  	default y -config USB_ARCH_HAS_EHCI -	bool -  config USB_EHCI_BIG_ENDIAN_MMIO  	bool  config USB_EHCI_BIG_ENDIAN_DESC  	bool -config USB_ARCH_HAS_XHCI -	bool -  menuconfig USB_SUPPORT  	bool "USB support"  	depends on HAS_IOMEM @@ -94,8 +84,6 @@ source "drivers/usb/wusbcore/Kconfig"  source "drivers/usb/host/Kconfig" -source "drivers/usb/musb/Kconfig" -  source "drivers/usb/renesas_usbhs/Kconfig"  source "drivers/usb/class/Kconfig" @@ -106,8 +94,12 @@ source "drivers/usb/image/Kconfig"  endif +source "drivers/usb/musb/Kconfig" +  source "drivers/usb/dwc3/Kconfig" +source "drivers/usb/dwc2/Kconfig" +  source "drivers/usb/chipidea/Kconfig"  comment "USB port drivers" diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 70d7c5b92c3..3cba892b83a 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -7,6 +7,7 @@  obj-$(CONFIG_USB)		+= core/  obj-$(CONFIG_USB_DWC3)		+= dwc3/ +obj-$(CONFIG_USB_DWC2)		+= dwc2/  obj-$(CONFIG_USB_MON)		+= mon/ @@ -27,6 +28,7 @@ obj-$(CONFIG_USB_IMX21_HCD)	+= host/  obj-$(CONFIG_USB_FSL_MPH_DR_OF)	+= host/  obj-$(CONFIG_USB_FUSBH200_HCD)	+= host/  obj-$(CONFIG_USB_FOTG210_HCD)	+= host/ +obj-$(CONFIG_USB_MAX3421_HCD)	+= host/  obj-$(CONFIG_USB_C67X00_HCD)	+= c67x00/ @@ -57,4 +59,4 @@ obj-$(CONFIG_USB_CHIPIDEA)	+= chipidea/  obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/  obj-$(CONFIG_USB_GADGET)	+= gadget/ -obj-$(CONFIG_USB_COMMON)	+= usb-common.o +obj-$(CONFIG_USB_COMMON)	+= common/ diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 8a7eb77233b..813d4d3a51c 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -35,7 +35,6 @@  #include <linux/timer.h>  #include <linux/errno.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/device.h>  #include <linux/firmware.h>  #include <linux/mutex.h> diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 69461d65397..0dc8c06a7b5 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -27,7 +27,6 @@  #include <linux/device.h>  #include <linux/errno.h>  #include <linux/firmware.h> -#include <linux/init.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/moduleparam.h> diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index defff43950b..5a459377574 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -57,7 +57,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h> -#include <linux/init.h>  #include <linux/crc32.h>  #include <linux/usb.h>  #include <linux/firmware.h> diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 25a7bfcf666..dada0146cd7 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -170,9 +170,9 @@ struct usbatm_control {  static void usbatm_atm_dev_close(struct atm_dev *atm_dev);  static int usbatm_atm_open(struct atm_vcc *vcc);  static void usbatm_atm_close(struct atm_vcc *vcc); -static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void __user * arg); +static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void __user *arg);  static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb); -static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page); +static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t *pos, char *page);  static struct atmdev_ops usbatm_atm_devops = {  	.dev_close	= usbatm_atm_dev_close, @@ -739,7 +739,7 @@ static void usbatm_atm_dev_close(struct atm_dev *atm_dev)  	usbatm_put_instance(instance);	/* taken in usbatm_atm_init */  } -static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page) +static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t *pos, char *page)  {  	struct usbatm_data *instance = atm_dev->dev_data;  	int left = *pos; @@ -895,7 +895,7 @@ static void usbatm_atm_close(struct atm_vcc *vcc)  }  static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, -			  void __user * arg) +			  void __user *arg)  {  	struct usbatm_data *instance = atm_dev->dev_data; diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h index 5651231a743..f3eecd967a8 100644 --- a/drivers/usb/atm/usbatm.h +++ b/drivers/usb/atm/usbatm.h @@ -34,6 +34,7 @@  #include <linux/stringify.h>  #include <linux/usb.h>  #include <linux/mutex.h> +#include <linux/ratelimit.h>  /*  #define VERBOSE_DEBUG @@ -59,13 +60,12 @@  	atm_printk(KERN_INFO, instance , format , ## arg)  #define atm_warn(instance, format, arg...)	\  	atm_printk(KERN_WARNING, instance , format , ## arg) -#define atm_dbg(instance, format, arg...)		\ -	dynamic_pr_debug("ATM dev %d: " format ,	\ -	(instance)->atm_dev->number , ## arg) -#define atm_rldbg(instance, format, arg...)		\ -	if (printk_ratelimit())				\ -		atm_dbg(instance , format , ## arg) - +#define atm_dbg(instance, format, ...)					\ +	pr_debug("ATM dev %d: " format,					\ +		 (instance)->atm_dev->number, ##__VA_ARGS__) +#define atm_rldbg(instance, format, ...)				\ +	pr_debug_ratelimited("ATM dev %d: " format,			\ +			     (instance)->atm_dev->number, ##__VA_ARGS__)  /* flags, set by mini-driver in bind() */ diff --git a/drivers/usb/c67x00/Makefile b/drivers/usb/c67x00/Makefile index b1218683c8e..da5f314a5de 100644 --- a/drivers/usb/c67x00/Makefile +++ b/drivers/usb/c67x00/Makefile @@ -2,8 +2,6 @@  # Makefile for Cypress C67X00 USB Controller  # -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG -  obj-$(CONFIG_USB_C67X00_HCD)	+= c67x00.o  c67x00-y := c67x00-drv.o c67x00-ll-hpi.o c67x00-hcd.o c67x00-sched.o diff --git a/drivers/usb/c67x00/c67x00-hcd.c b/drivers/usb/c67x00/c67x00-hcd.c index 75e47b860a5..20ec4eee1ac 100644 --- a/drivers/usb/c67x00/c67x00-hcd.c +++ b/drivers/usb/c67x00/c67x00-hcd.c @@ -384,6 +384,8 @@ int c67x00_hcd_probe(struct c67x00_sie *sie)  		goto err2;  	} +	device_wakeup_enable(hcd->self.controller); +  	spin_lock_irqsave(&sie->lock, flags);  	sie->private_data = c67x00;  	sie->irq = c67x00_hcd_irq; diff --git a/drivers/usb/c67x00/c67x00-hcd.h b/drivers/usb/c67x00/c67x00-hcd.h index e3d493d4d61..cf8a455a640 100644 --- a/drivers/usb/c67x00/c67x00-hcd.h +++ b/drivers/usb/c67x00/c67x00-hcd.h @@ -45,7 +45,7 @@  /*   * The current implementation switches between _STD (default) and _ISO (when   * isochronous transfers are scheduled), in order to optimize the throughput - * in normal cicrumstances, but also provide good isochronous behaviour. + * in normal circumstances, but also provide good isochronous behaviour.   *   * Bandwidth is described in bit time so with a 12MHz USB clock and 1ms   * frames; there are 12000 bit times per frame. diff --git a/drivers/usb/c67x00/c67x00-ll-hpi.c b/drivers/usb/c67x00/c67x00-ll-hpi.c index 3a1ca4dfc83..b58151841e1 100644 --- a/drivers/usb/c67x00/c67x00-ll-hpi.c +++ b/drivers/usb/c67x00/c67x00-ll-hpi.c @@ -22,6 +22,7 @@   */  #include <asm/byteorder.h> +#include <linux/delay.h>  #include <linux/io.h>  #include <linux/jiffies.h>  #include <linux/usb/c67x00.h> @@ -62,8 +63,8 @@ struct c67x00_lcp_int_data {   * HPI implementation   *   * The c67x00 chip also support control via SPI or HSS serial - * interfaces.  However, this driver assumes that register access can - * be performed from IRQ context.  While this is a safe assuption with + * interfaces. However, this driver assumes that register access can + * be performed from IRQ context. While this is a safe assumption with   * the HPI interface, it is not true for the serial interfaces.   */ @@ -73,13 +74,22 @@ struct c67x00_lcp_int_data {  #define HPI_ADDR	2  #define HPI_STATUS	3 +/* + * According to CY7C67300 specification (tables 140 and 141) HPI read and + * write cycle duration Tcyc must be at least 6T long, where T is 1/48MHz, + * which is 125ns. + */ +#define HPI_T_CYC_NS	125 +  static inline u16 hpi_read_reg(struct c67x00_device *dev, int reg)  { +	ndelay(HPI_T_CYC_NS);  	return __raw_readw(dev->hpi.base + reg * dev->hpi.regstep);  }  static inline void hpi_write_reg(struct c67x00_device *dev, int reg, u16 value)  { +	ndelay(HPI_T_CYC_NS);  	__raw_writew(value, dev->hpi.base + reg * dev->hpi.regstep);  } diff --git a/drivers/usb/c67x00/c67x00-sched.c b/drivers/usb/c67x00/c67x00-sched.c index aa491627a45..7311ed61e99 100644 --- a/drivers/usb/c67x00/c67x00-sched.c +++ b/drivers/usb/c67x00/c67x00-sched.c @@ -144,8 +144,6 @@ struct c67x00_urb_priv {  /* -------------------------------------------------------------------------- */ -#ifdef DEBUG -  /**   * dbg_td - Dump the contents of the TD   */ @@ -166,16 +164,8 @@ static void dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg)  	dev_dbg(dev, "retry_cnt:      0x%02x\n", td->retry_cnt);  	dev_dbg(dev, "residue:        0x%02x\n", td->residue);  	dev_dbg(dev, "next_td_addr: 0x%04x\n", td_next_td_addr(td)); -	dev_dbg(dev, "data:"); -	print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1, -		       td->data, td_length(td), 1); +	dev_dbg(dev, "data: %*ph\n", td_length(td), td->data);  } -#else				/* DEBUG */ - -static inline void -dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg) { } - -#endif				/* DEBUG */  /* -------------------------------------------------------------------------- */  /* Helper functions */ @@ -344,7 +334,7 @@ void c67x00_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)  		/* it could happen that we reinitialize this completion, while  		 * somebody was waiting for that completion.  The timeout and  		 * while loop handle such cases, but this might be improved */ -		INIT_COMPLETION(c67x00->endpoint_disable); +		reinit_completion(&c67x00->endpoint_disable);  		c67x00_sched_kick(c67x00);  		wait_for_completion_timeout(&c67x00->endpoint_disable, 1 * HZ); @@ -372,6 +362,13 @@ int c67x00_urb_enqueue(struct usb_hcd *hcd,  	struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);  	int port = get_root_port(urb->dev)-1; +	/* Allocate and initialize urb private data */ +	urbp = kzalloc(sizeof(*urbp), mem_flags); +	if (!urbp) { +		ret = -ENOMEM; +		goto err_urbp; +	} +  	spin_lock_irqsave(&c67x00->lock, flags);  	/* Make sure host controller is running */ @@ -384,13 +381,6 @@ int c67x00_urb_enqueue(struct usb_hcd *hcd,  	if (ret)  		goto err_not_linked; -	/* Allocate and initialize urb private data */ -	urbp = kzalloc(sizeof(*urbp), mem_flags); -	if (!urbp) { -		ret = -ENOMEM; -		goto err_urbp; -	} -  	INIT_LIST_HEAD(&urbp->hep_node);  	urbp->urb = urb;  	urbp->port = port; @@ -453,11 +443,11 @@ int c67x00_urb_enqueue(struct usb_hcd *hcd,  	return 0;  err_epdata: -	kfree(urbp); -err_urbp:  	usb_hcd_unlink_urb_from_ep(hcd, urb);  err_not_linked:  	spin_unlock_irqrestore(&c67x00->lock, flags); +	kfree(urbp); +err_urbp:  	return ret;  } @@ -780,7 +770,8 @@ static int c67x00_add_iso_urb(struct c67x00_hcd *c67x00, struct urb *urb)  		ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, 0,  				       urbp->cnt);  		if (ret) { -			printk(KERN_DEBUG "create failed: %d\n", ret); +			dev_dbg(c67x00_hcd_dev(c67x00), "create failed: %d\n", +				ret);  			urb->iso_frame_desc[urbp->cnt].actual_length = 0;  			urb->iso_frame_desc[urbp->cnt].status = ret;  			if (urbp->cnt + 1 == urb->number_of_packets) diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index 4a851e15e58..77b47d82c9a 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -1,6 +1,6 @@  config USB_CHIPIDEA  	tristate "ChipIdea Highspeed Dual Role Controller" -	depends on (USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET) +	depends on ((USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)) && HAS_DMA  	help  	  Say Y here if your system has a dual role high speed USB  	  controller based on ChipIdea silicon IP. Currently, only the diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index a99d980454a..2f099c7df7b 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -6,10 +6,12 @@ ci_hdrc-y				:= core.o otg.o  ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC)	+= udc.o  ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)	+= host.o  ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG)	+= debug.o +ci_hdrc-$(CONFIG_USB_OTG_FSM)		+= otg_fsm.o  # Glue/Bridge layers go here  obj-$(CONFIG_USB_CHIPIDEA)	+= ci_hdrc_msm.o +obj-$(CONFIG_USB_CHIPIDEA)	+= ci_hdrc_zevio.o  # PCI doesn't provide stubs, need to check  ifneq ($(CONFIG_PCI),) @@ -17,5 +19,5 @@ ifneq ($(CONFIG_PCI),)  endif  ifneq ($(CONFIG_OF),) -	obj-$(CONFIG_USB_CHIPIDEA)	+= ci_hdrc_imx.o usbmisc_imx.o +	obj-$(CONFIG_USB_CHIPIDEA)	+= usbmisc_imx.o ci_hdrc_imx.o  endif diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index 464584c6cca..ca57e3dcd3d 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h @@ -44,17 +44,28 @@  #define DEVICEADDR_USBADR     (0x7FUL << 25)  /* PORTSC */ +#define PORTSC_CCS            BIT(0) +#define PORTSC_CSC            BIT(1) +#define PORTSC_PEC            BIT(3) +#define PORTSC_OCC            BIT(5)  #define PORTSC_FPR            BIT(6)  #define PORTSC_SUSP           BIT(7)  #define PORTSC_HSP            BIT(9) +#define PORTSC_PP             BIT(12)  #define PORTSC_PTC            (0x0FUL << 16) +#define PORTSC_PHCD(d)	      ((d) ? BIT(22) : BIT(23))  /* PTS and PTW for non lpm version only */ +#define PORTSC_PFSC           BIT(24)  #define PORTSC_PTS(d)						\  	(u32)((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))  #define PORTSC_PTW            BIT(28)  #define PORTSC_STS            BIT(29) +#define PORTSC_W1C_BITS						\ +	(PORTSC_CSC | PORTSC_PEC | PORTSC_OCC) +  /* DEVLC */ +#define DEVLC_PFSC            BIT(23)  #define DEVLC_PSPD            (0x03UL << 25)  #define DEVLC_PSPD_HS         (0x02UL << 25)  #define DEVLC_PTW             BIT(27) @@ -69,6 +80,8 @@  /* OTGSC */  #define OTGSC_IDPU	      BIT(5) +#define OTGSC_HADP	      BIT(6) +#define OTGSC_HABA	      BIT(7)  #define OTGSC_ID	      BIT(8)  #define OTGSC_AVV	      BIT(9)  #define OTGSC_ASV	      BIT(10) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 1c94fc5257f..9563cb56d56 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -17,6 +17,7 @@  #include <linux/irqreturn.h>  #include <linux/usb.h>  #include <linux/usb/gadget.h> +#include <linux/usb/otg-fsm.h>  /******************************************************************************   * DEFINE @@ -26,6 +27,35 @@  #define ENDPT_MAX          32  /****************************************************************************** + * REGISTERS + *****************************************************************************/ +/* register indices */ +enum ci_hw_regs { +	CAP_CAPLENGTH, +	CAP_HCCPARAMS, +	CAP_DCCPARAMS, +	CAP_TESTMODE, +	CAP_LAST = CAP_TESTMODE, +	OP_USBCMD, +	OP_USBSTS, +	OP_USBINTR, +	OP_DEVICEADDR, +	OP_ENDPTLISTADDR, +	OP_PORTSC, +	OP_DEVLC, +	OP_OTGSC, +	OP_USBMODE, +	OP_ENDPTSETUPSTAT, +	OP_ENDPTPRIME, +	OP_ENDPTFLUSH, +	OP_ENDPTSTAT, +	OP_ENDPTCOMPLETE, +	OP_ENDPTCTRL, +	/* endptctrl1..15 follow */ +	OP_LAST = OP_ENDPTCTRL + ENDPT_MAX / 2, +}; + +/******************************************************************************   * STRUCTURES   *****************************************************************************/  /** @@ -98,7 +128,7 @@ struct hw_bank {  	void __iomem	*cap;  	void __iomem	*op;  	size_t		size; -	void __iomem	**regmap; +	void __iomem	*regmap[OP_LAST + 1];  };  /** @@ -110,6 +140,8 @@ struct hw_bank {   * @roles: array of supported roles for this controller   * @role: current role   * @is_otg: if the device is otg-capable + * @fsm: otg finite state machine + * @fsm_timer: pointer to timer list of otg fsm   * @work: work for role changing   * @wq: workqueue thread   * @qh_pool: allocation pool for queue heads @@ -135,6 +167,7 @@ struct hw_bank {   * @id_event: indicates there is an id event, and handled at ci_otg_work   * @b_sess_valid_event: indicates there is a vbus event, and handled   * at ci_otg_work + * @imx28_write_fix: Freescale imx28 needs swp instruction for writing   */  struct ci_hdrc {  	struct device			*dev; @@ -144,6 +177,8 @@ struct ci_hdrc {  	struct ci_role_driver		*roles[CI_ROLE_END];  	enum ci_role			role;  	bool				is_otg; +	struct otg_fsm			fsm; +	struct ci_otg_fsm_timer_list	*fsm_timer;  	struct work_struct		work;  	struct workqueue_struct		*wq; @@ -166,13 +201,12 @@ struct ci_hdrc {  	struct ci_hdrc_platform_data	*platdata;  	int				vbus_active; -	/* FIXME: some day, we'll not use global phy */ -	bool				global_phy;  	struct usb_phy			*transceiver;  	struct usb_hcd			*hcd;  	struct dentry			*debugfs;  	bool				id_event;  	bool				b_sess_valid_event; +	bool				imx28_write_fix;  };  static inline struct ci_role_driver *ci_role(struct ci_hdrc *ci) @@ -209,38 +243,6 @@ static inline void ci_role_stop(struct ci_hdrc *ci)  	ci->roles[role]->stop(ci);  } -/****************************************************************************** - * REGISTERS - *****************************************************************************/ -/* register size */ -#define REG_BITS   (32) - -/* register indices */ -enum ci_hw_regs { -	CAP_CAPLENGTH, -	CAP_HCCPARAMS, -	CAP_DCCPARAMS, -	CAP_TESTMODE, -	CAP_LAST = CAP_TESTMODE, -	OP_USBCMD, -	OP_USBSTS, -	OP_USBINTR, -	OP_DEVICEADDR, -	OP_ENDPTLISTADDR, -	OP_PORTSC, -	OP_DEVLC, -	OP_OTGSC, -	OP_USBMODE, -	OP_ENDPTSETUPSTAT, -	OP_ENDPTPRIME, -	OP_ENDPTFLUSH, -	OP_ENDPTSTAT, -	OP_ENDPTCOMPLETE, -	OP_ENDPTCTRL, -	/* endptctrl1..15 follow */ -	OP_LAST = OP_ENDPTCTRL + ENDPT_MAX / 2, -}; -  /**   * hw_read: reads from a hw register   * @reg:  register index @@ -253,6 +255,26 @@ static inline u32 hw_read(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask)  	return ioread32(ci->hw_bank.regmap[reg]) & mask;  } +#ifdef CONFIG_SOC_IMX28 +static inline void imx28_ci_writel(u32 val, volatile void __iomem *addr) +{ +	__asm__ ("swp %0, %0, [%1]" : : "r"(val), "r"(addr)); +} +#else +static inline void imx28_ci_writel(u32 val, volatile void __iomem *addr) +{ +} +#endif + +static inline void __hw_write(struct ci_hdrc *ci, u32 val, +		void __iomem *addr) +{ +	if (ci->imx28_write_fix) +		imx28_ci_writel(val, addr); +	else +		iowrite32(val, addr); +} +  /**   * hw_write: writes to a hw register   * @reg:  register index @@ -266,7 +288,7 @@ static inline void hw_write(struct ci_hdrc *ci, enum ci_hw_regs reg,  		data = (ioread32(ci->hw_bank.regmap[reg]) & ~mask)  			| (data & mask); -	iowrite32(data, ci->hw_bank.regmap[reg]); +	__hw_write(ci, data, ci->hw_bank.regmap[reg]);  }  /** @@ -281,7 +303,7 @@ static inline u32 hw_test_and_clear(struct ci_hdrc *ci, enum ci_hw_regs reg,  {  	u32 val = ioread32(ci->hw_bank.regmap[reg]) & mask; -	iowrite32(val, ci->hw_bank.regmap[reg]); +	__hw_write(ci, val, ci->hw_bank.regmap[reg]);  	return val;  } @@ -302,6 +324,24 @@ static inline u32 hw_test_and_write(struct ci_hdrc *ci, enum ci_hw_regs reg,  	return (val & mask) >> __ffs(mask);  } +/** + * ci_otg_is_fsm_mode: runtime check if otg controller + * is in otg fsm mode. + */ +static inline bool ci_otg_is_fsm_mode(struct ci_hdrc *ci) +{ +#ifdef CONFIG_USB_OTG_FSM +	return ci->is_otg && ci->roles[CI_ROLE_HOST] && +					ci->roles[CI_ROLE_GADGET]; +#else +	return false; +#endif +} + +u32 hw_read_intr_enable(struct ci_hdrc *ci); + +u32 hw_read_intr_status(struct ci_hdrc *ci); +  int hw_device_reset(struct ci_hdrc *ci, u32 mode);  int hw_port_test_set(struct ci_hdrc *ci, u8 mode); diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 74d998d9b45..2e58f8dfd31 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -23,6 +23,26 @@  #include "ci.h"  #include "ci_hdrc_imx.h" +#define CI_HDRC_IMX_IMX28_WRITE_FIX BIT(0) + +struct ci_hdrc_imx_platform_flag { +	unsigned int flags; +}; + +static const struct ci_hdrc_imx_platform_flag imx27_usb_data = { +}; + +static const struct ci_hdrc_imx_platform_flag imx28_usb_data = { +	.flags = CI_HDRC_IMX_IMX28_WRITE_FIX, +}; + +static const struct of_device_id ci_hdrc_imx_dt_ids[] = { +	{ .compatible = "fsl,imx28-usb", .data = &imx28_usb_data}, +	{ .compatible = "fsl,imx27-usb", .data = &imx27_usb_data}, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids); +  struct ci_hdrc_imx_data {  	struct usb_phy *phy;  	struct platform_device *ci_pdev; @@ -76,12 +96,15 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)  {  	struct ci_hdrc_imx_data *data;  	struct ci_hdrc_platform_data pdata = { -		.name		= "ci_hdrc_imx", +		.name		= dev_name(&pdev->dev),  		.capoffset	= DEF_CAPOFFSET,  		.flags		= CI_HDRC_REQUIRE_TRANSCEIVER |  				  CI_HDRC_DISABLE_STREAMING,  	};  	int ret; +	const struct of_device_id *of_id = +			of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev); +	const struct ci_hdrc_imx_platform_flag *imx_platform_flag = of_id->data;  	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);  	if (!data) { @@ -108,23 +131,19 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)  	}  	data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0); -	if (!IS_ERR(data->phy)) { -		ret = usb_phy_init(data->phy); -		if (ret) { -			dev_err(&pdev->dev, "unable to init phy: %d\n", ret); -			goto err_clk; -		} -	} else if (PTR_ERR(data->phy) == -EPROBE_DEFER) { -		ret = -EPROBE_DEFER; +	if (IS_ERR(data->phy)) { +		ret = PTR_ERR(data->phy);  		goto err_clk;  	}  	pdata.phy = data->phy; -	if (!pdev->dev.dma_mask) -		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; -	if (!pdev->dev.coherent_dma_mask) -		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	if (imx_platform_flag->flags & CI_HDRC_IMX_IMX28_WRITE_FIX) +		pdata.flags |= CI_HDRC_IMX28_WRITE_FIX; + +	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (ret) +		goto err_clk;  	if (data->usbmisc_data) {  		ret = imx_usbmisc_init(data->usbmisc_data); @@ -175,21 +194,11 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)  	pm_runtime_disable(&pdev->dev);  	ci_hdrc_remove_device(data->ci_pdev); - -	if (data->phy) -		usb_phy_shutdown(data->phy); -  	clk_disable_unprepare(data->clk);  	return 0;  } -static const struct of_device_id ci_hdrc_imx_dt_ids[] = { -	{ .compatible = "fsl,imx27-usb", }, -	{ /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids); -  static struct platform_driver ci_hdrc_imx_driver = {  	.probe = ci_hdrc_imx_probe,  	.remove = ci_hdrc_imx_remove, diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h index c7271590dd0..996ec93467b 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.h +++ b/drivers/usb/chipidea/ci_hdrc_imx.h @@ -9,6 +9,9 @@   * http://www.gnu.org/copyleft/gpl.html   */ +#ifndef __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H +#define __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H +  struct imx_usbmisc_data {  	int index; @@ -18,3 +21,5 @@ struct imx_usbmisc_data {  int imx_usbmisc_init(struct imx_usbmisc_data *);  int imx_usbmisc_init_post(struct imx_usbmisc_data *); + +#endif /* __DRIVER_USB_CHIPIDEA_CI_HDRC_IMX_H */ diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index 2d51d852b47..d72b9d2de2c 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -47,6 +47,7 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)  static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = {  	.name			= "ci_hdrc_msm", +	.capoffset		= DEF_CAPOFFSET,  	.flags			= CI_HDRC_REGS_SHARED |  				  CI_HDRC_REQUIRE_TRANSCEIVER |  				  CI_HDRC_DISABLE_STREAMING, @@ -57,9 +58,21 @@ static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = {  static int ci_hdrc_msm_probe(struct platform_device *pdev)  {  	struct platform_device *plat_ci; +	struct usb_phy *phy;  	dev_dbg(&pdev->dev, "ci_hdrc_msm_probe\n"); +	/* +	 * OTG(PHY) driver takes care of PHY initialization, clock management, +	 * powering up VBUS, mapping of registers address space and power +	 * management. +	 */ +	phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); +	if (IS_ERR(phy)) +		return PTR_ERR(phy); + +	ci_hdrc_msm_platdata.phy = phy; +  	plat_ci = ci_hdrc_add_device(&pdev->dev,  				pdev->resource, pdev->num_resources,  				&ci_hdrc_msm_platdata); @@ -86,10 +99,19 @@ static int ci_hdrc_msm_remove(struct platform_device *pdev)  	return 0;  } +static const struct of_device_id msm_ci_dt_match[] = { +	{ .compatible = "qcom,ci-hdrc", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, msm_ci_dt_match); +  static struct platform_driver ci_hdrc_msm_driver = {  	.probe = ci_hdrc_msm_probe,  	.remove = ci_hdrc_msm_remove, -	.driver = { .name = "msm_hsusb", }, +	.driver = { +		.name = "msm_hsusb", +		.of_match_table = msm_ci_dt_match, +	},  };  module_platform_driver(ci_hdrc_msm_driver); diff --git a/drivers/usb/chipidea/ci_hdrc_pci.c b/drivers/usb/chipidea/ci_hdrc_pci.c index 042320a6c6c..241ae3444fd 100644 --- a/drivers/usb/chipidea/ci_hdrc_pci.c +++ b/drivers/usb/chipidea/ci_hdrc_pci.c @@ -112,7 +112,7 @@ static void ci_hdrc_pci_remove(struct pci_dev *pdev)   *   * Check "pci.h" for details   */ -static DEFINE_PCI_DEVICE_TABLE(ci_hdrc_pci_id_table) = { +static const struct pci_device_id ci_hdrc_pci_id_table[] = {  	{  		PCI_DEVICE(0x153F, 0x1004),  		.driver_data = (kernel_ulong_t)&pci_platdata, @@ -129,7 +129,12 @@ static DEFINE_PCI_DEVICE_TABLE(ci_hdrc_pci_id_table) = {  		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829),  		.driver_data = (kernel_ulong_t)&penwell_pci_platdata,  	}, -	{ 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ } +	{ +		/* Intel Clovertrail */ +		PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe006), +		.driver_data = (kernel_ulong_t)&penwell_pci_platdata, +	}, +	{ 0 } /* end: all zeroes */  };  MODULE_DEVICE_TABLE(pci, ci_hdrc_pci_id_table); diff --git a/drivers/usb/chipidea/ci_hdrc_zevio.c b/drivers/usb/chipidea/ci_hdrc_zevio.c new file mode 100644 index 00000000000..3bf6489ef5e --- /dev/null +++ b/drivers/usb/chipidea/ci_hdrc_zevio.c @@ -0,0 +1,72 @@ +/* + *	Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * Based off drivers/usb/chipidea/ci_hdrc_msm.c + * + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/usb/gadget.h> +#include <linux/usb/chipidea.h> + +#include "ci.h" + +static struct ci_hdrc_platform_data ci_hdrc_zevio_platdata = { +	.name			= "ci_hdrc_zevio", +	.flags			= CI_HDRC_REGS_SHARED, +	.capoffset		= DEF_CAPOFFSET, +}; + +static int ci_hdrc_zevio_probe(struct platform_device *pdev) +{ +	struct platform_device *ci_pdev; + +	dev_dbg(&pdev->dev, "ci_hdrc_zevio_probe\n"); + +	ci_pdev = ci_hdrc_add_device(&pdev->dev, +				pdev->resource, pdev->num_resources, +				&ci_hdrc_zevio_platdata); + +	if (IS_ERR(ci_pdev)) { +		dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n"); +		return PTR_ERR(ci_pdev); +	} + +	platform_set_drvdata(pdev, ci_pdev); + +	return 0; +} + +static int ci_hdrc_zevio_remove(struct platform_device *pdev) +{ +	struct platform_device *ci_pdev = platform_get_drvdata(pdev); + +	ci_hdrc_remove_device(ci_pdev); + +	return 0; +} + +static const struct of_device_id ci_hdrc_zevio_dt_ids[] = { +	{ .compatible = "lsi,zevio-usb", }, +	{ /* sentinel */ } +}; + +static struct platform_driver ci_hdrc_zevio_driver = { +	.probe = ci_hdrc_zevio_probe, +	.remove = ci_hdrc_zevio_remove, +	.driver = { +		.name = "zevio_usb", +		.owner = THIS_MODULE, +		.of_match_table = ci_hdrc_zevio_dt_ids, +	}, +}; + +MODULE_DEVICE_TABLE(of, ci_hdrc_zevio_dt_ids); +module_platform_driver(ci_hdrc_zevio_driver); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 94626409559..619d13e2999 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -23,7 +23,7 @@   * - BUS:    bus glue code, bus abstraction layer   *   * Compile Options - * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities + * - CONFIG_USB_CHIPIDEA_DEBUG: enable debug facilities   * - STALL_IN:  non-empty bulk-in pipes cannot be halted   *              if defined mass storage compliance succeeds but with warnings   *              => case 4: Hi >  Dn @@ -42,10 +42,6 @@   * - Not Supported: 15 & 16 (ISO)   *   * TODO List - * - OTG - * - Interrupt Traffic - * - GET_STATUS(device) - always reports 0 - * - Gadget API (majority of optional features)   * - Suspend & Remote Wakeup   */  #include <linux/delay.h> @@ -64,6 +60,7 @@  #include <linux/usb/otg.h>  #include <linux/usb/chipidea.h>  #include <linux/usb/of.h> +#include <linux/of.h>  #include <linux/phy.h>  #include <linux/regulator/consumer.h> @@ -73,63 +70,57 @@  #include "host.h"  #include "debug.h"  #include "otg.h" +#include "otg_fsm.h"  /* Controller register map */ -static uintptr_t ci_regs_nolpm[] = { -	[CAP_CAPLENGTH]		= 0x000UL, -	[CAP_HCCPARAMS]		= 0x008UL, -	[CAP_DCCPARAMS]		= 0x024UL, -	[CAP_TESTMODE]		= 0x038UL, -	[OP_USBCMD]		= 0x000UL, -	[OP_USBSTS]		= 0x004UL, -	[OP_USBINTR]		= 0x008UL, -	[OP_DEVICEADDR]		= 0x014UL, -	[OP_ENDPTLISTADDR]	= 0x018UL, -	[OP_PORTSC]		= 0x044UL, -	[OP_DEVLC]		= 0x084UL, -	[OP_OTGSC]		= 0x064UL, -	[OP_USBMODE]		= 0x068UL, -	[OP_ENDPTSETUPSTAT]	= 0x06CUL, -	[OP_ENDPTPRIME]		= 0x070UL, -	[OP_ENDPTFLUSH]		= 0x074UL, -	[OP_ENDPTSTAT]		= 0x078UL, -	[OP_ENDPTCOMPLETE]	= 0x07CUL, -	[OP_ENDPTCTRL]		= 0x080UL, +static const u8 ci_regs_nolpm[] = { +	[CAP_CAPLENGTH]		= 0x00U, +	[CAP_HCCPARAMS]		= 0x08U, +	[CAP_DCCPARAMS]		= 0x24U, +	[CAP_TESTMODE]		= 0x38U, +	[OP_USBCMD]		= 0x00U, +	[OP_USBSTS]		= 0x04U, +	[OP_USBINTR]		= 0x08U, +	[OP_DEVICEADDR]		= 0x14U, +	[OP_ENDPTLISTADDR]	= 0x18U, +	[OP_PORTSC]		= 0x44U, +	[OP_DEVLC]		= 0x84U, +	[OP_OTGSC]		= 0x64U, +	[OP_USBMODE]		= 0x68U, +	[OP_ENDPTSETUPSTAT]	= 0x6CU, +	[OP_ENDPTPRIME]		= 0x70U, +	[OP_ENDPTFLUSH]		= 0x74U, +	[OP_ENDPTSTAT]		= 0x78U, +	[OP_ENDPTCOMPLETE]	= 0x7CU, +	[OP_ENDPTCTRL]		= 0x80U,  }; -static uintptr_t ci_regs_lpm[] = { -	[CAP_CAPLENGTH]		= 0x000UL, -	[CAP_HCCPARAMS]		= 0x008UL, -	[CAP_DCCPARAMS]		= 0x024UL, -	[CAP_TESTMODE]		= 0x0FCUL, -	[OP_USBCMD]		= 0x000UL, -	[OP_USBSTS]		= 0x004UL, -	[OP_USBINTR]		= 0x008UL, -	[OP_DEVICEADDR]		= 0x014UL, -	[OP_ENDPTLISTADDR]	= 0x018UL, -	[OP_PORTSC]		= 0x044UL, -	[OP_DEVLC]		= 0x084UL, -	[OP_OTGSC]		= 0x0C4UL, -	[OP_USBMODE]		= 0x0C8UL, -	[OP_ENDPTSETUPSTAT]	= 0x0D8UL, -	[OP_ENDPTPRIME]		= 0x0DCUL, -	[OP_ENDPTFLUSH]		= 0x0E0UL, -	[OP_ENDPTSTAT]		= 0x0E4UL, -	[OP_ENDPTCOMPLETE]	= 0x0E8UL, -	[OP_ENDPTCTRL]		= 0x0ECUL, +static const u8 ci_regs_lpm[] = { +	[CAP_CAPLENGTH]		= 0x00U, +	[CAP_HCCPARAMS]		= 0x08U, +	[CAP_DCCPARAMS]		= 0x24U, +	[CAP_TESTMODE]		= 0xFCU, +	[OP_USBCMD]		= 0x00U, +	[OP_USBSTS]		= 0x04U, +	[OP_USBINTR]		= 0x08U, +	[OP_DEVICEADDR]		= 0x14U, +	[OP_ENDPTLISTADDR]	= 0x18U, +	[OP_PORTSC]		= 0x44U, +	[OP_DEVLC]		= 0x84U, +	[OP_OTGSC]		= 0xC4U, +	[OP_USBMODE]		= 0xC8U, +	[OP_ENDPTSETUPSTAT]	= 0xD8U, +	[OP_ENDPTPRIME]		= 0xDCU, +	[OP_ENDPTFLUSH]		= 0xE0U, +	[OP_ENDPTSTAT]		= 0xE4U, +	[OP_ENDPTCOMPLETE]	= 0xE8U, +	[OP_ENDPTCTRL]		= 0xECU,  };  static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm)  {  	int i; -	kfree(ci->hw_bank.regmap); - -	ci->hw_bank.regmap = kzalloc((OP_LAST + 1) * sizeof(void *), -				     GFP_KERNEL); -	if (!ci->hw_bank.regmap) -		return -ENOMEM; -  	for (i = 0; i < OP_ENDPTCTRL; i++)  		ci->hw_bank.regmap[i] =  			(i <= CAP_LAST ? ci->hw_bank.cap : ci->hw_bank.op) + @@ -146,6 +137,26 @@ static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm)  }  /** + * hw_read_intr_enable: returns interrupt enable register + * + * This function returns register data + */ +u32 hw_read_intr_enable(struct ci_hdrc *ci) +{ +	return hw_read(ci, OP_USBINTR, ~0); +} + +/** + * hw_read_intr_status: returns interrupt status register + * + * This function returns register data + */ +u32 hw_read_intr_status(struct ci_hdrc *ci) +{ +	return hw_read(ci, OP_USBSTS, ~0); +} + +/**   * hw_port_test_set: writes port test mode (execute without interruption)   * @mode: new value   * @@ -172,6 +183,26 @@ u8 hw_port_test_get(struct ci_hdrc *ci)  	return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC);  } +/* The PHY enters/leaves low power mode */ +static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable) +{ +	enum ci_hw_regs reg = ci->hw_bank.lpm ? OP_DEVLC : OP_PORTSC; +	bool lpm = !!(hw_read(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm))); + +	if (enable && !lpm) { +		hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), +				PORTSC_PHCD(ci->hw_bank.lpm)); +	} else  if (!enable && lpm) { +		hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm), +				0); +		/*  +		 * the PHY needs some time (less +		 * than 1ms) to leave low power mode. +		 */ +		usleep_range(1000, 1100); +	} +} +  static int hw_device_init(struct ci_hdrc *ci, void __iomem *base)  {  	u32 reg; @@ -187,7 +218,8 @@ static int hw_device_init(struct ci_hdrc *ci, void __iomem *base)  	reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >>  		__ffs(HCCPARAMS_LEN);  	ci->hw_bank.lpm  = reg; -	hw_alloc_regmap(ci, !!reg); +	if (reg) +		hw_alloc_regmap(ci, !!reg);  	ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs;  	ci->hw_bank.size += OP_LAST;  	ci->hw_bank.size /= sizeof(u32); @@ -199,6 +231,8 @@ static int hw_device_init(struct ci_hdrc *ci, void __iomem *base)  	if (ci->hw_ep_max > ENDPT_MAX)  		return -ENODEV; +	ci_hdrc_enter_lpm(ci, false); +  	/* Disable all interrupts bits */  	hw_write(ci, OP_USBINTR, 0xffffffff, 0); @@ -219,7 +253,7 @@ static int hw_device_init(struct ci_hdrc *ci, void __iomem *base)  static void hw_phymode_configure(struct ci_hdrc *ci)  { -	u32 portsc, lpm, sts; +	u32 portsc, lpm, sts = 0;  	switch (ci->platdata->phy_mode) {  	case USBPHY_INTERFACE_MODE_UTMI: @@ -249,14 +283,49 @@ static void hw_phymode_configure(struct ci_hdrc *ci)  	if (ci->hw_bank.lpm) {  		hw_write(ci, OP_DEVLC, DEVLC_PTS(7) | DEVLC_PTW, lpm); -		hw_write(ci, OP_DEVLC, DEVLC_STS, sts); +		if (sts) +			hw_write(ci, OP_DEVLC, DEVLC_STS, DEVLC_STS);  	} else {  		hw_write(ci, OP_PORTSC, PORTSC_PTS(7) | PORTSC_PTW, portsc); -		hw_write(ci, OP_PORTSC, PORTSC_STS, sts); +		if (sts) +			hw_write(ci, OP_PORTSC, PORTSC_STS, PORTSC_STS);  	}  }  /** + * ci_usb_phy_init: initialize phy according to different phy type + * @ci: the controller +  * + * This function returns an error code if usb_phy_init has failed + */ +static int ci_usb_phy_init(struct ci_hdrc *ci) +{ +	int ret; + +	switch (ci->platdata->phy_mode) { +	case USBPHY_INTERFACE_MODE_UTMI: +	case USBPHY_INTERFACE_MODE_UTMIW: +	case USBPHY_INTERFACE_MODE_HSIC: +		ret = usb_phy_init(ci->transceiver); +		if (ret) +			return ret; +		hw_phymode_configure(ci); +		break; +	case USBPHY_INTERFACE_MODE_ULPI: +	case USBPHY_INTERFACE_MODE_SERIAL: +		hw_phymode_configure(ci); +		ret = usb_phy_init(ci->transceiver); +		if (ret) +			return ret; +		break; +	default: +		ret = usb_phy_init(ci->transceiver); +	} + +	return ret; +} + +/**   * hw_device_reset: resets chip (execute without interruption)   * @ci: the controller    * @@ -279,6 +348,13 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode)  	if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)  		hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); +	if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) { +		if (ci->hw_bank.lpm) +			hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC); +		else +			hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC); +	} +  	/* USBMODE should be configured step by step */  	hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);  	hw_write(ci, OP_USBMODE, USBMODE_CM, mode); @@ -332,8 +408,14 @@ static irqreturn_t ci_irq(int irq, void *data)  	irqreturn_t ret = IRQ_NONE;  	u32 otgsc = 0; -	if (ci->is_otg) -		otgsc = hw_read(ci, OP_OTGSC, ~0); +	if (ci->is_otg) { +		otgsc = hw_read_otgsc(ci, ~0); +		if (ci_otg_is_fsm_mode(ci)) { +			ret = ci_otg_fsm_irq(ci); +			if (ret == IRQ_HANDLED) +				return ret; +		} +	}  	/*  	 * Handle id change interrupt, it indicates device/host function @@ -341,9 +423,9 @@ static irqreturn_t ci_irq(int irq, void *data)  	 */  	if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {  		ci->id_event = true; -		ci_clear_otg_interrupt(ci, OTGSC_IDIS); -		disable_irq_nosync(ci->irq); -		queue_work(ci->wq, &ci->work); +		/* Clear ID change irq status */ +		hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS); +		ci_otg_queue_work(ci);  		return IRQ_HANDLED;  	} @@ -353,9 +435,9 @@ static irqreturn_t ci_irq(int irq, void *data)  	 */  	if (ci->is_otg && (otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {  		ci->b_sess_valid_event = true; -		ci_clear_otg_interrupt(ci, OTGSC_BSVIS); -		disable_irq_nosync(ci->irq); -		queue_work(ci->wq, &ci->work); +		/* Clear BSV irq */ +		hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS); +		ci_otg_queue_work(ci);  		return IRQ_HANDLED;  	} @@ -369,18 +451,33 @@ static irqreturn_t ci_irq(int irq, void *data)  static int ci_get_platdata(struct device *dev,  		struct ci_hdrc_platform_data *platdata)  { -	/* Get the vbus regulator */ -	platdata->reg_vbus = devm_regulator_get(dev, "vbus"); -	if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) { -		return -EPROBE_DEFER; -	} else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) { -		platdata->reg_vbus = NULL; /* no vbus regualator is needed */ -	} else if (IS_ERR(platdata->reg_vbus)) { -		dev_err(dev, "Getting regulator error: %ld\n", -			PTR_ERR(platdata->reg_vbus)); -		return PTR_ERR(platdata->reg_vbus); +	if (!platdata->phy_mode) +		platdata->phy_mode = of_usb_get_phy_mode(dev->of_node); + +	if (!platdata->dr_mode) +		platdata->dr_mode = of_usb_get_dr_mode(dev->of_node); + +	if (platdata->dr_mode == USB_DR_MODE_UNKNOWN) +		platdata->dr_mode = USB_DR_MODE_OTG; + +	if (platdata->dr_mode != USB_DR_MODE_PERIPHERAL) { +		/* Get the vbus regulator */ +		platdata->reg_vbus = devm_regulator_get(dev, "vbus"); +		if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) { +			return -EPROBE_DEFER; +		} else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) { +			/* no vbus regualator is needed */ +			platdata->reg_vbus = NULL; +		} else if (IS_ERR(platdata->reg_vbus)) { +			dev_err(dev, "Getting regulator error: %ld\n", +				PTR_ERR(platdata->reg_vbus)); +			return PTR_ERR(platdata->reg_vbus); +		}  	} +	if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL) +		platdata->flags |= CI_HDRC_FORCE_FULLSPEED; +  	return 0;  } @@ -458,11 +555,8 @@ static void ci_get_otg_capable(struct ci_hdrc *ci)  		ci->is_otg = (hw_read(ci, CAP_DCCPARAMS,  				DCCPARAMS_DC | DCCPARAMS_HC)  					== (DCCPARAMS_DC | DCCPARAMS_HC)); -	if (ci->is_otg) { +	if (ci->is_otg)  		dev_dbg(ci->dev, "It is OTG capable controller\n"); -		ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS); -		ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS); -	}  }  static int ci_hdrc_probe(struct platform_device *pdev) @@ -473,9 +567,8 @@ static int ci_hdrc_probe(struct platform_device *pdev)  	void __iomem	*base;  	int		ret;  	enum usb_dr_mode dr_mode; -	struct device_node *of_node = dev->of_node ?: dev->parent->of_node; -	if (!dev->platform_data) { +	if (!dev_get_platdata(dev)) {  		dev_err(dev, "platform data missing\n");  		return -ENODEV;  	} @@ -492,11 +585,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)  	}  	ci->dev = dev; -	ci->platdata = dev->platform_data; -	if (ci->platdata->phy) -		ci->transceiver = ci->platdata->phy; -	else -		ci->global_phy = true; +	ci->platdata = dev_get_platdata(dev); +	ci->imx28_write_fix = !!(ci->platdata->flags & +		CI_HDRC_IMX28_WRITE_FIX);  	ret = hw_device_init(ci, base);  	if (ret < 0) { @@ -504,27 +595,49 @@ static int ci_hdrc_probe(struct platform_device *pdev)  		return -ENODEV;  	} +	if (ci->platdata->phy) +		ci->transceiver = ci->platdata->phy; +	else +		ci->transceiver = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); + +	if (IS_ERR(ci->transceiver)) { +		ret = PTR_ERR(ci->transceiver); +		/* +		 * if -ENXIO is returned, it means PHY layer wasn't +		 * enabled, so it makes no sense to return -EPROBE_DEFER +		 * in that case, since no PHY driver will ever probe. +		 */ +		if (ret == -ENXIO) +			return ret; + +		dev_err(dev, "no usb2 phy configured\n"); +		return -EPROBE_DEFER; +	} + +	ret = ci_usb_phy_init(ci); +	if (ret) { +		dev_err(dev, "unable to init phy: %d\n", ret); +		return ret; +	} else { +		/*  +		 * The delay to sync PHY's status, the maximum delay is +		 * 2ms since the otgsc uses 1ms timer to debounce the +		 * PHY's input +		 */ +		usleep_range(2000, 2500); +	} +  	ci->hw_bank.phys = res->start;  	ci->irq = platform_get_irq(pdev, 0);  	if (ci->irq < 0) {  		dev_err(dev, "missing IRQ\n"); -		return -ENODEV; +		ret = ci->irq; +		goto deinit_phy;  	}  	ci_get_otg_capable(ci); -	if (!ci->platdata->phy_mode) -		ci->platdata->phy_mode = of_usb_get_phy_mode(of_node); - -	hw_phymode_configure(ci); - -	if (!ci->platdata->dr_mode) -		ci->platdata->dr_mode = of_usb_get_dr_mode(of_node); - -	if (ci->platdata->dr_mode == USB_DR_MODE_UNKNOWN) -		ci->platdata->dr_mode = USB_DR_MODE_OTG; -  	dr_mode = ci->platdata->dr_mode;  	/* initialize role(s) before the interrupt is requested */  	if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { @@ -541,10 +654,14 @@ static int ci_hdrc_probe(struct platform_device *pdev)  	if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {  		dev_err(dev, "no supported roles\n"); -		return -ENODEV; +		ret = -ENODEV; +		goto deinit_phy;  	}  	if (ci->is_otg) { +		/* Disable and clear all OTG irq */ +		hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS, +							OTGSC_INT_STATUS_BITS);  		ret = ci_hdrc_otg_init(ci);  		if (ret) {  			dev_err(dev, "init otg fails, ret = %d\n", ret); @@ -554,13 +671,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)  	if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {  		if (ci->is_otg) { -			/* -			 * ID pin needs 1ms debouce time, -			 * we delay 2ms for safe. -			 */ -			mdelay(2);  			ci->role = ci_otg_role(ci); -			ci_enable_otg_interrupt(ci, OTGSC_IDIE); +			/* Enable ID change irq */ +			hw_write_otgsc(ci, OTGSC_IDIE, OTGSC_IDIE);  		} else {  			/*  			 * If the controller is not OTG capable, but support @@ -575,10 +688,17 @@ static int ci_hdrc_probe(struct platform_device *pdev)  			: CI_ROLE_GADGET;  	} -	ret = ci_role_start(ci, ci->role); -	if (ret) { -		dev_err(dev, "can't start %s role\n", ci_role(ci)->name); -		goto stop; +	/* only update vbus status for peripheral */ +	if (ci->role == CI_ROLE_GADGET) +		ci_handle_vbus_change(ci); + +	if (!ci_otg_is_fsm_mode(ci)) { +		ret = ci_role_start(ci, ci->role); +		if (ret) { +			dev_err(dev, "can't start %s role\n", +						ci_role(ci)->name); +			goto stop; +		}  	}  	platform_set_drvdata(pdev, ci); @@ -587,6 +707,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)  	if (ret)  		goto stop; +	if (ci_otg_is_fsm_mode(ci)) +		ci_hdrc_otg_fsm_start(ci); +  	ret = dbg_create_files(ci);  	if (!ret)  		return 0; @@ -594,6 +717,8 @@ static int ci_hdrc_probe(struct platform_device *pdev)  	free_irq(ci->irq, ci);  stop:  	ci_role_destroy(ci); +deinit_phy: +	usb_phy_shutdown(ci->transceiver);  	return ret;  } @@ -605,6 +730,9 @@ static int ci_hdrc_remove(struct platform_device *pdev)  	dbg_remove_files(ci);  	free_irq(ci->irq, ci);  	ci_role_destroy(ci); +	ci_hdrc_enter_lpm(ci, true); +	usb_phy_shutdown(ci->transceiver); +	kfree(ci->hw_bank.regmap);  	return 0;  } @@ -614,6 +742,7 @@ static struct platform_driver ci_hdrc_driver = {  	.remove	= ci_hdrc_remove,  	.driver	= {  		.name	= "ci_hdrc", +		.owner	= THIS_MODULE,  	},  }; diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index 96d899aee47..7cccab6ff30 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -7,11 +7,15 @@  #include <linux/uaccess.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h> +#include <linux/usb/phy.h> +#include <linux/usb/otg.h> +#include <linux/usb/otg-fsm.h>  #include "ci.h"  #include "udc.h"  #include "bits.h"  #include "debug.h" +#include "otg.h"  /**   * ci_device_show: prints information about device capabilities and status @@ -204,6 +208,80 @@ static const struct file_operations ci_requests_fops = {  	.release	= single_release,  }; +int ci_otg_show(struct seq_file *s, void *unused) +{ +	struct ci_hdrc *ci = s->private; +	struct otg_fsm *fsm; + +	if (!ci || !ci_otg_is_fsm_mode(ci)) +		return 0; + +	fsm = &ci->fsm; + +	/* ------ State ----- */ +	seq_printf(s, "OTG state: %s\n\n", +		usb_otg_state_string(ci->transceiver->state)); + +	/* ------ State Machine Variables ----- */ +	seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop); + +	seq_printf(s, "a_bus_req: %d\n", fsm->a_bus_req); + +	seq_printf(s, "a_srp_det: %d\n", fsm->a_srp_det); + +	seq_printf(s, "a_vbus_vld: %d\n", fsm->a_vbus_vld); + +	seq_printf(s, "b_conn: %d\n", fsm->b_conn); + +	seq_printf(s, "adp_change: %d\n", fsm->adp_change); + +	seq_printf(s, "power_up: %d\n", fsm->power_up); + +	seq_printf(s, "a_bus_resume: %d\n", fsm->a_bus_resume); + +	seq_printf(s, "a_bus_suspend: %d\n", fsm->a_bus_suspend); + +	seq_printf(s, "a_conn: %d\n", fsm->a_conn); + +	seq_printf(s, "b_bus_req: %d\n", fsm->b_bus_req); + +	seq_printf(s, "b_bus_suspend: %d\n", fsm->b_bus_suspend); + +	seq_printf(s, "b_se0_srp: %d\n", fsm->b_se0_srp); + +	seq_printf(s, "b_ssend_srp: %d\n", fsm->b_ssend_srp); + +	seq_printf(s, "b_sess_vld: %d\n", fsm->b_sess_vld); + +	seq_printf(s, "b_srp_done: %d\n", fsm->b_srp_done); + +	seq_printf(s, "drv_vbus: %d\n", fsm->drv_vbus); + +	seq_printf(s, "loc_conn: %d\n", fsm->loc_conn); + +	seq_printf(s, "loc_sof: %d\n", fsm->loc_sof); + +	seq_printf(s, "adp_prb: %d\n", fsm->adp_prb); + +	seq_printf(s, "id: %d\n", fsm->id); + +	seq_printf(s, "protocol: %d\n", fsm->protocol); + +	return 0; +} + +static int ci_otg_open(struct inode *inode, struct file *file) +{ +	return single_open(file, ci_otg_show, inode->i_private); +} + +static const struct file_operations ci_otg_fops = { +	.open			= ci_otg_open, +	.read			= seq_read, +	.llseek			= seq_lseek, +	.release		= single_release, +}; +  static int ci_role_show(struct seq_file *s, void *data)  {  	struct ci_hdrc *ci = s->private; @@ -253,6 +331,50 @@ static const struct file_operations ci_role_fops = {  	.release	= single_release,  }; +int ci_registers_show(struct seq_file *s, void *unused) +{ +	struct ci_hdrc *ci = s->private; +	u32 tmp_reg; + +	if (!ci) +		return 0; + +	/* ------ Registers ----- */ +	tmp_reg = hw_read_intr_enable(ci); +	seq_printf(s, "USBINTR reg: %08x\n", tmp_reg); + +	tmp_reg = hw_read_intr_status(ci); +	seq_printf(s, "USBSTS reg: %08x\n", tmp_reg); + +	tmp_reg = hw_read(ci, OP_USBMODE, ~0); +	seq_printf(s, "USBMODE reg: %08x\n", tmp_reg); + +	tmp_reg = hw_read(ci, OP_USBCMD, ~0); +	seq_printf(s, "USBCMD reg: %08x\n", tmp_reg); + +	tmp_reg = hw_read(ci, OP_PORTSC, ~0); +	seq_printf(s, "PORTSC reg: %08x\n", tmp_reg); + +	if (ci->is_otg) { +		tmp_reg = hw_read_otgsc(ci, ~0); +		seq_printf(s, "OTGSC reg: %08x\n", tmp_reg); +	} + +	return 0; +} + +static int ci_registers_open(struct inode *inode, struct file *file) +{ +	return single_open(file, ci_registers_show, inode->i_private); +} + +static const struct file_operations ci_registers_fops = { +	.open			= ci_registers_open, +	.read			= seq_read, +	.llseek			= seq_lseek, +	.release		= single_release, +}; +  /**   * dbg_create_files: initializes the attribute interface   * @ci: device @@ -287,8 +409,21 @@ int dbg_create_files(struct ci_hdrc *ci)  	if (!dent)  		goto err; +	if (ci_otg_is_fsm_mode(ci)) { +		dent = debugfs_create_file("otg", S_IRUGO, ci->debugfs, ci, +					&ci_otg_fops); +		if (!dent) +			goto err; +	} +  	dent = debugfs_create_file("role", S_IRUGO | S_IWUSR, ci->debugfs, ci,  				   &ci_role_fops); +	if (!dent) +		goto err; + +	dent = debugfs_create_file("registers", S_IRUGO, ci->debugfs, ci, +				&ci_registers_fops); +  	if (dent)  		return 0;  err: diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 6f96795dd20..a93d950e946 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -65,8 +65,13 @@ static int host_start(struct ci_hdrc *ci)  	ehci->caps = ci->hw_bank.cap;  	ehci->has_hostpc = ci->hw_bank.lpm;  	ehci->has_tdi_phy_lpm = ci->hw_bank.lpm; +	ehci->imx28_write_fix = ci->imx28_write_fix; -	if (ci->platdata->reg_vbus) { +	/* +	 * vbus is always on if host is not in OTG FSM mode, +	 * otherwise should be controlled by OTG FSM +	 */ +	if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) {  		ret = regulator_enable(ci->platdata->reg_vbus);  		if (ret) {  			dev_err(ci->dev, @@ -77,10 +82,17 @@ static int host_start(struct ci_hdrc *ci)  	}  	ret = usb_add_hcd(hcd, 0, 0); -	if (ret) +	if (ret) {  		goto disable_reg; -	else +	} else { +		struct usb_otg *otg = ci->transceiver->otg; +  		ci->hcd = hcd; +		if (otg) { +			otg->host = &hcd->self; +			hcd->self.otg_port = 1; +		} +	}  	if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)  		hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); @@ -88,7 +100,8 @@ static int host_start(struct ci_hdrc *ci)  	return ret;  disable_reg: -	regulator_disable(ci->platdata->reg_vbus); +	if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) +		regulator_disable(ci->platdata->reg_vbus);  put_hcd:  	usb_put_hcd(hcd); @@ -100,16 +113,18 @@ static void host_stop(struct ci_hdrc *ci)  {  	struct usb_hcd *hcd = ci->hcd; -	usb_remove_hcd(hcd); -	usb_put_hcd(hcd); -	if (ci->platdata->reg_vbus) -		regulator_disable(ci->platdata->reg_vbus); +	if (hcd) { +		usb_remove_hcd(hcd); +		usb_put_hcd(hcd); +		if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) +			regulator_disable(ci->platdata->reg_vbus); +	}  }  void ci_hdrc_host_destroy(struct ci_hdrc *ci)  { -	if (ci->role == CI_ROLE_HOST) +	if (ci->role == CI_ROLE_HOST && ci->hcd)  		host_stop(ci);  } diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 39bd7ec8bf7..a048b08b9d4 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -11,8 +11,8 @@   */  /* - * This file mainly handles otgsc register, it may include OTG operation - * in the future. + * This file mainly handles otgsc register, OTG fsm operations for HNP and SRP + * are also included.   */  #include <linux/usb/otg.h> @@ -22,6 +22,26 @@  #include "ci.h"  #include "bits.h"  #include "otg.h" +#include "otg_fsm.h" + +/** + * hw_read_otgsc returns otgsc register bits value. + * @mask: bitfield mask + */ +u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) +{ +	return hw_read(ci, OP_OTGSC, mask); +} + +/** + * hw_write_otgsc updates target bits of OTGSC register. + * @mask: bitfield mask + * @data: to be written + */ +void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data) +{ +	hw_write(ci, OP_OTGSC, mask | OTGSC_INT_STATUS_BITS, data); +}  /**   * ci_otg_role - pick role based on ID pin state @@ -29,8 +49,7 @@   */  enum ci_role ci_otg_role(struct ci_hdrc *ci)  { -	u32 sts = hw_read(ci, OP_OTGSC, ~0); -	enum ci_role role = sts & OTGSC_ID +	enum ci_role role = hw_read_otgsc(ci, OTGSC_ID)  		? CI_ROLE_GADGET  		: CI_ROLE_HOST; @@ -39,14 +58,10 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci)  void ci_handle_vbus_change(struct ci_hdrc *ci)  { -	u32 otgsc; -  	if (!ci->is_otg)  		return; -	otgsc = hw_read(ci, OP_OTGSC, ~0); - -	if (otgsc & OTGSC_BSV) +	if (hw_read_otgsc(ci, OTGSC_BSV))  		usb_gadget_vbus_connect(&ci->gadget);  	else  		usb_gadget_vbus_disconnect(&ci->gadget); @@ -76,6 +91,11 @@ static void ci_otg_work(struct work_struct *work)  {  	struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); +	if (ci_otg_is_fsm_mode(ci) && !ci_otg_fsm_work(ci)) { +		enable_irq(ci->irq); +		return; +	} +  	if (ci->id_event) {  		ci->id_event = false;  		ci_handle_id_switch(ci); @@ -102,6 +122,9 @@ int ci_hdrc_otg_init(struct ci_hdrc *ci)  		return -ENODEV;  	} +	if (ci_otg_is_fsm_mode(ci)) +		return ci_hdrc_otg_fsm_init(ci); +  	return 0;  } @@ -115,6 +138,9 @@ void ci_hdrc_otg_destroy(struct ci_hdrc *ci)  		flush_workqueue(ci->wq);  		destroy_workqueue(ci->wq);  	} -	ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS); -	ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS); +	/* Disable all OTG irq and clear status */ +	hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS, +						OTGSC_INT_STATUS_BITS); +	if (ci_otg_is_fsm_mode(ci)) +		ci_hdrc_otg_fsm_remove(ci);  } diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h index 2d9f090733b..9ecb598e48f 100644 --- a/drivers/usb/chipidea/otg.h +++ b/drivers/usb/chipidea/otg.h @@ -1,5 +1,5 @@  /* - * Copyright (C) 2013 Freescale Semiconductor, Inc. + * Copyright (C) 2013-2014 Freescale Semiconductor, Inc.   *   * Author: Peter Chen   * @@ -11,25 +11,16 @@  #ifndef __DRIVERS_USB_CHIPIDEA_OTG_H  #define __DRIVERS_USB_CHIPIDEA_OTG_H -static inline void ci_clear_otg_interrupt(struct ci_hdrc *ci, u32 bits) -{ -	/* Only clear request bits */ -	hw_write(ci, OP_OTGSC, OTGSC_INT_STATUS_BITS, bits); -} - -static inline void ci_enable_otg_interrupt(struct ci_hdrc *ci, u32 bits) -{ -	hw_write(ci, OP_OTGSC, bits, bits); -} - -static inline void ci_disable_otg_interrupt(struct ci_hdrc *ci, u32 bits) -{ -	hw_write(ci, OP_OTGSC, bits, 0); -} - +u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask); +void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data);  int ci_hdrc_otg_init(struct ci_hdrc *ci);  void ci_hdrc_otg_destroy(struct ci_hdrc *ci);  enum ci_role ci_otg_role(struct ci_hdrc *ci);  void ci_handle_vbus_change(struct ci_hdrc *ci); +static inline void ci_otg_queue_work(struct ci_hdrc *ci) +{ +	disable_irq_nosync(ci->irq); +	queue_work(ci->wq, &ci->work); +}  #endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */ diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c new file mode 100644 index 00000000000..caaabc58021 --- /dev/null +++ b/drivers/usb/chipidea/otg_fsm.c @@ -0,0 +1,842 @@ +/* + * otg_fsm.c - ChipIdea USB IP core OTG FSM driver + * + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Jun Li + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This file mainly handles OTG fsm, it includes OTG fsm operations + * for HNP and SRP. + * + * TODO List + * - ADP + * - OTG test device + */ + +#include <linux/usb/otg.h> +#include <linux/usb/gadget.h> +#include <linux/usb/hcd.h> +#include <linux/usb/chipidea.h> +#include <linux/regulator/consumer.h> + +#include "ci.h" +#include "bits.h" +#include "otg.h" +#include "otg_fsm.h" + +static struct ci_otg_fsm_timer *otg_timer_initializer +(struct ci_hdrc *ci, void (*function)(void *, unsigned long), +			unsigned long expires, unsigned long data) +{ +	struct ci_otg_fsm_timer *timer; + +	timer = devm_kzalloc(ci->dev, sizeof(struct ci_otg_fsm_timer), +								GFP_KERNEL); +	if (!timer) +		return NULL; +	timer->function = function; +	timer->expires = expires; +	timer->data = data; +	return timer; +} + +/* Add for otg: interact with user space app */ +static ssize_t +get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ +	char		*next; +	unsigned	size, t; +	struct ci_hdrc	*ci = dev_get_drvdata(dev); + +	next = buf; +	size = PAGE_SIZE; +	t = scnprintf(next, size, "%d\n", ci->fsm.a_bus_req); +	size -= t; +	next += t; + +	return PAGE_SIZE - size; +} + +static ssize_t +set_a_bus_req(struct device *dev, struct device_attribute *attr, +					const char *buf, size_t count) +{ +	struct ci_hdrc *ci = dev_get_drvdata(dev); + +	if (count > 2) +		return -1; + +	mutex_lock(&ci->fsm.lock); +	if (buf[0] == '0') { +		ci->fsm.a_bus_req = 0; +	} else if (buf[0] == '1') { +		/* If a_bus_drop is TRUE, a_bus_req can't be set */ +		if (ci->fsm.a_bus_drop) { +			mutex_unlock(&ci->fsm.lock); +			return count; +		} +		ci->fsm.a_bus_req = 1; +	} + +	ci_otg_queue_work(ci); +	mutex_unlock(&ci->fsm.lock); + +	return count; +} +static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req, set_a_bus_req); + +static ssize_t +get_a_bus_drop(struct device *dev, struct device_attribute *attr, char *buf) +{ +	char		*next; +	unsigned	size, t; +	struct ci_hdrc	*ci = dev_get_drvdata(dev); + +	next = buf; +	size = PAGE_SIZE; +	t = scnprintf(next, size, "%d\n", ci->fsm.a_bus_drop); +	size -= t; +	next += t; + +	return PAGE_SIZE - size; +} + +static ssize_t +set_a_bus_drop(struct device *dev, struct device_attribute *attr, +					const char *buf, size_t count) +{ +	struct ci_hdrc	*ci = dev_get_drvdata(dev); + +	if (count > 2) +		return -1; + +	mutex_lock(&ci->fsm.lock); +	if (buf[0] == '0') { +		ci->fsm.a_bus_drop = 0; +	} else if (buf[0] == '1') { +		ci->fsm.a_bus_drop = 1; +		ci->fsm.a_bus_req = 0; +	} + +	ci_otg_queue_work(ci); +	mutex_unlock(&ci->fsm.lock); + +	return count; +} +static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR, get_a_bus_drop, +						set_a_bus_drop); + +static ssize_t +get_b_bus_req(struct device *dev, struct device_attribute *attr, char *buf) +{ +	char		*next; +	unsigned	size, t; +	struct ci_hdrc	*ci = dev_get_drvdata(dev); + +	next = buf; +	size = PAGE_SIZE; +	t = scnprintf(next, size, "%d\n", ci->fsm.b_bus_req); +	size -= t; +	next += t; + +	return PAGE_SIZE - size; +} + +static ssize_t +set_b_bus_req(struct device *dev, struct device_attribute *attr, +					const char *buf, size_t count) +{ +	struct ci_hdrc	*ci = dev_get_drvdata(dev); + +	if (count > 2) +		return -1; + +	mutex_lock(&ci->fsm.lock); +	if (buf[0] == '0') +		ci->fsm.b_bus_req = 0; +	else if (buf[0] == '1') +		ci->fsm.b_bus_req = 1; + +	ci_otg_queue_work(ci); +	mutex_unlock(&ci->fsm.lock); + +	return count; +} +static DEVICE_ATTR(b_bus_req, S_IRUGO | S_IWUSR, get_b_bus_req, set_b_bus_req); + +static ssize_t +set_a_clr_err(struct device *dev, struct device_attribute *attr, +					const char *buf, size_t count) +{ +	struct ci_hdrc	*ci = dev_get_drvdata(dev); + +	if (count > 2) +		return -1; + +	mutex_lock(&ci->fsm.lock); +	if (buf[0] == '1') +		ci->fsm.a_clr_err = 1; + +	ci_otg_queue_work(ci); +	mutex_unlock(&ci->fsm.lock); + +	return count; +} +static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err); + +static struct attribute *inputs_attrs[] = { +	&dev_attr_a_bus_req.attr, +	&dev_attr_a_bus_drop.attr, +	&dev_attr_b_bus_req.attr, +	&dev_attr_a_clr_err.attr, +	NULL, +}; + +static struct attribute_group inputs_attr_group = { +	.name = "inputs", +	.attrs = inputs_attrs, +}; + +/* + * Add timer to active timer list + */ +static void ci_otg_add_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t) +{ +	struct ci_otg_fsm_timer *tmp_timer; +	struct ci_otg_fsm_timer *timer = ci->fsm_timer->timer_list[t]; +	struct list_head *active_timers = &ci->fsm_timer->active_timers; + +	if (t >= NUM_CI_OTG_FSM_TIMERS) +		return; + +	/* +	 * Check if the timer is already in the active list, +	 * if so update timer count +	 */ +	list_for_each_entry(tmp_timer, active_timers, list) +		if (tmp_timer == timer) { +			timer->count = timer->expires; +			return; +		} + +	timer->count = timer->expires; +	list_add_tail(&timer->list, active_timers); + +	/* Enable 1ms irq */ +	if (!(hw_read_otgsc(ci, OTGSC_1MSIE))) +		hw_write_otgsc(ci, OTGSC_1MSIE, OTGSC_1MSIE); +} + +/* + * Remove timer from active timer list + */ +static void ci_otg_del_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t) +{ +	struct ci_otg_fsm_timer *tmp_timer, *del_tmp; +	struct ci_otg_fsm_timer *timer = ci->fsm_timer->timer_list[t]; +	struct list_head *active_timers = &ci->fsm_timer->active_timers; + +	if (t >= NUM_CI_OTG_FSM_TIMERS) +		return; + +	list_for_each_entry_safe(tmp_timer, del_tmp, active_timers, list) +		if (tmp_timer == timer) +			list_del(&timer->list); + +	/* Disable 1ms irq if there is no any active timer */ +	if (list_empty(active_timers)) +		hw_write_otgsc(ci, OTGSC_1MSIE, 0); +} + +/* + * Reduce timer count by 1, and find timeout conditions. + * Called by otg 1ms timer interrupt + */ +static inline int ci_otg_tick_timer(struct ci_hdrc *ci) +{ +	struct ci_otg_fsm_timer *tmp_timer, *del_tmp; +	struct list_head *active_timers = &ci->fsm_timer->active_timers; +	int expired = 0; + +	list_for_each_entry_safe(tmp_timer, del_tmp, active_timers, list) { +		tmp_timer->count--; +		/* check if timer expires */ +		if (!tmp_timer->count) { +			list_del(&tmp_timer->list); +			tmp_timer->function(ci, tmp_timer->data); +			expired = 1; +		} +	} + +	/* disable 1ms irq if there is no any timer active */ +	if ((expired == 1) && list_empty(active_timers)) +		hw_write_otgsc(ci, OTGSC_1MSIE, 0); + +	return expired; +} + +/* The timeout callback function to set time out bit */ +static void set_tmout(void *ptr, unsigned long indicator) +{ +	*(int *)indicator = 1; +} + +static void set_tmout_and_fsm(void *ptr, unsigned long indicator) +{ +	struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + +	set_tmout(ci, indicator); + +	ci_otg_queue_work(ci); +} + +static void a_wait_vfall_tmout_func(void *ptr, unsigned long indicator) +{ +	struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + +	set_tmout(ci, indicator); +	/* Disable port power */ +	hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, 0); +	/* Clear exsiting DP irq */ +	hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS); +	/* Enable data pulse irq */ +	hw_write_otgsc(ci, OTGSC_DPIE, OTGSC_DPIE); +	ci_otg_queue_work(ci); +} + +static void b_ase0_brst_tmout_func(void *ptr, unsigned long indicator) +{ +	struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + +	set_tmout(ci, indicator); +	if (!hw_read_otgsc(ci, OTGSC_BSV)) +		ci->fsm.b_sess_vld = 0; + +	ci_otg_queue_work(ci); +} + +static void b_ssend_srp_tmout_func(void *ptr, unsigned long indicator) +{ +	struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + +	set_tmout(ci, indicator); + +	/* only vbus fall below B_sess_vld in b_idle state */ +	if (ci->transceiver->state == OTG_STATE_B_IDLE) +		ci_otg_queue_work(ci); +} + +static void b_sess_vld_tmout_func(void *ptr, unsigned long indicator) +{ +	struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + +	/* Check if A detached */ +	if (!(hw_read_otgsc(ci, OTGSC_BSV))) { +		ci->fsm.b_sess_vld = 0; +		ci_otg_add_timer(ci, B_SSEND_SRP); +		ci_otg_queue_work(ci); +	} +} + +static void b_data_pulse_end(void *ptr, unsigned long indicator) +{ +	struct ci_hdrc *ci = (struct ci_hdrc *)ptr; + +	ci->fsm.b_srp_done = 1; +	ci->fsm.b_bus_req = 0; +	if (ci->fsm.power_up) +		ci->fsm.power_up = 0; + +	hw_write_otgsc(ci, OTGSC_HABA, 0); + +	ci_otg_queue_work(ci); +} + +/* Initialize timers */ +static int ci_otg_init_timers(struct ci_hdrc *ci) +{ +	struct otg_fsm *fsm = &ci->fsm; + +	/* FSM used timers */ +	ci->fsm_timer->timer_list[A_WAIT_VRISE] = +		otg_timer_initializer(ci, &set_tmout_and_fsm, TA_WAIT_VRISE, +			(unsigned long)&fsm->a_wait_vrise_tmout); +	if (ci->fsm_timer->timer_list[A_WAIT_VRISE] == NULL) +		return -ENOMEM; + +	ci->fsm_timer->timer_list[A_WAIT_VFALL] = +		otg_timer_initializer(ci, &a_wait_vfall_tmout_func, +		TA_WAIT_VFALL, (unsigned long)&fsm->a_wait_vfall_tmout); +	if (ci->fsm_timer->timer_list[A_WAIT_VFALL] == NULL) +		return -ENOMEM; + +	ci->fsm_timer->timer_list[A_WAIT_BCON] = +		otg_timer_initializer(ci, &set_tmout_and_fsm, TA_WAIT_BCON, +				(unsigned long)&fsm->a_wait_bcon_tmout); +	if (ci->fsm_timer->timer_list[A_WAIT_BCON] == NULL) +		return -ENOMEM; + +	ci->fsm_timer->timer_list[A_AIDL_BDIS] = +		otg_timer_initializer(ci, &set_tmout_and_fsm, TA_AIDL_BDIS, +				(unsigned long)&fsm->a_aidl_bdis_tmout); +	if (ci->fsm_timer->timer_list[A_AIDL_BDIS] == NULL) +		return -ENOMEM; + +	ci->fsm_timer->timer_list[A_BIDL_ADIS] = +		otg_timer_initializer(ci, &set_tmout_and_fsm, TA_BIDL_ADIS, +				(unsigned long)&fsm->a_bidl_adis_tmout); +	if (ci->fsm_timer->timer_list[A_BIDL_ADIS] == NULL) +		return -ENOMEM; + +	ci->fsm_timer->timer_list[B_ASE0_BRST] = +		otg_timer_initializer(ci, &b_ase0_brst_tmout_func, TB_ASE0_BRST, +					(unsigned long)&fsm->b_ase0_brst_tmout); +	if (ci->fsm_timer->timer_list[B_ASE0_BRST] == NULL) +		return -ENOMEM; + +	ci->fsm_timer->timer_list[B_SE0_SRP] = +		otg_timer_initializer(ci, &set_tmout_and_fsm, TB_SE0_SRP, +					(unsigned long)&fsm->b_se0_srp); +	if (ci->fsm_timer->timer_list[B_SE0_SRP] == NULL) +		return -ENOMEM; + +	ci->fsm_timer->timer_list[B_SSEND_SRP] = +		otg_timer_initializer(ci, &b_ssend_srp_tmout_func, TB_SSEND_SRP, +					(unsigned long)&fsm->b_ssend_srp); +	if (ci->fsm_timer->timer_list[B_SSEND_SRP] == NULL) +		return -ENOMEM; + +	ci->fsm_timer->timer_list[B_SRP_FAIL] = +		otg_timer_initializer(ci, &set_tmout, TB_SRP_FAIL, +				(unsigned long)&fsm->b_srp_done); +	if (ci->fsm_timer->timer_list[B_SRP_FAIL] == NULL) +		return -ENOMEM; + +	ci->fsm_timer->timer_list[B_DATA_PLS] = +		otg_timer_initializer(ci, &b_data_pulse_end, TB_DATA_PLS, 0); +	if (ci->fsm_timer->timer_list[B_DATA_PLS] == NULL) +		return -ENOMEM; + +	ci->fsm_timer->timer_list[B_SESS_VLD] =	otg_timer_initializer(ci, +					&b_sess_vld_tmout_func, TB_SESS_VLD, 0); +	if (ci->fsm_timer->timer_list[B_SESS_VLD] == NULL) +		return -ENOMEM; + +	return 0; +} + +/* -------------------------------------------------------------*/ +/* Operations that will be called from OTG Finite State Machine */ +/* -------------------------------------------------------------*/ +static void ci_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t) +{ +	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm); + +	if (t < NUM_OTG_FSM_TIMERS) +		ci_otg_add_timer(ci, t); +	return; +} + +static void ci_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t) +{ +	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm); + +	if (t < NUM_OTG_FSM_TIMERS) +		ci_otg_del_timer(ci, t); +	return; +} + +/* + * A-device drive vbus: turn on vbus regulator and enable port power + * Data pulse irq should be disabled while vbus is on. + */ +static void ci_otg_drv_vbus(struct otg_fsm *fsm, int on) +{ +	int ret; +	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm); + +	if (on) { +		/* Enable power power */ +		hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, +							PORTSC_PP); +		if (ci->platdata->reg_vbus) { +			ret = regulator_enable(ci->platdata->reg_vbus); +			if (ret) { +				dev_err(ci->dev, +				"Failed to enable vbus regulator, ret=%d\n", +				ret); +				return; +			} +		} +		/* Disable data pulse irq */ +		hw_write_otgsc(ci, OTGSC_DPIE, 0); + +		fsm->a_srp_det = 0; +		fsm->power_up = 0; +	} else { +		if (ci->platdata->reg_vbus) +			regulator_disable(ci->platdata->reg_vbus); + +		fsm->a_bus_drop = 1; +		fsm->a_bus_req = 0; +	} +} + +/* + * Control data line by Run Stop bit. + */ +static void ci_otg_loc_conn(struct otg_fsm *fsm, int on) +{ +	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm); + +	if (on) +		hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS); +	else +		hw_write(ci, OP_USBCMD, USBCMD_RS, 0); +} + +/* + * Generate SOF by host. + * This is controlled through suspend/resume the port. + * In host mode, controller will automatically send SOF. + * Suspend will block the data on the port. + */ +static void ci_otg_loc_sof(struct otg_fsm *fsm, int on) +{ +	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm); + +	if (on) +		hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_FPR, +							PORTSC_FPR); +	else +		hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_SUSP, +							PORTSC_SUSP); +} + +/* + * Start SRP pulsing by data-line pulsing, + * no v-bus pulsing followed + */ +static void ci_otg_start_pulse(struct otg_fsm *fsm) +{ +	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm); + +	/* Hardware Assistant Data pulse */ +	hw_write_otgsc(ci, OTGSC_HADP, OTGSC_HADP); + +	ci_otg_add_timer(ci, B_DATA_PLS); +} + +static int ci_otg_start_host(struct otg_fsm *fsm, int on) +{ +	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm); + +	mutex_unlock(&fsm->lock); +	if (on) { +		ci_role_stop(ci); +		ci_role_start(ci, CI_ROLE_HOST); +	} else { +		ci_role_stop(ci); +		hw_device_reset(ci, USBMODE_CM_DC); +		ci_role_start(ci, CI_ROLE_GADGET); +	} +	mutex_lock(&fsm->lock); +	return 0; +} + +static int ci_otg_start_gadget(struct otg_fsm *fsm, int on) +{ +	struct ci_hdrc	*ci = container_of(fsm, struct ci_hdrc, fsm); + +	mutex_unlock(&fsm->lock); +	if (on) +		usb_gadget_vbus_connect(&ci->gadget); +	else +		usb_gadget_vbus_disconnect(&ci->gadget); +	mutex_lock(&fsm->lock); + +	return 0; +} + +static struct otg_fsm_ops ci_otg_ops = { +	.drv_vbus = ci_otg_drv_vbus, +	.loc_conn = ci_otg_loc_conn, +	.loc_sof = ci_otg_loc_sof, +	.start_pulse = ci_otg_start_pulse, +	.add_timer = ci_otg_fsm_add_timer, +	.del_timer = ci_otg_fsm_del_timer, +	.start_host = ci_otg_start_host, +	.start_gadget = ci_otg_start_gadget, +}; + +int ci_otg_fsm_work(struct ci_hdrc *ci) +{ +	/* +	 * Don't do fsm transition for B device +	 * when there is no gadget class driver +	 */ +	if (ci->fsm.id && !(ci->driver) && +		ci->transceiver->state < OTG_STATE_A_IDLE) +		return 0; + +	if (otg_statemachine(&ci->fsm)) { +		if (ci->transceiver->state == OTG_STATE_A_IDLE) { +			/* +			 * Further state change for cases: +			 * a_idle to b_idle; or +			 * a_idle to a_wait_vrise due to ID change(1->0), so +			 * B-dev becomes A-dev can try to start new session +			 * consequently; or +			 * a_idle to a_wait_vrise when power up +			 */ +			if ((ci->fsm.id) || (ci->id_event) || +						(ci->fsm.power_up)) +				ci_otg_queue_work(ci); +			if (ci->id_event) +				ci->id_event = false; +		} else if (ci->transceiver->state == OTG_STATE_B_IDLE) { +			if (ci->fsm.b_sess_vld) { +				ci->fsm.power_up = 0; +				/* +				 * Further transite to b_periphearl state +				 * when register gadget driver with vbus on +				 */ +				ci_otg_queue_work(ci); +			} +		} +	} +	return 0; +} + +/* + * Update fsm variables in each state if catching expected interrupts, + * called by otg fsm isr. + */ +static void ci_otg_fsm_event(struct ci_hdrc *ci) +{ +	u32 intr_sts, otg_bsess_vld, port_conn; +	struct otg_fsm *fsm = &ci->fsm; + +	intr_sts = hw_read_intr_status(ci); +	otg_bsess_vld = hw_read_otgsc(ci, OTGSC_BSV); +	port_conn = hw_read(ci, OP_PORTSC, PORTSC_CCS); + +	switch (ci->transceiver->state) { +	case OTG_STATE_A_WAIT_BCON: +		if (port_conn) { +			fsm->b_conn = 1; +			fsm->a_bus_req = 1; +			ci_otg_queue_work(ci); +		} +		break; +	case OTG_STATE_B_IDLE: +		if (otg_bsess_vld && (intr_sts & USBi_PCI) && port_conn) { +			fsm->b_sess_vld = 1; +			ci_otg_queue_work(ci); +		} +		break; +	case OTG_STATE_B_PERIPHERAL: +		if ((intr_sts & USBi_SLI) && port_conn && otg_bsess_vld) { +			fsm->a_bus_suspend = 1; +			ci_otg_queue_work(ci); +		} else if (intr_sts & USBi_PCI) { +			if (fsm->a_bus_suspend == 1) +				fsm->a_bus_suspend = 0; +		} +		break; +	case OTG_STATE_B_HOST: +		if ((intr_sts & USBi_PCI) && !port_conn) { +			fsm->a_conn = 0; +			fsm->b_bus_req = 0; +			ci_otg_queue_work(ci); +			ci_otg_add_timer(ci, B_SESS_VLD); +		} +		break; +	case OTG_STATE_A_PERIPHERAL: +		if (intr_sts & USBi_SLI) { +			 fsm->b_bus_suspend = 1; +			/* +			 * Init a timer to know how long this suspend +			 * will contine, if time out, indicates B no longer +			 * wants to be host role +			 */ +			 ci_otg_add_timer(ci, A_BIDL_ADIS); +		} + +		if (intr_sts & USBi_URI) +			ci_otg_del_timer(ci, A_BIDL_ADIS); + +		if (intr_sts & USBi_PCI) { +			if (fsm->b_bus_suspend == 1) { +				ci_otg_del_timer(ci, A_BIDL_ADIS); +				fsm->b_bus_suspend = 0; +			} +		} +		break; +	case OTG_STATE_A_SUSPEND: +		if ((intr_sts & USBi_PCI) && !port_conn) { +			fsm->b_conn = 0; + +			/* if gadget driver is binded */ +			if (ci->driver) { +				/* A device to be peripheral mode */ +				ci->gadget.is_a_peripheral = 1; +			} +			ci_otg_queue_work(ci); +		} +		break; +	case OTG_STATE_A_HOST: +		if ((intr_sts & USBi_PCI) && !port_conn) { +			fsm->b_conn = 0; +			ci_otg_queue_work(ci); +		} +		break; +	case OTG_STATE_B_WAIT_ACON: +		if ((intr_sts & USBi_PCI) && port_conn) { +			fsm->a_conn = 1; +			ci_otg_queue_work(ci); +		} +		break; +	default: +		break; +	} +} + +/* + * ci_otg_irq - otg fsm related irq handling + * and also update otg fsm variable by monitoring usb host and udc + * state change interrupts. + * @ci: ci_hdrc + */ +irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci) +{ +	irqreturn_t retval =  IRQ_NONE; +	u32 otgsc, otg_int_src = 0; +	struct otg_fsm *fsm = &ci->fsm; + +	otgsc = hw_read_otgsc(ci, ~0); +	otg_int_src = otgsc & OTGSC_INT_STATUS_BITS & (otgsc >> 8); +	fsm->id = (otgsc & OTGSC_ID) ? 1 : 0; + +	if (otg_int_src) { +		if (otg_int_src & OTGSC_1MSIS) { +			hw_write_otgsc(ci, OTGSC_1MSIS, OTGSC_1MSIS); +			retval = ci_otg_tick_timer(ci); +			return IRQ_HANDLED; +		} else if (otg_int_src & OTGSC_DPIS) { +			hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS); +			fsm->a_srp_det = 1; +			fsm->a_bus_drop = 0; +		} else if (otg_int_src & OTGSC_IDIS) { +			hw_write_otgsc(ci, OTGSC_IDIS, OTGSC_IDIS); +			if (fsm->id == 0) { +				fsm->a_bus_drop = 0; +				fsm->a_bus_req = 1; +				ci->id_event = true; +			} +		} else if (otg_int_src & OTGSC_BSVIS) { +			hw_write_otgsc(ci, OTGSC_BSVIS, OTGSC_BSVIS); +			if (otgsc & OTGSC_BSV) { +				fsm->b_sess_vld = 1; +				ci_otg_del_timer(ci, B_SSEND_SRP); +				ci_otg_del_timer(ci, B_SRP_FAIL); +				fsm->b_ssend_srp = 0; +			} else { +				fsm->b_sess_vld = 0; +				if (fsm->id) +					ci_otg_add_timer(ci, B_SSEND_SRP); +			} +		} else if (otg_int_src & OTGSC_AVVIS) { +			hw_write_otgsc(ci, OTGSC_AVVIS, OTGSC_AVVIS); +			if (otgsc & OTGSC_AVV) { +				fsm->a_vbus_vld = 1; +			} else { +				fsm->a_vbus_vld = 0; +				fsm->b_conn = 0; +			} +		} +		ci_otg_queue_work(ci); +		return IRQ_HANDLED; +	} + +	ci_otg_fsm_event(ci); + +	return retval; +} + +void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci) +{ +	ci_otg_queue_work(ci); +} + +int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) +{ +	int retval = 0; +	struct usb_otg *otg; + +	otg = devm_kzalloc(ci->dev, +			sizeof(struct usb_otg), GFP_KERNEL); +	if (!otg) { +		dev_err(ci->dev, +		"Failed to allocate usb_otg structure for ci hdrc otg!\n"); +		return -ENOMEM; +	} + +	otg->phy = ci->transceiver; +	otg->gadget = &ci->gadget; +	ci->fsm.otg = otg; +	ci->transceiver->otg = ci->fsm.otg; +	ci->fsm.power_up = 1; +	ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0; +	ci->transceiver->state = OTG_STATE_UNDEFINED; +	ci->fsm.ops = &ci_otg_ops; + +	mutex_init(&ci->fsm.lock); + +	ci->fsm_timer = devm_kzalloc(ci->dev, +			sizeof(struct ci_otg_fsm_timer_list), GFP_KERNEL); +	if (!ci->fsm_timer) { +		dev_err(ci->dev, +		"Failed to allocate timer structure for ci hdrc otg!\n"); +		return -ENOMEM; +	} + +	INIT_LIST_HEAD(&ci->fsm_timer->active_timers); +	retval = ci_otg_init_timers(ci); +	if (retval) { +		dev_err(ci->dev, "Couldn't init OTG timers\n"); +		return retval; +	} + +	retval = sysfs_create_group(&ci->dev->kobj, &inputs_attr_group); +	if (retval < 0) { +		dev_dbg(ci->dev, +			"Can't register sysfs attr group: %d\n", retval); +		return retval; +	} + +	/* Enable A vbus valid irq */ +	hw_write_otgsc(ci, OTGSC_AVVIE, OTGSC_AVVIE); + +	if (ci->fsm.id) { +		ci->fsm.b_ssend_srp = +			hw_read_otgsc(ci, OTGSC_BSV) ? 0 : 1; +		ci->fsm.b_sess_vld = +			hw_read_otgsc(ci, OTGSC_BSV) ? 1 : 0; +		/* Enable BSV irq */ +		hw_write_otgsc(ci, OTGSC_BSVIE, OTGSC_BSVIE); +	} + +	return 0; +} + +void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci) +{ +	sysfs_remove_group(&ci->dev->kobj, &inputs_attr_group); +} diff --git a/drivers/usb/chipidea/otg_fsm.h b/drivers/usb/chipidea/otg_fsm.h new file mode 100644 index 00000000000..94c085f456a --- /dev/null +++ b/drivers/usb/chipidea/otg_fsm.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + * Author: Jun Li + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DRIVERS_USB_CHIPIDEA_OTG_FSM_H +#define __DRIVERS_USB_CHIPIDEA_OTG_FSM_H + +#include <linux/usb/otg-fsm.h> + +/* + *  A-DEVICE timing  constants + */ + +/* Wait for VBUS Rise  */ +#define TA_WAIT_VRISE        (100)	/* a_wait_vrise: section 7.1.2 +					 * a_wait_vrise_tmr: section 7.4.5.1 +					 * TA_VBUS_RISE <= 100ms, section 4.4 +					 * Table 4-1: Electrical Characteristics +					 * ->DC Electrical Timing +					 */ +/* Wait for VBUS Fall  */ +#define TA_WAIT_VFALL        (1000)	/* a_wait_vfall: section 7.1.7 +					 * a_wait_vfall_tmr: section: 7.4.5.2 +					 */ +/* Wait for B-Connect */ +#define TA_WAIT_BCON         (10000)	/* a_wait_bcon: section 7.1.3 +					 * TA_WAIT_BCON: should be between 1100 +					 * and 30000 ms, section 5.5, Table 5-1 +					 */ +/* A-Idle to B-Disconnect */ +#define TA_AIDL_BDIS         (5000)	/* a_suspend min 200 ms, section 5.2.1 +					 * TA_AIDL_BDIS: section 5.5, Table 5-1 +					 */ +/* B-Idle to A-Disconnect */ +#define TA_BIDL_ADIS         (500)	/* TA_BIDL_ADIS: section 5.2.1 +					 * 500ms is used for B switch to host +					 * for safe +					 */ + +/* + * B-device timing constants + */ + +/* Data-Line Pulse Time*/ +#define TB_DATA_PLS          (10)	/* b_srp_init,continue 5~10ms +					 * section:5.1.3 +					 */ +/* SRP Fail Time  */ +#define TB_SRP_FAIL          (6000)	/* b_srp_init,fail time 5~6s +					 * section:5.1.6 +					 */ +/* A-SE0 to B-Reset  */ +#define TB_ASE0_BRST         (155)	/* minimum 155 ms, section:5.3.1 */ +/* SE0 Time Before SRP */ +#define TB_SE0_SRP           (1000)	/* b_idle,minimum 1s, section:5.1.2 */ +/* SSEND time before SRP */ +#define TB_SSEND_SRP         (1500)	/* minimum 1.5 sec, section:5.1.2 */ + +#define TB_SESS_VLD          (1000) + +enum ci_otg_fsm_timer_index { +	/* +	 * CI specific timers, start from the end +	 * of standard and auxiliary OTG timers +	 */ +	B_DATA_PLS = NUM_OTG_FSM_TIMERS, +	B_SSEND_SRP, +	B_SESS_VLD, + +	NUM_CI_OTG_FSM_TIMERS, +}; + +struct ci_otg_fsm_timer { +	unsigned long expires;  /* Number of count increase to timeout */ +	unsigned long count;    /* Tick counter */ +	void (*function)(void *, unsigned long);        /* Timeout function */ +	unsigned long data;     /* Data passed to function */ +	struct list_head list; +}; + +struct ci_otg_fsm_timer_list { +	struct ci_otg_fsm_timer *timer_list[NUM_CI_OTG_FSM_TIMERS]; +	struct list_head active_timers; +}; + +#ifdef CONFIG_USB_OTG_FSM + +int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci); +int ci_otg_fsm_work(struct ci_hdrc *ci); +irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci); +void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci); +void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci); + +#else + +static inline int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) +{ +	return 0; +} + +static inline int ci_otg_fsm_work(struct ci_hdrc *ci) +{ +	return -ENXIO; +} + +static inline irqreturn_t ci_otg_fsm_irq(struct ci_hdrc *ci) +{ +	return IRQ_NONE; +} + +static inline void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci) +{ + +} + +static inline void ci_hdrc_otg_fsm_remove(struct ci_hdrc *ci) +{ + +} + +#endif + +#endif /* __DRIVERS_USB_CHIPIDEA_OTG_FSM_H */ diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 6b4c2f2eb94..b8125aa64ad 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -20,7 +20,7 @@  #include <linux/pm_runtime.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h> -#include <linux/usb/otg.h> +#include <linux/usb/otg-fsm.h>  #include <linux/usb/chipidea.h>  #include "ci.h" @@ -28,6 +28,7 @@  #include "bits.h"  #include "debug.h"  #include "otg.h" +#include "otg_fsm.h"  /* control endpoint description */  static const struct usb_endpoint_descriptor @@ -106,7 +107,7 @@ static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir)  	do {  		/* flush any pending transfer */ -		hw_write(ci, OP_ENDPTFLUSH, BIT(n), BIT(n)); +		hw_write(ci, OP_ENDPTFLUSH, ~0, BIT(n));  		while (hw_read(ci, OP_ENDPTFLUSH, BIT(n)))  			cpu_relax();  	} while (hw_read(ci, OP_ENDPTSTAT, BIT(n))); @@ -179,19 +180,6 @@ static int hw_ep_get_halt(struct ci_hdrc *ci, int num, int dir)  }  /** - * hw_test_and_clear_setup_status: test & clear setup status (execute without - *                                 interruption) - * @n: endpoint number - * - * This function returns setup status - */ -static int hw_test_and_clear_setup_status(struct ci_hdrc *ci, int n) -{ -	n = ep_to_bit(ci, n); -	return hw_test_and_clear(ci, OP_ENDPTSETUPSTAT, BIT(n)); -} - -/**   * hw_ep_prime: primes endpoint (execute without interruption)   * @num:     endpoint number   * @dir:     endpoint direction @@ -206,7 +194,7 @@ static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl)  	if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num)))  		return -EAGAIN; -	hw_write(ci, OP_ENDPTPRIME, BIT(n), BIT(n)); +	hw_write(ci, OP_ENDPTPRIME, ~0, BIT(n));  	while (hw_read(ci, OP_ENDPTPRIME, BIT(n)))  		cpu_relax(); @@ -256,26 +244,6 @@ static int hw_port_is_high_speed(struct ci_hdrc *ci)  }  /** - * hw_read_intr_enable: returns interrupt enable register - * - * This function returns register data - */ -static u32 hw_read_intr_enable(struct ci_hdrc *ci) -{ -	return hw_read(ci, OP_USBINTR, ~0); -} - -/** - * hw_read_intr_status: returns interrupt status register - * - * This function returns register data - */ -static u32 hw_read_intr_status(struct ci_hdrc *ci) -{ -	return hw_read(ci, OP_USBSTS, ~0); -} - -/**   * hw_test_and_clear_complete: test & clear complete status (execute without   *                             interruption)   * @n: endpoint number @@ -394,6 +362,14 @@ static int add_td_to_list(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq,  	node->ptr->token = cpu_to_le32(length << __ffs(TD_TOTAL_BYTES));  	node->ptr->token &= cpu_to_le32(TD_TOTAL_BYTES);  	node->ptr->token |= cpu_to_le32(TD_STATUS_ACTIVE); +	if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == TX) { +		u32 mul = hwreq->req.length / hwep->ep.maxpacket; + +		if (hwreq->req.length == 0 +				|| hwreq->req.length % hwep->ep.maxpacket) +			mul++; +		node->ptr->token |= mul << __ffs(TD_MULTO); +	}  	temp = (u32) (hwreq->req.dma + hwreq->req.actual);  	if (length) { @@ -516,10 +492,11 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)  	hwep->qh.ptr->td.token &=  		cpu_to_le32(~(TD_STATUS_HALTED|TD_STATUS_ACTIVE)); -	if (hwep->type == USB_ENDPOINT_XFER_ISOC) { +	if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == RX) {  		u32 mul = hwreq->req.length / hwep->ep.maxpacket; -		if (hwreq->req.length % hwep->ep.maxpacket) +		if (hwreq->req.length == 0 +				|| hwreq->req.length % hwep->ep.maxpacket)  			mul++;  		hwep->qh.ptr->cap |= mul << __ffs(QH_MULT);  	} @@ -686,9 +663,6 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)  	usb_ep_fifo_flush(&ci->ep0out->ep);  	usb_ep_fifo_flush(&ci->ep0in->ep); -	if (ci->driver) -		ci->driver->disconnect(gadget); -  	/* make sure to disable all endpoints */  	gadget_for_each_ep(ep, gadget) {  		usb_ep_disable(ep); @@ -718,6 +692,11 @@ __acquires(ci->lock)  	int retval;  	spin_unlock(&ci->lock); +	if (ci->gadget.speed != USB_SPEED_UNKNOWN) { +		if (ci->driver) +			ci->driver->disconnect(&ci->gadget); +	} +  	retval = _gadget_stop_activity(&ci->gadget);  	if (retval)  		goto done; @@ -730,6 +709,8 @@ __acquires(ci->lock)  	if (ci->status == NULL)  		retval = -ENOMEM; +	usb_gadget_set_state(&ci->gadget, USB_STATE_DEFAULT); +  done:  	spin_lock(&ci->lock); @@ -844,7 +825,6 @@ __acquires(hwep->lock)  	if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {  		/* Assume that device is bus powered for now. */  		*(u16 *)req->buf = ci->remote_wakeup << 1; -		retval = 0;  	} else if ((setup->bRequestType & USB_RECIP_MASK) \  		   == USB_RECIP_ENDPOINT) {  		dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ? @@ -886,6 +866,8 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)  	if (ci->setaddr) {  		hw_usb_set_address(ci, ci->address);  		ci->setaddr = false; +		if (ci->address) +			usb_gadget_set_state(&ci->gadget, USB_STATE_ADDRESS);  	}  	spin_lock_irqsave(&ci->lock, flags); @@ -952,6 +934,164 @@ __acquires(hwep->lock)  }  /** + * isr_setup_packet_handler: setup packet handler + * @ci: UDC descriptor + * + * This function handles setup packet  + */ +static void isr_setup_packet_handler(struct ci_hdrc *ci) +__releases(ci->lock) +__acquires(ci->lock) +{ +	struct ci_hw_ep *hwep = &ci->ci_hw_ep[0]; +	struct usb_ctrlrequest req; +	int type, num, dir, err = -EINVAL; +	u8 tmode = 0; + +	/* +	 * Flush data and handshake transactions of previous +	 * setup packet. +	 */ +	_ep_nuke(ci->ep0out); +	_ep_nuke(ci->ep0in); + +	/* read_setup_packet */ +	do { +		hw_test_and_set_setup_guard(ci); +		memcpy(&req, &hwep->qh.ptr->setup, sizeof(req)); +	} while (!hw_test_and_clear_setup_guard(ci)); + +	type = req.bRequestType; + +	ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX; + +	switch (req.bRequest) { +	case USB_REQ_CLEAR_FEATURE: +		if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && +				le16_to_cpu(req.wValue) == +				USB_ENDPOINT_HALT) { +			if (req.wLength != 0) +				break; +			num  = le16_to_cpu(req.wIndex); +			dir = num & USB_ENDPOINT_DIR_MASK; +			num &= USB_ENDPOINT_NUMBER_MASK; +			if (dir) /* TX */ +				num += ci->hw_ep_max / 2; +			if (!ci->ci_hw_ep[num].wedge) { +				spin_unlock(&ci->lock); +				err = usb_ep_clear_halt( +					&ci->ci_hw_ep[num].ep); +				spin_lock(&ci->lock); +				if (err) +					break; +			} +			err = isr_setup_status_phase(ci); +		} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) && +				le16_to_cpu(req.wValue) == +				USB_DEVICE_REMOTE_WAKEUP) { +			if (req.wLength != 0) +				break; +			ci->remote_wakeup = 0; +			err = isr_setup_status_phase(ci); +		} else { +			goto delegate; +		} +		break; +	case USB_REQ_GET_STATUS: +		if (type != (USB_DIR_IN|USB_RECIP_DEVICE)   && +		    type != (USB_DIR_IN|USB_RECIP_ENDPOINT) && +		    type != (USB_DIR_IN|USB_RECIP_INTERFACE)) +			goto delegate; +		if (le16_to_cpu(req.wLength) != 2 || +		    le16_to_cpu(req.wValue)  != 0) +			break; +		err = isr_get_status_response(ci, &req); +		break; +	case USB_REQ_SET_ADDRESS: +		if (type != (USB_DIR_OUT|USB_RECIP_DEVICE)) +			goto delegate; +		if (le16_to_cpu(req.wLength) != 0 || +		    le16_to_cpu(req.wIndex)  != 0) +			break; +		ci->address = (u8)le16_to_cpu(req.wValue); +		ci->setaddr = true; +		err = isr_setup_status_phase(ci); +		break; +	case USB_REQ_SET_FEATURE: +		if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && +				le16_to_cpu(req.wValue) == +				USB_ENDPOINT_HALT) { +			if (req.wLength != 0) +				break; +			num  = le16_to_cpu(req.wIndex); +			dir = num & USB_ENDPOINT_DIR_MASK; +			num &= USB_ENDPOINT_NUMBER_MASK; +			if (dir) /* TX */ +				num += ci->hw_ep_max / 2; + +			spin_unlock(&ci->lock); +			err = usb_ep_set_halt(&ci->ci_hw_ep[num].ep); +			spin_lock(&ci->lock); +			if (!err) +				isr_setup_status_phase(ci); +		} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) { +			if (req.wLength != 0) +				break; +			switch (le16_to_cpu(req.wValue)) { +			case USB_DEVICE_REMOTE_WAKEUP: +				ci->remote_wakeup = 1; +				err = isr_setup_status_phase(ci); +				break; +			case USB_DEVICE_TEST_MODE: +				tmode = le16_to_cpu(req.wIndex) >> 8; +				switch (tmode) { +				case TEST_J: +				case TEST_K: +				case TEST_SE0_NAK: +				case TEST_PACKET: +				case TEST_FORCE_EN: +					ci->test_mode = tmode; +					err = isr_setup_status_phase( +							ci); +					break; +				default: +					break; +				} +				break; +			case USB_DEVICE_B_HNP_ENABLE: +				if (ci_otg_is_fsm_mode(ci)) { +					ci->gadget.b_hnp_enable = 1; +					err = isr_setup_status_phase( +							ci); +				} +				break; +			default: +				goto delegate; +			} +		} else { +			goto delegate; +		} +		break; +	default: +delegate: +		if (req.wLength == 0)   /* no data phase */ +			ci->ep0_dir = TX; + +		spin_unlock(&ci->lock); +		err = ci->driver->setup(&ci->gadget, &req); +		spin_lock(&ci->lock); +		break; +	} + +	if (err < 0) { +		spin_unlock(&ci->lock); +		if (usb_ep_set_halt(&hwep->ep)) +			dev_err(ci->dev, "error: ep_set_halt\n"); +		spin_lock(&ci->lock); +	} +} + +/**   * isr_tr_complete_handler: transaction complete interrupt handler   * @ci: UDC descriptor   * @@ -962,12 +1102,10 @@ __releases(ci->lock)  __acquires(ci->lock)  {  	unsigned i; -	u8 tmode = 0; +	int err;  	for (i = 0; i < ci->hw_ep_max; i++) {  		struct ci_hw_ep *hwep  = &ci->ci_hw_ep[i]; -		int type, num, dir, err = -EINVAL; -		struct usb_ctrlrequest req;  		if (hwep->ep.desc == NULL)  			continue;   /* not configured */ @@ -987,148 +1125,10 @@ __acquires(ci->lock)  			}  		} -		if (hwep->type != USB_ENDPOINT_XFER_CONTROL || -		    !hw_test_and_clear_setup_status(ci, i)) -			continue; - -		if (i != 0) { -			dev_warn(ci->dev, "ctrl traffic at endpoint %d\n", i); -			continue; -		} - -		/* -		 * Flush data and handshake transactions of previous -		 * setup packet. -		 */ -		_ep_nuke(ci->ep0out); -		_ep_nuke(ci->ep0in); - -		/* read_setup_packet */ -		do { -			hw_test_and_set_setup_guard(ci); -			memcpy(&req, &hwep->qh.ptr->setup, sizeof(req)); -		} while (!hw_test_and_clear_setup_guard(ci)); - -		type = req.bRequestType; - -		ci->ep0_dir = (type & USB_DIR_IN) ? TX : RX; - -		switch (req.bRequest) { -		case USB_REQ_CLEAR_FEATURE: -			if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && -					le16_to_cpu(req.wValue) == -					USB_ENDPOINT_HALT) { -				if (req.wLength != 0) -					break; -				num  = le16_to_cpu(req.wIndex); -				dir = num & USB_ENDPOINT_DIR_MASK; -				num &= USB_ENDPOINT_NUMBER_MASK; -				if (dir) /* TX */ -					num += ci->hw_ep_max/2; -				if (!ci->ci_hw_ep[num].wedge) { -					spin_unlock(&ci->lock); -					err = usb_ep_clear_halt( -						&ci->ci_hw_ep[num].ep); -					spin_lock(&ci->lock); -					if (err) -						break; -				} -				err = isr_setup_status_phase(ci); -			} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) && -					le16_to_cpu(req.wValue) == -					USB_DEVICE_REMOTE_WAKEUP) { -				if (req.wLength != 0) -					break; -				ci->remote_wakeup = 0; -				err = isr_setup_status_phase(ci); -			} else { -				goto delegate; -			} -			break; -		case USB_REQ_GET_STATUS: -			if (type != (USB_DIR_IN|USB_RECIP_DEVICE)   && -			    type != (USB_DIR_IN|USB_RECIP_ENDPOINT) && -			    type != (USB_DIR_IN|USB_RECIP_INTERFACE)) -				goto delegate; -			if (le16_to_cpu(req.wLength) != 2 || -			    le16_to_cpu(req.wValue)  != 0) -				break; -			err = isr_get_status_response(ci, &req); -			break; -		case USB_REQ_SET_ADDRESS: -			if (type != (USB_DIR_OUT|USB_RECIP_DEVICE)) -				goto delegate; -			if (le16_to_cpu(req.wLength) != 0 || -			    le16_to_cpu(req.wIndex)  != 0) -				break; -			ci->address = (u8)le16_to_cpu(req.wValue); -			ci->setaddr = true; -			err = isr_setup_status_phase(ci); -			break; -		case USB_REQ_SET_FEATURE: -			if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && -					le16_to_cpu(req.wValue) == -					USB_ENDPOINT_HALT) { -				if (req.wLength != 0) -					break; -				num  = le16_to_cpu(req.wIndex); -				dir = num & USB_ENDPOINT_DIR_MASK; -				num &= USB_ENDPOINT_NUMBER_MASK; -				if (dir) /* TX */ -					num += ci->hw_ep_max/2; - -				spin_unlock(&ci->lock); -				err = usb_ep_set_halt(&ci->ci_hw_ep[num].ep); -				spin_lock(&ci->lock); -				if (!err) -					isr_setup_status_phase(ci); -			} else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) { -				if (req.wLength != 0) -					break; -				switch (le16_to_cpu(req.wValue)) { -				case USB_DEVICE_REMOTE_WAKEUP: -					ci->remote_wakeup = 1; -					err = isr_setup_status_phase(ci); -					break; -				case USB_DEVICE_TEST_MODE: -					tmode = le16_to_cpu(req.wIndex) >> 8; -					switch (tmode) { -					case TEST_J: -					case TEST_K: -					case TEST_SE0_NAK: -					case TEST_PACKET: -					case TEST_FORCE_EN: -						ci->test_mode = tmode; -						err = isr_setup_status_phase( -								ci); -						break; -					default: -						break; -					} -				default: -					goto delegate; -				} -			} else { -				goto delegate; -			} -			break; -		default: -delegate: -			if (req.wLength == 0)   /* no data phase */ -				ci->ep0_dir = TX; - -			spin_unlock(&ci->lock); -			err = ci->driver->setup(&ci->gadget, &req); -			spin_lock(&ci->lock); -			break; -		} - -		if (err < 0) { -			spin_unlock(&ci->lock); -			if (usb_ep_set_halt(&hwep->ep)) -				dev_err(ci->dev, "error: ep_set_halt\n"); -			spin_lock(&ci->lock); -		} +		/* Only handle setup packet below */ +		if (i == 0 && +			hw_test_and_clear(ci, OP_ENDPTSETUPSTAT, BIT(0))) +			isr_setup_packet_handler(ci);  	}  } @@ -1169,14 +1169,25 @@ static int ep_enable(struct usb_ep *ep,  	if (hwep->type == USB_ENDPOINT_XFER_CONTROL)  		cap |= QH_IOS; -	if (hwep->num) -		cap |= QH_ZLT; + +	cap |= QH_ZLT;  	cap |= (hwep->ep.maxpacket << __ffs(QH_MAX_PKT)) & QH_MAX_PKT; +	/* +	 * For ISO-TX, we set mult at QH as the largest value, and use +	 * MultO at TD as real mult value. +	 */ +	if (hwep->type == USB_ENDPOINT_XFER_ISOC && hwep->dir == TX) +		cap |= 3 << __ffs(QH_MULT);  	hwep->qh.ptr->cap = cpu_to_le32(cap);  	hwep->qh.ptr->td.next |= cpu_to_le32(TD_TERMINATE);   /* needed? */ +	if (hwep->num != 0 && hwep->type == USB_ENDPOINT_XFER_CONTROL) { +		dev_err(hwep->ci->dev, "Set control xfer at non-ep0\n"); +		retval = -EINVAL; +	} +  	/*  	 * Enable endpoints in the HW other than ep0 as ep0  	 * is always enabled @@ -1310,6 +1321,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)  	struct ci_hw_ep  *hwep  = container_of(ep,  struct ci_hw_ep, ep);  	struct ci_hw_req *hwreq = container_of(req, struct ci_hw_req, req);  	unsigned long flags; +	struct td_node *node, *tmpnode;  	if (ep == NULL || req == NULL || hwreq->req.status != -EALREADY ||  		hwep->ep.desc == NULL || list_empty(&hwreq->queue) || @@ -1320,6 +1332,12 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)  	hw_ep_flush(hwep->ci, hwep->num, hwep->dir); +	list_for_each_entry_safe(node, tmpnode, &hwreq->tds, td) { +		dma_pool_free(hwep->td_pool, node->ptr, node->dma); +		list_del(&node->td); +		kfree(node); +	} +  	/* pop request */  	list_del_init(&hwreq->queue); @@ -1459,15 +1477,17 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)  			pm_runtime_get_sync(&_gadget->dev);  			hw_device_reset(ci, USBMODE_CM_DC);  			hw_device_state(ci, ci->ep0out->qh.dma); -			dev_dbg(ci->dev, "Connected to host\n"); +			usb_gadget_set_state(_gadget, USB_STATE_POWERED);  		} else { +			if (ci->driver) +				ci->driver->disconnect(&ci->gadget);  			hw_device_state(ci, 0);  			if (ci->platdata->notify_event)  				ci->platdata->notify_event(ci,  				CI_HDRC_CONTROLLER_STOPPED_EVENT);  			_gadget_stop_activity(&ci->gadget);  			pm_runtime_put_sync(&_gadget->dev); -			dev_dbg(ci->dev, "Disconnected from host\n"); +			usb_gadget_set_state(_gadget, USB_STATE_NOTATTACHED);  		}  	} @@ -1563,7 +1583,7 @@ static int init_eps(struct ci_hdrc *ci)  			 * eps, maxP is set by epautoconfig() called  			 * by gadget layer  			 */ -			hwep->ep.maxpacket = (unsigned short)~0; +			usb_ep_set_maxpacket_limit(&hwep->ep, (unsigned short)~0);  			INIT_LIST_HEAD(&hwep->qh.queue);  			hwep->qh.ptr = dma_pool_alloc(ci->qh_pool, GFP_KERNEL, @@ -1583,7 +1603,7 @@ static int init_eps(struct ci_hdrc *ci)  				else  					ci->ep0in = hwep; -				hwep->ep.maxpacket = CTRL_PAYLOAD_MAX; +				usb_ep_set_maxpacket_limit(&hwep->ep, CTRL_PAYLOAD_MAX);  				continue;  			} @@ -1600,6 +1620,8 @@ static void destroy_eps(struct ci_hdrc *ci)  	for (i = 0; i < ci->hw_ep_max; i++) {  		struct ci_hw_ep *hwep = &ci->ci_hw_ep[i]; +		if (hwep->pending_td) +			free_pending_td(hwep);  		dma_pool_free(ci->qh_pool, hwep->qh.ptr, hwep->qh.dma);  	}  } @@ -1631,23 +1653,29 @@ static int ci_udc_start(struct usb_gadget *gadget,  	retval = usb_ep_enable(&ci->ep0in->ep);  	if (retval)  		return retval; -	spin_lock_irqsave(&ci->lock, flags);  	ci->driver = driver; + +	/* Start otg fsm for B-device */ +	if (ci_otg_is_fsm_mode(ci) && ci->fsm.id) { +		ci_hdrc_otg_fsm_start(ci); +		return retval; +	} +  	pm_runtime_get_sync(&ci->gadget.dev);  	if (ci->vbus_active) { +		spin_lock_irqsave(&ci->lock, flags);  		hw_device_reset(ci, USBMODE_CM_DC);  	} else {  		pm_runtime_put_sync(&ci->gadget.dev); -		goto done; +		return retval;  	}  	retval = hw_device_state(ci, ci->ep0out->qh.dma); +	spin_unlock_irqrestore(&ci->lock, flags);  	if (retval)  		pm_runtime_put_sync(&ci->gadget.dev); - done: -	spin_unlock_irqrestore(&ci->lock, flags);  	return retval;  } @@ -1667,13 +1695,13 @@ static int ci_udc_stop(struct usb_gadget *gadget,  		if (ci->platdata->notify_event)  			ci->platdata->notify_event(ci,  			CI_HDRC_CONTROLLER_STOPPED_EVENT); -		ci->driver = NULL;  		spin_unlock_irqrestore(&ci->lock, flags);  		_gadget_stop_activity(&ci->gadget);  		spin_lock_irqsave(&ci->lock, flags);  		pm_runtime_put(&ci->gadget.dev);  	} +	ci->driver = NULL;  	spin_unlock_irqrestore(&ci->lock, flags);  	return 0; @@ -1732,6 +1760,8 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci)  				ci->suspended = 1;  				spin_unlock(&ci->lock);  				ci->driver->suspend(&ci->gadget); +				usb_gadget_set_state(&ci->gadget, +						USB_STATE_SUSPENDED);  				spin_lock(&ci->lock);  			}  		} @@ -1758,7 +1788,7 @@ static int udc_start(struct ci_hdrc *ci)  	ci->gadget.ops          = &usb_gadget_ops;  	ci->gadget.speed        = USB_SPEED_UNKNOWN;  	ci->gadget.max_speed    = USB_SPEED_HIGH; -	ci->gadget.is_otg       = 0; +	ci->gadget.is_otg       = ci->is_otg ? 1 : 0;  	ci->gadget.name         = ci->platdata->name;  	INIT_LIST_HEAD(&ci->gadget.ep_list); @@ -1784,54 +1814,15 @@ static int udc_start(struct ci_hdrc *ci)  	ci->gadget.ep0 = &ci->ep0in->ep; -	if (ci->global_phy) { -		ci->transceiver = usb_get_phy(USB_PHY_TYPE_USB2); -		if (IS_ERR(ci->transceiver)) -			ci->transceiver = NULL; -	} - -	if (ci->platdata->flags & CI_HDRC_REQUIRE_TRANSCEIVER) { -		if (ci->transceiver == NULL) { -			retval = -ENODEV; -			goto destroy_eps; -		} -	} - -	if (ci->transceiver) { -		retval = otg_set_peripheral(ci->transceiver->otg, -						&ci->gadget); -		/* -		 * If we implement all USB functions using chipidea drivers, -		 * it doesn't need to call above API, meanwhile, if we only -		 * use gadget function, calling above API is useless. -		 */ -		if (retval && retval != -ENOTSUPP) -			goto put_transceiver; -	} -  	retval = usb_add_gadget_udc(dev, &ci->gadget);  	if (retval) -		goto remove_trans; +		goto destroy_eps;  	pm_runtime_no_callbacks(&ci->gadget.dev);  	pm_runtime_enable(&ci->gadget.dev); -	/* Update ci->vbus_active */ -	ci_handle_vbus_change(ci); -  	return retval; -remove_trans: -	if (ci->transceiver) { -		otg_set_peripheral(ci->transceiver->otg, NULL); -		if (ci->global_phy) -			usb_put_phy(ci->transceiver); -	} - -	dev_err(dev, "error = %i\n", retval); -put_transceiver: -	if (ci->transceiver && ci->global_phy) -		usb_put_phy(ci->transceiver);  destroy_eps:  	destroy_eps(ci);  free_pools: @@ -1857,31 +1848,26 @@ void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)  	dma_pool_destroy(ci->td_pool);  	dma_pool_destroy(ci->qh_pool); - -	if (ci->transceiver) { -		otg_set_peripheral(ci->transceiver->otg, NULL); -		if (ci->global_phy) -			usb_put_phy(ci->transceiver); -	}  }  static int udc_id_switch_for_device(struct ci_hdrc *ci)  { -	if (ci->is_otg) { -		ci_clear_otg_interrupt(ci, OTGSC_BSVIS); -		ci_enable_otg_interrupt(ci, OTGSC_BSVIE); -	} +	if (ci->is_otg) +		/* Clear and enable BSV irq */ +		hw_write_otgsc(ci, OTGSC_BSVIS | OTGSC_BSVIE, +					OTGSC_BSVIS | OTGSC_BSVIE);  	return 0;  }  static void udc_id_switch_for_host(struct ci_hdrc *ci)  { -	if (ci->is_otg) { -		/* host doesn't care B_SESSION_VALID event */ -		ci_clear_otg_interrupt(ci, OTGSC_BSVIS); -		ci_disable_otg_interrupt(ci, OTGSC_BSVIE); -	} +	/* +	 * host doesn't care B_SESSION_VALID event +	 * so clear and disbale BSV irq +	 */ +	if (ci->is_otg) +		hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);  }  /** diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 8a1094b1182..85293b8b1df 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -21,12 +21,39 @@  #define MX25_USB_PHY_CTRL_OFFSET	0x08  #define MX25_BM_EXTERNAL_VBUS_DIVIDER	BIT(23) +#define MX25_EHCI_INTERFACE_SINGLE_UNI	(2 << 0) +#define MX25_EHCI_INTERFACE_DIFF_UNI	(0 << 0) +#define MX25_EHCI_INTERFACE_MASK	(0xf) + +#define MX25_OTG_SIC_SHIFT		29 +#define MX25_OTG_SIC_MASK		(0x3 << MX25_OTG_SIC_SHIFT) +#define MX25_OTG_PM_BIT			BIT(24) +#define MX25_OTG_PP_BIT			BIT(11) +#define MX25_OTG_OCPOL_BIT		BIT(3) + +#define MX25_H1_SIC_SHIFT		21 +#define MX25_H1_SIC_MASK		(0x3 << MX25_H1_SIC_SHIFT) +#define MX25_H1_PP_BIT			BIT(18) +#define MX25_H1_PM_BIT			BIT(16) +#define MX25_H1_IPPUE_UP_BIT		BIT(7) +#define MX25_H1_IPPUE_DOWN_BIT		BIT(6) +#define MX25_H1_TLL_BIT			BIT(5) +#define MX25_H1_USBTE_BIT		BIT(4) +#define MX25_H1_OCPOL_BIT		BIT(2) + +#define MX27_H1_PM_BIT			BIT(8) +#define MX27_H2_PM_BIT			BIT(16) +#define MX27_OTG_PM_BIT			BIT(24) +  #define MX53_USB_OTG_PHY_CTRL_0_OFFSET	0x08 +#define MX53_USB_OTG_PHY_CTRL_1_OFFSET	0x0c  #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 MX53_USB_PHYCTRL1_PLLDIV_MASK	0x3 +#define MX53_USB_PLL_DIV_24_MHZ		0x01  #define MX6_BM_OVER_CUR_DIS		BIT(7) @@ -46,6 +73,39 @@ struct imx_usbmisc {  static struct imx_usbmisc *usbmisc; +static int usbmisc_imx25_init(struct imx_usbmisc_data *data) +{ +	unsigned long flags; +	u32 val = 0; + +	if (data->index > 1) +		return -EINVAL; + +	spin_lock_irqsave(&usbmisc->lock, flags); +	switch (data->index) { +	case 0: +		val = readl(usbmisc->base); +		val &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT); +		val |= (MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT; +		val |= (MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT); +		writel(val, usbmisc->base); +		break; +	case 1: +		val = readl(usbmisc->base); +		val &= ~(MX25_H1_SIC_MASK | MX25_H1_PP_BIT |  MX25_H1_IPPUE_UP_BIT); +		val |= (MX25_EHCI_INTERFACE_SINGLE_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT; +		val |= (MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT | +			MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT); + +		writel(val, usbmisc->base); + +		break; +	} +	spin_unlock_irqrestore(&usbmisc->lock, flags); + +	return 0; +} +  static int usbmisc_imx25_post(struct imx_usbmisc_data *data)  {  	void __iomem *reg; @@ -68,6 +128,36 @@ static int usbmisc_imx25_post(struct imx_usbmisc_data *data)  	return 0;  } +static int usbmisc_imx27_init(struct imx_usbmisc_data *data) +{ +	unsigned long flags; +	u32 val; + +	switch (data->index) { +	case 0: +		val = MX27_OTG_PM_BIT; +		break; +	case 1: +		val = MX27_H1_PM_BIT; +		break; +	case 2: +		val = MX27_H2_PM_BIT; +		break; +	default: +		return -EINVAL; +	}; + +	spin_lock_irqsave(&usbmisc->lock, flags); +	if (data->disable_oc) +		val = readl(usbmisc->base) | val; +	else +		val = readl(usbmisc->base) & ~val; +	writel(val, usbmisc->base); +	spin_unlock_irqrestore(&usbmisc->lock, flags); + +	return 0; +} +  static int usbmisc_imx53_init(struct imx_usbmisc_data *data)  {  	void __iomem *reg = NULL; @@ -77,6 +167,13 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data)  	if (data->index > 3)  		return -EINVAL; +	/* Select a 24 MHz reference clock for the PHY  */ +	reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET; +	val = readl(reg); +	val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK; +	val |= MX53_USB_PLL_DIV_24_MHZ; +	writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET); +  	if (data->disable_oc) {  		spin_lock_irqsave(&usbmisc->lock, flags);  		switch (data->index) { @@ -125,9 +222,14 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)  }  static const struct usbmisc_ops imx25_usbmisc_ops = { +	.init = usbmisc_imx25_init,  	.post = usbmisc_imx25_post,  }; +static const struct usbmisc_ops imx27_usbmisc_ops = { +	.init = usbmisc_imx27_init, +}; +  static const struct usbmisc_ops imx53_usbmisc_ops = {  	.init = usbmisc_imx53_init,  }; @@ -162,6 +264,18 @@ static const struct of_device_id usbmisc_imx_dt_ids[] = {  		.data = &imx25_usbmisc_ops,  	},  	{ +		.compatible = "fsl,imx35-usbmisc", +		.data = &imx25_usbmisc_ops, +	}, +	{ +		.compatible = "fsl,imx27-usbmisc", +		.data = &imx27_usbmisc_ops, +	}, +	{ +		.compatible = "fsl,imx51-usbmisc", +		.data = &imx53_usbmisc_ops, +	}, +	{  		.compatible = "fsl,imx53-usbmisc",  		.data = &imx53_usbmisc_ops,  	}, diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 3e7560f004f..e934e19f49f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -122,13 +122,23 @@ static void acm_release_minor(struct acm *acm)  static int acm_ctrl_msg(struct acm *acm, int request, int value,  							void *buf, int len)  { -	int retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0), +	int retval; + +	retval = usb_autopm_get_interface(acm->control); +	if (retval) +		return retval; + +	retval = usb_control_msg(acm->dev, usb_sndctrlpipe(acm->dev, 0),  		request, USB_RT_ACM, value,  		acm->control->altsetting[0].desc.bInterfaceNumber,  		buf, len, 5000); +  	dev_dbg(&acm->control->dev,  			"%s - rq 0x%02x, val %#x, len %#x, result %d\n",  			__func__, request, value, len, retval); + +	usb_autopm_put_interface(acm->control); +  	return retval < 0 ? retval : 0;  } @@ -262,6 +272,7 @@ static void acm_ctrl_irq(struct urb *urb)  	struct usb_cdc_notification *dr = urb->transfer_buffer;  	unsigned char *data;  	int newctrl; +	int difference;  	int retval;  	int status = urb->status; @@ -302,20 +313,31 @@ static void acm_ctrl_irq(struct urb *urb)  			tty_port_tty_hangup(&acm->port, false);  		} +		difference = acm->ctrlin ^ newctrl; +		spin_lock(&acm->read_lock);  		acm->ctrlin = newctrl; +		acm->oldcount = acm->iocount; + +		if (difference & ACM_CTRL_DSR) +			acm->iocount.dsr++; +		if (difference & ACM_CTRL_BRK) +			acm->iocount.brk++; +		if (difference & ACM_CTRL_RI) +			acm->iocount.rng++; +		if (difference & ACM_CTRL_DCD) +			acm->iocount.dcd++; +		if (difference & ACM_CTRL_FRAMING) +			acm->iocount.frame++; +		if (difference & ACM_CTRL_PARITY) +			acm->iocount.parity++; +		if (difference & ACM_CTRL_OVERRUN) +			acm->iocount.overrun++; +		spin_unlock(&acm->read_lock); + +		if (difference) +			wake_up_all(&acm->wioctl); -		dev_dbg(&acm->control->dev, -			"%s - input control lines: dcd%c dsr%c break%c " -			"ring%c framing%c parity%c overrun%c\n", -			__func__, -			acm->ctrlin & ACM_CTRL_DCD ? '+' : '-', -			acm->ctrlin & ACM_CTRL_DSR ? '+' : '-', -			acm->ctrlin & ACM_CTRL_BRK ? '+' : '-', -			acm->ctrlin & ACM_CTRL_RI  ? '+' : '-', -			acm->ctrlin & ACM_CTRL_FRAMING ? '+' : '-', -			acm->ctrlin & ACM_CTRL_PARITY ? '+' : '-', -			acm->ctrlin & ACM_CTRL_OVERRUN ? '+' : '-'); -			break; +		break;  	default:  		dev_dbg(&acm->control->dev, @@ -394,19 +416,21 @@ static void acm_read_bulk_callback(struct urb *urb)  		dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__);  		return;  	} -	usb_mark_last_busy(acm->dev);  	if (urb->status) {  		dev_dbg(&acm->data->dev, "%s - non-zero urb status: %d\n",  							__func__, urb->status);  		return;  	} + +	usb_mark_last_busy(acm->dev); +  	acm_process_read_urb(acm, urb);  	/* throttle device if requested by tty */  	spin_lock_irqsave(&acm->read_lock, flags);  	acm->throttled = acm->throttle_req; -	if (!acm->throttled && !acm->susp_count) { +	if (!acm->throttled) {  		spin_unlock_irqrestore(&acm->read_lock, flags);  		acm_submit_read_urb(acm, rb->index, GFP_ATOMIC);  	} else { @@ -480,10 +504,30 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)  	return tty_port_open(&acm->port, tty, filp);  } +static void acm_port_dtr_rts(struct tty_port *port, int raise) +{ +	struct acm *acm = container_of(port, struct acm, port); +	int val; +	int res; + +	if (raise) +		val = ACM_CTRL_DTR | ACM_CTRL_RTS; +	else +		val = 0; + +	/* FIXME: add missing ctrlout locking throughout driver */ +	acm->ctrlout = val; + +	res = acm_set_control(acm, val); +	if (res && (acm->ctrl_caps & USB_CDC_CAP_LINE)) +		dev_err(&acm->control->dev, "failed to set dtr/rts\n"); +} +  static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)  {  	struct acm *acm = container_of(port, struct acm, port);  	int retval = -ENODEV; +	int i;  	dev_dbg(&acm->control->dev, "%s\n", __func__); @@ -503,19 +547,13 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)  	acm->control->needs_remote_wakeup = 1;  	acm->ctrlurb->dev = acm->dev; -	if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { +	retval = usb_submit_urb(acm->ctrlurb, GFP_KERNEL); +	if (retval) {  		dev_err(&acm->control->dev,  			"%s - usb_submit_urb(ctrl irq) failed\n", __func__);  		goto error_submit_urb;  	} -	acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS; -	if (acm_set_control(acm, acm->ctrlout) < 0 && -	    (acm->ctrl_caps & USB_CDC_CAP_LINE)) -		goto error_set_control; - -	usb_autopm_put_interface(acm->control); -  	/*  	 * Unthrottle device in case the TTY was closed while throttled.  	 */ @@ -524,24 +562,27 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)  	acm->throttle_req = 0;  	spin_unlock_irq(&acm->read_lock); -	if (acm_submit_read_urbs(acm, GFP_KERNEL)) +	retval = acm_submit_read_urbs(acm, GFP_KERNEL); +	if (retval)  		goto error_submit_read_urbs; +	usb_autopm_put_interface(acm->control); +  	mutex_unlock(&acm->mutex);  	return 0;  error_submit_read_urbs: -	acm->ctrlout = 0; -	acm_set_control(acm, acm->ctrlout); -error_set_control: +	for (i = 0; i < acm->rx_buflimit; i++) +		usb_kill_urb(acm->read_urbs[i]);  	usb_kill_urb(acm->ctrlurb);  error_submit_urb:  	usb_autopm_put_interface(acm->control);  error_get_interface:  disconnected:  	mutex_unlock(&acm->mutex); -	return retval; + +	return usb_translate_errors(retval);  }  static void acm_port_destruct(struct tty_port *port) @@ -559,23 +600,37 @@ static void acm_port_destruct(struct tty_port *port)  static void acm_port_shutdown(struct tty_port *port)  {  	struct acm *acm = container_of(port, struct acm, port); +	struct urb *urb; +	struct acm_wb *wb;  	int i;  	dev_dbg(&acm->control->dev, "%s\n", __func__); -	mutex_lock(&acm->mutex); -	if (!acm->disconnected) { -		usb_autopm_get_interface(acm->control); -		acm_set_control(acm, acm->ctrlout = 0); -		usb_kill_urb(acm->ctrlurb); -		for (i = 0; i < ACM_NW; i++) -			usb_kill_urb(acm->wb[i].urb); -		for (i = 0; i < acm->rx_buflimit; i++) -			usb_kill_urb(acm->read_urbs[i]); -		acm->control->needs_remote_wakeup = 0; -		usb_autopm_put_interface(acm->control); +	/* +	 * Need to grab write_lock to prevent race with resume, but no need to +	 * hold it due to the tty-port initialised flag. +	 */ +	spin_lock_irq(&acm->write_lock); +	spin_unlock_irq(&acm->write_lock); + +	usb_autopm_get_interface_no_resume(acm->control); +	acm->control->needs_remote_wakeup = 0; +	usb_autopm_put_interface(acm->control); + +	for (;;) { +		urb = usb_get_from_anchor(&acm->delayed); +		if (!urb) +			break; +		wb = urb->context; +		wb->use = 0; +		usb_autopm_put_interface_async(acm->control);  	} -	mutex_unlock(&acm->mutex); + +	usb_kill_urb(acm->ctrlurb); +	for (i = 0; i < ACM_NW; i++) +		usb_kill_urb(acm->wb[i].urb); +	for (i = 0; i < acm->rx_buflimit; i++) +		usb_kill_urb(acm->read_urbs[i]);  }  static void acm_tty_cleanup(struct tty_struct *tty) @@ -632,16 +687,18 @@ static int acm_tty_write(struct tty_struct *tty,  	memcpy(wb->buf, buf, count);  	wb->len = count; -	usb_autopm_get_interface_async(acm->control); +	stat = usb_autopm_get_interface_async(acm->control); +	if (stat) { +		wb->use = 0; +		spin_unlock_irqrestore(&acm->write_lock, flags); +		return stat; +	} +  	if (acm->susp_count) { -		if (!acm->delayed_wb) -			acm->delayed_wb = wb; -		else -			usb_autopm_put_interface_async(acm->control); +		usb_anchor_urb(wb->urb, &acm->delayed);  		spin_unlock_irqrestore(&acm->write_lock, flags); -		return count;	/* A white lie */ +		return count;  	} -	usb_mark_last_busy(acm->dev);  	stat = acm_start_wb(acm, wb);  	spin_unlock_irqrestore(&acm->write_lock, flags); @@ -796,6 +853,72 @@ static int set_serial_info(struct acm *acm,  	return retval;  } +static int wait_serial_change(struct acm *acm, unsigned long arg) +{ +	int rv = 0; +	DECLARE_WAITQUEUE(wait, current); +	struct async_icount old, new; + +	if (arg & (TIOCM_DSR | TIOCM_RI | TIOCM_CD )) +		return -EINVAL; +	do { +		spin_lock_irq(&acm->read_lock); +		old = acm->oldcount; +		new = acm->iocount; +		acm->oldcount = new; +		spin_unlock_irq(&acm->read_lock); + +		if ((arg & TIOCM_DSR) && +			old.dsr != new.dsr) +			break; +		if ((arg & TIOCM_CD)  && +			old.dcd != new.dcd) +			break; +		if ((arg & TIOCM_RI) && +			old.rng != new.rng) +			break; + +		add_wait_queue(&acm->wioctl, &wait); +		set_current_state(TASK_INTERRUPTIBLE); +		schedule(); +		remove_wait_queue(&acm->wioctl, &wait); +		if (acm->disconnected) { +			if (arg & TIOCM_CD) +				break; +			else +				rv = -ENODEV; +		} else { +			if (signal_pending(current)) +				rv = -ERESTARTSYS; +		} +	} while (!rv); + +	 + +	return rv; +} + +static int get_serial_usage(struct acm *acm, +			    struct serial_icounter_struct __user *count) +{ +	struct serial_icounter_struct icount; +	int rv = 0; + +	memset(&icount, 0, sizeof(icount)); +	icount.dsr = acm->iocount.dsr; +	icount.rng = acm->iocount.rng; +	icount.dcd = acm->iocount.dcd; +	icount.frame = acm->iocount.frame; +	icount.overrun = acm->iocount.overrun; +	icount.parity = acm->iocount.parity; +	icount.brk = acm->iocount.brk; + +	if (copy_to_user(count, &icount, sizeof(icount)) > 0) +		rv = -EFAULT; + +	return rv; +} +  static int acm_tty_ioctl(struct tty_struct *tty,  					unsigned int cmd, unsigned long arg)  { @@ -809,6 +932,18 @@ static int acm_tty_ioctl(struct tty_struct *tty,  	case TIOCSSERIAL:  		rv = set_serial_info(acm, (struct serial_struct __user *) arg);  		break; +	case TIOCMIWAIT: +		rv = usb_autopm_get_interface(acm->control); +		if (rv < 0) { +			rv = -EIO; +			break; +		} +		rv = wait_serial_change(acm, arg); +		usb_autopm_put_interface(acm->control); +		break; +	case TIOCGICOUNT: +		rv = get_serial_usage(acm, (struct serial_icounter_struct __user *) arg); +		break;  	}  	return rv; @@ -866,6 +1001,7 @@ static void acm_tty_set_termios(struct tty_struct *tty,  }  static const struct tty_port_operations acm_port_ops = { +	.dtr_rts = acm_port_dtr_rts,  	.shutdown = acm_port_shutdown,  	.activate = acm_port_activate,  	.destruct = acm_port_destruct, @@ -1167,6 +1303,7 @@ made_compressed_probe:  	acm->readsize = readsize;  	acm->rx_buflimit = num_rx_buf;  	INIT_WORK(&acm->work, acm_softint); +	init_waitqueue_head(&acm->wioctl);  	spin_lock_init(&acm->write_lock);  	spin_lock_init(&acm->read_lock);  	mutex_init(&acm->mutex); @@ -1176,6 +1313,7 @@ made_compressed_probe:  		acm->bInterval = epread->bInterval;  	tty_port_init(&acm->port);  	acm->port.ops = &acm_port_ops; +	init_usb_anchor(&acm->delayed);  	buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);  	if (!buf) { @@ -1301,8 +1439,6 @@ skip_countries:  	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); -	acm_set_control(acm, acm->ctrlout); -  	acm->line.dwDTERate = cpu_to_le32(9600);  	acm->line.bDataBits = 8;  	acm_set_line(acm, &acm->line); @@ -1383,6 +1519,7 @@ static void acm_disconnect(struct usb_interface *intf)  		device_remove_file(&acm->control->dev,  				&dev_attr_iCountryCodeRelDate);  	} +	wake_up_all(&acm->wioctl);  	device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);  	usb_set_intfdata(acm->control, NULL);  	usb_set_intfdata(acm->data, NULL); @@ -1420,27 +1557,20 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)  	struct acm *acm = usb_get_intfdata(intf);  	int cnt; +	spin_lock_irq(&acm->write_lock);  	if (PMSG_IS_AUTO(message)) { -		int b; - -		spin_lock_irq(&acm->write_lock); -		b = acm->transmitting; -		spin_unlock_irq(&acm->write_lock); -		if (b) +		if (acm->transmitting) { +			spin_unlock_irq(&acm->write_lock);  			return -EBUSY; +		}  	} - -	spin_lock_irq(&acm->read_lock); -	spin_lock(&acm->write_lock);  	cnt = acm->susp_count++; -	spin_unlock(&acm->write_lock); -	spin_unlock_irq(&acm->read_lock); +	spin_unlock_irq(&acm->write_lock);  	if (cnt)  		return 0; -	if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) -		stop_data_traffic(acm); +	stop_data_traffic(acm);  	return 0;  } @@ -1448,29 +1578,23 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)  static int acm_resume(struct usb_interface *intf)  {  	struct acm *acm = usb_get_intfdata(intf); -	struct acm_wb *wb; +	struct urb *urb;  	int rv = 0; -	int cnt; -	spin_lock_irq(&acm->read_lock); -	acm->susp_count -= 1; -	cnt = acm->susp_count; -	spin_unlock_irq(&acm->read_lock); +	spin_lock_irq(&acm->write_lock); -	if (cnt) -		return 0; +	if (--acm->susp_count) +		goto out;  	if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { -		rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); +		rv = usb_submit_urb(acm->ctrlurb, GFP_ATOMIC); -		spin_lock_irq(&acm->write_lock); -		if (acm->delayed_wb) { -			wb = acm->delayed_wb; -			acm->delayed_wb = NULL; -			spin_unlock_irq(&acm->write_lock); -			acm_start_wb(acm, wb); -		} else { -			spin_unlock_irq(&acm->write_lock); +		for (;;) { +			urb = usb_get_from_anchor(&acm->delayed); +			if (!urb) +				break; + +			acm_start_wb(acm, urb->context);  		}  		/* @@ -1478,12 +1602,13 @@ static int acm_resume(struct usb_interface *intf)  		 * do the write path at all cost  		 */  		if (rv < 0) -			goto err_out; +			goto out; -		rv = acm_submit_read_urbs(acm, GFP_NOIO); +		rv = acm_submit_read_urbs(acm, GFP_ATOMIC);  	} +out: +	spin_unlock_irq(&acm->write_lock); -err_out:  	return rv;  } @@ -1515,6 +1640,8 @@ static int acm_reset_resume(struct usb_interface *intf)  static const struct usb_device_id acm_ids[] = {  	/* quirky and broken devices */ +	{ USB_DEVICE(0x17ef, 0x7000), /* Lenovo USB modem */ +	.driver_info = NO_UNION_NORMAL, },/* has no union descriptor */  	{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */  	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */  	}, @@ -1558,13 +1685,27 @@ static const struct usb_device_id acm_ids[] = {  	},  	/* Motorola H24 HSPA module: */  	{ USB_DEVICE(0x22b8, 0x2d91) }, /* modem                                */ -	{ USB_DEVICE(0x22b8, 0x2d92) }, /* modem           + diagnostics        */ -	{ USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port                      */ -	{ USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics        */ -	{ USB_DEVICE(0x22b8, 0x2d96) }, /* modem                         + NMEA */ -	{ USB_DEVICE(0x22b8, 0x2d97) }, /* modem           + diagnostics + NMEA */ -	{ USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port               + NMEA */ -	{ USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */ +	{ USB_DEVICE(0x22b8, 0x2d92),   /* modem           + diagnostics        */ +	.driver_info = NO_UNION_NORMAL, /* handle only modem interface          */ +	}, +	{ USB_DEVICE(0x22b8, 0x2d93),   /* modem + AT port                      */ +	.driver_info = NO_UNION_NORMAL, /* handle only modem interface          */ +	}, +	{ USB_DEVICE(0x22b8, 0x2d95),   /* modem + AT port + diagnostics        */ +	.driver_info = NO_UNION_NORMAL, /* handle only modem interface          */ +	}, +	{ USB_DEVICE(0x22b8, 0x2d96),   /* modem                         + NMEA */ +	.driver_info = NO_UNION_NORMAL, /* handle only modem interface          */ +	}, +	{ USB_DEVICE(0x22b8, 0x2d97),   /* modem           + diagnostics + NMEA */ +	.driver_info = NO_UNION_NORMAL, /* handle only modem interface          */ +	}, +	{ USB_DEVICE(0x22b8, 0x2d99),   /* modem + AT port               + NMEA */ +	.driver_info = NO_UNION_NORMAL, /* handle only modem interface          */ +	}, +	{ USB_DEVICE(0x22b8, 0x2d9a),   /* modem + AT port + diagnostics + NMEA */ +	.driver_info = NO_UNION_NORMAL, /* handle only modem interface          */ +	},  	{ USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */  	.driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 0f76e4af600..fc75651afe1 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -106,6 +106,9 @@ struct acm {  	struct work_struct work;			/* work queue entry for line discipline waking up */  	unsigned int ctrlin;				/* input control lines (DCD, DSR, RI, break, overruns) */  	unsigned int ctrlout;				/* output control lines (DTR, RTS) */ +	struct async_icount iocount;			/* counters for control line changes */ +	struct async_icount oldcount;			/* for comparison of counter */ +	wait_queue_head_t wioctl;			/* for ioctl */  	unsigned int writesize;				/* max packet size for the output bulk endpoint */  	unsigned int readsize,ctrlsize;			/* buffer sizes for freeing */  	unsigned int minor;				/* acm minor number */ @@ -117,15 +120,15 @@ struct acm {  	unsigned int throttled:1;			/* actually throttled */  	unsigned int throttle_req:1;			/* throttle requested */  	u8 bInterval; -	struct acm_wb *delayed_wb;			/* write queued for a device about to be woken */ +	struct usb_anchor delayed;			/* writes queued for a device about to be woken */  };  #define CDC_DATA_INTERFACE_TYPE	0x0a  /* constants describing various quirks and errors */ -#define NO_UNION_NORMAL			1 -#define SINGLE_RX_URB			2 -#define NO_CAP_LINE			4 -#define NOT_A_MODEM			8 -#define NO_DATA_INTERFACE		16 -#define IGNORE_DEVICE			32 +#define NO_UNION_NORMAL			BIT(0) +#define SINGLE_RX_URB			BIT(1) +#define NO_CAP_LINE			BIT(2) +#define NOT_A_MODEM			BIT(3) +#define NO_DATA_INTERFACE		BIT(4) +#define IGNORE_DEVICE			BIT(5) diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index d3318a0df8e..a051a7a2b1b 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -101,6 +101,7 @@ struct wdm_device {  	struct work_struct	rxwork;  	int			werr;  	int			rerr; +	int                     resp_count;  	struct list_head	device_list;  	int			(*manage_power)(struct usb_interface *, int); @@ -253,6 +254,10 @@ static void wdm_int_callback(struct urb *urb)  			"NOTIFY_NETWORK_CONNECTION %s network",  			dr->wValue ? "connected to" : "disconnected from");  		goto exit; +	case USB_CDC_NOTIFY_SPEED_CHANGE: +		dev_dbg(&desc->intf->dev, "SPEED_CHANGE received (len %u)", +			urb->actual_length); +		goto exit;  	default:  		clear_bit(WDM_POLL_RUNNING, &desc->flags);  		dev_err(&desc->intf->dev, @@ -262,9 +267,9 @@ static void wdm_int_callback(struct urb *urb)  	}  	spin_lock(&desc->iuspin); -	clear_bit(WDM_READ, &desc->flags);  	responding = test_and_set_bit(WDM_RESPONDING, &desc->flags); -	if (!responding && !test_bit(WDM_DISCONNECTING, &desc->flags) +	if (!desc->resp_count++ && !responding +		&& !test_bit(WDM_DISCONNECTING, &desc->flags)  		&& !test_bit(WDM_SUSPENDING, &desc->flags)) {  		rv = usb_submit_urb(desc->response, GFP_ATOMIC);  		dev_dbg(&desc->intf->dev, "%s: usb_submit_urb %d", @@ -427,6 +432,38 @@ outnl:  	return rv < 0 ? rv : count;  } +/* + * clear WDM_READ flag and possibly submit the read urb if resp_count + * is non-zero. + * + * Called with desc->iuspin locked + */ +static int clear_wdm_read_flag(struct wdm_device *desc) +{ +	int rv = 0; + +	clear_bit(WDM_READ, &desc->flags); + +	/* submit read urb only if the device is waiting for it */ +	if (!desc->resp_count || !--desc->resp_count) +		goto out; + +	set_bit(WDM_RESPONDING, &desc->flags); +	spin_unlock_irq(&desc->iuspin); +	rv = usb_submit_urb(desc->response, GFP_KERNEL); +	spin_lock_irq(&desc->iuspin); +	if (rv) { +		dev_err(&desc->intf->dev, +			"usb_submit_urb failed with result %d\n", rv); + +		/* make sure the next notification trigger a submit */ +		clear_bit(WDM_RESPONDING, &desc->flags); +		desc->resp_count = 0; +	} +out: +	return rv; +} +  static ssize_t wdm_read  (struct file *file, char __user *buffer, size_t count, loff_t *ppos)  { @@ -498,8 +535,10 @@ retry:  		if (!desc->reslength) { /* zero length read */  			dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); -			clear_bit(WDM_READ, &desc->flags); +			rv = clear_wdm_read_flag(desc);  			spin_unlock_irq(&desc->iuspin); +			if (rv < 0) +				goto err;  			goto retry;  		}  		cntr = desc->length; @@ -522,10 +561,8 @@ retry:  	desc->length -= cntr;  	/* in case we had outstanding data */  	if (!desc->length) -		clear_bit(WDM_READ, &desc->flags); - +		clear_wdm_read_flag(desc);  	spin_unlock_irq(&desc->iuspin); -  	rv = cntr;  err: @@ -635,6 +672,9 @@ static int wdm_release(struct inode *inode, struct file *file)  		if (!test_bit(WDM_DISCONNECTING, &desc->flags)) {  			dev_dbg(&desc->intf->dev, "wdm_release: cleanup");  			kill_urbs(desc); +			spin_lock_irq(&desc->iuspin); +			desc->resp_count = 0; +			spin_unlock_irq(&desc->iuspin);  			desc->manage_power(desc->intf, 0);  		} else {  			/* must avoid dev_printk here as desc->intf is invalid */ @@ -820,13 +860,11 @@ static int wdm_manage_power(struct usb_interface *intf, int on)  {  	/* need autopm_get/put here to ensure the usbcore sees the new value */  	int rv = usb_autopm_get_interface(intf); -	if (rv < 0) -		goto err;  	intf->needs_remote_wakeup = on; -	usb_autopm_put_interface(intf); -err: -	return rv; +	if (!rv) +		usb_autopm_put_interface(intf); +	return 0;  }  static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id) diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index d4c47d5d762..0924ee40a96 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -52,7 +52,6 @@  #include <linux/sched.h>  #include <linux/signal.h>  #include <linux/poll.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/lp.h>  #include <linux/mutex.h> diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 09de131ee0c..103a6e9ee49 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -21,7 +21,6 @@  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <linux/init.h>  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/fs.h> @@ -384,9 +383,12 @@ exit:  static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t transfer_size)  {  	int retval; -	u8 buffer[USBTMC_HEADER_SIZE]; +	u8 *buffer;  	int actual; +	buffer = kmalloc(USBTMC_HEADER_SIZE, GFP_KERNEL); +	if (!buffer) +		return -ENOMEM;  	/* Setup IO buffer for REQUEST_DEV_DEP_MSG_IN message  	 * Refer to class specs for details  	 */ @@ -418,6 +420,7 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t  	if (!data->bTag)  		data->bTag++; +	kfree(buffer);  	if (retval < 0) {  		dev_err(&data->intf->dev, "usb_bulk_msg in send_request_dev_dep_msg_in() returned %d\n", retval);  		return retval; diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile new file mode 100644 index 00000000000..752646167e1 --- /dev/null +++ b/drivers/usb/common/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the usb common parts. +# + +obj-$(CONFIG_USB_COMMON) += usb-common.o +obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o diff --git a/drivers/usb/usb-common.c b/drivers/usb/common/usb-common.c index d771870a819..6dfd30a863c 100644 --- a/drivers/usb/usb-common.c +++ b/drivers/usb/common/usb-common.c @@ -69,7 +69,7 @@ const char *usb_state_string(enum usb_device_state state)  		[USB_STATE_RECONNECTING] = "reconnecting",  		[USB_STATE_UNAUTHENTICATED] = "unauthenticated",  		[USB_STATE_DEFAULT] = "default", -		[USB_STATE_ADDRESS] = "addresssed", +		[USB_STATE_ADDRESS] = "addressed",  		[USB_STATE_CONFIGURED] = "configured",  		[USB_STATE_SUSPENDED] = "suspended",  	}; diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/common/usb-otg-fsm.c index 7f4596606e1..98e8340a5bb 100644 --- a/drivers/usb/phy/phy-fsm-usb.c +++ b/drivers/usb/common/usb-otg-fsm.c @@ -23,13 +23,12 @@  #include <linux/kernel.h>  #include <linux/types.h> -#include <linux/spinlock.h> +#include <linux/mutex.h>  #include <linux/delay.h>  #include <linux/usb.h>  #include <linux/usb/gadget.h>  #include <linux/usb/otg.h> - -#include "phy-fsm-usb.h" +#include <linux/usb/otg-fsm.h>  /* Change USB protocol when there is a protocol change */  static int otg_set_protocol(struct otg_fsm *fsm, int protocol) @@ -41,17 +40,17 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)  			fsm->protocol, protocol);  		/* stop old protocol */  		if (fsm->protocol == PROTO_HOST) -			ret = fsm->ops->start_host(fsm, 0); +			ret = otg_start_host(fsm, 0);  		else if (fsm->protocol == PROTO_GADGET) -			ret = fsm->ops->start_gadget(fsm, 0); +			ret = otg_start_gadget(fsm, 0);  		if (ret)  			return ret;  		/* start new protocol */  		if (protocol == PROTO_HOST) -			ret = fsm->ops->start_host(fsm, 1); +			ret = otg_start_host(fsm, 1);  		else if (protocol == PROTO_GADGET) -			ret = fsm->ops->start_gadget(fsm, 1); +			ret = otg_start_gadget(fsm, 1);  		if (ret)  			return ret; @@ -65,46 +64,54 @@ static int otg_set_protocol(struct otg_fsm *fsm, int protocol)  static int state_changed;  /* Called when leaving a state.  Do state clean up jobs here */ -void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state) +static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)  {  	switch (old_state) {  	case OTG_STATE_B_IDLE: -		otg_del_timer(fsm, b_se0_srp_tmr); +		otg_del_timer(fsm, B_SE0_SRP);  		fsm->b_se0_srp = 0; +		fsm->adp_sns = 0; +		fsm->adp_prb = 0;  		break;  	case OTG_STATE_B_SRP_INIT: +		fsm->data_pulse = 0;  		fsm->b_srp_done = 0;  		break;  	case OTG_STATE_B_PERIPHERAL:  		break;  	case OTG_STATE_B_WAIT_ACON: -		otg_del_timer(fsm, b_ase0_brst_tmr); +		otg_del_timer(fsm, B_ASE0_BRST);  		fsm->b_ase0_brst_tmout = 0;  		break;  	case OTG_STATE_B_HOST:  		break;  	case OTG_STATE_A_IDLE: +		fsm->adp_prb = 0;  		break;  	case OTG_STATE_A_WAIT_VRISE: -		otg_del_timer(fsm, a_wait_vrise_tmr); +		otg_del_timer(fsm, A_WAIT_VRISE);  		fsm->a_wait_vrise_tmout = 0;  		break;  	case OTG_STATE_A_WAIT_BCON: -		otg_del_timer(fsm, a_wait_bcon_tmr); +		otg_del_timer(fsm, A_WAIT_BCON);  		fsm->a_wait_bcon_tmout = 0;  		break;  	case OTG_STATE_A_HOST: -		otg_del_timer(fsm, a_wait_enum_tmr); +		otg_del_timer(fsm, A_WAIT_ENUM);  		break;  	case OTG_STATE_A_SUSPEND: -		otg_del_timer(fsm, a_aidl_bdis_tmr); +		otg_del_timer(fsm, A_AIDL_BDIS);  		fsm->a_aidl_bdis_tmout = 0; -		fsm->a_suspend_req = 0; +		fsm->a_suspend_req_inf = 0;  		break;  	case OTG_STATE_A_PERIPHERAL: +		otg_del_timer(fsm, A_BIDL_ADIS); +		fsm->a_bidl_adis_tmout = 0;  		break;  	case OTG_STATE_A_WAIT_VFALL: -		otg_del_timer(fsm, a_wait_vrise_tmr); +		otg_del_timer(fsm, A_WAIT_VFALL); +		fsm->a_wait_vfall_tmout = 0; +		otg_del_timer(fsm, A_WAIT_VRISE);  		break;  	case OTG_STATE_A_VBUS_ERR:  		break; @@ -114,7 +121,7 @@ void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)  }  /* Called when entering a state */ -int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state) +static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)  {  	state_changed = 1;  	if (fsm->otg->phy->state == new_state) @@ -127,14 +134,19 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)  		otg_chrg_vbus(fsm, 0);  		otg_loc_conn(fsm, 0);  		otg_loc_sof(fsm, 0); +		/* +		 * Driver is responsible for starting ADP probing +		 * if ADP sensing times out. +		 */ +		otg_start_adp_sns(fsm);  		otg_set_protocol(fsm, PROTO_UNDEF); -		otg_add_timer(fsm, b_se0_srp_tmr); +		otg_add_timer(fsm, B_SE0_SRP);  		break;  	case OTG_STATE_B_SRP_INIT:  		otg_start_pulse(fsm);  		otg_loc_sof(fsm, 0);  		otg_set_protocol(fsm, PROTO_UNDEF); -		otg_add_timer(fsm, b_srp_fail_tmr); +		otg_add_timer(fsm, B_SRP_FAIL);  		break;  	case OTG_STATE_B_PERIPHERAL:  		otg_chrg_vbus(fsm, 0); @@ -147,7 +159,7 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)  		otg_loc_conn(fsm, 0);  		otg_loc_sof(fsm, 0);  		otg_set_protocol(fsm, PROTO_HOST); -		otg_add_timer(fsm, b_ase0_brst_tmr); +		otg_add_timer(fsm, B_ASE0_BRST);  		fsm->a_bus_suspend = 0;  		break;  	case OTG_STATE_B_HOST: @@ -163,6 +175,7 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)  		otg_chrg_vbus(fsm, 0);  		otg_loc_conn(fsm, 0);  		otg_loc_sof(fsm, 0); +		otg_start_adp_prb(fsm);  		otg_set_protocol(fsm, PROTO_HOST);  		break;  	case OTG_STATE_A_WAIT_VRISE: @@ -170,14 +183,14 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)  		otg_loc_conn(fsm, 0);  		otg_loc_sof(fsm, 0);  		otg_set_protocol(fsm, PROTO_HOST); -		otg_add_timer(fsm, a_wait_vrise_tmr); +		otg_add_timer(fsm, A_WAIT_VRISE);  		break;  	case OTG_STATE_A_WAIT_BCON:  		otg_drv_vbus(fsm, 1);  		otg_loc_conn(fsm, 0);  		otg_loc_sof(fsm, 0);  		otg_set_protocol(fsm, PROTO_HOST); -		otg_add_timer(fsm, a_wait_bcon_tmr); +		otg_add_timer(fsm, A_WAIT_BCON);  		break;  	case OTG_STATE_A_HOST:  		otg_drv_vbus(fsm, 1); @@ -188,15 +201,15 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)  		 * When HNP is triggered while a_bus_req = 0, a_host will  		 * suspend too fast to complete a_set_b_hnp_en  		 */ -		if (!fsm->a_bus_req || fsm->a_suspend_req) -			otg_add_timer(fsm, a_wait_enum_tmr); +		if (!fsm->a_bus_req || fsm->a_suspend_req_inf) +			otg_add_timer(fsm, A_WAIT_ENUM);  		break;  	case OTG_STATE_A_SUSPEND:  		otg_drv_vbus(fsm, 1);  		otg_loc_conn(fsm, 0);  		otg_loc_sof(fsm, 0);  		otg_set_protocol(fsm, PROTO_HOST); -		otg_add_timer(fsm, a_aidl_bdis_tmr); +		otg_add_timer(fsm, A_AIDL_BDIS);  		break;  	case OTG_STATE_A_PERIPHERAL: @@ -204,12 +217,14 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)  		otg_loc_sof(fsm, 0);  		otg_set_protocol(fsm, PROTO_GADGET);  		otg_drv_vbus(fsm, 1); +		otg_add_timer(fsm, A_BIDL_ADIS);  		break;  	case OTG_STATE_A_WAIT_VFALL:  		otg_drv_vbus(fsm, 0);  		otg_loc_conn(fsm, 0);  		otg_loc_sof(fsm, 0);  		otg_set_protocol(fsm, PROTO_HOST); +		otg_add_timer(fsm, A_WAIT_VFALL);  		break;  	case OTG_STATE_A_VBUS_ERR:  		otg_drv_vbus(fsm, 0); @@ -229,9 +244,8 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)  int otg_statemachine(struct otg_fsm *fsm)  {  	enum usb_otg_state state; -	unsigned long flags; -	spin_lock_irqsave(&fsm->lock, flags); +	mutex_lock(&fsm->lock);  	state = fsm->otg->phy->state;  	state_changed = 0; @@ -250,7 +264,8 @@ int otg_statemachine(struct otg_fsm *fsm)  			otg_set_state(fsm, OTG_STATE_A_IDLE);  		else if (fsm->b_sess_vld && fsm->otg->gadget)  			otg_set_state(fsm, OTG_STATE_B_PERIPHERAL); -		else if (fsm->b_bus_req && fsm->b_sess_end && fsm->b_se0_srp) +		else if ((fsm->b_bus_req || fsm->adp_change || fsm->power_up) && +				fsm->b_ssend_srp && fsm->b_se0_srp)  			otg_set_state(fsm, OTG_STATE_B_SRP_INIT);  		break;  	case OTG_STATE_B_SRP_INIT: @@ -277,34 +292,38 @@ int otg_statemachine(struct otg_fsm *fsm)  	case OTG_STATE_B_HOST:  		if (!fsm->id || !fsm->b_sess_vld)  			otg_set_state(fsm, OTG_STATE_B_IDLE); -		else if (!fsm->b_bus_req || !fsm->a_conn) +		else if (!fsm->b_bus_req || !fsm->a_conn || fsm->test_device)  			otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);  		break;  	case OTG_STATE_A_IDLE:  		if (fsm->id)  			otg_set_state(fsm, OTG_STATE_B_IDLE); -		else if (!fsm->a_bus_drop && (fsm->a_bus_req || fsm->a_srp_det)) +		else if (!fsm->a_bus_drop && (fsm->a_bus_req || +			  fsm->a_srp_det || fsm->adp_change || fsm->power_up))  			otg_set_state(fsm, OTG_STATE_A_WAIT_VRISE);  		break;  	case OTG_STATE_A_WAIT_VRISE: -		if (fsm->id || fsm->a_bus_drop || fsm->a_vbus_vld || -				fsm->a_wait_vrise_tmout) { +		if (fsm->a_vbus_vld)  			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON); -		} +		else if (fsm->id || fsm->a_bus_drop || +				fsm->a_wait_vrise_tmout) +			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);  		break;  	case OTG_STATE_A_WAIT_BCON:  		if (!fsm->a_vbus_vld)  			otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);  		else if (fsm->b_conn)  			otg_set_state(fsm, OTG_STATE_A_HOST); -		else if (fsm->id | fsm->a_bus_drop | fsm->a_wait_bcon_tmout) +		else if (fsm->id || fsm->a_bus_drop || fsm->a_wait_bcon_tmout)  			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL);  		break;  	case OTG_STATE_A_HOST: -		if ((!fsm->a_bus_req || fsm->a_suspend_req) && +		if (fsm->id || fsm->a_bus_drop) +			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); +		else if ((!fsm->a_bus_req || fsm->a_suspend_req_inf) &&  				fsm->otg->host->b_hnp_enable)  			otg_set_state(fsm, OTG_STATE_A_SUSPEND); -		else if (fsm->id || !fsm->b_conn || fsm->a_bus_drop) +		else if (!fsm->b_conn)  			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);  		else if (!fsm->a_vbus_vld)  			otg_set_state(fsm, OTG_STATE_A_VBUS_ERR); @@ -324,14 +343,13 @@ int otg_statemachine(struct otg_fsm *fsm)  	case OTG_STATE_A_PERIPHERAL:  		if (fsm->id || fsm->a_bus_drop)  			otg_set_state(fsm, OTG_STATE_A_WAIT_VFALL); -		else if (fsm->b_bus_suspend) +		else if (fsm->a_bidl_adis_tmout || fsm->b_bus_suspend)  			otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);  		else if (!fsm->a_vbus_vld)  			otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);  		break;  	case OTG_STATE_A_WAIT_VFALL: -		if (fsm->id || fsm->a_bus_req || (!fsm->a_sess_vld && -					!fsm->b_conn)) +		if (fsm->a_wait_vfall_tmout)  			otg_set_state(fsm, OTG_STATE_A_IDLE);  		break;  	case OTG_STATE_A_VBUS_ERR: @@ -341,8 +359,9 @@ int otg_statemachine(struct otg_fsm *fsm)  	default:  		break;  	} -	spin_unlock_irqrestore(&fsm->lock, flags); +	mutex_unlock(&fsm->lock);  	VDBG("quit statemachine, changed = %d\n", state_changed);  	return state_changed;  } +EXPORT_SYMBOL_GPL(otg_statemachine); diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index db535b0aa17..1060657ca1b 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -1,16 +1,8 @@  #  # USB Core configuration  # -config USB_DEBUG -	bool "USB verbose debug messages" -	help -	  Say Y here if you want the USB core & hub drivers to produce a bunch -	  of debug messages to the system log. Select this if you are having a -	  problem with USB support and want to see more of what is going on. -  config USB_ANNOUNCE_NEW_DEVICES  	bool "USB announce new devices" -	default N  	help  	  Say Y here if you want the USB core to always announce the  	  idVendor, idProduct, Manufacturer, Product, and SerialNumber @@ -28,7 +20,7 @@ config USB_DEFAULT_PERSIST  	bool "Enable USB persist by default"  	default y  	help -	  Say N here if you don't want USB power session persistance +	  Say N here if you don't want USB power session persistence  	  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 @@ -89,3 +81,12 @@ config USB_OTG_BLACKLIST_HUB  	  and software costs by not supporting external hubs.  So  	  are "Embedded Hosts" that don't offer OTG support. +config USB_OTG_FSM +	tristate "USB 2.0 OTG FSM implementation" +	depends on USB +	select USB_OTG +	select USB_PHY +	help +	  Implements OTG Finite State Machine as specified in On-The-Go +	  and Embedded Host Supplement to the USB Revision 2.0 Specification. + diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 5e847ad2f58..2f6f9322004 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -2,8 +2,6 @@  # Makefile for USB Core files and filesystem  # -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG -  usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o  usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o  usbcore-y += devio.o notify.o generic.o quirks.o devices.o diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index 23559746be9..684ef70dc09 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -2,7 +2,7 @@   * DMA memory management for framework level HCD code (hc_driver)   *   * This implementation plugs in through generic "usb_bus" level methods, - * and should work with all USB controllers, regardles of bus type. + * and should work with all USB controllers, regardless of bus type.   */  #include <linux/module.h> diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index a6b2cabe793..1ab4df1de2d 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -3,7 +3,6 @@  #include <linux/usb/hcd.h>  #include <linux/usb/quirks.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/device.h>  #include <asm/byteorder.h> @@ -11,7 +10,6 @@  #define USB_MAXALTSETTING		128	/* Hard limit */ -#define USB_MAXENDPOINTS		30	/* Hard limit */  #define USB_MAXCONFIG			8	/* Arbitrary limit */ @@ -651,10 +649,6 @@ void usb_destroy_configuration(struct usb_device *dev)   *   * hub-only!! ... and only in reset path, or usb_new_device()   * (used by real hubs and virtual root hubs) - * - * NOTE: if this is a WUSB device and is not authorized, we skip the - *       whole thing. A non-authorized USB device has no - *       configurations.   */  int usb_get_configuration(struct usb_device *dev)  { @@ -666,8 +660,6 @@ int usb_get_configuration(struct usb_device *dev)  	struct usb_config_descriptor *desc;  	cfgno = 0; -	if (dev->authorized == 0)	/* Not really an error */ -		goto out_not_authorized;  	result = -ENOMEM;  	if (ncfg > USB_MAXCONFIG) {  		dev_warn(ddev, "too many configurations: %d, " @@ -724,6 +716,10 @@ int usb_get_configuration(struct usb_device *dev)  			result = -ENOMEM;  			goto err;  		} + +		if (dev->quirks & USB_QUIRK_DELAY_INIT) +			msleep(100); +  		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,  		    bigbuffer, length);  		if (result < 0) { @@ -751,7 +747,6 @@ int usb_get_configuration(struct usb_device *dev)  err:  	kfree(desc); -out_not_authorized:  	dev->descriptor.bNumConfigurations = cfgno;  err2:  	if (result == -ENOMEM) diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 737e3c19967..257876ea03a 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -62,7 +62,7 @@  /* Mutual exclusion for removal, open, and release */  DEFINE_MUTEX(usbfs_mutex); -struct dev_state { +struct usb_dev_state {  	struct list_head list;      /* state list */  	struct usb_device *dev;  	struct file *file; @@ -81,7 +81,7 @@ struct dev_state {  struct async {  	struct list_head asynclist; -	struct dev_state *ps; +	struct usb_dev_state *ps;  	struct pid *pid;  	const struct cred *cred;  	unsigned int signr; @@ -118,7 +118,7 @@ module_param(usbfs_memory_mb, uint, 0644);  MODULE_PARM_DESC(usbfs_memory_mb,  		"maximum MB allowed for usbfs buffers (0 = no limit)"); -/* Hard limit, necessary to avoid aithmetic overflow */ +/* Hard limit, necessary to avoid arithmetic overflow */  #define USBFS_XFER_MAX		(UINT_MAX / 2 - 1000000)  static atomic_t usbfs_memory_usage;	/* Total memory currently allocated */ @@ -151,7 +151,7 @@ static void usbfs_decrease_memory_usage(unsigned amount)  	atomic_sub(amount, &usbfs_memory_usage);  } -static int connected(struct dev_state *ps) +static int connected(struct usb_dev_state *ps)  {  	return (!list_empty(&ps->list) &&  			ps->dev->state != USB_STATE_NOTATTACHED); @@ -184,7 +184,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)  static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,  			   loff_t *ppos)  { -	struct dev_state *ps = file->private_data; +	struct usb_dev_state *ps = file->private_data;  	struct usb_device *dev = ps->dev;  	ssize_t ret = 0;  	unsigned len; @@ -307,7 +307,7 @@ static void free_async(struct async *as)  static void async_newpending(struct async *as)  { -	struct dev_state *ps = as->ps; +	struct usb_dev_state *ps = as->ps;  	unsigned long flags;  	spin_lock_irqsave(&ps->lock, flags); @@ -317,7 +317,7 @@ static void async_newpending(struct async *as)  static void async_removepending(struct async *as)  { -	struct dev_state *ps = as->ps; +	struct usb_dev_state *ps = as->ps;  	unsigned long flags;  	spin_lock_irqsave(&ps->lock, flags); @@ -325,7 +325,7 @@ static void async_removepending(struct async *as)  	spin_unlock_irqrestore(&ps->lock, flags);  } -static struct async *async_getcompleted(struct dev_state *ps) +static struct async *async_getcompleted(struct usb_dev_state *ps)  {  	unsigned long flags;  	struct async *as = NULL; @@ -340,7 +340,7 @@ static struct async *async_getcompleted(struct dev_state *ps)  	return as;  } -static struct async *async_getpending(struct dev_state *ps, +static struct async *async_getpending(struct usb_dev_state *ps,  					     void __user *userurb)  {  	struct async *as; @@ -448,7 +448,7 @@ static int copy_urb_data_to_user(u8 __user *userbuffer, struct urb *urb)  #define AS_CONTINUATION	1  #define AS_UNLINK	2 -static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr) +static void cancel_bulk_urbs(struct usb_dev_state *ps, unsigned bulk_addr)  __releases(ps->lock)  __acquires(ps->lock)  { @@ -489,7 +489,7 @@ __acquires(ps->lock)  static void async_completed(struct urb *urb)  {  	struct async *as = urb->context; -	struct dev_state *ps = as->ps; +	struct usb_dev_state *ps = as->ps;  	struct siginfo sinfo;  	struct pid *pid = NULL;  	u32 secid = 0; @@ -529,7 +529,7 @@ static void async_completed(struct urb *urb)  	wake_up(&ps->wait);  } -static void destroy_async(struct dev_state *ps, struct list_head *list) +static void destroy_async(struct usb_dev_state *ps, struct list_head *list)  {  	struct urb *urb;  	struct async *as; @@ -551,7 +551,7 @@ static void destroy_async(struct dev_state *ps, struct list_head *list)  	spin_unlock_irqrestore(&ps->lock, flags);  } -static void destroy_async_on_interface(struct dev_state *ps, +static void destroy_async_on_interface(struct usb_dev_state *ps,  				       unsigned int ifnum)  {  	struct list_head *p, *q, hitlist; @@ -566,7 +566,7 @@ static void destroy_async_on_interface(struct dev_state *ps,  	destroy_async(ps, &hitlist);  } -static void destroy_all_async(struct dev_state *ps) +static void destroy_all_async(struct usb_dev_state *ps)  {  	destroy_async(ps, &ps->async_pending);  } @@ -585,7 +585,7 @@ static int driver_probe(struct usb_interface *intf,  static void driver_disconnect(struct usb_interface *intf)  { -	struct dev_state *ps = usb_get_intfdata(intf); +	struct usb_dev_state *ps = usb_get_intfdata(intf);  	unsigned int ifnum = intf->altsetting->desc.bInterfaceNumber;  	if (!ps) @@ -628,7 +628,7 @@ struct usb_driver usbfs_driver = {  	.resume =	driver_resume,  }; -static int claimintf(struct dev_state *ps, unsigned int ifnum) +static int claimintf(struct usb_dev_state *ps, unsigned int ifnum)  {  	struct usb_device *dev = ps->dev;  	struct usb_interface *intf; @@ -650,7 +650,7 @@ static int claimintf(struct dev_state *ps, unsigned int ifnum)  	return err;  } -static int releaseintf(struct dev_state *ps, unsigned int ifnum) +static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum)  {  	struct usb_device *dev;  	struct usb_interface *intf; @@ -670,7 +670,7 @@ static int releaseintf(struct dev_state *ps, unsigned int ifnum)  	return err;  } -static int checkintf(struct dev_state *ps, unsigned int ifnum) +static int checkintf(struct usb_dev_state *ps, unsigned int ifnum)  {  	if (ps->dev->state != USB_STATE_CONFIGURED)  		return -EHOSTUNREACH; @@ -710,7 +710,7 @@ static int findintfep(struct usb_device *dev, unsigned int ep)  	return -ENOENT;  } -static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, +static int check_ctrlrecip(struct usb_dev_state *ps, unsigned int requesttype,  			   unsigned int request, unsigned int index)  {  	int ret = 0; @@ -742,6 +742,22 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,  		if ((index & ~USB_DIR_IN) == 0)  			return 0;  		ret = findintfep(ps->dev, index); +		if (ret < 0) { +			/* +			 * Some not fully compliant Win apps seem to get +			 * index wrong and have the endpoint number here +			 * rather than the endpoint address (with the +			 * correct direction). Win does let this through, +			 * so we'll not reject it here but leave it to +			 * the device to not break KVM. But we warn. +			 */ +			ret = findintfep(ps->dev, index ^ 0x80); +			if (ret >= 0) +				dev_info(&ps->dev->dev, +					"%s: process %i (%s) requesting ep %02x but needs %02x\n", +					__func__, task_pid_nr(current), +					current->comm, index, index ^ 0x80); +		}  		if (ret >= 0)  			ret = checkintf(ps, ret);  		break; @@ -753,6 +769,88 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,  	return ret;  } +static struct usb_host_endpoint *ep_to_host_endpoint(struct usb_device *dev, +						     unsigned char ep) +{ +	if (ep & USB_ENDPOINT_DIR_MASK) +		return dev->ep_in[ep & USB_ENDPOINT_NUMBER_MASK]; +	else +		return dev->ep_out[ep & USB_ENDPOINT_NUMBER_MASK]; +} + +static int parse_usbdevfs_streams(struct usb_dev_state *ps, +				  struct usbdevfs_streams __user *streams, +				  unsigned int *num_streams_ret, +				  unsigned int *num_eps_ret, +				  struct usb_host_endpoint ***eps_ret, +				  struct usb_interface **intf_ret) +{ +	unsigned int i, num_streams, num_eps; +	struct usb_host_endpoint **eps; +	struct usb_interface *intf = NULL; +	unsigned char ep; +	int ifnum, ret; + +	if (get_user(num_streams, &streams->num_streams) || +	    get_user(num_eps, &streams->num_eps)) +		return -EFAULT; + +	if (num_eps < 1 || num_eps > USB_MAXENDPOINTS) +		return -EINVAL; + +	/* The XHCI controller allows max 2 ^ 16 streams */ +	if (num_streams_ret && (num_streams < 2 || num_streams > 65536)) +		return -EINVAL; + +	eps = kmalloc(num_eps * sizeof(*eps), GFP_KERNEL); +	if (!eps) +		return -ENOMEM; + +	for (i = 0; i < num_eps; i++) { +		if (get_user(ep, &streams->eps[i])) { +			ret = -EFAULT; +			goto error; +		} +		eps[i] = ep_to_host_endpoint(ps->dev, ep); +		if (!eps[i]) { +			ret = -EINVAL; +			goto error; +		} + +		/* usb_alloc/free_streams operate on an usb_interface */ +		ifnum = findintfep(ps->dev, ep); +		if (ifnum < 0) { +			ret = ifnum; +			goto error; +		} + +		if (i == 0) { +			ret = checkintf(ps, ifnum); +			if (ret < 0) +				goto error; +			intf = usb_ifnum_to_if(ps->dev, ifnum); +		} else { +			/* Verify all eps belong to the same interface */ +			if (ifnum != intf->altsetting->desc.bInterfaceNumber) { +				ret = -EINVAL; +				goto error; +			} +		} +	} + +	if (num_streams_ret) +		*num_streams_ret = num_streams; +	*num_eps_ret = num_eps; +	*eps_ret = eps; +	*intf_ret = intf; + +	return 0; + +error: +	kfree(eps); +	return ret; +} +  static int match_devt(struct device *dev, void *data)  {  	return dev->devt == (dev_t) (unsigned long) data; @@ -775,11 +873,11 @@ static struct usb_device *usbdev_lookup_by_devt(dev_t devt)  static int usbdev_open(struct inode *inode, struct file *file)  {  	struct usb_device *dev = NULL; -	struct dev_state *ps; +	struct usb_dev_state *ps;  	int ret;  	ret = -ENOMEM; -	ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL); +	ps = kmalloc(sizeof(struct usb_dev_state), GFP_KERNEL);  	if (!ps)  		goto out_free_ps; @@ -836,7 +934,7 @@ static int usbdev_open(struct inode *inode, struct file *file)  static int usbdev_release(struct inode *inode, struct file *file)  { -	struct dev_state *ps = file->private_data; +	struct usb_dev_state *ps = file->private_data;  	struct usb_device *dev = ps->dev;  	unsigned int ifnum;  	struct async *as; @@ -867,7 +965,7 @@ static int usbdev_release(struct inode *inode, struct file *file)  	return 0;  } -static int proc_control(struct dev_state *ps, void __user *arg) +static int proc_control(struct usb_dev_state *ps, void __user *arg)  {  	struct usb_device *dev = ps->dev;  	struct usbdevfs_ctrltransfer ctrl; @@ -898,10 +996,8 @@ static int proc_control(struct dev_state *ps, void __user *arg)  	snoop(&dev->dev, "control urb: bRequestType=%02x "  		"bRequest=%02x wValue=%04x "  		"wIndex=%04x wLength=%04x\n", -		ctrl.bRequestType, ctrl.bRequest, -		__le16_to_cpup(&ctrl.wValue), -		__le16_to_cpup(&ctrl.wIndex), -		__le16_to_cpup(&ctrl.wLength)); +		ctrl.bRequestType, ctrl.bRequest, ctrl.wValue, +		ctrl.wIndex, ctrl.wLength);  	if (ctrl.bRequestType & 0x80) {  		if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,  					       ctrl.wLength)) { @@ -956,7 +1052,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)  	return ret;  } -static int proc_bulk(struct dev_state *ps, void __user *arg) +static int proc_bulk(struct usb_dev_state *ps, void __user *arg)  {  	struct usb_device *dev = ps->dev;  	struct usbdevfs_bulktransfer bulk; @@ -1029,7 +1125,21 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)  	return ret;  } -static int proc_resetep(struct dev_state *ps, void __user *arg) +static void check_reset_of_active_ep(struct usb_device *udev, +		unsigned int epnum, char *ioctl_name) +{ +	struct usb_host_endpoint **eps; +	struct usb_host_endpoint *ep; + +	eps = (epnum & USB_DIR_IN) ? udev->ep_in : udev->ep_out; +	ep = eps[epnum & 0x0f]; +	if (ep && !list_empty(&ep->urb_list)) +		dev_warn(&udev->dev, "Process %d (%s) called USBDEVFS_%s for active endpoint 0x%02x\n", +				task_pid_nr(current), current->comm, +				ioctl_name, epnum); +} + +static int proc_resetep(struct usb_dev_state *ps, void __user *arg)  {  	unsigned int ep;  	int ret; @@ -1042,11 +1152,12 @@ static int proc_resetep(struct dev_state *ps, void __user *arg)  	ret = checkintf(ps, ret);  	if (ret)  		return ret; +	check_reset_of_active_ep(ps->dev, ep, "RESETEP");  	usb_reset_endpoint(ps->dev, ep);  	return 0;  } -static int proc_clearhalt(struct dev_state *ps, void __user *arg) +static int proc_clearhalt(struct usb_dev_state *ps, void __user *arg)  {  	unsigned int ep;  	int pipe; @@ -1060,6 +1171,7 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg)  	ret = checkintf(ps, ret);  	if (ret)  		return ret; +	check_reset_of_active_ep(ps->dev, ep, "CLEAR_HALT");  	if (ep & USB_DIR_IN)  		pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);  	else @@ -1068,7 +1180,7 @@ static int proc_clearhalt(struct dev_state *ps, void __user *arg)  	return usb_clear_halt(ps->dev, pipe);  } -static int proc_getdriver(struct dev_state *ps, void __user *arg) +static int proc_getdriver(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_getdriver gd;  	struct usb_interface *intf; @@ -1087,7 +1199,7 @@ static int proc_getdriver(struct dev_state *ps, void __user *arg)  	return ret;  } -static int proc_connectinfo(struct dev_state *ps, void __user *arg) +static int proc_connectinfo(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_connectinfo ci = {  		.devnum = ps->dev->devnum, @@ -1099,12 +1211,12 @@ static int proc_connectinfo(struct dev_state *ps, void __user *arg)  	return 0;  } -static int proc_resetdevice(struct dev_state *ps) +static int proc_resetdevice(struct usb_dev_state *ps)  {  	return usb_reset_device(ps->dev);  } -static int proc_setintf(struct dev_state *ps, void __user *arg) +static int proc_setintf(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_setinterface setintf;  	int ret; @@ -1113,11 +1225,14 @@ static int proc_setintf(struct dev_state *ps, void __user *arg)  		return -EFAULT;  	if ((ret = checkintf(ps, setintf.interface)))  		return ret; + +	destroy_async_on_interface(ps, setintf.interface); +  	return usb_set_interface(ps->dev, setintf.interface,  			setintf.altsetting);  } -static int proc_setconfig(struct dev_state *ps, void __user *arg) +static int proc_setconfig(struct usb_dev_state *ps, void __user *arg)  {  	int u;  	int status = 0; @@ -1165,7 +1280,7 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)  	return status;  } -static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, +static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb,  			struct usbdevfs_iso_packet_desc __user *iso_frame_desc,  			void __user *arg)  { @@ -1175,6 +1290,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  	struct usb_ctrlrequest *dr = NULL;  	unsigned int u, totlen, isofrmlen;  	int i, ret, is_in, num_sgs = 0, ifnum = -1; +	int number_of_packets = 0; +	unsigned int stream_id = 0;  	void *buf;  	if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | @@ -1195,15 +1312,10 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  		if (ret)  			return ret;  	} -	if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) { -		is_in = 1; -		ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; -	} else { -		is_in = 0; -		ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK]; -	} +	ep = ep_to_host_endpoint(ps->dev, uurb->endpoint);  	if (!ep)  		return -ENOENT; +	is_in = (uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0;  	u = 0;  	switch(uurb->type) { @@ -1228,7 +1340,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  				      le16_to_cpup(&dr->wIndex));  		if (ret)  			goto error; -		uurb->number_of_packets = 0;  		uurb->buffer_length = le16_to_cpup(&dr->wLength);  		uurb->buffer += 8;  		if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { @@ -1258,17 +1369,17 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  			uurb->type = USBDEVFS_URB_TYPE_INTERRUPT;  			goto interrupt_urb;  		} -		uurb->number_of_packets = 0;  		num_sgs = DIV_ROUND_UP(uurb->buffer_length, USB_SG_SIZE);  		if (num_sgs == 1 || num_sgs > ps->dev->bus->sg_tablesize)  			num_sgs = 0; +		if (ep->streams) +			stream_id = uurb->stream_id;  		break;  	case USBDEVFS_URB_TYPE_INTERRUPT:  		if (!usb_endpoint_xfer_int(&ep->desc))  			return -EINVAL;   interrupt_urb: -		uurb->number_of_packets = 0;  		break;  	case USBDEVFS_URB_TYPE_ISO: @@ -1278,15 +1389,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  			return -EINVAL;  		if (!usb_endpoint_xfer_isoc(&ep->desc))  			return -EINVAL; +		number_of_packets = uurb->number_of_packets;  		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * -				   uurb->number_of_packets; +				   number_of_packets;  		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))  			return -ENOMEM;  		if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {  			ret = -EFAULT;  			goto error;  		} -		for (totlen = u = 0; u < uurb->number_of_packets; u++) { +		for (totlen = u = 0; u < number_of_packets; u++) {  			/*  			 * arbitrary limit need for USB 3.0  			 * bMaxBurst (0~15 allowed, 1~16 packets) @@ -1317,7 +1429,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  		ret = -EFAULT;  		goto error;  	} -	as = alloc_async(uurb->number_of_packets); +	as = alloc_async(number_of_packets);  	if (!as) {  		ret = -ENOMEM;  		goto error; @@ -1411,7 +1523,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  	as->urb->setup_packet = (unsigned char *)dr;  	dr = NULL;  	as->urb->start_frame = uurb->start_frame; -	as->urb->number_of_packets = uurb->number_of_packets; +	as->urb->number_of_packets = number_of_packets; +	as->urb->stream_id = stream_id;  	if (uurb->type == USBDEVFS_URB_TYPE_ISO ||  			ps->dev->speed == USB_SPEED_HIGH)  		as->urb->interval = 1 << min(15, ep->desc.bInterval - 1); @@ -1419,7 +1532,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  		as->urb->interval = ep->desc.bInterval;  	as->urb->context = as;  	as->urb->complete = async_completed; -	for (totlen = u = 0; u < uurb->number_of_packets; u++) { +	for (totlen = u = 0; u < number_of_packets; u++) {  		as->urb->iso_frame_desc[u].offset = totlen;  		as->urb->iso_frame_desc[u].length = isopkt[u].length;  		totlen += isopkt[u].length; @@ -1494,7 +1607,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,  	return ret;  } -static int proc_submiturb(struct dev_state *ps, void __user *arg) +static int proc_submiturb(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_urb uurb; @@ -1506,7 +1619,7 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)  			arg);  } -static int proc_unlinkurb(struct dev_state *ps, void __user *arg) +static int proc_unlinkurb(struct usb_dev_state *ps, void __user *arg)  {  	struct urb *urb;  	struct async *as; @@ -1566,7 +1679,7 @@ err_out:  	return -EFAULT;  } -static struct async *reap_as(struct dev_state *ps) +static struct async *reap_as(struct usb_dev_state *ps)  {  	DECLARE_WAITQUEUE(wait, current);  	struct async *as = NULL; @@ -1589,7 +1702,7 @@ static struct async *reap_as(struct dev_state *ps)  	return as;  } -static int proc_reapurb(struct dev_state *ps, void __user *arg) +static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)  {  	struct async *as = reap_as(ps);  	if (as) { @@ -1602,7 +1715,7 @@ static int proc_reapurb(struct dev_state *ps, void __user *arg)  	return -EIO;  } -static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg) +static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)  {  	int retval;  	struct async *as; @@ -1617,37 +1730,37 @@ static int proc_reapurbnonblock(struct dev_state *ps, void __user *arg)  }  #ifdef CONFIG_COMPAT -static int proc_control_compat(struct dev_state *ps, +static int proc_control_compat(struct usb_dev_state *ps,  				struct usbdevfs_ctrltransfer32 __user *p32)  { -        struct usbdevfs_ctrltransfer __user *p; -        __u32 udata; -        p = compat_alloc_user_space(sizeof(*p)); -        if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) || -            get_user(udata, &p32->data) || +	struct usbdevfs_ctrltransfer __user *p; +	__u32 udata; +	p = compat_alloc_user_space(sizeof(*p)); +	if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) || +	    get_user(udata, &p32->data) ||  	    put_user(compat_ptr(udata), &p->data))  		return -EFAULT; -        return proc_control(ps, p); +	return proc_control(ps, p);  } -static int proc_bulk_compat(struct dev_state *ps, +static int proc_bulk_compat(struct usb_dev_state *ps,  			struct usbdevfs_bulktransfer32 __user *p32)  { -        struct usbdevfs_bulktransfer __user *p; -        compat_uint_t n; -        compat_caddr_t addr; +	struct usbdevfs_bulktransfer __user *p; +	compat_uint_t n; +	compat_caddr_t addr; -        p = compat_alloc_user_space(sizeof(*p)); +	p = compat_alloc_user_space(sizeof(*p)); -        if (get_user(n, &p32->ep) || put_user(n, &p->ep) || -            get_user(n, &p32->len) || put_user(n, &p->len) || -            get_user(n, &p32->timeout) || put_user(n, &p->timeout) || -            get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data)) -                return -EFAULT; +	if (get_user(n, &p32->ep) || put_user(n, &p->ep) || +	    get_user(n, &p32->len) || put_user(n, &p->len) || +	    get_user(n, &p32->timeout) || put_user(n, &p->timeout) || +	    get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data)) +		return -EFAULT; -        return proc_bulk(ps, p); +	return proc_bulk(ps, p);  } -static int proc_disconnectsignal_compat(struct dev_state *ps, void __user *arg) +static int proc_disconnectsignal_compat(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_disconnectsignal32 ds; @@ -1685,7 +1798,7 @@ static int get_urb32(struct usbdevfs_urb *kurb,  	return 0;  } -static int proc_submiturb_compat(struct dev_state *ps, void __user *arg) +static int proc_submiturb_compat(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_urb uurb; @@ -1731,7 +1844,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)  	return 0;  } -static int proc_reapurb_compat(struct dev_state *ps, void __user *arg) +static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)  {  	struct async *as = reap_as(ps);  	if (as) { @@ -1744,7 +1857,7 @@ static int proc_reapurb_compat(struct dev_state *ps, void __user *arg)  	return -EIO;  } -static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg) +static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg)  {  	int retval;  	struct async *as; @@ -1761,7 +1874,7 @@ static int proc_reapurbnonblock_compat(struct dev_state *ps, void __user *arg)  #endif -static int proc_disconnectsignal(struct dev_state *ps, void __user *arg) +static int proc_disconnectsignal(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_disconnectsignal ds; @@ -1772,7 +1885,7 @@ static int proc_disconnectsignal(struct dev_state *ps, void __user *arg)  	return 0;  } -static int proc_claiminterface(struct dev_state *ps, void __user *arg) +static int proc_claiminterface(struct usb_dev_state *ps, void __user *arg)  {  	unsigned int ifnum; @@ -1781,7 +1894,7 @@ static int proc_claiminterface(struct dev_state *ps, void __user *arg)  	return claimintf(ps, ifnum);  } -static int proc_releaseinterface(struct dev_state *ps, void __user *arg) +static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg)  {  	unsigned int ifnum;  	int ret; @@ -1794,7 +1907,7 @@ static int proc_releaseinterface(struct dev_state *ps, void __user *arg)  	return 0;  } -static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl) +static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)  {  	int			size;  	void			*buf = NULL; @@ -1870,7 +1983,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)  	return retval;  } -static int proc_ioctl_default(struct dev_state *ps, void __user *arg) +static int proc_ioctl_default(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_ioctl	ctrl; @@ -1880,7 +1993,7 @@ static int proc_ioctl_default(struct dev_state *ps, void __user *arg)  }  #ifdef CONFIG_COMPAT -static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg) +static int proc_ioctl_compat(struct usb_dev_state *ps, compat_uptr_t arg)  {  	struct usbdevfs_ioctl32 __user *uioc;  	struct usbdevfs_ioctl ctrl; @@ -1898,7 +2011,7 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)  }  #endif -static int proc_claim_port(struct dev_state *ps, void __user *arg) +static int proc_claim_port(struct usb_dev_state *ps, void __user *arg)  {  	unsigned portnum;  	int rc; @@ -1912,7 +2025,7 @@ static int proc_claim_port(struct dev_state *ps, void __user *arg)  	return rc;  } -static int proc_release_port(struct dev_state *ps, void __user *arg) +static int proc_release_port(struct usb_dev_state *ps, void __user *arg)  {  	unsigned portnum; @@ -1921,7 +2034,7 @@ static int proc_release_port(struct dev_state *ps, void __user *arg)  	return usb_hub_release_port(ps->dev, portnum, ps);  } -static int proc_get_capabilities(struct dev_state *ps, void __user *arg) +static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)  {  	__u32 caps; @@ -1937,7 +2050,7 @@ static int proc_get_capabilities(struct dev_state *ps, void __user *arg)  	return 0;  } -static int proc_disconnect_claim(struct dev_state *ps, void __user *arg) +static int proc_disconnect_claim(struct usb_dev_state *ps, void __user *arg)  {  	struct usbdevfs_disconnect_claim dc;  	struct usb_interface *intf; @@ -1969,6 +2082,45 @@ static int proc_disconnect_claim(struct dev_state *ps, void __user *arg)  	return claimintf(ps, dc.interface);  } +static int proc_alloc_streams(struct usb_dev_state *ps, void __user *arg) +{ +	unsigned num_streams, num_eps; +	struct usb_host_endpoint **eps; +	struct usb_interface *intf; +	int r; + +	r = parse_usbdevfs_streams(ps, arg, &num_streams, &num_eps, +				   &eps, &intf); +	if (r) +		return r; + +	destroy_async_on_interface(ps, +				   intf->altsetting[0].desc.bInterfaceNumber); + +	r = usb_alloc_streams(intf, eps, num_eps, num_streams, GFP_KERNEL); +	kfree(eps); +	return r; +} + +static int proc_free_streams(struct usb_dev_state *ps, void __user *arg) +{ +	unsigned num_eps; +	struct usb_host_endpoint **eps; +	struct usb_interface *intf; +	int r; + +	r = parse_usbdevfs_streams(ps, arg, NULL, &num_eps, &eps, &intf); +	if (r) +		return r; + +	destroy_async_on_interface(ps, +				   intf->altsetting[0].desc.bInterfaceNumber); + +	r = usb_free_streams(intf, eps, num_eps, GFP_KERNEL); +	kfree(eps); +	return r; +} +  /*   * NOTE:  All requests here that have interface numbers as parameters   * are assuming that somehow the configuration has been prevented from @@ -1977,7 +2129,7 @@ static int proc_disconnect_claim(struct dev_state *ps, void __user *arg)  static long usbdev_do_ioctl(struct file *file, unsigned int cmd,  				void __user *p)  { -	struct dev_state *ps = file->private_data; +	struct usb_dev_state *ps = file->private_data;  	struct inode *inode = file_inode(file);  	struct usb_device *dev = ps->dev;  	int ret = -ENOTTY; @@ -2145,6 +2297,12 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,  	case USBDEVFS_DISCONNECT_CLAIM:  		ret = proc_disconnect_claim(ps, p);  		break; +	case USBDEVFS_ALLOC_STREAMS: +		ret = proc_alloc_streams(ps, p); +		break; +	case USBDEVFS_FREE_STREAMS: +		ret = proc_free_streams(ps, p); +		break;  	}  	usb_unlock_device(dev);  	if (ret >= 0) @@ -2178,7 +2336,7 @@ static long usbdev_compat_ioctl(struct file *file, unsigned int cmd,  static unsigned int usbdev_poll(struct file *file,  				struct poll_table_struct *wait)  { -	struct dev_state *ps = file->private_data; +	struct usb_dev_state *ps = file->private_data;  	unsigned int mask = 0;  	poll_wait(file, &ps->wait, wait); @@ -2204,11 +2362,11 @@ const struct file_operations usbdev_file_operations = {  static void usbdev_remove(struct usb_device *udev)  { -	struct dev_state *ps; +	struct usb_dev_state *ps;  	struct siginfo sinfo;  	while (!list_empty(&udev->filelist)) { -		ps = list_entry(udev->filelist.next, struct dev_state, list); +		ps = list_entry(udev->filelist.next, struct usb_dev_state, list);  		destroy_all_async(ps);  		wake_up_all(&ps->wait);  		list_del_init(&ps->list); diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index f7841d44fed..4aeb10034de 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -37,6 +37,7 @@   * and cause the driver to probe for all devices again.   */  ssize_t usb_store_new_id(struct usb_dynids *dynids, +			 const struct usb_device_id *id_table,  			 struct device_driver *driver,  			 const char *buf, size_t count)  { @@ -44,11 +45,12 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,  	u32 idVendor = 0;  	u32 idProduct = 0;  	unsigned int bInterfaceClass = 0; +	u32 refVendor, refProduct;  	int fields = 0;  	int retval = 0; -	fields = sscanf(buf, "%x %x %x", &idVendor, &idProduct, -					&bInterfaceClass); +	fields = sscanf(buf, "%x %x %x %x %x", &idVendor, &idProduct, +			&bInterfaceClass, &refVendor, &refProduct);  	if (fields < 2)  		return -EINVAL; @@ -60,11 +62,36 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,  	dynid->id.idVendor = idVendor;  	dynid->id.idProduct = idProduct;  	dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE; -	if (fields == 3) { +	if (fields > 2 && bInterfaceClass) { +		if (bInterfaceClass > 255) { +			retval = -EINVAL; +			goto fail; +		} +  		dynid->id.bInterfaceClass = (u8)bInterfaceClass;  		dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;  	} +	if (fields > 4) { +		const struct usb_device_id *id = id_table; + +		if (!id) { +			retval = -ENODEV; +			goto fail; +		} + +		for (; id->match_flags; id++) +			if (id->idVendor == refVendor && id->idProduct == refProduct) +				break; + +		if (id->match_flags) { +			dynid->id.driver_info = id->driver_info; +		} else { +			retval = -ENODEV; +			goto fail; +		} +	} +  	spin_lock(&dynids->lock);  	list_add_tail(&dynid->node, &dynids->list);  	spin_unlock(&dynids->lock); @@ -74,6 +101,10 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,  	if (retval)  		return retval;  	return count; + +fail: +	kfree(dynid); +	return retval;  }  EXPORT_SYMBOL_GPL(usb_store_new_id); @@ -106,7 +137,7 @@ static ssize_t new_id_store(struct device_driver *driver,  {  	struct usb_driver *usb_drv = to_usb_driver(driver); -	return usb_store_new_id(&usb_drv->dynids, driver, buf, count); +	return usb_store_new_id(&usb_drv->dynids, usb_drv->id_table, driver, buf, count);  }  static DRIVER_ATTR_RW(new_id); @@ -281,9 +312,9 @@ static int usb_probe_interface(struct device *dev)  		return error;  	} -	id = usb_match_id(intf, driver->id_table); +	id = usb_match_dynamic_id(intf, driver);  	if (!id) -		id = usb_match_dynamic_id(intf, driver); +		id = usb_match_id(intf, driver->id_table);  	if (!id)  		return error; @@ -369,8 +400,9 @@ static int usb_unbind_interface(struct device *dev)  {  	struct usb_driver *driver = to_usb_driver(dev->driver);  	struct usb_interface *intf = to_usb_interface(dev); +	struct usb_host_endpoint *ep, **eps = NULL;  	struct usb_device *udev; -	int error, r, lpm_disable_error; +	int i, j, error, r, lpm_disable_error;  	intf->condition = USB_INTERFACE_UNBINDING; @@ -394,6 +426,26 @@ static int usb_unbind_interface(struct device *dev)  	driver->disconnect(intf);  	usb_cancel_queued_reset(intf); +	/* Free streams */ +	for (i = 0, j = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) { +		ep = &intf->cur_altsetting->endpoint[i]; +		if (ep->streams == 0) +			continue; +		if (j == 0) { +			eps = kmalloc(USB_MAXENDPOINTS * sizeof(void *), +				      GFP_KERNEL); +			if (!eps) { +				dev_warn(dev, "oom, leaking streams\n"); +				break; +			} +		} +		eps[j++] = ep; +	} +	if (j) { +		usb_free_streams(intf, eps, j, GFP_KERNEL); +		kfree(eps); +	} +  	/* Reset other interface state.  	 * We cannot do a Set-Interface if the device is suspended or  	 * if it is prepared for a system sleep (since installing a new @@ -839,7 +891,7 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver,  		return -ENODEV;  	new_udriver->drvwrap.for_devices = 1; -	new_udriver->drvwrap.driver.name = (char *) new_udriver->name; +	new_udriver->drvwrap.driver.name = new_udriver->name;  	new_udriver->drvwrap.driver.bus = &usb_bus_type;  	new_udriver->drvwrap.driver.probe = usb_probe_device;  	new_udriver->drvwrap.driver.remove = usb_unbind_device; @@ -900,7 +952,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,  		return -ENODEV;  	new_driver->drvwrap.for_devices = 0; -	new_driver->drvwrap.driver.name = (char *) new_driver->name; +	new_driver->drvwrap.driver.name = new_driver->name;  	new_driver->drvwrap.driver.bus = &usb_bus_type;  	new_driver->drvwrap.driver.probe = usb_probe_interface;  	new_driver->drvwrap.driver.remove = usb_unbind_interface; @@ -959,8 +1011,7 @@ EXPORT_SYMBOL_GPL(usb_deregister);   * it doesn't support pre_reset/post_reset/reset_resume or   * because it doesn't support suspend/resume.   * - * The caller must hold @intf's device's lock, but not its pm_mutex - * and not @intf->dev.sem. + * The caller must hold @intf's device's lock, but not @intf's lock.   */  void usb_forced_unbind_intf(struct usb_interface *intf)  { @@ -973,16 +1024,37 @@ void usb_forced_unbind_intf(struct usb_interface *intf)  	intf->needs_binding = 1;  } +/* + * Unbind drivers for @udev's marked interfaces.  These interfaces have + * the needs_binding flag set, for example by usb_resume_interface(). + * + * The caller must hold @udev's device lock. + */ +static void unbind_marked_interfaces(struct usb_device *udev) +{ +	struct usb_host_config	*config; +	int			i; +	struct usb_interface	*intf; + +	config = udev->actconfig; +	if (config) { +		for (i = 0; i < config->desc.bNumInterfaces; ++i) { +			intf = config->interface[i]; +			if (intf->dev.driver && intf->needs_binding) +				usb_forced_unbind_intf(intf); +		} +	} +} +  /* Delayed forced unbinding of a USB interface driver and scan   * for rebinding.   * - * The caller must hold @intf's device's lock, but not its pm_mutex - * and not @intf->dev.sem. + * The caller must hold @intf's device's lock, but not @intf's lock.   *   * Note: Rebinds will be skipped if a system sleep transition is in   * progress and the PM "complete" callback hasn't occurred yet.   */ -void usb_rebind_intf(struct usb_interface *intf) +static void usb_rebind_intf(struct usb_interface *intf)  {  	int rc; @@ -999,68 +1071,66 @@ void usb_rebind_intf(struct usb_interface *intf)  	}  } -#ifdef CONFIG_PM - -/* Unbind drivers for @udev's interfaces that don't support suspend/resume - * There is no check for reset_resume here because it can be determined - * only during resume whether reset_resume is needed. +/* + * Rebind drivers to @udev's marked interfaces.  These interfaces have + * the needs_binding flag set.   *   * The caller must hold @udev's device lock.   */ -static void unbind_no_pm_drivers_interfaces(struct usb_device *udev) +static void rebind_marked_interfaces(struct usb_device *udev)  {  	struct usb_host_config	*config;  	int			i;  	struct usb_interface	*intf; -	struct usb_driver	*drv;  	config = udev->actconfig;  	if (config) {  		for (i = 0; i < config->desc.bNumInterfaces; ++i) {  			intf = config->interface[i]; - -			if (intf->dev.driver) { -				drv = to_usb_driver(intf->dev.driver); -				if (!drv->suspend || !drv->resume) -					usb_forced_unbind_intf(intf); -			} +			if (intf->needs_binding) +				usb_rebind_intf(intf);  		}  	}  } -/* Unbind drivers for @udev's interfaces that failed to support reset-resume. - * These interfaces have the needs_binding flag set by usb_resume_interface(). +/* + * Unbind all of @udev's marked interfaces and then rebind all of them. + * This ordering is necessary because some drivers claim several interfaces + * when they are first probed.   *   * The caller must hold @udev's device lock.   */ -static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev) +void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev)  { -	struct usb_host_config	*config; -	int			i; -	struct usb_interface	*intf; - -	config = udev->actconfig; -	if (config) { -		for (i = 0; i < config->desc.bNumInterfaces; ++i) { -			intf = config->interface[i]; -			if (intf->dev.driver && intf->needs_binding) -				usb_forced_unbind_intf(intf); -		} -	} +	unbind_marked_interfaces(udev); +	rebind_marked_interfaces(udev);  } -static void do_rebind_interfaces(struct usb_device *udev) +#ifdef CONFIG_PM + +/* Unbind drivers for @udev's interfaces that don't support suspend/resume + * There is no check for reset_resume here because it can be determined + * only during resume whether reset_resume is needed. + * + * The caller must hold @udev's device lock. + */ +static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)  {  	struct usb_host_config	*config;  	int			i;  	struct usb_interface	*intf; +	struct usb_driver	*drv;  	config = udev->actconfig;  	if (config) {  		for (i = 0; i < config->desc.bNumInterfaces; ++i) {  			intf = config->interface[i]; -			if (intf->needs_binding) -				usb_rebind_intf(intf); + +			if (intf->dev.driver) { +				drv = to_usb_driver(intf->dev.driver); +				if (!drv->suspend || !drv->resume) +					usb_forced_unbind_intf(intf); +			}  		}  	}  } @@ -1179,8 +1249,8 @@ static int usb_resume_interface(struct usb_device *udev,  						"reset_resume", status);  		} else {  			intf->needs_binding = 1; -			dev_warn(&intf->dev, "no %s for driver %s?\n", -					"reset_resume", driver->name); +			dev_dbg(&intf->dev, "no reset_resume for driver %s?\n", +					driver->name);  		}  	} else {  		status = driver->resume(intf); @@ -1389,7 +1459,7 @@ int usb_resume_complete(struct device *dev)  	 * whose needs_binding flag is set  	 */  	if (udev->state != USB_STATE_NOTATTACHED) -		do_rebind_interfaces(udev); +		rebind_marked_interfaces(udev);  	return 0;  } @@ -1411,7 +1481,7 @@ int usb_resume(struct device *dev, pm_message_t msg)  		pm_runtime_disable(dev);  		pm_runtime_set_active(dev);  		pm_runtime_enable(dev); -		unbind_no_reset_resume_drivers_interfaces(udev); +		unbind_marked_interfaces(udev);  	}  	/* Avoid PM error messages for devices disconnected while suspended @@ -1752,10 +1822,13 @@ int usb_runtime_suspend(struct device *dev)  	if (status == -EAGAIN || status == -EBUSY)  		usb_mark_last_busy(udev); -	/* The PM core reacts badly unless the return code is 0, -	 * -EAGAIN, or -EBUSY, so always return -EBUSY on an error. +	/* +	 * The PM core reacts badly unless the return code is 0, +	 * -EAGAIN, or -EBUSY, so always return -EBUSY on an error +	 * (except for root hubs, because they don't suspend through +	 * an upstream port like other USB devices).  	 */ -	if (status != 0) +	if (status != 0 && udev->parent)  		return -EBUSY;  	return status;  } @@ -1790,6 +1863,9 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)  	struct usb_hcd *hcd = bus_to_hcd(udev->bus);  	int ret = -EPERM; +	if (enable && !udev->usb2_hw_lpm_allowed) +		return 0; +  	if (hcd->driver->set_usb2_hw_lpm) {  		ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable);  		if (!ret) diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index 7421888087a..ea337a718cc 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -8,7 +8,7 @@   * (C) Copyright Deti Fliegl 1999 (new USB architecture)   * (C) Copyright Randy Dunlap 2000   * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id, - 	more docs, etc) + *	more docs, etc)   * (C) Copyright Yggdrasil Computing, Inc. 2000   *     (usb_device_id matching changes by Adam J. Richter)   * (C) Copyright Greg Kroah-Hartman 2002-2003 @@ -27,29 +27,21 @@  static const struct file_operations *usb_minors[MAX_USB_MINORS];  static DECLARE_RWSEM(minor_rwsem); -static int usb_open(struct inode * inode, struct file * file) +static int usb_open(struct inode *inode, struct file *file)  { -	int minor = iminor(inode); -	const struct file_operations *c;  	int err = -ENODEV; -	const struct file_operations *old_fops, *new_fops = NULL; +	const struct file_operations *new_fops;  	down_read(&minor_rwsem); -	c = usb_minors[minor]; +	new_fops = fops_get(usb_minors[iminor(inode)]); -	if (!c || !(new_fops = fops_get(c))) +	if (!new_fops)  		goto done; -	old_fops = file->f_op; -	file->f_op = new_fops; +	replace_fops(file, new_fops);  	/* Curiouser and curiouser... NULL ->open() as "no device" ? */  	if (file->f_op->open) -		err = file->f_op->open(inode,file); -	if (err) { -		fops_put(file->f_op); -		file->f_op = fops_get(old_fops); -	} -	fops_put(old_fops); +		err = file->f_op->open(inode, file);   done:  	up_read(&minor_rwsem);  	return err; @@ -166,7 +158,7 @@ int usb_register_dev(struct usb_interface *intf,  	char *temp;  #ifdef CONFIG_USB_DYNAMIC_MINORS -	/*  +	/*  	 * We don't care what the device tries to start at, we want to start  	 * at zero to pack the devices into the smallest available space with  	 * no holes in the minor range. diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c index acbfeb0a011..358ca8dd784 100644 --- a/drivers/usb/core/generic.c +++ b/drivers/usb/core/generic.c @@ -155,6 +155,7 @@ int usb_choose_configuration(struct usb_device *udev)  	}  	return i;  } +EXPORT_SYMBOL_GPL(usb_choose_configuration);  static int generic_probe(struct usb_device *udev)  { diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index b9d3c43e385..82044b5d611 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -75,7 +75,7 @@ static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd,  				PCI_SLOT(companion->devfn) != slot)  			continue;  		companion_hcd = pci_get_drvdata(companion); -		if (!companion_hcd) +		if (!companion_hcd || !companion_hcd->self.root_hub)  			continue;  		fn(pdev, hcd, companion, companion_hcd);  	} @@ -192,7 +192,6 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  	if (pci_enable_device(dev) < 0)  		return -ENODEV; -	dev->current_state = PCI_D0;  	/*  	 * The xHCI driver has its own irq management @@ -215,6 +214,9 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  		goto disable_pci;  	} +	hcd->amd_resume_bug = (usb_hcd_amd_remote_wakeup_quirk(dev) && +			driver->flags & (HCD_USB11 | HCD_USB3)) ? 1 : 0; +  	if (driver->flags & HCD_MEMORY) {  		/* EHCI, OHCI */  		hcd->rsrc_start = pci_resource_start(dev, 0); @@ -279,6 +281,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  	if (retval != 0)  		goto unmap_registers; +	device_wakeup_enable(hcd->self.controller);  	if (pci_dev_run_wake(dev))  		pm_runtime_put_noidle(&dev->dev); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index d6a8d23f047..bec31e2efb8 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -6,7 +6,7 @@   * (C) Copyright Deti Fliegl 1999   * (C) Copyright Randy Dunlap 2000   * (C) Copyright David Brownell 2000-2002 - *  + *   * This program is free software; you can redistribute it and/or modify it   * under the terms of the GNU General Public License as published by the   * Free Software Foundation; either version 2 of the License, or (at your @@ -40,9 +40,11 @@  #include <linux/platform_device.h>  #include <linux/workqueue.h>  #include <linux/pm_runtime.h> +#include <linux/types.h>  #include <linux/usb.h>  #include <linux/usb/hcd.h> +#include <linux/usb/phy.h>  #include "usb.h" @@ -92,10 +94,7 @@ EXPORT_SYMBOL_GPL (usb_bus_list);  /* used when allocating bus numbers */  #define USB_MAXBUS		64 -struct usb_busmap { -	unsigned long busmap [USB_MAXBUS / (8*sizeof (unsigned long))]; -}; -static struct usb_busmap busmap; +static DECLARE_BITMAP(busmap, USB_MAXBUS);  /* used when updating list of hcds */  DEFINE_MUTEX(usb_bus_list_lock);	/* exported only for usbfs */ @@ -171,7 +170,7 @@ static const u8 usb25_rh_dev_descriptor[18] = {  };  /* usb 2.0 root hub device descriptor */ -static const u8 usb2_rh_dev_descriptor [18] = { +static const u8 usb2_rh_dev_descriptor[18] = {  	0x12,       /*  __u8  bLength; */  	0x01,       /*  __u8  bDescriptorType; Device */  	0x00, 0x02, /*  __le16 bcdUSB; v2.0 */ @@ -194,7 +193,7 @@ static const u8 usb2_rh_dev_descriptor [18] = {  /* no usb 2.0 root hub "device qualifier" descriptor: one speed only */  /* usb 1.1 root hub device descriptor */ -static const u8 usb11_rh_dev_descriptor [18] = { +static const u8 usb11_rh_dev_descriptor[18] = {  	0x12,       /*  __u8  bLength; */  	0x01,       /*  __u8  bDescriptorType; Device */  	0x10, 0x01, /*  __le16 bcdUSB; v1.1 */ @@ -219,7 +218,7 @@ static const u8 usb11_rh_dev_descriptor [18] = {  /* Configuration descriptors for our root hubs */ -static const u8 fs_rh_config_descriptor [] = { +static const u8 fs_rh_config_descriptor[] = {  	/* one configuration */  	0x09,       /*  __u8  bLength; */ @@ -228,13 +227,13 @@ static const u8 fs_rh_config_descriptor [] = {  	0x01,       /*  __u8  bNumInterfaces; (1) */  	0x01,       /*  __u8  bConfigurationValue; */  	0x00,       /*  __u8  iConfiguration; */ -	0xc0,       /*  __u8  bmAttributes;  +	0xc0,       /*  __u8  bmAttributes;  				 Bit 7: must be set,  				     6: Self-powered,  				     5: Remote wakeup,  				     4..0: resvd */  	0x00,       /*  __u8  MaxPower; */ -       +  	/* USB 1.1:  	 * USB 2.0, single TT organization (mandatory):  	 *	one interface, protocol 0 @@ -256,17 +255,17 @@ static const u8 fs_rh_config_descriptor [] = {  	0x00,       /*  __u8  if_bInterfaceSubClass; */  	0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */  	0x00,       /*  __u8  if_iInterface; */ -      +  	/* one endpoint (status change endpoint) */  	0x07,       /*  __u8  ep_bLength; */  	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */  	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */ - 	0x03,       /*  __u8  ep_bmAttributes; Interrupt */ - 	0x02, 0x00, /*  __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ +	0x03,       /*  __u8  ep_bmAttributes; Interrupt */ +	0x02, 0x00, /*  __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */  	0xff        /*  __u8  ep_bInterval; (255ms -- usb 2.0 spec) */  }; -static const u8 hs_rh_config_descriptor [] = { +static const u8 hs_rh_config_descriptor[] = {  	/* one configuration */  	0x09,       /*  __u8  bLength; */ @@ -275,13 +274,13 @@ static const u8 hs_rh_config_descriptor [] = {  	0x01,       /*  __u8  bNumInterfaces; (1) */  	0x01,       /*  __u8  bConfigurationValue; */  	0x00,       /*  __u8  iConfiguration; */ -	0xc0,       /*  __u8  bmAttributes;  +	0xc0,       /*  __u8  bmAttributes;  				 Bit 7: must be set,  				     6: Self-powered,  				     5: Remote wakeup,  				     4..0: resvd */  	0x00,       /*  __u8  MaxPower; */ -       +  	/* USB 1.1:  	 * USB 2.0, single TT organization (mandatory):  	 *	one interface, protocol 0 @@ -303,12 +302,12 @@ static const u8 hs_rh_config_descriptor [] = {  	0x00,       /*  __u8  if_bInterfaceSubClass; */  	0x00,       /*  __u8  if_bInterfaceProtocol; [usb1.1 or single tt] */  	0x00,       /*  __u8  if_iInterface; */ -      +  	/* one endpoint (status change endpoint) */  	0x07,       /*  __u8  ep_bLength; */  	0x05,       /*  __u8  ep_bDescriptorType; Endpoint */  	0x81,       /*  __u8  ep_bEndpointAddress; IN Endpoint 1 */ - 	0x03,       /*  __u8  ep_bmAttributes; Interrupt */ +	0x03,       /*  __u8  ep_bmAttributes; Interrupt */  		    /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)  		     * see hub.c:hub_configure() for details. */  	(USB_MAXCHILDREN + 1 + 7) / 8, 0x00, @@ -428,7 +427,7 @@ rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len)  	char const *s;  	static char const langids[4] = {4, USB_DT_STRING, 0x09, 0x04}; -	// language ids +	/* language ids */  	switch (id) {  	case 0:  		/* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */ @@ -464,7 +463,7 @@ rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len)  static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)  {  	struct usb_ctrlrequest *cmd; - 	u16		typeReq, wValue, wIndex, wLength; +	u16		typeReq, wValue, wIndex, wLength;  	u8		*ubuf = urb->transfer_buffer;  	unsigned	len = 0;  	int		status; @@ -526,10 +525,10 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)  	 */  	case DeviceRequest | USB_REQ_GET_STATUS: -		tbuf [0] = (device_may_wakeup(&hcd->self.root_hub->dev) +		tbuf[0] = (device_may_wakeup(&hcd->self.root_hub->dev)  					<< USB_DEVICE_REMOTE_WAKEUP)  				| (1 << USB_DEVICE_SELF_POWERED); -		tbuf [1] = 0; +		tbuf[1] = 0;  		len = 2;  		break;  	case DeviceOutRequest | USB_REQ_CLEAR_FEATURE: @@ -546,7 +545,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)  			goto error;  		break;  	case DeviceRequest | USB_REQ_GET_CONFIGURATION: -		tbuf [0] = 1; +		tbuf[0] = 1;  		len = 1;  			/* FALLTHROUGH */  	case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: @@ -609,13 +608,13 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)  		}  		break;  	case DeviceRequest | USB_REQ_GET_INTERFACE: -		tbuf [0] = 0; +		tbuf[0] = 0;  		len = 1;  			/* FALLTHROUGH */  	case DeviceOutRequest | USB_REQ_SET_INTERFACE:  		break;  	case DeviceOutRequest | USB_REQ_SET_ADDRESS: -		// wValue == urb->dev->devaddr +		/* wValue == urb->dev->devaddr */  		dev_dbg (hcd->self.controller, "root hub device address %d\n",  			wValue);  		break; @@ -625,9 +624,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)  	/* ENDPOINT REQUESTS */  	case EndpointRequest | USB_REQ_GET_STATUS: -		// ENDPOINT_HALT flag -		tbuf [0] = 0; -		tbuf [1] = 0; +		/* ENDPOINT_HALT flag */ +		tbuf[0] = 0; +		tbuf[1] = 0;  		len = 2;  			/* FALLTHROUGH */  	case EndpointOutRequest | USB_REQ_CLEAR_FEATURE: @@ -683,7 +682,7 @@ error:  		if (urb->transfer_buffer_length < len)  			len = urb->transfer_buffer_length;  		urb->actual_length = len; -		// always USB_DIR_IN, toward host +		/* always USB_DIR_IN, toward host */  		memcpy (ubuf, bufp, len);  		/* report whether RH hardware supports remote wakeup */ @@ -877,11 +876,11 @@ static ssize_t authorized_default_store(struct device *dev,  	usb_hcd = bus_to_hcd(usb_bus);  	result = sscanf(buf, "%u\n", &val);  	if (result == 1) { -		usb_hcd->authorized_default = val? 1 : 0; +		usb_hcd->authorized_default = val ? 1 : 0;  		result = size; -	} -	else +	} else {  		result = -EINVAL; +	}  	return result;  }  static DEVICE_ATTR_RW(authorized_default); @@ -919,6 +918,7 @@ static void usb_bus_init (struct usb_bus *bus)  	bus->bandwidth_allocated = 0;  	bus->bandwidth_int_reqs  = 0;  	bus->bandwidth_isoc_reqs = 0; +	mutex_init(&bus->usb_address0_mutex);  	INIT_LIST_HEAD (&bus->bus_list);  } @@ -941,12 +941,12 @@ static int usb_register_bus(struct usb_bus *bus)  	int busnum;  	mutex_lock(&usb_bus_list_lock); -	busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1); +	busnum = find_next_zero_bit(busmap, USB_MAXBUS, 1);  	if (busnum >= USB_MAXBUS) {  		printk (KERN_ERR "%s: too many buses\n", usbcore_name);  		goto error_find_busnum;  	} -	set_bit (busnum, busmap.busmap); +	set_bit(busnum, busmap);  	bus->busnum = busnum;  	/* Add it to the local list of buses */ @@ -987,7 +987,7 @@ static void usb_deregister_bus (struct usb_bus *bus)  	usb_notify_remove_bus(bus); -	clear_bit (bus->busnum, busmap.busmap); +	clear_bit(bus->busnum, busmap);  }  /** @@ -1120,21 +1120,21 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)  	case USB_SPEED_LOW: 	/* INTR only */  		if (is_input) {  			tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L; -			return (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); +			return 64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp;  		} else {  			tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L; -			return (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp); +			return 64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp;  		}  	case USB_SPEED_FULL:	/* ISOC or INTR */  		if (isoc) {  			tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; -			return (((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp); +			return ((is_input) ? 7268L : 6265L) + BW_HOST_DELAY + tmp;  		} else {  			tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L; -			return (9107L + BW_HOST_DELAY + tmp); +			return 9107L + BW_HOST_DELAY + tmp;  		}  	case USB_SPEED_HIGH:	/* ISOC or INTR */ -		// FIXME adjust for input vs output +		/* FIXME adjust for input vs output */  		if (isoc)  			tmp = HS_NSECS_ISO (bytecount);  		else @@ -1298,7 +1298,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);   *   DMA framework is dma_declare_coherent_memory()   *   * - So we use that, even though the primary requirement - *   is that the memory be "local" (hence addressible + *   is that the memory be "local" (hence addressable   *   by that device), not "coherent".   *   */ @@ -1503,6 +1503,9 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,  					ret = -EAGAIN;  				else  					urb->transfer_flags |= URB_DMA_MAP_PAGE; +			} else if (is_vmalloc_addr(urb->transfer_buffer)) { +				WARN_ONCE(1, "transfer buffer not dma capable\n"); +				ret = -EAGAIN;  			} else {  				urb->transfer_dma = dma_map_single(  						hcd->self.controller, @@ -1651,6 +1654,7 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)  static void __usb_hcd_giveback_urb(struct urb *urb)  {  	struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus); +	struct usb_anchor *anchor = urb->anchor;  	int status = urb->unlinked;  	unsigned long flags; @@ -1662,6 +1666,7 @@ static void __usb_hcd_giveback_urb(struct urb *urb)  	unmap_urb_for_dma(hcd, urb);  	usbmon_urb_complete(&hcd->self, urb, status); +	usb_anchor_suspend_wakeups(anchor);  	usb_unanchor_urb(urb);  	/* pass ownership to the completion handler */ @@ -1681,6 +1686,7 @@ static void __usb_hcd_giveback_urb(struct urb *urb)  	urb->complete(urb);  	local_irq_restore(flags); +	usb_anchor_resume_wakeups(anchor);  	atomic_dec(&urb->use_count);  	if (unlikely(atomic_read(&urb->reject)))  		wake_up(&usb_kill_urb_queue); @@ -1703,7 +1709,9 @@ static void usb_giveback_urb_bh(unsigned long param)  		urb = list_entry(local_list.next, struct urb, urb_list);  		list_del_init(&urb->urb_list); +		bh->completing_ep = urb->ep;  		__usb_hcd_giveback_urb(urb); +		bh->completing_ep = NULL;  	}  	/* check if there are new URBs to giveback */ @@ -1812,7 +1820,7 @@ rescan:  				 case USB_ENDPOINT_XFER_INT:  					s = "-intr"; break;  				 default: -			 		s = "-iso"; break; +					s = "-iso"; break;  				};  				s;  			})); @@ -2045,7 +2053,7 @@ int usb_alloc_streams(struct usb_interface *interface,  {  	struct usb_hcd *hcd;  	struct usb_device *dev; -	int i; +	int i, ret;  	dev = interface_to_usbdev(interface);  	hcd = bus_to_hcd(dev->bus); @@ -2054,13 +2062,24 @@ int usb_alloc_streams(struct usb_interface *interface,  	if (dev->speed != USB_SPEED_SUPER)  		return -EINVAL; -	/* Streams only apply to bulk endpoints. */ -	for (i = 0; i < num_eps; i++) +	for (i = 0; i < num_eps; i++) { +		/* Streams only apply to bulk endpoints. */  		if (!usb_endpoint_xfer_bulk(&eps[i]->desc))  			return -EINVAL; +		/* Re-alloc is not allowed */ +		if (eps[i]->streams) +			return -EINVAL; +	} -	return hcd->driver->alloc_streams(hcd, dev, eps, num_eps, +	ret = hcd->driver->alloc_streams(hcd, dev, eps, num_eps,  			num_streams, mem_flags); +	if (ret < 0) +		return ret; + +	for (i = 0; i < num_eps; i++) +		eps[i]->streams = ret; + +	return ret;  }  EXPORT_SYMBOL_GPL(usb_alloc_streams); @@ -2073,26 +2092,35 @@ EXPORT_SYMBOL_GPL(usb_alloc_streams);   *   * Reverts a group of bulk endpoints back to not using stream IDs.   * Can fail if we are given bad arguments, or HCD is broken. + * + * Return: 0 on success. On failure, a negative error code.   */ -void usb_free_streams(struct usb_interface *interface, +int usb_free_streams(struct usb_interface *interface,  		struct usb_host_endpoint **eps, unsigned int num_eps,  		gfp_t mem_flags)  {  	struct usb_hcd *hcd;  	struct usb_device *dev; -	int i; +	int i, ret;  	dev = interface_to_usbdev(interface);  	hcd = bus_to_hcd(dev->bus);  	if (dev->speed != USB_SPEED_SUPER) -		return; +		return -EINVAL; -	/* Streams only apply to bulk endpoints. */ +	/* Double-free is not allowed */  	for (i = 0; i < num_eps; i++) -		if (!eps[i] || !usb_endpoint_xfer_bulk(&eps[i]->desc)) -			return; +		if (!eps[i] || !eps[i]->streams) +			return -EINVAL; + +	ret = hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags); +	if (ret < 0) +		return ret; -	hcd->driver->free_streams(hcd, dev, eps, num_eps, mem_flags); +	for (i = 0; i < num_eps; i++) +		eps[i]->streams = 0; + +	return ret;  }  EXPORT_SYMBOL_GPL(usb_free_streams); @@ -2239,13 +2267,11 @@ static void hcd_resume_work(struct work_struct *work)  	struct usb_hcd *hcd = container_of(work, struct usb_hcd, wakeup_work);  	struct usb_device *udev = hcd->self.root_hub; -	usb_lock_device(udev);  	usb_remote_wakeup(udev); -	usb_unlock_device(udev);  }  /** - * usb_hcd_resume_root_hub - called by HCD to resume its root hub  + * usb_hcd_resume_root_hub - called by HCD to resume its root hub   * @hcd: host controller for this root hub   *   * The USB host controller calls this function when its root hub is @@ -2324,15 +2350,8 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);  irqreturn_t usb_hcd_irq (int irq, void *__hcd)  {  	struct usb_hcd		*hcd = __hcd; -	unsigned long		flags;  	irqreturn_t		rc; -	/* IRQF_DISABLED doesn't work correctly with shared IRQs -	 * when the first handler doesn't use it.  So let's just -	 * assume it's never used. -	 */ -	local_irq_save(flags); -  	if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))  		rc = IRQ_NONE;  	else if (hcd->driver->irq(hcd) == IRQ_NONE) @@ -2340,7 +2359,6 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)  	else  		rc = IRQ_HANDLED; -	local_irq_restore(flags);  	return rc;  }  EXPORT_SYMBOL_GPL(usb_hcd_irq); @@ -2438,11 +2456,13 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,  		mutex_init(hcd->bandwidth_mutex);  		dev_set_drvdata(dev, hcd);  	} else { +		mutex_lock(&usb_port_peer_mutex);  		hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;  		hcd->primary_hcd = primary_hcd;  		primary_hcd->primary_hcd = primary_hcd;  		hcd->shared_hcd = primary_hcd;  		primary_hcd->shared_hcd = hcd; +		mutex_unlock(&usb_port_peer_mutex);  	}  	kref_init(&hcd->kref); @@ -2494,18 +2514,25 @@ EXPORT_SYMBOL_GPL(usb_create_hcd);   * deallocated.   *   * Make sure to only deallocate the bandwidth_mutex when the primary HCD is - * freed.  When hcd_release() is called for the non-primary HCD, set the - * primary_hcd's shared_hcd pointer to null (since the non-primary HCD will be - * freed shortly). + * freed.  When hcd_release() is called for either hcd in a peer set + * invalidate the peer's ->shared_hcd and ->primary_hcd pointers to + * block new peering attempts   */ -static void hcd_release (struct kref *kref) +static void hcd_release(struct kref *kref)  {  	struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); +	mutex_lock(&usb_port_peer_mutex);  	if (usb_hcd_is_primary_hcd(hcd))  		kfree(hcd->bandwidth_mutex); -	else -		hcd->shared_hcd->shared_hcd = NULL; +	if (hcd->shared_hcd) { +		struct usb_hcd *peer = hcd->shared_hcd; + +		peer->shared_hcd = NULL; +		if (peer->primary_hcd == hcd) +			peer->primary_hcd = NULL; +	} +	mutex_unlock(&usb_port_peer_mutex);  	kfree(hcd);  } @@ -2547,13 +2574,6 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd,  	if (hcd->driver->irq) { -		/* IRQF_DISABLED doesn't work as advertised when used together -		 * with IRQF_SHARED. As usb_hcd_irq() will always disable -		 * interrupts we can remove it here. -		 */ -		if (irqflags & IRQF_SHARED) -			irqflags &= ~IRQF_DISABLED; -  		snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d",  				hcd->driver->description, hcd->self.busnum);  		retval = request_irq(irqnum, &usb_hcd_irq, irqflags, @@ -2580,6 +2600,21 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd,  	return 0;  } +/* + * Before we free this root hub, flush in-flight peering attempts + * and disable peer lookups + */ +static void usb_put_invalidate_rhdev(struct usb_hcd *hcd) +{ +	struct usb_device *rhdev; + +	mutex_lock(&usb_port_peer_mutex); +	rhdev = hcd->self.root_hub; +	hcd->self.root_hub = NULL; +	mutex_unlock(&usb_port_peer_mutex); +	usb_put_dev(rhdev); +} +  /**   * usb_add_hcd - finish generic HCD structure initialization and register   * @hcd: the usb_hcd structure to initialize @@ -2596,11 +2631,29 @@ int usb_add_hcd(struct usb_hcd *hcd,  	int retval;  	struct usb_device *rhdev; +	if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->phy) { +		struct usb_phy *phy = usb_get_phy_dev(hcd->self.controller, 0); + +		if (IS_ERR(phy)) { +			retval = PTR_ERR(phy); +			if (retval == -EPROBE_DEFER) +				return retval; +		} else { +			retval = usb_phy_init(phy); +			if (retval) { +				usb_put_phy(phy); +				return retval; +			} +			hcd->phy = phy; +			hcd->remove_phy = 1; +		} +	} +  	dev_info(hcd->self.controller, "%s\n", hcd->product_desc);  	/* Keep old behaviour if authorized_default is not in [0, 1]. */  	if (authorized_default < 0 || authorized_default > 1) -		hcd->authorized_default = hcd->wireless? 0 : 1; +		hcd->authorized_default = hcd->wireless ? 0 : 1;  	else  		hcd->authorized_default = authorized_default;  	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); @@ -2611,7 +2664,7 @@ int usb_add_hcd(struct usb_hcd *hcd,  	 */  	if ((retval = hcd_buffer_create(hcd)) != 0) {  		dev_dbg(hcd->self.controller, "pool alloc failed\n"); -		return retval; +		goto err_remove_phy;  	}  	if ((retval = usb_register_bus(&hcd->self)) < 0) @@ -2622,7 +2675,9 @@ int usb_add_hcd(struct usb_hcd *hcd,  		retval = -ENOMEM;  		goto err_allocate_root_hub;  	} +	mutex_lock(&usb_port_peer_mutex);  	hcd->self.root_hub = rhdev; +	mutex_unlock(&usb_port_peer_mutex);  	switch (hcd->speed) {  	case HCD_USB11: @@ -2701,12 +2756,6 @@ int usb_add_hcd(struct usb_hcd *hcd,  	if (hcd->uses_new_polling && HCD_POLL_RH(hcd))  		usb_hcd_poll_rh_status(hcd); -	/* -	 * Host controllers don't generate their own wakeup requests; -	 * they only forward requests from the root hub.  Therefore -	 * controllers should always be enabled for remote wakeup. -	 */ -	device_wakeup_enable(hcd->self.controller);  	return retval;  error_create_attr_group: @@ -2737,13 +2786,19 @@ err_hcd_driver_start:  err_request_irq:  err_hcd_driver_setup:  err_set_rh_speed: -	usb_put_dev(hcd->self.root_hub); +	usb_put_invalidate_rhdev(hcd);  err_allocate_root_hub:  	usb_deregister_bus(&hcd->self);  err_register_bus:  	hcd_buffer_destroy(hcd); +err_remove_phy: +	if (hcd->remove_phy && hcd->phy) { +		usb_phy_shutdown(hcd->phy); +		usb_put_phy(hcd->phy); +		hcd->phy = NULL; +	}  	return retval; -}  +}  EXPORT_SYMBOL_GPL(usb_add_hcd);  /** @@ -2811,14 +2866,20 @@ void usb_remove_hcd(struct usb_hcd *hcd)  			free_irq(hcd->irq, hcd);  	} -	usb_put_dev(hcd->self.root_hub);  	usb_deregister_bus(&hcd->self);  	hcd_buffer_destroy(hcd); +	if (hcd->remove_phy && hcd->phy) { +		usb_phy_shutdown(hcd->phy); +		usb_put_phy(hcd->phy); +		hcd->phy = NULL; +	} + +	usb_put_invalidate_rhdev(hcd);  }  EXPORT_SYMBOL_GPL(usb_remove_hcd);  void -usb_hcd_platform_shutdown(struct platform_device* dev) +usb_hcd_platform_shutdown(struct platform_device *dev)  {  	struct usb_hcd *hcd = platform_get_drvdata(dev); @@ -2840,7 +2901,7 @@ struct usb_mon_operations *mon_ops;   * Notice that the code is minimally error-proof. Because usbmon needs   * symbols from usbcore, usbcore gets referenced and cannot be unloaded first.   */ -  +  int usb_mon_register (struct usb_mon_operations *ops)  { diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index dde4c83516a..0e950ad8cb2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -33,21 +33,9 @@  #include "hub.h" -/* if we are in debug mode, always announce new devices */ -#ifdef DEBUG -#ifndef CONFIG_USB_ANNOUNCE_NEW_DEVICES -#define CONFIG_USB_ANNOUNCE_NEW_DEVICES -#endif -#endif -  #define USB_VENDOR_GENESYS_LOGIC		0x05e3  #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND	0x01 -static inline int hub_is_superspeed(struct usb_device *hdev) -{ -	return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS); -} -  /* Protect struct usb_device->state and ->children members   * Note: Both are also protected by ->dev.sem, except that ->state can   * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ @@ -62,6 +50,9 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);  static struct task_struct *khubd_task; +/* synchronize hub-port add/remove and peering operations */ +DEFINE_MUTEX(usb_port_peer_mutex); +  /* cycle leds on hubs that aren't blinking for attention */  static bool blinkenlights = 0;  module_param (blinkenlights, bool, S_IRUGO); @@ -120,7 +111,7 @@ static inline char *portspeed(struct usb_hub *hub, int portstatus)  	if (hub_is_superspeed(hub->hdev))  		return "5.0 Gb/s";  	if (portstatus & USB_PORT_STAT_HIGH_SPEED) -    		return "480 Mb/s"; +		return "480 Mb/s";  	else if (portstatus & USB_PORT_STAT_LOW_SPEED)  		return "1.5 Mb/s";  	else @@ -148,19 +139,27 @@ static int usb_device_supports_lpm(struct usb_device *udev)  		return 0;  	} -	/* All USB 3.0 must support LPM, but we need their max exit latency -	 * information from the SuperSpeed Extended Capabilities BOS descriptor. +	/* +	 * According to the USB 3.0 spec, all USB 3.0 devices must support LPM. +	 * However, there are some that don't, and they set the U1/U2 exit +	 * latencies to zero.  	 */  	if (!udev->bos->ss_cap) { -		dev_warn(&udev->dev, "No LPM exit latency info found.  " -				"Power management will be impacted.\n"); +		dev_info(&udev->dev, "No LPM exit latency info found, disabling LPM.\n");  		return 0;  	} -	if (udev->parent->lpm_capable) -		return 1; -	dev_warn(&udev->dev, "Parent hub missing LPM exit latency info.  " -			"Power management will be impacted.\n"); +	if (udev->bos->ss_cap->bU1devExitLat == 0 && +			udev->bos->ss_cap->bU2DevExitLat == 0) { +		if (udev->parent) +			dev_info(&udev->dev, "LPM exit latency is zeroed, disabling LPM.\n"); +		else +			dev_info(&udev->dev, "We don't know the algorithms for LPM for this host, disabling LPM.\n"); +		return 0; +	} + +	if (!udev->parent || udev->parent->lpm_capable) +		return 1;  	return 0;  } @@ -310,9 +309,9 @@ static void usb_set_lpm_parameters(struct usb_device *udev)  		return;  	udev_u1_del = udev->bos->ss_cap->bU1devExitLat; -	udev_u2_del = udev->bos->ss_cap->bU2DevExitLat; +	udev_u2_del = le16_to_cpu(udev->bos->ss_cap->bU2DevExitLat);  	hub_u1_del = udev->parent->bos->ss_cap->bU1devExitLat; -	hub_u2_del = udev->parent->bos->ss_cap->bU2DevExitLat; +	hub_u2_del = le16_to_cpu(udev->parent->bos->ss_cap->bU2DevExitLat);  	usb_set_lpm_mel(udev, &udev->u1_params, udev_u1_del,  			hub, &udev->parent->u1_params, hub_u1_del); @@ -411,30 +410,35 @@ static int set_port_feature(struct usb_device *hdev, int port1, int feature)  		NULL, 0, 1000);  } +static char *to_led_name(int selector) +{ +	switch (selector) { +	case HUB_LED_AMBER: +		return "amber"; +	case HUB_LED_GREEN: +		return "green"; +	case HUB_LED_OFF: +		return "off"; +	case HUB_LED_AUTO: +		return "auto"; +	default: +		return "??"; +	} +} +  /*   * USB 2.0 spec Section 11.24.2.7.1.10 and table 11-7   * for info about using port indicators   */ -static void set_port_led( -	struct usb_hub *hub, -	int port1, -	int selector -) +static void set_port_led(struct usb_hub *hub, int port1, int selector)  { -	int status = set_port_feature(hub->hdev, (selector << 8) | port1, +	struct usb_port *port_dev = hub->ports[port1 - 1]; +	int status; + +	status = set_port_feature(hub->hdev, (selector << 8) | port1,  			USB_PORT_FEAT_INDICATOR); -	if (status < 0) -		dev_dbg (hub->intfdev, -			"port %d indicator %s status %d\n", -			port1, -			({ char *s; switch (selector) { -			case HUB_LED_AMBER: s = "amber"; break; -			case HUB_LED_GREEN: s = "green"; break; -			case HUB_LED_OFF: s = "off"; break; -			case HUB_LED_AUTO: s = "auto"; break; -			default: s = "??"; break; -			}; s; }), -			status); +	dev_dbg(&port_dev->dev, "indicator %s status %d\n", +		to_led_name(selector), status);  }  #define	LED_CYCLE_PERIOD	((2*HZ)/3) @@ -506,7 +510,8 @@ static void led_work (struct work_struct *work)  		changed++;  	}  	if (changed) -		schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); +		queue_delayed_work(system_power_efficient_wq, +				&hub->leds, LED_CYCLE_PERIOD);  }  /* use a short timeout for hub/port status fetches */ @@ -741,16 +746,20 @@ int usb_hub_set_port_power(struct usb_device *hdev, struct usb_hub *hub,  			   int port1, bool set)  {  	int ret; -	struct usb_port *port_dev = hub->ports[port1 - 1];  	if (set)  		ret = set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);  	else  		ret = usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_POWER); -	if (!ret) -		port_dev->power_is_on = set; -	return ret; +	if (ret) +		return ret; + +	if (set) +		set_bit(port1, hub->power_bits); +	else +		clear_bit(port1, hub->power_bits); +	return 0;  }  /** @@ -808,16 +817,9 @@ int usb_hub_clear_tt_buffer(struct urb *urb)  }  EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer); -/* If do_delay is false, return the number of milliseconds the caller - * needs to delay. - */ -static unsigned hub_power_on(struct usb_hub *hub, bool do_delay) +static void hub_power_on(struct usb_hub *hub, bool do_delay)  {  	int port1; -	unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2; -	unsigned delay; -	u16 wHubCharacteristics = -			le16_to_cpu(hub->descriptor->wHubCharacteristics);  	/* Enable power on each port.  Some hubs have reserved values  	 * of LPSM (> 2) in their descriptors, even though they are @@ -825,23 +827,19 @@ static unsigned hub_power_on(struct usb_hub *hub, bool do_delay)  	 * but only emulate it.  In all cases, the ports won't work  	 * unless we send these messages to the hub.  	 */ -	if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) +	if (hub_is_port_power_switchable(hub))  		dev_dbg(hub->intfdev, "enabling power on all ports\n");  	else  		dev_dbg(hub->intfdev, "trying to enable port power on "  				"non-switchable hub\n");  	for (port1 = 1; port1 <= hub->hdev->maxchild; port1++) -		if (hub->ports[port1 - 1]->power_is_on) +		if (test_bit(port1, hub->power_bits))  			set_port_feature(hub->hdev, port1, USB_PORT_FEAT_POWER);  		else  			usb_clear_port_feature(hub->hdev, port1,  						USB_PORT_FEAT_POWER); - -	/* Wait at least 100 msec for power to become stable */ -	delay = max(pgood_delay, (unsigned) 100);  	if (do_delay) -		msleep(delay); -	return delay; +		msleep(hub_power_on_good_delay(hub));  }  static int hub_hub_status(struct usb_hub *hub, @@ -857,7 +855,7 @@ static int hub_hub_status(struct usb_hub *hub,  				"%s failed (err = %d)\n", __func__, ret);  	} else {  		*status = le16_to_cpu(hub->status->hub.wHubStatus); -		*change = le16_to_cpu(hub->status->hub.wHubChange);  +		*change = le16_to_cpu(hub->status->hub.wHubChange);  		ret = 0;  	}  	mutex_unlock(&hub->status_mutex); @@ -891,6 +889,25 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1)  	if (!hub_is_superspeed(hub->hdev))  		return -EINVAL; +	ret = hub_port_status(hub, port1, &portstatus, &portchange); +	if (ret < 0) +		return ret; + +	/* +	 * USB controller Advanced Micro Devices, Inc. [AMD] FCH USB XHCI +	 * Controller [1022:7814] will have spurious result making the following +	 * usb 3.0 device hotplugging route to the 2.0 root hub and recognized +	 * as high-speed device if we set the usb 3.0 port link state to +	 * Disabled. Since it's already in USB_SS_PORT_LS_RX_DETECT state, we +	 * check the state here to avoid the bug. +	 */ +	if ((portstatus & USB_PORT_STAT_LINK_STATE) == +				USB_SS_PORT_LS_RX_DETECT) { +		dev_dbg(&hub->ports[port1 - 1]->dev, +			 "Not disabling port; link state is RxDetect\n"); +		return ret; +	} +  	ret = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_SS_DISABLED);  	if (ret)  		return ret; @@ -909,20 +926,20 @@ static int hub_usb3_port_disable(struct usb_hub *hub, int port1)  		msleep(HUB_DEBOUNCE_STEP);  	}  	if (total_time >= HUB_DEBOUNCE_TIMEOUT) -		dev_warn(hub->intfdev, "Could not disable port %d after %d ms\n", -				port1, total_time); +		dev_warn(&hub->ports[port1 - 1]->dev, +				"Could not disable after %d ms\n", total_time);  	return hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_RX_DETECT);  }  static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)  { +	struct usb_port *port_dev = hub->ports[port1 - 1];  	struct usb_device *hdev = hub->hdev;  	int ret = 0; -	if (hub->ports[port1 - 1]->child && set_state) -		usb_set_device_state(hub->ports[port1 - 1]->child, -				USB_STATE_NOTATTACHED); +	if (port_dev->child && set_state) +		usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED);  	if (!hub->error) {  		if (hub_is_superspeed(hub->hdev))  			ret = hub_usb3_port_disable(hub, port1); @@ -931,8 +948,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)  					USB_PORT_FEAT_ENABLE);  	}  	if (ret && ret != -ENODEV) -		dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n", -				port1, ret); +		dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret);  	return ret;  } @@ -943,7 +959,7 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)   */  static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)  { -	dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1); +	dev_dbg(&hub->ports[port1 - 1]->dev, "logical disconnect\n");  	hub_port_disable(hub, port1, 1);  	/* FIXME let caller ask to power down the port: @@ -956,7 +972,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)  	 */  	set_bit(port1, hub->change_bits); - 	kick_khubd(hub); +	kick_khubd(hub);  }  /** @@ -1046,9 +1062,12 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  		 * for HUB_POST_RESET, but it's easier not to.  		 */  		if (type == HUB_INIT) { -			delay = hub_power_on(hub, false); -			PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func2); -			schedule_delayed_work(&hub->init_work, +			unsigned delay = hub_power_on_good_delay(hub); + +			hub_power_on(hub, false); +			INIT_DELAYED_WORK(&hub->init_work, hub_init_func2); +			queue_delayed_work(system_power_efficient_wq, +					&hub->init_work,  					msecs_to_jiffies(delay));  			/* Suppress autosuspend until init is done */ @@ -1080,21 +1099,23 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  	}   init2: -	/* Check each port and set hub->change_bits to let khubd know +	/* +	 * Check each port and set hub->change_bits to let khubd know  	 * which ports need attention.  	 */  	for (port1 = 1; port1 <= hdev->maxchild; ++port1) { -		struct usb_device *udev = hub->ports[port1 - 1]->child; +		struct usb_port *port_dev = hub->ports[port1 - 1]; +		struct usb_device *udev = port_dev->child;  		u16 portstatus, portchange;  		portstatus = portchange = 0;  		status = hub_port_status(hub, port1, &portstatus, &portchange);  		if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) -			dev_dbg(hub->intfdev, -					"port %d: status %04x change %04x\n", -					port1, portstatus, portchange); +			dev_dbg(&port_dev->dev, "status %04x change %04x\n", +					portstatus, portchange); -		/* After anything other than HUB_RESUME (i.e., initialization +		/* +		 * After anything other than HUB_RESUME (i.e., initialization  		 * or any sort of reset), every port should be disabled.  		 * Unconnected ports should likewise be disabled (paranoia),  		 * and so should ports for which we have no usb_device. @@ -1107,16 +1128,13 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  			/*  			 * USB3 protocol ports will automatically transition  			 * to Enabled state when detect an USB3.0 device attach. -			 * Do not disable USB3 protocol ports. +			 * Do not disable USB3 protocol ports, just pretend +			 * power was lost  			 */ -			if (!hub_is_superspeed(hdev)) { +			portstatus &= ~USB_PORT_STAT_ENABLE; +			if (!hub_is_superspeed(hdev))  				usb_clear_port_feature(hdev, port1,  						   USB_PORT_FEAT_ENABLE); -				portstatus &= ~USB_PORT_STAT_ENABLE; -			} else { -				/* Pretend that power was lost for USB3 devs */ -				portstatus &= ~USB_PORT_STAT_ENABLE; -			}  		}  		/* Clear status-change flags; we'll debounce later */ @@ -1130,6 +1148,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  			usb_clear_port_feature(hub->hdev, port1,  					USB_PORT_FEAT_C_ENABLE);  		} +		if (portchange & USB_PORT_STAT_C_RESET) { +			need_debounce_delay = true; +			usb_clear_port_feature(hub->hdev, port1, +					USB_PORT_FEAT_C_RESET); +		}  		if ((portchange & USB_PORT_STAT_C_BH_RESET) &&  				hub_is_superspeed(hub->hdev)) {  			need_debounce_delay = true; @@ -1147,7 +1170,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  			/* Tell khubd to disconnect the device or  			 * check for a new connection  			 */ -			if (udev || (portstatus & USB_PORT_STAT_CONNECTION)) +			if (udev || (portstatus & USB_PORT_STAT_CONNECTION) || +			    (portstatus & USB_PORT_STAT_OVERCURRENT))  				set_bit(port1, hub->change_bits);  		} else if (portstatus & USB_PORT_STAT_ENABLE) { @@ -1167,15 +1191,13 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  				set_bit(port1, hub->change_bits);  		} else if (udev->persist_enabled) { -			struct usb_port *port_dev = hub->ports[port1 - 1]; -  #ifdef CONFIG_PM  			udev->reset_resume = 1;  #endif  			/* Don't set the change_bits when the device  			 * was powered off.  			 */ -			if (port_dev->power_is_on) +			if (test_bit(port1, hub->power_bits))  				set_bit(port1, hub->change_bits);  		} else { @@ -1198,8 +1220,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  		/* Don't do a long sleep inside a workqueue routine */  		if (type == HUB_INIT2) { -			PREPARE_DELAYED_WORK(&hub->init_work, hub_init_func3); -			schedule_delayed_work(&hub->init_work, +			INIT_DELAYED_WORK(&hub->init_work, hub_init_func3); +			queue_delayed_work(system_power_efficient_wq, +					&hub->init_work,  					msecs_to_jiffies(delay));  			return;		/* Continues at init3: below */  		} else { @@ -1213,7 +1236,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)  	if (status < 0)  		dev_err(hub->intfdev, "activate --> %d\n", status);  	if (hub->has_indicators && blinkenlights) -		schedule_delayed_work(&hub->leds, LED_CYCLE_PERIOD); +		queue_delayed_work(system_power_efficient_wq, +				&hub->leds, LED_CYCLE_PERIOD);  	/* Scan all ports that need attention */  	kick_khubd(hub); @@ -1268,12 +1292,22 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)  		flush_work(&hub->tt.clear_work);  } +static void hub_pm_barrier_for_all_ports(struct usb_hub *hub) +{ +	int i; + +	for (i = 0; i < hub->hdev->maxchild; ++i) +		pm_runtime_barrier(&hub->ports[i]->dev); +} +  /* caller has locked the hub device */  static int hub_pre_reset(struct usb_interface *intf)  {  	struct usb_hub *hub = usb_get_intfdata(intf);  	hub_quiesce(hub, HUB_PRE_RESET); +	hub->in_reset = 1; +	hub_pm_barrier_for_all_ports(hub);  	return 0;  } @@ -1282,6 +1316,8 @@ static int hub_post_reset(struct usb_interface *intf)  {  	struct usb_hub *hub = usb_get_intfdata(intf); +	hub->in_reset = 0; +	hub_pm_barrier_for_all_ports(hub);  	hub_activate(hub, HUB_POST_RESET);  	return 0;  } @@ -1299,6 +1335,7 @@ static int hub_configure(struct usb_hub *hub,  	char *message = "out of memory";  	unsigned unit_load;  	unsigned full_load; +	unsigned maxchild;  	hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);  	if (!hub->buffer) { @@ -1337,12 +1374,11 @@ static int hub_configure(struct usb_hub *hub,  		goto fail;  	} -	hdev->maxchild = hub->descriptor->bNbrPorts; -	dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, -		(hdev->maxchild == 1) ? "" : "s"); +	maxchild = hub->descriptor->bNbrPorts; +	dev_info(hub_dev, "%d port%s detected\n", maxchild, +			(maxchild == 1) ? "" : "s"); -	hub->ports = kzalloc(hdev->maxchild * sizeof(struct usb_port *), -			     GFP_KERNEL); +	hub->ports = kzalloc(maxchild * sizeof(struct usb_port *), GFP_KERNEL);  	if (!hub->ports) {  		ret = -ENOMEM;  		goto fail; @@ -1361,13 +1397,13 @@ static int hub_configure(struct usb_hub *hub,  	if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&  			!(hub_is_superspeed(hdev))) {  		int	i; -		char	portstr [USB_MAXCHILDREN + 1]; +		char	portstr[USB_MAXCHILDREN + 1]; -		for (i = 0; i < hdev->maxchild; i++) +		for (i = 0; i < maxchild; i++)  			portstr[i] = hub->descriptor->u.hs.DeviceRemovable  				    [((i + 1) / 8)] & (1 << ((i + 1) % 8))  				? 'F' : 'R'; -		portstr[hdev->maxchild] = 0; +		portstr[maxchild] = 0;  		dev_dbg(hub_dev, "compound device; port removable status: %s\n", portstr);  	} else  		dev_dbg(hub_dev, "standalone hub\n"); @@ -1429,32 +1465,32 @@ static int hub_configure(struct usb_hub *hub,  	/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */  	switch (wHubCharacteristics & HUB_CHAR_TTTT) { -		case HUB_TTTT_8_BITS: -			if (hdev->descriptor.bDeviceProtocol != 0) { -				hub->tt.think_time = 666; -				dev_dbg(hub_dev, "TT requires at most %d " -						"FS bit times (%d ns)\n", -					8, hub->tt.think_time); -			} -			break; -		case HUB_TTTT_16_BITS: -			hub->tt.think_time = 666 * 2; -			dev_dbg(hub_dev, "TT requires at most %d " -					"FS bit times (%d ns)\n", -				16, hub->tt.think_time); -			break; -		case HUB_TTTT_24_BITS: -			hub->tt.think_time = 666 * 3; -			dev_dbg(hub_dev, "TT requires at most %d " -					"FS bit times (%d ns)\n", -				24, hub->tt.think_time); -			break; -		case HUB_TTTT_32_BITS: -			hub->tt.think_time = 666 * 4; +	case HUB_TTTT_8_BITS: +		if (hdev->descriptor.bDeviceProtocol != 0) { +			hub->tt.think_time = 666;  			dev_dbg(hub_dev, "TT requires at most %d "  					"FS bit times (%d ns)\n", -				32, hub->tt.think_time); -			break; +				8, hub->tt.think_time); +		} +		break; +	case HUB_TTTT_16_BITS: +		hub->tt.think_time = 666 * 2; +		dev_dbg(hub_dev, "TT requires at most %d " +				"FS bit times (%d ns)\n", +			16, hub->tt.think_time); +		break; +	case HUB_TTTT_24_BITS: +		hub->tt.think_time = 666 * 3; +		dev_dbg(hub_dev, "TT requires at most %d " +				"FS bit times (%d ns)\n", +			24, hub->tt.think_time); +		break; +	case HUB_TTTT_32_BITS: +		hub->tt.think_time = 666 * 4; +		dev_dbg(hub_dev, "TT requires at most %d " +				"FS bit times (%d ns)\n", +			32, hub->tt.think_time); +		break;  	}  	/* probe() zeroes hub->indicator[] */ @@ -1479,7 +1515,7 @@ static int hub_configure(struct usb_hub *hub,  		if (hcd->power_budget > 0)  			hdev->bus_mA = hcd->power_budget;  		else -			hdev->bus_mA = full_load * hdev->maxchild; +			hdev->bus_mA = full_load * maxchild;  		if (hdev->bus_mA >= full_load)  			hub->mA_per_port = full_load;  		else { @@ -1494,7 +1530,7 @@ static int hub_configure(struct usb_hub *hub,  			hub->descriptor->bHubContrCurrent);  		hub->limited_power = 1; -		if (remaining < hdev->maxchild * unit_load) +		if (remaining < maxchild * unit_load)  			dev_warn(hub_dev,  					"insufficient power available "  					"to use all downstream ports\n"); @@ -1509,18 +1545,6 @@ static int hub_configure(struct usb_hub *hub,  		dev_dbg(hub_dev, "%umA bus power budget for each child\n",  				hub->mA_per_port); -	/* Update the HCD's internal representation of this hub before khubd -	 * starts getting port status changes for devices under the hub. -	 */ -	if (hcd->driver->update_hub_device) { -		ret = hcd->driver->update_hub_device(hcd, hdev, -				&hub->tt, GFP_KERNEL); -		if (ret < 0) { -			message = "can't update HCD hub info"; -			goto fail; -		} -	} -  	ret = hub_hub_status(hub, &hubstatus, &hubchange);  	if (ret < 0) {  		message = "can't get hub status"; @@ -1560,15 +1584,37 @@ static int hub_configure(struct usb_hub *hub,  	/* maybe cycle the hub leds */  	if (hub->has_indicators && blinkenlights) -		hub->indicator [0] = INDICATOR_CYCLE; +		hub->indicator[0] = INDICATOR_CYCLE; -	for (i = 0; i < hdev->maxchild; i++) { +	mutex_lock(&usb_port_peer_mutex); +	for (i = 0; i < maxchild; i++) {  		ret = usb_hub_create_port_device(hub, i + 1);  		if (ret < 0) {  			dev_err(hub->intfdev,  				"couldn't create port%d device.\n", i + 1); -			hdev->maxchild = i; -			goto fail_keep_maxchild; +			break; +		} +	} +	hdev->maxchild = i; +	for (i = 0; i < hdev->maxchild; i++) { +		struct usb_port *port_dev = hub->ports[i]; + +		pm_runtime_put(&port_dev->dev); +	} + +	mutex_unlock(&usb_port_peer_mutex); +	if (ret < 0) +		goto fail; + +	/* Update the HCD's internal representation of this hub before khubd +	 * starts getting port status changes for devices under the hub. +	 */ +	if (hcd->driver->update_hub_device) { +		ret = hcd->driver->update_hub_device(hcd, hdev, +				&hub->tt, GFP_KERNEL); +		if (ret < 0) { +			message = "can't update HCD hub info"; +			goto fail;  		}  	} @@ -1578,8 +1624,6 @@ static int hub_configure(struct usb_hub *hub,  	return 0;  fail: -	hdev->maxchild = 0; -fail_keep_maxchild:  	dev_err (hub_dev, "config failed, %s (err %d)\n",  			message, ret);  	/* hub_disconnect() frees urb and descriptor */ @@ -1600,7 +1644,7 @@ static void hub_disconnect(struct usb_interface *intf)  {  	struct usb_hub *hub = usb_get_intfdata(intf);  	struct usb_device *hdev = interface_to_usbdev(intf); -	int i; +	int port1;  	/* Take the hub off the event list and don't let it be added again */  	spin_lock_irq(&hub_event_lock); @@ -1615,11 +1659,19 @@ static void hub_disconnect(struct usb_interface *intf)  	hub->error = 0;  	hub_quiesce(hub, HUB_DISCONNECT); -	usb_set_intfdata (intf, NULL); +	mutex_lock(&usb_port_peer_mutex); -	for (i = 0; i < hdev->maxchild; i++) -		usb_hub_remove_port_device(hub, i + 1); -	hub->hdev->maxchild = 0; +	/* Avoid races with recursively_mark_NOTATTACHED() */ +	spin_lock_irq(&device_state_lock); +	port1 = hdev->maxchild; +	hdev->maxchild = 0; +	usb_set_intfdata(intf, NULL); +	spin_unlock_irq(&device_state_lock); + +	for (; port1 > 0; --port1) +		usb_hub_remove_port_device(hub, port1); + +	mutex_unlock(&usb_port_peer_mutex);  	if (hub->hdev->speed == USB_SPEED_HIGH)  		highspeed_hubs--; @@ -1679,8 +1731,19 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)  	 */  	pm_runtime_set_autosuspend_delay(&hdev->dev, 0); -	/* Hubs have proper suspend/resume support. */ -	usb_enable_autosuspend(hdev); +	/* +	 * Hubs have proper suspend/resume support, except for root hubs +	 * where the controller driver doesn't have bus_suspend and +	 * bus_resume methods. +	 */ +	if (hdev->parent) {		/* normal device */ +		usb_enable_autosuspend(hdev); +	} else {			/* root hub */ +		const struct hc_driver *drv = bus_to_hcd(hdev->bus)->driver; + +		if (drv->bus_suspend && drv->bus_resume) +			usb_enable_autosuspend(hdev); +	}  	if (hdev->level == MAX_TOPO_LEVEL) {  		dev_err(&intf->dev, @@ -1788,7 +1851,7 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)   * to one of these "claimed" ports, the program will "own" the device.   */  static int find_port_owner(struct usb_device *hdev, unsigned port1, -		struct dev_state ***ppowner) +		struct usb_dev_state ***ppowner)  {  	struct usb_hub *hub = usb_hub_to_struct_hub(hdev); @@ -1806,10 +1869,10 @@ static int find_port_owner(struct usb_device *hdev, unsigned port1,  /* In the following three functions, the caller must hold hdev's lock */  int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, -		       struct dev_state *owner) +		       struct usb_dev_state *owner)  {  	int rc; -	struct dev_state **powner; +	struct usb_dev_state **powner;  	rc = find_port_owner(hdev, port1, &powner);  	if (rc) @@ -1819,12 +1882,13 @@ int usb_hub_claim_port(struct usb_device *hdev, unsigned port1,  	*powner = owner;  	return rc;  } +EXPORT_SYMBOL_GPL(usb_hub_claim_port);  int usb_hub_release_port(struct usb_device *hdev, unsigned port1, -			 struct dev_state *owner) +			 struct usb_dev_state *owner)  {  	int rc; -	struct dev_state **powner; +	struct usb_dev_state **powner;  	rc = find_port_owner(hdev, port1, &powner);  	if (rc) @@ -1834,8 +1898,9 @@ int usb_hub_release_port(struct usb_device *hdev, unsigned port1,  	*powner = NULL;  	return rc;  } +EXPORT_SYMBOL_GPL(usb_hub_release_port); -void usb_hub_release_all_ports(struct usb_device *hdev, struct dev_state *owner) +void usb_hub_release_all_ports(struct usb_device *hdev, struct usb_dev_state *owner)  {  	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);  	int n; @@ -1978,7 +2043,7 @@ static void choose_devnum(struct usb_device *udev)  		if (devnum >= 128)  			devnum = find_next_zero_bit(bus->devmap.devicemap,  						    128, 1); -		bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1); +		bus->devnum_next = (devnum >= 127 ? 1 : devnum + 1);  	}  	if (devnum < 128) {  		set_bit(devnum, bus->devmap.devicemap); @@ -2010,6 +2075,18 @@ static void hub_free_dev(struct usb_device *udev)  		hcd->driver->free_dev(hcd, udev);  } +static void hub_disconnect_children(struct usb_device *udev) +{ +	struct usb_hub *hub = usb_hub_to_struct_hub(udev); +	int i; + +	/* Free up all the children before we remove this device */ +	for (i = 0; i < udev->maxchild; i++) { +		if (hub->ports[i]->child) +			usb_disconnect(&hub->ports[i]->child); +	} +} +  /**   * usb_disconnect - disconnect a device (usbcore-internal)   * @pdev: pointer to device being disconnected @@ -2018,8 +2095,8 @@ static void hub_free_dev(struct usb_device *udev)   * Something got disconnected. Get rid of it and all of its children.   *   * If *pdev is a normal device then the parent hub must already be locked. - * If *pdev is a root hub then this routine will acquire the - * usb_bus_list_lock on behalf of the caller. + * If *pdev is a root hub then the caller must hold the usb_bus_list_lock, + * which protects the set of root hubs as well as the list of buses.   *   * Only hub drivers (including virtual root hub drivers for host   * controllers) should ever call this. @@ -2028,9 +2105,10 @@ static void hub_free_dev(struct usb_device *udev)   */  void usb_disconnect(struct usb_device **pdev)  { -	struct usb_device	*udev = *pdev; -	struct usb_hub		*hub = usb_hub_to_struct_hub(udev); -	int			i; +	struct usb_port *port_dev = NULL; +	struct usb_device *udev = *pdev; +	struct usb_hub *hub; +	int port1;  	/* mark the device as inactive, so any further urb submissions for  	 * this device (and any of its children) will fail immediately. @@ -2042,11 +2120,7 @@ void usb_disconnect(struct usb_device **pdev)  	usb_lock_device(udev); -	/* Free up all the children before we remove this device */ -	for (i = 0; i < udev->maxchild; i++) { -		if (hub->ports[i]->child) -			usb_disconnect(&hub->ports[i]->child); -	} +	hub_disconnect_children(udev);  	/* deallocate hcd/hardware state ... nuking all pending urbs and  	 * cleaning up all state associated with the current configuration @@ -2057,16 +2131,19 @@ void usb_disconnect(struct usb_device **pdev)  	usb_hcd_synchronize_unlinks(udev);  	if (udev->parent) { -		struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); -		struct usb_port	*port_dev = hub->ports[udev->portnum - 1]; +		port1 = udev->portnum; +		hub = usb_hub_to_struct_hub(udev->parent); +		port_dev = hub->ports[port1 - 1];  		sysfs_remove_link(&udev->dev.kobj, "port");  		sysfs_remove_link(&port_dev->dev.kobj, "device"); -		if (!port_dev->did_runtime_put) -			pm_runtime_put(&port_dev->dev); -		else -			port_dev->did_runtime_put = false; +		/* +		 * As usb_port_runtime_resume() de-references udev, make +		 * sure no resumes occur during removal +		 */ +		if (!test_and_set_bit(port1, hub->child_usage_bits)) +			pm_runtime_get_sync(&port_dev->dev);  	}  	usb_remove_ep_devs(&udev->ep0); @@ -2088,6 +2165,9 @@ void usb_disconnect(struct usb_device **pdev)  	*pdev = NULL;  	spin_unlock_irq(&device_state_lock); +	if (port_dev && test_and_clear_bit(port1, hub->child_usage_bits)) +		pm_runtime_put(&port_dev->dev); +  	hub_free_dev(udev);  	put_device(&udev->dev); @@ -2228,18 +2308,13 @@ static int usb_enumerate_device(struct usb_device *udev)  			return err;  		}  	} -	if (udev->wusb == 1 && udev->authorized == 0) { -		udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); -		udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); -		udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); -	} -	else { -		/* read the standard strings and cache them if present */ -		udev->product = usb_cache_string(udev, udev->descriptor.iProduct); -		udev->manufacturer = usb_cache_string(udev, -						      udev->descriptor.iManufacturer); -		udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); -	} + +	/* read the standard strings and cache them if present */ +	udev->product = usb_cache_string(udev, udev->descriptor.iProduct); +	udev->manufacturer = usb_cache_string(udev, +					      udev->descriptor.iManufacturer); +	udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber); +  	err = usb_enumerate_device_otg(udev);  	if (err < 0)  		return err; @@ -2280,6 +2355,22 @@ static void set_usb_port_removable(struct usb_device *udev)  		udev->removable = USB_DEVICE_REMOVABLE;  	else  		udev->removable = USB_DEVICE_FIXED; + +	/* +	 * Platform firmware may have populated an alternative value for +	 * removable.  If the parent port has a known connect_type use +	 * that instead. +	 */ +	switch (hub->ports[udev->portnum - 1]->connect_type) { +	case USB_PORT_CONNECT_TYPE_HOT_PLUG: +		udev->removable = USB_DEVICE_REMOVABLE; +		break; +	case USB_PORT_CONNECT_TYPE_HARD_WIRED: +		udev->removable = USB_DEVICE_FIXED; +		break; +	default: /* use what was set above */ +		break; +	}  }  /** @@ -2349,11 +2440,7 @@ int usb_new_device(struct usb_device *udev)  	device_enable_async_suspend(&udev->dev); -	/* -	 * check whether the hub marks this port as non-removable. Do it -	 * now so that platform-specific data can override it in -	 * device_add() -	 */ +	/* check whether the hub or firmware marks this port as non-removable */  	if (udev->parent)  		set_usb_port_removable(udev); @@ -2370,7 +2457,8 @@ int usb_new_device(struct usb_device *udev)  	/* Create link files between child device and usb port device. */  	if (udev->parent) {  		struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); -		struct usb_port	*port_dev = hub->ports[udev->portnum - 1]; +		int port1 = udev->portnum; +		struct usb_port	*port_dev = hub->ports[port1 - 1];  		err = sysfs_create_link(&udev->dev.kobj,  				&port_dev->dev.kobj, "port"); @@ -2384,7 +2472,8 @@ int usb_new_device(struct usb_device *udev)  			goto fail;  		} -		pm_runtime_get_sync(&port_dev->dev); +		if (!test_and_set_bit(port1, hub->child_usage_bits)) +			pm_runtime_get_sync(&port_dev->dev);  	}  	(void) usb_create_ep_devs(&udev->dev, &udev->ep0, udev); @@ -2421,16 +2510,6 @@ int usb_deauthorize_device(struct usb_device *usb_dev)  	usb_dev->authorized = 0;  	usb_set_configuration(usb_dev, -1); -	kfree(usb_dev->product); -	usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL); -	kfree(usb_dev->manufacturer); -	usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL); -	kfree(usb_dev->serial); -	usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL); - -	usb_destroy_configuration(usb_dev); -	usb_dev->descriptor.bNumConfigurations = 0; -  out_unauthorized:  	usb_unlock_device(usb_dev);  	return 0; @@ -2458,17 +2537,7 @@ int usb_authorize_device(struct usb_device *usb_dev)  		goto error_device_descriptor;  	} -	kfree(usb_dev->product); -	usb_dev->product = NULL; -	kfree(usb_dev->manufacturer); -	usb_dev->manufacturer = NULL; -	kfree(usb_dev->serial); -	usb_dev->serial = NULL; -  	usb_dev->authorized = 1; -	result = usb_enumerate_device(usb_dev); -	if (result < 0) -		goto error_enumerate;  	/* Choose and set the configuration.  This registers the interfaces  	 * with the driver core and lets interface drivers bind to them.  	 */ @@ -2484,12 +2553,11 @@ int usb_authorize_device(struct usb_device *usb_dev)  	}  	dev_info(&usb_dev->dev, "authorized to connect\n"); -error_enumerate:  error_device_descriptor:  	usb_autosuspend_device(usb_dev);  error_autoresume:  out_authorized: -	usb_unlock_device(usb_dev);	// complements locktree +	usb_unlock_device(usb_dev);	/* complements locktree */  	return result;  } @@ -2517,10 +2585,25 @@ static unsigned hub_is_wusb(struct usb_hub *hub)  #define HUB_LONG_RESET_TIME	200  #define HUB_RESET_TIMEOUT	800 +/* + * "New scheme" enumeration causes an extra state transition to be + * exposed to an xhci host and causes USB3 devices to receive control + * commands in the default state.  This has been seen to cause + * enumeration failures, so disable this enumeration scheme for USB3 + * devices. + */ +static bool use_new_scheme(struct usb_device *udev, int retry) +{ +	if (udev->speed == USB_SPEED_SUPER) +		return false; + +	return USE_NEW_SCHEME(retry); +} +  static int hub_port_reset(struct usb_hub *hub, int port1,  			struct usb_device *udev, unsigned int delay, bool warm); -/* Is a USB 3.0 port in the Inactive or Complinance Mode state? +/* Is a USB 3.0 port in the Inactive or Compliance Mode state?   * Port worm reset is required to recover   */  static bool hub_port_warm_reset_required(struct usb_hub *hub, u16 portstatus) @@ -2558,9 +2641,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,  		if (delay_time >= 2 * HUB_SHORT_RESET_TIME)  			delay = HUB_LONG_RESET_TIME; -		dev_dbg (hub->intfdev, -			"port %d not %sreset yet, waiting %dms\n", -			port1, warm ? "warm " : "", delay); +		dev_dbg(&hub->ports[port1 - 1]->dev, +				"not %sreset yet, waiting %dms\n", +				warm ? "warm " : "", delay);  	}  	if ((portstatus & USB_PORT_STAT_RESET)) @@ -2644,6 +2727,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,  {  	int i, status;  	u16 portchange, portstatus; +	struct usb_port *port_dev = hub->ports[port1 - 1];  	if (!hub_is_superspeed(hub->hdev)) {  		if (warm) { @@ -2677,9 +2761,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1,  		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); +			dev_err(&port_dev->dev, +					"cannot %sreset (err = %d)\n", +					warm ? "warm " : "", status);  		} else {  			status = hub_port_wait_reset(hub, port1, udev, delay,  								warm); @@ -2712,21 +2796,19 @@ static int hub_port_reset(struct usb_hub *hub, int port1,  			 * hot or warm reset failed.  Try another warm reset.  			 */  			if (!warm) { -				dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n", -						port1); +				dev_dbg(&port_dev->dev, +						"hot reset failed, warm reset\n");  				warm = true;  			}  		} -		dev_dbg (hub->intfdev, -			"port %d not enabled, trying %sreset again...\n", -			port1, warm ? "warm " : ""); +		dev_dbg(&port_dev->dev, +				"not enabled, trying %sreset again...\n", +				warm ? "warm " : "");  		delay = HUB_LONG_RESET_TIME;  	} -	dev_err (hub->intfdev, -		"Cannot enable port %i.  Maybe the USB cable is bad?\n", -		port1); +	dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");  done:  	if (!hub_is_superspeed(hub->hdev)) @@ -2751,6 +2833,20 @@ static int port_is_power_on(struct usb_hub *hub, unsigned portstatus)  	return ret;  } +static void usb_lock_port(struct usb_port *port_dev) +		__acquires(&port_dev->status_lock) +{ +	mutex_lock(&port_dev->status_lock); +	__acquire(&port_dev->status_lock); +} + +static void usb_unlock_port(struct usb_port *port_dev) +		__releases(&port_dev->status_lock) +{ +	mutex_unlock(&port_dev->status_lock); +	__release(&port_dev->status_lock); +} +  #ifdef	CONFIG_PM  /* Check if a port is suspended(USB2.0 port) or in U3 state(USB3.0 port) */ @@ -2777,6 +2873,8 @@ static int check_port_resume_type(struct usb_device *udev,  		struct usb_hub *hub, int port1,  		int status, unsigned portchange, unsigned portstatus)  { +	struct usb_port *port_dev = hub->ports[port1 - 1]; +  	/* Is the device still present? */  	if (status || port_is_suspended(hub, portstatus) ||  			!port_is_power_on(hub, portstatus) || @@ -2796,9 +2894,8 @@ static int check_port_resume_type(struct usb_device *udev,  	}  	if (status) { -		dev_dbg(hub->intfdev, -				"port %d status %04x.%04x after resume, %d\n", -				port1, portchange, portstatus, status); +		dev_dbg(&port_dev->dev, "status %04x.%04x after resume, %d\n", +				portchange, portstatus, status);  	} else if (udev->reset_resume) {  		/* Late port handoff can set status-change bits */ @@ -2972,6 +3069,8 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  	int		status;  	bool		really_suspend = true; +	usb_lock_port(port_dev); +  	/* enable remote wakeup when appropriate; this lets the device  	 * wake up the upstream hub (including maybe the root hub).  	 * @@ -3029,8 +3128,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  		status = 0;  	}  	if (status) { -		dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n", -				port1, status); +		dev_dbg(&port_dev->dev, "can't suspend, status %d\n", status);  		/* Try to enable USB3 LPM and LTM again */  		usb_unlocked_enable_lpm(udev); @@ -3061,12 +3159,13 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)  		usb_set_device_state(udev, USB_STATE_SUSPENDED);  	} -	if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled) { +	if (status == 0 && !udev->do_remote_wakeup && udev->persist_enabled +			&& test_and_clear_bit(port1, hub->child_usage_bits))  		pm_runtime_put_sync(&port_dev->dev); -		port_dev->did_runtime_put = true; -	}  	usb_mark_last_busy(hub->hdev); + +	usb_unlock_port(port_dev);  	return status;  } @@ -3104,12 +3203,22 @@ static int finish_port_resume(struct usb_device *udev)  	 * operation is carried out here, after the port has been  	 * resumed.  	 */ -	if (udev->reset_resume) +	if (udev->reset_resume) { +		/* +		 * If the device morphs or switches modes when it is reset, +		 * we don't want to perform a reset-resume.  We'll fail the +		 * resume, which will cause a logical disconnect, and then +		 * the device will be rediscovered. +		 */   retry_reset_resume: -		status = usb_reset_and_verify_device(udev); +		if (udev->quirks & USB_QUIRK_RESET) +			status = -ENODEV; +		else +			status = usb_reset_and_verify_device(udev); +	} - 	/* 10.5.4.5 says be sure devices in the tree are still there. - 	 * For now let's assume the device didn't go crazy on resume, +	/* 10.5.4.5 says be sure devices in the tree are still there. +	 * For now let's assume the device didn't go crazy on resume,  	 * and device drivers will know about any resume quirks.  	 */  	if (status == 0) { @@ -3196,9 +3305,8 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  	int		status;  	u16		portchange, portstatus; -	if (port_dev->did_runtime_put) { +	if (!test_and_set_bit(port1, hub->child_usage_bits)) {  		status = pm_runtime_get_sync(&port_dev->dev); -		port_dev->did_runtime_put = false;  		if (status < 0) {  			dev_dbg(&udev->dev, "can't resume usb port, status %d\n",  					status); @@ -3206,15 +3314,13 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  		}  	} +	usb_lock_port(port_dev); +  	/* Skip the initial Clear-Suspend step for a remote wakeup */  	status = hub_port_status(hub, port1, &portstatus, &portchange);  	if (status == 0 && !port_is_suspended(hub, portstatus))  		goto SuspendCleared; -	// dev_dbg(hub->intfdev, "resume port %d\n", port1); - -	set_bit(port1, hub->busy_bits); -  	/* see 7.1.7.7; affects power usage, but not budgeting */  	if (hub_is_superspeed(hub->hdev))  		status = hub_set_port_link_state(hub, port1, USB_SS_PORT_LS_U0); @@ -3222,8 +3328,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  		status = usb_clear_port_feature(hub->hdev,  				port1, USB_PORT_FEAT_SUSPEND);  	if (status) { -		dev_dbg(hub->intfdev, "can't resume port %d, status %d\n", -				port1, status); +		dev_dbg(&port_dev->dev, "can't resume, status %d\n", status);  	} else {  		/* drive resume for at least 20 msec */  		dev_dbg(&udev->dev, "usb %sresume\n", @@ -3254,8 +3359,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  		}  	} -	clear_bit(port1, hub->busy_bits); -  	status = check_port_resume_type(udev,  			hub, port1, status, portchange, portstatus);  	if (status == 0) @@ -3273,16 +3376,18 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)  		usb_unlocked_enable_lpm(udev);  	} +	usb_unlock_port(port_dev); +  	return status;  }  #ifdef	CONFIG_PM_RUNTIME -/* caller has locked udev */  int usb_remote_wakeup(struct usb_device *udev)  {  	int	status = 0; +	usb_lock_device(udev);  	if (udev->state == USB_STATE_SUSPENDED) {  		dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");  		status = usb_autoresume_device(udev); @@ -3291,9 +3396,59 @@ int usb_remote_wakeup(struct usb_device *udev)  			usb_autosuspend_device(udev);  		}  	} +	usb_unlock_device(udev);  	return status;  } +/* Returns 1 if there was a remote wakeup and a connect status change. */ +static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, +		u16 portstatus, u16 portchange) +		__must_hold(&port_dev->status_lock) +{ +	struct usb_port *port_dev = hub->ports[port - 1]; +	struct usb_device *hdev; +	struct usb_device *udev; +	int connect_change = 0; +	int ret; + +	hdev = hub->hdev; +	udev = port_dev->child; +	if (!hub_is_superspeed(hdev)) { +		if (!(portchange & USB_PORT_STAT_C_SUSPEND)) +			return 0; +		usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND); +	} else { +		if (!udev || udev->state != USB_STATE_SUSPENDED || +				 (portstatus & USB_PORT_STAT_LINK_STATE) != +				 USB_SS_PORT_LS_U0) +			return 0; +	} + +	if (udev) { +		/* TRSMRCY = 10 msec */ +		msleep(10); + +		usb_unlock_port(port_dev); +		ret = usb_remote_wakeup(udev); +		usb_lock_port(port_dev); +		if (ret < 0) +			connect_change = 1; +	} else { +		ret = -ENODEV; +		hub_port_disable(hub, port, 1); +	} +	dev_dbg(&port_dev->dev, "resume, status %d\n", ret); +	return connect_change; +} + +#else + +static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, +		u16 portstatus, u16 portchange) +{ +	return 0; +} +  #endif  static int check_ports_changed(struct usb_hub *hub) @@ -3324,11 +3479,12 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)  	 */  	hub->wakeup_enabled_descendants = 0;  	for (port1 = 1; port1 <= hdev->maxchild; port1++) { -		struct usb_device	*udev; +		struct usb_port *port_dev = hub->ports[port1 - 1]; +		struct usb_device *udev = port_dev->child; -		udev = hub->ports[port1 - 1]->child;  		if (udev && udev->can_submit) { -			dev_warn(&intf->dev, "port %d nyet suspended\n", port1); +			dev_warn(&port_dev->dev, "device %s not suspended yet\n", +					dev_name(&udev->dev));  			if (PMSG_IS_AUTO(msg))  				return -EBUSY;  		} @@ -3426,6 +3582,9 @@ static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state)  	unsigned long long u2_pel;  	int ret; +	if (udev->state != USB_STATE_CONFIGURED) +		return 0; +  	/* Convert SEL and PEL stored in ns to us */  	u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000);  	u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000); @@ -3844,6 +4003,12 @@ EXPORT_SYMBOL_GPL(usb_disable_ltm);  void usb_enable_ltm(struct usb_device *udev) { }  EXPORT_SYMBOL_GPL(usb_enable_ltm); +static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, +		u16 portstatus, u16 portchange) +{ +	return 0; +} +  #endif	/* CONFIG_PM */ @@ -3852,7 +4017,7 @@ EXPORT_SYMBOL_GPL(usb_enable_ltm);   * Between connect detection and reset signaling there must be a delay   * of 100ms at least for debounce and power-settling.  The corresponding   * timer shall restart whenever the downstream port detects a disconnect. - *  + *   * Apparently there are some bluetooth and irda-dongles and a number of   * low-speed devices for which this debounce period may last over a second.   * Not covered by the spec - but easy to deal with. @@ -3865,9 +4030,10 @@ EXPORT_SYMBOL_GPL(usb_enable_ltm);  int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected)  {  	int ret; -	int total_time, stable_time = 0;  	u16 portchange, portstatus;  	unsigned connection = 0xffff; +	int total_time, stable_time = 0; +	struct usb_port *port_dev = hub->ports[port1 - 1];  	for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {  		ret = hub_port_status(hub, port1, &portstatus, &portchange); @@ -3896,9 +4062,8 @@ int hub_port_debounce(struct usb_hub *hub, int port1, bool must_be_connected)  		msleep(HUB_DEBOUNCE_STEP);  	} -	dev_dbg (hub->intfdev, -		"debounce: port %d: total %dms stable %dms status 0x%x\n", -		port1, total_time, stable_time, portstatus); +	dev_dbg(&port_dev->dev, "debounce total %dms stable %dms status 0x%x\n", +			total_time, stable_time, portstatus);  	if (stable_time < HUB_DEBOUNCE_STABLE)  		return -ETIMEDOUT; @@ -3946,21 +4111,61 @@ static int hub_set_address(struct usb_device *udev, int devnum)  	return retval;  } +/* + * There are reports of USB 3.0 devices that say they support USB 2.0 Link PM + * when they're plugged into a USB 2.0 port, but they don't work when LPM is + * enabled. + * + * Only enable USB 2.0 Link PM if the port is internal (hardwired), or the + * device says it supports the new USB 2.0 Link PM errata by setting the BESL + * support bit in the BOS descriptor. + */ +static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) +{ +	struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); +	int connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN; + +	if (!udev->usb2_hw_lpm_capable) +		return; + +	if (hub) +		connect_type = hub->ports[udev->portnum - 1]->connect_type; + +	if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) || +			connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) { +		udev->usb2_hw_lpm_allowed = 1; +		usb_set_usb2_hardware_lpm(udev, 1); +	} +} + +static int hub_enable_device(struct usb_device *udev) +{ +	struct usb_hcd *hcd = bus_to_hcd(udev->bus); + +	if (!hcd->driver->enable_device) +		return 0; +	if (udev->state == USB_STATE_ADDRESS) +		return 0; +	if (udev->state != USB_STATE_DEFAULT) +		return -EINVAL; + +	return hcd->driver->enable_device(hcd, udev); +} +  /* Reset device, (re)assign address, get device descriptor.   * Device connection must be stable, no more debouncing needed.   * Returns device in USB_STATE_ADDRESS, except on error.   *   * If this is called for an already-existing device (as part of - * usb_reset_and_verify_device), the caller must own the device lock.  For a - * newly detected device that is not accessible through any global - * pointers, it's not necessary to lock the device. + * usb_reset_and_verify_device), the caller must own the device lock and + * the port lock.  For a newly detected device that is not accessible + * through any global pointers, it's not necessary to lock the device, + * but it is still necessary to lock the port.   */  static int  hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  		int retry_counter)  { -	static DEFINE_MUTEX(usb_address0_mutex); -  	struct usb_device	*hdev = hub->hdev;  	struct usb_hcd		*hcd = bus_to_hcd(hdev->bus);  	int			i, j, retval; @@ -3983,7 +4188,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  	if (oldspeed == USB_SPEED_LOW)  		delay = HUB_LONG_RESET_TIME; -	mutex_lock(&usb_address0_mutex); +	mutex_lock(&hdev->bus->usb_address0_mutex);  	/* Reset the device; full speed may morph to high speed */  	/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */ @@ -4052,13 +4257,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  		udev->tt = &hub->tt;  		udev->ttport = port1;  	} -  +  	/* Why interleave GET_DESCRIPTOR and SET_ADDRESS this way?  	 * Because device hardware and firmware is sometimes buggy in  	 * this area, and this is how Linux has done it for ages.  	 * Change it cautiously.  	 * -	 * NOTE:  If USE_NEW_SCHEME() is true we will start by issuing +	 * NOTE:  If use_new_scheme() is true we will start by issuing  	 * a 64-byte GET_DESCRIPTOR request.  This is what Windows does,  	 * so it may help with some non-standards-compliant devices.  	 * Otherwise we start with SET_ADDRESS and then try to read the @@ -4066,10 +4271,21 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  	 * value.  	 */  	for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) { -		if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) { +		bool did_new_scheme = false; + +		if (use_new_scheme(udev, retry_counter)) {  			struct usb_device_descriptor *buf;  			int r = 0; +			did_new_scheme = true; +			retval = hub_enable_device(udev); +			if (retval < 0) { +				dev_err(&udev->dev, +					"hub failed to enable device, error %d\n", +					retval); +				goto fail; +			} +  #define GET_DESCRIPTOR_BUFSIZE	64  			buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO);  			if (!buf) { @@ -4127,11 +4343,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  #undef GET_DESCRIPTOR_BUFSIZE  		} - 		/* - 		 * If device is WUSB, we already assigned an - 		 * unauthorized address in the Connect Ack sequence; - 		 * authorization will assign the final address. - 		 */ +		/* +		 * If device is WUSB, we already assigned an +		 * unauthorized address in the Connect Ack sequence; +		 * authorization will assign the final address. +		 */  		if (udev->wusb == 0) {  			for (j = 0; j < SET_ADDRESS_TRIES; ++j) {  				retval = hub_set_address(udev, devnum); @@ -4158,9 +4374,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  			 *  - read ep0 maxpacket even for high and low speed,  			 */  			msleep(10); -			if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) +			/* use_new_scheme() checks the speed which may have +			 * changed since the initial look so we cache the result +			 * in did_new_scheme +			 */ +			if (did_new_scheme)  				break; -  		} +		}  		retval = usb_get_device_descriptor(udev, 8);  		if (retval < 8) { @@ -4216,7 +4436,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);  		usb_ep0_reinit(udev);  	} -   +  	retval = usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE);  	if (retval < (signed)sizeof(udev->descriptor)) {  		if (retval != -ENODEV) @@ -4239,12 +4459,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,  	/* notify HCD that we have a device connected and addressed */  	if (hcd->driver->update_device)  		hcd->driver->update_device(hcd, udev); +	hub_set_initial_usb2_lpm_policy(udev);  fail:  	if (retval) {  		hub_port_disable(hub, port1, 0);  		update_devnum(udev, devnum);	/* for disconnect processing */  	} -	mutex_unlock(&usb_address0_mutex); +	mutex_unlock(&hdev->bus->usb_address0_mutex);  	return retval;  } @@ -4266,7 +4487,8 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1)  		/* hub LEDs are probably harder to miss than syslog */  		if (hub->has_indicators) {  			hub->indicator[port1-1] = INDICATOR_GREEN_BLINK; -			schedule_delayed_work (&hub->leds, 0); +			queue_delayed_work(system_power_efficient_wq, +					&hub->leds, 0);  		}  	}  	kfree(qual); @@ -4284,9 +4506,10 @@ hub_power_remaining (struct usb_hub *hub)  	remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent;  	for (port1 = 1; port1 <= hdev->maxchild; ++port1) { -		struct usb_device	*udev = hub->ports[port1 - 1]->child; -		int			delta; -		unsigned		unit_load; +		struct usb_port *port_dev = hub->ports[port1 - 1]; +		struct usb_device *udev = port_dev->child; +		unsigned unit_load; +		int delta;  		if (!udev)  			continue; @@ -4306,91 +4529,35 @@ hub_power_remaining (struct usb_hub *hub)  		else  			delta = 8;  		if (delta > hub->mA_per_port) -			dev_warn(&udev->dev, -				 "%dmA is over %umA budget for port %d!\n", -				 delta, hub->mA_per_port, port1); +			dev_warn(&port_dev->dev, "%dmA is over %umA budget!\n", +					delta, hub->mA_per_port);  		remaining -= delta;  	}  	if (remaining < 0) {  		dev_warn(hub->intfdev, "%dmA over power budget!\n", -			- remaining); +			-remaining);  		remaining = 0;  	}  	return remaining;  } -/* Handle physical or logical connection change events. - * This routine is called when: - * 	a port connection-change occurs; - *	a port enable-change occurs (often caused by EMI); - *	usb_reset_and_verify_device() encounters changed descriptors (as from - *		a firmware download) - * caller already locked the hub - */ -static void hub_port_connect_change(struct usb_hub *hub, int port1, -					u16 portstatus, u16 portchange) +static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, +		u16 portchange)  { -	struct usb_device *hdev = hub->hdev; -	struct device *hub_dev = hub->intfdev; -	struct usb_hcd *hcd = bus_to_hcd(hdev->bus); -	unsigned wHubCharacteristics = -			le16_to_cpu(hub->descriptor->wHubCharacteristics); -	struct usb_device *udev;  	int status, i;  	unsigned unit_load; - -	dev_dbg (hub_dev, -		"port %d, status %04x, change %04x, %s\n", -		port1, portstatus, portchange, portspeed(hub, portstatus)); - -	if (hub->has_indicators) { -		set_port_led(hub, port1, HUB_LED_AUTO); -		hub->indicator[port1-1] = INDICATOR_AUTO; -	} - -#ifdef	CONFIG_USB_OTG -	/* during HNP, don't repeat the debounce */ -	if (hdev->bus->is_b_host) -		portchange &= ~(USB_PORT_STAT_C_CONNECTION | -				USB_PORT_STAT_C_ENABLE); -#endif - -	/* Try to resuscitate an existing device */ -	udev = hub->ports[port1 - 1]->child; -	if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && -			udev->state != USB_STATE_NOTATTACHED) { -		usb_lock_device(udev); -		if (portstatus & USB_PORT_STAT_ENABLE) { -			status = 0;		/* Nothing to do */ - -#ifdef CONFIG_PM_RUNTIME -		} else if (udev->state == USB_STATE_SUSPENDED && -				udev->persist_enabled) { -			/* For a suspended device, treat this as a -			 * remote wakeup event. -			 */ -			status = usb_remote_wakeup(udev); -#endif - -		} else { -			status = -ENODEV;	/* Don't resuscitate */ -		} -		usb_unlock_device(udev); - -		if (status == 0) { -			clear_bit(port1, hub->change_bits); -			return; -		} -	} +	struct usb_device *hdev = hub->hdev; +	struct usb_hcd *hcd = bus_to_hcd(hdev->bus); +	struct usb_port *port_dev = hub->ports[port1 - 1]; +	struct usb_device *udev = port_dev->child;  	/* Disconnect any existing devices under this port */  	if (udev) {  		if (hcd->phy && !hdev->parent &&  				!(portstatus & USB_PORT_STAT_CONNECTION))  			usb_phy_notify_disconnect(hcd->phy, udev->speed); -		usb_disconnect(&hub->ports[port1 - 1]->child); +		usb_disconnect(&port_dev->child);  	} -	clear_bit(port1, hub->change_bits);  	/* We can forget about a "removed" device when there's a physical  	 * disconnect or the connect status changes. @@ -4404,8 +4571,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		status = hub_port_debounce_be_stable(hub, port1);  		if (status < 0) {  			if (status != -ENODEV && printk_ratelimit()) -				dev_err(hub_dev, "connect-debounce failed, " -						"port %d disabled\n", port1); +				dev_err(&port_dev->dev, +						"connect-debounce failed\n");  			portstatus &= ~USB_PORT_STAT_CONNECTION;  		} else {  			portstatus = status; @@ -4419,12 +4586,12 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  			test_bit(port1, hub->removed_bits)) {  		/* maybe switch power back on (e.g. root hub was reset) */ -		if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2 +		if (hub_is_port_power_switchable(hub)  				&& !port_is_power_on(hub, portstatus))  			set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);  		if (portstatus & USB_PORT_STAT_ENABLE) -  			goto done; +			goto done;  		return;  	}  	if (hub_is_superspeed(hub->hdev)) @@ -4440,14 +4607,13 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		 */  		udev = usb_alloc_dev(hdev, hdev->bus, port1);  		if (!udev) { -			dev_err (hub_dev, -				"couldn't allocate port %d usb_device\n", -				port1); +			dev_err(&port_dev->dev, +					"couldn't allocate usb_device\n");  			goto done;  		}  		usb_set_device_state(udev, USB_STATE_POWERED); - 		udev->bus_mA = hub->mA_per_port; +		udev->bus_mA = hub->mA_per_port;  		udev->level = hdev->level + 1;  		udev->wusb = hub_is_wusb(hub); @@ -4464,7 +4630,9 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		}  		/* reset (non-USB 3.0 devices) and get descriptor */ +		usb_lock_port(port_dev);  		status = hub_port_init(hub, udev, port1, i); +		usb_unlock_port(port_dev);  		if (status < 0)  			goto loop; @@ -4495,13 +4663,15 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  				if (hub->has_indicators) {  					hub->indicator[port1-1] =  						INDICATOR_AMBER_BLINK; -					schedule_delayed_work (&hub->leds, 0); +					queue_delayed_work( +						system_power_efficient_wq, +						&hub->leds, 0);  				}  				status = -ENOTCONN;	/* Don't retry */  				goto loop_disable;  			}  		} -  +  		/* check for devices running slower than they could */  		if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0200  				&& udev->speed == USB_SPEED_FULL @@ -4514,6 +4684,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		 */  		status = 0; +		mutex_lock(&usb_port_peer_mutex); +  		/* We mustn't add new devices if the parent hub has  		 * been disconnected; we would race with the  		 * recursively_mark_NOTATTACHED() routine. @@ -4522,16 +4694,19 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		if (hdev->state == USB_STATE_NOTATTACHED)  			status = -ENOTCONN;  		else -			hub->ports[port1 - 1]->child = udev; +			port_dev->child = udev;  		spin_unlock_irq(&device_state_lock); +		mutex_unlock(&usb_port_peer_mutex);  		/* Run it through the hoops (find a driver, etc) */  		if (!status) {  			status = usb_new_device(udev);  			if (status) { +				mutex_lock(&usb_port_peer_mutex);  				spin_lock_irq(&device_state_lock); -				hub->ports[port1 - 1]->child = NULL; +				port_dev->child = NULL;  				spin_unlock_irq(&device_state_lock); +				mutex_unlock(&usb_port_peer_mutex);  			}  		} @@ -4540,7 +4715,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,  		status = hub_power_remaining(hub);  		if (status) -			dev_dbg(hub_dev, "%dmA power budget left\n", status); +			dev_dbg(hub->intfdev, "%dmA power budget left\n", status);  		return; @@ -4558,56 +4733,200 @@ loop:  			!hcd->driver->port_handed_over ||  			!(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); +			dev_err(&port_dev->dev, +					"unable to enumerate USB device\n");  	} -  +  done:  	hub_port_disable(hub, port1, 1);  	if (hcd->driver->relinquish_port && !hub->hdev->parent)  		hcd->driver->relinquish_port(hcd, port1); +  } -/* Returns 1 if there was a remote wakeup and a connect status change. */ -static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, -		u16 portstatus, u16 portchange) +/* Handle physical or logical connection change events. + * This routine is called when: + *	a port connection-change occurs; + *	a port enable-change occurs (often caused by EMI); + *	usb_reset_and_verify_device() encounters changed descriptors (as from + *		a firmware download) + * caller already locked the hub + */ +static void hub_port_connect_change(struct usb_hub *hub, int port1, +					u16 portstatus, u16 portchange) +		__must_hold(&port_dev->status_lock)  { -	struct usb_device *hdev; -	struct usb_device *udev; -	int connect_change = 0; -	int ret; +	struct usb_port *port_dev = hub->ports[port1 - 1]; +	struct usb_device *udev = port_dev->child; +	int status = -ENODEV; -	hdev = hub->hdev; -	udev = hub->ports[port - 1]->child; -	if (!hub_is_superspeed(hdev)) { -		if (!(portchange & USB_PORT_STAT_C_SUSPEND)) -			return 0; -		usb_clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND); -	} else { -		if (!udev || udev->state != USB_STATE_SUSPENDED || -				 (portstatus & USB_PORT_STAT_LINK_STATE) != -				 USB_SS_PORT_LS_U0) -			return 0; +	dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus, +			portchange, portspeed(hub, portstatus)); + +	if (hub->has_indicators) { +		set_port_led(hub, port1, HUB_LED_AUTO); +		hub->indicator[port1-1] = INDICATOR_AUTO;  	} -	if (udev) { -		/* TRSMRCY = 10 msec */ -		msleep(10); +#ifdef	CONFIG_USB_OTG +	/* during HNP, don't repeat the debounce */ +	if (hub->hdev->bus->is_b_host) +		portchange &= ~(USB_PORT_STAT_C_CONNECTION | +				USB_PORT_STAT_C_ENABLE); +#endif + +	/* Try to resuscitate an existing device */ +	if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && +			udev->state != USB_STATE_NOTATTACHED) { +		if (portstatus & USB_PORT_STAT_ENABLE) { +			status = 0;		/* Nothing to do */ +#ifdef CONFIG_PM_RUNTIME +		} else if (udev->state == USB_STATE_SUSPENDED && +				udev->persist_enabled) { +			/* For a suspended device, treat this as a +			 * remote wakeup event. +			 */ +			usb_unlock_port(port_dev); +			status = usb_remote_wakeup(udev); +			usb_lock_port(port_dev); +#endif +		} else { +			/* Don't resuscitate */; +		} +	} +	clear_bit(port1, hub->change_bits); + +	/* successfully revalidated the connection */ +	if (status == 0) +		return; + +	usb_unlock_port(port_dev); +	hub_port_connect(hub, port1, portstatus, portchange); +	usb_lock_port(port_dev); +} + +static void port_event(struct usb_hub *hub, int port1) +		__must_hold(&port_dev->status_lock) +{ +	int connect_change, reset_device = 0; +	struct usb_port *port_dev = hub->ports[port1 - 1]; +	struct usb_device *udev = port_dev->child; +	struct usb_device *hdev = hub->hdev; +	u16 portstatus, portchange; + +	connect_change = test_bit(port1, hub->change_bits); +	clear_bit(port1, hub->event_bits); +	clear_bit(port1, hub->wakeup_bits); + +	if (hub_port_status(hub, port1, &portstatus, &portchange) < 0) +		return; + +	if (portchange & USB_PORT_STAT_C_CONNECTION) { +		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); +		connect_change = 1; +	} + +	if (portchange & USB_PORT_STAT_C_ENABLE) { +		if (!connect_change) +			dev_dbg(&port_dev->dev, "enable change, status %08x\n", +					portstatus); +		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE); + +		/* +		 * EM interference sometimes causes badly shielded USB devices +		 * to be shutdown by the hub, this hack enables them again. +		 * Works at least with mouse driver. +		 */ +		if (!(portstatus & USB_PORT_STAT_ENABLE) +		    && !connect_change && udev) { +			dev_err(&port_dev->dev, "disabled by hub (EMI?), re-enabling...\n"); +			connect_change = 1; +		} +	} +	if (portchange & USB_PORT_STAT_C_OVERCURRENT) { +		u16 status = 0, unused; + +		dev_dbg(&port_dev->dev, "over-current change\n"); +		usb_clear_port_feature(hdev, port1, +				USB_PORT_FEAT_C_OVER_CURRENT); +		msleep(100);	/* Cool down */ +		hub_power_on(hub, true); +		hub_port_status(hub, port1, &status, &unused); +		if (status & USB_PORT_STAT_OVERCURRENT) +			dev_err(&port_dev->dev, "over-current condition\n"); +	} + +	if (portchange & USB_PORT_STAT_C_RESET) { +		dev_dbg(&port_dev->dev, "reset change\n"); +		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_RESET); +	} +	if ((portchange & USB_PORT_STAT_C_BH_RESET) +	    && hub_is_superspeed(hdev)) { +		dev_dbg(&port_dev->dev, "warm reset change\n"); +		usb_clear_port_feature(hdev, port1, +				USB_PORT_FEAT_C_BH_PORT_RESET); +	} +	if (portchange & USB_PORT_STAT_C_LINK_STATE) { +		dev_dbg(&port_dev->dev, "link state change\n"); +		usb_clear_port_feature(hdev, port1, +				USB_PORT_FEAT_C_PORT_LINK_STATE); +	} +	if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { +		dev_warn(&port_dev->dev, "config error\n"); +		usb_clear_port_feature(hdev, port1, +				USB_PORT_FEAT_C_PORT_CONFIG_ERROR); +	} + +	/* skip port actions that require the port to be powered on */ +	if (!pm_runtime_active(&port_dev->dev)) +		return; + +	if (hub_handle_remote_wakeup(hub, port1, portstatus, portchange)) +		connect_change = 1; + +	/* +	 * Warm reset a USB3 protocol port if it's in +	 * SS.Inactive state. +	 */ +	if (hub_port_warm_reset_required(hub, portstatus)) { +		dev_dbg(&port_dev->dev, "do warm reset\n"); +		if (!udev || !(portstatus & USB_PORT_STAT_CONNECTION) +				|| udev->state == USB_STATE_NOTATTACHED) { +			if (hub_port_reset(hub, port1, NULL, +					HUB_BH_RESET_TIME, true) < 0) +				hub_port_disable(hub, port1, 1); +		} else +			reset_device = 1; +	} + +	/* +	 * On disconnect USB3 protocol ports transit from U0 to +	 * SS.Inactive to Rx.Detect. If this happens a warm- +	 * reset is not needed, but a (re)connect may happen +	 * before khubd runs and sees the disconnect, and the +	 * device may be an unknown state. +	 * +	 * If the port went through SS.Inactive without khubd +	 * seeing it the C_LINK_STATE change flag will be set, +	 * and we reset the dev to put it in a known state. +	 */ +	if (reset_device || (udev && hub_is_superspeed(hub->hdev) +				&& (portchange & USB_PORT_STAT_C_LINK_STATE) +				&& (portstatus & USB_PORT_STAT_CONNECTION))) { +		usb_unlock_port(port_dev);  		usb_lock_device(udev); -		ret = usb_remote_wakeup(udev); +		usb_reset_device(udev);  		usb_unlock_device(udev); -		if (ret < 0) -			connect_change = 1; -	} else { -		ret = -ENODEV; -		hub_port_disable(hub, port, 1); +		usb_lock_port(port_dev); +		connect_change = 0;  	} -	dev_dbg(hub->intfdev, "resume on port %d, status %d\n", -			port, ret); -	return connect_change; + +	if (connect_change) +		hub_port_connect_change(hub, port1, portstatus, portchange);  } +  static void hub_events(void)  {  	struct list_head *tmp; @@ -4617,10 +4936,7 @@ static void hub_events(void)  	struct device *hub_dev;  	u16 hubstatus;  	u16 hubchange; -	u16 portstatus; -	u16 portchange;  	int i, ret; -	int connect_change, wakeup_change;  	/*  	 *  We restart the list every time to avoid a deadlock with @@ -4694,127 +5010,28 @@ static void hub_events(void)  		/* deal with port status changes */  		for (i = 1; i <= hdev->maxchild; i++) { -			if (test_bit(i, hub->busy_bits)) -				continue; -			connect_change = test_bit(i, hub->change_bits); -			wakeup_change = test_and_clear_bit(i, hub->wakeup_bits); -			if (!test_and_clear_bit(i, hub->event_bits) && -					!connect_change && !wakeup_change) -				continue; - -			ret = hub_port_status(hub, i, -					&portstatus, &portchange); -			if (ret < 0) -				continue; - -			if (portchange & USB_PORT_STAT_C_CONNECTION) { -				usb_clear_port_feature(hdev, i, -					USB_PORT_FEAT_C_CONNECTION); -				connect_change = 1; -			} - -			if (portchange & USB_PORT_STAT_C_ENABLE) { -				if (!connect_change) -					dev_dbg (hub_dev, -						"port %d enable change, " -						"status %08x\n", -						i, portstatus); -				usb_clear_port_feature(hdev, i, -					USB_PORT_FEAT_C_ENABLE); +			struct usb_port *port_dev = hub->ports[i - 1]; +			if (test_bit(i, hub->event_bits) +					|| test_bit(i, hub->change_bits) +					|| test_bit(i, hub->wakeup_bits)) {  				/* -				 * EM interference sometimes causes badly -				 * shielded USB devices to be shutdown by -				 * the hub, this hack enables them again. -				 * Works at least with mouse driver.  +				 * The get_noresume and barrier ensure that if +				 * the port was in the process of resuming, we +				 * flush that work and keep the port active for +				 * the duration of the port_event().  However, +				 * if the port is runtime pm suspended +				 * (powered-off), we leave it in that state, run +				 * an abbreviated port_event(), and move on.  				 */ -				if (!(portstatus & USB_PORT_STAT_ENABLE) -				    && !connect_change -				    && hub->ports[i - 1]->child) { -					dev_err (hub_dev, -					    "port %i " -					    "disabled by hub (EMI?), " -					    "re-enabling...\n", -						i); -					connect_change = 1; -				} +				pm_runtime_get_noresume(&port_dev->dev); +				pm_runtime_barrier(&port_dev->dev); +				usb_lock_port(port_dev); +				port_event(hub, i); +				usb_unlock_port(port_dev); +				pm_runtime_put_sync(&port_dev->dev);  			} - -			if (hub_handle_remote_wakeup(hub, i, -						portstatus, portchange)) -				connect_change = 1; - -			if (portchange & USB_PORT_STAT_C_OVERCURRENT) { -				u16 status = 0; -				u16 unused; - -				dev_dbg(hub_dev, "over-current change on port " -					"%d\n", i); -				usb_clear_port_feature(hdev, i, -					USB_PORT_FEAT_C_OVER_CURRENT); -				msleep(100);	/* Cool down */ -				hub_power_on(hub, true); -				hub_port_status(hub, i, &status, &unused); -				if (status & USB_PORT_STAT_OVERCURRENT) -					dev_err(hub_dev, "over-current " -						"condition on port %d\n", i); -			} - -			if (portchange & USB_PORT_STAT_C_RESET) { -				dev_dbg (hub_dev, -					"reset change on port %d\n", -					i); -				usb_clear_port_feature(hdev, i, -					USB_PORT_FEAT_C_RESET); -			} -			if ((portchange & USB_PORT_STAT_C_BH_RESET) && -					hub_is_superspeed(hub->hdev)) { -				dev_dbg(hub_dev, -					"warm reset change on port %d\n", -					i); -				usb_clear_port_feature(hdev, i, -					USB_PORT_FEAT_C_BH_PORT_RESET); -			} -			if (portchange & USB_PORT_STAT_C_LINK_STATE) { -				usb_clear_port_feature(hub->hdev, i, -						USB_PORT_FEAT_C_PORT_LINK_STATE); -			} -			if (portchange & USB_PORT_STAT_C_CONFIG_ERROR) { -				dev_warn(hub_dev, -					"config error on port %d\n", -					i); -				usb_clear_port_feature(hub->hdev, i, -						USB_PORT_FEAT_C_PORT_CONFIG_ERROR); -			} - -			/* Warm reset a USB3 protocol port if it's in -			 * SS.Inactive state. -			 */ -			if (hub_port_warm_reset_required(hub, portstatus)) { -				int status; -				struct usb_device *udev = -					hub->ports[i - 1]->child; - -				dev_dbg(hub_dev, "warm reset port %d\n", i); -				if (!udev || !(portstatus & -						USB_PORT_STAT_CONNECTION)) { -					status = hub_port_reset(hub, i, -							NULL, HUB_BH_RESET_TIME, -							true); -					if (status < 0) -						hub_port_disable(hub, i, 1); -				} else { -					usb_lock_device(udev); -					status = usb_reset_device(udev); -					usb_unlock_device(udev); -					connect_change = 0; -				} -			} - -			if (connect_change) -				hub_port_connect_change(hub, i, -						portstatus, portchange); -		} /* end for i */ +		}  		/* deal with hub status changes */  		if (test_and_clear_bit(0, hub->event_bits) == 0) @@ -4838,7 +5055,7 @@ static void hub_events(void)  				dev_dbg(hub_dev, "over-current change\n");  				clear_hub_feature(hdev, C_HUB_OVER_CURRENT);  				msleep(500);	/* Cool down */ -                        	hub_power_on(hub, true); +				hub_power_on(hub, true);  				hub_hub_status(hub, &status, &unused);  				if (status & HUB_STATUS_OVERCURRENT)  					dev_err(hub_dev, "over-current " @@ -4858,12 +5075,12 @@ static void hub_events(void)  		usb_unlock_device(hdev);  		kref_put(&hub->kref, hub_release); -        } /* end while (1) */ +	} /* end while (1) */  }  static int hub_thread(void *__unused)  { -	/* khubd needs to be freezable to avoid intefering with USB-PERSIST +	/* khubd needs to be freezable to avoid interfering with USB-PERSIST  	 * port handover.  Otherwise it might see that a full-speed device  	 * was gone before the EHCI controller had handed its port over to  	 * the companion full-speed controller. @@ -4883,7 +5100,7 @@ static int hub_thread(void *__unused)  static const struct usb_device_id hub_id_table[] = {      { .match_flags = USB_DEVICE_ID_MATCH_VENDOR -	           | USB_DEVICE_ID_MATCH_INT_CLASS, +			| USB_DEVICE_ID_MATCH_INT_CLASS,        .idVendor = USB_VENDOR_GENESYS_LOGIC,        .bInterfaceClass = USB_CLASS_HUB,        .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND}, @@ -5049,15 +5266,18 @@ static int descriptors_changed(struct usb_device *udev,   * if the reset wasn't even attempted.   *   * Note: - * The caller must own the device lock.  For example, it's safe to use - * this from a driver probe() routine after downloading new firmware. - * For calls that might not occur during probe(), drivers should lock - * the device using usb_lock_device_for_reset(). + * The caller must own the device lock and the port lock, the latter is + * taken by usb_reset_device().  For example, it's safe to use + * usb_reset_device() from a driver probe() routine after downloading + * new firmware.  For calls that might not occur during probe(), drivers + * should lock the device using usb_lock_device_for_reset().   *   * Locking exception: This routine may also be called from within an   * autoresume handler.  Such usage won't conflict with other tasks   * holding the device lock because these tasks should always call - * usb_autopm_resume_device(), thereby preventing any unwanted autoresume. + * usb_autopm_resume_device(), thereby preventing any unwanted + * autoresume.  The autoresume handler is expected to have already + * acquired the port lock before calling this routine.   */  static int usb_reset_and_verify_device(struct usb_device *udev)  { @@ -5066,7 +5286,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)  	struct usb_hcd			*hcd = bus_to_hcd(udev->bus);  	struct usb_device_descriptor	descriptor = udev->descriptor;  	struct usb_host_bos		*bos; -	int 				i, ret = 0; +	int				i, j, ret = 0;  	int				port1 = udev->portnum;  	if (udev->state == USB_STATE_NOTATTACHED || @@ -5076,13 +5296,17 @@ static int usb_reset_and_verify_device(struct usb_device *udev)  		return -EINVAL;  	} -	if (!parent_hdev) { -		/* this requires hcd-specific logic; see ohci_restart() */ -		dev_dbg(&udev->dev, "%s for root hub!\n", __func__); +	if (!parent_hdev)  		return -EISDIR; -	} +  	parent_hub = usb_hub_to_struct_hub(parent_hdev); +	/* Disable USB2 hardware LPM. +	 * It will be re-enabled by the enumeration process. +	 */ +	if (udev->usb2_hw_lpm_enabled == 1) +		usb_set_usb2_hardware_lpm(udev, 0); +  	bos = udev->bos;  	udev->bos = NULL; @@ -5103,7 +5327,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev)  		goto re_enumerate;  	} -	set_bit(port1, parent_hub->busy_bits);  	for (i = 0; i < SET_CONFIG_TRIES; ++i) {  		/* ep0 maxpacket size may change; let the HCD know about it. @@ -5113,17 +5336,16 @@ static int usb_reset_and_verify_device(struct usb_device *udev)  		if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV)  			break;  	} -	clear_bit(port1, parent_hub->busy_bits);  	if (ret < 0)  		goto re_enumerate; -  +  	/* Device might have changed firmware (DFU or similar) */  	if (descriptors_changed(udev, &descriptor, bos)) {  		dev_info(&udev->dev, "device firmware changed\n");  		udev->descriptor = descriptor;	/* for disconnect() calls */  		goto re_enumerate; -  	} +	}  	/* Restore the device's previous configuration */  	if (!udev->actconfig) @@ -5148,7 +5370,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)  			udev->actconfig->desc.bConfigurationValue, ret);  		mutex_unlock(hcd->bandwidth_mutex);  		goto re_enumerate; -  	} +	}  	mutex_unlock(hcd->bandwidth_mutex);  	usb_set_device_state(udev, USB_STATE_CONFIGURED); @@ -5186,16 +5408,20 @@ static int usb_reset_and_verify_device(struct usb_device *udev)  				ret);  			goto re_enumerate;  		} +		/* Resetting also frees any allocated streams */ +		for (j = 0; j < intf->cur_altsetting->desc.bNumEndpoints; j++) +			intf->cur_altsetting->endpoint[j].streams = 0;  	}  done:  	/* Now that the alt settings are re-installed, enable LTM and LPM. */ +	usb_set_usb2_hardware_lpm(udev, 1);  	usb_unlocked_enable_lpm(udev);  	usb_enable_ltm(udev);  	usb_release_bos_descriptor(udev);  	udev->bos = bos;  	return 0; -  +  re_enumerate:  	/* LPM state doesn't matter when we're about to destroy the device. */  	hub_port_logical_disconnect(parent_hub, port1); @@ -5230,7 +5456,9 @@ int usb_reset_device(struct usb_device *udev)  	int ret;  	int i;  	unsigned int noio_flag; +	struct usb_port *port_dev;  	struct usb_host_config *config = udev->actconfig; +	struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent);  	if (udev->state == USB_STATE_NOTATTACHED ||  			udev->state == USB_STATE_SUSPENDED) { @@ -5239,6 +5467,14 @@ int usb_reset_device(struct usb_device *udev)  		return -EINVAL;  	} +	if (!udev->parent) { +		/* this requires hcd-specific logic; see ohci_restart() */ +		dev_dbg(&udev->dev, "%s for root hub!\n", __func__); +		return -EISDIR; +	} + +	port_dev = hub->ports[udev->portnum - 1]; +  	/*  	 * Don't allocate memory with GFP_KERNEL in current  	 * context to avoid possible deadlock if usb mass @@ -5272,7 +5508,9 @@ int usb_reset_device(struct usb_device *udev)  		}  	} +	usb_lock_port(port_dev);  	ret = usb_reset_and_verify_device(udev); +	usb_unlock_port(port_dev);  	if (config) {  		for (i = config->desc.bNumInterfaces - 1; i >= 0; --i) { @@ -5287,10 +5525,11 @@ int usb_reset_device(struct usb_device *udev)  				else if (cintf->condition ==  						USB_INTERFACE_BOUND)  					rebind = 1; +				if (rebind) +					cintf->needs_binding = 1;  			} -			if (ret == 0 && rebind) -				usb_rebind_intf(cintf);  		} +		usb_unbind_and_rebind_marked_interfaces(udev);  	}  	usb_autosuspend_device(udev); @@ -5366,56 +5605,26 @@ struct usb_device *usb_hub_find_child(struct usb_device *hdev,  }  EXPORT_SYMBOL_GPL(usb_hub_find_child); -/** - * usb_set_hub_port_connect_type - set hub port connect type. - * @hdev: USB device belonging to the usb hub - * @port1: port num of the port - * @type: connect type of the port - */ -void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1, -	enum usb_port_connect_type type) -{ -	struct usb_hub *hub = usb_hub_to_struct_hub(hdev); - -	if (hub) -		hub->ports[port1 - 1]->connect_type = type; -} - -/** - * usb_get_hub_port_connect_type - Get the port's connect type - * @hdev: USB device belonging to the usb hub - * @port1: port num of the port - * - * Return: The connect type of the port if successful. Or - * USB_PORT_CONNECT_TYPE_UNKNOWN if input params are invalid. - */ -enum usb_port_connect_type -usb_get_hub_port_connect_type(struct usb_device *hdev, int port1) -{ -	struct usb_hub *hub = usb_hub_to_struct_hub(hdev); - -	if (!hub) -		return USB_PORT_CONNECT_TYPE_UNKNOWN; - -	return hub->ports[port1 - 1]->connect_type; -} -  void usb_hub_adjust_deviceremovable(struct usb_device *hdev,  		struct usb_hub_descriptor *desc)  { +	struct usb_hub *hub = usb_hub_to_struct_hub(hdev);  	enum usb_port_connect_type connect_type;  	int i; +	if (!hub) +		return; +  	if (!hub_is_superspeed(hdev)) {  		for (i = 1; i <= hdev->maxchild; i++) { -			connect_type = usb_get_hub_port_connect_type(hdev, i); +			struct usb_port *port_dev = hub->ports[i - 1]; +			connect_type = port_dev->connect_type;  			if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {  				u8 mask = 1 << (i%8);  				if (!(desc->u.hs.DeviceRemovable[i/8] & mask)) { -					dev_dbg(&hdev->dev, "usb port%d's DeviceRemovable is changed to 1 according to platform information.\n", -						i); +					dev_dbg(&port_dev->dev, "DeviceRemovable is changed to 1 according to platform information.\n");  					desc->u.hs.DeviceRemovable[i/8]	|= mask;  				}  			} @@ -5424,14 +5633,14 @@ void usb_hub_adjust_deviceremovable(struct usb_device *hdev,  		u16 port_removable = le16_to_cpu(desc->u.ss.DeviceRemovable);  		for (i = 1; i <= hdev->maxchild; i++) { -			connect_type = usb_get_hub_port_connect_type(hdev, i); +			struct usb_port *port_dev = hub->ports[i - 1]; +			connect_type = port_dev->connect_type;  			if (connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {  				u16 mask = 1 << i;  				if (!(port_removable & mask)) { -					dev_dbg(&hdev->dev, "usb port%d's DeviceRemovable is changed to 1 according to platform information.\n", -						i); +					dev_dbg(&port_dev->dev, "DeviceRemovable is changed to 1 according to platform information.\n");  					port_removable |= mask;  				}  			} @@ -5458,6 +5667,6 @@ acpi_handle usb_get_hub_port_acpi_handle(struct usb_device *hdev,  	if (!hub)  		return NULL; -	return DEVICE_ACPI_HANDLE(&hub->ports[port1 - 1]->dev); +	return ACPI_HANDLE(&hub->ports[port1 - 1]->dev);  }  #endif diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 4e4790dea34..326308e5396 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -45,12 +45,13 @@ struct usb_hub {  	unsigned long		event_bits[1];	/* status change bitmask */  	unsigned long		change_bits[1];	/* ports with logical connect  							status change */ -	unsigned long		busy_bits[1];	/* ports being reset or -							resumed */  	unsigned long		removed_bits[1]; /* ports with a "removed"  							device present */  	unsigned long		wakeup_bits[1];	/* ports that have signaled  							remote wakeup */ +	unsigned long		power_bits[1]; /* ports that are powered */ +	unsigned long		child_usage_bits[1]; /* ports powered on for +							children */  #if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */  #error event_bits[] is too short!  #endif @@ -66,6 +67,7 @@ struct usb_hub {  	unsigned		limited_power:1;  	unsigned		quiescing:1;  	unsigned		disconnected:1; +	unsigned		in_reset:1;  	unsigned		quirk_check_port_auto_suspend:1; @@ -78,22 +80,28 @@ struct usb_hub {  /**   * struct usb port - kernel's representation of a usb port - * @child: usb device attatched to the port + * @child: usb device attached to the port   * @dev: generic device interface   * @port_owner: port's owner + * @peer: related usb2 and usb3 ports (share the same connector) + * @req: default pm qos request for hubs without port power control   * @connect_type: port's connect type + * @location: opaque representation of platform connector location + * @status_lock: synchronize port_event() vs usb_port_{suspend|resume}   * @portnum: port index num based one - * @power_is_on: port's power state - * @did_runtime_put: port has done pm_runtime_put(). + * @is_superspeed cache super-speed status   */  struct usb_port {  	struct usb_device *child;  	struct device dev; -	struct dev_state *port_owner; +	struct usb_dev_state *port_owner; +	struct usb_port *peer; +	struct dev_pm_qos_request *req;  	enum usb_port_connect_type connect_type; +	usb_port_location_t location; +	struct mutex status_lock;  	u8 portnum; -	unsigned power_is_on:1; -	unsigned did_runtime_put:1; +	unsigned int is_superspeed:1;  };  #define to_usb_port(_dev) \ @@ -111,6 +119,29 @@ extern int hub_port_debounce(struct usb_hub *hub, int port1,  extern int usb_clear_port_feature(struct usb_device *hdev,  		int port1, int feature); +static inline bool hub_is_port_power_switchable(struct usb_hub *hub) +{ +	__le16 hcs; + +	if (!hub) +		return false; +	hcs = hub->descriptor->wHubCharacteristics; +	return (le16_to_cpu(hcs) & HUB_CHAR_LPSM) < HUB_CHAR_NO_LPSM; +} + +static inline int hub_is_superspeed(struct usb_device *hdev) +{ +	return hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS; +} + +static inline unsigned hub_power_on_good_delay(struct usb_hub *hub) +{ +	unsigned delay = hub->descriptor->bPwrOn2PwrGood * 2; + +	/* Wait at least 100 msec for power to become stable */ +	return max(delay, 100U); +} +  static inline int hub_port_debounce_be_connected(struct usb_hub *hub,  		int port1)  { diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 82927e1ed27..0c8a7fc4dad 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -6,7 +6,6 @@  #include <linux/usb.h>  #include <linux/module.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/mm.h>  #include <linux/timer.h>  #include <linux/ctype.h> @@ -179,7 +178,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg);   *   * Return:   * If successful, 0. Otherwise a negative error number. The number of actual - * bytes transferred will be stored in the @actual_length paramater. + * bytes transferred will be stored in the @actual_length parameter.   */  int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,  		      void *data, int len, int *actual_length, int timeout) @@ -218,7 +217,7 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg);   *   * Return:   * If successful, 0. Otherwise a negative error number. The number of actual - * bytes transferred will be stored in the @actual_length paramater. + * bytes transferred will be stored in the @actual_length parameter.   *   */  int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, @@ -518,7 +517,7 @@ void usb_sg_wait(struct usb_sg_request *io)  		io->urbs[i]->dev = io->dev;  		retval = usb_submit_urb(io->urbs[i], GFP_ATOMIC); -		/* after we submit, let completions or cancelations fire; +		/* after we submit, let completions or cancellations fire;  		 * we handshake using io->status.  		 */  		spin_unlock_irq(&io->lock); @@ -1182,8 +1181,12 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)  			put_device(&dev->actconfig->interface[i]->dev);  			dev->actconfig->interface[i] = NULL;  		} + +		if (dev->usb2_hw_lpm_enabled == 1) +			usb_set_usb2_hardware_lpm(dev, 0);  		usb_unlocked_disable_lpm(dev);  		usb_disable_ltm(dev); +  		dev->actconfig = NULL;  		if (dev->state == USB_STATE_CONFIGURED)  			usb_set_device_state(dev, USB_STATE_ADDRESS); @@ -1290,8 +1293,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)  	struct usb_interface *iface;  	struct usb_host_interface *alt;  	struct usb_hcd *hcd = bus_to_hcd(dev->bus); -	int ret; -	int manual = 0; +	int i, ret, manual = 0;  	unsigned int epaddr;  	unsigned int pipe; @@ -1326,6 +1328,10 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)  		mutex_unlock(hcd->bandwidth_mutex);  		return -ENOMEM;  	} +	/* Changing alt-setting also frees any allocated streams */ +	for (i = 0; i < iface->cur_altsetting->desc.bNumEndpoints; i++) +		iface->cur_altsetting->endpoint[i].streams = 0; +  	ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt);  	if (ret < 0) {  		dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n", @@ -1917,6 +1923,7 @@ free_interfaces:  	usb_autosuspend_device(dev);  	return 0;  } +EXPORT_SYMBOL_GPL(usb_set_configuration);  static LIST_HEAD(set_config_list);  static DEFINE_SPINLOCK(set_config_lock); diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 51542f85239..fe1b6d0967e 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -21,6 +21,8 @@  #include "hub.h" +static int usb_port_block_power_off; +  static const struct attribute_group *port_dev_group[];  static ssize_t connect_type_show(struct device *dev, @@ -66,6 +68,7 @@ static void usb_port_device_release(struct device *dev)  {  	struct usb_port *port_dev = to_usb_port(dev); +	kfree(port_dev->req);  	kfree(port_dev);  } @@ -76,17 +79,29 @@ static int usb_port_runtime_resume(struct device *dev)  	struct usb_device *hdev = to_usb_device(dev->parent->parent);  	struct usb_interface *intf = to_usb_interface(dev->parent);  	struct usb_hub *hub = usb_hub_to_struct_hub(hdev); +	struct usb_device *udev = port_dev->child; +	struct usb_port *peer = port_dev->peer;  	int port1 = port_dev->portnum;  	int retval;  	if (!hub)  		return -EINVAL; +	if (hub->in_reset) { +		set_bit(port1, hub->power_bits); +		return 0; +	} -	usb_autopm_get_interface(intf); -	set_bit(port1, hub->busy_bits); +	/* +	 * Power on our usb3 peer before this usb2 port to prevent a usb3 +	 * device from degrading to its usb2 connection +	 */ +	if (!port_dev->is_superspeed && peer) +		pm_runtime_get_sync(&peer->dev); +	usb_autopm_get_interface(intf);  	retval = usb_hub_set_port_power(hdev, hub, port1, true); -	if (port_dev->child && !retval) { +	msleep(hub_power_on_good_delay(hub)); +	if (udev && !retval) {  		/*  		 * Attempt to wait for usb hub port to be reconnected in order  		 * to make the resume procedure successful.  The device may have @@ -97,12 +112,17 @@ static int usb_port_runtime_resume(struct device *dev)  		if (retval < 0)  			dev_dbg(&port_dev->dev, "can't get reconnection after setting port  power on, status %d\n",  					retval); -		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);  		retval = 0; + +		/* Force the child awake to revalidate after the power loss. */ +		if (!test_and_set_bit(port1, hub->child_usage_bits)) { +			pm_runtime_get_noresume(&port_dev->dev); +			pm_request_resume(&udev->dev); +		}  	} -	clear_bit(port1, hub->busy_bits);  	usb_autopm_put_interface(intf); +  	return retval;  } @@ -112,23 +132,37 @@ static int usb_port_runtime_suspend(struct device *dev)  	struct usb_device *hdev = to_usb_device(dev->parent->parent);  	struct usb_interface *intf = to_usb_interface(dev->parent);  	struct usb_hub *hub = usb_hub_to_struct_hub(hdev); +	struct usb_port *peer = port_dev->peer;  	int port1 = port_dev->portnum;  	int retval;  	if (!hub)  		return -EINVAL; +	if (hub->in_reset) +		return -EBUSY;  	if (dev_pm_qos_flags(&port_dev->dev, PM_QOS_FLAG_NO_POWER_OFF)  			== PM_QOS_FLAGS_ALL)  		return -EAGAIN; +	if (usb_port_block_power_off) +		return -EBUSY; +  	usb_autopm_get_interface(intf); -	set_bit(port1, hub->busy_bits);  	retval = usb_hub_set_port_power(hdev, hub, port1, false);  	usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); -	usb_clear_port_feature(hdev, port1,	USB_PORT_FEAT_C_ENABLE); -	clear_bit(port1, hub->busy_bits); +	if (!port_dev->is_superspeed) +		usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_ENABLE);  	usb_autopm_put_interface(intf); + +	/* +	 * Our peer usb3 port may now be able to suspend, so +	 * asynchronously queue a suspend request to observe that this +	 * usb2 port is now off. +	 */ +	if (!port_dev->is_superspeed && peer) +		pm_runtime_put(&peer->dev); +  	return retval;  }  #endif @@ -146,51 +180,305 @@ struct device_type usb_port_device_type = {  	.pm =		&usb_port_pm_ops,  }; +static struct device_driver usb_port_driver = { +	.name = "usb", +	.owner = THIS_MODULE, +}; + +static int link_peers(struct usb_port *left, struct usb_port *right) +{ +	struct usb_port *ss_port, *hs_port; +	int rc; + +	if (left->peer == right && right->peer == left) +		return 0; + +	if (left->peer || right->peer) { +		struct usb_port *lpeer = left->peer; +		struct usb_port *rpeer = right->peer; +		char *method; + +		if (left->location && left->location == right->location) +			method = "location"; +		else +			method = "default"; + +		pr_warn("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n", +			dev_name(&left->dev), dev_name(&right->dev), method, +			dev_name(&left->dev), +			lpeer ? dev_name(&lpeer->dev) : "none", +			dev_name(&right->dev), +			rpeer ? dev_name(&rpeer->dev) : "none"); +		return -EBUSY; +	} + +	rc = sysfs_create_link(&left->dev.kobj, &right->dev.kobj, "peer"); +	if (rc) +		return rc; +	rc = sysfs_create_link(&right->dev.kobj, &left->dev.kobj, "peer"); +	if (rc) { +		sysfs_remove_link(&left->dev.kobj, "peer"); +		return rc; +	} + +	/* +	 * We need to wake the HiSpeed port to make sure we don't race +	 * setting ->peer with usb_port_runtime_suspend().  Otherwise we +	 * may miss a suspend event for the SuperSpeed port. +	 */ +	if (left->is_superspeed) { +		ss_port = left; +		WARN_ON(right->is_superspeed); +		hs_port = right; +	} else { +		ss_port = right; +		WARN_ON(!right->is_superspeed); +		hs_port = left; +	} +	pm_runtime_get_sync(&hs_port->dev); + +	left->peer = right; +	right->peer = left; + +	/* +	 * The SuperSpeed reference is dropped when the HiSpeed port in +	 * this relationship suspends, i.e. when it is safe to allow a +	 * SuperSpeed connection to drop since there is no risk of a +	 * device degrading to its powered-off HiSpeed connection. +	 * +	 * Also, drop the HiSpeed ref taken above. +	 */ +	pm_runtime_get_sync(&ss_port->dev); +	pm_runtime_put(&hs_port->dev); + +	return 0; +} + +static void link_peers_report(struct usb_port *left, struct usb_port *right) +{ +	int rc; + +	rc = link_peers(left, right); +	if (rc == 0) { +		dev_dbg(&left->dev, "peered to %s\n", dev_name(&right->dev)); +	} else { +		dev_warn(&left->dev, "failed to peer to %s (%d)\n", +				dev_name(&right->dev), rc); +		pr_warn_once("usb: port power management may be unreliable\n"); +		usb_port_block_power_off = 1; +	} +} + +static void unlink_peers(struct usb_port *left, struct usb_port *right) +{ +	struct usb_port *ss_port, *hs_port; + +	WARN(right->peer != left || left->peer != right, +			"%s and %s are not peers?\n", +			dev_name(&left->dev), dev_name(&right->dev)); + +	/* +	 * We wake the HiSpeed port to make sure we don't race its +	 * usb_port_runtime_resume() event which takes a SuperSpeed ref +	 * when ->peer is !NULL. +	 */ +	if (left->is_superspeed) { +		ss_port = left; +		hs_port = right; +	} else { +		ss_port = right; +		hs_port = left; +	} + +	pm_runtime_get_sync(&hs_port->dev); + +	sysfs_remove_link(&left->dev.kobj, "peer"); +	right->peer = NULL; +	sysfs_remove_link(&right->dev.kobj, "peer"); +	left->peer = NULL; + +	/* Drop the SuperSpeed ref held on behalf of the active HiSpeed port */ +	pm_runtime_put(&ss_port->dev); + +	/* Drop the ref taken above */ +	pm_runtime_put(&hs_port->dev); +} + +/* + * For each usb hub device in the system check to see if it is in the + * peer domain of the given port_dev, and if it is check to see if it + * has a port that matches the given port by location + */ +static int match_location(struct usb_device *peer_hdev, void *p) +{ +	int port1; +	struct usb_hcd *hcd, *peer_hcd; +	struct usb_port *port_dev = p, *peer; +	struct usb_hub *peer_hub = usb_hub_to_struct_hub(peer_hdev); +	struct usb_device *hdev = to_usb_device(port_dev->dev.parent->parent); + +	if (!peer_hub) +		return 0; + +	hcd = bus_to_hcd(hdev->bus); +	peer_hcd = bus_to_hcd(peer_hdev->bus); +	/* peer_hcd is provisional until we verify it against the known peer */ +	if (peer_hcd != hcd->shared_hcd) +		return 0; + +	for (port1 = 1; port1 <= peer_hdev->maxchild; port1++) { +		peer = peer_hub->ports[port1 - 1]; +		if (peer && peer->location == port_dev->location) { +			link_peers_report(port_dev, peer); +			return 1; /* done */ +		} +	} + +	return 0; +} + +/* + * Find the peer port either via explicit platform firmware "location" + * data, the peer hcd for root hubs, or the upstream peer relationship + * for all other hubs. + */ +static void find_and_link_peer(struct usb_hub *hub, int port1) +{ +	struct usb_port *port_dev = hub->ports[port1 - 1], *peer; +	struct usb_device *hdev = hub->hdev; +	struct usb_device *peer_hdev; +	struct usb_hub *peer_hub; + +	/* +	 * If location data is available then we can only peer this port +	 * by a location match, not the default peer (lest we create a +	 * situation where we need to go back and undo a default peering +	 * when the port is later peered by location data) +	 */ +	if (port_dev->location) { +		/* we link the peer in match_location() if found */ +		usb_for_each_dev(port_dev, match_location); +		return; +	} else if (!hdev->parent) { +		struct usb_hcd *hcd = bus_to_hcd(hdev->bus); +		struct usb_hcd *peer_hcd = hcd->shared_hcd; + +		if (!peer_hcd) +			return; + +		peer_hdev = peer_hcd->self.root_hub; +	} else { +		struct usb_port *upstream; +		struct usb_device *parent = hdev->parent; +		struct usb_hub *parent_hub = usb_hub_to_struct_hub(parent); + +		if (!parent_hub) +			return; + +		upstream = parent_hub->ports[hdev->portnum - 1]; +		if (!upstream || !upstream->peer) +			return; + +		peer_hdev = upstream->peer->child; +	} + +	peer_hub = usb_hub_to_struct_hub(peer_hdev); +	if (!peer_hub || port1 > peer_hdev->maxchild) +		return; + +	/* +	 * we found a valid default peer, last check is to make sure it +	 * does not have location data +	 */ +	peer = peer_hub->ports[port1 - 1]; +	if (peer && peer->location == 0) +		link_peers_report(port_dev, peer); +} +  int usb_hub_create_port_device(struct usb_hub *hub, int port1)  { -	struct usb_port *port_dev = NULL; +	struct usb_port *port_dev;  	int retval;  	port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); -	if (!port_dev) { -		retval = -ENOMEM; -		goto exit; +	if (!port_dev) +		return -ENOMEM; + +	port_dev->req = kzalloc(sizeof(*(port_dev->req)), GFP_KERNEL); +	if (!port_dev->req) { +		kfree(port_dev); +		return -ENOMEM;  	}  	hub->ports[port1 - 1] = port_dev;  	port_dev->portnum = port1; -	port_dev->power_is_on = true; +	set_bit(port1, hub->power_bits);  	port_dev->dev.parent = hub->intfdev;  	port_dev->dev.groups = port_dev_group;  	port_dev->dev.type = &usb_port_device_type; -	dev_set_name(&port_dev->dev, "port%d", port1); - +	port_dev->dev.driver = &usb_port_driver; +	if (hub_is_superspeed(hub->hdev)) +		port_dev->is_superspeed = 1; +	dev_set_name(&port_dev->dev, "%s-port%d", dev_name(&hub->hdev->dev), +			port1); +	mutex_init(&port_dev->status_lock);  	retval = device_register(&port_dev->dev); -	if (retval) -		goto error_register; +	if (retval) { +		put_device(&port_dev->dev); +		return retval; +	} + +	/* Set default policy of port-poweroff disabled. */ +	retval = dev_pm_qos_add_request(&port_dev->dev, port_dev->req, +			DEV_PM_QOS_FLAGS, PM_QOS_FLAG_NO_POWER_OFF); +	if (retval < 0) { +		device_unregister(&port_dev->dev); +		return retval; +	} + +	find_and_link_peer(hub, port1); +	/* +	 * Enable runtime pm and hold a refernce that hub_configure() +	 * will drop once the PM_QOS_NO_POWER_OFF flag state has been set +	 * and the hub has been fully registered (hdev->maxchild set). +	 */  	pm_runtime_set_active(&port_dev->dev); +	pm_runtime_get_noresume(&port_dev->dev); +	pm_runtime_enable(&port_dev->dev); +	device_enable_async_suspend(&port_dev->dev); -	/* It would be dangerous if user space couldn't -	 * prevent usb device from being powered off. So don't -	 * enable port runtime pm if failed to expose port's pm qos. +	/* +	 * Keep hidden the ability to enable port-poweroff if the hub +	 * does not support power switching.  	 */ -	if (!dev_pm_qos_expose_flags(&port_dev->dev, -			PM_QOS_FLAG_NO_POWER_OFF)) -		pm_runtime_enable(&port_dev->dev); +	if (!hub_is_port_power_switchable(hub)) +		return 0; + +	/* Attempt to let userspace take over the policy. */ +	retval = dev_pm_qos_expose_flags(&port_dev->dev, +			PM_QOS_FLAG_NO_POWER_OFF); +	if (retval < 0) { +		dev_warn(&port_dev->dev, "failed to expose pm_qos_no_poweroff\n"); +		return 0; +	} -	device_enable_async_suspend(&port_dev->dev); +	/* Userspace owns the policy, drop the kernel 'no_poweroff' request. */ +	retval = dev_pm_qos_remove_request(port_dev->req); +	if (retval >= 0) { +		kfree(port_dev->req); +		port_dev->req = NULL; +	}  	return 0; - -error_register: -	put_device(&port_dev->dev); -exit: -	return retval;  } -void usb_hub_remove_port_device(struct usb_hub *hub, -				       int port1) +void usb_hub_remove_port_device(struct usb_hub *hub, int port1)  { -	device_unregister(&hub->ports[port1 - 1]->dev); -} +	struct usb_port *port_dev = hub->ports[port1 - 1]; +	struct usb_port *peer; +	peer = port_dev->peer; +	if (peer) +		unlink_peers(port_dev, peer); +	device_unregister(&port_dev->dev); +} diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 5b44cd47da5..739ee8e8bdf 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -13,6 +13,7 @@  #include <linux/usb.h>  #include <linux/usb/quirks.h> +#include <linux/usb/hcd.h>  #include "usb.h"  /* Lists of quirky USB devices, split in device quirks and interface quirks. @@ -46,6 +47,10 @@ static const struct usb_device_id usb_quirk_list[] = {  	/* Microsoft LifeCam-VX700 v2.0 */  	{ USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, +	/* Logitech HD Pro Webcams C920 and C930e */ +	{ USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT }, +	{ USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT }, +  	/* Logitech Quickcam Fusion */  	{ USB_DEVICE(0x046d, 0x08c1), .driver_info = USB_QUIRK_RESET_RESUME }, @@ -130,6 +135,9 @@ static const struct usb_device_id usb_quirk_list[] = {  	/* Broadcom BCM92035DGROM BT dongle */  	{ USB_DEVICE(0x0a5c, 0x2021), .driver_info = USB_QUIRK_RESET_RESUME }, +	/* MAYA44USB sound device */ +	{ USB_DEVICE(0x0a92, 0x0091), .driver_info = USB_QUIRK_RESET_RESUME }, +  	/* Action Semiconductor flash disk */  	{ USB_DEVICE(0x10d6, 0x2200), .driver_info =  			USB_QUIRK_STRING_FETCH_255 }, @@ -155,6 +163,21 @@ static const struct usb_device_id usb_interface_quirk_list[] = {  	{ }  /* terminating entry must be last */  }; +static const struct usb_device_id usb_amd_resume_quirk_list[] = { +	/* Lenovo Mouse with Pixart controller */ +	{ USB_DEVICE(0x17ef, 0x602e), .driver_info = USB_QUIRK_RESET_RESUME }, + +	/* Pixart Mouse */ +	{ USB_DEVICE(0x093a, 0x2500), .driver_info = USB_QUIRK_RESET_RESUME }, +	{ USB_DEVICE(0x093a, 0x2510), .driver_info = USB_QUIRK_RESET_RESUME }, +	{ USB_DEVICE(0x093a, 0x2521), .driver_info = USB_QUIRK_RESET_RESUME }, + +	/* Logitech Optical Mouse M90/M100 */ +	{ USB_DEVICE(0x046d, 0xc05a), .driver_info = USB_QUIRK_RESET_RESUME }, + +	{ }  /* terminating entry must be last */ +}; +  static bool usb_match_any_interface(struct usb_device *udev,  				    const struct usb_device_id *id)  { @@ -181,6 +204,18 @@ static bool usb_match_any_interface(struct usb_device *udev,  	return false;  } +static int usb_amd_resume_quirk(struct usb_device *udev) +{ +	struct usb_hcd *hcd; + +	hcd = bus_to_hcd(udev->bus); +	/* The device should be attached directly to root hub */ +	if (udev->level == 1 && hcd->amd_resume_bug == 1) +		return 1; + +	return 0; +} +  static u32 __usb_detect_quirks(struct usb_device *udev,  			       const struct usb_device_id *id)  { @@ -206,6 +241,15 @@ static u32 __usb_detect_quirks(struct usb_device *udev,  void usb_detect_quirks(struct usb_device *udev)  {  	udev->quirks = __usb_detect_quirks(udev, usb_quirk_list); + +	/* +	 * Pixart-based mice would trigger remote wakeup issue on AMD +	 * Yangtze chipset, so set them as RESET_RESUME flag. +	 */ +	if (usb_amd_resume_quirk(udev)) +		udev->quirks |= __usb_detect_quirks(udev, +				usb_amd_resume_quirk_list); +  	if (udev->quirks)  		dev_dbg(&udev->dev, "USB quirks for this device: %x\n",  			udev->quirks); diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 6d2c8edb1ff..1236c6011c7 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -23,14 +23,16 @@ static ssize_t field##_show(struct device *dev,				\  {									\  	struct usb_device *udev;					\  	struct usb_host_config *actconfig;				\ +	ssize_t rc = 0;							\  									\  	udev = to_usb_device(dev);					\ +	usb_lock_device(udev);						\  	actconfig = udev->actconfig;					\  	if (actconfig)							\ -		return sprintf(buf, format_string,			\ +		rc = sprintf(buf, format_string,			\  				actconfig->desc.field);			\ -	else								\ -		return 0;						\ +	usb_unlock_device(udev);					\ +	return rc;							\  }									\  #define usb_actconfig_attr(field, format_string)		\ @@ -45,12 +47,15 @@ static ssize_t bMaxPower_show(struct device *dev,  {  	struct usb_device *udev;  	struct usb_host_config *actconfig; +	ssize_t rc = 0;  	udev = to_usb_device(dev); +	usb_lock_device(udev);  	actconfig = udev->actconfig; -	if (!actconfig) -		return 0; -	return sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); +	if (actconfig) +		rc = sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); +	usb_unlock_device(udev); +	return rc;  }  static DEVICE_ATTR_RO(bMaxPower); @@ -59,12 +64,15 @@ static ssize_t configuration_show(struct device *dev,  {  	struct usb_device *udev;  	struct usb_host_config *actconfig; +	ssize_t rc = 0;  	udev = to_usb_device(dev); +	usb_lock_device(udev);  	actconfig = udev->actconfig; -	if ((!actconfig) || (!actconfig->string)) -		return 0; -	return sprintf(buf, "%s\n", actconfig->string); +	if (actconfig && actconfig->string) +		rc = sprintf(buf, "%s\n", actconfig->string); +	usb_unlock_device(udev); +	return rc;  }  static DEVICE_ATTR_RO(configuration); @@ -390,7 +398,8 @@ static DEVICE_ATTR_RW(autosuspend);  static const char on_string[] = "on";  static const char auto_string[] = "auto"; -static void warn_level(void) { +static void warn_level(void) +{  	static int level_warned;  	if (!level_warned) { @@ -449,7 +458,7 @@ static ssize_t usb2_hardware_lpm_show(struct device *dev,  	struct usb_device *udev = to_usb_device(dev);  	const char *p; -	if (udev->usb2_hw_lpm_enabled == 1) +	if (udev->usb2_hw_lpm_allowed == 1)  		p = "enabled";  	else  		p = "disabled"; @@ -469,8 +478,10 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev,  	ret = strtobool(buf, &value); -	if (!ret) +	if (!ret) { +		udev->usb2_hw_lpm_allowed = value;  		ret = usb_set_usb2_hardware_lpm(udev, value); +	}  	usb_unlock_device(udev); @@ -644,7 +655,7 @@ static ssize_t authorized_store(struct device *dev,  		result = usb_deauthorize_device(usb_dev);  	else  		result = usb_authorize_device(usb_dev); -	return result < 0? result : size; +	return result < 0 ? result : size;  }  static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, S_IRUGO | S_IWUSR,  				  authorized_show, authorized_store); @@ -764,6 +775,7 @@ read_descriptors(struct file *filp, struct kobject *kobj,  	 * Following that are the raw descriptor entries for all the  	 * configurations (config plus subsidiary descriptors).  	 */ +	usb_lock_device(udev);  	for (cfgno = -1; cfgno < udev->descriptor.bNumConfigurations &&  			nleft > 0; ++cfgno) {  		if (cfgno < 0) { @@ -784,6 +796,7 @@ read_descriptors(struct file *filp, struct kobject *kobj,  			off -= srclen;  		}  	} +	usb_unlock_device(udev);  	return count - nleft;  } @@ -824,7 +837,7 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)  	device_remove_bin_file(dev, &dev_bin_attr_descriptors);  } -/* Interface Accociation Descriptor fields */ +/* Interface Association Descriptor fields */  #define usb_intf_assoc_attr(field, format_string)			\  static ssize_t								\  iad_##field##_show(struct device *dev, struct device_attribute *attr,	\ @@ -870,9 +883,7 @@ static ssize_t interface_show(struct device *dev, struct device_attribute *attr,  	char *string;  	intf = to_usb_interface(dev); -	string = intf->cur_altsetting->string; -	barrier();		/* The altsetting might change! */ - +	string = ACCESS_ONCE(intf->cur_altsetting->string);  	if (!string)  		return 0;  	return sprintf(buf, "%s\n", string); @@ -888,7 +899,7 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,  	intf = to_usb_interface(dev);  	udev = interface_to_usbdev(intf); -	alt = intf->cur_altsetting; +	alt = ACCESS_ONCE(intf->cur_altsetting);  	return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"  			"ic%02Xisc%02Xip%02Xin%02X\n", @@ -909,23 +920,14 @@ static ssize_t supports_autosuspend_show(struct device *dev,  					 struct device_attribute *attr,  					 char *buf)  { -	struct usb_interface *intf; -	struct usb_device *udev; -	int ret; +	int s; -	intf = to_usb_interface(dev); -	udev = interface_to_usbdev(intf); - -	usb_lock_device(udev); +	device_lock(dev);  	/* Devices will be autosuspended even when an interface isn't claimed */ -	if (!intf->dev.driver || -			to_usb_driver(intf->dev.driver)->supports_autosuspend) -		ret = sprintf(buf, "%u\n", 1); -	else -		ret = sprintf(buf, "%u\n", 0); -	usb_unlock_device(udev); +	s = (!dev->driver || to_usb_driver(dev->driver)->supports_autosuspend); +	device_unlock(dev); -	return ret; +	return sprintf(buf, "%u\n", s);  }  static DEVICE_ATTR_RO(supports_autosuspend); diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index c12bc790a6a..991386ceb4e 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -2,7 +2,6 @@  #include <linux/string.h>  #include <linux/bitops.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/log2.h>  #include <linux/usb.h>  #include <linux/wait.h> @@ -53,7 +52,7 @@ EXPORT_SYMBOL_GPL(usb_init_urb);   *	valid options for this.   *   * Creates an urb for the USB driver to use, initializes a few internal - * structures, incrementes the usage counter, and returns a pointer to it. + * structures, increments the usage counter, and returns a pointer to it.   *   * If the driver want to use this urb for interrupt, control, or bulk   * endpoints, pass '0' as the number of iso packets. @@ -138,13 +137,19 @@ void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)  }  EXPORT_SYMBOL_GPL(usb_anchor_urb); +static int usb_anchor_check_wakeup(struct usb_anchor *anchor) +{ +	return atomic_read(&anchor->suspend_wakeups) == 0 && +		list_empty(&anchor->urb_list); +} +  /* Callers must hold anchor->lock */  static void __usb_unanchor_urb(struct urb *urb, struct usb_anchor *anchor)  {  	urb->anchor = NULL;  	list_del(&urb->anchor_list);  	usb_put_urb(urb); -	if (list_empty(&anchor->urb_list)) +	if (usb_anchor_check_wakeup(anchor))  		wake_up(&anchor->wait);  } @@ -275,7 +280,7 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);   *   * Device drivers must explicitly request that repetition, by ensuring that   * some URB is always on the endpoint's queue (except possibly for short - * periods during completion callacks).  When there is no longer an urb + * periods during completion callbacks).  When there is no longer an urb   * queued, the endpoint's bandwidth reservation is canceled.  This means   * drivers can use their completion handlers to ensure they keep bandwidth   * they need, by reinitializing and resubmitting the just-completed urb @@ -319,10 +324,14 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);   */  int usb_submit_urb(struct urb *urb, gfp_t mem_flags)  { +	static int			pipetypes[4] = { +		PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT +	};  	int				xfertype, max;  	struct usb_device		*dev;  	struct usb_host_endpoint	*ep;  	int				is_out; +	unsigned int			allowed;  	if (!urb || !urb->complete)  		return -EINVAL; @@ -430,15 +439,10 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)  	if (urb->transfer_buffer_length > INT_MAX)  		return -EMSGSIZE; -#ifdef DEBUG -	/* stuff that drivers shouldn't do, but which shouldn't +	/* +	 * stuff that drivers shouldn't do, but which shouldn't  	 * cause problems in HCDs if they get it wrong.  	 */ -	{ -	unsigned int	allowed; -	static int pipetypes[4] = { -		PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT -	};  	/* Check that the pipe's type matches the endpoint's type */  	if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) @@ -470,8 +474,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)  	if (allowed != urb->transfer_flags)  		dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n",  			urb->transfer_flags, allowed); -	} -#endif +  	/*  	 * Force periodic transfer intervals to be legal values that are  	 * a power of two (so HCDs don't need to). @@ -486,9 +489,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)  		/* too small? */  		switch (dev->speed) {  		case USB_SPEED_WIRELESS: -			if (urb->interval < 6) +			if ((urb->interval < 6) +				&& (xfertype == USB_ENDPOINT_XFER_INT))  				return -EINVAL; -			break;  		default:  			if (urb->interval <= 0)  				return -EINVAL; @@ -828,7 +831,7 @@ EXPORT_SYMBOL_GPL(usb_unpoison_anchored_urbs);   *   * this allows all outstanding URBs to be unlinked starting   * from the back of the queue. This function is asynchronous. - * The unlinking is just tiggered. It may happen after this + * The unlinking is just triggered. It may happen after this   * function has returned.   *   * This routine should not be called by a driver after its disconnect @@ -846,6 +849,39 @@ void usb_unlink_anchored_urbs(struct usb_anchor *anchor)  EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs);  /** + * usb_anchor_suspend_wakeups + * @anchor: the anchor you want to suspend wakeups on + * + * Call this to stop the last urb being unanchored from waking up any + * usb_wait_anchor_empty_timeout waiters. This is used in the hcd urb give- + * back path to delay waking up until after the completion handler has run. + */ +void usb_anchor_suspend_wakeups(struct usb_anchor *anchor) +{ +	if (anchor) +		atomic_inc(&anchor->suspend_wakeups); +} +EXPORT_SYMBOL_GPL(usb_anchor_suspend_wakeups); + +/** + * usb_anchor_resume_wakeups + * @anchor: the anchor you want to resume wakeups on + * + * Allow usb_wait_anchor_empty_timeout waiters to be woken up again, and + * wake up any current waiters if the anchor is empty. + */ +void usb_anchor_resume_wakeups(struct usb_anchor *anchor) +{ +	if (!anchor) +		return; + +	atomic_dec(&anchor->suspend_wakeups); +	if (usb_anchor_check_wakeup(anchor)) +		wake_up(&anchor->wait); +} +EXPORT_SYMBOL_GPL(usb_anchor_resume_wakeups); + +/**   * usb_wait_anchor_empty_timeout - wait for an anchor to be unused   * @anchor: the anchor you want to become unused   * @timeout: how long you are willing to wait in milliseconds @@ -858,7 +894,8 @@ EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs);  int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,  				  unsigned int timeout)  { -	return wait_event_timeout(anchor->wait, list_empty(&anchor->urb_list), +	return wait_event_timeout(anchor->wait, +				  usb_anchor_check_wakeup(anchor),  				  msecs_to_jiffies(timeout));  }  EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout); diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 255c14464bf..2776cfe64c0 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -16,9 +16,8 @@  #include <linux/acpi.h>  #include <linux/pci.h>  #include <linux/usb/hcd.h> -#include <acpi/acpi_bus.h> -#include "usb.h" +#include "hub.h"  /**   * usb_acpi_power_manageable - check whether usb port has @@ -56,13 +55,18 @@ EXPORT_SYMBOL_GPL(usb_acpi_power_manageable);   */  int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable)  { +	struct usb_hub *hub = usb_hub_to_struct_hub(hdev); +	struct usb_port *port_dev;  	acpi_handle port_handle;  	unsigned char state;  	int port1 = index + 1;  	int error = -EINVAL; -	port_handle = (acpi_handle)usb_get_hub_port_acpi_handle(hdev, -		port1); +	if (!hub) +		return -ENODEV; +	port_dev = hub->ports[port1 - 1]; + +	port_handle = (acpi_handle) usb_get_hub_port_acpi_handle(hdev, port1);  	if (!port_handle)  		return error; @@ -73,65 +77,61 @@ int usb_acpi_set_power_state(struct usb_device *hdev, int index, bool enable)  	error = acpi_bus_set_power(port_handle, state);  	if (!error) -		dev_dbg(&hdev->dev, "The power of hub port %d was set to %d\n", -			port1, enable); +		dev_dbg(&port_dev->dev, "acpi: power was set to %d\n", enable);  	else -		dev_dbg(&hdev->dev, "The power of hub port failed to be set\n"); +		dev_dbg(&port_dev->dev, "acpi: power failed to be set\n");  	return error;  }  EXPORT_SYMBOL_GPL(usb_acpi_set_power_state); -static int usb_acpi_check_port_connect_type(struct usb_device *hdev, -	acpi_handle handle, int port1) +static enum usb_port_connect_type usb_acpi_get_connect_type(acpi_handle handle, +		struct acpi_pld_info *pld)  { -	acpi_status status; +	enum usb_port_connect_type connect_type = USB_PORT_CONNECT_TYPE_UNKNOWN;  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };  	union acpi_object *upc; -	struct acpi_pld_info *pld; -	int ret = 0; +	acpi_status status;  	/* -	 * Accoding to ACPI Spec 9.13. PLD indicates whether usb port is +	 * According to ACPI Spec 9.13. PLD indicates whether usb port is  	 * user visible and _UPC indicates whether it is connectable. If  	 * the port was visible and connectable, it could be freely connected  	 * and disconnected with USB devices. If no visible and connectable,  	 * a usb device is directly hard-wired to the port. If no visible and  	 * no connectable, the port would be not used.  	 */ -	status = acpi_get_physical_device_location(handle, &pld); -	if (ACPI_FAILURE(status)) -		return -ENODEV; -  	status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer);  	upc = buffer.pointer;  	if (!upc || (upc->type != ACPI_TYPE_PACKAGE)  		|| upc->package.count != 4) { -		ret = -EINVAL;  		goto out;  	}  	if (upc->package.elements[0].integer.value)  		if (pld->user_visible) -			usb_set_hub_port_connect_type(hdev, port1, -				USB_PORT_CONNECT_TYPE_HOT_PLUG); +			connect_type = USB_PORT_CONNECT_TYPE_HOT_PLUG;  		else -			usb_set_hub_port_connect_type(hdev, port1, -				USB_PORT_CONNECT_TYPE_HARD_WIRED); +			connect_type = USB_PORT_CONNECT_TYPE_HARD_WIRED;  	else if (!pld->user_visible) -		usb_set_hub_port_connect_type(hdev, port1, USB_PORT_NOT_USED); - +		connect_type = USB_PORT_NOT_USED;  out: -	ACPI_FREE(pld);  	kfree(upc); -	return ret; +	return connect_type;  } -static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) + +/* + * Private to usb-acpi, all the core needs to know is that + * port_dev->location is non-zero when it has been set by the firmware. + */ +#define USB_ACPI_LOCATION_VALID (1 << 31) + +static struct acpi_device *usb_acpi_find_companion(struct device *dev)  {  	struct usb_device *udev; +	struct acpi_device *adev;  	acpi_handle *parent_handle; -	int port_num;  	/*  	 * In the ACPI DSDT table, only usb root hub and usb ports are @@ -148,38 +148,19 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)  	 */  	if (is_usb_device(dev)) {  		udev = to_usb_device(dev); -		if (udev->parent) { -			enum usb_port_connect_type type; - -			/* -			 * According usb port's connect type to set usb device's -			 * removability. -			 */ -			type = usb_get_hub_port_connect_type(udev->parent, -				udev->portnum); -			switch (type) { -			case USB_PORT_CONNECT_TYPE_HOT_PLUG: -				udev->removable = USB_DEVICE_REMOVABLE; -				break; -			case USB_PORT_CONNECT_TYPE_HARD_WIRED: -				udev->removable = USB_DEVICE_FIXED; -				break; -			default: -				udev->removable = USB_DEVICE_REMOVABLE_UNKNOWN; -				break; -			} - -			return -ENODEV; -		} +		if (udev->parent) +			return NULL; -		/* root hub's parent is the usb hcd. */ -		parent_handle = DEVICE_ACPI_HANDLE(dev->parent); -		*handle = acpi_get_child(parent_handle, udev->portnum); -		if (!*handle) -			return -ENODEV; -		return 0; +		/* root hub is only child (_ADR=0) under its parent, the HC */ +		adev = ACPI_COMPANION(dev->parent); +		return acpi_find_child_device(adev, 0, false);  	} else if (is_usb_port(dev)) { -		sscanf(dev_name(dev), "port%d", &port_num); +		struct usb_port *port_dev = to_usb_port(dev); +		int port1 = port_dev->portnum; +		struct acpi_pld_info *pld; +		acpi_handle *handle; +		acpi_status status; +  		/* Get the struct usb_device point of port's hub */  		udev = to_usb_device(dev->parent->parent); @@ -190,30 +171,39 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle)  		 */  		if (!udev->parent) {  			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; +			int raw; + +			raw = usb_hcd_find_raw_port_number(hcd, port1); +			adev = acpi_find_child_device(ACPI_COMPANION(&udev->dev), +					raw, false); +			if (!adev) +				return NULL;  		} else {  			parent_handle =  				usb_get_hub_port_acpi_handle(udev->parent,  				udev->portnum);  			if (!parent_handle) -				return -ENODEV; +				return NULL; -			*handle = acpi_get_child(parent_handle,	port_num); -			if (!*handle) -				return -ENODEV; +			acpi_bus_get_device(parent_handle, &adev); +			adev = acpi_find_child_device(adev, port1, false); +			if (!adev) +				return NULL;  		} -		usb_acpi_check_port_connect_type(udev, *handle, port_num); -	} else -		return -ENODEV; +		handle = adev->handle; +		status = acpi_get_physical_device_location(handle, &pld); +		if (ACPI_FAILURE(status) || !pld) +			return adev; + +		port_dev->location = USB_ACPI_LOCATION_VALID +			| pld->group_token << 8 | pld->group_position; +		port_dev->connect_type = usb_acpi_get_connect_type(handle, pld); +		ACPI_FREE(pld); + +		return adev; +	} -	return 0; +	return NULL;  }  static bool usb_acpi_bus_match(struct device *dev) @@ -224,7 +214,7 @@ static bool usb_acpi_bus_match(struct device *dev)  static struct acpi_bus_type usb_acpi_bus = {  	.name = "USB",  	.match = usb_acpi_bus_match, -	.find_device = usb_acpi_find_device, +	.find_companion = usb_acpi_find_companion,  };  int usb_acpi_register(void) diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 0a6ee2e70b2..4d1144990d4 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -497,7 +497,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,  		dev->authorized = 1;  	else {  		dev->authorized = usb_hcd->authorized_default; -		dev->wusb = usb_bus_is_wusb(bus)? 1 : 0; +		dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0;  	}  	return dev;  } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 823857767a1..d9d08720c38 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -2,7 +2,7 @@  #include <linux/acpi.h>  struct usb_hub_descriptor; -struct dev_state; +struct usb_dev_state;  /* Functions local to drivers/usb/core/ */ @@ -55,14 +55,10 @@ extern int usb_match_one_id_intf(struct usb_device *dev,  extern int usb_match_device(struct usb_device *dev,  			    const struct usb_device_id *id);  extern void usb_forced_unbind_intf(struct usb_interface *intf); -extern void usb_rebind_intf(struct usb_interface *intf); +extern void usb_unbind_and_rebind_marked_interfaces(struct usb_device *udev); -extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port, -		struct dev_state *owner); -extern int usb_hub_release_port(struct usb_device *hdev, unsigned port, -		struct dev_state *owner);  extern void usb_hub_release_all_ports(struct usb_device *hdev, -		struct dev_state *owner); +		struct usb_dev_state *owner);  extern bool usb_device_is_owned(struct usb_device *udev);  extern int  usb_hub_init(void); @@ -111,11 +107,6 @@ static inline int usb_autoresume_device(struct usb_device *udev)  	return 0;  } -static inline int usb_remote_wakeup(struct usb_device *udev) -{ -	return 0; -} -  static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)  {  	return 0; @@ -123,6 +114,7 @@ static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)  #endif  extern struct bus_type usb_bus_type; +extern struct mutex usb_port_peer_mutex;  extern struct device_type usb_device_type;  extern struct device_type usb_if_device_type;  extern struct device_type usb_ep_device_type; @@ -174,15 +166,17 @@ extern void usbfs_conn_disc_event(void);  extern int usb_devio_init(void);  extern void usb_devio_cleanup(void); +/* + * Firmware specific cookie identifying a port's location. '0' == no location + * data available + */ +typedef u32 usb_port_location_t; +  /* internal notify stuff */  extern void usb_notify_add_device(struct usb_device *udev);  extern void usb_notify_remove_device(struct usb_device *udev);  extern void usb_notify_add_bus(struct usb_bus *ubus);  extern void usb_notify_remove_bus(struct usb_bus *ubus); -extern enum usb_port_connect_type -	usb_get_hub_port_connect_type(struct usb_device *hdev, int port1); -extern void usb_set_hub_port_connect_type(struct usb_device *hdev, int port1, -	enum usb_port_connect_type type);  extern void usb_hub_adjust_deviceremovable(struct usb_device *hdev,  		struct usb_hub_descriptor *desc); diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig new file mode 100644 index 00000000000..f93807b3631 --- /dev/null +++ b/drivers/usb/dwc2/Kconfig @@ -0,0 +1,86 @@ +config USB_DWC2 +	bool "DesignWare USB2 DRD Core Support" +	depends on USB +	help +	  Say Y here if your system has a Dual Role Hi-Speed USB +	  controller based on the DesignWare HSOTG IP Core. + +	  For host mode, if you choose to build the driver as dynamically +	  linked modules, the core module will be called dwc2.ko, the PCI +	  bus interface module (if you have a PCI bus system) will be +	  called dwc2_pci.ko, and the platform interface module (for +	  controllers directly connected to the CPU) will be called +	  dwc2_platform.ko. For gadget mode, there will be a single +	  module called dwc2_gadget.ko. + +	  NOTE: The s3c-hsotg driver is now renamed to dwc2_gadget. The +	  host and gadget drivers are still currently separate drivers. +	  There are plans to merge the dwc2_gadget driver with the dwc2 +	  host driver in the near future to create a dual-role driver. + +if USB_DWC2 + +config USB_DWC2_HOST +	tristate "Host only mode" +	depends on USB +	help +	  The Designware USB2.0 high-speed host controller +	  integrated into many SoCs. + +config USB_DWC2_PLATFORM +	bool "DWC2 Platform" +	depends on USB_DWC2_HOST +	default USB_DWC2_HOST +	help +	  The Designware USB2.0 platform interface module for +	  controllers directly connected to the CPU. This is only +	  used for host mode. + +config USB_DWC2_PCI +	bool "DWC2 PCI" +	depends on USB_DWC2_HOST && PCI +	default USB_DWC2_HOST +	help +	  The Designware USB2.0 PCI interface module for controllers +	  connected to a PCI bus. This is only used for host mode. + +comment "Gadget mode requires USB Gadget support to be enabled" + +config USB_DWC2_PERIPHERAL +	tristate "Gadget only mode" +	depends on USB_GADGET +	help +	  The Designware USB2.0 high-speed gadget controller +	  integrated into many SoCs. + +config USB_DWC2_DEBUG +	bool "Enable Debugging Messages" +	help +	  Say Y here to enable debugging messages in the DWC2 Driver. + +config USB_DWC2_VERBOSE +	bool "Enable Verbose Debugging Messages" +	depends on USB_DWC2_DEBUG +	help +	  Say Y here to enable verbose debugging messages in the DWC2 Driver. +	  WARNING: Enabling this will quickly fill your message log. +	  If in doubt, say N. + +config USB_DWC2_TRACK_MISSED_SOFS +	bool "Enable Missed SOF Tracking" +	help +	  Say Y here to enable logging of missed SOF events to the dmesg log. +	  WARNING: This feature is still experimental. +	  If in doubt, say N. + +config USB_DWC2_DEBUG_PERIODIC +	bool "Enable Debugging Messages For Periodic Transfers" +	depends on USB_DWC2_DEBUG || USB_DWC2_VERBOSE +	default y +	help +	  Say N here to disable (verbose) debugging messages to be +	  logged for periodic transfers. This allows better debugging of +	  non-periodic transfers, but of course the debug logs will be +	  incomplete. Note that this also disables some debug messages +	  for which the transfer type cannot be deduced. +endif diff --git a/drivers/usb/dwc2/Makefile b/drivers/usb/dwc2/Makefile new file mode 100644 index 00000000000..b73d2a52797 --- /dev/null +++ b/drivers/usb/dwc2/Makefile @@ -0,0 +1,28 @@ +ccflags-$(CONFIG_USB_DWC2_DEBUG)	+= -DDEBUG +ccflags-$(CONFIG_USB_DWC2_VERBOSE)	+= -DVERBOSE_DEBUG + +obj-$(CONFIG_USB_DWC2_HOST)		+= dwc2.o +dwc2-y					:= core.o core_intr.o +dwc2-y					+= hcd.o hcd_intr.o +dwc2-y					+= hcd_queue.o hcd_ddma.o + +# NOTE: The previous s3c-hsotg peripheral mode only driver has been moved to +# this location and renamed gadget.c. When building for dynamically linked +# modules, dwc2_gadget.ko will get built for peripheral mode. For host mode, +# the core module will be dwc2.ko, the PCI bus interface module will called +# dwc2_pci.ko and the platform interface module will be called dwc2_platform.ko. +# At present the host and gadget driver will be separate drivers, but there +# are plans in the near future to create a dual-role driver. + +ifneq ($(CONFIG_USB_DWC2_PCI),) +	obj-$(CONFIG_USB_DWC2_HOST)	+= dwc2_pci.o +	dwc2_pci-y			:= pci.o +endif + +ifneq ($(CONFIG_USB_DWC2_PLATFORM),) +	obj-$(CONFIG_USB_DWC2_HOST)	+= dwc2_platform.o +	dwc2_platform-y			:= platform.o +endif + +obj-$(CONFIG_USB_DWC2_PERIPHERAL)	+= dwc2_gadget.o +dwc2_gadget-y				:= gadget.o diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c new file mode 100644 index 00000000000..27d2c9b8a03 --- /dev/null +++ b/drivers/usb/dwc2/core.c @@ -0,0 +1,2845 @@ +/* + * core.c - DesignWare HS OTG Controller common routines + * + * Copyright (C) 2004-2013 Synopsys, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + *    to endorse or promote products derived from this software without + *    specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * The Core code provides basic services for accessing and managing the + * DWC_otg hardware. These services are used by both the Host Controller + * Driver and the Peripheral Controller Driver. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include <linux/usb/hcd.h> +#include <linux/usb/ch11.h> + +#include "core.h" +#include "hcd.h" + +/** + * dwc2_enable_common_interrupts() - Initializes the commmon interrupts, + * used in both device and host modes + * + * @hsotg: Programming view of the DWC_otg controller + */ +static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg) +{ +	u32 intmsk; + +	/* Clear any pending OTG Interrupts */ +	writel(0xffffffff, hsotg->regs + GOTGINT); + +	/* Clear any pending interrupts */ +	writel(0xffffffff, hsotg->regs + GINTSTS); + +	/* Enable the interrupts in the GINTMSK */ +	intmsk = GINTSTS_MODEMIS | GINTSTS_OTGINT; + +	if (hsotg->core_params->dma_enable <= 0) +		intmsk |= GINTSTS_RXFLVL; + +	intmsk |= GINTSTS_CONIDSTSCHNG | GINTSTS_WKUPINT | GINTSTS_USBSUSP | +		  GINTSTS_SESSREQINT; + +	writel(intmsk, hsotg->regs + GINTMSK); +} + +/* + * Initializes the FSLSPClkSel field of the HCFG register depending on the + * PHY type + */ +static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) +{ +	u32 hcfg, val; + +	if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && +	     hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && +	     hsotg->core_params->ulpi_fs_ls > 0) || +	    hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) { +		/* Full speed PHY */ +		val = HCFG_FSLSPCLKSEL_48_MHZ; +	} else { +		/* High speed PHY running at full speed or high speed */ +		val = HCFG_FSLSPCLKSEL_30_60_MHZ; +	} + +	dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val); +	hcfg = readl(hsotg->regs + HCFG); +	hcfg &= ~HCFG_FSLSPCLKSEL_MASK; +	hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT; +	writel(hcfg, hsotg->regs + HCFG); +} + +/* + * Do core a soft reset of the core.  Be careful with this because it + * resets all the internal state machines of the core. + */ +static int dwc2_core_reset(struct dwc2_hsotg *hsotg) +{ +	u32 greset; +	int count = 0; + +	dev_vdbg(hsotg->dev, "%s()\n", __func__); + +	/* Wait for AHB master IDLE state */ +	do { +		usleep_range(20000, 40000); +		greset = readl(hsotg->regs + GRSTCTL); +		if (++count > 50) { +			dev_warn(hsotg->dev, +				 "%s() HANG! AHB Idle GRSTCTL=%0x\n", +				 __func__, greset); +			return -EBUSY; +		} +	} while (!(greset & GRSTCTL_AHBIDLE)); + +	/* Core Soft Reset */ +	count = 0; +	greset |= GRSTCTL_CSFTRST; +	writel(greset, hsotg->regs + GRSTCTL); +	do { +		usleep_range(20000, 40000); +		greset = readl(hsotg->regs + GRSTCTL); +		if (++count > 50) { +			dev_warn(hsotg->dev, +				 "%s() HANG! Soft Reset GRSTCTL=%0x\n", +				 __func__, greset); +			return -EBUSY; +		} +	} while (greset & GRSTCTL_CSFTRST); + +	/* +	 * NOTE: This long sleep is _very_ important, otherwise the core will +	 * not stay in host mode after a connector ID change! +	 */ +	usleep_range(150000, 200000); + +	return 0; +} + +static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) +{ +	u32 usbcfg, i2cctl; +	int retval = 0; + +	/* +	 * core_init() is now called on every switch so only call the +	 * following for the first time through +	 */ +	if (select_phy) { +		dev_dbg(hsotg->dev, "FS PHY selected\n"); +		usbcfg = readl(hsotg->regs + GUSBCFG); +		usbcfg |= GUSBCFG_PHYSEL; +		writel(usbcfg, hsotg->regs + GUSBCFG); + +		/* Reset after a PHY select */ +		retval = dwc2_core_reset(hsotg); +		if (retval) { +			dev_err(hsotg->dev, "%s() Reset failed, aborting", +					__func__); +			return retval; +		} +	} + +	/* +	 * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also +	 * do this on HNP Dev/Host mode switches (done in dev_init and +	 * host_init). +	 */ +	if (dwc2_is_host_mode(hsotg)) +		dwc2_init_fs_ls_pclk_sel(hsotg); + +	if (hsotg->core_params->i2c_enable > 0) { +		dev_dbg(hsotg->dev, "FS PHY enabling I2C\n"); + +		/* Program GUSBCFG.OtgUtmiFsSel to I2C */ +		usbcfg = readl(hsotg->regs + GUSBCFG); +		usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL; +		writel(usbcfg, hsotg->regs + GUSBCFG); + +		/* Program GI2CCTL.I2CEn */ +		i2cctl = readl(hsotg->regs + GI2CCTL); +		i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK; +		i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT; +		i2cctl &= ~GI2CCTL_I2CEN; +		writel(i2cctl, hsotg->regs + GI2CCTL); +		i2cctl |= GI2CCTL_I2CEN; +		writel(i2cctl, hsotg->regs + GI2CCTL); +	} + +	return retval; +} + +static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) +{ +	u32 usbcfg; +	int retval = 0; + +	if (!select_phy) +		return 0; + +	usbcfg = readl(hsotg->regs + GUSBCFG); + +	/* +	 * HS PHY parameters. These parameters are preserved during soft reset +	 * so only program the first time. Do a soft reset immediately after +	 * setting phyif. +	 */ +	switch (hsotg->core_params->phy_type) { +	case DWC2_PHY_TYPE_PARAM_ULPI: +		/* ULPI interface */ +		dev_dbg(hsotg->dev, "HS ULPI PHY selected\n"); +		usbcfg |= GUSBCFG_ULPI_UTMI_SEL; +		usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); +		if (hsotg->core_params->phy_ulpi_ddr > 0) +			usbcfg |= GUSBCFG_DDRSEL; +		break; +	case DWC2_PHY_TYPE_PARAM_UTMI: +		/* UTMI+ interface */ +		dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n"); +		usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16); +		if (hsotg->core_params->phy_utmi_width == 16) +			usbcfg |= GUSBCFG_PHYIF16; +		break; +	default: +		dev_err(hsotg->dev, "FS PHY selected at HS!\n"); +		break; +	} + +	writel(usbcfg, hsotg->regs + GUSBCFG); + +	/* Reset after setting the PHY parameters */ +	retval = dwc2_core_reset(hsotg); +	if (retval) { +		dev_err(hsotg->dev, "%s() Reset failed, aborting", +				__func__); +		return retval; +	} + +	return retval; +} + +static int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) +{ +	u32 usbcfg; +	int retval = 0; + +	if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL && +	    hsotg->core_params->phy_type == DWC2_PHY_TYPE_PARAM_FS) { +		/* If FS mode with FS PHY */ +		retval = dwc2_fs_phy_init(hsotg, select_phy); +		if (retval) +			return retval; +	} else { +		/* High speed PHY */ +		retval = dwc2_hs_phy_init(hsotg, select_phy); +		if (retval) +			return retval; +	} + +	if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && +	    hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && +	    hsotg->core_params->ulpi_fs_ls > 0) { +		dev_dbg(hsotg->dev, "Setting ULPI FSLS\n"); +		usbcfg = readl(hsotg->regs + GUSBCFG); +		usbcfg |= GUSBCFG_ULPI_FS_LS; +		usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M; +		writel(usbcfg, hsotg->regs + GUSBCFG); +	} else { +		usbcfg = readl(hsotg->regs + GUSBCFG); +		usbcfg &= ~GUSBCFG_ULPI_FS_LS; +		usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M; +		writel(usbcfg, hsotg->regs + GUSBCFG); +	} + +	return retval; +} + +static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg) +{ +	u32 ahbcfg = readl(hsotg->regs + GAHBCFG); + +	switch (hsotg->hw_params.arch) { +	case GHWCFG2_EXT_DMA_ARCH: +		dev_err(hsotg->dev, "External DMA Mode not supported\n"); +		return -EINVAL; + +	case GHWCFG2_INT_DMA_ARCH: +		dev_dbg(hsotg->dev, "Internal DMA Mode\n"); +		if (hsotg->core_params->ahbcfg != -1) { +			ahbcfg &= GAHBCFG_CTRL_MASK; +			ahbcfg |= hsotg->core_params->ahbcfg & +				  ~GAHBCFG_CTRL_MASK; +		} +		break; + +	case GHWCFG2_SLAVE_ONLY_ARCH: +	default: +		dev_dbg(hsotg->dev, "Slave Only Mode\n"); +		break; +	} + +	dev_dbg(hsotg->dev, "dma_enable:%d dma_desc_enable:%d\n", +		hsotg->core_params->dma_enable, +		hsotg->core_params->dma_desc_enable); + +	if (hsotg->core_params->dma_enable > 0) { +		if (hsotg->core_params->dma_desc_enable > 0) +			dev_dbg(hsotg->dev, "Using Descriptor DMA mode\n"); +		else +			dev_dbg(hsotg->dev, "Using Buffer DMA mode\n"); +	} else { +		dev_dbg(hsotg->dev, "Using Slave mode\n"); +		hsotg->core_params->dma_desc_enable = 0; +	} + +	if (hsotg->core_params->dma_enable > 0) +		ahbcfg |= GAHBCFG_DMA_EN; + +	writel(ahbcfg, hsotg->regs + GAHBCFG); + +	return 0; +} + +static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg) +{ +	u32 usbcfg; + +	usbcfg = readl(hsotg->regs + GUSBCFG); +	usbcfg &= ~(GUSBCFG_HNPCAP | GUSBCFG_SRPCAP); + +	switch (hsotg->hw_params.op_mode) { +	case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: +		if (hsotg->core_params->otg_cap == +				DWC2_CAP_PARAM_HNP_SRP_CAPABLE) +			usbcfg |= GUSBCFG_HNPCAP; +		if (hsotg->core_params->otg_cap != +				DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE) +			usbcfg |= GUSBCFG_SRPCAP; +		break; + +	case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: +	case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: +	case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: +		if (hsotg->core_params->otg_cap != +				DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE) +			usbcfg |= GUSBCFG_SRPCAP; +		break; + +	case GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE: +	case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE: +	case GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST: +	default: +		break; +	} + +	writel(usbcfg, hsotg->regs + GUSBCFG); +} + +/** + * dwc2_core_init() - Initializes the DWC_otg controller registers and + * prepares the core for device mode or host mode operation + * + * @hsotg:      Programming view of the DWC_otg controller + * @select_phy: If true then also set the Phy type + * @irq:        If >= 0, the irq to register + */ +int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq) +{ +	u32 usbcfg, otgctl; +	int retval; + +	dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg); + +	usbcfg = readl(hsotg->regs + GUSBCFG); + +	/* Set ULPI External VBUS bit if needed */ +	usbcfg &= ~GUSBCFG_ULPI_EXT_VBUS_DRV; +	if (hsotg->core_params->phy_ulpi_ext_vbus == +				DWC2_PHY_ULPI_EXTERNAL_VBUS) +		usbcfg |= GUSBCFG_ULPI_EXT_VBUS_DRV; + +	/* Set external TS Dline pulsing bit if needed */ +	usbcfg &= ~GUSBCFG_TERMSELDLPULSE; +	if (hsotg->core_params->ts_dline > 0) +		usbcfg |= GUSBCFG_TERMSELDLPULSE; + +	writel(usbcfg, hsotg->regs + GUSBCFG); + +	/* Reset the Controller */ +	retval = dwc2_core_reset(hsotg); +	if (retval) { +		dev_err(hsotg->dev, "%s(): Reset failed, aborting\n", +				__func__); +		return retval; +	} + +	/* +	 * This needs to happen in FS mode before any other programming occurs +	 */ +	retval = dwc2_phy_init(hsotg, select_phy); +	if (retval) +		return retval; + +	/* Program the GAHBCFG Register */ +	retval = dwc2_gahbcfg_init(hsotg); +	if (retval) +		return retval; + +	/* Program the GUSBCFG register */ +	dwc2_gusbcfg_init(hsotg); + +	/* Program the GOTGCTL register */ +	otgctl = readl(hsotg->regs + GOTGCTL); +	otgctl &= ~GOTGCTL_OTGVER; +	if (hsotg->core_params->otg_ver > 0) +		otgctl |= GOTGCTL_OTGVER; +	writel(otgctl, hsotg->regs + GOTGCTL); +	dev_dbg(hsotg->dev, "OTG VER PARAM: %d\n", hsotg->core_params->otg_ver); + +	/* Clear the SRP success bit for FS-I2c */ +	hsotg->srp_success = 0; + +	if (irq >= 0) { +		dev_dbg(hsotg->dev, "registering common handler for irq%d\n", +			irq); +		retval = devm_request_irq(hsotg->dev, irq, +					  dwc2_handle_common_intr, IRQF_SHARED, +					  dev_name(hsotg->dev), hsotg); +		if (retval) +			return retval; +	} + +	/* Enable common interrupts */ +	dwc2_enable_common_interrupts(hsotg); + +	/* +	 * Do device or host intialization based on mode during PCD and +	 * HCD initialization +	 */ +	if (dwc2_is_host_mode(hsotg)) { +		dev_dbg(hsotg->dev, "Host Mode\n"); +		hsotg->op_state = OTG_STATE_A_HOST; +	} else { +		dev_dbg(hsotg->dev, "Device Mode\n"); +		hsotg->op_state = OTG_STATE_B_PERIPHERAL; +	} + +	return 0; +} + +/** + * dwc2_enable_host_interrupts() - Enables the Host mode interrupts + * + * @hsotg: Programming view of DWC_otg controller + */ +void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg) +{ +	u32 intmsk; + +	dev_dbg(hsotg->dev, "%s()\n", __func__); + +	/* Disable all interrupts */ +	writel(0, hsotg->regs + GINTMSK); +	writel(0, hsotg->regs + HAINTMSK); + +	/* Enable the common interrupts */ +	dwc2_enable_common_interrupts(hsotg); + +	/* Enable host mode interrupts without disturbing common interrupts */ +	intmsk = readl(hsotg->regs + GINTMSK); +	intmsk |= GINTSTS_DISCONNINT | GINTSTS_PRTINT | GINTSTS_HCHINT; +	writel(intmsk, hsotg->regs + GINTMSK); +} + +/** + * dwc2_disable_host_interrupts() - Disables the Host Mode interrupts + * + * @hsotg: Programming view of DWC_otg controller + */ +void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg) +{ +	u32 intmsk = readl(hsotg->regs + GINTMSK); + +	/* Disable host mode interrupts without disturbing common interrupts */ +	intmsk &= ~(GINTSTS_SOF | GINTSTS_PRTINT | GINTSTS_HCHINT | +		    GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP); +	writel(intmsk, hsotg->regs + GINTMSK); +} + +/* + * dwc2_calculate_dynamic_fifo() - Calculates the default fifo size + * For system that have a total fifo depth that is smaller than the default + * RX + TX fifo size. + * + * @hsotg: Programming view of DWC_otg controller + */ +static void dwc2_calculate_dynamic_fifo(struct dwc2_hsotg *hsotg) +{ +	struct dwc2_core_params *params = hsotg->core_params; +	struct dwc2_hw_params *hw = &hsotg->hw_params; +	u32 rxfsiz, nptxfsiz, ptxfsiz, total_fifo_size; + +	total_fifo_size = hw->total_fifo_size; +	rxfsiz = params->host_rx_fifo_size; +	nptxfsiz = params->host_nperio_tx_fifo_size; +	ptxfsiz = params->host_perio_tx_fifo_size; + +	/* +	 * Will use Method 2 defined in the DWC2 spec: minimum FIFO depth +	 * allocation with support for high bandwidth endpoints. Synopsys +	 * defines MPS(Max Packet size) for a periodic EP=1024, and for +	 * non-periodic as 512. +	 */ +	if (total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz)) { +		/* +		 * For Buffer DMA mode/Scatter Gather DMA mode +		 * 2 * ((Largest Packet size / 4) + 1 + 1) + n +		 * with n = number of host channel. +		 * 2 * ((1024/4) + 2) = 516 +		 */ +		rxfsiz = 516 + hw->host_channels; + +		/* +		 * min non-periodic tx fifo depth +		 * 2 * (largest non-periodic USB packet used / 4) +		 * 2 * (512/4) = 256 +		 */ +		nptxfsiz = 256; + +		/* +		 * min periodic tx fifo depth +		 * (largest packet size*MC)/4 +		 * (1024 * 3)/4 = 768 +		 */ +		ptxfsiz = 768; + +		params->host_rx_fifo_size = rxfsiz; +		params->host_nperio_tx_fifo_size = nptxfsiz; +		params->host_perio_tx_fifo_size = ptxfsiz; +	} + +	/* +	 * If the summation of RX, NPTX and PTX fifo sizes is still +	 * bigger than the total_fifo_size, then we have a problem. +	 * +	 * We won't be able to allocate as many endpoints. Right now, +	 * we're just printing an error message, but ideally this FIFO +	 * allocation algorithm would be improved in the future. +	 * +	 * FIXME improve this FIFO allocation algorithm. +	 */ +	if (unlikely(total_fifo_size < (rxfsiz + nptxfsiz + ptxfsiz))) +		dev_err(hsotg->dev, "invalid fifo sizes\n"); +} + +static void dwc2_config_fifos(struct dwc2_hsotg *hsotg) +{ +	struct dwc2_core_params *params = hsotg->core_params; +	u32 nptxfsiz, hptxfsiz, dfifocfg, grxfsiz; + +	if (!params->enable_dynamic_fifo) +		return; + +	dwc2_calculate_dynamic_fifo(hsotg); + +	/* Rx FIFO */ +	grxfsiz = readl(hsotg->regs + GRXFSIZ); +	dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n", grxfsiz); +	grxfsiz &= ~GRXFSIZ_DEPTH_MASK; +	grxfsiz |= params->host_rx_fifo_size << +		   GRXFSIZ_DEPTH_SHIFT & GRXFSIZ_DEPTH_MASK; +	writel(grxfsiz, hsotg->regs + GRXFSIZ); +	dev_dbg(hsotg->dev, "new grxfsiz=%08x\n", readl(hsotg->regs + GRXFSIZ)); + +	/* Non-periodic Tx FIFO */ +	dev_dbg(hsotg->dev, "initial gnptxfsiz=%08x\n", +		readl(hsotg->regs + GNPTXFSIZ)); +	nptxfsiz = params->host_nperio_tx_fifo_size << +		   FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK; +	nptxfsiz |= params->host_rx_fifo_size << +		    FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK; +	writel(nptxfsiz, hsotg->regs + GNPTXFSIZ); +	dev_dbg(hsotg->dev, "new gnptxfsiz=%08x\n", +		readl(hsotg->regs + GNPTXFSIZ)); + +	/* Periodic Tx FIFO */ +	dev_dbg(hsotg->dev, "initial hptxfsiz=%08x\n", +		readl(hsotg->regs + HPTXFSIZ)); +	hptxfsiz = params->host_perio_tx_fifo_size << +		   FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK; +	hptxfsiz |= (params->host_rx_fifo_size + +		     params->host_nperio_tx_fifo_size) << +		    FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK; +	writel(hptxfsiz, hsotg->regs + HPTXFSIZ); +	dev_dbg(hsotg->dev, "new hptxfsiz=%08x\n", +		readl(hsotg->regs + HPTXFSIZ)); + +	if (hsotg->core_params->en_multiple_tx_fifo > 0 && +	    hsotg->hw_params.snpsid <= DWC2_CORE_REV_2_94a) { +		/* +		 * Global DFIFOCFG calculation for Host mode - +		 * include RxFIFO, NPTXFIFO and HPTXFIFO +		 */ +		dfifocfg = readl(hsotg->regs + GDFIFOCFG); +		dfifocfg &= ~GDFIFOCFG_EPINFOBASE_MASK; +		dfifocfg |= (params->host_rx_fifo_size + +			     params->host_nperio_tx_fifo_size + +			     params->host_perio_tx_fifo_size) << +			    GDFIFOCFG_EPINFOBASE_SHIFT & +			    GDFIFOCFG_EPINFOBASE_MASK; +		writel(dfifocfg, hsotg->regs + GDFIFOCFG); +	} +} + +/** + * dwc2_core_host_init() - Initializes the DWC_otg controller registers for + * Host mode + * + * @hsotg: Programming view of DWC_otg controller + * + * This function flushes the Tx and Rx FIFOs and flushes any entries in the + * request queues. Host channels are reset to ensure that they are ready for + * performing transfers. + */ +void dwc2_core_host_init(struct dwc2_hsotg *hsotg) +{ +	u32 hcfg, hfir, otgctl; + +	dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg); + +	/* Restart the Phy Clock */ +	writel(0, hsotg->regs + PCGCTL); + +	/* Initialize Host Configuration Register */ +	dwc2_init_fs_ls_pclk_sel(hsotg); +	if (hsotg->core_params->speed == DWC2_SPEED_PARAM_FULL) { +		hcfg = readl(hsotg->regs + HCFG); +		hcfg |= HCFG_FSLSSUPP; +		writel(hcfg, hsotg->regs + HCFG); +	} + +	/* +	 * This bit allows dynamic reloading of the HFIR register during +	 * runtime. This bit needs to be programmed during initial configuration +	 * and its value must not be changed during runtime. +	 */ +	if (hsotg->core_params->reload_ctl > 0) { +		hfir = readl(hsotg->regs + HFIR); +		hfir |= HFIR_RLDCTRL; +		writel(hfir, hsotg->regs + HFIR); +	} + +	if (hsotg->core_params->dma_desc_enable > 0) { +		u32 op_mode = hsotg->hw_params.op_mode; +		if (hsotg->hw_params.snpsid < DWC2_CORE_REV_2_90a || +		    !hsotg->hw_params.dma_desc_enable || +		    op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE || +		    op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE || +		    op_mode == GHWCFG2_OP_MODE_UNDEFINED) { +			dev_err(hsotg->dev, +				"Hardware does not support descriptor DMA mode -\n"); +			dev_err(hsotg->dev, +				"falling back to buffer DMA mode.\n"); +			hsotg->core_params->dma_desc_enable = 0; +		} else { +			hcfg = readl(hsotg->regs + HCFG); +			hcfg |= HCFG_DESCDMA; +			writel(hcfg, hsotg->regs + HCFG); +		} +	} + +	/* Configure data FIFO sizes */ +	dwc2_config_fifos(hsotg); + +	/* TODO - check this */ +	/* Clear Host Set HNP Enable in the OTG Control Register */ +	otgctl = readl(hsotg->regs + GOTGCTL); +	otgctl &= ~GOTGCTL_HSTSETHNPEN; +	writel(otgctl, hsotg->regs + GOTGCTL); + +	/* Make sure the FIFOs are flushed */ +	dwc2_flush_tx_fifo(hsotg, 0x10 /* all TX FIFOs */); +	dwc2_flush_rx_fifo(hsotg); + +	/* Clear Host Set HNP Enable in the OTG Control Register */ +	otgctl = readl(hsotg->regs + GOTGCTL); +	otgctl &= ~GOTGCTL_HSTSETHNPEN; +	writel(otgctl, hsotg->regs + GOTGCTL); + +	if (hsotg->core_params->dma_desc_enable <= 0) { +		int num_channels, i; +		u32 hcchar; + +		/* Flush out any leftover queued requests */ +		num_channels = hsotg->core_params->host_channels; +		for (i = 0; i < num_channels; i++) { +			hcchar = readl(hsotg->regs + HCCHAR(i)); +			hcchar &= ~HCCHAR_CHENA; +			hcchar |= HCCHAR_CHDIS; +			hcchar &= ~HCCHAR_EPDIR; +			writel(hcchar, hsotg->regs + HCCHAR(i)); +		} + +		/* Halt all channels to put them into a known state */ +		for (i = 0; i < num_channels; i++) { +			int count = 0; + +			hcchar = readl(hsotg->regs + HCCHAR(i)); +			hcchar |= HCCHAR_CHENA | HCCHAR_CHDIS; +			hcchar &= ~HCCHAR_EPDIR; +			writel(hcchar, hsotg->regs + HCCHAR(i)); +			dev_dbg(hsotg->dev, "%s: Halt channel %d\n", +				__func__, i); +			do { +				hcchar = readl(hsotg->regs + HCCHAR(i)); +				if (++count > 1000) { +					dev_err(hsotg->dev, +						"Unable to clear enable on channel %d\n", +						i); +					break; +				} +				udelay(1); +			} while (hcchar & HCCHAR_CHENA); +		} +	} + +	/* Turn on the vbus power */ +	dev_dbg(hsotg->dev, "Init: Port Power? op_state=%d\n", hsotg->op_state); +	if (hsotg->op_state == OTG_STATE_A_HOST) { +		u32 hprt0 = dwc2_read_hprt0(hsotg); + +		dev_dbg(hsotg->dev, "Init: Power Port (%d)\n", +			!!(hprt0 & HPRT0_PWR)); +		if (!(hprt0 & HPRT0_PWR)) { +			hprt0 |= HPRT0_PWR; +			writel(hprt0, hsotg->regs + HPRT0); +		} +	} + +	dwc2_enable_host_interrupts(hsotg); +} + +static void dwc2_hc_enable_slave_ints(struct dwc2_hsotg *hsotg, +				      struct dwc2_host_chan *chan) +{ +	u32 hcintmsk = HCINTMSK_CHHLTD; + +	switch (chan->ep_type) { +	case USB_ENDPOINT_XFER_CONTROL: +	case USB_ENDPOINT_XFER_BULK: +		dev_vdbg(hsotg->dev, "control/bulk\n"); +		hcintmsk |= HCINTMSK_XFERCOMPL; +		hcintmsk |= HCINTMSK_STALL; +		hcintmsk |= HCINTMSK_XACTERR; +		hcintmsk |= HCINTMSK_DATATGLERR; +		if (chan->ep_is_in) { +			hcintmsk |= HCINTMSK_BBLERR; +		} else { +			hcintmsk |= HCINTMSK_NAK; +			hcintmsk |= HCINTMSK_NYET; +			if (chan->do_ping) +				hcintmsk |= HCINTMSK_ACK; +		} + +		if (chan->do_split) { +			hcintmsk |= HCINTMSK_NAK; +			if (chan->complete_split) +				hcintmsk |= HCINTMSK_NYET; +			else +				hcintmsk |= HCINTMSK_ACK; +		} + +		if (chan->error_state) +			hcintmsk |= HCINTMSK_ACK; +		break; + +	case USB_ENDPOINT_XFER_INT: +		if (dbg_perio()) +			dev_vdbg(hsotg->dev, "intr\n"); +		hcintmsk |= HCINTMSK_XFERCOMPL; +		hcintmsk |= HCINTMSK_NAK; +		hcintmsk |= HCINTMSK_STALL; +		hcintmsk |= HCINTMSK_XACTERR; +		hcintmsk |= HCINTMSK_DATATGLERR; +		hcintmsk |= HCINTMSK_FRMOVRUN; + +		if (chan->ep_is_in) +			hcintmsk |= HCINTMSK_BBLERR; +		if (chan->error_state) +			hcintmsk |= HCINTMSK_ACK; +		if (chan->do_split) { +			if (chan->complete_split) +				hcintmsk |= HCINTMSK_NYET; +			else +				hcintmsk |= HCINTMSK_ACK; +		} +		break; + +	case USB_ENDPOINT_XFER_ISOC: +		if (dbg_perio()) +			dev_vdbg(hsotg->dev, "isoc\n"); +		hcintmsk |= HCINTMSK_XFERCOMPL; +		hcintmsk |= HCINTMSK_FRMOVRUN; +		hcintmsk |= HCINTMSK_ACK; + +		if (chan->ep_is_in) { +			hcintmsk |= HCINTMSK_XACTERR; +			hcintmsk |= HCINTMSK_BBLERR; +		} +		break; +	default: +		dev_err(hsotg->dev, "## Unknown EP type ##\n"); +		break; +	} + +	writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num)); +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk); +} + +static void dwc2_hc_enable_dma_ints(struct dwc2_hsotg *hsotg, +				    struct dwc2_host_chan *chan) +{ +	u32 hcintmsk = HCINTMSK_CHHLTD; + +	/* +	 * For Descriptor DMA mode core halts the channel on AHB error. +	 * Interrupt is not required. +	 */ +	if (hsotg->core_params->dma_desc_enable <= 0) { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "desc DMA disabled\n"); +		hcintmsk |= HCINTMSK_AHBERR; +	} else { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "desc DMA enabled\n"); +		if (chan->ep_type == USB_ENDPOINT_XFER_ISOC) +			hcintmsk |= HCINTMSK_XFERCOMPL; +	} + +	if (chan->error_state && !chan->do_split && +	    chan->ep_type != USB_ENDPOINT_XFER_ISOC) { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "setting ACK\n"); +		hcintmsk |= HCINTMSK_ACK; +		if (chan->ep_is_in) { +			hcintmsk |= HCINTMSK_DATATGLERR; +			if (chan->ep_type != USB_ENDPOINT_XFER_INT) +				hcintmsk |= HCINTMSK_NAK; +		} +	} + +	writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num)); +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk); +} + +static void dwc2_hc_enable_ints(struct dwc2_hsotg *hsotg, +				struct dwc2_host_chan *chan) +{ +	u32 intmsk; + +	if (hsotg->core_params->dma_enable > 0) { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "DMA enabled\n"); +		dwc2_hc_enable_dma_ints(hsotg, chan); +	} else { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "DMA disabled\n"); +		dwc2_hc_enable_slave_ints(hsotg, chan); +	} + +	/* Enable the top level host channel interrupt */ +	intmsk = readl(hsotg->regs + HAINTMSK); +	intmsk |= 1 << chan->hc_num; +	writel(intmsk, hsotg->regs + HAINTMSK); +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "set HAINTMSK to %08x\n", intmsk); + +	/* Make sure host channel interrupts are enabled */ +	intmsk = readl(hsotg->regs + GINTMSK); +	intmsk |= GINTSTS_HCHINT; +	writel(intmsk, hsotg->regs + GINTMSK); +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "set GINTMSK to %08x\n", intmsk); +} + +/** + * dwc2_hc_init() - Prepares a host channel for transferring packets to/from + * a specific endpoint + * + * @hsotg: Programming view of DWC_otg controller + * @chan:  Information needed to initialize the host channel + * + * The HCCHARn register is set up with the characteristics specified in chan. + * Host channel interrupts that may need to be serviced while this transfer is + * in progress are enabled. + */ +void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan) +{ +	u8 hc_num = chan->hc_num; +	u32 hcintmsk; +	u32 hcchar; +	u32 hcsplt = 0; + +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "%s()\n", __func__); + +	/* Clear old interrupt conditions for this host channel */ +	hcintmsk = 0xffffffff; +	hcintmsk &= ~HCINTMSK_RESERVED14_31; +	writel(hcintmsk, hsotg->regs + HCINT(hc_num)); + +	/* Enable channel interrupts required for this transfer */ +	dwc2_hc_enable_ints(hsotg, chan); + +	/* +	 * Program the HCCHARn register with the endpoint characteristics for +	 * the current transfer +	 */ +	hcchar = chan->dev_addr << HCCHAR_DEVADDR_SHIFT & HCCHAR_DEVADDR_MASK; +	hcchar |= chan->ep_num << HCCHAR_EPNUM_SHIFT & HCCHAR_EPNUM_MASK; +	if (chan->ep_is_in) +		hcchar |= HCCHAR_EPDIR; +	if (chan->speed == USB_SPEED_LOW) +		hcchar |= HCCHAR_LSPDDEV; +	hcchar |= chan->ep_type << HCCHAR_EPTYPE_SHIFT & HCCHAR_EPTYPE_MASK; +	hcchar |= chan->max_packet << HCCHAR_MPS_SHIFT & HCCHAR_MPS_MASK; +	writel(hcchar, hsotg->regs + HCCHAR(hc_num)); +	if (dbg_hc(chan)) { +		dev_vdbg(hsotg->dev, "set HCCHAR(%d) to %08x\n", +			 hc_num, hcchar); + +		dev_vdbg(hsotg->dev, "%s: Channel %d\n", +			 __func__, hc_num); +		dev_vdbg(hsotg->dev, "	 Dev Addr: %d\n", +			 chan->dev_addr); +		dev_vdbg(hsotg->dev, "	 Ep Num: %d\n", +			 chan->ep_num); +		dev_vdbg(hsotg->dev, "	 Is In: %d\n", +			 chan->ep_is_in); +		dev_vdbg(hsotg->dev, "	 Is Low Speed: %d\n", +			 chan->speed == USB_SPEED_LOW); +		dev_vdbg(hsotg->dev, "	 Ep Type: %d\n", +			 chan->ep_type); +		dev_vdbg(hsotg->dev, "	 Max Pkt: %d\n", +			 chan->max_packet); +	} + +	/* Program the HCSPLT register for SPLITs */ +	if (chan->do_split) { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, +				 "Programming HC %d with split --> %s\n", +				 hc_num, +				 chan->complete_split ? "CSPLIT" : "SSPLIT"); +		if (chan->complete_split) +			hcsplt |= HCSPLT_COMPSPLT; +		hcsplt |= chan->xact_pos << HCSPLT_XACTPOS_SHIFT & +			  HCSPLT_XACTPOS_MASK; +		hcsplt |= chan->hub_addr << HCSPLT_HUBADDR_SHIFT & +			  HCSPLT_HUBADDR_MASK; +		hcsplt |= chan->hub_port << HCSPLT_PRTADDR_SHIFT & +			  HCSPLT_PRTADDR_MASK; +		if (dbg_hc(chan)) { +			dev_vdbg(hsotg->dev, "	  comp split %d\n", +				 chan->complete_split); +			dev_vdbg(hsotg->dev, "	  xact pos %d\n", +				 chan->xact_pos); +			dev_vdbg(hsotg->dev, "	  hub addr %d\n", +				 chan->hub_addr); +			dev_vdbg(hsotg->dev, "	  hub port %d\n", +				 chan->hub_port); +			dev_vdbg(hsotg->dev, "	  is_in %d\n", +				 chan->ep_is_in); +			dev_vdbg(hsotg->dev, "	  Max Pkt %d\n", +				 chan->max_packet); +			dev_vdbg(hsotg->dev, "	  xferlen %d\n", +				 chan->xfer_len); +		} +	} + +	writel(hcsplt, hsotg->regs + HCSPLT(hc_num)); +} + +/** + * dwc2_hc_halt() - Attempts to halt a host channel + * + * @hsotg:       Controller register interface + * @chan:        Host channel to halt + * @halt_status: Reason for halting the channel + * + * This function should only be called in Slave mode or to abort a transfer in + * either Slave mode or DMA mode. Under normal circumstances in DMA mode, the + * controller halts the channel when the transfer is complete or a condition + * occurs that requires application intervention. + * + * In slave mode, checks for a free request queue entry, then sets the Channel + * Enable and Channel Disable bits of the Host Channel Characteristics + * register of the specified channel to intiate the halt. If there is no free + * request queue entry, sets only the Channel Disable bit of the HCCHARn + * register to flush requests for this channel. In the latter case, sets a + * flag to indicate that the host channel needs to be halted when a request + * queue slot is open. + * + * In DMA mode, always sets the Channel Enable and Channel Disable bits of the + * HCCHARn register. The controller ensures there is space in the request + * queue before submitting the halt request. + * + * Some time may elapse before the core flushes any posted requests for this + * host channel and halts. The Channel Halted interrupt handler completes the + * deactivation of the host channel. + */ +void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan, +		  enum dwc2_halt_status halt_status) +{ +	u32 nptxsts, hptxsts, hcchar; + +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "%s()\n", __func__); +	if (halt_status == DWC2_HC_XFER_NO_HALT_STATUS) +		dev_err(hsotg->dev, "!!! halt_status = %d !!!\n", halt_status); + +	if (halt_status == DWC2_HC_XFER_URB_DEQUEUE || +	    halt_status == DWC2_HC_XFER_AHB_ERR) { +		/* +		 * Disable all channel interrupts except Ch Halted. The QTD +		 * and QH state associated with this transfer has been cleared +		 * (in the case of URB_DEQUEUE), so the channel needs to be +		 * shut down carefully to prevent crashes. +		 */ +		u32 hcintmsk = HCINTMSK_CHHLTD; + +		dev_vdbg(hsotg->dev, "dequeue/error\n"); +		writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num)); + +		/* +		 * Make sure no other interrupts besides halt are currently +		 * pending. Handling another interrupt could cause a crash due +		 * to the QTD and QH state. +		 */ +		writel(~hcintmsk, hsotg->regs + HCINT(chan->hc_num)); + +		/* +		 * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR +		 * even if the channel was already halted for some other +		 * reason +		 */ +		chan->halt_status = halt_status; + +		hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num)); +		if (!(hcchar & HCCHAR_CHENA)) { +			/* +			 * The channel is either already halted or it hasn't +			 * started yet. In DMA mode, the transfer may halt if +			 * it finishes normally or a condition occurs that +			 * requires driver intervention. Don't want to halt +			 * the channel again. In either Slave or DMA mode, +			 * it's possible that the transfer has been assigned +			 * to a channel, but not started yet when an URB is +			 * dequeued. Don't want to halt a channel that hasn't +			 * started yet. +			 */ +			return; +		} +	} +	if (chan->halt_pending) { +		/* +		 * A halt has already been issued for this channel. This might +		 * happen when a transfer is aborted by a higher level in +		 * the stack. +		 */ +		dev_vdbg(hsotg->dev, +			 "*** %s: Channel %d, chan->halt_pending already set ***\n", +			 __func__, chan->hc_num); +		return; +	} + +	hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num)); + +	/* No need to set the bit in DDMA for disabling the channel */ +	/* TODO check it everywhere channel is disabled */ +	if (hsotg->core_params->dma_desc_enable <= 0) { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "desc DMA disabled\n"); +		hcchar |= HCCHAR_CHENA; +	} else { +		if (dbg_hc(chan)) +			dev_dbg(hsotg->dev, "desc DMA enabled\n"); +	} +	hcchar |= HCCHAR_CHDIS; + +	if (hsotg->core_params->dma_enable <= 0) { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "DMA not enabled\n"); +		hcchar |= HCCHAR_CHENA; + +		/* Check for space in the request queue to issue the halt */ +		if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL || +		    chan->ep_type == USB_ENDPOINT_XFER_BULK) { +			dev_vdbg(hsotg->dev, "control/bulk\n"); +			nptxsts = readl(hsotg->regs + GNPTXSTS); +			if ((nptxsts & TXSTS_QSPCAVAIL_MASK) == 0) { +				dev_vdbg(hsotg->dev, "Disabling channel\n"); +				hcchar &= ~HCCHAR_CHENA; +			} +		} else { +			if (dbg_perio()) +				dev_vdbg(hsotg->dev, "isoc/intr\n"); +			hptxsts = readl(hsotg->regs + HPTXSTS); +			if ((hptxsts & TXSTS_QSPCAVAIL_MASK) == 0 || +			    hsotg->queuing_high_bandwidth) { +				if (dbg_perio()) +					dev_vdbg(hsotg->dev, "Disabling channel\n"); +				hcchar &= ~HCCHAR_CHENA; +			} +		} +	} else { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "DMA enabled\n"); +	} + +	writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num)); +	chan->halt_status = halt_status; + +	if (hcchar & HCCHAR_CHENA) { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "Channel enabled\n"); +		chan->halt_pending = 1; +		chan->halt_on_queue = 0; +	} else { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "Channel disabled\n"); +		chan->halt_on_queue = 1; +	} + +	if (dbg_hc(chan)) { +		dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__, +			 chan->hc_num); +		dev_vdbg(hsotg->dev, "	 hcchar: 0x%08x\n", +			 hcchar); +		dev_vdbg(hsotg->dev, "	 halt_pending: %d\n", +			 chan->halt_pending); +		dev_vdbg(hsotg->dev, "	 halt_on_queue: %d\n", +			 chan->halt_on_queue); +		dev_vdbg(hsotg->dev, "	 halt_status: %d\n", +			 chan->halt_status); +	} +} + +/** + * dwc2_hc_cleanup() - Clears the transfer state for a host channel + * + * @hsotg: Programming view of DWC_otg controller + * @chan:  Identifies the host channel to clean up + * + * This function is normally called after a transfer is done and the host + * channel is being released + */ +void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan) +{ +	u32 hcintmsk; + +	chan->xfer_started = 0; + +	/* +	 * Clear channel interrupt enables and any unhandled channel interrupt +	 * conditions +	 */ +	writel(0, hsotg->regs + HCINTMSK(chan->hc_num)); +	hcintmsk = 0xffffffff; +	hcintmsk &= ~HCINTMSK_RESERVED14_31; +	writel(hcintmsk, hsotg->regs + HCINT(chan->hc_num)); +} + +/** + * dwc2_hc_set_even_odd_frame() - Sets the channel property that indicates in + * which frame a periodic transfer should occur + * + * @hsotg:  Programming view of DWC_otg controller + * @chan:   Identifies the host channel to set up and its properties + * @hcchar: Current value of the HCCHAR register for the specified host channel + * + * This function has no effect on non-periodic transfers + */ +static void dwc2_hc_set_even_odd_frame(struct dwc2_hsotg *hsotg, +				       struct dwc2_host_chan *chan, u32 *hcchar) +{ +	if (chan->ep_type == USB_ENDPOINT_XFER_INT || +	    chan->ep_type == USB_ENDPOINT_XFER_ISOC) { +		/* 1 if _next_ frame is odd, 0 if it's even */ +		if (!(dwc2_hcd_get_frame_number(hsotg) & 0x1)) +			*hcchar |= HCCHAR_ODDFRM; +	} +} + +static void dwc2_set_pid_isoc(struct dwc2_host_chan *chan) +{ +	/* Set up the initial PID for the transfer */ +	if (chan->speed == USB_SPEED_HIGH) { +		if (chan->ep_is_in) { +			if (chan->multi_count == 1) +				chan->data_pid_start = DWC2_HC_PID_DATA0; +			else if (chan->multi_count == 2) +				chan->data_pid_start = DWC2_HC_PID_DATA1; +			else +				chan->data_pid_start = DWC2_HC_PID_DATA2; +		} else { +			if (chan->multi_count == 1) +				chan->data_pid_start = DWC2_HC_PID_DATA0; +			else +				chan->data_pid_start = DWC2_HC_PID_MDATA; +		} +	} else { +		chan->data_pid_start = DWC2_HC_PID_DATA0; +	} +} + +/** + * dwc2_hc_write_packet() - Writes a packet into the Tx FIFO associated with + * the Host Channel + * + * @hsotg: Programming view of DWC_otg controller + * @chan:  Information needed to initialize the host channel + * + * This function should only be called in Slave mode. For a channel associated + * with a non-periodic EP, the non-periodic Tx FIFO is written. For a channel + * associated with a periodic EP, the periodic Tx FIFO is written. + * + * Upon return the xfer_buf and xfer_count fields in chan are incremented by + * the number of bytes written to the Tx FIFO. + */ +static void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg, +				 struct dwc2_host_chan *chan) +{ +	u32 i; +	u32 remaining_count; +	u32 byte_count; +	u32 dword_count; +	u32 __iomem *data_fifo; +	u32 *data_buf = (u32 *)chan->xfer_buf; + +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "%s()\n", __func__); + +	data_fifo = (u32 __iomem *)(hsotg->regs + HCFIFO(chan->hc_num)); + +	remaining_count = chan->xfer_len - chan->xfer_count; +	if (remaining_count > chan->max_packet) +		byte_count = chan->max_packet; +	else +		byte_count = remaining_count; + +	dword_count = (byte_count + 3) / 4; + +	if (((unsigned long)data_buf & 0x3) == 0) { +		/* xfer_buf is DWORD aligned */ +		for (i = 0; i < dword_count; i++, data_buf++) +			writel(*data_buf, data_fifo); +	} else { +		/* xfer_buf is not DWORD aligned */ +		for (i = 0; i < dword_count; i++, data_buf++) { +			u32 data = data_buf[0] | data_buf[1] << 8 | +				   data_buf[2] << 16 | data_buf[3] << 24; +			writel(data, data_fifo); +		} +	} + +	chan->xfer_count += byte_count; +	chan->xfer_buf += byte_count; +} + +/** + * dwc2_hc_start_transfer() - Does the setup for a data transfer for a host + * channel and starts the transfer + * + * @hsotg: Programming view of DWC_otg controller + * @chan:  Information needed to initialize the host channel. The xfer_len value + *         may be reduced to accommodate the max widths of the XferSize and + *         PktCnt fields in the HCTSIZn register. The multi_count value may be + *         changed to reflect the final xfer_len value. + * + * This function may be called in either Slave mode or DMA mode. In Slave mode, + * the caller must ensure that there is sufficient space in the request queue + * and Tx Data FIFO. + * + * For an OUT transfer in Slave mode, it loads a data packet into the + * appropriate FIFO. If necessary, additional data packets are loaded in the + * Host ISR. + * + * For an IN transfer in Slave mode, a data packet is requested. The data + * packets are unloaded from the Rx FIFO in the Host ISR. If necessary, + * additional data packets are requested in the Host ISR. + * + * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ + * register along with a packet count of 1 and the channel is enabled. This + * causes a single PING transaction to occur. Other fields in HCTSIZ are + * simply set to 0 since no data transfer occurs in this case. + * + * For a PING transfer in DMA mode, the HCTSIZ register is initialized with + * all the information required to perform the subsequent data transfer. In + * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the + * controller performs the entire PING protocol, then starts the data + * transfer. + */ +void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, +			    struct dwc2_host_chan *chan) +{ +	u32 max_hc_xfer_size = hsotg->core_params->max_transfer_size; +	u16 max_hc_pkt_count = hsotg->core_params->max_packet_count; +	u32 hcchar; +	u32 hctsiz = 0; +	u16 num_packets; + +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "%s()\n", __func__); + +	if (chan->do_ping) { +		if (hsotg->core_params->dma_enable <= 0) { +			if (dbg_hc(chan)) +				dev_vdbg(hsotg->dev, "ping, no DMA\n"); +			dwc2_hc_do_ping(hsotg, chan); +			chan->xfer_started = 1; +			return; +		} else { +			if (dbg_hc(chan)) +				dev_vdbg(hsotg->dev, "ping, DMA\n"); +			hctsiz |= TSIZ_DOPNG; +		} +	} + +	if (chan->do_split) { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "split\n"); +		num_packets = 1; + +		if (chan->complete_split && !chan->ep_is_in) +			/* +			 * For CSPLIT OUT Transfer, set the size to 0 so the +			 * core doesn't expect any data written to the FIFO +			 */ +			chan->xfer_len = 0; +		else if (chan->ep_is_in || chan->xfer_len > chan->max_packet) +			chan->xfer_len = chan->max_packet; +		else if (!chan->ep_is_in && chan->xfer_len > 188) +			chan->xfer_len = 188; + +		hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT & +			  TSIZ_XFERSIZE_MASK; +	} else { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "no split\n"); +		/* +		 * Ensure that the transfer length and packet count will fit +		 * in the widths allocated for them in the HCTSIZn register +		 */ +		if (chan->ep_type == USB_ENDPOINT_XFER_INT || +		    chan->ep_type == USB_ENDPOINT_XFER_ISOC) { +			/* +			 * Make sure the transfer size is no larger than one +			 * (micro)frame's worth of data. (A check was done +			 * when the periodic transfer was accepted to ensure +			 * that a (micro)frame's worth of data can be +			 * programmed into a channel.) +			 */ +			u32 max_periodic_len = +				chan->multi_count * chan->max_packet; + +			if (chan->xfer_len > max_periodic_len) +				chan->xfer_len = max_periodic_len; +		} else if (chan->xfer_len > max_hc_xfer_size) { +			/* +			 * Make sure that xfer_len is a multiple of max packet +			 * size +			 */ +			chan->xfer_len = +				max_hc_xfer_size - chan->max_packet + 1; +		} + +		if (chan->xfer_len > 0) { +			num_packets = (chan->xfer_len + chan->max_packet - 1) / +					chan->max_packet; +			if (num_packets > max_hc_pkt_count) { +				num_packets = max_hc_pkt_count; +				chan->xfer_len = num_packets * chan->max_packet; +			} +		} else { +			/* Need 1 packet for transfer length of 0 */ +			num_packets = 1; +		} + +		if (chan->ep_is_in) +			/* +			 * Always program an integral # of max packets for IN +			 * transfers +			 */ +			chan->xfer_len = num_packets * chan->max_packet; + +		if (chan->ep_type == USB_ENDPOINT_XFER_INT || +		    chan->ep_type == USB_ENDPOINT_XFER_ISOC) +			/* +			 * Make sure that the multi_count field matches the +			 * actual transfer length +			 */ +			chan->multi_count = num_packets; + +		if (chan->ep_type == USB_ENDPOINT_XFER_ISOC) +			dwc2_set_pid_isoc(chan); + +		hctsiz |= chan->xfer_len << TSIZ_XFERSIZE_SHIFT & +			  TSIZ_XFERSIZE_MASK; +	} + +	chan->start_pkt_count = num_packets; +	hctsiz |= num_packets << TSIZ_PKTCNT_SHIFT & TSIZ_PKTCNT_MASK; +	hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT & +		  TSIZ_SC_MC_PID_MASK; +	writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num)); +	if (dbg_hc(chan)) { +		dev_vdbg(hsotg->dev, "Wrote %08x to HCTSIZ(%d)\n", +			 hctsiz, chan->hc_num); + +		dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__, +			 chan->hc_num); +		dev_vdbg(hsotg->dev, "	 Xfer Size: %d\n", +			 (hctsiz & TSIZ_XFERSIZE_MASK) >> +			 TSIZ_XFERSIZE_SHIFT); +		dev_vdbg(hsotg->dev, "	 Num Pkts: %d\n", +			 (hctsiz & TSIZ_PKTCNT_MASK) >> +			 TSIZ_PKTCNT_SHIFT); +		dev_vdbg(hsotg->dev, "	 Start PID: %d\n", +			 (hctsiz & TSIZ_SC_MC_PID_MASK) >> +			 TSIZ_SC_MC_PID_SHIFT); +	} + +	if (hsotg->core_params->dma_enable > 0) { +		dma_addr_t dma_addr; + +		if (chan->align_buf) { +			if (dbg_hc(chan)) +				dev_vdbg(hsotg->dev, "align_buf\n"); +			dma_addr = chan->align_buf; +		} else { +			dma_addr = chan->xfer_dma; +		} +		writel((u32)dma_addr, hsotg->regs + HCDMA(chan->hc_num)); +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "Wrote %08lx to HCDMA(%d)\n", +				 (unsigned long)dma_addr, chan->hc_num); +	} + +	/* Start the split */ +	if (chan->do_split) { +		u32 hcsplt = readl(hsotg->regs + HCSPLT(chan->hc_num)); + +		hcsplt |= HCSPLT_SPLTENA; +		writel(hcsplt, hsotg->regs + HCSPLT(chan->hc_num)); +	} + +	hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num)); +	hcchar &= ~HCCHAR_MULTICNT_MASK; +	hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT & +		  HCCHAR_MULTICNT_MASK; +	dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar); + +	if (hcchar & HCCHAR_CHDIS) +		dev_warn(hsotg->dev, +			 "%s: chdis set, channel %d, hcchar 0x%08x\n", +			 __func__, chan->hc_num, hcchar); + +	/* Set host channel enable after all other setup is complete */ +	hcchar |= HCCHAR_CHENA; +	hcchar &= ~HCCHAR_CHDIS; + +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "	 Multi Cnt: %d\n", +			 (hcchar & HCCHAR_MULTICNT_MASK) >> +			 HCCHAR_MULTICNT_SHIFT); + +	writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num)); +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar, +			 chan->hc_num); + +	chan->xfer_started = 1; +	chan->requests++; + +	if (hsotg->core_params->dma_enable <= 0 && +	    !chan->ep_is_in && chan->xfer_len > 0) +		/* Load OUT packet into the appropriate Tx FIFO */ +		dwc2_hc_write_packet(hsotg, chan); +} + +/** + * dwc2_hc_start_transfer_ddma() - Does the setup for a data transfer for a + * host channel and starts the transfer in Descriptor DMA mode + * + * @hsotg: Programming view of DWC_otg controller + * @chan:  Information needed to initialize the host channel + * + * Initializes HCTSIZ register. For a PING transfer the Do Ping bit is set. + * Sets PID and NTD values. For periodic transfers initializes SCHED_INFO field + * with micro-frame bitmap. + * + * Initializes HCDMA register with descriptor list address and CTD value then + * starts the transfer via enabling the channel. + */ +void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg, +				 struct dwc2_host_chan *chan) +{ +	u32 hcchar; +	u32 hc_dma; +	u32 hctsiz = 0; + +	if (chan->do_ping) +		hctsiz |= TSIZ_DOPNG; + +	if (chan->ep_type == USB_ENDPOINT_XFER_ISOC) +		dwc2_set_pid_isoc(chan); + +	/* Packet Count and Xfer Size are not used in Descriptor DMA mode */ +	hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT & +		  TSIZ_SC_MC_PID_MASK; + +	/* 0 - 1 descriptor, 1 - 2 descriptors, etc */ +	hctsiz |= (chan->ntd - 1) << TSIZ_NTD_SHIFT & TSIZ_NTD_MASK; + +	/* Non-zero only for high-speed interrupt endpoints */ +	hctsiz |= chan->schinfo << TSIZ_SCHINFO_SHIFT & TSIZ_SCHINFO_MASK; + +	if (dbg_hc(chan)) { +		dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__, +			 chan->hc_num); +		dev_vdbg(hsotg->dev, "	 Start PID: %d\n", +			 chan->data_pid_start); +		dev_vdbg(hsotg->dev, "	 NTD: %d\n", chan->ntd - 1); +	} + +	writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num)); + +	hc_dma = (u32)chan->desc_list_addr & HCDMA_DMA_ADDR_MASK; + +	/* Always start from first descriptor */ +	hc_dma &= ~HCDMA_CTD_MASK; +	writel(hc_dma, hsotg->regs + HCDMA(chan->hc_num)); +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "Wrote %08x to HCDMA(%d)\n", +			 hc_dma, chan->hc_num); + +	hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num)); +	hcchar &= ~HCCHAR_MULTICNT_MASK; +	hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT & +		  HCCHAR_MULTICNT_MASK; + +	if (hcchar & HCCHAR_CHDIS) +		dev_warn(hsotg->dev, +			 "%s: chdis set, channel %d, hcchar 0x%08x\n", +			 __func__, chan->hc_num, hcchar); + +	/* Set host channel enable after all other setup is complete */ +	hcchar |= HCCHAR_CHENA; +	hcchar &= ~HCCHAR_CHDIS; + +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "	 Multi Cnt: %d\n", +			 (hcchar & HCCHAR_MULTICNT_MASK) >> +			 HCCHAR_MULTICNT_SHIFT); + +	writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num)); +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar, +			 chan->hc_num); + +	chan->xfer_started = 1; +	chan->requests++; +} + +/** + * dwc2_hc_continue_transfer() - Continues a data transfer that was started by + * a previous call to dwc2_hc_start_transfer() + * + * @hsotg: Programming view of DWC_otg controller + * @chan:  Information needed to initialize the host channel + * + * The caller must ensure there is sufficient space in the request queue and Tx + * Data FIFO. This function should only be called in Slave mode. In DMA mode, + * the controller acts autonomously to complete transfers programmed to a host + * channel. + * + * For an OUT transfer, a new data packet is loaded into the appropriate FIFO + * if there is any data remaining to be queued. For an IN transfer, another + * data packet is always requested. For the SETUP phase of a control transfer, + * this function does nothing. + * + * Return: 1 if a new request is queued, 0 if no more requests are required + * for this transfer + */ +int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg, +			      struct dwc2_host_chan *chan) +{ +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__, +			 chan->hc_num); + +	if (chan->do_split) +		/* SPLITs always queue just once per channel */ +		return 0; + +	if (chan->data_pid_start == DWC2_HC_PID_SETUP) +		/* SETUPs are queued only once since they can't be NAK'd */ +		return 0; + +	if (chan->ep_is_in) { +		/* +		 * Always queue another request for other IN transfers. If +		 * back-to-back INs are issued and NAKs are received for both, +		 * the driver may still be processing the first NAK when the +		 * second NAK is received. When the interrupt handler clears +		 * the NAK interrupt for the first NAK, the second NAK will +		 * not be seen. So we can't depend on the NAK interrupt +		 * handler to requeue a NAK'd request. Instead, IN requests +		 * are issued each time this function is called. When the +		 * transfer completes, the extra requests for the channel will +		 * be flushed. +		 */ +		u32 hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num)); + +		dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar); +		hcchar |= HCCHAR_CHENA; +		hcchar &= ~HCCHAR_CHDIS; +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "	 IN xfer: hcchar = 0x%08x\n", +				 hcchar); +		writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num)); +		chan->requests++; +		return 1; +	} + +	/* OUT transfers */ + +	if (chan->xfer_count < chan->xfer_len) { +		if (chan->ep_type == USB_ENDPOINT_XFER_INT || +		    chan->ep_type == USB_ENDPOINT_XFER_ISOC) { +			u32 hcchar = readl(hsotg->regs + +					   HCCHAR(chan->hc_num)); + +			dwc2_hc_set_even_odd_frame(hsotg, chan, +						   &hcchar); +		} + +		/* Load OUT packet into the appropriate Tx FIFO */ +		dwc2_hc_write_packet(hsotg, chan); +		chan->requests++; +		return 1; +	} + +	return 0; +} + +/** + * dwc2_hc_do_ping() - Starts a PING transfer + * + * @hsotg: Programming view of DWC_otg controller + * @chan:  Information needed to initialize the host channel + * + * This function should only be called in Slave mode. The Do Ping bit is set in + * the HCTSIZ register, then the channel is enabled. + */ +void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan) +{ +	u32 hcchar; +	u32 hctsiz; + +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "%s: Channel %d\n", __func__, +			 chan->hc_num); + + +	hctsiz = TSIZ_DOPNG; +	hctsiz |= 1 << TSIZ_PKTCNT_SHIFT; +	writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num)); + +	hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num)); +	hcchar |= HCCHAR_CHENA; +	hcchar &= ~HCCHAR_CHDIS; +	writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num)); +} + +/** + * dwc2_calc_frame_interval() - Calculates the correct frame Interval value for + * the HFIR register according to PHY type and speed + * + * @hsotg: Programming view of DWC_otg controller + * + * NOTE: The caller can modify the value of the HFIR register only after the + * Port Enable bit of the Host Port Control and Status register (HPRT.EnaPort) + * has been set + */ +u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg) +{ +	u32 usbcfg; +	u32 hprt0; +	int clock = 60;	/* default value */ + +	usbcfg = readl(hsotg->regs + GUSBCFG); +	hprt0 = readl(hsotg->regs + HPRT0); + +	if (!(usbcfg & GUSBCFG_PHYSEL) && (usbcfg & GUSBCFG_ULPI_UTMI_SEL) && +	    !(usbcfg & GUSBCFG_PHYIF16)) +		clock = 60; +	if ((usbcfg & GUSBCFG_PHYSEL) && hsotg->hw_params.fs_phy_type == +	    GHWCFG2_FS_PHY_TYPE_SHARED_ULPI) +		clock = 48; +	if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) && +	    !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16)) +		clock = 30; +	if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) && +	    !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && !(usbcfg & GUSBCFG_PHYIF16)) +		clock = 60; +	if ((usbcfg & GUSBCFG_PHY_LP_CLK_SEL) && !(usbcfg & GUSBCFG_PHYSEL) && +	    !(usbcfg & GUSBCFG_ULPI_UTMI_SEL) && (usbcfg & GUSBCFG_PHYIF16)) +		clock = 48; +	if ((usbcfg & GUSBCFG_PHYSEL) && !(usbcfg & GUSBCFG_PHYIF16) && +	    hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_SHARED_UTMI) +		clock = 48; +	if ((usbcfg & GUSBCFG_PHYSEL) && +	    hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) +		clock = 48; + +	if ((hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT == HPRT0_SPD_HIGH_SPEED) +		/* High speed case */ +		return 125 * clock; +	else +		/* FS/LS case */ +		return 1000 * clock; +} + +/** + * dwc2_read_packet() - Reads a packet from the Rx FIFO into the destination + * buffer + * + * @core_if: Programming view of DWC_otg controller + * @dest:    Destination buffer for the packet + * @bytes:   Number of bytes to copy to the destination + */ +void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes) +{ +	u32 __iomem *fifo = hsotg->regs + HCFIFO(0); +	u32 *data_buf = (u32 *)dest; +	int word_count = (bytes + 3) / 4; +	int i; + +	/* +	 * Todo: Account for the case where dest is not dword aligned. This +	 * requires reading data from the FIFO into a u32 temp buffer, then +	 * moving it into the data buffer. +	 */ + +	dev_vdbg(hsotg->dev, "%s(%p,%p,%d)\n", __func__, hsotg, dest, bytes); + +	for (i = 0; i < word_count; i++, data_buf++) +		*data_buf = readl(fifo); +} + +/** + * dwc2_dump_host_registers() - Prints the host registers + * + * @hsotg: Programming view of DWC_otg controller + * + * NOTE: This function will be removed once the peripheral controller code + * is integrated and the driver is stable + */ +void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg) +{ +#ifdef DEBUG +	u32 __iomem *addr; +	int i; + +	dev_dbg(hsotg->dev, "Host Global Registers\n"); +	addr = hsotg->regs + HCFG; +	dev_dbg(hsotg->dev, "HCFG	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + HFIR; +	dev_dbg(hsotg->dev, "HFIR	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + HFNUM; +	dev_dbg(hsotg->dev, "HFNUM	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + HPTXSTS; +	dev_dbg(hsotg->dev, "HPTXSTS	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + HAINT; +	dev_dbg(hsotg->dev, "HAINT	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + HAINTMSK; +	dev_dbg(hsotg->dev, "HAINTMSK	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	if (hsotg->core_params->dma_desc_enable > 0) { +		addr = hsotg->regs + HFLBADDR; +		dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n", +			(unsigned long)addr, readl(addr)); +	} + +	addr = hsotg->regs + HPRT0; +	dev_dbg(hsotg->dev, "HPRT0	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); + +	for (i = 0; i < hsotg->core_params->host_channels; i++) { +		dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i); +		addr = hsotg->regs + HCCHAR(i); +		dev_dbg(hsotg->dev, "HCCHAR	 @0x%08lX : 0x%08X\n", +			(unsigned long)addr, readl(addr)); +		addr = hsotg->regs + HCSPLT(i); +		dev_dbg(hsotg->dev, "HCSPLT	 @0x%08lX : 0x%08X\n", +			(unsigned long)addr, readl(addr)); +		addr = hsotg->regs + HCINT(i); +		dev_dbg(hsotg->dev, "HCINT	 @0x%08lX : 0x%08X\n", +			(unsigned long)addr, readl(addr)); +		addr = hsotg->regs + HCINTMSK(i); +		dev_dbg(hsotg->dev, "HCINTMSK	 @0x%08lX : 0x%08X\n", +			(unsigned long)addr, readl(addr)); +		addr = hsotg->regs + HCTSIZ(i); +		dev_dbg(hsotg->dev, "HCTSIZ	 @0x%08lX : 0x%08X\n", +			(unsigned long)addr, readl(addr)); +		addr = hsotg->regs + HCDMA(i); +		dev_dbg(hsotg->dev, "HCDMA	 @0x%08lX : 0x%08X\n", +			(unsigned long)addr, readl(addr)); +		if (hsotg->core_params->dma_desc_enable > 0) { +			addr = hsotg->regs + HCDMAB(i); +			dev_dbg(hsotg->dev, "HCDMAB	 @0x%08lX : 0x%08X\n", +				(unsigned long)addr, readl(addr)); +		} +	} +#endif +} + +/** + * dwc2_dump_global_registers() - Prints the core global registers + * + * @hsotg: Programming view of DWC_otg controller + * + * NOTE: This function will be removed once the peripheral controller code + * is integrated and the driver is stable + */ +void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg) +{ +#ifdef DEBUG +	u32 __iomem *addr; + +	dev_dbg(hsotg->dev, "Core Global Registers\n"); +	addr = hsotg->regs + GOTGCTL; +	dev_dbg(hsotg->dev, "GOTGCTL	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GOTGINT; +	dev_dbg(hsotg->dev, "GOTGINT	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GAHBCFG; +	dev_dbg(hsotg->dev, "GAHBCFG	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GUSBCFG; +	dev_dbg(hsotg->dev, "GUSBCFG	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GRSTCTL; +	dev_dbg(hsotg->dev, "GRSTCTL	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GINTSTS; +	dev_dbg(hsotg->dev, "GINTSTS	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GINTMSK; +	dev_dbg(hsotg->dev, "GINTMSK	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GRXSTSR; +	dev_dbg(hsotg->dev, "GRXSTSR	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GRXFSIZ; +	dev_dbg(hsotg->dev, "GRXFSIZ	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GNPTXFSIZ; +	dev_dbg(hsotg->dev, "GNPTXFSIZ	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GNPTXSTS; +	dev_dbg(hsotg->dev, "GNPTXSTS	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GI2CCTL; +	dev_dbg(hsotg->dev, "GI2CCTL	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GPVNDCTL; +	dev_dbg(hsotg->dev, "GPVNDCTL	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GGPIO; +	dev_dbg(hsotg->dev, "GGPIO	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GUID; +	dev_dbg(hsotg->dev, "GUID	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GSNPSID; +	dev_dbg(hsotg->dev, "GSNPSID	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GHWCFG1; +	dev_dbg(hsotg->dev, "GHWCFG1	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GHWCFG2; +	dev_dbg(hsotg->dev, "GHWCFG2	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GHWCFG3; +	dev_dbg(hsotg->dev, "GHWCFG3	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GHWCFG4; +	dev_dbg(hsotg->dev, "GHWCFG4	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GLPMCFG; +	dev_dbg(hsotg->dev, "GLPMCFG	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GPWRDN; +	dev_dbg(hsotg->dev, "GPWRDN	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + GDFIFOCFG; +	dev_dbg(hsotg->dev, "GDFIFOCFG	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +	addr = hsotg->regs + HPTXFSIZ; +	dev_dbg(hsotg->dev, "HPTXFSIZ	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); + +	addr = hsotg->regs + PCGCTL; +	dev_dbg(hsotg->dev, "PCGCTL	 @0x%08lX : 0x%08X\n", +		(unsigned long)addr, readl(addr)); +#endif +} + +/** + * dwc2_flush_tx_fifo() - Flushes a Tx FIFO + * + * @hsotg: Programming view of DWC_otg controller + * @num:   Tx FIFO to flush + */ +void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num) +{ +	u32 greset; +	int count = 0; + +	dev_vdbg(hsotg->dev, "Flush Tx FIFO %d\n", num); + +	greset = GRSTCTL_TXFFLSH; +	greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK; +	writel(greset, hsotg->regs + GRSTCTL); + +	do { +		greset = readl(hsotg->regs + GRSTCTL); +		if (++count > 10000) { +			dev_warn(hsotg->dev, +				 "%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n", +				 __func__, greset, +				 readl(hsotg->regs + GNPTXSTS)); +			break; +		} +		udelay(1); +	} while (greset & GRSTCTL_TXFFLSH); + +	/* Wait for at least 3 PHY Clocks */ +	udelay(1); +} + +/** + * dwc2_flush_rx_fifo() - Flushes the Rx FIFO + * + * @hsotg: Programming view of DWC_otg controller + */ +void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg) +{ +	u32 greset; +	int count = 0; + +	dev_vdbg(hsotg->dev, "%s()\n", __func__); + +	greset = GRSTCTL_RXFFLSH; +	writel(greset, hsotg->regs + GRSTCTL); + +	do { +		greset = readl(hsotg->regs + GRSTCTL); +		if (++count > 10000) { +			dev_warn(hsotg->dev, "%s() HANG! GRSTCTL=%0x\n", +				 __func__, greset); +			break; +		} +		udelay(1); +	} while (greset & GRSTCTL_RXFFLSH); + +	/* Wait for at least 3 PHY Clocks */ +	udelay(1); +} + +#define DWC2_OUT_OF_BOUNDS(a, b, c)	((a) < (b) || (a) > (c)) + +/* Parameter access functions */ +void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	switch (val) { +	case DWC2_CAP_PARAM_HNP_SRP_CAPABLE: +		if (hsotg->hw_params.op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) +			valid = 0; +		break; +	case DWC2_CAP_PARAM_SRP_ONLY_CAPABLE: +		switch (hsotg->hw_params.op_mode) { +		case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: +		case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: +		case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: +		case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: +			break; +		default: +			valid = 0; +			break; +		} +		break; +	case DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE: +		/* always valid */ +		break; +	default: +		valid = 0; +		break; +	} + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for otg_cap parameter. Check HW configuration.\n", +				val); +		switch (hsotg->hw_params.op_mode) { +		case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: +			val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE; +			break; +		case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: +		case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: +		case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: +			val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE; +			break; +		default: +			val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; +			break; +		} +		dev_dbg(hsotg->dev, "Setting otg_cap to %d\n", val); +	} + +	hsotg->core_params->otg_cap = val; +} + +void dwc2_set_param_dma_enable(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (val > 0 && hsotg->hw_params.arch == GHWCFG2_SLAVE_ONLY_ARCH) +		valid = 0; +	if (val < 0) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for dma_enable parameter. Check HW configuration.\n", +				val); +		val = hsotg->hw_params.arch != GHWCFG2_SLAVE_ONLY_ARCH; +		dev_dbg(hsotg->dev, "Setting dma_enable to %d\n", val); +	} + +	hsotg->core_params->dma_enable = val; +} + +void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (val > 0 && (hsotg->core_params->dma_enable <= 0 || +			!hsotg->hw_params.dma_desc_enable)) +		valid = 0; +	if (val < 0) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for dma_desc_enable parameter. Check HW configuration.\n", +				val); +		val = (hsotg->core_params->dma_enable > 0 && +			hsotg->hw_params.dma_desc_enable); +		dev_dbg(hsotg->dev, "Setting dma_desc_enable to %d\n", val); +	} + +	hsotg->core_params->dma_desc_enable = val; +} + +void dwc2_set_param_host_support_fs_ls_low_power(struct dwc2_hsotg *hsotg, +						 int val) +{ +	if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { +		if (val >= 0) { +			dev_err(hsotg->dev, +				"Wrong value for host_support_fs_low_power\n"); +			dev_err(hsotg->dev, +				"host_support_fs_low_power must be 0 or 1\n"); +		} +		val = 0; +		dev_dbg(hsotg->dev, +			"Setting host_support_fs_low_power to %d\n", val); +	} + +	hsotg->core_params->host_support_fs_ls_low_power = val; +} + +void dwc2_set_param_enable_dynamic_fifo(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (val > 0 && !hsotg->hw_params.enable_dynamic_fifo) +		valid = 0; +	if (val < 0) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for enable_dynamic_fifo parameter. Check HW configuration.\n", +				val); +		val = hsotg->hw_params.enable_dynamic_fifo; +		dev_dbg(hsotg->dev, "Setting enable_dynamic_fifo to %d\n", val); +	} + +	hsotg->core_params->enable_dynamic_fifo = val; +} + +void dwc2_set_param_host_rx_fifo_size(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (val < 16 || val > hsotg->hw_params.host_rx_fifo_size) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for host_rx_fifo_size. Check HW configuration.\n", +				val); +		val = hsotg->hw_params.host_rx_fifo_size; +		dev_dbg(hsotg->dev, "Setting host_rx_fifo_size to %d\n", val); +	} + +	hsotg->core_params->host_rx_fifo_size = val; +} + +void dwc2_set_param_host_nperio_tx_fifo_size(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (val < 16 || val > hsotg->hw_params.host_nperio_tx_fifo_size) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n", +				val); +		val = hsotg->hw_params.host_nperio_tx_fifo_size; +		dev_dbg(hsotg->dev, "Setting host_nperio_tx_fifo_size to %d\n", +			val); +	} + +	hsotg->core_params->host_nperio_tx_fifo_size = val; +} + +void dwc2_set_param_host_perio_tx_fifo_size(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (val < 16 || val > hsotg->hw_params.host_perio_tx_fifo_size) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n", +				val); +		val = hsotg->hw_params.host_perio_tx_fifo_size; +		dev_dbg(hsotg->dev, "Setting host_perio_tx_fifo_size to %d\n", +			val); +	} + +	hsotg->core_params->host_perio_tx_fifo_size = val; +} + +void dwc2_set_param_max_transfer_size(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (val < 2047 || val > hsotg->hw_params.max_transfer_size) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for max_transfer_size. Check HW configuration.\n", +				val); +		val = hsotg->hw_params.max_transfer_size; +		dev_dbg(hsotg->dev, "Setting max_transfer_size to %d\n", val); +	} + +	hsotg->core_params->max_transfer_size = val; +} + +void dwc2_set_param_max_packet_count(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (val < 15 || val > hsotg->hw_params.max_packet_count) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for max_packet_count. Check HW configuration.\n", +				val); +		val = hsotg->hw_params.max_packet_count; +		dev_dbg(hsotg->dev, "Setting max_packet_count to %d\n", val); +	} + +	hsotg->core_params->max_packet_count = val; +} + +void dwc2_set_param_host_channels(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (val < 1 || val > hsotg->hw_params.host_channels) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for host_channels. Check HW configuration.\n", +				val); +		val = hsotg->hw_params.host_channels; +		dev_dbg(hsotg->dev, "Setting host_channels to %d\n", val); +	} + +	hsotg->core_params->host_channels = val; +} + +void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 0; +	u32 hs_phy_type, fs_phy_type; + +	if (DWC2_OUT_OF_BOUNDS(val, DWC2_PHY_TYPE_PARAM_FS, +			       DWC2_PHY_TYPE_PARAM_ULPI)) { +		if (val >= 0) { +			dev_err(hsotg->dev, "Wrong value for phy_type\n"); +			dev_err(hsotg->dev, "phy_type must be 0, 1 or 2\n"); +		} + +		valid = 0; +	} + +	hs_phy_type = hsotg->hw_params.hs_phy_type; +	fs_phy_type = hsotg->hw_params.fs_phy_type; +	if (val == DWC2_PHY_TYPE_PARAM_UTMI && +	    (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI || +	     hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)) +		valid = 1; +	else if (val == DWC2_PHY_TYPE_PARAM_ULPI && +		 (hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI || +		  hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)) +		valid = 1; +	else if (val == DWC2_PHY_TYPE_PARAM_FS && +		 fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) +		valid = 1; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for phy_type. Check HW configuration.\n", +				val); +		val = DWC2_PHY_TYPE_PARAM_FS; +		if (hs_phy_type != GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED) { +			if (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI || +			    hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI) +				val = DWC2_PHY_TYPE_PARAM_UTMI; +			else +				val = DWC2_PHY_TYPE_PARAM_ULPI; +		} +		dev_dbg(hsotg->dev, "Setting phy_type to %d\n", val); +	} + +	hsotg->core_params->phy_type = val; +} + +static int dwc2_get_param_phy_type(struct dwc2_hsotg *hsotg) +{ +	return hsotg->core_params->phy_type; +} + +void dwc2_set_param_speed(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { +		if (val >= 0) { +			dev_err(hsotg->dev, "Wrong value for speed parameter\n"); +			dev_err(hsotg->dev, "max_speed parameter must be 0 or 1\n"); +		} +		valid = 0; +	} + +	if (val == DWC2_SPEED_PARAM_HIGH && +	    dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for speed parameter. Check HW configuration.\n", +				val); +		val = dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS ? +				DWC2_SPEED_PARAM_FULL : DWC2_SPEED_PARAM_HIGH; +		dev_dbg(hsotg->dev, "Setting speed to %d\n", val); +	} + +	hsotg->core_params->speed = val; +} + +void dwc2_set_param_host_ls_low_power_phy_clk(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (DWC2_OUT_OF_BOUNDS(val, DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ, +			       DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)) { +		if (val >= 0) { +			dev_err(hsotg->dev, +				"Wrong value for host_ls_low_power_phy_clk parameter\n"); +			dev_err(hsotg->dev, +				"host_ls_low_power_phy_clk must be 0 or 1\n"); +		} +		valid = 0; +	} + +	if (val == DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ && +	    dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n", +				val); +		val = dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS +			? DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ +			: DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ; +		dev_dbg(hsotg->dev, "Setting host_ls_low_power_phy_clk to %d\n", +			val); +	} + +	hsotg->core_params->host_ls_low_power_phy_clk = val; +} + +void dwc2_set_param_phy_ulpi_ddr(struct dwc2_hsotg *hsotg, int val) +{ +	if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { +		if (val >= 0) { +			dev_err(hsotg->dev, "Wrong value for phy_ulpi_ddr\n"); +			dev_err(hsotg->dev, "phy_upli_ddr must be 0 or 1\n"); +		} +		val = 0; +		dev_dbg(hsotg->dev, "Setting phy_upli_ddr to %d\n", val); +	} + +	hsotg->core_params->phy_ulpi_ddr = val; +} + +void dwc2_set_param_phy_ulpi_ext_vbus(struct dwc2_hsotg *hsotg, int val) +{ +	if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { +		if (val >= 0) { +			dev_err(hsotg->dev, +				"Wrong value for phy_ulpi_ext_vbus\n"); +			dev_err(hsotg->dev, +				"phy_ulpi_ext_vbus must be 0 or 1\n"); +		} +		val = 0; +		dev_dbg(hsotg->dev, "Setting phy_ulpi_ext_vbus to %d\n", val); +	} + +	hsotg->core_params->phy_ulpi_ext_vbus = val; +} + +void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 0; + +	switch (hsotg->hw_params.utmi_phy_data_width) { +	case GHWCFG4_UTMI_PHY_DATA_WIDTH_8: +		valid = (val == 8); +		break; +	case GHWCFG4_UTMI_PHY_DATA_WIDTH_16: +		valid = (val == 16); +		break; +	case GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16: +		valid = (val == 8 || val == 16); +		break; +	} + +	if (!valid) { +		if (val >= 0) { +			dev_err(hsotg->dev, +				"%d invalid for phy_utmi_width. Check HW configuration.\n", +				val); +		} +		val = (hsotg->hw_params.utmi_phy_data_width == +		       GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16; +		dev_dbg(hsotg->dev, "Setting phy_utmi_width to %d\n", val); +	} + +	hsotg->core_params->phy_utmi_width = val; +} + +void dwc2_set_param_ulpi_fs_ls(struct dwc2_hsotg *hsotg, int val) +{ +	if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { +		if (val >= 0) { +			dev_err(hsotg->dev, "Wrong value for ulpi_fs_ls\n"); +			dev_err(hsotg->dev, "ulpi_fs_ls must be 0 or 1\n"); +		} +		val = 0; +		dev_dbg(hsotg->dev, "Setting ulpi_fs_ls to %d\n", val); +	} + +	hsotg->core_params->ulpi_fs_ls = val; +} + +void dwc2_set_param_ts_dline(struct dwc2_hsotg *hsotg, int val) +{ +	if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { +		if (val >= 0) { +			dev_err(hsotg->dev, "Wrong value for ts_dline\n"); +			dev_err(hsotg->dev, "ts_dline must be 0 or 1\n"); +		} +		val = 0; +		dev_dbg(hsotg->dev, "Setting ts_dline to %d\n", val); +	} + +	hsotg->core_params->ts_dline = val; +} + +void dwc2_set_param_i2c_enable(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { +		if (val >= 0) { +			dev_err(hsotg->dev, "Wrong value for i2c_enable\n"); +			dev_err(hsotg->dev, "i2c_enable must be 0 or 1\n"); +		} + +		valid = 0; +	} + +	if (val == 1 && !(hsotg->hw_params.i2c_enable)) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for i2c_enable. Check HW configuration.\n", +				val); +		val = hsotg->hw_params.i2c_enable; +		dev_dbg(hsotg->dev, "Setting i2c_enable to %d\n", val); +	} + +	hsotg->core_params->i2c_enable = val; +} + +void dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { +		if (val >= 0) { +			dev_err(hsotg->dev, +				"Wrong value for en_multiple_tx_fifo,\n"); +			dev_err(hsotg->dev, +				"en_multiple_tx_fifo must be 0 or 1\n"); +		} +		valid = 0; +	} + +	if (val == 1 && !hsotg->hw_params.en_multiple_tx_fifo) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n", +				val); +		val = hsotg->hw_params.en_multiple_tx_fifo; +		dev_dbg(hsotg->dev, "Setting en_multiple_tx_fifo to %d\n", val); +	} + +	hsotg->core_params->en_multiple_tx_fifo = val; +} + +void dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val) +{ +	int valid = 1; + +	if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { +		if (val >= 0) { +			dev_err(hsotg->dev, +				"'%d' invalid for parameter reload_ctl\n", val); +			dev_err(hsotg->dev, "reload_ctl must be 0 or 1\n"); +		} +		valid = 0; +	} + +	if (val == 1 && hsotg->hw_params.snpsid < DWC2_CORE_REV_2_92a) +		valid = 0; + +	if (!valid) { +		if (val >= 0) +			dev_err(hsotg->dev, +				"%d invalid for parameter reload_ctl. Check HW configuration.\n", +				val); +		val = hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_92a; +		dev_dbg(hsotg->dev, "Setting reload_ctl to %d\n", val); +	} + +	hsotg->core_params->reload_ctl = val; +} + +void dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val) +{ +	if (val != -1) +		hsotg->core_params->ahbcfg = val; +	else +		hsotg->core_params->ahbcfg = GAHBCFG_HBSTLEN_INCR4 << +						GAHBCFG_HBSTLEN_SHIFT; +} + +void dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val) +{ +	if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { +		if (val >= 0) { +			dev_err(hsotg->dev, +				"'%d' invalid for parameter otg_ver\n", val); +			dev_err(hsotg->dev, +				"otg_ver must be 0 (for OTG 1.3 support) or 1 (for OTG 2.0 support)\n"); +		} +		val = 0; +		dev_dbg(hsotg->dev, "Setting otg_ver to %d\n", val); +	} + +	hsotg->core_params->otg_ver = val; +} + +static void dwc2_set_param_uframe_sched(struct dwc2_hsotg *hsotg, int val) +{ +	if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { +		if (val >= 0) { +			dev_err(hsotg->dev, +				"'%d' invalid for parameter uframe_sched\n", +				val); +			dev_err(hsotg->dev, "uframe_sched must be 0 or 1\n"); +		} +		val = 1; +		dev_dbg(hsotg->dev, "Setting uframe_sched to %d\n", val); +	} + +	hsotg->core_params->uframe_sched = val; +} + +/* + * This function is called during module intialization to pass module parameters + * for the DWC_otg core. + */ +void dwc2_set_parameters(struct dwc2_hsotg *hsotg, +			 const struct dwc2_core_params *params) +{ +	dev_dbg(hsotg->dev, "%s()\n", __func__); + +	dwc2_set_param_otg_cap(hsotg, params->otg_cap); +	dwc2_set_param_dma_enable(hsotg, params->dma_enable); +	dwc2_set_param_dma_desc_enable(hsotg, params->dma_desc_enable); +	dwc2_set_param_host_support_fs_ls_low_power(hsotg, +			params->host_support_fs_ls_low_power); +	dwc2_set_param_enable_dynamic_fifo(hsotg, +			params->enable_dynamic_fifo); +	dwc2_set_param_host_rx_fifo_size(hsotg, +			params->host_rx_fifo_size); +	dwc2_set_param_host_nperio_tx_fifo_size(hsotg, +			params->host_nperio_tx_fifo_size); +	dwc2_set_param_host_perio_tx_fifo_size(hsotg, +			params->host_perio_tx_fifo_size); +	dwc2_set_param_max_transfer_size(hsotg, +			params->max_transfer_size); +	dwc2_set_param_max_packet_count(hsotg, +			params->max_packet_count); +	dwc2_set_param_host_channels(hsotg, params->host_channels); +	dwc2_set_param_phy_type(hsotg, params->phy_type); +	dwc2_set_param_speed(hsotg, params->speed); +	dwc2_set_param_host_ls_low_power_phy_clk(hsotg, +			params->host_ls_low_power_phy_clk); +	dwc2_set_param_phy_ulpi_ddr(hsotg, params->phy_ulpi_ddr); +	dwc2_set_param_phy_ulpi_ext_vbus(hsotg, +			params->phy_ulpi_ext_vbus); +	dwc2_set_param_phy_utmi_width(hsotg, params->phy_utmi_width); +	dwc2_set_param_ulpi_fs_ls(hsotg, params->ulpi_fs_ls); +	dwc2_set_param_ts_dline(hsotg, params->ts_dline); +	dwc2_set_param_i2c_enable(hsotg, params->i2c_enable); +	dwc2_set_param_en_multiple_tx_fifo(hsotg, +			params->en_multiple_tx_fifo); +	dwc2_set_param_reload_ctl(hsotg, params->reload_ctl); +	dwc2_set_param_ahbcfg(hsotg, params->ahbcfg); +	dwc2_set_param_otg_ver(hsotg, params->otg_ver); +	dwc2_set_param_uframe_sched(hsotg, params->uframe_sched); +} + +/** + * During device initialization, read various hardware configuration + * registers and interpret the contents. + */ +int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) +{ +	struct dwc2_hw_params *hw = &hsotg->hw_params; +	unsigned width; +	u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4; +	u32 hptxfsiz, grxfsiz, gnptxfsiz; +	u32 gusbcfg; + +	/* +	 * Attempt to ensure this device is really a DWC_otg Controller. +	 * Read and verify the GSNPSID register contents. The value should be +	 * 0x45f42xxx or 0x45f43xxx, which corresponds to either "OT2" or "OT3", +	 * as in "OTG version 2.xx" or "OTG version 3.xx". +	 */ +	hw->snpsid = readl(hsotg->regs + GSNPSID); +	if ((hw->snpsid & 0xfffff000) != 0x4f542000 && +	    (hw->snpsid & 0xfffff000) != 0x4f543000) { +		dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n", +			hw->snpsid); +		return -ENODEV; +	} + +	dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n", +		hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf, +		hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid); + +	hwcfg1 = readl(hsotg->regs + GHWCFG1); +	hwcfg2 = readl(hsotg->regs + GHWCFG2); +	hwcfg3 = readl(hsotg->regs + GHWCFG3); +	hwcfg4 = readl(hsotg->regs + GHWCFG4); +	gnptxfsiz = readl(hsotg->regs + GNPTXFSIZ); +	grxfsiz = readl(hsotg->regs + GRXFSIZ); + +	dev_dbg(hsotg->dev, "hwcfg1=%08x\n", hwcfg1); +	dev_dbg(hsotg->dev, "hwcfg2=%08x\n", hwcfg2); +	dev_dbg(hsotg->dev, "hwcfg3=%08x\n", hwcfg3); +	dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hwcfg4); +	dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz); +	dev_dbg(hsotg->dev, "grxfsiz=%08x\n", grxfsiz); + +	/* Force host mode to get HPTXFSIZ exact power on value */ +	gusbcfg = readl(hsotg->regs + GUSBCFG); +	gusbcfg |= GUSBCFG_FORCEHOSTMODE; +	writel(gusbcfg, hsotg->regs + GUSBCFG); +	usleep_range(100000, 150000); + +	hptxfsiz = readl(hsotg->regs + HPTXFSIZ); +	dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz); +	gusbcfg = readl(hsotg->regs + GUSBCFG); +	gusbcfg &= ~GUSBCFG_FORCEHOSTMODE; +	writel(gusbcfg, hsotg->regs + GUSBCFG); +	usleep_range(100000, 150000); + +	/* hwcfg2 */ +	hw->op_mode = (hwcfg2 & GHWCFG2_OP_MODE_MASK) >> +		      GHWCFG2_OP_MODE_SHIFT; +	hw->arch = (hwcfg2 & GHWCFG2_ARCHITECTURE_MASK) >> +		   GHWCFG2_ARCHITECTURE_SHIFT; +	hw->enable_dynamic_fifo = !!(hwcfg2 & GHWCFG2_DYNAMIC_FIFO); +	hw->host_channels = 1 + ((hwcfg2 & GHWCFG2_NUM_HOST_CHAN_MASK) >> +				GHWCFG2_NUM_HOST_CHAN_SHIFT); +	hw->hs_phy_type = (hwcfg2 & GHWCFG2_HS_PHY_TYPE_MASK) >> +			  GHWCFG2_HS_PHY_TYPE_SHIFT; +	hw->fs_phy_type = (hwcfg2 & GHWCFG2_FS_PHY_TYPE_MASK) >> +			  GHWCFG2_FS_PHY_TYPE_SHIFT; +	hw->num_dev_ep = (hwcfg2 & GHWCFG2_NUM_DEV_EP_MASK) >> +			 GHWCFG2_NUM_DEV_EP_SHIFT; +	hw->nperio_tx_q_depth = +		(hwcfg2 & GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK) >> +		GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT << 1; +	hw->host_perio_tx_q_depth = +		(hwcfg2 & GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK) >> +		GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT << 1; +	hw->dev_token_q_depth = +		(hwcfg2 & GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK) >> +		GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT; + +	/* hwcfg3 */ +	width = (hwcfg3 & GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK) >> +		GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT; +	hw->max_transfer_size = (1 << (width + 11)) - 1; +	width = (hwcfg3 & GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK) >> +		GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT; +	hw->max_packet_count = (1 << (width + 4)) - 1; +	hw->i2c_enable = !!(hwcfg3 & GHWCFG3_I2C); +	hw->total_fifo_size = (hwcfg3 & GHWCFG3_DFIFO_DEPTH_MASK) >> +			      GHWCFG3_DFIFO_DEPTH_SHIFT; + +	/* hwcfg4 */ +	hw->en_multiple_tx_fifo = !!(hwcfg4 & GHWCFG4_DED_FIFO_EN); +	hw->num_dev_perio_in_ep = (hwcfg4 & GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK) >> +				  GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT; +	hw->dma_desc_enable = !!(hwcfg4 & GHWCFG4_DESC_DMA); +	hw->power_optimized = !!(hwcfg4 & GHWCFG4_POWER_OPTIMIZ); +	hw->utmi_phy_data_width = (hwcfg4 & GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK) >> +				  GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT; + +	/* fifo sizes */ +	hw->host_rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >> +				GRXFSIZ_DEPTH_SHIFT; +	hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >> +				       FIFOSIZE_DEPTH_SHIFT; +	hw->host_perio_tx_fifo_size = (hptxfsiz & FIFOSIZE_DEPTH_MASK) >> +				      FIFOSIZE_DEPTH_SHIFT; + +	dev_dbg(hsotg->dev, "Detected values from hardware:\n"); +	dev_dbg(hsotg->dev, "  op_mode=%d\n", +		hw->op_mode); +	dev_dbg(hsotg->dev, "  arch=%d\n", +		hw->arch); +	dev_dbg(hsotg->dev, "  dma_desc_enable=%d\n", +		hw->dma_desc_enable); +	dev_dbg(hsotg->dev, "  power_optimized=%d\n", +		hw->power_optimized); +	dev_dbg(hsotg->dev, "  i2c_enable=%d\n", +		hw->i2c_enable); +	dev_dbg(hsotg->dev, "  hs_phy_type=%d\n", +		hw->hs_phy_type); +	dev_dbg(hsotg->dev, "  fs_phy_type=%d\n", +		hw->fs_phy_type); +	dev_dbg(hsotg->dev, "  utmi_phy_data_wdith=%d\n", +		hw->utmi_phy_data_width); +	dev_dbg(hsotg->dev, "  num_dev_ep=%d\n", +		hw->num_dev_ep); +	dev_dbg(hsotg->dev, "  num_dev_perio_in_ep=%d\n", +		hw->num_dev_perio_in_ep); +	dev_dbg(hsotg->dev, "  host_channels=%d\n", +		hw->host_channels); +	dev_dbg(hsotg->dev, "  max_transfer_size=%d\n", +		hw->max_transfer_size); +	dev_dbg(hsotg->dev, "  max_packet_count=%d\n", +		hw->max_packet_count); +	dev_dbg(hsotg->dev, "  nperio_tx_q_depth=0x%0x\n", +		hw->nperio_tx_q_depth); +	dev_dbg(hsotg->dev, "  host_perio_tx_q_depth=0x%0x\n", +		hw->host_perio_tx_q_depth); +	dev_dbg(hsotg->dev, "  dev_token_q_depth=0x%0x\n", +		hw->dev_token_q_depth); +	dev_dbg(hsotg->dev, "  enable_dynamic_fifo=%d\n", +		hw->enable_dynamic_fifo); +	dev_dbg(hsotg->dev, "  en_multiple_tx_fifo=%d\n", +		hw->en_multiple_tx_fifo); +	dev_dbg(hsotg->dev, "  total_fifo_size=%d\n", +		hw->total_fifo_size); +	dev_dbg(hsotg->dev, "  host_rx_fifo_size=%d\n", +		hw->host_rx_fifo_size); +	dev_dbg(hsotg->dev, "  host_nperio_tx_fifo_size=%d\n", +		hw->host_nperio_tx_fifo_size); +	dev_dbg(hsotg->dev, "  host_perio_tx_fifo_size=%d\n", +		hw->host_perio_tx_fifo_size); +	dev_dbg(hsotg->dev, "\n"); + +	return 0; +} + +u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg) +{ +	return hsotg->core_params->otg_ver == 1 ? 0x0200 : 0x0103; +} + +bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg) +{ +	if (readl(hsotg->regs + GSNPSID) == 0xffffffff) +		return false; +	else +		return true; +} + +/** + * dwc2_enable_global_interrupts() - Enables the controller's Global + * Interrupt in the AHB Config register + * + * @hsotg: Programming view of DWC_otg controller + */ +void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg) +{ +	u32 ahbcfg = readl(hsotg->regs + GAHBCFG); + +	ahbcfg |= GAHBCFG_GLBL_INTR_EN; +	writel(ahbcfg, hsotg->regs + GAHBCFG); +} + +/** + * dwc2_disable_global_interrupts() - Disables the controller's Global + * Interrupt in the AHB Config register + * + * @hsotg: Programming view of DWC_otg controller + */ +void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg) +{ +	u32 ahbcfg = readl(hsotg->regs + GAHBCFG); + +	ahbcfg &= ~GAHBCFG_GLBL_INTR_EN; +	writel(ahbcfg, hsotg->regs + GAHBCFG); +} + +MODULE_DESCRIPTION("DESIGNWARE HS OTG Core"); +MODULE_AUTHOR("Synopsys, Inc."); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h new file mode 100644 index 00000000000..1efd10cc962 --- /dev/null +++ b/drivers/usb/dwc2/core.h @@ -0,0 +1,950 @@ +/* + * core.h - DesignWare HS OTG Controller common declarations + * + * Copyright (C) 2004-2013 Synopsys, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + *    to endorse or promote products derived from this software without + *    specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DWC2_CORE_H__ +#define __DWC2_CORE_H__ + +#include <linux/phy/phy.h> +#include <linux/regulator/consumer.h> +#include <linux/usb/gadget.h> +#include <linux/usb/otg.h> +#include <linux/usb/phy.h> +#include "hw.h" + +#ifdef DWC2_LOG_WRITES +static inline void do_write(u32 value, void *addr) +{ +	writel(value, addr); +	pr_info("INFO:: wrote %08x to %p\n", value, addr); +} + +#undef writel +#define writel(v, a)	do_write(v, a) +#endif + +/* Maximum number of Endpoints/HostChannels */ +#define MAX_EPS_CHANNELS	16 + +/* s3c-hsotg declarations */ +static const char * const s3c_hsotg_supply_names[] = { +	"vusb_d",               /* digital USB supply, 1.2V */ +	"vusb_a",               /* analog USB supply, 1.1V */ +}; + +/* + * EP0_MPS_LIMIT + * + * Unfortunately there seems to be a limit of the amount of data that can + * be transferred by IN transactions on EP0. This is either 127 bytes or 3 + * packets (which practically means 1 packet and 63 bytes of data) when the + * MPS is set to 64. + * + * This means if we are wanting to move >127 bytes of data, we need to + * split the transactions up, but just doing one packet at a time does + * not work (this may be an implicit DATA0 PID on first packet of the + * transaction) and doing 2 packets is outside the controller's limits. + * + * If we try to lower the MPS size for EP0, then no transfers work properly + * for EP0, and the system will fail basic enumeration. As no cause for this + * has currently been found, we cannot support any large IN transfers for + * EP0. + */ +#define EP0_MPS_LIMIT   64 + +struct s3c_hsotg; +struct s3c_hsotg_req; + +/** + * struct s3c_hsotg_ep - driver endpoint definition. + * @ep: The gadget layer representation of the endpoint. + * @name: The driver generated name for the endpoint. + * @queue: Queue of requests for this endpoint. + * @parent: Reference back to the parent device structure. + * @req: The current request that the endpoint is processing. This is + *       used to indicate an request has been loaded onto the endpoint + *       and has yet to be completed (maybe due to data move, or simply + *       awaiting an ack from the core all the data has been completed). + * @debugfs: File entry for debugfs file for this endpoint. + * @lock: State lock to protect contents of endpoint. + * @dir_in: Set to true if this endpoint is of the IN direction, which + *          means that it is sending data to the Host. + * @index: The index for the endpoint registers. + * @mc: Multi Count - number of transactions per microframe + * @interval - Interval for periodic endpoints + * @name: The name array passed to the USB core. + * @halted: Set if the endpoint has been halted. + * @periodic: Set if this is a periodic ep, such as Interrupt + * @isochronous: Set if this is a isochronous ep + * @sent_zlp: Set if we've sent a zero-length packet. + * @total_data: The total number of data bytes done. + * @fifo_size: The size of the FIFO (for periodic IN endpoints) + * @fifo_load: The amount of data loaded into the FIFO (periodic IN) + * @last_load: The offset of data for the last start of request. + * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN + * + * This is the driver's state for each registered enpoint, allowing it + * to keep track of transactions that need doing. Each endpoint has a + * lock to protect the state, to try and avoid using an overall lock + * for the host controller as much as possible. + * + * For periodic IN endpoints, we have fifo_size and fifo_load to try + * and keep track of the amount of data in the periodic FIFO for each + * of these as we don't have a status register that tells us how much + * is in each of them. (note, this may actually be useless information + * as in shared-fifo mode periodic in acts like a single-frame packet + * buffer than a fifo) + */ +struct s3c_hsotg_ep { +	struct usb_ep           ep; +	struct list_head        queue; +	struct s3c_hsotg        *parent; +	struct s3c_hsotg_req    *req; +	struct dentry           *debugfs; + +	unsigned long           total_data; +	unsigned int            size_loaded; +	unsigned int            last_load; +	unsigned int            fifo_load; +	unsigned short          fifo_size; + +	unsigned char           dir_in; +	unsigned char           index; +	unsigned char           mc; +	unsigned char           interval; + +	unsigned int            halted:1; +	unsigned int            periodic:1; +	unsigned int            isochronous:1; +	unsigned int            sent_zlp:1; + +	char                    name[10]; +}; + +/** + * struct s3c_hsotg - driver state. + * @dev: The parent device supplied to the probe function + * @driver: USB gadget driver + * @phy: The otg phy transceiver structure for phy control. + * @uphy: The otg phy transceiver structure for old USB phy control. + * @plat: The platform specific configuration data. This can be removed once + * all SoCs support usb transceiver. + * @regs: The memory area mapped for accessing registers. + * @irq: The IRQ number we are using + * @supplies: Definition of USB power supplies + * @phyif: PHY interface width + * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. + * @num_of_eps: Number of available EPs (excluding EP0) + * @debug_root: root directrory for debugfs. + * @debug_file: main status file for debugfs. + * @debug_fifo: FIFO status file for debugfs. + * @ep0_reply: Request used for ep0 reply. + * @ep0_buff: Buffer for EP0 reply data, if needed. + * @ctrl_buff: Buffer for EP0 control requests. + * @ctrl_req: Request for EP0 control packets. + * @setup: NAK management for EP0 SETUP + * @last_rst: Time of last reset + * @eps: The endpoints being supplied to the gadget framework + */ +struct s3c_hsotg { +	struct device            *dev; +	struct usb_gadget_driver *driver; +	struct phy               *phy; +	struct usb_phy           *uphy; +	struct s3c_hsotg_plat    *plat; + +	spinlock_t              lock; + +	void __iomem            *regs; +	int                     irq; +	struct clk              *clk; + +	struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; + +	u32                     phyif; +	unsigned int            dedicated_fifos:1; +	unsigned char           num_of_eps; + +	struct dentry           *debug_root; +	struct dentry           *debug_file; +	struct dentry           *debug_fifo; + +	struct usb_request      *ep0_reply; +	struct usb_request      *ctrl_req; +	u8                      ep0_buff[8]; +	u8                      ctrl_buff[8]; + +	struct usb_gadget       gadget; +	unsigned int            setup; +	unsigned long           last_rst; +	struct s3c_hsotg_ep     *eps; +}; + +/** + * struct s3c_hsotg_req - data transfer request + * @req: The USB gadget request + * @queue: The list of requests for the endpoint this is queued for. + * @in_progress: Has already had size/packets written to core + * @mapped: DMA buffer for this request has been mapped via dma_map_single(). + */ +struct s3c_hsotg_req { +	struct usb_request      req; +	struct list_head        queue; +	unsigned char           in_progress; +	unsigned char           mapped; +}; + +#define call_gadget(_hs, _entry) \ +do { \ +	if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ +		(_hs)->driver && (_hs)->driver->_entry) { \ +		spin_unlock(&_hs->lock); \ +		(_hs)->driver->_entry(&(_hs)->gadget); \ +		spin_lock(&_hs->lock); \ +	} \ +} while (0) + +struct dwc2_hsotg; +struct dwc2_host_chan; + +/* Device States */ +enum dwc2_lx_state { +	DWC2_L0,	/* On state */ +	DWC2_L1,	/* LPM sleep state */ +	DWC2_L2,	/* USB suspend state */ +	DWC2_L3,	/* Off state */ +}; + +/** + * struct dwc2_core_params - Parameters for configuring the core + * + * @otg_cap:            Specifies the OTG capabilities. + *                       0 - HNP and SRP capable + *                       1 - SRP Only capable + *                       2 - No HNP/SRP capable (always available) + *                      Defaults to best available option (0, 1, then 2) + * @otg_ver:            OTG version supported + *                       0 - 1.3 (default) + *                       1 - 2.0 + * @dma_enable:         Specifies whether to use slave or DMA mode for accessing + *                      the data FIFOs. The driver will automatically detect the + *                      value for this parameter if none is specified. + *                       0 - Slave (always available) + *                       1 - DMA (default, if available) + * @dma_desc_enable:    When DMA mode is enabled, specifies whether to use + *                      address DMA mode or descriptor DMA mode for accessing + *                      the data FIFOs. The driver will automatically detect the + *                      value for this if none is specified. + *                       0 - Address DMA + *                       1 - Descriptor DMA (default, if available) + * @speed:              Specifies the maximum speed of operation in host and + *                      device mode. The actual speed depends on the speed of + *                      the attached device and the value of phy_type. + *                       0 - High Speed + *                           (default when phy_type is UTMI+ or ULPI) + *                       1 - Full Speed + *                           (default when phy_type is Full Speed) + * @enable_dynamic_fifo: 0 - Use coreConsultant-specified FIFO size parameters + *                       1 - Allow dynamic FIFO sizing (default, if available) + * @en_multiple_tx_fifo: Specifies whether dedicated per-endpoint transmit FIFOs + *                      are enabled + * @host_rx_fifo_size:  Number of 4-byte words in the Rx FIFO in host mode when + *                      dynamic FIFO sizing is enabled + *                       16 to 32768 + *                      Actual maximum value is autodetected and also + *                      the default. + * @host_nperio_tx_fifo_size: Number of 4-byte words in the non-periodic Tx FIFO + *                      in host mode when dynamic FIFO sizing is enabled + *                       16 to 32768 + *                      Actual maximum value is autodetected and also + *                      the default. + * @host_perio_tx_fifo_size: Number of 4-byte words in the periodic Tx FIFO in + *                      host mode when dynamic FIFO sizing is enabled + *                       16 to 32768 + *                      Actual maximum value is autodetected and also + *                      the default. + * @max_transfer_size:  The maximum transfer size supported, in bytes + *                       2047 to 65,535 + *                      Actual maximum value is autodetected and also + *                      the default. + * @max_packet_count:   The maximum number of packets in a transfer + *                       15 to 511 + *                      Actual maximum value is autodetected and also + *                      the default. + * @host_channels:      The number of host channel registers to use + *                       1 to 16 + *                      Actual maximum value is autodetected and also + *                      the default. + * @phy_type:           Specifies the type of PHY interface to use. By default, + *                      the driver will automatically detect the phy_type. + *                       0 - Full Speed Phy + *                       1 - UTMI+ Phy + *                       2 - ULPI Phy + *                      Defaults to best available option (2, 1, then 0) + * @phy_utmi_width:     Specifies the UTMI+ Data Width (in bits). This parameter + *                      is applicable for a phy_type of UTMI+ or ULPI. (For a + *                      ULPI phy_type, this parameter indicates the data width + *                      between the MAC and the ULPI Wrapper.) Also, this + *                      parameter is applicable only if the OTG_HSPHY_WIDTH cC + *                      parameter was set to "8 and 16 bits", meaning that the + *                      core has been configured to work at either data path + *                      width. + *                       8 or 16 (default 16 if available) + * @phy_ulpi_ddr:       Specifies whether the ULPI operates at double or single + *                      data rate. This parameter is only applicable if phy_type + *                      is ULPI. + *                       0 - single data rate ULPI interface with 8 bit wide + *                           data bus (default) + *                       1 - double data rate ULPI interface with 4 bit wide + *                           data bus + * @phy_ulpi_ext_vbus:  For a ULPI phy, specifies whether to use the internal or + *                      external supply to drive the VBus + *                       0 - Internal supply (default) + *                       1 - External supply + * @i2c_enable:         Specifies whether to use the I2Cinterface for a full + *                      speed PHY. This parameter is only applicable if phy_type + *                      is FS. + *                       0 - No (default) + *                       1 - Yes + * @ulpi_fs_ls:         Make ULPI phy operate in FS/LS mode only + *                       0 - No (default) + *                       1 - Yes + * @host_support_fs_ls_low_power: Specifies whether low power mode is supported + *                      when attached to a Full Speed or Low Speed device in + *                      host mode. + *                       0 - Don't support low power mode (default) + *                       1 - Support low power mode + * @host_ls_low_power_phy_clk: Specifies the PHY clock rate in low power mode + *                      when connected to a Low Speed device in host + *                      mode. This parameter is applicable only if + *                      host_support_fs_ls_low_power is enabled. + *                       0 - 48 MHz + *                           (default when phy_type is UTMI+ or ULPI) + *                       1 - 6 MHz + *                           (default when phy_type is Full Speed) + * @ts_dline:           Enable Term Select Dline pulsing + *                       0 - No (default) + *                       1 - Yes + * @reload_ctl:         Allow dynamic reloading of HFIR register during runtime + *                       0 - No (default for core < 2.92a) + *                       1 - Yes (default for core >= 2.92a) + * @ahbcfg:             This field allows the default value of the GAHBCFG + *                      register to be overridden + *                       -1         - GAHBCFG value will be set to 0x06 + *                                    (INCR4, default) + *                       all others - GAHBCFG value will be overridden with + *                                    this value + *                      Not all bits can be controlled like this, the + *                      bits defined by GAHBCFG_CTRL_MASK are controlled + *                      by the driver and are ignored in this + *                      configuration value. + * @uframe_sched:       True to enable the microframe scheduler + * + * The following parameters may be specified when starting the module. These + * parameters define how the DWC_otg controller should be configured. A + * value of -1 (or any other out of range value) for any parameter means + * to read the value from hardware (if possible) or use the builtin + * default described above. + */ +struct dwc2_core_params { +	/* +	 * Don't add any non-int members here, this will break +	 * dwc2_set_all_params! +	 */ +	int otg_cap; +	int otg_ver; +	int dma_enable; +	int dma_desc_enable; +	int speed; +	int enable_dynamic_fifo; +	int en_multiple_tx_fifo; +	int host_rx_fifo_size; +	int host_nperio_tx_fifo_size; +	int host_perio_tx_fifo_size; +	int max_transfer_size; +	int max_packet_count; +	int host_channels; +	int phy_type; +	int phy_utmi_width; +	int phy_ulpi_ddr; +	int phy_ulpi_ext_vbus; +	int i2c_enable; +	int ulpi_fs_ls; +	int host_support_fs_ls_low_power; +	int host_ls_low_power_phy_clk; +	int ts_dline; +	int reload_ctl; +	int ahbcfg; +	int uframe_sched; +}; + +/** + * struct dwc2_hw_params - Autodetected parameters. + * + * These parameters are the various parameters read from hardware + * registers during initialization. They typically contain the best + * supported or maximum value that can be configured in the + * corresponding dwc2_core_params value. + * + * The values that are not in dwc2_core_params are documented below. + * + * @op_mode             Mode of Operation + *                       0 - HNP- and SRP-Capable OTG (Host & Device) + *                       1 - SRP-Capable OTG (Host & Device) + *                       2 - Non-HNP and Non-SRP Capable OTG (Host & Device) + *                       3 - SRP-Capable Device + *                       4 - Non-OTG Device + *                       5 - SRP-Capable Host + *                       6 - Non-OTG Host + * @arch                Architecture + *                       0 - Slave only + *                       1 - External DMA + *                       2 - Internal DMA + * @power_optimized     Are power optimizations enabled? + * @num_dev_ep          Number of device endpoints available + * @num_dev_perio_in_ep Number of device periodic IN endpoints + *                      avaialable + * @dev_token_q_depth   Device Mode IN Token Sequence Learning Queue + *                      Depth + *                       0 to 30 + * @host_perio_tx_q_depth + *                      Host Mode Periodic Request Queue Depth + *                       2, 4 or 8 + * @nperio_tx_q_depth + *                      Non-Periodic Request Queue Depth + *                       2, 4 or 8 + * @hs_phy_type         High-speed PHY interface type + *                       0 - High-speed interface not supported + *                       1 - UTMI+ + *                       2 - ULPI + *                       3 - UTMI+ and ULPI + * @fs_phy_type         Full-speed PHY interface type + *                       0 - Full speed interface not supported + *                       1 - Dedicated full speed interface + *                       2 - FS pins shared with UTMI+ pins + *                       3 - FS pins shared with ULPI pins + * @total_fifo_size:    Total internal RAM for FIFOs (bytes) + * @utmi_phy_data_width UTMI+ PHY data width + *                       0 - 8 bits + *                       1 - 16 bits + *                       2 - 8 or 16 bits + * @snpsid:             Value from SNPSID register + */ +struct dwc2_hw_params { +	unsigned op_mode:3; +	unsigned arch:2; +	unsigned dma_desc_enable:1; +	unsigned enable_dynamic_fifo:1; +	unsigned en_multiple_tx_fifo:1; +	unsigned host_rx_fifo_size:16; +	unsigned host_nperio_tx_fifo_size:16; +	unsigned host_perio_tx_fifo_size:16; +	unsigned nperio_tx_q_depth:3; +	unsigned host_perio_tx_q_depth:3; +	unsigned dev_token_q_depth:5; +	unsigned max_transfer_size:26; +	unsigned max_packet_count:11; +	unsigned host_channels:5; +	unsigned hs_phy_type:2; +	unsigned fs_phy_type:2; +	unsigned i2c_enable:1; +	unsigned num_dev_ep:4; +	unsigned num_dev_perio_in_ep:4; +	unsigned total_fifo_size:16; +	unsigned power_optimized:1; +	unsigned utmi_phy_data_width:2; +	u32 snpsid; +}; + +/** + * struct dwc2_hsotg - Holds the state of the driver, including the non-periodic + * and periodic schedules + * + * @dev:                The struct device pointer + * @regs:		Pointer to controller regs + * @core_params:        Parameters that define how the core should be configured + * @hw_params:          Parameters that were autodetected from the + *                      hardware registers + * @op_state:           The operational State, during transitions (a_host=> + *                      a_peripheral and b_device=>b_host) this may not match + *                      the core, but allows the software to determine + *                      transitions + * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth + *                      transfer are in process of being queued + * @srp_success:        Stores status of SRP request in the case of a FS PHY + *                      with an I2C interface + * @wq_otg:             Workqueue object used for handling of some interrupts + * @wf_otg:             Work object for handling Connector ID Status Change + *                      interrupt + * @wkp_timer:          Timer object for handling Wakeup Detected interrupt + * @lx_state:           Lx state of connected device + * @flags:              Flags for handling root port state changes + * @non_periodic_sched_inactive: Inactive QHs in the non-periodic schedule. + *                      Transfers associated with these QHs are not currently + *                      assigned to a host channel. + * @non_periodic_sched_active: Active QHs in the non-periodic schedule. + *                      Transfers associated with these QHs are currently + *                      assigned to a host channel. + * @non_periodic_qh_ptr: Pointer to next QH to process in the active + *                      non-periodic schedule + * @periodic_sched_inactive: Inactive QHs in the periodic schedule. This is a + *                      list of QHs for periodic transfers that are _not_ + *                      scheduled for the next frame. Each QH in the list has an + *                      interval counter that determines when it needs to be + *                      scheduled for execution. This scheduling mechanism + *                      allows only a simple calculation for periodic bandwidth + *                      used (i.e. must assume that all periodic transfers may + *                      need to execute in the same frame). However, it greatly + *                      simplifies scheduling and should be sufficient for the + *                      vast majority of OTG hosts, which need to connect to a + *                      small number of peripherals at one time. Items move from + *                      this list to periodic_sched_ready when the QH interval + *                      counter is 0 at SOF. + * @periodic_sched_ready:  List of periodic QHs that are ready for execution in + *                      the next frame, but have not yet been assigned to host + *                      channels. Items move from this list to + *                      periodic_sched_assigned as host channels become + *                      available during the current frame. + * @periodic_sched_assigned: List of periodic QHs to be executed in the next + *                      frame that are assigned to host channels. Items move + *                      from this list to periodic_sched_queued as the + *                      transactions for the QH are queued to the DWC_otg + *                      controller. + * @periodic_sched_queued: List of periodic QHs that have been queued for + *                      execution. Items move from this list to either + *                      periodic_sched_inactive or periodic_sched_ready when the + *                      channel associated with the transfer is released. If the + *                      interval for the QH is 1, the item moves to + *                      periodic_sched_ready because it must be rescheduled for + *                      the next frame. Otherwise, the item moves to + *                      periodic_sched_inactive. + * @periodic_usecs:     Total bandwidth claimed so far for periodic transfers. + *                      This value is in microseconds per (micro)frame. The + *                      assumption is that all periodic transfers may occur in + *                      the same (micro)frame. + * @frame_usecs:        Internal variable used by the microframe scheduler + * @frame_number:       Frame number read from the core at SOF. The value ranges + *                      from 0 to HFNUM_MAX_FRNUM. + * @periodic_qh_count:  Count of periodic QHs, if using several eps. Used for + *                      SOF enable/disable. + * @free_hc_list:       Free host channels in the controller. This is a list of + *                      struct dwc2_host_chan items. + * @periodic_channels:  Number of host channels assigned to periodic transfers. + *                      Currently assuming that there is a dedicated host + *                      channel for each periodic transaction and at least one + *                      host channel is available for non-periodic transactions. + * @non_periodic_channels: Number of host channels assigned to non-periodic + *                      transfers + * @available_host_channels Number of host channels available for the microframe + *                      scheduler to use + * @hc_ptr_array:       Array of pointers to the host channel descriptors. + *                      Allows accessing a host channel descriptor given the + *                      host channel number. This is useful in interrupt + *                      handlers. + * @status_buf:         Buffer used for data received during the status phase of + *                      a control transfer. + * @status_buf_dma:     DMA address for status_buf + * @start_work:         Delayed work for handling host A-cable connection + * @reset_work:         Delayed work for handling a port reset + * @lock:               Spinlock that protects all the driver data structures + * @priv:               Stores a pointer to the struct usb_hcd + * @otg_port:           OTG port number + * @frame_list:         Frame list + * @frame_list_dma:     Frame list DMA address + */ +struct dwc2_hsotg { +	struct device *dev; +	void __iomem *regs; +	/** Params detected from hardware */ +	struct dwc2_hw_params hw_params; +	/** Params to actually use */ +	struct dwc2_core_params *core_params; +	enum usb_otg_state op_state; + +	unsigned int queuing_high_bandwidth:1; +	unsigned int srp_success:1; + +	struct workqueue_struct *wq_otg; +	struct work_struct wf_otg; +	struct timer_list wkp_timer; +	enum dwc2_lx_state lx_state; + +	union dwc2_hcd_internal_flags { +		u32 d32; +		struct { +			unsigned port_connect_status_change:1; +			unsigned port_connect_status:1; +			unsigned port_reset_change:1; +			unsigned port_enable_change:1; +			unsigned port_suspend_change:1; +			unsigned port_over_current_change:1; +			unsigned port_l1_change:1; +			unsigned reserved:26; +		} b; +	} flags; + +	struct list_head non_periodic_sched_inactive; +	struct list_head non_periodic_sched_active; +	struct list_head *non_periodic_qh_ptr; +	struct list_head periodic_sched_inactive; +	struct list_head periodic_sched_ready; +	struct list_head periodic_sched_assigned; +	struct list_head periodic_sched_queued; +	u16 periodic_usecs; +	u16 frame_usecs[8]; +	u16 frame_number; +	u16 periodic_qh_count; + +#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS +#define FRAME_NUM_ARRAY_SIZE 1000 +	u16 last_frame_num; +	u16 *frame_num_array; +	u16 *last_frame_num_array; +	int frame_num_idx; +	int dumped_frame_num_array; +#endif + +	struct list_head free_hc_list; +	int periodic_channels; +	int non_periodic_channels; +	int available_host_channels; +	struct dwc2_host_chan *hc_ptr_array[MAX_EPS_CHANNELS]; +	u8 *status_buf; +	dma_addr_t status_buf_dma; +#define DWC2_HCD_STATUS_BUF_SIZE 64 + +	struct delayed_work start_work; +	struct delayed_work reset_work; +	spinlock_t lock; +	void *priv; +	u8 otg_port; +	u32 *frame_list; +	dma_addr_t frame_list_dma; + +	/* DWC OTG HW Release versions */ +#define DWC2_CORE_REV_2_71a	0x4f54271a +#define DWC2_CORE_REV_2_90a	0x4f54290a +#define DWC2_CORE_REV_2_92a	0x4f54292a +#define DWC2_CORE_REV_2_94a	0x4f54294a +#define DWC2_CORE_REV_3_00a	0x4f54300a + +#ifdef DEBUG +	u32 frrem_samples; +	u64 frrem_accum; + +	u32 hfnum_7_samples_a; +	u64 hfnum_7_frrem_accum_a; +	u32 hfnum_0_samples_a; +	u64 hfnum_0_frrem_accum_a; +	u32 hfnum_other_samples_a; +	u64 hfnum_other_frrem_accum_a; + +	u32 hfnum_7_samples_b; +	u64 hfnum_7_frrem_accum_b; +	u32 hfnum_0_samples_b; +	u64 hfnum_0_frrem_accum_b; +	u32 hfnum_other_samples_b; +	u64 hfnum_other_frrem_accum_b; +#endif +}; + +/* Reasons for halting a host channel */ +enum dwc2_halt_status { +	DWC2_HC_XFER_NO_HALT_STATUS, +	DWC2_HC_XFER_COMPLETE, +	DWC2_HC_XFER_URB_COMPLETE, +	DWC2_HC_XFER_ACK, +	DWC2_HC_XFER_NAK, +	DWC2_HC_XFER_NYET, +	DWC2_HC_XFER_STALL, +	DWC2_HC_XFER_XACT_ERR, +	DWC2_HC_XFER_FRAME_OVERRUN, +	DWC2_HC_XFER_BABBLE_ERR, +	DWC2_HC_XFER_DATA_TOGGLE_ERR, +	DWC2_HC_XFER_AHB_ERR, +	DWC2_HC_XFER_PERIODIC_INCOMPLETE, +	DWC2_HC_XFER_URB_DEQUEUE, +}; + +/* + * The following functions support initialization of the core driver component + * and the DWC_otg controller + */ +extern void dwc2_core_host_init(struct dwc2_hsotg *hsotg); + +/* + * Host core Functions. + * The following functions support managing the DWC_otg controller in host + * mode. + */ +extern void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan); +extern void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan, +			 enum dwc2_halt_status halt_status); +extern void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, +			    struct dwc2_host_chan *chan); +extern void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, +				   struct dwc2_host_chan *chan); +extern void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg, +					struct dwc2_host_chan *chan); +extern int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg, +				     struct dwc2_host_chan *chan); +extern void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg, +			    struct dwc2_host_chan *chan); +extern void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg); +extern void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg); + +extern u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg); +extern bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg); + +/* + * Common core Functions. + * The following functions support managing the DWC_otg controller in either + * device or host mode. + */ +extern void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes); +extern void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num); +extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg); + +extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq); +extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd); +extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd); + +/* This function should be called on every hardware interrupt. */ +extern irqreturn_t dwc2_handle_common_intr(int irq, void *dev); + +/* OTG Core Parameters */ + +/* + * Specifies the OTG capabilities. The driver will automatically + * detect the value for this parameter if none is specified. + * 0 - HNP and SRP capable (default) + * 1 - SRP Only capable + * 2 - No HNP/SRP capable + */ +extern void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg, int val); +#define DWC2_CAP_PARAM_HNP_SRP_CAPABLE		0 +#define DWC2_CAP_PARAM_SRP_ONLY_CAPABLE		1 +#define DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE	2 + +/* + * Specifies whether to use slave or DMA mode for accessing the data + * FIFOs. The driver will automatically detect the value for this + * parameter if none is specified. + * 0 - Slave + * 1 - DMA (default, if available) + */ +extern void dwc2_set_param_dma_enable(struct dwc2_hsotg *hsotg, int val); + +/* + * When DMA mode is enabled specifies whether to use + * address DMA or DMA Descritor mode for accessing the data + * FIFOs in device mode. The driver will automatically detect + * the value for this parameter if none is specified. + * 0 - address DMA + * 1 - DMA Descriptor(default, if available) + */ +extern void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val); + +/* + * Specifies the maximum speed of operation in host and device mode. + * The actual speed depends on the speed of the attached device and + * the value of phy_type. The actual speed depends on the speed of the + * attached device. + * 0 - High Speed (default) + * 1 - Full Speed + */ +extern void dwc2_set_param_speed(struct dwc2_hsotg *hsotg, int val); +#define DWC2_SPEED_PARAM_HIGH	0 +#define DWC2_SPEED_PARAM_FULL	1 + +/* + * Specifies whether low power mode is supported when attached + * to a Full Speed or Low Speed device in host mode. + * + * 0 - Don't support low power mode (default) + * 1 - Support low power mode + */ +extern void dwc2_set_param_host_support_fs_ls_low_power( +		struct dwc2_hsotg *hsotg, int val); + +/* + * Specifies the PHY clock rate in low power mode when connected to a + * Low Speed device in host mode. This parameter is applicable only if + * HOST_SUPPORT_FS_LS_LOW_POWER is enabled. If PHY_TYPE is set to FS + * then defaults to 6 MHZ otherwise 48 MHZ. + * + * 0 - 48 MHz + * 1 - 6 MHz + */ +extern void dwc2_set_param_host_ls_low_power_phy_clk(struct dwc2_hsotg *hsotg, +						     int val); +#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ	0 +#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ	1 + +/* + * 0 - Use cC FIFO size parameters + * 1 - Allow dynamic FIFO sizing (default) + */ +extern void dwc2_set_param_enable_dynamic_fifo(struct dwc2_hsotg *hsotg, +					       int val); + +/* + * Number of 4-byte words in the Rx FIFO in host mode when dynamic + * FIFO sizing is enabled. + * 16 to 32768 (default 1024) + */ +extern void dwc2_set_param_host_rx_fifo_size(struct dwc2_hsotg *hsotg, int val); + +/* + * Number of 4-byte words in the non-periodic Tx FIFO in host mode + * when Dynamic FIFO sizing is enabled in the core. + * 16 to 32768 (default 256) + */ +extern void dwc2_set_param_host_nperio_tx_fifo_size(struct dwc2_hsotg *hsotg, +						    int val); + +/* + * Number of 4-byte words in the host periodic Tx FIFO when dynamic + * FIFO sizing is enabled. + * 16 to 32768 (default 256) + */ +extern void dwc2_set_param_host_perio_tx_fifo_size(struct dwc2_hsotg *hsotg, +						   int val); + +/* + * The maximum transfer size supported in bytes. + * 2047 to 65,535  (default 65,535) + */ +extern void dwc2_set_param_max_transfer_size(struct dwc2_hsotg *hsotg, int val); + +/* + * The maximum number of packets in a transfer. + * 15 to 511  (default 511) + */ +extern void dwc2_set_param_max_packet_count(struct dwc2_hsotg *hsotg, int val); + +/* + * The number of host channel registers to use. + * 1 to 16 (default 11) + * Note: The FPGA configuration supports a maximum of 11 host channels. + */ +extern void dwc2_set_param_host_channels(struct dwc2_hsotg *hsotg, int val); + +/* + * Specifies the type of PHY interface to use. By default, the driver + * will automatically detect the phy_type. + * + * 0 - Full Speed PHY + * 1 - UTMI+ (default) + * 2 - ULPI + */ +extern void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val); +#define DWC2_PHY_TYPE_PARAM_FS		0 +#define DWC2_PHY_TYPE_PARAM_UTMI	1 +#define DWC2_PHY_TYPE_PARAM_ULPI	2 + +/* + * Specifies the UTMI+ Data Width. This parameter is + * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI + * PHY_TYPE, this parameter indicates the data width between + * the MAC and the ULPI Wrapper.) Also, this parameter is + * applicable only if the OTG_HSPHY_WIDTH cC parameter was set + * to "8 and 16 bits", meaning that the core has been + * configured to work at either data path width. + * + * 8 or 16 bits (default 16) + */ +extern void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg, int val); + +/* + * Specifies whether the ULPI operates at double or single + * data rate. This parameter is only applicable if PHY_TYPE is + * ULPI. + * + * 0 - single data rate ULPI interface with 8 bit wide data + * bus (default) + * 1 - double data rate ULPI interface with 4 bit wide data + * bus + */ +extern void dwc2_set_param_phy_ulpi_ddr(struct dwc2_hsotg *hsotg, int val); + +/* + * Specifies whether to use the internal or external supply to + * drive the vbus with a ULPI phy. + */ +extern void dwc2_set_param_phy_ulpi_ext_vbus(struct dwc2_hsotg *hsotg, int val); +#define DWC2_PHY_ULPI_INTERNAL_VBUS	0 +#define DWC2_PHY_ULPI_EXTERNAL_VBUS	1 + +/* + * Specifies whether to use the I2Cinterface for full speed PHY. This + * parameter is only applicable if PHY_TYPE is FS. + * 0 - No (default) + * 1 - Yes + */ +extern void dwc2_set_param_i2c_enable(struct dwc2_hsotg *hsotg, int val); + +extern void dwc2_set_param_ulpi_fs_ls(struct dwc2_hsotg *hsotg, int val); + +extern void dwc2_set_param_ts_dline(struct dwc2_hsotg *hsotg, int val); + +/* + * Specifies whether dedicated transmit FIFOs are + * enabled for non periodic IN endpoints in device mode + * 0 - No + * 1 - Yes + */ +extern void dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg, +					       int val); + +extern void dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val); + +extern void dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val); + +extern void dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val); + +/* + * Dump core registers and SPRAM + */ +extern void dwc2_dump_dev_registers(struct dwc2_hsotg *hsotg); +extern void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg); +extern void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg); + +/* + * Return OTG version - either 1.3 or 2.0 + */ +extern u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg); + +#endif /* __DWC2_CORE_H__ */ diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c new file mode 100644 index 00000000000..c93918b70d0 --- /dev/null +++ b/drivers/usb/dwc2/core_intr.c @@ -0,0 +1,511 @@ +/* + * core_intr.c - DesignWare HS OTG Controller common interrupt handling + * + * Copyright (C) 2004-2013 Synopsys, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + *    to endorse or promote products derived from this software without + *    specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file contains the common interrupt handlers + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include <linux/usb/hcd.h> +#include <linux/usb/ch11.h> + +#include "core.h" +#include "hcd.h" + +static const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg) +{ +	switch (hsotg->op_state) { +	case OTG_STATE_A_HOST: +		return "a_host"; +	case OTG_STATE_A_SUSPEND: +		return "a_suspend"; +	case OTG_STATE_A_PERIPHERAL: +		return "a_peripheral"; +	case OTG_STATE_B_PERIPHERAL: +		return "b_peripheral"; +	case OTG_STATE_B_HOST: +		return "b_host"; +	default: +		return "unknown"; +	} +} + +/** + * dwc2_handle_usb_port_intr - handles OTG PRTINT interrupts. + * When the PRTINT interrupt fires, there are certain status bits in the Host + * Port that needs to get cleared. + * + * @hsotg: Programming view of DWC_otg controller + */ +static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg) +{ +	u32 hprt0 = readl(hsotg->regs + HPRT0); + +	if (hprt0 & HPRT0_ENACHG) { +		hprt0 &= ~HPRT0_ENA; +		writel(hprt0, hsotg->regs + HPRT0); +	} + +	/* Clear interrupt */ +	writel(GINTSTS_PRTINT, hsotg->regs + GINTSTS); +} + +/** + * dwc2_handle_mode_mismatch_intr() - Logs a mode mismatch warning message + * + * @hsotg: Programming view of DWC_otg controller + */ +static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg) +{ +	dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n", +		 dwc2_is_host_mode(hsotg) ? "Host" : "Device"); + +	/* Clear interrupt */ +	writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS); +} + +/** + * dwc2_handle_otg_intr() - Handles the OTG Interrupts. It reads the OTG + * Interrupt Register (GOTGINT) to determine what interrupt has occurred. + * + * @hsotg: Programming view of DWC_otg controller + */ +static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg) +{ +	u32 gotgint; +	u32 gotgctl; +	u32 gintmsk; + +	gotgint = readl(hsotg->regs + GOTGINT); +	gotgctl = readl(hsotg->regs + GOTGCTL); +	dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint, +		dwc2_op_state_str(hsotg)); + +	if (gotgint & GOTGINT_SES_END_DET) { +		dev_dbg(hsotg->dev, +			" ++OTG Interrupt: Session End Detected++ (%s)\n", +			dwc2_op_state_str(hsotg)); +		gotgctl = readl(hsotg->regs + GOTGCTL); + +		if (hsotg->op_state == OTG_STATE_B_HOST) { +			hsotg->op_state = OTG_STATE_B_PERIPHERAL; +		} else { +			/* +			 * If not B_HOST and Device HNP still set, HNP did +			 * not succeed! +			 */ +			if (gotgctl & GOTGCTL_DEVHNPEN) { +				dev_dbg(hsotg->dev, "Session End Detected\n"); +				dev_err(hsotg->dev, +					"Device Not Connected/Responding!\n"); +			} + +			/* +			 * If Session End Detected the B-Cable has been +			 * disconnected +			 */ +			/* Reset to a clean state */ +			hsotg->lx_state = DWC2_L0; +		} + +		gotgctl = readl(hsotg->regs + GOTGCTL); +		gotgctl &= ~GOTGCTL_DEVHNPEN; +		writel(gotgctl, hsotg->regs + GOTGCTL); +	} + +	if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) { +		dev_dbg(hsotg->dev, +			" ++OTG Interrupt: Session Request Success Status Change++\n"); +		gotgctl = readl(hsotg->regs + GOTGCTL); +		if (gotgctl & GOTGCTL_SESREQSCS) { +			if (hsotg->core_params->phy_type == +					DWC2_PHY_TYPE_PARAM_FS +			    && hsotg->core_params->i2c_enable > 0) { +				hsotg->srp_success = 1; +			} else { +				/* Clear Session Request */ +				gotgctl = readl(hsotg->regs + GOTGCTL); +				gotgctl &= ~GOTGCTL_SESREQ; +				writel(gotgctl, hsotg->regs + GOTGCTL); +			} +		} +	} + +	if (gotgint & GOTGINT_HST_NEG_SUC_STS_CHNG) { +		/* +		 * Print statements during the HNP interrupt handling +		 * can cause it to fail +		 */ +		gotgctl = readl(hsotg->regs + GOTGCTL); +		/* +		 * WA for 3.00a- HW is not setting cur_mode, even sometimes +		 * this does not help +		 */ +		if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a) +			udelay(100); +		if (gotgctl & GOTGCTL_HSTNEGSCS) { +			if (dwc2_is_host_mode(hsotg)) { +				hsotg->op_state = OTG_STATE_B_HOST; +				/* +				 * Need to disable SOF interrupt immediately. +				 * When switching from device to host, the PCD +				 * interrupt handler won't handle the interrupt +				 * if host mode is already set. The HCD +				 * interrupt handler won't get called if the +				 * HCD state is HALT. This means that the +				 * interrupt does not get handled and Linux +				 * complains loudly. +				 */ +				gintmsk = readl(hsotg->regs + GINTMSK); +				gintmsk &= ~GINTSTS_SOF; +				writel(gintmsk, hsotg->regs + GINTMSK); + +				/* +				 * Call callback function with spin lock +				 * released +				 */ +				spin_unlock(&hsotg->lock); + +				/* Initialize the Core for Host mode */ +				dwc2_hcd_start(hsotg); +				spin_lock(&hsotg->lock); +				hsotg->op_state = OTG_STATE_B_HOST; +			} +		} else { +			gotgctl = readl(hsotg->regs + GOTGCTL); +			gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN); +			writel(gotgctl, hsotg->regs + GOTGCTL); +			dev_dbg(hsotg->dev, "HNP Failed\n"); +			dev_err(hsotg->dev, +				"Device Not Connected/Responding\n"); +		} +	} + +	if (gotgint & GOTGINT_HST_NEG_DET) { +		/* +		 * The disconnect interrupt is set at the same time as +		 * Host Negotiation Detected. During the mode switch all +		 * interrupts are cleared so the disconnect interrupt +		 * handler will not get executed. +		 */ +		dev_dbg(hsotg->dev, +			" ++OTG Interrupt: Host Negotiation Detected++ (%s)\n", +			(dwc2_is_host_mode(hsotg) ? "Host" : "Device")); +		if (dwc2_is_device_mode(hsotg)) { +			dev_dbg(hsotg->dev, "a_suspend->a_peripheral (%d)\n", +				hsotg->op_state); +			spin_unlock(&hsotg->lock); +			dwc2_hcd_disconnect(hsotg); +			spin_lock(&hsotg->lock); +			hsotg->op_state = OTG_STATE_A_PERIPHERAL; +		} else { +			/* Need to disable SOF interrupt immediately */ +			gintmsk = readl(hsotg->regs + GINTMSK); +			gintmsk &= ~GINTSTS_SOF; +			writel(gintmsk, hsotg->regs + GINTMSK); +			spin_unlock(&hsotg->lock); +			dwc2_hcd_start(hsotg); +			spin_lock(&hsotg->lock); +			hsotg->op_state = OTG_STATE_A_HOST; +		} +	} + +	if (gotgint & GOTGINT_A_DEV_TOUT_CHG) +		dev_dbg(hsotg->dev, +			" ++OTG Interrupt: A-Device Timeout Change++\n"); +	if (gotgint & GOTGINT_DBNCE_DONE) +		dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n"); + +	/* Clear GOTGINT */ +	writel(gotgint, hsotg->regs + GOTGINT); +} + +/** + * dwc2_handle_conn_id_status_change_intr() - Handles the Connector ID Status + * Change Interrupt + * + * @hsotg: Programming view of DWC_otg controller + * + * Reads the OTG Interrupt Register (GOTCTL) to determine whether this is a + * Device to Host Mode transition or a Host to Device Mode transition. This only + * occurs when the cable is connected/removed from the PHY connector. + */ +static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg) +{ +	u32 gintmsk = readl(hsotg->regs + GINTMSK); + +	/* Need to disable SOF interrupt immediately */ +	gintmsk &= ~GINTSTS_SOF; +	writel(gintmsk, hsotg->regs + GINTMSK); + +	dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++  (%s)\n", +		dwc2_is_host_mode(hsotg) ? "Host" : "Device"); + +	/* +	 * Need to schedule a work, as there are possible DELAY function calls. +	 * Release lock before scheduling workq as it holds spinlock during +	 * scheduling. +	 */ +	spin_unlock(&hsotg->lock); +	queue_work(hsotg->wq_otg, &hsotg->wf_otg); +	spin_lock(&hsotg->lock); + +	/* Clear interrupt */ +	writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS); +} + +/** + * dwc2_handle_session_req_intr() - This interrupt indicates that a device is + * initiating the Session Request Protocol to request the host to turn on bus + * power so a new session can begin + * + * @hsotg: Programming view of DWC_otg controller + * + * This handler responds by turning on bus power. If the DWC_otg controller is + * in low power mode, this handler brings the controller out of low power mode + * before turning on bus power. + */ +static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg) +{ +	dev_dbg(hsotg->dev, "++Session Request Interrupt++\n"); + +	/* Clear interrupt */ +	writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS); +} + +/* + * This interrupt indicates that the DWC_otg controller has detected a + * resume or remote wakeup sequence. If the DWC_otg controller is in + * low power mode, the handler must brings the controller out of low + * power mode. The controller automatically begins resume signaling. + * The handler schedules a time to stop resume signaling. + */ +static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) +{ +	dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n"); +	dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state); + +	if (dwc2_is_device_mode(hsotg)) { +		dev_dbg(hsotg->dev, "DSTS=0x%0x\n", readl(hsotg->regs + DSTS)); +		if (hsotg->lx_state == DWC2_L2) { +			u32 dctl = readl(hsotg->regs + DCTL); + +			/* Clear Remote Wakeup Signaling */ +			dctl &= ~DCTL_RMTWKUPSIG; +			writel(dctl, hsotg->regs + DCTL); +		} +		/* Change to L0 state */ +		hsotg->lx_state = DWC2_L0; +	} else { +		if (hsotg->lx_state != DWC2_L1) { +			u32 pcgcctl = readl(hsotg->regs + PCGCTL); + +			/* Restart the Phy Clock */ +			pcgcctl &= ~PCGCTL_STOPPCLK; +			writel(pcgcctl, hsotg->regs + PCGCTL); +			mod_timer(&hsotg->wkp_timer, +				  jiffies + msecs_to_jiffies(71)); +		} else { +			/* Change to L0 state */ +			hsotg->lx_state = DWC2_L0; +		} +	} + +	/* Clear interrupt */ +	writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS); +} + +/* + * This interrupt indicates that a device has been disconnected from the + * root port + */ +static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg) +{ +	dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n", +		dwc2_is_host_mode(hsotg) ? "Host" : "Device", +		dwc2_op_state_str(hsotg)); + +	/* Change to L3 (OFF) state */ +	hsotg->lx_state = DWC2_L3; + +	writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS); +} + +/* + * This interrupt indicates that SUSPEND state has been detected on the USB. + * + * For HNP the USB Suspend interrupt signals the change from "a_peripheral" + * to "a_host". + * + * When power management is enabled the core will be put in low power mode. + */ +static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) +{ +	u32 dsts; + +	dev_dbg(hsotg->dev, "USB SUSPEND\n"); + +	if (dwc2_is_device_mode(hsotg)) { +		/* +		 * Check the Device status register to determine if the Suspend +		 * state is active +		 */ +		dsts = readl(hsotg->regs + DSTS); +		dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dsts); +		dev_dbg(hsotg->dev, +			"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n", +			!!(dsts & DSTS_SUSPSTS), +			hsotg->hw_params.power_optimized); +	} else { +		if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) { +			dev_dbg(hsotg->dev, "a_peripheral->a_host\n"); + +			/* Clear the a_peripheral flag, back to a_host */ +			spin_unlock(&hsotg->lock); +			dwc2_hcd_start(hsotg); +			spin_lock(&hsotg->lock); +			hsotg->op_state = OTG_STATE_A_HOST; +		} +	} + +	/* Change to L2 (suspend) state */ +	hsotg->lx_state = DWC2_L2; + +	/* Clear interrupt */ +	writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS); +} + +#define GINTMSK_COMMON	(GINTSTS_WKUPINT | GINTSTS_SESSREQINT |		\ +			 GINTSTS_CONIDSTSCHNG | GINTSTS_OTGINT |	\ +			 GINTSTS_MODEMIS | GINTSTS_DISCONNINT |		\ +			 GINTSTS_USBSUSP | GINTSTS_PRTINT) + +/* + * This function returns the Core Interrupt register + */ +static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg) +{ +	u32 gintsts; +	u32 gintmsk; +	u32 gahbcfg; +	u32 gintmsk_common = GINTMSK_COMMON; + +	gintsts = readl(hsotg->regs + GINTSTS); +	gintmsk = readl(hsotg->regs + GINTMSK); +	gahbcfg = readl(hsotg->regs + GAHBCFG); + +	/* If any common interrupts set */ +	if (gintsts & gintmsk_common) +		dev_dbg(hsotg->dev, "gintsts=%08x  gintmsk=%08x\n", +			gintsts, gintmsk); + +	if (gahbcfg & GAHBCFG_GLBL_INTR_EN) +		return gintsts & gintmsk & gintmsk_common; +	else +		return 0; +} + +/* + * Common interrupt handler + * + * The common interrupts are those that occur in both Host and Device mode. + * This handler handles the following interrupts: + * - Mode Mismatch Interrupt + * - OTG Interrupt + * - Connector ID Status Change Interrupt + * - Disconnect Interrupt + * - Session Request Interrupt + * - Resume / Remote Wakeup Detected Interrupt + * - Suspend Interrupt + */ +irqreturn_t dwc2_handle_common_intr(int irq, void *dev) +{ +	struct dwc2_hsotg *hsotg = dev; +	u32 gintsts; +	irqreturn_t retval = IRQ_NONE; + +	if (!dwc2_is_controller_alive(hsotg)) { +		dev_warn(hsotg->dev, "Controller is dead\n"); +		goto out; +	} + +	spin_lock(&hsotg->lock); + +	gintsts = dwc2_read_common_intr(hsotg); +	if (gintsts & ~GINTSTS_PRTINT) +		retval = IRQ_HANDLED; + +	if (gintsts & GINTSTS_MODEMIS) +		dwc2_handle_mode_mismatch_intr(hsotg); +	if (gintsts & GINTSTS_OTGINT) +		dwc2_handle_otg_intr(hsotg); +	if (gintsts & GINTSTS_CONIDSTSCHNG) +		dwc2_handle_conn_id_status_change_intr(hsotg); +	if (gintsts & GINTSTS_DISCONNINT) +		dwc2_handle_disconnect_intr(hsotg); +	if (gintsts & GINTSTS_SESSREQINT) +		dwc2_handle_session_req_intr(hsotg); +	if (gintsts & GINTSTS_WKUPINT) +		dwc2_handle_wakeup_detected_intr(hsotg); +	if (gintsts & GINTSTS_USBSUSP) +		dwc2_handle_usb_suspend_intr(hsotg); + +	if (gintsts & GINTSTS_PRTINT) { +		/* +		 * The port interrupt occurs while in device mode with HPRT0 +		 * Port Enable/Disable +		 */ +		if (dwc2_is_device_mode(hsotg)) { +			dev_dbg(hsotg->dev, +				" --Port interrupt received in Device mode--\n"); +			dwc2_handle_usb_port_intr(hsotg); +			retval = IRQ_HANDLED; +		} +	} + +	spin_unlock(&hsotg->lock); +out: +	return retval; +} +EXPORT_SYMBOL_GPL(dwc2_handle_common_intr); diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/dwc2/gadget.c index d69b36a99db..f3c56a2fed5 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/dwc2/gadget.c @@ -30,173 +30,14 @@  #include <linux/clk.h>  #include <linux/regulator/consumer.h>  #include <linux/of_platform.h> +#include <linux/phy/phy.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h>  #include <linux/usb/phy.h>  #include <linux/platform_data/s3c-hsotg.h> -#include <mach/map.h> - -#include "s3c-hsotg.h" - -static const char * const s3c_hsotg_supply_names[] = { -	"vusb_d",		/* digital USB supply, 1.2V */ -	"vusb_a",		/* analog USB supply, 1.1V */ -}; - -/* - * EP0_MPS_LIMIT - * - * Unfortunately there seems to be a limit of the amount of data that can - * be transferred by IN transactions on EP0. This is either 127 bytes or 3 - * packets (which practically means 1 packet and 63 bytes of data) when the - * MPS is set to 64. - * - * This means if we are wanting to move >127 bytes of data, we need to - * split the transactions up, but just doing one packet at a time does - * not work (this may be an implicit DATA0 PID on first packet of the - * transaction) and doing 2 packets is outside the controller's limits. - * - * If we try to lower the MPS size for EP0, then no transfers work properly - * for EP0, and the system will fail basic enumeration. As no cause for this - * has currently been found, we cannot support any large IN transfers for - * EP0. - */ -#define EP0_MPS_LIMIT	64 - -struct s3c_hsotg; -struct s3c_hsotg_req; - -/** - * struct s3c_hsotg_ep - driver endpoint definition. - * @ep: The gadget layer representation of the endpoint. - * @name: The driver generated name for the endpoint. - * @queue: Queue of requests for this endpoint. - * @parent: Reference back to the parent device structure. - * @req: The current request that the endpoint is processing. This is - *       used to indicate an request has been loaded onto the endpoint - *       and has yet to be completed (maybe due to data move, or simply - *	 awaiting an ack from the core all the data has been completed). - * @debugfs: File entry for debugfs file for this endpoint. - * @lock: State lock to protect contents of endpoint. - * @dir_in: Set to true if this endpoint is of the IN direction, which - *	    means that it is sending data to the Host. - * @index: The index for the endpoint registers. - * @name: The name array passed to the USB core. - * @halted: Set if the endpoint has been halted. - * @periodic: Set if this is a periodic ep, such as Interrupt - * @sent_zlp: Set if we've sent a zero-length packet. - * @total_data: The total number of data bytes done. - * @fifo_size: The size of the FIFO (for periodic IN endpoints) - * @fifo_load: The amount of data loaded into the FIFO (periodic IN) - * @last_load: The offset of data for the last start of request. - * @size_loaded: The last loaded size for DxEPTSIZE for periodic IN - * - * This is the driver's state for each registered enpoint, allowing it - * to keep track of transactions that need doing. Each endpoint has a - * lock to protect the state, to try and avoid using an overall lock - * for the host controller as much as possible. - * - * For periodic IN endpoints, we have fifo_size and fifo_load to try - * and keep track of the amount of data in the periodic FIFO for each - * of these as we don't have a status register that tells us how much - * is in each of them. (note, this may actually be useless information - * as in shared-fifo mode periodic in acts like a single-frame packet - * buffer than a fifo) - */ -struct s3c_hsotg_ep { -	struct usb_ep		ep; -	struct list_head	queue; -	struct s3c_hsotg	*parent; -	struct s3c_hsotg_req	*req; -	struct dentry		*debugfs; - - -	unsigned long		total_data; -	unsigned int		size_loaded; -	unsigned int		last_load; -	unsigned int		fifo_load; -	unsigned short		fifo_size; - -	unsigned char		dir_in; -	unsigned char		index; - -	unsigned int		halted:1; -	unsigned int		periodic:1; -	unsigned int		sent_zlp:1; - -	char			name[10]; -}; - -/** - * struct s3c_hsotg - driver state. - * @dev: The parent device supplied to the probe function - * @driver: USB gadget driver - * @phy: The otg phy transceiver structure for phy control. - * @plat: The platform specific configuration data. This can be removed once - * all SoCs support usb transceiver. - * @regs: The memory area mapped for accessing registers. - * @irq: The IRQ number we are using - * @supplies: Definition of USB power supplies - * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. - * @num_of_eps: Number of available EPs (excluding EP0) - * @debug_root: root directrory for debugfs. - * @debug_file: main status file for debugfs. - * @debug_fifo: FIFO status file for debugfs. - * @ep0_reply: Request used for ep0 reply. - * @ep0_buff: Buffer for EP0 reply data, if needed. - * @ctrl_buff: Buffer for EP0 control requests. - * @ctrl_req: Request for EP0 control packets. - * @setup: NAK management for EP0 SETUP - * @last_rst: Time of last reset - * @eps: The endpoints being supplied to the gadget framework - */ -struct s3c_hsotg { -	struct device		 *dev; -	struct usb_gadget_driver *driver; -	struct usb_phy		*phy; -	struct s3c_hsotg_plat	 *plat; - -	spinlock_t              lock; - -	void __iomem		*regs; -	int			irq; -	struct clk		*clk; - -	struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; - -	unsigned int		dedicated_fifos:1; -	unsigned char           num_of_eps; - -	struct dentry		*debug_root; -	struct dentry		*debug_file; -	struct dentry		*debug_fifo; - -	struct usb_request	*ep0_reply; -	struct usb_request	*ctrl_req; -	u8			ep0_buff[8]; -	u8			ctrl_buff[8]; - -	struct usb_gadget	gadget; -	unsigned int		setup; -	unsigned long           last_rst; -	struct s3c_hsotg_ep	*eps; -}; - -/** - * struct s3c_hsotg_req - data transfer request - * @req: The USB gadget request - * @queue: The list of requests for the endpoint this is queued for. - * @in_progress: Has already had size/packets written to core - * @mapped: DMA buffer for this request has been mapped via dma_map_single(). - */ -struct s3c_hsotg_req { -	struct usb_request	req; -	struct list_head	queue; -	unsigned char		in_progress; -	unsigned char		mapped; -}; +#include "core.h"  /* conversion functions */  static inline struct s3c_hsotg_req *our_req(struct usb_request *req) @@ -331,9 +172,8 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)  	/* set FIFO sizes to 2048/1024 */  	writel(2048, hsotg->regs + GRXFSIZ); -	writel(GNPTXFSIZ_NPTxFStAddr(2048) | -	       GNPTXFSIZ_NPTxFDep(1024), -	       hsotg->regs + GNPTXFSIZ); +	writel((2048 << FIFOSIZE_STARTADDR_SHIFT) | +		(1024 << FIFOSIZE_DEPTH_SHIFT), hsotg->regs + GNPTXFSIZ);  	/*  	 * arange all the rest of the TX FIFOs, as some versions of this @@ -353,10 +193,10 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)  	for (ep = 1; ep <= 15; ep++) {  		val = addr; -		val |= size << DPTXFSIZn_DPTxFSize_SHIFT; +		val |= size << FIFOSIZE_DEPTH_SHIFT;  		addr += size; -		writel(val, hsotg->regs + DPTXFSIZn(ep)); +		writel(val, hsotg->regs + DPTXFSIZN(ep));  	}  	/* @@ -364,15 +204,15 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)  	 * all fifos are flushed before continuing  	 */ -	writel(GRSTCTL_TxFNum(0x10) | GRSTCTL_TxFFlsh | -	       GRSTCTL_RxFFlsh, hsotg->regs + GRSTCTL); +	writel(GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH | +	       GRSTCTL_RXFFLSH, hsotg->regs + GRSTCTL);  	/* wait until the fifos are both flushed */  	timeout = 100;  	while (1) {  		val = readl(hsotg->regs + GRSTCTL); -		if ((val & (GRSTCTL_TxFFlsh | GRSTCTL_RxFFlsh)) == 0) +		if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0)  			break;  		if (--timeout == 0) { @@ -468,6 +308,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,  	void *data;  	int can_write;  	int pkt_round; +	int max_transfer;  	to_write -= (buf_pos - hs_ep->last_load); @@ -485,14 +326,14 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,  		 * how much data is left in the fifo.  		 */ -		size_left = DxEPTSIZ_XferSize_GET(epsize); +		size_left = DXEPTSIZ_XFERSIZE_GET(epsize);  		/*  		 * if shared fifo, we cannot write anything until the  		 * previous data has been completely sent.  		 */  		if (hs_ep->fifo_load != 0) { -			s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); +			s3c_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP);  			return -ENOSPC;  		} @@ -513,7 +354,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,  			__func__, can_write);  		if (can_write <= 0) { -			s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); +			s3c_hsotg_en_gsint(hsotg, GINTSTS_PTXFEMP);  			return -ENOSPC;  		}  	} else if (hsotg->dedicated_fifos && hs_ep->index != 0) { @@ -522,28 +363,30 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,  		can_write &= 0xffff;  		can_write *= 4;  	} else { -		if (GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { +		if (GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(gnptxsts) == 0) {  			dev_dbg(hsotg->dev,  				"%s: no queue slots available (0x%08x)\n",  				__func__, gnptxsts); -			s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTxFEmp); +			s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTXFEMP);  			return -ENOSPC;  		} -		can_write = GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts); +		can_write = GNPTXSTS_NP_TXF_SPC_AVAIL_GET(gnptxsts);  		can_write *= 4;	/* fifo size is in 32bit quantities. */  	} -	dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n", -		 __func__, gnptxsts, can_write, to_write, hs_ep->ep.maxpacket); +	max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; + +	dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", +		 __func__, gnptxsts, can_write, to_write, max_transfer);  	/*  	 * limit to 512 bytes of data, it seems at least on the non-periodic  	 * FIFO, requests of >512 cause the endpoint to get stuck with a  	 * fragment of the end of the transfer in it.  	 */ -	if (can_write > 512) +	if (can_write > 512 && !periodic)  		can_write = 512;  	/* @@ -551,19 +394,21 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,  	 * the transfer to return that it did not run out of fifo space  	 * doing it.  	 */ -	if (to_write > hs_ep->ep.maxpacket) { -		to_write = hs_ep->ep.maxpacket; +	if (to_write > max_transfer) { +		to_write = max_transfer; -		s3c_hsotg_en_gsint(hsotg, -				   periodic ? GINTSTS_PTxFEmp : -				   GINTSTS_NPTxFEmp); +		/* it's needed only when we do not use dedicated fifos */ +		if (!hsotg->dedicated_fifos) +			s3c_hsotg_en_gsint(hsotg, +					   periodic ? GINTSTS_PTXFEMP : +					   GINTSTS_NPTXFEMP);  	}  	/* see if we can write data */  	if (to_write > can_write) {  		to_write = can_write; -		pkt_round = to_write % hs_ep->ep.maxpacket; +		pkt_round = to_write % max_transfer;  		/*  		 * Round the write down to an @@ -581,9 +426,11 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,  		 * is more room left.  		 */ -		s3c_hsotg_en_gsint(hsotg, -				   periodic ? GINTSTS_PTxFEmp : -				   GINTSTS_NPTxFEmp); +		/* it's needed only when we do not use dedicated fifos */ +		if (!hsotg->dedicated_fifos) +			s3c_hsotg_en_gsint(hsotg, +					   periodic ? GINTSTS_PTXFEMP : +					   GINTSTS_NPTXFEMP);  	}  	dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", @@ -601,7 +448,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,  	to_write = DIV_ROUND_UP(to_write, 4);  	data = hs_req->req.buf + buf_pos; -	writesl(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); +	iowrite32_rep(hsotg->regs + EPFIFO(hs_ep->index), data, to_write);  	return (to_write >= can_write) ? -ENOSPC : 0;  } @@ -620,12 +467,12 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep)  	unsigned maxpkt;  	if (index != 0) { -		maxsize = DxEPTSIZ_XferSize_LIMIT + 1; -		maxpkt = DxEPTSIZ_PktCnt_LIMIT + 1; +		maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; +		maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1;  	} else {  		maxsize = 64+64;  		if (hs_ep->dir_in) -			maxpkt = DIEPTSIZ0_PktCnt_LIMIT + 1; +			maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1;  		else  			maxpkt = 2;  	} @@ -694,7 +541,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,  	/* If endpoint is stalled, we will restart request later */  	ctrl = readl(hsotg->regs + epctrl_reg); -	if (ctrl & DxEPCTL_Stall) { +	if (ctrl & DXEPCTL_STALL) {  		dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index);  		return;  	} @@ -704,8 +551,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,  		ureq->length, ureq->actual);  	if (0)  		dev_dbg(hsotg->dev, -			"REQ buf %p len %d dma 0x%08x noi=%d zp=%d snok=%d\n", -			ureq->buf, length, ureq->dma, +			"REQ buf %p len %d dma %pad noi=%d zp=%d snok=%d\n", +			ureq->buf, length, &ureq->dma,  			ureq->no_interrupt, ureq->zero, ureq->short_not_ok);  	maxreq = get_ep_limit(hs_ep); @@ -727,8 +574,16 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,  	else  		packets = 1;	/* send one packet if length is zero. */ +	if (hs_ep->isochronous && length > (hs_ep->mc * hs_ep->ep.maxpacket)) { +		dev_err(hsotg->dev, "req length > maxpacket*mc\n"); +		return; +	} +  	if (dir_in && index != 0) -		epsize = DxEPTSIZ_MC(1); +		if (hs_ep->isochronous) +			epsize = DXEPTSIZ_MC(packets); +		else +			epsize = DXEPTSIZ_MC(1);  	else  		epsize = 0; @@ -742,8 +597,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,  			packets++;  	} -	epsize |= DxEPTSIZ_PktCnt(packets); -	epsize |= DxEPTSIZ_XferSize(length); +	epsize |= DXEPTSIZ_PKTCNT(packets); +	epsize |= DXEPTSIZ_XFERSIZE(length);  	dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n",  		__func__, packets, length, ureq->length, epsize, epsize_reg); @@ -765,12 +620,12 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,  		dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index);  		writel(ureq->dma, hsotg->regs + dma_reg); -		dev_dbg(hsotg->dev, "%s: 0x%08x => 0x%08x\n", -			__func__, ureq->dma, dma_reg); +		dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n", +			__func__, &ureq->dma, dma_reg);  	} -	ctrl |= DxEPCTL_EPEna;	/* ensure ep enabled */ -	ctrl |= DxEPCTL_USBActEp; +	ctrl |= DXEPCTL_EPENA;	/* ensure ep enabled */ +	ctrl |= DXEPCTL_USBACTEP;  	dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup); @@ -778,7 +633,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,  	if (hsotg->setup && index == 0)  		hsotg->setup = 0;  	else -		ctrl |= DxEPCTL_CNAK;	/* clear NAK set by core */ +		ctrl |= DXEPCTL_CNAK;	/* clear NAK set by core */  	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); @@ -804,7 +659,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,  	 * to debugging to see what is going on.  	 */  	if (dir_in) -		writel(DIEPMSK_INTknTXFEmpMsk, +		writel(DIEPMSK_INTKNTXFEMPMSK,  		       hsotg->regs + DIEPINT(index));  	/* @@ -813,13 +668,16 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,  	 */  	/* check ep is enabled */ -	if (!(readl(hsotg->regs + epctrl_reg) & DxEPCTL_EPEna)) +	if (!(readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA))  		dev_warn(hsotg->dev, -			 "ep%d: failed to become enabled (DxEPCTL=0x%08x)?\n", +			 "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n",  			 index, readl(hsotg->regs + epctrl_reg)); -	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", +	dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n",  		__func__, readl(hsotg->regs + epctrl_reg)); + +	/* enable ep interrupts */ +	s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1);  }  /** @@ -1091,6 +949,7 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,  	bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE);  	struct s3c_hsotg_ep *ep;  	int ret; +	bool halted;  	dev_dbg(hsotg->dev, "%s: %s_FEATURE\n",  		__func__, set ? "SET" : "CLEAR"); @@ -1105,6 +964,8 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,  		switch (le16_to_cpu(ctrl->wValue)) {  		case USB_ENDPOINT_HALT: +			halted = ep->halted; +  			s3c_hsotg_ep_sethalt(&ep->ep, set);  			ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0); @@ -1114,7 +975,12 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,  				return ret;  			} -			if (!set) { +			/* +			 * we have to complete all requests for ep if it was +			 * halted, and the halt was cleared by CLEAR_FEATURE +			 */ + +			if (!set && halted) {  				/*  				 * If we have request in progress,  				 * then complete it @@ -1147,6 +1013,44 @@ static int s3c_hsotg_process_req_feature(struct s3c_hsotg *hsotg,  	return 1;  } +static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg); +static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg); + +/** + * s3c_hsotg_stall_ep0 - stall ep0 + * @hsotg: The device state + * + * Set stall for ep0 as response for setup request. + */ +static void s3c_hsotg_stall_ep0(struct s3c_hsotg *hsotg) { +	struct s3c_hsotg_ep *ep0 = &hsotg->eps[0]; +	u32 reg; +	u32 ctrl; + +	dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); +	reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; + +	/* +	 * DxEPCTL_Stall will be cleared by EP once it has +	 * taken effect, so no need to clear later. +	 */ + +	ctrl = readl(hsotg->regs + reg); +	ctrl |= DXEPCTL_STALL; +	ctrl |= DXEPCTL_CNAK; +	writel(ctrl, hsotg->regs + reg); + +	dev_dbg(hsotg->dev, +		"written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n", +		ctrl, reg, readl(hsotg->regs + reg)); + +	 /* +	  * complete won't be called, so we enqueue +	  * setup request here +	  */ +	 s3c_hsotg_enqueue_setup(hsotg); +} +  /**   * s3c_hsotg_process_control - process a control request   * @hsotg: The device state @@ -1187,9 +1091,11 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,  	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {  		switch (ctrl->bRequest) {  		case USB_REQ_SET_ADDRESS: +			s3c_hsotg_disconnect(hsotg);  			dcfg = readl(hsotg->regs + DCFG); -			dcfg &= ~DCFG_DevAddr_MASK; -			dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT; +			dcfg &= ~DCFG_DEVADDR_MASK; +			dcfg |= (le16_to_cpu(ctrl->wValue) << +				 DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK;  			writel(dcfg, hsotg->regs + DCFG);  			dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); @@ -1211,7 +1117,9 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,  	/* as a fallback, try delivering it to the driver to deal with */  	if (ret == 0 && hsotg->driver) { +		spin_unlock(&hsotg->lock);  		ret = hsotg->driver->setup(&hsotg->gadget, ctrl); +		spin_lock(&hsotg->lock);  		if (ret < 0)  			dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret);  	} @@ -1221,36 +1129,10 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg,  	 * so respond with a STALL for the status stage to indicate failure.  	 */ -	if (ret < 0) { -		u32 reg; -		u32 ctrl; - -		dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); -		reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; - -		/* -		 * DxEPCTL_Stall will be cleared by EP once it has -		 * taken effect, so no need to clear later. -		 */ - -		ctrl = readl(hsotg->regs + reg); -		ctrl |= DxEPCTL_Stall; -		ctrl |= DxEPCTL_CNAK; -		writel(ctrl, hsotg->regs + reg); - -		dev_dbg(hsotg->dev, -			"written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n", -			ctrl, reg, readl(hsotg->regs + reg)); - -		/* -		 * don't believe we need to anything more to get the EP -		 * to reply with a STALL packet -		 */ -	} +	if (ret < 0) +		s3c_hsotg_stall_ep0(hsotg);  } -static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg); -  /**   * s3c_hsotg_complete_setup - completion of a setup transfer   * @ep: The endpoint the request was on. @@ -1270,10 +1152,12 @@ static void s3c_hsotg_complete_setup(struct usb_ep *ep,  		return;  	} +	spin_lock(&hsotg->lock);  	if (req->actual == 0)  		s3c_hsotg_enqueue_setup(hsotg);  	else  		s3c_hsotg_process_control(hsotg, req->buf); +	spin_unlock(&hsotg->lock);  }  /** @@ -1406,7 +1290,7 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)  		int ptr;  		dev_warn(hsotg->dev, -			 "%s: FIFO %d bytes on ep%d but no req (DxEPCTl=0x%08x)\n", +			 "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n",  			 __func__, size, ep_idx, epctl);  		/* dump the data from the FIFO, we've nothing we can do */ @@ -1441,7 +1325,7 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)  	 * note, we might over-write the buffer end by 3 bytes depending on  	 * alignment of the data.  	 */ -	readsl(fifo, hs_req->req.buf + read_ptr, to_read); +	ioread32_rep(fifo, hs_req->req.buf + read_ptr, to_read);  }  /** @@ -1478,13 +1362,13 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg,  	dev_dbg(hsotg->dev, "sending zero-length packet\n");  	/* issue a zero-sized packet to terminate this */ -	writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) | -	       DxEPTSIZ_XferSize(0), hsotg->regs + DIEPTSIZ(0)); +	writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | +	       DXEPTSIZ_XFERSIZE(0), hsotg->regs + DIEPTSIZ(0));  	ctrl = readl(hsotg->regs + DIEPCTL0); -	ctrl |= DxEPCTL_CNAK;  /* clear NAK set by core */ -	ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */ -	ctrl |= DxEPCTL_USBActEp; +	ctrl |= DXEPCTL_CNAK;  /* clear NAK set by core */ +	ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */ +	ctrl |= DXEPCTL_USBACTEP;  	writel(ctrl, hsotg->regs + DIEPCTL0);  } @@ -1505,7 +1389,7 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,  	struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum];  	struct s3c_hsotg_req *hs_req = hs_ep->req;  	struct usb_request *req = &hs_req->req; -	unsigned size_left = DxEPTSIZ_XferSize_GET(epsize); +	unsigned size_left = DXEPTSIZ_XFERSIZE_GET(epsize);  	int result = 0;  	if (!hs_req) { @@ -1605,24 +1489,22 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)  	WARN_ON(using_dma(hsotg)); -	epnum = grxstsr & GRXSTS_EPNum_MASK; -	status = grxstsr & GRXSTS_PktSts_MASK; +	epnum = grxstsr & GRXSTS_EPNUM_MASK; +	status = grxstsr & GRXSTS_PKTSTS_MASK; -	size = grxstsr & GRXSTS_ByteCnt_MASK; -	size >>= GRXSTS_ByteCnt_SHIFT; +	size = grxstsr & GRXSTS_BYTECNT_MASK; +	size >>= GRXSTS_BYTECNT_SHIFT;  	if (1)  		dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n",  			__func__, grxstsr, size, epnum); -#define __status(x) ((x) >> GRXSTS_PktSts_SHIFT) - -	switch (status >> GRXSTS_PktSts_SHIFT) { -	case __status(GRXSTS_PktSts_GlobalOutNAK): -		dev_dbg(hsotg->dev, "GlobalOutNAK\n"); +	switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { +	case GRXSTS_PKTSTS_GLOBALOUTNAK: +		dev_dbg(hsotg->dev, "GLOBALOUTNAK\n");  		break; -	case __status(GRXSTS_PktSts_OutDone): +	case GRXSTS_PKTSTS_OUTDONE:  		dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n",  			s3c_hsotg_read_frameno(hsotg)); @@ -1630,7 +1512,7 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)  			s3c_hsotg_handle_outdone(hsotg, epnum, false);  		break; -	case __status(GRXSTS_PktSts_SetupDone): +	case GRXSTS_PKTSTS_SETUPDONE:  		dev_dbg(hsotg->dev,  			"SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n",  			s3c_hsotg_read_frameno(hsotg), @@ -1639,11 +1521,11 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)  		s3c_hsotg_handle_outdone(hsotg, epnum, true);  		break; -	case __status(GRXSTS_PktSts_OutRX): +	case GRXSTS_PKTSTS_OUTRX:  		s3c_hsotg_rx_data(hsotg, epnum, size);  		break; -	case __status(GRXSTS_PktSts_SetupRX): +	case GRXSTS_PKTSTS_SETUPRX:  		dev_dbg(hsotg->dev,  			"SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n",  			s3c_hsotg_read_frameno(hsotg), @@ -1698,6 +1580,7 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg,  	struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep];  	void __iomem *regs = hsotg->regs;  	u32 mpsval; +	u32 mcval;  	u32 reg;  	if (ep == 0) { @@ -1705,28 +1588,32 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg,  		mpsval = s3c_hsotg_ep0_mps(mps);  		if (mpsval > 3)  			goto bad_mps; +		hs_ep->ep.maxpacket = mps; +		hs_ep->mc = 1;  	} else { -		if (mps >= DxEPCTL_MPS_LIMIT+1) +		mpsval = mps & DXEPCTL_MPS_MASK; +		if (mpsval > 1024)  			goto bad_mps; - -		mpsval = mps; +		mcval = ((mps >> 11) & 0x3) + 1; +		hs_ep->mc = mcval; +		if (mcval > 3) +			goto bad_mps; +		hs_ep->ep.maxpacket = mpsval;  	} -	hs_ep->ep.maxpacket = mps; -  	/*  	 * update both the in and out endpoint controldir_ registers, even  	 * if one of the directions may not be in use.  	 */  	reg = readl(regs + DIEPCTL(ep)); -	reg &= ~DxEPCTL_MPS_MASK; +	reg &= ~DXEPCTL_MPS_MASK;  	reg |= mpsval;  	writel(reg, regs + DIEPCTL(ep));  	if (ep) {  		reg = readl(regs + DOEPCTL(ep)); -		reg &= ~DxEPCTL_MPS_MASK; +		reg &= ~DXEPCTL_MPS_MASK;  		reg |= mpsval;  		writel(reg, regs + DOEPCTL(ep));  	} @@ -1747,7 +1634,7 @@ static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx)  	int timeout;  	int val; -	writel(GRSTCTL_TxFNum(idx) | GRSTCTL_TxFFlsh, +	writel(GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH,  		hsotg->regs + GRSTCTL);  	/* wait until the fifo is flushed */ @@ -1756,7 +1643,7 @@ static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx)  	while (1) {  		val = readl(hsotg->regs + GRSTCTL); -		if ((val & (GRSTCTL_TxFFlsh)) == 0) +		if ((val & (GRSTCTL_TXFFLSH)) == 0)  			break;  		if (--timeout == 0) { @@ -1782,8 +1669,16 @@ static int s3c_hsotg_trytx(struct s3c_hsotg *hsotg,  {  	struct s3c_hsotg_req *hs_req = hs_ep->req; -	if (!hs_ep->dir_in || !hs_req) +	if (!hs_ep->dir_in || !hs_req) { +		/** +		 * if request is not enqueued, we disable interrupts +		 * for endpoints, excepting ep0 +		 */ +		if (hs_ep->index != 0) +			s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, +					     hs_ep->dir_in, 0);  		return 0; +	}  	if (hs_req->req.actual < hs_req->req.length) {  		dev_dbg(hsotg->dev, "trying to write more for ep%d\n", @@ -1831,7 +1726,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg,  	 * aligned).  	 */ -	size_left = DxEPTSIZ_XferSize_GET(epsize); +	size_left = DXEPTSIZ_XFERSIZE_GET(epsize);  	size_done = hs_ep->size_loaded - size_left;  	size_done += hs_ep->last_load; @@ -1887,8 +1782,10 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,  	u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);  	u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx);  	u32 ints; +	u32 ctrl;  	ints = readl(hsotg->regs + epint_reg); +	ctrl = readl(hsotg->regs + epctl_reg);  	/* Clear endpoint interrupts */  	writel(ints, hsotg->regs + epint_reg); @@ -1896,9 +1793,17 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,  	dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n",  		__func__, idx, dir_in ? "in" : "out", ints); -	if (ints & DxEPINT_XferCompl) { +	if (ints & DXEPINT_XFERCOMPL) { +		if (hs_ep->isochronous && hs_ep->interval == 1) { +			if (ctrl & DXEPCTL_EOFRNUM) +				ctrl |= DXEPCTL_SETEVENFR; +			else +				ctrl |= DXEPCTL_SETODDFR; +			writel(ctrl, hsotg->regs + epctl_reg); +		} +  		dev_dbg(hsotg->dev, -			"%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n", +			"%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n",  			__func__, readl(hsotg->regs + epctl_reg),  			readl(hsotg->regs + epsiz_reg)); @@ -1921,7 +1826,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,  		}  	} -	if (ints & DxEPINT_EPDisbld) { +	if (ints & DXEPINT_EPDISBLD) {  		dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);  		if (dir_in) { @@ -1929,20 +1834,20 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,  			s3c_hsotg_txfifo_flush(hsotg, idx); -			if ((epctl & DxEPCTL_Stall) && -				(epctl & DxEPCTL_EPType_Bulk)) { +			if ((epctl & DXEPCTL_STALL) && +				(epctl & DXEPCTL_EPTYPE_BULK)) {  				int dctl = readl(hsotg->regs + DCTL); -				dctl |= DCTL_CGNPInNAK; +				dctl |= DCTL_CGNPINNAK;  				writel(dctl, hsotg->regs + DCTL);  			}  		}  	} -	if (ints & DxEPINT_AHBErr) +	if (ints & DXEPINT_AHBERR)  		dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); -	if (ints & DxEPINT_Setup) {  /* Setup or Timeout */ +	if (ints & DXEPINT_SETUP) {  /* Setup or Timeout */  		dev_dbg(hsotg->dev, "%s: Setup/Timeout\n",  __func__);  		if (using_dma(hsotg) && idx == 0) { @@ -1960,25 +1865,25 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,  		}  	} -	if (ints & DxEPINT_Back2BackSetup) +	if (ints & DXEPINT_BACK2BACKSETUP)  		dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); -	if (dir_in) { +	if (dir_in && !hs_ep->isochronous) {  		/* not sure if this is important, but we'll clear it anyway */ -		if (ints & DIEPMSK_INTknTXFEmpMsk) { +		if (ints & DIEPMSK_INTKNTXFEMPMSK) {  			dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n",  				__func__, idx);  		}  		/* this probably means something bad is happening */ -		if (ints & DIEPMSK_INTknEPMisMsk) { +		if (ints & DIEPMSK_INTKNEPMISMSK) {  			dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n",  				 __func__, idx);  		}  		/* FIFO has space or is empty (see GAHBCFG) */  		if (hsotg->dedicated_fifos && -		    ints & DIEPMSK_TxFIFOEmpty) { +		    ints & DIEPMSK_TXFIFOEMPTY) {  			dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",  				__func__, idx);  			if (!using_dma(hsotg)) @@ -2014,21 +1919,21 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg)  	 */  	/* catch both EnumSpd_FS and EnumSpd_FS48 */ -	switch (dsts & DSTS_EnumSpd_MASK) { -	case DSTS_EnumSpd_FS: -	case DSTS_EnumSpd_FS48: +	switch (dsts & DSTS_ENUMSPD_MASK) { +	case DSTS_ENUMSPD_FS: +	case DSTS_ENUMSPD_FS48:  		hsotg->gadget.speed = USB_SPEED_FULL;  		ep0_mps = EP0_MPS_LIMIT; -		ep_mps = 64; +		ep_mps = 1023;  		break; -	case DSTS_EnumSpd_HS: +	case DSTS_ENUMSPD_HS:  		hsotg->gadget.speed = USB_SPEED_HIGH;  		ep0_mps = EP0_MPS_LIMIT; -		ep_mps = 512; +		ep_mps = 1024;  		break; -	case DSTS_EnumSpd_LS: +	case DSTS_ENUMSPD_LS:  		hsotg->gadget.speed = USB_SPEED_LOW;  		/*  		 * note, we don't actually support LS in this driver at the @@ -2089,16 +1994,11 @@ static void kill_all_requests(struct s3c_hsotg *hsotg,  		s3c_hsotg_complete_request(hsotg, ep, req,  					   result);  	} +	if(hsotg->dedicated_fifos) +		if ((readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4 < 3072) +			s3c_hsotg_txfifo_flush(hsotg, ep->index);  } -#define call_gadget(_hs, _entry) \ -	if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN &&	\ -	    (_hs)->driver && (_hs)->driver->_entry) { \ -		spin_unlock(&_hs->lock); \ -		(_hs)->driver->_entry(&(_hs)->gadget); \ -		spin_lock(&_hs->lock); \ -		} -  /**   * s3c_hsotg_disconnect - disconnect service   * @hsotg: The device state. @@ -2146,9 +2046,9 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic)  }  /* IRQ flags which will trigger a retry around the IRQ loop */ -#define IRQ_RETRY_MASK (GINTSTS_NPTxFEmp | \ -			GINTSTS_PTxFEmp |  \ -			GINTSTS_RxFLvl) +#define IRQ_RETRY_MASK (GINTSTS_NPTXFEMP | \ +			GINTSTS_PTXFEMP |  \ +			GINTSTS_RXFLVL)  /**   * s3c_hsotg_corereset - issue softreset to the core @@ -2164,14 +2064,14 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)  	dev_dbg(hsotg->dev, "resetting core\n");  	/* issue soft reset */ -	writel(GRSTCTL_CSftRst, hsotg->regs + GRSTCTL); +	writel(GRSTCTL_CSFTRST, hsotg->regs + GRSTCTL);  	timeout = 10000;  	do {  		grstctl = readl(hsotg->regs + GRSTCTL); -	} while ((grstctl & GRSTCTL_CSftRst) && timeout-- > 0); +	} while ((grstctl & GRSTCTL_CSFTRST) && timeout-- > 0); -	if (grstctl & GRSTCTL_CSftRst) { +	if (grstctl & GRSTCTL_CSFTRST) {  		dev_err(hsotg->dev, "Failed to get CSftRst asserted\n");  		return -EINVAL;  	} @@ -2188,7 +2088,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)  			return -ETIMEDOUT;  		} -		if (!(grstctl & GRSTCTL_AHBIdle)) +		if (!(grstctl & GRSTCTL_AHBIDLE))  			continue;  		break;		/* reset done */ @@ -2214,14 +2114,14 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg)  	 */  	/* set the PLL on, remove the HNP/SRP and set the PHY */ -	writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | +	writel(hsotg->phyif | GUSBCFG_TOUTCAL(7) |  	       (0x5 << 10), hsotg->regs + GUSBCFG);  	s3c_hsotg_init_fifo(hsotg); -	__orr32(hsotg->regs + DCTL, DCTL_SftDiscon); +	__orr32(hsotg->regs + DCTL, DCTL_SFTDISCON); -	writel(1 << 18 | DCFG_DevSpd_HS,  hsotg->regs + DCFG); +	writel(1 << 18 | DCFG_DEVSPD_HS,  hsotg->regs + DCFG);  	/* Clear any pending OTG interrupts */  	writel(0xffffffff, hsotg->regs + GOTGINT); @@ -2229,41 +2129,45 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg)  	/* Clear any pending interrupts */  	writel(0xffffffff, hsotg->regs + GINTSTS); -	writel(GINTSTS_ErlySusp | GINTSTS_SessReqInt | -	       GINTSTS_GOUTNakEff | GINTSTS_GINNakEff | -	       GINTSTS_ConIDStsChng | GINTSTS_USBRst | -	       GINTSTS_EnumDone | GINTSTS_OTGInt | -	       GINTSTS_USBSusp | GINTSTS_WkUpInt, -	       hsotg->regs + GINTMSK); +	writel(GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT | +		GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF | +		GINTSTS_CONIDSTSCHNG | GINTSTS_USBRST | +		GINTSTS_ENUMDONE | GINTSTS_OTGINT | +		GINTSTS_USBSUSP | GINTSTS_WKUPINT, +		hsotg->regs + GINTMSK);  	if (using_dma(hsotg)) -		writel(GAHBCFG_GlblIntrEn | GAHBCFG_DMAEn | -		       GAHBCFG_HBstLen_Incr4, +		writel(GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN | +		       GAHBCFG_HBSTLEN_INCR4,  		       hsotg->regs + GAHBCFG);  	else -		writel(GAHBCFG_GlblIntrEn, hsotg->regs + GAHBCFG); +		writel(((hsotg->dedicated_fifos) ? (GAHBCFG_NP_TXF_EMP_LVL | +						    GAHBCFG_P_TXF_EMP_LVL) : 0) | +		       GAHBCFG_GLBL_INTR_EN, +		       hsotg->regs + GAHBCFG);  	/* -	 * Enabling INTknTXFEmpMsk here seems to be a big mistake, we end -	 * up being flooded with interrupts if the host is polling the -	 * endpoint to try and read data. +	 * If INTknTXFEmpMsk is enabled, it's important to disable ep interrupts +	 * when we have no data to transfer. Otherwise we get being flooded by +	 * interrupts.  	 */ -	writel(((hsotg->dedicated_fifos) ? DIEPMSK_TxFIFOEmpty : 0) | -	       DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk | -	       DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | -	       DIEPMSK_INTknEPMisMsk, -	       hsotg->regs + DIEPMSK); +	writel(((hsotg->dedicated_fifos) ? DIEPMSK_TXFIFOEMPTY | +		DIEPMSK_INTKNTXFEMPMSK : 0) | +		DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK | +		DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | +		DIEPMSK_INTKNEPMISMSK, +		hsotg->regs + DIEPMSK);  	/*  	 * don't need XferCompl, we get that from RXFIFO in slave mode. In  	 * DMA mode we may need this.  	 */ -	writel((using_dma(hsotg) ? (DIEPMSK_XferComplMsk | -				    DIEPMSK_TimeOUTMsk) : 0) | -	       DOEPMSK_EPDisbldMsk | DOEPMSK_AHBErrMsk | -	       DOEPMSK_SetupMsk, -	       hsotg->regs + DOEPMSK); +	writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK | +				    DIEPMSK_TIMEOUTMSK) : 0) | +		DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK | +		DOEPMSK_SETUPMSK, +		hsotg->regs + DOEPMSK);  	writel(0, hsotg->regs + DAINTMSK); @@ -2272,7 +2176,7 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg)  		readl(hsotg->regs + DOEPCTL0));  	/* enable in and out endpoint interrupts */ -	s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPInt | GINTSTS_IEPInt); +	s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT);  	/*  	 * Enable the RXFIFO when in slave mode, as this is how we collect @@ -2280,15 +2184,15 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg)  	 * things we cannot process, so do not use it.  	 */  	if (!using_dma(hsotg)) -		s3c_hsotg_en_gsint(hsotg, GINTSTS_RxFLvl); +		s3c_hsotg_en_gsint(hsotg, GINTSTS_RXFLVL);  	/* Enable interrupts for EP0 in and out */  	s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1);  	s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1); -	__orr32(hsotg->regs + DCTL, DCTL_PWROnPrgDone); +	__orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);  	udelay(10);  /* see openiboot */ -	__bic32(hsotg->regs + DCTL, DCTL_PWROnPrgDone); +	__bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);  	dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL)); @@ -2298,17 +2202,17 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg)  	 */  	/* set to read 1 8byte packet */ -	writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) | -	       DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0); +	writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) | +	       DXEPTSIZ_XFERSIZE(8), hsotg->regs + DOEPTSIZ0);  	writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | -	       DxEPCTL_CNAK | DxEPCTL_EPEna | -	       DxEPCTL_USBActEp, +	       DXEPCTL_CNAK | DXEPCTL_EPENA | +	       DXEPCTL_USBACTEP,  	       hsotg->regs + DOEPCTL0);  	/* enable, but don't activate EP0in */  	writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | -	       DxEPCTL_USBActEp, hsotg->regs + DIEPCTL0); +	       DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0);  	s3c_hsotg_enqueue_setup(hsotg); @@ -2317,14 +2221,14 @@ static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg)  		readl(hsotg->regs + DOEPCTL0));  	/* clear global NAKs */ -	writel(DCTL_CGOUTNak | DCTL_CGNPInNAK, +	writel(DCTL_CGOUTNAK | DCTL_CGNPINNAK,  	       hsotg->regs + DCTL);  	/* must be at-least 3ms to allow bus to see disconnect */  	mdelay(3);  	/* remove the soft-disconnect and let's go */ -	__bic32(hsotg->regs + DCTL, DCTL_SftDiscon); +	__bic32(hsotg->regs + DCTL, DCTL_SFTDISCON);  }  /** @@ -2349,7 +2253,7 @@ irq_retry:  	gintsts &= gintmsk; -	if (gintsts & GINTSTS_OTGInt) { +	if (gintsts & GINTSTS_OTGINT) {  		u32 otgint = readl(hsotg->regs + GOTGINT);  		dev_info(hsotg->dev, "OTGInt: %08x\n", otgint); @@ -2357,31 +2261,35 @@ irq_retry:  		writel(otgint, hsotg->regs + GOTGINT);  	} -	if (gintsts & GINTSTS_SessReqInt) { +	if (gintsts & GINTSTS_SESSREQINT) {  		dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__); -		writel(GINTSTS_SessReqInt, hsotg->regs + GINTSTS); +		writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);  	} -	if (gintsts & GINTSTS_EnumDone) { -		writel(GINTSTS_EnumDone, hsotg->regs + GINTSTS); +	if (gintsts & GINTSTS_ENUMDONE) { +		writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS);  		s3c_hsotg_irq_enumdone(hsotg);  	} -	if (gintsts & GINTSTS_ConIDStsChng) { +	if (gintsts & GINTSTS_CONIDSTSCHNG) {  		dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n",  			readl(hsotg->regs + DSTS),  			readl(hsotg->regs + GOTGCTL)); -		writel(GINTSTS_ConIDStsChng, hsotg->regs + GINTSTS); +		writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);  	} -	if (gintsts & (GINTSTS_OEPInt | GINTSTS_IEPInt)) { +	if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) {  		u32 daint = readl(hsotg->regs + DAINT); -		u32 daint_out = daint >> DAINT_OutEP_SHIFT; -		u32 daint_in = daint & ~(daint_out << DAINT_OutEP_SHIFT); +		u32 daintmsk = readl(hsotg->regs + DAINTMSK); +		u32 daint_out, daint_in;  		int ep; +		daint &= daintmsk; +		daint_out = daint >> DAINT_OUTEP_SHIFT; +		daint_in = daint & ~(daint_out << DAINT_OUTEP_SHIFT); +  		dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint);  		for (ep = 0; ep < 15 && daint_out; ep++, daint_out >>= 1) { @@ -2395,7 +2303,7 @@ irq_retry:  		}  	} -	if (gintsts & GINTSTS_USBRst) { +	if (gintsts & GINTSTS_USBRST) {  		u32 usb_status = readl(hsotg->regs + GOTGCTL); @@ -2403,7 +2311,7 @@ irq_retry:  		dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",  			readl(hsotg->regs + GNPTXSTS)); -		writel(GINTSTS_USBRst, hsotg->regs + GINTSTS); +		writel(GINTSTS_USBRST, hsotg->regs + GINTSTS);  		if (usb_status & GOTGCTL_BSESVLD) {  			if (time_after(jiffies, hsotg->last_rst + @@ -2420,7 +2328,7 @@ irq_retry:  	/* check both FIFOs */ -	if (gintsts & GINTSTS_NPTxFEmp) { +	if (gintsts & GINTSTS_NPTXFEMP) {  		dev_dbg(hsotg->dev, "NPTxFEmp\n");  		/* @@ -2429,20 +2337,20 @@ irq_retry:  		 * it needs re-enabling  		 */ -		s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTxFEmp); +		s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTXFEMP);  		s3c_hsotg_irq_fifoempty(hsotg, false);  	} -	if (gintsts & GINTSTS_PTxFEmp) { +	if (gintsts & GINTSTS_PTXFEMP) {  		dev_dbg(hsotg->dev, "PTxFEmp\n");  		/* See note in GINTSTS_NPTxFEmp */ -		s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTxFEmp); +		s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTXFEMP);  		s3c_hsotg_irq_fifoempty(hsotg, true);  	} -	if (gintsts & GINTSTS_RxFLvl) { +	if (gintsts & GINTSTS_RXFLVL) {  		/*  		 * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty,  		 * we need to retry s3c_hsotg_handle_rx if this is still @@ -2452,31 +2360,28 @@ irq_retry:  		s3c_hsotg_handle_rx(hsotg);  	} -	if (gintsts & GINTSTS_ModeMis) { +	if (gintsts & GINTSTS_MODEMIS) {  		dev_warn(hsotg->dev, "warning, mode mismatch triggered\n"); -		writel(GINTSTS_ModeMis, hsotg->regs + GINTSTS); +		writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);  	} -	if (gintsts & GINTSTS_USBSusp) { +	if (gintsts & GINTSTS_USBSUSP) {  		dev_info(hsotg->dev, "GINTSTS_USBSusp\n"); -		writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS); +		writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);  		call_gadget(hsotg, suspend); -		s3c_hsotg_disconnect(hsotg);  	} -	if (gintsts & GINTSTS_WkUpInt) { +	if (gintsts & GINTSTS_WKUPINT) {  		dev_info(hsotg->dev, "GINTSTS_WkUpIn\n"); -		writel(GINTSTS_WkUpInt, hsotg->regs + GINTSTS); +		writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);  		call_gadget(hsotg, resume);  	} -	if (gintsts & GINTSTS_ErlySusp) { +	if (gintsts & GINTSTS_ERLYSUSP) {  		dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); -		writel(GINTSTS_ErlySusp, hsotg->regs + GINTSTS); - -		s3c_hsotg_disconnect(hsotg); +		writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS);  	}  	/* @@ -2485,18 +2390,18 @@ irq_retry:  	 * the occurrence.  	 */ -	if (gintsts & GINTSTS_GOUTNakEff) { +	if (gintsts & GINTSTS_GOUTNAKEFF) {  		dev_info(hsotg->dev, "GOUTNakEff triggered\n"); -		writel(DCTL_CGOUTNak, hsotg->regs + DCTL); +		writel(DCTL_CGOUTNAK, hsotg->regs + DCTL);  		s3c_hsotg_dump(hsotg);  	} -	if (gintsts & GINTSTS_GINNakEff) { +	if (gintsts & GINTSTS_GINNAKEFF) {  		dev_info(hsotg->dev, "GINNakEff triggered\n"); -		writel(DCTL_CGNPInNAK, hsotg->regs + DCTL); +		writel(DCTL_CGNPINNAK, hsotg->regs + DCTL);  		s3c_hsotg_dump(hsotg);  	} @@ -2560,14 +2465,14 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,  	spin_lock_irqsave(&hsotg->lock, flags); -	epctrl &= ~(DxEPCTL_EPType_MASK | DxEPCTL_MPS_MASK); -	epctrl |= DxEPCTL_MPS(mps); +	epctrl &= ~(DXEPCTL_EPTYPE_MASK | DXEPCTL_MPS_MASK); +	epctrl |= DXEPCTL_MPS(mps);  	/*  	 * mark the endpoint as active, otherwise the core may ignore  	 * transactions entirely for this endpoint  	 */ -	epctrl |= DxEPCTL_USBActEp; +	epctrl |= DXEPCTL_USBACTEP;  	/*  	 * set the NAK status on the endpoint, otherwise we might try and @@ -2576,22 +2481,31 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,  	 * size register hasn't been set.  	 */ -	epctrl |= DxEPCTL_SNAK; +	epctrl |= DXEPCTL_SNAK;  	/* update the endpoint state */ -	hs_ep->ep.maxpacket = mps; +	s3c_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps);  	/* default, set to non-periodic */ +	hs_ep->isochronous = 0;  	hs_ep->periodic = 0; +	hs_ep->halted = 0; +	hs_ep->interval = desc->bInterval; + +	if (hs_ep->interval > 1 && hs_ep->mc > 1) +		dev_err(hsotg->dev, "MC > 1 when interval is not 1\n");  	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {  	case USB_ENDPOINT_XFER_ISOC: -		dev_err(hsotg->dev, "no current ISOC support\n"); -		ret = -EINVAL; -		goto out; +		epctrl |= DXEPCTL_EPTYPE_ISO; +		epctrl |= DXEPCTL_SETEVENFR; +		hs_ep->isochronous = 1; +		if (dir_in) +			hs_ep->periodic = 1; +		break;  	case USB_ENDPOINT_XFER_BULK: -		epctrl |= DxEPCTL_EPType_Bulk; +		epctrl |= DXEPCTL_EPTYPE_BULK;  		break;  	case USB_ENDPOINT_XFER_INT: @@ -2604,14 +2518,14 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,  			 */  			hs_ep->periodic = 1; -			epctrl |= DxEPCTL_TxFNum(index); +			epctrl |= DXEPCTL_TXFNUM(index);  		} -		epctrl |= DxEPCTL_EPType_Intterupt; +		epctrl |= DXEPCTL_EPTYPE_INTERRUPT;  		break;  	case USB_ENDPOINT_XFER_CONTROL: -		epctrl |= DxEPCTL_EPType_Control; +		epctrl |= DXEPCTL_EPTYPE_CONTROL;  		break;  	} @@ -2620,11 +2534,11 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,  	 * a unique tx-fifo even if it is non-periodic.  	 */  	if (dir_in && hsotg->dedicated_fifos) -		epctrl |= DxEPCTL_TxFNum(index); +		epctrl |= DXEPCTL_TXFNUM(index);  	/* for non control endpoints, set PID to D0 */  	if (index) -		epctrl |= DxEPCTL_SetD0PID; +		epctrl |= DXEPCTL_SETD0PID;  	dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n",  		__func__, epctrl); @@ -2636,7 +2550,6 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,  	/* enable the endpoint interrupt */  	s3c_hsotg_ctrl_epint(hsotg, index, dir_in, 1); -out:  	spin_unlock_irqrestore(&hsotg->lock, flags);  	return ret;  } @@ -2670,9 +2583,9 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep)  	ctrl = readl(hsotg->regs + epctrl_reg); -	ctrl &= ~DxEPCTL_EPEna; -	ctrl &= ~DxEPCTL_USBActEp; -	ctrl |= DxEPCTL_SNAK; +	ctrl &= ~DXEPCTL_EPENA; +	ctrl &= ~DXEPCTL_USBACTEP; +	ctrl |= DXEPCTL_SNAK;  	dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);  	writel(ctrl, hsotg->regs + epctrl_reg); @@ -2744,21 +2657,30 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)  	dev_info(hs->dev, "%s(ep %p %s, %d)\n", __func__, ep, ep->name, value); +	if (index == 0) { +		if (value) +			s3c_hsotg_stall_ep0(hs); +		else +			dev_warn(hs->dev, +				 "%s: can't clear halt on ep0\n", __func__); +		return 0; +	} +  	/* write both IN and OUT control registers */  	epreg = DIEPCTL(index);  	epctl = readl(hs->regs + epreg);  	if (value) { -		epctl |= DxEPCTL_Stall + DxEPCTL_SNAK; -		if (epctl & DxEPCTL_EPEna) -			epctl |= DxEPCTL_EPDis; +		epctl |= DXEPCTL_STALL + DXEPCTL_SNAK; +		if (epctl & DXEPCTL_EPENA) +			epctl |= DXEPCTL_EPDIS;  	} else { -		epctl &= ~DxEPCTL_Stall; -		xfertype = epctl & DxEPCTL_EPType_MASK; -		if (xfertype == DxEPCTL_EPType_Bulk || -			xfertype == DxEPCTL_EPType_Intterupt) -				epctl |= DxEPCTL_SetD0PID; +		epctl &= ~DXEPCTL_STALL; +		xfertype = epctl & DXEPCTL_EPTYPE_MASK; +		if (xfertype == DXEPCTL_EPTYPE_BULK || +			xfertype == DXEPCTL_EPTYPE_INTERRUPT) +				epctl |= DXEPCTL_SETD0PID;  	}  	writel(epctl, hs->regs + epreg); @@ -2767,17 +2689,19 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)  	epctl = readl(hs->regs + epreg);  	if (value) -		epctl |= DxEPCTL_Stall; +		epctl |= DXEPCTL_STALL;  	else { -		epctl &= ~DxEPCTL_Stall; -		xfertype = epctl & DxEPCTL_EPType_MASK; -		if (xfertype == DxEPCTL_EPType_Bulk || -			xfertype == DxEPCTL_EPType_Intterupt) -				epctl |= DxEPCTL_SetD0PID; +		epctl &= ~DXEPCTL_STALL; +		xfertype = epctl & DXEPCTL_EPTYPE_MASK; +		if (xfertype == DXEPCTL_EPTYPE_BULK || +			xfertype == DXEPCTL_EPTYPE_INTERRUPT) +				epctl |= DXEPCTL_SETD0PID;  	}  	writel(epctl, hs->regs + epreg); +	hs_ep->halted = value; +  	return 0;  } @@ -2824,8 +2748,11 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg)  	dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev); -	if (hsotg->phy) -		usb_phy_init(hsotg->phy); +	if (hsotg->phy) { +		phy_init(hsotg->phy); +		phy_power_on(hsotg->phy); +	} else if (hsotg->uphy) +		usb_phy_init(hsotg->uphy);  	else if (hsotg->plat->phy_init)  		hsotg->plat->phy_init(pdev, hsotg->plat->phy_type);  } @@ -2841,8 +2768,11 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg)  {  	struct platform_device *pdev = to_platform_device(hsotg->dev); -	if (hsotg->phy) -		usb_phy_shutdown(hsotg->phy); +	if (hsotg->phy) { +		phy_power_off(hsotg->phy); +		phy_exit(hsotg->phy); +	} else if (hsotg->uphy) +		usb_phy_shutdown(hsotg->uphy);  	else if (hsotg->plat->phy_exit)  		hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type);  } @@ -2855,22 +2785,22 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg)  {  	/* unmask subset of endpoint interrupts */ -	writel(DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | -	       DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk, -	       hsotg->regs + DIEPMSK); +	writel(DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | +		DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK, +		hsotg->regs + DIEPMSK); -	writel(DOEPMSK_SetupMsk | DOEPMSK_AHBErrMsk | -	       DOEPMSK_EPDisbldMsk | DOEPMSK_XferComplMsk, -	       hsotg->regs + DOEPMSK); +	writel(DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK | +		DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK, +		hsotg->regs + DOEPMSK);  	writel(0, hsotg->regs + DAINTMSK);  	/* Be in disconnected state until gadget is registered */ -	__orr32(hsotg->regs + DCTL, DCTL_SftDiscon); +	__orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);  	if (0) {  		/* post global nak until we're ready */ -		writel(DCTL_SGNPInNAK | DCTL_SGOUTNak, +		writel(DCTL_SGNPINNAK | DCTL_SGOUTNAK,  		       hsotg->regs + DCTL);  	} @@ -2883,10 +2813,10 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg)  	s3c_hsotg_init_fifo(hsotg);  	/* set the PLL on, remove the HNP/SRP and set the PHY */ -	writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | (0x5 << 10), +	writel(GUSBCFG_PHYIF16 | GUSBCFG_TOUTCAL(7) | (0x5 << 10),  	       hsotg->regs + GUSBCFG); -	writel(using_dma(hsotg) ? GAHBCFG_DMAEn : 0x0, +	writel(using_dma(hsotg) ? GAHBCFG_DMA_EN : 0x0,  	       hsotg->regs + GAHBCFG);  } @@ -2905,7 +2835,7 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,  	int ret;  	if (!hsotg) { -		printk(KERN_ERR "%s: called with no device\n", __func__); +		pr_err("%s: called with no device\n", __func__);  		return -ENODEV;  	} @@ -2962,9 +2892,6 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,  	if (!hsotg)  		return -ENODEV; -	if (!driver || driver != hsotg->driver || !driver->unbind) -		return -EINVAL; -  	/* all endpoints should be shutdown */  	for (ep = 0; ep < hsotg->num_of_eps; ep++)  		s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); @@ -2972,15 +2899,15 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget,  	spin_lock_irqsave(&hsotg->lock, flags);  	s3c_hsotg_phy_disable(hsotg); -	regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); -	hsotg->driver = NULL; +	if (!driver) +		hsotg->driver = NULL; +  	hsotg->gadget.speed = USB_SPEED_UNKNOWN;  	spin_unlock_irqrestore(&hsotg->lock, flags); -	dev_info(hsotg->dev, "unregistered gadget driver '%s'\n", -		 driver->driver.name); +	regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);  	return 0;  } @@ -3071,7 +2998,7 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg,  	hs_ep->parent = hsotg;  	hs_ep->ep.name = hs_ep->name; -	hs_ep->ep.maxpacket = epnum ? 512 : EP0_MPS_LIMIT; +	usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT);  	hs_ep->ep.ops = &s3c_hsotg_ep_ops;  	/* @@ -3080,8 +3007,8 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg,  	 * code is changed to make each endpoint's direction changeable.  	 */ -	ptxfifo = readl(hsotg->regs + DPTXFSIZn(epnum)); -	hs_ep->fifo_size = DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4; +	ptxfifo = readl(hsotg->regs + DPTXFSIZN(epnum)); +	hs_ep->fifo_size = FIFOSIZE_DEPTH_GET(ptxfifo) * 4;  	/*  	 * if we're using dma, we need to set the next-endpoint pointer @@ -3089,7 +3016,7 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg,  	 */  	if (using_dma(hsotg)) { -		u32 next = DxEPCTL_NextEp((epnum + 1) % 15); +		u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15);  		writel(next, hsotg->regs + DIEPCTL(epnum));  		writel(next, hsotg->regs + DOEPCTL(epnum));  	} @@ -3143,10 +3070,10 @@ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)  	/* show periodic fifo settings */  	for (idx = 1; idx <= 15; idx++) { -		val = readl(regs + DPTXFSIZn(idx)); +		val = readl(regs + DPTXFSIZN(idx));  		dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, -			 val >> DPTXFSIZn_DPTxFSize_SHIFT, -			 val & DPTXFSIZn_DPTxFStAddr_MASK); +			 val >> FIFOSIZE_DEPTH_SHIFT, +			 val & FIFOSIZE_STARTADDR_MASK);  	}  	for (idx = 0; idx < 15; idx++) { @@ -3205,7 +3132,7 @@ static int state_show(struct seq_file *seq, void *v)  		   readl(regs + GNPTXSTS),  		   readl(regs + GRXSTSR)); -	seq_printf(seq, "\nEndpoint status:\n"); +	seq_puts(seq, "\nEndpoint status:\n");  	for (idx = 0; idx < 15; idx++) {  		u32 in, out; @@ -3222,7 +3149,7 @@ static int state_show(struct seq_file *seq, void *v)  		seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",  			   in, out); -		seq_printf(seq, "\n"); +		seq_puts(seq, "\n");  	}  	return 0; @@ -3256,22 +3183,22 @@ static int fifo_show(struct seq_file *seq, void *v)  	u32 val;  	int idx; -	seq_printf(seq, "Non-periodic FIFOs:\n"); +	seq_puts(seq, "Non-periodic FIFOs:\n");  	seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ));  	val = readl(regs + GNPTXFSIZ);  	seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n", -		   val >> GNPTXFSIZ_NPTxFDep_SHIFT, -		   val & GNPTXFSIZ_NPTxFStAddr_MASK); +		   val >> FIFOSIZE_DEPTH_SHIFT, +		   val & FIFOSIZE_DEPTH_MASK); -	seq_printf(seq, "\nPeriodic TXFIFOs:\n"); +	seq_puts(seq, "\nPeriodic TXFIFOs:\n");  	for (idx = 1; idx <= 15; idx++) { -		val = readl(regs + DPTXFSIZn(idx)); +		val = readl(regs + DPTXFSIZN(idx));  		seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx, -			   val >> DPTXFSIZn_DPTxFSize_SHIFT, -			   val & DPTXFSIZn_DPTxFStAddr_MASK); +			   val >> FIFOSIZE_DEPTH_SHIFT, +			   val & FIFOSIZE_STARTADDR_MASK);  	}  	return 0; @@ -3335,7 +3262,7 @@ static int ep_show(struct seq_file *seq, void *v)  		   readl(regs + DIEPTSIZ(index)),  		   readl(regs + DOEPTSIZ(index))); -	seq_printf(seq, "\n"); +	seq_puts(seq, "\n");  	seq_printf(seq, "mps %d\n", ep->ep.maxpacket);  	seq_printf(seq, "total_data=%ld\n", ep->total_data); @@ -3346,7 +3273,7 @@ static int ep_show(struct seq_file *seq, void *v)  	list_for_each_entry(req, &ep->queue, queue) {  		if (--show_limit < 0) { -			seq_printf(seq, "not showing more requests...\n"); +			seq_puts(seq, "not showing more requests...\n");  			break;  		} @@ -3452,7 +3379,8 @@ static void s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg)  static int s3c_hsotg_probe(struct platform_device *pdev)  {  	struct s3c_hsotg_plat *plat = dev_get_platdata(&pdev->dev); -	struct usb_phy *phy; +	struct phy *phy; +	struct usb_phy *uphy;  	struct device *dev = &pdev->dev;  	struct s3c_hsotg_ep *eps;  	struct s3c_hsotg *hsotg; @@ -3467,19 +3395,26 @@ static int s3c_hsotg_probe(struct platform_device *pdev)  		return -ENOMEM;  	} -	phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); +	/* +	 * Attempt to find a generic PHY, then look for an old style +	 * USB PHY, finally fall back to pdata +	 */ +	phy = devm_phy_get(&pdev->dev, "usb2-phy");  	if (IS_ERR(phy)) { -		/* Fallback for pdata */ -		plat = dev_get_platdata(&pdev->dev); -		if (!plat) { -			dev_err(&pdev->dev, "no platform data or transceiver defined\n"); -			return -EPROBE_DEFER; -		} else { +		uphy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); +		if (IS_ERR(uphy)) { +			/* Fallback for pdata */ +			plat = dev_get_platdata(&pdev->dev); +			if (!plat) { +				dev_err(&pdev->dev, +				"no platform data or transceiver defined\n"); +				return -EPROBE_DEFER; +			}  			hsotg->plat = plat; -		} -	} else { +		} else +			hsotg->uphy = uphy; +	} else  		hsotg->phy = phy; -	}  	hsotg->dev = dev; @@ -3546,6 +3481,19 @@ static int s3c_hsotg_probe(struct platform_device *pdev)  		goto err_supplies;  	} +	/* Set default UTMI width */ +	hsotg->phyif = GUSBCFG_PHYIF16; + +	/* +	 * If using the generic PHY framework, check if the PHY bus +	 * width is 8-bit and set the phyif appropriately. +	 */ +	if (hsotg->phy && (phy_get_bus_width(phy) == 8)) +		hsotg->phyif = GUSBCFG_PHYIF8; + +	if (hsotg->phy) +		phy_init(hsotg->phy); +  	/* usb phy enable */  	s3c_hsotg_phy_enable(hsotg); @@ -3639,19 +3587,67 @@ static int s3c_hsotg_remove(struct platform_device *pdev)  	}  	s3c_hsotg_phy_disable(hsotg); +	if (hsotg->phy) +		phy_exit(hsotg->phy);  	clk_disable_unprepare(hsotg->clk);  	return 0;  } -#if 1 -#define s3c_hsotg_suspend NULL -#define s3c_hsotg_resume NULL -#endif +static int s3c_hsotg_suspend(struct platform_device *pdev, pm_message_t state) +{ +	struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); +	unsigned long flags; +	int ret = 0; + +	if (hsotg->driver) +		dev_info(hsotg->dev, "suspending usb gadget %s\n", +			 hsotg->driver->driver.name); + +	spin_lock_irqsave(&hsotg->lock, flags); +	s3c_hsotg_disconnect(hsotg); +	s3c_hsotg_phy_disable(hsotg); +	hsotg->gadget.speed = USB_SPEED_UNKNOWN; +	spin_unlock_irqrestore(&hsotg->lock, flags); + +	if (hsotg->driver) { +		int ep; +		for (ep = 0; ep < hsotg->num_of_eps; ep++) +			s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); + +		ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), +					     hsotg->supplies); +	} + +	return ret; +} + +static int s3c_hsotg_resume(struct platform_device *pdev) +{ +	struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); +	unsigned long flags; +	int ret = 0; + +	if (hsotg->driver) { +		dev_info(hsotg->dev, "resuming usb gadget %s\n", +			 hsotg->driver->driver.name); +		ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), +				      hsotg->supplies); +	} + +	spin_lock_irqsave(&hsotg->lock, flags); +	hsotg->last_rst = jiffies; +	s3c_hsotg_phy_enable(hsotg); +	s3c_hsotg_core_init(hsotg); +	spin_unlock_irqrestore(&hsotg->lock, flags); + +	return ret; +}  #ifdef CONFIG_OF  static const struct of_device_id s3c_hsotg_of_ids[] = {  	{ .compatible = "samsung,s3c6400-hsotg", }, +	{ .compatible = "snps,dwc2", },  	{ /* sentinel */ }  };  MODULE_DEVICE_TABLE(of, s3c_hsotg_of_ids); diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c new file mode 100644 index 00000000000..4d918ed8d34 --- /dev/null +++ b/drivers/usb/dwc2/hcd.c @@ -0,0 +1,2981 @@ +/* + * hcd.c - DesignWare HS OTG Controller host-mode routines + * + * Copyright (C) 2004-2013 Synopsys, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + *    to endorse or promote products derived from this software without + *    specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file contains the core HCD code, and implements the Linux hc_driver + * API + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include <linux/usb/hcd.h> +#include <linux/usb/ch11.h> + +#include "core.h" +#include "hcd.h" + +/** + * dwc2_dump_channel_info() - Prints the state of a host channel + * + * @hsotg: Programming view of DWC_otg controller + * @chan:  Pointer to the channel to dump + * + * Must be called with interrupt disabled and spinlock held + * + * NOTE: This function will be removed once the peripheral controller code + * is integrated and the driver is stable + */ +static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg, +				   struct dwc2_host_chan *chan) +{ +#ifdef VERBOSE_DEBUG +	int num_channels = hsotg->core_params->host_channels; +	struct dwc2_qh *qh; +	u32 hcchar; +	u32 hcsplt; +	u32 hctsiz; +	u32 hc_dma; +	int i; + +	if (chan == NULL) +		return; + +	hcchar = readl(hsotg->regs + HCCHAR(chan->hc_num)); +	hcsplt = readl(hsotg->regs + HCSPLT(chan->hc_num)); +	hctsiz = readl(hsotg->regs + HCTSIZ(chan->hc_num)); +	hc_dma = readl(hsotg->regs + HCDMA(chan->hc_num)); + +	dev_dbg(hsotg->dev, "  Assigned to channel %p:\n", chan); +	dev_dbg(hsotg->dev, "    hcchar 0x%08x, hcsplt 0x%08x\n", +		hcchar, hcsplt); +	dev_dbg(hsotg->dev, "    hctsiz 0x%08x, hc_dma 0x%08x\n", +		hctsiz, hc_dma); +	dev_dbg(hsotg->dev, "    dev_addr: %d, ep_num: %d, ep_is_in: %d\n", +		chan->dev_addr, chan->ep_num, chan->ep_is_in); +	dev_dbg(hsotg->dev, "    ep_type: %d\n", chan->ep_type); +	dev_dbg(hsotg->dev, "    max_packet: %d\n", chan->max_packet); +	dev_dbg(hsotg->dev, "    data_pid_start: %d\n", chan->data_pid_start); +	dev_dbg(hsotg->dev, "    xfer_started: %d\n", chan->xfer_started); +	dev_dbg(hsotg->dev, "    halt_status: %d\n", chan->halt_status); +	dev_dbg(hsotg->dev, "    xfer_buf: %p\n", chan->xfer_buf); +	dev_dbg(hsotg->dev, "    xfer_dma: %08lx\n", +		(unsigned long)chan->xfer_dma); +	dev_dbg(hsotg->dev, "    xfer_len: %d\n", chan->xfer_len); +	dev_dbg(hsotg->dev, "    qh: %p\n", chan->qh); +	dev_dbg(hsotg->dev, "  NP inactive sched:\n"); +	list_for_each_entry(qh, &hsotg->non_periodic_sched_inactive, +			    qh_list_entry) +		dev_dbg(hsotg->dev, "    %p\n", qh); +	dev_dbg(hsotg->dev, "  NP active sched:\n"); +	list_for_each_entry(qh, &hsotg->non_periodic_sched_active, +			    qh_list_entry) +		dev_dbg(hsotg->dev, "    %p\n", qh); +	dev_dbg(hsotg->dev, "  Channels:\n"); +	for (i = 0; i < num_channels; i++) { +		struct dwc2_host_chan *chan = hsotg->hc_ptr_array[i]; + +		dev_dbg(hsotg->dev, "    %2d: %p\n", i, chan); +	} +#endif /* VERBOSE_DEBUG */ +} + +/* + * Processes all the URBs in a single list of QHs. Completes them with + * -ETIMEDOUT and frees the QTD. + * + * Must be called with interrupt disabled and spinlock held + */ +static void dwc2_kill_urbs_in_qh_list(struct dwc2_hsotg *hsotg, +				      struct list_head *qh_list) +{ +	struct dwc2_qh *qh, *qh_tmp; +	struct dwc2_qtd *qtd, *qtd_tmp; + +	list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) { +		list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, +					 qtd_list_entry) { +			dwc2_host_complete(hsotg, qtd, -ETIMEDOUT); +			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh); +		} +	} +} + +static void dwc2_qh_list_free(struct dwc2_hsotg *hsotg, +			      struct list_head *qh_list) +{ +	struct dwc2_qtd *qtd, *qtd_tmp; +	struct dwc2_qh *qh, *qh_tmp; +	unsigned long flags; + +	if (!qh_list->next) +		/* The list hasn't been initialized yet */ +		return; + +	spin_lock_irqsave(&hsotg->lock, flags); + +	/* Ensure there are no QTDs or URBs left */ +	dwc2_kill_urbs_in_qh_list(hsotg, qh_list); + +	list_for_each_entry_safe(qh, qh_tmp, qh_list, qh_list_entry) { +		dwc2_hcd_qh_unlink(hsotg, qh); + +		/* Free each QTD in the QH's QTD list */ +		list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, +					 qtd_list_entry) +			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh); + +		spin_unlock_irqrestore(&hsotg->lock, flags); +		dwc2_hcd_qh_free(hsotg, qh); +		spin_lock_irqsave(&hsotg->lock, flags); +	} + +	spin_unlock_irqrestore(&hsotg->lock, flags); +} + +/* + * Responds with an error status of -ETIMEDOUT to all URBs in the non-periodic + * and periodic schedules. The QTD associated with each URB is removed from + * the schedule and freed. This function may be called when a disconnect is + * detected or when the HCD is being stopped. + * + * Must be called with interrupt disabled and spinlock held + */ +static void dwc2_kill_all_urbs(struct dwc2_hsotg *hsotg) +{ +	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_inactive); +	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->non_periodic_sched_active); +	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_inactive); +	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_ready); +	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_assigned); +	dwc2_kill_urbs_in_qh_list(hsotg, &hsotg->periodic_sched_queued); +} + +/** + * dwc2_hcd_start() - Starts the HCD when switching to Host mode + * + * @hsotg: Pointer to struct dwc2_hsotg + */ +void dwc2_hcd_start(struct dwc2_hsotg *hsotg) +{ +	u32 hprt0; + +	if (hsotg->op_state == OTG_STATE_B_HOST) { +		/* +		 * Reset the port. During a HNP mode switch the reset +		 * needs to occur within 1ms and have a duration of at +		 * least 50ms. +		 */ +		hprt0 = dwc2_read_hprt0(hsotg); +		hprt0 |= HPRT0_RST; +		writel(hprt0, hsotg->regs + HPRT0); +	} + +	queue_delayed_work(hsotg->wq_otg, &hsotg->start_work, +			   msecs_to_jiffies(50)); +} + +/* Must be called with interrupt disabled and spinlock held */ +static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg) +{ +	int num_channels = hsotg->core_params->host_channels; +	struct dwc2_host_chan *channel; +	u32 hcchar; +	int i; + +	if (hsotg->core_params->dma_enable <= 0) { +		/* Flush out any channel requests in slave mode */ +		for (i = 0; i < num_channels; i++) { +			channel = hsotg->hc_ptr_array[i]; +			if (!list_empty(&channel->hc_list_entry)) +				continue; +			hcchar = readl(hsotg->regs + HCCHAR(i)); +			if (hcchar & HCCHAR_CHENA) { +				hcchar &= ~(HCCHAR_CHENA | HCCHAR_EPDIR); +				hcchar |= HCCHAR_CHDIS; +				writel(hcchar, hsotg->regs + HCCHAR(i)); +			} +		} +	} + +	for (i = 0; i < num_channels; i++) { +		channel = hsotg->hc_ptr_array[i]; +		if (!list_empty(&channel->hc_list_entry)) +			continue; +		hcchar = readl(hsotg->regs + HCCHAR(i)); +		if (hcchar & HCCHAR_CHENA) { +			/* Halt the channel */ +			hcchar |= HCCHAR_CHDIS; +			writel(hcchar, hsotg->regs + HCCHAR(i)); +		} + +		dwc2_hc_cleanup(hsotg, channel); +		list_add_tail(&channel->hc_list_entry, &hsotg->free_hc_list); +		/* +		 * Added for Descriptor DMA to prevent channel double cleanup in +		 * release_channel_ddma(), which is called from ep_disable when +		 * device disconnects +		 */ +		channel->qh = NULL; +	} +} + +/** + * dwc2_hcd_disconnect() - Handles disconnect of the HCD + * + * @hsotg: Pointer to struct dwc2_hsotg + * + * Must be called with interrupt disabled and spinlock held + */ +void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg) +{ +	u32 intr; + +	/* Set status flags for the hub driver */ +	hsotg->flags.b.port_connect_status_change = 1; +	hsotg->flags.b.port_connect_status = 0; + +	/* +	 * Shutdown any transfers in process by clearing the Tx FIFO Empty +	 * interrupt mask and status bits and disabling subsequent host +	 * channel interrupts. +	 */ +	intr = readl(hsotg->regs + GINTMSK); +	intr &= ~(GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT); +	writel(intr, hsotg->regs + GINTMSK); +	intr = GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT; +	writel(intr, hsotg->regs + GINTSTS); + +	/* +	 * Turn off the vbus power only if the core has transitioned to device +	 * mode. If still in host mode, need to keep power on to detect a +	 * reconnection. +	 */ +	if (dwc2_is_device_mode(hsotg)) { +		if (hsotg->op_state != OTG_STATE_A_SUSPEND) { +			dev_dbg(hsotg->dev, "Disconnect: PortPower off\n"); +			writel(0, hsotg->regs + HPRT0); +		} + +		dwc2_disable_host_interrupts(hsotg); +	} + +	/* Respond with an error status to all URBs in the schedule */ +	dwc2_kill_all_urbs(hsotg); + +	if (dwc2_is_host_mode(hsotg)) +		/* Clean up any host channels that were in use */ +		dwc2_hcd_cleanup_channels(hsotg); + +	dwc2_host_disconnect(hsotg); +} + +/** + * dwc2_hcd_rem_wakeup() - Handles Remote Wakeup + * + * @hsotg: Pointer to struct dwc2_hsotg + */ +static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg) +{ +	if (hsotg->lx_state == DWC2_L2) +		hsotg->flags.b.port_suspend_change = 1; +	else +		hsotg->flags.b.port_l1_change = 1; +} + +/** + * dwc2_hcd_stop() - Halts the DWC_otg host mode operations in a clean manner + * + * @hsotg: Pointer to struct dwc2_hsotg + * + * Must be called with interrupt disabled and spinlock held + */ +void dwc2_hcd_stop(struct dwc2_hsotg *hsotg) +{ +	dev_dbg(hsotg->dev, "DWC OTG HCD STOP\n"); + +	/* +	 * The root hub should be disconnected before this function is called. +	 * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue) +	 * and the QH lists (via ..._hcd_endpoint_disable). +	 */ + +	/* Turn off all host-specific interrupts */ +	dwc2_disable_host_interrupts(hsotg); + +	/* Turn off the vbus power */ +	dev_dbg(hsotg->dev, "PortPower off\n"); +	writel(0, hsotg->regs + HPRT0); +} + +static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg, +				struct dwc2_hcd_urb *urb, void **ep_handle, +				gfp_t mem_flags) +{ +	struct dwc2_qtd *qtd; +	unsigned long flags; +	u32 intr_mask; +	int retval; +	int dev_speed; + +	if (!hsotg->flags.b.port_connect_status) { +		/* No longer connected */ +		dev_err(hsotg->dev, "Not connected\n"); +		return -ENODEV; +	} + +	dev_speed = dwc2_host_get_speed(hsotg, urb->priv); + +	/* Some configurations cannot support LS traffic on a FS root port */ +	if ((dev_speed == USB_SPEED_LOW) && +	    (hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) && +	    (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI)) { +		u32 hprt0 = readl(hsotg->regs + HPRT0); +		u32 prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT; + +		if (prtspd == HPRT0_SPD_FULL_SPEED) +			return -ENODEV; +	} + +	qtd = kzalloc(sizeof(*qtd), mem_flags); +	if (!qtd) +		return -ENOMEM; + +	dwc2_hcd_qtd_init(qtd, urb); +	retval = dwc2_hcd_qtd_add(hsotg, qtd, (struct dwc2_qh **)ep_handle, +				  mem_flags); +	if (retval) { +		dev_err(hsotg->dev, +			"DWC OTG HCD URB Enqueue failed adding QTD. Error status %d\n", +			retval); +		kfree(qtd); +		return retval; +	} + +	intr_mask = readl(hsotg->regs + GINTMSK); +	if (!(intr_mask & GINTSTS_SOF)) { +		enum dwc2_transaction_type tr_type; + +		if (qtd->qh->ep_type == USB_ENDPOINT_XFER_BULK && +		    !(qtd->urb->flags & URB_GIVEBACK_ASAP)) +			/* +			 * Do not schedule SG transactions until qtd has +			 * URB_GIVEBACK_ASAP set +			 */ +			return 0; + +		spin_lock_irqsave(&hsotg->lock, flags); +		tr_type = dwc2_hcd_select_transactions(hsotg); +		if (tr_type != DWC2_TRANSACTION_NONE) +			dwc2_hcd_queue_transactions(hsotg, tr_type); +		spin_unlock_irqrestore(&hsotg->lock, flags); +	} + +	return 0; +} + +/* Must be called with interrupt disabled and spinlock held */ +static int dwc2_hcd_urb_dequeue(struct dwc2_hsotg *hsotg, +				struct dwc2_hcd_urb *urb) +{ +	struct dwc2_qh *qh; +	struct dwc2_qtd *urb_qtd; + +	urb_qtd = urb->qtd; +	if (!urb_qtd) { +		dev_dbg(hsotg->dev, "## Urb QTD is NULL ##\n"); +		return -EINVAL; +	} + +	qh = urb_qtd->qh; +	if (!qh) { +		dev_dbg(hsotg->dev, "## Urb QTD QH is NULL ##\n"); +		return -EINVAL; +	} + +	urb->priv = NULL; + +	if (urb_qtd->in_process && qh->channel) { +		dwc2_dump_channel_info(hsotg, qh->channel); + +		/* The QTD is in process (it has been assigned to a channel) */ +		if (hsotg->flags.b.port_connect_status) +			/* +			 * If still connected (i.e. in host mode), halt the +			 * channel so it can be used for other transfers. If +			 * no longer connected, the host registers can't be +			 * written to halt the channel since the core is in +			 * device mode. +			 */ +			dwc2_hc_halt(hsotg, qh->channel, +				     DWC2_HC_XFER_URB_DEQUEUE); +	} + +	/* +	 * Free the QTD and clean up the associated QH. Leave the QH in the +	 * schedule if it has any remaining QTDs. +	 */ +	if (hsotg->core_params->dma_desc_enable <= 0) { +		u8 in_process = urb_qtd->in_process; + +		dwc2_hcd_qtd_unlink_and_free(hsotg, urb_qtd, qh); +		if (in_process) { +			dwc2_hcd_qh_deactivate(hsotg, qh, 0); +			qh->channel = NULL; +		} else if (list_empty(&qh->qtd_list)) { +			dwc2_hcd_qh_unlink(hsotg, qh); +		} +	} else { +		dwc2_hcd_qtd_unlink_and_free(hsotg, urb_qtd, qh); +	} + +	return 0; +} + +/* Must NOT be called with interrupt disabled or spinlock held */ +static int dwc2_hcd_endpoint_disable(struct dwc2_hsotg *hsotg, +				     struct usb_host_endpoint *ep, int retry) +{ +	struct dwc2_qtd *qtd, *qtd_tmp; +	struct dwc2_qh *qh; +	unsigned long flags; +	int rc; + +	spin_lock_irqsave(&hsotg->lock, flags); + +	qh = ep->hcpriv; +	if (!qh) { +		rc = -EINVAL; +		goto err; +	} + +	while (!list_empty(&qh->qtd_list) && retry--) { +		if (retry == 0) { +			dev_err(hsotg->dev, +				"## timeout in dwc2_hcd_endpoint_disable() ##\n"); +			rc = -EBUSY; +			goto err; +		} + +		spin_unlock_irqrestore(&hsotg->lock, flags); +		usleep_range(20000, 40000); +		spin_lock_irqsave(&hsotg->lock, flags); +		qh = ep->hcpriv; +		if (!qh) { +			rc = -EINVAL; +			goto err; +		} +	} + +	dwc2_hcd_qh_unlink(hsotg, qh); + +	/* Free each QTD in the QH's QTD list */ +	list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) +		dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh); + +	ep->hcpriv = NULL; +	spin_unlock_irqrestore(&hsotg->lock, flags); +	dwc2_hcd_qh_free(hsotg, qh); + +	return 0; + +err: +	ep->hcpriv = NULL; +	spin_unlock_irqrestore(&hsotg->lock, flags); + +	return rc; +} + +/* Must be called with interrupt disabled and spinlock held */ +static int dwc2_hcd_endpoint_reset(struct dwc2_hsotg *hsotg, +				   struct usb_host_endpoint *ep) +{ +	struct dwc2_qh *qh = ep->hcpriv; + +	if (!qh) +		return -EINVAL; + +	qh->data_toggle = DWC2_HC_PID_DATA0; + +	return 0; +} + +/* + * Initializes dynamic portions of the DWC_otg HCD state + * + * Must be called with interrupt disabled and spinlock held + */ +static void dwc2_hcd_reinit(struct dwc2_hsotg *hsotg) +{ +	struct dwc2_host_chan *chan, *chan_tmp; +	int num_channels; +	int i; + +	hsotg->flags.d32 = 0; +	hsotg->non_periodic_qh_ptr = &hsotg->non_periodic_sched_active; + +	if (hsotg->core_params->uframe_sched > 0) { +		hsotg->available_host_channels = +			hsotg->core_params->host_channels; +	} else { +		hsotg->non_periodic_channels = 0; +		hsotg->periodic_channels = 0; +	} + +	/* +	 * Put all channels in the free channel list and clean up channel +	 * states +	 */ +	list_for_each_entry_safe(chan, chan_tmp, &hsotg->free_hc_list, +				 hc_list_entry) +		list_del_init(&chan->hc_list_entry); + +	num_channels = hsotg->core_params->host_channels; +	for (i = 0; i < num_channels; i++) { +		chan = hsotg->hc_ptr_array[i]; +		list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list); +		dwc2_hc_cleanup(hsotg, chan); +	} + +	/* Initialize the DWC core for host mode operation */ +	dwc2_core_host_init(hsotg); +} + +static void dwc2_hc_init_split(struct dwc2_hsotg *hsotg, +			       struct dwc2_host_chan *chan, +			       struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb) +{ +	int hub_addr, hub_port; + +	chan->do_split = 1; +	chan->xact_pos = qtd->isoc_split_pos; +	chan->complete_split = qtd->complete_split; +	dwc2_host_hub_info(hsotg, urb->priv, &hub_addr, &hub_port); +	chan->hub_addr = (u8)hub_addr; +	chan->hub_port = (u8)hub_port; +} + +static void *dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg, +			       struct dwc2_host_chan *chan, +			       struct dwc2_qtd *qtd, void *bufptr) +{ +	struct dwc2_hcd_urb *urb = qtd->urb; +	struct dwc2_hcd_iso_packet_desc *frame_desc; + +	switch (dwc2_hcd_get_pipe_type(&urb->pipe_info)) { +	case USB_ENDPOINT_XFER_CONTROL: +		chan->ep_type = USB_ENDPOINT_XFER_CONTROL; + +		switch (qtd->control_phase) { +		case DWC2_CONTROL_SETUP: +			dev_vdbg(hsotg->dev, "  Control setup transaction\n"); +			chan->do_ping = 0; +			chan->ep_is_in = 0; +			chan->data_pid_start = DWC2_HC_PID_SETUP; +			if (hsotg->core_params->dma_enable > 0) +				chan->xfer_dma = urb->setup_dma; +			else +				chan->xfer_buf = urb->setup_packet; +			chan->xfer_len = 8; +			bufptr = NULL; +			break; + +		case DWC2_CONTROL_DATA: +			dev_vdbg(hsotg->dev, "  Control data transaction\n"); +			chan->data_pid_start = qtd->data_toggle; +			break; + +		case DWC2_CONTROL_STATUS: +			/* +			 * Direction is opposite of data direction or IN if no +			 * data +			 */ +			dev_vdbg(hsotg->dev, "  Control status transaction\n"); +			if (urb->length == 0) +				chan->ep_is_in = 1; +			else +				chan->ep_is_in = +					dwc2_hcd_is_pipe_out(&urb->pipe_info); +			if (chan->ep_is_in) +				chan->do_ping = 0; +			chan->data_pid_start = DWC2_HC_PID_DATA1; +			chan->xfer_len = 0; +			if (hsotg->core_params->dma_enable > 0) +				chan->xfer_dma = hsotg->status_buf_dma; +			else +				chan->xfer_buf = hsotg->status_buf; +			bufptr = NULL; +			break; +		} +		break; + +	case USB_ENDPOINT_XFER_BULK: +		chan->ep_type = USB_ENDPOINT_XFER_BULK; +		break; + +	case USB_ENDPOINT_XFER_INT: +		chan->ep_type = USB_ENDPOINT_XFER_INT; +		break; + +	case USB_ENDPOINT_XFER_ISOC: +		chan->ep_type = USB_ENDPOINT_XFER_ISOC; +		if (hsotg->core_params->dma_desc_enable > 0) +			break; + +		frame_desc = &urb->iso_descs[qtd->isoc_frame_index]; +		frame_desc->status = 0; + +		if (hsotg->core_params->dma_enable > 0) { +			chan->xfer_dma = urb->dma; +			chan->xfer_dma += frame_desc->offset + +					qtd->isoc_split_offset; +		} else { +			chan->xfer_buf = urb->buf; +			chan->xfer_buf += frame_desc->offset + +					qtd->isoc_split_offset; +		} + +		chan->xfer_len = frame_desc->length - qtd->isoc_split_offset; + +		/* For non-dword aligned buffers */ +		if (hsotg->core_params->dma_enable > 0 && +		    (chan->xfer_dma & 0x3)) +			bufptr = (u8 *)urb->buf + frame_desc->offset + +					qtd->isoc_split_offset; +		else +			bufptr = NULL; + +		if (chan->xact_pos == DWC2_HCSPLT_XACTPOS_ALL) { +			if (chan->xfer_len <= 188) +				chan->xact_pos = DWC2_HCSPLT_XACTPOS_ALL; +			else +				chan->xact_pos = DWC2_HCSPLT_XACTPOS_BEGIN; +		} +		break; +	} + +	return bufptr; +} + +static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, +				   struct dwc2_host_chan *chan, void *bufptr) +{ +	u32 buf_size; + +	if (chan->ep_type != USB_ENDPOINT_XFER_ISOC) +		buf_size = hsotg->core_params->max_transfer_size; +	else +		buf_size = 4096; + +	if (!qh->dw_align_buf) { +		qh->dw_align_buf = dma_alloc_coherent(hsotg->dev, buf_size, +						      &qh->dw_align_buf_dma, +						      GFP_ATOMIC); +		if (!qh->dw_align_buf) +			return -ENOMEM; +	} + +	if (!chan->ep_is_in && chan->xfer_len) { +		dma_sync_single_for_cpu(hsotg->dev, chan->xfer_dma, buf_size, +					DMA_TO_DEVICE); +		memcpy(qh->dw_align_buf, bufptr, chan->xfer_len); +		dma_sync_single_for_device(hsotg->dev, chan->xfer_dma, buf_size, +					   DMA_TO_DEVICE); +	} + +	chan->align_buf = qh->dw_align_buf_dma; +	return 0; +} + +/** + * dwc2_assign_and_init_hc() - Assigns transactions from a QTD to a free host + * channel and initializes the host channel to perform the transactions. The + * host channel is removed from the free list. + * + * @hsotg: The HCD state structure + * @qh:    Transactions from the first QTD for this QH are selected and assigned + *         to a free host channel + */ +static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ +	struct dwc2_host_chan *chan; +	struct dwc2_hcd_urb *urb; +	struct dwc2_qtd *qtd; +	void *bufptr = NULL; + +	if (dbg_qh(qh)) +		dev_vdbg(hsotg->dev, "%s(%p,%p)\n", __func__, hsotg, qh); + +	if (list_empty(&qh->qtd_list)) { +		dev_dbg(hsotg->dev, "No QTDs in QH list\n"); +		return -ENOMEM; +	} + +	if (list_empty(&hsotg->free_hc_list)) { +		dev_dbg(hsotg->dev, "No free channel to assign\n"); +		return -ENOMEM; +	} + +	chan = list_first_entry(&hsotg->free_hc_list, struct dwc2_host_chan, +				hc_list_entry); + +	/* Remove host channel from free list */ +	list_del_init(&chan->hc_list_entry); + +	qtd = list_first_entry(&qh->qtd_list, struct dwc2_qtd, qtd_list_entry); +	urb = qtd->urb; +	qh->channel = chan; +	qtd->in_process = 1; + +	/* +	 * Use usb_pipedevice to determine device address. This address is +	 * 0 before the SET_ADDRESS command and the correct address afterward. +	 */ +	chan->dev_addr = dwc2_hcd_get_dev_addr(&urb->pipe_info); +	chan->ep_num = dwc2_hcd_get_ep_num(&urb->pipe_info); +	chan->speed = qh->dev_speed; +	chan->max_packet = dwc2_max_packet(qh->maxp); + +	chan->xfer_started = 0; +	chan->halt_status = DWC2_HC_XFER_NO_HALT_STATUS; +	chan->error_state = (qtd->error_count > 0); +	chan->halt_on_queue = 0; +	chan->halt_pending = 0; +	chan->requests = 0; + +	/* +	 * The following values may be modified in the transfer type section +	 * below. The xfer_len value may be reduced when the transfer is +	 * started to accommodate the max widths of the XferSize and PktCnt +	 * fields in the HCTSIZn register. +	 */ + +	chan->ep_is_in = (dwc2_hcd_is_pipe_in(&urb->pipe_info) != 0); +	if (chan->ep_is_in) +		chan->do_ping = 0; +	else +		chan->do_ping = qh->ping_state; + +	chan->data_pid_start = qh->data_toggle; +	chan->multi_count = 1; + +	if (urb->actual_length > urb->length && +		!dwc2_hcd_is_pipe_in(&urb->pipe_info)) +		urb->actual_length = urb->length; + +	if (hsotg->core_params->dma_enable > 0) { +		chan->xfer_dma = urb->dma + urb->actual_length; + +		/* For non-dword aligned case */ +		if (hsotg->core_params->dma_desc_enable <= 0 && +		    (chan->xfer_dma & 0x3)) +			bufptr = (u8 *)urb->buf + urb->actual_length; +	} else { +		chan->xfer_buf = (u8 *)urb->buf + urb->actual_length; +	} + +	chan->xfer_len = urb->length - urb->actual_length; +	chan->xfer_count = 0; + +	/* Set the split attributes if required */ +	if (qh->do_split) +		dwc2_hc_init_split(hsotg, chan, qtd, urb); +	else +		chan->do_split = 0; + +	/* Set the transfer attributes */ +	bufptr = dwc2_hc_init_xfer(hsotg, chan, qtd, bufptr); + +	/* Non DWORD-aligned buffer case */ +	if (bufptr) { +		dev_vdbg(hsotg->dev, "Non-aligned buffer\n"); +		if (dwc2_hc_setup_align_buf(hsotg, qh, chan, bufptr)) { +			dev_err(hsotg->dev, +				"%s: Failed to allocate memory to handle non-dword aligned buffer\n", +				__func__); +			/* Add channel back to free list */ +			chan->align_buf = 0; +			chan->multi_count = 0; +			list_add_tail(&chan->hc_list_entry, +				      &hsotg->free_hc_list); +			qtd->in_process = 0; +			qh->channel = NULL; +			return -ENOMEM; +		} +	} else { +		chan->align_buf = 0; +	} + +	if (chan->ep_type == USB_ENDPOINT_XFER_INT || +	    chan->ep_type == USB_ENDPOINT_XFER_ISOC) +		/* +		 * This value may be modified when the transfer is started +		 * to reflect the actual transfer length +		 */ +		chan->multi_count = dwc2_hb_mult(qh->maxp); + +	if (hsotg->core_params->dma_desc_enable > 0) +		chan->desc_list_addr = qh->desc_list_dma; + +	dwc2_hc_init(hsotg, chan); +	chan->qh = qh; + +	return 0; +} + +/** + * dwc2_hcd_select_transactions() - Selects transactions from the HCD transfer + * schedule and assigns them to available host channels. Called from the HCD + * interrupt handler functions. + * + * @hsotg: The HCD state structure + * + * Return: The types of new transactions that were assigned to host channels + */ +enum dwc2_transaction_type dwc2_hcd_select_transactions( +		struct dwc2_hsotg *hsotg) +{ +	enum dwc2_transaction_type ret_val = DWC2_TRANSACTION_NONE; +	struct list_head *qh_ptr; +	struct dwc2_qh *qh; +	int num_channels; + +#ifdef DWC2_DEBUG_SOF +	dev_vdbg(hsotg->dev, "  Select Transactions\n"); +#endif + +	/* Process entries in the periodic ready list */ +	qh_ptr = hsotg->periodic_sched_ready.next; +	while (qh_ptr != &hsotg->periodic_sched_ready) { +		if (list_empty(&hsotg->free_hc_list)) +			break; +		if (hsotg->core_params->uframe_sched > 0) { +			if (hsotg->available_host_channels <= 1) +				break; +			hsotg->available_host_channels--; +		} +		qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry); +		if (dwc2_assign_and_init_hc(hsotg, qh)) +			break; + +		/* +		 * Move the QH from the periodic ready schedule to the +		 * periodic assigned schedule +		 */ +		qh_ptr = qh_ptr->next; +		list_move(&qh->qh_list_entry, &hsotg->periodic_sched_assigned); +		ret_val = DWC2_TRANSACTION_PERIODIC; +	} + +	/* +	 * Process entries in the inactive portion of the non-periodic +	 * schedule. Some free host channels may not be used if they are +	 * reserved for periodic transfers. +	 */ +	num_channels = hsotg->core_params->host_channels; +	qh_ptr = hsotg->non_periodic_sched_inactive.next; +	while (qh_ptr != &hsotg->non_periodic_sched_inactive) { +		if (hsotg->core_params->uframe_sched <= 0 && +		    hsotg->non_periodic_channels >= num_channels - +						hsotg->periodic_channels) +			break; +		if (list_empty(&hsotg->free_hc_list)) +			break; +		qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry); +		if (hsotg->core_params->uframe_sched > 0) { +			if (hsotg->available_host_channels < 1) +				break; +			hsotg->available_host_channels--; +		} + +		if (dwc2_assign_and_init_hc(hsotg, qh)) +			break; + +		/* +		 * Move the QH from the non-periodic inactive schedule to the +		 * non-periodic active schedule +		 */ +		qh_ptr = qh_ptr->next; +		list_move(&qh->qh_list_entry, +			  &hsotg->non_periodic_sched_active); + +		if (ret_val == DWC2_TRANSACTION_NONE) +			ret_val = DWC2_TRANSACTION_NON_PERIODIC; +		else +			ret_val = DWC2_TRANSACTION_ALL; + +		if (hsotg->core_params->uframe_sched <= 0) +			hsotg->non_periodic_channels++; +	} + +	return ret_val; +} + +/** + * dwc2_queue_transaction() - Attempts to queue a single transaction request for + * a host channel associated with either a periodic or non-periodic transfer + * + * @hsotg: The HCD state structure + * @chan:  Host channel descriptor associated with either a periodic or + *         non-periodic transfer + * @fifo_dwords_avail: Number of DWORDs available in the periodic Tx FIFO + *                     for periodic transfers or the non-periodic Tx FIFO + *                     for non-periodic transfers + * + * Return: 1 if a request is queued and more requests may be needed to + * complete the transfer, 0 if no more requests are required for this + * transfer, -1 if there is insufficient space in the Tx FIFO + * + * This function assumes that there is space available in the appropriate + * request queue. For an OUT transfer or SETUP transaction in Slave mode, + * it checks whether space is available in the appropriate Tx FIFO. + * + * Must be called with interrupt disabled and spinlock held + */ +static int dwc2_queue_transaction(struct dwc2_hsotg *hsotg, +				  struct dwc2_host_chan *chan, +				  u16 fifo_dwords_avail) +{ +	int retval = 0; + +	if (hsotg->core_params->dma_enable > 0) { +		if (hsotg->core_params->dma_desc_enable > 0) { +			if (!chan->xfer_started || +			    chan->ep_type == USB_ENDPOINT_XFER_ISOC) { +				dwc2_hcd_start_xfer_ddma(hsotg, chan->qh); +				chan->qh->ping_state = 0; +			} +		} else if (!chan->xfer_started) { +			dwc2_hc_start_transfer(hsotg, chan); +			chan->qh->ping_state = 0; +		} +	} else if (chan->halt_pending) { +		/* Don't queue a request if the channel has been halted */ +	} else if (chan->halt_on_queue) { +		dwc2_hc_halt(hsotg, chan, chan->halt_status); +	} else if (chan->do_ping) { +		if (!chan->xfer_started) +			dwc2_hc_start_transfer(hsotg, chan); +	} else if (!chan->ep_is_in || +		   chan->data_pid_start == DWC2_HC_PID_SETUP) { +		if ((fifo_dwords_avail * 4) >= chan->max_packet) { +			if (!chan->xfer_started) { +				dwc2_hc_start_transfer(hsotg, chan); +				retval = 1; +			} else { +				retval = dwc2_hc_continue_transfer(hsotg, chan); +			} +		} else { +			retval = -1; +		} +	} else { +		if (!chan->xfer_started) { +			dwc2_hc_start_transfer(hsotg, chan); +			retval = 1; +		} else { +			retval = dwc2_hc_continue_transfer(hsotg, chan); +		} +	} + +	return retval; +} + +/* + * Processes periodic channels for the next frame and queues transactions for + * these channels to the DWC_otg controller. After queueing transactions, the + * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions + * to queue as Periodic Tx FIFO or request queue space becomes available. + * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled. + * + * Must be called with interrupt disabled and spinlock held + */ +static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg) +{ +	struct list_head *qh_ptr; +	struct dwc2_qh *qh; +	u32 tx_status; +	u32 fspcavail; +	u32 gintmsk; +	int status; +	int no_queue_space = 0; +	int no_fifo_space = 0; +	u32 qspcavail; + +	if (dbg_perio()) +		dev_vdbg(hsotg->dev, "Queue periodic transactions\n"); + +	tx_status = readl(hsotg->regs + HPTXSTS); +	qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >> +		    TXSTS_QSPCAVAIL_SHIFT; +	fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >> +		    TXSTS_FSPCAVAIL_SHIFT; + +	if (dbg_perio()) { +		dev_vdbg(hsotg->dev, "  P Tx Req Queue Space Avail (before queue): %d\n", +			 qspcavail); +		dev_vdbg(hsotg->dev, "  P Tx FIFO Space Avail (before queue): %d\n", +			 fspcavail); +	} + +	qh_ptr = hsotg->periodic_sched_assigned.next; +	while (qh_ptr != &hsotg->periodic_sched_assigned) { +		tx_status = readl(hsotg->regs + HPTXSTS); +		qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >> +			    TXSTS_QSPCAVAIL_SHIFT; +		if (qspcavail == 0) { +			no_queue_space = 1; +			break; +		} + +		qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry); +		if (!qh->channel) { +			qh_ptr = qh_ptr->next; +			continue; +		} + +		/* Make sure EP's TT buffer is clean before queueing qtds */ +		if (qh->tt_buffer_dirty) { +			qh_ptr = qh_ptr->next; +			continue; +		} + +		/* +		 * Set a flag if we're queuing high-bandwidth in slave mode. +		 * The flag prevents any halts to get into the request queue in +		 * the middle of multiple high-bandwidth packets getting queued. +		 */ +		if (hsotg->core_params->dma_enable <= 0 && +				qh->channel->multi_count > 1) +			hsotg->queuing_high_bandwidth = 1; + +		fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >> +			    TXSTS_FSPCAVAIL_SHIFT; +		status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail); +		if (status < 0) { +			no_fifo_space = 1; +			break; +		} + +		/* +		 * In Slave mode, stay on the current transfer until there is +		 * nothing more to do or the high-bandwidth request count is +		 * reached. In DMA mode, only need to queue one request. The +		 * controller automatically handles multiple packets for +		 * high-bandwidth transfers. +		 */ +		if (hsotg->core_params->dma_enable > 0 || status == 0 || +		    qh->channel->requests == qh->channel->multi_count) { +			qh_ptr = qh_ptr->next; +			/* +			 * Move the QH from the periodic assigned schedule to +			 * the periodic queued schedule +			 */ +			list_move(&qh->qh_list_entry, +				  &hsotg->periodic_sched_queued); + +			/* done queuing high bandwidth */ +			hsotg->queuing_high_bandwidth = 0; +		} +	} + +	if (hsotg->core_params->dma_enable <= 0) { +		tx_status = readl(hsotg->regs + HPTXSTS); +		qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >> +			    TXSTS_QSPCAVAIL_SHIFT; +		fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >> +			    TXSTS_FSPCAVAIL_SHIFT; +		if (dbg_perio()) { +			dev_vdbg(hsotg->dev, +				 "  P Tx Req Queue Space Avail (after queue): %d\n", +				 qspcavail); +			dev_vdbg(hsotg->dev, +				 "  P Tx FIFO Space Avail (after queue): %d\n", +				 fspcavail); +		} + +		if (!list_empty(&hsotg->periodic_sched_assigned) || +		    no_queue_space || no_fifo_space) { +			/* +			 * May need to queue more transactions as the request +			 * queue or Tx FIFO empties. Enable the periodic Tx +			 * FIFO empty interrupt. (Always use the half-empty +			 * level to ensure that new requests are loaded as +			 * soon as possible.) +			 */ +			gintmsk = readl(hsotg->regs + GINTMSK); +			gintmsk |= GINTSTS_PTXFEMP; +			writel(gintmsk, hsotg->regs + GINTMSK); +		} else { +			/* +			 * Disable the Tx FIFO empty interrupt since there are +			 * no more transactions that need to be queued right +			 * now. This function is called from interrupt +			 * handlers to queue more transactions as transfer +			 * states change. +			 */ +			gintmsk = readl(hsotg->regs + GINTMSK); +			gintmsk &= ~GINTSTS_PTXFEMP; +			writel(gintmsk, hsotg->regs + GINTMSK); +		} +	} +} + +/* + * Processes active non-periodic channels and queues transactions for these + * channels to the DWC_otg controller. After queueing transactions, the NP Tx + * FIFO Empty interrupt is enabled if there are more transactions to queue as + * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx + * FIFO Empty interrupt is disabled. + * + * Must be called with interrupt disabled and spinlock held + */ +static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg) +{ +	struct list_head *orig_qh_ptr; +	struct dwc2_qh *qh; +	u32 tx_status; +	u32 qspcavail; +	u32 fspcavail; +	u32 gintmsk; +	int status; +	int no_queue_space = 0; +	int no_fifo_space = 0; +	int more_to_do = 0; + +	dev_vdbg(hsotg->dev, "Queue non-periodic transactions\n"); + +	tx_status = readl(hsotg->regs + GNPTXSTS); +	qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >> +		    TXSTS_QSPCAVAIL_SHIFT; +	fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >> +		    TXSTS_FSPCAVAIL_SHIFT; +	dev_vdbg(hsotg->dev, "  NP Tx Req Queue Space Avail (before queue): %d\n", +		 qspcavail); +	dev_vdbg(hsotg->dev, "  NP Tx FIFO Space Avail (before queue): %d\n", +		 fspcavail); + +	/* +	 * Keep track of the starting point. Skip over the start-of-list +	 * entry. +	 */ +	if (hsotg->non_periodic_qh_ptr == &hsotg->non_periodic_sched_active) +		hsotg->non_periodic_qh_ptr = hsotg->non_periodic_qh_ptr->next; +	orig_qh_ptr = hsotg->non_periodic_qh_ptr; + +	/* +	 * Process once through the active list or until no more space is +	 * available in the request queue or the Tx FIFO +	 */ +	do { +		tx_status = readl(hsotg->regs + GNPTXSTS); +		qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >> +			    TXSTS_QSPCAVAIL_SHIFT; +		if (hsotg->core_params->dma_enable <= 0 && qspcavail == 0) { +			no_queue_space = 1; +			break; +		} + +		qh = list_entry(hsotg->non_periodic_qh_ptr, struct dwc2_qh, +				qh_list_entry); +		if (!qh->channel) +			goto next; + +		/* Make sure EP's TT buffer is clean before queueing qtds */ +		if (qh->tt_buffer_dirty) +			goto next; + +		fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >> +			    TXSTS_FSPCAVAIL_SHIFT; +		status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail); + +		if (status > 0) { +			more_to_do = 1; +		} else if (status < 0) { +			no_fifo_space = 1; +			break; +		} +next: +		/* Advance to next QH, skipping start-of-list entry */ +		hsotg->non_periodic_qh_ptr = hsotg->non_periodic_qh_ptr->next; +		if (hsotg->non_periodic_qh_ptr == +				&hsotg->non_periodic_sched_active) +			hsotg->non_periodic_qh_ptr = +					hsotg->non_periodic_qh_ptr->next; +	} while (hsotg->non_periodic_qh_ptr != orig_qh_ptr); + +	if (hsotg->core_params->dma_enable <= 0) { +		tx_status = readl(hsotg->regs + GNPTXSTS); +		qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >> +			    TXSTS_QSPCAVAIL_SHIFT; +		fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >> +			    TXSTS_FSPCAVAIL_SHIFT; +		dev_vdbg(hsotg->dev, +			 "  NP Tx Req Queue Space Avail (after queue): %d\n", +			 qspcavail); +		dev_vdbg(hsotg->dev, +			 "  NP Tx FIFO Space Avail (after queue): %d\n", +			 fspcavail); + +		if (more_to_do || no_queue_space || no_fifo_space) { +			/* +			 * May need to queue more transactions as the request +			 * queue or Tx FIFO empties. Enable the non-periodic +			 * Tx FIFO empty interrupt. (Always use the half-empty +			 * level to ensure that new requests are loaded as +			 * soon as possible.) +			 */ +			gintmsk = readl(hsotg->regs + GINTMSK); +			gintmsk |= GINTSTS_NPTXFEMP; +			writel(gintmsk, hsotg->regs + GINTMSK); +		} else { +			/* +			 * Disable the Tx FIFO empty interrupt since there are +			 * no more transactions that need to be queued right +			 * now. This function is called from interrupt +			 * handlers to queue more transactions as transfer +			 * states change. +			 */ +			gintmsk = readl(hsotg->regs + GINTMSK); +			gintmsk &= ~GINTSTS_NPTXFEMP; +			writel(gintmsk, hsotg->regs + GINTMSK); +		} +	} +} + +/** + * dwc2_hcd_queue_transactions() - Processes the currently active host channels + * and queues transactions for these channels to the DWC_otg controller. Called + * from the HCD interrupt handler functions. + * + * @hsotg:   The HCD state structure + * @tr_type: The type(s) of transactions to queue (non-periodic, periodic, + *           or both) + * + * Must be called with interrupt disabled and spinlock held + */ +void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg, +				 enum dwc2_transaction_type tr_type) +{ +#ifdef DWC2_DEBUG_SOF +	dev_vdbg(hsotg->dev, "Queue Transactions\n"); +#endif +	/* Process host channels associated with periodic transfers */ +	if ((tr_type == DWC2_TRANSACTION_PERIODIC || +	     tr_type == DWC2_TRANSACTION_ALL) && +	    !list_empty(&hsotg->periodic_sched_assigned)) +		dwc2_process_periodic_channels(hsotg); + +	/* Process host channels associated with non-periodic transfers */ +	if (tr_type == DWC2_TRANSACTION_NON_PERIODIC || +	    tr_type == DWC2_TRANSACTION_ALL) { +		if (!list_empty(&hsotg->non_periodic_sched_active)) { +			dwc2_process_non_periodic_channels(hsotg); +		} else { +			/* +			 * Ensure NP Tx FIFO empty interrupt is disabled when +			 * there are no non-periodic transfers to process +			 */ +			u32 gintmsk = readl(hsotg->regs + GINTMSK); + +			gintmsk &= ~GINTSTS_NPTXFEMP; +			writel(gintmsk, hsotg->regs + GINTMSK); +		} +	} +} + +static void dwc2_conn_id_status_change(struct work_struct *work) +{ +	struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg, +						wf_otg); +	u32 count = 0; +	u32 gotgctl; + +	dev_dbg(hsotg->dev, "%s()\n", __func__); + +	gotgctl = readl(hsotg->regs + GOTGCTL); +	dev_dbg(hsotg->dev, "gotgctl=%0x\n", gotgctl); +	dev_dbg(hsotg->dev, "gotgctl.b.conidsts=%d\n", +		!!(gotgctl & GOTGCTL_CONID_B)); + +	/* B-Device connector (Device Mode) */ +	if (gotgctl & GOTGCTL_CONID_B) { +		/* Wait for switch to device mode */ +		dev_dbg(hsotg->dev, "connId B\n"); +		while (!dwc2_is_device_mode(hsotg)) { +			dev_info(hsotg->dev, +				 "Waiting for Peripheral Mode, Mode=%s\n", +				 dwc2_is_host_mode(hsotg) ? "Host" : +				 "Peripheral"); +			usleep_range(20000, 40000); +			if (++count > 250) +				break; +		} +		if (count > 250) +			dev_err(hsotg->dev, +				"Connection id status change timed out\n"); +		hsotg->op_state = OTG_STATE_B_PERIPHERAL; +		dwc2_core_init(hsotg, false, -1); +		dwc2_enable_global_interrupts(hsotg); +	} else { +		/* A-Device connector (Host Mode) */ +		dev_dbg(hsotg->dev, "connId A\n"); +		while (!dwc2_is_host_mode(hsotg)) { +			dev_info(hsotg->dev, "Waiting for Host Mode, Mode=%s\n", +				 dwc2_is_host_mode(hsotg) ? +				 "Host" : "Peripheral"); +			usleep_range(20000, 40000); +			if (++count > 250) +				break; +		} +		if (count > 250) +			dev_err(hsotg->dev, +				"Connection id status change timed out\n"); +		hsotg->op_state = OTG_STATE_A_HOST; + +		/* Initialize the Core for Host mode */ +		dwc2_core_init(hsotg, false, -1); +		dwc2_enable_global_interrupts(hsotg); +		dwc2_hcd_start(hsotg); +	} +} + +static void dwc2_wakeup_detected(unsigned long data) +{ +	struct dwc2_hsotg *hsotg = (struct dwc2_hsotg *)data; +	u32 hprt0; + +	dev_dbg(hsotg->dev, "%s()\n", __func__); + +	/* +	 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms +	 * so that OPT tests pass with all PHYs.) +	 */ +	hprt0 = dwc2_read_hprt0(hsotg); +	dev_dbg(hsotg->dev, "Resume: HPRT0=%0x\n", hprt0); +	hprt0 &= ~HPRT0_RES; +	writel(hprt0, hsotg->regs + HPRT0); +	dev_dbg(hsotg->dev, "Clear Resume: HPRT0=%0x\n", +		readl(hsotg->regs + HPRT0)); + +	dwc2_hcd_rem_wakeup(hsotg); + +	/* Change to L0 state */ +	hsotg->lx_state = DWC2_L0; +} + +static int dwc2_host_is_b_hnp_enabled(struct dwc2_hsotg *hsotg) +{ +	struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg); + +	return hcd->self.b_hnp_enable; +} + +/* Must NOT be called with interrupt disabled or spinlock held */ +static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) +{ +	unsigned long flags; +	u32 hprt0; +	u32 pcgctl; +	u32 gotgctl; + +	dev_dbg(hsotg->dev, "%s()\n", __func__); + +	spin_lock_irqsave(&hsotg->lock, flags); + +	if (windex == hsotg->otg_port && dwc2_host_is_b_hnp_enabled(hsotg)) { +		gotgctl = readl(hsotg->regs + GOTGCTL); +		gotgctl |= GOTGCTL_HSTSETHNPEN; +		writel(gotgctl, hsotg->regs + GOTGCTL); +		hsotg->op_state = OTG_STATE_A_SUSPEND; +	} + +	hprt0 = dwc2_read_hprt0(hsotg); +	hprt0 |= HPRT0_SUSP; +	writel(hprt0, hsotg->regs + HPRT0); + +	/* Update lx_state */ +	hsotg->lx_state = DWC2_L2; + +	/* Suspend the Phy Clock */ +	pcgctl = readl(hsotg->regs + PCGCTL); +	pcgctl |= PCGCTL_STOPPCLK; +	writel(pcgctl, hsotg->regs + PCGCTL); +	udelay(10); + +	/* For HNP the bus must be suspended for at least 200ms */ +	if (dwc2_host_is_b_hnp_enabled(hsotg)) { +		pcgctl = readl(hsotg->regs + PCGCTL); +		pcgctl &= ~PCGCTL_STOPPCLK; +		writel(pcgctl, hsotg->regs + PCGCTL); + +		spin_unlock_irqrestore(&hsotg->lock, flags); + +		usleep_range(200000, 250000); +	} else { +		spin_unlock_irqrestore(&hsotg->lock, flags); +	} +} + +/* Handles hub class-specific requests */ +static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, +				u16 wvalue, u16 windex, char *buf, u16 wlength) +{ +	struct usb_hub_descriptor *hub_desc; +	int retval = 0; +	u32 hprt0; +	u32 port_status; +	u32 speed; +	u32 pcgctl; + +	switch (typereq) { +	case ClearHubFeature: +		dev_dbg(hsotg->dev, "ClearHubFeature %1xh\n", wvalue); + +		switch (wvalue) { +		case C_HUB_LOCAL_POWER: +		case C_HUB_OVER_CURRENT: +			/* Nothing required here */ +			break; + +		default: +			retval = -EINVAL; +			dev_err(hsotg->dev, +				"ClearHubFeature request %1xh unknown\n", +				wvalue); +		} +		break; + +	case ClearPortFeature: +		if (wvalue != USB_PORT_FEAT_L1) +			if (!windex || windex > 1) +				goto error; +		switch (wvalue) { +		case USB_PORT_FEAT_ENABLE: +			dev_dbg(hsotg->dev, +				"ClearPortFeature USB_PORT_FEAT_ENABLE\n"); +			hprt0 = dwc2_read_hprt0(hsotg); +			hprt0 |= HPRT0_ENA; +			writel(hprt0, hsotg->regs + HPRT0); +			break; + +		case USB_PORT_FEAT_SUSPEND: +			dev_dbg(hsotg->dev, +				"ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); +			writel(0, hsotg->regs + PCGCTL); +			usleep_range(20000, 40000); + +			hprt0 = dwc2_read_hprt0(hsotg); +			hprt0 |= HPRT0_RES; +			writel(hprt0, hsotg->regs + HPRT0); +			hprt0 &= ~HPRT0_SUSP; +			usleep_range(100000, 150000); + +			hprt0 &= ~HPRT0_RES; +			writel(hprt0, hsotg->regs + HPRT0); +			break; + +		case USB_PORT_FEAT_POWER: +			dev_dbg(hsotg->dev, +				"ClearPortFeature USB_PORT_FEAT_POWER\n"); +			hprt0 = dwc2_read_hprt0(hsotg); +			hprt0 &= ~HPRT0_PWR; +			writel(hprt0, hsotg->regs + HPRT0); +			break; + +		case USB_PORT_FEAT_INDICATOR: +			dev_dbg(hsotg->dev, +				"ClearPortFeature USB_PORT_FEAT_INDICATOR\n"); +			/* Port indicator not supported */ +			break; + +		case USB_PORT_FEAT_C_CONNECTION: +			/* +			 * Clears driver's internal Connect Status Change flag +			 */ +			dev_dbg(hsotg->dev, +				"ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n"); +			hsotg->flags.b.port_connect_status_change = 0; +			break; + +		case USB_PORT_FEAT_C_RESET: +			/* Clears driver's internal Port Reset Change flag */ +			dev_dbg(hsotg->dev, +				"ClearPortFeature USB_PORT_FEAT_C_RESET\n"); +			hsotg->flags.b.port_reset_change = 0; +			break; + +		case USB_PORT_FEAT_C_ENABLE: +			/* +			 * Clears the driver's internal Port Enable/Disable +			 * Change flag +			 */ +			dev_dbg(hsotg->dev, +				"ClearPortFeature USB_PORT_FEAT_C_ENABLE\n"); +			hsotg->flags.b.port_enable_change = 0; +			break; + +		case USB_PORT_FEAT_C_SUSPEND: +			/* +			 * Clears the driver's internal Port Suspend Change +			 * flag, which is set when resume signaling on the host +			 * port is complete +			 */ +			dev_dbg(hsotg->dev, +				"ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n"); +			hsotg->flags.b.port_suspend_change = 0; +			break; + +		case USB_PORT_FEAT_C_PORT_L1: +			dev_dbg(hsotg->dev, +				"ClearPortFeature USB_PORT_FEAT_C_PORT_L1\n"); +			hsotg->flags.b.port_l1_change = 0; +			break; + +		case USB_PORT_FEAT_C_OVER_CURRENT: +			dev_dbg(hsotg->dev, +				"ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n"); +			hsotg->flags.b.port_over_current_change = 0; +			break; + +		default: +			retval = -EINVAL; +			dev_err(hsotg->dev, +				"ClearPortFeature request %1xh unknown or unsupported\n", +				wvalue); +		} +		break; + +	case GetHubDescriptor: +		dev_dbg(hsotg->dev, "GetHubDescriptor\n"); +		hub_desc = (struct usb_hub_descriptor *)buf; +		hub_desc->bDescLength = 9; +		hub_desc->bDescriptorType = 0x29; +		hub_desc->bNbrPorts = 1; +		hub_desc->wHubCharacteristics = cpu_to_le16(0x08); +		hub_desc->bPwrOn2PwrGood = 1; +		hub_desc->bHubContrCurrent = 0; +		hub_desc->u.hs.DeviceRemovable[0] = 0; +		hub_desc->u.hs.DeviceRemovable[1] = 0xff; +		break; + +	case GetHubStatus: +		dev_dbg(hsotg->dev, "GetHubStatus\n"); +		memset(buf, 0, 4); +		break; + +	case GetPortStatus: +		dev_vdbg(hsotg->dev, +			 "GetPortStatus wIndex=0x%04x flags=0x%08x\n", windex, +			 hsotg->flags.d32); +		if (!windex || windex > 1) +			goto error; + +		port_status = 0; +		if (hsotg->flags.b.port_connect_status_change) +			port_status |= USB_PORT_STAT_C_CONNECTION << 16; +		if (hsotg->flags.b.port_enable_change) +			port_status |= USB_PORT_STAT_C_ENABLE << 16; +		if (hsotg->flags.b.port_suspend_change) +			port_status |= USB_PORT_STAT_C_SUSPEND << 16; +		if (hsotg->flags.b.port_l1_change) +			port_status |= USB_PORT_STAT_C_L1 << 16; +		if (hsotg->flags.b.port_reset_change) +			port_status |= USB_PORT_STAT_C_RESET << 16; +		if (hsotg->flags.b.port_over_current_change) { +			dev_warn(hsotg->dev, "Overcurrent change detected\n"); +			port_status |= USB_PORT_STAT_C_OVERCURRENT << 16; +		} + +		if (!hsotg->flags.b.port_connect_status) { +			/* +			 * The port is disconnected, which means the core is +			 * either in device mode or it soon will be. Just +			 * return 0's for the remainder of the port status +			 * since the port register can't be read if the core +			 * is in device mode. +			 */ +			*(__le32 *)buf = cpu_to_le32(port_status); +			break; +		} + +		hprt0 = readl(hsotg->regs + HPRT0); +		dev_vdbg(hsotg->dev, "  HPRT0: 0x%08x\n", hprt0); + +		if (hprt0 & HPRT0_CONNSTS) +			port_status |= USB_PORT_STAT_CONNECTION; +		if (hprt0 & HPRT0_ENA) +			port_status |= USB_PORT_STAT_ENABLE; +		if (hprt0 & HPRT0_SUSP) +			port_status |= USB_PORT_STAT_SUSPEND; +		if (hprt0 & HPRT0_OVRCURRACT) +			port_status |= USB_PORT_STAT_OVERCURRENT; +		if (hprt0 & HPRT0_RST) +			port_status |= USB_PORT_STAT_RESET; +		if (hprt0 & HPRT0_PWR) +			port_status |= USB_PORT_STAT_POWER; + +		speed = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT; +		if (speed == HPRT0_SPD_HIGH_SPEED) +			port_status |= USB_PORT_STAT_HIGH_SPEED; +		else if (speed == HPRT0_SPD_LOW_SPEED) +			port_status |= USB_PORT_STAT_LOW_SPEED; + +		if (hprt0 & HPRT0_TSTCTL_MASK) +			port_status |= USB_PORT_STAT_TEST; +		/* USB_PORT_FEAT_INDICATOR unsupported always 0 */ + +		dev_vdbg(hsotg->dev, "port_status=%08x\n", port_status); +		*(__le32 *)buf = cpu_to_le32(port_status); +		break; + +	case SetHubFeature: +		dev_dbg(hsotg->dev, "SetHubFeature\n"); +		/* No HUB features supported */ +		break; + +	case SetPortFeature: +		dev_dbg(hsotg->dev, "SetPortFeature\n"); +		if (wvalue != USB_PORT_FEAT_TEST && (!windex || windex > 1)) +			goto error; + +		if (!hsotg->flags.b.port_connect_status) { +			/* +			 * The port is disconnected, which means the core is +			 * either in device mode or it soon will be. Just +			 * return without doing anything since the port +			 * register can't be written if the core is in device +			 * mode. +			 */ +			break; +		} + +		switch (wvalue) { +		case USB_PORT_FEAT_SUSPEND: +			dev_dbg(hsotg->dev, +				"SetPortFeature - USB_PORT_FEAT_SUSPEND\n"); +			if (windex != hsotg->otg_port) +				goto error; +			dwc2_port_suspend(hsotg, windex); +			break; + +		case USB_PORT_FEAT_POWER: +			dev_dbg(hsotg->dev, +				"SetPortFeature - USB_PORT_FEAT_POWER\n"); +			hprt0 = dwc2_read_hprt0(hsotg); +			hprt0 |= HPRT0_PWR; +			writel(hprt0, hsotg->regs + HPRT0); +			break; + +		case USB_PORT_FEAT_RESET: +			hprt0 = dwc2_read_hprt0(hsotg); +			dev_dbg(hsotg->dev, +				"SetPortFeature - USB_PORT_FEAT_RESET\n"); +			pcgctl = readl(hsotg->regs + PCGCTL); +			pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING | PCGCTL_STOPPCLK); +			writel(pcgctl, hsotg->regs + PCGCTL); +			/* ??? Original driver does this */ +			writel(0, hsotg->regs + PCGCTL); + +			hprt0 = dwc2_read_hprt0(hsotg); +			/* Clear suspend bit if resetting from suspend state */ +			hprt0 &= ~HPRT0_SUSP; + +			/* +			 * When B-Host the Port reset bit is set in the Start +			 * HCD Callback function, so that the reset is started +			 * within 1ms of the HNP success interrupt +			 */ +			if (!dwc2_hcd_is_b_host(hsotg)) { +				hprt0 |= HPRT0_PWR | HPRT0_RST; +				dev_dbg(hsotg->dev, +					"In host mode, hprt0=%08x\n", hprt0); +				writel(hprt0, hsotg->regs + HPRT0); +			} + +			/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ +			usleep_range(50000, 70000); +			hprt0 &= ~HPRT0_RST; +			writel(hprt0, hsotg->regs + HPRT0); +			hsotg->lx_state = DWC2_L0; /* Now back to On state */ +			break; + +		case USB_PORT_FEAT_INDICATOR: +			dev_dbg(hsotg->dev, +				"SetPortFeature - USB_PORT_FEAT_INDICATOR\n"); +			/* Not supported */ +			break; + +		default: +			retval = -EINVAL; +			dev_err(hsotg->dev, +				"SetPortFeature %1xh unknown or unsupported\n", +				wvalue); +			break; +		} +		break; + +	default: +error: +		retval = -EINVAL; +		dev_dbg(hsotg->dev, +			"Unknown hub control request: %1xh wIndex: %1xh wValue: %1xh\n", +			typereq, windex, wvalue); +		break; +	} + +	return retval; +} + +static int dwc2_hcd_is_status_changed(struct dwc2_hsotg *hsotg, int port) +{ +	int retval; + +	if (port != 1) +		return -EINVAL; + +	retval = (hsotg->flags.b.port_connect_status_change || +		  hsotg->flags.b.port_reset_change || +		  hsotg->flags.b.port_enable_change || +		  hsotg->flags.b.port_suspend_change || +		  hsotg->flags.b.port_over_current_change); + +	if (retval) { +		dev_dbg(hsotg->dev, +			"DWC OTG HCD HUB STATUS DATA: Root port status changed\n"); +		dev_dbg(hsotg->dev, "  port_connect_status_change: %d\n", +			hsotg->flags.b.port_connect_status_change); +		dev_dbg(hsotg->dev, "  port_reset_change: %d\n", +			hsotg->flags.b.port_reset_change); +		dev_dbg(hsotg->dev, "  port_enable_change: %d\n", +			hsotg->flags.b.port_enable_change); +		dev_dbg(hsotg->dev, "  port_suspend_change: %d\n", +			hsotg->flags.b.port_suspend_change); +		dev_dbg(hsotg->dev, "  port_over_current_change: %d\n", +			hsotg->flags.b.port_over_current_change); +	} + +	return retval; +} + +int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg) +{ +	u32 hfnum = readl(hsotg->regs + HFNUM); + +#ifdef DWC2_DEBUG_SOF +	dev_vdbg(hsotg->dev, "DWC OTG HCD GET FRAME NUMBER %d\n", +		 (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT); +#endif +	return (hfnum & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT; +} + +int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg) +{ +	return hsotg->op_state == OTG_STATE_B_HOST; +} + +static struct dwc2_hcd_urb *dwc2_hcd_urb_alloc(struct dwc2_hsotg *hsotg, +					       int iso_desc_count, +					       gfp_t mem_flags) +{ +	struct dwc2_hcd_urb *urb; +	u32 size = sizeof(*urb) + iso_desc_count * +		   sizeof(struct dwc2_hcd_iso_packet_desc); + +	urb = kzalloc(size, mem_flags); +	if (urb) +		urb->packet_count = iso_desc_count; +	return urb; +} + +static void dwc2_hcd_urb_set_pipeinfo(struct dwc2_hsotg *hsotg, +				      struct dwc2_hcd_urb *urb, u8 dev_addr, +				      u8 ep_num, u8 ep_type, u8 ep_dir, u16 mps) +{ +	if (dbg_perio() || +	    ep_type == USB_ENDPOINT_XFER_BULK || +	    ep_type == USB_ENDPOINT_XFER_CONTROL) +		dev_vdbg(hsotg->dev, +			 "addr=%d, ep_num=%d, ep_dir=%1x, ep_type=%1x, mps=%d\n", +			 dev_addr, ep_num, ep_dir, ep_type, mps); +	urb->pipe_info.dev_addr = dev_addr; +	urb->pipe_info.ep_num = ep_num; +	urb->pipe_info.pipe_type = ep_type; +	urb->pipe_info.pipe_dir = ep_dir; +	urb->pipe_info.mps = mps; +} + +/* + * NOTE: This function will be removed once the peripheral controller code + * is integrated and the driver is stable + */ +void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg) +{ +#ifdef DEBUG +	struct dwc2_host_chan *chan; +	struct dwc2_hcd_urb *urb; +	struct dwc2_qtd *qtd; +	int num_channels; +	u32 np_tx_status; +	u32 p_tx_status; +	int i; + +	num_channels = hsotg->core_params->host_channels; +	dev_dbg(hsotg->dev, "\n"); +	dev_dbg(hsotg->dev, +		"************************************************************\n"); +	dev_dbg(hsotg->dev, "HCD State:\n"); +	dev_dbg(hsotg->dev, "  Num channels: %d\n", num_channels); + +	for (i = 0; i < num_channels; i++) { +		chan = hsotg->hc_ptr_array[i]; +		dev_dbg(hsotg->dev, "  Channel %d:\n", i); +		dev_dbg(hsotg->dev, +			"    dev_addr: %d, ep_num: %d, ep_is_in: %d\n", +			chan->dev_addr, chan->ep_num, chan->ep_is_in); +		dev_dbg(hsotg->dev, "    speed: %d\n", chan->speed); +		dev_dbg(hsotg->dev, "    ep_type: %d\n", chan->ep_type); +		dev_dbg(hsotg->dev, "    max_packet: %d\n", chan->max_packet); +		dev_dbg(hsotg->dev, "    data_pid_start: %d\n", +			chan->data_pid_start); +		dev_dbg(hsotg->dev, "    multi_count: %d\n", chan->multi_count); +		dev_dbg(hsotg->dev, "    xfer_started: %d\n", +			chan->xfer_started); +		dev_dbg(hsotg->dev, "    xfer_buf: %p\n", chan->xfer_buf); +		dev_dbg(hsotg->dev, "    xfer_dma: %08lx\n", +			(unsigned long)chan->xfer_dma); +		dev_dbg(hsotg->dev, "    xfer_len: %d\n", chan->xfer_len); +		dev_dbg(hsotg->dev, "    xfer_count: %d\n", chan->xfer_count); +		dev_dbg(hsotg->dev, "    halt_on_queue: %d\n", +			chan->halt_on_queue); +		dev_dbg(hsotg->dev, "    halt_pending: %d\n", +			chan->halt_pending); +		dev_dbg(hsotg->dev, "    halt_status: %d\n", chan->halt_status); +		dev_dbg(hsotg->dev, "    do_split: %d\n", chan->do_split); +		dev_dbg(hsotg->dev, "    complete_split: %d\n", +			chan->complete_split); +		dev_dbg(hsotg->dev, "    hub_addr: %d\n", chan->hub_addr); +		dev_dbg(hsotg->dev, "    hub_port: %d\n", chan->hub_port); +		dev_dbg(hsotg->dev, "    xact_pos: %d\n", chan->xact_pos); +		dev_dbg(hsotg->dev, "    requests: %d\n", chan->requests); +		dev_dbg(hsotg->dev, "    qh: %p\n", chan->qh); + +		if (chan->xfer_started) { +			u32 hfnum, hcchar, hctsiz, hcint, hcintmsk; + +			hfnum = readl(hsotg->regs + HFNUM); +			hcchar = readl(hsotg->regs + HCCHAR(i)); +			hctsiz = readl(hsotg->regs + HCTSIZ(i)); +			hcint = readl(hsotg->regs + HCINT(i)); +			hcintmsk = readl(hsotg->regs + HCINTMSK(i)); +			dev_dbg(hsotg->dev, "    hfnum: 0x%08x\n", hfnum); +			dev_dbg(hsotg->dev, "    hcchar: 0x%08x\n", hcchar); +			dev_dbg(hsotg->dev, "    hctsiz: 0x%08x\n", hctsiz); +			dev_dbg(hsotg->dev, "    hcint: 0x%08x\n", hcint); +			dev_dbg(hsotg->dev, "    hcintmsk: 0x%08x\n", hcintmsk); +		} + +		if (!(chan->xfer_started && chan->qh)) +			continue; + +		list_for_each_entry(qtd, &chan->qh->qtd_list, qtd_list_entry) { +			if (!qtd->in_process) +				break; +			urb = qtd->urb; +			dev_dbg(hsotg->dev, "    URB Info:\n"); +			dev_dbg(hsotg->dev, "      qtd: %p, urb: %p\n", +				qtd, urb); +			if (urb) { +				dev_dbg(hsotg->dev, +					"      Dev: %d, EP: %d %s\n", +					dwc2_hcd_get_dev_addr(&urb->pipe_info), +					dwc2_hcd_get_ep_num(&urb->pipe_info), +					dwc2_hcd_is_pipe_in(&urb->pipe_info) ? +					"IN" : "OUT"); +				dev_dbg(hsotg->dev, +					"      Max packet size: %d\n", +					dwc2_hcd_get_mps(&urb->pipe_info)); +				dev_dbg(hsotg->dev, +					"      transfer_buffer: %p\n", +					urb->buf); +				dev_dbg(hsotg->dev, +					"      transfer_dma: %08lx\n", +					(unsigned long)urb->dma); +				dev_dbg(hsotg->dev, +					"      transfer_buffer_length: %d\n", +					urb->length); +				dev_dbg(hsotg->dev, "      actual_length: %d\n", +					urb->actual_length); +			} +		} +	} + +	dev_dbg(hsotg->dev, "  non_periodic_channels: %d\n", +		hsotg->non_periodic_channels); +	dev_dbg(hsotg->dev, "  periodic_channels: %d\n", +		hsotg->periodic_channels); +	dev_dbg(hsotg->dev, "  periodic_usecs: %d\n", hsotg->periodic_usecs); +	np_tx_status = readl(hsotg->regs + GNPTXSTS); +	dev_dbg(hsotg->dev, "  NP Tx Req Queue Space Avail: %d\n", +		(np_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT); +	dev_dbg(hsotg->dev, "  NP Tx FIFO Space Avail: %d\n", +		(np_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT); +	p_tx_status = readl(hsotg->regs + HPTXSTS); +	dev_dbg(hsotg->dev, "  P Tx Req Queue Space Avail: %d\n", +		(p_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT); +	dev_dbg(hsotg->dev, "  P Tx FIFO Space Avail: %d\n", +		(p_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT); +	dwc2_hcd_dump_frrem(hsotg); +	dwc2_dump_global_registers(hsotg); +	dwc2_dump_host_registers(hsotg); +	dev_dbg(hsotg->dev, +		"************************************************************\n"); +	dev_dbg(hsotg->dev, "\n"); +#endif +} + +/* + * NOTE: This function will be removed once the peripheral controller code + * is integrated and the driver is stable + */ +void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg) +{ +#ifdef DWC2_DUMP_FRREM +	dev_dbg(hsotg->dev, "Frame remaining at SOF:\n"); +	dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n", +		hsotg->frrem_samples, hsotg->frrem_accum, +		hsotg->frrem_samples > 0 ? +		hsotg->frrem_accum / hsotg->frrem_samples : 0); +	dev_dbg(hsotg->dev, "\n"); +	dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 7):\n"); +	dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n", +		hsotg->hfnum_7_samples, +		hsotg->hfnum_7_frrem_accum, +		hsotg->hfnum_7_samples > 0 ? +		hsotg->hfnum_7_frrem_accum / hsotg->hfnum_7_samples : 0); +	dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 0):\n"); +	dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n", +		hsotg->hfnum_0_samples, +		hsotg->hfnum_0_frrem_accum, +		hsotg->hfnum_0_samples > 0 ? +		hsotg->hfnum_0_frrem_accum / hsotg->hfnum_0_samples : 0); +	dev_dbg(hsotg->dev, "Frame remaining at start_transfer (uframe 1-6):\n"); +	dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n", +		hsotg->hfnum_other_samples, +		hsotg->hfnum_other_frrem_accum, +		hsotg->hfnum_other_samples > 0 ? +		hsotg->hfnum_other_frrem_accum / hsotg->hfnum_other_samples : +		0); +	dev_dbg(hsotg->dev, "\n"); +	dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 7):\n"); +	dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n", +		hsotg->hfnum_7_samples_a, hsotg->hfnum_7_frrem_accum_a, +		hsotg->hfnum_7_samples_a > 0 ? +		hsotg->hfnum_7_frrem_accum_a / hsotg->hfnum_7_samples_a : 0); +	dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 0):\n"); +	dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n", +		hsotg->hfnum_0_samples_a, hsotg->hfnum_0_frrem_accum_a, +		hsotg->hfnum_0_samples_a > 0 ? +		hsotg->hfnum_0_frrem_accum_a / hsotg->hfnum_0_samples_a : 0); +	dev_dbg(hsotg->dev, "Frame remaining at sample point A (uframe 1-6):\n"); +	dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n", +		hsotg->hfnum_other_samples_a, hsotg->hfnum_other_frrem_accum_a, +		hsotg->hfnum_other_samples_a > 0 ? +		hsotg->hfnum_other_frrem_accum_a / hsotg->hfnum_other_samples_a +		: 0); +	dev_dbg(hsotg->dev, "\n"); +	dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 7):\n"); +	dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n", +		hsotg->hfnum_7_samples_b, hsotg->hfnum_7_frrem_accum_b, +		hsotg->hfnum_7_samples_b > 0 ? +		hsotg->hfnum_7_frrem_accum_b / hsotg->hfnum_7_samples_b : 0); +	dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 0):\n"); +	dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n", +		hsotg->hfnum_0_samples_b, hsotg->hfnum_0_frrem_accum_b, +		(hsotg->hfnum_0_samples_b > 0) ? +		hsotg->hfnum_0_frrem_accum_b / hsotg->hfnum_0_samples_b : 0); +	dev_dbg(hsotg->dev, "Frame remaining at sample point B (uframe 1-6):\n"); +	dev_dbg(hsotg->dev, "  samples %u, accum %llu, avg %llu\n", +		hsotg->hfnum_other_samples_b, hsotg->hfnum_other_frrem_accum_b, +		(hsotg->hfnum_other_samples_b > 0) ? +		hsotg->hfnum_other_frrem_accum_b / hsotg->hfnum_other_samples_b +		: 0); +#endif +} + +struct wrapper_priv_data { +	struct dwc2_hsotg *hsotg; +}; + +/* Gets the dwc2_hsotg from a usb_hcd */ +static struct dwc2_hsotg *dwc2_hcd_to_hsotg(struct usb_hcd *hcd) +{ +	struct wrapper_priv_data *p; + +	p = (struct wrapper_priv_data *) &hcd->hcd_priv; +	return p->hsotg; +} + +static int _dwc2_hcd_start(struct usb_hcd *hcd); + +void dwc2_host_start(struct dwc2_hsotg *hsotg) +{ +	struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg); + +	hcd->self.is_b_host = dwc2_hcd_is_b_host(hsotg); +	_dwc2_hcd_start(hcd); +} + +void dwc2_host_disconnect(struct dwc2_hsotg *hsotg) +{ +	struct usb_hcd *hcd = dwc2_hsotg_to_hcd(hsotg); + +	hcd->self.is_b_host = 0; +} + +void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context, int *hub_addr, +			int *hub_port) +{ +	struct urb *urb = context; + +	if (urb->dev->tt) +		*hub_addr = urb->dev->tt->hub->devnum; +	else +		*hub_addr = 0; +	*hub_port = urb->dev->ttport; +} + +int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context) +{ +	struct urb *urb = context; + +	return urb->dev->speed; +} + +static void dwc2_allocate_bus_bandwidth(struct usb_hcd *hcd, u16 bw, +					struct urb *urb) +{ +	struct usb_bus *bus = hcd_to_bus(hcd); + +	if (urb->interval) +		bus->bandwidth_allocated += bw / urb->interval; +	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) +		bus->bandwidth_isoc_reqs++; +	else +		bus->bandwidth_int_reqs++; +} + +static void dwc2_free_bus_bandwidth(struct usb_hcd *hcd, u16 bw, +				    struct urb *urb) +{ +	struct usb_bus *bus = hcd_to_bus(hcd); + +	if (urb->interval) +		bus->bandwidth_allocated -= bw / urb->interval; +	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) +		bus->bandwidth_isoc_reqs--; +	else +		bus->bandwidth_int_reqs--; +} + +/* + * Sets the final status of an URB and returns it to the upper layer. Any + * required cleanup of the URB is performed. + * + * Must be called with interrupt disabled and spinlock held + */ +void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, +			int status) +{ +	struct urb *urb; +	int i; + +	if (!qtd) { +		dev_dbg(hsotg->dev, "## %s: qtd is NULL ##\n", __func__); +		return; +	} + +	if (!qtd->urb) { +		dev_dbg(hsotg->dev, "## %s: qtd->urb is NULL ##\n", __func__); +		return; +	} + +	urb = qtd->urb->priv; +	if (!urb) { +		dev_dbg(hsotg->dev, "## %s: urb->priv is NULL ##\n", __func__); +		return; +	} + +	urb->actual_length = dwc2_hcd_urb_get_actual_length(qtd->urb); + +	if (dbg_urb(urb)) +		dev_vdbg(hsotg->dev, +			 "%s: urb %p device %d ep %d-%s status %d actual %d\n", +			 __func__, urb, usb_pipedevice(urb->pipe), +			 usb_pipeendpoint(urb->pipe), +			 usb_pipein(urb->pipe) ? "IN" : "OUT", status, +			 urb->actual_length); + +	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS && dbg_perio()) { +		for (i = 0; i < urb->number_of_packets; i++) +			dev_vdbg(hsotg->dev, " ISO Desc %d status %d\n", +				 i, urb->iso_frame_desc[i].status); +	} + +	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { +		urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb); +		for (i = 0; i < urb->number_of_packets; ++i) { +			urb->iso_frame_desc[i].actual_length = +				dwc2_hcd_urb_get_iso_desc_actual_length( +						qtd->urb, i); +			urb->iso_frame_desc[i].status = +				dwc2_hcd_urb_get_iso_desc_status(qtd->urb, i); +		} +	} + +	urb->status = status; +	if (!status) { +		if ((urb->transfer_flags & URB_SHORT_NOT_OK) && +		    urb->actual_length < urb->transfer_buffer_length) +			urb->status = -EREMOTEIO; +	} + +	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS || +	    usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { +		struct usb_host_endpoint *ep = urb->ep; + +		if (ep) +			dwc2_free_bus_bandwidth(dwc2_hsotg_to_hcd(hsotg), +					dwc2_hcd_get_ep_bandwidth(hsotg, ep), +					urb); +	} + +	usb_hcd_unlink_urb_from_ep(dwc2_hsotg_to_hcd(hsotg), urb); +	urb->hcpriv = NULL; +	kfree(qtd->urb); +	qtd->urb = NULL; + +	spin_unlock(&hsotg->lock); +	usb_hcd_giveback_urb(dwc2_hsotg_to_hcd(hsotg), urb, status); +	spin_lock(&hsotg->lock); +} + +/* + * Work queue function for starting the HCD when A-Cable is connected + */ +static void dwc2_hcd_start_func(struct work_struct *work) +{ +	struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg, +						start_work.work); + +	dev_dbg(hsotg->dev, "%s() %p\n", __func__, hsotg); +	dwc2_host_start(hsotg); +} + +/* + * Reset work queue function + */ +static void dwc2_hcd_reset_func(struct work_struct *work) +{ +	struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg, +						reset_work.work); +	u32 hprt0; + +	dev_dbg(hsotg->dev, "USB RESET function called\n"); +	hprt0 = dwc2_read_hprt0(hsotg); +	hprt0 &= ~HPRT0_RST; +	writel(hprt0, hsotg->regs + HPRT0); +	hsotg->flags.b.port_reset_change = 1; +} + +/* + * ========================================================================= + *  Linux HC Driver Functions + * ========================================================================= + */ + +/* + * Initializes the DWC_otg controller and its root hub and prepares it for host + * mode operation. Activates the root port. Returns 0 on success and a negative + * error code on failure. + */ +static int _dwc2_hcd_start(struct usb_hcd *hcd) +{ +	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); +	struct usb_bus *bus = hcd_to_bus(hcd); +	unsigned long flags; + +	dev_dbg(hsotg->dev, "DWC OTG HCD START\n"); + +	spin_lock_irqsave(&hsotg->lock, flags); + +	hcd->state = HC_STATE_RUNNING; + +	if (dwc2_is_device_mode(hsotg)) { +		spin_unlock_irqrestore(&hsotg->lock, flags); +		return 0;	/* why 0 ?? */ +	} + +	dwc2_hcd_reinit(hsotg); + +	/* Initialize and connect root hub if one is not already attached */ +	if (bus->root_hub) { +		dev_dbg(hsotg->dev, "DWC OTG HCD Has Root Hub\n"); +		/* Inform the HUB driver to resume */ +		usb_hcd_resume_root_hub(hcd); +	} + +	spin_unlock_irqrestore(&hsotg->lock, flags); +	return 0; +} + +/* + * Halts the DWC_otg host mode operations in a clean manner. USB transfers are + * stopped. + */ +static void _dwc2_hcd_stop(struct usb_hcd *hcd) +{ +	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); +	unsigned long flags; + +	spin_lock_irqsave(&hsotg->lock, flags); +	dwc2_hcd_stop(hsotg); +	spin_unlock_irqrestore(&hsotg->lock, flags); + +	usleep_range(1000, 3000); +} + +/* Returns the current frame number */ +static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd) +{ +	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + +	return dwc2_hcd_get_frame_number(hsotg); +} + +static void dwc2_dump_urb_info(struct usb_hcd *hcd, struct urb *urb, +			       char *fn_name) +{ +#ifdef VERBOSE_DEBUG +	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); +	char *pipetype; +	char *speed; + +	dev_vdbg(hsotg->dev, "%s, urb %p\n", fn_name, urb); +	dev_vdbg(hsotg->dev, "  Device address: %d\n", +		 usb_pipedevice(urb->pipe)); +	dev_vdbg(hsotg->dev, "  Endpoint: %d, %s\n", +		 usb_pipeendpoint(urb->pipe), +		 usb_pipein(urb->pipe) ? "IN" : "OUT"); + +	switch (usb_pipetype(urb->pipe)) { +	case PIPE_CONTROL: +		pipetype = "CONTROL"; +		break; +	case PIPE_BULK: +		pipetype = "BULK"; +		break; +	case PIPE_INTERRUPT: +		pipetype = "INTERRUPT"; +		break; +	case PIPE_ISOCHRONOUS: +		pipetype = "ISOCHRONOUS"; +		break; +	default: +		pipetype = "UNKNOWN"; +		break; +	} + +	dev_vdbg(hsotg->dev, "  Endpoint type: %s %s (%s)\n", pipetype, +		 usb_urb_dir_in(urb) ? "IN" : "OUT", usb_pipein(urb->pipe) ? +		 "IN" : "OUT"); + +	switch (urb->dev->speed) { +	case USB_SPEED_HIGH: +		speed = "HIGH"; +		break; +	case USB_SPEED_FULL: +		speed = "FULL"; +		break; +	case USB_SPEED_LOW: +		speed = "LOW"; +		break; +	default: +		speed = "UNKNOWN"; +		break; +	} + +	dev_vdbg(hsotg->dev, "  Speed: %s\n", speed); +	dev_vdbg(hsotg->dev, "  Max packet size: %d\n", +		 usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); +	dev_vdbg(hsotg->dev, "  Data buffer length: %d\n", +		 urb->transfer_buffer_length); +	dev_vdbg(hsotg->dev, "  Transfer buffer: %p, Transfer DMA: %08lx\n", +		 urb->transfer_buffer, (unsigned long)urb->transfer_dma); +	dev_vdbg(hsotg->dev, "  Setup buffer: %p, Setup DMA: %08lx\n", +		 urb->setup_packet, (unsigned long)urb->setup_dma); +	dev_vdbg(hsotg->dev, "  Interval: %d\n", urb->interval); + +	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { +		int i; + +		for (i = 0; i < urb->number_of_packets; i++) { +			dev_vdbg(hsotg->dev, "  ISO Desc %d:\n", i); +			dev_vdbg(hsotg->dev, "    offset: %d, length %d\n", +				 urb->iso_frame_desc[i].offset, +				 urb->iso_frame_desc[i].length); +		} +	} +#endif +} + +/* + * Starts processing a USB transfer request specified by a USB Request Block + * (URB). mem_flags indicates the type of memory allocation to use while + * processing this URB. + */ +static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, +				 gfp_t mem_flags) +{ +	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); +	struct usb_host_endpoint *ep = urb->ep; +	struct dwc2_hcd_urb *dwc2_urb; +	int i; +	int retval; +	int alloc_bandwidth = 0; +	u8 ep_type = 0; +	u32 tflags = 0; +	void *buf; +	unsigned long flags; + +	if (dbg_urb(urb)) { +		dev_vdbg(hsotg->dev, "DWC OTG HCD URB Enqueue\n"); +		dwc2_dump_urb_info(hcd, urb, "urb_enqueue"); +	} + +	if (ep == NULL) +		return -EINVAL; + +	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS || +	    usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { +		spin_lock_irqsave(&hsotg->lock, flags); +		if (!dwc2_hcd_is_bandwidth_allocated(hsotg, ep)) +			alloc_bandwidth = 1; +		spin_unlock_irqrestore(&hsotg->lock, flags); +	} + +	switch (usb_pipetype(urb->pipe)) { +	case PIPE_CONTROL: +		ep_type = USB_ENDPOINT_XFER_CONTROL; +		break; +	case PIPE_ISOCHRONOUS: +		ep_type = USB_ENDPOINT_XFER_ISOC; +		break; +	case PIPE_BULK: +		ep_type = USB_ENDPOINT_XFER_BULK; +		break; +	case PIPE_INTERRUPT: +		ep_type = USB_ENDPOINT_XFER_INT; +		break; +	default: +		dev_warn(hsotg->dev, "Wrong ep type\n"); +	} + +	dwc2_urb = dwc2_hcd_urb_alloc(hsotg, urb->number_of_packets, +				      mem_flags); +	if (!dwc2_urb) +		return -ENOMEM; + +	dwc2_hcd_urb_set_pipeinfo(hsotg, dwc2_urb, usb_pipedevice(urb->pipe), +				  usb_pipeendpoint(urb->pipe), ep_type, +				  usb_pipein(urb->pipe), +				  usb_maxpacket(urb->dev, urb->pipe, +						!(usb_pipein(urb->pipe)))); + +	buf = urb->transfer_buffer; + +	if (hcd->self.uses_dma) { +		if (!buf && (urb->transfer_dma & 3)) { +			dev_err(hsotg->dev, +				"%s: unaligned transfer with no transfer_buffer", +				__func__); +			retval = -EINVAL; +			goto fail1; +		} +	} + +	if (!(urb->transfer_flags & URB_NO_INTERRUPT)) +		tflags |= URB_GIVEBACK_ASAP; +	if (urb->transfer_flags & URB_ZERO_PACKET) +		tflags |= URB_SEND_ZERO_PACKET; + +	dwc2_urb->priv = urb; +	dwc2_urb->buf = buf; +	dwc2_urb->dma = urb->transfer_dma; +	dwc2_urb->length = urb->transfer_buffer_length; +	dwc2_urb->setup_packet = urb->setup_packet; +	dwc2_urb->setup_dma = urb->setup_dma; +	dwc2_urb->flags = tflags; +	dwc2_urb->interval = urb->interval; +	dwc2_urb->status = -EINPROGRESS; + +	for (i = 0; i < urb->number_of_packets; ++i) +		dwc2_hcd_urb_set_iso_desc_params(dwc2_urb, i, +						 urb->iso_frame_desc[i].offset, +						 urb->iso_frame_desc[i].length); + +	urb->hcpriv = dwc2_urb; + +	spin_lock_irqsave(&hsotg->lock, flags); +	retval = usb_hcd_link_urb_to_ep(hcd, urb); +	spin_unlock_irqrestore(&hsotg->lock, flags); +	if (retval) +		goto fail1; + +	retval = dwc2_hcd_urb_enqueue(hsotg, dwc2_urb, &ep->hcpriv, mem_flags); +	if (retval) +		goto fail2; + +	if (alloc_bandwidth) { +		spin_lock_irqsave(&hsotg->lock, flags); +		dwc2_allocate_bus_bandwidth(hcd, +				dwc2_hcd_get_ep_bandwidth(hsotg, ep), +				urb); +		spin_unlock_irqrestore(&hsotg->lock, flags); +	} + +	return 0; + +fail2: +	spin_lock_irqsave(&hsotg->lock, flags); +	dwc2_urb->priv = NULL; +	usb_hcd_unlink_urb_from_ep(hcd, urb); +	spin_unlock_irqrestore(&hsotg->lock, flags); +fail1: +	urb->hcpriv = NULL; +	kfree(dwc2_urb); + +	return retval; +} + +/* + * Aborts/cancels a USB transfer request. Always returns 0 to indicate success. + */ +static int _dwc2_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, +				 int status) +{ +	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); +	int rc; +	unsigned long flags; + +	dev_dbg(hsotg->dev, "DWC OTG HCD URB Dequeue\n"); +	dwc2_dump_urb_info(hcd, urb, "urb_dequeue"); + +	spin_lock_irqsave(&hsotg->lock, flags); + +	rc = usb_hcd_check_unlink_urb(hcd, urb, status); +	if (rc) +		goto out; + +	if (!urb->hcpriv) { +		dev_dbg(hsotg->dev, "## urb->hcpriv is NULL ##\n"); +		goto out; +	} + +	rc = dwc2_hcd_urb_dequeue(hsotg, urb->hcpriv); + +	usb_hcd_unlink_urb_from_ep(hcd, urb); + +	kfree(urb->hcpriv); +	urb->hcpriv = NULL; + +	/* Higher layer software sets URB status */ +	spin_unlock(&hsotg->lock); +	usb_hcd_giveback_urb(hcd, urb, status); +	spin_lock(&hsotg->lock); + +	dev_dbg(hsotg->dev, "Called usb_hcd_giveback_urb()\n"); +	dev_dbg(hsotg->dev, "  urb->status = %d\n", urb->status); +out: +	spin_unlock_irqrestore(&hsotg->lock, flags); + +	return rc; +} + +/* + * Frees resources in the DWC_otg controller related to a given endpoint. Also + * clears state in the HCD related to the endpoint. Any URBs for the endpoint + * must already be dequeued. + */ +static void _dwc2_hcd_endpoint_disable(struct usb_hcd *hcd, +				       struct usb_host_endpoint *ep) +{ +	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + +	dev_dbg(hsotg->dev, +		"DWC OTG HCD EP DISABLE: bEndpointAddress=0x%02x, ep->hcpriv=%p\n", +		ep->desc.bEndpointAddress, ep->hcpriv); +	dwc2_hcd_endpoint_disable(hsotg, ep, 250); +} + +/* + * Resets endpoint specific parameter values, in current version used to reset + * the data toggle (as a WA). This function can be called from usb_clear_halt + * routine. + */ +static void _dwc2_hcd_endpoint_reset(struct usb_hcd *hcd, +				     struct usb_host_endpoint *ep) +{ +	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); +	unsigned long flags; + +	dev_dbg(hsotg->dev, +		"DWC OTG HCD EP RESET: bEndpointAddress=0x%02x\n", +		ep->desc.bEndpointAddress); + +	spin_lock_irqsave(&hsotg->lock, flags); +	dwc2_hcd_endpoint_reset(hsotg, ep); +	spin_unlock_irqrestore(&hsotg->lock, flags); +} + +/* + * Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if + * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid + * interrupt. + * + * This function is called by the USB core when an interrupt occurs + */ +static irqreturn_t _dwc2_hcd_irq(struct usb_hcd *hcd) +{ +	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + +	return dwc2_handle_hcd_intr(hsotg); +} + +/* + * Creates Status Change bitmap for the root hub and root port. The bitmap is + * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1 + * is the status change indicator for the single root port. Returns 1 if either + * change indicator is 1, otherwise returns 0. + */ +static int _dwc2_hcd_hub_status_data(struct usb_hcd *hcd, char *buf) +{ +	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + +	buf[0] = dwc2_hcd_is_status_changed(hsotg, 1) << 1; +	return buf[0] != 0; +} + +/* Handles hub class-specific requests */ +static int _dwc2_hcd_hub_control(struct usb_hcd *hcd, u16 typereq, u16 wvalue, +				 u16 windex, char *buf, u16 wlength) +{ +	int retval = dwc2_hcd_hub_control(dwc2_hcd_to_hsotg(hcd), typereq, +					  wvalue, windex, buf, wlength); +	return retval; +} + +/* Handles hub TT buffer clear completions */ +static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, +					       struct usb_host_endpoint *ep) +{ +	struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); +	struct dwc2_qh *qh; +	unsigned long flags; + +	qh = ep->hcpriv; +	if (!qh) +		return; + +	spin_lock_irqsave(&hsotg->lock, flags); +	qh->tt_buffer_dirty = 0; + +	if (hsotg->flags.b.port_connect_status) +		dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_ALL); + +	spin_unlock_irqrestore(&hsotg->lock, flags); +} + +static struct hc_driver dwc2_hc_driver = { +	.description = "dwc2_hsotg", +	.product_desc = "DWC OTG Controller", +	.hcd_priv_size = sizeof(struct wrapper_priv_data), + +	.irq = _dwc2_hcd_irq, +	.flags = HCD_MEMORY | HCD_USB2, + +	.start = _dwc2_hcd_start, +	.stop = _dwc2_hcd_stop, +	.urb_enqueue = _dwc2_hcd_urb_enqueue, +	.urb_dequeue = _dwc2_hcd_urb_dequeue, +	.endpoint_disable = _dwc2_hcd_endpoint_disable, +	.endpoint_reset = _dwc2_hcd_endpoint_reset, +	.get_frame_number = _dwc2_hcd_get_frame_number, + +	.hub_status_data = _dwc2_hcd_hub_status_data, +	.hub_control = _dwc2_hcd_hub_control, +	.clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete, +}; + +/* + * Frees secondary storage associated with the dwc2_hsotg structure contained + * in the struct usb_hcd field + */ +static void dwc2_hcd_free(struct dwc2_hsotg *hsotg) +{ +	u32 ahbcfg; +	u32 dctl; +	int i; + +	dev_dbg(hsotg->dev, "DWC OTG HCD FREE\n"); + +	/* Free memory for QH/QTD lists */ +	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_inactive); +	dwc2_qh_list_free(hsotg, &hsotg->non_periodic_sched_active); +	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_inactive); +	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_ready); +	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_assigned); +	dwc2_qh_list_free(hsotg, &hsotg->periodic_sched_queued); + +	/* Free memory for the host channels */ +	for (i = 0; i < MAX_EPS_CHANNELS; i++) { +		struct dwc2_host_chan *chan = hsotg->hc_ptr_array[i]; + +		if (chan != NULL) { +			dev_dbg(hsotg->dev, "HCD Free channel #%i, chan=%p\n", +				i, chan); +			hsotg->hc_ptr_array[i] = NULL; +			kfree(chan); +		} +	} + +	if (hsotg->core_params->dma_enable > 0) { +		if (hsotg->status_buf) { +			dma_free_coherent(hsotg->dev, DWC2_HCD_STATUS_BUF_SIZE, +					  hsotg->status_buf, +					  hsotg->status_buf_dma); +			hsotg->status_buf = NULL; +		} +	} else { +		kfree(hsotg->status_buf); +		hsotg->status_buf = NULL; +	} + +	ahbcfg = readl(hsotg->regs + GAHBCFG); + +	/* Disable all interrupts */ +	ahbcfg &= ~GAHBCFG_GLBL_INTR_EN; +	writel(ahbcfg, hsotg->regs + GAHBCFG); +	writel(0, hsotg->regs + GINTMSK); + +	if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a) { +		dctl = readl(hsotg->regs + DCTL); +		dctl |= DCTL_SFTDISCON; +		writel(dctl, hsotg->regs + DCTL); +	} + +	if (hsotg->wq_otg) { +		if (!cancel_work_sync(&hsotg->wf_otg)) +			flush_workqueue(hsotg->wq_otg); +		destroy_workqueue(hsotg->wq_otg); +	} + +	kfree(hsotg->core_params); +	hsotg->core_params = NULL; +	del_timer(&hsotg->wkp_timer); +} + +static void dwc2_hcd_release(struct dwc2_hsotg *hsotg) +{ +	/* Turn off all host-specific interrupts */ +	dwc2_disable_host_interrupts(hsotg); + +	dwc2_hcd_free(hsotg); +} + +/* + * Sets all parameters to the given value. + * + * Assumes that the dwc2_core_params struct contains only integers. + */ +void dwc2_set_all_params(struct dwc2_core_params *params, int value) +{ +	int *p = (int *)params; +	size_t size = sizeof(*params) / sizeof(*p); +	int i; + +	for (i = 0; i < size; i++) +		p[i] = value; +} +EXPORT_SYMBOL_GPL(dwc2_set_all_params); + +/* + * Initializes the HCD. This function allocates memory for and initializes the + * static parts of the usb_hcd and dwc2_hsotg structures. It also registers the + * USB bus with the core and calls the hc_driver->start() function. It returns + * a negative error on failure. + */ +int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq, +		  const struct dwc2_core_params *params) +{ +	struct usb_hcd *hcd; +	struct dwc2_host_chan *channel; +	u32 hcfg; +	int i, num_channels; +	int retval; + +	dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n"); + +	/* Detect config values from hardware */ +	retval = dwc2_get_hwparams(hsotg); + +	if (retval) +		return retval; + +	retval = -ENOMEM; + +	hcfg = readl(hsotg->regs + HCFG); +	dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg); + +#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS +	hsotg->frame_num_array = kzalloc(sizeof(*hsotg->frame_num_array) * +					 FRAME_NUM_ARRAY_SIZE, GFP_KERNEL); +	if (!hsotg->frame_num_array) +		goto error1; +	hsotg->last_frame_num_array = kzalloc( +			sizeof(*hsotg->last_frame_num_array) * +			FRAME_NUM_ARRAY_SIZE, GFP_KERNEL); +	if (!hsotg->last_frame_num_array) +		goto error1; +	hsotg->last_frame_num = HFNUM_MAX_FRNUM; +#endif + +	hsotg->core_params = kzalloc(sizeof(*hsotg->core_params), GFP_KERNEL); +	if (!hsotg->core_params) +		goto error1; + +	dwc2_set_all_params(hsotg->core_params, -1); + +	/* Validate parameter values */ +	dwc2_set_parameters(hsotg, params); + +	/* Check if the bus driver or platform code has setup a dma_mask */ +	if (hsotg->core_params->dma_enable > 0 && +	    hsotg->dev->dma_mask == NULL) { +		dev_warn(hsotg->dev, +			 "dma_mask not set, disabling DMA\n"); +		hsotg->core_params->dma_enable = 0; +		hsotg->core_params->dma_desc_enable = 0; +	} + +	/* Set device flags indicating whether the HCD supports DMA */ +	if (hsotg->core_params->dma_enable > 0) { +		if (dma_set_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0) +			dev_warn(hsotg->dev, "can't set DMA mask\n"); +		if (dma_set_coherent_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0) +			dev_warn(hsotg->dev, "can't set coherent DMA mask\n"); +	} + +	hcd = usb_create_hcd(&dwc2_hc_driver, hsotg->dev, dev_name(hsotg->dev)); +	if (!hcd) +		goto error1; + +	if (hsotg->core_params->dma_enable <= 0) +		hcd->self.uses_dma = 0; + +	hcd->has_tt = 1; + +	spin_lock_init(&hsotg->lock); +	((struct wrapper_priv_data *) &hcd->hcd_priv)->hsotg = hsotg; +	hsotg->priv = hcd; + +	/* +	 * Disable the global interrupt until all the interrupt handlers are +	 * installed +	 */ +	dwc2_disable_global_interrupts(hsotg); + +	/* Initialize the DWC_otg core, and select the Phy type */ +	retval = dwc2_core_init(hsotg, true, irq); +	if (retval) +		goto error2; + +	/* Create new workqueue and init work */ +	retval = -ENOMEM; +	hsotg->wq_otg = create_singlethread_workqueue("dwc2"); +	if (!hsotg->wq_otg) { +		dev_err(hsotg->dev, "Failed to create workqueue\n"); +		goto error2; +	} +	INIT_WORK(&hsotg->wf_otg, dwc2_conn_id_status_change); + +	setup_timer(&hsotg->wkp_timer, dwc2_wakeup_detected, +		    (unsigned long)hsotg); + +	/* Initialize the non-periodic schedule */ +	INIT_LIST_HEAD(&hsotg->non_periodic_sched_inactive); +	INIT_LIST_HEAD(&hsotg->non_periodic_sched_active); + +	/* Initialize the periodic schedule */ +	INIT_LIST_HEAD(&hsotg->periodic_sched_inactive); +	INIT_LIST_HEAD(&hsotg->periodic_sched_ready); +	INIT_LIST_HEAD(&hsotg->periodic_sched_assigned); +	INIT_LIST_HEAD(&hsotg->periodic_sched_queued); + +	/* +	 * Create a host channel descriptor for each host channel implemented +	 * in the controller. Initialize the channel descriptor array. +	 */ +	INIT_LIST_HEAD(&hsotg->free_hc_list); +	num_channels = hsotg->core_params->host_channels; +	memset(&hsotg->hc_ptr_array[0], 0, sizeof(hsotg->hc_ptr_array)); + +	for (i = 0; i < num_channels; i++) { +		channel = kzalloc(sizeof(*channel), GFP_KERNEL); +		if (channel == NULL) +			goto error3; +		channel->hc_num = i; +		hsotg->hc_ptr_array[i] = channel; +	} + +	if (hsotg->core_params->uframe_sched > 0) +		dwc2_hcd_init_usecs(hsotg); + +	/* Initialize hsotg start work */ +	INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func); + +	/* Initialize port reset work */ +	INIT_DELAYED_WORK(&hsotg->reset_work, dwc2_hcd_reset_func); + +	/* +	 * Allocate space for storing data on status transactions. Normally no +	 * data is sent, but this space acts as a bit bucket. This must be +	 * done after usb_add_hcd since that function allocates the DMA buffer +	 * pool. +	 */ +	if (hsotg->core_params->dma_enable > 0) +		hsotg->status_buf = dma_alloc_coherent(hsotg->dev, +					DWC2_HCD_STATUS_BUF_SIZE, +					&hsotg->status_buf_dma, GFP_KERNEL); +	else +		hsotg->status_buf = kzalloc(DWC2_HCD_STATUS_BUF_SIZE, +					  GFP_KERNEL); + +	if (!hsotg->status_buf) +		goto error3; + +	hsotg->otg_port = 1; +	hsotg->frame_list = NULL; +	hsotg->frame_list_dma = 0; +	hsotg->periodic_qh_count = 0; + +	/* Initiate lx_state to L3 disconnected state */ +	hsotg->lx_state = DWC2_L3; + +	hcd->self.otg_port = hsotg->otg_port; + +	/* Don't support SG list at this point */ +	hcd->self.sg_tablesize = 0; + +	/* +	 * Finish generic HCD initialization and start the HCD. This function +	 * allocates the DMA buffer pool, registers the USB bus, requests the +	 * IRQ line, and calls hcd_start method. +	 */ +	retval = usb_add_hcd(hcd, irq, IRQF_SHARED); +	if (retval < 0) +		goto error3; + +	device_wakeup_enable(hcd->self.controller); + +	dwc2_hcd_dump_state(hsotg); + +	dwc2_enable_global_interrupts(hsotg); + +	return 0; + +error3: +	dwc2_hcd_release(hsotg); +error2: +	usb_put_hcd(hcd); +error1: +	kfree(hsotg->core_params); + +#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS +	kfree(hsotg->last_frame_num_array); +	kfree(hsotg->frame_num_array); +#endif + +	dev_err(hsotg->dev, "%s() FAILED, returning %d\n", __func__, retval); +	return retval; +} +EXPORT_SYMBOL_GPL(dwc2_hcd_init); + +/* + * Removes the HCD. + * Frees memory and resources associated with the HCD and deregisters the bus. + */ +void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) +{ +	struct usb_hcd *hcd; + +	dev_dbg(hsotg->dev, "DWC OTG HCD REMOVE\n"); + +	hcd = dwc2_hsotg_to_hcd(hsotg); +	dev_dbg(hsotg->dev, "hsotg->hcd = %p\n", hcd); + +	if (!hcd) { +		dev_dbg(hsotg->dev, "%s: dwc2_hsotg_to_hcd(hsotg) NULL!\n", +			__func__); +		return; +	} + +	usb_remove_hcd(hcd); +	hsotg->priv = NULL; +	dwc2_hcd_release(hsotg); +	usb_put_hcd(hcd); + +#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS +	kfree(hsotg->last_frame_num_array); +	kfree(hsotg->frame_num_array); +#endif +} +EXPORT_SYMBOL_GPL(dwc2_hcd_remove); diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h new file mode 100644 index 00000000000..fdc6d489084 --- /dev/null +++ b/drivers/usb/dwc2/hcd.h @@ -0,0 +1,769 @@ +/* + * hcd.h - DesignWare HS OTG Controller host-mode declarations + * + * Copyright (C) 2004-2013 Synopsys, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + *    to endorse or promote products derived from this software without + *    specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef __DWC2_HCD_H__ +#define __DWC2_HCD_H__ + +/* + * This file contains the structures, constants, and interfaces for the + * Host Contoller Driver (HCD) + * + * The Host Controller Driver (HCD) is responsible for translating requests + * from the USB Driver into the appropriate actions on the DWC_otg controller. + * It isolates the USBD from the specifics of the controller by providing an + * API to the USBD. + */ + +struct dwc2_qh; + +/** + * struct dwc2_host_chan - Software host channel descriptor + * + * @hc_num:             Host channel number, used for register address lookup + * @dev_addr:           Address of the device + * @ep_num:             Endpoint of the device + * @ep_is_in:           Endpoint direction + * @speed:              Device speed. One of the following values: + *                       - USB_SPEED_LOW + *                       - USB_SPEED_FULL + *                       - USB_SPEED_HIGH + * @ep_type:            Endpoint type. One of the following values: + *                       - USB_ENDPOINT_XFER_CONTROL: 0 + *                       - USB_ENDPOINT_XFER_ISOC:    1 + *                       - USB_ENDPOINT_XFER_BULK:    2 + *                       - USB_ENDPOINT_XFER_INTR:    3 + * @max_packet:         Max packet size in bytes + * @data_pid_start:     PID for initial transaction. + *                       0: DATA0 + *                       1: DATA2 + *                       2: DATA1 + *                       3: MDATA (non-Control EP), + *                          SETUP (Control EP) + * @multi_count:        Number of additional periodic transactions per + *                      (micro)frame + * @xfer_buf:           Pointer to current transfer buffer position + * @xfer_dma:           DMA address of xfer_buf + * @align_buf:          In Buffer DMA mode this will be used if xfer_buf is not + *                      DWORD aligned + * @xfer_len:           Total number of bytes to transfer + * @xfer_count:         Number of bytes transferred so far + * @start_pkt_count:    Packet count at start of transfer + * @xfer_started:       True if the transfer has been started + * @ping:               True if a PING request should be issued on this channel + * @error_state:        True if the error count for this transaction is non-zero + * @halt_on_queue:      True if this channel should be halted the next time a + *                      request is queued for the channel. This is necessary in + *                      slave mode if no request queue space is available when + *                      an attempt is made to halt the channel. + * @halt_pending:       True if the host channel has been halted, but the core + *                      is not finished flushing queued requests + * @do_split:           Enable split for the channel + * @complete_split:     Enable complete split + * @hub_addr:           Address of high speed hub for the split + * @hub_port:           Port of the low/full speed device for the split + * @xact_pos:           Split transaction position. One of the following values: + *                       - DWC2_HCSPLT_XACTPOS_MID + *                       - DWC2_HCSPLT_XACTPOS_BEGIN + *                       - DWC2_HCSPLT_XACTPOS_END + *                       - DWC2_HCSPLT_XACTPOS_ALL + * @requests:           Number of requests issued for this channel since it was + *                      assigned to the current transfer (not counting PINGs) + * @schinfo:            Scheduling micro-frame bitmap + * @ntd:                Number of transfer descriptors for the transfer + * @halt_status:        Reason for halting the host channel + * @hcint               Contents of the HCINT register when the interrupt came + * @qh:                 QH for the transfer being processed by this channel + * @hc_list_entry:      For linking to list of host channels + * @desc_list_addr:     Current QH's descriptor list DMA address + * + * This structure represents the state of a single host channel when acting in + * host mode. It contains the data items needed to transfer packets to an + * endpoint via a host channel. + */ +struct dwc2_host_chan { +	u8 hc_num; + +	unsigned dev_addr:7; +	unsigned ep_num:4; +	unsigned ep_is_in:1; +	unsigned speed:4; +	unsigned ep_type:2; +	unsigned max_packet:11; +	unsigned data_pid_start:2; +#define DWC2_HC_PID_DATA0	TSIZ_SC_MC_PID_DATA0 +#define DWC2_HC_PID_DATA2	TSIZ_SC_MC_PID_DATA2 +#define DWC2_HC_PID_DATA1	TSIZ_SC_MC_PID_DATA1 +#define DWC2_HC_PID_MDATA	TSIZ_SC_MC_PID_MDATA +#define DWC2_HC_PID_SETUP	TSIZ_SC_MC_PID_SETUP + +	unsigned multi_count:2; + +	u8 *xfer_buf; +	dma_addr_t xfer_dma; +	dma_addr_t align_buf; +	u32 xfer_len; +	u32 xfer_count; +	u16 start_pkt_count; +	u8 xfer_started; +	u8 do_ping; +	u8 error_state; +	u8 halt_on_queue; +	u8 halt_pending; +	u8 do_split; +	u8 complete_split; +	u8 hub_addr; +	u8 hub_port; +	u8 xact_pos; +#define DWC2_HCSPLT_XACTPOS_MID	HCSPLT_XACTPOS_MID +#define DWC2_HCSPLT_XACTPOS_END	HCSPLT_XACTPOS_END +#define DWC2_HCSPLT_XACTPOS_BEGIN HCSPLT_XACTPOS_BEGIN +#define DWC2_HCSPLT_XACTPOS_ALL	HCSPLT_XACTPOS_ALL + +	u8 requests; +	u8 schinfo; +	u16 ntd; +	enum dwc2_halt_status halt_status; +	u32 hcint; +	struct dwc2_qh *qh; +	struct list_head hc_list_entry; +	dma_addr_t desc_list_addr; +}; + +struct dwc2_hcd_pipe_info { +	u8 dev_addr; +	u8 ep_num; +	u8 pipe_type; +	u8 pipe_dir; +	u16 mps; +}; + +struct dwc2_hcd_iso_packet_desc { +	u32 offset; +	u32 length; +	u32 actual_length; +	u32 status; +}; + +struct dwc2_qtd; + +struct dwc2_hcd_urb { +	void *priv; +	struct dwc2_qtd *qtd; +	void *buf; +	dma_addr_t dma; +	void *setup_packet; +	dma_addr_t setup_dma; +	u32 length; +	u32 actual_length; +	u32 status; +	u32 error_count; +	u32 packet_count; +	u32 flags; +	u16 interval; +	struct dwc2_hcd_pipe_info pipe_info; +	struct dwc2_hcd_iso_packet_desc iso_descs[0]; +}; + +/* Phases for control transfers */ +enum dwc2_control_phase { +	DWC2_CONTROL_SETUP, +	DWC2_CONTROL_DATA, +	DWC2_CONTROL_STATUS, +}; + +/* Transaction types */ +enum dwc2_transaction_type { +	DWC2_TRANSACTION_NONE, +	DWC2_TRANSACTION_PERIODIC, +	DWC2_TRANSACTION_NON_PERIODIC, +	DWC2_TRANSACTION_ALL, +}; + +/** + * struct dwc2_qh - Software queue head structure + * + * @ep_type:            Endpoint type. One of the following values: + *                       - USB_ENDPOINT_XFER_CONTROL + *                       - USB_ENDPOINT_XFER_BULK + *                       - USB_ENDPOINT_XFER_INT + *                       - USB_ENDPOINT_XFER_ISOC + * @ep_is_in:           Endpoint direction + * @maxp:               Value from wMaxPacketSize field of Endpoint Descriptor + * @dev_speed:          Device speed. One of the following values: + *                       - USB_SPEED_LOW + *                       - USB_SPEED_FULL + *                       - USB_SPEED_HIGH + * @data_toggle:        Determines the PID of the next data packet for + *                      non-controltransfers. Ignored for control transfers. + *                      One of the following values: + *                       - DWC2_HC_PID_DATA0 + *                       - DWC2_HC_PID_DATA1 + * @ping_state:         Ping state + * @do_split:           Full/low speed endpoint on high-speed hub requires split + * @td_first:           Index of first activated isochronous transfer descriptor + * @td_last:            Index of last activated isochronous transfer descriptor + * @usecs:              Bandwidth in microseconds per (micro)frame + * @interval:           Interval between transfers in (micro)frames + * @sched_frame:        (Micro)frame to initialize a periodic transfer. + *                      The transfer executes in the following (micro)frame. + * @frame_usecs:        Internal variable used by the microframe scheduler + * @start_split_frame:  (Micro)frame at which last start split was initialized + * @ntd:                Actual number of transfer descriptors in a list + * @dw_align_buf:       Used instead of original buffer if its physical address + *                      is not dword-aligned + * @dw_align_buf_dma:   DMA address for align_buf + * @qtd_list:           List of QTDs for this QH + * @channel:            Host channel currently processing transfers for this QH + * @qh_list_entry:      Entry for QH in either the periodic or non-periodic + *                      schedule + * @desc_list:          List of transfer descriptors + * @desc_list_dma:      Physical address of desc_list + * @n_bytes:            Xfer Bytes array. Each element corresponds to a transfer + *                      descriptor and indicates original XferSize value for the + *                      descriptor + * @tt_buffer_dirty     True if clear_tt_buffer_complete is pending + * + * A Queue Head (QH) holds the static characteristics of an endpoint and + * maintains a list of transfers (QTDs) for that endpoint. A QH structure may + * be entered in either the non-periodic or periodic schedule. + */ +struct dwc2_qh { +	u8 ep_type; +	u8 ep_is_in; +	u16 maxp; +	u8 dev_speed; +	u8 data_toggle; +	u8 ping_state; +	u8 do_split; +	u8 td_first; +	u8 td_last; +	u16 usecs; +	u16 interval; +	u16 sched_frame; +	u16 frame_usecs[8]; +	u16 start_split_frame; +	u16 ntd; +	u8 *dw_align_buf; +	dma_addr_t dw_align_buf_dma; +	struct list_head qtd_list; +	struct dwc2_host_chan *channel; +	struct list_head qh_list_entry; +	struct dwc2_hcd_dma_desc *desc_list; +	dma_addr_t desc_list_dma; +	u32 *n_bytes; +	unsigned tt_buffer_dirty:1; +}; + +/** + * struct dwc2_qtd - Software queue transfer descriptor (QTD) + * + * @control_phase:      Current phase for control transfers (Setup, Data, or + *                      Status) + * @in_process:         Indicates if this QTD is currently processed by HW + * @data_toggle:        Determines the PID of the next data packet for the + *                      data phase of control transfers. Ignored for other + *                      transfer types. One of the following values: + *                       - DWC2_HC_PID_DATA0 + *                       - DWC2_HC_PID_DATA1 + * @complete_split:     Keeps track of the current split type for FS/LS + *                      endpoints on a HS Hub + * @isoc_split_pos:     Position of the ISOC split in full/low speed + * @isoc_frame_index:   Index of the next frame descriptor for an isochronous + *                      transfer. A frame descriptor describes the buffer + *                      position and length of the data to be transferred in the + *                      next scheduled (micro)frame of an isochronous transfer. + *                      It also holds status for that transaction. The frame + *                      index starts at 0. + * @isoc_split_offset:  Position of the ISOC split in the buffer for the + *                      current frame + * @ssplit_out_xfer_count: How many bytes transferred during SSPLIT OUT + * @error_count:        Holds the number of bus errors that have occurred for + *                      a transaction within this transfer + * @n_desc:             Number of DMA descriptors for this QTD + * @isoc_frame_index_last: Last activated frame (packet) index, used in + *                      descriptor DMA mode only + * @urb:                URB for this transfer + * @qh:                 Queue head for this QTD + * @qtd_list_entry:     For linking to the QH's list of QTDs + * + * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control, + * interrupt, or isochronous transfer. A single QTD is created for each URB + * (of one of these types) submitted to the HCD. The transfer associated with + * a QTD may require one or multiple transactions. + * + * A QTD is linked to a Queue Head, which is entered in either the + * non-periodic or periodic schedule for execution. When a QTD is chosen for + * execution, some or all of its transactions may be executed. After + * execution, the state of the QTD is updated. The QTD may be retired if all + * its transactions are complete or if an error occurred. Otherwise, it + * remains in the schedule so more transactions can be executed later. + */ +struct dwc2_qtd { +	enum dwc2_control_phase control_phase; +	u8 in_process; +	u8 data_toggle; +	u8 complete_split; +	u8 isoc_split_pos; +	u16 isoc_frame_index; +	u16 isoc_split_offset; +	u32 ssplit_out_xfer_count; +	u8 error_count; +	u8 n_desc; +	u16 isoc_frame_index_last; +	struct dwc2_hcd_urb *urb; +	struct dwc2_qh *qh; +	struct list_head qtd_list_entry; +}; + +#ifdef DEBUG +struct hc_xfer_info { +	struct dwc2_hsotg *hsotg; +	struct dwc2_host_chan *chan; +}; +#endif + +/* Gets the struct usb_hcd that contains a struct dwc2_hsotg */ +static inline struct usb_hcd *dwc2_hsotg_to_hcd(struct dwc2_hsotg *hsotg) +{ +	return (struct usb_hcd *)hsotg->priv; +} + +/* + * Inline used to disable one channel interrupt. Channel interrupts are + * disabled when the channel is halted or released by the interrupt handler. + * There is no need to handle further interrupts of that type until the + * channel is re-assigned. In fact, subsequent handling may cause crashes + * because the channel structures are cleaned up when the channel is released. + */ +static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr) +{ +	u32 mask = readl(hsotg->regs + HCINTMSK(chnum)); + +	mask &= ~intr; +	writel(mask, hsotg->regs + HCINTMSK(chnum)); +} + +/* + * Returns the mode of operation, host or device + */ +static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg) +{ +	return (readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0; +} +static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg) +{ +	return (readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0; +} + +/* + * Reads HPRT0 in preparation to modify. It keeps the WC bits 0 so that if they + * are read as 1, they won't clear when written back. + */ +static inline u32 dwc2_read_hprt0(struct dwc2_hsotg *hsotg) +{ +	u32 hprt0 = readl(hsotg->regs + HPRT0); + +	hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG); +	return hprt0; +} + +static inline u8 dwc2_hcd_get_ep_num(struct dwc2_hcd_pipe_info *pipe) +{ +	return pipe->ep_num; +} + +static inline u8 dwc2_hcd_get_pipe_type(struct dwc2_hcd_pipe_info *pipe) +{ +	return pipe->pipe_type; +} + +static inline u16 dwc2_hcd_get_mps(struct dwc2_hcd_pipe_info *pipe) +{ +	return pipe->mps; +} + +static inline u8 dwc2_hcd_get_dev_addr(struct dwc2_hcd_pipe_info *pipe) +{ +	return pipe->dev_addr; +} + +static inline u8 dwc2_hcd_is_pipe_isoc(struct dwc2_hcd_pipe_info *pipe) +{ +	return pipe->pipe_type == USB_ENDPOINT_XFER_ISOC; +} + +static inline u8 dwc2_hcd_is_pipe_int(struct dwc2_hcd_pipe_info *pipe) +{ +	return pipe->pipe_type == USB_ENDPOINT_XFER_INT; +} + +static inline u8 dwc2_hcd_is_pipe_bulk(struct dwc2_hcd_pipe_info *pipe) +{ +	return pipe->pipe_type == USB_ENDPOINT_XFER_BULK; +} + +static inline u8 dwc2_hcd_is_pipe_control(struct dwc2_hcd_pipe_info *pipe) +{ +	return pipe->pipe_type == USB_ENDPOINT_XFER_CONTROL; +} + +static inline u8 dwc2_hcd_is_pipe_in(struct dwc2_hcd_pipe_info *pipe) +{ +	return pipe->pipe_dir == USB_DIR_IN; +} + +static inline u8 dwc2_hcd_is_pipe_out(struct dwc2_hcd_pipe_info *pipe) +{ +	return !dwc2_hcd_is_pipe_in(pipe); +} + +extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq, +			 const struct dwc2_core_params *params); +extern void dwc2_hcd_remove(struct dwc2_hsotg *hsotg); +extern void dwc2_set_parameters(struct dwc2_hsotg *hsotg, +				const struct dwc2_core_params *params); +extern void dwc2_set_all_params(struct dwc2_core_params *params, int value); +extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg); + +/* Transaction Execution Functions */ +extern enum dwc2_transaction_type dwc2_hcd_select_transactions( +						struct dwc2_hsotg *hsotg); +extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg, +					enum dwc2_transaction_type tr_type); + +/* Schedule Queue Functions */ +/* Implemented in hcd_queue.c */ +extern void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg); +extern void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); +extern int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); +extern void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); +extern void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, +				   int sched_csplit); + +extern void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb); +extern int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, +			    struct dwc2_qh **qh, gfp_t mem_flags); + +/* Unlinks and frees a QTD */ +static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg, +						struct dwc2_qtd *qtd, +						struct dwc2_qh *qh) +{ +	list_del(&qtd->qtd_list_entry); +	kfree(qtd); +} + +/* Descriptor DMA support functions */ +extern void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg, +				     struct dwc2_qh *qh); +extern void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg, +					struct dwc2_host_chan *chan, int chnum, +					enum dwc2_halt_status halt_status); + +extern int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, +				 gfp_t mem_flags); +extern void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); + +/* Check if QH is non-periodic */ +#define dwc2_qh_is_non_per(_qh_ptr_) \ +	((_qh_ptr_)->ep_type == USB_ENDPOINT_XFER_BULK || \ +	 (_qh_ptr_)->ep_type == USB_ENDPOINT_XFER_CONTROL) + +#ifdef CONFIG_USB_DWC2_DEBUG_PERIODIC +static inline bool dbg_hc(struct dwc2_host_chan *hc) { return true; } +static inline bool dbg_qh(struct dwc2_qh *qh) { return true; } +static inline bool dbg_urb(struct urb *urb) { return true; } +static inline bool dbg_perio(void) { return true; } +#else /* !CONFIG_USB_DWC2_DEBUG_PERIODIC */ +static inline bool dbg_hc(struct dwc2_host_chan *hc) +{ +	return hc->ep_type == USB_ENDPOINT_XFER_BULK || +	       hc->ep_type == USB_ENDPOINT_XFER_CONTROL; +} + +static inline bool dbg_qh(struct dwc2_qh *qh) +{ +	return qh->ep_type == USB_ENDPOINT_XFER_BULK || +	       qh->ep_type == USB_ENDPOINT_XFER_CONTROL; +} + +static inline bool dbg_urb(struct urb *urb) +{ +	return usb_pipetype(urb->pipe) == PIPE_BULK || +	       usb_pipetype(urb->pipe) == PIPE_CONTROL; +} + +static inline bool dbg_perio(void) { return false; } +#endif + +/* High bandwidth multiplier as encoded in highspeed endpoint descriptors */ +#define dwc2_hb_mult(wmaxpacketsize) (1 + (((wmaxpacketsize) >> 11) & 0x03)) + +/* Packet size for any kind of endpoint descriptor */ +#define dwc2_max_packet(wmaxpacketsize) ((wmaxpacketsize) & 0x07ff) + +/* + * Returns true if frame1 is less than or equal to frame2. The comparison is + * done modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the + * frame number when the max frame number is reached. + */ +static inline int dwc2_frame_num_le(u16 frame1, u16 frame2) +{ +	return ((frame2 - frame1) & HFNUM_MAX_FRNUM) <= (HFNUM_MAX_FRNUM >> 1); +} + +/* + * Returns true if frame1 is greater than frame2. The comparison is done + * modulo HFNUM_MAX_FRNUM. This accounts for the rollover of the frame + * number when the max frame number is reached. + */ +static inline int dwc2_frame_num_gt(u16 frame1, u16 frame2) +{ +	return (frame1 != frame2) && +	       ((frame1 - frame2) & HFNUM_MAX_FRNUM) < (HFNUM_MAX_FRNUM >> 1); +} + +/* + * Increments frame by the amount specified by inc. The addition is done + * modulo HFNUM_MAX_FRNUM. Returns the incremented value. + */ +static inline u16 dwc2_frame_num_inc(u16 frame, u16 inc) +{ +	return (frame + inc) & HFNUM_MAX_FRNUM; +} + +static inline u16 dwc2_full_frame_num(u16 frame) +{ +	return (frame & HFNUM_MAX_FRNUM) >> 3; +} + +static inline u16 dwc2_micro_frame_num(u16 frame) +{ +	return frame & 0x7; +} + +/* + * Returns the Core Interrupt Status register contents, ANDed with the Core + * Interrupt Mask register contents + */ +static inline u32 dwc2_read_core_intr(struct dwc2_hsotg *hsotg) +{ +	return readl(hsotg->regs + GINTSTS) & readl(hsotg->regs + GINTMSK); +} + +static inline u32 dwc2_hcd_urb_get_status(struct dwc2_hcd_urb *dwc2_urb) +{ +	return dwc2_urb->status; +} + +static inline u32 dwc2_hcd_urb_get_actual_length( +		struct dwc2_hcd_urb *dwc2_urb) +{ +	return dwc2_urb->actual_length; +} + +static inline u32 dwc2_hcd_urb_get_error_count(struct dwc2_hcd_urb *dwc2_urb) +{ +	return dwc2_urb->error_count; +} + +static inline void dwc2_hcd_urb_set_iso_desc_params( +		struct dwc2_hcd_urb *dwc2_urb, int desc_num, u32 offset, +		u32 length) +{ +	dwc2_urb->iso_descs[desc_num].offset = offset; +	dwc2_urb->iso_descs[desc_num].length = length; +} + +static inline u32 dwc2_hcd_urb_get_iso_desc_status( +		struct dwc2_hcd_urb *dwc2_urb, int desc_num) +{ +	return dwc2_urb->iso_descs[desc_num].status; +} + +static inline u32 dwc2_hcd_urb_get_iso_desc_actual_length( +		struct dwc2_hcd_urb *dwc2_urb, int desc_num) +{ +	return dwc2_urb->iso_descs[desc_num].actual_length; +} + +static inline int dwc2_hcd_is_bandwidth_allocated(struct dwc2_hsotg *hsotg, +						  struct usb_host_endpoint *ep) +{ +	struct dwc2_qh *qh = ep->hcpriv; + +	if (qh && !list_empty(&qh->qh_list_entry)) +		return 1; + +	return 0; +} + +static inline u16 dwc2_hcd_get_ep_bandwidth(struct dwc2_hsotg *hsotg, +					    struct usb_host_endpoint *ep) +{ +	struct dwc2_qh *qh = ep->hcpriv; + +	if (!qh) { +		WARN_ON(1); +		return 0; +	} + +	return qh->usecs; +} + +extern void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg, +				      struct dwc2_host_chan *chan, int chnum, +				      struct dwc2_qtd *qtd); + +/* HCD Core API */ + +/** + * dwc2_handle_hcd_intr() - Called on every hardware interrupt + * + * @hsotg: The DWC2 HCD + * + * Returns IRQ_HANDLED if interrupt is handled + * Return IRQ_NONE if interrupt is not handled + */ +extern irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg); + +/** + * dwc2_hcd_stop() - Halts the DWC_otg host mode operation + * + * @hsotg: The DWC2 HCD + */ +extern void dwc2_hcd_stop(struct dwc2_hsotg *hsotg); + +extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg); +extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg); + +/** + * dwc2_hcd_is_b_host() - Returns 1 if core currently is acting as B host, + * and 0 otherwise + * + * @hsotg: The DWC2 HCD + */ +extern int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg); + +/** + * dwc2_hcd_get_frame_number() - Returns current frame number + * + * @hsotg: The DWC2 HCD + */ +extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg); + +/** + * dwc2_hcd_dump_state() - Dumps hsotg state + * + * @hsotg: The DWC2 HCD + * + * NOTE: This function will be removed once the peripheral controller code + * is integrated and the driver is stable + */ +extern void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg); + +/** + * dwc2_hcd_dump_frrem() - Dumps the average frame remaining at SOF + * + * @hsotg: The DWC2 HCD + * + * This can be used to determine average interrupt latency. Frame remaining is + * also shown for start transfer and two additional sample points. + * + * NOTE: This function will be removed once the peripheral controller code + * is integrated and the driver is stable + */ +extern void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg); + +/* URB interface */ + +/* Transfer flags */ +#define URB_GIVEBACK_ASAP	0x1 +#define URB_SEND_ZERO_PACKET	0x2 + +/* Host driver callbacks */ + +extern void dwc2_host_start(struct dwc2_hsotg *hsotg); +extern void dwc2_host_disconnect(struct dwc2_hsotg *hsotg); +extern void dwc2_host_hub_info(struct dwc2_hsotg *hsotg, void *context, +			       int *hub_addr, int *hub_port); +extern int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context); +extern void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, +			       int status); + +#ifdef DEBUG +/* + * Macro to sample the remaining PHY clocks left in the current frame. This + * may be used during debugging to determine the average time it takes to + * execute sections of code. There are two possible sample points, "a" and + * "b", so the _letter_ argument must be one of these values. + * + * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For + * example, "cat /sys/devices/lm0/hcd_frrem". + */ +#define dwc2_sample_frrem(_hcd_, _qh_, _letter_)			\ +do {									\ +	struct hfnum_data _hfnum_;					\ +	struct dwc2_qtd *_qtd_;						\ +									\ +	_qtd_ = list_entry((_qh_)->qtd_list.next, struct dwc2_qtd,	\ +			   qtd_list_entry);				\ +	if (usb_pipeint(_qtd_->urb->pipe) &&				\ +	    (_qh_)->start_split_frame != 0 && !_qtd_->complete_split) {	\ +		_hfnum_.d32 = readl((_hcd_)->regs + HFNUM);		\ +		switch (_hfnum_.b.frnum & 0x7) {			\ +		case 7:							\ +			(_hcd_)->hfnum_7_samples_##_letter_++;		\ +			(_hcd_)->hfnum_7_frrem_accum_##_letter_ +=	\ +				_hfnum_.b.frrem;			\ +			break;						\ +		case 0:							\ +			(_hcd_)->hfnum_0_samples_##_letter_++;		\ +			(_hcd_)->hfnum_0_frrem_accum_##_letter_ +=	\ +				_hfnum_.b.frrem;			\ +			break;						\ +		default:						\ +			(_hcd_)->hfnum_other_samples_##_letter_++;	\ +			(_hcd_)->hfnum_other_frrem_accum_##_letter_ +=	\ +				_hfnum_.b.frrem;			\ +			break;						\ +		}							\ +	}								\ +} while (0) +#else +#define dwc2_sample_frrem(_hcd_, _qh_, _letter_)	do {} while (0) +#endif + +#endif /* __DWC2_HCD_H__ */ diff --git a/drivers/usb/dwc2/hcd_ddma.c b/drivers/usb/dwc2/hcd_ddma.c new file mode 100644 index 00000000000..3376177e4d3 --- /dev/null +++ b/drivers/usb/dwc2/hcd_ddma.c @@ -0,0 +1,1212 @@ +/* + * hcd_ddma.c - DesignWare HS OTG Controller descriptor DMA routines + * + * Copyright (C) 2004-2013 Synopsys, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + *    to endorse or promote products derived from this software without + *    specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file contains the Descriptor DMA implementation for Host mode + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include <linux/usb/hcd.h> +#include <linux/usb/ch11.h> + +#include "core.h" +#include "hcd.h" + +static u16 dwc2_frame_list_idx(u16 frame) +{ +	return frame & (FRLISTEN_64_SIZE - 1); +} + +static u16 dwc2_desclist_idx_inc(u16 idx, u16 inc, u8 speed) +{ +	return (idx + inc) & +		((speed == USB_SPEED_HIGH ? MAX_DMA_DESC_NUM_HS_ISOC : +		  MAX_DMA_DESC_NUM_GENERIC) - 1); +} + +static u16 dwc2_desclist_idx_dec(u16 idx, u16 inc, u8 speed) +{ +	return (idx - inc) & +		((speed == USB_SPEED_HIGH ? MAX_DMA_DESC_NUM_HS_ISOC : +		  MAX_DMA_DESC_NUM_GENERIC) - 1); +} + +static u16 dwc2_max_desc_num(struct dwc2_qh *qh) +{ +	return (qh->ep_type == USB_ENDPOINT_XFER_ISOC && +		qh->dev_speed == USB_SPEED_HIGH) ? +		MAX_DMA_DESC_NUM_HS_ISOC : MAX_DMA_DESC_NUM_GENERIC; +} + +static u16 dwc2_frame_incr_val(struct dwc2_qh *qh) +{ +	return qh->dev_speed == USB_SPEED_HIGH ? +	       (qh->interval + 8 - 1) / 8 : qh->interval; +} + +static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, +				gfp_t flags) +{ +	qh->desc_list = dma_alloc_coherent(hsotg->dev, +				sizeof(struct dwc2_hcd_dma_desc) * +				dwc2_max_desc_num(qh), &qh->desc_list_dma, +				flags); + +	if (!qh->desc_list) +		return -ENOMEM; + +	memset(qh->desc_list, 0, +	       sizeof(struct dwc2_hcd_dma_desc) * dwc2_max_desc_num(qh)); + +	qh->n_bytes = kzalloc(sizeof(u32) * dwc2_max_desc_num(qh), flags); +	if (!qh->n_bytes) { +		dma_free_coherent(hsotg->dev, sizeof(struct dwc2_hcd_dma_desc) +				  * dwc2_max_desc_num(qh), qh->desc_list, +				  qh->desc_list_dma); +		qh->desc_list = NULL; +		return -ENOMEM; +	} + +	return 0; +} + +static void dwc2_desc_list_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ +	if (qh->desc_list) { +		dma_free_coherent(hsotg->dev, sizeof(struct dwc2_hcd_dma_desc) +				  * dwc2_max_desc_num(qh), qh->desc_list, +				  qh->desc_list_dma); +		qh->desc_list = NULL; +	} + +	kfree(qh->n_bytes); +	qh->n_bytes = NULL; +} + +static int dwc2_frame_list_alloc(struct dwc2_hsotg *hsotg, gfp_t mem_flags) +{ +	if (hsotg->frame_list) +		return 0; + +	hsotg->frame_list = dma_alloc_coherent(hsotg->dev, +					       4 * FRLISTEN_64_SIZE, +					       &hsotg->frame_list_dma, +					       mem_flags); +	if (!hsotg->frame_list) +		return -ENOMEM; + +	memset(hsotg->frame_list, 0, 4 * FRLISTEN_64_SIZE); +	return 0; +} + +static void dwc2_frame_list_free(struct dwc2_hsotg *hsotg) +{ +	u32 *frame_list; +	dma_addr_t frame_list_dma; +	unsigned long flags; + +	spin_lock_irqsave(&hsotg->lock, flags); + +	if (!hsotg->frame_list) { +		spin_unlock_irqrestore(&hsotg->lock, flags); +		return; +	} + +	frame_list = hsotg->frame_list; +	frame_list_dma = hsotg->frame_list_dma; +	hsotg->frame_list = NULL; + +	spin_unlock_irqrestore(&hsotg->lock, flags); + +	dma_free_coherent(hsotg->dev, 4 * FRLISTEN_64_SIZE, frame_list, +			  frame_list_dma); +} + +static void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en) +{ +	u32 hcfg; +	unsigned long flags; + +	spin_lock_irqsave(&hsotg->lock, flags); + +	hcfg = readl(hsotg->regs + HCFG); +	if (hcfg & HCFG_PERSCHEDENA) { +		/* already enabled */ +		spin_unlock_irqrestore(&hsotg->lock, flags); +		return; +	} + +	writel(hsotg->frame_list_dma, hsotg->regs + HFLBADDR); + +	hcfg &= ~HCFG_FRLISTEN_MASK; +	hcfg |= fr_list_en | HCFG_PERSCHEDENA; +	dev_vdbg(hsotg->dev, "Enabling Periodic schedule\n"); +	writel(hcfg, hsotg->regs + HCFG); + +	spin_unlock_irqrestore(&hsotg->lock, flags); +} + +static void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg) +{ +	u32 hcfg; +	unsigned long flags; + +	spin_lock_irqsave(&hsotg->lock, flags); + +	hcfg = readl(hsotg->regs + HCFG); +	if (!(hcfg & HCFG_PERSCHEDENA)) { +		/* already disabled */ +		spin_unlock_irqrestore(&hsotg->lock, flags); +		return; +	} + +	hcfg &= ~HCFG_PERSCHEDENA; +	dev_vdbg(hsotg->dev, "Disabling Periodic schedule\n"); +	writel(hcfg, hsotg->regs + HCFG); + +	spin_unlock_irqrestore(&hsotg->lock, flags); +} + +/* + * Activates/Deactivates FrameList entries for the channel based on endpoint + * servicing period + */ +static void dwc2_update_frame_list(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, +				   int enable) +{ +	struct dwc2_host_chan *chan; +	u16 i, j, inc; + +	if (!hsotg) { +		pr_err("hsotg = %p\n", hsotg); +		return; +	} + +	if (!qh->channel) { +		dev_err(hsotg->dev, "qh->channel = %p\n", qh->channel); +		return; +	} + +	if (!hsotg->frame_list) { +		dev_err(hsotg->dev, "hsotg->frame_list = %p\n", +			hsotg->frame_list); +		return; +	} + +	chan = qh->channel; +	inc = dwc2_frame_incr_val(qh); +	if (qh->ep_type == USB_ENDPOINT_XFER_ISOC) +		i = dwc2_frame_list_idx(qh->sched_frame); +	else +		i = 0; + +	j = i; +	do { +		if (enable) +			hsotg->frame_list[j] |= 1 << chan->hc_num; +		else +			hsotg->frame_list[j] &= ~(1 << chan->hc_num); +		j = (j + inc) & (FRLISTEN_64_SIZE - 1); +	} while (j != i); + +	if (!enable) +		return; + +	chan->schinfo = 0; +	if (chan->speed == USB_SPEED_HIGH && qh->interval) { +		j = 1; +		/* TODO - check this */ +		inc = (8 + qh->interval - 1) / qh->interval; +		for (i = 0; i < inc; i++) { +			chan->schinfo |= j; +			j = j << qh->interval; +		} +	} else { +		chan->schinfo = 0xff; +	} +} + +static void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg, +				      struct dwc2_qh *qh) +{ +	struct dwc2_host_chan *chan = qh->channel; + +	if (dwc2_qh_is_non_per(qh)) { +		if (hsotg->core_params->uframe_sched > 0) +			hsotg->available_host_channels++; +		else +			hsotg->non_periodic_channels--; +	} else { +		dwc2_update_frame_list(hsotg, qh, 0); +	} + +	/* +	 * The condition is added to prevent double cleanup try in case of +	 * device disconnect. See channel cleanup in dwc2_hcd_disconnect(). +	 */ +	if (chan->qh) { +		if (!list_empty(&chan->hc_list_entry)) +			list_del(&chan->hc_list_entry); +		dwc2_hc_cleanup(hsotg, chan); +		list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list); +		chan->qh = NULL; +	} + +	qh->channel = NULL; +	qh->ntd = 0; + +	if (qh->desc_list) +		memset(qh->desc_list, 0, sizeof(struct dwc2_hcd_dma_desc) * +		       dwc2_max_desc_num(qh)); +} + +/** + * dwc2_hcd_qh_init_ddma() - Initializes a QH structure's Descriptor DMA + * related members + * + * @hsotg: The HCD state structure for the DWC OTG controller + * @qh:    The QH to init + * + * Return: 0 if successful, negative error code otherwise + * + * Allocates memory for the descriptor list. For the first periodic QH, + * allocates memory for the FrameList and enables periodic scheduling. + */ +int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, +			  gfp_t mem_flags) +{ +	int retval; + +	if (qh->do_split) { +		dev_err(hsotg->dev, +			"SPLIT Transfers are not supported in Descriptor DMA mode.\n"); +		retval = -EINVAL; +		goto err0; +	} + +	retval = dwc2_desc_list_alloc(hsotg, qh, mem_flags); +	if (retval) +		goto err0; + +	if (qh->ep_type == USB_ENDPOINT_XFER_ISOC || +	    qh->ep_type == USB_ENDPOINT_XFER_INT) { +		if (!hsotg->frame_list) { +			retval = dwc2_frame_list_alloc(hsotg, mem_flags); +			if (retval) +				goto err1; +			/* Enable periodic schedule on first periodic QH */ +			dwc2_per_sched_enable(hsotg, HCFG_FRLISTEN_64); +		} +	} + +	qh->ntd = 0; +	return 0; + +err1: +	dwc2_desc_list_free(hsotg, qh); +err0: +	return retval; +} + +/** + * dwc2_hcd_qh_free_ddma() - Frees a QH structure's Descriptor DMA related + * members + * + * @hsotg: The HCD state structure for the DWC OTG controller + * @qh:    The QH to free + * + * Frees descriptor list memory associated with the QH. If QH is periodic and + * the last, frees FrameList memory and disables periodic scheduling. + */ +void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ +	dwc2_desc_list_free(hsotg, qh); + +	/* +	 * Channel still assigned due to some reasons. +	 * Seen on Isoc URB dequeue. Channel halted but no subsequent +	 * ChHalted interrupt to release the channel. Afterwards +	 * when it comes here from endpoint disable routine +	 * channel remains assigned. +	 */ +	if (qh->channel) +		dwc2_release_channel_ddma(hsotg, qh); + +	if ((qh->ep_type == USB_ENDPOINT_XFER_ISOC || +	     qh->ep_type == USB_ENDPOINT_XFER_INT) && +	    (hsotg->core_params->uframe_sched > 0 || +	     !hsotg->periodic_channels) && hsotg->frame_list) { +		dwc2_per_sched_disable(hsotg); +		dwc2_frame_list_free(hsotg); +	} +} + +static u8 dwc2_frame_to_desc_idx(struct dwc2_qh *qh, u16 frame_idx) +{ +	if (qh->dev_speed == USB_SPEED_HIGH) +		/* Descriptor set (8 descriptors) index which is 8-aligned */ +		return (frame_idx & ((MAX_DMA_DESC_NUM_HS_ISOC / 8) - 1)) * 8; +	else +		return frame_idx & (MAX_DMA_DESC_NUM_GENERIC - 1); +} + +/* + * Determine starting frame for Isochronous transfer. + * Few frames skipped to prevent race condition with HC. + */ +static u16 dwc2_calc_starting_frame(struct dwc2_hsotg *hsotg, +				    struct dwc2_qh *qh, u16 *skip_frames) +{ +	u16 frame; + +	hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg); + +	/* sched_frame is always frame number (not uFrame) both in FS and HS! */ + +	/* +	 * skip_frames is used to limit activated descriptors number +	 * to avoid the situation when HC services the last activated +	 * descriptor firstly. +	 * Example for FS: +	 * Current frame is 1, scheduled frame is 3. Since HC always fetches +	 * the descriptor corresponding to curr_frame+1, the descriptor +	 * corresponding to frame 2 will be fetched. If the number of +	 * descriptors is max=64 (or greather) the list will be fully programmed +	 * with Active descriptors and it is possible case (rare) that the +	 * latest descriptor(considering rollback) corresponding to frame 2 will +	 * be serviced first. HS case is more probable because, in fact, up to +	 * 11 uframes (16 in the code) may be skipped. +	 */ +	if (qh->dev_speed == USB_SPEED_HIGH) { +		/* +		 * Consider uframe counter also, to start xfer asap. If half of +		 * the frame elapsed skip 2 frames otherwise just 1 frame. +		 * Starting descriptor index must be 8-aligned, so if the +		 * current frame is near to complete the next one is skipped as +		 * well. +		 */ +		if (dwc2_micro_frame_num(hsotg->frame_number) >= 5) { +			*skip_frames = 2 * 8; +			frame = dwc2_frame_num_inc(hsotg->frame_number, +						   *skip_frames); +		} else { +			*skip_frames = 1 * 8; +			frame = dwc2_frame_num_inc(hsotg->frame_number, +						   *skip_frames); +		} + +		frame = dwc2_full_frame_num(frame); +	} else { +		/* +		 * Two frames are skipped for FS - the current and the next. +		 * But for descriptor programming, 1 frame (descriptor) is +		 * enough, see example above. +		 */ +		*skip_frames = 1; +		frame = dwc2_frame_num_inc(hsotg->frame_number, 2); +	} + +	return frame; +} + +/* + * Calculate initial descriptor index for isochronous transfer based on + * scheduled frame + */ +static u16 dwc2_recalc_initial_desc_idx(struct dwc2_hsotg *hsotg, +					struct dwc2_qh *qh) +{ +	u16 frame, fr_idx, fr_idx_tmp, skip_frames; + +	/* +	 * With current ISOC processing algorithm the channel is being released +	 * when no more QTDs in the list (qh->ntd == 0). Thus this function is +	 * called only when qh->ntd == 0 and qh->channel == 0. +	 * +	 * So qh->channel != NULL branch is not used and just not removed from +	 * the source file. It is required for another possible approach which +	 * is, do not disable and release the channel when ISOC session +	 * completed, just move QH to inactive schedule until new QTD arrives. +	 * On new QTD, the QH moved back to 'ready' schedule, starting frame and +	 * therefore starting desc_index are recalculated. In this case channel +	 * is released only on ep_disable. +	 */ + +	/* +	 * Calculate starting descriptor index. For INTERRUPT endpoint it is +	 * always 0. +	 */ +	if (qh->channel) { +		frame = dwc2_calc_starting_frame(hsotg, qh, &skip_frames); +		/* +		 * Calculate initial descriptor index based on FrameList current +		 * bitmap and servicing period +		 */ +		fr_idx_tmp = dwc2_frame_list_idx(frame); +		fr_idx = (FRLISTEN_64_SIZE + +			  dwc2_frame_list_idx(qh->sched_frame) - fr_idx_tmp) +			 % dwc2_frame_incr_val(qh); +		fr_idx = (fr_idx + fr_idx_tmp) % FRLISTEN_64_SIZE; +	} else { +		qh->sched_frame = dwc2_calc_starting_frame(hsotg, qh, +							   &skip_frames); +		fr_idx = dwc2_frame_list_idx(qh->sched_frame); +	} + +	qh->td_first = qh->td_last = dwc2_frame_to_desc_idx(qh, fr_idx); + +	return skip_frames; +} + +#define ISOC_URB_GIVEBACK_ASAP + +#define MAX_ISOC_XFER_SIZE_FS	1023 +#define MAX_ISOC_XFER_SIZE_HS	3072 +#define DESCNUM_THRESHOLD	4 + +static void dwc2_fill_host_isoc_dma_desc(struct dwc2_hsotg *hsotg, +					 struct dwc2_qtd *qtd, +					 struct dwc2_qh *qh, u32 max_xfer_size, +					 u16 idx) +{ +	struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[idx]; +	struct dwc2_hcd_iso_packet_desc *frame_desc; + +	memset(dma_desc, 0, sizeof(*dma_desc)); +	frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last]; + +	if (frame_desc->length > max_xfer_size) +		qh->n_bytes[idx] = max_xfer_size; +	else +		qh->n_bytes[idx] = frame_desc->length; + +	dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset); +	dma_desc->status = qh->n_bytes[idx] << HOST_DMA_ISOC_NBYTES_SHIFT & +			   HOST_DMA_ISOC_NBYTES_MASK; + +#ifdef ISOC_URB_GIVEBACK_ASAP +	/* Set IOC for each descriptor corresponding to last frame of URB */ +	if (qtd->isoc_frame_index_last == qtd->urb->packet_count) +		dma_desc->status |= HOST_DMA_IOC; +#endif + +	qh->ntd++; +	qtd->isoc_frame_index_last++; +} + +static void dwc2_init_isoc_dma_desc(struct dwc2_hsotg *hsotg, +				    struct dwc2_qh *qh, u16 skip_frames) +{ +	struct dwc2_qtd *qtd; +	u32 max_xfer_size; +	u16 idx, inc, n_desc, ntd_max = 0; + +	idx = qh->td_last; +	inc = qh->interval; +	n_desc = 0; + +	if (qh->interval) { +		ntd_max = (dwc2_max_desc_num(qh) + qh->interval - 1) / +				qh->interval; +		if (skip_frames && !qh->channel) +			ntd_max -= skip_frames / qh->interval; +	} + +	max_xfer_size = qh->dev_speed == USB_SPEED_HIGH ? +			MAX_ISOC_XFER_SIZE_HS : MAX_ISOC_XFER_SIZE_FS; + +	list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) { +		while (qh->ntd < ntd_max && qtd->isoc_frame_index_last < +						qtd->urb->packet_count) { +			if (n_desc > 1) +				qh->desc_list[n_desc - 1].status |= HOST_DMA_A; +			dwc2_fill_host_isoc_dma_desc(hsotg, qtd, qh, +						     max_xfer_size, idx); +			idx = dwc2_desclist_idx_inc(idx, inc, qh->dev_speed); +			n_desc++; +		} +		qtd->in_process = 1; +	} + +	qh->td_last = idx; + +#ifdef ISOC_URB_GIVEBACK_ASAP +	/* Set IOC for last descriptor if descriptor list is full */ +	if (qh->ntd == ntd_max) { +		idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed); +		qh->desc_list[idx].status |= HOST_DMA_IOC; +	} +#else +	/* +	 * Set IOC bit only for one descriptor. Always try to be ahead of HW +	 * processing, i.e. on IOC generation driver activates next descriptor +	 * but core continues to process descriptors following the one with IOC +	 * set. +	 */ + +	if (n_desc > DESCNUM_THRESHOLD) +		/* +		 * Move IOC "up". Required even if there is only one QTD +		 * in the list, because QTDs might continue to be queued, +		 * but during the activation it was only one queued. +		 * Actually more than one QTD might be in the list if this +		 * function called from XferCompletion - QTDs was queued during +		 * HW processing of the previous descriptor chunk. +		 */ +		idx = dwc2_desclist_idx_dec(idx, inc * ((qh->ntd + 1) / 2), +					    qh->dev_speed); +	else +		/* +		 * Set the IOC for the latest descriptor if either number of +		 * descriptors is not greater than threshold or no more new +		 * descriptors activated +		 */ +		idx = dwc2_desclist_idx_dec(qh->td_last, inc, qh->dev_speed); + +	qh->desc_list[idx].status |= HOST_DMA_IOC; +#endif + +	if (n_desc) { +		qh->desc_list[n_desc - 1].status |= HOST_DMA_A; +		if (n_desc > 1) +			qh->desc_list[0].status |= HOST_DMA_A; +	} +} + +static void dwc2_fill_host_dma_desc(struct dwc2_hsotg *hsotg, +				    struct dwc2_host_chan *chan, +				    struct dwc2_qtd *qtd, struct dwc2_qh *qh, +				    int n_desc) +{ +	struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[n_desc]; +	int len = chan->xfer_len; + +	if (len > MAX_DMA_DESC_SIZE - (chan->max_packet - 1)) +		len = MAX_DMA_DESC_SIZE - (chan->max_packet - 1); + +	if (chan->ep_is_in) { +		int num_packets; + +		if (len > 0 && chan->max_packet) +			num_packets = (len + chan->max_packet - 1) +					/ chan->max_packet; +		else +			/* Need 1 packet for transfer length of 0 */ +			num_packets = 1; + +		/* Always program an integral # of packets for IN transfers */ +		len = num_packets * chan->max_packet; +	} + +	dma_desc->status = len << HOST_DMA_NBYTES_SHIFT & HOST_DMA_NBYTES_MASK; +	qh->n_bytes[n_desc] = len; + +	if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL && +	    qtd->control_phase == DWC2_CONTROL_SETUP) +		dma_desc->status |= HOST_DMA_SUP; + +	dma_desc->buf = (u32)chan->xfer_dma; + +	/* +	 * Last (or only) descriptor of IN transfer with actual size less +	 * than MaxPacket +	 */ +	if (len > chan->xfer_len) { +		chan->xfer_len = 0; +	} else { +		chan->xfer_dma += len; +		chan->xfer_len -= len; +	} +} + +static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg, +					struct dwc2_qh *qh) +{ +	struct dwc2_qtd *qtd; +	struct dwc2_host_chan *chan = qh->channel; +	int n_desc = 0; + +	dev_vdbg(hsotg->dev, "%s(): qh=%p dma=%08lx len=%d\n", __func__, qh, +		 (unsigned long)chan->xfer_dma, chan->xfer_len); + +	/* +	 * Start with chan->xfer_dma initialized in assign_and_init_hc(), then +	 * if SG transfer consists of multiple URBs, this pointer is re-assigned +	 * to the buffer of the currently processed QTD. For non-SG request +	 * there is always one QTD active. +	 */ + +	list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) { +		dev_vdbg(hsotg->dev, "qtd=%p\n", qtd); + +		if (n_desc) { +			/* SG request - more than 1 QTD */ +			chan->xfer_dma = qtd->urb->dma + +					qtd->urb->actual_length; +			chan->xfer_len = qtd->urb->length - +					qtd->urb->actual_length; +			dev_vdbg(hsotg->dev, "buf=%08lx len=%d\n", +				 (unsigned long)chan->xfer_dma, chan->xfer_len); +		} + +		qtd->n_desc = 0; +		do { +			if (n_desc > 1) { +				qh->desc_list[n_desc - 1].status |= HOST_DMA_A; +				dev_vdbg(hsotg->dev, +					 "set A bit in desc %d (%p)\n", +					 n_desc - 1, +					 &qh->desc_list[n_desc - 1]); +			} +			dwc2_fill_host_dma_desc(hsotg, chan, qtd, qh, n_desc); +			dev_vdbg(hsotg->dev, +				 "desc %d (%p) buf=%08x status=%08x\n", +				 n_desc, &qh->desc_list[n_desc], +				 qh->desc_list[n_desc].buf, +				 qh->desc_list[n_desc].status); +			qtd->n_desc++; +			n_desc++; +		} while (chan->xfer_len > 0 && +			 n_desc != MAX_DMA_DESC_NUM_GENERIC); + +		dev_vdbg(hsotg->dev, "n_desc=%d\n", n_desc); +		qtd->in_process = 1; +		if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL) +			break; +		if (n_desc == MAX_DMA_DESC_NUM_GENERIC) +			break; +	} + +	if (n_desc) { +		qh->desc_list[n_desc - 1].status |= +				HOST_DMA_IOC | HOST_DMA_EOL | HOST_DMA_A; +		dev_vdbg(hsotg->dev, "set IOC/EOL/A bits in desc %d (%p)\n", +			 n_desc - 1, &qh->desc_list[n_desc - 1]); +		if (n_desc > 1) { +			qh->desc_list[0].status |= HOST_DMA_A; +			dev_vdbg(hsotg->dev, "set A bit in desc 0 (%p)\n", +				 &qh->desc_list[0]); +		} +		chan->ntd = n_desc; +	} +} + +/** + * dwc2_hcd_start_xfer_ddma() - Starts a transfer in Descriptor DMA mode + * + * @hsotg: The HCD state structure for the DWC OTG controller + * @qh:    The QH to init + * + * Return: 0 if successful, negative error code otherwise + * + * For Control and Bulk endpoints, initializes descriptor list and starts the + * transfer. For Interrupt and Isochronous endpoints, initializes descriptor + * list then updates FrameList, marking appropriate entries as active. + * + * For Isochronous endpoints the starting descriptor index is calculated based + * on the scheduled frame, but only on the first transfer descriptor within a + * session. Then the transfer is started via enabling the channel. + * + * For Isochronous endpoints the channel is not halted on XferComplete + * interrupt so remains assigned to the endpoint(QH) until session is done. + */ +void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ +	/* Channel is already assigned */ +	struct dwc2_host_chan *chan = qh->channel; +	u16 skip_frames = 0; + +	switch (chan->ep_type) { +	case USB_ENDPOINT_XFER_CONTROL: +	case USB_ENDPOINT_XFER_BULK: +		dwc2_init_non_isoc_dma_desc(hsotg, qh); +		dwc2_hc_start_transfer_ddma(hsotg, chan); +		break; +	case USB_ENDPOINT_XFER_INT: +		dwc2_init_non_isoc_dma_desc(hsotg, qh); +		dwc2_update_frame_list(hsotg, qh, 1); +		dwc2_hc_start_transfer_ddma(hsotg, chan); +		break; +	case USB_ENDPOINT_XFER_ISOC: +		if (!qh->ntd) +			skip_frames = dwc2_recalc_initial_desc_idx(hsotg, qh); +		dwc2_init_isoc_dma_desc(hsotg, qh, skip_frames); + +		if (!chan->xfer_started) { +			dwc2_update_frame_list(hsotg, qh, 1); + +			/* +			 * Always set to max, instead of actual size. Otherwise +			 * ntd will be changed with channel being enabled. Not +			 * recommended. +			 */ +			chan->ntd = dwc2_max_desc_num(qh); + +			/* Enable channel only once for ISOC */ +			dwc2_hc_start_transfer_ddma(hsotg, chan); +		} + +		break; +	default: +		break; +	} +} + +#define DWC2_CMPL_DONE		1 +#define DWC2_CMPL_STOP		2 + +static int dwc2_cmpl_host_isoc_dma_desc(struct dwc2_hsotg *hsotg, +					struct dwc2_host_chan *chan, +					struct dwc2_qtd *qtd, +					struct dwc2_qh *qh, u16 idx) +{ +	struct dwc2_hcd_dma_desc *dma_desc = &qh->desc_list[idx]; +	struct dwc2_hcd_iso_packet_desc *frame_desc; +	u16 remain = 0; +	int rc = 0; + +	if (!qtd->urb) +		return -EINVAL; + +	frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index_last]; +	dma_desc->buf = (u32)(qtd->urb->dma + frame_desc->offset); +	if (chan->ep_is_in) +		remain = (dma_desc->status & HOST_DMA_ISOC_NBYTES_MASK) >> +			 HOST_DMA_ISOC_NBYTES_SHIFT; + +	if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) { +		/* +		 * XactError, or unable to complete all the transactions +		 * in the scheduled micro-frame/frame, both indicated by +		 * HOST_DMA_STS_PKTERR +		 */ +		qtd->urb->error_count++; +		frame_desc->actual_length = qh->n_bytes[idx] - remain; +		frame_desc->status = -EPROTO; +	} else { +		/* Success */ +		frame_desc->actual_length = qh->n_bytes[idx] - remain; +		frame_desc->status = 0; +	} + +	if (++qtd->isoc_frame_index == qtd->urb->packet_count) { +		/* +		 * urb->status is not used for isoc transfers here. The +		 * individual frame_desc status are used instead. +		 */ +		dwc2_host_complete(hsotg, qtd, 0); +		dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh); + +		/* +		 * This check is necessary because urb_dequeue can be called +		 * from urb complete callback (sound driver for example). All +		 * pending URBs are dequeued there, so no need for further +		 * processing. +		 */ +		if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) +			return -1; +		rc = DWC2_CMPL_DONE; +	} + +	qh->ntd--; + +	/* Stop if IOC requested descriptor reached */ +	if (dma_desc->status & HOST_DMA_IOC) +		rc = DWC2_CMPL_STOP; + +	return rc; +} + +static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg, +					 struct dwc2_host_chan *chan, +					 enum dwc2_halt_status halt_status) +{ +	struct dwc2_hcd_iso_packet_desc *frame_desc; +	struct dwc2_qtd *qtd, *qtd_tmp; +	struct dwc2_qh *qh; +	u16 idx; +	int rc; + +	qh = chan->qh; +	idx = qh->td_first; + +	if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) { +		list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) +			qtd->in_process = 0; +		return; +	} + +	if (halt_status == DWC2_HC_XFER_AHB_ERR || +	    halt_status == DWC2_HC_XFER_BABBLE_ERR) { +		/* +		 * Channel is halted in these error cases, considered as serious +		 * issues. +		 * Complete all URBs marking all frames as failed, irrespective +		 * whether some of the descriptors (frames) succeeded or not. +		 * Pass error code to completion routine as well, to update +		 * urb->status, some of class drivers might use it to stop +		 * queing transfer requests. +		 */ +		int err = halt_status == DWC2_HC_XFER_AHB_ERR ? +			  -EIO : -EOVERFLOW; + +		list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, +					 qtd_list_entry) { +			if (qtd->urb) { +				for (idx = 0; idx < qtd->urb->packet_count; +				     idx++) { +					frame_desc = &qtd->urb->iso_descs[idx]; +					frame_desc->status = err; +				} + +				dwc2_host_complete(hsotg, qtd, err); +			} + +			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh); +		} + +		return; +	} + +	list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) { +		if (!qtd->in_process) +			break; +		do { +			rc = dwc2_cmpl_host_isoc_dma_desc(hsotg, chan, qtd, qh, +							  idx); +			if (rc < 0) +				return; +			idx = dwc2_desclist_idx_inc(idx, qh->interval, +						    chan->speed); +			if (rc == DWC2_CMPL_STOP) +				goto stop_scan; +			if (rc == DWC2_CMPL_DONE) +				break; +		} while (idx != qh->td_first); +	} + +stop_scan: +	qh->td_first = idx; +} + +static int dwc2_update_non_isoc_urb_state_ddma(struct dwc2_hsotg *hsotg, +					struct dwc2_host_chan *chan, +					struct dwc2_qtd *qtd, +					struct dwc2_hcd_dma_desc *dma_desc, +					enum dwc2_halt_status halt_status, +					u32 n_bytes, int *xfer_done) +{ +	struct dwc2_hcd_urb *urb = qtd->urb; +	u16 remain = 0; + +	if (chan->ep_is_in) +		remain = (dma_desc->status & HOST_DMA_NBYTES_MASK) >> +			 HOST_DMA_NBYTES_SHIFT; + +	dev_vdbg(hsotg->dev, "remain=%d dwc2_urb=%p\n", remain, urb); + +	if (halt_status == DWC2_HC_XFER_AHB_ERR) { +		dev_err(hsotg->dev, "EIO\n"); +		urb->status = -EIO; +		return 1; +	} + +	if ((dma_desc->status & HOST_DMA_STS_MASK) == HOST_DMA_STS_PKTERR) { +		switch (halt_status) { +		case DWC2_HC_XFER_STALL: +			dev_vdbg(hsotg->dev, "Stall\n"); +			urb->status = -EPIPE; +			break; +		case DWC2_HC_XFER_BABBLE_ERR: +			dev_err(hsotg->dev, "Babble\n"); +			urb->status = -EOVERFLOW; +			break; +		case DWC2_HC_XFER_XACT_ERR: +			dev_err(hsotg->dev, "XactErr\n"); +			urb->status = -EPROTO; +			break; +		default: +			dev_err(hsotg->dev, +				"%s: Unhandled descriptor error status (%d)\n", +				__func__, halt_status); +			break; +		} +		return 1; +	} + +	if (dma_desc->status & HOST_DMA_A) { +		dev_vdbg(hsotg->dev, +			 "Active descriptor encountered on channel %d\n", +			 chan->hc_num); +		return 0; +	} + +	if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL) { +		if (qtd->control_phase == DWC2_CONTROL_DATA) { +			urb->actual_length += n_bytes - remain; +			if (remain || urb->actual_length >= urb->length) { +				/* +				 * For Control Data stage do not set urb->status +				 * to 0, to prevent URB callback. Set it when +				 * Status phase is done. See below. +				 */ +				*xfer_done = 1; +			} +		} else if (qtd->control_phase == DWC2_CONTROL_STATUS) { +			urb->status = 0; +			*xfer_done = 1; +		} +		/* No handling for SETUP stage */ +	} else { +		/* BULK and INTR */ +		urb->actual_length += n_bytes - remain; +		dev_vdbg(hsotg->dev, "length=%d actual=%d\n", urb->length, +			 urb->actual_length); +		if (remain || urb->actual_length >= urb->length) { +			urb->status = 0; +			*xfer_done = 1; +		} +	} + +	return 0; +} + +static int dwc2_process_non_isoc_desc(struct dwc2_hsotg *hsotg, +				      struct dwc2_host_chan *chan, +				      int chnum, struct dwc2_qtd *qtd, +				      int desc_num, +				      enum dwc2_halt_status halt_status, +				      int *xfer_done) +{ +	struct dwc2_qh *qh = chan->qh; +	struct dwc2_hcd_urb *urb = qtd->urb; +	struct dwc2_hcd_dma_desc *dma_desc; +	u32 n_bytes; +	int failed; + +	dev_vdbg(hsotg->dev, "%s()\n", __func__); + +	if (!urb) +		return -EINVAL; + +	dma_desc = &qh->desc_list[desc_num]; +	n_bytes = qh->n_bytes[desc_num]; +	dev_vdbg(hsotg->dev, +		 "qtd=%p dwc2_urb=%p desc_num=%d desc=%p n_bytes=%d\n", +		 qtd, urb, desc_num, dma_desc, n_bytes); +	failed = dwc2_update_non_isoc_urb_state_ddma(hsotg, chan, qtd, dma_desc, +						     halt_status, n_bytes, +						     xfer_done); +	if (failed || (*xfer_done && urb->status != -EINPROGRESS)) { +		dwc2_host_complete(hsotg, qtd, urb->status); +		dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh); +		dev_vdbg(hsotg->dev, "failed=%1x xfer_done=%1x status=%08x\n", +			 failed, *xfer_done, urb->status); +		return failed; +	} + +	if (qh->ep_type == USB_ENDPOINT_XFER_CONTROL) { +		switch (qtd->control_phase) { +		case DWC2_CONTROL_SETUP: +			if (urb->length > 0) +				qtd->control_phase = DWC2_CONTROL_DATA; +			else +				qtd->control_phase = DWC2_CONTROL_STATUS; +			dev_vdbg(hsotg->dev, +				 "  Control setup transaction done\n"); +			break; +		case DWC2_CONTROL_DATA: +			if (*xfer_done) { +				qtd->control_phase = DWC2_CONTROL_STATUS; +				dev_vdbg(hsotg->dev, +					 "  Control data transfer done\n"); +			} else if (desc_num + 1 == qtd->n_desc) { +				/* +				 * Last descriptor for Control data stage which +				 * is not completed yet +				 */ +				dwc2_hcd_save_data_toggle(hsotg, chan, chnum, +							  qtd); +			} +			break; +		default: +			break; +		} +	} + +	return 0; +} + +static void dwc2_complete_non_isoc_xfer_ddma(struct dwc2_hsotg *hsotg, +					     struct dwc2_host_chan *chan, +					     int chnum, +					     enum dwc2_halt_status halt_status) +{ +	struct list_head *qtd_item, *qtd_tmp; +	struct dwc2_qh *qh = chan->qh; +	struct dwc2_qtd *qtd = NULL; +	int xfer_done; +	int desc_num = 0; + +	if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) { +		list_for_each_entry(qtd, &qh->qtd_list, qtd_list_entry) +			qtd->in_process = 0; +		return; +	} + +	list_for_each_safe(qtd_item, qtd_tmp, &qh->qtd_list) { +		int i; + +		qtd = list_entry(qtd_item, struct dwc2_qtd, qtd_list_entry); +		xfer_done = 0; + +		for (i = 0; i < qtd->n_desc; i++) { +			if (dwc2_process_non_isoc_desc(hsotg, chan, chnum, qtd, +						       desc_num, halt_status, +						       &xfer_done)) { +				qtd = NULL; +				break; +			} +			desc_num++; +		} +	} + +	if (qh->ep_type != USB_ENDPOINT_XFER_CONTROL) { +		/* +		 * Resetting the data toggle for bulk and interrupt endpoints +		 * in case of stall. See handle_hc_stall_intr(). +		 */ +		if (halt_status == DWC2_HC_XFER_STALL) +			qh->data_toggle = DWC2_HC_PID_DATA0; +		else if (qtd) +			dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); +	} + +	if (halt_status == DWC2_HC_XFER_COMPLETE) { +		if (chan->hcint & HCINTMSK_NYET) { +			/* +			 * Got a NYET on the last transaction of the transfer. +			 * It means that the endpoint should be in the PING +			 * state at the beginning of the next transfer. +			 */ +			qh->ping_state = 1; +		} +	} +} + +/** + * dwc2_hcd_complete_xfer_ddma() - Scans the descriptor list, updates URB's + * status and calls completion routine for the URB if it's done. Called from + * interrupt handlers. + * + * @hsotg:       The HCD state structure for the DWC OTG controller + * @chan:        Host channel the transfer is completed on + * @chnum:       Index of Host channel registers + * @halt_status: Reason the channel is being halted or just XferComplete + *               for isochronous transfers + * + * Releases the channel to be used by other transfers. + * In case of Isochronous endpoint the channel is not halted until the end of + * the session, i.e. QTD list is empty. + * If periodic channel released the FrameList is updated accordingly. + * Calls transaction selection routines to activate pending transfers. + */ +void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg, +				 struct dwc2_host_chan *chan, int chnum, +				 enum dwc2_halt_status halt_status) +{ +	struct dwc2_qh *qh = chan->qh; +	int continue_isoc_xfer = 0; +	enum dwc2_transaction_type tr_type; + +	if (chan->ep_type == USB_ENDPOINT_XFER_ISOC) { +		dwc2_complete_isoc_xfer_ddma(hsotg, chan, halt_status); + +		/* Release the channel if halted or session completed */ +		if (halt_status != DWC2_HC_XFER_COMPLETE || +		    list_empty(&qh->qtd_list)) { +			/* Halt the channel if session completed */ +			if (halt_status == DWC2_HC_XFER_COMPLETE) +				dwc2_hc_halt(hsotg, chan, halt_status); +			dwc2_release_channel_ddma(hsotg, qh); +			dwc2_hcd_qh_unlink(hsotg, qh); +		} else { +			/* Keep in assigned schedule to continue transfer */ +			list_move(&qh->qh_list_entry, +				  &hsotg->periodic_sched_assigned); +			continue_isoc_xfer = 1; +		} +		/* +		 * Todo: Consider the case when period exceeds FrameList size. +		 * Frame Rollover interrupt should be used. +		 */ +	} else { +		/* +		 * Scan descriptor list to complete the URB(s), then release +		 * the channel +		 */ +		dwc2_complete_non_isoc_xfer_ddma(hsotg, chan, chnum, +						 halt_status); +		dwc2_release_channel_ddma(hsotg, qh); +		dwc2_hcd_qh_unlink(hsotg, qh); + +		if (!list_empty(&qh->qtd_list)) { +			/* +			 * Add back to inactive non-periodic schedule on normal +			 * completion +			 */ +			dwc2_hcd_qh_add(hsotg, qh); +		} +	} + +	tr_type = dwc2_hcd_select_transactions(hsotg); +	if (tr_type != DWC2_TRANSACTION_NONE || continue_isoc_xfer) { +		if (continue_isoc_xfer) { +			if (tr_type == DWC2_TRANSACTION_NONE) +				tr_type = DWC2_TRANSACTION_PERIODIC; +			else if (tr_type == DWC2_TRANSACTION_NON_PERIODIC) +				tr_type = DWC2_TRANSACTION_ALL; +		} +		dwc2_hcd_queue_transactions(hsotg, tr_type); +	} +} diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c new file mode 100644 index 00000000000..47b9eb5389b --- /dev/null +++ b/drivers/usb/dwc2/hcd_intr.c @@ -0,0 +1,2123 @@ +/* + * hcd_intr.c - DesignWare HS OTG Controller host-mode interrupt handling + * + * Copyright (C) 2004-2013 Synopsys, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + *    to endorse or promote products derived from this software without + *    specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file contains the interrupt handlers for Host mode + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include <linux/usb/hcd.h> +#include <linux/usb/ch11.h> + +#include "core.h" +#include "hcd.h" + +/* This function is for debug only */ +static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg) +{ +#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS +	u16 curr_frame_number = hsotg->frame_number; + +	if (hsotg->frame_num_idx < FRAME_NUM_ARRAY_SIZE) { +		if (((hsotg->last_frame_num + 1) & HFNUM_MAX_FRNUM) != +		    curr_frame_number) { +			hsotg->frame_num_array[hsotg->frame_num_idx] = +					curr_frame_number; +			hsotg->last_frame_num_array[hsotg->frame_num_idx] = +					hsotg->last_frame_num; +			hsotg->frame_num_idx++; +		} +	} else if (!hsotg->dumped_frame_num_array) { +		int i; + +		dev_info(hsotg->dev, "Frame     Last Frame\n"); +		dev_info(hsotg->dev, "-----     ----------\n"); +		for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) { +			dev_info(hsotg->dev, "0x%04x    0x%04x\n", +				 hsotg->frame_num_array[i], +				 hsotg->last_frame_num_array[i]); +		} +		hsotg->dumped_frame_num_array = 1; +	} +	hsotg->last_frame_num = curr_frame_number; +#endif +} + +static void dwc2_hc_handle_tt_clear(struct dwc2_hsotg *hsotg, +				    struct dwc2_host_chan *chan, +				    struct dwc2_qtd *qtd) +{ +	struct urb *usb_urb; + +	if (!chan->qh) +		return; + +	if (chan->qh->dev_speed == USB_SPEED_HIGH) +		return; + +	if (!qtd->urb) +		return; + +	usb_urb = qtd->urb->priv; +	if (!usb_urb || !usb_urb->dev || !usb_urb->dev->tt) +		return; + +	if (qtd->urb->status != -EPIPE && qtd->urb->status != -EREMOTEIO) { +		chan->qh->tt_buffer_dirty = 1; +		if (usb_hub_clear_tt_buffer(usb_urb)) +			/* Clear failed; let's hope things work anyway */ +			chan->qh->tt_buffer_dirty = 0; +	} +} + +/* + * Handles the start-of-frame interrupt in host mode. Non-periodic + * transactions may be queued to the DWC_otg controller for the current + * (micro)frame. Periodic transactions may be queued to the controller + * for the next (micro)frame. + */ +static void dwc2_sof_intr(struct dwc2_hsotg *hsotg) +{ +	struct list_head *qh_entry; +	struct dwc2_qh *qh; +	enum dwc2_transaction_type tr_type; + +#ifdef DEBUG_SOF +	dev_vdbg(hsotg->dev, "--Start of Frame Interrupt--\n"); +#endif + +	hsotg->frame_number = dwc2_hcd_get_frame_number(hsotg); + +	dwc2_track_missed_sofs(hsotg); + +	/* Determine whether any periodic QHs should be executed */ +	qh_entry = hsotg->periodic_sched_inactive.next; +	while (qh_entry != &hsotg->periodic_sched_inactive) { +		qh = list_entry(qh_entry, struct dwc2_qh, qh_list_entry); +		qh_entry = qh_entry->next; +		if (dwc2_frame_num_le(qh->sched_frame, hsotg->frame_number)) +			/* +			 * Move QH to the ready list to be executed next +			 * (micro)frame +			 */ +			list_move(&qh->qh_list_entry, +				  &hsotg->periodic_sched_ready); +	} +	tr_type = dwc2_hcd_select_transactions(hsotg); +	if (tr_type != DWC2_TRANSACTION_NONE) +		dwc2_hcd_queue_transactions(hsotg, tr_type); + +	/* Clear interrupt */ +	writel(GINTSTS_SOF, hsotg->regs + GINTSTS); +} + +/* + * Handles the Rx FIFO Level Interrupt, which indicates that there is + * at least one packet in the Rx FIFO. The packets are moved from the FIFO to + * memory if the DWC_otg controller is operating in Slave mode. + */ +static void dwc2_rx_fifo_level_intr(struct dwc2_hsotg *hsotg) +{ +	u32 grxsts, chnum, bcnt, dpid, pktsts; +	struct dwc2_host_chan *chan; + +	if (dbg_perio()) +		dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n"); + +	grxsts = readl(hsotg->regs + GRXSTSP); +	chnum = (grxsts & GRXSTS_HCHNUM_MASK) >> GRXSTS_HCHNUM_SHIFT; +	chan = hsotg->hc_ptr_array[chnum]; +	if (!chan) { +		dev_err(hsotg->dev, "Unable to get corresponding channel\n"); +		return; +	} + +	bcnt = (grxsts & GRXSTS_BYTECNT_MASK) >> GRXSTS_BYTECNT_SHIFT; +	dpid = (grxsts & GRXSTS_DPID_MASK) >> GRXSTS_DPID_SHIFT; +	pktsts = (grxsts & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT; + +	/* Packet Status */ +	if (dbg_perio()) { +		dev_vdbg(hsotg->dev, "    Ch num = %d\n", chnum); +		dev_vdbg(hsotg->dev, "    Count = %d\n", bcnt); +		dev_vdbg(hsotg->dev, "    DPID = %d, chan.dpid = %d\n", dpid, +			 chan->data_pid_start); +		dev_vdbg(hsotg->dev, "    PStatus = %d\n", pktsts); +	} + +	switch (pktsts) { +	case GRXSTS_PKTSTS_HCHIN: +		/* Read the data into the host buffer */ +		if (bcnt > 0) { +			dwc2_read_packet(hsotg, chan->xfer_buf, bcnt); + +			/* Update the HC fields for the next packet received */ +			chan->xfer_count += bcnt; +			chan->xfer_buf += bcnt; +		} +		break; +	case GRXSTS_PKTSTS_HCHIN_XFER_COMP: +	case GRXSTS_PKTSTS_DATATOGGLEERR: +	case GRXSTS_PKTSTS_HCHHALTED: +		/* Handled in interrupt, just ignore data */ +		break; +	default: +		dev_err(hsotg->dev, +			"RxFIFO Level Interrupt: Unknown status %d\n", pktsts); +		break; +	} +} + +/* + * This interrupt occurs when the non-periodic Tx FIFO is half-empty. More + * data packets may be written to the FIFO for OUT transfers. More requests + * may be written to the non-periodic request queue for IN transfers. This + * interrupt is enabled only in Slave mode. + */ +static void dwc2_np_tx_fifo_empty_intr(struct dwc2_hsotg *hsotg) +{ +	dev_vdbg(hsotg->dev, "--Non-Periodic TxFIFO Empty Interrupt--\n"); +	dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_NON_PERIODIC); +} + +/* + * This interrupt occurs when the periodic Tx FIFO is half-empty. More data + * packets may be written to the FIFO for OUT transfers. More requests may be + * written to the periodic request queue for IN transfers. This interrupt is + * enabled only in Slave mode. + */ +static void dwc2_perio_tx_fifo_empty_intr(struct dwc2_hsotg *hsotg) +{ +	if (dbg_perio()) +		dev_vdbg(hsotg->dev, "--Periodic TxFIFO Empty Interrupt--\n"); +	dwc2_hcd_queue_transactions(hsotg, DWC2_TRANSACTION_PERIODIC); +} + +static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0, +			      u32 *hprt0_modify) +{ +	struct dwc2_core_params *params = hsotg->core_params; +	int do_reset = 0; +	u32 usbcfg; +	u32 prtspd; +	u32 hcfg; +	u32 fslspclksel; +	u32 hfir; + +	dev_vdbg(hsotg->dev, "%s(%p)\n", __func__, hsotg); + +	/* Every time when port enables calculate HFIR.FrInterval */ +	hfir = readl(hsotg->regs + HFIR); +	hfir &= ~HFIR_FRINT_MASK; +	hfir |= dwc2_calc_frame_interval(hsotg) << HFIR_FRINT_SHIFT & +		HFIR_FRINT_MASK; +	writel(hfir, hsotg->regs + HFIR); + +	/* Check if we need to adjust the PHY clock speed for low power */ +	if (!params->host_support_fs_ls_low_power) { +		/* Port has been enabled, set the reset change flag */ +		hsotg->flags.b.port_reset_change = 1; +		return; +	} + +	usbcfg = readl(hsotg->regs + GUSBCFG); +	prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT; + +	if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) { +		/* Low power */ +		if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL)) { +			/* Set PHY low power clock select for FS/LS devices */ +			usbcfg |= GUSBCFG_PHY_LP_CLK_SEL; +			writel(usbcfg, hsotg->regs + GUSBCFG); +			do_reset = 1; +		} + +		hcfg = readl(hsotg->regs + HCFG); +		fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >> +			      HCFG_FSLSPCLKSEL_SHIFT; + +		if (prtspd == HPRT0_SPD_LOW_SPEED && +		    params->host_ls_low_power_phy_clk == +		    DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ) { +			/* 6 MHZ */ +			dev_vdbg(hsotg->dev, +				 "FS_PHY programming HCFG to 6 MHz\n"); +			if (fslspclksel != HCFG_FSLSPCLKSEL_6_MHZ) { +				fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ; +				hcfg &= ~HCFG_FSLSPCLKSEL_MASK; +				hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT; +				writel(hcfg, hsotg->regs + HCFG); +				do_reset = 1; +			} +		} else { +			/* 48 MHZ */ +			dev_vdbg(hsotg->dev, +				 "FS_PHY programming HCFG to 48 MHz\n"); +			if (fslspclksel != HCFG_FSLSPCLKSEL_48_MHZ) { +				fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ; +				hcfg &= ~HCFG_FSLSPCLKSEL_MASK; +				hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT; +				writel(hcfg, hsotg->regs + HCFG); +				do_reset = 1; +			} +		} +	} else { +		/* Not low power */ +		if (usbcfg & GUSBCFG_PHY_LP_CLK_SEL) { +			usbcfg &= ~GUSBCFG_PHY_LP_CLK_SEL; +			writel(usbcfg, hsotg->regs + GUSBCFG); +			do_reset = 1; +		} +	} + +	if (do_reset) { +		*hprt0_modify |= HPRT0_RST; +		queue_delayed_work(hsotg->wq_otg, &hsotg->reset_work, +				   msecs_to_jiffies(60)); +	} else { +		/* Port has been enabled, set the reset change flag */ +		hsotg->flags.b.port_reset_change = 1; +	} +} + +/* + * There are multiple conditions that can cause a port interrupt. This function + * determines which interrupt conditions have occurred and handles them + * appropriately. + */ +static void dwc2_port_intr(struct dwc2_hsotg *hsotg) +{ +	u32 hprt0; +	u32 hprt0_modify; + +	dev_vdbg(hsotg->dev, "--Port Interrupt--\n"); + +	hprt0 = readl(hsotg->regs + HPRT0); +	hprt0_modify = hprt0; + +	/* +	 * Clear appropriate bits in HPRT0 to clear the interrupt bit in +	 * GINTSTS +	 */ +	hprt0_modify &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | +			  HPRT0_OVRCURRCHG); + +	/* +	 * Port Connect Detected +	 * Set flag and clear if detected +	 */ +	if (hprt0 & HPRT0_CONNDET) { +		dev_vdbg(hsotg->dev, +			 "--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n", +			 hprt0); +		hsotg->flags.b.port_connect_status_change = 1; +		hsotg->flags.b.port_connect_status = 1; +		hprt0_modify |= HPRT0_CONNDET; + +		/* +		 * The Hub driver asserts a reset when it sees port connect +		 * status change flag +		 */ +	} + +	/* +	 * Port Enable Changed +	 * Clear if detected - Set internal flag if disabled +	 */ +	if (hprt0 & HPRT0_ENACHG) { +		dev_vdbg(hsotg->dev, +			 "  --Port Interrupt HPRT0=0x%08x Port Enable Changed (now %d)--\n", +			 hprt0, !!(hprt0 & HPRT0_ENA)); +		hprt0_modify |= HPRT0_ENACHG; +		if (hprt0 & HPRT0_ENA) +			dwc2_hprt0_enable(hsotg, hprt0, &hprt0_modify); +		else +			hsotg->flags.b.port_enable_change = 1; +	} + +	/* Overcurrent Change Interrupt */ +	if (hprt0 & HPRT0_OVRCURRCHG) { +		dev_vdbg(hsotg->dev, +			 "  --Port Interrupt HPRT0=0x%08x Port Overcurrent Changed--\n", +			 hprt0); +		hsotg->flags.b.port_over_current_change = 1; +		hprt0_modify |= HPRT0_OVRCURRCHG; +	} + +	/* Clear Port Interrupts */ +	writel(hprt0_modify, hsotg->regs + HPRT0); +} + +/* + * Gets the actual length of a transfer after the transfer halts. halt_status + * holds the reason for the halt. + * + * For IN transfers where halt_status is DWC2_HC_XFER_COMPLETE, *short_read + * is set to 1 upon return if less than the requested number of bytes were + * transferred. short_read may also be NULL on entry, in which case it remains + * unchanged. + */ +static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg, +				       struct dwc2_host_chan *chan, int chnum, +				       struct dwc2_qtd *qtd, +				       enum dwc2_halt_status halt_status, +				       int *short_read) +{ +	u32 hctsiz, count, length; + +	hctsiz = readl(hsotg->regs + HCTSIZ(chnum)); + +	if (halt_status == DWC2_HC_XFER_COMPLETE) { +		if (chan->ep_is_in) { +			count = (hctsiz & TSIZ_XFERSIZE_MASK) >> +				TSIZ_XFERSIZE_SHIFT; +			length = chan->xfer_len - count; +			if (short_read != NULL) +				*short_read = (count != 0); +		} else if (chan->qh->do_split) { +			length = qtd->ssplit_out_xfer_count; +		} else { +			length = chan->xfer_len; +		} +	} else { +		/* +		 * Must use the hctsiz.pktcnt field to determine how much data +		 * has been transferred. This field reflects the number of +		 * packets that have been transferred via the USB. This is +		 * always an integral number of packets if the transfer was +		 * halted before its normal completion. (Can't use the +		 * hctsiz.xfersize field because that reflects the number of +		 * bytes transferred via the AHB, not the USB). +		 */ +		count = (hctsiz & TSIZ_PKTCNT_MASK) >> TSIZ_PKTCNT_SHIFT; +		length = (chan->start_pkt_count - count) * chan->max_packet; +	} + +	return length; +} + +/** + * dwc2_update_urb_state() - Updates the state of the URB after a Transfer + * Complete interrupt on the host channel. Updates the actual_length field + * of the URB based on the number of bytes transferred via the host channel. + * Sets the URB status if the data transfer is finished. + * + * Return: 1 if the data transfer specified by the URB is completely finished, + * 0 otherwise + */ +static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg, +				 struct dwc2_host_chan *chan, int chnum, +				 struct dwc2_hcd_urb *urb, +				 struct dwc2_qtd *qtd) +{ +	u32 hctsiz; +	int xfer_done = 0; +	int short_read = 0; +	int xfer_length = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd, +						      DWC2_HC_XFER_COMPLETE, +						      &short_read); + +	if (urb->actual_length + xfer_length > urb->length) { +		dev_warn(hsotg->dev, "%s(): trimming xfer length\n", __func__); +		xfer_length = urb->length - urb->actual_length; +	} + +	/* Non DWORD-aligned buffer case handling */ +	if (chan->align_buf && xfer_length && chan->ep_is_in) { +		dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__); +		dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length, +					DMA_FROM_DEVICE); +		memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf, +		       xfer_length); +		dma_sync_single_for_device(hsotg->dev, urb->dma, urb->length, +					   DMA_FROM_DEVICE); +	} + +	dev_vdbg(hsotg->dev, "urb->actual_length=%d xfer_length=%d\n", +		 urb->actual_length, xfer_length); +	urb->actual_length += xfer_length; + +	if (xfer_length && chan->ep_type == USB_ENDPOINT_XFER_BULK && +	    (urb->flags & URB_SEND_ZERO_PACKET) && +	    urb->actual_length >= urb->length && +	    !(urb->length % chan->max_packet)) { +		xfer_done = 0; +	} else if (short_read || urb->actual_length >= urb->length) { +		xfer_done = 1; +		urb->status = 0; +	} + +	hctsiz = readl(hsotg->regs + HCTSIZ(chnum)); +	dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n", +		 __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum); +	dev_vdbg(hsotg->dev, "  chan->xfer_len %d\n", chan->xfer_len); +	dev_vdbg(hsotg->dev, "  hctsiz.xfersize %d\n", +		 (hctsiz & TSIZ_XFERSIZE_MASK) >> TSIZ_XFERSIZE_SHIFT); +	dev_vdbg(hsotg->dev, "  urb->transfer_buffer_length %d\n", urb->length); +	dev_vdbg(hsotg->dev, "  urb->actual_length %d\n", urb->actual_length); +	dev_vdbg(hsotg->dev, "  short_read %d, xfer_done %d\n", short_read, +		 xfer_done); + +	return xfer_done; +} + +/* + * Save the starting data toggle for the next transfer. The data toggle is + * saved in the QH for non-control transfers and it's saved in the QTD for + * control transfers. + */ +void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg, +			       struct dwc2_host_chan *chan, int chnum, +			       struct dwc2_qtd *qtd) +{ +	u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum)); +	u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT; + +	if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) { +		if (pid == TSIZ_SC_MC_PID_DATA0) +			chan->qh->data_toggle = DWC2_HC_PID_DATA0; +		else +			chan->qh->data_toggle = DWC2_HC_PID_DATA1; +	} else { +		if (pid == TSIZ_SC_MC_PID_DATA0) +			qtd->data_toggle = DWC2_HC_PID_DATA0; +		else +			qtd->data_toggle = DWC2_HC_PID_DATA1; +	} +} + +/** + * dwc2_update_isoc_urb_state() - Updates the state of an Isochronous URB when + * the transfer is stopped for any reason. The fields of the current entry in + * the frame descriptor array are set based on the transfer state and the input + * halt_status. Completes the Isochronous URB if all the URB frames have been + * completed. + * + * Return: DWC2_HC_XFER_COMPLETE if there are more frames remaining to be + * transferred in the URB. Otherwise return DWC2_HC_XFER_URB_COMPLETE. + */ +static enum dwc2_halt_status dwc2_update_isoc_urb_state( +		struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan, +		int chnum, struct dwc2_qtd *qtd, +		enum dwc2_halt_status halt_status) +{ +	struct dwc2_hcd_iso_packet_desc *frame_desc; +	struct dwc2_hcd_urb *urb = qtd->urb; + +	if (!urb) +		return DWC2_HC_XFER_NO_HALT_STATUS; + +	frame_desc = &urb->iso_descs[qtd->isoc_frame_index]; + +	switch (halt_status) { +	case DWC2_HC_XFER_COMPLETE: +		frame_desc->status = 0; +		frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg, +					chan, chnum, qtd, halt_status, NULL); + +		/* Non DWORD-aligned buffer case handling */ +		if (chan->align_buf && frame_desc->actual_length && +		    chan->ep_is_in) { +			dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", +				 __func__); +			dma_sync_single_for_cpu(hsotg->dev, urb->dma, +						urb->length, DMA_FROM_DEVICE); +			memcpy(urb->buf + frame_desc->offset + +			       qtd->isoc_split_offset, chan->qh->dw_align_buf, +			       frame_desc->actual_length); +			dma_sync_single_for_device(hsotg->dev, urb->dma, +						   urb->length, +						   DMA_FROM_DEVICE); +		} +		break; +	case DWC2_HC_XFER_FRAME_OVERRUN: +		urb->error_count++; +		if (chan->ep_is_in) +			frame_desc->status = -ENOSR; +		else +			frame_desc->status = -ECOMM; +		frame_desc->actual_length = 0; +		break; +	case DWC2_HC_XFER_BABBLE_ERR: +		urb->error_count++; +		frame_desc->status = -EOVERFLOW; +		/* Don't need to update actual_length in this case */ +		break; +	case DWC2_HC_XFER_XACT_ERR: +		urb->error_count++; +		frame_desc->status = -EPROTO; +		frame_desc->actual_length = dwc2_get_actual_xfer_length(hsotg, +					chan, chnum, qtd, halt_status, NULL); + +		/* Non DWORD-aligned buffer case handling */ +		if (chan->align_buf && frame_desc->actual_length && +		    chan->ep_is_in) { +			dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", +				 __func__); +			dma_sync_single_for_cpu(hsotg->dev, urb->dma, +						urb->length, DMA_FROM_DEVICE); +			memcpy(urb->buf + frame_desc->offset + +			       qtd->isoc_split_offset, chan->qh->dw_align_buf, +			       frame_desc->actual_length); +			dma_sync_single_for_device(hsotg->dev, urb->dma, +						   urb->length, +						   DMA_FROM_DEVICE); +		} + +		/* Skip whole frame */ +		if (chan->qh->do_split && +		    chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in && +		    hsotg->core_params->dma_enable > 0) { +			qtd->complete_split = 0; +			qtd->isoc_split_offset = 0; +		} + +		break; +	default: +		dev_err(hsotg->dev, "Unhandled halt_status (%d)\n", +			halt_status); +		break; +	} + +	if (++qtd->isoc_frame_index == urb->packet_count) { +		/* +		 * urb->status is not used for isoc transfers. The individual +		 * frame_desc statuses are used instead. +		 */ +		dwc2_host_complete(hsotg, qtd, 0); +		halt_status = DWC2_HC_XFER_URB_COMPLETE; +	} else { +		halt_status = DWC2_HC_XFER_COMPLETE; +	} + +	return halt_status; +} + +/* + * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic + * QHs, removes the QH from the active non-periodic schedule. If any QTDs are + * still linked to the QH, the QH is added to the end of the inactive + * non-periodic schedule. For periodic QHs, removes the QH from the periodic + * schedule if no more QTDs are linked to the QH. + */ +static void dwc2_deactivate_qh(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, +			       int free_qtd) +{ +	int continue_split = 0; +	struct dwc2_qtd *qtd; + +	if (dbg_qh(qh)) +		dev_vdbg(hsotg->dev, "  %s(%p,%p,%d)\n", __func__, +			 hsotg, qh, free_qtd); + +	if (list_empty(&qh->qtd_list)) { +		dev_dbg(hsotg->dev, "## QTD list empty ##\n"); +		goto no_qtd; +	} + +	qtd = list_first_entry(&qh->qtd_list, struct dwc2_qtd, qtd_list_entry); + +	if (qtd->complete_split) +		continue_split = 1; +	else if (qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_MID || +		 qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_END) +		continue_split = 1; + +	if (free_qtd) { +		dwc2_hcd_qtd_unlink_and_free(hsotg, qtd, qh); +		continue_split = 0; +	} + +no_qtd: +	if (qh->channel) +		qh->channel->align_buf = 0; +	qh->channel = NULL; +	dwc2_hcd_qh_deactivate(hsotg, qh, continue_split); +} + +/** + * dwc2_release_channel() - Releases a host channel for use by other transfers + * + * @hsotg:       The HCD state structure + * @chan:        The host channel to release + * @qtd:         The QTD associated with the host channel. This QTD may be + *               freed if the transfer is complete or an error has occurred. + * @halt_status: Reason the channel is being released. This status + *               determines the actions taken by this function. + * + * Also attempts to select and queue more transactions since at least one host + * channel is available. + */ +static void dwc2_release_channel(struct dwc2_hsotg *hsotg, +				 struct dwc2_host_chan *chan, +				 struct dwc2_qtd *qtd, +				 enum dwc2_halt_status halt_status) +{ +	enum dwc2_transaction_type tr_type; +	u32 haintmsk; +	int free_qtd = 0; + +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "  %s: channel %d, halt_status %d\n", +			 __func__, chan->hc_num, halt_status); + +	switch (halt_status) { +	case DWC2_HC_XFER_URB_COMPLETE: +		free_qtd = 1; +		break; +	case DWC2_HC_XFER_AHB_ERR: +	case DWC2_HC_XFER_STALL: +	case DWC2_HC_XFER_BABBLE_ERR: +		free_qtd = 1; +		break; +	case DWC2_HC_XFER_XACT_ERR: +		if (qtd && qtd->error_count >= 3) { +			dev_vdbg(hsotg->dev, +				 "  Complete URB with transaction error\n"); +			free_qtd = 1; +			dwc2_host_complete(hsotg, qtd, -EPROTO); +		} +		break; +	case DWC2_HC_XFER_URB_DEQUEUE: +		/* +		 * The QTD has already been removed and the QH has been +		 * deactivated. Don't want to do anything except release the +		 * host channel and try to queue more transfers. +		 */ +		goto cleanup; +	case DWC2_HC_XFER_PERIODIC_INCOMPLETE: +		dev_vdbg(hsotg->dev, "  Complete URB with I/O error\n"); +		free_qtd = 1; +		dwc2_host_complete(hsotg, qtd, -EIO); +		break; +	case DWC2_HC_XFER_NO_HALT_STATUS: +	default: +		break; +	} + +	dwc2_deactivate_qh(hsotg, chan->qh, free_qtd); + +cleanup: +	/* +	 * Release the host channel for use by other transfers. The cleanup +	 * function clears the channel interrupt enables and conditions, so +	 * there's no need to clear the Channel Halted interrupt separately. +	 */ +	if (!list_empty(&chan->hc_list_entry)) +		list_del(&chan->hc_list_entry); +	dwc2_hc_cleanup(hsotg, chan); +	list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list); + +	if (hsotg->core_params->uframe_sched > 0) { +		hsotg->available_host_channels++; +	} else { +		switch (chan->ep_type) { +		case USB_ENDPOINT_XFER_CONTROL: +		case USB_ENDPOINT_XFER_BULK: +			hsotg->non_periodic_channels--; +			break; +		default: +			/* +			 * Don't release reservations for periodic channels +			 * here. That's done when a periodic transfer is +			 * descheduled (i.e. when the QH is removed from the +			 * periodic schedule). +			 */ +			break; +		} +	} + +	haintmsk = readl(hsotg->regs + HAINTMSK); +	haintmsk &= ~(1 << chan->hc_num); +	writel(haintmsk, hsotg->regs + HAINTMSK); + +	/* Try to queue more transfers now that there's a free channel */ +	tr_type = dwc2_hcd_select_transactions(hsotg); +	if (tr_type != DWC2_TRANSACTION_NONE) +		dwc2_hcd_queue_transactions(hsotg, tr_type); +} + +/* + * Halts a host channel. If the channel cannot be halted immediately because + * the request queue is full, this function ensures that the FIFO empty + * interrupt for the appropriate queue is enabled so that the halt request can + * be queued when there is space in the request queue. + * + * This function may also be called in DMA mode. In that case, the channel is + * simply released since the core always halts the channel automatically in + * DMA mode. + */ +static void dwc2_halt_channel(struct dwc2_hsotg *hsotg, +			      struct dwc2_host_chan *chan, struct dwc2_qtd *qtd, +			      enum dwc2_halt_status halt_status) +{ +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "%s()\n", __func__); + +	if (hsotg->core_params->dma_enable > 0) { +		if (dbg_hc(chan)) +			dev_vdbg(hsotg->dev, "DMA enabled\n"); +		dwc2_release_channel(hsotg, chan, qtd, halt_status); +		return; +	} + +	/* Slave mode processing */ +	dwc2_hc_halt(hsotg, chan, halt_status); + +	if (chan->halt_on_queue) { +		u32 gintmsk; + +		dev_vdbg(hsotg->dev, "Halt on queue\n"); +		if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL || +		    chan->ep_type == USB_ENDPOINT_XFER_BULK) { +			dev_vdbg(hsotg->dev, "control/bulk\n"); +			/* +			 * Make sure the Non-periodic Tx FIFO empty interrupt +			 * is enabled so that the non-periodic schedule will +			 * be processed +			 */ +			gintmsk = readl(hsotg->regs + GINTMSK); +			gintmsk |= GINTSTS_NPTXFEMP; +			writel(gintmsk, hsotg->regs + GINTMSK); +		} else { +			dev_vdbg(hsotg->dev, "isoc/intr\n"); +			/* +			 * Move the QH from the periodic queued schedule to +			 * the periodic assigned schedule. This allows the +			 * halt to be queued when the periodic schedule is +			 * processed. +			 */ +			list_move(&chan->qh->qh_list_entry, +				  &hsotg->periodic_sched_assigned); + +			/* +			 * Make sure the Periodic Tx FIFO Empty interrupt is +			 * enabled so that the periodic schedule will be +			 * processed +			 */ +			gintmsk = readl(hsotg->regs + GINTMSK); +			gintmsk |= GINTSTS_PTXFEMP; +			writel(gintmsk, hsotg->regs + GINTMSK); +		} +	} +} + +/* + * Performs common cleanup for non-periodic transfers after a Transfer + * Complete interrupt. This function should be called after any endpoint type + * specific handling is finished to release the host channel. + */ +static void dwc2_complete_non_periodic_xfer(struct dwc2_hsotg *hsotg, +					    struct dwc2_host_chan *chan, +					    int chnum, struct dwc2_qtd *qtd, +					    enum dwc2_halt_status halt_status) +{ +	dev_vdbg(hsotg->dev, "%s()\n", __func__); + +	qtd->error_count = 0; + +	if (chan->hcint & HCINTMSK_NYET) { +		/* +		 * Got a NYET on the last transaction of the transfer. This +		 * means that the endpoint should be in the PING state at the +		 * beginning of the next transfer. +		 */ +		dev_vdbg(hsotg->dev, "got NYET\n"); +		chan->qh->ping_state = 1; +	} + +	/* +	 * Always halt and release the host channel to make it available for +	 * more transfers. There may still be more phases for a control +	 * transfer or more data packets for a bulk transfer at this point, +	 * but the host channel is still halted. A channel will be reassigned +	 * to the transfer when the non-periodic schedule is processed after +	 * the channel is released. This allows transactions to be queued +	 * properly via dwc2_hcd_queue_transactions, which also enables the +	 * Tx FIFO Empty interrupt if necessary. +	 */ +	if (chan->ep_is_in) { +		/* +		 * IN transfers in Slave mode require an explicit disable to +		 * halt the channel. (In DMA mode, this call simply releases +		 * the channel.) +		 */ +		dwc2_halt_channel(hsotg, chan, qtd, halt_status); +	} else { +		/* +		 * The channel is automatically disabled by the core for OUT +		 * transfers in Slave mode +		 */ +		dwc2_release_channel(hsotg, chan, qtd, halt_status); +	} +} + +/* + * Performs common cleanup for periodic transfers after a Transfer Complete + * interrupt. This function should be called after any endpoint type specific + * handling is finished to release the host channel. + */ +static void dwc2_complete_periodic_xfer(struct dwc2_hsotg *hsotg, +					struct dwc2_host_chan *chan, int chnum, +					struct dwc2_qtd *qtd, +					enum dwc2_halt_status halt_status) +{ +	u32 hctsiz = readl(hsotg->regs + HCTSIZ(chnum)); + +	qtd->error_count = 0; + +	if (!chan->ep_is_in || (hctsiz & TSIZ_PKTCNT_MASK) == 0) +		/* Core halts channel in these cases */ +		dwc2_release_channel(hsotg, chan, qtd, halt_status); +	else +		/* Flush any outstanding requests from the Tx queue */ +		dwc2_halt_channel(hsotg, chan, qtd, halt_status); +} + +static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg, +				       struct dwc2_host_chan *chan, int chnum, +				       struct dwc2_qtd *qtd) +{ +	struct dwc2_hcd_iso_packet_desc *frame_desc; +	u32 len; + +	if (!qtd->urb) +		return 0; + +	frame_desc = &qtd->urb->iso_descs[qtd->isoc_frame_index]; +	len = dwc2_get_actual_xfer_length(hsotg, chan, chnum, qtd, +					  DWC2_HC_XFER_COMPLETE, NULL); +	if (!len) { +		qtd->complete_split = 0; +		qtd->isoc_split_offset = 0; +		return 0; +	} + +	frame_desc->actual_length += len; + +	if (chan->align_buf) { +		dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__); +		dma_sync_single_for_cpu(hsotg->dev, qtd->urb->dma, +					qtd->urb->length, DMA_FROM_DEVICE); +		memcpy(qtd->urb->buf + frame_desc->offset + +		       qtd->isoc_split_offset, chan->qh->dw_align_buf, len); +		dma_sync_single_for_device(hsotg->dev, qtd->urb->dma, +					   qtd->urb->length, DMA_FROM_DEVICE); +	} + +	qtd->isoc_split_offset += len; + +	if (frame_desc->actual_length >= frame_desc->length) { +		frame_desc->status = 0; +		qtd->isoc_frame_index++; +		qtd->complete_split = 0; +		qtd->isoc_split_offset = 0; +	} + +	if (qtd->isoc_frame_index == qtd->urb->packet_count) { +		dwc2_host_complete(hsotg, qtd, 0); +		dwc2_release_channel(hsotg, chan, qtd, +				     DWC2_HC_XFER_URB_COMPLETE); +	} else { +		dwc2_release_channel(hsotg, chan, qtd, +				     DWC2_HC_XFER_NO_HALT_STATUS); +	} + +	return 1;	/* Indicates that channel released */ +} + +/* + * Handles a host channel Transfer Complete interrupt. This handler may be + * called in either DMA mode or Slave mode. + */ +static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg, +				  struct dwc2_host_chan *chan, int chnum, +				  struct dwc2_qtd *qtd) +{ +	struct dwc2_hcd_urb *urb = qtd->urb; +	enum dwc2_halt_status halt_status = DWC2_HC_XFER_COMPLETE; +	int pipe_type; +	int urb_xfer_done; + +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, +			 "--Host Channel %d Interrupt: Transfer Complete--\n", +			 chnum); + +	if (!urb) +		goto handle_xfercomp_done; + +	pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info); + +	if (hsotg->core_params->dma_desc_enable > 0) { +		dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, halt_status); +		if (pipe_type == USB_ENDPOINT_XFER_ISOC) +			/* Do not disable the interrupt, just clear it */ +			return; +		goto handle_xfercomp_done; +	} + +	/* Handle xfer complete on CSPLIT */ +	if (chan->qh->do_split) { +		if (chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in && +		    hsotg->core_params->dma_enable > 0) { +			if (qtd->complete_split && +			    dwc2_xfercomp_isoc_split_in(hsotg, chan, chnum, +							qtd)) +				goto handle_xfercomp_done; +		} else { +			qtd->complete_split = 0; +		} +	} + +	/* Update the QTD and URB states */ +	switch (pipe_type) { +	case USB_ENDPOINT_XFER_CONTROL: +		switch (qtd->control_phase) { +		case DWC2_CONTROL_SETUP: +			if (urb->length > 0) +				qtd->control_phase = DWC2_CONTROL_DATA; +			else +				qtd->control_phase = DWC2_CONTROL_STATUS; +			dev_vdbg(hsotg->dev, +				 "  Control setup transaction done\n"); +			halt_status = DWC2_HC_XFER_COMPLETE; +			break; +		case DWC2_CONTROL_DATA: +			urb_xfer_done = dwc2_update_urb_state(hsotg, chan, +							      chnum, urb, qtd); +			if (urb_xfer_done) { +				qtd->control_phase = DWC2_CONTROL_STATUS; +				dev_vdbg(hsotg->dev, +					 "  Control data transfer done\n"); +			} else { +				dwc2_hcd_save_data_toggle(hsotg, chan, chnum, +							  qtd); +			} +			halt_status = DWC2_HC_XFER_COMPLETE; +			break; +		case DWC2_CONTROL_STATUS: +			dev_vdbg(hsotg->dev, "  Control transfer complete\n"); +			if (urb->status == -EINPROGRESS) +				urb->status = 0; +			dwc2_host_complete(hsotg, qtd, urb->status); +			halt_status = DWC2_HC_XFER_URB_COMPLETE; +			break; +		} + +		dwc2_complete_non_periodic_xfer(hsotg, chan, chnum, qtd, +						halt_status); +		break; +	case USB_ENDPOINT_XFER_BULK: +		dev_vdbg(hsotg->dev, "  Bulk transfer complete\n"); +		urb_xfer_done = dwc2_update_urb_state(hsotg, chan, chnum, urb, +						      qtd); +		if (urb_xfer_done) { +			dwc2_host_complete(hsotg, qtd, urb->status); +			halt_status = DWC2_HC_XFER_URB_COMPLETE; +		} else { +			halt_status = DWC2_HC_XFER_COMPLETE; +		} + +		dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); +		dwc2_complete_non_periodic_xfer(hsotg, chan, chnum, qtd, +						halt_status); +		break; +	case USB_ENDPOINT_XFER_INT: +		dev_vdbg(hsotg->dev, "  Interrupt transfer complete\n"); +		urb_xfer_done = dwc2_update_urb_state(hsotg, chan, chnum, urb, +						      qtd); + +		/* +		 * Interrupt URB is done on the first transfer complete +		 * interrupt +		 */ +		if (urb_xfer_done) { +			dwc2_host_complete(hsotg, qtd, urb->status); +			halt_status = DWC2_HC_XFER_URB_COMPLETE; +		} else { +			halt_status = DWC2_HC_XFER_COMPLETE; +		} + +		dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); +		dwc2_complete_periodic_xfer(hsotg, chan, chnum, qtd, +					    halt_status); +		break; +	case USB_ENDPOINT_XFER_ISOC: +		if (dbg_perio()) +			dev_vdbg(hsotg->dev, "  Isochronous transfer complete\n"); +		if (qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_ALL) +			halt_status = dwc2_update_isoc_urb_state(hsotg, chan, +					chnum, qtd, DWC2_HC_XFER_COMPLETE); +		dwc2_complete_periodic_xfer(hsotg, chan, chnum, qtd, +					    halt_status); +		break; +	} + +handle_xfercomp_done: +	disable_hc_int(hsotg, chnum, HCINTMSK_XFERCOMPL); +} + +/* + * Handles a host channel STALL interrupt. This handler may be called in + * either DMA mode or Slave mode. + */ +static void dwc2_hc_stall_intr(struct dwc2_hsotg *hsotg, +			       struct dwc2_host_chan *chan, int chnum, +			       struct dwc2_qtd *qtd) +{ +	struct dwc2_hcd_urb *urb = qtd->urb; +	int pipe_type; + +	dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: STALL Received--\n", +		chnum); + +	if (hsotg->core_params->dma_desc_enable > 0) { +		dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, +					    DWC2_HC_XFER_STALL); +		goto handle_stall_done; +	} + +	if (!urb) +		goto handle_stall_halt; + +	pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info); + +	if (pipe_type == USB_ENDPOINT_XFER_CONTROL) +		dwc2_host_complete(hsotg, qtd, -EPIPE); + +	if (pipe_type == USB_ENDPOINT_XFER_BULK || +	    pipe_type == USB_ENDPOINT_XFER_INT) { +		dwc2_host_complete(hsotg, qtd, -EPIPE); +		/* +		 * USB protocol requires resetting the data toggle for bulk +		 * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT) +		 * setup command is issued to the endpoint. Anticipate the +		 * CLEAR_FEATURE command since a STALL has occurred and reset +		 * the data toggle now. +		 */ +		chan->qh->data_toggle = 0; +	} + +handle_stall_halt: +	dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_STALL); + +handle_stall_done: +	disable_hc_int(hsotg, chnum, HCINTMSK_STALL); +} + +/* + * Updates the state of the URB when a transfer has been stopped due to an + * abnormal condition before the transfer completes. Modifies the + * actual_length field of the URB to reflect the number of bytes that have + * actually been transferred via the host channel. + */ +static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg, +				      struct dwc2_host_chan *chan, int chnum, +				      struct dwc2_hcd_urb *urb, +				      struct dwc2_qtd *qtd, +				      enum dwc2_halt_status halt_status) +{ +	u32 xfer_length = dwc2_get_actual_xfer_length(hsotg, chan, chnum, +						      qtd, halt_status, NULL); +	u32 hctsiz; + +	if (urb->actual_length + xfer_length > urb->length) { +		dev_warn(hsotg->dev, "%s(): trimming xfer length\n", __func__); +		xfer_length = urb->length - urb->actual_length; +	} + +	/* Non DWORD-aligned buffer case handling */ +	if (chan->align_buf && xfer_length && chan->ep_is_in) { +		dev_vdbg(hsotg->dev, "%s(): non-aligned buffer\n", __func__); +		dma_sync_single_for_cpu(hsotg->dev, urb->dma, urb->length, +					DMA_FROM_DEVICE); +		memcpy(urb->buf + urb->actual_length, chan->qh->dw_align_buf, +		       xfer_length); +		dma_sync_single_for_device(hsotg->dev, urb->dma, urb->length, +					   DMA_FROM_DEVICE); +	} + +	urb->actual_length += xfer_length; + +	hctsiz = readl(hsotg->regs + HCTSIZ(chnum)); +	dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n", +		 __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum); +	dev_vdbg(hsotg->dev, "  chan->start_pkt_count %d\n", +		 chan->start_pkt_count); +	dev_vdbg(hsotg->dev, "  hctsiz.pktcnt %d\n", +		 (hctsiz & TSIZ_PKTCNT_MASK) >> TSIZ_PKTCNT_SHIFT); +	dev_vdbg(hsotg->dev, "  chan->max_packet %d\n", chan->max_packet); +	dev_vdbg(hsotg->dev, "  bytes_transferred %d\n", +		 xfer_length); +	dev_vdbg(hsotg->dev, "  urb->actual_length %d\n", +		 urb->actual_length); +	dev_vdbg(hsotg->dev, "  urb->transfer_buffer_length %d\n", +		 urb->length); +} + +/* + * Handles a host channel NAK interrupt. This handler may be called in either + * DMA mode or Slave mode. + */ +static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg, +			     struct dwc2_host_chan *chan, int chnum, +			     struct dwc2_qtd *qtd) +{ +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NAK Received--\n", +			 chnum); + +	/* +	 * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and +	 * interrupt. Re-start the SSPLIT transfer. +	 */ +	if (chan->do_split) { +		if (chan->complete_split) +			qtd->error_count = 0; +		qtd->complete_split = 0; +		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK); +		goto handle_nak_done; +	} + +	switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) { +	case USB_ENDPOINT_XFER_CONTROL: +	case USB_ENDPOINT_XFER_BULK: +		if (hsotg->core_params->dma_enable > 0 && chan->ep_is_in) { +			/* +			 * NAK interrupts are enabled on bulk/control IN +			 * transfers in DMA mode for the sole purpose of +			 * resetting the error count after a transaction error +			 * occurs. The core will continue transferring data. +			 */ +			qtd->error_count = 0; +			break; +		} + +		/* +		 * NAK interrupts normally occur during OUT transfers in DMA +		 * or Slave mode. For IN transfers, more requests will be +		 * queued as request queue space is available. +		 */ +		qtd->error_count = 0; + +		if (!chan->qh->ping_state) { +			dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb, +						  qtd, DWC2_HC_XFER_NAK); +			dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); + +			if (chan->speed == USB_SPEED_HIGH) +				chan->qh->ping_state = 1; +		} + +		/* +		 * Halt the channel so the transfer can be re-started from +		 * the appropriate point or the PING protocol will +		 * start/continue +		 */ +		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK); +		break; +	case USB_ENDPOINT_XFER_INT: +		qtd->error_count = 0; +		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NAK); +		break; +	case USB_ENDPOINT_XFER_ISOC: +		/* Should never get called for isochronous transfers */ +		dev_err(hsotg->dev, "NACK interrupt for ISOC transfer\n"); +		break; +	} + +handle_nak_done: +	disable_hc_int(hsotg, chnum, HCINTMSK_NAK); +} + +/* + * Handles a host channel ACK interrupt. This interrupt is enabled when + * performing the PING protocol in Slave mode, when errors occur during + * either Slave mode or DMA mode, and during Start Split transactions. + */ +static void dwc2_hc_ack_intr(struct dwc2_hsotg *hsotg, +			     struct dwc2_host_chan *chan, int chnum, +			     struct dwc2_qtd *qtd) +{ +	struct dwc2_hcd_iso_packet_desc *frame_desc; + +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: ACK Received--\n", +			 chnum); + +	if (chan->do_split) { +		/* Handle ACK on SSPLIT. ACK should not occur in CSPLIT. */ +		if (!chan->ep_is_in && +		    chan->data_pid_start != DWC2_HC_PID_SETUP) +			qtd->ssplit_out_xfer_count = chan->xfer_len; + +		if (chan->ep_type != USB_ENDPOINT_XFER_ISOC || chan->ep_is_in) { +			qtd->complete_split = 1; +			dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_ACK); +		} else { +			/* ISOC OUT */ +			switch (chan->xact_pos) { +			case DWC2_HCSPLT_XACTPOS_ALL: +				break; +			case DWC2_HCSPLT_XACTPOS_END: +				qtd->isoc_split_pos = DWC2_HCSPLT_XACTPOS_ALL; +				qtd->isoc_split_offset = 0; +				break; +			case DWC2_HCSPLT_XACTPOS_BEGIN: +			case DWC2_HCSPLT_XACTPOS_MID: +				/* +				 * For BEGIN or MID, calculate the length for +				 * the next microframe to determine the correct +				 * SSPLIT token, either MID or END +				 */ +				frame_desc = &qtd->urb->iso_descs[ +						qtd->isoc_frame_index]; +				qtd->isoc_split_offset += 188; + +				if (frame_desc->length - qtd->isoc_split_offset +							<= 188) +					qtd->isoc_split_pos = +							DWC2_HCSPLT_XACTPOS_END; +				else +					qtd->isoc_split_pos = +							DWC2_HCSPLT_XACTPOS_MID; +				break; +			} +		} +	} else { +		qtd->error_count = 0; + +		if (chan->qh->ping_state) { +			chan->qh->ping_state = 0; +			/* +			 * Halt the channel so the transfer can be re-started +			 * from the appropriate point. This only happens in +			 * Slave mode. In DMA mode, the ping_state is cleared +			 * when the transfer is started because the core +			 * automatically executes the PING, then the transfer. +			 */ +			dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_ACK); +		} +	} + +	/* +	 * If the ACK occurred when _not_ in the PING state, let the channel +	 * continue transferring data after clearing the error count +	 */ +	disable_hc_int(hsotg, chnum, HCINTMSK_ACK); +} + +/* + * Handles a host channel NYET interrupt. This interrupt should only occur on + * Bulk and Control OUT endpoints and for complete split transactions. If a + * NYET occurs at the same time as a Transfer Complete interrupt, it is + * handled in the xfercomp interrupt handler, not here. This handler may be + * called in either DMA mode or Slave mode. + */ +static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg, +			      struct dwc2_host_chan *chan, int chnum, +			      struct dwc2_qtd *qtd) +{ +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: NYET Received--\n", +			 chnum); + +	/* +	 * NYET on CSPLIT +	 * re-do the CSPLIT immediately on non-periodic +	 */ +	if (chan->do_split && chan->complete_split) { +		if (chan->ep_is_in && chan->ep_type == USB_ENDPOINT_XFER_ISOC && +		    hsotg->core_params->dma_enable > 0) { +			qtd->complete_split = 0; +			qtd->isoc_split_offset = 0; +			qtd->isoc_frame_index++; +			if (qtd->urb && +			    qtd->isoc_frame_index == qtd->urb->packet_count) { +				dwc2_host_complete(hsotg, qtd, 0); +				dwc2_release_channel(hsotg, chan, qtd, +						     DWC2_HC_XFER_URB_COMPLETE); +			} else { +				dwc2_release_channel(hsotg, chan, qtd, +						DWC2_HC_XFER_NO_HALT_STATUS); +			} +			goto handle_nyet_done; +		} + +		if (chan->ep_type == USB_ENDPOINT_XFER_INT || +		    chan->ep_type == USB_ENDPOINT_XFER_ISOC) { +			int frnum = dwc2_hcd_get_frame_number(hsotg); + +			if (dwc2_full_frame_num(frnum) != +			    dwc2_full_frame_num(chan->qh->sched_frame)) { +				/* +				 * No longer in the same full speed frame. +				 * Treat this as a transaction error. +				 */ +#if 0 +				/* +				 * Todo: Fix system performance so this can +				 * be treated as an error. Right now complete +				 * splits cannot be scheduled precisely enough +				 * due to other system activity, so this error +				 * occurs regularly in Slave mode. +				 */ +				qtd->error_count++; +#endif +				qtd->complete_split = 0; +				dwc2_halt_channel(hsotg, chan, qtd, +						  DWC2_HC_XFER_XACT_ERR); +				/* Todo: add support for isoc release */ +				goto handle_nyet_done; +			} +		} + +		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NYET); +		goto handle_nyet_done; +	} + +	chan->qh->ping_state = 1; +	qtd->error_count = 0; + +	dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb, qtd, +				  DWC2_HC_XFER_NYET); +	dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); + +	/* +	 * Halt the channel and re-start the transfer so the PING protocol +	 * will start +	 */ +	dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_NYET); + +handle_nyet_done: +	disable_hc_int(hsotg, chnum, HCINTMSK_NYET); +} + +/* + * Handles a host channel babble interrupt. This handler may be called in + * either DMA mode or Slave mode. + */ +static void dwc2_hc_babble_intr(struct dwc2_hsotg *hsotg, +				struct dwc2_host_chan *chan, int chnum, +				struct dwc2_qtd *qtd) +{ +	dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Babble Error--\n", +		chnum); + +	dwc2_hc_handle_tt_clear(hsotg, chan, qtd); + +	if (hsotg->core_params->dma_desc_enable > 0) { +		dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, +					    DWC2_HC_XFER_BABBLE_ERR); +		goto disable_int; +	} + +	if (chan->ep_type != USB_ENDPOINT_XFER_ISOC) { +		dwc2_host_complete(hsotg, qtd, -EOVERFLOW); +		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_BABBLE_ERR); +	} else { +		enum dwc2_halt_status halt_status; + +		halt_status = dwc2_update_isoc_urb_state(hsotg, chan, chnum, +						qtd, DWC2_HC_XFER_BABBLE_ERR); +		dwc2_halt_channel(hsotg, chan, qtd, halt_status); +	} + +disable_int: +	disable_hc_int(hsotg, chnum, HCINTMSK_BBLERR); +} + +/* + * Handles a host channel AHB error interrupt. This handler is only called in + * DMA mode. + */ +static void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg, +				struct dwc2_host_chan *chan, int chnum, +				struct dwc2_qtd *qtd) +{ +	struct dwc2_hcd_urb *urb = qtd->urb; +	char *pipetype, *speed; +	u32 hcchar; +	u32 hcsplt; +	u32 hctsiz; +	u32 hc_dma; + +	dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: AHB Error--\n", +		chnum); + +	if (!urb) +		goto handle_ahberr_halt; + +	dwc2_hc_handle_tt_clear(hsotg, chan, qtd); + +	hcchar = readl(hsotg->regs + HCCHAR(chnum)); +	hcsplt = readl(hsotg->regs + HCSPLT(chnum)); +	hctsiz = readl(hsotg->regs + HCTSIZ(chnum)); +	hc_dma = readl(hsotg->regs + HCDMA(chnum)); + +	dev_err(hsotg->dev, "AHB ERROR, Channel %d\n", chnum); +	dev_err(hsotg->dev, "  hcchar 0x%08x, hcsplt 0x%08x\n", hcchar, hcsplt); +	dev_err(hsotg->dev, "  hctsiz 0x%08x, hc_dma 0x%08x\n", hctsiz, hc_dma); +	dev_err(hsotg->dev, "  Device address: %d\n", +		dwc2_hcd_get_dev_addr(&urb->pipe_info)); +	dev_err(hsotg->dev, "  Endpoint: %d, %s\n", +		dwc2_hcd_get_ep_num(&urb->pipe_info), +		dwc2_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"); + +	switch (dwc2_hcd_get_pipe_type(&urb->pipe_info)) { +	case USB_ENDPOINT_XFER_CONTROL: +		pipetype = "CONTROL"; +		break; +	case USB_ENDPOINT_XFER_BULK: +		pipetype = "BULK"; +		break; +	case USB_ENDPOINT_XFER_INT: +		pipetype = "INTERRUPT"; +		break; +	case USB_ENDPOINT_XFER_ISOC: +		pipetype = "ISOCHRONOUS"; +		break; +	default: +		pipetype = "UNKNOWN"; +		break; +	} + +	dev_err(hsotg->dev, "  Endpoint type: %s\n", pipetype); + +	switch (chan->speed) { +	case USB_SPEED_HIGH: +		speed = "HIGH"; +		break; +	case USB_SPEED_FULL: +		speed = "FULL"; +		break; +	case USB_SPEED_LOW: +		speed = "LOW"; +		break; +	default: +		speed = "UNKNOWN"; +		break; +	} + +	dev_err(hsotg->dev, "  Speed: %s\n", speed); + +	dev_err(hsotg->dev, "  Max packet size: %d\n", +		dwc2_hcd_get_mps(&urb->pipe_info)); +	dev_err(hsotg->dev, "  Data buffer length: %d\n", urb->length); +	dev_err(hsotg->dev, "  Transfer buffer: %p, Transfer DMA: %08lx\n", +		urb->buf, (unsigned long)urb->dma); +	dev_err(hsotg->dev, "  Setup buffer: %p, Setup DMA: %08lx\n", +		urb->setup_packet, (unsigned long)urb->setup_dma); +	dev_err(hsotg->dev, "  Interval: %d\n", urb->interval); + +	/* Core halts the channel for Descriptor DMA mode */ +	if (hsotg->core_params->dma_desc_enable > 0) { +		dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, +					    DWC2_HC_XFER_AHB_ERR); +		goto handle_ahberr_done; +	} + +	dwc2_host_complete(hsotg, qtd, -EIO); + +handle_ahberr_halt: +	/* +	 * Force a channel halt. Don't call dwc2_halt_channel because that won't +	 * write to the HCCHARn register in DMA mode to force the halt. +	 */ +	dwc2_hc_halt(hsotg, chan, DWC2_HC_XFER_AHB_ERR); + +handle_ahberr_done: +	disable_hc_int(hsotg, chnum, HCINTMSK_AHBERR); +} + +/* + * Handles a host channel transaction error interrupt. This handler may be + * called in either DMA mode or Slave mode. + */ +static void dwc2_hc_xacterr_intr(struct dwc2_hsotg *hsotg, +				 struct dwc2_host_chan *chan, int chnum, +				 struct dwc2_qtd *qtd) +{ +	dev_dbg(hsotg->dev, +		"--Host Channel %d Interrupt: Transaction Error--\n", chnum); + +	dwc2_hc_handle_tt_clear(hsotg, chan, qtd); + +	if (hsotg->core_params->dma_desc_enable > 0) { +		dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, +					    DWC2_HC_XFER_XACT_ERR); +		goto handle_xacterr_done; +	} + +	switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) { +	case USB_ENDPOINT_XFER_CONTROL: +	case USB_ENDPOINT_XFER_BULK: +		qtd->error_count++; +		if (!chan->qh->ping_state) { + +			dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb, +						  qtd, DWC2_HC_XFER_XACT_ERR); +			dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); +			if (!chan->ep_is_in && chan->speed == USB_SPEED_HIGH) +				chan->qh->ping_state = 1; +		} + +		/* +		 * Halt the channel so the transfer can be re-started from +		 * the appropriate point or the PING protocol will start +		 */ +		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_XACT_ERR); +		break; +	case USB_ENDPOINT_XFER_INT: +		qtd->error_count++; +		if (chan->do_split && chan->complete_split) +			qtd->complete_split = 0; +		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_XACT_ERR); +		break; +	case USB_ENDPOINT_XFER_ISOC: +		{ +			enum dwc2_halt_status halt_status; + +			halt_status = dwc2_update_isoc_urb_state(hsotg, chan, +					chnum, qtd, DWC2_HC_XFER_XACT_ERR); +			dwc2_halt_channel(hsotg, chan, qtd, halt_status); +		} +		break; +	} + +handle_xacterr_done: +	disable_hc_int(hsotg, chnum, HCINTMSK_XACTERR); +} + +/* + * Handles a host channel frame overrun interrupt. This handler may be called + * in either DMA mode or Slave mode. + */ +static void dwc2_hc_frmovrun_intr(struct dwc2_hsotg *hsotg, +				  struct dwc2_host_chan *chan, int chnum, +				  struct dwc2_qtd *qtd) +{ +	enum dwc2_halt_status halt_status; + +	if (dbg_hc(chan)) +		dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: Frame Overrun--\n", +			chnum); + +	dwc2_hc_handle_tt_clear(hsotg, chan, qtd); + +	switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) { +	case USB_ENDPOINT_XFER_CONTROL: +	case USB_ENDPOINT_XFER_BULK: +		break; +	case USB_ENDPOINT_XFER_INT: +		dwc2_halt_channel(hsotg, chan, qtd, DWC2_HC_XFER_FRAME_OVERRUN); +		break; +	case USB_ENDPOINT_XFER_ISOC: +		halt_status = dwc2_update_isoc_urb_state(hsotg, chan, chnum, +					qtd, DWC2_HC_XFER_FRAME_OVERRUN); +		dwc2_halt_channel(hsotg, chan, qtd, halt_status); +		break; +	} + +	disable_hc_int(hsotg, chnum, HCINTMSK_FRMOVRUN); +} + +/* + * Handles a host channel data toggle error interrupt. This handler may be + * called in either DMA mode or Slave mode. + */ +static void dwc2_hc_datatglerr_intr(struct dwc2_hsotg *hsotg, +				    struct dwc2_host_chan *chan, int chnum, +				    struct dwc2_qtd *qtd) +{ +	dev_dbg(hsotg->dev, +		"--Host Channel %d Interrupt: Data Toggle Error--\n", chnum); + +	if (chan->ep_is_in) +		qtd->error_count = 0; +	else +		dev_err(hsotg->dev, +			"Data Toggle Error on OUT transfer, channel %d\n", +			chnum); + +	dwc2_hc_handle_tt_clear(hsotg, chan, qtd); +	disable_hc_int(hsotg, chnum, HCINTMSK_DATATGLERR); +} + +/* + * For debug only. It checks that a valid halt status is set and that + * HCCHARn.chdis is clear. If there's a problem, corrective action is + * taken and a warning is issued. + * + * Return: true if halt status is ok, false otherwise + */ +static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg, +				struct dwc2_host_chan *chan, int chnum, +				struct dwc2_qtd *qtd) +{ +#ifdef DEBUG +	u32 hcchar; +	u32 hctsiz; +	u32 hcintmsk; +	u32 hcsplt; + +	if (chan->halt_status == DWC2_HC_XFER_NO_HALT_STATUS) { +		/* +		 * This code is here only as a check. This condition should +		 * never happen. Ignore the halt if it does occur. +		 */ +		hcchar = readl(hsotg->regs + HCCHAR(chnum)); +		hctsiz = readl(hsotg->regs + HCTSIZ(chnum)); +		hcintmsk = readl(hsotg->regs + HCINTMSK(chnum)); +		hcsplt = readl(hsotg->regs + HCSPLT(chnum)); +		dev_dbg(hsotg->dev, +			"%s: chan->halt_status DWC2_HC_XFER_NO_HALT_STATUS,\n", +			 __func__); +		dev_dbg(hsotg->dev, +			"channel %d, hcchar 0x%08x, hctsiz 0x%08x,\n", +			chnum, hcchar, hctsiz); +		dev_dbg(hsotg->dev, +			"hcint 0x%08x, hcintmsk 0x%08x, hcsplt 0x%08x,\n", +			chan->hcint, hcintmsk, hcsplt); +		if (qtd) +			dev_dbg(hsotg->dev, "qtd->complete_split %d\n", +				qtd->complete_split); +		dev_warn(hsotg->dev, +			 "%s: no halt status, channel %d, ignoring interrupt\n", +			 __func__, chnum); +		return false; +	} + +	/* +	 * This code is here only as a check. hcchar.chdis should never be set +	 * when the halt interrupt occurs. Halt the channel again if it does +	 * occur. +	 */ +	hcchar = readl(hsotg->regs + HCCHAR(chnum)); +	if (hcchar & HCCHAR_CHDIS) { +		dev_warn(hsotg->dev, +			 "%s: hcchar.chdis set unexpectedly, hcchar 0x%08x, trying to halt again\n", +			 __func__, hcchar); +		chan->halt_pending = 0; +		dwc2_halt_channel(hsotg, chan, qtd, chan->halt_status); +		return false; +	} +#endif + +	return true; +} + +/* + * Handles a host Channel Halted interrupt in DMA mode. This handler + * determines the reason the channel halted and proceeds accordingly. + */ +static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg, +				    struct dwc2_host_chan *chan, int chnum, +				    struct dwc2_qtd *qtd) +{ +	u32 hcintmsk; +	int out_nak_enh = 0; + +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, +			 "--Host Channel %d Interrupt: DMA Channel Halted--\n", +			 chnum); + +	/* +	 * For core with OUT NAK enhancement, the flow for high-speed +	 * CONTROL/BULK OUT is handled a little differently +	 */ +	if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_71a) { +		if (chan->speed == USB_SPEED_HIGH && !chan->ep_is_in && +		    (chan->ep_type == USB_ENDPOINT_XFER_CONTROL || +		     chan->ep_type == USB_ENDPOINT_XFER_BULK)) { +			out_nak_enh = 1; +		} +	} + +	if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE || +	    (chan->halt_status == DWC2_HC_XFER_AHB_ERR && +	     hsotg->core_params->dma_desc_enable <= 0)) { +		if (hsotg->core_params->dma_desc_enable > 0) +			dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, +						    chan->halt_status); +		else +			/* +			 * Just release the channel. A dequeue can happen on a +			 * transfer timeout. In the case of an AHB Error, the +			 * channel was forced to halt because there's no way to +			 * gracefully recover. +			 */ +			dwc2_release_channel(hsotg, chan, qtd, +					     chan->halt_status); +		return; +	} + +	hcintmsk = readl(hsotg->regs + HCINTMSK(chnum)); + +	if (chan->hcint & HCINTMSK_XFERCOMPL) { +		/* +		 * Todo: This is here because of a possible hardware bug. Spec +		 * says that on SPLIT-ISOC OUT transfers in DMA mode that a HALT +		 * interrupt w/ACK bit set should occur, but I only see the +		 * XFERCOMP bit, even with it masked out. This is a workaround +		 * for that behavior. Should fix this when hardware is fixed. +		 */ +		if (chan->ep_type == USB_ENDPOINT_XFER_ISOC && !chan->ep_is_in) +			dwc2_hc_ack_intr(hsotg, chan, chnum, qtd); +		dwc2_hc_xfercomp_intr(hsotg, chan, chnum, qtd); +	} else if (chan->hcint & HCINTMSK_STALL) { +		dwc2_hc_stall_intr(hsotg, chan, chnum, qtd); +	} else if ((chan->hcint & HCINTMSK_XACTERR) && +		   hsotg->core_params->dma_desc_enable <= 0) { +		if (out_nak_enh) { +			if (chan->hcint & +			    (HCINTMSK_NYET | HCINTMSK_NAK | HCINTMSK_ACK)) { +				dev_vdbg(hsotg->dev, +					 "XactErr with NYET/NAK/ACK\n"); +				qtd->error_count = 0; +			} else { +				dev_vdbg(hsotg->dev, +					 "XactErr without NYET/NAK/ACK\n"); +			} +		} + +		/* +		 * Must handle xacterr before nak or ack. Could get a xacterr +		 * at the same time as either of these on a BULK/CONTROL OUT +		 * that started with a PING. The xacterr takes precedence. +		 */ +		dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd); +	} else if ((chan->hcint & HCINTMSK_XCS_XACT) && +		   hsotg->core_params->dma_desc_enable > 0) { +		dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd); +	} else if ((chan->hcint & HCINTMSK_AHBERR) && +		   hsotg->core_params->dma_desc_enable > 0) { +		dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd); +	} else if (chan->hcint & HCINTMSK_BBLERR) { +		dwc2_hc_babble_intr(hsotg, chan, chnum, qtd); +	} else if (chan->hcint & HCINTMSK_FRMOVRUN) { +		dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd); +	} else if (!out_nak_enh) { +		if (chan->hcint & HCINTMSK_NYET) { +			/* +			 * Must handle nyet before nak or ack. Could get a nyet +			 * at the same time as either of those on a BULK/CONTROL +			 * OUT that started with a PING. The nyet takes +			 * precedence. +			 */ +			dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd); +		} else if ((chan->hcint & HCINTMSK_NAK) && +			   !(hcintmsk & HCINTMSK_NAK)) { +			/* +			 * If nak is not masked, it's because a non-split IN +			 * transfer is in an error state. In that case, the nak +			 * is handled by the nak interrupt handler, not here. +			 * Handle nak here for BULK/CONTROL OUT transfers, which +			 * halt on a NAK to allow rewinding the buffer pointer. +			 */ +			dwc2_hc_nak_intr(hsotg, chan, chnum, qtd); +		} else if ((chan->hcint & HCINTMSK_ACK) && +			   !(hcintmsk & HCINTMSK_ACK)) { +			/* +			 * If ack is not masked, it's because a non-split IN +			 * transfer is in an error state. In that case, the ack +			 * is handled by the ack interrupt handler, not here. +			 * Handle ack here for split transfers. Start splits +			 * halt on ACK. +			 */ +			dwc2_hc_ack_intr(hsotg, chan, chnum, qtd); +		} else { +			if (chan->ep_type == USB_ENDPOINT_XFER_INT || +			    chan->ep_type == USB_ENDPOINT_XFER_ISOC) { +				/* +				 * A periodic transfer halted with no other +				 * channel interrupts set. Assume it was halted +				 * by the core because it could not be completed +				 * in its scheduled (micro)frame. +				 */ +				dev_dbg(hsotg->dev, +					"%s: Halt channel %d (assume incomplete periodic transfer)\n", +					__func__, chnum); +				dwc2_halt_channel(hsotg, chan, qtd, +					DWC2_HC_XFER_PERIODIC_INCOMPLETE); +			} else { +				dev_err(hsotg->dev, +					"%s: Channel %d - ChHltd set, but reason is unknown\n", +					__func__, chnum); +				dev_err(hsotg->dev, +					"hcint 0x%08x, intsts 0x%08x\n", +					chan->hcint, +					readl(hsotg->regs + GINTSTS)); +			} +		} +	} else { +		dev_info(hsotg->dev, +			 "NYET/NAK/ACK/other in non-error case, 0x%08x\n", +			 chan->hcint); +	} +} + +/* + * Handles a host channel Channel Halted interrupt + * + * In slave mode, this handler is called only when the driver specifically + * requests a halt. This occurs during handling other host channel interrupts + * (e.g. nak, xacterr, stall, nyet, etc.). + * + * In DMA mode, this is the interrupt that occurs when the core has finished + * processing a transfer on a channel. Other host channel interrupts (except + * ahberr) are disabled in DMA mode. + */ +static void dwc2_hc_chhltd_intr(struct dwc2_hsotg *hsotg, +				struct dwc2_host_chan *chan, int chnum, +				struct dwc2_qtd *qtd) +{ +	if (dbg_hc(chan)) +		dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: Channel Halted--\n", +			 chnum); + +	if (hsotg->core_params->dma_enable > 0) { +		dwc2_hc_chhltd_intr_dma(hsotg, chan, chnum, qtd); +	} else { +		if (!dwc2_halt_status_ok(hsotg, chan, chnum, qtd)) +			return; +		dwc2_release_channel(hsotg, chan, qtd, chan->halt_status); +	} +} + +/* Handles interrupt for a specific Host Channel */ +static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) +{ +	struct dwc2_qtd *qtd; +	struct dwc2_host_chan *chan; +	u32 hcint, hcintmsk; + +	chan = hsotg->hc_ptr_array[chnum]; + +	hcint = readl(hsotg->regs + HCINT(chnum)); +	hcintmsk = readl(hsotg->regs + HCINTMSK(chnum)); +	if (!chan) { +		dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n"); +		writel(hcint, hsotg->regs + HCINT(chnum)); +		return; +	} + +	if (dbg_hc(chan)) { +		dev_vdbg(hsotg->dev, "--Host Channel Interrupt--, Channel %d\n", +			 chnum); +		dev_vdbg(hsotg->dev, +			 "  hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", +			 hcint, hcintmsk, hcint & hcintmsk); +	} + +	writel(hcint, hsotg->regs + HCINT(chnum)); +	chan->hcint = hcint; +	hcint &= hcintmsk; + +	/* +	 * If the channel was halted due to a dequeue, the qtd list might +	 * be empty or at least the first entry will not be the active qtd. +	 * In this case, take a shortcut and just release the channel. +	 */ +	if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) { +		/* +		 * If the channel was halted, this should be the only +		 * interrupt unmasked +		 */ +		WARN_ON(hcint != HCINTMSK_CHHLTD); +		if (hsotg->core_params->dma_desc_enable > 0) +			dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, +						    chan->halt_status); +		else +			dwc2_release_channel(hsotg, chan, NULL, +					     chan->halt_status); +		return; +	} + +	if (list_empty(&chan->qh->qtd_list)) { +		/* +		 * TODO: Will this ever happen with the +		 * DWC2_HC_XFER_URB_DEQUEUE handling above? +		 */ +		dev_dbg(hsotg->dev, "## no QTD queued for channel %d ##\n", +			chnum); +		dev_dbg(hsotg->dev, +			"  hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n", +			chan->hcint, hcintmsk, hcint); +		chan->halt_status = DWC2_HC_XFER_NO_HALT_STATUS; +		disable_hc_int(hsotg, chnum, HCINTMSK_CHHLTD); +		chan->hcint = 0; +		return; +	} + +	qtd = list_first_entry(&chan->qh->qtd_list, struct dwc2_qtd, +			       qtd_list_entry); + +	if (hsotg->core_params->dma_enable <= 0) { +		if ((hcint & HCINTMSK_CHHLTD) && hcint != HCINTMSK_CHHLTD) +			hcint &= ~HCINTMSK_CHHLTD; +	} + +	if (hcint & HCINTMSK_XFERCOMPL) { +		dwc2_hc_xfercomp_intr(hsotg, chan, chnum, qtd); +		/* +		 * If NYET occurred at same time as Xfer Complete, the NYET is +		 * handled by the Xfer Complete interrupt handler. Don't want +		 * to call the NYET interrupt handler in this case. +		 */ +		hcint &= ~HCINTMSK_NYET; +	} +	if (hcint & HCINTMSK_CHHLTD) +		dwc2_hc_chhltd_intr(hsotg, chan, chnum, qtd); +	if (hcint & HCINTMSK_AHBERR) +		dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd); +	if (hcint & HCINTMSK_STALL) +		dwc2_hc_stall_intr(hsotg, chan, chnum, qtd); +	if (hcint & HCINTMSK_NAK) +		dwc2_hc_nak_intr(hsotg, chan, chnum, qtd); +	if (hcint & HCINTMSK_ACK) +		dwc2_hc_ack_intr(hsotg, chan, chnum, qtd); +	if (hcint & HCINTMSK_NYET) +		dwc2_hc_nyet_intr(hsotg, chan, chnum, qtd); +	if (hcint & HCINTMSK_XACTERR) +		dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd); +	if (hcint & HCINTMSK_BBLERR) +		dwc2_hc_babble_intr(hsotg, chan, chnum, qtd); +	if (hcint & HCINTMSK_FRMOVRUN) +		dwc2_hc_frmovrun_intr(hsotg, chan, chnum, qtd); +	if (hcint & HCINTMSK_DATATGLERR) +		dwc2_hc_datatglerr_intr(hsotg, chan, chnum, qtd); + +	chan->hcint = 0; +} + +/* + * This interrupt indicates that one or more host channels has a pending + * interrupt. There are multiple conditions that can cause each host channel + * interrupt. This function determines which conditions have occurred for each + * host channel interrupt and handles them appropriately. + */ +static void dwc2_hc_intr(struct dwc2_hsotg *hsotg) +{ +	u32 haint; +	int i; + +	haint = readl(hsotg->regs + HAINT); +	if (dbg_perio()) { +		dev_vdbg(hsotg->dev, "%s()\n", __func__); + +		dev_vdbg(hsotg->dev, "HAINT=%08x\n", haint); +	} + +	for (i = 0; i < hsotg->core_params->host_channels; i++) { +		if (haint & (1 << i)) +			dwc2_hc_n_intr(hsotg, i); +	} +} + +/* This function handles interrupts for the HCD */ +irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg) +{ +	u32 gintsts, dbg_gintsts; +	irqreturn_t retval = IRQ_NONE; + +	if (!dwc2_is_controller_alive(hsotg)) { +		dev_warn(hsotg->dev, "Controller is dead\n"); +		return retval; +	} + +	spin_lock(&hsotg->lock); + +	/* Check if HOST Mode */ +	if (dwc2_is_host_mode(hsotg)) { +		gintsts = dwc2_read_core_intr(hsotg); +		if (!gintsts) { +			spin_unlock(&hsotg->lock); +			return retval; +		} + +		retval = IRQ_HANDLED; + +		dbg_gintsts = gintsts; +#ifndef DEBUG_SOF +		dbg_gintsts &= ~GINTSTS_SOF; +#endif +		if (!dbg_perio()) +			dbg_gintsts &= ~(GINTSTS_HCHINT | GINTSTS_RXFLVL | +					 GINTSTS_PTXFEMP); + +		/* Only print if there are any non-suppressed interrupts left */ +		if (dbg_gintsts) +			dev_vdbg(hsotg->dev, +				 "DWC OTG HCD Interrupt Detected gintsts&gintmsk=0x%08x\n", +				 gintsts); + +		if (gintsts & GINTSTS_SOF) +			dwc2_sof_intr(hsotg); +		if (gintsts & GINTSTS_RXFLVL) +			dwc2_rx_fifo_level_intr(hsotg); +		if (gintsts & GINTSTS_NPTXFEMP) +			dwc2_np_tx_fifo_empty_intr(hsotg); +		if (gintsts & GINTSTS_PRTINT) +			dwc2_port_intr(hsotg); +		if (gintsts & GINTSTS_HCHINT) +			dwc2_hc_intr(hsotg); +		if (gintsts & GINTSTS_PTXFEMP) +			dwc2_perio_tx_fifo_empty_intr(hsotg); + +		if (dbg_gintsts) { +			dev_vdbg(hsotg->dev, +				 "DWC OTG HCD Finished Servicing Interrupts\n"); +			dev_vdbg(hsotg->dev, +				 "DWC OTG HCD gintsts=0x%08x gintmsk=0x%08x\n", +				 readl(hsotg->regs + GINTSTS), +				 readl(hsotg->regs + GINTMSK)); +		} +	} + +	spin_unlock(&hsotg->lock); + +	return retval; +} diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c new file mode 100644 index 00000000000..9540f7e1e20 --- /dev/null +++ b/drivers/usb/dwc2/hcd_queue.c @@ -0,0 +1,835 @@ +/* + * hcd_queue.c - DesignWare HS OTG Controller host queuing routines + * + * Copyright (C) 2004-2013 Synopsys, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + *    to endorse or promote products derived from this software without + *    specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This file contains the functions to manage Queue Heads and Queue + * Transfer Descriptors for Host mode + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include <linux/usb/hcd.h> +#include <linux/usb/ch11.h> + +#include "core.h" +#include "hcd.h" + +/** + * dwc2_qh_init() - Initializes a QH structure + * + * @hsotg: The HCD state structure for the DWC OTG controller + * @qh:    The QH to init + * @urb:   Holds the information about the device/endpoint needed to initialize + *         the QH + */ +#define SCHEDULE_SLOP 10 +static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, +			 struct dwc2_hcd_urb *urb) +{ +	int dev_speed, hub_addr, hub_port; +	char *speed, *type; + +	dev_vdbg(hsotg->dev, "%s()\n", __func__); + +	/* Initialize QH */ +	qh->ep_type = dwc2_hcd_get_pipe_type(&urb->pipe_info); +	qh->ep_is_in = dwc2_hcd_is_pipe_in(&urb->pipe_info) ? 1 : 0; + +	qh->data_toggle = DWC2_HC_PID_DATA0; +	qh->maxp = dwc2_hcd_get_mps(&urb->pipe_info); +	INIT_LIST_HEAD(&qh->qtd_list); +	INIT_LIST_HEAD(&qh->qh_list_entry); + +	/* FS/LS Endpoint on HS Hub, NOT virtual root hub */ +	dev_speed = dwc2_host_get_speed(hsotg, urb->priv); + +	dwc2_host_hub_info(hsotg, urb->priv, &hub_addr, &hub_port); + +	if ((dev_speed == USB_SPEED_LOW || dev_speed == USB_SPEED_FULL) && +	    hub_addr != 0 && hub_addr != 1) { +		dev_vdbg(hsotg->dev, +			 "QH init: EP %d: TT found at hub addr %d, for port %d\n", +			 dwc2_hcd_get_ep_num(&urb->pipe_info), hub_addr, +			 hub_port); +		qh->do_split = 1; +	} + +	if (qh->ep_type == USB_ENDPOINT_XFER_INT || +	    qh->ep_type == USB_ENDPOINT_XFER_ISOC) { +		/* Compute scheduling parameters once and save them */ +		u32 hprt, prtspd; + +		/* Todo: Account for split transfers in the bus time */ +		int bytecount = +			dwc2_hb_mult(qh->maxp) * dwc2_max_packet(qh->maxp); + +		qh->usecs = NS_TO_US(usb_calc_bus_time(qh->do_split ? +				USB_SPEED_HIGH : dev_speed, qh->ep_is_in, +				qh->ep_type == USB_ENDPOINT_XFER_ISOC, +				bytecount)); +		/* Start in a slightly future (micro)frame */ +		qh->sched_frame = dwc2_frame_num_inc(hsotg->frame_number, +						     SCHEDULE_SLOP); +		qh->interval = urb->interval; +#if 0 +		/* Increase interrupt polling rate for debugging */ +		if (qh->ep_type == USB_ENDPOINT_XFER_INT) +			qh->interval = 8; +#endif +		hprt = readl(hsotg->regs + HPRT0); +		prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT; +		if (prtspd == HPRT0_SPD_HIGH_SPEED && +		    (dev_speed == USB_SPEED_LOW || +		     dev_speed == USB_SPEED_FULL)) { +			qh->interval *= 8; +			qh->sched_frame |= 0x7; +			qh->start_split_frame = qh->sched_frame; +		} +		dev_dbg(hsotg->dev, "interval=%d\n", qh->interval); +	} + +	dev_vdbg(hsotg->dev, "DWC OTG HCD QH Initialized\n"); +	dev_vdbg(hsotg->dev, "DWC OTG HCD QH - qh = %p\n", qh); +	dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Device Address = %d\n", +		 dwc2_hcd_get_dev_addr(&urb->pipe_info)); +	dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Endpoint %d, %s\n", +		 dwc2_hcd_get_ep_num(&urb->pipe_info), +		 dwc2_hcd_is_pipe_in(&urb->pipe_info) ? "IN" : "OUT"); + +	qh->dev_speed = dev_speed; + +	switch (dev_speed) { +	case USB_SPEED_LOW: +		speed = "low"; +		break; +	case USB_SPEED_FULL: +		speed = "full"; +		break; +	case USB_SPEED_HIGH: +		speed = "high"; +		break; +	default: +		speed = "?"; +		break; +	} +	dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Speed = %s\n", speed); + +	switch (qh->ep_type) { +	case USB_ENDPOINT_XFER_ISOC: +		type = "isochronous"; +		break; +	case USB_ENDPOINT_XFER_INT: +		type = "interrupt"; +		break; +	case USB_ENDPOINT_XFER_CONTROL: +		type = "control"; +		break; +	case USB_ENDPOINT_XFER_BULK: +		type = "bulk"; +		break; +	default: +		type = "?"; +		break; +	} + +	dev_vdbg(hsotg->dev, "DWC OTG HCD QH - Type = %s\n", type); + +	if (qh->ep_type == USB_ENDPOINT_XFER_INT) { +		dev_vdbg(hsotg->dev, "DWC OTG HCD QH - usecs = %d\n", +			 qh->usecs); +		dev_vdbg(hsotg->dev, "DWC OTG HCD QH - interval = %d\n", +			 qh->interval); +	} +} + +/** + * dwc2_hcd_qh_create() - Allocates and initializes a QH + * + * @hsotg:        The HCD state structure for the DWC OTG controller + * @urb:          Holds the information about the device/endpoint needed + *                to initialize the QH + * @atomic_alloc: Flag to do atomic allocation if needed + * + * Return: Pointer to the newly allocated QH, or NULL on error + */ +static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg, +					  struct dwc2_hcd_urb *urb, +					  gfp_t mem_flags) +{ +	struct dwc2_qh *qh; + +	if (!urb->priv) +		return NULL; + +	/* Allocate memory */ +	qh = kzalloc(sizeof(*qh), mem_flags); +	if (!qh) +		return NULL; + +	dwc2_qh_init(hsotg, qh, urb); + +	if (hsotg->core_params->dma_desc_enable > 0 && +	    dwc2_hcd_qh_init_ddma(hsotg, qh, mem_flags) < 0) { +		dwc2_hcd_qh_free(hsotg, qh); +		return NULL; +	} + +	return qh; +} + +/** + * dwc2_hcd_qh_free() - Frees the QH + * + * @hsotg: HCD instance + * @qh:    The QH to free + * + * QH should already be removed from the list. QTD list should already be empty + * if called from URB Dequeue. + * + * Must NOT be called with interrupt disabled or spinlock held + */ +void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ +	u32 buf_size; + +	if (hsotg->core_params->dma_desc_enable > 0) { +		dwc2_hcd_qh_free_ddma(hsotg, qh); +	} else if (qh->dw_align_buf) { +		if (qh->ep_type == USB_ENDPOINT_XFER_ISOC) +			buf_size = 4096; +		else +			buf_size = hsotg->core_params->max_transfer_size; +		dma_free_coherent(hsotg->dev, buf_size, qh->dw_align_buf, +				  qh->dw_align_buf_dma); +	} + +	kfree(qh); +} + +/** + * dwc2_periodic_channel_available() - Checks that a channel is available for a + * periodic transfer + * + * @hsotg: The HCD state structure for the DWC OTG controller + * + * Return: 0 if successful, negative error code otherwise + */ +static int dwc2_periodic_channel_available(struct dwc2_hsotg *hsotg) +{ +	/* +	 * Currently assuming that there is a dedicated host channel for +	 * each periodic transaction plus at least one host channel for +	 * non-periodic transactions +	 */ +	int status; +	int num_channels; + +	num_channels = hsotg->core_params->host_channels; +	if (hsotg->periodic_channels + hsotg->non_periodic_channels < +								num_channels +	    && hsotg->periodic_channels < num_channels - 1) { +		status = 0; +	} else { +		dev_dbg(hsotg->dev, +			"%s: Total channels: %d, Periodic: %d, " +			"Non-periodic: %d\n", __func__, num_channels, +			hsotg->periodic_channels, hsotg->non_periodic_channels); +		status = -ENOSPC; +	} + +	return status; +} + +/** + * dwc2_check_periodic_bandwidth() - Checks that there is sufficient bandwidth + * for the specified QH in the periodic schedule + * + * @hsotg: The HCD state structure for the DWC OTG controller + * @qh:    QH containing periodic bandwidth required + * + * Return: 0 if successful, negative error code otherwise + * + * For simplicity, this calculation assumes that all the transfers in the + * periodic schedule may occur in the same (micro)frame + */ +static int dwc2_check_periodic_bandwidth(struct dwc2_hsotg *hsotg, +					 struct dwc2_qh *qh) +{ +	int status; +	s16 max_claimed_usecs; + +	status = 0; + +	if (qh->dev_speed == USB_SPEED_HIGH || qh->do_split) { +		/* +		 * High speed mode +		 * Max periodic usecs is 80% x 125 usec = 100 usec +		 */ +		max_claimed_usecs = 100 - qh->usecs; +	} else { +		/* +		 * Full speed mode +		 * Max periodic usecs is 90% x 1000 usec = 900 usec +		 */ +		max_claimed_usecs = 900 - qh->usecs; +	} + +	if (hsotg->periodic_usecs > max_claimed_usecs) { +		dev_err(hsotg->dev, +			"%s: already claimed usecs %d, required usecs %d\n", +			__func__, hsotg->periodic_usecs, qh->usecs); +		status = -ENOSPC; +	} + +	return status; +} + +/** + * Microframe scheduler + * track the total use in hsotg->frame_usecs + * keep each qh use in qh->frame_usecs + * when surrendering the qh then donate the time back + */ +static const unsigned short max_uframe_usecs[] = { +	100, 100, 100, 100, 100, 100, 30, 0 +}; + +void dwc2_hcd_init_usecs(struct dwc2_hsotg *hsotg) +{ +	int i; + +	for (i = 0; i < 8; i++) +		hsotg->frame_usecs[i] = max_uframe_usecs[i]; +} + +static int dwc2_find_single_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ +	unsigned short utime = qh->usecs; +	int i; + +	for (i = 0; i < 8; i++) { +		/* At the start hsotg->frame_usecs[i] = max_uframe_usecs[i] */ +		if (utime <= hsotg->frame_usecs[i]) { +			hsotg->frame_usecs[i] -= utime; +			qh->frame_usecs[i] += utime; +			return i; +		} +	} +	return -ENOSPC; +} + +/* + * use this for FS apps that can span multiple uframes + */ +static int dwc2_find_multi_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ +	unsigned short utime = qh->usecs; +	unsigned short xtime; +	int t_left; +	int i; +	int j; +	int k; + +	for (i = 0; i < 8; i++) { +		if (hsotg->frame_usecs[i] <= 0) +			continue; + +		/* +		 * we need n consecutive slots so use j as a start slot +		 * j plus j+1 must be enough time (for now) +		 */ +		xtime = hsotg->frame_usecs[i]; +		for (j = i + 1; j < 8; j++) { +			/* +			 * if we add this frame remaining time to xtime we may +			 * be OK, if not we need to test j for a complete frame +			 */ +			if (xtime + hsotg->frame_usecs[j] < utime) { +				if (hsotg->frame_usecs[j] < +							max_uframe_usecs[j]) +					continue; +			} +			if (xtime >= utime) { +				t_left = utime; +				for (k = i; k < 8; k++) { +					t_left -= hsotg->frame_usecs[k]; +					if (t_left <= 0) { +						qh->frame_usecs[k] += +							hsotg->frame_usecs[k] +								+ t_left; +						hsotg->frame_usecs[k] = -t_left; +						return i; +					} else { +						qh->frame_usecs[k] += +							hsotg->frame_usecs[k]; +						hsotg->frame_usecs[k] = 0; +					} +				} +			} +			/* add the frame time to x time */ +			xtime += hsotg->frame_usecs[j]; +			/* we must have a fully available next frame or break */ +			if (xtime < utime && +			   hsotg->frame_usecs[j] == max_uframe_usecs[j]) +				continue; +		} +	} +	return -ENOSPC; +} + +static int dwc2_find_uframe(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ +	int ret; + +	if (qh->dev_speed == USB_SPEED_HIGH) { +		/* if this is a hs transaction we need a full frame */ +		ret = dwc2_find_single_uframe(hsotg, qh); +	} else { +		/* +		 * if this is a fs transaction we may need a sequence +		 * of frames +		 */ +		ret = dwc2_find_multi_uframe(hsotg, qh); +	} +	return ret; +} + +/** + * dwc2_check_max_xfer_size() - Checks that the max transfer size allowed in a + * host channel is large enough to handle the maximum data transfer in a single + * (micro)frame for a periodic transfer + * + * @hsotg: The HCD state structure for the DWC OTG controller + * @qh:    QH for a periodic endpoint + * + * Return: 0 if successful, negative error code otherwise + */ +static int dwc2_check_max_xfer_size(struct dwc2_hsotg *hsotg, +				    struct dwc2_qh *qh) +{ +	u32 max_xfer_size; +	u32 max_channel_xfer_size; +	int status = 0; + +	max_xfer_size = dwc2_max_packet(qh->maxp) * dwc2_hb_mult(qh->maxp); +	max_channel_xfer_size = hsotg->core_params->max_transfer_size; + +	if (max_xfer_size > max_channel_xfer_size) { +		dev_err(hsotg->dev, +			"%s: Periodic xfer length %d > max xfer length for channel %d\n", +			__func__, max_xfer_size, max_channel_xfer_size); +		status = -ENOSPC; +	} + +	return status; +} + +/** + * dwc2_schedule_periodic() - Schedules an interrupt or isochronous transfer in + * the periodic schedule + * + * @hsotg: The HCD state structure for the DWC OTG controller + * @qh:    QH for the periodic transfer. The QH should already contain the + *         scheduling information. + * + * Return: 0 if successful, negative error code otherwise + */ +static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ +	int status; + +	if (hsotg->core_params->uframe_sched > 0) { +		int frame = -1; + +		status = dwc2_find_uframe(hsotg, qh); +		if (status == 0) +			frame = 7; +		else if (status > 0) +			frame = status - 1; + +		/* Set the new frame up */ +		if (frame >= 0) { +			qh->sched_frame &= ~0x7; +			qh->sched_frame |= (frame & 7); +		} + +		if (status > 0) +			status = 0; +	} else { +		status = dwc2_periodic_channel_available(hsotg); +		if (status) { +			dev_info(hsotg->dev, +				 "%s: No host channel available for periodic transfer\n", +				 __func__); +			return status; +		} + +		status = dwc2_check_periodic_bandwidth(hsotg, qh); +	} + +	if (status) { +		dev_dbg(hsotg->dev, +			"%s: Insufficient periodic bandwidth for periodic transfer\n", +			__func__); +		return status; +	} + +	status = dwc2_check_max_xfer_size(hsotg, qh); +	if (status) { +		dev_dbg(hsotg->dev, +			"%s: Channel max transfer size too small for periodic transfer\n", +			__func__); +		return status; +	} + +	if (hsotg->core_params->dma_desc_enable > 0) +		/* Don't rely on SOF and start in ready schedule */ +		list_add_tail(&qh->qh_list_entry, &hsotg->periodic_sched_ready); +	else +		/* Always start in inactive schedule */ +		list_add_tail(&qh->qh_list_entry, +			      &hsotg->periodic_sched_inactive); + +	if (hsotg->core_params->uframe_sched <= 0) +		/* Reserve periodic channel */ +		hsotg->periodic_channels++; + +	/* Update claimed usecs per (micro)frame */ +	hsotg->periodic_usecs += qh->usecs; + +	return status; +} + +/** + * dwc2_deschedule_periodic() - Removes an interrupt or isochronous transfer + * from the periodic schedule + * + * @hsotg: The HCD state structure for the DWC OTG controller + * @qh:	   QH for the periodic transfer + */ +static void dwc2_deschedule_periodic(struct dwc2_hsotg *hsotg, +				     struct dwc2_qh *qh) +{ +	int i; + +	list_del_init(&qh->qh_list_entry); + +	/* Update claimed usecs per (micro)frame */ +	hsotg->periodic_usecs -= qh->usecs; + +	if (hsotg->core_params->uframe_sched > 0) { +		for (i = 0; i < 8; i++) { +			hsotg->frame_usecs[i] += qh->frame_usecs[i]; +			qh->frame_usecs[i] = 0; +		} +	} else { +		/* Release periodic channel reservation */ +		hsotg->periodic_channels--; +	} +} + +/** + * dwc2_hcd_qh_add() - Adds a QH to either the non periodic or periodic + * schedule if it is not already in the schedule. If the QH is already in + * the schedule, no action is taken. + * + * @hsotg: The HCD state structure for the DWC OTG controller + * @qh:    The QH to add + * + * Return: 0 if successful, negative error code otherwise + */ +int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ +	int status; +	u32 intr_mask; + +	if (dbg_qh(qh)) +		dev_vdbg(hsotg->dev, "%s()\n", __func__); + +	if (!list_empty(&qh->qh_list_entry)) +		/* QH already in a schedule */ +		return 0; + +	/* Add the new QH to the appropriate schedule */ +	if (dwc2_qh_is_non_per(qh)) { +		/* Always start in inactive schedule */ +		list_add_tail(&qh->qh_list_entry, +			      &hsotg->non_periodic_sched_inactive); +		return 0; +	} + +	status = dwc2_schedule_periodic(hsotg, qh); +	if (status) +		return status; +	if (!hsotg->periodic_qh_count) { +		intr_mask = readl(hsotg->regs + GINTMSK); +		intr_mask |= GINTSTS_SOF; +		writel(intr_mask, hsotg->regs + GINTMSK); +	} +	hsotg->periodic_qh_count++; + +	return 0; +} + +/** + * dwc2_hcd_qh_unlink() - Removes a QH from either the non-periodic or periodic + * schedule. Memory is not freed. + * + * @hsotg: The HCD state structure + * @qh:    QH to remove from schedule + */ +void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) +{ +	u32 intr_mask; + +	dev_vdbg(hsotg->dev, "%s()\n", __func__); + +	if (list_empty(&qh->qh_list_entry)) +		/* QH is not in a schedule */ +		return; + +	if (dwc2_qh_is_non_per(qh)) { +		if (hsotg->non_periodic_qh_ptr == &qh->qh_list_entry) +			hsotg->non_periodic_qh_ptr = +					hsotg->non_periodic_qh_ptr->next; +		list_del_init(&qh->qh_list_entry); +		return; +	} + +	dwc2_deschedule_periodic(hsotg, qh); +	hsotg->periodic_qh_count--; +	if (!hsotg->periodic_qh_count) { +		intr_mask = readl(hsotg->regs + GINTMSK); +		intr_mask &= ~GINTSTS_SOF; +		writel(intr_mask, hsotg->regs + GINTMSK); +	} +} + +/* + * Schedule the next continuing periodic split transfer + */ +static void dwc2_sched_periodic_split(struct dwc2_hsotg *hsotg, +				      struct dwc2_qh *qh, u16 frame_number, +				      int sched_next_periodic_split) +{ +	u16 incr; + +	if (sched_next_periodic_split) { +		qh->sched_frame = frame_number; +		incr = dwc2_frame_num_inc(qh->start_split_frame, 1); +		if (dwc2_frame_num_le(frame_number, incr)) { +			/* +			 * Allow one frame to elapse after start split +			 * microframe before scheduling complete split, but +			 * DON'T if we are doing the next start split in the +			 * same frame for an ISOC out +			 */ +			if (qh->ep_type != USB_ENDPOINT_XFER_ISOC || +			    qh->ep_is_in != 0) { +				qh->sched_frame = +					dwc2_frame_num_inc(qh->sched_frame, 1); +			} +		} +	} else { +		qh->sched_frame = dwc2_frame_num_inc(qh->start_split_frame, +						     qh->interval); +		if (dwc2_frame_num_le(qh->sched_frame, frame_number)) +			qh->sched_frame = frame_number; +		qh->sched_frame |= 0x7; +		qh->start_split_frame = qh->sched_frame; +	} +} + +/* + * Deactivates a QH. For non-periodic QHs, removes the QH from the active + * non-periodic schedule. The QH is added to the inactive non-periodic + * schedule if any QTDs are still attached to the QH. + * + * For periodic QHs, the QH is removed from the periodic queued schedule. If + * there are any QTDs still attached to the QH, the QH is added to either the + * periodic inactive schedule or the periodic ready schedule and its next + * scheduled frame is calculated. The QH is placed in the ready schedule if + * the scheduled frame has been reached already. Otherwise it's placed in the + * inactive schedule. If there are no QTDs attached to the QH, the QH is + * completely removed from the periodic schedule. + */ +void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, +			    int sched_next_periodic_split) +{ +	u16 frame_number; + +	if (dbg_qh(qh)) +		dev_vdbg(hsotg->dev, "%s()\n", __func__); + +	if (dwc2_qh_is_non_per(qh)) { +		dwc2_hcd_qh_unlink(hsotg, qh); +		if (!list_empty(&qh->qtd_list)) +			/* Add back to inactive non-periodic schedule */ +			dwc2_hcd_qh_add(hsotg, qh); +		return; +	} + +	frame_number = dwc2_hcd_get_frame_number(hsotg); + +	if (qh->do_split) { +		dwc2_sched_periodic_split(hsotg, qh, frame_number, +					  sched_next_periodic_split); +	} else { +		qh->sched_frame = dwc2_frame_num_inc(qh->sched_frame, +						     qh->interval); +		if (dwc2_frame_num_le(qh->sched_frame, frame_number)) +			qh->sched_frame = frame_number; +	} + +	if (list_empty(&qh->qtd_list)) { +		dwc2_hcd_qh_unlink(hsotg, qh); +		return; +	} +	/* +	 * Remove from periodic_sched_queued and move to +	 * appropriate queue +	 */ +	if ((hsotg->core_params->uframe_sched > 0 && +	     dwc2_frame_num_le(qh->sched_frame, frame_number)) || +	    (hsotg->core_params->uframe_sched <= 0 && +	     qh->sched_frame == frame_number)) +		list_move(&qh->qh_list_entry, &hsotg->periodic_sched_ready); +	else +		list_move(&qh->qh_list_entry, &hsotg->periodic_sched_inactive); +} + +/** + * dwc2_hcd_qtd_init() - Initializes a QTD structure + * + * @qtd: The QTD to initialize + * @urb: The associated URB + */ +void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb) +{ +	qtd->urb = urb; +	if (dwc2_hcd_get_pipe_type(&urb->pipe_info) == +			USB_ENDPOINT_XFER_CONTROL) { +		/* +		 * The only time the QTD data toggle is used is on the data +		 * phase of control transfers. This phase always starts with +		 * DATA1. +		 */ +		qtd->data_toggle = DWC2_HC_PID_DATA1; +		qtd->control_phase = DWC2_CONTROL_SETUP; +	} + +	/* Start split */ +	qtd->complete_split = 0; +	qtd->isoc_split_pos = DWC2_HCSPLT_XACTPOS_ALL; +	qtd->isoc_split_offset = 0; +	qtd->in_process = 0; + +	/* Store the qtd ptr in the urb to reference the QTD */ +	urb->qtd = qtd; +} + +/** + * dwc2_hcd_qtd_add() - Adds a QTD to the QTD-list of a QH + * + * @hsotg:        The DWC HCD structure + * @qtd:          The QTD to add + * @qh:           Out parameter to return queue head + * @atomic_alloc: Flag to do atomic alloc if needed + * + * Return: 0 if successful, negative error code otherwise + * + * Finds the correct QH to place the QTD into. If it does not find a QH, it + * will create a new QH. If the QH to which the QTD is added is not currently + * scheduled, it is placed into the proper schedule based on its EP type. + */ +int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, +		     struct dwc2_qh **qh, gfp_t mem_flags) +{ +	struct dwc2_hcd_urb *urb = qtd->urb; +	unsigned long flags; +	int allocated = 0; +	int retval; + +	/* +	 * Get the QH which holds the QTD-list to insert to. Create QH if it +	 * doesn't exist. +	 */ +	if (*qh == NULL) { +		*qh = dwc2_hcd_qh_create(hsotg, urb, mem_flags); +		if (*qh == NULL) +			return -ENOMEM; +		allocated = 1; +	} + +	spin_lock_irqsave(&hsotg->lock, flags); + +	retval = dwc2_hcd_qh_add(hsotg, *qh); +	if (retval) +		goto fail; + +	qtd->qh = *qh; +	list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list); +	spin_unlock_irqrestore(&hsotg->lock, flags); + +	return 0; + +fail: +	if (allocated) { +		struct dwc2_qtd *qtd2, *qtd2_tmp; +		struct dwc2_qh *qh_tmp = *qh; + +		*qh = NULL; +		dwc2_hcd_qh_unlink(hsotg, qh_tmp); + +		/* Free each QTD in the QH's QTD list */ +		list_for_each_entry_safe(qtd2, qtd2_tmp, &qh_tmp->qtd_list, +					 qtd_list_entry) +			dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp); + +		spin_unlock_irqrestore(&hsotg->lock, flags); +		dwc2_hcd_qh_free(hsotg, qh_tmp); +	} else { +		spin_unlock_irqrestore(&hsotg->lock, flags); +	} + +	return retval; +} diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h new file mode 100644 index 00000000000..51248b93549 --- /dev/null +++ b/drivers/usb/dwc2/hw.h @@ -0,0 +1,811 @@ +/* + * hw.h - DesignWare HS OTG Controller hardware definitions + * + * Copyright 2004-2013 Synopsys, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + *    to endorse or promote products derived from this software without + *    specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __DWC2_HW_H__ +#define __DWC2_HW_H__ + +#define HSOTG_REG(x)	(x) + +#define GOTGCTL				HSOTG_REG(0x000) +#define GOTGCTL_CHIRPEN			(1 << 27) +#define GOTGCTL_MULT_VALID_BC_MASK	(0x1f << 22) +#define GOTGCTL_MULT_VALID_BC_SHIFT	22 +#define GOTGCTL_OTGVER			(1 << 20) +#define GOTGCTL_BSESVLD			(1 << 19) +#define GOTGCTL_ASESVLD			(1 << 18) +#define GOTGCTL_DBNC_SHORT		(1 << 17) +#define GOTGCTL_CONID_B			(1 << 16) +#define GOTGCTL_DEVHNPEN		(1 << 11) +#define GOTGCTL_HSTSETHNPEN		(1 << 10) +#define GOTGCTL_HNPREQ			(1 << 9) +#define GOTGCTL_HSTNEGSCS		(1 << 8) +#define GOTGCTL_SESREQ			(1 << 1) +#define GOTGCTL_SESREQSCS		(1 << 0) + +#define GOTGINT				HSOTG_REG(0x004) +#define GOTGINT_DBNCE_DONE		(1 << 19) +#define GOTGINT_A_DEV_TOUT_CHG		(1 << 18) +#define GOTGINT_HST_NEG_DET		(1 << 17) +#define GOTGINT_HST_NEG_SUC_STS_CHNG	(1 << 9) +#define GOTGINT_SES_REQ_SUC_STS_CHNG	(1 << 8) +#define GOTGINT_SES_END_DET		(1 << 2) + +#define GAHBCFG				HSOTG_REG(0x008) +#define GAHBCFG_AHB_SINGLE		(1 << 23) +#define GAHBCFG_NOTI_ALL_DMA_WRIT	(1 << 22) +#define GAHBCFG_REM_MEM_SUPP		(1 << 21) +#define GAHBCFG_P_TXF_EMP_LVL		(1 << 8) +#define GAHBCFG_NP_TXF_EMP_LVL		(1 << 7) +#define GAHBCFG_DMA_EN			(1 << 5) +#define GAHBCFG_HBSTLEN_MASK		(0xf << 1) +#define GAHBCFG_HBSTLEN_SHIFT		1 +#define GAHBCFG_HBSTLEN_SINGLE		0 +#define GAHBCFG_HBSTLEN_INCR		1 +#define GAHBCFG_HBSTLEN_INCR4		3 +#define GAHBCFG_HBSTLEN_INCR8		5 +#define GAHBCFG_HBSTLEN_INCR16		7 +#define GAHBCFG_GLBL_INTR_EN		(1 << 0) +#define GAHBCFG_CTRL_MASK		(GAHBCFG_P_TXF_EMP_LVL | \ +					 GAHBCFG_NP_TXF_EMP_LVL | \ +					 GAHBCFG_DMA_EN | \ +					 GAHBCFG_GLBL_INTR_EN) + +#define GUSBCFG				HSOTG_REG(0x00C) +#define GUSBCFG_FORCEDEVMODE		(1 << 30) +#define GUSBCFG_FORCEHOSTMODE		(1 << 29) +#define GUSBCFG_TXENDDELAY		(1 << 28) +#define GUSBCFG_ICTRAFFICPULLREMOVE	(1 << 27) +#define GUSBCFG_ICUSBCAP		(1 << 26) +#define GUSBCFG_ULPI_INT_PROT_DIS	(1 << 25) +#define GUSBCFG_INDICATORPASSTHROUGH	(1 << 24) +#define GUSBCFG_INDICATORCOMPLEMENT	(1 << 23) +#define GUSBCFG_TERMSELDLPULSE		(1 << 22) +#define GUSBCFG_ULPI_INT_VBUS_IND	(1 << 21) +#define GUSBCFG_ULPI_EXT_VBUS_DRV	(1 << 20) +#define GUSBCFG_ULPI_CLK_SUSP_M		(1 << 19) +#define GUSBCFG_ULPI_AUTO_RES		(1 << 18) +#define GUSBCFG_ULPI_FS_LS		(1 << 17) +#define GUSBCFG_OTG_UTMI_FS_SEL		(1 << 16) +#define GUSBCFG_PHY_LP_CLK_SEL		(1 << 15) +#define GUSBCFG_USBTRDTIM_MASK		(0xf << 10) +#define GUSBCFG_USBTRDTIM_SHIFT		10 +#define GUSBCFG_HNPCAP			(1 << 9) +#define GUSBCFG_SRPCAP			(1 << 8) +#define GUSBCFG_DDRSEL			(1 << 7) +#define GUSBCFG_PHYSEL			(1 << 6) +#define GUSBCFG_FSINTF			(1 << 5) +#define GUSBCFG_ULPI_UTMI_SEL		(1 << 4) +#define GUSBCFG_PHYIF16			(1 << 3) +#define GUSBCFG_PHYIF8			(0 << 3) +#define GUSBCFG_TOUTCAL_MASK		(0x7 << 0) +#define GUSBCFG_TOUTCAL_SHIFT		0 +#define GUSBCFG_TOUTCAL_LIMIT		0x7 +#define GUSBCFG_TOUTCAL(_x)		((_x) << 0) + +#define GRSTCTL				HSOTG_REG(0x010) +#define GRSTCTL_AHBIDLE			(1 << 31) +#define GRSTCTL_DMAREQ			(1 << 30) +#define GRSTCTL_TXFNUM_MASK		(0x1f << 6) +#define GRSTCTL_TXFNUM_SHIFT		6 +#define GRSTCTL_TXFNUM_LIMIT		0x1f +#define GRSTCTL_TXFNUM(_x)		((_x) << 6) +#define GRSTCTL_TXFFLSH			(1 << 5) +#define GRSTCTL_RXFFLSH			(1 << 4) +#define GRSTCTL_IN_TKNQ_FLSH		(1 << 3) +#define GRSTCTL_FRMCNTRRST		(1 << 2) +#define GRSTCTL_HSFTRST			(1 << 1) +#define GRSTCTL_CSFTRST			(1 << 0) + +#define GINTSTS				HSOTG_REG(0x014) +#define GINTMSK				HSOTG_REG(0x018) +#define GINTSTS_WKUPINT			(1 << 31) +#define GINTSTS_SESSREQINT		(1 << 30) +#define GINTSTS_DISCONNINT		(1 << 29) +#define GINTSTS_CONIDSTSCHNG		(1 << 28) +#define GINTSTS_LPMTRANRCVD		(1 << 27) +#define GINTSTS_PTXFEMP			(1 << 26) +#define GINTSTS_HCHINT			(1 << 25) +#define GINTSTS_PRTINT			(1 << 24) +#define GINTSTS_RESETDET		(1 << 23) +#define GINTSTS_FET_SUSP		(1 << 22) +#define GINTSTS_INCOMPL_IP		(1 << 21) +#define GINTSTS_INCOMPL_SOIN		(1 << 20) +#define GINTSTS_OEPINT			(1 << 19) +#define GINTSTS_IEPINT			(1 << 18) +#define GINTSTS_EPMIS			(1 << 17) +#define GINTSTS_RESTOREDONE		(1 << 16) +#define GINTSTS_EOPF			(1 << 15) +#define GINTSTS_ISOUTDROP		(1 << 14) +#define GINTSTS_ENUMDONE		(1 << 13) +#define GINTSTS_USBRST			(1 << 12) +#define GINTSTS_USBSUSP			(1 << 11) +#define GINTSTS_ERLYSUSP		(1 << 10) +#define GINTSTS_I2CINT			(1 << 9) +#define GINTSTS_ULPI_CK_INT		(1 << 8) +#define GINTSTS_GOUTNAKEFF		(1 << 7) +#define GINTSTS_GINNAKEFF		(1 << 6) +#define GINTSTS_NPTXFEMP		(1 << 5) +#define GINTSTS_RXFLVL			(1 << 4) +#define GINTSTS_SOF			(1 << 3) +#define GINTSTS_OTGINT			(1 << 2) +#define GINTSTS_MODEMIS			(1 << 1) +#define GINTSTS_CURMODE_HOST		(1 << 0) + +#define GRXSTSR				HSOTG_REG(0x01C) +#define GRXSTSP				HSOTG_REG(0x020) +#define GRXSTS_FN_MASK			(0x7f << 25) +#define GRXSTS_FN_SHIFT			25 +#define GRXSTS_PKTSTS_MASK		(0xf << 17) +#define GRXSTS_PKTSTS_SHIFT		17 +#define GRXSTS_PKTSTS_GLOBALOUTNAK	1 +#define GRXSTS_PKTSTS_OUTRX		2 +#define GRXSTS_PKTSTS_HCHIN		2 +#define GRXSTS_PKTSTS_OUTDONE		3 +#define GRXSTS_PKTSTS_HCHIN_XFER_COMP	3 +#define GRXSTS_PKTSTS_SETUPDONE		4 +#define GRXSTS_PKTSTS_DATATOGGLEERR	5 +#define GRXSTS_PKTSTS_SETUPRX		6 +#define GRXSTS_PKTSTS_HCHHALTED		7 +#define GRXSTS_HCHNUM_MASK		(0xf << 0) +#define GRXSTS_HCHNUM_SHIFT		0 +#define GRXSTS_DPID_MASK		(0x3 << 15) +#define GRXSTS_DPID_SHIFT		15 +#define GRXSTS_BYTECNT_MASK		(0x7ff << 4) +#define GRXSTS_BYTECNT_SHIFT		4 +#define GRXSTS_EPNUM_MASK		(0xf << 0) +#define GRXSTS_EPNUM_SHIFT		0 + +#define GRXFSIZ				HSOTG_REG(0x024) +#define GRXFSIZ_DEPTH_MASK		(0xffff << 0) +#define GRXFSIZ_DEPTH_SHIFT		0 + +#define GNPTXFSIZ			HSOTG_REG(0x028) +/* Use FIFOSIZE_* constants to access this register */ + +#define GNPTXSTS			HSOTG_REG(0x02C) +#define GNPTXSTS_NP_TXQ_TOP_MASK		(0x7f << 24) +#define GNPTXSTS_NP_TXQ_TOP_SHIFT		24 +#define GNPTXSTS_NP_TXQ_SPC_AVAIL_MASK		(0xff << 16) +#define GNPTXSTS_NP_TXQ_SPC_AVAIL_SHIFT		16 +#define GNPTXSTS_NP_TXQ_SPC_AVAIL_GET(_v)	(((_v) >> 16) & 0xff) +#define GNPTXSTS_NP_TXF_SPC_AVAIL_MASK		(0xffff << 0) +#define GNPTXSTS_NP_TXF_SPC_AVAIL_SHIFT		0 +#define GNPTXSTS_NP_TXF_SPC_AVAIL_GET(_v)	(((_v) >> 0) & 0xffff) + +#define GI2CCTL				HSOTG_REG(0x0030) +#define GI2CCTL_BSYDNE			(1 << 31) +#define GI2CCTL_RW			(1 << 30) +#define GI2CCTL_I2CDATSE0		(1 << 28) +#define GI2CCTL_I2CDEVADDR_MASK		(0x3 << 26) +#define GI2CCTL_I2CDEVADDR_SHIFT	26 +#define GI2CCTL_I2CSUSPCTL		(1 << 25) +#define GI2CCTL_ACK			(1 << 24) +#define GI2CCTL_I2CEN			(1 << 23) +#define GI2CCTL_ADDR_MASK		(0x7f << 16) +#define GI2CCTL_ADDR_SHIFT		16 +#define GI2CCTL_REGADDR_MASK		(0xff << 8) +#define GI2CCTL_REGADDR_SHIFT		8 +#define GI2CCTL_RWDATA_MASK		(0xff << 0) +#define GI2CCTL_RWDATA_SHIFT		0 + +#define GPVNDCTL			HSOTG_REG(0x0034) +#define GGPIO				HSOTG_REG(0x0038) +#define GUID				HSOTG_REG(0x003c) +#define GSNPSID				HSOTG_REG(0x0040) +#define GHWCFG1				HSOTG_REG(0x0044) + +#define GHWCFG2				HSOTG_REG(0x0048) +#define GHWCFG2_OTG_ENABLE_IC_USB		(1 << 31) +#define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK		(0x1f << 26) +#define GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT		26 +#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK	(0x3 << 24) +#define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT	24 +#define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK	(0x3 << 22) +#define GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT	22 +#define GHWCFG2_MULTI_PROC_INT			(1 << 20) +#define GHWCFG2_DYNAMIC_FIFO			(1 << 19) +#define GHWCFG2_PERIO_EP_SUPPORTED		(1 << 18) +#define GHWCFG2_NUM_HOST_CHAN_MASK		(0xf << 14) +#define GHWCFG2_NUM_HOST_CHAN_SHIFT		14 +#define GHWCFG2_NUM_DEV_EP_MASK			(0xf << 10) +#define GHWCFG2_NUM_DEV_EP_SHIFT		10 +#define GHWCFG2_FS_PHY_TYPE_MASK		(0x3 << 8) +#define GHWCFG2_FS_PHY_TYPE_SHIFT		8 +#define GHWCFG2_FS_PHY_TYPE_NOT_SUPPORTED	0 +#define GHWCFG2_FS_PHY_TYPE_DEDICATED		1 +#define GHWCFG2_FS_PHY_TYPE_SHARED_UTMI		2 +#define GHWCFG2_FS_PHY_TYPE_SHARED_ULPI		3 +#define GHWCFG2_HS_PHY_TYPE_MASK		(0x3 << 6) +#define GHWCFG2_HS_PHY_TYPE_SHIFT		6 +#define GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED	0 +#define GHWCFG2_HS_PHY_TYPE_UTMI		1 +#define GHWCFG2_HS_PHY_TYPE_ULPI		2 +#define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI		3 +#define GHWCFG2_POINT2POINT			(1 << 5) +#define GHWCFG2_ARCHITECTURE_MASK		(0x3 << 3) +#define GHWCFG2_ARCHITECTURE_SHIFT		3 +#define GHWCFG2_SLAVE_ONLY_ARCH			0 +#define GHWCFG2_EXT_DMA_ARCH			1 +#define GHWCFG2_INT_DMA_ARCH			2 +#define GHWCFG2_OP_MODE_MASK			(0x7 << 0) +#define GHWCFG2_OP_MODE_SHIFT			0 +#define GHWCFG2_OP_MODE_HNP_SRP_CAPABLE		0 +#define GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE	1 +#define GHWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE	2 +#define GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE	3 +#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE	4 +#define GHWCFG2_OP_MODE_SRP_CAPABLE_HOST	5 +#define GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST	6 +#define GHWCFG2_OP_MODE_UNDEFINED		7 + +#define GHWCFG3				HSOTG_REG(0x004c) +#define GHWCFG3_DFIFO_DEPTH_MASK		(0xffff << 16) +#define GHWCFG3_DFIFO_DEPTH_SHIFT		16 +#define GHWCFG3_OTG_LPM_EN			(1 << 15) +#define GHWCFG3_BC_SUPPORT			(1 << 14) +#define GHWCFG3_OTG_ENABLE_HSIC			(1 << 13) +#define GHWCFG3_ADP_SUPP			(1 << 12) +#define GHWCFG3_SYNCH_RESET_TYPE		(1 << 11) +#define GHWCFG3_OPTIONAL_FEATURES		(1 << 10) +#define GHWCFG3_VENDOR_CTRL_IF			(1 << 9) +#define GHWCFG3_I2C				(1 << 8) +#define GHWCFG3_OTG_FUNC			(1 << 7) +#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK	(0x7 << 4) +#define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT	4 +#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK	(0xf << 0) +#define GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT	0 + +#define GHWCFG4				HSOTG_REG(0x0050) +#define GHWCFG4_DESC_DMA_DYN			(1 << 31) +#define GHWCFG4_DESC_DMA			(1 << 30) +#define GHWCFG4_NUM_IN_EPS_MASK			(0xf << 26) +#define GHWCFG4_NUM_IN_EPS_SHIFT		26 +#define GHWCFG4_DED_FIFO_EN			(1 << 25) +#define GHWCFG4_SESSION_END_FILT_EN		(1 << 24) +#define GHWCFG4_B_VALID_FILT_EN			(1 << 23) +#define GHWCFG4_A_VALID_FILT_EN			(1 << 22) +#define GHWCFG4_VBUS_VALID_FILT_EN		(1 << 21) +#define GHWCFG4_IDDIG_FILT_EN			(1 << 20) +#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK	(0xf << 16) +#define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT	16 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK	(0x3 << 14) +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT	14 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8		0 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_16		1 +#define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16	2 +#define GHWCFG4_XHIBER				(1 << 7) +#define GHWCFG4_HIBER				(1 << 6) +#define GHWCFG4_MIN_AHB_FREQ			(1 << 5) +#define GHWCFG4_POWER_OPTIMIZ			(1 << 4) +#define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK	(0xf << 0) +#define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT	0 + +#define GLPMCFG				HSOTG_REG(0x0054) +#define GLPMCFG_INV_SEL_HSIC		(1 << 31) +#define GLPMCFG_HSIC_CONNECT		(1 << 30) +#define GLPMCFG_RETRY_COUNT_STS_MASK	(0x7 << 25) +#define GLPMCFG_RETRY_COUNT_STS_SHIFT	25 +#define GLPMCFG_SEND_LPM		(1 << 24) +#define GLPMCFG_RETRY_COUNT_MASK	(0x7 << 21) +#define GLPMCFG_RETRY_COUNT_SHIFT	21 +#define GLPMCFG_LPM_CHAN_INDEX_MASK	(0xf << 17) +#define GLPMCFG_LPM_CHAN_INDEX_SHIFT	17 +#define GLPMCFG_SLEEP_STATE_RESUMEOK	(1 << 16) +#define GLPMCFG_PRT_SLEEP_STS		(1 << 15) +#define GLPMCFG_LPM_RESP_MASK		(0x3 << 13) +#define GLPMCFG_LPM_RESP_SHIFT		13 +#define GLPMCFG_HIRD_THRES_MASK		(0x1f << 8) +#define GLPMCFG_HIRD_THRES_SHIFT	8 +#define GLPMCFG_HIRD_THRES_EN			(0x10 << 8) +#define GLPMCFG_EN_UTMI_SLEEP		(1 << 7) +#define GLPMCFG_REM_WKUP_EN		(1 << 6) +#define GLPMCFG_HIRD_MASK		(0xf << 2) +#define GLPMCFG_HIRD_SHIFT		2 +#define GLPMCFG_APPL_RESP		(1 << 1) +#define GLPMCFG_LPM_CAP_EN		(1 << 0) + +#define GPWRDN				HSOTG_REG(0x0058) +#define GPWRDN_MULT_VAL_ID_BC_MASK	(0x1f << 24) +#define GPWRDN_MULT_VAL_ID_BC_SHIFT	24 +#define GPWRDN_ADP_INT			(1 << 23) +#define GPWRDN_BSESSVLD			(1 << 22) +#define GPWRDN_IDSTS			(1 << 21) +#define GPWRDN_LINESTATE_MASK		(0x3 << 19) +#define GPWRDN_LINESTATE_SHIFT		19 +#define GPWRDN_STS_CHGINT_MSK		(1 << 18) +#define GPWRDN_STS_CHGINT		(1 << 17) +#define GPWRDN_SRP_DET_MSK		(1 << 16) +#define GPWRDN_SRP_DET			(1 << 15) +#define GPWRDN_CONNECT_DET_MSK		(1 << 14) +#define GPWRDN_CONNECT_DET		(1 << 13) +#define GPWRDN_DISCONN_DET_MSK		(1 << 12) +#define GPWRDN_DISCONN_DET		(1 << 11) +#define GPWRDN_RST_DET_MSK		(1 << 10) +#define GPWRDN_RST_DET			(1 << 9) +#define GPWRDN_LNSTSCHG_MSK		(1 << 8) +#define GPWRDN_LNSTSCHG			(1 << 7) +#define GPWRDN_DIS_VBUS			(1 << 6) +#define GPWRDN_PWRDNSWTCH		(1 << 5) +#define GPWRDN_PWRDNRSTN		(1 << 4) +#define GPWRDN_PWRDNCLMP		(1 << 3) +#define GPWRDN_RESTORE			(1 << 2) +#define GPWRDN_PMUACTV			(1 << 1) +#define GPWRDN_PMUINTSEL		(1 << 0) + +#define GDFIFOCFG			HSOTG_REG(0x005c) +#define GDFIFOCFG_EPINFOBASE_MASK	(0xffff << 16) +#define GDFIFOCFG_EPINFOBASE_SHIFT	16 +#define GDFIFOCFG_GDFIFOCFG_MASK	(0xffff << 0) +#define GDFIFOCFG_GDFIFOCFG_SHIFT	0 + +#define ADPCTL				HSOTG_REG(0x0060) +#define ADPCTL_AR_MASK			(0x3 << 27) +#define ADPCTL_AR_SHIFT			27 +#define ADPCTL_ADP_TMOUT_INT_MSK	(1 << 26) +#define ADPCTL_ADP_SNS_INT_MSK		(1 << 25) +#define ADPCTL_ADP_PRB_INT_MSK		(1 << 24) +#define ADPCTL_ADP_TMOUT_INT		(1 << 23) +#define ADPCTL_ADP_SNS_INT		(1 << 22) +#define ADPCTL_ADP_PRB_INT		(1 << 21) +#define ADPCTL_ADPENA			(1 << 20) +#define ADPCTL_ADPRES			(1 << 19) +#define ADPCTL_ENASNS			(1 << 18) +#define ADPCTL_ENAPRB			(1 << 17) +#define ADPCTL_RTIM_MASK		(0x7ff << 6) +#define ADPCTL_RTIM_SHIFT		6 +#define ADPCTL_PRB_PER_MASK		(0x3 << 4) +#define ADPCTL_PRB_PER_SHIFT		4 +#define ADPCTL_PRB_DELTA_MASK		(0x3 << 2) +#define ADPCTL_PRB_DELTA_SHIFT		2 +#define ADPCTL_PRB_DSCHRG_MASK		(0x3 << 0) +#define ADPCTL_PRB_DSCHRG_SHIFT		0 + +#define HPTXFSIZ			HSOTG_REG(0x100) +/* Use FIFOSIZE_* constants to access this register */ + +#define DPTXFSIZN(_a)			HSOTG_REG(0x104 + (((_a) - 1) * 4)) +/* Use FIFOSIZE_* constants to access this register */ + +/* These apply to the GNPTXFSIZ, HPTXFSIZ and DPTXFSIZN registers */ +#define FIFOSIZE_DEPTH_MASK		(0xffff << 16) +#define FIFOSIZE_DEPTH_SHIFT		16 +#define FIFOSIZE_STARTADDR_MASK		(0xffff << 0) +#define FIFOSIZE_STARTADDR_SHIFT	0 +#define FIFOSIZE_DEPTH_GET(_x)		(((_x) >> 16) & 0xffff) + +/* Device mode registers */ + +#define DCFG				HSOTG_REG(0x800) +#define DCFG_EPMISCNT_MASK		(0x1f << 18) +#define DCFG_EPMISCNT_SHIFT		18 +#define DCFG_EPMISCNT_LIMIT		0x1f +#define DCFG_EPMISCNT(_x)		((_x) << 18) +#define DCFG_PERFRINT_MASK		(0x3 << 11) +#define DCFG_PERFRINT_SHIFT		11 +#define DCFG_PERFRINT_LIMIT		0x3 +#define DCFG_PERFRINT(_x)		((_x) << 11) +#define DCFG_DEVADDR_MASK		(0x7f << 4) +#define DCFG_DEVADDR_SHIFT		4 +#define DCFG_DEVADDR_LIMIT		0x7f +#define DCFG_DEVADDR(_x)		((_x) << 4) +#define DCFG_NZ_STS_OUT_HSHK		(1 << 2) +#define DCFG_DEVSPD_MASK		(0x3 << 0) +#define DCFG_DEVSPD_SHIFT		0 +#define DCFG_DEVSPD_HS			0 +#define DCFG_DEVSPD_FS			1 +#define DCFG_DEVSPD_LS			2 +#define DCFG_DEVSPD_FS48		3 + +#define DCTL				HSOTG_REG(0x804) +#define DCTL_PWRONPRGDONE		(1 << 11) +#define DCTL_CGOUTNAK			(1 << 10) +#define DCTL_SGOUTNAK			(1 << 9) +#define DCTL_CGNPINNAK			(1 << 8) +#define DCTL_SGNPINNAK			(1 << 7) +#define DCTL_TSTCTL_MASK		(0x7 << 4) +#define DCTL_TSTCTL_SHIFT		4 +#define DCTL_GOUTNAKSTS			(1 << 3) +#define DCTL_GNPINNAKSTS		(1 << 2) +#define DCTL_SFTDISCON			(1 << 1) +#define DCTL_RMTWKUPSIG			(1 << 0) + +#define DSTS				HSOTG_REG(0x808) +#define DSTS_SOFFN_MASK			(0x3fff << 8) +#define DSTS_SOFFN_SHIFT		8 +#define DSTS_SOFFN_LIMIT		0x3fff +#define DSTS_SOFFN(_x)			((_x) << 8) +#define DSTS_ERRATICERR			(1 << 3) +#define DSTS_ENUMSPD_MASK		(0x3 << 1) +#define DSTS_ENUMSPD_SHIFT		1 +#define DSTS_ENUMSPD_HS			0 +#define DSTS_ENUMSPD_FS			1 +#define DSTS_ENUMSPD_LS			2 +#define DSTS_ENUMSPD_FS48		3 +#define DSTS_SUSPSTS			(1 << 0) + +#define DIEPMSK				HSOTG_REG(0x810) +#define DIEPMSK_TXFIFOEMPTY		(1 << 7) +#define DIEPMSK_INEPNAKEFFMSK		(1 << 6) +#define DIEPMSK_INTKNEPMISMSK		(1 << 5) +#define DIEPMSK_INTKNTXFEMPMSK		(1 << 4) +#define DIEPMSK_TIMEOUTMSK		(1 << 3) +#define DIEPMSK_AHBERRMSK		(1 << 2) +#define DIEPMSK_EPDISBLDMSK		(1 << 1) +#define DIEPMSK_XFERCOMPLMSK		(1 << 0) + +#define DOEPMSK				HSOTG_REG(0x814) +#define DOEPMSK_BACK2BACKSETUP		(1 << 6) +#define DOEPMSK_OUTTKNEPDISMSK		(1 << 4) +#define DOEPMSK_SETUPMSK		(1 << 3) +#define DOEPMSK_AHBERRMSK		(1 << 2) +#define DOEPMSK_EPDISBLDMSK		(1 << 1) +#define DOEPMSK_XFERCOMPLMSK		(1 << 0) + +#define DAINT				HSOTG_REG(0x818) +#define DAINTMSK			HSOTG_REG(0x81C) +#define DAINT_OUTEP_SHIFT		16 +#define DAINT_OUTEP(_x)			(1 << ((_x) + 16)) +#define DAINT_INEP(_x)			(1 << (_x)) + +#define DTKNQR1				HSOTG_REG(0x820) +#define DTKNQR2				HSOTG_REG(0x824) +#define DTKNQR3				HSOTG_REG(0x830) +#define DTKNQR4				HSOTG_REG(0x834) + +#define DVBUSDIS			HSOTG_REG(0x828) +#define DVBUSPULSE			HSOTG_REG(0x82C) + +#define DIEPCTL0			HSOTG_REG(0x900) +#define DIEPCTL(_a)			HSOTG_REG(0x900 + ((_a) * 0x20)) + +#define DOEPCTL0			HSOTG_REG(0xB00) +#define DOEPCTL(_a)			HSOTG_REG(0xB00 + ((_a) * 0x20)) + +/* EP0 specialness: + * bits[29..28] - reserved (no SetD0PID, SetD1PID) + * bits[25..22] - should always be zero, this isn't a periodic endpoint + * bits[10..0]  - MPS setting different for EP0 + */ +#define D0EPCTL_MPS_MASK		(0x3 << 0) +#define D0EPCTL_MPS_SHIFT		0 +#define D0EPCTL_MPS_64			0 +#define D0EPCTL_MPS_32			1 +#define D0EPCTL_MPS_16			2 +#define D0EPCTL_MPS_8			3 + +#define DXEPCTL_EPENA			(1 << 31) +#define DXEPCTL_EPDIS			(1 << 30) +#define DXEPCTL_SETD1PID		(1 << 29) +#define DXEPCTL_SETODDFR		(1 << 29) +#define DXEPCTL_SETD0PID		(1 << 28) +#define DXEPCTL_SETEVENFR		(1 << 28) +#define DXEPCTL_SNAK			(1 << 27) +#define DXEPCTL_CNAK			(1 << 26) +#define DXEPCTL_TXFNUM_MASK		(0xf << 22) +#define DXEPCTL_TXFNUM_SHIFT		22 +#define DXEPCTL_TXFNUM_LIMIT		0xf +#define DXEPCTL_TXFNUM(_x)		((_x) << 22) +#define DXEPCTL_STALL			(1 << 21) +#define DXEPCTL_SNP			(1 << 20) +#define DXEPCTL_EPTYPE_MASK		(0x3 << 18) +#define DXEPCTL_EPTYPE_CONTROL		(0x0 << 18) +#define DXEPCTL_EPTYPE_ISO		(0x1 << 18) +#define DXEPCTL_EPTYPE_BULK		(0x2 << 18) +#define DXEPCTL_EPTYPE_INTERRUPT	(0x3 << 18) + +#define DXEPCTL_NAKSTS			(1 << 17) +#define DXEPCTL_DPID			(1 << 16) +#define DXEPCTL_EOFRNUM			(1 << 16) +#define DXEPCTL_USBACTEP		(1 << 15) +#define DXEPCTL_NEXTEP_MASK		(0xf << 11) +#define DXEPCTL_NEXTEP_SHIFT		11 +#define DXEPCTL_NEXTEP_LIMIT		0xf +#define DXEPCTL_NEXTEP(_x)		((_x) << 11) +#define DXEPCTL_MPS_MASK		(0x7ff << 0) +#define DXEPCTL_MPS_SHIFT		0 +#define DXEPCTL_MPS_LIMIT		0x7ff +#define DXEPCTL_MPS(_x)			((_x) << 0) + +#define DIEPINT(_a)			HSOTG_REG(0x908 + ((_a) * 0x20)) +#define DOEPINT(_a)			HSOTG_REG(0xB08 + ((_a) * 0x20)) +#define DXEPINT_INEPNAKEFF		(1 << 6) +#define DXEPINT_BACK2BACKSETUP		(1 << 6) +#define DXEPINT_INTKNEPMIS		(1 << 5) +#define DXEPINT_INTKNTXFEMP		(1 << 4) +#define DXEPINT_OUTTKNEPDIS		(1 << 4) +#define DXEPINT_TIMEOUT			(1 << 3) +#define DXEPINT_SETUP			(1 << 3) +#define DXEPINT_AHBERR			(1 << 2) +#define DXEPINT_EPDISBLD		(1 << 1) +#define DXEPINT_XFERCOMPL		(1 << 0) + +#define DIEPTSIZ0			HSOTG_REG(0x910) +#define DIEPTSIZ0_PKTCNT_MASK		(0x3 << 19) +#define DIEPTSIZ0_PKTCNT_SHIFT		19 +#define DIEPTSIZ0_PKTCNT_LIMIT		0x3 +#define DIEPTSIZ0_PKTCNT(_x)		((_x) << 19) +#define DIEPTSIZ0_XFERSIZE_MASK		(0x7f << 0) +#define DIEPTSIZ0_XFERSIZE_SHIFT	0 +#define DIEPTSIZ0_XFERSIZE_LIMIT	0x7f +#define DIEPTSIZ0_XFERSIZE(_x)		((_x) << 0) + +#define DOEPTSIZ0			HSOTG_REG(0xB10) +#define DOEPTSIZ0_SUPCNT_MASK		(0x3 << 29) +#define DOEPTSIZ0_SUPCNT_SHIFT		29 +#define DOEPTSIZ0_SUPCNT_LIMIT		0x3 +#define DOEPTSIZ0_SUPCNT(_x)		((_x) << 29) +#define DOEPTSIZ0_PKTCNT		(1 << 19) +#define DOEPTSIZ0_XFERSIZE_MASK		(0x7f << 0) +#define DOEPTSIZ0_XFERSIZE_SHIFT	0 + +#define DIEPTSIZ(_a)			HSOTG_REG(0x910 + ((_a) * 0x20)) +#define DOEPTSIZ(_a)			HSOTG_REG(0xB10 + ((_a) * 0x20)) +#define DXEPTSIZ_MC_MASK		(0x3 << 29) +#define DXEPTSIZ_MC_SHIFT		29 +#define DXEPTSIZ_MC_LIMIT		0x3 +#define DXEPTSIZ_MC(_x)			((_x) << 29) +#define DXEPTSIZ_PKTCNT_MASK		(0x3ff << 19) +#define DXEPTSIZ_PKTCNT_SHIFT		19 +#define DXEPTSIZ_PKTCNT_LIMIT		0x3ff +#define DXEPTSIZ_PKTCNT_GET(_v)		(((_v) >> 19) & 0x3ff) +#define DXEPTSIZ_PKTCNT(_x)		((_x) << 19) +#define DXEPTSIZ_XFERSIZE_MASK		(0x7ffff << 0) +#define DXEPTSIZ_XFERSIZE_SHIFT		0 +#define DXEPTSIZ_XFERSIZE_LIMIT		0x7ffff +#define DXEPTSIZ_XFERSIZE_GET(_v)	(((_v) >> 0) & 0x7ffff) +#define DXEPTSIZ_XFERSIZE(_x)		((_x) << 0) + +#define DIEPDMA(_a)			HSOTG_REG(0x914 + ((_a) * 0x20)) +#define DOEPDMA(_a)			HSOTG_REG(0xB14 + ((_a) * 0x20)) + +#define DTXFSTS(_a)			HSOTG_REG(0x918 + ((_a) * 0x20)) + +#define PCGCTL				HSOTG_REG(0x0e00) +#define PCGCTL_IF_DEV_MODE		(1 << 31) +#define PCGCTL_P2HD_PRT_SPD_MASK	(0x3 << 29) +#define PCGCTL_P2HD_PRT_SPD_SHIFT	29 +#define PCGCTL_P2HD_DEV_ENUM_SPD_MASK	(0x3 << 27) +#define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT	27 +#define PCGCTL_MAC_DEV_ADDR_MASK	(0x7f << 20) +#define PCGCTL_MAC_DEV_ADDR_SHIFT	20 +#define PCGCTL_MAX_TERMSEL		(1 << 19) +#define PCGCTL_MAX_XCVRSELECT_MASK	(0x3 << 17) +#define PCGCTL_MAX_XCVRSELECT_SHIFT	17 +#define PCGCTL_PORT_POWER		(1 << 16) +#define PCGCTL_PRT_CLK_SEL_MASK		(0x3 << 14) +#define PCGCTL_PRT_CLK_SEL_SHIFT	14 +#define PCGCTL_ESS_REG_RESTORED		(1 << 13) +#define PCGCTL_EXTND_HIBER_SWITCH	(1 << 12) +#define PCGCTL_EXTND_HIBER_PWRCLMP	(1 << 11) +#define PCGCTL_ENBL_EXTND_HIBER		(1 << 10) +#define PCGCTL_RESTOREMODE		(1 << 9) +#define PCGCTL_RESETAFTSUSP		(1 << 8) +#define PCGCTL_DEEP_SLEEP		(1 << 7) +#define PCGCTL_PHY_IN_SLEEP		(1 << 6) +#define PCGCTL_ENBL_SLEEP_GATING	(1 << 5) +#define PCGCTL_RSTPDWNMODULE		(1 << 3) +#define PCGCTL_PWRCLMP			(1 << 2) +#define PCGCTL_GATEHCLK			(1 << 1) +#define PCGCTL_STOPPCLK			(1 << 0) + +#define EPFIFO(_a)			HSOTG_REG(0x1000 + ((_a) * 0x1000)) + +/* Host Mode Registers */ + +#define HCFG				HSOTG_REG(0x0400) +#define HCFG_MODECHTIMEN		(1 << 31) +#define HCFG_PERSCHEDENA		(1 << 26) +#define HCFG_FRLISTEN_MASK		(0x3 << 24) +#define HCFG_FRLISTEN_SHIFT		24 +#define HCFG_FRLISTEN_8				(0 << 24) +#define FRLISTEN_8_SIZE				8 +#define HCFG_FRLISTEN_16			(1 << 24) +#define FRLISTEN_16_SIZE			16 +#define HCFG_FRLISTEN_32			(2 << 24) +#define FRLISTEN_32_SIZE			32 +#define HCFG_FRLISTEN_64			(3 << 24) +#define FRLISTEN_64_SIZE			64 +#define HCFG_DESCDMA			(1 << 23) +#define HCFG_RESVALID_MASK		(0xff << 8) +#define HCFG_RESVALID_SHIFT		8 +#define HCFG_ENA32KHZ			(1 << 7) +#define HCFG_FSLSSUPP			(1 << 2) +#define HCFG_FSLSPCLKSEL_MASK		(0x3 << 0) +#define HCFG_FSLSPCLKSEL_SHIFT		0 +#define HCFG_FSLSPCLKSEL_30_60_MHZ	0 +#define HCFG_FSLSPCLKSEL_48_MHZ		1 +#define HCFG_FSLSPCLKSEL_6_MHZ		2 + +#define HFIR				HSOTG_REG(0x0404) +#define HFIR_FRINT_MASK			(0xffff << 0) +#define HFIR_FRINT_SHIFT		0 +#define HFIR_RLDCTRL			(1 << 16) + +#define HFNUM				HSOTG_REG(0x0408) +#define HFNUM_FRREM_MASK		(0xffff << 16) +#define HFNUM_FRREM_SHIFT		16 +#define HFNUM_FRNUM_MASK		(0xffff << 0) +#define HFNUM_FRNUM_SHIFT		0 +#define HFNUM_MAX_FRNUM			0x3fff + +#define HPTXSTS				HSOTG_REG(0x0410) +#define TXSTS_QTOP_ODD			(1 << 31) +#define TXSTS_QTOP_CHNEP_MASK		(0xf << 27) +#define TXSTS_QTOP_CHNEP_SHIFT		27 +#define TXSTS_QTOP_TOKEN_MASK		(0x3 << 25) +#define TXSTS_QTOP_TOKEN_SHIFT		25 +#define TXSTS_QTOP_TERMINATE		(1 << 24) +#define TXSTS_QSPCAVAIL_MASK		(0xff << 16) +#define TXSTS_QSPCAVAIL_SHIFT		16 +#define TXSTS_FSPCAVAIL_MASK		(0xffff << 0) +#define TXSTS_FSPCAVAIL_SHIFT		0 + +#define HAINT				HSOTG_REG(0x0414) +#define HAINTMSK			HSOTG_REG(0x0418) +#define HFLBADDR			HSOTG_REG(0x041c) + +#define HPRT0				HSOTG_REG(0x0440) +#define HPRT0_SPD_MASK			(0x3 << 17) +#define HPRT0_SPD_SHIFT			17 +#define HPRT0_SPD_HIGH_SPEED		0 +#define HPRT0_SPD_FULL_SPEED		1 +#define HPRT0_SPD_LOW_SPEED		2 +#define HPRT0_TSTCTL_MASK		(0xf << 13) +#define HPRT0_TSTCTL_SHIFT		13 +#define HPRT0_PWR			(1 << 12) +#define HPRT0_LNSTS_MASK		(0x3 << 10) +#define HPRT0_LNSTS_SHIFT		10 +#define HPRT0_RST			(1 << 8) +#define HPRT0_SUSP			(1 << 7) +#define HPRT0_RES			(1 << 6) +#define HPRT0_OVRCURRCHG		(1 << 5) +#define HPRT0_OVRCURRACT		(1 << 4) +#define HPRT0_ENACHG			(1 << 3) +#define HPRT0_ENA			(1 << 2) +#define HPRT0_CONNDET			(1 << 1) +#define HPRT0_CONNSTS			(1 << 0) + +#define HCCHAR(_ch)			HSOTG_REG(0x0500 + 0x20 * (_ch)) +#define HCCHAR_CHENA			(1 << 31) +#define HCCHAR_CHDIS			(1 << 30) +#define HCCHAR_ODDFRM			(1 << 29) +#define HCCHAR_DEVADDR_MASK		(0x7f << 22) +#define HCCHAR_DEVADDR_SHIFT		22 +#define HCCHAR_MULTICNT_MASK		(0x3 << 20) +#define HCCHAR_MULTICNT_SHIFT		20 +#define HCCHAR_EPTYPE_MASK		(0x3 << 18) +#define HCCHAR_EPTYPE_SHIFT		18 +#define HCCHAR_LSPDDEV			(1 << 17) +#define HCCHAR_EPDIR			(1 << 15) +#define HCCHAR_EPNUM_MASK		(0xf << 11) +#define HCCHAR_EPNUM_SHIFT		11 +#define HCCHAR_MPS_MASK			(0x7ff << 0) +#define HCCHAR_MPS_SHIFT		0 + +#define HCSPLT(_ch)			HSOTG_REG(0x0504 + 0x20 * (_ch)) +#define HCSPLT_SPLTENA			(1 << 31) +#define HCSPLT_COMPSPLT			(1 << 16) +#define HCSPLT_XACTPOS_MASK		(0x3 << 14) +#define HCSPLT_XACTPOS_SHIFT		14 +#define HCSPLT_XACTPOS_MID		0 +#define HCSPLT_XACTPOS_END		1 +#define HCSPLT_XACTPOS_BEGIN		2 +#define HCSPLT_XACTPOS_ALL		3 +#define HCSPLT_HUBADDR_MASK		(0x7f << 7) +#define HCSPLT_HUBADDR_SHIFT		7 +#define HCSPLT_PRTADDR_MASK		(0x7f << 0) +#define HCSPLT_PRTADDR_SHIFT		0 + +#define HCINT(_ch)			HSOTG_REG(0x0508 + 0x20 * (_ch)) +#define HCINTMSK(_ch)			HSOTG_REG(0x050c + 0x20 * (_ch)) +#define HCINTMSK_RESERVED14_31		(0x3ffff << 14) +#define HCINTMSK_FRM_LIST_ROLL		(1 << 13) +#define HCINTMSK_XCS_XACT		(1 << 12) +#define HCINTMSK_BNA			(1 << 11) +#define HCINTMSK_DATATGLERR		(1 << 10) +#define HCINTMSK_FRMOVRUN		(1 << 9) +#define HCINTMSK_BBLERR			(1 << 8) +#define HCINTMSK_XACTERR		(1 << 7) +#define HCINTMSK_NYET			(1 << 6) +#define HCINTMSK_ACK			(1 << 5) +#define HCINTMSK_NAK			(1 << 4) +#define HCINTMSK_STALL			(1 << 3) +#define HCINTMSK_AHBERR			(1 << 2) +#define HCINTMSK_CHHLTD			(1 << 1) +#define HCINTMSK_XFERCOMPL		(1 << 0) + +#define HCTSIZ(_ch)			HSOTG_REG(0x0510 + 0x20 * (_ch)) +#define TSIZ_DOPNG			(1 << 31) +#define TSIZ_SC_MC_PID_MASK		(0x3 << 29) +#define TSIZ_SC_MC_PID_SHIFT		29 +#define TSIZ_SC_MC_PID_DATA0		0 +#define TSIZ_SC_MC_PID_DATA2		1 +#define TSIZ_SC_MC_PID_DATA1		2 +#define TSIZ_SC_MC_PID_MDATA		3 +#define TSIZ_SC_MC_PID_SETUP		3 +#define TSIZ_PKTCNT_MASK		(0x3ff << 19) +#define TSIZ_PKTCNT_SHIFT		19 +#define TSIZ_NTD_MASK			(0xff << 8) +#define TSIZ_NTD_SHIFT			8 +#define TSIZ_SCHINFO_MASK		(0xff << 0) +#define TSIZ_SCHINFO_SHIFT		0 +#define TSIZ_XFERSIZE_MASK		(0x7ffff << 0) +#define TSIZ_XFERSIZE_SHIFT		0 + +#define HCDMA(_ch)			HSOTG_REG(0x0514 + 0x20 * (_ch)) +#define HCDMA_DMA_ADDR_MASK		(0x1fffff << 11) +#define HCDMA_DMA_ADDR_SHIFT		11 +#define HCDMA_CTD_MASK			(0xff << 3) +#define HCDMA_CTD_SHIFT			3 + +#define HCDMAB(_ch)			HSOTG_REG(0x051c + 0x20 * (_ch)) + +#define HCFIFO(_ch)			HSOTG_REG(0x1000 + 0x1000 * (_ch)) + +/** + * struct dwc2_hcd_dma_desc - Host-mode DMA descriptor structure + * + * @status: DMA descriptor status quadlet + * @buf:    DMA descriptor data buffer pointer + * + * DMA Descriptor structure contains two quadlets: + * Status quadlet and Data buffer pointer. + */ +struct dwc2_hcd_dma_desc { +	u32 status; +	u32 buf; +}; + +#define HOST_DMA_A			(1 << 31) +#define HOST_DMA_STS_MASK		(0x3 << 28) +#define HOST_DMA_STS_SHIFT		28 +#define HOST_DMA_STS_PKTERR		(1 << 28) +#define HOST_DMA_EOL			(1 << 26) +#define HOST_DMA_IOC			(1 << 25) +#define HOST_DMA_SUP			(1 << 24) +#define HOST_DMA_ALT_QTD		(1 << 23) +#define HOST_DMA_QTD_OFFSET_MASK	(0x3f << 17) +#define HOST_DMA_QTD_OFFSET_SHIFT	17 +#define HOST_DMA_ISOC_NBYTES_MASK	(0xfff << 0) +#define HOST_DMA_ISOC_NBYTES_SHIFT	0 +#define HOST_DMA_NBYTES_MASK		(0x1ffff << 0) +#define HOST_DMA_NBYTES_SHIFT		0 + +#define MAX_DMA_DESC_SIZE		131071 +#define MAX_DMA_DESC_NUM_GENERIC	64 +#define MAX_DMA_DESC_NUM_HS_ISOC	256 + +#endif /* __DWC2_HW_H__ */ diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c new file mode 100644 index 00000000000..c291fca5d21 --- /dev/null +++ b/drivers/usb/dwc2/pci.c @@ -0,0 +1,178 @@ +/* + * pci.c - DesignWare HS OTG Controller PCI driver + * + * Copyright (C) 2004-2013 Synopsys, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + *    to endorse or promote products derived from this software without + *    specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Provides the initialization and cleanup entry points for the DWC_otg PCI + * driver + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/spinlock.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/usb.h> + +#include <linux/usb/hcd.h> +#include <linux/usb/ch11.h> + +#include "core.h" +#include "hcd.h" + +#define PCI_VENDOR_ID_SYNOPSYS		0x16c3 +#define PCI_PRODUCT_ID_HAPS_HSOTG	0xabc0 + +static const char dwc2_driver_name[] = "dwc2"; + +static const struct dwc2_core_params dwc2_module_params = { +	.otg_cap			= -1, +	.otg_ver			= -1, +	.dma_enable			= -1, +	.dma_desc_enable		= 0, +	.speed				= -1, +	.enable_dynamic_fifo		= -1, +	.en_multiple_tx_fifo		= -1, +	.host_rx_fifo_size		= 1024, +	.host_nperio_tx_fifo_size	= 256, +	.host_perio_tx_fifo_size	= 1024, +	.max_transfer_size		= 65535, +	.max_packet_count		= 511, +	.host_channels			= -1, +	.phy_type			= -1, +	.phy_utmi_width			= -1, +	.phy_ulpi_ddr			= -1, +	.phy_ulpi_ext_vbus		= -1, +	.i2c_enable			= -1, +	.ulpi_fs_ls			= -1, +	.host_support_fs_ls_low_power	= -1, +	.host_ls_low_power_phy_clk	= -1, +	.ts_dline			= -1, +	.reload_ctl			= -1, +	.ahbcfg				= -1, +	.uframe_sched			= -1, +}; + +/** + * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the + * DWC_otg driver + * + * @dev: Bus device + * + * This routine is called, for example, when the rmmod command is executed. The + * device may or may not be electrically present. If it is present, the driver + * stops device processing. Any resources used on behalf of this device are + * freed. + */ +static void dwc2_driver_remove(struct pci_dev *dev) +{ +	struct dwc2_hsotg *hsotg = pci_get_drvdata(dev); + +	dwc2_hcd_remove(hsotg); +	pci_disable_device(dev); +} + +/** + * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg + * driver + * + * @dev: Bus device + * + * This routine creates the driver components required to control the device + * (core, HCD, and PCD) and initializes the device. The driver components are + * stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved + * in the device private data. This allows the driver to access the dwc2_hsotg + * structure on subsequent calls to driver methods for this device. + */ +static int dwc2_driver_probe(struct pci_dev *dev, +			     const struct pci_device_id *id) +{ +	struct dwc2_hsotg *hsotg; +	int retval; + +	hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL); +	if (!hsotg) +		return -ENOMEM; + +	hsotg->dev = &dev->dev; +	hsotg->regs = devm_ioremap_resource(&dev->dev, &dev->resource[0]); +	if (IS_ERR(hsotg->regs)) +		return PTR_ERR(hsotg->regs); + +	dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n", +		(unsigned long)pci_resource_start(dev, 0), hsotg->regs); + +	if (pci_enable_device(dev) < 0) +		return -ENODEV; + +	pci_set_master(dev); + +	retval = dwc2_hcd_init(hsotg, dev->irq, &dwc2_module_params); +	if (retval) { +		pci_disable_device(dev); +		return retval; +	} + +	pci_set_drvdata(dev, hsotg); + +	return retval; +} + +static const struct pci_device_id dwc2_pci_ids[] = { +	{ +		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, PCI_PRODUCT_ID_HAPS_HSOTG), +	}, +	{ +		PCI_DEVICE(PCI_VENDOR_ID_STMICRO, +			   PCI_DEVICE_ID_STMICRO_USB_OTG), +	}, +	{ /* end: all zeroes */ } +}; +MODULE_DEVICE_TABLE(pci, dwc2_pci_ids); + +static struct pci_driver dwc2_pci_driver = { +	.name = dwc2_driver_name, +	.id_table = dwc2_pci_ids, +	.probe = dwc2_driver_probe, +	.remove = dwc2_driver_remove, +}; + +module_pci_driver(dwc2_pci_driver); + +MODULE_DESCRIPTION("DESIGNWARE HS OTG PCI Bus Glue"); +MODULE_AUTHOR("Synopsys, Inc."); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c new file mode 100644 index 00000000000..a10e7a35357 --- /dev/null +++ b/drivers/usb/dwc2/platform.c @@ -0,0 +1,196 @@ +/* + * platform.c - DesignWare HS OTG Controller platform driver + * + * Copyright (C) Matthijs Kooijman <matthijs@stdin.nl> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + *    notice, this list of conditions, and the following disclaimer, + *    without modification. + * 2. Redistributions in binary form must reproduce the above copyright + *    notice, this list of conditions and the following disclaimer in the + *    documentation and/or other materials provided with the distribution. + * 3. The names of the above-listed copyright holders may not be used + *    to endorse or promote products derived from this software without + *    specific prior written permission. + * + * ALTERNATIVELY, this software may be distributed under the terms of the + * GNU General Public License ("GPL") as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any + * later version. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> + +#include "core.h" +#include "hcd.h" + +static const char dwc2_driver_name[] = "dwc2"; + +static const struct dwc2_core_params params_bcm2835 = { +	.otg_cap			= 0,	/* HNP/SRP capable */ +	.otg_ver			= 0,	/* 1.3 */ +	.dma_enable			= 1, +	.dma_desc_enable		= 0, +	.speed				= 0,	/* High Speed */ +	.enable_dynamic_fifo		= 1, +	.en_multiple_tx_fifo		= 1, +	.host_rx_fifo_size		= 774,	/* 774 DWORDs */ +	.host_nperio_tx_fifo_size	= 256,	/* 256 DWORDs */ +	.host_perio_tx_fifo_size	= 512,	/* 512 DWORDs */ +	.max_transfer_size		= 65535, +	.max_packet_count		= 511, +	.host_channels			= 8, +	.phy_type			= 1,	/* UTMI */ +	.phy_utmi_width			= 8,	/* 8 bits */ +	.phy_ulpi_ddr			= 0,	/* Single */ +	.phy_ulpi_ext_vbus		= 0, +	.i2c_enable			= 0, +	.ulpi_fs_ls			= 0, +	.host_support_fs_ls_low_power	= 0, +	.host_ls_low_power_phy_clk	= 0,	/* 48 MHz */ +	.ts_dline			= 0, +	.reload_ctl			= 0, +	.ahbcfg				= 0x10, +	.uframe_sched			= 0, +}; + +/** + * dwc2_driver_remove() - Called when the DWC_otg core is unregistered with the + * DWC_otg driver + * + * @dev: Platform device + * + * This routine is called, for example, when the rmmod command is executed. The + * device may or may not be electrically present. If it is present, the driver + * stops device processing. Any resources used on behalf of this device are + * freed. + */ +static int dwc2_driver_remove(struct platform_device *dev) +{ +	struct dwc2_hsotg *hsotg = platform_get_drvdata(dev); + +	dwc2_hcd_remove(hsotg); + +	return 0; +} + +static const struct of_device_id dwc2_of_match_table[] = { +	{ .compatible = "brcm,bcm2835-usb", .data = ¶ms_bcm2835 }, +	{ .compatible = "snps,dwc2", .data = NULL }, +	{}, +}; +MODULE_DEVICE_TABLE(of, dwc2_of_match_table); + +/** + * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg + * driver + * + * @dev: Platform device + * + * This routine creates the driver components required to control the device + * (core, HCD, and PCD) and initializes the device. The driver components are + * stored in a dwc2_hsotg structure. A reference to the dwc2_hsotg is saved + * in the device private data. This allows the driver to access the dwc2_hsotg + * structure on subsequent calls to driver methods for this device. + */ +static int dwc2_driver_probe(struct platform_device *dev) +{ +	const struct of_device_id *match; +	const struct dwc2_core_params *params; +	struct dwc2_core_params defparams; +	struct dwc2_hsotg *hsotg; +	struct resource *res; +	int retval; +	int irq; + +	if (usb_disabled()) +		return -ENODEV; + +	match = of_match_device(dwc2_of_match_table, &dev->dev); +	if (match && match->data) { +		params = match->data; +	} else { +		/* Default all params to autodetect */ +		dwc2_set_all_params(&defparams, -1); +		params = &defparams; + +		/* +		 * Disable descriptor dma mode by default as the HW can support +		 * it, but does not support it for SPLIT transactions. +		 */ +		defparams.dma_desc_enable = 0; +	} + +	hsotg = devm_kzalloc(&dev->dev, sizeof(*hsotg), GFP_KERNEL); +	if (!hsotg) +		return -ENOMEM; + +	hsotg->dev = &dev->dev; + +	/* +	 * Use reasonable defaults so platforms don't have to provide these. +	 */ +	if (!dev->dev.dma_mask) +		dev->dev.dma_mask = &dev->dev.coherent_dma_mask; +	retval = dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32)); +	if (retval) +		return retval; + +	irq = platform_get_irq(dev, 0); +	if (irq < 0) { +		dev_err(&dev->dev, "missing IRQ resource\n"); +		return irq; +	} + +	res = platform_get_resource(dev, IORESOURCE_MEM, 0); +	hsotg->regs = devm_ioremap_resource(&dev->dev, res); +	if (IS_ERR(hsotg->regs)) +		return PTR_ERR(hsotg->regs); + +	dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n", +		(unsigned long)res->start, hsotg->regs); + +	retval = dwc2_hcd_init(hsotg, irq, params); +	if (retval) +		return retval; + +	platform_set_drvdata(dev, hsotg); + +	return retval; +} + +static struct platform_driver dwc2_platform_driver = { +	.driver = { +		.name = dwc2_driver_name, +		.of_match_table = dwc2_of_match_table, +	}, +	.probe = dwc2_driver_probe, +	.remove = dwc2_driver_remove, +}; + +module_platform_driver(dwc2_platform_driver); + +MODULE_DESCRIPTION("DESIGNWARE HS OTG Platform Glue"); +MODULE_AUTHOR("Matthijs Kooijman <matthijs@stdin.nl>"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index b870872e020..261c3b42822 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -1,7 +1,6 @@  config USB_DWC3  	tristate "DesignWare USB3 DRD Core Support"  	depends on (USB || USB_GADGET) && HAS_DMA -	depends on EXTCON  	select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD  	help  	  Say Y or M here if your system has a Dual Role SuperSpeed @@ -45,7 +44,8 @@ comment "Platform Glue Driver Support"  config USB_DWC3_OMAP  	tristate "Texas Instruments OMAP5 and similar Platforms" -	depends on EXTCON +	depends on EXTCON && (ARCH_OMAP2PLUS || COMPILE_TEST) +	depends on OF  	default USB_DWC3  	help  	  Some platforms from Texas Instruments like OMAP5, DRA7xxx and @@ -55,6 +55,7 @@ config USB_DWC3_OMAP  config USB_DWC3_EXYNOS  	tristate "Samsung Exynos Platform" +	depends on ARCH_EXYNOS || COMPILE_TEST  	default USB_DWC3  	help  	  Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside, @@ -71,6 +72,14 @@ config USB_DWC3_PCI  	  One such PCIe-based platform is Synopsys' PCIe HAPS model of  	  this IP. +config USB_DWC3_KEYSTONE +	tristate "Texas Instruments Keystone2 Platforms" +	depends on ARCH_KEYSTONE || COMPILE_TEST +	default USB_DWC3 +	help +	  Support of USB2/3 functionality in TI Keystone2 platforms. +	  Say 'Y' or 'M' here if you have one such device +  comment "Debugging features"  config USB_DWC3_DEBUG diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index dd1760145c4..10ac3e72482 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -32,3 +32,4 @@ endif  obj-$(CONFIG_USB_DWC3_OMAP)		+= dwc3-omap.o  obj-$(CONFIG_USB_DWC3_EXYNOS)		+= dwc3-exynos.o  obj-$(CONFIG_USB_DWC3_PCI)		+= dwc3-pci.o +obj-$(CONFIG_USB_DWC3_KEYSTONE)		+= dwc3-keystone.o diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 474162e9d01..eb69eb9f06c 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -61,9 +61,10 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)   * dwc3_core_soft_reset - Issues core soft reset and PHY reset   * @dwc: pointer to our context structure   */ -static void dwc3_core_soft_reset(struct dwc3 *dwc) +static int dwc3_core_soft_reset(struct dwc3 *dwc)  {  	u32		reg; +	int		ret;  	/* Before Resetting PHY, put Core in Reset */  	reg = dwc3_readl(dwc->regs, DWC3_GCTL); @@ -82,6 +83,15 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc)  	usb_phy_init(dwc->usb2_phy);  	usb_phy_init(dwc->usb3_phy); +	ret = phy_init(dwc->usb2_generic_phy); +	if (ret < 0) +		return ret; + +	ret = phy_init(dwc->usb3_generic_phy); +	if (ret < 0) { +		phy_exit(dwc->usb2_generic_phy); +		return ret; +	}  	mdelay(100);  	/* Clear USB3 PHY reset */ @@ -100,6 +110,8 @@ static void dwc3_core_soft_reset(struct dwc3 *dwc)  	reg = dwc3_readl(dwc->regs, DWC3_GCTL);  	reg &= ~DWC3_GCTL_CORESOFTRESET;  	dwc3_writel(dwc->regs, DWC3_GCTL, reg); + +	return 0;  }  /** @@ -242,6 +254,90 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)  	}  } +static int dwc3_alloc_scratch_buffers(struct dwc3 *dwc) +{ +	if (!dwc->has_hibernation) +		return 0; + +	if (!dwc->nr_scratch) +		return 0; + +	dwc->scratchbuf = kmalloc_array(dwc->nr_scratch, +			DWC3_SCRATCHBUF_SIZE, GFP_KERNEL); +	if (!dwc->scratchbuf) +		return -ENOMEM; + +	return 0; +} + +static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) +{ +	dma_addr_t scratch_addr; +	u32 param; +	int ret; + +	if (!dwc->has_hibernation) +		return 0; + +	if (!dwc->nr_scratch) +		return 0; + +	 /* should never fall here */ +	if (!WARN_ON(dwc->scratchbuf)) +		return 0; + +	scratch_addr = dma_map_single(dwc->dev, dwc->scratchbuf, +			dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, +			DMA_BIDIRECTIONAL); +	if (dma_mapping_error(dwc->dev, scratch_addr)) { +		dev_err(dwc->dev, "failed to map scratch buffer\n"); +		ret = -EFAULT; +		goto err0; +	} + +	dwc->scratch_addr = scratch_addr; + +	param = lower_32_bits(scratch_addr); + +	ret = dwc3_send_gadget_generic_command(dwc, +			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO, param); +	if (ret < 0) +		goto err1; + +	param = upper_32_bits(scratch_addr); + +	ret = dwc3_send_gadget_generic_command(dwc, +			DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI, param); +	if (ret < 0) +		goto err1; + +	return 0; + +err1: +	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch * +			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); + +err0: +	return ret; +} + +static void dwc3_free_scratch_buffers(struct dwc3 *dwc) +{ +	if (!dwc->has_hibernation) +		return; + +	if (!dwc->nr_scratch) +		return; + +	 /* should never fall here */ +	if (!WARN_ON(dwc->scratchbuf)) +		return; + +	dma_unmap_single(dwc->dev, dwc->scratch_addr, dwc->nr_scratch * +			DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); +	kfree(dwc->scratchbuf); +} +  static void dwc3_core_num_eps(struct dwc3 *dwc)  {  	struct dwc3_hwparams	*parms = &dwc->hwparams; @@ -277,6 +373,7 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)  static int dwc3_core_init(struct dwc3 *dwc)  {  	unsigned long		timeout; +	u32			hwparams4 = dwc->hwparams.hwparams4;  	u32			reg;  	int			ret; @@ -306,7 +403,9 @@ static int dwc3_core_init(struct dwc3 *dwc)  		cpu_relax();  	} while (true); -	dwc3_core_soft_reset(dwc); +	ret = dwc3_core_soft_reset(dwc); +	if (ret) +		goto err0;  	reg = dwc3_readl(dwc->regs, DWC3_GCTL);  	reg &= ~DWC3_GCTL_SCALEDOWN_MASK; @@ -314,7 +413,29 @@ static int dwc3_core_init(struct dwc3 *dwc)  	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {  	case DWC3_GHWPARAMS1_EN_PWROPT_CLK: -		reg &= ~DWC3_GCTL_DSBLCLKGTNG; +		/** +		 * WORKAROUND: DWC3 revisions between 2.10a and 2.50a have an +		 * issue which would cause xHCI compliance tests to fail. +		 * +		 * Because of that we cannot enable clock gating on such +		 * configurations. +		 * +		 * Refers to: +		 * +		 * STAR#9000588375: Clock Gating, SOF Issues when ref_clk-Based +		 * SOF/ITP Mode Used +		 */ +		if ((dwc->dr_mode == USB_DR_MODE_HOST || +				dwc->dr_mode == USB_DR_MODE_OTG) && +				(dwc->revision >= DWC3_REVISION_210A && +				dwc->revision <= DWC3_REVISION_250A)) +			reg |= DWC3_GCTL_DSBLCLKGTNG | DWC3_GCTL_SOFITPSYNC; +		else +			reg &= ~DWC3_GCTL_DSBLCLKGTNG; +		break; +	case DWC3_GHWPARAMS1_EN_PWROPT_HIB: +		/* enable hibernation here */ +		dwc->nr_scratch = DWC3_GHWPARAMS4_HIBER_SCRATCHBUFS(hwparams4);  		break;  	default:  		dev_dbg(dwc->dev, "No power optimization available\n"); @@ -333,16 +454,166 @@ static int dwc3_core_init(struct dwc3 *dwc)  	dwc3_writel(dwc->regs, DWC3_GCTL, reg); +	ret = dwc3_alloc_scratch_buffers(dwc); +	if (ret) +		goto err1; + +	ret = dwc3_setup_scratch_buffers(dwc); +	if (ret) +		goto err2; +  	return 0; +err2: +	dwc3_free_scratch_buffers(dwc); + +err1: +	usb_phy_shutdown(dwc->usb2_phy); +	usb_phy_shutdown(dwc->usb3_phy); +	phy_exit(dwc->usb2_generic_phy); +	phy_exit(dwc->usb3_generic_phy); +  err0:  	return ret;  }  static void dwc3_core_exit(struct dwc3 *dwc)  { +	dwc3_free_scratch_buffers(dwc);  	usb_phy_shutdown(dwc->usb2_phy);  	usb_phy_shutdown(dwc->usb3_phy); +	phy_exit(dwc->usb2_generic_phy); +	phy_exit(dwc->usb3_generic_phy); +} + +static int dwc3_core_get_phy(struct dwc3 *dwc) +{ +	struct device		*dev = dwc->dev; +	struct device_node	*node = dev->of_node; +	int ret; + +	if (node) { +		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); +		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); +	} else { +		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); +		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); +	} + +	if (IS_ERR(dwc->usb2_phy)) { +		ret = PTR_ERR(dwc->usb2_phy); +		if (ret == -ENXIO || ret == -ENODEV) { +			dwc->usb2_phy = NULL; +		} else if (ret == -EPROBE_DEFER) { +			return ret; +		} else { +			dev_err(dev, "no usb2 phy configured\n"); +			return ret; +		} +	} + +	if (IS_ERR(dwc->usb3_phy)) { +		ret = PTR_ERR(dwc->usb3_phy); +		if (ret == -ENXIO || ret == -ENODEV) { +			dwc->usb3_phy = NULL; +		} else if (ret == -EPROBE_DEFER) { +			return ret; +		} else { +			dev_err(dev, "no usb3 phy configured\n"); +			return ret; +		} +	} + +	dwc->usb2_generic_phy = devm_phy_get(dev, "usb2-phy"); +	if (IS_ERR(dwc->usb2_generic_phy)) { +		ret = PTR_ERR(dwc->usb2_generic_phy); +		if (ret == -ENOSYS || ret == -ENODEV) { +			dwc->usb2_generic_phy = NULL; +		} else if (ret == -EPROBE_DEFER) { +			return ret; +		} else { +			dev_err(dev, "no usb2 phy configured\n"); +			return ret; +		} +	} + +	dwc->usb3_generic_phy = devm_phy_get(dev, "usb3-phy"); +	if (IS_ERR(dwc->usb3_generic_phy)) { +		ret = PTR_ERR(dwc->usb3_generic_phy); +		if (ret == -ENOSYS || ret == -ENODEV) { +			dwc->usb3_generic_phy = NULL; +		} else if (ret == -EPROBE_DEFER) { +			return ret; +		} else { +			dev_err(dev, "no usb3 phy configured\n"); +			return ret; +		} +	} + +	return 0; +} + +static int dwc3_core_init_mode(struct dwc3 *dwc) +{ +	struct device *dev = dwc->dev; +	int ret; + +	switch (dwc->dr_mode) { +	case USB_DR_MODE_PERIPHERAL: +		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); +		ret = dwc3_gadget_init(dwc); +		if (ret) { +			dev_err(dev, "failed to initialize gadget\n"); +			return ret; +		} +		break; +	case USB_DR_MODE_HOST: +		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); +		ret = dwc3_host_init(dwc); +		if (ret) { +			dev_err(dev, "failed to initialize host\n"); +			return ret; +		} +		break; +	case USB_DR_MODE_OTG: +		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); +		ret = dwc3_host_init(dwc); +		if (ret) { +			dev_err(dev, "failed to initialize host\n"); +			return ret; +		} + +		ret = dwc3_gadget_init(dwc); +		if (ret) { +			dev_err(dev, "failed to initialize gadget\n"); +			return ret; +		} +		break; +	default: +		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); +		return -EINVAL; +	} + +	return 0; +} + +static void dwc3_core_exit_mode(struct dwc3 *dwc) +{ +	switch (dwc->dr_mode) { +	case USB_DR_MODE_PERIPHERAL: +		dwc3_gadget_exit(dwc); +		break; +	case USB_DR_MODE_HOST: +		dwc3_host_exit(dwc); +		break; +	case USB_DR_MODE_OTG: +		dwc3_host_exit(dwc); +		dwc3_gadget_exit(dwc); +		break; +	default: +		/* do nothing */ +		break; +	}  }  #define DWC3_ALIGN_MASK		(16 - 1) @@ -355,7 +626,7 @@ static int dwc3_probe(struct platform_device *pdev)  	struct resource		*res;  	struct dwc3		*dwc; -	int			ret = -ENOMEM; +	int			ret;  	void __iomem		*regs;  	void			*mem; @@ -367,6 +638,7 @@ static int dwc3_probe(struct platform_device *pdev)  	}  	dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);  	dwc->mem = mem; +	dwc->dev = dev;  	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);  	if (!res) { @@ -387,57 +659,22 @@ static int dwc3_probe(struct platform_device *pdev)  	if (node) {  		dwc->maximum_speed = of_usb_get_maximum_speed(node); -		dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); -		dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); -  		dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize");  		dwc->dr_mode = of_usb_get_dr_mode(node);  	} else if (pdata) {  		dwc->maximum_speed = pdata->maximum_speed; -		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); -		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); -  		dwc->needs_fifo_resize = pdata->tx_fifo_resize;  		dwc->dr_mode = pdata->dr_mode; -	} else { -		dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); -		dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3);  	}  	/* default to superspeed if no maximum_speed passed */  	if (dwc->maximum_speed == USB_SPEED_UNKNOWN)  		dwc->maximum_speed = USB_SPEED_SUPER; -	if (IS_ERR(dwc->usb2_phy)) { -		ret = PTR_ERR(dwc->usb2_phy); - -		/* -		 * if -ENXIO is returned, it means PHY layer wasn't -		 * enabled, so it makes no sense to return -EPROBE_DEFER -		 * in that case, since no PHY driver will ever probe. -		 */ -		if (ret == -ENXIO) -			return ret; - -		dev_err(dev, "no usb2 phy configured\n"); -		return -EPROBE_DEFER; -	} - -	if (IS_ERR(dwc->usb3_phy)) { -		ret = PTR_ERR(dwc->usb3_phy); - -		/* -		 * if -ENXIO is returned, it means PHY layer wasn't -		 * enabled, so it makes no sense to return -EPROBE_DEFER -		 * in that case, since no PHY driver will ever probe. -		 */ -		if (ret == -ENXIO) -			return ret; - -		dev_err(dev, "no usb3 phy configured\n"); -		return -EPROBE_DEFER; -	} +	ret = dwc3_core_get_phy(dwc); +	if (ret) +		return ret;  	dwc->xhci_resources[0].start = res->start;  	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + @@ -455,15 +692,11 @@ static int dwc3_probe(struct platform_device *pdev)  	if (IS_ERR(regs))  		return PTR_ERR(regs); -	usb_phy_set_suspend(dwc->usb2_phy, 0); -	usb_phy_set_suspend(dwc->usb3_phy, 0); -  	spin_lock_init(&dwc->lock);  	platform_set_drvdata(pdev, dwc);  	dwc->regs	= regs;  	dwc->regs_size	= resource_size(res); -	dwc->dev	= dev;  	dev->dma_mask	= dev->parent->dma_mask;  	dev->dma_parms	= dev->parent->dma_parms; @@ -482,61 +715,39 @@ static int dwc3_probe(struct platform_device *pdev)  		goto err0;  	} +	if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) +		dwc->dr_mode = USB_DR_MODE_HOST; +	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) +		dwc->dr_mode = USB_DR_MODE_PERIPHERAL; + +	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) +		dwc->dr_mode = USB_DR_MODE_OTG; +  	ret = dwc3_core_init(dwc);  	if (ret) {  		dev_err(dev, "failed to initialize core\n");  		goto err0;  	} +	usb_phy_set_suspend(dwc->usb2_phy, 0); +	usb_phy_set_suspend(dwc->usb3_phy, 0); +	ret = phy_power_on(dwc->usb2_generic_phy); +	if (ret < 0) +		goto err1; + +	ret = phy_power_on(dwc->usb3_generic_phy); +	if (ret < 0) +		goto err_usb2phy_power; +  	ret = dwc3_event_buffers_setup(dwc);  	if (ret) {  		dev_err(dwc->dev, "failed to setup event buffers\n"); -		goto err1; +		goto err_usb3phy_power;  	} -	if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) -		dwc->dr_mode = USB_DR_MODE_HOST; -	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) -		dwc->dr_mode = USB_DR_MODE_PERIPHERAL; - -	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) -		dwc->dr_mode = USB_DR_MODE_OTG; - -	switch (dwc->dr_mode) { -	case USB_DR_MODE_PERIPHERAL: -		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); -		ret = dwc3_gadget_init(dwc); -		if (ret) { -			dev_err(dev, "failed to initialize gadget\n"); -			goto err2; -		} -		break; -	case USB_DR_MODE_HOST: -		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST); -		ret = dwc3_host_init(dwc); -		if (ret) { -			dev_err(dev, "failed to initialize host\n"); -			goto err2; -		} -		break; -	case USB_DR_MODE_OTG: -		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG); -		ret = dwc3_host_init(dwc); -		if (ret) { -			dev_err(dev, "failed to initialize host\n"); -			goto err2; -		} - -		ret = dwc3_gadget_init(dwc); -		if (ret) { -			dev_err(dev, "failed to initialize gadget\n"); -			goto err2; -		} -		break; -	default: -		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode); +	ret = dwc3_core_init_mode(dwc); +	if (ret)  		goto err2; -	}  	ret = dwc3_debugfs_init(dwc);  	if (ret) { @@ -549,26 +760,20 @@ static int dwc3_probe(struct platform_device *pdev)  	return 0;  err3: -	switch (dwc->dr_mode) { -	case USB_DR_MODE_PERIPHERAL: -		dwc3_gadget_exit(dwc); -		break; -	case USB_DR_MODE_HOST: -		dwc3_host_exit(dwc); -		break; -	case USB_DR_MODE_OTG: -		dwc3_host_exit(dwc); -		dwc3_gadget_exit(dwc); -		break; -	default: -		/* do nothing */ -		break; -	} +	dwc3_core_exit_mode(dwc);  err2:  	dwc3_event_buffers_cleanup(dwc); +err_usb3phy_power: +	phy_power_off(dwc->usb3_generic_phy); + +err_usb2phy_power: +	phy_power_off(dwc->usb2_generic_phy); +  err1: +	usb_phy_set_suspend(dwc->usb2_phy, 1); +	usb_phy_set_suspend(dwc->usb3_phy, 1);  	dwc3_core_exit(dwc);  err0: @@ -583,28 +788,14 @@ static int dwc3_remove(struct platform_device *pdev)  	usb_phy_set_suspend(dwc->usb2_phy, 1);  	usb_phy_set_suspend(dwc->usb3_phy, 1); +	phy_power_off(dwc->usb2_generic_phy); +	phy_power_off(dwc->usb3_generic_phy); -	pm_runtime_put(&pdev->dev); +	pm_runtime_put_sync(&pdev->dev);  	pm_runtime_disable(&pdev->dev);  	dwc3_debugfs_exit(dwc); - -	switch (dwc->dr_mode) { -	case USB_DR_MODE_PERIPHERAL: -		dwc3_gadget_exit(dwc); -		break; -	case USB_DR_MODE_HOST: -		dwc3_host_exit(dwc); -		break; -	case USB_DR_MODE_OTG: -		dwc3_host_exit(dwc); -		dwc3_gadget_exit(dwc); -		break; -	default: -		/* do nothing */ -		break; -	} - +	dwc3_core_exit_mode(dwc);  	dwc3_event_buffers_cleanup(dwc);  	dwc3_free_event_buffers(dwc);  	dwc3_core_exit(dwc); @@ -643,6 +834,7 @@ static void dwc3_complete(struct device *dev)  	spin_lock_irqsave(&dwc->lock, flags); +	dwc3_event_buffers_setup(dwc);  	switch (dwc->dr_mode) {  	case USB_DR_MODE_PERIPHERAL:  	case USB_DR_MODE_OTG: @@ -650,7 +842,6 @@ static void dwc3_complete(struct device *dev)  		/* FALLTHROUGH */  	case USB_DR_MODE_HOST:  	default: -		dwc3_event_buffers_setup(dwc);  		break;  	} @@ -680,6 +871,8 @@ static int dwc3_suspend(struct device *dev)  	usb_phy_shutdown(dwc->usb3_phy);  	usb_phy_shutdown(dwc->usb2_phy); +	phy_exit(dwc->usb2_generic_phy); +	phy_exit(dwc->usb3_generic_phy);  	return 0;  } @@ -688,10 +881,17 @@ static int dwc3_resume(struct device *dev)  {  	struct dwc3	*dwc = dev_get_drvdata(dev);  	unsigned long	flags; +	int		ret;  	usb_phy_init(dwc->usb3_phy);  	usb_phy_init(dwc->usb2_phy); -	msleep(100); +	ret = phy_init(dwc->usb2_generic_phy); +	if (ret < 0) +		return ret; + +	ret = phy_init(dwc->usb3_generic_phy); +	if (ret < 0) +		goto err_usb2phy_init;  	spin_lock_irqsave(&dwc->lock, flags); @@ -715,6 +915,11 @@ static int dwc3_resume(struct device *dev)  	pm_runtime_enable(dev);  	return 0; + +err_usb2phy_init: +	phy_exit(dwc->usb2_generic_phy); + +	return ret;  }  static const struct dev_pm_ops dwc3_dev_pm_ops = { diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index f8af8d44af8..57332e3768e 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -31,11 +31,14 @@  #include <linux/usb/gadget.h>  #include <linux/usb/otg.h> +#include <linux/phy/phy.h> +  /* Global constants */  #define DWC3_EP0_BOUNCE_SIZE	512  #define DWC3_ENDPOINTS_NUM	32  #define DWC3_XHCI_RESOURCES_NUM	2 +#define DWC3_SCRATCHBUF_SIZE	4096	/* each buffer is assumed to be 4KiB */  #define DWC3_EVENT_SIZE		4	/* bytes */  #define DWC3_EVENT_MAX_NUM	64	/* 2 events/endpoint */  #define DWC3_EVENT_BUFFERS_SIZE	(DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM) @@ -157,6 +160,7 @@  #define DWC3_GCTL_PRTCAP_OTG	3  #define DWC3_GCTL_CORESOFTRESET		(1 << 11) +#define DWC3_GCTL_SOFITPSYNC		(1 << 10)  #define DWC3_GCTL_SCALEDOWN(n)		((n) << 4)  #define DWC3_GCTL_SCALEDOWN_MASK	DWC3_GCTL_SCALEDOWN(3)  #define DWC3_GCTL_DISSCRAMBLE		(1 << 3) @@ -318,7 +322,7 @@  /* Device Endpoint Command Register */  #define DWC3_DEPCMD_PARAM_SHIFT		16  #define DWC3_DEPCMD_PARAM(x)		((x) << DWC3_DEPCMD_PARAM_SHIFT) -#define DWC3_DEPCMD_GET_RSC_IDX(x)     (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f) +#define DWC3_DEPCMD_GET_RSC_IDX(x)	(((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)  #define DWC3_DEPCMD_STATUS(x)		(((x) >> 15) & 1)  #define DWC3_DEPCMD_HIPRI_FORCERM	(1 << 11)  #define DWC3_DEPCMD_CMDACT		(1 << 10) @@ -393,6 +397,7 @@ struct dwc3_event_buffer {   * @busy_slot: first slot which is owned by HW   * @desc: usb_endpoint_descriptor pointer   * @dwc: pointer to DWC controller + * @saved_state: ep state saved during hibernation   * @flags: endpoint flags (wedged, stalled, ...)   * @current_trb: index of current used trb   * @number: endpoint number (1 - 15) @@ -415,6 +420,7 @@ struct dwc3_ep {  	const struct usb_ss_ep_comp_descriptor *comp_desc;  	struct dwc3		*dwc; +	u32			saved_state;  	unsigned		flags;  #define DWC3_EP_ENABLED		(1 << 0)  #define DWC3_EP_STALL		(1 << 1) @@ -598,6 +604,7 @@ struct dwc3_scratchpad_array {   * @ep0_trb: dma address of ep0_trb   * @ep0_usb_req: dummy req used while handling STD USB requests   * @ep0_bounce_addr: dma address of ep0_bounce + * @scratch_addr: dma address of scratchbuf   * @lock: for synchronizing   * @dev: pointer to our struct device   * @xhci: pointer to our xHCI child @@ -606,6 +613,7 @@ struct dwc3_scratchpad_array {   * @gadget_driver: pointer to the gadget driver   * @regs: base address for our registers   * @regs_size: address space size + * @nr_scratch: number of scratch buffers   * @num_event_buffers: calculated number of event buffers   * @u1u2: only used on revisions <1.83a for workaround   * @maximum_speed: maximum speed requested (mainly for testing purposes) @@ -613,16 +621,10 @@ struct dwc3_scratchpad_array {   * @dr_mode: requested mode of operation   * @usb2_phy: pointer to USB2 PHY   * @usb3_phy: pointer to USB3 PHY + * @usb2_generic_phy: pointer to USB2 PHY + * @usb3_generic_phy: pointer to USB3 PHY   * @dcfg: saved contents of DCFG register   * @gctl: saved contents of GCTL register - * @is_selfpowered: true when we are selfpowered - * @three_stage_setup: set if we perform a three phase setup - * @ep0_bounced: true when we used bounce buffer - * @ep0_expect_in: true when we expect a DATA IN transfer - * @start_config_issued: true when StartConfig command has been issued - * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround - * @needs_fifo_resize: not all users might want fifo resizing, flag it - * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.   * @isoch_delay: wValue from Set Isochronous Delay request;   * @u2sel: parameter from Set SEL request.   * @u2pel: parameter from Set SEL request. @@ -637,15 +639,31 @@ struct dwc3_scratchpad_array {   * @mem: points to start of memory which is used for this struct.   * @hwparams: copy of hwparams registers   * @root: debugfs root folder pointer + * @regset: debugfs pointer to regdump file + * @test_mode: true when we're entering a USB test mode + * @test_mode_nr: test feature selector + * @delayed_status: true when gadget driver asks for delayed status + * @ep0_bounced: true when we used bounce buffer + * @ep0_expect_in: true when we expect a DATA IN transfer + * @has_hibernation: true when dwc3 was configured with Hibernation + * @is_selfpowered: true when we are selfpowered + * @needs_fifo_resize: not all users might want fifo resizing, flag it + * @pullups_connected: true when Run/Stop bit is set + * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes. + * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround + * @start_config_issued: true when StartConfig command has been issued + * @three_stage_setup: set if we perform a three phase setup   */  struct dwc3 {  	struct usb_ctrlrequest	*ctrl_req;  	struct dwc3_trb		*ep0_trb;  	void			*ep0_bounce; +	void			*scratchbuf;  	u8			*setup_buf;  	dma_addr_t		ctrl_req_addr;  	dma_addr_t		ep0_trb_addr;  	dma_addr_t		ep0_bounce_addr; +	dma_addr_t		scratch_addr;  	struct dwc3_request	ep0_usb_req;  	/* device lock */ @@ -665,6 +683,9 @@ struct dwc3 {  	struct usb_phy		*usb2_phy;  	struct usb_phy		*usb3_phy; +	struct phy		*usb2_generic_phy; +	struct phy		*usb3_generic_phy; +  	void __iomem		*regs;  	size_t			regs_size; @@ -674,6 +695,7 @@ struct dwc3 {  	u32			dcfg;  	u32			gctl; +	u32			nr_scratch;  	u32			num_event_buffers;  	u32			u1u2;  	u32			maximum_speed; @@ -695,17 +717,9 @@ struct dwc3 {  #define DWC3_REVISION_230A	0x5533230a  #define DWC3_REVISION_240A	0x5533240a  #define DWC3_REVISION_250A	0x5533250a - -	unsigned		is_selfpowered:1; -	unsigned		three_stage_setup:1; -	unsigned		ep0_bounced:1; -	unsigned		ep0_expect_in:1; -	unsigned		start_config_issued:1; -	unsigned		setup_packet_pending:1; -	unsigned		delayed_status:1; -	unsigned		needs_fifo_resize:1; -	unsigned		resize_fifos:1; -	unsigned		pullups_connected:1; +#define DWC3_REVISION_260A	0x5533260a +#define DWC3_REVISION_270A	0x5533270a +#define DWC3_REVISION_280A	0x5533280a  	enum dwc3_ep0_next	ep0_next_event;  	enum dwc3_ep0_state	ep0state; @@ -730,6 +744,18 @@ struct dwc3 {  	u8			test_mode;  	u8			test_mode_nr; + +	unsigned		delayed_status:1; +	unsigned		ep0_bounced:1; +	unsigned		ep0_expect_in:1; +	unsigned		has_hibernation:1; +	unsigned		is_selfpowered:1; +	unsigned		needs_fifo_resize:1; +	unsigned		pullups_connected:1; +	unsigned		resize_fifos:1; +	unsigned		setup_packet_pending:1; +	unsigned		start_config_issued:1; +	unsigned		three_stage_setup:1;  };  /* -------------------------------------------------------------------------- */ @@ -815,15 +841,15 @@ struct dwc3_event_depevt {   *	12	- VndrDevTstRcved   * @reserved15_12: Reserved, not used   * @event_info: Information about this event - * @reserved31_24: Reserved, not used + * @reserved31_25: Reserved, not used   */  struct dwc3_event_devt {  	u32	one_bit:1;  	u32	device_event:7;  	u32	type:4;  	u32	reserved15_12:4; -	u32	event_info:8; -	u32	reserved31_24:8; +	u32	event_info:9; +	u32	reserved31_25:7;  } __packed;  /** @@ -856,6 +882,19 @@ union dwc3_event {  	struct dwc3_event_gevt		gevt;  }; +/** + * struct dwc3_gadget_ep_cmd_params - representation of endpoint command + * parameters + * @param2: third parameter + * @param1: second parameter + * @param0: first parameter + */ +struct dwc3_gadget_ep_cmd_params { +	u32	param2; +	u32	param1; +	u32	param0; +}; +  /*   * DWC3 Features to be used as Driver Data   */ @@ -881,11 +920,31 @@ static inline void dwc3_host_exit(struct dwc3 *dwc)  #if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)  int dwc3_gadget_init(struct dwc3 *dwc);  void dwc3_gadget_exit(struct dwc3 *dwc); +int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode); +int dwc3_gadget_get_link_state(struct dwc3 *dwc); +int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); +int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, +		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); +int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param);  #else  static inline int dwc3_gadget_init(struct dwc3 *dwc)  { return 0; }  static inline void dwc3_gadget_exit(struct dwc3 *dwc)  { } +static inline int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) +{ return 0; } +static inline int dwc3_gadget_get_link_state(struct dwc3 *dwc) +{ return 0; } +static inline int dwc3_gadget_set_link_state(struct dwc3 *dwc, +		enum dwc3_link_state state) +{ return 0; } + +static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, +		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) +{ return 0; } +static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc, +		int cmd, u32 param) +{ return 0; }  #endif  /* power management interface */ diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index 2f2e88a3a11..f9fb8adb785 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -24,9 +24,10 @@  #include <linux/dma-mapping.h>  #include <linux/clk.h>  #include <linux/usb/otg.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <linux/of.h>  #include <linux/of_platform.h> +#include <linux/regulator/consumer.h>  struct dwc3_exynos {  	struct platform_device	*usb2_phy; @@ -34,28 +35,31 @@ struct dwc3_exynos {  	struct device		*dev;  	struct clk		*clk; +	struct regulator	*vdd33; +	struct regulator	*vdd10;  };  static int dwc3_exynos_register_phys(struct dwc3_exynos *exynos)  { -	struct usb_phy_gen_xceiv_platform_data pdata; +	struct usb_phy_generic_platform_data pdata;  	struct platform_device	*pdev;  	int			ret;  	memset(&pdata, 0x00, sizeof(pdata)); -	pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); +	pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO);  	if (!pdev)  		return -ENOMEM;  	exynos->usb2_phy = pdev;  	pdata.type = USB_PHY_TYPE_USB2; +	pdata.gpio_reset = -1;  	ret = platform_device_add_data(exynos->usb2_phy, &pdata, sizeof(pdata));  	if (ret)  		goto err1; -	pdev = platform_device_alloc("usb_phy_gen_xceiv", PLATFORM_DEVID_AUTO); +	pdev = platform_device_alloc("usb_phy_generic", PLATFORM_DEVID_AUTO);  	if (!pdev) {  		ret = -ENOMEM;  		goto err1; @@ -106,12 +110,12 @@ static int dwc3_exynos_probe(struct platform_device *pdev)  	struct device		*dev = &pdev->dev;  	struct device_node	*node = dev->of_node; -	int			ret = -ENOMEM; +	int			ret;  	exynos = devm_kzalloc(dev, sizeof(*exynos), GFP_KERNEL);  	if (!exynos) {  		dev_err(dev, "not enough memory\n"); -		goto err1; +		return -ENOMEM;  	}  	/* @@ -119,24 +123,22 @@ static int dwc3_exynos_probe(struct platform_device *pdev)  	 * Since shared usb code relies on it, set it here for now.  	 * Once we move to full device tree support this will vanish off.  	 */ -	if (!dev->dma_mask) -		dev->dma_mask = &dev->coherent_dma_mask; -	if (!dev->coherent_dma_mask) -		dev->coherent_dma_mask = DMA_BIT_MASK(32); +	ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); +	if (ret) +		return ret;  	platform_set_drvdata(pdev, exynos);  	ret = dwc3_exynos_register_phys(exynos);  	if (ret) {  		dev_err(dev, "couldn't register PHYs\n"); -		goto err1; +		return ret;  	}  	clk = devm_clk_get(dev, "usbdrd30");  	if (IS_ERR(clk)) {  		dev_err(dev, "couldn't get clock\n"); -		ret = -EINVAL; -		goto err1; +		return -EINVAL;  	}  	exynos->dev	= dev; @@ -144,23 +146,48 @@ static int dwc3_exynos_probe(struct platform_device *pdev)  	clk_prepare_enable(exynos->clk); +	exynos->vdd33 = devm_regulator_get(dev, "vdd33"); +	if (IS_ERR(exynos->vdd33)) { +		ret = PTR_ERR(exynos->vdd33); +		goto err2; +	} +	ret = regulator_enable(exynos->vdd33); +	if (ret) { +		dev_err(dev, "Failed to enable VDD33 supply\n"); +		goto err2; +	} + +	exynos->vdd10 = devm_regulator_get(dev, "vdd10"); +	if (IS_ERR(exynos->vdd10)) { +		ret = PTR_ERR(exynos->vdd10); +		goto err3; +	} +	ret = regulator_enable(exynos->vdd10); +	if (ret) { +		dev_err(dev, "Failed to enable VDD10 supply\n"); +		goto err3; +	} +  	if (node) {  		ret = of_platform_populate(node, NULL, NULL, dev);  		if (ret) {  			dev_err(dev, "failed to add dwc3 core\n"); -			goto err2; +			goto err4;  		}  	} else {  		dev_err(dev, "no device node, failed to add dwc3 core\n");  		ret = -ENODEV; -		goto err2; +		goto err4;  	}  	return 0; +err4: +	regulator_disable(exynos->vdd10); +err3: +	regulator_disable(exynos->vdd33);  err2:  	clk_disable_unprepare(clk); -err1:  	return ret;  } @@ -174,6 +201,9 @@ static int dwc3_exynos_remove(struct platform_device *pdev)  	clk_disable_unprepare(exynos->clk); +	regulator_disable(exynos->vdd33); +	regulator_disable(exynos->vdd10); +  	return 0;  } @@ -192,12 +222,27 @@ static int dwc3_exynos_suspend(struct device *dev)  	clk_disable(exynos->clk); +	regulator_disable(exynos->vdd33); +	regulator_disable(exynos->vdd10); +  	return 0;  }  static int dwc3_exynos_resume(struct device *dev)  {  	struct dwc3_exynos *exynos = dev_get_drvdata(dev); +	int ret; + +	ret = regulator_enable(exynos->vdd33); +	if (ret) { +		dev_err(dev, "Failed to enable VDD33 supply\n"); +		return ret; +	} +	ret = regulator_enable(exynos->vdd10); +	if (ret) { +		dev_err(dev, "Failed to enable VDD10 supply\n"); +		return ret; +	}  	clk_enable(exynos->clk); diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c new file mode 100644 index 00000000000..1fad1618df6 --- /dev/null +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -0,0 +1,202 @@ +/** + * dwc3-keystone.c - Keystone Specific Glue layer + * + * Copyright (C) 2010-2013 Texas Instruments Incorporated - http://www.ti.com + * + * Author: WingMan Kwok <w-kwok2@ti.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2  of + * the License as published by the Free Software Foundation. + * + * 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/clk.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/of_platform.h> + +/* USBSS register offsets */ +#define USBSS_REVISION		0x0000 +#define USBSS_SYSCONFIG		0x0010 +#define USBSS_IRQ_EOI		0x0018 +#define USBSS_IRQSTATUS_RAW_0	0x0020 +#define USBSS_IRQSTATUS_0	0x0024 +#define USBSS_IRQENABLE_SET_0	0x0028 +#define USBSS_IRQENABLE_CLR_0	0x002c + +/* IRQ register bits */ +#define USBSS_IRQ_EOI_LINE(n)	BIT(n) +#define USBSS_IRQ_EVENT_ST	BIT(0) +#define USBSS_IRQ_COREIRQ_EN	BIT(0) +#define USBSS_IRQ_COREIRQ_CLR	BIT(0) + +static u64 kdwc3_dma_mask; + +struct dwc3_keystone { +	struct device			*dev; +	struct clk			*clk; +	void __iomem			*usbss; +}; + +static inline u32 kdwc3_readl(void __iomem *base, u32 offset) +{ +	return readl(base + offset); +} + +static inline void kdwc3_writel(void __iomem *base, u32 offset, u32 value) +{ +	writel(value, base + offset); +} + +static void kdwc3_enable_irqs(struct dwc3_keystone *kdwc) +{ +	u32 val; + +	val = kdwc3_readl(kdwc->usbss, USBSS_IRQENABLE_SET_0); +	val |= USBSS_IRQ_COREIRQ_EN; +	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, val); +} + +static void kdwc3_disable_irqs(struct dwc3_keystone *kdwc) +{ +	u32 val; + +	val = kdwc3_readl(kdwc->usbss, USBSS_IRQENABLE_SET_0); +	val &= ~USBSS_IRQ_COREIRQ_EN; +	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, val); +} + +static irqreturn_t dwc3_keystone_interrupt(int irq, void *_kdwc) +{ +	struct dwc3_keystone	*kdwc = _kdwc; + +	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_CLR_0, USBSS_IRQ_COREIRQ_CLR); +	kdwc3_writel(kdwc->usbss, USBSS_IRQSTATUS_0, USBSS_IRQ_EVENT_ST); +	kdwc3_writel(kdwc->usbss, USBSS_IRQENABLE_SET_0, USBSS_IRQ_COREIRQ_EN); +	kdwc3_writel(kdwc->usbss, USBSS_IRQ_EOI, USBSS_IRQ_EOI_LINE(0)); + +	return IRQ_HANDLED; +} + +static int kdwc3_probe(struct platform_device *pdev) +{ +	struct device		*dev = &pdev->dev; +	struct device_node	*node = pdev->dev.of_node; +	struct dwc3_keystone	*kdwc; +	struct resource		*res; +	int			error, irq; + +	kdwc = devm_kzalloc(dev, sizeof(*kdwc), GFP_KERNEL); +	if (!kdwc) +		return -ENOMEM; + +	platform_set_drvdata(pdev, kdwc); + +	kdwc->dev = dev; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!res) { +		dev_err(dev, "missing usbss resource\n"); +		return -EINVAL; +	} + +	kdwc->usbss = devm_ioremap_resource(dev, res); +	if (IS_ERR(kdwc->usbss)) +		return PTR_ERR(kdwc->usbss); + +	kdwc3_dma_mask = dma_get_mask(dev); +	dev->dma_mask = &kdwc3_dma_mask; + +	kdwc->clk = devm_clk_get(kdwc->dev, "usb"); + +	error = clk_prepare_enable(kdwc->clk); +	if (error < 0) { +		dev_dbg(kdwc->dev, "unable to enable usb clock, err %d\n", +			error); +		return error; +	} + +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) { +		dev_err(&pdev->dev, "missing irq\n"); +		goto err_irq; +	} + +	error = devm_request_irq(dev, irq, dwc3_keystone_interrupt, IRQF_SHARED, +			dev_name(dev), kdwc); +	if (error) { +		dev_err(dev, "failed to request IRQ #%d --> %d\n", +				irq, error); +		goto err_irq; +	} + +	kdwc3_enable_irqs(kdwc); + +	error = of_platform_populate(node, NULL, NULL, dev); +	if (error) { +		dev_err(&pdev->dev, "failed to create dwc3 core\n"); +		goto err_core; +	} + +	return 0; + +err_core: +	kdwc3_disable_irqs(kdwc); +err_irq: +	clk_disable_unprepare(kdwc->clk); + +	return error; +} + +static int kdwc3_remove_core(struct device *dev, void *c) +{ +	struct platform_device *pdev = to_platform_device(dev); + +	platform_device_unregister(pdev); + +	return 0; +} + +static int kdwc3_remove(struct platform_device *pdev) +{ +	struct dwc3_keystone *kdwc = platform_get_drvdata(pdev); + +	kdwc3_disable_irqs(kdwc); +	device_for_each_child(&pdev->dev, NULL, kdwc3_remove_core); +	clk_disable_unprepare(kdwc->clk); +	platform_set_drvdata(pdev, NULL); + +	return 0; +} + +static const struct of_device_id kdwc3_of_match[] = { +	{ .compatible = "ti,keystone-dwc3", }, +	{}, +}; +MODULE_DEVICE_TABLE(of, kdwc3_of_match); + +static struct platform_driver kdwc3_driver = { +	.probe		= kdwc3_probe, +	.remove		= kdwc3_remove, +	.driver		= { +		.name	= "keystone-dwc3", +		.owner	        = THIS_MODULE, +		.of_match_table	= kdwc3_of_match, +	}, +}; + +module_platform_driver(kdwc3_driver); + +MODULE_ALIAS("platform:keystone-dwc3"); +MODULE_AUTHOR("WingMan Kwok <w-kwok2@ti.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("DesignWare USB3 KEYSTONE Glue Layer"); diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 7f7ea62e961..07a736acd0f 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -20,7 +20,6 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/interrupt.h> -#include <linux/spinlock.h>  #include <linux/platform_device.h>  #include <linux/platform_data/dwc3-omap.h>  #include <linux/pm_runtime.h> @@ -30,7 +29,6 @@  #include <linux/of.h>  #include <linux/of_platform.h>  #include <linux/extcon.h> -#include <linux/extcon/of_extcon.h>  #include <linux/regulator/consumer.h>  #include <linux/usb/otg.h> @@ -120,9 +118,6 @@  #define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID	(1 << 1)  struct dwc3_omap { -	/* device lock */ -	spinlock_t		lock; -  	struct device		*dev;  	int			irq; @@ -280,8 +275,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)  	struct dwc3_omap	*omap = _omap;  	u32			reg; -	spin_lock(&omap->lock); -  	reg = dwc3_omap_read_irqmisc_status(omap);  	if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) { @@ -322,8 +315,6 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)  	dwc3_omap_write_irq0_status(omap, reg); -	spin_unlock(&omap->lock); -  	return IRQ_HANDLED;  } @@ -331,7 +322,7 @@ static int dwc3_omap_remove_core(struct device *dev, void *c)  {  	struct platform_device *pdev = to_platform_device(dev); -	platform_device_unregister(pdev); +	of_device_unregister(pdev);  	return 0;  } @@ -402,7 +393,7 @@ static int dwc3_omap_probe(struct platform_device *pdev)  	struct extcon_dev	*edev;  	struct regulator	*vbus_reg = NULL; -	int			ret = -ENOMEM; +	int			ret;  	int			irq;  	int			utmi_mode = 0; @@ -432,11 +423,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)  	}  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) { -		dev_err(dev, "missing memory base resource\n"); -		return -EINVAL; -	} -  	base = devm_ioremap_resource(dev, res);  	if (IS_ERR(base))  		return PTR_ERR(base); @@ -449,8 +435,6 @@ static int dwc3_omap_probe(struct platform_device *pdev)  		}  	} -	spin_lock_init(&omap->lock); -  	omap->dev	= dev;  	omap->irq	= irq;  	omap->base	= base; @@ -532,10 +516,10 @@ static int dwc3_omap_probe(struct platform_device *pdev)  	dwc3_omap_enable_irqs(omap);  	if (of_property_read_bool(node, "extcon")) { -		edev = of_extcon_get_extcon_dev(dev, 0); +		edev = extcon_get_edev_by_phandle(dev, 0);  		if (IS_ERR(edev)) {  			dev_vdbg(dev, "couldn't get extcon device\n"); -			ret = PTR_ERR(edev); +			ret = -EPROBE_DEFER;  			goto err2;  		} @@ -615,7 +599,7 @@ static int dwc3_omap_prepare(struct device *dev)  {  	struct dwc3_omap	*omap = dev_get_drvdata(dev); -	dwc3_omap_disable_irqs(omap); +	dwc3_omap_write_irqmisc_set(omap, 0x00);  	return 0;  } @@ -623,8 +607,19 @@ static int dwc3_omap_prepare(struct device *dev)  static void dwc3_omap_complete(struct device *dev)  {  	struct dwc3_omap	*omap = dev_get_drvdata(dev); +	u32			reg; -	dwc3_omap_enable_irqs(omap); +	reg = (USBOTGSS_IRQMISC_OEVT | +			USBOTGSS_IRQMISC_DRVVBUS_RISE | +			USBOTGSS_IRQMISC_CHRGVBUS_RISE | +			USBOTGSS_IRQMISC_DISCHRGVBUS_RISE | +			USBOTGSS_IRQMISC_IDPULLUP_RISE | +			USBOTGSS_IRQMISC_DRVVBUS_FALL | +			USBOTGSS_IRQMISC_CHRGVBUS_FALL | +			USBOTGSS_IRQMISC_DISCHRGVBUS_FALL | +			USBOTGSS_IRQMISC_IDPULLUP_FALL); + +	dwc3_omap_write_irqmisc_set(omap, reg);  }  static int dwc3_omap_suspend(struct device *dev) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 9b138129e85..a60bab7dfa0 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -23,11 +23,13 @@  #include <linux/platform_device.h>  #include <linux/usb/otg.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  /* FIXME define these in <linux/pci_ids.h> */  #define PCI_VENDOR_ID_SYNOPSYS		0x16c3  #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3	0xabcd +#define PCI_DEVICE_ID_INTEL_BYT		0x0f37 +#define PCI_DEVICE_ID_INTEL_MRFLD	0x119e  struct dwc3_pci {  	struct device		*dev; @@ -38,24 +40,25 @@ struct dwc3_pci {  static int dwc3_pci_register_phys(struct dwc3_pci *glue)  { -	struct usb_phy_gen_xceiv_platform_data pdata; +	struct usb_phy_generic_platform_data pdata;  	struct platform_device	*pdev;  	int			ret;  	memset(&pdata, 0x00, sizeof(pdata)); -	pdev = platform_device_alloc("usb_phy_gen_xceiv", 0); +	pdev = platform_device_alloc("usb_phy_generic", 0);  	if (!pdev)  		return -ENOMEM;  	glue->usb2_phy = pdev;  	pdata.type = USB_PHY_TYPE_USB2; +	pdata.gpio_reset = -1;  	ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));  	if (ret)  		goto err1; -	pdev = platform_device_alloc("usb_phy_gen_xceiv", 1); +	pdev = platform_device_alloc("usb_phy_generic", 1);  	if (!pdev) {  		ret = -ENOMEM;  		goto err1; @@ -96,7 +99,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,  	struct resource		res[2];  	struct platform_device	*dwc3;  	struct dwc3_pci		*glue; -	int			ret = -ENOMEM; +	int			ret;  	struct device		*dev = &pci->dev;  	glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); @@ -107,7 +110,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,  	glue->dev = dev; -	ret = pci_enable_device(pci); +	ret = pcim_enable_device(pci);  	if (ret) {  		dev_err(dev, "failed to enable pci device\n");  		return -ENODEV; @@ -124,8 +127,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,  	dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);  	if (!dwc3) {  		dev_err(dev, "couldn't allocate dwc3 device\n"); -		ret = -ENOMEM; -		goto err1; +		return -ENOMEM;  	}  	memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); @@ -142,7 +144,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,  	ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));  	if (ret) {  		dev_err(dev, "couldn't add resources to dwc3 device\n"); -		goto err1; +		return ret;  	}  	pci_set_drvdata(pci, glue); @@ -163,11 +165,7 @@ static int dwc3_pci_probe(struct pci_dev *pci,  	return 0;  err3: -	pci_set_drvdata(pci, NULL);  	platform_device_put(dwc3); -err1: -	pci_disable_device(pci); -  	return ret;  } @@ -178,15 +176,15 @@ static void dwc3_pci_remove(struct pci_dev *pci)  	platform_device_unregister(glue->dwc3);  	platform_device_unregister(glue->usb2_phy);  	platform_device_unregister(glue->usb3_phy); -	pci_set_drvdata(pci, NULL); -	pci_disable_device(pci);  } -static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = { +static const struct pci_device_id dwc3_pci_id_table[] = {  	{  		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,  				PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),  	}, +	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, +	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },  	{  }	/* Terminating Entry */  };  MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 7fa93f4bc50..21a352079bc 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -352,7 +352,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,  		break;  	default:  		return -EINVAL; -	}; +	}  	response_pkt = (__le16 *) dwc->setup_buf;  	*response_pkt = cpu_to_le16(usb_status); @@ -459,6 +459,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,  			dep = dwc3_wIndex_to_dep(dwc, wIndex);  			if (!dep)  				return -EINVAL; +			if (set == 0 && (dep->flags & DWC3_EP_WEDGE)) +				break;  			ret = __dwc3_gadget_ep_set_halt(dep, set);  			if (ret)  				return -EINVAL; @@ -470,7 +472,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,  	default:  		return -EINVAL; -	}; +	}  	return 0;  } @@ -709,7 +711,7 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)  		dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");  		ret = dwc3_ep0_delegate_req(dwc, ctrl);  		break; -	}; +	}  	return ret;  } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index f168eaebdef..dab7927d100 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -68,6 +68,22 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)  }  /** + * dwc3_gadget_get_link_state - Gets current state of USB Link + * @dwc: pointer to our context structure + * + * Caller should take care of locking. This function will + * return the link state on success (>= 0) or -ETIMEDOUT. + */ +int dwc3_gadget_get_link_state(struct dwc3 *dwc) +{ +	u32		reg; + +	reg = dwc3_readl(dwc->regs, DWC3_DSTS); + +	return DWC3_DSTS_USBLNKST(reg); +} + +/**   * dwc3_gadget_set_link_state - Sets USB Link to a particular State   * @dwc: pointer to our context structure   * @state: the state to put link into @@ -171,15 +187,12 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)  	 * improve this algorithm so that we better use the internal  	 * FIFO space  	 */ -	for (num = 0; num < DWC3_ENDPOINTS_NUM; num++) { -		struct dwc3_ep	*dep = dwc->eps[num]; -		int		fifo_number = dep->number >> 1; +	for (num = 0; num < dwc->num_in_eps; num++) { +		/* bit0 indicates direction; 1 means IN ep */ +		struct dwc3_ep	*dep = dwc->eps[(num << 1) | 1];  		int		mult = 1;  		int		tmp; -		if (!(dep->number & 1)) -			continue; -  		if (!(dep->flags & DWC3_EP_ENABLED))  			continue; @@ -208,8 +221,7 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)  		dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",  				dep->name, last_fifo_depth, fifo_size & 0xffff); -		dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(fifo_number), -				fifo_size); +		dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);  		last_fifo_depth += (fifo_size & 0xffff);  	} @@ -286,11 +298,76 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd)  	}  } +static const char *dwc3_gadget_generic_cmd_string(u8 cmd) +{ +	switch (cmd) { +	case DWC3_DGCMD_SET_LMP: +		return "Set LMP"; +	case DWC3_DGCMD_SET_PERIODIC_PAR: +		return "Set Periodic Parameters"; +	case DWC3_DGCMD_XMIT_FUNCTION: +		return "Transmit Function Wake Device Notification"; +	case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO: +		return "Set Scratchpad Buffer Array Address Lo"; +	case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI: +		return "Set Scratchpad Buffer Array Address Hi"; +	case DWC3_DGCMD_SELECTED_FIFO_FLUSH: +		return "Selected FIFO Flush"; +	case DWC3_DGCMD_ALL_FIFO_FLUSH: +		return "All FIFO Flush"; +	case DWC3_DGCMD_SET_ENDPOINT_NRDY: +		return "Set Endpoint NRDY"; +	case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK: +		return "Run SoC Bus Loopback Test"; +	default: +		return "UNKNOWN"; +	} +} + +static const char *dwc3_gadget_link_string(enum dwc3_link_state link_state) +{ +	switch (link_state) { +	case DWC3_LINK_STATE_U0: +		return "U0"; +	case DWC3_LINK_STATE_U1: +		return "U1"; +	case DWC3_LINK_STATE_U2: +		return "U2"; +	case DWC3_LINK_STATE_U3: +		return "U3"; +	case DWC3_LINK_STATE_SS_DIS: +		return "SS.Disabled"; +	case DWC3_LINK_STATE_RX_DET: +		return "RX.Detect"; +	case DWC3_LINK_STATE_SS_INACT: +		return "SS.Inactive"; +	case DWC3_LINK_STATE_POLL: +		return "Polling"; +	case DWC3_LINK_STATE_RECOV: +		return "Recovery"; +	case DWC3_LINK_STATE_HRESET: +		return "Hot Reset"; +	case DWC3_LINK_STATE_CMPLY: +		return "Compliance"; +	case DWC3_LINK_STATE_LPBK: +		return "Loopback"; +	case DWC3_LINK_STATE_RESET: +		return "Reset"; +	case DWC3_LINK_STATE_RESUME: +		return "Resume"; +	default: +		return "UNKNOWN link state\n"; +	} +} +  int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param)  {  	u32		timeout = 500;  	u32		reg; +	dev_vdbg(dwc->dev, "generic cmd '%s' [%d] param %08x\n", +			dwc3_gadget_generic_cmd_string(cmd), cmd, param); +  	dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);  	dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT); @@ -320,9 +397,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,  	u32			timeout = 500;  	u32			reg; -	dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n", +	dev_vdbg(dwc->dev, "%s: cmd '%s' [%d] params %08x %08x %08x\n",  			dep->name, -			dwc3_gadget_ep_cmd_string(cmd), params->param0, +			dwc3_gadget_ep_cmd_string(cmd), cmd, params->param0,  			params->param1, params->param2);  	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0); @@ -417,7 +494,7 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)  static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,  		const struct usb_endpoint_descriptor *desc,  		const struct usb_ss_ep_comp_descriptor *comp_desc, -		bool ignore) +		bool ignore, bool restore)  {  	struct dwc3_gadget_ep_cmd_params params; @@ -436,6 +513,11 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,  	if (ignore)  		params.param0 |= DWC3_DEPCFG_IGN_SEQ_NUM; +	if (restore) { +		params.param0 |= DWC3_DEPCFG_ACTION_RESTORE; +		params.param2 |= dep->saved_state; +	} +  	params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN  		| DWC3_DEPCFG_XFER_NOT_READY_EN; @@ -494,11 +576,11 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)  static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,  		const struct usb_endpoint_descriptor *desc,  		const struct usb_ss_ep_comp_descriptor *comp_desc, -		bool ignore) +		bool ignore, bool restore)  {  	struct dwc3		*dwc = dep->dwc;  	u32			reg; -	int			ret = -ENOMEM; +	int			ret;  	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name); @@ -508,7 +590,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,  			return ret;  	} -	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore); +	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc, ignore, +			restore);  	if (ret)  		return ret; @@ -548,13 +631,13 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,  	return 0;  } -static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum); +static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);  static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)  {  	struct dwc3_request		*req;  	if (!list_empty(&dep->req_queued)) { -		dwc3_stop_active_transfer(dwc, dep->number); +		dwc3_stop_active_transfer(dwc, dep->number, true);  		/* - giveback all requests to gadget driver */  		while (!list_empty(&dep->req_queued)) { @@ -586,6 +669,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)  	dwc3_remove_requests(dwc, dep); +	/* make sure HW endpoint isn't stalled */ +	if (dep->flags & DWC3_EP_STALL) +		__dwc3_gadget_ep_set_halt(dep, 0); +  	reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);  	reg &= ~DWC3_DALEPENA_EP(dep->number);  	dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); @@ -659,7 +746,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,  	}  	spin_lock_irqsave(&dwc->lock, flags); -	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false); +	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false);  	spin_unlock_irqrestore(&dwc->lock, flags);  	return ret; @@ -741,10 +828,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,  			length, last ? " last" : "",  			chain ? " chain" : ""); -	/* Skip the LINK-TRB on ISOC */ -	if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && -			usb_endpoint_xfer_isoc(dep->endpoint.desc)) -		dep->free_slot++;  	trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK]; @@ -756,6 +839,10 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,  	}  	dep->free_slot++; +	/* Skip the LINK-TRB on ISOC */ +	if (((dep->free_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && +			usb_endpoint_xfer_isoc(dep->endpoint.desc)) +		dep->free_slot++;  	trb->size = DWC3_TRB_SIZE_LENGTH(length);  	trb->bpl = lower_32_bits(dma); @@ -771,9 +858,6 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,  			trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;  		else  			trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS; - -		if (!req->request.no_interrupt && !chain) -			trb->ctrl |= DWC3_TRB_CTRL_IOC;  		break;  	case USB_ENDPOINT_XFER_BULK: @@ -788,6 +872,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,  		BUG();  	} +	if (!req->request.no_interrupt && !chain) +		trb->ctrl |= DWC3_TRB_CTRL_IOC; +  	if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {  		trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;  		trb->ctrl |= DWC3_TRB_CTRL_CSP; @@ -1077,7 +1164,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)  		 */  		if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {  			if (list_empty(&dep->req_queued)) { -				dwc3_stop_active_transfer(dwc, dep->number); +				dwc3_stop_active_transfer(dwc, dep->number, true);  				dep->flags = DWC3_EP_ENABLED;  			}  			return 0; @@ -1107,6 +1194,23 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)  		return ret;  	} +	/* +	 * 4. Stream Capable Bulk Endpoints. We need to start the transfer +	 * right away, otherwise host will not know we have streams to be +	 * handled. +	 */ +	if (dep->stream_capable) { +		int	ret; + +		ret = __dwc3_gadget_kick_transfer(dep, 0, true); +		if (ret && ret != -EBUSY) { +			struct dwc3	*dwc = dep->dwc; + +			dev_dbg(dwc->dev, "%s: failed to kick transfers\n", +					dep->name); +		} +	} +  	return 0;  } @@ -1163,7 +1267,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,  		}  		if (r == req) {  			/* wait until it is processed */ -			dwc3_stop_active_transfer(dwc, dep->number); +			dwc3_stop_active_transfer(dwc, dep->number, true);  			goto out1;  		}  		dev_err(dwc->dev, "request %p was not queued to %s\n", @@ -1194,23 +1298,18 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)  		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,  			DWC3_DEPCMD_SETSTALL, ¶ms);  		if (ret) -			dev_err(dwc->dev, "failed to %s STALL on %s\n", -					value ? "set" : "clear", +			dev_err(dwc->dev, "failed to set STALL on %s\n",  					dep->name);  		else  			dep->flags |= DWC3_EP_STALL;  	} else { -		if (dep->flags & DWC3_EP_WEDGE) -			return 0; -  		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,  			DWC3_DEPCMD_CLEARSTALL, ¶ms);  		if (ret) -			dev_err(dwc->dev, "failed to %s STALL on %s\n", -					value ? "set" : "clear", +			dev_err(dwc->dev, "failed to clear STALL on %s\n",  					dep->name);  		else -			dep->flags &= ~DWC3_EP_STALL; +			dep->flags &= ~(DWC3_EP_STALL | DWC3_EP_WEDGE);  	}  	return ret; @@ -1390,7 +1489,7 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,  	return 0;  } -static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) +static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)  {  	u32			reg;  	u32			timeout = 500; @@ -1405,9 +1504,17 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)  		if (dwc->revision >= DWC3_REVISION_194A)  			reg &= ~DWC3_DCTL_KEEP_CONNECT;  		reg |= DWC3_DCTL_RUN_STOP; + +		if (dwc->has_hibernation) +			reg |= DWC3_DCTL_KEEP_CONNECT; +  		dwc->pullups_connected = true;  	} else {  		reg &= ~DWC3_DCTL_RUN_STOP; + +		if (dwc->has_hibernation && !suspend) +			reg &= ~DWC3_DCTL_KEEP_CONNECT; +  		dwc->pullups_connected = false;  	} @@ -1445,7 +1552,7 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)  	is_on = !!is_on;  	spin_lock_irqsave(&dwc->lock, flags); -	ret = dwc3_gadget_run_stop(dwc, is_on); +	ret = dwc3_gadget_run_stop(dwc, is_on, false);  	spin_unlock_irqrestore(&dwc->lock, flags);  	return ret; @@ -1552,14 +1659,16 @@ static int dwc3_gadget_start(struct usb_gadget *g,  	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);  	dep = dwc->eps[0]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, +			false);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		goto err2;  	}  	dep = dwc->eps[1]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, +			false);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		goto err3; @@ -1653,7 +1762,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,  		dev_vdbg(dwc->dev, "initializing %s\n", dep->name);  		if (epnum == 0 || epnum == 1) { -			dep->endpoint.maxpacket = 512; +			usb_ep_set_maxpacket_limit(&dep->endpoint, 512);  			dep->endpoint.maxburst = 1;  			dep->endpoint.ops = &dwc3_gadget_ep0_ops;  			if (!epnum) @@ -1661,7 +1770,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,  		} else {  			int		ret; -			dep->endpoint.maxpacket = 1024; +			usb_ep_set_maxpacket_limit(&dep->endpoint, 1024);  			dep->endpoint.max_streams = 15;  			dep->endpoint.ops = &dwc3_gadget_ep_ops;  			list_add_tail(&dep->endpoint.ep_list, @@ -1852,15 +1961,12 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,  			 */  			dep->flags = DWC3_EP_PENDING_REQUEST;  		} else { -			dwc3_stop_active_transfer(dwc, dep->number); +			dwc3_stop_active_transfer(dwc, dep->number, true);  			dep->flags = DWC3_EP_ENABLED;  		}  		return 1;  	} -	if ((event->status & DEPEVT_STATUS_IOC) && -			(trb->ctrl & DWC3_TRB_CTRL_IOC)) -		return 0;  	return 1;  } @@ -2002,7 +2108,25 @@ static void dwc3_disconnect_gadget(struct dwc3 *dwc)  	}  } -static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) +static void dwc3_suspend_gadget(struct dwc3 *dwc) +{ +	if (dwc->gadget_driver && dwc->gadget_driver->suspend) { +		spin_unlock(&dwc->lock); +		dwc->gadget_driver->suspend(&dwc->gadget); +		spin_lock(&dwc->lock); +	} +} + +static void dwc3_resume_gadget(struct dwc3 *dwc) +{ +	if (dwc->gadget_driver && dwc->gadget_driver->resume) { +		spin_unlock(&dwc->lock); +		dwc->gadget_driver->resume(&dwc->gadget); +		spin_lock(&dwc->lock); +	} +} + +static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)  {  	struct dwc3_ep *dep;  	struct dwc3_gadget_ep_cmd_params params; @@ -2034,7 +2158,8 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)  	 */  	cmd = DWC3_DEPCMD_ENDTRANSFER; -	cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC; +	cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0; +	cmd |= DWC3_DEPCMD_CMDIOC;  	cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);  	memset(¶ms, 0, sizeof(params));  	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); @@ -2263,17 +2388,23 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)  		reg |= DWC3_DCTL_HIRD_THRES(12);  		dwc3_writel(dwc->regs, DWC3_DCTL, reg); +	} else { +		reg = dwc3_readl(dwc->regs, DWC3_DCTL); +		reg &= ~DWC3_DCTL_HIRD_THRES_MASK; +		dwc3_writel(dwc->regs, DWC3_DCTL, reg);  	}  	dep = dwc->eps[0]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true, +			false);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		return;  	}  	dep = dwc->eps[1]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, true, +			false);  	if (ret) {  		dev_err(dwc->dev, "failed to enable %s\n", dep->name);  		return; @@ -2379,9 +2510,52 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,  		}  	} +	switch (next) { +	case DWC3_LINK_STATE_U1: +		if (dwc->speed == USB_SPEED_SUPER) +			dwc3_suspend_gadget(dwc); +		break; +	case DWC3_LINK_STATE_U2: +	case DWC3_LINK_STATE_U3: +		dwc3_suspend_gadget(dwc); +		break; +	case DWC3_LINK_STATE_RESUME: +		dwc3_resume_gadget(dwc); +		break; +	default: +		/* do nothing */ +		break; +	} + +	dev_vdbg(dwc->dev, "link change: %s [%d] -> %s [%d]\n", +			dwc3_gadget_link_string(dwc->link_state), +			dwc->link_state, dwc3_gadget_link_string(next), next); +  	dwc->link_state = next; +} + +static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc, +		unsigned int evtinfo) +{ +	unsigned int is_ss = evtinfo & BIT(4); -	dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state); +	/** +	 * WORKAROUND: DWC3 revison 2.20a with hibernation support +	 * have a known issue which can cause USB CV TD.9.23 to fail +	 * randomly. +	 * +	 * Because of this issue, core could generate bogus hibernation +	 * events which SW needs to ignore. +	 * +	 * Refers to: +	 * +	 * STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0 +	 * Device Fallback from SuperSpeed +	 */ +	if (is_ss ^ (dwc->speed == USB_SPEED_SUPER)) +		return; + +	/* enter hibernation here */  }  static void dwc3_gadget_interrupt(struct dwc3 *dwc, @@ -2400,6 +2574,13 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,  	case DWC3_DEVICE_EVENT_WAKEUP:  		dwc3_gadget_wakeup_interrupt(dwc);  		break; +	case DWC3_DEVICE_EVENT_HIBER_REQ: +		if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation, +					"unexpected hibernation event\n")) +			break; + +		dwc3_gadget_hibernation_interrupt(dwc, event->event_info); +		break;  	case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:  		dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);  		break; @@ -2600,6 +2781,12 @@ int dwc3_gadget_init(struct dwc3 *dwc)  	dwc->gadget.name		= "dwc3-gadget";  	/* +	 * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize +	 * on ep out. +	 */ +	dwc->gadget.quirk_ep_out_aligned_size = true; + +	/*  	 * REVISIT: Here we should clear all pending IRQs to be  	 * sure we're starting from a well known location.  	 */ @@ -2611,15 +2798,13 @@ int dwc3_gadget_init(struct dwc3 *dwc)  	ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);  	if (ret) {  		dev_err(dwc->dev, "failed to register udc\n"); -		goto err5; +		goto err4;  	}  	return 0; -err5: -	dwc3_gadget_free_endpoints(dwc); -  err4: +	dwc3_gadget_free_endpoints(dwc);  	dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE,  			dwc->ep0_bounce, dwc->ep0_bounce_addr); @@ -2660,8 +2845,10 @@ void dwc3_gadget_exit(struct dwc3 *dwc)  int dwc3_gadget_prepare(struct dwc3 *dwc)  { -	if (dwc->pullups_connected) +	if (dwc->pullups_connected) {  		dwc3_gadget_disable_irq(dwc); +		dwc3_gadget_run_stop(dwc, true, true); +	}  	return 0;  } @@ -2670,7 +2857,7 @@ void dwc3_gadget_complete(struct dwc3 *dwc)  {  	if (dwc->pullups_connected) {  		dwc3_gadget_enable_irq(dwc); -		dwc3_gadget_run_stop(dwc, true); +		dwc3_gadget_run_stop(dwc, true, false);  	}  } @@ -2693,12 +2880,14 @@ int dwc3_gadget_resume(struct dwc3 *dwc)  	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);  	dep = dwc->eps[0]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, +			false);  	if (ret)  		goto err0;  	dep = dwc->eps[1]; -	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false); +	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false, +			false);  	if (ret)  		goto err1; diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index febe1aa7b71..a0ee75b68a8 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -56,12 +56,6 @@ struct dwc3;  /* DEPXFERCFG parameter 0 */  #define DWC3_DEPXFERCFG_NUM_XFER_RES(n)	((n) & 0xffff) -struct dwc3_gadget_ep_cmd_params { -	u32	param2; -	u32	param1; -	u32	param0; -}; -  /* -------------------------------------------------------------------------- */  #define to_dwc3_request(r)	(container_of(r, struct dwc3_request, request)) @@ -85,9 +79,6 @@ static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)  void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,  		int status); -int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode); -int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); -  void dwc3_ep0_interrupt(struct dwc3 *dwc,  		const struct dwc3_event_depevt *event);  void dwc3_ep0_out_start(struct dwc3 *dwc); @@ -95,9 +86,6 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value);  int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,  		gfp_t gfp_flags);  int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value); -int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, -		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); -int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param);  /**   * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index 5e29ddeb4d3..8cfc3191be5 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -568,10 +568,6 @@ try_again:  		dbgp_printk("Could not find attached debug device\n");  		goto err;  	} -	if (ret < 0) { -		dbgp_printk("Attached device is not a debug device\n"); -		goto err; -	}  	dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint;  	dbgp_endpoint_in = dbgp_desc.bDebugInEndpoint; diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 48cddf3cd6b..ba18e9c110c 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -58,6 +58,20 @@ config USB_GADGET_DEBUG  	   trying to track down.  Never enable these messages for a  	   production build. +config USB_GADGET_VERBOSE +	bool "Verbose debugging Messages (DEVELOPMENT)" +	depends on USB_GADGET_DEBUG +	help +	   Many controller and gadget drivers will print verbose debugging +	   messages if you use this option to ask for those messages. + +	   Avoid enabling these messages, even if you're actively +	   debugging such a driver.  Many drivers will emit so many +	   messages that the driver timings are affected, which will +	   either create new failure modes or remove the one you're +	   trying to track down.  Never enable these messages for a +	   production build. +  config USB_GADGET_DEBUG_FILES  	boolean "Debugging information files (DEVELOPMENT)"  	depends on PROC_FS @@ -143,7 +157,7 @@ config USB_AT91  config USB_LPC32XX  	tristate "LPC32XX USB Peripheral Controller" -	depends on ARCH_LPC32XX +	depends on ARCH_LPC32XX && I2C  	select USB_ISP1301  	help  	   This option selects the USB device controller in the LPC32xx SoC. @@ -202,10 +216,17 @@ config USB_FOTG210_UDC  	   Say "y" to link the driver statically, or "m" to build a  	   dynamically linked module called "fotg210_udc". +config USB_GR_UDC +       tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver" +       depends on HAS_DMA +       help +          Select this to support Aeroflex Gaisler GRUSBDC cores from the GRLIB +	  VHDL IP core library. +  config USB_OMAP  	tristate "OMAP USB Device Controller"  	depends on ARCH_OMAP1 -	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG +	depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3)  	help  	   Many Texas Instruments OMAP processors have flexible full  	   speed USB device controllers, with support for up to 30 @@ -279,13 +300,6 @@ config USB_PXA27X  	   dynamically linked module called "pxa27x_udc" and force all  	   gadget drivers to also be dynamically linked. -config USB_S3C_HSOTG -	tristate "S3C HS/OtG USB Device controller" -	depends on S3C_DEV_USB_HSOTG -	help -	  The Samsung S3C64XX USB2.0 high-speed gadget controller -	  integrated into the S3C64XX series SoC. -  config USB_S3C2410  	tristate "S3C2410 USB Device Controller"  	depends on ARCH_S3C24XX @@ -498,9 +512,6 @@ config USB_U_SERIAL  config USB_U_ETHER  	tristate -config USB_U_RNDIS -	tristate -  config USB_F_SERIAL  	tristate @@ -525,6 +536,12 @@ config USB_F_SUBSET  config USB_F_RNDIS  	tristate +config USB_F_MASS_STORAGE +	tristate + +config USB_F_FS +	tristate +  choice  	tristate "USB Gadget Drivers"  	default USB_ETH @@ -625,7 +642,6 @@ config USB_CONFIGFS_RNDIS  	depends on USB_CONFIGFS  	depends on NET  	select USB_U_ETHER -	select USB_U_RNDIS  	select USB_F_RNDIS  	help  	   Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol, @@ -662,6 +678,42 @@ config USB_CONFIGFS_PHONET  	help  	  The Phonet protocol implementation for USB device. +config USB_CONFIGFS_MASS_STORAGE +	boolean "Mass storage" +	depends on USB_CONFIGFS +	depends on BLOCK +	select USB_F_MASS_STORAGE +	help +	  The Mass Storage Gadget acts as a USB Mass Storage disk drive. +	  As its storage repository it can use a regular file or a block +	  device (in much the same way as the "loop" device driver), +	  specified as a module parameter or sysfs option. + +config USB_CONFIGFS_F_LB_SS +	boolean "Loopback and sourcesink function (for testing)" +	depends on USB_CONFIGFS +	select USB_F_SS_LB +	help +	  Loopback function loops back a configurable number of transfers. +	  Sourcesink function either sinks and sources bulk data. +	  It also implements control requests, for "chapter 9" conformance. +	  Make this be the first driver you try using on top of any new +	  USB peripheral controller driver.  Then you can use host-side +	  test software, like the "usbtest" driver, to put your hardware +	  and its driver through a basic set of functional tests. + +config USB_CONFIGFS_F_FS +	boolean "Function filesystem (FunctionFS)" +	depends on USB_CONFIGFS +	select USB_F_FS +	help +	  The Function Filesystem (FunctionFS) lets one create USB +	  composite functions in user space in the same way GadgetFS +	  lets one create USB gadgets in user space.  This allows creation +	  of composite gadgets such that some of the functions are +	  implemented in kernel space (for instance Ethernet, serial or +	  mass storage) and other are implemented in user space. +  config USB_ZERO  	tristate "Gadget Zero (DEVELOPMENT)"  	select USB_LIBCOMPOSITE @@ -732,7 +784,6 @@ config USB_ETH  	depends on NET  	select USB_LIBCOMPOSITE  	select USB_U_ETHER -	select USB_U_RNDIS  	select USB_F_ECM  	select USB_F_SUBSET  	select CRC32 @@ -836,6 +887,7 @@ config USB_GADGETFS  config USB_FUNCTIONFS  	tristate "Function Filesystem"  	select USB_LIBCOMPOSITE +	select USB_F_FS  	select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)  	help  	  The Function Filesystem (FunctionFS) lets one create USB @@ -855,6 +907,8 @@ config USB_FUNCTIONFS_ETH  	bool "Include configuration with CDC ECM (Ethernet)"  	depends on USB_FUNCTIONFS && NET  	select USB_U_ETHER +	select USB_F_ECM +	select USB_F_SUBSET  	help  	  Include a configuration with CDC ECM function (Ethernet) and the  	  Function Filesystem. @@ -863,7 +917,7 @@ config USB_FUNCTIONFS_RNDIS  	bool "Include configuration with RNDIS (Ethernet)"  	depends on USB_FUNCTIONFS && NET  	select USB_U_ETHER -	select USB_U_RNDIS +	select USB_F_RNDIS  	help  	  Include a configuration with RNDIS function (Ethernet) and the Filesystem. @@ -878,6 +932,7 @@ config USB_MASS_STORAGE  	tristate "Mass Storage Gadget"  	depends on BLOCK  	select USB_LIBCOMPOSITE +	select USB_F_MASS_STORAGE  	help  	  The Mass Storage Gadget acts as a USB Mass Storage disk drive.  	  As its storage repository it can use a regular file or a block @@ -1001,6 +1056,7 @@ config USB_G_ACM_MS  	select USB_LIBCOMPOSITE  	select USB_U_SERIAL  	select USB_F_ACM +	select USB_F_MASS_STORAGE  	help  	  This driver provides two functions in one configuration:  	  a mass storage, and a CDC ACM (serial port) link. @@ -1015,8 +1071,8 @@ config USB_G_MULTI  	select USB_LIBCOMPOSITE  	select USB_U_SERIAL  	select USB_U_ETHER -	select USB_U_RNDIS  	select USB_F_ACM +	select USB_F_MASS_STORAGE  	help  	  The Multifunction Composite Gadget provides Ethernet (RNDIS  	  and/or CDC Ethernet), mass storage and ACM serial link @@ -1035,6 +1091,7 @@ config USB_G_MULTI  config USB_G_MULTI_RNDIS  	bool "RNDIS + CDC Serial + Storage configuration"  	depends on USB_G_MULTI +	select USB_F_RNDIS  	default y  	help  	  This option enables a configuration with RNDIS, CDC Serial and @@ -1048,6 +1105,7 @@ config USB_G_MULTI_CDC  	bool "CDC Ethernet + CDC Serial + Storage configuration"  	depends on USB_G_MULTI  	default n +	select USB_F_ECM  	help  	  This option enables a configuration with CDC Ethernet (ECM), CDC  	  Serial and Mass Storage functions available in the Multifunction diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 386db9daf1d..49514ea60a9 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -1,12 +1,13 @@  #  # USB peripheral controller drivers  # -ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG +ccflags-$(CONFIG_USB_GADGET_DEBUG)	:= -DDEBUG +ccflags-$(CONFIG_USB_GADGET_VERBOSE)	+= -DVERBOSE_DEBUG  obj-$(CONFIG_USB_GADGET)	+= udc-core.o  obj-$(CONFIG_USB_LIBCOMPOSITE)	+= libcomposite.o  libcomposite-y			:= usbstring.o config.o epautoconf.o -libcomposite-y			+= composite.o functions.o configfs.o +libcomposite-y			+= composite.o functions.o configfs.o u_f.o  obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o  obj-$(CONFIG_USB_NET2272)	+= net2272.o  obj-$(CONFIG_USB_NET2280)	+= net2280.o @@ -25,7 +26,6 @@ fsl_usb2_udc-$(CONFIG_ARCH_MXC)	+= fsl_mxc_udc.o  obj-$(CONFIG_USB_M66592)	+= m66592-udc.o  obj-$(CONFIG_USB_R8A66597)	+= r8a66597-udc.o  obj-$(CONFIG_USB_FSL_QE)	+= fsl_qe_udc.o -obj-$(CONFIG_USB_S3C_HSOTG)	+= s3c-hsotg.o  obj-$(CONFIG_USB_S3C_HSUDC)	+= s3c-hsudc.o  obj-$(CONFIG_USB_LPC32XX)	+= lpc32xx_udc.o  obj-$(CONFIG_USB_EG20T)		+= pch_udc.o @@ -34,6 +34,7 @@ mv_udc-y			:= mv_udc_core.o  obj-$(CONFIG_USB_FUSB300)	+= fusb300_udc.o  obj-$(CONFIG_USB_FOTG210_UDC)	+= fotg210-udc.o  obj-$(CONFIG_USB_MV_U3D)	+= mv_u3d_core.o +obj-$(CONFIG_USB_GR_UDC)	+= gr_udc.o  # USB Functions  usb_f_acm-y			:= f_acm.o @@ -46,8 +47,6 @@ obj-$(CONFIG_USB_F_SERIAL)	+= usb_f_serial.o  usb_f_obex-y			:= f_obex.o  obj-$(CONFIG_USB_F_OBEX)	+= usb_f_obex.o  obj-$(CONFIG_USB_U_ETHER)	+= u_ether.o -u_rndis-y			:= rndis.o -obj-$(CONFIG_USB_U_RNDIS)	+= u_rndis.o  usb_f_ncm-y			:= f_ncm.o  obj-$(CONFIG_USB_F_NCM)		+= usb_f_ncm.o  usb_f_ecm-y			:= f_ecm.o @@ -58,8 +57,12 @@ usb_f_eem-y			:= f_eem.o  obj-$(CONFIG_USB_F_EEM)		+= usb_f_eem.o  usb_f_ecm_subset-y		:= f_subset.o  obj-$(CONFIG_USB_F_SUBSET)	+= usb_f_ecm_subset.o -usb_f_rndis-y			:= f_rndis.o +usb_f_rndis-y			:= f_rndis.o rndis.o  obj-$(CONFIG_USB_F_RNDIS)	+= usb_f_rndis.o +usb_f_mass_storage-y		:= f_mass_storage.o storage_common.o +obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o +usb_f_fs-y			:= f_fs.o +obj-$(CONFIG_USB_F_FS)		+= usb_f_fs.o  #  # USB gadget drivers diff --git a/drivers/usb/gadget/acm_ms.c b/drivers/usb/gadget/acm_ms.c index 4b947bb50f6..a252444cc0a 100644 --- a/drivers/usb/gadget/acm_ms.c +++ b/drivers/usb/gadget/acm_ms.c @@ -31,16 +31,7 @@  #define ACM_MS_VENDOR_NUM	0x1d6b	/* Linux Foundation */  #define ACM_MS_PRODUCT_NUM	0x0106	/* Composite Gadget: ACM + MS*/ -/*-------------------------------------------------------------------------*/ - -/* - * Kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module.  So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ -#include "f_mass_storage.c" +#include "f_mass_storage.h"  /*-------------------------------------------------------------------------*/  USB_GADGET_COMPOSITE_OPTIONS(); @@ -104,18 +95,35 @@ static struct usb_gadget_strings *dev_strings[] = {  /****************************** Configurations ******************************/  static struct fsg_module_parameters fsg_mod_data = { .stall = 1 }; -FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); +#ifdef CONFIG_USB_GADGET_DEBUG_FILES -static struct fsg_common fsg_common; +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; + +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS + +#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ + +FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);  /*-------------------------------------------------------------------------*/  static struct usb_function *f_acm;  static struct usb_function_instance *f_acm_inst; + +static struct usb_function_instance *fi_msg; +static struct usb_function *f_msg; +  /*   * We _always_ have both ACM and mass storage functions.   */  static int __init acm_ms_do_config(struct usb_configuration *c)  { +	struct fsg_opts *opts;  	int	status;  	if (gadget_is_otg(c->cdev->gadget)) { @@ -123,31 +131,37 @@ static int __init acm_ms_do_config(struct usb_configuration *c)  		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;  	} -	f_acm_inst = usb_get_function_instance("acm"); -	if (IS_ERR(f_acm_inst)) -		return PTR_ERR(f_acm_inst); +	opts = fsg_opts_from_func_inst(fi_msg);  	f_acm = usb_get_function(f_acm_inst); -	if (IS_ERR(f_acm)) { -		status = PTR_ERR(f_acm); -		goto err_func; +	if (IS_ERR(f_acm)) +		return PTR_ERR(f_acm); + +	f_msg = usb_get_function(fi_msg); +	if (IS_ERR(f_msg)) { +		status = PTR_ERR(f_msg); +		goto put_acm;  	}  	status = usb_add_function(c, f_acm);  	if (status < 0) -		goto err_conf; +		goto put_msg; -	status = fsg_bind_config(c->cdev, c, &fsg_common); -	if (status < 0) -		goto err_fsg; +	status = fsg_common_run_thread(opts->common); +	if (status) +		goto remove_acm; + +	status = usb_add_function(c, f_msg); +	if (status) +		goto remove_acm;  	return 0; -err_fsg: +remove_acm:  	usb_remove_function(c, f_acm); -err_conf: +put_msg: +	usb_put_function(f_msg); +put_acm:  	usb_put_function(f_acm); -err_func: -	usb_put_function_instance(f_acm_inst);  	return status;  } @@ -163,45 +177,82 @@ static struct usb_configuration acm_ms_config_driver = {  static int __init acm_ms_bind(struct usb_composite_dev *cdev)  {  	struct usb_gadget	*gadget = cdev->gadget; +	struct fsg_opts		*opts; +	struct fsg_config	config;  	int			status; -	void			*retp; -	/* set up mass storage function */ -	retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data); -	if (IS_ERR(retp)) { -		status = PTR_ERR(retp); -		return PTR_ERR(retp); +	f_acm_inst = usb_get_function_instance("acm"); +	if (IS_ERR(f_acm_inst)) +		return PTR_ERR(f_acm_inst); + +	fi_msg = usb_get_function_instance("mass_storage"); +	if (IS_ERR(fi_msg)) { +		status = PTR_ERR(fi_msg); +		goto fail_get_msg;  	} +	/* set up mass storage function */ +	fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers); +	opts = fsg_opts_from_func_inst(fi_msg); + +	opts->no_configfs = true; +	status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers); +	if (status) +		goto fail; + +	status = fsg_common_set_nluns(opts->common, config.nluns); +	if (status) +		goto fail_set_nluns; + +	status = fsg_common_set_cdev(opts->common, cdev, config.can_stall); +	if (status) +		goto fail_set_cdev; + +	fsg_common_set_sysfs(opts->common, true); +	status = fsg_common_create_luns(opts->common, &config); +	if (status) +		goto fail_set_cdev; + +	fsg_common_set_inquiry_string(opts->common, config.vendor_name, +				      config.product_name);  	/*  	 * Allocate string descriptor numbers ... note that string  	 * contents can be overridden by the composite_dev glue.  	 */  	status = usb_string_ids_tab(cdev, strings_dev);  	if (status < 0) -		goto fail1; +		goto fail_string_ids;  	device_desc.iManufacturer = strings_dev[USB_GADGET_MANUFACTURER_IDX].id;  	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;  	/* register our configuration */  	status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);  	if (status < 0) -		goto fail1; +		goto fail_string_ids;  	usb_composite_overwrite_options(cdev, &coverwrite);  	dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",  			DRIVER_DESC); -	fsg_common_put(&fsg_common);  	return 0;  	/* error recovery */ -fail1: -	fsg_common_put(&fsg_common); +fail_string_ids: +	fsg_common_remove_luns(opts->common); +fail_set_cdev: +	fsg_common_free_luns(opts->common); +fail_set_nluns: +	fsg_common_free_buffers(opts->common); +fail: +	usb_put_function_instance(fi_msg); +fail_get_msg: +	usb_put_function_instance(f_acm_inst);  	return status;  }  static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)  { +	usb_put_function(f_msg); +	usb_put_function_instance(fi_msg);  	usb_put_function(f_acm);  	usb_put_function_instance(f_acm_inst);  	return 0; diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index a9a4346c83a..41b062eb4de 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -40,7 +40,6 @@  #include <linux/sched.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/interrupt.h> @@ -446,7 +445,7 @@ static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)  	ep->ep.ops = &udc_ep_ops;  	INIT_LIST_HEAD(&ep->queue); -	ep->ep.maxpacket = (u16) ~0; +	usb_ep_set_maxpacket_limit(&ep->ep,(u16) ~0);  	/* set NAK */  	tmp = readl(&ep->regs->ctl);  	tmp |= AMD_BIT(UDC_EPCTL_SNAK); @@ -1564,12 +1563,15 @@ static void udc_setup_endpoints(struct udc *dev)  	}  	/* EP0 max packet */  	if (dev->gadget.speed == USB_SPEED_FULL) { -		dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE; -		dev->ep[UDC_EP0OUT_IX].ep.maxpacket = -						UDC_FS_EP0OUT_MAX_PKT_SIZE; +		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IX].ep, +					   UDC_FS_EP0IN_MAX_PKT_SIZE); +		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IX].ep, +					   UDC_FS_EP0OUT_MAX_PKT_SIZE);  	} else if (dev->gadget.speed == USB_SPEED_HIGH) { -		dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; -		dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; +		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IX].ep, +					   UDC_EP0IN_MAX_PKT_SIZE); +		usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IX].ep, +					   UDC_EP0OUT_MAX_PKT_SIZE);  	}  	/* @@ -3078,8 +3080,6 @@ static void udc_pci_remove(struct pci_dev *pdev)  	if (dev->active)  		pci_disable_device(pdev); -	pci_set_drvdata(pdev, NULL); -  	udc_remove(dev);  } @@ -3340,7 +3340,7 @@ static int udc_remote_wakeup(struct udc *dev)  }  /* PCI device parameters */ -static DEFINE_PCI_DEVICE_TABLE(pci_id) = { +static const struct pci_device_id pci_id[] = {  	{  		PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),  		.class =	(PCI_CLASS_SERIAL_USB << 8) | 0xfe, diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 4cc4fd6d147..cfd18bcca72 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -21,7 +21,6 @@  #include <linux/ioport.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/interrupt.h>  #include <linux/proc_fs.h> @@ -834,7 +833,7 @@ static void udc_reinit(struct at91_udc *udc)  		ep->ep.desc = NULL;  		ep->stopped = 0;  		ep->fifo_bank = 0; -		ep->ep.maxpacket = ep->maxpacket; +		usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket);  		ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);  		/* initialize one queue per endpoint */  		INIT_LIST_HEAD(&ep->queue); @@ -1710,16 +1709,6 @@ static int at91udc_probe(struct platform_device *pdev)  		return -ENODEV;  	} -	if (pdev->num_resources != 2) { -		DBG("invalid num_resources\n"); -		return -ENODEV; -	} -	if ((pdev->resource[0].flags != IORESOURCE_MEM) -			|| (pdev->resource[1].flags != IORESOURCE_IRQ)) { -		DBG("invalid resource type\n"); -		return -ENODEV; -	} -  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!res)  		return -ENXIO; diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 2cb52e0438d..76023ce449a 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -326,7 +326,7 @@ static int vbus_is_present(struct usba_udc *udc)  #if defined(CONFIG_ARCH_AT91SAM9RL) -#include <mach/at91_pmc.h> +#include <linux/clk/at91_pmc.h>  static void toggle_bias(int is_on)  { @@ -1012,7 +1012,7 @@ static void nop_release(struct device *dev)  } -struct usb_gadget usba_gadget_template = { +static struct usb_gadget usba_gadget_template = {  	.ops		= &usba_udc_ops,  	.max_speed	= USB_SPEED_HIGH,  	.name		= "atmel_usba_udc", @@ -1661,7 +1661,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)  	if (dma_status) {  		int i; -		for (i = 1; i < USBA_NR_ENDPOINTS; i++) +		for (i = 1; i < USBA_NR_DMAS; i++)  			if (dma_status & (1 << i))  				usba_dma_irq(udc, &udc->usba_ep[i]);  	} @@ -1670,7 +1670,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)  	if (ep_status) {  		int i; -		for (i = 0; i < USBA_NR_ENDPOINTS; i++) +		for (i = 0; i < udc->num_ep; i++)  			if (ep_status & (1 << i)) {  				if (ep_is_control(&udc->usba_ep[i]))  					usba_control_irq(udc, &udc->usba_ep[i]); @@ -1686,7 +1686,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)  		reset_all_endpoints(udc);  		if (udc->gadget.speed != USB_SPEED_UNKNOWN -				&& udc->driver->disconnect) { +				&& udc->driver && udc->driver->disconnect) {  			udc->gadget.speed = USB_SPEED_UNKNOWN;  			spin_unlock(&udc->lock);  			udc->driver->disconnect(&udc->gadget); @@ -1827,12 +1827,12 @@ static int atmel_usba_stop(struct usb_gadget *gadget,  	toggle_bias(0);  	usba_writel(udc, CTRL, USBA_DISABLE_MASK); -	udc->driver = NULL; -  	clk_disable_unprepare(udc->hclk);  	clk_disable_unprepare(udc->pclk); -	DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name); +	DBG(DBG_GADGET, "unregistered driver `%s'\n", udc->driver->driver.name); + +	udc->driver = NULL;  	return 0;  } @@ -1904,7 +1904,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,  		ep->dma_regs = udc->regs + USBA_DMA_BASE(i);  		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);  		ep->ep.ops = &usba_ep_ops; -		ep->ep.maxpacket = ep->fifo_size; +		usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size);  		ep->udc = udc;  		INIT_LIST_HEAD(&ep->queue); @@ -1914,6 +1914,12 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,  		i++;  	} +	if (i == 0) { +		dev_err(&pdev->dev, "of_probe: no endpoint specified\n"); +		ret = -EINVAL; +		goto err; +	} +  	return eps;  err:  	return ERR_PTR(ret); @@ -1957,7 +1963,8 @@ static struct usba_ep * usba_udc_pdata(struct platform_device *pdev,  		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);  		ep->ep.ops = &usba_ep_ops;  		ep->ep.name = pdata->ep[i].name; -		ep->fifo_size = ep->ep.maxpacket = pdata->ep[i].fifo_size; +		ep->fifo_size = pdata->ep[i].fifo_size; +		usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size);  		ep->udc = udc;  		INIT_LIST_HEAD(&ep->queue);  		ep->nr_banks = pdata->ep[i].nr_banks; @@ -1995,14 +2002,12 @@ static int __init usba_udc_probe(struct platform_device *pdev)  	if (irq < 0)  		return irq; -	pclk = clk_get(&pdev->dev, "pclk"); +	pclk = devm_clk_get(&pdev->dev, "pclk");  	if (IS_ERR(pclk))  		return PTR_ERR(pclk); -	hclk = clk_get(&pdev->dev, "hclk"); -	if (IS_ERR(hclk)) { -		ret = PTR_ERR(hclk); -		goto err_get_hclk; -	} +	hclk = devm_clk_get(&pdev->dev, "hclk"); +	if (IS_ERR(hclk)) +		return PTR_ERR(hclk);  	spin_lock_init(&udc->lock);  	udc->pdev = pdev; @@ -2011,17 +2016,17 @@ static int __init usba_udc_probe(struct platform_device *pdev)  	udc->vbus_pin = -ENODEV;  	ret = -ENOMEM; -	udc->regs = ioremap(regs->start, resource_size(regs)); +	udc->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));  	if (!udc->regs) {  		dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n"); -		goto err_map_regs; +		return ret;  	}  	dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",  		 (unsigned long)regs->start, udc->regs); -	udc->fifo = ioremap(fifo->start, resource_size(fifo)); +	udc->fifo = devm_ioremap(&pdev->dev, fifo->start, resource_size(fifo));  	if (!udc->fifo) {  		dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n"); -		goto err_map_fifo; +		return ret;  	}  	dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",  		 (unsigned long)fifo->start, udc->fifo); @@ -2032,7 +2037,7 @@ static int __init usba_udc_probe(struct platform_device *pdev)  	ret = clk_prepare_enable(pclk);  	if (ret) {  		dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n"); -		goto err_clk_enable; +		return ret;  	}  	toggle_bias(0);  	usba_writel(udc, CTRL, USBA_DISABLE_MASK); @@ -2043,22 +2048,22 @@ static int __init usba_udc_probe(struct platform_device *pdev)  	else  		udc->usba_ep = usba_udc_pdata(pdev, udc); -	if (IS_ERR(udc->usba_ep)) { -		ret = PTR_ERR(udc->usba_ep); -		goto err_alloc_ep; -	} +	if (IS_ERR(udc->usba_ep)) +		return PTR_ERR(udc->usba_ep); -	ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc); +	ret = devm_request_irq(&pdev->dev, irq, usba_udc_irq, 0, +				"atmel_usba_udc", udc);  	if (ret) {  		dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n",  			irq, ret); -		goto err_request_irq; +		return ret;  	}  	udc->irq = irq;  	if (gpio_is_valid(udc->vbus_pin)) {  		if (!devm_gpio_request(&pdev->dev, udc->vbus_pin, "atmel_usba_udc")) { -			ret = request_irq(gpio_to_irq(udc->vbus_pin), +			ret = devm_request_irq(&pdev->dev, +					gpio_to_irq(udc->vbus_pin),  					usba_vbus_irq, 0,  					"atmel_usba_udc", udc);  			if (ret) { @@ -2077,31 +2082,13 @@ static int __init usba_udc_probe(struct platform_device *pdev)  	ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);  	if (ret) -		goto err_add_udc; +		return ret;  	usba_init_debugfs(udc);  	for (i = 1; i < udc->num_ep; i++)  		usba_ep_init_debugfs(udc, &udc->usba_ep[i]);  	return 0; - -err_add_udc: -	if (gpio_is_valid(udc->vbus_pin)) -		free_irq(gpio_to_irq(udc->vbus_pin), udc); - -	free_irq(irq, udc); -err_request_irq: -err_alloc_ep: -err_clk_enable: -	iounmap(udc->fifo); -err_map_fifo: -	iounmap(udc->regs); -err_map_regs: -	clk_put(hclk); -err_get_hclk: -	clk_put(pclk); - -	return ret;  }  static int __exit usba_udc_remove(struct platform_device *pdev) @@ -2117,16 +2104,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)  		usba_ep_cleanup_debugfs(&udc->usba_ep[i]);  	usba_cleanup_debugfs(udc); -	if (gpio_is_valid(udc->vbus_pin)) { -		free_irq(gpio_to_irq(udc->vbus_pin), udc); -	} - -	free_irq(udc->irq, udc); -	iounmap(udc->fifo); -	iounmap(udc->regs); -	clk_put(udc->hclk); -	clk_put(udc->pclk); -  	return 0;  } diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h index 2922db50bef..a70706e8cb0 100644 --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -210,7 +210,7 @@  #define USBA_FIFO_BASE(x)	((x) << 16)  /* Synth parameters */ -#define USBA_NR_ENDPOINTS	7 +#define USBA_NR_DMAS		7  #define EP0_FIFO_SIZE		64  #define EP0_EPT_SIZE		USBA_EPT_SIZE_64 diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c index c58fcf1ebe4..e969eb809a8 100644 --- a/drivers/usb/gadget/bcm63xx_udc.c +++ b/drivers/usb/gadget/bcm63xx_udc.c @@ -19,7 +19,6 @@  #include <linux/device.h>  #include <linux/dma-mapping.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/ioport.h>  #include <linux/kconfig.h> @@ -361,24 +360,30 @@ static inline void usb_dma_writel(struct bcm63xx_udc *udc, u32 val, u32 off)  	bcm_writel(val, udc->iudma_regs + off);  } -static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off) +static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off, int chan)  { -	return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off); +	return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off + +			(ENETDMA_CHAN_WIDTH * chan));  } -static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off, +					int chan)  { -	bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off); +	bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off + +			(ENETDMA_CHAN_WIDTH * chan));  } -static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off) +static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off, int chan)  { -	return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off); +	return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off + +			(ENETDMA_CHAN_WIDTH * chan));  } -static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off, +					int chan)  { -	bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off); +	bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off + +			(ENETDMA_CHAN_WIDTH * chan));  }  static inline void set_clocks(struct bcm63xx_udc *udc, bool is_enabled) @@ -549,7 +554,7 @@ static void bcm63xx_ep_setup(struct bcm63xx_udc *udc)  		if (idx < 0)  			continue; -		udc->bep[idx].ep.maxpacket = max_pkt; +		usb_ep_set_maxpacket_limit(&udc->bep[idx].ep, max_pkt);  		val = (idx << USBD_CSR_EP_LOG_SHIFT) |  		      (cfg->dir << USBD_CSR_EP_DIR_SHIFT) | @@ -639,7 +644,7 @@ static void iudma_write(struct bcm63xx_udc *udc, struct iudma_ch *iudma,  	} while (!last_bd);  	usb_dmac_writel(udc, ENETDMAC_CHANCFG_EN_MASK, -			ENETDMAC_CHANCFG_REG(iudma->ch_idx)); +			ENETDMAC_CHANCFG_REG, iudma->ch_idx);  }  /** @@ -695,9 +700,9 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)  		bcm63xx_fifo_reset_ep(udc, max(0, iudma->ep_num));  	/* stop DMA, then wait for the hardware to wrap up */ -	usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG(ch_idx)); +	usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG, ch_idx); -	while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)) & +	while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx) &  				   ENETDMAC_CHANCFG_EN_MASK) {  		udelay(1); @@ -714,10 +719,10 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)  			dev_warn(udc->dev, "forcibly halting IUDMA channel %d\n",  				 ch_idx);  			usb_dmac_writel(udc, ENETDMAC_CHANCFG_BUFHALT_MASK, -					ENETDMAC_CHANCFG_REG(ch_idx)); +					ENETDMAC_CHANCFG_REG, ch_idx);  		}  	} -	usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG(ch_idx)); +	usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG, ch_idx);  	/* don't leave "live" HW-owned entries for the next guy to step on */  	for (d = iudma->bd_ring; d <= iudma->end_bd; d++) @@ -729,11 +734,11 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma)  	/* set up IRQs, UBUS burst size, and BD base for this channel */  	usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK, -			ENETDMAC_IRMASK_REG(ch_idx)); -	usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG(ch_idx)); +			ENETDMAC_IRMASK_REG, ch_idx); +	usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG, ch_idx); -	usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG(ch_idx)); -	usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG(ch_idx)); +	usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG, ch_idx); +	usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG, ch_idx);  }  /** @@ -943,7 +948,7 @@ static int bcm63xx_init_udc_hw(struct bcm63xx_udc *udc)  		bep->ep.ops = &bcm63xx_udc_ep_ops;  		list_add_tail(&bep->ep.ep_list, &udc->gadget.ep_list);  		bep->halted = 0; -		bep->ep.maxpacket = BCM63XX_MAX_CTRL_PKT; +		usb_ep_set_maxpacket_limit(&bep->ep, BCM63XX_MAX_CTRL_PKT);  		bep->udc = udc;  		bep->ep.desc = NULL;  		INIT_LIST_HEAD(&bep->queue); @@ -2036,7 +2041,7 @@ static irqreturn_t bcm63xx_udc_data_isr(int irq, void *dev_id)  	spin_lock(&udc->lock);  	usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK, -			ENETDMAC_IR_REG(iudma->ch_idx)); +			ENETDMAC_IR_REG, iudma->ch_idx);  	bep = iudma->bep;  	rc = iudma_read(udc, iudma); @@ -2176,18 +2181,18 @@ static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p)  		seq_printf(s, " [ep%d]:\n",  			   max_t(int, iudma_defaults[ch_idx].ep_num, 0));  		seq_printf(s, "  cfg: %08x; irqstat: %08x; irqmask: %08x; maxburst: %08x\n", -			   usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)), -			   usb_dmac_readl(udc, ENETDMAC_IR_REG(ch_idx)), -			   usb_dmac_readl(udc, ENETDMAC_IRMASK_REG(ch_idx)), -			   usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG(ch_idx))); +			   usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx), +			   usb_dmac_readl(udc, ENETDMAC_IR_REG, ch_idx), +			   usb_dmac_readl(udc, ENETDMAC_IRMASK_REG, ch_idx), +			   usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG, ch_idx)); -		sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG(ch_idx)); -		sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG(ch_idx)); +		sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG, ch_idx); +		sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG, ch_idx);  		seq_printf(s, "  base: %08x; index: %04x_%04x; desc: %04x_%04x %08x\n", -			   usb_dmas_readl(udc, ENETDMAS_RSTART_REG(ch_idx)), +			   usb_dmas_readl(udc, ENETDMAS_RSTART_REG, ch_idx),  			   sram2 >> 16, sram2 & 0xffff,  			   sram3 >> 16, sram3 & 0xffff, -			   usb_dmas_readl(udc, ENETDMAS_SRAM4_REG(ch_idx))); +			   usb_dmas_readl(udc, ENETDMAS_SRAM4_REG, ch_idx));  		seq_printf(s, "  desc: %d/%d used", iudma->n_bds_used,  			   iudma->n_bds); diff --git a/drivers/usb/gadget/cdc2.c b/drivers/usb/gadget/cdc2.c index 5a5acf22c69..e126b6b248e 100644 --- a/drivers/usb/gadget/cdc2.c +++ b/drivers/usb/gadget/cdc2.c @@ -113,12 +113,6 @@ static int __init cdc_do_config(struct usb_configuration *c)  		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;  	} -	fi_ecm = usb_get_function_instance("ecm"); -	if (IS_ERR(fi_ecm)) { -		status = PTR_ERR(fi_ecm); -		goto err_func_ecm; -	} -  	f_ecm = usb_get_function(fi_ecm);  	if (IS_ERR(f_ecm)) {  		status = PTR_ERR(f_ecm); @@ -129,35 +123,24 @@ static int __init cdc_do_config(struct usb_configuration *c)  	if (status)  		goto err_add_ecm; -	fi_serial = usb_get_function_instance("acm"); -	if (IS_ERR(fi_serial)) { -		status = PTR_ERR(fi_serial); -		goto err_get_acm; -	} -  	f_acm = usb_get_function(fi_serial);  	if (IS_ERR(f_acm)) {  		status = PTR_ERR(f_acm); -		goto err_func_acm; +		goto err_get_acm;  	}  	status = usb_add_function(c, f_acm);  	if (status)  		goto err_add_acm; -  	return 0;  err_add_acm:  	usb_put_function(f_acm); -err_func_acm: -	usb_put_function_instance(fi_serial);  err_get_acm:  	usb_remove_function(c, f_ecm);  err_add_ecm:  	usb_put_function(f_ecm);  err_get_ecm: -	usb_put_function_instance(fi_ecm); -err_func_ecm:  	return status;  } diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index d4f0f330575..f8015193205 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -21,6 +21,24 @@  #include <linux/usb/composite.h>  #include <asm/unaligned.h> +#include "u_os_desc.h" + +/** + * struct usb_os_string - represents OS String to be reported by a gadget + * @bLength: total length of the entire descritor, always 0x12 + * @bDescriptorType: USB_DT_STRING + * @qwSignature: the OS String proper + * @bMS_VendorCode: code used by the host for subsequent requests + * @bPad: not used, must be zero + */ +struct usb_os_string { +	__u8	bLength; +	__u8	bDescriptorType; +	__u8	qwSignature[OS_STRING_QW_SIGN_LEN]; +	__u8	bMS_VendorCode; +	__u8	bPad; +} __packed; +  /*   * The code in this file is utility code, used to build a gadget driver   * from one or more "function" drivers, one or more "configuration" @@ -354,7 +372,7 @@ static u8 encode_bMaxPower(enum usb_device_speed speed,  		return DIV_ROUND_UP(val, 8);  	default:  		return DIV_ROUND_UP(val, 2); -	}; +	}  }  static int config_buf(struct usb_configuration *config, @@ -422,6 +440,7 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)  {  	struct usb_gadget		*gadget = cdev->gadget;  	struct usb_configuration	*c; +	struct list_head		*pos;  	u8				type = w_value >> 8;  	enum usb_device_speed		speed = USB_SPEED_UNKNOWN; @@ -440,7 +459,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)  	/* This is a lookup by config *INDEX* */  	w_value &= 0xff; -	list_for_each_entry(c, &cdev->configs, list) { + +	pos = &cdev->configs; +	c = cdev->os_desc_config; +	if (c) +		goto check_config; + +	while ((pos = pos->next) !=  &cdev->configs) { +		c = list_entry(pos, typeof(*c), list); + +		/* skip OS Descriptors config which is handled separately */ +		if (c == cdev->os_desc_config) +			continue; + +check_config:  		/* ignore configs that won't work at this speed */  		switch (speed) {  		case USB_SPEED_SUPER: @@ -593,6 +625,7 @@ static void reset_config(struct usb_composite_dev *cdev)  		bitmap_zero(f->endpoints, 32);  	}  	cdev->config = NULL; +	cdev->delayed_status = 0;  }  static int set_config(struct usb_composite_dev *cdev, @@ -633,6 +666,7 @@ static int set_config(struct usb_composite_dev *cdev,  	if (!c)  		goto done; +	usb_gadget_set_state(gadget, USB_STATE_CONFIGURED);  	cdev->config = c;  	/* Initialize all interfaces by setting them to altsetting zero. */ @@ -959,6 +993,19 @@ static int get_string(struct usb_composite_dev *cdev,  		return s->bLength;  	} +	if (cdev->use_os_string && language == 0 && id == OS_STRING_IDX) { +		struct usb_os_string *b = buf; +		b->bLength = sizeof(*b); +		b->bDescriptorType = USB_DT_STRING; +		compiletime_assert( +			sizeof(b->qwSignature) == sizeof(cdev->qw_sign), +			"qwSignature size must be equal to qw_sign"); +		memcpy(&b->qwSignature, cdev->qw_sign, sizeof(b->qwSignature)); +		b->bMS_VendorCode = cdev->b_vendor_code; +		b->bPad = 0; +		return sizeof(*b); +	} +  	list_for_each_entry(uc, &cdev->gstrings, list) {  		struct usb_gadget_strings **sp; @@ -1138,7 +1185,7 @@ struct usb_string *usb_gstrings_attach(struct usb_composite_dev *cdev,  	uc = copy_gadget_strings(sp, n_gstrings, n_strings);  	if (IS_ERR(uc)) -		return ERR_PTR(PTR_ERR(uc)); +		return ERR_CAST(uc);  	n_gs = get_containers_gs(uc);  	ret = usb_string_ids_tab(cdev, n_gs[0]->strings); @@ -1205,6 +1252,156 @@ static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)  				req->status, req->actual, req->length);  } +static int count_ext_compat(struct usb_configuration *c) +{ +	int i, res; + +	res = 0; +	for (i = 0; i < c->next_interface_id; ++i) { +		struct usb_function *f; +		int j; + +		f = c->interface[i]; +		for (j = 0; j < f->os_desc_n; ++j) { +			struct usb_os_desc *d; + +			if (i != f->os_desc_table[j].if_id) +				continue; +			d = f->os_desc_table[j].os_desc; +			if (d && d->ext_compat_id) +				++res; +		} +	} +	BUG_ON(res > 255); +	return res; +} + +static void fill_ext_compat(struct usb_configuration *c, u8 *buf) +{ +	int i, count; + +	count = 16; +	for (i = 0; i < c->next_interface_id; ++i) { +		struct usb_function *f; +		int j; + +		f = c->interface[i]; +		for (j = 0; j < f->os_desc_n; ++j) { +			struct usb_os_desc *d; + +			if (i != f->os_desc_table[j].if_id) +				continue; +			d = f->os_desc_table[j].os_desc; +			if (d && d->ext_compat_id) { +				*buf++ = i; +				*buf++ = 0x01; +				memcpy(buf, d->ext_compat_id, 16); +				buf += 22; +			} else { +				++buf; +				*buf = 0x01; +				buf += 23; +			} +			count += 24; +			if (count >= 4096) +				return; +		} +	} +} + +static int count_ext_prop(struct usb_configuration *c, int interface) +{ +	struct usb_function *f; +	int j; + +	f = c->interface[interface]; +	for (j = 0; j < f->os_desc_n; ++j) { +		struct usb_os_desc *d; + +		if (interface != f->os_desc_table[j].if_id) +			continue; +		d = f->os_desc_table[j].os_desc; +		if (d && d->ext_compat_id) +			return d->ext_prop_count; +	} +	return 0; +} + +static int len_ext_prop(struct usb_configuration *c, int interface) +{ +	struct usb_function *f; +	struct usb_os_desc *d; +	int j, res; + +	res = 10; /* header length */ +	f = c->interface[interface]; +	for (j = 0; j < f->os_desc_n; ++j) { +		if (interface != f->os_desc_table[j].if_id) +			continue; +		d = f->os_desc_table[j].os_desc; +		if (d) +			return min(res + d->ext_prop_len, 4096); +	} +	return res; +} + +static int fill_ext_prop(struct usb_configuration *c, int interface, u8 *buf) +{ +	struct usb_function *f; +	struct usb_os_desc *d; +	struct usb_os_desc_ext_prop *ext_prop; +	int j, count, n, ret; +	u8 *start = buf; + +	f = c->interface[interface]; +	for (j = 0; j < f->os_desc_n; ++j) { +		if (interface != f->os_desc_table[j].if_id) +			continue; +		d = f->os_desc_table[j].os_desc; +		if (d) +			list_for_each_entry(ext_prop, &d->ext_prop, entry) { +				/* 4kB minus header length */ +				n = buf - start; +				if (n >= 4086) +					return 0; + +				count = ext_prop->data_len + +					ext_prop->name_len + 14; +				if (count > 4086 - n) +					return -EINVAL; +				usb_ext_prop_put_size(buf, count); +				usb_ext_prop_put_type(buf, ext_prop->type); +				ret = usb_ext_prop_put_name(buf, ext_prop->name, +							    ext_prop->name_len); +				if (ret < 0) +					return ret; +				switch (ext_prop->type) { +				case USB_EXT_PROP_UNICODE: +				case USB_EXT_PROP_UNICODE_ENV: +				case USB_EXT_PROP_UNICODE_LINK: +					usb_ext_prop_put_unicode(buf, ret, +							 ext_prop->data, +							 ext_prop->data_len); +					break; +				case USB_EXT_PROP_BINARY: +					usb_ext_prop_put_binary(buf, ret, +							ext_prop->data, +							ext_prop->data_len); +					break; +				case USB_EXT_PROP_LE32: +					/* not implemented */ +				case USB_EXT_PROP_BE32: +					/* not implemented */ +				default: +					return -EINVAL; +				} +				buf += count; +			} +	} + +	return 0; +} +  /*   * The setup() callback implements all the ep0 functionality that's   * not handled lower down, in hardware or the hardware driver(like @@ -1414,6 +1611,91 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  		break;  	default:  unknown: +		/* +		 * OS descriptors handling +		 */ +		if (cdev->use_os_string && cdev->os_desc_config && +		    (ctrl->bRequest & USB_TYPE_VENDOR) && +		    ctrl->bRequest == cdev->b_vendor_code) { +			struct usb_request		*req; +			struct usb_configuration	*os_desc_cfg; +			u8				*buf; +			int				interface; +			int				count = 0; + +			req = cdev->os_desc_req; +			req->complete = composite_setup_complete; +			buf = req->buf; +			os_desc_cfg = cdev->os_desc_config; +			memset(buf, 0, w_length); +			buf[5] = 0x01; +			switch (ctrl->bRequestType & USB_RECIP_MASK) { +			case USB_RECIP_DEVICE: +				if (w_index != 0x4 || (w_value >> 8)) +					break; +				buf[6] = w_index; +				if (w_length == 0x10) { +					/* Number of ext compat interfaces */ +					count = count_ext_compat(os_desc_cfg); +					buf[8] = count; +					count *= 24; /* 24 B/ext compat desc */ +					count += 16; /* header */ +					put_unaligned_le32(count, buf); +					value = w_length; +				} else { +					/* "extended compatibility ID"s */ +					count = count_ext_compat(os_desc_cfg); +					buf[8] = count; +					count *= 24; /* 24 B/ext compat desc */ +					count += 16; /* header */ +					put_unaligned_le32(count, buf); +					buf += 16; +					fill_ext_compat(os_desc_cfg, buf); +					value = w_length; +				} +				break; +			case USB_RECIP_INTERFACE: +				if (w_index != 0x5 || (w_value >> 8)) +					break; +				interface = w_value & 0xFF; +				buf[6] = w_index; +				if (w_length == 0x0A) { +					count = count_ext_prop(os_desc_cfg, +						interface); +					put_unaligned_le16(count, buf + 8); +					count = len_ext_prop(os_desc_cfg, +						interface); +					put_unaligned_le32(count, buf); + +					value = w_length; +				} else { +					count = count_ext_prop(os_desc_cfg, +						interface); +					put_unaligned_le16(count, buf + 8); +					count = len_ext_prop(os_desc_cfg, +						interface); +					put_unaligned_le32(count, buf); +					buf += 10; +					value = fill_ext_prop(os_desc_cfg, +							      interface, buf); +					if (value < 0) +						return value; + +					value = w_length; +				} +				break; +			} +			req->length = value; +			req->zero = value < w_length; +			value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); +			if (value < 0) { +				DBG(cdev, "ep_queue --> %d\n", value); +				req->status = 0; +				composite_setup_complete(gadget->ep0, req); +			} +			return value; +		} +  		VDBG(cdev,  			"non-core control req%02x.%02x v%04x i%04x l%d\n",  			ctrl->bRequestType, ctrl->bRequest, @@ -1451,8 +1733,22 @@ unknown:  			struct usb_configuration	*c;  			c = cdev->config; -			if (c && c->setup) +			if (!c) +				goto done; + +			/* try current config's setup */ +			if (c->setup) {  				value = c->setup(c, ctrl); +				goto done; +			} + +			/* try the only function in the current config */ +			if (!list_is_singular(&c->functions)) +				goto done; +			f = list_first_entry(&c->functions, struct usb_function, +					     list); +			if (f->setup) +				value = f->setup(f, ctrl);  		}  		goto done; @@ -1623,6 +1919,29 @@ fail:  	return ret;  } +int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, +				  struct usb_ep *ep0) +{ +	int ret = 0; + +	cdev->os_desc_req = usb_ep_alloc_request(ep0, GFP_KERNEL); +	if (!cdev->os_desc_req) { +		ret = PTR_ERR(cdev->os_desc_req); +		goto end; +	} + +	/* OS feature descriptor length <= 4kB */ +	cdev->os_desc_req->buf = kmalloc(4096, GFP_KERNEL); +	if (!cdev->os_desc_req->buf) { +		ret = PTR_ERR(cdev->os_desc_req->buf); +		kfree(cdev->os_desc_req); +		goto end; +	} +	cdev->os_desc_req->complete = composite_setup_complete; +end: +	return ret; +} +  void composite_dev_cleanup(struct usb_composite_dev *cdev)  {  	struct usb_gadget_string_container *uc, *tmp; @@ -1631,6 +1950,10 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev)  		list_del(&uc->list);  		kfree(uc);  	} +	if (cdev->os_desc_req) { +		kfree(cdev->os_desc_req->buf); +		usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req); +	}  	if (cdev->req) {  		kfree(cdev->req->buf);  		usb_ep_free_request(cdev->gadget->ep0, cdev->req); @@ -1668,6 +1991,12 @@ static int composite_bind(struct usb_gadget *gadget,  	if (status < 0)  		goto fail; +	if (cdev->use_os_string) { +		status = composite_os_desc_req_prepare(cdev, gadget->ep0); +		if (status) +			goto fail; +	} +  	update_unchanged_dev_desc(&cdev->desc, composite->dev);  	/* has userspace failed to provide a serial number? */ @@ -1713,7 +2042,7 @@ composite_resume(struct usb_gadget *gadget)  {  	struct usb_composite_dev	*cdev = get_gadget_data(gadget);  	struct usb_function		*f; -	u8				maxpower; +	u16				maxpower;  	/* REVISIT:  should we have config level  	 * suspend/resume callbacks? diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 8f0d6141e5e..97142146eea 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -2,8 +2,12 @@  #include <linux/module.h>  #include <linux/slab.h>  #include <linux/device.h> +#include <linux/nls.h>  #include <linux/usb/composite.h>  #include <linux/usb/gadget_configfs.h> +#include "configfs.h" +#include "u_f.h" +#include "u_os_desc.h"  int check_user_usb_string(const char *name,  		struct usb_gadget_strings *stringtab_dev) @@ -42,7 +46,8 @@ struct gadget_info {  	struct config_group functions_group;  	struct config_group configs_group;  	struct config_group strings_group; -	struct config_group *default_groups[4]; +	struct config_group os_desc_group; +	struct config_group *default_groups[5];  	struct mutex lock;  	struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; @@ -55,6 +60,9 @@ struct gadget_info {  #endif  	struct usb_composite_driver composite;  	struct usb_composite_dev cdev; +	bool use_os_desc; +	char b_vendor_code; +	char qw_sign[OS_STRING_QW_SIGN_LEN];  };  struct config_usb_cfg { @@ -78,6 +86,10 @@ struct gadget_strings {  	struct list_head list;  }; +struct os_desc { +	struct config_group group; +}; +  struct gadget_config_name {  	struct usb_gadget_strings stringtab_dev;  	struct usb_string strings; @@ -557,13 +569,20 @@ static struct config_group *function_make(  	fi = usb_get_function_instance(func_name);  	if (IS_ERR(fi)) -		return ERR_PTR(PTR_ERR(fi)); +		return ERR_CAST(fi);  	ret = config_item_set_name(&fi->group.cg_item, name);  	if (ret) {  		usb_put_function_instance(fi);  		return ERR_PTR(ret);  	} +	if (fi->set_inst_name) { +		ret = fi->set_inst_name(fi, instance_name); +		if (ret) { +			usb_put_function_instance(fi); +			return ERR_PTR(ret); +		} +	}  	gi = container_of(group, struct gadget_info, functions_group); @@ -728,6 +747,526 @@ static void gadget_strings_attr_release(struct config_item *item)  USB_CONFIG_STRING_RW_OPS(gadget_strings);  USB_CONFIG_STRINGS_LANG(gadget_strings, gadget_info); +static inline struct os_desc *to_os_desc(struct config_item *item) +{ +	return container_of(to_config_group(item), struct os_desc, group); +} + +CONFIGFS_ATTR_STRUCT(os_desc); +CONFIGFS_ATTR_OPS(os_desc); + +static ssize_t os_desc_use_show(struct os_desc *os_desc, char *page) +{ +	struct gadget_info *gi; + +	gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + +	return sprintf(page, "%d", gi->use_os_desc); +} + +static ssize_t os_desc_use_store(struct os_desc *os_desc, const char *page, +				 size_t len) +{ +	struct gadget_info *gi; +	int ret; +	bool use; + +	gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + +	mutex_lock(&gi->lock); +	ret = strtobool(page, &use); +	if (!ret) { +		gi->use_os_desc = use; +		ret = len; +	} +	mutex_unlock(&gi->lock); + +	return ret; +} + +static struct os_desc_attribute os_desc_use = +	__CONFIGFS_ATTR(use, S_IRUGO | S_IWUSR, +			os_desc_use_show, +			os_desc_use_store); + +static ssize_t os_desc_b_vendor_code_show(struct os_desc *os_desc, char *page) +{ +	struct gadget_info *gi; + +	gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + +	return sprintf(page, "%d", gi->b_vendor_code); +} + +static ssize_t os_desc_b_vendor_code_store(struct os_desc *os_desc, +					   const char *page, size_t len) +{ +	struct gadget_info *gi; +	int ret; +	u8 b_vendor_code; + +	gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + +	mutex_lock(&gi->lock); +	ret = kstrtou8(page, 0, &b_vendor_code); +	if (!ret) { +		gi->b_vendor_code = b_vendor_code; +		ret = len; +	} +	mutex_unlock(&gi->lock); + +	return ret; +} + +static struct os_desc_attribute os_desc_b_vendor_code = +	__CONFIGFS_ATTR(b_vendor_code, S_IRUGO | S_IWUSR, +			os_desc_b_vendor_code_show, +			os_desc_b_vendor_code_store); + +static ssize_t os_desc_qw_sign_show(struct os_desc *os_desc, char *page) +{ +	struct gadget_info *gi; + +	gi = to_gadget_info(os_desc->group.cg_item.ci_parent); + +	memcpy(page, gi->qw_sign, OS_STRING_QW_SIGN_LEN); + +	return OS_STRING_QW_SIGN_LEN; +} + +static ssize_t os_desc_qw_sign_store(struct os_desc *os_desc, const char *page, +				     size_t len) +{ +	struct gadget_info *gi; +	int res, l; + +	gi = to_gadget_info(os_desc->group.cg_item.ci_parent); +	l = min((int)len, OS_STRING_QW_SIGN_LEN >> 1); +	if (page[l - 1] == '\n') +		--l; + +	mutex_lock(&gi->lock); +	res = utf8s_to_utf16s(page, l, +			      UTF16_LITTLE_ENDIAN, (wchar_t *) gi->qw_sign, +			      OS_STRING_QW_SIGN_LEN); +	if (res > 0) +		res = len; +	mutex_unlock(&gi->lock); + +	return res; +} + +static struct os_desc_attribute os_desc_qw_sign = +	__CONFIGFS_ATTR(qw_sign, S_IRUGO | S_IWUSR, +			os_desc_qw_sign_show, +			os_desc_qw_sign_store); + +static struct configfs_attribute *os_desc_attrs[] = { +	&os_desc_use.attr, +	&os_desc_b_vendor_code.attr, +	&os_desc_qw_sign.attr, +	NULL, +}; + +static void os_desc_attr_release(struct config_item *item) +{ +	struct os_desc *os_desc = to_os_desc(item); +	kfree(os_desc); +} + +static int os_desc_link(struct config_item *os_desc_ci, +			struct config_item *usb_cfg_ci) +{ +	struct gadget_info *gi = container_of(to_config_group(os_desc_ci), +					struct gadget_info, os_desc_group); +	struct usb_composite_dev *cdev = &gi->cdev; +	struct config_usb_cfg *c_target = +		container_of(to_config_group(usb_cfg_ci), +			     struct config_usb_cfg, group); +	struct usb_configuration *c; +	int ret; + +	mutex_lock(&gi->lock); +	list_for_each_entry(c, &cdev->configs, list) { +		if (c == &c_target->c) +			break; +	} +	if (c != &c_target->c) { +		ret = -EINVAL; +		goto out; +	} + +	if (cdev->os_desc_config) { +		ret = -EBUSY; +		goto out; +	} + +	cdev->os_desc_config = &c_target->c; +	ret = 0; + +out: +	mutex_unlock(&gi->lock); +	return ret; +} + +static int os_desc_unlink(struct config_item *os_desc_ci, +			  struct config_item *usb_cfg_ci) +{ +	struct gadget_info *gi = container_of(to_config_group(os_desc_ci), +					struct gadget_info, os_desc_group); +	struct usb_composite_dev *cdev = &gi->cdev; + +	mutex_lock(&gi->lock); +	if (gi->udc_name) +		unregister_gadget(gi); +	cdev->os_desc_config = NULL; +	WARN_ON(gi->udc_name); +	mutex_unlock(&gi->lock); +	return 0; +} + +static struct configfs_item_operations os_desc_ops = { +	.release                = os_desc_attr_release, +	.show_attribute         = os_desc_attr_show, +	.store_attribute        = os_desc_attr_store, +	.allow_link		= os_desc_link, +	.drop_link		= os_desc_unlink, +}; + +static struct config_item_type os_desc_type = { +	.ct_item_ops	= &os_desc_ops, +	.ct_attrs	= os_desc_attrs, +	.ct_owner	= THIS_MODULE, +}; + +CONFIGFS_ATTR_STRUCT(usb_os_desc); +CONFIGFS_ATTR_OPS(usb_os_desc); + + +static inline struct usb_os_desc_ext_prop +*to_usb_os_desc_ext_prop(struct config_item *item) +{ +	return container_of(item, struct usb_os_desc_ext_prop, item); +} + +CONFIGFS_ATTR_STRUCT(usb_os_desc_ext_prop); +CONFIGFS_ATTR_OPS(usb_os_desc_ext_prop); + +static ssize_t ext_prop_type_show(struct usb_os_desc_ext_prop *ext_prop, +				  char *page) +{ +	return sprintf(page, "%d", ext_prop->type); +} + +static ssize_t ext_prop_type_store(struct usb_os_desc_ext_prop *ext_prop, +				   const char *page, size_t len) +{ +	struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent); +	u8 type; +	int ret; + +	if (desc->opts_mutex) +		mutex_lock(desc->opts_mutex); +	ret = kstrtou8(page, 0, &type); +	if (ret) +		goto end; +	if (type < USB_EXT_PROP_UNICODE || type > USB_EXT_PROP_UNICODE_MULTI) { +		ret = -EINVAL; +		goto end; +	} + +	if ((ext_prop->type == USB_EXT_PROP_BINARY || +	    ext_prop->type == USB_EXT_PROP_LE32 || +	    ext_prop->type == USB_EXT_PROP_BE32) && +	    (type == USB_EXT_PROP_UNICODE || +	    type == USB_EXT_PROP_UNICODE_ENV || +	    type == USB_EXT_PROP_UNICODE_LINK)) +		ext_prop->data_len <<= 1; +	else if ((ext_prop->type == USB_EXT_PROP_UNICODE || +		   ext_prop->type == USB_EXT_PROP_UNICODE_ENV || +		   ext_prop->type == USB_EXT_PROP_UNICODE_LINK) && +		   (type == USB_EXT_PROP_BINARY || +		   type == USB_EXT_PROP_LE32 || +		   type == USB_EXT_PROP_BE32)) +		ext_prop->data_len >>= 1; +	ext_prop->type = type; +	ret = len; + +end: +	if (desc->opts_mutex) +		mutex_unlock(desc->opts_mutex); +	return ret; +} + +static ssize_t ext_prop_data_show(struct usb_os_desc_ext_prop *ext_prop, +				  char *page) +{ +	int len = ext_prop->data_len; + +	if (ext_prop->type == USB_EXT_PROP_UNICODE || +	    ext_prop->type == USB_EXT_PROP_UNICODE_ENV || +	    ext_prop->type == USB_EXT_PROP_UNICODE_LINK) +		len >>= 1; +	memcpy(page, ext_prop->data, len); + +	return len; +} + +static ssize_t ext_prop_data_store(struct usb_os_desc_ext_prop *ext_prop, +				   const char *page, size_t len) +{ +	struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent); +	char *new_data; +	size_t ret_len = len; + +	if (page[len - 1] == '\n' || page[len - 1] == '\0') +		--len; +	new_data = kzalloc(len, GFP_KERNEL); +	if (!new_data) +		return -ENOMEM; + +	memcpy(new_data, page, len); + +	if (desc->opts_mutex) +		mutex_lock(desc->opts_mutex); +	kfree(ext_prop->data); +	ext_prop->data = new_data; +	desc->ext_prop_len -= ext_prop->data_len; +	ext_prop->data_len = len; +	desc->ext_prop_len += ext_prop->data_len; +	if (ext_prop->type == USB_EXT_PROP_UNICODE || +	    ext_prop->type == USB_EXT_PROP_UNICODE_ENV || +	    ext_prop->type == USB_EXT_PROP_UNICODE_LINK) { +		desc->ext_prop_len -= ext_prop->data_len; +		ext_prop->data_len <<= 1; +		ext_prop->data_len += 2; +		desc->ext_prop_len += ext_prop->data_len; +	} +	if (desc->opts_mutex) +		mutex_unlock(desc->opts_mutex); +	return ret_len; +} + +static struct usb_os_desc_ext_prop_attribute ext_prop_type = +	__CONFIGFS_ATTR(type, S_IRUGO | S_IWUSR, +			ext_prop_type_show, ext_prop_type_store); + +static struct usb_os_desc_ext_prop_attribute ext_prop_data = +	__CONFIGFS_ATTR(data, S_IRUGO | S_IWUSR, +			ext_prop_data_show, ext_prop_data_store); + +static struct configfs_attribute *ext_prop_attrs[] = { +	&ext_prop_type.attr, +	&ext_prop_data.attr, +	NULL, +}; + +static void usb_os_desc_ext_prop_release(struct config_item *item) +{ +	struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item); + +	kfree(ext_prop); /* frees a whole chunk */ +} + +static struct configfs_item_operations ext_prop_ops = { +	.release		= usb_os_desc_ext_prop_release, +	.show_attribute		= usb_os_desc_ext_prop_attr_show, +	.store_attribute	= usb_os_desc_ext_prop_attr_store, +}; + +static struct config_item *ext_prop_make( +		struct config_group *group, +		const char *name) +{ +	struct usb_os_desc_ext_prop *ext_prop; +	struct config_item_type *ext_prop_type; +	struct usb_os_desc *desc; +	char *vlabuf; + +	vla_group(data_chunk); +	vla_item(data_chunk, struct usb_os_desc_ext_prop, ext_prop, 1); +	vla_item(data_chunk, struct config_item_type, ext_prop_type, 1); + +	vlabuf = kzalloc(vla_group_size(data_chunk), GFP_KERNEL); +	if (!vlabuf) +		return ERR_PTR(-ENOMEM); + +	ext_prop = vla_ptr(vlabuf, data_chunk, ext_prop); +	ext_prop_type = vla_ptr(vlabuf, data_chunk, ext_prop_type); + +	desc = container_of(group, struct usb_os_desc, group); +	ext_prop_type->ct_item_ops = &ext_prop_ops; +	ext_prop_type->ct_attrs = ext_prop_attrs; +	ext_prop_type->ct_owner = desc->owner; + +	config_item_init_type_name(&ext_prop->item, name, ext_prop_type); + +	ext_prop->name = kstrdup(name, GFP_KERNEL); +	if (!ext_prop->name) { +		kfree(vlabuf); +		return ERR_PTR(-ENOMEM); +	} +	desc->ext_prop_len += 14; +	ext_prop->name_len = 2 * strlen(ext_prop->name) + 2; +	if (desc->opts_mutex) +		mutex_lock(desc->opts_mutex); +	desc->ext_prop_len += ext_prop->name_len; +	list_add_tail(&ext_prop->entry, &desc->ext_prop); +	++desc->ext_prop_count; +	if (desc->opts_mutex) +		mutex_unlock(desc->opts_mutex); + +	return &ext_prop->item; +} + +static void ext_prop_drop(struct config_group *group, struct config_item *item) +{ +	struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item); +	struct usb_os_desc *desc = to_usb_os_desc(&group->cg_item); + +	if (desc->opts_mutex) +		mutex_lock(desc->opts_mutex); +	list_del(&ext_prop->entry); +	--desc->ext_prop_count; +	kfree(ext_prop->name); +	desc->ext_prop_len -= (ext_prop->name_len + ext_prop->data_len + 14); +	if (desc->opts_mutex) +		mutex_unlock(desc->opts_mutex); +	config_item_put(item); +} + +static struct configfs_group_operations interf_grp_ops = { +	.make_item	= &ext_prop_make, +	.drop_item	= &ext_prop_drop, +}; + +static struct configfs_item_operations interf_item_ops = { +	.show_attribute		= usb_os_desc_attr_show, +	.store_attribute	= usb_os_desc_attr_store, +}; + +static ssize_t interf_grp_compatible_id_show(struct usb_os_desc *desc, +					     char *page) +{ +	memcpy(page, desc->ext_compat_id, 8); +	return 8; +} + +static ssize_t interf_grp_compatible_id_store(struct usb_os_desc *desc, +					      const char *page, size_t len) +{ +	int l; + +	l = min_t(int, 8, len); +	if (page[l - 1] == '\n') +		--l; +	if (desc->opts_mutex) +		mutex_lock(desc->opts_mutex); +	memcpy(desc->ext_compat_id, page, l); +	desc->ext_compat_id[l] = '\0'; + +	if (desc->opts_mutex) +		mutex_unlock(desc->opts_mutex); + +	return len; +} + +static struct usb_os_desc_attribute interf_grp_attr_compatible_id = +	__CONFIGFS_ATTR(compatible_id, S_IRUGO | S_IWUSR, +			interf_grp_compatible_id_show, +			interf_grp_compatible_id_store); + +static ssize_t interf_grp_sub_compatible_id_show(struct usb_os_desc *desc, +						 char *page) +{ +	memcpy(page, desc->ext_compat_id + 8, 8); +	return 8; +} + +static ssize_t interf_grp_sub_compatible_id_store(struct usb_os_desc *desc, +						  const char *page, size_t len) +{ +	int l; + +	l = min_t(int, 8, len); +	if (page[l - 1] == '\n') +		--l; +	if (desc->opts_mutex) +		mutex_lock(desc->opts_mutex); +	memcpy(desc->ext_compat_id + 8, page, l); +	desc->ext_compat_id[l + 8] = '\0'; + +	if (desc->opts_mutex) +		mutex_unlock(desc->opts_mutex); + +	return len; +} + +static struct usb_os_desc_attribute interf_grp_attr_sub_compatible_id = +	__CONFIGFS_ATTR(sub_compatible_id, S_IRUGO | S_IWUSR, +			interf_grp_sub_compatible_id_show, +			interf_grp_sub_compatible_id_store); + +static struct configfs_attribute *interf_grp_attrs[] = { +	&interf_grp_attr_compatible_id.attr, +	&interf_grp_attr_sub_compatible_id.attr, +	NULL +}; + +int usb_os_desc_prepare_interf_dir(struct config_group *parent, +				   int n_interf, +				   struct usb_os_desc **desc, +				   char **names, +				   struct module *owner) +{ +	struct config_group **f_default_groups, *os_desc_group, +				**interface_groups; +	struct config_item_type *os_desc_type, *interface_type; + +	vla_group(data_chunk); +	vla_item(data_chunk, struct config_group *, f_default_groups, 2); +	vla_item(data_chunk, struct config_group, os_desc_group, 1); +	vla_item(data_chunk, struct config_group *, interface_groups, +		 n_interf + 1); +	vla_item(data_chunk, struct config_item_type, os_desc_type, 1); +	vla_item(data_chunk, struct config_item_type, interface_type, 1); + +	char *vlabuf = kzalloc(vla_group_size(data_chunk), GFP_KERNEL); +	if (!vlabuf) +		return -ENOMEM; + +	f_default_groups = vla_ptr(vlabuf, data_chunk, f_default_groups); +	os_desc_group = vla_ptr(vlabuf, data_chunk, os_desc_group); +	os_desc_type = vla_ptr(vlabuf, data_chunk, os_desc_type); +	interface_groups = vla_ptr(vlabuf, data_chunk, interface_groups); +	interface_type = vla_ptr(vlabuf, data_chunk, interface_type); + +	parent->default_groups = f_default_groups; +	os_desc_type->ct_owner = owner; +	config_group_init_type_name(os_desc_group, "os_desc", os_desc_type); +	f_default_groups[0] = os_desc_group; + +	os_desc_group->default_groups = interface_groups; +	interface_type->ct_item_ops = &interf_item_ops; +	interface_type->ct_group_ops = &interf_grp_ops; +	interface_type->ct_attrs = interf_grp_attrs; +	interface_type->ct_owner = owner; + +	while (n_interf--) { +		struct usb_os_desc *d; + +		d = desc[n_interf]; +		d->owner = owner; +		config_group_init_type_name(&d->group, "", interface_type); +		config_item_set_name(&d->group.cg_item, "interface.%s", +				     names[n_interf]); +		interface_groups[n_interf] = &d->group; +	} + +	return 0; +} +EXPORT_SYMBOL(usb_os_desc_prepare_interf_dir); +  static int configfs_do_nothing(struct usb_composite_dev *cdev)  {  	WARN_ON(1); @@ -737,6 +1276,9 @@ static int configfs_do_nothing(struct usb_composite_dev *cdev)  int composite_dev_prepare(struct usb_composite_driver *composite,  		struct usb_composite_dev *dev); +int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, +				  struct usb_ep *ep0); +  static void purge_configs_funcs(struct gadget_info *gi)  {  	struct usb_configuration	*c; @@ -785,7 +1327,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget,  	ret = -EINVAL;  	if (list_empty(&gi->cdev.configs)) { -		pr_err("Need atleast one configuration in %s.\n", +		pr_err("Need at least one configuration in %s.\n",  				gi->composite.name);  		goto err_comp_cleanup;  	} @@ -796,7 +1338,7 @@ static int configfs_composite_bind(struct usb_gadget *gadget,  		cfg = container_of(c, struct config_usb_cfg, c);  		if (list_empty(&cfg->func_list)) { -			pr_err("Config %s/%d of %s needs atleast one function.\n", +			pr_err("Config %s/%d of %s needs at least one function.\n",  			      c->label, c->bConfigurationValue,  			      gi->composite.name);  			goto err_comp_cleanup; @@ -831,6 +1373,12 @@ static int configfs_composite_bind(struct usb_gadget *gadget,  		gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id;  	} +	if (gi->use_os_desc) { +		cdev->use_os_string = true; +		cdev->b_vendor_code = gi->b_vendor_code; +		memcpy(cdev->qw_sign, gi->qw_sign, OS_STRING_QW_SIGN_LEN); +	} +  	/* Go through all configs, attach all functions */  	list_for_each_entry(c, &gi->cdev.configs, list) {  		struct config_usb_cfg *cfg; @@ -866,6 +1414,12 @@ static int configfs_composite_bind(struct usb_gadget *gadget,  		}  		usb_ep_autoconfig_reset(cdev->gadget);  	} +	if (cdev->use_os_string) { +		ret = composite_os_desc_req_prepare(cdev, gadget->ep0); +		if (ret) +			goto err_purge_funcs; +	} +  	usb_ep_autoconfig_reset(cdev->gadget);  	return 0; @@ -921,6 +1475,7 @@ static struct config_group *gadgets_make(  	gi->group.default_groups[0] = &gi->functions_group;  	gi->group.default_groups[1] = &gi->configs_group;  	gi->group.default_groups[2] = &gi->strings_group; +	gi->group.default_groups[3] = &gi->os_desc_group;  	config_group_init_type_name(&gi->functions_group, "functions",  			&functions_type); @@ -928,6 +1483,8 @@ static struct config_group *gadgets_make(  			&config_desc_type);  	config_group_init_type_name(&gi->strings_group, "strings",  			&gadget_strings_strings_type); +	config_group_init_type_name(&gi->os_desc_group, "os_desc", +			&os_desc_type);  	gi->composite.bind = configfs_do_nothing;  	gi->composite.unbind = configfs_do_nothing; @@ -991,6 +1548,14 @@ static struct configfs_subsystem gadget_subsys = {  	.su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex),  }; +void unregister_gadget_item(struct config_item *item) +{ +	struct gadget_info *gi = to_gadget_info(item); + +	unregister_gadget(gi); +} +EXPORT_SYMBOL_GPL(unregister_gadget_item); +  static int __init gadget_cfs_init(void)  {  	int ret; diff --git a/drivers/usb/gadget/configfs.h b/drivers/usb/gadget/configfs.h new file mode 100644 index 00000000000..36c468c4f5e --- /dev/null +++ b/drivers/usb/gadget/configfs.h @@ -0,0 +1,19 @@ +#ifndef USB__GADGET__CONFIGFS__H +#define USB__GADGET__CONFIGFS__H + +#include <linux/configfs.h> + +void unregister_gadget_item(struct config_item *item); + +int usb_os_desc_prepare_interf_dir(struct config_group *parent, +				   int n_interf, +				   struct usb_os_desc **desc, +				   char **names, +				   struct module *owner); + +static inline struct usb_os_desc *to_usb_os_desc(struct config_item *item) +{ +	return container_of(to_config_group(item), struct usb_os_desc, group); +} + +#endif /*  USB__GADGET__CONFIGFS__H */ diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 06ecd08fd57..2b54955d316 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -544,7 +544,7 @@ static int dummy_enable(struct usb_ep *_ep,  		 default:  			 val = "ctrl";  			 break; -		 }; val; }), +		 } val; }),  		max, ep->stream_en ? "enabled" : "disabled");  	/* at this point real hardware should be NAKing transfers @@ -561,7 +561,6 @@ static int dummy_disable(struct usb_ep *_ep)  	struct dummy_ep		*ep;  	struct dummy		*dum;  	unsigned long		flags; -	int			retval;  	ep = usb_ep_to_dummy_ep(_ep);  	if (!_ep || !ep->desc || _ep->name == ep0name) @@ -571,12 +570,11 @@ static int dummy_disable(struct usb_ep *_ep)  	spin_lock_irqsave(&dum->lock, flags);  	ep->desc = NULL;  	ep->stream_en = 0; -	retval = 0;  	nuke(dum, ep);  	spin_unlock_irqrestore(&dum->lock, flags);  	dev_dbg(udc_dev(dum), "disabled %s\n", _ep->name); -	return retval; +	return 0;  }  static struct usb_request *dummy_alloc_request(struct usb_ep *_ep, @@ -923,8 +921,9 @@ static int dummy_udc_stop(struct usb_gadget *g,  	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);  	struct dummy		*dum = dum_hcd->dum; -	dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n", -			driver->driver.name); +	if (driver) +		dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n", +				driver->driver.name);  	dum->driver = NULL; @@ -950,7 +949,7 @@ static void init_dummy_udc_hw(struct dummy *dum)  		list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list);  		ep->halted = ep->wedged = ep->already_seen =  				ep->setup_stage = 0; -		ep->ep.maxpacket = ~0; +		usb_ep_set_maxpacket_limit(&ep->ep, ~0);  		ep->ep.max_streams = 16;  		ep->last_io = jiffies;  		ep->gadget = &dum->gadget; @@ -1000,8 +999,8 @@ static int dummy_udc_remove(struct platform_device *pdev)  {  	struct dummy	*dum = platform_get_drvdata(pdev); -	usb_del_gadget_udc(&dum->gadget);  	device_remove_file(&dum->gadget.dev, &dev_attr_function); +	usb_del_gadget_udc(&dum->gadget);  	return 0;  } @@ -2270,7 +2269,7 @@ static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb)  		default:  			s = "?";  			break; -		 }; s; }), +		 } s; }),  		ep, ep ? (usb_pipein(urb->pipe) ? "in" : "out") : "",  		({ char *s; \  		switch (usb_pipetype(urb->pipe)) { \ @@ -2286,7 +2285,7 @@ static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb)  		default: \  			s = "-iso"; \  			break; \ -		}; s; }), +		} s; }),  		urb->actual_length, urb->transfer_buffer_length);  } diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index a777f7bd11b..0567cca1465 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -11,7 +11,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/types.h>  #include <linux/device.h> @@ -58,7 +57,7 @@ ep_matches (  		return 0;  	/* only support ep0 for portable CONTROL traffic */ -	type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; +	type = usb_endpoint_type(desc);  	if (USB_ENDPOINT_XFER_CONTROL == type)  		return 0; @@ -129,7 +128,7 @@ ep_matches (  	 * and wants to know the maximum possible, provide the info.  	 */  	if (desc->wMaxPacketSize == 0) -		desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket); +		desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit);  	/* endpoint maxpacket size is an input parameter, except for bulk  	 * where it's an output parameter representing the full speed limit. @@ -145,7 +144,7 @@ ep_matches (  	case USB_ENDPOINT_XFER_ISOC:  		/* ISO:  limit 1023 bytes full speed, 1024 high/super speed */ -		if (ep->maxpacket < max) +		if (ep->maxpacket_limit < max)  			return 0;  		if (!gadget_is_dualspeed(gadget) && max > 1023)  			return 0; @@ -178,7 +177,7 @@ ep_matches (  	/* report (variable) full speed bulk maxpacket */  	if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) { -		int size = ep->maxpacket; +		int size = ep->maxpacket_limit;  		/* min() doesn't work on bitfields with gcc-3.5 */  		if (size > 64) diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c index edab45da374..798760fa7e7 100644 --- a/drivers/usb/gadget/f_ecm.c +++ b/drivers/usb/gadget/f_ecm.c @@ -691,7 +691,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)  	int			status;  	struct usb_ep		*ep; -#ifndef USBF_ECM_INCLUDED  	struct f_ecm_opts	*ecm_opts;  	if (!can_support_ecm(cdev->gadget)) @@ -715,7 +714,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)  			return status;  		ecm_opts->bound = true;  	} -#endif +  	us = usb_gstrings_attach(cdev, ecm_strings,  				 ARRAY_SIZE(ecm_string_defs));  	if (IS_ERR(us)) @@ -834,74 +833,6 @@ fail:  	return status;  } -#ifdef USBF_ECM_INCLUDED - -static void -ecm_old_unbind(struct usb_configuration *c, struct usb_function *f) -{ -	struct f_ecm		*ecm = func_to_ecm(f); - -	DBG(c->cdev, "ecm unbind\n"); - -	usb_free_all_descriptors(f); - -	kfree(ecm->notify_req->buf); -	usb_ep_free_request(ecm->notify, ecm->notify_req); -	kfree(ecm); -} - -/** - * ecm_bind_config - add CDC Ethernet network link to a configuration - * @c: the configuration to support the network link - * @ethaddr: a buffer in which the ethernet address of the host side - *	side of the link was recorded - * @dev: eth_dev structure - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup().  Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ -int -ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		struct eth_dev *dev) -{ -	struct f_ecm	*ecm; -	int		status; - -	if (!can_support_ecm(c->cdev->gadget) || !ethaddr) -		return -EINVAL; - -	/* allocate and initialize one new instance */ -	ecm = kzalloc(sizeof *ecm, GFP_KERNEL); -	if (!ecm) -		return -ENOMEM; - -	/* export host's Ethernet address in CDC format */ -	snprintf(ecm->ethaddr, sizeof ecm->ethaddr, "%pm", ethaddr); -	ecm_string_defs[1].s = ecm->ethaddr; - -	ecm->port.ioport = dev; -	ecm->port.cdc_filter = DEFAULT_FILTER; - -	ecm->port.func.name = "cdc_ethernet"; -	/* descriptors are per-instance copies */ -	ecm->port.func.bind = ecm_bind; -	ecm->port.func.unbind = ecm_old_unbind; -	ecm->port.func.set_alt = ecm_set_alt; -	ecm->port.func.get_alt = ecm_get_alt; -	ecm->port.func.setup = ecm_setup; -	ecm->port.func.disable = ecm_disable; - -	status = usb_add_function(c, &ecm->port.func); -	if (status) -		kfree(ecm); -	return status; -} - -#else -  static inline struct f_ecm_opts *to_f_ecm_opts(struct config_item *item)  {  	return container_of(to_config_group(item), struct f_ecm_opts, @@ -995,7 +926,7 @@ static void ecm_unbind(struct usb_configuration *c, struct usb_function *f)  	usb_ep_free_request(ecm->notify, ecm->notify_req);  } -struct usb_function *ecm_alloc(struct usb_function_instance *fi) +static struct usb_function *ecm_alloc(struct usb_function_instance *fi)  {  	struct f_ecm	*ecm;  	struct f_ecm_opts *opts; @@ -1040,5 +971,3 @@ struct usb_function *ecm_alloc(struct usb_function_instance *fi)  DECLARE_USB_FUNCTION_INIT(ecm, ecm_alloc_inst, ecm_alloc);  MODULE_LICENSE("GPL");  MODULE_AUTHOR("David Brownell"); - -#endif diff --git a/drivers/usb/gadget/f_eem.c b/drivers/usb/gadget/f_eem.c index d00392d879d..d61c11d765d 100644 --- a/drivers/usb/gadget/f_eem.c +++ b/drivers/usb/gadget/f_eem.c @@ -624,7 +624,7 @@ static void eem_unbind(struct usb_configuration *c, struct usb_function *f)  	usb_free_all_descriptors(f);  } -struct usb_function *eem_alloc(struct usb_function_instance *fi) +static struct usb_function *eem_alloc(struct usb_function_instance *fi)  {  	struct f_eem	*eem;  	struct f_eem_opts *opts; diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 1a66c5baa0d..8598c27c7d4 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -22,218 +22,21 @@  #include <linux/pagemap.h>  #include <linux/export.h>  #include <linux/hid.h> +#include <linux/module.h>  #include <asm/unaligned.h>  #include <linux/usb/composite.h>  #include <linux/usb/functionfs.h> +#include <linux/aio.h> +#include <linux/mmu_context.h> +#include <linux/poll.h> -#define FUNCTIONFS_MAGIC	0xa647361 /* Chosen by a honest dice roll ;) */ - - -/* Debugging ****************************************************************/ - -#ifdef VERBOSE_DEBUG -#ifndef pr_vdebug -#  define pr_vdebug pr_debug -#endif /* pr_vdebug */ -#  define ffs_dump_mem(prefix, ptr, len) \ -	print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len) -#else -#ifndef pr_vdebug -#  define pr_vdebug(...)                 do { } while (0) -#endif /* pr_vdebug */ -#  define ffs_dump_mem(prefix, ptr, len) do { } while (0) -#endif /* VERBOSE_DEBUG */ - -#define ENTER()    pr_vdebug("%s()\n", __func__) - - -/* The data structure and setup file ****************************************/ - -enum ffs_state { -	/* -	 * Waiting for descriptors and strings. -	 * -	 * In this state no open(2), read(2) or write(2) on epfiles -	 * may succeed (which should not be the problem as there -	 * should be no such files opened in the first place). -	 */ -	FFS_READ_DESCRIPTORS, -	FFS_READ_STRINGS, - -	/* -	 * We've got descriptors and strings.  We are or have called -	 * functionfs_ready_callback().  functionfs_bind() may have -	 * been called but we don't know. -	 * -	 * This is the only state in which operations on epfiles may -	 * succeed. -	 */ -	FFS_ACTIVE, - -	/* -	 * All endpoints have been closed.  This state is also set if -	 * we encounter an unrecoverable error.  The only -	 * unrecoverable error is situation when after reading strings -	 * from user space we fail to initialise epfiles or -	 * functionfs_ready_callback() returns with error (<0). -	 * -	 * In this state no open(2), read(2) or write(2) (both on ep0 -	 * as well as epfile) may succeed (at this point epfiles are -	 * unlinked and all closed so this is not a problem; ep0 is -	 * also closed but ep0 file exists and so open(2) on ep0 must -	 * fail). -	 */ -	FFS_CLOSING -}; - - -enum ffs_setup_state { -	/* There is no setup request pending. */ -	FFS_NO_SETUP, -	/* -	 * User has read events and there was a setup request event -	 * there.  The next read/write on ep0 will handle the -	 * request. -	 */ -	FFS_SETUP_PENDING, -	/* -	 * There was event pending but before user space handled it -	 * some other event was introduced which canceled existing -	 * setup.  If this state is set read/write on ep0 return -	 * -EIDRM.  This state is only set when adding event. -	 */ -	FFS_SETUP_CANCELED -}; - - - -struct ffs_epfile; -struct ffs_function; - -struct ffs_data { -	struct usb_gadget		*gadget; - -	/* -	 * Protect access read/write operations, only one read/write -	 * at a time.  As a consequence protects ep0req and company. -	 * While setup request is being processed (queued) this is -	 * held. -	 */ -	struct mutex			mutex; - -	/* -	 * Protect access to endpoint related structures (basically -	 * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for -	 * endpoint zero. -	 */ -	spinlock_t			eps_lock; +#include "u_fs.h" +#include "u_f.h" +#include "configfs.h" -	/* -	 * XXX REVISIT do we need our own request? Since we are not -	 * handling setup requests immediately user space may be so -	 * slow that another setup will be sent to the gadget but this -	 * time not to us but another function and then there could be -	 * a race.  Is that the case? Or maybe we can use cdev->req -	 * after all, maybe we just need some spinlock for that? -	 */ -	struct usb_request		*ep0req;		/* P: mutex */ -	struct completion		ep0req_completion;	/* P: mutex */ -	int				ep0req_status;		/* P: mutex */ - -	/* reference counter */ -	atomic_t			ref; -	/* how many files are opened (EP0 and others) */ -	atomic_t			opened; - -	/* EP0 state */ -	enum ffs_state			state; - -	/* -	 * Possible transitions: -	 * + FFS_NO_SETUP       -> FFS_SETUP_PENDING  -- P: ev.waitq.lock -	 *               happens only in ep0 read which is P: mutex -	 * + FFS_SETUP_PENDING  -> FFS_NO_SETUP       -- P: ev.waitq.lock -	 *               happens only in ep0 i/o  which is P: mutex -	 * + FFS_SETUP_PENDING  -> FFS_SETUP_CANCELED -- P: ev.waitq.lock -	 * + FFS_SETUP_CANCELED -> FFS_NO_SETUP       -- cmpxchg -	 */ -	enum ffs_setup_state		setup_state; - -#define FFS_SETUP_STATE(ffs)					\ -	((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state,	\ -				       FFS_SETUP_CANCELED, FFS_NO_SETUP)) - -	/* Events & such. */ -	struct { -		u8				types[4]; -		unsigned short			count; -		/* XXX REVISIT need to update it in some places, or do we? */ -		unsigned short			can_stall; -		struct usb_ctrlrequest		setup; - -		wait_queue_head_t		waitq; -	} ev; /* the whole structure, P: ev.waitq.lock */ - -	/* Flags */ -	unsigned long			flags; -#define FFS_FL_CALL_CLOSED_CALLBACK 0 -#define FFS_FL_BOUND                1 - -	/* Active function */ -	struct ffs_function		*func; - -	/* -	 * Device name, write once when file system is mounted. -	 * Intended for user to read if she wants. -	 */ -	const char			*dev_name; -	/* Private data for our user (ie. gadget).  Managed by user. */ -	void				*private_data; - -	/* filled by __ffs_data_got_descs() */ -	/* -	 * Real descriptors are 16 bytes after raw_descs (so you need -	 * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the -	 * first full speed descriptor).  raw_descs_length and -	 * raw_fs_descs_length do not have those 16 bytes added. -	 */ -	const void			*raw_descs; -	unsigned			raw_descs_length; -	unsigned			raw_fs_descs_length; -	unsigned			fs_descs_count; -	unsigned			hs_descs_count; - -	unsigned short			strings_count; -	unsigned short			interfaces_count; -	unsigned short			eps_count; -	unsigned short			_pad1; - -	/* filled by __ffs_data_got_strings() */ -	/* ids in stringtabs are set in functionfs_bind() */ -	const void			*raw_strings; -	struct usb_gadget_strings	**stringtabs; - -	/* -	 * File system's super block, write once when file system is -	 * mounted. -	 */ -	struct super_block		*sb; - -	/* File permissions, written once when fs is mounted */ -	struct ffs_file_perms { -		umode_t				mode; -		kuid_t				uid; -		kgid_t				gid; -	}				file_perms; - -	/* -	 * The endpoint files, filled by ffs_epfiles_create(), -	 * destroyed by ffs_epfiles_destroy(). -	 */ -	struct ffs_epfile		*epfiles; -}; +#define FUNCTIONFS_MAGIC	0xa647361 /* Chosen by a honest dice roll ;) */  /* Reference counter handling */  static void ffs_data_get(struct ffs_data *ffs); @@ -274,15 +77,20 @@ static struct ffs_function *ffs_func_from_usb(struct usb_function *f)  	return container_of(f, struct ffs_function, function);  } -static void ffs_func_free(struct ffs_function *func); + +static inline enum ffs_setup_state +ffs_setup_state_clear_cancelled(struct ffs_data *ffs) +{ +	return (enum ffs_setup_state) +		cmpxchg(&ffs->setup_state, FFS_SETUP_CANCELLED, FFS_NO_SETUP); +} +  static void ffs_func_eps_disable(struct ffs_function *func);  static int __must_check ffs_func_eps_enable(struct ffs_function *func);  static int ffs_func_bind(struct usb_configuration *,  			 struct usb_function *); -static void ffs_func_unbind(struct usb_configuration *, -			    struct usb_function *);  static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned);  static void ffs_func_disable(struct usb_function *);  static int ffs_func_setup(struct usb_function *, @@ -301,8 +109,8 @@ struct ffs_ep {  	struct usb_ep			*ep;	/* P: ffs->eps_lock */  	struct usb_request		*req;	/* P: epfile->mutex */ -	/* [0]: full speed, [1]: high speed */ -	struct usb_endpoint_descriptor	*descs[2]; +	/* [0]: full speed, [1]: high speed, [2]: super speed */ +	struct usb_endpoint_descriptor	*descs[3];  	u8				num; @@ -327,6 +135,25 @@ struct ffs_epfile {  	unsigned char			_pad;  }; +/*  ffs_io_data structure ***************************************************/ + +struct ffs_io_data { +	bool aio; +	bool read; + +	struct kiocb *kiocb; +	const struct iovec *iovec; +	unsigned long nr_segs; +	char __user *buf; +	size_t len; + +	struct mm_struct *mm; +	struct work_struct work; + +	struct usb_ep *ep; +	struct usb_request *req; +}; +  static int  __must_check ffs_epfiles_create(struct ffs_data *ffs);  static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count); @@ -335,6 +162,19 @@ ffs_sb_create_file(struct super_block *sb, const char *name, void *data,  		   const struct file_operations *fops,  		   struct dentry **dentry_p); +/* Devices management *******************************************************/ + +DEFINE_MUTEX(ffs_lock); +EXPORT_SYMBOL_GPL(ffs_lock); + +static struct ffs_dev *_ffs_find_dev(const char *name); +static struct ffs_dev *_ffs_alloc_dev(void); +static int _ffs_name_dev(struct ffs_dev *dev, const char *name); +static void _ffs_free_dev(struct ffs_dev *dev); +static void *ffs_acquire_dev(const char *dev_name); +static void ffs_release_dev(struct ffs_data *ffs_data); +static int ffs_ready(struct ffs_data *ffs); +static void ffs_closed(struct ffs_data *ffs);  /* Misc helper functions ****************************************************/ @@ -373,7 +213,7 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)  	if (req->buf == NULL)  		req->buf = (void *)0xDEADBABE; -	INIT_COMPLETION(ffs->ep0req_completion); +	reinit_completion(&ffs->ep0req_completion);  	ret = usb_ep_queue(ffs->gadget->ep0, req, GFP_ATOMIC);  	if (unlikely(ret < 0)) @@ -386,7 +226,7 @@ static int __ffs_ep0_queue_wait(struct ffs_data *ffs, char *data, size_t len)  	}  	ffs->setup_state = FFS_NO_SETUP; -	return ffs->ep0req_status; +	return req->status ? req->status : req->actual;  }  static int __ffs_ep0_stall(struct ffs_data *ffs) @@ -412,7 +252,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,  	ENTER();  	/* Fast check if setup was canceled */ -	if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) +	if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)  		return -EIDRM;  	/* Acquire mutex */ @@ -460,7 +300,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,  			ffs->state = FFS_ACTIVE;  			mutex_unlock(&ffs->mutex); -			ret = functionfs_ready_callback(ffs); +			ret = ffs_ready(ffs);  			if (unlikely(ret < 0)) {  				ffs->state = FFS_CLOSING;  				return ret; @@ -478,8 +318,8 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,  		 * rather then _irqsave  		 */  		spin_lock_irq(&ffs->ev.waitq.lock); -		switch (FFS_SETUP_STATE(ffs)) { -		case FFS_SETUP_CANCELED: +		switch (ffs_setup_state_clear_cancelled(ffs)) { +		case FFS_SETUP_CANCELLED:  			ret = -EIDRM;  			goto done_spin; @@ -514,7 +354,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,  		/*  		 * We are guaranteed to be still in FFS_ACTIVE state  		 * but the state of setup could have changed from -		 * FFS_SETUP_PENDING to FFS_SETUP_CANCELED so we need +		 * FFS_SETUP_PENDING to FFS_SETUP_CANCELLED so we need  		 * to check for that.  If that happened we copied data  		 * from user space in vain but it's unlikely.  		 * @@ -523,7 +363,8 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,  		 * transition can be performed and it's protected by  		 * mutex.  		 */ -		if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) { +		if (ffs_setup_state_clear_cancelled(ffs) == +		    FFS_SETUP_CANCELLED) {  			ret = -EIDRM;  done_spin:  			spin_unlock_irq(&ffs->ev.waitq.lock); @@ -589,7 +430,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,  	ENTER();  	/* Fast check if setup was canceled */ -	if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) +	if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED)  		return -EIDRM;  	/* Acquire mutex */ @@ -609,8 +450,8 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,  	 */  	spin_lock_irq(&ffs->ev.waitq.lock); -	switch (FFS_SETUP_STATE(ffs)) { -	case FFS_SETUP_CANCELED: +	switch (ffs_setup_state_clear_cancelled(ffs)) { +	case FFS_SETUP_CANCELLED:  		ret = -EIDRM;  		break; @@ -657,7 +498,8 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,  		spin_lock_irq(&ffs->ev.waitq.lock);  		/* See ffs_ep0_write() */ -		if (FFS_SETUP_STATE(ffs) == FFS_SETUP_CANCELED) { +		if (ffs_setup_state_clear_cancelled(ffs) == +		    FFS_SETUP_CANCELLED) {  			ret = -EIDRM;  			break;  		} @@ -726,6 +568,45 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)  	return ret;  } +static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait) +{ +	struct ffs_data *ffs = file->private_data; +	unsigned int mask = POLLWRNORM; +	int ret; + +	poll_wait(file, &ffs->ev.waitq, wait); + +	ret = ffs_mutex_lock(&ffs->mutex, file->f_flags & O_NONBLOCK); +	if (unlikely(ret < 0)) +		return mask; + +	switch (ffs->state) { +	case FFS_READ_DESCRIPTORS: +	case FFS_READ_STRINGS: +		mask |= POLLOUT; +		break; + +	case FFS_ACTIVE: +		switch (ffs->setup_state) { +		case FFS_NO_SETUP: +			if (ffs->ev.count) +				mask |= POLLIN; +			break; + +		case FFS_SETUP_PENDING: +		case FFS_SETUP_CANCELLED: +			mask |= (POLLIN | POLLOUT); +			break; +		} +	case FFS_CLOSING: +		break; +	} + +	mutex_unlock(&ffs->mutex); + +	return mask; +} +  static const struct file_operations ffs_ep0_operations = {  	.llseek =	no_llseek, @@ -734,6 +615,7 @@ static const struct file_operations ffs_ep0_operations = {  	.read =		ffs_ep0_read,  	.release =	ffs_ep0_release,  	.unlocked_ioctl =	ffs_ep0_ioctl, +	.poll =		ffs_ep0_poll,  }; @@ -749,114 +631,226 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req)  	}  } -static ssize_t ffs_epfile_io(struct file *file, -			     char __user *buf, size_t len, int read) +static void ffs_user_copy_worker(struct work_struct *work) +{ +	struct ffs_io_data *io_data = container_of(work, struct ffs_io_data, +						   work); +	int ret = io_data->req->status ? io_data->req->status : +					 io_data->req->actual; + +	if (io_data->read && ret > 0) { +		int i; +		size_t pos = 0; +		use_mm(io_data->mm); +		for (i = 0; i < io_data->nr_segs; i++) { +			if (unlikely(copy_to_user(io_data->iovec[i].iov_base, +						 &io_data->buf[pos], +						 io_data->iovec[i].iov_len))) { +				ret = -EFAULT; +				break; +			} +			pos += io_data->iovec[i].iov_len; +		} +		unuse_mm(io_data->mm); +	} + +	aio_complete(io_data->kiocb, ret, ret); + +	usb_ep_free_request(io_data->ep, io_data->req); + +	io_data->kiocb->private = NULL; +	if (io_data->read) +		kfree(io_data->iovec); +	kfree(io_data->buf); +	kfree(io_data); +} + +static void ffs_epfile_async_io_complete(struct usb_ep *_ep, +					 struct usb_request *req) +{ +	struct ffs_io_data *io_data = req->context; + +	ENTER(); + +	INIT_WORK(&io_data->work, ffs_user_copy_worker); +	schedule_work(&io_data->work); +} + +static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)  {  	struct ffs_epfile *epfile = file->private_data;  	struct ffs_ep *ep;  	char *data = NULL; -	ssize_t ret; +	ssize_t ret, data_len;  	int halt; -	goto first_try; -	do { -		spin_unlock_irq(&epfile->ffs->eps_lock); -		mutex_unlock(&epfile->mutex); +	/* Are we still active? */ +	if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) { +		ret = -ENODEV; +		goto error; +	} -first_try: -		/* Are we still active? */ -		if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) { -			ret = -ENODEV; +	/* Wait for endpoint to be enabled */ +	ep = epfile->ep; +	if (!ep) { +		if (file->f_flags & O_NONBLOCK) { +			ret = -EAGAIN;  			goto error;  		} -		/* Wait for endpoint to be enabled */ -		ep = epfile->ep; -		if (!ep) { -			if (file->f_flags & O_NONBLOCK) { -				ret = -EAGAIN; -				goto error; -			} - -			if (wait_event_interruptible(epfile->wait, -						     (ep = epfile->ep))) { -				ret = -EINTR; -				goto error; -			} -		} - -		/* Do we halt? */ -		halt = !read == !epfile->in; -		if (halt && epfile->isoc) { -			ret = -EINVAL; +		ret = wait_event_interruptible(epfile->wait, (ep = epfile->ep)); +		if (ret) { +			ret = -EINTR;  			goto error;  		} +	} -		/* Allocate & copy */ -		if (!halt && !data) { -			data = kzalloc(len, GFP_KERNEL); -			if (unlikely(!data)) -				return -ENOMEM; +	/* Do we halt? */ +	halt = (!io_data->read == !epfile->in); +	if (halt && epfile->isoc) { +		ret = -EINVAL; +		goto error; +	} -			if (!read && -			    unlikely(__copy_from_user(data, buf, len))) { +	/* Allocate & copy */ +	if (!halt) { +		/* +		 * if we _do_ wait above, the epfile->ffs->gadget might be NULL +		 * before the waiting completes, so do not assign to 'gadget' earlier +		 */ +		struct usb_gadget *gadget = epfile->ffs->gadget; + +		spin_lock_irq(&epfile->ffs->eps_lock); +		/* In the meantime, endpoint got disabled or changed. */ +		if (epfile->ep != ep) { +			spin_unlock_irq(&epfile->ffs->eps_lock); +			return -ESHUTDOWN; +		} +		/* +		 * Controller may require buffer size to be aligned to +		 * maxpacketsize of an out endpoint. +		 */ +		data_len = io_data->read ? +			   usb_ep_align_maybe(gadget, ep->ep, io_data->len) : +			   io_data->len; +		spin_unlock_irq(&epfile->ffs->eps_lock); + +		data = kmalloc(data_len, GFP_KERNEL); +		if (unlikely(!data)) +			return -ENOMEM; +		if (io_data->aio && !io_data->read) { +			int i; +			size_t pos = 0; +			for (i = 0; i < io_data->nr_segs; i++) { +				if (unlikely(copy_from_user(&data[pos], +					     io_data->iovec[i].iov_base, +					     io_data->iovec[i].iov_len))) { +					ret = -EFAULT; +					goto error; +				} +				pos += io_data->iovec[i].iov_len; +			} +		} else { +			if (!io_data->read && +			    unlikely(__copy_from_user(data, io_data->buf, +						      io_data->len))) {  				ret = -EFAULT;  				goto error;  			}  		} +	} -		/* We will be using request */ -		ret = ffs_mutex_lock(&epfile->mutex, -				     file->f_flags & O_NONBLOCK); -		if (unlikely(ret)) -			goto error; - -		/* -		 * We're called from user space, we can use _irq rather then -		 * _irqsave -		 */ -		spin_lock_irq(&epfile->ffs->eps_lock); +	/* We will be using request */ +	ret = ffs_mutex_lock(&epfile->mutex, file->f_flags & O_NONBLOCK); +	if (unlikely(ret)) +		goto error; -		/* -		 * While we were acquiring mutex endpoint got disabled -		 * or changed? -		 */ -	} while (unlikely(epfile->ep != ep)); +	spin_lock_irq(&epfile->ffs->eps_lock); -	/* Halt */ -	if (unlikely(halt)) { +	if (epfile->ep != ep) { +		/* In the meantime, endpoint got disabled or changed. */ +		ret = -ESHUTDOWN; +		spin_unlock_irq(&epfile->ffs->eps_lock); +	} else if (halt) { +		/* Halt */  		if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep))  			usb_ep_set_halt(ep->ep);  		spin_unlock_irq(&epfile->ffs->eps_lock);  		ret = -EBADMSG;  	} else {  		/* Fire the request */ -		DECLARE_COMPLETION_ONSTACK(done); +		struct usb_request *req; -		struct usb_request *req = ep->req; -		req->context  = &done; -		req->complete = ffs_epfile_io_complete; -		req->buf      = data; -		req->length   = len; +		if (io_data->aio) { +			req = usb_ep_alloc_request(ep->ep, GFP_KERNEL); +			if (unlikely(!req)) +				goto error_lock; -		ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); +			req->buf      = data; +			req->length   = io_data->len; -		spin_unlock_irq(&epfile->ffs->eps_lock); +			io_data->buf = data; +			io_data->ep = ep->ep; +			io_data->req = req; -		if (unlikely(ret < 0)) { -			/* nop */ -		} else if (unlikely(wait_for_completion_interruptible(&done))) { -			ret = -EINTR; -			usb_ep_dequeue(ep->ep, req); +			req->context  = io_data; +			req->complete = ffs_epfile_async_io_complete; + +			ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); +			if (unlikely(ret)) { +				usb_ep_free_request(ep->ep, req); +				goto error_lock; +			} +			ret = -EIOCBQUEUED; + +			spin_unlock_irq(&epfile->ffs->eps_lock);  		} else { -			ret = ep->status; -			if (read && ret > 0 && -			    unlikely(copy_to_user(buf, data, ret))) -				ret = -EFAULT; +			DECLARE_COMPLETION_ONSTACK(done); + +			req = ep->req; +			req->buf      = data; +			req->length   = io_data->len; + +			req->context  = &done; +			req->complete = ffs_epfile_io_complete; + +			ret = usb_ep_queue(ep->ep, req, GFP_ATOMIC); + +			spin_unlock_irq(&epfile->ffs->eps_lock); + +			if (unlikely(ret < 0)) { +				/* nop */ +			} else if (unlikely( +				   wait_for_completion_interruptible(&done))) { +				ret = -EINTR; +				usb_ep_dequeue(ep->ep, req); +			} else { +				/* +				 * XXX We may end up silently droping data +				 * here.  Since data_len (i.e. req->length) may +				 * be bigger than len (after being rounded up +				 * to maxpacketsize), we may end up with more +				 * data then user space has space for. +				 */ +				ret = ep->status; +				if (io_data->read && ret > 0) { +					ret = min_t(size_t, ret, io_data->len); + +					if (unlikely(copy_to_user(io_data->buf, +						data, ret))) +						ret = -EFAULT; +				} +			} +			kfree(data);  		}  	}  	mutex_unlock(&epfile->mutex); +	return ret; + +error_lock: +	spin_unlock_irq(&epfile->ffs->eps_lock); +	mutex_unlock(&epfile->mutex);  error:  	kfree(data);  	return ret; @@ -866,17 +860,31 @@ static ssize_t  ffs_epfile_write(struct file *file, const char __user *buf, size_t len,  		 loff_t *ptr)  { +	struct ffs_io_data io_data; +  	ENTER(); -	return ffs_epfile_io(file, (char __user *)buf, len, 0); +	io_data.aio = false; +	io_data.read = false; +	io_data.buf = (char * __user)buf; +	io_data.len = len; + +	return ffs_epfile_io(file, &io_data);  }  static ssize_t  ffs_epfile_read(struct file *file, char __user *buf, size_t len, loff_t *ptr)  { +	struct ffs_io_data io_data; +  	ENTER(); -	return ffs_epfile_io(file, buf, len, 1); +	io_data.aio = false; +	io_data.read = true; +	io_data.buf = buf; +	io_data.len = len; + +	return ffs_epfile_io(file, &io_data);  }  static int @@ -895,6 +903,89 @@ ffs_epfile_open(struct inode *inode, struct file *file)  	return 0;  } +static int ffs_aio_cancel(struct kiocb *kiocb) +{ +	struct ffs_io_data *io_data = kiocb->private; +	struct ffs_epfile *epfile = kiocb->ki_filp->private_data; +	int value; + +	ENTER(); + +	spin_lock_irq(&epfile->ffs->eps_lock); + +	if (likely(io_data && io_data->ep && io_data->req)) +		value = usb_ep_dequeue(io_data->ep, io_data->req); +	else +		value = -EINVAL; + +	spin_unlock_irq(&epfile->ffs->eps_lock); + +	return value; +} + +static ssize_t ffs_epfile_aio_write(struct kiocb *kiocb, +				    const struct iovec *iovec, +				    unsigned long nr_segs, loff_t loff) +{ +	struct ffs_io_data *io_data; + +	ENTER(); + +	io_data = kmalloc(sizeof(*io_data), GFP_KERNEL); +	if (unlikely(!io_data)) +		return -ENOMEM; + +	io_data->aio = true; +	io_data->read = false; +	io_data->kiocb = kiocb; +	io_data->iovec = iovec; +	io_data->nr_segs = nr_segs; +	io_data->len = kiocb->ki_nbytes; +	io_data->mm = current->mm; + +	kiocb->private = io_data; + +	kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); + +	return ffs_epfile_io(kiocb->ki_filp, io_data); +} + +static ssize_t ffs_epfile_aio_read(struct kiocb *kiocb, +				   const struct iovec *iovec, +				   unsigned long nr_segs, loff_t loff) +{ +	struct ffs_io_data *io_data; +	struct iovec *iovec_copy; + +	ENTER(); + +	iovec_copy = kmalloc_array(nr_segs, sizeof(*iovec_copy), GFP_KERNEL); +	if (unlikely(!iovec_copy)) +		return -ENOMEM; + +	memcpy(iovec_copy, iovec, sizeof(struct iovec)*nr_segs); + +	io_data = kmalloc(sizeof(*io_data), GFP_KERNEL); +	if (unlikely(!io_data)) { +		kfree(iovec_copy); +		return -ENOMEM; +	} + +	io_data->aio = true; +	io_data->read = true; +	io_data->kiocb = kiocb; +	io_data->iovec = iovec_copy; +	io_data->nr_segs = nr_segs; +	io_data->len = kiocb->ki_nbytes; +	io_data->mm = current->mm; + +	kiocb->private = io_data; + +	kiocb_set_cancel_fn(kiocb, ffs_aio_cancel); + +	return ffs_epfile_io(kiocb->ki_filp, io_data); +} +  static int  ffs_epfile_release(struct inode *inode, struct file *file)  { @@ -951,6 +1042,8 @@ static const struct file_operations ffs_epfile_operations = {  	.open =		ffs_epfile_open,  	.write =	ffs_epfile_write,  	.read =		ffs_epfile_read, +	.aio_write =	ffs_epfile_aio_write, +	.aio_read =	ffs_epfile_aio_read,  	.release =	ffs_epfile_release,  	.unlocked_ioctl =	ffs_epfile_ioctl,  }; @@ -1034,37 +1127,19 @@ struct ffs_sb_fill_data {  	struct ffs_file_perms perms;  	umode_t root_mode;  	const char *dev_name; -	union { -		/* set by ffs_fs_mount(), read by ffs_sb_fill() */ -		void *private_data; -		/* set by ffs_sb_fill(), read by ffs_fs_mount */ -		struct ffs_data *ffs_data; -	}; +	struct ffs_data *ffs_data;  };  static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)  {  	struct ffs_sb_fill_data *data = _data;  	struct inode	*inode; -	struct ffs_data	*ffs; +	struct ffs_data	*ffs = data->ffs_data;  	ENTER(); -	/* Initialise data */ -	ffs = ffs_data_new(); -	if (unlikely(!ffs)) -		goto Enomem; -  	ffs->sb              = sb; -	ffs->dev_name        = kstrdup(data->dev_name, GFP_KERNEL); -	if (unlikely(!ffs->dev_name)) -		goto Enomem; -	ffs->file_perms      = data->perms; -	ffs->private_data    = data->private_data; - -	/* used by the caller of this function */ -	data->ffs_data       = ffs; - +	data->ffs_data       = NULL;  	sb->s_fs_info        = ffs;  	sb->s_blocksize      = PAGE_CACHE_SIZE;  	sb->s_blocksize_bits = PAGE_CACHE_SHIFT; @@ -1080,17 +1155,14 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)  				  &data->perms);  	sb->s_root = d_make_root(inode);  	if (unlikely(!sb->s_root)) -		goto Enomem; +		return -ENOMEM;  	/* EP0 file */  	if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,  					 &ffs_ep0_operations, NULL))) -		goto Enomem; +		return -ENOMEM;  	return 0; - -Enomem: -	return -ENOMEM;  }  static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts) @@ -1193,6 +1265,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,  	struct dentry *rv;  	int ret;  	void *ffs_dev; +	struct ffs_data	*ffs;  	ENTER(); @@ -1200,18 +1273,30 @@ ffs_fs_mount(struct file_system_type *t, int flags,  	if (unlikely(ret < 0))  		return ERR_PTR(ret); -	ffs_dev = functionfs_acquire_dev_callback(dev_name); -	if (IS_ERR(ffs_dev)) -		return ffs_dev; +	ffs = ffs_data_new(); +	if (unlikely(!ffs)) +		return ERR_PTR(-ENOMEM); +	ffs->file_perms = data.perms; -	data.dev_name = dev_name; -	data.private_data = ffs_dev; -	rv = mount_nodev(t, flags, &data, ffs_sb_fill); +	ffs->dev_name = kstrdup(dev_name, GFP_KERNEL); +	if (unlikely(!ffs->dev_name)) { +		ffs_data_put(ffs); +		return ERR_PTR(-ENOMEM); +	} -	/* data.ffs_data is set by ffs_sb_fill */ -	if (IS_ERR(rv)) -		functionfs_release_dev_callback(data.ffs_data); +	ffs_dev = ffs_acquire_dev(dev_name); +	if (IS_ERR(ffs_dev)) { +		ffs_data_put(ffs); +		return ERR_CAST(ffs_dev); +	} +	ffs->private_data = ffs_dev; +	data.ffs_data = ffs; +	rv = mount_nodev(t, flags, &data, ffs_sb_fill); +	if (IS_ERR(rv) && data.ffs_data) { +		ffs_release_dev(data.ffs_data); +		ffs_data_put(data.ffs_data); +	}  	return rv;  } @@ -1222,7 +1307,7 @@ ffs_fs_kill_sb(struct super_block *sb)  	kill_litter_super(sb);  	if (sb->s_fs_info) { -		functionfs_release_dev_callback(sb->s_fs_info); +		ffs_release_dev(sb->s_fs_info);  		ffs_data_put(sb->s_fs_info);  	}  } @@ -1312,7 +1397,7 @@ static struct ffs_data *ffs_data_new(void)  {  	struct ffs_data *ffs = kzalloc(sizeof *ffs, GFP_KERNEL);  	if (unlikely(!ffs)) -		return 0; +		return NULL;  	ENTER(); @@ -1335,14 +1420,14 @@ static void ffs_data_clear(struct ffs_data *ffs)  	ENTER();  	if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags)) -		functionfs_closed_callback(ffs); +		ffs_closed(ffs);  	BUG_ON(ffs->gadget);  	if (ffs->epfiles)  		ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count); -	kfree(ffs->raw_descs); +	kfree(ffs->raw_descs_data);  	kfree(ffs->raw_strings);  	kfree(ffs->stringtabs);  } @@ -1354,14 +1439,15 @@ static void ffs_data_reset(struct ffs_data *ffs)  	ffs_data_clear(ffs);  	ffs->epfiles = NULL; +	ffs->raw_descs_data = NULL;  	ffs->raw_descs = NULL;  	ffs->raw_strings = NULL;  	ffs->stringtabs = NULL;  	ffs->raw_descs_length = 0; -	ffs->raw_fs_descs_length = 0;  	ffs->fs_descs_count = 0;  	ffs->hs_descs_count = 0; +	ffs->ss_descs_count = 0;  	ffs->strings_count = 0;  	ffs->interfaces_count = 0; @@ -1397,11 +1483,13 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)  	ffs->ep0req->context = ffs;  	lang = ffs->stringtabs; -	for (lang = ffs->stringtabs; *lang; ++lang) { -		struct usb_string *str = (*lang)->strings; -		int id = first_id; -		for (; str->s; ++id, ++str) -			str->id = id; +	if (lang) { +		for (; *lang; ++lang) { +			struct usb_string *str = (*lang)->strings; +			int id = first_id; +			for (; str->s; ++id, ++str) +				str->id = id; +		}  	}  	ffs->gadget = cdev->gadget; @@ -1471,71 +1559,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)  	kfree(epfiles);  } -static int functionfs_bind_config(struct usb_composite_dev *cdev, -				  struct usb_configuration *c, -				  struct ffs_data *ffs) -{ -	struct ffs_function *func; -	int ret; - -	ENTER(); - -	func = kzalloc(sizeof *func, GFP_KERNEL); -	if (unlikely(!func)) -		return -ENOMEM; - -	func->function.name    = "Function FS Gadget"; -	func->function.strings = ffs->stringtabs; - -	func->function.bind    = ffs_func_bind; -	func->function.unbind  = ffs_func_unbind; -	func->function.set_alt = ffs_func_set_alt; -	func->function.disable = ffs_func_disable; -	func->function.setup   = ffs_func_setup; -	func->function.suspend = ffs_func_suspend; -	func->function.resume  = ffs_func_resume; - -	func->conf   = c; -	func->gadget = cdev->gadget; -	func->ffs = ffs; -	ffs_data_get(ffs); - -	ret = usb_add_function(c, &func->function); -	if (unlikely(ret)) -		ffs_func_free(func); - -	return ret; -} - -static void ffs_func_free(struct ffs_function *func) -{ -	struct ffs_ep *ep         = func->eps; -	unsigned count            = func->ffs->eps_count; -	unsigned long flags; - -	ENTER(); - -	/* cleanup after autoconfig */ -	spin_lock_irqsave(&func->ffs->eps_lock, flags); -	do { -		if (ep->ep && ep->req) -			usb_ep_free_request(ep->ep, ep->req); -		ep->req = NULL; -		++ep; -	} while (--count); -	spin_unlock_irqrestore(&func->ffs->eps_lock, flags); - -	ffs_data_put(func->ffs); - -	kfree(func->eps); -	/* -	 * eps and interfaces_nums are allocated in the same chunk so -	 * only one free is required.  Descriptors are also allocated -	 * in the same chunk. -	 */ - -	kfree(func); -}  static void ffs_func_eps_disable(struct ffs_function *func)  { @@ -1569,7 +1592,24 @@ static int ffs_func_eps_enable(struct ffs_function *func)  	spin_lock_irqsave(&func->ffs->eps_lock, flags);  	do {  		struct usb_endpoint_descriptor *ds; -		ds = ep->descs[ep->descs[1] ? 1 : 0]; +		int desc_idx; + +		if (ffs->gadget->speed == USB_SPEED_SUPER) +			desc_idx = 2; +		else if (ffs->gadget->speed == USB_SPEED_HIGH) +			desc_idx = 1; +		else +			desc_idx = 0; + +		/* fall-back to lower speed if desc missing for current speed */ +		do { +			ds = ep->descs[desc_idx]; +		} while (!ds && --desc_idx >= 0); + +		if (!ds) { +			ret = -EINVAL; +			break; +		}  		ep->ep->driver_data = ep;  		ep->ep->desc = ds; @@ -1704,6 +1744,12 @@ static int __must_check ffs_do_desc(char *data, unsigned len,  	}  		break; +	case USB_DT_SS_ENDPOINT_COMP: +		pr_vdebug("EP SS companion descriptor\n"); +		if (length != sizeof(struct usb_ss_ep_comp_descriptor)) +			goto inv_length; +		break; +  	case USB_DT_OTHER_SPEED_CONFIG:  	case USB_DT_INTERFACE_POWER:  	case USB_DT_DEBUG: @@ -1814,60 +1860,76 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,  static int __ffs_data_got_descs(struct ffs_data *ffs,  				char *const _data, size_t len)  { -	unsigned fs_count, hs_count; -	int fs_len, ret = -EINVAL; -	char *data = _data; +	char *data = _data, *raw_descs; +	unsigned counts[3], flags; +	int ret = -EINVAL, i;  	ENTER(); -	if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_DESCRIPTORS_MAGIC || -		     get_unaligned_le32(data + 4) != len)) +	if (get_unaligned_le32(data + 4) != len)  		goto error; -	fs_count = get_unaligned_le32(data +  8); -	hs_count = get_unaligned_le32(data + 12); - -	if (!fs_count && !hs_count) -		goto einval; -	data += 16; -	len  -= 16; - -	if (likely(fs_count)) { -		fs_len = ffs_do_descs(fs_count, data, len, -				      __ffs_data_do_entity, ffs); -		if (unlikely(fs_len < 0)) { -			ret = fs_len; +	switch (get_unaligned_le32(data)) { +	case FUNCTIONFS_DESCRIPTORS_MAGIC: +		flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC; +		data += 8; +		len  -= 8; +		break; +	case FUNCTIONFS_DESCRIPTORS_MAGIC_V2: +		flags = get_unaligned_le32(data + 8); +		if (flags & ~(FUNCTIONFS_HAS_FS_DESC | +			      FUNCTIONFS_HAS_HS_DESC | +			      FUNCTIONFS_HAS_SS_DESC)) { +			ret = -ENOSYS;  			goto error;  		} +		data += 12; +		len  -= 12; +		break; +	default: +		goto error; +	} -		data += fs_len; -		len  -= fs_len; -	} else { -		fs_len = 0; +	/* Read fs_count, hs_count and ss_count (if present) */ +	for (i = 0; i < 3; ++i) { +		if (!(flags & (1 << i))) { +			counts[i] = 0; +		} else if (len < 4) { +			goto error; +		} else { +			counts[i] = get_unaligned_le32(data); +			data += 4; +			len  -= 4; +		}  	} -	if (likely(hs_count)) { -		ret = ffs_do_descs(hs_count, data, len, +	/* Read descriptors */ +	raw_descs = data; +	for (i = 0; i < 3; ++i) { +		if (!counts[i]) +			continue; +		ret = ffs_do_descs(counts[i], data, len,  				   __ffs_data_do_entity, ffs); -		if (unlikely(ret < 0)) +		if (ret < 0)  			goto error; -	} else { -		ret = 0; +		data += ret; +		len  -= ret;  	} -	if (unlikely(len != ret)) -		goto einval; +	if (raw_descs == data || len) { +		ret = -EINVAL; +		goto error; +	} -	ffs->raw_fs_descs_length = fs_len; -	ffs->raw_descs_length    = fs_len + ret; -	ffs->raw_descs           = _data; -	ffs->fs_descs_count      = fs_count; -	ffs->hs_descs_count      = hs_count; +	ffs->raw_descs_data	= _data; +	ffs->raw_descs		= raw_descs; +	ffs->raw_descs_length	= data - raw_descs; +	ffs->fs_descs_count	= counts[0]; +	ffs->hs_descs_count	= counts[1]; +	ffs->ss_descs_count	= counts[2];  	return 0; -einval: -	ret = -EINVAL;  error:  	kfree(_data);  	return ret; @@ -1909,30 +1971,34 @@ static int __ffs_data_got_strings(struct ffs_data *ffs,  	/* Allocate everything in one chunk so there's less maintenance. */  	{ -		struct { -			struct usb_gadget_strings *stringtabs[lang_count + 1]; -			struct usb_gadget_strings stringtab[lang_count]; -			struct usb_string strings[lang_count*(needed_count+1)]; -		} *d;  		unsigned i = 0; +		vla_group(d); +		vla_item(d, struct usb_gadget_strings *, stringtabs, +			lang_count + 1); +		vla_item(d, struct usb_gadget_strings, stringtab, lang_count); +		vla_item(d, struct usb_string, strings, +			lang_count*(needed_count+1)); + +		char *vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL); -		d = kmalloc(sizeof *d, GFP_KERNEL); -		if (unlikely(!d)) { +		if (unlikely(!vlabuf)) {  			kfree(_data);  			return -ENOMEM;  		} -		stringtabs = d->stringtabs; -		t = d->stringtab; +		/* Initialize the VLA pointers */ +		stringtabs = vla_ptr(vlabuf, d, stringtabs); +		t = vla_ptr(vlabuf, d, stringtab);  		i = lang_count;  		do {  			*stringtabs++ = t++;  		} while (--i);  		*stringtabs = NULL; -		stringtabs = d->stringtabs; -		t = d->stringtab; -		s = d->strings; +		/* stringtabs = vlabuf = d_stringtabs for later kfree */ +		stringtabs = vla_ptr(vlabuf, d, stringtabs); +		t = vla_ptr(vlabuf, d, stringtab); +		s = vla_ptr(vlabuf, d, strings);  		strings = s;  	} @@ -2020,7 +2086,7 @@ static void __ffs_event_add(struct ffs_data *ffs,  	 * the source does nothing.  	 */  	if (ffs->setup_state == FFS_SETUP_PENDING) -		ffs->setup_state = FFS_SETUP_CANCELED; +		ffs->setup_state = FFS_SETUP_CANCELLED;  	switch (type) {  	case FUNCTIONFS_RESUME: @@ -2081,21 +2147,28 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,  	struct usb_endpoint_descriptor *ds = (void *)desc;  	struct ffs_function *func = priv;  	struct ffs_ep *ffs_ep; - -	/* -	 * If hs_descriptors is not NULL then we are reading hs -	 * descriptors now -	 */ -	const int isHS = func->function.hs_descriptors != NULL; -	unsigned idx; +	unsigned ep_desc_id, idx; +	static const char *speed_names[] = { "full", "high", "super" };  	if (type != FFS_DESCRIPTOR)  		return 0; -	if (isHS) +	/* +	 * If ss_descriptors is not NULL, we are reading super speed +	 * descriptors; if hs_descriptors is not NULL, we are reading high +	 * speed descriptors; otherwise, we are reading full speed +	 * descriptors. +	 */ +	if (func->function.ss_descriptors) { +		ep_desc_id = 2; +		func->function.ss_descriptors[(long)valuep] = desc; +	} else if (func->function.hs_descriptors) { +		ep_desc_id = 1;  		func->function.hs_descriptors[(long)valuep] = desc; -	else +	} else { +		ep_desc_id = 0;  		func->function.fs_descriptors[(long)valuep]    = desc; +	}  	if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)  		return 0; @@ -2103,13 +2176,13 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,  	idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;  	ffs_ep = func->eps + idx; -	if (unlikely(ffs_ep->descs[isHS])) { -		pr_vdebug("two %sspeed descriptors for EP %d\n", -			  isHS ? "high" : "full", +	if (unlikely(ffs_ep->descs[ep_desc_id])) { +		pr_err("two %sspeed descriptors for EP %d\n", +			  speed_names[ep_desc_id],  			  ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);  		return -EINVAL;  	} -	ffs_ep->descs[isHS] = ds; +	ffs_ep->descs[ep_desc_id] = ds;  	ffs_dump_mem(": Original  ep desc", ds, ds->bLength);  	if (ffs_ep->ep) { @@ -2195,8 +2268,57 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep,  	return 0;  } -static int ffs_func_bind(struct usb_configuration *c, -			 struct usb_function *f) +static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, +						struct usb_configuration *c) +{ +	struct ffs_function *func = ffs_func_from_usb(f); +	struct f_fs_opts *ffs_opts = +		container_of(f->fi, struct f_fs_opts, func_inst); +	int ret; + +	ENTER(); + +	/* +	 * Legacy gadget triggers binding in functionfs_ready_callback, +	 * which already uses locking; taking the same lock here would +	 * cause a deadlock. +	 * +	 * Configfs-enabled gadgets however do need ffs_dev_lock. +	 */ +	if (!ffs_opts->no_configfs) +		ffs_dev_lock(); +	ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV; +	func->ffs = ffs_opts->dev->ffs_data; +	if (!ffs_opts->no_configfs) +		ffs_dev_unlock(); +	if (ret) +		return ERR_PTR(ret); + +	func->conf = c; +	func->gadget = c->cdev->gadget; + +	ffs_data_get(func->ffs); + +	/* +	 * in drivers/usb/gadget/configfs.c:configfs_composite_bind() +	 * configurations are bound in sequence with list_for_each_entry, +	 * in each configuration its functions are bound in sequence +	 * with list_for_each_entry, so we assume no race condition +	 * with regard to ffs_opts->bound access +	 */ +	if (!ffs_opts->refcnt) { +		ret = functionfs_bind(func->ffs, c->cdev); +		if (ret) +			return ERR_PTR(ret); +	} +	ffs_opts->refcnt++; +	func->function.strings = func->ffs->stringtabs; + +	return ffs_opts; +} + +static int _ffs_func_bind(struct usb_configuration *c, +			  struct usb_function *f)  {  	struct ffs_function *func = ffs_func_from_usb(f);  	struct ffs_data *ffs = func->ffs; @@ -2204,42 +2326,54 @@ static int ffs_func_bind(struct usb_configuration *c,  	const int full = !!func->ffs->fs_descs_count;  	const int high = gadget_is_dualspeed(func->gadget) &&  		func->ffs->hs_descs_count; +	const int super = gadget_is_superspeed(func->gadget) && +		func->ffs->ss_descs_count; -	int ret; +	int fs_len, hs_len, ret;  	/* Make it a single chunk, less management later on */ -	struct { -		struct ffs_ep eps[ffs->eps_count]; -		struct usb_descriptor_header -			*fs_descs[full ? ffs->fs_descs_count + 1 : 0]; -		struct usb_descriptor_header -			*hs_descs[high ? ffs->hs_descs_count + 1 : 0]; -		short inums[ffs->interfaces_count]; -		char raw_descs[high ? ffs->raw_descs_length -				    : ffs->raw_fs_descs_length]; -	} *data; +	vla_group(d); +	vla_item_with_sz(d, struct ffs_ep, eps, ffs->eps_count); +	vla_item_with_sz(d, struct usb_descriptor_header *, fs_descs, +		full ? ffs->fs_descs_count + 1 : 0); +	vla_item_with_sz(d, struct usb_descriptor_header *, hs_descs, +		high ? ffs->hs_descs_count + 1 : 0); +	vla_item_with_sz(d, struct usb_descriptor_header *, ss_descs, +		super ? ffs->ss_descs_count + 1 : 0); +	vla_item_with_sz(d, short, inums, ffs->interfaces_count); +	vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length); +	char *vlabuf;  	ENTER(); -	/* Only high speed but not supported by gadget? */ -	if (unlikely(!(full | high))) +	/* Has descriptors only for speeds gadget does not support */ +	if (unlikely(!(full | high | super)))  		return -ENOTSUPP; -	/* Allocate */ -	data = kmalloc(sizeof *data, GFP_KERNEL); -	if (unlikely(!data)) +	/* Allocate a single chunk, less management later on */ +	vlabuf = kmalloc(vla_group_size(d), GFP_KERNEL); +	if (unlikely(!vlabuf))  		return -ENOMEM;  	/* Zero */ -	memset(data->eps, 0, sizeof data->eps); -	memcpy(data->raw_descs, ffs->raw_descs + 16, sizeof data->raw_descs); -	memset(data->inums, 0xff, sizeof data->inums); -	for (ret = ffs->eps_count; ret; --ret) -		data->eps[ret].num = -1; +	memset(vla_ptr(vlabuf, d, eps), 0, d_eps__sz); +	/* Copy descriptors  */ +	memcpy(vla_ptr(vlabuf, d, raw_descs), ffs->raw_descs, +	       ffs->raw_descs_length); -	/* Save pointers */ -	func->eps             = data->eps; -	func->interfaces_nums = data->inums; +	memset(vla_ptr(vlabuf, d, inums), 0xff, d_inums__sz); +	for (ret = ffs->eps_count; ret; --ret) { +		struct ffs_ep *ptr; + +		ptr = vla_ptr(vlabuf, d, eps); +		ptr[ret].num = -1; +	} + +	/* Save pointers +	 * d_eps == vlabuf, func->eps used to kfree vlabuf later +	*/ +	func->eps             = vla_ptr(vlabuf, d, eps); +	func->interfaces_nums = vla_ptr(vlabuf, d, inums);  	/*  	 * Go through all the endpoint descriptors and allocate @@ -2247,23 +2381,41 @@ static int ffs_func_bind(struct usb_configuration *c,  	 * numbers without worrying that it may be described later on.  	 */  	if (likely(full)) { -		func->function.fs_descriptors = data->fs_descs; -		ret = ffs_do_descs(ffs->fs_descs_count, -				   data->raw_descs, -				   sizeof data->raw_descs, -				   __ffs_func_bind_do_descs, func); -		if (unlikely(ret < 0)) +		func->function.fs_descriptors = vla_ptr(vlabuf, d, fs_descs); +		fs_len = ffs_do_descs(ffs->fs_descs_count, +				      vla_ptr(vlabuf, d, raw_descs), +				      d_raw_descs__sz, +				      __ffs_func_bind_do_descs, func); +		if (unlikely(fs_len < 0)) { +			ret = fs_len;  			goto error; +		}  	} else { -		ret = 0; +		fs_len = 0;  	}  	if (likely(high)) { -		func->function.hs_descriptors = data->hs_descs; -		ret = ffs_do_descs(ffs->hs_descs_count, -				   data->raw_descs + ret, -				   (sizeof data->raw_descs) - ret, -				   __ffs_func_bind_do_descs, func); +		func->function.hs_descriptors = vla_ptr(vlabuf, d, hs_descs); +		hs_len = ffs_do_descs(ffs->hs_descs_count, +				      vla_ptr(vlabuf, d, raw_descs) + fs_len, +				      d_raw_descs__sz - fs_len, +				      __ffs_func_bind_do_descs, func); +		if (unlikely(hs_len < 0)) { +			ret = hs_len; +			goto error; +		} +	} else { +		hs_len = 0; +	} + +	if (likely(super)) { +		func->function.ss_descriptors = vla_ptr(vlabuf, d, ss_descs); +		ret = ffs_do_descs(ffs->ss_descs_count, +				vla_ptr(vlabuf, d, raw_descs) + fs_len + hs_len, +				d_raw_descs__sz - fs_len - hs_len, +				__ffs_func_bind_do_descs, func); +		if (unlikely(ret < 0)) +			goto error;  	}  	/* @@ -2272,8 +2424,9 @@ static int ffs_func_bind(struct usb_configuration *c,  	 * now.  	 */  	ret = ffs_do_descs(ffs->fs_descs_count + -			   (high ? ffs->hs_descs_count : 0), -			   data->raw_descs, sizeof data->raw_descs, +			   (high ? ffs->hs_descs_count : 0) + +			   (super ? ffs->ss_descs_count : 0), +			   vla_ptr(vlabuf, d, raw_descs), d_raw_descs__sz,  			   __ffs_func_bind_do_nums, func);  	if (unlikely(ret < 0))  		goto error; @@ -2287,26 +2440,19 @@ error:  	return ret;  } - -/* Other USB function hooks *************************************************/ - -static void ffs_func_unbind(struct usb_configuration *c, -			    struct usb_function *f) +static int ffs_func_bind(struct usb_configuration *c, +			 struct usb_function *f)  { -	struct ffs_function *func = ffs_func_from_usb(f); -	struct ffs_data *ffs = func->ffs; +	struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c); -	ENTER(); +	if (IS_ERR(ffs_opts)) +		return PTR_ERR(ffs_opts); -	if (ffs->func == func) { -		ffs_func_eps_disable(func); -		ffs->func = NULL; -	} +	return _ffs_func_bind(c, f); +} -	ffs_event_add(ffs, FUNCTIONFS_UNBIND); -	ffs_func_free(func); -} +/* Other USB function hooks *************************************************/  static int ffs_func_set_alt(struct usb_function *f,  			    unsigned interface, unsigned alt) @@ -2434,6 +2580,413 @@ static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf)  } +/* Devices management *******************************************************/ + +static LIST_HEAD(ffs_devices); + +static struct ffs_dev *_ffs_do_find_dev(const char *name) +{ +	struct ffs_dev *dev; + +	list_for_each_entry(dev, &ffs_devices, entry) { +		if (!dev->name || !name) +			continue; +		if (strcmp(dev->name, name) == 0) +			return dev; +	} + +	return NULL; +} + +/* + * ffs_lock must be taken by the caller of this function + */ +static struct ffs_dev *_ffs_get_single_dev(void) +{ +	struct ffs_dev *dev; + +	if (list_is_singular(&ffs_devices)) { +		dev = list_first_entry(&ffs_devices, struct ffs_dev, entry); +		if (dev->single) +			return dev; +	} + +	return NULL; +} + +/* + * ffs_lock must be taken by the caller of this function + */ +static struct ffs_dev *_ffs_find_dev(const char *name) +{ +	struct ffs_dev *dev; + +	dev = _ffs_get_single_dev(); +	if (dev) +		return dev; + +	return _ffs_do_find_dev(name); +} + +/* Configfs support *********************************************************/ + +static inline struct f_fs_opts *to_ffs_opts(struct config_item *item) +{ +	return container_of(to_config_group(item), struct f_fs_opts, +			    func_inst.group); +} + +static void ffs_attr_release(struct config_item *item) +{ +	struct f_fs_opts *opts = to_ffs_opts(item); + +	usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations ffs_item_ops = { +	.release	= ffs_attr_release, +}; + +static struct config_item_type ffs_func_type = { +	.ct_item_ops	= &ffs_item_ops, +	.ct_owner	= THIS_MODULE, +}; + + +/* Function registration interface ******************************************/ + +static void ffs_free_inst(struct usb_function_instance *f) +{ +	struct f_fs_opts *opts; + +	opts = to_f_fs_opts(f); +	ffs_dev_lock(); +	_ffs_free_dev(opts->dev); +	ffs_dev_unlock(); +	kfree(opts); +} + +#define MAX_INST_NAME_LEN	40 + +static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name) +{ +	struct f_fs_opts *opts; +	char *ptr; +	const char *tmp; +	int name_len, ret; + +	name_len = strlen(name) + 1; +	if (name_len > MAX_INST_NAME_LEN) +		return -ENAMETOOLONG; + +	ptr = kstrndup(name, name_len, GFP_KERNEL); +	if (!ptr) +		return -ENOMEM; + +	opts = to_f_fs_opts(fi); +	tmp = NULL; + +	ffs_dev_lock(); + +	tmp = opts->dev->name_allocated ? opts->dev->name : NULL; +	ret = _ffs_name_dev(opts->dev, ptr); +	if (ret) { +		kfree(ptr); +		ffs_dev_unlock(); +		return ret; +	} +	opts->dev->name_allocated = true; + +	ffs_dev_unlock(); + +	kfree(tmp); + +	return 0; +} + +static struct usb_function_instance *ffs_alloc_inst(void) +{ +	struct f_fs_opts *opts; +	struct ffs_dev *dev; + +	opts = kzalloc(sizeof(*opts), GFP_KERNEL); +	if (!opts) +		return ERR_PTR(-ENOMEM); + +	opts->func_inst.set_inst_name = ffs_set_inst_name; +	opts->func_inst.free_func_inst = ffs_free_inst; +	ffs_dev_lock(); +	dev = _ffs_alloc_dev(); +	ffs_dev_unlock(); +	if (IS_ERR(dev)) { +		kfree(opts); +		return ERR_CAST(dev); +	} +	opts->dev = dev; +	dev->opts = opts; + +	config_group_init_type_name(&opts->func_inst.group, "", +				    &ffs_func_type); +	return &opts->func_inst; +} + +static void ffs_free(struct usb_function *f) +{ +	kfree(ffs_func_from_usb(f)); +} + +static void ffs_func_unbind(struct usb_configuration *c, +			    struct usb_function *f) +{ +	struct ffs_function *func = ffs_func_from_usb(f); +	struct ffs_data *ffs = func->ffs; +	struct f_fs_opts *opts = +		container_of(f->fi, struct f_fs_opts, func_inst); +	struct ffs_ep *ep = func->eps; +	unsigned count = ffs->eps_count; +	unsigned long flags; + +	ENTER(); +	if (ffs->func == func) { +		ffs_func_eps_disable(func); +		ffs->func = NULL; +	} + +	if (!--opts->refcnt) +		functionfs_unbind(ffs); + +	/* cleanup after autoconfig */ +	spin_lock_irqsave(&func->ffs->eps_lock, flags); +	do { +		if (ep->ep && ep->req) +			usb_ep_free_request(ep->ep, ep->req); +		ep->req = NULL; +		++ep; +	} while (--count); +	spin_unlock_irqrestore(&func->ffs->eps_lock, flags); +	kfree(func->eps); +	func->eps = NULL; +	/* +	 * eps, descriptors and interfaces_nums are allocated in the +	 * same chunk so only one free is required. +	 */ +	func->function.fs_descriptors = NULL; +	func->function.hs_descriptors = NULL; +	func->function.ss_descriptors = NULL; +	func->interfaces_nums = NULL; + +	ffs_event_add(ffs, FUNCTIONFS_UNBIND); +} + +static struct usb_function *ffs_alloc(struct usb_function_instance *fi) +{ +	struct ffs_function *func; + +	ENTER(); + +	func = kzalloc(sizeof(*func), GFP_KERNEL); +	if (unlikely(!func)) +		return ERR_PTR(-ENOMEM); + +	func->function.name    = "Function FS Gadget"; + +	func->function.bind    = ffs_func_bind; +	func->function.unbind  = ffs_func_unbind; +	func->function.set_alt = ffs_func_set_alt; +	func->function.disable = ffs_func_disable; +	func->function.setup   = ffs_func_setup; +	func->function.suspend = ffs_func_suspend; +	func->function.resume  = ffs_func_resume; +	func->function.free_func = ffs_free; + +	return &func->function; +} + +/* + * ffs_lock must be taken by the caller of this function + */ +static struct ffs_dev *_ffs_alloc_dev(void) +{ +	struct ffs_dev *dev; +	int ret; + +	if (_ffs_get_single_dev()) +			return ERR_PTR(-EBUSY); + +	dev = kzalloc(sizeof(*dev), GFP_KERNEL); +	if (!dev) +		return ERR_PTR(-ENOMEM); + +	if (list_empty(&ffs_devices)) { +		ret = functionfs_init(); +		if (ret) { +			kfree(dev); +			return ERR_PTR(ret); +		} +	} + +	list_add(&dev->entry, &ffs_devices); + +	return dev; +} + +/* + * ffs_lock must be taken by the caller of this function + * The caller is responsible for "name" being available whenever f_fs needs it + */ +static int _ffs_name_dev(struct ffs_dev *dev, const char *name) +{ +	struct ffs_dev *existing; + +	existing = _ffs_do_find_dev(name); +	if (existing) +		return -EBUSY; + +	dev->name = name; + +	return 0; +} + +/* + * The caller is responsible for "name" being available whenever f_fs needs it + */ +int ffs_name_dev(struct ffs_dev *dev, const char *name) +{ +	int ret; + +	ffs_dev_lock(); +	ret = _ffs_name_dev(dev, name); +	ffs_dev_unlock(); + +	return ret; +} +EXPORT_SYMBOL_GPL(ffs_name_dev); + +int ffs_single_dev(struct ffs_dev *dev) +{ +	int ret; + +	ret = 0; +	ffs_dev_lock(); + +	if (!list_is_singular(&ffs_devices)) +		ret = -EBUSY; +	else +		dev->single = true; + +	ffs_dev_unlock(); +	return ret; +} +EXPORT_SYMBOL_GPL(ffs_single_dev); + +/* + * ffs_lock must be taken by the caller of this function + */ +static void _ffs_free_dev(struct ffs_dev *dev) +{ +	list_del(&dev->entry); +	if (dev->name_allocated) +		kfree(dev->name); +	kfree(dev); +	if (list_empty(&ffs_devices)) +		functionfs_cleanup(); +} + +static void *ffs_acquire_dev(const char *dev_name) +{ +	struct ffs_dev *ffs_dev; + +	ENTER(); +	ffs_dev_lock(); + +	ffs_dev = _ffs_find_dev(dev_name); +	if (!ffs_dev) +		ffs_dev = ERR_PTR(-ENODEV); +	else if (ffs_dev->mounted) +		ffs_dev = ERR_PTR(-EBUSY); +	else if (ffs_dev->ffs_acquire_dev_callback && +	    ffs_dev->ffs_acquire_dev_callback(ffs_dev)) +		ffs_dev = ERR_PTR(-ENODEV); +	else +		ffs_dev->mounted = true; + +	ffs_dev_unlock(); +	return ffs_dev; +} + +static void ffs_release_dev(struct ffs_data *ffs_data) +{ +	struct ffs_dev *ffs_dev; + +	ENTER(); +	ffs_dev_lock(); + +	ffs_dev = ffs_data->private_data; +	if (ffs_dev) { +		ffs_dev->mounted = false; + +		if (ffs_dev->ffs_release_dev_callback) +			ffs_dev->ffs_release_dev_callback(ffs_dev); +	} + +	ffs_dev_unlock(); +} + +static int ffs_ready(struct ffs_data *ffs) +{ +	struct ffs_dev *ffs_obj; +	int ret = 0; + +	ENTER(); +	ffs_dev_lock(); + +	ffs_obj = ffs->private_data; +	if (!ffs_obj) { +		ret = -EINVAL; +		goto done; +	} +	if (WARN_ON(ffs_obj->desc_ready)) { +		ret = -EBUSY; +		goto done; +	} + +	ffs_obj->desc_ready = true; +	ffs_obj->ffs_data = ffs; + +	if (ffs_obj->ffs_ready_callback) +		ret = ffs_obj->ffs_ready_callback(ffs); + +done: +	ffs_dev_unlock(); +	return ret; +} + +static void ffs_closed(struct ffs_data *ffs) +{ +	struct ffs_dev *ffs_obj; + +	ENTER(); +	ffs_dev_lock(); + +	ffs_obj = ffs->private_data; +	if (!ffs_obj) +		goto done; + +	ffs_obj->desc_ready = false; + +	if (ffs_obj->ffs_closed_callback) +		ffs_obj->ffs_closed_callback(ffs); + +	if (!ffs_obj->opts || ffs_obj->opts->no_configfs +	    || !ffs_obj->opts->func_inst.group.cg_item.ci_parent) +		goto done; + +	unregister_gadget_item(ffs_obj->opts-> +			       func_inst.group.cg_item.ci_parent->ci_parent); +done: +	ffs_dev_unlock(); +} +  /* Misc helper functions ****************************************************/  static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) @@ -2464,3 +3017,7 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len)  	return data;  } + +DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michal Nazarewicz"); diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c index 6e69a8e8d22..a95290a1289 100644 --- a/drivers/usb/gadget/f_hid.c +++ b/drivers/usb/gadget/f_hid.c @@ -20,6 +20,8 @@  #include <linux/sched.h>  #include <linux/usb/g_hid.h> +#include "u_f.h" +  static int major, minors;  static struct class *hidg_class; @@ -334,20 +336,10 @@ static int f_hidg_open(struct inode *inode, struct file *fd)  /*-------------------------------------------------------------------------*/  /*                                usb_function                             */ -static struct usb_request *hidg_alloc_ep_req(struct usb_ep *ep, unsigned length) +static inline struct usb_request *hidg_alloc_ep_req(struct usb_ep *ep, +						    unsigned length)  { -	struct usb_request *req; - -	req = usb_ep_alloc_request(ep, GFP_ATOMIC); -	if (req) { -		req->length = length; -		req->buf = kmalloc(length, GFP_ATOMIC); -		if (!req->buf) { -			usb_ep_free_request(ep, req); -			req = NULL; -		} -	} -	return req; +	return alloc_ep_req(ep, length, length);  }  static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req) diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index 4a3873a0f2d..4557cd03f0b 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -20,6 +20,7 @@  #include <linux/usb/composite.h>  #include "g_zero.h" +#include "u_f.h"  /*   * LOOPBACK FUNCTION ... a testing vehicle for USB peripherals, @@ -119,7 +120,7 @@ static struct usb_endpoint_descriptor ss_loop_source_desc = {  	.wMaxPacketSize =	cpu_to_le16(1024),  }; -struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = {  	.bLength =		USB_DT_SS_EP_COMP_SIZE,  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,  	.bMaxBurst =		0, @@ -135,7 +136,7 @@ static struct usb_endpoint_descriptor ss_loop_sink_desc = {  	.wMaxPacketSize =	cpu_to_le16(1024),  }; -struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = {  	.bLength =		USB_DT_SS_EP_COMP_SIZE,  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,  	.bMaxBurst =		0, @@ -230,6 +231,14 @@ autoconf_fail:  static void lb_free_func(struct usb_function *f)  { +	struct f_lb_opts *opts; + +	opts = container_of(f->fi, struct f_lb_opts, func_inst); + +	mutex_lock(&opts->lock); +	opts->refcnt--; +	mutex_unlock(&opts->lock); +  	usb_free_all_descriptors(f);  	kfree(func_to_loop(f));  } @@ -293,6 +302,11 @@ static void disable_loopback(struct f_loopback *loop)  	VDBG(cdev, "%s disabled\n", loop->function.name);  } +static inline struct usb_request *lb_alloc_ep_req(struct usb_ep *ep, int len) +{ +	return alloc_ep_req(ep, len, buflen); +} +  static int  enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)  { @@ -332,7 +346,7 @@ fail0:  	 * than 'buflen' bytes each.  	 */  	for (i = 0; i < qlen && result == 0; i++) { -		req = alloc_ep_req(ep, 0); +		req = lb_alloc_ep_req(ep, 0);  		if (req) {  			req->complete = loopback_complete;  			result = usb_ep_queue(ep, req, GFP_ATOMIC); @@ -380,6 +394,11 @@ static struct usb_function *loopback_alloc(struct usb_function_instance *fi)  		return ERR_PTR(-ENOMEM);  	lb_opts = container_of(fi, struct f_lb_opts, func_inst); + +	mutex_lock(&lb_opts->lock); +	lb_opts->refcnt++; +	mutex_unlock(&lb_opts->lock); +  	buflen = lb_opts->bulk_buflen;  	qlen = lb_opts->qlen;  	if (!qlen) @@ -396,6 +415,118 @@ static struct usb_function *loopback_alloc(struct usb_function_instance *fi)  	return &loop->function;  } +static inline struct f_lb_opts *to_f_lb_opts(struct config_item *item) +{ +	return container_of(to_config_group(item), struct f_lb_opts, +			    func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_lb_opts); +CONFIGFS_ATTR_OPS(f_lb_opts); + +static void lb_attr_release(struct config_item *item) +{ +	struct f_lb_opts *lb_opts = to_f_lb_opts(item); + +	usb_put_function_instance(&lb_opts->func_inst); +} + +static struct configfs_item_operations lb_item_ops = { +	.release		= lb_attr_release, +	.show_attribute		= f_lb_opts_attr_show, +	.store_attribute	= f_lb_opts_attr_store, +}; + +static ssize_t f_lb_opts_qlen_show(struct f_lb_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->qlen); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_lb_opts_qlen_store(struct f_lb_opts *opts, +				    const char *page, size_t len) +{ +	int ret; +	u32 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou32(page, 0, &num); +	if (ret) +		goto end; + +	opts->qlen = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_lb_opts_attribute f_lb_opts_qlen = +	__CONFIGFS_ATTR(qlen, S_IRUGO | S_IWUSR, +			f_lb_opts_qlen_show, +			f_lb_opts_qlen_store); + +static ssize_t f_lb_opts_bulk_buflen_show(struct f_lb_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->bulk_buflen); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_lb_opts_bulk_buflen_store(struct f_lb_opts *opts, +				    const char *page, size_t len) +{ +	int ret; +	u32 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou32(page, 0, &num); +	if (ret) +		goto end; + +	opts->bulk_buflen = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_lb_opts_attribute f_lb_opts_bulk_buflen = +	__CONFIGFS_ATTR(buflen, S_IRUGO | S_IWUSR, +			f_lb_opts_bulk_buflen_show, +			f_lb_opts_bulk_buflen_store); + +static struct configfs_attribute *lb_attrs[] = { +	&f_lb_opts_qlen.attr, +	&f_lb_opts_bulk_buflen.attr, +	NULL, +}; + +static struct config_item_type lb_func_type = { +	.ct_item_ops    = &lb_item_ops, +	.ct_attrs	= lb_attrs, +	.ct_owner       = THIS_MODULE, +}; +  static void lb_free_instance(struct usb_function_instance *fi)  {  	struct f_lb_opts *lb_opts; @@ -411,7 +542,14 @@ static struct usb_function_instance *loopback_alloc_instance(void)  	lb_opts = kzalloc(sizeof(*lb_opts), GFP_KERNEL);  	if (!lb_opts)  		return ERR_PTR(-ENOMEM); +	mutex_init(&lb_opts->lock);  	lb_opts->func_inst.free_func_inst = lb_free_instance; +	lb_opts->bulk_buflen = GZERO_BULK_BUFLEN; +	lb_opts->qlen = GZERO_QLEN; + +	config_group_init_type_name(&lb_opts->func_inst.group, "", +				    &lb_func_type); +  	return  &lb_opts->func_inst;  }  DECLARE_USB_FUNCTION(Loopback, loopback_alloc_instance, loopback_alloc); diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 313b835eedf..b9639390886 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -213,12 +213,14 @@  #include <linux/spinlock.h>  #include <linux/string.h>  #include <linux/freezer.h> +#include <linux/module.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h>  #include <linux/usb/composite.h>  #include "gadget_chips.h" +#include "configfs.h"  /*------------------------------------------------------------------------*/ @@ -228,26 +230,30 @@  static const char fsg_string_interface[] = "Mass Storage"; -#include "storage_common.c" +#include "storage_common.h" +#include "f_mass_storage.h" +/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ +static struct usb_string		fsg_strings[] = { +	{FSG_STRING_INTERFACE,		fsg_string_interface}, +	{} +}; + +static struct usb_gadget_strings	fsg_stringtab = { +	.language	= 0x0409,		/* en-us */ +	.strings	= fsg_strings, +}; + +static struct usb_gadget_strings *fsg_strings_array[] = { +	&fsg_stringtab, +	NULL, +};  /*-------------------------------------------------------------------------*/  struct fsg_dev;  struct fsg_common; -/* FSF callback functions */ -struct fsg_operations { -	/* -	 * Callback function to call when thread exits.  If no -	 * callback is set or it returns value lower then zero MSF -	 * will force eject all LUNs it operates on (including those -	 * marked as non-removable or with prevent_medium_removal flag -	 * set). -	 */ -	int (*thread_exits)(struct fsg_common *common); -}; -  /* Data shared by all the FSG instances. */  struct fsg_common {  	struct usb_gadget	*gadget; @@ -268,13 +274,14 @@ struct fsg_common {  	struct fsg_buffhd	*next_buffhd_to_fill;  	struct fsg_buffhd	*next_buffhd_to_drain;  	struct fsg_buffhd	*buffhds; +	unsigned int		fsg_num_buffers;  	int			cmnd_size;  	u8			cmnd[MAX_COMMAND_SIZE];  	unsigned int		nluns;  	unsigned int		lun; -	struct fsg_lun		*luns; +	struct fsg_lun		**luns;  	struct fsg_lun		*curlun;  	unsigned int		bulk_out_maxpacket; @@ -294,6 +301,7 @@ struct fsg_common {  	unsigned int		short_packet_received:1;  	unsigned int		bad_lun_okay:1;  	unsigned int		running:1; +	unsigned int		sysfs:1;  	int			thread_wakeup_needed;  	struct completion	thread_notifier; @@ -313,27 +321,6 @@ struct fsg_common {  	struct kref		ref;  }; -struct fsg_config { -	unsigned nluns; -	struct fsg_lun_config { -		const char *filename; -		char ro; -		char removable; -		char cdrom; -		char nofua; -	} luns[FSG_MAX_LUNS]; - -	/* Callback functions. */ -	const struct fsg_operations	*ops; -	/* Gadget's private data. */ -	void			*private_data; - -	const char *vendor_name;		/*  8 characters or less */ -	const char *product_name;		/* 16 characters or less */ - -	char			can_stall; -}; -  struct fsg_dev {  	struct usb_function	function;  	struct usb_gadget	*gadget;	/* Copy of cdev->gadget */ @@ -536,7 +523,7 @@ static int fsg_setup(struct usb_function *f,  		 */  		DBG(fsg, "bulk reset request\n");  		raise_exception(fsg->common, FSG_STATE_RESET); -		return DELAYED_STATUS; +		return USB_GADGET_DELAYED_STATUS;  	case US_BULK_GET_MAX_LUN:  		if (ctrl->bRequestType != @@ -615,13 +602,14 @@ static bool start_out_transfer(struct fsg_common *common, struct fsg_buffhd *bh)  	return true;  } -static int sleep_thread(struct fsg_common *common) +static int sleep_thread(struct fsg_common *common, bool can_freeze)  {  	int	rc = 0;  	/* Wait until a signal arrives or we are woken up */  	for (;;) { -		try_to_freeze(); +		if (can_freeze) +			try_to_freeze();  		set_current_state(TASK_INTERRUPTIBLE);  		if (signal_pending(current)) {  			rc = -EINTR; @@ -695,7 +683,7 @@ static int do_read(struct fsg_common *common)  		/* Wait for the next buffer to become available */  		bh = common->next_buffhd_to_fill;  		while (bh->state != BUF_STATE_EMPTY) { -			rc = sleep_thread(common); +			rc = sleep_thread(common, false);  			if (rc)  				return rc;  		} @@ -950,7 +938,7 @@ static int do_write(struct fsg_common *common)  		}  		/* Wait for something to happen */ -		rc = sleep_thread(common); +		rc = sleep_thread(common, false);  		if (rc)  			return rc;  	} @@ -1517,7 +1505,7 @@ static int throw_away_data(struct fsg_common *common)  		}  		/* Otherwise wait for something to happen */ -		rc = sleep_thread(common); +		rc = sleep_thread(common, true);  		if (rc)  			return rc;  	} @@ -1638,7 +1626,7 @@ static int send_status(struct fsg_common *common)  	/* Wait for the next buffer to become available */  	bh = common->next_buffhd_to_fill;  	while (bh->state != BUF_STATE_EMPTY) { -		rc = sleep_thread(common); +		rc = sleep_thread(common, true);  		if (rc)  			return rc;  	} @@ -1841,7 +1829,7 @@ static int do_scsi_command(struct fsg_common *common)  	bh = common->next_buffhd_to_fill;  	common->next_buffhd_to_drain = bh;  	while (bh->state != BUF_STATE_EMPTY) { -		rc = sleep_thread(common); +		rc = sleep_thread(common, true);  		if (rc)  			return rc;  	} @@ -2172,7 +2160,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)  		common->data_dir = DATA_DIR_NONE;  	common->lun = cbw->Lun;  	if (common->lun < common->nluns) -		common->curlun = &common->luns[common->lun]; +		common->curlun = common->luns[common->lun];  	else  		common->curlun = NULL;  	common->tag = cbw->Tag; @@ -2187,7 +2175,7 @@ static int get_next_command(struct fsg_common *common)  	/* Wait for the next buffer to become available */  	bh = common->next_buffhd_to_fill;  	while (bh->state != BUF_STATE_EMPTY) { -		rc = sleep_thread(common); +		rc = sleep_thread(common, true);  		if (rc)  			return rc;  	} @@ -2206,7 +2194,7 @@ static int get_next_command(struct fsg_common *common)  	/* Wait for the CBW to arrive */  	while (bh->state != BUF_STATE_FULL) { -		rc = sleep_thread(common); +		rc = sleep_thread(common, true);  		if (rc)  			return rc;  	} @@ -2244,7 +2232,7 @@ reset:  	if (common->fsg) {  		fsg = common->fsg; -		for (i = 0; i < fsg_num_buffers; ++i) { +		for (i = 0; i < common->fsg_num_buffers; ++i) {  			struct fsg_buffhd *bh = &common->buffhds[i];  			if (bh->inreq) { @@ -2260,10 +2248,12 @@ reset:  		/* Disable the endpoints */  		if (fsg->bulk_in_enabled) {  			usb_ep_disable(fsg->bulk_in); +			fsg->bulk_in->driver_data = NULL;  			fsg->bulk_in_enabled = 0;  		}  		if (fsg->bulk_out_enabled) {  			usb_ep_disable(fsg->bulk_out); +			fsg->bulk_out->driver_data = NULL;  			fsg->bulk_out_enabled = 0;  		} @@ -2301,7 +2291,7 @@ reset:  	clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);  	/* Allocate the requests */ -	for (i = 0; i < fsg_num_buffers; ++i) { +	for (i = 0; i < common->fsg_num_buffers; ++i) {  		struct fsg_buffhd	*bh = &common->buffhds[i];  		rc = alloc_request(common, fsg->bulk_in, &bh->inreq); @@ -2318,7 +2308,9 @@ reset:  	common->running = 1;  	for (i = 0; i < common->nluns; ++i) -		common->luns[i].unit_attention_data = SS_RESET_OCCURRED; +		if (common->luns[i]) +			common->luns[i]->unit_attention_data = +				SS_RESET_OCCURRED;  	return rc;  } @@ -2370,7 +2362,7 @@ static void handle_exception(struct fsg_common *common)  	/* Cancel all the pending transfers */  	if (likely(common->fsg)) { -		for (i = 0; i < fsg_num_buffers; ++i) { +		for (i = 0; i < common->fsg_num_buffers; ++i) {  			bh = &common->buffhds[i];  			if (bh->inreq_busy)  				usb_ep_dequeue(common->fsg->bulk_in, bh->inreq); @@ -2382,13 +2374,13 @@ static void handle_exception(struct fsg_common *common)  		/* Wait until everything is idle */  		for (;;) {  			int num_active = 0; -			for (i = 0; i < fsg_num_buffers; ++i) { +			for (i = 0; i < common->fsg_num_buffers; ++i) {  				bh = &common->buffhds[i];  				num_active += bh->inreq_busy + bh->outreq_busy;  			}  			if (num_active == 0)  				break; -			if (sleep_thread(common)) +			if (sleep_thread(common, true))  				return;  		} @@ -2405,7 +2397,7 @@ static void handle_exception(struct fsg_common *common)  	 */  	spin_lock_irq(&common->lock); -	for (i = 0; i < fsg_num_buffers; ++i) { +	for (i = 0; i < common->fsg_num_buffers; ++i) {  		bh = &common->buffhds[i];  		bh->state = BUF_STATE_EMPTY;  	} @@ -2418,7 +2410,9 @@ static void handle_exception(struct fsg_common *common)  		common->state = FSG_STATE_STATUS_PHASE;  	else {  		for (i = 0; i < common->nluns; ++i) { -			curlun = &common->luns[i]; +			curlun = common->luns[i]; +			if (!curlun) +				continue;  			curlun->prevent_medium_removal = 0;  			curlun->sense_data = SS_NO_SENSE;  			curlun->unit_attention_data = SS_NO_SENSE; @@ -2460,8 +2454,9 @@ static void handle_exception(struct fsg_common *common)  		 * CONFIG_CHANGE cases.  		 */  		/* for (i = 0; i < common->nluns; ++i) */ -		/*	common->luns[i].unit_attention_data = */ -		/*		SS_RESET_OCCURRED;  */ +		/*	if (common->luns[i]) */ +		/*		common->luns[i]->unit_attention_data = */ +		/*			SS_RESET_OCCURRED;  */  		break;  	case FSG_STATE_CONFIG_CHANGE: @@ -2522,7 +2517,7 @@ static int fsg_main_thread(void *common_)  		}  		if (!common->running) { -			sleep_thread(common); +			sleep_thread(common, true);  			continue;  		} @@ -2557,12 +2552,13 @@ static int fsg_main_thread(void *common_)  	if (!common->ops || !common->ops->thread_exits  	 || common->ops->thread_exits(common) < 0) { -		struct fsg_lun *curlun = common->luns; +		struct fsg_lun **curlun_it = common->luns;  		unsigned i = common->nluns;  		down_write(&common->filesem); -		for (; i--; ++curlun) { -			if (!fsg_lun_is_open(curlun)) +		for (; i--; ++curlun_it) { +			struct fsg_lun *curlun = *curlun_it; +			if (!curlun || !fsg_lun_is_open(curlun))  				continue;  			fsg_lun_close(curlun); @@ -2578,6 +2574,56 @@ static int fsg_main_thread(void *common_)  /*************************** DEVICE ATTRIBUTES ***************************/ +static ssize_t ro_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +	struct fsg_lun		*curlun = fsg_lun_from_dev(dev); + +	return fsg_show_ro(curlun, buf); +} + +static ssize_t nofua_show(struct device *dev, struct device_attribute *attr, +			  char *buf) +{ +	struct fsg_lun		*curlun = fsg_lun_from_dev(dev); + +	return fsg_show_nofua(curlun, buf); +} + +static ssize_t file_show(struct device *dev, struct device_attribute *attr, +			 char *buf) +{ +	struct fsg_lun		*curlun = fsg_lun_from_dev(dev); +	struct rw_semaphore	*filesem = dev_get_drvdata(dev); + +	return fsg_show_file(curlun, filesem, buf); +} + +static ssize_t ro_store(struct device *dev, struct device_attribute *attr, +			const char *buf, size_t count) +{ +	struct fsg_lun		*curlun = fsg_lun_from_dev(dev); +	struct rw_semaphore	*filesem = dev_get_drvdata(dev); + +	return fsg_store_ro(curlun, filesem, buf, count); +} + +static ssize_t nofua_store(struct device *dev, struct device_attribute *attr, +			   const char *buf, size_t count) +{ +	struct fsg_lun		*curlun = fsg_lun_from_dev(dev); + +	return fsg_store_nofua(curlun, buf, count); +} + +static ssize_t file_store(struct device *dev, struct device_attribute *attr, +			  const char *buf, size_t count) +{ +	struct fsg_lun		*curlun = fsg_lun_from_dev(dev); +	struct rw_semaphore	*filesem = dev_get_drvdata(dev); + +	return fsg_store_file(curlun, filesem, buf, count); +} +  static DEVICE_ATTR_RW(ro);  static DEVICE_ATTR_RW(nofua);  static DEVICE_ATTR_RW(file); @@ -2595,221 +2641,422 @@ static void fsg_lun_release(struct device *dev)  	/* Nothing needs to be done */  } -static inline void fsg_common_get(struct fsg_common *common) +void fsg_common_get(struct fsg_common *common)  {  	kref_get(&common->ref);  } +EXPORT_SYMBOL_GPL(fsg_common_get); -static inline void fsg_common_put(struct fsg_common *common) +void fsg_common_put(struct fsg_common *common)  {  	kref_put(&common->ref, fsg_common_release);  } +EXPORT_SYMBOL_GPL(fsg_common_put); -static struct fsg_common *fsg_common_init(struct fsg_common *common, -					  struct usb_composite_dev *cdev, -					  struct fsg_config *cfg) +/* check if fsg_num_buffers is within a valid range */ +static inline int fsg_num_buffers_validate(unsigned int fsg_num_buffers)  { -	struct usb_gadget *gadget = cdev->gadget; -	struct fsg_buffhd *bh; -	struct fsg_lun *curlun; -	struct fsg_lun_config *lcfg; -	int nluns, i, rc; -	char *pathbuf; - -	rc = fsg_num_buffers_validate(); -	if (rc != 0) -		return ERR_PTR(rc); - -	/* Find out how many LUNs there should be */ -	nluns = cfg->nluns; -	if (nluns < 1 || nluns > FSG_MAX_LUNS) { -		dev_err(&gadget->dev, "invalid number of LUNs: %u\n", nluns); -		return ERR_PTR(-EINVAL); -	} +	if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4) +		return 0; +	pr_err("fsg_num_buffers %u is out of range (%d to %d)\n", +	       fsg_num_buffers, 2, 4); +	return -EINVAL; +} -	/* Allocate? */ +static struct fsg_common *fsg_common_setup(struct fsg_common *common) +{  	if (!common) { -		common = kzalloc(sizeof *common, GFP_KERNEL); +		common = kzalloc(sizeof(*common), GFP_KERNEL);  		if (!common)  			return ERR_PTR(-ENOMEM);  		common->free_storage_on_release = 1;  	} else { -		memset(common, 0, sizeof *common);  		common->free_storage_on_release = 0;  	} +	init_rwsem(&common->filesem); +	spin_lock_init(&common->lock); +	kref_init(&common->ref); +	init_completion(&common->thread_notifier); +	init_waitqueue_head(&common->fsg_wait); +	common->state = FSG_STATE_TERMINATED; -	common->buffhds = kcalloc(fsg_num_buffers, -				  sizeof *(common->buffhds), GFP_KERNEL); -	if (!common->buffhds) { -		if (common->free_storage_on_release) -			kfree(common); -		return ERR_PTR(-ENOMEM); +	return common; +} + +void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs) +{ +	common->sysfs = sysfs; +} +EXPORT_SYMBOL_GPL(fsg_common_set_sysfs); + +static void _fsg_common_free_buffers(struct fsg_buffhd *buffhds, unsigned n) +{ +	if (buffhds) { +		struct fsg_buffhd *bh = buffhds; +		while (n--) { +			kfree(bh->buf); +			++bh; +		} +		kfree(buffhds);  	} +} -	common->ops = cfg->ops; -	common->private_data = cfg->private_data; +int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n) +{ +	struct fsg_buffhd *bh, *buffhds; +	int i, rc; -	common->gadget = gadget; -	common->ep0 = gadget->ep0; -	common->ep0req = cdev->req; -	common->cdev = cdev; +	rc = fsg_num_buffers_validate(n); +	if (rc != 0) +		return rc; + +	buffhds = kcalloc(n, sizeof(*buffhds), GFP_KERNEL); +	if (!buffhds) +		return -ENOMEM; -	/* Maybe allocate device-global string IDs, and patch descriptors */ -	if (fsg_strings[FSG_STRING_INTERFACE].id == 0) { -		rc = usb_string_id(cdev); -		if (unlikely(rc < 0)) +	/* Data buffers cyclic list */ +	bh = buffhds; +	i = n; +	goto buffhds_first_it; +	do { +		bh->next = bh + 1; +		++bh; +buffhds_first_it: +		bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL); +		if (unlikely(!bh->buf))  			goto error_release; -		fsg_strings[FSG_STRING_INTERFACE].id = rc; -		fsg_intf_desc.iInterface = rc; -	} +	} while (--i); +	bh->next = buffhds; +	_fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers); +	common->fsg_num_buffers = n; +	common->buffhds = buffhds; + +	return 0; + +error_release:  	/* -	 * Create the LUNs, open their backing files, and register the -	 * LUN devices in sysfs. +	 * "buf"s pointed to by heads after n - i are NULL +	 * so releasing them won't hurt  	 */ -	curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); -	if (unlikely(!curlun)) { -		rc = -ENOMEM; -		goto error_release; +	_fsg_common_free_buffers(buffhds, n); + +	return -ENOMEM; +} +EXPORT_SYMBOL_GPL(fsg_common_set_num_buffers); + +static inline void fsg_common_remove_sysfs(struct fsg_lun *lun) +{ +	device_remove_file(&lun->dev, &dev_attr_nofua); +	/* +	 * device_remove_file() => +	 * +	 * here the attr (e.g. dev_attr_ro) is only used to be passed to: +	 * +	 *	sysfs_remove_file() => +	 * +	 *	here e.g. both dev_attr_ro_cdrom and dev_attr_ro are in +	 *	the same namespace and +	 *	from here only attr->name is passed to: +	 * +	 *		sysfs_hash_and_remove() +	 * +	 *		attr->name is the same for dev_attr_ro_cdrom and +	 *		dev_attr_ro +	 *		attr->name is the same for dev_attr_file and +	 *		dev_attr_file_nonremovable +	 * +	 * so we don't differentiate between removing e.g. dev_attr_ro_cdrom +	 * and dev_attr_ro +	 */ +	device_remove_file(&lun->dev, &dev_attr_ro); +	device_remove_file(&lun->dev, &dev_attr_file); +} + +void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs) +{ +	if (sysfs) { +		fsg_common_remove_sysfs(lun); +		device_unregister(&lun->dev);  	} -	common->luns = curlun; +	fsg_lun_close(lun); +	kfree(lun); +} +EXPORT_SYMBOL_GPL(fsg_common_remove_lun); -	init_rwsem(&common->filesem); +static void _fsg_common_remove_luns(struct fsg_common *common, int n) +{ +	int i; -	for (i = 0, lcfg = cfg->luns; i < nluns; ++i, ++curlun, ++lcfg) { -		curlun->cdrom = !!lcfg->cdrom; -		curlun->ro = lcfg->cdrom || lcfg->ro; -		curlun->initially_ro = curlun->ro; -		curlun->removable = lcfg->removable; -		curlun->dev.release = fsg_lun_release; -		curlun->dev.parent = &gadget->dev; -		/* curlun->dev.driver = &fsg_driver.driver; XXX */ -		dev_set_drvdata(&curlun->dev, &common->filesem); -		dev_set_name(&curlun->dev, "lun%d", i); - -		rc = device_register(&curlun->dev); -		if (rc) { -			INFO(common, "failed to register LUN%d: %d\n", i, rc); -			common->nluns = i; -			put_device(&curlun->dev); -			goto error_release; +	for (i = 0; i < n; ++i) +		if (common->luns[i]) { +			fsg_common_remove_lun(common->luns[i], common->sysfs); +			common->luns[i] = NULL;  		} +} +EXPORT_SYMBOL_GPL(fsg_common_remove_luns); -		rc = device_create_file(&curlun->dev, -					curlun->cdrom -				      ? &dev_attr_ro_cdrom -				      : &dev_attr_ro); -		if (rc) -			goto error_luns; -		rc = device_create_file(&curlun->dev, -					curlun->removable -				      ? &dev_attr_file -				      : &dev_attr_file_nonremovable); -		if (rc) -			goto error_luns; -		rc = device_create_file(&curlun->dev, &dev_attr_nofua); -		if (rc) -			goto error_luns; +void fsg_common_remove_luns(struct fsg_common *common) +{ +	_fsg_common_remove_luns(common, common->nluns); +} -		if (lcfg->filename) { -			rc = fsg_lun_open(curlun, lcfg->filename); -			if (rc) -				goto error_luns; -		} else if (!curlun->removable) { -			ERROR(common, "no file given for LUN%d\n", i); -			rc = -EINVAL; -			goto error_luns; -		} +void fsg_common_free_luns(struct fsg_common *common) +{ +	fsg_common_remove_luns(common); +	kfree(common->luns); +	common->luns = NULL; +} +EXPORT_SYMBOL_GPL(fsg_common_free_luns); + +int fsg_common_set_nluns(struct fsg_common *common, int nluns) +{ +	struct fsg_lun **curlun; + +	/* Find out how many LUNs there should be */ +	if (nluns < 1 || nluns > FSG_MAX_LUNS) { +		pr_err("invalid number of LUNs: %u\n", nluns); +		return -EINVAL;  	} + +	curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); +	if (unlikely(!curlun)) +		return -ENOMEM; + +	if (common->luns) +		fsg_common_free_luns(common); + +	common->luns = curlun;  	common->nluns = nluns; -	/* Data buffers cyclic list */ -	bh = common->buffhds; -	i = fsg_num_buffers; -	goto buffhds_first_it; -	do { -		bh->next = bh + 1; -		++bh; -buffhds_first_it: -		bh->buf = kmalloc(FSG_BUFLEN, GFP_KERNEL); -		if (unlikely(!bh->buf)) { -			rc = -ENOMEM; -			goto error_release; -		} -	} while (--i); -	bh->next = common->buffhds; +	pr_info("Number of LUNs=%d\n", common->nluns); -	/* Prepare inquiryString */ -	i = get_default_bcdDevice(); -	snprintf(common->inquiry_string, sizeof common->inquiry_string, -		 "%-8s%-16s%04x", cfg->vendor_name ?: "Linux", -		 /* Assume product name dependent on the first LUN */ -		 cfg->product_name ?: (common->luns->cdrom -				     ? "File-CD Gadget" -				     : "File-Stor Gadget"), -		 i); +	return 0; +} +EXPORT_SYMBOL_GPL(fsg_common_set_nluns); + +void fsg_common_set_ops(struct fsg_common *common, +			const struct fsg_operations *ops) +{ +	common->ops = ops; +} +EXPORT_SYMBOL_GPL(fsg_common_set_ops); + +void fsg_common_free_buffers(struct fsg_common *common) +{ +	_fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers); +	common->buffhds = NULL; +} +EXPORT_SYMBOL_GPL(fsg_common_free_buffers); + +int fsg_common_set_cdev(struct fsg_common *common, +			 struct usb_composite_dev *cdev, bool can_stall) +{ +	struct usb_string *us; + +	common->gadget = cdev->gadget; +	common->ep0 = cdev->gadget->ep0; +	common->ep0req = cdev->req; +	common->cdev = cdev; + +	us = usb_gstrings_attach(cdev, fsg_strings_array, +				 ARRAY_SIZE(fsg_strings)); +	if (IS_ERR(us)) +		return PTR_ERR(us); + +	fsg_intf_desc.iInterface = us[FSG_STRING_INTERFACE].id;  	/*  	 * Some peripheral controllers are known not to be able to  	 * halt bulk endpoints correctly.  If one of them is present,  	 * disable stalls.  	 */ -	common->can_stall = cfg->can_stall && -		!(gadget_is_at91(common->gadget)); +	common->can_stall = can_stall && !(gadget_is_at91(common->gadget)); -	spin_lock_init(&common->lock); -	kref_init(&common->ref); +	return 0; +} +EXPORT_SYMBOL_GPL(fsg_common_set_cdev); -	/* Tell the thread to start working */ -	common->thread_task = -		kthread_create(fsg_main_thread, common, "file-storage"); -	if (IS_ERR(common->thread_task)) { -		rc = PTR_ERR(common->thread_task); -		goto error_release; +static inline int fsg_common_add_sysfs(struct fsg_common *common, +				       struct fsg_lun *lun) +{ +	int rc; + +	rc = device_register(&lun->dev); +	if (rc) { +		put_device(&lun->dev); +		return rc;  	} -	init_completion(&common->thread_notifier); -	init_waitqueue_head(&common->fsg_wait); -	/* Information */ -	INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); -	INFO(common, "Number of LUNs=%d\n", common->nluns); +	rc = device_create_file(&lun->dev, +				lun->cdrom +			      ? &dev_attr_ro_cdrom +			      : &dev_attr_ro); +	if (rc) +		goto error; +	rc = device_create_file(&lun->dev, +				lun->removable +			      ? &dev_attr_file +			      : &dev_attr_file_nonremovable); +	if (rc) +		goto error; +	rc = device_create_file(&lun->dev, &dev_attr_nofua); +	if (rc) +		goto error; + +	return 0; + +error: +	/* removing nonexistent files is a no-op */ +	fsg_common_remove_sysfs(lun); +	device_unregister(&lun->dev); +	return rc; +} + +int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, +			  unsigned int id, const char *name, +			  const char **name_pfx) +{ +	struct fsg_lun *lun; +	char *pathbuf, *p; +	int rc = -ENOMEM; + +	if (!common->nluns || !common->luns) +		return -ENODEV; + +	if (common->luns[id]) +		return -EBUSY; + +	if (!cfg->filename && !cfg->removable) { +		pr_err("no file given for LUN%d\n", id); +		return -EINVAL; +	} + +	lun = kzalloc(sizeof(*lun), GFP_KERNEL); +	if (!lun) +		return -ENOMEM; + +	lun->name_pfx = name_pfx; + +	lun->cdrom = !!cfg->cdrom; +	lun->ro = cfg->cdrom || cfg->ro; +	lun->initially_ro = lun->ro; +	lun->removable = !!cfg->removable; + +	if (!common->sysfs) { +		/* we DON'T own the name!*/ +		lun->name = name; +	} else { +		lun->dev.release = fsg_lun_release; +		lun->dev.parent = &common->gadget->dev; +		dev_set_drvdata(&lun->dev, &common->filesem); +		dev_set_name(&lun->dev, "%s", name); +		lun->name = dev_name(&lun->dev); + +		rc = fsg_common_add_sysfs(common, lun); +		if (rc) { +			pr_info("failed to register LUN%d: %d\n", id, rc); +			goto error_sysfs; +		} +	} + +	common->luns[id] = lun; + +	if (cfg->filename) { +		rc = fsg_lun_open(lun, cfg->filename); +		if (rc) +			goto error_lun; +	}  	pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); -	for (i = 0, nluns = common->nluns, curlun = common->luns; -	     i < nluns; -	     ++curlun, ++i) { -		char *p = "(no medium)"; -		if (fsg_lun_is_open(curlun)) { -			p = "(error)"; -			if (pathbuf) { -				p = d_path(&curlun->filp->f_path, -					   pathbuf, PATH_MAX); -				if (IS_ERR(p)) -					p = "(error)"; -			} +	p = "(no medium)"; +	if (fsg_lun_is_open(lun)) { +		p = "(error)"; +		if (pathbuf) { +			p = d_path(&lun->filp->f_path, pathbuf, PATH_MAX); +			if (IS_ERR(p)) +				p = "(error)";  		} -		LINFO(curlun, "LUN: %s%s%sfile: %s\n", -		      curlun->removable ? "removable " : "", -		      curlun->ro ? "read only " : "", -		      curlun->cdrom ? "CD-ROM " : "", -		      p);  	} +	pr_info("LUN: %s%s%sfile: %s\n", +	      lun->removable ? "removable " : "", +	      lun->ro ? "read only " : "", +	      lun->cdrom ? "CD-ROM " : "", +	      p);  	kfree(pathbuf); +	return 0; + +error_lun: +	if (common->sysfs) { +		fsg_common_remove_sysfs(lun); +		device_unregister(&lun->dev); +	} +	fsg_lun_close(lun); +	common->luns[id] = NULL; +error_sysfs: +	kfree(lun); +	return rc; +} +EXPORT_SYMBOL_GPL(fsg_common_create_lun); + +int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg) +{ +	char buf[8]; /* enough for 100000000 different numbers, decimal */ +	int i, rc; + +	for (i = 0; i < common->nluns; ++i) { +		snprintf(buf, sizeof(buf), "lun%d", i); +		rc = fsg_common_create_lun(common, &cfg->luns[i], i, buf, NULL); +		if (rc) +			goto fail; +	} + +	pr_info("Number of LUNs=%d\n", common->nluns); + +	return 0; + +fail: +	_fsg_common_remove_luns(common, i); +	return rc; +} +EXPORT_SYMBOL_GPL(fsg_common_create_luns); + +void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, +				   const char *pn) +{ +	int i; + +	/* Prepare inquiryString */ +	i = get_default_bcdDevice(); +	snprintf(common->inquiry_string, sizeof(common->inquiry_string), +		 "%-8s%-16s%04x", vn ?: "Linux", +		 /* Assume product name dependent on the first LUN */ +		 pn ?: ((*common->luns)->cdrom +		     ? "File-CD Gadget" +		     : "File-Stor Gadget"), +		 i); +} +EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string); + +int fsg_common_run_thread(struct fsg_common *common) +{ +	common->state = FSG_STATE_IDLE; +	/* Tell the thread to start working */ +	common->thread_task = +		kthread_create(fsg_main_thread, common, "file-storage"); +	if (IS_ERR(common->thread_task)) { +		common->state = FSG_STATE_TERMINATED; +		return PTR_ERR(common->thread_task); +	} +  	DBG(common, "I/O thread pid: %d\n", task_pid_nr(common->thread_task));  	wake_up_process(common->thread_task); -	return common; - -error_luns: -	common->nluns = i + 1; -error_release: -	common->state = FSG_STATE_TERMINATED;	/* The thread is dead */ -	/* Call fsg_common_release() directly, ref might be not initialised. */ -	fsg_common_release(&common->ref); -	return ERR_PTR(rc); +	return 0;  } +EXPORT_SYMBOL_GPL(fsg_common_run_thread);  static void fsg_common_release(struct kref *ref)  { @@ -2822,36 +3069,26 @@ static void fsg_common_release(struct kref *ref)  	}  	if (likely(common->luns)) { -		struct fsg_lun *lun = common->luns; +		struct fsg_lun **lun_it = common->luns;  		unsigned i = common->nluns;  		/* In error recovery common->nluns may be zero. */ -		for (; i; --i, ++lun) { -			device_remove_file(&lun->dev, &dev_attr_nofua); -			device_remove_file(&lun->dev, -					   lun->cdrom -					 ? &dev_attr_ro_cdrom -					 : &dev_attr_ro); -			device_remove_file(&lun->dev, -					   lun->removable -					 ? &dev_attr_file -					 : &dev_attr_file_nonremovable); +		for (; i; --i, ++lun_it) { +			struct fsg_lun *lun = *lun_it; +			if (!lun) +				continue; +			if (common->sysfs) +				fsg_common_remove_sysfs(lun);  			fsg_lun_close(lun); -			device_unregister(&lun->dev); +			if (common->sysfs) +				device_unregister(&lun->dev); +			kfree(lun);  		}  		kfree(common->luns);  	} -	{ -		struct fsg_buffhd *bh = common->buffhds; -		unsigned i = fsg_num_buffers; -		do { -			kfree(bh->buf); -		} while (++bh, --i); -	} - -	kfree(common->buffhds); +	_fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers);  	if (common->free_storage_on_release)  		kfree(common);  } @@ -2859,24 +3096,6 @@ static void fsg_common_release(struct kref *ref)  /*-------------------------------------------------------------------------*/ -static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) -{ -	struct fsg_dev		*fsg = fsg_from_func(f); -	struct fsg_common	*common = fsg->common; - -	DBG(fsg, "unbind\n"); -	if (fsg->common->fsg == fsg) { -		fsg->common->new_fsg = NULL; -		raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); -		/* FIXME: make interruptible or killable somehow? */ -		wait_event(common->fsg_wait, common->fsg != fsg); -	} - -	fsg_common_put(common); -	usb_free_all_descriptors(&fsg->function); -	kfree(fsg); -} -  static int fsg_bind(struct usb_configuration *c, struct usb_function *f)  {  	struct fsg_dev		*fsg = fsg_from_func(f); @@ -2885,6 +3104,19 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)  	struct usb_ep		*ep;  	unsigned		max_burst;  	int			ret; +	struct fsg_opts		*opts; + +	opts = fsg_opts_from_func_inst(f->fi); +	if (!opts->no_configfs) { +		ret = fsg_common_set_cdev(fsg->common, c->cdev, +					  fsg->common->can_stall); +		if (ret) +			return ret; +		fsg_common_set_inquiry_string(fsg->common, NULL, NULL); +		ret = fsg_common_run_thread(fsg->common); +		if (ret) +			return ret; +	}  	fsg->gadget = gadget; @@ -2937,95 +3169,472 @@ autoconf_fail:  	return -ENOTSUPP;  } -/****************************** ADD FUNCTION ******************************/ +/****************************** ALLOCATE FUNCTION *************************/ -static struct usb_gadget_strings *fsg_strings_array[] = { -	&fsg_stringtab, +static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) +{ +	struct fsg_dev		*fsg = fsg_from_func(f); +	struct fsg_common	*common = fsg->common; + +	DBG(fsg, "unbind\n"); +	if (fsg->common->fsg == fsg) { +		fsg->common->new_fsg = NULL; +		raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); +		/* FIXME: make interruptible or killable somehow? */ +		wait_event(common->fsg_wait, common->fsg != fsg); +	} + +	usb_free_all_descriptors(&fsg->function); +} + +static inline struct fsg_lun_opts *to_fsg_lun_opts(struct config_item *item) +{ +	return container_of(to_config_group(item), struct fsg_lun_opts, group); +} + +static inline struct fsg_opts *to_fsg_opts(struct config_item *item) +{ +	return container_of(to_config_group(item), struct fsg_opts, +			    func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(fsg_lun_opts); +CONFIGFS_ATTR_OPS(fsg_lun_opts); + +static void fsg_lun_attr_release(struct config_item *item) +{ +	struct fsg_lun_opts *lun_opts; + +	lun_opts = to_fsg_lun_opts(item); +	kfree(lun_opts); +} + +static struct configfs_item_operations fsg_lun_item_ops = { +	.release		= fsg_lun_attr_release, +	.show_attribute		= fsg_lun_opts_attr_show, +	.store_attribute	= fsg_lun_opts_attr_store, +}; + +static ssize_t fsg_lun_opts_file_show(struct fsg_lun_opts *opts, char *page) +{ +	struct fsg_opts *fsg_opts; + +	fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + +	return fsg_show_file(opts->lun, &fsg_opts->common->filesem, page); +} + +static ssize_t fsg_lun_opts_file_store(struct fsg_lun_opts *opts, +				       const char *page, size_t len) +{ +	struct fsg_opts *fsg_opts; + +	fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + +	return fsg_store_file(opts->lun, &fsg_opts->common->filesem, page, len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_file = +	__CONFIGFS_ATTR(file, S_IRUGO | S_IWUSR, fsg_lun_opts_file_show, +			fsg_lun_opts_file_store); + +static ssize_t fsg_lun_opts_ro_show(struct fsg_lun_opts *opts, char *page) +{ +	return fsg_show_ro(opts->lun, page); +} + +static ssize_t fsg_lun_opts_ro_store(struct fsg_lun_opts *opts, +				       const char *page, size_t len) +{ +	struct fsg_opts *fsg_opts; + +	fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + +	return fsg_store_ro(opts->lun, &fsg_opts->common->filesem, page, len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_ro = +	__CONFIGFS_ATTR(ro, S_IRUGO | S_IWUSR, fsg_lun_opts_ro_show, +			fsg_lun_opts_ro_store); + +static ssize_t fsg_lun_opts_removable_show(struct fsg_lun_opts *opts, +					   char *page) +{ +	return fsg_show_removable(opts->lun, page); +} + +static ssize_t fsg_lun_opts_removable_store(struct fsg_lun_opts *opts, +				       const char *page, size_t len) +{ +	return fsg_store_removable(opts->lun, page, len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_removable = +	__CONFIGFS_ATTR(removable, S_IRUGO | S_IWUSR, +			fsg_lun_opts_removable_show, +			fsg_lun_opts_removable_store); + +static ssize_t fsg_lun_opts_cdrom_show(struct fsg_lun_opts *opts, char *page) +{ +	return fsg_show_cdrom(opts->lun, page); +} + +static ssize_t fsg_lun_opts_cdrom_store(struct fsg_lun_opts *opts, +				       const char *page, size_t len) +{ +	struct fsg_opts *fsg_opts; + +	fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent); + +	return fsg_store_cdrom(opts->lun, &fsg_opts->common->filesem, page, +			       len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_cdrom = +	__CONFIGFS_ATTR(cdrom, S_IRUGO | S_IWUSR, fsg_lun_opts_cdrom_show, +			fsg_lun_opts_cdrom_store); + +static ssize_t fsg_lun_opts_nofua_show(struct fsg_lun_opts *opts, char *page) +{ +	return fsg_show_nofua(opts->lun, page); +} + +static ssize_t fsg_lun_opts_nofua_store(struct fsg_lun_opts *opts, +				       const char *page, size_t len) +{ +	return fsg_store_nofua(opts->lun, page, len); +} + +static struct fsg_lun_opts_attribute fsg_lun_opts_nofua = +	__CONFIGFS_ATTR(nofua, S_IRUGO | S_IWUSR, fsg_lun_opts_nofua_show, +			fsg_lun_opts_nofua_store); + +static struct configfs_attribute *fsg_lun_attrs[] = { +	&fsg_lun_opts_file.attr, +	&fsg_lun_opts_ro.attr, +	&fsg_lun_opts_removable.attr, +	&fsg_lun_opts_cdrom.attr, +	&fsg_lun_opts_nofua.attr,  	NULL,  }; -static int fsg_bind_config(struct usb_composite_dev *cdev, -			   struct usb_configuration *c, -			   struct fsg_common *common) +static struct config_item_type fsg_lun_type = { +	.ct_item_ops	= &fsg_lun_item_ops, +	.ct_attrs	= fsg_lun_attrs, +	.ct_owner	= THIS_MODULE, +}; + +static struct config_group *fsg_lun_make(struct config_group *group, +					 const char *name)  { -	struct fsg_dev *fsg; +	struct fsg_lun_opts *opts; +	struct fsg_opts *fsg_opts; +	struct fsg_lun_config config; +	char *num_str; +	u8 num; +	int ret; + +	num_str = strchr(name, '.'); +	if (!num_str) { +		pr_err("Unable to locate . in LUN.NUMBER\n"); +		return ERR_PTR(-EINVAL); +	} +	num_str++; + +	ret = kstrtou8(num_str, 0, &num); +	if (ret) +		return ERR_PTR(ret); + +	fsg_opts = to_fsg_opts(&group->cg_item); +	if (num >= FSG_MAX_LUNS) +		return ERR_PTR(-ERANGE); + +	mutex_lock(&fsg_opts->lock); +	if (fsg_opts->refcnt || fsg_opts->common->luns[num]) { +		ret = -EBUSY; +		goto out; +	} + +	opts = kzalloc(sizeof(*opts), GFP_KERNEL); +	if (!opts) { +		ret = -ENOMEM; +		goto out; +	} + +	memset(&config, 0, sizeof(config)); +	config.removable = true; + +	ret = fsg_common_create_lun(fsg_opts->common, &config, num, name, +				    (const char **)&group->cg_item.ci_name); +	if (ret) { +		kfree(opts); +		goto out; +	} +	opts->lun = fsg_opts->common->luns[num]; +	opts->lun_id = num; +	mutex_unlock(&fsg_opts->lock); + +	config_group_init_type_name(&opts->group, name, &fsg_lun_type); + +	return &opts->group; +out: +	mutex_unlock(&fsg_opts->lock); +	return ERR_PTR(ret); +} + +static void fsg_lun_drop(struct config_group *group, struct config_item *item) +{ +	struct fsg_lun_opts *lun_opts; +	struct fsg_opts *fsg_opts; + +	lun_opts = to_fsg_lun_opts(item); +	fsg_opts = to_fsg_opts(&group->cg_item); + +	mutex_lock(&fsg_opts->lock); +	if (fsg_opts->refcnt) { +		struct config_item *gadget; + +		gadget = group->cg_item.ci_parent->ci_parent; +		unregister_gadget_item(gadget); +	} + +	fsg_common_remove_lun(lun_opts->lun, fsg_opts->common->sysfs); +	fsg_opts->common->luns[lun_opts->lun_id] = NULL; +	lun_opts->lun_id = 0; +	mutex_unlock(&fsg_opts->lock); + +	config_item_put(item); +} + +CONFIGFS_ATTR_STRUCT(fsg_opts); +CONFIGFS_ATTR_OPS(fsg_opts); + +static void fsg_attr_release(struct config_item *item) +{ +	struct fsg_opts *opts = to_fsg_opts(item); + +	usb_put_function_instance(&opts->func_inst); +} + +static struct configfs_item_operations fsg_item_ops = { +	.release		= fsg_attr_release, +	.show_attribute		= fsg_opts_attr_show, +	.store_attribute	= fsg_opts_attr_store, +}; + +static ssize_t fsg_opts_stall_show(struct fsg_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->common->can_stall); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t fsg_opts_stall_store(struct fsg_opts *opts, const char *page, +				    size_t len) +{ +	int ret; +	bool stall; + +	mutex_lock(&opts->lock); + +	if (opts->refcnt) { +		mutex_unlock(&opts->lock); +		return -EBUSY; +	} + +	ret = strtobool(page, &stall); +	if (!ret) { +		opts->common->can_stall = stall; +		ret = len; +	} + +	mutex_unlock(&opts->lock); + +	return ret; +} + +static struct fsg_opts_attribute fsg_opts_stall = +	__CONFIGFS_ATTR(stall, S_IRUGO | S_IWUSR, fsg_opts_stall_show, +			fsg_opts_stall_store); + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES +static ssize_t fsg_opts_num_buffers_show(struct fsg_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->common->fsg_num_buffers); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t fsg_opts_num_buffers_store(struct fsg_opts *opts, +					  const char *page, size_t len) +{ +	int ret; +	u8 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} +	ret = kstrtou8(page, 0, &num); +	if (ret) +		goto end; + +	ret = fsg_num_buffers_validate(num); +	if (ret) +		goto end; + +	fsg_common_set_num_buffers(opts->common, num); +	ret = len; + +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct fsg_opts_attribute fsg_opts_num_buffers = +	__CONFIGFS_ATTR(num_buffers, S_IRUGO | S_IWUSR, +			fsg_opts_num_buffers_show, +			fsg_opts_num_buffers_store); + +#endif + +static struct configfs_attribute *fsg_attrs[] = { +	&fsg_opts_stall.attr, +#ifdef CONFIG_USB_GADGET_DEBUG_FILES +	&fsg_opts_num_buffers.attr, +#endif +	NULL, +}; + +static struct configfs_group_operations fsg_group_ops = { +	.make_group	= fsg_lun_make, +	.drop_item	= fsg_lun_drop, +}; + +static struct config_item_type fsg_func_type = { +	.ct_item_ops	= &fsg_item_ops, +	.ct_group_ops	= &fsg_group_ops, +	.ct_attrs	= fsg_attrs, +	.ct_owner	= THIS_MODULE, +}; + +static void fsg_free_inst(struct usb_function_instance *fi) +{ +	struct fsg_opts *opts; + +	opts = fsg_opts_from_func_inst(fi); +	fsg_common_put(opts->common); +	kfree(opts); +} + +static struct usb_function_instance *fsg_alloc_inst(void) +{ +	struct fsg_opts *opts; +	struct fsg_lun_config config;  	int rc; -	fsg = kzalloc(sizeof *fsg, GFP_KERNEL); +	opts = kzalloc(sizeof(*opts), GFP_KERNEL); +	if (!opts) +		return ERR_PTR(-ENOMEM); +	mutex_init(&opts->lock); +	opts->func_inst.free_func_inst = fsg_free_inst; +	opts->common = fsg_common_setup(opts->common); +	if (IS_ERR(opts->common)) { +		rc = PTR_ERR(opts->common); +		goto release_opts; +	} +	rc = fsg_common_set_nluns(opts->common, FSG_MAX_LUNS); +	if (rc) +		goto release_opts; + +	rc = fsg_common_set_num_buffers(opts->common, +					CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS); +	if (rc) +		goto release_luns; + +	pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); + +	memset(&config, 0, sizeof(config)); +	config.removable = true; +	rc = fsg_common_create_lun(opts->common, &config, 0, "lun.0", +			(const char **)&opts->func_inst.group.cg_item.ci_name); +	opts->lun0.lun = opts->common->luns[0]; +	opts->lun0.lun_id = 0; +	config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type); +	opts->default_groups[0] = &opts->lun0.group; +	opts->func_inst.group.default_groups = opts->default_groups; + +	config_group_init_type_name(&opts->func_inst.group, "", &fsg_func_type); + +	return &opts->func_inst; + +release_luns: +	kfree(opts->common->luns); +release_opts: +	kfree(opts); +	return ERR_PTR(rc); +} + +static void fsg_free(struct usb_function *f) +{ +	struct fsg_dev *fsg; +	struct fsg_opts *opts; + +	fsg = container_of(f, struct fsg_dev, function); +	opts = container_of(f->fi, struct fsg_opts, func_inst); + +	mutex_lock(&opts->lock); +	opts->refcnt--; +	mutex_unlock(&opts->lock); + +	kfree(fsg); +} + +static struct usb_function *fsg_alloc(struct usb_function_instance *fi) +{ +	struct fsg_opts *opts = fsg_opts_from_func_inst(fi); +	struct fsg_common *common = opts->common; +	struct fsg_dev *fsg; + +	fsg = kzalloc(sizeof(*fsg), GFP_KERNEL);  	if (unlikely(!fsg)) -		return -ENOMEM; +		return ERR_PTR(-ENOMEM); -	fsg->function.name        = FSG_DRIVER_DESC; -	fsg->function.strings     = fsg_strings_array; -	fsg->function.bind        = fsg_bind; -	fsg->function.unbind      = fsg_unbind; -	fsg->function.setup       = fsg_setup; -	fsg->function.set_alt     = fsg_set_alt; -	fsg->function.disable     = fsg_disable; +	mutex_lock(&opts->lock); +	opts->refcnt++; +	mutex_unlock(&opts->lock); +	fsg->function.name	= FSG_DRIVER_DESC; +	fsg->function.bind	= fsg_bind; +	fsg->function.unbind	= fsg_unbind; +	fsg->function.setup	= fsg_setup; +	fsg->function.set_alt	= fsg_set_alt; +	fsg->function.disable	= fsg_disable; +	fsg->function.free_func	= fsg_free;  	fsg->common               = common; -	/* -	 * Our caller holds a reference to common structure so we -	 * don't have to be worry about it being freed until we return -	 * from this function.  So instead of incrementing counter now -	 * and decrement in error recovery we increment it only when -	 * call to usb_add_function() was successful. -	 */ -	rc = usb_add_function(c, &fsg->function); -	if (unlikely(rc)) -		kfree(fsg); -	else -		fsg_common_get(fsg->common); -	return rc; +	return &fsg->function;  } +DECLARE_USB_FUNCTION_INIT(mass_storage, fsg_alloc_inst, fsg_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michal Nazarewicz");  /************************* Module parameters *************************/ -struct fsg_module_parameters { -	char		*file[FSG_MAX_LUNS]; -	bool		ro[FSG_MAX_LUNS]; -	bool		removable[FSG_MAX_LUNS]; -	bool		cdrom[FSG_MAX_LUNS]; -	bool		nofua[FSG_MAX_LUNS]; - -	unsigned int	file_count, ro_count, removable_count, cdrom_count; -	unsigned int	nofua_count; -	unsigned int	luns;	/* nluns */ -	bool		stall;	/* can_stall */ -}; -#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc)	\ -	module_param_array_named(prefix ## name, params.name, type,	\ -				 &prefix ## params.name ## _count,	\ -				 S_IRUGO);				\ -	MODULE_PARM_DESC(prefix ## name, desc) - -#define _FSG_MODULE_PARAM(prefix, params, name, type, desc)		\ -	module_param_named(prefix ## name, params.name, type,		\ -			   S_IRUGO);					\ -	MODULE_PARM_DESC(prefix ## name, desc) - -#define FSG_MODULE_PARAMETERS(prefix, params)				\ -	_FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp,		\ -				"names of backing files or devices");	\ -	_FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool,		\ -				"true to force read-only");		\ -	_FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool,	\ -				"true to simulate removable media");	\ -	_FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool,		\ -				"true to simulate CD-ROM instead of disk"); \ -	_FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool,		\ -				"true to ignore SCSI WRITE(10,12) FUA bit"); \ -	_FSG_MODULE_PARAM(prefix, params, luns, uint,			\ -			  "number of LUNs");				\ -	_FSG_MODULE_PARAM(prefix, params, stall, bool,			\ -			  "false to prevent bulk stalls") - -static void -fsg_config_from_params(struct fsg_config *cfg, -		       const struct fsg_module_parameters *params) +void fsg_config_from_params(struct fsg_config *cfg, +		       const struct fsg_module_parameters *params, +		       unsigned int fsg_num_buffers)  {  	struct fsg_lun_config *lun;  	unsigned i; @@ -3053,19 +3662,7 @@ fsg_config_from_params(struct fsg_config *cfg,  	/* Finalise */  	cfg->can_stall = params->stall; +	cfg->fsg_num_buffers = fsg_num_buffers;  } +EXPORT_SYMBOL_GPL(fsg_config_from_params); -static inline struct fsg_common * -fsg_common_from_params(struct fsg_common *common, -		       struct usb_composite_dev *cdev, -		       const struct fsg_module_parameters *params) -	__attribute__((unused)); -static inline struct fsg_common * -fsg_common_from_params(struct fsg_common *common, -		       struct usb_composite_dev *cdev, -		       const struct fsg_module_parameters *params) -{ -	struct fsg_config cfg; -	fsg_config_from_params(&cfg, params); -	return fsg_common_init(common, cdev, &cfg); -} diff --git a/drivers/usb/gadget/f_mass_storage.h b/drivers/usb/gadget/f_mass_storage.h new file mode 100644 index 00000000000..b4866fcef30 --- /dev/null +++ b/drivers/usb/gadget/f_mass_storage.h @@ -0,0 +1,166 @@ +#ifndef USB_F_MASS_STORAGE_H +#define USB_F_MASS_STORAGE_H + +#include <linux/usb/composite.h> +#include "storage_common.h" + +struct fsg_module_parameters { +	char		*file[FSG_MAX_LUNS]; +	bool		ro[FSG_MAX_LUNS]; +	bool		removable[FSG_MAX_LUNS]; +	bool		cdrom[FSG_MAX_LUNS]; +	bool		nofua[FSG_MAX_LUNS]; + +	unsigned int	file_count, ro_count, removable_count, cdrom_count; +	unsigned int	nofua_count; +	unsigned int	luns;	/* nluns */ +	bool		stall;	/* can_stall */ +}; + +#define _FSG_MODULE_PARAM_ARRAY(prefix, params, name, type, desc)	\ +	module_param_array_named(prefix ## name, params.name, type,	\ +				 &prefix ## params.name ## _count,	\ +				 S_IRUGO);				\ +	MODULE_PARM_DESC(prefix ## name, desc) + +#define _FSG_MODULE_PARAM(prefix, params, name, type, desc)		\ +	module_param_named(prefix ## name, params.name, type,		\ +			   S_IRUGO);					\ +	MODULE_PARM_DESC(prefix ## name, desc) + +#define __FSG_MODULE_PARAMETERS(prefix, params)				\ +	_FSG_MODULE_PARAM_ARRAY(prefix, params, file, charp,		\ +				"names of backing files or devices");	\ +	_FSG_MODULE_PARAM_ARRAY(prefix, params, ro, bool,		\ +				"true to force read-only");		\ +	_FSG_MODULE_PARAM_ARRAY(prefix, params, removable, bool,	\ +				"true to simulate removable media");	\ +	_FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool,		\ +				"true to simulate CD-ROM instead of disk"); \ +	_FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool,		\ +				"true to ignore SCSI WRITE(10,12) FUA bit"); \ +	_FSG_MODULE_PARAM(prefix, params, luns, uint,			\ +			  "number of LUNs");				\ +	_FSG_MODULE_PARAM(prefix, params, stall, bool,			\ +			  "false to prevent bulk stalls") + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +#define FSG_MODULE_PARAMETERS(prefix, params)				\ +	__FSG_MODULE_PARAMETERS(prefix, params);			\ +	module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO);\ +	MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers") +#else + +#define FSG_MODULE_PARAMETERS(prefix, params)				\ +	__FSG_MODULE_PARAMETERS(prefix, params) + +#endif + +struct fsg_common; + +/* FSF callback functions */ +struct fsg_operations { +	/* +	 * Callback function to call when thread exits.  If no +	 * callback is set or it returns value lower then zero MSF +	 * will force eject all LUNs it operates on (including those +	 * marked as non-removable or with prevent_medium_removal flag +	 * set). +	 */ +	int (*thread_exits)(struct fsg_common *common); +}; + +struct fsg_lun_opts { +	struct config_group group; +	struct fsg_lun *lun; +	int lun_id; +}; + +struct fsg_opts { +	struct fsg_common *common; +	struct usb_function_instance func_inst; +	struct fsg_lun_opts lun0; +	struct config_group *default_groups[2]; +	bool no_configfs; /* for legacy gadgets */ + +	/* +	 * Read/write access to configfs attributes is handled by configfs. +	 * +	 * This is to protect the data from concurrent access by read/write +	 * and create symlink/remove symlink. +	 */ +	struct mutex			lock; +	int				refcnt; +}; + +struct fsg_lun_config { +	const char *filename; +	char ro; +	char removable; +	char cdrom; +	char nofua; +}; + +struct fsg_config { +	unsigned nluns; +	struct fsg_lun_config luns[FSG_MAX_LUNS]; + +	/* Callback functions. */ +	const struct fsg_operations	*ops; +	/* Gadget's private data. */ +	void			*private_data; + +	const char *vendor_name;		/*  8 characters or less */ +	const char *product_name;		/* 16 characters or less */ + +	char			can_stall; +	unsigned int		fsg_num_buffers; +}; + +static inline struct fsg_opts * +fsg_opts_from_func_inst(const struct usb_function_instance *fi) +{ +	return container_of(fi, struct fsg_opts, func_inst); +} + +void fsg_common_get(struct fsg_common *common); + +void fsg_common_put(struct fsg_common *common); + +void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs); + +int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n); + +void fsg_common_free_buffers(struct fsg_common *common); + +int fsg_common_set_cdev(struct fsg_common *common, +			struct usb_composite_dev *cdev, bool can_stall); + +void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs); + +void fsg_common_remove_luns(struct fsg_common *common); + +void fsg_common_free_luns(struct fsg_common *common); + +int fsg_common_set_nluns(struct fsg_common *common, int nluns); + +void fsg_common_set_ops(struct fsg_common *common, +			const struct fsg_operations *ops); + +int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg, +			  unsigned int id, const char *name, +			  const char **name_pfx); + +int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg); + +void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn, +				   const char *pn); + +int fsg_common_run_thread(struct fsg_common *common); + +void fsg_config_from_params(struct fsg_config *cfg, +			    const struct fsg_module_parameters *params, +			    unsigned int fsg_num_buffers); + +#endif /* USB_F_MASS_STORAGE_H */ diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c index 263e721c269..807b31c0edc 100644 --- a/drivers/usb/gadget/f_midi.c +++ b/drivers/usb/gadget/f_midi.c @@ -32,6 +32,8 @@  #include <linux/usb/audio.h>  #include <linux/usb/midi.h> +#include "u_f.h" +  MODULE_AUTHOR("Ben Williamson");  MODULE_LICENSE("GPL v2"); @@ -191,20 +193,10 @@ static struct usb_gadget_strings *midi_strings[] = {  	NULL,  }; -static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) +static inline struct usb_request *midi_alloc_ep_req(struct usb_ep *ep, +						    unsigned length)  { -	struct usb_request *req; - -	req = usb_ep_alloc_request(ep, GFP_ATOMIC); -	if (req) { -		req->length = length; -		req->buf = kmalloc(length, GFP_ATOMIC); -		if (!req->buf) { -			usb_ep_free_request(ep, req); -			req = NULL; -		} -	} -	return req; +	return alloc_ep_req(ep, length, length);  }  static void free_ep_req(struct usb_ep *ep, struct usb_request *req) @@ -365,7 +357,7 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  	/* allocate a bunch of read buffers and queue them all at once. */  	for (i = 0; i < midi->qlen && err == 0; i++) {  		struct usb_request *req = -			alloc_ep_req(midi->out_ep, midi->buflen); +			midi_alloc_ep_req(midi->out_ep, midi->buflen);  		if (req == NULL)  			return -ENOMEM; @@ -546,7 +538,7 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)  		return;  	if (!req) -		req = alloc_ep_req(ep, midi->buflen); +		req = midi_alloc_ep_req(ep, midi->buflen);  	if (!req) {  		ERROR(midi, "gmidi_transmit: alloc_ep_request failed\n"); @@ -672,9 +664,10 @@ static int f_midi_register_card(struct f_midi *midi)  		.dev_free = f_midi_snd_free,  	}; -	err = snd_card_create(midi->index, midi->id, THIS_MODULE, 0, &card); +	err = snd_card_new(&midi->gadget->dev, midi->index, midi->id, +			   THIS_MODULE, 0, &card);  	if (err < 0) { -		ERROR(midi, "snd_card_create() failed\n"); +		ERROR(midi, "snd_card_new() failed\n");  		goto fail;  	}  	midi->card = card; @@ -711,8 +704,6 @@ static int f_midi_register_card(struct f_midi *midi)  	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops);  	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops); -	snd_card_set_dev(card, &midi->gadget->dev); -  	/* register it - we're ready to go */  	err = snd_card_register(card);  	if (err < 0) { diff --git a/drivers/usb/gadget/f_ncm.c b/drivers/usb/gadget/f_ncm.c index 1c28fe13328..a9499fd3079 100644 --- a/drivers/usb/gadget/f_ncm.c +++ b/drivers/usb/gadget/f_ncm.c @@ -1386,7 +1386,7 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f)  	usb_ep_free_request(ncm->notify, ncm->notify_req);  } -struct usb_function *ncm_alloc(struct usb_function_instance *fi) +static struct usb_function *ncm_alloc(struct usb_function_instance *fi)  {  	struct f_ncm		*ncm;  	struct f_ncm_opts	*opts; diff --git a/drivers/usb/gadget/f_obex.c b/drivers/usb/gadget/f_obex.c index ad39f1dacba..aebae1853bc 100644 --- a/drivers/usb/gadget/f_obex.c +++ b/drivers/usb/gadget/f_obex.c @@ -499,7 +499,7 @@ static void obex_unbind(struct usb_configuration *c, struct usb_function *f)  	usb_free_all_descriptors(f);  } -struct usb_function *obex_alloc(struct usb_function_instance *fi) +static struct usb_function *obex_alloc(struct usb_function_instance *fi)  {  	struct f_obex	*obex;  	struct f_serial_opts *opts; diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index eb3aa817a66..f2b781773ee 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -689,7 +689,7 @@ static void pn_unbind(struct usb_configuration *c, struct usb_function *f)  	usb_free_all_descriptors(f);  } -struct usb_function *phonet_alloc(struct usb_function_instance *fi) +static struct usb_function *phonet_alloc(struct usb_function_instance *fi)  {  	struct f_phonet *fp;  	struct f_phonet_opts *opts; diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 717ed7f9563..9c41e9515b8 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -27,6 +27,7 @@  #include "u_ether_configfs.h"  #include "u_rndis.h"  #include "rndis.h" +#include "configfs.h"  /*   * This function is an RNDIS Ethernet port -- a Microsoft protocol that's @@ -377,7 +378,7 @@ static struct sk_buff *rndis_add_header(struct gether *port,  	if (skb2)  		rndis_add_hdr(skb2); -	dev_kfree_skb_any(skb); +	dev_kfree_skb(skb);  	return skb2;  } @@ -675,7 +676,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  	int			status;  	struct usb_ep		*ep; -#ifndef USB_FRNDIS_INCLUDED  	struct f_rndis_opts *rndis_opts;  	if (!can_support_rndis(c)) @@ -683,6 +683,15 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  	rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst); +	if (cdev->use_os_string) { +		f->os_desc_table = kzalloc(sizeof(*f->os_desc_table), +					   GFP_KERNEL); +		if (!f->os_desc_table) +			return -ENOMEM; +		f->os_desc_n = 1; +		f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc; +	} +  	/*  	 * in drivers/usb/gadget/configfs.c:configfs_composite_bind()  	 * configurations are bound in sequence with list_for_each_entry, @@ -694,14 +703,16 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  		gether_set_gadget(rndis_opts->net, cdev->gadget);  		status = gether_register_netdev(rndis_opts->net);  		if (status) -			return status; +			goto fail;  		rndis_opts->bound = true;  	} -#endif +  	us = usb_gstrings_attach(cdev, rndis_strings,  				 ARRAY_SIZE(rndis_string_defs)); -	if (IS_ERR(us)) -		return PTR_ERR(us); +	if (IS_ERR(us)) { +		status = PTR_ERR(us); +		goto fail; +	}  	rndis_control_intf.iInterface = us[0].id;  	rndis_data_intf.iInterface = us[1].id;  	rndis_iad_descriptor.iFunction = us[2].id; @@ -782,13 +793,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  	rndis->port.open = rndis_open;  	rndis->port.close = rndis_close; -#ifdef USB_FRNDIS_INCLUDED -	status = rndis_register(rndis_response_available, rndis); -	if (status < 0) -		goto fail; -	rndis->config = status; -#endif -  	rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0);  	rndis_set_host_mac(rndis->config, rndis->ethaddr); @@ -810,6 +814,8 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  	return 0;  fail: +	kfree(f->os_desc_table); +	f->os_desc_n = 0;  	usb_free_all_descriptors(f);  	if (rndis->notify_req) { @@ -830,66 +836,6 @@ fail:  	return status;  } -#ifdef USB_FRNDIS_INCLUDED - -static void -rndis_old_unbind(struct usb_configuration *c, struct usb_function *f) -{ -	struct f_rndis		*rndis = func_to_rndis(f); - -	rndis_deregister(rndis->config); - -	usb_free_all_descriptors(f); - -	kfree(rndis->notify_req->buf); -	usb_ep_free_request(rndis->notify, rndis->notify_req); - -	kfree(rndis); -} - -int -rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		u32 vendorID, const char *manufacturer, struct eth_dev *dev) -{ -	struct f_rndis	*rndis; -	int		status; - -	/* allocate and initialize one new instance */ -	status = -ENOMEM; -	rndis = kzalloc(sizeof *rndis, GFP_KERNEL); -	if (!rndis) -		goto fail; - -	memcpy(rndis->ethaddr, ethaddr, ETH_ALEN); -	rndis->vendorID = vendorID; -	rndis->manufacturer = manufacturer; - -	rndis->port.ioport = dev; -	/* RNDIS activates when the host changes this filter */ -	rndis->port.cdc_filter = 0; - -	/* RNDIS has special (and complex) framing */ -	rndis->port.header_len = sizeof(struct rndis_packet_msg_type); -	rndis->port.wrap = rndis_add_header; -	rndis->port.unwrap = rndis_rm_hdr; - -	rndis->port.func.name = "rndis"; -	/* descriptors are per-instance copies */ -	rndis->port.func.bind = rndis_bind; -	rndis->port.func.unbind = rndis_old_unbind; -	rndis->port.func.set_alt = rndis_set_alt; -	rndis->port.func.setup = rndis_setup; -	rndis->port.func.disable = rndis_disable; - -	status = usb_add_function(c, &rndis->port.func); -	if (status) -		kfree(rndis); -fail: -	return status; -} - -#else -  void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)  {  	struct f_rndis_opts *opts; @@ -902,7 +848,7 @@ void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net)  	opts->borrowed_net = opts->bound = true;  	opts->net = net;  } -EXPORT_SYMBOL(rndis_borrow_net); +EXPORT_SYMBOL_GPL(rndis_borrow_net);  static inline struct f_rndis_opts *to_f_rndis_opts(struct config_item *item)  { @@ -950,16 +896,22 @@ static void rndis_free_inst(struct usb_function_instance *f)  		else  			free_netdev(opts->net);  	} + +	kfree(opts->rndis_os_desc.group.default_groups); /* single VLA chunk */  	kfree(opts);  }  static struct usb_function_instance *rndis_alloc_inst(void)  {  	struct f_rndis_opts *opts; +	struct usb_os_desc *descs[1]; +	char *names[1];  	opts = kzalloc(sizeof(*opts), GFP_KERNEL);  	if (!opts)  		return ERR_PTR(-ENOMEM); +	opts->rndis_os_desc.ext_compat_id = opts->rndis_ext_compat_id; +  	mutex_init(&opts->lock);  	opts->func_inst.free_func_inst = rndis_free_inst;  	opts->net = gether_setup_default(); @@ -968,7 +920,12 @@ static struct usb_function_instance *rndis_alloc_inst(void)  		kfree(opts);  		return ERR_CAST(net);  	} +	INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop); +	descs[0] = &opts->rndis_os_desc; +	names[0] = "rndis"; +	usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs, +				       names, THIS_MODULE);  	config_group_init_type_name(&opts->func_inst.group, "",  				    &rndis_func_type); @@ -993,6 +950,8 @@ static void rndis_unbind(struct usb_configuration *c, struct usb_function *f)  {  	struct f_rndis		*rndis = func_to_rndis(f); +	kfree(f->os_desc_table); +	f->os_desc_n = 0;  	usb_free_all_descriptors(f);  	kfree(rndis->notify_req->buf); @@ -1047,8 +1006,26 @@ static struct usb_function *rndis_alloc(struct usb_function_instance *fi)  	return &rndis->port.func;  } -DECLARE_USB_FUNCTION_INIT(rndis, rndis_alloc_inst, rndis_alloc); +DECLARE_USB_FUNCTION(rndis, rndis_alloc_inst, rndis_alloc); + +static int __init rndis_mod_init(void) +{ +	int ret; + +	ret = rndis_init(); +	if (ret) +		return ret; + +	return usb_function_register(&rndisusb_func); +} +module_init(rndis_mod_init); + +static void __exit rndis_mod_exit(void) +{ +	usb_function_unregister(&rndisusb_func); +	rndis_exit(); +} +module_exit(rndis_mod_exit); +  MODULE_LICENSE("GPL");  MODULE_AUTHOR("David Brownell"); - -#endif diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c index 981113c9924..9ecbcbf36a4 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -354,7 +354,7 @@ static void gser_unbind(struct usb_configuration *c, struct usb_function *f)  	usb_free_all_descriptors(f);  } -struct usb_function *gser_alloc(struct usb_function_instance *fi) +static struct usb_function *gser_alloc(struct usb_function_instance *fi)  {  	struct f_gser	*gser;  	struct f_serial_opts *opts; diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index a8895859a22..d3cd52db78f 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -21,6 +21,7 @@  #include "g_zero.h"  #include "gadget_chips.h" +#include "u_f.h"  /*   * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripheral @@ -201,7 +202,7 @@ static struct usb_endpoint_descriptor ss_source_desc = {  	.wMaxPacketSize =	cpu_to_le16(1024),  }; -struct usb_ss_ep_comp_descriptor ss_source_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_source_comp_desc = {  	.bLength =		USB_DT_SS_EP_COMP_SIZE,  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, @@ -218,7 +219,7 @@ static struct usb_endpoint_descriptor ss_sink_desc = {  	.wMaxPacketSize =	cpu_to_le16(1024),  }; -struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = {  	.bLength =		USB_DT_SS_EP_COMP_SIZE,  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, @@ -236,7 +237,7 @@ static struct usb_endpoint_descriptor ss_iso_source_desc = {  	.bInterval =		4,  }; -struct usb_ss_ep_comp_descriptor ss_iso_source_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_iso_source_comp_desc = {  	.bLength =		USB_DT_SS_EP_COMP_SIZE,  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, @@ -254,7 +255,7 @@ static struct usb_endpoint_descriptor ss_iso_sink_desc = {  	.bInterval =		4,  }; -struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = { +static struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = {  	.bLength =		USB_DT_SS_EP_COMP_SIZE,  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP, @@ -301,23 +302,9 @@ static struct usb_gadget_strings *sourcesink_strings[] = {  /*-------------------------------------------------------------------------*/ -struct usb_request *alloc_ep_req(struct usb_ep *ep, int len) +static inline struct usb_request *ss_alloc_ep_req(struct usb_ep *ep, int len)  { -	struct usb_request      *req; - -	req = usb_ep_alloc_request(ep, GFP_ATOMIC); -	if (req) { -		if (len) -			req->length = len; -		else -			req->length = buflen; -		req->buf = kmalloc(req->length, GFP_ATOMIC); -		if (!req->buf) { -			usb_ep_free_request(ep, req); -			req = NULL; -		} -	} -	return req; +	return alloc_ep_req(ep, len, buflen);  }  void free_ep_req(struct usb_ep *ep, struct usb_request *req) @@ -490,6 +477,14 @@ no_iso:  static void  sourcesink_free_func(struct usb_function *f)  { +	struct f_ss_opts *opts; + +	opts = container_of(f->fi, struct f_ss_opts, func_inst); + +	mutex_lock(&opts->lock); +	opts->refcnt--; +	mutex_unlock(&opts->lock); +  	usb_free_all_descriptors(f);  	kfree(func_to_ss(f));  } @@ -628,10 +623,10 @@ static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in,  				break;  			}  			ep = is_in ? ss->iso_in_ep : ss->iso_out_ep; -			req = alloc_ep_req(ep, size); +			req = ss_alloc_ep_req(ep, size);  		} else {  			ep = is_in ? ss->in_ep : ss->out_ep; -			req = alloc_ep_req(ep, 0); +			req = ss_alloc_ep_req(ep, 0);  		}  		if (!req) @@ -878,6 +873,11 @@ static struct usb_function *source_sink_alloc_func(  		return NULL;  	ss_opts =  container_of(fi, struct f_ss_opts, func_inst); + +	mutex_lock(&ss_opts->lock); +	ss_opts->refcnt++; +	mutex_unlock(&ss_opts->lock); +  	pattern = ss_opts->pattern;  	isoc_interval = ss_opts->isoc_interval;  	isoc_maxpacket = ss_opts->isoc_maxpacket; @@ -898,6 +898,303 @@ static struct usb_function *source_sink_alloc_func(  	return &ss->function;  } +static inline struct f_ss_opts *to_f_ss_opts(struct config_item *item) +{ +	return container_of(to_config_group(item), struct f_ss_opts, +			    func_inst.group); +} + +CONFIGFS_ATTR_STRUCT(f_ss_opts); +CONFIGFS_ATTR_OPS(f_ss_opts); + +static void ss_attr_release(struct config_item *item) +{ +	struct f_ss_opts *ss_opts = to_f_ss_opts(item); + +	usb_put_function_instance(&ss_opts->func_inst); +} + +static struct configfs_item_operations ss_item_ops = { +	.release		= ss_attr_release, +	.show_attribute		= f_ss_opts_attr_show, +	.store_attribute	= f_ss_opts_attr_store, +}; + +static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->pattern); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_ss_opts_pattern_store(struct f_ss_opts *opts, +				       const char *page, size_t len) +{ +	int ret; +	u8 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou8(page, 0, &num); +	if (ret) +		goto end; + +	if (num != 0 && num != 1 && num != 2) { +		ret = -EINVAL; +		goto end; +	} + +	opts->pattern = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_pattern = +	__CONFIGFS_ATTR(pattern, S_IRUGO | S_IWUSR, +			f_ss_opts_pattern_show, +			f_ss_opts_pattern_store); + +static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->isoc_interval); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_ss_opts_isoc_interval_store(struct f_ss_opts *opts, +				       const char *page, size_t len) +{ +	int ret; +	u8 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou8(page, 0, &num); +	if (ret) +		goto end; + +	if (num > 16) { +		ret = -EINVAL; +		goto end; +	} + +	opts->isoc_interval = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_isoc_interval = +	__CONFIGFS_ATTR(isoc_interval, S_IRUGO | S_IWUSR, +			f_ss_opts_isoc_interval_show, +			f_ss_opts_isoc_interval_store); + +static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->isoc_maxpacket); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_ss_opts_isoc_maxpacket_store(struct f_ss_opts *opts, +				       const char *page, size_t len) +{ +	int ret; +	u16 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou16(page, 0, &num); +	if (ret) +		goto end; + +	if (num > 1024) { +		ret = -EINVAL; +		goto end; +	} + +	opts->isoc_maxpacket = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_isoc_maxpacket = +	__CONFIGFS_ATTR(isoc_maxpacket, S_IRUGO | S_IWUSR, +			f_ss_opts_isoc_maxpacket_show, +			f_ss_opts_isoc_maxpacket_store); + +static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->isoc_mult); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_ss_opts_isoc_mult_store(struct f_ss_opts *opts, +				       const char *page, size_t len) +{ +	int ret; +	u8 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou8(page, 0, &num); +	if (ret) +		goto end; + +	if (num > 2) { +		ret = -EINVAL; +		goto end; +	} + +	opts->isoc_mult = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_isoc_mult = +	__CONFIGFS_ATTR(isoc_mult, S_IRUGO | S_IWUSR, +			f_ss_opts_isoc_mult_show, +			f_ss_opts_isoc_mult_store); + +static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->isoc_maxburst); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_ss_opts_isoc_maxburst_store(struct f_ss_opts *opts, +				       const char *page, size_t len) +{ +	int ret; +	u8 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou8(page, 0, &num); +	if (ret) +		goto end; + +	if (num > 15) { +		ret = -EINVAL; +		goto end; +	} + +	opts->isoc_maxburst = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_isoc_maxburst = +	__CONFIGFS_ATTR(isoc_maxburst, S_IRUGO | S_IWUSR, +			f_ss_opts_isoc_maxburst_show, +			f_ss_opts_isoc_maxburst_store); + +static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page) +{ +	int result; + +	mutex_lock(&opts->lock); +	result = sprintf(page, "%d", opts->bulk_buflen); +	mutex_unlock(&opts->lock); + +	return result; +} + +static ssize_t f_ss_opts_bulk_buflen_store(struct f_ss_opts *opts, +					   const char *page, size_t len) +{ +	int ret; +	u32 num; + +	mutex_lock(&opts->lock); +	if (opts->refcnt) { +		ret = -EBUSY; +		goto end; +	} + +	ret = kstrtou32(page, 0, &num); +	if (ret) +		goto end; + +	opts->bulk_buflen = num; +	ret = len; +end: +	mutex_unlock(&opts->lock); +	return ret; +} + +static struct f_ss_opts_attribute f_ss_opts_bulk_buflen = +	__CONFIGFS_ATTR(buflen, S_IRUGO | S_IWUSR, +			f_ss_opts_bulk_buflen_show, +			f_ss_opts_bulk_buflen_store); + +static struct configfs_attribute *ss_attrs[] = { +	&f_ss_opts_pattern.attr, +	&f_ss_opts_isoc_interval.attr, +	&f_ss_opts_isoc_maxpacket.attr, +	&f_ss_opts_isoc_mult.attr, +	&f_ss_opts_isoc_maxburst.attr, +	&f_ss_opts_bulk_buflen.attr, +	NULL, +}; + +static struct config_item_type ss_func_type = { +	.ct_item_ops    = &ss_item_ops, +	.ct_attrs	= ss_attrs, +	.ct_owner       = THIS_MODULE, +}; +  static void source_sink_free_instance(struct usb_function_instance *fi)  {  	struct f_ss_opts *ss_opts; @@ -913,7 +1210,15 @@ static struct usb_function_instance *source_sink_alloc_inst(void)  	ss_opts = kzalloc(sizeof(*ss_opts), GFP_KERNEL);  	if (!ss_opts)  		return ERR_PTR(-ENOMEM); +	mutex_init(&ss_opts->lock);  	ss_opts->func_inst.free_func_inst = source_sink_free_instance; +	ss_opts->isoc_interval = GZERO_ISOC_INTERVAL; +	ss_opts->isoc_maxpacket = GZERO_ISOC_MAXPACKET; +	ss_opts->bulk_buflen = GZERO_BULK_BUFLEN; + +	config_group_init_type_name(&ss_opts->func_inst.group, "", +				    &ss_func_type); +  	return &ss_opts->func_inst;  }  DECLARE_USB_FUNCTION(SourceSink, source_sink_alloc_inst, diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c index 7c8674fa7e8..1ea8baf3333 100644 --- a/drivers/usb/gadget/f_subset.c +++ b/drivers/usb/gadget/f_subset.c @@ -276,7 +276,7 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  	}  	net = gether_connect(&geth->port); -	return IS_ERR(net) ? PTR_ERR(net) : 0; +	return PTR_ERR_OR_ZERO(net);  }  static void geth_disable(struct usb_function *f) @@ -301,7 +301,6 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)  	int			status;  	struct usb_ep		*ep; -#ifndef USB_FSUBSET_INCLUDED  	struct f_gether_opts	*gether_opts;  	gether_opts = container_of(f->fi, struct f_gether_opts, func_inst); @@ -322,7 +321,7 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)  			return status;  		gether_opts->bound = true;  	} -#endif +  	us = usb_gstrings_attach(cdev, geth_strings,  				 ARRAY_SIZE(geth_string_defs));  	if (IS_ERR(us)) @@ -393,61 +392,6 @@ fail:  	return status;  } -#ifdef USB_FSUBSET_INCLUDED - -static void -geth_old_unbind(struct usb_configuration *c, struct usb_function *f) -{ -	geth_string_defs[0].id = 0; -	usb_free_all_descriptors(f); -	kfree(func_to_geth(f)); -} - -/** - * geth_bind_config - add CDC Subset network link to a configuration - * @c: the configuration to support the network link - * @ethaddr: a buffer in which the ethernet address of the host side - *	side of the link was recorded - * @dev: eth_dev structure - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup().  Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ -int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		struct eth_dev *dev) -{ -	struct f_gether	*geth; -	int		status; - -	/* allocate and initialize one new instance */ -	geth = kzalloc(sizeof *geth, GFP_KERNEL); -	if (!geth) -		return -ENOMEM; - -	/* export host's Ethernet address in CDC format */ -	snprintf(geth->ethaddr, sizeof geth->ethaddr, "%pm", ethaddr); -	geth_string_defs[1].s = geth->ethaddr; - -	geth->port.ioport = dev; -	geth->port.cdc_filter = DEFAULT_FILTER; - -	geth->port.func.name = "cdc_subset"; -	geth->port.func.bind = geth_bind; -	geth->port.func.unbind = geth_old_unbind; -	geth->port.func.set_alt = geth_set_alt; -	geth->port.func.disable = geth_disable; - -	status = usb_add_function(c, &geth->port.func); -	if (status) -		kfree(geth); -	return status; -} - -#else -  static inline struct f_gether_opts *to_f_gether_opts(struct config_item *item)  {  	return container_of(to_config_group(item), struct f_gether_opts, @@ -573,5 +517,3 @@ static struct usb_function *geth_alloc(struct usb_function_instance *fi)  DECLARE_USB_FUNCTION_INIT(geth, geth_alloc_inst, geth_alloc);  MODULE_LICENSE("GPL");  MODULE_AUTHOR("David Brownell"); - -#endif diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c index 2f23566e53d..6261db4a991 100644 --- a/drivers/usb/gadget/f_uac2.c +++ b/drivers/usb/gadget/f_uac2.c @@ -196,7 +196,7 @@ agdev_iso_complete(struct usb_ep *ep, struct usb_request *req)  	struct snd_uac2_chip *uac2 = prm->uac2;  	/* i/f shutting down */ -	if (!prm->ep_enabled) +	if (!prm->ep_enabled || req->status == -ESHUTDOWN)  		return;  	/* @@ -394,7 +394,7 @@ static int snd_uac2_probe(struct platform_device *pdev)  	int err;  	/* Choose any slot, with no id */ -	err = snd_card_create(-1, NULL, THIS_MODULE, 0, &card); +	err = snd_card_new(&pdev->dev, -1, NULL, THIS_MODULE, 0, &card);  	if (err < 0)  		return err; @@ -421,8 +421,6 @@ static int snd_uac2_probe(struct platform_device *pdev)  	strcpy(card->shortname, "UAC2_Gadget");  	sprintf(card->longname, "UAC2_Gadget %i", pdev->id); -	snd_card_set_dev(card, &pdev->dev); -  	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,  		snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX); @@ -976,8 +974,6 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)  	prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);  	if (!prm->rbuf) {  		prm->max_psize = 0; -		dev_err(&uac2->pdev.dev, -			"%s:%d Error!\n", __func__, __LINE__);  		goto err;  	} @@ -986,8 +982,6 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)  	prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);  	if (!prm->rbuf) {  		prm->max_psize = 0; -		dev_err(&uac2->pdev.dev, -			"%s:%d Error!\n", __func__, __LINE__);  		goto err;  	} @@ -1300,10 +1294,8 @@ static int audio_bind_config(struct usb_configuration *cfg)  	int res;  	agdev_g = kzalloc(sizeof *agdev_g, GFP_KERNEL); -	if (agdev_g == NULL) { -		printk(KERN_ERR "Unable to allocate audio gadget\n"); +	if (agdev_g == NULL)  		return -ENOMEM; -	}  	res = usb_string_ids_tab(cfg->cdev, strings_fn);  	if (res) diff --git a/drivers/usb/gadget/fotg210-udc.c b/drivers/usb/gadget/fotg210-udc.c index 32db2eee2d8..e143d69f601 100644 --- a/drivers/usb/gadget/fotg210-udc.c +++ b/drivers/usb/gadget/fotg210-udc.c @@ -1112,17 +1112,13 @@ static int fotg210_udc_probe(struct platform_device *pdev)  	/* initialize udc */  	fotg210 = kzalloc(sizeof(struct fotg210_udc), GFP_KERNEL); -	if (fotg210 == NULL) { -		pr_err("kzalloc error\n"); +	if (fotg210 == NULL)  		goto err_alloc; -	}  	for (i = 0; i < FOTG210_MAX_NUM_EP; i++) {  		_ep[i] = kzalloc(sizeof(struct fotg210_ep), GFP_KERNEL); -		if (_ep[i] == NULL) { -			pr_err("_ep kzalloc error\n"); +		if (_ep[i] == NULL)  			goto err_alloc; -		}  		fotg210->ep[i] = _ep[i];  	} @@ -1157,8 +1153,9 @@ static int fotg210_udc_probe(struct platform_device *pdev)  		INIT_LIST_HEAD(&ep->queue);  		ep->ep.name = fotg210_ep_name[i];  		ep->ep.ops = &fotg210_ep_ops; +		usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);  	} -	fotg210->ep[0]->ep.maxpacket = 0x40; +	usb_ep_set_maxpacket_limit(&fotg210->ep[0]->ep, 0x40);  	fotg210->gadget.ep0 = &fotg210->ep[0]->ep;  	INIT_LIST_HEAD(&fotg210->gadget.ep0->ep_list); @@ -1214,6 +1211,6 @@ static struct platform_driver fotg210_driver = {  module_platform_driver(fotg210_driver); -MODULE_AUTHOR("Yuan-Hsin Chen <yhchen@faraday-tech.com>"); +MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>");  MODULE_LICENSE("GPL");  MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index f3bb363f1d4..ad548333516 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -22,7 +22,6 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/ioport.h>  #include <linux/types.h>  #include <linux/errno.h> @@ -33,6 +32,7 @@  #include <linux/io.h>  #include <linux/moduleparam.h>  #include <linux/of_address.h> +#include <linux/of_irq.h>  #include <linux/of_platform.h>  #include <linux/dma-mapping.h>  #include <linux/usb/ch9.h> @@ -2428,7 +2428,7 @@ static int qe_ep_config(struct qe_udc *udc, unsigned char pipe_num)  	ep->ep.ops = &qe_ep_ops;  	ep->stopped = 1; -	ep->ep.maxpacket = (unsigned short) ~0; +	usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);  	ep->ep.desc = NULL;  	ep->dir = 0xff;  	ep->epnum = (u8)pipe_num; @@ -2716,7 +2716,7 @@ MODULE_DEVICE_TABLE(of, qe_udc_match);  static struct platform_driver udc_driver = {  	.driver = { -		.name = (char *)driver_name, +		.name = driver_name,  		.owner = THIS_MODULE,  		.of_match_table = qe_udc_match,  	}, diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 36ac7cfba91..28e4fc95702 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1219,6 +1219,10 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)  	struct fsl_udc *udc;  	udc = container_of(gadget, struct fsl_udc, gadget); + +	if (!udc->vbus_active) +		return -EOPNOTSUPP; +  	udc->softconnect = (is_on != 0);  	if (can_pullup(udc))  		fsl_writel((fsl_readl(&dr_regs->usbcmd) | USB_CMD_RUN_STOP), @@ -2252,10 +2256,8 @@ static int __init struct_udc_setup(struct fsl_udc *udc,  	udc->phy_mode = pdata->phy_mode;  	udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL); -	if (!udc->eps) { -		ERR("malloc fsl_ep failed\n"); +	if (!udc->eps)  		return -1; -	}  	/* initialized QHs, take care of alignment */  	size = udc->max_ep * sizeof(struct ep_queue_head); @@ -2311,7 +2313,7 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,  	/* for ep0: maxP defined in desc  	 * for other eps, maxP is set by epautoconfig() called by gadget layer  	 */ -	ep->ep.maxpacket = (unsigned short) ~0; +	usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);  	/* the queue lists any req for this ep */  	INIT_LIST_HEAD(&ep->queue); @@ -2338,10 +2340,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev)  	u32 dccparams;  	udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL); -	if (udc_controller == NULL) { -		ERR("malloc udc failed\n"); +	if (udc_controller == NULL)  		return -ENOMEM; -	}  	pdata = dev_get_platdata(&pdev->dev);  	udc_controller->pdata = pdata; @@ -2469,7 +2469,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev)  	 * for other eps, gadget layer called ep_enable with defined desc  	 */  	udc_controller->eps[0].ep.desc = &fsl_ep0_desc; -	udc_controller->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD; +	usb_ep_set_maxpacket_limit(&udc_controller->eps[0].ep, +				   USB_MAX_CTRL_PAYLOAD);  	/* setup the udc->eps[] for non-control endpoints and link  	 * to gadget.ep_list */ @@ -2531,8 +2532,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)  	if (!udc_controller)  		return -ENODEV; -	usb_del_gadget_udc(&udc_controller->gadget);  	udc_controller->done = &done; +	usb_del_gadget_udc(&udc_controller->gadget);  	fsl_udc_clk_release(); @@ -2666,7 +2667,7 @@ static struct platform_driver udc_driver = {  	.suspend	= fsl_udc_suspend,  	.resume		= fsl_udc_resume,  	.driver		= { -			.name = (char *)driver_name, +			.name = driver_name,  			.owner = THIS_MODULE,  			/* udc suspend/resume called from OTG driver */  			.suspend = fsl_udc_otg_suspend, diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index f1dd6daabe2..3deb4e93807 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -22,7 +22,7 @@  MODULE_DESCRIPTION("FUSB300  USB gadget driver");  MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Yuan Hsin Chen <yhchen@faraday-tech.com>"); +MODULE_AUTHOR("Yuan-Hsin Chen, Feng-Hsin Chiang <john453@faraday-tech.com>");  MODULE_ALIAS("platform:fusb300_udc");  #define DRIVER_VERSION	"20 October 2010" @@ -1400,17 +1400,13 @@ static int __init fusb300_probe(struct platform_device *pdev)  	/* initialize udc */  	fusb300 = kzalloc(sizeof(struct fusb300), GFP_KERNEL); -	if (fusb300 == NULL) { -		pr_err("kzalloc error\n"); +	if (fusb300 == NULL)  		goto clean_up; -	}  	for (i = 0; i < FUSB300_MAX_NUM_EP; i++) {  		_ep[i] = kzalloc(sizeof(struct fusb300_ep), GFP_KERNEL); -		if (_ep[i] == NULL) { -			pr_err("_ep kzalloc error\n"); +		if (_ep[i] == NULL)  			goto clean_up; -		}  		fusb300->ep[i] = _ep[i];  	} @@ -1452,9 +1448,9 @@ static int __init fusb300_probe(struct platform_device *pdev)  		INIT_LIST_HEAD(&ep->queue);  		ep->ep.name = fusb300_ep_name[i];  		ep->ep.ops = &fusb300_ep_ops; -		ep->ep.maxpacket = HS_BULK_MAX_PACKET_SIZE; +		usb_ep_set_maxpacket_limit(&ep->ep, HS_BULK_MAX_PACKET_SIZE);  	} -	fusb300->ep[0]->ep.maxpacket = HS_CTL_MAX_PACKET_SIZE; +	usb_ep_set_maxpacket_limit(&fusb300->ep[0]->ep, HS_CTL_MAX_PACKET_SIZE);  	fusb300->ep[0]->epnum = 0;  	fusb300->gadget.ep0 = &fusb300->ep[0]->ep;  	INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list); diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index 5327c82472e..fe12e6a2744 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -13,14 +13,10 @@  #define pr_fmt(fmt) "g_ffs: " fmt  #include <linux/module.h> -/* - * kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module.  So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ +  #if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS +#include <linux/netdevice.h> +  #  if defined USB_ETH_RNDIS  #    undef USB_ETH_RNDIS  #  endif @@ -28,31 +24,31 @@  #    define USB_ETH_RNDIS y  #  endif -#define USBF_ECM_INCLUDED -#  include "f_ecm.c" -#define USB_FSUBSET_INCLUDED -#  include "f_subset.c" +#  include "u_ecm.h" +#  include "u_gether.h"  #  ifdef USB_ETH_RNDIS -#    define USB_FRNDIS_INCLUDED -#    include "f_rndis.c" +#    include "u_rndis.h"  #    include "rndis.h"  #  endif  #  include "u_ether.h" -static u8 gfs_host_mac[ETH_ALEN]; -static struct eth_dev *the_dev; +USB_ETHERNET_MODULE_PARAMETERS(); +  #  ifdef CONFIG_USB_FUNCTIONFS_ETH -static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		struct eth_dev *dev); +static int eth_bind_config(struct usb_configuration *c); +static struct usb_function_instance *fi_ecm; +static struct usb_function *f_ecm; +static struct usb_function_instance *fi_geth; +static struct usb_function *f_geth; +#  endif +#  ifdef CONFIG_USB_FUNCTIONFS_RNDIS +static int bind_rndis_config(struct usb_configuration *c); +static struct usb_function_instance *fi_rndis; +static struct usb_function *f_rndis;  #  endif -#else -#  define the_dev	NULL -#  define gether_cleanup(dev) do { } while (0) -#  define gfs_host_mac NULL -struct eth_dev;  #endif -#include "f_fs.c" +#include "u_fs.h"  #define DRIVER_NAME	"g_ffs"  #define DRIVER_DESC	"USB Function Filesystem" @@ -67,17 +63,8 @@ MODULE_LICENSE("GPL");  #define GFS_MAX_DEVS	10 -struct gfs_ffs_obj { -	const char *name; -	bool mounted; -	bool desc_ready; -	struct ffs_data *ffs_data; -}; -  USB_GADGET_COMPOSITE_OPTIONS(); -USB_ETHERNET_MODULE_PARAMETERS(); -  static struct usb_device_descriptor gfs_dev_desc = {  	.bLength		= sizeof gfs_dev_desc,  	.bDescriptorType	= USB_DT_DEVICE, @@ -144,12 +131,12 @@ static struct usb_gadget_strings *gfs_dev_strings[] = {  struct gfs_configuration {  	struct usb_configuration c; -	int (*eth)(struct usb_configuration *c, u8 *ethaddr, -			struct eth_dev *dev); +	int (*eth)(struct usb_configuration *c); +	int num;  } gfs_configurations[] = {  #ifdef CONFIG_USB_FUNCTIONFS_RNDIS  	{ -		.eth		= rndis_bind_config, +		.eth		= bind_rndis_config,  	},  #endif @@ -165,10 +152,15 @@ struct gfs_configuration {  #endif  }; +static void *functionfs_acquire_dev(struct ffs_dev *dev); +static void functionfs_release_dev(struct ffs_dev *dev); +static int functionfs_ready_callback(struct ffs_data *ffs); +static void functionfs_closed_callback(struct ffs_data *ffs);  static int gfs_bind(struct usb_composite_dev *cdev);  static int gfs_unbind(struct usb_composite_dev *cdev);  static int gfs_do_config(struct usb_configuration *c); +  static __refdata struct usb_composite_driver gfs_driver = {  	.name		= DRIVER_NAME,  	.dev		= &gfs_dev_desc, @@ -178,206 +170,244 @@ static __refdata struct usb_composite_driver gfs_driver = {  	.unbind		= gfs_unbind,  }; -static DEFINE_MUTEX(gfs_lock);  static unsigned int missing_funcs; -static bool gfs_ether_setup;  static bool gfs_registered;  static bool gfs_single_func; -static struct gfs_ffs_obj *ffs_tab; +static struct usb_function_instance **fi_ffs; +static struct usb_function **f_ffs[] = { +#ifdef CONFIG_USB_FUNCTIONFS_RNDIS +	NULL, +#endif + +#ifdef CONFIG_USB_FUNCTIONFS_ETH +	NULL, +#endif + +#ifdef CONFIG_USB_FUNCTIONFS_GENERIC +	NULL, +#endif +}; + +#define N_CONF ARRAY_SIZE(f_ffs)  static int __init gfs_init(void)  { +	struct f_fs_opts *opts;  	int i; +	int ret = 0;  	ENTER(); -	if (!func_num) { +	if (func_num < 2) {  		gfs_single_func = true;  		func_num = 1;  	} -	ffs_tab = kcalloc(func_num, sizeof *ffs_tab, GFP_KERNEL); -	if (!ffs_tab) -		return -ENOMEM; +	/* +	 * Allocate in one chunk for easier maintenance +	 */ +	f_ffs[0] = kcalloc(func_num * N_CONF, sizeof(*f_ffs), GFP_KERNEL); +	if (!f_ffs[0]) { +		ret = -ENOMEM; +		goto no_func; +	} +	for (i = 1; i < N_CONF; ++i) +		f_ffs[i] = f_ffs[0] + i * func_num; + +	fi_ffs = kcalloc(func_num, sizeof(*fi_ffs), GFP_KERNEL); +	if (!fi_ffs) { +		ret = -ENOMEM; +		goto no_func; +	} -	if (!gfs_single_func) -		for (i = 0; i < func_num; i++) -			ffs_tab[i].name = func_names[i]; +	for (i = 0; i < func_num; i++) { +		fi_ffs[i] = usb_get_function_instance("ffs"); +		if (IS_ERR(fi_ffs[i])) { +			ret = PTR_ERR(fi_ffs[i]); +			--i; +			goto no_dev; +		} +		opts = to_f_fs_opts(fi_ffs[i]); +		if (gfs_single_func) +			ret = ffs_single_dev(opts->dev); +		else +			ret = ffs_name_dev(opts->dev, func_names[i]); +		if (ret) +			goto no_dev; +		opts->dev->ffs_ready_callback = functionfs_ready_callback; +		opts->dev->ffs_closed_callback = functionfs_closed_callback; +		opts->dev->ffs_acquire_dev_callback = functionfs_acquire_dev; +		opts->dev->ffs_release_dev_callback = functionfs_release_dev; +		opts->no_configfs = true; +	}  	missing_funcs = func_num; -	return functionfs_init(); +	return 0; +no_dev: +	while (i >= 0) +		usb_put_function_instance(fi_ffs[i--]); +	kfree(fi_ffs); +no_func: +	kfree(f_ffs[0]); +	return ret;  }  module_init(gfs_init);  static void __exit gfs_exit(void)  { +	int i; +  	ENTER(); -	mutex_lock(&gfs_lock);  	if (gfs_registered)  		usb_composite_unregister(&gfs_driver);  	gfs_registered = false; -	functionfs_cleanup(); +	kfree(f_ffs[0]); -	mutex_unlock(&gfs_lock); -	kfree(ffs_tab); +	for (i = 0; i < func_num; i++) +		usb_put_function_instance(fi_ffs[i]); + +	kfree(fi_ffs);  }  module_exit(gfs_exit); -static struct gfs_ffs_obj *gfs_find_dev(const char *dev_name) +static void *functionfs_acquire_dev(struct ffs_dev *dev)  { -	int i; - -	ENTER(); - -	if (gfs_single_func) -		return &ffs_tab[0]; - -	for (i = 0; i < func_num; i++) -		if (strcmp(ffs_tab[i].name, dev_name) == 0) -			return &ffs_tab[i]; +	if (!try_module_get(THIS_MODULE)) +		return ERR_PTR(-ENODEV); +	 +	return 0; +} -	return NULL; +static void functionfs_release_dev(struct ffs_dev *dev) +{ +	module_put(THIS_MODULE);  } +/* + * The caller of this function takes ffs_lock  + */  static int functionfs_ready_callback(struct ffs_data *ffs)  { -	struct gfs_ffs_obj *ffs_obj; -	int ret; - -	ENTER(); -	mutex_lock(&gfs_lock); +	int ret = 0; -	ffs_obj = ffs->private_data; -	if (!ffs_obj) { -		ret = -EINVAL; -		goto done; -	} - -	if (WARN_ON(ffs_obj->desc_ready)) { -		ret = -EBUSY; -		goto done; -	} -	ffs_obj->desc_ready = true; -	ffs_obj->ffs_data = ffs; +	if (--missing_funcs) +		return 0; -	if (--missing_funcs) { -		ret = 0; -		goto done; -	} +	if (gfs_registered) +		return -EBUSY; -	if (gfs_registered) { -		ret = -EBUSY; -		goto done; -	}  	gfs_registered = true;  	ret = usb_composite_probe(&gfs_driver);  	if (unlikely(ret < 0))  		gfs_registered = false; - -done: -	mutex_unlock(&gfs_lock); +	  	return ret;  } +/* + * The caller of this function takes ffs_lock  + */  static void functionfs_closed_callback(struct ffs_data *ffs)  { -	struct gfs_ffs_obj *ffs_obj; - -	ENTER(); -	mutex_lock(&gfs_lock); - -	ffs_obj = ffs->private_data; -	if (!ffs_obj) -		goto done; - -	ffs_obj->desc_ready = false;  	missing_funcs++;  	if (gfs_registered)  		usb_composite_unregister(&gfs_driver);  	gfs_registered = false; - -done: -	mutex_unlock(&gfs_lock);  } -static void *functionfs_acquire_dev_callback(const char *dev_name) +/* + * It is assumed that gfs_bind is called from a context where ffs_lock is held + */ +static int gfs_bind(struct usb_composite_dev *cdev)  { -	struct gfs_ffs_obj *ffs_dev; +#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS +	struct net_device *net; +#endif +	int ret, i;  	ENTER(); -	mutex_lock(&gfs_lock); -	ffs_dev = gfs_find_dev(dev_name); -	if (!ffs_dev) { -		ffs_dev = ERR_PTR(-ENODEV); -		goto done; -	} - -	if (ffs_dev->mounted) { -		ffs_dev = ERR_PTR(-EBUSY); -		goto done; +	if (missing_funcs) +		return -ENODEV; +#if defined CONFIG_USB_FUNCTIONFS_ETH +	if (can_support_ecm(cdev->gadget)) { +		struct f_ecm_opts *ecm_opts; + +		fi_ecm = usb_get_function_instance("ecm"); +		if (IS_ERR(fi_ecm)) +			return PTR_ERR(fi_ecm); +		ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); +		net = ecm_opts->net; +	} else { +		struct f_gether_opts *geth_opts; + +		fi_geth = usb_get_function_instance("geth"); +		if (IS_ERR(fi_geth)) +			return PTR_ERR(fi_geth); +		geth_opts = container_of(fi_geth, struct f_gether_opts, +					 func_inst); +		net = geth_opts->net;  	} -	ffs_dev->mounted = true; +#endif -done: -	mutex_unlock(&gfs_lock); -	return ffs_dev; -} +#ifdef CONFIG_USB_FUNCTIONFS_RNDIS +	{ +		struct f_rndis_opts *rndis_opts; -static void functionfs_release_dev_callback(struct ffs_data *ffs_data) -{ -	struct gfs_ffs_obj *ffs_dev; +		fi_rndis = usb_get_function_instance("rndis"); +		if (IS_ERR(fi_rndis)) { +			ret = PTR_ERR(fi_rndis); +			goto error; +		} +		rndis_opts = container_of(fi_rndis, struct f_rndis_opts, +					  func_inst); +#ifndef CONFIG_USB_FUNCTIONFS_ETH +		net = rndis_opts->net; +#endif +	} +#endif -	ENTER(); -	mutex_lock(&gfs_lock); +#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS +	gether_set_qmult(net, qmult); +	if (!gether_set_host_addr(net, host_addr)) +		pr_info("using host ethernet address: %s", host_addr); +	if (!gether_set_dev_addr(net, dev_addr)) +		pr_info("using self ethernet address: %s", dev_addr); +#endif -	ffs_dev = ffs_data->private_data; -	if (ffs_dev) -		ffs_dev->mounted = false; +#if defined CONFIG_USB_FUNCTIONFS_RNDIS && defined CONFIG_USB_FUNCTIONFS_ETH +	gether_set_gadget(net, cdev->gadget); +	ret = gether_register_netdev(net); +	if (ret) +		goto error_rndis; -	mutex_unlock(&gfs_lock); -} +	if (can_support_ecm(cdev->gadget)) { +		struct f_ecm_opts *ecm_opts; -/* - * It is assumed that gfs_bind is called from a context where gfs_lock is held - */ -static int gfs_bind(struct usb_composite_dev *cdev) -{ -	int ret, i; +		ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); +		ecm_opts->bound = true; +	} else { +		struct f_gether_opts *geth_opts; -	ENTER(); +		geth_opts = container_of(fi_geth, struct f_gether_opts, +					 func_inst); +		geth_opts->bound = true; +	} -	if (missing_funcs) -		return -ENODEV; -#if defined CONFIG_USB_FUNCTIONFS_ETH || defined CONFIG_USB_FUNCTIONFS_RNDIS -	the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, gfs_host_mac, -			       qmult); +	rndis_borrow_net(fi_rndis, net);  #endif -	if (IS_ERR(the_dev)) { -		ret = PTR_ERR(the_dev); -		goto error_quick; -	} -	gfs_ether_setup = true; +	/* TODO: gstrings_attach? */  	ret = usb_string_ids_tab(cdev, gfs_strings);  	if (unlikely(ret < 0)) -		goto error; +		goto error_rndis;  	gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id; -	for (i = func_num; i--; ) { -		ret = functionfs_bind(ffs_tab[i].ffs_data, cdev); -		if (unlikely(ret < 0)) { -			while (++i < func_num) -				functionfs_unbind(ffs_tab[i].ffs_data); -			goto error; -		} -	} -  	for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {  		struct gfs_configuration *c = gfs_configurations + i;  		int sid = USB_GADGET_FIRST_AVAIL_IDX + i; @@ -387,6 +417,8 @@ static int gfs_bind(struct usb_composite_dev *cdev)  		c->c.bConfigurationValue	= 1 + i;  		c->c.bmAttributes		= USB_CONFIG_ATT_SELFPOWER; +		c->num = i; +  		ret = usb_add_config(cdev, &c->c, gfs_do_config);  		if (unlikely(ret < 0))  			goto error_unbind; @@ -394,18 +426,24 @@ static int gfs_bind(struct usb_composite_dev *cdev)  	usb_composite_overwrite_options(cdev, &coverwrite);  	return 0; +/* TODO */  error_unbind: -	for (i = 0; i < func_num; i++) -		functionfs_unbind(ffs_tab[i].ffs_data); +error_rndis: +#ifdef CONFIG_USB_FUNCTIONFS_RNDIS +	usb_put_function_instance(fi_rndis);  error: -	gether_cleanup(the_dev); -error_quick: -	gfs_ether_setup = false; +#endif +#if defined CONFIG_USB_FUNCTIONFS_ETH +	if (can_support_ecm(cdev->gadget)) +		usb_put_function_instance(fi_ecm); +	else +		usb_put_function_instance(fi_geth); +#endif  	return ret;  }  /* - * It is assumed that gfs_unbind is called from a context where gfs_lock is held + * It is assumed that gfs_unbind is called from a context where ffs_lock is held   */  static int gfs_unbind(struct usb_composite_dev *cdev)  { @@ -413,28 +451,30 @@ static int gfs_unbind(struct usb_composite_dev *cdev)  	ENTER(); -	/* -	 * We may have been called in an error recovery from -	 * composite_bind() after gfs_unbind() failure so we need to -	 * check if gfs_ffs_data is not NULL since gfs_bind() handles -	 * all error recovery itself.  I'd rather we werent called -	 * from composite on orror recovery, but what you're gonna -	 * do...? -	 */ -	if (gfs_ether_setup) -		gether_cleanup(the_dev); -	gfs_ether_setup = false; -	for (i = func_num; i--; ) -		if (ffs_tab[i].ffs_data) -			functionfs_unbind(ffs_tab[i].ffs_data); +#ifdef CONFIG_USB_FUNCTIONFS_RNDIS +	usb_put_function(f_rndis); +	usb_put_function_instance(fi_rndis); +#endif + +#if defined CONFIG_USB_FUNCTIONFS_ETH +	if (can_support_ecm(cdev->gadget)) { +		usb_put_function(f_ecm); +		usb_put_function_instance(fi_ecm); +	} else { +		usb_put_function(f_geth); +		usb_put_function_instance(fi_geth); +	} +#endif +	for (i = 0; i < N_CONF * func_num; ++i) +		usb_put_function(*(f_ffs[0] + i));  	return 0;  }  /*   * It is assumed that gfs_do_config is called from a context where - * gfs_lock is held + * ffs_lock is held   */  static int gfs_do_config(struct usb_configuration *c)  { @@ -452,15 +492,22 @@ static int gfs_do_config(struct usb_configuration *c)  	}  	if (gc->eth) { -		ret = gc->eth(c, gfs_host_mac, the_dev); +		ret = gc->eth(c);  		if (unlikely(ret < 0))  			return ret;  	}  	for (i = 0; i < func_num; i++) { -		ret = functionfs_bind_config(c->cdev, c, ffs_tab[i].ffs_data); -		if (unlikely(ret < 0)) -			return ret; +		f_ffs[gc->num][i] = usb_get_function(fi_ffs[i]); +		if (IS_ERR(f_ffs[gc->num][i])) { +			ret = PTR_ERR(f_ffs[gc->num][i]); +			goto error; +		} +		ret = usb_add_function(c, f_ffs[gc->num][i]); +		if (ret < 0) { +			usb_put_function(f_ffs[gc->num][i]); +			goto error; +		}  	}  	/* @@ -477,16 +524,59 @@ static int gfs_do_config(struct usb_configuration *c)  		c->interface[c->next_interface_id] = NULL;  	return 0; +error: +	while (--i >= 0) { +		if (!IS_ERR(f_ffs[gc->num][i])) +			usb_remove_function(c, f_ffs[gc->num][i]); +		usb_put_function(f_ffs[gc->num][i]); +	} +	return ret;  }  #ifdef CONFIG_USB_FUNCTIONFS_ETH -static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		struct eth_dev *dev) +static int eth_bind_config(struct usb_configuration *c)  { -	return can_support_ecm(c->cdev->gadget) -		? ecm_bind_config(c, ethaddr, dev) -		: geth_bind_config(c, ethaddr, dev); +	int status = 0; + +	if (can_support_ecm(c->cdev->gadget)) { +		f_ecm = usb_get_function(fi_ecm); +		if (IS_ERR(f_ecm)) +			return PTR_ERR(f_ecm); + +		status = usb_add_function(c, f_ecm); +		if (status < 0) +			usb_put_function(f_ecm); + +	} else { +		f_geth = usb_get_function(fi_geth); +		if (IS_ERR(f_geth)) +			return PTR_ERR(f_geth); + +		status = usb_add_function(c, f_geth); +		if (status < 0) +			usb_put_function(f_geth); +	} +	return status; +} + +#endif + +#ifdef CONFIG_USB_FUNCTIONFS_RNDIS + +static int bind_rndis_config(struct usb_configuration *c) +{ +	int status = 0; + +	f_rndis = usb_get_function(fi_rndis); +	if (IS_ERR(f_rndis)) +		return PTR_ERR(f_rndis); + +	status = usb_add_function(c, f_rndis); +	if (status < 0) +		usb_put_function(f_rndis); + +	return status;  }  #endif diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/g_zero.h index ef3e8515272..15f180904f8 100644 --- a/drivers/usb/gadget/g_zero.h +++ b/drivers/usb/gadget/g_zero.h @@ -6,6 +6,11 @@  #ifndef __G_ZERO_H  #define __G_ZERO_H +#define GZERO_BULK_BUFLEN	4096 +#define GZERO_QLEN		32 +#define GZERO_ISOC_INTERVAL	4 +#define GZERO_ISOC_MAXPACKET	1024 +  struct usb_zero_options {  	unsigned pattern;  	unsigned isoc_interval; @@ -24,19 +29,36 @@ struct f_ss_opts {  	unsigned isoc_mult;  	unsigned isoc_maxburst;  	unsigned bulk_buflen; + +	/* +	 * Read/write access to configfs attributes is handled by configfs. +	 * +	 * This is to protect the data from concurrent access by read/write +	 * and create symlink/remove symlink. +	 */ +	struct mutex			lock; +	int				refcnt;  };  struct f_lb_opts {  	struct usb_function_instance func_inst;  	unsigned bulk_buflen;  	unsigned qlen; + +	/* +	 * Read/write access to configfs attributes is handled by configfs. +	 * +	 * This is to protect the data from concurrent access by read/write +	 * and create symlink/remove symlink. +	 */ +	struct mutex			lock; +	int				refcnt;  };  void lb_modexit(void);  int lb_modinit(void);  /* common utilities */ -struct usb_request *alloc_ep_req(struct usb_ep *ep, int len);  void free_ep_req(struct usb_ep *ep, struct usb_request *req);  void disable_endpoints(struct usb_composite_dev *cdev,  		struct usb_ep *in, struct usb_ep *out, diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index c64deb9e3d6..6c85839e15a 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -30,7 +30,6 @@  #include <linux/ioport.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/interrupt.h> @@ -231,7 +230,7 @@ static void ep_reset(struct goku_udc_regs __iomem *regs, struct goku_ep *ep)  		}  	} -	ep->ep.maxpacket = MAX_FIFO_SIZE; +	usb_ep_set_maxpacket_limit(&ep->ep, MAX_FIFO_SIZE);  	ep->ep.desc = NULL;  	ep->stopped = 1;  	ep->irqs = 0; @@ -1165,7 +1164,7 @@ static int udc_proc_read(struct seq_file *m, void *v)  				s = "invalid"; break;  			default:  				s = "?"; break; -			}; s; }), +			} s; }),  			(tmp & EPxSTATUS_TOGGLE) ? "data1" : "data0",  			(tmp & EPxSTATUS_SUSPEND) ? " suspend" : "",  			(tmp & EPxSTATUS_FIFO_DISABLE) ? " disable" : "", @@ -1251,7 +1250,7 @@ static void udc_reinit (struct goku_udc *dev)  	}  	dev->ep[0].reg_mode = NULL; -	dev->ep[0].ep.maxpacket = MAX_EP0_SIZE; +	usb_ep_set_maxpacket_limit(&dev->ep[0].ep, MAX_EP0_SIZE);  	list_del_init (&dev->ep[0].ep.ep_list);  } @@ -1350,16 +1349,12 @@ static int goku_udc_start(struct usb_gadget *g,  	return 0;  } -static void -stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver) +static void stop_activity(struct goku_udc *dev)  {  	unsigned	i;  	DBG (dev, "%s\n", __func__); -	if (dev->gadget.speed == USB_SPEED_UNKNOWN) -		driver = NULL; -  	/* disconnect gadget driver after quiesceing hw and the driver */  	udc_reset (dev);  	for (i = 0; i < 4; i++) @@ -1377,7 +1372,7 @@ static int goku_udc_stop(struct usb_gadget *g,  	spin_lock_irqsave(&dev->lock, flags);  	dev->driver = NULL; -	stop_activity(dev, driver); +	stop_activity(dev);  	spin_unlock_irqrestore(&dev->lock, flags);  	return 0; @@ -1521,7 +1516,7 @@ rescan:  	if (unlikely(stat & INT_DEVWIDE)) {  		if (stat & INT_SYSERROR) {  			ERROR(dev, "system error\n"); -			stop_activity(dev, dev->driver); +			stop_activity(dev);  			stat = 0;  			handled = 1;  			// FIXME have a neater way to prevent re-enumeration @@ -1536,7 +1531,7 @@ rescan:  			} else {  				DBG(dev, "disconnect\n");  				if (dev->gadget.speed == USB_SPEED_FULL) -					stop_activity(dev, dev->driver); +					stop_activity(dev);  				dev->ep0state = EP0_DISCONNECT;  				dev->int_enable = INT_DEVWIDE;  				writel(dev->int_enable, &dev->regs->int_enable); @@ -1701,7 +1696,6 @@ static void goku_remove(struct pci_dev *pdev)  	if (dev->enabled)  		pci_disable_device(pdev); -	pci_set_drvdata(pdev, NULL);  	dev->regs = NULL;  	INFO(dev, "unbind\n"); diff --git a/drivers/usb/gadget/gr_udc.c b/drivers/usb/gadget/gr_udc.c new file mode 100644 index 00000000000..c7004ee89c9 --- /dev/null +++ b/drivers/usb/gadget/gr_udc.c @@ -0,0 +1,2236 @@ +/* + * USB Peripheral Controller driver for Aeroflex Gaisler GRUSBDC. + * + * 2013 (c) Aeroflex Gaisler AB + * + * This driver supports GRUSBDC USB Device Controller cores available in the + * GRLIB VHDL IP core library. + * + * Full documentation of the GRUSBDC core can be found here: + * http://www.gaisler.com/products/grlib/grip.pdf + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Contributors: + * - Andreas Larsson <andreas@gaisler.com> + * - Marko Isomaki + */ + +/* + * A GRUSBDC core can have up to 16 IN endpoints and 16 OUT endpoints each + * individually configurable to any of the four USB transfer types. This driver + * only supports cores in DMA mode. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/errno.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/dma-mapping.h> +#include <linux/dmapool.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/of_platform.h> +#include <linux/of_irq.h> +#include <linux/of_address.h> + +#include <asm/byteorder.h> + +#include "gr_udc.h" + +#define	DRIVER_NAME	"gr_udc" +#define	DRIVER_DESC	"Aeroflex Gaisler GRUSBDC USB Peripheral Controller" + +static const char driver_name[] = DRIVER_NAME; +static const char driver_desc[] = DRIVER_DESC; + +#define gr_read32(x) (ioread32be((x))) +#define gr_write32(x, v) (iowrite32be((v), (x))) + +/* USB speed and corresponding string calculated from status register value */ +#define GR_SPEED(status) \ +	((status & GR_STATUS_SP) ? USB_SPEED_FULL : USB_SPEED_HIGH) +#define GR_SPEED_STR(status) usb_speed_string(GR_SPEED(status)) + +/* Size of hardware buffer calculated from epctrl register value */ +#define GR_BUFFER_SIZE(epctrl)					      \ +	((((epctrl) & GR_EPCTRL_BUFSZ_MASK) >> GR_EPCTRL_BUFSZ_POS) * \ +	 GR_EPCTRL_BUFSZ_SCALER) + +/* ---------------------------------------------------------------------- */ +/* Debug printout functionality */ + +static const char * const gr_modestring[] = {"control", "iso", "bulk", "int"}; + +static const char *gr_ep0state_string(enum gr_ep0state state) +{ +	static const char *const names[] = { +		[GR_EP0_DISCONNECT] = "disconnect", +		[GR_EP0_SETUP] = "setup", +		[GR_EP0_IDATA] = "idata", +		[GR_EP0_ODATA] = "odata", +		[GR_EP0_ISTATUS] = "istatus", +		[GR_EP0_OSTATUS] = "ostatus", +		[GR_EP0_STALL] = "stall", +		[GR_EP0_SUSPEND] = "suspend", +	}; + +	if (state < 0 || state >= ARRAY_SIZE(names)) +		return "UNKNOWN"; + +	return names[state]; +} + +#ifdef VERBOSE_DEBUG + +static void gr_dbgprint_request(const char *str, struct gr_ep *ep, +				struct gr_request *req) +{ +	int buflen = ep->is_in ? req->req.length : req->req.actual; +	int rowlen = 32; +	int plen = min(rowlen, buflen); + +	dev_dbg(ep->dev->dev, "%s: 0x%p, %d bytes data%s:\n", str, req, buflen, +		(buflen > plen ? " (truncated)" : "")); +	print_hex_dump_debug("   ", DUMP_PREFIX_NONE, +			     rowlen, 4, req->req.buf, plen, false); +} + +static void gr_dbgprint_devreq(struct gr_udc *dev, u8 type, u8 request, +			       u16 value, u16 index, u16 length) +{ +	dev_vdbg(dev->dev, "REQ: %02x.%02x v%04x i%04x l%04x\n", +		 type, request, value, index, length); +} +#else /* !VERBOSE_DEBUG */ + +static void gr_dbgprint_request(const char *str, struct gr_ep *ep, +				struct gr_request *req) {} + +static void gr_dbgprint_devreq(struct gr_udc *dev, u8 type, u8 request, +			       u16 value, u16 index, u16 length) {} + +#endif /* VERBOSE_DEBUG */ + +/* ---------------------------------------------------------------------- */ +/* Debugfs functionality */ + +#ifdef CONFIG_USB_GADGET_DEBUG_FS + +static void gr_seq_ep_show(struct seq_file *seq, struct gr_ep *ep) +{ +	u32 epctrl = gr_read32(&ep->regs->epctrl); +	u32 epstat = gr_read32(&ep->regs->epstat); +	int mode = (epctrl & GR_EPCTRL_TT_MASK) >> GR_EPCTRL_TT_POS; +	struct gr_request *req; + +	seq_printf(seq, "%s:\n", ep->ep.name); +	seq_printf(seq, "  mode = %s\n", gr_modestring[mode]); +	seq_printf(seq, "  halted: %d\n", !!(epctrl & GR_EPCTRL_EH)); +	seq_printf(seq, "  disabled: %d\n", !!(epctrl & GR_EPCTRL_ED)); +	seq_printf(seq, "  valid: %d\n", !!(epctrl & GR_EPCTRL_EV)); +	seq_printf(seq, "  dma_start = %d\n", ep->dma_start); +	seq_printf(seq, "  stopped = %d\n", ep->stopped); +	seq_printf(seq, "  wedged = %d\n", ep->wedged); +	seq_printf(seq, "  callback = %d\n", ep->callback); +	seq_printf(seq, "  maxpacket = %d\n", ep->ep.maxpacket); +	seq_printf(seq, "  maxpacket_limit = %d\n", ep->ep.maxpacket_limit); +	seq_printf(seq, "  bytes_per_buffer = %d\n", ep->bytes_per_buffer); +	if (mode == 1 || mode == 3) +		seq_printf(seq, "  nt = %d\n", +			   (epctrl & GR_EPCTRL_NT_MASK) >> GR_EPCTRL_NT_POS); + +	seq_printf(seq, "  Buffer 0: %s %s%d\n", +		   epstat & GR_EPSTAT_B0 ? "valid" : "invalid", +		   epstat & GR_EPSTAT_BS ? " " : "selected ", +		   (epstat & GR_EPSTAT_B0CNT_MASK) >> GR_EPSTAT_B0CNT_POS); +	seq_printf(seq, "  Buffer 1: %s %s%d\n", +		   epstat & GR_EPSTAT_B1 ? "valid" : "invalid", +		   epstat & GR_EPSTAT_BS ? "selected " : " ", +		   (epstat & GR_EPSTAT_B1CNT_MASK) >> GR_EPSTAT_B1CNT_POS); + +	if (list_empty(&ep->queue)) { +		seq_puts(seq, "  Queue: empty\n\n"); +		return; +	} + +	seq_puts(seq, "  Queue:\n"); +	list_for_each_entry(req, &ep->queue, queue) { +		struct gr_dma_desc *desc; +		struct gr_dma_desc *next; + +		seq_printf(seq, "    0x%p: 0x%p %d %d\n", req, +			   &req->req.buf, req->req.actual, req->req.length); + +		next = req->first_desc; +		do { +			desc = next; +			next = desc->next_desc; +			seq_printf(seq, "    %c 0x%p (0x%08x): 0x%05x 0x%08x\n", +				   desc == req->curr_desc ? 'c' : ' ', +				   desc, desc->paddr, desc->ctrl, desc->data); +		} while (desc != req->last_desc); +	} +	seq_puts(seq, "\n"); +} + + +static int gr_seq_show(struct seq_file *seq, void *v) +{ +	struct gr_udc *dev = seq->private; +	u32 control = gr_read32(&dev->regs->control); +	u32 status = gr_read32(&dev->regs->status); +	struct gr_ep *ep; + +	seq_printf(seq, "usb state = %s\n", +		   usb_state_string(dev->gadget.state)); +	seq_printf(seq, "address = %d\n", +		   (control & GR_CONTROL_UA_MASK) >> GR_CONTROL_UA_POS); +	seq_printf(seq, "speed = %s\n", GR_SPEED_STR(status)); +	seq_printf(seq, "ep0state = %s\n", gr_ep0state_string(dev->ep0state)); +	seq_printf(seq, "irq_enabled = %d\n", dev->irq_enabled); +	seq_printf(seq, "remote_wakeup = %d\n", dev->remote_wakeup); +	seq_printf(seq, "test_mode = %d\n", dev->test_mode); +	seq_puts(seq, "\n"); + +	list_for_each_entry(ep, &dev->ep_list, ep_list) +		gr_seq_ep_show(seq, ep); + +	return 0; +} + +static int gr_dfs_open(struct inode *inode, struct file *file) +{ +	return single_open(file, gr_seq_show, inode->i_private); +} + +static const struct file_operations gr_dfs_fops = { +	.owner		= THIS_MODULE, +	.open		= gr_dfs_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= single_release, +}; + +static void gr_dfs_create(struct gr_udc *dev) +{ +	const char *name = "gr_udc_state"; + +	dev->dfs_root = debugfs_create_dir(dev_name(dev->dev), NULL); +	dev->dfs_state = debugfs_create_file(name, 0444, dev->dfs_root, dev, +					     &gr_dfs_fops); +} + +static void gr_dfs_delete(struct gr_udc *dev) +{ +	/* Handles NULL and ERR pointers internally */ +	debugfs_remove(dev->dfs_state); +	debugfs_remove(dev->dfs_root); +} + +#else /* !CONFIG_USB_GADGET_DEBUG_FS */ + +static void gr_dfs_create(struct gr_udc *dev) {} +static void gr_dfs_delete(struct gr_udc *dev) {} + +#endif /* CONFIG_USB_GADGET_DEBUG_FS */ + +/* ---------------------------------------------------------------------- */ +/* DMA and request handling */ + +/* Allocates a new struct gr_dma_desc, sets paddr and zeroes the rest */ +static struct gr_dma_desc *gr_alloc_dma_desc(struct gr_ep *ep, gfp_t gfp_flags) +{ +	dma_addr_t paddr; +	struct gr_dma_desc *dma_desc; + +	dma_desc = dma_pool_alloc(ep->dev->desc_pool, gfp_flags, &paddr); +	if (!dma_desc) { +		dev_err(ep->dev->dev, "Could not allocate from DMA pool\n"); +		return NULL; +	} + +	memset(dma_desc, 0, sizeof(*dma_desc)); +	dma_desc->paddr = paddr; + +	return dma_desc; +} + +static inline void gr_free_dma_desc(struct gr_udc *dev, +				    struct gr_dma_desc *desc) +{ +	dma_pool_free(dev->desc_pool, desc, (dma_addr_t)desc->paddr); +} + +/* Frees the chain of struct gr_dma_desc for the given request */ +static void gr_free_dma_desc_chain(struct gr_udc *dev, struct gr_request *req) +{ +	struct gr_dma_desc *desc; +	struct gr_dma_desc *next; + +	next = req->first_desc; +	if (!next) +		return; + +	do { +		desc = next; +		next = desc->next_desc; +		gr_free_dma_desc(dev, desc); +	} while (desc != req->last_desc); + +	req->first_desc = NULL; +	req->curr_desc = NULL; +	req->last_desc = NULL; +} + +static void gr_ep0_setup(struct gr_udc *dev, struct gr_request *req); + +/* + * Frees allocated resources and calls the appropriate completion function/setup + * package handler for a finished request. + * + * Must be called with dev->lock held and irqs disabled. + */ +static void gr_finish_request(struct gr_ep *ep, struct gr_request *req, +			      int status) +	__releases(&dev->lock) +	__acquires(&dev->lock) +{ +	struct gr_udc *dev; + +	list_del_init(&req->queue); + +	if (likely(req->req.status == -EINPROGRESS)) +		req->req.status = status; +	else +		status = req->req.status; + +	dev = ep->dev; +	usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in); +	gr_free_dma_desc_chain(dev, req); + +	if (ep->is_in) /* For OUT, actual gets updated bit by bit */ +		req->req.actual = req->req.length; + +	if (!status) { +		if (ep->is_in) +			gr_dbgprint_request("SENT", ep, req); +		else +			gr_dbgprint_request("RECV", ep, req); +	} + +	/* Prevent changes to ep->queue during callback */ +	ep->callback = 1; +	if (req == dev->ep0reqo && !status) { +		if (req->setup) +			gr_ep0_setup(dev, req); +		else +			dev_err(dev->dev, +				"Unexpected non setup packet on ep0in\n"); +	} else if (req->req.complete) { +		spin_unlock(&dev->lock); + +		req->req.complete(&ep->ep, &req->req); + +		spin_lock(&dev->lock); +	} +	ep->callback = 0; +} + +static struct usb_request *gr_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) +{ +	struct gr_request *req; + +	req = kzalloc(sizeof(*req), gfp_flags); +	if (!req) +		return NULL; + +	INIT_LIST_HEAD(&req->queue); + +	return &req->req; +} + +/* + * Starts DMA for endpoint ep if there are requests in the queue. + * + * Must be called with dev->lock held and with !ep->stopped. + */ +static void gr_start_dma(struct gr_ep *ep) +{ +	struct gr_request *req; +	u32 dmactrl; + +	if (list_empty(&ep->queue)) { +		ep->dma_start = 0; +		return; +	} + +	req = list_first_entry(&ep->queue, struct gr_request, queue); + +	/* A descriptor should already have been allocated */ +	BUG_ON(!req->curr_desc); + +	wmb(); /* Make sure all is settled before handing it over to DMA */ + +	/* Set the descriptor pointer in the hardware */ +	gr_write32(&ep->regs->dmaaddr, req->curr_desc->paddr); + +	/* Announce available descriptors */ +	dmactrl = gr_read32(&ep->regs->dmactrl); +	gr_write32(&ep->regs->dmactrl, dmactrl | GR_DMACTRL_DA); + +	ep->dma_start = 1; +} + +/* + * Finishes the first request in the ep's queue and, if available, starts the + * next request in queue. + * + * Must be called with dev->lock held, irqs disabled and with !ep->stopped. + */ +static void gr_dma_advance(struct gr_ep *ep, int status) +{ +	struct gr_request *req; + +	req = list_first_entry(&ep->queue, struct gr_request, queue); +	gr_finish_request(ep, req, status); +	gr_start_dma(ep); /* Regardless of ep->dma_start */ +} + +/* + * Abort DMA for an endpoint. Sets the abort DMA bit which causes an ongoing DMA + * transfer to be canceled and clears GR_DMACTRL_DA. + * + * Must be called with dev->lock held. + */ +static void gr_abort_dma(struct gr_ep *ep) +{ +	u32 dmactrl; + +	dmactrl = gr_read32(&ep->regs->dmactrl); +	gr_write32(&ep->regs->dmactrl, dmactrl | GR_DMACTRL_AD); +} + +/* + * Allocates and sets up a struct gr_dma_desc and putting it on the descriptor + * chain. + * + * Size is not used for OUT endpoints. Hardware can not be instructed to handle + * smaller buffer than MAXPL in the OUT direction. + */ +static int gr_add_dma_desc(struct gr_ep *ep, struct gr_request *req, +			   dma_addr_t data, unsigned size, gfp_t gfp_flags) +{ +	struct gr_dma_desc *desc; + +	desc = gr_alloc_dma_desc(ep, gfp_flags); +	if (!desc) +		return -ENOMEM; + +	desc->data = data; +	if (ep->is_in) +		desc->ctrl = +			(GR_DESC_IN_CTRL_LEN_MASK & size) | GR_DESC_IN_CTRL_EN; +	else +		desc->ctrl = GR_DESC_OUT_CTRL_IE; + +	if (!req->first_desc) { +		req->first_desc = desc; +		req->curr_desc = desc; +	} else { +		req->last_desc->next_desc = desc; +		req->last_desc->next = desc->paddr; +		req->last_desc->ctrl |= GR_DESC_OUT_CTRL_NX; +	} +	req->last_desc = desc; + +	return 0; +} + +/* + * Sets up a chain of struct gr_dma_descriptors pointing to buffers that + * together covers req->req.length bytes of the buffer at DMA address + * req->req.dma for the OUT direction. + * + * The first descriptor in the chain is enabled, the rest disabled. The + * interrupt handler will later enable them one by one when needed so we can + * find out when the transfer is finished. For OUT endpoints, all descriptors + * therefore generate interrutps. + */ +static int gr_setup_out_desc_list(struct gr_ep *ep, struct gr_request *req, +				  gfp_t gfp_flags) +{ +	u16 bytes_left; /* Bytes left to provide descriptors for */ +	u16 bytes_used; /* Bytes accommodated for */ +	int ret = 0; + +	req->first_desc = NULL; /* Signals that no allocation is done yet */ +	bytes_left = req->req.length; +	bytes_used = 0; +	while (bytes_left > 0) { +		dma_addr_t start = req->req.dma + bytes_used; +		u16 size = min(bytes_left, ep->bytes_per_buffer); + +		/* Should not happen however - gr_queue stops such lengths */ +		if (size < ep->bytes_per_buffer) +			dev_warn(ep->dev->dev, +				 "Buffer overrun risk: %u < %u bytes/buffer\n", +				 size, ep->bytes_per_buffer); + +		ret = gr_add_dma_desc(ep, req, start, size, gfp_flags); +		if (ret) +			goto alloc_err; + +		bytes_left -= size; +		bytes_used += size; +	} + +	req->first_desc->ctrl |= GR_DESC_OUT_CTRL_EN; + +	return 0; + +alloc_err: +	gr_free_dma_desc_chain(ep->dev, req); + +	return ret; +} + +/* + * Sets up a chain of struct gr_dma_descriptors pointing to buffers that + * together covers req->req.length bytes of the buffer at DMA address + * req->req.dma for the IN direction. + * + * When more data is provided than the maximum payload size, the hardware splits + * this up into several payloads automatically. Moreover, ep->bytes_per_buffer + * is always set to a multiple of the maximum payload (restricted to the valid + * number of maximum payloads during high bandwidth isochronous or interrupt + * transfers) + * + * All descriptors are enabled from the beginning and we only generate an + * interrupt for the last one indicating that the entire request has been pushed + * to hardware. + */ +static int gr_setup_in_desc_list(struct gr_ep *ep, struct gr_request *req, +				 gfp_t gfp_flags) +{ +	u16 bytes_left; /* Bytes left in req to provide descriptors for */ +	u16 bytes_used; /* Bytes in req accommodated for */ +	int ret = 0; + +	req->first_desc = NULL; /* Signals that no allocation is done yet */ +	bytes_left = req->req.length; +	bytes_used = 0; +	do { /* Allow for zero length packets */ +		dma_addr_t start = req->req.dma + bytes_used; +		u16 size = min(bytes_left, ep->bytes_per_buffer); + +		ret = gr_add_dma_desc(ep, req, start, size, gfp_flags); +		if (ret) +			goto alloc_err; + +		bytes_left -= size; +		bytes_used += size; +	} while (bytes_left > 0); + +	/* +	 * Send an extra zero length packet to indicate that no more data is +	 * available when req->req.zero is set and the data length is even +	 * multiples of ep->ep.maxpacket. +	 */ +	if (req->req.zero && (req->req.length % ep->ep.maxpacket == 0)) { +		ret = gr_add_dma_desc(ep, req, 0, 0, gfp_flags); +		if (ret) +			goto alloc_err; +	} + +	/* +	 * For IN packets we only want to know when the last packet has been +	 * transmitted (not just put into internal buffers). +	 */ +	req->last_desc->ctrl |= GR_DESC_IN_CTRL_PI; + +	return 0; + +alloc_err: +	gr_free_dma_desc_chain(ep->dev, req); + +	return ret; +} + +/* Must be called with dev->lock held */ +static int gr_queue(struct gr_ep *ep, struct gr_request *req, gfp_t gfp_flags) +{ +	struct gr_udc *dev = ep->dev; +	int ret; + +	if (unlikely(!ep->ep.desc && ep->num != 0)) { +		dev_err(dev->dev, "No ep descriptor for %s\n", ep->ep.name); +		return -EINVAL; +	} + +	if (unlikely(!req->req.buf || !list_empty(&req->queue))) { +		dev_err(dev->dev, +			"Invalid request for %s: buf=%p list_empty=%d\n", +			ep->ep.name, req->req.buf, list_empty(&req->queue)); +		return -EINVAL; +	} + +	/* +	 * The DMA controller can not handle smaller OUT buffers than +	 * maxpacket. It could lead to buffer overruns if unexpectedly long +	 * packet are received. +	 */ +	if (!ep->is_in && (req->req.length % ep->ep.maxpacket) != 0) { +		dev_err(dev->dev, +			"OUT request length %d is not multiple of maxpacket\n", +			req->req.length); +		return -EMSGSIZE; +	} + +	if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { +		dev_err(dev->dev, "-ESHUTDOWN"); +		return -ESHUTDOWN; +	} + +	/* Can't touch registers when suspended */ +	if (dev->ep0state == GR_EP0_SUSPEND) { +		dev_err(dev->dev, "-EBUSY"); +		return -EBUSY; +	} + +	/* Set up DMA mapping in case the caller didn't */ +	ret = usb_gadget_map_request(&dev->gadget, &req->req, ep->is_in); +	if (ret) { +		dev_err(dev->dev, "usb_gadget_map_request"); +		return ret; +	} + +	if (ep->is_in) +		ret = gr_setup_in_desc_list(ep, req, gfp_flags); +	else +		ret = gr_setup_out_desc_list(ep, req, gfp_flags); +	if (ret) +		return ret; + +	req->req.status = -EINPROGRESS; +	req->req.actual = 0; +	list_add_tail(&req->queue, &ep->queue); + +	/* Start DMA if not started, otherwise interrupt handler handles it */ +	if (!ep->dma_start && likely(!ep->stopped)) +		gr_start_dma(ep); + +	return 0; +} + +/* + * Queue a request from within the driver. + * + * Must be called with dev->lock held. + */ +static inline int gr_queue_int(struct gr_ep *ep, struct gr_request *req, +			       gfp_t gfp_flags) +{ +	if (ep->is_in) +		gr_dbgprint_request("RESP", ep, req); + +	return gr_queue(ep, req, gfp_flags); +} + +/* ---------------------------------------------------------------------- */ +/* General helper functions */ + +/* + * Dequeue ALL requests. + * + * Must be called with dev->lock held and irqs disabled. + */ +static void gr_ep_nuke(struct gr_ep *ep) +{ +	struct gr_request *req; + +	ep->stopped = 1; +	ep->dma_start = 0; +	gr_abort_dma(ep); + +	while (!list_empty(&ep->queue)) { +		req = list_first_entry(&ep->queue, struct gr_request, queue); +		gr_finish_request(ep, req, -ESHUTDOWN); +	} +} + +/* + * Reset the hardware state of this endpoint. + * + * Must be called with dev->lock held. + */ +static void gr_ep_reset(struct gr_ep *ep) +{ +	gr_write32(&ep->regs->epctrl, 0); +	gr_write32(&ep->regs->dmactrl, 0); + +	ep->ep.maxpacket = MAX_CTRL_PL_SIZE; +	ep->ep.desc = NULL; +	ep->stopped = 1; +	ep->dma_start = 0; +} + +/* + * Generate STALL on ep0in/out. + * + * Must be called with dev->lock held. + */ +static void gr_control_stall(struct gr_udc *dev) +{ +	u32 epctrl; + +	epctrl = gr_read32(&dev->epo[0].regs->epctrl); +	gr_write32(&dev->epo[0].regs->epctrl, epctrl | GR_EPCTRL_CS); +	epctrl = gr_read32(&dev->epi[0].regs->epctrl); +	gr_write32(&dev->epi[0].regs->epctrl, epctrl | GR_EPCTRL_CS); + +	dev->ep0state = GR_EP0_STALL; +} + +/* + * Halts, halts and wedges, or clears halt for an endpoint. + * + * Must be called with dev->lock held. + */ +static int gr_ep_halt_wedge(struct gr_ep *ep, int halt, int wedge, int fromhost) +{ +	u32 epctrl; +	int retval = 0; + +	if (ep->num && !ep->ep.desc) +		return -EINVAL; + +	if (ep->num && ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) +		return -EOPNOTSUPP; + +	/* Never actually halt ep0, and therefore never clear halt for ep0 */ +	if (!ep->num) { +		if (halt && !fromhost) { +			/* ep0 halt from gadget - generate protocol stall */ +			gr_control_stall(ep->dev); +			dev_dbg(ep->dev->dev, "EP: stall ep0\n"); +			return 0; +		} +		return -EINVAL; +	} + +	dev_dbg(ep->dev->dev, "EP: %s halt %s\n", +		(halt ? (wedge ? "wedge" : "set") : "clear"), ep->ep.name); + +	epctrl = gr_read32(&ep->regs->epctrl); +	if (halt) { +		/* Set HALT */ +		gr_write32(&ep->regs->epctrl, epctrl | GR_EPCTRL_EH); +		ep->stopped = 1; +		if (wedge) +			ep->wedged = 1; +	} else { +		gr_write32(&ep->regs->epctrl, epctrl & ~GR_EPCTRL_EH); +		ep->stopped = 0; +		ep->wedged = 0; + +		/* Things might have been queued up in the meantime */ +		if (!ep->dma_start) +			gr_start_dma(ep); +	} + +	return retval; +} + +/* Must be called with dev->lock held */ +static inline void gr_set_ep0state(struct gr_udc *dev, enum gr_ep0state value) +{ +	if (dev->ep0state != value) +		dev_vdbg(dev->dev, "STATE:  ep0state=%s\n", +			 gr_ep0state_string(value)); +	dev->ep0state = value; +} + +/* + * Should only be called when endpoints can not generate interrupts. + * + * Must be called with dev->lock held. + */ +static void gr_disable_interrupts_and_pullup(struct gr_udc *dev) +{ +	gr_write32(&dev->regs->control, 0); +	wmb(); /* Make sure that we do not deny one of our interrupts */ +	dev->irq_enabled = 0; +} + +/* + * Stop all device activity and disable data line pullup. + * + * Must be called with dev->lock held and irqs disabled. + */ +static void gr_stop_activity(struct gr_udc *dev) +{ +	struct gr_ep *ep; + +	list_for_each_entry(ep, &dev->ep_list, ep_list) +		gr_ep_nuke(ep); + +	gr_disable_interrupts_and_pullup(dev); + +	gr_set_ep0state(dev, GR_EP0_DISCONNECT); +	usb_gadget_set_state(&dev->gadget, USB_STATE_NOTATTACHED); +} + +/* ---------------------------------------------------------------------- */ +/* ep0 setup packet handling */ + +static void gr_ep0_testmode_complete(struct usb_ep *_ep, +				     struct usb_request *_req) +{ +	struct gr_ep *ep; +	struct gr_udc *dev; +	u32 control; + +	ep = container_of(_ep, struct gr_ep, ep); +	dev = ep->dev; + +	spin_lock(&dev->lock); + +	control = gr_read32(&dev->regs->control); +	control |= GR_CONTROL_TM | (dev->test_mode << GR_CONTROL_TS_POS); +	gr_write32(&dev->regs->control, control); + +	spin_unlock(&dev->lock); +} + +static void gr_ep0_dummy_complete(struct usb_ep *_ep, struct usb_request *_req) +{ +	/* Nothing needs to be done here */ +} + +/* + * Queue a response on ep0in. + * + * Must be called with dev->lock held. + */ +static int gr_ep0_respond(struct gr_udc *dev, u8 *buf, int length, +			  void (*complete)(struct usb_ep *ep, +					   struct usb_request *req)) +{ +	u8 *reqbuf = dev->ep0reqi->req.buf; +	int status; +	int i; + +	for (i = 0; i < length; i++) +		reqbuf[i] = buf[i]; +	dev->ep0reqi->req.length = length; +	dev->ep0reqi->req.complete = complete; + +	status = gr_queue_int(&dev->epi[0], dev->ep0reqi, GFP_ATOMIC); +	if (status < 0) +		dev_err(dev->dev, +			"Could not queue ep0in setup response: %d\n", status); + +	return status; +} + +/* + * Queue a 2 byte response on ep0in. + * + * Must be called with dev->lock held. + */ +static inline int gr_ep0_respond_u16(struct gr_udc *dev, u16 response) +{ +	__le16 le_response = cpu_to_le16(response); + +	return gr_ep0_respond(dev, (u8 *)&le_response, 2, +			      gr_ep0_dummy_complete); +} + +/* + * Queue a ZLP response on ep0in. + * + * Must be called with dev->lock held. + */ +static inline int gr_ep0_respond_empty(struct gr_udc *dev) +{ +	return gr_ep0_respond(dev, NULL, 0, gr_ep0_dummy_complete); +} + +/* + * This is run when a SET_ADDRESS request is received. First writes + * the new address to the control register which is updated internally + * when the next IN packet is ACKED. + * + * Must be called with dev->lock held. + */ +static void gr_set_address(struct gr_udc *dev, u8 address) +{ +	u32 control; + +	control = gr_read32(&dev->regs->control) & ~GR_CONTROL_UA_MASK; +	control |= (address << GR_CONTROL_UA_POS) & GR_CONTROL_UA_MASK; +	control |= GR_CONTROL_SU; +	gr_write32(&dev->regs->control, control); +} + +/* + * Returns negative for STALL, 0 for successful handling and positive for + * delegation. + * + * Must be called with dev->lock held. + */ +static int gr_device_request(struct gr_udc *dev, u8 type, u8 request, +			     u16 value, u16 index) +{ +	u16 response; +	u8 test; + +	switch (request) { +	case USB_REQ_SET_ADDRESS: +		dev_dbg(dev->dev, "STATUS: address %d\n", value & 0xff); +		gr_set_address(dev, value & 0xff); +		if (value) +			usb_gadget_set_state(&dev->gadget, USB_STATE_ADDRESS); +		else +			usb_gadget_set_state(&dev->gadget, USB_STATE_DEFAULT); +		return gr_ep0_respond_empty(dev); + +	case USB_REQ_GET_STATUS: +		/* Self powered | remote wakeup */ +		response = 0x0001 | (dev->remote_wakeup ? 0x0002 : 0); +		return gr_ep0_respond_u16(dev, response); + +	case USB_REQ_SET_FEATURE: +		switch (value) { +		case USB_DEVICE_REMOTE_WAKEUP: +			/* Allow remote wakeup */ +			dev->remote_wakeup = 1; +			return gr_ep0_respond_empty(dev); + +		case USB_DEVICE_TEST_MODE: +			/* The hardware does not support TEST_FORCE_EN */ +			test = index >> 8; +			if (test >= TEST_J && test <= TEST_PACKET) { +				dev->test_mode = test; +				return gr_ep0_respond(dev, NULL, 0, +						      gr_ep0_testmode_complete); +			} +		} +		break; + +	case USB_REQ_CLEAR_FEATURE: +		switch (value) { +		case USB_DEVICE_REMOTE_WAKEUP: +			/* Disallow remote wakeup */ +			dev->remote_wakeup = 0; +			return gr_ep0_respond_empty(dev); +		} +		break; +	} + +	return 1; /* Delegate the rest */ +} + +/* + * Returns negative for STALL, 0 for successful handling and positive for + * delegation. + * + * Must be called with dev->lock held. + */ +static int gr_interface_request(struct gr_udc *dev, u8 type, u8 request, +				u16 value, u16 index) +{ +	if (dev->gadget.state != USB_STATE_CONFIGURED) +		return -1; + +	/* +	 * Should return STALL for invalid interfaces, but udc driver does not +	 * know anything about that. However, many gadget drivers do not handle +	 * GET_STATUS so we need to take care of that. +	 */ + +	switch (request) { +	case USB_REQ_GET_STATUS: +		return gr_ep0_respond_u16(dev, 0x0000); + +	case USB_REQ_SET_FEATURE: +	case USB_REQ_CLEAR_FEATURE: +		/* +		 * No possible valid standard requests. Still let gadget drivers +		 * have a go at it. +		 */ +		break; +	} + +	return 1; /* Delegate the rest */ +} + +/* + * Returns negative for STALL, 0 for successful handling and positive for + * delegation. + * + * Must be called with dev->lock held. + */ +static int gr_endpoint_request(struct gr_udc *dev, u8 type, u8 request, +			       u16 value, u16 index) +{ +	struct gr_ep *ep; +	int status; +	int halted; +	u8 epnum = index & USB_ENDPOINT_NUMBER_MASK; +	u8 is_in = index & USB_ENDPOINT_DIR_MASK; + +	if ((is_in && epnum >= dev->nepi) || (!is_in && epnum >= dev->nepo)) +		return -1; + +	if (dev->gadget.state != USB_STATE_CONFIGURED && epnum != 0) +		return -1; + +	ep = (is_in ? &dev->epi[epnum] : &dev->epo[epnum]); + +	switch (request) { +	case USB_REQ_GET_STATUS: +		halted = gr_read32(&ep->regs->epctrl) & GR_EPCTRL_EH; +		return gr_ep0_respond_u16(dev, halted ? 0x0001 : 0); + +	case USB_REQ_SET_FEATURE: +		switch (value) { +		case USB_ENDPOINT_HALT: +			status = gr_ep_halt_wedge(ep, 1, 0, 1); +			if (status >= 0) +				status = gr_ep0_respond_empty(dev); +			return status; +		} +		break; + +	case USB_REQ_CLEAR_FEATURE: +		switch (value) { +		case USB_ENDPOINT_HALT: +			if (ep->wedged) +				return -1; +			status = gr_ep_halt_wedge(ep, 0, 0, 1); +			if (status >= 0) +				status = gr_ep0_respond_empty(dev); +			return status; +		} +		break; +	} + +	return 1; /* Delegate the rest */ +} + +/* Must be called with dev->lock held */ +static void gr_ep0out_requeue(struct gr_udc *dev) +{ +	int ret = gr_queue_int(&dev->epo[0], dev->ep0reqo, GFP_ATOMIC); + +	if (ret) +		dev_err(dev->dev, "Could not queue ep0out setup request: %d\n", +			ret); +} + +/* + * The main function dealing with setup requests on ep0. + * + * Must be called with dev->lock held and irqs disabled + */ +static void gr_ep0_setup(struct gr_udc *dev, struct gr_request *req) +	__releases(&dev->lock) +	__acquires(&dev->lock) +{ +	union { +		struct usb_ctrlrequest ctrl; +		u8 raw[8]; +		u32 word[2]; +	} u; +	u8 type; +	u8 request; +	u16 value; +	u16 index; +	u16 length; +	int i; +	int status; + +	/* Restore from ep0 halt */ +	if (dev->ep0state == GR_EP0_STALL) { +		gr_set_ep0state(dev, GR_EP0_SETUP); +		if (!req->req.actual) +			goto out; +	} + +	if (dev->ep0state == GR_EP0_ISTATUS) { +		gr_set_ep0state(dev, GR_EP0_SETUP); +		if (req->req.actual > 0) +			dev_dbg(dev->dev, +				"Unexpected setup packet at state %s\n", +				gr_ep0state_string(GR_EP0_ISTATUS)); +		else +			goto out; /* Got expected ZLP */ +	} else if (dev->ep0state != GR_EP0_SETUP) { +		dev_info(dev->dev, +			 "Unexpected ep0out request at state %s - stalling\n", +			 gr_ep0state_string(dev->ep0state)); +		gr_control_stall(dev); +		gr_set_ep0state(dev, GR_EP0_SETUP); +		goto out; +	} else if (!req->req.actual) { +		dev_dbg(dev->dev, "Unexpected ZLP at state %s\n", +			gr_ep0state_string(dev->ep0state)); +		goto out; +	} + +	/* Handle SETUP packet */ +	for (i = 0; i < req->req.actual; i++) +		u.raw[i] = ((u8 *)req->req.buf)[i]; + +	type = u.ctrl.bRequestType; +	request = u.ctrl.bRequest; +	value = le16_to_cpu(u.ctrl.wValue); +	index = le16_to_cpu(u.ctrl.wIndex); +	length = le16_to_cpu(u.ctrl.wLength); + +	gr_dbgprint_devreq(dev, type, request, value, index, length); + +	/* Check for data stage */ +	if (length) { +		if (type & USB_DIR_IN) +			gr_set_ep0state(dev, GR_EP0_IDATA); +		else +			gr_set_ep0state(dev, GR_EP0_ODATA); +	} + +	status = 1; /* Positive status flags delegation */ +	if ((type & USB_TYPE_MASK) == USB_TYPE_STANDARD) { +		switch (type & USB_RECIP_MASK) { +		case USB_RECIP_DEVICE: +			status = gr_device_request(dev, type, request, +						   value, index); +			break; +		case USB_RECIP_ENDPOINT: +			status =  gr_endpoint_request(dev, type, request, +						      value, index); +			break; +		case USB_RECIP_INTERFACE: +			status = gr_interface_request(dev, type, request, +						      value, index); +			break; +		} +	} + +	if (status > 0) { +		spin_unlock(&dev->lock); + +		dev_vdbg(dev->dev, "DELEGATE\n"); +		status = dev->driver->setup(&dev->gadget, &u.ctrl); + +		spin_lock(&dev->lock); +	} + +	/* Generate STALL on both ep0out and ep0in if requested */ +	if (unlikely(status < 0)) { +		dev_vdbg(dev->dev, "STALL\n"); +		gr_control_stall(dev); +	} + +	if ((type & USB_TYPE_MASK) == USB_TYPE_STANDARD && +	    request == USB_REQ_SET_CONFIGURATION) { +		if (!value) { +			dev_dbg(dev->dev, "STATUS: deconfigured\n"); +			usb_gadget_set_state(&dev->gadget, USB_STATE_ADDRESS); +		} else if (status >= 0) { +			/* Not configured unless gadget OK:s it */ +			dev_dbg(dev->dev, "STATUS: configured: %d\n", value); +			usb_gadget_set_state(&dev->gadget, +					     USB_STATE_CONFIGURED); +		} +	} + +	/* Get ready for next stage */ +	if (dev->ep0state == GR_EP0_ODATA) +		gr_set_ep0state(dev, GR_EP0_OSTATUS); +	else if (dev->ep0state == GR_EP0_IDATA) +		gr_set_ep0state(dev, GR_EP0_ISTATUS); +	else +		gr_set_ep0state(dev, GR_EP0_SETUP); + +out: +	gr_ep0out_requeue(dev); +} + +/* ---------------------------------------------------------------------- */ +/* VBUS and USB reset handling */ + +/* Must be called with dev->lock held and irqs disabled  */ +static void gr_vbus_connected(struct gr_udc *dev, u32 status) +{ +	u32 control; + +	dev->gadget.speed = GR_SPEED(status); +	usb_gadget_set_state(&dev->gadget, USB_STATE_POWERED); + +	/* Turn on full interrupts and pullup */ +	control = (GR_CONTROL_SI | GR_CONTROL_UI | GR_CONTROL_VI | +		   GR_CONTROL_SP | GR_CONTROL_EP); +	gr_write32(&dev->regs->control, control); +} + +/* Must be called with dev->lock held */ +static void gr_enable_vbus_detect(struct gr_udc *dev) +{ +	u32 status; + +	dev->irq_enabled = 1; +	wmb(); /* Make sure we do not ignore an interrupt */ +	gr_write32(&dev->regs->control, GR_CONTROL_VI); + +	/* Take care of the case we are already plugged in at this point */ +	status = gr_read32(&dev->regs->status); +	if (status & GR_STATUS_VB) +		gr_vbus_connected(dev, status); +} + +/* Must be called with dev->lock held and irqs disabled */ +static void gr_vbus_disconnected(struct gr_udc *dev) +{ +	gr_stop_activity(dev); + +	/* Report disconnect */ +	if (dev->driver && dev->driver->disconnect) { +		spin_unlock(&dev->lock); + +		dev->driver->disconnect(&dev->gadget); + +		spin_lock(&dev->lock); +	} + +	gr_enable_vbus_detect(dev); +} + +/* Must be called with dev->lock held and irqs disabled */ +static void gr_udc_usbreset(struct gr_udc *dev, u32 status) +{ +	gr_set_address(dev, 0); +	gr_set_ep0state(dev, GR_EP0_SETUP); +	usb_gadget_set_state(&dev->gadget, USB_STATE_DEFAULT); +	dev->gadget.speed = GR_SPEED(status); + +	gr_ep_nuke(&dev->epo[0]); +	gr_ep_nuke(&dev->epi[0]); +	dev->epo[0].stopped = 0; +	dev->epi[0].stopped = 0; +	gr_ep0out_requeue(dev); +} + +/* ---------------------------------------------------------------------- */ +/* Irq handling */ + +/* + * Handles interrupts from in endpoints. Returns whether something was handled. + * + * Must be called with dev->lock held, irqs disabled and with !ep->stopped. + */ +static int gr_handle_in_ep(struct gr_ep *ep) +{ +	struct gr_request *req; + +	req = list_first_entry(&ep->queue, struct gr_request, queue); +	if (!req->last_desc) +		return 0; + +	if (ACCESS_ONCE(req->last_desc->ctrl) & GR_DESC_IN_CTRL_EN) +		return 0; /* Not put in hardware buffers yet */ + +	if (gr_read32(&ep->regs->epstat) & (GR_EPSTAT_B1 | GR_EPSTAT_B0)) +		return 0; /* Not transmitted yet, still in hardware buffers */ + +	/* Write complete */ +	gr_dma_advance(ep, 0); + +	return 1; +} + +/* + * Handles interrupts from out endpoints. Returns whether something was handled. + * + * Must be called with dev->lock held, irqs disabled and with !ep->stopped. + */ +static int gr_handle_out_ep(struct gr_ep *ep) +{ +	u32 ep_dmactrl; +	u32 ctrl; +	u16 len; +	struct gr_request *req; +	struct gr_udc *dev = ep->dev; + +	req = list_first_entry(&ep->queue, struct gr_request, queue); +	if (!req->curr_desc) +		return 0; + +	ctrl = ACCESS_ONCE(req->curr_desc->ctrl); +	if (ctrl & GR_DESC_OUT_CTRL_EN) +		return 0; /* Not received yet */ + +	/* Read complete */ +	len = ctrl & GR_DESC_OUT_CTRL_LEN_MASK; +	req->req.actual += len; +	if (ctrl & GR_DESC_OUT_CTRL_SE) +		req->setup = 1; + +	if (len < ep->ep.maxpacket || req->req.actual == req->req.length) { +		/* Short packet or the expected size - we are done */ + +		if ((ep == &dev->epo[0]) && (dev->ep0state == GR_EP0_OSTATUS)) { +			/* +			 * Send a status stage ZLP to ack the DATA stage in the +			 * OUT direction. This needs to be done before +			 * gr_dma_advance as that can lead to a call to +			 * ep0_setup that can change dev->ep0state. +			 */ +			gr_ep0_respond_empty(dev); +			gr_set_ep0state(dev, GR_EP0_SETUP); +		} + +		gr_dma_advance(ep, 0); +	} else { +		/* Not done yet. Enable the next descriptor to receive more. */ +		req->curr_desc = req->curr_desc->next_desc; +		req->curr_desc->ctrl |= GR_DESC_OUT_CTRL_EN; + +		ep_dmactrl = gr_read32(&ep->regs->dmactrl); +		gr_write32(&ep->regs->dmactrl, ep_dmactrl | GR_DMACTRL_DA); +	} + +	return 1; +} + +/* + * Handle state changes. Returns whether something was handled. + * + * Must be called with dev->lock held and irqs disabled. + */ +static int gr_handle_state_changes(struct gr_udc *dev) +{ +	u32 status = gr_read32(&dev->regs->status); +	int handled = 0; +	int powstate = !(dev->gadget.state == USB_STATE_NOTATTACHED || +			 dev->gadget.state == USB_STATE_ATTACHED); + +	/* VBUS valid detected */ +	if (!powstate && (status & GR_STATUS_VB)) { +		dev_dbg(dev->dev, "STATUS: vbus valid detected\n"); +		gr_vbus_connected(dev, status); +		handled = 1; +	} + +	/* Disconnect */ +	if (powstate && !(status & GR_STATUS_VB)) { +		dev_dbg(dev->dev, "STATUS: vbus invalid detected\n"); +		gr_vbus_disconnected(dev); +		handled = 1; +	} + +	/* USB reset detected */ +	if (status & GR_STATUS_UR) { +		dev_dbg(dev->dev, "STATUS: USB reset - speed is %s\n", +			GR_SPEED_STR(status)); +		gr_write32(&dev->regs->status, GR_STATUS_UR); +		gr_udc_usbreset(dev, status); +		handled = 1; +	} + +	/* Speed change */ +	if (dev->gadget.speed != GR_SPEED(status)) { +		dev_dbg(dev->dev, "STATUS: USB Speed change to %s\n", +			GR_SPEED_STR(status)); +		dev->gadget.speed = GR_SPEED(status); +		handled = 1; +	} + +	/* Going into suspend */ +	if ((dev->ep0state != GR_EP0_SUSPEND) && !(status & GR_STATUS_SU)) { +		dev_dbg(dev->dev, "STATUS: USB suspend\n"); +		gr_set_ep0state(dev, GR_EP0_SUSPEND); +		dev->suspended_from = dev->gadget.state; +		usb_gadget_set_state(&dev->gadget, USB_STATE_SUSPENDED); + +		if ((dev->gadget.speed != USB_SPEED_UNKNOWN) && +		    dev->driver && dev->driver->suspend) { +			spin_unlock(&dev->lock); + +			dev->driver->suspend(&dev->gadget); + +			spin_lock(&dev->lock); +		} +		handled = 1; +	} + +	/* Coming out of suspend */ +	if ((dev->ep0state == GR_EP0_SUSPEND) && (status & GR_STATUS_SU)) { +		dev_dbg(dev->dev, "STATUS: USB resume\n"); +		if (dev->suspended_from == USB_STATE_POWERED) +			gr_set_ep0state(dev, GR_EP0_DISCONNECT); +		else +			gr_set_ep0state(dev, GR_EP0_SETUP); +		usb_gadget_set_state(&dev->gadget, dev->suspended_from); + +		if ((dev->gadget.speed != USB_SPEED_UNKNOWN) && +		    dev->driver && dev->driver->resume) { +			spin_unlock(&dev->lock); + +			dev->driver->resume(&dev->gadget); + +			spin_lock(&dev->lock); +		} +		handled = 1; +	} + +	return handled; +} + +/* Non-interrupt context irq handler */ +static irqreturn_t gr_irq_handler(int irq, void *_dev) +{ +	struct gr_udc *dev = _dev; +	struct gr_ep *ep; +	int handled = 0; +	int i; +	unsigned long flags; + +	spin_lock_irqsave(&dev->lock, flags); + +	if (!dev->irq_enabled) +		goto out; + +	/* +	 * Check IN ep interrupts. We check these before the OUT eps because +	 * some gadgets reuse the request that might already be currently +	 * outstanding and needs to be completed (mainly setup requests). +	 */ +	for (i = 0; i < dev->nepi; i++) { +		ep = &dev->epi[i]; +		if (!ep->stopped && !ep->callback && !list_empty(&ep->queue)) +			handled = gr_handle_in_ep(ep) || handled; +	} + +	/* Check OUT ep interrupts */ +	for (i = 0; i < dev->nepo; i++) { +		ep = &dev->epo[i]; +		if (!ep->stopped && !ep->callback && !list_empty(&ep->queue)) +			handled = gr_handle_out_ep(ep) || handled; +	} + +	/* Check status interrupts */ +	handled = gr_handle_state_changes(dev) || handled; + +	/* +	 * Check AMBA DMA errors. Only check if we didn't find anything else to +	 * handle because this shouldn't happen if we did everything right. +	 */ +	if (!handled) { +		list_for_each_entry(ep, &dev->ep_list, ep_list) { +			if (gr_read32(&ep->regs->dmactrl) & GR_DMACTRL_AE) { +				dev_err(dev->dev, +					"AMBA Error occurred for %s\n", +					ep->ep.name); +				handled = 1; +			} +		} +	} + +out: +	spin_unlock_irqrestore(&dev->lock, flags); + +	return handled ? IRQ_HANDLED : IRQ_NONE; +} + +/* Interrupt context irq handler */ +static irqreturn_t gr_irq(int irq, void *_dev) +{ +	struct gr_udc *dev = _dev; + +	if (!dev->irq_enabled) +		return IRQ_NONE; + +	return IRQ_WAKE_THREAD; +} + +/* ---------------------------------------------------------------------- */ +/* USB ep ops */ + +/* Enable endpoint. Not for ep0in and ep0out that are handled separately. */ +static int gr_ep_enable(struct usb_ep *_ep, +			const struct usb_endpoint_descriptor *desc) +{ +	struct gr_udc *dev; +	struct gr_ep *ep; +	u8 mode; +	u8 nt; +	u16 max; +	u16 buffer_size = 0; +	u32 epctrl; + +	ep = container_of(_ep, struct gr_ep, ep); +	if (!_ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) +		return -EINVAL; + +	dev = ep->dev; + +	/* 'ep0' IN and OUT are reserved */ +	if (ep == &dev->epo[0] || ep == &dev->epi[0]) +		return -EINVAL; + +	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) +		return -ESHUTDOWN; + +	/* Make sure we are clear for enabling */ +	epctrl = gr_read32(&ep->regs->epctrl); +	if (epctrl & GR_EPCTRL_EV) +		return -EBUSY; + +	/* Check that directions match */ +	if (!ep->is_in != !usb_endpoint_dir_in(desc)) +		return -EINVAL; + +	/* Check ep num */ +	if ((!ep->is_in && ep->num >= dev->nepo) || +	    (ep->is_in && ep->num >= dev->nepi)) +		return -EINVAL; + +	if (usb_endpoint_xfer_control(desc)) { +		mode = 0; +	} else if (usb_endpoint_xfer_isoc(desc)) { +		mode = 1; +	} else if (usb_endpoint_xfer_bulk(desc)) { +		mode = 2; +	} else if (usb_endpoint_xfer_int(desc)) { +		mode = 3; +	} else { +		dev_err(dev->dev, "Unknown transfer type for %s\n", +			ep->ep.name); +		return -EINVAL; +	} + +	/* +	 * Bits 10-0 set the max payload. 12-11 set the number of +	 * additional transactions. +	 */ +	max = 0x7ff & usb_endpoint_maxp(desc); +	nt = 0x3 & (usb_endpoint_maxp(desc) >> 11); +	buffer_size = GR_BUFFER_SIZE(epctrl); +	if (nt && (mode == 0 || mode == 2)) { +		dev_err(dev->dev, +			"%s mode: multiple trans./microframe not valid\n", +			(mode == 2 ? "Bulk" : "Control")); +		return -EINVAL; +	} else if (nt == 0x3) { +		dev_err(dev->dev, +			"Invalid value 0x3 for additional trans./microframe\n"); +		return -EINVAL; +	} else if ((nt + 1) * max > buffer_size) { +		dev_err(dev->dev, "Hw buffer size %d < max payload %d * %d\n", +			buffer_size, (nt + 1), max); +		return -EINVAL; +	} else if (max == 0) { +		dev_err(dev->dev, "Max payload cannot be set to 0\n"); +		return -EINVAL; +	} else if (max > ep->ep.maxpacket_limit) { +		dev_err(dev->dev, "Requested max payload %d > limit %d\n", +			max, ep->ep.maxpacket_limit); +		return -EINVAL; +	} + +	spin_lock(&ep->dev->lock); + +	if (!ep->stopped) { +		spin_unlock(&ep->dev->lock); +		return -EBUSY; +	} + +	ep->stopped = 0; +	ep->wedged = 0; +	ep->ep.desc = desc; +	ep->ep.maxpacket = max; +	ep->dma_start = 0; + + +	if (nt) { +		/* +		 * Maximum possible size of all payloads in one microframe +		 * regardless of direction when using high-bandwidth mode. +		 */ +		ep->bytes_per_buffer = (nt + 1) * max; +	} else if (ep->is_in) { +		/* +		 * The biggest multiple of maximum packet size that fits into +		 * the buffer. The hardware will split up into many packets in +		 * the IN direction. +		 */ +		ep->bytes_per_buffer = (buffer_size / max) * max; +	} else { +		/* +		 * Only single packets will be placed the buffers in the OUT +		 * direction. +		 */ +		ep->bytes_per_buffer = max; +	} + +	epctrl = (max << GR_EPCTRL_MAXPL_POS) +		| (nt << GR_EPCTRL_NT_POS) +		| (mode << GR_EPCTRL_TT_POS) +		| GR_EPCTRL_EV; +	if (ep->is_in) +		epctrl |= GR_EPCTRL_PI; +	gr_write32(&ep->regs->epctrl, epctrl); + +	gr_write32(&ep->regs->dmactrl, GR_DMACTRL_IE | GR_DMACTRL_AI); + +	spin_unlock(&ep->dev->lock); + +	dev_dbg(ep->dev->dev, "EP: %s enabled - %s with %d bytes/buffer\n", +		ep->ep.name, gr_modestring[mode], ep->bytes_per_buffer); +	return 0; +} + +/* Disable endpoint. Not for ep0in and ep0out that are handled separately. */ +static int gr_ep_disable(struct usb_ep *_ep) +{ +	struct gr_ep *ep; +	struct gr_udc *dev; +	unsigned long flags; + +	ep = container_of(_ep, struct gr_ep, ep); +	if (!_ep || !ep->ep.desc) +		return -ENODEV; + +	dev = ep->dev; + +	/* 'ep0' IN and OUT are reserved */ +	if (ep == &dev->epo[0] || ep == &dev->epi[0]) +		return -EINVAL; + +	if (dev->ep0state == GR_EP0_SUSPEND) +		return -EBUSY; + +	dev_dbg(ep->dev->dev, "EP: disable %s\n", ep->ep.name); + +	spin_lock_irqsave(&dev->lock, flags); + +	gr_ep_nuke(ep); +	gr_ep_reset(ep); +	ep->ep.desc = NULL; + +	spin_unlock_irqrestore(&dev->lock, flags); + +	return 0; +} + +/* + * Frees a request, but not any DMA buffers associated with it + * (gr_finish_request should already have taken care of that). + */ +static void gr_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ +	struct gr_request *req; + +	if (!_ep || !_req) +		return; +	req = container_of(_req, struct gr_request, req); + +	/* Leads to memory leak */ +	WARN(!list_empty(&req->queue), +	     "request not dequeued properly before freeing\n"); + +	kfree(req); +} + +/* Queue a request from the gadget */ +static int gr_queue_ext(struct usb_ep *_ep, struct usb_request *_req, +			gfp_t gfp_flags) +{ +	struct gr_ep *ep; +	struct gr_request *req; +	struct gr_udc *dev; +	int ret; + +	if (unlikely(!_ep || !_req)) +		return -EINVAL; + +	ep = container_of(_ep, struct gr_ep, ep); +	req = container_of(_req, struct gr_request, req); +	dev = ep->dev; + +	spin_lock(&ep->dev->lock); + +	/* +	 * The ep0 pointer in the gadget struct is used both for ep0in and +	 * ep0out. In a data stage in the out direction ep0out needs to be used +	 * instead of the default ep0in. Completion functions might use +	 * driver_data, so that needs to be copied as well. +	 */ +	if ((ep == &dev->epi[0]) && (dev->ep0state == GR_EP0_ODATA)) { +		ep = &dev->epo[0]; +		ep->ep.driver_data = dev->epi[0].ep.driver_data; +	} + +	if (ep->is_in) +		gr_dbgprint_request("EXTERN", ep, req); + +	ret = gr_queue(ep, req, GFP_ATOMIC); + +	spin_unlock(&ep->dev->lock); + +	return ret; +} + +/* Dequeue JUST ONE request */ +static int gr_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ +	struct gr_request *req; +	struct gr_ep *ep; +	struct gr_udc *dev; +	int ret = 0; +	unsigned long flags; + +	ep = container_of(_ep, struct gr_ep, ep); +	if (!_ep || !_req || (!ep->ep.desc && ep->num != 0)) +		return -EINVAL; +	dev = ep->dev; +	if (!dev->driver) +		return -ESHUTDOWN; + +	/* We can't touch (DMA) registers when suspended */ +	if (dev->ep0state == GR_EP0_SUSPEND) +		return -EBUSY; + +	spin_lock_irqsave(&dev->lock, flags); + +	/* Make sure it's actually queued on this endpoint */ +	list_for_each_entry(req, &ep->queue, queue) { +		if (&req->req == _req) +			break; +	} +	if (&req->req != _req) { +		ret = -EINVAL; +		goto out; +	} + +	if (list_first_entry(&ep->queue, struct gr_request, queue) == req) { +		/* This request is currently being processed */ +		gr_abort_dma(ep); +		if (ep->stopped) +			gr_finish_request(ep, req, -ECONNRESET); +		else +			gr_dma_advance(ep, -ECONNRESET); +	} else if (!list_empty(&req->queue)) { +		/* Not being processed - gr_finish_request dequeues it */ +		gr_finish_request(ep, req, -ECONNRESET); +	} else { +		ret = -EOPNOTSUPP; +	} + +out: +	spin_unlock_irqrestore(&dev->lock, flags); + +	return ret; +} + +/* Helper for gr_set_halt and gr_set_wedge */ +static int gr_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge) +{ +	int ret; +	struct gr_ep *ep; + +	if (!_ep) +		return -ENODEV; +	ep = container_of(_ep, struct gr_ep, ep); + +	spin_lock(&ep->dev->lock); + +	/* Halting an IN endpoint should fail if queue is not empty */ +	if (halt && ep->is_in && !list_empty(&ep->queue)) { +		ret = -EAGAIN; +		goto out; +	} + +	ret = gr_ep_halt_wedge(ep, halt, wedge, 0); + +out: +	spin_unlock(&ep->dev->lock); + +	return ret; +} + +/* Halt endpoint */ +static int gr_set_halt(struct usb_ep *_ep, int halt) +{ +	return gr_set_halt_wedge(_ep, halt, 0); +} + +/* Halt and wedge endpoint */ +static int gr_set_wedge(struct usb_ep *_ep) +{ +	return gr_set_halt_wedge(_ep, 1, 1); +} + +/* + * Return the total number of bytes currently stored in the internal buffers of + * the endpoint. + */ +static int gr_fifo_status(struct usb_ep *_ep) +{ +	struct gr_ep *ep; +	u32 epstat; +	u32 bytes = 0; + +	if (!_ep) +		return -ENODEV; +	ep = container_of(_ep, struct gr_ep, ep); + +	epstat = gr_read32(&ep->regs->epstat); + +	if (epstat & GR_EPSTAT_B0) +		bytes += (epstat & GR_EPSTAT_B0CNT_MASK) >> GR_EPSTAT_B0CNT_POS; +	if (epstat & GR_EPSTAT_B1) +		bytes += (epstat & GR_EPSTAT_B1CNT_MASK) >> GR_EPSTAT_B1CNT_POS; + +	return bytes; +} + + +/* Empty data from internal buffers of an endpoint. */ +static void gr_fifo_flush(struct usb_ep *_ep) +{ +	struct gr_ep *ep; +	u32 epctrl; + +	if (!_ep) +		return; +	ep = container_of(_ep, struct gr_ep, ep); +	dev_vdbg(ep->dev->dev, "EP: flush fifo %s\n", ep->ep.name); + +	spin_lock(&ep->dev->lock); + +	epctrl = gr_read32(&ep->regs->epctrl); +	epctrl |= GR_EPCTRL_CB; +	gr_write32(&ep->regs->epctrl, epctrl); + +	spin_unlock(&ep->dev->lock); +} + +static struct usb_ep_ops gr_ep_ops = { +	.enable		= gr_ep_enable, +	.disable	= gr_ep_disable, + +	.alloc_request	= gr_alloc_request, +	.free_request	= gr_free_request, + +	.queue		= gr_queue_ext, +	.dequeue	= gr_dequeue, + +	.set_halt	= gr_set_halt, +	.set_wedge	= gr_set_wedge, +	.fifo_status	= gr_fifo_status, +	.fifo_flush	= gr_fifo_flush, +}; + +/* ---------------------------------------------------------------------- */ +/* USB Gadget ops */ + +static int gr_get_frame(struct usb_gadget *_gadget) +{ +	struct gr_udc *dev; + +	if (!_gadget) +		return -ENODEV; +	dev = container_of(_gadget, struct gr_udc, gadget); +	return gr_read32(&dev->regs->status) & GR_STATUS_FN_MASK; +} + +static int gr_wakeup(struct usb_gadget *_gadget) +{ +	struct gr_udc *dev; + +	if (!_gadget) +		return -ENODEV; +	dev = container_of(_gadget, struct gr_udc, gadget); + +	/* Remote wakeup feature not enabled by host*/ +	if (!dev->remote_wakeup) +		return -EINVAL; + +	spin_lock(&dev->lock); + +	gr_write32(&dev->regs->control, +		   gr_read32(&dev->regs->control) | GR_CONTROL_RW); + +	spin_unlock(&dev->lock); + +	return 0; +} + +static int gr_pullup(struct usb_gadget *_gadget, int is_on) +{ +	struct gr_udc *dev; +	u32 control; + +	if (!_gadget) +		return -ENODEV; +	dev = container_of(_gadget, struct gr_udc, gadget); + +	spin_lock(&dev->lock); + +	control = gr_read32(&dev->regs->control); +	if (is_on) +		control |= GR_CONTROL_EP; +	else +		control &= ~GR_CONTROL_EP; +	gr_write32(&dev->regs->control, control); + +	spin_unlock(&dev->lock); + +	return 0; +} + +static int gr_udc_start(struct usb_gadget *gadget, +			struct usb_gadget_driver *driver) +{ +	struct gr_udc *dev = to_gr_udc(gadget); + +	spin_lock(&dev->lock); + +	/* Hook up the driver */ +	driver->driver.bus = NULL; +	dev->driver = driver; + +	/* Get ready for host detection */ +	gr_enable_vbus_detect(dev); + +	spin_unlock(&dev->lock); + +	dev_info(dev->dev, "Started with gadget driver '%s'\n", +		 driver->driver.name); + +	return 0; +} + +static int gr_udc_stop(struct usb_gadget *gadget, +		       struct usb_gadget_driver *driver) +{ +	struct gr_udc *dev = to_gr_udc(gadget); +	unsigned long flags; + +	spin_lock_irqsave(&dev->lock, flags); + +	dev->driver = NULL; +	gr_stop_activity(dev); + +	spin_unlock_irqrestore(&dev->lock, flags); + +	dev_info(dev->dev, "Stopped\n"); + +	return 0; +} + +static const struct usb_gadget_ops gr_ops = { +	.get_frame	= gr_get_frame, +	.wakeup         = gr_wakeup, +	.pullup         = gr_pullup, +	.udc_start	= gr_udc_start, +	.udc_stop	= gr_udc_stop, +	/* Other operations not supported */ +}; + +/* ---------------------------------------------------------------------- */ +/* Module probe, removal and of-matching */ + +static const char * const onames[] = { +	"ep0out", "ep1out", "ep2out", "ep3out", "ep4out", "ep5out", +	"ep6out", "ep7out", "ep8out", "ep9out", "ep10out", "ep11out", +	"ep12out", "ep13out", "ep14out", "ep15out" +}; + +static const char * const inames[] = { +	"ep0in", "ep1in", "ep2in", "ep3in", "ep4in", "ep5in", +	"ep6in", "ep7in", "ep8in", "ep9in", "ep10in", "ep11in", +	"ep12in", "ep13in", "ep14in", "ep15in" +}; + +/* Must be called with dev->lock held */ +static int gr_ep_init(struct gr_udc *dev, int num, int is_in, u32 maxplimit) +{ +	struct gr_ep *ep; +	struct gr_request *req; +	struct usb_request *_req; +	void *buf; + +	if (is_in) { +		ep = &dev->epi[num]; +		ep->ep.name = inames[num]; +		ep->regs = &dev->regs->epi[num]; +	} else { +		ep = &dev->epo[num]; +		ep->ep.name = onames[num]; +		ep->regs = &dev->regs->epo[num]; +	} + +	gr_ep_reset(ep); +	ep->num = num; +	ep->is_in = is_in; +	ep->dev = dev; +	ep->ep.ops = &gr_ep_ops; +	INIT_LIST_HEAD(&ep->queue); + +	if (num == 0) { +		_req = gr_alloc_request(&ep->ep, GFP_ATOMIC); +		buf = devm_kzalloc(dev->dev, PAGE_SIZE, GFP_DMA | GFP_ATOMIC); +		if (!_req || !buf) { +			/* possible _req freed by gr_probe via gr_remove */ +			return -ENOMEM; +		} + +		req = container_of(_req, struct gr_request, req); +		req->req.buf = buf; +		req->req.length = MAX_CTRL_PL_SIZE; + +		if (is_in) +			dev->ep0reqi = req; /* Complete gets set as used */ +		else +			dev->ep0reqo = req; /* Completion treated separately */ + +		usb_ep_set_maxpacket_limit(&ep->ep, MAX_CTRL_PL_SIZE); +		ep->bytes_per_buffer = MAX_CTRL_PL_SIZE; +	} else { +		usb_ep_set_maxpacket_limit(&ep->ep, (u16)maxplimit); +		list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); +	} +	list_add_tail(&ep->ep_list, &dev->ep_list); + +	return 0; +} + +/* Must be called with dev->lock held */ +static int gr_udc_init(struct gr_udc *dev) +{ +	struct device_node *np = dev->dev->of_node; +	u32 epctrl_val; +	u32 dmactrl_val; +	int i; +	int ret = 0; +	u32 bufsize; + +	gr_set_address(dev, 0); + +	INIT_LIST_HEAD(&dev->gadget.ep_list); +	dev->gadget.speed = USB_SPEED_UNKNOWN; +	dev->gadget.ep0 = &dev->epi[0].ep; + +	INIT_LIST_HEAD(&dev->ep_list); +	gr_set_ep0state(dev, GR_EP0_DISCONNECT); + +	for (i = 0; i < dev->nepo; i++) { +		if (of_property_read_u32_index(np, "epobufsizes", i, &bufsize)) +			bufsize = 1024; +		ret = gr_ep_init(dev, i, 0, bufsize); +		if (ret) +			return ret; +	} + +	for (i = 0; i < dev->nepi; i++) { +		if (of_property_read_u32_index(np, "epibufsizes", i, &bufsize)) +			bufsize = 1024; +		ret = gr_ep_init(dev, i, 1, bufsize); +		if (ret) +			return ret; +	} + +	/* Must be disabled by default */ +	dev->remote_wakeup = 0; + +	/* Enable ep0out and ep0in */ +	epctrl_val = (MAX_CTRL_PL_SIZE << GR_EPCTRL_MAXPL_POS) | GR_EPCTRL_EV; +	dmactrl_val = GR_DMACTRL_IE | GR_DMACTRL_AI; +	gr_write32(&dev->epo[0].regs->epctrl, epctrl_val); +	gr_write32(&dev->epi[0].regs->epctrl, epctrl_val | GR_EPCTRL_PI); +	gr_write32(&dev->epo[0].regs->dmactrl, dmactrl_val); +	gr_write32(&dev->epi[0].regs->dmactrl, dmactrl_val); + +	return 0; +} + +static int gr_remove(struct platform_device *pdev) +{ +	struct gr_udc *dev = platform_get_drvdata(pdev); + +	if (dev->added) +		usb_del_gadget_udc(&dev->gadget); /* Shuts everything down */ +	if (dev->driver) +		return -EBUSY; + +	gr_dfs_delete(dev); +	if (dev->desc_pool) +		dma_pool_destroy(dev->desc_pool); +	platform_set_drvdata(pdev, NULL); + +	gr_free_request(&dev->epi[0].ep, &dev->ep0reqi->req); +	gr_free_request(&dev->epo[0].ep, &dev->ep0reqo->req); + +	return 0; +} +static int gr_request_irq(struct gr_udc *dev, int irq) +{ +	return devm_request_threaded_irq(dev->dev, irq, gr_irq, gr_irq_handler, +					 IRQF_SHARED, driver_name, dev); +} + +static int gr_probe(struct platform_device *pdev) +{ +	struct gr_udc *dev; +	struct resource *res; +	struct gr_regs __iomem *regs; +	int retval; +	u32 status; + +	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); +	if (!dev) +		return -ENOMEM; +	dev->dev = &pdev->dev; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	regs = devm_ioremap_resource(dev->dev, res); +	if (IS_ERR(regs)) +		return PTR_ERR(regs); + +	dev->irq = platform_get_irq(pdev, 0); +	if (dev->irq <= 0) { +		dev_err(dev->dev, "No irq found\n"); +		return -ENODEV; +	} + +	/* Some core configurations has separate irqs for IN and OUT events */ +	dev->irqi = platform_get_irq(pdev, 1); +	if (dev->irqi > 0) { +		dev->irqo = platform_get_irq(pdev, 2); +		if (dev->irqo <= 0) { +			dev_err(dev->dev, "Found irqi but not irqo\n"); +			return -ENODEV; +		} +	} else { +		dev->irqi = 0; +	} + +	dev->gadget.name = driver_name; +	dev->gadget.max_speed = USB_SPEED_HIGH; +	dev->gadget.ops = &gr_ops; +	dev->gadget.quirk_ep_out_aligned_size = true; + +	spin_lock_init(&dev->lock); +	dev->regs = regs; + +	platform_set_drvdata(pdev, dev); + +	/* Determine number of endpoints and data interface mode */ +	status = gr_read32(&dev->regs->status); +	dev->nepi = ((status & GR_STATUS_NEPI_MASK) >> GR_STATUS_NEPI_POS) + 1; +	dev->nepo = ((status & GR_STATUS_NEPO_MASK) >> GR_STATUS_NEPO_POS) + 1; + +	if (!(status & GR_STATUS_DM)) { +		dev_err(dev->dev, "Slave mode cores are not supported\n"); +		return -ENODEV; +	} + +	/* --- Effects of the following calls might need explicit cleanup --- */ + +	/* Create DMA pool for descriptors */ +	dev->desc_pool = dma_pool_create("desc_pool", dev->dev, +					 sizeof(struct gr_dma_desc), 4, 0); +	if (!dev->desc_pool) { +		dev_err(dev->dev, "Could not allocate DMA pool"); +		return -ENOMEM; +	} + +	spin_lock(&dev->lock); + +	/* Inside lock so that no gadget can use this udc until probe is done */ +	retval = usb_add_gadget_udc(dev->dev, &dev->gadget); +	if (retval) { +		dev_err(dev->dev, "Could not add gadget udc"); +		goto out; +	} +	dev->added = 1; + +	retval = gr_udc_init(dev); +	if (retval) +		goto out; + +	gr_dfs_create(dev); + +	/* Clear all interrupt enables that might be left on since last boot */ +	gr_disable_interrupts_and_pullup(dev); + +	retval = gr_request_irq(dev, dev->irq); +	if (retval) { +		dev_err(dev->dev, "Failed to request irq %d\n", dev->irq); +		goto out; +	} + +	if (dev->irqi) { +		retval = gr_request_irq(dev, dev->irqi); +		if (retval) { +			dev_err(dev->dev, "Failed to request irqi %d\n", +				dev->irqi); +			goto out; +		} +		retval = gr_request_irq(dev, dev->irqo); +		if (retval) { +			dev_err(dev->dev, "Failed to request irqo %d\n", +				dev->irqo); +			goto out; +		} +	} + +	if (dev->irqi) +		dev_info(dev->dev, "regs: %p, irqs %d, %d, %d\n", dev->regs, +			 dev->irq, dev->irqi, dev->irqo); +	else +		dev_info(dev->dev, "regs: %p, irq %d\n", dev->regs, dev->irq); + +out: +	spin_unlock(&dev->lock); + +	if (retval) +		gr_remove(pdev); + +	return retval; +} + +static struct of_device_id gr_match[] = { +	{.name = "GAISLER_USBDC"}, +	{.name = "01_021"}, +	{}, +}; +MODULE_DEVICE_TABLE(of, gr_match); + +static struct platform_driver gr_driver = { +	.driver = { +		.name = DRIVER_NAME, +		.owner = THIS_MODULE, +		.of_match_table = gr_match, +	}, +	.probe = gr_probe, +	.remove = gr_remove, +}; +module_platform_driver(gr_driver); + +MODULE_AUTHOR("Aeroflex Gaisler AB."); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/gr_udc.h b/drivers/usb/gadget/gr_udc.h new file mode 100644 index 00000000000..8388897d9ec --- /dev/null +++ b/drivers/usb/gadget/gr_udc.h @@ -0,0 +1,220 @@ +/* + * USB Peripheral Controller driver for Aeroflex Gaisler GRUSBDC. + * + * 2013 (c) Aeroflex Gaisler AB + * + * This driver supports GRUSBDC USB Device Controller cores available in the + * GRLIB VHDL IP core library. + * + * Full documentation of the GRUSBDC core can be found here: + * http://www.gaisler.com/products/grlib/grip.pdf + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * Contributors: + * - Andreas Larsson <andreas@gaisler.com> + * - Marko Isomaki + */ + +/* Control registers on the AMBA bus */ + +#define GR_MAXEP	16	/* Max # endpoints for *each* direction */ + +struct gr_epregs { +	u32 epctrl; +	union { +		struct { /* Slave mode*/ +			u32 slvctrl; +			u32 slvdata; +		}; +		struct { /* DMA mode*/ +			u32 dmactrl; +			u32 dmaaddr; +		}; +	}; +	u32 epstat; +}; + +struct gr_regs { +	struct gr_epregs	epo[GR_MAXEP];	/* 0x000 - 0x0fc */ +	struct gr_epregs	epi[GR_MAXEP];	/* 0x100 - 0x1fc */ +	u32			control;	/* 0x200 */ +	u32			status;		/* 0x204 */ +}; + +#define GR_EPCTRL_BUFSZ_SCALER	8 +#define GR_EPCTRL_BUFSZ_MASK	0xffe00000 +#define GR_EPCTRL_BUFSZ_POS	21 +#define GR_EPCTRL_PI		BIT(20) +#define GR_EPCTRL_CB		BIT(19) +#define GR_EPCTRL_CS		BIT(18) +#define GR_EPCTRL_MAXPL_MASK	0x0003ff80 +#define GR_EPCTRL_MAXPL_POS	7 +#define GR_EPCTRL_NT_MASK	0x00000060 +#define GR_EPCTRL_NT_POS	5 +#define GR_EPCTRL_TT_MASK	0x00000018 +#define GR_EPCTRL_TT_POS	3 +#define GR_EPCTRL_EH		BIT(2) +#define GR_EPCTRL_ED		BIT(1) +#define GR_EPCTRL_EV		BIT(0) + +#define GR_DMACTRL_AE		BIT(10) +#define GR_DMACTRL_AD		BIT(3) +#define GR_DMACTRL_AI		BIT(2) +#define GR_DMACTRL_IE		BIT(1) +#define GR_DMACTRL_DA		BIT(0) + +#define GR_EPSTAT_PT		BIT(29) +#define GR_EPSTAT_PR		BIT(29) +#define GR_EPSTAT_B1CNT_MASK	0x1fff0000 +#define GR_EPSTAT_B1CNT_POS	16 +#define GR_EPSTAT_B0CNT_MASK	0x0000fff8 +#define GR_EPSTAT_B0CNT_POS	3 +#define GR_EPSTAT_B1		BIT(2) +#define GR_EPSTAT_B0		BIT(1) +#define GR_EPSTAT_BS		BIT(0) + +#define GR_CONTROL_SI		BIT(31) +#define GR_CONTROL_UI		BIT(30) +#define GR_CONTROL_VI		BIT(29) +#define GR_CONTROL_SP		BIT(28) +#define GR_CONTROL_FI		BIT(27) +#define GR_CONTROL_EP		BIT(14) +#define GR_CONTROL_DH		BIT(13) +#define GR_CONTROL_RW		BIT(12) +#define GR_CONTROL_TS_MASK	0x00000e00 +#define GR_CONTROL_TS_POS	9 +#define GR_CONTROL_TM		BIT(8) +#define GR_CONTROL_UA_MASK	0x000000fe +#define GR_CONTROL_UA_POS	1 +#define GR_CONTROL_SU		BIT(0) + +#define GR_STATUS_NEPI_MASK	0xf0000000 +#define GR_STATUS_NEPI_POS	28 +#define GR_STATUS_NEPO_MASK	0x0f000000 +#define GR_STATUS_NEPO_POS	24 +#define GR_STATUS_DM		BIT(23) +#define GR_STATUS_SU		BIT(17) +#define GR_STATUS_UR		BIT(16) +#define GR_STATUS_VB		BIT(15) +#define GR_STATUS_SP		BIT(14) +#define GR_STATUS_AF_MASK	0x00003800 +#define GR_STATUS_AF_POS	11 +#define GR_STATUS_FN_MASK	0x000007ff +#define GR_STATUS_FN_POS	0 + + +#define MAX_CTRL_PL_SIZE 64 /* As per USB standard for full and high speed */ + +/*-------------------------------------------------------------------------*/ + +/* Driver data structures and utilities */ + +struct gr_dma_desc { +	u32 ctrl; +	u32 data; +	u32 next; + +	/* These must be last because hw uses the previous three */ +	u32 paddr; +	struct gr_dma_desc *next_desc; +}; + +#define GR_DESC_OUT_CTRL_SE		BIT(17) +#define GR_DESC_OUT_CTRL_IE		BIT(15) +#define GR_DESC_OUT_CTRL_NX		BIT(14) +#define GR_DESC_OUT_CTRL_EN		BIT(13) +#define GR_DESC_OUT_CTRL_LEN_MASK	0x00001fff + +#define GR_DESC_IN_CTRL_MO		BIT(18) +#define GR_DESC_IN_CTRL_PI		BIT(17) +#define GR_DESC_IN_CTRL_ML		BIT(16) +#define GR_DESC_IN_CTRL_IE		BIT(15) +#define GR_DESC_IN_CTRL_NX		BIT(14) +#define GR_DESC_IN_CTRL_EN		BIT(13) +#define GR_DESC_IN_CTRL_LEN_MASK	0x00001fff + +#define GR_DESC_DMAADDR_MASK		0xfffffffc + +struct gr_ep { +	struct usb_ep ep; +	struct gr_udc *dev; +	u16 bytes_per_buffer; +	unsigned int dma_start; +	struct gr_epregs __iomem *regs; + +	unsigned num:8; +	unsigned is_in:1; +	unsigned stopped:1; +	unsigned wedged:1; +	unsigned callback:1; + +	/* analogous to a host-side qh */ +	struct list_head queue; + +	struct list_head ep_list; +}; + +struct gr_request { +	struct usb_request req; +	struct list_head queue; + +	/* Chain of dma descriptors */ +	struct gr_dma_desc *first_desc; /* First in the chain */ +	struct gr_dma_desc *curr_desc; /* Current descriptor */ +	struct gr_dma_desc *last_desc; /* Last in the chain */ + +	u8 setup; /* Setup packet */ +}; + +enum gr_ep0state { +	GR_EP0_DISCONNECT = 0,	/* No host */ +	GR_EP0_SETUP,		/* Between STATUS ack and SETUP report */ +	GR_EP0_IDATA,		/* IN data stage */ +	GR_EP0_ODATA,		/* OUT data stage */ +	GR_EP0_ISTATUS,		/* Status stage after IN data stage */ +	GR_EP0_OSTATUS,		/* Status stage after OUT data stage */ +	GR_EP0_STALL,		/* Data or status stages */ +	GR_EP0_SUSPEND,		/* USB suspend */ +}; + +struct gr_udc { +	struct usb_gadget gadget; +	struct gr_ep epi[GR_MAXEP]; +	struct gr_ep epo[GR_MAXEP]; +	struct usb_gadget_driver *driver; +	struct dma_pool *desc_pool; +	struct device *dev; + +	enum gr_ep0state ep0state; +	struct gr_request *ep0reqo; +	struct gr_request *ep0reqi; + +	struct gr_regs __iomem *regs; +	int irq; +	int irqi; +	int irqo; + +	unsigned added:1; +	unsigned irq_enabled:1; +	unsigned remote_wakeup:1; + +	u8 test_mode; + +	enum usb_device_state suspended_from; + +	unsigned int nepi; +	unsigned int nepo; + +	struct list_head ep_list; + +	spinlock_t lock; /* General lock, a.k.a. "dev->lock" in comments */ + +	struct dentry *dfs_root; +	struct dentry *dfs_state; +}; + +#define to_gr_udc(gadget)	(container_of((gadget), struct gr_udc, gadget)) diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index b94c049ab0d..2e4ce770490 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -439,11 +439,9 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)  	/* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */  	value = -ENOMEM; -	kbuf = kmalloc (len, GFP_KERNEL); -	if (!kbuf) -		goto free1; -	if (copy_from_user (kbuf, buf, len)) { -		value = -EFAULT; +	kbuf = memdup_user(buf, len); +	if (!kbuf) { +		value = PTR_ERR(kbuf);  		goto free1;  	} @@ -452,7 +450,6 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)  		data->name, len, (int) value);  free1:  	mutex_unlock(&data->lock); -	kfree (kbuf);  	return value;  } @@ -1267,8 +1264,13 @@ dev_release (struct inode *inode, struct file *fd)  	kfree (dev->buf);  	dev->buf = NULL; -	put_dev (dev); +	/* other endpoints were all decoupled from this device */ +	spin_lock_irq(&dev->lock); +	dev->state = STATE_DEV_DISABLED; +	spin_unlock_irq(&dev->lock); + +	put_dev (dev);  	return 0;  } @@ -1497,6 +1499,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  		 */  		if (value == 0) {  			INFO (dev, "configuration #%d\n", dev->current_config); +			usb_gadget_set_state(gadget, USB_STATE_CONFIGURED);  			if (dev->usermode_setup) {  				dev->setup_can_stall = 0;  				goto delegate; @@ -1504,7 +1507,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)  		}  		break; -#ifndef	CONFIG_USB_GADGET_PXA25X +#ifndef	CONFIG_USB_PXA25X  	/* PXA automagically handles this request too */  	case USB_REQ_GET_CONFIGURATION:  		if (ctrl->bRequestType != 0x80) @@ -2046,6 +2049,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)  		return -ESRCH;  	/* fake probe to determine $CHIP */ +	CHIP = NULL;  	usb_gadget_probe_driver(&probe_driver);  	if (!CHIP)  		return -ENODEV; diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c index 67128be1e1b..e471580a2a3 100644 --- a/drivers/usb/gadget/lpc32xx_udc.c +++ b/drivers/usb/gadget/lpc32xx_udc.c @@ -55,7 +55,6 @@  #include <mach/hardware.h>  #include <linux/io.h>  #include <asm/irq.h> -#include <asm/system.h>  #include <mach/platform.h>  #include <mach/irqs.h> @@ -1449,7 +1448,7 @@ static void udc_reinit(struct lpc32xx_udc *udc)  		if (i != 0)  			list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); -		ep->ep.maxpacket = ep->maxpacket; +		usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket);  		INIT_LIST_HEAD(&ep->queue);  		ep->req_pending = 0;  	} @@ -3078,7 +3077,9 @@ static int __init lpc32xx_udc_probe(struct platform_device *pdev)  		 udc->isp1301_i2c_client->addr);  	pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; -	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); +	if (retval) +		goto resource_fail;  	udc->board = &lpc32xx_usbddata; @@ -3293,9 +3294,9 @@ usb_clk_enable_fail:  pll_set_fail:  	clk_disable(udc->usb_pll_clk);  pll_enable_fail: -	clk_put(udc->usb_slv_clk); -usb_otg_clk_get_fail:  	clk_put(udc->usb_otg_clk); +usb_otg_clk_get_fail: +	clk_put(udc->usb_slv_clk);  usb_clk_get_fail:  	clk_put(udc->usb_pll_clk);  pll_get_fail: diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index d5f050d30ed..0d17174b86f 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1594,7 +1594,6 @@ static int __init m66592_probe(struct platform_device *pdev)  	m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL);  	if (m66592 == NULL) {  		ret = -ENOMEM; -		pr_err("kzalloc error\n");  		goto clean_up;  	} @@ -1647,9 +1646,9 @@ static int __init m66592_probe(struct platform_device *pdev)  		INIT_LIST_HEAD(&ep->queue);  		ep->ep.name = m66592_ep_name[i];  		ep->ep.ops = &m66592_ep_ops; -		ep->ep.maxpacket = 512; +		usb_ep_set_maxpacket_limit(&ep->ep, 512);  	} -	m66592->ep[0].ep.maxpacket = 64; +	usb_ep_set_maxpacket_limit(&m66592->ep[0].ep, 64);  	m66592->ep[0].pipenum = 0;  	m66592->ep[0].fifoaddr = M66592_CFIFO;  	m66592->ep[0].fifosel = M66592_CFIFOSEL; diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c index 080e577773d..8e27a8c9644 100644 --- a/drivers/usb/gadget/mass_storage.c +++ b/drivers/usb/gadget/mass_storage.c @@ -37,16 +37,16 @@  #define DRIVER_DESC		"Mass Storage Gadget"  #define DRIVER_VERSION		"2009/09/11" -/*-------------------------------------------------------------------------*/ -  /* - * kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module.  So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. + * Thanks to NetChip Technologies for donating this product ID. + * + * DO NOT REUSE THESE IDs with any other driver!!  Ever!! + * Instead:  allocate your own, using normal USB-IF procedures.   */ -#include "f_mass_storage.c" +#define FSG_VENDOR_ID	0x0525	/* NetChip */ +#define FSG_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */ + +#include "f_mass_storage.h"  /*-------------------------------------------------------------------------*/  USB_GADGET_COMPOSITE_OPTIONS(); @@ -97,11 +97,28 @@ static struct usb_gadget_strings *dev_strings[] = {  	NULL,  }; +static struct usb_function_instance *fi_msg; +static struct usb_function *f_msg; +  /****************************** Configurations ******************************/  static struct fsg_module_parameters mod_data = {  	.stall = 1  }; +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; + +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS + +#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ +  FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);  static unsigned long msg_registered; @@ -115,13 +132,7 @@ static int msg_thread_exits(struct fsg_common *common)  static int __init msg_do_config(struct usb_configuration *c)  { -	static const struct fsg_operations ops = { -		.thread_exits = msg_thread_exits, -	}; -	static struct fsg_common common; - -	struct fsg_common *retp; -	struct fsg_config config; +	struct fsg_opts *opts;  	int ret;  	if (gadget_is_otg(c->cdev->gadget)) { @@ -129,15 +140,24 @@ static int __init msg_do_config(struct usb_configuration *c)  		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;  	} -	fsg_config_from_params(&config, &mod_data); -	config.ops = &ops; +	opts = fsg_opts_from_func_inst(fi_msg); + +	f_msg = usb_get_function(fi_msg); +	if (IS_ERR(f_msg)) +		return PTR_ERR(f_msg); + +	ret = fsg_common_run_thread(opts->common); +	if (ret) +		goto put_func; + +	ret = usb_add_function(c, f_msg); +	if (ret) +		goto put_func; -	retp = fsg_common_init(&common, c->cdev, &config); -	if (IS_ERR(retp)) -		return PTR_ERR(retp); +	return 0; -	ret = fsg_bind_config(c->cdev, c, &common); -	fsg_common_put(&common); +put_func: +	usb_put_function(f_msg);  	return ret;  } @@ -152,23 +172,79 @@ static struct usb_configuration msg_config_driver = {  static int __init msg_bind(struct usb_composite_dev *cdev)  { +	static const struct fsg_operations ops = { +		.thread_exits = msg_thread_exits, +	}; +	struct fsg_opts *opts; +	struct fsg_config config;  	int status; +	fi_msg = usb_get_function_instance("mass_storage"); +	if (IS_ERR(fi_msg)) +		return PTR_ERR(fi_msg); + +	fsg_config_from_params(&config, &mod_data, fsg_num_buffers); +	opts = fsg_opts_from_func_inst(fi_msg); + +	opts->no_configfs = true; +	status = fsg_common_set_num_buffers(opts->common, fsg_num_buffers); +	if (status) +		goto fail; + +	status = fsg_common_set_nluns(opts->common, config.nluns); +	if (status) +		goto fail_set_nluns; + +	fsg_common_set_ops(opts->common, &ops); + +	status = fsg_common_set_cdev(opts->common, cdev, config.can_stall); +	if (status) +		goto fail_set_cdev; + +	fsg_common_set_sysfs(opts->common, true); +	status = fsg_common_create_luns(opts->common, &config); +	if (status) +		goto fail_set_cdev; + +	fsg_common_set_inquiry_string(opts->common, config.vendor_name, +				      config.product_name); +  	status = usb_string_ids_tab(cdev, strings_dev);  	if (status < 0) -		return status; +		goto fail_string_ids;  	msg_device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;  	status = usb_add_config(cdev, &msg_config_driver, msg_do_config);  	if (status < 0) -		return status; +		goto fail_string_ids; +  	usb_composite_overwrite_options(cdev, &coverwrite);  	dev_info(&cdev->gadget->dev,  		 DRIVER_DESC ", version: " DRIVER_VERSION "\n");  	set_bit(0, &msg_registered);  	return 0; + +fail_string_ids: +	fsg_common_remove_luns(opts->common); +fail_set_cdev: +	fsg_common_free_luns(opts->common); +fail_set_nluns: +	fsg_common_free_buffers(opts->common); +fail: +	usb_put_function_instance(fi_msg); +	return status;  } +static int msg_unbind(struct usb_composite_dev *cdev) +{ +	if (!IS_ERR(f_msg)) +		usb_put_function(f_msg); + +	if (!IS_ERR(fi_msg)) +		usb_put_function_instance(fi_msg); + +	return 0; +}  /****************************** Some noise ******************************/ @@ -179,6 +255,7 @@ static __refdata struct usb_composite_driver msg_driver = {  	.needs_serial	= 1,  	.strings	= dev_strings,  	.bind		= msg_bind, +	.unbind		= msg_unbind,  };  MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c index 2a1ebefd8f9..940f6cde8e8 100644 --- a/drivers/usb/gadget/multi.c +++ b/drivers/usb/gadget/multi.c @@ -15,6 +15,7 @@  #include <linux/kernel.h>  #include <linux/module.h> +#include <linux/netdevice.h>  #include "u_serial.h"  #if defined USB_ETH_RNDIS @@ -32,22 +33,11 @@ MODULE_AUTHOR("Michal Nazarewicz");  MODULE_LICENSE("GPL"); -/***************************** All the files... *****************************/ +#include "f_mass_storage.h" -/* - * kbuild is not very cooperative with respect to linking separately - * compiled library objects into one module.  So for now we won't use - * separate compilation ... ensuring init/exit sections work to shrink - * the runtime footprint, and giving us at least some parts of what - * a "gcc --combine ... part1.c part2.c part3.c ... " build would. - */ -#include "f_mass_storage.c" - -#define USBF_ECM_INCLUDED -#include "f_ecm.c" +#include "u_ecm.h"  #ifdef USB_ETH_RNDIS -#  define USB_FRNDIS_INCLUDED -#  include "f_rndis.c" +#  include "u_rndis.h"  #  include "rndis.h"  #endif  #include "u_ether.h" @@ -132,22 +122,36 @@ static struct usb_gadget_strings *dev_strings[] = {  /****************************** Configurations ******************************/  static struct fsg_module_parameters fsg_mod_data = { .stall = 1 }; -FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data); +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; -static struct fsg_common fsg_common; +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS -static u8 host_mac[ETH_ALEN]; +#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ + +FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);  static struct usb_function_instance *fi_acm; -static struct eth_dev *the_dev; +static struct usb_function_instance *fi_msg;  /********** RNDIS **********/  #ifdef USB_ETH_RNDIS +static struct usb_function_instance *fi_rndis;  static struct usb_function *f_acm_rndis; +static struct usb_function *f_rndis; +static struct usb_function *f_msg_rndis;  static __init int rndis_do_config(struct usb_configuration *c)  { +	struct fsg_opts *fsg_opts;  	int ret;  	if (gadget_is_otg(c->cdev->gadget)) { @@ -155,31 +159,54 @@ static __init int rndis_do_config(struct usb_configuration *c)  		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;  	} -	ret = rndis_bind_config(c, host_mac, the_dev); +	f_rndis = usb_get_function(fi_rndis); +	if (IS_ERR(f_rndis)) +		return PTR_ERR(f_rndis); + +	ret = usb_add_function(c, f_rndis);  	if (ret < 0) -		return ret; +		goto err_func_rndis;  	f_acm_rndis = usb_get_function(fi_acm); -	if (IS_ERR(f_acm_rndis)) -		return PTR_ERR(f_acm_rndis); +	if (IS_ERR(f_acm_rndis)) { +		ret = PTR_ERR(f_acm_rndis); +		goto err_func_acm; +	}  	ret = usb_add_function(c, f_acm_rndis);  	if (ret)  		goto err_conf; -	ret = fsg_bind_config(c->cdev, c, &fsg_common); -	if (ret < 0) +	f_msg_rndis = usb_get_function(fi_msg); +	if (IS_ERR(f_msg_rndis)) { +		ret = PTR_ERR(f_msg_rndis);  		goto err_fsg; +	} + +	fsg_opts = fsg_opts_from_func_inst(fi_msg); +	ret = fsg_common_run_thread(fsg_opts->common); +	if (ret) +		goto err_run; + +	ret = usb_add_function(c, f_msg_rndis); +	if (ret) +		goto err_run;  	return 0; +err_run: +	usb_put_function(f_msg_rndis);  err_fsg:  	usb_remove_function(c, f_acm_rndis);  err_conf:  	usb_put_function(f_acm_rndis); +err_func_acm: +	usb_remove_function(c, f_rndis); +err_func_rndis: +	usb_put_function(f_rndis);  	return ret;  } -static int rndis_config_register(struct usb_composite_dev *cdev) +static __ref int rndis_config_register(struct usb_composite_dev *cdev)  {  	static struct usb_configuration config = {  		.bConfigurationValue	= MULTI_RNDIS_CONFIG_NUM, @@ -194,7 +221,7 @@ static int rndis_config_register(struct usb_composite_dev *cdev)  #else -static int rndis_config_register(struct usb_composite_dev *cdev) +static __ref int rndis_config_register(struct usb_composite_dev *cdev)  {  	return 0;  } @@ -205,10 +232,14 @@ static int rndis_config_register(struct usb_composite_dev *cdev)  /********** CDC ECM **********/  #ifdef CONFIG_USB_G_MULTI_CDC +static struct usb_function_instance *fi_ecm;  static struct usb_function *f_acm_multi; +static struct usb_function *f_ecm; +static struct usb_function *f_msg_multi;  static __init int cdc_do_config(struct usb_configuration *c)  { +	struct fsg_opts *fsg_opts;  	int ret;  	if (gadget_is_otg(c->cdev->gadget)) { @@ -216,32 +247,55 @@ static __init int cdc_do_config(struct usb_configuration *c)  		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;  	} -	ret = ecm_bind_config(c, host_mac, the_dev); +	f_ecm = usb_get_function(fi_ecm); +	if (IS_ERR(f_ecm)) +		return PTR_ERR(f_ecm); + +	ret = usb_add_function(c, f_ecm);  	if (ret < 0) -		return ret; +		goto err_func_ecm;  	/* implicit port_num is zero */  	f_acm_multi = usb_get_function(fi_acm); -	if (IS_ERR(f_acm_multi)) -		return PTR_ERR(f_acm_multi); +	if (IS_ERR(f_acm_multi)) { +		ret = PTR_ERR(f_acm_multi); +		goto err_func_acm; +	}  	ret = usb_add_function(c, f_acm_multi);  	if (ret)  		goto err_conf; -	ret = fsg_bind_config(c->cdev, c, &fsg_common); -	if (ret < 0) +	f_msg_multi = usb_get_function(fi_msg); +	if (IS_ERR(f_msg_multi)) { +		ret = PTR_ERR(f_msg_multi);  		goto err_fsg; +	} + +	fsg_opts = fsg_opts_from_func_inst(fi_msg); +	ret = fsg_common_run_thread(fsg_opts->common); +	if (ret) +		goto err_run; + +	ret = usb_add_function(c, f_msg_multi); +	if (ret) +		goto err_run;  	return 0; +err_run: +	usb_put_function(f_msg_multi);  err_fsg:  	usb_remove_function(c, f_acm_multi);  err_conf:  	usb_put_function(f_acm_multi); +err_func_acm: +	usb_remove_function(c, f_ecm); +err_func_ecm: +	usb_put_function(f_ecm);  	return ret;  } -static int cdc_config_register(struct usb_composite_dev *cdev) +static __ref int cdc_config_register(struct usb_composite_dev *cdev)  {  	static struct usb_configuration config = {  		.bConfigurationValue	= MULTI_CDC_CONFIG_NUM, @@ -256,7 +310,7 @@ static int cdc_config_register(struct usb_composite_dev *cdev)  #else -static int cdc_config_register(struct usb_composite_dev *cdev) +static __ref int cdc_config_register(struct usb_composite_dev *cdev)  {  	return 0;  } @@ -270,19 +324,67 @@ static int cdc_config_register(struct usb_composite_dev *cdev)  static int __ref multi_bind(struct usb_composite_dev *cdev)  {  	struct usb_gadget *gadget = cdev->gadget; +#ifdef CONFIG_USB_G_MULTI_CDC +	struct f_ecm_opts *ecm_opts; +#endif +#ifdef USB_ETH_RNDIS +	struct f_rndis_opts *rndis_opts; +#endif +	struct fsg_opts *fsg_opts; +	struct fsg_config config;  	int status;  	if (!can_support_ecm(cdev->gadget)) {  		dev_err(&gadget->dev, "controller '%s' not usable\n", -		        gadget->name); +			gadget->name);  		return -EINVAL;  	} -	/* set up network link layer */ -	the_dev = gether_setup(cdev->gadget, dev_addr, host_addr, host_mac, -			       qmult); -	if (IS_ERR(the_dev)) -		return PTR_ERR(the_dev); +#ifdef CONFIG_USB_G_MULTI_CDC +	fi_ecm = usb_get_function_instance("ecm"); +	if (IS_ERR(fi_ecm)) +		return PTR_ERR(fi_ecm); + +	ecm_opts = container_of(fi_ecm, struct f_ecm_opts, func_inst); + +	gether_set_qmult(ecm_opts->net, qmult); +	if (!gether_set_host_addr(ecm_opts->net, host_addr)) +		pr_info("using host ethernet address: %s", host_addr); +	if (!gether_set_dev_addr(ecm_opts->net, dev_addr)) +		pr_info("using self ethernet address: %s", dev_addr); +#endif + +#ifdef USB_ETH_RNDIS +	fi_rndis = usb_get_function_instance("rndis"); +	if (IS_ERR(fi_rndis)) { +		status = PTR_ERR(fi_rndis); +		goto fail; +	} + +	rndis_opts = container_of(fi_rndis, struct f_rndis_opts, func_inst); + +	gether_set_qmult(rndis_opts->net, qmult); +	if (!gether_set_host_addr(rndis_opts->net, host_addr)) +		pr_info("using host ethernet address: %s", host_addr); +	if (!gether_set_dev_addr(rndis_opts->net, dev_addr)) +		pr_info("using self ethernet address: %s", dev_addr); +#endif + +#if (defined CONFIG_USB_G_MULTI_CDC && defined USB_ETH_RNDIS) +	/* +	 * If both ecm and rndis are selected then: +	 *	1) rndis borrows the net interface from ecm +	 *	2) since the interface is shared it must not be bound +	 *	twice - in ecm's _and_ rndis' binds, so do it here. +	 */ +	gether_set_gadget(ecm_opts->net, cdev->gadget); +	status = gether_register_netdev(ecm_opts->net); +	if (status) +		goto fail0; + +	rndis_borrow_net(fi_rndis, ecm_opts->net); +	ecm_opts->bound = true; +#endif  	/* set up serial link layer */  	fi_acm = usb_get_function_instance("acm"); @@ -292,57 +394,102 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)  	}  	/* set up mass storage function */ -	{ -		void *retp; -		retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data); -		if (IS_ERR(retp)) { -			status = PTR_ERR(retp); -			goto fail1; -		} +	fi_msg = usb_get_function_instance("mass_storage"); +	if (IS_ERR(fi_msg)) { +		status = PTR_ERR(fi_msg); +		goto fail1;  	} +	fsg_config_from_params(&config, &fsg_mod_data, fsg_num_buffers); +	fsg_opts = fsg_opts_from_func_inst(fi_msg); + +	fsg_opts->no_configfs = true; +	status = fsg_common_set_num_buffers(fsg_opts->common, fsg_num_buffers); +	if (status) +		goto fail2; + +	status = fsg_common_set_nluns(fsg_opts->common, config.nluns); +	if (status) +		goto fail_set_nluns; + +	status = fsg_common_set_cdev(fsg_opts->common, cdev, config.can_stall); +	if (status) +		goto fail_set_cdev; + +	fsg_common_set_sysfs(fsg_opts->common, true); +	status = fsg_common_create_luns(fsg_opts->common, &config); +	if (status) +		goto fail_set_cdev; + +	fsg_common_set_inquiry_string(fsg_opts->common, config.vendor_name, +				      config.product_name);  	/* allocate string IDs */  	status = usb_string_ids_tab(cdev, strings_dev);  	if (unlikely(status < 0)) -		goto fail2; +		goto fail_string_ids;  	device_desc.iProduct = strings_dev[USB_GADGET_PRODUCT_IDX].id;  	/* register configurations */  	status = rndis_config_register(cdev);  	if (unlikely(status < 0)) -		goto fail2; +		goto fail_string_ids;  	status = cdc_config_register(cdev);  	if (unlikely(status < 0)) -		goto fail2; +		goto fail_string_ids;  	usb_composite_overwrite_options(cdev, &coverwrite);  	/* we're done */  	dev_info(&gadget->dev, DRIVER_DESC "\n"); -	fsg_common_put(&fsg_common);  	return 0;  	/* error recovery */ +fail_string_ids: +	fsg_common_remove_luns(fsg_opts->common); +fail_set_cdev: +	fsg_common_free_luns(fsg_opts->common); +fail_set_nluns: +	fsg_common_free_buffers(fsg_opts->common);  fail2: -	fsg_common_put(&fsg_common); +	usb_put_function_instance(fi_msg);  fail1:  	usb_put_function_instance(fi_acm);  fail0: -	gether_cleanup(the_dev); +#ifdef USB_ETH_RNDIS +	usb_put_function_instance(fi_rndis); +fail: +#endif +#ifdef CONFIG_USB_G_MULTI_CDC +	usb_put_function_instance(fi_ecm); +#endif  	return status;  }  static int __exit multi_unbind(struct usb_composite_dev *cdev)  {  #ifdef CONFIG_USB_G_MULTI_CDC +	usb_put_function(f_msg_multi); +#endif +#ifdef USB_ETH_RNDIS +	usb_put_function(f_msg_rndis); +#endif +	usb_put_function_instance(fi_msg); +#ifdef CONFIG_USB_G_MULTI_CDC  	usb_put_function(f_acm_multi);  #endif  #ifdef USB_ETH_RNDIS  	usb_put_function(f_acm_rndis);  #endif  	usb_put_function_instance(fi_acm); -	gether_cleanup(the_dev); +#ifdef USB_ETH_RNDIS +	usb_put_function(f_rndis); +	usb_put_function_instance(fi_rndis); +#endif +#ifdef CONFIG_USB_G_MULTI_CDC +	usb_put_function(f_ecm); +	usb_put_function_instance(fi_ecm); +#endif  	return 0;  } diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c index bbb6e98c438..16248711c15 100644 --- a/drivers/usb/gadget/mv_u3d_core.c +++ b/drivers/usb/gadget/mv_u3d_core.c @@ -15,7 +15,6 @@  #include <linux/sched.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/notifier.h> @@ -298,10 +297,8 @@ static struct mv_u3d_trb *mv_u3d_build_trb_one(struct mv_u3d_req *req,  	u3d = req->ep->u3d;  	trb = kzalloc(sizeof(*trb), GFP_ATOMIC); -	if (!trb) { -		dev_err(u3d->dev, "%s, trb alloc fail\n", __func__); +	if (!trb)  		return NULL; -	}  	/*  	 * Be careful that no _GFP_HIGHMEM is set, @@ -310,6 +307,7 @@ static struct mv_u3d_trb *mv_u3d_build_trb_one(struct mv_u3d_req *req,  	 */  	trb_hw = dma_pool_alloc(u3d->trb_pool, GFP_ATOMIC, dma);  	if (!trb_hw) { +		kfree(trb);  		dev_err(u3d->dev,  			"%s, dma_pool_alloc fail\n", __func__);  		return NULL; @@ -446,16 +444,12 @@ static int mv_u3d_req_to_trb(struct mv_u3d_req *req)  			trb_num++;  		trb = kcalloc(trb_num, sizeof(*trb), GFP_ATOMIC); -		if (!trb) { -			dev_err(u3d->dev, -					"%s, trb alloc fail\n", __func__); +		if (!trb)  			return -ENOMEM; -		}  		trb_hw = kcalloc(trb_num, sizeof(*trb_hw), GFP_ATOMIC);  		if (!trb_hw) { -			dev_err(u3d->dev, -					"%s, trb_hw alloc fail\n", __func__); +			kfree(trb);  			return -ENOMEM;  		} @@ -645,6 +639,7 @@ static int  mv_u3d_ep_disable(struct usb_ep *_ep)  	struct mv_u3d_ep *ep;  	struct mv_u3d_ep_context *ep_context;  	u32 epxcr, direction; +	unsigned long flags;  	if (!_ep)  		return -EINVAL; @@ -661,7 +656,9 @@ static int  mv_u3d_ep_disable(struct usb_ep *_ep)  	direction = mv_u3d_ep_dir(ep);  	/* nuke all pending requests (does flush) */ +	spin_lock_irqsave(&u3d->lock, flags);  	mv_u3d_nuke(ep, -ESHUTDOWN); +	spin_unlock_irqrestore(&u3d->lock, flags);  	/* Disable the endpoint for Rx or Tx and reset the endpoint type */  	if (direction == MV_U3D_EP_DIR_OUT) { @@ -1331,7 +1328,7 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d)  	ep->ep.name = ep->name;  	ep->ep.ops = &mv_u3d_ep_ops;  	ep->wedge = 0; -	ep->ep.maxpacket = MV_U3D_EP0_MAX_PKT_SIZE; +	usb_ep_set_maxpacket_limit(&ep->ep, MV_U3D_EP0_MAX_PKT_SIZE);  	ep->ep_num = 0;  	ep->ep.desc = &mv_u3d_ep0_desc;  	INIT_LIST_HEAD(&ep->queue); @@ -1356,7 +1353,7 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d)  		ep->ep.name = ep->name;  		ep->ep.ops = &mv_u3d_ep_ops; -		ep->ep.maxpacket = (unsigned short) ~0; +		usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);  		ep->ep_num = i / 2;  		INIT_LIST_HEAD(&ep->queue); @@ -1807,7 +1804,6 @@ static int mv_u3d_probe(struct platform_device *dev)  	u3d = kzalloc(sizeof(*u3d), GFP_KERNEL);  	if (!u3d) { -		dev_err(&dev->dev, "failed to allocate memory for u3d\n");  		retval = -ENOMEM;  		goto err_alloc_private;  	} @@ -1901,7 +1897,6 @@ static int mv_u3d_probe(struct platform_device *dev)  	size = u3d->max_eps * sizeof(struct mv_u3d_ep) * 2;  	u3d->eps = kzalloc(size, GFP_KERNEL);  	if (!u3d->eps) { -		dev_err(&dev->dev, "allocate ep memory failed\n");  		retval = -ENOMEM;  		goto err_alloc_eps;  	} @@ -1909,7 +1904,6 @@ static int mv_u3d_probe(struct platform_device *dev)  	/* initialize ep0 status request structure */  	u3d->status_req = kzalloc(sizeof(struct mv_u3d_req) + 8, GFP_KERNEL);  	if (!u3d->status_req) { -		dev_err(&dev->dev, "allocate status_req memory failed\n");  		retval = -ENOMEM;  		goto err_alloc_status_req;  	} @@ -1933,7 +1927,7 @@ static int mv_u3d_probe(struct platform_device *dev)  	}  	u3d->irq = r->start;  	if (request_irq(u3d->irq, mv_u3d_irq, -		IRQF_DISABLED | IRQF_SHARED, driver_name, u3d)) { +		IRQF_SHARED, driver_name, u3d)) {  		u3d->irq = 0;  		dev_err(&dev->dev, "Request irq %d for u3d failed\n",  			u3d->irq); diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 104cdbea635..fcff3a571b4 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -20,7 +20,6 @@  #include <linux/slab.h>  #include <linux/errno.h>  #include <linux/err.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/interrupt.h> @@ -1261,7 +1260,7 @@ static int eps_init(struct mv_udc *udc)  	ep->ep.ops = &mv_ep_ops;  	ep->wedge = 0;  	ep->stopped = 0; -	ep->ep.maxpacket = EP0_MAX_PKT_SIZE; +	usb_ep_set_maxpacket_limit(&ep->ep, EP0_MAX_PKT_SIZE);  	ep->ep_num = 0;  	ep->ep.desc = &mv_ep0_desc;  	INIT_LIST_HEAD(&ep->queue); @@ -1284,7 +1283,7 @@ static int eps_init(struct mv_udc *udc)  		ep->ep.ops = &mv_ep_ops;  		ep->stopped = 0; -		ep->ep.maxpacket = (unsigned short) ~0; +		usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0);  		ep->ep_num = i / 2;  		INIT_LIST_HEAD(&ep->queue); diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index bf2bb39f35a..ca15405583e 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -266,7 +266,7 @@ static void net2272_ep_reset(struct net2272_ep *ep)  	ep->desc = NULL;  	INIT_LIST_HEAD(&ep->queue); -	ep->ep.maxpacket = ~0; +	usb_ep_set_maxpacket_limit(&ep->ep, ~0);  	ep->ep.ops = &net2272_ep_ops;  	/* disable irqs, endpoint */ @@ -1409,7 +1409,7 @@ net2272_usb_reinit(struct net2272 *dev)  			ep->fifo_size = 64;  		net2272_ep_reset(ep);  	} -	dev->ep[0].ep.maxpacket = 64; +	usb_ep_set_maxpacket_limit(&dev->ep[0].ep, 64);  	dev->gadget.ep0 = &dev->ep[0].ep;  	dev->ep[0].stopped = 0; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 0781bff7001..300b3a71383 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -129,7 +129,7 @@ static char *type_string (u8 bmAttributes)  	case USB_ENDPOINT_XFER_BULK:	return "bulk";  	case USB_ENDPOINT_XFER_ISOC:	return "iso";  	case USB_ENDPOINT_XFER_INT:	return "intr"; -	}; +	}  	return "control";  }  #endif @@ -293,7 +293,7 @@ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)  	ep->desc = NULL;  	INIT_LIST_HEAD (&ep->queue); -	ep->ep.maxpacket = ~0; +	usb_ep_set_maxpacket_limit(&ep->ep, ~0);  	ep->ep.ops = &net2280_ep_ops;  	/* disable the dma, irqs, endpoint... */ @@ -1630,7 +1630,7 @@ static ssize_t queues_show(struct device *_dev, struct device_attribute *attr,  					val = "intr"; break;  				 default:  					val = "iso"; break; -				 }; val; }), +				 } val; }),  				usb_endpoint_maxp (d) & 0x1fff,  				ep->dma ? "dma" : "pio", ep->fifo_size  				); @@ -1805,9 +1805,9 @@ static void usb_reinit (struct net2280 *dev)  		ep->regs = &dev->epregs [tmp];  		ep_reset (dev->regs, ep);  	} -	dev->ep [0].ep.maxpacket = 64; -	dev->ep [5].ep.maxpacket = 64; -	dev->ep [6].ep.maxpacket = 64; +	usb_ep_set_maxpacket_limit(&dev->ep [0].ep, 64); +	usb_ep_set_maxpacket_limit(&dev->ep [5].ep, 64); +	usb_ep_set_maxpacket_limit(&dev->ep [6].ep, 64);  	dev->gadget.ep0 = &dev->ep [0].ep;  	dev->ep [0].stopped = 0; @@ -1972,7 +1972,9 @@ static int net2280_stop(struct usb_gadget *_gadget,  	device_remove_file (&dev->pdev->dev, &dev_attr_function);  	device_remove_file (&dev->pdev->dev, &dev_attr_queues); -	DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name); +	DEBUG(dev, "unregistered driver '%s'\n", +			driver ? driver->driver.name : ""); +  	return 0;  } @@ -2680,7 +2682,6 @@ static void net2280_remove (struct pci_dev *pdev)  	if (dev->enabled)  		pci_disable_device (pdev);  	device_remove_file (&pdev->dev, &dev_attr_registers); -	pci_set_drvdata (pdev, NULL);  	INFO (dev, "unbind\n");  } diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c index 0a8099a488c..3ab38616751 100644 --- a/drivers/usb/gadget/nokia.c +++ b/drivers/usb/gadget/nokia.c @@ -126,9 +126,9 @@ static int __init nokia_bind_config(struct usb_configuration *c)  	struct usb_function *f_ecm;  	struct usb_function *f_obex2 = NULL;  	int status = 0; -	int obex1_stat = 0; -	int obex2_stat = 0; -	int phonet_stat = 0; +	int obex1_stat = -1; +	int obex2_stat = -1; +	int phonet_stat = -1;  	if (!IS_ERR(fi_phonet)) {  		f_phonet = usb_get_function(fi_phonet); diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 83957cc225d..2ae4f6d69f7 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -22,7 +22,6 @@  #include <linux/errno.h>  #include <linux/delay.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/interrupt.h> @@ -2586,7 +2585,8 @@ omap_ep_setup(char *name, u8 addr, u8 type,  	ep->ep.name = ep->name;  	ep->ep.ops = &omap_ep_ops; -	ep->ep.maxpacket = ep->maxpacket = maxp; +	ep->maxpacket = maxp; +	usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket);  	list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);  	return buf; diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 24174e1d156..eb8c3bedb57 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -2896,12 +2896,12 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev)  			ep->offset_addr = (UDC_EPINT_OUT_SHIFT + ep->num) *  					  UDC_EP_REG_SHIFT;  		/* need to set ep->ep.maxpacket and set Default Configuration?*/ -		ep->ep.maxpacket = UDC_BULK_MAX_PKT_SIZE; +		usb_ep_set_maxpacket_limit(&ep->ep, UDC_BULK_MAX_PKT_SIZE);  		list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);  		INIT_LIST_HEAD(&ep->queue);  	} -	dev->ep[UDC_EP0IN_IDX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; -	dev->ep[UDC_EP0OUT_IDX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; +	usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IDX].ep, UDC_EP0IN_MAX_PKT_SIZE); +	usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IDX].ep, UDC_EP0OUT_MAX_PKT_SIZE);  	/* remove ep0 in and out from the list.  They have own pointer */  	list_del_init(&dev->ep[UDC_EP0IN_IDX].ep.ep_list); @@ -3080,7 +3080,6 @@ static void pch_udc_remove(struct pci_dev *pdev)  	if (dev->active)  		pci_disable_device(pdev);  	kfree(dev); -	pci_set_drvdata(pdev, NULL);  }  #ifdef CONFIG_PM @@ -3211,7 +3210,7 @@ finished:  	return retval;  } -static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = { +static const struct pci_device_id pch_udc_pcidev_id[] = {  	{  		PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EG20T_UDC),  		.class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index bf7a56b6d48..6474081dcba 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -427,12 +427,17 @@ setup_rx_reqs(struct printer_dev *dev)  		req->length = USB_BUFSIZE;  		req->complete = rx_complete; +		/* here, we unlock, and only unlock, to avoid deadlock. */ +		spin_unlock(&dev->lock);  		error = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC); +		spin_lock(&dev->lock);  		if (error) {  			DBG(dev, "rx submit --> %d\n", error);  			list_add(&req->list, &dev->rx_reqs);  			break; -		} else { +		} +		/* if the req is empty, then add it into dev->rx_reqs_active. */ +		else if (list_empty(&req->list)) {  			list_add(&req->list, &dev->rx_reqs_active);  		}  	} @@ -1133,6 +1138,7 @@ static int __init printer_bind_config(struct usb_configuration *c)  				  NULL, "g_printer");  	if (IS_ERR(dev->pdev)) {  		ERROR(dev, "Failed to create device: g_printer\n"); +		status = PTR_ERR(dev->pdev);  		goto fail;  	} @@ -1157,7 +1163,7 @@ static int __init printer_bind_config(struct usb_configuration *c)  	usb_gadget_set_selfpowered(gadget); -	if (gadget->is_otg) { +	if (gadget_is_otg(gadget)) {  		otg_descriptor.bmAttributes |= USB_OTG_HNP;  		printer_cfg_driver.descriptors = otg_desc;  		printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index cc9207473db..9984437d295 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -24,7 +24,6 @@  #include <linux/err.h>  #include <linux/delay.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/interrupt.h> @@ -54,6 +53,7 @@   */  #ifdef CONFIG_ARCH_PXA  #include <mach/pxa25x-udc.h> +#include <mach/hardware.h>  #endif  #ifdef CONFIG_ARCH_LUBBOCK @@ -1193,6 +1193,7 @@ static void udc_reinit(struct pxa25x_udc *dev)  		ep->stopped = 0;  		INIT_LIST_HEAD (&ep->queue);  		ep->pio_irqs = 0; +		usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket);  	}  	/* the rest was statically initialized, and is read-only */ @@ -2054,7 +2055,7 @@ static struct pxa25x_udc memory = {  /*   *	probe - binds to the platform device   */ -static int __init pxa25x_udc_probe(struct platform_device *pdev) +static int pxa25x_udc_probe(struct platform_device *pdev)  {  	struct pxa25x_udc *dev = &memory;  	int retval, irq; @@ -2203,7 +2204,7 @@ static void pxa25x_udc_shutdown(struct platform_device *_dev)  	pullup_off();  } -static int __exit pxa25x_udc_remove(struct platform_device *pdev) +static int pxa25x_udc_remove(struct platform_device *pdev)  {  	struct pxa25x_udc *dev = platform_get_drvdata(pdev); @@ -2294,7 +2295,8 @@ static int pxa25x_udc_resume(struct platform_device *dev)  static struct platform_driver udc_driver = {  	.shutdown	= pxa25x_udc_shutdown, -	.remove		= __exit_p(pxa25x_udc_remove), +	.probe		= pxa25x_udc_probe, +	.remove		= pxa25x_udc_remove,  	.suspend	= pxa25x_udc_suspend,  	.resume		= pxa25x_udc_resume,  	.driver		= { @@ -2303,7 +2305,7 @@ static struct platform_driver udc_driver = {  	},  }; -module_platform_driver_probe(udc_driver, pxa25x_udc_probe); +module_platform_driver(udc_driver);  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell"); diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 3c97da7760d..cdf4d678be9 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1737,9 +1737,12 @@ static void udc_init_data(struct pxa_udc *dev)  	}  	/* USB endpoints init */ -	for (i = 1; i < NR_USB_ENDPOINTS; i++) +	for (i = 1; i < NR_USB_ENDPOINTS; i++) {  		list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list,  				&dev->gadget.ep_list); +		usb_ep_set_maxpacket_limit(&dev->udc_usb_ep[i].usb_ep, +					   dev->udc_usb_ep[i].usb_ep.maxpacket); +	}  }  /** diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 68be48d3340..b698a490cc7 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1833,7 +1833,7 @@ static int __exit r8a66597_remove(struct platform_device *pdev)  	r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);  	if (r8a66597->pdata->on_chip) { -		clk_disable(r8a66597->clk); +		clk_disable_unprepare(r8a66597->clk);  		clk_put(r8a66597->clk);  	} @@ -1904,7 +1904,6 @@ static int __init r8a66597_probe(struct platform_device *pdev)  	r8a66597 = kzalloc(sizeof(struct r8a66597), GFP_KERNEL);  	if (r8a66597 == NULL) {  		ret = -ENOMEM; -		dev_err(&pdev->dev, "kzalloc error\n");  		goto clean_up;  	} @@ -1931,7 +1930,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)  			ret = PTR_ERR(r8a66597->clk);  			goto clean_up;  		} -		clk_enable(r8a66597->clk); +		clk_prepare_enable(r8a66597->clk);  	}  	if (r8a66597->pdata->sudmac) { @@ -1964,9 +1963,9 @@ static int __init r8a66597_probe(struct platform_device *pdev)  		INIT_LIST_HEAD(&ep->queue);  		ep->ep.name = r8a66597_ep_name[i];  		ep->ep.ops = &r8a66597_ep_ops; -		ep->ep.maxpacket = 512; +		usb_ep_set_maxpacket_limit(&ep->ep, 512);  	} -	r8a66597->ep[0].ep.maxpacket = 64; +	usb_ep_set_maxpacket_limit(&r8a66597->ep[0].ep, 64);  	r8a66597->ep[0].pipenum = 0;  	r8a66597->ep[0].fifoaddr = CFIFO;  	r8a66597->ep[0].fifosel = CFIFOSEL; @@ -1996,7 +1995,7 @@ clean_up3:  	free_irq(irq, r8a66597);  clean_up2:  	if (r8a66597->pdata->on_chip) { -		clk_disable(r8a66597->clk); +		clk_disable_unprepare(r8a66597->clk);  		clk_put(r8a66597->clk);  	}  clean_up: diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 9575085ded8..95d2324f697 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -25,7 +25,6 @@  #include <linux/moduleparam.h>  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/proc_fs.h>  #include <linux/slab.h> @@ -36,6 +35,7 @@  #include <asm/byteorder.h>  #include <asm/unaligned.h> +#include "u_rndis.h"  #undef	VERBOSE_DEBUG @@ -761,7 +761,7 @@ int rndis_signal_connect(int configNr)  	return rndis_indicate_status_msg(configNr,  					  RNDIS_STATUS_MEDIA_CONNECT);  } -EXPORT_SYMBOL(rndis_signal_connect); +EXPORT_SYMBOL_GPL(rndis_signal_connect);  int rndis_signal_disconnect(int configNr)  { @@ -770,7 +770,7 @@ int rndis_signal_disconnect(int configNr)  	return rndis_indicate_status_msg(configNr,  					  RNDIS_STATUS_MEDIA_DISCONNECT);  } -EXPORT_SYMBOL(rndis_signal_disconnect); +EXPORT_SYMBOL_GPL(rndis_signal_disconnect);  void rndis_uninit(int configNr)  { @@ -785,13 +785,13 @@ void rndis_uninit(int configNr)  	while ((buf = rndis_get_next_response(configNr, &length)))  		rndis_free_response(configNr, buf);  } -EXPORT_SYMBOL(rndis_uninit); +EXPORT_SYMBOL_GPL(rndis_uninit);  void rndis_set_host_mac(int configNr, const u8 *addr)  {  	rndis_per_dev_params[configNr].host_mac = addr;  } -EXPORT_SYMBOL(rndis_set_host_mac); +EXPORT_SYMBOL_GPL(rndis_set_host_mac);  /*   * Message Parser @@ -874,7 +874,7 @@ int rndis_msg_parser(u8 configNr, u8 *buf)  	return -ENOTSUPP;  } -EXPORT_SYMBOL(rndis_msg_parser); +EXPORT_SYMBOL_GPL(rndis_msg_parser);  int rndis_register(void (*resp_avail)(void *v), void *v)  { @@ -896,7 +896,7 @@ int rndis_register(void (*resp_avail)(void *v), void *v)  	return -ENODEV;  } -EXPORT_SYMBOL(rndis_register); +EXPORT_SYMBOL_GPL(rndis_register);  void rndis_deregister(int configNr)  { @@ -905,7 +905,7 @@ void rndis_deregister(int configNr)  	if (configNr >= RNDIS_MAX_CONFIGS) return;  	rndis_per_dev_params[configNr].used = 0;  } -EXPORT_SYMBOL(rndis_deregister); +EXPORT_SYMBOL_GPL(rndis_deregister);  int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)  { @@ -919,7 +919,7 @@ int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)  	return 0;  } -EXPORT_SYMBOL(rndis_set_param_dev); +EXPORT_SYMBOL_GPL(rndis_set_param_dev);  int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)  { @@ -932,7 +932,7 @@ int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)  	return 0;  } -EXPORT_SYMBOL(rndis_set_param_vendor); +EXPORT_SYMBOL_GPL(rndis_set_param_vendor);  int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)  { @@ -944,7 +944,7 @@ int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)  	return 0;  } -EXPORT_SYMBOL(rndis_set_param_medium); +EXPORT_SYMBOL_GPL(rndis_set_param_medium);  void rndis_add_hdr(struct sk_buff *skb)  { @@ -959,7 +959,7 @@ void rndis_add_hdr(struct sk_buff *skb)  	header->DataOffset = cpu_to_le32(36);  	header->DataLength = cpu_to_le32(skb->len - sizeof(*header));  } -EXPORT_SYMBOL(rndis_add_hdr); +EXPORT_SYMBOL_GPL(rndis_add_hdr);  void rndis_free_response(int configNr, u8 *buf)  { @@ -976,7 +976,7 @@ void rndis_free_response(int configNr, u8 *buf)  		}  	}  } -EXPORT_SYMBOL(rndis_free_response); +EXPORT_SYMBOL_GPL(rndis_free_response);  u8 *rndis_get_next_response(int configNr, u32 *length)  { @@ -998,7 +998,7 @@ u8 *rndis_get_next_response(int configNr, u32 *length)  	return NULL;  } -EXPORT_SYMBOL(rndis_get_next_response); +EXPORT_SYMBOL_GPL(rndis_get_next_response);  static rndis_resp_t *rndis_add_response(int configNr, u32 length)  { @@ -1042,7 +1042,7 @@ int rndis_rm_hdr(struct gether *port,  	skb_queue_tail(list, skb);  	return 0;  } -EXPORT_SYMBOL(rndis_rm_hdr); +EXPORT_SYMBOL_GPL(rndis_rm_hdr);  #ifdef CONFIG_USB_GADGET_DEBUG_FILES @@ -1068,7 +1068,7 @@ static int rndis_proc_show(struct seq_file *m, void *v)  				s = "RNDIS_INITIALIZED"; break;  			 case RNDIS_DATA_INITIALIZED:  				s = "RNDIS_DATA_INITIALIZED"; break; -			}; s; }), +			} s; }),  			 param->medium,  			 (param->media_state) ? 0 : param->speed*100,  			 (param->media_state) ? "disconnected" : "connected", @@ -1142,7 +1142,7 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];  #endif /* CONFIG_USB_GADGET_DEBUG_FILES */ -static int rndis_init(void) +int rndis_init(void)  {  	u8 i; @@ -1174,9 +1174,8 @@ static int rndis_init(void)  	return 0;  } -module_init(rndis_init); -static void rndis_exit(void) +void rndis_exit(void)  {  #ifdef CONFIG_USB_GADGET_DEBUG_FILES  	u8 i; @@ -1188,6 +1187,4 @@ static void rndis_exit(void)  	}  #endif  } -module_exit(rndis_exit); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/s3c-hsotg.h b/drivers/usb/gadget/s3c-hsotg.h deleted file mode 100644 index d650b129583..00000000000 --- a/drivers/usb/gadget/s3c-hsotg.h +++ /dev/null @@ -1,377 +0,0 @@ -/* drivers/usb/gadget/s3c-hsotg.h - * - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - *      http://armlinux.simtec.co.uk/ - *      Ben Dooks <ben@simtec.co.uk> - * - * USB2.0 Highspeed/OtG Synopsis DWC2 device block registers - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#ifndef __REGS_USB_HSOTG_H -#define __REGS_USB_HSOTG_H __FILE__ - -#define HSOTG_REG(x) (x) - -#define GOTGCTL				HSOTG_REG(0x000) -#define GOTGCTL_BSESVLD			(1 << 19) -#define GOTGCTL_ASESVLD			(1 << 18) -#define GOTGCTL_DBNC_SHORT			(1 << 17) -#define GOTGCTL_CONID_B			(1 << 16) -#define GOTGCTL_DEVHNPEN			(1 << 11) -#define GOTGCTL_HSSETHNPEN			(1 << 10) -#define GOTGCTL_HNPREQ				(1 << 9) -#define GOTGCTL_HSTNEGSCS			(1 << 8) -#define GOTGCTL_SESREQ				(1 << 1) -#define GOTGCTL_SESREQSCS			(1 << 0) - -#define GOTGINT				HSOTG_REG(0x004) -#define GOTGINT_DbnceDone			(1 << 19) -#define GOTGINT_ADevTOUTChg			(1 << 18) -#define GOTGINT_HstNegDet			(1 << 17) -#define GOTGINT_HstnegSucStsChng		(1 << 9) -#define GOTGINT_SesReqSucStsChng		(1 << 8) -#define GOTGINT_SesEndDet			(1 << 2) - -#define GAHBCFG				HSOTG_REG(0x008) -#define GAHBCFG_PTxFEmpLvl			(1 << 8) -#define GAHBCFG_NPTxFEmpLvl			(1 << 7) -#define GAHBCFG_DMAEn				(1 << 5) -#define GAHBCFG_HBstLen_MASK			(0xf << 1) -#define GAHBCFG_HBstLen_SHIFT			(1) -#define GAHBCFG_HBstLen_Single			(0x0 << 1) -#define GAHBCFG_HBstLen_Incr			(0x1 << 1) -#define GAHBCFG_HBstLen_Incr4			(0x3 << 1) -#define GAHBCFG_HBstLen_Incr8			(0x5 << 1) -#define GAHBCFG_HBstLen_Incr16			(0x7 << 1) -#define GAHBCFG_GlblIntrEn			(1 << 0) - -#define GUSBCFG				HSOTG_REG(0x00C) -#define GUSBCFG_PHYLPClkSel			(1 << 15) -#define GUSBCFG_HNPCap				(1 << 9) -#define GUSBCFG_SRPCap				(1 << 8) -#define GUSBCFG_PHYIf16			(1 << 3) -#define GUSBCFG_TOutCal_MASK			(0x7 << 0) -#define GUSBCFG_TOutCal_SHIFT			(0) -#define GUSBCFG_TOutCal_LIMIT			(0x7) -#define GUSBCFG_TOutCal(_x)			((_x) << 0) - -#define GRSTCTL				HSOTG_REG(0x010) - -#define GRSTCTL_AHBIdle			(1 << 31) -#define GRSTCTL_DMAReq				(1 << 30) -#define GRSTCTL_TxFNum_MASK			(0x1f << 6) -#define GRSTCTL_TxFNum_SHIFT			(6) -#define GRSTCTL_TxFNum_LIMIT			(0x1f) -#define GRSTCTL_TxFNum(_x)			((_x) << 6) -#define GRSTCTL_TxFFlsh			(1 << 5) -#define GRSTCTL_RxFFlsh			(1 << 4) -#define GRSTCTL_INTknQFlsh			(1 << 3) -#define GRSTCTL_FrmCntrRst			(1 << 2) -#define GRSTCTL_HSftRst			(1 << 1) -#define GRSTCTL_CSftRst			(1 << 0) - -#define GINTSTS				HSOTG_REG(0x014) -#define GINTMSK				HSOTG_REG(0x018) - -#define GINTSTS_WkUpInt			(1 << 31) -#define GINTSTS_SessReqInt			(1 << 30) -#define GINTSTS_DisconnInt			(1 << 29) -#define GINTSTS_ConIDStsChng			(1 << 28) -#define GINTSTS_PTxFEmp			(1 << 26) -#define GINTSTS_HChInt				(1 << 25) -#define GINTSTS_PrtInt				(1 << 24) -#define GINTSTS_FetSusp			(1 << 22) -#define GINTSTS_incompIP			(1 << 21) -#define GINTSTS_IncomplSOIN			(1 << 20) -#define GINTSTS_OEPInt				(1 << 19) -#define GINTSTS_IEPInt				(1 << 18) -#define GINTSTS_EPMis				(1 << 17) -#define GINTSTS_EOPF				(1 << 15) -#define GINTSTS_ISOutDrop			(1 << 14) -#define GINTSTS_EnumDone			(1 << 13) -#define GINTSTS_USBRst				(1 << 12) -#define GINTSTS_USBSusp			(1 << 11) -#define GINTSTS_ErlySusp			(1 << 10) -#define GINTSTS_GOUTNakEff			(1 << 7) -#define GINTSTS_GINNakEff			(1 << 6) -#define GINTSTS_NPTxFEmp			(1 << 5) -#define GINTSTS_RxFLvl				(1 << 4) -#define GINTSTS_SOF				(1 << 3) -#define GINTSTS_OTGInt				(1 << 2) -#define GINTSTS_ModeMis			(1 << 1) -#define GINTSTS_CurMod_Host			(1 << 0) - -#define GRXSTSR				HSOTG_REG(0x01C) -#define GRXSTSP				HSOTG_REG(0x020) - -#define GRXSTS_FN_MASK				(0x7f << 25) -#define GRXSTS_FN_SHIFT			(25) - -#define GRXSTS_PktSts_MASK			(0xf << 17) -#define GRXSTS_PktSts_SHIFT			(17) -#define GRXSTS_PktSts_GlobalOutNAK		(0x1 << 17) -#define GRXSTS_PktSts_OutRX			(0x2 << 17) -#define GRXSTS_PktSts_OutDone			(0x3 << 17) -#define GRXSTS_PktSts_SetupDone		(0x4 << 17) -#define GRXSTS_PktSts_SetupRX			(0x6 << 17) - -#define GRXSTS_DPID_MASK			(0x3 << 15) -#define GRXSTS_DPID_SHIFT			(15) -#define GRXSTS_ByteCnt_MASK			(0x7ff << 4) -#define GRXSTS_ByteCnt_SHIFT			(4) -#define GRXSTS_EPNum_MASK			(0xf << 0) -#define GRXSTS_EPNum_SHIFT			(0) - -#define GRXFSIZ				HSOTG_REG(0x024) - -#define GNPTXFSIZ				HSOTG_REG(0x028) - -#define GNPTXFSIZ_NPTxFDep_MASK		(0xffff << 16) -#define GNPTXFSIZ_NPTxFDep_SHIFT		(16) -#define GNPTXFSIZ_NPTxFDep_LIMIT		(0xffff) -#define GNPTXFSIZ_NPTxFDep(_x)			((_x) << 16) -#define GNPTXFSIZ_NPTxFStAddr_MASK		(0xffff << 0) -#define GNPTXFSIZ_NPTxFStAddr_SHIFT		(0) -#define GNPTXFSIZ_NPTxFStAddr_LIMIT		(0xffff) -#define GNPTXFSIZ_NPTxFStAddr(_x)		((_x) << 0) - -#define GNPTXSTS				HSOTG_REG(0x02C) - -#define GNPTXSTS_NPtxQTop_MASK			(0x7f << 24) -#define GNPTXSTS_NPtxQTop_SHIFT		(24) - -#define GNPTXSTS_NPTxQSpcAvail_MASK		(0xff << 16) -#define GNPTXSTS_NPTxQSpcAvail_SHIFT		(16) -#define GNPTXSTS_NPTxQSpcAvail_GET(_v)		(((_v) >> 16) & 0xff) - -#define GNPTXSTS_NPTxFSpcAvail_MASK		(0xffff << 0) -#define GNPTXSTS_NPTxFSpcAvail_SHIFT		(0) -#define GNPTXSTS_NPTxFSpcAvail_GET(_v)		(((_v) >> 0) & 0xffff) - - -#define HPTXFSIZ				HSOTG_REG(0x100) - -#define DPTXFSIZn(_a)		HSOTG_REG(0x104 + (((_a) - 1) * 4)) - -#define DPTXFSIZn_DPTxFSize_MASK		(0xffff << 16) -#define DPTXFSIZn_DPTxFSize_SHIFT		(16) -#define DPTXFSIZn_DPTxFSize_GET(_v)		(((_v) >> 16) & 0xffff) -#define DPTXFSIZn_DPTxFSize_LIMIT		(0xffff) -#define DPTXFSIZn_DPTxFSize(_x)		((_x) << 16) - -#define DPTXFSIZn_DPTxFStAddr_MASK		(0xffff << 0) -#define DPTXFSIZn_DPTxFStAddr_SHIFT		(0) - -/* Device mode registers */ -#define DCFG					HSOTG_REG(0x800) - -#define DCFG_EPMisCnt_MASK			(0x1f << 18) -#define DCFG_EPMisCnt_SHIFT			(18) -#define DCFG_EPMisCnt_LIMIT			(0x1f) -#define DCFG_EPMisCnt(_x)			((_x) << 18) - -#define DCFG_PerFrInt_MASK			(0x3 << 11) -#define DCFG_PerFrInt_SHIFT			(11) -#define DCFG_PerFrInt_LIMIT			(0x3) -#define DCFG_PerFrInt(_x)			((_x) << 11) - -#define DCFG_DevAddr_MASK			(0x7f << 4) -#define DCFG_DevAddr_SHIFT			(4) -#define DCFG_DevAddr_LIMIT			(0x7f) -#define DCFG_DevAddr(_x)			((_x) << 4) - -#define DCFG_NZStsOUTHShk			(1 << 2) - -#define DCFG_DevSpd_MASK			(0x3 << 0) -#define DCFG_DevSpd_SHIFT			(0) -#define DCFG_DevSpd_HS				(0x0 << 0) -#define DCFG_DevSpd_FS				(0x1 << 0) -#define DCFG_DevSpd_LS				(0x2 << 0) -#define DCFG_DevSpd_FS48			(0x3 << 0) - -#define DCTL					HSOTG_REG(0x804) - -#define DCTL_PWROnPrgDone			(1 << 11) -#define DCTL_CGOUTNak				(1 << 10) -#define DCTL_SGOUTNak				(1 << 9) -#define DCTL_CGNPInNAK				(1 << 8) -#define DCTL_SGNPInNAK				(1 << 7) -#define DCTL_TstCtl_MASK			(0x7 << 4) -#define DCTL_TstCtl_SHIFT			(4) -#define DCTL_GOUTNakSts			(1 << 3) -#define DCTL_GNPINNakSts			(1 << 2) -#define DCTL_SftDiscon				(1 << 1) -#define DCTL_RmtWkUpSig			(1 << 0) - -#define DSTS					HSOTG_REG(0x808) - -#define DSTS_SOFFN_MASK			(0x3fff << 8) -#define DSTS_SOFFN_SHIFT			(8) -#define DSTS_SOFFN_LIMIT			(0x3fff) -#define DSTS_SOFFN(_x)				((_x) << 8) -#define DSTS_ErraticErr			(1 << 3) -#define DSTS_EnumSpd_MASK			(0x3 << 1) -#define DSTS_EnumSpd_SHIFT			(1) -#define DSTS_EnumSpd_HS			(0x0 << 1) -#define DSTS_EnumSpd_FS			(0x1 << 1) -#define DSTS_EnumSpd_LS			(0x2 << 1) -#define DSTS_EnumSpd_FS48			(0x3 << 1) - -#define DSTS_SuspSts				(1 << 0) - -#define DIEPMSK				HSOTG_REG(0x810) - -#define DIEPMSK_TxFIFOEmpty			(1 << 7) -#define DIEPMSK_INEPNakEffMsk			(1 << 6) -#define DIEPMSK_INTknEPMisMsk			(1 << 5) -#define DIEPMSK_INTknTXFEmpMsk			(1 << 4) -#define DIEPMSK_TimeOUTMsk			(1 << 3) -#define DIEPMSK_AHBErrMsk			(1 << 2) -#define DIEPMSK_EPDisbldMsk			(1 << 1) -#define DIEPMSK_XferComplMsk			(1 << 0) - -#define DOEPMSK				HSOTG_REG(0x814) - -#define DOEPMSK_Back2BackSetup			(1 << 6) -#define DOEPMSK_OUTTknEPdisMsk			(1 << 4) -#define DOEPMSK_SetupMsk			(1 << 3) -#define DOEPMSK_AHBErrMsk			(1 << 2) -#define DOEPMSK_EPDisbldMsk			(1 << 1) -#define DOEPMSK_XferComplMsk			(1 << 0) - -#define DAINT					HSOTG_REG(0x818) -#define DAINTMSK				HSOTG_REG(0x81C) - -#define DAINT_OutEP_SHIFT			(16) -#define DAINT_OutEP(x)				(1 << ((x) + 16)) -#define DAINT_InEP(x)				(1 << (x)) - -#define DTKNQR1				HSOTG_REG(0x820) -#define DTKNQR2				HSOTG_REG(0x824) -#define DTKNQR3				HSOTG_REG(0x830) -#define DTKNQR4				HSOTG_REG(0x834) - -#define DVBUSDIS				HSOTG_REG(0x828) -#define DVBUSPULSE				HSOTG_REG(0x82C) - -#define DIEPCTL0				HSOTG_REG(0x900) -#define DOEPCTL0				HSOTG_REG(0xB00) -#define DIEPCTL(_a)			HSOTG_REG(0x900 + ((_a) * 0x20)) -#define DOEPCTL(_a)			HSOTG_REG(0xB00 + ((_a) * 0x20)) - -/* EP0 specialness: - * bits[29..28] - reserved (no SetD0PID, SetD1PID) - * bits[25..22] - should always be zero, this isn't a periodic endpoint - * bits[10..0] - MPS setting differenct for EP0 - */ -#define D0EPCTL_MPS_MASK			(0x3 << 0) -#define D0EPCTL_MPS_SHIFT			(0) -#define D0EPCTL_MPS_64				(0x0 << 0) -#define D0EPCTL_MPS_32				(0x1 << 0) -#define D0EPCTL_MPS_16				(0x2 << 0) -#define D0EPCTL_MPS_8				(0x3 << 0) - -#define DxEPCTL_EPEna				(1 << 31) -#define DxEPCTL_EPDis				(1 << 30) -#define DxEPCTL_SetD1PID			(1 << 29) -#define DxEPCTL_SetOddFr			(1 << 29) -#define DxEPCTL_SetD0PID			(1 << 28) -#define DxEPCTL_SetEvenFr			(1 << 28) -#define DxEPCTL_SNAK				(1 << 27) -#define DxEPCTL_CNAK				(1 << 26) -#define DxEPCTL_TxFNum_MASK			(0xf << 22) -#define DxEPCTL_TxFNum_SHIFT			(22) -#define DxEPCTL_TxFNum_LIMIT			(0xf) -#define DxEPCTL_TxFNum(_x)			((_x) << 22) - -#define DxEPCTL_Stall				(1 << 21) -#define DxEPCTL_Snp				(1 << 20) -#define DxEPCTL_EPType_MASK			(0x3 << 18) -#define DxEPCTL_EPType_SHIFT			(18) -#define DxEPCTL_EPType_Control			(0x0 << 18) -#define DxEPCTL_EPType_Iso			(0x1 << 18) -#define DxEPCTL_EPType_Bulk			(0x2 << 18) -#define DxEPCTL_EPType_Intterupt		(0x3 << 18) - -#define DxEPCTL_NAKsts				(1 << 17) -#define DxEPCTL_DPID				(1 << 16) -#define DxEPCTL_EOFrNum			(1 << 16) -#define DxEPCTL_USBActEp			(1 << 15) -#define DxEPCTL_NextEp_MASK			(0xf << 11) -#define DxEPCTL_NextEp_SHIFT			(11) -#define DxEPCTL_NextEp_LIMIT			(0xf) -#define DxEPCTL_NextEp(_x)			((_x) << 11) - -#define DxEPCTL_MPS_MASK			(0x7ff << 0) -#define DxEPCTL_MPS_SHIFT			(0) -#define DxEPCTL_MPS_LIMIT			(0x7ff) -#define DxEPCTL_MPS(_x)			((_x) << 0) - -#define DIEPINT(_a)			HSOTG_REG(0x908 + ((_a) * 0x20)) -#define DOEPINT(_a)			HSOTG_REG(0xB08 + ((_a) * 0x20)) - -#define DxEPINT_INEPNakEff			(1 << 6) -#define DxEPINT_Back2BackSetup			(1 << 6) -#define DxEPINT_INTknEPMis			(1 << 5) -#define DxEPINT_INTknTXFEmp			(1 << 4) -#define DxEPINT_OUTTknEPdis			(1 << 4) -#define DxEPINT_Timeout			(1 << 3) -#define DxEPINT_Setup				(1 << 3) -#define DxEPINT_AHBErr				(1 << 2) -#define DxEPINT_EPDisbld			(1 << 1) -#define DxEPINT_XferCompl			(1 << 0) - -#define DIEPTSIZ0				HSOTG_REG(0x910) - -#define DIEPTSIZ0_PktCnt_MASK			(0x3 << 19) -#define DIEPTSIZ0_PktCnt_SHIFT			(19) -#define DIEPTSIZ0_PktCnt_LIMIT			(0x3) -#define DIEPTSIZ0_PktCnt(_x)			((_x) << 19) - -#define DIEPTSIZ0_XferSize_MASK		(0x7f << 0) -#define DIEPTSIZ0_XferSize_SHIFT		(0) -#define DIEPTSIZ0_XferSize_LIMIT		(0x7f) -#define DIEPTSIZ0_XferSize(_x)			((_x) << 0) - -#define DOEPTSIZ0				HSOTG_REG(0xB10) -#define DOEPTSIZ0_SUPCnt_MASK			(0x3 << 29) -#define DOEPTSIZ0_SUPCnt_SHIFT			(29) -#define DOEPTSIZ0_SUPCnt_LIMIT			(0x3) -#define DOEPTSIZ0_SUPCnt(_x)			((_x) << 29) - -#define DOEPTSIZ0_PktCnt			(1 << 19) -#define DOEPTSIZ0_XferSize_MASK		(0x7f << 0) -#define DOEPTSIZ0_XferSize_SHIFT		(0) - -#define DIEPTSIZ(_a)			HSOTG_REG(0x910 + ((_a) * 0x20)) -#define DOEPTSIZ(_a)			HSOTG_REG(0xB10 + ((_a) * 0x20)) - -#define DxEPTSIZ_MC_MASK			(0x3 << 29) -#define DxEPTSIZ_MC_SHIFT			(29) -#define DxEPTSIZ_MC_LIMIT			(0x3) -#define DxEPTSIZ_MC(_x)			((_x) << 29) - -#define DxEPTSIZ_PktCnt_MASK			(0x3ff << 19) -#define DxEPTSIZ_PktCnt_SHIFT			(19) -#define DxEPTSIZ_PktCnt_GET(_v)		(((_v) >> 19) & 0x3ff) -#define DxEPTSIZ_PktCnt_LIMIT			(0x3ff) -#define DxEPTSIZ_PktCnt(_x)			((_x) << 19) - -#define DxEPTSIZ_XferSize_MASK			(0x7ffff << 0) -#define DxEPTSIZ_XferSize_SHIFT		(0) -#define DxEPTSIZ_XferSize_GET(_v)		(((_v) >> 0) & 0x7ffff) -#define DxEPTSIZ_XferSize_LIMIT		(0x7ffff) -#define DxEPTSIZ_XferSize(_x)			((_x) << 0) - -#define DIEPDMA(_a)			HSOTG_REG(0x914 + ((_a) * 0x20)) -#define DOEPDMA(_a)			HSOTG_REG(0xB14 + ((_a) * 0x20)) -#define DTXFSTS(_a)			HSOTG_REG(0x918 + ((_a) * 0x20)) - -#define EPFIFO(_a)			HSOTG_REG(0x1000 + ((_a) * 0x1000)) - -#endif /* __REGS_USB_HSOTG_H */ diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 1a1a41498db..10c6a128250 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -999,7 +999,7 @@ static void s3c_hsudc_initep(struct s3c_hsudc *hsudc,  	hsep->dev = hsudc;  	hsep->ep.name = hsep->name; -	hsep->ep.maxpacket = epnum ? 512 : 64; +	usb_ep_set_maxpacket_limit(&hsep->ep, epnum ? 512 : 64);  	hsep->ep.ops = &s3c_hsudc_ep_ops;  	hsep->fifo = hsudc->regs + S3C_BR(epnum);  	hsep->ep.desc = NULL; @@ -1344,7 +1344,6 @@ static int s3c_hsudc_probe(struct platform_device *pdev)  	return 0;  err_add_udc: -err_add_device:  	clk_disable(hsudc->uclk);  err_res:  	if (!IS_ERR_OR_NULL(hsudc->transceiver)) diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index c72d810e6b3..7987aa049fa 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -117,7 +117,8 @@ static int dprintk(int level, const char *fmt, ...)  			sizeof(printk_buf)-len, fmt, args);  	va_end(args); -	return pr_debug("%s", printk_buf); +	pr_debug("%s", printk_buf); +	return len;  }  #else  static int dprintk(int level, const char *fmt, ...) @@ -1629,6 +1630,7 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev)  		ep->ep.desc = NULL;  		ep->halted = 0;  		INIT_LIST_HEAD(&ep->queue); +		usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket);  	}  } diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 08a1a3210a2..648f9e489b3 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -23,242 +23,17 @@   * The valid range of num_buffers is: num >= 2 && num <= 4.   */ +#include <linux/module.h> +#include <linux/blkdev.h> +#include <linux/file.h> +#include <linux/fs.h> +#include <linux/usb/composite.h> -#include <linux/usb/storage.h> -#include <scsi/scsi.h> -#include <asm/unaligned.h> - - -/* - * Thanks to NetChip Technologies for donating this product ID. - * - * DO NOT REUSE THESE IDs with any other driver!!  Ever!! - * Instead:  allocate your own, using normal USB-IF procedures. - */ -#define FSG_VENDOR_ID	0x0525	/* NetChip */ -#define FSG_PRODUCT_ID	0xa4a5	/* Linux-USB File-backed Storage Gadget */ - - -/*-------------------------------------------------------------------------*/ - - -#ifndef DEBUG -#undef VERBOSE_DEBUG -#undef DUMP_MSGS -#endif /* !DEBUG */ - -#ifdef VERBOSE_DEBUG -#define VLDBG	LDBG -#else -#define VLDBG(lun, fmt, args...) do { } while (0) -#endif /* VERBOSE_DEBUG */ - -#define LDBG(lun, fmt, args...)   dev_dbg (&(lun)->dev, fmt, ## args) -#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args) -#define LWARN(lun, fmt, args...)  dev_warn(&(lun)->dev, fmt, ## args) -#define LINFO(lun, fmt, args...)  dev_info(&(lun)->dev, fmt, ## args) - - -#ifdef DUMP_MSGS - -#  define dump_msg(fsg, /* const char * */ label,			\ -		   /* const u8 * */ buf, /* unsigned */ length) do {	\ -	if (length < 512) {						\ -		DBG(fsg, "%s, length %u:\n", label, length);		\ -		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,	\ -			       16, 1, buf, length, 0);			\ -	}								\ -} while (0) - -#  define dump_cdb(fsg) do { } while (0) - -#else - -#  define dump_msg(fsg, /* const char * */ label, \ -		   /* const u8 * */ buf, /* unsigned */ length) do { } while (0) - -#  ifdef VERBOSE_DEBUG - -#    define dump_cdb(fsg)						\ -	print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,	\ -		       16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0)		\ - -#  else - -#    define dump_cdb(fsg) do { } while (0) - -#  endif /* VERBOSE_DEBUG */ - -#endif /* DUMP_MSGS */ - -/*-------------------------------------------------------------------------*/ - -/* Length of a SCSI Command Data Block */ -#define MAX_COMMAND_SIZE	16 - -/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ -#define SS_NO_SENSE				0 -#define SS_COMMUNICATION_FAILURE		0x040800 -#define SS_INVALID_COMMAND			0x052000 -#define SS_INVALID_FIELD_IN_CDB			0x052400 -#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE	0x052100 -#define SS_LOGICAL_UNIT_NOT_SUPPORTED		0x052500 -#define SS_MEDIUM_NOT_PRESENT			0x023a00 -#define SS_MEDIUM_REMOVAL_PREVENTED		0x055302 -#define SS_NOT_READY_TO_READY_TRANSITION	0x062800 -#define SS_RESET_OCCURRED			0x062900 -#define SS_SAVING_PARAMETERS_NOT_SUPPORTED	0x053900 -#define SS_UNRECOVERED_READ_ERROR		0x031100 -#define SS_WRITE_ERROR				0x030c02 -#define SS_WRITE_PROTECTED			0x072700 - -#define SK(x)		((u8) ((x) >> 16))	/* Sense Key byte, etc. */ -#define ASC(x)		((u8) ((x) >> 8)) -#define ASCQ(x)		((u8) (x)) - - -/*-------------------------------------------------------------------------*/ - - -struct fsg_lun { -	struct file	*filp; -	loff_t		file_length; -	loff_t		num_sectors; - -	unsigned int	initially_ro:1; -	unsigned int	ro:1; -	unsigned int	removable:1; -	unsigned int	cdrom:1; -	unsigned int	prevent_medium_removal:1; -	unsigned int	registered:1; -	unsigned int	info_valid:1; -	unsigned int	nofua:1; - -	u32		sense_data; -	u32		sense_data_info; -	u32		unit_attention_data; - -	unsigned int	blkbits;	/* Bits of logical block size of bound block device */ -	unsigned int	blksize;	/* logical block size of bound block device */ -	struct device	dev; -}; - -static inline bool fsg_lun_is_open(struct fsg_lun *curlun) -{ -	return curlun->filp != NULL; -} - -static inline struct fsg_lun *fsg_lun_from_dev(struct device *dev) -{ -	return container_of(dev, struct fsg_lun, dev); -} - - -/* Big enough to hold our biggest descriptor */ -#define EP0_BUFSIZE	256 -#define DELAYED_STATUS	(EP0_BUFSIZE + 999)	/* An impossibly large value */ - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - -static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; -module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO); -MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers"); - -#else - -/* - * Number of buffers we will use. - * 2 is usually enough for good buffering pipeline - */ -#define fsg_num_buffers	CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS - -#endif /* CONFIG_USB_GADGET_DEBUG_FILES */ - -/* check if fsg_num_buffers is within a valid range */ -static inline int fsg_num_buffers_validate(void) -{ -	if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4) -		return 0; -	pr_err("fsg_num_buffers %u is out of range (%d to %d)\n", -	       fsg_num_buffers, 2 ,4); -	return -EINVAL; -} - -/* Default size of buffer length. */ -#define FSG_BUFLEN	((u32)16384) - -/* Maximal number of LUNs supported in mass storage function */ -#define FSG_MAX_LUNS	8 - -enum fsg_buffer_state { -	BUF_STATE_EMPTY = 0, -	BUF_STATE_FULL, -	BUF_STATE_BUSY -}; - -struct fsg_buffhd { -	void				*buf; -	enum fsg_buffer_state		state; -	struct fsg_buffhd		*next; - -	/* -	 * The NetChip 2280 is faster, and handles some protocol faults -	 * better, if we don't submit any short bulk-out read requests. -	 * So we will record the intended request length here. -	 */ -	unsigned int			bulk_out_intended_length; - -	struct usb_request		*inreq; -	int				inreq_busy; -	struct usb_request		*outreq; -	int				outreq_busy; -}; - -enum fsg_state { -	/* This one isn't used anywhere */ -	FSG_STATE_COMMAND_PHASE = -10, -	FSG_STATE_DATA_PHASE, -	FSG_STATE_STATUS_PHASE, - -	FSG_STATE_IDLE = 0, -	FSG_STATE_ABORT_BULK_OUT, -	FSG_STATE_RESET, -	FSG_STATE_INTERFACE_CHANGE, -	FSG_STATE_CONFIG_CHANGE, -	FSG_STATE_DISCONNECT, -	FSG_STATE_EXIT, -	FSG_STATE_TERMINATED -}; - -enum data_direction { -	DATA_DIR_UNKNOWN = 0, -	DATA_DIR_FROM_HOST, -	DATA_DIR_TO_HOST, -	DATA_DIR_NONE -}; - - -/*-------------------------------------------------------------------------*/ - - -static inline u32 get_unaligned_be24(u8 *buf) -{ -	return 0xffffff & (u32) get_unaligned_be32(buf - 1); -} - - -/*-------------------------------------------------------------------------*/ - - -enum { -	FSG_STRING_INTERFACE -}; - +#include "storage_common.h"  /* There is only one interface. */ -static struct usb_interface_descriptor -fsg_intf_desc = { +struct usb_interface_descriptor fsg_intf_desc = {  	.bLength =		sizeof fsg_intf_desc,  	.bDescriptorType =	USB_DT_INTERFACE, @@ -268,14 +43,14 @@ fsg_intf_desc = {  	.bInterfaceProtocol =	USB_PR_BULK,	/* Adjusted during fsg_bind() */  	.iInterface =		FSG_STRING_INTERFACE,  }; +EXPORT_SYMBOL_GPL(fsg_intf_desc);  /*   * Three full-speed endpoint descriptors: bulk-in, bulk-out, and   * interrupt-in.   */ -static struct usb_endpoint_descriptor -fsg_fs_bulk_in_desc = { +struct usb_endpoint_descriptor fsg_fs_bulk_in_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -283,9 +58,9 @@ fsg_fs_bulk_in_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  	/* wMaxPacketSize set by autoconfiguration */  }; +EXPORT_SYMBOL_GPL(fsg_fs_bulk_in_desc); -static struct usb_endpoint_descriptor -fsg_fs_bulk_out_desc = { +struct usb_endpoint_descriptor fsg_fs_bulk_out_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -293,13 +68,15 @@ fsg_fs_bulk_out_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  	/* wMaxPacketSize set by autoconfiguration */  }; +EXPORT_SYMBOL_GPL(fsg_fs_bulk_out_desc); -static struct usb_descriptor_header *fsg_fs_function[] = { +struct usb_descriptor_header *fsg_fs_function[] = {  	(struct usb_descriptor_header *) &fsg_intf_desc,  	(struct usb_descriptor_header *) &fsg_fs_bulk_in_desc,  	(struct usb_descriptor_header *) &fsg_fs_bulk_out_desc,  	NULL,  }; +EXPORT_SYMBOL_GPL(fsg_fs_function);  /* @@ -310,8 +87,7 @@ static struct usb_descriptor_header *fsg_fs_function[] = {   * and a "device qualifier" ... plus more construction options   * for the configuration descriptor.   */ -static struct usb_endpoint_descriptor -fsg_hs_bulk_in_desc = { +struct usb_endpoint_descriptor fsg_hs_bulk_in_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -319,9 +95,9 @@ fsg_hs_bulk_in_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  	.wMaxPacketSize =	cpu_to_le16(512),  }; +EXPORT_SYMBOL_GPL(fsg_hs_bulk_in_desc); -static struct usb_endpoint_descriptor -fsg_hs_bulk_out_desc = { +struct usb_endpoint_descriptor fsg_hs_bulk_out_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -330,17 +106,18 @@ fsg_hs_bulk_out_desc = {  	.wMaxPacketSize =	cpu_to_le16(512),  	.bInterval =		1,	/* NAK every 1 uframe */  }; +EXPORT_SYMBOL_GPL(fsg_hs_bulk_out_desc); -static struct usb_descriptor_header *fsg_hs_function[] = { +struct usb_descriptor_header *fsg_hs_function[] = {  	(struct usb_descriptor_header *) &fsg_intf_desc,  	(struct usb_descriptor_header *) &fsg_hs_bulk_in_desc,  	(struct usb_descriptor_header *) &fsg_hs_bulk_out_desc,  	NULL,  }; +EXPORT_SYMBOL_GPL(fsg_hs_function); -static struct usb_endpoint_descriptor -fsg_ss_bulk_in_desc = { +struct usb_endpoint_descriptor fsg_ss_bulk_in_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -348,16 +125,17 @@ fsg_ss_bulk_in_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  	.wMaxPacketSize =	cpu_to_le16(1024),  }; +EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_desc); -static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = { +struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc = {  	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,  	/*.bMaxBurst =		DYNAMIC, */  }; +EXPORT_SYMBOL_GPL(fsg_ss_bulk_in_comp_desc); -static struct usb_endpoint_descriptor -fsg_ss_bulk_out_desc = { +struct usb_endpoint_descriptor fsg_ss_bulk_out_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, @@ -365,15 +143,17 @@ fsg_ss_bulk_out_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  	.wMaxPacketSize =	cpu_to_le16(1024),  }; +EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_desc); -static struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = { +struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc = {  	.bLength =		sizeof(fsg_ss_bulk_in_comp_desc),  	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,  	/*.bMaxBurst =		DYNAMIC, */  }; +EXPORT_SYMBOL_GPL(fsg_ss_bulk_out_comp_desc); -static struct usb_descriptor_header *fsg_ss_function[] = { +struct usb_descriptor_header *fsg_ss_function[] = {  	(struct usb_descriptor_header *) &fsg_intf_desc,  	(struct usb_descriptor_header *) &fsg_ss_bulk_in_desc,  	(struct usb_descriptor_header *) &fsg_ss_bulk_in_comp_desc, @@ -381,17 +161,7 @@ static struct usb_descriptor_header *fsg_ss_function[] = {  	(struct usb_descriptor_header *) &fsg_ss_bulk_out_comp_desc,  	NULL,  }; - -/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ -static struct usb_string		fsg_strings[] = { -	{FSG_STRING_INTERFACE,		fsg_string_interface}, -	{} -}; - -static struct usb_gadget_strings	fsg_stringtab = { -	.language	= 0x0409,		/* en-us */ -	.strings	= fsg_strings, -}; +EXPORT_SYMBOL_GPL(fsg_ss_function);   /*-------------------------------------------------------------------------*/ @@ -401,7 +171,7 @@ static struct usb_gadget_strings	fsg_stringtab = {   * the caller must own fsg->filesem for writing.   */ -static void fsg_lun_close(struct fsg_lun *curlun) +void fsg_lun_close(struct fsg_lun *curlun)  {  	if (curlun->filp) {  		LDBG(curlun, "close backing file\n"); @@ -409,9 +179,9 @@ static void fsg_lun_close(struct fsg_lun *curlun)  		curlun->filp = NULL;  	}  } +EXPORT_SYMBOL_GPL(fsg_lun_close); - -static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) +int fsg_lun_open(struct fsg_lun *curlun, const char *filename)  {  	int				ro;  	struct file			*filp = NULL; @@ -450,11 +220,11 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)  	 * If we can't read the file, it's no good.  	 * If we can't write the file, use it read-only.  	 */ -	if (!(filp->f_op->read || filp->f_op->aio_read)) { +	if (!(filp->f_mode & FMODE_CAN_READ)) {  		LINFO(curlun, "file not readable: %s\n", filename);  		goto out;  	} -	if (!(filp->f_op->write || filp->f_op->aio_write)) +	if (!(filp->f_mode & FMODE_CAN_WRITE))  		ro = 1;  	size = i_size_read(inode->i_mapping->host); @@ -508,6 +278,7 @@ out:  	fput(filp);  	return rc;  } +EXPORT_SYMBOL_GPL(fsg_lun_open);  /*-------------------------------------------------------------------------*/ @@ -516,7 +287,7 @@ out:   * Sync the file data, don't bother with the metadata.   * This code was copied from fs/buffer.c:sys_fdatasync().   */ -static int fsg_lun_fsync_sub(struct fsg_lun *curlun) +int fsg_lun_fsync_sub(struct fsg_lun *curlun)  {  	struct file	*filp = curlun->filp; @@ -524,8 +295,9 @@ static int fsg_lun_fsync_sub(struct fsg_lun *curlun)  		return 0;  	return vfs_fsync(filp, 1);  } +EXPORT_SYMBOL_GPL(fsg_lun_fsync_sub); -static void store_cdrom_address(u8 *dest, int msf, u32 addr) +void store_cdrom_address(u8 *dest, int msf, u32 addr)  {  	if (msf) {  		/* Convert to Minutes-Seconds-Frames */ @@ -542,34 +314,28 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr)  		put_unaligned_be32(addr, dest);  	}  } - +EXPORT_SYMBOL_GPL(store_cdrom_address);  /*-------------------------------------------------------------------------*/ -static ssize_t ro_show(struct device *dev, struct device_attribute *attr, -		       char *buf) +ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -  	return sprintf(buf, "%d\n", fsg_lun_is_open(curlun)  				  ? curlun->ro  				  : curlun->initially_ro);  } +EXPORT_SYMBOL_GPL(fsg_show_ro); -static ssize_t nofua_show(struct device *dev, struct device_attribute *attr, -			  char *buf) +ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -  	return sprintf(buf, "%u\n", curlun->nofua);  } +EXPORT_SYMBOL_GPL(fsg_show_nofua); -static ssize_t file_show(struct device *dev, struct device_attribute *attr, -			 char *buf) +ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		      char *buf)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -	struct rw_semaphore	*filesem = dev_get_drvdata(dev);  	char		*p;  	ssize_t		rc; @@ -591,17 +357,44 @@ static ssize_t file_show(struct device *dev, struct device_attribute *attr,  	up_read(filesem);  	return rc;  } +EXPORT_SYMBOL_GPL(fsg_show_file); +ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf) +{ +	return sprintf(buf, "%u\n", curlun->cdrom); +} +EXPORT_SYMBOL_GPL(fsg_show_cdrom); -static ssize_t ro_store(struct device *dev, struct device_attribute *attr, -			const char *buf, size_t count) +ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf) +{ +	return sprintf(buf, "%u\n", curlun->removable); +} +EXPORT_SYMBOL_GPL(fsg_show_removable); + +/* + * The caller must hold fsg->filesem for reading when calling this function. + */ +static ssize_t _fsg_store_ro(struct fsg_lun *curlun, bool ro) +{ +	if (fsg_lun_is_open(curlun)) { +		LDBG(curlun, "read-only status change prevented\n"); +		return -EBUSY; +	} + +	curlun->ro = ro; +	curlun->initially_ro = ro; +	LDBG(curlun, "read-only status set to %d\n", curlun->ro); + +	return 0; +} + +ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		     const char *buf, size_t count)  {  	ssize_t		rc; -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -	struct rw_semaphore	*filesem = dev_get_drvdata(dev); -	unsigned	ro; +	bool		ro; -	rc = kstrtouint(buf, 2, &ro); +	rc = strtobool(buf, &ro);  	if (rc)  		return rc; @@ -610,27 +403,21 @@ static ssize_t ro_store(struct device *dev, struct device_attribute *attr,  	 * backing file is closed.  	 */  	down_read(filesem); -	if (fsg_lun_is_open(curlun)) { -		LDBG(curlun, "read-only status change prevented\n"); -		rc = -EBUSY; -	} else { -		curlun->ro = ro; -		curlun->initially_ro = ro; -		LDBG(curlun, "read-only status set to %d\n", curlun->ro); +	rc = _fsg_store_ro(curlun, ro); +	if (!rc)  		rc = count; -	}  	up_read(filesem); +  	return rc;  } +EXPORT_SYMBOL_GPL(fsg_store_ro); -static ssize_t nofua_store(struct device *dev, struct device_attribute *attr, -			   const char *buf, size_t count) +ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -	unsigned	nofua; +	bool		nofua;  	int		ret; -	ret = kstrtouint(buf, 2, &nofua); +	ret = strtobool(buf, &nofua);  	if (ret)  		return ret; @@ -642,12 +429,11 @@ static ssize_t nofua_store(struct device *dev, struct device_attribute *attr,  	return count;  } +EXPORT_SYMBOL_GPL(fsg_store_nofua); -static ssize_t file_store(struct device *dev, struct device_attribute *attr, -			  const char *buf, size_t count) +ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		       const char *buf, size_t count)  { -	struct fsg_lun	*curlun = fsg_lun_from_dev(dev); -	struct rw_semaphore	*filesem = dev_get_drvdata(dev);  	int		rc = 0;  	if (curlun->prevent_medium_removal && fsg_lun_is_open(curlun)) { @@ -674,3 +460,45 @@ static ssize_t file_store(struct device *dev, struct device_attribute *attr,  	up_write(filesem);  	return (rc < 0 ? rc : count);  } +EXPORT_SYMBOL_GPL(fsg_store_file); + +ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, +			const char *buf, size_t count) +{ +	bool		cdrom; +	int		ret; + +	ret = strtobool(buf, &cdrom); +	if (ret) +		return ret; + +	down_read(filesem); +	ret = cdrom ? _fsg_store_ro(curlun, true) : 0; + +	if (!ret) { +		curlun->cdrom = cdrom; +		ret = count; +	} +	up_read(filesem); + +	return ret; +} +EXPORT_SYMBOL_GPL(fsg_store_cdrom); + +ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, +			    size_t count) +{ +	bool		removable; +	int		ret; + +	ret = strtobool(buf, &removable); +	if (ret) +		return ret; + +	curlun->removable = removable; + +	return count; +} +EXPORT_SYMBOL_GPL(fsg_store_removable); + +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/storage_common.h b/drivers/usb/gadget/storage_common.h new file mode 100644 index 00000000000..70c891469f5 --- /dev/null +++ b/drivers/usb/gadget/storage_common.h @@ -0,0 +1,225 @@ +#ifndef USB_STORAGE_COMMON_H +#define USB_STORAGE_COMMON_H + +#include <linux/device.h> +#include <linux/usb/storage.h> +#include <scsi/scsi.h> +#include <asm/unaligned.h> + +#ifndef DEBUG +#undef VERBOSE_DEBUG +#undef DUMP_MSGS +#endif /* !DEBUG */ + +#ifdef VERBOSE_DEBUG +#define VLDBG	LDBG +#else +#define VLDBG(lun, fmt, args...) do { } while (0) +#endif /* VERBOSE_DEBUG */ + +#define _LMSG(func, lun, fmt, args...)					\ +	do {								\ +		if ((lun)->name_pfx && *(lun)->name_pfx)		\ +			func("%s/%s: " fmt, *(lun)->name_pfx,		\ +				 (lun)->name, ## args);			\ +		else							\ +			func("%s: " fmt, (lun)->name, ## args);		\ +	} while (0) + +#define LDBG(lun, fmt, args...)		_LMSG(pr_debug, lun, fmt, ## args) +#define LERROR(lun, fmt, args...)	_LMSG(pr_err, lun, fmt, ## args) +#define LWARN(lun, fmt, args...)	_LMSG(pr_warn, lun, fmt, ## args) +#define LINFO(lun, fmt, args...)	_LMSG(pr_info, lun, fmt, ## args) + + +#ifdef DUMP_MSGS + +#  define dump_msg(fsg, /* const char * */ label,			\ +		   /* const u8 * */ buf, /* unsigned */ length)		\ +do {									\ +	if (length < 512) {						\ +		DBG(fsg, "%s, length %u:\n", label, length);		\ +		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,	\ +			       16, 1, buf, length, 0);			\ +	}								\ +} while (0) + +#  define dump_cdb(fsg) do { } while (0) + +#else + +#  define dump_msg(fsg, /* const char * */ label, \ +		   /* const u8 * */ buf, /* unsigned */ length) do { } while (0) + +#  ifdef VERBOSE_DEBUG + +#    define dump_cdb(fsg)						\ +	print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,	\ +		       16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0)		\ + +#  else + +#    define dump_cdb(fsg) do { } while (0) + +#  endif /* VERBOSE_DEBUG */ + +#endif /* DUMP_MSGS */ + +/* Length of a SCSI Command Data Block */ +#define MAX_COMMAND_SIZE	16 + +/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ +#define SS_NO_SENSE				0 +#define SS_COMMUNICATION_FAILURE		0x040800 +#define SS_INVALID_COMMAND			0x052000 +#define SS_INVALID_FIELD_IN_CDB			0x052400 +#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE	0x052100 +#define SS_LOGICAL_UNIT_NOT_SUPPORTED		0x052500 +#define SS_MEDIUM_NOT_PRESENT			0x023a00 +#define SS_MEDIUM_REMOVAL_PREVENTED		0x055302 +#define SS_NOT_READY_TO_READY_TRANSITION	0x062800 +#define SS_RESET_OCCURRED			0x062900 +#define SS_SAVING_PARAMETERS_NOT_SUPPORTED	0x053900 +#define SS_UNRECOVERED_READ_ERROR		0x031100 +#define SS_WRITE_ERROR				0x030c02 +#define SS_WRITE_PROTECTED			0x072700 + +#define SK(x)		((u8) ((x) >> 16))	/* Sense Key byte, etc. */ +#define ASC(x)		((u8) ((x) >> 8)) +#define ASCQ(x)		((u8) (x)) + +struct fsg_lun { +	struct file	*filp; +	loff_t		file_length; +	loff_t		num_sectors; + +	unsigned int	initially_ro:1; +	unsigned int	ro:1; +	unsigned int	removable:1; +	unsigned int	cdrom:1; +	unsigned int	prevent_medium_removal:1; +	unsigned int	registered:1; +	unsigned int	info_valid:1; +	unsigned int	nofua:1; + +	u32		sense_data; +	u32		sense_data_info; +	u32		unit_attention_data; + +	unsigned int	blkbits; /* Bits of logical block size +						       of bound block device */ +	unsigned int	blksize; /* logical block size of bound block device */ +	struct device	dev; +	const char	*name;		/* "lun.name" */ +	const char	**name_pfx;	/* "function.name" */ +}; + +static inline bool fsg_lun_is_open(struct fsg_lun *curlun) +{ +	return curlun->filp != NULL; +} + +/* Default size of buffer length. */ +#define FSG_BUFLEN	((u32)16384) + +/* Maximal number of LUNs supported in mass storage function */ +#define FSG_MAX_LUNS	8 + +enum fsg_buffer_state { +	BUF_STATE_EMPTY = 0, +	BUF_STATE_FULL, +	BUF_STATE_BUSY +}; + +struct fsg_buffhd { +	void				*buf; +	enum fsg_buffer_state		state; +	struct fsg_buffhd		*next; + +	/* +	 * The NetChip 2280 is faster, and handles some protocol faults +	 * better, if we don't submit any short bulk-out read requests. +	 * So we will record the intended request length here. +	 */ +	unsigned int			bulk_out_intended_length; + +	struct usb_request		*inreq; +	int				inreq_busy; +	struct usb_request		*outreq; +	int				outreq_busy; +}; + +enum fsg_state { +	/* This one isn't used anywhere */ +	FSG_STATE_COMMAND_PHASE = -10, +	FSG_STATE_DATA_PHASE, +	FSG_STATE_STATUS_PHASE, + +	FSG_STATE_IDLE = 0, +	FSG_STATE_ABORT_BULK_OUT, +	FSG_STATE_RESET, +	FSG_STATE_INTERFACE_CHANGE, +	FSG_STATE_CONFIG_CHANGE, +	FSG_STATE_DISCONNECT, +	FSG_STATE_EXIT, +	FSG_STATE_TERMINATED +}; + +enum data_direction { +	DATA_DIR_UNKNOWN = 0, +	DATA_DIR_FROM_HOST, +	DATA_DIR_TO_HOST, +	DATA_DIR_NONE +}; + +static inline u32 get_unaligned_be24(u8 *buf) +{ +	return 0xffffff & (u32) get_unaligned_be32(buf - 1); +} + +static inline struct fsg_lun *fsg_lun_from_dev(struct device *dev) +{ +	return container_of(dev, struct fsg_lun, dev); +} + +enum { +	FSG_STRING_INTERFACE +}; + +extern struct usb_interface_descriptor fsg_intf_desc; + +extern struct usb_endpoint_descriptor fsg_fs_bulk_in_desc; +extern struct usb_endpoint_descriptor fsg_fs_bulk_out_desc; +extern struct usb_descriptor_header *fsg_fs_function[]; + +extern struct usb_endpoint_descriptor fsg_hs_bulk_in_desc; +extern struct usb_endpoint_descriptor fsg_hs_bulk_out_desc; +extern struct usb_descriptor_header *fsg_hs_function[]; + +extern struct usb_endpoint_descriptor fsg_ss_bulk_in_desc; +extern struct usb_ss_ep_comp_descriptor fsg_ss_bulk_in_comp_desc; +extern struct usb_endpoint_descriptor fsg_ss_bulk_out_desc; +extern struct usb_ss_ep_comp_descriptor fsg_ss_bulk_out_comp_desc; +extern struct usb_descriptor_header *fsg_ss_function[]; + +void fsg_lun_close(struct fsg_lun *curlun); +int fsg_lun_open(struct fsg_lun *curlun, const char *filename); +int fsg_lun_fsync_sub(struct fsg_lun *curlun); +void store_cdrom_address(u8 *dest, int msf, u32 addr); +ssize_t fsg_show_ro(struct fsg_lun *curlun, char *buf); +ssize_t fsg_show_nofua(struct fsg_lun *curlun, char *buf); +ssize_t fsg_show_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		      char *buf); +ssize_t fsg_show_cdrom(struct fsg_lun *curlun, char *buf); +ssize_t fsg_show_removable(struct fsg_lun *curlun, char *buf); +ssize_t fsg_store_ro(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		     const char *buf, size_t count); +ssize_t fsg_store_nofua(struct fsg_lun *curlun, const char *buf, size_t count); +ssize_t fsg_store_file(struct fsg_lun *curlun, struct rw_semaphore *filesem, +		       const char *buf, size_t count); +ssize_t fsg_store_cdrom(struct fsg_lun *curlun, struct rw_semaphore *filesem, +			const char *buf, size_t count); +ssize_t fsg_store_removable(struct fsg_lun *curlun, const char *buf, +			    size_t count); + +#endif /* USB_STORAGE_COMMON_H */ diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c index 0ff33396eef..6cdb7a534f2 100644 --- a/drivers/usb/gadget/tcm_usb_gadget.c +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -370,7 +370,7 @@ err:  	return -ENOMEM;  } -void bot_cleanup_old_alt(struct f_uas *fu) +static void bot_cleanup_old_alt(struct f_uas *fu)  {  	if (!(fu->flags & USBG_ENABLED))  		return; @@ -472,7 +472,7 @@ static int usbg_bot_setup(struct usb_function *f,  		bot_enqueue_cmd_cbw(fu);  		return 0;  		break; -	}; +	}  	return -ENOTSUPP;  } @@ -617,7 +617,7 @@ static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req)  	default:  		BUG(); -	}; +	}  	return;  cleanup: @@ -1383,10 +1383,8 @@ static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg)  	struct usbg_nacl *nacl;  	nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL); -	if (!nacl) { -		printk(KERN_ERR "Unable to allocate struct usbg_nacl\n"); +	if (!nacl)  		return NULL; -	}  	return &nacl->se_node_acl;  } @@ -1471,6 +1469,11 @@ static void usbg_queue_tm_rsp(struct se_cmd *se_cmd)  {  } +static void usbg_aborted_task(struct se_cmd *se_cmd) +{ +	return; +} +  static const char *usbg_check_wwn(const char *name)  {  	const char *n; @@ -1556,10 +1559,8 @@ static struct se_portal_group *usbg_make_tpg(  	}  	tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL); -	if (!tpg) { -		printk(KERN_ERR "Unable to allocate struct usbg_tpg"); +	if (!tpg)  		return ERR_PTR(-ENOMEM); -	}  	mutex_init(&tpg->tpg_mutex);  	atomic_set(&tpg->tpg_port_count, 0);  	tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1); @@ -1608,12 +1609,10 @@ static struct se_wwn *usbg_make_tport(  		return ERR_PTR(-EINVAL);  	tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL); -	if (!(tport)) { -		printk(KERN_ERR "Unable to allocate struct usbg_tport"); +	if (!(tport))  		return ERR_PTR(-ENOMEM); -	}  	tport->tport_wwpn = wwpn; -	snprintf(tport->tport_name, sizeof(tport->tport_name), wnn_name); +	snprintf(tport->tport_name, sizeof(tport->tport_name), "%s", wnn_name);  	return &tport->tport_wwn;  } @@ -1722,11 +1721,9 @@ static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name)  	ret = -ENOMEM;  	tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL); -	if (!tv_nexus) { -		pr_err("Unable to allocate struct tcm_vhost_nexus\n"); +	if (!tv_nexus)  		goto err_unlock; -	} -	tv_nexus->tvn_se_sess = transport_init_session(); +	tv_nexus->tvn_se_sess = transport_init_session(TARGET_PROT_NORMAL);  	if (IS_ERR(tv_nexus->tvn_se_sess))  		goto err_free; @@ -1846,7 +1843,7 @@ static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun)  	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);  	atomic_inc(&tpg->tpg_port_count); -	smp_mb__after_atomic_inc(); +	smp_mb__after_atomic();  	return 0;  } @@ -1856,7 +1853,7 @@ static void usbg_port_unlink(struct se_portal_group *se_tpg,  	struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);  	atomic_dec(&tpg->tpg_port_count); -	smp_mb__after_atomic_dec(); +	smp_mb__after_atomic();  }  static int usbg_check_stop_free(struct se_cmd *se_cmd) @@ -1897,6 +1894,7 @@ static struct target_core_fabric_ops usbg_ops = {  	.queue_data_in			= usbg_send_read_response,  	.queue_status			= usbg_send_status_response,  	.queue_tm_rsp			= usbg_queue_tm_rsp, +	.aborted_task			= usbg_aborted_task,  	.check_stop_free		= usbg_check_stop_free,  	.fabric_make_wwn		= usbg_make_tport, @@ -1923,15 +1921,15 @@ static int usbg_register_configfs(void)  	}  	fabric->tf_ops = usbg_ops; -	TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = usbg_wwn_attrs; -	TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = usbg_base_attrs; -	TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL; -	TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL; -	TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL; -	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL; -	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; -	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL; -	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = usbg_wwn_attrs; +	fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = usbg_base_attrs; +	fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_tpg_nacl_base_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_tpg_nacl_auth_cit.ct_attrs = NULL; +	fabric->tf_cit_tmpl.tfc_tpg_nacl_param_cit.ct_attrs = NULL;  	ret = target_fabric_configfs_register(fabric);  	if (ret < 0) {  		printk(KERN_ERR "target_fabric_configfs_register() failed" diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 2aae0d61bb1..97b027724ee 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -753,7 +753,7 @@ static struct device_type gadget_type = {   * gadget driver using this framework.  The link layer addresses are   * set up using module parameters.   * - * Returns negative errno, or zero on success + * Returns an eth_dev pointer on success, or an ERR_PTR on failure.   */  struct eth_dev *gether_setup_name(struct usb_gadget *g,  		const char *dev_addr, const char *host_addr, @@ -793,7 +793,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,  	net->netdev_ops = ð_netdev_ops; -	SET_ETHTOOL_OPS(net, &ops); +	net->ethtool_ops = &ops;  	dev->gadget = g;  	SET_NETDEV_DEV(net, &g->dev); @@ -818,7 +818,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,  	return dev;  } -EXPORT_SYMBOL(gether_setup_name); +EXPORT_SYMBOL_GPL(gether_setup_name);  struct net_device *gether_setup_name_default(const char *netname)  { @@ -850,12 +850,12 @@ struct net_device *gether_setup_name_default(const char *netname)  	net->netdev_ops = ð_netdev_ops; -	SET_ETHTOOL_OPS(net, &ops); +	net->ethtool_ops = &ops;  	SET_NETDEV_DEVTYPE(net, &gadget_type);  	return net;  } -EXPORT_SYMBOL(gether_setup_name_default); +EXPORT_SYMBOL_GPL(gether_setup_name_default);  int gether_register_netdev(struct net_device *net)  { @@ -893,7 +893,7 @@ int gether_register_netdev(struct net_device *net)  	return status;  } -EXPORT_SYMBOL(gether_register_netdev); +EXPORT_SYMBOL_GPL(gether_register_netdev);  void gether_set_gadget(struct net_device *net, struct usb_gadget *g)  { @@ -903,7 +903,7 @@ void gether_set_gadget(struct net_device *net, struct usb_gadget *g)  	dev->gadget = g;  	SET_NETDEV_DEV(net, &g->dev);  } -EXPORT_SYMBOL(gether_set_gadget); +EXPORT_SYMBOL_GPL(gether_set_gadget);  int gether_set_dev_addr(struct net_device *net, const char *dev_addr)  { @@ -916,7 +916,7 @@ int gether_set_dev_addr(struct net_device *net, const char *dev_addr)  	memcpy(dev->dev_mac, new_addr, ETH_ALEN);  	return 0;  } -EXPORT_SYMBOL(gether_set_dev_addr); +EXPORT_SYMBOL_GPL(gether_set_dev_addr);  int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len)  { @@ -925,7 +925,7 @@ int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len)  	dev = netdev_priv(net);  	return get_ether_addr_str(dev->dev_mac, dev_addr, len);  } -EXPORT_SYMBOL(gether_get_dev_addr); +EXPORT_SYMBOL_GPL(gether_get_dev_addr);  int gether_set_host_addr(struct net_device *net, const char *host_addr)  { @@ -938,7 +938,7 @@ int gether_set_host_addr(struct net_device *net, const char *host_addr)  	memcpy(dev->host_mac, new_addr, ETH_ALEN);  	return 0;  } -EXPORT_SYMBOL(gether_set_host_addr); +EXPORT_SYMBOL_GPL(gether_set_host_addr);  int gether_get_host_addr(struct net_device *net, char *host_addr, int len)  { @@ -947,7 +947,7 @@ int gether_get_host_addr(struct net_device *net, char *host_addr, int len)  	dev = netdev_priv(net);  	return get_ether_addr_str(dev->host_mac, host_addr, len);  } -EXPORT_SYMBOL(gether_get_host_addr); +EXPORT_SYMBOL_GPL(gether_get_host_addr);  int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len)  { @@ -961,7 +961,7 @@ int gether_get_host_addr_cdc(struct net_device *net, char *host_addr, int len)  	return strlen(host_addr);  } -EXPORT_SYMBOL(gether_get_host_addr_cdc); +EXPORT_SYMBOL_GPL(gether_get_host_addr_cdc);  void gether_get_host_addr_u8(struct net_device *net, u8 host_mac[ETH_ALEN])  { @@ -970,7 +970,7 @@ void gether_get_host_addr_u8(struct net_device *net, u8 host_mac[ETH_ALEN])  	dev = netdev_priv(net);  	memcpy(host_mac, dev->host_mac, ETH_ALEN);  } -EXPORT_SYMBOL(gether_get_host_addr_u8); +EXPORT_SYMBOL_GPL(gether_get_host_addr_u8);  void gether_set_qmult(struct net_device *net, unsigned qmult)  { @@ -979,7 +979,7 @@ void gether_set_qmult(struct net_device *net, unsigned qmult)  	dev = netdev_priv(net);  	dev->qmult = qmult;  } -EXPORT_SYMBOL(gether_set_qmult); +EXPORT_SYMBOL_GPL(gether_set_qmult);  unsigned gether_get_qmult(struct net_device *net)  { @@ -988,7 +988,7 @@ unsigned gether_get_qmult(struct net_device *net)  	dev = netdev_priv(net);  	return dev->qmult;  } -EXPORT_SYMBOL(gether_get_qmult); +EXPORT_SYMBOL_GPL(gether_get_qmult);  int gether_get_ifname(struct net_device *net, char *name, int len)  { @@ -997,7 +997,7 @@ int gether_get_ifname(struct net_device *net, char *name, int len)  	rtnl_unlock();  	return strlen(name);  } -EXPORT_SYMBOL(gether_get_ifname); +EXPORT_SYMBOL_GPL(gether_get_ifname);  /**   * gether_cleanup - remove Ethernet-over-USB device @@ -1014,7 +1014,7 @@ void gether_cleanup(struct eth_dev *dev)  	flush_work(&dev->work);  	free_netdev(dev->net);  } -EXPORT_SYMBOL(gether_cleanup); +EXPORT_SYMBOL_GPL(gether_cleanup);  /**   * gether_connect - notify network layer that USB link is active @@ -1095,7 +1095,7 @@ fail0:  		return ERR_PTR(result);  	return dev->net;  } -EXPORT_SYMBOL(gether_connect); +EXPORT_SYMBOL_GPL(gether_connect);  /**   * gether_disconnect - notify network layer that USB link is inactive @@ -1120,7 +1120,10 @@ void gether_disconnect(struct gether *link)  	DBG(dev, "%s\n", __func__); +	netif_tx_lock(dev->net);  	netif_stop_queue(dev->net); +	netif_tx_unlock(dev->net); +  	netif_carrier_off(dev->net);  	/* disable endpoints, forcing (synchronous) completion @@ -1166,7 +1169,7 @@ void gether_disconnect(struct gether *link)  	dev->port_usb = NULL;  	spin_unlock(&dev->lock);  } -EXPORT_SYMBOL(gether_disconnect); +EXPORT_SYMBOL_GPL(gether_disconnect);  MODULE_LICENSE("GPL");  MODULE_AUTHOR("David Brownell"); diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h index fb23d1fde8e..0f0290acea7 100644 --- a/drivers/usb/gadget/u_ether.h +++ b/drivers/usb/gadget/u_ether.h @@ -106,7 +106,7 @@ struct eth_dev *gether_setup_name(struct usb_gadget *g,   * gadget driver using this framework.  The link layer addresses are   * set up using module parameters.   * - * Returns negative errno, or zero on success + * Returns a eth_dev pointer on success, or an ERR_PTR on failure   */  static inline struct eth_dev *gether_setup(struct usb_gadget *g,  		const char *dev_addr, const char *host_addr, @@ -267,45 +267,4 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)  	return true;  } -/* each configuration may bind one instance of an ethernet link */ -int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		struct eth_dev *dev); -int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		struct eth_dev *dev); - -#ifdef USB_ETH_RNDIS - -int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		u32 vendorID, const char *manufacturer, struct eth_dev *dev); - -#else - -static inline int -rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], -		u32 vendorID, const char *manufacturer, struct eth_dev *dev) -{ -	return 0; -} - -#endif - -/** - * rndis_bind_config - add RNDIS network link to a configuration - * @c: the configuration to support the network link - * @ethaddr: a buffer in which the ethernet address of the host side - *	side of the link was recorded - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup().  Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ -static inline int rndis_bind_config(struct usb_configuration *c, -		u8 ethaddr[ETH_ALEN], struct eth_dev *dev) -{ -	return rndis_bind_config_vendor(c, ethaddr, 0, NULL, dev); -} - -  #endif /* __U_ETHER_H */ diff --git a/drivers/usb/gadget/u_f.c b/drivers/usb/gadget/u_f.c new file mode 100644 index 00000000000..c6276f0268a --- /dev/null +++ b/drivers/usb/gadget/u_f.c @@ -0,0 +1,32 @@ +/* + * u_f.c -- USB function utilities for Gadget stack + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/usb/gadget.h> +#include "u_f.h" + +struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len) +{ +	struct usb_request      *req; + +	req = usb_ep_alloc_request(ep, GFP_ATOMIC); +	if (req) { +		req->length = len ?: default_len; +		req->buf = kmalloc(req->length, GFP_ATOMIC); +		if (!req->buf) { +			usb_ep_free_request(ep, req); +			req = NULL; +		} +	} +	return req; +} +EXPORT_SYMBOL_GPL(alloc_ep_req); diff --git a/drivers/usb/gadget/u_f.h b/drivers/usb/gadget/u_f.h new file mode 100644 index 00000000000..1d5f0eb6855 --- /dev/null +++ b/drivers/usb/gadget/u_f.h @@ -0,0 +1,52 @@ +/* + * u_f.h + * + * Utility definitions for USB functions + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __U_F_H__ +#define __U_F_H__ + +/* Variable Length Array Macros **********************************************/ +#define vla_group(groupname) size_t groupname##__next = 0 +#define vla_group_size(groupname) groupname##__next + +#define vla_item(groupname, type, name, n) \ +	size_t groupname##_##name##__offset = ({			       \ +		size_t align_mask = __alignof__(type) - 1;		       \ +		size_t offset = (groupname##__next + align_mask) & ~align_mask;\ +		size_t size = (n) * sizeof(type);			       \ +		groupname##__next = offset + size;			       \ +		offset;							       \ +	}) + +#define vla_item_with_sz(groupname, type, name, n) \ +	size_t groupname##_##name##__sz = (n) * sizeof(type);		       \ +	size_t groupname##_##name##__offset = ({			       \ +		size_t align_mask = __alignof__(type) - 1;		       \ +		size_t offset = (groupname##__next + align_mask) & ~align_mask;\ +		size_t size = groupname##_##name##__sz;			       \ +		groupname##__next = offset + size;			       \ +		offset;							       \ +	}) + +#define vla_ptr(ptr, groupname, name) \ +	((void *) ((char *)ptr + groupname##_##name##__offset)) + +struct usb_ep; +struct usb_request; + +struct usb_request *alloc_ep_req(struct usb_ep *ep, int len, int default_len); + +#endif /* __U_F_H__ */ + + diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h new file mode 100644 index 00000000000..bf0ba375d45 --- /dev/null +++ b/drivers/usb/gadget/u_fs.h @@ -0,0 +1,263 @@ +/* + * u_fs.h + * + * Utility definitions for the FunctionFS + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef U_FFS_H +#define U_FFS_H + +#include <linux/usb/composite.h> +#include <linux/list.h> +#include <linux/mutex.h> + +#ifdef VERBOSE_DEBUG +#ifndef pr_vdebug +#  define pr_vdebug pr_debug +#endif /* pr_vdebug */ +#  define ffs_dump_mem(prefix, ptr, len) \ +	print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len) +#else +#ifndef pr_vdebug +#  define pr_vdebug(...)                 do { } while (0) +#endif /* pr_vdebug */ +#  define ffs_dump_mem(prefix, ptr, len) do { } while (0) +#endif /* VERBOSE_DEBUG */ + +#define ENTER()    pr_vdebug("%s()\n", __func__) + +struct f_fs_opts; + +struct ffs_dev { +	const char *name; +	bool name_allocated; +	bool mounted; +	bool desc_ready; +	bool single; +	struct ffs_data *ffs_data; +	struct f_fs_opts *opts; +	struct list_head entry; + +	int (*ffs_ready_callback)(struct ffs_data *ffs); +	void (*ffs_closed_callback)(struct ffs_data *ffs); +	void *(*ffs_acquire_dev_callback)(struct ffs_dev *dev); +	void (*ffs_release_dev_callback)(struct ffs_dev *dev); +}; + +extern struct mutex ffs_lock; + +static inline void ffs_dev_lock(void) +{ +	mutex_lock(&ffs_lock); +} + +static inline void ffs_dev_unlock(void) +{ +	mutex_unlock(&ffs_lock); +} + +int ffs_name_dev(struct ffs_dev *dev, const char *name); +int ffs_single_dev(struct ffs_dev *dev); + +struct ffs_epfile; +struct ffs_function; + +enum ffs_state { +	/* +	 * Waiting for descriptors and strings. +	 * +	 * In this state no open(2), read(2) or write(2) on epfiles +	 * may succeed (which should not be the problem as there +	 * should be no such files opened in the first place). +	 */ +	FFS_READ_DESCRIPTORS, +	FFS_READ_STRINGS, + +	/* +	 * We've got descriptors and strings.  We are or have called +	 * functionfs_ready_callback().  functionfs_bind() may have +	 * been called but we don't know. +	 * +	 * This is the only state in which operations on epfiles may +	 * succeed. +	 */ +	FFS_ACTIVE, + +	/* +	 * All endpoints have been closed.  This state is also set if +	 * we encounter an unrecoverable error.  The only +	 * unrecoverable error is situation when after reading strings +	 * from user space we fail to initialise epfiles or +	 * functionfs_ready_callback() returns with error (<0). +	 * +	 * In this state no open(2), read(2) or write(2) (both on ep0 +	 * as well as epfile) may succeed (at this point epfiles are +	 * unlinked and all closed so this is not a problem; ep0 is +	 * also closed but ep0 file exists and so open(2) on ep0 must +	 * fail). +	 */ +	FFS_CLOSING +}; + +enum ffs_setup_state { +	/* There is no setup request pending. */ +	FFS_NO_SETUP, +	/* +	 * User has read events and there was a setup request event +	 * there.  The next read/write on ep0 will handle the +	 * request. +	 */ +	FFS_SETUP_PENDING, +	/* +	 * There was event pending but before user space handled it +	 * some other event was introduced which canceled existing +	 * setup.  If this state is set read/write on ep0 return +	 * -EIDRM.  This state is only set when adding event. +	 */ +	FFS_SETUP_CANCELLED +}; + +struct ffs_data { +	struct usb_gadget		*gadget; + +	/* +	 * Protect access read/write operations, only one read/write +	 * at a time.  As a consequence protects ep0req and company. +	 * While setup request is being processed (queued) this is +	 * held. +	 */ +	struct mutex			mutex; + +	/* +	 * Protect access to endpoint related structures (basically +	 * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for +	 * endpoint zero. +	 */ +	spinlock_t			eps_lock; + +	/* +	 * XXX REVISIT do we need our own request? Since we are not +	 * handling setup requests immediately user space may be so +	 * slow that another setup will be sent to the gadget but this +	 * time not to us but another function and then there could be +	 * a race.  Is that the case? Or maybe we can use cdev->req +	 * after all, maybe we just need some spinlock for that? +	 */ +	struct usb_request		*ep0req;		/* P: mutex */ +	struct completion		ep0req_completion;	/* P: mutex */ + +	/* reference counter */ +	atomic_t			ref; +	/* how many files are opened (EP0 and others) */ +	atomic_t			opened; + +	/* EP0 state */ +	enum ffs_state			state; + +	/* +	 * Possible transitions: +	 * + FFS_NO_SETUP        -> FFS_SETUP_PENDING  -- P: ev.waitq.lock +	 *               happens only in ep0 read which is P: mutex +	 * + FFS_SETUP_PENDING   -> FFS_NO_SETUP       -- P: ev.waitq.lock +	 *               happens only in ep0 i/o  which is P: mutex +	 * + FFS_SETUP_PENDING   -> FFS_SETUP_CANCELLED -- P: ev.waitq.lock +	 * + FFS_SETUP_CANCELLED -> FFS_NO_SETUP        -- cmpxchg +	 * +	 * This field should never be accessed directly and instead +	 * ffs_setup_state_clear_cancelled function should be used. +	 */ +	enum ffs_setup_state		setup_state; + +	/* Events & such. */ +	struct { +		u8				types[4]; +		unsigned short			count; +		/* XXX REVISIT need to update it in some places, or do we? */ +		unsigned short			can_stall; +		struct usb_ctrlrequest		setup; + +		wait_queue_head_t		waitq; +	} ev; /* the whole structure, P: ev.waitq.lock */ + +	/* Flags */ +	unsigned long			flags; +#define FFS_FL_CALL_CLOSED_CALLBACK 0 +#define FFS_FL_BOUND                1 + +	/* Active function */ +	struct ffs_function		*func; + +	/* +	 * Device name, write once when file system is mounted. +	 * Intended for user to read if she wants. +	 */ +	const char			*dev_name; +	/* Private data for our user (ie. gadget).  Managed by user. */ +	void				*private_data; + +	/* filled by __ffs_data_got_descs() */ +	/* +	 * raw_descs is what you kfree, real_descs points inside of raw_descs, +	 * where full speed, high speed and super speed descriptors start. +	 * real_descs_length is the length of all those descriptors. +	 */ +	const void			*raw_descs_data; +	const void			*raw_descs; +	unsigned			raw_descs_length; +	unsigned			fs_descs_count; +	unsigned			hs_descs_count; +	unsigned			ss_descs_count; + +	unsigned short			strings_count; +	unsigned short			interfaces_count; +	unsigned short			eps_count; +	unsigned short			_pad1; + +	/* filled by __ffs_data_got_strings() */ +	/* ids in stringtabs are set in functionfs_bind() */ +	const void			*raw_strings; +	struct usb_gadget_strings	**stringtabs; + +	/* +	 * File system's super block, write once when file system is +	 * mounted. +	 */ +	struct super_block		*sb; + +	/* File permissions, written once when fs is mounted */ +	struct ffs_file_perms { +		umode_t				mode; +		kuid_t				uid; +		kgid_t				gid; +	}				file_perms; + +	/* +	 * The endpoint files, filled by ffs_epfiles_create(), +	 * destroyed by ffs_epfiles_destroy(). +	 */ +	struct ffs_epfile		*epfiles; +}; + + +struct f_fs_opts { +	struct usb_function_instance	func_inst; +	struct ffs_dev			*dev; +	unsigned			refcnt; +	bool				no_configfs; +}; + +static inline struct f_fs_opts *to_f_fs_opts(struct usb_function_instance *fi) +{ +	return container_of(fi, struct f_fs_opts, func_inst); +} + +#endif /* U_FFS_H */ diff --git a/drivers/usb/gadget/u_os_desc.h b/drivers/usb/gadget/u_os_desc.h new file mode 100644 index 00000000000..ea5cf8c2da2 --- /dev/null +++ b/drivers/usb/gadget/u_os_desc.h @@ -0,0 +1,90 @@ +/* + * u_os_desc.h + * + * Utility definitions for "OS Descriptors" support + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd. + *		http://www.samsung.com + * + * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __U_OS_DESC_H__ +#define __U_OS_DESC_H__ + +#include <asm/unaligned.h> +#include <linux/nls.h> + +#define USB_EXT_PROP_DW_SIZE			0 +#define USB_EXT_PROP_DW_PROPERTY_DATA_TYPE	4 +#define USB_EXT_PROP_W_PROPERTY_NAME_LENGTH	8 +#define USB_EXT_PROP_B_PROPERTY_NAME		10 +#define USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH	10 +#define USB_EXT_PROP_B_PROPERTY_DATA		14 + +#define USB_EXT_PROP_RESERVED			0 +#define USB_EXT_PROP_UNICODE			1 +#define USB_EXT_PROP_UNICODE_ENV		2 +#define USB_EXT_PROP_BINARY			3 +#define USB_EXT_PROP_LE32			4 +#define USB_EXT_PROP_BE32			5 +#define USB_EXT_PROP_UNICODE_LINK		6 +#define USB_EXT_PROP_UNICODE_MULTI		7 + +static inline void usb_ext_prop_put_size(u8 *buf, int dw_size) +{ +	put_unaligned_le32(dw_size, &buf[USB_EXT_PROP_DW_SIZE]); +} + +static inline void usb_ext_prop_put_type(u8 *buf, int type) +{ +	put_unaligned_le32(type, &buf[USB_EXT_PROP_DW_PROPERTY_DATA_TYPE]); +} + +static inline int usb_ext_prop_put_name(u8 *buf, const char *name, int pnl) +{ +	int result; + +	put_unaligned_le16(pnl, &buf[USB_EXT_PROP_W_PROPERTY_NAME_LENGTH]); +	result = utf8s_to_utf16s(name, strlen(name), UTF16_LITTLE_ENDIAN, +		(wchar_t *) &buf[USB_EXT_PROP_B_PROPERTY_NAME], pnl - 2); +	if (result < 0) +		return result; + +	put_unaligned_le16(0, &buf[USB_EXT_PROP_B_PROPERTY_NAME + pnl]); + +	return pnl; +} + +static inline void usb_ext_prop_put_binary(u8 *buf, int pnl, const u8 *data, +					   int data_len) +{ +	put_unaligned_le32(data_len, +			   &buf[USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + pnl]); +	memcpy(&buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl], data, data_len); +} + +static inline int usb_ext_prop_put_unicode(u8 *buf, int pnl, const char *string, +					   int data_len) +{ +	int result; +	put_unaligned_le32(data_len, +			&buf[USB_EXT_PROP_DW_PROPERTY_DATA_LENGTH + pnl]); + +	result = utf8s_to_utf16s(string, data_len >> 1, UTF16_LITTLE_ENDIAN, +			(wchar_t *) &buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl], +			data_len - 2); +	if (result < 0) +		return result; + +	put_unaligned_le16(0, +			&buf[USB_EXT_PROP_B_PROPERTY_DATA + pnl + data_len]); + +	return data_len; +} + +#endif /* __U_OS_DESC_H__ */ diff --git a/drivers/usb/gadget/u_rndis.h b/drivers/usb/gadget/u_rndis.h index c62ba82e960..e902aa42a29 100644 --- a/drivers/usb/gadget/u_rndis.h +++ b/drivers/usb/gadget/u_rndis.h @@ -26,6 +26,9 @@ struct f_rndis_opts {  	bool				bound;  	bool				borrowed_net; +	struct usb_os_desc		rndis_os_desc; +	char				rndis_ext_compat_id[16]; +  	/*  	 * Read/write access to configfs attributes is handled by configfs.  	 * @@ -36,6 +39,8 @@ struct f_rndis_opts {  	int				refcnt;  }; +int rndis_init(void); +void rndis_exit(void);  void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net);  #endif /* U_RNDIS_H */ diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index b369292d4b9..ad0aca81200 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -549,8 +549,8 @@ static void gs_rx_push(unsigned long _port)  		port->read_started--;  	} -	/* Push from tty to ldisc; without low_latency set this is handled by -	 * a workqueue, so we won't get callbacks and can hold port_lock +	/* Push from tty to ldisc; this is handled by a workqueue, +	 * so we won't get callbacks and can hold port_lock  	 */  	if (do_push)  		tty_flip_buffer_push(&port->port); diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 59891b1c48f..b0d98172bc0 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -356,7 +356,8 @@ static int udc_bind_to_driver(struct usb_udc *udc, struct usb_gadget_driver *dri  	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);  	return 0;  err1: -	dev_err(&udc->dev, "failed to start %s: %d\n", +	if (ret != -EISNAM) +		dev_err(&udc->dev, "failed to start %s: %d\n",  			udc->driver->function, ret);  	udc->driver = NULL;  	udc->dev.driver = NULL; @@ -427,6 +428,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)  	list_for_each_entry(udc, &udc_list, list)  		if (udc->driver == driver) {  			usb_gadget_remove_driver(udc); +			usb_gadget_set_state(udc->gadget, +					USB_STATE_NOTATTACHED);  			ret = 0;  			break;  		} diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c index 1f49fce0f0b..73a4dfba0ed 100644 --- a/drivers/usb/gadget/usbstring.c +++ b/drivers/usb/gadget/usbstring.c @@ -13,7 +13,6 @@  #include <linux/list.h>  #include <linux/string.h>  #include <linux/device.h> -#include <linux/init.h>  #include <linux/nls.h>  #include <linux/usb/ch9.h> diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c index 0bb5d50075d..1c29bc954db 100644 --- a/drivers/usb/gadget/uvc_queue.c +++ b/drivers/usb/gadget/uvc_queue.c @@ -20,6 +20,7 @@  #include <linux/vmalloc.h>  #include <linux/wait.h> +#include <media/v4l2-common.h>  #include <media/videobuf2-vmalloc.h>  #include "uvc.h" @@ -136,6 +137,8 @@ static int uvc_queue_init(struct uvc_video_queue *queue,  	queue->queue.buf_struct_size = sizeof(struct uvc_buffer);  	queue->queue.ops = &uvc_queue_qops;  	queue->queue.mem_ops = &vb2_vmalloc_memops; +	queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC +				     | V4L2_BUF_FLAG_TSTAMP_SRC_EOF;  	ret = vb2_queue_init(&queue->queue);  	if (ret)  		return ret; @@ -379,14 +382,9 @@ static struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,  	else  		nextbuf = NULL; -	/* -	 * FIXME: with videobuf2, the sequence number or timestamp fields -	 * are valid only for video capture devices and the UVC gadget usually -	 * is a video output device. Keeping these until the specs are clear on -	 * this aspect. -	 */ +	buf->buf.v4l2_buf.field = V4L2_FIELD_NONE;  	buf->buf.v4l2_buf.sequence = queue->sequence++; -	do_gettimeofday(&buf->buf.v4l2_buf.timestamp); +	v4l2_get_timestamp(&buf->buf.v4l2_buf.timestamp);  	vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);  	vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE); diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 0deb9d6cde2..134f354ede6 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -64,10 +64,10 @@ static bool loopdefault = 0;  module_param(loopdefault, bool, S_IRUGO|S_IWUSR);  static struct usb_zero_options gzero_options = { -	.isoc_interval = 4, -	.isoc_maxpacket = 1024, -	.bulk_buflen = 4096, -	.qlen = 32, +	.isoc_interval = GZERO_ISOC_INTERVAL, +	.isoc_maxpacket = GZERO_ISOC_MAXPACKET, +	.bulk_buflen = GZERO_BULK_BUFLEN, +	.qlen = GZERO_QLEN,  };  /*-------------------------------------------------------------------------*/ @@ -91,10 +91,22 @@ static struct usb_zero_options gzero_options = {   * functional coverage for the "USBCV" test harness from USB-IF.   * It's always set if OTG mode is enabled.   */ -unsigned autoresume = DEFAULT_AUTORESUME; +static unsigned autoresume = DEFAULT_AUTORESUME;  module_param(autoresume, uint, S_IRUGO);  MODULE_PARM_DESC(autoresume, "zero, or seconds before remote wakeup"); +/* Maximum Autoresume time */ +static unsigned max_autoresume; +module_param(max_autoresume, uint, S_IRUGO); +MODULE_PARM_DESC(max_autoresume, "maximum seconds before remote wakeup"); + +/* Interval between two remote wakeups */ +static unsigned autoresume_interval_ms; +module_param(autoresume_interval_ms, uint, S_IRUGO); +MODULE_PARM_DESC(autoresume_interval_ms, +		"milliseconds to increase successive wakeup delays"); + +static unsigned autoresume_step_ms;  /*-------------------------------------------------------------------------*/  static struct usb_device_descriptor device_desc = { @@ -183,8 +195,16 @@ static void zero_suspend(struct usb_composite_dev *cdev)  		return;  	if (autoresume) { -		mod_timer(&autoresume_timer, jiffies + (HZ * autoresume)); -		DBG(cdev, "suspend, wakeup in %d seconds\n", autoresume); +		if (max_autoresume && +			(autoresume_step_ms > max_autoresume * 1000)) +				autoresume_step_ms = autoresume * 1000; + +		mod_timer(&autoresume_timer, jiffies + +			msecs_to_jiffies(autoresume_step_ms)); +		DBG(cdev, "suspend, wakeup in %d milliseconds\n", +			autoresume_step_ms); + +		autoresume_step_ms += autoresume_interval_ms;  	} else  		DBG(cdev, "%s\n", __func__);  } @@ -280,7 +300,7 @@ static int __init zero_bind(struct usb_composite_dev *cdev)  	ss_opts->isoc_interval = gzero_options.isoc_interval;  	ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket;  	ss_opts->isoc_mult = gzero_options.isoc_mult; -	ss_opts->isoc_maxburst = gzero_options.isoc_maxpacket; +	ss_opts->isoc_maxburst = gzero_options.isoc_maxburst;  	ss_opts->bulk_buflen = gzero_options.bulk_buflen;  	func_ss = usb_get_function(func_inst_ss); @@ -316,6 +336,7 @@ static int __init zero_bind(struct usb_composite_dev *cdev)  	if (autoresume) {  		sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;  		loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; +		autoresume_step_ms = autoresume * 1000;  	}  	/* support OTG systems */ diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index b3f20d7f15d..03314f861be 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -29,6 +29,14 @@ if USB_XHCI_HCD  config USB_XHCI_PLATFORM  	tristate +config USB_XHCI_MVEBU +	tristate "xHCI support for Marvell Armada 375/38x" +	select USB_XHCI_PLATFORM +	depends on ARCH_MVEBU || COMPILE_TEST +	---help--- +	  Say 'Y' to enable the support for the xHCI host controller +	  found in Marvell Armada 375/38x ARM SOCs. +  endif # USB_XHCI_HCD  config USB_EHCI_HCD @@ -54,7 +62,7 @@ config USB_EHCI_HCD  config USB_EHCI_ROOT_HUB_TT  	bool "Root Hub Transaction Translators" -	depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST +	depends on USB_EHCI_HCD  	---help---  	  Some EHCI chips have vendor-specific extensions to integrate  	  transaction translators, so that no OHCI or UHCI companion @@ -66,7 +74,7 @@ config USB_EHCI_ROOT_HUB_TT  config USB_EHCI_TT_NEWSCHED  	bool "Improved Transaction Translator scheduling" -	depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST +	depends on USB_EHCI_HCD  	default y  	---help---  	  This changes the periodic scheduling code to fill more of the low @@ -168,9 +176,8 @@ config USB_EHCI_HCD_AT91  config USB_EHCI_MSM  	tristate "Support for Qualcomm QSD/MSM on-chip EHCI USB controller" -	depends on ARCH_MSM +	depends on ARCH_MSM || ARCH_QCOM  	select USB_EHCI_ROOT_HUB_TT -	select USB_MSM_OTG  	---help---  	  Enables support for the USB Host controller present on the  	  Qualcomm chipsets. Root Hub has inbuilt TT. @@ -203,12 +210,11 @@ config USB_EHCI_SH  	  Enables support for the on-chip EHCI controller on the SuperH.  	  If you use the PCI EHCI controller, this option is not necessary. -config USB_EHCI_S5P +config USB_EHCI_EXYNOS         tristate "EHCI support for Samsung S5P/EXYNOS SoC Series"         depends on PLAT_S5P || ARCH_EXYNOS         help -	Enable support for the Samsung S5Pxxxx and Exynos3/4/5 SOC's -	on-chip EHCI controller. +	Enable support for the Samsung Exynos SOC's on-chip EHCI controller.  config USB_EHCI_MV  	bool "EHCI support for Marvell PXA/MMP USB controller" @@ -224,7 +230,7 @@ config USB_EHCI_MV  	  on-chip EHCI USB controller" for those.  config USB_W90X900_EHCI -	bool "W90X900(W90P910) EHCI support" +	tristate "W90X900(W90P910) EHCI support"  	depends on ARCH_W90X900  	---help---  		Enables support for the W90X900 USB controller @@ -315,7 +321,6 @@ config USB_ISP1760_HCD  config USB_ISP1362_HCD  	tristate "ISP1362 HCD support" -	default N  	---help---  	  Supports the Philips ISP1362 chip as a host controller @@ -327,7 +332,6 @@ config USB_ISP1362_HCD  config USB_FUSBH200_HCD  	tristate "FUSBH200 HCD support"  	depends on USB -	default N  	---help---  	Faraday FUSBH200 is designed to meet USB2.0 EHCI specification  	with minor modification. @@ -338,7 +342,6 @@ config USB_FUSBH200_HCD  config USB_FOTG210_HCD  	tristate "FOTG210 HCD support"  	depends on USB -	default N  	---help---  	  Faraday FOTG210 is an OTG controller which can be configured as  	  an USB2.0 host. It is designed to meet USB2.0 EHCI specification @@ -347,10 +350,19 @@ config USB_FOTG210_HCD  	  To compile this driver as a module, choose M here: the  	  module will be called fotg210-hcd. +config USB_MAX3421_HCD +	tristate "MAX3421 HCD (USB-over-SPI) support" +	depends on USB && SPI +	---help--- +	  The Maxim MAX3421E chip supports standard USB 2.0-compliant +	  full-speed devices either in host or peripheral mode.  This +	  driver supports the host-mode of the MAX3421E only. + +	  To compile this driver as a module, choose M here: the module will +	  be called max3421-hcd. +  config USB_OHCI_HCD  	tristate "OHCI HCD (USB 1.1) support" -	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 -	depends on USB_ISP1301 || !ARCH_LPC32XX  	---help---  	  The Open Host Controller Interface (OHCI) is a standard for accessing  	  USB 1.1 host controller hardware.  It does more in hardware than Intel's @@ -367,20 +379,72 @@ config USB_OHCI_HCD  if USB_OHCI_HCD  config USB_OHCI_HCD_OMAP1 -	bool "OHCI support for OMAP1/2 chips" +	tristate "OHCI support for OMAP1/2 chips"  	depends on ARCH_OMAP1 +	depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3)  	default y  	---help---  	  Enables support for the OHCI controller on OMAP1/2 chips. +config USB_OHCI_HCD_SPEAR +        tristate "Support for ST SPEAr on-chip OHCI USB controller" +        depends on USB_OHCI_HCD && PLAT_SPEAR +        default y +        ---help--- +          Enables support for the on-chip OHCI controller on +          ST SPEAr chips. + +config USB_OHCI_HCD_S3C2410 +        tristate "OHCI support for Samsung S3C24xx/S3C64xx SoC series" +        depends on USB_OHCI_HCD && (ARCH_S3C24XX || ARCH_S3C64XX) +        default y +        ---help--- +          Enables support for the on-chip OHCI controller on +          S3C24xx/S3C64xx chips. + +config USB_OHCI_HCD_LPC32XX +	tristate "Support for LPC on-chip OHCI USB controller" +	depends on USB_OHCI_HCD && ARCH_LPC32XX +	depends on USB_ISP1301 +	default y +	---help--- +          Enables support for the on-chip OHCI controller on +          NXP chips. + +config USB_OHCI_HCD_PXA27X +	tristate "Support for PXA27X/PXA3XX on-chip OHCI USB controller" +	depends on USB_OHCI_HCD && (PXA27x || PXA3xx) +	default y +	---help--- +	  Enables support for the on-chip OHCI controller on +	  PXA27x/PXA3xx chips. + +config USB_OHCI_HCD_AT91 +        tristate "Support for Atmel on-chip OHCI USB controller" +        depends on USB_OHCI_HCD && ARCH_AT91 +        default y +        ---help--- +          Enables support for the on-chip OHCI controller on +          Atmel chips. +  config USB_OHCI_HCD_OMAP3 -	bool "OHCI support for OMAP3 and later chips" +	tristate "OHCI support for OMAP3 and later chips"  	depends on (ARCH_OMAP3 || ARCH_OMAP4)  	default y  	---help---  	  Enables support for the on-chip OHCI controller on  	  OMAP3 and later chips. +config USB_OHCI_HCD_DAVINCI +	bool "OHCI support for TI DaVinci DA8xx" +	depends on ARCH_DAVINCI_DA8XX +	depends on USB_OHCI_HCD=y +	default y +	help +	  Enables support for the DaVinci DA8xx integrated OHCI +	  controller. This driver cannot currently be a loadable +	  module because it lacks a proper PHY abstraction. +  config USB_OHCI_ATH79  	bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs (DEPRECATED)"  	depends on (SOC_AR71XX || SOC_AR724X) @@ -454,8 +518,8 @@ config USB_OHCI_SH  	  If you use the PCI OHCI controller, this option is not necessary.  config USB_OHCI_EXYNOS -	boolean "OHCI support for Samsung EXYNOS SoC Series" -	depends on ARCH_EXYNOS +	tristate "OHCI support for Samsung S5P/EXYNOS SoC Series" +	depends on PLAT_S5P || ARCH_EXYNOS  	help  	 Enable support for the Samsung Exynos SOC's on-chip OHCI controller. @@ -545,7 +609,6 @@ config FHCI_DEBUG  config USB_U132_HCD  	tristate "Elan U132 Adapter Host Controller"  	depends on USB_FTDI_ELAN -	default M  	help  	  The U132 adapter is a USB to CardBus adapter specifically designed  	  for PC cards that contain an OHCI host controller. Typical PC cards diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 50b0041c09a..af89a903d97 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -2,8 +2,6 @@  # Makefile for USB Host Controller Drivers  # -ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG -  # tell define_trace.h where to find the xhci trace header  CFLAGS_xhci-trace.o := -I$(src) @@ -21,6 +19,9 @@ xhci-hcd-$(CONFIG_PCI)	+= xhci-pci.o  ifneq ($(CONFIG_USB_XHCI_PLATFORM), )  	xhci-hcd-y		+= xhci-plat.o +ifneq ($(CONFIG_USB_XHCI_MVEBU), ) +	xhci-hcd-y		+= xhci-mvebu.o +endif  endif  obj-$(CONFIG_USB_WHCI_HCD)	+= whci/ @@ -34,10 +35,11 @@ obj-$(CONFIG_USB_EHCI_MXC)	+= ehci-mxc.o  obj-$(CONFIG_USB_EHCI_HCD_OMAP)	+= ehci-omap.o  obj-$(CONFIG_USB_EHCI_HCD_ORION)	+= ehci-orion.o  obj-$(CONFIG_USB_EHCI_HCD_SPEAR)	+= ehci-spear.o -obj-$(CONFIG_USB_EHCI_S5P)	+= ehci-s5p.o +obj-$(CONFIG_USB_EHCI_EXYNOS)	+= ehci-exynos.o  obj-$(CONFIG_USB_EHCI_HCD_AT91) += ehci-atmel.o  obj-$(CONFIG_USB_EHCI_MSM)	+= ehci-msm.o  obj-$(CONFIG_USB_EHCI_TEGRA)	+= ehci-tegra.o +obj-$(CONFIG_USB_W90X900_EHCI)	+= ehci-w90x900.o  obj-$(CONFIG_USB_OXU210HP_HCD)	+= oxu210hp-hcd.o  obj-$(CONFIG_USB_ISP116X_HCD)	+= isp116x-hcd.o @@ -46,6 +48,14 @@ obj-$(CONFIG_USB_ISP1362_HCD)	+= isp1362-hcd.o  obj-$(CONFIG_USB_OHCI_HCD)	+= ohci-hcd.o  obj-$(CONFIG_USB_OHCI_HCD_PCI)	+= ohci-pci.o  obj-$(CONFIG_USB_OHCI_HCD_PLATFORM)	+= ohci-platform.o +obj-$(CONFIG_USB_OHCI_EXYNOS)	+= ohci-exynos.o +obj-$(CONFIG_USB_OHCI_HCD_OMAP1)	+= ohci-omap.o +obj-$(CONFIG_USB_OHCI_HCD_OMAP3)	+= ohci-omap3.o +obj-$(CONFIG_USB_OHCI_HCD_SPEAR)	+= ohci-spear.o +obj-$(CONFIG_USB_OHCI_HCD_AT91)	+= ohci-at91.o +obj-$(CONFIG_USB_OHCI_HCD_S3C2410)	+= ohci-s3c2410.o +obj-$(CONFIG_USB_OHCI_HCD_LPC32XX)	+= ohci-nxp.o +obj-$(CONFIG_USB_OHCI_HCD_PXA27X)	+= ohci-pxa27x.o  obj-$(CONFIG_USB_UHCI_HCD)	+= uhci-hcd.o  obj-$(CONFIG_USB_FHCI_HCD)	+= fhci.o @@ -63,3 +73,4 @@ obj-$(CONFIG_USB_HCD_BCMA)	+= bcma-hcd.o  obj-$(CONFIG_USB_HCD_SSB)	+= ssb-hcd.o  obj-$(CONFIG_USB_FUSBH200_HCD)	+= fusbh200-hcd.o  obj-$(CONFIG_USB_FOTG210_HCD)	+= fotg210-hcd.o +obj-$(CONFIG_USB_MAX3421_HCD)	+= max3421-hcd.o diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index df13d425e9c..205f4a33658 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -227,8 +227,7 @@ static int bcma_hcd_probe(struct bcma_device *dev)  	/* TODO: Probably need checks here; is the core connected? */ -	if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || -	    dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) +	if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32)))  		return -EOPNOTSUPP;  	usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL); diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c index 3b645ff46f7..ec9f7b75d49 100644 --- a/drivers/usb/host/ehci-atmel.c +++ b/drivers/usb/host/ehci-atmel.c @@ -30,13 +30,17 @@ static const char hcd_name[] = "ehci-atmel";  static struct hc_driver __read_mostly ehci_atmel_hc_driver;  /* interface and function clocks */ -static struct clk *iclk, *fclk; +static struct clk *iclk, *fclk, *uclk;  static int clocked;  /*-------------------------------------------------------------------------*/  static void atmel_start_clock(void)  { +	if (IS_ENABLED(CONFIG_COMMON_CLK)) { +		clk_set_rate(uclk, 48000000); +		clk_prepare_enable(uclk); +	}  	clk_prepare_enable(iclk);  	clk_prepare_enable(fclk);  	clocked = 1; @@ -46,6 +50,8 @@ static void atmel_stop_clock(void)  {  	clk_disable_unprepare(fclk);  	clk_disable_unprepare(iclk); +	if (IS_ENABLED(CONFIG_COMMON_CLK)) +		clk_disable_unprepare(uclk);  	clocked = 0;  } @@ -90,10 +96,9 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)  	 * 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 = &pdev->dev.coherent_dma_mask; -	if (!pdev->dev.coherent_dma_mask) -		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (retval) +		goto fail_create_hcd;  	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));  	if (!hcd) { @@ -130,6 +135,14 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)  		retval = -ENOENT;  		goto fail_request_resource;  	} +	if (IS_ENABLED(CONFIG_COMMON_CLK)) { +		uclk = devm_clk_get(&pdev->dev, "usb_clk"); +		if (IS_ERR(uclk)) { +			dev_err(&pdev->dev, "failed to get uclk\n"); +			retval = PTR_ERR(uclk); +			goto fail_request_resource; +		} +	}  	ehci = hcd_to_ehci(hcd);  	/* registers start at offset 0x0 */ @@ -140,6 +153,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)  	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (retval)  		goto fail_add_hcd; +	device_wakeup_enable(hcd->self.controller);  	return retval; diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index aa5b603f393..524cbf26d99 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -18,7 +18,7 @@  /* this file is part of ehci-hcd.c */ -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#ifdef CONFIG_DYNAMIC_DEBUG  /* check the values in the HCSPARAMS register   * (host controller _Structural_ parameters) @@ -62,7 +62,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}  #endif -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#ifdef CONFIG_DYNAMIC_DEBUG  /* check the values in the HCCPARAMS register   * (host controller _Capability_ parameters) @@ -101,7 +101,7 @@ static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}  #endif -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#ifdef CONFIG_DYNAMIC_DEBUG  static void __maybe_unused  dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd) @@ -301,7 +301,7 @@ static inline int __maybe_unused  dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)  { return 0; } -#endif	/* DEBUG || CONFIG_DYNAMIC_DEBUG */ +#endif	/* CONFIG_DYNAMIC_DEBUG */  /* functions have the "wrong" filename when they're output... */  #define dbg_status(ehci, label, status) { \ @@ -334,6 +334,7 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }  /* troubleshooting help: expose state in debugfs */  static int debug_async_open(struct inode *, struct file *); +static int debug_bandwidth_open(struct inode *, struct file *);  static int debug_periodic_open(struct inode *, struct file *);  static int debug_registers_open(struct inode *, struct file *); @@ -347,6 +348,13 @@ static const struct file_operations debug_async_fops = {  	.release	= debug_close,  	.llseek		= default_llseek,  }; +static const struct file_operations debug_bandwidth_fops = { +	.owner		= THIS_MODULE, +	.open		= debug_bandwidth_open, +	.read		= debug_output, +	.release	= debug_close, +	.llseek		= default_llseek, +};  static const struct file_operations debug_periodic_fops = {  	.owner		= THIS_MODULE,  	.open		= debug_periodic_open, @@ -379,7 +387,7 @@ struct debug_buffer {  		case QH_LOW_SPEED:  tmp = 'l'; break; \  		case QH_HIGH_SPEED: tmp = 'h'; break; \  		default: tmp = '?'; break; \ -		}; tmp; }) +		} tmp; })  static inline char token_mark(struct ehci_hcd *ehci, __hc32 token)  { @@ -525,6 +533,89 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)  	return strlen(buf->output_buf);  } +static ssize_t fill_bandwidth_buffer(struct debug_buffer *buf) +{ +	struct ehci_hcd		*ehci; +	struct ehci_tt		*tt; +	struct ehci_per_sched	*ps; +	unsigned		temp, size; +	char			*next; +	unsigned		i; +	u8			*bw; +	u16			*bf; +	u8			budget[EHCI_BANDWIDTH_SIZE]; + +	ehci = hcd_to_ehci(bus_to_hcd(buf->bus)); +	next = buf->output_buf; +	size = buf->alloc_size; + +	*next = 0; + +	spin_lock_irq(&ehci->lock); + +	/* Dump the HS bandwidth table */ +	temp = scnprintf(next, size, +			"HS bandwidth allocation (us per microframe)\n"); +	size -= temp; +	next += temp; +	for (i = 0; i < EHCI_BANDWIDTH_SIZE; i += 8) { +		bw = &ehci->bandwidth[i]; +		temp = scnprintf(next, size, +				"%2u: %4u%4u%4u%4u%4u%4u%4u%4u\n", +				i, bw[0], bw[1], bw[2], bw[3], +					bw[4], bw[5], bw[6], bw[7]); +		size -= temp; +		next += temp; +	} + +	/* Dump all the FS/LS tables */ +	list_for_each_entry(tt, &ehci->tt_list, tt_list) { +		temp = scnprintf(next, size, +				"\nTT %s port %d  FS/LS bandwidth allocation (us per frame)\n", +				dev_name(&tt->usb_tt->hub->dev), +				tt->tt_port + !!tt->usb_tt->multi); +		size -= temp; +		next += temp; + +		bf = tt->bandwidth; +		temp = scnprintf(next, size, +				"  %5u%5u%5u%5u%5u%5u%5u%5u\n", +				bf[0], bf[1], bf[2], bf[3], +					bf[4], bf[5], bf[6], bf[7]); +		size -= temp; +		next += temp; + +		temp = scnprintf(next, size, +				"FS/LS budget (us per microframe)\n"); +		size -= temp; +		next += temp; +		compute_tt_budget(budget, tt); +		for (i = 0; i < EHCI_BANDWIDTH_SIZE; i += 8) { +			bw = &budget[i]; +			temp = scnprintf(next, size, +					"%2u: %4u%4u%4u%4u%4u%4u%4u%4u\n", +					i, bw[0], bw[1], bw[2], bw[3], +						bw[4], bw[5], bw[6], bw[7]); +			size -= temp; +			next += temp; +		} +		list_for_each_entry(ps, &tt->ps_list, ps_list) { +			temp = scnprintf(next, size, +					"%s ep %02x:  %4u @ %2u.%u+%u mask %04x\n", +					dev_name(&ps->udev->dev), +					ps->ep->desc.bEndpointAddress, +					ps->tt_usecs, +					ps->bw_phase, ps->phase_uf, +					ps->bw_period, ps->cs_mask); +			size -= temp; +			next += temp; +		} +	} +	spin_unlock_irq(&ehci->lock); + +	return next - buf->output_buf; +} +  #define DBG_SCHED_LIMIT 64  static ssize_t fill_periodic_buffer(struct debug_buffer *buf)  { @@ -571,7 +662,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)  			case Q_TYPE_QH:  				hw = p.qh->hw;  				temp = scnprintf (next, size, " qh%d-%04x/%p", -						p.qh->period, +						p.qh->ps.period,  						hc32_to_cpup(ehci,  							&hw->hw_info2)  							/* uframe masks */ @@ -618,7 +709,8 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)  						speed_char (scratch),  						scratch & 0x007f,  						(scratch >> 8) & 0x000f, type, -						p.qh->usecs, p.qh->c_usecs, +						p.qh->ps.usecs, +						p.qh->ps.c_usecs,  						temp,  						0x7ff & (scratch >> 16)); @@ -645,7 +737,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)  			case Q_TYPE_SITD:  				temp = scnprintf (next, size,  					" sitd%d-%04x/%p", -					p.sitd->stream->interval, +					p.sitd->stream->ps.period,  					hc32_to_cpup(ehci, &p.sitd->hw_uframe)  						& 0x0000ffff,  					p.sitd); @@ -726,7 +818,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)  #ifdef	CONFIG_PCI  	/* EHCI 0.96 and later may have "extended capabilities" */ -	if (hcd->self.controller->bus == &pci_bus_type) { +	if (dev_is_pci(hcd->self.controller)) {  		struct pci_dev	*pdev;  		u32		offset, cap, cap2;  		unsigned	count = 256/4; @@ -918,6 +1010,7 @@ static int debug_close(struct inode *inode, struct file *file)  	return 0;  } +  static int debug_async_open(struct inode *inode, struct file *file)  {  	file->private_data = alloc_buffer(inode->i_private, fill_async_buffer); @@ -925,6 +1018,14 @@ static int debug_async_open(struct inode *inode, struct file *file)  	return file->private_data ? 0 : -ENOMEM;  } +static int debug_bandwidth_open(struct inode *inode, struct file *file) +{ +	file->private_data = alloc_buffer(inode->i_private, +			fill_bandwidth_buffer); + +	return file->private_data ? 0 : -ENOMEM; +} +  static int debug_periodic_open(struct inode *inode, struct file *file)  {  	struct debug_buffer *buf; @@ -957,6 +1058,10 @@ static inline void create_debug_files (struct ehci_hcd *ehci)  						&debug_async_fops))  		goto file_error; +	if (!debugfs_create_file("bandwidth", S_IRUGO, ehci->debug_dir, bus, +						&debug_bandwidth_fops)) +		goto file_error; +  	if (!debugfs_create_file("periodic", S_IRUGO, ehci->debug_dir, bus,  						&debug_periodic_fops))  		goto file_error; diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c new file mode 100644 index 00000000000..d1c76216350 --- /dev/null +++ b/drivers/usb/host/ehci-exynos.c @@ -0,0 +1,390 @@ +/* + * SAMSUNG EXYNOS USB HOST EHCI Controller + * + * Copyright (C) 2011 Samsung Electronics Co.Ltd + * Author: Jingoo Han <jg1.han@samsung.com> + * Author: Joonyoung Shim <jy0922.shim@samsung.com> + * + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version. + * + */ + +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/usb/phy.h> +#include <linux/usb/samsung_usb_phy.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/usb/otg.h> + +#include "ehci.h" + +#define DRIVER_DESC "EHCI EXYNOS driver" + +#define EHCI_INSNREG00(base)			(base + 0x90) +#define EHCI_INSNREG00_ENA_INCR16		(0x1 << 25) +#define EHCI_INSNREG00_ENA_INCR8		(0x1 << 24) +#define EHCI_INSNREG00_ENA_INCR4		(0x1 << 23) +#define EHCI_INSNREG00_ENA_INCRX_ALIGN		(0x1 << 22) +#define EHCI_INSNREG00_ENABLE_DMA_BURST	\ +	(EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 |	\ +	 EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN) + +static const char hcd_name[] = "ehci-exynos"; +static struct hc_driver __read_mostly exynos_ehci_hc_driver; + +#define PHY_NUMBER 3 + +struct exynos_ehci_hcd { +	struct clk *clk; +	struct usb_phy *phy; +	struct usb_otg *otg; +	struct phy *phy_g[PHY_NUMBER]; +}; + +#define to_exynos_ehci(hcd) (struct exynos_ehci_hcd *)(hcd_to_ehci(hcd)->priv) + +static int exynos_ehci_get_phy(struct device *dev, +				struct exynos_ehci_hcd *exynos_ehci) +{ +	struct device_node *child; +	struct phy *phy; +	int phy_number; +	int ret = 0; + +	exynos_ehci->phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); +	if (IS_ERR(exynos_ehci->phy)) { +		ret = PTR_ERR(exynos_ehci->phy); +		if (ret != -ENXIO && ret != -ENODEV) { +			dev_err(dev, "no usb2 phy configured\n"); +			return ret; +		} +		dev_dbg(dev, "Failed to get usb2 phy\n"); +	} else { +		exynos_ehci->otg = exynos_ehci->phy->otg; +	} + +	for_each_available_child_of_node(dev->of_node, child) { +		ret = of_property_read_u32(child, "reg", &phy_number); +		if (ret) { +			dev_err(dev, "Failed to parse device tree\n"); +			of_node_put(child); +			return ret; +		} + +		if (phy_number >= PHY_NUMBER) { +			dev_err(dev, "Invalid number of PHYs\n"); +			of_node_put(child); +			return -EINVAL; +		} + +		phy = devm_of_phy_get(dev, child, 0); +		of_node_put(child); +		if (IS_ERR(phy)) { +			ret = PTR_ERR(phy); +			if (ret != -ENOSYS && ret != -ENODEV) { +				dev_err(dev, "no usb2 phy configured\n"); +				return ret; +			} +			dev_dbg(dev, "Failed to get usb2 phy\n"); +		} +		exynos_ehci->phy_g[phy_number] = phy; +	} + +	return ret; +} + +static int exynos_ehci_phy_enable(struct device *dev) +{ +	struct usb_hcd *hcd = dev_get_drvdata(dev); +	struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); +	int i; +	int ret = 0; + +	if (!IS_ERR(exynos_ehci->phy)) +		return usb_phy_init(exynos_ehci->phy); + +	for (i = 0; ret == 0 && i < PHY_NUMBER; i++) +		if (!IS_ERR(exynos_ehci->phy_g[i])) +			ret = phy_power_on(exynos_ehci->phy_g[i]); +	if (ret) +		for (i--; i >= 0; i--) +			if (!IS_ERR(exynos_ehci->phy_g[i])) +				phy_power_off(exynos_ehci->phy_g[i]); + +	return ret; +} + +static void exynos_ehci_phy_disable(struct device *dev) +{ +	struct usb_hcd *hcd = dev_get_drvdata(dev); +	struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); +	int i; + +	if (!IS_ERR(exynos_ehci->phy)) { +		usb_phy_shutdown(exynos_ehci->phy); +		return; +	} + +	for (i = 0; i < PHY_NUMBER; i++) +		if (!IS_ERR(exynos_ehci->phy_g[i])) +			phy_power_off(exynos_ehci->phy_g[i]); +} + +static void exynos_setup_vbus_gpio(struct device *dev) +{ +	int err; +	int gpio; + +	if (!dev->of_node) +		return; + +	gpio = of_get_named_gpio(dev->of_node, "samsung,vbus-gpio", 0); +	if (!gpio_is_valid(gpio)) +		return; + +	err = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH, +				    "ehci_vbus_gpio"); +	if (err) +		dev_err(dev, "can't request ehci vbus gpio %d", gpio); +} + +static int exynos_ehci_probe(struct platform_device *pdev) +{ +	struct exynos_ehci_hcd *exynos_ehci; +	struct usb_hcd *hcd; +	struct ehci_hcd *ehci; +	struct resource *res; +	int irq; +	int err; + +	/* +	 * 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 move to full device tree support this will vanish off. +	 */ +	err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (err) +		return err; + +	exynos_setup_vbus_gpio(&pdev->dev); + +	hcd = usb_create_hcd(&exynos_ehci_hc_driver, +			     &pdev->dev, dev_name(&pdev->dev)); +	if (!hcd) { +		dev_err(&pdev->dev, "Unable to create HCD\n"); +		return -ENOMEM; +	} +	exynos_ehci = to_exynos_ehci(hcd); + +	if (of_device_is_compatible(pdev->dev.of_node, +					"samsung,exynos5440-ehci")) +		goto skip_phy; + +	err = exynos_ehci_get_phy(&pdev->dev, exynos_ehci); +	if (err) +		goto fail_clk; + +skip_phy: + +	exynos_ehci->clk = devm_clk_get(&pdev->dev, "usbhost"); + +	if (IS_ERR(exynos_ehci->clk)) { +		dev_err(&pdev->dev, "Failed to get usbhost clock\n"); +		err = PTR_ERR(exynos_ehci->clk); +		goto fail_clk; +	} + +	err = clk_prepare_enable(exynos_ehci->clk); +	if (err) +		goto fail_clk; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!res) { +		dev_err(&pdev->dev, "Failed to get I/O memory\n"); +		err = -ENXIO; +		goto fail_io; +	} + +	hcd->rsrc_start = res->start; +	hcd->rsrc_len = resource_size(res); +	hcd->regs = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(hcd->regs)) { +		err = PTR_ERR(hcd->regs); +		goto fail_io; +	} + +	irq = platform_get_irq(pdev, 0); +	if (!irq) { +		dev_err(&pdev->dev, "Failed to get IRQ\n"); +		err = -ENODEV; +		goto fail_io; +	} + +	if (exynos_ehci->otg) +		exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); + +	err = exynos_ehci_phy_enable(&pdev->dev); +	if (err) { +		dev_err(&pdev->dev, "Failed to enable USB phy\n"); +		goto fail_io; +	} + +	ehci = hcd_to_ehci(hcd); +	ehci->caps = hcd->regs; + +	/* DMA burst Enable */ +	writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); + +	err = usb_add_hcd(hcd, irq, IRQF_SHARED); +	if (err) { +		dev_err(&pdev->dev, "Failed to add USB HCD\n"); +		goto fail_add_hcd; +	} +	device_wakeup_enable(hcd->self.controller); + +	platform_set_drvdata(pdev, hcd); + +	return 0; + +fail_add_hcd: +	exynos_ehci_phy_disable(&pdev->dev); +fail_io: +	clk_disable_unprepare(exynos_ehci->clk); +fail_clk: +	usb_put_hcd(hcd); +	return err; +} + +static int exynos_ehci_remove(struct platform_device *pdev) +{ +	struct usb_hcd *hcd = platform_get_drvdata(pdev); +	struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); + +	usb_remove_hcd(hcd); + +	if (exynos_ehci->otg) +		exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); + +	exynos_ehci_phy_disable(&pdev->dev); + +	clk_disable_unprepare(exynos_ehci->clk); + +	usb_put_hcd(hcd); + +	return 0; +} + +#ifdef CONFIG_PM +static int exynos_ehci_suspend(struct device *dev) +{ +	struct usb_hcd *hcd = dev_get_drvdata(dev); +	struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); + +	bool do_wakeup = device_may_wakeup(dev); +	int rc; + +	rc = ehci_suspend(hcd, do_wakeup); +	if (rc) +		return rc; + +	if (exynos_ehci->otg) +		exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); + +	exynos_ehci_phy_disable(dev); + +	clk_disable_unprepare(exynos_ehci->clk); + +	return rc; +} + +static int exynos_ehci_resume(struct device *dev) +{ +	struct usb_hcd *hcd = dev_get_drvdata(dev); +	struct exynos_ehci_hcd *exynos_ehci = to_exynos_ehci(hcd); +	int ret; + +	clk_prepare_enable(exynos_ehci->clk); + +	if (exynos_ehci->otg) +		exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); + +	ret = exynos_ehci_phy_enable(dev); +	if (ret) { +		dev_err(dev, "Failed to enable USB phy\n"); +		clk_disable_unprepare(exynos_ehci->clk); +		return ret; +	} + +	/* DMA burst Enable */ +	writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); + +	ehci_resume(hcd, false); +	return 0; +} +#else +#define exynos_ehci_suspend	NULL +#define exynos_ehci_resume	NULL +#endif + +static const struct dev_pm_ops exynos_ehci_pm_ops = { +	.suspend	= exynos_ehci_suspend, +	.resume		= exynos_ehci_resume, +}; + +#ifdef CONFIG_OF +static const struct of_device_id exynos_ehci_match[] = { +	{ .compatible = "samsung,exynos4210-ehci" }, +	{ .compatible = "samsung,exynos5440-ehci" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, exynos_ehci_match); +#endif + +static struct platform_driver exynos_ehci_driver = { +	.probe		= exynos_ehci_probe, +	.remove		= exynos_ehci_remove, +	.shutdown	= usb_hcd_platform_shutdown, +	.driver = { +		.name	= "exynos-ehci", +		.owner	= THIS_MODULE, +		.pm	= &exynos_ehci_pm_ops, +		.of_match_table = of_match_ptr(exynos_ehci_match), +	} +}; +static const struct ehci_driver_overrides exynos_overrides __initdata = { +	.extra_priv_size = sizeof(struct exynos_ehci_hcd), +}; + +static int __init ehci_exynos_init(void) +{ +	if (usb_disabled()) +		return -ENODEV; + +	pr_info("%s: " DRIVER_DESC "\n", hcd_name); +	ehci_init_driver(&exynos_ehci_hc_driver, &exynos_overrides); +	return platform_driver_register(&exynos_ehci_driver); +} +module_init(ehci_exynos_init); + +static void __exit ehci_exynos_cleanup(void) +{ +	platform_driver_unregister(&exynos_ehci_driver); +} +module_exit(ehci_exynos_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_ALIAS("platform:exynos-ehci"); +MODULE_AUTHOR("Jingoo Han"); +MODULE_AUTHOR("Joonyoung Shim"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 947b009009f..cf2734b532a 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -57,7 +57,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,  	pr_debug("initializing FSL-SOC USB Controller\n");  	/* Need platform data for setup */ -	pdata = (struct fsl_usb2_platform_data *)dev_get_platdata(&pdev->dev); +	pdata = dev_get_platdata(&pdev->dev);  	if (!pdata) {  		dev_err(&pdev->dev,  			"No platform data for %s.\n", dev_name(&pdev->dev)); @@ -102,19 +102,11 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,  	}  	hcd->rsrc_start = res->start;  	hcd->rsrc_len = resource_size(res); -	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, -				driver->description)) { -		dev_dbg(&pdev->dev, "controller already in use\n"); -		retval = -EBUSY; +	hcd->regs = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(hcd->regs)) { +		retval = PTR_ERR(hcd->regs);  		goto err2;  	} -	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); - -	if (hcd->regs == NULL) { -		dev_dbg(&pdev->dev, "error mapping memory\n"); -		retval = -EFAULT; -		goto err3; -	}  	pdata->regs = hcd->regs; @@ -126,18 +118,19 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,  	 */  	if (pdata->init && pdata->init(pdev)) {  		retval = -ENODEV; -		goto err4; +		goto err2;  	}  	/* Enable USB controller, 83xx or 8536 */ -	if (pdata->have_sysif_regs) +	if (pdata->have_sysif_regs && pdata->controller_ver < FSL_USB_VER_1_6)  		setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4);  	/* Don't need to set host mode here. It will be done by tdi_reset() */  	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (retval != 0) -		goto err4; +		goto err2; +	device_wakeup_enable(hcd->self.controller);  #ifdef CONFIG_USB_OTG  	if (pdata->operating_mode == FSL_USB2_DR_OTG) { @@ -152,21 +145,17 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,  					      &ehci_to_hcd(ehci)->self);  			if (retval) {  				usb_put_phy(hcd->phy); -				goto err4; +				goto err2;  			}  		} else {  			dev_err(&pdev->dev, "can't find phy\n");  			retval = -ENODEV; -			goto err4; +			goto err2;  		}  	}  #endif  	return retval; -      err4: -	iounmap(hcd->regs); -      err3: -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);        err2:  	usb_put_hcd(hcd);        err1: @@ -205,8 +194,6 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,  	 */  	if (pdata->exit)  		pdata->exit(pdev); -	iounmap(hcd->regs); -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	usb_put_hcd(hcd);  } @@ -232,15 +219,9 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,  	case FSL_USB2_PHY_ULPI:  		if (pdata->have_sysif_regs && pdata->controller_ver) {  			/* controller version 1.6 or above */ +			clrbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN);  			setbits32(non_ehci + FSL_SOC_USB_CTRL, -					ULPI_PHY_CLK_SEL); -			/* -			 * Due to controller issue of PHY_CLK_VALID in ULPI -			 * mode, we set USB_CTRL_USB_EN before checking -			 * PHY_CLK_VALID, otherwise PHY_CLK_VALID doesn't work. -			 */ -			clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL, -					UTMI_PHY_EN, USB_CTRL_USB_EN); +				ULPI_PHY_CLK_SEL | USB_CTRL_USB_EN);  		}  		portsc |= PORT_PTS_ULPI;  		break; @@ -267,12 +248,14 @@ static int ehci_fsl_setup_phy(struct usb_hcd *hcd,  		break;  	} -	if (pdata->have_sysif_regs && pdata->controller_ver && +	if (pdata->have_sysif_regs && +	    pdata->controller_ver > FSL_USB_VER_1_6 &&  	    (phy_mode == FSL_USB2_PHY_ULPI)) {  		/* check PHY_CLK_VALID to get phy clk valid */ -		if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & -				PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) { -			printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n"); +		if (!(spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) & +				PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0) || +				in_be32(non_ehci + FSL_SOC_USB_PRICTRL))) { +			dev_warn(hcd->self.controller, "USB PHY clock invalid\n");  			return -EINVAL;  		}  	} @@ -418,7 +401,7 @@ static int ehci_fsl_mpc512x_drv_suspend(struct device *dev)  	struct fsl_usb2_platform_data *pdata = dev_get_platdata(dev);  	u32 tmp; -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#ifdef CONFIG_DYNAMIC_DEBUG  	u32 mode = ehci_readl(ehci, hcd->regs + FSL_SOC_USB_USBMODE);  	mode &= USBMODE_CM_MASK;  	tmp = ehci_readl(ehci, hcd->regs + 0x140);	/* usbcmd */ diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c index b52a66ce92e..495b6fbcbcd 100644 --- a/drivers/usb/host/ehci-grlib.c +++ b/drivers/usb/host/ehci-grlib.c @@ -113,7 +113,8 @@ static int ehci_hcd_grlib_probe(struct platform_device *op)  	irq = irq_of_parse_and_map(dn, 0);  	if (irq == NO_IRQ) { -		printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); +		dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n", +			__FILE__);  		rv = -EBUSY;  		goto err_irq;  	} @@ -140,6 +141,7 @@ static int ehci_hcd_grlib_probe(struct platform_device *op)  	if (rv)  		goto err_ioremap; +	device_wakeup_enable(hcd->self.controller);  	return 0;  err_ioremap: diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 5d6022f30eb..81cda09b47e 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -71,7 +71,6 @@  static const char	hcd_name [] = "ehci_hcd"; -#undef VERBOSE_DEBUG  #undef EHCI_URB_TRACE  /* magic numbers that can affect system performance */ @@ -110,6 +109,9 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");  #include "ehci.h"  #include "pci-quirks.h" +static void compute_tt_budget(u8 budget_table[EHCI_BANDWIDTH_SIZE], +		struct ehci_tt *tt); +  /*   * The MosChip MCS9990 controller updates its microframe counter   * a little before the frame counter, and occasionally we will read @@ -484,6 +486,7 @@ static int ehci_init(struct usb_hcd *hcd)  	INIT_LIST_HEAD(&ehci->intr_qh_list);  	INIT_LIST_HEAD(&ehci->cached_itd_list);  	INIT_LIST_HEAD(&ehci->cached_sitd_list); +	INIT_LIST_HEAD(&ehci->tt_list);  	if (HCC_PGM_FRAMELISTLEN(hcc_params)) {  		/* periodic schedule size can be smaller than default */ @@ -682,8 +685,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)  	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);  	u32			status, masked_status, pcd_status = 0, cmd;  	int			bh; +	unsigned long		flags; -	spin_lock (&ehci->lock); +	/* +	 * For threadirqs option we use spin_lock_irqsave() variant to prevent +	 * deadlock with ehci hrtimer callback, because hrtimer callbacks run +	 * in interrupt context even when threadirqs is specified. We can go +	 * back to spin_lock() variant when hrtimer callbacks become threaded. +	 */ +	spin_lock_irqsave(&ehci->lock, flags);  	status = ehci_readl(ehci, &ehci->regs->status); @@ -701,7 +711,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)  	/* Shared IRQ? */  	if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) { -		spin_unlock(&ehci->lock); +		spin_unlock_irqrestore(&ehci->lock, flags);  		return IRQ_NONE;  	} @@ -710,13 +720,6 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)  	cmd = ehci_readl(ehci, &ehci->regs->command);  	bh = 0; -#ifdef	VERBOSE_DEBUG -	/* unrequested/ignored: Frame List Rollover */ -	dbg_status (ehci, "irq", status); -#endif - -	/* INT, ERR, and IAA interrupt rates can be throttled */ -  	/* normal [4.15.1.2] or error [4.15.1.1] completion */  	if (likely ((status & (STS_INT|STS_ERR)) != 0)) {  		if (likely ((status & STS_ERR) == 0)) @@ -819,7 +822,7 @@ dead:  	if (bh)  		ehci_work (ehci); -	spin_unlock (&ehci->lock); +	spin_unlock_irqrestore(&ehci->lock, flags);  	if (pcd_status)  		usb_hcd_poll_rh_status(hcd);  	return IRQ_HANDLED; @@ -956,6 +959,7 @@ rescan:  			goto idle_timeout;  		/* BUG_ON(!list_empty(&stream->free_list)); */ +		reserve_release_iso_bandwidth(ehci, stream, -1);  		kfree(stream);  		goto done;  	} @@ -982,6 +986,8 @@ idle_timeout:  		if (qh->clearing_tt)  			goto idle_timeout;  		if (list_empty (&qh->qtd_list)) { +			if (qh->ps.bw_uperiod) +				reserve_release_intr_bandwidth(ehci, qh, -1);  			qh_destroy(ehci, qh);  			break;  		} @@ -1022,7 +1028,6 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)  	 * the toggle bit in the QH.  	 */  	if (qh) { -		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 { @@ -1030,6 +1035,7 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)  			 * while the QH is active.  Unlink it now;  			 * re-linking will call qh_refresh().  			 */ +			usb_settoggle(qh->ps.udev, epnum, is_out, 0);  			qh->exception = 1;  			if (eptype == USB_ENDPOINT_XFER_BULK)  				start_unlink_async(ehci, qh); @@ -1048,6 +1054,19 @@ static int ehci_get_frame (struct usb_hcd *hcd)  /*-------------------------------------------------------------------------*/ +/* Device addition and removal */ + +static void ehci_remove_device(struct usb_hcd *hcd, struct usb_device *udev) +{ +	struct ehci_hcd		*ehci = hcd_to_ehci(hcd); + +	spin_lock_irq(&ehci->lock); +	drop_tt(udev); +	spin_unlock_irq(&ehci->lock); +} + +/*-------------------------------------------------------------------------*/ +  #ifdef	CONFIG_PM  /* suspend/resume, section 4.3 */ @@ -1075,6 +1094,14 @@ int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup)  	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);  	spin_unlock_irq(&ehci->lock); +	synchronize_irq(hcd->irq); + +	/* Check for race with a wakeup request */ +	if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) { +		ehci_resume(hcd, false); +		return -EBUSY; +	} +  	return 0;  }  EXPORT_SYMBOL_GPL(ehci_suspend); @@ -1191,6 +1218,11 @@ static const struct hc_driver ehci_hc_driver = {  	.bus_resume =		ehci_bus_resume,  	.relinquish_port =	ehci_relinquish_port,  	.port_handed_over =	ehci_port_handed_over, + +	/* +	 * device support +	 */ +	.free_dev =		ehci_remove_device,  };  void ehci_init_driver(struct hc_driver *drv, @@ -1238,11 +1270,6 @@ MODULE_LICENSE ("GPL");  #define XILINX_OF_PLATFORM_DRIVER	ehci_hcd_xilinx_of_driver  #endif -#ifdef CONFIG_USB_W90X900_EHCI -#include "ehci-w90x900.c" -#define	PLATFORM_DRIVER		ehci_hcd_w90x900_driver -#endif -  #ifdef CONFIG_USB_OCTEON_EHCI  #include "ehci-octeon.c"  #define PLATFORM_DRIVER		ehci_octeon_driver @@ -1292,7 +1319,7 @@ static int __init ehci_hcd_init(void)  		 sizeof(struct ehci_qh), sizeof(struct ehci_qtd),  		 sizeof(struct ehci_itd), sizeof(struct ehci_sitd)); -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#ifdef CONFIG_DYNAMIC_DEBUG  	ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root);  	if (!ehci_debug_root) {  		retval = -ENOENT; @@ -1341,7 +1368,7 @@ clean2:  	platform_driver_unregister(&PLATFORM_DRIVER);  clean0:  #endif -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#ifdef CONFIG_DYNAMIC_DEBUG  	debugfs_remove(ehci_debug_root);  	ehci_debug_root = NULL;  err_debug: @@ -1365,7 +1392,7 @@ static void __exit ehci_hcd_cleanup(void)  #ifdef PS3_SYSTEM_BUS_DRIVER  	ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);  #endif -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#ifdef CONFIG_DYNAMIC_DEBUG  	debugfs_remove(ehci_debug_root);  #endif  	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 835fc0844a6..cc305c71ac3 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -33,15 +33,6 @@  #ifdef	CONFIG_PM -static int ehci_hub_control( -	struct usb_hcd	*hcd, -	u16		typeReq, -	u16		wValue, -	u16		wIndex, -	char		*buf, -	u16		wLength -); -  static int persist_enabled_on_companion(struct usb_device *udev, void *unused)  {  	return !udev->maxchild && udev->persist_enabled && @@ -238,6 +229,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)  	int			port;  	int			mask;  	int			changed; +	bool			fs_idle_delay;  	ehci_dbg(ehci, "suspend root hub\n"); @@ -272,6 +264,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)  	ehci->bus_suspended = 0;  	ehci->owned_ports = 0;  	changed = 0; +	fs_idle_delay = false;  	port = HCS_N_PORTS(ehci->hcs_params);  	while (port--) {  		u32 __iomem	*reg = &ehci->regs->port_status [port]; @@ -300,16 +293,32 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)  		}  		if (t1 != t2) { +			/* +			 * On some controllers, Wake-On-Disconnect will +			 * generate false wakeup signals until the bus +			 * switches over to full-speed idle.  For their +			 * sake, add a delay if we need one. +			 */ +			if ((t2 & PORT_WKDISC_E) && +					ehci_port_speed(ehci, t2) == +						USB_PORT_STAT_HIGH_SPEED) +				fs_idle_delay = true;  			ehci_writel(ehci, t2, reg);  			changed = 1;  		}  	} +	spin_unlock_irq(&ehci->lock); + +	if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) { +		/* +		 * Wait for HCD to enter low-power mode or for the bus +		 * to switch to full-speed idle. +		 */ +		usleep_range(5000, 5500); +	}  	if (changed && ehci->has_tdi_phy_lpm) { -		spin_unlock_irq(&ehci->lock); -		msleep(5);	/* 5 ms for HCD to enter low-power mode */  		spin_lock_irq(&ehci->lock); -  		port = HCS_N_PORTS(ehci->hcs_params);  		while (port--) {  			u32 __iomem	*hostpc_reg = &ehci->regs->hostpc[port]; @@ -322,8 +331,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)  					port, (t3 & HOSTPC_PHCD) ?  					"succeeded" : "failed");  		} +		spin_unlock_irq(&ehci->lock);  	} -	spin_unlock_irq(&ehci->lock);  	/* Apparently some devices need a >= 1-uframe delay here */  	if (ehci->bus_suspended) @@ -847,7 +856,7 @@ cleanup:  #endif /* CONFIG_USB_HCD_TEST_MODE */  /*-------------------------------------------------------------------------*/ -static int ehci_hub_control ( +int ehci_hub_control(  	struct usb_hcd	*hcd,  	u16		typeReq,  	u16		wValue, @@ -1114,10 +1123,8 @@ static int ehci_hub_control (  		if (test_bit(wIndex, &ehci->port_c_suspend))  			status |= USB_PORT_STAT_C_SUSPEND << 16; -#ifndef	VERBOSE_DEBUG -	if (status & ~0xffff)	/* only if wPortChange is interesting */ -#endif -		dbg_port (ehci, "GetStatus", wIndex + 1, temp); +		if (status & ~0xffff)	/* only if wPortChange is interesting */ +			dbg_port(ehci, "GetStatus", wIndex + 1, temp);  		put_unaligned_le32(status, buf);  		break;  	case SetHubFeature: @@ -1269,6 +1276,7 @@ error_exit:  	spin_unlock_irqrestore (&ehci->lock, flags);  	return retval;  } +EXPORT_SYMBOL_GPL(ehci_hub_control);  static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)  { diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index 52a77734a22..c0fb6a8ae6a 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c @@ -224,11 +224,11 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)  		hw->hw_next = EHCI_LIST_END(ehci);  		hw->hw_qtd_next = EHCI_LIST_END(ehci);  		hw->hw_alt_next = EHCI_LIST_END(ehci); -		hw->hw_token &= ~QTD_STS_ACTIVE;  		ehci->dummy->hw = hw;  		for (i = 0; i < ehci->periodic_size; i++) -			ehci->periodic[i] = ehci->dummy->qh_dma; +			ehci->periodic[i] = cpu_to_hc32(ehci, +					ehci->dummy->qh_dma);  	} else {  		for (i = 0; i < ehci->periodic_size; i++)  			ehci->periodic[i] = EHCI_LIST_END(ehci); diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c index 0f717dc688b..982c09bebe0 100644 --- a/drivers/usb/host/ehci-msm.c +++ b/drivers/usb/host/ehci-msm.c @@ -42,7 +42,6 @@  static const char hcd_name[] = "ehci-msm";  static struct hc_driver __read_mostly msm_hc_driver; -static struct usb_phy *phy;  static int ehci_msm_reset(struct usb_hcd *hcd)  { @@ -70,6 +69,7 @@ static int ehci_msm_probe(struct platform_device *pdev)  {  	struct usb_hcd *hcd;  	struct resource *res; +	struct usb_phy *phy;  	int ret;  	dev_dbg(&pdev->dev, "ehci_msm proble\n"); @@ -96,10 +96,9 @@ static int ehci_msm_probe(struct platform_device *pdev)  	hcd->rsrc_start = res->start;  	hcd->rsrc_len = resource_size(res); -	hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len); -	if (!hcd->regs) { -		dev_err(&pdev->dev, "ioremap failed\n"); -		ret = -ENOMEM; +	hcd->regs = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(hcd->regs)) { +		ret = PTR_ERR(hcd->regs);  		goto put_hcd;  	} @@ -108,10 +107,14 @@ static int ehci_msm_probe(struct platform_device *pdev)  	 * powering up VBUS, mapping of registers address space and power  	 * management.  	 */ -	phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); +	if (pdev->dev.of_node) +		phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); +	else +		phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); +  	if (IS_ERR(phy)) {  		dev_err(&pdev->dev, "unable to find transceiver\n"); -		ret = -ENODEV; +		ret = -EPROBE_DEFER;  		goto put_hcd;  	} @@ -121,6 +124,7 @@ static int ehci_msm_probe(struct platform_device *pdev)  		goto put_hcd;  	} +	hcd->phy = phy;  	device_init_wakeup(&pdev->dev, 1);  	/*  	 * OTG device parent of HCD takes care of putting @@ -147,7 +151,7 @@ static int ehci_msm_remove(struct platform_device *pdev)  	pm_runtime_disable(&pdev->dev);  	pm_runtime_set_suspended(&pdev->dev); -	otg_set_host(phy->otg, NULL); +	otg_set_host(hcd->phy->otg, NULL);  	/* FIXME: need to call usb_remove_hcd() here? */ @@ -186,12 +190,19 @@ static const struct dev_pm_ops ehci_msm_dev_pm_ops = {  	.resume          = ehci_msm_pm_resume,  }; +static struct of_device_id msm_ehci_dt_match[] = { +	{ .compatible = "qcom,ehci-host", }, +	{} +}; +MODULE_DEVICE_TABLE(of, msm_ehci_dt_match); +  static struct platform_driver ehci_msm_driver = {  	.probe	= ehci_msm_probe,  	.remove	= ehci_msm_remove,  	.driver = {  		   .name = "msm_hsusb_host",  		   .pm = &ehci_msm_dev_pm_ops, +		   .of_match_table = msm_ehci_dt_match,  	},  }; diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c index 417c10da945..08147c35f83 100644 --- a/drivers/usb/host/ehci-mv.c +++ b/drivers/usb/host/ehci-mv.c @@ -176,11 +176,9 @@ static int mv_ehci_probe(struct platform_device *pdev)  		goto err_put_hcd;  	} -	ehci_mv->phy_regs = devm_ioremap(&pdev->dev, r->start, -					 resource_size(r)); -	if (ehci_mv->phy_regs == 0) { -		dev_err(&pdev->dev, "failed to map phy I/O memory\n"); -		retval = -EFAULT; +	ehci_mv->phy_regs = devm_ioremap_resource(&pdev->dev, r); +	if (IS_ERR(ehci_mv->phy_regs)) { +		retval = PTR_ERR(ehci_mv->phy_regs);  		goto err_put_hcd;  	} @@ -191,11 +189,9 @@ static int mv_ehci_probe(struct platform_device *pdev)  		goto err_put_hcd;  	} -	ehci_mv->cap_regs = devm_ioremap(&pdev->dev, r->start, -					 resource_size(r)); -	if (ehci_mv->cap_regs == NULL) { -		dev_err(&pdev->dev, "failed to map I/O memory\n"); -		retval = -EFAULT; +	ehci_mv->cap_regs = devm_ioremap_resource(&pdev->dev, r); +	if (IS_ERR(ehci_mv->cap_regs)) { +		retval = PTR_ERR(ehci_mv->cap_regs);  		goto err_put_hcd;  	} @@ -257,6 +253,7 @@ static int mv_ehci_probe(struct platform_device *pdev)  				"failed to add hcd with err %d\n", retval);  			goto err_set_vbus;  		} +		device_wakeup_enable(hcd->self.controller);  	}  	if (pdata->private_init) diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index 0528dc4526c..dbe5e4eea08 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c @@ -155,6 +155,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)  	if (ret)  		goto err_add; +	device_wakeup_enable(hcd->self.controller);  	return 0;  err_add: diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c index ab0397e4d8f..9051439039a 100644 --- a/drivers/usb/host/ehci-octeon.c +++ b/drivers/usb/host/ehci-octeon.c @@ -116,8 +116,10 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)  	 * We can DMA from anywhere. But the descriptors must be in  	 * the lower 4GB.  	 */ -	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);  	pdev->dev.dma_mask = &ehci_octeon_dma_mask; +	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); +	if (ret) +		return ret;  	hcd = usb_create_hcd(&ehci_octeon_hc_driver, &pdev->dev, "octeon");  	if (!hcd) @@ -126,20 +128,12 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)  	hcd->rsrc_start = res_mem->start;  	hcd->rsrc_len = resource_size(res_mem); -	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, -				OCTEON_EHCI_HCD_NAME)) { -		dev_err(&pdev->dev, "request_mem_region failed\n"); -		ret = -EBUSY; +	hcd->regs = devm_ioremap_resource(&pdev->dev, res_mem); +	if (IS_ERR(hcd->regs)) { +		ret = PTR_ERR(hcd->regs);  		goto err1;  	} -	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); -	if (!hcd->regs) { -		dev_err(&pdev->dev, "ioremap failed\n"); -		ret = -ENOMEM; -		goto err2; -	} -  	ehci_octeon_start();  	ehci = hcd_to_ehci(hcd); @@ -154,18 +148,16 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)  	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (ret) {  		dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); -		goto err3; +		goto err2;  	} +	device_wakeup_enable(hcd->self.controller);  	platform_set_drvdata(pdev, hcd);  	return 0; -err3: +err2:  	ehci_octeon_stop(); -	iounmap(hcd->regs); -err2: -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  err1:  	usb_put_hcd(hcd);  	return ret; @@ -178,8 +170,6 @@ static int ehci_octeon_drv_remove(struct platform_device *pdev)  	usb_remove_hcd(hcd);  	ehci_octeon_stop(); -	iounmap(hcd->regs); -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	usb_put_hcd(hcd);  	return 0; diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 78b01fa475b..a24720beb39 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -104,7 +104,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)  	struct resource	*res;  	struct usb_hcd	*hcd;  	void __iomem *regs; -	int ret = -ENODEV; +	int ret;  	int irq;  	int i;  	struct omap_hcd	*omap; @@ -144,11 +144,11 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)  	 * Since shared usb code relies on it, set it here for now.  	 * Once we have dma capability bindings this can go away.  	 */ -	if (!dev->dma_mask) -		dev->dma_mask = &dev->coherent_dma_mask; -	if (!dev->coherent_dma_mask) -		dev->coherent_dma_mask = DMA_BIT_MASK(32); +	ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); +	if (ret) +		return ret; +	ret = -ENODEV;  	hcd = usb_create_hcd(&ehci_omap_hc_driver, dev,  			dev_name(dev));  	if (!hcd) { @@ -215,6 +215,7 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)  		dev_err(dev, "failed to add hcd with err %d\n", ret);  		goto err_pm_runtime;  	} +	device_wakeup_enable(hcd->self.controller);  	/*  	 * Bring PHYs out of reset for non PHY modes. diff --git a/drivers/usb/host/ehci-orion.c b/drivers/usb/host/ehci-orion.c index d1dfb9db5b4..22e15cab8ea 100644 --- a/drivers/usb/host/ehci-orion.c +++ b/drivers/usb/host/ehci-orion.c @@ -15,6 +15,7 @@  #include <linux/clk.h>  #include <linux/platform_data/usb-ehci-orion.h>  #include <linux/of.h> +#include <linux/phy/phy.h>  #include <linux/of_device.h>  #include <linux/of_irq.h>  #include <linux/usb.h> @@ -42,6 +43,13 @@  #define DRIVER_DESC "EHCI orion driver" +#define hcd_to_orion_priv(h) ((struct orion_ehci_hcd *)hcd_to_ehci(h)->priv) + +struct orion_ehci_hcd { +	struct clk *clk; +	struct phy *phy; +}; +  static const char hcd_name[] = "ehci-orion";  static struct hc_driver __read_mostly ehci_orion_hc_driver; @@ -137,6 +145,10 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd,  	}  } +static const struct ehci_driver_overrides orion_overrides __initconst = { +	.extra_priv_size =	sizeof(struct orion_ehci_hcd), +}; +  static int ehci_orion_drv_probe(struct platform_device *pdev)  {  	struct orion_ehci_data *pd = dev_get_platdata(&pdev->dev); @@ -144,26 +156,23 @@ static int ehci_orion_drv_probe(struct platform_device *pdev)  	struct resource *res;  	struct usb_hcd *hcd;  	struct ehci_hcd *ehci; -	struct clk *clk;  	void __iomem *regs;  	int irq, err;  	enum orion_ehci_phy_ver phy_version; +	struct orion_ehci_hcd *priv;  	if (usb_disabled())  		return -ENODEV;  	pr_debug("Initializing Orion-SoC USB Host Controller\n"); -	if (pdev->dev.of_node) -		irq = irq_of_parse_and_map(pdev->dev.of_node, 0); -	else -		irq = platform_get_irq(pdev, 0); +	irq = platform_get_irq(pdev, 0);  	if (irq <= 0) {  		dev_err(&pdev->dev,  			"Found HC with no IRQ. Check %s setup!\n",  			dev_name(&pdev->dev));  		err = -ENODEV; -		goto err1; +		goto err;  	}  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -172,7 +181,7 @@ static int ehci_orion_drv_probe(struct platform_device *pdev)  			"Found HC with no register addr. Check %s setup!\n",  			dev_name(&pdev->dev));  		err = -ENODEV; -		goto err1; +		goto err;  	}  	/* @@ -180,38 +189,21 @@ static int ehci_orion_drv_probe(struct platform_device *pdev)  	 * 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 = &pdev->dev.coherent_dma_mask; -	if (!pdev->dev.coherent_dma_mask) -		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - -	if (!request_mem_region(res->start, resource_size(res), -				ehci_orion_hc_driver.description)) { -		dev_dbg(&pdev->dev, "controller already in use\n"); -		err = -EBUSY; -		goto err1; -	} - -	regs = ioremap(res->start, resource_size(res)); -	if (regs == NULL) { -		dev_dbg(&pdev->dev, "error mapping memory\n"); -		err = -EFAULT; -		goto err2; -	} +	err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (err) +		goto err; -	/* Not all platforms can gate the clock, so it is not -	   an error if the clock does not exists. */ -	clk = clk_get(&pdev->dev, NULL); -	if (!IS_ERR(clk)) { -		clk_prepare_enable(clk); -		clk_put(clk); +	regs = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(regs)) { +		err = PTR_ERR(regs); +		goto err;  	}  	hcd = usb_create_hcd(&ehci_orion_hc_driver,  			&pdev->dev, dev_name(&pdev->dev));  	if (!hcd) {  		err = -ENOMEM; -		goto err3; +		goto err;  	}  	hcd->rsrc_start = res->start; @@ -222,6 +214,29 @@ static int ehci_orion_drv_probe(struct platform_device *pdev)  	ehci->caps = hcd->regs + 0x100;  	hcd->has_tt = 1; +	priv = hcd_to_orion_priv(hcd); +	/* +	 * Not all platforms can gate the clock, so it is not an error if +	 * the clock does not exists. +	 */ +	priv->clk = devm_clk_get(&pdev->dev, NULL); +	if (!IS_ERR(priv->clk)) +		clk_prepare_enable(priv->clk); + +	priv->phy = devm_phy_optional_get(&pdev->dev, "usb"); +	if (IS_ERR(priv->phy)) { +		err = PTR_ERR(priv->phy); +		goto err_phy_get; +	} else { +		err = phy_init(priv->phy); +		if (err) +			goto err_phy_init; + +		err = phy_power_on(priv->phy); +		if (err) +			goto err_phy_power_on; +	} +  	/*  	 * (Re-)program MBUS remapping windows if we are asked to.  	 */ @@ -246,26 +261,28 @@ static int ehci_orion_drv_probe(struct platform_device *pdev)  	case EHCI_PHY_DD:  	case EHCI_PHY_KW:  	default: -		printk(KERN_WARNING "Orion ehci -USB phy version isn't supported.\n"); +		dev_warn(&pdev->dev, "USB phy version isn't supported.\n");  	}  	err = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (err) -		goto err4; +		goto err_add_hcd; +	device_wakeup_enable(hcd->self.controller);  	return 0; -err4: +err_add_hcd: +	if (!IS_ERR(priv->phy)) +		phy_power_off(priv->phy); +err_phy_power_on: +	if (!IS_ERR(priv->phy)) +		phy_exit(priv->phy); +err_phy_init: +err_phy_get: +	if (!IS_ERR(priv->clk)) +		clk_disable_unprepare(priv->clk);  	usb_put_hcd(hcd); -err3: -	if (!IS_ERR(clk)) { -		clk_disable_unprepare(clk); -		clk_put(clk); -	} -	iounmap(regs); -err2: -	release_mem_region(res->start, resource_size(res)); -err1: +err:  	dev_err(&pdev->dev, "init %s fail, %d\n",  		dev_name(&pdev->dev), err); @@ -275,18 +292,20 @@ err1:  static int ehci_orion_drv_remove(struct platform_device *pdev)  {  	struct usb_hcd *hcd = platform_get_drvdata(pdev); -	struct clk *clk; +	struct orion_ehci_hcd *priv = hcd_to_orion_priv(hcd);  	usb_remove_hcd(hcd); -	iounmap(hcd->regs); -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -	usb_put_hcd(hcd); -	clk = clk_get(&pdev->dev, NULL); -	if (!IS_ERR(clk)) { -		clk_disable_unprepare(clk); -		clk_put(clk); +	if (!IS_ERR(priv->phy)) { +		phy_power_off(priv->phy); +		phy_exit(priv->phy);  	} + +	if (!IS_ERR(priv->clk)) +		clk_disable_unprepare(priv->clk); + +	usb_put_hcd(hcd); +  	return 0;  } @@ -314,7 +333,7 @@ static int __init ehci_orion_init(void)  	pr_info("%s: " DRIVER_DESC "\n", hcd_name); -	ehci_init_driver(&ehci_orion_hc_driver, NULL); +	ehci_init_driver(&ehci_orion_hc_driver, &orion_overrides);  	return platform_driver_register(&ehci_orion_driver);  }  module_init(ehci_orion_init); diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 6bd299e61f5..3e86bf4371b 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -58,8 +58,6 @@ static int ehci_pci_setup(struct usb_hcd *hcd)  {  	struct ehci_hcd		*ehci = hcd_to_ehci(hcd);  	struct pci_dev		*pdev = to_pci_dev(hcd->self.controller); -	struct pci_dev		*p_smbus; -	u8			rev;  	u32			temp;  	int			retval; @@ -175,22 +173,12 @@ static int ehci_pci_setup(struct usb_hcd *hcd)  		/* SB600 and old version of SB700 have a bug in EHCI controller,  		 * which causes usb devices lose response in some cases.  		 */ -		if ((pdev->device == 0x4386) || (pdev->device == 0x4396)) { -			p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, -						 PCI_DEVICE_ID_ATI_SBX00_SMBUS, -						 NULL); -			if (!p_smbus) -				break; -			rev = p_smbus->revision; -			if ((pdev->device == 0x4386) || (rev == 0x3a) -			    || (rev == 0x3b)) { -				u8 tmp; -				ehci_info(ehci, "applying AMD SB600/SB700 USB " -					"freeze workaround\n"); -				pci_read_config_byte(pdev, 0x53, &tmp); -				pci_write_config_byte(pdev, 0x53, tmp | (1<<3)); -			} -			pci_dev_put(p_smbus); +		if ((pdev->device == 0x4386 || pdev->device == 0x4396) && +				usb_amd_hang_symptom_quirk()) { +			u8 tmp; +			ehci_info(ehci, "applying AMD SB600/SB700 USB freeze workaround\n"); +			pci_read_config_byte(pdev, 0x53, &tmp); +			pci_write_config_byte(pdev, 0x53, tmp | (1<<3));  		}  		break;  	case PCI_VENDOR_ID_NETMOS: @@ -361,7 +349,7 @@ static struct pci_driver ehci_pci_driver = {  	.remove =	usb_hcd_pci_remove,  	.shutdown = 	usb_hcd_pci_shutdown, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM  	.driver =	{  		.pm =	&usb_hcd_pci_pm_ops  	}, diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index f6b790ca8cf..2f5b9ce3e04 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -3,6 +3,7 @@   *   * Copyright 2007 Steven Brown <sbrown@cortland.com>   * Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de> + * Copyright 2014 Hans de Goede <hdegoede@redhat.com>   *   * Derived from the ohci-ssb driver   * Copyright 2007 Michael Buesch <m@bues.ch> @@ -18,6 +19,7 @@   *   * Licensed under the GNU/GPL. See COPYING for details.   */ +#include <linux/clk.h>  #include <linux/dma-mapping.h>  #include <linux/err.h>  #include <linux/kernel.h> @@ -25,7 +27,9 @@  #include <linux/io.h>  #include <linux/module.h>  #include <linux/of.h> +#include <linux/phy/phy.h>  #include <linux/platform_device.h> +#include <linux/reset.h>  #include <linux/usb.h>  #include <linux/usb/hcd.h>  #include <linux/usb/ehci_pdriver.h> @@ -33,6 +37,14 @@  #include "ehci.h"  #define DRIVER_DESC "EHCI generic platform driver" +#define EHCI_MAX_CLKS 3 +#define hcd_to_ehci_priv(h) ((struct ehci_platform_priv *)hcd_to_ehci(h)->priv) + +struct ehci_platform_priv { +	struct clk *clks[EHCI_MAX_CLKS]; +	struct reset_control *rst; +	struct phy *phy; +};  static const char hcd_name[] = "ehci-platform"; @@ -45,8 +57,6 @@ static int ehci_platform_reset(struct usb_hcd *hcd)  	hcd->has_tt = pdata->has_tt;  	ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug; -	ehci->big_endian_desc = pdata->big_endian_desc; -	ehci->big_endian_mmio = pdata->big_endian_mmio;  	if (pdata->pre_setup) {  		retval = pdata->pre_setup(hcd); @@ -64,37 +74,90 @@ static int ehci_platform_reset(struct usb_hcd *hcd)  	return 0;  } +static int ehci_platform_power_on(struct platform_device *dev) +{ +	struct usb_hcd *hcd = platform_get_drvdata(dev); +	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); +	int clk, ret; + +	for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) { +		ret = clk_prepare_enable(priv->clks[clk]); +		if (ret) +			goto err_disable_clks; +	} + +	if (priv->phy) { +		ret = phy_init(priv->phy); +		if (ret) +			goto err_disable_clks; + +		ret = phy_power_on(priv->phy); +		if (ret) +			goto err_exit_phy; +	} + +	return 0; + +err_exit_phy: +	phy_exit(priv->phy); +err_disable_clks: +	while (--clk >= 0) +		clk_disable_unprepare(priv->clks[clk]); + +	return ret; +} + +static void ehci_platform_power_off(struct platform_device *dev) +{ +	struct usb_hcd *hcd = platform_get_drvdata(dev); +	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); +	int clk; + +	if (priv->phy) { +		phy_power_off(priv->phy); +		phy_exit(priv->phy); +	} + +	for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--) +		if (priv->clks[clk]) +			clk_disable_unprepare(priv->clks[clk]); +} +  static struct hc_driver __read_mostly ehci_platform_hc_driver;  static const struct ehci_driver_overrides platform_overrides __initconst = { -	.reset =	ehci_platform_reset, +	.reset =		ehci_platform_reset, +	.extra_priv_size =	sizeof(struct ehci_platform_priv),  }; -static struct usb_ehci_pdata ehci_platform_defaults; +static struct usb_ehci_pdata ehci_platform_defaults = { +	.power_on =		ehci_platform_power_on, +	.power_suspend =	ehci_platform_power_off, +	.power_off =		ehci_platform_power_off, +};  static int ehci_platform_probe(struct platform_device *dev)  {  	struct usb_hcd *hcd;  	struct resource *res_mem; -	struct usb_ehci_pdata *pdata; -	int irq; -	int err = -ENOMEM; +	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); +	struct ehci_platform_priv *priv; +	struct ehci_hcd *ehci; +	int err, irq, clk = 0;  	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. +	 * Use reasonable defaults so platforms don't have to provide these +	 * with DT probing on ARM.  	 */ -	if (!dev_get_platdata(&dev->dev)) -		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); +	if (!pdata) +		pdata = &ehci_platform_defaults; -	pdata = dev_get_platdata(&dev->dev); +	err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); +	if (err) +		return err;  	irq = platform_get_irq(dev, 0);  	if (irq < 0) { @@ -107,17 +170,84 @@ static int ehci_platform_probe(struct platform_device *dev)  		return -ENXIO;  	} +	hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev, +			     dev_name(&dev->dev)); +	if (!hcd) +		return -ENOMEM; + +	platform_set_drvdata(dev, hcd); +	dev->dev.platform_data = pdata; +	priv = hcd_to_ehci_priv(hcd); +	ehci = hcd_to_ehci(hcd); + +	if (pdata == &ehci_platform_defaults && dev->dev.of_node) { +		if (of_property_read_bool(dev->dev.of_node, "big-endian-regs")) +			ehci->big_endian_mmio = 1; + +		if (of_property_read_bool(dev->dev.of_node, "big-endian-desc")) +			ehci->big_endian_desc = 1; + +		if (of_property_read_bool(dev->dev.of_node, "big-endian")) +			ehci->big_endian_mmio = ehci->big_endian_desc = 1; + +		priv->phy = devm_phy_get(&dev->dev, "usb"); +		if (IS_ERR(priv->phy)) { +			err = PTR_ERR(priv->phy); +			if (err == -EPROBE_DEFER) +				goto err_put_hcd; +			priv->phy = NULL; +		} + +		for (clk = 0; clk < EHCI_MAX_CLKS; clk++) { +			priv->clks[clk] = of_clk_get(dev->dev.of_node, clk); +			if (IS_ERR(priv->clks[clk])) { +				err = PTR_ERR(priv->clks[clk]); +				if (err == -EPROBE_DEFER) +					goto err_put_clks; +				priv->clks[clk] = NULL; +				break; +			} +		} +	} + +	priv->rst = devm_reset_control_get_optional(&dev->dev, NULL); +	if (IS_ERR(priv->rst)) { +		err = PTR_ERR(priv->rst); +		if (err == -EPROBE_DEFER) +			goto err_put_clks; +		priv->rst = NULL; +	} else { +		err = reset_control_deassert(priv->rst); +		if (err) +			goto err_put_clks; +	} + +	if (pdata->big_endian_desc) +		ehci->big_endian_desc = 1; +	if (pdata->big_endian_mmio) +		ehci->big_endian_mmio = 1; + +#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO +	if (ehci->big_endian_mmio) { +		dev_err(&dev->dev, +			"Error: CONFIG_USB_EHCI_BIG_ENDIAN_MMIO not set\n"); +		err = -EINVAL; +		goto err_reset; +	} +#endif +#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_DESC +	if (ehci->big_endian_desc) { +		dev_err(&dev->dev, +			"Error: CONFIG_USB_EHCI_BIG_ENDIAN_DESC not set\n"); +		err = -EINVAL; +		goto err_reset; +	} +#endif +  	if (pdata->power_on) {  		err = pdata->power_on(dev);  		if (err < 0) -			return err; -	} - -	hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev, -			     dev_name(&dev->dev)); -	if (!hcd) { -		err = -ENOMEM; -		goto err_power; +			goto err_reset;  	}  	hcd->rsrc_start = res_mem->start; @@ -126,21 +256,31 @@ static int ehci_platform_probe(struct platform_device *dev)  	hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);  	if (IS_ERR(hcd->regs)) {  		err = PTR_ERR(hcd->regs); -		goto err_put_hcd; +		goto err_power;  	}  	err = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (err) -		goto err_put_hcd; +		goto err_power; +	device_wakeup_enable(hcd->self.controller);  	platform_set_drvdata(dev, hcd);  	return err; -err_put_hcd: -	usb_put_hcd(hcd);  err_power:  	if (pdata->power_off)  		pdata->power_off(dev); +err_reset: +	if (priv->rst) +		reset_control_assert(priv->rst); +err_put_clks: +	while (--clk >= 0) +		clk_put(priv->clks[clk]); +err_put_hcd: +	if (pdata == &ehci_platform_defaults) +		dev->dev.platform_data = NULL; + +	usb_put_hcd(hcd);  	return err;  } @@ -149,13 +289,22 @@ static int ehci_platform_remove(struct platform_device *dev)  {  	struct usb_hcd *hcd = platform_get_drvdata(dev);  	struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); +	struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); +	int clk;  	usb_remove_hcd(hcd); -	usb_put_hcd(hcd);  	if (pdata->power_off)  		pdata->power_off(dev); +	if (priv->rst) +		reset_control_assert(priv->rst); + +	for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) +		clk_put(priv->clks[clk]); + +	usb_put_hcd(hcd); +  	if (pdata == &ehci_platform_defaults)  		dev->dev.platform_data = NULL; @@ -174,6 +323,8 @@ static int ehci_platform_suspend(struct device *dev)  	int ret;  	ret = ehci_suspend(hcd, do_wakeup); +	if (ret) +		return ret;  	if (pdata->power_suspend)  		pdata->power_suspend(pdev); @@ -206,8 +357,10 @@ static int ehci_platform_resume(struct device *dev)  static const struct of_device_id vt8500_ehci_ids[] = {  	{ .compatible = "via,vt8500-ehci", },  	{ .compatible = "wm,prizm-ehci", }, +	{ .compatible = "generic-ehci", },  	{}  }; +MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);  static const struct platform_device_id ehci_platform_table[] = {  	{ "ehci-platform", 0 }, diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c index 893b707f000..7d75465d97c 100644 --- a/drivers/usb/host/ehci-pmcmsp.c +++ b/drivers/usb/host/ehci-pmcmsp.c @@ -68,9 +68,6 @@ static void usb_hcd_tdi_set_mode(struct ehci_hcd *ehci)  	/* set TWI GPIO USB_HOST_DEV pin high */  	gpio_direction_output(MSP_PIN_USB0_HOST_DEV, 1); -#ifdef CONFIG_MSP_HAS_DUAL_USB -	gpio_direction_output(MSP_PIN_USB1_HOST_DEV, 1); -#endif  }  /* called during probe() after chip reset completes */ @@ -210,8 +207,10 @@ int usb_hcd_msp_probe(const struct hc_driver *driver,  	retval = usb_add_hcd(hcd, res->start, IRQF_SHARED); -	if (retval == 0) +	if (retval == 0) { +		device_wakeup_enable(hcd->self.controller);  		return 0; +	}  	usb_remove_hcd(hcd);  err3: @@ -246,33 +245,6 @@ void usb_hcd_msp_remove(struct usb_hcd *hcd, struct platform_device *dev)  	usb_put_hcd(hcd);  } -#ifdef CONFIG_MSP_HAS_DUAL_USB -/* - * Wrapper around the main ehci_irq.  Since both USB host controllers are - * sharing the same IRQ, need to first determine whether we're the intended - * recipient of this interrupt. - */ -static irqreturn_t ehci_msp_irq(struct usb_hcd *hcd) -{ -	u32 int_src; -	struct device *dev = hcd->self.controller; -	struct platform_device *pdev; -	struct mspusb_device *mdev; -	struct ehci_hcd	*ehci = hcd_to_ehci(hcd); -	/* need to reverse-map a couple of containers to get our device */ -	pdev = to_platform_device(dev); -	mdev = to_mspusb_device(pdev); - -	/* Check to see if this interrupt is for this host controller */ -	int_src = ehci_readl(ehci, &mdev->mab_regs->int_stat); -	if (int_src & (1 << pdev->id)) -		return ehci_irq(hcd); - -	/* Not for this device */ -	return IRQ_NONE; -} -#endif /* DUAL_USB */ -  static const struct hc_driver ehci_msp_hc_driver = {  	.description =		hcd_name,  	.product_desc =		"PMC MSP EHCI", @@ -281,11 +253,7 @@ static const struct hc_driver ehci_msp_hc_driver = {  	/*  	 * generic hardware linkage  	 */ -#ifdef CONFIG_MSP_HAS_DUAL_USB -	.irq =			ehci_msp_irq, -#else  	.irq =			ehci_irq, -#endif  	.flags =		HCD_MEMORY | HCD_USB2 | HCD_BH,  	/* @@ -332,9 +300,6 @@ static int ehci_hcd_msp_drv_probe(struct platform_device *pdev)  		return -ENODEV;  	gpio_request(MSP_PIN_USB0_HOST_DEV, "USB0_HOST_DEV_GPIO"); -#ifdef CONFIG_MSP_HAS_DUAL_USB -	gpio_request(MSP_PIN_USB1_HOST_DEV, "USB1_HOST_DEV_GPIO"); -#endif  	ret = usb_hcd_msp_probe(&ehci_msp_hc_driver, pdev); @@ -349,9 +314,6 @@ static int ehci_hcd_msp_drv_remove(struct platform_device *pdev)  	/* free TWI GPIO USB_HOST_DEV pin */  	gpio_free(MSP_PIN_USB0_HOST_DEV); -#ifdef CONFIG_MSP_HAS_DUAL_USB -	gpio_free(MSP_PIN_USB1_HOST_DEV); -#endif  	return 0;  } diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index 6cc5567bf9c..547924796d2 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -16,6 +16,8 @@  #include <linux/signal.h>  #include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h>  #include <linux/of_platform.h> @@ -117,7 +119,8 @@ static int ehci_hcd_ppc_of_probe(struct platform_device *op)  	irq = irq_of_parse_and_map(dn, 0);  	if (irq == NO_IRQ) { -		printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); +		dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n", +			__FILE__);  		rv = -EBUSY;  		goto err_irq;  	} @@ -167,6 +170,7 @@ static int ehci_hcd_ppc_of_probe(struct platform_device *op)  	if (rv)  		goto err_ioremap; +	device_wakeup_enable(hcd->self.controller);  	return 0;  err_ioremap: diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 8188542ba17..7934ff9b35e 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c @@ -189,6 +189,7 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev)  		goto fail_add_hcd;  	} +	device_wakeup_enable(hcd->self.controller);  	return result;  fail_add_hcd: diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index e321804c347..54f5332f814 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -105,9 +105,9 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)  		is_out = qh->is_out;  		epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f; -		if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { +		if (unlikely(!usb_gettoggle(qh->ps.udev, epnum, is_out))) {  			hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); -			usb_settoggle (qh->dev, epnum, is_out, 1); +			usb_settoggle(qh->ps.udev, epnum, is_out, 1);  		}  	} @@ -168,13 +168,13 @@ static void ehci_clear_tt_buffer(struct ehci_hcd *ehci, struct ehci_qh *qh,  	 * Note: this routine is never called for Isochronous transfers.  	 */  	if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) { -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#ifdef CONFIG_DYNAMIC_DEBUG  		struct usb_device *tt = urb->dev->tt->hub;  		dev_dbg(&tt->dev,  			"clear tt buffer port %d, a%d ep%d t%08x\n",  			urb->dev->ttport, urb->dev->devnum,  			usb_pipeendpoint(urb->pipe), token); -#endif /* DEBUG || CONFIG_DYNAMIC_DEBUG */ +#endif /* CONFIG_DYNAMIC_DEBUG */  		if (!ehci_is_TDI(ehci)  				|| urb->dev->tt->hub !=  				   ehci_to_hcd(ehci)->self.root_hub) { @@ -797,26 +797,35 @@ qh_make (  	 * For control/bulk requests, the HC or TT handles these.  	 */  	if (type == PIPE_INTERRUPT) { -		qh->usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH, +		unsigned	tmp; + +		qh->ps.usecs = NS_TO_US(usb_calc_bus_time(USB_SPEED_HIGH,  				is_input, 0,  				hb_mult(maxp) * max_packet(maxp))); -		qh->start = NO_FRAME; +		qh->ps.phase = NO_FRAME;  		if (urb->dev->speed == USB_SPEED_HIGH) { -			qh->c_usecs = 0; +			qh->ps.c_usecs = 0;  			qh->gap_uf = 0; -			qh->period = urb->interval >> 3; -			if (qh->period == 0 && urb->interval != 1) { +			if (urb->interval > 1 && urb->interval < 8) {  				/* NOTE interval 2 or 4 uframes could work.  				 * But interval 1 scheduling is simpler, and  				 * includes high bandwidth.  				 */  				urb->interval = 1; -			} else if (qh->period > ehci->periodic_size) { -				qh->period = ehci->periodic_size; -				urb->interval = qh->period << 3; +			} else if (urb->interval > ehci->periodic_size << 3) { +				urb->interval = ehci->periodic_size << 3;  			} +			qh->ps.period = urb->interval >> 3; + +			/* period for bandwidth allocation */ +			tmp = min_t(unsigned, EHCI_BANDWIDTH_SIZE, +					1 << (urb->ep->desc.bInterval - 1)); + +			/* Allow urb->interval to override */ +			qh->ps.bw_uperiod = min_t(unsigned, tmp, urb->interval); +			qh->ps.bw_period = qh->ps.bw_uperiod >> 3;  		} else {  			int		think_time; @@ -826,27 +835,35 @@ qh_make (  			/* FIXME this just approximates SPLIT/CSPLIT times */  			if (is_input) {		// SPLIT, gap, CSPLIT+DATA -				qh->c_usecs = qh->usecs + HS_USECS (0); -				qh->usecs = HS_USECS (1); +				qh->ps.c_usecs = qh->ps.usecs + HS_USECS(0); +				qh->ps.usecs = HS_USECS(1);  			} else {		// SPLIT+DATA, gap, CSPLIT -				qh->usecs += HS_USECS (1); -				qh->c_usecs = HS_USECS (0); +				qh->ps.usecs += HS_USECS(1); +				qh->ps.c_usecs = HS_USECS(0);  			}  			think_time = tt ? tt->think_time : 0; -			qh->tt_usecs = NS_TO_US (think_time + +			qh->ps.tt_usecs = NS_TO_US(think_time +  					usb_calc_bus_time (urb->dev->speed,  					is_input, 0, max_packet (maxp))); -			qh->period = urb->interval; -			if (qh->period > ehci->periodic_size) { -				qh->period = ehci->periodic_size; -				urb->interval = qh->period; -			} +			if (urb->interval > ehci->periodic_size) +				urb->interval = ehci->periodic_size; +			qh->ps.period = urb->interval; + +			/* period for bandwidth allocation */ +			tmp = min_t(unsigned, EHCI_BANDWIDTH_FRAMES, +					urb->ep->desc.bInterval); +			tmp = rounddown_pow_of_two(tmp); + +			/* Allow urb->interval to override */ +			qh->ps.bw_period = min_t(unsigned, tmp, urb->interval); +			qh->ps.bw_uperiod = qh->ps.bw_period << 3;  		}  	}  	/* support for tt scheduling, and access to toggles */ -	qh->dev = urb->dev; +	qh->ps.udev = urb->dev; +	qh->ps.ep = urb->ep;  	/* using TT? */  	switch (urb->dev->speed) { diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c deleted file mode 100644 index 7c3de95c705..00000000000 --- a/drivers/usb/host/ehci-s5p.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * SAMSUNG S5P USB HOST EHCI Controller - * - * Copyright (C) 2011 Samsung Electronics Co.Ltd - * Author: Jingoo Han <jg1.han@samsung.com> - * Author: Joonyoung Shim <jy0922.shim@samsung.com> - * - * This program is free software; you can redistribute  it and/or modify it - * under  the terms of  the GNU General  Public License as published by the - * Free Software Foundation;  either version 2 of the  License, or (at your - * option) any later version. - * - */ - -#include <linux/clk.h> -#include <linux/dma-mapping.h> -#include <linux/io.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_gpio.h> -#include <linux/platform_device.h> -#include <linux/platform_data/usb-ehci-s5p.h> -#include <linux/usb/phy.h> -#include <linux/usb/samsung_usb_phy.h> -#include <linux/usb.h> -#include <linux/usb/hcd.h> -#include <linux/usb/otg.h> - -#include "ehci.h" - -#define DRIVER_DESC "EHCI s5p driver" - -#define EHCI_INSNREG00(base)			(base + 0x90) -#define EHCI_INSNREG00_ENA_INCR16		(0x1 << 25) -#define EHCI_INSNREG00_ENA_INCR8		(0x1 << 24) -#define EHCI_INSNREG00_ENA_INCR4		(0x1 << 23) -#define EHCI_INSNREG00_ENA_INCRX_ALIGN		(0x1 << 22) -#define EHCI_INSNREG00_ENABLE_DMA_BURST	\ -	(EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 |	\ -	 EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN) - -static const char hcd_name[] = "ehci-s5p"; -static struct hc_driver __read_mostly s5p_ehci_hc_driver; - -struct s5p_ehci_hcd { -	struct clk *clk; -	struct usb_phy *phy; -	struct usb_otg *otg; -	struct s5p_ehci_platdata *pdata; -}; - -static struct s5p_ehci_platdata empty_platdata; - -#define to_s5p_ehci(hcd)      (struct s5p_ehci_hcd *)(hcd_to_ehci(hcd)->priv) - -static void s5p_setup_vbus_gpio(struct platform_device *pdev) -{ -	struct device *dev = &pdev->dev; -	int err; -	int gpio; - -	if (!dev->of_node) -		return; - -	gpio = of_get_named_gpio(dev->of_node, "samsung,vbus-gpio", 0); -	if (!gpio_is_valid(gpio)) -		return; - -	err = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_HIGH, -				    "ehci_vbus_gpio"); -	if (err) -		dev_err(dev, "can't request ehci vbus gpio %d", gpio); -} - -static int s5p_ehci_probe(struct platform_device *pdev) -{ -	struct s5p_ehci_platdata *pdata = dev_get_platdata(&pdev->dev); -	struct s5p_ehci_hcd *s5p_ehci; -	struct usb_hcd *hcd; -	struct ehci_hcd *ehci; -	struct resource *res; -	struct usb_phy *phy; -	int irq; -	int err; - -	/* -	 * 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 move to full device tree support this will vanish off. -	 */ -	if (!pdev->dev.dma_mask) -		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; -	if (!pdev->dev.coherent_dma_mask) -		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - -	s5p_setup_vbus_gpio(pdev); - -	hcd = usb_create_hcd(&s5p_ehci_hc_driver, -			     &pdev->dev, dev_name(&pdev->dev)); -	if (!hcd) { -		dev_err(&pdev->dev, "Unable to create HCD\n"); -		return -ENOMEM; -	} -	s5p_ehci = to_s5p_ehci(hcd); - -	if (of_device_is_compatible(pdev->dev.of_node, -					"samsung,exynos5440-ehci")) { -		s5p_ehci->pdata = &empty_platdata; -		goto skip_phy; -	} - -	phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); -	if (IS_ERR(phy)) { -		/* Fallback to pdata */ -		if (!pdata) { -			usb_put_hcd(hcd); -			dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); -			return -EPROBE_DEFER; -		} else { -			s5p_ehci->pdata = pdata; -		} -	} else { -		s5p_ehci->phy = phy; -		s5p_ehci->otg = phy->otg; -	} - -skip_phy: - -	s5p_ehci->clk = devm_clk_get(&pdev->dev, "usbhost"); - -	if (IS_ERR(s5p_ehci->clk)) { -		dev_err(&pdev->dev, "Failed to get usbhost clock\n"); -		err = PTR_ERR(s5p_ehci->clk); -		goto fail_clk; -	} - -	err = clk_prepare_enable(s5p_ehci->clk); -	if (err) -		goto fail_clk; - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) { -		dev_err(&pdev->dev, "Failed to get I/O memory\n"); -		err = -ENXIO; -		goto fail_io; -	} - -	hcd->rsrc_start = res->start; -	hcd->rsrc_len = resource_size(res); -	hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len); -	if (!hcd->regs) { -		dev_err(&pdev->dev, "Failed to remap I/O memory\n"); -		err = -ENOMEM; -		goto fail_io; -	} - -	irq = platform_get_irq(pdev, 0); -	if (!irq) { -		dev_err(&pdev->dev, "Failed to get IRQ\n"); -		err = -ENODEV; -		goto fail_io; -	} - -	if (s5p_ehci->otg) -		s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - -	if (s5p_ehci->phy) -		usb_phy_init(s5p_ehci->phy); -	else if (s5p_ehci->pdata->phy_init) -		s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); - -	ehci = hcd_to_ehci(hcd); -	ehci->caps = hcd->regs; - -	/* DMA burst Enable */ -	writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); - -	err = usb_add_hcd(hcd, irq, IRQF_SHARED); -	if (err) { -		dev_err(&pdev->dev, "Failed to add USB HCD\n"); -		goto fail_add_hcd; -	} - -	platform_set_drvdata(pdev, hcd); - -	return 0; - -fail_add_hcd: -	if (s5p_ehci->phy) -		usb_phy_shutdown(s5p_ehci->phy); -	else if (s5p_ehci->pdata->phy_exit) -		s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); -fail_io: -	clk_disable_unprepare(s5p_ehci->clk); -fail_clk: -	usb_put_hcd(hcd); -	return err; -} - -static int s5p_ehci_remove(struct platform_device *pdev) -{ -	struct usb_hcd *hcd = platform_get_drvdata(pdev); -	struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); - -	usb_remove_hcd(hcd); - -	if (s5p_ehci->otg) -		s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - -	if (s5p_ehci->phy) -		usb_phy_shutdown(s5p_ehci->phy); -	else if (s5p_ehci->pdata->phy_exit) -		s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); - -	clk_disable_unprepare(s5p_ehci->clk); - -	usb_put_hcd(hcd); - -	return 0; -} - -#ifdef CONFIG_PM -static int s5p_ehci_suspend(struct device *dev) -{ -	struct usb_hcd *hcd = dev_get_drvdata(dev); -	struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); -	struct platform_device *pdev = to_platform_device(dev); - -	bool do_wakeup = device_may_wakeup(dev); -	int rc; - -	rc = ehci_suspend(hcd, do_wakeup); - -	if (s5p_ehci->otg) -		s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - -	if (s5p_ehci->phy) -		usb_phy_shutdown(s5p_ehci->phy); -	else if (s5p_ehci->pdata->phy_exit) -		s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); - -	clk_disable_unprepare(s5p_ehci->clk); - -	return rc; -} - -static int s5p_ehci_resume(struct device *dev) -{ -	struct usb_hcd *hcd = dev_get_drvdata(dev); -	struct  s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); -	struct platform_device *pdev = to_platform_device(dev); - -	clk_prepare_enable(s5p_ehci->clk); - -	if (s5p_ehci->otg) -		s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - -	if (s5p_ehci->phy) -		usb_phy_init(s5p_ehci->phy); -	else if (s5p_ehci->pdata->phy_init) -		s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); - -	/* DMA burst Enable */ -	writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); - -	ehci_resume(hcd, false); -	return 0; -} -#else -#define s5p_ehci_suspend	NULL -#define s5p_ehci_resume		NULL -#endif - -static const struct dev_pm_ops s5p_ehci_pm_ops = { -	.suspend	= s5p_ehci_suspend, -	.resume		= s5p_ehci_resume, -}; - -#ifdef CONFIG_OF -static const struct of_device_id exynos_ehci_match[] = { -	{ .compatible = "samsung,exynos4210-ehci" }, -	{ .compatible = "samsung,exynos5440-ehci" }, -	{}, -}; -MODULE_DEVICE_TABLE(of, exynos_ehci_match); -#endif - -static struct platform_driver s5p_ehci_driver = { -	.probe		= s5p_ehci_probe, -	.remove		= s5p_ehci_remove, -	.shutdown	= usb_hcd_platform_shutdown, -	.driver = { -		.name	= "s5p-ehci", -		.owner	= THIS_MODULE, -		.pm	= &s5p_ehci_pm_ops, -		.of_match_table = of_match_ptr(exynos_ehci_match), -	} -}; -static const struct ehci_driver_overrides s5p_overrides __initdata = { -	.extra_priv_size = sizeof(struct s5p_ehci_hcd), -}; - -static int __init ehci_s5p_init(void) -{ -	if (usb_disabled()) -		return -ENODEV; - -	pr_info("%s: " DRIVER_DESC "\n", hcd_name); -	ehci_init_driver(&s5p_ehci_hc_driver, &s5p_overrides); -	return platform_driver_register(&s5p_ehci_driver); -} -module_init(ehci_s5p_init); - -static void __exit ehci_s5p_cleanup(void) -{ -	platform_driver_unregister(&s5p_ehci_driver); -} -module_exit(ehci_s5p_cleanup); - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_ALIAS("platform:s5p-ehci"); -MODULE_AUTHOR("Jingoo Han"); -MODULE_AUTHOR("Joonyoung Shim"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 85dd24ed97a..e113fd73aea 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -103,83 +103,210 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)  		*hw_p = *shadow_next_periodic(ehci, &here,  				Q_NEXT_TYPE(ehci, *hw_p));  	else -		*hw_p = ehci->dummy->qh_dma; +		*hw_p = cpu_to_hc32(ehci, ehci->dummy->qh_dma);  } -/* how many of the uframe's 125 usecs are allocated? */ -static unsigned short -periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe) +/*-------------------------------------------------------------------------*/ + +/* Bandwidth and TT management */ + +/* Find the TT data structure for this device; create it if necessary */ +static struct ehci_tt *find_tt(struct usb_device *udev)  { -	__hc32			*hw_p = &ehci->periodic [frame]; -	union ehci_shadow	*q = &ehci->pshadow [frame]; -	unsigned		usecs = 0; -	struct ehci_qh_hw	*hw; - -	while (q->ptr) { -		switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { -		case Q_TYPE_QH: -			hw = q->qh->hw; -			/* is it in the S-mask? */ -			if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe)) -				usecs += q->qh->usecs; -			/* ... or C-mask? */ -			if (hw->hw_info2 & cpu_to_hc32(ehci, -					1 << (8 + uframe))) -				usecs += q->qh->c_usecs; -			hw_p = &hw->hw_next; -			q = &q->qh->qh_next; -			break; -		// case Q_TYPE_FSTN: -		default: -			/* for "save place" FSTNs, count the relevant INTR -			 * bandwidth from the previous frame -			 */ -			if (q->fstn->hw_prev != EHCI_LIST_END(ehci)) { -				ehci_dbg (ehci, "ignoring FSTN cost ...\n"); -			} -			hw_p = &q->fstn->hw_next; -			q = &q->fstn->fstn_next; -			break; -		case Q_TYPE_ITD: -			if (q->itd->hw_transaction[uframe]) -				usecs += q->itd->stream->usecs; -			hw_p = &q->itd->hw_next; -			q = &q->itd->itd_next; -			break; -		case Q_TYPE_SITD: -			/* is it in the S-mask?  (count SPLIT, DATA) */ -			if (q->sitd->hw_uframe & cpu_to_hc32(ehci, -					1 << uframe)) { -				if (q->sitd->hw_fullspeed_ep & -						cpu_to_hc32(ehci, 1<<31)) -					usecs += q->sitd->stream->usecs; -				else	/* worst case for OUT start-split */ -					usecs += HS_USECS_ISO (188); -			} +	struct usb_tt		*utt = udev->tt; +	struct ehci_tt		*tt, **tt_index, **ptt; +	unsigned		port; +	bool			allocated_index = false; + +	if (!utt) +		return NULL;		/* Not below a TT */ + +	/* +	 * Find/create our data structure. +	 * For hubs with a single TT, we get it directly. +	 * For hubs with multiple TTs, there's an extra level of pointers. +	 */ +	tt_index = NULL; +	if (utt->multi) { +		tt_index = utt->hcpriv; +		if (!tt_index) {		/* Create the index array */ +			tt_index = kzalloc(utt->hub->maxchild * +					sizeof(*tt_index), GFP_ATOMIC); +			if (!tt_index) +				return ERR_PTR(-ENOMEM); +			utt->hcpriv = tt_index; +			allocated_index = true; +		} +		port = udev->ttport - 1; +		ptt = &tt_index[port]; +	} else { +		port = 0; +		ptt = (struct ehci_tt **) &utt->hcpriv; +	} + +	tt = *ptt; +	if (!tt) {				/* Create the ehci_tt */ +		struct ehci_hcd		*ehci = +				hcd_to_ehci(bus_to_hcd(udev->bus)); -			/* ... C-mask?  (count CSPLIT, DATA) */ -			if (q->sitd->hw_uframe & -					cpu_to_hc32(ehci, 1 << (8 + uframe))) { -				/* worst case for IN complete-split */ -				usecs += q->sitd->stream->c_usecs; +		tt = kzalloc(sizeof(*tt), GFP_ATOMIC); +		if (!tt) { +			if (allocated_index) { +				utt->hcpriv = NULL; +				kfree(tt_index);  			} +			return ERR_PTR(-ENOMEM); +		} +		list_add_tail(&tt->tt_list, &ehci->tt_list); +		INIT_LIST_HEAD(&tt->ps_list); +		tt->usb_tt = utt; +		tt->tt_port = port; +		*ptt = tt; +	} -			hw_p = &q->sitd->hw_next; -			q = &q->sitd->sitd_next; -			break; +	return tt; +} + +/* Release the TT above udev, if it's not in use */ +static void drop_tt(struct usb_device *udev) +{ +	struct usb_tt		*utt = udev->tt; +	struct ehci_tt		*tt, **tt_index, **ptt; +	int			cnt, i; + +	if (!utt || !utt->hcpriv) +		return;		/* Not below a TT, or never allocated */ + +	cnt = 0; +	if (utt->multi) { +		tt_index = utt->hcpriv; +		ptt = &tt_index[udev->ttport - 1]; + +		/* How many entries are left in tt_index? */ +		for (i = 0; i < utt->hub->maxchild; ++i) +			cnt += !!tt_index[i]; +	} else { +		tt_index = NULL; +		ptt = (struct ehci_tt **) &utt->hcpriv; +	} + +	tt = *ptt; +	if (!tt || !list_empty(&tt->ps_list)) +		return;		/* never allocated, or still in use */ + +	list_del(&tt->tt_list); +	*ptt = NULL; +	kfree(tt); +	if (cnt == 1) { +		utt->hcpriv = NULL; +		kfree(tt_index); +	} +} + +static void bandwidth_dbg(struct ehci_hcd *ehci, int sign, char *type, +		struct ehci_per_sched *ps) +{ +	dev_dbg(&ps->udev->dev, +			"ep %02x: %s %s @ %u+%u (%u.%u+%u) [%u/%u us] mask %04x\n", +			ps->ep->desc.bEndpointAddress, +			(sign >= 0 ? "reserve" : "release"), type, +			(ps->bw_phase << 3) + ps->phase_uf, ps->bw_uperiod, +			ps->phase, ps->phase_uf, ps->period, +			ps->usecs, ps->c_usecs, ps->cs_mask); +} + +static void reserve_release_intr_bandwidth(struct ehci_hcd *ehci, +		struct ehci_qh *qh, int sign) +{ +	unsigned		start_uf; +	unsigned		i, j, m; +	int			usecs = qh->ps.usecs; +	int			c_usecs = qh->ps.c_usecs; +	int			tt_usecs = qh->ps.tt_usecs; +	struct ehci_tt		*tt; + +	if (qh->ps.phase == NO_FRAME)	/* Bandwidth wasn't reserved */ +		return; +	start_uf = qh->ps.bw_phase << 3; + +	bandwidth_dbg(ehci, sign, "intr", &qh->ps); + +	if (sign < 0) {		/* Release bandwidth */ +		usecs = -usecs; +		c_usecs = -c_usecs; +		tt_usecs = -tt_usecs; +	} + +	/* Entire transaction (high speed) or start-split (full/low speed) */ +	for (i = start_uf + qh->ps.phase_uf; i < EHCI_BANDWIDTH_SIZE; +			i += qh->ps.bw_uperiod) +		ehci->bandwidth[i] += usecs; + +	/* Complete-split (full/low speed) */ +	if (qh->ps.c_usecs) { +		/* NOTE: adjustments needed for FSTN */ +		for (i = start_uf; i < EHCI_BANDWIDTH_SIZE; +				i += qh->ps.bw_uperiod) { +			for ((j = 2, m = 1 << (j+8)); j < 8; (++j, m <<= 1)) { +				if (qh->ps.cs_mask & m) +					ehci->bandwidth[i+j] += c_usecs; +			}  		}  	} -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) -	if (usecs > ehci->uframe_periodic_max) -		ehci_err (ehci, "uframe %d sched overrun: %d usecs\n", -			frame * 8 + uframe, usecs); -#endif -	return usecs; + +	/* FS/LS bus bandwidth */ +	if (tt_usecs) { +		tt = find_tt(qh->ps.udev); +		if (sign > 0) +			list_add_tail(&qh->ps.ps_list, &tt->ps_list); +		else +			list_del(&qh->ps.ps_list); + +		for (i = start_uf >> 3; i < EHCI_BANDWIDTH_FRAMES; +				i += qh->ps.bw_period) +			tt->bandwidth[i] += tt_usecs; +	}  }  /*-------------------------------------------------------------------------*/ -static int same_tt (struct usb_device *dev1, struct usb_device *dev2) +static void compute_tt_budget(u8 budget_table[EHCI_BANDWIDTH_SIZE], +		struct ehci_tt *tt) +{ +	struct ehci_per_sched	*ps; +	unsigned		uframe, uf, x; +	u8			*budget_line; + +	if (!tt) +		return; +	memset(budget_table, 0, EHCI_BANDWIDTH_SIZE); + +	/* Add up the contributions from all the endpoints using this TT */ +	list_for_each_entry(ps, &tt->ps_list, ps_list) { +		for (uframe = ps->bw_phase << 3; uframe < EHCI_BANDWIDTH_SIZE; +				uframe += ps->bw_uperiod) { +			budget_line = &budget_table[uframe]; +			x = ps->tt_usecs; + +			/* propagate the time forward */ +			for (uf = ps->phase_uf; uf < 8; ++uf) { +				x += budget_line[uf]; + +				/* Each microframe lasts 125 us */ +				if (x <= 125) { +					budget_line[uf] = x; +					break; +				} else { +					budget_line[uf] = 125; +					x -= 125; +				} +			} +		} +	} +} + +static int __maybe_unused same_tt(struct usb_device *dev1, +		struct usb_device *dev2)  {  	if (!dev1->tt || !dev2->tt)  		return 0; @@ -227,68 +354,6 @@ static inline void carryover_tt_bandwidth(unsigned short tt_usecs[8])  	}  } -/* How many of the tt's periodic downstream 1000 usecs are allocated? - * - * While this measures the bandwidth in terms of usecs/uframe, - * the low/fullspeed bus has no notion of uframes, so any particular - * low/fullspeed transfer can "carry over" from one uframe to the next, - * since the TT just performs downstream transfers in sequence. - * - * For example two separate 100 usec transfers can start in the same uframe, - * and the second one would "carry over" 75 usecs into the next uframe. - */ -static void -periodic_tt_usecs ( -	struct ehci_hcd *ehci, -	struct usb_device *dev, -	unsigned frame, -	unsigned short tt_usecs[8] -) -{ -	__hc32			*hw_p = &ehci->periodic [frame]; -	union ehci_shadow	*q = &ehci->pshadow [frame]; -	unsigned char		uf; - -	memset(tt_usecs, 0, 16); - -	while (q->ptr) { -		switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { -		case Q_TYPE_ITD: -			hw_p = &q->itd->hw_next; -			q = &q->itd->itd_next; -			continue; -		case Q_TYPE_QH: -			if (same_tt(dev, q->qh->dev)) { -				uf = tt_start_uframe(ehci, q->qh->hw->hw_info2); -				tt_usecs[uf] += q->qh->tt_usecs; -			} -			hw_p = &q->qh->hw->hw_next; -			q = &q->qh->qh_next; -			continue; -		case Q_TYPE_SITD: -			if (same_tt(dev, q->sitd->urb->dev)) { -				uf = tt_start_uframe(ehci, q->sitd->hw_uframe); -				tt_usecs[uf] += q->sitd->stream->tt_usecs; -			} -			hw_p = &q->sitd->hw_next; -			q = &q->sitd->sitd_next; -			continue; -		// case Q_TYPE_FSTN: -		default: -			ehci_dbg(ehci, "ignoring periodic frame %d FSTN\n", -					frame); -			hw_p = &q->fstn->hw_next; -			q = &q->fstn->fstn_next; -		} -	} - -	carryover_tt_bandwidth(tt_usecs); - -	if (max_tt_usecs[7] < tt_usecs[7]) -		ehci_err(ehci, "frame %d tt sched overrun: %d usecs\n", -			frame, tt_usecs[7] - max_tt_usecs[7]); -} -  /*   * Return true if the device's tt's downstream bus is available for a   * periodic transfer of the specified length (usecs), starting at the @@ -312,20 +377,29 @@ periodic_tt_usecs (   */  static int tt_available (  	struct ehci_hcd		*ehci, -	unsigned		period, -	struct usb_device	*dev, +	struct ehci_per_sched	*ps, +	struct ehci_tt		*tt,  	unsigned		frame, -	unsigned		uframe, -	u16			usecs +	unsigned		uframe  )  { +	unsigned		period = ps->bw_period; +	unsigned		usecs = ps->tt_usecs; +  	if ((period == 0) || (uframe >= 7))	/* error */  		return 0; -	for (; frame < ehci->periodic_size; frame += period) { -		unsigned short tt_usecs[8]; +	for (frame &= period - 1; frame < EHCI_BANDWIDTH_FRAMES; +			frame += period) { +		unsigned	i, uf; +		unsigned short	tt_usecs[8]; -		periodic_tt_usecs (ehci, dev, frame, tt_usecs); +		if (tt->bandwidth[frame] + usecs > 900) +			return 0; + +		uf = frame << 3; +		for (i = 0; i < 8; (++i, ++uf)) +			tt_usecs[i] = ehci->tt_budget[uf];  		if (max_tt_usecs[uframe] <= tt_usecs[uframe])  			return 0; @@ -337,7 +411,7 @@ static int tt_available (  		 */  		if (125 < usecs) {  			int ufs = (usecs / 125); -			int i; +  			for (i = uframe; i < (uframe + ufs) && i < 8; i++)  				if (0 < tt_usecs[i])  					return 0; @@ -391,7 +465,7 @@ static int tt_no_collision (  				continue;  			case Q_TYPE_QH:  				hw = here.qh->hw; -				if (same_tt (dev, here.qh->dev)) { +				if (same_tt(dev, here.qh->ps.udev)) {  					u32		mask;  					mask = hc32_to_cpu(ehci, @@ -471,19 +545,19 @@ static void disable_periodic(struct ehci_hcd *ehci)  static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)  {  	unsigned	i; -	unsigned	period = qh->period; +	unsigned	period = qh->ps.period; -	dev_dbg (&qh->dev->dev, +	dev_dbg(&qh->ps.udev->dev,  		"link qh%d-%04x/%p start %d [%d/%d us]\n",  		period, hc32_to_cpup(ehci, &qh->hw->hw_info2)  			& (QH_CMASK | QH_SMASK), -		qh, qh->start, qh->usecs, qh->c_usecs); +		qh, qh->ps.phase, qh->ps.usecs, qh->ps.c_usecs);  	/* high bandwidth, or otherwise every microframe */  	if (period == 0)  		period = 1; -	for (i = qh->start; i < ehci->periodic_size; i += period) { +	for (i = qh->ps.phase; i < ehci->periodic_size; i += period) {  		union ehci_shadow	*prev = &ehci->pshadow[i];  		__hc32			*hw_p = &ehci->periodic[i];  		union ehci_shadow	here = *prev; @@ -503,7 +577,7 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)  		 * enables sharing interior tree nodes  		 */  		while (here.ptr && qh != here.qh) { -			if (qh->period > here.qh->period) +			if (qh->ps.period > here.qh->ps.period)  				break;  			prev = &here.qh->qh_next;  			hw_p = &here.qh->hw->hw_next; @@ -523,10 +597,10 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)  	qh->xacterrs = 0;  	qh->exception = 0; -	/* update per-qh bandwidth for usbfs */ -	ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period -		? ((qh->usecs + qh->c_usecs) / qh->period) -		: (qh->usecs * 8); +	/* update per-qh bandwidth for debugfs */ +	ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->ps.bw_period +		? ((qh->ps.usecs + qh->ps.c_usecs) / qh->ps.bw_period) +		: (qh->ps.usecs * 8);  	list_add(&qh->intr_node, &ehci->intr_qh_list); @@ -556,22 +630,21 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)  	 */  	/* high bandwidth, or otherwise part of every microframe */ -	if ((period = qh->period) == 0) -		period = 1; +	period = qh->ps.period ? : 1; -	for (i = qh->start; i < ehci->periodic_size; i += period) +	for (i = qh->ps.phase; i < ehci->periodic_size; i += period)  		periodic_unlink (ehci, i, qh); -	/* update per-qh bandwidth for usbfs */ -	ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->period -		? ((qh->usecs + qh->c_usecs) / qh->period) -		: (qh->usecs * 8); +	/* update per-qh bandwidth for debugfs */ +	ehci_to_hcd(ehci)->self.bandwidth_allocated -= qh->ps.bw_period +		? ((qh->ps.usecs + qh->ps.c_usecs) / qh->ps.bw_period) +		: (qh->ps.usecs * 8); -	dev_dbg (&qh->dev->dev, +	dev_dbg(&qh->ps.udev->dev,  		"unlink qh%d-%04x/%p start %d [%d/%d us]\n", -		qh->period, +		qh->ps.period,  		hc32_to_cpup(ehci, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK), -		qh, qh->start, qh->usecs, qh->c_usecs); +		qh, qh->ps.phase, qh->ps.usecs, qh->ps.c_usecs);  	/* qh->qh_next still "live" to HC */  	qh->qh_state = QH_STATE_UNLINK; @@ -694,11 +767,9 @@ static int check_period (  	struct ehci_hcd *ehci,  	unsigned	frame,  	unsigned	uframe, -	unsigned	period, +	unsigned	uperiod,  	unsigned	usecs  ) { -	int		claimed; -  	/* complete split running into next frame?  	 * given FSTN support, we could sometimes check...  	 */ @@ -708,25 +779,10 @@ static int check_period (  	/* convert "usecs we need" to "max already claimed" */  	usecs = ehci->uframe_periodic_max - usecs; -	/* we "know" 2 and 4 uframe intervals were rejected; so -	 * for period 0, check _every_ microframe in the schedule. -	 */ -	if (unlikely (period == 0)) { -		do { -			for (uframe = 0; uframe < 7; uframe++) { -				claimed = periodic_usecs (ehci, frame, uframe); -				if (claimed > usecs) -					return 0; -			} -		} while ((frame += 1) < ehci->periodic_size); - -	/* just check the specified uframe, at that period */ -	} else { -		do { -			claimed = periodic_usecs (ehci, frame, uframe); -			if (claimed > usecs) -				return 0; -		} while ((frame += period) < ehci->periodic_size); +	for (uframe += frame << 3; uframe < EHCI_BANDWIDTH_SIZE; +			uframe += uperiod) { +		if (ehci->bandwidth[uframe] > usecs) +			return 0;  	}  	// success! @@ -737,40 +793,40 @@ static int check_intr_schedule (  	struct ehci_hcd		*ehci,  	unsigned		frame,  	unsigned		uframe, -	const struct ehci_qh	*qh, -	__hc32			*c_maskp +	struct ehci_qh		*qh, +	unsigned		*c_maskp, +	struct ehci_tt		*tt  )  {  	int		retval = -ENOSPC;  	u8		mask = 0; -	if (qh->c_usecs && uframe >= 6)		/* FSTN territory? */ +	if (qh->ps.c_usecs && uframe >= 6)	/* FSTN territory? */  		goto done; -	if (!check_period (ehci, frame, uframe, qh->period, qh->usecs)) +	if (!check_period(ehci, frame, uframe, qh->ps.bw_uperiod, qh->ps.usecs))  		goto done; -	if (!qh->c_usecs) { +	if (!qh->ps.c_usecs) {  		retval = 0;  		*c_maskp = 0;  		goto done;  	}  #ifdef CONFIG_USB_EHCI_TT_NEWSCHED -	if (tt_available (ehci, qh->period, qh->dev, frame, uframe, -				qh->tt_usecs)) { +	if (tt_available(ehci, &qh->ps, tt, frame, uframe)) {  		unsigned i;  		/* TODO : this may need FSTN for SSPLIT in uframe 5. */ -		for (i=uframe+1; i<8 && i<uframe+4; i++) -			if (!check_period (ehci, frame, i, -						qh->period, qh->c_usecs)) +		for (i = uframe+2; i < 8 && i <= uframe+4; i++) +			if (!check_period(ehci, frame, i, +					qh->ps.bw_uperiod, qh->ps.c_usecs))  				goto done;  			else  				mask |= 1 << i;  		retval = 0; -		*c_maskp = cpu_to_hc32(ehci, mask << 8); +		*c_maskp = mask;  	}  #else  	/* Make sure this tt's buffer is also available for CSPLITs. @@ -781,15 +837,15 @@ static int check_intr_schedule (  	 * one smart pass...  	 */  	mask = 0x03 << (uframe + qh->gap_uf); -	*c_maskp = cpu_to_hc32(ehci, mask << 8); +	*c_maskp = mask;  	mask |= 1 << uframe; -	if (tt_no_collision (ehci, qh->period, qh->dev, frame, mask)) { -		if (!check_period (ehci, frame, uframe + qh->gap_uf + 1, -					qh->period, qh->c_usecs)) +	if (tt_no_collision(ehci, qh->ps.bw_period, qh->ps.udev, frame, mask)) { +		if (!check_period(ehci, frame, uframe + qh->gap_uf + 1, +				qh->ps.bw_uperiod, qh->ps.c_usecs))  			goto done; -		if (!check_period (ehci, frame, uframe + qh->gap_uf, -					qh->period, qh->c_usecs)) +		if (!check_period(ehci, frame, uframe + qh->gap_uf, +				qh->ps.bw_uperiod, qh->ps.c_usecs))  			goto done;  		retval = 0;  	} @@ -803,62 +859,67 @@ done:   */  static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)  { -	int		status; +	int		status = 0;  	unsigned	uframe; -	__hc32		c_mask; -	unsigned	frame;		/* 0..(qh->period - 1), or NO_FRAME */ +	unsigned	c_mask;  	struct ehci_qh_hw	*hw = qh->hw; +	struct ehci_tt		*tt;  	hw->hw_next = EHCI_LIST_END(ehci); -	frame = qh->start;  	/* reuse the previous schedule slots, if we can */ -	if (frame < qh->period) { -		uframe = ffs(hc32_to_cpup(ehci, &hw->hw_info2) & QH_SMASK); -		status = check_intr_schedule (ehci, frame, --uframe, -				qh, &c_mask); -	} else { -		uframe = 0; -		c_mask = 0; -		status = -ENOSPC; +	if (qh->ps.phase != NO_FRAME) { +		ehci_dbg(ehci, "reused qh %p schedule\n", qh); +		return 0; +	} + +	uframe = 0; +	c_mask = 0; +	tt = find_tt(qh->ps.udev); +	if (IS_ERR(tt)) { +		status = PTR_ERR(tt); +		goto done;  	} +	compute_tt_budget(ehci->tt_budget, tt);  	/* else scan the schedule to find a group of slots such that all  	 * uframes have enough periodic bandwidth available.  	 */ -	if (status) { -		/* "normal" case, uframing flexible except with splits */ -		if (qh->period) { -			int		i; - -			for (i = qh->period; status && i > 0; --i) { -				frame = ++ehci->random_frame % qh->period; -				for (uframe = 0; uframe < 8; uframe++) { -					status = check_intr_schedule (ehci, -							frame, uframe, qh, -							&c_mask); -					if (status == 0) -						break; -				} +	/* "normal" case, uframing flexible except with splits */ +	if (qh->ps.bw_period) { +		int		i; +		unsigned	frame; + +		for (i = qh->ps.bw_period; i > 0; --i) { +			frame = ++ehci->random_frame & (qh->ps.bw_period - 1); +			for (uframe = 0; uframe < 8; uframe++) { +				status = check_intr_schedule(ehci, +						frame, uframe, qh, &c_mask, tt); +				if (status == 0) +					goto got_it;  			} - -		/* qh->period == 0 means every uframe */ -		} else { -			frame = 0; -			status = check_intr_schedule (ehci, 0, 0, qh, &c_mask);  		} -		if (status) -			goto done; -		qh->start = frame; -		/* reset S-frame and (maybe) C-frame masks */ -		hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK)); -		hw->hw_info2 |= qh->period -			? cpu_to_hc32(ehci, 1 << uframe) -			: cpu_to_hc32(ehci, QH_SMASK); -		hw->hw_info2 |= c_mask; -	} else -		ehci_dbg (ehci, "reused qh %p schedule\n", qh); +	/* qh->ps.bw_period == 0 means every uframe */ +	} else { +		status = check_intr_schedule(ehci, 0, 0, qh, &c_mask, tt); +	} +	if (status) +		goto done; + + got_it: +	qh->ps.phase = (qh->ps.period ? ehci->random_frame & +			(qh->ps.period - 1) : 0); +	qh->ps.bw_phase = qh->ps.phase & (qh->ps.bw_period - 1); +	qh->ps.phase_uf = uframe; +	qh->ps.cs_mask = qh->ps.period ? +			(c_mask << 8) | (1 << uframe) : +			QH_SMASK; + +	/* reset S-frame and (maybe) C-frame masks */ +	hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK)); +	hw->hw_info2 |= cpu_to_hc32(ehci, qh->ps.cs_mask); +	reserve_release_intr_bandwidth(ehci, qh, 1);  done:  	return status; @@ -969,7 +1030,8 @@ iso_stream_alloc (gfp_t mem_flags)  	if (likely (stream != NULL)) {  		INIT_LIST_HEAD(&stream->td_list);  		INIT_LIST_HEAD(&stream->free_list); -		stream->next_uframe = -1; +		stream->next_uframe = NO_FRAME; +		stream->ps.phase = NO_FRAME;  	}  	return stream;  } @@ -978,25 +1040,24 @@ static void  iso_stream_init (  	struct ehci_hcd		*ehci,  	struct ehci_iso_stream	*stream, -	struct usb_device	*dev, -	int			pipe, -	unsigned		interval +	struct urb		*urb  )  {  	static const u8 smask_out [] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f }; +	struct usb_device	*dev = urb->dev;  	u32			buf1;  	unsigned		epnum, maxp;  	int			is_input; -	long			bandwidth; +	unsigned		tmp;  	/*  	 * this might be a "high bandwidth" highspeed endpoint,  	 * as encoded in the ep descriptor's wMaxPacket field  	 */ -	epnum = usb_pipeendpoint (pipe); -	is_input = usb_pipein (pipe) ? USB_DIR_IN : 0; -	maxp = usb_maxpacket(dev, pipe, !is_input); +	epnum = usb_pipeendpoint(urb->pipe); +	is_input = usb_pipein(urb->pipe) ? USB_DIR_IN : 0; +	maxp = usb_endpoint_maxp(&urb->ep->desc);  	if (is_input) {  		buf1 = (1 << 11);  	} else { @@ -1020,9 +1081,19 @@ iso_stream_init (  		/* usbfs wants to report the average usecs per frame tied up  		 * when transfers on this endpoint are scheduled ...  		 */ -		stream->usecs = HS_USECS_ISO (maxp); -		bandwidth = stream->usecs * 8; -		bandwidth /= interval; +		stream->ps.usecs = HS_USECS_ISO(maxp); + +		/* period for bandwidth allocation */ +		tmp = min_t(unsigned, EHCI_BANDWIDTH_SIZE, +				1 << (urb->ep->desc.bInterval - 1)); + +		/* Allow urb->interval to override */ +		stream->ps.bw_uperiod = min_t(unsigned, tmp, urb->interval); + +		stream->uperiod = urb->interval; +		stream->ps.period = urb->interval >> 3; +		stream->bandwidth = stream->ps.usecs * 8 / +				stream->ps.bw_uperiod;  	} else {  		u32		addr; @@ -1036,36 +1107,46 @@ iso_stream_init (  			addr |= dev->tt->hub->devnum << 16;  		addr |= epnum << 8;  		addr |= dev->devnum; -		stream->usecs = HS_USECS_ISO (maxp); +		stream->ps.usecs = HS_USECS_ISO(maxp);  		think_time = dev->tt ? dev->tt->think_time : 0; -		stream->tt_usecs = NS_TO_US (think_time + usb_calc_bus_time ( +		stream->ps.tt_usecs = NS_TO_US(think_time + usb_calc_bus_time(  				dev->speed, is_input, 1, maxp));  		hs_transfers = max (1u, (maxp + 187) / 188);  		if (is_input) {  			u32	tmp;  			addr |= 1 << 31; -			stream->c_usecs = stream->usecs; -			stream->usecs = HS_USECS_ISO (1); -			stream->raw_mask = 1; +			stream->ps.c_usecs = stream->ps.usecs; +			stream->ps.usecs = HS_USECS_ISO(1); +			stream->ps.cs_mask = 1;  			/* c-mask as specified in USB 2.0 11.18.4 3.c */  			tmp = (1 << (hs_transfers + 2)) - 1; -			stream->raw_mask |= tmp << (8 + 2); +			stream->ps.cs_mask |= tmp << (8 + 2);  		} else -			stream->raw_mask = smask_out [hs_transfers - 1]; -		bandwidth = stream->usecs + stream->c_usecs; -		bandwidth /= interval << 3; +			stream->ps.cs_mask = smask_out[hs_transfers - 1]; + +		/* period for bandwidth allocation */ +		tmp = min_t(unsigned, EHCI_BANDWIDTH_FRAMES, +				1 << (urb->ep->desc.bInterval - 1)); + +		/* Allow urb->interval to override */ +		stream->ps.bw_period = min_t(unsigned, tmp, urb->interval); +		stream->ps.bw_uperiod = stream->ps.bw_period << 3; -		/* stream->splits gets created from raw_mask later */ +		stream->ps.period = urb->interval; +		stream->uperiod = urb->interval << 3; +		stream->bandwidth = (stream->ps.usecs + stream->ps.c_usecs) / +				stream->ps.bw_period; + +		/* stream->splits gets created from cs_mask later */  		stream->address = cpu_to_hc32(ehci, addr);  	} -	stream->bandwidth = bandwidth; -	stream->udev = dev; +	stream->ps.udev = dev; +	stream->ps.ep = urb->ep;  	stream->bEndpointAddress = is_input | epnum; -	stream->interval = interval;  	stream->maxp = maxp;  } @@ -1090,9 +1171,7 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)  		stream = iso_stream_alloc(GFP_ATOMIC);  		if (likely (stream != NULL)) {  			ep->hcpriv = stream; -			stream->ep = ep; -			iso_stream_init(ehci, stream, urb->dev, urb->pipe, -					urb->interval); +			iso_stream_init(ehci, stream, urb);  		}  	/* if dev->ep [epnum] is a QH, hw is set */ @@ -1137,7 +1216,7 @@ itd_sched_init(  	dma_addr_t	dma = urb->transfer_dma;  	/* how many uframes are needed for these transfers */ -	iso_sched->span = urb->number_of_packets * stream->interval; +	iso_sched->span = urb->number_of_packets * stream->uperiod;  	/* figure out per-uframe itd fields that we'll need later  	 * when we fit new itds into the schedule. @@ -1236,7 +1315,7 @@ itd_urb_transaction (  		memset (itd, 0, sizeof *itd);  		itd->itd_dma = itd_dma; -		itd->frame = 9999;		/* an invalid value */ +		itd->frame = NO_FRAME;  		list_add (&itd->itd_list, &sched->td_list);  	}  	spin_unlock_irqrestore (&ehci->lock, flags); @@ -1249,49 +1328,106 @@ itd_urb_transaction (  /*-------------------------------------------------------------------------*/ +static void reserve_release_iso_bandwidth(struct ehci_hcd *ehci, +		struct ehci_iso_stream *stream, int sign) +{ +	unsigned		uframe; +	unsigned		i, j; +	unsigned		s_mask, c_mask, m; +	int			usecs = stream->ps.usecs; +	int			c_usecs = stream->ps.c_usecs; +	int			tt_usecs = stream->ps.tt_usecs; +	struct ehci_tt		*tt; + +	if (stream->ps.phase == NO_FRAME)	/* Bandwidth wasn't reserved */ +		return; +	uframe = stream->ps.bw_phase << 3; + +	bandwidth_dbg(ehci, sign, "iso", &stream->ps); + +	if (sign < 0) {		/* Release bandwidth */ +		usecs = -usecs; +		c_usecs = -c_usecs; +		tt_usecs = -tt_usecs; +	} + +	if (!stream->splits) {		/* High speed */ +		for (i = uframe + stream->ps.phase_uf; i < EHCI_BANDWIDTH_SIZE; +				i += stream->ps.bw_uperiod) +			ehci->bandwidth[i] += usecs; + +	} else {			/* Full speed */ +		s_mask = stream->ps.cs_mask; +		c_mask = s_mask >> 8; + +		/* NOTE: adjustment needed for frame overflow */ +		for (i = uframe; i < EHCI_BANDWIDTH_SIZE; +				i += stream->ps.bw_uperiod) { +			for ((j = stream->ps.phase_uf, m = 1 << j); j < 8; +					(++j, m <<= 1)) { +				if (s_mask & m) +					ehci->bandwidth[i+j] += usecs; +				else if (c_mask & m) +					ehci->bandwidth[i+j] += c_usecs; +			} +		} + +		tt = find_tt(stream->ps.udev); +		if (sign > 0) +			list_add_tail(&stream->ps.ps_list, &tt->ps_list); +		else +			list_del(&stream->ps.ps_list); + +		for (i = uframe >> 3; i < EHCI_BANDWIDTH_FRAMES; +				i += stream->ps.bw_period) +			tt->bandwidth[i] += tt_usecs; +	} +} +  static inline int  itd_slot_ok (  	struct ehci_hcd		*ehci, -	u32			mod, -	u32			uframe, -	u8			usecs, -	u32			period +	struct ehci_iso_stream	*stream, +	unsigned		uframe  )  { -	uframe %= period; -	do { -		/* can't commit more than uframe_periodic_max usec */ -		if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7) -				> (ehci->uframe_periodic_max - usecs)) -			return 0; +	unsigned		usecs; + +	/* convert "usecs we need" to "max already claimed" */ +	usecs = ehci->uframe_periodic_max - stream->ps.usecs; -		/* we know urb->interval is 2^N uframes */ -		uframe += period; -	} while (uframe < mod); +	for (uframe &= stream->ps.bw_uperiod - 1; uframe < EHCI_BANDWIDTH_SIZE; +			uframe += stream->ps.bw_uperiod) { +		if (ehci->bandwidth[uframe] > usecs) +			return 0; +	}  	return 1;  }  static inline int  sitd_slot_ok (  	struct ehci_hcd		*ehci, -	u32			mod,  	struct ehci_iso_stream	*stream, -	u32			uframe, +	unsigned		uframe,  	struct ehci_iso_sched	*sched, -	u32			period_uframes +	struct ehci_tt		*tt  )  { -	u32			mask, tmp; -	u32			frame, uf; +	unsigned		mask, tmp; +	unsigned		frame, uf; + +	mask = stream->ps.cs_mask << (uframe & 7); -	mask = stream->raw_mask << (uframe & 7); +	/* for OUT, don't wrap SSPLIT into H-microframe 7 */ +	if (((stream->ps.cs_mask & 0xff) << (uframe & 7)) >= (1 << 7)) +		return 0;  	/* for IN, don't wrap CSPLIT into the next frame */  	if (mask & ~0xffff)  		return 0;  	/* check bandwidth */ -	uframe %= period_uframes; +	uframe &= stream->ps.bw_uperiod - 1;  	frame = uframe >> 3;  #ifdef CONFIG_USB_EHCI_TT_NEWSCHED @@ -1299,54 +1435,48 @@ sitd_slot_ok (  	 * tt_available scheduling guarantees 10+% for control/bulk.  	 */  	uf = uframe & 7; -	if (!tt_available(ehci, period_uframes >> 3, -			stream->udev, frame, uf, stream->tt_usecs)) +	if (!tt_available(ehci, &stream->ps, tt, frame, uf))  		return 0;  #else  	/* tt must be idle for start(s), any gap, and csplit.  	 * assume scheduling slop leaves 10+% for control/bulk.  	 */ -	if (!tt_no_collision(ehci, period_uframes >> 3, -			stream->udev, frame, mask)) +	if (!tt_no_collision(ehci, stream->ps.bw_period, +			stream->ps.udev, frame, mask))  		return 0;  #endif -	/* this multi-pass logic is simple, but performance may -	 * suffer when the schedule data isn't cached. -	 */  	do { -		u32		max_used; - -		frame = uframe >> 3; -		uf = uframe & 7; +		unsigned	max_used; +		unsigned	i;  		/* check starts (OUT uses more than one) */ -		max_used = ehci->uframe_periodic_max - stream->usecs; -		for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) { -			if (periodic_usecs (ehci, frame, uf) > max_used) +		uf = uframe; +		max_used = ehci->uframe_periodic_max - stream->ps.usecs; +		for (tmp = stream->ps.cs_mask & 0xff; tmp; tmp >>= 1, uf++) { +			if (ehci->bandwidth[uf] > max_used)  				return 0;  		}  		/* for IN, check CSPLIT */ -		if (stream->c_usecs) { -			uf = uframe & 7; -			max_used = ehci->uframe_periodic_max - stream->c_usecs; -			do { -				tmp = 1 << uf; -				tmp <<= 8; -				if ((stream->raw_mask & tmp) == 0) +		if (stream->ps.c_usecs) { +			max_used = ehci->uframe_periodic_max - +					stream->ps.c_usecs; +			uf = uframe & ~7; +			tmp = 1 << (2+8); +			for (i = (uframe & 7) + 2; i < 8; (++i, tmp <<= 1)) { +				if ((stream->ps.cs_mask & tmp) == 0)  					continue; -				if (periodic_usecs (ehci, frame, uf) -						> max_used) +				if (ehci->bandwidth[uf+i] > max_used)  					return 0; -			} while (++uf < 8); +			}  		} -		/* we know urb->interval is 2^N uframes */ -		uframe += period_uframes; -	} while (uframe < mod); +		uframe += stream->ps.bw_uperiod; +	} while (uframe < EHCI_BANDWIDTH_SIZE); -	stream->splits = cpu_to_hc32(ehci, stream->raw_mask << (uframe & 7)); +	stream->ps.cs_mask <<= uframe & 7; +	stream->splits = cpu_to_hc32(ehci, stream->ps.cs_mask);  	return 1;  } @@ -1361,8 +1491,6 @@ sitd_slot_ok (   * given EHCI_TUNE_FLS and the slop).  Or, write a smarter scheduler!   */ -#define SCHEDULING_DELAY	40	/* microframes */ -  static int  iso_stream_schedule (  	struct ehci_hcd		*ehci, @@ -1370,134 +1498,184 @@ iso_stream_schedule (  	struct ehci_iso_stream	*stream  )  { -	u32			now, base, next, start, period, span; -	int			status; +	u32			now, base, next, start, period, span, now2; +	u32			wrap = 0, skip = 0; +	int			status = 0;  	unsigned		mod = ehci->periodic_size << 3;  	struct ehci_iso_sched	*sched = urb->hcpriv; +	bool			empty = list_empty(&stream->td_list); +	bool			new_stream = false; -	period = urb->interval; +	period = stream->uperiod;  	span = sched->span; -	if (!stream->highspeed) { -		period <<= 3; +	if (!stream->highspeed)  		span <<= 3; -	} -	now = ehci_read_frame_index(ehci) & (mod - 1); +	/* Start a new isochronous stream? */ +	if (unlikely(empty && !hcd_periodic_completion_in_progress( +			ehci_to_hcd(ehci), urb->ep))) { -	/* Typical case: reuse current schedule, stream is still active. -	 * Hopefully there are no gaps from the host falling behind -	 * (irq delays etc).  If there are, the behavior depends on -	 * whether URB_ISO_ASAP is set. -	 */ -	if (likely (!list_empty (&stream->td_list))) { +		/* Schedule the endpoint */ +		if (stream->ps.phase == NO_FRAME) { +			int		done = 0; +			struct ehci_tt	*tt = find_tt(stream->ps.udev); -		/* Take the isochronous scheduling threshold into account */ -		if (ehci->i_thresh) -			next = now + ehci->i_thresh;	/* uframe cache */ -		else -			next = (now + 2 + 7) & ~0x07;	/* full frame cache */ - -		/* -		 * Use ehci->last_iso_frame as the base.  There can't be any -		 * TDs scheduled for earlier than that. -		 */ -		base = ehci->last_iso_frame << 3; -		next = (next - base) & (mod - 1); -		start = (stream->next_uframe - base) & (mod - 1); - -		/* Is the schedule already full? */ -		if (unlikely(start < period)) { -			ehci_dbg(ehci, "iso sched full %p (%u-%u < %u mod %u)\n", -					urb, stream->next_uframe, base, -					period, mod); -			status = -ENOSPC; -			goto fail; -		} - -		/* Behind the scheduling threshold? */ -		if (unlikely(start < next)) { -			unsigned now2 = (now - base) & (mod - 1); +			if (IS_ERR(tt)) { +				status = PTR_ERR(tt); +				goto fail; +			} +			compute_tt_budget(ehci->tt_budget, tt); -			/* USB_ISO_ASAP: Round up to the first available slot */ -			if (urb->transfer_flags & URB_ISO_ASAP) -				start += (next - start + period - 1) & -period; +			start = ((-(++ehci->random_frame)) << 3) & (period - 1); -			/* -			 * Not ASAP: Use the next slot in the stream, -			 * no matter what. +			/* find a uframe slot with enough bandwidth. +			 * Early uframes are more precious because full-speed +			 * iso IN transfers can't use late uframes, +			 * and therefore they should be allocated last.  			 */ -			else if (start + span - period < now2) { -				ehci_dbg(ehci, "iso underrun %p (%u+%u < %u)\n", -						urb, start + base, -						span - period, now2 + base); +			next = start; +			start += period; +			do { +				start--; +				/* check schedule: enough space? */ +				if (stream->highspeed) { +					if (itd_slot_ok(ehci, stream, start)) +						done = 1; +				} else { +					if ((start % 8) >= 6) +						continue; +					if (sitd_slot_ok(ehci, stream, start, +							sched, tt)) +						done = 1; +				} +			} while (start > next && !done); + +			/* no room in the schedule */ +			if (!done) { +				ehci_dbg(ehci, "iso sched full %p", urb); +				status = -ENOSPC; +				goto fail;  			} +			stream->ps.phase = (start >> 3) & +					(stream->ps.period - 1); +			stream->ps.bw_phase = stream->ps.phase & +					(stream->ps.bw_period - 1); +			stream->ps.phase_uf = start & 7; +			reserve_release_iso_bandwidth(ehci, stream, 1); +		} + +		/* New stream is already scheduled; use the upcoming slot */ +		else { +			start = (stream->ps.phase << 3) + stream->ps.phase_uf;  		} -		start += base; +		stream->next_uframe = start; +		new_stream = true;  	} -	/* need to schedule; when's the next (u)frame we could start? -	 * this is bigger than ehci->i_thresh allows; scheduling itself -	 * isn't free, the delay should handle reasonably slow cpus.  it -	 * can also help high bandwidth if the dma and irq loads don't -	 * jump until after the queue is primed. +	now = ehci_read_frame_index(ehci) & (mod - 1); + +	/* Take the isochronous scheduling threshold into account */ +	if (ehci->i_thresh) +		next = now + ehci->i_thresh;	/* uframe cache */ +	else +		next = (now + 2 + 7) & ~0x07;	/* full frame cache */ + +	/* +	 * Use ehci->last_iso_frame as the base.  There can't be any +	 * TDs scheduled for earlier than that.  	 */ -	else { -		int done = 0; +	base = ehci->last_iso_frame << 3; +	next = (next - base) & (mod - 1); +	start = (stream->next_uframe - base) & (mod - 1); -		base = now & ~0x07; -		start = base + SCHEDULING_DELAY; +	if (unlikely(new_stream)) +		goto do_ASAP; -		/* find a uframe slot with enough bandwidth. -		 * Early uframes are more precious because full-speed -		 * iso IN transfers can't use late uframes, -		 * and therefore they should be allocated last. -		 */ -		next = start; -		start += period; -		do { -			start--; -			/* check schedule: enough space? */ -			if (stream->highspeed) { -				if (itd_slot_ok(ehci, mod, start, -						stream->usecs, period)) -					done = 1; -			} else { -				if ((start % 8) >= 6) -					continue; -				if (sitd_slot_ok(ehci, mod, stream, -						start, sched, period)) -					done = 1; -			} -		} while (start > next && !done); +	/* +	 * Typical case: reuse current schedule, stream may still be active. +	 * Hopefully there are no gaps from the host falling behind +	 * (irq delays etc).  If there are, the behavior depends on +	 * whether URB_ISO_ASAP is set. +	 */ +	now2 = (now - base) & (mod - 1); + +	/* Is the schedule already full? */ +	if (unlikely(!empty && start < period)) { +		ehci_dbg(ehci, "iso sched full %p (%u-%u < %u mod %u)\n", +				urb, stream->next_uframe, base, period, mod); +		status = -ENOSPC; +		goto fail; +	} + +	/* Is the next packet scheduled after the base time? */ +	if (likely(!empty || start <= now2 + period)) { + +		/* URB_ISO_ASAP: make sure that start >= next */ +		if (unlikely(start < next && +				(urb->transfer_flags & URB_ISO_ASAP))) +			goto do_ASAP; + +		/* Otherwise use start, if it's not in the past */ +		if (likely(start >= now2)) +			goto use_start; -		/* no room in the schedule */ -		if (!done) { -			ehci_dbg(ehci, "iso sched full %p", urb); -			status = -ENOSPC; -			goto fail; +	/* Otherwise we got an underrun while the queue was empty */ +	} else { +		if (urb->transfer_flags & URB_ISO_ASAP) +			goto do_ASAP; +		wrap = mod; +		now2 += mod; +	} + +	/* How many uframes and packets do we need to skip? */ +	skip = (now2 - start + period - 1) & -period; +	if (skip >= span) {		/* Entirely in the past? */ +		ehci_dbg(ehci, "iso underrun %p (%u+%u < %u) [%u]\n", +				urb, start + base, span - period, now2 + base, +				base); + +		/* Try to keep the last TD intact for scanning later */ +		skip = span - period; + +		/* Will it come before the current scan position? */ +		if (empty) { +			skip = span;	/* Skip the entire URB */ +			status = 1;	/* and give it back immediately */ +			iso_sched_free(stream, sched); +			sched = NULL;  		}  	} +	urb->error_count = skip / period; +	if (sched) +		sched->first_packet = urb->error_count; +	goto use_start; + do_ASAP: +	/* Use the first slot after "next" */ +	start = next + ((start - next) & (period - 1)); + + use_start:  	/* Tried to schedule too far into the future? */ -	if (unlikely(start - base + span - period >= mod)) { +	if (unlikely(start + span - period >= mod + wrap)) {  		ehci_dbg(ehci, "request %p would overflow (%u+%u >= %u)\n", -				urb, start - base, span - period, mod); +				urb, start, span - period, mod + wrap);  		status = -EFBIG;  		goto fail;  	} -	stream->next_uframe = start & (mod - 1); +	start += base; +	stream->next_uframe = (start + skip) & (mod - 1);  	/* report high speed start in uframes; full speed, in frames */ -	urb->start_frame = stream->next_uframe; +	urb->start_frame = start & (mod - 1);  	if (!stream->highspeed)  		urb->start_frame >>= 3;  	/* Make sure scan_isoc() sees these */  	if (ehci->isoc_count == 0)  		ehci->last_iso_frame = now >> 3; -	return 0; +	return status;   fail:  	iso_sched_free(stream, sched); @@ -1610,7 +1788,8 @@ static void itd_link_urb(  	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;  	/* fill iTDs uframe by uframe */ -	for (packet = 0, itd = NULL; packet < urb->number_of_packets; ) { +	for (packet = iso_sched->first_packet, itd = NULL; +			packet < urb->number_of_packets;) {  		if (itd == NULL) {  			/* ASSERT:  we have all necessary itds */  			// BUG_ON (list_empty (&iso_sched->td_list)); @@ -1630,7 +1809,7 @@ static void itd_link_urb(  		itd_patch(ehci, itd, iso_sched, packet, uframe); -		next_uframe += stream->interval; +		next_uframe += stream->uperiod;  		next_uframe &= mod - 1;  		packet++; @@ -1770,9 +1949,9 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,  		ehci_dbg (ehci, "can't get iso stream\n");  		return -ENOMEM;  	} -	if (unlikely (urb->interval != stream->interval)) { +	if (unlikely(urb->interval != stream->uperiod)) {  		ehci_dbg (ehci, "can't change iso interval %d --> %d\n", -			stream->interval, urb->interval); +			stream->uperiod, urb->interval);  		goto done;  	} @@ -1804,10 +1983,14 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,  	if (unlikely(status))  		goto done_not_linked;  	status = iso_stream_schedule(ehci, urb, stream); -	if (likely (status == 0)) +	if (likely(status == 0)) {  		itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); -	else +	} else if (status > 0) { +		status = 0; +		ehci_urb_done(ehci, urb, 0); +	} else {  		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +	}   done_not_linked:  	spin_unlock_irqrestore (&ehci->lock, flags);   done: @@ -1833,7 +2016,7 @@ sitd_sched_init(  	dma_addr_t	dma = urb->transfer_dma;  	/* how many frames are needed for these transfers */ -	iso_sched->span = urb->number_of_packets * stream->interval; +	iso_sched->span = urb->number_of_packets * stream->ps.period;  	/* figure out per-frame sitd fields that we'll need later  	 * when we fit new sitds into the schedule. @@ -1925,7 +2108,7 @@ sitd_urb_transaction (  		memset (sitd, 0, sizeof *sitd);  		sitd->sitd_dma = sitd_dma; -		sitd->frame = 9999;		/* an invalid value */ +		sitd->frame = NO_FRAME;  		list_add (&sitd->sitd_list, &iso_sched->td_list);  	} @@ -2008,7 +2191,7 @@ static void sitd_link_urb(  	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;  	/* fill sITDs frame by frame */ -	for (packet = 0, sitd = NULL; +	for (packet = sched->first_packet, sitd = NULL;  			packet < urb->number_of_packets;  			packet++) { @@ -2027,7 +2210,7 @@ static void sitd_link_urb(  		sitd_link(ehci, (next_uframe >> 3) & (ehci->periodic_size - 1),  				sitd); -		next_uframe += stream->interval << 3; +		next_uframe += stream->uperiod;  	}  	stream->next_uframe = next_uframe & (mod - 1); @@ -2146,9 +2329,9 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,  		ehci_dbg (ehci, "can't get iso stream\n");  		return -ENOMEM;  	} -	if (urb->interval != stream->interval) { +	if (urb->interval != stream->ps.period) {  		ehci_dbg (ehci, "can't change iso interval %d --> %d\n", -			stream->interval, urb->interval); +			stream->ps.period, urb->interval);  		goto done;  	} @@ -2178,10 +2361,14 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,  	if (unlikely(status))  		goto done_not_linked;  	status = iso_stream_schedule(ehci, urb, stream); -	if (status == 0) +	if (likely(status == 0)) {  		sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); -	else +	} else if (status > 0) { +		status = 0; +		ehci_urb_done(ehci, urb, 0); +	} else {  		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); +	}   done_not_linked:  	spin_unlock_irqrestore (&ehci->lock, flags);   done: @@ -2259,7 +2446,8 @@ restart:  				    q.itd->hw_next != EHCI_LIST_END(ehci))  					*hw_p = q.itd->hw_next;  				else -					*hw_p = ehci->dummy->qh_dma; +					*hw_p = cpu_to_hc32(ehci, +							ehci->dummy->qh_dma);  				type = Q_NEXT_TYPE(ehci, q.itd->hw_next);  				wmb();  				modified = itd_complete (ehci, q.itd); @@ -2294,7 +2482,8 @@ restart:  				    q.sitd->hw_next != EHCI_LIST_END(ehci))  					*hw_p = q.sitd->hw_next;  				else -					*hw_p = ehci->dummy->qh_dma; +					*hw_p = cpu_to_hc32(ehci, +							ehci->dummy->qh_dma);  				type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);  				wmb();  				modified = sitd_complete (ehci, q.sitd); diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c index 8a734498079..cf126767386 100644 --- a/drivers/usb/host/ehci-sead3.c +++ b/drivers/usb/host/ehci-sead3.c @@ -126,6 +126,7 @@ static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev)  			  IRQF_SHARED);  	if (ret == 0) {  		platform_set_drvdata(pdev, hcd); +		device_wakeup_enable(hcd->self.controller);  		return ret;  	} diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c index dc899eb2b86..9b9b9f5b016 100644 --- a/drivers/usb/host/ehci-sh.c +++ b/drivers/usb/host/ehci-sh.c @@ -151,6 +151,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)  		dev_err(&pdev->dev, "Failed to add hcd");  		goto fail_add_hcd;  	} +	device_wakeup_enable(hcd->self.controller);  	priv->hcd = hcd;  	platform_set_drvdata(pdev, priv); diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index 1cf0adba3fc..1d59958ad0c 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -81,10 +81,9 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)  	 * 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 = &pdev->dev.coherent_dma_mask; -	if (!pdev->dev.coherent_dma_mask) -		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (retval) +		goto fail;  	usbh_clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(usbh_clk)) { @@ -107,16 +106,9 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)  	hcd->rsrc_start = res->start;  	hcd->rsrc_len = resource_size(res); -	if (!devm_request_mem_region(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len, -				driver->description)) { -		retval = -EBUSY; -		goto err_put_hcd; -	} - -	hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len); -	if (hcd->regs == NULL) { -		dev_dbg(&pdev->dev, "error mapping memory\n"); -		retval = -ENOMEM; +	hcd->regs = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(hcd->regs)) { +		retval = PTR_ERR(hcd->regs);  		goto err_put_hcd;  	} @@ -131,6 +123,7 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)  	if (retval)  		goto err_stop_ehci; +	device_wakeup_enable(hcd->self.controller);  	return retval;  err_stop_ehci: diff --git a/drivers/usb/host/ehci-sysfs.c b/drivers/usb/host/ehci-sysfs.c index 14ced00ba22..f6459dfb6f5 100644 --- a/drivers/usb/host/ehci-sysfs.c +++ b/drivers/usb/host/ehci-sysfs.c @@ -97,8 +97,7 @@ static ssize_t store_uframe_periodic_max(struct device *dev,  {  	struct ehci_hcd		*ehci;  	unsigned		uframe_periodic_max; -	unsigned		frame, uframe; -	unsigned short		allocated_max; +	unsigned		uframe;  	unsigned long		flags;  	ssize_t			ret; @@ -122,16 +121,14 @@ static ssize_t store_uframe_periodic_max(struct device *dev,  	/*  	 * for request to decrease max periodic bandwidth, we have to check -	 * every microframe in the schedule to see whether the decrease is -	 * possible. +	 * to see whether the decrease is possible.  	 */  	if (uframe_periodic_max < ehci->uframe_periodic_max) { -		allocated_max = 0; +		u8		allocated_max = 0; -		for (frame = 0; frame < ehci->periodic_size; ++frame) -			for (uframe = 0; uframe < 7; ++uframe) -				allocated_max = max(allocated_max, -						    periodic_usecs (ehci, frame, uframe)); +		for (uframe = 0; uframe < EHCI_BANDWIDTH_SIZE; ++uframe) +			allocated_max = max(allocated_max, +					ehci->bandwidth[uframe]);  		if (allocated_max > uframe_periodic_max) {  			ehci_info(ehci, diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 78fa76da332..6fdcb8ad229 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -17,7 +17,6 @@   */  #include <linux/clk.h> -#include <linux/clk/tegra.h>  #include <linux/dma-mapping.h>  #include <linux/err.h>  #include <linux/gpio.h> @@ -29,6 +28,7 @@  #include <linux/of_gpio.h>  #include <linux/platform_device.h>  #include <linux/pm_runtime.h> +#include <linux/reset.h>  #include <linux/slab.h>  #include <linux/usb/ehci_def.h>  #include <linux/usb/tegra_usb_phy.h> @@ -38,10 +38,6 @@  #include "ehci.h" -#define TEGRA_USB_BASE			0xC5000000 -#define TEGRA_USB2_BASE			0xC5004000 -#define TEGRA_USB3_BASE			0xC5008000 -  #define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)  #define TEGRA_USB_DMA_ALIGN 32 @@ -55,13 +51,10 @@ struct tegra_ehci_soc_config {  	bool has_hostpc;  }; -static int (*orig_hub_control)(struct usb_hcd *hcd, -				u16 typeReq, u16 wValue, u16 wIndex, -				char *buf, u16 wLength); -  struct tegra_ehci_hcd {  	struct tegra_usb_phy *phy;  	struct clk *clk; +	struct reset_control *rst;  	int port_resuming;  	bool needs_double_reset;  	enum tegra_usb_phy_port_speed port_speed; @@ -239,7 +232,7 @@ static int tegra_ehci_hub_control(  	spin_unlock_irqrestore(&ehci->lock, flags);  	/* Handle the hub control events here */ -	return orig_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); +	return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);  done:  	spin_unlock_irqrestore(&ehci->lock, flags); @@ -362,10 +355,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)  	 * 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 = &pdev->dev.coherent_dma_mask; -	if (!pdev->dev.coherent_dma_mask) -		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (err) +		return err;  	hcd = usb_create_hcd(&tegra_ehci_hc_driver, &pdev->dev,  					dev_name(&pdev->dev)); @@ -386,13 +378,20 @@ static int tegra_ehci_probe(struct platform_device *pdev)  		goto cleanup_hcd_create;  	} +	tegra->rst = devm_reset_control_get(&pdev->dev, "usb"); +	if (IS_ERR(tegra->rst)) { +		dev_err(&pdev->dev, "Can't get ehci reset\n"); +		err = PTR_ERR(tegra->rst); +		goto cleanup_hcd_create; +	} +  	err = clk_prepare_enable(tegra->clk);  	if (err) -		goto cleanup_clk_get; +		goto cleanup_hcd_create; -	tegra_periph_reset_assert(tegra->clk); +	reset_control_assert(tegra->rst);  	udelay(1); -	tegra_periph_reset_deassert(tegra->clk); +	reset_control_deassert(tegra->rst);  	u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0);  	if (IS_ERR(u_phy)) { @@ -412,10 +411,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)  	}  	hcd->rsrc_start = res->start;  	hcd->rsrc_len = resource_size(res); -	hcd->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); -	if (!hcd->regs) { -		dev_err(&pdev->dev, "Failed to remap I/O memory\n"); -		err = -ENOMEM; +	hcd->regs = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(hcd->regs)) { +		err = PTR_ERR(hcd->regs);  		goto cleanup_clk_en;  	}  	ehci->caps = hcd->regs + 0x100; @@ -456,6 +454,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)  		dev_err(&pdev->dev, "Failed to add USB HCD\n");  		goto cleanup_otg_set_host;  	} +	device_wakeup_enable(hcd->self.controller);  	return err; @@ -465,8 +464,6 @@ cleanup_phy:  	usb_phy_shutdown(hcd->phy);  cleanup_clk_en:  	clk_disable_unprepare(tegra->clk); -cleanup_clk_get: -	clk_put(tegra->clk);  cleanup_hcd_create:  	usb_put_hcd(hcd);  	return err; @@ -507,8 +504,31 @@ static struct platform_driver tegra_ehci_driver = {  	}  }; +static int tegra_ehci_reset(struct usb_hcd *hcd) +{ +	struct ehci_hcd *ehci = hcd_to_ehci(hcd); +	int retval; +	int txfifothresh; + +	retval = ehci_setup(hcd); +	if (retval) +		return retval; + +	/* +	 * We should really pull this value out of tegra_ehci_soc_config, but +	 * to avoid needing access to it, make use of the fact that Tegra20 is +	 * the only one so far that needs a value of 10, and Tegra20 is the +	 * only one which doesn't set has_hostpc. +	 */ +	txfifothresh = ehci->has_hostpc ? 0x10 : 10; +	ehci_writel(ehci, txfifothresh << 16, &ehci->regs->txfill_tuning); + +	return 0; +} +  static const struct ehci_driver_overrides tegra_overrides __initconst = {  	.extra_priv_size	= sizeof(struct tegra_ehci_hcd), +	.reset			= tegra_ehci_reset,  };  static int __init ehci_tegra_init(void) @@ -529,8 +549,6 @@ static int __init ehci_tegra_init(void)  	 * too easy.  	 */ -	orig_hub_control = tegra_ehci_hc_driver.hub_control; -  	tegra_ehci_hc_driver.map_urb_for_dma = tegra_ehci_map_urb_for_dma;  	tegra_ehci_hc_driver.unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma;  	tegra_ehci_hc_driver.hub_control = tegra_ehci_hub_control; diff --git a/drivers/usb/host/ehci-tilegx.c b/drivers/usb/host/ehci-tilegx.c index 67026ffbf9a..0d247673c3c 100644 --- a/drivers/usb/host/ehci-tilegx.c +++ b/drivers/usb/host/ehci-tilegx.c @@ -142,8 +142,8 @@ static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev)  	ehci->hcs_params = readl(&ehci->caps->hcs_params);  	/* Create our IRQs and register them. */ -	pdata->irq = create_irq(); -	if (pdata->irq < 0) { +	pdata->irq = irq_alloc_hwirq(-1); +	if (!pdata->irq) {  		ret = -ENXIO;  		goto err_no_irq;  	} @@ -170,11 +170,12 @@ static int ehci_hcd_tilegx_drv_probe(struct platform_device *pdev)  	ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED);  	if (ret == 0) {  		platform_set_drvdata(pdev, hcd); +		device_wakeup_enable(hcd->self.controller);  		return ret;  	}  err_have_irq: -	destroy_irq(pdata->irq); +	irq_free_hwirq(pdata->irq);  err_no_irq:  	tilegx_stop_ehc();  	usb_put_hcd(hcd); @@ -192,7 +193,7 @@ static int ehci_hcd_tilegx_drv_remove(struct platform_device *pdev)  	usb_put_hcd(hcd);  	tilegx_stop_ehc();  	gxio_usb_host_destroy(&pdata->usb_ctx); -	destroy_irq(pdata->irq); +	irq_free_hwirq(pdata->irq);  	return 0;  } diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c index 1c370dfbee0..a9303aff125 100644 --- a/drivers/usb/host/ehci-w90x900.c +++ b/drivers/usb/host/ehci-w90x900.c @@ -11,13 +11,28 @@   *   */ +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h>  #include <linux/platform_device.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ehci.h"  /* enable phy0 and phy1 for w90p910 */  #define	ENPHY		(0x01<<8)  #define PHY0_CTR	(0xA4)  #define PHY1_CTR	(0xA8) +#define DRIVER_DESC "EHCI w90x900 driver" + +static const char hcd_name[] = "ehci-w90x900 "; + +static struct hc_driver __read_mostly ehci_w90x900_hc_driver; +  static int usb_w90x900_probe(const struct hc_driver *driver,  		      struct platform_device *pdev)  { @@ -43,17 +58,12 @@ static int usb_w90x900_probe(const struct hc_driver *driver,  	hcd->rsrc_start = res->start;  	hcd->rsrc_len = resource_size(res); -	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { -		retval = -EBUSY; +	hcd->regs = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(hcd->regs)) { +		retval = PTR_ERR(hcd->regs);  		goto err2;  	} -	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); -	if (hcd->regs == NULL) { -		retval = -EFAULT; -		goto err3; -	} -  	ehci = hcd_to_ehci(hcd);  	ehci->caps = hcd->regs;  	ehci->regs = hcd->regs + @@ -73,80 +83,27 @@ static int usb_w90x900_probe(const struct hc_driver *driver,  	irq = platform_get_irq(pdev, 0);  	if (irq < 0) -		goto err4; +		goto err2;  	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (retval != 0) -		goto err4; +		goto err2; +	device_wakeup_enable(hcd->self.controller);  	return retval; -err4: -	iounmap(hcd->regs); -err3: -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  err2:  	usb_put_hcd(hcd);  err1:  	return retval;  } -static -void usb_w90x900_remove(struct usb_hcd *hcd, struct platform_device *pdev) +static void usb_w90x900_remove(struct usb_hcd *hcd, +			struct platform_device *pdev)  {  	usb_remove_hcd(hcd); -	iounmap(hcd->regs); -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	usb_put_hcd(hcd);  } -static const struct hc_driver ehci_w90x900_hc_driver = { -	.description = hcd_name, -	.product_desc = "Nuvoton w90x900 EHCI Host Controller", -	.hcd_priv_size = sizeof(struct ehci_hcd), - -	/* -	 * generic hardware linkage -	 */ -	.irq = ehci_irq, -	.flags = HCD_USB2|HCD_MEMORY|HCD_BH, - -	/* -	 * 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, -#ifdef	CONFIG_PM -	.bus_suspend = ehci_bus_suspend, -	.bus_resume = ehci_bus_resume, -#endif -	.relinquish_port	= ehci_relinquish_port, -	.port_handed_over	= ehci_port_handed_over, - -	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -}; -  static int ehci_w90x900_probe(struct platform_device *pdev)  {  	if (usb_disabled()) @@ -173,7 +130,25 @@ static struct platform_driver ehci_hcd_w90x900_driver = {  	},  }; +static int __init ehci_w90X900_init(void) +{ +	if (usb_disabled()) +		return -ENODEV; + +	pr_info("%s: " DRIVER_DESC "\n", hcd_name); + +	ehci_init_driver(&ehci_w90x900_hc_driver, NULL); +	return platform_driver_register(&ehci_hcd_w90x900_driver); +} +module_init(ehci_w90X900_init); + +static void __exit ehci_w90X900_cleanup(void) +{ +	platform_driver_unregister(&ehci_hcd_w90x900_driver); +} +module_exit(ehci_w90X900_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); -MODULE_DESCRIPTION("w90p910 usb ehci driver!"); -MODULE_LICENSE("GPL");  MODULE_ALIAS("platform:w90p910-ehci"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c index 95979f9f438..fe57710753e 100644 --- a/drivers/usb/host/ehci-xilinx-of.c +++ b/drivers/usb/host/ehci-xilinx-of.c @@ -155,7 +155,8 @@ static int ehci_hcd_xilinx_of_probe(struct platform_device *op)  	irq = irq_of_parse_and_map(dn, 0);  	if (!irq) { -		printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); +		dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n", +			__FILE__);  		rv = -EBUSY;  		goto err_irq;  	} @@ -191,8 +192,10 @@ static int ehci_hcd_xilinx_of_probe(struct platform_device *op)  	ehci->caps = hcd->regs + 0x100;  	rv = usb_add_hcd(hcd, irq, 0); -	if (rv == 0) +	if (rv == 0) { +		device_wakeup_enable(hcd->self.controller);  		return 0; +	}  err_irq:  	usb_put_hcd(hcd); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 291db7d09f2..eee228a26a0 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -38,7 +38,7 @@ typedef __u16 __bitwise __hc16;  #endif  /* statistics can be kept for tuning/monitoring */ -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#ifdef CONFIG_DYNAMIC_DEBUG  #define EHCI_STATS  #endif @@ -54,6 +54,28 @@ struct ehci_stats {  	unsigned long		unlink;  }; +/* + * Scheduling and budgeting information for periodic transfers, for both + * high-speed devices and full/low-speed devices lying behind a TT. + */ +struct ehci_per_sched { +	struct usb_device	*udev;		/* access to the TT */ +	struct usb_host_endpoint *ep; +	struct list_head	ps_list;	/* node on ehci_tt's ps_list */ +	u16			tt_usecs;	/* time on the FS/LS bus */ +	u16			cs_mask;	/* C-mask and S-mask bytes */ +	u16			period;		/* actual period in frames */ +	u16			phase;		/* actual phase, frame part */ +	u8			bw_phase;	/* same, for bandwidth +						   reservation */ +	u8			phase_uf;	/* uframe part of the phase */ +	u8			usecs, c_usecs;	/* times on the HS bus */ +	u8			bw_uperiod;	/* period in microframes, for +						   bandwidth reservation */ +	u8			bw_period;	/* same, in frames */ +}; +#define NO_FRAME	29999			/* frame not assigned yet */ +  /* ehci_hcd->lock guards shared data against other CPUs:   *   ehci_hcd:	async, unlink, periodic (and shadow), ...   *   usb_host_endpoint: hcpriv @@ -203,6 +225,7 @@ struct ehci_hcd {			/* one per controller */  	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 */ +	unsigned		imx28_write_fix:1; /* For Freescale i.MX28 */  	/* required for usb32 quirk */  	#define OHCI_CTRL_HCFS          (3 << 6) @@ -226,10 +249,19 @@ struct ehci_hcd {			/* one per controller */  #endif  	/* debug files */ -#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG) +#ifdef CONFIG_DYNAMIC_DEBUG  	struct dentry		*debug_dir;  #endif +	/* bandwidth usage */ +#define EHCI_BANDWIDTH_SIZE	64 +#define EHCI_BANDWIDTH_FRAMES	(EHCI_BANDWIDTH_SIZE >> 3) +	u8			bandwidth[EHCI_BANDWIDTH_SIZE]; +						/* us allocated per uframe */ +	u8			tt_budget[EHCI_BANDWIDTH_SIZE]; +						/* us budgeted per uframe */ +	struct list_head	tt_list; +  	/* platform-specific data -- must come last */  	unsigned long		priv[0] __aligned(sizeof(s64));  }; @@ -385,6 +417,7 @@ struct ehci_qh {  	struct list_head	intr_node;	/* list of intr QHs */  	struct ehci_qtd		*dummy;  	struct list_head	unlink_node; +	struct ehci_per_sched	ps;		/* scheduling info */  	unsigned		unlink_cycle; @@ -398,16 +431,8 @@ struct ehci_qh {  	u8			xacterrs;	/* XactErr retry counter */  #define	QH_XACTERR_MAX		32		/* XactErr retry limit */ -	/* periodic schedule info */ -	u8			usecs;		/* intr bandwidth */  	u8			gap_uf;		/* uframes split/csplit gap */ -	u8			c_usecs;	/* ... split completion bw */ -	u16			tt_usecs;	/* tt downstream bandwidth */ -	unsigned short		period;		/* polling interval */ -	unsigned short		start;		/* where polling starts */ -#define NO_FRAME ((unsigned short)~0)			/* pick new start */ -	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; @@ -434,6 +459,7 @@ struct ehci_iso_packet {  struct ehci_iso_sched {  	struct list_head	td_list;  	unsigned		span; +	unsigned		first_packet;  	struct ehci_iso_packet	packet [0];  }; @@ -449,22 +475,17 @@ struct ehci_iso_stream {  	u8			highspeed;  	struct list_head	td_list;	/* queued itds/sitds */  	struct list_head	free_list;	/* list of unused itds/sitds */ -	struct usb_device	*udev; -	struct usb_host_endpoint *ep;  	/* output of (re)scheduling */ -	int			next_uframe; +	struct ehci_per_sched	ps;		/* scheduling info */ +	unsigned		next_uframe;  	__hc32			splits;  	/* the rest is derived from the endpoint descriptor, -	 * trusting urb->interval == f(epdesc->bInterval) and  	 * including the extra info for hw_bufp[0..2]  	 */ -	u8			usecs, c_usecs; -	u16			interval; -	u16			tt_usecs; +	u16			uperiod;	/* period in uframes */  	u16			maxp; -	u16			raw_mask;  	unsigned		bandwidth;  	/* This is used to initialize iTD's hw_bufp fields */ @@ -579,6 +600,35 @@ struct ehci_fstn {  /*-------------------------------------------------------------------------*/ +/* + * USB-2.0 Specification Sections 11.14 and 11.18 + * Scheduling and budgeting split transactions using TTs + * + * A hub can have a single TT for all its ports, or multiple TTs (one for each + * port).  The bandwidth and budgeting information for the full/low-speed bus + * below each TT is self-contained and independent of the other TTs or the + * high-speed bus. + * + * "Bandwidth" refers to the number of microseconds on the FS/LS bus allocated + * to an interrupt or isochronous endpoint for each frame.  "Budget" refers to + * the best-case estimate of the number of full-speed bytes allocated to an + * endpoint for each microframe within an allocated frame. + * + * Removal of an endpoint invalidates a TT's budget.  Instead of trying to + * keep an up-to-date record, we recompute the budget when it is needed. + */ + +struct ehci_tt { +	u16			bandwidth[EHCI_BANDWIDTH_FRAMES]; + +	struct list_head	tt_list;	/* List of all ehci_tt's */ +	struct list_head	ps_list;	/* Items using this TT */ +	struct usb_tt		*usb_tt; +	int			tt_port;	/* TT port number */ +}; + +/*-------------------------------------------------------------------------*/ +  /* Prepare the PORTSC wakeup flags during controller suspend/resume */  #define ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup)	\ @@ -679,6 +729,18 @@ static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,  #endif  } +#ifdef CONFIG_SOC_IMX28 +static inline void imx28_ehci_writel(const unsigned int val, +		volatile __u32 __iomem *addr) +{ +	__asm__ ("swp %0, %0, [%1]" : : "r"(val), "r"(addr)); +} +#else +static inline void imx28_ehci_writel(const unsigned int val, +		volatile __u32 __iomem *addr) +{ +} +#endif  static inline void ehci_writel(const struct ehci_hcd *ehci,  		const unsigned int val, __u32 __iomem *regs)  { @@ -687,7 +749,10 @@ static inline void ehci_writel(const struct ehci_hcd *ehci,  		writel_be(val, regs) :  		writel(val, regs);  #else -	writel(val, regs); +	if (ehci->imx28_write_fix) +		imx28_ehci_writel(val, regs); +	else +		writel(val, regs);  #endif  } @@ -783,9 +848,9 @@ static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)  	dev_warn(ehci_to_hcd(ehci)->self.controller , fmt , ## args) -#if !defined(DEBUG) && !defined(CONFIG_DYNAMIC_DEBUG) +#ifndef CONFIG_DYNAMIC_DEBUG  #define STUB_DEBUG_FILES -#endif	/* !DEBUG && !CONFIG_DYNAMIC_DEBUG */ +#endif  /*-------------------------------------------------------------------------*/ @@ -807,4 +872,7 @@ extern int	ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);  extern int	ehci_resume(struct usb_hcd *hcd, bool hibernated);  #endif	/* CONFIG_PM */ +extern int	ehci_hub_control(struct usb_hcd	*hcd, u16 typeReq, u16 wValue, +				 u16 wIndex, char *buf, u16 wLength); +  #endif /* __LINUX_EHCI_HCD_H */ diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c index 0b46542591f..1cf68eaf2ed 100644 --- a/drivers/usb/host/fhci-hcd.c +++ b/drivers/usb/host/fhci-hcd.c @@ -26,6 +26,8 @@  #include <linux/io.h>  #include <linux/usb.h>  #include <linux/usb/hcd.h> +#include <linux/of_address.h> +#include <linux/of_irq.h>  #include <linux/of_platform.h>  #include <linux/of_gpio.h>  #include <linux/slab.h> @@ -752,6 +754,8 @@ static int of_fhci_probe(struct platform_device *ofdev)  	if (ret < 0)  		goto err_add_hcd; +	device_wakeup_enable(hcd->self.controller); +  	fhci_dfs_create(fhci);  	return 0; diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index fce13bcc4a3..98a89d16cc3 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -56,12 +56,9 @@  static const char	hcd_name[] = "fotg210_hcd"; -#undef VERBOSE_DEBUG  #undef FOTG210_URB_TRACE -#ifdef DEBUG  #define FOTG210_STATS -#endif  /* magic numbers that can affect system performance */  #define	FOTG210_TUNE_CERR		3 /* 0-3 qtd retries; 0 == don't stop */ @@ -107,14 +104,6 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");  #define fotg210_warn(fotg210, fmt, args...) \  	dev_warn(fotg210_to_hcd(fotg210)->self.controller , fmt , ## args) -#ifdef VERBOSE_DEBUG -#	define fotg210_vdbg fotg210_dbg -#else -	static inline void fotg210_vdbg(struct fotg210_hcd *fotg210, ...) {} -#endif - -#ifdef	DEBUG -  /* check the values in the HCSPARAMS register   * (host controller _Structural_ parameters)   * see EHCI spec, Table 2-4 for each value @@ -129,13 +118,6 @@ static void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label)  		HCS_N_PORTS(params)  		);  } -#else - -static inline void dbg_hcs_params(struct fotg210_hcd *fotg210, char *label) {} - -#endif - -#ifdef	DEBUG  /* check the values in the HCCPARAMS register   * (host controller _Capability_ parameters) @@ -152,13 +134,6 @@ static void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label)  		HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",  		HCC_CANPARK(params) ? " park" : "");  } -#else - -static inline void dbg_hcc_params(struct fotg210_hcd *fotg210, char *label) {} - -#endif - -#ifdef	DEBUG  static void __maybe_unused  dbg_qtd(const char *label, struct fotg210_hcd *fotg210, struct fotg210_qtd *qtd) @@ -272,8 +247,8 @@ dbg_command_buf(char *buf, unsigned len, const char *label, u32 command)  		);  } -static int -dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status) +static char +*dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)  {  	char	*sig; @@ -293,7 +268,7 @@ dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)  		break;  	} -	return scnprintf(buf, len, +	scnprintf(buf, len,  		"%s%sport:%d status %06x %d "  		"sig=%s%s%s%s%s%s%s%s",  		label, label[0] ? " " : "", port, status, @@ -306,31 +281,9 @@ dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)  		(status & PORT_PE) ? " PE" : "",  		(status & PORT_CSC) ? " CSC" : "",  		(status & PORT_CONNECT) ? " CONNECT" : ""); +	return buf;  } -#else -static inline void __maybe_unused -dbg_qh(char *label, struct fotg210_hcd *fotg210, struct fotg210_qh *qh) -{} - -static inline int __maybe_unused -dbg_status_buf(char *buf, unsigned len, const char *label, u32 status) -{ return 0; } - -static inline int __maybe_unused -dbg_command_buf(char *buf, unsigned len, const char *label, u32 command) -{ return 0; } - -static inline int __maybe_unused -dbg_intr_buf(char *buf, unsigned len, const char *label, u32 enable) -{ return 0; } - -static inline int __maybe_unused -dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status) -{ return 0; } - -#endif	/* DEBUG */ -  /* functions have the "wrong" filename when they're output... */  #define dbg_status(fotg210, label, status) { \  	char _buf[80]; \ @@ -346,19 +299,11 @@ dbg_port_buf(char *buf, unsigned len, const char *label, int port, u32 status)  #define dbg_port(fotg210, label, port, status) { \  	char _buf[80]; \ -	dbg_port_buf(_buf, sizeof(_buf), label, port, status); \ -	fotg210_dbg(fotg210, "%s\n", _buf); \ +	fotg210_dbg(fotg210, "%s\n", dbg_port_buf(_buf, sizeof(_buf), label, port, status) ); \  }  /*-------------------------------------------------------------------------*/ -#ifdef STUB_DEBUG_FILES - -static inline void create_debug_files(struct fotg210_hcd *bus) { } -static inline void remove_debug_files(struct fotg210_hcd *bus) { } - -#else -  /* troubleshooting help: expose state in debugfs */  static int debug_async_open(struct inode *, struct file *); @@ -412,7 +357,7 @@ struct debug_buffer {  			tmp = 'h'; break; \  		default:		\  			tmp = '?'; break; \ -		}; tmp; }) +		} tmp; })  static inline char token_mark(struct fotg210_hcd *fotg210, __hc32 token)  { @@ -954,7 +899,6 @@ static inline void remove_debug_files(struct fotg210_hcd *fotg210)  	debugfs_remove_recursive(fotg210->debug_dir);  } -#endif /* STUB_DEBUG_FILES */  /*-------------------------------------------------------------------------*/  /* @@ -1398,7 +1342,7 @@ static void fotg210_iaa_watchdog(struct fotg210_hcd *fotg210)  				       &fotg210->regs->status);  		} -		fotg210_vdbg(fotg210, "IAA watchdog: status %x cmd %x\n", +		fotg210_dbg(fotg210, "IAA watchdog: status %x cmd %x\n",  				status, cmd);  		end_unlink_async(fotg210);  	} @@ -1810,10 +1754,8 @@ static int fotg210_hub_control(  		if (test_bit(wIndex, &fotg210->port_c_suspend))  			status |= USB_PORT_STAT_C_SUSPEND << 16; -#ifndef	VERBOSE_DEBUG -	if (status & ~0xffff)	/* only if wPortChange is interesting */ -#endif -		dbg_port(fotg210, "GetStatus", wIndex + 1, temp); +		if (status & ~0xffff)	/* only if wPortChange is interesting */ +			dbg_port(fotg210, "GetStatus", wIndex + 1, temp);  		put_unaligned_le32(status, buf);  		break;  	case SetHubFeature: @@ -1856,7 +1798,7 @@ static int fotg210_hub_control(  			 * which can be fine if this root hub has a  			 * transaction translator built in.  			 */ -			fotg210_vdbg(fotg210, "port %d reset\n", wIndex + 1); +			fotg210_dbg(fotg210, "port %d reset\n", wIndex + 1);  			temp |= PORT_RESET;  			temp &= ~PORT_PE; @@ -2274,13 +2216,12 @@ static void fotg210_clear_tt_buffer(struct fotg210_hcd *fotg210,  	 * Note: this routine is never called for Isochronous transfers.  	 */  	if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) { -#ifdef DEBUG  		struct usb_device *tt = urb->dev->tt->hub;  		dev_dbg(&tt->dev,  			"clear tt buffer port %d, a%d ep%d t%08x\n",  			urb->dev->ttport, urb->dev->devnum,  			usb_pipeendpoint(urb->pipe), token); -#endif /* DEBUG */ +  		if (urb->dev->tt->hub !=  		    fotg210_to_hcd(fotg210)->self.root_hub) {  			if (usb_hub_clear_tt_buffer(urb) == 0) @@ -2341,7 +2282,7 @@ static int qtd_copy_status(  			status = -EPROTO;  		} -		fotg210_vdbg(fotg210, +		fotg210_dbg(fotg210,  			"dev%d ep%d%s qtd token %08x --> status %d\n",  			usb_pipedevice(urb->pipe),  			usb_pipeendpoint(urb->pipe), @@ -3583,11 +3524,9 @@ periodic_usecs(struct fotg210_hcd *fotg210, unsigned frame, unsigned uframe)  			break;  		}  	} -#ifdef	DEBUG  	if (usecs > fotg210->uframe_periodic_max)  		fotg210_err(fotg210, "uframe %d sched overrun: %d usecs\n",  			frame * 8 + uframe, usecs); -#endif  	return usecs;  } @@ -4646,7 +4585,7 @@ static void itd_link_urb(  	if (unlikely(list_empty(&stream->td_list))) {  		fotg210_to_hcd(fotg210)->self.bandwidth_allocated  				+= stream->bandwidth; -		fotg210_vdbg(fotg210, +		fotg210_dbg(fotg210,  			"schedule devp %s ep%d%s-iso period %d start %d.%d\n",  			urb->dev->devpath, stream->bEndpointAddress & 0x0f,  			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", @@ -4779,7 +4718,7 @@ static bool itd_complete(struct fotg210_hcd *fotg210, struct fotg210_itd *itd)  	if (unlikely(list_is_singular(&stream->td_list))) {  		fotg210_to_hcd(fotg210)->self.bandwidth_allocated  				-= stream->bandwidth; -		fotg210_vdbg(fotg210, +		fotg210_dbg(fotg210,  			"deschedule devp %s ep%d%s-iso\n",  			dev->devpath, stream->bEndpointAddress & 0x0f,  			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); @@ -5444,10 +5383,8 @@ static irqreturn_t fotg210_irq(struct usb_hcd *hcd)  	cmd = fotg210_readl(fotg210, &fotg210->regs->command);  	bh = 0; -#ifdef	VERBOSE_DEBUG  	/* unrequested/ignored: Frame List Rollover */  	dbg_status(fotg210, "irq", status); -#endif  	/* INT, ERR, and IAA interrupt rates can be throttled */ @@ -5952,6 +5889,7 @@ static int fotg210_hcd_probe(struct platform_device *pdev)  		dev_err(dev, "failed to add hcd with err %d\n", retval);  		goto fail_add_hcd;  	} +	device_wakeup_enable(hcd->self.controller);  	return retval; @@ -6013,13 +5951,11 @@ static int __init fotg210_hcd_init(void)  		 sizeof(struct fotg210_qh), sizeof(struct fotg210_qtd),  		 sizeof(struct fotg210_itd)); -#ifdef DEBUG  	fotg210_debug_root = debugfs_create_dir("fotg210", usb_debug_root);  	if (!fotg210_debug_root) {  		retval = -ENOENT;  		goto err_debug;  	} -#endif  	retval = platform_driver_register(&fotg210_hcd_driver);  	if (retval < 0) @@ -6028,11 +5964,9 @@ static int __init fotg210_hcd_init(void)  	platform_driver_unregister(&fotg210_hcd_driver);  clean: -#ifdef DEBUG  	debugfs_remove(fotg210_debug_root);  	fotg210_debug_root = NULL;  err_debug: -#endif  	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);  	return retval;  } @@ -6041,9 +5975,7 @@ module_init(fotg210_hcd_init);  static void __exit fotg210_hcd_cleanup(void)  {  	platform_driver_unregister(&fotg210_hcd_driver); -#ifdef DEBUG  	debugfs_remove(fotg210_debug_root); -#endif  	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);  }  module_exit(fotg210_hcd_cleanup); diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h index 8920f9d3256..ac6cd1bfd20 100644 --- a/drivers/usb/host/fotg210.h +++ b/drivers/usb/host/fotg210.h @@ -174,9 +174,7 @@ struct fotg210_hcd {			/* one per controller */  #endif  	/* debug files */ -#ifdef DEBUG  	struct dentry		*debug_dir; -#endif  };  /* convert between an HCD pointer and the corresponding FOTG210_HCD */ @@ -741,10 +739,4 @@ static inline unsigned fotg210_read_frame_index(struct fotg210_hcd *fotg210)  })  /*-------------------------------------------------------------------------*/ -#ifndef DEBUG -#define STUB_DEBUG_FILES -#endif	/* DEBUG */ - -/*-------------------------------------------------------------------------*/ -  #endif /* __LINUX_FOTG210_H */ diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 9e0020d9e4c..9162d1b6c0a 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -24,7 +24,7 @@ struct fsl_usb2_dev_data {  	enum fsl_usb2_operating_modes op_mode;	/* operating mode */  }; -struct fsl_usb2_dev_data dr_mode_data[] = { +static struct fsl_usb2_dev_data dr_mode_data[] = {  	{  		.dr_mode = "host",  		.drivers = { "fsl-ehci", NULL, NULL, }, @@ -42,7 +42,7 @@ struct fsl_usb2_dev_data dr_mode_data[] = {  	},  }; -struct fsl_usb2_dev_data *get_dr_mode_data(struct device_node *np) +static struct fsl_usb2_dev_data *get_dr_mode_data(struct device_node *np)  {  	const unsigned char *prop;  	int i; @@ -75,7 +75,7 @@ static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)  	return FSL_USB2_PHY_NONE;  } -struct platform_device *fsl_usb2_device_register( +static struct platform_device *fsl_usb2_device_register(  					struct platform_device *ofdev,  					struct fsl_usb2_platform_data *pdata,  					const char *name, int id) @@ -261,19 +261,8 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev)  	struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);  	struct clk *clk;  	int err; -	char clk_name[10]; -	int base, clk_num; - -	base = pdev->resource->start & 0xf000; -	if (base == 0x3000) -		clk_num = 1; -	else if (base == 0x4000) -		clk_num = 2; -	else -		return -ENODEV; -	snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num); -	clk = devm_clk_get(pdev->dev.parent, clk_name); +	clk = devm_clk_get(pdev->dev.parent, "ipg");  	if (IS_ERR(clk)) {  		dev_err(&pdev->dev, "failed to get clk\n");  		return PTR_ERR(clk); diff --git a/drivers/usb/host/fusbh200-hcd.c b/drivers/usb/host/fusbh200-hcd.c index 299253c826c..ba9499060f6 100644 --- a/drivers/usb/host/fusbh200-hcd.c +++ b/drivers/usb/host/fusbh200-hcd.c @@ -57,13 +57,8 @@  static const char	hcd_name [] = "fusbh200_hcd"; -#undef VERBOSE_DEBUG  #undef FUSBH200_URB_TRACE -#ifdef DEBUG -#define FUSBH200_STATS -#endif -  /* magic numbers that can affect system performance */  #define	FUSBH200_TUNE_CERR		3	/* 0-3 qtd retries; 0 == don't stop */  #define	FUSBH200_TUNE_RL_HS		4	/* nak throttle; see 4.9 */ @@ -108,14 +103,6 @@ MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");  #define fusbh200_warn(fusbh200, fmt, args...) \  	dev_warn (fusbh200_to_hcd(fusbh200)->self.controller , fmt , ## args ) -#ifdef VERBOSE_DEBUG -#	define fusbh200_vdbg fusbh200_dbg -#else -	static inline void fusbh200_vdbg(struct fusbh200_hcd *fusbh200, ...) {} -#endif - -#ifdef	DEBUG -  /* check the values in the HCSPARAMS register   * (host controller _Structural_ parameters)   * see EHCI spec, Table 2-4 for each value @@ -130,13 +117,6 @@ static void dbg_hcs_params (struct fusbh200_hcd *fusbh200, char *label)  		HCS_N_PORTS (params)  		);  } -#else - -static inline void dbg_hcs_params (struct fusbh200_hcd *fusbh200, char *label) {} - -#endif - -#ifdef	DEBUG  /* check the values in the HCCPARAMS register   * (host controller _Capability_ parameters) @@ -153,13 +133,6 @@ static void dbg_hcc_params (struct fusbh200_hcd *fusbh200, char *label)  		HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",  		HCC_CANPARK(params) ? " park" : "");  } -#else - -static inline void dbg_hcc_params (struct fusbh200_hcd *fusbh200, char *label) {} - -#endif - -#ifdef	DEBUG  static void __maybe_unused  dbg_qtd (const char *label, struct fusbh200_hcd *fusbh200, struct fusbh200_qtd *qtd) @@ -302,29 +275,6 @@ dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)  		(status & PORT_CONNECT) ? " CONNECT" : "");  } -#else -static inline void __maybe_unused -dbg_qh (char *label, struct fusbh200_hcd *fusbh200, struct fusbh200_qh *qh) -{} - -static inline int __maybe_unused -dbg_status_buf (char *buf, unsigned len, const char *label, u32 status) -{ return 0; } - -static inline int __maybe_unused -dbg_command_buf (char *buf, unsigned len, const char *label, u32 command) -{ return 0; } - -static inline int __maybe_unused -dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable) -{ return 0; } - -static inline int __maybe_unused -dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status) -{ return 0; } - -#endif	/* DEBUG */ -  /* functions have the "wrong" filename when they're output... */  #define dbg_status(fusbh200, label, status) { \  	char _buf [80]; \ @@ -346,13 +296,6 @@ dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)  /*-------------------------------------------------------------------------*/ -#ifdef STUB_DEBUG_FILES - -static inline void create_debug_files (struct fusbh200_hcd *bus) { } -static inline void remove_debug_files (struct fusbh200_hcd *bus) { } - -#else -  /* troubleshooting help: expose state in debugfs */  static int debug_async_open(struct inode *, struct file *); @@ -402,7 +345,7 @@ struct debug_buffer {  		case QH_LOW_SPEED:  tmp = 'l'; break; \  		case QH_HIGH_SPEED: tmp = 'h'; break; \  		default: tmp = '?'; break; \ -		}; tmp; }) +		} tmp; })  static inline char token_mark(struct fusbh200_hcd *fusbh200, __hc32 token)  { @@ -775,7 +718,6 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)  		next += temp;  	} -#ifdef FUSBH200_STATS  	temp = scnprintf (next, size,  		"irq normal %ld err %ld iaa %ld (lost %ld)\n",  		fusbh200->stats.normal, fusbh200->stats.error, fusbh200->stats.iaa, @@ -787,7 +729,6 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)  		fusbh200->stats.complete, fusbh200->stats.unlink);  	size -= temp;  	next += temp; -#endif  done:  	spin_unlock_irqrestore (&fusbh200->lock, flags); @@ -928,7 +869,6 @@ static inline void remove_debug_files (struct fusbh200_hcd *fusbh200)  	debugfs_remove_recursive(fusbh200->debug_dir);  } -#endif /* STUB_DEBUG_FILES */  /*-------------------------------------------------------------------------*/  /* @@ -1362,7 +1302,7 @@ static void fusbh200_iaa_watchdog(struct fusbh200_hcd *fusbh200)  			fusbh200_writel(fusbh200, STS_IAA, &fusbh200->regs->status);  		} -		fusbh200_vdbg(fusbh200, "IAA watchdog: status %x cmd %x\n", +		fusbh200_dbg(fusbh200, "IAA watchdog: status %x cmd %x\n",  				status, cmd);  		end_unlink_async(fusbh200);  	} @@ -1769,10 +1709,8 @@ static int fusbh200_hub_control (  		if (test_bit(wIndex, &fusbh200->port_c_suspend))  			status |= USB_PORT_STAT_C_SUSPEND << 16; -#ifndef	VERBOSE_DEBUG -	if (status & ~0xffff)	/* only if wPortChange is interesting */ -#endif -		dbg_port (fusbh200, "GetStatus", wIndex + 1, temp); +		if (status & ~0xffff)	/* only if wPortChange is interesting */ +			dbg_port(fusbh200, "GetStatus", wIndex + 1, temp);  		put_unaligned_le32(status, buf);  		break;  	case SetHubFeature: @@ -1814,7 +1752,7 @@ static int fusbh200_hub_control (  			 * which can be fine if this root hub has a  			 * transaction translator built in.  			 */ -			fusbh200_vdbg (fusbh200, "port %d reset\n", wIndex + 1); +			fusbh200_dbg(fusbh200, "port %d reset\n", wIndex + 1);  			temp |= PORT_RESET;  			temp &= ~PORT_PE; @@ -2230,13 +2168,13 @@ static void fusbh200_clear_tt_buffer(struct fusbh200_hcd *fusbh200, struct fusbh  	 * Note: this routine is never called for Isochronous transfers.  	 */  	if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) { -#ifdef DEBUG  		struct usb_device *tt = urb->dev->tt->hub; +  		dev_dbg(&tt->dev,  			"clear tt buffer port %d, a%d ep%d t%08x\n",  			urb->dev->ttport, urb->dev->devnum,  			usb_pipeendpoint(urb->pipe), token); -#endif /* DEBUG */ +  		if (urb->dev->tt->hub !=  		    fusbh200_to_hcd(fusbh200)->self.root_hub) {  			if (usb_hub_clear_tt_buffer(urb) == 0) @@ -2297,7 +2235,7 @@ static int qtd_copy_status (  			status = -EPROTO;  		} -		fusbh200_vdbg (fusbh200, +		fusbh200_dbg(fusbh200,  			"dev%d ep%d%s qtd token %08x --> status %d\n",  			usb_pipedevice (urb->pipe),  			usb_pipeendpoint (urb->pipe), @@ -3529,11 +3467,9 @@ periodic_usecs (struct fusbh200_hcd *fusbh200, unsigned frame, unsigned uframe)  			break;  		}  	} -#ifdef	DEBUG  	if (usecs > fusbh200->uframe_periodic_max)  		fusbh200_err (fusbh200, "uframe %d sched overrun: %d usecs\n",  			frame * 8 + uframe, usecs); -#endif  	return usecs;  } @@ -4586,7 +4522,7 @@ static void itd_link_urb(  	if (unlikely (list_empty(&stream->td_list))) {  		fusbh200_to_hcd(fusbh200)->self.bandwidth_allocated  				+= stream->bandwidth; -		fusbh200_vdbg (fusbh200, +		fusbh200_dbg(fusbh200,  			"schedule devp %s ep%d%s-iso period %d start %d.%d\n",  			urb->dev->devpath, stream->bEndpointAddress & 0x0f,  			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", @@ -4717,7 +4653,7 @@ static bool itd_complete(struct fusbh200_hcd *fusbh200, struct fusbh200_itd *itd  	if (unlikely(list_is_singular(&stream->td_list))) {  		fusbh200_to_hcd(fusbh200)->self.bandwidth_allocated  				-= stream->bandwidth; -		fusbh200_vdbg (fusbh200, +		fusbh200_dbg(fusbh200,  			"deschedule devp %s ep%d%s-iso\n",  			dev->devpath, stream->bEndpointAddress & 0x0f,  			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); @@ -5115,13 +5051,11 @@ static void fusbh200_stop (struct usb_hcd *hcd)  	spin_unlock_irq (&fusbh200->lock);  	fusbh200_mem_cleanup (fusbh200); -#ifdef	FUSBH200_STATS  	fusbh200_dbg(fusbh200, "irq normal %ld err %ld iaa %ld (lost %ld)\n",  		fusbh200->stats.normal, fusbh200->stats.error, fusbh200->stats.iaa,  		fusbh200->stats.lost_iaa);  	fusbh200_dbg (fusbh200, "complete %ld unlink %ld\n",  		fusbh200->stats.complete, fusbh200->stats.unlink); -#endif  	dbg_status (fusbh200, "fusbh200_stop completed",  		    fusbh200_readl(fusbh200, &fusbh200->regs->status)); @@ -5365,13 +5299,6 @@ static irqreturn_t fusbh200_irq (struct usb_hcd *hcd)  	cmd = fusbh200_readl(fusbh200, &fusbh200->regs->command);  	bh = 0; -#ifdef	VERBOSE_DEBUG -	/* unrequested/ignored: Frame List Rollover */ -	dbg_status (fusbh200, "irq", status); -#endif - -	/* INT, ERR, and IAA interrupt rates can be throttled */ -  	/* normal [4.15.1.2] or error [4.15.1.1] completion */  	if (likely ((status & (STS_INT|STS_ERR)) != 0)) {  		if (likely ((status & STS_ERR) == 0)) @@ -5871,6 +5798,7 @@ static int fusbh200_hcd_probe(struct platform_device *pdev)  		dev_err(dev, "failed to add hcd with err %d\n", retval);  		goto fail_add_hcd;  	} +	device_wakeup_enable(hcd->self.controller);  	return retval; @@ -5936,13 +5864,11 @@ static int __init fusbh200_hcd_init(void)  		 sizeof(struct fusbh200_qh), sizeof(struct fusbh200_qtd),  		 sizeof(struct fusbh200_itd)); -#ifdef DEBUG  	fusbh200_debug_root = debugfs_create_dir("fusbh200", usb_debug_root);  	if (!fusbh200_debug_root) {  		retval = -ENOENT;  		goto err_debug;  	} -#endif  	retval = platform_driver_register(&fusbh200_hcd_fusbh200_driver);  	if (retval < 0) @@ -5951,11 +5877,9 @@ static int __init fusbh200_hcd_init(void)  	platform_driver_unregister(&fusbh200_hcd_fusbh200_driver);  clean: -#ifdef DEBUG  	debugfs_remove(fusbh200_debug_root);  	fusbh200_debug_root = NULL;  err_debug: -#endif  	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);  	return retval;  } @@ -5964,9 +5888,7 @@ module_init(fusbh200_hcd_init);  static void __exit fusbh200_hcd_cleanup(void)  {  	platform_driver_unregister(&fusbh200_hcd_fusbh200_driver); -#ifdef DEBUG  	debugfs_remove(fusbh200_debug_root); -#endif  	clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);  }  module_exit(fusbh200_hcd_cleanup); diff --git a/drivers/usb/host/fusbh200.h b/drivers/usb/host/fusbh200.h index 797c9e85527..6b719e066c3 100644 --- a/drivers/usb/host/fusbh200.h +++ b/drivers/usb/host/fusbh200.h @@ -165,17 +165,11 @@ struct fusbh200_hcd {			/* one per controller */  	u8			sbrn;		/* packed release number */  	/* irq statistics */ -#ifdef FUSBH200_STATS  	struct fusbh200_stats	stats;  #	define COUNT(x) do { (x)++; } while (0) -#else -#	define COUNT(x) do {} while (0) -#endif  	/* debug files */ -#ifdef DEBUG  	struct dentry		*debug_dir; -#endif  };  /* convert between an HCD pointer and the corresponding FUSBH200_HCD */ @@ -734,10 +728,4 @@ static inline unsigned fusbh200_read_frame_index(struct fusbh200_hcd *fusbh200)  })  /*-------------------------------------------------------------------------*/ -#ifndef DEBUG -#define STUB_DEBUG_FILES -#endif	/* DEBUG */ - -/*-------------------------------------------------------------------------*/ -  #endif /* __LINUX_FUSBH200_H */ diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c index 5b86ffb88f1..d0d8fadf706 100644 --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c @@ -54,7 +54,6 @@   *                      DWA).   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/workqueue.h> @@ -86,7 +85,7 @@ static int __hwahc_set_cluster_id(struct hwahc *hwahc, u8 cluster_id)  			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  			cluster_id,  			wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, -			NULL, 0, 1000 /* FIXME: arbitrary */); +			NULL, 0, USB_CTRL_SET_TIMEOUT);  	if (result < 0)  		dev_err(dev, "Cannot set WUSB Cluster ID to 0x%02x: %d\n",  			cluster_id, result); @@ -106,7 +105,7 @@ static int __hwahc_op_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)  			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  			interval << 8 | slots,  			wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, -			NULL, 0, 1000 /* FIXME: arbitrary */); +			NULL, 0, USB_CTRL_SET_TIMEOUT);  }  /* @@ -199,10 +198,14 @@ static int hwahc_op_get_frame_number(struct usb_hcd *usb_hcd)  {  	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);  	struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); +	struct wahc *wa = &hwahc->wa; -	dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__, -		usb_hcd, hwahc); -	return -ENOSYS; +	/* +	 * We cannot query the HWA for the WUSB time since that requires sending +	 * a synchronous URB and this function can be called in_interrupt. +	 * Instead, query the USB frame number for our parent and use that. +	 */ +	return usb_get_current_frame_number(wa->usb_dev);  }  static int hwahc_op_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb, @@ -220,7 +223,7 @@ static int hwahc_op_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb,  	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);  	struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); -	return wa_urb_dequeue(&hwahc->wa, urb); +	return wa_urb_dequeue(&hwahc->wa, urb, status);  }  /* @@ -258,8 +261,44 @@ static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc)  		dev_err(dev, "cannot listen to notifications: %d\n", result);  		goto error_stop;  	} +	/* +	 * If WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS is set, +	 *  disable transfer notifications. +	 */ +	if (hwahc->wa.quirks & +		WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS) { +		struct usb_host_interface *cur_altsetting = +			hwahc->wa.usb_iface->cur_altsetting; + +		result = usb_control_msg(hwahc->wa.usb_dev, +				usb_sndctrlpipe(hwahc->wa.usb_dev, 0), +				WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS, +				USB_DIR_OUT | USB_TYPE_VENDOR | +					USB_RECIP_INTERFACE, +				WA_REQ_ALEREON_FEATURE_SET, +				cur_altsetting->desc.bInterfaceNumber, +				NULL, 0, +				USB_CTRL_SET_TIMEOUT); +		/* +		 * If we successfully sent the control message, start DTI here +		 * because no transfer notifications will be received which is +		 * where DTI is normally started. +		 */ +		if (result == 0) +			result = wa_dti_start(&hwahc->wa); +		else +			result = 0;	/* OK.  Continue normally. */ + +		if (result < 0) { +			dev_err(dev, "cannot start DTI: %d\n", result); +			goto error_dti_start; +		} +	} +  	return result; +error_dti_start: +	wa_nep_disarm(&hwahc->wa);  error_stop:  	__wa_clear_feature(&hwahc->wa, WA_ENABLE);  	return result; @@ -277,7 +316,7 @@ static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc, int delay)  			      USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  			      delay * 1000,  			      iface_no, -			      NULL, 0, 1000 /* FIXME: arbitrary */); +			      NULL, 0, USB_CTRL_SET_TIMEOUT);  	if (ret == 0)  		msleep(delay); @@ -306,7 +345,7 @@ static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index,  			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  			stream_index,  			wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, -			NULL, 0, 1000 /* FIXME: arbitrary */); +			NULL, 0, USB_CTRL_SET_TIMEOUT);  	if (result < 0) {  		dev_err(dev, "Cannot set WUSB stream index: %d\n", result);  		goto out; @@ -317,7 +356,7 @@ static int __hwahc_op_bwa_set(struct wusbhc *wusbhc, s8 stream_index,  			WUSB_REQ_SET_WUSB_MAS,  			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  			0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, -			mas_le, 32, 1000 /* FIXME: arbitrary */); +			mas_le, 32, USB_CTRL_SET_TIMEOUT);  	if (result < 0)  		dev_err(dev, "Cannot set WUSB MAS allocation: %d\n", result);  out: @@ -351,7 +390,7 @@ static int __hwahc_op_mmcie_add(struct wusbhc *wusbhc, u8 interval,  			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  			interval << 8 | repeat_cnt,  			handle << 8 | iface_no, -			wuie, wuie->bLength, 1000 /* FIXME: arbitrary */); +			wuie, wuie->bLength, USB_CTRL_SET_TIMEOUT);  }  /* @@ -368,7 +407,7 @@ static int __hwahc_op_mmcie_rm(struct wusbhc *wusbhc, u8 handle)  			WUSB_REQ_REMOVE_MMC_IE,  			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  			0, handle << 8 | iface_no, -			NULL, 0, 1000 /* FIXME: arbitrary */); +			NULL, 0, USB_CTRL_SET_TIMEOUT);  }  /* @@ -411,7 +450,7 @@ static int __hwahc_op_dev_info_set(struct wusbhc *wusbhc,  			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  			0, wusb_dev->port_idx << 8 | iface_no,  			dev_info, sizeof(struct hwa_dev_info), -			1000 /* FIXME: arbitrary */); +			USB_CTRL_SET_TIMEOUT);  	kfree(dev_info);  	return ret;  } @@ -451,7 +490,7 @@ static int __hwahc_dev_set_key(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,  			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  			USB_DT_KEY << 8 | key_idx,  			port_idx << 8 | iface_no, -			keyd, keyd_len, 1000 /* FIXME: arbitrary */); +			keyd, keyd_len, USB_CTRL_SET_TIMEOUT);  	kzfree(keyd); /* clear keys etc. */  	return result; @@ -493,7 +532,7 @@ static int __hwahc_op_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,  			USB_REQ_SET_ENCRYPTION,  			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  			encryption_value, port_idx << 8 | iface_no, -			NULL, 0, 1000 /* FIXME: arbitrary */); +			NULL, 0, USB_CTRL_SET_TIMEOUT);  	if (result < 0)  		dev_err(wusbhc->dev, "Can't set host's WUSB encryption for "  			"port index %u to %s (value %d): %d\n", port_idx, @@ -566,14 +605,10 @@ found:  		goto error;  	}  	wa->wa_descr = wa_descr = (struct usb_wa_descriptor *) hdr; -	/* Make LE fields CPU order */ -	wa_descr->bcdWAVersion = le16_to_cpu(wa_descr->bcdWAVersion); -	wa_descr->wNumRPipes = le16_to_cpu(wa_descr->wNumRPipes); -	wa_descr->wRPipeMaxBlock = le16_to_cpu(wa_descr->wRPipeMaxBlock); -	if (wa_descr->bcdWAVersion > 0x0100) +	if (le16_to_cpu(wa_descr->bcdWAVersion) > 0x0100)  		dev_warn(dev, "Wire Adapter v%d.%d newer than groked v1.0\n", -			 wa_descr->bcdWAVersion & 0xff00 >> 8, -			 wa_descr->bcdWAVersion & 0x00ff); +			 le16_to_cpu(wa_descr->bcdWAVersion) & 0xff00 >> 8, +			 le16_to_cpu(wa_descr->bcdWAVersion) & 0x00ff);  	result = 0;  error:  	return result; @@ -679,7 +714,8 @@ static void hwahc_security_release(struct hwahc *hwahc)  	/* nothing to do here so far... */  } -static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface) +static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface, +	kernel_ulong_t quirks)  {  	int result;  	struct device *dev = &iface->dev; @@ -724,7 +760,7 @@ static int hwahc_create(struct hwahc *hwahc, struct usb_interface *iface)  		dev_err(dev, "Can't create WUSB HC structures: %d\n", result);  		goto error_wusbhc_create;  	} -	result = wa_create(&hwahc->wa, iface); +	result = wa_create(&hwahc->wa, iface, quirks);  	if (result < 0)  		goto error_wa_create;  	return 0; @@ -780,7 +816,7 @@ static int hwahc_probe(struct usb_interface *usb_iface,  	wusbhc = usb_hcd_to_wusbhc(usb_hcd);  	hwahc = container_of(wusbhc, struct hwahc, wusbhc);  	hwahc_init(hwahc); -	result = hwahc_create(hwahc, usb_iface); +	result = hwahc_create(hwahc, usb_iface, id->driver_info);  	if (result < 0) {  		dev_err(dev, "Cannot initialize internals: %d\n", result);  		goto error_hwahc_create; @@ -790,6 +826,7 @@ static int hwahc_probe(struct usb_interface *usb_iface,  		dev_err(dev, "Cannot add HCD: %d\n", result);  		goto error_add_hcd;  	} +	device_wakeup_enable(usb_hcd->self.controller);  	result = wusbhc_b_create(&hwahc->wusbhc);  	if (result < 0) {  		dev_err(dev, "Cannot setup phase B of WUSBHC: %d\n", result); @@ -824,6 +861,14 @@ static void hwahc_disconnect(struct usb_interface *usb_iface)  }  static struct usb_device_id hwahc_id_table[] = { +	/* Alereon 5310 */ +	{ USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x02, 0x01), +	  .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC | +		WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS }, +	/* Alereon 5611 */ +	{ USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5611, 0xe0, 0x02, 0x01), +	  .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC | +		WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS },  	/* FIXME: use class labels for this */  	{ USB_INTERFACE_INFO(0xe0, 0x02, 0x01), },  	{}, diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c index ec98ecee351..4f320d050da 100644 --- a/drivers/usb/host/imx21-dbg.c +++ b/drivers/usb/host/imx21-dbg.c @@ -18,6 +18,10 @@  /* this file is part of imx21-hcd.c */ +#ifdef CONFIG_DYNAMIC_DEBUG +#define DEBUG +#endif +  #ifndef DEBUG  static inline void create_debug_files(struct imx21 *imx21) { } diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index 60a5de505ca..207bad99301 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -62,6 +62,10 @@  #include "imx21-hcd.h" +#ifdef CONFIG_DYNAMIC_DEBUG +#define DEBUG +#endif +  #ifdef DEBUG  #define DEBUG_LOG_FRAME(imx21, etd, event) \  	(etd)->event##_frame = readl((imx21)->regs + USBH_FRMNUB) @@ -824,13 +828,13 @@ static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd,  			i = DIV_ROUND_UP(wrap_frame(  					cur_frame - urb->start_frame),  					urb->interval); -			if (urb->transfer_flags & URB_ISO_ASAP) { + +			/* Treat underruns as if URB_ISO_ASAP was set */ +			if ((urb->transfer_flags & URB_ISO_ASAP) || +					i >= urb->number_of_packets) {  				urb->start_frame = wrap_frame(urb->start_frame  						+ i * urb->interval);  				i = 0; -			} else if (i >= urb->number_of_packets) { -				ret = -EXDEV; -				goto alloc_dmem_failed;  			}  		}  	} @@ -1906,6 +1910,7 @@ static int imx21_probe(struct platform_device *pdev)  		dev_err(imx21->dev, "usb_add_hcd() returned %d\n", ret);  		goto failed_add_hcd;  	} +	device_wakeup_enable(hcd->self.controller);  	return 0; @@ -1926,7 +1931,7 @@ failed_request_mem:  static struct platform_driver imx21_hcd_driver = {  	.driver = { -		   .name = (char *)hcd_name, +		   .name = hcd_name,  		   },  	.probe = imx21_probe,  	.remove = imx21_remove, diff --git a/drivers/usb/host/imx21-hcd.h b/drivers/usb/host/imx21-hcd.h index c005770a73e..05122f8a698 100644 --- a/drivers/usb/host/imx21-hcd.h +++ b/drivers/usb/host/imx21-hcd.h @@ -24,6 +24,10 @@  #ifndef __LINUX_IMX21_HCD_H__  #define __LINUX_IMX21_HCD_H__ +#ifdef CONFIG_DYNAMIC_DEBUG +#define DEBUG +#endif +  #include <linux/platform_data/usb-mx2.h>  #define NUM_ISO_ETDS 	2 diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index c7d0f8f231b..240e792c81a 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -60,7 +60,6 @@  #include <linux/debugfs.h>  #include <linux/seq_file.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/slab.h>  #include <linux/usb.h> @@ -1645,6 +1644,8 @@ static int isp116x_probe(struct platform_device *pdev)  	if (ret)  		goto err6; +	device_wakeup_enable(hcd->self.controller); +  	ret = create_debug_file(isp116x);  	if (ret) {  		ERR("Couldn't create debugfs entry\n"); @@ -1705,7 +1706,7 @@ static struct platform_driver isp116x_driver = {  	.suspend = isp116x_suspend,  	.resume = isp116x_resume,  	.driver = { -		.name = (char *)hcd_name, +		.name = hcd_name,  		.owner	= THIS_MODULE,  	},  }; diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 6f29abad681..875bcfd3ec1 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -67,7 +67,6 @@  #include <linux/sched.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/interrupt.h>  #include <linux/usb.h> @@ -2108,7 +2107,7 @@ static int isp1362_show(struct seq_file *s, void *unused)  				   default:  					   s = "?";  					   break; -				   }; +				   }  				   s;}), ep->maxpacket) ;  		list_for_each_entry(urb, &ep->hep->urb_list, urb_list) {  			seq_printf(s, "  urb%p, %d/%d\n", urb, @@ -2746,6 +2745,8 @@ static int isp1362_probe(struct platform_device *pdev)  	retval = usb_add_hcd(hcd, irq, irq_flags | IRQF_SHARED);  	if (retval != 0)  		goto err6; +	device_wakeup_enable(hcd->self.controller); +  	pr_info("%s, irq %d\n", hcd->product_desc, irq);  	create_debug_file(isp1362_hcd); @@ -2829,7 +2830,7 @@ static struct platform_driver isp1362_driver = {  	.suspend = isp1362_suspend,  	.resume = isp1362_resume,  	.driver = { -		.name = (char *)hcd_name, +		.name = hcd_name,  		.owner = THIS_MODULE,  	},  }; diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index 2facee53eab..51a0ae9cdd1 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -2250,6 +2250,7 @@ struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,  	ret = usb_add_hcd(hcd, irq, irqflags);  	if (ret)  		goto err_unmap; +	device_wakeup_enable(hcd->self.controller);  	return hcd; diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c new file mode 100644 index 00000000000..858efcfda50 --- /dev/null +++ b/drivers/usb/host/max3421-hcd.c @@ -0,0 +1,1957 @@ +/* + * MAX3421 Host Controller driver for USB. + * + * Author: David Mosberger-Tang <davidm@egauge.net> + * + * (C) Copyright 2014 David Mosberger-Tang <davidm@egauge.net> + * + * MAX3421 is a chip implementing a USB 2.0 Full-/Low-Speed host + * controller on a SPI bus. + * + * Based on: + *	o MAX3421E datasheet + *		http://datasheets.maximintegrated.com/en/ds/MAX3421E.pdf + *	o MAX3421E Programming Guide + *		http://www.hdl.co.jp/ftpdata/utl-001/AN3785.pdf + *	o gadget/dummy_hcd.c + *		For USB HCD implementation. + *	o Arduino MAX3421 driver + *	     https://github.com/felis/USB_Host_Shield_2.0/blob/master/Usb.cpp + * + * This file is licenced under the GPL v2. + * + * Important note on worst-case (full-speed) packet size constraints + * (See USB 2.0 Section 5.6.3 and following): + * + *	- control:	  64 bytes + *	- isochronous:	1023 bytes + *	- interrupt:	  64 bytes + *	- bulk:		  64 bytes + * + * Since the MAX3421 FIFO size is 64 bytes, we do not have to work about + * multi-FIFO writes/reads for a single USB packet *except* for isochronous + * transfers.  We don't support isochronous transfers at this time, so we + * just assume that a USB packet always fits into a single FIFO buffer. + * + * NOTE: The June 2006 version of "MAX3421E Programming Guide" + * (AN3785) has conflicting info for the RCVDAVIRQ bit: + * + *	The description of RCVDAVIRQ says "The CPU *must* clear + *	this IRQ bit (by writing a 1 to it) before reading the + *	RCVFIFO data. + * + * However, the earlier section on "Programming BULK-IN + * Transfers" says * that: + * + *	After the CPU retrieves the data, it clears the + *	RCVDAVIRQ bit. + * + * The December 2006 version has been corrected and it consistently + * states the second behavior is the correct one. + * + * Synchronous SPI transactions sleep so we can't perform any such + * transactions while holding a spin-lock (and/or while interrupts are + * masked).  To achieve this, all SPI transactions are issued from a + * single thread (max3421_spi_thread). + */ + +#include <linux/module.h> +#include <linux/spi/spi.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include <linux/platform_data/max3421-hcd.h> + +#define DRIVER_DESC	"MAX3421 USB Host-Controller Driver" +#define DRIVER_VERSION	"1.0" + +/* 11-bit counter that wraps around (USB 2.0 Section 8.3.3): */ +#define USB_MAX_FRAME_NUMBER	0x7ff +#define USB_MAX_RETRIES		3 /* # of retries before error is reported */ + +/* + * Max. # of times we're willing to retransmit a request immediately in + * resposne to a NAK.  Afterwards, we fall back on trying once a frame. + */ +#define NAK_MAX_FAST_RETRANSMITS	2 + +#define POWER_BUDGET	500	/* in mA; use 8 for low-power port testing */ + +/* Port-change mask: */ +#define PORT_C_MASK	((USB_PORT_STAT_C_CONNECTION |	\ +			  USB_PORT_STAT_C_ENABLE |	\ +			  USB_PORT_STAT_C_SUSPEND |	\ +			  USB_PORT_STAT_C_OVERCURRENT | \ +			  USB_PORT_STAT_C_RESET) << 16) + +enum max3421_rh_state { +	MAX3421_RH_RESET, +	MAX3421_RH_SUSPENDED, +	MAX3421_RH_RUNNING +}; + +enum pkt_state { +	PKT_STATE_SETUP,	/* waiting to send setup packet to ctrl pipe */ +	PKT_STATE_TRANSFER,	/* waiting to xfer transfer_buffer */ +	PKT_STATE_TERMINATE	/* waiting to terminate control transfer */ +}; + +enum scheduling_pass { +	SCHED_PASS_PERIODIC, +	SCHED_PASS_NON_PERIODIC, +	SCHED_PASS_DONE +}; + +struct max3421_dma_buf { +	u8 data[2]; +}; + +struct max3421_hcd { +	spinlock_t lock; + +	struct task_struct *spi_thread; + +	struct max3421_hcd *next; + +	enum max3421_rh_state rh_state; +	/* lower 16 bits contain port status, upper 16 bits the change mask: */ +	u32 port_status; + +	unsigned active:1; + +	struct list_head ep_list;	/* list of EP's with work */ + +	/* +	 * The following are owned by spi_thread (may be accessed by +	 * SPI-thread without acquiring the HCD lock: +	 */ +	u8 rev;				/* chip revision */ +	u16 frame_number; +	/* +	 * kmalloc'd buffers guaranteed to be in separate (DMA) +	 * cache-lines: +	 */ +	struct max3421_dma_buf *tx; +	struct max3421_dma_buf *rx; +	/* +	 * URB we're currently processing.  Must not be reset to NULL +	 * unless MAX3421E chip is idle: +	 */ +	struct urb *curr_urb; +	enum scheduling_pass sched_pass; +	struct usb_device *loaded_dev;	/* dev that's loaded into the chip */ +	int loaded_epnum;		/* epnum whose toggles are loaded */ +	int urb_done;			/* > 0 -> no errors, < 0: errno */ +	size_t curr_len; +	u8 hien; +	u8 mode; +	u8 iopins[2]; +	unsigned int do_enable_irq:1; +	unsigned int do_reset_hcd:1; +	unsigned int do_reset_port:1; +	unsigned int do_check_unlink:1; +	unsigned int do_iopin_update:1; +#ifdef DEBUG +	unsigned long err_stat[16]; +#endif +}; + +struct max3421_ep { +	struct usb_host_endpoint *ep; +	struct list_head ep_list; +	u32 naks; +	u16 last_active;		/* frame # this ep was last active */ +	enum pkt_state pkt_state; +	u8 retries; +	u8 retransmit;			/* packet needs retransmission */ +}; + +static struct max3421_hcd *max3421_hcd_list; + +#define MAX3421_FIFO_SIZE	64 + +#define MAX3421_SPI_DIR_RD	0	/* read register from MAX3421 */ +#define MAX3421_SPI_DIR_WR	1	/* write register to MAX3421 */ + +/* SPI commands: */ +#define MAX3421_SPI_DIR_SHIFT	1 +#define MAX3421_SPI_REG_SHIFT	3 + +#define MAX3421_REG_RCVFIFO	1 +#define MAX3421_REG_SNDFIFO	2 +#define MAX3421_REG_SUDFIFO	4 +#define MAX3421_REG_RCVBC	6 +#define MAX3421_REG_SNDBC	7 +#define MAX3421_REG_USBIRQ	13 +#define MAX3421_REG_USBIEN	14 +#define MAX3421_REG_USBCTL	15 +#define MAX3421_REG_CPUCTL	16 +#define MAX3421_REG_PINCTL	17 +#define MAX3421_REG_REVISION	18 +#define MAX3421_REG_IOPINS1	20 +#define MAX3421_REG_IOPINS2	21 +#define MAX3421_REG_GPINIRQ	22 +#define MAX3421_REG_GPINIEN	23 +#define MAX3421_REG_GPINPOL	24 +#define MAX3421_REG_HIRQ	25 +#define MAX3421_REG_HIEN	26 +#define MAX3421_REG_MODE	27 +#define MAX3421_REG_PERADDR	28 +#define MAX3421_REG_HCTL	29 +#define MAX3421_REG_HXFR	30 +#define MAX3421_REG_HRSL	31 + +enum { +	MAX3421_USBIRQ_OSCOKIRQ_BIT = 0, +	MAX3421_USBIRQ_NOVBUSIRQ_BIT = 5, +	MAX3421_USBIRQ_VBUSIRQ_BIT +}; + +enum { +	MAX3421_CPUCTL_IE_BIT = 0, +	MAX3421_CPUCTL_PULSEWID0_BIT = 6, +	MAX3421_CPUCTL_PULSEWID1_BIT +}; + +enum { +	MAX3421_USBCTL_PWRDOWN_BIT = 4, +	MAX3421_USBCTL_CHIPRES_BIT +}; + +enum { +	MAX3421_PINCTL_GPXA_BIT	= 0, +	MAX3421_PINCTL_GPXB_BIT, +	MAX3421_PINCTL_POSINT_BIT, +	MAX3421_PINCTL_INTLEVEL_BIT, +	MAX3421_PINCTL_FDUPSPI_BIT, +	MAX3421_PINCTL_EP0INAK_BIT, +	MAX3421_PINCTL_EP2INAK_BIT, +	MAX3421_PINCTL_EP3INAK_BIT, +}; + +enum { +	MAX3421_HI_BUSEVENT_BIT = 0,	/* bus-reset/-resume */ +	MAX3421_HI_RWU_BIT,		/* remote wakeup */ +	MAX3421_HI_RCVDAV_BIT,		/* receive FIFO data available */ +	MAX3421_HI_SNDBAV_BIT,		/* send buffer available */ +	MAX3421_HI_SUSDN_BIT,		/* suspend operation done */ +	MAX3421_HI_CONDET_BIT,		/* peripheral connect/disconnect */ +	MAX3421_HI_FRAME_BIT,		/* frame generator */ +	MAX3421_HI_HXFRDN_BIT,		/* host transfer done */ +}; + +enum { +	MAX3421_HCTL_BUSRST_BIT = 0, +	MAX3421_HCTL_FRMRST_BIT, +	MAX3421_HCTL_SAMPLEBUS_BIT, +	MAX3421_HCTL_SIGRSM_BIT, +	MAX3421_HCTL_RCVTOG0_BIT, +	MAX3421_HCTL_RCVTOG1_BIT, +	MAX3421_HCTL_SNDTOG0_BIT, +	MAX3421_HCTL_SNDTOG1_BIT +}; + +enum { +	MAX3421_MODE_HOST_BIT = 0, +	MAX3421_MODE_LOWSPEED_BIT, +	MAX3421_MODE_HUBPRE_BIT, +	MAX3421_MODE_SOFKAENAB_BIT, +	MAX3421_MODE_SEPIRQ_BIT, +	MAX3421_MODE_DELAYISO_BIT, +	MAX3421_MODE_DMPULLDN_BIT, +	MAX3421_MODE_DPPULLDN_BIT +}; + +enum { +	MAX3421_HRSL_OK = 0, +	MAX3421_HRSL_BUSY, +	MAX3421_HRSL_BADREQ, +	MAX3421_HRSL_UNDEF, +	MAX3421_HRSL_NAK, +	MAX3421_HRSL_STALL, +	MAX3421_HRSL_TOGERR, +	MAX3421_HRSL_WRONGPID, +	MAX3421_HRSL_BADBC, +	MAX3421_HRSL_PIDERR, +	MAX3421_HRSL_PKTERR, +	MAX3421_HRSL_CRCERR, +	MAX3421_HRSL_KERR, +	MAX3421_HRSL_JERR, +	MAX3421_HRSL_TIMEOUT, +	MAX3421_HRSL_BABBLE, +	MAX3421_HRSL_RESULT_MASK = 0xf, +	MAX3421_HRSL_RCVTOGRD_BIT = 4, +	MAX3421_HRSL_SNDTOGRD_BIT, +	MAX3421_HRSL_KSTATUS_BIT, +	MAX3421_HRSL_JSTATUS_BIT +}; + +/* Return same error-codes as ohci.h:cc_to_error: */ +static const int hrsl_to_error[] = { +	[MAX3421_HRSL_OK] =		0, +	[MAX3421_HRSL_BUSY] =		-EINVAL, +	[MAX3421_HRSL_BADREQ] =		-EINVAL, +	[MAX3421_HRSL_UNDEF] =		-EINVAL, +	[MAX3421_HRSL_NAK] =		-EAGAIN, +	[MAX3421_HRSL_STALL] =		-EPIPE, +	[MAX3421_HRSL_TOGERR] =		-EILSEQ, +	[MAX3421_HRSL_WRONGPID] =	-EPROTO, +	[MAX3421_HRSL_BADBC] =		-EREMOTEIO, +	[MAX3421_HRSL_PIDERR] =		-EPROTO, +	[MAX3421_HRSL_PKTERR] =		-EPROTO, +	[MAX3421_HRSL_CRCERR] =		-EILSEQ, +	[MAX3421_HRSL_KERR] =		-EIO, +	[MAX3421_HRSL_JERR] =		-EIO, +	[MAX3421_HRSL_TIMEOUT] =	-ETIME, +	[MAX3421_HRSL_BABBLE] =		-EOVERFLOW +}; + +/* + * See http://www.beyondlogic.org/usbnutshell/usb4.shtml#Control for a + * reasonable overview of how control transfers use the the IN/OUT + * tokens. + */ +#define MAX3421_HXFR_BULK_IN(ep)	(0x00 | (ep))	/* bulk or interrupt */ +#define MAX3421_HXFR_SETUP		 0x10 +#define MAX3421_HXFR_BULK_OUT(ep)	(0x20 | (ep))	/* bulk or interrupt */ +#define MAX3421_HXFR_ISO_IN(ep)		(0x40 | (ep)) +#define MAX3421_HXFR_ISO_OUT(ep)	(0x60 | (ep)) +#define MAX3421_HXFR_HS_IN		 0x80		/* handshake in */ +#define MAX3421_HXFR_HS_OUT		 0xa0		/* handshake out */ + +#define field(val, bit)	((val) << (bit)) + +static inline s16 +frame_diff(u16 left, u16 right) +{ +	return ((unsigned) (left - right)) % (USB_MAX_FRAME_NUMBER + 1); +} + +static inline struct max3421_hcd * +hcd_to_max3421(struct usb_hcd *hcd) +{ +	return (struct max3421_hcd *) hcd->hcd_priv; +} + +static inline struct usb_hcd * +max3421_to_hcd(struct max3421_hcd *max3421_hcd) +{ +	return container_of((void *) max3421_hcd, struct usb_hcd, hcd_priv); +} + +static u8 +spi_rd8(struct usb_hcd *hcd, unsigned int reg) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct spi_transfer transfer; +	struct spi_message msg; + +	memset(&transfer, 0, sizeof(transfer)); + +	spi_message_init(&msg); + +	max3421_hcd->tx->data[0] = +		(field(reg, MAX3421_SPI_REG_SHIFT) | +		 field(MAX3421_SPI_DIR_RD, MAX3421_SPI_DIR_SHIFT)); + +	transfer.tx_buf = max3421_hcd->tx->data; +	transfer.rx_buf = max3421_hcd->rx->data; +	transfer.len = 2; + +	spi_message_add_tail(&transfer, &msg); +	spi_sync(spi, &msg); + +	return max3421_hcd->rx->data[1]; +} + +static void +spi_wr8(struct usb_hcd *hcd, unsigned int reg, u8 val) +{ +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	struct spi_transfer transfer; +	struct spi_message msg; + +	memset(&transfer, 0, sizeof(transfer)); + +	spi_message_init(&msg); + +	max3421_hcd->tx->data[0] = +		(field(reg, MAX3421_SPI_REG_SHIFT) | +		 field(MAX3421_SPI_DIR_WR, MAX3421_SPI_DIR_SHIFT)); +	max3421_hcd->tx->data[1] = val; + +	transfer.tx_buf = max3421_hcd->tx->data; +	transfer.len = 2; + +	spi_message_add_tail(&transfer, &msg); +	spi_sync(spi, &msg); +} + +static void +spi_rd_buf(struct usb_hcd *hcd, unsigned int reg, void *buf, size_t len) +{ +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	struct spi_transfer transfer[2]; +	struct spi_message msg; + +	memset(transfer, 0, sizeof(transfer)); + +	spi_message_init(&msg); + +	max3421_hcd->tx->data[0] = +		(field(reg, MAX3421_SPI_REG_SHIFT) | +		 field(MAX3421_SPI_DIR_RD, MAX3421_SPI_DIR_SHIFT)); +	transfer[0].tx_buf = max3421_hcd->tx->data; +	transfer[0].len = 1; + +	transfer[1].rx_buf = buf; +	transfer[1].len = len; + +	spi_message_add_tail(&transfer[0], &msg); +	spi_message_add_tail(&transfer[1], &msg); +	spi_sync(spi, &msg); +} + +static void +spi_wr_buf(struct usb_hcd *hcd, unsigned int reg, void *buf, size_t len) +{ +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	struct spi_transfer transfer[2]; +	struct spi_message msg; + +	memset(transfer, 0, sizeof(transfer)); + +	spi_message_init(&msg); + +	max3421_hcd->tx->data[0] = +		(field(reg, MAX3421_SPI_REG_SHIFT) | +		 field(MAX3421_SPI_DIR_WR, MAX3421_SPI_DIR_SHIFT)); + +	transfer[0].tx_buf = max3421_hcd->tx->data; +	transfer[0].len = 1; + +	transfer[1].tx_buf = buf; +	transfer[1].len = len; + +	spi_message_add_tail(&transfer[0], &msg); +	spi_message_add_tail(&transfer[1], &msg); +	spi_sync(spi, &msg); +} + +/* + * Figure out the correct setting for the LOWSPEED and HUBPRE mode + * bits.  The HUBPRE bit needs to be set when MAX3421E operates at + * full speed, but it's talking to a low-speed device (i.e., through a + * hub).  Setting that bit ensures that every low-speed packet is + * preceded by a full-speed PRE PID.  Possible configurations: + * + * Hub speed:	Device speed:	=>	LOWSPEED bit:	HUBPRE bit: + *	FULL	FULL		=>	0		0 + *	FULL	LOW		=>	1		1 + *	LOW	LOW		=>	1		0 + *	LOW	FULL		=>	1		0 + */ +static void +max3421_set_speed(struct usb_hcd *hcd, struct usb_device *dev) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	u8 mode_lowspeed, mode_hubpre, mode = max3421_hcd->mode; + +	mode_lowspeed = BIT(MAX3421_MODE_LOWSPEED_BIT); +	mode_hubpre   = BIT(MAX3421_MODE_HUBPRE_BIT); +	if (max3421_hcd->port_status & USB_PORT_STAT_LOW_SPEED) { +		mode |=  mode_lowspeed; +		mode &= ~mode_hubpre; +	} else if (dev->speed == USB_SPEED_LOW) { +		mode |= mode_lowspeed | mode_hubpre; +	} else { +		mode &= ~(mode_lowspeed | mode_hubpre); +	} +	if (mode != max3421_hcd->mode) { +		max3421_hcd->mode = mode; +		spi_wr8(hcd, MAX3421_REG_MODE, max3421_hcd->mode); +	} + +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static void +max3421_set_address(struct usb_hcd *hcd, struct usb_device *dev, int epnum, +		    int force_toggles) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	int old_epnum, same_ep, rcvtog, sndtog; +	struct usb_device *old_dev; +	u8 hctl; + +	old_dev = max3421_hcd->loaded_dev; +	old_epnum = max3421_hcd->loaded_epnum; + +	same_ep = (dev == old_dev && epnum == old_epnum); +	if (same_ep && !force_toggles) +		return; + +	if (old_dev && !same_ep) { +		/* save the old end-points toggles: */ +		u8 hrsl = spi_rd8(hcd, MAX3421_REG_HRSL); + +		rcvtog = (hrsl >> MAX3421_HRSL_RCVTOGRD_BIT) & 1; +		sndtog = (hrsl >> MAX3421_HRSL_SNDTOGRD_BIT) & 1; + +		/* no locking: HCD (i.e., we) own toggles, don't we? */ +		usb_settoggle(old_dev, old_epnum, 0, rcvtog); +		usb_settoggle(old_dev, old_epnum, 1, sndtog); +	} +	/* setup new endpoint's toggle bits: */ +	rcvtog = usb_gettoggle(dev, epnum, 0); +	sndtog = usb_gettoggle(dev, epnum, 1); +	hctl = (BIT(rcvtog + MAX3421_HCTL_RCVTOG0_BIT) | +		BIT(sndtog + MAX3421_HCTL_SNDTOG0_BIT)); + +	max3421_hcd->loaded_epnum = epnum; +	spi_wr8(hcd, MAX3421_REG_HCTL, hctl); + +	/* +	 * Note: devnum for one and the same device can change during +	 * address-assignment so it's best to just always load the +	 * address whenever the end-point changed/was forced. +	 */ +	max3421_hcd->loaded_dev = dev; +	spi_wr8(hcd, MAX3421_REG_PERADDR, dev->devnum); +} + +static int +max3421_ctrl_setup(struct usb_hcd *hcd, struct urb *urb) +{ +	spi_wr_buf(hcd, MAX3421_REG_SUDFIFO, urb->setup_packet, 8); +	return MAX3421_HXFR_SETUP; +} + +static int +max3421_transfer_in(struct usb_hcd *hcd, struct urb *urb) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	int epnum = usb_pipeendpoint(urb->pipe); + +	max3421_hcd->curr_len = 0; +	max3421_hcd->hien |= BIT(MAX3421_HI_RCVDAV_BIT); +	return MAX3421_HXFR_BULK_IN(epnum); +} + +static int +max3421_transfer_out(struct usb_hcd *hcd, struct urb *urb, int fast_retransmit) +{ +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	int epnum = usb_pipeendpoint(urb->pipe); +	u32 max_packet; +	void *src; + +	src = urb->transfer_buffer + urb->actual_length; + +	if (fast_retransmit) { +		if (max3421_hcd->rev == 0x12) { +			/* work around rev 0x12 bug: */ +			spi_wr8(hcd, MAX3421_REG_SNDBC, 0); +			spi_wr8(hcd, MAX3421_REG_SNDFIFO, ((u8 *) src)[0]); +			spi_wr8(hcd, MAX3421_REG_SNDBC, max3421_hcd->curr_len); +		} +		return MAX3421_HXFR_BULK_OUT(epnum); +	} + +	max_packet = usb_maxpacket(urb->dev, urb->pipe, 1); + +	if (max_packet > MAX3421_FIFO_SIZE) { +		/* +		 * We do not support isochronous transfers at this +		 * time. +		 */ +		dev_err(&spi->dev, +			"%s: packet-size of %u too big (limit is %u bytes)", +			__func__, max_packet, MAX3421_FIFO_SIZE); +		max3421_hcd->urb_done = -EMSGSIZE; +		return -EMSGSIZE; +	} +	max3421_hcd->curr_len = min((urb->transfer_buffer_length - +				     urb->actual_length), max_packet); + +	spi_wr_buf(hcd, MAX3421_REG_SNDFIFO, src, max3421_hcd->curr_len); +	spi_wr8(hcd, MAX3421_REG_SNDBC, max3421_hcd->curr_len); +	return MAX3421_HXFR_BULK_OUT(epnum); +} + +/* + * Issue the next host-transfer command. + * Caller must NOT hold HCD spinlock. + */ +static void +max3421_next_transfer(struct usb_hcd *hcd, int fast_retransmit) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	struct urb *urb = max3421_hcd->curr_urb; +	struct max3421_ep *max3421_ep; +	int cmd = -EINVAL; + +	if (!urb) +		return;	/* nothing to do */ + +	max3421_ep = urb->ep->hcpriv; + +	switch (max3421_ep->pkt_state) { +	case PKT_STATE_SETUP: +		cmd = max3421_ctrl_setup(hcd, urb); +		break; + +	case PKT_STATE_TRANSFER: +		if (usb_urb_dir_in(urb)) +			cmd = max3421_transfer_in(hcd, urb); +		else +			cmd = max3421_transfer_out(hcd, urb, fast_retransmit); +		break; + +	case PKT_STATE_TERMINATE: +		/* +		 * IN transfers are terminated with HS_OUT token, +		 * OUT transfers with HS_IN: +		 */ +		if (usb_urb_dir_in(urb)) +			cmd = MAX3421_HXFR_HS_OUT; +		else +			cmd = MAX3421_HXFR_HS_IN; +		break; +	} + +	if (cmd < 0) +		return; + +	/* issue the command and wait for host-xfer-done interrupt: */ + +	spi_wr8(hcd, MAX3421_REG_HXFR, cmd); +	max3421_hcd->hien |= BIT(MAX3421_HI_HXFRDN_BIT); +} + +/* + * Find the next URB to process and start its execution. + * + * At this time, we do not anticipate ever connecting a USB hub to the + * MAX3421 chip, so at most USB device can be connected and we can use + * a simplistic scheduler: at the start of a frame, schedule all + * periodic transfers.  Once that is done, use the remainder of the + * frame to process non-periodic (bulk & control) transfers. + * + * Preconditions: + * o Caller must NOT hold HCD spinlock. + * o max3421_hcd->curr_urb MUST BE NULL. + * o MAX3421E chip must be idle. + */ +static int +max3421_select_and_start_urb(struct usb_hcd *hcd) +{ +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	struct urb *urb, *curr_urb = NULL; +	struct max3421_ep *max3421_ep; +	int epnum, force_toggles = 0; +	struct usb_host_endpoint *ep; +	struct list_head *pos; +	unsigned long flags; + +	spin_lock_irqsave(&max3421_hcd->lock, flags); + +	for (; +	     max3421_hcd->sched_pass < SCHED_PASS_DONE; +	     ++max3421_hcd->sched_pass) +		list_for_each(pos, &max3421_hcd->ep_list) { +			urb = NULL; +			max3421_ep = container_of(pos, struct max3421_ep, +						  ep_list); +			ep = max3421_ep->ep; + +			switch (usb_endpoint_type(&ep->desc)) { +			case USB_ENDPOINT_XFER_ISOC: +			case USB_ENDPOINT_XFER_INT: +				if (max3421_hcd->sched_pass != +				    SCHED_PASS_PERIODIC) +					continue; +				break; + +			case USB_ENDPOINT_XFER_CONTROL: +			case USB_ENDPOINT_XFER_BULK: +				if (max3421_hcd->sched_pass != +				    SCHED_PASS_NON_PERIODIC) +					continue; +				break; +			} + +			if (list_empty(&ep->urb_list)) +				continue;	/* nothing to do */ +			urb = list_first_entry(&ep->urb_list, struct urb, +					       urb_list); +			if (urb->unlinked) { +				dev_dbg(&spi->dev, "%s: URB %p unlinked=%d", +					__func__, urb, urb->unlinked); +				max3421_hcd->curr_urb = urb; +				max3421_hcd->urb_done = 1; +				spin_unlock_irqrestore(&max3421_hcd->lock, +						       flags); +				return 1; +			} + +			switch (usb_endpoint_type(&ep->desc)) { +			case USB_ENDPOINT_XFER_CONTROL: +				/* +				 * Allow one control transaction per +				 * frame per endpoint: +				 */ +				if (frame_diff(max3421_ep->last_active, +					       max3421_hcd->frame_number) == 0) +					continue; +				break; + +			case USB_ENDPOINT_XFER_BULK: +				if (max3421_ep->retransmit +				    && (frame_diff(max3421_ep->last_active, +						   max3421_hcd->frame_number) +					== 0)) +					/* +					 * We already tried this EP +					 * during this frame and got a +					 * NAK or error; wait for next frame +					 */ +					continue; +				break; + +			case USB_ENDPOINT_XFER_ISOC: +			case USB_ENDPOINT_XFER_INT: +				if (frame_diff(max3421_hcd->frame_number, +					       max3421_ep->last_active) +				    < urb->interval) +					/* +					 * We already processed this +					 * end-point in the current +					 * frame +					 */ +					continue; +				break; +			} + +			/* move current ep to tail: */ +			list_move_tail(pos, &max3421_hcd->ep_list); +			curr_urb = urb; +			goto done; +		} +done: +	if (!curr_urb) { +		spin_unlock_irqrestore(&max3421_hcd->lock, flags); +		return 0; +	} + +	urb = max3421_hcd->curr_urb = curr_urb; +	epnum = usb_endpoint_num(&urb->ep->desc); +	if (max3421_ep->retransmit) +		/* restart (part of) a USB transaction: */ +		max3421_ep->retransmit = 0; +	else { +		/* start USB transaction: */ +		if (usb_endpoint_xfer_control(&ep->desc)) { +			/* +			 * See USB 2.0 spec section 8.6.1 +			 * Initialization via SETUP Token: +			 */ +			usb_settoggle(urb->dev, epnum, 0, 1); +			usb_settoggle(urb->dev, epnum, 1, 1); +			max3421_ep->pkt_state = PKT_STATE_SETUP; +			force_toggles = 1; +		} else +			max3421_ep->pkt_state = PKT_STATE_TRANSFER; +	} + +	spin_unlock_irqrestore(&max3421_hcd->lock, flags); + +	max3421_ep->last_active = max3421_hcd->frame_number; +	max3421_set_address(hcd, urb->dev, epnum, force_toggles); +	max3421_set_speed(hcd, urb->dev); +	max3421_next_transfer(hcd, 0); +	return 1; +} + +/* + * Check all endpoints for URBs that got unlinked. + * + * Caller must NOT hold HCD spinlock. + */ +static int +max3421_check_unlink(struct usb_hcd *hcd) +{ +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	struct list_head *pos, *upos, *next_upos; +	struct max3421_ep *max3421_ep; +	struct usb_host_endpoint *ep; +	struct urb *urb; +	unsigned long flags; +	int retval = 0; + +	spin_lock_irqsave(&max3421_hcd->lock, flags); +	list_for_each(pos, &max3421_hcd->ep_list) { +		max3421_ep = container_of(pos, struct max3421_ep, ep_list); +		ep = max3421_ep->ep; +		list_for_each_safe(upos, next_upos, &ep->urb_list) { +			urb = container_of(upos, struct urb, urb_list); +			if (urb->unlinked) { +				retval = 1; +				dev_dbg(&spi->dev, "%s: URB %p unlinked=%d", +					__func__, urb, urb->unlinked); +				usb_hcd_unlink_urb_from_ep(hcd, urb); +				spin_unlock_irqrestore(&max3421_hcd->lock, +						       flags); +				usb_hcd_giveback_urb(hcd, urb, 0); +				spin_lock_irqsave(&max3421_hcd->lock, flags); +			} +		} +	} +	spin_unlock_irqrestore(&max3421_hcd->lock, flags); +	return retval; +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static void +max3421_slow_retransmit(struct usb_hcd *hcd) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	struct urb *urb = max3421_hcd->curr_urb; +	struct max3421_ep *max3421_ep; + +	max3421_ep = urb->ep->hcpriv; +	max3421_ep->retransmit = 1; +	max3421_hcd->curr_urb = NULL; +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static void +max3421_recv_data_available(struct usb_hcd *hcd) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	struct urb *urb = max3421_hcd->curr_urb; +	size_t remaining, transfer_size; +	u8 rcvbc; + +	rcvbc = spi_rd8(hcd, MAX3421_REG_RCVBC); + +	if (rcvbc > MAX3421_FIFO_SIZE) +		rcvbc = MAX3421_FIFO_SIZE; +	if (urb->actual_length >= urb->transfer_buffer_length) +		remaining = 0; +	else +		remaining = urb->transfer_buffer_length - urb->actual_length; +	transfer_size = rcvbc; +	if (transfer_size > remaining) +		transfer_size = remaining; +	if (transfer_size > 0) { +		void *dst = urb->transfer_buffer + urb->actual_length; + +		spi_rd_buf(hcd, MAX3421_REG_RCVFIFO, dst, transfer_size); +		urb->actual_length += transfer_size; +		max3421_hcd->curr_len = transfer_size; +	} + +	/* ack the RCVDAV irq now that the FIFO has been read: */ +	spi_wr8(hcd, MAX3421_REG_HIRQ, BIT(MAX3421_HI_RCVDAV_BIT)); +} + +static void +max3421_handle_error(struct usb_hcd *hcd, u8 hrsl) +{ +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	u8 result_code = hrsl & MAX3421_HRSL_RESULT_MASK; +	struct urb *urb = max3421_hcd->curr_urb; +	struct max3421_ep *max3421_ep = urb->ep->hcpriv; +	int switch_sndfifo; + +	/* +	 * If an OUT command results in any response other than OK +	 * (i.e., error or NAK), we have to perform a dummy-write to +	 * SNDBC so the FIFO gets switched back to us.  Otherwise, we +	 * get out of sync with the SNDFIFO double buffer. +	 */ +	switch_sndfifo = (max3421_ep->pkt_state == PKT_STATE_TRANSFER && +			  usb_urb_dir_out(urb)); + +	switch (result_code) { +	case MAX3421_HRSL_OK: +		return;			/* this shouldn't happen */ + +	case MAX3421_HRSL_WRONGPID:	/* received wrong PID */ +	case MAX3421_HRSL_BUSY:		/* SIE busy */ +	case MAX3421_HRSL_BADREQ:	/* bad val in HXFR */ +	case MAX3421_HRSL_UNDEF:	/* reserved */ +	case MAX3421_HRSL_KERR:		/* K-state instead of response */ +	case MAX3421_HRSL_JERR:		/* J-state instead of response */ +		/* +		 * packet experienced an error that we cannot recover +		 * from; report error +		 */ +		max3421_hcd->urb_done = hrsl_to_error[result_code]; +		dev_dbg(&spi->dev, "%s: unexpected error HRSL=0x%02x", +			__func__, hrsl); +		break; + +	case MAX3421_HRSL_TOGERR: +		if (usb_urb_dir_in(urb)) +			; /* don't do anything (device will switch toggle) */ +		else { +			/* flip the send toggle bit: */ +			int sndtog = (hrsl >> MAX3421_HRSL_SNDTOGRD_BIT) & 1; + +			sndtog ^= 1; +			spi_wr8(hcd, MAX3421_REG_HCTL, +				BIT(sndtog + MAX3421_HCTL_SNDTOG0_BIT)); +		} +		/* FALL THROUGH */ +	case MAX3421_HRSL_BADBC:	/* bad byte count */ +	case MAX3421_HRSL_PIDERR:	/* received PID is corrupted */ +	case MAX3421_HRSL_PKTERR:	/* packet error (stuff, EOP) */ +	case MAX3421_HRSL_CRCERR:	/* CRC error */ +	case MAX3421_HRSL_BABBLE:	/* device talked too long */ +	case MAX3421_HRSL_TIMEOUT: +		if (max3421_ep->retries++ < USB_MAX_RETRIES) +			/* retry the packet again in the next frame */ +			max3421_slow_retransmit(hcd); +		else { +			/* Based on ohci.h cc_to_err[]: */ +			max3421_hcd->urb_done = hrsl_to_error[result_code]; +			dev_dbg(&spi->dev, "%s: unexpected error HRSL=0x%02x", +				__func__, hrsl); +		} +		break; + +	case MAX3421_HRSL_STALL: +		dev_dbg(&spi->dev, "%s: unexpected error HRSL=0x%02x", +			__func__, hrsl); +		max3421_hcd->urb_done = hrsl_to_error[result_code]; +		break; + +	case MAX3421_HRSL_NAK: +		/* +		 * Device wasn't ready for data or has no data +		 * available: retry the packet again. +		 */ +		if (max3421_ep->naks++ < NAK_MAX_FAST_RETRANSMITS) { +			max3421_next_transfer(hcd, 1); +			switch_sndfifo = 0; +		} else +			max3421_slow_retransmit(hcd); +		break; +	} +	if (switch_sndfifo) +		spi_wr8(hcd, MAX3421_REG_SNDBC, 0); +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static int +max3421_transfer_in_done(struct usb_hcd *hcd, struct urb *urb) +{ +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	u32 max_packet; + +	if (urb->actual_length >= urb->transfer_buffer_length) +		return 1;	/* read is complete, so we're done */ + +	/* +	 * USB 2.0 Section 5.3.2 Pipes: packets must be full size +	 * except for last one. +	 */ +	max_packet = usb_maxpacket(urb->dev, urb->pipe, 0); +	if (max_packet > MAX3421_FIFO_SIZE) { +		/* +		 * We do not support isochronous transfers at this +		 * time... +		 */ +		dev_err(&spi->dev, +			"%s: packet-size of %u too big (limit is %u bytes)", +			__func__, max_packet, MAX3421_FIFO_SIZE); +		return -EINVAL; +	} + +	if (max3421_hcd->curr_len < max_packet) { +		if (urb->transfer_flags & URB_SHORT_NOT_OK) { +			/* +			 * remaining > 0 and received an +			 * unexpected partial packet -> +			 * error +			 */ +			return -EREMOTEIO; +		} else +			/* short read, but it's OK */ +			return 1; +	} +	return 0;	/* not done */ +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static int +max3421_transfer_out_done(struct usb_hcd *hcd, struct urb *urb) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + +	urb->actual_length += max3421_hcd->curr_len; +	if (urb->actual_length < urb->transfer_buffer_length) +		return 0; +	if (urb->transfer_flags & URB_ZERO_PACKET) { +		/* +		 * Some hardware needs a zero-size packet at the end +		 * of a bulk-out transfer if the last transfer was a +		 * full-sized packet (i.e., such hardware use < +		 * max_packet as an indicator that the end of the +		 * packet has been reached). +		 */ +		u32 max_packet = usb_maxpacket(urb->dev, urb->pipe, 1); + +		if (max3421_hcd->curr_len == max_packet) +			return 0; +	} +	return 1; +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static void +max3421_host_transfer_done(struct usb_hcd *hcd) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	struct urb *urb = max3421_hcd->curr_urb; +	struct max3421_ep *max3421_ep; +	u8 result_code, hrsl; +	int urb_done = 0; + +	max3421_hcd->hien &= ~(BIT(MAX3421_HI_HXFRDN_BIT) | +			       BIT(MAX3421_HI_RCVDAV_BIT)); + +	hrsl = spi_rd8(hcd, MAX3421_REG_HRSL); +	result_code = hrsl & MAX3421_HRSL_RESULT_MASK; + +#ifdef DEBUG +	++max3421_hcd->err_stat[result_code]; +#endif + +	max3421_ep = urb->ep->hcpriv; + +	if (unlikely(result_code != MAX3421_HRSL_OK)) { +		max3421_handle_error(hcd, hrsl); +		return; +	} + +	max3421_ep->naks = 0; +	max3421_ep->retries = 0; +	switch (max3421_ep->pkt_state) { + +	case PKT_STATE_SETUP: +		if (urb->transfer_buffer_length > 0) +			max3421_ep->pkt_state = PKT_STATE_TRANSFER; +		else +			max3421_ep->pkt_state = PKT_STATE_TERMINATE; +		break; + +	case PKT_STATE_TRANSFER: +		if (usb_urb_dir_in(urb)) +			urb_done = max3421_transfer_in_done(hcd, urb); +		else +			urb_done = max3421_transfer_out_done(hcd, urb); +		if (urb_done > 0 && usb_pipetype(urb->pipe) == PIPE_CONTROL) { +			/* +			 * We aren't really done - we still need to +			 * terminate the control transfer: +			 */ +			max3421_hcd->urb_done = urb_done = 0; +			max3421_ep->pkt_state = PKT_STATE_TERMINATE; +		} +		break; + +	case PKT_STATE_TERMINATE: +		urb_done = 1; +		break; +	} + +	if (urb_done) +		max3421_hcd->urb_done = urb_done; +	else +		max3421_next_transfer(hcd, 0); +} + +/* + * Caller must NOT hold HCD spinlock. + */ +static void +max3421_detect_conn(struct usb_hcd *hcd) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	unsigned int jk, have_conn = 0; +	u32 old_port_status, chg; +	unsigned long flags; +	u8 hrsl, mode; + +	hrsl = spi_rd8(hcd, MAX3421_REG_HRSL); + +	jk = ((((hrsl >> MAX3421_HRSL_JSTATUS_BIT) & 1) << 0) | +	      (((hrsl >> MAX3421_HRSL_KSTATUS_BIT) & 1) << 1)); + +	mode = max3421_hcd->mode; + +	switch (jk) { +	case 0x0: /* SE0: disconnect */ +		/* +		 * Turn off SOFKAENAB bit to avoid getting interrupt +		 * every milli-second: +		 */ +		mode &= ~BIT(MAX3421_MODE_SOFKAENAB_BIT); +		break; + +	case 0x1: /* J=0,K=1: low-speed (in full-speed or vice versa) */ +	case 0x2: /* J=1,K=0: full-speed (in full-speed or vice versa) */ +		if (jk == 0x2) +			/* need to switch to the other speed: */ +			mode ^= BIT(MAX3421_MODE_LOWSPEED_BIT); +		/* turn on SOFKAENAB bit: */ +		mode |= BIT(MAX3421_MODE_SOFKAENAB_BIT); +		have_conn = 1; +		break; + +	case 0x3: /* illegal */ +		break; +	} + +	max3421_hcd->mode = mode; +	spi_wr8(hcd, MAX3421_REG_MODE, max3421_hcd->mode); + +	spin_lock_irqsave(&max3421_hcd->lock, flags); +	old_port_status = max3421_hcd->port_status; +	if (have_conn) +		max3421_hcd->port_status |=  USB_PORT_STAT_CONNECTION; +	else +		max3421_hcd->port_status &= ~USB_PORT_STAT_CONNECTION; +	if (mode & BIT(MAX3421_MODE_LOWSPEED_BIT)) +		max3421_hcd->port_status |=  USB_PORT_STAT_LOW_SPEED; +	else +		max3421_hcd->port_status &= ~USB_PORT_STAT_LOW_SPEED; +	chg = (old_port_status ^ max3421_hcd->port_status); +	max3421_hcd->port_status |= chg << 16; +	spin_unlock_irqrestore(&max3421_hcd->lock, flags); +} + +static irqreturn_t +max3421_irq_handler(int irq, void *dev_id) +{ +	struct usb_hcd *hcd = dev_id; +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + +	if (max3421_hcd->spi_thread && +	    max3421_hcd->spi_thread->state != TASK_RUNNING) +		wake_up_process(max3421_hcd->spi_thread); +	if (!max3421_hcd->do_enable_irq) { +		max3421_hcd->do_enable_irq = 1; +		disable_irq_nosync(spi->irq); +	} +	return IRQ_HANDLED; +} + +#ifdef DEBUG + +static void +dump_eps(struct usb_hcd *hcd) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	struct max3421_ep *max3421_ep; +	struct usb_host_endpoint *ep; +	struct list_head *pos, *upos; +	char ubuf[512], *dp, *end; +	unsigned long flags; +	struct urb *urb; +	int epnum, ret; + +	spin_lock_irqsave(&max3421_hcd->lock, flags); +	list_for_each(pos, &max3421_hcd->ep_list) { +		max3421_ep = container_of(pos, struct max3421_ep, ep_list); +		ep = max3421_ep->ep; + +		dp = ubuf; +		end = dp + sizeof(ubuf); +		*dp = '\0'; +		list_for_each(upos, &ep->urb_list) { +			urb = container_of(upos, struct urb, urb_list); +			ret = snprintf(dp, end - dp, " %p(%d.%s %d/%d)", urb, +				       usb_pipetype(urb->pipe), +				       usb_urb_dir_in(urb) ? "IN" : "OUT", +				       urb->actual_length, +				       urb->transfer_buffer_length); +			if (ret < 0 || ret >= end - dp) +				break;	/* error or buffer full */ +			dp += ret; +		} + +		epnum = usb_endpoint_num(&ep->desc); +		pr_info("EP%0u %u lst %04u rtr %u nak %6u rxmt %u: %s\n", +			epnum, max3421_ep->pkt_state, max3421_ep->last_active, +			max3421_ep->retries, max3421_ep->naks, +			max3421_ep->retransmit, ubuf); +	} +	spin_unlock_irqrestore(&max3421_hcd->lock, flags); +} + +#endif /* DEBUG */ + +/* Return zero if no work was performed, 1 otherwise.  */ +static int +max3421_handle_irqs(struct usb_hcd *hcd) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	u32 chg, old_port_status; +	unsigned long flags; +	u8 hirq; + +	/* +	 * Read and ack pending interrupts (CPU must never +	 * clear SNDBAV directly and RCVDAV must be cleared by +	 * max3421_recv_data_available()!): +	 */ +	hirq = spi_rd8(hcd, MAX3421_REG_HIRQ); +	hirq &= max3421_hcd->hien; +	if (!hirq) +		return 0; + +	spi_wr8(hcd, MAX3421_REG_HIRQ, +		hirq & ~(BIT(MAX3421_HI_SNDBAV_BIT) | +			 BIT(MAX3421_HI_RCVDAV_BIT))); + +	if (hirq & BIT(MAX3421_HI_FRAME_BIT)) { +		max3421_hcd->frame_number = ((max3421_hcd->frame_number + 1) +					     & USB_MAX_FRAME_NUMBER); +		max3421_hcd->sched_pass = SCHED_PASS_PERIODIC; +	} + +	if (hirq & BIT(MAX3421_HI_RCVDAV_BIT)) +		max3421_recv_data_available(hcd); + +	if (hirq & BIT(MAX3421_HI_HXFRDN_BIT)) +		max3421_host_transfer_done(hcd); + +	if (hirq & BIT(MAX3421_HI_CONDET_BIT)) +		max3421_detect_conn(hcd); + +	/* +	 * Now process interrupts that may affect HCD state +	 * other than the end-points: +	 */ +	spin_lock_irqsave(&max3421_hcd->lock, flags); + +	old_port_status = max3421_hcd->port_status; +	if (hirq & BIT(MAX3421_HI_BUSEVENT_BIT)) { +		if (max3421_hcd->port_status & USB_PORT_STAT_RESET) { +			/* BUSEVENT due to completion of Bus Reset */ +			max3421_hcd->port_status &= ~USB_PORT_STAT_RESET; +			max3421_hcd->port_status |=  USB_PORT_STAT_ENABLE; +		} else { +			/* BUSEVENT due to completion of Bus Resume */ +			pr_info("%s: BUSEVENT Bus Resume Done\n", __func__); +		} +	} +	if (hirq & BIT(MAX3421_HI_RWU_BIT)) +		pr_info("%s: RWU\n", __func__); +	if (hirq & BIT(MAX3421_HI_SUSDN_BIT)) +		pr_info("%s: SUSDN\n", __func__); + +	chg = (old_port_status ^ max3421_hcd->port_status); +	max3421_hcd->port_status |= chg << 16; + +	spin_unlock_irqrestore(&max3421_hcd->lock, flags); + +#ifdef DEBUG +	{ +		static unsigned long last_time; +		char sbuf[16 * 16], *dp, *end; +		int i; + +		if (jiffies - last_time > 5*HZ) { +			dp = sbuf; +			end = sbuf + sizeof(sbuf); +			*dp = '\0'; +			for (i = 0; i < 16; ++i) { +				int ret = snprintf(dp, end - dp, " %lu", +						   max3421_hcd->err_stat[i]); +				if (ret < 0 || ret >= end - dp) +					break;	/* error or buffer full */ +				dp += ret; +			} +			pr_info("%s: hrsl_stats %s\n", __func__, sbuf); +			memset(max3421_hcd->err_stat, 0, +			       sizeof(max3421_hcd->err_stat)); +			last_time = jiffies; + +			dump_eps(hcd); +		} +	} +#endif +	return 1; +} + +static int +max3421_reset_hcd(struct usb_hcd *hcd) +{ +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	int timeout; + +	/* perform a chip reset and wait for OSCIRQ signal to appear: */ +	spi_wr8(hcd, MAX3421_REG_USBCTL, BIT(MAX3421_USBCTL_CHIPRES_BIT)); +	/* clear reset: */ +	spi_wr8(hcd, MAX3421_REG_USBCTL, 0); +	timeout = 1000; +	while (1) { +		if (spi_rd8(hcd, MAX3421_REG_USBIRQ) +		    & BIT(MAX3421_USBIRQ_OSCOKIRQ_BIT)) +			break; +		if (--timeout < 0) { +			dev_err(&spi->dev, +				"timed out waiting for oscillator OK signal"); +			return 1; +		} +		cond_resched(); +	} + +	/* +	 * Turn on host mode, automatic generation of SOF packets, and +	 * enable pull-down registers on DM/DP: +	 */ +	max3421_hcd->mode = (BIT(MAX3421_MODE_HOST_BIT) | +			     BIT(MAX3421_MODE_SOFKAENAB_BIT) | +			     BIT(MAX3421_MODE_DMPULLDN_BIT) | +			     BIT(MAX3421_MODE_DPPULLDN_BIT)); +	spi_wr8(hcd, MAX3421_REG_MODE, max3421_hcd->mode); + +	/* reset frame-number: */ +	max3421_hcd->frame_number = USB_MAX_FRAME_NUMBER; +	spi_wr8(hcd, MAX3421_REG_HCTL, BIT(MAX3421_HCTL_FRMRST_BIT)); + +	/* sample the state of the D+ and D- lines */ +	spi_wr8(hcd, MAX3421_REG_HCTL, BIT(MAX3421_HCTL_SAMPLEBUS_BIT)); +	max3421_detect_conn(hcd); + +	/* enable frame, connection-detected, and bus-event interrupts: */ +	max3421_hcd->hien = (BIT(MAX3421_HI_FRAME_BIT) | +			     BIT(MAX3421_HI_CONDET_BIT) | +			     BIT(MAX3421_HI_BUSEVENT_BIT)); +	spi_wr8(hcd, MAX3421_REG_HIEN, max3421_hcd->hien); + +	/* enable interrupts: */ +	spi_wr8(hcd, MAX3421_REG_CPUCTL, BIT(MAX3421_CPUCTL_IE_BIT)); +	return 1; +} + +static int +max3421_urb_done(struct usb_hcd *hcd) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	unsigned long flags; +	struct urb *urb; +	int status; + +	status = max3421_hcd->urb_done; +	max3421_hcd->urb_done = 0; +	if (status > 0) +		status = 0; +	urb = max3421_hcd->curr_urb; +	if (urb) { +		max3421_hcd->curr_urb = NULL; +		spin_lock_irqsave(&max3421_hcd->lock, flags); +		usb_hcd_unlink_urb_from_ep(hcd, urb); +		spin_unlock_irqrestore(&max3421_hcd->lock, flags); + +		/* must be called without the HCD spinlock: */ +		usb_hcd_giveback_urb(hcd, urb, status); +	} +	return 1; +} + +static int +max3421_spi_thread(void *dev_id) +{ +	struct usb_hcd *hcd = dev_id; +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	int i, i_worked = 1; + +	/* set full-duplex SPI mode, low-active interrupt pin: */ +	spi_wr8(hcd, MAX3421_REG_PINCTL, +		(BIT(MAX3421_PINCTL_FDUPSPI_BIT) |	/* full-duplex */ +		 BIT(MAX3421_PINCTL_INTLEVEL_BIT)));	/* low-active irq */ + +	while (!kthread_should_stop()) { +		max3421_hcd->rev = spi_rd8(hcd, MAX3421_REG_REVISION); +		if (max3421_hcd->rev == 0x12 || max3421_hcd->rev == 0x13) +			break; +		dev_err(&spi->dev, "bad rev 0x%02x", max3421_hcd->rev); +		msleep(10000); +	} +	dev_info(&spi->dev, "rev 0x%x, SPI clk %dHz, bpw %u, irq %d\n", +		 max3421_hcd->rev, spi->max_speed_hz, spi->bits_per_word, +		 spi->irq); + +	while (!kthread_should_stop()) { +		if (!i_worked) { +			/* +			 * We'll be waiting for wakeups from the hard +			 * interrupt handler, so now is a good time to +			 * sync our hien with the chip: +			 */ +			spi_wr8(hcd, MAX3421_REG_HIEN, max3421_hcd->hien); + +			set_current_state(TASK_INTERRUPTIBLE); +			if (max3421_hcd->do_enable_irq) { +				max3421_hcd->do_enable_irq = 0; +				enable_irq(spi->irq); +			} +			schedule(); +			__set_current_state(TASK_RUNNING); +		} + +		i_worked = 0; + +		if (max3421_hcd->urb_done) +			i_worked |= max3421_urb_done(hcd); +		else if (max3421_handle_irqs(hcd)) +			i_worked = 1; +		else if (!max3421_hcd->curr_urb) +			i_worked |= max3421_select_and_start_urb(hcd); + +		if (max3421_hcd->do_reset_hcd) { +			/* reset the HCD: */ +			max3421_hcd->do_reset_hcd = 0; +			i_worked |= max3421_reset_hcd(hcd); +		} +		if (max3421_hcd->do_reset_port) { +			/* perform a USB bus reset: */ +			max3421_hcd->do_reset_port = 0; +			spi_wr8(hcd, MAX3421_REG_HCTL, +				BIT(MAX3421_HCTL_BUSRST_BIT)); +			i_worked = 1; +		} +		if (max3421_hcd->do_check_unlink) { +			max3421_hcd->do_check_unlink = 0; +			i_worked |= max3421_check_unlink(hcd); +		} +		if (max3421_hcd->do_iopin_update) { +			/* +			 * IOPINS1/IOPINS2 do not auto-increment, so we can't +			 * use spi_wr_buf(). +			 */ +			for (i = 0; i < ARRAY_SIZE(max3421_hcd->iopins); ++i) { +				u8 val = spi_rd8(hcd, MAX3421_REG_IOPINS1); + +				val = ((val & 0xf0) | +				       (max3421_hcd->iopins[i] & 0x0f)); +				spi_wr8(hcd, MAX3421_REG_IOPINS1 + i, val); +				max3421_hcd->iopins[i] = val; +			} +			max3421_hcd->do_iopin_update = 0; +			i_worked = 1; +		} +	} +	set_current_state(TASK_RUNNING); +	dev_info(&spi->dev, "SPI thread exiting"); +	return 0; +} + +static int +max3421_reset_port(struct usb_hcd *hcd) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + +	max3421_hcd->port_status &= ~(USB_PORT_STAT_ENABLE | +				      USB_PORT_STAT_LOW_SPEED); +	max3421_hcd->do_reset_port = 1; +	wake_up_process(max3421_hcd->spi_thread); +	return 0; +} + +static int +max3421_reset(struct usb_hcd *hcd) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + +	hcd->self.sg_tablesize = 0; +	hcd->speed = HCD_USB2; +	hcd->self.root_hub->speed = USB_SPEED_FULL; +	max3421_hcd->do_reset_hcd = 1; +	wake_up_process(max3421_hcd->spi_thread); +	return 0; +} + +static int +max3421_start(struct usb_hcd *hcd) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); + +	spin_lock_init(&max3421_hcd->lock); +	max3421_hcd->rh_state = MAX3421_RH_RUNNING; + +	INIT_LIST_HEAD(&max3421_hcd->ep_list); + +	hcd->power_budget = POWER_BUDGET; +	hcd->state = HC_STATE_RUNNING; +	hcd->uses_new_polling = 1; +	return 0; +} + +static void +max3421_stop(struct usb_hcd *hcd) +{ +} + +static int +max3421_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) +{ +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	struct max3421_ep *max3421_ep; +	unsigned long flags; +	int retval; + +	switch (usb_pipetype(urb->pipe)) { +	case PIPE_INTERRUPT: +	case PIPE_ISOCHRONOUS: +		if (urb->interval < 0) { +			dev_err(&spi->dev, +			  "%s: interval=%d for intr-/iso-pipe; expected > 0\n", +				__func__, urb->interval); +			return -EINVAL; +		} +	default: +		break; +	} + +	spin_lock_irqsave(&max3421_hcd->lock, flags); + +	max3421_ep = urb->ep->hcpriv; +	if (!max3421_ep) { +		/* gets freed in max3421_endpoint_disable: */ +		max3421_ep = kzalloc(sizeof(struct max3421_ep), mem_flags); +		if (!max3421_ep) { +			retval = -ENOMEM; +			goto out; +		} +		max3421_ep->ep = urb->ep; +		max3421_ep->last_active = max3421_hcd->frame_number; +		urb->ep->hcpriv = max3421_ep; + +		list_add_tail(&max3421_ep->ep_list, &max3421_hcd->ep_list); +	} + +	retval = usb_hcd_link_urb_to_ep(hcd, urb); +	if (retval == 0) { +		/* Since we added to the queue, restart scheduling: */ +		max3421_hcd->sched_pass = SCHED_PASS_PERIODIC; +		wake_up_process(max3421_hcd->spi_thread); +	} + +out: +	spin_unlock_irqrestore(&max3421_hcd->lock, flags); +	return retval; +} + +static int +max3421_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	unsigned long flags; +	int retval; + +	spin_lock_irqsave(&max3421_hcd->lock, flags); + +	/* +	 * This will set urb->unlinked which in turn causes the entry +	 * to be dropped at the next opportunity. +	 */ +	retval = usb_hcd_check_unlink_urb(hcd, urb, status); +	if (retval == 0) { +		max3421_hcd->do_check_unlink = 1; +		wake_up_process(max3421_hcd->spi_thread); +	} +	spin_unlock_irqrestore(&max3421_hcd->lock, flags); +	return retval; +} + +static void +max3421_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	unsigned long flags; + +	spin_lock_irqsave(&max3421_hcd->lock, flags); + +	if (ep->hcpriv) { +		struct max3421_ep *max3421_ep = ep->hcpriv; + +		/* remove myself from the ep_list: */ +		if (!list_empty(&max3421_ep->ep_list)) +			list_del(&max3421_ep->ep_list); +		kfree(max3421_ep); +		ep->hcpriv = NULL; +	} + +	spin_unlock_irqrestore(&max3421_hcd->lock, flags); +} + +static int +max3421_get_frame_number(struct usb_hcd *hcd) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	return max3421_hcd->frame_number; +} + +/* + * Should return a non-zero value when any port is undergoing a resume + * transition while the root hub is suspended. + */ +static int +max3421_hub_status_data(struct usb_hcd *hcd, char *buf) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	unsigned long flags; +	int retval = 0; + +	spin_lock_irqsave(&max3421_hcd->lock, flags); +	if (!HCD_HW_ACCESSIBLE(hcd)) +		goto done; + +	*buf = 0; +	if ((max3421_hcd->port_status & PORT_C_MASK) != 0) { +		*buf = (1 << 1); /* a hub over-current condition exists */ +		dev_dbg(hcd->self.controller, +			"port status 0x%08x has changes\n", +			max3421_hcd->port_status); +		retval = 1; +		if (max3421_hcd->rh_state == MAX3421_RH_SUSPENDED) +			usb_hcd_resume_root_hub(hcd); +	} +done: +	spin_unlock_irqrestore(&max3421_hcd->lock, flags); +	return retval; +} + +static inline void +hub_descriptor(struct usb_hub_descriptor *desc) +{ +	memset(desc, 0, sizeof(*desc)); +	/* +	 * See Table 11-13: Hub Descriptor in USB 2.0 spec. +	 */ +	desc->bDescriptorType = 0x29;	/* hub descriptor */ +	desc->bDescLength = 9; +	desc->wHubCharacteristics = cpu_to_le16(0x0001); +	desc->bNbrPorts = 1; +} + +/* + * Set the MAX3421E general-purpose output with number PIN_NUMBER to + * VALUE (0 or 1).  PIN_NUMBER may be in the range from 1-8.  For + * any other value, this function acts as a no-op. + */ +static void +max3421_gpout_set_value(struct usb_hcd *hcd, u8 pin_number, u8 value) +{ +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	u8 mask, idx; + +	--pin_number; +	if (pin_number > 7) +		return; + +	mask = 1u << pin_number; +	idx = pin_number / 4; + +	if (value) +		max3421_hcd->iopins[idx] |=  mask; +	else +		max3421_hcd->iopins[idx] &= ~mask; +	max3421_hcd->do_iopin_update = 1; +	wake_up_process(max3421_hcd->spi_thread); +} + +static int +max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index, +		    char *buf, u16 length) +{ +	struct spi_device *spi = to_spi_device(hcd->self.controller); +	struct max3421_hcd *max3421_hcd = hcd_to_max3421(hcd); +	struct max3421_hcd_platform_data *pdata; +	unsigned long flags; +	int retval = 0; + +	spin_lock_irqsave(&max3421_hcd->lock, flags); + +	pdata = spi->dev.platform_data; + +	switch (type_req) { +	case ClearHubFeature: +		break; +	case ClearPortFeature: +		switch (value) { +		case USB_PORT_FEAT_SUSPEND: +			break; +		case USB_PORT_FEAT_POWER: +			dev_dbg(hcd->self.controller, "power-off\n"); +			max3421_gpout_set_value(hcd, pdata->vbus_gpout, +						!pdata->vbus_active_level); +			/* FALLS THROUGH */ +		default: +			max3421_hcd->port_status &= ~(1 << value); +		} +		break; +	case GetHubDescriptor: +		hub_descriptor((struct usb_hub_descriptor *) buf); +		break; + +	case DeviceRequest | USB_REQ_GET_DESCRIPTOR: +	case GetPortErrorCount: +	case SetHubDepth: +		/* USB3 only */ +		goto error; + +	case GetHubStatus: +		*(__le32 *) buf = cpu_to_le32(0); +		break; + +	case GetPortStatus: +		if (index != 1) { +			retval = -EPIPE; +			goto error; +		} +		((__le16 *) buf)[0] = cpu_to_le16(max3421_hcd->port_status); +		((__le16 *) buf)[1] = +			cpu_to_le16(max3421_hcd->port_status >> 16); +		break; + +	case SetHubFeature: +		retval = -EPIPE; +		break; + +	case SetPortFeature: +		switch (value) { +		case USB_PORT_FEAT_LINK_STATE: +		case USB_PORT_FEAT_U1_TIMEOUT: +		case USB_PORT_FEAT_U2_TIMEOUT: +		case USB_PORT_FEAT_BH_PORT_RESET: +			goto error; +		case USB_PORT_FEAT_SUSPEND: +			if (max3421_hcd->active) +				max3421_hcd->port_status |= +					USB_PORT_STAT_SUSPEND; +			break; +		case USB_PORT_FEAT_POWER: +			dev_dbg(hcd->self.controller, "power-on\n"); +			max3421_hcd->port_status |= USB_PORT_STAT_POWER; +			max3421_gpout_set_value(hcd, pdata->vbus_gpout, +						pdata->vbus_active_level); +			break; +		case USB_PORT_FEAT_RESET: +			max3421_reset_port(hcd); +			/* FALLS THROUGH */ +		default: +			if ((max3421_hcd->port_status & USB_PORT_STAT_POWER) +			    != 0) +				max3421_hcd->port_status |= (1 << value); +		} +		break; + +	default: +		dev_dbg(hcd->self.controller, +			"hub control req%04x v%04x i%04x l%d\n", +			type_req, value, index, length); +error:		/* "protocol stall" on error */ +		retval = -EPIPE; +	} + +	spin_unlock_irqrestore(&max3421_hcd->lock, flags); +	return retval; +} + +static int +max3421_bus_suspend(struct usb_hcd *hcd) +{ +	return -1; +} + +static int +max3421_bus_resume(struct usb_hcd *hcd) +{ +	return -1; +} + +/* + * The SPI driver already takes care of DMA-mapping/unmapping, so no + * reason to do it twice. + */ +static int +max3421_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) +{ +	return 0; +} + +static void +max3421_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ +} + +static struct hc_driver max3421_hcd_desc = { +	.description =		"max3421", +	.product_desc =		DRIVER_DESC, +	.hcd_priv_size =	sizeof(struct max3421_hcd), +	.flags =		HCD_USB11, +	.reset =		max3421_reset, +	.start =		max3421_start, +	.stop =			max3421_stop, +	.get_frame_number =	max3421_get_frame_number, +	.urb_enqueue =		max3421_urb_enqueue, +	.urb_dequeue =		max3421_urb_dequeue, +	.map_urb_for_dma =	max3421_map_urb_for_dma, +	.unmap_urb_for_dma =	max3421_unmap_urb_for_dma, +	.endpoint_disable =	max3421_endpoint_disable, +	.hub_status_data =	max3421_hub_status_data, +	.hub_control =		max3421_hub_control, +	.bus_suspend =		max3421_bus_suspend, +	.bus_resume =		max3421_bus_resume, +}; + +static int +max3421_probe(struct spi_device *spi) +{ +	struct max3421_hcd *max3421_hcd; +	struct usb_hcd *hcd = NULL; +	int retval = -ENOMEM; + +	if (spi_setup(spi) < 0) { +		dev_err(&spi->dev, "Unable to setup SPI bus"); +		return -EFAULT; +	} + +	hcd = usb_create_hcd(&max3421_hcd_desc, &spi->dev, +			     dev_name(&spi->dev)); +	if (!hcd) { +		dev_err(&spi->dev, "failed to create HCD structure\n"); +		goto error; +	} +	set_bit(HCD_FLAG_POLL_RH, &hcd->flags); +	max3421_hcd = hcd_to_max3421(hcd); +	max3421_hcd->next = max3421_hcd_list; +	max3421_hcd_list = max3421_hcd; +	INIT_LIST_HEAD(&max3421_hcd->ep_list); + +	max3421_hcd->tx = kmalloc(sizeof(*max3421_hcd->tx), GFP_KERNEL); +	if (!max3421_hcd->tx) { +		dev_err(&spi->dev, "failed to kmalloc tx buffer\n"); +		goto error; +	} +	max3421_hcd->rx = kmalloc(sizeof(*max3421_hcd->rx), GFP_KERNEL); +	if (!max3421_hcd->rx) { +		dev_err(&spi->dev, "failed to kmalloc rx buffer\n"); +		goto error; +	} + +	max3421_hcd->spi_thread = kthread_run(max3421_spi_thread, hcd, +					      "max3421_spi_thread"); +	if (max3421_hcd->spi_thread == ERR_PTR(-ENOMEM)) { +		dev_err(&spi->dev, +			"failed to create SPI thread (out of memory)\n"); +		goto error; +	} + +	retval = usb_add_hcd(hcd, 0, 0); +	if (retval) { +		dev_err(&spi->dev, "failed to add HCD\n"); +		goto error; +	} + +	retval = request_irq(spi->irq, max3421_irq_handler, +			     IRQF_TRIGGER_LOW, "max3421", hcd); +	if (retval < 0) { +		dev_err(&spi->dev, "failed to request irq %d\n", spi->irq); +		goto error; +	} +	return 0; + +error: +	if (hcd) { +		kfree(max3421_hcd->tx); +		kfree(max3421_hcd->rx); +		if (max3421_hcd->spi_thread) +			kthread_stop(max3421_hcd->spi_thread); +		usb_put_hcd(hcd); +	} +	return retval; +} + +static int +max3421_remove(struct spi_device *spi) +{ +	struct max3421_hcd *max3421_hcd = NULL, **prev; +	struct usb_hcd *hcd = NULL; +	unsigned long flags; + +	for (prev = &max3421_hcd_list; *prev; prev = &(*prev)->next) { +		max3421_hcd = *prev; +		hcd = max3421_to_hcd(max3421_hcd); +		if (hcd->self.controller == &spi->dev) +			break; +	} +	if (!max3421_hcd) { +		dev_err(&spi->dev, "no MAX3421 HCD found for SPI device %p\n", +			spi); +		return -ENODEV; +	} + +	usb_remove_hcd(hcd); + +	spin_lock_irqsave(&max3421_hcd->lock, flags); + +	kthread_stop(max3421_hcd->spi_thread); +	*prev = max3421_hcd->next; + +	spin_unlock_irqrestore(&max3421_hcd->lock, flags); + +	free_irq(spi->irq, hcd); + +	usb_put_hcd(hcd); +	return 0; +} + +static struct spi_driver max3421_driver = { +	.probe		= max3421_probe, +	.remove		= max3421_remove, +	.driver		= { +		.name	= "max3421-hcd", +		.owner	= THIS_MODULE, +	}, +}; + +module_spi_driver(max3421_driver); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("David Mosberger <davidm@egauge.net>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index caa3764a340..e49eb4f90f5 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -13,19 +13,24 @@   */  #include <linux/clk.h> -#include <linux/platform_device.h> +#include <linux/dma-mapping.h>  #include <linux/of_platform.h>  #include <linux/of_gpio.h> +#include <linux/platform_device.h>  #include <linux/platform_data/atmel.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h>  #include <mach/hardware.h>  #include <asm/gpio.h>  #include <mach/cpu.h> -#ifndef CONFIG_ARCH_AT91 -#error "CONFIG_ARCH_AT91 must be defined." -#endif + +#include "ohci.h"  #define valid_port(index)	((index) >= 0 && (index) < AT91_MAX_USBH_PORTS)  #define at91_for_each_port(index)	\ @@ -33,6 +38,13 @@  /* interface, function and usb clocks; sometimes also an AHB clock */  static struct clk *iclk, *fclk, *uclk, *hclk; +/* interface and function clocks; sometimes also an AHB clock */ + +#define DRIVER_DESC "OHCI Atmel driver" + +static const char hcd_name[] = "ohci-atmel"; + +static struct hc_driver __read_mostly ohci_at91_hc_driver;  static int clocked;  extern int usb_disabled(void); @@ -117,92 +129,80 @@ static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);  static int usb_hcd_at91_probe(const struct hc_driver *driver,  			struct platform_device *pdev)  { +	struct at91_usbh_data *board; +	struct ohci_hcd *ohci;  	int retval;  	struct usb_hcd *hcd = NULL; - -	if (pdev->num_resources != 2) { -		pr_debug("hcd probe: invalid num_resources"); -		return -ENODEV; +	struct device *dev = &pdev->dev; +	struct resource *res; +	int irq; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!res) { +		dev_dbg(dev, "hcd probe: missing memory resource\n"); +		return -ENXIO;  	} -	if ((pdev->resource[0].flags != IORESOURCE_MEM) -			|| (pdev->resource[1].flags != IORESOURCE_IRQ)) { -		pr_debug("hcd probe: invalid resource type\n"); -		return -ENODEV; +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) { +		dev_dbg(dev, "hcd probe: missing irq resource\n"); +		return irq;  	} -	hcd = usb_create_hcd(driver, &pdev->dev, "at91"); +	hcd = usb_create_hcd(driver, dev, "at91");  	if (!hcd)  		return -ENOMEM; -	hcd->rsrc_start = pdev->resource[0].start; -	hcd->rsrc_len = resource_size(&pdev->resource[0]); - -	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { -		pr_debug("request_mem_region failed\n"); -		retval = -EBUSY; -		goto err1; -	} +	hcd->rsrc_start = res->start; +	hcd->rsrc_len = resource_size(res); -	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); -	if (!hcd->regs) { -		pr_debug("ioremap failed\n"); -		retval = -EIO; -		goto err2; +	hcd->regs = devm_ioremap_resource(dev, res); +	if (IS_ERR(hcd->regs)) { +		retval = PTR_ERR(hcd->regs); +		goto err;  	} -	iclk = clk_get(&pdev->dev, "ohci_clk"); +	iclk = devm_clk_get(dev, "ohci_clk");  	if (IS_ERR(iclk)) { -		dev_err(&pdev->dev, "failed to get ohci_clk\n"); +		dev_err(dev, "failed to get ohci_clk\n");  		retval = PTR_ERR(iclk); -		goto err3; +		goto err;  	} -	fclk = clk_get(&pdev->dev, "uhpck"); +	fclk = devm_clk_get(dev, "uhpck");  	if (IS_ERR(fclk)) { -		dev_err(&pdev->dev, "failed to get uhpck\n"); +		dev_err(dev, "failed to get uhpck\n");  		retval = PTR_ERR(fclk); -		goto err4; +		goto err;  	} -	hclk = clk_get(&pdev->dev, "hclk"); +	hclk = devm_clk_get(dev, "hclk");  	if (IS_ERR(hclk)) { -		dev_err(&pdev->dev, "failed to get hclk\n"); +		dev_err(dev, "failed to get hclk\n");  		retval = PTR_ERR(hclk); -		goto err5; +		goto err;  	}  	if (IS_ENABLED(CONFIG_COMMON_CLK)) { -		uclk = clk_get(&pdev->dev, "usb_clk"); +		uclk = devm_clk_get(dev, "usb_clk");  		if (IS_ERR(uclk)) { -			dev_err(&pdev->dev, "failed to get uclk\n"); +			dev_err(dev, "failed to get uclk\n");  			retval = PTR_ERR(uclk); -			goto err6; +			goto err;  		}  	} +	board = hcd->self.controller->platform_data; +	ohci = hcd_to_ohci(hcd); +	ohci->num_ports = board->ports;  	at91_start_hc(pdev); -	ohci_hcd_init(hcd_to_ohci(hcd)); -	retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED); -	if (retval == 0) +	retval = usb_add_hcd(hcd, irq, IRQF_SHARED); +	if (retval == 0) { +		device_wakeup_enable(hcd->self.controller);  		return retval; +	}  	/* Error handling */  	at91_stop_hc(pdev); -	if (IS_ENABLED(CONFIG_COMMON_CLK)) -		clk_put(uclk); - err6: -	clk_put(hclk); - err5: -	clk_put(fclk); - err4: -	clk_put(iclk); - - err3: -	iounmap(hcd->regs); - - err2: -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - - err1: + err:  	usb_put_hcd(hcd);  	return retval;  } @@ -225,49 +225,10 @@ static void usb_hcd_at91_remove(struct usb_hcd *hcd,  {  	usb_remove_hcd(hcd);  	at91_stop_hc(pdev); -	iounmap(hcd->regs); -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	usb_put_hcd(hcd); - -	if (IS_ENABLED(CONFIG_COMMON_CLK)) -		clk_put(uclk); -	clk_put(hclk); -	clk_put(fclk); -	clk_put(iclk); -	fclk = iclk = hclk = NULL;  }  /*-------------------------------------------------------------------------*/ - -static int -ohci_at91_reset (struct usb_hcd *hcd) -{ -	struct at91_usbh_data	*board = dev_get_platdata(hcd->self.controller); -	struct ohci_hcd		*ohci = hcd_to_ohci (hcd); -	int			ret; - -	if ((ret = ohci_init(ohci)) < 0) -		return ret; - -	ohci->num_ports = board->ports; -	return 0; -} - -static int -ohci_at91_start (struct usb_hcd *hcd) -{ -	struct ohci_hcd		*ohci = hcd_to_ohci (hcd); -	int			ret; - -	if ((ret = ohci_run(ohci)) < 0) { -		dev_err(hcd->self.controller, "can't start %s\n", -			hcd->self.bus_name); -		ohci_stop(hcd); -		return ret; -	} -	return 0; -} -  static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable)  {  	if (!valid_port(port)) @@ -297,7 +258,7 @@ static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port)   */  static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf)  { -	struct at91_usbh_data *pdata = dev_get_platdata(hcd->self.controller); +	struct at91_usbh_data *pdata = hcd->self.controller->platform_data;  	int length = ohci_hub_status_data(hcd, buf);  	int port; @@ -430,51 +391,6 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  /*-------------------------------------------------------------------------*/ -static const struct hc_driver ohci_at91_hc_driver = { -	.description =		hcd_name, -	.product_desc =		"AT91 OHCI", -	.hcd_priv_size =	sizeof(struct ohci_hcd), - -	/* -	 * generic hardware linkage -	 */ -	.irq =			ohci_irq, -	.flags =		HCD_USB11 | HCD_MEMORY, - -	/* -	 * basic lifecycle operations -	 */ -	.reset =		ohci_at91_reset, -	.start =		ohci_at91_start, -	.stop =			ohci_stop, -	.shutdown =		ohci_shutdown, - -	/* -	 * managing i/o requests and associated device resources -	 */ -	.urb_enqueue =		ohci_urb_enqueue, -	.urb_dequeue =		ohci_urb_dequeue, -	.endpoint_disable =	ohci_endpoint_disable, - -	/* -	 * scheduling support -	 */ -	.get_frame_number =	ohci_get_frame, - -	/* -	 * root hub support -	 */ -	.hub_status_data =	ohci_at91_hub_status_data, -	.hub_control =		ohci_at91_hub_control, -#ifdef CONFIG_PM -	.bus_suspend =		ohci_bus_suspend, -	.bus_resume =		ohci_bus_resume, -#endif -	.start_port_reset =	ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ -  static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)  {  	struct platform_device *pdev = data; @@ -524,7 +440,7 @@ MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids);  static int ohci_at91_of_init(struct platform_device *pdev)  {  	struct device_node *np = pdev->dev.of_node; -	int i, gpio; +	int i, gpio, ret;  	enum of_gpio_flags flags;  	struct at91_usbh_data	*pdata;  	u32 ports; @@ -536,10 +452,9 @@ static int ohci_at91_of_init(struct platform_device *pdev)  	 * 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 = &pdev->dev.coherent_dma_mask; -	if (!pdev->dev.coherent_dma_mask) -		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (ret) +		return ret;  	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);  	if (!pdata) @@ -691,10 +606,17 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)  {  	struct usb_hcd	*hcd = platform_get_drvdata(pdev);  	struct ohci_hcd	*ohci = hcd_to_ohci(hcd); +	bool		do_wakeup = device_may_wakeup(&pdev->dev); +	int		ret; -	if (device_may_wakeup(&pdev->dev)) +	if (do_wakeup)  		enable_irq_wake(hcd->irq); +	ret = ohci_suspend(hcd, do_wakeup); +	if (ret) { +		disable_irq_wake(hcd->irq); +		return ret; +	}  	/*  	 * The integrated transceivers seem unable to notice disconnect,  	 * reconnect, or wakeup without the 48 MHz clock active.  so for @@ -703,13 +625,17 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)  	 * REVISIT: some boards will be able to turn VBUS off...  	 */  	if (at91_suspend_entering_slow_clock()) { -		ohci_usb_reset (ohci); +		ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); +		ohci->hc_control &= OHCI_CTRL_RWC; +		ohci_writel(ohci, ohci->hc_control, &ohci->regs->control); +		ohci->rh_state = OHCI_RH_HALTED; +  		/* flush the writes */  		(void) ohci_readl (ohci, &ohci->regs->control);  		at91_stop_clock();  	} -	return 0; +	return ret;  }  static int ohci_hcd_at91_drv_resume(struct platform_device *pdev) @@ -730,8 +656,6 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)  #define ohci_hcd_at91_drv_resume  NULL  #endif -MODULE_ALIAS("platform:at91_ohci"); -  static struct platform_driver ohci_hcd_at91_driver = {  	.probe		= ohci_hcd_at91_drv_probe,  	.remove		= ohci_hcd_at91_drv_remove, @@ -744,3 +668,37 @@ static struct platform_driver ohci_hcd_at91_driver = {  		.of_match_table	= of_match_ptr(at91_ohci_dt_ids),  	},  }; + +static int __init ohci_at91_init(void) +{ +	if (usb_disabled()) +		return -ENODEV; + +	pr_info("%s: " DRIVER_DESC "\n", hcd_name); +	ohci_init_driver(&ohci_at91_hc_driver, NULL); + +	/* +	 * The Atmel HW has some unusual quirks, which require Atmel-specific +	 * workarounds. We override certain hc_driver functions here to +	 * achieve that. We explicitly do not enhance ohci_driver_overrides to +	 * allow this more easily, since this is an unusual case, and we don't +	 * want to encourage others to override these functions by making it +	 * too easy. +	 */ + +	ohci_at91_hc_driver.hub_status_data	= ohci_at91_hub_status_data; +	ohci_at91_hc_driver.hub_control		= ohci_at91_hub_control; + +	return platform_driver_register(&ohci_hcd_at91_driver); +} +module_init(ohci_at91_init); + +static void __exit ohci_at91_cleanup(void) +{ +	platform_driver_unregister(&ohci_hcd_at91_driver); +} +module_exit(ohci_at91_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:at91_ohci"); diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index 9be59f11e05..df06be6b47f 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -300,41 +300,28 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver,  	if (hub == NULL)  		return -ENODEV; -	usb11_clk = clk_get(&pdev->dev, "usb11"); +	usb11_clk = devm_clk_get(&pdev->dev, "usb11");  	if (IS_ERR(usb11_clk))  		return PTR_ERR(usb11_clk); -	usb20_clk = clk_get(&pdev->dev, "usb20"); -	if (IS_ERR(usb20_clk)) { -		error = PTR_ERR(usb20_clk); -		goto err0; -	} +	usb20_clk = devm_clk_get(&pdev->dev, "usb20"); +	if (IS_ERR(usb20_clk)) +		return PTR_ERR(usb20_clk);  	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); -	if (!hcd) { -		error = -ENOMEM; -		goto err1; -	} +	if (!hcd) +		return -ENOMEM;  	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!mem) { -		error = -ENODEV; -		goto err2; -	} +	if (!mem) +		return -ENODEV;  	hcd->rsrc_start = mem->start;  	hcd->rsrc_len = resource_size(mem); -	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { -		dev_dbg(&pdev->dev, "request_mem_region failed\n"); -		error = -EBUSY; -		goto err2; -	} - -	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); -	if (!hcd->regs) { -		dev_err(&pdev->dev, "ioremap failed\n"); -		error = -ENOMEM; -		goto err3; +	hcd->regs = devm_ioremap_resource(&pdev->dev, mem); +	if (IS_ERR(hcd->regs)) { +		error = PTR_ERR(hcd->regs); +		goto err;  	}  	ohci_hcd_init(hcd_to_ohci(hcd)); @@ -342,11 +329,13 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver,  	irq = platform_get_irq(pdev, 0);  	if (irq < 0) {  		error = -ENODEV; -		goto err4; +		goto err;  	}  	error = usb_add_hcd(hcd, irq, 0);  	if (error) -		goto err4; +		goto err; + +	device_wakeup_enable(hcd->self.controller);  	if (hub->ocic_notify) {  		error = hub->ocic_notify(ohci_da8xx_ocic_handler); @@ -355,16 +344,8 @@ static int usb_hcd_da8xx_probe(const struct hc_driver *driver,  	}  	usb_remove_hcd(hcd); -err4: -	iounmap(hcd->regs); -err3: -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -err2: +err:  	usb_put_hcd(hcd); -err1: -	clk_put(usb20_clk); -err0: -	clk_put(usb11_clk);  	return error;  } @@ -384,11 +365,7 @@ usb_hcd_da8xx_remove(struct usb_hcd *hcd, struct platform_device *pdev)  	hub->ocic_notify(NULL);  	usb_remove_hcd(hcd); -	iounmap(hcd->regs); -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	usb_put_hcd(hcd); -	clk_put(usb20_clk); -	clk_put(usb11_clk);  }  static int ohci_hcd_da8xx_drv_probe(struct platform_device *dev) @@ -406,19 +383,27 @@ static int ohci_hcd_da8xx_drv_remove(struct platform_device *dev)  }  #ifdef CONFIG_PM -static int ohci_da8xx_suspend(struct platform_device *dev, pm_message_t message) +static int ohci_da8xx_suspend(struct platform_device *pdev, +				pm_message_t message)  { -	struct usb_hcd	*hcd	= platform_get_drvdata(dev); +	struct usb_hcd	*hcd	= platform_get_drvdata(pdev);  	struct ohci_hcd	*ohci	= hcd_to_ohci(hcd); +	bool		do_wakeup	= device_may_wakeup(&pdev->dev); +	int		ret; +  	if (time_before(jiffies, ohci->next_statechange))  		msleep(5);  	ohci->next_statechange = jiffies; +	ret = ohci_suspend(hcd, do_wakeup); +	if (ret) +		return ret; +  	ohci_da8xx_clock(0);  	hcd->state = HC_STATE_SUSPENDED; -	dev->dev.power.power_state = PMSG_SUSPEND; -	return 0; + +	return ret;  }  static int ohci_da8xx_resume(struct platform_device *dev) diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 31b81f9eacd..45032e933e1 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -9,68 +9,15 @@  /*-------------------------------------------------------------------------*/ -#ifdef DEBUG -  #define edstring(ed_type) ({ char *temp; \  	switch (ed_type) { \  	case PIPE_CONTROL:	temp = "ctrl"; break; \  	case PIPE_BULK:		temp = "bulk"; break; \  	case PIPE_INTERRUPT:	temp = "intr"; break; \  	default:		temp = "isoc"; break; \ -	}; temp;}) +	} temp;})  #define pipestring(pipe) edstring(usb_pipetype(pipe)) -/* debug| print the main components of an URB - * small: 0) header + data packets 1) just header - */ -static void __maybe_unused -urb_print(struct urb * urb, char * str, int small, int status) -{ -	unsigned int pipe= urb->pipe; - -	if (!urb->dev || !urb->dev->bus) { -		printk(KERN_DEBUG "%s URB: no dev\n", str); -		return; -	} - -#ifndef	OHCI_VERBOSE_DEBUG -	if (status != 0) -#endif -	printk(KERN_DEBUG "%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d\n", -		    str, -		    urb, -		    usb_pipedevice (pipe), -		    usb_pipeendpoint (pipe), -		    usb_pipeout (pipe)? "out" : "in", -		    pipestring (pipe), -		    urb->transfer_flags, -		    urb->actual_length, -		    urb->transfer_buffer_length, -		    status); - -#ifdef	OHCI_VERBOSE_DEBUG -	if (!small) { -		int i, len; - -		if (usb_pipecontrol (pipe)) { -			printk (KERN_DEBUG "%s: setup(8):", __FILE__); -			for (i = 0; i < 8 ; i++) -				printk (" %02x", ((__u8 *) urb->setup_packet) [i]); -			printk ("\n"); -		} -		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) { -			printk (KERN_DEBUG "%s: data(%d/%d):", __FILE__, -				urb->actual_length, -				urb->transfer_buffer_length); -			len = usb_pipeout (pipe)? -						urb->transfer_buffer_length: urb->actual_length; -			for (i = 0; i < 16 && i < len; i++) -				printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]); -			printk ("%s stat:%d\n", i < len? "...": "", status); -		} -	} -#endif -}  #define ohci_dbg_sw(ohci, next, size, format, arg...) \  	do { \ @@ -407,22 +354,8 @@ ohci_dump_ed (const struct ohci_hcd *ohci, const char *label,  	}  } -#else -static inline void ohci_dump (struct ohci_hcd *controller, int verbose) {} - -#undef OHCI_VERBOSE_DEBUG - -#endif /* DEBUG */ -  /*-------------------------------------------------------------------------*/ -#ifdef STUB_DEBUG_FILES - -static inline void create_debug_files (struct ohci_hcd *bus) { } -static inline void remove_debug_files (struct ohci_hcd *bus) { } - -#else -  static int debug_async_open(struct inode *, struct file *);  static int debug_periodic_open(struct inode *, struct file *);  static int debug_registers_open(struct inode *, struct file *); @@ -871,7 +804,5 @@ static inline void remove_debug_files (struct ohci_hcd *ohci)  	debugfs_remove(ohci->debug_dir);  } -#endif -  /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c deleted file mode 100644 index 84a20d5223b..00000000000 --- a/drivers/usb/host/ohci-ep93xx.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> - * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> - * (C) Copyright 2002 Hewlett-Packard Company - * - * Bus Glue for ep93xx. - * - * Written by Christopher Hoover <ch@hpl.hp.com> - * Based on fragments of previous driver by Russell King et al. - * - * Modified for LH7A404 from ohci-sa1111.c - *  by Durgesh Pattamatta <pattamattad@sharpsec.com> - * - * Modified for pxa27x from ohci-lh7a404.c - *  by Nick Bane <nick@cecomputing.co.uk> 26-8-2004 - * - * Modified for ep93xx from ohci-pxa27x.c - *  by Lennert Buytenhek <buytenh@wantstofly.org> 28-2-2006 - *  Based on an earlier driver by Ray Lehtiniemi - * - * This file is licenced under the GPL. - */ - -#include <linux/clk.h> -#include <linux/device.h> -#include <linux/signal.h> -#include <linux/platform_device.h> - -static struct clk *usb_host_clock; - -static int ohci_ep93xx_start(struct usb_hcd *hcd) -{ -	struct ohci_hcd *ohci = hcd_to_ohci(hcd); -	int ret; - -	if ((ret = ohci_init(ohci)) < 0) -		return ret; - -	if ((ret = ohci_run(ohci)) < 0) { -		dev_err(hcd->self.controller, "can't start %s\n", -			hcd->self.bus_name); -		ohci_stop(hcd); -		return ret; -	} - -	return 0; -} - -static struct hc_driver ohci_ep93xx_hc_driver = { -	.description		= hcd_name, -	.product_desc		= "EP93xx OHCI", -	.hcd_priv_size		= sizeof(struct ohci_hcd), -	.irq			= ohci_irq, -	.flags			= HCD_USB11 | HCD_MEMORY, -	.start			= ohci_ep93xx_start, -	.stop			= ohci_stop, -	.shutdown		= ohci_shutdown, -	.urb_enqueue		= ohci_urb_enqueue, -	.urb_dequeue		= ohci_urb_dequeue, -	.endpoint_disable	= ohci_endpoint_disable, -	.get_frame_number	= ohci_get_frame, -	.hub_status_data	= ohci_hub_status_data, -	.hub_control		= ohci_hub_control, -#ifdef CONFIG_PM -	.bus_suspend		= ohci_bus_suspend, -	.bus_resume		= ohci_bus_resume, -#endif -	.start_port_reset	= ohci_start_port_reset, -}; - -static int ohci_hcd_ep93xx_drv_probe(struct platform_device *pdev) -{ -	struct usb_hcd *hcd; -	struct resource *res; -	int irq; -	int ret; - -	if (usb_disabled()) -		return -ENODEV; - -	irq = platform_get_irq(pdev, 0); -	if (irq < 0) -		return irq; - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) -		return -ENXIO; - -	hcd = usb_create_hcd(&ohci_ep93xx_hc_driver, &pdev->dev, "ep93xx"); -	if (!hcd) -		return -ENOMEM; - -	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 err_put_hcd; -	} - -	usb_host_clock = devm_clk_get(&pdev->dev, NULL); -	if (IS_ERR(usb_host_clock)) { -		ret = PTR_ERR(usb_host_clock); -		goto err_put_hcd; -	} - -	clk_enable(usb_host_clock); - -	ohci_hcd_init(hcd_to_ohci(hcd)); - -	ret = usb_add_hcd(hcd, irq, 0); -	if (ret) -		goto err_clk_disable; - -	return 0; - -err_clk_disable: -	clk_disable(usb_host_clock); -err_put_hcd: -	usb_put_hcd(hcd); - -	return ret; -} - -static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev) -{ -	struct usb_hcd *hcd = platform_get_drvdata(pdev); - -	usb_remove_hcd(hcd); -	clk_disable(usb_host_clock); -	usb_put_hcd(hcd); - -	return 0; -} - -#ifdef CONFIG_PM -static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_t state) -{ -	struct usb_hcd *hcd = platform_get_drvdata(pdev); -	struct ohci_hcd *ohci = hcd_to_ohci(hcd); - -	if (time_before(jiffies, ohci->next_statechange)) -		msleep(5); -	ohci->next_statechange = jiffies; - -	clk_disable(usb_host_clock); -	return 0; -} - -static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev) -{ -	struct usb_hcd *hcd = platform_get_drvdata(pdev); -	struct ohci_hcd *ohci = hcd_to_ohci(hcd); - -	if (time_before(jiffies, ohci->next_statechange)) -		msleep(5); -	ohci->next_statechange = jiffies; - -	clk_enable(usb_host_clock); - -	ohci_resume(hcd, false); -	return 0; -} -#endif - - -static struct platform_driver ohci_hcd_ep93xx_driver = { -	.probe		= ohci_hcd_ep93xx_drv_probe, -	.remove		= ohci_hcd_ep93xx_drv_remove, -	.shutdown	= usb_hcd_platform_shutdown, -#ifdef CONFIG_PM -	.suspend	= ohci_hcd_ep93xx_drv_suspend, -	.resume		= ohci_hcd_ep93xx_drv_resume, -#endif -	.driver		= { -		.name	= "ep93xx-ohci", -		.owner	= THIS_MODULE, -	}, -}; - -MODULE_ALIAS("platform:ep93xx-ohci"); diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index dc6ee9adacf..060a6a41475 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -12,100 +12,139 @@   */  #include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h>  #include <linux/of.h>  #include <linux/platform_device.h> -#include <linux/platform_data/usb-ohci-exynos.h> +#include <linux/phy/phy.h>  #include <linux/usb/phy.h>  #include <linux/usb/samsung_usb_phy.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/usb/otg.h> + +#include "ohci.h" + +#define DRIVER_DESC "OHCI EXYNOS driver" + +static const char hcd_name[] = "ohci-exynos"; +static struct hc_driver __read_mostly exynos_ohci_hc_driver; + +#define to_exynos_ohci(hcd) (struct exynos_ohci_hcd *)(hcd_to_ohci(hcd)->priv) + +#define PHY_NUMBER 3  struct exynos_ohci_hcd { -	struct device *dev; -	struct usb_hcd *hcd;  	struct clk *clk;  	struct usb_phy *phy;  	struct usb_otg *otg; -	struct exynos4_ohci_platdata *pdata; +	struct phy *phy_g[PHY_NUMBER];  }; -static void exynos_ohci_phy_enable(struct exynos_ohci_hcd *exynos_ohci) +static int exynos_ohci_get_phy(struct device *dev, +				struct exynos_ohci_hcd *exynos_ohci)  { -	struct platform_device *pdev = to_platform_device(exynos_ohci->dev); +	struct device_node *child; +	struct phy *phy; +	int phy_number; +	int ret = 0; + +	exynos_ohci->phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); +	if (IS_ERR(exynos_ohci->phy)) { +		ret = PTR_ERR(exynos_ohci->phy); +		if (ret != -ENXIO && ret != -ENODEV) { +			dev_err(dev, "no usb2 phy configured\n"); +			return ret; +		} +		dev_dbg(dev, "Failed to get usb2 phy\n"); +	} else { +		exynos_ohci->otg = exynos_ohci->phy->otg; +	} -	if (exynos_ohci->phy) -		usb_phy_init(exynos_ohci->phy); -	else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_init) -		exynos_ohci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); -} +	/* +	 * Getting generic phy: +	 * We are keeping both types of phys as a part of transiting OHCI +	 * to generic phy framework, so as to maintain backward compatibilty +	 * with old DTB. +	 * If there are existing devices using DTB files built from them, +	 * to remove the support for old bindings in this driver, +	 * we need to make sure that such devices have their DTBs +	 * updated to ones built from new DTS. +	 */ +	for_each_available_child_of_node(dev->of_node, child) { +		ret = of_property_read_u32(child, "reg", &phy_number); +		if (ret) { +			dev_err(dev, "Failed to parse device tree\n"); +			of_node_put(child); +			return ret; +		} -static void exynos_ohci_phy_disable(struct exynos_ohci_hcd *exynos_ohci) -{ -	struct platform_device *pdev = to_platform_device(exynos_ohci->dev); +		if (phy_number >= PHY_NUMBER) { +			dev_err(dev, "Invalid number of PHYs\n"); +			of_node_put(child); +			return -EINVAL; +		} -	if (exynos_ohci->phy) -		usb_phy_shutdown(exynos_ohci->phy); -	else if (exynos_ohci->pdata && exynos_ohci->pdata->phy_exit) -		exynos_ohci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); +		phy = devm_of_phy_get(dev, child, 0); +		of_node_put(child); +		if (IS_ERR(phy)) { +			ret = PTR_ERR(phy); +			if (ret != -ENOSYS && ret != -ENODEV) { +				dev_err(dev, "no usb2 phy configured\n"); +				return ret; +			} +			dev_dbg(dev, "Failed to get usb2 phy\n"); +		} +		exynos_ohci->phy_g[phy_number] = phy; +	} + +	return ret;  } -static int ohci_exynos_reset(struct usb_hcd *hcd) +static int exynos_ohci_phy_enable(struct device *dev)  { -	return ohci_init(hcd_to_ohci(hcd)); +	struct usb_hcd *hcd = dev_get_drvdata(dev); +	struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); +	int i; +	int ret = 0; + +	if (!IS_ERR(exynos_ohci->phy)) +		return usb_phy_init(exynos_ohci->phy); + +	for (i = 0; ret == 0 && i < PHY_NUMBER; i++) +		if (!IS_ERR(exynos_ohci->phy_g[i])) +			ret = phy_power_on(exynos_ohci->phy_g[i]); +	if (ret) +		for (i--; i >= 0; i--) +			if (!IS_ERR(exynos_ohci->phy_g[i])) +				phy_power_off(exynos_ohci->phy_g[i]); + +	return ret;  } -static int ohci_exynos_start(struct usb_hcd *hcd) +static void exynos_ohci_phy_disable(struct device *dev)  { -	struct ohci_hcd *ohci = hcd_to_ohci(hcd); -	int ret; - -	ohci_dbg(ohci, "ohci_exynos_start, ohci:%p", ohci); +	struct usb_hcd *hcd = dev_get_drvdata(dev); +	struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); +	int i; -	ret = ohci_run(ohci); -	if (ret < 0) { -		dev_err(hcd->self.controller, "can't start %s\n", -			hcd->self.bus_name); -		ohci_stop(hcd); -		return ret; +	if (!IS_ERR(exynos_ohci->phy)) { +		usb_phy_shutdown(exynos_ohci->phy); +		return;  	} -	return 0; +	for (i = 0; i < PHY_NUMBER; i++) +		if (!IS_ERR(exynos_ohci->phy_g[i])) +			phy_power_off(exynos_ohci->phy_g[i]);  } -static const struct hc_driver exynos_ohci_hc_driver = { -	.description		= hcd_name, -	.product_desc		= "EXYNOS OHCI Host Controller", -	.hcd_priv_size		= sizeof(struct ohci_hcd), - -	.irq			= ohci_irq, -	.flags			= HCD_MEMORY|HCD_USB11, - -	.reset			= ohci_exynos_reset, -	.start			= ohci_exynos_start, -	.stop			= ohci_stop, -	.shutdown		= ohci_shutdown, - -	.get_frame_number	= ohci_get_frame, - -	.urb_enqueue		= ohci_urb_enqueue, -	.urb_dequeue		= ohci_urb_dequeue, -	.endpoint_disable	= ohci_endpoint_disable, - -	.hub_status_data	= ohci_hub_status_data, -	.hub_control		= ohci_hub_control, -#ifdef	CONFIG_PM -	.bus_suspend		= ohci_bus_suspend, -	.bus_resume		= ohci_bus_resume, -#endif -	.start_port_reset	= ohci_start_port_reset, -}; -  static int exynos_ohci_probe(struct platform_device *pdev)  { -	struct exynos4_ohci_platdata *pdata = dev_get_platdata(&pdev->dev);  	struct exynos_ohci_hcd *exynos_ohci;  	struct usb_hcd *hcd; -	struct ohci_hcd *ohci;  	struct resource *res; -	struct usb_phy *phy;  	int irq;  	int err; @@ -114,46 +153,28 @@ static int exynos_ohci_probe(struct platform_device *pdev)  	 * Since shared usb code relies on it, set it here for now.  	 * Once we move to full device tree support this will vanish off.  	 */ -	if (!pdev->dev.dma_mask) -		pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; -	if (!pdev->dev.coherent_dma_mask) -		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - -	exynos_ohci = devm_kzalloc(&pdev->dev, sizeof(struct exynos_ohci_hcd), -					GFP_KERNEL); -	if (!exynos_ohci) +	err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (err) +		return err; + +	hcd = usb_create_hcd(&exynos_ohci_hc_driver, +				&pdev->dev, dev_name(&pdev->dev)); +	if (!hcd) { +		dev_err(&pdev->dev, "Unable to create HCD\n");  		return -ENOMEM; +	} + +	exynos_ohci = to_exynos_ohci(hcd);  	if (of_device_is_compatible(pdev->dev.of_node,  					"samsung,exynos5440-ohci"))  		goto skip_phy; -	phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); -	if (IS_ERR(phy)) { -		/* Fallback to pdata */ -		if (!pdata) { -			dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); -			return -EPROBE_DEFER; -		} else { -			exynos_ohci->pdata = pdata; -		} -	} else { -		exynos_ohci->phy = phy; -		exynos_ohci->otg = phy->otg; -	} +	err = exynos_ohci_get_phy(&pdev->dev, exynos_ohci); +	if (err) +		goto fail_clk;  skip_phy: - -	exynos_ohci->dev = &pdev->dev; - -	hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev, -					dev_name(&pdev->dev)); -	if (!hcd) { -		dev_err(&pdev->dev, "Unable to create HCD\n"); -		return -ENOMEM; -	} - -	exynos_ohci->hcd = hcd;  	exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost");  	if (IS_ERR(exynos_ohci->clk)) { @@ -175,10 +196,9 @@ skip_phy:  	hcd->rsrc_start = res->start;  	hcd->rsrc_len = resource_size(res); -	hcd->regs = devm_ioremap(&pdev->dev, res->start, hcd->rsrc_len); -	if (!hcd->regs) { -		dev_err(&pdev->dev, "Failed to remap I/O memory\n"); -		err = -ENOMEM; +	hcd->regs = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(hcd->regs)) { +		err = PTR_ERR(hcd->regs);  		goto fail_io;  	} @@ -190,26 +210,26 @@ skip_phy:  	}  	if (exynos_ohci->otg) -		exynos_ohci->otg->set_host(exynos_ohci->otg, -					&exynos_ohci->hcd->self); +		exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); -	exynos_ohci_phy_enable(exynos_ohci); +	platform_set_drvdata(pdev, hcd); -	ohci = hcd_to_ohci(hcd); -	ohci_hcd_init(ohci); +	err = exynos_ohci_phy_enable(&pdev->dev); +	if (err) { +		dev_err(&pdev->dev, "Failed to enable USB phy\n"); +		goto fail_io; +	}  	err = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (err) {  		dev_err(&pdev->dev, "Failed to add USB HCD\n");  		goto fail_add_hcd;  	} - -	platform_set_drvdata(pdev, exynos_ohci); - +	device_wakeup_enable(hcd->self.controller);  	return 0;  fail_add_hcd: -	exynos_ohci_phy_disable(exynos_ohci); +	exynos_ohci_phy_disable(&pdev->dev);  fail_io:  	clk_disable_unprepare(exynos_ohci->clk);  fail_clk: @@ -219,16 +239,15 @@ fail_clk:  static int exynos_ohci_remove(struct platform_device *pdev)  { -	struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); -	struct usb_hcd *hcd = exynos_ohci->hcd; +	struct usb_hcd *hcd = platform_get_drvdata(pdev); +	struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd);  	usb_remove_hcd(hcd);  	if (exynos_ohci->otg) -		exynos_ohci->otg->set_host(exynos_ohci->otg, -					&exynos_ohci->hcd->self); +		exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); -	exynos_ohci_phy_disable(exynos_ohci); +	exynos_ohci_phy_disable(&pdev->dev);  	clk_disable_unprepare(exynos_ohci->clk); @@ -239,8 +258,7 @@ static int exynos_ohci_remove(struct platform_device *pdev)  static void exynos_ohci_shutdown(struct platform_device *pdev)  { -	struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); -	struct usb_hcd *hcd = exynos_ohci->hcd; +	struct usb_hcd *hcd = platform_get_drvdata(pdev);  	if (hcd->driver->shutdown)  		hcd->driver->shutdown(hcd); @@ -249,53 +267,41 @@ static void exynos_ohci_shutdown(struct platform_device *pdev)  #ifdef CONFIG_PM  static int exynos_ohci_suspend(struct device *dev)  { -	struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); -	struct usb_hcd *hcd = exynos_ohci->hcd; -	struct ohci_hcd *ohci = hcd_to_ohci(hcd); -	unsigned long flags; -	int rc = 0; - -	/* -	 * Root hub was already suspended. Disable irq emission and -	 * mark HW unaccessible, bail out if RH has been resumed. Use -	 * the spinlock to properly synchronize with possible pending -	 * RH suspend or resume activity. -	 */ -	spin_lock_irqsave(&ohci->lock, flags); -	if (ohci->rh_state != OHCI_RH_SUSPENDED && -			ohci->rh_state != OHCI_RH_HALTED) { -		rc = -EINVAL; -		goto fail; -	} +	struct usb_hcd *hcd = dev_get_drvdata(dev); +	struct exynos_ohci_hcd *exynos_ohci = to_exynos_ohci(hcd); +	bool do_wakeup = device_may_wakeup(dev); +	int rc = ohci_suspend(hcd, do_wakeup); -	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); +	if (rc) +		return rc;  	if (exynos_ohci->otg) -		exynos_ohci->otg->set_host(exynos_ohci->otg, -					&exynos_ohci->hcd->self); +		exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); -	exynos_ohci_phy_disable(exynos_ohci); +	exynos_ohci_phy_disable(dev);  	clk_disable_unprepare(exynos_ohci->clk); -fail: -	spin_unlock_irqrestore(&ohci->lock, flags); - -	return rc; +	return 0;  }  static int exynos_ohci_resume(struct device *dev)  { -	struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); -	struct usb_hcd *hcd = exynos_ohci->hcd; +	struct usb_hcd *hcd			= dev_get_drvdata(dev); +	struct exynos_ohci_hcd *exynos_ohci	= to_exynos_ohci(hcd); +	int ret;  	clk_prepare_enable(exynos_ohci->clk);  	if (exynos_ohci->otg) -		exynos_ohci->otg->set_host(exynos_ohci->otg, -					&exynos_ohci->hcd->self); +		exynos_ohci->otg->set_host(exynos_ohci->otg, &hcd->self); -	exynos_ohci_phy_enable(exynos_ohci); +	ret = exynos_ohci_phy_enable(dev); +	if (ret) { +		dev_err(dev, "Failed to enable USB phy\n"); +		clk_disable_unprepare(exynos_ohci->clk); +		return ret; +	}  	ohci_resume(hcd, false); @@ -306,6 +312,10 @@ static int exynos_ohci_resume(struct device *dev)  #define exynos_ohci_resume	NULL  #endif +static const struct ohci_driver_overrides exynos_overrides __initconst = { +	.extra_priv_size =	sizeof(struct exynos_ohci_hcd), +}; +  static const struct dev_pm_ops exynos_ohci_pm_ops = {  	.suspend	= exynos_ohci_suspend,  	.resume		= exynos_ohci_resume, @@ -331,6 +341,23 @@ static struct platform_driver exynos_ohci_driver = {  		.of_match_table	= of_match_ptr(exynos_ohci_match),  	}  }; +static int __init ohci_exynos_init(void) +{ +	if (usb_disabled()) +		return -ENODEV; + +	pr_info("%s: " DRIVER_DESC "\n", hcd_name); +	ohci_init_driver(&exynos_ohci_hc_driver, &exynos_overrides); +	return platform_driver_register(&exynos_ohci_driver); +} +module_init(ohci_exynos_init); + +static void __exit ohci_exynos_cleanup(void) +{ +	platform_driver_unregister(&exynos_ohci_driver); +} +module_exit(ohci_exynos_cleanup);  MODULE_ALIAS("platform:exynos-ohci");  MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 8f6b695af6a..f98d03f3144 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -51,8 +51,6 @@  /*-------------------------------------------------------------------------*/ -#undef OHCI_VERBOSE_DEBUG	/* not always helpful */ -  /* For initializing controller (mask in an HCFS mode too) */  #define	OHCI_CONTROL_INIT	OHCI_CTRL_CBSR  #define	OHCI_INTR_INIT \ @@ -127,10 +125,6 @@ static int ohci_urb_enqueue (  	unsigned long	flags;  	int		retval = 0; -#ifdef OHCI_VERBOSE_DEBUG -	urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS); -#endif -  	/* every endpoint has a ed, locate and maybe (re)initialize it */  	if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))  		return -ENOMEM; @@ -216,31 +210,26 @@ static int ohci_urb_enqueue (  			frame &= ~(ed->interval - 1);  			frame |= ed->branch;  			urb->start_frame = frame; +			ed->last_iso = frame + ed->interval * (size - 1);  		}  	} else if (ed->type == PIPE_ISOCHRONOUS) {  		u16	next = ohci_frame_no(ohci) + 1;  		u16	frame = ed->last_iso + ed->interval; +		u16	length = ed->interval * (size - 1);  		/* Behind the scheduling threshold? */  		if (unlikely(tick_before(frame, next))) { -			/* USB_ISO_ASAP: Round up to the first available slot */ +			/* URB_ISO_ASAP: Round up to the first available slot */  			if (urb->transfer_flags & URB_ISO_ASAP) {  				frame += (next - frame + ed->interval - 1) &  						-ed->interval;  			/* -			 * Not ASAP: Use the next slot in the stream.  If -			 * the entire URB falls before the threshold, fail. +			 * Not ASAP: Use the next slot in the stream, +			 * no matter what.  			 */  			} else { -				if (tick_before(frame + ed->interval * -					(urb->number_of_packets - 1), next)) { -					retval = -EXDEV; -					usb_hcd_unlink_urb_from_ep(hcd, urb); -					goto fail; -				} -  				/*  				 * Some OHCI hardware doesn't handle late TDs  				 * correctly.  After retiring them it proceeds @@ -251,9 +240,16 @@ static int ohci_urb_enqueue (  				urb_priv->td_cnt = DIV_ROUND_UP(  						(u16) (next - frame),  						ed->interval); +				if (urb_priv->td_cnt >= urb_priv->length) { +					++urb_priv->td_cnt;	/* Mark it */ +					ohci_dbg(ohci, "iso underrun %p (%u+%u < %u)\n", +							urb, frame, length, +							next); +				}  			}  		}  		urb->start_frame = frame; +		ed->last_iso = frame + length;  	}  	/* fill the TDs and link them to the ed; and @@ -282,10 +278,6 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  	unsigned long		flags;  	int			rc; -#ifdef OHCI_VERBOSE_DEBUG -	urb_print(urb, "UNLINK", 1, status); -#endif -  	spin_lock_irqsave (&ohci->lock, flags);  	rc = usb_hcd_check_unlink_urb(hcd, urb, status);  	if (rc) { @@ -838,7 +830,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)  	}  	if (ints & OHCI_INTR_RHSC) { -		ohci_vdbg(ohci, "rhsc\n"); +		ohci_dbg(ohci, "rhsc\n");  		ohci->next_statechange = jiffies + STATECHANGE_DELAY;  		ohci_writel(ohci, OHCI_INTR_RD | OHCI_INTR_RHSC,  				®s->intrstatus); @@ -860,7 +852,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)  	 * this might not happen.  	 */  	else if (ints & OHCI_INTR_RD) { -		ohci_vdbg(ohci, "resume detect\n"); +		ohci_dbg(ohci, "resume detect\n");  		ohci_writel(ohci, OHCI_INTR_RD, ®s->intrstatus);  		set_bit(HCD_FLAG_POLL_RH, &hcd->flags);  		if (ohci->autostop) { @@ -1034,6 +1026,7 @@ int ohci_suspend(struct usb_hcd *hcd, bool do_wakeup)  {  	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);  	unsigned long	flags; +	int		rc = 0;  	/* Disable irq emission and mark HW unaccessible. Use  	 * the spinlock to properly synchronize with possible pending @@ -1046,7 +1039,13 @@ int ohci_suspend(struct usb_hcd *hcd, bool do_wakeup)  	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);  	spin_unlock_irqrestore (&ohci->lock, flags); -	return 0; +	synchronize_irq(hcd->irq); + +	if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) { +		ohci_resume(hcd, false); +		rc = -EBUSY; +	} +	return rc;  }  EXPORT_SYMBOL_GPL(ohci_suspend); @@ -1159,10 +1158,12 @@ void ohci_init_driver(struct hc_driver *drv,  	/* Copy the generic table to drv and then apply the overrides */  	*drv = ohci_hc_driver; -	drv->product_desc = over->product_desc; -	drv->hcd_priv_size += over->extra_priv_size; -	if (over->reset) -		drv->reset = over->reset; +	if (over) { +		drv->product_desc = over->product_desc; +		drv->hcd_priv_size += over->extra_priv_size; +		if (over->reset) +			drv->reset = over->reset; +	}  }  EXPORT_SYMBOL_GPL(ohci_init_driver); @@ -1177,47 +1178,7 @@ MODULE_LICENSE ("GPL");  #define SA1111_DRIVER		ohci_hcd_sa1111_driver  #endif -#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX) -#include "ohci-s3c2410.c" -#define S3C2410_PLATFORM_DRIVER	ohci_hcd_s3c2410_driver -#endif - -#ifdef CONFIG_USB_OHCI_EXYNOS -#include "ohci-exynos.c" -#define EXYNOS_PLATFORM_DRIVER	exynos_ohci_driver -#endif - -#ifdef CONFIG_USB_OHCI_HCD_OMAP1 -#include "ohci-omap.c" -#define OMAP1_PLATFORM_DRIVER	ohci_hcd_omap_driver -#endif - -#ifdef CONFIG_USB_OHCI_HCD_OMAP3 -#include "ohci-omap3.c" -#define OMAP3_PLATFORM_DRIVER	ohci_hcd_omap3_driver -#endif - -#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx) -#include "ohci-pxa27x.c" -#define PLATFORM_DRIVER		ohci_hcd_pxa27x_driver -#endif - -#ifdef CONFIG_ARCH_EP93XX -#include "ohci-ep93xx.c" -#define EP93XX_PLATFORM_DRIVER	ohci_hcd_ep93xx_driver -#endif - -#ifdef CONFIG_ARCH_AT91 -#include "ohci-at91.c" -#define AT91_PLATFORM_DRIVER	ohci_hcd_at91_driver -#endif - -#ifdef CONFIG_ARCH_LPC32XX -#include "ohci-nxp.c" -#define NXP_PLATFORM_DRIVER	usb_hcd_nxp_driver -#endif - -#ifdef CONFIG_ARCH_DAVINCI_DA8XX +#ifdef CONFIG_USB_OHCI_HCD_DAVINCI  #include "ohci-da8xx.c"  #define DAVINCI_PLATFORM_DRIVER	ohci_hcd_da8xx_driver  #endif @@ -1227,11 +1188,6 @@ MODULE_LICENSE ("GPL");  #define OF_PLATFORM_DRIVER	ohci_hcd_ppc_of_driver  #endif -#ifdef CONFIG_PLAT_SPEAR -#include "ohci-spear.c" -#define SPEAR_PLATFORM_DRIVER	spear_ohci_hcd_driver -#endif -  #ifdef CONFIG_PPC_PS3  #include "ohci-ps3.c"  #define PS3_SYSTEM_BUS_DRIVER	ps3_ohci_driver @@ -1274,13 +1230,11 @@ static int __init ohci_hcd_mod_init(void)  		sizeof (struct ed), sizeof (struct td));  	set_bit(USB_OHCI_LOADED, &usb_hcds_loaded); -#ifdef DEBUG  	ohci_debug_root = debugfs_create_dir("ohci", usb_debug_root);  	if (!ohci_debug_root) {  		retval = -ENOENT;  		goto error_debug;  	} -#endif  #ifdef PS3_SYSTEM_BUS_DRIVER  	retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER); @@ -1294,18 +1248,6 @@ static int __init ohci_hcd_mod_init(void)  		goto error_platform;  #endif -#ifdef OMAP1_PLATFORM_DRIVER -	retval = platform_driver_register(&OMAP1_PLATFORM_DRIVER); -	if (retval < 0) -		goto error_omap1_platform; -#endif - -#ifdef OMAP3_PLATFORM_DRIVER -	retval = platform_driver_register(&OMAP3_PLATFORM_DRIVER); -	if (retval < 0) -		goto error_omap3_platform; -#endif -  #ifdef OF_PLATFORM_DRIVER  	retval = platform_driver_register(&OF_PLATFORM_DRIVER);  	if (retval < 0) @@ -1330,79 +1272,19 @@ static int __init ohci_hcd_mod_init(void)  		goto error_tmio;  #endif -#ifdef S3C2410_PLATFORM_DRIVER -	retval = platform_driver_register(&S3C2410_PLATFORM_DRIVER); -	if (retval < 0) -		goto error_s3c2410; -#endif - -#ifdef EXYNOS_PLATFORM_DRIVER -	retval = platform_driver_register(&EXYNOS_PLATFORM_DRIVER); -	if (retval < 0) -		goto error_exynos; -#endif - -#ifdef EP93XX_PLATFORM_DRIVER -	retval = platform_driver_register(&EP93XX_PLATFORM_DRIVER); -	if (retval < 0) -		goto error_ep93xx; -#endif - -#ifdef AT91_PLATFORM_DRIVER -	retval = platform_driver_register(&AT91_PLATFORM_DRIVER); -	if (retval < 0) -		goto error_at91; -#endif - -#ifdef NXP_PLATFORM_DRIVER -	retval = platform_driver_register(&NXP_PLATFORM_DRIVER); -	if (retval < 0) -		goto error_nxp; -#endif -  #ifdef DAVINCI_PLATFORM_DRIVER  	retval = platform_driver_register(&DAVINCI_PLATFORM_DRIVER);  	if (retval < 0)  		goto error_davinci;  #endif -#ifdef SPEAR_PLATFORM_DRIVER -	retval = platform_driver_register(&SPEAR_PLATFORM_DRIVER); -	if (retval < 0) -		goto error_spear; -#endif -  	return retval;  	/* Error path */ -#ifdef SPEAR_PLATFORM_DRIVER -	platform_driver_unregister(&SPEAR_PLATFORM_DRIVER); - error_spear: -#endif  #ifdef DAVINCI_PLATFORM_DRIVER  	platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER);   error_davinci:  #endif -#ifdef NXP_PLATFORM_DRIVER -	platform_driver_unregister(&NXP_PLATFORM_DRIVER); - error_nxp: -#endif -#ifdef AT91_PLATFORM_DRIVER -	platform_driver_unregister(&AT91_PLATFORM_DRIVER); - error_at91: -#endif -#ifdef EP93XX_PLATFORM_DRIVER -	platform_driver_unregister(&EP93XX_PLATFORM_DRIVER); - error_ep93xx: -#endif -#ifdef EXYNOS_PLATFORM_DRIVER -	platform_driver_unregister(&EXYNOS_PLATFORM_DRIVER); - error_exynos: -#endif -#ifdef S3C2410_PLATFORM_DRIVER -	platform_driver_unregister(&S3C2410_PLATFORM_DRIVER); - error_s3c2410: -#endif  #ifdef TMIO_OHCI_DRIVER  	platform_driver_unregister(&TMIO_OHCI_DRIVER);   error_tmio: @@ -1419,14 +1301,6 @@ static int __init ohci_hcd_mod_init(void)  	platform_driver_unregister(&OF_PLATFORM_DRIVER);   error_of_platform:  #endif -#ifdef OMAP3_PLATFORM_DRIVER -	platform_driver_unregister(&OMAP3_PLATFORM_DRIVER); - error_omap3_platform: -#endif -#ifdef OMAP1_PLATFORM_DRIVER -	platform_driver_unregister(&OMAP1_PLATFORM_DRIVER); - error_omap1_platform: -#endif  #ifdef PLATFORM_DRIVER  	platform_driver_unregister(&PLATFORM_DRIVER);   error_platform: @@ -1435,11 +1309,9 @@ static int __init ohci_hcd_mod_init(void)  	ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);   error_ps3:  #endif -#ifdef DEBUG  	debugfs_remove(ohci_debug_root);  	ohci_debug_root = NULL;   error_debug: -#endif  	clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded);  	return retval; @@ -1448,27 +1320,9 @@ module_init(ohci_hcd_mod_init);  static void __exit ohci_hcd_mod_exit(void)  { -#ifdef SPEAR_PLATFORM_DRIVER -	platform_driver_unregister(&SPEAR_PLATFORM_DRIVER); -#endif  #ifdef DAVINCI_PLATFORM_DRIVER  	platform_driver_unregister(&DAVINCI_PLATFORM_DRIVER);  #endif -#ifdef NXP_PLATFORM_DRIVER -	platform_driver_unregister(&NXP_PLATFORM_DRIVER); -#endif -#ifdef AT91_PLATFORM_DRIVER -	platform_driver_unregister(&AT91_PLATFORM_DRIVER); -#endif -#ifdef EP93XX_PLATFORM_DRIVER -	platform_driver_unregister(&EP93XX_PLATFORM_DRIVER); -#endif -#ifdef EXYNOS_PLATFORM_DRIVER -	platform_driver_unregister(&EXYNOS_PLATFORM_DRIVER); -#endif -#ifdef S3C2410_PLATFORM_DRIVER -	platform_driver_unregister(&S3C2410_PLATFORM_DRIVER); -#endif  #ifdef TMIO_OHCI_DRIVER  	platform_driver_unregister(&TMIO_OHCI_DRIVER);  #endif @@ -1481,21 +1335,13 @@ static void __exit ohci_hcd_mod_exit(void)  #ifdef OF_PLATFORM_DRIVER  	platform_driver_unregister(&OF_PLATFORM_DRIVER);  #endif -#ifdef OMAP3_PLATFORM_DRIVER -	platform_driver_unregister(&OMAP3_PLATFORM_DRIVER); -#endif -#ifdef OMAP1_PLATFORM_DRIVER -	platform_driver_unregister(&OMAP1_PLATFORM_DRIVER); -#endif  #ifdef PLATFORM_DRIVER  	platform_driver_unregister(&PLATFORM_DRIVER);  #endif  #ifdef PS3_SYSTEM_BUS_DRIVER  	ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);  #endif -#ifdef DEBUG  	debugfs_remove(ohci_debug_root); -#endif  	clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded);  }  module_exit(ohci_hcd_mod_exit); diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 2347ab83f04..b4940de1eba 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -90,6 +90,24 @@ __acquires(ohci->lock)  	dl_done_list (ohci);  	finish_unlinks (ohci, ohci_frame_no(ohci)); +	/* +	 * Some controllers don't handle "global" suspend properly if +	 * there are unsuspended ports.  For these controllers, put all +	 * the enabled ports into suspend before suspending the root hub. +	 */ +	if (ohci->flags & OHCI_QUIRK_GLOBAL_SUSPEND) { +		__hc32 __iomem	*portstat = ohci->regs->roothub.portstatus; +		int		i; +		unsigned	temp; + +		for (i = 0; i < ohci->num_ports; (++i, ++portstat)) { +			temp = ohci_readl(ohci, portstat); +			if ((temp & (RH_PS_PES | RH_PS_PSS)) == +					RH_PS_PES) +				ohci_writel(ohci, RH_PS_PSS, portstat); +		} +	} +  	/* maybe resume can wake root hub */  	if (ohci_to_hcd(ohci)->self.root_hub->do_remote_wakeup || autostop) {  		ohci->hc_control |= OHCI_CTRL_RWE; @@ -212,10 +230,11 @@ __acquires(ohci->lock)  	/* Sometimes PCI D3 suspend trashes frame timings ... */  	periodic_reinit (ohci); -	/* the following code is executed with ohci->lock held and -	 * irqs disabled if and only if autostopped is true +	/* +	 * The following code is executed with ohci->lock held and +	 * irqs disabled if and only if autostopped is true.  This +	 * will cause sparse to warn about a "context imbalance".  	 */ -  skip_resume:  	/* interrupts might have been disabled */  	ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); @@ -437,8 +456,7 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,  /* build "status change" packet (one or two bytes) from HC registers */ -static int -ohci_hub_status_data (struct usb_hcd *hcd, char *buf) +int ohci_hub_status_data(struct usb_hcd *hcd, char *buf)  {  	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);  	int		i, changed = 0, length = 1; @@ -503,6 +521,7 @@ done:  	return changed ? length : 0;  } +EXPORT_SYMBOL_GPL(ohci_hub_status_data);  /*-------------------------------------------------------------------------*/ @@ -531,7 +550,7 @@ ohci_hub_descriptor (  	    temp |= 0x0010;  	else if (rh & RH_A_OCPM)	/* per-port overcurrent reporting? */  	    temp |= 0x0008; -	desc->wHubCharacteristics = (__force __u16)cpu_to_hc16(ohci, temp); +	desc->wHubCharacteristics = cpu_to_le16(temp);  	/* ports removable, and usb 1.0 legacy PortPwrCtrlMask */  	rh = roothub_b (ohci); @@ -645,7 +664,7 @@ static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)  	return 0;  } -static int ohci_hub_control ( +int ohci_hub_control(  	struct usb_hcd	*hcd,  	u16		typeReq,  	u16		wValue, @@ -724,10 +743,8 @@ static int ohci_hub_control (  		temp = roothub_portstatus (ohci, wIndex);  		put_unaligned_le32(temp, buf); -#ifndef	OHCI_VERBOSE_DEBUG -	if (*(u16*)(buf+2))	/* only if wPortChange is interesting */ -#endif -		dbg_port (ohci, "GetStatus", wIndex, temp); +		if (*(u16*)(buf+2))	/* only if wPortChange is interesting */ +			dbg_port(ohci, "GetStatus", wIndex, temp);  		break;  	case SetHubFeature:  		switch (wValue) { @@ -773,4 +790,4 @@ error:  	}  	return retval;  } - +EXPORT_SYMBOL_GPL(ohci_hub_control); diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c index d4ef53990d7..c2c221a332e 100644 --- a/drivers/usb/host/ohci-jz4740.c +++ b/drivers/usb/host/ohci-jz4740.c @@ -82,14 +82,14 @@ static int ohci_jz4740_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  	u16 wIndex, char *buf, u16 wLength)  {  	struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd); -	int ret; +	int ret = 0;  	switch (typeReq) { -	case SetHubFeature: +	case SetPortFeature:  		if (wValue == USB_PORT_FEAT_POWER)  			ret = ohci_jz4740_set_vbus_power(jz4740_ohci, true);  		break; -	case ClearHubFeature: +	case ClearPortFeature:  		if (wValue == USB_PORT_FEAT_POWER)  			ret = ohci_jz4740_set_vbus_power(jz4740_ohci, false);  		break; @@ -174,31 +174,23 @@ static int jz4740_ohci_probe(struct platform_device *pdev)  	jz4740_ohci = hcd_to_jz4740_hcd(hcd); -	res = request_mem_region(res->start, resource_size(res), hcd_name); -	if (!res) { -		dev_err(&pdev->dev, "Failed to request mem region.\n"); -		ret = -EBUSY; -		goto err_free; -	} -  	hcd->rsrc_start = res->start;  	hcd->rsrc_len = resource_size(res); -	hcd->regs = ioremap(res->start, resource_size(res)); -	if (!hcd->regs) { -		dev_err(&pdev->dev, "Failed to ioremap registers.\n"); -		ret = -EBUSY; -		goto err_release_mem; +	hcd->regs = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(hcd->regs)) { +		ret = PTR_ERR(hcd->regs); +		goto err_free;  	} -	jz4740_ohci->clk = clk_get(&pdev->dev, "uhc"); +	jz4740_ohci->clk = devm_clk_get(&pdev->dev, "uhc");  	if (IS_ERR(jz4740_ohci->clk)) {  		ret = PTR_ERR(jz4740_ohci->clk);  		dev_err(&pdev->dev, "Failed to get clock: %d\n", ret); -		goto err_iounmap; +		goto err_free;  	} -	jz4740_ohci->vbus = regulator_get(&pdev->dev, "vbus"); +	jz4740_ohci->vbus = devm_regulator_get(&pdev->dev, "vbus");  	if (IS_ERR(jz4740_ohci->vbus))  		jz4740_ohci->vbus = NULL; @@ -217,21 +209,15 @@ static int jz4740_ohci_probe(struct platform_device *pdev)  		dev_err(&pdev->dev, "Failed to add hcd: %d\n", ret);  		goto err_disable;  	} +	device_wakeup_enable(hcd->self.controller);  	return 0;  err_disable: -	if (jz4740_ohci->vbus) { +	if (jz4740_ohci->vbus)  		regulator_disable(jz4740_ohci->vbus); -		regulator_put(jz4740_ohci->vbus); -	}  	clk_disable(jz4740_ohci->clk); -	clk_put(jz4740_ohci->clk); -err_iounmap: -	iounmap(hcd->regs); -err_release_mem: -	release_mem_region(res->start, resource_size(res));  err_free:  	usb_put_hcd(hcd); @@ -245,16 +231,10 @@ static int jz4740_ohci_remove(struct platform_device *pdev)  	usb_remove_hcd(hcd); -	if (jz4740_ohci->vbus) { +	if (jz4740_ohci->vbus)  		regulator_disable(jz4740_ohci->vbus); -		regulator_put(jz4740_ohci->vbus); -	}  	clk_disable(jz4740_ohci->clk); -	clk_put(jz4740_ohci->clk); - -	iounmap(hcd->regs); -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	usb_put_hcd(hcd); diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index 7d7d507d54e..ba180ed0f81 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -19,10 +19,19 @@   * or implied.   */  #include <linux/clk.h> -#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/io.h>  #include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h>  #include <linux/of.h> +#include <linux/platform_device.h>  #include <linux/usb/isp1301.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ohci.h" +  #include <mach/hardware.h>  #include <asm/mach-types.h> @@ -57,6 +66,11 @@  #define start_int_umask(irq)  #endif +#define DRIVER_DESC "OHCI NXP driver" + +static const char hcd_name[] = "ohci-nxp"; +static struct hc_driver __read_mostly ohci_nxp_hc_driver; +  static struct i2c_client *isp1301_i2c_client;  extern int usb_disabled(void); @@ -132,14 +146,14 @@ static inline void isp1301_vbus_off(void)  		OTG1_VBUS_DRV);  } -static void nxp_start_hc(void) +static void ohci_nxp_start_hc(void)  {  	unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN;  	__raw_writel(tmp, USB_OTG_STAT_CONTROL);  	isp1301_vbus_on();  } -static void nxp_stop_hc(void) +static void ohci_nxp_stop_hc(void)  {  	unsigned long tmp;  	isp1301_vbus_off(); @@ -147,68 +161,9 @@ static void nxp_stop_hc(void)  	__raw_writel(tmp, USB_OTG_STAT_CONTROL);  } -static int ohci_nxp_start(struct usb_hcd *hcd) -{ -	struct ohci_hcd *ohci = hcd_to_ohci(hcd); -	int ret; - -	if ((ret = ohci_init(ohci)) < 0) -		return ret; - -	if ((ret = ohci_run(ohci)) < 0) { -		dev_err(hcd->self.controller, "can't start\n"); -		ohci_stop(hcd); -		return ret; -	} -	return 0; -} - -static const struct hc_driver ohci_nxp_hc_driver = { -	.description = hcd_name, -	.product_desc =		"nxp OHCI", - -	/* -	 * generic hardware linkage -	 */ -	.irq = ohci_irq, -	.flags = HCD_USB11 | HCD_MEMORY, - -	.hcd_priv_size =	sizeof(struct ohci_hcd), -	/* -	 * basic lifecycle operations -	 */ -	.start = ohci_nxp_start, -	.stop = ohci_stop, -	.shutdown = ohci_shutdown, - -	/* -	 * managing i/o requests and associated device resources -	 */ -	.urb_enqueue = ohci_urb_enqueue, -	.urb_dequeue = ohci_urb_dequeue, -	.endpoint_disable = ohci_endpoint_disable, - -	/* -	 * scheduling support -	 */ -	.get_frame_number = ohci_get_frame, - -	/* -	 * root hub support -	 */ -	.hub_status_data = ohci_hub_status_data, -	.hub_control = ohci_hub_control, -#ifdef	CONFIG_PM -	.bus_suspend = ohci_bus_suspend, -	.bus_resume = ohci_bus_resume, -#endif -	.start_port_reset = ohci_start_port_reset, -}; - -static int usb_hcd_nxp_probe(struct platform_device *pdev) +static int ohci_hcd_nxp_probe(struct platform_device *pdev)  {  	struct usb_hcd *hcd = 0; -	struct ohci_hcd *ohci;  	const struct hc_driver *driver = &ohci_nxp_hc_driver;  	struct resource *res;  	int ret = 0, irq; @@ -226,8 +181,9 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)  		return -EPROBE_DEFER;  	} -	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); -	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; +	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (ret) +		goto fail_disable;  	dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name);  	if (usb_disabled()) { @@ -240,17 +196,17 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)  	__raw_writel(USB_SLAVE_HCLK_EN | PAD_CONTROL_LAST_DRIVEN, USB_CTRL);  	/* Enable USB PLL */ -	usb_pll_clk = clk_get(&pdev->dev, "ck_pll5"); +	usb_pll_clk = devm_clk_get(&pdev->dev, "ck_pll5");  	if (IS_ERR(usb_pll_clk)) {  		dev_err(&pdev->dev, "failed to acquire USB PLL\n");  		ret = PTR_ERR(usb_pll_clk); -		goto fail_pll; +		goto fail_disable;  	}  	ret = clk_enable(usb_pll_clk);  	if (ret < 0) {  		dev_err(&pdev->dev, "failed to start USB PLL\n"); -		goto fail_pllen; +		goto fail_disable;  	}  	ret = clk_set_rate(usb_pll_clk, 48000); @@ -260,21 +216,21 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)  	}  	/* Enable USB device clock */ -	usb_dev_clk = clk_get(&pdev->dev, "ck_usbd"); +	usb_dev_clk = devm_clk_get(&pdev->dev, "ck_usbd");  	if (IS_ERR(usb_dev_clk)) {  		dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");  		ret = PTR_ERR(usb_dev_clk); -		goto fail_dev; +		goto fail_rate;  	}  	ret = clk_enable(usb_dev_clk);  	if (ret < 0) {  		dev_err(&pdev->dev, "failed to start USB DEV Clock\n"); -		goto fail_deven; +		goto fail_rate;  	}  	/* Enable USB otg clocks */ -	usb_otg_clk = clk_get(&pdev->dev, "ck_usb_otg"); +	usb_otg_clk = devm_clk_get(&pdev->dev, "ck_usb_otg");  	if (IS_ERR(usb_otg_clk)) {  		dev_err(&pdev->dev, "failed to acquire USB DEV Clock\n");  		ret = PTR_ERR(usb_otg_clk); @@ -286,7 +242,7 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)  	ret = clk_enable(usb_otg_clk);  	if (ret < 0) {  		dev_err(&pdev->dev, "failed to start USB DEV Clock\n"); -		goto fail_otgen; +		goto fail_otg;  	}  	isp1301_configure(); @@ -313,49 +269,39 @@ static int usb_hcd_nxp_probe(struct platform_device *pdev)  		goto fail_resource;  	} -	nxp_start_hc(); +	ohci_nxp_start_hc();  	platform_set_drvdata(pdev, hcd); -	ohci = hcd_to_ohci(hcd); -	ohci_hcd_init(ohci);  	dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq);  	ret = usb_add_hcd(hcd, irq, 0); -	if (ret == 0) +	if (ret == 0) { +		device_wakeup_enable(hcd->self.controller);  		return ret; +	} -	nxp_stop_hc(); +	ohci_nxp_stop_hc();  fail_resource:  	usb_put_hcd(hcd);  fail_hcd:  	clk_disable(usb_otg_clk); -fail_otgen: -	clk_put(usb_otg_clk);  fail_otg:  	clk_disable(usb_dev_clk); -fail_deven: -	clk_put(usb_dev_clk); -fail_dev:  fail_rate:  	clk_disable(usb_pll_clk); -fail_pllen: -	clk_put(usb_pll_clk); -fail_pll:  fail_disable:  	isp1301_i2c_client = NULL;  	return ret;  } -static int usb_hcd_nxp_remove(struct platform_device *pdev) +static int ohci_hcd_nxp_remove(struct platform_device *pdev)  {  	struct usb_hcd *hcd = platform_get_drvdata(pdev);  	usb_remove_hcd(hcd); -	nxp_stop_hc(); +	ohci_nxp_stop_hc();  	usb_put_hcd(hcd);  	clk_disable(usb_pll_clk); -	clk_put(usb_pll_clk);  	clk_disable(usb_dev_clk); -	clk_put(usb_dev_clk);  	i2c_unregister_device(isp1301_i2c_client);  	isp1301_i2c_client = NULL; @@ -366,20 +312,40 @@ static int usb_hcd_nxp_remove(struct platform_device *pdev)  MODULE_ALIAS("platform:usb-ohci");  #ifdef CONFIG_OF -static const struct of_device_id usb_hcd_nxp_match[] = { +static const struct of_device_id ohci_hcd_nxp_match[] = {  	{ .compatible = "nxp,ohci-nxp" },  	{},  }; -MODULE_DEVICE_TABLE(of, usb_hcd_nxp_match); +MODULE_DEVICE_TABLE(of, ohci_hcd_nxp_match);  #endif -static struct platform_driver usb_hcd_nxp_driver = { +static struct platform_driver ohci_hcd_nxp_driver = {  	.driver = {  		.name = "usb-ohci",  		.owner	= THIS_MODULE, -		.of_match_table = of_match_ptr(usb_hcd_nxp_match), +		.of_match_table = of_match_ptr(ohci_hcd_nxp_match),  	}, -	.probe = usb_hcd_nxp_probe, -	.remove = usb_hcd_nxp_remove, +	.probe = ohci_hcd_nxp_probe, +	.remove = ohci_hcd_nxp_remove,  }; +static int __init ohci_nxp_init(void) +{ +	if (usb_disabled()) +		return -ENODEV; + +	pr_info("%s: " DRIVER_DESC "\n", hcd_name); + +	ohci_init_driver(&ohci_nxp_hc_driver, NULL); +	return platform_driver_register(&ohci_hcd_nxp_driver); +} +module_init(ohci_nxp_init); + +static void __exit ohci_nxp_cleanup(void) +{ +	platform_driver_unregister(&ohci_hcd_nxp_driver); +} +module_exit(ohci_nxp_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/ohci-octeon.c b/drivers/usb/host/ohci-octeon.c index 342dc7e543b..15af8954085 100644 --- a/drivers/usb/host/ohci-octeon.c +++ b/drivers/usb/host/ohci-octeon.c @@ -127,8 +127,9 @@ static int ohci_octeon_drv_probe(struct platform_device *pdev)  	}  	/* Ohci is a 32-bit device. */ -	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); -	pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; +	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (ret) +		return ret;  	hcd = usb_create_hcd(&ohci_octeon_hc_driver, &pdev->dev, "octeon");  	if (!hcd) @@ -137,20 +138,12 @@ static int ohci_octeon_drv_probe(struct platform_device *pdev)  	hcd->rsrc_start = res_mem->start;  	hcd->rsrc_len = resource_size(res_mem); -	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, -				OCTEON_OHCI_HCD_NAME)) { -		dev_err(&pdev->dev, "request_mem_region failed\n"); -		ret = -EBUSY; +	reg_base = devm_ioremap_resource(&pdev->dev, res_mem); +	if (IS_ERR(reg_base)) { +		ret = PTR_ERR(reg_base);  		goto err1;  	} -	reg_base = ioremap(hcd->rsrc_start, hcd->rsrc_len); -	if (!reg_base) { -		dev_err(&pdev->dev, "ioremap failed\n"); -		ret = -ENOMEM; -		goto err2; -	} -  	ohci_octeon_hw_start();  	hcd->regs = reg_base; @@ -167,19 +160,18 @@ static int ohci_octeon_drv_probe(struct platform_device *pdev)  	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (ret) {  		dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret); -		goto err3; +		goto err2;  	} +	device_wakeup_enable(hcd->self.controller); +  	platform_set_drvdata(pdev, hcd);  	return 0; -err3: +err2:  	ohci_octeon_hw_stop(); -	iounmap(hcd->regs); -err2: -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  err1:  	usb_put_hcd(hcd);  	return ret; @@ -192,8 +184,6 @@ static int ohci_octeon_drv_remove(struct platform_device *pdev)  	usb_remove_hcd(hcd);  	ohci_octeon_hw_stop(); -	iounmap(hcd->regs); -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	usb_put_hcd(hcd);  	return 0; diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 31d3a12eb48..c923cafcaca 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -14,12 +14,21 @@   * This file is licenced under the GPL.   */ -#include <linux/signal.h> -#include <linux/jiffies.h> -#include <linux/platform_device.h>  #include <linux/clk.h> +#include <linux/dma-mapping.h>  #include <linux/err.h>  #include <linux/gpio.h> +#include <linux/io.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/usb/otg.h> +#include <linux/platform_device.h> +#include <linux/signal.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ohci.h"  #include <asm/io.h>  #include <asm/mach-types.h> @@ -42,10 +51,7 @@  #define OMAP1510_LB_MMU_RAM_H	0xfffec234  #define OMAP1510_LB_MMU_RAM_L	0xfffec238 - -#ifndef CONFIG_ARCH_OMAP -#error "This file is OMAP bus glue.  CONFIG_OMAP must be defined." -#endif +#define DRIVER_DESC "OHCI OMAP driver"  #ifdef CONFIG_TPS65010  #include <linux/i2c/tps65010.h> @@ -68,8 +74,9 @@ extern int ocpi_enable(void);  static struct clk *usb_host_ck;  static struct clk *usb_dc_ck; -static int host_enabled; -static int host_initialized; + +static const char hcd_name[] = "ohci-omap"; +static struct hc_driver __read_mostly ohci_omap_hc_driver;  static void omap_ohci_clock_power(int on)  { @@ -188,7 +195,7 @@ static void start_hnp(struct ohci_hcd *ohci)  /*-------------------------------------------------------------------------*/ -static int ohci_omap_init(struct usb_hcd *hcd) +static int ohci_omap_reset(struct usb_hcd *hcd)  {  	struct ohci_hcd		*ohci = hcd_to_ohci(hcd);  	struct omap_usb_config	*config = dev_get_platdata(hcd->self.controller); @@ -198,9 +205,9 @@ static int ohci_omap_init(struct usb_hcd *hcd)  	dev_dbg(hcd->self.controller, "starting USB Controller\n");  	if (config->otg) { -		ohci_to_hcd(ohci)->self.otg_port = config->otg; +		hcd->self.otg_port = config->otg;  		/* default/minimum OTG power budget:  8 mA */ -		ohci_to_hcd(ohci)->power_budget = 8; +		hcd->power_budget = 8;  	}  	/* boards can use OTG transceivers in non-OTG modes */ @@ -238,9 +245,15 @@ static int ohci_omap_init(struct usb_hcd *hcd)  		omap_1510_local_bus_init();  	} -	if ((ret = ohci_init(ohci)) < 0) +	ret = ohci_setup(hcd); +	if (ret < 0)  		return ret; +	if (config->otg || config->rwc) { +		ohci->hc_control = OHCI_CTRL_RWC; +		writel(OHCI_CTRL_RWC, &ohci->regs->control); +	} +  	/* board-specific power switching and overcurrent support */  	if (machine_is_omap_osk() || machine_is_omap_innovator()) {  		u32	rh = roothub_a (ohci); @@ -281,14 +294,6 @@ static int ohci_omap_init(struct usb_hcd *hcd)  	return 0;  } -static void ohci_omap_stop(struct usb_hcd *hcd) -{ -	dev_dbg(hcd->self.controller, "stopping USB Controller\n"); -	ohci_stop(hcd); -	omap_ohci_clock_power(0); -} - -  /*-------------------------------------------------------------------------*/  /** @@ -304,17 +309,16 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,  {  	int retval, irq;  	struct usb_hcd *hcd = 0; -	struct ohci_hcd *ohci;  	if (pdev->num_resources != 2) { -		printk(KERN_ERR "hcd probe: invalid num_resources: %i\n", +		dev_err(&pdev->dev, "invalid num_resources: %i\n",  		       pdev->num_resources);  		return -ENODEV;  	}  	if (pdev->resource[0].flags != IORESOURCE_MEM  			|| pdev->resource[1].flags != IORESOURCE_IRQ) { -		printk(KERN_ERR "hcd probe: invalid resource type\n"); +		dev_err(&pdev->dev, "invalid resource type\n");  		return -ENODEV;  	} @@ -354,12 +358,6 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,  		goto err2;  	} -	ohci = hcd_to_ohci(hcd); -	ohci_hcd_init(ohci); - -	host_initialized = 0; -	host_enabled = 1; -  	irq = platform_get_irq(pdev, 0);  	if (irq < 0) {  		retval = -ENXIO; @@ -369,11 +367,7 @@ static int usb_hcd_omap_probe (const struct hc_driver *driver,  	if (retval)  		goto err3; -	host_initialized = 1; - -	if (!host_enabled) -		omap_ohci_clock_power(0); - +	device_wakeup_enable(hcd->self.controller);  	return 0;  err3:  	iounmap(hcd->regs); @@ -402,7 +396,9 @@ err0:  static inline void  usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)  { +	dev_dbg(hcd->self.controller, "stopping USB Controller\n");  	usb_remove_hcd(hcd); +	omap_ohci_clock_power(0);  	if (!IS_ERR_OR_NULL(hcd->phy)) {  		(void) otg_set_host(hcd->phy->otg, 0);  		usb_put_phy(hcd->phy); @@ -418,76 +414,6 @@ usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)  /*-------------------------------------------------------------------------*/ -static int -ohci_omap_start (struct usb_hcd *hcd) -{ -	struct omap_usb_config *config; -	struct ohci_hcd	*ohci = hcd_to_ohci (hcd); -	int		ret; - -	if (!host_enabled) -		return 0; -	config = dev_get_platdata(hcd->self.controller); -	if (config->otg || config->rwc) { -		ohci->hc_control = OHCI_CTRL_RWC; -		writel(OHCI_CTRL_RWC, &ohci->regs->control); -	} - -	if ((ret = ohci_run (ohci)) < 0) { -		dev_err(hcd->self.controller, "can't start\n"); -		ohci_stop (hcd); -		return ret; -	} -	return 0; -} - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_omap_hc_driver = { -	.description =		hcd_name, -	.product_desc =		"OMAP OHCI", -	.hcd_priv_size =	sizeof(struct ohci_hcd), - -	/* -	 * generic hardware linkage -	 */ -	.irq =			ohci_irq, -	.flags =		HCD_USB11 | HCD_MEMORY, - -	/* -	 * basic lifecycle operations -	 */ -	.reset =		ohci_omap_init, -	.start =		ohci_omap_start, -	.stop =			ohci_omap_stop, -	.shutdown =		ohci_shutdown, - -	/* -	 * managing i/o requests and associated device resources -	 */ -	.urb_enqueue =		ohci_urb_enqueue, -	.urb_dequeue =		ohci_urb_dequeue, -	.endpoint_disable =	ohci_endpoint_disable, - -	/* -	 * scheduling support -	 */ -	.get_frame_number =	ohci_get_frame, - -	/* -	 * root hub support -	 */ -	.hub_status_data =	ohci_hub_status_data, -	.hub_control =		ohci_hub_control, -#ifdef	CONFIG_PM -	.bus_suspend =		ohci_bus_suspend, -	.bus_resume =		ohci_bus_resume, -#endif -	.start_port_reset =	ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ -  static int ohci_hcd_omap_drv_probe(struct platform_device *dev)  {  	return usb_hcd_omap_probe(&ohci_omap_hc_driver, dev); @@ -506,16 +432,23 @@ static int ohci_hcd_omap_drv_remove(struct platform_device *dev)  #ifdef	CONFIG_PM -static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message) +static int ohci_omap_suspend(struct platform_device *pdev, pm_message_t message)  { -	struct ohci_hcd	*ohci = hcd_to_ohci(platform_get_drvdata(dev)); +	struct usb_hcd *hcd = platform_get_drvdata(pdev); +	struct ohci_hcd *ohci = hcd_to_ohci(hcd); +	bool do_wakeup = device_may_wakeup(&pdev->dev); +	int ret;  	if (time_before(jiffies, ohci->next_statechange))  		msleep(5);  	ohci->next_statechange = jiffies; +	ret = ohci_suspend(hcd, do_wakeup); +	if (ret) +		return ret; +  	omap_ohci_clock_power(0); -	return 0; +	return ret;  }  static int ohci_omap_resume(struct platform_device *dev) @@ -553,4 +486,29 @@ static struct platform_driver ohci_hcd_omap_driver = {  	},  }; +static const struct ohci_driver_overrides omap_overrides __initconst = { +	.product_desc	= "OMAP OHCI", +	.reset		= ohci_omap_reset +}; + +static int __init ohci_omap_init(void) +{ +	if (usb_disabled()) +		return -ENODEV; + +	pr_info("%s: " DRIVER_DESC "\n", hcd_name); + +	ohci_init_driver(&ohci_omap_hc_driver, &omap_overrides); +	return platform_driver_register(&ohci_hcd_omap_driver); +} +module_init(ohci_omap_init); + +static void __exit ohci_omap_cleanup(void) +{ +	platform_driver_unregister(&ohci_hcd_omap_driver); +} +module_exit(ohci_omap_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_ALIAS("platform:ohci"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c index a09af26f69e..ec15aebe878 100644 --- a/drivers/usb/host/ohci-omap3.c +++ b/drivers/usb/host/ohci-omap3.c @@ -29,90 +29,22 @@   *	- add kernel-doc   */ +#include <linux/dma-mapping.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/usb/otg.h>  #include <linux/platform_device.h>  #include <linux/pm_runtime.h> -#include <linux/of.h> -#include <linux/dma-mapping.h> - -/*-------------------------------------------------------------------------*/ - -static int ohci_omap3_init(struct usb_hcd *hcd) -{ -	dev_dbg(hcd->self.controller, "starting OHCI controller\n"); - -	return ohci_init(hcd_to_ohci(hcd)); -} - -/*-------------------------------------------------------------------------*/ - -static int ohci_omap3_start(struct usb_hcd *hcd) -{ -	struct ohci_hcd *ohci = hcd_to_ohci(hcd); -	int ret; - -	/* -	 * RemoteWakeupConnected has to be set explicitly before -	 * calling ohci_run. The reset value of RWC is 0. -	 */ -	ohci->hc_control = OHCI_CTRL_RWC; -	writel(OHCI_CTRL_RWC, &ohci->regs->control); - -	ret = ohci_run(ohci); - -	if (ret < 0) { -		dev_err(hcd->self.controller, "can't start\n"); -		ohci_stop(hcd); -	} - -	return ret; -} - -/*-------------------------------------------------------------------------*/ - -static const struct hc_driver ohci_omap3_hc_driver = { -	.description =		hcd_name, -	.product_desc =		"OMAP3 OHCI Host Controller", -	.hcd_priv_size =	sizeof(struct ohci_hcd), - -	/* -	 * generic hardware linkage -	 */ -	.irq =			ohci_irq, -	.flags =		HCD_USB11 | HCD_MEMORY, - -	/* -	 * basic lifecycle operations -	 */ -	.reset =		ohci_omap3_init, -	.start =		ohci_omap3_start, -	.stop =			ohci_stop, -	.shutdown =		ohci_shutdown, - -	/* -	 * managing i/o requests and associated device resources -	 */ -	.urb_enqueue =		ohci_urb_enqueue, -	.urb_dequeue =		ohci_urb_dequeue, -	.endpoint_disable =	ohci_endpoint_disable, +#include <linux/usb.h> +#include <linux/usb/hcd.h> -	/* -	 * scheduling support -	 */ -	.get_frame_number =	ohci_get_frame, +#include "ohci.h" -	/* -	 * root hub support -	 */ -	.hub_status_data =	ohci_hub_status_data, -	.hub_control =		ohci_hub_control, -#ifdef	CONFIG_PM -	.bus_suspend =		ohci_bus_suspend, -	.bus_resume =		ohci_bus_resume, -#endif -	.start_port_reset =	ohci_start_port_reset, -}; +#define DRIVER_DESC "OHCI OMAP3 driver" -/*-------------------------------------------------------------------------*/ +static const char hcd_name[] = "ohci-omap3"; +static struct hc_driver __read_mostly ohci_omap3_hc_driver;  /*   * configure so an HC device and id are always provided @@ -129,10 +61,11 @@ static const struct hc_driver ohci_omap3_hc_driver = {  static int ohci_hcd_omap3_probe(struct platform_device *pdev)  {  	struct device		*dev = &pdev->dev; +	struct ohci_hcd		*ohci;  	struct usb_hcd		*hcd = NULL;  	void __iomem		*regs = NULL;  	struct resource		*res; -	int			ret = -ENODEV; +	int			ret;  	int			irq;  	if (usb_disabled()) @@ -166,11 +99,11 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev)  	 * Since shared usb code relies on it, set it here for now.  	 * Once we have dma capability bindings this can go away.  	 */ -	if (!dev->dma_mask) -		dev->dma_mask = &dev->coherent_dma_mask; -	if (!dev->coherent_dma_mask) -		dev->coherent_dma_mask = DMA_BIT_MASK(32); +	ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); +	if (ret) +		goto err_io; +	ret = -ENODEV;  	hcd = usb_create_hcd(&ohci_omap3_hc_driver, dev,  			dev_name(dev));  	if (!hcd) { @@ -185,13 +118,19 @@ static int ohci_hcd_omap3_probe(struct platform_device *pdev)  	pm_runtime_enable(dev);  	pm_runtime_get_sync(dev); -	ohci_hcd_init(hcd_to_ohci(hcd)); +	ohci = hcd_to_ohci(hcd); +	/* +	 * RemoteWakeupConnected has to be set explicitly before +	 * calling ohci_run. The reset value of RWC is 0. +	 */ +	ohci->hc_control = OHCI_CTRL_RWC;  	ret = usb_add_hcd(hcd, irq, 0);  	if (ret) {  		dev_dbg(dev, "failed to add hcd with err %d\n", ret);  		goto err_add_hcd;  	} +	device_wakeup_enable(hcd->self.controller);  	return 0; @@ -248,5 +187,25 @@ static struct platform_driver ohci_hcd_omap3_driver = {  	},  }; +static int __init ohci_omap3_init(void) +{ +	if (usb_disabled()) +		return -ENODEV; + +	pr_info("%s: " DRIVER_DESC "\n", hcd_name); + +	ohci_init_driver(&ohci_omap3_hc_driver, NULL); +	return platform_driver_register(&ohci_hcd_omap3_driver); +} +module_init(ohci_omap3_init); + +static void __exit ohci_omap3_cleanup(void) +{ +	platform_driver_unregister(&ohci_hcd_omap3_driver); +} +module_exit(ohci_omap3_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_ALIAS("platform:ohci-omap3");  MODULE_AUTHOR("Anand Gadiyar <gadiyar@ti.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index ec337c2bd5e..bb150967572 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -150,28 +150,17 @@ static int ohci_quirk_nec(struct usb_hcd *hcd)  static int ohci_quirk_amd700(struct usb_hcd *hcd)  {  	struct ohci_hcd *ohci = hcd_to_ohci(hcd); -	struct pci_dev *amd_smbus_dev; -	u8 rev;  	if (usb_amd_find_chipset_info())  		ohci->flags |= OHCI_QUIRK_AMD_PLL; -	amd_smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, -			PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); -	if (!amd_smbus_dev) -		return 0; - -	rev = amd_smbus_dev->revision; -  	/* SB800 needs pre-fetch fix */ -	if ((rev >= 0x40) && (rev <= 0x4f)) { +	if (usb_amd_prefetch_quirk()) {  		ohci->flags |= OHCI_QUIRK_AMD_PREFETCH;  		ohci_dbg(ohci, "enabled AMD prefetch quirk\n");  	} -	pci_dev_put(amd_smbus_dev); -	amd_smbus_dev = NULL; - +	ohci->flags |= OHCI_QUIRK_GLOBAL_SUSPEND;  	return 0;  } @@ -323,3 +312,4 @@ module_exit(ohci_pci_cleanup);  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_LICENSE("GPL"); +MODULE_SOFTDEP("pre: ehci_pci"); diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index a4c6410f0ed..4369299064c 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -3,6 +3,7 @@   *   * Copyright 2007 Michael Buesch <m@bues.ch>   * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de> + * Copyright 2014 Hans de Goede <hdegoede@redhat.com>   *   * Derived from the OCHI-SSB driver   * Derived from the OHCI-PCI driver @@ -14,12 +15,16 @@   * Licensed under the GNU/GPL. See COPYING for details.   */ +#include <linux/clk.h> +#include <linux/dma-mapping.h>  #include <linux/hrtimer.h>  #include <linux/io.h>  #include <linux/kernel.h>  #include <linux/module.h>  #include <linux/err.h> +#include <linux/phy/phy.h>  #include <linux/platform_device.h> +#include <linux/reset.h>  #include <linux/usb/ohci_pdriver.h>  #include <linux/usb.h>  #include <linux/usb/hcd.h> @@ -27,6 +32,14 @@  #include "ohci.h"  #define DRIVER_DESC "OHCI generic platform driver" +#define OHCI_MAX_CLKS 3 +#define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv) + +struct ohci_platform_priv { +	struct clk *clks[OHCI_MAX_CLKS]; +	struct reset_control *rst; +	struct phy *phy; +};  static const char hcd_name[] = "ohci-platform"; @@ -36,10 +49,6 @@ static int ohci_platform_reset(struct usb_hcd *hcd)  	struct usb_ohci_pdata *pdata = dev_get_platdata(&pdev->dev);  	struct ohci_hcd *ohci = hcd_to_ohci(hcd); -	if (pdata->big_endian_desc) -		ohci->flags |= OHCI_QUIRK_BE_DESC; -	if (pdata->big_endian_mmio) -		ohci->flags |= OHCI_QUIRK_BE_MMIO;  	if (pdata->no_big_frame_no)  		ohci->flags |= OHCI_QUIRK_FRAME_NO;  	if (pdata->num_ports) @@ -48,11 +57,67 @@ static int ohci_platform_reset(struct usb_hcd *hcd)  	return ohci_setup(hcd);  } +static int ohci_platform_power_on(struct platform_device *dev) +{ +	struct usb_hcd *hcd = platform_get_drvdata(dev); +	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); +	int clk, ret; + +	for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) { +		ret = clk_prepare_enable(priv->clks[clk]); +		if (ret) +			goto err_disable_clks; +	} + +	if (priv->phy) { +		ret = phy_init(priv->phy); +		if (ret) +			goto err_disable_clks; + +		ret = phy_power_on(priv->phy); +		if (ret) +			goto err_exit_phy; +	} + +	return 0; + +err_exit_phy: +	phy_exit(priv->phy); +err_disable_clks: +	while (--clk >= 0) +		clk_disable_unprepare(priv->clks[clk]); + +	return ret; +} + +static void ohci_platform_power_off(struct platform_device *dev) +{ +	struct usb_hcd *hcd = platform_get_drvdata(dev); +	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); +	int clk; + +	if (priv->phy) { +		phy_power_off(priv->phy); +		phy_exit(priv->phy); +	} + +	for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--) +		if (priv->clks[clk]) +			clk_disable_unprepare(priv->clks[clk]); +} +  static struct hc_driver __read_mostly ohci_platform_hc_driver;  static const struct ohci_driver_overrides platform_overrides __initconst = { -	.product_desc =	"Generic Platform OHCI controller", -	.reset =	ohci_platform_reset, +	.product_desc =		"Generic Platform OHCI controller", +	.reset =		ohci_platform_reset, +	.extra_priv_size =	sizeof(struct ohci_platform_priv), +}; + +static struct usb_ohci_pdata ohci_platform_defaults = { +	.power_on =		ohci_platform_power_on, +	.power_suspend =	ohci_platform_power_off, +	.power_off =		ohci_platform_power_off,  };  static int ohci_platform_probe(struct platform_device *dev) @@ -60,17 +125,24 @@ static int ohci_platform_probe(struct platform_device *dev)  	struct usb_hcd *hcd;  	struct resource *res_mem;  	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); -	int irq; -	int err = -ENOMEM; - -	if (!pdata) { -		WARN_ON(1); -		return -ENODEV; -	} +	struct ohci_platform_priv *priv; +	struct ohci_hcd *ohci; +	int err, irq, clk = 0;  	if (usb_disabled())  		return -ENODEV; +	/* +	 * Use reasonable defaults so platforms don't have to provide these +	 * with DT probing on ARM. +	 */ +	if (!pdata) +		pdata = &ohci_platform_defaults; + +	err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); +	if (err) +		return err; +  	irq = platform_get_irq(dev, 0);  	if (irq < 0) {  		dev_err(&dev->dev, "no irq provided"); @@ -83,17 +155,85 @@ static int ohci_platform_probe(struct platform_device *dev)  		return -ENXIO;  	} +	hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev, +			dev_name(&dev->dev)); +	if (!hcd) +		return -ENOMEM; + +	platform_set_drvdata(dev, hcd); +	dev->dev.platform_data = pdata; +	priv = hcd_to_ohci_priv(hcd); +	ohci = hcd_to_ohci(hcd); + +	if (pdata == &ohci_platform_defaults && dev->dev.of_node) { +		if (of_property_read_bool(dev->dev.of_node, "big-endian-regs")) +			ohci->flags |= OHCI_QUIRK_BE_MMIO; + +		if (of_property_read_bool(dev->dev.of_node, "big-endian-desc")) +			ohci->flags |= OHCI_QUIRK_BE_DESC; + +		if (of_property_read_bool(dev->dev.of_node, "big-endian")) +			ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; + +		priv->phy = devm_phy_get(&dev->dev, "usb"); +		if (IS_ERR(priv->phy)) { +			err = PTR_ERR(priv->phy); +			if (err == -EPROBE_DEFER) +				goto err_put_hcd; +			priv->phy = NULL; +		} + +		for (clk = 0; clk < OHCI_MAX_CLKS; clk++) { +			priv->clks[clk] = of_clk_get(dev->dev.of_node, clk); +			if (IS_ERR(priv->clks[clk])) { +				err = PTR_ERR(priv->clks[clk]); +				if (err == -EPROBE_DEFER) +					goto err_put_clks; +				priv->clks[clk] = NULL; +				break; +			} +		} + +	} + +	priv->rst = devm_reset_control_get_optional(&dev->dev, NULL); +	if (IS_ERR(priv->rst)) { +		err = PTR_ERR(priv->rst); +		if (err == -EPROBE_DEFER) +			goto err_put_clks; +		priv->rst = NULL; +	} else { +		err = reset_control_deassert(priv->rst); +		if (err) +			goto err_put_clks; +	} + +	if (pdata->big_endian_desc) +		ohci->flags |= OHCI_QUIRK_BE_DESC; +	if (pdata->big_endian_mmio) +		ohci->flags |= OHCI_QUIRK_BE_MMIO; + +#ifndef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO +	if (ohci->flags & OHCI_QUIRK_BE_MMIO) { +		dev_err(&dev->dev, +			"Error: CONFIG_USB_OHCI_BIG_ENDIAN_MMIO not set\n"); +		err = -EINVAL; +		goto err_reset; +	} +#endif +#ifndef CONFIG_USB_OHCI_BIG_ENDIAN_DESC +	if (ohci->flags & OHCI_QUIRK_BE_DESC) { +		dev_err(&dev->dev, +			"Error: CONFIG_USB_OHCI_BIG_ENDIAN_DESC not set\n"); +		err = -EINVAL; +		goto err_reset; +	} +#endif +  	if (pdata->power_on) {  		err = pdata->power_on(dev);  		if (err < 0) -			return err; -	} - -	hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev, -			dev_name(&dev->dev)); -	if (!hcd) { -		err = -ENOMEM; -		goto err_power; +			goto err_reset;  	}  	hcd->rsrc_start = res_mem->start; @@ -102,21 +242,32 @@ static int ohci_platform_probe(struct platform_device *dev)  	hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);  	if (IS_ERR(hcd->regs)) {  		err = PTR_ERR(hcd->regs); -		goto err_put_hcd; +		goto err_power;  	}  	err = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (err) -		goto err_put_hcd; +		goto err_power; + +	device_wakeup_enable(hcd->self.controller);  	platform_set_drvdata(dev, hcd);  	return err; -err_put_hcd: -	usb_put_hcd(hcd);  err_power:  	if (pdata->power_off)  		pdata->power_off(dev); +err_reset: +	if (priv->rst) +		reset_control_assert(priv->rst); +err_put_clks: +	while (--clk >= 0) +		clk_put(priv->clks[clk]); +err_put_hcd: +	if (pdata == &ohci_platform_defaults) +		dev->dev.platform_data = NULL; + +	usb_put_hcd(hcd);  	return err;  } @@ -125,13 +276,25 @@ static int ohci_platform_remove(struct platform_device *dev)  {  	struct usb_hcd *hcd = platform_get_drvdata(dev);  	struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); +	struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); +	int clk;  	usb_remove_hcd(hcd); -	usb_put_hcd(hcd);  	if (pdata->power_off)  		pdata->power_off(dev); +	if (priv->rst) +		reset_control_assert(priv->rst); + +	for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) +		clk_put(priv->clks[clk]); + +	usb_put_hcd(hcd); + +	if (pdata == &ohci_platform_defaults) +		dev->dev.platform_data = NULL; +  	return 0;  } @@ -139,14 +302,21 @@ static int ohci_platform_remove(struct platform_device *dev)  static int ohci_platform_suspend(struct device *dev)  { -	struct usb_ohci_pdata *pdata = dev_get_platdata(dev); +	struct usb_hcd *hcd = dev_get_drvdata(dev); +	struct usb_ohci_pdata *pdata = dev->platform_data;  	struct platform_device *pdev =  		container_of(dev, struct platform_device, dev); +	bool do_wakeup = device_may_wakeup(dev); +	int ret; + +	ret = ohci_suspend(hcd, do_wakeup); +	if (ret) +		return ret;  	if (pdata->power_suspend)  		pdata->power_suspend(pdev); -	return 0; +	return ret;  }  static int ohci_platform_resume(struct device *dev) @@ -171,6 +341,12 @@ static int ohci_platform_resume(struct device *dev)  #define ohci_platform_resume	NULL  #endif /* CONFIG_PM */ +static const struct of_device_id ohci_platform_ids[] = { +	{ .compatible = "generic-ohci", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, ohci_platform_ids); +  static const struct platform_device_id ohci_platform_table[] = {  	{ "ohci-platform", 0 },  	{ } @@ -191,6 +367,7 @@ static struct platform_driver ohci_platform_driver = {  		.owner	= THIS_MODULE,  		.name	= "ohci-platform",  		.pm	= &ohci_platform_pm_ops, +		.of_match_table = ohci_platform_ids,  	}  }; diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index 75f5a1e2f01..965e3e9e688 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -14,6 +14,8 @@   */  #include <linux/signal.h> +#include <linux/of_address.h> +#include <linux/of_irq.h>  #include <linux/of_platform.h>  #include <asm/prom.h> @@ -113,24 +115,18 @@ static int ohci_hcd_ppc_of_probe(struct platform_device *op)  	hcd->rsrc_start = res.start;  	hcd->rsrc_len = resource_size(&res); -	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { -		printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__); -		rv = -EBUSY; +	hcd->regs = devm_ioremap_resource(&op->dev, &res); +	if (IS_ERR(hcd->regs)) { +		rv = PTR_ERR(hcd->regs);  		goto err_rmr;  	}  	irq = irq_of_parse_and_map(dn, 0);  	if (irq == NO_IRQ) { -		printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__); +		dev_err(&op->dev, "%s: irq_of_parse_and_map failed\n", +			__FILE__);  		rv = -EBUSY; -		goto err_irq; -	} - -	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); -	if (!hcd->regs) { -		printk(KERN_ERR "%s: ioremap failed\n", __FILE__); -		rv = -ENOMEM; -		goto err_ioremap; +		goto err_rmr;  	}  	ohci = hcd_to_ohci(hcd); @@ -145,8 +141,10 @@ static int ohci_hcd_ppc_of_probe(struct platform_device *op)  	ohci_hcd_init(ohci);  	rv = usb_add_hcd(hcd, irq, 0); -	if (rv == 0) +	if (rv == 0) { +		device_wakeup_enable(hcd->self.controller);  		return 0; +	}  	/* by now, 440epx is known to show usb_23 erratum */  	np = of_find_compatible_node(NULL, NULL, "ibm,usb-ehci-440epx"); @@ -172,11 +170,7 @@ static int ohci_hcd_ppc_of_probe(struct platform_device *op)  			pr_debug("%s: cannot get ehci offset from fdt\n", __FILE__);  	} -	iounmap(hcd->regs); -err_ioremap:  	irq_dispose_mapping(irq); -err_irq: -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  err_rmr:   	usb_put_hcd(hcd); @@ -191,9 +185,7 @@ static int ohci_hcd_ppc_of_remove(struct platform_device *op)  	usb_remove_hcd(hcd); -	iounmap(hcd->regs);  	irq_dispose_mapping(hcd->irq); -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	usb_put_hcd(hcd); diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c index 7d35cd9e286..71d8bc4c27f 100644 --- a/drivers/usb/host/ohci-ps3.c +++ b/drivers/usb/host/ohci-ps3.c @@ -173,6 +173,7 @@ static int ps3_ohci_probe(struct ps3_system_bus_device *dev)  		goto fail_add_hcd;  	} +	device_wakeup_enable(hcd->self.controller);  	return result;  fail_add_hcd: diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 93371a235e8..e68f3d02cd1 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -19,15 +19,28 @@   * This file is licenced under the GPL.   */ -#include <linux/device.h> -#include <linux/signal.h> -#include <linux/platform_device.h>  #include <linux/clk.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h>  #include <linux/of_platform.h>  #include <linux/of_gpio.h> -#include <mach/hardware.h>  #include <linux/platform_data/usb-ohci-pxa27x.h>  #include <linux/platform_data/usb-pxa3xx-ulpi.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> +#include <linux/signal.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/usb/otg.h> + +#include <mach/hardware.h> + +#include "ohci.h" + +#define DRIVER_DESC "OHCI PXA27x/PXA3x driver"  /*   * UHC: USB Host Controller (OHCI-like) register definitions @@ -101,16 +114,18 @@  #define PXA_UHC_MAX_PORTNUM    3 -struct pxa27x_ohci { -	/* must be 1st member here for hcd_to_ohci() to work */ -	struct ohci_hcd ohci; +static const char hcd_name[] = "ohci-pxa27x"; -	struct device	*dev; +static struct hc_driver __read_mostly ohci_pxa27x_hc_driver; + +struct pxa27x_ohci {  	struct clk	*clk;  	void __iomem	*mmio_base; +	struct regulator *vbus[3]; +	bool		vbus_enabled[3];  }; -#define to_pxa27x_ohci(hcd)	(struct pxa27x_ohci *)hcd_to_ohci(hcd) +#define to_pxa27x_ohci(hcd)	(struct pxa27x_ohci *)(hcd_to_ohci(hcd)->priv)  /*    PMM_NPS_MODE -- PMM Non-power switching mode @@ -122,10 +137,10 @@ struct pxa27x_ohci {    PMM_PERPORT_MODE -- PMM per port switching mode        Ports are powered individually.   */ -static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *ohci, int mode) +static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *pxa_ohci, int mode)  { -	uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA); -	uint32_t uhcrhdb = __raw_readl(ohci->mmio_base + UHCRHDB); +	uint32_t uhcrhda = __raw_readl(pxa_ohci->mmio_base + UHCRHDA); +	uint32_t uhcrhdb = __raw_readl(pxa_ohci->mmio_base + UHCRHDB);  	switch (mode) {  	case PMM_NPS_MODE: @@ -149,20 +164,64 @@ static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *ohci, int mode)  		uhcrhda |= RH_A_NPS;  	} -	__raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA); -	__raw_writel(uhcrhdb, ohci->mmio_base + UHCRHDB); +	__raw_writel(uhcrhda, pxa_ohci->mmio_base + UHCRHDA); +	__raw_writel(uhcrhdb, pxa_ohci->mmio_base + UHCRHDB);  	return 0;  } -extern int usb_disabled(void); +static int pxa27x_ohci_set_vbus_power(struct pxa27x_ohci *pxa_ohci, +				      unsigned int port, bool enable) +{ +	struct regulator *vbus = pxa_ohci->vbus[port]; +	int ret = 0; + +	if (IS_ERR_OR_NULL(vbus)) +		return 0; + +	if (enable && !pxa_ohci->vbus_enabled[port]) +		ret = regulator_enable(vbus); +	else if (!enable && pxa_ohci->vbus_enabled[port]) +		ret = regulator_disable(vbus); + +	if (ret < 0) +		return ret; + +	pxa_ohci->vbus_enabled[port] = enable; + +	return 0; +} +static int pxa27x_ohci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, +				   u16 wIndex, char *buf, u16 wLength) +{ +	struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); +	int ret; + +	switch (typeReq) { +	case SetPortFeature: +	case ClearPortFeature: +		if (!wIndex || wIndex > 3) +			return -EPIPE; + +		if (wValue != USB_PORT_FEAT_POWER) +			break; + +		ret = pxa27x_ohci_set_vbus_power(pxa_ohci, wIndex - 1, +						 typeReq == SetPortFeature); +		if (ret) +			return ret; +		break; +	} + +	return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); +}  /*-------------------------------------------------------------------------*/ -static inline void pxa27x_setup_hc(struct pxa27x_ohci *ohci, +static inline void pxa27x_setup_hc(struct pxa27x_ohci *pxa_ohci,  				   struct pxaohci_platform_data *inf)  { -	uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR); -	uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA); +	uint32_t uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR); +	uint32_t uhcrhda = __raw_readl(pxa_ohci->mmio_base + UHCRHDA);  	if (inf->flags & ENABLE_PORT1)  		uhchr &= ~UHCHR_SSEP1; @@ -194,17 +253,17 @@ static inline void pxa27x_setup_hc(struct pxa27x_ohci *ohci,  		uhcrhda |= UHCRHDA_POTPGT(inf->power_on_delay / 2);  	} -	__raw_writel(uhchr, ohci->mmio_base + UHCHR); -	__raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA); +	__raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR); +	__raw_writel(uhcrhda, pxa_ohci->mmio_base + UHCRHDA);  } -static inline void pxa27x_reset_hc(struct pxa27x_ohci *ohci) +static inline void pxa27x_reset_hc(struct pxa27x_ohci *pxa_ohci)  { -	uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR); +	uint32_t uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR); -	__raw_writel(uhchr | UHCHR_FHR, ohci->mmio_base + UHCHR); +	__raw_writel(uhchr | UHCHR_FHR, pxa_ohci->mmio_base + UHCHR);  	udelay(11); -	__raw_writel(uhchr & ~UHCHR_FHR, ohci->mmio_base + UHCHR); +	__raw_writel(uhchr & ~UHCHR_FHR, pxa_ohci->mmio_base + UHCHR);  }  #ifdef CONFIG_PXA27x @@ -213,25 +272,26 @@ extern void pxa27x_clear_otgph(void);  #define pxa27x_clear_otgph()	do {} while (0)  #endif -static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev) +static int pxa27x_start_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev)  {  	int retval = 0;  	struct pxaohci_platform_data *inf;  	uint32_t uhchr; +	struct usb_hcd *hcd = dev_get_drvdata(dev);  	inf = dev_get_platdata(dev); -	clk_prepare_enable(ohci->clk); +	clk_prepare_enable(pxa_ohci->clk); -	pxa27x_reset_hc(ohci); +	pxa27x_reset_hc(pxa_ohci); -	uhchr = __raw_readl(ohci->mmio_base + UHCHR) | UHCHR_FSBIR; -	__raw_writel(uhchr, ohci->mmio_base + UHCHR); +	uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR) | UHCHR_FSBIR; +	__raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR); -	while (__raw_readl(ohci->mmio_base + UHCHR) & UHCHR_FSBIR) +	while (__raw_readl(pxa_ohci->mmio_base + UHCHR) & UHCHR_FSBIR)  		cpu_relax(); -	pxa27x_setup_hc(ohci, inf); +	pxa27x_setup_hc(pxa_ohci, inf);  	if (inf->init)  		retval = inf->init(dev); @@ -240,38 +300,39 @@ static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev)  		return retval;  	if (cpu_is_pxa3xx()) -		pxa3xx_u2d_start_hc(&ohci_to_hcd(&ohci->ohci)->self); +		pxa3xx_u2d_start_hc(&hcd->self); -	uhchr = __raw_readl(ohci->mmio_base + UHCHR) & ~UHCHR_SSE; -	__raw_writel(uhchr, ohci->mmio_base + UHCHR); -	__raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, ohci->mmio_base + UHCHIE); +	uhchr = __raw_readl(pxa_ohci->mmio_base + UHCHR) & ~UHCHR_SSE; +	__raw_writel(uhchr, pxa_ohci->mmio_base + UHCHR); +	__raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, pxa_ohci->mmio_base + UHCHIE);  	/* Clear any OTG Pin Hold */  	pxa27x_clear_otgph();  	return 0;  } -static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev) +static void pxa27x_stop_hc(struct pxa27x_ohci *pxa_ohci, struct device *dev)  {  	struct pxaohci_platform_data *inf; +	struct usb_hcd *hcd = dev_get_drvdata(dev);  	uint32_t uhccoms;  	inf = dev_get_platdata(dev);  	if (cpu_is_pxa3xx()) -		pxa3xx_u2d_stop_hc(&ohci_to_hcd(&ohci->ohci)->self); +		pxa3xx_u2d_stop_hc(&hcd->self);  	if (inf->exit)  		inf->exit(dev); -	pxa27x_reset_hc(ohci); +	pxa27x_reset_hc(pxa_ohci);  	/* Host Controller Reset */ -	uhccoms = __raw_readl(ohci->mmio_base + UHCCOMS) | 0x01; -	__raw_writel(uhccoms, ohci->mmio_base + UHCCOMS); +	uhccoms = __raw_readl(pxa_ohci->mmio_base + UHCCOMS) | 0x01; +	__raw_writel(uhccoms, pxa_ohci->mmio_base + UHCCOMS);  	udelay(10); -	clk_disable_unprepare(ohci->clk); +	clk_disable_unprepare(pxa_ohci->clk);  }  #ifdef CONFIG_OF @@ -287,6 +348,7 @@ static int ohci_pxa_of_init(struct platform_device *pdev)  	struct device_node *np = pdev->dev.of_node;  	struct pxaohci_platform_data *pdata;  	u32 tmp; +	int ret;  	if (!np)  		return 0; @@ -295,10 +357,9 @@ static int ohci_pxa_of_init(struct platform_device *pdev)  	 * 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 = &pdev->dev.coherent_dma_mask; -	if (!pdev->dev.coherent_dma_mask) -		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (ret) +		return ret;  	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);  	if (!pdata) @@ -356,9 +417,11 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device  	int retval, irq;  	struct usb_hcd *hcd;  	struct pxaohci_platform_data *inf; -	struct pxa27x_ohci *ohci; +	struct pxa27x_ohci *pxa_ohci; +	struct ohci_hcd *ohci;  	struct resource *r;  	struct clk *usb_clk; +	unsigned int i;  	retval = ohci_pxa_of_init(pdev);  	if (retval) @@ -375,71 +438,70 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device  		return -ENXIO;  	} -	usb_clk = clk_get(&pdev->dev, NULL); +	usb_clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(usb_clk))  		return PTR_ERR(usb_clk);  	hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x"); -	if (!hcd) { -		retval = -ENOMEM; -		goto err0; -	} +	if (!hcd) +		return -ENOMEM;  	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!r) {  		pr_err("no resource of IORESOURCE_MEM");  		retval = -ENXIO; -		goto err1; +		goto err;  	}  	hcd->rsrc_start = r->start;  	hcd->rsrc_len = resource_size(r); -	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { -		pr_debug("request_mem_region failed"); -		retval = -EBUSY; -		goto err1; -	} - -	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); -	if (!hcd->regs) { -		pr_debug("ioremap failed"); -		retval = -ENOMEM; -		goto err2; +	hcd->regs = devm_ioremap_resource(&pdev->dev, r); +	if (IS_ERR(hcd->regs)) { +		retval = PTR_ERR(hcd->regs); +		goto err;  	}  	/* initialize "struct pxa27x_ohci" */ -	ohci = (struct pxa27x_ohci *)hcd_to_ohci(hcd); -	ohci->dev = &pdev->dev; -	ohci->clk = usb_clk; -	ohci->mmio_base = (void __iomem *)hcd->regs; +	pxa_ohci = to_pxa27x_ohci(hcd); +	pxa_ohci->clk = usb_clk; +	pxa_ohci->mmio_base = (void __iomem *)hcd->regs; -	if ((retval = pxa27x_start_hc(ohci, &pdev->dev)) < 0) { +	for (i = 0; i < 3; ++i) { +		char name[6]; + +		if (!(inf->flags & (ENABLE_PORT1 << i))) +			continue; + +		sprintf(name, "vbus%u", i + 1); +		pxa_ohci->vbus[i] = devm_regulator_get(&pdev->dev, name); +	} + +	retval = pxa27x_start_hc(pxa_ohci, &pdev->dev); +	if (retval < 0) {  		pr_debug("pxa27x_start_hc failed"); -		goto err3; +		goto err;  	}  	/* Select Power Management Mode */ -	pxa27x_ohci_select_pmm(ohci, inf->port_mode); +	pxa27x_ohci_select_pmm(pxa_ohci, inf->port_mode);  	if (inf->power_budget)  		hcd->power_budget = inf->power_budget; -	ohci_hcd_init(hcd_to_ohci(hcd)); +	/* The value of NDP in roothub_a is incorrect on this hardware */ +	ohci = hcd_to_ohci(hcd); +	ohci->num_ports = 3;  	retval = usb_add_hcd(hcd, irq, 0); -	if (retval == 0) +	if (retval == 0) { +		device_wakeup_enable(hcd->self.controller);  		return retval; +	} -	pxa27x_stop_hc(ohci, &pdev->dev); - err3: -	iounmap(hcd->regs); - err2: -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - err1: +	pxa27x_stop_hc(pxa_ohci, &pdev->dev); + err:  	usb_put_hcd(hcd); - err0: -	clk_put(usb_clk);  	return retval;  } @@ -459,88 +521,20 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device   */  void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev)  { -	struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); +	struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); +	unsigned int i;  	usb_remove_hcd(hcd); -	pxa27x_stop_hc(ohci, &pdev->dev); -	iounmap(hcd->regs); -	release_mem_region(hcd->rsrc_start, hcd->rsrc_len); -	usb_put_hcd(hcd); -	clk_put(ohci->clk); -} - -/*-------------------------------------------------------------------------*/ +	pxa27x_stop_hc(pxa_ohci, &pdev->dev); -static int -ohci_pxa27x_start (struct usb_hcd *hcd) -{ -	struct ohci_hcd	*ohci = hcd_to_ohci (hcd); -	int		ret; - -	ohci_dbg (ohci, "ohci_pxa27x_start, ohci:%p", ohci); - -	/* The value of NDP in roothub_a is incorrect on this hardware */ -	ohci->num_ports = 3; - -	if ((ret = ohci_init(ohci)) < 0) -		return ret; - -	if ((ret = ohci_run (ohci)) < 0) { -		dev_err(hcd->self.controller, "can't start %s", -			hcd->self.bus_name); -		ohci_stop (hcd); -		return ret; -	} +	for (i = 0; i < 3; ++i) +		pxa27x_ohci_set_vbus_power(pxa_ohci, i, false); -	return 0; +	usb_put_hcd(hcd);  }  /*-------------------------------------------------------------------------*/ -static const struct hc_driver ohci_pxa27x_hc_driver = { -	.description =		hcd_name, -	.product_desc =		"PXA27x OHCI", -	.hcd_priv_size =	sizeof(struct pxa27x_ohci), - -	/* -	 * generic hardware linkage -	 */ -	.irq =			ohci_irq, -	.flags =		HCD_USB11 | HCD_MEMORY, - -	/* -	 * basic lifecycle operations -	 */ -	.start =		ohci_pxa27x_start, -	.stop =			ohci_stop, -	.shutdown =		ohci_shutdown, - -	/* -	 * managing i/o requests and associated device resources -	 */ -	.urb_enqueue =		ohci_urb_enqueue, -	.urb_dequeue =		ohci_urb_dequeue, -	.endpoint_disable =	ohci_endpoint_disable, - -	/* -	 * scheduling support -	 */ -	.get_frame_number =	ohci_get_frame, - -	/* -	 * root hub support -	 */ -	.hub_status_data =	ohci_hub_status_data, -	.hub_control =		ohci_hub_control, -#ifdef  CONFIG_PM -	.bus_suspend =		ohci_bus_suspend, -	.bus_resume =		ohci_bus_resume, -#endif -	.start_port_reset =	ohci_start_port_reset, -}; - -/*-------------------------------------------------------------------------*/ -  static int ohci_hcd_pxa27x_drv_probe(struct platform_device *pdev)  {  	pr_debug ("In ohci_hcd_pxa27x_drv_probe"); @@ -563,32 +557,42 @@ static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev)  static int ohci_hcd_pxa27x_drv_suspend(struct device *dev)  {  	struct usb_hcd *hcd = dev_get_drvdata(dev); -	struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); +	struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd); +	struct ohci_hcd *ohci = hcd_to_ohci(hcd); +	bool do_wakeup = device_may_wakeup(dev); +	int ret; -	if (time_before(jiffies, ohci->ohci.next_statechange)) + +	if (time_before(jiffies, ohci->next_statechange))  		msleep(5); -	ohci->ohci.next_statechange = jiffies; +	ohci->next_statechange = jiffies; -	pxa27x_stop_hc(ohci, dev); -	return 0; +	ret = ohci_suspend(hcd, do_wakeup); +	if (ret) +		return ret; + +	pxa27x_stop_hc(pxa_ohci, dev); +	return ret;  }  static int ohci_hcd_pxa27x_drv_resume(struct device *dev)  {  	struct usb_hcd *hcd = dev_get_drvdata(dev); -	struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); +	struct pxa27x_ohci *pxa_ohci = to_pxa27x_ohci(hcd);  	struct pxaohci_platform_data *inf = dev_get_platdata(dev); +	struct ohci_hcd *ohci = hcd_to_ohci(hcd);  	int status; -	if (time_before(jiffies, ohci->ohci.next_statechange)) +	if (time_before(jiffies, ohci->next_statechange))  		msleep(5); -	ohci->ohci.next_statechange = jiffies; +	ohci->next_statechange = jiffies; -	if ((status = pxa27x_start_hc(ohci, dev)) < 0) +	status = pxa27x_start_hc(pxa_ohci, dev); +	if (status < 0)  		return status;  	/* Select Power Management Mode */ -	pxa27x_ohci_select_pmm(ohci, inf->port_mode); +	pxa27x_ohci_select_pmm(pxa_ohci, inf->port_mode);  	ohci_resume(hcd, false);  	return 0; @@ -600,9 +604,6 @@ static const struct dev_pm_ops ohci_hcd_pxa27x_pm_ops = {  };  #endif -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:pxa27x-ohci"); -  static struct platform_driver ohci_hcd_pxa27x_driver = {  	.probe		= ohci_hcd_pxa27x_drv_probe,  	.remove		= ohci_hcd_pxa27x_drv_remove, @@ -617,3 +618,30 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {  	},  }; +static const struct ohci_driver_overrides pxa27x_overrides __initconst = { +	.extra_priv_size =      sizeof(struct pxa27x_ohci), +}; + +static int __init ohci_pxa27x_init(void) +{ +	if (usb_disabled()) +		return -ENODEV; + +	pr_info("%s: " DRIVER_DESC "\n", hcd_name); + +	ohci_init_driver(&ohci_pxa27x_hc_driver, &pxa27x_overrides); +	ohci_pxa27x_hc_driver.hub_control = pxa27x_ohci_hub_control; + +	return platform_driver_register(&ohci_hcd_pxa27x_driver); +} +module_init(ohci_pxa27x_init); + +static void __exit ohci_pxa27x_cleanup(void) +{ +	platform_driver_unregister(&ohci_hcd_pxa27x_driver); +} +module_exit(ohci_pxa27x_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pxa27x-ohci"); diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c index df4a6707322..d4253e31942 100644 --- a/drivers/usb/host/ohci-q.c +++ b/drivers/usb/host/ohci-q.c @@ -41,9 +41,13 @@ finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status)  __releases(ohci->lock)  __acquires(ohci->lock)  { -	 struct device *dev = ohci_to_hcd(ohci)->self.controller; +	struct device *dev = ohci_to_hcd(ohci)->self.controller; +	struct usb_host_endpoint *ep = urb->ep; +	struct urb_priv *urb_priv; +  	// ASSERT (urb->hcpriv != 0); + restart:  	urb_free_priv (ohci, urb->hcpriv);  	urb->hcpriv = NULL;  	if (likely(status == -EINPROGRESS)) @@ -64,10 +68,6 @@ __acquires(ohci->lock)  		break;  	} -#ifdef OHCI_VERBOSE_DEBUG -	urb_print(urb, "RET", usb_pipeout (urb->pipe), status); -#endif -  	/* urb->complete() can reenter this HCD */  	usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb);  	spin_unlock (&ohci->lock); @@ -80,6 +80,21 @@ __acquires(ohci->lock)  		ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_IE);  		ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);  	} + +	/* +	 * An isochronous URB that is sumitted too late won't have any TDs +	 * (marked by the fact that the td_cnt value is larger than the +	 * actual number of TDs).  If the next URB on this endpoint is like +	 * that, give it back now. +	 */ +	if (!list_empty(&ep->urb_list)) { +		urb = list_first_entry(&ep->urb_list, struct urb, urb_list); +		urb_priv = urb->hcpriv; +		if (urb_priv->td_cnt > urb_priv->length) { +			status = 0; +			goto restart; +		} +	}  } @@ -128,7 +143,7 @@ static void periodic_link (struct ohci_hcd *ohci, struct ed *ed)  {  	unsigned	i; -	ohci_vdbg (ohci, "link %sed %p branch %d [%dus.], interval %d\n", +	ohci_dbg(ohci, "link %sed %p branch %d [%dus.], interval %d\n",  		(ed->hwINFO & cpu_to_hc32 (ohci, ED_ISO)) ? "iso " : "",  		ed, ed->branch, ed->load, ed->interval); @@ -275,7 +290,7 @@ static void periodic_unlink (struct ohci_hcd *ohci, struct ed *ed)  	}  	ohci_to_hcd(ohci)->self.bandwidth_allocated -= ed->load / ed->interval; -	ohci_vdbg (ohci, "unlink %sed %p branch %d [%dus.], interval %d\n", +	ohci_dbg(ohci, "unlink %sed %p branch %d [%dus.], interval %d\n",  		(ed->hwINFO & cpu_to_hc32 (ohci, ED_ISO)) ? "iso " : "",  		ed, ed->branch, ed->load, ed->interval);  } @@ -546,7 +561,6 @@ td_fill (struct ohci_hcd *ohci, u32 info,  		td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000);  		*ohci_hwPSWp(ohci, td, 0) = cpu_to_hc16 (ohci,  						(data & 0x0FFF) | 0xE000); -		td->ed->last_iso = info & 0xffff;  	} else {  		td->hwCBP = cpu_to_hc32 (ohci, data);  	} @@ -747,7 +761,7 @@ static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td)  		urb->iso_frame_desc [td->index].status = cc_to_error [cc];  		if (cc != TD_CC_NOERROR) -			ohci_vdbg (ohci, +			ohci_dbg(ohci,  				"urb %p iso td %p (%d) len %d cc %d\n",  				urb, td, 1 + td->index, dlen, cc); @@ -779,7 +793,7 @@ static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td)  		}  		if (cc != TD_CC_NOERROR && cc < 0x0E) -			ohci_vdbg (ohci, +			ohci_dbg(ohci,  				"urb %p td %p (%d) cc %d, len=%d/%d\n",  				urb, td, 1 + td->index, cc,  				urb->actual_length, @@ -996,7 +1010,7 @@ rescan_this:  			urb_priv->td_cnt++;  			/* if URB is done, clean up */ -			if (urb_priv->td_cnt == urb_priv->length) { +			if (urb_priv->td_cnt >= urb_priv->length) {  				modified = completed = 1;  				finish_urb(ohci, urb, 0);  			} @@ -1086,7 +1100,7 @@ static void takeback_td(struct ohci_hcd *ohci, struct td *td)  	urb_priv->td_cnt++;  	/* If all this urb's TDs are done, call complete() */ -	if (urb_priv->td_cnt == urb_priv->length) +	if (urb_priv->td_cnt >= urb_priv->length)  		finish_urb(ohci, urb, status);  	/* clean schedule:  unlink EDs that are no longer busy */ diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 4919afa4125..3d753a9d314 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -19,14 +19,27 @@   * This file is licenced under the GPL.  */ -#include <linux/platform_device.h>  #include <linux/clk.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h>  #include <linux/platform_data/usb-ohci-s3c2410.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> + +#include "ohci.h" +  #define valid_port(idx) ((idx) == 1 || (idx) == 2)  /* clock device associated with the hcd */ + +#define DRIVER_DESC "OHCI S3C2410 driver" + +static const char hcd_name[] = "ohci-s3c2410"; +  static struct clk *clk;  static struct clk *usb_clk; @@ -47,10 +60,10 @@ static void s3c2410_start_hc(struct platform_device *dev, struct usb_hcd *hcd)  	dev_dbg(&dev->dev, "s3c2410_start_hc:\n"); -	clk_enable(usb_clk); +	clk_prepare_enable(usb_clk);  	mdelay(2);			/* let the bus clock stabilise */ -	clk_enable(clk); +	clk_prepare_enable(clk);  	if (info != NULL) {  		info->hcd	= hcd; @@ -75,8 +88,8 @@ static void s3c2410_stop_hc(struct platform_device *dev)  			(info->enable_oc)(info, 0);  	} -	clk_disable(clk); -	clk_disable(usb_clk); +	clk_disable_unprepare(clk); +	clk_disable_unprepare(usb_clk);  }  /* ohci_s3c2410_hub_status_data @@ -93,7 +106,7 @@ ohci_s3c2410_hub_status_data(struct usb_hcd *hcd, char *buf)  	int orig;  	int portno; -	orig  = ohci_hub_status_data(hcd, buf); +	orig = ohci_hub_status_data(hcd, buf);  	if (info == NULL)  		return orig; @@ -374,12 +387,11 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,  	s3c2410_start_hc(dev, hcd); -	ohci_hcd_init(hcd_to_ohci(hcd)); -  	retval = usb_add_hcd(hcd, dev->resource[1].start, 0);  	if (retval != 0)  		goto err_ioremap; +	device_wakeup_enable(hcd->self.controller);  	return 0;   err_ioremap: @@ -392,71 +404,7 @@ static int usb_hcd_s3c2410_probe(const struct hc_driver *driver,  /*-------------------------------------------------------------------------*/ -static int -ohci_s3c2410_start(struct usb_hcd *hcd) -{ -	struct ohci_hcd	*ohci = hcd_to_ohci(hcd); -	int ret; - -	ret = ohci_init(ohci); -	if (ret < 0) -		return ret; - -	ret = ohci_run(ohci); -	if (ret < 0) { -		dev_err(hcd->self.controller, "can't start %s\n", -			hcd->self.bus_name); -		ohci_stop(hcd); -		return ret; -	} - -	return 0; -} - - -static const struct hc_driver ohci_s3c2410_hc_driver = { -	.description =		hcd_name, -	.product_desc =		"S3C24XX OHCI", -	.hcd_priv_size =	sizeof(struct ohci_hcd), - -	/* -	 * generic hardware linkage -	 */ -	.irq =			ohci_irq, -	.flags =		HCD_USB11 | HCD_MEMORY, - -	/* -	 * basic lifecycle operations -	 */ -	.start =		ohci_s3c2410_start, -	.stop =			ohci_stop, -	.shutdown =		ohci_shutdown, - -	/* -	 * managing i/o requests and associated device resources -	 */ -	.urb_enqueue =		ohci_urb_enqueue, -	.urb_dequeue =		ohci_urb_dequeue, -	.endpoint_disable =	ohci_endpoint_disable, - -	/* -	 * scheduling support -	 */ -	.get_frame_number =	ohci_get_frame, - -	/* -	 * root hub support -	 */ -	.hub_status_data =	ohci_s3c2410_hub_status_data, -	.hub_control =		ohci_s3c2410_hub_control, -#ifdef	CONFIG_PM -	.bus_suspend =		ohci_bus_suspend, -	.bus_resume =		ohci_bus_resume, -#endif -	.start_port_reset =	ohci_start_port_reset, -}; - -/* device driver */ +static struct hc_driver __read_mostly ohci_s3c2410_hc_driver;  static int ohci_hcd_s3c2410_drv_probe(struct platform_device *pdev)  { @@ -475,28 +423,15 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)  static int ohci_hcd_s3c2410_drv_suspend(struct device *dev)  {  	struct usb_hcd *hcd = dev_get_drvdata(dev); -	struct ohci_hcd *ohci = hcd_to_ohci(hcd);  	struct platform_device *pdev = to_platform_device(dev); -	unsigned long flags; +	bool do_wakeup = device_may_wakeup(dev);  	int rc = 0; -	/* -	 * Root hub was already suspended. Disable irq emission and -	 * mark HW unaccessible, bail out if RH has been resumed. Use -	 * the spinlock to properly synchronize with possible pending -	 * RH suspend or resume activity. -	 */ -	spin_lock_irqsave(&ohci->lock, flags); -	if (ohci->rh_state != OHCI_RH_SUSPENDED) { -		rc = -EINVAL; -		goto bail; -	} - -	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); +	rc = ohci_suspend(hcd, do_wakeup); +	if (rc) +		return rc;  	s3c2410_stop_hc(pdev); -bail: -	spin_unlock_irqrestore(&ohci->lock, flags);  	return rc;  } @@ -533,4 +468,36 @@ static struct platform_driver ohci_hcd_s3c2410_driver = {  	},  }; +static int __init ohci_s3c2410_init(void) +{ +	if (usb_disabled()) +		return -ENODEV; + +	pr_info("%s: " DRIVER_DESC "\n", hcd_name); +	ohci_init_driver(&ohci_s3c2410_hc_driver, NULL); + +	/* +	 * The Samsung HW has some unusual quirks, which require +	 * Sumsung-specific workarounds. We override certain hc_driver +	 * functions here to achieve that. We explicitly do not enhance +	 * ohci_driver_overrides to allow this more easily, since this +	 * is an unusual case, and we don't want to encourage others to +	 * override these functions by making it too easy. +	 */ + +	ohci_s3c2410_hc_driver.hub_status_data	= ohci_s3c2410_hub_status_data; +	ohci_s3c2410_hc_driver.hub_control	= ohci_s3c2410_hub_control; + +	return platform_driver_register(&ohci_hcd_s3c2410_driver); +} +module_init(ohci_s3c2410_init); + +static void __exit ohci_s3c2410_cleanup(void) +{ +	platform_driver_unregister(&ohci_hcd_s3c2410_driver); +} +module_exit(ohci_s3c2410_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL");  MODULE_ALIAS("platform:s3c2410-ohci"); diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index 17b2a7dad77..2ac266d692a 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -185,6 +185,12 @@ static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)  	if (usb_disabled())  		return -ENODEV; +	/* +	 * We don't call dma_set_mask_and_coherent() here because the +	 * DMA mask has already been appropraitely setup by the core +	 * SA-1111 bus code (which includes bug workarounds.) +	 */ +  	hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111");  	if (!hcd)  		return -ENOMEM; @@ -205,8 +211,10 @@ static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)  		goto err2;  	ret = usb_add_hcd(hcd, dev->irq[1], 0); -	if (ret == 0) +	if (ret == 0) { +		device_wakeup_enable(hcd->self.controller);  		return ret; +	}  	sa1111_stop_hc(dev);   err2: diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c index d479d5ddab8..4e81c804c73 100644 --- a/drivers/usb/host/ohci-sm501.c +++ b/drivers/usb/host/ohci-sm501.c @@ -168,6 +168,7 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)  	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (retval)  		goto err5; +	device_wakeup_enable(hcd->self.controller);  	/* enable power and unmask interrupts */ @@ -216,14 +217,21 @@ static int ohci_hcd_sm501_drv_remove(struct platform_device *pdev)  static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg)  {  	struct device *dev = &pdev->dev; -	struct ohci_hcd	*ohci = hcd_to_ohci(platform_get_drvdata(pdev)); +	struct usb_hcd  *hcd = platform_get_drvdata(pdev); +	struct ohci_hcd	*ohci = hcd_to_ohci(hcd); +	bool do_wakeup = device_may_wakeup(dev); +	int ret;  	if (time_before(jiffies, ohci->next_statechange))  		msleep(5);  	ohci->next_statechange = jiffies; +	ret = ohci_suspend(hcd, do_wakeup); +	if (ret) +		return ret; +  	sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0); -	return 0; +	return ret;  }  static int ohci_sm501_resume(struct platform_device *pdev) diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index cc9dd9e4f05..8b29a0c04c2 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -11,92 +11,37 @@  * warranty of any kind, whether express or implied.  */ -#include <linux/signal.h> -#include <linux/platform_device.h>  #include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h>  #include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/signal.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include "ohci.h" + +#define DRIVER_DESC "OHCI SPEAr driver" + +static const char hcd_name[] = "SPEAr-ohci";  struct spear_ohci { -	struct ohci_hcd ohci;  	struct clk *clk;  }; -#define to_spear_ohci(hcd)	(struct spear_ohci *)hcd_to_ohci(hcd) - -static void spear_start_ohci(struct spear_ohci *ohci) -{ -	clk_prepare_enable(ohci->clk); -} - -static void spear_stop_ohci(struct spear_ohci *ohci) -{ -	clk_disable_unprepare(ohci->clk); -} - -static int ohci_spear_start(struct usb_hcd *hcd) -{ -	struct ohci_hcd *ohci = hcd_to_ohci(hcd); -	int ret; - -	ret = ohci_init(ohci); -	if (ret < 0) -		return ret; -	ohci->regs = hcd->regs; - -	ret = ohci_run(ohci); -	if (ret < 0) { -		dev_err(hcd->self.controller, "can't start\n"); -		ohci_stop(hcd); -		return ret; -	} - -	create_debug_files(ohci); - -#ifdef DEBUG -	ohci_dump(ohci, 1); -#endif -	return 0; -} - -static const struct hc_driver ohci_spear_hc_driver = { -	.description		= hcd_name, -	.product_desc		= "SPEAr OHCI", -	.hcd_priv_size		= sizeof(struct spear_ohci), - -	/* generic hardware linkage */ -	.irq			= ohci_irq, -	.flags			= HCD_USB11 | HCD_MEMORY, - -	/* basic lifecycle operations */ -	.start			= ohci_spear_start, -	.stop			= ohci_stop, -	.shutdown		= ohci_shutdown, -#ifdef	CONFIG_PM -	.bus_suspend		= ohci_bus_suspend, -	.bus_resume		= ohci_bus_resume, -#endif - -	/* managing i/o requests and associated device resources */ -	.urb_enqueue		= ohci_urb_enqueue, -	.urb_dequeue		= ohci_urb_dequeue, -	.endpoint_disable	= ohci_endpoint_disable, - -	/* scheduling support */ -	.get_frame_number	= ohci_get_frame, +#define to_spear_ohci(hcd)     (struct spear_ohci *)(hcd_to_ohci(hcd)->priv) -	/* root hub support */ -	.hub_status_data	= ohci_hub_status_data, -	.hub_control		= ohci_hub_control, - -	.start_port_reset	= ohci_start_port_reset, -}; +static struct hc_driver __read_mostly ohci_spear_hc_driver;  static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)  {  	const struct hc_driver *driver = &ohci_spear_hc_driver; +	struct ohci_hcd *ohci;  	struct usb_hcd *hcd = NULL;  	struct clk *usbh_clk; -	struct spear_ohci *ohci_p; +	struct spear_ohci *sohci_p;  	struct resource *res;  	int retval, irq; @@ -111,10 +56,9 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)  	 * 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 = &pdev->dev.coherent_dma_mask; -	if (!pdev->dev.coherent_dma_mask) -		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (retval) +		goto fail;  	usbh_clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(usbh_clk)) { @@ -137,30 +81,27 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev)  	hcd->rsrc_start = pdev->resource[0].start;  	hcd->rsrc_len = resource_size(res); -	if (!devm_request_mem_region(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len, -				hcd_name)) { -		dev_dbg(&pdev->dev, "request_mem_region failed\n"); -		retval = -EBUSY; -		goto err_put_hcd; -	} -	hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len); -	if (!hcd->regs) { -		dev_dbg(&pdev->dev, "ioremap failed\n"); -		retval = -ENOMEM; +	hcd->regs = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(hcd->regs)) { +		retval = PTR_ERR(hcd->regs);  		goto err_put_hcd;  	} -	ohci_p = (struct spear_ohci *)hcd_to_ohci(hcd); -	ohci_p->clk = usbh_clk; -	spear_start_ohci(ohci_p); -	ohci_hcd_init(hcd_to_ohci(hcd)); +	sohci_p = to_spear_ohci(hcd); +	sohci_p->clk = usbh_clk; + +	clk_prepare_enable(sohci_p->clk); + +	ohci = hcd_to_ohci(hcd);  	retval = usb_add_hcd(hcd, platform_get_irq(pdev, 0), 0); -	if (retval == 0) +	if (retval == 0) { +		device_wakeup_enable(hcd->self.controller);  		return retval; +	} -	spear_stop_ohci(ohci_p); +	clk_disable_unprepare(sohci_p->clk);  err_put_hcd:  	usb_put_hcd(hcd);  fail: @@ -172,43 +113,50 @@ fail:  static int spear_ohci_hcd_drv_remove(struct platform_device *pdev)  {  	struct usb_hcd *hcd = platform_get_drvdata(pdev); -	struct spear_ohci *ohci_p = to_spear_ohci(hcd); +	struct spear_ohci *sohci_p = to_spear_ohci(hcd);  	usb_remove_hcd(hcd); -	if (ohci_p->clk) -		spear_stop_ohci(ohci_p); +	if (sohci_p->clk) +		clk_disable_unprepare(sohci_p->clk);  	usb_put_hcd(hcd);  	return 0;  }  #if defined(CONFIG_PM) -static int spear_ohci_hcd_drv_suspend(struct platform_device *dev, +static int spear_ohci_hcd_drv_suspend(struct platform_device *pdev,  		pm_message_t message)  { -	struct usb_hcd *hcd = platform_get_drvdata(dev); +	struct usb_hcd *hcd = platform_get_drvdata(pdev);  	struct ohci_hcd	*ohci = hcd_to_ohci(hcd); -	struct spear_ohci *ohci_p = to_spear_ohci(hcd); +	struct spear_ohci *sohci_p = to_spear_ohci(hcd); +	bool do_wakeup = device_may_wakeup(&pdev->dev); +	int ret;  	if (time_before(jiffies, ohci->next_statechange))  		msleep(5);  	ohci->next_statechange = jiffies; -	spear_stop_ohci(ohci_p); -	return 0; +	ret = ohci_suspend(hcd, do_wakeup); +	if (ret) +		return ret; + +	clk_disable_unprepare(sohci_p->clk); + +	return ret;  }  static int spear_ohci_hcd_drv_resume(struct platform_device *dev)  {  	struct usb_hcd *hcd = platform_get_drvdata(dev);  	struct ohci_hcd	*ohci = hcd_to_ohci(hcd); -	struct spear_ohci *ohci_p = to_spear_ohci(hcd); +	struct spear_ohci *sohci_p = to_spear_ohci(hcd);  	if (time_before(jiffies, ohci->next_statechange))  		msleep(5);  	ohci->next_statechange = jiffies; -	spear_start_ohci(ohci_p); +	clk_prepare_enable(sohci_p->clk);  	ohci_resume(hcd, false);  	return 0;  } @@ -234,4 +182,28 @@ static struct platform_driver spear_ohci_hcd_driver = {  	},  }; +static const struct ohci_driver_overrides spear_overrides __initconst = { +	.extra_priv_size = sizeof(struct spear_ohci), +}; +static int __init ohci_spear_init(void) +{ +	if (usb_disabled()) +		return -ENODEV; + +	pr_info("%s: " DRIVER_DESC "\n", hcd_name); + +	ohci_init_driver(&ohci_spear_hc_driver, &spear_overrides); +	return platform_driver_register(&spear_ohci_hcd_driver); +} +module_init(ohci_spear_init); + +static void __exit ohci_spear_cleanup(void) +{ +	platform_driver_unregister(&spear_ohci_hcd_driver); +} +module_exit(ohci_spear_cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Deepak Sikri"); +MODULE_LICENSE("GPL v2");  MODULE_ALIAS("platform:spear-ohci"); diff --git a/drivers/usb/host/ohci-tilegx.c b/drivers/usb/host/ohci-tilegx.c index 22540ab71f5..bef6dfb0405 100644 --- a/drivers/usb/host/ohci-tilegx.c +++ b/drivers/usb/host/ohci-tilegx.c @@ -129,8 +129,8 @@ static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev)  	tilegx_start_ohc();  	/* Create our IRQs and register them. */ -	pdata->irq = create_irq(); -	if (pdata->irq < 0) { +	pdata->irq = irq_alloc_hwirq(-1); +	if (!pdata->irq) {  		ret = -ENXIO;  		goto err_no_irq;  	} @@ -159,11 +159,12 @@ static int ohci_hcd_tilegx_drv_probe(struct platform_device *pdev)  	ret = usb_add_hcd(hcd, pdata->irq, IRQF_SHARED);  	if (ret == 0) {  		platform_set_drvdata(pdev, hcd); +		device_wakeup_enable(hcd->self.controller);  		return ret;  	}  err_have_irq: -	destroy_irq(pdata->irq); +	irq_free_hwirq(pdata->irq);  err_no_irq:  	tilegx_stop_ohc();  	usb_put_hcd(hcd); @@ -181,7 +182,7 @@ static int ohci_hcd_tilegx_drv_remove(struct platform_device *pdev)  	usb_put_hcd(hcd);  	tilegx_stop_ohc();  	gxio_usb_host_destroy(&pdata->usb_ctx); -	destroy_irq(pdata->irq); +	irq_free_hwirq(pdata->irq);  	return 0;  } diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index ecb09a5ada9..bb409588d39 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c @@ -27,7 +27,6 @@  /*#include <linux/fs.h>  #include <linux/mount.h>  #include <linux/pagemap.h> -#include <linux/init.h>  #include <linux/namei.h>  #include <linux/sched.h>*/  #include <linux/platform_device.h> @@ -250,6 +249,7 @@ static int ohci_hcd_tmio_drv_probe(struct platform_device *dev)  	if (ret)  		goto err_add_hcd; +	device_wakeup_enable(hcd->self.controller);  	if (ret == 0)  		return ret; diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index e2e5faa5a40..05e02a709d4 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -405,6 +405,8 @@ struct ohci_hcd {  #define	OHCI_QUIRK_HUB_POWER	0x100			/* distrust firmware power/oc setup */  #define	OHCI_QUIRK_AMD_PLL	0x200			/* AMD PLL quirk*/  #define	OHCI_QUIRK_AMD_PREFETCH	0x400			/* pre-fetch for ISO transfer */ +#define	OHCI_QUIRK_GLOBAL_SUSPEND	0x800		/* must suspend ports */ +  	// there are also chip quirks/bugs in init logic  	struct work_struct	nec_work;	/* Worker for NEC quirk */ @@ -415,12 +417,11 @@ struct ohci_hcd {  	struct ed		*ed_to_check;  	unsigned		zf_delay; -#ifdef DEBUG  	struct dentry		*debug_dir;  	struct dentry		*debug_async;  	struct dentry		*debug_periodic;  	struct dentry		*debug_registers; -#endif +  	/* platform-specific data -- must come last */  	unsigned long           priv[0] __aligned(sizeof(s64)); @@ -474,10 +475,6 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci)  /*-------------------------------------------------------------------------*/ -#ifndef DEBUG -#define STUB_DEBUG_FILES -#endif	/* DEBUG */ -  #define ohci_dbg(ohci, fmt, args...) \  	dev_dbg (ohci_to_hcd(ohci)->self.controller , fmt , ## args )  #define ohci_err(ohci, fmt, args...) \ @@ -487,12 +484,6 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci)  #define ohci_warn(ohci, fmt, args...) \  	dev_warn (ohci_to_hcd(ohci)->self.controller , fmt , ## args ) -#ifdef OHCI_VERBOSE_DEBUG -#	define ohci_vdbg ohci_dbg -#else -#	define ohci_vdbg(ohci, fmt, args...) do { } while (0) -#endif -  /*-------------------------------------------------------------------------*/  /* @@ -738,3 +729,6 @@ extern int	ohci_setup(struct usb_hcd *hcd);  extern int	ohci_suspend(struct usb_hcd *hcd, bool do_wakeup);  extern int	ohci_resume(struct usb_hcd *hcd, bool hibernated);  #endif +extern int	ohci_hub_control(struct usb_hcd	*hcd, u16 typeReq, u16 wValue, +				 u16 wIndex, char *buf, u16 wLength); +extern int	ohci_hub_status_data(struct usb_hcd *hcd, char *buf); diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 4a6df2d8f90..e07248b6ab6 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -29,7 +29,6 @@  #include <linux/sched.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/interrupt.h> @@ -60,6 +59,10 @@  #define oxu_info(oxu, fmt, args...) \  		dev_info(oxu_to_hcd(oxu)->self.controller , fmt , ## args) +#ifdef CONFIG_DYNAMIC_DEBUG +#define DEBUG +#endif +  static inline struct usb_hcd *oxu_to_hcd(struct oxu_hcd *oxu)  {  	return container_of((void *) oxu, struct usb_hcd, hcd_priv); @@ -3747,6 +3750,7 @@ static struct usb_hcd *oxu_create(struct platform_device *pdev,  	if (ret < 0)  		return ERR_PTR(ret); +	device_wakeup_enable(hcd->self.controller);  	return hcd;  } diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 2c76ef1320e..2f3acebb577 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -12,7 +12,6 @@  #include <linux/kconfig.h>  #include <linux/kernel.h>  #include <linux/pci.h> -#include <linux/init.h>  #include <linux/delay.h>  #include <linux/export.h>  #include <linux/acpi.h> @@ -79,11 +78,30 @@  #define USB_INTEL_USB3_PSSEN   0xD8  #define USB_INTEL_USB3PRM      0xDC +/* + * amd_chipset_gen values represent AMD different chipset generations + */ +enum amd_chipset_gen { +	NOT_AMD_CHIPSET = 0, +	AMD_CHIPSET_SB600, +	AMD_CHIPSET_SB700, +	AMD_CHIPSET_SB800, +	AMD_CHIPSET_HUDSON2, +	AMD_CHIPSET_BOLTON, +	AMD_CHIPSET_YANGTZE, +	AMD_CHIPSET_UNKNOWN, +}; + +struct amd_chipset_type { +	enum amd_chipset_gen gen; +	u8 rev; +}; +  static struct amd_chipset_info {  	struct pci_dev	*nb_dev;  	struct pci_dev	*smbus_dev;  	int nb_type; -	int sb_type; +	struct amd_chipset_type sb_type;  	int isoc_reqs;  	int probe_count;  	int probe_result; @@ -91,6 +109,51 @@ static struct amd_chipset_info {  static DEFINE_SPINLOCK(amd_lock); +/* + * amd_chipset_sb_type_init - initialize amd chipset southbridge type + * + * AMD FCH/SB generation and revision is identified by SMBus controller + * vendor, device and revision IDs. + * + * Returns: 1 if it is an AMD chipset, 0 otherwise. + */ +static int amd_chipset_sb_type_init(struct amd_chipset_info *pinfo) +{ +	u8 rev = 0; +	pinfo->sb_type.gen = AMD_CHIPSET_UNKNOWN; + +	pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, +			PCI_DEVICE_ID_ATI_SBX00_SMBUS, NULL); +	if (pinfo->smbus_dev) { +		rev = pinfo->smbus_dev->revision; +		if (rev >= 0x10 && rev <= 0x1f) +			pinfo->sb_type.gen = AMD_CHIPSET_SB600; +		else if (rev >= 0x30 && rev <= 0x3f) +			pinfo->sb_type.gen = AMD_CHIPSET_SB700; +		else if (rev >= 0x40 && rev <= 0x4f) +			pinfo->sb_type.gen = AMD_CHIPSET_SB800; +	} else { +		pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, +				PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL); + +		if (!pinfo->smbus_dev) { +			pinfo->sb_type.gen = NOT_AMD_CHIPSET; +			return 0; +		} + +		rev = pinfo->smbus_dev->revision; +		if (rev >= 0x11 && rev <= 0x14) +			pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2; +		else if (rev >= 0x15 && rev <= 0x18) +			pinfo->sb_type.gen = AMD_CHIPSET_BOLTON; +		else if (rev >= 0x39 && rev <= 0x3a) +			pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE; +	} + +	pinfo->sb_type.rev = rev; +	return 1; +} +  void sb800_prefetch(struct device *dev, int on)  {  	u16 misc; @@ -106,7 +169,6 @@ EXPORT_SYMBOL_GPL(sb800_prefetch);  int usb_amd_find_chipset_info(void)  { -	u8 rev = 0;  	unsigned long flags;  	struct amd_chipset_info info;  	int ret; @@ -122,27 +184,17 @@ int usb_amd_find_chipset_info(void)  	memset(&info, 0, sizeof(info));  	spin_unlock_irqrestore(&amd_lock, flags); -	info.smbus_dev = pci_get_device(PCI_VENDOR_ID_ATI, 0x4385, NULL); -	if (info.smbus_dev) { -		rev = info.smbus_dev->revision; -		if (rev >= 0x40) -			info.sb_type = 1; -		else if (rev >= 0x30 && rev <= 0x3b) -			info.sb_type = 3; -	} else { -		info.smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, -						0x780b, NULL); -		if (!info.smbus_dev) { -			ret = 0; -			goto commit; -		} - -		rev = info.smbus_dev->revision; -		if (rev >= 0x11 && rev <= 0x18) -			info.sb_type = 2; +	if (!amd_chipset_sb_type_init(&info)) { +		ret = 0; +		goto commit;  	} -	if (info.sb_type == 0) { +	/* Below chipset generations needn't enable AMD PLL quirk */ +	if (info.sb_type.gen == AMD_CHIPSET_UNKNOWN || +			info.sb_type.gen == AMD_CHIPSET_SB600 || +			info.sb_type.gen == AMD_CHIPSET_YANGTZE || +			(info.sb_type.gen == AMD_CHIPSET_SB700 && +			info.sb_type.rev > 0x3b)) {  		if (info.smbus_dev) {  			pci_dev_put(info.smbus_dev);  			info.smbus_dev = NULL; @@ -197,6 +249,39 @@ commit:  }  EXPORT_SYMBOL_GPL(usb_amd_find_chipset_info); +int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev) +{ +	/* Make sure amd chipset type has already been initialized */ +	usb_amd_find_chipset_info(); +	if (amd_chipset.sb_type.gen != AMD_CHIPSET_YANGTZE) +		return 0; + +	dev_dbg(&pdev->dev, "QUIRK: Enable AMD remote wakeup fix\n"); +	return 1; +} +EXPORT_SYMBOL_GPL(usb_hcd_amd_remote_wakeup_quirk); + +bool usb_amd_hang_symptom_quirk(void) +{ +	u8 rev; + +	usb_amd_find_chipset_info(); +	rev = amd_chipset.sb_type.rev; +	/* SB600 and old version of SB700 have hang symptom bug */ +	return amd_chipset.sb_type.gen == AMD_CHIPSET_SB600 || +			(amd_chipset.sb_type.gen == AMD_CHIPSET_SB700 && +			 rev >= 0x3a && rev <= 0x3b); +} +EXPORT_SYMBOL_GPL(usb_amd_hang_symptom_quirk); + +bool usb_amd_prefetch_quirk(void) +{ +	usb_amd_find_chipset_info(); +	/* SB800 needs pre-fetch fix */ +	return amd_chipset.sb_type.gen == AMD_CHIPSET_SB800; +} +EXPORT_SYMBOL_GPL(usb_amd_prefetch_quirk); +  /*   * The hardware normally enables the A-link power management feature, which   * lets the system lower the power consumption in idle states. @@ -229,7 +314,9 @@ static void usb_amd_quirk_pll(int disable)  		}  	} -	if (amd_chipset.sb_type == 1 || amd_chipset.sb_type == 2) { +	if (amd_chipset.sb_type.gen == AMD_CHIPSET_SB800 || +			amd_chipset.sb_type.gen == AMD_CHIPSET_HUDSON2 || +			amd_chipset.sb_type.gen == AMD_CHIPSET_BOLTON) {  		outb_p(AB_REG_BAR_LOW, 0xcd6);  		addr_low = inb_p(0xcd7);  		outb_p(AB_REG_BAR_HIGH, 0xcd6); @@ -240,7 +327,8 @@ static void usb_amd_quirk_pll(int disable)  		outl_p(0x40, AB_DATA(addr));  		outl_p(0x34, AB_INDX(addr));  		val = inl_p(AB_DATA(addr)); -	} else if (amd_chipset.sb_type == 3) { +	} else if (amd_chipset.sb_type.gen == AMD_CHIPSET_SB700 && +			amd_chipset.sb_type.rev <= 0x3b) {  		pci_read_config_dword(amd_chipset.smbus_dev,  					AB_REG_BAR_SB700, &addr);  		outl(AX_INDXC, AB_INDX(addr)); @@ -353,7 +441,7 @@ void usb_amd_dev_put(void)  	amd_chipset.nb_dev = NULL;  	amd_chipset.smbus_dev = NULL;  	amd_chipset.nb_type = 0; -	amd_chipset.sb_type = 0; +	memset(&amd_chipset.sb_type, 0, sizeof(amd_chipset.sb_type));  	amd_chipset.isoc_reqs = 0;  	amd_chipset.probe_result = 0; @@ -568,6 +656,14 @@ static const struct dmi_system_id ehci_dmi_nohandoff_table[] = {  			DMI_MATCH(DMI_BIOS_VERSION, "Lucid-"),  		},  	}, +	{ +		/* HASEE E200 */ +		.matches = { +			DMI_MATCH(DMI_BOARD_VENDOR, "HASEE"), +			DMI_MATCH(DMI_BOARD_NAME, "E210"), +			DMI_MATCH(DMI_BIOS_VERSION, "6.00"), +		}, +	},  	{ }  }; @@ -577,9 +673,14 @@ static void ehci_bios_handoff(struct pci_dev *pdev,  {  	int try_handoff = 1, tried_handoff = 0; -	/* The Pegatron Lucid tablet sporadically waits for 98 seconds trying -	 * the handoff on its unused controller.  Skip it. */ -	if (pdev->vendor == 0x8086 && pdev->device == 0x283a) { +	/* +	 * The Pegatron Lucid tablet sporadically waits for 98 seconds trying +	 * the handoff on its unused controller.  Skip it. +	 * +	 * The HASEE E200 hangs when the semaphore is set (bugzilla #77021). +	 */ +	if (pdev->vendor == 0x8086 && (pdev->device == 0x283a || +			pdev->device == 0x27cc)) {  		if (dmi_check_system(ehci_dmi_nohandoff_table))  			try_handoff = 0;  	} @@ -759,6 +860,13 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)  	bool		ehci_found = false;  	struct pci_dev	*companion = NULL; +	/* Sony VAIO t-series with subsystem device ID 90a8 is not capable of +	 * switching ports from EHCI to xHCI +	 */ +	if (xhci_pdev->subsystem_vendor == PCI_VENDOR_ID_SONY && +	    xhci_pdev->subsystem_device == 0x90a8) +		return; +  	/* make sure an intel EHCI controller exists */  	for_each_pci_dev(companion) {  		if (companion->class == PCI_CLASS_SERIAL_USB_EHCI && @@ -799,7 +907,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)  	 * switchable ports.  	 */  	pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, -			cpu_to_le32(ports_available)); +			ports_available);  	pci_read_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,  			&ports_available); @@ -821,7 +929,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)  	 * host.  	 */  	pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, -			cpu_to_le32(ports_available)); +			ports_available);  	pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,  			&ports_available); diff --git a/drivers/usb/host/pci-quirks.h b/drivers/usb/host/pci-quirks.h index ed6700d00fe..c622ddf21c9 100644 --- a/drivers/usb/host/pci-quirks.h +++ b/drivers/usb/host/pci-quirks.h @@ -5,6 +5,9 @@  void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);  int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);  int usb_amd_find_chipset_info(void); +int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev); +bool usb_amd_hang_symptom_quirk(void); +bool usb_amd_prefetch_quirk(void);  void usb_amd_dev_put(void);  void usb_amd_quirk_pll_disable(void);  void usb_amd_quirk_pll_enable(void); diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 2ad004ae747..110b4b9ebea 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -27,7 +27,6 @@  #include <linux/kernel.h>  #include <linux/sched.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/delay.h>  #include <linux/list.h> @@ -95,7 +94,7 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597)  	int i = 0;  	if (r8a66597->pdata->on_chip) { -		clk_enable(r8a66597->clk); +		clk_prepare_enable(r8a66597->clk);  		do {  			r8a66597_write(r8a66597, SCKE, SYSCFG0);  			tmp = r8a66597_read(r8a66597, SYSCFG0); @@ -139,7 +138,7 @@ static void r8a66597_clock_disable(struct r8a66597 *r8a66597)  	udelay(1);  	if (r8a66597->pdata->on_chip) { -		clk_disable(r8a66597->clk); +		clk_disable_unprepare(r8a66597->clk);  	} else {  		r8a66597_bclr(r8a66597, PLLC, SYSCFG0);  		r8a66597_bclr(r8a66597, XCKE, SYSCFG0); @@ -2514,6 +2513,7 @@ static int r8a66597_probe(struct platform_device *pdev)  		dev_err(&pdev->dev, "Failed to add hcd\n");  		goto clean_up3;  	} +	device_wakeup_enable(hcd->self.controller);  	return 0; @@ -2534,7 +2534,7 @@ static struct platform_driver r8a66597_driver = {  	.probe =	r8a66597_probe,  	.remove =	r8a66597_remove,  	.driver		= { -		.name = (char *) hcd_name, +		.name = hcd_name,  		.owner	= THIS_MODULE,  		.pm	= R8A66597_DEV_PM_OPS,  	}, diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index 5477bf5df21..a517151867a 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -39,7 +39,6 @@  #include <linux/sched.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/timer.h>  #include <linux/list.h>  #include <linux/interrupt.h> @@ -1413,7 +1412,7 @@ static int sl811h_show(struct seq_file *s, void *unused)  			case SL11H_CTL1MASK_SE0: s = " se0/reset"; break;  			case SL11H_CTL1MASK_K: s = " k/resume"; break;  			default: s = "j"; break; -			}; s; }), +			} s; }),  			(t & SL11H_CTL1MASK_LSPD) ? " lowspeed" : "",  			(t & SL11H_CTL1MASK_SUSPEND) ? " suspend" : ""); @@ -1446,7 +1445,7 @@ static int sl811h_show(struct seq_file *s, void *unused)  			case USB_PID_SETUP: s = "setup"; break;  			case USB_PID_ACK: s = "status"; break;  			default: s = "?"; break; -			}; s;}), +			} s;}),  			ep->maxpacket,  			ep->nak_count, ep->error_count);  		list_for_each_entry (urb, &ep->hep->urb_list, urb_list) { @@ -1732,6 +1731,8 @@ sl811h_probe(struct platform_device *dev)  	if (retval != 0)  		goto err6; +	device_wakeup_enable(hcd->self.controller); +  	create_debug_file(sl811);  	return retval; diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 469564e57a5..88a9bffe93d 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -12,7 +12,6 @@  #include <linux/kernel.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/ptrace.h>  #include <linux/slab.h>  #include <linux/string.h> diff --git a/drivers/usb/host/ssb-hcd.c b/drivers/usb/host/ssb-hcd.c index 74af2c6287d..0196f766df7 100644 --- a/drivers/usb/host/ssb-hcd.c +++ b/drivers/usb/host/ssb-hcd.c @@ -163,8 +163,7 @@ static int ssb_hcd_probe(struct ssb_device *dev,  	/* TODO: Probably need checks here; is the core connected? */ -	if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || -	    dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) +	if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32)))  		return -EOPNOTSUPP;  	usb_dev = kzalloc(sizeof(struct ssb_hcd_device), GFP_KERNEL); diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index e402beb5a06..c0671750671 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -3133,6 +3133,7 @@ static int u132_probe(struct platform_device *pdev)  			u132_u132_put_kref(u132);  			return retval;  		} else { +			device_wakeup_enable(hcd->self.controller);  			u132_monitor_queue_work(u132, 100);  			return 0;  		} @@ -3217,7 +3218,7 @@ static struct platform_driver u132_platform_driver = {  	.suspend = u132_suspend,  	.resume = u132_resume,  	.driver = { -		   .name = (char *)hcd_name, +		   .name = hcd_name,  		   .owner = THIS_MODULE,  		   },  }; diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c index 45573754652..1b28a000d5c 100644 --- a/drivers/usb/host/uhci-debug.c +++ b/drivers/usb/host/uhci-debug.c @@ -20,7 +20,7 @@  static struct dentry *uhci_debugfs_root; -#ifdef DEBUG +#ifdef CONFIG_DYNAMIC_DEBUG  /* Handle REALLY large printks so we don't overflow buffers */  static void lprintk(char *buf) @@ -310,14 +310,14 @@ static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)  	unsigned short portsc1, portsc2; -	usbcmd    = uhci_readw(uhci, 0); -	usbstat   = uhci_readw(uhci, 2); -	usbint    = uhci_readw(uhci, 4); -	usbfrnum  = uhci_readw(uhci, 6); -	flbaseadd = uhci_readl(uhci, 8); -	sof       = uhci_readb(uhci, 12); -	portsc1   = uhci_readw(uhci, 16); -	portsc2   = uhci_readw(uhci, 18); +	usbcmd    = uhci_readw(uhci, USBCMD); +	usbstat   = uhci_readw(uhci, USBSTS); +	usbint    = uhci_readw(uhci, USBINTR); +	usbfrnum  = uhci_readw(uhci, USBFRNUM); +	flbaseadd = uhci_readl(uhci, USBFLBASEADD); +	sof       = uhci_readb(uhci, USBSOF); +	portsc1   = uhci_readw(uhci, USBPORTSC1); +	portsc2   = uhci_readw(uhci, USBPORTSC2);  	out += sprintf(out, "  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",  		usbcmd, @@ -635,7 +635,7 @@ static const struct file_operations uhci_debug_operations = {  #endif	/* CONFIG_DEBUG_FS */ -#else	/* DEBUG */ +#else	/* CONFIG_DYNAMIC_DEBUG*/  static inline void lprintk(char *buf)  {} diff --git a/drivers/usb/host/uhci-grlib.c b/drivers/usb/host/uhci-grlib.c index 53c23ff7d68..ab25dc397e8 100644 --- a/drivers/usb/host/uhci-grlib.c +++ b/drivers/usb/host/uhci-grlib.c @@ -141,6 +141,7 @@ static int uhci_hcd_grlib_probe(struct platform_device *op)  	if (rv)  		goto err_uhci; +	device_wakeup_enable(hcd->self.controller);  	return 0;  err_uhci: diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 4a86b63745b..27f35e8f161 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -69,18 +69,21 @@ MODULE_PARM_DESC(ignore_oc, "ignore hardware overcurrent indications");   *            show all queues in /sys/kernel/debug/uhci/[pci_addr]   * debug = 3, show all TDs in URBs when dumping   */ -#ifdef DEBUG -#define DEBUG_CONFIGURED	1 +#ifdef CONFIG_DYNAMIC_DEBUG +  static int debug = 1;  module_param(debug, int, S_IRUGO | S_IWUSR);  MODULE_PARM_DESC(debug, "Debug level"); +static char *errbuf;  #else -#define DEBUG_CONFIGURED	0 -#define debug			0 + +#define debug 0 +#define errbuf NULL +  #endif -static char *errbuf; +  #define ERRBUF_LEN    (32 * 1024)  static struct kmem_cache *uhci_up_cachep;	/* urb_priv */ @@ -516,13 +519,12 @@ static void release_uhci(struct uhci_hcd *uhci)  {  	int i; -	if (DEBUG_CONFIGURED) { -		spin_lock_irq(&uhci->lock); -		uhci->is_initialized = 0; -		spin_unlock_irq(&uhci->lock); -		debugfs_remove(uhci->dentry); -	} +	spin_lock_irq(&uhci->lock); +	uhci->is_initialized = 0; +	spin_unlock_irq(&uhci->lock); + +	debugfs_remove(uhci->dentry);  	for (i = 0; i < UHCI_NUM_SKELQH; i++)  		uhci_free_qh(uhci, uhci->skelqh[i]); @@ -868,14 +870,14 @@ static int __init uhci_hcd_init(void)  			ignore_oc ? ", overcurrent ignored" : "");  	set_bit(USB_UHCI_LOADED, &usb_hcds_loaded); -	if (DEBUG_CONFIGURED) { -		errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL); -		if (!errbuf) -			goto errbuf_failed; -		uhci_debugfs_root = debugfs_create_dir("uhci", usb_debug_root); -		if (!uhci_debugfs_root) -			goto debug_failed; -	} +#ifdef CONFIG_DYNAMIC_DEBUG +	errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL); +	if (!errbuf) +		goto errbuf_failed; +	uhci_debugfs_root = debugfs_create_dir("uhci", usb_debug_root); +	if (!uhci_debugfs_root) +		goto debug_failed; +#endif  	uhci_up_cachep = kmem_cache_create("uhci_urb_priv",  		sizeof(struct urb_priv), 0, 0, NULL); @@ -906,12 +908,14 @@ clean0:  	kmem_cache_destroy(uhci_up_cachep);  up_failed: +#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)  	debugfs_remove(uhci_debugfs_root);  debug_failed:  	kfree(errbuf);  errbuf_failed: +#endif  	clear_bit(USB_UHCI_LOADED, &usb_hcds_loaded);  	return retval; @@ -927,7 +931,9 @@ static void __exit uhci_hcd_cleanup(void)  #endif  	kmem_cache_destroy(uhci_up_cachep);  	debugfs_remove(uhci_debugfs_root); +#ifdef CONFIG_DYNAMIC_DEBUG  	kfree(errbuf); +#endif  	clear_bit(USB_UHCI_LOADED, &usb_hcds_loaded);  } diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c index 9189bc984c9..93e17b12fb3 100644 --- a/drivers/usb/host/uhci-hub.c +++ b/drivers/usb/host/uhci-hub.c @@ -75,8 +75,6 @@ static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)  	return !!*buf;  } -#define OK(x)			len = (x); break -  #define CLR_RH_PORTSTAT(x) \  	status = uhci_readw(uhci, port_addr);	\  	status &= ~(RWC_BITS|WZ_BITS); \ @@ -244,7 +242,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			u16 wIndex, char *buf, u16 wLength)  {  	struct uhci_hcd *uhci = hcd_to_uhci(hcd); -	int status, lstatus, retval = 0, len = 0; +	int status, lstatus, retval = 0;  	unsigned int port = wIndex - 1;  	unsigned long port_addr = USBPORTSC1 + 2 * port;  	u16 wPortChange, wPortStatus; @@ -258,7 +256,8 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  	case GetHubStatus:  		*(__le32 *)buf = cpu_to_le32(0); -		OK(4);		/* hub power */ +		retval = 4; /* hub power */ +		break;  	case GetPortStatus:  		if (port >= uhci->rh_numports)  			goto err; @@ -311,13 +310,14 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  		*(__le16 *)buf = cpu_to_le16(wPortStatus);  		*(__le16 *)(buf + 2) = cpu_to_le16(wPortChange); -		OK(4); +		retval = 4; +		break;  	case SetHubFeature:		/* We don't implement these */  	case ClearHubFeature:  		switch (wValue) {  		case C_HUB_OVER_CURRENT:  		case C_HUB_LOCAL_POWER: -			OK(0); +			break;  		default:  			goto err;  		} @@ -329,7 +329,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  		switch (wValue) {  		case USB_PORT_FEAT_SUSPEND:  			SET_RH_PORTSTAT(USBPORTSC_SUSP); -			OK(0); +			break;  		case USB_PORT_FEAT_RESET:  			SET_RH_PORTSTAT(USBPORTSC_PR); @@ -338,10 +338,10 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			/* USB v2.0 7.1.7.5 */  			uhci->ports_timeout = jiffies + msecs_to_jiffies(50); -			OK(0); +			break;  		case USB_PORT_FEAT_POWER:  			/* UHCI has no power switching */ -			OK(0); +			break;  		default:  			goto err;  		} @@ -356,10 +356,10 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			/* Disable terminates Resume signalling */  			uhci_finish_suspend(uhci, port, port_addr); -			OK(0); +			break;  		case USB_PORT_FEAT_C_ENABLE:  			CLR_RH_PORTSTAT(USBPORTSC_PEC); -			OK(0); +			break;  		case USB_PORT_FEAT_SUSPEND:  			if (!(uhci_readw(uhci, port_addr) & USBPORTSC_SUSP)) { @@ -382,32 +382,32 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  					uhci->ports_timeout = jiffies +  						msecs_to_jiffies(20);  			} -			OK(0); +			break;  		case USB_PORT_FEAT_C_SUSPEND:  			clear_bit(port, &uhci->port_c_suspend); -			OK(0); +			break;  		case USB_PORT_FEAT_POWER:  			/* UHCI has no power switching */  			goto err;  		case USB_PORT_FEAT_C_CONNECTION:  			CLR_RH_PORTSTAT(USBPORTSC_CSC); -			OK(0); +			break;  		case USB_PORT_FEAT_C_OVER_CURRENT:  			CLR_RH_PORTSTAT(USBPORTSC_OCC); -			OK(0); +			break;  		case USB_PORT_FEAT_C_RESET:  			/* this driver won't report these */ -			OK(0); +			break;  		default:  			goto err;  		}  		break;  	case GetHubDescriptor: -		len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength); -		memcpy(buf, root_hub_hub_des, len); -		if (len > 2) +		retval = min_t(unsigned int, sizeof(root_hub_hub_des), wLength); +		memcpy(buf, root_hub_hub_des, retval); +		if (retval > 2)  			buf[2] = uhci->rh_numports; -		OK(len); +		break;  	default:  err:  		retval = -EPIPE; diff --git a/drivers/usb/host/uhci-pci.c b/drivers/usb/host/uhci-pci.c index c300bd2f7d1..940304c3322 100644 --- a/drivers/usb/host/uhci-pci.c +++ b/drivers/usb/host/uhci-pci.c @@ -162,6 +162,8 @@ static void uhci_shutdown(struct pci_dev *pdev)  #ifdef CONFIG_PM +static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated); +  static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)  {  	struct uhci_hcd *uhci = hcd_to_uhci(hcd); @@ -174,12 +176,6 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)  	if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead)  		goto done_okay;		/* Already suspended or dead */ -	if (uhci->rh_state > UHCI_RH_SUSPENDED) { -		dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); -		rc = -EBUSY; -		goto done; -	}; -  	/* All PCI host controllers are required to disable IRQ generation  	 * at the source, so we must turn off PIRQ.  	 */ @@ -195,8 +191,15 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)  done_okay:  	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); -done:  	spin_unlock_irq(&uhci->lock); + +	synchronize_irq(hcd->irq); + +	/* Check for race with a wakeup request */ +	if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) { +		uhci_pci_resume(hcd, false); +		rc = -EBUSY; +	}  	return rc;  } @@ -276,7 +279,7 @@ static const struct hc_driver uhci_driver = {  	.hub_control =		uhci_hub_control,  }; -static DEFINE_PCI_DEVICE_TABLE(uhci_pci_ids) = { { +static const struct pci_device_id uhci_pci_ids[] = { {  	/* handle any USB UHCI controller */  	PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_UHCI, ~0),  	.driver_data =	(unsigned long) &uhci_driver, @@ -293,9 +296,11 @@ static struct pci_driver uhci_pci_driver = {  	.remove =	usb_hcd_pci_remove,  	.shutdown =	uhci_shutdown, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM  	.driver =	{  		.pm =	&usb_hcd_pci_pm_ops  	},  #endif  }; + +MODULE_SOFTDEP("pre: ehci_pci"); diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c index d033a0ec7f0..01833ab2b5c 100644 --- a/drivers/usb/host/uhci-platform.c +++ b/drivers/usb/host/uhci-platform.c @@ -75,10 +75,9 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev)  	 * 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 = &pdev->dev.coherent_dma_mask; -	if (!pdev->dev.coherent_dma_mask) -		pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +	if (ret) +		return ret;  	hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev,  			pdev->name); @@ -105,11 +104,11 @@ static int uhci_hcd_platform_probe(struct platform_device *pdev)  	uhci->regs = hcd->regs; -	ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED | -								IRQF_SHARED); +	ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED);  	if (ret)  		goto err_uhci; +	device_wakeup_enable(hcd->self.controller);  	return 0;  err_uhci: @@ -149,6 +148,7 @@ static void uhci_hcd_platform_shutdown(struct platform_device *op)  }  static const struct of_device_id platform_uhci_ids[] = { +	{ .compatible = "generic-uhci", },  	{ .compatible = "platform-uhci", },  	{}  }; diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 041c6ddb695..da6f56d996c 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -1303,7 +1303,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,  		}  		/* Fell behind? */ -		if (uhci_frame_before_eq(frame, next)) { +		if (!uhci_frame_before_eq(next, frame)) {  			/* USB_ISO_ASAP: Round up to the first available slot */  			if (urb->transfer_flags & URB_ISO_ASAP) @@ -1311,13 +1311,17 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,  						-qh->period;  			/* -			 * Not ASAP: Use the next slot in the stream.  If -			 * the entire URB falls before the threshold, fail. +			 * Not ASAP: Use the next slot in the stream, +			 * no matter what.  			 */  			else if (!uhci_frame_before_eq(next,  					frame + (urb->number_of_packets - 1) *  						qh->period)) -				return -EXDEV; +				dev_dbg(uhci_dev(uhci), "iso underrun %p (%u+%u < %u)\n", +						urb, frame, +						(urb->number_of_packets - 1) * +							qh->period, +						next);  		}  	} diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c index ecc88db804e..d7b363a418d 100644 --- a/drivers/usb/host/whci/hcd.c +++ b/drivers/usb/host/whci/hcd.c @@ -134,7 +134,7 @@ static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,  	default:  		ret = asl_urb_enqueue(whc, urb, mem_flags);  		break; -	}; +	}  	return ret;  } @@ -160,7 +160,7 @@ static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status)  	default:  		ret = asl_urb_dequeue(whc, urb, status);  		break; -	}; +	}  	return ret;  } @@ -293,6 +293,7 @@ static int whc_probe(struct umc_dev *umc)  		dev_err(dev, "cannot add HCD: %d\n", ret);  		goto error_usb_add_hcd;  	} +	device_wakeup_enable(usb_hcd->self.controller);  	ret = wusbhc_b_create(wusbhc);  	if (ret) { diff --git a/drivers/usb/host/whci/int.c b/drivers/usb/host/whci/int.c index 6aae7002810..0c086b2790d 100644 --- a/drivers/usb/host/whci/int.c +++ b/drivers/usb/host/whci/int.c @@ -16,7 +16,6 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/uwb/umc.h>  #include "../../wusbcore/wusbhc.h" diff --git a/drivers/usb/host/whci/wusb.c b/drivers/usb/host/whci/wusb.c index f24efdebad1..8d276268286 100644 --- a/drivers/usb/host/whci/wusb.c +++ b/drivers/usb/host/whci/wusb.c @@ -16,7 +16,6 @@   * along with this program.  If not, see <http://www.gnu.org/licenses/>.   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/uwb/umc.h>  #include "../../wusbcore/wusbhc.h" diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 73503a81ee8..eb009a457fb 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -32,7 +32,7 @@ void xhci_dbg_regs(struct xhci_hcd *xhci)  	xhci_dbg(xhci, "// xHCI capability registers at %p:\n",  			xhci->cap_regs); -	temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); +	temp = readl(&xhci->cap_regs->hc_capbase);  	xhci_dbg(xhci, "// @%p = 0x%x (CAPLENGTH AND HCIVERSION)\n",  			&xhci->cap_regs->hc_capbase, temp);  	xhci_dbg(xhci, "//   CAPLENGTH: 0x%x\n", @@ -44,13 +44,13 @@ void xhci_dbg_regs(struct xhci_hcd *xhci)  	xhci_dbg(xhci, "// xHCI operational registers at %p:\n", xhci->op_regs); -	temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off); +	temp = readl(&xhci->cap_regs->run_regs_off);  	xhci_dbg(xhci, "// @%p = 0x%x RTSOFF\n",  			&xhci->cap_regs->run_regs_off,  			(unsigned int) temp & RTSOFF_MASK);  	xhci_dbg(xhci, "// xHCI runtime registers at %p:\n", xhci->run_regs); -	temp = xhci_readl(xhci, &xhci->cap_regs->db_off); +	temp = readl(&xhci->cap_regs->db_off);  	xhci_dbg(xhci, "// @%p = 0x%x DBOFF\n", &xhci->cap_regs->db_off, temp);  	xhci_dbg(xhci, "// Doorbell array at %p:\n", xhci->dba);  } @@ -61,7 +61,7 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci)  	xhci_dbg(xhci, "xHCI capability registers at %p:\n", xhci->cap_regs); -	temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); +	temp = readl(&xhci->cap_regs->hc_capbase);  	xhci_dbg(xhci, "CAPLENGTH AND HCIVERSION 0x%x:\n",  			(unsigned int) temp);  	xhci_dbg(xhci, "CAPLENGTH: 0x%x\n", @@ -69,7 +69,7 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci)  	xhci_dbg(xhci, "HCIVERSION: 0x%x\n",  			(unsigned int) HC_VERSION(temp)); -	temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); +	temp = readl(&xhci->cap_regs->hcs_params1);  	xhci_dbg(xhci, "HCSPARAMS 1: 0x%x\n",  			(unsigned int) temp);  	xhci_dbg(xhci, "  Max device slots: %u\n", @@ -79,7 +79,7 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci)  	xhci_dbg(xhci, "  Max ports: %u\n",  			(unsigned int) HCS_MAX_PORTS(temp)); -	temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); +	temp = readl(&xhci->cap_regs->hcs_params2);  	xhci_dbg(xhci, "HCSPARAMS 2: 0x%x\n",  			(unsigned int) temp);  	xhci_dbg(xhci, "  Isoc scheduling threshold: %u\n", @@ -87,7 +87,7 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci)  	xhci_dbg(xhci, "  Maximum allowed segments in event ring: %u\n",  			(unsigned int) HCS_ERST_MAX(temp)); -	temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); +	temp = readl(&xhci->cap_regs->hcs_params3);  	xhci_dbg(xhci, "HCSPARAMS 3 0x%x:\n",  			(unsigned int) temp);  	xhci_dbg(xhci, "  Worst case U1 device exit latency: %u\n", @@ -95,14 +95,14 @@ static void xhci_print_cap_regs(struct xhci_hcd *xhci)  	xhci_dbg(xhci, "  Worst case U2 device exit latency: %u\n",  			(unsigned int) HCS_U2_LATENCY(temp)); -	temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); +	temp = readl(&xhci->cap_regs->hcc_params);  	xhci_dbg(xhci, "HCC PARAMS 0x%x:\n", (unsigned int) temp);  	xhci_dbg(xhci, "  HC generates %s bit addresses\n",  			HCC_64BIT_ADDR(temp) ? "64" : "32");  	/* FIXME */  	xhci_dbg(xhci, "  FIXME: more HCCPARAMS debugging\n"); -	temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off); +	temp = readl(&xhci->cap_regs->run_regs_off);  	xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK);  } @@ -110,7 +110,7 @@ static void xhci_print_command_reg(struct xhci_hcd *xhci)  {  	u32 temp; -	temp = xhci_readl(xhci, &xhci->op_regs->command); +	temp = readl(&xhci->op_regs->command);  	xhci_dbg(xhci, "USBCMD 0x%x:\n", temp);  	xhci_dbg(xhci, "  HC is %s\n",  			(temp & CMD_RUN) ? "running" : "being stopped"); @@ -128,7 +128,7 @@ static void xhci_print_status(struct xhci_hcd *xhci)  {  	u32 temp; -	temp = xhci_readl(xhci, &xhci->op_regs->status); +	temp = readl(&xhci->op_regs->status);  	xhci_dbg(xhci, "USBSTS 0x%x:\n", temp);  	xhci_dbg(xhci, "  Event ring is %sempty\n",  			(temp & STS_EINT) ? "not " : ""); @@ -163,7 +163,7 @@ static void xhci_print_ports(struct xhci_hcd *xhci)  		for (j = 0; j < NUM_PORT_REGS; ++j) {  			xhci_dbg(xhci, "%p port %s reg = 0x%x\n",  					addr, names[j], -					(unsigned int) xhci_readl(xhci, addr)); +					(unsigned int) readl(addr));  			addr++;  		}  	} @@ -177,7 +177,7 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num)  	u64 temp_64;  	addr = &ir_set->irq_pending; -	temp = xhci_readl(xhci, addr); +	temp = readl(addr);  	if (temp == XHCI_INIT_VALUE)  		return; @@ -187,17 +187,17 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num)  			(unsigned int)temp);  	addr = &ir_set->irq_control; -	temp = xhci_readl(xhci, addr); +	temp = readl(addr);  	xhci_dbg(xhci, "  %p: ir_set.control = 0x%x\n", addr,  			(unsigned int)temp);  	addr = &ir_set->erst_size; -	temp = xhci_readl(xhci, addr); +	temp = readl(addr);  	xhci_dbg(xhci, "  %p: ir_set.erst_size = 0x%x\n", addr,  			(unsigned int)temp);  	addr = &ir_set->rsvd; -	temp = xhci_readl(xhci, addr); +	temp = readl(addr);  	if (temp != XHCI_INIT_VALUE)  		xhci_dbg(xhci, "  WARN: %p: ir_set.rsvd = 0x%x\n",  				addr, (unsigned int)temp); @@ -219,12 +219,12 @@ void xhci_print_run_regs(struct xhci_hcd *xhci)  	int i;  	xhci_dbg(xhci, "xHCI runtime registers at %p:\n", xhci->run_regs); -	temp = xhci_readl(xhci, &xhci->run_regs->microframe_index); +	temp = readl(&xhci->run_regs->microframe_index);  	xhci_dbg(xhci, "  %p: Microframe index = 0x%x\n",  			&xhci->run_regs->microframe_index,  			(unsigned int) temp);  	for (i = 0; i < 7; ++i) { -		temp = xhci_readl(xhci, &xhci->run_regs->rsvd[i]); +		temp = readl(&xhci->run_regs->rsvd[i]);  		if (temp != XHCI_INIT_VALUE)  			xhci_dbg(xhci, "  WARN: %p: Rsvd[%i] = 0x%x\n",  					&xhci->run_regs->rsvd[i], diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index fae697ed0b7..aa79e874904 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -20,7 +20,9 @@   * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   */ -#include <linux/gfp.h> + +#include <linux/slab.h> +#include <linux/device.h>  #include <asm/unaligned.h>  #include "xhci.h" @@ -94,7 +96,7 @@ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,  	 */  	memset(port_removable, 0, sizeof(port_removable));  	for (i = 0; i < ports; i++) { -		portsc = xhci_readl(xhci, xhci->usb2_ports[i]); +		portsc = readl(xhci->usb2_ports[i]);  		/* If a device is removable, PORTSC reports a 0, same as in the  		 * hub descriptor DeviceRemovable bits.  		 */ @@ -148,7 +150,7 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,  	port_removable = 0;  	/* bit 0 is reserved, bit 1 is for port 1, etc. */  	for (i = 0; i < ports; i++) { -		portsc = xhci_readl(xhci, xhci->usb3_ports[i]); +		portsc = readl(xhci->usb3_ports[i]);  		if (portsc & PORT_DEV_REMOVE)  			port_removable |= 1 << (i + 1);  	} @@ -270,7 +272,6 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)  	struct xhci_virt_device *virt_dev;  	struct xhci_command *cmd;  	unsigned long flags; -	int timeleft;  	int ret;  	int i; @@ -284,34 +285,31 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)  	spin_lock_irqsave(&xhci->lock, flags);  	for (i = LAST_EP_INDEX; i > 0; i--) { -		if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) -			xhci_queue_stop_endpoint(xhci, slot_id, i, suspend); +		if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) { +			struct xhci_command *command; +			command = xhci_alloc_command(xhci, false, false, +						     GFP_NOWAIT); +			if (!command) { +				spin_unlock_irqrestore(&xhci->lock, flags); +				xhci_free_command(xhci, cmd); +				return -ENOMEM; + +			} +			xhci_queue_stop_endpoint(xhci, command, slot_id, i, +						 suspend); +		}  	} -	cmd->command_trb = xhci->cmd_ring->enqueue; -	list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list); -	xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend); +	xhci_queue_stop_endpoint(xhci, cmd, slot_id, 0, suspend);  	xhci_ring_cmd_db(xhci);  	spin_unlock_irqrestore(&xhci->lock, flags);  	/* Wait for last stop endpoint command to finish */ -	timeleft = wait_for_completion_interruptible_timeout( -			cmd->completion, -			USB_CTRL_SET_TIMEOUT); -	if (timeleft <= 0) { -		xhci_warn(xhci, "%s while waiting for stop endpoint command\n", -				timeleft == 0 ? "Timeout" : "Signal"); -		spin_lock_irqsave(&xhci->lock, flags); -		/* The timeout might have raced with the event ring handler, so -		 * only delete from the list if the item isn't poisoned. -		 */ -		if (cmd->cmd_list.next != LIST_POISON1) -			list_del(&cmd->cmd_list); -		spin_unlock_irqrestore(&xhci->lock, flags); +	wait_for_completion(cmd->completion); + +	if (cmd->status == COMP_CMD_ABORT || cmd->status == COMP_CMD_STOP) { +		xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n");  		ret = -ETIME; -		goto command_cleanup;  	} - -command_cleanup:  	xhci_free_command(xhci, cmd);  	return ret;  } @@ -342,8 +340,8 @@ static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,  	}  	/* Write 1 to disable the port */ -	xhci_writel(xhci, port_status | PORT_PE, addr); -	port_status = xhci_readl(xhci, addr); +	writel(port_status | PORT_PE, addr); +	port_status = readl(addr);  	xhci_dbg(xhci, "disable port, actual port %d status  = 0x%x\n",  			wIndex, port_status);  } @@ -388,8 +386,8 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,  		return;  	}  	/* Change bits are all write 1 to clear */ -	xhci_writel(xhci, port_status | status, addr); -	port_status = xhci_readl(xhci, addr); +	writel(port_status | status, addr); +	port_status = readl(addr);  	xhci_dbg(xhci, "clear port %s change, actual port %d status  = 0x%x\n",  			port_change_bit, wIndex, port_status);  } @@ -415,11 +413,11 @@ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,  {  	u32 temp; -	temp = xhci_readl(xhci, port_array[port_id]); +	temp = readl(port_array[port_id]);  	temp = xhci_port_state_to_neutral(temp);  	temp &= ~PORT_PLS_MASK;  	temp |= PORT_LINK_STROBE | link_state; -	xhci_writel(xhci, temp, port_array[port_id]); +	writel(temp, port_array[port_id]);  }  static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, @@ -427,7 +425,7 @@ static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,  {  	u32 temp; -	temp = xhci_readl(xhci, port_array[port_id]); +	temp = readl(port_array[port_id]);  	temp = xhci_port_state_to_neutral(temp);  	if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT) @@ -445,7 +443,7 @@ static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,  	else  		temp &= ~PORT_WKOC_E; -	xhci_writel(xhci, temp, port_array[port_id]); +	writel(temp, port_array[port_id]);  }  /* Test and clear port RWC bit */ @@ -454,11 +452,11 @@ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,  {  	u32 temp; -	temp = xhci_readl(xhci, port_array[port_id]); +	temp = readl(port_array[port_id]);  	if (temp & port_bit) {  		temp = xhci_port_state_to_neutral(temp);  		temp |= port_bit; -		xhci_writel(xhci, temp, port_array[port_id]); +		writel(temp, port_array[port_id]);  	}  } @@ -524,7 +522,8 @@ static void xhci_hub_report_usb3_link_state(u32 *status, u32 status_reg)   * the compliance mode timer is deleted. A port won't enter   * compliance mode if it has previously entered U0.   */ -void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex) +static void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, +				    u16 wIndex)  {  	u32 all_ports_seen_u0 = ((1 << xhci->num_usb3_ports)-1);  	bool port_in_u0 = ((status & PORT_PLS_MASK) == XDEV_U0); @@ -552,11 +551,15 @@ void xhci_del_comp_mod_timer(struct xhci_hcd *xhci, u32 status, u16 wIndex)   *  - Mark a port as being done with device resume,   *    and ring the endpoint doorbells.   *  - Stop the Synopsys redriver Compliance Mode polling. + *  - Drop and reacquire the xHCI lock, in order to wait for port resume.   */  static u32 xhci_get_port_status(struct usb_hcd *hcd,  		struct xhci_bus_state *bus_state,  		__le32 __iomem **port_array, -		u16 wIndex, u32 raw_port_status) +		u16 wIndex, u32 raw_port_status, +		unsigned long flags) +	__releases(&xhci->lock) +	__acquires(&xhci->lock)  {  	struct xhci_hcd *xhci = hcd_to_xhci(hcd);  	u32 status = 0; @@ -591,21 +594,41 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,  			return 0xffffffff;  		if (time_after_eq(jiffies,  					bus_state->resume_done[wIndex])) { +			int time_left; +  			xhci_dbg(xhci, "Resume USB2 port %d\n",  					wIndex + 1);  			bus_state->resume_done[wIndex] = 0;  			clear_bit(wIndex, &bus_state->resuming_ports); + +			set_bit(wIndex, &bus_state->rexit_ports);  			xhci_set_link_state(xhci, port_array, wIndex,  					XDEV_U0); -			xhci_dbg(xhci, "set port %d resume\n", -					wIndex + 1); -			slot_id = xhci_find_slot_id_by_port(hcd, xhci, -					wIndex + 1); -			if (!slot_id) { -				xhci_dbg(xhci, "slot_id is zero\n"); -				return 0xffffffff; + +			spin_unlock_irqrestore(&xhci->lock, flags); +			time_left = wait_for_completion_timeout( +					&bus_state->rexit_done[wIndex], +					msecs_to_jiffies( +						XHCI_MAX_REXIT_TIMEOUT)); +			spin_lock_irqsave(&xhci->lock, flags); + +			if (time_left) { +				slot_id = xhci_find_slot_id_by_port(hcd, +						xhci, wIndex + 1); +				if (!slot_id) { +					xhci_dbg(xhci, "slot_id is zero\n"); +					return 0xffffffff; +				} +				xhci_ring_device(xhci, slot_id); +			} else { +				int port_status = readl(port_array[wIndex]); +				xhci_warn(xhci, "Port resume took longer than %i msec, port status = 0x%x\n", +						XHCI_MAX_REXIT_TIMEOUT, +						port_status); +				status |= USB_PORT_STAT_SUSPEND; +				clear_bit(wIndex, &bus_state->rexit_ports);  			} -			xhci_ring_device(xhci, slot_id); +  			bus_state->port_c_suspend |= 1 << wIndex;  			bus_state->suspended_ports &= ~(1 << wIndex);  		} else { @@ -707,12 +730,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  		/* Set the U1 and U2 exit latencies. */  		memcpy(buf, &usb_bos_descriptor,  				USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE); -		temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); -		buf[12] = HCS_U1_LATENCY(temp); -		put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]); +		if ((xhci->quirks & XHCI_LPM_SUPPORT)) { +			temp = readl(&xhci->cap_regs->hcs_params3); +			buf[12] = HCS_U1_LATENCY(temp); +			put_unaligned_le16(HCS_U2_LATENCY(temp), &buf[13]); +		}  		/* Indicate whether the host has LTM support. */ -		temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); +		temp = readl(&xhci->cap_regs->hcc_params);  		if (HCC_LTC(temp))  			buf[8] |= USB_LTM_SUPPORT; @@ -722,13 +747,13 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  		if (!wIndex || wIndex > max_ports)  			goto error;  		wIndex--; -		temp = xhci_readl(xhci, port_array[wIndex]); +		temp = readl(port_array[wIndex]);  		if (temp == 0xffffffff) {  			retval = -ENODEV;  			break;  		}  		status = xhci_get_port_status(hcd, bus_state, port_array, -				wIndex, temp); +				wIndex, temp, flags);  		if (status == 0xffffffff)  			goto error; @@ -749,7 +774,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  		if (!wIndex || wIndex > max_ports)  			goto error;  		wIndex--; -		temp = xhci_readl(xhci, port_array[wIndex]); +		temp = readl(port_array[wIndex]);  		if (temp == 0xffffffff) {  			retval = -ENODEV;  			break; @@ -758,7 +783,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  		/* FIXME: What new port features do we need to support? */  		switch (wValue) {  		case USB_PORT_FEAT_SUSPEND: -			temp = xhci_readl(xhci, port_array[wIndex]); +			temp = readl(port_array[wIndex]);  			if ((temp & PORT_PLS_MASK) != XDEV_U0) {  				/* Resume the port to U0 first */  				xhci_set_link_state(xhci, port_array, wIndex, @@ -771,7 +796,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			 * a port unless the port reports that it is in the  			 * enabled (PED = ‘1’,PLS < ‘3’) state.  			 */ -			temp = xhci_readl(xhci, port_array[wIndex]); +			temp = readl(port_array[wIndex]);  			if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)  				|| (temp & PORT_PLS_MASK) >= XDEV_U3) {  				xhci_warn(xhci, "USB core suspending device " @@ -796,11 +821,11 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			msleep(10); /* wait device to enter */  			spin_lock_irqsave(&xhci->lock, flags); -			temp = xhci_readl(xhci, port_array[wIndex]); +			temp = readl(port_array[wIndex]);  			bus_state->suspended_ports |= 1 << wIndex;  			break;  		case USB_PORT_FEAT_LINK_STATE: -			temp = xhci_readl(xhci, port_array[wIndex]); +			temp = readl(port_array[wIndex]);  			/* Disable port */  			if (link_state == USB_SS_PORT_LS_SS_DISABLED) { @@ -813,9 +838,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  				temp |= PORT_CSC | PORT_PEC | PORT_WRC |  					PORT_OCC | PORT_RC | PORT_PLC |  					PORT_CEC; -				xhci_writel(xhci, temp | PORT_PE, -					port_array[wIndex]); -				temp = xhci_readl(xhci, port_array[wIndex]); +				writel(temp | PORT_PE, port_array[wIndex]); +				temp = readl(port_array[wIndex]);  				break;  			} @@ -824,7 +848,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  				xhci_dbg(xhci, "Enable port %d\n", wIndex);  				xhci_set_link_state(xhci, port_array, wIndex,  						link_state); -				temp = xhci_readl(xhci, port_array[wIndex]); +				temp = readl(port_array[wIndex]);  				break;  			} @@ -858,7 +882,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			msleep(20); /* wait device to enter */  			spin_lock_irqsave(&xhci->lock, flags); -			temp = xhci_readl(xhci, port_array[wIndex]); +			temp = readl(port_array[wIndex]);  			if (link_state == USB_SS_PORT_LS_U3)  				bus_state->suspended_ports |= 1 << wIndex;  			break; @@ -869,10 +893,9 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			 * However, khubd will ignore the roothub events until  			 * the roothub is registered.  			 */ -			xhci_writel(xhci, temp | PORT_POWER, -					port_array[wIndex]); +			writel(temp | PORT_POWER, port_array[wIndex]); -			temp = xhci_readl(xhci, port_array[wIndex]); +			temp = readl(port_array[wIndex]);  			xhci_dbg(xhci, "set port power, actual port %d status  = 0x%x\n", wIndex, temp);  			spin_unlock_irqrestore(&xhci->lock, flags); @@ -885,52 +908,52 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  			break;  		case USB_PORT_FEAT_RESET:  			temp = (temp | PORT_RESET); -			xhci_writel(xhci, temp, port_array[wIndex]); +			writel(temp, port_array[wIndex]); -			temp = xhci_readl(xhci, port_array[wIndex]); +			temp = readl(port_array[wIndex]);  			xhci_dbg(xhci, "set port reset, actual port %d status  = 0x%x\n", wIndex, temp);  			break;  		case USB_PORT_FEAT_REMOTE_WAKE_MASK:  			xhci_set_remote_wake_mask(xhci, port_array,  					wIndex, wake_mask); -			temp = xhci_readl(xhci, port_array[wIndex]); +			temp = readl(port_array[wIndex]);  			xhci_dbg(xhci, "set port remote wake mask, "  					"actual port %d status  = 0x%x\n",  					wIndex, temp);  			break;  		case USB_PORT_FEAT_BH_PORT_RESET:  			temp |= PORT_WR; -			xhci_writel(xhci, temp, port_array[wIndex]); +			writel(temp, port_array[wIndex]); -			temp = xhci_readl(xhci, port_array[wIndex]); +			temp = readl(port_array[wIndex]);  			break;  		case USB_PORT_FEAT_U1_TIMEOUT:  			if (hcd->speed != HCD_USB3)  				goto error; -			temp = xhci_readl(xhci, port_array[wIndex] + PORTPMSC); +			temp = readl(port_array[wIndex] + PORTPMSC);  			temp &= ~PORT_U1_TIMEOUT_MASK;  			temp |= PORT_U1_TIMEOUT(timeout); -			xhci_writel(xhci, temp, port_array[wIndex] + PORTPMSC); +			writel(temp, port_array[wIndex] + PORTPMSC);  			break;  		case USB_PORT_FEAT_U2_TIMEOUT:  			if (hcd->speed != HCD_USB3)  				goto error; -			temp = xhci_readl(xhci, port_array[wIndex] + PORTPMSC); +			temp = readl(port_array[wIndex] + PORTPMSC);  			temp &= ~PORT_U2_TIMEOUT_MASK;  			temp |= PORT_U2_TIMEOUT(timeout); -			xhci_writel(xhci, temp, port_array[wIndex] + PORTPMSC); +			writel(temp, port_array[wIndex] + PORTPMSC);  			break;  		default:  			goto error;  		}  		/* unblock any posted writes */ -		temp = xhci_readl(xhci, port_array[wIndex]); +		temp = readl(port_array[wIndex]);  		break;  	case ClearPortFeature:  		if (!wIndex || wIndex > max_ports)  			goto error;  		wIndex--; -		temp = xhci_readl(xhci, port_array[wIndex]); +		temp = readl(port_array[wIndex]);  		if (temp == 0xffffffff) {  			retval = -ENODEV;  			break; @@ -939,7 +962,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  		temp = xhci_port_state_to_neutral(temp);  		switch (wValue) {  		case USB_PORT_FEAT_SUSPEND: -			temp = xhci_readl(xhci, port_array[wIndex]); +			temp = readl(port_array[wIndex]);  			xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");  			xhci_dbg(xhci, "PORTSC %04x\n", temp);  			if (temp & PORT_RESET) @@ -982,8 +1005,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  					port_array[wIndex], temp);  			break;  		case USB_PORT_FEAT_POWER: -			xhci_writel(xhci, temp & ~PORT_POWER, -				port_array[wIndex]); +			writel(temp & ~PORT_POWER, port_array[wIndex]);  			spin_unlock_irqrestore(&xhci->lock, flags);  			temp = usb_acpi_power_manageable(hcd->self.root_hub, @@ -1044,7 +1066,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)  	spin_lock_irqsave(&xhci->lock, flags);  	/* For each port, did anything change?  If so, set that bit in buf. */  	for (i = 0; i < max_ports; i++) { -		temp = xhci_readl(xhci, port_array[i]); +		temp = readl(port_array[i]);  		if (temp == 0xffffffff) {  			retval = -ENODEV;  			break; @@ -1098,7 +1120,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)  		u32 t1, t2;  		int slot_id; -		t1 = xhci_readl(xhci, port_array[port_index]); +		t1 = readl(port_array[port_index]);  		t2 = xhci_port_state_to_neutral(t1);  		if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) { @@ -1118,7 +1140,9 @@ int xhci_bus_suspend(struct usb_hcd *hcd)  		 * 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) { +		if (hcd->self.root_hub->do_remote_wakeup +				&& device_may_wakeup(hcd->self.controller)) { +  			if (t1 & PORT_CONNECT) {  				t2 |= PORT_WKOC_E | PORT_WKDISC_E;  				t2 &= ~PORT_WKCONN_E; @@ -1131,19 +1155,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)  		t1 = xhci_port_state_to_neutral(t1);  		if (t1 != t2) -			xhci_writel(xhci, t2, port_array[port_index]); - -		if (hcd->speed != HCD_USB3) { -			/* enable remote wake up for USB 2.0 */ -			__le32 __iomem *addr; -			u32 tmp; - -			/* Get the port power control register address. */ -			addr = port_array[port_index] + PORTPMSC; -			tmp = xhci_readl(xhci, addr); -			tmp |= PORT_RWE; -			xhci_writel(xhci, tmp, addr); -		} +			writel(t2, port_array[port_index]);  	}  	hcd->state = HC_STATE_SUSPENDED;  	bus_state->next_statechange = jiffies + msecs_to_jiffies(10); @@ -1173,9 +1185,9 @@ int xhci_bus_resume(struct usb_hcd *hcd)  	}  	/* delay the irqs */ -	temp = xhci_readl(xhci, &xhci->op_regs->command); +	temp = readl(&xhci->op_regs->command);  	temp &= ~CMD_EIE; -	xhci_writel(xhci, temp, &xhci->op_regs->command); +	writel(temp, &xhci->op_regs->command);  	port_index = max_ports;  	while (port_index--) { @@ -1184,7 +1196,7 @@ int xhci_bus_resume(struct usb_hcd *hcd)  		u32 temp;  		int slot_id; -		temp = xhci_readl(xhci, port_array[port_index]); +		temp = readl(port_array[port_index]);  		if (DEV_SUPERSPEED(temp))  			temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);  		else @@ -1221,31 +1233,17 @@ int xhci_bus_resume(struct usb_hcd *hcd)  			if (slot_id)  				xhci_ring_device(xhci, slot_id);  		} else -			xhci_writel(xhci, temp, port_array[port_index]); - -		if (hcd->speed != HCD_USB3) { -			/* disable remote wake up for USB 2.0 */ -			__le32 __iomem *addr; -			u32 tmp; - -			/* Add one to the port status register address to get -			 * the port power control register address. -			 */ -			addr = port_array[port_index] + PORTPMSC; -			tmp = xhci_readl(xhci, addr); -			tmp &= ~PORT_RWE; -			xhci_writel(xhci, tmp, addr); -		} +			writel(temp, port_array[port_index]);  	} -	(void) xhci_readl(xhci, &xhci->op_regs->command); +	(void) readl(&xhci->op_regs->command);  	bus_state->next_statechange = jiffies + msecs_to_jiffies(5);  	/* re-enable irqs */ -	temp = xhci_readl(xhci, &xhci->op_regs->command); +	temp = readl(&xhci->op_regs->command);  	temp |= CMD_EIE; -	xhci_writel(xhci, temp, &xhci->op_regs->command); -	temp = xhci_readl(xhci, &xhci->op_regs->command); +	writel(temp, &xhci->op_regs->command); +	temp = readl(&xhci->op_regs->command);  	spin_unlock_irqrestore(&xhci->lock, flags);  	return 0; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 53b972c2a09..8056d90690e 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -57,7 +57,7 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,  	/* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */  	if (cycle_state == 0) {  		for (i = 0; i < TRBS_PER_SEGMENT; i++) -			seg->trbs[i].link.control |= TRB_CYCLE; +			seg->trbs[i].link.control |= cpu_to_le32(TRB_CYCLE);  	}  	seg->dma = dma;  	seg->next = NULL; @@ -149,14 +149,140 @@ static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring,  	}  } +/* + * We need a radix tree for mapping physical addresses of TRBs to which stream + * ID they belong to.  We need to do this because the host controller won't tell + * us which stream ring the TRB came from.  We could store the stream ID in an + * event data TRB, but that doesn't help us for the cancellation case, since the + * endpoint may stop before it reaches that event data TRB. + * + * The radix tree maps the upper portion of the TRB DMA address to a ring + * segment that has the same upper portion of DMA addresses.  For example, say I + * have segments of size 1KB, that are always 1KB aligned.  A segment may + * start at 0x10c91000 and end at 0x10c913f0.  If I use the upper 10 bits, the + * key to the stream ID is 0x43244.  I can use the DMA address of the TRB to + * pass the radix tree a key to get the right stream ID: + * + *	0x10c90fff >> 10 = 0x43243 + *	0x10c912c0 >> 10 = 0x43244 + *	0x10c91400 >> 10 = 0x43245 + * + * Obviously, only those TRBs with DMA addresses that are within the segment + * will make the radix tree return the stream ID for that ring. + * + * Caveats for the radix tree: + * + * The radix tree uses an unsigned long as a key pair.  On 32-bit systems, an + * unsigned long will be 32-bits; on a 64-bit system an unsigned long will be + * 64-bits.  Since we only request 32-bit DMA addresses, we can use that as the + * key on 32-bit or 64-bit systems (it would also be fine if we asked for 64-bit + * PCI DMA addresses on a 64-bit system).  There might be a problem on 32-bit + * extended systems (where the DMA address can be bigger than 32-bits), + * if we allow the PCI dma mask to be bigger than 32-bits.  So don't do that. + */ +static int xhci_insert_segment_mapping(struct radix_tree_root *trb_address_map, +		struct xhci_ring *ring, +		struct xhci_segment *seg, +		gfp_t mem_flags) +{ +	unsigned long key; +	int ret; + +	key = (unsigned long)(seg->dma >> TRB_SEGMENT_SHIFT); +	/* Skip any segments that were already added. */ +	if (radix_tree_lookup(trb_address_map, key)) +		return 0; + +	ret = radix_tree_maybe_preload(mem_flags); +	if (ret) +		return ret; +	ret = radix_tree_insert(trb_address_map, +			key, ring); +	radix_tree_preload_end(); +	return ret; +} + +static void xhci_remove_segment_mapping(struct radix_tree_root *trb_address_map, +		struct xhci_segment *seg) +{ +	unsigned long key; + +	key = (unsigned long)(seg->dma >> TRB_SEGMENT_SHIFT); +	if (radix_tree_lookup(trb_address_map, key)) +		radix_tree_delete(trb_address_map, key); +} + +static int xhci_update_stream_segment_mapping( +		struct radix_tree_root *trb_address_map, +		struct xhci_ring *ring, +		struct xhci_segment *first_seg, +		struct xhci_segment *last_seg, +		gfp_t mem_flags) +{ +	struct xhci_segment *seg; +	struct xhci_segment *failed_seg; +	int ret; + +	if (WARN_ON_ONCE(trb_address_map == NULL)) +		return 0; + +	seg = first_seg; +	do { +		ret = xhci_insert_segment_mapping(trb_address_map, +				ring, seg, mem_flags); +		if (ret) +			goto remove_streams; +		if (seg == last_seg) +			return 0; +		seg = seg->next; +	} while (seg != first_seg); + +	return 0; + +remove_streams: +	failed_seg = seg; +	seg = first_seg; +	do { +		xhci_remove_segment_mapping(trb_address_map, seg); +		if (seg == failed_seg) +			return ret; +		seg = seg->next; +	} while (seg != first_seg); + +	return ret; +} + +static void xhci_remove_stream_mapping(struct xhci_ring *ring) +{ +	struct xhci_segment *seg; + +	if (WARN_ON_ONCE(ring->trb_address_map == NULL)) +		return; + +	seg = ring->first_seg; +	do { +		xhci_remove_segment_mapping(ring->trb_address_map, seg); +		seg = seg->next; +	} while (seg != ring->first_seg); +} + +static int xhci_update_stream_mapping(struct xhci_ring *ring, gfp_t mem_flags) +{ +	return xhci_update_stream_segment_mapping(ring->trb_address_map, ring, +			ring->first_seg, ring->last_seg, mem_flags); +} +  /* XXX: Do we need the hcd structure in all these functions? */  void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)  {  	if (!ring)  		return; -	if (ring->first_seg) +	if (ring->first_seg) { +		if (ring->type == TYPE_STREAM) +			xhci_remove_stream_mapping(ring);  		xhci_free_segments_for_ring(xhci, ring->first_seg); +	}  	kfree(ring);  } @@ -308,7 +434,8 @@ static void xhci_reinit_cached_ring(struct xhci_hcd *xhci,  				sizeof(union xhci_trb)*TRBS_PER_SEGMENT);  		if (cycle_state == 0) {  			for (i = 0; i < TRBS_PER_SEGMENT; i++) -				seg->trbs[i].link.control |= TRB_CYCLE; +				seg->trbs[i].link.control |= +					cpu_to_le32(TRB_CYCLE);  		}  		/* All endpoint rings have link TRBs */  		xhci_link_segments(xhci, seg, seg->next, type); @@ -348,6 +475,21 @@ int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,  	if (ret)  		return -ENOMEM; +	if (ring->type == TYPE_STREAM) +		ret = xhci_update_stream_segment_mapping(ring->trb_address_map, +						ring, first, last, flags); +	if (ret) { +		struct xhci_segment *next; +		do { +			next = first->next; +			xhci_segment_free(xhci, first); +			if (first == last) +				break; +			first = next; +		} while (true); +		return ret; +	} +  	xhci_link_rings(xhci, ring, first, last, num_segs);  	xhci_dbg_trace(xhci, trace_xhci_dbg_ring_expansion,  			"ring expansion succeed, now has %d segments", @@ -432,13 +574,13 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci,  		unsigned int num_stream_ctxs,  		struct xhci_stream_ctx *stream_ctx, dma_addr_t dma)  { -	struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); +	struct device *dev = xhci_to_hcd(xhci)->self.controller; +	size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs; -	if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE) -		dma_free_coherent(&pdev->dev, -				sizeof(struct xhci_stream_ctx)*num_stream_ctxs, +	if (size > MEDIUM_STREAM_ARRAY_SIZE) +		dma_free_coherent(dev, size,  				stream_ctx, dma); -	else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE) +	else if (size <= SMALL_STREAM_ARRAY_SIZE)  		return dma_pool_free(xhci->small_streams_pool,  				stream_ctx, dma);  	else @@ -460,13 +602,13 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci,  		unsigned int num_stream_ctxs, dma_addr_t *dma,  		gfp_t mem_flags)  { -	struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); +	struct device *dev = xhci_to_hcd(xhci)->self.controller; +	size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs; -	if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE) -		return dma_alloc_coherent(&pdev->dev, -				sizeof(struct xhci_stream_ctx)*num_stream_ctxs, +	if (size > MEDIUM_STREAM_ARRAY_SIZE) +		return dma_alloc_coherent(dev, size,  				dma, mem_flags); -	else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE) +	else if (size <= SMALL_STREAM_ARRAY_SIZE)  		return dma_pool_alloc(xhci->small_streams_pool,  				mem_flags, dma);  	else @@ -509,36 +651,6 @@ struct xhci_ring *xhci_stream_id_to_ring(   * The number of stream contexts in the stream context array may be bigger than   * the number of streams the driver wants to use.  This is because the number of   * stream context array entries must be a power of two. - * - * We need a radix tree for mapping physical addresses of TRBs to which stream - * ID they belong to.  We need to do this because the host controller won't tell - * us which stream ring the TRB came from.  We could store the stream ID in an - * event data TRB, but that doesn't help us for the cancellation case, since the - * endpoint may stop before it reaches that event data TRB. - * - * The radix tree maps the upper portion of the TRB DMA address to a ring - * segment that has the same upper portion of DMA addresses.  For example, say I - * have segments of size 1KB, that are always 64-byte aligned.  A segment may - * start at 0x10c91000 and end at 0x10c913f0.  If I use the upper 10 bits, the - * key to the stream ID is 0x43244.  I can use the DMA address of the TRB to - * pass the radix tree a key to get the right stream ID: - * - * 	0x10c90fff >> 10 = 0x43243 - * 	0x10c912c0 >> 10 = 0x43244 - * 	0x10c91400 >> 10 = 0x43245 - * - * Obviously, only those TRBs with DMA addresses that are within the segment - * will make the radix tree return the stream ID for that ring. - * - * Caveats for the radix tree: - * - * The radix tree uses an unsigned long as a key pair.  On 32-bit systems, an - * unsigned long will be 32-bits; on a 64-bit system an unsigned long will be - * 64-bits.  Since we only request 32-bit DMA addresses, we can use that as the - * key on 32-bit or 64-bit systems (it would also be fine if we asked for 64-bit - * PCI DMA addresses on a 64-bit system).  There might be a problem on 32-bit - * extended systems (where the DMA address can be bigger than 32-bits), - * if we allow the PCI dma mask to be bigger than 32-bits.  So don't do that.   */  struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,  		unsigned int num_stream_ctxs, @@ -547,7 +659,6 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,  	struct xhci_stream_info *stream_info;  	u32 cur_stream;  	struct xhci_ring *cur_ring; -	unsigned long key;  	u64 addr;  	int ret; @@ -602,6 +713,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,  		if (!cur_ring)  			goto cleanup_rings;  		cur_ring->stream_id = cur_stream; +		cur_ring->trb_address_map = &stream_info->trb_address_map;  		/* Set deq ptr, cycle bit, and stream context type */  		addr = cur_ring->first_seg->dma |  			SCT_FOR_CTX(SCT_PRI_TR) | @@ -611,10 +723,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,  		xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n",  				cur_stream, (unsigned long long) addr); -		key = (unsigned long) -			(cur_ring->first_seg->dma >> TRB_SEGMENT_SHIFT); -		ret = radix_tree_insert(&stream_info->trb_address_map, -				key, cur_ring); +		ret = xhci_update_stream_mapping(cur_ring, mem_flags);  		if (ret) {  			xhci_ring_free(xhci, cur_ring);  			stream_info->stream_rings[cur_stream] = NULL; @@ -634,9 +743,6 @@ cleanup_rings:  	for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {  		cur_ring = stream_info->stream_rings[cur_stream];  		if (cur_ring) { -			addr = cur_ring->first_seg->dma; -			radix_tree_delete(&stream_info->trb_address_map, -					addr >> TRB_SEGMENT_SHIFT);  			xhci_ring_free(xhci, cur_ring);  			stream_info->stream_rings[cur_stream] = NULL;  		} @@ -697,7 +803,6 @@ void xhci_free_stream_info(struct xhci_hcd *xhci,  {  	int cur_stream;  	struct xhci_ring *cur_ring; -	dma_addr_t addr;  	if (!stream_info)  		return; @@ -706,9 +811,6 @@ void xhci_free_stream_info(struct xhci_hcd *xhci,  			cur_stream++) {  		cur_ring = stream_info->stream_rings[cur_stream];  		if (cur_ring) { -			addr = cur_ring->first_seg->dma; -			radix_tree_delete(&stream_info->trb_address_map, -					addr >> TRB_SEGMENT_SHIFT);  			xhci_ring_free(xhci, cur_ring);  			stream_info->stream_rings[cur_stream] = NULL;  		} @@ -721,8 +823,7 @@ void xhci_free_stream_info(struct xhci_hcd *xhci,  				stream_info->stream_ctx_array,  				stream_info->ctx_array_dma); -	if (stream_info) -		kfree(stream_info->stream_rings); +	kfree(stream_info->stream_rings);  	kfree(stream_info);  } @@ -919,7 +1020,6 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,  	dev->num_rings_cached = 0;  	init_completion(&dev->cmd_completion); -	INIT_LIST_HEAD(&dev->cmd_list);  	dev->udev = udev;  	/* Point to output device context in dcbaa. */ @@ -1616,7 +1716,7 @@ static void scratchpad_free(struct xhci_hcd *xhci)  {  	int num_sp;  	int i; -	struct pci_dev	*pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); +	struct device *dev = xhci_to_hcd(xhci)->self.controller;  	if (!xhci->scratchpad)  		return; @@ -1624,13 +1724,13 @@ static void scratchpad_free(struct xhci_hcd *xhci)  	num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);  	for (i = 0; i < num_sp; i++) { -		dma_free_coherent(&pdev->dev, xhci->page_size, +		dma_free_coherent(dev, xhci->page_size,  				    xhci->scratchpad->sp_buffers[i],  				    xhci->scratchpad->sp_dma_buffers[i]);  	}  	kfree(xhci->scratchpad->sp_dma_buffers);  	kfree(xhci->scratchpad->sp_buffers); -	dma_free_coherent(&pdev->dev, num_sp * sizeof(u64), +	dma_free_coherent(dev, num_sp * sizeof(u64),  			    xhci->scratchpad->sp_array,  			    xhci->scratchpad->sp_dma);  	kfree(xhci->scratchpad); @@ -1692,17 +1792,16 @@ void xhci_free_command(struct xhci_hcd *xhci,  void xhci_mem_cleanup(struct xhci_hcd *xhci)  { -	struct pci_dev	*pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); -	struct dev_info	*dev_info, *next; -	struct xhci_cd  *cur_cd, *next_cd; -	unsigned long	flags; +	struct device	*dev = xhci_to_hcd(xhci)->self.controller;  	int size;  	int i, j, num_ports; +	del_timer_sync(&xhci->cmd_timer); +  	/* Free the Event Ring Segment Table and the actual Event Ring */  	size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);  	if (xhci->erst.entries) -		dma_free_coherent(&pdev->dev, size, +		dma_free_coherent(dev, size,  				xhci->erst.entries, xhci->erst.erst_dma_addr);  	xhci->erst.entries = NULL;  	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed ERST"); @@ -1713,15 +1812,20 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)  	if (xhci->lpm_command)  		xhci_free_command(xhci, xhci->lpm_command); -	xhci->cmd_ring_reserved_trbs = 0;  	if (xhci->cmd_ring)  		xhci_ring_free(xhci, xhci->cmd_ring);  	xhci->cmd_ring = NULL;  	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed command ring"); -	list_for_each_entry_safe(cur_cd, next_cd, -			&xhci->cancel_cmd_list, cancel_cmd_list) { -		list_del(&cur_cd->cancel_cmd_list); -		kfree(cur_cd); +	xhci_cleanup_command_queue(xhci); + +	num_ports = HCS_MAX_PORTS(xhci->hcs_params1); +	for (i = 0; i < num_ports; i++) { +		struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table; +		for (j = 0; j < XHCI_MAX_INTERVAL; j++) { +			struct list_head *ep = &bwt->interval_bw[j].endpoints; +			while (!list_empty(ep)) +				list_del_init(ep->next); +		}  	}  	for (i = 1; i < MAX_HC_SLOTS; ++i) @@ -1750,32 +1854,15 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)  			"Freed medium stream array pool");  	if (xhci->dcbaa) -		dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa), +		dma_free_coherent(dev, sizeof(*xhci->dcbaa),  				xhci->dcbaa, xhci->dcbaa->dma);  	xhci->dcbaa = NULL;  	scratchpad_free(xhci); -	spin_lock_irqsave(&xhci->lock, flags); -	list_for_each_entry_safe(dev_info, next, &xhci->lpm_failed_devs, list) { -		list_del(&dev_info->list); -		kfree(dev_info); -	} -	spin_unlock_irqrestore(&xhci->lock, flags); -  	if (!xhci->rh_bw)  		goto no_bw; -	num_ports = HCS_MAX_PORTS(xhci->hcs_params1); -	for (i = 0; i < num_ports; i++) { -		struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table; -		for (j = 0; j < XHCI_MAX_INTERVAL; j++) { -			struct list_head *ep = &bwt->interval_bw[j].endpoints; -			while (!list_empty(ep)) -				list_del_init(ep->next); -		} -	} -  	for (i = 0; i < num_ports; i++) {  		struct xhci_tt_bw_info *tt, *n;  		list_for_each_entry_safe(tt, n, &xhci->rh_bw[i].tts, tt_list) { @@ -1785,6 +1872,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)  	}  no_bw: +	xhci->cmd_ring_reserved_trbs = 0;  	xhci->num_usb2_ports = 0;  	xhci->num_usb3_ports = 0;  	xhci->num_active_eps = 0; @@ -1995,7 +2083,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,  	}  	/* Port offset and count in the third dword, see section 7.2 */ -	temp = xhci_readl(xhci, addr + 2); +	temp = readl(addr + 2);  	port_offset = XHCI_EXT_PORT_OFF(temp);  	port_count = XHCI_EXT_PORT_COUNT(temp);  	xhci_dbg_trace(xhci, trace_xhci_dbg_init, @@ -2078,7 +2166,7 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)  	int cap_count = 0;  	addr = &xhci->cap_regs->hcc_params; -	offset = XHCI_HCC_EXT_CAPS(xhci_readl(xhci, addr)); +	offset = XHCI_HCC_EXT_CAPS(readl(addr));  	if (offset == 0) {  		xhci_err(xhci, "No Extended Capability registers, "  				"unable to set up roothub.\n"); @@ -2115,7 +2203,7 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)  	/* count extended protocol capability entries for later caching */  	do {  		u32 cap_id; -		cap_id = xhci_readl(xhci, tmp_addr); +		cap_id = readl(tmp_addr);  		if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL)  			cap_count++;  		tmp_offset = XHCI_EXT_CAPS_NEXT(cap_id); @@ -2129,7 +2217,7 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)  	while (1) {  		u32 cap_id; -		cap_id = xhci_readl(xhci, addr); +		cap_id = readl(addr);  		if (XHCI_EXT_CAPS_ID(cap_id) == XHCI_EXT_CAPS_PROTOCOL)  			xhci_add_in_port(xhci, num_ports, addr,  					(u8) XHCI_EXT_PORT_MAJOR(cap_id), @@ -2231,10 +2319,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  	u32 page_size, temp;  	int i; -	INIT_LIST_HEAD(&xhci->lpm_failed_devs); -	INIT_LIST_HEAD(&xhci->cancel_cmd_list); +	INIT_LIST_HEAD(&xhci->cmd_list); -	page_size = xhci_readl(xhci, &xhci->op_regs->page_size); +	page_size = readl(&xhci->op_regs->page_size);  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"Supported page size register = 0x%x", page_size);  	for (i = 0; i < 16; i++) { @@ -2257,14 +2344,14 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  	 * Program the Number of Device Slots Enabled field in the CONFIG  	 * register with the max value of slots the HC can handle.  	 */ -	val = HCS_MAX_SLOTS(xhci_readl(xhci, &xhci->cap_regs->hcs_params1)); +	val = HCS_MAX_SLOTS(readl(&xhci->cap_regs->hcs_params1));  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"// xHC can handle at most %d device slots.", val); -	val2 = xhci_readl(xhci, &xhci->op_regs->config_reg); +	val2 = readl(&xhci->op_regs->config_reg);  	val |= (val2 & ~HCS_SLOTS_MASK);  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"// Setting Max device slots reg = 0x%x.", val); -	xhci_writel(xhci, val, &xhci->op_regs->config_reg); +	writel(val, &xhci->op_regs->config_reg);  	/*  	 * Section 5.4.8 - doorbell array must be @@ -2284,11 +2371,12 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  	/*  	 * Initialize the ring segment pool.  The ring must be a contiguous  	 * structure comprised of TRBs.  The TRBs must be 16 byte aligned, -	 * however, the command ring segment needs 64-byte aligned segments, -	 * so we pick the greater alignment need. +	 * however, the command ring segment needs 64-byte aligned segments +	 * and our use of dma addresses in the trb_address_map radix tree needs +	 * TRB_SEGMENT_SIZE alignment, so we pick the greater alignment need.  	 */  	xhci->segment_pool = dma_pool_create("xHCI ring segments", dev, -			TRB_SEGMENT_SIZE, 64, xhci->page_size); +			TRB_SEGMENT_SIZE, TRB_SEGMENT_SIZE, xhci->page_size);  	/* See Table 46 and Note on Figure 55 */  	xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev, @@ -2341,7 +2429,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  	 */  	xhci->cmd_ring_reserved_trbs++; -	val = xhci_readl(xhci, &xhci->cap_regs->db_off); +	val = readl(&xhci->cap_regs->db_off);  	val &= DBOFF_MASK;  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"// Doorbell array is located at offset 0x%x" @@ -2392,13 +2480,13 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  	}  	/* set ERST count with the number of entries in the segment table */ -	val = xhci_readl(xhci, &xhci->ir_set->erst_size); +	val = readl(&xhci->ir_set->erst_size);  	val &= ERST_SIZE_MASK;  	val |= ERST_NUM_SEGS;  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"// Write ERST size = %i to ir_set 0 (some bits preserved)",  			val); -	xhci_writel(xhci, val, &xhci->ir_set->erst_size); +	writel(val, &xhci->ir_set->erst_size);  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"// Set ERST entries to point to event ring."); @@ -2417,6 +2505,11 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  			"Wrote ERST address to ir_set 0.");  	xhci_print_ir_set(xhci, 0); +	/* init command timeout timer */ +	init_timer(&xhci->cmd_timer); +	xhci->cmd_timer.data = (unsigned long) xhci; +	xhci->cmd_timer.function = xhci_handle_command_timeout; +  	/*  	 * XXX: Might need to set the Interrupter Moderation Register to  	 * something other than the default (~1ms minimum between interrupts). @@ -2428,6 +2521,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  	for (i = 0; i < USB_MAXCHILDREN; ++i) {  		xhci->bus_state[0].resume_done[i] = 0;  		xhci->bus_state[1].resume_done[i] = 0; +		/* Only the USB 2.0 completions will ever be used. */ +		init_completion(&xhci->bus_state[1].rexit_done[i]);  	}  	if (scratchpad_alloc(xhci, flags)) @@ -2439,10 +2534,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)  	 * is necessary for allowing USB 3.0 devices to do remote wakeup from  	 * U3 (device suspend).  	 */ -	temp = xhci_readl(xhci, &xhci->op_regs->dev_notification); +	temp = readl(&xhci->op_regs->dev_notification);  	temp &= ~DEV_NOTE_MASK;  	temp |= DEV_NOTE_FWAKE; -	xhci_writel(xhci, temp, &xhci->op_regs->dev_notification); +	writel(temp, &xhci->op_regs->dev_notification);  	return 0; diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c new file mode 100644 index 00000000000..1eefc988192 --- /dev/null +++ b/drivers/usb/host/xhci-mvebu.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2014 Marvell + * Author: Gregory CLEMENT <gregory.clement@free-electrons.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include <linux/io.h> +#include <linux/mbus.h> +#include <linux/of.h> +#include <linux/platform_device.h> + +#include "xhci-mvebu.h" + +#define USB3_MAX_WINDOWS	4 +#define USB3_WIN_CTRL(w)	(0x0 + ((w) * 8)) +#define USB3_WIN_BASE(w)	(0x4 + ((w) * 8)) + +static void xhci_mvebu_mbus_config(void __iomem *base, +			const struct mbus_dram_target_info *dram) +{ +	int win; + +	/* Clear all existing windows */ +	for (win = 0; win < USB3_MAX_WINDOWS; win++) { +		writel(0, base + USB3_WIN_CTRL(win)); +		writel(0, base + USB3_WIN_BASE(win)); +	} + +	/* Program each DRAM CS in a seperate window */ +	for (win = 0; win < dram->num_cs; win++) { +		const struct mbus_dram_window *cs = dram->cs + win; + +		writel(((cs->size - 1) & 0xffff0000) | (cs->mbus_attr << 8) | +		       (dram->mbus_dram_target_id << 4) | 1, +		       base + USB3_WIN_CTRL(win)); + +		writel((cs->base & 0xffff0000), base + USB3_WIN_BASE(win)); +	} +} + +int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev) +{ +	struct resource	*res; +	void __iomem *base; +	const struct mbus_dram_target_info *dram; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1); +	if (!res) +		return -ENODEV; + +	/* +	 * We don't use devm_ioremap() because this mapping should +	 * only exists for the duration of this probe function. +	 */ +	base = ioremap(res->start, resource_size(res)); +	if (!base) +		return -ENODEV; + +	dram = mv_mbus_dram_info(); +	xhci_mvebu_mbus_config(base, dram); + +	/* +	 * This memory area was only needed to configure the MBus +	 * windows, and is therefore no longer useful. +	 */ +	iounmap(base); + +	return 0; +} diff --git a/drivers/usb/host/xhci-mvebu.h b/drivers/usb/host/xhci-mvebu.h new file mode 100644 index 00000000000..7ede92aa41f --- /dev/null +++ b/drivers/usb/host/xhci-mvebu.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2014 Marvell + * + * Gregory Clement <gregory.clement@free-electrons.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2.  This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __LINUX_XHCI_MVEBU_H +#define __LINUX_XHCI_MVEBU_H +#if IS_ENABLED(CONFIG_USB_XHCI_MVEBU) +int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev); +#else +static inline int xhci_mvebu_mbus_init_quirk(struct platform_device *pdev) +{ +	return 0; +} +#endif +#endif /* __LINUX_XHCI_MVEBU_H */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index c2d495057eb..e20520f4275 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -35,6 +35,9 @@  #define PCI_VENDOR_ID_ETRON		0x1b6f  #define PCI_DEVICE_ID_ASROCK_P67	0x7023 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI	0x8c31 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI	0x9c31 +  static const char hcd_name[] = "xhci_hcd";  /* called after powerup, by probe or system-pm "wakeup" */ @@ -69,6 +72,14 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)  				"QUIRK: Fresco Logic xHC needs configure"  				" endpoint cmd after reset endpoint");  		} +		if (pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK && +				pdev->revision == 0x4) { +			xhci->quirks |= XHCI_SLOW_SUSPEND; +			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, +				"QUIRK: Fresco Logic xHC revision %u" +				"must be suspended extra slowly", +				pdev->revision); +		}  		/* Fresco Logic confirms: all revisions of this chip do not  		 * support MSI, even though some of them claim to in their PCI  		 * capabilities. @@ -110,15 +121,38 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)  		xhci->quirks |= XHCI_SPURIOUS_REBOOT;  		xhci->quirks |= XHCI_AVOID_BEI;  	} +	if (pdev->vendor == PCI_VENDOR_ID_INTEL && +	    (pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_XHCI || +	     pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI)) { +		/* Workaround for occasional spurious wakeups from S5 (or +		 * any other sleep) on Haswell machines with LPT and LPT-LP +		 * with the new Intel BIOS +		 */ +		/* Limit the quirk to only known vendors, as this triggers +		 * yet another BIOS bug on some other machines +		 * https://bugzilla.kernel.org/show_bug.cgi?id=66171 +		 */ +		if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP) +			xhci->quirks |= XHCI_SPURIOUS_WAKEUP; +	} +	if (pdev->vendor == PCI_VENDOR_ID_INTEL && +		pdev->device == PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI) { +		xhci->quirks |= XHCI_SPURIOUS_REBOOT; +	}  	if (pdev->vendor == PCI_VENDOR_ID_ETRON &&  			pdev->device == PCI_DEVICE_ID_ASROCK_P67) {  		xhci->quirks |= XHCI_RESET_ON_RESUME; -		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, -				"QUIRK: Resetting on resume");  		xhci->quirks |= XHCI_TRUST_TX_LENGTH;  	} +	if (pdev->vendor == PCI_VENDOR_ID_RENESAS && +			pdev->device == 0x0015) +		xhci->quirks |= XHCI_RESET_ON_RESUME;  	if (pdev->vendor == PCI_VENDOR_ID_VIA)  		xhci->quirks |= XHCI_RESET_ON_RESUME; + +	if (xhci->quirks & XHCI_RESET_ON_RESUME) +		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, +				"QUIRK: Resetting on resume");  }  /* called during probe() after chip reset completes */ @@ -160,6 +194,10 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  	struct usb_hcd *hcd;  	driver = (struct hc_driver *)id->driver_data; + +	/* Prevent runtime suspending between USB-2 and USB-3 initialization */ +	pm_runtime_get_noresume(&dev->dev); +  	/* Register the USB 2.0 roothub.  	 * FIXME: USB core must know to register the USB 2.0 roothub first.  	 * This is sort of silly, because we could just set the HCD driver flags @@ -169,7 +207,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  	retval = usb_hcd_pci_probe(dev, id);  	if (retval) -		return retval; +		goto put_runtime_pm;  	/* USB 2.0 roothub is stored in the PCI device now. */  	hcd = dev_get_drvdata(&dev->dev); @@ -192,11 +230,11 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)  		goto put_usb3_hcd;  	/* Roothub already marked as USB 3.0 speed */ -	/* We know the LPM timeout algorithms for this host, let the USB core -	 * enable and disable LPM for devices under the USB 3.0 roothub. -	 */ -	if (xhci->quirks & XHCI_LPM_SUPPORT) -		hcd_to_bus(xhci->shared_hcd)->root_hub->lpm_capable = 1; +	if (HCC_MAX_PSA(xhci->hcc_params) >= 4) +		xhci->shared_hcd->can_do_streams = 1; + +	/* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */ +	pm_runtime_put_noidle(&dev->dev);  	return 0; @@ -204,6 +242,8 @@ put_usb3_hcd:  	usb_put_hcd(xhci->shared_hcd);  dealloc_usb2_hcd:  	usb_hcd_pci_remove(dev); +put_runtime_pm: +	pm_runtime_put_noidle(&dev->dev);  	return retval;  } @@ -217,6 +257,11 @@ static void xhci_pci_remove(struct pci_dev *dev)  		usb_put_hcd(xhci->shared_hcd);  	}  	usb_hcd_pci_remove(dev); + +	/* Workaround for spurious wakeups at shutdown with HSW */ +	if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) +		pci_set_power_state(dev, PCI_D3hot); +  	kfree(xhci);  } @@ -306,6 +351,7 @@ static const struct hc_driver xhci_pci_hc_driver = {  	.check_bandwidth =	xhci_check_bandwidth,  	.reset_bandwidth =	xhci_reset_bandwidth,  	.address_device =	xhci_address_device, +	.enable_device =	xhci_enable_device,  	.update_hub_device =	xhci_update_hub_device,  	.reset_device =		xhci_discover_or_reset_device, @@ -351,7 +397,7 @@ static struct pci_driver xhci_pci_driver = {  	/* suspend and resume implemented later */  	.shutdown = 	usb_hcd_pci_shutdown, -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM  	.driver = {  		.pm = &usb_hcd_pci_pm_ops  	}, diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index d9c169f470d..29d8adb5c8d 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -11,13 +11,15 @@   * version 2 as published by the Free Software Foundation.   */ -#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/dma-mapping.h>  #include <linux/module.h> -#include <linux/slab.h>  #include <linux/of.h> -#include <linux/dma-mapping.h> +#include <linux/platform_device.h> +#include <linux/slab.h>  #include "xhci.h" +#include "xhci-mvebu.h"  static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)  { @@ -35,6 +37,11 @@ static int xhci_plat_setup(struct usb_hcd *hcd)  	return xhci_gen_setup(hcd, xhci_plat_quirks);  } +static int xhci_plat_start(struct usb_hcd *hcd) +{ +	return xhci_run(hcd); +} +  static const struct hc_driver xhci_plat_xhci_driver = {  	.description =		"xhci-hcd",  	.product_desc =		"xHCI Host Controller", @@ -50,7 +57,7 @@ static const struct hc_driver xhci_plat_xhci_driver = {  	 * basic lifecycle operations  	 */  	.reset =		xhci_plat_setup, -	.start =		xhci_run, +	.start =		xhci_plat_start,  	.stop =			xhci_stop,  	.shutdown =		xhci_shutdown, @@ -69,6 +76,7 @@ static const struct hc_driver xhci_plat_xhci_driver = {  	.check_bandwidth =	xhci_check_bandwidth,  	.reset_bandwidth =	xhci_reset_bandwidth,  	.address_device =	xhci_address_device, +	.enable_device =	xhci_enable_device,  	.update_hub_device =	xhci_update_hub_device,  	.reset_device =		xhci_discover_or_reset_device, @@ -90,6 +98,7 @@ static int xhci_plat_probe(struct platform_device *pdev)  	struct xhci_hcd		*xhci;  	struct resource         *res;  	struct usb_hcd		*hcd; +	struct clk              *clk;  	int			ret;  	int			irq; @@ -106,6 +115,15 @@ static int xhci_plat_probe(struct platform_device *pdev)  	if (!res)  		return -ENODEV; +	if (of_device_is_compatible(pdev->dev.of_node, +				    "marvell,armada-375-xhci") || +	    of_device_is_compatible(pdev->dev.of_node, +				    "marvell,armada-380-xhci")) { +		ret = xhci_mvebu_mbus_init_quirk(pdev); +		if (ret) +			return ret; +	} +  	/* Initialize dma_mask and coherent_dma_mask to 32-bits */  	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));  	if (ret) @@ -136,13 +154,27 @@ static int xhci_plat_probe(struct platform_device *pdev)  		goto release_mem_region;  	} +	/* +	 * Not all platforms have a clk so it is not an error if the +	 * clock does not exists. +	 */ +	clk = devm_clk_get(&pdev->dev, NULL); +	if (!IS_ERR(clk)) { +		ret = clk_prepare_enable(clk); +		if (ret) +			goto unmap_registers; +	} +  	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);  	if (ret) -		goto unmap_registers; +		goto disable_clk; + +	device_wakeup_enable(hcd->self.controller);  	/* USB 2.0 roothub is stored in the platform_device now. */  	hcd = platform_get_drvdata(pdev);  	xhci = hcd_to_xhci(hcd); +	xhci->clk = clk;  	xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev,  			dev_name(&pdev->dev), hcd);  	if (!xhci->shared_hcd) { @@ -156,6 +188,9 @@ static int xhci_plat_probe(struct platform_device *pdev)  	 */  	*((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; +	if (HCC_MAX_PSA(xhci->hcc_params) >= 4) +		xhci->shared_hcd->can_do_streams = 1; +  	ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);  	if (ret)  		goto put_usb3_hcd; @@ -168,6 +203,10 @@ put_usb3_hcd:  dealloc_usb2_hcd:  	usb_remove_hcd(hcd); +disable_clk: +	if (!IS_ERR(clk)) +		clk_disable_unprepare(clk); +  unmap_registers:  	iounmap(hcd->regs); @@ -184,11 +223,14 @@ static int xhci_plat_remove(struct platform_device *dev)  {  	struct usb_hcd	*hcd = platform_get_drvdata(dev);  	struct xhci_hcd	*xhci = hcd_to_xhci(hcd); +	struct clk *clk = xhci->clk;  	usb_remove_hcd(xhci->shared_hcd);  	usb_put_hcd(xhci->shared_hcd);  	usb_remove_hcd(hcd); +	if (!IS_ERR(clk)) +		clk_disable_unprepare(clk);  	iounmap(hcd->regs);  	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);  	usb_put_hcd(hcd); @@ -197,7 +239,7 @@ static int xhci_plat_remove(struct platform_device *dev)  	return 0;  } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP  static int xhci_plat_suspend(struct device *dev)  {  	struct usb_hcd	*hcd = dev_get_drvdata(dev); @@ -224,7 +266,10 @@ static const struct dev_pm_ops xhci_plat_pm_ops = {  #ifdef CONFIG_OF  static const struct of_device_id usb_xhci_of_match[] = { +	{ .compatible = "generic-xhci" },  	{ .compatible = "xhci-platform" }, +	{ .compatible = "marvell,armada-375-xhci"}, +	{ .compatible = "marvell,armada-380-xhci"},  	{ },  };  MODULE_DEVICE_TABLE(of, usb_xhci_of_match); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 411da1fc7ae..749fc68eb5c 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -69,10 +69,6 @@  #include "xhci.h"  #include "xhci-trace.h" -static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, -		struct xhci_virt_device *virt_dev, -		struct xhci_event_cmd *event); -  /*   * Returns zero if the TRB isn't in this segment, otherwise it returns the DMA   * address of the TRB. @@ -146,8 +142,6 @@ static void next_trb(struct xhci_hcd *xhci,   */  static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)  { -	unsigned long long addr; -  	ring->deq_updates++;  	/* @@ -168,7 +162,7 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)  			if (ring->type == TYPE_EVENT &&  					last_trb_on_last_seg(xhci, ring,  						ring->deq_seg, ring->dequeue)) { -				ring->cycle_state = (ring->cycle_state ? 0 : 1); +				ring->cycle_state ^= 1;  			}  			ring->deq_seg = ring->deq_seg->next;  			ring->dequeue = ring->deq_seg->trbs; @@ -176,8 +170,6 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)  			ring->dequeue++;  		}  	} while (last_trb(xhci, ring, ring->deq_seg, ring->dequeue)); - -	addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue);  }  /* @@ -202,7 +194,6 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,  {  	u32 chain;  	union xhci_trb *next; -	unsigned long long addr;  	chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;  	/* If this is not event ring, there is one less usable TRB */ @@ -254,7 +245,6 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,  		ring->enqueue = ring->enq_seg->trbs;  		next = ring->enqueue;  	} -	addr = (unsigned long long) xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue);  }  /* @@ -285,9 +275,9 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci)  		return;  	xhci_dbg(xhci, "// Ding dong!\n"); -	xhci_writel(xhci, DB_VALUE_HOST, &xhci->dba->doorbell[0]); +	writel(DB_VALUE_HOST, &xhci->dba->doorbell[0]);  	/* Flush PCI posted writes */ -	xhci_readl(xhci, &xhci->dba->doorbell[0]); +	readl(&xhci->dba->doorbell[0]);  }  static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) @@ -297,17 +287,7 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)  	xhci_dbg(xhci, "Abort command ring\n"); -	if (!(xhci->cmd_ring_state & CMD_RING_STATE_RUNNING)) { -		xhci_dbg(xhci, "The command ring isn't running, " -				"Have the command ring been stopped?\n"); -		return 0; -	} -  	temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); -	if (!(temp_64 & CMD_RING_RUNNING)) { -		xhci_dbg(xhci, "Command ring had been stopped\n"); -		return 0; -	}  	xhci->cmd_ring_state = CMD_RING_STATE_ABORTED;  	xhci_write_64(xhci, temp_64 | CMD_RING_ABORT,  			&xhci->op_regs->cmd_ring); @@ -333,71 +313,6 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)  	return 0;  } -static int xhci_queue_cd(struct xhci_hcd *xhci, -		struct xhci_command *command, -		union xhci_trb *cmd_trb) -{ -	struct xhci_cd *cd; -	cd = kzalloc(sizeof(struct xhci_cd), GFP_ATOMIC); -	if (!cd) -		return -ENOMEM; -	INIT_LIST_HEAD(&cd->cancel_cmd_list); - -	cd->command = command; -	cd->cmd_trb = cmd_trb; -	list_add_tail(&cd->cancel_cmd_list, &xhci->cancel_cmd_list); - -	return 0; -} - -/* - * Cancel the command which has issue. - * - * Some commands may hang due to waiting for acknowledgement from - * usb device. It is outside of the xHC's ability to control and - * will cause the command ring is blocked. When it occurs software - * should intervene to recover the command ring. - * See Section 4.6.1.1 and 4.6.1.2 - */ -int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command, -		union xhci_trb *cmd_trb) -{ -	int retval = 0; -	unsigned long flags; - -	spin_lock_irqsave(&xhci->lock, flags); - -	if (xhci->xhc_state & XHCI_STATE_DYING) { -		xhci_warn(xhci, "Abort the command ring," -				" but the xHCI is dead.\n"); -		retval = -ESHUTDOWN; -		goto fail; -	} - -	/* queue the cmd desriptor to cancel_cmd_list */ -	retval = xhci_queue_cd(xhci, command, cmd_trb); -	if (retval) { -		xhci_warn(xhci, "Queuing command descriptor failed.\n"); -		goto fail; -	} - -	/* abort command ring */ -	retval = xhci_abort_cmd_ring(xhci); -	if (retval) { -		xhci_err(xhci, "Abort command ring failed\n"); -		if (unlikely(retval == -ESHUTDOWN)) { -			spin_unlock_irqrestore(&xhci->lock, flags); -			usb_hc_died(xhci_to_hcd(xhci)->primary_hcd); -			xhci_dbg(xhci, "xHCI host controller is dead.\n"); -			return retval; -		} -	} - -fail: -	spin_unlock_irqrestore(&xhci->lock, flags); -	return retval; -} -  void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,  		unsigned int slot_id,  		unsigned int ep_index, @@ -417,7 +332,7 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,  	if ((ep_state & EP_HALT_PENDING) || (ep_state & SET_DEQ_PENDING) ||  	    (ep_state & EP_HALTED))  		return; -	xhci_writel(xhci, DB_VALUE(ep_index, stream_id), db_addr); +	writel(DB_VALUE(ep_index, stream_id), db_addr);  	/* The CPU has better things to do at this point than wait for a  	 * write-posting flush.  It'll get there soon enough.  	 */ @@ -542,10 +457,11 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,  		struct xhci_dequeue_state *state)  {  	struct xhci_virt_device *dev = xhci->devs[slot_id]; +	struct xhci_virt_ep *ep = &dev->eps[ep_index];  	struct xhci_ring *ep_ring;  	struct xhci_generic_trb *trb; -	struct xhci_ep_ctx *ep_ctx;  	dma_addr_t addr; +	u64 hw_dequeue;  	ep_ring = xhci_triad_to_transfer_ring(xhci, slot_id,  			ep_index, stream_id); @@ -555,56 +471,65 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,  				stream_id);  		return;  	} -	state->new_cycle_state = 0; -	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, -			"Finding segment containing stopped TRB."); -	state->new_deq_seg = find_trb_seg(cur_td->start_seg, -			dev->eps[ep_index].stopped_trb, -			&state->new_cycle_state); -	if (!state->new_deq_seg) { -		WARN_ON(1); -		return; -	}  	/* Dig out the cycle state saved by the xHC during the stop ep cmd */  	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,  			"Finding endpoint context"); -	ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); -	state->new_cycle_state = 0x1 & le64_to_cpu(ep_ctx->deq); +	/* 4.6.9 the css flag is written to the stream context for streams */ +	if (ep->ep_state & EP_HAS_STREAMS) { +		struct xhci_stream_ctx *ctx = +			&ep->stream_info->stream_ctx_array[stream_id]; +		hw_dequeue = le64_to_cpu(ctx->stream_ring); +	} else { +		struct xhci_ep_ctx *ep_ctx +			= xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); +		hw_dequeue = le64_to_cpu(ep_ctx->deq); +	} + +	/* Find virtual address and segment of hardware dequeue pointer */ +	state->new_deq_seg = ep_ring->deq_seg; +	state->new_deq_ptr = ep_ring->dequeue; +	while (xhci_trb_virt_to_dma(state->new_deq_seg, state->new_deq_ptr) +			!= (dma_addr_t)(hw_dequeue & ~0xf)) { +		next_trb(xhci, ep_ring, &state->new_deq_seg, +					&state->new_deq_ptr); +		if (state->new_deq_ptr == ep_ring->dequeue) { +			WARN_ON(1); +			return; +		} +	} +	/* +	 * Find cycle state for last_trb, starting at old cycle state of +	 * hw_dequeue. If there is only one segment ring, find_trb_seg() will +	 * return immediately and cannot toggle the cycle state if this search +	 * wraps around, so add one more toggle manually in that case. +	 */ +	state->new_cycle_state = hw_dequeue & 0x1; +	if (ep_ring->first_seg == ep_ring->first_seg->next && +			cur_td->last_trb < state->new_deq_ptr) +		state->new_cycle_state ^= 0x1;  	state->new_deq_ptr = cur_td->last_trb;  	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,  			"Finding segment containing last TRB in TD.");  	state->new_deq_seg = find_trb_seg(state->new_deq_seg, -			state->new_deq_ptr, -			&state->new_cycle_state); +			state->new_deq_ptr, &state->new_cycle_state);  	if (!state->new_deq_seg) {  		WARN_ON(1);  		return;  	} +	/* Increment to find next TRB after last_trb. Cycle if appropriate. */  	trb = &state->new_deq_ptr->generic;  	if (TRB_TYPE_LINK_LE32(trb->field[3]) &&  	    (trb->field[3] & cpu_to_le32(LINK_TOGGLE)))  		state->new_cycle_state ^= 0x1;  	next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr); -	/* -	 * If there is only one segment in a ring, find_trb_seg()'s while loop -	 * will not run, and it will return before it has a chance to see if it -	 * needs to toggle the cycle bit.  It can't tell if the stalled transfer -	 * ended just before the link TRB on a one-segment ring, or if the TD -	 * wrapped around the top of the ring, because it doesn't have the TD in -	 * question.  Look for the one-segment case where stalled TRB's address -	 * is greater than the new dequeue pointer address. -	 */ -	if (ep_ring->first_seg == ep_ring->first_seg->next && -			state->new_deq_ptr < dev->eps[ep_index].stopped_trb) -		state->new_cycle_state ^= 0x1; +	/* Don't update the ring cycle state for the producer (us). */  	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,  			"Cycle state = 0x%x", state->new_cycle_state); -	/* Don't update the ring cycle state for the producer (us). */  	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,  			"New dequeue segment = %p (virtual)",  			state->new_deq_seg); @@ -670,12 +595,14 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,  	}  } -static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, +static int queue_set_tr_deq(struct xhci_hcd *xhci, +		struct xhci_command *cmd, int slot_id,  		unsigned int ep_index, unsigned int stream_id,  		struct xhci_segment *deq_seg,  		union xhci_trb *deq_ptr, u32 cycle_state);  void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, +		struct xhci_command *cmd,  		unsigned int slot_id, unsigned int ep_index,  		unsigned int stream_id,  		struct xhci_dequeue_state *deq_state) @@ -690,7 +617,7 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,  			deq_state->new_deq_ptr,  			(unsigned long long)xhci_trb_virt_to_dma(deq_state->new_deq_seg, deq_state->new_deq_ptr),  			deq_state->new_cycle_state); -	queue_set_tr_deq(xhci, slot_id, ep_index, stream_id, +	queue_set_tr_deq(xhci, cmd, slot_id, ep_index, stream_id,  			deq_state->new_deq_seg,  			deq_state->new_deq_ptr,  			(u32) deq_state->new_cycle_state); @@ -716,7 +643,7 @@ static void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci,  /* Must be called with xhci->lock held in interrupt context */  static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci, -		struct xhci_td *cur_td, int status, char *adjective) +		struct xhci_td *cur_td, int status)  {  	struct usb_hcd *hcd;  	struct urb	*urb; @@ -755,12 +682,10 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,   *  2. Otherwise, we turn all the TRBs in the TD into No-op TRBs (with the chain   *     bit cleared) so that the HW will skip over them.   */ -static void handle_stopped_endpoint(struct xhci_hcd *xhci, +static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id,  		union xhci_trb *trb, struct xhci_event_cmd *event)  { -	unsigned int slot_id;  	unsigned int ep_index; -	struct xhci_virt_device *virt_dev;  	struct xhci_ring *ep_ring;  	struct xhci_virt_ep *ep;  	struct list_head *entry; @@ -769,15 +694,8 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,  	struct xhci_dequeue_state deq_state; -	if (unlikely(TRB_TO_SUSPEND_PORT( -			     le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])))) { -		slot_id = TRB_TO_SLOT_ID( -			le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])); -		virt_dev = xhci->devs[slot_id]; -		if (virt_dev) -			handle_cmd_in_cmd_wait_list(xhci, virt_dev, -				event); -		else +	if (unlikely(TRB_TO_SUSPEND_PORT(le32_to_cpu(trb->generic.field[3])))) { +		if (!xhci->devs[slot_id])  			xhci_warn(xhci, "Stop endpoint command "  				"completion for disabled slot %u\n",  				slot_id); @@ -785,14 +703,12 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,  	}  	memset(&deq_state, 0, sizeof(deq_state)); -	slot_id = TRB_TO_SLOT_ID(le32_to_cpu(trb->generic.field[3]));  	ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3]));  	ep = &xhci->devs[slot_id]->eps[ep_index];  	if (list_empty(&ep->cancelled_td_list)) {  		xhci_stop_watchdog_timer_in_irq(xhci, ep);  		ep->stopped_td = NULL; -		ep->stopped_trb = NULL;  		ring_doorbell_for_active_rings(xhci, slot_id, ep_index);  		return;  	} @@ -850,7 +766,9 @@ remove_finished_td:  	/* If necessary, queue a Set Transfer Ring Dequeue Pointer command */  	if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { -		xhci_queue_new_dequeue_state(xhci, +		struct xhci_command *command; +		command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); +		xhci_queue_new_dequeue_state(xhci, command,  				slot_id, ep_index,  				ep->stopped_td->urb->stream_id,  				&deq_state); @@ -859,8 +777,10 @@ remove_finished_td:  		/* Otherwise ring the doorbell(s) to restart queued transfers */  		ring_doorbell_for_active_rings(xhci, slot_id, ep_index);  	} -	ep->stopped_td = NULL; -	ep->stopped_trb = NULL; + +	/* Clear stopped_td if endpoint is not halted */ +	if (!(ep->ep_state & EP_HALTED)) +		ep->stopped_td = NULL;  	/*  	 * Drop the lock and complete the URBs in the cancelled TD list. @@ -877,7 +797,7 @@ remove_finished_td:  		/* Doesn't matter what we pass for status, since the core will  		 * just overwrite it (because the URB has been unlinked).  		 */ -		xhci_giveback_urb_in_irq(xhci, cur_td, 0, "cancelled"); +		xhci_giveback_urb_in_irq(xhci, cur_td, 0);  		/* Stop processing the cancelled list if the watchdog timer is  		 * running. @@ -889,6 +809,57 @@ remove_finished_td:  	/* Return to the event handler with xhci->lock re-acquired */  } +static void xhci_kill_ring_urbs(struct xhci_hcd *xhci, struct xhci_ring *ring) +{ +	struct xhci_td *cur_td; + +	while (!list_empty(&ring->td_list)) { +		cur_td = list_first_entry(&ring->td_list, +				struct xhci_td, td_list); +		list_del_init(&cur_td->td_list); +		if (!list_empty(&cur_td->cancelled_td_list)) +			list_del_init(&cur_td->cancelled_td_list); +		xhci_giveback_urb_in_irq(xhci, cur_td, -ESHUTDOWN); +	} +} + +static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, +		int slot_id, int ep_index) +{ +	struct xhci_td *cur_td; +	struct xhci_virt_ep *ep; +	struct xhci_ring *ring; + +	ep = &xhci->devs[slot_id]->eps[ep_index]; +	if ((ep->ep_state & EP_HAS_STREAMS) || +			(ep->ep_state & EP_GETTING_NO_STREAMS)) { +		int stream_id; + +		for (stream_id = 0; stream_id < ep->stream_info->num_streams; +				stream_id++) { +			xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, +					"Killing URBs for slot ID %u, ep index %u, stream %u", +					slot_id, ep_index, stream_id + 1); +			xhci_kill_ring_urbs(xhci, +					ep->stream_info->stream_rings[stream_id]); +		} +	} else { +		ring = ep->ring; +		if (!ring) +			return; +		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, +				"Killing URBs for slot ID %u, ep index %u", +				slot_id, ep_index); +		xhci_kill_ring_urbs(xhci, ring); +	} +	while (!list_empty(&ep->cancelled_td_list)) { +		cur_td = list_first_entry(&ep->cancelled_td_list, +				struct xhci_td, cancelled_td_list); +		list_del_init(&cur_td->cancelled_td_list); +		xhci_giveback_urb_in_irq(xhci, cur_td, -ESHUTDOWN); +	} +} +  /* Watchdog timer function for when a stop endpoint command fails to complete.   * In this case, we assume the host controller is broken or dying or dead.  The   * host may still be completing some other events, so we have to be careful to @@ -912,9 +883,6 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)  {  	struct xhci_hcd *xhci;  	struct xhci_virt_ep *ep; -	struct xhci_virt_ep *temp_ep; -	struct xhci_ring *ring; -	struct xhci_td *cur_td;  	int ret, i, j;  	unsigned long flags; @@ -971,34 +939,8 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)  	for (i = 0; i < MAX_HC_SLOTS; i++) {  		if (!xhci->devs[i])  			continue; -		for (j = 0; j < 31; j++) { -			temp_ep = &xhci->devs[i]->eps[j]; -			ring = temp_ep->ring; -			if (!ring) -				continue; -			xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, -					"Killing URBs for slot ID %u, " -					"ep index %u", i, j); -			while (!list_empty(&ring->td_list)) { -				cur_td = list_first_entry(&ring->td_list, -						struct xhci_td, -						td_list); -				list_del_init(&cur_td->td_list); -				if (!list_empty(&cur_td->cancelled_td_list)) -					list_del_init(&cur_td->cancelled_td_list); -				xhci_giveback_urb_in_irq(xhci, cur_td, -						-ESHUTDOWN, "killed"); -			} -			while (!list_empty(&temp_ep->cancelled_td_list)) { -				cur_td = list_first_entry( -						&temp_ep->cancelled_td_list, -						struct xhci_td, -						cancelled_td_list); -				list_del_init(&cur_td->cancelled_td_list); -				xhci_giveback_urb_in_irq(xhci, cur_td, -						-ESHUTDOWN, "killed"); -			} -		} +		for (j = 0; j < 31; j++) +			xhci_kill_endpoint_urbs(xhci, i, j);  	}  	spin_unlock_irqrestore(&xhci->lock, flags);  	xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, @@ -1063,27 +1005,25 @@ static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,   * endpoint doorbell to restart the ring, but only if there aren't more   * cancellations pending.   */ -static void handle_set_deq_completion(struct xhci_hcd *xhci, -		struct xhci_event_cmd *event, -		union xhci_trb *trb) +static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, +		union xhci_trb *trb, u32 cmd_comp_code)  { -	unsigned int slot_id;  	unsigned int ep_index;  	unsigned int stream_id;  	struct xhci_ring *ep_ring;  	struct xhci_virt_device *dev; +	struct xhci_virt_ep *ep;  	struct xhci_ep_ctx *ep_ctx;  	struct xhci_slot_ctx *slot_ctx; -	slot_id = TRB_TO_SLOT_ID(le32_to_cpu(trb->generic.field[3]));  	ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3]));  	stream_id = TRB_TO_STREAM_ID(le32_to_cpu(trb->generic.field[2]));  	dev = xhci->devs[slot_id]; +	ep = &dev->eps[ep_index];  	ep_ring = xhci_stream_id_to_ring(dev, ep_index, stream_id);  	if (!ep_ring) { -		xhci_warn(xhci, "WARN Set TR deq ptr command for " -				"freed stream ID %u\n", +		xhci_warn(xhci, "WARN Set TR deq ptr command for freed stream ID %u\n",  				stream_id);  		/* XXX: Harmless??? */  		dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING; @@ -1093,18 +1033,16 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,  	ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);  	slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx); -	if (GET_COMP_CODE(le32_to_cpu(event->status)) != COMP_SUCCESS) { +	if (cmd_comp_code != COMP_SUCCESS) {  		unsigned int ep_state;  		unsigned int slot_state; -		switch (GET_COMP_CODE(le32_to_cpu(event->status))) { +		switch (cmd_comp_code) {  		case COMP_TRB_ERR: -			xhci_warn(xhci, "WARN Set TR Deq Ptr cmd invalid because " -					"of stream ID configuration\n"); +			xhci_warn(xhci, "WARN Set TR Deq Ptr cmd invalid because of stream ID configuration\n");  			break;  		case COMP_CTX_STATE: -			xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due " -					"to incorrect slot or ep state.\n"); +			xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due to incorrect slot or ep state.\n");  			ep_state = le32_to_cpu(ep_ctx->ep_info);  			ep_state &= EP_STATE_MASK;  			slot_state = le32_to_cpu(slot_ctx->dev_state); @@ -1114,13 +1052,12 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,  					slot_state, ep_state);  			break;  		case COMP_EBADSLT: -			xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed because " -					"slot %u was not enabled.\n", slot_id); +			xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed because slot %u was not enabled.\n", +					slot_id);  			break;  		default: -			xhci_warn(xhci, "WARN Set TR Deq Ptr cmd with unknown " -					"completion code of %u.\n", -				  GET_COMP_CODE(le32_to_cpu(event->status))); +			xhci_warn(xhci, "WARN Set TR Deq Ptr cmd with unknown completion code of %u.\n", +					cmd_comp_code);  			break;  		}  		/* OK what do we do now?  The endpoint state is hosed, and we @@ -1130,23 +1067,28 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,  		 * cancelling URBs, which might not be an error...  		 */  	} else { +		u64 deq; +		/* 4.6.10 deq ptr is written to the stream ctx for streams */ +		if (ep->ep_state & EP_HAS_STREAMS) { +			struct xhci_stream_ctx *ctx = +				&ep->stream_info->stream_ctx_array[stream_id]; +			deq = le64_to_cpu(ctx->stream_ring) & SCTX_DEQ_MASK; +		} else { +			deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK; +		}  		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, -			"Successful Set TR Deq Ptr cmd, deq = @%08llx", -			 le64_to_cpu(ep_ctx->deq)); -		if (xhci_trb_virt_to_dma(dev->eps[ep_index].queued_deq_seg, -					 dev->eps[ep_index].queued_deq_ptr) == -		    (le64_to_cpu(ep_ctx->deq) & ~(EP_CTX_CYCLE_MASK))) { +			"Successful Set TR Deq Ptr cmd, deq = @%08llx", deq); +		if (xhci_trb_virt_to_dma(ep->queued_deq_seg, +					 ep->queued_deq_ptr) == deq) {  			/* Update the ring's dequeue segment and dequeue pointer  			 * to reflect the new position.  			 */  			update_ring_for_set_deq_completion(xhci, dev,  				ep_ring, ep_index);  		} else { -			xhci_warn(xhci, "Mismatch between completed Set TR Deq " -					"Ptr command & xHCI internal state.\n"); +			xhci_warn(xhci, "Mismatch between completed Set TR Deq Ptr command & xHCI internal state.\n");  			xhci_warn(xhci, "ep deq seg = %p, deq ptr = %p\n", -					dev->eps[ep_index].queued_deq_seg, -					dev->eps[ep_index].queued_deq_ptr); +				  ep->queued_deq_seg, ep->queued_deq_ptr);  		}  	} @@ -1157,30 +1099,28 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,  	ring_doorbell_for_active_rings(xhci, slot_id, ep_index);  } -static void handle_reset_ep_completion(struct xhci_hcd *xhci, -		struct xhci_event_cmd *event, -		union xhci_trb *trb) +static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id, +		union xhci_trb *trb, u32 cmd_comp_code)  { -	int slot_id;  	unsigned int ep_index; -	slot_id = TRB_TO_SLOT_ID(le32_to_cpu(trb->generic.field[3]));  	ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3]));  	/* This command will only fail if the endpoint wasn't halted,  	 * but we don't care.  	 */  	xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, -		"Ignoring reset ep completion code of %u", -		 GET_COMP_CODE(le32_to_cpu(event->status))); +		"Ignoring reset ep completion code of %u", cmd_comp_code);  	/* HW with the reset endpoint quirk needs to have a configure endpoint  	 * command complete before the endpoint can be used.  Queue that here  	 * because the HW can't handle two commands being queued in a row.  	 */  	if (xhci->quirks & XHCI_RESET_EP_QUIRK) { +		struct xhci_command *command; +		command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC);  		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks,  				"Queueing configure endpoint command"); -		xhci_queue_configure_endpoint(xhci, +		xhci_queue_configure_endpoint(xhci, command,  				xhci->devs[slot_id]->in_ctx->dma, slot_id,  				false);  		xhci_ring_cmd_db(xhci); @@ -1191,185 +1131,211 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci,  	}  } -/* Complete the command and detele it from the devcie's command queue. - */ -static void xhci_complete_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, -		struct xhci_command *command, u32 status) +static void xhci_handle_cmd_enable_slot(struct xhci_hcd *xhci, int slot_id, +		u32 cmd_comp_code)  { -	command->status = status; -	list_del(&command->cmd_list); -	if (command->completion) -		complete(command->completion); +	if (cmd_comp_code == COMP_SUCCESS) +		xhci->slot_id = slot_id;  	else -		xhci_free_command(xhci, command); +		xhci->slot_id = 0;  } - -/* Check to see if a command in the device's command queue matches this one. - * Signal the completion or free the command, and return 1.  Return 0 if the - * completed command isn't at the head of the command list. - */ -static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci, -		struct xhci_virt_device *virt_dev, -		struct xhci_event_cmd *event) +static void xhci_handle_cmd_disable_slot(struct xhci_hcd *xhci, int slot_id)  { -	struct xhci_command *command; - -	if (list_empty(&virt_dev->cmd_list)) -		return 0; - -	command = list_entry(virt_dev->cmd_list.next, -			struct xhci_command, cmd_list); -	if (xhci->cmd_ring->dequeue != command->command_trb) -		return 0; +	struct xhci_virt_device *virt_dev; -	xhci_complete_cmd_in_cmd_wait_list(xhci, command, -			GET_COMP_CODE(le32_to_cpu(event->status))); -	return 1; +	virt_dev = xhci->devs[slot_id]; +	if (!virt_dev) +		return; +	if (xhci->quirks & XHCI_EP_LIMIT_QUIRK) +		/* Delete default control endpoint resources */ +		xhci_free_device_endpoint_resources(xhci, virt_dev, true); +	xhci_free_virt_device(xhci, slot_id);  } -/* - * Finding the command trb need to be cancelled and modifying it to - * NO OP command. And if the command is in device's command wait - * list, finishing and freeing it. - * - * If we can't find the command trb, we think it had already been - * executed. - */ -static void xhci_cmd_to_noop(struct xhci_hcd *xhci, struct xhci_cd *cur_cd) +static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id, +		struct xhci_event_cmd *event, u32 cmd_comp_code)  { -	struct xhci_segment *cur_seg; -	union xhci_trb *cmd_trb; -	u32 cycle_state; - -	if (xhci->cmd_ring->dequeue == xhci->cmd_ring->enqueue) -		return; +	struct xhci_virt_device *virt_dev; +	struct xhci_input_control_ctx *ctrl_ctx; +	unsigned int ep_index; +	unsigned int ep_state; +	u32 add_flags, drop_flags; -	/* find the current segment of command ring */ -	cur_seg = find_trb_seg(xhci->cmd_ring->first_seg, -			xhci->cmd_ring->dequeue, &cycle_state); - -	if (!cur_seg) { -		xhci_warn(xhci, "Command ring mismatch, dequeue = %p %llx (dma)\n", -				xhci->cmd_ring->dequeue, -				(unsigned long long) -				xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, -					xhci->cmd_ring->dequeue)); -		xhci_debug_ring(xhci, xhci->cmd_ring); -		xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); +	/* +	 * Configure endpoint commands can come from the USB core +	 * configuration or alt setting changes, or because the HW +	 * needed an extra configure endpoint command after a reset +	 * endpoint command or streams were being configured. +	 * If the command was for a halted endpoint, the xHCI driver +	 * is not waiting on the configure endpoint command. +	 */ +	virt_dev = xhci->devs[slot_id]; +	ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); +	if (!ctrl_ctx) { +		xhci_warn(xhci, "Could not get input context, bad type.\n");  		return;  	} -	/* find the command trb matched by cd from command ring */ -	for (cmd_trb = xhci->cmd_ring->dequeue; -			cmd_trb != xhci->cmd_ring->enqueue; -			next_trb(xhci, xhci->cmd_ring, &cur_seg, &cmd_trb)) { -		/* If the trb is link trb, continue */ -		if (TRB_TYPE_LINK_LE32(cmd_trb->generic.field[3])) -			continue; - -		if (cur_cd->cmd_trb == cmd_trb) { +	add_flags = le32_to_cpu(ctrl_ctx->add_flags); +	drop_flags = le32_to_cpu(ctrl_ctx->drop_flags); +	/* Input ctx add_flags are the endpoint index plus one */ +	ep_index = xhci_last_valid_endpoint(add_flags) - 1; -			/* If the command in device's command list, we should -			 * finish it and free the command structure. -			 */ -			if (cur_cd->command) -				xhci_complete_cmd_in_cmd_wait_list(xhci, -					cur_cd->command, COMP_CMD_STOP); - -			/* get cycle state from the origin command trb */ -			cycle_state = le32_to_cpu(cmd_trb->generic.field[3]) -				& TRB_CYCLE; - -			/* modify the command trb to NO OP command */ -			cmd_trb->generic.field[0] = 0; -			cmd_trb->generic.field[1] = 0; -			cmd_trb->generic.field[2] = 0; -			cmd_trb->generic.field[3] = cpu_to_le32( -					TRB_TYPE(TRB_CMD_NOOP) | cycle_state); -			break; -		} +	/* A usb_set_interface() call directly after clearing a halted +	 * condition may race on this quirky hardware.  Not worth +	 * worrying about, since this is prototype hardware.  Not sure +	 * if this will work for streams, but streams support was +	 * untested on this prototype. +	 */ +	if (xhci->quirks & XHCI_RESET_EP_QUIRK && +			ep_index != (unsigned int) -1 && +			add_flags - SLOT_FLAG == drop_flags) { +		ep_state = virt_dev->eps[ep_index].ep_state; +		if (!(ep_state & EP_HALTED)) +			return; +		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, +				"Completed config ep cmd - " +				"last ep index = %d, state = %d", +				ep_index, ep_state); +		/* Clear internal halted state and restart ring(s) */ +		virt_dev->eps[ep_index].ep_state &= ~EP_HALTED; +		ring_doorbell_for_active_rings(xhci, slot_id, ep_index); +		return;  	} +	return;  } -static void xhci_cancel_cmd_in_cd_list(struct xhci_hcd *xhci) +static void xhci_handle_cmd_reset_dev(struct xhci_hcd *xhci, int slot_id, +		struct xhci_event_cmd *event)  { -	struct xhci_cd *cur_cd, *next_cd; +	xhci_dbg(xhci, "Completed reset device command.\n"); +	if (!xhci->devs[slot_id]) +		xhci_warn(xhci, "Reset device command completion " +				"for disabled slot %u\n", slot_id); +} -	if (list_empty(&xhci->cancel_cmd_list)) +static void xhci_handle_cmd_nec_get_fw(struct xhci_hcd *xhci, +		struct xhci_event_cmd *event) +{ +	if (!(xhci->quirks & XHCI_NEC_HOST)) { +		xhci->error_bitmask |= 1 << 6;  		return; - -	list_for_each_entry_safe(cur_cd, next_cd, -			&xhci->cancel_cmd_list, cancel_cmd_list) { -		xhci_cmd_to_noop(xhci, cur_cd); -		list_del(&cur_cd->cancel_cmd_list); -		kfree(cur_cd);  	} +	xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, +			"NEC firmware version %2x.%02x", +			NEC_FW_MAJOR(le32_to_cpu(event->status)), +			NEC_FW_MINOR(le32_to_cpu(event->status)));  } -/* - * traversing the cancel_cmd_list. If the command descriptor according - * to cmd_trb is found, the function free it and return 1, otherwise - * return 0. - */ -static int xhci_search_cmd_trb_in_cd_list(struct xhci_hcd *xhci, -		union xhci_trb *cmd_trb) +static void xhci_complete_del_and_free_cmd(struct xhci_command *cmd, u32 status)  { -	struct xhci_cd *cur_cd, *next_cd; - -	if (list_empty(&xhci->cancel_cmd_list)) -		return 0; +	list_del(&cmd->cmd_list); -	list_for_each_entry_safe(cur_cd, next_cd, -			&xhci->cancel_cmd_list, cancel_cmd_list) { -		if (cur_cd->cmd_trb == cmd_trb) { -			if (cur_cd->command) -				xhci_complete_cmd_in_cmd_wait_list(xhci, -					cur_cd->command, COMP_CMD_STOP); -			list_del(&cur_cd->cancel_cmd_list); -			kfree(cur_cd); -			return 1; -		} +	if (cmd->completion) { +		cmd->status = status; +		complete(cmd->completion); +	} else { +		kfree(cmd);  	} +} -	return 0; +void xhci_cleanup_command_queue(struct xhci_hcd *xhci) +{ +	struct xhci_command *cur_cmd, *tmp_cmd; +	list_for_each_entry_safe(cur_cmd, tmp_cmd, &xhci->cmd_list, cmd_list) +		xhci_complete_del_and_free_cmd(cur_cmd, COMP_CMD_ABORT);  }  /* - * If the cmd_trb_comp_code is COMP_CMD_ABORT, we just check whether the - * trb pointed by the command ring dequeue pointer is the trb we want to - * cancel or not. And if the cmd_trb_comp_code is COMP_CMD_STOP, we will - * traverse the cancel_cmd_list to trun the all of the commands according - * to command descriptor to NO-OP trb. + * Turn all commands on command ring with status set to "aborted" to no-op trbs. + * If there are other commands waiting then restart the ring and kick the timer. + * This must be called with command ring stopped and xhci->lock held.   */ -static int handle_stopped_cmd_ring(struct xhci_hcd *xhci, -		int cmd_trb_comp_code) +static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci, +					 struct xhci_command *cur_cmd)  { -	int cur_trb_is_good = 0; +	struct xhci_command *i_cmd, *tmp_cmd; +	u32 cycle_state; -	/* Searching the cmd trb pointed by the command ring dequeue -	 * pointer in command descriptor list. If it is found, free it. -	 */ -	cur_trb_is_good = xhci_search_cmd_trb_in_cd_list(xhci, -			xhci->cmd_ring->dequeue); +	/* Turn all aborted commands in list to no-ops, then restart */ +	list_for_each_entry_safe(i_cmd, tmp_cmd, &xhci->cmd_list, +				 cmd_list) { -	if (cmd_trb_comp_code == COMP_CMD_ABORT) -		xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; -	else if (cmd_trb_comp_code == COMP_CMD_STOP) { -		/* traversing the cancel_cmd_list and canceling -		 * the command according to command descriptor -		 */ -		xhci_cancel_cmd_in_cd_list(xhci); +		if (i_cmd->status != COMP_CMD_ABORT) +			continue; + +		i_cmd->status = COMP_CMD_STOP; + +		xhci_dbg(xhci, "Turn aborted command %p to no-op\n", +			 i_cmd->command_trb); +		/* get cycle state from the original cmd trb */ +		cycle_state = le32_to_cpu( +			i_cmd->command_trb->generic.field[3]) &	TRB_CYCLE; +		/* modify the command trb to no-op command */ +		i_cmd->command_trb->generic.field[0] = 0; +		i_cmd->command_trb->generic.field[1] = 0; +		i_cmd->command_trb->generic.field[2] = 0; +		i_cmd->command_trb->generic.field[3] = cpu_to_le32( +			TRB_TYPE(TRB_CMD_NOOP) | cycle_state); -		xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;  		/* -		 * ring command ring doorbell again to restart the -		 * command ring +		 * caller waiting for completion is called when command +		 *  completion event is received for these no-op commands  		 */ -		if (xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) -			xhci_ring_cmd_db(xhci);  	} -	return cur_trb_is_good; + +	xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; + +	/* ring command ring doorbell to restart the command ring */ +	if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) && +	    !(xhci->xhc_state & XHCI_STATE_DYING)) { +		xhci->current_cmd = cur_cmd; +		mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT); +		xhci_ring_cmd_db(xhci); +	} +	return; +} + + +void xhci_handle_command_timeout(unsigned long data) +{ +	struct xhci_hcd *xhci; +	int ret; +	unsigned long flags; +	u64 hw_ring_state; +	struct xhci_command *cur_cmd = NULL; +	xhci = (struct xhci_hcd *) data; + +	/* mark this command to be cancelled */ +	spin_lock_irqsave(&xhci->lock, flags); +	if (xhci->current_cmd) { +		cur_cmd = xhci->current_cmd; +		cur_cmd->status = COMP_CMD_ABORT; +	} + + +	/* Make sure command ring is running before aborting it */ +	hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); +	if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) && +	    (hw_ring_state & CMD_RING_RUNNING))  { + +		spin_unlock_irqrestore(&xhci->lock, flags); +		xhci_dbg(xhci, "Command timeout\n"); +		ret = xhci_abort_cmd_ring(xhci); +		if (unlikely(ret == -ESHUTDOWN)) { +			xhci_err(xhci, "Abort command ring failed\n"); +			xhci_cleanup_command_queue(xhci); +			usb_hc_died(xhci_to_hcd(xhci)->primary_hcd); +			xhci_dbg(xhci, "xHCI host controller is dead.\n"); +		} +		return; +	} +	/* command timeout on stopped ring, ring can't be aborted */ +	xhci_dbg(xhci, "Command timeout on stopped ring\n"); +	xhci_handle_stopped_cmd_ring(xhci, xhci->current_cmd); +	spin_unlock_irqrestore(&xhci->lock, flags); +	return;  }  static void handle_cmd_completion(struct xhci_hcd *xhci, @@ -1378,15 +1344,15 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,  	int slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags));  	u64 cmd_dma;  	dma_addr_t cmd_dequeue_dma; -	struct xhci_input_control_ctx *ctrl_ctx; -	struct xhci_virt_device *virt_dev; -	unsigned int ep_index; -	struct xhci_ring *ep_ring; -	unsigned int ep_state; +	u32 cmd_comp_code; +	union xhci_trb *cmd_trb; +	struct xhci_command *cmd; +	u32 cmd_type;  	cmd_dma = le64_to_cpu(event->cmd_trb); +	cmd_trb = xhci->cmd_ring->dequeue;  	cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, -			xhci->cmd_ring->dequeue); +			cmd_trb);  	/* Is the command ring deq ptr out of sync with the deq seg ptr? */  	if (cmd_dequeue_dma == 0) {  		xhci->error_bitmask |= 1 << 4; @@ -1398,141 +1364,101 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,  		return;  	} -	trace_xhci_cmd_completion(&xhci->cmd_ring->dequeue->generic, -					(struct xhci_generic_trb *) event); +	cmd = list_entry(xhci->cmd_list.next, struct xhci_command, cmd_list); -	if ((GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_ABORT) || -		(GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_CMD_STOP)) { -		/* If the return value is 0, we think the trb pointed by -		 * command ring dequeue pointer is a good trb. The good -		 * trb means we don't want to cancel the trb, but it have -		 * been stopped by host. So we should handle it normally. -		 * Otherwise, driver should invoke inc_deq() and return. -		 */ -		if (handle_stopped_cmd_ring(xhci, -				GET_COMP_CODE(le32_to_cpu(event->status)))) { -			inc_deq(xhci, xhci->cmd_ring); -			return; -		} +	if (cmd->command_trb != xhci->cmd_ring->dequeue) { +		xhci_err(xhci, +			 "Command completion event does not match command\n"); +		return;  	} -	switch (le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3]) -		& TRB_TYPE_BITMASK) { -	case TRB_TYPE(TRB_ENABLE_SLOT): -		if (GET_COMP_CODE(le32_to_cpu(event->status)) == COMP_SUCCESS) -			xhci->slot_id = slot_id; -		else -			xhci->slot_id = 0; -		complete(&xhci->addr_dev); +	del_timer(&xhci->cmd_timer); + +	trace_xhci_cmd_completion(cmd_trb, (struct xhci_generic_trb *) event); + +	cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status)); + +	/* If CMD ring stopped we own the trbs between enqueue and dequeue */ +	if (cmd_comp_code == COMP_CMD_STOP) { +		xhci_handle_stopped_cmd_ring(xhci, cmd); +		return; +	} +	/* +	 * Host aborted the command ring, check if the current command was +	 * supposed to be aborted, otherwise continue normally. +	 * The command ring is stopped now, but the xHC will issue a Command +	 * Ring Stopped event which will cause us to restart it. +	 */ +	if (cmd_comp_code == COMP_CMD_ABORT) { +		xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; +		if (cmd->status == COMP_CMD_ABORT) +			goto event_handled; +	} + +	cmd_type = TRB_FIELD_TO_TYPE(le32_to_cpu(cmd_trb->generic.field[3])); +	switch (cmd_type) { +	case TRB_ENABLE_SLOT: +		xhci_handle_cmd_enable_slot(xhci, slot_id, cmd_comp_code);  		break; -	case TRB_TYPE(TRB_DISABLE_SLOT): -		if (xhci->devs[slot_id]) { -			if (xhci->quirks & XHCI_EP_LIMIT_QUIRK) -				/* Delete default control endpoint resources */ -				xhci_free_device_endpoint_resources(xhci, -						xhci->devs[slot_id], true); -			xhci_free_virt_device(xhci, slot_id); -		} +	case TRB_DISABLE_SLOT: +		xhci_handle_cmd_disable_slot(xhci, slot_id);  		break; -	case TRB_TYPE(TRB_CONFIG_EP): -		virt_dev = xhci->devs[slot_id]; -		if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event)) -			break; -		/* -		 * Configure endpoint commands can come from the USB core -		 * configuration or alt setting changes, or because the HW -		 * needed an extra configure endpoint command after a reset -		 * endpoint command or streams were being configured. -		 * If the command was for a halted endpoint, the xHCI driver -		 * is not waiting on the configure endpoint command. -		 */ -		ctrl_ctx = xhci_get_input_control_ctx(xhci, -				virt_dev->in_ctx); -		if (!ctrl_ctx) { -			xhci_warn(xhci, "Could not get input context, bad type.\n"); -			break; -		} -		/* Input ctx add_flags are the endpoint index plus one */ -		ep_index = xhci_last_valid_endpoint(le32_to_cpu(ctrl_ctx->add_flags)) - 1; -		/* A usb_set_interface() call directly after clearing a halted -		 * condition may race on this quirky hardware.  Not worth -		 * worrying about, since this is prototype hardware.  Not sure -		 * if this will work for streams, but streams support was -		 * untested on this prototype. -		 */ -		if (xhci->quirks & XHCI_RESET_EP_QUIRK && -				ep_index != (unsigned int) -1 && -		    le32_to_cpu(ctrl_ctx->add_flags) - SLOT_FLAG == -		    le32_to_cpu(ctrl_ctx->drop_flags)) { -			ep_ring = xhci->devs[slot_id]->eps[ep_index].ring; -			ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; -			if (!(ep_state & EP_HALTED)) -				goto bandwidth_change; -			xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, -					"Completed config ep cmd - " -					"last ep index = %d, state = %d", -					ep_index, ep_state); -			/* Clear internal halted state and restart ring(s) */ -			xhci->devs[slot_id]->eps[ep_index].ep_state &= -				~EP_HALTED; -			ring_doorbell_for_active_rings(xhci, slot_id, ep_index); -			break; -		} -bandwidth_change: -		xhci_dbg_trace(xhci,  trace_xhci_dbg_context_change, -				"Completed config ep cmd"); -		xhci->devs[slot_id]->cmd_status = -			GET_COMP_CODE(le32_to_cpu(event->status)); -		complete(&xhci->devs[slot_id]->cmd_completion); +	case TRB_CONFIG_EP: +		if (!cmd->completion) +			xhci_handle_cmd_config_ep(xhci, slot_id, event, +						  cmd_comp_code);  		break; -	case TRB_TYPE(TRB_EVAL_CONTEXT): -		virt_dev = xhci->devs[slot_id]; -		if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event)) -			break; -		xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(le32_to_cpu(event->status)); -		complete(&xhci->devs[slot_id]->cmd_completion); +	case TRB_EVAL_CONTEXT:  		break; -	case TRB_TYPE(TRB_ADDR_DEV): -		xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(le32_to_cpu(event->status)); -		complete(&xhci->addr_dev); +	case TRB_ADDR_DEV:  		break; -	case TRB_TYPE(TRB_STOP_RING): -		handle_stopped_endpoint(xhci, xhci->cmd_ring->dequeue, event); +	case TRB_STOP_RING: +		WARN_ON(slot_id != TRB_TO_SLOT_ID( +				le32_to_cpu(cmd_trb->generic.field[3]))); +		xhci_handle_cmd_stop_ep(xhci, slot_id, cmd_trb, event);  		break; -	case TRB_TYPE(TRB_SET_DEQ): -		handle_set_deq_completion(xhci, event, xhci->cmd_ring->dequeue); +	case TRB_SET_DEQ: +		WARN_ON(slot_id != TRB_TO_SLOT_ID( +				le32_to_cpu(cmd_trb->generic.field[3]))); +		xhci_handle_cmd_set_deq(xhci, slot_id, cmd_trb, cmd_comp_code);  		break; -	case TRB_TYPE(TRB_CMD_NOOP): +	case TRB_CMD_NOOP: +		/* Is this an aborted command turned to NO-OP? */ +		if (cmd->status == COMP_CMD_STOP) +			cmd_comp_code = COMP_CMD_STOP;  		break; -	case TRB_TYPE(TRB_RESET_EP): -		handle_reset_ep_completion(xhci, event, xhci->cmd_ring->dequeue); +	case TRB_RESET_EP: +		WARN_ON(slot_id != TRB_TO_SLOT_ID( +				le32_to_cpu(cmd_trb->generic.field[3]))); +		xhci_handle_cmd_reset_ep(xhci, slot_id, cmd_trb, cmd_comp_code);  		break; -	case TRB_TYPE(TRB_RESET_DEV): -		xhci_dbg(xhci, "Completed reset device command.\n"); +	case TRB_RESET_DEV: +		/* SLOT_ID field in reset device cmd completion event TRB is 0. +		 * Use the SLOT_ID from the command TRB instead (xhci 4.6.11) +		 */  		slot_id = TRB_TO_SLOT_ID( -			le32_to_cpu(xhci->cmd_ring->dequeue->generic.field[3])); -		virt_dev = xhci->devs[slot_id]; -		if (virt_dev) -			handle_cmd_in_cmd_wait_list(xhci, virt_dev, event); -		else -			xhci_warn(xhci, "Reset device command completion " -					"for disabled slot %u\n", slot_id); +				le32_to_cpu(cmd_trb->generic.field[3])); +		xhci_handle_cmd_reset_dev(xhci, slot_id, event);  		break; -	case TRB_TYPE(TRB_NEC_GET_FW): -		if (!(xhci->quirks & XHCI_NEC_HOST)) { -			xhci->error_bitmask |= 1 << 6; -			break; -		} -		xhci_dbg_trace(xhci, trace_xhci_dbg_quirks, -			"NEC firmware version %2x.%02x", -			 NEC_FW_MAJOR(le32_to_cpu(event->status)), -			 NEC_FW_MINOR(le32_to_cpu(event->status))); +	case TRB_NEC_GET_FW: +		xhci_handle_cmd_nec_get_fw(xhci, event);  		break;  	default:  		/* Skip over unknown commands on the event ring */  		xhci->error_bitmask |= 1 << 6;  		break;  	} + +	/* restart timer if this wasn't the last command */ +	if (cmd->cmd_list.next != &xhci->cmd_list) { +		xhci->current_cmd = list_entry(cmd->cmd_list.next, +					       struct xhci_command, cmd_list); +		mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT); +	} + +event_handled: +	xhci_complete_del_and_free_cmd(cmd, cmd_comp_code); +  	inc_deq(xhci, xhci->cmd_ring);  } @@ -1591,7 +1517,7 @@ static void handle_device_notification(struct xhci_hcd *xhci,  	u32 slot_id;  	struct usb_device *udev; -	slot_id = TRB_TO_SLOT_ID(event->generic.field[3]); +	slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->generic.field[3]));  	if (!xhci->devs[slot_id]) {  		xhci_warn(xhci, "Device Notification event for "  				"unused slot %u\n", slot_id); @@ -1675,7 +1601,7 @@ static void handle_port_status(struct xhci_hcd *xhci,  	faked_port_index = find_faked_portnum_from_hw_portnum(hcd, xhci,  			port_id); -	temp = xhci_readl(xhci, port_array[faked_port_index]); +	temp = readl(port_array[faked_port_index]);  	if (hcd->state == HC_STATE_SUSPENDED) {  		xhci_dbg(xhci, "resume root hub\n");  		usb_hcd_resume_root_hub(hcd); @@ -1684,7 +1610,7 @@ static void handle_port_status(struct xhci_hcd *xhci,  	if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) {  		xhci_dbg(xhci, "port resume event for port %d\n", port_id); -		temp1 = xhci_readl(xhci, &xhci->op_regs->command); +		temp1 = readl(&xhci->op_regs->command);  		if (!(temp1 & CMD_RUN)) {  			xhci_warn(xhci, "xHC is not running.\n");  			goto cleanup; @@ -1743,6 +1669,19 @@ static void handle_port_status(struct xhci_hcd *xhci,  		}  	} +	/* +	 * Check to see if xhci-hub.c is waiting on RExit to U0 transition (or +	 * RExit to a disconnect state).  If so, let the the driver know it's +	 * out of the RExit state. +	 */ +	if (!DEV_SUPERSPEED(temp) && +			test_and_clear_bit(faked_port_index, +				&bus_state->rexit_ports)) { +		complete(&bus_state->rexit_done[faked_port_index]); +		bogus_port_status = true; +		goto cleanup; +	} +  	if (hcd->speed != HCD_USB3)  		xhci_test_and_clear_bit(xhci, port_array, faked_port_index,  					PORT_PLC); @@ -1835,16 +1774,19 @@ static void xhci_cleanup_halted_endpoint(struct xhci_hcd *xhci,  		struct xhci_td *td, union xhci_trb *event_trb)  {  	struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index]; +	struct xhci_command *command; +	command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); +	if (!command) +		return; +  	ep->ep_state |= EP_HALTED;  	ep->stopped_td = td; -	ep->stopped_trb = event_trb;  	ep->stopped_stream = stream_id; -	xhci_queue_reset_ep(xhci, slot_id, ep_index); +	xhci_queue_reset_ep(xhci, command, slot_id, ep_index);  	xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index);  	ep->stopped_td = NULL; -	ep->stopped_trb = NULL;  	ep->stopped_stream = 0;  	xhci_ring_cmd_db(xhci); @@ -1926,7 +1868,6 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,  		 * the ring dequeue pointer or take this TD off any lists yet.  		 */  		ep->stopped_td = td; -		ep->stopped_trb = event_trb;  		return 0;  	} else {  		if (trb_comp_code == COMP_STALL) { @@ -1938,7 +1879,6 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,  			 * USB class driver clear the stall later.  			 */  			ep->stopped_td = td; -			ep->stopped_trb = event_trb;  			ep->stopped_stream = ep_ring->stream_id;  		} else if (xhci_requires_manual_halt_cleanup(xhci,  					ep_ctx, trb_comp_code)) { @@ -2555,7 +2495,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,  				 * successful event after a short transfer.  				 * Ignore it.  				 */ -				if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) &&  +				if ((xhci->quirks & XHCI_SPURIOUS_SUCCESS) &&  						ep_ring->last_td_was_short) {  					ep_ring->last_td_was_short = false;  					ret = 0; @@ -2754,7 +2694,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)  	spin_lock(&xhci->lock);  	/* Check if the xHC generated the interrupt, or the irq is shared */ -	status = xhci_readl(xhci, &xhci->op_regs->status); +	status = readl(&xhci->op_regs->status);  	if (status == 0xffffffff)  		goto hw_died; @@ -2776,16 +2716,16 @@ hw_died:  	 * Write 1 to clear the interrupt status.  	 */  	status |= STS_EINT; -	xhci_writel(xhci, status, &xhci->op_regs->status); +	writel(status, &xhci->op_regs->status);  	/* FIXME when MSI-X is supported and there are multiple vectors */  	/* Clear the MSI-X event interrupt status */  	if (hcd->irq) {  		u32 irq_pending;  		/* Acknowledge the PCI interrupt */ -		irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending); +		irq_pending = readl(&xhci->ir_set->irq_pending);  		irq_pending |= IMAN_IP; -		xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending); +		writel(irq_pending, &xhci->ir_set->irq_pending);  	}  	if (xhci->xhc_state & XHCI_STATE_DYING) { @@ -3597,7 +3537,7 @@ static unsigned int xhci_get_burst_count(struct xhci_hcd *xhci,  		return 0;  	max_burst = urb->ep->ss_ep_comp.bMaxBurst; -	return roundup(total_packet_count, max_burst + 1) - 1; +	return DIV_ROUND_UP(total_packet_count, max_burst + 1) - 1;  }  /* @@ -3854,7 +3794,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,  	if (ret)  		return ret; -	start_frame = xhci_readl(xhci, &xhci->run_regs->microframe_index); +	start_frame = readl(&xhci->run_regs->microframe_index);  	start_frame &= 0x3fff;  	urb->start_frame = start_frame; @@ -3897,11 +3837,14 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,   * Don't decrement xhci->cmd_ring_reserved_trbs after we've queued the TRB   * because the command event handler may want to resubmit a failed command.   */ -static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, -		u32 field3, u32 field4, bool command_must_succeed) +static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd, +			 u32 field1, u32 field2, +			 u32 field3, u32 field4, bool command_must_succeed)  {  	int reserved_trbs = xhci->cmd_ring_reserved_trbs;  	int ret; +	if (xhci->xhc_state & XHCI_STATE_DYING) +		return -ESHUTDOWN;  	if (!command_must_succeed)  		reserved_trbs++; @@ -3915,57 +3858,71 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2,  					"unfailable commands failed.\n");  		return ret;  	} + +	cmd->command_trb = xhci->cmd_ring->enqueue; +	list_add_tail(&cmd->cmd_list, &xhci->cmd_list); + +	/* if there are no other commands queued we start the timeout timer */ +	if (xhci->cmd_list.next == &cmd->cmd_list && +	    !timer_pending(&xhci->cmd_timer)) { +		xhci->current_cmd = cmd; +		mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT); +	} +  	queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3,  			field4 | xhci->cmd_ring->cycle_state);  	return 0;  }  /* Queue a slot enable or disable request on the command ring */ -int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id) +int xhci_queue_slot_control(struct xhci_hcd *xhci, struct xhci_command *cmd, +		u32 trb_type, u32 slot_id)  { -	return queue_command(xhci, 0, 0, 0, +	return queue_command(xhci, cmd, 0, 0, 0,  			TRB_TYPE(trb_type) | SLOT_ID_FOR_TRB(slot_id), false);  }  /* Queue an address device command TRB */ -int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, -		u32 slot_id) +int xhci_queue_address_device(struct xhci_hcd *xhci, struct xhci_command *cmd, +		dma_addr_t in_ctx_ptr, u32 slot_id, enum xhci_setup_dev setup)  { -	return queue_command(xhci, lower_32_bits(in_ctx_ptr), +	return queue_command(xhci, cmd, lower_32_bits(in_ctx_ptr),  			upper_32_bits(in_ctx_ptr), 0, -			TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id), -			false); +			TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id) +			| (setup == SETUP_CONTEXT_ONLY ? TRB_BSR : 0), false);  } -int xhci_queue_vendor_command(struct xhci_hcd *xhci, +int xhci_queue_vendor_command(struct xhci_hcd *xhci, struct xhci_command *cmd,  		u32 field1, u32 field2, u32 field3, u32 field4)  { -	return queue_command(xhci, field1, field2, field3, field4, false); +	return queue_command(xhci, cmd, field1, field2, field3, field4, false);  }  /* Queue a reset device command TRB */ -int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id) +int xhci_queue_reset_device(struct xhci_hcd *xhci, struct xhci_command *cmd, +		u32 slot_id)  { -	return queue_command(xhci, 0, 0, 0, +	return queue_command(xhci, cmd, 0, 0, 0,  			TRB_TYPE(TRB_RESET_DEV) | SLOT_ID_FOR_TRB(slot_id),  			false);  }  /* Queue a configure endpoint command TRB */ -int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, +int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, +		struct xhci_command *cmd, dma_addr_t in_ctx_ptr,  		u32 slot_id, bool command_must_succeed)  { -	return queue_command(xhci, lower_32_bits(in_ctx_ptr), +	return queue_command(xhci, cmd, lower_32_bits(in_ctx_ptr),  			upper_32_bits(in_ctx_ptr), 0,  			TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id),  			command_must_succeed);  }  /* Queue an evaluate context command TRB */ -int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, -		u32 slot_id, bool command_must_succeed) +int xhci_queue_evaluate_context(struct xhci_hcd *xhci, struct xhci_command *cmd, +		dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed)  { -	return queue_command(xhci, lower_32_bits(in_ctx_ptr), +	return queue_command(xhci, cmd, lower_32_bits(in_ctx_ptr),  			upper_32_bits(in_ctx_ptr), 0,  			TRB_TYPE(TRB_EVAL_CONTEXT) | SLOT_ID_FOR_TRB(slot_id),  			command_must_succeed); @@ -3975,30 +3932,32 @@ int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,   * Suspend is set to indicate "Stop Endpoint Command" is being issued to stop   * activity on an endpoint that is about to be suspended.   */ -int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, -		unsigned int ep_index, int suspend) +int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, struct xhci_command *cmd, +			     int slot_id, unsigned int ep_index, int suspend)  {  	u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);  	u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);  	u32 type = TRB_TYPE(TRB_STOP_RING);  	u32 trb_suspend = SUSPEND_PORT_FOR_TRB(suspend); -	return queue_command(xhci, 0, 0, 0, +	return queue_command(xhci, cmd, 0, 0, 0,  			trb_slot_id | trb_ep_index | type | trb_suspend, false);  }  /* Set Transfer Ring Dequeue Pointer command.   * This should not be used for endpoints that have streams enabled.   */ -static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id, -		unsigned int ep_index, unsigned int stream_id, -		struct xhci_segment *deq_seg, -		union xhci_trb *deq_ptr, u32 cycle_state) +static int queue_set_tr_deq(struct xhci_hcd *xhci, struct xhci_command *cmd, +			int slot_id, +			unsigned int ep_index, unsigned int stream_id, +			struct xhci_segment *deq_seg, +			union xhci_trb *deq_ptr, u32 cycle_state)  {  	dma_addr_t addr;  	u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);  	u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);  	u32 trb_stream_id = STREAM_ID_FOR_TRB(stream_id); +	u32 trb_sct = 0;  	u32 type = TRB_TYPE(TRB_SET_DEQ);  	struct xhci_virt_ep *ep; @@ -4017,18 +3976,21 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,  	}  	ep->queued_deq_seg = deq_seg;  	ep->queued_deq_ptr = deq_ptr; -	return queue_command(xhci, lower_32_bits(addr) | cycle_state, +	if (stream_id) +		trb_sct = SCT_FOR_TRB(SCT_PRI_TR); +	return queue_command(xhci, cmd, +			lower_32_bits(addr) | trb_sct | cycle_state,  			upper_32_bits(addr), trb_stream_id,  			trb_slot_id | trb_ep_index | type, false);  } -int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, -		unsigned int ep_index) +int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd, +			int slot_id, unsigned int ep_index)  {  	u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);  	u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);  	u32 type = TRB_TYPE(TRB_RESET_EP); -	return queue_command(xhci, 0, 0, 0, trb_slot_id | trb_ep_index | type, -			false); +	return queue_command(xhci, cmd, 0, 0, 0, +			trb_slot_id | trb_ep_index | type, false);  } diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index 20364cc8d2f..dde3959b7a3 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -116,12 +116,12 @@ DECLARE_EVENT_CLASS(xhci_log_event,  		__field(u64, dma)  		__field(u32, status)  		__field(u32, flags) -		__dynamic_array(__le32, trb, 4) +		__dynamic_array(u8, trb, sizeof(struct xhci_generic_trb))  	),  	TP_fast_assign(  		__entry->va = trb_va; -		__entry->dma = le64_to_cpu(((u64)ev->field[1]) << 32 | -						ev->field[0]); +		__entry->dma = ((u64)le32_to_cpu(ev->field[1])) << 32 | +					le32_to_cpu(ev->field[0]);  		__entry->status = le32_to_cpu(ev->field[2]);  		__entry->flags = le32_to_cpu(ev->field[3]);  		memcpy(__get_dynamic_array(trb), trb_va, diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 49b6edb84a7..7436d5f5e67 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -40,6 +40,10 @@ static int link_quirk;  module_param(link_quirk, int, S_IRUGO | S_IWUSR);  MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB"); +static unsigned int quirks; +module_param(quirks, uint, S_IRUGO); +MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default"); +  /* TODO: copied from ehci-hcd.c - can this be refactored? */  /*   * xhci_handshake - spin reading hc until handshake completes or fails @@ -60,7 +64,7 @@ int xhci_handshake(struct xhci_hcd *xhci, void __iomem *ptr,  	u32	result;  	do { -		result = xhci_readl(xhci, ptr); +		result = readl(ptr);  		if (result == ~(u32)0)		/* card removed */  			return -ENODEV;  		result &= mask; @@ -82,13 +86,13 @@ void xhci_quiesce(struct xhci_hcd *xhci)  	u32 mask;  	mask = ~(XHCI_IRQS); -	halted = xhci_readl(xhci, &xhci->op_regs->status) & STS_HALT; +	halted = readl(&xhci->op_regs->status) & STS_HALT;  	if (!halted)  		mask &= ~CMD_RUN; -	cmd = xhci_readl(xhci, &xhci->op_regs->command); +	cmd = readl(&xhci->op_regs->command);  	cmd &= mask; -	xhci_writel(xhci, cmd, &xhci->op_regs->command); +	writel(cmd, &xhci->op_regs->command);  }  /* @@ -124,11 +128,11 @@ static int xhci_start(struct xhci_hcd *xhci)  	u32 temp;  	int ret; -	temp = xhci_readl(xhci, &xhci->op_regs->command); +	temp = readl(&xhci->op_regs->command);  	temp |= (CMD_RUN);  	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Turn on HC, cmd = 0x%x.",  			temp); -	xhci_writel(xhci, temp, &xhci->op_regs->command); +	writel(temp, &xhci->op_regs->command);  	/*  	 * Wait for the HCHalted Status bit to be 0 to indicate the host is @@ -158,16 +162,16 @@ int xhci_reset(struct xhci_hcd *xhci)  	u32 state;  	int ret, i; -	state = xhci_readl(xhci, &xhci->op_regs->status); +	state = readl(&xhci->op_regs->status);  	if ((state & STS_HALT) == 0) {  		xhci_warn(xhci, "Host controller not halted, aborting reset.\n");  		return 0;  	}  	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Reset the HC"); -	command = xhci_readl(xhci, &xhci->op_regs->command); +	command = readl(&xhci->op_regs->command);  	command |= CMD_RESET; -	xhci_writel(xhci, command, &xhci->op_regs->command); +	writel(command, &xhci->op_regs->command);  	ret = xhci_handshake(xhci, &xhci->op_regs->command,  			CMD_RESET, 0, 10 * 1000 * 1000); @@ -287,7 +291,7 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)  		xhci->msix_entries[i].vector = 0;  	} -	ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count); +	ret = pci_enable_msix_exact(pdev, xhci->msix_entries, xhci->msix_count);  	if (ret) {  		xhci_dbg_trace(xhci, trace_xhci_dbg_init,  				"Failed to enable MSI-X"); @@ -321,6 +325,9 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci)  	struct usb_hcd *hcd = xhci_to_hcd(xhci);  	struct pci_dev *pdev = to_pci_dev(hcd->self.controller); +	if (xhci->quirks & XHCI_PLAT) +		return; +  	xhci_free_irq(xhci);  	if (xhci->msix_entries) { @@ -383,6 +390,10 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)  	}   legacy_irq: +	if (!strlen(hcd->irq_descr)) +		snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", +			 hcd->driver->description, hcd->self.busnum); +  	/* fall back to legacy interrupt*/  	ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,  			hcd->irq_descr, hcd); @@ -397,16 +408,16 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)  #else -static int xhci_try_enable_msi(struct usb_hcd *hcd) +static inline int xhci_try_enable_msi(struct usb_hcd *hcd)  {  	return 0;  } -static void xhci_cleanup_msix(struct xhci_hcd *xhci) +static inline void xhci_cleanup_msix(struct xhci_hcd *xhci)  {  } -static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) +static inline void xhci_msix_sync_irqs(struct xhci_hcd *xhci)  {  } @@ -422,7 +433,7 @@ static void compliance_mode_recovery(unsigned long arg)  	xhci = (struct xhci_hcd *)arg;  	for (i = 0; i < xhci->num_usb3_ports; i++) { -		temp = xhci_readl(xhci, xhci->usb3_ports[i]); +		temp = readl(xhci->usb3_ports[i]);  		if ((temp & PORT_PLS_MASK) == USB_SS_PORT_LS_COMP_MOD) {  			/*  			 * Compliance Mode Detected. Letting USB Core @@ -611,30 +622,33 @@ int xhci_run(struct usb_hcd *hcd)  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"// Set the interrupt modulation register"); -	temp = xhci_readl(xhci, &xhci->ir_set->irq_control); +	temp = readl(&xhci->ir_set->irq_control);  	temp &= ~ER_IRQ_INTERVAL_MASK;  	temp |= (u32) 160; -	xhci_writel(xhci, temp, &xhci->ir_set->irq_control); +	writel(temp, &xhci->ir_set->irq_control);  	/* Set the HCD state before we enable the irqs */ -	temp = xhci_readl(xhci, &xhci->op_regs->command); +	temp = readl(&xhci->op_regs->command);  	temp |= (CMD_EIE);  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"// Enable interrupts, cmd = 0x%x.", temp); -	xhci_writel(xhci, temp, &xhci->op_regs->command); +	writel(temp, &xhci->op_regs->command); -	temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); +	temp = readl(&xhci->ir_set->irq_pending);  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"// Enabling event ring interrupter %p by writing 0x%x to irq_pending",  			xhci->ir_set, (unsigned int) ER_IRQ_ENABLE(temp)); -	xhci_writel(xhci, ER_IRQ_ENABLE(temp), -			&xhci->ir_set->irq_pending); +	writel(ER_IRQ_ENABLE(temp), &xhci->ir_set->irq_pending);  	xhci_print_ir_set(xhci, 0); -	if (xhci->quirks & XHCI_NEC_HOST) -		xhci_queue_vendor_command(xhci, 0, 0, 0, +	if (xhci->quirks & XHCI_NEC_HOST) { +		struct xhci_command *command; +		command = xhci_alloc_command(xhci, false, false, GFP_KERNEL); +		if (!command) +			return -ENOMEM; +		xhci_queue_vendor_command(xhci, command, 0, 0, 0,  				TRB_TYPE(TRB_NEC_GET_FW)); - +	}  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"Finished xhci_run for USB2 roothub");  	return 0; @@ -698,18 +712,17 @@ void xhci_stop(struct usb_hcd *hcd)  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"// Disabling event ring interrupts"); -	temp = xhci_readl(xhci, &xhci->op_regs->status); -	xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status); -	temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); -	xhci_writel(xhci, ER_IRQ_DISABLE(temp), -			&xhci->ir_set->irq_pending); +	temp = readl(&xhci->op_regs->status); +	writel(temp & ~STS_EINT, &xhci->op_regs->status); +	temp = readl(&xhci->ir_set->irq_pending); +	writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);  	xhci_print_ir_set(xhci, 0);  	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");  	xhci_mem_cleanup(xhci);  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"xhci_stop completed - status = %x", -			xhci_readl(xhci, &xhci->op_regs->status)); +			readl(&xhci->op_regs->status));  }  /* @@ -730,40 +743,47 @@ void xhci_shutdown(struct usb_hcd *hcd)  	spin_lock_irq(&xhci->lock);  	xhci_halt(xhci); +	/* Workaround for spurious wakeups at shutdown with HSW */ +	if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) +		xhci_reset(xhci);  	spin_unlock_irq(&xhci->lock);  	xhci_cleanup_msix(xhci);  	xhci_dbg_trace(xhci, trace_xhci_dbg_init,  			"xhci_shutdown completed - status = %x", -			xhci_readl(xhci, &xhci->op_regs->status)); +			readl(&xhci->op_regs->status)); + +	/* Yet another workaround for spurious wakeups at shutdown with HSW */ +	if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) +		pci_set_power_state(to_pci_dev(hcd->self.controller), PCI_D3hot);  }  #ifdef CONFIG_PM  static void xhci_save_registers(struct xhci_hcd *xhci)  { -	xhci->s3.command = xhci_readl(xhci, &xhci->op_regs->command); -	xhci->s3.dev_nt = xhci_readl(xhci, &xhci->op_regs->dev_notification); +	xhci->s3.command = readl(&xhci->op_regs->command); +	xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification);  	xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); -	xhci->s3.config_reg = xhci_readl(xhci, &xhci->op_regs->config_reg); -	xhci->s3.erst_size = xhci_readl(xhci, &xhci->ir_set->erst_size); +	xhci->s3.config_reg = readl(&xhci->op_regs->config_reg); +	xhci->s3.erst_size = readl(&xhci->ir_set->erst_size);  	xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);  	xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); -	xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending); -	xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control); +	xhci->s3.irq_pending = readl(&xhci->ir_set->irq_pending); +	xhci->s3.irq_control = readl(&xhci->ir_set->irq_control);  }  static void xhci_restore_registers(struct xhci_hcd *xhci)  { -	xhci_writel(xhci, xhci->s3.command, &xhci->op_regs->command); -	xhci_writel(xhci, xhci->s3.dev_nt, &xhci->op_regs->dev_notification); +	writel(xhci->s3.command, &xhci->op_regs->command); +	writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification);  	xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr); -	xhci_writel(xhci, xhci->s3.config_reg, &xhci->op_regs->config_reg); -	xhci_writel(xhci, xhci->s3.erst_size, &xhci->ir_set->erst_size); +	writel(xhci->s3.config_reg, &xhci->op_regs->config_reg); +	writel(xhci->s3.erst_size, &xhci->ir_set->erst_size);  	xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);  	xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue); -	xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending); -	xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control); +	writel(xhci->s3.irq_pending, &xhci->ir_set->irq_pending); +	writel(xhci->s3.irq_control, &xhci->ir_set->irq_control);  }  static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) @@ -839,6 +859,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)  int xhci_suspend(struct xhci_hcd *xhci)  {  	int			rc = 0; +	unsigned int		delay = XHCI_MAX_HALT_USEC;  	struct usb_hcd		*hcd = xhci_to_hcd(xhci);  	u32			command; @@ -858,11 +879,15 @@ int xhci_suspend(struct xhci_hcd *xhci)  	/* skipped assuming that port suspend has done */  	/* step 2: clear Run/Stop bit */ -	command = xhci_readl(xhci, &xhci->op_regs->command); +	command = readl(&xhci->op_regs->command);  	command &= ~CMD_RUN; -	xhci_writel(xhci, command, &xhci->op_regs->command); +	writel(command, &xhci->op_regs->command); + +	/* Some chips from Fresco Logic need an extraordinary delay */ +	delay *= (xhci->quirks & XHCI_SLOW_SUSPEND) ? 10 : 1; +  	if (xhci_handshake(xhci, &xhci->op_regs->status, -		      STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC)) { +		      STS_HALT, STS_HALT, delay)) {  		xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n");  		spin_unlock_irq(&xhci->lock);  		return -ETIMEDOUT; @@ -873,9 +898,9 @@ int xhci_suspend(struct xhci_hcd *xhci)  	xhci_save_registers(xhci);  	/* step 4: set CSS flag */ -	command = xhci_readl(xhci, &xhci->op_regs->command); +	command = readl(&xhci->op_regs->command);  	command |= CMD_CSS; -	xhci_writel(xhci, command, &xhci->op_regs->command); +	writel(command, &xhci->op_regs->command);  	if (xhci_handshake(xhci, &xhci->op_regs->status,  				STS_SAVE, 0, 10 * 1000)) {  		xhci_warn(xhci, "WARN: xHC save state timeout\n"); @@ -911,7 +936,7 @@ int xhci_suspend(struct xhci_hcd *xhci)   */  int xhci_resume(struct xhci_hcd *xhci, bool hibernated)  { -	u32			command, temp = 0; +	u32			command, temp = 0, status;  	struct usb_hcd		*hcd = xhci_to_hcd(xhci);  	struct usb_hcd		*secondary_hcd;  	int			retval = 0; @@ -939,16 +964,16 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)  		xhci_set_cmd_ring_deq(xhci);  		/* step 3: restore state and start state*/  		/* step 3: set CRS flag */ -		command = xhci_readl(xhci, &xhci->op_regs->command); +		command = readl(&xhci->op_regs->command);  		command |= CMD_CRS; -		xhci_writel(xhci, command, &xhci->op_regs->command); +		writel(command, &xhci->op_regs->command);  		if (xhci_handshake(xhci, &xhci->op_regs->status,  			      STS_RESTORE, 0, 10 * 1000)) {  			xhci_warn(xhci, "WARN: xHC restore state timeout\n");  			spin_unlock_irq(&xhci->lock);  			return -ETIMEDOUT;  		} -		temp = xhci_readl(xhci, &xhci->op_regs->status); +		temp = readl(&xhci->op_regs->status);  	}  	/* If restore operation fails, re-initialize the HC during resume */ @@ -972,17 +997,16 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)  		xhci_cleanup_msix(xhci);  		xhci_dbg(xhci, "// Disabling event ring interrupts\n"); -		temp = xhci_readl(xhci, &xhci->op_regs->status); -		xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status); -		temp = xhci_readl(xhci, &xhci->ir_set->irq_pending); -		xhci_writel(xhci, ER_IRQ_DISABLE(temp), -				&xhci->ir_set->irq_pending); +		temp = readl(&xhci->op_regs->status); +		writel(temp & ~STS_EINT, &xhci->op_regs->status); +		temp = readl(&xhci->ir_set->irq_pending); +		writel(ER_IRQ_DISABLE(temp), &xhci->ir_set->irq_pending);  		xhci_print_ir_set(xhci, 0);  		xhci_dbg(xhci, "cleaning up memory\n");  		xhci_mem_cleanup(xhci);  		xhci_dbg(xhci, "xhci_stop completed - status = %x\n", -			    xhci_readl(xhci, &xhci->op_regs->status)); +			    readl(&xhci->op_regs->status));  		/* USB core calls the PCI reinit and start functions twice:  		 * first with the primary HCD, and then with the secondary HCD. @@ -1011,9 +1035,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)  	}  	/* step 4: set Run/Stop bit */ -	command = xhci_readl(xhci, &xhci->op_regs->command); +	command = readl(&xhci->op_regs->command);  	command |= CMD_RUN; -	xhci_writel(xhci, command, &xhci->op_regs->command); +	writel(command, &xhci->op_regs->command);  	xhci_handshake(xhci, &xhci->op_regs->status, STS_HALT,  		  0, 250 * 1000); @@ -1030,8 +1054,12 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)   done:  	if (retval == 0) { -		usb_hcd_resume_root_hub(hcd); -		usb_hcd_resume_root_hub(xhci->shared_hcd); +		/* Resume root hubs only when have pending events. */ +		status = readl(&xhci->op_regs->status); +		if (status & STS_EINT) { +			usb_hcd_resume_root_hub(hcd); +			usb_hcd_resume_root_hub(xhci->shared_hcd); +		}  	}  	/* @@ -1167,10 +1195,10 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,  static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,  		unsigned int ep_index, struct urb *urb)  { -	struct xhci_container_ctx *in_ctx;  	struct xhci_container_ctx *out_ctx;  	struct xhci_input_control_ctx *ctrl_ctx;  	struct xhci_ep_ctx *ep_ctx; +	struct xhci_command *command;  	int max_packet_size;  	int hw_max_packet_size;  	int ret = 0; @@ -1195,18 +1223,24 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,  		/* FIXME: This won't work if a non-default control endpoint  		 * changes max packet sizes.  		 */ -		in_ctx = xhci->devs[slot_id]->in_ctx; -		ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); + +		command = xhci_alloc_command(xhci, false, true, GFP_KERNEL); +		if (!command) +			return -ENOMEM; + +		command->in_ctx = xhci->devs[slot_id]->in_ctx; +		ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);  		if (!ctrl_ctx) {  			xhci_warn(xhci, "%s: Could not get input context, bad type.\n",  					__func__); -			return -ENOMEM; +			ret = -ENOMEM; +			goto command_cleanup;  		}  		/* Set up the modified control endpoint 0 */  		xhci_endpoint_copy(xhci, xhci->devs[slot_id]->in_ctx,  				xhci->devs[slot_id]->out_ctx, ep_index); -		ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index); +		ep_ctx = xhci_get_ep_ctx(xhci, command->in_ctx, ep_index);  		ep_ctx->ep_info2 &= cpu_to_le32(~MAX_PACKET_MASK);  		ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet_size)); @@ -1214,17 +1248,20 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,  		ctrl_ctx->drop_flags = 0;  		xhci_dbg(xhci, "Slot %d input context\n", slot_id); -		xhci_dbg_ctx(xhci, in_ctx, ep_index); +		xhci_dbg_ctx(xhci, command->in_ctx, ep_index);  		xhci_dbg(xhci, "Slot %d output context\n", slot_id);  		xhci_dbg_ctx(xhci, out_ctx, ep_index); -		ret = xhci_configure_endpoint(xhci, urb->dev, NULL, +		ret = xhci_configure_endpoint(xhci, urb->dev, command,  				true, false);  		/* Clean up the input context for later use by bandwidth  		 * functions.  		 */  		ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG); +command_cleanup: +		kfree(command->completion); +		kfree(command);  	}  	return ret;  } @@ -1445,6 +1482,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  	unsigned int ep_index;  	struct xhci_ring *ep_ring;  	struct xhci_virt_ep *ep; +	struct xhci_command *command;  	xhci = hcd_to_xhci(hcd);  	spin_lock_irqsave(&xhci->lock, flags); @@ -1452,7 +1490,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  	ret = usb_hcd_check_unlink_urb(hcd, urb, status);  	if (ret || !urb->hcpriv)  		goto done; -	temp = xhci_readl(xhci, &xhci->op_regs->status); +	temp = readl(&xhci->op_regs->status);  	if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {  		xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb,  				"HW died, freeing TD."); @@ -1514,12 +1552,14 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)  	 * the first cancellation to be handled.  	 */  	if (!(ep->ep_state & EP_HALT_PENDING)) { +		command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC);  		ep->ep_state |= EP_HALT_PENDING;  		ep->stop_cmds_pending++;  		ep->stop_cmd_timer.expires = jiffies +  			XHCI_STOP_EP_CMD_TIMEOUT * HZ;  		add_timer(&ep->stop_cmd_timer); -		xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index, 0); +		xhci_queue_stop_endpoint(xhci, command, urb->dev->slot_id, +					 ep_index, 0);  		xhci_ring_cmd_db(xhci);  	}  done: @@ -1784,6 +1824,11 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,  	int ret;  	switch (*cmd_status) { +	case COMP_CMD_ABORT: +	case COMP_CMD_STOP: +		xhci_warn(xhci, "Timeout while waiting for configure endpoint command\n"); +		ret = -ETIME; +		break;  	case COMP_ENOMEM:  		dev_warn(&udev->dev, "Not enough host controller resources "  				"for new device state.\n"); @@ -1830,6 +1875,11 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci,  	struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id];  	switch (*cmd_status) { +	case COMP_CMD_ABORT: +	case COMP_CMD_STOP: +		xhci_warn(xhci, "Timeout while waiting for evaluate context command\n"); +		ret = -ETIME; +		break;  	case COMP_EINVAL:  		dev_warn(&udev->dev, "WARN: xHCI driver setup invalid evaluate "  				"context command.\n"); @@ -1880,8 +1930,8 @@ static u32 xhci_count_num_new_endpoints(struct xhci_hcd *xhci,  	 * (bit 1).  The default control endpoint is added during the Address  	 * Device command and is never removed until the slot is disabled.  	 */ -	valid_add_flags = ctrl_ctx->add_flags >> 2; -	valid_drop_flags = ctrl_ctx->drop_flags >> 2; +	valid_add_flags = le32_to_cpu(ctrl_ctx->add_flags) >> 2; +	valid_drop_flags = le32_to_cpu(ctrl_ctx->drop_flags) >> 2;  	/* Use hweight32 to count the number of ones in the add flags, or  	 * number of endpoints added.  Don't count endpoints that are changed @@ -1897,8 +1947,8 @@ static unsigned int xhci_count_num_dropped_endpoints(struct xhci_hcd *xhci,  	u32 valid_add_flags;  	u32 valid_drop_flags; -	valid_add_flags = ctrl_ctx->add_flags >> 2; -	valid_drop_flags = ctrl_ctx->drop_flags >> 2; +	valid_add_flags = le32_to_cpu(ctrl_ctx->add_flags) >> 2; +	valid_drop_flags = le32_to_cpu(ctrl_ctx->drop_flags) >> 2;  	return hweight32(valid_drop_flags) -  		hweight32(valid_add_flags & valid_drop_flags); @@ -2554,23 +2604,17 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,  		bool ctx_change, bool must_succeed)  {  	int ret; -	int timeleft;  	unsigned long flags; -	struct xhci_container_ctx *in_ctx;  	struct xhci_input_control_ctx *ctrl_ctx; -	struct completion *cmd_completion; -	u32 *cmd_status;  	struct xhci_virt_device *virt_dev; -	union xhci_trb *cmd_trb; + +	if (!command) +		return -EINVAL;  	spin_lock_irqsave(&xhci->lock, flags);  	virt_dev = xhci->devs[udev->slot_id]; -	if (command) -		in_ctx = command->in_ctx; -	else -		in_ctx = virt_dev->in_ctx; -	ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx); +	ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);  	if (!ctrl_ctx) {  		spin_unlock_irqrestore(&xhci->lock, flags);  		xhci_warn(xhci, "%s: Could not get input context, bad type.\n", @@ -2587,7 +2631,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,  		return -ENOMEM;  	}  	if ((xhci->quirks & XHCI_SW_BW_CHECKING) && -			xhci_reserve_bandwidth(xhci, virt_dev, in_ctx)) { +	    xhci_reserve_bandwidth(xhci, virt_dev, command->in_ctx)) {  		if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK))  			xhci_free_host_resources(xhci, ctrl_ctx);  		spin_unlock_irqrestore(&xhci->lock, flags); @@ -2595,35 +2639,15 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,  		return -ENOMEM;  	} -	if (command) { -		cmd_completion = command->completion; -		cmd_status = &command->status; -		command->command_trb = xhci->cmd_ring->enqueue; - -		/* Enqueue pointer can be left pointing to the link TRB, -		 * we must handle that -		 */ -		if (TRB_TYPE_LINK_LE32(command->command_trb->link.control)) -			command->command_trb = -				xhci->cmd_ring->enq_seg->next->trbs; - -		list_add_tail(&command->cmd_list, &virt_dev->cmd_list); -	} else { -		cmd_completion = &virt_dev->cmd_completion; -		cmd_status = &virt_dev->cmd_status; -	} -	init_completion(cmd_completion); - -	cmd_trb = xhci->cmd_ring->dequeue;  	if (!ctx_change) -		ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma, +		ret = xhci_queue_configure_endpoint(xhci, command, +				command->in_ctx->dma,  				udev->slot_id, must_succeed);  	else -		ret = xhci_queue_evaluate_context(xhci, in_ctx->dma, +		ret = xhci_queue_evaluate_context(xhci, command, +				command->in_ctx->dma,  				udev->slot_id, must_succeed);  	if (ret < 0) { -		if (command) -			list_del(&command->cmd_list);  		if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK))  			xhci_free_host_resources(xhci, ctrl_ctx);  		spin_unlock_irqrestore(&xhci->lock, flags); @@ -2635,26 +2659,14 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,  	spin_unlock_irqrestore(&xhci->lock, flags);  	/* Wait for the configure endpoint command to complete */ -	timeleft = wait_for_completion_interruptible_timeout( -			cmd_completion, -			XHCI_CMD_DEFAULT_TIMEOUT); -	if (timeleft <= 0) { -		xhci_warn(xhci, "%s while waiting for %s command\n", -				timeleft == 0 ? "Timeout" : "Signal", -				ctx_change == 0 ? -					"configure endpoint" : -					"evaluate context"); -		/* cancel the configure endpoint command */ -		ret = xhci_cancel_cmd(xhci, command, cmd_trb); -		if (ret < 0) -			return ret; -		return -ETIME; -	} +	wait_for_completion(command->completion);  	if (!ctx_change) -		ret = xhci_configure_endpoint_result(xhci, udev, cmd_status); +		ret = xhci_configure_endpoint_result(xhci, udev, +						     &command->status);  	else -		ret = xhci_evaluate_context_result(xhci, udev, cmd_status); +		ret = xhci_evaluate_context_result(xhci, udev, +						   &command->status);  	if ((xhci->quirks & XHCI_EP_LIMIT_QUIRK)) {  		spin_lock_irqsave(&xhci->lock, flags); @@ -2670,6 +2682,20 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,  	return ret;  } +static void xhci_check_bw_drop_ep_streams(struct xhci_hcd *xhci, +	struct xhci_virt_device *vdev, int i) +{ +	struct xhci_virt_ep *ep = &vdev->eps[i]; + +	if (ep->ep_state & EP_HAS_STREAMS) { +		xhci_warn(xhci, "WARN: endpoint 0x%02x has streams on set_interface, freeing streams.\n", +				xhci_get_endpoint_address(i)); +		xhci_free_stream_info(xhci, ep->stream_info); +		ep->stream_info = NULL; +		ep->ep_state &= ~EP_HAS_STREAMS; +	} +} +  /* Called after one or more calls to xhci_add_endpoint() or   * xhci_drop_endpoint().  If this call fails, the USB core is expected   * to call xhci_reset_bandwidth(). @@ -2688,6 +2714,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)  	struct xhci_virt_device	*virt_dev;  	struct xhci_input_control_ctx *ctrl_ctx;  	struct xhci_slot_ctx *slot_ctx; +	struct xhci_command *command;  	ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);  	if (ret <= 0) @@ -2699,12 +2726,19 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)  	xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);  	virt_dev = xhci->devs[udev->slot_id]; +	command = xhci_alloc_command(xhci, false, true, GFP_KERNEL); +	if (!command) +		return -ENOMEM; + +	command->in_ctx = virt_dev->in_ctx; +  	/* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */ -	ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); +	ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);  	if (!ctrl_ctx) {  		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",  				__func__); -		return -ENOMEM; +		ret = -ENOMEM; +		goto command_cleanup;  	}  	ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);  	ctrl_ctx->add_flags &= cpu_to_le32(~EP0_FLAG); @@ -2712,20 +2746,20 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)  	/* Don't issue the command if there's no endpoints to update. */  	if (ctrl_ctx->add_flags == cpu_to_le32(SLOT_FLAG) && -			ctrl_ctx->drop_flags == 0) -		return 0; - +	    ctrl_ctx->drop_flags == 0) { +		ret = 0; +		goto command_cleanup; +	}  	xhci_dbg(xhci, "New Input Control Context:\n");  	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);  	xhci_dbg_ctx(xhci, virt_dev->in_ctx,  		     LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info))); -	ret = xhci_configure_endpoint(xhci, udev, NULL, +	ret = xhci_configure_endpoint(xhci, udev, command,  			false, false); -	if (ret) { +	if (ret)  		/* Callee should call reset_bandwidth() */ -		return ret; -	} +		goto command_cleanup;  	xhci_dbg(xhci, "Output context after successful config ep cmd:\n");  	xhci_dbg_ctx(xhci, virt_dev->out_ctx, @@ -2734,8 +2768,10 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)  	/* Free any rings that were dropped, but not changed. */  	for (i = 1; i < 31; ++i) {  		if ((le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1))) && -		    !(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1)))) +		    !(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1)))) {  			xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); +			xhci_check_bw_drop_ep_streams(xhci, virt_dev, i); +		}  	}  	xhci_zero_in_ctx(xhci, virt_dev);  	/* @@ -2751,9 +2787,13 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)  		if (virt_dev->eps[i].ring) {  			xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);  		} +		xhci_check_bw_drop_ep_streams(xhci, virt_dev, i);  		virt_dev->eps[i].ring = virt_dev->eps[i].new_ring;  		virt_dev->eps[i].new_ring = NULL;  	} +command_cleanup: +	kfree(command->completion); +	kfree(command);  	return ret;  } @@ -2855,9 +2895,14 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,  	 * issue a configure endpoint command later.  	 */  	if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) { +		struct xhci_command *command; +		/* Can't sleep if we're called from cleanup_halted_endpoint() */ +		command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); +		if (!command) +			return;  		xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,  				"Queueing new dequeue state"); -		xhci_queue_new_dequeue_state(xhci, udev->slot_id, +		xhci_queue_new_dequeue_state(xhci, command, udev->slot_id,  				ep_index, ep->stopped_stream, &deq_state);  	} else {  		/* Better hope no one uses the input context between now and the @@ -2888,6 +2933,7 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,  	unsigned long flags;  	int ret;  	struct xhci_virt_ep *virt_ep; +	struct xhci_command *command;  	xhci = hcd_to_xhci(hcd);  	udev = (struct usb_device *) ep->hcpriv; @@ -2910,10 +2956,14 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,  		return;  	} +	command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); +	if (!command) +		return; +  	xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep,  			"Queueing reset endpoint command");  	spin_lock_irqsave(&xhci->lock, flags); -	ret = xhci_queue_reset_ep(xhci, udev->slot_id, ep_index); +	ret = xhci_queue_reset_ep(xhci, command, udev->slot_id, ep_index);  	/*  	 * Can't change the ring dequeue pointer until it's transitioned to the  	 * stopped state, which is only upon a successful reset endpoint @@ -2925,7 +2975,6 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,  		xhci_ring_cmd_db(xhci);  	}  	virt_ep->stopped_td = NULL; -	virt_ep->stopped_trb = NULL;  	virt_ep->stopped_stream = 0;  	spin_unlock_irqrestore(&xhci->lock, flags); @@ -2946,7 +2995,7 @@ static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,  	ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, true, __func__);  	if (ret <= 0)  		return -EINVAL; -	if (ep->ss_ep_comp.bmAttributes == 0) { +	if (usb_ss_max_streams(&ep->ss_ep_comp) == 0) {  		xhci_warn(xhci, "WARN: SuperSpeed Endpoint Companion"  				" descriptor for ep 0x%x does not support streams\n",  				ep->desc.bEndpointAddress); @@ -3113,6 +3162,12 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,  	xhci_dbg(xhci, "Driver wants %u stream IDs (including stream 0).\n",  			num_streams); +	/* MaxPSASize value 0 (2 streams) means streams are not supported */ +	if (HCC_MAX_PSA(xhci->hcc_params) < 4) { +		xhci_dbg(xhci, "xHCI controller does not support streams.\n"); +		return -ENOSYS; +	} +  	config_cmd = xhci_alloc_command(xhci, true, true, mem_flags);  	if (!config_cmd) {  		xhci_dbg(xhci, "Could not allocate xHCI command structure.\n"); @@ -3382,7 +3437,6 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)  	unsigned int slot_id;  	struct xhci_virt_device *virt_dev;  	struct xhci_command *reset_device_cmd; -	int timeleft;  	int last_freed_endpoint;  	struct xhci_slot_ctx *slot_ctx;  	int old_active_eps = 0; @@ -3439,20 +3493,10 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)  	/* Attempt to submit the Reset Device command to the command ring */  	spin_lock_irqsave(&xhci->lock, flags); -	reset_device_cmd->command_trb = xhci->cmd_ring->enqueue; -	/* Enqueue pointer can be left pointing to the link TRB, -	 * we must handle that -	 */ -	if (TRB_TYPE_LINK_LE32(reset_device_cmd->command_trb->link.control)) -		reset_device_cmd->command_trb = -			xhci->cmd_ring->enq_seg->next->trbs; - -	list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list); -	ret = xhci_queue_reset_device(xhci, slot_id); +	ret = xhci_queue_reset_device(xhci, reset_device_cmd, slot_id);  	if (ret) {  		xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); -		list_del(&reset_device_cmd->cmd_list);  		spin_unlock_irqrestore(&xhci->lock, flags);  		goto command_cleanup;  	} @@ -3460,22 +3504,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)  	spin_unlock_irqrestore(&xhci->lock, flags);  	/* Wait for the Reset Device command to finish */ -	timeleft = wait_for_completion_interruptible_timeout( -			reset_device_cmd->completion, -			USB_CTRL_SET_TIMEOUT); -	if (timeleft <= 0) { -		xhci_warn(xhci, "%s while waiting for reset device command\n", -				timeleft == 0 ? "Timeout" : "Signal"); -		spin_lock_irqsave(&xhci->lock, flags); -		/* The timeout might have raced with the event ring handler, so -		 * only delete from the list if the item isn't poisoned. -		 */ -		if (reset_device_cmd->cmd_list.next != LIST_POISON1) -			list_del(&reset_device_cmd->cmd_list); -		spin_unlock_irqrestore(&xhci->lock, flags); -		ret = -ETIME; -		goto command_cleanup; -	} +	wait_for_completion(reset_device_cmd->completion);  	/* The Reset Device command can't fail, according to the 0.95/0.96 spec,  	 * unless we tried to reset a slot ID that wasn't enabled, @@ -3483,6 +3512,11 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)  	 */  	ret = reset_device_cmd->status;  	switch (ret) { +	case COMP_CMD_ABORT: +	case COMP_CMD_STOP: +		xhci_warn(xhci, "Timeout waiting for reset device command\n"); +		ret = -ETIME; +		goto command_cleanup;  	case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */  	case COMP_CTX_STATE: /* 0.96 completion code for same thing */  		xhci_dbg(xhci, "Can't reset device (slot ID %u) in %s state\n", @@ -3518,6 +3552,8 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)  		struct xhci_virt_ep *ep = &virt_dev->eps[i];  		if (ep->ep_state & EP_HAS_STREAMS) { +			xhci_warn(xhci, "WARN: endpoint 0x%02x has streams on device reset, freeing streams.\n", +					xhci_get_endpoint_address(i));  			xhci_free_stream_info(xhci, ep->stream_info);  			ep->stream_info = NULL;  			ep->ep_state &= ~EP_HAS_STREAMS; @@ -3560,6 +3596,11 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)  	unsigned long flags;  	u32 state;  	int i, ret; +	struct xhci_command *command; + +	command = xhci_alloc_command(xhci, false, false, GFP_KERNEL); +	if (!command) +		return;  #ifndef CONFIG_USB_DEFAULT_PERSIST  	/* @@ -3575,8 +3616,10 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)  	/* If the host is halted due to driver unload, we still need to free the  	 * device.  	 */ -	if (ret <= 0 && ret != -ENODEV) +	if (ret <= 0 && ret != -ENODEV) { +		kfree(command);  		return; +	}  	virt_dev = xhci->devs[udev->slot_id]; @@ -3586,28 +3629,26 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)  		del_timer_sync(&virt_dev->eps[i].stop_cmd_timer);  	} -	if (udev->usb2_hw_lpm_enabled) { -		xhci_set_usb2_hardware_lpm(hcd, udev, 0); -		udev->usb2_hw_lpm_enabled = 0; -	} -  	spin_lock_irqsave(&xhci->lock, flags);  	/* Don't disable the slot if the host controller is dead. */ -	state = xhci_readl(xhci, &xhci->op_regs->status); +	state = readl(&xhci->op_regs->status);  	if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||  			(xhci->xhc_state & XHCI_STATE_HALTED)) {  		xhci_free_virt_device(xhci, udev->slot_id);  		spin_unlock_irqrestore(&xhci->lock, flags); +		kfree(command);  		return;  	} -	if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) { +	if (xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT, +				    udev->slot_id)) {  		spin_unlock_irqrestore(&xhci->lock, flags);  		xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");  		return;  	}  	xhci_ring_cmd_db(xhci);  	spin_unlock_irqrestore(&xhci->lock, flags); +  	/*  	 * Event command completion handler will free any data structures  	 * associated with the slot.  XXX Can free sleep? @@ -3645,33 +3686,33 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)  {  	struct xhci_hcd *xhci = hcd_to_xhci(hcd);  	unsigned long flags; -	int timeleft;  	int ret; -	union xhci_trb *cmd_trb; +	struct xhci_command *command; + +	command = xhci_alloc_command(xhci, false, false, GFP_KERNEL); +	if (!command) +		return 0;  	spin_lock_irqsave(&xhci->lock, flags); -	cmd_trb = xhci->cmd_ring->dequeue; -	ret = xhci_queue_slot_control(xhci, TRB_ENABLE_SLOT, 0); +	command->completion = &xhci->addr_dev; +	ret = xhci_queue_slot_control(xhci, command, TRB_ENABLE_SLOT, 0);  	if (ret) {  		spin_unlock_irqrestore(&xhci->lock, flags);  		xhci_dbg(xhci, "FIXME: allocate a command ring segment\n"); +		kfree(command);  		return 0;  	}  	xhci_ring_cmd_db(xhci);  	spin_unlock_irqrestore(&xhci->lock, flags); -	/* XXX: how much time for xHC slot assignment? */ -	timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev, -			XHCI_CMD_DEFAULT_TIMEOUT); -	if (timeleft <= 0) { -		xhci_warn(xhci, "%s while waiting for a slot\n", -				timeleft == 0 ? "Timeout" : "Signal"); -		/* cancel the enable slot request */ -		return xhci_cancel_cmd(xhci, NULL, cmd_trb); -	} +	wait_for_completion(command->completion); -	if (!xhci->slot_id) { +	if (!xhci->slot_id || command->status != COMP_SUCCESS) {  		xhci_err(xhci, "Error while assigning device slot ID\n"); +		xhci_err(xhci, "Max number of devices this xHCI host supports is %u.\n", +				HCS_MAX_SLOTS( +					readl(&xhci->cap_regs->hcs_params1))); +		kfree(command);  		return 0;  	} @@ -3706,6 +3747,8 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)  		pm_runtime_get_noresume(hcd->self.controller);  #endif + +	kfree(command);  	/* Is this a LS or FS device under a HS hub? */  	/* Hub or peripherial? */  	return 1; @@ -3713,32 +3756,33 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev)  disable_slot:  	/* Disable slot, if we can do it without mem alloc */  	spin_lock_irqsave(&xhci->lock, flags); -	if (!xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) +	command->completion = NULL; +	command->status = 0; +	if (!xhci_queue_slot_control(xhci, command, TRB_DISABLE_SLOT, +				     udev->slot_id))  		xhci_ring_cmd_db(xhci);  	spin_unlock_irqrestore(&xhci->lock, flags);  	return 0;  }  /* - * Issue an Address Device command (which will issue a SetAddress request to - * the device). + * Issue an Address Device command and optionally send a corresponding + * SetAddress request to the device.   * We should be protected by the usb_address0_mutex in khubd's hub_port_init, so   * we should only issue and wait on one address command at the same time. - * - * We add one to the device address issued by the hardware because the USB core - * uses address 1 for the root hubs (even though they're not really devices).   */ -int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) +static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, +			     enum xhci_setup_dev setup)  { +	const char *act = setup == SETUP_CONTEXT_ONLY ? "context" : "address";  	unsigned long flags; -	int timeleft;  	struct xhci_virt_device *virt_dev;  	int ret = 0;  	struct xhci_hcd *xhci = hcd_to_xhci(hcd);  	struct xhci_slot_ctx *slot_ctx;  	struct xhci_input_control_ctx *ctrl_ctx;  	u64 temp_64; -	union xhci_trb *cmd_trb; +	struct xhci_command *command;  	if (!udev->slot_id) {  		xhci_dbg_trace(xhci, trace_xhci_dbg_address, @@ -3759,11 +3803,19 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)  		return -EINVAL;  	} +	command = xhci_alloc_command(xhci, false, false, GFP_KERNEL); +	if (!command) +		return -ENOMEM; + +	command->in_ctx = virt_dev->in_ctx; +	command->completion = &xhci->addr_dev; +  	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);  	ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);  	if (!ctrl_ctx) {  		xhci_warn(xhci, "%s: Could not get input context, bad type.\n",  				__func__); +		kfree(command);  		return -EINVAL;  	}  	/* @@ -3782,61 +3834,57 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)  	xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);  	xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);  	trace_xhci_address_ctx(xhci, virt_dev->in_ctx, -				slot_ctx->dev_info >> 27); +				le32_to_cpu(slot_ctx->dev_info) >> 27);  	spin_lock_irqsave(&xhci->lock, flags); -	cmd_trb = xhci->cmd_ring->dequeue; -	ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma, -					udev->slot_id); +	ret = xhci_queue_address_device(xhci, command, virt_dev->in_ctx->dma, +					udev->slot_id, setup);  	if (ret) {  		spin_unlock_irqrestore(&xhci->lock, flags);  		xhci_dbg_trace(xhci, trace_xhci_dbg_address,  				"FIXME: allocate a command ring segment"); +		kfree(command);  		return ret;  	}  	xhci_ring_cmd_db(xhci);  	spin_unlock_irqrestore(&xhci->lock, flags);  	/* ctrl tx can take up to 5 sec; XXX: need more time for xHC? */ -	timeleft = wait_for_completion_interruptible_timeout(&xhci->addr_dev, -			XHCI_CMD_DEFAULT_TIMEOUT); +	wait_for_completion(command->completion); +  	/* FIXME: From section 4.3.4: "Software shall be responsible for timing  	 * the SetAddress() "recovery interval" required by USB and aborting the  	 * command on a timeout.  	 */ -	if (timeleft <= 0) { -		xhci_warn(xhci, "%s while waiting for address device command\n", -				timeleft == 0 ? "Timeout" : "Signal"); -		/* cancel the address device command */ -		ret = xhci_cancel_cmd(xhci, NULL, cmd_trb); -		if (ret < 0) -			return ret; -		return -ETIME; -	} - -	switch (virt_dev->cmd_status) { +	switch (command->status) { +	case COMP_CMD_ABORT: +	case COMP_CMD_STOP: +		xhci_warn(xhci, "Timeout while waiting for setup device command\n"); +		ret = -ETIME; +		break;  	case COMP_CTX_STATE:  	case COMP_EBADSLT: -		xhci_err(xhci, "Setup ERROR: address device command for slot %d.\n", -				udev->slot_id); +		xhci_err(xhci, "Setup ERROR: setup %s command for slot %d.\n", +			 act, udev->slot_id);  		ret = -EINVAL;  		break;  	case COMP_TX_ERR: -		dev_warn(&udev->dev, "Device not responding to set address.\n"); +		dev_warn(&udev->dev, "Device not responding to setup %s.\n", act);  		ret = -EPROTO;  		break;  	case COMP_DEV_ERR: -		dev_warn(&udev->dev, "ERROR: Incompatible device for address " -				"device command.\n"); +		dev_warn(&udev->dev, +			 "ERROR: Incompatible device for setup %s command\n", act);  		ret = -ENODEV;  		break;  	case COMP_SUCCESS:  		xhci_dbg_trace(xhci, trace_xhci_dbg_address, -				"Successful Address Device command"); +			       "Successful setup %s command", act);  		break;  	default: -		xhci_err(xhci, "ERROR: unexpected command completion " -				"code 0x%x.\n", virt_dev->cmd_status); +		xhci_err(xhci, +			 "ERROR: unexpected setup %s command completion code 0x%x.\n", +			 act, command->status);  		xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);  		xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);  		trace_xhci_address_ctx(xhci, virt_dev->out_ctx, 1); @@ -3844,6 +3892,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)  		break;  	}  	if (ret) { +		kfree(command);  		return ret;  	}  	temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); @@ -3861,7 +3910,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)  	xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);  	xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);  	trace_xhci_address_ctx(xhci, virt_dev->in_ctx, -				slot_ctx->dev_info >> 27); +				le32_to_cpu(slot_ctx->dev_info) >> 27);  	xhci_dbg(xhci, "Slot ID %d Output Context:\n", udev->slot_id);  	xhci_dbg_ctx(xhci, virt_dev->out_ctx, 2);  	/* @@ -3870,21 +3919,28 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)  	 */  	slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);  	trace_xhci_address_ctx(xhci, virt_dev->out_ctx, -				slot_ctx->dev_info >> 27); -	/* Use kernel assigned address for devices; store xHC assigned -	 * address locally. */ -	virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK) -		+ 1; +				le32_to_cpu(slot_ctx->dev_info) >> 27);  	/* Zero the input context control for later use */  	ctrl_ctx->add_flags = 0;  	ctrl_ctx->drop_flags = 0;  	xhci_dbg_trace(xhci, trace_xhci_dbg_address, -			"Internal device address = %d", virt_dev->address); - +		       "Internal device address = %d", +		       le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK); +	kfree(command);  	return 0;  } +int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) +{ +	return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ADDRESS); +} + +int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev) +{ +	return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ONLY); +} +  /*   * Transfer the port index into real index in the HW port status   * registers. Caculate offset between the port's PORTSC register @@ -4028,133 +4084,6 @@ static int xhci_calculate_usb2_hw_lpm_params(struct usb_device *udev)  	return PORT_BESLD(besld) | PORT_L1_TIMEOUT(l1) | PORT_HIRDM(hirdm);  } -static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd, -					struct usb_device *udev) -{ -	struct xhci_hcd	*xhci = hcd_to_xhci(hcd); -	struct dev_info	*dev_info; -	__le32 __iomem	**port_array; -	__le32 __iomem	*addr, *pm_addr; -	u32		temp, dev_id; -	unsigned int	port_num; -	unsigned long	flags; -	int		hird; -	int		ret; - -	if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support || -			!udev->lpm_capable) -		return -EINVAL; - -	/* we only support lpm for non-hub device connected to root hub yet */ -	if (!udev->parent || udev->parent->parent || -			udev->descriptor.bDeviceClass == USB_CLASS_HUB) -		return -EINVAL; - -	spin_lock_irqsave(&xhci->lock, flags); - -	/* Look for devices in lpm_failed_devs list */ -	dev_id = le16_to_cpu(udev->descriptor.idVendor) << 16 | -			le16_to_cpu(udev->descriptor.idProduct); -	list_for_each_entry(dev_info, &xhci->lpm_failed_devs, list) { -		if (dev_info->dev_id == dev_id) { -			ret = -EINVAL; -			goto finish; -		} -	} - -	port_array = xhci->usb2_ports; -	port_num = udev->portnum - 1; - -	if (port_num > HCS_MAX_PORTS(xhci->hcs_params1)) { -		xhci_dbg(xhci, "invalid port number %d\n", udev->portnum); -		ret = -EINVAL; -		goto finish; -	} - -	/* -	 * Test USB 2.0 software LPM. -	 * FIXME: some xHCI 1.0 hosts may implement a new register to set up -	 * hardware-controlled USB 2.0 LPM. See section 5.4.11 and 4.23.5.1.1.1 -	 * in the June 2011 errata release. -	 */ -	xhci_dbg(xhci, "test port %d software LPM\n", port_num); -	/* -	 * Set L1 Device Slot and HIRD/BESL. -	 * Check device's USB 2.0 extension descriptor to determine whether -	 * HIRD or BESL shoule be used. See USB2.0 LPM errata. -	 */ -	pm_addr = port_array[port_num] + PORTPMSC; -	hird = xhci_calculate_hird_besl(xhci, udev); -	temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird); -	xhci_writel(xhci, temp, pm_addr); - -	/* Set port link state to U2(L1) */ -	addr = port_array[port_num]; -	xhci_set_link_state(xhci, port_array, port_num, XDEV_U2); - -	/* wait for ACK */ -	spin_unlock_irqrestore(&xhci->lock, flags); -	msleep(10); -	spin_lock_irqsave(&xhci->lock, flags); - -	/* Check L1 Status */ -	ret = xhci_handshake(xhci, pm_addr, -			PORT_L1S_MASK, PORT_L1S_SUCCESS, 125); -	if (ret != -ETIMEDOUT) { -		/* enter L1 successfully */ -		temp = xhci_readl(xhci, addr); -		xhci_dbg(xhci, "port %d entered L1 state, port status 0x%x\n", -				port_num, temp); -		ret = 0; -	} else { -		temp = xhci_readl(xhci, pm_addr); -		xhci_dbg(xhci, "port %d software lpm failed, L1 status %d\n", -				port_num, temp & PORT_L1S_MASK); -		ret = -EINVAL; -	} - -	/* Resume the port */ -	xhci_set_link_state(xhci, port_array, port_num, XDEV_U0); - -	spin_unlock_irqrestore(&xhci->lock, flags); -	msleep(10); -	spin_lock_irqsave(&xhci->lock, flags); - -	/* Clear PLC */ -	xhci_test_and_clear_bit(xhci, port_array, port_num, PORT_PLC); - -	/* Check PORTSC to make sure the device is in the right state */ -	if (!ret) { -		temp = xhci_readl(xhci, addr); -		xhci_dbg(xhci, "resumed port %d status 0x%x\n",	port_num, temp); -		if (!(temp & PORT_CONNECT) || !(temp & PORT_PE) || -				(temp & PORT_PLS_MASK) != XDEV_U0) { -			xhci_dbg(xhci, "port L1 resume fail\n"); -			ret = -EINVAL; -		} -	} - -	if (ret) { -		/* Insert dev to lpm_failed_devs list */ -		xhci_warn(xhci, "device LPM test failed, may disconnect and " -				"re-enumerate\n"); -		dev_info = kzalloc(sizeof(struct dev_info), GFP_ATOMIC); -		if (!dev_info) { -			ret = -ENOMEM; -			goto finish; -		} -		dev_info->dev_id = dev_id; -		INIT_LIST_HEAD(&dev_info->list); -		list_add(&dev_info->list, &xhci->lpm_failed_devs); -	} else { -		xhci_ring_device(xhci, udev->slot_id); -	} - -finish: -	spin_unlock_irqrestore(&xhci->lock, flags); -	return ret; -} -  int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,  			struct usb_device *udev, int enable)  { @@ -4183,12 +4112,12 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,  	port_array = xhci->usb2_ports;  	port_num = udev->portnum - 1;  	pm_addr = port_array[port_num] + PORTPMSC; -	pm_val = xhci_readl(xhci, pm_addr); +	pm_val = readl(pm_addr);  	hlpm_addr = port_array[port_num] + PORTHLPMC;  	field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);  	xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n", -			enable ? "enable" : "disable", port_num); +			enable ? "enable" : "disable", port_num + 1);  	if (enable) {  		/* Host supports BESL timeout instead of HIRD */ @@ -4223,26 +4152,26 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,  			spin_lock_irqsave(&xhci->lock, flags);  			hlpm_val = xhci_calculate_usb2_hw_lpm_params(udev); -			xhci_writel(xhci, hlpm_val, hlpm_addr); +			writel(hlpm_val, hlpm_addr);  			/* flush write */ -			xhci_readl(xhci, hlpm_addr); +			readl(hlpm_addr);  		} else {  			hird = xhci_calculate_hird_besl(xhci, udev);  		}  		pm_val &= ~PORT_HIRD_MASK; -		pm_val |= PORT_HIRD(hird) | PORT_RWE; -		xhci_writel(xhci, pm_val, pm_addr); -		pm_val = xhci_readl(xhci, pm_addr); +		pm_val |= PORT_HIRD(hird) | PORT_RWE | PORT_L1DS(udev->slot_id); +		writel(pm_val, pm_addr); +		pm_val = readl(pm_addr);  		pm_val |= PORT_HLE; -		xhci_writel(xhci, pm_val, pm_addr); +		writel(pm_val, pm_addr);  		/* flush write */ -		xhci_readl(xhci, pm_addr); +		readl(pm_addr);  	} else { -		pm_val &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK); -		xhci_writel(xhci, pm_val, pm_addr); +		pm_val &= ~(PORT_HLE | PORT_RWE | PORT_HIRD_MASK | PORT_L1DS_MASK); +		writel(pm_val, pm_addr);  		/* flush write */ -		xhci_readl(xhci, pm_addr); +		readl(pm_addr);  		if (udev->usb2_hw_lpm_besl_capable) {  			spin_unlock_irqrestore(&xhci->lock, flags);  			mutex_lock(hcd->bandwidth_mutex); @@ -4282,24 +4211,26 @@ static int xhci_check_usb2_port_capability(struct xhci_hcd *xhci, int port,  int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)  {  	struct xhci_hcd	*xhci = hcd_to_xhci(hcd); -	int		ret;  	int		portnum = udev->portnum - 1; -	ret = xhci_usb2_software_lpm_test(hcd, udev); -	if (!ret) { -		xhci_dbg(xhci, "software LPM test succeed\n"); -		if (xhci->hw_lpm_support == 1 && -		    xhci_check_usb2_port_capability(xhci, portnum, XHCI_HLC)) { -			udev->usb2_hw_lpm_capable = 1; -			udev->l1_params.timeout = XHCI_L1_TIMEOUT; -			udev->l1_params.besl = XHCI_DEFAULT_BESL; -			if (xhci_check_usb2_port_capability(xhci, portnum, -							    XHCI_BLC)) -				udev->usb2_hw_lpm_besl_capable = 1; -			ret = xhci_set_usb2_hardware_lpm(hcd, udev, 1); -			if (!ret) -				udev->usb2_hw_lpm_enabled = 1; -		} +	if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support || +			!udev->lpm_capable) +		return 0; + +	/* we only support lpm for non-hub device connected to root hub yet */ +	if (!udev->parent || udev->parent->parent || +			udev->descriptor.bDeviceClass == USB_CLASS_HUB) +		return 0; + +	if (xhci->hw_lpm_support == 1 && +			xhci_check_usb2_port_capability( +				xhci, portnum, XHCI_HLC)) { +		udev->usb2_hw_lpm_capable = 1; +		udev->l1_params.timeout = XHCI_L1_TIMEOUT; +		udev->l1_params.besl = XHCI_DEFAULT_BESL; +		if (xhci_check_usb2_port_capability(xhci, portnum, +					XHCI_BLC)) +			udev->usb2_hw_lpm_besl_capable = 1;  	}  	return 0; @@ -4594,7 +4525,7 @@ static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd,  	if (!config)  		return timeout; -	for (i = 0; i < USB_MAXINTERFACES; i++) { +	for (i = 0; i < config->desc.bNumInterfaces; i++) {  		struct usb_driver *driver;  		struct usb_interface *intf = config->interface[i]; @@ -4843,7 +4774,7 @@ int xhci_get_frame(struct usb_hcd *hcd)  {  	struct xhci_hcd *xhci = hcd_to_xhci(hcd);  	/* EHCI mods by the periodic size.  Why? */ -	return xhci_readl(xhci, &xhci->run_regs->microframe_index) >> 3; +	return readl(&xhci->run_regs->microframe_index) >> 3;  }  int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) @@ -4887,18 +4818,20 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)  	xhci->cap_regs = hcd->regs;  	xhci->op_regs = hcd->regs + -		HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); +		HC_LENGTH(readl(&xhci->cap_regs->hc_capbase));  	xhci->run_regs = hcd->regs + -		(xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK); +		(readl(&xhci->cap_regs->run_regs_off) & RTSOFF_MASK);  	/* Cache read-only capability registers */ -	xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); -	xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); -	xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); -	xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); +	xhci->hcs_params1 = readl(&xhci->cap_regs->hcs_params1); +	xhci->hcs_params2 = readl(&xhci->cap_regs->hcs_params2); +	xhci->hcs_params3 = readl(&xhci->cap_regs->hcs_params3); +	xhci->hcc_params = readl(&xhci->cap_regs->hc_capbase);  	xhci->hci_version = HC_VERSION(xhci->hcc_params); -	xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params); +	xhci->hcc_params = readl(&xhci->cap_regs->hcc_params);  	xhci_print_registers(xhci); +	xhci->quirks = quirks; +  	get_quirks(dev, xhci);  	/* In xhci controllers which follow xhci 1.0 spec gives a spurious diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 46aa1489414..9ffecd56600 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -383,6 +383,7 @@ struct xhci_op_regs {  #define	PORT_RWE		(1 << 3)  #define	PORT_HIRD(p)		(((p) & 0xf) << 4)  #define	PORT_HIRD_MASK		(0xf << 4) +#define	PORT_L1DS_MASK		(0xff << 8)  #define	PORT_L1DS(p)		(((p) & 0xff) << 8)  #define	PORT_HLE		(1 << 16) @@ -702,6 +703,7 @@ struct xhci_ep_ctx {  /* deq bitmasks */  #define EP_CTX_CYCLE_MASK		(1 << 0) +#define SCTX_DEQ_MASK			(~0xfL)  /** @@ -751,7 +753,7 @@ struct xhci_stream_ctx {  };  /* Stream Context Types (section 6.4.1) - bits 3:1 of stream ctx deq ptr */ -#define	SCT_FOR_CTX(p)		(((p) << 1) & 0x7) +#define	SCT_FOR_CTX(p)		(((p) & 0x7) << 1)  /* Secondary stream array type, dequeue pointer is to a transfer ring */  #define	SCT_SEC_TR		0  /* Primary stream array type, dequeue pointer is to a transfer ring */ @@ -863,8 +865,6 @@ struct xhci_virt_ep {  #define EP_GETTING_NO_STREAMS	(1 << 5)  	/* ----  Related to URB cancellation ---- */  	struct list_head	cancelled_td_list; -	/* The TRB that was last reported in a stopped endpoint ring */ -	union xhci_trb		*stopped_trb;  	struct xhci_td		*stopped_td;  	unsigned int		stopped_stream;  	/* Watchdog timer for stop endpoint command to cancel URBs */ @@ -934,14 +934,9 @@ struct xhci_virt_device {  	/* Rings saved to ensure old alt settings can be re-instated */  	struct xhci_ring		**ring_cache;  	int				num_rings_cached; -	/* Store xHC assigned device address */ -	int				address;  #define	XHCI_MAX_RINGS_CACHED	31  	struct xhci_virt_ep		eps[31];  	struct completion		cmd_completion; -	/* Status of the last command issued for this device */ -	u32				cmd_status; -	struct list_head		cmd_list;  	u8				fake_port;  	u8				real_port;  	struct xhci_interval_bw_table	*bw_table; @@ -1098,6 +1093,14 @@ struct xhci_event_cmd {  };  /* flags bitmasks */ + +/* Address device - disable SetAddress */ +#define TRB_BSR		(1<<9) +enum xhci_setup_dev { +	SETUP_CONTEXT_ONLY, +	SETUP_CONTEXT_ADDRESS, +}; +  /* bits 16:23 are the virtual function ID */  /* bits 24:31 are the slot ID */  #define TRB_TO_SLOT_ID(p)	(((p) & (0xff<<24)) >> 24) @@ -1111,9 +1114,10 @@ struct xhci_event_cmd {  #define TRB_TO_SUSPEND_PORT(p)		(((p) & (1 << 23)) >> 23)  #define LAST_EP_INDEX			30 -/* Set TR Dequeue Pointer command TRB fields */ +/* Set TR Dequeue Pointer command TRB fields, 6.4.3.9 */  #define TRB_TO_STREAM_ID(p)		((((p) & (0xffff << 16)) >> 16))  #define STREAM_ID_FOR_TRB(p)		((((p)) & 0xffff) << 16) +#define SCT_FOR_TRB(p)			(((p) << 1) & 0x7)  /* Port Status Change Event TRB fields */ @@ -1291,7 +1295,6 @@ struct xhci_td {  /* command descriptor */  struct xhci_cd { -	struct list_head	cancel_cmd_list;  	struct xhci_command	*command;  	union xhci_trb		*cmd_trb;  }; @@ -1334,6 +1337,7 @@ struct xhci_ring {  	unsigned int		num_trbs_free_temp;  	enum xhci_ring_type	type;  	bool			last_td_was_short; +	struct radix_tree_root	*trb_address_map;  };  struct xhci_erst_entry { @@ -1412,8 +1416,18 @@ struct xhci_bus_state {  	unsigned long		resume_done[USB_MAXCHILDREN];  	/* which ports have started to resume */  	unsigned long		resuming_ports; +	/* Which ports are waiting on RExit to U0 transition. */ +	unsigned long		rexit_ports; +	struct completion	rexit_done[USB_MAXCHILDREN];  }; + +/* + * It can take up to 20 ms to transition from RExit to U0 on the + * Intel Lynx Point LP xHCI host. + */ +#define	XHCI_MAX_REXIT_TIMEOUT	(20 * 1000) +  static inline unsigned int hcd_index(struct usb_hcd *hcd)  {  	if (hcd->speed == HCD_USB3) @@ -1458,6 +1472,8 @@ struct xhci_hcd {  	/* msi-x vectors */  	int		msix_count;  	struct msix_entry	*msix_entries; +	/* optional clock */ +	struct clk		*clk;  	/* data structures */  	struct xhci_device_context_array *dcbaa;  	struct xhci_ring	*cmd_ring; @@ -1465,8 +1481,10 @@ struct xhci_hcd {  #define CMD_RING_STATE_RUNNING         (1 << 0)  #define CMD_RING_STATE_ABORTED         (1 << 1)  #define CMD_RING_STATE_STOPPED         (1 << 2) -	struct list_head        cancel_cmd_list; +	struct list_head        cmd_list;  	unsigned int		cmd_ring_reserved_trbs; +	struct timer_list	cmd_timer; +	struct xhci_command	*current_cmd;  	struct xhci_ring	*event_ring;  	struct xhci_erst	erst;  	/* Scratchpad */ @@ -1538,6 +1556,8 @@ struct xhci_hcd {  #define XHCI_COMP_MODE_QUIRK	(1 << 14)  #define XHCI_AVOID_BEI		(1 << 15)  #define XHCI_PLAT		(1 << 16) +#define XHCI_SLOW_SUSPEND	(1 << 17) +#define XHCI_SPURIOUS_WAKEUP	(1 << 18)  	unsigned int		num_active_eps;  	unsigned int		limit_active_eps;  	/* There are two roothubs to keep track of bus suspend info for */ @@ -1584,19 +1604,6 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)  #define xhci_warn_ratelimited(xhci, fmt, args...) \  	dev_warn_ratelimited(xhci_to_hcd(xhci)->self.controller , fmt , ## args) -/* TODO: copied from ehci.h - can be refactored? */ -/* xHCI spec says all registers are little endian */ -static inline unsigned int xhci_readl(const struct xhci_hcd *xhci, -		__le32 __iomem *regs) -{ -	return readl(regs); -} -static inline void xhci_writel(struct xhci_hcd *xhci, -		const unsigned int val, __le32 __iomem *regs) -{ -	writel(val, regs); -} -  /*   * Registers should always be accessed with double word or quad word accesses.   * @@ -1731,8 +1738,7 @@ static inline int xhci_register_pci(void) { return 0; }  static inline void xhci_unregister_pci(void) {}  #endif -#if defined(CONFIG_USB_XHCI_PLATFORM) \ -	|| defined(CONFIG_USB_XHCI_PLATFORM_MODULE) +#if IS_ENABLED(CONFIG_USB_XHCI_PLATFORM)  int xhci_register_plat(void);  void xhci_unregister_plat(void);  #else @@ -1779,6 +1785,7 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,  		struct usb_host_endpoint **eps, unsigned int num_eps,  		gfp_t mem_flags);  int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev); +int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev);  int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev);  int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,  				struct usb_device *udev, int enable); @@ -1800,13 +1807,14 @@ struct xhci_segment *trb_in_td(struct xhci_segment *start_seg,  		dma_addr_t suspect_dma);  int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code);  void xhci_ring_cmd_db(struct xhci_hcd *xhci); -int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id); -int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, -		u32 slot_id); -int xhci_queue_vendor_command(struct xhci_hcd *xhci, +int xhci_queue_slot_control(struct xhci_hcd *xhci, struct xhci_command *cmd, +		u32 trb_type, u32 slot_id); +int xhci_queue_address_device(struct xhci_hcd *xhci, struct xhci_command *cmd, +		dma_addr_t in_ctx_ptr, u32 slot_id, enum xhci_setup_dev); +int xhci_queue_vendor_command(struct xhci_hcd *xhci, struct xhci_command *cmd,  		u32 field1, u32 field2, u32 field3, u32 field4); -int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, -		unsigned int ep_index, int suspend); +int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, struct xhci_command *cmd, +		int slot_id, unsigned int ep_index, int suspend);  int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,  		int slot_id, unsigned int ep_index);  int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, @@ -1815,18 +1823,21 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,  		int slot_id, unsigned int ep_index);  int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,  		struct urb *urb, int slot_id, unsigned int ep_index); -int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, -		u32 slot_id, bool command_must_succeed); -int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, -		u32 slot_id, bool command_must_succeed); -int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, -		unsigned int ep_index); -int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id); +int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, +		struct xhci_command *cmd, dma_addr_t in_ctx_ptr, u32 slot_id, +		bool command_must_succeed); +int xhci_queue_evaluate_context(struct xhci_hcd *xhci, struct xhci_command *cmd, +		dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed); +int xhci_queue_reset_ep(struct xhci_hcd *xhci, struct xhci_command *cmd, +		int slot_id, unsigned int ep_index); +int xhci_queue_reset_device(struct xhci_hcd *xhci, struct xhci_command *cmd, +		u32 slot_id);  void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,  		unsigned int slot_id, unsigned int ep_index,  		unsigned int stream_id, struct xhci_td *cur_td,  		struct xhci_dequeue_state *state);  void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, +		struct xhci_command *cmd,  		unsigned int slot_id, unsigned int ep_index,  		unsigned int stream_id,  		struct xhci_dequeue_state *deq_state); @@ -1836,10 +1847,11 @@ void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,  		unsigned int slot_id, unsigned int ep_index,  		struct xhci_dequeue_state *deq_state);  void xhci_stop_endpoint_command_watchdog(unsigned long arg); -int xhci_cancel_cmd(struct xhci_hcd *xhci, struct xhci_command *command, -		union xhci_trb *cmd_trb); +void xhci_handle_command_timeout(unsigned long data); +  void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,  		unsigned int ep_index, unsigned int stream_id); +void xhci_cleanup_command_queue(struct xhci_hcd *xhci);  /* xHCI roothub code */  void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index 7121b50098d..a62865af53c 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -51,7 +51,7 @@   *   * version 0.7.3   * bugfix : The mdc800->state field gets set to READY after the - * the diconnect function sets it to NOT_CONNECTED. This makes the + * the disconnect function sets it to NOT_CONNECTED. This makes the   * driver running like the camera is connected and causes some   * hang ups.   * diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 9c0f8caba3b..37b44b04a70 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -125,7 +125,6 @@  #include <linux/errno.h>  #include <linux/random.h>  #include <linux/poll.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/spinlock.h>  #include <linux/usb.h> diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index e2b21c1d9c4..1bca274dc3b 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -128,7 +128,6 @@ config USB_IDMOUSE  config USB_FTDI_ELAN  	tristate "Elan PCMCIA CardBus Adapter USB Client" -	default M  	help  	  ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters.  	  Currently only the U132 adapter is available. @@ -246,6 +245,6 @@ config USB_EZUSB_FX2  config USB_HSIC_USB3503         tristate "USB3503 HSIC to USB20 Driver"         depends on I2C -       select REGMAP +       select REGMAP_I2C         help           This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver. diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 3eaa83f0508..493c7f268b6 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -22,7 +22,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/usb.h> diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index ba6a5d6e618..b3d245ef46e 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -81,6 +81,7 @@ struct appledisplay {  	struct delayed_work work;  	int button_pressed;  	spinlock_t lock; +	struct mutex sysfslock;		/* concurrent read and write */  };  static atomic_t count_displays = ATOMIC_INIT(0); @@ -110,7 +111,7 @@ static void appledisplay_complete(struct urb *urb)  			__func__, status);  		return;  	default: -		dev_dbg(dev, "%s - nonzero urb status received: %d/n", +		dev_dbg(dev, "%s - nonzero urb status received: %d\n",  			__func__, status);  		goto exit;  	} @@ -144,6 +145,7 @@ static int appledisplay_bl_update_status(struct backlight_device *bd)  	struct appledisplay *pdata = bl_get_data(bd);  	int retval; +	mutex_lock(&pdata->sysfslock);  	pdata->msgdata[0] = 0x10;  	pdata->msgdata[1] = bd->props.brightness; @@ -156,15 +158,17 @@ static int appledisplay_bl_update_status(struct backlight_device *bd)  		0,  		pdata->msgdata, 2,  		ACD_USB_TIMEOUT); - +	mutex_unlock(&pdata->sysfslock); +	  	return retval;  }  static int appledisplay_bl_get_brightness(struct backlight_device *bd)  {  	struct appledisplay *pdata = bl_get_data(bd); -	int retval; +	int retval, brightness; +	mutex_lock(&pdata->sysfslock);  	retval = usb_control_msg(  		pdata->udev,  		usb_rcvctrlpipe(pdata->udev, 0), @@ -174,11 +178,13 @@ static int appledisplay_bl_get_brightness(struct backlight_device *bd)  		0,  		pdata->msgdata, 2,  		ACD_USB_TIMEOUT); +	brightness = pdata->msgdata[1]; +	mutex_unlock(&pdata->sysfslock);  	if (retval < 0)  		return retval;  	else -		return pdata->msgdata[1]; +		return brightness;  }  static const struct backlight_ops appledisplay_bl_data = { @@ -241,6 +247,7 @@ static int appledisplay_probe(struct usb_interface *iface,  	spin_lock_init(&pdata->lock);  	INIT_DELAYED_WORK(&pdata->work, appledisplay_work); +	mutex_init(&pdata->sysfslock);  	/* Allocate buffer for control messages */  	pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL); diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c index 3f7c1a92579..402b94dd253 100644 --- a/drivers/usb/misc/cypress_cy7c63.c +++ b/drivers/usb/misc/cypress_cy7c63.c @@ -29,7 +29,6 @@  *	published by the Free Software Foundation, version 2.  */ -#include <linux/init.h>  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/slab.h> diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c index 5b9831b95d9..9bab1a33bc1 100644 --- a/drivers/usb/misc/cytherm.c +++ b/drivers/usb/misc/cytherm.c @@ -16,7 +16,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/usb.h> diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c index d65984dee75..8950fa5e973 100644 --- a/drivers/usb/misc/emi26.c +++ b/drivers/usb/misc/emi26.c @@ -13,7 +13,6 @@  #include <linux/errno.h>  #include <linux/slab.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/usb.h>  #include <linux/delay.h>  #include <linux/firmware.h> diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c index ae794b90766..1d9be4431b7 100644 --- a/drivers/usb/misc/emi62.c +++ b/drivers/usb/misc/emi62.c @@ -10,7 +10,6 @@  #include <linux/kernel.h>  #include <linux/errno.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/module.h>  #include <linux/usb.h>  #include <linux/delay.h> diff --git a/drivers/usb/misc/ezusb.c b/drivers/usb/misc/ezusb.c index e712afed947..947811bc812 100644 --- a/drivers/usb/misc/ezusb.c +++ b/drivers/usb/misc/ezusb.c @@ -9,7 +9,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/usb.h> diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index a4a3c7cd4a1..8ab1f8f3c26 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -1,40 +1,43 @@  /* -* USB FTDI client driver for Elan Digital Systems's Uxxx adapters -* -* Copyright(C) 2006 Elan Digital Systems Limited -* http://www.elandigitalsystems.com -* -* Author and Maintainer - Tony Olech - Elan Digital Systems -* tony.olech@elandigitalsystems.com -* -* This program is free software;you can redistribute it and/or -* modify it under the terms of the GNU General Public License as -* published by the Free Software Foundation, version 2. -* -* -* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) -* based on various USB client drivers in the 2.6.15 linux kernel -* with constant reference to the 3rd Edition of Linux Device Drivers -* published by O'Reilly -* -* The U132 adapter is a USB to CardBus adapter specifically designed -* for PC cards that contain an OHCI host controller. Typical PC cards -* are the Orange Mobile 3G Option GlobeTrotter Fusion card. -* -* The U132 adapter will *NOT *work with PC cards that do not contain -* an OHCI controller. A simple way to test whether a PC card has an -* OHCI controller as an interface is to insert the PC card directly -* into a laptop(or desktop) with a CardBus slot and if "lspci" shows -* a new USB controller and "lsusb -v" shows a new OHCI Host Controller -* then there is a good chance that the U132 adapter will support the -* PC card.(you also need the specific client driver for the PC card) -* -* Please inform the Author and Maintainer about any PC cards that -* contain OHCI Host Controller and work when directly connected to -* an embedded CardBus slot but do not work when they are connected -* via an ELAN U132 adapter. -* -*/ + * USB FTDI client driver for Elan Digital Systems's Uxxx adapters + * + * Copyright(C) 2006 Elan Digital Systems Limited + * http://www.elandigitalsystems.com + * + * Author and Maintainer - Tony Olech - Elan Digital Systems + * tony.olech@elandigitalsystems.com + * + * This program is free software;you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, version 2. + * + * + * This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) + * based on various USB client drivers in the 2.6.15 linux kernel + * with constant reference to the 3rd Edition of Linux Device Drivers + * published by O'Reilly + * + * The U132 adapter is a USB to CardBus adapter specifically designed + * for PC cards that contain an OHCI host controller. Typical PC cards + * are the Orange Mobile 3G Option GlobeTrotter Fusion card. + * + * The U132 adapter will *NOT *work with PC cards that do not contain + * an OHCI controller. A simple way to test whether a PC card has an + * OHCI controller as an interface is to insert the PC card directly + * into a laptop(or desktop) with a CardBus slot and if "lspci" shows + * a new USB controller and "lsusb -v" shows a new OHCI Host Controller + * then there is a good chance that the U132 adapter will support the + * PC card.(you also need the specific client driver for the PC card) + * + * Please inform the Author and Maintainer about any PC cards that + * contain OHCI Host Controller and work when directly connected to + * an embedded CardBus slot but do not work when they are connected + * via an ELAN U132 adapter. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/kernel.h>  #include <linux/errno.h>  #include <linux/init.h> @@ -55,31 +58,31 @@ MODULE_LICENSE("GPL");  #define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)  static bool distrust_firmware = 1;  module_param(distrust_firmware, bool, 0); -MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" -        "t setup"); +MODULE_PARM_DESC(distrust_firmware, +		 "true to distrust firmware power/overcurrent setup");  extern struct platform_driver u132_platform_driver;  static struct workqueue_struct *status_queue;  static struct workqueue_struct *command_queue;  static struct workqueue_struct *respond_queue;  /* -* ftdi_module_lock exists to protect access to global variables -* -*/ + * ftdi_module_lock exists to protect access to global variables + * + */  static struct mutex ftdi_module_lock;  static int ftdi_instances = 0;  static struct list_head ftdi_static_list;  /* -* end of the global variables protected by ftdi_module_lock -*/ + * end of the global variables protected by ftdi_module_lock + */  #include "usb_u132.h"  #include <asm/io.h>  #include <linux/usb/hcd.h> -	/* FIXME ohci.h is ONLY for internal use by the OHCI driver. -	 * If you're going to try stuff like this, you need to split -	 * out shareable stuff (register declarations?) into its own -	 * file, maybe name <linux/usb/ohci.h> -	 */ +/* FIXME ohci.h is ONLY for internal use by the OHCI driver. + * If you're going to try stuff like this, you need to split + * out shareable stuff (register declarations?) into its own + * file, maybe name <linux/usb/ohci.h> + */  #include "../host/ohci.h"  /* Define these values to match your devices*/ @@ -87,140 +90,140 @@ static struct list_head ftdi_static_list;  #define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea  /* table of devices that work with this driver*/  static const struct usb_device_id ftdi_elan_table[] = { -        {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)}, -        { /* Terminating entry */ } +	{USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)}, +	{ /* Terminating entry */ }  };  MODULE_DEVICE_TABLE(usb, ftdi_elan_table);  /* only the jtag(firmware upgrade device) interface requires -* a device file and corresponding minor number, but the -* interface is created unconditionally - I suppose it could -* be configured or not according to a module parameter. -* But since we(now) require one interface per device, -* and since it unlikely that a normal installation would -* require more than a couple of elan-ftdi devices, 8 seems -* like a reasonable limit to have here, and if someone -* really requires more than 8 devices, then they can frig the -* code and recompile -*/ + * a device file and corresponding minor number, but the + * interface is created unconditionally - I suppose it could + * be configured or not according to a module parameter. + * But since we(now) require one interface per device, + * and since it unlikely that a normal installation would + * require more than a couple of elan-ftdi devices, 8 seems + * like a reasonable limit to have here, and if someone + * really requires more than 8 devices, then they can frig the + * code and recompile + */  #define USB_FTDI_ELAN_MINOR_BASE 192  #define COMMAND_BITS 5  #define COMMAND_SIZE (1<<COMMAND_BITS)  #define COMMAND_MASK (COMMAND_SIZE-1)  struct u132_command { -        u8 header; -        u16 length; -        u8 address; -        u8 width; -        u32 value; -        int follows; -        void *buffer; +	u8 header; +	u16 length; +	u8 address; +	u8 width; +	u32 value; +	int follows; +	void *buffer;  };  #define RESPOND_BITS 5  #define RESPOND_SIZE (1<<RESPOND_BITS)  #define RESPOND_MASK (RESPOND_SIZE-1)  struct u132_respond { -        u8 header; -        u8 address; -        u32 *value; -        int *result; -        struct completion wait_completion; +	u8 header; +	u8 address; +	u32 *value; +	int *result; +	struct completion wait_completion;  };  struct u132_target { -        void *endp; -        struct urb *urb; -        int toggle_bits; -        int error_count; -        int condition_code; -        int repeat_number; -        int halted; -        int skipped; -        int actual; -        int non_null; -        int active; -        int abandoning; -        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, -                int toggle_bits, int error_count, int condition_code, -                int repeat_number, int halted, int skipped, int actual, -                int non_null); +	void *endp; +	struct urb *urb; +	int toggle_bits; +	int error_count; +	int condition_code; +	int repeat_number; +	int halted; +	int skipped; +	int actual; +	int non_null; +	int active; +	int abandoning; +	void (*callback)(void *endp, struct urb *urb, u8 *buf, int len, +			 int toggle_bits, int error_count, int condition_code, +			 int repeat_number, int halted, int skipped, int actual, +			 int non_null);  };  /* Structure to hold all of our device specific stuff*/  struct usb_ftdi { -        struct list_head ftdi_list; -        struct mutex u132_lock; -        int command_next; -        int command_head; -        struct u132_command command[COMMAND_SIZE]; -        int respond_next; -        int respond_head; -        struct u132_respond respond[RESPOND_SIZE]; -        struct u132_target target[4]; -        char device_name[16]; -        unsigned synchronized:1; -        unsigned enumerated:1; -        unsigned registered:1; -        unsigned initialized:1; -        unsigned card_ejected:1; -        int function; -        int sequence_num; -        int disconnected; -        int gone_away; -        int stuck_status; -        int status_queue_delay; -        struct semaphore sw_lock; -        struct usb_device *udev; -        struct usb_interface *interface; -        struct usb_class_driver *class; -        struct delayed_work status_work; -        struct delayed_work command_work; -        struct delayed_work respond_work; -        struct u132_platform_data platform_data; -        struct resource resources[0]; -        struct platform_device platform_dev; -        unsigned char *bulk_in_buffer; -        size_t bulk_in_size; -        size_t bulk_in_last; -        size_t bulk_in_left; -        __u8 bulk_in_endpointAddr; -        __u8 bulk_out_endpointAddr; -        struct kref kref; -        u32 controlreg; -        u8 response[4 + 1024]; -        int expected; -        int received; -        int ed_found; +	struct list_head ftdi_list; +	struct mutex u132_lock; +	int command_next; +	int command_head; +	struct u132_command command[COMMAND_SIZE]; +	int respond_next; +	int respond_head; +	struct u132_respond respond[RESPOND_SIZE]; +	struct u132_target target[4]; +	char device_name[16]; +	unsigned synchronized:1; +	unsigned enumerated:1; +	unsigned registered:1; +	unsigned initialized:1; +	unsigned card_ejected:1; +	int function; +	int sequence_num; +	int disconnected; +	int gone_away; +	int stuck_status; +	int status_queue_delay; +	struct semaphore sw_lock; +	struct usb_device *udev; +	struct usb_interface *interface; +	struct usb_class_driver *class; +	struct delayed_work status_work; +	struct delayed_work command_work; +	struct delayed_work respond_work; +	struct u132_platform_data platform_data; +	struct resource resources[0]; +	struct platform_device platform_dev; +	unsigned char *bulk_in_buffer; +	size_t bulk_in_size; +	size_t bulk_in_last; +	size_t bulk_in_left; +	__u8 bulk_in_endpointAddr; +	__u8 bulk_out_endpointAddr; +	struct kref kref; +	u32 controlreg; +	u8 response[4 + 1024]; +	int expected; +	int received; +	int ed_found;  };  #define kref_to_usb_ftdi(d) container_of(d, struct usb_ftdi, kref)  #define platform_device_to_usb_ftdi(d) container_of(d, struct usb_ftdi, \ -        platform_dev) +						    platform_dev)  static struct usb_driver ftdi_elan_driver;  static void ftdi_elan_delete(struct kref *kref)  { -        struct usb_ftdi *ftdi = kref_to_usb_ftdi(kref); -        dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi); -        usb_put_dev(ftdi->udev); -        ftdi->disconnected += 1; -        mutex_lock(&ftdi_module_lock); -        list_del_init(&ftdi->ftdi_list); -        ftdi_instances -= 1; -        mutex_unlock(&ftdi_module_lock); -        kfree(ftdi->bulk_in_buffer); -        ftdi->bulk_in_buffer = NULL; +	struct usb_ftdi *ftdi = kref_to_usb_ftdi(kref); +	dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi); +	usb_put_dev(ftdi->udev); +	ftdi->disconnected += 1; +	mutex_lock(&ftdi_module_lock); +	list_del_init(&ftdi->ftdi_list); +	ftdi_instances -= 1; +	mutex_unlock(&ftdi_module_lock); +	kfree(ftdi->bulk_in_buffer); +	ftdi->bulk_in_buffer = NULL;  }  static void ftdi_elan_put_kref(struct usb_ftdi *ftdi)  { -        kref_put(&ftdi->kref, ftdi_elan_delete); +	kref_put(&ftdi->kref, ftdi_elan_delete);  }  static void ftdi_elan_get_kref(struct usb_ftdi *ftdi)  { -        kref_get(&ftdi->kref); +	kref_get(&ftdi->kref);  }  static void ftdi_elan_init_kref(struct usb_ftdi *ftdi)  { -        kref_init(&ftdi->kref); +	kref_init(&ftdi->kref);  }  static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) @@ -237,8 +240,8 @@ static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta)  static void ftdi_status_cancel_work(struct usb_ftdi *ftdi)  { -        if (cancel_delayed_work(&ftdi->status_work)) -                kref_put(&ftdi->kref, ftdi_elan_delete); +	if (cancel_delayed_work(&ftdi->status_work)) +		kref_put(&ftdi->kref, ftdi_elan_delete);  }  static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) @@ -255,12 +258,12 @@ static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta)  static void ftdi_command_cancel_work(struct usb_ftdi *ftdi)  { -        if (cancel_delayed_work(&ftdi->command_work)) -                kref_put(&ftdi->kref, ftdi_elan_delete); +	if (cancel_delayed_work(&ftdi->command_work)) +		kref_put(&ftdi->kref, ftdi_elan_delete);  }  static void ftdi_response_requeue_work(struct usb_ftdi *ftdi, -        unsigned int delta) +				       unsigned int delta)  {  	if (!queue_delayed_work(respond_queue, &ftdi->respond_work, delta))  		kref_put(&ftdi->kref, ftdi_elan_delete); @@ -274,26 +277,26 @@ static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta)  static void ftdi_response_cancel_work(struct usb_ftdi *ftdi)  { -        if (cancel_delayed_work(&ftdi->respond_work)) -                kref_put(&ftdi->kref, ftdi_elan_delete); +	if (cancel_delayed_work(&ftdi->respond_work)) +		kref_put(&ftdi->kref, ftdi_elan_delete);  }  void ftdi_elan_gone_away(struct platform_device *pdev)  { -        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); -        ftdi->gone_away += 1; -        ftdi_elan_put_kref(ftdi); +	struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); +	ftdi->gone_away += 1; +	ftdi_elan_put_kref(ftdi);  }  EXPORT_SYMBOL_GPL(ftdi_elan_gone_away);  static void ftdi_release_platform_dev(struct device *dev)  { -        dev->parent = NULL; +	dev->parent = NULL;  }  static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, -        struct u132_target *target, u8 *buffer, int length); +				  struct u132_target *target, u8 *buffer, int length);  static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi);  static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi);  static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi); @@ -305,421 +308,416 @@ static int ftdi_elan_command_engine(struct usb_ftdi *ftdi);  static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi);  static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi)  { -        int result; -        if (ftdi->platform_dev.dev.parent) -                return -EBUSY; -        ftdi_elan_get_kref(ftdi); -        ftdi->platform_data.potpg = 100; -        ftdi->platform_data.reset = NULL; -        ftdi->platform_dev.id = ftdi->sequence_num; -        ftdi->platform_dev.resource = ftdi->resources; -        ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources); -        ftdi->platform_dev.dev.platform_data = &ftdi->platform_data; -        ftdi->platform_dev.dev.parent = NULL; -        ftdi->platform_dev.dev.release = ftdi_release_platform_dev; -        ftdi->platform_dev.dev.dma_mask = NULL; -        snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd"); -        ftdi->platform_dev.name = ftdi->device_name; -        dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd"); -        request_module("u132_hcd"); -        dev_info(&ftdi->udev->dev, "registering '%s'\n", -                ftdi->platform_dev.name); -        result = platform_device_register(&ftdi->platform_dev); -        return result; +	int result; +	if (ftdi->platform_dev.dev.parent) +		return -EBUSY; +	ftdi_elan_get_kref(ftdi); +	ftdi->platform_data.potpg = 100; +	ftdi->platform_data.reset = NULL; +	ftdi->platform_dev.id = ftdi->sequence_num; +	ftdi->platform_dev.resource = ftdi->resources; +	ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources); +	ftdi->platform_dev.dev.platform_data = &ftdi->platform_data; +	ftdi->platform_dev.dev.parent = NULL; +	ftdi->platform_dev.dev.release = ftdi_release_platform_dev; +	ftdi->platform_dev.dev.dma_mask = NULL; +	snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd"); +	ftdi->platform_dev.name = ftdi->device_name; +	dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd"); +	request_module("u132_hcd"); +	dev_info(&ftdi->udev->dev, "registering '%s'\n", +		 ftdi->platform_dev.name); +	result = platform_device_register(&ftdi->platform_dev); +	return result;  }  static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi)  { -        mutex_lock(&ftdi->u132_lock); -        while (ftdi->respond_next > ftdi->respond_head) { -                struct u132_respond *respond = &ftdi->respond[RESPOND_MASK & -                        ftdi->respond_head++]; -                *respond->result = -ESHUTDOWN; -                *respond->value = 0; -                complete(&respond->wait_completion); -        } mutex_unlock(&ftdi->u132_lock); +	mutex_lock(&ftdi->u132_lock); +	while (ftdi->respond_next > ftdi->respond_head) { +		struct u132_respond *respond = &ftdi->respond[RESPOND_MASK & +							      ftdi->respond_head++]; +		*respond->result = -ESHUTDOWN; +		*respond->value = 0; +		complete(&respond->wait_completion); +	} mutex_unlock(&ftdi->u132_lock);  }  static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi)  { -        int ed_number = 4; -        mutex_lock(&ftdi->u132_lock); -        while (ed_number-- > 0) { -                struct u132_target *target = &ftdi->target[ed_number]; -                if (target->active == 1) { -                        target->condition_code = TD_DEVNOTRESP; -                        mutex_unlock(&ftdi->u132_lock); -                        ftdi_elan_do_callback(ftdi, target, NULL, 0); -                        mutex_lock(&ftdi->u132_lock); -                } -        } -        ftdi->received = 0; -        ftdi->expected = 4; -        ftdi->ed_found = 0; -        mutex_unlock(&ftdi->u132_lock); +	int ed_number = 4; +	mutex_lock(&ftdi->u132_lock); +	while (ed_number-- > 0) { +		struct u132_target *target = &ftdi->target[ed_number]; +		if (target->active == 1) { +			target->condition_code = TD_DEVNOTRESP; +			mutex_unlock(&ftdi->u132_lock); +			ftdi_elan_do_callback(ftdi, target, NULL, 0); +			mutex_lock(&ftdi->u132_lock); +		} +	} +	ftdi->received = 0; +	ftdi->expected = 4; +	ftdi->ed_found = 0; +	mutex_unlock(&ftdi->u132_lock);  }  static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi)  { -        int ed_number = 4; -        mutex_lock(&ftdi->u132_lock); -        while (ed_number-- > 0) { -                struct u132_target *target = &ftdi->target[ed_number]; -                target->abandoning = 1; -              wait_1:if (target->active == 1) { -                        int command_size = ftdi->command_next - -                                ftdi->command_head; -                        if (command_size < COMMAND_SIZE) { -                                struct u132_command *command = &ftdi->command[ -                                        COMMAND_MASK & ftdi->command_next]; -                                command->header = 0x80 | (ed_number << 5) | 0x4; -                                command->length = 0x00; -                                command->address = 0x00; -                                command->width = 0x00; -                                command->follows = 0; -                                command->value = 0; -                                command->buffer = &command->value; -                                ftdi->command_next += 1; -                                ftdi_elan_kick_command_queue(ftdi); -                        } else { -                                mutex_unlock(&ftdi->u132_lock); -                                msleep(100); -                                mutex_lock(&ftdi->u132_lock); -                                goto wait_1; -                        } -                } -              wait_2:if (target->active == 1) { -                        int command_size = ftdi->command_next - -                                ftdi->command_head; -                        if (command_size < COMMAND_SIZE) { -                                struct u132_command *command = &ftdi->command[ -                                        COMMAND_MASK & ftdi->command_next]; -                                command->header = 0x90 | (ed_number << 5); -                                command->length = 0x00; -                                command->address = 0x00; -                                command->width = 0x00; -                                command->follows = 0; -                                command->value = 0; -                                command->buffer = &command->value; -                                ftdi->command_next += 1; -                                ftdi_elan_kick_command_queue(ftdi); -                        } else { -                                mutex_unlock(&ftdi->u132_lock); -                                msleep(100); -                                mutex_lock(&ftdi->u132_lock); -                                goto wait_2; -                        } -                } -        } -        ftdi->received = 0; -        ftdi->expected = 4; -        ftdi->ed_found = 0; -        mutex_unlock(&ftdi->u132_lock); +	int ed_number = 4; +	mutex_lock(&ftdi->u132_lock); +	while (ed_number-- > 0) { +		struct u132_target *target = &ftdi->target[ed_number]; +		target->abandoning = 1; +	wait_1:if (target->active == 1) { +			int command_size = ftdi->command_next - +				ftdi->command_head; +			if (command_size < COMMAND_SIZE) { +				struct u132_command *command = &ftdi->command[ +					COMMAND_MASK & ftdi->command_next]; +				command->header = 0x80 | (ed_number << 5) | 0x4; +				command->length = 0x00; +				command->address = 0x00; +				command->width = 0x00; +				command->follows = 0; +				command->value = 0; +				command->buffer = &command->value; +				ftdi->command_next += 1; +				ftdi_elan_kick_command_queue(ftdi); +			} else { +				mutex_unlock(&ftdi->u132_lock); +				msleep(100); +				mutex_lock(&ftdi->u132_lock); +				goto wait_1; +			} +		} +	wait_2:if (target->active == 1) { +			int command_size = ftdi->command_next - +				ftdi->command_head; +			if (command_size < COMMAND_SIZE) { +				struct u132_command *command = &ftdi->command[ +					COMMAND_MASK & ftdi->command_next]; +				command->header = 0x90 | (ed_number << 5); +				command->length = 0x00; +				command->address = 0x00; +				command->width = 0x00; +				command->follows = 0; +				command->value = 0; +				command->buffer = &command->value; +				ftdi->command_next += 1; +				ftdi_elan_kick_command_queue(ftdi); +			} else { +				mutex_unlock(&ftdi->u132_lock); +				msleep(100); +				mutex_lock(&ftdi->u132_lock); +				goto wait_2; +			} +		} +	} +	ftdi->received = 0; +	ftdi->expected = 4; +	ftdi->ed_found = 0; +	mutex_unlock(&ftdi->u132_lock);  }  static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi)  { -        int ed_number = 4; -        mutex_lock(&ftdi->u132_lock); -        while (ed_number-- > 0) { -                struct u132_target *target = &ftdi->target[ed_number]; -                target->abandoning = 1; -              wait:if (target->active == 1) { -                        int command_size = ftdi->command_next - -                                ftdi->command_head; -                        if (command_size < COMMAND_SIZE) { -                                struct u132_command *command = &ftdi->command[ -                                        COMMAND_MASK & ftdi->command_next]; -                                command->header = 0x80 | (ed_number << 5) | 0x4; -                                command->length = 0x00; -                                command->address = 0x00; -                                command->width = 0x00; -                                command->follows = 0; -                                command->value = 0; -                                command->buffer = &command->value; -                                ftdi->command_next += 1; -                                ftdi_elan_kick_command_queue(ftdi); -                        } else { -                                mutex_unlock(&ftdi->u132_lock); -                                msleep(100); -                                mutex_lock(&ftdi->u132_lock); -                                goto wait; -                        } -                } -        } -        ftdi->received = 0; -        ftdi->expected = 4; -        ftdi->ed_found = 0; -        mutex_unlock(&ftdi->u132_lock); +	int ed_number = 4; +	mutex_lock(&ftdi->u132_lock); +	while (ed_number-- > 0) { +		struct u132_target *target = &ftdi->target[ed_number]; +		target->abandoning = 1; +	wait:if (target->active == 1) { +			int command_size = ftdi->command_next - +				ftdi->command_head; +			if (command_size < COMMAND_SIZE) { +				struct u132_command *command = &ftdi->command[ +					COMMAND_MASK & ftdi->command_next]; +				command->header = 0x80 | (ed_number << 5) | 0x4; +				command->length = 0x00; +				command->address = 0x00; +				command->width = 0x00; +				command->follows = 0; +				command->value = 0; +				command->buffer = &command->value; +				ftdi->command_next += 1; +				ftdi_elan_kick_command_queue(ftdi); +			} else { +				mutex_unlock(&ftdi->u132_lock); +				msleep(100); +				mutex_lock(&ftdi->u132_lock); +				goto wait; +			} +		} +	} +	ftdi->received = 0; +	ftdi->expected = 4; +	ftdi->ed_found = 0; +	mutex_unlock(&ftdi->u132_lock);  }  static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi)  { -        ftdi_command_queue_work(ftdi, 0); +	ftdi_command_queue_work(ftdi, 0);  }  static void ftdi_elan_command_work(struct work_struct *work)  { -        struct usb_ftdi *ftdi = +	struct usb_ftdi *ftdi =  		container_of(work, struct usb_ftdi, command_work.work); -        if (ftdi->disconnected > 0) { -                ftdi_elan_put_kref(ftdi); -                return; -        } else { -                int retval = ftdi_elan_command_engine(ftdi); -                if (retval == -ESHUTDOWN) { -                        ftdi->disconnected += 1; -                } else if (retval == -ENODEV) { -                        ftdi->disconnected += 1; -                } else if (retval) -                        dev_err(&ftdi->udev->dev, "command error %d\n", retval); -                ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10)); -                return; -        } +	if (ftdi->disconnected > 0) { +		ftdi_elan_put_kref(ftdi); +		return; +	} else { +		int retval = ftdi_elan_command_engine(ftdi); +		if (retval == -ESHUTDOWN) { +			ftdi->disconnected += 1; +		} else if (retval == -ENODEV) { +			ftdi->disconnected += 1; +		} else if (retval) +			dev_err(&ftdi->udev->dev, "command error %d\n", retval); +		ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10)); +		return; +	}  }  static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi)  { -        ftdi_respond_queue_work(ftdi, 0); +	ftdi_respond_queue_work(ftdi, 0);  }  static void ftdi_elan_respond_work(struct work_struct *work)  { -        struct usb_ftdi *ftdi = +	struct usb_ftdi *ftdi =  		container_of(work, struct usb_ftdi, respond_work.work); -        if (ftdi->disconnected > 0) { -                ftdi_elan_put_kref(ftdi); -                return; -        } else { -                int retval = ftdi_elan_respond_engine(ftdi); -                if (retval == 0) { -                } else if (retval == -ESHUTDOWN) { -                        ftdi->disconnected += 1; -                } else if (retval == -ENODEV) { -                        ftdi->disconnected += 1; -                } else if (retval == -EILSEQ) { -                        ftdi->disconnected += 1; -                } else { -                        ftdi->disconnected += 1; -                        dev_err(&ftdi->udev->dev, "respond error %d\n", retval); -                } -                if (ftdi->disconnected > 0) { -                        ftdi_elan_abandon_completions(ftdi); -                        ftdi_elan_abandon_targets(ftdi); -                } -                ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10)); -                return; -        } +	if (ftdi->disconnected > 0) { +		ftdi_elan_put_kref(ftdi); +		return; +	} else { +		int retval = ftdi_elan_respond_engine(ftdi); +		if (retval == 0) { +		} else if (retval == -ESHUTDOWN) { +			ftdi->disconnected += 1; +		} else if (retval == -ENODEV) { +			ftdi->disconnected += 1; +		} else if (retval == -EILSEQ) { +			ftdi->disconnected += 1; +		} else { +			ftdi->disconnected += 1; +			dev_err(&ftdi->udev->dev, "respond error %d\n", retval); +		} +		if (ftdi->disconnected > 0) { +			ftdi_elan_abandon_completions(ftdi); +			ftdi_elan_abandon_targets(ftdi); +		} +		ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10)); +		return; +	}  }  /* -* the sw_lock is initially held and will be freed -* after the FTDI has been synchronized -* -*/ + * the sw_lock is initially held and will be freed + * after the FTDI has been synchronized + * + */  static void ftdi_elan_status_work(struct work_struct *work)  { -        struct usb_ftdi *ftdi = +	struct usb_ftdi *ftdi =  		container_of(work, struct usb_ftdi, status_work.work); -        int work_delay_in_msec = 0; -        if (ftdi->disconnected > 0) { -                ftdi_elan_put_kref(ftdi); -                return; -        } else if (ftdi->synchronized == 0) { -                down(&ftdi->sw_lock); -                if (ftdi_elan_synchronize(ftdi) == 0) { -                        ftdi->synchronized = 1; -                        ftdi_command_queue_work(ftdi, 1); -                        ftdi_respond_queue_work(ftdi, 1); -                        up(&ftdi->sw_lock); -                        work_delay_in_msec = 100; -                } else { -                        dev_err(&ftdi->udev->dev, "synchronize failed\n"); -                        up(&ftdi->sw_lock); -                        work_delay_in_msec = 10 *1000; -                } -        } else if (ftdi->stuck_status > 0) { -                if (ftdi_elan_stuck_waiting(ftdi) == 0) { -                        ftdi->stuck_status = 0; -                        ftdi->synchronized = 0; -                } else if ((ftdi->stuck_status++ % 60) == 1) { -                        dev_err(&ftdi->udev->dev, "WRONG type of card inserted " -                                "- please remove\n"); -                } else -                        dev_err(&ftdi->udev->dev, "WRONG type of card inserted " -                                "- checked %d times\n", ftdi->stuck_status); -                work_delay_in_msec = 100; -        } else if (ftdi->enumerated == 0) { -                if (ftdi_elan_enumeratePCI(ftdi) == 0) { -                        ftdi->enumerated = 1; -                        work_delay_in_msec = 250; -                } else -                        work_delay_in_msec = 1000; -        } else if (ftdi->initialized == 0) { -                if (ftdi_elan_setupOHCI(ftdi) == 0) { -                        ftdi->initialized = 1; -                        work_delay_in_msec = 500; -                } else { -                        dev_err(&ftdi->udev->dev, "initialized failed - trying " -                                "again in 10 seconds\n"); -                        work_delay_in_msec = 1 *1000; -                } -        } else if (ftdi->registered == 0) { -                work_delay_in_msec = 10; -                if (ftdi_elan_hcd_init(ftdi) == 0) { -                        ftdi->registered = 1; -                } else -                        dev_err(&ftdi->udev->dev, "register failed\n"); -                work_delay_in_msec = 250; -        } else { -                if (ftdi_elan_checkingPCI(ftdi) == 0) { -                        work_delay_in_msec = 250; -                } else if (ftdi->controlreg & 0x00400000) { -                        if (ftdi->gone_away > 0) { -                                dev_err(&ftdi->udev->dev, "PCI device eject con" -                                        "firmed platform_dev.dev.parent=%p plat" -                                        "form_dev.dev=%p\n", -                                        ftdi->platform_dev.dev.parent, -                                        &ftdi->platform_dev.dev); -                                platform_device_unregister(&ftdi->platform_dev); -                                ftdi->platform_dev.dev.parent = NULL; -                                ftdi->registered = 0; -                                ftdi->enumerated = 0; -                                ftdi->card_ejected = 0; -                                ftdi->initialized = 0; -                                ftdi->gone_away = 0; -                        } else -                                ftdi_elan_flush_targets(ftdi); -                        work_delay_in_msec = 250; -                } else { -                        dev_err(&ftdi->udev->dev, "PCI device has disappeared\n" -                                ); -                        ftdi_elan_cancel_targets(ftdi); -                        work_delay_in_msec = 500; -                        ftdi->enumerated = 0; -                        ftdi->initialized = 0; -                } -        } -        if (ftdi->disconnected > 0) { -                ftdi_elan_put_kref(ftdi); -                return; -        } else { -                ftdi_status_requeue_work(ftdi, -                        msecs_to_jiffies(work_delay_in_msec)); -                return; -        } +	int work_delay_in_msec = 0; +	if (ftdi->disconnected > 0) { +		ftdi_elan_put_kref(ftdi); +		return; +	} else if (ftdi->synchronized == 0) { +		down(&ftdi->sw_lock); +		if (ftdi_elan_synchronize(ftdi) == 0) { +			ftdi->synchronized = 1; +			ftdi_command_queue_work(ftdi, 1); +			ftdi_respond_queue_work(ftdi, 1); +			up(&ftdi->sw_lock); +			work_delay_in_msec = 100; +		} else { +			dev_err(&ftdi->udev->dev, "synchronize failed\n"); +			up(&ftdi->sw_lock); +			work_delay_in_msec = 10 *1000; +		} +	} else if (ftdi->stuck_status > 0) { +		if (ftdi_elan_stuck_waiting(ftdi) == 0) { +			ftdi->stuck_status = 0; +			ftdi->synchronized = 0; +		} else if ((ftdi->stuck_status++ % 60) == 1) { +			dev_err(&ftdi->udev->dev, "WRONG type of card inserted - please remove\n"); +		} else +			dev_err(&ftdi->udev->dev, "WRONG type of card inserted - checked %d times\n", +				ftdi->stuck_status); +		work_delay_in_msec = 100; +	} else if (ftdi->enumerated == 0) { +		if (ftdi_elan_enumeratePCI(ftdi) == 0) { +			ftdi->enumerated = 1; +			work_delay_in_msec = 250; +		} else +			work_delay_in_msec = 1000; +	} else if (ftdi->initialized == 0) { +		if (ftdi_elan_setupOHCI(ftdi) == 0) { +			ftdi->initialized = 1; +			work_delay_in_msec = 500; +		} else { +			dev_err(&ftdi->udev->dev, "initialized failed - trying again in 10 seconds\n"); +			work_delay_in_msec = 1 *1000; +		} +	} else if (ftdi->registered == 0) { +		work_delay_in_msec = 10; +		if (ftdi_elan_hcd_init(ftdi) == 0) { +			ftdi->registered = 1; +		} else +			dev_err(&ftdi->udev->dev, "register failed\n"); +		work_delay_in_msec = 250; +	} else { +		if (ftdi_elan_checkingPCI(ftdi) == 0) { +			work_delay_in_msec = 250; +		} else if (ftdi->controlreg & 0x00400000) { +			if (ftdi->gone_away > 0) { +				dev_err(&ftdi->udev->dev, "PCI device eject confirmed platform_dev.dev.parent=%p platform_dev.dev=%p\n", +					ftdi->platform_dev.dev.parent, +					&ftdi->platform_dev.dev); +				platform_device_unregister(&ftdi->platform_dev); +				ftdi->platform_dev.dev.parent = NULL; +				ftdi->registered = 0; +				ftdi->enumerated = 0; +				ftdi->card_ejected = 0; +				ftdi->initialized = 0; +				ftdi->gone_away = 0; +			} else +				ftdi_elan_flush_targets(ftdi); +			work_delay_in_msec = 250; +		} else { +			dev_err(&ftdi->udev->dev, "PCI device has disappeared\n"); +			ftdi_elan_cancel_targets(ftdi); +			work_delay_in_msec = 500; +			ftdi->enumerated = 0; +			ftdi->initialized = 0; +		} +	} +	if (ftdi->disconnected > 0) { +		ftdi_elan_put_kref(ftdi); +		return; +	} else { +		ftdi_status_requeue_work(ftdi, +					 msecs_to_jiffies(work_delay_in_msec)); +		return; +	}  }  /* -* file_operations for the jtag interface -* -* the usage count for the device is incremented on open() -* and decremented on release() -*/ + * file_operations for the jtag interface + * + * the usage count for the device is incremented on open() + * and decremented on release() + */  static int ftdi_elan_open(struct inode *inode, struct file *file)  {  	int subminor;  	struct usb_interface *interface; -        subminor = iminor(inode); -        interface = usb_find_interface(&ftdi_elan_driver, subminor); - -        if (!interface) { -                printk(KERN_ERR "can't find device for minor %d\n", subminor); -                return -ENODEV; -        } else { -                struct usb_ftdi *ftdi = usb_get_intfdata(interface); -                if (!ftdi) { -                        return -ENODEV; -                } else { -                        if (down_interruptible(&ftdi->sw_lock)) { -                                return -EINTR; -                        } else { -                                ftdi_elan_get_kref(ftdi); -                                file->private_data = ftdi; -                                return 0; -                        } -                } -        } +	subminor = iminor(inode); +	interface = usb_find_interface(&ftdi_elan_driver, subminor); + +	if (!interface) { +		pr_err("can't find device for minor %d\n", subminor); +		return -ENODEV; +	} else { +		struct usb_ftdi *ftdi = usb_get_intfdata(interface); +		if (!ftdi) { +			return -ENODEV; +		} else { +			if (down_interruptible(&ftdi->sw_lock)) { +				return -EINTR; +			} else { +				ftdi_elan_get_kref(ftdi); +				file->private_data = ftdi; +				return 0; +			} +		} +	}  }  static int ftdi_elan_release(struct inode *inode, struct file *file)  { -        struct usb_ftdi *ftdi = file->private_data; -        if (ftdi == NULL) -                return -ENODEV; -        up(&ftdi->sw_lock);        /* decrement the count on our device */ -        ftdi_elan_put_kref(ftdi); -        return 0; +	struct usb_ftdi *ftdi = file->private_data; +	if (ftdi == NULL) +		return -ENODEV; +	up(&ftdi->sw_lock);        /* decrement the count on our device */ +	ftdi_elan_put_kref(ftdi); +	return 0;  }  /* -* -* blocking bulk reads are used to get data from the device -* -*/ + * + * blocking bulk reads are used to get data from the device + * + */  static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,  			      size_t count, loff_t *ppos)  { -        char data[30 *3 + 4]; -        char *d = data; -        int m = (sizeof(data) - 1) / 3; -        int bytes_read = 0; -        int retry_on_empty = 10; -        int retry_on_timeout = 5; -        struct usb_ftdi *ftdi = file->private_data; -        if (ftdi->disconnected > 0) { -                return -ENODEV; -        } -        data[0] = 0; -      have:if (ftdi->bulk_in_left > 0) { -                if (count-- > 0) { -                        char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer; -                        ftdi->bulk_in_left -= 1; -                        if (bytes_read < m) { -                                d += sprintf(d, " %02X", 0x000000FF & *p); -                        } else if (bytes_read > m) { -                        } else -                                d += sprintf(d, " .."); -                        if (copy_to_user(buffer++, p, 1)) { -                                return -EFAULT; -                        } else { -                                bytes_read += 1; -                                goto have; -                        } -                } else -                        return bytes_read; -        } -      more:if (count > 0) { -                int packet_bytes = 0; -                int retval = usb_bulk_msg(ftdi->udev, -                        usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), -                         ftdi->bulk_in_buffer, ftdi->bulk_in_size, -                        &packet_bytes, 50); -                if (packet_bytes > 2) { -                        ftdi->bulk_in_left = packet_bytes - 2; -                        ftdi->bulk_in_last = 1; -                        goto have; -                } else if (retval == -ETIMEDOUT) { -                        if (retry_on_timeout-- > 0) { -                                goto more; -                        } else if (bytes_read > 0) { -                                return bytes_read; -                        } else -                                return retval; -                } else if (retval == 0) { -                        if (retry_on_empty-- > 0) { -                                goto more; -                        } else -                                return bytes_read; -                } else -                        return retval; -        } else -                return bytes_read; +	char data[30 *3 + 4]; +	char *d = data; +	int m = (sizeof(data) - 1) / 3; +	int bytes_read = 0; +	int retry_on_empty = 10; +	int retry_on_timeout = 5; +	struct usb_ftdi *ftdi = file->private_data; +	if (ftdi->disconnected > 0) { +		return -ENODEV; +	} +	data[0] = 0; +have:if (ftdi->bulk_in_left > 0) { +		if (count-- > 0) { +			char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer; +			ftdi->bulk_in_left -= 1; +			if (bytes_read < m) { +				d += sprintf(d, " %02X", 0x000000FF & *p); +			} else if (bytes_read > m) { +			} else +				d += sprintf(d, " .."); +			if (copy_to_user(buffer++, p, 1)) { +				return -EFAULT; +			} else { +				bytes_read += 1; +				goto have; +			} +		} else +			return bytes_read; +	} +more:if (count > 0) { +		int packet_bytes = 0; +		int retval = usb_bulk_msg(ftdi->udev, +					  usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), +					  ftdi->bulk_in_buffer, ftdi->bulk_in_size, +					  &packet_bytes, 50); +		if (packet_bytes > 2) { +			ftdi->bulk_in_left = packet_bytes - 2; +			ftdi->bulk_in_last = 1; +			goto have; +		} else if (retval == -ETIMEDOUT) { +			if (retry_on_timeout-- > 0) { +				goto more; +			} else if (bytes_read > 0) { +				return bytes_read; +			} else +				return retval; +		} else if (retval == 0) { +			if (retry_on_empty-- > 0) { +				goto more; +			} else +				return bytes_read; +		} else +			return retval; +	} else +		return bytes_read;  }  static void ftdi_elan_write_bulk_callback(struct urb *urb) @@ -728,467 +726,460 @@ static void ftdi_elan_write_bulk_callback(struct urb *urb)  	int status = urb->status;  	if (status && !(status == -ENOENT || status == -ECONNRESET || -	    status == -ESHUTDOWN)) { -                dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %" -                        "d\n", urb, status); -        } -        usb_free_coherent(urb->dev, urb->transfer_buffer_length, -                urb->transfer_buffer, urb->transfer_dma); +			status == -ESHUTDOWN)) { +		dev_err(&ftdi->udev->dev, +			"urb=%p write bulk status received: %d\n", urb, status); +	} +	usb_free_coherent(urb->dev, urb->transfer_buffer_length, +			  urb->transfer_buffer, urb->transfer_dma);  }  static int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi, -        char *buf, int command_size, int total_size) -{ -        int ed_commands = 0; -        int b = 0; -        int I = command_size; -        int i = ftdi->command_head; -        while (I-- > 0) { -                struct u132_command *command = &ftdi->command[COMMAND_MASK & -                        i++]; -                int F = command->follows; -                u8 *f = command->buffer; -                if (command->header & 0x80) { -                        ed_commands |= 1 << (0x3 & (command->header >> 5)); -                } -                buf[b++] = command->header; -                buf[b++] = (command->length >> 0) & 0x00FF; -                buf[b++] = (command->length >> 8) & 0x00FF; -                buf[b++] = command->address; -                buf[b++] = command->width; -                while (F-- > 0) { -                        buf[b++] = *f++; -                } -        } -        return ed_commands; +						char *buf, int command_size, int total_size) +{ +	int ed_commands = 0; +	int b = 0; +	int I = command_size; +	int i = ftdi->command_head; +	while (I-- > 0) { +		struct u132_command *command = &ftdi->command[COMMAND_MASK & +							      i++]; +		int F = command->follows; +		u8 *f = command->buffer; +		if (command->header & 0x80) { +			ed_commands |= 1 << (0x3 & (command->header >> 5)); +		} +		buf[b++] = command->header; +		buf[b++] = (command->length >> 0) & 0x00FF; +		buf[b++] = (command->length >> 8) & 0x00FF; +		buf[b++] = command->address; +		buf[b++] = command->width; +		while (F-- > 0) { +			buf[b++] = *f++; +		} +	} +	return ed_commands;  }  static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size)  { -        int total_size = 0; -        int I = command_size; -        int i = ftdi->command_head; -        while (I-- > 0) { -                struct u132_command *command = &ftdi->command[COMMAND_MASK & -                        i++]; -                total_size += 5 + command->follows; -        } return total_size; +	int total_size = 0; +	int I = command_size; +	int i = ftdi->command_head; +	while (I-- > 0) { +		struct u132_command *command = &ftdi->command[COMMAND_MASK & +							      i++]; +		total_size += 5 + command->follows; +	} return total_size;  }  static int ftdi_elan_command_engine(struct usb_ftdi *ftdi)  { -        int retval; -        char *buf; -        int ed_commands; -        int total_size; -        struct urb *urb; -        int command_size = ftdi->command_next - ftdi->command_head; -        if (command_size == 0) -                return 0; -        total_size = ftdi_elan_total_command_size(ftdi, command_size); -        urb = usb_alloc_urb(0, GFP_KERNEL); -        if (!urb) { -                dev_err(&ftdi->udev->dev, "could not get a urb to write %d comm" -                        "ands totaling %d bytes to the Uxxx\n", command_size, -                        total_size); -                return -ENOMEM; -        } -        buf = usb_alloc_coherent(ftdi->udev, total_size, GFP_KERNEL, -                &urb->transfer_dma); -        if (!buf) { -                dev_err(&ftdi->udev->dev, "could not get a buffer to write %d c" -                        "ommands totaling %d bytes to the Uxxx\n", command_size, -                         total_size); -                usb_free_urb(urb); -                return -ENOMEM; -        } -        ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf, -                command_size, total_size); -        usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, -                ftdi->bulk_out_endpointAddr), buf, total_size, -                ftdi_elan_write_bulk_callback, ftdi); -        urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -        if (ed_commands) { -                char diag[40 *3 + 4]; -                char *d = diag; -                int m = total_size; -                u8 *c = buf; -                int s = (sizeof(diag) - 1) / 3; -                diag[0] = 0; -                while (s-- > 0 && m-- > 0) { -                        if (s > 0 || m == 0) { -                                d += sprintf(d, " %02X", *c++); -                        } else -                                d += sprintf(d, " .."); -                } -        } -        retval = usb_submit_urb(urb, GFP_KERNEL); -        if (retval) { -                dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write " -                        "%d commands totaling %d bytes to the Uxxx\n", retval, -                        urb, command_size, total_size); -                usb_free_coherent(ftdi->udev, total_size, buf, urb->transfer_dma); -                usb_free_urb(urb); -                return retval; -        } -        usb_free_urb(urb);        /* release our reference to this urb, -                the USB core will eventually free it entirely */ -        ftdi->command_head += command_size; -        ftdi_elan_kick_respond_queue(ftdi); -        return 0; +	int retval; +	char *buf; +	int ed_commands; +	int total_size; +	struct urb *urb; +	int command_size = ftdi->command_next - ftdi->command_head; +	if (command_size == 0) +		return 0; +	total_size = ftdi_elan_total_command_size(ftdi, command_size); +	urb = usb_alloc_urb(0, GFP_KERNEL); +	if (!urb) { +		dev_err(&ftdi->udev->dev, "could not get a urb to write %d commands totaling %d bytes to the Uxxx\n", +			command_size, total_size); +		return -ENOMEM; +	} +	buf = usb_alloc_coherent(ftdi->udev, total_size, GFP_KERNEL, +				 &urb->transfer_dma); +	if (!buf) { +		dev_err(&ftdi->udev->dev, "could not get a buffer to write %d commands totaling %d bytes to the Uxxx\n", +			command_size, total_size); +		usb_free_urb(urb); +		return -ENOMEM; +	} +	ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf, +							   command_size, total_size); +	usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, +							   ftdi->bulk_out_endpointAddr), buf, total_size, +			  ftdi_elan_write_bulk_callback, ftdi); +	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +	if (ed_commands) { +		char diag[40 *3 + 4]; +		char *d = diag; +		int m = total_size; +		u8 *c = buf; +		int s = (sizeof(diag) - 1) / 3; +		diag[0] = 0; +		while (s-- > 0 && m-- > 0) { +			if (s > 0 || m == 0) { +				d += sprintf(d, " %02X", *c++); +			} else +				d += sprintf(d, " .."); +		} +	} +	retval = usb_submit_urb(urb, GFP_KERNEL); +	if (retval) { +		dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write %d commands totaling %d bytes to the Uxxx\n", +			retval, urb, command_size, total_size); +		usb_free_coherent(ftdi->udev, total_size, buf, urb->transfer_dma); +		usb_free_urb(urb); +		return retval; +	} +	usb_free_urb(urb);        /* release our reference to this urb, +				     the USB core will eventually free it entirely */ +	ftdi->command_head += command_size; +	ftdi_elan_kick_respond_queue(ftdi); +	return 0;  }  static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, -        struct u132_target *target, u8 *buffer, int length) -{ -        struct urb *urb = target->urb; -        int halted = target->halted; -        int skipped = target->skipped; -        int actual = target->actual; -        int non_null = target->non_null; -        int toggle_bits = target->toggle_bits; -        int error_count = target->error_count; -        int condition_code = target->condition_code; -        int repeat_number = target->repeat_number; -        void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int, -                int, int, int, int) = target->callback; -        target->active -= 1; -        target->callback = NULL; -        (*callback) (target->endp, urb, buffer, length, toggle_bits, -                error_count, condition_code, repeat_number, halted, skipped, -                actual, non_null); +				  struct u132_target *target, u8 *buffer, int length) +{ +	struct urb *urb = target->urb; +	int halted = target->halted; +	int skipped = target->skipped; +	int actual = target->actual; +	int non_null = target->non_null; +	int toggle_bits = target->toggle_bits; +	int error_count = target->error_count; +	int condition_code = target->condition_code; +	int repeat_number = target->repeat_number; +	void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int, +			  int, int, int, int) = target->callback; +	target->active -= 1; +	target->callback = NULL; +	(*callback) (target->endp, urb, buffer, length, toggle_bits, +		     error_count, condition_code, repeat_number, halted, skipped, +		     actual, non_null);  }  static char *have_ed_set_response(struct usb_ftdi *ftdi, -        struct u132_target *target, u16 ed_length, int ed_number, int ed_type, -        char *b) -{ -        int payload = (ed_length >> 0) & 0x07FF; -        mutex_lock(&ftdi->u132_lock); -        target->actual = 0; -        target->non_null = (ed_length >> 15) & 0x0001; -        target->repeat_number = (ed_length >> 11) & 0x000F; -        if (ed_type == 0x02) { -                if (payload == 0 || target->abandoning > 0) { -                        target->abandoning = 0; -                        mutex_unlock(&ftdi->u132_lock); -                        ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, -                                payload); -                        ftdi->received = 0; -                        ftdi->expected = 4; -                        ftdi->ed_found = 0; -                        return ftdi->response; -                } else { -                        ftdi->expected = 4 + payload; -                        ftdi->ed_found = 1; -                        mutex_unlock(&ftdi->u132_lock); -                        return b; -                } -        } else if (ed_type == 0x03) { -                if (payload == 0 || target->abandoning > 0) { -                        target->abandoning = 0; -                        mutex_unlock(&ftdi->u132_lock); -                        ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, -                                payload); -                        ftdi->received = 0; -                        ftdi->expected = 4; -                        ftdi->ed_found = 0; -                        return ftdi->response; -                } else { -                        ftdi->expected = 4 + payload; -                        ftdi->ed_found = 1; -                        mutex_unlock(&ftdi->u132_lock); -                        return b; -                } -        } else if (ed_type == 0x01) { -                target->abandoning = 0; -                mutex_unlock(&ftdi->u132_lock); -                ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, -                        payload); -                ftdi->received = 0; -                ftdi->expected = 4; -                ftdi->ed_found = 0; -                return ftdi->response; -        } else { -                target->abandoning = 0; -                mutex_unlock(&ftdi->u132_lock); -                ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, -                        payload); -                ftdi->received = 0; -                ftdi->expected = 4; -                ftdi->ed_found = 0; -                return ftdi->response; -        } +				  struct u132_target *target, u16 ed_length, int ed_number, int ed_type, +				  char *b) +{ +	int payload = (ed_length >> 0) & 0x07FF; +	mutex_lock(&ftdi->u132_lock); +	target->actual = 0; +	target->non_null = (ed_length >> 15) & 0x0001; +	target->repeat_number = (ed_length >> 11) & 0x000F; +	if (ed_type == 0x02) { +		if (payload == 0 || target->abandoning > 0) { +			target->abandoning = 0; +			mutex_unlock(&ftdi->u132_lock); +			ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, +					      payload); +			ftdi->received = 0; +			ftdi->expected = 4; +			ftdi->ed_found = 0; +			return ftdi->response; +		} else { +			ftdi->expected = 4 + payload; +			ftdi->ed_found = 1; +			mutex_unlock(&ftdi->u132_lock); +			return b; +		} +	} else if (ed_type == 0x03) { +		if (payload == 0 || target->abandoning > 0) { +			target->abandoning = 0; +			mutex_unlock(&ftdi->u132_lock); +			ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, +					      payload); +			ftdi->received = 0; +			ftdi->expected = 4; +			ftdi->ed_found = 0; +			return ftdi->response; +		} else { +			ftdi->expected = 4 + payload; +			ftdi->ed_found = 1; +			mutex_unlock(&ftdi->u132_lock); +			return b; +		} +	} else if (ed_type == 0x01) { +		target->abandoning = 0; +		mutex_unlock(&ftdi->u132_lock); +		ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, +				      payload); +		ftdi->received = 0; +		ftdi->expected = 4; +		ftdi->ed_found = 0; +		return ftdi->response; +	} else { +		target->abandoning = 0; +		mutex_unlock(&ftdi->u132_lock); +		ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, +				      payload); +		ftdi->received = 0; +		ftdi->expected = 4; +		ftdi->ed_found = 0; +		return ftdi->response; +	}  }  static char *have_ed_get_response(struct usb_ftdi *ftdi, -        struct u132_target *target, u16 ed_length, int ed_number, int ed_type, -        char *b) +				  struct u132_target *target, u16 ed_length, int ed_number, int ed_type, +				  char *b)  { -        mutex_lock(&ftdi->u132_lock); -        target->condition_code = TD_DEVNOTRESP; -        target->actual = (ed_length >> 0) & 0x01FF; -        target->non_null = (ed_length >> 15) & 0x0001; -        target->repeat_number = (ed_length >> 11) & 0x000F; -        mutex_unlock(&ftdi->u132_lock); -        if (target->active) -                ftdi_elan_do_callback(ftdi, target, NULL, 0); -        target->abandoning = 0; -        ftdi->received = 0; -        ftdi->expected = 4; -        ftdi->ed_found = 0; -        return ftdi->response; +	mutex_lock(&ftdi->u132_lock); +	target->condition_code = TD_DEVNOTRESP; +	target->actual = (ed_length >> 0) & 0x01FF; +	target->non_null = (ed_length >> 15) & 0x0001; +	target->repeat_number = (ed_length >> 11) & 0x000F; +	mutex_unlock(&ftdi->u132_lock); +	if (target->active) +		ftdi_elan_do_callback(ftdi, target, NULL, 0); +	target->abandoning = 0; +	ftdi->received = 0; +	ftdi->expected = 4; +	ftdi->ed_found = 0; +	return ftdi->response;  }  /* -* The engine tries to empty the FTDI fifo -* -* all responses found in the fifo data are dispatched thus -* the response buffer can only ever hold a maximum sized -* response from the Uxxx. -* -*/ + * The engine tries to empty the FTDI fifo + * + * all responses found in the fifo data are dispatched thus + * the response buffer can only ever hold a maximum sized + * response from the Uxxx. + * + */  static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi)  { -        u8 *b = ftdi->response + ftdi->received; -        int bytes_read = 0; -        int retry_on_empty = 1; -        int retry_on_timeout = 3; -        int empty_packets = 0; -      read:{ -                int packet_bytes = 0; -                int retval = usb_bulk_msg(ftdi->udev, -                        usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), -                         ftdi->bulk_in_buffer, ftdi->bulk_in_size, -                        &packet_bytes, 500); -                char diag[30 *3 + 4]; -                char *d = diag; -                int m = packet_bytes; -                u8 *c = ftdi->bulk_in_buffer; -                int s = (sizeof(diag) - 1) / 3; -                diag[0] = 0; -                while (s-- > 0 && m-- > 0) { -                        if (s > 0 || m == 0) { -                                d += sprintf(d, " %02X", *c++); -                        } else -                                d += sprintf(d, " .."); -                } -                if (packet_bytes > 2) { -                        ftdi->bulk_in_left = packet_bytes - 2; -                        ftdi->bulk_in_last = 1; -                        goto have; -                } else if (retval == -ETIMEDOUT) { -                        if (retry_on_timeout-- > 0) { -                                dev_err(&ftdi->udev->dev, "TIMED OUT with packe" -                                        "t_bytes = %d with total %d bytes%s\n", -                                        packet_bytes, bytes_read, diag); -                                goto more; -                        } else if (bytes_read > 0) { -                                dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n", -                                        bytes_read, diag); -                                return -ENOMEM; -                        } else { -                                dev_err(&ftdi->udev->dev, "TIMED OUT with packe" -                                        "t_bytes = %d with total %d bytes%s\n", -                                        packet_bytes, bytes_read, diag); -                                return -ENOMEM; -                        } -                } else if (retval == -EILSEQ) { -                        dev_err(&ftdi->udev->dev, "error = %d with packet_bytes" -                                " = %d with total %d bytes%s\n", retval, -                                packet_bytes, bytes_read, diag); -                        return retval; -                } else if (retval) { -                        dev_err(&ftdi->udev->dev, "error = %d with packet_bytes" -                                " = %d with total %d bytes%s\n", retval, -                                packet_bytes, bytes_read, diag); -                        return retval; -                } else if (packet_bytes == 2) { -                        unsigned char s0 = ftdi->bulk_in_buffer[0]; -                        unsigned char s1 = ftdi->bulk_in_buffer[1]; -                        empty_packets += 1; -                        if (s0 == 0x31 && s1 == 0x60) { -                                if (retry_on_empty-- > 0) { -                                        goto more; -                                } else -                                        return 0; -                        } else if (s0 == 0x31 && s1 == 0x00) { -                                if (retry_on_empty-- > 0) { -                                        goto more; -                                } else -                                        return 0; -                        } else { -                                if (retry_on_empty-- > 0) { -                                        goto more; -                                } else -                                        return 0; -                        } -                } else if (packet_bytes == 1) { -                        if (retry_on_empty-- > 0) { -                                goto more; -                        } else -                                return 0; -                } else { -                        if (retry_on_empty-- > 0) { -                                goto more; -                        } else -                                return 0; -                } -        } -      more:{ -                goto read; -        } -      have:if (ftdi->bulk_in_left > 0) { -                u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last]; -                bytes_read += 1; -                ftdi->bulk_in_left -= 1; -                if (ftdi->received == 0 && c == 0xFF) { -                        goto have; -                } else -                        *b++ = c; -                if (++ftdi->received < ftdi->expected) { -                        goto have; -                } else if (ftdi->ed_found) { -                        int ed_number = (ftdi->response[0] >> 5) & 0x03; -                        u16 ed_length = (ftdi->response[2] << 8) | -                                ftdi->response[1]; -                        struct u132_target *target = &ftdi->target[ed_number]; -                        int payload = (ed_length >> 0) & 0x07FF; -                        char diag[30 *3 + 4]; -                        char *d = diag; -                        int m = payload; -                        u8 *c = 4 + ftdi->response; -                        int s = (sizeof(diag) - 1) / 3; -                        diag[0] = 0; -                        while (s-- > 0 && m-- > 0) { -                                if (s > 0 || m == 0) { -                                        d += sprintf(d, " %02X", *c++); -                                } else -                                        d += sprintf(d, " .."); -                        } -                        ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, -                                payload); -                        ftdi->received = 0; -                        ftdi->expected = 4; -                        ftdi->ed_found = 0; -                        b = ftdi->response; -                        goto have; -                } else if (ftdi->expected == 8) { -                        u8 buscmd; -                        int respond_head = ftdi->respond_head++; -                        struct u132_respond *respond = &ftdi->respond[ -                                RESPOND_MASK & respond_head]; -                        u32 data = ftdi->response[7]; -                        data <<= 8; -                        data |= ftdi->response[6]; -                        data <<= 8; -                        data |= ftdi->response[5]; -                        data <<= 8; -                        data |= ftdi->response[4]; -                        *respond->value = data; -                        *respond->result = 0; -                        complete(&respond->wait_completion); -                        ftdi->received = 0; -                        ftdi->expected = 4; -                        ftdi->ed_found = 0; -                        b = ftdi->response; -                        buscmd = (ftdi->response[0] >> 0) & 0x0F; -                        if (buscmd == 0x00) { -                        } else if (buscmd == 0x02) { -                        } else if (buscmd == 0x06) { -                        } else if (buscmd == 0x0A) { -                        } else -                                dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) va" -                                        "lue = %08X\n", buscmd, data); -                        goto have; -                } else { -                        if ((ftdi->response[0] & 0x80) == 0x00) { -                                ftdi->expected = 8; -                                goto have; -                        } else { -                                int ed_number = (ftdi->response[0] >> 5) & 0x03; -                                int ed_type = (ftdi->response[0] >> 0) & 0x03; -                                u16 ed_length = (ftdi->response[2] << 8) | -                                        ftdi->response[1]; -                                struct u132_target *target = &ftdi->target[ -                                        ed_number]; -                                target->halted = (ftdi->response[0] >> 3) & -                                        0x01; -                                target->skipped = (ftdi->response[0] >> 2) & -                                        0x01; -                                target->toggle_bits = (ftdi->response[3] >> 6) -                                        & 0x03; -                                target->error_count = (ftdi->response[3] >> 4) -                                        & 0x03; -                                target->condition_code = (ftdi->response[ -                                        3] >> 0) & 0x0F; -                                if ((ftdi->response[0] & 0x10) == 0x00) { -                                        b = have_ed_set_response(ftdi, target, -                                                ed_length, ed_number, ed_type, -                                                b); -                                        goto have; -                                } else { -                                        b = have_ed_get_response(ftdi, target, -                                                ed_length, ed_number, ed_type, -                                                b); -                                        goto have; -                                } -                        } -                } -        } else -                goto more; +	u8 *b = ftdi->response + ftdi->received; +	int bytes_read = 0; +	int retry_on_empty = 1; +	int retry_on_timeout = 3; +	int empty_packets = 0; +read:{ +		int packet_bytes = 0; +		int retval = usb_bulk_msg(ftdi->udev, +					  usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), +					  ftdi->bulk_in_buffer, ftdi->bulk_in_size, +					  &packet_bytes, 500); +		char diag[30 *3 + 4]; +		char *d = diag; +		int m = packet_bytes; +		u8 *c = ftdi->bulk_in_buffer; +		int s = (sizeof(diag) - 1) / 3; +		diag[0] = 0; +		while (s-- > 0 && m-- > 0) { +			if (s > 0 || m == 0) { +				d += sprintf(d, " %02X", *c++); +			} else +				d += sprintf(d, " .."); +		} +		if (packet_bytes > 2) { +			ftdi->bulk_in_left = packet_bytes - 2; +			ftdi->bulk_in_last = 1; +			goto have; +		} else if (retval == -ETIMEDOUT) { +			if (retry_on_timeout-- > 0) { +				dev_err(&ftdi->udev->dev, "TIMED OUT with packet_bytes = %d with total %d bytes%s\n", +					packet_bytes, bytes_read, diag); +				goto more; +			} else if (bytes_read > 0) { +				dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n", +					bytes_read, diag); +				return -ENOMEM; +			} else { +				dev_err(&ftdi->udev->dev, "TIMED OUT with packet_bytes = %d with total %d bytes%s\n", +					packet_bytes, bytes_read, diag); +				return -ENOMEM; +			} +		} else if (retval == -EILSEQ) { +			dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n", +				retval, packet_bytes, bytes_read, diag); +			return retval; +		} else if (retval) { +			dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n", +				retval, packet_bytes, bytes_read, diag); +			return retval; +		} else if (packet_bytes == 2) { +			unsigned char s0 = ftdi->bulk_in_buffer[0]; +			unsigned char s1 = ftdi->bulk_in_buffer[1]; +			empty_packets += 1; +			if (s0 == 0x31 && s1 == 0x60) { +				if (retry_on_empty-- > 0) { +					goto more; +				} else +					return 0; +			} else if (s0 == 0x31 && s1 == 0x00) { +				if (retry_on_empty-- > 0) { +					goto more; +				} else +					return 0; +			} else { +				if (retry_on_empty-- > 0) { +					goto more; +				} else +					return 0; +			} +		} else if (packet_bytes == 1) { +			if (retry_on_empty-- > 0) { +				goto more; +			} else +				return 0; +		} else { +			if (retry_on_empty-- > 0) { +				goto more; +			} else +				return 0; +		} +	} +more:{ +		goto read; +	} +have:if (ftdi->bulk_in_left > 0) { +		u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last]; +		bytes_read += 1; +		ftdi->bulk_in_left -= 1; +		if (ftdi->received == 0 && c == 0xFF) { +			goto have; +		} else +			*b++ = c; +		if (++ftdi->received < ftdi->expected) { +			goto have; +		} else if (ftdi->ed_found) { +			int ed_number = (ftdi->response[0] >> 5) & 0x03; +			u16 ed_length = (ftdi->response[2] << 8) | +				ftdi->response[1]; +			struct u132_target *target = &ftdi->target[ed_number]; +			int payload = (ed_length >> 0) & 0x07FF; +			char diag[30 *3 + 4]; +			char *d = diag; +			int m = payload; +			u8 *c = 4 + ftdi->response; +			int s = (sizeof(diag) - 1) / 3; +			diag[0] = 0; +			while (s-- > 0 && m-- > 0) { +				if (s > 0 || m == 0) { +					d += sprintf(d, " %02X", *c++); +				} else +					d += sprintf(d, " .."); +			} +			ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, +					      payload); +			ftdi->received = 0; +			ftdi->expected = 4; +			ftdi->ed_found = 0; +			b = ftdi->response; +			goto have; +		} else if (ftdi->expected == 8) { +			u8 buscmd; +			int respond_head = ftdi->respond_head++; +			struct u132_respond *respond = &ftdi->respond[ +				RESPOND_MASK & respond_head]; +			u32 data = ftdi->response[7]; +			data <<= 8; +			data |= ftdi->response[6]; +			data <<= 8; +			data |= ftdi->response[5]; +			data <<= 8; +			data |= ftdi->response[4]; +			*respond->value = data; +			*respond->result = 0; +			complete(&respond->wait_completion); +			ftdi->received = 0; +			ftdi->expected = 4; +			ftdi->ed_found = 0; +			b = ftdi->response; +			buscmd = (ftdi->response[0] >> 0) & 0x0F; +			if (buscmd == 0x00) { +			} else if (buscmd == 0x02) { +			} else if (buscmd == 0x06) { +			} else if (buscmd == 0x0A) { +			} else +				dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) value = %08X\n", +					buscmd, data); +			goto have; +		} else { +			if ((ftdi->response[0] & 0x80) == 0x00) { +				ftdi->expected = 8; +				goto have; +			} else { +				int ed_number = (ftdi->response[0] >> 5) & 0x03; +				int ed_type = (ftdi->response[0] >> 0) & 0x03; +				u16 ed_length = (ftdi->response[2] << 8) | +					ftdi->response[1]; +				struct u132_target *target = &ftdi->target[ +					ed_number]; +				target->halted = (ftdi->response[0] >> 3) & +					0x01; +				target->skipped = (ftdi->response[0] >> 2) & +					0x01; +				target->toggle_bits = (ftdi->response[3] >> 6) +					& 0x03; +				target->error_count = (ftdi->response[3] >> 4) +					& 0x03; +				target->condition_code = (ftdi->response[ +								  3] >> 0) & 0x0F; +				if ((ftdi->response[0] & 0x10) == 0x00) { +					b = have_ed_set_response(ftdi, target, +								 ed_length, ed_number, ed_type, +								 b); +					goto have; +				} else { +					b = have_ed_get_response(ftdi, target, +								 ed_length, ed_number, ed_type, +								 b); +					goto have; +				} +			} +		} +	} else +		goto more;  }  /* -* create a urb, and a buffer for it, and copy the data to the urb -* -*/ + * create a urb, and a buffer for it, and copy the data to the urb + * + */  static ssize_t ftdi_elan_write(struct file *file,  			       const char __user *user_buffer, size_t count,  			       loff_t *ppos)  { -        int retval = 0; -        struct urb *urb; -        char *buf; -        struct usb_ftdi *ftdi = file->private_data; - -        if (ftdi->disconnected > 0) { -                return -ENODEV; -        } -        if (count == 0) { -                goto exit; -        } -        urb = usb_alloc_urb(0, GFP_KERNEL); -        if (!urb) { -                retval = -ENOMEM; -                goto error_1; -        } -        buf = usb_alloc_coherent(ftdi->udev, count, GFP_KERNEL, -                &urb->transfer_dma); -        if (!buf) { -                retval = -ENOMEM; -                goto error_2; -        } -        if (copy_from_user(buf, user_buffer, count)) { -                retval = -EFAULT; -                goto error_3; -        } -        usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, -                ftdi->bulk_out_endpointAddr), buf, count, -                ftdi_elan_write_bulk_callback, ftdi); -        urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -        retval = usb_submit_urb(urb, GFP_KERNEL); -        if (retval) { -                dev_err(&ftdi->udev->dev, "failed submitting write urb, error %" -                        "d\n", retval); -                goto error_3; -        } -        usb_free_urb(urb); +	int retval = 0; +	struct urb *urb; +	char *buf; +	struct usb_ftdi *ftdi = file->private_data; + +	if (ftdi->disconnected > 0) { +		return -ENODEV; +	} +	if (count == 0) { +		goto exit; +	} +	urb = usb_alloc_urb(0, GFP_KERNEL); +	if (!urb) { +		retval = -ENOMEM; +		goto error_1; +	} +	buf = usb_alloc_coherent(ftdi->udev, count, GFP_KERNEL, +				 &urb->transfer_dma); +	if (!buf) { +		retval = -ENOMEM; +		goto error_2; +	} +	if (copy_from_user(buf, user_buffer, count)) { +		retval = -EFAULT; +		goto error_3; +	} +	usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, +							   ftdi->bulk_out_endpointAddr), buf, count, +			  ftdi_elan_write_bulk_callback, ftdi); +	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +	retval = usb_submit_urb(urb, GFP_KERNEL); +	if (retval) { +		dev_err(&ftdi->udev->dev, +			"failed submitting write urb, error %d\n", retval); +		goto error_3; +	} +	usb_free_urb(urb);  exit: -        return count; +	return count;  error_3:  	usb_free_coherent(ftdi->udev, count, buf, urb->transfer_dma);  error_2: @@ -1198,29 +1189,29 @@ error_1:  }  static const struct file_operations ftdi_elan_fops = { -        .owner = THIS_MODULE, -        .llseek = no_llseek, -        .read = ftdi_elan_read, -        .write = ftdi_elan_write, -        .open = ftdi_elan_open, -        .release = ftdi_elan_release, +	.owner = THIS_MODULE, +	.llseek = no_llseek, +	.read = ftdi_elan_read, +	.write = ftdi_elan_write, +	.open = ftdi_elan_open, +	.release = ftdi_elan_release,  };  /* -* usb class driver info in order to get a minor number from the usb core, -* and to have the device registered with the driver core -*/ + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with the driver core + */  static struct usb_class_driver ftdi_elan_jtag_class = { -        .name = "ftdi-%d-jtag", -        .fops = &ftdi_elan_fops, -        .minor_base = USB_FTDI_ELAN_MINOR_BASE, +	.name = "ftdi-%d-jtag", +	.fops = &ftdi_elan_fops, +	.minor_base = USB_FTDI_ELAN_MINOR_BASE,  };  /* -* the following definitions are for the -* ELAN FPGA state machgine processor that -* lies on the other side of the FTDI chip -*/ + * the following definitions are for the + * ELAN FPGA state machgine processor that + * lies on the other side of the FTDI chip + */  #define cPCIu132rd 0x0  #define cPCIu132wr 0x1  #define cPCIiord 0x2 @@ -1251,1694 +1242,1663 @@ static struct usb_class_driver ftdi_elan_jtag_class = {  #define cCCnotaccessed 0xF  static int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data)  { -      wait:if (ftdi->disconnected > 0) { -                return -ENODEV; -        } else { -                int command_size; -                mutex_lock(&ftdi->u132_lock); -                command_size = ftdi->command_next - ftdi->command_head; -                if (command_size < COMMAND_SIZE) { -                        struct u132_command *command = &ftdi->command[ -                                COMMAND_MASK & ftdi->command_next]; -                        command->header = 0x00 | cPCIu132wr; -                        command->length = 0x04; -                        command->address = 0x00; -                        command->width = 0x00; -                        command->follows = 4; -                        command->value = data; -                        command->buffer = &command->value; -                        ftdi->command_next += 1; -                        ftdi_elan_kick_command_queue(ftdi); -                        mutex_unlock(&ftdi->u132_lock); -                        return 0; -                } else { -                        mutex_unlock(&ftdi->u132_lock); -                        msleep(100); -                        goto wait; -                } -        } +wait:if (ftdi->disconnected > 0) { +		return -ENODEV; +	} else { +		int command_size; +		mutex_lock(&ftdi->u132_lock); +		command_size = ftdi->command_next - ftdi->command_head; +		if (command_size < COMMAND_SIZE) { +			struct u132_command *command = &ftdi->command[ +				COMMAND_MASK & ftdi->command_next]; +			command->header = 0x00 | cPCIu132wr; +			command->length = 0x04; +			command->address = 0x00; +			command->width = 0x00; +			command->follows = 4; +			command->value = data; +			command->buffer = &command->value; +			ftdi->command_next += 1; +			ftdi_elan_kick_command_queue(ftdi); +			mutex_unlock(&ftdi->u132_lock); +			return 0; +		} else { +			mutex_unlock(&ftdi->u132_lock); +			msleep(100); +			goto wait; +		} +	}  }  static int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset, -        u8 width, u32 data) -{ -        u8 addressofs = config_offset / 4; -      wait:if (ftdi->disconnected > 0) { -                return -ENODEV; -        } else { -                int command_size; -                mutex_lock(&ftdi->u132_lock); -                command_size = ftdi->command_next - ftdi->command_head; -                if (command_size < COMMAND_SIZE) { -                        struct u132_command *command = &ftdi->command[ -                                COMMAND_MASK & ftdi->command_next]; -                        command->header = 0x00 | (cPCIcfgwr & 0x0F); -                        command->length = 0x04; -                        command->address = addressofs; -                        command->width = 0x00 | (width & 0x0F); -                        command->follows = 4; -                        command->value = data; -                        command->buffer = &command->value; -                        ftdi->command_next += 1; -                        ftdi_elan_kick_command_queue(ftdi); -                        mutex_unlock(&ftdi->u132_lock); -                        return 0; -                } else { -                        mutex_unlock(&ftdi->u132_lock); -                        msleep(100); -                        goto wait; -                } -        } +				  u8 width, u32 data) +{ +	u8 addressofs = config_offset / 4; +wait:if (ftdi->disconnected > 0) { +		return -ENODEV; +	} else { +		int command_size; +		mutex_lock(&ftdi->u132_lock); +		command_size = ftdi->command_next - ftdi->command_head; +		if (command_size < COMMAND_SIZE) { +			struct u132_command *command = &ftdi->command[ +				COMMAND_MASK & ftdi->command_next]; +			command->header = 0x00 | (cPCIcfgwr & 0x0F); +			command->length = 0x04; +			command->address = addressofs; +			command->width = 0x00 | (width & 0x0F); +			command->follows = 4; +			command->value = data; +			command->buffer = &command->value; +			ftdi->command_next += 1; +			ftdi_elan_kick_command_queue(ftdi); +			mutex_unlock(&ftdi->u132_lock); +			return 0; +		} else { +			mutex_unlock(&ftdi->u132_lock); +			msleep(100); +			goto wait; +		} +	}  }  static int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset, -        u8 width, u32 data) -{ -        u8 addressofs = mem_offset / 4; -      wait:if (ftdi->disconnected > 0) { -                return -ENODEV; -        } else { -                int command_size; -                mutex_lock(&ftdi->u132_lock); -                command_size = ftdi->command_next - ftdi->command_head; -                if (command_size < COMMAND_SIZE) { -                        struct u132_command *command = &ftdi->command[ -                                COMMAND_MASK & ftdi->command_next]; -                        command->header = 0x00 | (cPCImemwr & 0x0F); -                        command->length = 0x04; -                        command->address = addressofs; -                        command->width = 0x00 | (width & 0x0F); -                        command->follows = 4; -                        command->value = data; -                        command->buffer = &command->value; -                        ftdi->command_next += 1; -                        ftdi_elan_kick_command_queue(ftdi); -                        mutex_unlock(&ftdi->u132_lock); -                        return 0; -                } else { -                        mutex_unlock(&ftdi->u132_lock); -                        msleep(100); -                        goto wait; -                } -        } +				  u8 width, u32 data) +{ +	u8 addressofs = mem_offset / 4; +wait:if (ftdi->disconnected > 0) { +		return -ENODEV; +	} else { +		int command_size; +		mutex_lock(&ftdi->u132_lock); +		command_size = ftdi->command_next - ftdi->command_head; +		if (command_size < COMMAND_SIZE) { +			struct u132_command *command = &ftdi->command[ +				COMMAND_MASK & ftdi->command_next]; +			command->header = 0x00 | (cPCImemwr & 0x0F); +			command->length = 0x04; +			command->address = addressofs; +			command->width = 0x00 | (width & 0x0F); +			command->follows = 4; +			command->value = data; +			command->buffer = &command->value; +			ftdi->command_next += 1; +			ftdi_elan_kick_command_queue(ftdi); +			mutex_unlock(&ftdi->u132_lock); +			return 0; +		} else { +			mutex_unlock(&ftdi->u132_lock); +			msleep(100); +			goto wait; +		} +	}  }  int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset, -        u8 width, u32 data) +			       u8 width, u32 data)  { -        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); -        return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data); +	struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); +	return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data);  }  EXPORT_SYMBOL_GPL(usb_ftdi_elan_write_pcimem);  static int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data)  { -      wait:if (ftdi->disconnected > 0) { -                return -ENODEV; -        } else { -                int command_size; -                int respond_size; -                mutex_lock(&ftdi->u132_lock); -                command_size = ftdi->command_next - ftdi->command_head; -                respond_size = ftdi->respond_next - ftdi->respond_head; -                if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) -                        { -                        struct u132_command *command = &ftdi->command[ -                                COMMAND_MASK & ftdi->command_next]; -                        struct u132_respond *respond = &ftdi->respond[ -                                RESPOND_MASK & ftdi->respond_next]; -                        int result = -ENODEV; -                        respond->result = &result; -                        respond->header = command->header = 0x00 | cPCIu132rd; -                        command->length = 0x04; -                        respond->address = command->address = cU132cmd_status; -                        command->width = 0x00; -                        command->follows = 0; -                        command->value = 0; -                        command->buffer = NULL; -                        respond->value = data; -                        init_completion(&respond->wait_completion); -                        ftdi->command_next += 1; -                        ftdi->respond_next += 1; -                        ftdi_elan_kick_command_queue(ftdi); -                        mutex_unlock(&ftdi->u132_lock); -                        wait_for_completion(&respond->wait_completion); -                        return result; -                } else { -                        mutex_unlock(&ftdi->u132_lock); -                        msleep(100); -                        goto wait; -                } -        } +wait:if (ftdi->disconnected > 0) { +		return -ENODEV; +	} else { +		int command_size; +		int respond_size; +		mutex_lock(&ftdi->u132_lock); +		command_size = ftdi->command_next - ftdi->command_head; +		respond_size = ftdi->respond_next - ftdi->respond_head; +		if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) +		{ +			struct u132_command *command = &ftdi->command[ +				COMMAND_MASK & ftdi->command_next]; +			struct u132_respond *respond = &ftdi->respond[ +				RESPOND_MASK & ftdi->respond_next]; +			int result = -ENODEV; +			respond->result = &result; +			respond->header = command->header = 0x00 | cPCIu132rd; +			command->length = 0x04; +			respond->address = command->address = cU132cmd_status; +			command->width = 0x00; +			command->follows = 0; +			command->value = 0; +			command->buffer = NULL; +			respond->value = data; +			init_completion(&respond->wait_completion); +			ftdi->command_next += 1; +			ftdi->respond_next += 1; +			ftdi_elan_kick_command_queue(ftdi); +			mutex_unlock(&ftdi->u132_lock); +			wait_for_completion(&respond->wait_completion); +			return result; +		} else { +			mutex_unlock(&ftdi->u132_lock); +			msleep(100); +			goto wait; +		} +	}  }  static int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset, -        u8 width, u32 *data) -{ -        u8 addressofs = config_offset / 4; -      wait:if (ftdi->disconnected > 0) { -                return -ENODEV; -        } else { -                int command_size; -                int respond_size; -                mutex_lock(&ftdi->u132_lock); -                command_size = ftdi->command_next - ftdi->command_head; -                respond_size = ftdi->respond_next - ftdi->respond_head; -                if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) -                        { -                        struct u132_command *command = &ftdi->command[ -                                COMMAND_MASK & ftdi->command_next]; -                        struct u132_respond *respond = &ftdi->respond[ -                                RESPOND_MASK & ftdi->respond_next]; -                        int result = -ENODEV; -                        respond->result = &result; -                        respond->header = command->header = 0x00 | (cPCIcfgrd & -                                0x0F); -                        command->length = 0x04; -                        respond->address = command->address = addressofs; -                        command->width = 0x00 | (width & 0x0F); -                        command->follows = 0; -                        command->value = 0; -                        command->buffer = NULL; -                        respond->value = data; -                        init_completion(&respond->wait_completion); -                        ftdi->command_next += 1; -                        ftdi->respond_next += 1; -                        ftdi_elan_kick_command_queue(ftdi); -                        mutex_unlock(&ftdi->u132_lock); -                        wait_for_completion(&respond->wait_completion); -                        return result; -                } else { -                        mutex_unlock(&ftdi->u132_lock); -                        msleep(100); -                        goto wait; -                } -        } +				 u8 width, u32 *data) +{ +	u8 addressofs = config_offset / 4; +wait:if (ftdi->disconnected > 0) { +		return -ENODEV; +	} else { +		int command_size; +		int respond_size; +		mutex_lock(&ftdi->u132_lock); +		command_size = ftdi->command_next - ftdi->command_head; +		respond_size = ftdi->respond_next - ftdi->respond_head; +		if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) +		{ +			struct u132_command *command = &ftdi->command[ +				COMMAND_MASK & ftdi->command_next]; +			struct u132_respond *respond = &ftdi->respond[ +				RESPOND_MASK & ftdi->respond_next]; +			int result = -ENODEV; +			respond->result = &result; +			respond->header = command->header = 0x00 | (cPCIcfgrd & +								    0x0F); +			command->length = 0x04; +			respond->address = command->address = addressofs; +			command->width = 0x00 | (width & 0x0F); +			command->follows = 0; +			command->value = 0; +			command->buffer = NULL; +			respond->value = data; +			init_completion(&respond->wait_completion); +			ftdi->command_next += 1; +			ftdi->respond_next += 1; +			ftdi_elan_kick_command_queue(ftdi); +			mutex_unlock(&ftdi->u132_lock); +			wait_for_completion(&respond->wait_completion); +			return result; +		} else { +			mutex_unlock(&ftdi->u132_lock); +			msleep(100); +			goto wait; +		} +	}  }  static int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset, -        u8 width, u32 *data) -{ -        u8 addressofs = mem_offset / 4; -      wait:if (ftdi->disconnected > 0) { -                return -ENODEV; -        } else { -                int command_size; -                int respond_size; -                mutex_lock(&ftdi->u132_lock); -                command_size = ftdi->command_next - ftdi->command_head; -                respond_size = ftdi->respond_next - ftdi->respond_head; -                if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) -                        { -                        struct u132_command *command = &ftdi->command[ -                                COMMAND_MASK & ftdi->command_next]; -                        struct u132_respond *respond = &ftdi->respond[ -                                RESPOND_MASK & ftdi->respond_next]; -                        int result = -ENODEV; -                        respond->result = &result; -                        respond->header = command->header = 0x00 | (cPCImemrd & -                                0x0F); -                        command->length = 0x04; -                        respond->address = command->address = addressofs; -                        command->width = 0x00 | (width & 0x0F); -                        command->follows = 0; -                        command->value = 0; -                        command->buffer = NULL; -                        respond->value = data; -                        init_completion(&respond->wait_completion); -                        ftdi->command_next += 1; -                        ftdi->respond_next += 1; -                        ftdi_elan_kick_command_queue(ftdi); -                        mutex_unlock(&ftdi->u132_lock); -                        wait_for_completion(&respond->wait_completion); -                        return result; -                } else { -                        mutex_unlock(&ftdi->u132_lock); -                        msleep(100); -                        goto wait; -                } -        } +				 u8 width, u32 *data) +{ +	u8 addressofs = mem_offset / 4; +wait:if (ftdi->disconnected > 0) { +		return -ENODEV; +	} else { +		int command_size; +		int respond_size; +		mutex_lock(&ftdi->u132_lock); +		command_size = ftdi->command_next - ftdi->command_head; +		respond_size = ftdi->respond_next - ftdi->respond_head; +		if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) +		{ +			struct u132_command *command = &ftdi->command[ +				COMMAND_MASK & ftdi->command_next]; +			struct u132_respond *respond = &ftdi->respond[ +				RESPOND_MASK & ftdi->respond_next]; +			int result = -ENODEV; +			respond->result = &result; +			respond->header = command->header = 0x00 | (cPCImemrd & +								    0x0F); +			command->length = 0x04; +			respond->address = command->address = addressofs; +			command->width = 0x00 | (width & 0x0F); +			command->follows = 0; +			command->value = 0; +			command->buffer = NULL; +			respond->value = data; +			init_completion(&respond->wait_completion); +			ftdi->command_next += 1; +			ftdi->respond_next += 1; +			ftdi_elan_kick_command_queue(ftdi); +			mutex_unlock(&ftdi->u132_lock); +			wait_for_completion(&respond->wait_completion); +			return result; +		} else { +			mutex_unlock(&ftdi->u132_lock); +			msleep(100); +			goto wait; +		} +	}  }  int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset, -        u8 width, u32 *data) +			      u8 width, u32 *data)  { -        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); -        if (ftdi->initialized == 0) { -                return -ENODEV; -        } else -                return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data); +	struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); +	if (ftdi->initialized == 0) { +		return -ENODEV; +	} else +		return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data);  }  EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_pcimem);  static int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number, -        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, -        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, -        int toggle_bits, int error_count, int condition_code, int repeat_number, -         int halted, int skipped, int actual, int non_null)) -{ -        u8 ed = ed_number - 1; -      wait:if (ftdi->disconnected > 0) { -                return -ENODEV; -        } else if (ftdi->initialized == 0) { -                return -ENODEV; -        } else { -                int command_size; -                mutex_lock(&ftdi->u132_lock); -                command_size = ftdi->command_next - ftdi->command_head; -                if (command_size < COMMAND_SIZE) { -                        struct u132_target *target = &ftdi->target[ed]; -                        struct u132_command *command = &ftdi->command[ -                                COMMAND_MASK & ftdi->command_next]; -                        command->header = 0x80 | (ed << 5); -                        command->length = 0x8007; -                        command->address = (toggle_bits << 6) | (ep_number << 2) -                                | (address << 0); -                        command->width = usb_maxpacket(urb->dev, urb->pipe, -                                usb_pipeout(urb->pipe)); -                        command->follows = 8; -                        command->value = 0; -                        command->buffer = urb->setup_packet; -                        target->callback = callback; -                        target->endp = endp; -                        target->urb = urb; -                        target->active = 1; -                        ftdi->command_next += 1; -                        ftdi_elan_kick_command_queue(ftdi); -                        mutex_unlock(&ftdi->u132_lock); -                        return 0; -                } else { -                        mutex_unlock(&ftdi->u132_lock); -                        msleep(100); -                        goto wait; -                } -        } +				 void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, +				 void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, +						   int toggle_bits, int error_count, int condition_code, int repeat_number, +						   int halted, int skipped, int actual, int non_null)) +{ +	u8 ed = ed_number - 1; +wait:if (ftdi->disconnected > 0) { +		return -ENODEV; +	} else if (ftdi->initialized == 0) { +		return -ENODEV; +	} else { +		int command_size; +		mutex_lock(&ftdi->u132_lock); +		command_size = ftdi->command_next - ftdi->command_head; +		if (command_size < COMMAND_SIZE) { +			struct u132_target *target = &ftdi->target[ed]; +			struct u132_command *command = &ftdi->command[ +				COMMAND_MASK & ftdi->command_next]; +			command->header = 0x80 | (ed << 5); +			command->length = 0x8007; +			command->address = (toggle_bits << 6) | (ep_number << 2) +				| (address << 0); +			command->width = usb_maxpacket(urb->dev, urb->pipe, +						       usb_pipeout(urb->pipe)); +			command->follows = 8; +			command->value = 0; +			command->buffer = urb->setup_packet; +			target->callback = callback; +			target->endp = endp; +			target->urb = urb; +			target->active = 1; +			ftdi->command_next += 1; +			ftdi_elan_kick_command_queue(ftdi); +			mutex_unlock(&ftdi->u132_lock); +			return 0; +		} else { +			mutex_unlock(&ftdi->u132_lock); +			msleep(100); +			goto wait; +		} +	}  }  int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number, -        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, -        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, -        int toggle_bits, int error_count, int condition_code, int repeat_number, -         int halted, int skipped, int actual, int non_null)) +			      void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, +			      void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, +						int toggle_bits, int error_count, int condition_code, int repeat_number, +						int halted, int skipped, int actual, int non_null))  { -        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); -        return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address, -                ep_number, toggle_bits, callback); +	struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); +	return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address, +				     ep_number, toggle_bits, callback);  }  EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_setup);  static int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number, -        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, -        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, -        int toggle_bits, int error_count, int condition_code, int repeat_number, -         int halted, int skipped, int actual, int non_null)) -{ -        u8 ed = ed_number - 1; -      wait:if (ftdi->disconnected > 0) { -                return -ENODEV; -        } else if (ftdi->initialized == 0) { -                return -ENODEV; -        } else { -                int command_size; -                mutex_lock(&ftdi->u132_lock); -                command_size = ftdi->command_next - ftdi->command_head; -                if (command_size < COMMAND_SIZE) { -                        struct u132_target *target = &ftdi->target[ed]; -                        struct u132_command *command = &ftdi->command[ -                                COMMAND_MASK & ftdi->command_next]; -                        u32 remaining_length = urb->transfer_buffer_length - -                                urb->actual_length; -                        command->header = 0x82 | (ed << 5); -                        if (remaining_length == 0) { -                                command->length = 0x0000; -                        } else if (remaining_length > 1024) { -                                command->length = 0x8000 | 1023; -                        } else -                                command->length = 0x8000 | (remaining_length - -                                        1); -                        command->address = (toggle_bits << 6) | (ep_number << 2) -                                | (address << 0); -                        command->width = usb_maxpacket(urb->dev, urb->pipe, -                                usb_pipeout(urb->pipe)); -                        command->follows = 0; -                        command->value = 0; -                        command->buffer = NULL; -                        target->callback = callback; -                        target->endp = endp; -                        target->urb = urb; -                        target->active = 1; -                        ftdi->command_next += 1; -                        ftdi_elan_kick_command_queue(ftdi); -                        mutex_unlock(&ftdi->u132_lock); -                        return 0; -                } else { -                        mutex_unlock(&ftdi->u132_lock); -                        msleep(100); -                        goto wait; -                } -        } +				 void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, +				 void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, +						   int toggle_bits, int error_count, int condition_code, int repeat_number, +						   int halted, int skipped, int actual, int non_null)) +{ +	u8 ed = ed_number - 1; +wait:if (ftdi->disconnected > 0) { +		return -ENODEV; +	} else if (ftdi->initialized == 0) { +		return -ENODEV; +	} else { +		int command_size; +		mutex_lock(&ftdi->u132_lock); +		command_size = ftdi->command_next - ftdi->command_head; +		if (command_size < COMMAND_SIZE) { +			struct u132_target *target = &ftdi->target[ed]; +			struct u132_command *command = &ftdi->command[ +				COMMAND_MASK & ftdi->command_next]; +			u32 remaining_length = urb->transfer_buffer_length - +				urb->actual_length; +			command->header = 0x82 | (ed << 5); +			if (remaining_length == 0) { +				command->length = 0x0000; +			} else if (remaining_length > 1024) { +				command->length = 0x8000 | 1023; +			} else +				command->length = 0x8000 | (remaining_length - +							    1); +			command->address = (toggle_bits << 6) | (ep_number << 2) +				| (address << 0); +			command->width = usb_maxpacket(urb->dev, urb->pipe, +						       usb_pipeout(urb->pipe)); +			command->follows = 0; +			command->value = 0; +			command->buffer = NULL; +			target->callback = callback; +			target->endp = endp; +			target->urb = urb; +			target->active = 1; +			ftdi->command_next += 1; +			ftdi_elan_kick_command_queue(ftdi); +			mutex_unlock(&ftdi->u132_lock); +			return 0; +		} else { +			mutex_unlock(&ftdi->u132_lock); +			msleep(100); +			goto wait; +		} +	}  }  int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number, -        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, -        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, -        int toggle_bits, int error_count, int condition_code, int repeat_number, -         int halted, int skipped, int actual, int non_null)) +			      void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, +			      void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, +						int toggle_bits, int error_count, int condition_code, int repeat_number, +						int halted, int skipped, int actual, int non_null))  { -        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); -        return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address, -                ep_number, toggle_bits, callback); +	struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); +	return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address, +				     ep_number, toggle_bits, callback);  }  EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_input);  static int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number, -        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, -        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, -        int toggle_bits, int error_count, int condition_code, int repeat_number, -         int halted, int skipped, int actual, int non_null)) -{ -        u8 ed = ed_number - 1; -      wait:if (ftdi->disconnected > 0) { -                return -ENODEV; -        } else if (ftdi->initialized == 0) { -                return -ENODEV; -        } else { -                int command_size; -                mutex_lock(&ftdi->u132_lock); -                command_size = ftdi->command_next - ftdi->command_head; -                if (command_size < COMMAND_SIZE) { -                        struct u132_target *target = &ftdi->target[ed]; -                        struct u132_command *command = &ftdi->command[ -                                COMMAND_MASK & ftdi->command_next]; -                        command->header = 0x81 | (ed << 5); -                        command->length = 0x0000; -                        command->address = (toggle_bits << 6) | (ep_number << 2) -                                | (address << 0); -                        command->width = usb_maxpacket(urb->dev, urb->pipe, -                                usb_pipeout(urb->pipe)); -                        command->follows = 0; -                        command->value = 0; -                        command->buffer = NULL; -                        target->callback = callback; -                        target->endp = endp; -                        target->urb = urb; -                        target->active = 1; -                        ftdi->command_next += 1; -                        ftdi_elan_kick_command_queue(ftdi); -                        mutex_unlock(&ftdi->u132_lock); -                        return 0; -                } else { -                        mutex_unlock(&ftdi->u132_lock); -                        msleep(100); -                        goto wait; -                } -        } +				 void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, +				 void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, +						   int toggle_bits, int error_count, int condition_code, int repeat_number, +						   int halted, int skipped, int actual, int non_null)) +{ +	u8 ed = ed_number - 1; +wait:if (ftdi->disconnected > 0) { +		return -ENODEV; +	} else if (ftdi->initialized == 0) { +		return -ENODEV; +	} else { +		int command_size; +		mutex_lock(&ftdi->u132_lock); +		command_size = ftdi->command_next - ftdi->command_head; +		if (command_size < COMMAND_SIZE) { +			struct u132_target *target = &ftdi->target[ed]; +			struct u132_command *command = &ftdi->command[ +				COMMAND_MASK & ftdi->command_next]; +			command->header = 0x81 | (ed << 5); +			command->length = 0x0000; +			command->address = (toggle_bits << 6) | (ep_number << 2) +				| (address << 0); +			command->width = usb_maxpacket(urb->dev, urb->pipe, +						       usb_pipeout(urb->pipe)); +			command->follows = 0; +			command->value = 0; +			command->buffer = NULL; +			target->callback = callback; +			target->endp = endp; +			target->urb = urb; +			target->active = 1; +			ftdi->command_next += 1; +			ftdi_elan_kick_command_queue(ftdi); +			mutex_unlock(&ftdi->u132_lock); +			return 0; +		} else { +			mutex_unlock(&ftdi->u132_lock); +			msleep(100); +			goto wait; +		} +	}  }  int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number, -        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, -        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, -        int toggle_bits, int error_count, int condition_code, int repeat_number, -         int halted, int skipped, int actual, int non_null)) +			      void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, +			      void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, +						int toggle_bits, int error_count, int condition_code, int repeat_number, +						int halted, int skipped, int actual, int non_null))  { -        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); -        return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address, -                ep_number, toggle_bits, callback); +	struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); +	return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address, +				     ep_number, toggle_bits, callback);  }  EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_empty);  static int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number, -        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, -        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, -        int toggle_bits, int error_count, int condition_code, int repeat_number, -         int halted, int skipped, int actual, int non_null)) -{ -        u8 ed = ed_number - 1; -      wait:if (ftdi->disconnected > 0) { -                return -ENODEV; -        } else if (ftdi->initialized == 0) { -                return -ENODEV; -        } else { -                int command_size; -                mutex_lock(&ftdi->u132_lock); -                command_size = ftdi->command_next - ftdi->command_head; -                if (command_size < COMMAND_SIZE) { -                        u8 *b; -                        u16 urb_size; -                        int i = 0; -                        char data[30 *3 + 4]; -                        char *d = data; -                        int m = (sizeof(data) - 1) / 3; -                        int l = 0; -                        struct u132_target *target = &ftdi->target[ed]; -                        struct u132_command *command = &ftdi->command[ -                                COMMAND_MASK & ftdi->command_next]; -                        command->header = 0x81 | (ed << 5); -                        command->address = (toggle_bits << 6) | (ep_number << 2) -                                | (address << 0); -                        command->width = usb_maxpacket(urb->dev, urb->pipe, -                                usb_pipeout(urb->pipe)); -                        command->follows = min_t(u32, 1024, -                                urb->transfer_buffer_length - -                                urb->actual_length); -                        command->value = 0; -                        command->buffer = urb->transfer_buffer + -                                urb->actual_length; -                        command->length = 0x8000 | (command->follows - 1); -                        b = command->buffer; -                        urb_size = command->follows; -                        data[0] = 0; -                        while (urb_size-- > 0) { -                                if (i > m) { -                                } else if (i++ < m) { -                                        int w = sprintf(d, " %02X", *b++); -                                        d += w; -                                        l += w; -                                } else -                                        d += sprintf(d, " .."); -                        } -                        target->callback = callback; -                        target->endp = endp; -                        target->urb = urb; -                        target->active = 1; -                        ftdi->command_next += 1; -                        ftdi_elan_kick_command_queue(ftdi); -                        mutex_unlock(&ftdi->u132_lock); -                        return 0; -                } else { -                        mutex_unlock(&ftdi->u132_lock); -                        msleep(100); -                        goto wait; -                } -        } +				  void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, +				  void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, +						    int toggle_bits, int error_count, int condition_code, int repeat_number, +						    int halted, int skipped, int actual, int non_null)) +{ +	u8 ed = ed_number - 1; +wait:if (ftdi->disconnected > 0) { +		return -ENODEV; +	} else if (ftdi->initialized == 0) { +		return -ENODEV; +	} else { +		int command_size; +		mutex_lock(&ftdi->u132_lock); +		command_size = ftdi->command_next - ftdi->command_head; +		if (command_size < COMMAND_SIZE) { +			u8 *b; +			u16 urb_size; +			int i = 0; +			char data[30 *3 + 4]; +			char *d = data; +			int m = (sizeof(data) - 1) / 3; +			int l = 0; +			struct u132_target *target = &ftdi->target[ed]; +			struct u132_command *command = &ftdi->command[ +				COMMAND_MASK & ftdi->command_next]; +			command->header = 0x81 | (ed << 5); +			command->address = (toggle_bits << 6) | (ep_number << 2) +				| (address << 0); +			command->width = usb_maxpacket(urb->dev, urb->pipe, +						       usb_pipeout(urb->pipe)); +			command->follows = min_t(u32, 1024, +						 urb->transfer_buffer_length - +						 urb->actual_length); +			command->value = 0; +			command->buffer = urb->transfer_buffer + +				urb->actual_length; +			command->length = 0x8000 | (command->follows - 1); +			b = command->buffer; +			urb_size = command->follows; +			data[0] = 0; +			while (urb_size-- > 0) { +				if (i > m) { +				} else if (i++ < m) { +					int w = sprintf(d, " %02X", *b++); +					d += w; +					l += w; +				} else +					d += sprintf(d, " .."); +			} +			target->callback = callback; +			target->endp = endp; +			target->urb = urb; +			target->active = 1; +			ftdi->command_next += 1; +			ftdi_elan_kick_command_queue(ftdi); +			mutex_unlock(&ftdi->u132_lock); +			return 0; +		} else { +			mutex_unlock(&ftdi->u132_lock); +			msleep(100); +			goto wait; +		} +	}  }  int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number, -        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, -        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, -        int toggle_bits, int error_count, int condition_code, int repeat_number, -         int halted, int skipped, int actual, int non_null)) +			       void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, +			       void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, +						 int toggle_bits, int error_count, int condition_code, int repeat_number, +						 int halted, int skipped, int actual, int non_null))  { -        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); -        return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address, -                ep_number, toggle_bits, callback); +	struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); +	return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address, +				      ep_number, toggle_bits, callback);  }  EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_output);  static int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number, -        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, -        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, -        int toggle_bits, int error_count, int condition_code, int repeat_number, -         int halted, int skipped, int actual, int non_null)) -{ -        u8 ed = ed_number - 1; -      wait:if (ftdi->disconnected > 0) { -                return -ENODEV; -        } else if (ftdi->initialized == 0) { -                return -ENODEV; -        } else { -                int command_size; -                mutex_lock(&ftdi->u132_lock); -                command_size = ftdi->command_next - ftdi->command_head; -                if (command_size < COMMAND_SIZE) { -                        u32 remaining_length = urb->transfer_buffer_length - -                                urb->actual_length; -                        struct u132_target *target = &ftdi->target[ed]; -                        struct u132_command *command = &ftdi->command[ -                                COMMAND_MASK & ftdi->command_next]; -                        command->header = 0x83 | (ed << 5); -                        if (remaining_length == 0) { -                                command->length = 0x0000; -                        } else if (remaining_length > 1024) { -                                command->length = 0x8000 | 1023; -                        } else -                                command->length = 0x8000 | (remaining_length - -                                        1); -                        command->address = (toggle_bits << 6) | (ep_number << 2) -                                | (address << 0); -                        command->width = usb_maxpacket(urb->dev, urb->pipe, -                                usb_pipeout(urb->pipe)); -                        command->follows = 0; -                        command->value = 0; -                        command->buffer = NULL; -                        target->callback = callback; -                        target->endp = endp; -                        target->urb = urb; -                        target->active = 1; -                        ftdi->command_next += 1; -                        ftdi_elan_kick_command_queue(ftdi); -                        mutex_unlock(&ftdi->u132_lock); -                        return 0; -                } else { -                        mutex_unlock(&ftdi->u132_lock); -                        msleep(100); -                        goto wait; -                } -        } +				  void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, +				  void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, +						    int toggle_bits, int error_count, int condition_code, int repeat_number, +						    int halted, int skipped, int actual, int non_null)) +{ +	u8 ed = ed_number - 1; +wait:if (ftdi->disconnected > 0) { +		return -ENODEV; +	} else if (ftdi->initialized == 0) { +		return -ENODEV; +	} else { +		int command_size; +		mutex_lock(&ftdi->u132_lock); +		command_size = ftdi->command_next - ftdi->command_head; +		if (command_size < COMMAND_SIZE) { +			u32 remaining_length = urb->transfer_buffer_length - +				urb->actual_length; +			struct u132_target *target = &ftdi->target[ed]; +			struct u132_command *command = &ftdi->command[ +				COMMAND_MASK & ftdi->command_next]; +			command->header = 0x83 | (ed << 5); +			if (remaining_length == 0) { +				command->length = 0x0000; +			} else if (remaining_length > 1024) { +				command->length = 0x8000 | 1023; +			} else +				command->length = 0x8000 | (remaining_length - +							    1); +			command->address = (toggle_bits << 6) | (ep_number << 2) +				| (address << 0); +			command->width = usb_maxpacket(urb->dev, urb->pipe, +						       usb_pipeout(urb->pipe)); +			command->follows = 0; +			command->value = 0; +			command->buffer = NULL; +			target->callback = callback; +			target->endp = endp; +			target->urb = urb; +			target->active = 1; +			ftdi->command_next += 1; +			ftdi_elan_kick_command_queue(ftdi); +			mutex_unlock(&ftdi->u132_lock); +			return 0; +		} else { +			mutex_unlock(&ftdi->u132_lock); +			msleep(100); +			goto wait; +		} +	}  }  int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number, -        void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, -        void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, -        int toggle_bits, int error_count, int condition_code, int repeat_number, -         int halted, int skipped, int actual, int non_null)) +			       void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, +			       void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, +						 int toggle_bits, int error_count, int condition_code, int repeat_number, +						 int halted, int skipped, int actual, int non_null))  { -        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); -        return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address, -                ep_number, toggle_bits, callback); +	struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); +	return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address, +				      ep_number, toggle_bits, callback);  }  EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_single);  static int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number, -        void *endp) -{ -        u8 ed = ed_number - 1; -        if (ftdi->disconnected > 0) { -                return -ENODEV; -        } else if (ftdi->initialized == 0) { -                return -ENODEV; -        } else { -                struct u132_target *target = &ftdi->target[ed]; -                mutex_lock(&ftdi->u132_lock); -                if (target->abandoning > 0) { -                        mutex_unlock(&ftdi->u132_lock); -                        return 0; -                } else { -                        target->abandoning = 1; -                      wait_1:if (target->active == 1) { -                                int command_size = ftdi->command_next - -                                        ftdi->command_head; -                                if (command_size < COMMAND_SIZE) { -                                        struct u132_command *command = -                                                &ftdi->command[COMMAND_MASK & -                                                ftdi->command_next]; -                                        command->header = 0x80 | (ed << 5) | -                                                0x4; -                                        command->length = 0x00; -                                        command->address = 0x00; -                                        command->width = 0x00; -                                        command->follows = 0; -                                        command->value = 0; -                                        command->buffer = &command->value; -                                        ftdi->command_next += 1; -                                        ftdi_elan_kick_command_queue(ftdi); -                                } else { -                                        mutex_unlock(&ftdi->u132_lock); -                                        msleep(100); -                                        mutex_lock(&ftdi->u132_lock); -                                        goto wait_1; -                                } -                        } -                        mutex_unlock(&ftdi->u132_lock); -                        return 0; -                } -        } +				 void *endp) +{ +	u8 ed = ed_number - 1; +	if (ftdi->disconnected > 0) { +		return -ENODEV; +	} else if (ftdi->initialized == 0) { +		return -ENODEV; +	} else { +		struct u132_target *target = &ftdi->target[ed]; +		mutex_lock(&ftdi->u132_lock); +		if (target->abandoning > 0) { +			mutex_unlock(&ftdi->u132_lock); +			return 0; +		} else { +			target->abandoning = 1; +		wait_1:if (target->active == 1) { +				int command_size = ftdi->command_next - +					ftdi->command_head; +				if (command_size < COMMAND_SIZE) { +					struct u132_command *command = +						&ftdi->command[COMMAND_MASK & +							       ftdi->command_next]; +					command->header = 0x80 | (ed << 5) | +						0x4; +					command->length = 0x00; +					command->address = 0x00; +					command->width = 0x00; +					command->follows = 0; +					command->value = 0; +					command->buffer = &command->value; +					ftdi->command_next += 1; +					ftdi_elan_kick_command_queue(ftdi); +				} else { +					mutex_unlock(&ftdi->u132_lock); +					msleep(100); +					mutex_lock(&ftdi->u132_lock); +					goto wait_1; +				} +			} +			mutex_unlock(&ftdi->u132_lock); +			return 0; +		} +	}  }  int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number, -        void *endp) +			      void *endp)  { -        struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); -        return ftdi_elan_edset_flush(ftdi, ed_number, endp); +	struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); +	return ftdi_elan_edset_flush(ftdi, ed_number, endp);  }  EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_flush);  static int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi)  { -        int retry_on_empty = 10; -        int retry_on_timeout = 5; -        int retry_on_status = 20; -      more:{ -                int packet_bytes = 0; -                int retval = usb_bulk_msg(ftdi->udev, -                        usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), -                         ftdi->bulk_in_buffer, ftdi->bulk_in_size, -                        &packet_bytes, 100); -                if (packet_bytes > 2) { -                        char diag[30 *3 + 4]; -                        char *d = diag; -                        int m = (sizeof(diag) - 1) / 3; -                        char *b = ftdi->bulk_in_buffer; -                        int bytes_read = 0; -                        diag[0] = 0; -                        while (packet_bytes-- > 0) { -                                char c = *b++; -                                if (bytes_read < m) { -                                        d += sprintf(d, " %02X", -                                                0x000000FF & c); -                                } else if (bytes_read > m) { -                                } else -                                        d += sprintf(d, " .."); -                                bytes_read += 1; -                                continue; -                        } -                        goto more; -                } else if (packet_bytes > 1) { -                        char s1 = ftdi->bulk_in_buffer[0]; -                        char s2 = ftdi->bulk_in_buffer[1]; -                        if (s1 == 0x31 && s2 == 0x60) { -                                return 0; -                        } else if (retry_on_status-- > 0) { -                                goto more; -                        } else { -                                dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" -                                        "imit reached\n"); -                                return -EFAULT; -                        } -                } else if (packet_bytes > 0) { -                        char b1 = ftdi->bulk_in_buffer[0]; -                        dev_err(&ftdi->udev->dev, "only one byte flushed from F" -                                "TDI = %02X\n", b1); -                        if (retry_on_status-- > 0) { -                                goto more; -                        } else { -                                dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" -                                        "imit reached\n"); -                                return -EFAULT; -                        } -                } else if (retval == -ETIMEDOUT) { -                        if (retry_on_timeout-- > 0) { -                                goto more; -                        } else { -                                dev_err(&ftdi->udev->dev, "TIMED OUT retry limi" -                                        "t reached\n"); -                                return -ENOMEM; -                        } -                } else if (retval == 0) { -                        if (retry_on_empty-- > 0) { -                                goto more; -                        } else { -                                dev_err(&ftdi->udev->dev, "empty packet retry l" -                                        "imit reached\n"); -                                return -ENOMEM; -                        } -                } else { -                        dev_err(&ftdi->udev->dev, "error = %d\n", retval); -                        return retval; -                } -        } -        return -1; +	int retry_on_empty = 10; +	int retry_on_timeout = 5; +	int retry_on_status = 20; +more:{ +		int packet_bytes = 0; +		int retval = usb_bulk_msg(ftdi->udev, +					  usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), +					  ftdi->bulk_in_buffer, ftdi->bulk_in_size, +					  &packet_bytes, 100); +		if (packet_bytes > 2) { +			char diag[30 *3 + 4]; +			char *d = diag; +			int m = (sizeof(diag) - 1) / 3; +			char *b = ftdi->bulk_in_buffer; +			int bytes_read = 0; +			diag[0] = 0; +			while (packet_bytes-- > 0) { +				char c = *b++; +				if (bytes_read < m) { +					d += sprintf(d, " %02X", +						     0x000000FF & c); +				} else if (bytes_read > m) { +				} else +					d += sprintf(d, " .."); +				bytes_read += 1; +				continue; +			} +			goto more; +		} else if (packet_bytes > 1) { +			char s1 = ftdi->bulk_in_buffer[0]; +			char s2 = ftdi->bulk_in_buffer[1]; +			if (s1 == 0x31 && s2 == 0x60) { +				return 0; +			} else if (retry_on_status-- > 0) { +				goto more; +			} else { +				dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); +				return -EFAULT; +			} +		} else if (packet_bytes > 0) { +			char b1 = ftdi->bulk_in_buffer[0]; +			dev_err(&ftdi->udev->dev, "only one byte flushed from FTDI = %02X\n", +				b1); +			if (retry_on_status-- > 0) { +				goto more; +			} else { +				dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); +				return -EFAULT; +			} +		} else if (retval == -ETIMEDOUT) { +			if (retry_on_timeout-- > 0) { +				goto more; +			} else { +				dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); +				return -ENOMEM; +			} +		} else if (retval == 0) { +			if (retry_on_empty-- > 0) { +				goto more; +			} else { +				dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); +				return -ENOMEM; +			} +		} else { +			dev_err(&ftdi->udev->dev, "error = %d\n", retval); +			return retval; +		} +	} +	return -1;  }  /* -* send the long flush sequence -* -*/ + * send the long flush sequence + * + */  static int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi)  { -        int retval; -        struct urb *urb; -        char *buf; -        int I = 257; -        int i = 0; -        urb = usb_alloc_urb(0, GFP_KERNEL); -        if (!urb) { -                dev_err(&ftdi->udev->dev, "could not alloc a urb for flush sequ" -                        "ence\n"); -                return -ENOMEM; -        } -        buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); -        if (!buf) { -                dev_err(&ftdi->udev->dev, "could not get a buffer for flush seq" -                        "uence\n"); -                usb_free_urb(urb); -                return -ENOMEM; -        } -        while (I-- > 0) -                buf[i++] = 0x55; -        usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, -                ftdi->bulk_out_endpointAddr), buf, i, -                ftdi_elan_write_bulk_callback, ftdi); -        urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -        retval = usb_submit_urb(urb, GFP_KERNEL); -        if (retval) { -                dev_err(&ftdi->udev->dev, "failed to submit urb containing the " -                        "flush sequence\n"); -                usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); -                usb_free_urb(urb); -                return -ENOMEM; -        } -        usb_free_urb(urb); -        return 0; +	int retval; +	struct urb *urb; +	char *buf; +	int I = 257; +	int i = 0; +	urb = usb_alloc_urb(0, GFP_KERNEL); +	if (!urb) { +		dev_err(&ftdi->udev->dev, "could not alloc a urb for flush sequence\n"); +		return -ENOMEM; +	} +	buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); +	if (!buf) { +		dev_err(&ftdi->udev->dev, "could not get a buffer for flush sequence\n"); +		usb_free_urb(urb); +		return -ENOMEM; +	} +	while (I-- > 0) +		buf[i++] = 0x55; +	usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, +							   ftdi->bulk_out_endpointAddr), buf, i, +			  ftdi_elan_write_bulk_callback, ftdi); +	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +	retval = usb_submit_urb(urb, GFP_KERNEL); +	if (retval) { +		dev_err(&ftdi->udev->dev, "failed to submit urb containing the flush sequence\n"); +		usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); +		usb_free_urb(urb); +		return -ENOMEM; +	} +	usb_free_urb(urb); +	return 0;  }  /* -* send the reset sequence -* -*/ + * send the reset sequence + * + */  static int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi)  { -        int retval; -        struct urb *urb; -        char *buf; -        int I = 4; -        int i = 0; -        urb = usb_alloc_urb(0, GFP_KERNEL); -        if (!urb) { -                dev_err(&ftdi->udev->dev, "could not get a urb for the reset se" -                        "quence\n"); -                return -ENOMEM; -        } -        buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); -        if (!buf) { -                dev_err(&ftdi->udev->dev, "could not get a buffer for the reset" -                        " sequence\n"); -                usb_free_urb(urb); -                return -ENOMEM; -        } -        buf[i++] = 0x55; -        buf[i++] = 0xAA; -        buf[i++] = 0x5A; -        buf[i++] = 0xA5; -        usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, -                ftdi->bulk_out_endpointAddr), buf, i, -                ftdi_elan_write_bulk_callback, ftdi); -        urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; -        retval = usb_submit_urb(urb, GFP_KERNEL); -        if (retval) { -                dev_err(&ftdi->udev->dev, "failed to submit urb containing the " -                        "reset sequence\n"); -                usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); -                usb_free_urb(urb); -                return -ENOMEM; -        } -        usb_free_urb(urb); -        return 0; +	int retval; +	struct urb *urb; +	char *buf; +	int I = 4; +	int i = 0; +	urb = usb_alloc_urb(0, GFP_KERNEL); +	if (!urb) { +		dev_err(&ftdi->udev->dev, "could not get a urb for the reset sequence\n"); +		return -ENOMEM; +	} +	buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); +	if (!buf) { +		dev_err(&ftdi->udev->dev, "could not get a buffer for the reset sequence\n"); +		usb_free_urb(urb); +		return -ENOMEM; +	} +	buf[i++] = 0x55; +	buf[i++] = 0xAA; +	buf[i++] = 0x5A; +	buf[i++] = 0xA5; +	usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, +							   ftdi->bulk_out_endpointAddr), buf, i, +			  ftdi_elan_write_bulk_callback, ftdi); +	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +	retval = usb_submit_urb(urb, GFP_KERNEL); +	if (retval) { +		dev_err(&ftdi->udev->dev, "failed to submit urb containing the reset sequence\n"); +		usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); +		usb_free_urb(urb); +		return -ENOMEM; +	} +	usb_free_urb(urb); +	return 0;  }  static int ftdi_elan_synchronize(struct usb_ftdi *ftdi)  { -        int retval; -        int long_stop = 10; -        int retry_on_timeout = 5; -        int retry_on_empty = 10; -        int err_count = 0; -        retval = ftdi_elan_flush_input_fifo(ftdi); -        if (retval) -                return retval; -        ftdi->bulk_in_left = 0; -        ftdi->bulk_in_last = -1; -        while (long_stop-- > 0) { -                int read_stop; -                int read_stuck; -                retval = ftdi_elan_synchronize_flush(ftdi); -                if (retval) -                        return retval; -                retval = ftdi_elan_flush_input_fifo(ftdi); -                if (retval) -                        return retval; -              reset:retval = ftdi_elan_synchronize_reset(ftdi); -                if (retval) -                        return retval; -                read_stop = 100; -                read_stuck = 10; -              read:{ -                        int packet_bytes = 0; -                        retval = usb_bulk_msg(ftdi->udev, -                                usb_rcvbulkpipe(ftdi->udev, -                                ftdi->bulk_in_endpointAddr), -                                ftdi->bulk_in_buffer, ftdi->bulk_in_size, -                                &packet_bytes, 500); -                        if (packet_bytes > 2) { -                                char diag[30 *3 + 4]; -                                char *d = diag; -                                int m = (sizeof(diag) - 1) / 3; -                                char *b = ftdi->bulk_in_buffer; -                                int bytes_read = 0; -                                unsigned char c = 0; -                                diag[0] = 0; -                                while (packet_bytes-- > 0) { -                                        c = *b++; -                                        if (bytes_read < m) { -                                                d += sprintf(d, " %02X", c); -                                        } else if (bytes_read > m) { -                                        } else -                                                d += sprintf(d, " .."); -                                        bytes_read += 1; -                                        continue; -                                } -                                if (c == 0x7E) { -                                        return 0; -                                } else { -                                        if (c == 0x55) { -                                                goto read; -                                        } else if (read_stop-- > 0) { -                                                goto read; -                                        } else { -                                                dev_err(&ftdi->udev->dev, "retr" -                                                        "y limit reached\n"); -                                                continue; -                                        } -                                } -                        } else if (packet_bytes > 1) { -                                unsigned char s1 = ftdi->bulk_in_buffer[0]; -                                unsigned char s2 = ftdi->bulk_in_buffer[1]; -                                if (s1 == 0x31 && s2 == 0x00) { -                                        if (read_stuck-- > 0) { -                                                goto read; -                                        } else -                                                goto reset; -                                } else if (s1 == 0x31 && s2 == 0x60) { -                                        if (read_stop-- > 0) { -                                                goto read; -                                        } else { -                                                dev_err(&ftdi->udev->dev, "retr" -                                                        "y limit reached\n"); -                                                continue; -                                        } -                                } else { -                                        if (read_stop-- > 0) { -                                                goto read; -                                        } else { -                                                dev_err(&ftdi->udev->dev, "retr" -                                                        "y limit reached\n"); -                                                continue; -                                        } -                                } -                        } else if (packet_bytes > 0) { -                                if (read_stop-- > 0) { -                                        goto read; -                                } else { -                                        dev_err(&ftdi->udev->dev, "retry limit " -                                                "reached\n"); -                                        continue; -                                } -                        } else if (retval == -ETIMEDOUT) { -                                if (retry_on_timeout-- > 0) { -                                        goto read; -                                } else { -                                        dev_err(&ftdi->udev->dev, "TIMED OUT re" -                                                "try limit reached\n"); -                                        continue; -                                } -                        } else if (retval == 0) { -                                if (retry_on_empty-- > 0) { -                                        goto read; -                                } else { -                                        dev_err(&ftdi->udev->dev, "empty packet" -                                                " retry limit reached\n"); -                                        continue; -                                } -                        } else { -                                err_count += 1; -                                dev_err(&ftdi->udev->dev, "error = %d\n", -                                        retval); -                                if (read_stop-- > 0) { -                                        goto read; -                                } else { -                                        dev_err(&ftdi->udev->dev, "retry limit " -                                                "reached\n"); -                                        continue; -                                } -                        } -                } -        } -        dev_err(&ftdi->udev->dev, "failed to synchronize\n"); -        return -EFAULT; +	int retval; +	int long_stop = 10; +	int retry_on_timeout = 5; +	int retry_on_empty = 10; +	int err_count = 0; +	retval = ftdi_elan_flush_input_fifo(ftdi); +	if (retval) +		return retval; +	ftdi->bulk_in_left = 0; +	ftdi->bulk_in_last = -1; +	while (long_stop-- > 0) { +		int read_stop; +		int read_stuck; +		retval = ftdi_elan_synchronize_flush(ftdi); +		if (retval) +			return retval; +		retval = ftdi_elan_flush_input_fifo(ftdi); +		if (retval) +			return retval; +	reset:retval = ftdi_elan_synchronize_reset(ftdi); +		if (retval) +			return retval; +		read_stop = 100; +		read_stuck = 10; +	read:{ +			int packet_bytes = 0; +			retval = usb_bulk_msg(ftdi->udev, +					      usb_rcvbulkpipe(ftdi->udev, +							      ftdi->bulk_in_endpointAddr), +					      ftdi->bulk_in_buffer, ftdi->bulk_in_size, +					      &packet_bytes, 500); +			if (packet_bytes > 2) { +				char diag[30 *3 + 4]; +				char *d = diag; +				int m = (sizeof(diag) - 1) / 3; +				char *b = ftdi->bulk_in_buffer; +				int bytes_read = 0; +				unsigned char c = 0; +				diag[0] = 0; +				while (packet_bytes-- > 0) { +					c = *b++; +					if (bytes_read < m) { +						d += sprintf(d, " %02X", c); +					} else if (bytes_read > m) { +					} else +						d += sprintf(d, " .."); +					bytes_read += 1; +					continue; +				} +				if (c == 0x7E) { +					return 0; +				} else { +					if (c == 0x55) { +						goto read; +					} else if (read_stop-- > 0) { +						goto read; +					} else { +						dev_err(&ftdi->udev->dev, "retry limit reached\n"); +						continue; +					} +				} +			} else if (packet_bytes > 1) { +				unsigned char s1 = ftdi->bulk_in_buffer[0]; +				unsigned char s2 = ftdi->bulk_in_buffer[1]; +				if (s1 == 0x31 && s2 == 0x00) { +					if (read_stuck-- > 0) { +						goto read; +					} else +						goto reset; +				} else if (s1 == 0x31 && s2 == 0x60) { +					if (read_stop-- > 0) { +						goto read; +					} else { +						dev_err(&ftdi->udev->dev, "retry limit reached\n"); +						continue; +					} +				} else { +					if (read_stop-- > 0) { +						goto read; +					} else { +						dev_err(&ftdi->udev->dev, "retry limit reached\n"); +						continue; +					} +				} +			} else if (packet_bytes > 0) { +				if (read_stop-- > 0) { +					goto read; +				} else { +					dev_err(&ftdi->udev->dev, "retry limit reached\n"); +					continue; +				} +			} else if (retval == -ETIMEDOUT) { +				if (retry_on_timeout-- > 0) { +					goto read; +				} else { +					dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); +					continue; +				} +			} else if (retval == 0) { +				if (retry_on_empty-- > 0) { +					goto read; +				} else { +					dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); +					continue; +				} +			} else { +				err_count += 1; +				dev_err(&ftdi->udev->dev, "error = %d\n", +					retval); +				if (read_stop-- > 0) { +					goto read; +				} else { +					dev_err(&ftdi->udev->dev, "retry limit reached\n"); +					continue; +				} +			} +		} +	} +	dev_err(&ftdi->udev->dev, "failed to synchronize\n"); +	return -EFAULT;  }  static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi)  { -        int retry_on_empty = 10; -        int retry_on_timeout = 5; -        int retry_on_status = 50; -      more:{ -                int packet_bytes = 0; -                int retval = usb_bulk_msg(ftdi->udev, -                        usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), -                         ftdi->bulk_in_buffer, ftdi->bulk_in_size, -                        &packet_bytes, 1000); -                if (packet_bytes > 2) { -                        char diag[30 *3 + 4]; -                        char *d = diag; -                        int m = (sizeof(diag) - 1) / 3; -                        char *b = ftdi->bulk_in_buffer; -                        int bytes_read = 0; -                        diag[0] = 0; -                        while (packet_bytes-- > 0) { -                                char c = *b++; -                                if (bytes_read < m) { -                                        d += sprintf(d, " %02X", -                                                0x000000FF & c); -                                } else if (bytes_read > m) { -                                } else -                                        d += sprintf(d, " .."); -                                bytes_read += 1; -                                continue; -                        } -                        goto more; -                } else if (packet_bytes > 1) { -                        char s1 = ftdi->bulk_in_buffer[0]; -                        char s2 = ftdi->bulk_in_buffer[1]; -                        if (s1 == 0x31 && s2 == 0x60) { -                                return 0; -                        } else if (retry_on_status-- > 0) { -                                msleep(5); -                                goto more; -                        } else -                                return -EFAULT; -                } else if (packet_bytes > 0) { -                        char b1 = ftdi->bulk_in_buffer[0]; -                        dev_err(&ftdi->udev->dev, "only one byte flushed from F" -                                "TDI = %02X\n", b1); -                        if (retry_on_status-- > 0) { -                                msleep(5); -                                goto more; -                        } else { -                                dev_err(&ftdi->udev->dev, "STATUS ERROR retry l" -                                        "imit reached\n"); -                                return -EFAULT; -                        } -                } else if (retval == -ETIMEDOUT) { -                        if (retry_on_timeout-- > 0) { -                                goto more; -                        } else { -                                dev_err(&ftdi->udev->dev, "TIMED OUT retry limi" -                                        "t reached\n"); -                                return -ENOMEM; -                        } -                } else if (retval == 0) { -                        if (retry_on_empty-- > 0) { -                                goto more; -                        } else { -                                dev_err(&ftdi->udev->dev, "empty packet retry l" -                                        "imit reached\n"); -                                return -ENOMEM; -                        } -                } else { -                        dev_err(&ftdi->udev->dev, "error = %d\n", retval); -                        return -ENOMEM; -                } -        } -        return -1; +	int retry_on_empty = 10; +	int retry_on_timeout = 5; +	int retry_on_status = 50; +more:{ +		int packet_bytes = 0; +		int retval = usb_bulk_msg(ftdi->udev, +					  usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), +					  ftdi->bulk_in_buffer, ftdi->bulk_in_size, +					  &packet_bytes, 1000); +		if (packet_bytes > 2) { +			char diag[30 *3 + 4]; +			char *d = diag; +			int m = (sizeof(diag) - 1) / 3; +			char *b = ftdi->bulk_in_buffer; +			int bytes_read = 0; +			diag[0] = 0; +			while (packet_bytes-- > 0) { +				char c = *b++; +				if (bytes_read < m) { +					d += sprintf(d, " %02X", +						     0x000000FF & c); +				} else if (bytes_read > m) { +				} else +					d += sprintf(d, " .."); +				bytes_read += 1; +				continue; +			} +			goto more; +		} else if (packet_bytes > 1) { +			char s1 = ftdi->bulk_in_buffer[0]; +			char s2 = ftdi->bulk_in_buffer[1]; +			if (s1 == 0x31 && s2 == 0x60) { +				return 0; +			} else if (retry_on_status-- > 0) { +				msleep(5); +				goto more; +			} else +				return -EFAULT; +		} else if (packet_bytes > 0) { +			char b1 = ftdi->bulk_in_buffer[0]; +			dev_err(&ftdi->udev->dev, "only one byte flushed from FTDI = %02X\n", b1); +			if (retry_on_status-- > 0) { +				msleep(5); +				goto more; +			} else { +				dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); +				return -EFAULT; +			} +		} else if (retval == -ETIMEDOUT) { +			if (retry_on_timeout-- > 0) { +				goto more; +			} else { +				dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); +				return -ENOMEM; +			} +		} else if (retval == 0) { +			if (retry_on_empty-- > 0) { +				goto more; +			} else { +				dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); +				return -ENOMEM; +			} +		} else { +			dev_err(&ftdi->udev->dev, "error = %d\n", retval); +			return -ENOMEM; +		} +	} +	return -1;  }  static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi)  { -        int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg); -        if (UxxxStatus) -                return UxxxStatus; -        if (ftdi->controlreg & 0x00400000) { -                if (ftdi->card_ejected) { -                } else { -                        ftdi->card_ejected = 1; -                        dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = " -                                "%08X\n", ftdi->controlreg); -                } -                return -ENODEV; -        } else { -                u8 fn = ftdi->function - 1; -                int activePCIfn = fn << 8; -                u32 pcidata; -                u32 pciVID; -                u32 pciPID; -                int reg = 0; -                UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, -                        &pcidata); -                if (UxxxStatus) -                        return UxxxStatus; -                pciVID = pcidata & 0xFFFF; -                pciPID = (pcidata >> 16) & 0xFFFF; -                if (pciVID == ftdi->platform_data.vendor && pciPID == -                        ftdi->platform_data.device) { -                        return 0; -                } else { -                        dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X devi" -                                "ce=%04X pciPID=%04X\n", -                                ftdi->platform_data.vendor, pciVID, -                                ftdi->platform_data.device, pciPID); -                        return -ENODEV; -                } -        } +	int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg); +	if (UxxxStatus) +		return UxxxStatus; +	if (ftdi->controlreg & 0x00400000) { +		if (ftdi->card_ejected) { +		} else { +			ftdi->card_ejected = 1; +			dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = %08X\n", +				ftdi->controlreg); +		} +		return -ENODEV; +	} else { +		u8 fn = ftdi->function - 1; +		int activePCIfn = fn << 8; +		u32 pcidata; +		u32 pciVID; +		u32 pciPID; +		int reg = 0; +		UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, +						   &pcidata); +		if (UxxxStatus) +			return UxxxStatus; +		pciVID = pcidata & 0xFFFF; +		pciPID = (pcidata >> 16) & 0xFFFF; +		if (pciVID == ftdi->platform_data.vendor && pciPID == +		    ftdi->platform_data.device) { +			return 0; +		} else { +			dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X device=%04X pciPID=%04X\n", +				ftdi->platform_data.vendor, pciVID, +				ftdi->platform_data.device, pciPID); +			return -ENODEV; +		} +	}  }  #define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \ -        offsetof(struct ohci_regs, member), 0, data); +								   offsetof(struct ohci_regs, member), 0, data);  #define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \ -        offsetof(struct ohci_regs, member), 0, data); +								     offsetof(struct ohci_regs, member), 0, data);  #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR -#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ -        OHCI_INTR_WDH) +#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD |	\ +			OHCI_INTR_WDH)  static int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk)  { -        int devices = 0; -        int retval; -        u32 hc_control; -        int num_ports; -        u32 control; -        u32 rh_a = -1; -        u32 status; -        u32 fminterval; -        u32 hc_fminterval; -        u32 periodicstart; -        u32 cmdstatus; -        u32 roothub_a; -        int mask = OHCI_INTR_INIT; -        int sleep_time = 0; -        int reset_timeout = 30;        /* ... allow extra time */ -        int temp; -        retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE); -        if (retval) -                return retval; -        retval = ftdi_read_pcimem(ftdi, control, &control); -        if (retval) -                return retval; -        retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a); -        if (retval) -                return retval; -        num_ports = rh_a & RH_A_NDP; -        retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval); -        if (retval) -                return retval; -        hc_fminterval &= 0x3fff; -        if (hc_fminterval != FI) { -        } -        hc_fminterval |= FSMP(hc_fminterval) << 16; -        retval = ftdi_read_pcimem(ftdi, control, &hc_control); -        if (retval) -                return retval; -        switch (hc_control & OHCI_CTRL_HCFS) { -        case OHCI_USB_OPER: -                sleep_time = 0; -                break; -        case OHCI_USB_SUSPEND: -        case OHCI_USB_RESUME: -                hc_control &= OHCI_CTRL_RWC; -                hc_control |= OHCI_USB_RESUME; -                sleep_time = 10; -                break; -        default: -                hc_control &= OHCI_CTRL_RWC; -                hc_control |= OHCI_USB_RESET; -                sleep_time = 50; -                break; -        } -        retval = ftdi_write_pcimem(ftdi, control, hc_control); -        if (retval) -                return retval; -        retval = ftdi_read_pcimem(ftdi, control, &control); -        if (retval) -                return retval; -        msleep(sleep_time); -        retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); -        if (retval) -                return retval; -        if (!(roothub_a & RH_A_NPS)) {        /* power down each port */ -                for (temp = 0; temp < num_ports; temp++) { -                        retval = ftdi_write_pcimem(ftdi, -                                roothub.portstatus[temp], RH_PS_LSDA); -                        if (retval) -                                return retval; -                } -        } -        retval = ftdi_read_pcimem(ftdi, control, &control); -        if (retval) -                return retval; -      retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); -        if (retval) -                return retval; -        retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR); -        if (retval) -                return retval; -      extra:{ -                retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); -                if (retval) -                        return retval; -                if (0 != (status & OHCI_HCR)) { -                        if (--reset_timeout == 0) { -                                dev_err(&ftdi->udev->dev, "USB HC reset timed o" -                                        "ut!\n"); -                                return -ENODEV; -                        } else { -                                msleep(5); -                                goto extra; -                        } -                } -        } -        if (quirk & OHCI_QUIRK_INITRESET) { -                retval = ftdi_write_pcimem(ftdi, control, hc_control); -                if (retval) -                        return retval; -                retval = ftdi_read_pcimem(ftdi, control, &control); -                if (retval) -                        return retval; -        } -        retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000); -        if (retval) -                return retval; -        retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000); -        if (retval) -                return retval; -        retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000); -        if (retval) -                return retval; -        retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); -        if (retval) -                return retval; -        retval = ftdi_write_pcimem(ftdi, fminterval, -                ((fminterval & FIT) ^ FIT) | hc_fminterval); -        if (retval) -                return retval; -        retval = ftdi_write_pcimem(ftdi, periodicstart, -                ((9 *hc_fminterval) / 10) & 0x3fff); -        if (retval) -                return retval; -        retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); -        if (retval) -                return retval; -        retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart); -        if (retval) -                return retval; -        if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { -                if (!(quirk & OHCI_QUIRK_INITRESET)) { -                        quirk |= OHCI_QUIRK_INITRESET; -                        goto retry; -                } else -                        dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n", -                                fminterval, periodicstart); -        }                        /* start controller operations */ -        hc_control &= OHCI_CTRL_RWC; -        hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; -        retval = ftdi_write_pcimem(ftdi, control, hc_control); -        if (retval) -                return retval; -        retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF); -        if (retval) -                return retval; -        retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus); -        if (retval) -                return retval; -        retval = ftdi_read_pcimem(ftdi, control, &control); -        if (retval) -                return retval; -        retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE); -        if (retval) -                return retval; -        retval = ftdi_write_pcimem(ftdi, intrstatus, mask); -        if (retval) -                return retval; -        retval = ftdi_write_pcimem(ftdi, intrdisable, -                OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | -                OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | -                OHCI_INTR_SO); -        if (retval) -                return retval;        /* handle root hub init quirks ... */ -        retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); -        if (retval) -                return retval; -        roothub_a &= ~(RH_A_PSM | RH_A_OCPM); -        if (quirk & OHCI_QUIRK_SUPERIO) { -                roothub_a |= RH_A_NOCP; -                roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); -                retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); -                if (retval) -                        return retval; -        } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) { -                roothub_a |= RH_A_NPS; -                retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); -                if (retval) -                        return retval; -        } -        retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC); -        if (retval) -                return retval; -        retval = ftdi_write_pcimem(ftdi, roothub.b, -                (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); -        if (retval) -                return retval; -        retval = ftdi_read_pcimem(ftdi, control, &control); -        if (retval) -                return retval; -        mdelay((roothub_a >> 23) & 0x1fe); -        for (temp = 0; temp < num_ports; temp++) { -                u32 portstatus; -                retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp], -                        &portstatus); -                if (retval) -                        return retval; -                if (1 & portstatus) -                        devices += 1; -        } -        return devices; +	int devices = 0; +	int retval; +	u32 hc_control; +	int num_ports; +	u32 control; +	u32 rh_a = -1; +	u32 status; +	u32 fminterval; +	u32 hc_fminterval; +	u32 periodicstart; +	u32 cmdstatus; +	u32 roothub_a; +	int mask = OHCI_INTR_INIT; +	int sleep_time = 0; +	int reset_timeout = 30;        /* ... allow extra time */ +	int temp; +	retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE); +	if (retval) +		return retval; +	retval = ftdi_read_pcimem(ftdi, control, &control); +	if (retval) +		return retval; +	retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a); +	if (retval) +		return retval; +	num_ports = rh_a & RH_A_NDP; +	retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval); +	if (retval) +		return retval; +	hc_fminterval &= 0x3fff; +	if (hc_fminterval != FI) { +	} +	hc_fminterval |= FSMP(hc_fminterval) << 16; +	retval = ftdi_read_pcimem(ftdi, control, &hc_control); +	if (retval) +		return retval; +	switch (hc_control & OHCI_CTRL_HCFS) { +	case OHCI_USB_OPER: +		sleep_time = 0; +		break; +	case OHCI_USB_SUSPEND: +	case OHCI_USB_RESUME: +		hc_control &= OHCI_CTRL_RWC; +		hc_control |= OHCI_USB_RESUME; +		sleep_time = 10; +		break; +	default: +		hc_control &= OHCI_CTRL_RWC; +		hc_control |= OHCI_USB_RESET; +		sleep_time = 50; +		break; +	} +	retval = ftdi_write_pcimem(ftdi, control, hc_control); +	if (retval) +		return retval; +	retval = ftdi_read_pcimem(ftdi, control, &control); +	if (retval) +		return retval; +	msleep(sleep_time); +	retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); +	if (retval) +		return retval; +	if (!(roothub_a & RH_A_NPS)) {        /* power down each port */ +		for (temp = 0; temp < num_ports; temp++) { +			retval = ftdi_write_pcimem(ftdi, +						   roothub.portstatus[temp], RH_PS_LSDA); +			if (retval) +				return retval; +		} +	} +	retval = ftdi_read_pcimem(ftdi, control, &control); +	if (retval) +		return retval; +retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); +	if (retval) +		return retval; +	retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR); +	if (retval) +		return retval; +extra:{ +		retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); +		if (retval) +			return retval; +		if (0 != (status & OHCI_HCR)) { +			if (--reset_timeout == 0) { +				dev_err(&ftdi->udev->dev, "USB HC reset timed out!\n"); +				return -ENODEV; +			} else { +				msleep(5); +				goto extra; +			} +		} +	} +	if (quirk & OHCI_QUIRK_INITRESET) { +		retval = ftdi_write_pcimem(ftdi, control, hc_control); +		if (retval) +			return retval; +		retval = ftdi_read_pcimem(ftdi, control, &control); +		if (retval) +			return retval; +	} +	retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000); +	if (retval) +		return retval; +	retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000); +	if (retval) +		return retval; +	retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000); +	if (retval) +		return retval; +	retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); +	if (retval) +		return retval; +	retval = ftdi_write_pcimem(ftdi, fminterval, +				   ((fminterval & FIT) ^ FIT) | hc_fminterval); +	if (retval) +		return retval; +	retval = ftdi_write_pcimem(ftdi, periodicstart, +				   ((9 *hc_fminterval) / 10) & 0x3fff); +	if (retval) +		return retval; +	retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); +	if (retval) +		return retval; +	retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart); +	if (retval) +		return retval; +	if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { +		if (!(quirk & OHCI_QUIRK_INITRESET)) { +			quirk |= OHCI_QUIRK_INITRESET; +			goto retry; +		} else +			dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n", +				fminterval, periodicstart); +	}                        /* start controller operations */ +	hc_control &= OHCI_CTRL_RWC; +	hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; +	retval = ftdi_write_pcimem(ftdi, control, hc_control); +	if (retval) +		return retval; +	retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF); +	if (retval) +		return retval; +	retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus); +	if (retval) +		return retval; +	retval = ftdi_read_pcimem(ftdi, control, &control); +	if (retval) +		return retval; +	retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE); +	if (retval) +		return retval; +	retval = ftdi_write_pcimem(ftdi, intrstatus, mask); +	if (retval) +		return retval; +	retval = ftdi_write_pcimem(ftdi, intrdisable, +				   OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | +				   OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | +				   OHCI_INTR_SO); +	if (retval) +		return retval;        /* handle root hub init quirks ... */ +	retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); +	if (retval) +		return retval; +	roothub_a &= ~(RH_A_PSM | RH_A_OCPM); +	if (quirk & OHCI_QUIRK_SUPERIO) { +		roothub_a |= RH_A_NOCP; +		roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); +		retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); +		if (retval) +			return retval; +	} else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) { +		roothub_a |= RH_A_NPS; +		retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); +		if (retval) +			return retval; +	} +	retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC); +	if (retval) +		return retval; +	retval = ftdi_write_pcimem(ftdi, roothub.b, +				   (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); +	if (retval) +		return retval; +	retval = ftdi_read_pcimem(ftdi, control, &control); +	if (retval) +		return retval; +	mdelay((roothub_a >> 23) & 0x1fe); +	for (temp = 0; temp < num_ports; temp++) { +		u32 portstatus; +		retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp], +					  &portstatus); +		if (retval) +			return retval; +		if (1 & portstatus) +			devices += 1; +	} +	return devices;  }  static int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn)  { -        u32 latence_timer; -        int UxxxStatus; -        u32 pcidata; -        int reg = 0; -        int activePCIfn = fn << 8; -        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); -        if (UxxxStatus) -                return UxxxStatus; -        reg = 16; -        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, -                0xFFFFFFFF); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, -                &pcidata); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, -                0xF0000000); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, -                &pcidata); -        if (UxxxStatus) -                return UxxxStatus; -        reg = 12; -        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, -                &latence_timer); -        if (UxxxStatus) -                return UxxxStatus; -        latence_timer &= 0xFFFF00FF; -        latence_timer |= 0x00001600; -        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, -                latence_timer); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, -                &pcidata); -        if (UxxxStatus) -                return UxxxStatus; -        reg = 4; -        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, -                0x06); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, -                &pcidata); -        if (UxxxStatus) -                return UxxxStatus; -        for (reg = 0; reg <= 0x54; reg += 4) { -                UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); -                if (UxxxStatus) -                        return UxxxStatus; -        } -        return 0; +	u32 latence_timer; +	int UxxxStatus; +	u32 pcidata; +	int reg = 0; +	int activePCIfn = fn << 8; +	UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); +	if (UxxxStatus) +		return UxxxStatus; +	reg = 16; +	UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, +					    0xFFFFFFFF); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, +					   &pcidata); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, +					    0xF0000000); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, +					   &pcidata); +	if (UxxxStatus) +		return UxxxStatus; +	reg = 12; +	UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, +					   &latence_timer); +	if (UxxxStatus) +		return UxxxStatus; +	latence_timer &= 0xFFFF00FF; +	latence_timer |= 0x00001600; +	UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, +					    latence_timer); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, +					   &pcidata); +	if (UxxxStatus) +		return UxxxStatus; +	reg = 4; +	UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, +					    0x06); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, +					   &pcidata); +	if (UxxxStatus) +		return UxxxStatus; +	for (reg = 0; reg <= 0x54; reg += 4) { +		UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); +		if (UxxxStatus) +			return UxxxStatus; +	} +	return 0;  }  static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn)  { -        u32 latence_timer; -        int UxxxStatus; -        u32 pcidata; -        int reg = 0; -        int activePCIfn = fn << 8; -        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); -        if (UxxxStatus) -                return UxxxStatus; -        reg = 16; -        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, -                0xFFFFFFFF); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, -                &pcidata); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, -                0x00000000); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, -                &pcidata); -        if (UxxxStatus) -                return UxxxStatus; -        reg = 12; -        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, -                &latence_timer); -        if (UxxxStatus) -                return UxxxStatus; -        latence_timer &= 0xFFFF00FF; -        latence_timer |= 0x00001600; -        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, -                latence_timer); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, -                &pcidata); -        if (UxxxStatus) -                return UxxxStatus; -        reg = 4; -        UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, -                0x00); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, -                &pcidata); -        if (UxxxStatus) -                return UxxxStatus; -        return 0; +	u32 latence_timer; +	int UxxxStatus; +	u32 pcidata; +	int reg = 0; +	int activePCIfn = fn << 8; +	UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); +	if (UxxxStatus) +		return UxxxStatus; +	reg = 16; +	UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, +					    0xFFFFFFFF); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, +					   &pcidata); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, +					    0x00000000); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, +					   &pcidata); +	if (UxxxStatus) +		return UxxxStatus; +	reg = 12; +	UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, +					   &latence_timer); +	if (UxxxStatus) +		return UxxxStatus; +	latence_timer &= 0xFFFF00FF; +	latence_timer |= 0x00001600; +	UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, +					    latence_timer); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, +					   &pcidata); +	if (UxxxStatus) +		return UxxxStatus; +	reg = 4; +	UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, +					    0x00); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, +					   &pcidata); +	if (UxxxStatus) +		return UxxxStatus; +	return 0;  }  static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk)  { -        int result; -        int UxxxStatus; -        UxxxStatus = ftdi_elan_setup_controller(ftdi, fn); -        if (UxxxStatus) -                return UxxxStatus; -        result = ftdi_elan_check_controller(ftdi, quirk); -        UxxxStatus = ftdi_elan_close_controller(ftdi, fn); -        if (UxxxStatus) -                return UxxxStatus; -        return result; +	int result; +	int UxxxStatus; +	UxxxStatus = ftdi_elan_setup_controller(ftdi, fn); +	if (UxxxStatus) +		return UxxxStatus; +	result = ftdi_elan_check_controller(ftdi, quirk); +	UxxxStatus = ftdi_elan_close_controller(ftdi, fn); +	if (UxxxStatus) +		return UxxxStatus; +	return result;  }  static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)  { -        u32 controlreg; -        u8 sensebits; -        int UxxxStatus; -        UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); -        if (UxxxStatus) -                return UxxxStatus; -        msleep(750); -        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); -        if (UxxxStatus) -                return UxxxStatus; -        msleep(250); -        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); -        if (UxxxStatus) -                return UxxxStatus; -        UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); -        if (UxxxStatus) -                return UxxxStatus; -        msleep(1000); -        sensebits = (controlreg >> 16) & 0x000F; -        if (0x0D == sensebits) -                return 0; -        else +	u32 controlreg; +	u8 sensebits; +	int UxxxStatus; +	UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); +	if (UxxxStatus) +		return UxxxStatus; +	msleep(750); +	UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); +	if (UxxxStatus) +		return UxxxStatus; +	msleep(250); +	UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); +	if (UxxxStatus) +		return UxxxStatus; +	UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); +	if (UxxxStatus) +		return UxxxStatus; +	msleep(1000); +	sensebits = (controlreg >> 16) & 0x000F; +	if (0x0D == sensebits) +		return 0; +	else  		return - ENXIO;  }  static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi)  { -        int UxxxStatus; -        u32 pcidata; -        int reg = 0; -        u8 fn; -        int activePCIfn = 0; -        int max_devices = 0; -        int controllers = 0; -        int unrecognized = 0; -        ftdi->function = 0; -        for (fn = 0; (fn < 4); fn++) { -                u32 pciVID = 0; -                u32 pciPID = 0; -                int devices = 0; -                activePCIfn = fn << 8; -                UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, -                        &pcidata); -                if (UxxxStatus) -                        return UxxxStatus; -                pciVID = pcidata & 0xFFFF; -                pciPID = (pcidata >> 16) & 0xFFFF; -                if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) { -                        devices = ftdi_elan_found_controller(ftdi, fn, 0); -                        controllers += 1; -                } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035)) -                        { -                        devices = ftdi_elan_found_controller(ftdi, fn, 0); -                        controllers += 1; -                } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) { -                        devices = ftdi_elan_found_controller(ftdi, fn, 0); -                        controllers += 1; -                } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802)) -                        { -                        devices = ftdi_elan_found_controller(ftdi, fn, 0); -                        controllers += 1; -                } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) { -                        devices = ftdi_elan_found_controller(ftdi, fn, -                                OHCI_QUIRK_AMD756); -                        controllers += 1; -                } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) { -                        devices = ftdi_elan_found_controller(ftdi, fn, -                                OHCI_QUIRK_ZFMICRO); -                        controllers += 1; -                } else if (0 == pcidata) { -                } else -                        unrecognized += 1; -                if (devices > max_devices) { -                        max_devices = devices; -                        ftdi->function = fn + 1; -                        ftdi->platform_data.vendor = pciVID; -                        ftdi->platform_data.device = pciPID; -                } -        } -        if (ftdi->function > 0) { -                UxxxStatus = ftdi_elan_setup_controller(ftdi, -                        ftdi->function - 1); -                if (UxxxStatus) -                        return UxxxStatus; -                return 0; -        } else if (controllers > 0) { -                return -ENXIO; -        } else if (unrecognized > 0) { -                return -ENXIO; -        } else { -                ftdi->enumerated = 0; -                return -ENXIO; -        } +	int UxxxStatus; +	u32 pcidata; +	int reg = 0; +	u8 fn; +	int activePCIfn = 0; +	int max_devices = 0; +	int controllers = 0; +	int unrecognized = 0; +	ftdi->function = 0; +	for (fn = 0; (fn < 4); fn++) { +		u32 pciVID = 0; +		u32 pciPID = 0; +		int devices = 0; +		activePCIfn = fn << 8; +		UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, +						   &pcidata); +		if (UxxxStatus) +			return UxxxStatus; +		pciVID = pcidata & 0xFFFF; +		pciPID = (pcidata >> 16) & 0xFFFF; +		if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) { +			devices = ftdi_elan_found_controller(ftdi, fn, 0); +			controllers += 1; +		} else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035)) +		{ +			devices = ftdi_elan_found_controller(ftdi, fn, 0); +			controllers += 1; +		} else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) { +			devices = ftdi_elan_found_controller(ftdi, fn, 0); +			controllers += 1; +		} else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802)) +		{ +			devices = ftdi_elan_found_controller(ftdi, fn, 0); +			controllers += 1; +		} else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) { +			devices = ftdi_elan_found_controller(ftdi, fn, +							     OHCI_QUIRK_AMD756); +			controllers += 1; +		} else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) { +			devices = ftdi_elan_found_controller(ftdi, fn, +							     OHCI_QUIRK_ZFMICRO); +			controllers += 1; +		} else if (0 == pcidata) { +		} else +			unrecognized += 1; +		if (devices > max_devices) { +			max_devices = devices; +			ftdi->function = fn + 1; +			ftdi->platform_data.vendor = pciVID; +			ftdi->platform_data.device = pciPID; +		} +	} +	if (ftdi->function > 0) { +		UxxxStatus = ftdi_elan_setup_controller(ftdi, +							ftdi->function - 1); +		if (UxxxStatus) +			return UxxxStatus; +		return 0; +	} else if (controllers > 0) { +		return -ENXIO; +	} else if (unrecognized > 0) { +		return -ENXIO; +	} else { +		ftdi->enumerated = 0; +		return -ENXIO; +	}  }  /* -* we use only the first bulk-in and bulk-out endpoints -*/ + * we use only the first bulk-in and bulk-out endpoints + */  static int ftdi_elan_probe(struct usb_interface *interface, -        const struct usb_device_id *id) +			   const struct usb_device_id *id)  { -        struct usb_host_interface *iface_desc; -        struct usb_endpoint_descriptor *endpoint; -        size_t buffer_size; -        int i; -        int retval = -ENOMEM; -        struct usb_ftdi *ftdi; +	struct usb_host_interface *iface_desc; +	struct usb_endpoint_descriptor *endpoint; +	size_t buffer_size; +	int i; +	int retval = -ENOMEM; +	struct usb_ftdi *ftdi;  	ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL); -	if (!ftdi) { -                printk(KERN_ERR "Out of memory\n"); -                return -ENOMEM; -        } - -        mutex_lock(&ftdi_module_lock); -        list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); -        ftdi->sequence_num = ++ftdi_instances; -        mutex_unlock(&ftdi_module_lock); -        ftdi_elan_init_kref(ftdi); +	if (!ftdi) +		return -ENOMEM; + +	mutex_lock(&ftdi_module_lock); +	list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); +	ftdi->sequence_num = ++ftdi_instances; +	mutex_unlock(&ftdi_module_lock); +	ftdi_elan_init_kref(ftdi);  	sema_init(&ftdi->sw_lock, 1); -        ftdi->udev = usb_get_dev(interface_to_usbdev(interface)); -        ftdi->interface = interface; -        mutex_init(&ftdi->u132_lock); -        ftdi->expected = 4; -        iface_desc = interface->cur_altsetting; -        for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { -                endpoint = &iface_desc->endpoint[i].desc; -                if (!ftdi->bulk_in_endpointAddr && +	ftdi->udev = usb_get_dev(interface_to_usbdev(interface)); +	ftdi->interface = interface; +	mutex_init(&ftdi->u132_lock); +	ftdi->expected = 4; +	iface_desc = interface->cur_altsetting; +	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { +		endpoint = &iface_desc->endpoint[i].desc; +		if (!ftdi->bulk_in_endpointAddr &&  		    usb_endpoint_is_bulk_in(endpoint)) { -                        buffer_size = usb_endpoint_maxp(endpoint); -                        ftdi->bulk_in_size = buffer_size; -                        ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress; -                        ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); -                        if (!ftdi->bulk_in_buffer) { -                                dev_err(&ftdi->udev->dev, "Could not allocate b" -                                        "ulk_in_buffer\n"); -                                retval = -ENOMEM; -                                goto error; -                        } -                } -                if (!ftdi->bulk_out_endpointAddr && +			buffer_size = usb_endpoint_maxp(endpoint); +			ftdi->bulk_in_size = buffer_size; +			ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress; +			ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); +			if (!ftdi->bulk_in_buffer) { +				dev_err(&ftdi->udev->dev, "Could not allocate bulk_in_buffer\n"); +				retval = -ENOMEM; +				goto error; +			} +		} +		if (!ftdi->bulk_out_endpointAddr &&  		    usb_endpoint_is_bulk_out(endpoint)) { -                        ftdi->bulk_out_endpointAddr = -                                endpoint->bEndpointAddress; -                } -        } -        if (!(ftdi->bulk_in_endpointAddr && ftdi->bulk_out_endpointAddr)) { -                dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk" -                        "-out endpoints\n"); -                retval = -ENODEV; -                goto error; -        } -        dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n", -                iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr, -                ftdi->bulk_out_endpointAddr); -        usb_set_intfdata(interface, ftdi); -        if (iface_desc->desc.bInterfaceNumber == 0 && -                ftdi->bulk_in_endpointAddr == 0x81 && -                ftdi->bulk_out_endpointAddr == 0x02) { -                retval = usb_register_dev(interface, &ftdi_elan_jtag_class); -                if (retval) { -                        dev_err(&ftdi->udev->dev, "Not able to get a minor for " -                                "this device.\n"); -                        usb_set_intfdata(interface, NULL); -                        retval = -ENOMEM; -                        goto error; -                } else { -                        ftdi->class = &ftdi_elan_jtag_class; -                        dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface " -                                "%d now attached to ftdi%d\n", ftdi, -                                iface_desc->desc.bInterfaceNumber, -                                interface->minor); -                        return 0; -                } -        } else if (iface_desc->desc.bInterfaceNumber == 1 && -                ftdi->bulk_in_endpointAddr == 0x83 && -                ftdi->bulk_out_endpointAddr == 0x04) { -                ftdi->class = NULL; -                dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now a" -                        "ctivated\n", ftdi, iface_desc->desc.bInterfaceNumber); -                INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work); -                INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work); -                INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work); -                ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); -                return 0; -        } else { -                dev_err(&ftdi->udev->dev, -                        "Could not find ELAN's U132 device\n"); -                retval = -ENODEV; -                goto error; -        } -      error:if (ftdi) { -                ftdi_elan_put_kref(ftdi); -        } -        return retval; +			ftdi->bulk_out_endpointAddr = +				endpoint->bEndpointAddress; +		} +	} +	if (!(ftdi->bulk_in_endpointAddr && ftdi->bulk_out_endpointAddr)) { +		dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk-out endpoints\n"); +		retval = -ENODEV; +		goto error; +	} +	dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n", +		 iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr, +		 ftdi->bulk_out_endpointAddr); +	usb_set_intfdata(interface, ftdi); +	if (iface_desc->desc.bInterfaceNumber == 0 && +	    ftdi->bulk_in_endpointAddr == 0x81 && +	    ftdi->bulk_out_endpointAddr == 0x02) { +		retval = usb_register_dev(interface, &ftdi_elan_jtag_class); +		if (retval) { +			dev_err(&ftdi->udev->dev, "Not able to get a minor for this device\n"); +			usb_set_intfdata(interface, NULL); +			retval = -ENOMEM; +			goto error; +		} else { +			ftdi->class = &ftdi_elan_jtag_class; +			dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface %d now attached to ftdi%d\n", +				 ftdi, iface_desc->desc.bInterfaceNumber, +				 interface->minor); +			return 0; +		} +	} else if (iface_desc->desc.bInterfaceNumber == 1 && +		   ftdi->bulk_in_endpointAddr == 0x83 && +		   ftdi->bulk_out_endpointAddr == 0x04) { +		ftdi->class = NULL; +		dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now activated\n", +			 ftdi, iface_desc->desc.bInterfaceNumber); +		INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work); +		INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work); +		INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work); +		ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); +		return 0; +	} else { +		dev_err(&ftdi->udev->dev, +			"Could not find ELAN's U132 device\n"); +		retval = -ENODEV; +		goto error; +	} +error:if (ftdi) { +		ftdi_elan_put_kref(ftdi); +	} +	return retval;  }  static void ftdi_elan_disconnect(struct usb_interface *interface)  { -        struct usb_ftdi *ftdi = usb_get_intfdata(interface); -        ftdi->disconnected += 1; -        if (ftdi->class) { -                int minor = interface->minor; -                struct usb_class_driver *class = ftdi->class; -                usb_set_intfdata(interface, NULL); -                usb_deregister_dev(interface, class); -                dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on min" -                        "or %d now disconnected\n", minor); -        } else { -                ftdi_status_cancel_work(ftdi); -                ftdi_command_cancel_work(ftdi); -                ftdi_response_cancel_work(ftdi); -                ftdi_elan_abandon_completions(ftdi); -                ftdi_elan_abandon_targets(ftdi); -                if (ftdi->registered) { -                        platform_device_unregister(&ftdi->platform_dev); -                        ftdi->synchronized = 0; -                        ftdi->enumerated = 0; -                        ftdi->initialized = 0; -                        ftdi->registered = 0; -                } -                flush_workqueue(status_queue); -                flush_workqueue(command_queue); -                flush_workqueue(respond_queue); -                ftdi->disconnected += 1; -                usb_set_intfdata(interface, NULL); -                dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller inter" -                        "face now disconnected\n"); -        } -        ftdi_elan_put_kref(ftdi); +	struct usb_ftdi *ftdi = usb_get_intfdata(interface); +	ftdi->disconnected += 1; +	if (ftdi->class) { +		int minor = interface->minor; +		struct usb_class_driver *class = ftdi->class; +		usb_set_intfdata(interface, NULL); +		usb_deregister_dev(interface, class); +		dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on minor %d now disconnected\n", +			 minor); +	} else { +		ftdi_status_cancel_work(ftdi); +		ftdi_command_cancel_work(ftdi); +		ftdi_response_cancel_work(ftdi); +		ftdi_elan_abandon_completions(ftdi); +		ftdi_elan_abandon_targets(ftdi); +		if (ftdi->registered) { +			platform_device_unregister(&ftdi->platform_dev); +			ftdi->synchronized = 0; +			ftdi->enumerated = 0; +			ftdi->initialized = 0; +			ftdi->registered = 0; +		} +		flush_workqueue(status_queue); +		flush_workqueue(command_queue); +		flush_workqueue(respond_queue); +		ftdi->disconnected += 1; +		usb_set_intfdata(interface, NULL); +		dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller interface now disconnected\n"); +	} +	ftdi_elan_put_kref(ftdi);  }  static struct usb_driver ftdi_elan_driver = { -        .name = "ftdi-elan", -        .probe = ftdi_elan_probe, -        .disconnect = ftdi_elan_disconnect, -        .id_table = ftdi_elan_table, +	.name = "ftdi-elan", +	.probe = ftdi_elan_probe, +	.disconnect = ftdi_elan_disconnect, +	.id_table = ftdi_elan_table,  };  static int __init ftdi_elan_init(void)  { -        int result; -        printk(KERN_INFO "driver %s\n", ftdi_elan_driver.name); -        mutex_init(&ftdi_module_lock); -        INIT_LIST_HEAD(&ftdi_static_list); -        status_queue = create_singlethread_workqueue("ftdi-status-control"); +	int result; +	pr_info("driver %s\n", ftdi_elan_driver.name); +	mutex_init(&ftdi_module_lock); +	INIT_LIST_HEAD(&ftdi_static_list); +	status_queue = create_singlethread_workqueue("ftdi-status-control");  	if (!status_queue)  		goto err_status_queue; -        command_queue = create_singlethread_workqueue("ftdi-command-engine"); +	command_queue = create_singlethread_workqueue("ftdi-command-engine");  	if (!command_queue)  		goto err_command_queue; -        respond_queue = create_singlethread_workqueue("ftdi-respond-engine"); +	respond_queue = create_singlethread_workqueue("ftdi-respond-engine");  	if (!respond_queue)  		goto err_respond_queue; -        result = usb_register(&ftdi_elan_driver); -        if (result) { +	result = usb_register(&ftdi_elan_driver); +	if (result) {  		destroy_workqueue(status_queue);  		destroy_workqueue(command_queue);  		destroy_workqueue(respond_queue); -                printk(KERN_ERR "usb_register failed. Error number %d\n", -		       result); +		pr_err("usb_register failed. Error number %d\n", result);  	} -        return result; +	return result; - err_respond_queue: +err_respond_queue:  	destroy_workqueue(command_queue); - err_command_queue: +err_command_queue:  	destroy_workqueue(status_queue); - err_status_queue: -	printk(KERN_ERR "%s couldn't create workqueue\n", ftdi_elan_driver.name); +err_status_queue: +	pr_err("%s couldn't create workqueue\n", ftdi_elan_driver.name);  	return -ENOMEM;  }  static void __exit ftdi_elan_exit(void)  { -        struct usb_ftdi *ftdi; -        struct usb_ftdi *temp; -        usb_deregister(&ftdi_elan_driver); -        printk(KERN_INFO "ftdi_u132 driver deregistered\n"); -        list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) { -                ftdi_status_cancel_work(ftdi); -                ftdi_command_cancel_work(ftdi); -                ftdi_response_cancel_work(ftdi); -        } flush_workqueue(status_queue); -        destroy_workqueue(status_queue); -        status_queue = NULL; -        flush_workqueue(command_queue); -        destroy_workqueue(command_queue); -        command_queue = NULL; -        flush_workqueue(respond_queue); -        destroy_workqueue(respond_queue); -        respond_queue = NULL; +	struct usb_ftdi *ftdi; +	struct usb_ftdi *temp; +	usb_deregister(&ftdi_elan_driver); +	pr_info("ftdi_u132 driver deregistered\n"); +	list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) { +		ftdi_status_cancel_work(ftdi); +		ftdi_command_cancel_work(ftdi); +		ftdi_response_cancel_work(ftdi); +	} flush_workqueue(status_queue); +	destroy_workqueue(status_queue); +	status_queue = NULL; +	flush_workqueue(command_queue); +	destroy_workqueue(command_queue); +	command_queue = NULL; +	flush_workqueue(respond_queue); +	destroy_workqueue(respond_queue); +	respond_queue = NULL;  } diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index ce978384fda..4e38683c653 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -19,7 +19,6 @@  #include <linux/kernel.h>  #include <linux/errno.h>  #include <linux/delay.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/completion.h> @@ -386,7 +385,7 @@ static int idmouse_probe(struct usb_interface *interface,  	result = usb_register_dev(interface, &idmouse_class);  	if (result) {  		/* something prevented us from registering this device */ -		dev_err(&interface->dev, "Unble to allocate minor number.\n"); +		dev_err(&interface->dev, "Unable to allocate minor number.\n");  		usb_set_intfdata(interface, NULL);  		idmouse_delete(dev);  		return result; diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index d36f34e25be..c6bfd13f6c9 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -15,7 +15,6 @@  #include <linux/module.h>  #include <linux/usb.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/sched.h>  #include <linux/mutex.h> @@ -52,19 +51,12 @@  */  #define MAX_WRITES_IN_FLIGHT 4 -/* Use our own dbg macro */ -#undef dbg -#define dbg( format, arg... ) do { if( debug ) printk( KERN_DEBUG __FILE__ ": " format "\n" , ## arg ); } while ( 0 ) -  MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_LICENSE("GPL");  /* Module parameters */  static DEFINE_MUTEX(iowarrior_mutex); -static bool debug = 0; -module_param(debug, bool, 0644); -MODULE_PARM_DESC(debug, "debug=1 enables debugging messages");  static struct usb_driver iowarrior_driver;  static DEFINE_MUTEX(iowarrior_open_disc_lock); @@ -236,8 +228,8 @@ static void iowarrior_write_callback(struct urb *urb)  	if (status &&  	    !(status == -ENOENT ||  	      status == -ECONNRESET || status == -ESHUTDOWN)) { -		dbg("%s - nonzero write bulk status received: %d", -		    __func__, status); +		dev_dbg(&dev->interface->dev, +			"nonzero write bulk status received: %d\n", status);  	}  	/* free up our allocated buffer */  	usb_free_coherent(urb->dev, urb->transfer_buffer_length, @@ -252,7 +244,7 @@ static void iowarrior_write_callback(struct urb *urb)   */  static inline void iowarrior_delete(struct iowarrior *dev)  { -	dbg("%s - minor %d", __func__, dev->minor); +	dev_dbg(&dev->interface->dev, "minor %d\n", dev->minor);  	kfree(dev->int_in_buffer);  	usb_free_urb(dev->int_in_urb);  	kfree(dev->read_queue); @@ -289,7 +281,8 @@ static ssize_t iowarrior_read(struct file *file, char __user *buffer,  	if (dev == NULL || !dev->present)  		return -ENODEV; -	dbg("%s - minor %d, count = %zd", __func__, dev->minor, count); +	dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n", +		dev->minor, count);  	/* read count must be packet size (+ time stamp) */  	if ((count != dev->report_size) @@ -300,7 +293,7 @@ static ssize_t iowarrior_read(struct file *file, char __user *buffer,  	do {  		atomic_set(&dev->overflow_flag, 0);  		if ((read_idx = read_index(dev)) == -1) { -			/* queue emty */ +			/* queue empty */  			if (file->f_flags & O_NONBLOCK)  				return -EAGAIN;  			else { @@ -357,7 +350,8 @@ static ssize_t iowarrior_write(struct file *file,  		retval = -ENODEV;  		goto exit;  	} -	dbg("%s - minor %d, count = %zd", __func__, dev->minor, count); +	dev_dbg(&dev->interface->dev, "minor %d, count = %zd\n", +		dev->minor, count);  	/* if count is 0 we're already done */  	if (count == 0) {  		retval = 0; @@ -419,14 +413,16 @@ static ssize_t iowarrior_write(struct file *file,  		int_out_urb = usb_alloc_urb(0, GFP_KERNEL);  		if (!int_out_urb) {  			retval = -ENOMEM; -			dbg("%s Unable to allocate urb ", __func__); +			dev_dbg(&dev->interface->dev, +				"Unable to allocate urb\n");  			goto error_no_urb;  		}  		buf = usb_alloc_coherent(dev->udev, dev->report_size,  					 GFP_KERNEL, &int_out_urb->transfer_dma);  		if (!buf) {  			retval = -ENOMEM; -			dbg("%s Unable to allocate buffer ", __func__); +			dev_dbg(&dev->interface->dev, +				"Unable to allocate buffer\n");  			goto error_no_buffer;  		}  		usb_fill_int_urb(int_out_urb, dev->udev, @@ -442,8 +438,9 @@ static ssize_t iowarrior_write(struct file *file,  		}  		retval = usb_submit_urb(int_out_urb, GFP_KERNEL);  		if (retval) { -			dbg("%s submit error %d for urb nr.%d", __func__, -			    retval, atomic_read(&dev->write_busy)); +			dev_dbg(&dev->interface->dev, +				"submit error %d for urb nr.%d\n", +				retval, atomic_read(&dev->write_busy));  			goto error;  		}  		/* submit was ok */ @@ -503,8 +500,8 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,  		goto error_out;  	} -	dbg("%s - minor %d, cmd 0x%.4x, arg %ld", __func__, dev->minor, cmd, -	    arg); +	dev_dbg(&dev->interface->dev, "minor %d, cmd 0x%.4x, arg %ld\n", +		dev->minor, cmd, arg);  	retval = 0;  	io_res = 0; @@ -602,8 +599,6 @@ static int iowarrior_open(struct inode *inode, struct file *file)  	int subminor;  	int retval = 0; -	dbg("%s", __func__); -  	mutex_lock(&iowarrior_mutex);  	subminor = iminor(inode); @@ -663,7 +658,7 @@ static int iowarrior_release(struct inode *inode, struct file *file)  		return -ENODEV;  	} -	dbg("%s - minor %d", __func__, dev->minor); +	dev_dbg(&dev->interface->dev, "minor %d\n", dev->minor);  	/* lock our device */  	mutex_lock(&dev->mutex); diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index b1d59532ac2..82503a7ff6c 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -24,7 +24,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/mutex.h> diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index eb37c954205..97cd9e24bd2 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -79,7 +79,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/completion.h> diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index b9b356a9dd1..13731d51262 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -36,7 +36,6 @@  #include <linux/errno.h>  #include <linux/random.h>  #include <linux/poll.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/spinlock.h>  #include <linux/usb.h> diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index de98906f786..06b5d77cd9a 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -2123,8 +2123,8 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)  	u8 tmp8, tmp82, ramtype;  	int bw = 0;  	char *ramtypetext1 = NULL; -	const char *ramtypetext2[] = {	"SDR SDRAM", "SDR SGRAM", -					"DDR SDRAM", "DDR SGRAM" }; +	static const char ram_datarate[4] = {'S', 'S', 'D', 'D'}; +	static const char ram_dynamictype[4] = {'D', 'G', 'D', 'G'};  	static const int busSDR[4]  = {64, 64, 128, 128};  	static const int busDDR[4]  = {32, 32,  64,  64};  	static const int busDDRA[4] = {64+32, 64+32 , (64+32)*2, (64+32)*2}; @@ -2156,8 +2156,10 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)  		break;  	} -	dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1, -			ramtypetext2[ramtype], bw); + +	dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %cDR S%cRAM, bus width %d\n", +		 sisusb->vramsize >> 20, ramtypetext1, +		 ram_datarate[ramtype], ram_dynamictype[ramtype], bw);  }  static int diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c index cb8a3d91f97..bf0032ca35e 100644 --- a/drivers/usb/misc/sisusbvga/sisusb_init.c +++ b/drivers/usb/misc/sisusbvga/sisusb_init.c @@ -40,7 +40,6 @@  #include <linux/kernel.h>  #include <linux/errno.h>  #include <linux/poll.h> -#include <linux/init.h>  #include <linux/spinlock.h>  #include "sisusb.h" diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index 741efed4a23..4145314a515 100644 --- a/drivers/usb/misc/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c @@ -21,7 +21,6 @@  /* Standard include files */  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/usb.h> diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index a31641e18d1..f43c61989ce 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -18,6 +18,7 @@   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   */ +#include <linux/clk.h>  #include <linux/i2c.h>  #include <linux/gpio.h>  #include <linux/delay.h> @@ -57,10 +58,12 @@ struct usb3503 {  	enum usb3503_mode	mode;  	struct regmap		*regmap;  	struct device		*dev; +	struct clk		*clk;  	u8	port_off_mask;  	int	gpio_intn;  	int	gpio_reset;  	int	gpio_connect; +	bool	secondary_ref_clk;  };  static int usb3503_reset(struct usb3503 *hub, int state) @@ -184,8 +187,58 @@ static int usb3503_probe(struct usb3503 *hub)  		hub->gpio_reset		= pdata->gpio_reset;  		hub->mode		= pdata->initial_mode;  	} else if (np) { +		struct clk *clk;  		hub->port_off_mask = 0; +		clk = devm_clk_get(dev, "refclk"); +		if (IS_ERR(clk) && PTR_ERR(clk) != -ENOENT) { +			dev_err(dev, "unable to request refclk (%d)\n", err); +			return PTR_ERR(clk); +		} + +		if (!IS_ERR(clk)) { +			u32 rate = 0; +			hub->clk = clk; + +			if (!of_property_read_u32(np, "refclk-frequency", +						 &rate)) { + +				switch (rate) { +				case 38400000: +				case 26000000: +				case 19200000: +				case 12000000: +					hub->secondary_ref_clk = 0; +					break; +				case 24000000: +				case 27000000: +				case 25000000: +				case 50000000: +					hub->secondary_ref_clk = 1; +					break; +				default: +					dev_err(dev, +						"unsupported reference clock rate (%d)\n", +						(int) rate); +					return -EINVAL; +				} +				err = clk_set_rate(hub->clk, rate); +				if (err) { +					dev_err(dev, +						"unable to set reference clock rate to %d\n", +						(int) rate); +					return err; +				} +			} + +			err = clk_prepare_enable(hub->clk); +			if (err) { +				dev_err(dev, +					"unable to enable reference clock\n"); +				return err; +			} +		} +  		property = of_get_property(np, "disabled-ports", &len);  		if (property && (len / sizeof(u32)) > 0) {  			int i; @@ -213,8 +266,10 @@ static int usb3503_probe(struct usb3503 *hub)  		dev_err(dev, "Ports disabled with no control interface\n");  	if (gpio_is_valid(hub->gpio_intn)) { -		err = devm_gpio_request_one(dev, hub->gpio_intn, -				GPIOF_OUT_INIT_HIGH, "usb3503 intn"); +		int val = hub->secondary_ref_clk ? GPIOF_OUT_INIT_LOW : +						   GPIOF_OUT_INIT_HIGH; +		err = devm_gpio_request_one(dev, hub->gpio_intn, val, +					    "usb3503 intn");  		if (err) {  			dev_err(dev,  				"unable to request GPIO %d as connect pin (%d)\n", diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index 89927bcff97..1184390508e 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -14,7 +14,6 @@   *****************************************************************************/  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/errno.h>  #include <linux/mutex.h> diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c index 12d03e7ad63..bdef0d6eb91 100644 --- a/drivers/usb/misc/usbled.c +++ b/drivers/usb/misc/usbled.c @@ -11,7 +11,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/usb.h> @@ -23,8 +22,27 @@  enum led_type {  	DELCOM_VISUAL_SIGNAL_INDICATOR,  	DREAM_CHEEKY_WEBMAIL_NOTIFIER, +	RISO_KAGAKU_LED  }; +/* the Webmail LED made by RISO KAGAKU CORP. decodes a color index +   internally, we want to keep the red+green+blue sysfs api, so we decode +   from 1-bit RGB to the riso kagaku color index according to this table... */ + +static unsigned const char riso_kagaku_tbl[] = { +/* R+2G+4B -> riso kagaku color index */ +	[0] = 0, /* black   */ +	[1] = 2, /* red     */ +	[2] = 1, /* green   */ +	[3] = 5, /* yellow  */ +	[4] = 3, /* blue    */ +	[5] = 6, /* magenta */ +	[6] = 4, /* cyan    */ +	[7] = 7  /* white   */ +}; + +#define RISO_KAGAKU_IX(r,g,b) riso_kagaku_tbl[((r)?1:0)+((g)?2:0)+((b)?4:0)] +  /* table of devices that work with this driver */  static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(0x0fc5, 0x1223), @@ -33,6 +51,8 @@ static const struct usb_device_id id_table[] = {  			.driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },  	{ USB_DEVICE(0x1d34, 0x000a),  			.driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER }, +	{ USB_DEVICE(0x1294, 0x1320), +			.driver_info = RISO_KAGAKU_LED },  	{ },  };  MODULE_DEVICE_TABLE(usb, id_table); @@ -49,6 +69,7 @@ static void change_color(struct usb_led *led)  {  	int retval = 0;  	unsigned char *buffer; +	int actlength;  	buffer = kmalloc(8, GFP_KERNEL);  	if (!buffer) { @@ -105,6 +126,18 @@ static void change_color(struct usb_led *led)  					2000);  		break; +	case RISO_KAGAKU_LED: +		buffer[0] = RISO_KAGAKU_IX(led->red, led->green, led->blue); +		buffer[1] = 0; +		buffer[2] = 0; +		buffer[3] = 0; +		buffer[4] = 0; + +		retval = usb_interrupt_msg(led->udev, +			usb_sndctrlpipe(led->udev, 2), +			buffer, 5, &actlength, 1000 /*ms timeout*/); +		break; +  	default:  		dev_err(&led->udev->dev, "unknown device type %d\n", led->type);  	} diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c index b2d82b93739..1fe6b73c22f 100644 --- a/drivers/usb/misc/usbsevseg.c +++ b/drivers/usb/misc/usbsevseg.c @@ -12,7 +12,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/string.h> @@ -57,7 +56,7 @@ struct usb_sevsegdev {   * if str commands are used, we would assume the end of string   * so mem commands are used.   */ -inline size_t my_memlen(const char *buf, size_t count) +static inline size_t my_memlen(const char *buf, size_t count)  {  	if (count > 0 && buf[count-1] == '\n')  		return count - 1; diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index aa28ac8c760..829f446064e 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -7,9 +7,10 @@  #include <linux/moduleparam.h>  #include <linux/scatterlist.h>  #include <linux/mutex.h> - +#include <linux/timer.h>  #include <linux/usb.h> +#define SIMPLE_IO_TIMEOUT	10000	/* in milliseconds */  /*-------------------------------------------------------------------------*/ @@ -120,7 +121,7 @@ get_endpoints(struct usbtest_dev *dev, struct usb_interface *intf)  			struct usb_host_endpoint	*e;  			e = alt->endpoint + ep; -			switch (e->desc.bmAttributes) { +			switch (usb_endpoint_type(&e->desc)) {  			case USB_ENDPOINT_XFER_BULK:  				break;  			case USB_ENDPOINT_XFER_ISOC: @@ -366,6 +367,7 @@ static int simple_io(  	int			max = urb->transfer_buffer_length;  	struct completion	completion;  	int			retval = 0; +	unsigned long		expire;  	urb->context = &completion;  	while (retval == 0 && iterations-- > 0) { @@ -378,9 +380,15 @@ static int simple_io(  		if (retval != 0)  			break; -		/* NOTE:  no timeouts; can't be broken out of by interrupt */ -		wait_for_completion(&completion); -		retval = urb->status; +		expire = msecs_to_jiffies(SIMPLE_IO_TIMEOUT); +		if (!wait_for_completion_timeout(&completion, expire)) { +			usb_kill_urb(urb); +			retval = (urb->status == -ENOENT ? +				  -ETIMEDOUT : urb->status); +		} else { +			retval = urb->status; +		} +  		urb->dev = udev;  		if (retval == 0 && usb_pipein(urb->pipe))  			retval = simple_check_buf(tdev, urb); @@ -437,7 +445,7 @@ alloc_sglist(int nents, int max, int vary)  	if (max == 0)  		return NULL; -	sg = kmalloc_array(nents, sizeof *sg, GFP_KERNEL); +	sg = kmalloc_array(nents, sizeof(*sg), GFP_KERNEL);  	if (!sg)  		return NULL;  	sg_init_table(sg, nents); @@ -476,6 +484,14 @@ alloc_sglist(int nents, int max, int vary)  	return sg;  } +static void sg_timeout(unsigned long _req) +{ +	struct usb_sg_request	*req = (struct usb_sg_request *) _req; + +	req->status = -ETIMEDOUT; +	usb_sg_cancel(req); +} +  static int perform_sglist(  	struct usbtest_dev	*tdev,  	unsigned		iterations, @@ -487,6 +503,9 @@ static int perform_sglist(  {  	struct usb_device	*udev = testdev_to_usbdev(tdev);  	int			retval = 0; +	struct timer_list	sg_timer; + +	setup_timer_on_stack(&sg_timer, sg_timeout, (unsigned long) req);  	while (retval == 0 && iterations-- > 0) {  		retval = usb_sg_init(req, udev, pipe, @@ -497,7 +516,10 @@ static int perform_sglist(  		if (retval)  			break; +		mod_timer(&sg_timer, jiffies + +				msecs_to_jiffies(SIMPLE_IO_TIMEOUT));  		usb_sg_wait(req); +		del_timer_sync(&sg_timer);  		retval = req->status;  		/* FIXME check resulting data pattern */ @@ -573,7 +595,7 @@ static int is_good_config(struct usbtest_dev *tdev, int len)  {  	struct usb_config_descriptor	*config; -	if (len < sizeof *config) +	if (len < sizeof(*config))  		return 0;  	config = (struct usb_config_descriptor *) tdev->buf; @@ -606,6 +628,76 @@ static int is_good_config(struct usbtest_dev *tdev, int len)  	return 0;  } +static int is_good_ext(struct usbtest_dev *tdev, u8 *buf) +{ +	struct usb_ext_cap_descriptor *ext; +	u32 attr; + +	ext = (struct usb_ext_cap_descriptor *) buf; + +	if (ext->bLength != USB_DT_USB_EXT_CAP_SIZE) { +		ERROR(tdev, "bogus usb 2.0 extension descriptor length\n"); +		return 0; +	} + +	attr = le32_to_cpu(ext->bmAttributes); +	/* bits[1:15] is used and others are reserved */ +	if (attr & ~0xfffe) {	/* reserved == 0 */ +		ERROR(tdev, "reserved bits set\n"); +		return 0; +	} + +	return 1; +} + +static int is_good_ss_cap(struct usbtest_dev *tdev, u8 *buf) +{ +	struct usb_ss_cap_descriptor *ss; + +	ss = (struct usb_ss_cap_descriptor *) buf; + +	if (ss->bLength != USB_DT_USB_SS_CAP_SIZE) { +		ERROR(tdev, "bogus superspeed device capability descriptor length\n"); +		return 0; +	} + +	/* +	 * only bit[1] of bmAttributes is used for LTM and others are +	 * reserved +	 */ +	if (ss->bmAttributes & ~0x02) {	/* reserved == 0 */ +		ERROR(tdev, "reserved bits set in bmAttributes\n"); +		return 0; +	} + +	/* bits[0:3] of wSpeedSupported is used and others are reserved */ +	if (le16_to_cpu(ss->wSpeedSupported) & ~0x0f) {	/* reserved == 0 */ +		ERROR(tdev, "reserved bits set in wSpeedSupported\n"); +		return 0; +	} + +	return 1; +} + +static int is_good_con_id(struct usbtest_dev *tdev, u8 *buf) +{ +	struct usb_ss_container_id_descriptor *con_id; + +	con_id = (struct usb_ss_container_id_descriptor *) buf; + +	if (con_id->bLength != USB_DT_USB_SS_CONTN_ID_SIZE) { +		ERROR(tdev, "bogus container id descriptor length\n"); +		return 0; +	} + +	if (con_id->bReserved) {	/* reserved == 0 */ +		ERROR(tdev, "reserved bits set\n"); +		return 0; +	} + +	return 1; +} +  /* sanity test for standard requests working with usb_control_mesg() and some   * of the utility functions which use it.   * @@ -683,12 +775,96 @@ static int ch9_postconfig(struct usbtest_dev *dev)  	/* there's always [9.4.3] a device descriptor [9.6.1] */  	retval = usb_get_descriptor(udev, USB_DT_DEVICE, 0, -			dev->buf, sizeof udev->descriptor); -	if (retval != sizeof udev->descriptor) { +			dev->buf, sizeof(udev->descriptor)); +	if (retval != sizeof(udev->descriptor)) {  		dev_err(&iface->dev, "dev descriptor --> %d\n", retval);  		return (retval < 0) ? retval : -EDOM;  	} +	/* +	 * there's always [9.4.3] a bos device descriptor [9.6.2] in USB +	 * 3.0 spec +	 */ +	if (le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0210) { +		struct usb_bos_descriptor *bos = NULL; +		struct usb_dev_cap_header *header = NULL; +		unsigned total, num, length; +		u8 *buf; + +		retval = usb_get_descriptor(udev, USB_DT_BOS, 0, dev->buf, +				sizeof(*udev->bos->desc)); +		if (retval != sizeof(*udev->bos->desc)) { +			dev_err(&iface->dev, "bos descriptor --> %d\n", retval); +			return (retval < 0) ? retval : -EDOM; +		} + +		bos = (struct usb_bos_descriptor *)dev->buf; +		total = le16_to_cpu(bos->wTotalLength); +		num = bos->bNumDeviceCaps; + +		if (total > TBUF_SIZE) +			total = TBUF_SIZE; + +		/* +		 * get generic device-level capability descriptors [9.6.2] +		 * in USB 3.0 spec +		 */ +		retval = usb_get_descriptor(udev, USB_DT_BOS, 0, dev->buf, +				total); +		if (retval != total) { +			dev_err(&iface->dev, "bos descriptor set --> %d\n", +					retval); +			return (retval < 0) ? retval : -EDOM; +		} + +		length = sizeof(*udev->bos->desc); +		buf = dev->buf; +		for (i = 0; i < num; i++) { +			buf += length; +			if (buf + sizeof(struct usb_dev_cap_header) > +					dev->buf + total) +				break; + +			header = (struct usb_dev_cap_header *)buf; +			length = header->bLength; + +			if (header->bDescriptorType != +					USB_DT_DEVICE_CAPABILITY) { +				dev_warn(&udev->dev, "not device capability descriptor, skip\n"); +				continue; +			} + +			switch (header->bDevCapabilityType) { +			case USB_CAP_TYPE_EXT: +				if (buf + USB_DT_USB_EXT_CAP_SIZE > +						dev->buf + total || +						!is_good_ext(dev, buf)) { +					dev_err(&iface->dev, "bogus usb 2.0 extension descriptor\n"); +					return -EDOM; +				} +				break; +			case USB_SS_CAP_TYPE: +				if (buf + USB_DT_USB_SS_CAP_SIZE > +						dev->buf + total || +						!is_good_ss_cap(dev, buf)) { +					dev_err(&iface->dev, "bogus superspeed device capability descriptor\n"); +					return -EDOM; +				} +				break; +			case CONTAINER_ID_TYPE: +				if (buf + USB_DT_USB_SS_CONTN_ID_SIZE > +						dev->buf + total || +						!is_good_con_id(dev, buf)) { +					dev_err(&iface->dev, "bogus container id descriptor\n"); +					return -EDOM; +				} +				break; +			default: +				break; +			} +		} +	} +  	/* there's always [9.4.3] at least one config descriptor [9.6.3] */  	for (i = 0; i < udev->descriptor.bNumConfigurations; i++) {  		retval = usb_get_descriptor(udev, USB_DT_CONFIG, i, @@ -790,7 +966,7 @@ struct ctrl_ctx {  	int			last;  }; -#define NUM_SUBCASES	15		/* how many test subcases here? */ +#define NUM_SUBCASES	16		/* how many test subcases here? */  struct subcase {  	struct usb_ctrlrequest	setup; @@ -954,7 +1130,7 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)  		 * device, but some are chosen to trigger protocol stalls  		 * or short reads.  		 */ -		memset(&req, 0, sizeof req); +		memset(&req, 0, sizeof(req));  		req.bRequest = USB_REQ_GET_DESCRIPTOR;  		req.bRequestType = USB_DIR_IN|USB_RECIP_DEVICE; @@ -1064,6 +1240,15 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)  			}  			expected = -EREMOTEIO;  			break; +		case 15: +			req.wValue = cpu_to_le16(USB_DT_BOS << 8); +			if (udev->bos) +				len = le16_to_cpu(udev->bos->desc->wTotalLength); +			else +				len = sizeof(struct usb_bos_descriptor); +			if (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0201) +				expected = -EPIPE; +			break;  		default:  			ERROR(dev, "bogus number of ctrl queue testcases!\n");  			context.status = -EINVAL; @@ -1074,7 +1259,7 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)  		if (!u)  			goto cleanup; -		reqp = kmalloc(sizeof *reqp, GFP_KERNEL); +		reqp = kmalloc(sizeof(*reqp), GFP_KERNEL);  		if (!reqp)  			goto cleanup;  		reqp->setup = req; @@ -1149,6 +1334,11 @@ static int unlink1(struct usbtest_dev *dev, int pipe, int size, int async)  	urb->context = &completion;  	urb->complete = unlink1_callback; +	if (usb_pipeout(urb->pipe)) { +		simple_fill_buf(urb); +		urb->transfer_flags |= URB_ZERO_PACKET; +	} +  	/* keep the endpoint busy.  there are lots of hc/hcd-internal  	 * states, and testing should get to all of them over time.  	 * @@ -1169,6 +1359,9 @@ static int unlink1(struct usbtest_dev *dev, int pipe, int size, int async)  		while (!completion_done(&completion)) {  			retval = usb_unlink_urb(urb); +			if (retval == 0 && usb_pipein(urb->pipe)) +				retval = simple_check_buf(dev, urb); +  			switch (retval) {  			case -EBUSY:  			case -EIDRM: @@ -1279,6 +1472,11 @@ static int unlink_queued(struct usbtest_dev *dev, int pipe, unsigned num,  				unlink_queued_callback, &ctx);  		ctx.urbs[i]->transfer_dma = buf_dma;  		ctx.urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + +		if (usb_pipeout(ctx.urbs[i]->pipe)) { +			simple_fill_buf(ctx.urbs[i]); +			ctx.urbs[i]->transfer_flags |= URB_ZERO_PACKET; +		}  	}  	/* Submit all the URBs and then unlink URBs num - 4 and num - 2. */ @@ -1383,8 +1581,17 @@ static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)  		return retval;  	}  	retval = verify_halted(tdev, ep, urb); -	if (retval < 0) +	if (retval < 0) { +		int ret; + +		/* clear halt anyways, else further tests will fail */ +		ret = usb_clear_halt(urb->dev, urb->pipe); +		if (ret) +			ERROR(tdev, "ep %02x couldn't clear halt, %d\n", +			      ep, ret); +  		return retval; +	}  	/* clear halt (tests API + protocol), verify it worked */  	retval = usb_clear_halt(urb->dev, urb->pipe); @@ -1667,13 +1874,13 @@ test_iso_queue(struct usbtest_dev *dev, struct usbtest_param *param,  	if (param->sglen > 10)  		return -EDOM; -	memset(&context, 0, sizeof context); +	memset(&context, 0, sizeof(context));  	context.count = param->iterations * param->sglen;  	context.dev = dev;  	init_completion(&context.done);  	spin_lock_init(&context.lock); -	memset(urbs, 0, sizeof urbs); +	memset(urbs, 0, sizeof(urbs));  	udev = testdev_to_usbdev(dev);  	dev_info(&dev->intf->dev,  		"... iso period %d %sframes, wMaxPacket %04x\n", diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index b6ab515bfc6..1472805083d 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -11,7 +11,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/kref.h> @@ -297,6 +296,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_  	/* save our data pointer in this interface device */  	usb_set_intfdata(interface, dev); +	dev->bbu = -1;  	/* we can register the device now, as it is ready */  	retval = usb_register_dev(interface, &yurex_class); @@ -307,8 +307,6 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_  		goto error;  	} -	dev->bbu = -1; -  	dev_info(&interface->dev,  		 "USB YUREX device now attached to Yurex #%d\n",  		 interface->minor); @@ -464,7 +462,7 @@ static ssize_t yurex_write(struct file *file, const char *user_buffer, size_t co  		goto error;  	mutex_lock(&dev->io_mutex); -	if (!dev->interface) {		/* alreaday disconnected */ +	if (!dev->interface) {		/* already disconnected */  		mutex_unlock(&dev->io_mutex);  		retval = -ENODEV;  		goto error; diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index c258a97ef1b..06cc5d6ea68 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -6,7 +6,7 @@  # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller  config USB_MUSB_HDRC  	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' -	depends on USB_GADGET +	depends on (USB || USB_GADGET)  	help  	  Say Y here if your system has a dual role high speed USB  	  controller based on the Mentor Graphics silicon IP.  Then @@ -35,21 +35,23 @@ choice  config USB_MUSB_HOST  	bool "Host only mode" -	depends on USB +	depends on USB=y || USB=USB_MUSB_HDRC  	help  	  Select this when you want to use MUSB in host mode only,  	  thereby the gadget feature will be regressed.  config USB_MUSB_GADGET  	bool "Gadget only mode" -	depends on USB_GADGET +	depends on USB_GADGET=y || USB_GADGET=USB_MUSB_HDRC +	depends on HAS_DMA  	help  	  Select this when you want to use MUSB in gadget mode only,  	  thereby the host feature will be regressed.  config USB_MUSB_DUAL_ROLE  	bool "Dual Role mode" -	depends on (USB && USB_GADGET) +	depends on ((USB=y || USB=USB_MUSB_HDRC) && (USB_GADGET=y || USB_GADGET=USB_MUSB_HDRC)) +	depends on HAS_DMA  	help  	  This is the default mode of working of MUSB controller where  	  both host and gadget features are enabled. @@ -74,7 +76,8 @@ config USB_MUSB_TUSB6010  config USB_MUSB_OMAP2PLUS  	tristate "OMAP2430 and onwards" -	depends on ARCH_OMAP2PLUS +	depends on ARCH_OMAP2PLUS && USB +	select GENERIC_PHY  config USB_MUSB_AM35X  	tristate "AM35x" @@ -90,7 +93,13 @@ config USB_MUSB_BLACKFIN  	depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)  config USB_MUSB_UX500 -	tristate "U8500 and U5500" +	tristate "Ux500 platforms" + +config USB_MUSB_JZ4740 +	tristate "JZ4740" +	depends on MACH_JZ4740 || COMPILE_TEST +	depends on USB_MUSB_GADGET +	depends on USB_OTG_BLACKLIST_HUB  endchoice @@ -99,7 +108,7 @@ config USB_MUSB_AM335X_CHILD  choice  	prompt 'MUSB DMA mode' -	default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM +	default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM || USB_MUSB_JZ4740  	default USB_UX500_DMA if USB_MUSB_UX500  	default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN  	default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI @@ -112,7 +121,7 @@ choice  	  allow using DMA on multiplatform kernels.  config USB_UX500_DMA -	bool 'ST Ericsson U8500 and U5500' +	bool 'ST Ericsson Ux500'  	depends on USB_MUSB_UX500  	help  	  Enable DMA transfers on UX500 platforms. @@ -132,10 +141,11 @@ config USB_TI_CPPI_DMA  config USB_TI_CPPI41_DMA  	bool 'TI CPPI 4.1 (AM335x)'  	depends on ARCH_OMAP +	select TI_CPPI41  config USB_TUSB_OMAP_DMA  	bool 'TUSB 6010' -	depends on USB_MUSB_TUSB6010 +	depends on USB_MUSB_TUSB6010 = USB_MUSB_HDRC # both built-in or both modules  	depends on ARCH_OMAP  	help  	  Enable DMA transfers on TUSB 6010 when OMAP DMA is available. diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index c5ea5c6dc16..ba495018b41 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_USB_MUSB_DAVINCI)			+= davinci.o  obj-$(CONFIG_USB_MUSB_DA8XX)			+= da8xx.o  obj-$(CONFIG_USB_MUSB_BLACKFIN)			+= blackfin.o  obj-$(CONFIG_USB_MUSB_UX500)			+= ux500.o +obj-$(CONFIG_USB_MUSB_JZ4740)			+= jz4740.o  obj-$(CONFIG_USB_MUSB_AM335X_CHILD)		+= musb_am335x.o diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 5c310c66421..0a34dd85955 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -26,14 +26,13 @@   *   */ -#include <linux/init.h>  #include <linux/module.h>  #include <linux/clk.h>  #include <linux/err.h>  #include <linux/io.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <linux/platform_data/usb-omap.h>  #include "musb_core.h" @@ -86,10 +85,10 @@  struct am35x_glue {  	struct device		*dev;  	struct platform_device	*musb; +	struct platform_device	*phy;  	struct clk		*phy_clk;  	struct clk		*clk;  }; -#define glue_to_musb(g)		platform_get_drvdata(g->musb)  /*   * am35x_musb_enable - enable interrupts @@ -362,7 +361,6 @@ static int am35x_musb_init(struct musb *musb)  	if (!rev)  		return -ENODEV; -	usb_nop_xceiv_register();  	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);  	if (IS_ERR_OR_NULL(musb->xceiv))  		return -EPROBE_DEFER; @@ -404,7 +402,6 @@ static int am35x_musb_exit(struct musb *musb)  		data->set_phy_power(0);  	usb_put_phy(musb->xceiv); -	usb_nop_xceiv_unregister();  	return 0;  } @@ -452,14 +449,18 @@ static const struct musb_platform_ops am35x_ops = {  	.set_vbus	= am35x_musb_set_vbus,  }; -static u64 am35x_dmamask = DMA_BIT_MASK(32); +static const struct platform_device_info am35x_dev_info = { +	.name		= "musb-hdrc", +	.id		= PLATFORM_DEVID_AUTO, +	.dma_mask	= DMA_BIT_MASK(32), +};  static int am35x_probe(struct platform_device *pdev)  {  	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);  	struct platform_device		*musb;  	struct am35x_glue		*glue; - +	struct platform_device_info	pinfo;  	struct clk			*phy_clk;  	struct clk			*clk; @@ -471,12 +472,6 @@ static int am35x_probe(struct platform_device *pdev)  		goto err0;  	} -	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); -	if (!musb) { -		dev_err(&pdev->dev, "failed to allocate musb device\n"); -		goto err1; -	} -  	phy_clk = clk_get(&pdev->dev, "fck");  	if (IS_ERR(phy_clk)) {  		dev_err(&pdev->dev, "failed to get PHY clock\n"); @@ -503,40 +498,36 @@ static int am35x_probe(struct platform_device *pdev)  		goto err6;  	} -	musb->dev.parent		= &pdev->dev; -	musb->dev.dma_mask		= &am35x_dmamask; -	musb->dev.coherent_dma_mask	= am35x_dmamask; -  	glue->dev			= &pdev->dev; -	glue->musb			= musb;  	glue->phy_clk			= phy_clk;  	glue->clk			= clk;  	pdata->platform_ops		= &am35x_ops; -	platform_set_drvdata(pdev, glue); - -	ret = platform_device_add_resources(musb, pdev->resource, -			pdev->num_resources); -	if (ret) { -		dev_err(&pdev->dev, "failed to add resources\n"); -		goto err7; -	} - -	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add platform_data\n"); +	glue->phy = usb_phy_generic_register(); +	if (IS_ERR(glue->phy))  		goto err7; -	} +	platform_set_drvdata(pdev, glue); -	ret = platform_device_add(musb); -	if (ret) { -		dev_err(&pdev->dev, "failed to register musb device\n"); -		goto err7; +	pinfo = am35x_dev_info; +	pinfo.parent = &pdev->dev; +	pinfo.res = pdev->resource; +	pinfo.num_res = pdev->num_resources; +	pinfo.data = pdata; +	pinfo.size_data = sizeof(*pdata); + +	glue->musb = musb = platform_device_register_full(&pinfo); +	if (IS_ERR(musb)) { +		ret = PTR_ERR(musb); +		dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); +		goto err8;  	}  	return 0; +err8: +	usb_phy_generic_unregister(glue->phy); +  err7:  	clk_disable(clk); @@ -550,9 +541,6 @@ err4:  	clk_put(phy_clk);  err3: -	platform_device_put(musb); - -err1:  	kfree(glue);  err0: @@ -564,6 +552,7 @@ static int am35x_remove(struct platform_device *pdev)  	struct am35x_glue	*glue = platform_get_drvdata(pdev);  	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister(glue->phy);  	clk_disable(glue->clk);  	clk_disable(glue->phy_clk);  	clk_put(glue->clk); @@ -615,23 +604,16 @@ static int am35x_resume(struct device *dev)  	return 0;  } - -static struct dev_pm_ops am35x_pm_ops = { -	.suspend	= am35x_suspend, -	.resume		= am35x_resume, -}; - -#define DEV_PM_OPS	&am35x_pm_ops -#else -#define DEV_PM_OPS	NULL  #endif +static SIMPLE_DEV_PM_OPS(am35x_pm_ops, am35x_suspend, am35x_resume); +  static struct platform_driver am35x_driver = {  	.probe		= am35x_probe,  	.remove		= am35x_remove,  	.driver		= {  		.name	= "musb-am35x", -		.pm	= DEV_PM_OPS, +		.pm	= &am35x_pm_ops,  	},  }; diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 72e2056b608..d40d5f0b552 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -11,7 +11,6 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/sched.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/gpio.h>  #include <linux/io.h> @@ -19,7 +18,7 @@  #include <linux/platform_device.h>  #include <linux/dma-mapping.h>  #include <linux/prefetch.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <asm/cacheflush.h> @@ -30,6 +29,7 @@  struct bfin_glue {  	struct device		*dev;  	struct platform_device	*musb; +	struct platform_device	*phy;  };  #define glue_to_musb(g)		platform_get_drvdata(g->musb) @@ -77,7 +77,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)  		bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);  		SSYNC(); -		/* Wait for compelete */ +		/* Wait for complete */  		while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))  			cpu_relax(); @@ -131,7 +131,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)  		bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);  		SSYNC(); -		/* Wait for compelete */ +		/* Wait for complete */  		while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))  			cpu_relax(); @@ -402,7 +402,6 @@ static int bfin_musb_init(struct musb *musb)  	}  	gpio_direction_output(musb->config->gpio_vrsel, 0); -	usb_nop_xceiv_register();  	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);  	if (IS_ERR_OR_NULL(musb->xceiv)) {  		gpio_free(musb->config->gpio_vrsel); @@ -425,9 +424,8 @@ static int bfin_musb_init(struct musb *musb)  static int bfin_musb_exit(struct musb *musb)  {  	gpio_free(musb->config->gpio_vrsel); -  	usb_put_phy(musb->xceiv); -	usb_nop_xceiv_unregister(); +  	return 0;  } @@ -478,6 +476,9 @@ static int bfin_probe(struct platform_device *pdev)  	pdata->platform_ops		= &bfin_ops; +	glue->phy = usb_phy_generic_register(); +	if (IS_ERR(glue->phy)) +		goto err2;  	platform_set_drvdata(pdev, glue);  	memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -515,6 +516,9 @@ static int bfin_probe(struct platform_device *pdev)  	return 0;  err3: +	usb_phy_generic_unregister(glue->phy); + +err2:  	platform_device_put(musb);  err1: @@ -529,6 +533,7 @@ static int bfin_remove(struct platform_device *pdev)  	struct bfin_glue		*glue = platform_get_drvdata(pdev);  	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister(glue->phy);  	kfree(glue);  	return 0; @@ -561,23 +566,16 @@ static int bfin_resume(struct device *dev)  	return 0;  } - -static struct dev_pm_ops bfin_pm_ops = { -	.suspend	= bfin_suspend, -	.resume		= bfin_resume, -}; - -#define DEV_PM_OPS	&bfin_pm_ops -#else -#define DEV_PM_OPS	NULL  #endif +static SIMPLE_DEV_PM_OPS(bfin_pm_ops, bfin_suspend, bfin_resume); +  static struct platform_driver bfin_driver = {  	.probe		= bfin_probe,  	.remove		= __exit_p(bfin_remove),  	.driver		= {  		.name	= "musb-blackfin", -		.pm	= DEV_PM_OPS, +		.pm	= &bfin_pm_ops,  	},  }; diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index d9ddf4122f3..058775e647a 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -26,14 +26,13 @@   *   */ -#include <linux/init.h>  #include <linux/module.h>  #include <linux/clk.h>  #include <linux/err.h>  #include <linux/io.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <mach/da8xx.h>  #include <linux/platform_data/usb-davinci.h> @@ -86,6 +85,7 @@  struct da8xx_glue {  	struct device		*dev;  	struct platform_device	*musb; +	struct platform_device	*phy;  	struct clk		*clk;  }; @@ -419,7 +419,6 @@ static int da8xx_musb_init(struct musb *musb)  	if (!rev)  		goto fail; -	usb_nop_xceiv_register();  	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);  	if (IS_ERR_OR_NULL(musb->xceiv)) {  		ret = -EPROBE_DEFER; @@ -454,7 +453,6 @@ static int da8xx_musb_exit(struct musb *musb)  	phy_off();  	usb_put_phy(musb->xceiv); -	usb_nop_xceiv_unregister();  	return 0;  } @@ -472,7 +470,11 @@ static const struct musb_platform_ops da8xx_ops = {  	.set_vbus	= da8xx_musb_set_vbus,  }; -static u64 da8xx_dmamask = DMA_BIT_MASK(32); +static const struct platform_device_info da8xx_dev_info = { +	.name		= "musb-hdrc", +	.id		= PLATFORM_DEVID_AUTO, +	.dma_mask	= DMA_BIT_MASK(32), +};  static int da8xx_probe(struct platform_device *pdev)  { @@ -480,7 +482,7 @@ static int da8xx_probe(struct platform_device *pdev)  	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);  	struct platform_device		*musb;  	struct da8xx_glue		*glue; - +	struct platform_device_info	pinfo;  	struct clk			*clk;  	int				ret = -ENOMEM; @@ -491,12 +493,6 @@ static int da8xx_probe(struct platform_device *pdev)  		goto err0;  	} -	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); -	if (!musb) { -		dev_err(&pdev->dev, "failed to allocate musb device\n"); -		goto err1; -	} -  	clk = clk_get(&pdev->dev, "usb20");  	if (IS_ERR(clk)) {  		dev_err(&pdev->dev, "failed to get clock\n"); @@ -510,16 +506,16 @@ static int da8xx_probe(struct platform_device *pdev)  		goto err4;  	} -	musb->dev.parent		= &pdev->dev; -	musb->dev.dma_mask		= &da8xx_dmamask; -	musb->dev.coherent_dma_mask	= da8xx_dmamask; -  	glue->dev			= &pdev->dev; -	glue->musb			= musb;  	glue->clk			= clk;  	pdata->platform_ops		= &da8xx_ops; +	glue->phy = usb_phy_generic_register(); +	if (IS_ERR(glue->phy)) { +		ret = PTR_ERR(glue->phy); +		goto err5; +	}  	platform_set_drvdata(pdev, glue);  	memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -535,27 +531,25 @@ static int da8xx_probe(struct platform_device *pdev)  	musb_resources[1].end = pdev->resource[1].end;  	musb_resources[1].flags = pdev->resource[1].flags; -	ret = platform_device_add_resources(musb, musb_resources, -			ARRAY_SIZE(musb_resources)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add resources\n"); -		goto err5; -	} - -	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add platform_data\n"); -		goto err5; -	} - -	ret = platform_device_add(musb); -	if (ret) { -		dev_err(&pdev->dev, "failed to register musb device\n"); -		goto err5; +	pinfo = da8xx_dev_info; +	pinfo.parent = &pdev->dev; +	pinfo.res = musb_resources; +	pinfo.num_res = ARRAY_SIZE(musb_resources); +	pinfo.data = pdata; +	pinfo.size_data = sizeof(*pdata); + +	glue->musb = musb = platform_device_register_full(&pinfo); +	if (IS_ERR(musb)) { +		ret = PTR_ERR(musb); +		dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); +		goto err6;  	}  	return 0; +err6: +	usb_phy_generic_unregister(glue->phy); +  err5:  	clk_disable(clk); @@ -563,9 +557,6 @@ err4:  	clk_put(clk);  err3: -	platform_device_put(musb); - -err1:  	kfree(glue);  err0: @@ -577,6 +568,7 @@ static int da8xx_remove(struct platform_device *pdev)  	struct da8xx_glue		*glue = platform_get_drvdata(pdev);  	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister(glue->phy);  	clk_disable(glue->clk);  	clk_put(glue->clk);  	kfree(glue); diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index ed0834e2b72..de8492b06e4 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -24,7 +24,6 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/sched.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/delay.h>  #include <linux/clk.h> @@ -33,7 +32,7 @@  #include <linux/gpio.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <mach/cputype.h>  #include <mach/hardware.h> @@ -382,7 +381,6 @@ static int davinci_musb_init(struct musb *musb)  	u32		revision;  	int 		ret = -ENODEV; -	usb_nop_xceiv_register();  	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);  	if (IS_ERR_OR_NULL(musb->xceiv)) {  		ret = -EPROBE_DEFER; @@ -440,7 +438,7 @@ static int davinci_musb_init(struct musb *musb)  fail:  	usb_put_phy(musb->xceiv);  unregister: -	usb_nop_xceiv_unregister(); +	usb_phy_generic_unregister();  	return ret;  } @@ -488,7 +486,6 @@ static int davinci_musb_exit(struct musb *musb)  	phy_off();  	usb_put_phy(musb->xceiv); -	usb_nop_xceiv_unregister();  	return 0;  } @@ -505,14 +502,19 @@ static const struct musb_platform_ops davinci_ops = {  	.set_vbus	= davinci_musb_set_vbus,  }; -static u64 davinci_dmamask = DMA_BIT_MASK(32); +static const struct platform_device_info davinci_dev_info = { +	.name		= "musb-hdrc", +	.id		= PLATFORM_DEVID_AUTO, +	.dma_mask	= DMA_BIT_MASK(32), +};  static int davinci_probe(struct platform_device *pdev)  { -	struct resource musb_resources[2]; +	struct resource			musb_resources[3];  	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);  	struct platform_device		*musb;  	struct davinci_glue		*glue; +	struct platform_device_info	pinfo;  	struct clk			*clk;  	int				ret = -ENOMEM; @@ -523,12 +525,6 @@ static int davinci_probe(struct platform_device *pdev)  		goto err0;  	} -	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); -	if (!musb) { -		dev_err(&pdev->dev, "failed to allocate musb device\n"); -		goto err1; -	} -  	clk = clk_get(&pdev->dev, "usb");  	if (IS_ERR(clk)) {  		dev_err(&pdev->dev, "failed to get clock\n"); @@ -542,16 +538,12 @@ static int davinci_probe(struct platform_device *pdev)  		goto err4;  	} -	musb->dev.parent		= &pdev->dev; -	musb->dev.dma_mask		= &davinci_dmamask; -	musb->dev.coherent_dma_mask	= davinci_dmamask; -  	glue->dev			= &pdev->dev; -	glue->musb			= musb;  	glue->clk			= clk;  	pdata->platform_ops		= &davinci_ops; +	usb_phy_generic_register();  	platform_set_drvdata(pdev, glue);  	memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -567,22 +559,26 @@ static int davinci_probe(struct platform_device *pdev)  	musb_resources[1].end = pdev->resource[1].end;  	musb_resources[1].flags = pdev->resource[1].flags; -	ret = platform_device_add_resources(musb, musb_resources, -			ARRAY_SIZE(musb_resources)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add resources\n"); -		goto err5; -	} - -	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add platform_data\n"); -		goto err5; -	} - -	ret = platform_device_add(musb); -	if (ret) { -		dev_err(&pdev->dev, "failed to register musb device\n"); +	/* +	 * For DM6467 3 resources are passed. A placeholder for the 3rd +	 * resource is always there, so it's safe to always copy it... +	 */ +	musb_resources[2].name = pdev->resource[2].name; +	musb_resources[2].start = pdev->resource[2].start; +	musb_resources[2].end = pdev->resource[2].end; +	musb_resources[2].flags = pdev->resource[2].flags; + +	pinfo = davinci_dev_info; +	pinfo.parent = &pdev->dev; +	pinfo.res = musb_resources; +	pinfo.num_res = ARRAY_SIZE(musb_resources); +	pinfo.data = pdata; +	pinfo.size_data = sizeof(*pdata); + +	glue->musb = musb = platform_device_register_full(&pinfo); +	if (IS_ERR(musb)) { +		ret = PTR_ERR(musb); +		dev_err(&pdev->dev, "failed to register musb device: %d\n", ret);  		goto err5;  	} @@ -595,9 +591,6 @@ err4:  	clk_put(clk);  err3: -	platform_device_put(musb); - -err1:  	kfree(glue);  err0: @@ -609,6 +602,7 @@ static int davinci_remove(struct platform_device *pdev)  	struct davinci_glue		*glue = platform_get_drvdata(pdev);  	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister();  	clk_disable(glue->clk);  	clk_put(glue->clk);  	kfree(glue); diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c new file mode 100644 index 00000000000..5f30537f192 --- /dev/null +++ b/drivers/usb/musb/jz4740.c @@ -0,0 +1,201 @@ +/* + * Ingenic JZ4740 "glue layer" + * + * Copyright (C) 2013, Apelete Seketeli <apelete@seketeli.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include "musb_core.h" + +struct jz4740_glue { +	struct device           *dev; +	struct platform_device  *musb; +	struct clk		*clk; +}; + +static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci) +{ +	unsigned long   flags; +	irqreturn_t     retval = IRQ_NONE; +	struct musb     *musb = __hci; + +	spin_lock_irqsave(&musb->lock, flags); + +	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); +	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); +	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + +	/* +	 * The controller is gadget only, the state of the host mode IRQ bits is +	 * undefined. Mask them to make sure that the musb driver core will +	 * never see them set +	 */ +	musb->int_usb &= MUSB_INTR_SUSPEND | MUSB_INTR_RESUME | +	    MUSB_INTR_RESET | MUSB_INTR_SOF; + +	if (musb->int_usb || musb->int_tx || musb->int_rx) +		retval = musb_interrupt(musb); + +	spin_unlock_irqrestore(&musb->lock, flags); + +	return retval; +} + +static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = { +{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, }, +}; + +static struct musb_hdrc_config jz4740_musb_config = { +	/* Silicon does not implement USB OTG. */ +	.multipoint = 0, +	/* Max EPs scanned, driver will decide which EP can be used. */ +	.num_eps    = 4, +	/* RAMbits needed to configure EPs from table */ +	.ram_bits   = 9, +	.fifo_cfg = jz4740_musb_fifo_cfg, +	.fifo_cfg_size = ARRAY_SIZE(jz4740_musb_fifo_cfg), +}; + +static struct musb_hdrc_platform_data jz4740_musb_platform_data = { +	.mode   = MUSB_PERIPHERAL, +	.config = &jz4740_musb_config, +}; + +static int jz4740_musb_init(struct musb *musb) +{ +	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); +	if (!musb->xceiv) { +		pr_err("HS UDC: no transceiver configured\n"); +		return -ENODEV; +	} + +	/* Silicon does not implement ConfigData register. +	 * Set dyn_fifo to avoid reading EP config from hardware. +	 */ +	musb->dyn_fifo = true; + +	musb->isr = jz4740_musb_interrupt; + +	return 0; +} + +static int jz4740_musb_exit(struct musb *musb) +{ +	usb_put_phy(musb->xceiv); + +	return 0; +} + +static const struct musb_platform_ops jz4740_musb_ops = { +	.init		= jz4740_musb_init, +	.exit		= jz4740_musb_exit, +}; + +static int jz4740_probe(struct platform_device *pdev) +{ +	struct musb_hdrc_platform_data	*pdata = &jz4740_musb_platform_data; +	struct platform_device		*musb; +	struct jz4740_glue		*glue; +	struct clk                      *clk; +	int				ret; + +	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); +	if (!glue) +		return -ENOMEM; + +	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); +	if (!musb) { +		dev_err(&pdev->dev, "failed to allocate musb device\n"); +		return -ENOMEM; +	} + +	clk = devm_clk_get(&pdev->dev, "udc"); +	if (IS_ERR(clk)) { +		dev_err(&pdev->dev, "failed to get clock\n"); +		ret = PTR_ERR(clk); +		goto err_platform_device_put; +	} + +	ret = clk_prepare_enable(clk); +	if (ret) { +		dev_err(&pdev->dev, "failed to enable clock\n"); +		goto err_platform_device_put; +	} + +	musb->dev.parent		= &pdev->dev; + +	glue->dev			= &pdev->dev; +	glue->musb			= musb; +	glue->clk			= clk; + +	pdata->platform_ops		= &jz4740_musb_ops; + +	platform_set_drvdata(pdev, glue); + +	ret = platform_device_add_resources(musb, pdev->resource, +					    pdev->num_resources); +	if (ret) { +		dev_err(&pdev->dev, "failed to add resources\n"); +		goto err_clk_disable; +	} + +	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); +	if (ret) { +		dev_err(&pdev->dev, "failed to add platform_data\n"); +		goto err_clk_disable; +	} + +	ret = platform_device_add(musb); +	if (ret) { +		dev_err(&pdev->dev, "failed to register musb device\n"); +		goto err_clk_disable; +	} + +	return 0; + +err_clk_disable: +	clk_disable_unprepare(clk); +err_platform_device_put: +	platform_device_put(musb); +	return ret; +} + +static int jz4740_remove(struct platform_device *pdev) +{ +	struct jz4740_glue	*glue = platform_get_drvdata(pdev); + +	platform_device_unregister(glue->musb); +	clk_disable_unprepare(glue->clk); + +	return 0; +} + +static struct platform_driver jz4740_driver = { +	.probe		= jz4740_probe, +	.remove		= jz4740_remove, +	.driver		= { +		.name	= "musb-jz4740", +	}, +}; + +MODULE_DESCRIPTION("JZ4740 MUSB Glue Layer"); +MODULE_AUTHOR("Apelete Seketeli <apelete@seketeli.net>"); +MODULE_LICENSE("GPL v2"); +module_platform_driver(jz4740_driver); diff --git a/drivers/usb/musb/musb_am335x.c b/drivers/usb/musb/musb_am335x.c index 41ac5b5b57c..1e58ed2361c 100644 --- a/drivers/usb/musb/musb_am335x.c +++ b/drivers/usb/musb/musb_am335x.c @@ -1,4 +1,3 @@ -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/pm_runtime.h>  #include <linux/module.h> @@ -20,21 +19,6 @@ err:  	return ret;  } -static int of_remove_populated_child(struct device *dev, void *d) -{ -	struct platform_device *pdev = to_platform_device(dev); - -	of_device_unregister(pdev); -	return 0; -} - -static int am335x_child_remove(struct platform_device *pdev) -{ -	device_for_each_child(&pdev->dev, NULL, of_remove_populated_child); -	pm_runtime_disable(&pdev->dev); -	return 0; -} -  static const struct of_device_id am335x_child_of_match[] = {  	{ .compatible = "ti,am33xx-usb" },  	{  }, @@ -43,13 +27,17 @@ MODULE_DEVICE_TABLE(of, am335x_child_of_match);  static struct platform_driver am335x_child_driver = {  	.probe		= am335x_child_probe, -	.remove         = am335x_child_remove,  	.driver         = {  		.name   = "am335x-usb-childs", -		.of_match_table	= of_match_ptr(am335x_child_of_match), +		.of_match_table	= am335x_child_of_match,  	},  }; -module_platform_driver(am335x_child_driver); +static int __init am335x_child_init(void) +{ +	return platform_driver_register(&am335x_child_driver); +} +module_init(am335x_child_init); +  MODULE_DESCRIPTION("AM33xx child devices");  MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 18e877ffe7b..eff3c5cf84f 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -83,7 +83,7 @@   * This gets many kinds of configuration information:   *	- Kconfig for everything user-configurable   *	- platform_device for addressing, irq, and platform_data - *	- platform_data is mostly for board-specific informarion + *	- platform_data is mostly for board-specific information   *	  (plus recentrly, SOC or family details)   *   * Most of the conditional compilation will (someday) vanish. @@ -93,7 +93,6 @@  #include <linux/kernel.h>  #include <linux/sched.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/kobject.h>  #include <linux/prefetch.h> @@ -439,7 +438,6 @@ void musb_hnp_stop(struct musb *musb)  static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  				u8 devctl)  { -	struct usb_otg *otg = musb->xceiv->otg;  	irqreturn_t handled = IRQ_NONE;  	dev_dbg(musb->controller, "<== DevCtl=%02x, int_usb=0x%x\n", devctl, @@ -479,7 +477,10 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  						(USB_PORT_STAT_C_SUSPEND << 16)  						| MUSB_PORT_STAT_RESUME;  				musb->rh_timer = jiffies -						+ msecs_to_jiffies(20); +						 + msecs_to_jiffies(20); +				schedule_delayed_work( +					&musb->finish_resume_work, +					msecs_to_jiffies(20));  				musb->xceiv->state = OTG_STATE_A_HOST;  				musb->is_active = 1; @@ -617,7 +618,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  				/* case 3 << MUSB_DEVCTL_VBUS_SHIFT: */  				default:  					s = "VALID"; break; -				}; s; }), +				} s; }),  				VBUSERR_RETRY_COUNT - musb->vbuserr_retry,  				musb->port1_status); @@ -654,7 +655,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  				break;  		case OTG_STATE_B_PERIPHERAL:  			musb_g_suspend(musb); -			musb->is_active = otg->gadget->b_hnp_enable; +			musb->is_active = musb->g.b_hnp_enable;  			if (musb->is_active) {  				musb->xceiv->state = OTG_STATE_B_WAIT_ACON;  				dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n"); @@ -670,7 +671,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  			break;  		case OTG_STATE_A_HOST:  			musb->xceiv->state = OTG_STATE_A_SUSPEND; -			musb->is_active = otg->host->b_hnp_enable; +			musb->is_active = musb->hcd->self.b_hnp_enable;  			break;  		case OTG_STATE_B_HOST:  			/* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ @@ -847,6 +848,10 @@ b_host:  		}  	} +	/* handle babble condition */ +	if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb)) +		schedule_work(&musb->recover_work); +  #if 0  /* REVISIT ... this would be for multiplexing periodic endpoints, or   * supporting transfer phasing to prevent exceeding ISO bandwidth @@ -922,6 +927,52 @@ static void musb_generic_disable(struct musb *musb)  }  /* + * Program the HDRC to start (enable interrupts, dma, etc.). + */ +void musb_start(struct musb *musb) +{ +	void __iomem    *regs = musb->mregs; +	u8              devctl = musb_readb(regs, MUSB_DEVCTL); + +	dev_dbg(musb->controller, "<== devctl %02x\n", devctl); + +	/*  Set INT enable registers, enable interrupts */ +	musb->intrtxe = musb->epmask; +	musb_writew(regs, MUSB_INTRTXE, musb->intrtxe); +	musb->intrrxe = musb->epmask & 0xfffe; +	musb_writew(regs, MUSB_INTRRXE, musb->intrrxe); +	musb_writeb(regs, MUSB_INTRUSBE, 0xf7); + +	musb_writeb(regs, MUSB_TESTMODE, 0); + +	/* put into basic highspeed mode and start session */ +	musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE +			| MUSB_POWER_HSENAB +			/* ENSUSPEND wedges tusb */ +			/* | MUSB_POWER_ENSUSPEND */ +		   ); + +	musb->is_active = 0; +	devctl = musb_readb(regs, MUSB_DEVCTL); +	devctl &= ~MUSB_DEVCTL_SESSION; + +	/* session started after: +	 * (a) ID-grounded irq, host mode; +	 * (b) vbus present/connect IRQ, peripheral mode; +	 * (c) peripheral initiates, using SRP +	 */ +	if (musb->port_mode != MUSB_PORT_MODE_HOST && +			(devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { +		musb->is_active = 1; +	} else { +		devctl |= MUSB_DEVCTL_SESSION; +	} + +	musb_platform_enable(musb); +	musb_writeb(regs, MUSB_DEVCTL, devctl); +} + +/*   * Make the HDRC stop (disable interrupts, etc.);   * reversible by musb_start   * called on gadget driver unregister @@ -1141,7 +1192,7 @@ fifo_setup(struct musb *musb, struct musb_hw_ep  *hw_ep,  	musb_writeb(mbase, MUSB_INDEX, hw_ep->epnum);  	/* EP0 reserved endpoint for control, bidirectional; -	 * EP1 reserved for bulk, two unidirection halves. +	 * EP1 reserved for bulk, two unidirectional halves.  	 */  	if (hw_ep->epnum == 1)  		musb->bulk_ep = hw_ep; @@ -1699,6 +1750,34 @@ static void musb_irq_work(struct work_struct *data)  	}  } +/* Recover from babble interrupt conditions */ +static void musb_recover_work(struct work_struct *data) +{ +	struct musb *musb = container_of(data, struct musb, recover_work); +	int status; + +	musb_platform_reset(musb); + +	usb_phy_vbus_off(musb->xceiv); +	udelay(100); + +	usb_phy_vbus_on(musb->xceiv); +	udelay(100); + +	/* +	 * When a babble condition occurs, the musb controller removes the +	 * session bit and the endpoint config is lost. +	 */ +	if (musb->dyn_fifo) +		status = ep_config_from_table(musb); +	else +		status = ep_config_from_hw(musb); + +	/* start the session again */ +	if (status == 0) +		musb_start(musb); +} +  /* --------------------------------------------------------------------------   * Init support   */ @@ -1763,12 +1842,25 @@ static void musb_free(struct musb *musb)  			disable_irq_wake(musb->nIrq);  		free_irq(musb->nIrq, musb);  	} -	if (musb->dma_controller) -		dma_controller_destroy(musb->dma_controller);  	musb_host_free(musb);  } +static void musb_deassert_reset(struct work_struct *work) +{ +	struct musb *musb; +	unsigned long flags; + +	musb = container_of(work, struct musb, deassert_reset_work.work); + +	spin_lock_irqsave(&musb->lock, flags); + +	if (musb->port1_status & USB_PORT_STAT_RESET) +		musb_port_reset(musb, false); + +	spin_unlock_irqrestore(&musb->lock, flags); +} +  /*   * Perform generic per-controller initialization.   * @@ -1813,7 +1905,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)  	/* The musb_platform_init() call:  	 *   - adjusts musb->mregs  	 *   - sets the musb->isr -	 *   - may initialize an integrated tranceiver +	 *   - may initialize an integrated transceiver  	 *   - initializes musb->xceiv, usually by otg_get_phy()  	 *   - stops powering VBUS  	 * @@ -1839,13 +1931,24 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)  	pm_runtime_get_sync(musb->controller); -	if (use_dma && dev->dma_mask) +	if (use_dma && dev->dma_mask) {  		musb->dma_controller = dma_controller_create(musb, musb->mregs); +		if (IS_ERR(musb->dma_controller)) { +			status = PTR_ERR(musb->dma_controller); +			goto fail2_5; +		} +	}  	/* be sure interrupts are disabled before connecting ISR */  	musb_platform_disable(musb);  	musb_generic_disable(musb); +	/* Init IRQ workqueue before request_irq */ +	INIT_WORK(&musb->irq_work, musb_irq_work); +	INIT_WORK(&musb->recover_work, musb_recover_work); +	INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); +	INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); +  	/* setup musb parts of the core (especially endpoints) */  	status = musb_core_init(plat->config->multipoint  			? MUSB_CONTROLLER_MHDRC @@ -1855,9 +1958,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)  	setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb); -	/* Init IRQ workqueue before request_irq */ -	INIT_WORK(&musb->irq_work, musb_irq_work); -  	/* attach to the IRQ */  	if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) {  		dev_err(dev, "request_irq %d failed!\n", nIrq); @@ -1891,15 +1991,26 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)  	switch (musb->port_mode) {  	case MUSB_PORT_MODE_HOST:  		status = musb_host_setup(musb, plat->power); +		if (status < 0) +			goto fail3; +		status = musb_platform_set_mode(musb, MUSB_HOST);  		break;  	case MUSB_PORT_MODE_GADGET:  		status = musb_gadget_setup(musb); +		if (status < 0) +			goto fail3; +		status = musb_platform_set_mode(musb, MUSB_PERIPHERAL);  		break;  	case MUSB_PORT_MODE_DUAL_ROLE:  		status = musb_host_setup(musb, plat->power);  		if (status < 0)  			goto fail3;  		status = musb_gadget_setup(musb); +		if (status) { +			musb_host_cleanup(musb); +			goto fail3; +		} +		status = musb_platform_set_mode(musb, MUSB_OTG);  		break;  	default:  		dev_err(dev, "unsupported port mode %d\n", musb->port_mode); @@ -1926,10 +2037,16 @@ fail5:  fail4:  	musb_gadget_cleanup(musb); +	musb_host_cleanup(musb);  fail3: +	cancel_work_sync(&musb->irq_work); +	cancel_work_sync(&musb->recover_work); +	cancel_delayed_work_sync(&musb->finish_resume_work); +	cancel_delayed_work_sync(&musb->deassert_reset_work);  	if (musb->dma_controller)  		dma_controller_destroy(musb->dma_controller); +fail2_5:  	pm_runtime_put_sync(musb->controller);  fail2: @@ -1986,6 +2103,13 @@ static int musb_remove(struct platform_device *pdev)  	musb_exit_debugfs(musb);  	musb_shutdown(pdev); +	if (musb->dma_controller) +		dma_controller_destroy(musb->dma_controller); + +	cancel_work_sync(&musb->irq_work); +	cancel_work_sync(&musb->recover_work); +	cancel_delayed_work_sync(&musb->finish_resume_work); +	cancel_delayed_work_sync(&musb->deassert_reset_work);  	musb_free(musb);  	device_init_wakeup(dev, 0);  	return 0; @@ -2070,11 +2194,19 @@ static void musb_restore_context(struct musb *musb)  	void __iomem *musb_base = musb->mregs;  	void __iomem *ep_target_regs;  	void __iomem *epio; +	u8 power;  	musb_writew(musb_base, MUSB_FRAME, musb->context.frame);  	musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);  	musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); -	musb_writeb(musb_base, MUSB_POWER, musb->context.power); + +	/* Don't affect SUSPENDM/RESUME bits in POWER reg */ +	power = musb_readb(musb_base, MUSB_POWER); +	power &= MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME; +	musb->context.power &= ~(MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME); +	power |= musb->context.power; +	musb_writeb(musb_base, MUSB_POWER, power); +  	musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe);  	musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe);  	musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe); @@ -2158,16 +2290,28 @@ static int musb_suspend(struct device *dev)  		 */  	} +	musb_save_context(musb); +  	spin_unlock_irqrestore(&musb->lock, flags);  	return 0;  }  static int musb_resume_noirq(struct device *dev)  { -	/* for static cmos like DaVinci, register values were preserved +	struct musb	*musb = dev_to_musb(dev); + +	/* +	 * For static cmos like DaVinci, register values were preserved  	 * unless for some reason the whole soc powered down or the USB  	 * module got reset through the PSC (vs just being disabled). +	 * +	 * For the DSPS glue layer though, a full register restore has to +	 * be done. As it shouldn't harm other platforms, we do it +	 * unconditionally.  	 */ + +	musb_restore_context(musb); +  	return 0;  } @@ -2225,19 +2369,4 @@ static struct platform_driver musb_driver = {  	.shutdown	= musb_shutdown,  }; -/*-------------------------------------------------------------------------*/ - -static int __init musb_init(void) -{ -	if (usb_disabled()) -		return 0; - -	return platform_driver_register(&musb_driver); -} -module_init(musb_init); - -static void __exit musb_cleanup(void) -{ -	platform_driver_unregister(&musb_driver); -} -module_exit(musb_cleanup); +module_platform_driver(musb_driver); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 65f3917b4fc..d155a156f24 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -46,6 +46,8 @@  #include <linux/usb.h>  #include <linux/usb/otg.h>  #include <linux/usb/musb.h> +#include <linux/phy/phy.h> +#include <linux/workqueue.h>  struct musb;  struct musb_hw_ep; @@ -190,6 +192,7 @@ struct musb_platform_ops {  	int	(*set_mode)(struct musb *musb, u8 mode);  	void	(*try_idle)(struct musb *musb, unsigned long timeout); +	void	(*reset)(struct musb *musb);  	int	(*vbus_status)(struct musb *musb);  	void	(*set_vbus)(struct musb *musb, int on); @@ -294,6 +297,9 @@ struct musb {  	irqreturn_t		(*isr)(int, void *);  	struct work_struct	irq_work; +	struct work_struct	recover_work; +	struct delayed_work	deassert_reset_work; +	struct delayed_work	finish_resume_work;  	u16			hwvers;  	u16			intrrxe; @@ -333,6 +339,7 @@ struct musb {  	dma_addr_t		async;  	dma_addr_t		sync;  	void __iomem		*sync_va; +	u8			tusb_revision;  #endif  	/* passed down from chip/board specific irq handlers */ @@ -341,6 +348,7 @@ struct musb {  	u16			int_tx;  	struct usb_phy		*xceiv; +	struct phy		*phy;  	int nIrq;  	unsigned		irq_wake:1; @@ -503,6 +511,7 @@ static inline void musb_configure_ep0(struct musb *musb)  extern const char musb_driver_name[];  extern void musb_stop(struct musb *musb); +extern void musb_start(struct musb *musb);  extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src);  extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst); @@ -546,6 +555,12 @@ static inline void musb_platform_try_idle(struct musb *musb,  		musb->ops->try_idle(musb, timeout);  } +static inline void musb_platform_reset(struct musb *musb) +{ +	if (musb->ops->reset) +		musb->ops->reset(musb); +} +  static inline int musb_platform_get_vbus_status(struct musb *musb)  {  	if (!musb->ops->vbus_status) diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index ae959746f77..5341bb223b7 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -38,6 +38,8 @@ struct cppi41_dma_channel {  	u32 prog_len;  	u32 transferred;  	u32 packet_sz; +	struct list_head tx_check; +	struct work_struct dma_completion;  };  #define MUSB_DMA_NUM_CHANNELS 15 @@ -47,6 +49,8 @@ struct cppi41_dma_controller {  	struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS];  	struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS];  	struct musb *musb; +	struct hrtimer early_tx; +	struct list_head early_tx_list;  	u32 rx_mode;  	u32 tx_mode;  	u32 auto_req; @@ -96,31 +100,40 @@ static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel)  	cppi41_channel->usb_toggle = toggle;  } -static void cppi41_dma_callback(void *private_data) +static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep)  { -	struct dma_channel *channel = private_data; -	struct cppi41_dma_channel *cppi41_channel = channel->private_data; -	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; -	struct musb *musb = hw_ep->musb; -	unsigned long flags; -	struct dma_tx_state txstate; -	u32 transferred; +	u8		epnum = hw_ep->epnum; +	struct musb	*musb = hw_ep->musb; +	void __iomem	*epio = musb->endpoints[epnum].regs; +	u16		csr; -	spin_lock_irqsave(&musb->lock, flags); +	csr = musb_readw(epio, MUSB_TXCSR); +	if (csr & MUSB_TXCSR_TXPKTRDY) +		return false; +	return true; +} -	dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, -			&txstate); -	transferred = cppi41_channel->prog_len - txstate.residue; -	cppi41_channel->transferred += transferred; +static bool is_isoc(struct musb_hw_ep *hw_ep, bool in) +{ +	if (in && hw_ep->in_qh) { +		if (hw_ep->in_qh->type == USB_ENDPOINT_XFER_ISOC) +			return true; +	} else if (hw_ep->out_qh) { +		if (hw_ep->out_qh->type == USB_ENDPOINT_XFER_ISOC) +			return true; +	} +	return false; +} -	dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n", -		hw_ep->epnum, cppi41_channel->transferred, -		cppi41_channel->total_len); +static void cppi41_dma_callback(void *private_data); -	update_rx_toggle(cppi41_channel); +static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) +{ +	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; +	struct musb *musb = hw_ep->musb; -	if (cppi41_channel->transferred == cppi41_channel->total_len || -			transferred < cppi41_channel->packet_sz) { +	if (!cppi41_channel->prog_len || +	    (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)) {  		/* done, complete */  		cppi41_channel->channel.actual_len = @@ -150,13 +163,11 @@ static void cppi41_dma_callback(void *private_data)  				remain_bytes,  				direction,  				DMA_PREP_INTERRUPT | DMA_CTRL_ACK); -		if (WARN_ON(!dma_desc)) { -			spin_unlock_irqrestore(&musb->lock, flags); +		if (WARN_ON(!dma_desc))  			return; -		}  		dma_desc->callback = cppi41_dma_callback; -		dma_desc->callback_param = channel; +		dma_desc->callback_param = &cppi41_channel->channel;  		cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);  		dma_async_issue_pending(dc); @@ -166,6 +177,155 @@ static void cppi41_dma_callback(void *private_data)  			musb_writew(epio, MUSB_RXCSR, csr);  		}  	} +} + +static void cppi_trans_done_work(struct work_struct *work) +{ +	unsigned long flags; +	struct cppi41_dma_channel *cppi41_channel = +		container_of(work, struct cppi41_dma_channel, dma_completion); +	struct cppi41_dma_controller *controller = cppi41_channel->controller; +	struct musb *musb = controller->musb; +	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; +	bool empty; + +	if (!cppi41_channel->is_tx && is_isoc(hw_ep, 1)) { +		spin_lock_irqsave(&musb->lock, flags); +		cppi41_trans_done(cppi41_channel); +		spin_unlock_irqrestore(&musb->lock, flags); +	} else { +		empty = musb_is_tx_fifo_empty(hw_ep); +		if (empty) { +			spin_lock_irqsave(&musb->lock, flags); +			cppi41_trans_done(cppi41_channel); +			spin_unlock_irqrestore(&musb->lock, flags); +		} else { +			schedule_work(&cppi41_channel->dma_completion); +		} +	} +} + +static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) +{ +	struct cppi41_dma_controller *controller; +	struct cppi41_dma_channel *cppi41_channel, *n; +	struct musb *musb; +	unsigned long flags; +	enum hrtimer_restart ret = HRTIMER_NORESTART; + +	controller = container_of(timer, struct cppi41_dma_controller, +			early_tx); +	musb = controller->musb; + +	spin_lock_irqsave(&musb->lock, flags); +	list_for_each_entry_safe(cppi41_channel, n, &controller->early_tx_list, +			tx_check) { +		bool empty; +		struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; + +		empty = musb_is_tx_fifo_empty(hw_ep); +		if (empty) { +			list_del_init(&cppi41_channel->tx_check); +			cppi41_trans_done(cppi41_channel); +		} +	} + +	if (!list_empty(&controller->early_tx_list)) { +		ret = HRTIMER_RESTART; +		hrtimer_forward_now(&controller->early_tx, +				ktime_set(0, 150 * NSEC_PER_USEC)); +	} + +	spin_unlock_irqrestore(&musb->lock, flags); +	return ret; +} + +static void cppi41_dma_callback(void *private_data) +{ +	struct dma_channel *channel = private_data; +	struct cppi41_dma_channel *cppi41_channel = channel->private_data; +	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; +	struct musb *musb = hw_ep->musb; +	unsigned long flags; +	struct dma_tx_state txstate; +	u32 transferred; +	bool empty; + +	spin_lock_irqsave(&musb->lock, flags); + +	dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, +			&txstate); +	transferred = cppi41_channel->prog_len - txstate.residue; +	cppi41_channel->transferred += transferred; + +	dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n", +		hw_ep->epnum, cppi41_channel->transferred, +		cppi41_channel->total_len); + +	update_rx_toggle(cppi41_channel); + +	if (cppi41_channel->transferred == cppi41_channel->total_len || +			transferred < cppi41_channel->packet_sz) +		cppi41_channel->prog_len = 0; + +	if (!cppi41_channel->is_tx) { +		if (is_isoc(hw_ep, 1)) +			schedule_work(&cppi41_channel->dma_completion); +		else +			cppi41_trans_done(cppi41_channel); +		goto out; +	} + +	empty = musb_is_tx_fifo_empty(hw_ep); +	if (empty) { +		cppi41_trans_done(cppi41_channel); +	} else { +		struct cppi41_dma_controller *controller; +		/* +		 * On AM335x it has been observed that the TX interrupt fires +		 * too early that means the TXFIFO is not yet empty but the DMA +		 * engine says that it is done with the transfer. We don't +		 * receive a FIFO empty interrupt so the only thing we can do is +		 * to poll for the bit. On HS it usually takes 2us, on FS around +		 * 110us - 150us depending on the transfer size. +		 * We spin on HS (no longer than than 25us and setup a timer on +		 * FS to check for the bit and complete the transfer. +		 */ +		controller = cppi41_channel->controller; + +		if (musb->g.speed == USB_SPEED_HIGH) { +			unsigned wait = 25; + +			do { +				empty = musb_is_tx_fifo_empty(hw_ep); +				if (empty) +					break; +				wait--; +				if (!wait) +					break; +				udelay(1); +			} while (1); + +			empty = musb_is_tx_fifo_empty(hw_ep); +			if (empty) { +				cppi41_trans_done(cppi41_channel); +				goto out; +			} +		} +		if (is_isoc(hw_ep, 0)) { +			schedule_work(&cppi41_channel->dma_completion); +			goto out; +		} +		list_add_tail(&cppi41_channel->tx_check, +				&controller->early_tx_list); +		if (!hrtimer_is_queued(&controller->early_tx)) { +			hrtimer_start_range_ns(&controller->early_tx, +				ktime_set(0, 140 * NSEC_PER_USEC), +				40 * NSEC_PER_USEC, +				HRTIMER_MODE_REL); +		} +	} +out:  	spin_unlock_irqrestore(&musb->lock, flags);  } @@ -340,12 +500,25 @@ static int cppi41_dma_channel_program(struct dma_channel *channel,  				dma_addr_t dma_addr, u32 len)  {  	int ret; +	struct cppi41_dma_channel *cppi41_channel = channel->private_data; +	int hb_mult = 0;  	BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||  		channel->status == MUSB_DMA_STATUS_BUSY); +	if (is_host_active(cppi41_channel->controller->musb)) { +		if (cppi41_channel->is_tx) +			hb_mult = cppi41_channel->hw_ep->out_qh->hb_mult; +		else +			hb_mult = cppi41_channel->hw_ep->in_qh->hb_mult; +	} +  	channel->status = MUSB_DMA_STATUS_BUSY;  	channel->actual_len = 0; + +	if (hb_mult) +		packet_sz = hb_mult * (packet_sz & 0x7FF); +  	ret = cppi41_configure_channel(channel, packet_sz, mode, dma_addr, len);  	if (!ret)  		channel->status = MUSB_DMA_STATUS_FREE; @@ -364,6 +537,8 @@ static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket,  		WARN_ON(1);  		return 1;  	} +	if (cppi41_channel->hw_ep->ep_in.type != USB_ENDPOINT_XFER_BULK) +		return 0;  	if (cppi41_channel->is_tx)  		return 1;  	/* AM335x Advisory 1.0.13. No workaround for device RX mode */ @@ -388,6 +563,7 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel)  	if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)  		return 0; +	list_del_init(&cppi41_channel->tx_check);  	if (is_tx) {  		csr = musb_readw(epio, MUSB_TXCSR);  		csr &= ~MUSB_TXCSR_DMAENAB; @@ -484,6 +660,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)  		if (ret)  			goto err; +		ret = -EINVAL;  		if (port > MUSB_DMA_NUM_CHANNELS || !port)  			goto err;  		if (is_tx) @@ -494,6 +671,9 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)  		cppi41_channel->controller = controller;  		cppi41_channel->port_num = port;  		cppi41_channel->is_tx = is_tx; +		INIT_LIST_HEAD(&cppi41_channel->tx_check); +		INIT_WORK(&cppi41_channel->dma_completion, +			  cppi_trans_done_work);  		musb_dma = &cppi41_channel->channel;  		musb_dma->private_data = cppi41_channel; @@ -502,7 +682,8 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)  		dc = dma_request_slave_channel(dev, str);  		if (!dc) { -			dev_err(dev, "Falied to request %s.\n", str); +			dev_err(dev, "Failed to request %s.\n", str); +			ret = -EPROBE_DEFER;  			goto err;  		}  		cppi41_channel->dc = dc; @@ -510,7 +691,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)  	return 0;  err:  	cppi41_release_all_dma_chans(controller); -	return -EINVAL; +	return ret;  }  void dma_controller_destroy(struct dma_controller *c) @@ -518,6 +699,7 @@ void dma_controller_destroy(struct dma_controller *c)  	struct cppi41_dma_controller *controller = container_of(c,  			struct cppi41_dma_controller, controller); +	hrtimer_cancel(&controller->early_tx);  	cppi41_dma_controller_stop(controller);  	kfree(controller);  } @@ -526,7 +708,7 @@ struct dma_controller *dma_controller_create(struct musb *musb,  					void __iomem *base)  {  	struct cppi41_dma_controller *controller; -	int ret; +	int ret = 0;  	if (!musb->controller->of_node) {  		dev_err(musb->controller, "Need DT for the DMA engine.\n"); @@ -537,6 +719,9 @@ struct dma_controller *dma_controller_create(struct musb *musb,  	if (!controller)  		goto kzalloc_fail; +	hrtimer_init(&controller->early_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL); +	controller->early_tx.function = cppi41_recheck_tx_req; +	INIT_LIST_HEAD(&controller->early_tx_list);  	controller->musb = musb;  	controller->controller.channel_alloc = cppi41_dma_channel_allocate; @@ -553,5 +738,7 @@ struct dma_controller *dma_controller_create(struct musb *musb,  plat_get_fail:  	kfree(controller);  kzalloc_fail: +	if (ret == -EPROBE_DEFER) +		return ERR_PTR(ret);  	return NULL;  } diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 4047cbb91ba..09529f94e72 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -29,14 +29,13 @@   * da8xx.c would be merged to this file after testing.   */ -#include <linux/init.h>  #include <linux/io.h>  #include <linux/err.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h>  #include <linux/pm_runtime.h>  #include <linux/module.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <linux/platform_data/usb-omap.h>  #include <linux/sizes.h> @@ -46,6 +45,8 @@  #include <linux/of_irq.h>  #include <linux/usb/of.h> +#include <linux/debugfs.h> +  #include "musb_core.h"  static const struct of_device_id musb_dsps_of_match[]; @@ -83,6 +84,8 @@ struct dsps_musb_wrapper {  	u16	coreintr_status;  	u16	phy_utmi;  	u16	mode; +	u16	tx_mode; +	u16	rx_mode;  	/* bit positions for control */  	unsigned	reset:5; @@ -106,10 +109,24 @@ struct dsps_musb_wrapper {  	/* bit positions for mode */  	unsigned	iddig:5; +	unsigned	iddig_mux:5;  	/* miscellaneous stuff */  	u8		poll_seconds;  }; +/* + * register shadow for suspend + */ +struct dsps_context { +	u32 control; +	u32 epintr; +	u32 coreintr; +	u32 phy_utmi; +	u32 mode; +	u32 tx_mode; +	u32 rx_mode; +}; +  /**   * DSPS glue structure.   */ @@ -119,8 +136,67 @@ struct dsps_glue {  	const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */  	struct timer_list timer;	/* otg_workaround timer */  	unsigned long last_timer;    /* last timer data for each instance */ + +	struct dsps_context context; +	struct debugfs_regset32 regset; +	struct dentry *dbgfs_root; +}; + +static const struct debugfs_reg32 dsps_musb_regs[] = { +	{ "revision",		0x00 }, +	{ "control",		0x14 }, +	{ "status",		0x18 }, +	{ "eoi",		0x24 }, +	{ "intr0_stat",		0x30 }, +	{ "intr1_stat",		0x34 }, +	{ "intr0_set",		0x38 }, +	{ "intr1_set",		0x3c }, +	{ "txmode",		0x70 }, +	{ "rxmode",		0x74 }, +	{ "autoreq",		0xd0 }, +	{ "srpfixtime",		0xd4 }, +	{ "tdown",		0xd8 }, +	{ "phy_utmi",		0xe0 }, +	{ "mode",		0xe8 },  }; +static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) +{ +	struct device *dev = musb->controller; +	struct dsps_glue *glue = dev_get_drvdata(dev->parent); + +	if (timeout == 0) +		timeout = jiffies + msecs_to_jiffies(3); + +	/* Never idle if active, or when VBUS timeout is not set as host */ +	if (musb->is_active || (musb->a_wait_bcon == 0 && +				musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { +		dev_dbg(musb->controller, "%s active, deleting timer\n", +				usb_otg_state_string(musb->xceiv->state)); +		del_timer(&glue->timer); +		glue->last_timer = jiffies; +		return; +	} +	if (musb->port_mode != MUSB_PORT_MODE_DUAL_ROLE) +		return; + +	if (!musb->g.dev.driver) +		return; + +	if (time_after(glue->last_timer, timeout) && +				timer_pending(&glue->timer)) { +		dev_dbg(musb->controller, +			"Longer idle timer already pending, ignoring...\n"); +		return; +	} +	glue->last_timer = timeout; + +	dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", +		usb_otg_state_string(musb->xceiv->state), +			jiffies_to_msecs(timeout - jiffies)); +	mod_timer(&glue->timer, timeout); +} +  /**   * dsps_musb_enable - enable interrupts   */ @@ -143,6 +219,7 @@ static void dsps_musb_enable(struct musb *musb)  	/* Force the DRVVBUS IRQ so we can start polling for ID change. */  	dsps_writel(reg_base, wrp->coreintr_set,  		    (1 << wrp->drvvbus) << wrp->usb_shift); +	dsps_musb_try_idle(musb, 0);  }  /** @@ -171,6 +248,7 @@ static void otg_timer(unsigned long _musb)  	const struct dsps_musb_wrapper *wrp = glue->wrp;  	u8 devctl;  	unsigned long flags; +	int skip_session = 0;  	/*  	 * We poll because DSPS IP's won't expose several OTG-critical @@ -183,10 +261,12 @@ static void otg_timer(unsigned long _musb)  	spin_lock_irqsave(&musb->lock, flags);  	switch (musb->xceiv->state) {  	case OTG_STATE_A_WAIT_BCON: -		devctl &= ~MUSB_DEVCTL_SESSION; -		dsps_writeb(musb->mregs, MUSB_DEVCTL, devctl); +		dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); +		skip_session = 1; +		/* fall */ -		devctl = dsps_readb(musb->mregs, MUSB_DEVCTL); +	case OTG_STATE_A_IDLE: +	case OTG_STATE_B_IDLE:  		if (devctl & MUSB_DEVCTL_BDEVICE) {  			musb->xceiv->state = OTG_STATE_B_IDLE;  			MUSB_DEV_MODE(musb); @@ -194,60 +274,21 @@ static void otg_timer(unsigned long _musb)  			musb->xceiv->state = OTG_STATE_A_IDLE;  			MUSB_HST_MODE(musb);  		} +		if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) +			dsps_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); +		mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);  		break;  	case OTG_STATE_A_WAIT_VFALL:  		musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;  		dsps_writel(musb->ctrl_base, wrp->coreintr_set,  			    MUSB_INTR_VBUSERROR << wrp->usb_shift);  		break; -	case OTG_STATE_B_IDLE: -		devctl = dsps_readb(mregs, MUSB_DEVCTL); -		if (devctl & MUSB_DEVCTL_BDEVICE) -			mod_timer(&glue->timer, -					jiffies + wrp->poll_seconds * HZ); -		else -			musb->xceiv->state = OTG_STATE_A_IDLE; -		break;  	default:  		break;  	}  	spin_unlock_irqrestore(&musb->lock, flags);  } -static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) -{ -	struct device *dev = musb->controller; -	struct dsps_glue *glue = dev_get_drvdata(dev->parent); - -	if (timeout == 0) -		timeout = jiffies + msecs_to_jiffies(3); - -	/* Never idle if active, or when VBUS timeout is not set as host */ -	if (musb->is_active || (musb->a_wait_bcon == 0 && -				musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { -		dev_dbg(musb->controller, "%s active, deleting timer\n", -				usb_otg_state_string(musb->xceiv->state)); -		del_timer(&glue->timer); -		glue->last_timer = jiffies; -		return; -	} -	if (musb->port_mode == MUSB_PORT_MODE_HOST) -		return; - -	if (time_after(glue->last_timer, timeout) && -				timer_pending(&glue->timer)) { -		dev_dbg(musb->controller, -			"Longer idle timer already pending, ignoring...\n"); -		return; -	} -	glue->last_timer = timeout; - -	dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", -		usb_otg_state_string(musb->xceiv->state), -			jiffies_to_msecs(timeout - jiffies)); -	mod_timer(&glue->timer, timeout); -} -  static irqreturn_t dsps_interrupt(int irq, void *hci)  {  	struct musb  *musb = hci; @@ -288,9 +329,21 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)  	 * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.  	 * Also, DRVVBUS pulses for SRP (but not at 5V) ...  	 */ -	if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) +	if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) {  		pr_info("CAUTION: musb: Babble Interrupt Occurred\n"); +		/* +		 * When a babble condition occurs, the musb controller removes +		 * the session and is no longer in host mode. Hence, all +		 * devices connected to its root hub get disconnected. +		 * +		 * Hand this error down to the musb core isr, so it can +		 * recover. +		 */ +		musb->int_usb = MUSB_INTR_BABBLE | MUSB_INTR_DISCONNECT; +		musb->int_tx = musb->int_rx = 0; +	} +  	if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {  		int drvvbus = dsps_readl(reg_base, wrp->status);  		void __iomem *mregs = musb->mregs; @@ -339,8 +392,9 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)  	if (musb->int_tx || musb->int_rx || musb->int_usb)  		ret |= musb_interrupt(musb); -	/* Poll for ID change */ -	if (musb->xceiv->state == OTG_STATE_B_IDLE) +	/* Poll for ID change in OTG port mode */ +	if (musb->xceiv->state == OTG_STATE_B_IDLE && +			musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)  		mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);  out:  	spin_unlock_irqrestore(&musb->lock, flags); @@ -348,6 +402,30 @@ out:  	return ret;  } +static int dsps_musb_dbg_init(struct musb *musb, struct dsps_glue *glue) +{ +	struct dentry *root; +	struct dentry *file; +	char buf[128]; + +	sprintf(buf, "%s.dsps", dev_name(musb->controller)); +	root = debugfs_create_dir(buf, NULL); +	if (!root) +		return -ENOMEM; +	glue->dbgfs_root = root; + +	glue->regset.regs = dsps_musb_regs; +	glue->regset.nregs = ARRAY_SIZE(dsps_musb_regs); +	glue->regset.base = musb->ctrl_base; + +	file = debugfs_create_regset32("regdump", S_IRUGO, root, &glue->regset); +	if (!file) { +		debugfs_remove_recursive(root); +		return -ENOMEM; +	} +	return 0; +} +  static int dsps_musb_init(struct musb *musb)  {  	struct device *dev = musb->controller; @@ -357,6 +435,7 @@ static int dsps_musb_init(struct musb *musb)  	void __iomem *reg_base;  	struct resource *r;  	u32 rev, val; +	int ret;  	r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control");  	if (!r) @@ -390,6 +469,10 @@ static int dsps_musb_init(struct musb *musb)  	val &= ~(1 << wrp->otg_disable);  	dsps_writel(musb->ctrl_base, wrp->phy_utmi, val); +	ret = dsps_musb_dbg_init(musb, glue); +	if (ret) +		return ret; +  	return 0;  } @@ -399,11 +482,69 @@ static int dsps_musb_exit(struct musb *musb)  	struct dsps_glue *glue = dev_get_drvdata(dev->parent);  	del_timer_sync(&glue->timer); -  	usb_phy_shutdown(musb->xceiv); +	debugfs_remove_recursive(glue->dbgfs_root); + +	return 0; +} + +static int dsps_musb_set_mode(struct musb *musb, u8 mode) +{ +	struct device *dev = musb->controller; +	struct dsps_glue *glue = dev_get_drvdata(dev->parent); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	void __iomem *ctrl_base = musb->ctrl_base; +	u32 reg; + +	reg = dsps_readl(ctrl_base, wrp->mode); + +	switch (mode) { +	case MUSB_HOST: +		reg &= ~(1 << wrp->iddig); + +		/* +		 * if we're setting mode to host-only or device-only, we're +		 * going to ignore whatever the PHY sends us and just force +		 * ID pin status by SW +		 */ +		reg |= (1 << wrp->iddig_mux); + +		dsps_writel(ctrl_base, wrp->mode, reg); +		dsps_writel(ctrl_base, wrp->phy_utmi, 0x02); +		break; +	case MUSB_PERIPHERAL: +		reg |= (1 << wrp->iddig); + +		/* +		 * if we're setting mode to host-only or device-only, we're +		 * going to ignore whatever the PHY sends us and just force +		 * ID pin status by SW +		 */ +		reg |= (1 << wrp->iddig_mux); + +		dsps_writel(ctrl_base, wrp->mode, reg); +		break; +	case MUSB_OTG: +		dsps_writel(ctrl_base, wrp->phy_utmi, 0x02); +		break; +	default: +		dev_err(glue->dev, "unsupported mode %d\n", mode); +		return -EINVAL; +	} +  	return 0;  } +static void dsps_musb_reset(struct musb *musb) +{ +	struct device *dev = musb->controller; +	struct dsps_glue *glue = dev_get_drvdata(dev->parent); +	const struct dsps_musb_wrapper *wrp = glue->wrp; + +	dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); +	udelay(100); +} +  static struct musb_platform_ops dsps_ops = {  	.init		= dsps_musb_init,  	.exit		= dsps_musb_exit, @@ -412,6 +553,8 @@ static struct musb_platform_ops dsps_ops = {  	.disable	= dsps_musb_disable,  	.try_idle	= dsps_musb_try_idle, +	.set_mode	= dsps_musb_set_mode, +	.reset		= dsps_musb_reset,  };  static u64 musb_dmamask = DMA_BIT_MASK(32); @@ -443,7 +586,7 @@ static int get_musb_port_mode(struct device *dev)  	case USB_DR_MODE_OTG:  	default:  		return MUSB_PORT_MODE_DUAL_ROLE; -	}; +	}  }  static int dsps_create_musb_pdev(struct dsps_glue *glue, @@ -505,6 +648,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,  	config->num_eps = get_int_prop(dn, "mentor,num-eps");  	config->ram_bits = get_int_prop(dn, "mentor,ram-bits"); +	config->host_port_deassert_reset_at_resume = 1;  	pdata.mode = get_musb_port_mode(dev);  	/* DT keeps this entry in mA, musb expects it as per USB spec */  	pdata.power = get_int_prop(dn, "mentor,power") / 2; @@ -535,6 +679,9 @@ static int dsps_probe(struct platform_device *pdev)  	struct dsps_glue *glue;  	int ret; +	if (!strcmp(pdev->name, "musb-hdrc")) +		return -ENODEV; +  	match = of_match_node(musb_dsps_of_match, pdev->dev.of_node);  	if (!match) {  		dev_err(&pdev->dev, "fail to get matching of_match struct\n"); @@ -543,7 +690,7 @@ static int dsps_probe(struct platform_device *pdev)  	wrp = match->data;  	/* allocate glue */ -	glue = kzalloc(sizeof(*glue), GFP_KERNEL); +	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);  	if (!glue) {  		dev_err(&pdev->dev, "unable to allocate glue memory\n");  		return -ENOMEM; @@ -571,7 +718,6 @@ err3:  	pm_runtime_put(&pdev->dev);  err2:  	pm_runtime_disable(&pdev->dev); -	kfree(glue);  	return ret;  } @@ -584,7 +730,7 @@ static int dsps_remove(struct platform_device *pdev)  	/* disable usbss clocks */  	pm_runtime_put(&pdev->dev);  	pm_runtime_disable(&pdev->dev); -	kfree(glue); +  	return 0;  } @@ -600,9 +746,12 @@ static const struct dsps_musb_wrapper am33xx_driver_data = {  	.coreintr_status	= 0x34,  	.phy_utmi		= 0xe0,  	.mode			= 0xe8, +	.tx_mode		= 0x70, +	.rx_mode		= 0x74,  	.reset			= 0,  	.otg_disable		= 21,  	.iddig			= 8, +	.iddig_mux		= 7,  	.usb_shift		= 0,  	.usb_mask		= 0x1ff,  	.usb_bitmap		= (0x1ff << 0), @@ -623,12 +772,53 @@ static const struct of_device_id musb_dsps_of_match[] = {  };  MODULE_DEVICE_TABLE(of, musb_dsps_of_match); +#ifdef CONFIG_PM_SLEEP +static int dsps_suspend(struct device *dev) +{ +	struct dsps_glue *glue = dev_get_drvdata(dev); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	struct musb *musb = platform_get_drvdata(glue->musb); +	void __iomem *mbase = musb->ctrl_base; + +	glue->context.control = dsps_readl(mbase, wrp->control); +	glue->context.epintr = dsps_readl(mbase, wrp->epintr_set); +	glue->context.coreintr = dsps_readl(mbase, wrp->coreintr_set); +	glue->context.phy_utmi = dsps_readl(mbase, wrp->phy_utmi); +	glue->context.mode = dsps_readl(mbase, wrp->mode); +	glue->context.tx_mode = dsps_readl(mbase, wrp->tx_mode); +	glue->context.rx_mode = dsps_readl(mbase, wrp->rx_mode); + +	return 0; +} + +static int dsps_resume(struct device *dev) +{ +	struct dsps_glue *glue = dev_get_drvdata(dev); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	struct musb *musb = platform_get_drvdata(glue->musb); +	void __iomem *mbase = musb->ctrl_base; + +	dsps_writel(mbase, wrp->control, glue->context.control); +	dsps_writel(mbase, wrp->epintr_set, glue->context.epintr); +	dsps_writel(mbase, wrp->coreintr_set, glue->context.coreintr); +	dsps_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi); +	dsps_writel(mbase, wrp->mode, glue->context.mode); +	dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode); +	dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode); + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); +  static struct platform_driver dsps_usbss_driver = {  	.probe		= dsps_probe,  	.remove         = dsps_remove,  	.driver         = {  		.name   = "musb-dsps", -		.of_match_table	= of_match_ptr(musb_dsps_of_match), +		.pm	= &dsps_pm_ops, +		.of_match_table	= musb_dsps_of_match,  	},  }; diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 9a08679d204..d4aa779339f 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1121,7 +1121,7 @@ static int musb_gadget_enable(struct usb_ep *ep,  			case USB_ENDPOINT_XFER_BULK:	s = "bulk"; break;  			case USB_ENDPOINT_XFER_INT:	s = "int"; break;  			default:			s = "iso"; break; -			}; s; }), +			} s; }),  			musb_ep->is_in ? "IN" : "OUT",  			musb_ep->dma ? "dma, " : "",  			musb_ep->packet_sz); @@ -1727,14 +1727,14 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)  	ep->end_point.name = ep->name;  	INIT_LIST_HEAD(&ep->end_point.ep_list);  	if (!epnum) { -		ep->end_point.maxpacket = 64; +		usb_ep_set_maxpacket_limit(&ep->end_point, 64);  		ep->end_point.ops = &musb_g_ep0_ops;  		musb->g.ep0 = &ep->end_point;  	} else {  		if (is_in) -			ep->end_point.maxpacket = hw_ep->max_packet_sz_tx; +			usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_tx);  		else -			ep->end_point.maxpacket = hw_ep->max_packet_sz_rx; +			usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_rx);  		ep->end_point.ops = &musb_ep_ops;  		list_add_tail(&ep->end_point.ep_list, &musb->g.ep_list);  	} @@ -1790,9 +1790,17 @@ int musb_gadget_setup(struct musb *musb)  	musb->g.max_speed = USB_SPEED_HIGH;  	musb->g.speed = USB_SPEED_UNKNOWN; +	MUSB_DEV_MODE(musb); +	musb->xceiv->otg->default_a = 0; +	musb->xceiv->state = OTG_STATE_B_IDLE; +  	/* this "gadget" abstracts/virtualizes the controller */  	musb->g.name = musb_driver_name; +#if IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE)  	musb->g.is_otg = 1; +#elif IS_ENABLED(CONFIG_USB_MUSB_GADGET) +	musb->g.is_otg = 0; +#endif  	musb_g_init_endpoints(musb); @@ -1855,6 +1863,8 @@ static int musb_gadget_start(struct usb_gadget *g,  	musb->xceiv->state = OTG_STATE_B_IDLE;  	spin_unlock_irqrestore(&musb->lock, flags); +	musb_start(musb); +  	/* REVISIT:  funcall to other code, which also  	 * handles power budgeting ... this way also  	 * ensures HdrcStart is indirectly called. @@ -2109,7 +2119,15 @@ __acquires(musb->lock)  	/* Normal reset, as B-Device;  	 * or else after HNP, as A-Device  	 */ -	if (devctl & MUSB_DEVCTL_BDEVICE) { +	if (!musb->g.is_otg) { +		/* USB device controllers that are not OTG compatible +		 * may not have DEVCTL register in silicon. +		 * In that case, do not rely on devctl for setting +		 * peripheral mode. +		 */ +		musb->xceiv->state = OTG_STATE_B_PERIPHERAL; +		musb->g.is_a_peripheral = 0; +	} else if (devctl & MUSB_DEVCTL_BDEVICE) {  		musb->xceiv->state = OTG_STATE_B_PERIPHERAL;  		musb->g.is_a_peripheral = 0;  	} else { diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 9a2b8c85f19..eb06291a40c 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -39,7 +39,6 @@  #include <linux/sched.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/dma-mapping.h> @@ -253,7 +252,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)  			case USB_ENDPOINT_XFER_BULK:	s = "-bulk"; break;  			case USB_ENDPOINT_XFER_ISOC:	s = "-iso"; break;  			default:			s = "-intr"; break; -			}; s; }), +			} s; }),  			epnum, buf + offset, len);  	/* Configure endpoint */ @@ -1184,6 +1183,9 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)  				csr = MUSB_CSR0_H_STATUSPKT  					| MUSB_CSR0_TXPKTRDY; +			/* disable ping token in status phase */ +			csr |= MUSB_CSR0_H_DIS_PING; +  			/* flag status stage */  			musb->ep0_stage = MUSB_EP0_STATUS; @@ -1692,7 +1694,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)  			| MUSB_RXCSR_RXPKTRDY);  		musb_writew(hw_ep->regs, MUSB_RXCSR, val); -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \ +	defined(CONFIG_USB_TI_CPPI41_DMA)  		if (usb_pipeisoc(pipe)) {  			struct usb_iso_packet_descriptor *d; @@ -1705,10 +1708,30 @@ void musb_host_rx(struct musb *musb, u8 epnum)  			if (d->status != -EILSEQ && d->status != -EOVERFLOW)  				d->status = 0; -			if (++qh->iso_idx >= urb->number_of_packets) +			if (++qh->iso_idx >= urb->number_of_packets) {  				done = true; -			else +			} else { +#if defined(CONFIG_USB_TI_CPPI41_DMA) +				struct dma_controller   *c; +				dma_addr_t *buf; +				u32 length, ret; + +				c = musb->dma_controller; +				buf = (void *) +					urb->iso_frame_desc[qh->iso_idx].offset +					+ (u32)urb->transfer_dma; + +				length = +					urb->iso_frame_desc[qh->iso_idx].length; + +				val |= MUSB_RXCSR_DMAENAB; +				musb_writew(hw_ep->regs, MUSB_RXCSR, val); + +				ret = c->channel_program(dma, qh->maxpacket, +						0, (u32) buf, length); +#endif  				done = false; +			}  		} else  {  		/* done if urb buffer is full or short packet is recd */ @@ -1748,7 +1771,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)  		}  		/* we are expecting IN packets */ -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \ +	defined(CONFIG_USB_TI_CPPI41_DMA)  		if (dma) {  			struct dma_controller	*c;  			u16			rx_count; @@ -2013,7 +2037,7 @@ static int musb_schedule(  			head = &musb->out_bulk;  		/* Enable bulk RX/TX NAK timeout scheme when bulk requests are -		 * multiplexed.  This scheme doen't work in high speed to full +		 * multiplexed. This scheme does not work in high speed to full  		 * speed scenario as NAK interrupts are not coming from a  		 * full speed device connected to a high speed device.  		 * NAK timeout interval is 8 (128 uframe or 16ms) for HS and @@ -2433,6 +2457,8 @@ static int musb_bus_suspend(struct usb_hcd *hcd)  	struct musb	*musb = hcd_to_musb(hcd);  	u8		devctl; +	musb_port_suspend(musb, true); +  	if (!is_host_active(musb))  		return 0; @@ -2462,7 +2488,12 @@ static int musb_bus_suspend(struct usb_hcd *hcd)  static int musb_bus_resume(struct usb_hcd *hcd)  { -	/* resuming child port does the work */ +	struct musb *musb = hcd_to_musb(hcd); + +	if (musb->config && +	    musb->config->host_port_deassert_reset_at_resume) +		musb_port_reset(musb, false); +  	return 0;  } @@ -2657,6 +2688,7 @@ int musb_host_setup(struct musb *musb, int power_budget)  	if (ret < 0)  		return ret; +	device_wakeup_enable(hcd->self.controller);  	return 0;  } diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 960d73570b2..7bbf01bf4bb 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -92,6 +92,9 @@ extern void musb_host_rx(struct musb *, u8);  extern void musb_root_disconnect(struct musb *musb);  extern void musb_host_resume_root_hub(struct musb *musb);  extern void musb_host_poke_root_hub(struct musb *musb); +extern void musb_port_suspend(struct musb *musb, bool do_suspend); +extern void musb_port_reset(struct musb *musb, bool do_reset); +extern void musb_host_finish_resume(struct work_struct *work);  #else  static inline struct musb *hcd_to_musb(struct usb_hcd *hcd)  { @@ -121,6 +124,9 @@ static inline void musb_root_disconnect(struct musb *musb)	{}  static inline void musb_host_resume_root_hub(struct musb *musb)	{}  static inline void musb_host_poll_rh_status(struct musb *musb)	{}  static inline void musb_host_poke_root_hub(struct musb *musb)	{} +static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {} +static inline void musb_port_reset(struct musb *musb, bool do_reset) {} +static inline void musb_host_finish_resume(struct work_struct *work) {}  #endif  struct usb_hcd; diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index a523950c2b3..e2d2d8c9891 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -36,7 +36,6 @@  #include <linux/kernel.h>  #include <linux/sched.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/time.h>  #include <linux/timer.h> @@ -44,53 +43,38 @@  #include "musb_core.h" -/* -* Program the HDRC to start (enable interrupts, dma, etc.). -*/ -static void musb_start(struct musb *musb) +void musb_host_finish_resume(struct work_struct *work)  { -	void __iomem	*regs = musb->mregs; -	u8		devctl = musb_readb(regs, MUSB_DEVCTL); - -	dev_dbg(musb->controller, "<== devctl %02x\n", devctl); - -	/*  Set INT enable registers, enable interrupts */ -	musb->intrtxe = musb->epmask; -	musb_writew(regs, MUSB_INTRTXE, musb->intrtxe); -	musb->intrrxe = musb->epmask & 0xfffe; -	musb_writew(regs, MUSB_INTRRXE, musb->intrrxe); -	musb_writeb(regs, MUSB_INTRUSBE, 0xf7); +	struct musb *musb; +	unsigned long flags; +	u8 power; -	musb_writeb(regs, MUSB_TESTMODE, 0); +	musb = container_of(work, struct musb, finish_resume_work.work); -	/* put into basic highspeed mode and start session */ -	musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE -						| MUSB_POWER_HSENAB -						/* ENSUSPEND wedges tusb */ -						/* | MUSB_POWER_ENSUSPEND */ -						); +	spin_lock_irqsave(&musb->lock, flags); -	musb->is_active = 0; -	devctl = musb_readb(regs, MUSB_DEVCTL); -	devctl &= ~MUSB_DEVCTL_SESSION; +	power = musb_readb(musb->mregs, MUSB_POWER); +	power &= ~MUSB_POWER_RESUME; +	dev_dbg(musb->controller, "root port resume stopped, power %02x\n", +		power); +	musb_writeb(musb->mregs, MUSB_POWER, power); -	/* session started after: -	 * (a) ID-grounded irq, host mode; -	 * (b) vbus present/connect IRQ, peripheral mode; -	 * (c) peripheral initiates, using SRP +	/* +	 * ISSUE:  DaVinci (RTL 1.300) disconnects after +	 * resume of high speed peripherals (but not full +	 * speed ones).  	 */ -	if (musb->port_mode != MUSB_PORT_MODE_HOST && -	    (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { -		musb->is_active = 1; -	} else { -		devctl |= MUSB_DEVCTL_SESSION; -	} +	musb->is_active = 1; +	musb->port1_status &= ~(USB_PORT_STAT_SUSPEND | MUSB_PORT_STAT_RESUME); +	musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; +	usb_hcd_poll_rh_status(musb->hcd); +	/* NOTE: it might really be A_WAIT_BCON ... */ +	musb->xceiv->state = OTG_STATE_A_HOST; -	musb_platform_enable(musb); -	musb_writeb(regs, MUSB_DEVCTL, devctl); +	spin_unlock_irqrestore(&musb->lock, flags);  } -static void musb_port_suspend(struct musb *musb, bool do_suspend) +void musb_port_suspend(struct musb *musb, bool do_suspend)  {  	struct usb_otg	*otg = musb->xceiv->otg;  	u8		power; @@ -151,11 +135,12 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)  		/* later, GetPortStatus will stop RESUME signaling */  		musb->port1_status |= MUSB_PORT_STAT_RESUME; -		musb->rh_timer = jiffies + msecs_to_jiffies(20); +		schedule_delayed_work(&musb->finish_resume_work, +				      msecs_to_jiffies(20));  	}  } -static void musb_port_reset(struct musb *musb, bool do_reset) +void musb_port_reset(struct musb *musb, bool do_reset)  {  	u8		power;  	void __iomem	*mbase = musb->mregs; @@ -174,7 +159,6 @@ static void musb_port_reset(struct musb *musb, bool do_reset)  	 */  	power = musb_readb(mbase, MUSB_POWER);  	if (do_reset) { -  		/*  		 * If RESUME is set, we must make sure it stays minimum 20 ms.  		 * Then we must clear RESUME and wait a bit to let musb start @@ -183,11 +167,22 @@ static void musb_port_reset(struct musb *musb, bool do_reset)  		 * detected".  		 */  		if (power &  MUSB_POWER_RESUME) { -			while (time_before(jiffies, musb->rh_timer)) -				msleep(1); +			long remain = (unsigned long) musb->rh_timer - jiffies; + +			if (musb->rh_timer > 0 && remain > 0) { +				/* take into account the minimum delay after resume */ +				schedule_delayed_work( +					&musb->deassert_reset_work, remain); +				return; +			} +  			musb_writeb(mbase, MUSB_POWER, -				power & ~MUSB_POWER_RESUME); -			msleep(1); +				    power & ~MUSB_POWER_RESUME); + +			/* Give the core 1 ms to clear MUSB_POWER_RESUME */ +			schedule_delayed_work(&musb->deassert_reset_work, +					      msecs_to_jiffies(1)); +			return;  		}  		power &= 0xf0; @@ -196,7 +191,8 @@ static void musb_port_reset(struct musb *musb, bool do_reset)  		musb->port1_status |= USB_PORT_STAT_RESET;  		musb->port1_status &= ~USB_PORT_STAT_ENABLE; -		musb->rh_timer = jiffies + msecs_to_jiffies(50); +		schedule_delayed_work(&musb->deassert_reset_work, +				      msecs_to_jiffies(50));  	} else {  		dev_dbg(musb->controller, "root port reset stopped\n");  		musb_writeb(mbase, MUSB_POWER, @@ -266,6 +262,23 @@ int musb_hub_status_data(struct usb_hcd *hcd, char *buf)  	return retval;  } +static int musb_has_gadget(struct musb *musb) +{ +	/* +	 * In host-only mode we start a connection right away. In OTG mode +	 * we have to wait until we loaded a gadget. We don't really need a +	 * gadget if we operate as a host but we should not start a session +	 * as a device without a gadget or else we explode. +	 */ +#ifdef CONFIG_USB_MUSB_HOST +	return 1; +#else +	if (musb->port_mode == MUSB_PORT_MODE_HOST) +		return 1; +	return musb->g.dev.driver != NULL; +#endif +} +  int musb_hub_control(  	struct usb_hcd	*hcd,  	u16		typeReq, @@ -354,36 +367,6 @@ int musb_hub_control(  		if (wIndex != 1)  			goto error; -		/* finish RESET signaling? */ -		if ((musb->port1_status & USB_PORT_STAT_RESET) -				&& time_after_eq(jiffies, musb->rh_timer)) -			musb_port_reset(musb, false); - -		/* finish RESUME signaling? */ -		if ((musb->port1_status & MUSB_PORT_STAT_RESUME) -				&& time_after_eq(jiffies, musb->rh_timer)) { -			u8		power; - -			power = musb_readb(musb->mregs, MUSB_POWER); -			power &= ~MUSB_POWER_RESUME; -			dev_dbg(musb->controller, "root port resume stopped, power %02x\n", -					power); -			musb_writeb(musb->mregs, MUSB_POWER, power); - -			/* ISSUE:  DaVinci (RTL 1.300) disconnects after -			 * resume of high speed peripherals (but not full -			 * speed ones). -			 */ - -			musb->is_active = 1; -			musb->port1_status &= ~(USB_PORT_STAT_SUSPEND -					| MUSB_PORT_STAT_RESUME); -			musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; -			usb_hcd_poll_rh_status(musb->hcd); -			/* NOTE: it might really be A_WAIT_BCON ... */ -			musb->xceiv->state = OTG_STATE_A_HOST; -		} -  		put_unaligned(cpu_to_le32(musb->port1_status  					& ~MUSB_PORT_STAT_RESUME),  				(__le32 *) buf); @@ -408,7 +391,7 @@ int musb_hub_control(  			 * initialization logic, e.g. for OTG, or change any  			 * logic relating to VBUS power-up.  			 */ -			if (!hcd->self.is_b_host) +			if (!hcd->self.is_b_host && musb_has_gadget(musb))  				musb_start(musb);  			break;  		case USB_PORT_FEAT_RESET: diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 59d2245db1c..d369bf1f393 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -37,7 +37,8 @@  #include <linux/err.h>  #include <linux/delay.h>  #include <linux/usb/musb-omap.h> -#include <linux/usb/omap_control_usb.h> +#include <linux/phy/omap_control_phy.h> +#include <linux/of_platform.h>  #include "musb_core.h"  #include "omap2430.h" @@ -305,6 +306,9 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)  	default:  		dev_dbg(dev, "ID float\n");  	} + +	atomic_notifier_call_chain(&musb->xceiv->notifier, +			musb->xceiv->last_event, NULL);  } @@ -312,7 +316,13 @@ static void omap_musb_mailbox_work(struct work_struct *mailbox_work)  {  	struct omap2430_glue *glue = container_of(mailbox_work,  				struct omap2430_glue, omap_musb_mailbox_work); +	struct musb *musb = glue_to_musb(glue); +	struct device *dev = musb->controller; + +	pm_runtime_get_sync(dev);  	omap_musb_set_mailbox(glue); +	pm_runtime_mark_last_busy(dev); +	pm_runtime_put_autosuspend(dev);  }  static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci) @@ -348,11 +358,21 @@ static int omap2430_musb_init(struct musb *musb)  	 * up through ULPI.  TWL4030-family PMICs include one,  	 * which needs a driver, drivers aren't always needed.  	 */ -	if (dev->parent->of_node) +	if (dev->parent->of_node) { +		musb->phy = devm_phy_get(dev->parent, "usb2-phy"); + +		/* We can't totally remove musb->xceiv as of now because +		 * musb core uses xceiv.state and xceiv.otg. Once we have +		 * a separate state machine to handle otg, these can be moved +		 * out of xceiv and then we can start using the generic PHY +		 * framework +		 */  		musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent,  		    "usb-phy", 0); -	else +	} else {  		musb->xceiv = devm_usb_get_phy_dev(dev, 0); +		musb->phy = devm_phy_get(dev, "usb"); +	}  	if (IS_ERR(musb->xceiv)) {  		status = PTR_ERR(musb->xceiv); @@ -364,6 +384,10 @@ static int omap2430_musb_init(struct musb *musb)  		return -EPROBE_DEFER;  	} +	if (IS_ERR(musb->phy)) { +		pr_err("HS USB OTG: no PHY configured\n"); +		return PTR_ERR(musb->phy); +	}  	musb->isr = omap2430_musb_interrupt;  	status = pm_runtime_get_sync(dev); @@ -397,7 +421,8 @@ static int omap2430_musb_init(struct musb *musb)  	if (glue->status != OMAP_MUSB_UNKNOWN)  		omap_musb_set_mailbox(glue); -	usb_phy_init(musb->xceiv); +	phy_init(musb->phy); +	phy_power_on(musb->phy);  	pm_runtime_put_noidle(musb->controller);  	return 0; @@ -460,6 +485,8 @@ static int omap2430_musb_exit(struct musb *musb)  	del_timer_sync(&musb_idle_timer);  	omap2430_low_level_exit(musb); +	phy_power_off(musb->phy); +	phy_exit(musb->phy);  	return 0;  } @@ -509,8 +536,12 @@ static int omap2430_probe(struct platform_device *pdev)  	glue->dev			= &pdev->dev;  	glue->musb			= musb;  	glue->status			= OMAP_MUSB_UNKNOWN; +	glue->control_otghs = ERR_PTR(-ENODEV);  	if (np) { +		struct device_node *control_node; +		struct platform_device *control_pdev; +  		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);  		if (!pdata) {  			dev_err(&pdev->dev, @@ -539,22 +570,20 @@ static int omap2430_probe(struct platform_device *pdev)  		of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);  		of_property_read_u32(np, "power", (u32 *)&pdata->power);  		config->multipoint = of_property_read_bool(np, "multipoint"); -		pdata->has_mailbox = of_property_read_bool(np, -		    "ti,has-mailbox");  		pdata->board_data	= data;  		pdata->config		= config; -	} -	if (pdata->has_mailbox) { -		glue->control_otghs = omap_get_control_dev(); -		if (IS_ERR(glue->control_otghs)) { -			dev_vdbg(&pdev->dev, "Failed to get control device\n"); -			ret = PTR_ERR(glue->control_otghs); -			goto err2; +		control_node = of_parse_phandle(np, "ctrl-module", 0); +		if (control_node) { +			control_pdev = of_find_device_by_node(control_node); +			if (!control_pdev) { +				dev_err(&pdev->dev, "Failed to get control device\n"); +				ret = -EINVAL; +				goto err2; +			} +			glue->control_otghs = &control_pdev->dev;  		} -	} else { -		glue->control_otghs = ERR_PTR(-ENODEV);  	}  	pdata->platform_ops		= &omap2430_ops; @@ -638,7 +667,6 @@ static int omap2430_runtime_suspend(struct device *dev)  				OTG_INTERFSEL);  		omap2430_low_level_exit(musb); -		usb_phy_set_suspend(musb->xceiv, 1);  	}  	return 0; @@ -653,8 +681,6 @@ static int omap2430_runtime_resume(struct device *dev)  		omap2430_low_level_init(musb);  		musb_writel(musb->mregs, OTG_INTERFSEL,  				musb->context.otg_interfsel); - -		usb_phy_set_suspend(musb->xceiv, 0);  	}  	return 0; diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index b3b3ed72388..159ef4be1ef 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -18,20 +18,20 @@  #include <linux/kernel.h>  #include <linux/errno.h>  #include <linux/err.h> -#include <linux/init.h>  #include <linux/prefetch.h>  #include <linux/usb.h>  #include <linux/irq.h>  #include <linux/io.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include "musb_core.h"  struct tusb6010_glue {  	struct device		*dev;  	struct platform_device	*musb; +	struct platform_device	*phy;  };  static void tusb_musb_set_vbus(struct musb *musb, int is_on); @@ -43,7 +43,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on);   * Checks the revision. We need to use the DMA register as 3.0 does not   * have correct versions for TUSB_PRCM_REV or TUSB_INT_CTRL_REV.   */ -u8 tusb_get_revision(struct musb *musb) +static u8 tusb_get_revision(struct musb *musb)  {  	void __iomem	*tbase = musb->ctrl_base;  	u32		die_id; @@ -59,14 +59,13 @@ u8 tusb_get_revision(struct musb *musb)  	return rev;  } -EXPORT_SYMBOL_GPL(tusb_get_revision); -static int tusb_print_revision(struct musb *musb) +static void tusb_print_revision(struct musb *musb)  {  	void __iomem	*tbase = musb->ctrl_base;  	u8		rev; -	rev = tusb_get_revision(musb); +	rev = musb->tusb_revision;  	pr_info("tusb: %s%i.%i %s%i.%i %s%i.%i %s%i.%i %s%i %s%i.%i\n",  		"prcm", @@ -85,8 +84,6 @@ static int tusb_print_revision(struct musb *musb)  		TUSB_DIDR1_HI_CHIP_REV(musb_readl(tbase, TUSB_DIDR1_HI)),  		"rev",  		TUSB_REV_MAJOR(rev), TUSB_REV_MINOR(rev)); - -	return tusb_get_revision(musb);  }  #define WBUS_QUIRK_MASK	(TUSB_PHY_OTG_CTRL_TESTM2 | TUSB_PHY_OTG_CTRL_TESTM1 \ @@ -350,7 +347,7 @@ static void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)  	u32		reg;  	if ((wakeup_enables & TUSB_PRCM_WBUS) -			&& (tusb_get_revision(musb) == TUSB_REV_30)) +			&& (musb->tusb_revision == TUSB_REV_30))  		tusb_wbus_quirk(musb, 1);  	tusb_set_clock_source(musb, 0); @@ -798,7 +795,7 @@ static irqreturn_t tusb_musb_interrupt(int irq, void *__hci)  		u32	reg;  		u32	i; -		if (tusb_get_revision(musb) == TUSB_REV_30) +		if (musb->tusb_revision == TUSB_REV_30)  			tusb_wbus_quirk(musb, 0);  		/* there are issues re-locking the PLL on wakeup ... */ @@ -1012,10 +1009,11 @@ static int tusb_musb_start(struct musb *musb)  		goto err;  	} -	ret = tusb_print_revision(musb); -	if (ret < 2) { +	musb->tusb_revision = tusb_get_revision(musb); +	tusb_print_revision(musb); +	if (musb->tusb_revision < 2) {  		printk(KERN_ERR "tusb: Unsupported TUSB6010 revision %i\n", -				ret); +				musb->tusb_revision);  		goto err;  	} @@ -1066,7 +1064,6 @@ static int tusb_musb_init(struct musb *musb)  	void __iomem		*sync = NULL;  	int			ret; -	usb_nop_xceiv_register();  	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);  	if (IS_ERR_OR_NULL(musb->xceiv))  		return -EPROBE_DEFER; @@ -1118,7 +1115,6 @@ done:  			iounmap(sync);  		usb_put_phy(musb->xceiv); -		usb_nop_xceiv_unregister();  	}  	return ret;  } @@ -1134,7 +1130,6 @@ static int tusb_musb_exit(struct musb *musb)  	iounmap(musb->sync_va);  	usb_put_phy(musb->xceiv); -	usb_nop_xceiv_unregister();  	return 0;  } @@ -1152,7 +1147,11 @@ static const struct musb_platform_ops tusb_ops = {  	.set_vbus	= tusb_musb_set_vbus,  }; -static u64 tusb_dmamask = DMA_BIT_MASK(32); +static const struct platform_device_info tusb_dev_info = { +	.name		= "musb-hdrc", +	.id		= PLATFORM_DEVID_AUTO, +	.dma_mask	= DMA_BIT_MASK(32), +};  static int tusb_probe(struct platform_device *pdev)  { @@ -1160,7 +1159,7 @@ static int tusb_probe(struct platform_device *pdev)  	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);  	struct platform_device		*musb;  	struct tusb6010_glue		*glue; - +	struct platform_device_info	pinfo;  	int				ret = -ENOMEM;  	glue = kzalloc(sizeof(*glue), GFP_KERNEL); @@ -1169,21 +1168,11 @@ static int tusb_probe(struct platform_device *pdev)  		goto err0;  	} -	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); -	if (!musb) { -		dev_err(&pdev->dev, "failed to allocate musb device\n"); -		goto err1; -	} - -	musb->dev.parent		= &pdev->dev; -	musb->dev.dma_mask		= &tusb_dmamask; -	musb->dev.coherent_dma_mask	= tusb_dmamask; -  	glue->dev			= &pdev->dev; -	glue->musb			= musb;  	pdata->platform_ops		= &tusb_ops; +	usb_phy_generic_register();  	platform_set_drvdata(pdev, glue);  	memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -1204,31 +1193,23 @@ static int tusb_probe(struct platform_device *pdev)  	musb_resources[2].end = pdev->resource[2].end;  	musb_resources[2].flags = pdev->resource[2].flags; -	ret = platform_device_add_resources(musb, musb_resources, -			ARRAY_SIZE(musb_resources)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add resources\n"); -		goto err3; -	} - -	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add platform_data\n"); -		goto err3; -	} - -	ret = platform_device_add(musb); -	if (ret) { -		dev_err(&pdev->dev, "failed to register musb device\n"); +	pinfo = tusb_dev_info; +	pinfo.parent = &pdev->dev; +	pinfo.res = musb_resources; +	pinfo.num_res = ARRAY_SIZE(musb_resources); +	pinfo.data = pdata; +	pinfo.size_data = sizeof(*pdata); + +	glue->musb = musb = platform_device_register_full(&pinfo); +	if (IS_ERR(musb)) { +		ret = PTR_ERR(musb); +		dev_err(&pdev->dev, "failed to register musb device: %d\n", ret);  		goto err3;  	}  	return 0;  err3: -	platform_device_put(musb); - -err1:  	kfree(glue);  err0: @@ -1240,6 +1221,7 @@ static int tusb_remove(struct platform_device *pdev)  	struct tusb6010_glue		*glue = platform_get_drvdata(pdev);  	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister(glue->phy);  	kfree(glue);  	return 0; diff --git a/drivers/usb/musb/tusb6010.h b/drivers/usb/musb/tusb6010.h index 35c933a5d99..aec86c86ce3 100644 --- a/drivers/usb/musb/tusb6010.h +++ b/drivers/usb/musb/tusb6010.h @@ -12,14 +12,6 @@  #ifndef __TUSB6010_H__  #define __TUSB6010_H__ -extern u8 tusb_get_revision(struct musb *musb); - -#ifdef CONFIG_USB_TUSB6010 -#define musb_in_tusb()			1 -#else -#define musb_in_tusb()			0 -#endif -  #ifdef CONFIG_USB_TUSB_OMAP_DMA  #define tusb_dma_omap()			1  #else diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c index b8794eb81e9..3ce152c0408 100644 --- a/drivers/usb/musb/tusb6010_omap.c +++ b/drivers/usb/musb/tusb6010_omap.c @@ -11,7 +11,6 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/usb.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> @@ -678,7 +677,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba  	tusb_dma->controller.channel_program = tusb_omap_dma_program;  	tusb_dma->controller.channel_abort = tusb_omap_dma_abort; -	if (tusb_get_revision(musb) >= TUSB_REV_30) +	if (musb->tusb_revision >= TUSB_REV_30)  		tusb_dma->multichannel = 1;  	for (i = 0; i < MAX_DMAREQ; i++) { diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 59256b12f74..f202e508846 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -21,7 +21,6 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/clk.h>  #include <linux/err.h>  #include <linux/io.h> @@ -259,7 +258,7 @@ static int ux500_probe(struct platform_device *pdev)  		goto err1;  	} -	clk = clk_get(&pdev->dev, "usb"); +	clk = clk_get(&pdev->dev, NULL);  	if (IS_ERR(clk)) {  		dev_err(&pdev->dev, "failed to get clock\n");  		ret = PTR_ERR(clk); @@ -275,7 +274,6 @@ static int ux500_probe(struct platform_device *pdev)  	musb->dev.parent		= &pdev->dev;  	musb->dev.dma_mask		= &pdev->dev.coherent_dma_mask;  	musb->dev.coherent_dma_mask	= pdev->dev.coherent_dma_mask; -	musb->dev.of_node		= pdev->dev.of_node;  	glue->dev			= &pdev->dev;  	glue->musb			= musb; @@ -376,17 +374,10 @@ static int ux500_resume(struct device *dev)  	return 0;  } - -static const struct dev_pm_ops ux500_pm_ops = { -	.suspend	= ux500_suspend, -	.resume		= ux500_resume, -}; - -#define DEV_PM_OPS	(&ux500_pm_ops) -#else -#define DEV_PM_OPS	NULL  #endif +static SIMPLE_DEV_PM_OPS(ux500_pm_ops, ux500_suspend, ux500_resume); +  static const struct of_device_id ux500_match[] = {          { .compatible = "stericsson,db8500-musb", },          {} @@ -397,7 +388,7 @@ static struct platform_driver ux500_driver = {  	.remove		= ux500_remove,  	.driver		= {  		.name	= "musb-ux500", -		.pm	= DEV_PM_OPS, +		.pm	= &ux500_pm_ops,  		.of_match_table = ux500_match,  	},  }; diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index 3700e971325..9aad00f11bd 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -336,7 +336,9 @@ static int ux500_dma_controller_start(struct ux500_dma_controller *controller)  							    data ?  							    data->dma_filter :  							    NULL, -							    param_array[ch_num]); +							    param_array ? +							    param_array[ch_num] : +							    NULL);  			if (!ux500_channel->dma_chan) {  				ERR("Dma pipe allocation error dir=%d ch=%d\n", diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index d5589f9c60a..e253fa05be6 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -20,7 +20,7 @@ config AB8500_USB  config FSL_USB2_OTG  	bool "Freescale USB OTG Transceiver Driver" -	depends on USB_EHCI_FSL && USB_FSL_USB2 && PM_RUNTIME +	depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM_RUNTIME  	select USB_OTG  	select USB_PHY  	help @@ -29,6 +29,7 @@ config FSL_USB2_OTG  config ISP1301_OMAP  	tristate "Philips ISP1301 with OMAP OTG"  	depends on I2C && ARCH_OMAP_OTG +	depends on USB  	select USB_PHY  	help  	  If you say yes here you get support for the Philips ISP1301 @@ -38,15 +39,16 @@ config ISP1301_OMAP  	  Instruments OMAP processors.  	  This driver can also be built as a module.  If so, the module -	  will be called isp1301_omap. +	  will be called phy-isp1301-omap. -config MV_U3D_PHY -	bool "Marvell USB 3.0 PHY controller Driver" -	depends on CPU_MMP3 -	select USB_PHY +config KEYSTONE_USB_PHY +	tristate "Keystone USB PHY Driver" +	depends on ARCH_KEYSTONE || COMPILE_TEST +	select NOP_USB_XCEIV  	help -	  Enable this to support Marvell USB 3.0 phy controller for Marvell -	  SoC. +	  Enable this to support Keystone USB phy. This driver provides +	  interface to interact with USB 2.0 and USB 3.0 PHY that is part +	  of the Keystone SOC.  config NOP_USB_XCEIV  	tristate "NOP USB Transceiver Driver" @@ -56,43 +58,12 @@ config NOP_USB_XCEIV  	  built-in with usb ip or which are autonomous and doesn't require any  	  phy programming such as ISP1x04 etc. -config OMAP_CONTROL_USB -	tristate "OMAP CONTROL USB Driver" -	depends on ARCH_OMAP2PLUS || COMPILE_TEST -	help -	  Enable this to add support for the USB part present in the control -	  module. This driver has API to power on the USB2 PHY and to write to -	  the mailbox. The mailbox is present only in omap4 and the register to -	  power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an -	  additional register to power on USB3 PHY. - -config OMAP_USB2 -	tristate "OMAP USB2 PHY Driver" -	depends on ARCH_OMAP2PLUS -	select OMAP_CONTROL_USB -	select USB_PHY -	help -	  Enable this to support the transceiver that is part of SOC. This -	  driver takes care of all the PHY functionality apart from comparator. -	  The USB OTG controller communicates with the comparator using this -	  driver. - -config OMAP_USB3 -	tristate "OMAP USB3 PHY Driver" -	depends on ARCH_OMAP2PLUS || COMPILE_TEST -	select OMAP_CONTROL_USB -	select USB_PHY -	help -	  Enable this to support the USB3 PHY that is part of SOC. This -	  driver takes care of all the PHY functionality apart from comparator. -	  This driver interacts with the "OMAP Control USB Driver" to power -	  on/off the PHY. -  config AM335X_CONTROL_USB  	tristate  config AM335X_PHY_USB  	tristate "AM335x USB PHY Driver" +	depends on ARM || COMPILE_TEST  	select USB_PHY  	select AM335X_CONTROL_USB  	select NOP_USB_XCEIV @@ -123,16 +94,6 @@ config SAMSUNG_USB3PHY  	  Enable this to support Samsung USB 3.0 (Super Speed) phy controller  	  for samsung SoCs. -config TWL4030_USB -	tristate "TWL4030 USB Transceiver Driver" -	depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS -	select USB_PHY -	help -	  Enable this to support the USB OTG transceiver on TWL4030 -	  family chips (including the TWL5030 and TPS659x0 devices). -	  This transceiver supports high and full speed devices plus, -	  in host mode, low speed. -  config TWL6030_USB  	tristate "TWL6030 USB Transceiver Driver"  	depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS @@ -154,6 +115,31 @@ config USB_GPIO_VBUS  	  optionally control of a D+ pullup GPIO as well as a VBUS  	  current limit regulator. +config OMAP_OTG +	tristate "OMAP USB OTG controller driver" +	depends on ARCH_OMAP_OTG && EXTCON +	help +	  Enable this to support some transceivers on OMAP1 platforms. OTG +	  controller is needed to switch between host and peripheral modes. + +	  This driver can also be built as a module. If so, the module +	  will be called phy-omap-otg. + +config TAHVO_USB +	tristate "Tahvo USB transceiver driver" +	depends on MFD_RETU && EXTCON +	select USB_PHY +	help +	  Enable this to support USB transceiver on Tahvo. This is used +	  at least on Nokia 770. + +config TAHVO_USB_HOST_BY_DEFAULT +	depends on TAHVO_USB +	boolean "Device in USB host mode by default" +	help +	  Say Y here, if you want the device to enter USB host mode +	  by default on bootup. +  config USB_ISP1301  	tristate "NXP ISP1301 USB transceiver support"  	depends on USB || USB_GADGET @@ -165,14 +151,15 @@ config USB_ISP1301  	  and OTG drivers (to be selected separately).  	  To compile this driver as a module, choose M here: the -	  module will be called isp1301. +	  module will be called phy-isp1301.  config USB_MSM_OTG -	tristate "OTG support for Qualcomm on-chip USB controller" -	depends on (USB || USB_GADGET) && ARCH_MSM +	tristate "Qualcomm on-chip USB OTG controller support" +	depends on (USB || USB_GADGET) && (ARCH_MSM || ARCH_QCOM || COMPILE_TEST) +	depends on RESET_CONTROLLER  	select USB_PHY  	help -	  Enable this to support the USB OTG transceiver on MSM chips. It +	  Enable this to support the USB OTG transceiver on Qualcomm chips. It  	  handles PHY initialization, clock management, and workarounds  	  required after resetting the hardware and power management.  	  This driver is required even for peripheral only or host only @@ -205,6 +192,7 @@ config USB_MXS_PHY  config USB_RCAR_PHY  	tristate "Renesas R-Car USB PHY support"  	depends on USB || USB_GADGET +	depends on ARCH_R8A7778 || ARCH_R8A7779 || COMPILE_TEST  	select USB_PHY  	help  	  Say Y here to add support for the Renesas R-Car USB common PHY driver. @@ -214,9 +202,22 @@ config USB_RCAR_PHY  	  To compile this driver as a module, choose M here: the  	  module will be called phy-rcar-usb. +config USB_RCAR_GEN2_PHY +	tristate "Renesas R-Car Gen2 USB PHY support" +	depends on ARCH_R8A7790 || ARCH_R8A7791 || COMPILE_TEST +	select USB_PHY +	help +	  Say Y here to add support for the Renesas R-Car Gen2 USB PHY driver. +	  It is typically used to control internal USB PHY for USBHS, +	  and to configure shared USB channels 0 and 2. +	  This driver supports R8A7790 and R8A7791. + +	  To compile this driver as a module, choose M here: the +	  module will be called phy-rcar-gen2-usb. +  config USB_ULPI  	bool "Generic ULPI Transceiver Driver" -	depends on ARM +	depends on ARM || ARM64  	help  	  Enable this to support ULPI connected USB OTG transceivers which  	  are likely found on embedded boards. diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 2135e85f46e..24a91332d4a 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -7,20 +7,16 @@ obj-$(CONFIG_OF)			+= of.o  # transceiver drivers, keep the list sorted  obj-$(CONFIG_AB8500_USB)		+= phy-ab8500-usb.o -phy-fsl-usb2-objs			:= phy-fsl-usb.o phy-fsm-usb.o -obj-$(CONFIG_FSL_USB2_OTG)		+= phy-fsl-usb2.o +obj-$(CONFIG_FSL_USB2_OTG)		+= phy-fsl-usb.o  obj-$(CONFIG_ISP1301_OMAP)		+= phy-isp1301-omap.o -obj-$(CONFIG_MV_U3D_PHY)		+= phy-mv-u3d-usb.o  obj-$(CONFIG_NOP_USB_XCEIV)		+= phy-generic.o -obj-$(CONFIG_OMAP_CONTROL_USB)		+= phy-omap-control.o +obj-$(CONFIG_TAHVO_USB)			+= phy-tahvo.o  obj-$(CONFIG_AM335X_CONTROL_USB)	+= phy-am335x-control.o  obj-$(CONFIG_AM335X_PHY_USB)		+= phy-am335x.o -obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o -obj-$(CONFIG_OMAP_USB3)			+= phy-omap-usb3.o +obj-$(CONFIG_OMAP_OTG)			+= phy-omap-otg.o  obj-$(CONFIG_SAMSUNG_USBPHY)		+= phy-samsung-usb.o  obj-$(CONFIG_SAMSUNG_USB2PHY)		+= phy-samsung-usb2.o  obj-$(CONFIG_SAMSUNG_USB3PHY)		+= phy-samsung-usb3.o -obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o  obj-$(CONFIG_TWL6030_USB)		+= phy-twl6030-usb.o  obj-$(CONFIG_USB_EHCI_TEGRA)		+= phy-tegra-usb.o  obj-$(CONFIG_USB_GPIO_VBUS)		+= phy-gpio-vbus-usb.o @@ -29,5 +25,7 @@ obj-$(CONFIG_USB_MSM_OTG)		+= phy-msm-usb.o  obj-$(CONFIG_USB_MV_OTG)		+= phy-mv-usb.o  obj-$(CONFIG_USB_MXS_PHY)		+= phy-mxs-usb.o  obj-$(CONFIG_USB_RCAR_PHY)		+= phy-rcar-usb.o +obj-$(CONFIG_USB_RCAR_GEN2_PHY)		+= phy-rcar-gen2-usb.o  obj-$(CONFIG_USB_ULPI)			+= phy-ulpi.o  obj-$(CONFIG_USB_ULPI_VIEWPORT)		+= phy-ulpi-viewport.o +obj-$(CONFIG_KEYSTONE_USB_PHY)		+= phy-keystone.o diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 087402350b6..11ab2c45e46 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -1415,8 +1415,6 @@ static int ab8500_usb_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, ab); -	ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier); -  	/* all: Disable phy when called from set_host and set_peripheral */  	INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work); diff --git a/drivers/usb/phy/phy-am335x-control.c b/drivers/usb/phy/phy-am335x-control.c index 22cf07d62e4..35b6083b799 100644 --- a/drivers/usb/phy/phy-am335x-control.c +++ b/drivers/usb/phy/phy-am335x-control.c @@ -3,11 +3,8 @@  #include <linux/err.h>  #include <linux/of.h>  #include <linux/io.h> - -struct phy_control { -	void (*phy_power)(struct phy_control *phy_ctrl, u32 id, bool on); -	void (*phy_wkup)(struct phy_control *phy_ctrl, u32 id, bool on); -}; +#include <linux/delay.h> +#include "am35x-phy-control.h"  struct am335x_control_usb {  	struct device *dev; @@ -26,6 +23,41 @@ struct am335x_control_usb {  #define USBPHY_OTGVDET_EN	(1 << 19)  #define USBPHY_OTGSESSEND_EN	(1 << 20) +#define AM335X_PHY0_WK_EN	(1 << 0) +#define AM335X_PHY1_WK_EN	(1 << 8) + +static void am335x_phy_wkup(struct  phy_control *phy_ctrl, u32 id, bool on) +{ +	struct am335x_control_usb *usb_ctrl; +	u32 val; +	u32 reg; + +	usb_ctrl = container_of(phy_ctrl, struct am335x_control_usb, phy_ctrl); + +	switch (id) { +	case 0: +		reg = AM335X_PHY0_WK_EN; +		break; +	case 1: +		reg = AM335X_PHY1_WK_EN; +		break; +	default: +		WARN_ON(1); +		return; +	} + +	spin_lock(&usb_ctrl->lock); +	val = readl(usb_ctrl->wkup); + +	if (on) +		val |= reg; +	else +		val &= ~reg; + +	writel(val, usb_ctrl->wkup); +	spin_unlock(&usb_ctrl->lock); +} +  static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on)  {  	struct am335x_control_usb *usb_ctrl; @@ -55,10 +87,19 @@ static void am335x_phy_power(struct phy_control *phy_ctrl, u32 id, bool on)  	}  	writel(val, usb_ctrl->phy_reg + reg); + +	/* +	 * Give the PHY ~1ms to complete the power up operation. +	 * Tests have shown unstable behaviour if other USB PHY related +	 * registers are written too shortly after such a transition. +	 */ +	if (on) +		mdelay(1);  }  static const struct phy_control ctrl_am335x = {  	.phy_power = am335x_phy_power, +	.phy_wkup = am335x_phy_wkup,  };  static const struct of_device_id omap_control_usb_id_table[] = { @@ -117,6 +158,12 @@ static int am335x_control_usb_probe(struct platform_device *pdev)  	ctrl_usb->phy_reg = devm_ioremap_resource(&pdev->dev, res);  	if (IS_ERR(ctrl_usb->phy_reg))  		return PTR_ERR(ctrl_usb->phy_reg); + +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wakeup"); +	ctrl_usb->wkup = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(ctrl_usb->wkup)) +		return PTR_ERR(ctrl_usb->wkup); +  	spin_lock_init(&ctrl_usb->lock);  	ctrl_usb->phy_ctrl = *phy_ctrl; @@ -129,7 +176,7 @@ static struct platform_driver am335x_control_driver = {  	.driver		= {  		.name	= "am335x-control-usb",  		.owner	= THIS_MODULE, -		.of_match_table = of_match_ptr(omap_control_usb_id_table), +		.of_match_table = omap_control_usb_id_table,  	},  }; diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index c4d614d1f17..585e50cb198 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -2,7 +2,7 @@  #include <linux/platform_device.h>  #include <linux/dma-mapping.h>  #include <linux/usb/otg.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <linux/slab.h>  #include <linux/clk.h>  #include <linux/regulator/consumer.h> @@ -13,7 +13,7 @@  #include "phy-generic.h"  struct am335x_phy { -	struct usb_phy_gen_xceiv usb_phy_gen; +	struct usb_phy_generic usb_phy_gen;  	struct phy_control *phy_ctrl;  	int id;  }; @@ -52,23 +52,32 @@ static int am335x_phy_probe(struct platform_device *pdev)  		return am_phy->id;  	} -	ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, -			USB_PHY_TYPE_USB2, 0, false, false); +	ret = usb_phy_gen_create_phy(dev, &am_phy->usb_phy_gen, NULL);  	if (ret)  		return ret;  	ret = usb_add_phy_dev(&am_phy->usb_phy_gen.phy);  	if (ret) -		goto err_add; +		return ret;  	am_phy->usb_phy_gen.phy.init = am335x_init;  	am_phy->usb_phy_gen.phy.shutdown = am335x_shutdown;  	platform_set_drvdata(pdev, am_phy); -	return 0; +	device_init_wakeup(dev, true); + +	/* +	 * If we leave PHY wakeup enabled then AM33XX wakes up +	 * immediately from DS0. To avoid this we mark dev->power.can_wakeup +	 * to false. The same is checked in suspend routine to decide +	 * on whether to enable PHY wakeup or not. +	 * PHY wakeup works fine in standby mode, there by allowing us to +	 * handle remote wakeup, wakeup on disconnect and connect. +	 */ + +	device_set_wakeup_enable(dev, false); +	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false); -err_add: -	usb_phy_gen_cleanup_phy(&am_phy->usb_phy_gen); -	return ret; +	return 0;  }  static int am335x_phy_remove(struct platform_device *pdev) @@ -79,6 +88,50 @@ static int am335x_phy_remove(struct platform_device *pdev)  	return 0;  } +#ifdef CONFIG_PM_SLEEP +static int am335x_phy_suspend(struct device *dev) +{ +	struct platform_device	*pdev = to_platform_device(dev); +	struct am335x_phy *am_phy = platform_get_drvdata(pdev); + +	/* +	 * Enable phy wakeup only if dev->power.can_wakeup is true. +	 * Make sure to enable wakeup to support remote wakeup	in +	 * standby mode ( same is not supported in OFF(DS0) mode). +	 * Enable it by doing +	 * echo enabled > /sys/bus/platform/devices/<usb-phy-id>/power/wakeup +	 */ + +	if (device_may_wakeup(dev)) +		phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, true); + +	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, false); + +	return 0; +} + +static int am335x_phy_resume(struct device *dev) +{ +	struct platform_device	*pdev = to_platform_device(dev); +	struct am335x_phy	*am_phy = platform_get_drvdata(pdev); + +	phy_ctrl_power(am_phy->phy_ctrl, am_phy->id, true); + +	if (device_may_wakeup(dev)) +		phy_ctrl_wkup(am_phy->phy_ctrl, am_phy->id, false); + +	return 0; +} + +static const struct dev_pm_ops am335x_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(am335x_phy_suspend, am335x_phy_resume) +}; + +#define DEV_PM_OPS     (&am335x_pm_ops) +#else +#define DEV_PM_OPS     NULL +#endif +  static const struct of_device_id am335x_phy_ids[] = {  	{ .compatible = "ti,am335x-usb-phy" },  	{ } @@ -91,7 +144,8 @@ static struct platform_driver am335x_phy_driver = {  	.driver         = {  		.name   = "am335x-phy-driver",  		.owner  = THIS_MODULE, -		.of_match_table = of_match_ptr(am335x_phy_ids), +		.pm = DEV_PM_OPS, +		.of_match_table = am335x_phy_ids,  	},  }; diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index fa7c9f9628b..2b0f968d932 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -27,7 +27,6 @@  #include <linux/slab.h>  #include <linux/proc_fs.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/interrupt.h>  #include <linux/io.h>  #include <linux/timer.h> @@ -134,7 +133,7 @@ int write_ulpi(u8 addr, u8 data)  /* Operations that will be called from OTG Finite State Machine */  /* Charge vbus for vbus pulsing in SRP */ -void fsl_otg_chrg_vbus(int on) +void fsl_otg_chrg_vbus(struct otg_fsm *fsm, int on)  {  	u32 tmp; @@ -170,7 +169,7 @@ void fsl_otg_dischrg_vbus(int on)  }  /* A-device driver vbus, controlled through PP bit in PORTSC */ -void fsl_otg_drv_vbus(int on) +void fsl_otg_drv_vbus(struct otg_fsm *fsm, int on)  {  	u32 tmp; @@ -188,7 +187,7 @@ void fsl_otg_drv_vbus(int on)   * Pull-up D+, signalling connect by periperal. Also used in   * data-line pulsing in SRP   */ -void fsl_otg_loc_conn(int on) +void fsl_otg_loc_conn(struct otg_fsm *fsm, int on)  {  	u32 tmp; @@ -207,7 +206,7 @@ void fsl_otg_loc_conn(int on)   * port.  In host mode, controller will automatically send SOF.   * Suspend will block the data on the port.   */ -void fsl_otg_loc_sof(int on) +void fsl_otg_loc_sof(struct otg_fsm *fsm, int on)  {  	u32 tmp; @@ -222,7 +221,7 @@ void fsl_otg_loc_sof(int on)  }  /* Start SRP pulsing by data-line pulsing, followed with v-bus pulsing. */ -void fsl_otg_start_pulse(void) +void fsl_otg_start_pulse(struct otg_fsm *fsm)  {  	u32 tmp; @@ -235,7 +234,7 @@ void fsl_otg_start_pulse(void)  	fsl_otg_loc_conn(1);  #endif -	fsl_otg_add_timer(b_data_pulse_tmr); +	fsl_otg_add_timer(fsm, b_data_pulse_tmr);  }  void b_data_pulse_end(unsigned long foo) @@ -252,14 +251,14 @@ void b_data_pulse_end(unsigned long foo)  void fsl_otg_pulse_vbus(void)  {  	srp_wait_done = 0; -	fsl_otg_chrg_vbus(1); +	fsl_otg_chrg_vbus(&fsl_otg_dev->fsm, 1);  	/* start the timer to end vbus charge */ -	fsl_otg_add_timer(b_vbus_pulse_tmr); +	fsl_otg_add_timer(&fsl_otg_dev->fsm, b_vbus_pulse_tmr);  }  void b_vbus_pulse_end(unsigned long foo)  { -	fsl_otg_chrg_vbus(0); +	fsl_otg_chrg_vbus(&fsl_otg_dev->fsm, 0);  	/*  	 * As USB3300 using the same a_sess_vld and b_sess_vld voltage @@ -267,7 +266,7 @@ void b_vbus_pulse_end(unsigned long foo)  	 * residual voltage of vbus pulsing and A device pull up  	 */  	fsl_otg_dischrg_vbus(1); -	fsl_otg_add_timer(b_srp_wait_tmr); +	fsl_otg_add_timer(&fsl_otg_dev->fsm, b_srp_wait_tmr);  }  void b_srp_end(unsigned long foo) @@ -289,7 +288,7 @@ void a_wait_enum(unsigned long foo)  {  	VDBG("a_wait_enum timeout\n");  	if (!fsl_otg_dev->phy.otg->host->b_hnp_enable) -		fsl_otg_add_timer(a_wait_enum_tmr); +		fsl_otg_add_timer(&fsl_otg_dev->fsm, a_wait_enum_tmr);  	else  		otg_statemachine(&fsl_otg_dev->fsm);  } @@ -375,8 +374,42 @@ void fsl_otg_uninit_timers(void)  	kfree(b_vbus_pulse_tmr);  } +static struct fsl_otg_timer *fsl_otg_get_timer(enum otg_fsm_timer t) +{ +	struct fsl_otg_timer *timer; + +	/* REVISIT: use array of pointers to timers instead */ +	switch (t) { +	case A_WAIT_VRISE: +		timer = a_wait_vrise_tmr; +		break; +	case A_WAIT_BCON: +		timer = a_wait_vrise_tmr; +		break; +	case A_AIDL_BDIS: +		timer = a_wait_vrise_tmr; +		break; +	case B_ASE0_BRST: +		timer = a_wait_vrise_tmr; +		break; +	case B_SE0_SRP: +		timer = a_wait_vrise_tmr; +		break; +	case B_SRP_FAIL: +		timer = a_wait_vrise_tmr; +		break; +	case A_WAIT_ENUM: +		timer = a_wait_vrise_tmr; +		break; +	default: +		timer = NULL; +	} + +	return timer; +} +  /* Add timer to timer list */ -void fsl_otg_add_timer(void *gtimer) +void fsl_otg_add_timer(struct otg_fsm *fsm, void *gtimer)  {  	struct fsl_otg_timer *timer = gtimer;  	struct fsl_otg_timer *tmp_timer; @@ -394,8 +427,19 @@ void fsl_otg_add_timer(void *gtimer)  	list_add_tail(&timer->list, &active_timers);  } +static void fsl_otg_fsm_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer t) +{ +	struct fsl_otg_timer *timer; + +	timer = fsl_otg_get_timer(t); +	if (!timer) +		return; + +	fsl_otg_add_timer(fsm, timer); +} +  /* Remove timer from the timer list; clear timeout status */ -void fsl_otg_del_timer(void *gtimer) +void fsl_otg_del_timer(struct otg_fsm *fsm, void *gtimer)  {  	struct fsl_otg_timer *timer = gtimer;  	struct fsl_otg_timer *tmp_timer, *del_tmp; @@ -405,6 +449,17 @@ void fsl_otg_del_timer(void *gtimer)  			list_del(&timer->list);  } +static void fsl_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t) +{ +	struct fsl_otg_timer *timer; + +	timer = fsl_otg_get_timer(t); +	if (!timer) +		return; + +	fsl_otg_del_timer(fsm, timer); +} +  /*   * Reduce timer count by 1, and find timeout conditions.   * Called by fsl_otg 1ms timer interrupt @@ -468,7 +523,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on)  				retval = dev->driver->pm->resume(dev);  				if (fsm->id) {  					/* default-b */ -					fsl_otg_drv_vbus(1); +					fsl_otg_drv_vbus(fsm, 1);  					/*  					 * Workaround: b_host can't driver  					 * vbus, but PP in PORTSC needs to @@ -493,7 +548,7 @@ int fsl_otg_start_host(struct otg_fsm *fsm, int on)  					retval = dev->driver->pm->suspend(dev);  				if (fsm->id)  					/* default-b */ -					fsl_otg_drv_vbus(0); +					fsl_otg_drv_vbus(fsm, 0);  			}  			otg_dev->host_working = 0;  		} @@ -757,8 +812,8 @@ static struct otg_fsm_ops fsl_otg_ops = {  	.loc_sof = fsl_otg_loc_sof,  	.start_pulse = fsl_otg_start_pulse, -	.add_timer = fsl_otg_add_timer, -	.del_timer = fsl_otg_del_timer, +	.add_timer = fsl_otg_fsm_add_timer, +	.del_timer = fsl_otg_fsm_del_timer,  	.start_host = fsl_otg_start_host,  	.start_gadget = fsl_otg_start_gadget, @@ -792,7 +847,7 @@ static int fsl_otg_conf(struct platform_device *pdev)  		pr_info("Couldn't init OTG timers\n");  		goto err;  	} -	spin_lock_init(&fsl_otg_tc->fsm.lock); +	mutex_init(&fsl_otg_tc->fsm.lock);  	/* Set OTG state machine operations */  	fsl_otg_tc->fsm.ops = &fsl_otg_ops; @@ -961,10 +1016,9 @@ static int show_fsl_usb2_otg_state(struct device *dev,  	struct otg_fsm *fsm = &fsl_otg_dev->fsm;  	char *next = buf;  	unsigned size = PAGE_SIZE; -	unsigned long flags;  	int t; -	spin_lock_irqsave(&fsm->lock, flags); +	mutex_lock(&fsm->lock);  	/* basic driver infomation */  	t = scnprintf(next, size, @@ -1011,7 +1065,7 @@ static int show_fsl_usb2_otg_state(struct device *dev,  			"b_bus_suspend: %d\n"  			"b_conn: %d\n"  			"b_se0_srp: %d\n" -			"b_sess_end: %d\n" +			"b_ssend_srp: %d\n"  			"b_sess_vld: %d\n"  			"id: %d\n",  			fsm->a_bus_req, @@ -1026,13 +1080,13 @@ static int show_fsl_usb2_otg_state(struct device *dev,  			fsm->b_bus_suspend,  			fsm->b_conn,  			fsm->b_se0_srp, -			fsm->b_sess_end, +			fsm->b_ssend_srp,  			fsm->b_sess_vld,  			fsm->id);  	size -= t;  	next += t; -	spin_unlock_irqrestore(&fsm->lock, flags); +	mutex_unlock(&fsm->lock);  	return PAGE_SIZE - size;  } @@ -1057,7 +1111,7 @@ static long fsl_otg_ioctl(struct file *file, unsigned int cmd,  		break;  	case SET_A_SUSPEND_REQ: -		fsl_otg_dev->fsm.a_suspend_req = arg; +		fsl_otg_dev->fsm.a_suspend_req_inf = arg;  		break;  	case SET_A_BUS_DROP: diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h index e1859b8ef56..5986c96354d 100644 --- a/drivers/usb/phy/phy-fsl-usb.h +++ b/drivers/usb/phy/phy-fsl-usb.h @@ -15,7 +15,7 @@   * 675 Mass Ave, Cambridge, MA 02139, USA.   */ -#include "phy-fsm-usb.h" +#include <linux/usb/otg-fsm.h>  #include <linux/usb/otg.h>  #include <linux/ioctl.h> @@ -401,6 +401,6 @@ struct fsl_otg_config {  #define GET_A_BUS_REQ		_IOR(OTG_IOCTL_MAGIC, 8, int)  #define GET_B_BUS_REQ		_IOR(OTG_IOCTL_MAGIC, 9, int) -void fsl_otg_add_timer(void *timer); -void fsl_otg_del_timer(void *timer); +void fsl_otg_add_timer(struct otg_fsm *fsm, void *timer); +void fsl_otg_del_timer(struct otg_fsm *fsm, void *timer);  void fsl_otg_pulse_vbus(void); diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h deleted file mode 100644 index fbe586206f3..00000000000 --- a/drivers/usb/phy/phy-fsm-usb.h +++ /dev/null @@ -1,147 +0,0 @@ -/* Copyright (C) 2007,2008 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute  it and/or modify it - * under  the terms of  the GNU General  Public License as published by the - * Free Software Foundation;  either version 2 of the  License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU - * General Public License for more details. - * - * You should have received a copy of the  GNU General Public License along - * with this program; if not, write  to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#undef VERBOSE - -#ifdef VERBOSE -#define VDBG(fmt, args...) pr_debug("[%s]  " fmt , \ -				 __func__, ## args) -#else -#define VDBG(stuff...)	do {} while (0) -#endif - -#ifdef VERBOSE -#define MPC_LOC printk("Current Location [%s]:[%d]\n", __FILE__, __LINE__) -#else -#define MPC_LOC do {} while (0) -#endif - -#define PROTO_UNDEF	(0) -#define PROTO_HOST	(1) -#define PROTO_GADGET	(2) - -/* OTG state machine according to the OTG spec */ -struct otg_fsm { -	/* Input */ -	int a_bus_resume; -	int a_bus_suspend; -	int a_conn; -	int a_sess_vld; -	int a_srp_det; -	int a_vbus_vld; -	int b_bus_resume; -	int b_bus_suspend; -	int b_conn; -	int b_se0_srp; -	int b_sess_end; -	int b_sess_vld; -	int id; - -	/* Internal variables */ -	int a_set_b_hnp_en; -	int b_srp_done; -	int b_hnp_enable; - -	/* Timeout indicator for timers */ -	int a_wait_vrise_tmout; -	int a_wait_bcon_tmout; -	int a_aidl_bdis_tmout; -	int b_ase0_brst_tmout; - -	/* Informative variables */ -	int a_bus_drop; -	int a_bus_req; -	int a_clr_err; -	int a_suspend_req; -	int b_bus_req; - -	/* Output */ -	int drv_vbus; -	int loc_conn; -	int loc_sof; - -	struct otg_fsm_ops *ops; -	struct usb_otg *otg; - -	/* Current usb protocol used: 0:undefine; 1:host; 2:client */ -	int protocol; -	spinlock_t lock; -}; - -struct otg_fsm_ops { -	void	(*chrg_vbus)(int on); -	void	(*drv_vbus)(int on); -	void	(*loc_conn)(int on); -	void	(*loc_sof)(int on); -	void	(*start_pulse)(void); -	void	(*add_timer)(void *timer); -	void	(*del_timer)(void *timer); -	int	(*start_host)(struct otg_fsm *fsm, int on); -	int	(*start_gadget)(struct otg_fsm *fsm, int on); -}; - - -static inline void otg_chrg_vbus(struct otg_fsm *fsm, int on) -{ -	fsm->ops->chrg_vbus(on); -} - -static inline void otg_drv_vbus(struct otg_fsm *fsm, int on) -{ -	if (fsm->drv_vbus != on) { -		fsm->drv_vbus = on; -		fsm->ops->drv_vbus(on); -	} -} - -static inline void otg_loc_conn(struct otg_fsm *fsm, int on) -{ -	if (fsm->loc_conn != on) { -		fsm->loc_conn = on; -		fsm->ops->loc_conn(on); -	} -} - -static inline void otg_loc_sof(struct otg_fsm *fsm, int on) -{ -	if (fsm->loc_sof != on) { -		fsm->loc_sof = on; -		fsm->ops->loc_sof(on); -	} -} - -static inline void otg_start_pulse(struct otg_fsm *fsm) -{ -	fsm->ops->start_pulse(); -} - -static inline void otg_add_timer(struct otg_fsm *fsm, void *timer) -{ -	fsm->ops->add_timer(timer); -} - -static inline void otg_del_timer(struct otg_fsm *fsm, void *timer) -{ -	fsm->ops->del_timer(timer); -} - -int otg_statemachine(struct otg_fsm *fsm); - -/* Defined by device specific driver, for different timer implementation */ -extern struct fsl_otg_timer *a_wait_vrise_tmr, *a_wait_bcon_tmr, -	*a_aidl_bdis_tmr, *b_ase0_brst_tmr, *b_se0_srp_tmr, *b_srp_fail_tmr, -	*a_wait_enum_tmr; diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index efe59f3f7fd..7594e5069ae 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -30,43 +30,55 @@  #include <linux/platform_device.h>  #include <linux/dma-mapping.h>  #include <linux/usb/otg.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <linux/slab.h>  #include <linux/clk.h>  #include <linux/regulator/consumer.h>  #include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/gpio.h> +#include <linux/delay.h>  #include "phy-generic.h" -static struct platform_device *pd; - -void usb_nop_xceiv_register(void) +struct platform_device *usb_phy_generic_register(void)  { -	if (pd) -		return; -	pd = platform_device_register_simple("usb_phy_gen_xceiv", -1, NULL, 0); -	if (!pd) { -		pr_err("Unable to register generic usb transceiver\n"); -		return; -	} +	return platform_device_register_simple("usb_phy_generic", +			PLATFORM_DEVID_AUTO, NULL, 0);  } -EXPORT_SYMBOL(usb_nop_xceiv_register); +EXPORT_SYMBOL_GPL(usb_phy_generic_register); -void usb_nop_xceiv_unregister(void) +void usb_phy_generic_unregister(struct platform_device *pdev)  { -	platform_device_unregister(pd); -	pd = NULL; +	platform_device_unregister(pdev);  } -EXPORT_SYMBOL(usb_nop_xceiv_unregister); +EXPORT_SYMBOL_GPL(usb_phy_generic_unregister);  static int nop_set_suspend(struct usb_phy *x, int suspend)  {  	return 0;  } +static void nop_reset_set(struct usb_phy_generic *nop, int asserted) +{ +	int value; + +	if (!gpio_is_valid(nop->gpio_reset)) +		return; + +	value = asserted; +	if (nop->reset_active_low) +		value = !value; + +	gpio_set_value_cansleep(nop->gpio_reset, value); + +	if (!asserted) +		usleep_range(10000, 20000); +} +  int usb_gen_phy_init(struct usb_phy *phy)  { -	struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); +	struct usb_phy_generic *nop = dev_get_drvdata(phy->dev);  	if (!IS_ERR(nop->vcc)) {  		if (regulator_enable(nop->vcc)) @@ -74,13 +86,10 @@ int usb_gen_phy_init(struct usb_phy *phy)  	}  	if (!IS_ERR(nop->clk)) -		clk_enable(nop->clk); +		clk_prepare_enable(nop->clk); -	if (!IS_ERR(nop->reset)) { -		/* De-assert RESET */ -		if (regulator_enable(nop->reset)) -			dev_err(phy->dev, "Failed to de-assert reset\n"); -	} +	/* De-assert RESET */ +	nop_reset_set(nop, 0);  	return 0;  } @@ -88,16 +97,13 @@ EXPORT_SYMBOL_GPL(usb_gen_phy_init);  void usb_gen_phy_shutdown(struct usb_phy *phy)  { -	struct usb_phy_gen_xceiv *nop = dev_get_drvdata(phy->dev); +	struct usb_phy_generic *nop = dev_get_drvdata(phy->dev); -	if (!IS_ERR(nop->reset)) { -		/* Assert RESET */ -		if (regulator_disable(nop->reset)) -			dev_err(phy->dev, "Failed to assert reset\n"); -	} +	/* Assert RESET */ +	nop_reset_set(nop, 1);  	if (!IS_ERR(nop->clk)) -		clk_disable(nop->clk); +		clk_disable_unprepare(nop->clk);  	if (!IS_ERR(nop->vcc)) {  		if (regulator_disable(nop->vcc)) @@ -135,12 +141,41 @@ static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)  	return 0;  } -int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, -		enum usb_phy_type type, u32 clk_rate, bool needs_vcc, -		bool needs_reset) +int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, +		struct usb_phy_generic_platform_data *pdata)  { +	enum usb_phy_type type = USB_PHY_TYPE_USB2;  	int err; +	u32 clk_rate = 0; +	bool needs_vcc = false; + +	nop->reset_active_low = true;	/* default behaviour */ + +	if (dev->of_node) { +		struct device_node *node = dev->of_node; +		enum of_gpio_flags flags = 0; + +		if (of_property_read_u32(node, "clock-frequency", &clk_rate)) +			clk_rate = 0; + +		needs_vcc = of_property_read_bool(node, "vcc-supply"); +		nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios", +								0, &flags); +		if (nop->gpio_reset == -EPROBE_DEFER) +			return -EPROBE_DEFER; + +		nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW; + +	} else if (pdata) { +		type = pdata->type; +		clk_rate = pdata->clk_rate; +		needs_vcc = pdata->needs_vcc; +		nop->gpio_reset = pdata->gpio_reset; +	} else { +		nop->gpio_reset = -1; +	} +  	nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),  			GFP_KERNEL);  	if (!nop->phy.otg) @@ -160,14 +195,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,  		}  	} -	if (!IS_ERR(nop->clk)) { -		err = clk_prepare(nop->clk); -		if (err) { -			dev_err(dev, "Error preparing clock\n"); -			return err; -		} -	} -  	nop->vcc = devm_regulator_get(dev, "vcc");  	if (IS_ERR(nop->vcc)) {  		dev_dbg(dev, "Error getting vcc regulator: %ld\n", @@ -176,12 +203,22 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,  			return -EPROBE_DEFER;  	} -	nop->reset = devm_regulator_get(dev, "reset"); -	if (IS_ERR(nop->reset)) { -		dev_dbg(dev, "Error getting reset regulator: %ld\n", -					PTR_ERR(nop->reset)); -		if (needs_reset) -			return -EPROBE_DEFER; +	if (gpio_is_valid(nop->gpio_reset)) { +		unsigned long gpio_flags; + +		/* Assert RESET */ +		if (nop->reset_active_low) +			gpio_flags = GPIOF_OUT_INIT_LOW; +		else +			gpio_flags = GPIOF_OUT_INIT_HIGH; + +		err = devm_gpio_request_one(dev, nop->gpio_reset, +						gpio_flags, dev_name(dev)); +		if (err) { +			dev_err(dev, "Error requesting RESET GPIO %d\n", +					nop->gpio_reset); +			return err; +		}  	}  	nop->dev		= dev; @@ -195,53 +232,21 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop,  	nop->phy.otg->set_host		= nop_set_host;  	nop->phy.otg->set_peripheral	= nop_set_peripheral; -	ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);  	return 0;  }  EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy); -void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop) -{ -	if (!IS_ERR(nop->clk)) -		clk_unprepare(nop->clk); -} -EXPORT_SYMBOL_GPL(usb_phy_gen_cleanup_phy); - -static int usb_phy_gen_xceiv_probe(struct platform_device *pdev) +static int usb_phy_generic_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev; -	struct usb_phy_gen_xceiv_platform_data *pdata = -			dev_get_platdata(&pdev->dev); -	struct usb_phy_gen_xceiv	*nop; -	enum usb_phy_type	type = USB_PHY_TYPE_USB2; +	struct usb_phy_generic	*nop;  	int err; -	u32 clk_rate = 0; -	bool needs_vcc = false; -	bool needs_reset = false; - -	if (dev->of_node) { -		struct device_node *node = dev->of_node; - -		if (of_property_read_u32(node, "clock-frequency", &clk_rate)) -			clk_rate = 0; - -		needs_vcc = of_property_read_bool(node, "vcc-supply"); -		needs_reset = of_property_read_bool(node, "reset-supply"); - -	} else if (pdata) { -		type = pdata->type; -		clk_rate = pdata->clk_rate; -		needs_vcc = pdata->needs_vcc; -		needs_reset = pdata->needs_reset; -	}  	nop = devm_kzalloc(dev, sizeof(*nop), GFP_KERNEL);  	if (!nop)  		return -ENOMEM; - -	err = usb_phy_gen_create_phy(dev, nop, type, clk_rate, needs_vcc, -			needs_reset); +	err = usb_phy_gen_create_phy(dev, nop, dev_get_platdata(&pdev->dev));  	if (err)  		return err; @@ -252,23 +257,18 @@ static int usb_phy_gen_xceiv_probe(struct platform_device *pdev)  	if (err) {  		dev_err(&pdev->dev, "can't register transceiver, err: %d\n",  			err); -		goto err_add; +		return err;  	}  	platform_set_drvdata(pdev, nop);  	return 0; - -err_add: -	usb_phy_gen_cleanup_phy(nop); -	return err;  } -static int usb_phy_gen_xceiv_remove(struct platform_device *pdev) +static int usb_phy_generic_remove(struct platform_device *pdev)  { -	struct usb_phy_gen_xceiv *nop = platform_get_drvdata(pdev); +	struct usb_phy_generic *nop = platform_get_drvdata(pdev); -	usb_phy_gen_cleanup_phy(nop);  	usb_remove_phy(&nop->phy);  	return 0; @@ -281,29 +281,29 @@ static const struct of_device_id nop_xceiv_dt_ids[] = {  MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); -static struct platform_driver usb_phy_gen_xceiv_driver = { -	.probe		= usb_phy_gen_xceiv_probe, -	.remove		= usb_phy_gen_xceiv_remove, +static struct platform_driver usb_phy_generic_driver = { +	.probe		= usb_phy_generic_probe, +	.remove		= usb_phy_generic_remove,  	.driver		= { -		.name	= "usb_phy_gen_xceiv", +		.name	= "usb_phy_generic",  		.owner	= THIS_MODULE,  		.of_match_table = nop_xceiv_dt_ids,  	},  }; -static int __init usb_phy_gen_xceiv_init(void) +static int __init usb_phy_generic_init(void)  { -	return platform_driver_register(&usb_phy_gen_xceiv_driver); +	return platform_driver_register(&usb_phy_generic_driver);  } -subsys_initcall(usb_phy_gen_xceiv_init); +subsys_initcall(usb_phy_generic_init); -static void __exit usb_phy_gen_xceiv_exit(void) +static void __exit usb_phy_generic_exit(void)  { -	platform_driver_unregister(&usb_phy_gen_xceiv_driver); +	platform_driver_unregister(&usb_phy_generic_driver);  } -module_exit(usb_phy_gen_xceiv_exit); +module_exit(usb_phy_generic_exit); -MODULE_ALIAS("platform:usb_phy_gen_xceiv"); +MODULE_ALIAS("platform:usb_phy_generic");  MODULE_AUTHOR("Texas Instruments Inc");  MODULE_DESCRIPTION("NOP USB Transceiver driver");  MODULE_LICENSE("GPL"); diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h index 61687d5a965..d8feacc0b7f 100644 --- a/drivers/usb/phy/phy-generic.h +++ b/drivers/usb/phy/phy-generic.h @@ -1,20 +1,21 @@  #ifndef _PHY_GENERIC_H_  #define _PHY_GENERIC_H_ -struct usb_phy_gen_xceiv { +#include <linux/usb/usb_phy_generic.h> + +struct usb_phy_generic {  	struct usb_phy phy;  	struct device *dev;  	struct clk *clk;  	struct regulator *vcc; -	struct regulator *reset; +	int gpio_reset; +	bool reset_active_low;  };  int usb_gen_phy_init(struct usb_phy *phy);  void usb_gen_phy_shutdown(struct usb_phy *phy); -int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_gen_xceiv *nop, -		enum usb_phy_type type, u32 clk_rate, bool needs_vcc, -		bool needs_reset); -void usb_phy_gen_cleanup_phy(struct usb_phy_gen_xceiv *nop); +int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, +		struct usb_phy_generic_platform_data *pdata);  #endif diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index b2f29c9aebb..69462e09d01 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -241,7 +241,7 @@ static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend)  /* platform driver interface */ -static int __init gpio_vbus_probe(struct platform_device *pdev) +static int gpio_vbus_probe(struct platform_device *pdev)  {  	struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev);  	struct gpio_vbus_data *gpio_vbus; @@ -314,8 +314,6 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)  		goto err_irq;  	} -	ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier); -  	INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work);  	gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw"); @@ -349,7 +347,7 @@ err_gpio:  	return err;  } -static int __exit gpio_vbus_remove(struct platform_device *pdev) +static int gpio_vbus_remove(struct platform_device *pdev)  {  	struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);  	struct gpio_vbus_mach_info *pdata = dev_get_platdata(&pdev->dev); @@ -398,8 +396,6 @@ static const struct dev_pm_ops gpio_vbus_dev_pm_ops = {  };  #endif -/* NOTE:  the gpio-vbus device may *NOT* be hotplugged */ -  MODULE_ALIAS("platform:gpio-vbus");  static struct platform_driver gpio_vbus_driver = { @@ -410,10 +406,11 @@ static struct platform_driver gpio_vbus_driver = {  		.pm = &gpio_vbus_dev_pm_ops,  #endif  	}, -	.remove  = __exit_p(gpio_vbus_remove), +	.probe		= gpio_vbus_probe, +	.remove		= gpio_vbus_remove,  }; -module_platform_driver_probe(gpio_vbus_driver, gpio_vbus_probe); +module_platform_driver(gpio_vbus_driver);  MODULE_DESCRIPTION("simple GPIO controlled OTG transceiver driver");  MODULE_AUTHOR("Philipp Zabel"); diff --git a/drivers/usb/phy/phy-isp1301-omap.c b/drivers/usb/phy/phy-isp1301-omap.c index d3a5160e4cc..69e49be8866 100644 --- a/drivers/usb/phy/phy-isp1301-omap.c +++ b/drivers/usb/phy/phy-isp1301-omap.c @@ -1277,7 +1277,7 @@ isp1301_set_host(struct usb_otg *otg, struct usb_bus *host)  {  	struct isp1301	*isp = container_of(otg->phy, struct isp1301, phy); -	if (!otg || isp != the_transceiver) +	if (isp != the_transceiver)  		return -ENODEV;  	if (!host) { @@ -1295,7 +1295,7 @@ isp1301_set_host(struct usb_otg *otg, struct usb_bus *host)  		return isp1301_otg_enable(isp);  	return 0; -#elif	!defined(CONFIG_USB_GADGET_OMAP) +#elif !IS_ENABLED(CONFIG_USB_OMAP)  	// FIXME update its refcount  	otg->host = host; @@ -1333,7 +1333,7 @@ isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)  {  	struct isp1301	*isp = container_of(otg->phy, struct isp1301, phy); -	if (!otg || isp != the_transceiver) +	if (isp != the_transceiver)  		return -ENODEV;  	if (!gadget) { @@ -1414,8 +1414,7 @@ isp1301_start_srp(struct usb_otg *otg)  	struct isp1301	*isp = container_of(otg->phy, struct isp1301, phy);  	u32		otg_ctrl; -	if (!otg || isp != the_transceiver -			|| isp->phy.state != OTG_STATE_B_IDLE) +	if (isp != the_transceiver || isp->phy.state != OTG_STATE_B_IDLE)  		return -ENODEV;  	otg_ctrl = omap_readl(OTG_CTRL); @@ -1442,7 +1441,7 @@ isp1301_start_hnp(struct usb_otg *otg)  	struct isp1301	*isp = container_of(otg->phy, struct isp1301, phy);  	u32 l; -	if (!otg || isp != the_transceiver) +	if (isp != the_transceiver)  		return -ENODEV;  	if (otg->default_a && (otg->host == NULL || !otg->host->b_hnp_enable))  		return -ENOTCONN; diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c new file mode 100644 index 00000000000..f4d722de912 --- /dev/null +++ b/drivers/usb/phy/phy-keystone.c @@ -0,0 +1,136 @@ +/* + * phy-keystone - USB PHY, talking to dwc3 controller in Keystone. + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: WingMan Kwok <w-kwok2@ti.com> + * + * 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/module.h> +#include <linux/platform_device.h> +#include <linux/usb/usb_phy_generic.h> +#include <linux/io.h> +#include <linux/of.h> + +#include "phy-generic.h" + +/* USB PHY control register offsets */ +#define USB_PHY_CTL_UTMI		0x0000 +#define USB_PHY_CTL_PIPE		0x0004 +#define USB_PHY_CTL_PARAM_1		0x0008 +#define USB_PHY_CTL_PARAM_2		0x000c +#define USB_PHY_CTL_CLOCK		0x0010 +#define USB_PHY_CTL_PLL			0x0014 + +#define PHY_REF_SSP_EN			BIT(29) + +struct keystone_usbphy { +	struct usb_phy_generic	usb_phy_gen; +	void __iomem			*phy_ctrl; +}; + +static inline u32 keystone_usbphy_readl(void __iomem *base, u32 offset) +{ +	return readl(base + offset); +} + +static inline void keystone_usbphy_writel(void __iomem *base, +					  u32 offset, u32 value) +{ +	writel(value, base + offset); +} + +static int keystone_usbphy_init(struct usb_phy *phy) +{ +	struct keystone_usbphy *k_phy = dev_get_drvdata(phy->dev); +	u32 val; + +	val  = keystone_usbphy_readl(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK); +	keystone_usbphy_writel(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK, +				val | PHY_REF_SSP_EN); +	return 0; +} + +static void keystone_usbphy_shutdown(struct usb_phy *phy) +{ +	struct keystone_usbphy *k_phy = dev_get_drvdata(phy->dev); +	u32 val; + +	val  = keystone_usbphy_readl(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK); +	keystone_usbphy_writel(k_phy->phy_ctrl, USB_PHY_CTL_CLOCK, +				val &= ~PHY_REF_SSP_EN); +} + +static int keystone_usbphy_probe(struct platform_device *pdev) +{ +	struct device		*dev = &pdev->dev; +	struct keystone_usbphy	*k_phy; +	struct resource		*res; +	int ret; + +	k_phy = devm_kzalloc(dev, sizeof(*k_phy), GFP_KERNEL); +	if (!k_phy) +		return -ENOMEM; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	k_phy->phy_ctrl = devm_ioremap_resource(dev, res); +	if (IS_ERR(k_phy->phy_ctrl)) +		return PTR_ERR(k_phy->phy_ctrl); + +	ret = usb_phy_gen_create_phy(dev, &k_phy->usb_phy_gen, NULL); +	if (ret) +		return ret; + +	k_phy->usb_phy_gen.phy.init = keystone_usbphy_init; +	k_phy->usb_phy_gen.phy.shutdown = keystone_usbphy_shutdown; + +	platform_set_drvdata(pdev, k_phy); + +	ret = usb_add_phy_dev(&k_phy->usb_phy_gen.phy); +	if (ret) +		return ret; + +	return 0; +} + +static int keystone_usbphy_remove(struct platform_device *pdev) +{ +	struct keystone_usbphy *k_phy = platform_get_drvdata(pdev); + +	usb_remove_phy(&k_phy->usb_phy_gen.phy); + +	return 0; +} + +static const struct of_device_id keystone_usbphy_ids[] = { +	{ .compatible = "ti,keystone-usbphy" }, +	{ } +}; +MODULE_DEVICE_TABLE(of, keystone_usbphy_ids); + +static struct platform_driver keystone_usbphy_driver = { +	.probe          = keystone_usbphy_probe, +	.remove         = keystone_usbphy_remove, +	.driver         = { +		.name   = "keystone-usbphy", +		.owner  = THIS_MODULE, +		.of_match_table = keystone_usbphy_ids, +	}, +}; + +module_platform_driver(keystone_usbphy_driver); + +MODULE_ALIAS("platform:keystone-usbphy"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("Keystone USB phy driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index e9d4cd960ec..c929370cdaa 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -30,9 +30,13 @@  #include <linux/debugfs.h>  #include <linux/seq_file.h>  #include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/reset.h>  #include <linux/usb.h>  #include <linux/usb/otg.h> +#include <linux/usb/of.h>  #include <linux/usb/ulpi.h>  #include <linux/usb/gadget.h>  #include <linux/usb/hcd.h> @@ -40,12 +44,11 @@  #include <linux/usb/msm_hsusb_hw.h>  #include <linux/regulator/consumer.h> -#include <mach/clk.h> -  #define MSM_USB_BASE	(motg->regs)  #define DRIVER_NAME	"msm_otg"  #define ULPI_IO_TIMEOUT_USEC	(10 * 1000) +#define LINK_RESET_TIMEOUT_USEC	(250 * 1000)  #define USB_PHY_3P3_VOL_MIN	3050000 /* uV */  #define USB_PHY_3P3_VOL_MAX	3300000 /* uV */ @@ -59,48 +62,38 @@  #define USB_PHY_VDD_DIG_VOL_MIN	1000000 /* uV */  #define USB_PHY_VDD_DIG_VOL_MAX	1320000 /* uV */ +#define USB_PHY_SUSP_DIG_VOL	500000  /* uV */ -static struct regulator *hsusb_3p3; -static struct regulator *hsusb_1p8; -static struct regulator *hsusb_vddcx; +enum vdd_levels { +	VDD_LEVEL_NONE = 0, +	VDD_LEVEL_MIN, +	VDD_LEVEL_MAX, +};  static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)  {  	int ret = 0;  	if (init) { -		hsusb_vddcx = regulator_get(motg->phy.dev, "HSUSB_VDDCX"); -		if (IS_ERR(hsusb_vddcx)) { -			dev_err(motg->phy.dev, "unable to get hsusb vddcx\n"); -			return PTR_ERR(hsusb_vddcx); -		} - -		ret = regulator_set_voltage(hsusb_vddcx, -				USB_PHY_VDD_DIG_VOL_MIN, -				USB_PHY_VDD_DIG_VOL_MAX); +		ret = regulator_set_voltage(motg->vddcx, +				motg->vdd_levels[VDD_LEVEL_MIN], +				motg->vdd_levels[VDD_LEVEL_MAX]);  		if (ret) { -			dev_err(motg->phy.dev, "unable to set the voltage " -					"for hsusb vddcx\n"); -			regulator_put(hsusb_vddcx); +			dev_err(motg->phy.dev, "Cannot set vddcx voltage\n");  			return ret;  		} -		ret = regulator_enable(hsusb_vddcx); -		if (ret) { +		ret = regulator_enable(motg->vddcx); +		if (ret)  			dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n"); -			regulator_put(hsusb_vddcx); -		}  	} else { -		ret = regulator_set_voltage(hsusb_vddcx, 0, -			USB_PHY_VDD_DIG_VOL_MAX); +		ret = regulator_set_voltage(motg->vddcx, 0, +				motg->vdd_levels[VDD_LEVEL_MAX]);  		if (ret) -			dev_err(motg->phy.dev, "unable to set the voltage " -					"for hsusb vddcx\n"); -		ret = regulator_disable(hsusb_vddcx); +			dev_err(motg->phy.dev, "Cannot set vddcx voltage\n"); +		ret = regulator_disable(motg->vddcx);  		if (ret)  			dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n"); - -		regulator_put(hsusb_vddcx);  	}  	return ret; @@ -111,124 +104,67 @@ static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)  	int rc = 0;  	if (init) { -		hsusb_3p3 = regulator_get(motg->phy.dev, "HSUSB_3p3"); -		if (IS_ERR(hsusb_3p3)) { -			dev_err(motg->phy.dev, "unable to get hsusb 3p3\n"); -			return PTR_ERR(hsusb_3p3); -		} - -		rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN, +		rc = regulator_set_voltage(motg->v3p3, USB_PHY_3P3_VOL_MIN,  				USB_PHY_3P3_VOL_MAX);  		if (rc) { -			dev_err(motg->phy.dev, "unable to set voltage level " -					"for hsusb 3p3\n"); -			goto put_3p3; +			dev_err(motg->phy.dev, "Cannot set v3p3 voltage\n"); +			goto exit;  		} -		rc = regulator_enable(hsusb_3p3); +		rc = regulator_enable(motg->v3p3);  		if (rc) {  			dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n"); -			goto put_3p3; -		} -		hsusb_1p8 = regulator_get(motg->phy.dev, "HSUSB_1p8"); -		if (IS_ERR(hsusb_1p8)) { -			dev_err(motg->phy.dev, "unable to get hsusb 1p8\n"); -			rc = PTR_ERR(hsusb_1p8); -			goto disable_3p3; +			goto exit;  		} -		rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN, +		rc = regulator_set_voltage(motg->v1p8, USB_PHY_1P8_VOL_MIN,  				USB_PHY_1P8_VOL_MAX);  		if (rc) { -			dev_err(motg->phy.dev, "unable to set voltage level " -					"for hsusb 1p8\n"); -			goto put_1p8; +			dev_err(motg->phy.dev, "Cannot set v1p8 voltage\n"); +			goto disable_3p3;  		} -		rc = regulator_enable(hsusb_1p8); +		rc = regulator_enable(motg->v1p8);  		if (rc) {  			dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n"); -			goto put_1p8; +			goto disable_3p3;  		}  		return 0;  	} -	regulator_disable(hsusb_1p8); -put_1p8: -	regulator_put(hsusb_1p8); +	regulator_disable(motg->v1p8);  disable_3p3: -	regulator_disable(hsusb_3p3); -put_3p3: -	regulator_put(hsusb_3p3); +	regulator_disable(motg->v3p3); +exit:  	return rc;  } -#ifdef CONFIG_PM_SLEEP -#define USB_PHY_SUSP_DIG_VOL  500000 -static int msm_hsusb_config_vddcx(int high) -{ -	int max_vol = USB_PHY_VDD_DIG_VOL_MAX; -	int min_vol; -	int ret; - -	if (high) -		min_vol = USB_PHY_VDD_DIG_VOL_MIN; -	else -		min_vol = USB_PHY_SUSP_DIG_VOL; - -	ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol); -	if (ret) { -		pr_err("%s: unable to set the voltage for regulator " -			"HSUSB_VDDCX\n", __func__); -		return ret; -	} - -	pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol); - -	return ret; -} -#endif - -static int msm_hsusb_ldo_set_mode(int on) +static int msm_hsusb_ldo_set_mode(struct msm_otg *motg, int on)  {  	int ret = 0; -	if (!hsusb_1p8 || IS_ERR(hsusb_1p8)) { -		pr_err("%s: HSUSB_1p8 is not initialized\n", __func__); -		return -ENODEV; -	} - -	if (!hsusb_3p3 || IS_ERR(hsusb_3p3)) { -		pr_err("%s: HSUSB_3p3 is not initialized\n", __func__); -		return -ENODEV; -	} -  	if (on) { -		ret = regulator_set_optimum_mode(hsusb_1p8, +		ret = regulator_set_optimum_mode(motg->v1p8,  				USB_PHY_1P8_HPM_LOAD);  		if (ret < 0) { -			pr_err("%s: Unable to set HPM of the regulator " -				"HSUSB_1p8\n", __func__); +			pr_err("Could not set HPM for v1p8\n");  			return ret;  		} -		ret = regulator_set_optimum_mode(hsusb_3p3, +		ret = regulator_set_optimum_mode(motg->v3p3,  				USB_PHY_3P3_HPM_LOAD);  		if (ret < 0) { -			pr_err("%s: Unable to set HPM of the regulator " -				"HSUSB_3p3\n", __func__); -			regulator_set_optimum_mode(hsusb_1p8, +			pr_err("Could not set HPM for v3p3\n"); +			regulator_set_optimum_mode(motg->v1p8,  				USB_PHY_1P8_LPM_LOAD);  			return ret;  		}  	} else { -		ret = regulator_set_optimum_mode(hsusb_1p8, +		ret = regulator_set_optimum_mode(motg->v1p8,  				USB_PHY_1P8_LPM_LOAD);  		if (ret < 0) -			pr_err("%s: Unable to set LPM of the regulator " -				"HSUSB_1p8\n", __func__); -		ret = regulator_set_optimum_mode(hsusb_3p3, +			pr_err("Could not set LPM for v1p8\n"); +		ret = regulator_set_optimum_mode(motg->v3p3,  				USB_PHY_3P3_LPM_LOAD);  		if (ret < 0) -			pr_err("%s: Unable to set LPM of the regulator " -				"HSUSB_3p3\n", __func__); +			pr_err("Could not set LPM for v3p3\n");  	}  	pr_debug("reg (%s)\n", on ? "HPM" : "LPM"); @@ -293,32 +229,51 @@ static struct usb_phy_io_ops msm_otg_io_ops = {  static void ulpi_init(struct msm_otg *motg)  {  	struct msm_otg_platform_data *pdata = motg->pdata; -	int *seq = pdata->phy_init_seq; +	int *seq = pdata->phy_init_seq, idx; +	u32 addr = ULPI_EXT_VENDOR_SPECIFIC; -	if (!seq) -		return; +	for (idx = 0; idx < pdata->phy_init_sz; idx++) { +		if (seq[idx] == -1) +			continue; -	while (seq[0] >= 0) {  		dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n", -				seq[0], seq[1]); -		ulpi_write(&motg->phy, seq[0], seq[1]); -		seq += 2; +				seq[idx], addr + idx); +		ulpi_write(&motg->phy, seq[idx], addr + idx);  	}  } +static int msm_phy_notify_disconnect(struct usb_phy *phy, +				   enum usb_device_speed speed) +{ +	int val; + +	/* +	 * Put the transceiver in non-driving mode. Otherwise host +	 * may not detect soft-disconnection. +	 */ +	val = ulpi_read(phy, ULPI_FUNC_CTRL); +	val &= ~ULPI_FUNC_CTRL_OPMODE_MASK; +	val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING; +	ulpi_write(phy, val, ULPI_FUNC_CTRL); + +	return 0; +} +  static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)  {  	int ret; -	if (assert) { -		ret = clk_reset(motg->clk, CLK_RESET_ASSERT); -		if (ret) -			dev_err(motg->phy.dev, "usb hs_clk assert failed\n"); -	} else { -		ret = clk_reset(motg->clk, CLK_RESET_DEASSERT); -		if (ret) -			dev_err(motg->phy.dev, "usb hs_clk deassert failed\n"); -	} +	if (motg->pdata->link_clk_reset) +		ret = motg->pdata->link_clk_reset(motg->clk, assert); +	else if (assert) +		ret = reset_control_assert(motg->link_rst); +	else +		ret = reset_control_deassert(motg->link_rst); + +	if (ret) +		dev_err(motg->phy.dev, "usb link clk reset %s failed\n", +			assert ? "assert" : "deassert"); +  	return ret;  } @@ -326,111 +281,148 @@ static int msm_otg_phy_clk_reset(struct msm_otg *motg)  {  	int ret; -	ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT); -	if (ret) { -		dev_err(motg->phy.dev, "usb phy clk assert failed\n"); -		return ret; -	} -	usleep_range(10000, 12000); -	ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT); +	if (motg->pdata->phy_clk_reset) +		ret = motg->pdata->phy_clk_reset(motg->phy_reset_clk); +	else +		ret = reset_control_reset(motg->phy_rst); +  	if (ret) -		dev_err(motg->phy.dev, "usb phy clk deassert failed\n"); +		dev_err(motg->phy.dev, "usb phy clk reset failed\n"); +  	return ret;  } -static int msm_otg_phy_reset(struct msm_otg *motg) +static int msm_link_reset(struct msm_otg *motg)  {  	u32 val;  	int ret; -	int retries;  	ret = msm_otg_link_clk_reset(motg, 1);  	if (ret)  		return ret; -	ret = msm_otg_phy_clk_reset(motg); -	if (ret) -		return ret; + +	/* wait for 1ms delay as suggested in HPG. */ +	usleep_range(1000, 1200); +  	ret = msm_otg_link_clk_reset(motg, 0);  	if (ret)  		return ret; +	if (motg->phy_number) +		writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); + +	/* put transceiver in serial mode as part of reset */  	val = readl(USB_PORTSC) & ~PORTSC_PTS_MASK; -	writel(val | PORTSC_PTS_ULPI, USB_PORTSC); +	writel(val | PORTSC_PTS_SERIAL, USB_PORTSC); -	for (retries = 3; retries > 0; retries--) { -		ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM, -				ULPI_CLR(ULPI_FUNC_CTRL)); -		if (!ret) -			break; -		ret = msm_otg_phy_clk_reset(motg); -		if (ret) -			return ret; -	} -	if (!retries) -		return -ETIMEDOUT; +	return 0; +} -	/* This reset calibrates the phy, if the above write succeeded */ -	ret = msm_otg_phy_clk_reset(motg); -	if (ret) -		return ret; +static int msm_otg_reset(struct usb_phy *phy) +{ +	struct msm_otg *motg = container_of(phy, struct msm_otg, phy); +	int cnt = 0; -	for (retries = 3; retries > 0; retries--) { -		ret = ulpi_read(&motg->phy, ULPI_DEBUG); -		if (ret != -ETIMEDOUT) +	writel(USBCMD_RESET, USB_USBCMD); +	while (cnt < LINK_RESET_TIMEOUT_USEC) { +		if (!(readl(USB_USBCMD) & USBCMD_RESET))  			break; -		ret = msm_otg_phy_clk_reset(motg); -		if (ret) -			return ret; +		udelay(1); +		cnt++;  	} -	if (!retries) +	if (cnt >= LINK_RESET_TIMEOUT_USEC)  		return -ETIMEDOUT; -	dev_info(motg->phy.dev, "phy_reset: success\n"); +	/* select ULPI phy and clear other status/control bits in PORTSC */ +	writel(PORTSC_PTS_ULPI, USB_PORTSC); + +	writel(0x0, USB_AHBBURST); +	writel(0x08, USB_AHBMODE); + +	if (motg->phy_number) +		writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);  	return 0;  } -#define LINK_RESET_TIMEOUT_USEC		(250 * 1000) -static int msm_otg_reset(struct usb_phy *phy) +static void msm_phy_reset(struct msm_otg *motg) +{ +	void __iomem *addr; + +	if (motg->pdata->phy_type != SNPS_28NM_INTEGRATED_PHY) { +		msm_otg_phy_clk_reset(motg); +		return; +	} + +	addr = USB_PHY_CTRL; +	if (motg->phy_number) +		addr = USB_PHY_CTRL2; + +	/* Assert USB PHY_POR */ +	writel(readl(addr) | PHY_POR_ASSERT, addr); + +	/* +	 * wait for minimum 10 microseconds as suggested in HPG. +	 * Use a slightly larger value since the exact value didn't +	 * work 100% of the time. +	 */ +	udelay(12); + +	/* Deassert USB PHY_POR */ +	writel(readl(addr) & ~PHY_POR_ASSERT, addr); +} + +static int msm_usb_reset(struct usb_phy *phy)  {  	struct msm_otg *motg = container_of(phy, struct msm_otg, phy); -	struct msm_otg_platform_data *pdata = motg->pdata; -	int cnt = 0;  	int ret; -	u32 val = 0; -	u32 ulpi_val = 0; -	ret = msm_otg_phy_reset(motg); +	if (!IS_ERR(motg->core_clk)) +		clk_prepare_enable(motg->core_clk); + +	ret = msm_link_reset(motg);  	if (ret) {  		dev_err(phy->dev, "phy_reset failed\n");  		return ret;  	} -	ulpi_init(motg); - -	writel(USBCMD_RESET, USB_USBCMD); -	while (cnt < LINK_RESET_TIMEOUT_USEC) { -		if (!(readl(USB_USBCMD) & USBCMD_RESET)) -			break; -		udelay(1); -		cnt++; +	ret = msm_otg_reset(&motg->phy); +	if (ret) { +		dev_err(phy->dev, "link reset failed\n"); +		return ret;  	} -	if (cnt >= LINK_RESET_TIMEOUT_USEC) -		return -ETIMEDOUT; - -	/* select ULPI phy */ -	writel(0x80000000, USB_PORTSC);  	msleep(100); -	writel(0x0, USB_AHBBURST); -	writel(0x00, USB_AHBMODE); +	/* Reset USB PHY after performing USB Link RESET */ +	msm_phy_reset(motg); + +	if (!IS_ERR(motg->core_clk)) +		clk_disable_unprepare(motg->core_clk); + +	return 0; +} + +static int msm_phy_init(struct usb_phy *phy) +{ +	struct msm_otg *motg = container_of(phy, struct msm_otg, phy); +	struct msm_otg_platform_data *pdata = motg->pdata; +	u32 val, ulpi_val = 0; + +	/* Program USB PHY Override registers. */ +	ulpi_init(motg); + +	/* +	 * It is recommended in HPG to reset USB PHY after programming +	 * USB PHY Override registers. +	 */ +	msm_phy_reset(motg);  	if (pdata->otg_control == OTG_PHY_CONTROL) {  		val = readl(USB_OTGSC); -		if (pdata->mode == USB_OTG) { +		if (pdata->mode == USB_DR_MODE_OTG) {  			ulpi_val = ULPI_INT_IDGRD | ULPI_INT_SESS_VALID;  			val |= OTGSC_IDIE | OTGSC_BSVIE; -		} else if (pdata->mode == USB_PERIPHERAL) { +		} else if (pdata->mode == USB_DR_MODE_PERIPHERAL) {  			ulpi_val = ULPI_INT_SESS_VALID;  			val |= OTGSC_BSVIE;  		} @@ -439,18 +431,45 @@ static int msm_otg_reset(struct usb_phy *phy)  		ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);  	} +	if (motg->phy_number) +		writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2); +  	return 0;  }  #define PHY_SUSPEND_TIMEOUT_USEC	(500 * 1000)  #define PHY_RESUME_TIMEOUT_USEC	(100 * 1000) -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM + +static int msm_hsusb_config_vddcx(struct msm_otg *motg, int high) +{ +	int max_vol = motg->vdd_levels[VDD_LEVEL_MAX]; +	int min_vol; +	int ret; + +	if (high) +		min_vol = motg->vdd_levels[VDD_LEVEL_MIN]; +	else +		min_vol = motg->vdd_levels[VDD_LEVEL_NONE]; + +	ret = regulator_set_voltage(motg->vddcx, min_vol, max_vol); +	if (ret) { +		pr_err("Cannot set vddcx voltage\n"); +		return ret; +	} + +	pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol); + +	return ret; +} +  static int msm_otg_suspend(struct msm_otg *motg)  {  	struct usb_phy *phy = &motg->phy;  	struct usb_bus *bus = phy->otg->host;  	struct msm_otg_platform_data *pdata = motg->pdata; +	void __iomem *addr;  	int cnt = 0;  	if (atomic_read(&motg->in_lpm)) @@ -510,22 +529,23 @@ static int msm_otg_suspend(struct msm_otg *motg)  	 */  	writel(readl(USB_USBCMD) | ASYNC_INTR_CTRL | ULPI_STP_CTRL, USB_USBCMD); +	addr = USB_PHY_CTRL; +	if (motg->phy_number) +		addr = USB_PHY_CTRL2; +  	if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&  			motg->pdata->otg_control == OTG_PMIC_CONTROL) -		writel(readl(USB_PHY_CTRL) | PHY_RETEN, USB_PHY_CTRL); +		writel(readl(addr) | PHY_RETEN, addr);  	clk_disable_unprepare(motg->pclk);  	clk_disable_unprepare(motg->clk); -	if (motg->core_clk) +	if (!IS_ERR(motg->core_clk))  		clk_disable_unprepare(motg->core_clk); -	if (!IS_ERR(motg->pclk_src)) -		clk_disable_unprepare(motg->pclk_src); -  	if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&  			motg->pdata->otg_control == OTG_PMIC_CONTROL) { -		msm_hsusb_ldo_set_mode(0); -		msm_hsusb_config_vddcx(0); +		msm_hsusb_ldo_set_mode(motg, 0); +		msm_hsusb_config_vddcx(motg, 0);  	}  	if (device_may_wakeup(phy->dev)) @@ -545,25 +565,28 @@ static int msm_otg_resume(struct msm_otg *motg)  {  	struct usb_phy *phy = &motg->phy;  	struct usb_bus *bus = phy->otg->host; +	void __iomem *addr;  	int cnt = 0;  	unsigned temp;  	if (!atomic_read(&motg->in_lpm))  		return 0; -	if (!IS_ERR(motg->pclk_src)) -		clk_prepare_enable(motg->pclk_src); -  	clk_prepare_enable(motg->pclk);  	clk_prepare_enable(motg->clk); -	if (motg->core_clk) +	if (!IS_ERR(motg->core_clk))  		clk_prepare_enable(motg->core_clk);  	if (motg->pdata->phy_type == SNPS_28NM_INTEGRATED_PHY &&  			motg->pdata->otg_control == OTG_PMIC_CONTROL) { -		msm_hsusb_ldo_set_mode(1); -		msm_hsusb_config_vddcx(1); -		writel(readl(USB_PHY_CTRL) & ~PHY_RETEN, USB_PHY_CTRL); + +		addr = USB_PHY_CTRL; +		if (motg->phy_number) +			addr = USB_PHY_CTRL2; + +		msm_hsusb_ldo_set_mode(motg, 1); +		msm_hsusb_config_vddcx(motg, 1); +		writel(readl(addr) & ~PHY_RETEN, addr);  	}  	temp = readl(USB_USBCMD); @@ -592,8 +615,7 @@ static int msm_otg_resume(struct msm_otg *motg)  		 * PHY. USB state can not be restored. Re-insertion  		 * of USB cable is the only way to get USB working.  		 */ -		dev_err(phy->dev, "Unable to resume USB." -				"Re-plugin the cable\n"); +		dev_err(phy->dev, "Unable to resume USB. Re-plugin the cable\n");  		msm_otg_reset(phy);  	} @@ -669,6 +691,7 @@ static void msm_otg_start_host(struct usb_phy *phy, int on)  			pdata->setup_gpio(OTG_STATE_A_HOST);  #ifdef CONFIG_USB  		usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); +		device_wakeup_enable(hcd->self.controller);  #endif  	} else {  		dev_dbg(phy->dev, "host off\n"); @@ -692,7 +715,7 @@ static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)  	 * Fail host registration if this board can support  	 * only peripheral configuration.  	 */ -	if (motg->pdata->mode == USB_PERIPHERAL) { +	if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL) {  		dev_info(otg->phy->dev, "Host mode is not supported\n");  		return -ENODEV;  	} @@ -721,7 +744,7 @@ static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)  	 * Kick the state machine work, if peripheral is not supported  	 * or peripheral is already registered with us.  	 */ -	if (motg->pdata->mode == USB_HOST || otg->gadget) { +	if (motg->pdata->mode == USB_DR_MODE_HOST || otg->gadget) {  		pm_runtime_get_sync(otg->phy->dev);  		schedule_work(&motg->sm_work);  	} @@ -765,7 +788,7 @@ static int msm_otg_set_peripheral(struct usb_otg *otg,  	 * Fail peripheral registration if this board can support  	 * only host configuration.  	 */ -	if (motg->pdata->mode == USB_HOST) { +	if (motg->pdata->mode == USB_DR_MODE_HOST) {  		dev_info(otg->phy->dev, "Peripheral mode is not supported\n");  		return -ENODEV;  	} @@ -790,7 +813,7 @@ static int msm_otg_set_peripheral(struct usb_otg *otg,  	 * Kick the state machine work, if host is not supported  	 * or host is already registered with us.  	 */ -	if (motg->pdata->mode == USB_PERIPHERAL || otg->host) { +	if (motg->pdata->mode == USB_DR_MODE_PERIPHERAL || otg->host) {  		pm_runtime_get_sync(otg->phy->dev);  		schedule_work(&motg->sm_work);  	} @@ -1111,7 +1134,7 @@ static void msm_otg_init_sm(struct msm_otg *motg)  	u32 otgsc = readl(USB_OTGSC);  	switch (pdata->mode) { -	case USB_OTG: +	case USB_DR_MODE_OTG:  		if (pdata->otg_control == OTG_PHY_CONTROL) {  			if (otgsc & OTGSC_ID)  				set_bit(ID, &motg->inputs); @@ -1123,21 +1146,14 @@ static void msm_otg_init_sm(struct msm_otg *motg)  			else  				clear_bit(B_SESS_VLD, &motg->inputs);  		} else if (pdata->otg_control == OTG_USER_CONTROL) { -			if (pdata->default_mode == USB_HOST) { -				clear_bit(ID, &motg->inputs); -			} else if (pdata->default_mode == USB_PERIPHERAL) { -				set_bit(ID, &motg->inputs); -				set_bit(B_SESS_VLD, &motg->inputs); -			} else {  				set_bit(ID, &motg->inputs);  				clear_bit(B_SESS_VLD, &motg->inputs); -			}  		}  		break; -	case USB_HOST: +	case USB_DR_MODE_HOST:  		clear_bit(ID, &motg->inputs);  		break; -	case USB_PERIPHERAL: +	case USB_DR_MODE_PERIPHERAL:  		set_bit(ID, &motg->inputs);  		if (otgsc & OTGSC_BSV)  			set_bit(B_SESS_VLD, &motg->inputs); @@ -1213,7 +1229,9 @@ static void msm_otg_sm_work(struct work_struct *w)  			motg->chg_state = USB_CHG_STATE_UNDEFINED;  			motg->chg_type = USB_INVALID_CHARGER;  		} -		pm_runtime_put_sync(otg->phy->dev); + +		if (otg->phy->state == OTG_STATE_B_IDLE) +			pm_runtime_put_sync(otg->phy->dev);  		break;  	case OTG_STATE_B_PERIPHERAL:  		dev_dbg(otg->phy->dev, "OTG_STATE_B_PERIPHERAL state\n"); @@ -1287,13 +1305,13 @@ static int msm_otg_mode_show(struct seq_file *s, void *unused)  	switch (otg->phy->state) {  	case OTG_STATE_A_HOST: -		seq_printf(s, "host\n"); +		seq_puts(s, "host\n");  		break;  	case OTG_STATE_B_PERIPHERAL: -		seq_printf(s, "peripheral\n"); +		seq_puts(s, "peripheral\n");  		break;  	default: -		seq_printf(s, "none\n"); +		seq_puts(s, "none\n");  		break;  	} @@ -1313,7 +1331,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,  	char buf[16];  	struct usb_otg *otg = motg->phy.otg;  	int status = count; -	enum usb_mode_type req_mode; +	enum usb_dr_mode req_mode;  	memset(buf, 0x00, sizeof(buf)); @@ -1323,18 +1341,18 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,  	}  	if (!strncmp(buf, "host", 4)) { -		req_mode = USB_HOST; +		req_mode = USB_DR_MODE_HOST;  	} else if (!strncmp(buf, "peripheral", 10)) { -		req_mode = USB_PERIPHERAL; +		req_mode = USB_DR_MODE_PERIPHERAL;  	} else if (!strncmp(buf, "none", 4)) { -		req_mode = USB_NONE; +		req_mode = USB_DR_MODE_UNKNOWN;  	} else {  		status = -EINVAL;  		goto out;  	}  	switch (req_mode) { -	case USB_NONE: +	case USB_DR_MODE_UNKNOWN:  		switch (otg->phy->state) {  		case OTG_STATE_A_HOST:  		case OTG_STATE_B_PERIPHERAL: @@ -1345,7 +1363,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,  			goto out;  		}  		break; -	case USB_PERIPHERAL: +	case USB_DR_MODE_PERIPHERAL:  		switch (otg->phy->state) {  		case OTG_STATE_B_IDLE:  		case OTG_STATE_A_HOST: @@ -1356,7 +1374,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,  			goto out;  		}  		break; -	case USB_HOST: +	case USB_DR_MODE_HOST:  		switch (otg->phy->state) {  		case OTG_STATE_B_IDLE:  		case OTG_STATE_B_PERIPHERAL: @@ -1411,73 +1429,154 @@ static void msm_otg_debugfs_cleanup(void)  	debugfs_remove(msm_otg_dbg_root);  } -static int __init msm_otg_probe(struct platform_device *pdev) +static struct of_device_id msm_otg_dt_match[] = { +	{ +		.compatible = "qcom,usb-otg-ci", +		.data = (void *) CI_45NM_INTEGRATED_PHY +	}, +	{ +		.compatible = "qcom,usb-otg-snps", +		.data = (void *) SNPS_28NM_INTEGRATED_PHY +	}, +	{ } +}; +MODULE_DEVICE_TABLE(of, msm_otg_dt_match); + +static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) +{ +	struct msm_otg_platform_data *pdata; +	const struct of_device_id *id; +	struct device_node *node = pdev->dev.of_node; +	struct property *prop; +	int len, ret, words; +	u32 val, tmp[3]; + +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata) +		return -ENOMEM; + +	motg->pdata = pdata; + +	id = of_match_device(msm_otg_dt_match, &pdev->dev); +	pdata->phy_type = (enum msm_usb_phy_type) id->data; + +	motg->link_rst = devm_reset_control_get(&pdev->dev, "link"); +	if (IS_ERR(motg->link_rst)) +		return PTR_ERR(motg->link_rst); + +	motg->phy_rst = devm_reset_control_get(&pdev->dev, "phy"); +	if (IS_ERR(motg->phy_rst)) +		return PTR_ERR(motg->phy_rst); + +	pdata->mode = of_usb_get_dr_mode(node); +	if (pdata->mode == USB_DR_MODE_UNKNOWN) +		pdata->mode = USB_DR_MODE_OTG; + +	pdata->otg_control = OTG_PHY_CONTROL; +	if (!of_property_read_u32(node, "qcom,otg-control", &val)) +		if (val == OTG_PMIC_CONTROL) +			pdata->otg_control = val; + +	if (!of_property_read_u32(node, "qcom,phy-num", &val) && val < 2) +		motg->phy_number = val; + +	motg->vdd_levels[VDD_LEVEL_NONE] = USB_PHY_SUSP_DIG_VOL; +	motg->vdd_levels[VDD_LEVEL_MIN] = USB_PHY_VDD_DIG_VOL_MIN; +	motg->vdd_levels[VDD_LEVEL_MAX] = USB_PHY_VDD_DIG_VOL_MAX; + +	if (of_get_property(node, "qcom,vdd-levels", &len) && +	    len == sizeof(tmp)) { +		of_property_read_u32_array(node, "qcom,vdd-levels", +					   tmp, len / sizeof(*tmp)); +		motg->vdd_levels[VDD_LEVEL_NONE] = tmp[VDD_LEVEL_NONE]; +		motg->vdd_levels[VDD_LEVEL_MIN] = tmp[VDD_LEVEL_MIN]; +		motg->vdd_levels[VDD_LEVEL_MAX] = tmp[VDD_LEVEL_MAX]; +	} + +	prop = of_find_property(node, "qcom,phy-init-sequence", &len); +	if (!prop || !len) +		return 0; + +	words = len / sizeof(u32); + +	if (words >= ULPI_EXT_VENDOR_SPECIFIC) { +		dev_warn(&pdev->dev, "Too big PHY init sequence %d\n", words); +		return 0; +	} + +	pdata->phy_init_seq = devm_kzalloc(&pdev->dev, len, GFP_KERNEL); +	if (!pdata->phy_init_seq) { +		dev_warn(&pdev->dev, "No space for PHY init sequence\n"); +		return 0; +	} + +	ret = of_property_read_u32_array(node, "qcom,phy-init-sequence", +					 pdata->phy_init_seq, words); +	if (!ret) +		pdata->phy_init_sz = words; + +	return 0; +} + +static int msm_otg_probe(struct platform_device *pdev)  { +	struct regulator_bulk_data regs[3];  	int ret = 0; +	struct device_node *np = pdev->dev.of_node; +	struct msm_otg_platform_data *pdata;  	struct resource *res;  	struct msm_otg *motg;  	struct usb_phy *phy; +	void __iomem *phy_select; -	dev_info(&pdev->dev, "msm_otg probe\n"); -	if (!dev_get_platdata(&pdev->dev)) { -		dev_err(&pdev->dev, "No platform data given. Bailing out\n"); -		return -ENODEV; -	} - -	motg = kzalloc(sizeof(struct msm_otg), GFP_KERNEL); +	motg = devm_kzalloc(&pdev->dev, sizeof(struct msm_otg), GFP_KERNEL);  	if (!motg) {  		dev_err(&pdev->dev, "unable to allocate msm_otg\n");  		return -ENOMEM;  	} -	motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL); +	pdata = dev_get_platdata(&pdev->dev); +	if (!pdata) { +		if (!np) +			return -ENXIO; +		ret = msm_otg_read_dt(pdev, motg); +		if (ret) +			return ret; +	} + +	motg->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), +				     GFP_KERNEL);  	if (!motg->phy.otg) {  		dev_err(&pdev->dev, "unable to allocate msm_otg\n");  		return -ENOMEM;  	} -	motg->pdata = dev_get_platdata(&pdev->dev);  	phy = &motg->phy;  	phy->dev = &pdev->dev; -	motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk"); +	motg->phy_reset_clk = devm_clk_get(&pdev->dev, +					   np ? "phy" : "usb_phy_clk");  	if (IS_ERR(motg->phy_reset_clk)) {  		dev_err(&pdev->dev, "failed to get usb_phy_clk\n"); -		ret = PTR_ERR(motg->phy_reset_clk); -		goto free_motg; +		return PTR_ERR(motg->phy_reset_clk);  	} -	motg->clk = clk_get(&pdev->dev, "usb_hs_clk"); +	motg->clk = devm_clk_get(&pdev->dev, np ? "core" : "usb_hs_clk");  	if (IS_ERR(motg->clk)) {  		dev_err(&pdev->dev, "failed to get usb_hs_clk\n"); -		ret = PTR_ERR(motg->clk); -		goto put_phy_reset_clk; +		return PTR_ERR(motg->clk);  	} -	clk_set_rate(motg->clk, 60000000);  	/*  	 * If USB Core is running its protocol engine based on CORE CLK,  	 * CORE CLK  must be running at >55Mhz for correct HSUSB  	 * operation and USB core cannot tolerate frequency changes on -	 * CORE CLK. For such USB cores, vote for maximum clk frequency -	 * on pclk source +	 * CORE CLK.  	 */ -	 if (motg->pdata->pclk_src_name) { -		motg->pclk_src = clk_get(&pdev->dev, -			motg->pdata->pclk_src_name); -		if (IS_ERR(motg->pclk_src)) -			goto put_clk; -		clk_set_rate(motg->pclk_src, INT_MAX); -		clk_prepare_enable(motg->pclk_src); -	} else -		motg->pclk_src = ERR_PTR(-ENOENT); - - -	motg->pclk = clk_get(&pdev->dev, "usb_hs_pclk"); +	motg->pclk = devm_clk_get(&pdev->dev, np ? "iface" : "usb_hs_pclk");  	if (IS_ERR(motg->pclk)) {  		dev_err(&pdev->dev, "failed to get usb_hs_pclk\n"); -		ret = PTR_ERR(motg->pclk); -		goto put_pclk_src; +		return PTR_ERR(motg->pclk);  	}  	/* @@ -1485,69 +1584,90 @@ static int __init msm_otg_probe(struct platform_device *pdev)  	 * clock is introduced to remove the dependency on AXI  	 * bus frequency.  	 */ -	motg->core_clk = clk_get(&pdev->dev, "usb_hs_core_clk"); -	if (IS_ERR(motg->core_clk)) -		motg->core_clk = NULL; +	motg->core_clk = devm_clk_get(&pdev->dev, +				      np ? "alt_core" : "usb_hs_core_clk");  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) { -		dev_err(&pdev->dev, "failed to get platform resource mem\n"); -		ret = -ENODEV; -		goto put_core_clk; -	} +	if (!res) +		return -EINVAL; +	motg->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); +	if (!motg->regs) +		return -ENOMEM; -	motg->regs = ioremap(res->start, resource_size(res)); -	if (!motg->regs) { -		dev_err(&pdev->dev, "ioremap failed\n"); -		ret = -ENOMEM; -		goto put_core_clk; +	/* +	 * NOTE: The PHYs can be multiplexed between the chipidea controller +	 * and the dwc3 controller, using a single bit. It is important that +	 * the dwc3 driver does not set this bit in an incompatible way. +	 */ +	if (motg->phy_number) { +		phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4); +		if (IS_ERR(phy_select)) +			return PTR_ERR(phy_select); +		/* Enable second PHY with the OTG port */ +		writel(0x1, phy_select);  	} +  	dev_info(&pdev->dev, "OTG regs = %p\n", motg->regs);  	motg->irq = platform_get_irq(pdev, 0); -	if (!motg->irq) { +	if (motg->irq < 0) {  		dev_err(&pdev->dev, "platform_get_irq failed\n"); -		ret = -ENODEV; -		goto free_regs; +		return motg->irq;  	} +	regs[0].supply = "vddcx"; +	regs[1].supply = "v3p3"; +	regs[2].supply = "v1p8"; + +	ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs); +	if (ret) +		return ret; + +	motg->vddcx = regs[0].consumer; +	motg->v3p3  = regs[1].consumer; +	motg->v1p8  = regs[2].consumer; + +	clk_set_rate(motg->clk, 60000000); +  	clk_prepare_enable(motg->clk);  	clk_prepare_enable(motg->pclk); +	if (!IS_ERR(motg->core_clk)) +		clk_prepare_enable(motg->core_clk); +  	ret = msm_hsusb_init_vddcx(motg, 1);  	if (ret) {  		dev_err(&pdev->dev, "hsusb vddcx configuration failed\n"); -		goto free_regs; +		goto disable_clks;  	}  	ret = msm_hsusb_ldo_init(motg, 1);  	if (ret) {  		dev_err(&pdev->dev, "hsusb vreg configuration failed\n"); -		goto vddcx_exit; +		goto disable_vddcx;  	} -	ret = msm_hsusb_ldo_set_mode(1); +	ret = msm_hsusb_ldo_set_mode(motg, 1);  	if (ret) {  		dev_err(&pdev->dev, "hsusb vreg enable failed\n"); -		goto ldo_exit; +		goto disable_ldo;  	} -	if (motg->core_clk) -		clk_prepare_enable(motg->core_clk); -  	writel(0, USB_USBINTR);  	writel(0, USB_OTGSC);  	INIT_WORK(&motg->sm_work, msm_otg_sm_work);  	INIT_DELAYED_WORK(&motg->chg_work, msm_chg_detect_work); -	ret = request_irq(motg->irq, msm_otg_irq, IRQF_SHARED, +	ret = devm_request_irq(&pdev->dev, motg->irq, msm_otg_irq, IRQF_SHARED,  					"msm_otg", motg);  	if (ret) {  		dev_err(&pdev->dev, "request irq failed\n"); -		goto disable_clks; +		goto disable_ldo;  	} -	phy->init = msm_otg_reset; +	phy->init = msm_phy_init;  	phy->set_power = msm_otg_set_power; +	phy->notify_disconnect = msm_phy_notify_disconnect; +	phy->type = USB_PHY_TYPE_USB2;  	phy->io_ops = &msm_otg_io_ops; @@ -1555,54 +1675,38 @@ static int __init msm_otg_probe(struct platform_device *pdev)  	phy->otg->set_host = msm_otg_set_host;  	phy->otg->set_peripheral = msm_otg_set_peripheral; -	ret = usb_add_phy(&motg->phy, USB_PHY_TYPE_USB2); +	msm_usb_reset(phy); + +	ret = usb_add_phy_dev(&motg->phy);  	if (ret) {  		dev_err(&pdev->dev, "usb_add_phy failed\n"); -		goto free_irq; +		goto disable_ldo;  	}  	platform_set_drvdata(pdev, motg);  	device_init_wakeup(&pdev->dev, 1); -	if (motg->pdata->mode == USB_OTG && -			motg->pdata->otg_control == OTG_USER_CONTROL) { +	if (motg->pdata->mode == USB_DR_MODE_OTG && +		motg->pdata->otg_control == OTG_USER_CONTROL) {  		ret = msm_otg_debugfs_init(motg);  		if (ret) -			dev_dbg(&pdev->dev, "mode debugfs file is" -					"not available\n"); +			dev_dbg(&pdev->dev, "Can not create mode change file\n");  	}  	pm_runtime_set_active(&pdev->dev);  	pm_runtime_enable(&pdev->dev);  	return 0; -free_irq: -	free_irq(motg->irq, motg); + +disable_ldo: +	msm_hsusb_ldo_init(motg, 0); +disable_vddcx: +	msm_hsusb_init_vddcx(motg, 0);  disable_clks:  	clk_disable_unprepare(motg->pclk);  	clk_disable_unprepare(motg->clk); -ldo_exit: -	msm_hsusb_ldo_init(motg, 0); -vddcx_exit: -	msm_hsusb_init_vddcx(motg, 0); -free_regs: -	iounmap(motg->regs); -put_core_clk: -	if (motg->core_clk) -		clk_put(motg->core_clk); -	clk_put(motg->pclk); -put_pclk_src: -	if (!IS_ERR(motg->pclk_src)) { -		clk_disable_unprepare(motg->pclk_src); -		clk_put(motg->pclk_src); -	} -put_clk: -	clk_put(motg->clk); -put_phy_reset_clk: -	clk_put(motg->phy_reset_clk); -free_motg: -	kfree(motg->phy.otg); -	kfree(motg); +	if (!IS_ERR(motg->core_clk)) +		clk_disable_unprepare(motg->core_clk);  	return ret;  } @@ -1625,7 +1729,7 @@ static int msm_otg_remove(struct platform_device *pdev)  	pm_runtime_disable(&pdev->dev);  	usb_remove_phy(phy); -	free_irq(motg->irq, motg); +	disable_irq(motg->irq);  	/*  	 * Put PHY in low power mode. @@ -1645,26 +1749,12 @@ static int msm_otg_remove(struct platform_device *pdev)  	clk_disable_unprepare(motg->pclk);  	clk_disable_unprepare(motg->clk); -	if (motg->core_clk) +	if (!IS_ERR(motg->core_clk))  		clk_disable_unprepare(motg->core_clk); -	if (!IS_ERR(motg->pclk_src)) { -		clk_disable_unprepare(motg->pclk_src); -		clk_put(motg->pclk_src); -	}  	msm_hsusb_ldo_init(motg, 0); -	iounmap(motg->regs);  	pm_runtime_set_suspended(&pdev->dev); -	clk_put(motg->phy_reset_clk); -	clk_put(motg->pclk); -	clk_put(motg->clk); -	if (motg->core_clk) -		clk_put(motg->core_clk); - -	kfree(motg->phy.otg); -	kfree(motg); -  	return 0;  } @@ -1737,26 +1827,24 @@ static int msm_otg_pm_resume(struct device *dev)  }  #endif -#ifdef CONFIG_PM  static const struct dev_pm_ops msm_otg_dev_pm_ops = {  	SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume)  	SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume,  				msm_otg_runtime_idle)  }; -#endif  static struct platform_driver msm_otg_driver = { +	.probe = msm_otg_probe,  	.remove = msm_otg_remove,  	.driver = {  		.name = DRIVER_NAME,  		.owner = THIS_MODULE, -#ifdef CONFIG_PM  		.pm = &msm_otg_dev_pm_ops, -#endif +		.of_match_table = msm_otg_dt_match,  	},  }; -module_platform_driver_probe(msm_otg_driver, msm_otg_probe); +module_platform_driver(msm_otg_driver);  MODULE_LICENSE("GPL v2");  MODULE_DESCRIPTION("MSM USB transceiver driver"); diff --git a/drivers/usb/phy/phy-mv-u3d-usb.c b/drivers/usb/phy/phy-mv-u3d-usb.c deleted file mode 100644 index d317903022b..00000000000 --- a/drivers/usb/phy/phy-mv-u3d-usb.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (C) 2011 Marvell International Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/usb/otg.h> -#include <linux/platform_data/mv_usb.h> - -#include "phy-mv-u3d-usb.h" - -/* - * struct mv_u3d_phy - transceiver driver state - * @phy: transceiver structure - * @dev: The parent device supplied to the probe function - * @clk: usb phy clock - * @base: usb phy register memory base - */ -struct mv_u3d_phy { -	struct usb_phy	phy; -	struct mv_usb_platform_data *plat; -	struct device	*dev; -	struct clk	*clk; -	void __iomem	*base; -}; - -static u32 mv_u3d_phy_read(void __iomem *base, u32 reg) -{ -	void __iomem *addr, *data; - -	addr = base; -	data = base + 0x4; - -	writel_relaxed(reg, addr); -	return readl_relaxed(data); -} - -static void mv_u3d_phy_set(void __iomem *base, u32 reg, u32 value) -{ -	void __iomem *addr, *data; -	u32 tmp; - -	addr = base; -	data = base + 0x4; - -	writel_relaxed(reg, addr); -	tmp = readl_relaxed(data); -	tmp |= value; -	writel_relaxed(tmp, data); -} - -static void mv_u3d_phy_clear(void __iomem *base, u32 reg, u32 value) -{ -	void __iomem *addr, *data; -	u32 tmp; - -	addr = base; -	data = base + 0x4; - -	writel_relaxed(reg, addr); -	tmp = readl_relaxed(data); -	tmp &= ~value; -	writel_relaxed(tmp, data); -} - -static void mv_u3d_phy_write(void __iomem *base, u32 reg, u32 value) -{ -	void __iomem *addr, *data; - -	addr = base; -	data = base + 0x4; - -	writel_relaxed(reg, addr); -	writel_relaxed(value, data); -} - -static void mv_u3d_phy_shutdown(struct usb_phy *phy) -{ -	struct mv_u3d_phy *mv_u3d_phy; -	void __iomem *base; -	u32 val; - -	mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy); -	base = mv_u3d_phy->base; - -	/* Power down Reference Analog current, bit 15 -	 * Power down PLL, bit 14 -	 * Power down Receiver, bit 13 -	 * Power down Transmitter, bit 12 -	 * of USB3_POWER_PLL_CONTROL register -	 */ -	val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL); -	val &= ~(USB3_POWER_PLL_CONTROL_PU); -	mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val); - -	if (mv_u3d_phy->clk) -		clk_disable(mv_u3d_phy->clk); -} - -static int mv_u3d_phy_init(struct usb_phy *phy) -{ -	struct mv_u3d_phy *mv_u3d_phy; -	void __iomem *base; -	u32 val, count; - -	/* enable usb3 phy */ -	mv_u3d_phy = container_of(phy, struct mv_u3d_phy, phy); - -	if (mv_u3d_phy->clk) -		clk_enable(mv_u3d_phy->clk); - -	base = mv_u3d_phy->base; - -	val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL); -	val &= ~(USB3_POWER_PLL_CONTROL_PU_MASK); -	val |= 0xF << USB3_POWER_PLL_CONTROL_PU_SHIFT; -	mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val); -	udelay(100); - -	mv_u3d_phy_write(base, USB3_RESET_CONTROL, -			USB3_RESET_CONTROL_RESET_PIPE); -	udelay(100); - -	mv_u3d_phy_write(base, USB3_RESET_CONTROL, -			USB3_RESET_CONTROL_RESET_PIPE -			| USB3_RESET_CONTROL_RESET_PHY); -	udelay(100); - -	val = mv_u3d_phy_read(base, USB3_POWER_PLL_CONTROL); -	val &= ~(USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK -		| USB3_POWER_PLL_CONTROL_PHY_MODE_MASK); -	val |=  (USB3_PLL_25MHZ << USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT) -		| (0x5 << USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT); -	mv_u3d_phy_write(base, USB3_POWER_PLL_CONTROL, val); -	udelay(100); - -	mv_u3d_phy_clear(base, USB3_KVCO_CALI_CONTROL, -		USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK); -	udelay(100); - -	val = mv_u3d_phy_read(base, USB3_SQUELCH_FFE); -	val &= ~(USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK -		| USB3_SQUELCH_FFE_FFE_RES_SEL_MASK -		| USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK); -	val |= ((0xD << USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT) -		| (0x7 << USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT) -		| (0x8 << USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT)); -	mv_u3d_phy_write(base, USB3_SQUELCH_FFE, val); -	udelay(100); - -	val = mv_u3d_phy_read(base, USB3_GEN1_SET0); -	val &= ~USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK; -	val |= 1 << USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT; -	mv_u3d_phy_write(base, USB3_GEN1_SET0, val); -	udelay(100); - -	val = mv_u3d_phy_read(base, USB3_GEN2_SET0); -	val &= ~(USB3_GEN2_SET0_G2_TX_AMP_MASK -		| USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK -		| USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK); -	val |= ((0x14 << USB3_GEN2_SET0_G2_TX_AMP_SHIFT) -		| (1 << USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT) -		| (0xA << USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT) -		| (1 << USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT)); -	mv_u3d_phy_write(base, USB3_GEN2_SET0, val); -	udelay(100); - -	mv_u3d_phy_read(base, USB3_TX_EMPPH); -	val &= ~(USB3_TX_EMPPH_AMP_MASK -		| USB3_TX_EMPPH_EN_MASK -		| USB3_TX_EMPPH_AMP_FORCE_MASK -		| USB3_TX_EMPPH_PAR1_MASK -		| USB3_TX_EMPPH_PAR2_MASK); -	val |= ((0xB << USB3_TX_EMPPH_AMP_SHIFT) -		| (1 << USB3_TX_EMPPH_EN_SHIFT) -		| (1 << USB3_TX_EMPPH_AMP_FORCE_SHIFT) -		| (0x1C << USB3_TX_EMPPH_PAR1_SHIFT) -		| (1 << USB3_TX_EMPPH_PAR2_SHIFT)); - -	mv_u3d_phy_write(base, USB3_TX_EMPPH, val); -	udelay(100); - -	val = mv_u3d_phy_read(base, USB3_GEN2_SET1); -	val &= ~(USB3_GEN2_SET1_G2_RX_SELMUPI_MASK -		| USB3_GEN2_SET1_G2_RX_SELMUPF_MASK -		| USB3_GEN2_SET1_G2_RX_SELMUFI_MASK -		| USB3_GEN2_SET1_G2_RX_SELMUFF_MASK); -	val |= ((1 << USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT) -		| (1 << USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT) -		| (1 << USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT) -		| (1 << USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT)); -	mv_u3d_phy_write(base, USB3_GEN2_SET1, val); -	udelay(100); - -	val = mv_u3d_phy_read(base, USB3_DIGITAL_LOOPBACK_EN); -	val &= ~USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK; -	val |= 1 << USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT; -	mv_u3d_phy_write(base, USB3_DIGITAL_LOOPBACK_EN, val); -	udelay(100); - -	val = mv_u3d_phy_read(base, USB3_IMPEDANCE_TX_SSC); -	val &= ~USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK; -	val |= 0xC << USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT; -	mv_u3d_phy_write(base, USB3_IMPEDANCE_TX_SSC, val); -	udelay(100); - -	val = mv_u3d_phy_read(base, USB3_IMPEDANCE_CALI_CTRL); -	val &= ~USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK; -	val |= 0x4 << USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT; -	mv_u3d_phy_write(base, USB3_IMPEDANCE_CALI_CTRL, val); -	udelay(100); - -	val = mv_u3d_phy_read(base, USB3_PHY_ISOLATION_MODE); -	val &= ~(USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK -		| USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK -		| USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK); -	val |= ((1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT) -		| (1 << USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT)); -	mv_u3d_phy_write(base, USB3_PHY_ISOLATION_MODE, val); -	udelay(100); - -	val = mv_u3d_phy_read(base, USB3_TXDETRX); -	val &= ~(USB3_TXDETRX_VTHSEL_MASK); -	val |= 0x1 << USB3_TXDETRX_VTHSEL_SHIFT; -	mv_u3d_phy_write(base, USB3_TXDETRX, val); -	udelay(100); - -	dev_dbg(mv_u3d_phy->dev, "start calibration\n"); - -calstart: -	/* Perform Manual Calibration */ -	mv_u3d_phy_set(base, USB3_KVCO_CALI_CONTROL, -		1 << USB3_KVCO_CALI_CONTROL_CAL_START_SHIFT); - -	mdelay(1); - -	count = 0; -	while (1) { -		val = mv_u3d_phy_read(base, USB3_KVCO_CALI_CONTROL); -		if (val & (1 << USB3_KVCO_CALI_CONTROL_CAL_DONE_SHIFT)) -			break; -		else if (count > 50) { -			dev_dbg(mv_u3d_phy->dev, "calibration failure, retry...\n"); -			goto calstart; -		} -		count++; -		mdelay(1); -	} - -	/* active PIPE interface */ -	mv_u3d_phy_write(base, USB3_PIPE_SM_CTRL, -		1 << USB3_PIPE_SM_CTRL_PHY_INIT_DONE); - -	return 0; -} - -static int mv_u3d_phy_probe(struct platform_device *pdev) -{ -	struct mv_u3d_phy *mv_u3d_phy; -	struct mv_usb_platform_data *pdata; -	struct device *dev = &pdev->dev; -	struct resource *res; -	void __iomem	*phy_base; -	int	ret; - -	pdata = dev_get_platdata(&pdev->dev); -	if (!pdata) { -		dev_err(&pdev->dev, "%s: no platform data defined\n", __func__); -		return -EINVAL; -	} - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	phy_base = devm_ioremap_resource(dev, res); -	if (IS_ERR(phy_base)) -		return PTR_ERR(phy_base); - -	mv_u3d_phy = devm_kzalloc(dev, sizeof(*mv_u3d_phy), GFP_KERNEL); -	if (!mv_u3d_phy) -		return -ENOMEM; - -	mv_u3d_phy->dev			= &pdev->dev; -	mv_u3d_phy->plat		= pdata; -	mv_u3d_phy->base		= phy_base; -	mv_u3d_phy->phy.dev		= mv_u3d_phy->dev; -	mv_u3d_phy->phy.label		= "mv-u3d-phy"; -	mv_u3d_phy->phy.init		= mv_u3d_phy_init; -	mv_u3d_phy->phy.shutdown	= mv_u3d_phy_shutdown; - -	ret = usb_add_phy(&mv_u3d_phy->phy, USB_PHY_TYPE_USB3); -	if (ret) -		goto err; - -	if (!mv_u3d_phy->clk) -		mv_u3d_phy->clk = clk_get(mv_u3d_phy->dev, "u3dphy"); - -	platform_set_drvdata(pdev, mv_u3d_phy); - -	dev_info(&pdev->dev, "Initialized Marvell USB 3.0 PHY\n"); -err: -	return ret; -} - -static int mv_u3d_phy_remove(struct platform_device *pdev) -{ -	struct mv_u3d_phy *mv_u3d_phy = platform_get_drvdata(pdev); - -	usb_remove_phy(&mv_u3d_phy->phy); - -	if (mv_u3d_phy->clk) { -		clk_put(mv_u3d_phy->clk); -		mv_u3d_phy->clk = NULL; -	} - -	return 0; -} - -static struct platform_driver mv_u3d_phy_driver = { -	.probe		= mv_u3d_phy_probe, -	.remove		= mv_u3d_phy_remove, -	.driver		= { -		.name	= "mv-u3d-phy", -		.owner	= THIS_MODULE, -	}, -}; - -module_platform_driver(mv_u3d_phy_driver); -MODULE_DESCRIPTION("Marvell USB 3.0 PHY controller"); -MODULE_AUTHOR("Yu Xu <yuxu@marvell.com>"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:mv-u3d-phy"); diff --git a/drivers/usb/phy/phy-mv-u3d-usb.h b/drivers/usb/phy/phy-mv-u3d-usb.h deleted file mode 100644 index 2a658cb9a52..00000000000 --- a/drivers/usb/phy/phy-mv-u3d-usb.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2011 Marvell International Ltd. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - */ - -#ifndef __MV_U3D_PHY_H -#define __MV_U3D_PHY_H - -#define USB3_POWER_PLL_CONTROL		0x1 -#define USB3_KVCO_CALI_CONTROL		0x2 -#define USB3_IMPEDANCE_CALI_CTRL	0x3 -#define USB3_IMPEDANCE_TX_SSC		0x4 -#define USB3_SQUELCH_FFE		0x6 -#define USB3_GEN1_SET0			0xD -#define USB3_GEN2_SET0			0xF -#define USB3_GEN2_SET1			0x10 -#define USB3_DIGITAL_LOOPBACK_EN	0x23 -#define USB3_PHY_ISOLATION_MODE		0x26 -#define USB3_TXDETRX			0x48 -#define USB3_TX_EMPPH			0x5E -#define USB3_RESET_CONTROL		0x90 -#define USB3_PIPE_SM_CTRL		0x91 - -#define USB3_RESET_CONTROL_RESET_PIPE			0x1 -#define USB3_RESET_CONTROL_RESET_PHY			0x2 - -#define USB3_POWER_PLL_CONTROL_REF_FREF_SEL_MASK	(0x1F << 0) -#define USB3_POWER_PLL_CONTROL_REF_FREF_SEL_SHIFT	0 -#define USB3_PLL_25MHZ					0x2 -#define USB3_PLL_26MHZ					0x5 -#define USB3_POWER_PLL_CONTROL_PHY_MODE_MASK		(0x7 << 5) -#define USB3_POWER_PLL_CONTROL_PHY_MODE_SHIFT		5 -#define USB3_POWER_PLL_CONTROL_PU_MASK			(0xF << 12) -#define USB3_POWER_PLL_CONTROL_PU_SHIFT			12 -#define USB3_POWER_PLL_CONTROL_PU			(0xF << 12) - -#define USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_MASK	(0x1 << 12) -#define USB3_KVCO_CALI_CONTROL_USE_MAX_PLL_RATE_SHIFT	12 -#define USB3_KVCO_CALI_CONTROL_CAL_DONE_SHIFT		14 -#define USB3_KVCO_CALI_CONTROL_CAL_START_SHIFT		15 - -#define USB3_SQUELCH_FFE_FFE_CAP_SEL_MASK		0xF -#define USB3_SQUELCH_FFE_FFE_CAP_SEL_SHIFT		0 -#define USB3_SQUELCH_FFE_FFE_RES_SEL_MASK		(0x7 << 4) -#define USB3_SQUELCH_FFE_FFE_RES_SEL_SHIFT		4 -#define USB3_SQUELCH_FFE_SQ_THRESH_IN_MASK		(0x1F << 8) -#define USB3_SQUELCH_FFE_SQ_THRESH_IN_SHIFT		8 - -#define USB3_GEN1_SET0_G1_TX_SLEW_CTRL_EN_MASK		(0x1 << 15) -#define USB3_GEN1_SET0_G1_TX_EMPH_EN_SHIFT		11 - -#define USB3_GEN2_SET0_G2_TX_AMP_MASK			(0x1F << 1) -#define USB3_GEN2_SET0_G2_TX_AMP_SHIFT			1 -#define USB3_GEN2_SET0_G2_TX_AMP_ADJ_SHIFT		6 -#define USB3_GEN2_SET0_G2_TX_EMPH_AMP_MASK		(0xF << 7) -#define USB3_GEN2_SET0_G2_TX_EMPH_AMP_SHIFT		7 -#define USB3_GEN2_SET0_G2_TX_EMPH_EN_MASK		(0x1 << 11) -#define USB3_GEN2_SET0_G2_TX_EMPH_EN_SHIFT		11 -#define USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_MASK		(0x1 << 15) -#define USB3_GEN2_SET0_G2_TX_SLEW_CTRL_EN_SHIFT		15 - -#define USB3_GEN2_SET1_G2_RX_SELMUPI_MASK		(0x7 << 0) -#define USB3_GEN2_SET1_G2_RX_SELMUPI_SHIFT		0 -#define USB3_GEN2_SET1_G2_RX_SELMUPF_MASK		(0x7 << 3) -#define USB3_GEN2_SET1_G2_RX_SELMUPF_SHIFT		3 -#define USB3_GEN2_SET1_G2_RX_SELMUFI_MASK		(0x3 << 6) -#define USB3_GEN2_SET1_G2_RX_SELMUFI_SHIFT		6 -#define USB3_GEN2_SET1_G2_RX_SELMUFF_MASK		(0x3 << 8) -#define USB3_GEN2_SET1_G2_RX_SELMUFF_SHIFT		8 - -#define USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_MASK		(0x3 << 10) -#define USB3_DIGITAL_LOOPBACK_EN_SEL_BITS_SHIFT		10 - -#define USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_MASK	(0x7 << 12) -#define USB3_IMPEDANCE_CALI_CTRL_IMP_CAL_THR_SHIFT	12 - -#define USB3_IMPEDANCE_TX_SSC_SSC_AMP_MASK		(0x3F << 0) -#define USB3_IMPEDANCE_TX_SSC_SSC_AMP_SHIFT		0 - -#define USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_MASK		0xF -#define USB3_PHY_ISOLATION_MODE_PHY_GEN_RX_SHIFT	0 -#define USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_MASK		(0xF << 4) -#define USB3_PHY_ISOLATION_MODE_PHY_GEN_TX_SHIFT	4 -#define USB3_PHY_ISOLATION_MODE_TX_DRV_IDLE_MASK	(0x1 << 8) - -#define USB3_TXDETRX_VTHSEL_MASK			(0x3 << 4) -#define USB3_TXDETRX_VTHSEL_SHIFT			4 - -#define USB3_TX_EMPPH_AMP_MASK				(0xF << 0) -#define USB3_TX_EMPPH_AMP_SHIFT				0 -#define USB3_TX_EMPPH_EN_MASK				(0x1 << 6) -#define USB3_TX_EMPPH_EN_SHIFT				6 -#define USB3_TX_EMPPH_AMP_FORCE_MASK			(0x1 << 7) -#define USB3_TX_EMPPH_AMP_FORCE_SHIFT			7 -#define USB3_TX_EMPPH_PAR1_MASK				(0x1F << 8) -#define USB3_TX_EMPPH_PAR1_SHIFT			8 -#define USB3_TX_EMPPH_PAR2_MASK				(0x1 << 13) -#define USB3_TX_EMPPH_PAR2_SHIFT			13 - -#define USB3_PIPE_SM_CTRL_PHY_INIT_DONE			15 - -#endif /* __MV_U3D_PHY_H */ diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index 98f6ac6a78e..7d80c54f0ac 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -11,7 +11,6 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/io.h>  #include <linux/uaccess.h>  #include <linux/device.h> @@ -213,10 +212,12 @@ static void mv_otg_start_host(struct mv_otg *mvotg, int on)  	hcd = bus_to_hcd(otg->host); -	if (on) +	if (on) {  		usb_add_hcd(hcd, hcd->irq, IRQF_SHARED); -	else +		device_wakeup_enable(hcd->self.controller); +	} else {  		usb_remove_hcd(hcd); +	}  #endif /* CONFIG_USB */  } diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index fdd33b44dbd..c42bdf0c4a1 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -1,5 +1,5 @@  /* - * Copyright 2012 Freescale Semiconductor, Inc. + * Copyright 2012-2013 Freescale Semiconductor, Inc.   * Copyright (C) 2012 Marek Vasut <marex@denx.de>   * on behalf of DENX Software Engineering GmbH   * @@ -20,6 +20,9 @@  #include <linux/delay.h>  #include <linux/err.h>  #include <linux/io.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h>  #define DRIVER_NAME "mxs_phy" @@ -28,18 +31,134 @@  #define HW_USBPHY_CTRL_SET			0x34  #define HW_USBPHY_CTRL_CLR			0x38 +#define HW_USBPHY_DEBUG_SET			0x54 +#define HW_USBPHY_DEBUG_CLR			0x58 + +#define HW_USBPHY_IP				0x90 +#define HW_USBPHY_IP_SET			0x94 +#define HW_USBPHY_IP_CLR			0x98 +  #define BM_USBPHY_CTRL_SFTRST			BIT(31)  #define BM_USBPHY_CTRL_CLKGATE			BIT(30) +#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS	BIT(26) +#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE	BIT(25) +#define BM_USBPHY_CTRL_ENVBUSCHG_WKUP		BIT(23) +#define BM_USBPHY_CTRL_ENIDCHG_WKUP		BIT(22) +#define BM_USBPHY_CTRL_ENDPDMCHG_WKUP		BIT(21) +#define BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD	BIT(20) +#define BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE	BIT(19) +#define BM_USBPHY_CTRL_ENAUTO_PWRON_PLL		BIT(18)  #define BM_USBPHY_CTRL_ENUTMILEVEL3		BIT(15)  #define BM_USBPHY_CTRL_ENUTMILEVEL2		BIT(14)  #define BM_USBPHY_CTRL_ENHOSTDISCONDETECT	BIT(1) +#define BM_USBPHY_IP_FIX                       (BIT(17) | BIT(18)) + +#define BM_USBPHY_DEBUG_CLKGATE			BIT(30) + +/* Anatop Registers */ +#define ANADIG_ANA_MISC0			0x150 +#define ANADIG_ANA_MISC0_SET			0x154 +#define ANADIG_ANA_MISC0_CLR			0x158 + +#define ANADIG_USB1_VBUS_DET_STAT		0x1c0 +#define ANADIG_USB2_VBUS_DET_STAT		0x220 + +#define ANADIG_USB1_LOOPBACK_SET		0x1e4 +#define ANADIG_USB1_LOOPBACK_CLR		0x1e8 +#define ANADIG_USB2_LOOPBACK_SET		0x244 +#define ANADIG_USB2_LOOPBACK_CLR		0x248 + +#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG	BIT(12) +#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11) + +#define BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID	BIT(3) +#define BM_ANADIG_USB2_VBUS_DET_STAT_VBUS_VALID	BIT(3) + +#define BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1	BIT(2) +#define BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN	BIT(5) +#define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1	BIT(2) +#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN	BIT(5) + +#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy) + +/* Do disconnection between PHY and controller without vbus */ +#define MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS	BIT(0) + +/* + * The PHY will be in messy if there is a wakeup after putting + * bus to suspend (set portsc.suspendM) but before setting PHY to low + * power mode (set portsc.phcd). + */ +#define MXS_PHY_ABNORMAL_IN_SUSPEND		BIT(1) + +/* + * The SOF sends too fast after resuming, it will cause disconnection + * between host and high speed device. + */ +#define MXS_PHY_SENDING_SOF_TOO_FAST		BIT(2) + +/* + * IC has bug fixes logic, they include + * MXS_PHY_ABNORMAL_IN_SUSPEND and MXS_PHY_SENDING_SOF_TOO_FAST + * which are described at above flags, the RTL will handle it + * according to different versions. + */ +#define MXS_PHY_NEED_IP_FIX			BIT(3) + +struct mxs_phy_data { +	unsigned int flags; +}; + +static const struct mxs_phy_data imx23_phy_data = { +	.flags = MXS_PHY_ABNORMAL_IN_SUSPEND | MXS_PHY_SENDING_SOF_TOO_FAST, +}; + +static const struct mxs_phy_data imx6q_phy_data = { +	.flags = MXS_PHY_SENDING_SOF_TOO_FAST | +		MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS | +		MXS_PHY_NEED_IP_FIX, +}; + +static const struct mxs_phy_data imx6sl_phy_data = { +	.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS | +		MXS_PHY_NEED_IP_FIX, +}; + +static const struct of_device_id mxs_phy_dt_ids[] = { +	{ .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, }, +	{ .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, }, +	{ .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, }, +	{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids); +  struct mxs_phy {  	struct usb_phy phy;  	struct clk *clk; +	const struct mxs_phy_data *data; +	struct regmap *regmap_anatop; +	int port_id;  }; -#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy) +static inline bool is_imx6q_phy(struct mxs_phy *mxs_phy) +{ +	return mxs_phy->data == &imx6q_phy_data; +} + +static inline bool is_imx6sl_phy(struct mxs_phy *mxs_phy) +{ +	return mxs_phy->data == &imx6sl_phy_data; +} + +/* + * PHY needs some 32K cycles to switch from 32K clock to + * bus (such as AHB/AXI, etc) clock. + */ +static void mxs_phy_clock_switch_delay(void) +{ +	usleep_range(300, 400); +}  static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)  { @@ -53,19 +172,109 @@ static int mxs_phy_hw_init(struct mxs_phy *mxs_phy)  	/* Power up the PHY */  	writel(0, base + HW_USBPHY_PWD); -	/* enable FS/LS device */ -	writel(BM_USBPHY_CTRL_ENUTMILEVEL2 | -	       BM_USBPHY_CTRL_ENUTMILEVEL3, +	/* +	 * USB PHY Ctrl Setting +	 * - Auto clock/power on +	 * - Enable full/low speed support +	 */ +	writel(BM_USBPHY_CTRL_ENAUTOSET_USBCLKS | +		BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE | +		BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD | +		BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE | +		BM_USBPHY_CTRL_ENAUTO_PWRON_PLL | +		BM_USBPHY_CTRL_ENUTMILEVEL2 | +		BM_USBPHY_CTRL_ENUTMILEVEL3,  	       base + HW_USBPHY_CTRL_SET); +	if (mxs_phy->data->flags & MXS_PHY_NEED_IP_FIX) +		writel(BM_USBPHY_IP_FIX, base + HW_USBPHY_IP_SET); +  	return 0;  } +/* Return true if the vbus is there */ +static bool mxs_phy_get_vbus_status(struct mxs_phy *mxs_phy) +{ +	unsigned int vbus_value; + +	if (mxs_phy->port_id == 0) +		regmap_read(mxs_phy->regmap_anatop, +			ANADIG_USB1_VBUS_DET_STAT, +			&vbus_value); +	else if (mxs_phy->port_id == 1) +		regmap_read(mxs_phy->regmap_anatop, +			ANADIG_USB2_VBUS_DET_STAT, +			&vbus_value); + +	if (vbus_value & BM_ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID) +		return true; +	else +		return false; +} + +static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect) +{ +	void __iomem *base = mxs_phy->phy.io_priv; +	u32 reg; + +	if (disconnect) +		writel_relaxed(BM_USBPHY_DEBUG_CLKGATE, +			base + HW_USBPHY_DEBUG_CLR); + +	if (mxs_phy->port_id == 0) { +		reg = disconnect ? ANADIG_USB1_LOOPBACK_SET +			: ANADIG_USB1_LOOPBACK_CLR; +		regmap_write(mxs_phy->regmap_anatop, reg, +			BM_ANADIG_USB1_LOOPBACK_UTMI_DIG_TST1 | +			BM_ANADIG_USB1_LOOPBACK_TSTI_TX_EN); +	} else if (mxs_phy->port_id == 1) { +		reg = disconnect ? ANADIG_USB2_LOOPBACK_SET +			: ANADIG_USB2_LOOPBACK_CLR; +		regmap_write(mxs_phy->regmap_anatop, reg, +			BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 | +			BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN); +	} + +	if (!disconnect) +		writel_relaxed(BM_USBPHY_DEBUG_CLKGATE, +			base + HW_USBPHY_DEBUG_SET); + +	/* Delay some time, and let Linestate be SE0 for controller */ +	if (disconnect) +		usleep_range(500, 1000); +} + +static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on) +{ +	bool vbus_is_on = false; + +	/* If the SoCs don't need to disconnect line without vbus, quit */ +	if (!(mxs_phy->data->flags & MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS)) +		return; + +	/* If the SoCs don't have anatop, quit */ +	if (!mxs_phy->regmap_anatop) +		return; + +	vbus_is_on = mxs_phy_get_vbus_status(mxs_phy); + +	if (on && !vbus_is_on) +		__mxs_phy_disconnect_line(mxs_phy, true); +	else +		__mxs_phy_disconnect_line(mxs_phy, false); + +} +  static int mxs_phy_init(struct usb_phy *phy)  { +	int ret;  	struct mxs_phy *mxs_phy = to_mxs_phy(phy); -	clk_prepare_enable(mxs_phy->clk); +	mxs_phy_clock_switch_delay(); +	ret = clk_prepare_enable(mxs_phy->clk); +	if (ret) +		return ret; +  	return mxs_phy_hw_init(mxs_phy);  } @@ -81,6 +290,7 @@ static void mxs_phy_shutdown(struct usb_phy *phy)  static int mxs_phy_suspend(struct usb_phy *x, int suspend)  { +	int ret;  	struct mxs_phy *mxs_phy = to_mxs_phy(x);  	if (suspend) { @@ -89,7 +299,10 @@ static int mxs_phy_suspend(struct usb_phy *x, int suspend)  		       x->io_priv + HW_USBPHY_CTRL_SET);  		clk_disable_unprepare(mxs_phy->clk);  	} else { -		clk_prepare_enable(mxs_phy->clk); +		mxs_phy_clock_switch_delay(); +		ret = clk_prepare_enable(mxs_phy->clk); +		if (ret) +			return ret;  		writel(BM_USBPHY_CTRL_CLKGATE,  		       x->io_priv + HW_USBPHY_CTRL_CLR);  		writel(0, x->io_priv + HW_USBPHY_PWD); @@ -98,11 +311,28 @@ static int mxs_phy_suspend(struct usb_phy *x, int suspend)  	return 0;  } +static int mxs_phy_set_wakeup(struct usb_phy *x, bool enabled) +{ +	struct mxs_phy *mxs_phy = to_mxs_phy(x); +	u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP | +			BM_USBPHY_CTRL_ENDPDMCHG_WKUP | +				BM_USBPHY_CTRL_ENIDCHG_WKUP; +	if (enabled) { +		mxs_phy_disconnect_line(mxs_phy, true); +		writel_relaxed(value, x->io_priv + HW_USBPHY_CTRL_SET); +	} else { +		writel_relaxed(value, x->io_priv + HW_USBPHY_CTRL_CLR); +		mxs_phy_disconnect_line(mxs_phy, false); +	} + +	return 0; +} +  static int mxs_phy_on_connect(struct usb_phy *phy,  		enum usb_device_speed speed)  { -	dev_dbg(phy->dev, "%s speed device has connected\n", -		(speed == USB_SPEED_HIGH) ? "high" : "non-high"); +	dev_dbg(phy->dev, "%s device has connected\n", +		(speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");  	if (speed == USB_SPEED_HIGH)  		writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, @@ -114,8 +344,8 @@ static int mxs_phy_on_connect(struct usb_phy *phy,  static int mxs_phy_on_disconnect(struct usb_phy *phy,  		enum usb_device_speed speed)  { -	dev_dbg(phy->dev, "%s speed device has disconnected\n", -		(speed == USB_SPEED_HIGH) ? "high" : "non-high"); +	dev_dbg(phy->dev, "%s device has disconnected\n", +		(speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");  	if (speed == USB_SPEED_HIGH)  		writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT, @@ -131,6 +361,9 @@ static int mxs_phy_probe(struct platform_device *pdev)  	struct clk *clk;  	struct mxs_phy *mxs_phy;  	int ret; +	const struct of_device_id *of_id = +			of_match_device(mxs_phy_dt_ids, &pdev->dev); +	struct device_node *np = pdev->dev.of_node;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	base = devm_ioremap_resource(&pdev->dev, res); @@ -150,6 +383,22 @@ static int mxs_phy_probe(struct platform_device *pdev)  		return -ENOMEM;  	} +	/* Some SoCs don't have anatop registers */ +	if (of_get_property(np, "fsl,anatop", NULL)) { +		mxs_phy->regmap_anatop = syscon_regmap_lookup_by_phandle +			(np, "fsl,anatop"); +		if (IS_ERR(mxs_phy->regmap_anatop)) { +			dev_dbg(&pdev->dev, +				"failed to find regmap for anatop\n"); +			return PTR_ERR(mxs_phy->regmap_anatop); +		} +	} + +	ret = of_alias_get_id(np, "usbphy"); +	if (ret < 0) +		dev_dbg(&pdev->dev, "failed to get alias id, errno %d\n", ret); +	mxs_phy->port_id = ret; +  	mxs_phy->phy.io_priv		= base;  	mxs_phy->phy.dev		= &pdev->dev;  	mxs_phy->phy.label		= DRIVER_NAME; @@ -159,12 +408,14 @@ static int mxs_phy_probe(struct platform_device *pdev)  	mxs_phy->phy.notify_connect	= mxs_phy_on_connect;  	mxs_phy->phy.notify_disconnect	= mxs_phy_on_disconnect;  	mxs_phy->phy.type		= USB_PHY_TYPE_USB2; - -	ATOMIC_INIT_NOTIFIER_HEAD(&mxs_phy->phy.notifier); +	mxs_phy->phy.set_wakeup		= mxs_phy_set_wakeup;  	mxs_phy->clk = clk; +	mxs_phy->data = of_id->data; + +	platform_set_drvdata(pdev, mxs_phy); -	platform_set_drvdata(pdev, &mxs_phy->phy); +	device_set_wakeup_capable(&pdev->dev, true);  	ret = usb_add_phy_dev(&mxs_phy->phy);  	if (ret) @@ -182,11 +433,46 @@ static int mxs_phy_remove(struct platform_device *pdev)  	return 0;  } -static const struct of_device_id mxs_phy_dt_ids[] = { -	{ .compatible = "fsl,imx23-usbphy", }, -	{ /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids); +#ifdef CONFIG_PM_SLEEP +static void mxs_phy_enable_ldo_in_suspend(struct mxs_phy *mxs_phy, bool on) +{ +	unsigned int reg = on ? ANADIG_ANA_MISC0_SET : ANADIG_ANA_MISC0_CLR; + +	/* If the SoCs don't have anatop, quit */ +	if (!mxs_phy->regmap_anatop) +		return; + +	if (is_imx6q_phy(mxs_phy)) +		regmap_write(mxs_phy->regmap_anatop, reg, +			BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG); +	else if (is_imx6sl_phy(mxs_phy)) +		regmap_write(mxs_phy->regmap_anatop, +			reg, BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL); +} + +static int mxs_phy_system_suspend(struct device *dev) +{ +	struct mxs_phy *mxs_phy = dev_get_drvdata(dev); + +	if (device_may_wakeup(dev)) +		mxs_phy_enable_ldo_in_suspend(mxs_phy, true); + +	return 0; +} + +static int mxs_phy_system_resume(struct device *dev) +{ +	struct mxs_phy *mxs_phy = dev_get_drvdata(dev); + +	if (device_may_wakeup(dev)) +		mxs_phy_enable_ldo_in_suspend(mxs_phy, false); + +	return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(mxs_phy_pm, mxs_phy_system_suspend, +		mxs_phy_system_resume);  static struct platform_driver mxs_phy_driver = {  	.probe = mxs_phy_probe, @@ -195,6 +481,7 @@ static struct platform_driver mxs_phy_driver = {  		.name = DRIVER_NAME,  		.owner	= THIS_MODULE,  		.of_match_table = mxs_phy_dt_ids, +		.pm = &mxs_phy_pm,  	 },  }; diff --git a/drivers/usb/phy/phy-omap-control.c b/drivers/usb/phy/phy-omap-control.c deleted file mode 100644 index a4dda8e1256..00000000000 --- a/drivers/usb/phy/phy-omap-control.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * omap-control-usb.c - The USB part of control module. - * - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Author: Kishon Vijay Abraham I <kishon@ti.com> - * - * 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/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/of.h> -#include <linux/err.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/usb/omap_control_usb.h> - -static struct omap_control_usb *control_usb; - -/** - * omap_get_control_dev - returns the device pointer for this control device - * - * This API should be called to get the device pointer for this control - * module device. This device pointer should be used for called other - * exported API's in this driver. - * - * To be used by PHY driver and glue driver. - */ -struct device *omap_get_control_dev(void) -{ -	if (!control_usb) -		return ERR_PTR(-ENODEV); - -	return control_usb->dev; -} -EXPORT_SYMBOL_GPL(omap_get_control_dev); - -/** - * omap_control_usb3_phy_power - power on/off the serializer using control - *	module - * @dev: the control module device - * @on: 0 to off and 1 to on based on powering on or off the PHY - * - * usb3 PHY driver should call this API to power on or off the PHY. - */ -void omap_control_usb3_phy_power(struct device *dev, bool on) -{ -	u32 val; -	unsigned long rate; -	struct omap_control_usb	*control_usb = dev_get_drvdata(dev); - -	if (control_usb->type != OMAP_CTRL_DEV_TYPE2) -		return; - -	rate = clk_get_rate(control_usb->sys_clk); -	rate = rate/1000000; - -	val = readl(control_usb->phy_power); - -	if (on) { -		val &= ~(OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK | -			OMAP_CTRL_USB_PWRCTL_CLK_FREQ_MASK); -		val |= OMAP_CTRL_USB3_PHY_TX_RX_POWERON << -			OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT; -		val |= rate << OMAP_CTRL_USB_PWRCTL_CLK_FREQ_SHIFT; -	} else { -		val &= ~OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK; -		val |= OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF << -			OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT; -	} - -	writel(val, control_usb->phy_power); -} -EXPORT_SYMBOL_GPL(omap_control_usb3_phy_power); - -/** - * omap_control_usb_phy_power - power on/off the phy using control module reg - * @dev: the control module device - * @on: 0 or 1, based on powering on or off the PHY - */ -void omap_control_usb_phy_power(struct device *dev, int on) -{ -	u32 val; -	struct omap_control_usb	*control_usb = dev_get_drvdata(dev); - -	val = readl(control_usb->dev_conf); - -	if (on) -		val &= ~OMAP_CTRL_DEV_PHY_PD; -	else -		val |= OMAP_CTRL_DEV_PHY_PD; - -	writel(val, control_usb->dev_conf); -} -EXPORT_SYMBOL_GPL(omap_control_usb_phy_power); - -/** - * omap_control_usb_host_mode - set AVALID, VBUSVALID and ID pin in grounded - * @ctrl_usb: struct omap_control_usb * - * - * Writes to the mailbox register to notify the usb core that a usb - * device has been connected. - */ -static void omap_control_usb_host_mode(struct omap_control_usb *ctrl_usb) -{ -	u32 val; - -	val = readl(ctrl_usb->otghs_control); -	val &= ~(OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND); -	val |= OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID; -	writel(val, ctrl_usb->otghs_control); -} - -/** - * omap_control_usb_device_mode - set AVALID, VBUSVALID and ID pin in high - * impedance - * @ctrl_usb: struct omap_control_usb * - * - * Writes to the mailbox register to notify the usb core that it has been - * connected to a usb host. - */ -static void omap_control_usb_device_mode(struct omap_control_usb *ctrl_usb) -{ -	u32 val; - -	val = readl(ctrl_usb->otghs_control); -	val &= ~OMAP_CTRL_DEV_SESSEND; -	val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_AVALID | -		OMAP_CTRL_DEV_VBUSVALID; -	writel(val, ctrl_usb->otghs_control); -} - -/** - * omap_control_usb_set_sessionend - Enable SESSIONEND and IDIG to high - * impedance - * @ctrl_usb: struct omap_control_usb * - * - * Writes to the mailbox register to notify the usb core it's now in - * disconnected state. - */ -static void omap_control_usb_set_sessionend(struct omap_control_usb *ctrl_usb) -{ -	u32 val; - -	val = readl(ctrl_usb->otghs_control); -	val &= ~(OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID); -	val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND; -	writel(val, ctrl_usb->otghs_control); -} - -/** - * omap_control_usb_set_mode - Calls to functions to set USB in one of host mode - * or device mode or to denote disconnected state - * @dev: the control module device - * @mode: The mode to which usb should be configured - * - * This is an API to write to the mailbox register to notify the usb core that - * a usb device has been connected. - */ -void omap_control_usb_set_mode(struct device *dev, -	enum omap_control_usb_mode mode) -{ -	struct omap_control_usb	*ctrl_usb; - -	if (IS_ERR(dev) || control_usb->type != OMAP_CTRL_DEV_TYPE1) -		return; - -	ctrl_usb = dev_get_drvdata(dev); - -	switch (mode) { -	case USB_MODE_HOST: -		omap_control_usb_host_mode(ctrl_usb); -		break; -	case USB_MODE_DEVICE: -		omap_control_usb_device_mode(ctrl_usb); -		break; -	case USB_MODE_DISCONNECT: -		omap_control_usb_set_sessionend(ctrl_usb); -		break; -	default: -		dev_vdbg(dev, "invalid omap control usb mode\n"); -	} -} -EXPORT_SYMBOL_GPL(omap_control_usb_set_mode); - -static int omap_control_usb_probe(struct platform_device *pdev) -{ -	struct resource	*res; -	struct device_node *np = pdev->dev.of_node; -	struct omap_control_usb_platform_data *pdata = -			dev_get_platdata(&pdev->dev); - -	control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb), -		GFP_KERNEL); -	if (!control_usb) { -		dev_err(&pdev->dev, "unable to alloc memory for control usb\n"); -		return -ENOMEM; -	} - -	if (np) { -		of_property_read_u32(np, "ti,type", &control_usb->type); -	} else if (pdata) { -		control_usb->type = pdata->type; -	} else { -		dev_err(&pdev->dev, "no pdata present\n"); -		return -EINVAL; -	} - -	control_usb->dev	= &pdev->dev; - -	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, -		"control_dev_conf"); -	control_usb->dev_conf = devm_ioremap_resource(&pdev->dev, res); -	if (IS_ERR(control_usb->dev_conf)) -		return PTR_ERR(control_usb->dev_conf); - -	if (control_usb->type == OMAP_CTRL_DEV_TYPE1) { -		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, -			"otghs_control"); -		control_usb->otghs_control = devm_ioremap_resource( -			&pdev->dev, res); -		if (IS_ERR(control_usb->otghs_control)) -			return PTR_ERR(control_usb->otghs_control); -	} - -	if (control_usb->type == OMAP_CTRL_DEV_TYPE2) { -		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, -			"phy_power_usb"); -		control_usb->phy_power = devm_ioremap_resource( -			&pdev->dev, res); -		if (IS_ERR(control_usb->phy_power)) -			return PTR_ERR(control_usb->phy_power); - -		control_usb->sys_clk = devm_clk_get(control_usb->dev, -			"sys_clkin"); -		if (IS_ERR(control_usb->sys_clk)) { -			pr_err("%s: unable to get sys_clkin\n", __func__); -			return -EINVAL; -		} -	} - - -	dev_set_drvdata(control_usb->dev, control_usb); - -	return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id omap_control_usb_id_table[] = { -	{ .compatible = "ti,omap-control-usb" }, -	{} -}; -MODULE_DEVICE_TABLE(of, omap_control_usb_id_table); -#endif - -static struct platform_driver omap_control_usb_driver = { -	.probe		= omap_control_usb_probe, -	.driver		= { -		.name	= "omap-control-usb", -		.owner	= THIS_MODULE, -		.of_match_table = of_match_ptr(omap_control_usb_id_table), -	}, -}; - -static int __init omap_control_usb_init(void) -{ -	return platform_driver_register(&omap_control_usb_driver); -} -subsys_initcall(omap_control_usb_init); - -static void __exit omap_control_usb_exit(void) -{ -	platform_driver_unregister(&omap_control_usb_driver); -} -module_exit(omap_control_usb_exit); - -MODULE_ALIAS("platform: omap_control_usb"); -MODULE_AUTHOR("Texas Instruments Inc."); -MODULE_DESCRIPTION("OMAP Control Module USB Driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/phy/phy-omap-otg.c b/drivers/usb/phy/phy-omap-otg.c new file mode 100644 index 00000000000..11598cdb318 --- /dev/null +++ b/drivers/usb/phy/phy-omap-otg.c @@ -0,0 +1,169 @@ +/* + * OMAP OTG controller driver + * + * Based on code from tahvo-usb.c and isp1301_omap.c drivers. + * + * Copyright (C) 2005-2006 Nokia Corporation + * Copyright (C) 2004 Texas Instruments + * Copyright (C) 2004 David Brownell + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * 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/io.h> +#include <linux/err.h> +#include <linux/extcon.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/platform_data/usb-omap1.h> + +struct otg_device { +	void __iomem			*base; +	bool				id; +	bool				vbus; +	struct extcon_specific_cable_nb	vbus_dev; +	struct extcon_specific_cable_nb	id_dev; +	struct notifier_block		vbus_nb; +	struct notifier_block		id_nb; +}; + +#define OMAP_OTG_CTRL		0x0c +#define OMAP_OTG_ASESSVLD	(1 << 20) +#define OMAP_OTG_BSESSEND	(1 << 19) +#define OMAP_OTG_BSESSVLD	(1 << 18) +#define OMAP_OTG_VBUSVLD	(1 << 17) +#define OMAP_OTG_ID		(1 << 16) +#define OMAP_OTG_XCEIV_OUTPUTS \ +	(OMAP_OTG_ASESSVLD | OMAP_OTG_BSESSEND | OMAP_OTG_BSESSVLD | \ +	 OMAP_OTG_VBUSVLD  | OMAP_OTG_ID) + +static void omap_otg_ctrl(struct otg_device *otg_dev, u32 outputs) +{ +	u32 l; + +	l = readl(otg_dev->base + OMAP_OTG_CTRL); +	l &= ~OMAP_OTG_XCEIV_OUTPUTS; +	l |= outputs; +	writel(l, otg_dev->base + OMAP_OTG_CTRL); +} + +static void omap_otg_set_mode(struct otg_device *otg_dev) +{ +	if (!otg_dev->id && otg_dev->vbus) +		/* Set B-session valid. */ +		omap_otg_ctrl(otg_dev, OMAP_OTG_ID | OMAP_OTG_BSESSVLD); +	else if (otg_dev->vbus) +		/* Set A-session valid. */ +		omap_otg_ctrl(otg_dev, OMAP_OTG_ASESSVLD); +	else if (!otg_dev->id) +		/* Set B-session end to indicate no VBUS. */ +		omap_otg_ctrl(otg_dev, OMAP_OTG_ID | OMAP_OTG_BSESSEND); +} + +static int omap_otg_id_notifier(struct notifier_block *nb, +				unsigned long event, void *ptr) +{ +	struct otg_device *otg_dev = container_of(nb, struct otg_device, id_nb); + +	otg_dev->id = event; +	omap_otg_set_mode(otg_dev); + +	return NOTIFY_DONE; +} + +static int omap_otg_vbus_notifier(struct notifier_block *nb, +				  unsigned long event, void *ptr) +{ +	struct otg_device *otg_dev = container_of(nb, struct otg_device, +						  vbus_nb); + +	otg_dev->vbus = event; +	omap_otg_set_mode(otg_dev); + +	return NOTIFY_DONE; +} + +static int omap_otg_probe(struct platform_device *pdev) +{ +	const struct omap_usb_config *config = pdev->dev.platform_data; +	struct otg_device *otg_dev; +	struct extcon_dev *extcon; +	int ret; +	u32 rev; + +	if (!config || !config->extcon) +		return -ENODEV; + +	extcon = extcon_get_extcon_dev(config->extcon); +	if (!extcon) +		return -EPROBE_DEFER; + +	otg_dev = devm_kzalloc(&pdev->dev, sizeof(*otg_dev), GFP_KERNEL); +	if (!otg_dev) +		return -ENOMEM; + +	otg_dev->base = devm_ioremap_resource(&pdev->dev, &pdev->resource[0]); +	if (IS_ERR(otg_dev->base)) +		return PTR_ERR(otg_dev->base); + +	otg_dev->id_nb.notifier_call = omap_otg_id_notifier; +	otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier; + +	ret = extcon_register_interest(&otg_dev->id_dev, config->extcon, +				       "USB-HOST", &otg_dev->id_nb); +	if (ret) +		return ret; + +	ret = extcon_register_interest(&otg_dev->vbus_dev, config->extcon, +				       "USB", &otg_dev->vbus_nb); +	if (ret) { +		extcon_unregister_interest(&otg_dev->id_dev); +		return ret; +	} + +	otg_dev->id = extcon_get_cable_state(extcon, "USB-HOST"); +	otg_dev->vbus = extcon_get_cable_state(extcon, "USB"); +	omap_otg_set_mode(otg_dev); + +	rev = readl(otg_dev->base); + +	dev_info(&pdev->dev, +		 "OMAP USB OTG controller rev %d.%d (%s, id=%d, vbus=%d)\n", +		 (rev >> 4) & 0xf, rev & 0xf, config->extcon, otg_dev->id, +		 otg_dev->vbus); + +	return 0; +} + +static int omap_otg_remove(struct platform_device *pdev) +{ +	struct otg_device *otg_dev = platform_get_drvdata(pdev); + +	extcon_unregister_interest(&otg_dev->id_dev); +	extcon_unregister_interest(&otg_dev->vbus_dev); + +	return 0; +} + +static struct platform_driver omap_otg_driver = { +	.probe		= omap_otg_probe, +	.remove		= omap_otg_remove, +	.driver		= { +		.owner	= THIS_MODULE, +		.name	= "omap_otg", +	}, +}; +module_platform_driver(omap_otg_driver); + +MODULE_DESCRIPTION("OMAP USB OTG controller driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>"); diff --git a/drivers/usb/phy/phy-omap-usb2.c b/drivers/usb/phy/phy-omap-usb2.c deleted file mode 100644 index d266861d24f..00000000000 --- a/drivers/usb/phy/phy-omap-usb2.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * omap-usb2.c - USB PHY, talking to musb controller in OMAP. - * - * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Author: Kishon Vijay Abraham I <kishon@ti.com> - * - * 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/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/of.h> -#include <linux/io.h> -#include <linux/usb/omap_usb.h> -#include <linux/usb/phy_companion.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/pm_runtime.h> -#include <linux/delay.h> -#include <linux/usb/omap_control_usb.h> - -/** - * omap_usb2_set_comparator - links the comparator present in the sytem with - *	this phy - * @comparator - the companion phy(comparator) for this phy - * - * The phy companion driver should call this API passing the phy_companion - * filled with set_vbus and start_srp to be used by usb phy. - * - * For use by phy companion driver - */ -int omap_usb2_set_comparator(struct phy_companion *comparator) -{ -	struct omap_usb	*phy; -	struct usb_phy	*x = usb_get_phy(USB_PHY_TYPE_USB2); - -	if (IS_ERR(x)) -		return -ENODEV; - -	phy = phy_to_omapusb(x); -	phy->comparator = comparator; -	return 0; -} -EXPORT_SYMBOL_GPL(omap_usb2_set_comparator); - -static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled) -{ -	struct omap_usb *phy = phy_to_omapusb(otg->phy); - -	if (!phy->comparator) -		return -ENODEV; - -	return phy->comparator->set_vbus(phy->comparator, enabled); -} - -static int omap_usb_start_srp(struct usb_otg *otg) -{ -	struct omap_usb *phy = phy_to_omapusb(otg->phy); - -	if (!phy->comparator) -		return -ENODEV; - -	return phy->comparator->start_srp(phy->comparator); -} - -static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host) -{ -	struct usb_phy	*phy = otg->phy; - -	otg->host = host; -	if (!host) -		phy->state = OTG_STATE_UNDEFINED; - -	return 0; -} - -static int omap_usb_set_peripheral(struct usb_otg *otg, -		struct usb_gadget *gadget) -{ -	struct usb_phy	*phy = otg->phy; - -	otg->gadget = gadget; -	if (!gadget) -		phy->state = OTG_STATE_UNDEFINED; - -	return 0; -} - -static int omap_usb2_suspend(struct usb_phy *x, int suspend) -{ -	struct omap_usb *phy = phy_to_omapusb(x); -	int ret; - -	if (suspend && !phy->is_suspended) { -		omap_control_usb_phy_power(phy->control_dev, 0); -		pm_runtime_put_sync(phy->dev); -		phy->is_suspended = 1; -	} else if (!suspend && phy->is_suspended) { -		ret = pm_runtime_get_sync(phy->dev); -		if (ret < 0) { -			dev_err(phy->dev, "get_sync failed with err %d\n", ret); -			return ret; -		} -		omap_control_usb_phy_power(phy->control_dev, 1); -		phy->is_suspended = 0; -	} - -	return 0; -} - -static int omap_usb2_probe(struct platform_device *pdev) -{ -	struct omap_usb			*phy; -	struct usb_otg			*otg; - -	phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); -	if (!phy) { -		dev_err(&pdev->dev, "unable to allocate memory for USB2 PHY\n"); -		return -ENOMEM; -	} - -	otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); -	if (!otg) { -		dev_err(&pdev->dev, "unable to allocate memory for USB OTG\n"); -		return -ENOMEM; -	} - -	phy->dev		= &pdev->dev; - -	phy->phy.dev		= phy->dev; -	phy->phy.label		= "omap-usb2"; -	phy->phy.set_suspend	= omap_usb2_suspend; -	phy->phy.otg		= otg; -	phy->phy.type		= USB_PHY_TYPE_USB2; - -	phy->control_dev = omap_get_control_dev(); -	if (IS_ERR(phy->control_dev)) { -		dev_dbg(&pdev->dev, "Failed to get control device\n"); -		return -ENODEV; -	} - -	phy->is_suspended	= 1; -	omap_control_usb_phy_power(phy->control_dev, 0); - -	otg->set_host		= omap_usb_set_host; -	otg->set_peripheral	= omap_usb_set_peripheral; -	otg->set_vbus		= omap_usb_set_vbus; -	otg->start_srp		= omap_usb_start_srp; -	otg->phy		= &phy->phy; - -	phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); -	if (IS_ERR(phy->wkupclk)) { -		dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); -		return PTR_ERR(phy->wkupclk); -	} -	clk_prepare(phy->wkupclk); - -	phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m"); -	if (IS_ERR(phy->optclk)) -		dev_vdbg(&pdev->dev, "unable to get refclk960m\n"); -	else -		clk_prepare(phy->optclk); - -	usb_add_phy_dev(&phy->phy); - -	platform_set_drvdata(pdev, phy); - -	pm_runtime_enable(phy->dev); - -	return 0; -} - -static int omap_usb2_remove(struct platform_device *pdev) -{ -	struct omap_usb	*phy = platform_get_drvdata(pdev); - -	clk_unprepare(phy->wkupclk); -	if (!IS_ERR(phy->optclk)) -		clk_unprepare(phy->optclk); -	usb_remove_phy(&phy->phy); - -	return 0; -} - -#ifdef CONFIG_PM_RUNTIME - -static int omap_usb2_runtime_suspend(struct device *dev) -{ -	struct platform_device	*pdev = to_platform_device(dev); -	struct omap_usb	*phy = platform_get_drvdata(pdev); - -	clk_disable(phy->wkupclk); -	if (!IS_ERR(phy->optclk)) -		clk_disable(phy->optclk); - -	return 0; -} - -static int omap_usb2_runtime_resume(struct device *dev) -{ -	struct platform_device	*pdev = to_platform_device(dev); -	struct omap_usb	*phy = platform_get_drvdata(pdev); -	int ret; - -	ret = clk_enable(phy->wkupclk); -	if (ret < 0) { -		dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); -		goto err0; -	} - -	if (!IS_ERR(phy->optclk)) { -		ret = clk_enable(phy->optclk); -		if (ret < 0) { -			dev_err(phy->dev, "Failed to enable optclk %d\n", ret); -			goto err1; -		} -	} - -	return 0; - -err1: -	clk_disable(phy->wkupclk); - -err0: -	return ret; -} - -static const struct dev_pm_ops omap_usb2_pm_ops = { -	SET_RUNTIME_PM_OPS(omap_usb2_runtime_suspend, omap_usb2_runtime_resume, -		NULL) -}; - -#define DEV_PM_OPS     (&omap_usb2_pm_ops) -#else -#define DEV_PM_OPS     NULL -#endif - -#ifdef CONFIG_OF -static const struct of_device_id omap_usb2_id_table[] = { -	{ .compatible = "ti,omap-usb2" }, -	{} -}; -MODULE_DEVICE_TABLE(of, omap_usb2_id_table); -#endif - -static struct platform_driver omap_usb2_driver = { -	.probe		= omap_usb2_probe, -	.remove		= omap_usb2_remove, -	.driver		= { -		.name	= "omap-usb2", -		.owner	= THIS_MODULE, -		.pm	= DEV_PM_OPS, -		.of_match_table = of_match_ptr(omap_usb2_id_table), -	}, -}; - -module_platform_driver(omap_usb2_driver); - -MODULE_ALIAS("platform: omap_usb2"); -MODULE_AUTHOR("Texas Instruments Inc."); -MODULE_DESCRIPTION("OMAP USB2 phy driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/phy/phy-omap-usb3.c b/drivers/usb/phy/phy-omap-usb3.c deleted file mode 100644 index fc15694d303..00000000000 --- a/drivers/usb/phy/phy-omap-usb3.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * omap-usb3 - USB PHY, talking to dwc3 controller in OMAP. - * - * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Author: Kishon Vijay Abraham I <kishon@ti.com> - * - * 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/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> -#include <linux/usb/omap_usb.h> -#include <linux/of.h> -#include <linux/clk.h> -#include <linux/err.h> -#include <linux/pm_runtime.h> -#include <linux/delay.h> -#include <linux/usb/omap_control_usb.h> - -#define	PLL_STATUS		0x00000004 -#define	PLL_GO			0x00000008 -#define	PLL_CONFIGURATION1	0x0000000C -#define	PLL_CONFIGURATION2	0x00000010 -#define	PLL_CONFIGURATION3	0x00000014 -#define	PLL_CONFIGURATION4	0x00000020 - -#define	PLL_REGM_MASK		0x001FFE00 -#define	PLL_REGM_SHIFT		0x9 -#define	PLL_REGM_F_MASK		0x0003FFFF -#define	PLL_REGM_F_SHIFT	0x0 -#define	PLL_REGN_MASK		0x000001FE -#define	PLL_REGN_SHIFT		0x1 -#define	PLL_SELFREQDCO_MASK	0x0000000E -#define	PLL_SELFREQDCO_SHIFT	0x1 -#define	PLL_SD_MASK		0x0003FC00 -#define	PLL_SD_SHIFT		0x9 -#define	SET_PLL_GO		0x1 -#define	PLL_TICOPWDN		0x10000 -#define	PLL_LOCK		0x2 -#define	PLL_IDLE		0x1 - -/* - * This is an Empirical value that works, need to confirm the actual - * value required for the USB3PHY_PLL_CONFIGURATION2.PLL_IDLE status - * to be correctly reflected in the USB3PHY_PLL_STATUS register. - */ -# define PLL_IDLE_TIME  100; - -struct usb_dpll_map { -	unsigned long rate; -	struct usb_dpll_params params; -}; - -static struct usb_dpll_map dpll_map[] = { -	{12000000, {1250, 5, 4, 20, 0} },	/* 12 MHz */ -	{16800000, {3125, 20, 4, 20, 0} },	/* 16.8 MHz */ -	{19200000, {1172, 8, 4, 20, 65537} },	/* 19.2 MHz */ -	{20000000, {1000, 7, 4, 10, 0} },	/* 20 MHz */ -	{26000000, {1250, 12, 4, 20, 0} },	/* 26 MHz */ -	{38400000, {3125, 47, 4, 20, 92843} },	/* 38.4 MHz */ -}; - -static struct usb_dpll_params *omap_usb3_get_dpll_params(unsigned long rate) -{ -	int i; - -	for (i = 0; i < ARRAY_SIZE(dpll_map); i++) { -		if (rate == dpll_map[i].rate) -			return &dpll_map[i].params; -	} - -	return 0; -} - -static int omap_usb3_suspend(struct usb_phy *x, int suspend) -{ -	struct omap_usb *phy = phy_to_omapusb(x); -	int	val; -	int timeout = PLL_IDLE_TIME; - -	if (suspend && !phy->is_suspended) { -		val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); -		val |= PLL_IDLE; -		omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); - -		do { -			val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS); -			if (val & PLL_TICOPWDN) -				break; -			udelay(1); -		} while (--timeout); - -		omap_control_usb3_phy_power(phy->control_dev, 0); - -		phy->is_suspended	= 1; -	} else if (!suspend && phy->is_suspended) { -		phy->is_suspended	= 0; - -		val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); -		val &= ~PLL_IDLE; -		omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); - -		do { -			val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS); -			if (!(val & PLL_TICOPWDN)) -				break; -			udelay(1); -		} while (--timeout); -	} - -	return 0; -} - -static void omap_usb_dpll_relock(struct omap_usb *phy) -{ -	u32		val; -	unsigned long	timeout; - -	omap_usb_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO); - -	timeout = jiffies + msecs_to_jiffies(20); -	do { -		val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS); -		if (val & PLL_LOCK) -			break; -	} while (!WARN_ON(time_after(jiffies, timeout))); -} - -static int omap_usb_dpll_lock(struct omap_usb *phy) -{ -	u32			val; -	unsigned long		rate; -	struct usb_dpll_params *dpll_params; - -	rate = clk_get_rate(phy->sys_clk); -	dpll_params = omap_usb3_get_dpll_params(rate); -	if (!dpll_params) { -		dev_err(phy->dev, -			  "No DPLL configuration for %lu Hz SYS CLK\n", rate); -		return -EINVAL; -	} - -	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); -	val &= ~PLL_REGN_MASK; -	val |= dpll_params->n << PLL_REGN_SHIFT; -	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); - -	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); -	val &= ~PLL_SELFREQDCO_MASK; -	val |= dpll_params->freq << PLL_SELFREQDCO_SHIFT; -	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); - -	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); -	val &= ~PLL_REGM_MASK; -	val |= dpll_params->m << PLL_REGM_SHIFT; -	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); - -	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4); -	val &= ~PLL_REGM_F_MASK; -	val |= dpll_params->mf << PLL_REGM_F_SHIFT; -	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val); - -	val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3); -	val &= ~PLL_SD_MASK; -	val |= dpll_params->sd << PLL_SD_SHIFT; -	omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val); - -	omap_usb_dpll_relock(phy); - -	return 0; -} - -static int omap_usb3_init(struct usb_phy *x) -{ -	struct omap_usb	*phy = phy_to_omapusb(x); -	int ret; - -	ret = omap_usb_dpll_lock(phy); -	if (ret) -		return ret; - -	omap_control_usb3_phy_power(phy->control_dev, 1); - -	return 0; -} - -static int omap_usb3_probe(struct platform_device *pdev) -{ -	struct omap_usb			*phy; -	struct resource			*res; - -	phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); -	if (!phy) { -		dev_err(&pdev->dev, "unable to alloc mem for OMAP USB3 PHY\n"); -		return -ENOMEM; -	} - -	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_ctrl"); -	phy->pll_ctrl_base = devm_ioremap_resource(&pdev->dev, res); -	if (IS_ERR(phy->pll_ctrl_base)) -		return PTR_ERR(phy->pll_ctrl_base); - -	phy->dev		= &pdev->dev; - -	phy->phy.dev		= phy->dev; -	phy->phy.label		= "omap-usb3"; -	phy->phy.init		= omap_usb3_init; -	phy->phy.set_suspend	= omap_usb3_suspend; -	phy->phy.type		= USB_PHY_TYPE_USB3; - -	phy->is_suspended	= 1; -	phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); -	if (IS_ERR(phy->wkupclk)) { -		dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); -		return PTR_ERR(phy->wkupclk); -	} -	clk_prepare(phy->wkupclk); - -	phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m"); -	if (IS_ERR(phy->optclk)) { -		dev_err(&pdev->dev, "unable to get usb_otg_ss_refclk960m\n"); -		return PTR_ERR(phy->optclk); -	} -	clk_prepare(phy->optclk); - -	phy->sys_clk = devm_clk_get(phy->dev, "sys_clkin"); -	if (IS_ERR(phy->sys_clk)) { -		pr_err("%s: unable to get sys_clkin\n", __func__); -		return -EINVAL; -	} - -	phy->control_dev = omap_get_control_dev(); -	if (IS_ERR(phy->control_dev)) { -		dev_dbg(&pdev->dev, "Failed to get control device\n"); -		return -ENODEV; -	} - -	omap_control_usb3_phy_power(phy->control_dev, 0); -	usb_add_phy_dev(&phy->phy); - -	platform_set_drvdata(pdev, phy); - -	pm_runtime_enable(phy->dev); -	pm_runtime_get(&pdev->dev); - -	return 0; -} - -static int omap_usb3_remove(struct platform_device *pdev) -{ -	struct omap_usb *phy = platform_get_drvdata(pdev); - -	clk_unprepare(phy->wkupclk); -	clk_unprepare(phy->optclk); -	usb_remove_phy(&phy->phy); -	if (!pm_runtime_suspended(&pdev->dev)) -		pm_runtime_put(&pdev->dev); -	pm_runtime_disable(&pdev->dev); - -	return 0; -} - -#ifdef CONFIG_PM_RUNTIME - -static int omap_usb3_runtime_suspend(struct device *dev) -{ -	struct platform_device	*pdev = to_platform_device(dev); -	struct omap_usb	*phy = platform_get_drvdata(pdev); - -	clk_disable(phy->wkupclk); -	clk_disable(phy->optclk); - -	return 0; -} - -static int omap_usb3_runtime_resume(struct device *dev) -{ -	u32 ret = 0; -	struct platform_device	*pdev = to_platform_device(dev); -	struct omap_usb	*phy = platform_get_drvdata(pdev); - -	ret = clk_enable(phy->optclk); -	if (ret) { -		dev_err(phy->dev, "Failed to enable optclk %d\n", ret); -		goto err1; -	} - -	ret = clk_enable(phy->wkupclk); -	if (ret) { -		dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); -		goto err2; -	} - -	return 0; - -err2: -	clk_disable(phy->optclk); - -err1: -	return ret; -} - -static const struct dev_pm_ops omap_usb3_pm_ops = { -	SET_RUNTIME_PM_OPS(omap_usb3_runtime_suspend, omap_usb3_runtime_resume, -		NULL) -}; - -#define DEV_PM_OPS     (&omap_usb3_pm_ops) -#else -#define DEV_PM_OPS     NULL -#endif - -#ifdef CONFIG_OF -static const struct of_device_id omap_usb3_id_table[] = { -	{ .compatible = "ti,omap-usb3" }, -	{} -}; -MODULE_DEVICE_TABLE(of, omap_usb3_id_table); -#endif - -static struct platform_driver omap_usb3_driver = { -	.probe		= omap_usb3_probe, -	.remove		= omap_usb3_remove, -	.driver		= { -		.name	= "omap-usb3", -		.owner	= THIS_MODULE, -		.pm	= DEV_PM_OPS, -		.of_match_table = of_match_ptr(omap_usb3_id_table), -	}, -}; - -module_platform_driver(omap_usb3_driver); - -MODULE_ALIAS("platform: omap_usb3"); -MODULE_AUTHOR("Texas Instruments Inc."); -MODULE_DESCRIPTION("OMAP USB3 phy driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/phy/phy-rcar-gen2-usb.c b/drivers/usb/phy/phy-rcar-gen2-usb.c new file mode 100644 index 00000000000..388d89f6b14 --- /dev/null +++ b/drivers/usb/phy/phy-rcar-gen2-usb.c @@ -0,0 +1,248 @@ +/* + * Renesas R-Car Gen2 USB phy driver + * + * Copyright (C) 2013 Renesas Solutions Corp. + * Copyright (C) 2013 Cogent Embedded, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_data/usb-rcar-gen2-phy.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/usb/otg.h> + +struct rcar_gen2_usb_phy_priv { +	struct usb_phy phy; +	void __iomem *base; +	struct clk *clk; +	spinlock_t lock; +	int usecount; +	u32 ugctrl2; +}; + +#define usb_phy_to_priv(p) container_of(p, struct rcar_gen2_usb_phy_priv, phy) + +/* Low Power Status register */ +#define USBHS_LPSTS_REG			0x02 +#define USBHS_LPSTS_SUSPM		(1 << 14) + +/* USB General control register */ +#define USBHS_UGCTRL_REG		0x80 +#define USBHS_UGCTRL_CONNECT		(1 << 2) +#define USBHS_UGCTRL_PLLRESET		(1 << 0) + +/* USB General control register 2 */ +#define USBHS_UGCTRL2_REG		0x84 +#define USBHS_UGCTRL2_USB0_PCI		(1 << 4) +#define USBHS_UGCTRL2_USB0_HS		(3 << 4) +#define USBHS_UGCTRL2_USB2_PCI		(0 << 31) +#define USBHS_UGCTRL2_USB2_SS		(1 << 31) + +/* USB General status register */ +#define USBHS_UGSTS_REG			0x88 +#define USBHS_UGSTS_LOCK		(3 << 8) + +/* Enable USBHS internal phy */ +static int __rcar_gen2_usbhs_phy_enable(void __iomem *base) +{ +	u32 val; +	int i; + +	/* USBHS PHY power on */ +	val = ioread32(base + USBHS_UGCTRL_REG); +	val &= ~USBHS_UGCTRL_PLLRESET; +	iowrite32(val, base + USBHS_UGCTRL_REG); + +	val = ioread16(base + USBHS_LPSTS_REG); +	val |= USBHS_LPSTS_SUSPM; +	iowrite16(val, base + USBHS_LPSTS_REG); + +	for (i = 0; i < 20; i++) { +		val = ioread32(base + USBHS_UGSTS_REG); +		if ((val & USBHS_UGSTS_LOCK) == USBHS_UGSTS_LOCK) { +			val = ioread32(base + USBHS_UGCTRL_REG); +			val |= USBHS_UGCTRL_CONNECT; +			iowrite32(val, base + USBHS_UGCTRL_REG); +			return 0; +		} +		udelay(1); +	} + +	/* Timed out waiting for the PLL lock */ +	return -ETIMEDOUT; +} + +/* Disable USBHS internal phy */ +static int __rcar_gen2_usbhs_phy_disable(void __iomem *base) +{ +	u32 val; + +	/* USBHS PHY power off */ +	val = ioread32(base + USBHS_UGCTRL_REG); +	val &= ~USBHS_UGCTRL_CONNECT; +	iowrite32(val, base + USBHS_UGCTRL_REG); + +	val = ioread16(base + USBHS_LPSTS_REG); +	val &= ~USBHS_LPSTS_SUSPM; +	iowrite16(val, base + USBHS_LPSTS_REG); + +	val = ioread32(base + USBHS_UGCTRL_REG); +	val |= USBHS_UGCTRL_PLLRESET; +	iowrite32(val, base + USBHS_UGCTRL_REG); +	return 0; +} + +/* Setup USB channels */ +static void __rcar_gen2_usb_phy_init(struct rcar_gen2_usb_phy_priv *priv) +{ +	u32 val; + +	clk_prepare_enable(priv->clk); + +	/* Set USB channels in the USBHS UGCTRL2 register */ +	val = ioread32(priv->base + USBHS_UGCTRL2_REG); +	val &= ~(USBHS_UGCTRL2_USB0_HS | USBHS_UGCTRL2_USB2_SS); +	val |= priv->ugctrl2; +	iowrite32(val, priv->base + USBHS_UGCTRL2_REG); +} + +/* Shutdown USB channels */ +static void __rcar_gen2_usb_phy_shutdown(struct rcar_gen2_usb_phy_priv *priv) +{ +	__rcar_gen2_usbhs_phy_disable(priv->base); +	clk_disable_unprepare(priv->clk); +} + +static int rcar_gen2_usb_phy_set_suspend(struct usb_phy *phy, int suspend) +{ +	struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); +	unsigned long flags; +	int retval; + +	spin_lock_irqsave(&priv->lock, flags); +	retval = suspend ? __rcar_gen2_usbhs_phy_disable(priv->base) : +			   __rcar_gen2_usbhs_phy_enable(priv->base); +	spin_unlock_irqrestore(&priv->lock, flags); +	return retval; +} + +static int rcar_gen2_usb_phy_init(struct usb_phy *phy) +{ +	struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); +	unsigned long flags; + +	spin_lock_irqsave(&priv->lock, flags); +	/* +	 * Enable the clock and setup USB channels +	 * if it's the first user +	 */ +	if (!priv->usecount++) +		__rcar_gen2_usb_phy_init(priv); +	spin_unlock_irqrestore(&priv->lock, flags); +	return 0; +} + +static void rcar_gen2_usb_phy_shutdown(struct usb_phy *phy) +{ +	struct rcar_gen2_usb_phy_priv *priv = usb_phy_to_priv(phy); +	unsigned long flags; + +	spin_lock_irqsave(&priv->lock, flags); +	if (!priv->usecount) { +		dev_warn(phy->dev, "Trying to disable phy with 0 usecount\n"); +		goto out; +	} + +	/* Disable everything if it's the last user */ +	if (!--priv->usecount) +		__rcar_gen2_usb_phy_shutdown(priv); +out: +	spin_unlock_irqrestore(&priv->lock, flags); +} + +static int rcar_gen2_usb_phy_probe(struct platform_device *pdev) +{ +	struct device *dev = &pdev->dev; +	struct rcar_gen2_phy_platform_data *pdata; +	struct rcar_gen2_usb_phy_priv *priv; +	struct resource *res; +	void __iomem *base; +	struct clk *clk; +	int retval; + +	pdata = dev_get_platdata(dev); +	if (!pdata) { +		dev_err(dev, "No platform data\n"); +		return -EINVAL; +	} + +	clk = devm_clk_get(dev, "usbhs"); +	if (IS_ERR(clk)) { +		dev_err(dev, "Can't get the clock\n"); +		return PTR_ERR(clk); +	} + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	base = devm_ioremap_resource(dev, res); +	if (IS_ERR(base)) +		return PTR_ERR(base); + +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) { +		dev_err(dev, "Memory allocation failed\n"); +		return -ENOMEM; +	} + +	spin_lock_init(&priv->lock); +	priv->clk = clk; +	priv->base = base; +	priv->ugctrl2 = pdata->chan0_pci ? +			USBHS_UGCTRL2_USB0_PCI : USBHS_UGCTRL2_USB0_HS; +	priv->ugctrl2 |= pdata->chan2_pci ? +			USBHS_UGCTRL2_USB2_PCI : USBHS_UGCTRL2_USB2_SS; +	priv->phy.dev = dev; +	priv->phy.label = dev_name(dev); +	priv->phy.init = rcar_gen2_usb_phy_init; +	priv->phy.shutdown = rcar_gen2_usb_phy_shutdown; +	priv->phy.set_suspend = rcar_gen2_usb_phy_set_suspend; + +	retval = usb_add_phy_dev(&priv->phy); +	if (retval < 0) { +		dev_err(dev, "Failed to add USB phy\n"); +		return retval; +	} + +	platform_set_drvdata(pdev, priv); + +	return retval; +} + +static int rcar_gen2_usb_phy_remove(struct platform_device *pdev) +{ +	struct rcar_gen2_usb_phy_priv *priv = platform_get_drvdata(pdev); + +	usb_remove_phy(&priv->phy); + +	return 0; +} + +static struct platform_driver rcar_gen2_usb_phy_driver = { +	.driver = { +		.name = "usb_phy_rcar_gen2", +	}, +	.probe = rcar_gen2_usb_phy_probe, +	.remove = rcar_gen2_usb_phy_remove, +}; + +module_platform_driver(rcar_gen2_usb_phy_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Renesas R-Car Gen2 USB phy"); +MODULE_AUTHOR("Valentine Barshak <valentine.barshak@cogentembedded.com>"); diff --git a/drivers/usb/phy/phy-samsung-usb2.c b/drivers/usb/phy/phy-samsung-usb2.c index ff70e4b19b9..b3ba86627b7 100644 --- a/drivers/usb/phy/phy-samsung-usb2.c +++ b/drivers/usb/phy/phy-samsung-usb2.c @@ -411,6 +411,7 @@ static int samsung_usb2phy_probe(struct platform_device *pdev)  	sphy->drv_data		= drv_data;  	sphy->phy.dev		= sphy->dev;  	sphy->phy.label		= "samsung-usb2phy"; +	sphy->phy.type		= USB_PHY_TYPE_USB2;  	sphy->phy.init		= samsung_usb2phy_init;  	sphy->phy.shutdown	= samsung_usb2phy_shutdown; @@ -426,7 +427,7 @@ static int samsung_usb2phy_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, sphy); -	return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2); +	return usb_add_phy_dev(&sphy->phy);  }  static int samsung_usb2phy_remove(struct platform_device *pdev) diff --git a/drivers/usb/phy/phy-samsung-usb3.c b/drivers/usb/phy/phy-samsung-usb3.c index c6eb22213de..cc0819248ac 100644 --- a/drivers/usb/phy/phy-samsung-usb3.c +++ b/drivers/usb/phy/phy-samsung-usb3.c @@ -271,6 +271,7 @@ static int samsung_usb3phy_probe(struct platform_device *pdev)  	sphy->clk		= clk;  	sphy->phy.dev		= sphy->dev;  	sphy->phy.label		= "samsung-usb3phy"; +	sphy->phy.type		= USB_PHY_TYPE_USB3;  	sphy->phy.init		= samsung_usb3phy_init;  	sphy->phy.shutdown	= samsung_usb3phy_shutdown;  	sphy->drv_data		= samsung_usbphy_get_driver_data(pdev); @@ -283,7 +284,7 @@ static int samsung_usb3phy_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, sphy); -	return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB3); +	return usb_add_phy_dev(&sphy->phy);  }  static int samsung_usb3phy_remove(struct platform_device *pdev) diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c new file mode 100644 index 00000000000..cc61ee44b91 --- /dev/null +++ b/drivers/usb/phy/phy-tahvo.c @@ -0,0 +1,457 @@ +/* + * Tahvo USB transceiver driver + * + * Copyright (C) 2005-2006 Nokia Corporation + * + * Parts copied from isp1301_omap.c. + * Copyright (C) 2004 Texas Instruments + * Copyright (C) 2004 David Brownell + * + * Original driver written by Juha Yrjölä, Tony Lindgren and Timo Teräs. + * Modified for Retu/Tahvo MFD by Aaro Koskinen. + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * 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/io.h> +#include <linux/clk.h> +#include <linux/usb.h> +#include <linux/extcon.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/usb/otg.h> +#include <linux/mfd/retu.h> +#include <linux/usb/gadget.h> +#include <linux/platform_device.h> + +#define DRIVER_NAME     "tahvo-usb" + +#define TAHVO_REG_IDSR	0x02 +#define TAHVO_REG_USBR	0x06 + +#define USBR_SLAVE_CONTROL	(1 << 8) +#define USBR_VPPVIO_SW		(1 << 7) +#define USBR_SPEED		(1 << 6) +#define USBR_REGOUT		(1 << 5) +#define USBR_MASTER_SW2		(1 << 4) +#define USBR_MASTER_SW1		(1 << 3) +#define USBR_SLAVE_SW		(1 << 2) +#define USBR_NSUSPEND		(1 << 1) +#define USBR_SEMODE		(1 << 0) + +#define TAHVO_MODE_HOST		0 +#define TAHVO_MODE_PERIPHERAL	1 + +struct tahvo_usb { +	struct platform_device	*pt_dev; +	struct usb_phy		phy; +	int			vbus_state; +	struct mutex		serialize; +	struct clk		*ick; +	int			irq; +	int			tahvo_mode; +	struct extcon_dev	extcon; +}; + +static const char *tahvo_cable[] = { +	"USB-HOST", +	"USB", +	NULL, +}; + +static ssize_t vbus_state_show(struct device *device, +			       struct device_attribute *attr, char *buf) +{ +	struct tahvo_usb *tu = dev_get_drvdata(device); +	return sprintf(buf, "%s\n", tu->vbus_state ? "on" : "off"); +} +static DEVICE_ATTR(vbus, 0444, vbus_state_show, NULL); + +static void check_vbus_state(struct tahvo_usb *tu) +{ +	struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); +	int reg, prev_state; + +	reg = retu_read(rdev, TAHVO_REG_IDSR); +	if (reg & TAHVO_STAT_VBUS) { +		switch (tu->phy.state) { +		case OTG_STATE_B_IDLE: +			/* Enable the gadget driver */ +			if (tu->phy.otg->gadget) +				usb_gadget_vbus_connect(tu->phy.otg->gadget); +			tu->phy.state = OTG_STATE_B_PERIPHERAL; +			break; +		case OTG_STATE_A_IDLE: +			/* +			 * Session is now valid assuming the USB hub is driving +			 * Vbus. +			 */ +			tu->phy.state = OTG_STATE_A_HOST; +			break; +		default: +			break; +		} +		dev_info(&tu->pt_dev->dev, "USB cable connected\n"); +	} else { +		switch (tu->phy.state) { +		case OTG_STATE_B_PERIPHERAL: +			if (tu->phy.otg->gadget) +				usb_gadget_vbus_disconnect(tu->phy.otg->gadget); +			tu->phy.state = OTG_STATE_B_IDLE; +			break; +		case OTG_STATE_A_HOST: +			tu->phy.state = OTG_STATE_A_IDLE; +			break; +		default: +			break; +		} +		dev_info(&tu->pt_dev->dev, "USB cable disconnected\n"); +	} + +	prev_state = tu->vbus_state; +	tu->vbus_state = reg & TAHVO_STAT_VBUS; +	if (prev_state != tu->vbus_state) { +		extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state); +		sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state"); +	} +} + +static void tahvo_usb_become_host(struct tahvo_usb *tu) +{ +	struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); + +	extcon_set_cable_state(&tu->extcon, "USB-HOST", true); + +	/* Power up the transceiver in USB host mode */ +	retu_write(rdev, TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND | +		   USBR_MASTER_SW2 | USBR_MASTER_SW1); +	tu->phy.state = OTG_STATE_A_IDLE; + +	check_vbus_state(tu); +} + +static void tahvo_usb_stop_host(struct tahvo_usb *tu) +{ +	tu->phy.state = OTG_STATE_A_IDLE; +} + +static void tahvo_usb_become_peripheral(struct tahvo_usb *tu) +{ +	struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); + +	extcon_set_cable_state(&tu->extcon, "USB-HOST", false); + +	/* Power up transceiver and set it in USB peripheral mode */ +	retu_write(rdev, TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT | +		   USBR_NSUSPEND | USBR_SLAVE_SW); +	tu->phy.state = OTG_STATE_B_IDLE; + +	check_vbus_state(tu); +} + +static void tahvo_usb_stop_peripheral(struct tahvo_usb *tu) +{ +	if (tu->phy.otg->gadget) +		usb_gadget_vbus_disconnect(tu->phy.otg->gadget); +	tu->phy.state = OTG_STATE_B_IDLE; +} + +static void tahvo_usb_power_off(struct tahvo_usb *tu) +{ +	struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); + +	/* Disable gadget controller if any */ +	if (tu->phy.otg->gadget) +		usb_gadget_vbus_disconnect(tu->phy.otg->gadget); + +	/* Power off transceiver */ +	retu_write(rdev, TAHVO_REG_USBR, 0); +	tu->phy.state = OTG_STATE_UNDEFINED; +} + +static int tahvo_usb_set_suspend(struct usb_phy *dev, int suspend) +{ +	struct tahvo_usb *tu = container_of(dev, struct tahvo_usb, phy); +	struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); +	u16 w; + +	dev_dbg(&tu->pt_dev->dev, "%s\n", __func__); + +	w = retu_read(rdev, TAHVO_REG_USBR); +	if (suspend) +		w &= ~USBR_NSUSPEND; +	else +		w |= USBR_NSUSPEND; +	retu_write(rdev, TAHVO_REG_USBR, w); + +	return 0; +} + +static int tahvo_usb_set_host(struct usb_otg *otg, struct usb_bus *host) +{ +	struct tahvo_usb *tu = container_of(otg->phy, struct tahvo_usb, phy); + +	dev_dbg(&tu->pt_dev->dev, "%s %p\n", __func__, host); + +	mutex_lock(&tu->serialize); + +	if (host == NULL) { +		if (tu->tahvo_mode == TAHVO_MODE_HOST) +			tahvo_usb_power_off(tu); +		otg->host = NULL; +		mutex_unlock(&tu->serialize); +		return 0; +	} + +	if (tu->tahvo_mode == TAHVO_MODE_HOST) { +		otg->host = NULL; +		tahvo_usb_become_host(tu); +	} + +	otg->host = host; + +	mutex_unlock(&tu->serialize); + +	return 0; +} + +static int tahvo_usb_set_peripheral(struct usb_otg *otg, +				    struct usb_gadget *gadget) +{ +	struct tahvo_usb *tu = container_of(otg->phy, struct tahvo_usb, phy); + +	dev_dbg(&tu->pt_dev->dev, "%s %p\n", __func__, gadget); + +	mutex_lock(&tu->serialize); + +	if (!gadget) { +		if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL) +			tahvo_usb_power_off(tu); +		tu->phy.otg->gadget = NULL; +		mutex_unlock(&tu->serialize); +		return 0; +	} + +	tu->phy.otg->gadget = gadget; +	if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL) +		tahvo_usb_become_peripheral(tu); + +	mutex_unlock(&tu->serialize); + +	return 0; +} + +static irqreturn_t tahvo_usb_vbus_interrupt(int irq, void *_tu) +{ +	struct tahvo_usb *tu = _tu; + +	mutex_lock(&tu->serialize); +	check_vbus_state(tu); +	mutex_unlock(&tu->serialize); + +	return IRQ_HANDLED; +} + +static ssize_t otg_mode_show(struct device *device, +			     struct device_attribute *attr, char *buf) +{ +	struct tahvo_usb *tu = dev_get_drvdata(device); + +	switch (tu->tahvo_mode) { +	case TAHVO_MODE_HOST: +		return sprintf(buf, "host\n"); +	case TAHVO_MODE_PERIPHERAL: +		return sprintf(buf, "peripheral\n"); +	} + +	return -EINVAL; +} + +static ssize_t otg_mode_store(struct device *device, +			      struct device_attribute *attr, +			      const char *buf, size_t count) +{ +	struct tahvo_usb *tu = dev_get_drvdata(device); +	int r; + +	mutex_lock(&tu->serialize); +	if (count >= 4 && strncmp(buf, "host", 4) == 0) { +		if (tu->tahvo_mode == TAHVO_MODE_PERIPHERAL) +			tahvo_usb_stop_peripheral(tu); +		tu->tahvo_mode = TAHVO_MODE_HOST; +		if (tu->phy.otg->host) { +			dev_info(device, "HOST mode: host controller present\n"); +			tahvo_usb_become_host(tu); +		} else { +			dev_info(device, "HOST mode: no host controller, powering off\n"); +			tahvo_usb_power_off(tu); +		} +		r = strlen(buf); +	} else if (count >= 10 && strncmp(buf, "peripheral", 10) == 0) { +		if (tu->tahvo_mode == TAHVO_MODE_HOST) +			tahvo_usb_stop_host(tu); +		tu->tahvo_mode = TAHVO_MODE_PERIPHERAL; +		if (tu->phy.otg->gadget) { +			dev_info(device, "PERIPHERAL mode: gadget driver present\n"); +			tahvo_usb_become_peripheral(tu); +		} else { +			dev_info(device, "PERIPHERAL mode: no gadget driver, powering off\n"); +			tahvo_usb_power_off(tu); +		} +		r = strlen(buf); +	} else { +		r = -EINVAL; +	} +	mutex_unlock(&tu->serialize); + +	return r; +} +static DEVICE_ATTR(otg_mode, 0644, otg_mode_show, otg_mode_store); + +static struct attribute *tahvo_attributes[] = { +	&dev_attr_vbus.attr, +	&dev_attr_otg_mode.attr, +	NULL +}; + +static struct attribute_group tahvo_attr_group = { +	.attrs = tahvo_attributes, +}; + +static int tahvo_usb_probe(struct platform_device *pdev) +{ +	struct retu_dev *rdev = dev_get_drvdata(pdev->dev.parent); +	struct tahvo_usb *tu; +	int ret; + +	tu = devm_kzalloc(&pdev->dev, sizeof(*tu), GFP_KERNEL); +	if (!tu) +		return -ENOMEM; + +	tu->phy.otg = devm_kzalloc(&pdev->dev, sizeof(*tu->phy.otg), +				   GFP_KERNEL); +	if (!tu->phy.otg) +		return -ENOMEM; + +	tu->pt_dev = pdev; + +	/* Default mode */ +#ifdef CONFIG_TAHVO_USB_HOST_BY_DEFAULT +	tu->tahvo_mode = TAHVO_MODE_HOST; +#else +	tu->tahvo_mode = TAHVO_MODE_PERIPHERAL; +#endif + +	mutex_init(&tu->serialize); + +	tu->ick = devm_clk_get(&pdev->dev, "usb_l4_ick"); +	if (!IS_ERR(tu->ick)) +		clk_enable(tu->ick); + +	/* +	 * Set initial state, so that we generate kevents only on state changes. +	 */ +	tu->vbus_state = retu_read(rdev, TAHVO_REG_IDSR) & TAHVO_STAT_VBUS; + +	tu->extcon.name = DRIVER_NAME; +	tu->extcon.supported_cable = tahvo_cable; +	tu->extcon.dev.parent = &pdev->dev; + +	ret = extcon_dev_register(&tu->extcon); +	if (ret) { +		dev_err(&pdev->dev, "could not register extcon device: %d\n", +			ret); +		goto err_disable_clk; +	} + +	/* Set the initial cable state. */ +	extcon_set_cable_state(&tu->extcon, "USB-HOST", +			       tu->tahvo_mode == TAHVO_MODE_HOST); +	extcon_set_cable_state(&tu->extcon, "USB", tu->vbus_state); + +	/* Create OTG interface */ +	tahvo_usb_power_off(tu); +	tu->phy.dev = &pdev->dev; +	tu->phy.state = OTG_STATE_UNDEFINED; +	tu->phy.label = DRIVER_NAME; +	tu->phy.set_suspend = tahvo_usb_set_suspend; + +	tu->phy.otg->phy = &tu->phy; +	tu->phy.otg->set_host = tahvo_usb_set_host; +	tu->phy.otg->set_peripheral = tahvo_usb_set_peripheral; + +	ret = usb_add_phy(&tu->phy, USB_PHY_TYPE_USB2); +	if (ret < 0) { +		dev_err(&pdev->dev, "cannot register USB transceiver: %d\n", +			ret); +		goto err_extcon_unreg; +	} + +	dev_set_drvdata(&pdev->dev, tu); + +	tu->irq = platform_get_irq(pdev, 0); +	ret = request_threaded_irq(tu->irq, NULL, tahvo_usb_vbus_interrupt, 0, +				   "tahvo-vbus", tu); +	if (ret) { +		dev_err(&pdev->dev, "could not register tahvo-vbus irq: %d\n", +			ret); +		goto err_remove_phy; +	} + +	/* Attributes */ +	ret = sysfs_create_group(&pdev->dev.kobj, &tahvo_attr_group); +	if (ret) { +		dev_err(&pdev->dev, "cannot create sysfs group: %d\n", ret); +		goto err_free_irq; +	} + +	return 0; + +err_free_irq: +	free_irq(tu->irq, tu); +err_remove_phy: +	usb_remove_phy(&tu->phy); +err_extcon_unreg: +	extcon_dev_unregister(&tu->extcon); +err_disable_clk: +	if (!IS_ERR(tu->ick)) +		clk_disable(tu->ick); + +	return ret; +} + +static int tahvo_usb_remove(struct platform_device *pdev) +{ +	struct tahvo_usb *tu = platform_get_drvdata(pdev); + +	sysfs_remove_group(&pdev->dev.kobj, &tahvo_attr_group); +	free_irq(tu->irq, tu); +	usb_remove_phy(&tu->phy); +	extcon_dev_unregister(&tu->extcon); +	if (!IS_ERR(tu->ick)) +		clk_disable(tu->ick); + +	return 0; +} + +static struct platform_driver tahvo_usb_driver = { +	.probe		= tahvo_usb_probe, +	.remove		= tahvo_usb_remove, +	.driver		= { +		.name	= "tahvo-usb", +		.owner	= THIS_MODULE, +	}, +}; +module_platform_driver(tahvo_usb_driver); + +MODULE_DESCRIPTION("Tahvo USB transceiver driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Juha Yrjölä, Tony Lindgren, and Timo Teräs"); +MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>"); diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index e9cb1cb8abc..bbe4f8e6e8d 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -876,7 +876,7 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy,  	tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start,  		resource_size(res)); -	if (!tegra_phy->regs) { +	if (!tegra_phy->pad_regs) {  		dev_err(&pdev->dev, "Failed to remap UTMI Pad regs\n");  		return -ENOMEM;  	} @@ -1090,7 +1090,7 @@ static struct platform_driver tegra_usb_phy_driver = {  	.driver		= {  		.name	= "tegra-phy",  		.owner	= THIS_MODULE, -		.of_match_table = of_match_ptr(tegra_usb_phy_id_table), +		.of_match_table = tegra_usb_phy_id_table,  	},  };  module_platform_driver(tegra_usb_phy_driver); diff --git a/drivers/usb/phy/phy-twl4030-usb.c b/drivers/usb/phy/phy-twl4030-usb.c deleted file mode 100644 index 90730c8762b..00000000000 --- a/drivers/usb/phy/phy-twl4030-usb.c +++ /dev/null @@ -1,794 +0,0 @@ -/* - * twl4030_usb - TWL4030 USB transceiver, talking to OMAP OTG controller - * - * Copyright (C) 2004-2007 Texas Instruments - * Copyright (C) 2008 Nokia Corporation - * Contact: Felipe Balbi <felipe.balbi@nokia.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Current status: - *	- HS USB ULPI mode works. - *	- 3-pin mode support may be added in future. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/platform_device.h> -#include <linux/spinlock.h> -#include <linux/workqueue.h> -#include <linux/io.h> -#include <linux/delay.h> -#include <linux/usb/otg.h> -#include <linux/usb/musb-omap.h> -#include <linux/usb/ulpi.h> -#include <linux/i2c/twl.h> -#include <linux/regulator/consumer.h> -#include <linux/err.h> -#include <linux/slab.h> - -/* Register defines */ - -#define MCPC_CTRL			0x30 -#define MCPC_CTRL_RTSOL			(1 << 7) -#define MCPC_CTRL_EXTSWR		(1 << 6) -#define MCPC_CTRL_EXTSWC		(1 << 5) -#define MCPC_CTRL_VOICESW		(1 << 4) -#define MCPC_CTRL_OUT64K		(1 << 3) -#define MCPC_CTRL_RTSCTSSW		(1 << 2) -#define MCPC_CTRL_HS_UART		(1 << 0) - -#define MCPC_IO_CTRL			0x33 -#define MCPC_IO_CTRL_MICBIASEN		(1 << 5) -#define MCPC_IO_CTRL_CTS_NPU		(1 << 4) -#define MCPC_IO_CTRL_RXD_PU		(1 << 3) -#define MCPC_IO_CTRL_TXDTYP		(1 << 2) -#define MCPC_IO_CTRL_CTSTYP		(1 << 1) -#define MCPC_IO_CTRL_RTSTYP		(1 << 0) - -#define MCPC_CTRL2			0x36 -#define MCPC_CTRL2_MCPC_CK_EN		(1 << 0) - -#define OTHER_FUNC_CTRL			0x80 -#define OTHER_FUNC_CTRL_BDIS_ACON_EN	(1 << 4) -#define OTHER_FUNC_CTRL_FIVEWIRE_MODE	(1 << 2) - -#define OTHER_IFC_CTRL			0x83 -#define OTHER_IFC_CTRL_OE_INT_EN	(1 << 6) -#define OTHER_IFC_CTRL_CEA2011_MODE	(1 << 5) -#define OTHER_IFC_CTRL_FSLSSERIALMODE_4PIN	(1 << 4) -#define OTHER_IFC_CTRL_HIZ_ULPI_60MHZ_OUT	(1 << 3) -#define OTHER_IFC_CTRL_HIZ_ULPI		(1 << 2) -#define OTHER_IFC_CTRL_ALT_INT_REROUTE	(1 << 0) - -#define OTHER_INT_EN_RISE		0x86 -#define OTHER_INT_EN_FALL		0x89 -#define OTHER_INT_STS			0x8C -#define OTHER_INT_LATCH			0x8D -#define OTHER_INT_VB_SESS_VLD		(1 << 7) -#define OTHER_INT_DM_HI			(1 << 6) /* not valid for "latch" reg */ -#define OTHER_INT_DP_HI			(1 << 5) /* not valid for "latch" reg */ -#define OTHER_INT_BDIS_ACON		(1 << 3) /* not valid for "fall" regs */ -#define OTHER_INT_MANU			(1 << 1) -#define OTHER_INT_ABNORMAL_STRESS	(1 << 0) - -#define ID_STATUS			0x96 -#define ID_RES_FLOAT			(1 << 4) -#define ID_RES_440K			(1 << 3) -#define ID_RES_200K			(1 << 2) -#define ID_RES_102K			(1 << 1) -#define ID_RES_GND			(1 << 0) - -#define POWER_CTRL			0xAC -#define POWER_CTRL_OTG_ENAB		(1 << 5) - -#define OTHER_IFC_CTRL2			0xAF -#define OTHER_IFC_CTRL2_ULPI_STP_LOW	(1 << 4) -#define OTHER_IFC_CTRL2_ULPI_TXEN_POL	(1 << 3) -#define OTHER_IFC_CTRL2_ULPI_4PIN_2430	(1 << 2) -#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_MASK	(3 << 0) /* bits 0 and 1 */ -#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT1N	(0 << 0) -#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT2N	(1 << 0) - -#define REG_CTRL_EN			0xB2 -#define REG_CTRL_ERROR			0xB5 -#define ULPI_I2C_CONFLICT_INTEN		(1 << 0) - -#define OTHER_FUNC_CTRL2		0xB8 -#define OTHER_FUNC_CTRL2_VBAT_TIMER_EN	(1 << 0) - -/* following registers do not have separate _clr and _set registers */ -#define VBUS_DEBOUNCE			0xC0 -#define ID_DEBOUNCE			0xC1 -#define VBAT_TIMER			0xD3 -#define PHY_PWR_CTRL			0xFD -#define PHY_PWR_PHYPWD			(1 << 0) -#define PHY_CLK_CTRL			0xFE -#define PHY_CLK_CTRL_CLOCKGATING_EN	(1 << 2) -#define PHY_CLK_CTRL_CLK32K_EN		(1 << 1) -#define REQ_PHY_DPLL_CLK		(1 << 0) -#define PHY_CLK_CTRL_STS		0xFF -#define PHY_DPLL_CLK			(1 << 0) - -/* In module TWL_MODULE_PM_MASTER */ -#define STS_HW_CONDITIONS		0x0F - -/* In module TWL_MODULE_PM_RECEIVER */ -#define VUSB_DEDICATED1			0x7D -#define VUSB_DEDICATED2			0x7E -#define VUSB1V5_DEV_GRP			0x71 -#define VUSB1V5_TYPE			0x72 -#define VUSB1V5_REMAP			0x73 -#define VUSB1V8_DEV_GRP			0x74 -#define VUSB1V8_TYPE			0x75 -#define VUSB1V8_REMAP			0x76 -#define VUSB3V1_DEV_GRP			0x77 -#define VUSB3V1_TYPE			0x78 -#define VUSB3V1_REMAP			0x79 - -/* In module TWL4030_MODULE_INTBR */ -#define PMBR1				0x0D -#define GPIO_USB_4PIN_ULPI_2430C	(3 << 0) - -struct twl4030_usb { -	struct usb_phy		phy; -	struct device		*dev; - -	/* TWL4030 internal USB regulator supplies */ -	struct regulator	*usb1v5; -	struct regulator	*usb1v8; -	struct regulator	*usb3v1; - -	/* for vbus reporting with irqs disabled */ -	spinlock_t		lock; - -	/* pin configuration */ -	enum twl4030_usb_mode	usb_mode; - -	int			irq; -	enum omap_musb_vbus_id_status linkstat; -	bool			vbus_supplied; -	u8			asleep; -	bool			irq_enabled; - -	struct delayed_work	id_workaround_work; -}; - -/* internal define on top of container_of */ -#define phy_to_twl(x)		container_of((x), struct twl4030_usb, phy) - -/*-------------------------------------------------------------------------*/ - -static int twl4030_i2c_write_u8_verify(struct twl4030_usb *twl, -		u8 module, u8 data, u8 address) -{ -	u8 check; - -	if ((twl_i2c_write_u8(module, data, address) >= 0) && -	    (twl_i2c_read_u8(module, &check, address) >= 0) && -						(check == data)) -		return 0; -	dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", -			1, module, address, check, data); - -	/* Failed once: Try again */ -	if ((twl_i2c_write_u8(module, data, address) >= 0) && -	    (twl_i2c_read_u8(module, &check, address) >= 0) && -						(check == data)) -		return 0; -	dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", -			2, module, address, check, data); - -	/* Failed again: Return error */ -	return -EBUSY; -} - -#define twl4030_usb_write_verify(twl, address, data)	\ -	twl4030_i2c_write_u8_verify(twl, TWL_MODULE_USB, (data), (address)) - -static inline int twl4030_usb_write(struct twl4030_usb *twl, -		u8 address, u8 data) -{ -	int ret = 0; - -	ret = twl_i2c_write_u8(TWL_MODULE_USB, data, address); -	if (ret < 0) -		dev_dbg(twl->dev, -			"TWL4030:USB:Write[0x%x] Error %d\n", address, ret); -	return ret; -} - -static inline int twl4030_readb(struct twl4030_usb *twl, u8 module, u8 address) -{ -	u8 data; -	int ret = 0; - -	ret = twl_i2c_read_u8(module, &data, address); -	if (ret >= 0) -		ret = data; -	else -		dev_dbg(twl->dev, -			"TWL4030:readb[0x%x,0x%x] Error %d\n", -					module, address, ret); - -	return ret; -} - -static inline int twl4030_usb_read(struct twl4030_usb *twl, u8 address) -{ -	return twl4030_readb(twl, TWL_MODULE_USB, address); -} - -/*-------------------------------------------------------------------------*/ - -static inline int -twl4030_usb_set_bits(struct twl4030_usb *twl, u8 reg, u8 bits) -{ -	return twl4030_usb_write(twl, ULPI_SET(reg), bits); -} - -static inline int -twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits) -{ -	return twl4030_usb_write(twl, ULPI_CLR(reg), bits); -} - -/*-------------------------------------------------------------------------*/ - -static bool twl4030_is_driving_vbus(struct twl4030_usb *twl) -{ -	int ret; - -	ret = twl4030_usb_read(twl, PHY_CLK_CTRL_STS); -	if (ret < 0 || !(ret & PHY_DPLL_CLK)) -		/* -		 * if clocks are off, registers are not updated, -		 * but we can assume we don't drive VBUS in this case -		 */ -		return false; - -	ret = twl4030_usb_read(twl, ULPI_OTG_CTRL); -	if (ret < 0) -		return false; - -	return (ret & (ULPI_OTG_DRVVBUS | ULPI_OTG_CHRGVBUS)) ? true : false; -} - -static enum omap_musb_vbus_id_status -	twl4030_usb_linkstat(struct twl4030_usb *twl) -{ -	int	status; -	enum omap_musb_vbus_id_status linkstat = OMAP_MUSB_UNKNOWN; - -	twl->vbus_supplied = false; - -	/* -	 * For ID/VBUS sensing, see manual section 15.4.8 ... -	 * except when using only battery backup power, two -	 * comparators produce VBUS_PRES and ID_PRES signals, -	 * which don't match docs elsewhere.  But ... BIT(7) -	 * and BIT(2) of STS_HW_CONDITIONS, respectively, do -	 * seem to match up.  If either is true the USB_PRES -	 * signal is active, the OTG module is activated, and -	 * its interrupt may be raised (may wake the system). -	 */ -	status = twl4030_readb(twl, TWL_MODULE_PM_MASTER, STS_HW_CONDITIONS); -	if (status < 0) -		dev_err(twl->dev, "USB link status err %d\n", status); -	else if (status & (BIT(7) | BIT(2))) { -		if (status & BIT(7)) { -			if (twl4030_is_driving_vbus(twl)) -				status &= ~BIT(7); -			else -				twl->vbus_supplied = true; -		} - -		if (status & BIT(2)) -			linkstat = OMAP_MUSB_ID_GROUND; -		else if (status & BIT(7)) -			linkstat = OMAP_MUSB_VBUS_VALID; -		else -			linkstat = OMAP_MUSB_VBUS_OFF; -	} else { -		if (twl->linkstat != OMAP_MUSB_UNKNOWN) -			linkstat = OMAP_MUSB_VBUS_OFF; -	} - -	dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n", -			status, status, linkstat); - -	/* REVISIT this assumes host and peripheral controllers -	 * are registered, and that both are active... -	 */ - -	return linkstat; -} - -static void twl4030_usb_set_mode(struct twl4030_usb *twl, int mode) -{ -	twl->usb_mode = mode; - -	switch (mode) { -	case T2_USB_MODE_ULPI: -		twl4030_usb_clear_bits(twl, ULPI_IFC_CTRL, -					ULPI_IFC_CTRL_CARKITMODE); -		twl4030_usb_set_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB); -		twl4030_usb_clear_bits(twl, ULPI_FUNC_CTRL, -					ULPI_FUNC_CTRL_XCVRSEL_MASK | -					ULPI_FUNC_CTRL_OPMODE_MASK); -		break; -	case -1: -		/* FIXME: power on defaults */ -		break; -	default: -		dev_err(twl->dev, "unsupported T2 transceiver mode %d\n", -				mode); -		break; -	}; -} - -static void twl4030_i2c_access(struct twl4030_usb *twl, int on) -{ -	unsigned long timeout; -	int val = twl4030_usb_read(twl, PHY_CLK_CTRL); - -	if (val >= 0) { -		if (on) { -			/* enable DPLL to access PHY registers over I2C */ -			val |= REQ_PHY_DPLL_CLK; -			WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL, -						(u8)val) < 0); - -			timeout = jiffies + HZ; -			while (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) & -							PHY_DPLL_CLK) -				&& time_before(jiffies, timeout)) -					udelay(10); -			if (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) & -							PHY_DPLL_CLK)) -				dev_err(twl->dev, "Timeout setting T2 HSUSB " -						"PHY DPLL clock\n"); -		} else { -			/* let ULPI control the DPLL clock */ -			val &= ~REQ_PHY_DPLL_CLK; -			WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL, -						(u8)val) < 0); -		} -	} -} - -static void __twl4030_phy_power(struct twl4030_usb *twl, int on) -{ -	u8 pwr = twl4030_usb_read(twl, PHY_PWR_CTRL); - -	if (on) -		pwr &= ~PHY_PWR_PHYPWD; -	else -		pwr |= PHY_PWR_PHYPWD; - -	WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); -} - -static void twl4030_phy_power(struct twl4030_usb *twl, int on) -{ -	int ret; - -	if (on) { -		ret = regulator_enable(twl->usb3v1); -		if (ret) -			dev_err(twl->dev, "Failed to enable usb3v1\n"); - -		ret = regulator_enable(twl->usb1v8); -		if (ret) -			dev_err(twl->dev, "Failed to enable usb1v8\n"); - -		/* -		 * Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP -		 * in twl4030) resets the VUSB_DEDICATED2 register. This reset -		 * enables VUSB3V1_SLEEP bit that remaps usb3v1 ACTIVE state to -		 * SLEEP. We work around this by clearing the bit after usv3v1 -		 * is re-activated. This ensures that VUSB3V1 is really active. -		 */ -		twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2); - -		ret = regulator_enable(twl->usb1v5); -		if (ret) -			dev_err(twl->dev, "Failed to enable usb1v5\n"); - -		__twl4030_phy_power(twl, 1); -		twl4030_usb_write(twl, PHY_CLK_CTRL, -				  twl4030_usb_read(twl, PHY_CLK_CTRL) | -					(PHY_CLK_CTRL_CLOCKGATING_EN | -						PHY_CLK_CTRL_CLK32K_EN)); -	} else { -		__twl4030_phy_power(twl, 0); -		regulator_disable(twl->usb1v5); -		regulator_disable(twl->usb1v8); -		regulator_disable(twl->usb3v1); -	} -} - -static void twl4030_phy_suspend(struct twl4030_usb *twl, int controller_off) -{ -	if (twl->asleep) -		return; - -	twl4030_phy_power(twl, 0); -	twl->asleep = 1; -	dev_dbg(twl->dev, "%s\n", __func__); -} - -static void __twl4030_phy_resume(struct twl4030_usb *twl) -{ -	twl4030_phy_power(twl, 1); -	twl4030_i2c_access(twl, 1); -	twl4030_usb_set_mode(twl, twl->usb_mode); -	if (twl->usb_mode == T2_USB_MODE_ULPI) -		twl4030_i2c_access(twl, 0); -} - -static void twl4030_phy_resume(struct twl4030_usb *twl) -{ -	if (!twl->asleep) -		return; -	__twl4030_phy_resume(twl); -	twl->asleep = 0; -	dev_dbg(twl->dev, "%s\n", __func__); - -	/* -	 * XXX When VBUS gets driven after musb goes to A mode, -	 * ID_PRES related interrupts no longer arrive, why? -	 * Register itself is updated fine though, so we must poll. -	 */ -	if (twl->linkstat == OMAP_MUSB_ID_GROUND) { -		cancel_delayed_work(&twl->id_workaround_work); -		schedule_delayed_work(&twl->id_workaround_work, HZ); -	} -} - -static int twl4030_usb_ldo_init(struct twl4030_usb *twl) -{ -	/* Enable writing to power configuration registers */ -	twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1, -			 TWL4030_PM_MASTER_PROTECT_KEY); - -	twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2, -			 TWL4030_PM_MASTER_PROTECT_KEY); - -	/* Keep VUSB3V1 LDO in sleep state until VBUS/ID change detected*/ -	/*twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2);*/ - -	/* input to VUSB3V1 LDO is from VBAT, not VBUS */ -	twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1); - -	/* Initialize 3.1V regulator */ -	twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP); - -	twl->usb3v1 = devm_regulator_get(twl->dev, "usb3v1"); -	if (IS_ERR(twl->usb3v1)) -		return -ENODEV; - -	twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE); - -	/* Initialize 1.5V regulator */ -	twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP); - -	twl->usb1v5 = devm_regulator_get(twl->dev, "usb1v5"); -	if (IS_ERR(twl->usb1v5)) -		return -ENODEV; - -	twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE); - -	/* Initialize 1.8V regulator */ -	twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP); - -	twl->usb1v8 = devm_regulator_get(twl->dev, "usb1v8"); -	if (IS_ERR(twl->usb1v8)) -		return -ENODEV; - -	twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE); - -	/* disable access to power configuration registers */ -	twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0, -			 TWL4030_PM_MASTER_PROTECT_KEY); - -	return 0; -} - -static ssize_t twl4030_usb_vbus_show(struct device *dev, -		struct device_attribute *attr, char *buf) -{ -	struct twl4030_usb *twl = dev_get_drvdata(dev); -	unsigned long flags; -	int ret = -EINVAL; - -	spin_lock_irqsave(&twl->lock, flags); -	ret = sprintf(buf, "%s\n", -			twl->vbus_supplied ? "on" : "off"); -	spin_unlock_irqrestore(&twl->lock, flags); - -	return ret; -} -static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL); - -static irqreturn_t twl4030_usb_irq(int irq, void *_twl) -{ -	struct twl4030_usb *twl = _twl; -	enum omap_musb_vbus_id_status status; -	bool status_changed = false; - -	status = twl4030_usb_linkstat(twl); - -	spin_lock_irq(&twl->lock); -	if (status >= 0 && status != twl->linkstat) { -		twl->linkstat = status; -		status_changed = true; -	} -	spin_unlock_irq(&twl->lock); - -	if (status_changed) { -		/* FIXME add a set_power() method so that B-devices can -		 * configure the charger appropriately.  It's not always -		 * correct to consume VBUS power, and how much current to -		 * consume is a function of the USB configuration chosen -		 * by the host. -		 * -		 * REVISIT usb_gadget_vbus_connect(...) as needed, ditto -		 * its disconnect() sibling, when changing to/from the -		 * USB_LINK_VBUS state.  musb_hdrc won't care until it -		 * starts to handle softconnect right. -		 */ -		omap_musb_mailbox(status); -	} -	sysfs_notify(&twl->dev->kobj, NULL, "vbus"); - -	return IRQ_HANDLED; -} - -static void twl4030_id_workaround_work(struct work_struct *work) -{ -	struct twl4030_usb *twl = container_of(work, struct twl4030_usb, -		id_workaround_work.work); -	enum omap_musb_vbus_id_status status; -	bool status_changed = false; - -	status = twl4030_usb_linkstat(twl); - -	spin_lock_irq(&twl->lock); -	if (status >= 0 && status != twl->linkstat) { -		twl->linkstat = status; -		status_changed = true; -	} -	spin_unlock_irq(&twl->lock); - -	if (status_changed) { -		dev_dbg(twl->dev, "handle missing status change to %d\n", -				status); -		omap_musb_mailbox(status); -	} - -	/* don't schedule during sleep - irq works right then */ -	if (status == OMAP_MUSB_ID_GROUND && !twl->asleep) { -		cancel_delayed_work(&twl->id_workaround_work); -		schedule_delayed_work(&twl->id_workaround_work, HZ); -	} -} - -static int twl4030_usb_phy_init(struct usb_phy *phy) -{ -	struct twl4030_usb *twl = phy_to_twl(phy); -	enum omap_musb_vbus_id_status status; - -	/* -	 * Start in sleep state, we'll get called through set_suspend() -	 * callback when musb is runtime resumed and it's time to start. -	 */ -	__twl4030_phy_power(twl, 0); -	twl->asleep = 1; - -	status = twl4030_usb_linkstat(twl); -	twl->linkstat = status; - -	if (status == OMAP_MUSB_ID_GROUND || status == OMAP_MUSB_VBUS_VALID) -		omap_musb_mailbox(twl->linkstat); - -	sysfs_notify(&twl->dev->kobj, NULL, "vbus"); -	return 0; -} - -static int twl4030_set_suspend(struct usb_phy *x, int suspend) -{ -	struct twl4030_usb *twl = phy_to_twl(x); - -	if (suspend) -		twl4030_phy_suspend(twl, 1); -	else -		twl4030_phy_resume(twl); - -	return 0; -} - -static int twl4030_set_peripheral(struct usb_otg *otg, -					struct usb_gadget *gadget) -{ -	if (!otg) -		return -ENODEV; - -	otg->gadget = gadget; -	if (!gadget) -		otg->phy->state = OTG_STATE_UNDEFINED; - -	return 0; -} - -static int twl4030_set_host(struct usb_otg *otg, struct usb_bus *host) -{ -	if (!otg) -		return -ENODEV; - -	otg->host = host; -	if (!host) -		otg->phy->state = OTG_STATE_UNDEFINED; - -	return 0; -} - -static int twl4030_usb_probe(struct platform_device *pdev) -{ -	struct twl4030_usb_data *pdata = dev_get_platdata(&pdev->dev); -	struct twl4030_usb	*twl; -	int			status, err; -	struct usb_otg		*otg; -	struct device_node	*np = pdev->dev.of_node; - -	twl = devm_kzalloc(&pdev->dev, sizeof *twl, GFP_KERNEL); -	if (!twl) -		return -ENOMEM; - -	if (np) -		of_property_read_u32(np, "usb_mode", -				(enum twl4030_usb_mode *)&twl->usb_mode); -	else if (pdata) -		twl->usb_mode = pdata->usb_mode; -	else { -		dev_err(&pdev->dev, "twl4030 initialized without pdata\n"); -		return -EINVAL; -	} - -	otg = devm_kzalloc(&pdev->dev, sizeof *otg, GFP_KERNEL); -	if (!otg) -		return -ENOMEM; - -	twl->dev		= &pdev->dev; -	twl->irq		= platform_get_irq(pdev, 0); -	twl->vbus_supplied	= false; -	twl->asleep		= 1; -	twl->linkstat		= OMAP_MUSB_UNKNOWN; - -	twl->phy.dev		= twl->dev; -	twl->phy.label		= "twl4030"; -	twl->phy.otg		= otg; -	twl->phy.type		= USB_PHY_TYPE_USB2; -	twl->phy.set_suspend	= twl4030_set_suspend; -	twl->phy.init		= twl4030_usb_phy_init; - -	otg->phy		= &twl->phy; -	otg->set_host		= twl4030_set_host; -	otg->set_peripheral	= twl4030_set_peripheral; - -	/* init spinlock for workqueue */ -	spin_lock_init(&twl->lock); - -	INIT_DELAYED_WORK(&twl->id_workaround_work, twl4030_id_workaround_work); - -	err = twl4030_usb_ldo_init(twl); -	if (err) { -		dev_err(&pdev->dev, "ldo init failed\n"); -		return err; -	} -	usb_add_phy_dev(&twl->phy); - -	platform_set_drvdata(pdev, twl); -	if (device_create_file(&pdev->dev, &dev_attr_vbus)) -		dev_warn(&pdev->dev, "could not create sysfs file\n"); - -	/* Our job is to use irqs and status from the power module -	 * to keep the transceiver disabled when nothing's connected. -	 * -	 * FIXME we actually shouldn't start enabling it until the -	 * USB controller drivers have said they're ready, by calling -	 * set_host() and/or set_peripheral() ... OTG_capable boards -	 * need both handles, otherwise just one suffices. -	 */ -	twl->irq_enabled = true; -	status = devm_request_threaded_irq(twl->dev, twl->irq, NULL, -			twl4030_usb_irq, IRQF_TRIGGER_FALLING | -			IRQF_TRIGGER_RISING | IRQF_ONESHOT, "twl4030_usb", twl); -	if (status < 0) { -		dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n", -			twl->irq, status); -		return status; -	} - -	dev_info(&pdev->dev, "Initialized TWL4030 USB module\n"); -	return 0; -} - -static int twl4030_usb_remove(struct platform_device *pdev) -{ -	struct twl4030_usb *twl = platform_get_drvdata(pdev); -	int val; - -	cancel_delayed_work(&twl->id_workaround_work); -	device_remove_file(twl->dev, &dev_attr_vbus); - -	/* set transceiver mode to power on defaults */ -	twl4030_usb_set_mode(twl, -1); - -	/* autogate 60MHz ULPI clock, -	 * clear dpll clock request for i2c access, -	 * disable 32KHz -	 */ -	val = twl4030_usb_read(twl, PHY_CLK_CTRL); -	if (val >= 0) { -		val |= PHY_CLK_CTRL_CLOCKGATING_EN; -		val &= ~(PHY_CLK_CTRL_CLK32K_EN | REQ_PHY_DPLL_CLK); -		twl4030_usb_write(twl, PHY_CLK_CTRL, (u8)val); -	} - -	/* disable complete OTG block */ -	twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB); - -	if (!twl->asleep) -		twl4030_phy_power(twl, 0); - -	return 0; -} - -#ifdef CONFIG_OF -static const struct of_device_id twl4030_usb_id_table[] = { -	{ .compatible = "ti,twl4030-usb" }, -	{} -}; -MODULE_DEVICE_TABLE(of, twl4030_usb_id_table); -#endif - -static struct platform_driver twl4030_usb_driver = { -	.probe		= twl4030_usb_probe, -	.remove		= twl4030_usb_remove, -	.driver		= { -		.name	= "twl4030_usb", -		.owner	= THIS_MODULE, -		.of_match_table = of_match_ptr(twl4030_usb_id_table), -	}, -}; - -static int __init twl4030_usb_init(void) -{ -	return platform_driver_register(&twl4030_usb_driver); -} -subsys_initcall(twl4030_usb_init); - -static void __exit twl4030_usb_exit(void) -{ -	platform_driver_unregister(&twl4030_usb_driver); -} -module_exit(twl4030_usb_exit); - -MODULE_ALIAS("platform:twl4030_usb"); -MODULE_AUTHOR("Texas Instruments, Inc, Nokia Corporation"); -MODULE_DESCRIPTION("TWL4030 USB transceiver driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index 16dbc938267..04778cf80d6 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -27,12 +27,13 @@  #include <linux/io.h>  #include <linux/usb/musb-omap.h>  #include <linux/usb/phy_companion.h> -#include <linux/usb/omap_usb.h> +#include <linux/phy/omap_usb.h>  #include <linux/i2c/twl.h>  #include <linux/regulator/consumer.h>  #include <linux/err.h>  #include <linux/slab.h>  #include <linux/delay.h> +#include <linux/of.h>  /* usb register definitions */  #define USB_VENDOR_ID_LSB		0x00 @@ -126,7 +127,8 @@ static inline int twl6030_writeb(struct twl6030_usb *twl, u8 module,  static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)  { -	u8 data, ret = 0; +	u8 data; +	int ret;  	ret = twl_i2c_read_u8(module, &data, address);  	if (ret >= 0) @@ -326,7 +328,7 @@ static int twl6030_usb_probe(struct platform_device *pdev)  	struct device		*dev = &pdev->dev;  	struct twl4030_usb_data	*pdata = dev_get_platdata(dev); -	twl = devm_kzalloc(dev, sizeof *twl, GFP_KERNEL); +	twl = devm_kzalloc(dev, sizeof(*twl), GFP_KERNEL);  	if (!twl)  		return -ENOMEM; diff --git a/drivers/usb/phy/phy-ulpi-viewport.c b/drivers/usb/phy/phy-ulpi-viewport.c index 7c22a5390fc..18bb8264b5a 100644 --- a/drivers/usb/phy/phy-ulpi-viewport.c +++ b/drivers/usb/phy/phy-ulpi-viewport.c @@ -36,7 +36,7 @@ static int ulpi_viewport_wait(void __iomem *view, u32 mask)  			return 0;  		udelay(1); -	}; +	}  	return -ETIMEDOUT;  } diff --git a/drivers/usb/phy/phy-ulpi.c b/drivers/usb/phy/phy-ulpi.c index 217339dd7a9..4e3877c329f 100644 --- a/drivers/usb/phy/phy-ulpi.c +++ b/drivers/usb/phy/phy-ulpi.c @@ -47,6 +47,9 @@ struct ulpi_info {  static struct ulpi_info ulpi_ids[] = {  	ULPI_INFO(ULPI_ID(0x04cc, 0x1504), "NXP ISP1504"),  	ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"), +	ULPI_INFO(ULPI_ID(0x0424, 0x0007), "SMSC USB3320"), +	ULPI_INFO(ULPI_ID(0x0424, 0x0009), "SMSC USB334x"), +	ULPI_INFO(ULPI_ID(0x0451, 0x1507), "TI TUSB1210"),  };  static int ulpi_set_otg_flags(struct usb_phy *phy) diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index a9984c700d2..36b6bce33b2 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -98,7 +98,7 @@ struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type)  	ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL);  	if (!ptr) -		return NULL; +		return ERR_PTR(-ENOMEM);  	phy = usb_get_phy(type);  	if (!IS_ERR(phy)) { @@ -130,8 +130,11 @@ struct usb_phy *usb_get_phy(enum usb_phy_type type)  	phy = __usb_find_phy(&phy_list, type);  	if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { -		pr_err("unable to find transceiver of type %s\n", +		pr_debug("PHY: unable to find transceiver of type %s\n",  			usb_phy_type_string(type)); +		if (!IS_ERR(phy)) +			phy = ERR_PTR(-ENODEV); +  		goto err0;  	} @@ -228,7 +231,7 @@ struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index)  	phy = __usb_find_phy_dev(dev, &phy_bind_list, index);  	if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { -		pr_err("unable to find transceiver\n"); +		dev_dbg(dev, "unable to find transceiver\n");  		goto err0;  	} @@ -329,6 +332,8 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)  		return -EINVAL;  	} +	ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier); +  	spin_lock_irqsave(&phy_lock, flags);  	list_for_each_entry(phy, &phy_list, head) { @@ -367,6 +372,8 @@ int usb_add_phy_dev(struct usb_phy *x)  		return -EINVAL;  	} +	ATOMIC_INIT_NOTIFIER_HEAD(&x->notifier); +  	spin_lock_irqsave(&phy_lock, flags);  	list_for_each_entry(phy_bind, &phy_bind_list, list)  		if (!(strcmp(phy_bind->phy_dev_name, dev_name(x->dev)))) @@ -420,10 +427,8 @@ int usb_bind_phy(const char *dev_name, u8 index,  	unsigned long flags;  	phy_bind = kzalloc(sizeof(*phy_bind), GFP_KERNEL); -	if (!phy_bind) { -		pr_err("phy_bind(): No memory for phy_bind"); +	if (!phy_bind)  		return -ENOMEM; -	}  	phy_bind->dev_name = dev_name;  	phy_bind->phy_dev_name = phy_dev_name; diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 45b94019aec..4fd36530bfa 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -681,6 +681,14 @@ usbhs_fifo_read_end:  		usbhs_pipe_number(pipe),  		pkt->length, pkt->actual, *is_done, pkt->zero); +	/* +	 * Transmission end +	 */ +	if (*is_done) { +		if (usbhs_pipe_is_dcp(pipe)) +			usbhs_dcp_control_transfer_done(pipe); +	} +  usbhs_fifo_read_busy:  	usbhsf_fifo_unselect(pipe, fifo); @@ -1124,19 +1132,8 @@ void usbhs_fifo_init(struct usbhs_priv *priv)  	mod->irq_brdysts	= 0;  	cfifo->pipe	= NULL; -	cfifo->tx_chan	= NULL; -	cfifo->rx_chan	= NULL; -  	d0fifo->pipe	= NULL; -	d0fifo->tx_chan	= NULL; -	d0fifo->rx_chan	= NULL; -  	d1fifo->pipe	= NULL; -	d1fifo->tx_chan	= NULL; -	d1fifo->rx_chan	= NULL; - -	usbhsf_dma_init(priv, usbhsf_get_d0fifo(priv)); -	usbhsf_dma_init(priv, usbhsf_get_d1fifo(priv));  }  void usbhs_fifo_quit(struct usbhs_priv *priv) @@ -1147,9 +1144,6 @@ void usbhs_fifo_quit(struct usbhs_priv *priv)  	mod->irq_ready		= NULL;  	mod->irq_bempsts	= 0;  	mod->irq_brdysts	= 0; - -	usbhsf_dma_quit(priv, usbhsf_get_d0fifo(priv)); -	usbhsf_dma_quit(priv, usbhsf_get_d1fifo(priv));  }  int usbhs_fifo_probe(struct usbhs_priv *priv) @@ -1171,6 +1165,7 @@ int usbhs_fifo_probe(struct usbhs_priv *priv)  	fifo->ctr	= D0FIFOCTR;  	fifo->tx_slave.shdma_slave.slave_id	= usbhs_get_dparam(priv, d0_tx_id);  	fifo->rx_slave.shdma_slave.slave_id	= usbhs_get_dparam(priv, d0_rx_id); +	usbhsf_dma_init(priv, fifo);  	/* D1FIFO */  	fifo = usbhsf_get_d1fifo(priv); @@ -1180,10 +1175,13 @@ int usbhs_fifo_probe(struct usbhs_priv *priv)  	fifo->ctr	= D1FIFOCTR;  	fifo->tx_slave.shdma_slave.slave_id	= usbhs_get_dparam(priv, d1_tx_id);  	fifo->rx_slave.shdma_slave.slave_id	= usbhs_get_dparam(priv, d1_rx_id); +	usbhsf_dma_init(priv, fifo);  	return 0;  }  void usbhs_fifo_remove(struct usbhs_priv *priv)  { +	usbhsf_dma_quit(priv, usbhsf_get_d0fifo(priv)); +	usbhsf_dma_quit(priv, usbhsf_get_d1fifo(priv));  } diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 3385aeb5a36..458f3766bef 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -987,11 +987,11 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)  		/* init DCP */  		if (usbhsg_is_dcp(uep)) {  			gpriv->gadget.ep0 = &uep->ep; -			uep->ep.maxpacket = 64; +			usb_ep_set_maxpacket_limit(&uep->ep, 64);  		}  		/* init normal pipe */  		else { -			uep->ep.maxpacket = 512; +			usb_ep_set_maxpacket_limit(&uep->ep, 512);  			list_add_tail(&uep->ep.ep_list, &gpriv->gadget.ep_list);  		}  	} diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index e40f565004d..10e1ded9c9c 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -1469,6 +1469,7 @@ static int usbhsh_start(struct usbhs_priv *priv)  	ret = usb_add_hcd(hcd, 0, 0);  	if (ret < 0)  		return 0; +	device_wakeup_enable(hcd->self.controller);  	/*  	 * pipe initialize and enable DCP diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index c454bfa22a1..3ce5c74b29e 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -60,7 +60,7 @@ config USB_SERIAL_SIMPLE  		- Suunto ANT+ USB device.  		- Fundamental Software dongle.  		- HP4x calculators -		- a number of Motoroloa phones +		- a number of Motorola phones  		- Siemens USB/MPI adapter.  		- ViVOtech ViVOpay USB device.  		- Infineon Modem Flashloader USB interface @@ -472,6 +472,35 @@ config USB_SERIAL_MOS7840  	  To compile this driver as a module, choose M here: the  	  module will be called mos7840.  If unsure, choose N. +config USB_SERIAL_MXUPORT +	tristate "USB Moxa UPORT Serial Driver" +	---help--- +	  Say Y here if you want to use a MOXA UPort Serial hub. + +	  This driver supports: + +	  [2 Port] +	  - UPort 1250 :  2 Port RS-232/422/485 USB to Serial Hub +	  - UPort 1250I : 2 Port RS-232/422/485 USB to Serial Hub with +			  Isolation + +	  [4 Port] +	  - UPort 1410 :  4 Port RS-232 USB to Serial Hub +	  - UPort 1450 :  4 Port RS-232/422/485 USB to Serial Hub +	  - UPort 1450I : 4 Port RS-232/422/485 USB to Serial Hub with +			  Isolation + +	  [8 Port] +	  - UPort 1610-8 : 8 Port RS-232 USB to Serial Hub +	  - UPort 1650-8 : 8 Port RS-232/422/485 USB to Serial Hub + +	  [16 Port] +	  - UPort 1610-16 : 16 Port RS-232 USB to Serial Hub +	  - UPort 1650-16 : 16 Port RS-232/422/485 USB to Serial Hub + +	  To compile this driver as a module, choose M here: the +	  module will be called mxuport. +  config USB_SERIAL_NAVMAN  	tristate "USB Navman GPS device"  	help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 42670f0b5bc..bfdafd34944 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -37,6 +37,7 @@ obj-$(CONFIG_USB_SERIAL_MCT_U232)		+= mct_u232.o  obj-$(CONFIG_USB_SERIAL_METRO)			+= metro-usb.o  obj-$(CONFIG_USB_SERIAL_MOS7720)		+= mos7720.o  obj-$(CONFIG_USB_SERIAL_MOS7840)		+= mos7840.o +obj-$(CONFIG_USB_SERIAL_MXUPORT)		+= mxuport.o  obj-$(CONFIG_USB_SERIAL_NAVMAN)			+= navman.o  obj-$(CONFIG_USB_SERIAL_OMNINET)		+= omninet.o  obj-$(CONFIG_USB_SERIAL_OPTICON)		+= opticon.o diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 6e320cec397..80a9845cd93 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -10,9 +10,9 @@   *   * The device works as an standard CDC device, it has 2 interfaces, the first   * one is for firmware access and the second is the serial one. - * The protocol is very simply, there are two posibilities reading or writing. + * The protocol is very simply, there are two possibilities reading or writing.   * When writing the first urb must have a Header that starts with 0x20 0x29 the - * next two bytes must say how much data will be sended. + * next two bytes must say how much data will be sent.   * When reading the process is almost equal except that the header starts with   * 0x00 0x20.   * @@ -31,15 +31,15 @@   *   * The driver registers himself with the USB-serial core and the USB Core. I had   * to implement a probe function against USB-serial, because other way, the - * driver was attaching himself to both interfaces. I have tryed with different + * driver was attaching himself to both interfaces. I have tried with different   * configurations of usb_serial_driver with out exit, only the probe function   * could handle this correctly.   *   * I have taken some info from a Greg Kroah-Hartman article:   * http://www.linuxjournal.com/article/6573   * And from Linux Device Driver Kit CD, which is a great work, the authors taken - * the work to recompile lots of information an knowladge in drivers development - * and made it all avaible inside a cd. + * the work to recompile lots of information an knowledge in drivers development + * and made it all available inside a cd.   * URL: http://kernel.org/pub/linux/kernel/people/gregkh/ddk/   *   */ diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index bc77e955cbe..1532cde8a43 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -23,7 +23,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/ioctl.h>  #include <linux/tty.h>  #include <linux/slab.h> @@ -71,7 +70,7 @@ struct ark3116_private {  	__u32			lcr;	/* line control register value */  	__u32			hcr;	/* handshake control register (0x8)  					 * value */ -	__u32			mcr;	/* modem contol register value */ +	__u32			mcr;	/* modem control register value */  	/* protects the status values below */  	spinlock_t		status_lock; @@ -609,7 +608,7 @@ static void ark3116_read_int_callback(struct urb *urb)  } -/* Data comes in via the bulk (data) URB, erors/interrupts via the int URB. +/* Data comes in via the bulk (data) URB, errors/interrupts via the int URB.   * This means that we cannot be sure which data byte has an associated error   * condition, so we report an error for all data in the next bulk read.   * diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 84217e78ded..15bc71853db 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -18,14 +18,13 @@   * driver   *   * TODO: - * -- Add true modem contol line query capability.  Currently we track the + * -- Add true modem control line query capability.  Currently we track the   *    states reported by the interrupt and the states we request.   * -- Add support for flush commands   */  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index 6335490d576..9374bd2aba2 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -97,13 +97,19 @@ static int usb_serial_device_remove(struct device *dev)  	struct usb_serial_port *port;  	int retval = 0;  	int minor; +	int autopm_err;  	port = to_usb_serial_port(dev);  	if (!port)  		return -ENODEV; -	/* make sure suspend/resume doesn't race against port_remove */ -	usb_autopm_get_interface(port->serial->interface); +	/* +	 * Make sure suspend/resume doesn't race against port_remove. +	 * +	 * Note that no further runtime PM callbacks will be made if +	 * autopm_get fails. +	 */ +	autopm_err = usb_autopm_get_interface(port->serial->interface);  	minor = port->minor;  	tty_unregister_device(usb_serial_tty_driver, minor); @@ -117,7 +123,9 @@ static int usb_serial_device_remove(struct device *dev)  	dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",  		 driver->description, minor); -	usb_autopm_put_interface(port->serial->interface); +	if (!autopm_err) +		usb_autopm_put_interface(port->serial->interface); +  	return retval;  } @@ -125,10 +133,12 @@ static ssize_t new_id_store(struct device_driver *driver,  			    const char *buf, size_t count)  {  	struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver); -	ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count); +	ssize_t retval = usb_store_new_id(&usb_drv->dynids, usb_drv->id_table, +					 driver, buf, count);  	if (retval >= 0 && usb_drv->usb_driver != NULL)  		retval = usb_store_new_id(&usb_drv->usb_driver->dynids, +					  usb_drv->usb_driver->id_table,  					  &usb_drv->usb_driver->drvwrap.driver,  					  buf, count);  	return retval; diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index c2a4171ab9c..2d72aa3564a 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -16,7 +16,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/tty.h>  #include <linux/module.h>  #include <linux/slab.h> @@ -83,7 +82,6 @@ struct ch341_private {  	unsigned baud_rate; /* set baud rate */  	u8 line_control; /* set line control value RTS/DTR */  	u8 line_status; /* active status of modem control inputs */ -	u8 multi_status_change; /* status changed multiple since last call */  };  static int ch341_control_out(struct usb_device *dev, u8 request, @@ -174,7 +172,6 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv)  		r = 0;  		spin_lock_irqsave(&priv->lock, flags);  		priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT; -		priv->multi_status_change = 0;  		spin_unlock_irqrestore(&priv->lock, flags);  	} else  		r = -EPROTO; @@ -326,11 +323,11 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)  	if (r)  		goto out; -	dev_dbg(&port->dev, "%s - submitting interrupt urb", __func__); +	dev_dbg(&port->dev, "%s - submitting interrupt urb\n", __func__);  	r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);  	if (r) { -		dev_err(&port->dev, "%s - failed submitting interrupt urb," -			" error %d\n", __func__, r); +		dev_err(&port->dev, "%s - failed to submit interrupt urb: %d\n", +			__func__, r);  		ch341_close(port);  		goto out;  	} @@ -384,10 +381,8 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)  	uint8_t *break_reg;  	break_reg = kmalloc(2, GFP_KERNEL); -	if (!break_reg) { -		dev_err(&port->dev, "%s - kmalloc failed\n", __func__); +	if (!break_reg)  		return; -	}  	r = ch341_control_in(port->serial->dev, CH341_REQ_READ_REG,  			ch341_break_reg, 0, break_reg, 2); @@ -442,11 +437,55 @@ static int ch341_tiocmset(struct tty_struct *tty,  	return ch341_set_handshake(port->serial->dev, control);  } +static void ch341_update_line_status(struct usb_serial_port *port, +					unsigned char *data, size_t len) +{ +	struct ch341_private *priv = usb_get_serial_port_data(port); +	struct tty_struct *tty; +	unsigned long flags; +	u8 status; +	u8 delta; + +	if (len < 4) +		return; + +	status = ~data[2] & CH341_BITS_MODEM_STAT; + +	spin_lock_irqsave(&priv->lock, flags); +	delta = status ^ priv->line_status; +	priv->line_status = status; +	spin_unlock_irqrestore(&priv->lock, flags); + +	if (data[1] & CH341_MULT_STAT) +		dev_dbg(&port->dev, "%s - multiple status change\n", __func__); + +	if (!delta) +		return; + +	if (delta & CH341_BIT_CTS) +		port->icount.cts++; +	if (delta & CH341_BIT_DSR) +		port->icount.dsr++; +	if (delta & CH341_BIT_RI) +		port->icount.rng++; +	if (delta & CH341_BIT_DCD) { +		port->icount.dcd++; +		tty = tty_port_tty_get(&port->port); +		if (tty) { +			usb_serial_handle_dcd_change(port, tty, +						status & CH341_BIT_DCD); +			tty_kref_put(tty); +		} +	} + +	wake_up_interruptible(&port->port.delta_msr_wait); +} +  static void ch341_read_int_callback(struct urb *urb)  { -	struct usb_serial_port *port = (struct usb_serial_port *) urb->context; +	struct usb_serial_port *port = urb->context;  	unsigned char *data = urb->transfer_buffer; -	unsigned int actual_length = urb->actual_length; +	unsigned int len = urb->actual_length;  	int status;  	switch (urb->status) { @@ -457,89 +496,23 @@ static void ch341_read_int_callback(struct urb *urb)  	case -ENOENT:  	case -ESHUTDOWN:  		/* this urb is terminated, clean up */ -		dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", +		dev_dbg(&urb->dev->dev, "%s - urb shutting down: %d\n",  			__func__, urb->status);  		return;  	default: -		dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", +		dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n",  			__func__, urb->status);  		goto exit;  	} -	usb_serial_debug_data(&port->dev, __func__, -			      urb->actual_length, urb->transfer_buffer); - -	if (actual_length >= 4) { -		struct ch341_private *priv = usb_get_serial_port_data(port); -		unsigned long flags; -		u8 prev_line_status = priv->line_status; - -		spin_lock_irqsave(&priv->lock, flags); -		priv->line_status = (~(data[2])) & CH341_BITS_MODEM_STAT; -		if ((data[1] & CH341_MULT_STAT)) -			priv->multi_status_change = 1; -		spin_unlock_irqrestore(&priv->lock, flags); - -		if ((priv->line_status ^ prev_line_status) & CH341_BIT_DCD) { -			struct tty_struct *tty = tty_port_tty_get(&port->port); -			if (tty) -				usb_serial_handle_dcd_change(port, tty, -					    priv->line_status & CH341_BIT_DCD); -			tty_kref_put(tty); -		} - -		wake_up_interruptible(&port->port.delta_msr_wait); -	} - +	usb_serial_debug_data(&port->dev, __func__, len, data); +	ch341_update_line_status(port, data, len);  exit:  	status = usb_submit_urb(urb, GFP_ATOMIC); -	if (status) -		dev_err(&urb->dev->dev, -			"%s - usb_submit_urb failed with result %d\n", +	if (status) { +		dev_err(&urb->dev->dev, "%s - usb_submit_urb failed: %d\n",  			__func__, status); -} - -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; -	u8 status; -	u8 changed; -	u8 multi_change = 0; - -	spin_lock_irqsave(&priv->lock, flags); -	prevstatus = priv->line_status; -	priv->multi_status_change = 0; -	spin_unlock_irqrestore(&priv->lock, flags); - -	while (!multi_change) { -		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; -		spin_unlock_irqrestore(&priv->lock, flags); - -		changed = prevstatus ^ status; - -		if (((arg & TIOCM_RNG) && (changed & CH341_BIT_RI)) || -		    ((arg & TIOCM_DSR) && (changed & CH341_BIT_DSR)) || -		    ((arg & TIOCM_CD)  && (changed & CH341_BIT_DCD)) || -		    ((arg & TIOCM_CTS) && (changed & CH341_BIT_CTS))) { -			return 0; -		} -		prevstatus = status;  	} - -	return 0;  }  static int ch341_tiocmget(struct tty_struct *tty) @@ -595,7 +568,7 @@ static struct usb_serial_driver ch341_device = {  	.break_ctl         = ch341_break_ctl,  	.tiocmget          = ch341_tiocmget,  	.tiocmset          = ch341_tiocmset, -	.tiocmiwait        = ch341_tiocmiwait, +	.tiocmiwait        = usb_serial_generic_tiocmiwait,  	.read_int_callback = ch341_read_int_callback,  	.port_probe        = ch341_port_probe,  	.port_remove       = ch341_port_remove, diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index c69bb50d466..8d7fc48b1f3 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -14,7 +14,6 @@  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/console.h> @@ -135,7 +134,6 @@ static int usb_console_setup(struct console *co, char *options)  			tty = kzalloc(sizeof(*tty), GFP_KERNEL);  			if (!tty) {  				retval = -ENOMEM; -				dev_err(&port->dev, "no more memory\n");  				goto reset_open_count;  			}  			kref_init(&tty->kref); @@ -144,7 +142,6 @@ static int usb_console_setup(struct console *co, char *options)  			tty->index = co->index;  			if (tty_init_termios(tty)) {  				retval = -ENOMEM; -				dev_err(&port->dev, "no more memory\n");  				goto free_tty;  			}  		} diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 6987b535aa9..330df5ce435 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -104,6 +104,7 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */  	{ USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */  	{ USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ +	{ USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */  	{ USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */  	{ USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */  	{ USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ @@ -152,6 +153,7 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(0x1843, 0x0200) }, /* Vaisala USB Instrument Cable */  	{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */  	{ USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ +	{ USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */  	{ USB_DEVICE(0x1BE3, 0x07A6) }, /* WAGO 750-923 USB Service Cable */  	{ USB_DEVICE(0x1E29, 0x0102) }, /* Festo CPX-USB */  	{ USB_DEVICE(0x1E29, 0x0501) }, /* Festo CMSP */ @@ -305,10 +307,8 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,  	length = (((size - 1) | 3) + 1) / 4;  	buf = kcalloc(length, sizeof(__le32), GFP_KERNEL); -	if (!buf) { -		dev_err(&port->dev, "%s - out of memory.\n", __func__); +	if (!buf)  		return -ENOMEM; -	}  	/* Issue the request, attempting to read 'size' bytes */  	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), @@ -352,10 +352,8 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,  	length = (((size - 1) | 3) + 1) / 4;  	buf = kmalloc(length * sizeof(__le32), GFP_KERNEL); -	if (!buf) { -		dev_err(&port->dev, "%s - out of memory.\n", __func__); +	if (!buf)  		return -ENOMEM; -	}  	/* Array of integers into bytes */  	for (i = 0; i < length; i++) diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 781426230d6..2916dea3ede 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -30,7 +30,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -221,7 +220,7 @@ static int cyberjack_write(struct tty_struct *tty,  		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);  		if (result) {  			dev_err(&port->dev, -				"%s - failed submitting write urb, error %d", +				"%s - failed submitting write urb, error %d\n",  				__func__, result);  			/* Throw away data. No better idea what to do with it. */  			priv->wrfilled = 0; @@ -279,13 +278,13 @@ static void cyberjack_read_int_callback(struct urb *urb)  		old_rdtodo = priv->rdtodo; -		if (old_rdtodo + size < old_rdtodo) { +		if (old_rdtodo > SHRT_MAX - size) {  			dev_dbg(dev, "To many bulk_in urbs to do.\n");  			spin_unlock(&priv->lock);  			goto resubmit;  		} -		/* "+=" is probably more fault tollerant than "=" */ +		/* "+=" is probably more fault tolerant than "=" */  		priv->rdtodo += size;  		dev_dbg(dev, "%s - rdtodo: %d\n", __func__, priv->rdtodo); diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index 558605d646f..01bf5339281 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -27,7 +27,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -113,7 +112,7 @@ struct cypress_private {  	int baud_rate;			   /* stores current baud rate in  					      integer form */  	int isthrottled;		   /* if throttled, discard reads */ -	char prev_status, diff_status;	   /* used for TIOCMIWAIT */ +	char prev_status;		   /* used for TIOCMIWAIT */  	/* we pass a pointer to this as the argument sent to  	   cypress_set_termios old_termios */  	struct ktermios tmp_termios; 	   /* stores the old termios settings */ @@ -136,7 +135,6 @@ static void cypress_set_termios(struct tty_struct *tty,  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); @@ -162,7 +160,7 @@ static struct usb_serial_driver cypress_earthmate_device = {  	.set_termios =			cypress_set_termios,  	.tiocmget =			cypress_tiocmget,  	.tiocmset =			cypress_tiocmset, -	.tiocmiwait =			cypress_tiocmiwait, +	.tiocmiwait =			usb_serial_generic_tiocmiwait,  	.chars_in_buffer =		cypress_chars_in_buffer,  	.throttle =		 	cypress_throttle,  	.unthrottle =			cypress_unthrottle, @@ -188,7 +186,7 @@ static struct usb_serial_driver cypress_hidcom_device = {  	.set_termios =			cypress_set_termios,  	.tiocmget =			cypress_tiocmget,  	.tiocmset =			cypress_tiocmset, -	.tiocmiwait =			cypress_tiocmiwait, +	.tiocmiwait =			usb_serial_generic_tiocmiwait,  	.chars_in_buffer =		cypress_chars_in_buffer,  	.throttle =			cypress_throttle,  	.unthrottle =			cypress_unthrottle, @@ -214,7 +212,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {  	.set_termios =			cypress_set_termios,  	.tiocmget =			cypress_tiocmget,  	.tiocmset =			cypress_tiocmset, -	.tiocmiwait =			cypress_tiocmiwait, +	.tiocmiwait =			usb_serial_generic_tiocmiwait,  	.chars_in_buffer =		cypress_chars_in_buffer,  	.throttle =			cypress_throttle,  	.unthrottle =			cypress_unthrottle, @@ -281,7 +279,7 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)  			 * the generic firmware, but are not used with  			 * NMEA and SiRF protocols */  			dev_dbg(&port->dev, -				"%s - failed setting baud rate, unsupported speed of %d on Earthmate GPS", +				"%s - failed setting baud rate, unsupported speed of %d on Earthmate GPS\n",  				__func__, new_rate);  			return -1;  		} @@ -864,45 +862,6 @@ static int cypress_tiocmset(struct tty_struct *tty,  	return cypress_write(tty, port, NULL, 0);  } - -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; - -	for (;;) { -		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; - -		diff = priv->diff_status; -		if (diff == 0) -			return -EIO; /* no change => error */ - -		/* 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. -		 */ -	} - -	return 0; -} -  static void cypress_set_termios(struct tty_struct *tty,  	struct usb_serial_port *port, struct ktermios *old_termios)  { @@ -1185,9 +1144,21 @@ static void cypress_read_int_callback(struct urb *urb)  	spin_lock_irqsave(&priv->lock, flags);  	/* check to see if status has changed */  	if (priv->current_status != priv->prev_status) { -		priv->diff_status |= priv->current_status ^ -			priv->prev_status; -		wake_up_interruptible(&port->port.delta_msr_wait); +		u8 delta = priv->current_status ^ priv->prev_status; + +		if (delta & UART_MSR_MASK) { +			if (delta & UART_CTS) +				port->icount.cts++; +			if (delta & UART_DSR) +				port->icount.dsr++; +			if (delta & UART_RI) +				port->icount.rng++; +			if (delta & UART_CD) +				port->icount.dcd++; + +			wake_up_interruptible(&port->port.delta_msr_wait); +		} +  		priv->prev_status = priv->current_status;  	}  	spin_unlock_irqrestore(&priv->lock, flags); @@ -1253,7 +1224,6 @@ static void cypress_write_int_callback(struct urb *urb)  	struct usb_serial_port *port = urb->context;  	struct cypress_private *priv = usb_get_serial_port_data(port);  	struct device *dev = &urb->dev->dev; -	int result;  	int status = urb->status;  	switch (status) { @@ -1268,21 +1238,9 @@ static void cypress_write_int_callback(struct urb *urb)  			__func__, status);  		priv->write_urb_in_use = 0;  		return; -	case -EPIPE: /* no break needed; clear halt and resubmit */ -		if (!priv->comm_is_ok) -			break; -		usb_clear_halt(port->serial->dev, 0x02); -		/* error in the urb, so we have to resubmit it */ -		dev_dbg(dev, "%s - nonzero write bulk status received: %d\n", -			__func__, status); -		port->interrupt_out_urb->transfer_buffer_length = 1; -		result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); -		if (!result) -			return; -		dev_err(dev, "%s - failed resubmitting write urb, error %d\n", -			__func__, result); -		cypress_set_dead(port); -		break; +	case -EPIPE: +		/* Cannot call usb_clear_halt while in_interrupt */ +		/* FALLTHROUGH */  	default:  		dev_err(dev, "%s - unexpected nonzero write status received: %d\n",  			__func__, status); diff --git a/drivers/usb/serial/cypress_m8.h b/drivers/usb/serial/cypress_m8.h index b461311a2ae..119d2e17077 100644 --- a/drivers/usb/serial/cypress_m8.h +++ b/drivers/usb/serial/cypress_m8.h @@ -55,19 +55,23 @@  #define CT_GENERIC	0x0F  /* End of chiptype definitions */ -/* RS-232 serial data communication protocol definitions */ -/* these are sent / read at byte 0 of the input/output hid reports */ -/* You can find these values defined in the CY4601 USB to Serial design notes */ - -#define CONTROL_DTR	0x20	/* data terminal ready - flow control - host to device */ -#define UART_DSR	0x20	/* data set ready - flow control - device to host */ -#define CONTROL_RTS	0x10	/* request to send - flow control - host to device */ -#define UART_CTS	0x10	/* clear to send - flow control - device to host */ -#define UART_RI		0x10	/* ring indicator - modem - device to host */ -#define UART_CD		0x40	/* carrier detect - modem - device to host */ -#define CYP_ERROR	0x08	/* received from input report - device to host */ -/* Note - the below has nothing to do with the "feature report" reset */ -#define CONTROL_RESET	0x08	/* sent with output report - host to device */ +/* + * RS-232 serial data communication protocol definitions. + * + * These are sent / read at byte 0 of the input/output hid reports. + * You can find these values defined in the CY4601 USB to Serial design notes. + */ + +#define CONTROL_DTR	0x20	/* data terminal ready */ +#define CONTROL_RTS	0x10	/* request to send */ +#define CONTROL_RESET	0x08	/* sent with output report */ + +#define UART_MSR_MASK	0xf0 +#define UART_RI		0x80	/* ring indicator */ +#define UART_CD		0x40	/* carrier detect */ +#define UART_DSR	0x20	/* data set ready */ +#define UART_CTS	0x10	/* clear to send */ +#define CYP_ERROR	0x08	/* received from input report */  /* End of RS-232 protocol definitions */ diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 19b467fe038..8a23c53b946 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -17,7 +17,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 0f658618db1..90e603d5f66 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -17,7 +17,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 639a18fb67e..c5dc233db2d 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -12,7 +12,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -55,6 +54,13 @@ static void f81232_update_line_status(struct usb_serial_port *port,  				      unsigned char *data,  				      unsigned int actual_length)  { +	/* +	 * FIXME: Update port->icount, and call +	 * +	 *		wake_up_interruptible(&port->port.delta_msr_wait); +	 * +	 *	  on MSR changes. +	 */  }  static void f81232_read_int_callback(struct urb *urb) @@ -110,7 +116,6 @@ 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(&port->port.delta_msr_wait);  	if (!urb->actual_length)  		return; @@ -241,54 +246,12 @@ static int f81232_carrier_raised(struct usb_serial_port *port)  	return 0;  } -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; -	unsigned int status; -	unsigned int changed; - -	spin_lock_irqsave(&priv->lock, flags); -	prevstatus = priv->line_status; -	spin_unlock_irqrestore(&priv->lock, flags); - -	while (1) { -		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); - -		changed = prevstatus ^ status; - -		if (((arg & TIOCM_RNG) && (changed & UART_RING)) || -		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) || -		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) || -		    ((arg & TIOCM_CTS) && (changed & UART_CTS))) { -			return 0; -		} -		prevstatus = status; -	} -	/* NOTREACHED */ -	return 0; -} -  static int f81232_ioctl(struct tty_struct *tty,  			unsigned int cmd, unsigned long arg)  {  	struct serial_struct ser;  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(&port->dev, "%s cmd = 0x%04x\n", __func__, cmd); -  	switch (cmd) {  	case TIOCGSERIAL:  		memset(&ser, 0, sizeof ser); @@ -302,8 +265,6 @@ static int f81232_ioctl(struct tty_struct *tty,  		return 0;  	default: -		dev_dbg(&port->dev, "%s not supported = 0x%04x\n", -			__func__, cmd);  		break;  	}  	return -ENOIOCTLCMD; @@ -354,7 +315,7 @@ static struct usb_serial_driver f81232_device = {  	.set_termios =		f81232_set_termios,  	.tiocmget =		f81232_tiocmget,  	.tiocmset =		f81232_tiocmset, -	.tiocmiwait =		f81232_tiocmiwait, +	.tiocmiwait =		usb_serial_generic_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 c45f9c0a1b3..8a3813be1b2 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -33,7 +33,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -145,7 +144,7 @@ static struct ftdi_sio_quirk ftdi_8u2232c_quirk = {   * Device ID not listed? Test it using   * /sys/bus/usb-serial/drivers/ftdi_sio/new_id and send a patch or report.   */ -static struct usb_device_id id_table_combined [] = { +static const struct usb_device_id id_table_combined[] = {  	{ USB_DEVICE(FTDI_VID, FTDI_ZEITCONTROL_TAGTRACE_MIFARE_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_CTI_MINI_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_CTI_NANO_PID) }, @@ -153,6 +152,7 @@ static struct usb_device_id id_table_combined [] = {  	{ USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) }, +	{ USB_DEVICE(FTDI_VID, FTDI_EV3CON_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) }, @@ -192,6 +192,8 @@ static struct usb_device_id id_table_combined [] = {  	{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },  	{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, +	{ USB_DEVICE(FTDI_VID, FTDI_TAGSYS_LP101_PID) }, +	{ USB_DEVICE(FTDI_VID, FTDI_TAGSYS_P200X_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, @@ -578,6 +580,8 @@ static struct usb_device_id id_table_combined [] = {  	{ USB_DEVICE(FTDI_VID, FTDI_TAVIR_STK500_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_TIAO_UMPA_PID),  		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, +	{ USB_DEVICE(FTDI_VID, FTDI_NT_ORIONLXM_PID), +		.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },  	/*  	 * ELV devices:  	 */ @@ -716,7 +720,8 @@ static struct usb_device_id id_table_combined [] = {  	{ USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) }, -	{ USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) }, +	{ USB_DEVICE(TESTO_VID, TESTO_1_PID) }, +	{ USB_DEVICE(TESTO_VID, TESTO_3_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) },  	{ USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) }, @@ -904,6 +909,44 @@ static struct usb_device_id id_table_combined [] = {  	{ USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },  	/* Crucible Devices */  	{ USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) }, +	{ USB_DEVICE(FTDI_VID, FTDI_Z3X_PID) }, +	/* Cressi Devices */ +	{ USB_DEVICE(FTDI_VID, FTDI_CRESSI_PID) }, +	/* Brainboxes Devices */ +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_001_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_012_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_023_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_034_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_101_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_1_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_2_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_3_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_4_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_5_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_6_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_7_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_8_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_257_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_1_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_2_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_3_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_4_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_313_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_324_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_1_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_2_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_357_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_1_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_2_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_3_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_701_1_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_701_2_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_1_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_2_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_3_PID) }, +	{ USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_4_PID) }, +	/* Infineon Devices */ +	{ USB_DEVICE_INTERFACE_NUMBER(INFINEON_VID, INFINEON_TRIBOARD_PID, 1) },  	{ }					/* Terminating entry */  }; @@ -1526,14 +1569,17 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port)  	struct usb_device *udev = serial->dev;  	struct usb_interface *interface = serial->interface; -	struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc; +	struct usb_endpoint_descriptor *ep_desc;  	unsigned num_endpoints; -	int i; +	unsigned i;  	num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;  	dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints); +	if (!num_endpoints) +		return; +  	/* NOTE: some customers have programmed FT232R/FT245R devices  	 * with an endpoint size of 0 - not good.  In this case, we  	 * want to override the endpoint descriptor setting and use a @@ -1694,11 +1740,8 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)  	priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); -	if (!priv) { -		dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__, -					sizeof(struct ftdi_private)); +	if (!priv)  		return -ENOMEM; -	}  	mutex_init(&priv->cfg_lock); @@ -1966,8 +2009,16 @@ static int ftdi_process_packet(struct usb_serial_port *port,  			port->icount.dsr++;  		if (diff_status & FTDI_RS0_RI)  			port->icount.rng++; -		if (diff_status & FTDI_RS0_RLSD) +		if (diff_status & FTDI_RS0_RLSD) { +			struct tty_struct *tty; +  			port->icount.dcd++; +			tty = tty_port_tty_get(&port->port); +			if (tty) +				usb_serial_handle_dcd_change(port, tty, +						status & FTDI_RS0_RLSD); +			tty_kref_put(tty); +		}  		wake_up_interruptible(&port->port.delta_msr_wait);  		priv->prev_status = status; @@ -2114,6 +2165,30 @@ static void ftdi_set_termios(struct tty_struct *tty,  		termios->c_cflag |= CRTSCTS;  	} +	/* +	 * All FTDI UART chips are limited to CS7/8. We shouldn't pretend to +	 * support CS5/6 and revert the CSIZE setting instead. +	 * +	 * CS5 however is used to control some smartcard readers which abuse +	 * this limitation to switch modes. Original FTDI chips fall back to +	 * eight data bits. +	 * +	 * TODO: Implement a quirk to only allow this with mentioned +	 *       readers. One I know of (Argolis Smartreader V1) +	 *       returns "USB smartcard server" as iInterface string. +	 *       The vendor didn't bother with a custom VID/PID of +	 *       course. +	 */ +	if (C_CSIZE(tty) == CS6) { +		dev_warn(ddev, "requested CSIZE setting not supported\n"); + +		termios->c_cflag &= ~CSIZE; +		if (old_termios) +			termios->c_cflag |= old_termios->c_cflag & CSIZE; +		else +			termios->c_cflag |= CS8; +	} +  	cflag = termios->c_cflag;  	if (!old_termios) @@ -2150,19 +2225,19 @@ no_skip:  	} else {  		urb_value |= FTDI_SIO_SET_DATA_PARITY_NONE;  	} -	if (cflag & CSIZE) { -		switch (cflag & CSIZE) { -		case CS7: -			urb_value |= 7; -			dev_dbg(ddev, "Setting CS7\n"); -			break; -		case CS8: -			urb_value |= 8; -			dev_dbg(ddev, "Setting CS8\n"); -			break; -		default: -			dev_err(ddev, "CSIZE was set but not CS7-CS8\n"); -		} +	switch (cflag & CSIZE) { +	case CS5: +		dev_dbg(ddev, "Setting CS5 quirk\n"); +		break; +	case CS7: +		urb_value |= 7; +		dev_dbg(ddev, "Setting CS7\n"); +		break; +	default: +	case CS8: +		urb_value |= 8; +		dev_dbg(ddev, "Setting CS8\n"); +		break;  	}  	/* This is needed by the break command since it uses the same command @@ -2363,8 +2438,6 @@ static int ftdi_ioctl(struct tty_struct *tty,  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd); -  	/* Based on code from acm.c and others */  	switch (cmd) { @@ -2381,11 +2454,7 @@ static int ftdi_ioctl(struct tty_struct *tty,  	default:  		break;  	} -	/* This is not necessarily an error - turns out the higher layers -	 * will do some ioctls themselves (see comment above) -	 */ -	dev_dbg(&port->dev, "%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h\n", -		__func__, cmd); +  	return -ENOIOCTLCMD;  } diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 1b8af461b52..c4777bc6aee 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -50,6 +50,7 @@  #define TI_XDS100V2_PID		0xa6d0  #define FTDI_NXTCAM_PID		0xABB8 /* NXTCam for Mindstorms NXT */ +#define FTDI_EV3CON_PID		0xABB9 /* Mindstorms EV3 Console Adapter */  /* US Interface Navigator (http://www.usinterface.com/) */  #define FTDI_USINT_CAT_PID	0xb810	/* Navigator CAT and 2nd PTT lines */ @@ -363,6 +364,12 @@  /* Sprog II (Andrew Crosland's SprogII DCC interface) */  #define FTDI_SPROG_II		0xF0C8 +/* + * Two of the Tagsys RFID Readers + */ +#define FTDI_TAGSYS_LP101_PID	0xF0E9	/* Tagsys L-P101 RFID*/ +#define FTDI_TAGSYS_P200X_PID	0xF0EE	/* Tagsys Medio P200x RFID*/ +  /* an infrared receiver for user access control with IR tags */  #define FTDI_PIEGROUP_PID	0xF208	/* Product Id */ @@ -531,6 +538,11 @@   */  #define FTDI_TIAO_UMPA_PID	0x8a98	/* TIAO/DIYGADGET USB Multi-Protocol Adapter */ +/* + * NovaTech product ids (FTDI_VID) + */ +#define FTDI_NT_ORIONLXM_PID	0x7c90	/* OrionLXm Substation Automation Platform */ +  /********************************/  /** third-party VID/PID combos **/ @@ -572,6 +584,12 @@  #define RATOC_PRODUCT_ID_USB60F	0xb020  /* + * Infineon Technologies + */ +#define INFINEON_VID		0x058b +#define INFINEON_TRIBOARD_PID	0x0028 /* DAS JTAG TriBoard TC1798 V1.0 */ + +/*   * Acton Research Corp.   */  #define ACTON_VID		0x0647	/* Vendor ID */ @@ -786,7 +804,8 @@   * Submitted by Colin Leroy   */  #define TESTO_VID			0x128D -#define TESTO_USB_INTERFACE_PID		0x0001 +#define TESTO_1_PID			0x0001 +#define TESTO_3_PID			0x0003  /*   * Mobility Electronics products. @@ -1307,3 +1326,52 @@   * Manufacturer: Crucible Technologies   */  #define FTDI_CT_COMET_PID	0x8e08 + +/* + * Product: Z3X Box + * Manufacturer: Smart GSM Team + */ +#define FTDI_Z3X_PID		0x0011 + +/* + * Product: Cressi PC Interface + * Manufacturer: Cressi + */ +#define FTDI_CRESSI_PID		0x87d0 + +/* + * Brainboxes devices + */ +#define BRAINBOXES_VID			0x05d1 +#define BRAINBOXES_VX_001_PID		0x1001 /* VX-001 ExpressCard 1 Port RS232 */ +#define BRAINBOXES_VX_012_PID		0x1002 /* VX-012 ExpressCard 2 Port RS232 */ +#define BRAINBOXES_VX_023_PID		0x1003 /* VX-023 ExpressCard 1 Port RS422/485 */ +#define BRAINBOXES_VX_034_PID		0x1004 /* VX-034 ExpressCard 2 Port RS422/485 */ +#define BRAINBOXES_US_101_PID		0x1011 /* US-101 1xRS232 */ +#define BRAINBOXES_US_324_PID		0x1013 /* US-324 1xRS422/485 1Mbaud */ +#define BRAINBOXES_US_606_1_PID		0x2001 /* US-606 6 Port RS232 Serial Port 1 and 2 */ +#define BRAINBOXES_US_606_2_PID		0x2002 /* US-606 6 Port RS232 Serial Port 3 and 4 */ +#define BRAINBOXES_US_606_3_PID		0x2003 /* US-606 6 Port RS232 Serial Port 4 and 6 */ +#define BRAINBOXES_US_701_1_PID		0x2011 /* US-701 4xRS232 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_701_2_PID		0x2012 /* US-701 4xRS422 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_279_1_PID		0x2021 /* US-279 8xRS422 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_279_2_PID		0x2022 /* US-279 8xRS422 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_279_3_PID		0x2023 /* US-279 8xRS422 1Mbaud Port 5 and 6 */ +#define BRAINBOXES_US_279_4_PID		0x2024 /* US-279 8xRS422 1Mbaud Port 7 and 8 */ +#define BRAINBOXES_US_346_1_PID		0x3011 /* US-346 4xRS422/485 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_346_2_PID		0x3012 /* US-346 4xRS422/485 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_257_PID		0x5001 /* US-257 2xRS232 1Mbaud */ +#define BRAINBOXES_US_313_PID		0x6001 /* US-313 2xRS422/485 1Mbaud */ +#define BRAINBOXES_US_357_PID		0x7001 /* US_357 1xRS232/422/485 */ +#define BRAINBOXES_US_842_1_PID		0x8001 /* US-842 8xRS422/485 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_842_2_PID		0x8002 /* US-842 8xRS422/485 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_842_3_PID		0x8003 /* US-842 8xRS422/485 1Mbaud Port 5 and 6 */ +#define BRAINBOXES_US_842_4_PID		0x8004 /* US-842 8xRS422/485 1Mbaud Port 7 and 8 */ +#define BRAINBOXES_US_160_1_PID		0x9001 /* US-160 16xRS232 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_160_2_PID		0x9002 /* US-160 16xRS232 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_160_3_PID		0x9003 /* US-160 16xRS232 1Mbaud Port 5 and 6 */ +#define BRAINBOXES_US_160_4_PID		0x9004 /* US-160 16xRS232 1Mbaud Port 7 and 8 */ +#define BRAINBOXES_US_160_5_PID		0x9005 /* US-160 16xRS232 1Mbaud Port 9 and 10 */ +#define BRAINBOXES_US_160_6_PID		0x9006 /* US-160 16xRS232 1Mbaud Port 11 and 12 */ +#define BRAINBOXES_US_160_7_PID		0x9007 /* US-160 16xRS232 1Mbaud Port 13 and 14 */ +#define BRAINBOXES_US_160_8_PID		0x9008 /* US-160 16xRS232 1Mbaud Port 15 and 16 */ diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 04b5ed90ffb..db591d19d41 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -25,7 +25,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/timer.h>  #include <linux/tty.h> @@ -275,14 +274,13 @@ static int pkt_add(struct garmin_data *garmin_data_p,  	unsigned long flags;  	struct garmin_packet *pkt; -	/* process only packets containg data ... */ +	/* process only packets containing data ... */  	if (data_length) {  		pkt = kmalloc(sizeof(struct garmin_packet)+data_length,  								GFP_ATOMIC); -		if (pkt == NULL) { -			dev_err(&garmin_data_p->port->dev, "out of memory\n"); +		if (!pkt)  			return 0; -		} +  		pkt->size = data_length;  		memcpy(pkt->data, data, data_length); @@ -1006,14 +1004,11 @@ static int garmin_write_bulk(struct usb_serial_port *port,  	spin_unlock_irqrestore(&garmin_data_p->lock, flags);  	buffer = kmalloc(count, GFP_ATOMIC); -	if (!buffer) { -		dev_err(&port->dev, "out of memory\n"); +	if (!buffer)  		return -ENOMEM; -	}  	urb = usb_alloc_urb(0, GFP_ATOMIC);  	if (!urb) { -		dev_err(&port->dev, "no more free urbs\n");  		kfree(buffer);  		return -ENOMEM;  	} @@ -1148,7 +1143,7 @@ static void garmin_read_process(struct garmin_data *garmin_data_p,  	unsigned long flags;  	if (garmin_data_p->flags & FLAGS_DROP_DATA) { -		/* abort-transfer cmd is actice */ +		/* abort-transfer cmd is active */  		dev_dbg(&garmin_data_p->port->dev, "%s - pkt dropped\n", __func__);  	} else if (garmin_data_p->state != STATE_DISCONNECTED &&  		garmin_data_p->state != STATE_RESET) { @@ -1393,10 +1388,9 @@ static int garmin_port_probe(struct usb_serial_port *port)  	struct garmin_data *garmin_data_p;  	garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL); -	if (garmin_data_p == NULL) { -		dev_err(&port->dev, "%s - Out of memory\n", __func__); +	if (!garmin_data_p)  		return -ENOMEM; -	} +  	init_timer(&garmin_data_p->timer);  	spin_lock_init(&garmin_data_p->lock);  	INIT_LIST_HEAD(&garmin_data_p->pktlist); diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 1f31e6b4c25..1bd192290b0 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -7,7 +7,6 @@   *	This program is free software; you can redistribute it and/or   *	modify it under the terms of the GNU General Public License version   *	2 as published by the Free Software Foundation. - *   */  #include <linux/kernel.h> @@ -37,7 +36,6 @@ MODULE_PARM_DESC(product, "User specified USB idProduct");  static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */ -/* All of the device info needed for the Generic Serial Converter */  struct usb_serial_driver usb_serial_generic_device = {  	.driver = {  		.owner =	THIS_MODULE, @@ -66,7 +64,6 @@ int usb_serial_generic_register(void)  	generic_device_ids[0].match_flags =  		USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; -	/* register our generic driver with ourselves */  	retval = usb_serial_register_drivers(serial_drivers,  			"usbserial_generic", generic_device_ids);  #endif @@ -76,7 +73,6 @@ int usb_serial_generic_register(void)  void usb_serial_generic_deregister(void)  {  #ifdef CONFIG_USB_SERIAL_GENERIC -	/* remove our generic driver */  	usb_serial_deregister_drivers(serial_drivers);  #endif  } @@ -86,13 +82,11 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port  	int result = 0;  	unsigned long flags; -	/* clear the throttle flags */  	spin_lock_irqsave(&port->lock, flags);  	port->throttled = 0;  	port->throttle_req = 0;  	spin_unlock_irqrestore(&port->lock, flags); -	/* if we have a bulk endpoint, start reading from it */  	if (port->bulk_in_size)  		result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); @@ -127,12 +121,16 @@ int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port,  }  /** - * usb_serial_generic_write_start - kick off an URB write - * @port:	Pointer to the &struct usb_serial_port data + * usb_serial_generic_write_start - start writing buffered data + * @port: usb-serial port + * @mem_flags: flags to use for memory allocations + * + * Serialised using USB_SERIAL_WRITE_BUSY flag.   * - * Returns zero on success, or a negative errno value + * Return: Zero on success or if busy, otherwise a negative errno value.   */ -static int usb_serial_generic_write_start(struct usb_serial_port *port) +int usb_serial_generic_write_start(struct usb_serial_port *port, +							gfp_t mem_flags)  {  	struct urb *urb;  	int count, result; @@ -163,7 +161,7 @@ retry:  	spin_unlock_irqrestore(&port->lock, flags);  	clear_bit(i, &port->write_urbs_free); -	result = usb_submit_urb(urb, GFP_ATOMIC); +	result = usb_submit_urb(urb, mem_flags);  	if (result) {  		dev_err_console(port, "%s - error submitting urb: %d\n",  						__func__, result); @@ -176,33 +174,25 @@ retry:  		return result;  	} -	/* Try sending off another urb, unless in irq context (in which case -	 * there will be no free urb). */ -	if (!in_irq()) -		goto retry; - -	clear_bit_unlock(USB_SERIAL_WRITE_BUSY, &port->flags); - -	return 0; +	goto retry;	/* try sending off another urb */  } +EXPORT_SYMBOL_GPL(usb_serial_generic_write_start);  /** - * usb_serial_generic_write - generic write function for serial USB devices - * @tty:	Pointer to &struct tty_struct for the device - * @port:	Pointer to the &usb_serial_port structure for the device - * @buf:	Pointer to the data to write - * @count:	Number of bytes to write + * usb_serial_generic_write - generic write function + * @tty: tty for the port + * @port: usb-serial port + * @buf: data to write + * @count: number of bytes to write   * - * Returns the number of characters actually written, which may be anything - * from zero to @count. If an error occurs, it returns the negative errno - * value. + * Return: The number of characters buffered, which may be anything from + * zero to @count, or a negative errno value.   */  int usb_serial_generic_write(struct tty_struct *tty,  	struct usb_serial_port *port, const unsigned char *buf, int count)  {  	int result; -	/* only do something if we have a bulk out endpoint */  	if (!port->bulk_out_size)  		return -ENODEV; @@ -210,7 +200,7 @@ int usb_serial_generic_write(struct tty_struct *tty,  		return 0;  	count = kfifo_in_locked(&port->write_fifo, buf, count, &port->lock); -	result = usb_serial_generic_write_start(port); +	result = usb_serial_generic_write_start(port, GFP_ATOMIC);  	if (result)  		return result; @@ -337,13 +327,14 @@ void usb_serial_generic_process_read_urb(struct urb *urb)  	if (!urb->actual_length)  		return; - -	/* The per character mucking around with sysrq path it too slow for -	   stuff like 3G modems, so shortcircuit it in the 99.9999999% of cases -	   where the USB serial is not a console anyway */ -	if (!port->port.console || !port->sysrq) +	/* +	 * The per character mucking around with sysrq path it too slow for +	 * stuff like 3G modems, so shortcircuit it in the 99.9999999% of +	 * cases where the USB serial is not a console anyway. +	 */ +	if (!port->port.console || !port->sysrq) {  		tty_insert_flip_string(&port->port, ch, urb->actual_length); -	else { +	} else {  		for (i = 0; i < urb->actual_length; i++, ch++) {  			if (!usb_serial_handle_sysrq_char(port, *ch))  				tty_insert_flip_char(&port->port, *ch, TTY_NORMAL); @@ -368,24 +359,38 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)  	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", -			__func__, urb->status); +	switch (urb->status) { +	case 0: +		break; +	case -ENOENT: +	case -ECONNRESET: +	case -ESHUTDOWN: +		dev_dbg(&port->dev, "%s - urb stopped: %d\n", +							__func__, urb->status);  		return; +	case -EPIPE: +		dev_err(&port->dev, "%s - urb stopped: %d\n", +							__func__, urb->status); +		return; +	default: +		dev_err(&port->dev, "%s - nonzero urb status: %d\n", +							__func__, urb->status); +		goto resubmit;  	}  	usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data);  	port->serial->type->process_read_urb(urb); +resubmit:  	/* Throttle the device if requested by tty */  	spin_lock_irqsave(&port->lock, flags);  	port->throttled = port->throttle_req;  	if (!port->throttled) {  		spin_unlock_irqrestore(&port->lock, flags);  		usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC); -	} else +	} else {  		spin_unlock_irqrestore(&port->lock, flags); +	}  }  EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); @@ -393,29 +398,38 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb)  {  	unsigned long flags;  	struct usb_serial_port *port = urb->context; -	int status = urb->status;  	int i; -	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) +	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {  		if (port->write_urbs[i] == urb)  			break; - +	}  	spin_lock_irqsave(&port->lock, flags);  	port->tx_bytes -= urb->transfer_buffer_length;  	set_bit(i, &port->write_urbs_free);  	spin_unlock_irqrestore(&port->lock, flags); -	if (status) { -		dev_dbg(&port->dev, "%s - non-zero urb status: %d\n", -			__func__, status); - -		spin_lock_irqsave(&port->lock, flags); -		kfifo_reset_out(&port->write_fifo); -		spin_unlock_irqrestore(&port->lock, flags); -	} else { -		usb_serial_generic_write_start(port); +	switch (urb->status) { +	case 0: +		break; +	case -ENOENT: +	case -ECONNRESET: +	case -ESHUTDOWN: +		dev_dbg(&port->dev, "%s - urb stopped: %d\n", +							__func__, urb->status); +		return; +	case -EPIPE: +		dev_err_console(port, "%s - urb stopped: %d\n", +							__func__, urb->status); +		return; +	default: +		dev_err_console(port, "%s - nonzero urb status: %d\n", +							__func__, urb->status); +		goto resubmit;  	} +resubmit: +	usb_serial_generic_write_start(port, GFP_ATOMIC);  	usb_serial_port_softint(port);  }  EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); @@ -425,8 +439,6 @@ void usb_serial_generic_throttle(struct tty_struct *tty)  	struct usb_serial_port *port = tty->driver_data;  	unsigned long flags; -	/* Set the throttle request flag. It will be picked up -	 * by usb_serial_generic_read_bulk_callback(). */  	spin_lock_irqsave(&port->lock, flags);  	port->throttle_req = 1;  	spin_unlock_irqrestore(&port->lock, flags); @@ -438,7 +450,6 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)  	struct usb_serial_port *port = tty->driver_data;  	int was_throttled; -	/* Clear the throttle flags */  	spin_lock_irq(&port->lock);  	was_throttled = port->throttled;  	port->throttled = port->throttle_req = 0; @@ -558,10 +569,10 @@ int usb_serial_handle_break(struct usb_serial_port *port)  EXPORT_SYMBOL_GPL(usb_serial_handle_break);  /** - *	usb_serial_handle_dcd_change - handle a change of carrier detect state - *	@port: usb_serial_port structure for the open port - *	@tty: tty_struct structure for the port - *	@status: new carrier detect status, nonzero if active + * usb_serial_handle_dcd_change - handle a change of carrier detect state + * @port: usb-serial port + * @tty: tty for the port + * @status: new carrier detect status, nonzero if active   */  void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,  				struct tty_struct *tty, unsigned int status) @@ -570,6 +581,16 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port,  	dev_dbg(&usb_port->dev, "%s - status %d\n", __func__, status); +	if (tty) { +		struct tty_ldisc *ld = tty_ldisc_ref(tty); + +		if (ld) { +			if (ld->ops->dcd_change) +				ld->ops->dcd_change(tty, status); +			tty_ldisc_deref(ld); +		} +	} +  	if (status)  		wake_up_interruptible(&port->open_wait);  	else if (tty && !C_CLOCAL(tty)) @@ -595,7 +616,7 @@ int usb_serial_generic_resume(struct usb_serial *serial)  		}  		if (port->bulk_out_size) { -			r = usb_serial_generic_write_start(port); +			r = usb_serial_generic_write_start(port, GFP_NOIO);  			if (r < 0)  				c++;  		} diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index c91481d74a1..c0866971db2 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -32,7 +32,6 @@  #include <linux/kernel.h>  #include <linux/jiffies.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -898,7 +897,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)  	edge_port->txfifo.fifo	= kmalloc(edge_port->maxTxCredits, GFP_KERNEL);  	if (!edge_port->txfifo.fifo) { -		dev_dbg(dev, "%s - no memory\n", __func__);  		edge_close(port);  		return -ENOMEM;  	} @@ -908,7 +906,6 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)  	edge_port->write_in_progress = false;  	if (!edge_port->write_urb) { -		dev_dbg(dev, "%s - no memory\n", __func__);  		edge_close(port);  		return -ENOMEM;  	} @@ -1245,9 +1242,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,  	   to send out */  	count = fifo->count;  	buffer = kmalloc(count+2, GFP_ATOMIC); -	if (buffer == NULL) { -		dev_err_console(edge_port->port, -				"%s - no more kernel memory...\n", __func__); +	if (!buffer) {  		edge_port->write_in_progress = false;  		goto exit_send;  	} @@ -1593,8 +1588,6 @@ static int edge_ioctl(struct tty_struct *tty,  	DEFINE_WAIT(wait);  	struct edgeport_port *edge_port = usb_get_serial_port_data(port); -	dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd); -  	switch (cmd) {  	case TIOCSERGETLSR:  		dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__); @@ -2027,11 +2020,8 @@ static int sram_write(struct usb_serial *serial, __u16 extAddr, __u16 addr,  	dev_dbg(&serial->dev->dev, "%s - %x, %x, %d\n", __func__, extAddr, addr, length);  	transfer_buffer =  kmalloc(64, GFP_KERNEL); -	if (!transfer_buffer) { -		dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", -							__func__, 64); +	if (!transfer_buffer)  		return -ENOMEM; -	}  	/* need to split these writes up into 64 byte chunks */  	result = 0; @@ -2075,11 +2065,8 @@ static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr,  	unsigned char *transfer_buffer;  	transfer_buffer =  kmalloc(64, GFP_KERNEL); -	if (!transfer_buffer) { -		dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", -								__func__, 64); +	if (!transfer_buffer)  		return -ENOMEM; -	}  	/* need to split these writes up into 64 byte chunks */  	result = 0; @@ -2121,11 +2108,8 @@ static int rom_read(struct usb_serial *serial, __u16 extAddr,  	unsigned char *transfer_buffer;  	transfer_buffer =  kmalloc(64, GFP_KERNEL); -	if (!transfer_buffer) { -		dev_err(&serial->dev->dev, -			"%s - kmalloc(%d) failed.\n", __func__, 64); +	if (!transfer_buffer)  		return -ENOMEM; -	}  	/* need to split these reads up into 64 byte chunks */  	result = 0; @@ -2165,11 +2149,8 @@ static int send_iosp_ext_cmd(struct edgeport_port *edge_port,  	int             status = 0;  	buffer = kmalloc(10, GFP_ATOMIC); -	if (!buffer) { -		dev_err(&edge_port->port->dev, -				"%s - kmalloc(%d) failed.\n", __func__, 10); +	if (!buffer)  		return -ENOMEM; -	}  	currentCommand = buffer; @@ -2276,10 +2257,9 @@ static int send_cmd_write_baud_rate(struct edgeport_port *edge_port,  	/* Alloc memory for the string of commands. */  	cmdBuffer =  kmalloc(0x100, GFP_ATOMIC); -	if (!cmdBuffer) { -		dev_err(dev, "%s - kmalloc(%d) failed.\n", __func__, 0x100); +	if (!cmdBuffer)  		return -ENOMEM; -	} +  	currCmd = cmdBuffer;  	/* Enable access to divisor latch */ @@ -2785,10 +2765,9 @@ static int edge_startup(struct usb_serial *serial)  	/* create our private serial structure */  	edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); -	if (edge_serial == NULL) { -		dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); +	if (!edge_serial)  		return -ENOMEM; -	} +  	spin_lock_init(&edge_serial->es_lock);  	edge_serial->serial = serial;  	usb_set_serial_data(serial, edge_serial); @@ -2877,14 +2856,12 @@ static int edge_startup(struct usb_serial *serial)  				/* not set up yet, so do it now */  				edge_serial->interrupt_read_urb =  						usb_alloc_urb(0, GFP_KERNEL); -				if (!edge_serial->interrupt_read_urb) { -					dev_err(ddev, "out of memory\n"); +				if (!edge_serial->interrupt_read_urb)  					return -ENOMEM; -				} +  				edge_serial->interrupt_in_buffer =  					kmalloc(buffer_size, GFP_KERNEL);  				if (!edge_serial->interrupt_in_buffer) { -					dev_err(ddev, "out of memory\n");  					usb_free_urb(edge_serial->interrupt_read_urb);  					return -ENOMEM;  				} @@ -2914,14 +2891,12 @@ static int edge_startup(struct usb_serial *serial)  				/* not set up yet, so do it now */  				edge_serial->read_urb =  						usb_alloc_urb(0, GFP_KERNEL); -				if (!edge_serial->read_urb) { -					dev_err(ddev, "out of memory\n"); +				if (!edge_serial->read_urb)  					return -ENOMEM; -				} +  				edge_serial->bulk_in_buffer =  					kmalloc(buffer_size, GFP_KERNEL);  				if (!edge_serial->bulk_in_buffer) { -					dev_err(&dev->dev, "out of memory\n");  					usb_free_urb(edge_serial->read_urb);  					return -ENOMEM;  				} diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index b7187bf3246..c0a42e9e677 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -20,7 +20,6 @@  #include <linux/kernel.h>  #include <linux/jiffies.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -29,6 +28,7 @@  #include <linux/spinlock.h>  #include <linux/mutex.h>  #include <linux/serial.h> +#include <linux/swab.h>  #include <linux/kfifo.h>  #include <linux/ioctl.h>  #include <linux/firmware.h> @@ -281,7 +281,7 @@ static int read_download_mem(struct usb_device *dev, int start_address,  {  	int status = 0;  	__u8 read_length; -	__be16 be_start_address; +	u16 be_start_address;  	dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, length); @@ -297,10 +297,14 @@ static int read_download_mem(struct usb_device *dev, int start_address,  		if (read_length > 1) {  			dev_dbg(&dev->dev, "%s - @ %x for %d\n", __func__, start_address, read_length);  		} -		be_start_address = cpu_to_be16(start_address); +		/* +		 * NOTE: Must use swab as wIndex is sent in little-endian +		 *       byte order regardless of host byte order. +		 */ +		be_start_address = swab16((u16)start_address);  		status = ti_vread_sync(dev, UMPC_MEMORY_READ,  					(__u16)address_type, -					(__force __u16)be_start_address, +					be_start_address,  					buffer, read_length);  		if (status) { @@ -364,11 +368,9 @@ static int write_boot_mem(struct edgeport_serial *serial,  	/* Must do a read before write */  	if (!serial->TiReadI2C) {  		temp = kmalloc(1, GFP_KERNEL); -		if (!temp) { -			dev_err(&serial->serial->dev->dev, -					"%s - out of memory\n", __func__); +		if (!temp)  			return -ENOMEM; -		} +  		status = read_boot_mem(serial, 0, 1, temp);  		kfree(temp);  		if (status) @@ -397,7 +399,7 @@ static int write_i2c_mem(struct edgeport_serial *serial,  	struct device *dev = &serial->serial->dev->dev;  	int status = 0;  	int write_length; -	__be16 be_start_address; +	u16 be_start_address;  	/* We can only send a maximum of 1 aligned byte page at a time */ @@ -412,11 +414,16 @@ static int write_i2c_mem(struct edgeport_serial *serial,  		__func__, start_address, write_length);  	usb_serial_debug_data(dev, __func__, write_length, buffer); -	/* Write first page */ -	be_start_address = cpu_to_be16(start_address); +	/* +	 * Write first page. +	 * +	 * NOTE: Must use swab as wIndex is sent in little-endian byte order +	 *       regardless of host byte order. +	 */ +	be_start_address = swab16((u16)start_address);  	status = ti_vsend_sync(serial->serial->dev,  				UMPC_MEMORY_WRITE, (__u16)address_type, -				(__force __u16)be_start_address, +				be_start_address,  				buffer,	write_length);  	if (status) {  		dev_dbg(dev, "%s - ERROR %d\n", __func__, status); @@ -439,11 +446,16 @@ static int write_i2c_mem(struct edgeport_serial *serial,  			__func__, start_address, write_length);  		usb_serial_debug_data(dev, __func__, write_length, buffer); -		/* Write next page */ -		be_start_address = cpu_to_be16(start_address); +		/* +		 * Write next page. +		 * +		 * NOTE: Must use swab as wIndex is sent in little-endian byte +		 *       order regardless of host byte order. +		 */ +		be_start_address = swab16((u16)start_address);  		status = ti_vsend_sync(serial->serial->dev, UMPC_MEMORY_WRITE,  				(__u16)address_type, -				(__force __u16)be_start_address, +				be_start_address,  				buffer, write_length);  		if (status) {  			dev_err(dev, "%s - ERROR %d\n", __func__, status); @@ -471,10 +483,8 @@ static int tx_active(struct edgeport_port *port)  	int bytes_left = 0;  	oedb = kmalloc(sizeof(*oedb), GFP_KERNEL); -	if (!oedb) { -		dev_err(&port->port->dev, "%s - out of memory\n", __func__); +	if (!oedb)  		return -ENOMEM; -	}  	lsr = kmalloc(1, GFP_KERNEL);	/* Sigh, that's right, just one byte,  					   as not all platforms can do DMA @@ -590,8 +600,8 @@ static int get_descriptor_addr(struct edgeport_serial *serial,  		if (rom_desc->Type == desc_type)  			return start_address; -		start_address = start_address + sizeof(struct ti_i2c_desc) -							+ rom_desc->Size; +		start_address = start_address + sizeof(struct ti_i2c_desc) + +						le16_to_cpu(rom_desc->Size);  	} while ((start_address < TI_MAX_I2C_SIZE) && rom_desc->Type); @@ -604,7 +614,7 @@ static int valid_csum(struct ti_i2c_desc *rom_desc, __u8 *buffer)  	__u16 i;  	__u8 cs = 0; -	for (i = 0; i < rom_desc->Size; i++) +	for (i = 0; i < le16_to_cpu(rom_desc->Size); i++)  		cs = (__u8)(cs + buffer[i]);  	if (cs != rom_desc->CheckSum) { @@ -625,14 +635,11 @@ static int check_i2c_image(struct edgeport_serial *serial)  	__u16 ttype;  	rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); -	if (!rom_desc) { -		dev_err(dev, "%s - out of memory\n", __func__); +	if (!rom_desc)  		return -ENOMEM; -	} +  	buffer = kmalloc(TI_MAX_I2C_SIZE, GFP_KERNEL);  	if (!buffer) { -		dev_err(dev, "%s - out of memory when allocating buffer\n", -								__func__);  		kfree(rom_desc);  		return -ENOMEM;  	} @@ -658,7 +665,7 @@ static int check_i2c_image(struct edgeport_serial *serial)  			break;  		if ((start_address + sizeof(struct ti_i2c_desc) + -					rom_desc->Size) > TI_MAX_I2C_SIZE) { +			le16_to_cpu(rom_desc->Size)) > TI_MAX_I2C_SIZE) {  			status = -ENODEV;  			dev_dbg(dev, "%s - structure too big, erroring out.\n", __func__);  			break; @@ -673,7 +680,8 @@ static int check_i2c_image(struct edgeport_serial *serial)  			/* Read the descriptor data */  			status = read_rom(serial, start_address +  						sizeof(struct ti_i2c_desc), -						rom_desc->Size, buffer); +						le16_to_cpu(rom_desc->Size), +						buffer);  			if (status)  				break; @@ -682,7 +690,7 @@ static int check_i2c_image(struct edgeport_serial *serial)  				break;  		}  		start_address = start_address + sizeof(struct ti_i2c_desc) + -								rom_desc->Size; +						le16_to_cpu(rom_desc->Size);  	} while ((rom_desc->Type != I2C_DESC_TYPE_ION) &&  				(start_address < TI_MAX_I2C_SIZE)); @@ -706,10 +714,9 @@ static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer)  	struct device *dev = &serial->serial->dev->dev;  	rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL); -	if (!rom_desc) { -		dev_err(dev, "%s - out of memory\n", __func__); +	if (!rom_desc)  		return -ENOMEM; -	} +  	start_address = get_descriptor_addr(serial, I2C_DESC_TYPE_ION,  								rom_desc); @@ -721,7 +728,7 @@ static int get_manuf_info(struct edgeport_serial *serial, __u8 *buffer)  	/* Read the descriptor data */  	status = read_rom(serial, start_address+sizeof(struct ti_i2c_desc), -						rom_desc->Size, buffer); +					le16_to_cpu(rom_desc->Size), buffer);  	if (status)  		goto exit; @@ -769,10 +776,8 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev)  			sizeof(struct ti_i2c_firmware_rec));  	buffer = kmalloc(buffer_size, GFP_KERNEL); -	if (!buffer) { -		dev_err(dev, "%s - out of memory\n", __func__); +	if (!buffer)  		return -ENOMEM; -	}  	// Set entire image of 0xffs  	memset(buffer, 0xff, buffer_size); @@ -816,7 +821,7 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev)  	firmware_rec =  (struct ti_i2c_firmware_rec*)i2c_header->Data;  	i2c_header->Type	= I2C_DESC_TYPE_FIRMWARE_BLANK; -	i2c_header->Size	= (__u16)buffer_size; +	i2c_header->Size	= cpu_to_le16(buffer_size);  	i2c_header->CheckSum	= cs;  	firmware_rec->Ver_Major	= OperationalMajorVersion;  	firmware_rec->Ver_Minor	= OperationalMinorVersion; @@ -832,10 +837,8 @@ static int i2c_type_bootmode(struct edgeport_serial *serial)  	u8 *data;  	data = kmalloc(1, GFP_KERNEL); -	if (!data) { -		dev_err(dev, "%s - out of memory\n", __func__); +	if (!data)  		return -ENOMEM; -	}  	/* Try to read type 2 */  	status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ, @@ -986,10 +989,9 @@ static int download_fw(struct edgeport_serial *serial)  		 * Read Manufacturing Descriptor from TI Based Edgeport  		 */  		ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL); -		if (!ti_manuf_desc) { -			dev_err(dev, "%s - out of memory.\n", __func__); +		if (!ti_manuf_desc)  			return -ENOMEM; -		} +  		status = get_manuf_info(serial, (__u8 *)ti_manuf_desc);  		if (status) {  			kfree(ti_manuf_desc); @@ -1006,7 +1008,6 @@ static int download_fw(struct edgeport_serial *serial)  		rom_desc = kmalloc(sizeof(*rom_desc), GFP_KERNEL);  		if (!rom_desc) { -			dev_err(dev, "%s - out of memory.\n", __func__);  			kfree(ti_manuf_desc);  			return -ENOMEM;  		} @@ -1023,7 +1024,6 @@ static int download_fw(struct edgeport_serial *serial)  			firmware_version = kmalloc(sizeof(*firmware_version),  								GFP_KERNEL);  			if (!firmware_version) { -				dev_err(dev, "%s - out of memory.\n", __func__);  				kfree(rom_desc);  				kfree(ti_manuf_desc);  				return -ENOMEM; @@ -1068,8 +1068,6 @@ static int download_fw(struct edgeport_serial *serial)  				record = kmalloc(1, GFP_KERNEL);  				if (!record) { -					dev_err(dev, "%s - out of memory.\n", -							__func__);  					kfree(firmware_version);  					kfree(rom_desc);  					kfree(ti_manuf_desc); @@ -1153,7 +1151,6 @@ static int download_fw(struct edgeport_serial *serial)  			header = kmalloc(HEADER_SIZE, GFP_KERNEL);  			if (!header) { -				dev_err(dev, "%s - out of memory.\n", __func__);  				kfree(rom_desc);  				kfree(ti_manuf_desc);  				return -ENOMEM; @@ -1161,7 +1158,6 @@ static int download_fw(struct edgeport_serial *serial)  			vheader = kmalloc(HEADER_SIZE, GFP_KERNEL);  			if (!vheader) { -				dev_err(dev, "%s - out of memory.\n", __func__);  				kfree(header);  				kfree(rom_desc);  				kfree(ti_manuf_desc); @@ -1290,10 +1286,9 @@ static int download_fw(struct edgeport_serial *serial)  		 * Read Manufacturing Descriptor from TI Based Edgeport  		 */  		ti_manuf_desc = kmalloc(sizeof(*ti_manuf_desc), GFP_KERNEL); -		if (!ti_manuf_desc) { -			dev_err(dev, "%s - out of memory.\n", __func__); +		if (!ti_manuf_desc)  			return -ENOMEM; -		} +  		status = get_manuf_info(serial, (__u8 *)ti_manuf_desc);  		if (status) {  			kfree(ti_manuf_desc); @@ -1328,10 +1323,8 @@ static int download_fw(struct edgeport_serial *serial)  		buffer_size = (((1024 * 16) - 512) +  					sizeof(struct ti_i2c_image_header));  		buffer = kmalloc(buffer_size, GFP_KERNEL); -		if (!buffer) { -			dev_err(dev, "%s - out of memory\n", __func__); +		if (!buffer)  			return -ENOMEM; -		}  		/* Initialize the buffer to 0xff (pad the buffer) */  		memset(buffer, 0xff, buffer_size); @@ -2122,7 +2115,6 @@ static void change_port_settings(struct tty_struct *tty,  	config = kmalloc (sizeof (*config), GFP_KERNEL);  	if (!config) {  		tty->termios = *old_termios; -		dev_err(dev, "%s - out of memory\n", __func__);  		return;  	} @@ -2362,8 +2354,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); -	dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd); -  	switch (cmd) {  	case TIOCGSERIAL:  		dev_dbg(&port->dev, "%s - TIOCGSERIAL\n", __func__); @@ -2395,10 +2385,9 @@ static int edge_startup(struct usb_serial *serial)  	/* create our private serial structure */  	edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); -	if (edge_serial == NULL) { -		dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); +	if (!edge_serial)  		return -ENOMEM; -	} +  	mutex_init(&edge_serial->es_lock);  	edge_serial->serial = serial;  	usb_set_serial_data(serial, edge_serial); diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h index 51f83fbb73b..6f6a856bc37 100644 --- a/drivers/usb/serial/io_usbvend.h +++ b/drivers/usb/serial/io_usbvend.h @@ -594,7 +594,7 @@ struct edge_boot_descriptor {  struct ti_i2c_desc {  	__u8	Type;			// Type of descriptor -	__u16	Size;			// Size of data only not including header +	__le16	Size;			// Size of data only not including header  	__u8	CheckSum;		// Checksum (8 bit sum of data only)  	__u8	Data[0];		// Data starts here  } __attribute__((packed)); diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 76c9a847da5..f51a5d52c0e 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -12,7 +12,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -37,7 +36,7 @@ static int  ipaq_open(struct tty_struct *tty,  static int  ipaq_calc_num_ports(struct usb_serial *serial);  static int  ipaq_startup(struct usb_serial *serial); -static struct usb_device_id ipaq_id_table [] = { +static const struct usb_device_id ipaq_id_table[] = {  	{ USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */  	{ USB_DEVICE(0x03F0, 0x1016) }, /* HP USB Sync */  	{ USB_DEVICE(0x03F0, 0x1116) }, /* HP USB Sync 1611 */ diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 155eab14b30..8b1cf18a668 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -38,7 +38,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_flip.h> diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 716930ab1bb..73956d48a0c 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -377,15 +377,12 @@ static void ir_set_termios(struct tty_struct *tty,  	 * send the baud change out on an "empty" data packet  	 */  	urb = usb_alloc_urb(0, GFP_KERNEL); -	if (!urb) { -		dev_err(&port->dev, "%s - no more urbs\n", __func__); +	if (!urb)  		return; -	} +  	transfer_buffer = kmalloc(1, GFP_KERNEL); -	if (!transfer_buffer) { -		dev_err(&port->dev, "%s - out of memory\n", __func__); +	if (!transfer_buffer)  		goto err_buf; -	}  	*transfer_buffer = ir_xbof | ir_baud; diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 57c439a24b5..5ad4a0fb4b2 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -17,7 +17,6 @@   */  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -770,7 +769,7 @@ uart_enable_failed:  	return status;  } -/*  Diables the IUU UART (a.k.a. the Phoenix voiderface) */ +/*  Disables the IUU UART (a.k.a. the Phoenix voiderface) */  static int iuu_uart_off(struct usb_serial_port *port)  {  	int status; @@ -1152,7 +1151,7 @@ static ssize_t vcc_mode_store(struct device *dev,  		goto fail_store_vcc_mode;  	} -	dev_dbg(dev, "%s: setting vcc_mode = %ld", __func__, v); +	dev_dbg(dev, "%s: setting vcc_mode = %ld\n", __func__, v);  	if ((v != 3) && (v != 5)) {  		dev_err(dev, "%s - vcc_mode %ld is invalid\n", __func__, v); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index d6960aebe24..93cb7cebda6 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -31,7 +31,6 @@  #include <linux/kernel.h>  #include <linux/jiffies.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -165,7 +164,7 @@ static void keyspan_set_termios(struct tty_struct *tty,  	if (d_details->calculate_baud_rate(port, baud_rate, d_details->baudclk,  				NULL, NULL, NULL, device_port) == KEYSPAN_BAUD_RATE_OK) {  		/* FIXME - more to do here to ensure rate changes cleanly */ -		/* FIXME - calcuate exact rate from divisor ? */ +		/* FIXME - calculate exact rate from divisor ? */  		p_priv->baud = baud_rate;  	} else  		baud_rate = tty_termios_baud_rate(old_termios); @@ -398,17 +397,6 @@ static void	usa26_instat_callback(struct urb *urb)  	msg = (struct keyspan_usa26_portStatusMessage *)data; -#if 0 -	dev_dbg(&urb->dev->dev, -		"%s - port status: port %d cts %d dcd %d dsr %d ri %d toff %d txoff %d rxen %d cr %d", -		__func__, msg->port, msg->hskia_cts, msg->gpia_dcd, msg->dsr, -		msg->ri, msg->_txOff, msg->_txXoff, msg->rxEnabled, -		msg->controlResponse); -#endif - -	/* Now do something useful with the data */ - -  	/* Check port number from message and retrieve private data */  	if (msg->port >= serial->num_ports) {  		dev_dbg(&urb->dev->dev, "%s - Unexpected port number %d\n", __func__, msg->port); @@ -524,9 +512,6 @@ static void	usa28_instat_callback(struct urb *urb)  		goto exit;  	} -	/*dev_dbg(&urb->dev->dev, "%s %12ph", __func__, data);*/ - -	/* Now do something useful with the data */  	msg = (struct keyspan_usa28_portStatusMessage *)data;  	/* Check port number from message and retrieve private data */ @@ -606,9 +591,6 @@ static void	usa49_instat_callback(struct urb *urb)  		goto exit;  	} -	/*dev_dbg(&urb->dev->dev, "%s: %11ph", __func__, data);*/ - -	/* Now do something useful with the data */  	msg = (struct keyspan_usa49_portStatusMessage *)data;  	/* Check port number from message and retrieve private data */ @@ -1226,10 +1208,8 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,  	dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d.\n", __func__, endpoint);  	urb = usb_alloc_urb(0, GFP_KERNEL);		/* No ISO */ -	if (urb == NULL) { -		dev_dbg(&serial->interface->dev, "%s - alloc for endpoint %d failed.\n", __func__, endpoint); +	if (!urb)  		return NULL; -	}  	if (endpoint == 0) {  		/* control EP filled in when used */ @@ -1555,14 +1535,14 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,  	this_urb = p_priv->outcont_urb; -	dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe)); -  		/* Make sure we have an urb then send the message */  	if (this_urb == NULL) {  		dev_dbg(&port->dev, "%s - oops no urb.\n", __func__);  		return -1;  	} +	dev_dbg(&port->dev, "%s - endpoint %d\n", __func__, usb_pipeendpoint(this_urb->pipe)); +  	/* Save reset port val for resend.  	   Don't overwrite resend for open/close condition. */  	if ((reset_port + 1) > p_priv->resend_cont) @@ -1796,12 +1776,6 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,  	err = usb_submit_urb(this_urb, GFP_ATOMIC);  	if (err != 0)  		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed\n", __func__); -#if 0 -	else { -		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) OK %d bytes\n", __func__, -		    this_urb->transfer_buffer_length); -	} -#endif  	return 0;  } @@ -1979,13 +1953,6 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,  	err = usb_submit_urb(this_urb, GFP_ATOMIC);  	if (err != 0)  		dev_dbg(&port->dev, "%s - usb_submit_urb(setup) failed (%d)\n", __func__, err); -#if 0 -	else { -		dev_dbg(&port->dev, "%s - usb_submit_urb(%d) OK %d bytes (end %d)\n", __func__, -			outcont_urb, this_urb->transfer_buffer_length, -			usb_pipeendpoint(this_urb->pipe)); -	} -#endif  	return 0;  } @@ -2312,10 +2279,8 @@ static int keyspan_startup(struct usb_serial *serial)  	/* Setup private data for serial driver */  	s_priv = kzalloc(sizeof(struct keyspan_serial_private), GFP_KERNEL); -	if (!s_priv) { -		dev_dbg(&serial->dev->dev, "%s - kmalloc for keyspan_serial_private failed.\n", __func__); +	if (!s_priv)  		return -ENOMEM; -	}  	s_priv->instat_buf = kzalloc(INSTAT_BUFLEN, GFP_KERNEL);  	if (!s_priv->instat_buf) diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 5f1d382e55c..742d827f876 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -17,7 +17,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -190,7 +189,7 @@ exit:  	retval = usb_submit_urb(urb, GFP_ATOMIC);  	if (retval)  		dev_err(&port->dev, -			"%s - usb_submit_urb failed with result %d", +			"%s - usb_submit_urb failed with result %d\n",  			__func__, retval);  } diff --git a/drivers/usb/serial/keyspan_usa26msg.h b/drivers/usb/serial/keyspan_usa26msg.h index 3808727db65..09e21e84fc4 100644 --- a/drivers/usb/serial/keyspan_usa26msg.h +++ b/drivers/usb/serial/keyspan_usa26msg.h @@ -62,7 +62,7 @@  	or:  		(b)	0x80 bit set -			indiates that the bytes following alternate data and +			indicates that the bytes following alternate data and  			status bytes:  				STAT DATA STAT DATA STAT DATA STAT DATA ... diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 1b4054fe52a..d7440b7557a 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -37,7 +37,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -182,11 +181,9 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,  	dev_info(&port->serial->dev->dev, "sending SIO Poll request\n");  	status_buf = kmalloc(KLSI_STATUSBUF_LEN, GFP_KERNEL); -	if (!status_buf) { -		dev_err(&port->dev, "%s - out of memory for status buffer.\n", -				__func__); +	if (!status_buf)  		return -ENOMEM; -	} +  	status_buf[0] = 0xff;  	status_buf[1] = 0xff;  	rc = usb_control_msg(port->serial->dev, @@ -204,7 +201,7 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,  	else {  		status = get_unaligned_le16(status_buf); -		dev_info(&port->serial->dev->dev, "read status %x %x", +		dev_info(&port->serial->dev->dev, "read status %x %x\n",  			 status_buf[0], status_buf[1]);  		*line_state_p = klsi_105_status2linestate(status); @@ -273,11 +270,9 @@ static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)  	 * priv->line_state.  	 */  	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); -	if (!cfg) { -		dev_err(&port->dev, "%s - out of memory for config buffer.\n", -				__func__); +	if (!cfg)  		return -ENOMEM; -	} +  	cfg->pktlen   = 5;  	cfg->baudrate = kl5kusb105a_sio_b9600;  	cfg->databits = kl5kusb105a_dtb_8; @@ -417,10 +412,8 @@ static void klsi_105_set_termios(struct tty_struct *tty,  	speed_t baud;  	cfg = kmalloc(sizeof(*cfg), GFP_KERNEL); -	if (!cfg) { -		dev_err(dev, "%s - out of memory for config buffer.\n", __func__); +	if (!cfg)  		return; -	}  	/* lock while we are modifying the settings */  	spin_lock_irqsave(&priv->lock, flags); @@ -471,7 +464,7 @@ static void klsi_105_set_termios(struct tty_struct *tty,  		priv->cfg.baudrate = kl5kusb105a_sio_b115200;  		break;  	default: -		dev_dbg(dev, "KLSI USB->Serial converter: unsupported baudrate request, using default of 9600"); +		dev_dbg(dev, "unsupported baudrate, using 9600\n");  		priv->cfg.baudrate = kl5kusb105a_sio_b9600;  		baud = 9600;  		break; diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 78b48c31abf..078f9ed419c 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -25,7 +25,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -194,7 +193,7 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)  			  KOBIL_TIMEOUT  	);  	dev_dbg(dev, "%s - Send get_HW_version URB returns: %i\n", __func__, result); -	dev_dbg(dev, "Harware version: %i.%i.%i\n", transfer_buffer[0], +	dev_dbg(dev, "Hardware version: %i.%i.%i\n", transfer_buffer[0],  		transfer_buffer[1], transfer_buffer[2]);  	/* get firmware version */ @@ -216,13 +215,13 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)  			priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {  		/* Setting Baudrate, Parity and Stopbits */  		result = usb_control_msg(port->serial->dev, -			  usb_rcvctrlpipe(port->serial->dev, 0), +			  usb_sndctrlpipe(port->serial->dev, 0),  			  SUSBCRequest_SetBaudRateParityAndStopBits,  			  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,  			  SUSBCR_SBR_9600 | SUSBCR_SPASB_EvenParity |  							SUSBCR_SPASB_1StopBit,  			  0, -			  transfer_buffer, +			  NULL,  			  0,  			  KOBIL_TIMEOUT  		); @@ -230,12 +229,12 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)  		/* reset all queues */  		result = usb_control_msg(port->serial->dev, -			  usb_rcvctrlpipe(port->serial->dev, 0), +			  usb_sndctrlpipe(port->serial->dev, 0),  			  SUSBCRequest_Misc,  			  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,  			  SUSBCR_MSC_ResetAllQueues,  			  0, -			  transfer_buffer, +			  NULL,  			  0,  			  KOBIL_TIMEOUT  		); @@ -446,12 +445,12 @@ static int kobil_tiocmset(struct tty_struct *tty,  		else  			dev_dbg(dev, "%s - Clearing DTR\n", __func__);  		result = usb_control_msg(port->serial->dev, -			  usb_rcvctrlpipe(port->serial->dev, 0), +			  usb_sndctrlpipe(port->serial->dev, 0),  			  SUSBCRequest_SetStatusLinesOrQueues,  			  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,  			  ((dtr != 0) ? SUSBCR_SSL_SETDTR : SUSBCR_SSL_CLRDTR),  			  0, -			  transfer_buffer, +			  NULL,  			  0,  			  KOBIL_TIMEOUT);  	} else { @@ -460,12 +459,12 @@ static int kobil_tiocmset(struct tty_struct *tty,  		else  			dev_dbg(dev, "%s - Clearing RTS\n", __func__);  		result = usb_control_msg(port->serial->dev, -			usb_rcvctrlpipe(port->serial->dev, 0), +			usb_sndctrlpipe(port->serial->dev, 0),  			SUSBCRequest_SetStatusLinesOrQueues,  			USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,  			((rts != 0) ? SUSBCR_SSL_SETRTS : SUSBCR_SSL_CLRRTS),  			0, -			transfer_buffer, +			NULL,  			0,  			KOBIL_TIMEOUT);  	} @@ -515,7 +514,7 @@ static void kobil_set_termios(struct tty_struct *tty,  	tty_encode_baud_rate(tty, speed, speed);  	result = usb_control_msg(port->serial->dev, -		  usb_rcvctrlpipe(port->serial->dev, 0), +		  usb_sndctrlpipe(port->serial->dev, 0),  		  SUSBCRequest_SetBaudRateParityAndStopBits,  		  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,  		  urb_val, @@ -547,18 +546,19 @@ static int kobil_ioctl(struct tty_struct *tty,  			return -ENOBUFS;  		result = usb_control_msg(port->serial->dev, -			  usb_rcvctrlpipe(port->serial->dev, 0), +			  usb_sndctrlpipe(port->serial->dev, 0),  			  SUSBCRequest_Misc,  			  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,  			  SUSBCR_MSC_ResetAllQueues,  			  0, -			  NULL, /* transfer_buffer, */ +			  NULL,  			  0,  			  KOBIL_TIMEOUT  			);  		dev_dbg(&port->dev, -			"%s - Send reset_all_queues (FLUSH) URB returns: %i", __func__, result); +			"%s - Send reset_all_queues (FLUSH) URB returns: %i\n", +			__func__, result);  		kfree(transfer_buffer);  		return (result < 0) ? -EIO: 0;  	default: diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 6a15adf5336..fd707d6a10e 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -23,7 +23,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 40ccf6e5e31..39e683096e9 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -7,7 +7,6 @@  */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/tty.h>  #include <linux/module.h>  #include <linux/usb.h> @@ -43,7 +42,7 @@ struct metrousb_private {  };  /* Device table list. */ -static struct usb_device_id id_table[] = { +static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_BI) },  	{ USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) },  	{ }, /* Terminating entry. */ @@ -54,7 +53,7 @@ MODULE_DEVICE_TABLE(usb, id_table);  #define UNI_CMD_OPEN	0x80  #define UNI_CMD_CLOSE	0xFF -inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port) +static inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port)  {  	__u16 product_id = le16_to_cpu(  		port->serial->dev->descriptor.idProduct); diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 84657e07dc5..dfd728a263d 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1,6 +1,6 @@  /*   * mos7720.c - *   Controls the Moschip 7720 usb to dual port serial convertor + *   Controls the Moschip 7720 usb to dual port serial converter   *   * Copyright 2006 Moschip Semiconductor Tech. Ltd.   * @@ -22,7 +22,6 @@   */  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -46,7 +45,7 @@  #define MOS_WRITE	0x0E  #define MOS_READ	0x0D -/* Interrupt Rotinue Defines	*/ +/* Interrupt Routines Defines	*/  #define SERIAL_IIR_RLS	0x06  #define SERIAL_IIR_RDA	0x04  #define SERIAL_IIR_CTI	0x0c @@ -210,7 +209,7 @@ static int write_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,  				     index, NULL, 0, MOS_WDR_TIMEOUT);  	if (status < 0)  		dev_err(&usbdev->dev, -			"mos7720: usb_control_msg() failed: %d", status); +			"mos7720: usb_control_msg() failed: %d\n", status);  	return status;  } @@ -241,7 +240,7 @@ static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum,  		*data = *buf;  	else if (status < 0)  		dev_err(&usbdev->dev, -			"mos7720: usb_control_msg() failed: %d", status); +			"mos7720: usb_control_msg() failed: %d\n", status);  	kfree(buf);  	return status; @@ -362,15 +361,13 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,  	/* create and initialize the control urb and containing urbtracker */  	urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC); -	if (urbtrack == NULL) { -		dev_err(&usbdev->dev, "out of memory"); +	if (!urbtrack)  		return -ENOMEM; -	} +  	kref_get(&mos_parport->ref_count);  	urbtrack->mos_parport = mos_parport;  	urbtrack->urb = usb_alloc_urb(0, GFP_ATOMIC); -	if (urbtrack->urb == NULL) { -		dev_err(&usbdev->dev, "out of urbs"); +	if (!urbtrack->urb) {  		kfree(urbtrack);  		return -ENOMEM;  	} @@ -402,7 +399,7 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,  			      &mos_parport->deferred_urbs);  		spin_unlock_irqrestore(&mos_parport->listlock, flags);  		tasklet_schedule(&mos_parport->urb_tasklet); -		dev_dbg(&usbdev->dev, "tasklet scheduled"); +		dev_dbg(&usbdev->dev, "tasklet scheduled\n");  		return 0;  	} @@ -421,7 +418,7 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,  	mutex_unlock(&serial->disc_mutex);  	if (ret_val) {  		dev_err(&usbdev->dev, -			"%s: submit_urb() failed: %d", __func__, ret_val); +			"%s: submit_urb() failed: %d\n", __func__, ret_val);  		spin_lock_irqsave(&mos_parport->listlock, flags);  		list_del(&urbtrack->urblist_entry);  		spin_unlock_irqrestore(&mos_parport->listlock, flags); @@ -440,7 +437,7 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport,   * not called the release function yet because someone has a serial port open.   * The shared release_lock prevents the first, and the mutex and disconnected   * flag maintained by usbserial covers the second.  We also use the msg_pending - * flag to ensure that all synchronous usb messgage calls have completed before + * flag to ensure that all synchronous usb message calls have completed before   * our release function can return.   */  static int parport_prologue(struct parport *pp) @@ -455,7 +452,7 @@ static int parport_prologue(struct parport *pp)  		return -1;  	}  	mos_parport->msg_pending = true;   /* synch usb call pending */ -	INIT_COMPLETION(mos_parport->syncmsg_compl); +	reinit_completion(&mos_parport->syncmsg_compl);  	spin_unlock(&release_lock);  	mutex_lock(&mos_parport->serial->disc_mutex); @@ -471,7 +468,7 @@ static int parport_prologue(struct parport *pp)  }  /* - * This is the the common bottom part of all parallel port functions that send + * This is the common bottom part of all parallel port functions that send   * synchronous messages to the device.   */  static inline void parport_epilogue(struct parport *pp) @@ -659,7 +656,7 @@ static size_t parport_mos7715_write_compat(struct parport *pp,  	parport_epilogue(pp);  	if (retval) {  		dev_err(&mos_parport->serial->dev->dev, -			"mos7720: usb_bulk_msg() failed: %d", retval); +			"mos7720: usb_bulk_msg() failed: %d\n", retval);  		return 0;  	}  	return actual_len; @@ -702,10 +699,9 @@ static int mos7715_parport_init(struct usb_serial *serial)  	/* allocate and initialize parallel port control struct */  	mos_parport = kzalloc(sizeof(struct mos7715_parport), GFP_KERNEL); -	if (mos_parport == NULL) { -		dev_dbg(&serial->dev->dev, "%s: kzalloc failed\n", __func__); +	if (!mos_parport)  		return -ENOMEM; -	} +  	mos_parport->msg_pending = false;  	kref_init(&mos_parport->ref_count);  	spin_lock_init(&mos_parport->listlock); @@ -879,7 +875,7 @@ static void mos7715_interrupt_callback(struct urb *urb)  	if (!(iir & 0x01)) {	/* serial port interrupt pending */  		switch (iir & 0x0f) {  		case SERIAL_IIR_RLS: -			dev_dbg(dev, "Serial Port: Receiver status error or address bit detected in 9-bit mode\n\n"); +			dev_dbg(dev, "Serial Port: Receiver status error or address bit detected in 9-bit mode\n");  			break;  		case SERIAL_IIR_CTI:  			dev_dbg(dev, "Serial Port: Receiver time out\n"); @@ -1018,18 +1014,12 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)  	for (j = 0; j < NUM_URBS; ++j) {  		urb = usb_alloc_urb(0, GFP_KERNEL);  		mos7720_port->write_urb_pool[j] = urb; - -		if (urb == NULL) { -			dev_err(&port->dev, "No more urbs???\n"); +		if (!urb)  			continue; -		}  		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,  					       GFP_KERNEL);  		if (!urb->transfer_buffer) { -			dev_err(&port->dev, -				"%s-out of memory for urb buffers.\n", -				__func__);  			usb_free_urb(mos7720_port->write_urb_pool[j]);  			mos7720_port->write_urb_pool[j] = NULL;  			continue; @@ -1250,11 +1240,8 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,  	if (urb->transfer_buffer == NULL) {  		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,  					       GFP_KERNEL); -		if (urb->transfer_buffer == NULL) { -			dev_err_console(port, "%s no more kernel memory...\n", -				__func__); +		if (!urb->transfer_buffer)  			goto exit; -		}  	}  	transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE); @@ -1885,8 +1872,6 @@ static int mos7720_ioctl(struct tty_struct *tty,  	if (mos7720_port == NULL)  		return -ENODEV; -	dev_dbg(&port->dev, "%s - cmd = 0x%x", __func__, cmd); -  	switch (cmd) {  	case TIOCSERGETLSR:  		dev_dbg(&port->dev, "%s TIOCSERGETLSR\n", __func__); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index fdf953539c6..393be562d87 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -24,7 +24,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -523,11 +522,11 @@ static void mos7840_set_led_callback(struct urb *urb)  	case -ENOENT:  	case -ESHUTDOWN:  		/* This urb is terminated, clean up */ -		dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d", +		dev_dbg(&urb->dev->dev, "%s - urb shutting down: %d\n",  			__func__, urb->status);  		break;  	default: -		dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d", +		dev_dbg(&urb->dev->dev, "%s - nonzero urb status: %d\n",  			__func__, urb->status);  	}  } @@ -876,20 +875,14 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)  	for (j = 0; j < NUM_URBS; ++j) {  		urb = usb_alloc_urb(0, GFP_KERNEL);  		mos7840_port->write_urb_pool[j] = urb; - -		if (urb == NULL) { -			dev_err(&port->dev, "No more urbs???\n"); +		if (!urb)  			continue; -		}  		urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,  								GFP_KERNEL);  		if (!urb->transfer_buffer) {  			usb_free_urb(urb);  			mos7840_port->write_urb_pool[j] = NULL; -			dev_err(&port->dev, -				"%s-out of memory for urb buffers.\n", -				__func__);  			continue;  		}  	} @@ -1381,12 +1374,8 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,  	if (urb->transfer_buffer == NULL) {  		urb->transfer_buffer =  		    kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL); - -		if (urb->transfer_buffer == NULL) { -			dev_err_console(port, "%s no more kernel memory...\n", -				__func__); +		if (!urb->transfer_buffer)  			goto exit; -		}  	}  	transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE); @@ -1532,7 +1521,11 @@ static int mos7840_tiocmget(struct tty_struct *tty)  		return -ENODEV;  	status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr); +	if (status != 1) +		return -EIO;  	status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr); +	if (status != 1) +		return -EIO;  	result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)  	    | ((mcr & MCR_RTS) ? TIOCM_RTS : 0)  	    | ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0) @@ -1809,25 +1802,25 @@ static void mos7840_change_port_settings(struct tty_struct *tty,  	iflag = tty->termios.c_iflag;  	/* Change the number of bits */ -	if (cflag & CSIZE) { -		switch (cflag & CSIZE) { -		case CS5: -			lData = LCR_BITS_5; -			break; +	switch (cflag & CSIZE) { +	case CS5: +		lData = LCR_BITS_5; +		break; -		case CS6: -			lData = LCR_BITS_6; -			break; +	case CS6: +		lData = LCR_BITS_6; +		break; -		case CS7: -			lData = LCR_BITS_7; -			break; -		default: -		case CS8: -			lData = LCR_BITS_8; -			break; -		} +	case CS7: +		lData = LCR_BITS_7; +		break; + +	default: +	case CS8: +		lData = LCR_BITS_8; +		break;  	} +  	/* Change the Parity bit */  	if (cflag & PARENB) {  		if (cflag & PARODD) { @@ -2066,8 +2059,6 @@ static int mos7840_ioctl(struct tty_struct *tty,  	if (mos7840_port == NULL)  		return -1; -	dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd); -  	switch (cmd) {  		/* return number of bytes available */ @@ -2204,10 +2195,8 @@ static int mos7840_port_probe(struct usb_serial_port *port)  	dev_dbg(&port->dev, "mos7840_startup: configuring port %d\n", pnum);  	mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); -	if (mos7840_port == NULL) { -		dev_err(&port->dev, "%s - Out of memory\n", __func__); +	if (!mos7840_port)  		return -ENOMEM; -	}  	/* Initialize all port interrupt end point to port 0 int  	 * endpoint. Our device has only one interrupt end point diff --git a/drivers/usb/serial/mxuport.c b/drivers/usb/serial/mxuport.c new file mode 100644 index 00000000000..ab1d690274a --- /dev/null +++ b/drivers/usb/serial/mxuport.c @@ -0,0 +1,1393 @@ +/* + *	mxuport.c - MOXA UPort series driver + * + *	Copyright (c) 2006 Moxa Technologies Co., Ltd. + *	Copyright (c) 2013 Andrew Lunn <andrew@lunn.ch> + * + *	This program is free software; you can redistribute it and/or modify + *	it under the terms of the GNU General Public License as published by + *	the Free Software Foundation; either version 2 of the License, or + *	(at your option) any later version. + * + *	Supports the following Moxa USB to serial converters: + *	 2 ports : UPort 1250, UPort 1250I + *	 4 ports : UPort 1410, UPort 1450, UPort 1450I + *	 8 ports : UPort 1610-8, UPort 1650-8 + *	16 ports : UPort 1610-16, UPort 1650-16 + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/firmware.h> +#include <linux/jiffies.h> +#include <linux/serial.h> +#include <linux/serial_reg.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/uaccess.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <asm/unaligned.h> + +/* Definitions for the vendor ID and device ID */ +#define MX_USBSERIAL_VID	0x110A +#define MX_UPORT1250_PID	0x1250 +#define MX_UPORT1251_PID	0x1251 +#define MX_UPORT1410_PID	0x1410 +#define MX_UPORT1450_PID	0x1450 +#define MX_UPORT1451_PID	0x1451 +#define MX_UPORT1618_PID	0x1618 +#define MX_UPORT1658_PID	0x1658 +#define MX_UPORT1613_PID	0x1613 +#define MX_UPORT1653_PID	0x1653 + +/* Definitions for USB info */ +#define HEADER_SIZE		4 +#define EVENT_LENGTH		8 +#define DOWN_BLOCK_SIZE		64 + +/* Definitions for firmware info */ +#define VER_ADDR_1		0x20 +#define VER_ADDR_2		0x24 +#define VER_ADDR_3		0x28 + +/* Definitions for USB vendor request */ +#define RQ_VENDOR_NONE			0x00 +#define RQ_VENDOR_SET_BAUD		0x01 /* Set baud rate */ +#define RQ_VENDOR_SET_LINE		0x02 /* Set line status */ +#define RQ_VENDOR_SET_CHARS		0x03 /* Set Xon/Xoff chars */ +#define RQ_VENDOR_SET_RTS		0x04 /* Set RTS */ +#define RQ_VENDOR_SET_DTR		0x05 /* Set DTR */ +#define RQ_VENDOR_SET_XONXOFF		0x06 /* Set auto Xon/Xoff */ +#define RQ_VENDOR_SET_RX_HOST_EN	0x07 /* Set RX host enable */ +#define RQ_VENDOR_SET_OPEN		0x08 /* Set open/close port */ +#define RQ_VENDOR_PURGE			0x09 /* Purge Rx/Tx buffer */ +#define RQ_VENDOR_SET_MCR		0x0A /* Set MCR register */ +#define RQ_VENDOR_SET_BREAK		0x0B /* Set Break signal */ + +#define RQ_VENDOR_START_FW_DOWN		0x0C /* Start firmware download */ +#define RQ_VENDOR_STOP_FW_DOWN		0x0D /* Stop firmware download */ +#define RQ_VENDOR_QUERY_FW_READY	0x0E /* Query if new firmware ready */ + +#define RQ_VENDOR_SET_FIFO_DISABLE	0x0F /* Set fifo disable */ +#define RQ_VENDOR_SET_INTERFACE		0x10 /* Set interface */ +#define RQ_VENDOR_SET_HIGH_PERFOR	0x11 /* Set hi-performance */ + +#define RQ_VENDOR_ERASE_BLOCK		0x12 /* Erase flash block */ +#define RQ_VENDOR_WRITE_PAGE		0x13 /* Write flash page */ +#define RQ_VENDOR_PREPARE_WRITE		0x14 /* Prepare write flash */ +#define RQ_VENDOR_CONFIRM_WRITE		0x15 /* Confirm write flash */ +#define RQ_VENDOR_LOCATE		0x16 /* Locate the device */ + +#define RQ_VENDOR_START_ROM_DOWN	0x17 /* Start firmware download */ +#define RQ_VENDOR_ROM_DATA		0x18 /* Rom file data */ +#define RQ_VENDOR_STOP_ROM_DOWN		0x19 /* Stop firmware download */ +#define RQ_VENDOR_FW_DATA		0x20 /* Firmware data */ + +#define RQ_VENDOR_RESET_DEVICE		0x23 /* Try to reset the device */ +#define RQ_VENDOR_QUERY_FW_CONFIG	0x24 + +#define RQ_VENDOR_GET_VERSION		0x81 /* Get firmware version */ +#define RQ_VENDOR_GET_PAGE		0x82 /* Read flash page */ +#define RQ_VENDOR_GET_ROM_PROC		0x83 /* Get ROM process state */ + +#define RQ_VENDOR_GET_INQUEUE		0x84 /* Data in input buffer */ +#define RQ_VENDOR_GET_OUTQUEUE		0x85 /* Data in output buffer */ + +#define RQ_VENDOR_GET_MSR		0x86 /* Get modem status register */ + +/* Definitions for UPort event type */ +#define UPORT_EVENT_NONE		0 /* None */ +#define UPORT_EVENT_TXBUF_THRESHOLD	1 /* Tx buffer threshold */ +#define UPORT_EVENT_SEND_NEXT		2 /* Send next */ +#define UPORT_EVENT_MSR			3 /* Modem status */ +#define UPORT_EVENT_LSR			4 /* Line status */ +#define UPORT_EVENT_MCR			5 /* Modem control */ + +/* Definitions for serial event type */ +#define SERIAL_EV_CTS			0x0008	/* CTS changed state */ +#define SERIAL_EV_DSR			0x0010	/* DSR changed state */ +#define SERIAL_EV_RLSD			0x0020	/* RLSD changed state */ + +/* Definitions for modem control event type */ +#define SERIAL_EV_XOFF			0x40	/* XOFF received */ + +/* Definitions for line control of communication */ +#define MX_WORDLENGTH_5			5 +#define MX_WORDLENGTH_6			6 +#define MX_WORDLENGTH_7			7 +#define MX_WORDLENGTH_8			8 + +#define MX_PARITY_NONE			0 +#define MX_PARITY_ODD			1 +#define MX_PARITY_EVEN			2 +#define MX_PARITY_MARK			3 +#define MX_PARITY_SPACE			4 + +#define MX_STOP_BITS_1			0 +#define MX_STOP_BITS_1_5		1 +#define MX_STOP_BITS_2			2 + +#define MX_RTS_DISABLE			0x0 +#define MX_RTS_ENABLE			0x1 +#define MX_RTS_HW			0x2 +#define MX_RTS_NO_CHANGE		0x3 /* Flag, not valid register value*/ + +#define MX_INT_RS232			0 +#define MX_INT_2W_RS485			1 +#define MX_INT_RS422			2 +#define MX_INT_4W_RS485			3 + +/* Definitions for holding reason */ +#define MX_WAIT_FOR_CTS			0x0001 +#define MX_WAIT_FOR_DSR			0x0002 +#define MX_WAIT_FOR_DCD			0x0004 +#define MX_WAIT_FOR_XON			0x0008 +#define MX_WAIT_FOR_START_TX		0x0010 +#define MX_WAIT_FOR_UNTHROTTLE		0x0020 +#define MX_WAIT_FOR_LOW_WATER		0x0040 +#define MX_WAIT_FOR_SEND_NEXT		0x0080 + +#define MX_UPORT_2_PORT			BIT(0) +#define MX_UPORT_4_PORT			BIT(1) +#define MX_UPORT_8_PORT			BIT(2) +#define MX_UPORT_16_PORT		BIT(3) + +/* This structure holds all of the local port information */ +struct mxuport_port { +	u8 mcr_state;		/* Last MCR state */ +	u8 msr_state;		/* Last MSR state */ +	struct mutex mutex;	/* Protects mcr_state */ +	spinlock_t spinlock;	/* Protects msr_state */ +}; + +/* Table of devices that work with this driver */ +static const struct usb_device_id mxuport_idtable[] = { +	{ USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1250_PID), +	  .driver_info = MX_UPORT_2_PORT }, +	{ USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1251_PID), +	  .driver_info = MX_UPORT_2_PORT }, +	{ USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1410_PID), +	  .driver_info = MX_UPORT_4_PORT }, +	{ USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1450_PID), +	  .driver_info = MX_UPORT_4_PORT }, +	{ USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1451_PID), +	  .driver_info = MX_UPORT_4_PORT }, +	{ USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1618_PID), +	  .driver_info = MX_UPORT_8_PORT }, +	{ USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1658_PID), +	  .driver_info = MX_UPORT_8_PORT }, +	{ USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1613_PID), +	  .driver_info = MX_UPORT_16_PORT }, +	{ USB_DEVICE(MX_USBSERIAL_VID, MX_UPORT1653_PID), +	  .driver_info = MX_UPORT_16_PORT }, +	{}			/* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, mxuport_idtable); + +/* + * Add a four byte header containing the port number and the number of + * bytes of data in the message. Return the number of bytes in the + * buffer. + */ +static int mxuport_prepare_write_buffer(struct usb_serial_port *port, +					void *dest, size_t size) +{ +	u8 *buf = dest; +	int count; + +	count = kfifo_out_locked(&port->write_fifo, buf + HEADER_SIZE, +				 size - HEADER_SIZE, +				 &port->lock); + +	put_unaligned_be16(port->port_number, buf); +	put_unaligned_be16(count, buf + 2); + +	dev_dbg(&port->dev, "%s - size %zd count %d\n", __func__, +		size, count); + +	return count + HEADER_SIZE; +} + +/* Read the given buffer in from the control pipe. */ +static int mxuport_recv_ctrl_urb(struct usb_serial *serial, +				 u8 request, u16 value, u16 index, +				 u8 *data, size_t size) +{ +	int status; + +	status = usb_control_msg(serial->dev, +				 usb_rcvctrlpipe(serial->dev, 0), +				 request, +				 (USB_DIR_IN | USB_TYPE_VENDOR | +				  USB_RECIP_DEVICE), value, index, +				 data, size, +				 USB_CTRL_GET_TIMEOUT); +	if (status < 0) { +		dev_err(&serial->interface->dev, +			"%s - usb_control_msg failed (%d)\n", +			__func__, status); +		return status; +	} + +	if (status != size) { +		dev_err(&serial->interface->dev, +			"%s - short read (%d / %zd)\n", +			__func__, status, size); +		return -EIO; +	} + +	return status; +} + +/* Write the given buffer out to the control pipe.  */ +static int mxuport_send_ctrl_data_urb(struct usb_serial *serial, +				      u8 request, +				      u16 value, u16 index, +				      u8 *data, size_t size) +{ +	int status; + +	status = usb_control_msg(serial->dev, +				 usb_sndctrlpipe(serial->dev, 0), +				 request, +				 (USB_DIR_OUT | USB_TYPE_VENDOR | +				  USB_RECIP_DEVICE), value, index, +				 data, size, +				 USB_CTRL_SET_TIMEOUT); +	if (status < 0) { +		dev_err(&serial->interface->dev, +			"%s - usb_control_msg failed (%d)\n", +			__func__, status); +		return status; +	} + +	if (status != size) { +		dev_err(&serial->interface->dev, +			"%s - short write (%d / %zd)\n", +			__func__, status, size); +		return -EIO; +	} + +	return 0; +} + +/* Send a vendor request without any data */ +static int mxuport_send_ctrl_urb(struct usb_serial *serial, +				 u8 request, u16 value, u16 index) +{ +	return mxuport_send_ctrl_data_urb(serial, request, value, index, +					  NULL, 0); +} + +/* + * mxuport_throttle - throttle function of driver + * + * This function is called by the tty driver when it wants to stop the + * data being read from the port. Since all the data comes over one + * bulk in endpoint, we cannot stop submitting urbs by setting + * port->throttle. Instead tell the device to stop sending us data for + * the port. + */ +static void mxuport_throttle(struct tty_struct *tty) +{ +	struct usb_serial_port *port = tty->driver_data; +	struct usb_serial *serial = port->serial; + +	dev_dbg(&port->dev, "%s\n", __func__); + +	mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN, +			      0, port->port_number); +} + +/* + * mxuport_unthrottle - unthrottle function of driver + * + * This function is called by the tty driver when it wants to resume + * the data being read from the port. Tell the device it can resume + * sending us received data from the port. + */ +static void mxuport_unthrottle(struct tty_struct *tty) +{ + +	struct usb_serial_port *port = tty->driver_data; +	struct usb_serial *serial = port->serial; + +	dev_dbg(&port->dev, "%s\n", __func__); + +	mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN, +			      1, port->port_number); +} + +/* + * Processes one chunk of data received for a port.  Mostly a copy of + * usb_serial_generic_process_read_urb(). + */ +static void mxuport_process_read_urb_data(struct usb_serial_port *port, +					  char *data, int size) +{ +	int i; + +	if (!port->port.console || !port->sysrq) { +		tty_insert_flip_string(&port->port, data, size); +	} else { +		for (i = 0; i < size; i++, data++) { +			if (!usb_serial_handle_sysrq_char(port, *data)) +				tty_insert_flip_char(&port->port, *data, +						     TTY_NORMAL); +		} +	} +	tty_flip_buffer_push(&port->port); +} + +static void mxuport_msr_event(struct usb_serial_port *port, u8 buf[4]) +{ +	struct mxuport_port *mxport = usb_get_serial_port_data(port); +	u8 rcv_msr_hold = buf[2] & 0xF0; +	u16 rcv_msr_event = get_unaligned_be16(buf); +	unsigned long flags; + +	if (rcv_msr_event == 0) +		return; + +	/* Update MSR status */ +	spin_lock_irqsave(&mxport->spinlock, flags); + +	dev_dbg(&port->dev, "%s - current MSR status = 0x%x\n", +		__func__, mxport->msr_state); + +	if (rcv_msr_hold & UART_MSR_CTS) { +		mxport->msr_state |= UART_MSR_CTS; +		dev_dbg(&port->dev, "%s - CTS high\n", __func__); +	} else { +		mxport->msr_state &= ~UART_MSR_CTS; +		dev_dbg(&port->dev, "%s - CTS low\n", __func__); +	} + +	if (rcv_msr_hold & UART_MSR_DSR) { +		mxport->msr_state |= UART_MSR_DSR; +		dev_dbg(&port->dev, "%s - DSR high\n", __func__); +	} else { +		mxport->msr_state &= ~UART_MSR_DSR; +		dev_dbg(&port->dev, "%s - DSR low\n", __func__); +	} + +	if (rcv_msr_hold & UART_MSR_DCD) { +		mxport->msr_state |= UART_MSR_DCD; +		dev_dbg(&port->dev, "%s - DCD high\n", __func__); +	} else { +		mxport->msr_state &= ~UART_MSR_DCD; +		dev_dbg(&port->dev, "%s - DCD low\n", __func__); +	} +	spin_unlock_irqrestore(&mxport->spinlock, flags); + +	if (rcv_msr_event & +	    (SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD)) { + +		if (rcv_msr_event & SERIAL_EV_CTS) { +			port->icount.cts++; +			dev_dbg(&port->dev, "%s - CTS change\n", __func__); +		} + +		if (rcv_msr_event & SERIAL_EV_DSR) { +			port->icount.dsr++; +			dev_dbg(&port->dev, "%s - DSR change\n", __func__); +		} + +		if (rcv_msr_event & SERIAL_EV_RLSD) { +			port->icount.dcd++; +			dev_dbg(&port->dev, "%s - DCD change\n", __func__); +		} +		wake_up_interruptible(&port->port.delta_msr_wait); +	} +} + +static void mxuport_lsr_event(struct usb_serial_port *port, u8 buf[4]) +{ +	u8 lsr_event = buf[2]; + +	if (lsr_event & UART_LSR_BI) { +		port->icount.brk++; +		dev_dbg(&port->dev, "%s - break error\n", __func__); +	} + +	if (lsr_event & UART_LSR_FE) { +		port->icount.frame++; +		dev_dbg(&port->dev, "%s - frame error\n", __func__); +	} + +	if (lsr_event & UART_LSR_PE) { +		port->icount.parity++; +		dev_dbg(&port->dev, "%s - parity error\n", __func__); +	} + +	if (lsr_event & UART_LSR_OE) { +		port->icount.overrun++; +		dev_dbg(&port->dev, "%s - overrun error\n", __func__); +	} +} + +/* + * When something interesting happens, modem control lines XON/XOFF + * etc, the device sends an event. Process these events. + */ +static void mxuport_process_read_urb_event(struct usb_serial_port *port, +					   u8 buf[4], u32 event) +{ +	dev_dbg(&port->dev, "%s - receive event : %04x\n", __func__, event); + +	switch (event) { +	case UPORT_EVENT_SEND_NEXT: +		/* +		 * Sent as part of the flow control on device buffers. +		 * Not currently used. +		 */ +		break; +	case UPORT_EVENT_MSR: +		mxuport_msr_event(port, buf); +		break; +	case UPORT_EVENT_LSR: +		mxuport_lsr_event(port, buf); +		break; +	case UPORT_EVENT_MCR: +		/* +		 * Event to indicate a change in XON/XOFF from the +		 * peer.  Currently not used. We just continue +		 * sending the device data and it will buffer it if +		 * needed. This event could be used for flow control +		 * between the host and the device. +		 */ +		break; +	default: +		dev_dbg(&port->dev, "Unexpected event\n"); +		break; +	} +} + +/* + * One URB can contain data for multiple ports. Demultiplex the data, + * checking the port exists, is opened and the message is valid. + */ +static void mxuport_process_read_urb_demux_data(struct urb *urb) +{ +	struct usb_serial_port *port = urb->context; +	struct usb_serial *serial = port->serial; +	u8 *data = urb->transfer_buffer; +	u8 *end = data + urb->actual_length; +	struct usb_serial_port *demux_port; +	u8 *ch; +	u16 rcv_port; +	u16 rcv_len; + +	while (data < end) { +		if (data + HEADER_SIZE > end) { +			dev_warn(&port->dev, "%s - message with short header\n", +				 __func__); +			return; +		} + +		rcv_port = get_unaligned_be16(data); +		if (rcv_port >= serial->num_ports) { +			dev_warn(&port->dev, "%s - message for invalid port\n", +				 __func__); +			return; +		} + +		demux_port = serial->port[rcv_port]; +		rcv_len = get_unaligned_be16(data + 2); +		if (!rcv_len || data + HEADER_SIZE + rcv_len > end) { +			dev_warn(&port->dev, "%s - short data\n", __func__); +			return; +		} + +		if (test_bit(ASYNCB_INITIALIZED, &demux_port->port.flags)) { +			ch = data + HEADER_SIZE; +			mxuport_process_read_urb_data(demux_port, ch, rcv_len); +		} else { +			dev_dbg(&demux_port->dev, "%s - data for closed port\n", +				__func__); +		} +		data += HEADER_SIZE + rcv_len; +	} +} + +/* + * One URB can contain events for multiple ports. Demultiplex the event, + * checking the port exists, and is opened. + */ +static void mxuport_process_read_urb_demux_event(struct urb *urb) +{ +	struct usb_serial_port *port = urb->context; +	struct usb_serial *serial = port->serial; +	u8 *data = urb->transfer_buffer; +	u8 *end = data + urb->actual_length; +	struct usb_serial_port *demux_port; +	u8 *ch; +	u16 rcv_port; +	u16 rcv_event; + +	while (data < end) { +		if (data + EVENT_LENGTH > end) { +			dev_warn(&port->dev, "%s - message with short event\n", +				 __func__); +			return; +		} + +		rcv_port = get_unaligned_be16(data); +		if (rcv_port >= serial->num_ports) { +			dev_warn(&port->dev, "%s - message for invalid port\n", +				 __func__); +			return; +		} + +		demux_port = serial->port[rcv_port]; +		if (test_bit(ASYNCB_INITIALIZED, &demux_port->port.flags)) { +			ch = data + HEADER_SIZE; +			rcv_event = get_unaligned_be16(data + 2); +			mxuport_process_read_urb_event(demux_port, ch, +						       rcv_event); +		} else { +			dev_dbg(&demux_port->dev, +				"%s - event for closed port\n", __func__); +		} +		data += EVENT_LENGTH; +	} +} + +/* + * This is called when we have received data on the bulk in + * endpoint. Depending on which port it was received on, it can + * contain serial data or events. + */ +static void mxuport_process_read_urb(struct urb *urb) +{ +	struct usb_serial_port *port = urb->context; +	struct usb_serial *serial = port->serial; + +	if (port == serial->port[0]) +		mxuport_process_read_urb_demux_data(urb); + +	if (port == serial->port[1]) +		mxuport_process_read_urb_demux_event(urb); +} + +/* + * Ask the device how many bytes it has queued to be sent out. If + * there are none, return true. + */ +static bool mxuport_tx_empty(struct usb_serial_port *port) +{ +	struct usb_serial *serial = port->serial; +	bool is_empty = true; +	u32 txlen; +	u8 *len_buf; +	int err; + +	len_buf = kzalloc(4, GFP_KERNEL); +	if (!len_buf) +		goto out; + +	err = mxuport_recv_ctrl_urb(serial, RQ_VENDOR_GET_OUTQUEUE, 0, +				    port->port_number, len_buf, 4); +	if (err < 0) +		goto out; + +	txlen = get_unaligned_be32(len_buf); +	dev_dbg(&port->dev, "%s - tx len = %u\n", __func__, txlen); + +	if (txlen != 0) +		is_empty = false; + +out: +	kfree(len_buf); +	return is_empty; +} + +static int mxuport_set_mcr(struct usb_serial_port *port, u8 mcr_state) +{ +	struct usb_serial *serial = port->serial; +	int err; + +	dev_dbg(&port->dev, "%s - %02x\n", __func__, mcr_state); + +	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_MCR, +				    mcr_state, port->port_number); +	if (err) +		dev_err(&port->dev, "%s - failed to change MCR\n", __func__); + +	return err; +} + +static int mxuport_set_dtr(struct usb_serial_port *port, int on) +{ +	struct mxuport_port *mxport = usb_get_serial_port_data(port); +	struct usb_serial *serial = port->serial; +	int err; + +	mutex_lock(&mxport->mutex); + +	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_DTR, +				    !!on, port->port_number); +	if (!err) { +		if (on) +			mxport->mcr_state |= UART_MCR_DTR; +		else +			mxport->mcr_state &= ~UART_MCR_DTR; +	} + +	mutex_unlock(&mxport->mutex); + +	return err; +} + +static int mxuport_set_rts(struct usb_serial_port *port, u8 state) +{ +	struct mxuport_port *mxport = usb_get_serial_port_data(port); +	struct usb_serial *serial = port->serial; +	int err; +	u8 mcr_state; + +	mutex_lock(&mxport->mutex); +	mcr_state = mxport->mcr_state; + +	switch (state) { +	case MX_RTS_DISABLE: +		mcr_state &= ~UART_MCR_RTS; +		break; +	case MX_RTS_ENABLE: +		mcr_state |= UART_MCR_RTS; +		break; +	case MX_RTS_HW: +		/* +		 * Do not update mxport->mcr_state when doing hardware +		 * flow control. +		 */ +		break; +	default: +		/* +		 * Should not happen, but somebody might try passing +		 * MX_RTS_NO_CHANGE, which is not valid. +		 */ +		err = -EINVAL; +		goto out; +	} +	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RTS, +				    state, port->port_number); +	if (!err) +		mxport->mcr_state = mcr_state; + +out: +	mutex_unlock(&mxport->mutex); + +	return err; +} + +static void mxuport_dtr_rts(struct usb_serial_port *port, int on) +{ +	struct mxuport_port *mxport = usb_get_serial_port_data(port); +	u8 mcr_state; +	int err; + +	mutex_lock(&mxport->mutex); +	mcr_state = mxport->mcr_state; + +	if (on) +		mcr_state |= (UART_MCR_RTS | UART_MCR_DTR); +	else +		mcr_state &= ~(UART_MCR_RTS | UART_MCR_DTR); + +	err = mxuport_set_mcr(port, mcr_state); +	if (!err) +		mxport->mcr_state = mcr_state; + +	mutex_unlock(&mxport->mutex); +} + +static int mxuport_tiocmset(struct tty_struct *tty, unsigned int set, +			    unsigned int clear) +{ +	struct usb_serial_port *port = tty->driver_data; +	struct mxuport_port *mxport = usb_get_serial_port_data(port); +	int err; +	u8 mcr_state; + +	mutex_lock(&mxport->mutex); +	mcr_state = mxport->mcr_state; + +	if (set & TIOCM_RTS) +		mcr_state |= UART_MCR_RTS; + +	if (set & TIOCM_DTR) +		mcr_state |= UART_MCR_DTR; + +	if (clear & TIOCM_RTS) +		mcr_state &= ~UART_MCR_RTS; + +	if (clear & TIOCM_DTR) +		mcr_state &= ~UART_MCR_DTR; + +	err = mxuport_set_mcr(port, mcr_state); +	if (!err) +		mxport->mcr_state = mcr_state; + +	mutex_unlock(&mxport->mutex); + +	return err; +} + +static int mxuport_tiocmget(struct tty_struct *tty) +{ +	struct mxuport_port *mxport; +	struct usb_serial_port *port = tty->driver_data; +	unsigned int result; +	unsigned long flags; +	unsigned int msr; +	unsigned int mcr; + +	mxport = usb_get_serial_port_data(port); + +	mutex_lock(&mxport->mutex); +	spin_lock_irqsave(&mxport->spinlock, flags); + +	msr = mxport->msr_state; +	mcr = mxport->mcr_state; + +	spin_unlock_irqrestore(&mxport->spinlock, flags); +	mutex_unlock(&mxport->mutex); + +	result = (((mcr & UART_MCR_DTR) ? TIOCM_DTR : 0) |	/* 0x002 */ +		  ((mcr & UART_MCR_RTS) ? TIOCM_RTS : 0) |	/* 0x004 */ +		  ((msr & UART_MSR_CTS) ? TIOCM_CTS : 0) |	/* 0x020 */ +		  ((msr & UART_MSR_DCD) ? TIOCM_CAR : 0) |	/* 0x040 */ +		  ((msr & UART_MSR_RI) ? TIOCM_RI : 0) |	/* 0x080 */ +		  ((msr & UART_MSR_DSR) ? TIOCM_DSR : 0));	/* 0x100 */ + +	dev_dbg(&port->dev, "%s - 0x%04x\n", __func__, result); + +	return result; +} + +static int mxuport_set_termios_flow(struct tty_struct *tty, +				    struct ktermios *old_termios, +				    struct usb_serial_port *port, +				    struct usb_serial *serial) +{ +	u8 xon = START_CHAR(tty); +	u8 xoff = STOP_CHAR(tty); +	int enable; +	int err; +	u8 *buf; +	u8 rts; + +	buf = kmalloc(2, GFP_KERNEL); +	if (!buf) +		return -ENOMEM; + +	/* S/W flow control settings */ +	if (I_IXOFF(tty) || I_IXON(tty)) { +		enable = 1; +		buf[0] = xon; +		buf[1] = xoff; + +		err = mxuport_send_ctrl_data_urb(serial, RQ_VENDOR_SET_CHARS, +						 0, port->port_number, +						 buf, 2); +		if (err) +			goto out; + +		dev_dbg(&port->dev, "%s - XON = 0x%02x, XOFF = 0x%02x\n", +			__func__, xon, xoff); +	} else { +		enable = 0; +	} + +	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_XONXOFF, +				    enable, port->port_number); +	if (err) +		goto out; + +	rts = MX_RTS_NO_CHANGE; + +	/* H/W flow control settings */ +	if (!old_termios || +	    C_CRTSCTS(tty) != (old_termios->c_cflag & CRTSCTS)) { +		if (C_CRTSCTS(tty)) +			rts = MX_RTS_HW; +		else +			rts = MX_RTS_ENABLE; +	} + +	if (C_BAUD(tty)) { +		if (old_termios && (old_termios->c_cflag & CBAUD) == B0) { +			/* Raise DTR and RTS */ +			if (C_CRTSCTS(tty)) +				rts = MX_RTS_HW; +			else +				rts = MX_RTS_ENABLE; +			mxuport_set_dtr(port, 1); +		} +	} else { +		/* Drop DTR and RTS */ +		rts = MX_RTS_DISABLE; +		mxuport_set_dtr(port, 0); +	} + +	if (rts != MX_RTS_NO_CHANGE) +		err = mxuport_set_rts(port, rts); + +out: +	kfree(buf); +	return err; +} + +static void mxuport_set_termios(struct tty_struct *tty, +				struct usb_serial_port *port, +				struct ktermios *old_termios) +{ +	struct usb_serial *serial = port->serial; +	u8 *buf; +	u8 data_bits; +	u8 stop_bits; +	u8 parity; +	int baud; +	int err; + +	if (old_termios && +	    !tty_termios_hw_change(&tty->termios, old_termios) && +	    tty->termios.c_iflag == old_termios->c_iflag) { +		dev_dbg(&port->dev, "%s - nothing to change\n", __func__); +		return; +	} + +	buf = kmalloc(4, GFP_KERNEL); +	if (!buf) +		return; + +	/* Set data bit of termios */ +	switch (C_CSIZE(tty)) { +	case CS5: +		data_bits = MX_WORDLENGTH_5; +		break; +	case CS6: +		data_bits = MX_WORDLENGTH_6; +		break; +	case CS7: +		data_bits = MX_WORDLENGTH_7; +		break; +	case CS8: +	default: +		data_bits = MX_WORDLENGTH_8; +		break; +	} + +	/* Set parity of termios */ +	if (C_PARENB(tty)) { +		if (C_CMSPAR(tty)) { +			if (C_PARODD(tty)) +				parity = MX_PARITY_MARK; +			else +				parity = MX_PARITY_SPACE; +		} else { +			if (C_PARODD(tty)) +				parity = MX_PARITY_ODD; +			else +				parity = MX_PARITY_EVEN; +		} +	} else { +		parity = MX_PARITY_NONE; +	} + +	/* Set stop bit of termios */ +	if (C_CSTOPB(tty)) +		stop_bits = MX_STOP_BITS_2; +	else +		stop_bits = MX_STOP_BITS_1; + +	buf[0] = data_bits; +	buf[1] = parity; +	buf[2] = stop_bits; +	buf[3] = 0; + +	err = mxuport_send_ctrl_data_urb(serial, RQ_VENDOR_SET_LINE, +					 0, port->port_number, buf, 4); +	if (err) +		goto out; + +	err = mxuport_set_termios_flow(tty, old_termios, port, serial); +	if (err) +		goto out; + +	baud = tty_get_baud_rate(tty); +	if (!baud) +		baud = 9600; + +	/* Note: Little Endian */ +	put_unaligned_le32(baud, buf); + +	err = mxuport_send_ctrl_data_urb(serial, RQ_VENDOR_SET_BAUD, +					 0, port->port_number, +					 buf, 4); +	if (err) +		goto out; + +	dev_dbg(&port->dev, "baud_rate	: %d\n", baud); +	dev_dbg(&port->dev, "data_bits	: %d\n", data_bits); +	dev_dbg(&port->dev, "parity	: %d\n", parity); +	dev_dbg(&port->dev, "stop_bits	: %d\n", stop_bits); + +out: +	kfree(buf); +} + +/* + * Determine how many ports this device has dynamically.  It will be + * called after the probe() callback is called, but before attach(). + */ +static int mxuport_calc_num_ports(struct usb_serial *serial) +{ +	unsigned long features = (unsigned long)usb_get_serial_data(serial); + +	if (features & MX_UPORT_2_PORT) +		return 2; +	if (features & MX_UPORT_4_PORT) +		return 4; +	if (features & MX_UPORT_8_PORT) +		return 8; +	if (features & MX_UPORT_16_PORT) +		return 16; + +	return 0; +} + +/* Get the version of the firmware currently running. */ +static int mxuport_get_fw_version(struct usb_serial *serial, u32 *version) +{ +	u8 *ver_buf; +	int err; + +	ver_buf = kzalloc(4, GFP_KERNEL); +	if (!ver_buf) +		return -ENOMEM; + +	/* Get firmware version from SDRAM */ +	err = mxuport_recv_ctrl_urb(serial, RQ_VENDOR_GET_VERSION, 0, 0, +				    ver_buf, 4); +	if (err != 4) { +		err = -EIO; +		goto out; +	} + +	*version = (ver_buf[0] << 16) | (ver_buf[1] << 8) | ver_buf[2]; +	err = 0; +out: +	kfree(ver_buf); +	return err; +} + +/* Given a firmware blob, download it to the device. */ +static int mxuport_download_fw(struct usb_serial *serial, +			       const struct firmware *fw_p) +{ +	u8 *fw_buf; +	size_t txlen; +	size_t fwidx; +	int err; + +	fw_buf = kmalloc(DOWN_BLOCK_SIZE, GFP_KERNEL); +	if (!fw_buf) +		return -ENOMEM; + +	dev_dbg(&serial->interface->dev, "Starting firmware download...\n"); +	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_START_FW_DOWN, 0, 0); +	if (err) +		goto out; + +	fwidx = 0; +	do { +		txlen = min_t(size_t, (fw_p->size - fwidx), DOWN_BLOCK_SIZE); + +		memcpy(fw_buf, &fw_p->data[fwidx], txlen); +		err = mxuport_send_ctrl_data_urb(serial, RQ_VENDOR_FW_DATA, +						 0, 0, fw_buf, txlen); +		if (err) { +			mxuport_send_ctrl_urb(serial, RQ_VENDOR_STOP_FW_DOWN, +					      0, 0); +			goto out; +		} + +		fwidx += txlen; +		usleep_range(1000, 2000); + +	} while (fwidx < fw_p->size); + +	msleep(1000); +	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_STOP_FW_DOWN, 0, 0); +	if (err) +		goto out; + +	msleep(1000); +	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_QUERY_FW_READY, 0, 0); + +out: +	kfree(fw_buf); +	return err; +} + +static int mxuport_probe(struct usb_serial *serial, +			 const struct usb_device_id *id) +{ +	u16 productid = le16_to_cpu(serial->dev->descriptor.idProduct); +	const struct firmware *fw_p = NULL; +	u32 version; +	int local_ver; +	char buf[32]; +	int err; + +	/* Load our firmware */ +	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_QUERY_FW_CONFIG, 0, 0); +	if (err) { +		mxuport_send_ctrl_urb(serial, RQ_VENDOR_RESET_DEVICE, 0, 0); +		return err; +	} + +	err = mxuport_get_fw_version(serial, &version); +	if (err < 0) +		return err; + +	dev_dbg(&serial->interface->dev, "Device firmware version v%x.%x.%x\n", +		(version & 0xff0000) >> 16, +		(version & 0xff00) >> 8, +		(version & 0xff)); + +	snprintf(buf, sizeof(buf) - 1, "moxa/moxa-%04x.fw", productid); + +	err = request_firmware(&fw_p, buf, &serial->interface->dev); +	if (err) { +		dev_warn(&serial->interface->dev, "Firmware %s not found\n", +			 buf); + +		/* Use the firmware already in the device */ +		err = 0; +	} else { +		local_ver = ((fw_p->data[VER_ADDR_1] << 16) | +			     (fw_p->data[VER_ADDR_2] << 8) | +			     fw_p->data[VER_ADDR_3]); +		dev_dbg(&serial->interface->dev, +			"Available firmware version v%x.%x.%x\n", +			fw_p->data[VER_ADDR_1], fw_p->data[VER_ADDR_2], +			fw_p->data[VER_ADDR_3]); +		if (local_ver > version) { +			err = mxuport_download_fw(serial, fw_p); +			if (err) +				goto out; +			err  = mxuport_get_fw_version(serial, &version); +			if (err < 0) +				goto out; +		} +	} + +	dev_info(&serial->interface->dev, +		 "Using device firmware version v%x.%x.%x\n", +		 (version & 0xff0000) >> 16, +		 (version & 0xff00) >> 8, +		 (version & 0xff)); + +	/* +	 * Contains the features of this hardware. Store away for +	 * later use, eg, number of ports. +	 */ +	usb_set_serial_data(serial, (void *)id->driver_info); +out: +	if (fw_p) +		release_firmware(fw_p); +	return err; +} + + +static int mxuport_port_probe(struct usb_serial_port *port) +{ +	struct usb_serial *serial = port->serial; +	struct mxuport_port *mxport; +	int err; + +	mxport = devm_kzalloc(&port->dev, sizeof(struct mxuport_port), +			      GFP_KERNEL); +	if (!mxport) +		return -ENOMEM; + +	mutex_init(&mxport->mutex); +	spin_lock_init(&mxport->spinlock); + +	/* Set the port private data */ +	usb_set_serial_port_data(port, mxport); + +	/* Set FIFO (Enable) */ +	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_FIFO_DISABLE, +				    0, port->port_number); +	if (err) +		return err; + +	/* Set transmission mode (Hi-Performance) */ +	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_HIGH_PERFOR, +				    0, port->port_number); +	if (err) +		return err; + +	/* Set interface (RS-232) */ +	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_INTERFACE, +				    MX_INT_RS232, +				    port->port_number); +	if (err) +		return err; + +	return 0; +} + +static int mxuport_alloc_write_urb(struct usb_serial *serial, +				   struct usb_serial_port *port, +				   struct usb_serial_port *port0, +				   int j) +{ +	struct usb_device *dev = interface_to_usbdev(serial->interface); + +	set_bit(j, &port->write_urbs_free); +	port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL); +	if (!port->write_urbs[j]) +		return -ENOMEM; + +	port->bulk_out_buffers[j] = kmalloc(port0->bulk_out_size, GFP_KERNEL); +	if (!port->bulk_out_buffers[j]) +		return -ENOMEM; + +	usb_fill_bulk_urb(port->write_urbs[j], dev, +			  usb_sndbulkpipe(dev, port->bulk_out_endpointAddress), +			  port->bulk_out_buffers[j], +			  port->bulk_out_size, +			  serial->type->write_bulk_callback, +			  port); +	return 0; +} + + +static int mxuport_alloc_write_urbs(struct usb_serial *serial, +				    struct usb_serial_port *port, +				    struct usb_serial_port *port0) +{ +	int j; +	int ret; + +	for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) { +		ret = mxuport_alloc_write_urb(serial, port, port0, j); +		if (ret) +			return ret; +	} +	return 0; +} + + +static int mxuport_attach(struct usb_serial *serial) +{ +	struct usb_serial_port *port0 = serial->port[0]; +	struct usb_serial_port *port1 = serial->port[1]; +	struct usb_serial_port *port; +	int err; +	int i; +	int j; + +	/* +	 * Throw away all but the first allocated write URBs so we can +	 * set them up again to fit the multiplexing scheme. +	 */ +	for (i = 1; i < serial->num_bulk_out; ++i) { +		port = serial->port[i]; +		for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) { +			usb_free_urb(port->write_urbs[j]); +			kfree(port->bulk_out_buffers[j]); +			port->write_urbs[j] = NULL; +			port->bulk_out_buffers[j] = NULL; +		} +		port->write_urbs_free = 0; +	} + +	/* +	 * All write data is sent over the first bulk out endpoint, +	 * with an added header to indicate the port. Allocate URBs +	 * for each port to the first bulk out endpoint. +	 */ +	for (i = 1; i < serial->num_ports; ++i) { +		port = serial->port[i]; +		port->bulk_out_size = port0->bulk_out_size; +		port->bulk_out_endpointAddress = +			port0->bulk_out_endpointAddress; + +		err = mxuport_alloc_write_urbs(serial, port, port0); +		if (err) +			return err; + +		port->write_urb = port->write_urbs[0]; +		port->bulk_out_buffer = port->bulk_out_buffers[0]; + +		/* +		 * Ensure each port has a fifo. The framework only +		 * allocates a fifo to ports with a bulk out endpoint, +		 * where as we need one for every port. +		 */ +		if (!kfifo_initialized(&port->write_fifo)) { +			err = kfifo_alloc(&port->write_fifo, PAGE_SIZE, +					  GFP_KERNEL); +			if (err) +				return err; +		} +	} + +	/* +	 * All data from the ports is received on the first bulk in +	 * endpoint, with a multiplex header. The second bulk in is +	 * used for events. +	 * +	 * Start to read from the device. +	 */ +	err = usb_serial_generic_submit_read_urbs(port0, GFP_KERNEL); +	if (err) +		return err; + +	err = usb_serial_generic_submit_read_urbs(port1, GFP_KERNEL); +	if (err) { +		usb_serial_generic_close(port0); +		return err; +	} + +	return 0; +} + +static int mxuport_open(struct tty_struct *tty, struct usb_serial_port *port) +{ +	struct mxuport_port *mxport = usb_get_serial_port_data(port); +	struct usb_serial *serial = port->serial; +	int err; + +	/* Set receive host (enable) */ +	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN, +				    1, port->port_number); +	if (err) +		return err; + +	err = mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_OPEN, +				    1, port->port_number); +	if (err) { +		mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN, +				      0, port->port_number); +		return err; +	} + +	/* Initial port termios */ +	mxuport_set_termios(tty, port, NULL); + +	/* +	 * TODO: use RQ_VENDOR_GET_MSR, once we know what it +	 * returns. +	 */ +	mxport->msr_state = 0; + +	return err; +} + +static void mxuport_close(struct usb_serial_port *port) +{ +	struct usb_serial *serial = port->serial; + +	mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_OPEN, 0, +			      port->port_number); + +	mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_RX_HOST_EN, 0, +			      port->port_number); +} + +/* Send a break to the port. */ +static void mxuport_break_ctl(struct tty_struct *tty, int break_state) +{ +	struct usb_serial_port *port = tty->driver_data; +	struct usb_serial *serial = port->serial; +	int enable; + +	if (break_state == -1) { +		enable = 1; +		dev_dbg(&port->dev, "%s - sending break\n", __func__); +	} else { +		enable = 0; +		dev_dbg(&port->dev, "%s - clearing break\n", __func__); +	} + +	mxuport_send_ctrl_urb(serial, RQ_VENDOR_SET_BREAK, +			      enable, port->port_number); +} + +static int mxuport_resume(struct usb_serial *serial) +{ +	struct usb_serial_port *port; +	int c = 0; +	int i; +	int r; + +	for (i = 0; i < 2; i++) { +		port = serial->port[i]; + +		r = usb_serial_generic_submit_read_urbs(port, GFP_NOIO); +		if (r < 0) +			c++; +	} + +	for (i = 0; i < serial->num_ports; i++) { +		port = serial->port[i]; +		if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) +			continue; + +		r = usb_serial_generic_write_start(port, GFP_NOIO); +		if (r < 0) +			c++; +	} + +	return c ? -EIO : 0; +} + +static struct usb_serial_driver mxuport_device = { +	.driver = { +		.owner =	THIS_MODULE, +		.name =		"mxuport", +	}, +	.description		= "MOXA UPort", +	.id_table		= mxuport_idtable, +	.num_ports		= 0, +	.probe			= mxuport_probe, +	.port_probe		= mxuport_port_probe, +	.attach			= mxuport_attach, +	.calc_num_ports		= mxuport_calc_num_ports, +	.open			= mxuport_open, +	.close			= mxuport_close, +	.set_termios		= mxuport_set_termios, +	.break_ctl		= mxuport_break_ctl, +	.tx_empty		= mxuport_tx_empty, +	.tiocmiwait		= usb_serial_generic_tiocmiwait, +	.get_icount		= usb_serial_generic_get_icount, +	.throttle		= mxuport_throttle, +	.unthrottle		= mxuport_unthrottle, +	.tiocmget		= mxuport_tiocmget, +	.tiocmset		= mxuport_tiocmset, +	.dtr_rts		= mxuport_dtr_rts, +	.process_read_urb	= mxuport_process_read_urb, +	.prepare_write_buffer	= mxuport_prepare_write_buffer, +	.resume			= mxuport_resume, +}; + +static struct usb_serial_driver *const serial_drivers[] = { +	&mxuport_device, NULL +}; + +module_usb_serial_driver(serial_drivers, mxuport_idtable); + +MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>"); +MODULE_AUTHOR("<support@moxa.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index 38725fc8c2c..2a97cdc078d 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -14,7 +14,6 @@  #include <linux/gfp.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/tty.h>  #include <linux/tty_flip.h>  #include <linux/module.h> diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 5739bf6f720..f6c6900bccf 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -13,7 +13,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index cbe779f578f..4856fb7e637 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -12,7 +12,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/tty.h>  #include <linux/tty_driver.h>  #include <linux/slab.h> @@ -139,7 +138,7 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port)  	/* Clear RTS line */  	send_control_msg(port, CONTROL_RTS, 0); -	/* clear the halt status of the enpoint */ +	/* clear the halt status of the endpoint */  	usb_clear_halt(port->serial->dev, port->read_urb->pipe);  	res = usb_serial_generic_open(tty, port); @@ -200,15 +199,12 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,  	buffer = kmalloc(count, GFP_ATOMIC);  	if (!buffer) { -		dev_err(&port->dev, "out of memory\n");  		count = -ENOMEM; -  		goto error_no_buffer;  	}  	urb = usb_alloc_urb(0, GFP_ATOMIC);  	if (!urb) { -		dev_err(&port->dev, "no more free urbs\n");  		count = -ENOMEM;  		goto error_no_urb;  	} @@ -217,11 +213,10 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,  	usb_serial_debug_data(&port->dev, __func__, count, buffer); -	/* The conncected devices do not have a bulk write endpoint, +	/* The connected devices do not have a bulk write endpoint,  	 * to transmit data to de barcode device the control endpoint is used */  	dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);  	if (!dr) { -		dev_err(&port->dev, "out of memory\n");  		count = -ENOMEM;  		goto error_no_dr;  	} @@ -367,8 +362,6 @@ static int opticon_ioctl(struct tty_struct *tty,  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(&port->dev, "%s - cmd = 0x%x\n", __func__, cmd); -  	switch (cmd) {  	case TIOCGSERIAL:  		return get_serial_info(port, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 1cf6f125f5f..a9688940543 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -81,9 +81,11 @@ static void option_instat_callback(struct urb *urb);  #define HUAWEI_VENDOR_ID			0x12D1  #define HUAWEI_PRODUCT_E173			0x140C +#define HUAWEI_PRODUCT_E1750			0x1406  #define HUAWEI_PRODUCT_K4505			0x1464  #define HUAWEI_PRODUCT_K3765			0x1465  #define HUAWEI_PRODUCT_K4605			0x14C6 +#define HUAWEI_PRODUCT_E173S6			0x1C07  #define QUANTA_VENDOR_ID			0x0408  #define QUANTA_PRODUCT_Q101			0xEA02 @@ -159,6 +161,7 @@ static void option_instat_callback(struct urb *urb);  #define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED	0x9000  #define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED	0x9001  #define NOVATELWIRELESS_PRODUCT_E362		0x9010 +#define NOVATELWIRELESS_PRODUCT_E371		0x9011  #define NOVATELWIRELESS_PRODUCT_G2		0xA010  #define NOVATELWIRELESS_PRODUCT_MC551		0xB001 @@ -232,8 +235,31 @@ static void option_instat_callback(struct urb *urb);  #define QUALCOMM_VENDOR_ID			0x05C6  #define CMOTECH_VENDOR_ID			0x16d8 -#define CMOTECH_PRODUCT_6008			0x6008 -#define CMOTECH_PRODUCT_6280			0x6280 +#define CMOTECH_PRODUCT_6001			0x6001 +#define CMOTECH_PRODUCT_CMU_300			0x6002 +#define CMOTECH_PRODUCT_6003			0x6003 +#define CMOTECH_PRODUCT_6004			0x6004 +#define CMOTECH_PRODUCT_6005			0x6005 +#define CMOTECH_PRODUCT_CGU_628A		0x6006 +#define CMOTECH_PRODUCT_CHE_628S		0x6007 +#define CMOTECH_PRODUCT_CMU_301			0x6008 +#define CMOTECH_PRODUCT_CHU_628			0x6280 +#define CMOTECH_PRODUCT_CHU_628S		0x6281 +#define CMOTECH_PRODUCT_CDU_680			0x6803 +#define CMOTECH_PRODUCT_CDU_685A		0x6804 +#define CMOTECH_PRODUCT_CHU_720S		0x7001 +#define CMOTECH_PRODUCT_7002			0x7002 +#define CMOTECH_PRODUCT_CHU_629K		0x7003 +#define CMOTECH_PRODUCT_7004			0x7004 +#define CMOTECH_PRODUCT_7005			0x7005 +#define CMOTECH_PRODUCT_CGU_629			0x7006 +#define CMOTECH_PRODUCT_CHU_629S		0x700a +#define CMOTECH_PRODUCT_CHU_720I		0x7211 +#define CMOTECH_PRODUCT_7212			0x7212 +#define CMOTECH_PRODUCT_7213			0x7213 +#define CMOTECH_PRODUCT_7251			0x7251 +#define CMOTECH_PRODUCT_7252			0x7252 +#define CMOTECH_PRODUCT_7253			0x7253  #define TELIT_VENDOR_ID				0x1bc7  #define TELIT_PRODUCT_UC864E			0x1003 @@ -241,6 +267,7 @@ static void option_instat_callback(struct urb *urb);  #define TELIT_PRODUCT_CC864_DUAL		0x1005  #define TELIT_PRODUCT_CC864_SINGLE		0x1006  #define TELIT_PRODUCT_DE910_DUAL		0x1010 +#define TELIT_PRODUCT_UE910_V2			0x1012  #define TELIT_PRODUCT_LE920			0x1200  /* ZTE PRODUCTS */ @@ -249,6 +276,7 @@ static void option_instat_callback(struct urb *urb);  #define ZTE_PRODUCT_MF628			0x0015  #define ZTE_PRODUCT_MF626			0x0031  #define ZTE_PRODUCT_MC2718			0xffe8 +#define ZTE_PRODUCT_AC2726			0xfff1  #define BENQ_VENDOR_ID				0x04a5  #define BENQ_PRODUCT_H10			0x4068 @@ -283,6 +311,7 @@ static void option_instat_callback(struct urb *urb);  #define ALCATEL_PRODUCT_X060S_X200		0x0000  #define ALCATEL_PRODUCT_X220_X500D		0x0017  #define ALCATEL_PRODUCT_L100V			0x011e +#define ALCATEL_PRODUCT_L800MA			0x0203  #define PIRELLI_VENDOR_ID			0x1266  #define PIRELLI_PRODUCT_C100_1			0x1002 @@ -317,9 +346,15 @@ static void option_instat_callback(struct urb *urb);   * It seems to contain a Qualcomm QSC6240/6290 chipset            */  #define FOUR_G_SYSTEMS_PRODUCT_W14		0x9603 +/* iBall 3.5G connect wireless modem */ +#define IBALL_3_5G_CONNECT			0x9605 +  /* Zoom */  #define ZOOM_PRODUCT_4597			0x9607 +/* SpeedUp SU9800 usb 3g modem */ +#define SPEEDUP_PRODUCT_SU9800			0x9800 +  /* Haier products */  #define HAIER_VENDOR_ID				0x201e  #define HAIER_PRODUCT_CE100			0x2009 @@ -340,8 +375,13 @@ static void option_instat_callback(struct urb *urb);  /* Olivetti products */  #define OLIVETTI_VENDOR_ID			0x0b3c  #define OLIVETTI_PRODUCT_OLICARD100		0xc000 +#define OLIVETTI_PRODUCT_OLICARD120		0xc001 +#define OLIVETTI_PRODUCT_OLICARD140		0xc002  #define OLIVETTI_PRODUCT_OLICARD145		0xc003 +#define OLIVETTI_PRODUCT_OLICARD155		0xc004  #define OLIVETTI_PRODUCT_OLICARD200		0xc005 +#define OLIVETTI_PRODUCT_OLICARD160		0xc00a +#define OLIVETTI_PRODUCT_OLICARD500		0xc00b  /* Celot products */  #define CELOT_VENDOR_ID				0x211f @@ -450,6 +490,10 @@ static void option_instat_callback(struct urb *urb);  #define CHANGHONG_VENDOR_ID			0x2077  #define CHANGHONG_PRODUCT_CH690			0x7001 +/* Inovia */ +#define INOVIA_VENDOR_ID			0x20a6 +#define INOVIA_SEW858				0x1105 +  /* some devices interfaces need special handling due to a number of reasons */  enum option_blacklist_reason {  		OPTION_BLACKLIST_NONE = 0, @@ -491,6 +535,10 @@ static const struct option_blacklist_info huawei_cdc12_blacklist = {  	.reserved = BIT(1) | BIT(2),  }; +static const struct option_blacklist_info net_intf0_blacklist = { +	.reserved = BIT(0), +}; +  static const struct option_blacklist_info net_intf1_blacklist = {  	.reserved = BIT(1),  }; @@ -567,6 +615,10 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1c23, USB_CLASS_COMM, 0x02, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173, 0xff, 0xff, 0xff),  		.driver_info = (kernel_ulong_t) &net_intf1_blacklist }, +	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S6, 0xff, 0xff, 0xff), +		.driver_info = (kernel_ulong_t) &net_intf1_blacklist }, +	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1750, 0xff, 0xff, 0xff), +		.driver_info = (kernel_ulong_t) &net_intf2_blacklist },  	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1441, USB_CLASS_COMM, 0x02, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0x1442, USB_CLASS_COMM, 0x02, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff), @@ -627,6 +679,10 @@ static const struct usb_device_id option_ids[] = {  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6D) },  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6E) },  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x72) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x73) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x74) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x75) },  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x78) },  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x79) },  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7A) }, @@ -681,11 +737,247 @@ static const struct usb_device_id option_ids[] = {  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6D) },  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6E) },  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x72) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x73) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x74) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x75) },  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x78) },  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x79) },  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7A) },  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7B) },  	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7C) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x01) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x02) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x03) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x04) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x05) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x06) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0D) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0E) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x0F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x10) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x12) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x13) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x14) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x15) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x17) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x18) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x19) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x1C) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x31) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x32) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x33) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x34) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x35) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x36) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3D) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3E) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x3F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x48) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x49) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x4C) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x61) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x62) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x63) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x64) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x65) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x66) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6D) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6E) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x6F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x72) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x73) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x74) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x75) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x78) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x79) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x03, 0x7C) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x01) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x02) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x03) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x04) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x05) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x06) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0D) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0E) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x0F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x10) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x12) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x13) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x14) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x15) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x17) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x18) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x19) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x1C) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x31) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x32) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x33) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x34) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x35) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x36) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3D) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3E) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x3F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x48) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x49) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x4C) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x61) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x62) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x63) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x64) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x65) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x66) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6D) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6E) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x6F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x72) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x73) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x74) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x75) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x78) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x79) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x04, 0x7C) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x01) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x02) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x03) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x04) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x05) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x06) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0D) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0E) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x0F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x10) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x12) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x13) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x14) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x15) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x17) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x18) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x19) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x1C) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x31) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x32) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x33) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x34) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x35) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x36) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3D) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3E) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x3F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x48) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x49) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x4C) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x61) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x62) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x63) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x64) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x65) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x66) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6D) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6E) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x6F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x72) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x73) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x74) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x75) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x78) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x79) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x05, 0x7C) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x01) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x02) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x03) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x04) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x05) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x06) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0D) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0E) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x0F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x10) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x12) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x13) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x14) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x15) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x17) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x18) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x19) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x1C) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x31) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x32) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x33) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x34) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x35) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x36) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3D) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3E) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x3F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x48) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x49) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x4C) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x61) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x62) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x63) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x64) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x65) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x66) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6D) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6E) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x6F) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x72) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x73) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x74) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x75) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x78) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x79) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7A) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7B) }, +	{ USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x06, 0x7C) },  	{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, @@ -728,6 +1020,7 @@ static const struct usb_device_id option_ids[] = {  	/* Novatel Ovation MC551 a.k.a. Verizon USB551L */  	{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_MC551, 0xff, 0xff, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E362, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E371, 0xff, 0xff, 0xff) },  	{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) },  	{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) }, @@ -780,13 +1073,53 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */  	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x0023)}, /* ONYX 3G device */  	{ USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ -	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */ -	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6001) }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_300) }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6003), +	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6004) }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6005) }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_628A) }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHE_628S), +	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CMU_301), +	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628), +	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_628S) }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_680) }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU_685A) }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720S), +	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7002), +	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629K), +	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7004), +	  .driver_info = (kernel_ulong_t)&net_intf3_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7005) }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CGU_629), +	  .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_629S), +	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CHU_720I), +	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7212), +	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7213), +	  .driver_info = (kernel_ulong_t)&net_intf0_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7251), +	  .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7252), +	  .driver_info = (kernel_ulong_t)&net_intf1_blacklist }, +	{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_7253), +	  .driver_info = (kernel_ulong_t)&net_intf1_blacklist },  	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },  	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) },  	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) },  	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },  	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, +	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) },  	{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),  		.driver_info = (kernel_ulong_t)&telit_le920_blacklist },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ @@ -1108,7 +1441,8 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1267, 0xff, 0xff, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1268, 0xff, 0xff, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1269, 0xff, 0xff, 0xff) }, -	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff), +	  .driver_info = (kernel_ulong_t)&net_intf5_blacklist },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1271, 0xff, 0xff, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) }, @@ -1153,6 +1487,25 @@ static const struct usb_device_id option_ids[] = {  		.driver_info = (kernel_ulong_t)&net_intf2_blacklist },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1426, 0xff, 0xff, 0xff),  /* ZTE MF91 */  		.driver_info = (kernel_ulong_t)&net_intf2_blacklist }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1428, 0xff, 0xff, 0xff),  /* Telewell TW-LTE 4G v2 */ +		.driver_info = (kernel_ulong_t)&net_intf2_blacklist }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1533, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1534, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1535, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1545, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1546, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1547, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1565, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1566, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1567, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1589, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1590, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1591, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1592, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1594, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1596, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1598, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1600, 0xff, 0xff, 0xff) },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2002, 0xff,  	  0xff, 0xff), .driver_info = (kernel_ulong_t)&zte_k3765_z_blacklist },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x2003, 0xff, 0xff, 0xff) }, @@ -1179,6 +1532,17 @@ static const struct usb_device_id option_ids[] = {  		.driver_info = (kernel_ulong_t)&net_intf3_blacklist },  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0178, 0xff, 0xff, 0xff),  		.driver_info = (kernel_ulong_t)&net_intf3_blacklist }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xffe9, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8b, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8c, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8d, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8e, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff8f, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff90, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff91, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff92, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff93, 0xff, 0xff, 0xff) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff94, 0xff, 0xff, 0xff) },  	/* NOTE: most ZTE CDMA devices should be driven by zte_ev, not option */  	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff), @@ -1186,6 +1550,7 @@ static const struct usb_device_id option_ids[] = {  	{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x01) },  	{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x02, 0x05) },  	{ USB_VENDOR_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0xff, 0x86, 0x10) }, +	{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) },  	{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },  	{ USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, @@ -1214,12 +1579,16 @@ static const struct usb_device_id option_ids[] = {  	  .driver_info = (kernel_ulong_t)&net_intf5_blacklist },  	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L100V),  	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, +	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_L800MA), +	  .driver_info = (kernel_ulong_t)&net_intf2_blacklist },  	{ USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },  	{ USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },  	{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),    	  .driver_info = (kernel_ulong_t)&four_g_w14_blacklist    	}, +	{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) },  	{ USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) }, +	{ USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) },  	{ USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },  	/* Pirelli  */  	{ USB_DEVICE_INTERFACE_CLASS(PIRELLI_VENDOR_ID, PIRELLI_PRODUCT_C100_1, 0xff) }, @@ -1241,7 +1610,8 @@ static const struct usb_device_id option_ids[] = {  	/* Cinterion */  	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) },  	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) }, -	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) }, +	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8), +		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },  	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) },  	{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX),  		.driver_info = (kernel_ulong_t)&net_intf4_blacklist }, @@ -1251,10 +1621,21 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDMNET) },  	{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, /* HC28 enumerates with Siemens or Cinterion VID depending on FW revision */  	{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, - -	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100) }, +	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD100), +		.driver_info = (kernel_ulong_t)&net_intf4_blacklist }, +	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD120), +		.driver_info = (kernel_ulong_t)&net_intf4_blacklist }, +	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD140), +		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },  	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD145) }, -	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200) }, +	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD155), +		.driver_info = (kernel_ulong_t)&net_intf6_blacklist }, +	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD200), +		.driver_info = (kernel_ulong_t)&net_intf6_blacklist }, +	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD160), +		.driver_info = (kernel_ulong_t)&net_intf6_blacklist }, +	{ USB_DEVICE(OLIVETTI_VENDOR_ID, OLIVETTI_PRODUCT_OLICARD500), +		.driver_info = (kernel_ulong_t)&net_intf4_blacklist },  	{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */  	{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/  	{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) }, @@ -1342,6 +1723,7 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) },  	{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e01, 0xff, 0xff, 0xff) }, /* D-Link DWM-152/C1 */  	{ USB_DEVICE_AND_INTERFACE_INFO(0x07d1, 0x3e02, 0xff, 0xff, 0xff) }, /* D-Link DWM-156/C1 */ +	{ USB_DEVICE(INOVIA_VENDOR_ID, INOVIA_SEW858) },  	{ } /* Terminating entry */  };  MODULE_DEVICE_TABLE(usb, option_ids); @@ -1365,7 +1747,6 @@ static struct usb_serial_driver option_1port_device = {  	.write             = usb_wwan_write,  	.write_room        = usb_wwan_write_room,  	.chars_in_buffer   = usb_wwan_chars_in_buffer, -	.set_termios       = usb_wwan_set_termios,  	.tiocmget          = usb_wwan_tiocmget,  	.tiocmset          = usb_wwan_tiocmset,  	.ioctl             = usb_wwan_ioctl, @@ -1540,6 +1921,7 @@ static void option_instat_callback(struct urb *urb)  	/* Resubmit urb so we continue receiving IRQ data */  	if (status != -ESHUTDOWN && status != -ENOENT) { +		usb_mark_last_busy(port->serial->dev);  		err = usb_submit_urb(urb, GFP_ATOMIC);  		if (err)  			dev_dbg(dev, "%s: resubmit intr urb failed. (%d)\n", @@ -1559,6 +1941,7 @@ static int option_send_setup(struct usb_serial_port *port)  	struct option_private *priv = intfdata->private;  	struct usb_wwan_port_private *portdata;  	int val = 0; +	int res;  	portdata = usb_get_serial_port_data(port); @@ -1567,9 +1950,17 @@ static int option_send_setup(struct usb_serial_port *port)  	if (portdata->rts_state)  		val |= 0x02; -	return usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), +	res = usb_autopm_get_interface(serial->interface); +	if (res) +		return res; + +	res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),  				0x22, 0x21, val, priv->bInterfaceNumber, NULL,  				0, USB_CTRL_SET_TIMEOUT); + +	usb_autopm_put_interface(serial->interface); + +	return res;  }  MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index a2080ac7b7e..a4b88bc038b 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -39,7 +39,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -103,6 +102,7 @@ struct oti6858_control_pkt {  #define	TX_BUFFER_EMPTIED	0x09  	u8	pin_state;  #define PIN_MASK		0x3f +#define PIN_MSR_MASK		0x1b  #define PIN_RTS			0x20	/* output pin */  #define PIN_CTS			0x10	/* input pin, active low */  #define PIN_DSR			0x08	/* input pin, active low */ @@ -134,7 +134,6 @@ 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); @@ -153,7 +152,7 @@ static struct usb_serial_driver oti6858_device = {  	.init_termios = 	oti6858_init_termios,  	.tiocmget =		oti6858_tiocmget,  	.tiocmset =		oti6858_tiocmset, -	.tiocmiwait =		oti6858_tiocmiwait, +	.tiocmiwait =		usb_serial_generic_tiocmiwait,  	.read_bulk_callback =	oti6858_read_bulk_callback,  	.read_int_callback =	oti6858_read_int_callback,  	.write_bulk_callback =	oti6858_write_bulk_callback, @@ -200,8 +199,7 @@ static void setup_line(struct work_struct *work)  	int result;  	new_setup = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL); -	if (new_setup == NULL) { -		dev_err(&port->dev, "%s(): out of memory!\n", __func__); +	if (!new_setup) {  		/* we will try again */  		schedule_delayed_work(&priv->delayed_setup_work,  						msecs_to_jiffies(2)); @@ -287,11 +285,9 @@ static void send_data(struct work_struct *work)  	if (count != 0) {  		allow = kmalloc(1, GFP_KERNEL); -		if (!allow) { -			dev_err_console(port, "%s(): kmalloc failed\n", -					__func__); +		if (!allow)  			return; -		} +  		result = usb_control_msg(port->serial->dev,  				usb_rcvctrlpipe(port->serial->dev, 0),  				OTI6858_REQ_T_CHECK_TXBUFF, @@ -517,10 +513,8 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)  	usb_clear_halt(serial->dev, port->read_urb->pipe);  	buf = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL); -	if (buf == NULL) { -		dev_err(&port->dev, "%s(): out of memory!\n", __func__); +	if (!buf)  		return -ENOMEM; -	}  	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),  				OTI6858_REQ_T_GET_STATUS, @@ -647,46 +641,6 @@ static int oti6858_tiocmget(struct tty_struct *tty)  	return result;  } -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; -	unsigned int changed; - -	spin_lock_irqsave(&priv->lock, flags); -	prev = priv->status.pin_state; -	spin_unlock_irqrestore(&priv->lock, flags); - -	while (1) { -		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); - -		changed = prev ^ status; -		/* FIXME: check if this is correct (active high/low) */ -		if (((arg & TIOCM_RNG) && (changed & PIN_RI)) || -		    ((arg & TIOCM_DSR) && (changed & PIN_DSR)) || -		    ((arg & TIOCM_CD)  && (changed & PIN_DCD)) || -		    ((arg & TIOCM_CTS) && (changed & PIN_CTS))) -			return 0; -		prev = status; -	} - -	/* NOTREACHED */ -	return 0; -} -  static void oti6858_read_int_callback(struct urb *urb)  {  	struct usb_serial_port *port =  urb->context; @@ -744,8 +698,21 @@ static void oti6858_read_int_callback(struct urb *urb)  		}  		if (!priv->transient) { -			if (xs->pin_state != priv->status.pin_state) +			u8 delta = xs->pin_state ^ priv->status.pin_state; + +			if (delta & PIN_MSR_MASK) { +				if (delta & PIN_CTS) +					port->icount.cts++; +				if (delta & PIN_DSR) +					port->icount.dsr++; +				if (delta & PIN_RI) +					port->icount.rng++; +				if (delta & PIN_DCD) +					port->icount.dcd++; +  				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 e7a84f0f517..b3d5a35c0d4 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -4,11 +4,6 @@   * Copyright (C) 2001-2007 Greg Kroah-Hartman (greg@kroah.com)   * Copyright (C) 2003 IBM Corp.   * - * Copyright (C) 2009, 2013 Frank Schäfer <fschaefer.oss@googlemail.com> - *  - fixes, improvements and documentation for the baud rate encoding methods - * Copyright (C) 2013 Reinhard Max <max@suse.de> - *  - fixes and improvements for the divisor based baud rate encoding method - *   * Original driver for 2.2.x by anonymous   *   *	This program is free software; you can redistribute it and/or @@ -17,12 +12,10 @@   *   * See Documentation/usb/usb-serial.txt for more information on using this   * driver - *   */  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -37,10 +30,9 @@  #include <asm/unaligned.h>  #include "pl2303.h" -/* - * Version Information - */ -#define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver" + +#define PL2303_QUIRK_UART_STATE_IDX0		BIT(0) +#define PL2303_QUIRK_LEGACY			BIT(1)  static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, @@ -69,9 +61,12 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(SITECOM_VENDOR_ID, SITECOM_PRODUCT_ID) },  	{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_ID) },  	{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_ID) }, -	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1) }, -	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65) }, -	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75) }, +	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_SX1), +		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, +	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X65), +		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 }, +	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_X75), +		.driver_info = PL2303_QUIRK_UART_STATE_IDX0 },  	{ USB_DEVICE(SIEMENS_VENDOR_ID, SIEMENS_PRODUCT_ID_EF81) },  	{ USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_ID_S81) }, /* Benq/Siemens S81 */  	{ USB_DEVICE(SYNTECH_VENDOR_ID, SYNTECH_PRODUCT_ID) }, @@ -88,6 +83,9 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) },  	{ USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) },  	{ USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, +	{ USB_DEVICE(HP_VENDOR_ID, HP_LD960_PRODUCT_ID) }, +	{ USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) }, +	{ USB_DEVICE(HP_VENDOR_ID, HP_LCM960_PRODUCT_ID) },  	{ USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) },  	{ USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) },  	{ USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, @@ -121,7 +119,8 @@ MODULE_DEVICE_TABLE(usb, id_table);  #define VENDOR_READ_REQUEST_TYPE	0xc0  #define VENDOR_READ_REQUEST		0x01 -#define UART_STATE			0x08 +#define UART_STATE_INDEX		8 +#define UART_STATE_MSR_MASK		0x8b  #define UART_STATE_TRANSIENT_MASK	0x74  #define UART_DCD			0x01  #define UART_DSR			0x02 @@ -134,129 +133,142 @@ MODULE_DEVICE_TABLE(usb, id_table);  enum pl2303_type { -	type_0,		/* H version ? */ -	type_1,		/* H version ? */ -	HX_TA,		/* HX(A) / X(A) / TA version  */ /* TODO: improve */ -	HXD_EA_RA_SA,	/* HXD / EA / RA / SA version */ /* TODO: improve */ -	TB,		/* TB version */ +	TYPE_01,	/* Type 0 and 1 (difference unknown) */ +	TYPE_HX,	/* HX version of the pl2303 chip */ +	TYPE_COUNT +}; + +struct pl2303_type_data { +	speed_t max_baud_rate; +	unsigned long quirks;  }; -/* - * NOTE: don't know the difference between type 0 and type 1, - * until someone from Prolific tells us... - * TODO: distinguish between X/HX, TA and HXD, EA, RA, SA variants - */  struct pl2303_serial_private { -	enum pl2303_type type; +	const struct pl2303_type_data *type; +	unsigned long quirks;  };  struct pl2303_private {  	spinlock_t lock;  	u8 line_control;  	u8 line_status; + +	u8 line_settings[7];  }; -static int pl2303_vendor_read(__u16 value, __u16 index, -		struct usb_serial *serial, unsigned char *buf) +static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { +	[TYPE_01] = { +		.max_baud_rate =	1228800, +		.quirks =		PL2303_QUIRK_LEGACY, +	}, +}; + +static int pl2303_vendor_read(struct usb_serial *serial, u16 value, +							unsigned char buf[1])  { -	int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), +	struct device *dev = &serial->interface->dev; +	int res; + +	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->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; +			value, 0, buf, 1, 100); +	if (res != 1) { +		dev_err(dev, "%s - failed to read [%04x]: %d\n", __func__, +								value, res); +		if (res >= 0) +			res = -EIO; + +		return res; +	} + +	dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, buf[0]); + +	return 0;  } -static int pl2303_vendor_write(__u16 value, __u16 index, -		struct usb_serial *serial) +static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index)  { -	int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), +	struct device *dev = &serial->interface->dev; +	int res; + +	dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, index); + +	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->interface->dev, "0x%x:0x%x:0x%x:0x%x  %d\n", -		VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index, -		res); -	return res; +	if (res) { +		dev_err(dev, "%s - failed to write [%04x]: %d\n", __func__, +								value, res); +		return res; +	} + +	return 0; +} + +static int pl2303_probe(struct usb_serial *serial, +					const struct usb_device_id *id) +{ +	usb_set_serial_data(serial, (void *)id->driver_info); + +	return 0;  }  static int pl2303_startup(struct usb_serial *serial)  {  	struct pl2303_serial_private *spriv; -	enum pl2303_type type = type_0; -	char *type_str = "unknown (treating as type_0)"; +	enum pl2303_type type = TYPE_01;  	unsigned char *buf;  	spriv = kzalloc(sizeof(*spriv), GFP_KERNEL);  	if (!spriv)  		return -ENOMEM; -	buf = kmalloc(10, GFP_KERNEL); +	buf = kmalloc(1, GFP_KERNEL);  	if (!buf) {  		kfree(spriv);  		return -ENOMEM;  	} -	if (serial->dev->descriptor.bDeviceClass == 0x02) { -		type = type_0; -		type_str = "type_0"; -	} else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) { -		/* -		 * NOTE: The bcdDevice version is the only difference between -		 * the device descriptors of the X/HX, HXD, EA, RA, SA, TA, TB -		 */ -		if (le16_to_cpu(serial->dev->descriptor.bcdDevice) == 0x300) { -			type = HX_TA; -			type_str = "X/HX/TA"; -		} else if (le16_to_cpu(serial->dev->descriptor.bcdDevice) -								     == 0x400) { -			type = HXD_EA_RA_SA; -			type_str = "HXD/EA/RA/SA"; -		} else if (le16_to_cpu(serial->dev->descriptor.bcdDevice) -								     == 0x500) { -			type = TB; -			type_str = "TB"; -		} else { -			dev_info(&serial->interface->dev, -					   "unknown/unsupported device type\n"); -			kfree(spriv); -			kfree(buf); -			return -ENODEV; -		} -	} else if (serial->dev->descriptor.bDeviceClass == 0x00 -		   || serial->dev->descriptor.bDeviceClass == 0xFF) { -		type = type_1; -		type_str = "type_1"; -	} -	dev_dbg(&serial->interface->dev, "device type: %s\n", type_str); +	if (serial->dev->descriptor.bDeviceClass == 0x02) +		type = TYPE_01;		/* type 0 */ +	else if (serial->dev->descriptor.bMaxPacketSize0 == 0x40) +		type = TYPE_HX; +	else if (serial->dev->descriptor.bDeviceClass == 0x00) +		type = TYPE_01;		/* type 1 */ +	else if (serial->dev->descriptor.bDeviceClass == 0xFF) +		type = TYPE_01;		/* type 1 */ +	dev_dbg(&serial->interface->dev, "device type: %d\n", type); + +	spriv->type = &pl2303_type_data[type]; +	spriv->quirks = (unsigned long)usb_get_serial_data(serial); +	spriv->quirks |= spriv->type->quirks; -	spriv->type = type;  	usb_set_serial_data(serial, spriv); -	pl2303_vendor_read(0x8484, 0, serial, buf); -	pl2303_vendor_write(0x0404, 0, serial); -	pl2303_vendor_read(0x8484, 0, serial, buf); -	pl2303_vendor_read(0x8383, 0, serial, buf); -	pl2303_vendor_read(0x8484, 0, serial, buf); -	pl2303_vendor_write(0x0404, 1, serial); -	pl2303_vendor_read(0x8484, 0, serial, buf); -	pl2303_vendor_read(0x8383, 0, serial, buf); -	pl2303_vendor_write(0, 1, serial); -	pl2303_vendor_write(1, 0, serial); -	if (type == type_0 || type == type_1) -		pl2303_vendor_write(2, 0x24, serial); +	pl2303_vendor_read(serial, 0x8484, buf); +	pl2303_vendor_write(serial, 0x0404, 0); +	pl2303_vendor_read(serial, 0x8484, buf); +	pl2303_vendor_read(serial, 0x8383, buf); +	pl2303_vendor_read(serial, 0x8484, buf); +	pl2303_vendor_write(serial, 0x0404, 1); +	pl2303_vendor_read(serial, 0x8484, buf); +	pl2303_vendor_read(serial, 0x8383, buf); +	pl2303_vendor_write(serial, 0, 1); +	pl2303_vendor_write(serial, 1, 0); +	if (spriv->quirks & PL2303_QUIRK_LEGACY) +		pl2303_vendor_write(serial, 2, 0x24);  	else -		pl2303_vendor_write(2, 0x44, serial); +		pl2303_vendor_write(serial, 2, 0x44);  	kfree(buf); +  	return 0;  }  static void pl2303_release(struct usb_serial *serial)  { -	struct pl2303_serial_private *spriv; +	struct pl2303_serial_private *spriv = usb_get_serial_data(serial); -	spriv = usb_get_serial_data(serial);  	kfree(spriv);  } @@ -279,9 +291,8 @@ static int pl2303_port_probe(struct usb_serial_port *port)  static int pl2303_port_remove(struct usb_serial_port *port)  { -	struct pl2303_private *priv; +	struct pl2303_private *priv = usb_get_serial_port_data(port); -	priv = usb_get_serial_port_data(port);  	kfree(priv);  	return 0; @@ -292,181 +303,157 @@ static int pl2303_set_control_lines(struct usb_serial_port *port, u8 value)  	struct usb_device *dev = port->serial->dev;  	int retval; +	dev_dbg(&port->dev, "%s - %02x\n", __func__, value); +  	retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),  				 SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,  				 value, 0, NULL, 0, 100); -	dev_dbg(&port->dev, "%s - value = %d, retval = %d\n", __func__, -		value, retval); +	if (retval) +		dev_err(&port->dev, "%s - failed: %d\n", __func__, retval); +  	return retval;  } -static int pl2303_baudrate_encode_direct(int baud, enum pl2303_type type, -								      u8 buf[4]) +/* + * Returns the nearest supported baud rate that can be set directly without + * using divisors. + */ +static speed_t pl2303_get_supported_baud_rate(speed_t baud)  { -	/* -	 * NOTE: Only the values defined in baud_sup are supported ! -	 *       => if unsupported values are set, the PL2303 seems to -	 *	    use 9600 baud (at least my PL2303X always does) -	 */ -	const int baud_sup[] = { 75, 150, 300, 600, 1200, 1800, 2400, 3600, -				 4800, 7200, 9600, 14400, 19200, 28800, 38400, -				 57600, 115200, 230400, 460800, 614400, 921600, -				 1228800, 2457600, 3000000, 6000000, 12000000 }; -	/* -	 * NOTE: With the exception of type_0/1 devices, the following -	 * additional baud rates are supported (tested with HX rev. 3A only): -	 * 110*, 56000*, 128000, 134400, 161280, 201600, 256000*, 268800, -	 * 403200, 806400.	(*: not HX) -	 * -	 * Maximum values: HXD, TB: 12000000; HX, TA: 6000000; -	 *                 type_0+1: 1228800; RA: 921600; SA: 115200 -	 * -	 * As long as we are not using this encoding method for anything else -	 * than the type_0+1 and HX chips, there is no point in complicating -	 * the code to support them. -	 */ -	int i; +	static const speed_t baud_sup[] = { +		75, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, +		14400, 19200, 28800, 38400, 57600, 115200, 230400, 460800, +		614400, 921600, 1228800, 2457600, 3000000, 6000000 +	}; + +	unsigned i; -	/* Set baudrate to nearest supported value */  	for (i = 0; i < ARRAY_SIZE(baud_sup); ++i) {  		if (baud_sup[i] > baud)  			break;  	} +  	if (i == ARRAY_SIZE(baud_sup))  		baud = baud_sup[i - 1];  	else if (i > 0 && (baud_sup[i] - baud) > (baud - baud_sup[i - 1]))  		baud = baud_sup[i - 1];  	else  		baud = baud_sup[i]; -	/* Respect the chip type specific baud rate limits */ -	/* -	 * FIXME: as long as we don't know how to distinguish between the -	 * HXD, EA, RA, and SA chip variants, allow the max. value of 12M. -	 */ -	if (type == HX_TA) -		baud = min_t(int, baud, 6000000); -	else if (type == type_0 || type == type_1) -		baud = min_t(int, baud, 1228800); -	/* Direct (standard) baud rate encoding method */ + +	return baud; +} + +/* + * NOTE: If unsupported baud rates are set directly, the PL2303 seems to + *       use 9600 baud. + */ +static speed_t pl2303_encode_baud_rate_direct(unsigned char buf[4], +								speed_t baud) +{  	put_unaligned_le32(baud, buf);  	return baud;  } -static int pl2303_baudrate_encode_divisor(int baud, enum pl2303_type type, -								      u8 buf[4]) +static speed_t pl2303_encode_baud_rate_divisor(unsigned char buf[4], +								speed_t baud)  { -	/* -	 * Divisor based baud rate encoding method -	 * -	 * NOTE: it's not clear if the type_0/1 chips support this method -	 * -	 * divisor = 12MHz * 32 / baudrate = 2^A * B -	 * -	 * with -	 * -	 * A = buf[1] & 0x0e -	 * B = buf[0]  +  (buf[1] & 0x01) << 8 -	 * -	 * Special cases: -	 * => 8 < B < 16: device seems to work not properly -	 * => B <= 8: device uses the max. value B = 512 instead -	 */ -	unsigned int A, B; +	unsigned int tmp;  	/* -	 * NOTE: The Windows driver allows maximum baud rates of 110% of the -	 * specified maximium value. -	 * Quick tests with early (2004) HX (rev. A) chips suggest, that even -	 * higher baud rates (up to the maximum of 24M baud !) are working fine, -	 * but that should really be tested carefully in "real life" scenarios -	 * before removing the upper limit completely. -	 * Baud rates smaller than the specified 75 baud are definitely working -	 * fine. +	 * Apparently the formula is: +	 * baudrate = 12M * 32 / (2^buf[1]) / buf[0]  	 */ -	if (type == type_0 || type == type_1) -		baud = min_t(int, baud, 1228800 * 1.1); -	else if (type == HX_TA) -		baud = min_t(int, baud, 6000000 * 1.1); -	else if (type == HXD_EA_RA_SA) -		/* HXD, EA: 12Mbps; RA: 1Mbps; SA: 115200 bps */ -		/* -		 * FIXME: as long as we don't know how to distinguish between -		 * these chip variants, allow the max. of these values -		 */ -		baud = min_t(int, baud, 12000000 * 1.1); -	else if (type == TB) -		baud = min_t(int, baud, 12000000 * 1.1); -	/* Determine factors A and B */ -	A = 0; -	B = 12000000 * 32 / baud;  /* 12MHz */ -	B <<= 1; /* Add one bit for rounding */ -	while (B > (512 << 1) && A <= 14) { -		A += 2; -		B >>= 2; -	} -	if (A > 14) { /* max. divisor = min. baudrate reached */ -		A = 14; -		B = 512; -		/* => ~45.78 baud */ -	} else { -		B = (B + 1) >> 1; /* Round the last bit */ -	} -	/* Handle special cases */ -	if (B == 512) -		B = 0; /* also: 1 to 8 */ -	else if (B < 16) -		/* -		 * NOTE: With the current algorithm this happens -		 * only for A=0 and means that the min. divisor -		 * (respectively: the max. baudrate) is reached. -		 */ -		B = 16;		/* => 24 MBaud */ -	/* Encode the baud rate */ -	buf[3] = 0x80;     /* Select divisor encoding method */ +	tmp = 12000000 * 32 / baud; +	buf[3] = 0x80;  	buf[2] = 0; -	buf[1] = (A & 0x0e);		/* A */ -	buf[1] |= ((B & 0x100) >> 8);	/* MSB of B */ -	buf[0] = B & 0xff;		/* 8 LSBs of B */ -	/* Calculate the actual/resulting baud rate */ -	if (B <= 8) -		B = 512; -	baud = 12000000 * 32 / ((1 << A) * B); +	buf[1] = (tmp >= 256); +	while (tmp >= 256) { +		tmp >>= 2; +		buf[1] <<= 1; +	} +	buf[0] = tmp;  	return baud;  } -static void pl2303_encode_baudrate(struct tty_struct *tty, +static void pl2303_encode_baud_rate(struct tty_struct *tty,  					struct usb_serial_port *port, -					enum pl2303_type type,  					u8 buf[4])  { -	int baud; +	struct usb_serial *serial = port->serial; +	struct pl2303_serial_private *spriv = usb_get_serial_data(serial); +	speed_t	baud_sup; +	speed_t baud;  	baud = tty_get_baud_rate(tty); -	dev_dbg(&port->dev, "baud requested = %d\n", baud); +	dev_dbg(&port->dev, "baud requested = %u\n", baud);  	if (!baud)  		return; + +	if (spriv->type->max_baud_rate) +		baud = min_t(speed_t, baud, spriv->type->max_baud_rate);  	/* -	 * There are two methods for setting/encoding the baud rate -	 * 1) Direct method: encodes the baud rate value directly -	 *    => supported by all chip types -	 * 2) Divisor based method: encodes a divisor to a base value (12MHz*32) -	 *    => supported by HX chips (and likely not by type_0/1 chips) +	 * Set baud rate to nearest supported value.  	 * -	 * NOTE: Although the divisor based baud rate encoding method is much -	 * more flexible, some of the standard baud rate values can not be -	 * realized exactly. But the difference is very small (max. 0.2%) and -	 * the device likely uses the same baud rate generator for both methods -	 * so that there is likley no difference. +	 * NOTE: Baud rate 500k can only be set using divisors.  	 */ -	if (type == type_0 || type == type_1) -		baud = pl2303_baudrate_encode_direct(baud, type, buf); +	baud_sup = pl2303_get_supported_baud_rate(baud); + +	if (baud == 500000) +		baud = pl2303_encode_baud_rate_divisor(buf, baud);  	else -		baud = pl2303_baudrate_encode_divisor(baud, type, buf); +		baud = pl2303_encode_baud_rate_direct(buf, baud_sup); +  	/* Save resulting baud rate */  	tty_encode_baud_rate(tty, baud, baud); -	dev_dbg(&port->dev, "baud set = %d\n", baud); +	dev_dbg(&port->dev, "baud set = %u\n", baud); +} + +static int pl2303_get_line_request(struct usb_serial_port *port, +							unsigned char buf[7]) +{ +	struct usb_device *udev = port->serial->dev; +	int ret; + +	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), +				GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, +				0, 0, buf, 7, 100); +	if (ret != 7) { +		dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); + +		if (ret > 0) +			ret = -EIO; + +		return ret; +	} + +	dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf); + +	return 0; +} + +static int pl2303_set_line_request(struct usb_serial_port *port, +							unsigned char buf[7]) +{ +	struct usb_device *udev = port->serial->dev; +	int ret; + +	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), +				SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, +				0, 0, buf, 7, 100); +	if (ret != 7) { +		dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); + +		if (ret > 0) +			ret = -EIO; + +		return ret; +	} + +	dev_dbg(&port->dev, "%s - %7ph\n", __func__, buf); + +	return 0;  }  static void pl2303_set_termios(struct tty_struct *tty, @@ -477,51 +464,40 @@ static void pl2303_set_termios(struct tty_struct *tty,  	struct pl2303_private *priv = usb_get_serial_port_data(port);  	unsigned long flags;  	unsigned char *buf; -	int i; +	int ret;  	u8 control; -	/* -	 * The PL2303 is reported to lose bytes if you change serial settings -	 * even to the same values as before. Thus we actually need to filter -	 * in this specific case. -	 */  	if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))  		return;  	buf = kzalloc(7, GFP_KERNEL);  	if (!buf) { -		dev_err(&port->dev, "%s - out of memory.\n", __func__);  		/* Report back no change occurred */  		if (old_termios)  			tty->termios = *old_termios;  		return;  	} -	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), -			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, -			    0, 0, buf, 7, 100); -	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %7ph\n", i, buf); +	pl2303_get_line_request(port, buf); -	if (C_CSIZE(tty)) { -		switch (C_CSIZE(tty)) { -		case CS5: -			buf[6] = 5; -			break; -		case CS6: -			buf[6] = 6; -			break; -		case CS7: -			buf[6] = 7; -			break; -		default: -		case CS8: -			buf[6] = 8; -		} -		dev_dbg(&port->dev, "data bits = %d\n", buf[6]); +	switch (C_CSIZE(tty)) { +	case CS5: +		buf[6] = 5; +		break; +	case CS6: +		buf[6] = 6; +		break; +	case CS7: +		buf[6] = 7; +		break; +	default: +	case CS8: +		buf[6] = 8;  	} +	dev_dbg(&port->dev, "data bits = %d\n", buf[6]); -	/* For reference:   buf[0]:buf[3] baud rate value */ -	pl2303_encode_baudrate(tty, port, spriv->type, buf); +	/* For reference buf[0]:buf[3] baud rate value */ +	pl2303_encode_baud_rate(tty, port, &buf[0]);  	/* For reference buf[4]=0 is 1 stop bits */  	/* For reference buf[4]=1 is 1.5 stop bits */ @@ -550,7 +526,7 @@ static void pl2303_set_termios(struct tty_struct *tty,  		/* For reference buf[5]=3 is mark parity */  		/* For reference buf[5]=4 is space parity */  		if (C_PARODD(tty)) { -			if (tty->termios.c_cflag & CMSPAR) { +			if (C_CMSPAR(tty)) {  				buf[5] = 3;  				dev_dbg(&port->dev, "parity = mark\n");  			} else { @@ -558,7 +534,7 @@ static void pl2303_set_termios(struct tty_struct *tty,  				dev_dbg(&port->dev, "parity = odd\n");  			}  		} else { -			if (tty->termios.c_cflag & CMSPAR) { +			if (C_CMSPAR(tty)) {  				buf[5] = 4;  				dev_dbg(&port->dev, "parity = space\n");  			} else { @@ -571,10 +547,23 @@ static void pl2303_set_termios(struct tty_struct *tty,  		dev_dbg(&port->dev, "parity = none\n");  	} -	i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), -			    SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, -			    0, 0, buf, 7, 100); -	dev_dbg(&port->dev, "0x21:0x20:0:0  %d\n", i); +	/* +	 * Some PL2303 are known to lose bytes if you change serial settings +	 * even to the same values as before. Thus we actually need to filter +	 * in this specific case. +	 * +	 * Note that the tty_termios_hw_change check above is not sufficient +	 * as a previously requested baud rate may differ from the one +	 * actually used (and stored in old_termios). +	 * +	 * NOTE: No additional locking needed for line_settings as it is +	 *       only used in set_termios, which is serialised against itself. +	 */ +	if (!old_termios || memcmp(buf, priv->line_settings, 7)) { +		ret = pl2303_set_line_request(port, buf); +		if (!ret) +			memcpy(priv->line_settings, buf, 7); +	}  	/* change control lines if we are switching to or from B0 */  	spin_lock_irqsave(&priv->lock, flags); @@ -591,19 +580,13 @@ static void pl2303_set_termios(struct tty_struct *tty,  		spin_unlock_irqrestore(&priv->lock, flags);  	} -	memset(buf, 0, 7); -	i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), -			    GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, -			    0, 0, buf, 7, 100); -	dev_dbg(&port->dev, "0xa1:0x21:0:0  %d - %7ph\n", i, buf); -  	if (C_CRTSCTS(tty)) { -		if (spriv->type == type_0 || spriv->type == type_1) -			pl2303_vendor_write(0x0, 0x41, serial); +		if (spriv->quirks & PL2303_QUIRK_LEGACY) +			pl2303_vendor_write(serial, 0x0, 0x41);  		else -			pl2303_vendor_write(0x0, 0x61, serial); +			pl2303_vendor_write(serial, 0x0, 0x61);  	} else { -		pl2303_vendor_write(0x0, 0x0, serial); +		pl2303_vendor_write(serial, 0x0, 0x0);  	}  	kfree(buf); @@ -616,13 +599,13 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on)  	u8 control;  	spin_lock_irqsave(&priv->lock, flags); -	/* Change DTR and RTS */  	if (on)  		priv->line_control |= (CONTROL_DTR | CONTROL_RTS);  	else  		priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);  	control = priv->line_control;  	spin_unlock_irqrestore(&priv->lock, flags); +  	pl2303_set_control_lines(port, control);  } @@ -638,13 +621,13 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)  	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);  	int result; -	if (spriv->type == type_0 || spriv->type == type_1) { +	if (spriv->quirks & PL2303_QUIRK_LEGACY) {  		usb_clear_halt(serial->dev, port->write_urb->pipe);  		usb_clear_halt(serial->dev, port->read_urb->pipe);  	} else {  		/* reset upstream data pipes */ -		pl2303_vendor_write(8, 0, serial); -		pl2303_vendor_write(9, 0, serial); +		pl2303_vendor_write(serial, 8, 0); +		pl2303_vendor_write(serial, 9, 0);  	}  	/* Setup termios */ @@ -653,8 +636,8 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)  	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);  	if (result) { -		dev_err(&port->dev, "%s - failed submitting interrupt urb," -			" error %d\n", __func__, result); +		dev_err(&port->dev, "failed to submit interrupt urb: %d\n", +			result);  		return result;  	} @@ -724,48 +707,10 @@ static int pl2303_tiocmget(struct tty_struct *tty)  static int pl2303_carrier_raised(struct usb_serial_port *port)  {  	struct pl2303_private *priv = usb_get_serial_port_data(port); +  	if (priv->line_status & UART_DCD)  		return 1; -	return 0; -} -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; -	unsigned int status; -	unsigned int changed; - -	spin_lock_irqsave(&priv->lock, flags); -	prevstatus = priv->line_status; -	spin_unlock_irqrestore(&priv->lock, flags); - -	while (1) { -		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); - -		changed = prevstatus ^ status; - -		if (((arg & TIOCM_RNG) && (changed & UART_RING)) || -		    ((arg & TIOCM_DSR) && (changed & UART_DSR)) || -		    ((arg & TIOCM_CD)  && (changed & UART_DCD)) || -		    ((arg & TIOCM_CTS) && (changed & UART_CTS))) { -			return 0; -		} -		prevstatus = status; -	} -	/* NOTREACHED */  	return 0;  } @@ -775,8 +720,6 @@ static int pl2303_ioctl(struct tty_struct *tty,  	struct serial_struct ser;  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(&port->dev, "%s cmd = 0x%04x\n", __func__, cmd); -  	switch (cmd) {  	case TIOCGSERIAL:  		memset(&ser, 0, sizeof ser); @@ -790,9 +733,9 @@ static int pl2303_ioctl(struct tty_struct *tty,  		return 0;  	default: -		dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd);  		break;  	} +  	return -ENOIOCTLCMD;  } @@ -807,6 +750,7 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state)  		state = BREAK_OFF;  	else  		state = BREAK_ON; +  	dev_dbg(&port->dev, "%s - turning break %s\n", __func__,  			state == BREAK_OFF ? "off" : "on"); @@ -821,48 +765,51 @@ static void pl2303_update_line_status(struct usb_serial_port *port,  				      unsigned char *data,  				      unsigned int actual_length)  { - +	struct usb_serial *serial = port->serial; +	struct pl2303_serial_private *spriv = usb_get_serial_data(serial);  	struct pl2303_private *priv = usb_get_serial_port_data(port);  	struct tty_struct *tty;  	unsigned long flags; -	u8 status_idx = UART_STATE; -	u8 length = UART_STATE + 1; -	u8 prev_line_status; -	u16 idv, idp; - -	idv = le16_to_cpu(port->serial->dev->descriptor.idVendor); -	idp = le16_to_cpu(port->serial->dev->descriptor.idProduct); +	unsigned int status_idx = UART_STATE_INDEX; +	u8 status; +	u8 delta; +	if (spriv->quirks & PL2303_QUIRK_UART_STATE_IDX0) +		status_idx = 0; -	if (idv == SIEMENS_VENDOR_ID) { -		if (idp == SIEMENS_PRODUCT_ID_X65 || -		    idp == SIEMENS_PRODUCT_ID_SX1 || -		    idp == SIEMENS_PRODUCT_ID_X75) { - -			length = 1; -			status_idx = 0; -		} -	} - -	if (actual_length < length) +	if (actual_length < status_idx + 1)  		return; +	status = data[status_idx]; +  	/* Save off the uart status for others to look at */  	spin_lock_irqsave(&priv->lock, flags); -	prev_line_status = priv->line_status; -	priv->line_status = data[status_idx]; +	delta = priv->line_status ^ status; +	priv->line_status = status;  	spin_unlock_irqrestore(&priv->lock, flags); -	if (priv->line_status & UART_BREAK_ERROR) + +	if (status & UART_BREAK_ERROR)  		usb_serial_handle_break(port); -	wake_up_interruptible(&port->port.delta_msr_wait); -	tty = tty_port_tty_get(&port->port); -	if (!tty) -		return; -	if ((priv->line_status ^ prev_line_status) & UART_DCD) -		usb_serial_handle_dcd_change(port, tty, -				priv->line_status & UART_DCD); -	tty_kref_put(tty); +	if (delta & UART_STATE_MSR_MASK) { +		if (delta & UART_CTS) +			port->icount.cts++; +		if (delta & UART_DSR) +			port->icount.dsr++; +		if (delta & UART_RING) +			port->icount.rng++; +		if (delta & UART_DCD) { +			port->icount.dcd++; +			tty = tty_port_tty_get(&port->port); +			if (tty) { +				usb_serial_handle_dcd_change(port, tty, +							status & UART_DCD); +				tty_kref_put(tty); +			} +		} + +		wake_up_interruptible(&port->port.delta_msr_wait); +	}  }  static void pl2303_read_int_callback(struct urb *urb) @@ -897,10 +844,11 @@ static void pl2303_read_int_callback(struct urb *urb)  exit:  	retval = usb_submit_urb(urb, GFP_ATOMIC); -	if (retval) +	if (retval) {  		dev_err(&port->dev,  			"%s - usb_submit_urb failed with result %d\n",  			__func__, retval); +	}  }  static void pl2303_process_read_urb(struct urb *urb) @@ -918,13 +866,14 @@ 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(&port->port.delta_msr_wait);  	if (!urb->actual_length)  		return; -	/* break takes precedence over parity, */ -	/* which takes precedence over framing errors */ +	/* +	 * Break takes precedence over parity, which takes precedence over +	 * framing errors. +	 */  	if (line_status & UART_BREAK_ERROR)  		tty_flag = TTY_BREAK;  	else if (line_status & UART_PARITY_ERROR) @@ -952,7 +901,6 @@ static void pl2303_process_read_urb(struct urb *urb)  	tty_flip_buffer_push(&port->port);  } -/* All of the device info needed for the PL2303 SIO serial converter */  static struct usb_serial_driver pl2303_device = {  	.driver = {  		.owner =	THIS_MODULE, @@ -964,16 +912,17 @@ static struct usb_serial_driver pl2303_device = {  	.bulk_out_size =	256,  	.open =			pl2303_open,  	.close =		pl2303_close, -	.dtr_rts = 		pl2303_dtr_rts, +	.dtr_rts =		pl2303_dtr_rts,  	.carrier_raised =	pl2303_carrier_raised,  	.ioctl =		pl2303_ioctl,  	.break_ctl =		pl2303_break_ctl,  	.set_termios =		pl2303_set_termios,  	.tiocmget =		pl2303_tiocmget,  	.tiocmset =		pl2303_tiocmset, -	.tiocmiwait =		pl2303_tiocmiwait, +	.tiocmiwait =		usb_serial_generic_tiocmiwait,  	.process_read_urb =	pl2303_process_read_urb,  	.read_int_callback =	pl2303_read_int_callback, +	.probe =		pl2303_probe,  	.attach =		pl2303_startup,  	.release =		pl2303_release,  	.port_probe =		pl2303_port_probe, @@ -986,5 +935,5 @@ static struct usb_serial_driver * const serial_drivers[] = {  module_usb_serial_driver(serial_drivers, id_table); -MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_DESCRIPTION("Prolific PL2303 USB to serial adaptor driver");  MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index c38b8c00c06..42bc082896a 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -121,8 +121,11 @@  #define SUPERIAL_VENDOR_ID	0x5372  #define SUPERIAL_PRODUCT_ID	0x2303 -/* Hewlett-Packard LD220-HP POS Pole Display */ +/* Hewlett-Packard POS Pole Displays */  #define HP_VENDOR_ID		0x03f0 +#define HP_LD960_PRODUCT_ID	0x0b39 +#define HP_LCM220_PRODUCT_ID	0x3139 +#define HP_LCM960_PRODUCT_ID	0x3239  #define HP_LD220_PRODUCT_ID	0x3524  /* Cressi Edy (diving computer) PC interface */ diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c index 31f81c3c15e..6e9f8af9695 100644 --- a/drivers/usb/serial/qcaux.c +++ b/drivers/usb/serial/qcaux.c @@ -16,7 +16,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/tty.h>  #include <linux/module.h>  #include <linux/usb.h> @@ -54,7 +53,7 @@  #define SAMSUNG_VENDOR_ID			0x04e8  #define SAMSUNG_PRODUCT_U520			0x6640 /* SCH-U520 */ -static struct usb_device_id id_table[] = { +static const struct usb_device_id id_table[] = {  	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5740, 0xff, 0x00, 0x00) },  	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5750, 0xff, 0x00, 0x00) },  	{ USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM150, 0xff, 0x00, 0x00) }, diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index c65437cfd4a..b2aa003bf41 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -22,8 +22,17 @@  #define DRIVER_AUTHOR "Qualcomm Inc"  #define DRIVER_DESC "Qualcomm USB Serial driver" +/* standard device layouts supported by this driver */ +enum qcserial_layouts { +	QCSERIAL_G2K = 0,	/* Gobi 2000 */ +	QCSERIAL_G1K = 1,	/* Gobi 1000 */ +	QCSERIAL_SWI = 2,	/* Sierra Wireless */ +}; +  #define DEVICE_G1K(v, p) \ -	USB_DEVICE(v, p), .driver_info = 1 +	USB_DEVICE(v, p), .driver_info = QCSERIAL_G1K +#define DEVICE_SWI(v, p) \ +	USB_DEVICE(v, p), .driver_info = QCSERIAL_SWI  static const struct usb_device_id id_table[] = {  	/* Gobi 1000 devices */ @@ -126,19 +135,27 @@ static const struct usb_device_id id_table[] = {  	{USB_DEVICE(0x12D1, 0x14F1)},	/* Sony Gobi 3000 Composite */  	{USB_DEVICE(0x0AF0, 0x8120)},	/* Option GTM681W */ -	/* non Gobi Qualcomm serial devices */ -	{USB_DEVICE_INTERFACE_NUMBER(0x0f3d, 0x68a2, 0)},	/* Sierra Wireless MC7700 Device Management */ -	{USB_DEVICE_INTERFACE_NUMBER(0x0f3d, 0x68a2, 2)},	/* Sierra Wireless MC7700 NMEA */ -	{USB_DEVICE_INTERFACE_NUMBER(0x0f3d, 0x68a2, 3)},	/* Sierra Wireless MC7700 Modem */ -	{USB_DEVICE_INTERFACE_NUMBER(0x114f, 0x68a2, 0)},	/* Sierra Wireless MC7750 Device Management */ -	{USB_DEVICE_INTERFACE_NUMBER(0x114f, 0x68a2, 2)},	/* Sierra Wireless MC7750 NMEA */ -	{USB_DEVICE_INTERFACE_NUMBER(0x114f, 0x68a2, 3)},	/* Sierra Wireless MC7750 Modem */ -	{USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x68a2, 0)},	/* Sierra Wireless MC7710 Device Management */ -	{USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x68a2, 2)},	/* Sierra Wireless MC7710 NMEA */ -	{USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x68a2, 3)},	/* Sierra Wireless MC7710 Modem */ -	{USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 0)},	/* Sierra Wireless EM7700 Device Management */ -	{USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 2)},	/* Sierra Wireless EM7700 NMEA */ -	{USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 3)},	/* Sierra Wireless EM7700 Modem */ +	/* non-Gobi Sierra Wireless devices */ +	{DEVICE_SWI(0x0f3d, 0x68a2)},	/* Sierra Wireless MC7700 */ +	{DEVICE_SWI(0x114f, 0x68a2)},	/* Sierra Wireless MC7750 */ +	{DEVICE_SWI(0x1199, 0x68a2)},	/* Sierra Wireless MC7710 */ +	{DEVICE_SWI(0x1199, 0x68c0)},	/* Sierra Wireless MC73xx */ +	{DEVICE_SWI(0x1199, 0x901c)},	/* Sierra Wireless EM7700 */ +	{DEVICE_SWI(0x1199, 0x901f)},	/* Sierra Wireless EM7355 */ +	{DEVICE_SWI(0x1199, 0x9040)},	/* Sierra Wireless Modem */ +	{DEVICE_SWI(0x1199, 0x9041)},	/* Sierra Wireless MC7305/MC7355 */ +	{DEVICE_SWI(0x1199, 0x9051)},	/* Netgear AirCard 340U */ +	{DEVICE_SWI(0x1199, 0x9053)},	/* Sierra Wireless Modem */ +	{DEVICE_SWI(0x1199, 0x9054)},	/* Sierra Wireless Modem */ +	{DEVICE_SWI(0x1199, 0x9055)},	/* Netgear AirCard 341U */ +	{DEVICE_SWI(0x1199, 0x9056)},	/* Sierra Wireless Modem */ +	{DEVICE_SWI(0x1199, 0x9060)},	/* Sierra Wireless Modem */ +	{DEVICE_SWI(0x1199, 0x9061)},	/* Sierra Wireless Modem */ +	{DEVICE_SWI(0x413c, 0x81a2)},	/* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */ +	{DEVICE_SWI(0x413c, 0x81a3)},	/* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */ +	{DEVICE_SWI(0x413c, 0x81a4)},	/* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ +	{DEVICE_SWI(0x413c, 0x81a8)},	/* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */ +	{DEVICE_SWI(0x413c, 0x81a9)},	/* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */  	{ }				/* Terminating entry */  }; @@ -151,11 +168,8 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)  	int retval = -ENODEV;  	__u8 nintf;  	__u8 ifnum; -	bool is_gobi1k = id->driver_info ? true : false;  	int altsetting = -1; -	dev_dbg(dev, "Is Gobi 1000 = %d\n", is_gobi1k); -  	nintf = serial->dev->actconfig->desc.bNumInterfaces;  	dev_dbg(dev, "Num Interfaces = %d\n", nintf);  	ifnum = intf->desc.bInterfaceNumber; @@ -183,32 +197,29 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)  	} -	/* allow any number of interfaces when doing direct interface match */ -	if (id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) { -		dev_dbg(dev, "Generic Qualcomm serial interface found\n"); -		altsetting = 0; -		goto done; -	} - -	if (nintf < 3 || nintf > 4) { -		dev_err(dev, "unknown number of interfaces: %d\n", nintf); -		goto done; -	} -  	/* default to enabling interface */  	altsetting = 0; -	/* Composite mode; don't bind to the QMI/net interface as that +	/* +	 * Composite mode; don't bind to the QMI/net interface as that  	 * gets handled by other drivers.  	 */ -	if (is_gobi1k) { -		/* Gobi 1K USB layout: +	switch (id->driver_info) { +	case QCSERIAL_G1K: +		/* +		 * Gobi 1K USB layout:  		 * 0: DM/DIAG (use libqcdm from ModemManager for communication)  		 * 1: serial port (doesn't respond)  		 * 2: AT-capable modem port  		 * 3: QMI/net  		 */ +		if (nintf < 3 || nintf > 4) { +			dev_err(dev, "unknown number of interfaces: %d\n", nintf); +			altsetting = -1; +			goto done; +		} +  		if (ifnum == 0) {  			dev_dbg(dev, "Gobi 1K DM/DIAG interface found\n");  			altsetting = 1; @@ -216,13 +227,21 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)  			dev_dbg(dev, "Modem port found\n");  		else  			altsetting = -1; -	} else { -		/* Gobi 2K+ USB layout: +		break; +	case QCSERIAL_G2K: +		/* +		 * Gobi 2K+ USB layout:  		 * 0: QMI/net  		 * 1: DM/DIAG (use libqcdm from ModemManager for communication)  		 * 2: AT-capable modem port  		 * 3: NMEA  		 */ +		if (nintf < 3 || nintf > 4) { +			dev_err(dev, "unknown number of interfaces: %d\n", nintf); +			altsetting = -1; +			goto done; +		} +  		switch (ifnum) {  		case 0:  			/* Don't claim the QMI/net interface */ @@ -243,6 +262,35 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)  			dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n");  			break;  		} +		break; +	case QCSERIAL_SWI: +		/* +		 * Sierra Wireless layout: +		 * 0: DM/DIAG (use libqcdm from ModemManager for communication) +		 * 2: NMEA +		 * 3: AT-capable modem port +		 * 8: QMI/net +		 */ +		switch (ifnum) { +		case 0: +			dev_dbg(dev, "DM/DIAG interface found\n"); +			break; +		case 2: +			dev_dbg(dev, "NMEA GPS interface found\n"); +			break; +		case 3: +			dev_dbg(dev, "Modem port found\n"); +			break; +		default: +			/* don't claim any unsupported interface */ +			altsetting = -1; +			break; +		} +		break; +	default: +		dev_err(dev, "unsupported device layout type: %lu\n", +			id->driver_info); +		break;  	}  done: diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index a24d59ae403..504f5bff79c 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -15,7 +15,6 @@  #include <asm/unaligned.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -373,7 +372,7 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)  				 device_port, data, 2, QT2_USB_TIMEOUT);  	if (status < 0) { -		dev_err(&port->dev, "%s - open port failed %i", __func__, +		dev_err(&port->dev, "%s - open port failed %i\n", __func__,  			status);  		kfree(data);  		return status; @@ -676,10 +675,8 @@ static int qt2_setup_urbs(struct usb_serial *serial)  	serial_priv = usb_get_serial_data(serial);  	serial_priv->read_urb = usb_alloc_urb(0, GFP_KERNEL); -	if (!serial_priv->read_urb) { -		dev_err(&serial->dev->dev, "No free urbs available\n"); +	if (!serial_priv->read_urb)  		return -ENOMEM; -	}  	usb_fill_bulk_urb(serial_priv->read_urb, serial->dev,  			  usb_rcvbulkpipe(serial->dev, @@ -715,10 +712,8 @@ static int qt2_attach(struct usb_serial *serial)  	}  	serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL); -	if (!serial_priv) { -		dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); +	if (!serial_priv)  		return -ENOMEM; -	}  	serial_priv->read_buffer = kmalloc(QT2_READ_BUFFER_SIZE, GFP_KERNEL);  	if (!serial_priv->read_buffer) { diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index ba895989d8c..b2dff0f1474 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -67,7 +67,6 @@  #include <linux/kernel.h>  #include <linux/errno.h>  #include <linux/gfp.h> -#include <linux/init.h>  #include <linux/tty.h>  #include <linux/tty_driver.h>  #include <linux/tty_flip.h> @@ -125,7 +124,7 @@ MODULE_PARM_DESC(padded, "Pad to full wMaxPacketSize On/Off");  	.bInterfaceClass = (ic), \  	.bInterfaceSubClass = (isc), -static struct usb_device_id id_table[] = { +static const struct usb_device_id id_table[] = {  	{MY_USB_DEVICE(0x49f, 0xffff, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	/* Itsy */  	{MY_USB_DEVICE(0x3f0, 0x2101, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	/* Calypso */  	{MY_USB_DEVICE(0x4dd, 0x8001, CDC_DEVICE_CLASS, LINEO_INTERFACE_CLASS, LINEO_INTERFACE_SUBCLASS_SAFESERIAL)},	/* Iris */ diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index de958c5b52e..6f7f01eb556 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -58,6 +58,7 @@ struct sierra_intf_private {  	spinlock_t susp_lock;  	unsigned int suspended:1;  	int in_flight; +	unsigned int open_ports;  };  static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) @@ -291,7 +292,6 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(0x0f3d, 0x68A3), 	/* Airprime/Sierra Wireless Direct IP modems */  	  .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist  	}, -       { USB_DEVICE(0x413C, 0x08133) }, /* Dell Computer Corp. Wireless 5720 VZW Mobile Broadband (EVDO Rev-A) Minicard GPS Port */  	{ }  }; @@ -316,7 +316,6 @@ struct sierra_port_private {  	int dsr_state;  	int dcd_state;  	int ri_state; -	unsigned int opened:1;  };  static int sierra_send_setup(struct usb_serial_port *port) @@ -365,20 +364,13 @@ static int sierra_send_setup(struct usb_serial_port *port)  	if (retval < 0)  		return retval; -	retval = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), +	retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),  		0x22, 0x21, val, interface, NULL, 0, USB_CTRL_SET_TIMEOUT);  	usb_autopm_put_interface(serial->interface);  	return retval;  } -static void sierra_set_termios(struct tty_struct *tty, -		struct usb_serial_port *port, struct ktermios *old_termios) -{ -	tty_termios_copy_hw(&tty->termios, old_termios); -	sierra_send_setup(port); -} -  static int sierra_tiocmget(struct tty_struct *tty)  {  	struct usb_serial_port *port = tty->driver_data; @@ -419,9 +411,7 @@ static int sierra_tiocmset(struct tty_struct *tty,  static void sierra_release_urb(struct urb *urb)  { -	struct usb_serial_port *port;  	if (urb) { -		port = urb->context;  		kfree(urb->transfer_buffer);  		usb_free_urb(urb);  	} @@ -434,7 +424,7 @@ static void sierra_outdat_callback(struct urb *urb)  	struct sierra_intf_private *intfdata;  	int status = urb->status; -	intfdata = port->serial->private; +	intfdata = usb_get_serial_data(port->serial);  	/* free up the transfer buffer, as usb_free_urb() does not do this */  	kfree(urb->transfer_buffer); @@ -471,7 +461,7 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,  		return 0;  	portdata = usb_get_serial_port_data(port); -	intfdata = serial->private; +	intfdata = usb_get_serial_data(serial);  	dev_dbg(&port->dev, "%s: write (%zd bytes)\n", __func__, writesize);  	spin_lock_irqsave(&portdata->lock, flags); @@ -497,14 +487,12 @@ static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,  	buffer = kmalloc(writesize, GFP_ATOMIC);  	if (!buffer) { -		dev_err(&port->dev, "out of memory\n");  		retval = -ENOMEM;  		goto error_no_buffer;  	}  	urb = usb_alloc_urb(0, GFP_ATOMIC);  	if (!urb) { -		dev_err(&port->dev, "no more free urbs\n");  		retval = -ENOMEM;  		goto error_no_urb;  	} @@ -677,6 +665,23 @@ static int sierra_write_room(struct tty_struct *tty)  	return 2048;  } +static int sierra_chars_in_buffer(struct tty_struct *tty) +{ +	struct usb_serial_port *port = tty->driver_data; +	struct sierra_port_private *portdata = usb_get_serial_port_data(port); +	unsigned long flags; +	int chars; + +	/* NOTE: This overcounts somewhat. */ +	spin_lock_irqsave(&portdata->lock, flags); +	chars = portdata->outstanding_urbs * MAX_TRANSFER; +	spin_unlock_irqrestore(&portdata->lock, flags); + +	dev_dbg(&port->dev, "%s - %d\n", __func__, chars); + +	return chars; +} +  static void sierra_stop_rx_urbs(struct usb_serial_port *port)  {  	int i; @@ -732,15 +737,9 @@ static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,  	struct urb	*urb;  	u8		*buf; -	if (endpoint == -1) -		return NULL; -  	urb = usb_alloc_urb(0, mem_flags); -	if (urb == NULL) { -		dev_dbg(&serial->dev->dev, "%s: alloc for endpoint %d failed\n", -			__func__, endpoint); +	if (!urb)  		return NULL; -	}  	buf = kmalloc(len, mem_flags);  	if (buf) { @@ -752,9 +751,6 @@ static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,  		dev_dbg(&serial->dev->dev, "%s %c u : %p d:%p\n", __func__,  				dir == USB_DIR_IN ? 'i' : 'o', urb, buf);  	} else { -		dev_dbg(&serial->dev->dev, "%s %c u:%p d:%p\n", __func__, -				dir == USB_DIR_IN ? 'i' : 'o', urb, buf); -  		sierra_release_urb(urb);  		urb = NULL;  	} @@ -767,40 +763,48 @@ static void sierra_close(struct usb_serial_port *port)  	int i;  	struct usb_serial *serial = port->serial;  	struct sierra_port_private *portdata; -	struct sierra_intf_private *intfdata = port->serial->private; +	struct sierra_intf_private *intfdata = usb_get_serial_data(serial); +	struct urb *urb;  	portdata = usb_get_serial_port_data(port); -	portdata->rts_state = 0; -	portdata->dtr_state = 0; - -	mutex_lock(&serial->disc_mutex); -	if (!serial->disconnected) { +	/* +	 * Need to take susp_lock to make sure port is not already being +	 * resumed, but no need to hold it due to ASYNC_INITIALIZED. +	 */ +	spin_lock_irq(&intfdata->susp_lock); +	if (--intfdata->open_ports == 0)  		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); +	spin_unlock_irq(&intfdata->susp_lock); +	for (;;) { +		urb = usb_get_from_anchor(&portdata->delayed); +		if (!urb) +			break; +		kfree(urb->transfer_buffer); +		usb_free_urb(urb); +		usb_autopm_put_interface_async(serial->interface); +		spin_lock(&portdata->lock); +		portdata->outstanding_urbs--; +		spin_unlock(&portdata->lock);  	} -	mutex_unlock(&serial->disc_mutex); -	spin_lock_irq(&intfdata->susp_lock); -	portdata->opened = 0; -	spin_unlock_irq(&intfdata->susp_lock);  	sierra_stop_rx_urbs(port); +	usb_kill_anchored_urbs(&portdata->active); +  	for (i = 0; i < portdata->num_in_urbs; i++) {  		sierra_release_urb(portdata->in_urbs[i]);  		portdata->in_urbs[i] = NULL;  	} + +	usb_autopm_get_interface_no_resume(serial->interface);  }  static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)  {  	struct sierra_port_private *portdata;  	struct usb_serial *serial = port->serial; -	struct sierra_intf_private *intfdata = serial->private; +	struct sierra_intf_private *intfdata = usb_get_serial_data(serial);  	int i;  	int err;  	int endpoint; @@ -808,11 +812,6 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)  	portdata = usb_get_serial_port_data(port); -	/* Set some sane defaults */ -	portdata->rts_state = 1; -	portdata->dtr_state = 1; - -  	endpoint = port->bulk_in_endpointAddress;  	for (i = 0; i < portdata->num_in_urbs; i++) {  		urb = sierra_setup_urb(serial, endpoint, USB_DIR_IN, port, @@ -825,23 +824,26 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port)  			usb_sndbulkpipe(serial->dev, endpoint) | USB_DIR_IN);  	err = sierra_submit_rx_urbs(port, GFP_KERNEL); -	if (err) { -		/* get rid of everything as in close */ -		sierra_close(port); -		/* restore balance for autopm */ -		if (!serial->disconnected) -			usb_autopm_put_interface(serial->interface); -		return err; -	} -	sierra_send_setup(port); +	if (err) +		goto err_submit; -	serial->interface->needs_remote_wakeup = 1;  	spin_lock_irq(&intfdata->susp_lock); -	portdata->opened = 1; +	if (++intfdata->open_ports == 1) +		serial->interface->needs_remote_wakeup = 1;  	spin_unlock_irq(&intfdata->susp_lock);  	usb_autopm_put_interface(serial->interface);  	return 0; + +err_submit: +	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; +	} + +	return err;  } @@ -937,6 +939,7 @@ static int sierra_port_remove(struct usb_serial_port *port)  	struct sierra_port_private *portdata;  	portdata = usb_get_serial_port_data(port); +	usb_set_serial_port_data(port, NULL);  	kfree(portdata);  	return 0; @@ -953,6 +956,8 @@ static void stop_read_write_urbs(struct usb_serial *serial)  	for (i = 0; i < serial->num_ports; ++i) {  		port = serial->port[i];  		portdata = usb_get_serial_port_data(port); +		if (!portdata) +			continue;  		sierra_stop_rx_urbs(port);  		usb_kill_anchored_urbs(&portdata->active);  	} @@ -960,58 +965,84 @@ static void stop_read_write_urbs(struct usb_serial *serial)  static int sierra_suspend(struct usb_serial *serial, pm_message_t message)  { -	struct sierra_intf_private *intfdata; -	int b; +	struct sierra_intf_private *intfdata = usb_get_serial_data(serial); +	spin_lock_irq(&intfdata->susp_lock);  	if (PMSG_IS_AUTO(message)) { -		intfdata = serial->private; -		spin_lock_irq(&intfdata->susp_lock); -		b = intfdata->in_flight; - -		if (b) { +		if (intfdata->in_flight) {  			spin_unlock_irq(&intfdata->susp_lock);  			return -EBUSY; -		} else { -			intfdata->suspended = 1; -			spin_unlock_irq(&intfdata->susp_lock);  		}  	} +	intfdata->suspended = 1; +	spin_unlock_irq(&intfdata->susp_lock); +  	stop_read_write_urbs(serial);  	return 0;  } +/* Caller must hold susp_lock. */ +static int sierra_submit_delayed_urbs(struct usb_serial_port *port) +{ +	struct sierra_port_private *portdata = usb_get_serial_port_data(port); +	struct sierra_intf_private *intfdata; +	struct urb *urb; +	int ec = 0; +	int err; + +	intfdata = usb_get_serial_data(port->serial); + +	for (;;) { +		urb = usb_get_from_anchor(&portdata->delayed); +		if (!urb) +			break; + +		usb_anchor_urb(urb, &portdata->active); +		intfdata->in_flight++; +		err = usb_submit_urb(urb, GFP_ATOMIC); +		if (err) { +			dev_err(&port->dev, "%s - submit urb failed: %d", +					__func__, err); +			ec++; +			intfdata->in_flight--; +			usb_unanchor_urb(urb); +			kfree(urb->transfer_buffer); +			usb_free_urb(urb); + +			spin_lock(&portdata->lock); +			portdata->outstanding_urbs--; +			spin_unlock(&portdata->lock); +		} +	} + +	if (ec) +		return -EIO; + +	return 0; +} +  static int sierra_resume(struct usb_serial *serial)  {  	struct usb_serial_port *port; -	struct sierra_intf_private *intfdata = serial->private; -	struct sierra_port_private *portdata; -	struct urb *urb; +	struct sierra_intf_private *intfdata = usb_get_serial_data(serial);  	int ec = 0;  	int i, err;  	spin_lock_irq(&intfdata->susp_lock);  	for (i = 0; i < serial->num_ports; i++) {  		port = serial->port[i]; -		portdata = usb_get_serial_port_data(port); -		while ((urb = usb_get_from_anchor(&portdata->delayed))) { -			usb_anchor_urb(urb, &portdata->active); -			intfdata->in_flight++; -			err = usb_submit_urb(urb, GFP_ATOMIC); -			if (err < 0) { -				intfdata->in_flight--; -				usb_unanchor_urb(urb); -				usb_scuttle_anchored_urbs(&portdata->delayed); -				break; -			} -		} +		if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) +			continue; -		if (portdata->opened) { -			err = sierra_submit_rx_urbs(port, GFP_ATOMIC); -			if (err) -				ec++; -		} +		err = sierra_submit_delayed_urbs(port); +		if (err) +			ec++; + +		err = sierra_submit_rx_urbs(port, GFP_ATOMIC); +		if (err) +			ec++;  	}  	intfdata->suspended = 0;  	spin_unlock_irq(&intfdata->susp_lock); @@ -1038,7 +1069,7 @@ static struct usb_serial_driver sierra_device = {  	.dtr_rts	   = sierra_dtr_rts,  	.write             = sierra_write,  	.write_room        = sierra_write_room, -	.set_termios       = sierra_set_termios, +	.chars_in_buffer   = sierra_chars_in_buffer,  	.tiocmget          = sierra_tiocmget,  	.tiocmset          = sierra_tiocmset,  	.attach            = sierra_startup, diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 4abac28b599..ef0dbf0703c 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -16,7 +16,6 @@   */  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -221,9 +220,9 @@ static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status)  			      GET_UART_STATUS, GET_UART_STATUS_TYPE,  			      0, GET_UART_STATUS_MSR, buf, 1, 100);  	if (ret < 0) -		dev_err(&port->dev, "failed to get modem status: %d", ret); +		dev_err(&port->dev, "failed to get modem status: %d\n", ret); -	dev_dbg(&port->dev, "0xc0:0x22:0:6  %d - 0x02%x", ret, *buf); +	dev_dbg(&port->dev, "0xc0:0x22:0:6  %d - 0x02%x\n", ret, *buf);  	*status = *buf;  	kfree(buf); @@ -343,27 +342,24 @@ static void spcp8x5_set_termios(struct tty_struct *tty,  	case 1000000:  			buf[0] = 0x0b;	break;  	default: -		dev_err(&port->dev, "spcp825 driver does not support the " -			"baudrate requested, using default of 9600.\n"); +		dev_err(&port->dev, "unsupported baudrate, using 9600\n");  	}  	/* Set Data Length : 00:5bit, 01:6bit, 10:7bit, 11:8bit */ -	if (cflag & CSIZE) { -		switch (cflag & CSIZE) { -		case CS5: -			buf[1] |= SET_UART_FORMAT_SIZE_5; -			break; -		case CS6: -			buf[1] |= SET_UART_FORMAT_SIZE_6; -			break; -		case CS7: -			buf[1] |= SET_UART_FORMAT_SIZE_7; -			break; -		default: -		case CS8: -			buf[1] |= SET_UART_FORMAT_SIZE_8; -			break; -		} +	switch (cflag & CSIZE) { +	case CS5: +		buf[1] |= SET_UART_FORMAT_SIZE_5; +		break; +	case CS6: +		buf[1] |= SET_UART_FORMAT_SIZE_6; +		break; +	case CS7: +		buf[1] |= SET_UART_FORMAT_SIZE_7; +		break; +	default: +	case CS8: +		buf[1] |= SET_UART_FORMAT_SIZE_8; +		break;  	}  	/* Set Stop bit2 : 0:1bit 1:2bit */ diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index e5750be4905..a7fe664b6b7 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -6,7 +6,6 @@   */  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -342,8 +341,6 @@ static int ssu100_ioctl(struct tty_struct *tty,  {  	struct usb_serial_port *port = tty->driver_data; -	dev_dbg(&port->dev, "%s cmd 0x%04x\n", __func__, cmd); -  	switch (cmd) {  	case TIOCGSERIAL:  		return get_serial_info(port, @@ -352,8 +349,6 @@ static int ssu100_ioctl(struct tty_struct *tty,  		break;  	} -	dev_dbg(&port->dev, "%s arg not supported\n", __func__); -  	return -ENOIOCTLCMD;  } diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index 9b1648945e7..8fceec7298e 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -11,7 +11,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/tty.h>  #include <linux/slab.h>  #include <linux/tty_driver.h> @@ -75,9 +74,7 @@ static void symbol_int_callback(struct urb *urb)  		tty_insert_flip_string(&port->port, &data[1], data_length);  		tty_flip_buffer_push(&port->port);  	} else { -		dev_dbg(&port->dev, -			"Improper amount of data received from the device, " -			"%d bytes", urb->actual_length); +		dev_dbg(&port->dev, "%s - short packet\n", __func__);  	}  exit: diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 760b78560f6..3dd3ff8c50d 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -21,7 +21,6 @@  #include <linux/kernel.h>  #include <linux/errno.h>  #include <linux/firmware.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -143,7 +142,7 @@ static int ti_download_firmware(struct ti_device *tdev);  static int closing_wait = TI_DEFAULT_CLOSING_WAIT;  /* supported devices */ -static struct usb_device_id ti_id_table_3410[] = { +static const struct usb_device_id ti_id_table_3410[] = {  	{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },  	{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },  	{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -163,7 +162,7 @@ static struct usb_device_id ti_id_table_3410[] = {  	{ }	/* terminator */  }; -static struct usb_device_id ti_id_table_5052[] = { +static const struct usb_device_id ti_id_table_5052[] = {  	{ USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) },  	{ USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) },  	{ USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, @@ -171,7 +170,7 @@ static struct usb_device_id ti_id_table_5052[] = {  	{ }	/* terminator */  }; -static struct usb_device_id ti_id_table_combined[] = { +static const struct usb_device_id ti_id_table_combined[] = {  	{ USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },  	{ USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },  	{ USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -190,6 +189,7 @@ static struct usb_device_id ti_id_table_combined[] = {  	{ USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) },  	{ USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) },  	{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, +	{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },  	{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },  	{ }	/* terminator */  }; @@ -293,17 +293,16 @@ static int ti_startup(struct usb_serial *serial)  	int status;  	dev_dbg(&dev->dev, -		"%s - product 0x%4X, num configurations %d, configuration value %d", +		"%s - product 0x%4X, num configurations %d, configuration value %d\n",  		__func__, le16_to_cpu(dev->descriptor.idProduct),  		dev->descriptor.bNumConfigurations,  		dev->actconfig->desc.bConfigurationValue);  	/* create device structure */  	tdev = kzalloc(sizeof(struct ti_device), GFP_KERNEL); -	if (tdev == NULL) { -		dev_err(&dev->dev, "%s - out of memory\n", __func__); +	if (!tdev)  		return -ENOMEM; -	} +  	mutex_init(&tdev->td_open_close_lock);  	tdev->td_serial = serial;  	usb_set_serial_data(serial, tdev); @@ -682,8 +681,6 @@ static int ti_ioctl(struct tty_struct *tty,  	struct usb_serial_port *port = tty->driver_data;  	struct ti_port *tport = usb_get_serial_port_data(port); -	dev_dbg(&port->dev, "%s - cmd = 0x%04X\n", __func__, cmd); -  	if (tport == NULL)  		return -ENODEV; @@ -723,10 +720,8 @@ static void ti_set_termios(struct tty_struct *tty,  		return;  	config = kmalloc(sizeof(*config), GFP_KERNEL); -	if (!config) { -		dev_err(&port->dev, "%s - out of memory\n", __func__); +	if (!config)  		return; -	}  	config->wFlags = 0; @@ -808,7 +803,7 @@ static void ti_set_termios(struct tty_struct *tty,  		tty_encode_baud_rate(tty, baud, baud);  	dev_dbg(&port->dev, -		"%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d", +		"%s - BaudRate=%d, wBaudRate=%d, wFlags=0x%04X, bDataBits=%d, bParity=%d, bStopBits=%d, cXon=%d, cXoff=%d, bUartMode=%d\n",  		__func__, baud, config->wBaudRate, config->wFlags,  		config->bDataBits, config->bParity, config->bStopBits,  		config->cXon, config->cXoff, config->bUartMode); @@ -1195,10 +1190,8 @@ static int ti_get_lsr(struct ti_port *tport, u8 *lsr)  	size = sizeof(struct ti_port_status);  	data = kmalloc(size, GFP_KERNEL); -	if (!data) { -		dev_err(&port->dev, "%s - out of memory\n", __func__); +	if (!data)  		return -ENOMEM; -	}  	status = ti_command_in_sync(tdev, TI_GET_PORT_STATUS,  		(__u8)(TI_UART1_PORT+port_number), 0, (__u8 *)data, size); @@ -1398,10 +1391,8 @@ static int ti_write_byte(struct usb_serial_port *port,  	size = sizeof(struct ti_write_data_bytes) + 2;  	data = kmalloc(size, GFP_KERNEL); -	if (!data) { -		dev_err(&port->dev, "%s - out of memory\n", __func__); +	if (!data)  		return -ENOMEM; -	}  	data->bAddrType = TI_RW_DATA_ADDR_XDATA;  	data->bDataType = TI_RW_DATA_BYTE; @@ -1517,7 +1508,6 @@ static int ti_download_firmware(struct ti_device *tdev)  		status = ti_do_download(dev, pipe, buffer, fw_p->size);  		kfree(buffer);  	} else { -		dev_dbg(&dev->dev, "%s ENOMEM\n", __func__);  		status = -ENOMEM;  	}  	release_firmware(fw_p); diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index 52eb91f2eb2..fb79775447b 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -15,7 +15,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/tty.h>  #include <linux/module.h>  #include <linux/usb.h> @@ -72,7 +71,8 @@ DEVICE(hp4x, HP4X_IDS);  /* Suunto ANT+ USB Driver */  #define SUUNTO_IDS()			\ -	{ USB_DEVICE(0x0fcf, 0x1008) } +	{ USB_DEVICE(0x0fcf, 0x1008) },	\ +	{ USB_DEVICE(0x0fcf, 0x1009) } /* Dynastream ANT USB-m Stick */  DEVICE(suunto, SUUNTO_IDS);  /* Siemens USB/MPI adapter */ diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 6091bd5a1f4..02de3110fe9 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -405,7 +405,7 @@ static int serial_ioctl(struct tty_struct *tty,  	struct usb_serial_port *port = tty->driver_data;  	int retval = -ENOIOCTLCMD; -	dev_dbg(tty->dev, "%s - cmd 0x%.4x\n", __func__, cmd); +	dev_dbg(tty->dev, "%s - cmd 0x%04x\n", __func__, cmd);  	switch (cmd) {  	case TIOCMIWAIT: @@ -868,7 +868,7 @@ static int usb_serial_probe(struct usb_interface *interface,  	max_endpoints = max(max_endpoints, (int)serial->num_ports);  	serial->num_port_pointers = max_endpoints; -	dev_dbg(ddev, "setting up %d port structures for this device", max_endpoints); +	dev_dbg(ddev, "setting up %d port structure(s)\n", max_endpoints);  	for (i = 0; i < max_endpoints; ++i) {  		port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);  		if (!port) @@ -923,9 +923,8 @@ static int usb_serial_probe(struct usb_interface *interface,  		port = serial->port[i];  		if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))  			goto probe_error; -		buffer_size = serial->type->bulk_out_size; -		if (!buffer_size) -			buffer_size = usb_endpoint_maxp(endpoint); +		buffer_size = max_t(int, serial->type->bulk_out_size, +						usb_endpoint_maxp(endpoint));  		port->bulk_out_size = buffer_size;  		port->bulk_out_endpointAddress = endpoint->bEndpointAddress; @@ -1034,7 +1033,7 @@ static int usb_serial_probe(struct usb_interface *interface,  	for (i = 0; i < num_ports; ++i) {  		port = serial->port[i];  		dev_set_name(&port->dev, "ttyUSB%d", port->minor); -		dev_dbg(ddev, "registering %s", dev_name(&port->dev)); +		dev_dbg(ddev, "registering %s\n", dev_name(&port->dev));  		device_enable_async_suspend(&port->dev);  		retval = device_add(&port->dev); @@ -1061,6 +1060,7 @@ static void usb_serial_disconnect(struct usb_interface *interface)  	struct usb_serial *serial = usb_get_intfdata(interface);  	struct device *dev = &interface->dev;  	struct usb_serial_port *port; +	struct tty_struct *tty;  	usb_serial_console_disconnect(serial); @@ -1071,18 +1071,16 @@ static void usb_serial_disconnect(struct usb_interface *interface)  	for (i = 0; i < serial->num_ports; ++i) {  		port = serial->port[i]; -		if (port) { -			struct tty_struct *tty = tty_port_tty_get(&port->port); -			if (tty) { -				tty_vhangup(tty); -				tty_kref_put(tty); -			} -			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); +		tty = tty_port_tty_get(&port->port); +		if (tty) { +			tty_vhangup(tty); +			tty_kref_put(tty);  		} +		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);  	}  	if (serial->type->disconnect)  		serial->type->disconnect(serial); @@ -1095,7 +1093,6 @@ static void usb_serial_disconnect(struct usb_interface *interface)  int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)  {  	struct usb_serial *serial = usb_get_intfdata(intf); -	struct usb_serial_port *port;  	int i, r = 0;  	serial->suspending = 1; @@ -1113,12 +1110,8 @@ 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) -			usb_serial_port_poison_urbs(port); -	} - +	for (i = 0; i < serial->num_ports; ++i) +		usb_serial_port_poison_urbs(serial->port[i]);  err_out:  	return r;  } @@ -1126,14 +1119,10 @@ 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); -	} +	for (i = 0; i < serial->num_ports; ++i) +		usb_serial_port_unpoison_urbs(serial->port[i]);  }  int usb_serial_resume(struct usb_interface *intf) @@ -1161,9 +1150,9 @@ static int usb_serial_reset_resume(struct usb_interface *intf)  	usb_serial_unpoison_port_urbs(serial);  	serial->suspending = 0; -	if (serial->type->reset_resume) +	if (serial->type->reset_resume) {  		rv = serial->type->reset_resume(serial); -	else { +	} else {  		rv = -EOPNOTSUPP;  		intf->needs_binding = 1;  	} @@ -1338,9 +1327,9 @@ static int usb_serial_register(struct usb_serial_driver *driver)  	if (retval) {  		pr_err("problem %d when registering driver %s\n", retval, driver->description);  		list_del(&driver->driver_list); -	} else +	} else {  		pr_info("USB Serial support registered for %s\n", driver->description); - +	}  	mutex_unlock(&table_lock);  	return retval;  } @@ -1348,10 +1337,12 @@ static int usb_serial_register(struct usb_serial_driver *driver)  static void usb_serial_deregister(struct usb_serial_driver *device)  {  	pr_info("USB Serial deregistering driver %s\n", device->description); +  	mutex_lock(&table_lock);  	list_del(&device->driver_list); -	usb_serial_bus_deregister(device);  	mutex_unlock(&table_lock); + +	usb_serial_bus_deregister(device);  }  /** diff --git a/drivers/usb/serial/usb-wwan.h b/drivers/usb/serial/usb-wwan.h index 684739b8efd..f22dff58b58 100644 --- a/drivers/usb/serial/usb-wwan.h +++ b/drivers/usb/serial/usb-wwan.h @@ -11,15 +11,11 @@ extern void usb_wwan_close(struct usb_serial_port *port);  extern int usb_wwan_port_probe(struct usb_serial_port *port);  extern int usb_wwan_port_remove(struct usb_serial_port *port);  extern int usb_wwan_write_room(struct tty_struct *tty); -extern void usb_wwan_set_termios(struct tty_struct *tty, -				 struct usb_serial_port *port, -				 struct ktermios *old);  extern int usb_wwan_tiocmget(struct tty_struct *tty);  extern int usb_wwan_tiocmset(struct tty_struct *tty,  			     unsigned int set, unsigned int clear);  extern int usb_wwan_ioctl(struct tty_struct *tty,  			  unsigned int cmd, unsigned long arg); -extern int usb_wwan_send_setup(struct usb_serial_port *port);  extern int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,  			  const unsigned char *buf, int count);  extern int usb_wwan_chars_in_buffer(struct tty_struct *tty); @@ -39,6 +35,7 @@ struct usb_wwan_intf_private {  	spinlock_t susp_lock;  	unsigned int suspended:1;  	int in_flight; +	unsigned int open_ports;  	int (*send_setup) (struct usb_serial_port *port);  	void *private;  }; @@ -51,7 +48,6 @@ struct usb_wwan_port_private {  	struct urb *out_urbs[N_OUT_URB];  	u8 *out_buffer[N_OUT_URB];  	unsigned long out_busy;	/* Bit vector of URBs in use */ -	int opened;  	struct usb_anchor delayed;  	/* Settings for the port */ diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c index 5760f97ee50..ca2fa5bbe17 100644 --- a/drivers/usb/serial/usb_debug.c +++ b/drivers/usb/serial/usb_debug.c @@ -10,7 +10,6 @@  #include <linux/gfp.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/tty.h>  #include <linux/module.h>  #include <linux/usb.h> diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 85365784040..2f805cb386a 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -41,7 +41,7 @@ void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)  	struct usb_wwan_port_private *portdata;  	struct usb_wwan_intf_private *intfdata; -	intfdata = port->serial->private; +	intfdata = usb_get_serial_data(port->serial);  	if (!intfdata->send_setup)  		return; @@ -55,20 +55,6 @@ void usb_wwan_dtr_rts(struct usb_serial_port *port, int on)  }  EXPORT_SYMBOL(usb_wwan_dtr_rts); -void usb_wwan_set_termios(struct tty_struct *tty, -			  struct usb_serial_port *port, -			  struct ktermios *old_termios) -{ -	struct usb_wwan_intf_private *intfdata = port->serial->private; - -	/* Doesn't support option setting */ -	tty_termios_copy_hw(&tty->termios, old_termios); - -	if (intfdata->send_setup) -		intfdata->send_setup(port); -} -EXPORT_SYMBOL(usb_wwan_set_termios); -  int usb_wwan_tiocmget(struct tty_struct *tty)  {  	struct usb_serial_port *port = tty->driver_data; @@ -96,7 +82,7 @@ int usb_wwan_tiocmset(struct tty_struct *tty,  	struct usb_wwan_intf_private *intfdata;  	portdata = usb_get_serial_port_data(port); -	intfdata = port->serial->private; +	intfdata = usb_get_serial_data(port->serial);  	if (!intfdata->send_setup)  		return -EINVAL; @@ -192,7 +178,6 @@ int usb_wwan_ioctl(struct tty_struct *tty,  }  EXPORT_SYMBOL(usb_wwan_ioctl); -/* Write */  int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,  		   const unsigned char *buf, int count)  { @@ -205,7 +190,7 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,  	unsigned long flags;  	portdata = usb_get_serial_port_data(port); -	intfdata = port->serial->private; +	intfdata = usb_get_serial_data(port->serial);  	dev_dbg(&port->dev, "%s: write (%d chars)\n", __func__, count); @@ -228,8 +213,10 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,  			usb_pipeendpoint(this_urb->pipe), i);  		err = usb_autopm_get_interface_async(port->serial->interface); -		if (err < 0) +		if (err < 0) { +			clear_bit(i, &portdata->out_busy);  			break; +		}  		/* send the data */  		memcpy(this_urb->transfer_buffer, buf, todo); @@ -244,9 +231,9 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port,  			spin_unlock_irqrestore(&intfdata->susp_lock, flags);  			err = usb_submit_urb(this_urb, GFP_ATOMIC);  			if (err) { -				dev_dbg(&port->dev, -					"usb_submit_urb %p (write bulk) failed (%d)\n", -					this_urb, err); +				dev_err(&port->dev, +					"%s: submit urb %d failed: %d\n", +					__func__, i, err);  				clear_bit(i, &portdata->out_busy);  				spin_lock_irqsave(&intfdata->susp_lock, flags);  				intfdata->in_flight--; @@ -314,7 +301,7 @@ static void usb_wwan_outdat_callback(struct urb *urb)  	int i;  	port = urb->context; -	intfdata = port->serial->private; +	intfdata = usb_get_serial_data(port->serial);  	usb_serial_port_softint(port);  	usb_autopm_put_interface_async(port->serial->interface); @@ -325,7 +312,7 @@ static void usb_wwan_outdat_callback(struct urb *urb)  	for (i = 0; i < N_OUT_URB; ++i) {  		if (portdata->out_urbs[i] == urb) { -			smp_mb__before_clear_bit(); +			smp_mb__before_atomic();  			clear_bit(i, &portdata->out_busy);  			break;  		} @@ -384,7 +371,15 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)  	struct urb *urb;  	portdata = usb_get_serial_port_data(port); -	intfdata = serial->private; +	intfdata = usb_get_serial_data(serial); + +	if (port->interrupt_in_urb) { +		err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); +		if (err) { +			dev_err(&port->dev, "%s: submit int urb failed: %d\n", +				__func__, err); +		} +	}  	/* Start reading from the IN endpoint */  	for (i = 0; i < N_IN_URB; i++) { @@ -393,17 +388,15 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)  			continue;  		err = usb_submit_urb(urb, GFP_KERNEL);  		if (err) { -			dev_dbg(&port->dev, "%s: submit urb %d failed (%d) %d\n", -				__func__, i, err, urb->transfer_buffer_length); +			dev_err(&port->dev, +				"%s: submit read urb %d failed: %d\n", +				__func__, i, err);  		}  	} -	if (intfdata->send_setup) -		intfdata->send_setup(port); - -	serial->interface->needs_remote_wakeup = 1;  	spin_lock_irq(&intfdata->susp_lock); -	portdata->opened = 1; +	if (++intfdata->open_ports == 1) +		serial->interface->needs_remote_wakeup = 1;  	spin_unlock_irq(&intfdata->susp_lock);  	/* this balances a get in the generic USB serial code */  	usb_autopm_put_interface(serial->interface); @@ -412,32 +405,56 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port)  }  EXPORT_SYMBOL(usb_wwan_open); +static void unbusy_queued_urb(struct urb *urb, +					struct usb_wwan_port_private *portdata) +{ +	int i; + +	for (i = 0; i < N_OUT_URB; i++) { +		if (urb == portdata->out_urbs[i]) { +			clear_bit(i, &portdata->out_busy); +			break; +		} +	} +} +  void usb_wwan_close(struct usb_serial_port *port)  {  	int i;  	struct usb_serial *serial = port->serial;  	struct usb_wwan_port_private *portdata; -	struct usb_wwan_intf_private *intfdata = port->serial->private; +	struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); +	struct urb *urb;  	portdata = usb_get_serial_port_data(port); -	/* Stop reading/writing urbs */ +	/* +	 * Need to take susp_lock to make sure port is not already being +	 * resumed, but no need to hold it due to ASYNC_INITIALIZED. +	 */  	spin_lock_irq(&intfdata->susp_lock); -	portdata->opened = 0; +	if (--intfdata->open_ports == 0) +		serial->interface->needs_remote_wakeup = 0;  	spin_unlock_irq(&intfdata->susp_lock); +	for (;;) { +		urb = usb_get_from_anchor(&portdata->delayed); +		if (!urb) +			break; +		unbusy_queued_urb(urb, portdata); +		usb_autopm_put_interface_async(serial->interface); +	} +  	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]); +	usb_kill_urb(port->interrupt_in_urb); -	/* 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); -/* Helper functions used by usb_wwan_setup_urbs */  static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,  				      int endpoint,  				      int dir, void *ctx, char *buf, int len, @@ -447,14 +464,9 @@ static struct urb *usb_wwan_setup_urb(struct usb_serial_port *port,  	struct urb *urb;  	urb = usb_alloc_urb(0, GFP_KERNEL);	/* No ISO */ -	if (urb == NULL) { -		dev_dbg(&serial->interface->dev, -			"%s: alloc for endpoint %d failed.\n", __func__, -			endpoint); +	if (!urb)  		return NULL; -	} -	/* Fill URB using supplied data. */  	usb_fill_bulk_urb(urb, serial->dev,  			  usb_sndbulkpipe(serial->dev, endpoint) | dir,  			  buf, len, callback, ctx); @@ -467,9 +479,11 @@ int usb_wwan_port_probe(struct usb_serial_port *port)  	struct usb_wwan_port_private *portdata;  	struct urb *urb;  	u8 *buffer; -	int err;  	int i; +	if (!port->bulk_in_size || !port->bulk_out_size) +		return -ENODEV; +  	portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);  	if (!portdata)  		return -ENOMEM; @@ -477,9 +491,6 @@ int usb_wwan_port_probe(struct usb_serial_port *port)  	init_usb_anchor(&portdata->delayed);  	for (i = 0; i < N_IN_URB; i++) { -		if (!port->bulk_in_size) -			break; -  		buffer = (u8 *)__get_free_page(GFP_KERNEL);  		if (!buffer)  			goto bail_out_error; @@ -493,9 +504,6 @@ int usb_wwan_port_probe(struct usb_serial_port *port)  	}  	for (i = 0; i < N_OUT_URB; i++) { -		if (!port->bulk_out_size) -			break; -  		buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL);  		if (!buffer)  			goto bail_out_error2; @@ -510,13 +518,6 @@ int usb_wwan_port_probe(struct usb_serial_port *port)  	usb_set_serial_port_data(port, portdata); -	if (port->interrupt_in_urb) { -		err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); -		if (err) -			dev_dbg(&port->dev, "%s: submit irq_in urb failed %d\n", -				__func__, err); -	} -  	return 0;  bail_out_error2: @@ -543,32 +544,28 @@ int usb_wwan_port_remove(struct usb_serial_port *port)  	portdata = usb_get_serial_port_data(port);  	usb_set_serial_port_data(port, NULL); -	/* Stop reading/writing urbs and free them */  	for (i = 0; i < N_IN_URB; i++) { -		usb_kill_urb(portdata->in_urbs[i]);  		usb_free_urb(portdata->in_urbs[i]);  		free_page((unsigned long)portdata->in_buffer[i]);  	}  	for (i = 0; i < N_OUT_URB; i++) { -		usb_kill_urb(portdata->out_urbs[i]);  		usb_free_urb(portdata->out_urbs[i]);  		kfree(portdata->out_buffer[i]);  	} -	/* Now free port private data */  	kfree(portdata); +  	return 0;  }  EXPORT_SYMBOL(usb_wwan_port_remove);  #ifdef CONFIG_PM -static void stop_read_write_urbs(struct usb_serial *serial) +static void stop_urbs(struct usb_serial *serial)  {  	int i, j;  	struct usb_serial_port *port;  	struct usb_wwan_port_private *portdata; -	/* Stop reading/writing urbs */  	for (i = 0; i < serial->num_ports; ++i) {  		port = serial->port[i];  		portdata = usb_get_serial_port_data(port); @@ -578,123 +575,117 @@ static void stop_read_write_urbs(struct usb_serial *serial)  			usb_kill_urb(portdata->in_urbs[j]);  		for (j = 0; j < N_OUT_URB; j++)  			usb_kill_urb(portdata->out_urbs[j]); +		usb_kill_urb(port->interrupt_in_urb);  	}  }  int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)  { -	struct usb_wwan_intf_private *intfdata = serial->private; -	int b; +	struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial); +	spin_lock_irq(&intfdata->susp_lock);  	if (PMSG_IS_AUTO(message)) { -		spin_lock_irq(&intfdata->susp_lock); -		b = intfdata->in_flight; -		spin_unlock_irq(&intfdata->susp_lock); - -		if (b) +		if (intfdata->in_flight) { +			spin_unlock_irq(&intfdata->susp_lock);  			return -EBUSY; +		}  	} - -	spin_lock_irq(&intfdata->susp_lock);  	intfdata->suspended = 1;  	spin_unlock_irq(&intfdata->susp_lock); -	stop_read_write_urbs(serial); + +	stop_urbs(serial);  	return 0;  }  EXPORT_SYMBOL(usb_wwan_suspend); -static void unbusy_queued_urb(struct urb *urb, struct usb_wwan_port_private *portdata) +/* Caller must hold susp_lock. */ +static int usb_wwan_submit_delayed_urbs(struct usb_serial_port *port)  { -	int i; - -	for (i = 0; i < N_OUT_URB; i++) { -		if (urb == portdata->out_urbs[i]) { -			clear_bit(i, &portdata->out_busy); -			break; -		} -	} -} - -static void play_delayed(struct usb_serial_port *port) -{ -	struct usb_wwan_intf_private *data; +	struct usb_serial *serial = port->serial; +	struct usb_wwan_intf_private *data = usb_get_serial_data(serial);  	struct usb_wwan_port_private *portdata;  	struct urb *urb; +	int err_count = 0;  	int err;  	portdata = usb_get_serial_port_data(port); -	data = port->serial->private; -	while ((urb = usb_get_from_anchor(&portdata->delayed))) { -		err = usb_submit_urb(urb, GFP_ATOMIC); -		if (!err) { -			data->in_flight++; -		} else { -			/* we have to throw away the rest */ -			do { -				unbusy_queued_urb(urb, portdata); -				usb_autopm_put_interface_no_suspend(port->serial->interface); -			} while ((urb = usb_get_from_anchor(&portdata->delayed))); + +	for (;;) { +		urb = usb_get_from_anchor(&portdata->delayed); +		if (!urb)  			break; + +		err = usb_submit_urb(urb, GFP_ATOMIC); +		if (err) { +			dev_err(&port->dev, "%s: submit urb failed: %d\n", +					__func__, err); +			err_count++; +			unbusy_queued_urb(urb, portdata); +			usb_autopm_put_interface_async(serial->interface); +			continue;  		} +		data->in_flight++;  	} + +	if (err_count) +		return -EIO; + +	return 0;  }  int usb_wwan_resume(struct usb_serial *serial)  {  	int i, j;  	struct usb_serial_port *port; -	struct usb_wwan_intf_private *intfdata = serial->private; +	struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);  	struct usb_wwan_port_private *portdata;  	struct urb *urb; -	int err = 0; +	int err; +	int err_count = 0; -	/* get the interrupt URBs resubmitted unconditionally */ +	spin_lock_irq(&intfdata->susp_lock);  	for (i = 0; i < serial->num_ports; i++) {  		port = serial->port[i]; -		if (!port->interrupt_in_urb) { -			dev_dbg(&port->dev, "%s: No interrupt URB for port\n", __func__); + +		if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))  			continue; -		} -		err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); -		dev_dbg(&port->dev, "Submitted interrupt URB for port (result %d)\n", err); -		if (err < 0) { -			dev_err(&port->dev, "%s: Error %d for interrupt URB\n", -				__func__, err); -			goto err_out; -		} -	} -	for (i = 0; i < serial->num_ports; i++) { -		/* walk all ports */ -		port = serial->port[i];  		portdata = usb_get_serial_port_data(port); -		/* skip closed ports */ -		spin_lock_irq(&intfdata->susp_lock); -		if (!portdata || !portdata->opened) { -			spin_unlock_irq(&intfdata->susp_lock); -			continue; +		if (port->interrupt_in_urb) { +			err = usb_submit_urb(port->interrupt_in_urb, +					GFP_ATOMIC); +			if (err) { +				dev_err(&port->dev, +					"%s: submit int urb failed: %d\n", +					__func__, err); +				err_count++; +			}  		} +		err = usb_wwan_submit_delayed_urbs(port); +		if (err) +			err_count++; +  		for (j = 0; j < N_IN_URB; j++) {  			urb = portdata->in_urbs[j];  			err = usb_submit_urb(urb, GFP_ATOMIC);  			if (err < 0) { -				dev_err(&port->dev, "%s: Error %d for bulk URB %d\n", -					__func__, err, i); -				spin_unlock_irq(&intfdata->susp_lock); -				goto err_out; +				dev_err(&port->dev, +					"%s: submit read urb %d failed: %d\n", +					__func__, i, err); +				err_count++;  			}  		} -		play_delayed(port); -		spin_unlock_irq(&intfdata->susp_lock);  	} -	spin_lock_irq(&intfdata->susp_lock);  	intfdata->suspended = 0;  	spin_unlock_irq(&intfdata->susp_lock); -err_out: -	return err; + +	if (err_count) +		return -EIO; + +	return 0;  }  EXPORT_SYMBOL(usb_wwan_resume);  #endif diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 9910aa2edf4..bf2bd40e5f2 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -16,7 +16,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -51,7 +50,7 @@ static int palm_os_3_probe(struct usb_serial *serial,  static int palm_os_4_probe(struct usb_serial *serial,  					const struct usb_device_id *id); -static struct usb_device_id id_table [] = { +static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID),  		.driver_info = (kernel_ulong_t)&palm_os_3_probe },  	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID), @@ -113,18 +112,18 @@ static struct usb_device_id id_table [] = {  	{ }					/* Terminating entry */  }; -static struct usb_device_id clie_id_5_table [] = { +static const struct usb_device_id clie_id_5_table[] = {  	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID),  		.driver_info = (kernel_ulong_t)&palm_os_4_probe },  	{ }					/* Terminating entry */  }; -static struct usb_device_id clie_id_3_5_table [] = { +static const struct usb_device_id clie_id_3_5_table[] = {  	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },  	{ }					/* Terminating entry */  }; -static struct usb_device_id id_table_combined [] = { +static const struct usb_device_id id_table_combined[] = {  	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },  	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO_ID) },  	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_TREO600_ID) }, @@ -324,11 +323,8 @@ static int palm_os_3_probe(struct usb_serial *serial,  	int num_ports = 0;  	transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL); -	if (!transfer_buffer) { -		dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__, -			sizeof(*connection_info)); +	if (!transfer_buffer)  		return -ENOMEM; -	}  	/* send a get connection info request */  	retval = usb_control_msg(serial->dev, @@ -419,11 +415,8 @@ static int palm_os_4_probe(struct usb_serial *serial,  	int retval;  	transfer_buffer =  kmalloc(sizeof(*connection_info), GFP_KERNEL); -	if (!transfer_buffer) { -		dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__, -			sizeof(*connection_info)); +	if (!transfer_buffer)  		return -ENOMEM; -	}  	retval = usb_control_msg(serial->dev,  				  usb_rcvctrlpipe(serial->dev, 0), diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h index 88db4d06aef..4c456dd69ce 100644 --- a/drivers/usb/serial/visor.h +++ b/drivers/usb/serial/visor.h @@ -136,7 +136,7 @@ struct visor_connection_info {   *	connections.end_point_info is non-zero.  If value is 0, then   *	connections.port contains the endpoint number, which is the same for in   *	and out. - * @port_function_id: contains the creator id of the applicaton that opened + * @port_function_id: contains the creator id of the application that opened   *	this connection.   * @port: contains the in/out endpoint number.  Is 0 if in and out endpoint   *	numbers are different. diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 36a7740e827..e62f2dff8b7 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -18,7 +18,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/tty.h>  #include <linux/tty_driver.h> @@ -288,12 +287,8 @@ static int whiteheat_attach(struct usb_serial *serial)  	command_info = kmalloc(sizeof(struct whiteheat_command_private),  								GFP_KERNEL); -	if (command_info == NULL) { -		dev_err(&serial->dev->dev, -			"%s: Out of memory for port structures\n", -			serial->type->description); +	if (!command_info)  		goto no_command_private; -	}  	mutex_init(&command_info->mutex);  	command_info->port_running = 0; @@ -455,8 +450,6 @@ static int whiteheat_ioctl(struct tty_struct *tty,  	struct serial_struct serstruct;  	void __user *user_arg = (void __user *)arg; -	dev_dbg(&port->dev, "%s - cmd 0x%.4x\n", __func__, cmd); -  	switch (cmd) {  	case TIOCGSERIAL:  		memset(&serstruct, 0, sizeof(serstruct)); diff --git a/drivers/usb/serial/wishbone-serial.c b/drivers/usb/serial/wishbone-serial.c index 100573c6f19..4fed4a0bd70 100644 --- a/drivers/usb/serial/wishbone-serial.c +++ b/drivers/usb/serial/wishbone-serial.c @@ -11,7 +11,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/tty.h>  #include <linux/module.h>  #include <linux/usb.h> diff --git a/drivers/usb/serial/xsens_mt.c b/drivers/usb/serial/xsens_mt.c index 1d5798d891b..4841fb57400 100644 --- a/drivers/usb/serial/xsens_mt.c +++ b/drivers/usb/serial/xsens_mt.c @@ -9,7 +9,6 @@   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/tty.h>  #include <linux/module.h>  #include <linux/usb.h> diff --git a/drivers/usb/serial/zte_ev.c b/drivers/usb/serial/zte_ev.c index fca4c752a4e..e40ab739c4a 100644 --- a/drivers/usb/serial/zte_ev.c +++ b/drivers/usb/serial/zte_ev.c @@ -13,7 +13,6 @@   * show the commands used to talk to the device, but I am not sure.   */  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/tty.h>  #include <linux/slab.h>  #include <linux/module.h> @@ -53,7 +52,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,  				 USB_CTRL_GET_TIMEOUT);  	dev_dbg(dev, "result = %d\n", result); -	/* send  2st cmd and recieve data */ +	/* send 2st cmd and receive data */  	/*  	 * 16.0  CTL    a1 21 00 00  00 00 07 00   CLASS              25.1.0(5)  	 * 16.0  DI     00 96 00 00  00 00 08 @@ -65,7 +64,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,  				 USB_CTRL_GET_TIMEOUT);  	debug_data(dev, __func__, len, buf, result); -	/* send 3 cmd */ +	/* send 3rd cmd */  	/*  	 * 16.0 CTL    21 20 00 00  00 00 07 00    CLASS                30.1.0  	 * 16.0 DO     80 25 00 00  00 00 08       .%.....              30.2.0 @@ -84,7 +83,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,  				 USB_CTRL_GET_TIMEOUT);  	debug_data(dev, __func__, len, buf, result); -	/* send 4 cmd */ +	/* send 4th cmd */  	/*  	 * 16.0 CTL    21 22 03 00  00 00 00 00  	 */ @@ -95,7 +94,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,  				 USB_CTRL_GET_TIMEOUT);  	dev_dbg(dev, "result = %d\n", result); -	/* send 5 cmd */ +	/* send 5th cmd */  	/*  	 * 16.0  CTL    a1 21 00 00  00 00 07 00   CLASS               33.1.0  	 * 16.0  DI     80 25 00 00  00 00 08 @@ -107,7 +106,7 @@ static int zte_ev_usb_serial_open(struct tty_struct *tty,  				 USB_CTRL_GET_TIMEOUT);  	debug_data(dev, __func__, len, buf, result); -	/* send 6 cmd */ +	/* send 6th cmd */  	/*  	 * 16.0  CTL    21 20 00 00  00 00 07 00    CLASS               34.1.0  	 * 16.0  DO     80 25 00 00  00 00 08 @@ -195,7 +194,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)  				 USB_CTRL_GET_TIMEOUT);  	debug_data(dev, __func__, len, buf, result); -	/* send 4 cmd */ +	/* send 4th cmd */  	/*  	 * 16.0 CTL    21 20 00 00  00 00 07 00      CLASS            30.1.0  	 * 16.0  DO    00 c2 01 00  00 00 08         .%.....          30.2.0 @@ -214,7 +213,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)  				 USB_CTRL_GET_TIMEOUT);  	debug_data(dev, __func__, len, buf, result); -	/* send 5 cmd */ +	/* send 5th cmd */  	/*  	 * 16.0 CTL    21 22 03 00  00 00 00 00  	 */ @@ -225,7 +224,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)  				 USB_CTRL_GET_TIMEOUT);  	dev_dbg(dev, "result = %d\n", result); -	/* send 6 cmd */ +	/* send 6th cmd */  	/*  	 * 16.0  CTL    a1 21 00 00  00 00 07 00        CLASS          33.1.0  	 * 16.0  DI     00 c2 01 00  00 00 08 @@ -237,7 +236,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)  				 USB_CTRL_GET_TIMEOUT);  	debug_data(dev, __func__, len, buf, result); -	/* send 7 cmd */ +	/* send 7th cmd */  	/*  	 * 16.0  CTL    21 20 00 00  00 00 07 00  CLASS               354.1.0  	 * 16.0  DO     00 c2 01 00  00 00 08     .......             354.2.0 @@ -256,7 +255,7 @@ static void zte_ev_usb_serial_close(struct usb_serial_port *port)  				 USB_CTRL_GET_TIMEOUT);  	debug_data(dev, __func__, len, buf, result); -	/* send 8 cmd */ +	/* send 8th cmd */  	/*  	 * 16.0 CTL    21 22 03 00  00 00 00 00  	 */ @@ -281,8 +280,7 @@ static const struct usb_device_id id_table[] = {  	{ USB_DEVICE(0x19d2, 0xfffd) },  	{ USB_DEVICE(0x19d2, 0xfffc) },  	{ USB_DEVICE(0x19d2, 0xfffb) }, -	/* AC2726, AC8710_V3 */ -	{ USB_DEVICE_AND_INTERFACE_INFO(0x19d2, 0xfff1, 0xff, 0xff, 0xff) }, +	/* AC8710_V3 */  	{ USB_DEVICE(0x19d2, 0xfff6) },  	{ USB_DEVICE(0x19d2, 0xfff7) },  	{ USB_DEVICE(0x19d2, 0xfff8) }, diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index 8470e1b114f..13b5bfbaf95 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -18,7 +18,9 @@ config USB_STORAGE  	  This option depends on 'SCSI' support being enabled, but you  	  probably also need 'SCSI device support: SCSI disk support' -	  (BLK_DEV_SD) for most USB storage devices. +	  (BLK_DEV_SD) for most USB storage devices.  Some devices also +	  will require 'Probe all LUNs on each SCSI device' +	  (SCSI_MULTI_LUN).  	  To compile this driver as a module, choose M here: the  	  module will be called usb-storage. @@ -202,7 +204,7 @@ config USB_STORAGE_ENE_UB6250  config USB_UAS  	tristate "USB Attached SCSI" -	depends on SCSI && BROKEN +	depends on SCSI && USB_STORAGE  	help  	  The USB Attached SCSI protocol is supported by some USB  	  storage devices.  It permits higher performance by supporting diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index 1bfc9a6cab5..ef6efb55dc3 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -1928,11 +1928,10 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag)  		usb_stor_dbg(us, "load firmware %s failed\n", fw_name);  		goto nofw;  	} -	buf = kmalloc(sd_fw->size, GFP_KERNEL); +	buf = kmemdup(sd_fw->data, sd_fw->size, GFP_KERNEL);  	if (buf == NULL)  		goto nofw; -	memcpy(buf, sd_fw->data, sd_fw->size);  	memset(bcb, 0, sizeof(struct bulk_cb_wrap));  	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);  	bcb->DataTransferLength = sd_fw->size; diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index 26964895c88..74e2aa23b04 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -30,7 +30,6 @@  #include <linux/kernel.h>  #include <linux/input.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/usb/input.h> diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c index 5dfb4c36a1b..12e3c2fac64 100644 --- a/drivers/usb/storage/protocol.c +++ b/drivers/usb/storage/protocol.c @@ -135,69 +135,42 @@ unsigned int usb_stor_access_xfer_buf(unsigned char *buffer,  	unsigned int buflen, struct scsi_cmnd *srb, struct scatterlist **sgptr,  	unsigned int *offset, enum xfer_buf_dir dir)  { -	unsigned int cnt; +	unsigned int cnt = 0;  	struct scatterlist *sg = *sgptr; +	struct sg_mapping_iter miter; +	unsigned int nents = scsi_sg_count(srb); -	/* We have to go through the list one entry -	 * at a time.  Each s-g entry contains some number of pages, and -	 * each page has to be kmap()'ed separately.  If the page is already -	 * in kernel-addressable memory then kmap() will return its address. -	 * If the page is not directly accessible -- such as a user buffer -	 * located in high memory -- then kmap() will map it to a temporary -	 * position in the kernel's virtual address space. -	 */ - -	if (!sg) +	if (sg) +		nents = sg_nents(sg); +	else  		sg = scsi_sglist(srb); -	/* This loop handles a single s-g list entry, which may -	 * include multiple pages.  Find the initial page structure -	 * and the starting offset within the page, and update -	 * the *offset and **sgptr values for the next loop. -	 */ -	cnt = 0; -	while (cnt < buflen && sg) { -		struct page *page = sg_page(sg) + -				((sg->offset + *offset) >> PAGE_SHIFT); -		unsigned int poff = (sg->offset + *offset) & (PAGE_SIZE-1); -		unsigned int sglen = sg->length - *offset; - -		if (sglen > buflen - cnt) { - -			/* Transfer ends within this s-g entry */ -			sglen = buflen - cnt; -			*offset += sglen; -		} else { +	sg_miter_start(&miter, sg, nents, dir == FROM_XFER_BUF ? +		SG_MITER_FROM_SG: SG_MITER_TO_SG); -			/* Transfer continues to next s-g entry */ -			*offset = 0; -			sg = sg_next(sg); -		} +	if (!sg_miter_skip(&miter, *offset)) +		return cnt; + +	while (sg_miter_next(&miter) && cnt < buflen) { +		unsigned int len = min_t(unsigned int, miter.length, +				buflen - cnt); + +		if (dir == FROM_XFER_BUF) +			memcpy(buffer + cnt, miter.addr, len); +		else +			memcpy(miter.addr, buffer + cnt, len); -		/* Transfer the data for all the pages in this -			* s-g entry.  For each page: call kmap(), do the -			* transfer, and call kunmap() immediately after. */ -		while (sglen > 0) { -			unsigned int plen = min(sglen, (unsigned int) -					PAGE_SIZE - poff); -			unsigned char *ptr = kmap(page); - -			if (dir == TO_XFER_BUF) -				memcpy(ptr + poff, buffer + cnt, plen); -			else -				memcpy(buffer + cnt, ptr + poff, plen); -			kunmap(page); - -			/* Start at the beginning of the next page */ -			poff = 0; -			++page; -			cnt += plen; -			sglen -= plen; +		if (*offset + len < miter.piter.sg->length) { +			*offset += len; +			*sgptr = miter.piter.sg; +		} else { +			*offset = 0; +			*sgptr = sg_next(miter.piter.sg);  		} +		cnt += len;  	} -	*sgptr = sg; +	sg_miter_stop(&miter); -	/* Return the amount actually transferred */  	return cnt;  }  EXPORT_SYMBOL_GPL(usb_stor_access_xfer_buf); diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 94d75edef77..866b5df36ed 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -78,6 +78,8 @@ static const char* host_info(struct Scsi_Host *host)  static int slave_alloc (struct scsi_device *sdev)  { +	struct us_data *us = host_to_us(sdev->host); +  	/*  	 * Set the INQUIRY transfer length to 36.  We don't use any of  	 * the extra data and many devices choke if asked for more or @@ -102,6 +104,10 @@ static int slave_alloc (struct scsi_device *sdev)  	 */  	blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); +	/* Tell the SCSI layer if we know there is more than one LUN */ +	if (us->protocol == USB_PR_BULK && us->max_lun > 0) +		sdev->sdev_bflags |= BLIST_FORCELUN; +  	return 0;  } @@ -211,8 +217,11 @@ static int slave_configure(struct scsi_device *sdev)  		/*  		 * Many devices do not respond properly to READ_CAPACITY_16.  		 * Tell the SCSI layer to try READ_CAPACITY_10 first. +		 * However some USB 3.0 drive enclosures return capacity +		 * modulo 2TB. Those must use READ_CAPACITY_16  		 */ -		sdev->try_rc_10_first = 1; +		if (!(us->fflags & US_FL_NEEDS_CAP16)) +			sdev->try_rc_10_first = 1;  		/* assume SPC3 or latter devices support sense size > 18 */  		if (sdev->scsi_level > SCSI_SPC_2) @@ -247,6 +256,10 @@ static int slave_configure(struct scsi_device *sdev)  		if (us->fflags & US_FL_WRITE_CACHE)  			sdev->wce_default_on = 1; +		/* A few buggy USB-ATA bridges don't understand FUA */ +		if (us->fflags & US_FL_BROKEN_FUA) +			sdev->broken_fua = 1; +  	} else {  		/* Non-disk-type devices don't need to blacklist any pages diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c index 4ef2a80728f..008d805c3d2 100644 --- a/drivers/usb/storage/shuttle_usbat.c +++ b/drivers/usb/storage/shuttle_usbat.c @@ -1851,7 +1851,7 @@ static int usbat_probe(struct usb_interface *intf,  	us->transport_name = "Shuttle USBAT";  	us->transport = usbat_flash_transport;  	us->transport_reset = usb_stor_CB_reset; -	us->max_lun = 1; +	us->max_lun = 0;  	result = usb_stor_probe2(us);  	return result; diff --git a/drivers/usb/storage/uas-detect.h b/drivers/usb/storage/uas-detect.h new file mode 100644 index 00000000000..bb05b984d5f --- /dev/null +++ b/drivers/usb/storage/uas-detect.h @@ -0,0 +1,96 @@ +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include "usb.h" + +static int uas_is_interface(struct usb_host_interface *intf) +{ +	return (intf->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE && +		intf->desc.bInterfaceSubClass == USB_SC_SCSI && +		intf->desc.bInterfaceProtocol == USB_PR_UAS); +} + +static int uas_isnt_supported(struct usb_device *udev) +{ +	struct usb_hcd *hcd = bus_to_hcd(udev->bus); + +	dev_warn(&udev->dev, "The driver for the USB controller %s does not " +			"support scatter-gather which is\n", +			hcd->driver->description); +	dev_warn(&udev->dev, "required by the UAS driver. Please try an" +			"alternative USB controller if you wish to use UAS.\n"); +	return -ENODEV; +} + +static int uas_find_uas_alt_setting(struct usb_interface *intf) +{ +	int i; +	struct usb_device *udev = interface_to_usbdev(intf); +	int sg_supported = udev->bus->sg_tablesize != 0; + +	for (i = 0; i < intf->num_altsetting; i++) { +		struct usb_host_interface *alt = &intf->altsetting[i]; + +		if (uas_is_interface(alt)) { +			if (!sg_supported) +				return uas_isnt_supported(udev); +			return alt->desc.bAlternateSetting; +		} +	} + +	return -ENODEV; +} + +static int uas_find_endpoints(struct usb_host_interface *alt, +			      struct usb_host_endpoint *eps[]) +{ +	struct usb_host_endpoint *endpoint = alt->endpoint; +	unsigned i, n_endpoints = alt->desc.bNumEndpoints; + +	for (i = 0; i < n_endpoints; i++) { +		unsigned char *extra = endpoint[i].extra; +		int len = endpoint[i].extralen; +		while (len >= 3) { +			if (extra[1] == USB_DT_PIPE_USAGE) { +				unsigned pipe_id = extra[2]; +				if (pipe_id > 0 && pipe_id < 5) +					eps[pipe_id - 1] = &endpoint[i]; +				break; +			} +			len -= extra[0]; +			extra += extra[0]; +		} +	} + +	if (!eps[0] || !eps[1] || !eps[2] || !eps[3]) +		return -ENODEV; + +	return 0; +} + +static int uas_use_uas_driver(struct usb_interface *intf, +			      const struct usb_device_id *id) +{ +	struct usb_host_endpoint *eps[4] = { }; +	struct usb_device *udev = interface_to_usbdev(intf); +	struct usb_hcd *hcd = bus_to_hcd(udev->bus); +	unsigned long flags = id->driver_info; +	int r, alt; + +	usb_stor_adjust_quirks(udev, &flags); + +	if (flags & US_FL_IGNORE_UAS) +		return 0; + +	if (udev->speed >= USB_SPEED_SUPER && !hcd->can_do_streams) +		return 0; + +	alt = uas_find_uas_alt_setting(intf); +	if (alt < 0) +		return 0; + +	r = uas_find_endpoints(&intf->altsetting[alt], eps); +	if (r < 0) +		return 0; + +	return 1; +} diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index d966b59f7d7..511b2295316 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -2,6 +2,7 @@   * USB Attached SCSI   * Note that this is not the same as the USB Mass Storage driver   * + * Copyright Hans de Goede <hdegoede@redhat.com> for Red Hat, Inc. 2013   * Copyright Matthew Wilcox for Intel Corp, 2010   * Copyright Sarah Sharp for Intel Corp, 2010   * @@ -13,17 +14,21 @@  #include <linux/types.h>  #include <linux/module.h>  #include <linux/usb.h> +#include <linux/usb_usual.h>  #include <linux/usb/hcd.h>  #include <linux/usb/storage.h>  #include <linux/usb/uas.h>  #include <scsi/scsi.h> +#include <scsi/scsi_eh.h>  #include <scsi/scsi_dbg.h>  #include <scsi/scsi_cmnd.h>  #include <scsi/scsi_device.h>  #include <scsi/scsi_host.h>  #include <scsi/scsi_tcq.h> +#include "uas-detect.h" +  /*   * The r00-r01c specs define this version of the SENSE IU data structure.   * It's still in use by several different firmware releases. @@ -45,12 +50,17 @@ struct uas_dev_info {  	struct usb_anchor sense_urbs;  	struct usb_anchor data_urbs;  	int qdepth, resetting; -	struct response_ui response; +	struct response_iu response;  	unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;  	unsigned use_streams:1;  	unsigned uas_sense_old:1; +	unsigned running_task:1; +	unsigned shutdown:1;  	struct scsi_cmnd *cmnd;  	spinlock_t lock; +	struct work_struct work; +	struct list_head inflight_list; +	struct list_head dead_list;  };  enum { @@ -85,103 +95,117 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,  				struct uas_dev_info *devinfo, gfp_t gfp);  static void uas_do_work(struct work_struct *work);  static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller); +static void uas_free_streams(struct uas_dev_info *devinfo); +static void uas_log_cmd_state(struct scsi_cmnd *cmnd, const char *caller); -static DECLARE_WORK(uas_work, uas_do_work); -static DEFINE_SPINLOCK(uas_work_lock); -static LIST_HEAD(uas_work_list); - +/* Must be called with devinfo->lock held, will temporary unlock the lock */  static void uas_unlink_data_urbs(struct uas_dev_info *devinfo, -				 struct uas_cmd_info *cmdinfo) +				 struct uas_cmd_info *cmdinfo, +				 unsigned long *lock_flags)  { -	unsigned long flags; -  	/*  	 * The UNLINK_DATA_URBS flag makes sure uas_try_complete  	 * (called by urb completion) doesn't release cmdinfo  	 * underneath us.  	 */ -	spin_lock_irqsave(&devinfo->lock, flags);  	cmdinfo->state |= UNLINK_DATA_URBS; -	spin_unlock_irqrestore(&devinfo->lock, flags); +	spin_unlock_irqrestore(&devinfo->lock, *lock_flags);  	if (cmdinfo->data_in_urb)  		usb_unlink_urb(cmdinfo->data_in_urb);  	if (cmdinfo->data_out_urb)  		usb_unlink_urb(cmdinfo->data_out_urb); -	spin_lock_irqsave(&devinfo->lock, flags); +	spin_lock_irqsave(&devinfo->lock, *lock_flags);  	cmdinfo->state &= ~UNLINK_DATA_URBS; -	spin_unlock_irqrestore(&devinfo->lock, flags);  }  static void uas_do_work(struct work_struct *work)  { +	struct uas_dev_info *devinfo = +		container_of(work, struct uas_dev_info, work);  	struct uas_cmd_info *cmdinfo; -	struct uas_cmd_info *temp; -	struct list_head list;  	unsigned long flags;  	int err; -	spin_lock_irq(&uas_work_lock); -	list_replace_init(&uas_work_list, &list); -	spin_unlock_irq(&uas_work_lock); - -	list_for_each_entry_safe(cmdinfo, temp, &list, list) { +	spin_lock_irqsave(&devinfo->lock, flags); +	list_for_each_entry(cmdinfo, &devinfo->inflight_list, list) {  		struct scsi_pointer *scp = (void *)cmdinfo; -		struct scsi_cmnd *cmnd = container_of(scp, -							struct scsi_cmnd, SCp); -		struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata; -		spin_lock_irqsave(&devinfo->lock, flags); +		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, +						      SCp); + +		if (!(cmdinfo->state & IS_IN_WORK_LIST)) +			continue; +  		err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);  		if (!err)  			cmdinfo->state &= ~IS_IN_WORK_LIST; -		spin_unlock_irqrestore(&devinfo->lock, flags); -		if (err) { -			list_del(&cmdinfo->list); -			spin_lock_irq(&uas_work_lock); -			list_add_tail(&cmdinfo->list, &uas_work_list); -			spin_unlock_irq(&uas_work_lock); -			schedule_work(&uas_work); -		} +		else +			schedule_work(&devinfo->work);  	} +	spin_unlock_irqrestore(&devinfo->lock, flags);  } -static void uas_abort_work(struct uas_dev_info *devinfo) +static void uas_mark_cmd_dead(struct uas_dev_info *devinfo, +			      struct uas_cmd_info *cmdinfo, +			      int result, const char *caller) +{ +	struct scsi_pointer *scp = (void *)cmdinfo; +	struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp); + +	uas_log_cmd_state(cmnd, caller); +	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock)); +	WARN_ON_ONCE(cmdinfo->state & COMMAND_ABORTED); +	cmdinfo->state |= COMMAND_ABORTED; +	cmdinfo->state &= ~IS_IN_WORK_LIST; +	cmnd->result = result << 16; +	list_move_tail(&cmdinfo->list, &devinfo->dead_list); +} + +static void uas_abort_inflight(struct uas_dev_info *devinfo, int result, +			       const char *caller)  {  	struct uas_cmd_info *cmdinfo;  	struct uas_cmd_info *temp; -	struct list_head list;  	unsigned long flags; -	spin_lock_irq(&uas_work_lock); -	list_replace_init(&uas_work_list, &list); -	spin_unlock_irq(&uas_work_lock); +	spin_lock_irqsave(&devinfo->lock, flags); +	list_for_each_entry_safe(cmdinfo, temp, &devinfo->inflight_list, list) +		uas_mark_cmd_dead(devinfo, cmdinfo, result, caller); +	spin_unlock_irqrestore(&devinfo->lock, flags); +} + +static void uas_add_work(struct uas_cmd_info *cmdinfo) +{ +	struct scsi_pointer *scp = (void *)cmdinfo; +	struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, SCp); +	struct uas_dev_info *devinfo = cmnd->device->hostdata; + +	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock)); +	cmdinfo->state |= IS_IN_WORK_LIST; +	schedule_work(&devinfo->work); +} + +static void uas_zap_dead(struct uas_dev_info *devinfo) +{ +	struct uas_cmd_info *cmdinfo; +	struct uas_cmd_info *temp; +	unsigned long flags;  	spin_lock_irqsave(&devinfo->lock, flags); -	list_for_each_entry_safe(cmdinfo, temp, &list, list) { +	list_for_each_entry_safe(cmdinfo, temp, &devinfo->dead_list, list) {  		struct scsi_pointer *scp = (void *)cmdinfo; -		struct scsi_cmnd *cmnd = container_of(scp, -							struct scsi_cmnd, SCp); -		struct uas_dev_info *di = (void *)cmnd->device->hostdata; - -		if (di == devinfo) { -			cmdinfo->state |= COMMAND_ABORTED; -			cmdinfo->state &= ~IS_IN_WORK_LIST; -			if (devinfo->resetting) { -				/* uas_stat_cmplt() will not do that -				 * when a device reset is in -				 * progress */ -				cmdinfo->state &= ~COMMAND_INFLIGHT; -			} -			uas_try_complete(cmnd, __func__); -		} else { -			/* not our uas device, relink into list */ -			list_del(&cmdinfo->list); -			spin_lock_irq(&uas_work_lock); -			list_add_tail(&cmdinfo->list, &uas_work_list); -			spin_unlock_irq(&uas_work_lock); -		} +		struct scsi_cmnd *cmnd = container_of(scp, struct scsi_cmnd, +						      SCp); +		uas_log_cmd_state(cmnd, __func__); +		WARN_ON_ONCE(!(cmdinfo->state & COMMAND_ABORTED)); +		/* all urbs are killed, clear inflight bits */ +		cmdinfo->state &= ~(COMMAND_INFLIGHT | +				    DATA_IN_URB_INFLIGHT | +				    DATA_OUT_URB_INFLIGHT); +		uas_try_complete(cmnd, __func__);  	} +	devinfo->running_task = 0;  	spin_unlock_irqrestore(&devinfo->lock, flags);  } @@ -259,20 +283,19 @@ static int uas_try_complete(struct scsi_cmnd *cmnd, const char *caller)  	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;  	struct uas_dev_info *devinfo = (void *)cmnd->device->hostdata; -	WARN_ON(!spin_is_locked(&devinfo->lock)); +	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));  	if (cmdinfo->state & (COMMAND_INFLIGHT |  			      DATA_IN_URB_INFLIGHT |  			      DATA_OUT_URB_INFLIGHT |  			      UNLINK_DATA_URBS))  		return -EBUSY; -	BUG_ON(cmdinfo->state & COMMAND_COMPLETED); +	WARN_ON_ONCE(cmdinfo->state & COMMAND_COMPLETED);  	cmdinfo->state |= COMMAND_COMPLETED;  	usb_free_urb(cmdinfo->data_in_urb);  	usb_free_urb(cmdinfo->data_out_urb); -	if (cmdinfo->state & COMMAND_ABORTED) { +	if (cmdinfo->state & COMMAND_ABORTED)  		scmd_printk(KERN_INFO, cmnd, "abort completed\n"); -		cmnd->result = DID_ABORT << 16; -	} +	list_del(&cmdinfo->list);  	cmnd->scsi_done(cmnd);  	return 0;  } @@ -286,11 +309,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,  	cmdinfo->state |= direction | SUBMIT_STATUS_URB;  	err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);  	if (err) { -		spin_lock(&uas_work_lock); -		list_add_tail(&cmdinfo->list, &uas_work_list); -		cmdinfo->state |= IS_IN_WORK_LIST; -		spin_unlock(&uas_work_lock); -		schedule_work(&uas_work); +		uas_add_work(cmdinfo);  	}  } @@ -298,14 +317,20 @@ static void uas_stat_cmplt(struct urb *urb)  {  	struct iu *iu = urb->transfer_buffer;  	struct Scsi_Host *shost = urb->context; -	struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; +	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;  	struct scsi_cmnd *cmnd;  	struct uas_cmd_info *cmdinfo;  	unsigned long flags;  	u16 tag;  	if (urb->status) { -		dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status); +		if (urb->status == -ENOENT) { +			dev_err(&urb->dev->dev, "stat urb: killed, stream %d\n", +				urb->stream_id); +		} else { +			dev_err(&urb->dev->dev, "stat urb: status %d\n", +				urb->status); +		}  		usb_free_urb(urb);  		return;  	} @@ -324,6 +349,9 @@ static void uas_stat_cmplt(struct urb *urb)  	if (!cmnd) {  		if (iu->iu_id == IU_ID_RESPONSE) { +			if (!devinfo->running_task) +				dev_warn(&urb->dev->dev, +				    "stat urb: recv unexpected response iu\n");  			/* store results for uas_eh_task_mgmt() */  			memcpy(&devinfo->response, iu, sizeof(devinfo->response));  		} @@ -346,17 +374,25 @@ static void uas_stat_cmplt(struct urb *urb)  			uas_sense(urb, cmnd);  		if (cmnd->result != 0) {  			/* cancel data transfers on error */ -			spin_unlock_irqrestore(&devinfo->lock, flags); -			uas_unlink_data_urbs(devinfo, cmdinfo); -			spin_lock_irqsave(&devinfo->lock, flags); +			uas_unlink_data_urbs(devinfo, cmdinfo, &flags);  		}  		cmdinfo->state &= ~COMMAND_INFLIGHT;  		uas_try_complete(cmnd, __func__);  		break;  	case IU_ID_READ_READY: +		if (!cmdinfo->data_in_urb || +				(cmdinfo->state & DATA_IN_URB_INFLIGHT)) { +			scmd_printk(KERN_ERR, cmnd, "unexpected read rdy\n"); +			break; +		}  		uas_xfer_data(urb, cmnd, SUBMIT_DATA_IN_URB);  		break;  	case IU_ID_WRITE_READY: +		if (!cmdinfo->data_out_urb || +				(cmdinfo->state & DATA_OUT_URB_INFLIGHT)) { +			scmd_printk(KERN_ERR, cmnd, "unexpected write rdy\n"); +			break; +		}  		uas_xfer_data(urb, cmnd, SUBMIT_DATA_OUT_URB);  		break;  	default: @@ -383,8 +419,15 @@ static void uas_data_cmplt(struct urb *urb)  		sdb = scsi_out(cmnd);  		cmdinfo->state &= ~DATA_OUT_URB_INFLIGHT;  	} -	BUG_ON(sdb == NULL); -	if (urb->status) { +	if (sdb == NULL) { +		WARN_ON_ONCE(1); +	} else if (urb->status) { +		if (urb->status != -ECONNRESET) { +			uas_log_cmd_state(cmnd, __func__); +			scmd_printk(KERN_ERR, cmnd, +				"data cmplt err %d stream %d\n", +				urb->status, urb->stream_id); +		}  		/* error: no data transfered */  		sdb->resid = sdb->length;  	} else { @@ -394,6 +437,17 @@ static void uas_data_cmplt(struct urb *urb)  	spin_unlock_irqrestore(&devinfo->lock, flags);  } +static void uas_cmd_cmplt(struct urb *urb) +{ +	struct scsi_cmnd *cmnd = urb->context; + +	if (urb->status) { +		uas_log_cmd_state(cmnd, __func__); +		scmd_printk(KERN_ERR, cmnd, "cmd cmplt err %d\n", urb->status); +	} +	usb_free_urb(urb); +} +  static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,  				      unsigned int pipe, u16 stream_id,  				      struct scsi_cmnd *cmnd, @@ -408,8 +462,7 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,  		goto out;  	usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,  			  uas_data_cmplt, cmnd); -	if (devinfo->use_streams) -		urb->stream_id = stream_id; +	urb->stream_id = stream_id;  	urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;  	urb->sg = sdb->table.sgl;   out: @@ -442,7 +495,7 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,  }  static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp, -					struct scsi_cmnd *cmnd, u16 stream_id) +					struct scsi_cmnd *cmnd)  {  	struct usb_device *udev = devinfo->udev;  	struct scsi_device *sdev = cmnd->device; @@ -472,7 +525,7 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,  	memcpy(iu->cdb, cmnd->cmnd, cmnd->cmd_len);  	usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu) + len, -							usb_free_urb, NULL); +							uas_cmd_cmplt, cmnd);  	urb->transfer_flags |= URB_FREE_BUFFER;   out:  	return urb; @@ -512,13 +565,17 @@ static int uas_submit_task_urb(struct scsi_cmnd *cmnd, gfp_t gfp,  	}  	usb_fill_bulk_urb(urb, udev, devinfo->cmd_pipe, iu, sizeof(*iu), -			  usb_free_urb, NULL); +			  uas_cmd_cmplt, cmnd);  	urb->transfer_flags |= URB_FREE_BUFFER; +	usb_anchor_urb(urb, &devinfo->cmd_urbs);  	err = usb_submit_urb(urb, gfp); -	if (err) +	if (err) { +		usb_unanchor_urb(urb); +		uas_log_cmd_state(cmnd, __func__); +		scmd_printk(KERN_ERR, cmnd, "task submission err %d\n", err);  		goto err; -	usb_anchor_urb(urb, &devinfo->cmd_urbs); +	}  	return 0; @@ -533,38 +590,43 @@ err:   * daft to me.   */ -static int uas_submit_sense_urb(struct Scsi_Host *shost, -				gfp_t gfp, unsigned int stream) +static struct urb *uas_submit_sense_urb(struct scsi_cmnd *cmnd, +					gfp_t gfp, unsigned int stream)  { -	struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; +	struct Scsi_Host *shost = cmnd->device->host; +	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;  	struct urb *urb; +	int err;  	urb = uas_alloc_sense_urb(devinfo, gfp, shost, stream);  	if (!urb) -		return SCSI_MLQUEUE_DEVICE_BUSY; -	if (usb_submit_urb(urb, gfp)) { +		return NULL; +	usb_anchor_urb(urb, &devinfo->sense_urbs); +	err = usb_submit_urb(urb, gfp); +	if (err) { +		usb_unanchor_urb(urb); +		uas_log_cmd_state(cmnd, __func__);  		shost_printk(KERN_INFO, shost, -			     "sense urb submission failure\n"); +			     "sense urb submission error %d stream %d\n", +			     err, stream);  		usb_free_urb(urb); -		return SCSI_MLQUEUE_DEVICE_BUSY; +		return NULL;  	} -	usb_anchor_urb(urb, &devinfo->sense_urbs); -	return 0; +	return urb;  }  static int uas_submit_urbs(struct scsi_cmnd *cmnd,  			   struct uas_dev_info *devinfo, gfp_t gfp)  {  	struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp; +	struct urb *urb;  	int err; -	WARN_ON(!spin_is_locked(&devinfo->lock)); +	WARN_ON_ONCE(!spin_is_locked(&devinfo->lock));  	if (cmdinfo->state & SUBMIT_STATUS_URB) { -		err = uas_submit_sense_urb(cmnd->device->host, gfp, -					   cmdinfo->stream); -		if (err) { -			return err; -		} +		urb = uas_submit_sense_urb(cmnd, gfp, cmdinfo->stream); +		if (!urb) +			return SCSI_MLQUEUE_DEVICE_BUSY;  		cmdinfo->state &= ~SUBMIT_STATUS_URB;  	} @@ -578,14 +640,18 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,  	}  	if (cmdinfo->state & SUBMIT_DATA_IN_URB) { -		if (usb_submit_urb(cmdinfo->data_in_urb, gfp)) { +		usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs); +		err = usb_submit_urb(cmdinfo->data_in_urb, gfp); +		if (err) { +			usb_unanchor_urb(cmdinfo->data_in_urb); +			uas_log_cmd_state(cmnd, __func__);  			scmd_printk(KERN_INFO, cmnd, -					"data in urb submission failure\n"); +				"data in urb submission error %d stream %d\n", +				err, cmdinfo->data_in_urb->stream_id);  			return SCSI_MLQUEUE_DEVICE_BUSY;  		}  		cmdinfo->state &= ~SUBMIT_DATA_IN_URB;  		cmdinfo->state |= DATA_IN_URB_INFLIGHT; -		usb_anchor_urb(cmdinfo->data_in_urb, &devinfo->data_urbs);  	}  	if (cmdinfo->state & ALLOC_DATA_OUT_URB) { @@ -598,33 +664,37 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,  	}  	if (cmdinfo->state & SUBMIT_DATA_OUT_URB) { -		if (usb_submit_urb(cmdinfo->data_out_urb, gfp)) { +		usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs); +		err = usb_submit_urb(cmdinfo->data_out_urb, gfp); +		if (err) { +			usb_unanchor_urb(cmdinfo->data_out_urb); +			uas_log_cmd_state(cmnd, __func__);  			scmd_printk(KERN_INFO, cmnd, -					"data out urb submission failure\n"); +				"data out urb submission error %d stream %d\n", +				err, cmdinfo->data_out_urb->stream_id);  			return SCSI_MLQUEUE_DEVICE_BUSY;  		}  		cmdinfo->state &= ~SUBMIT_DATA_OUT_URB;  		cmdinfo->state |= DATA_OUT_URB_INFLIGHT; -		usb_anchor_urb(cmdinfo->data_out_urb, &devinfo->data_urbs);  	}  	if (cmdinfo->state & ALLOC_CMD_URB) { -		cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd, -						     cmdinfo->stream); +		cmdinfo->cmd_urb = uas_alloc_cmd_urb(devinfo, gfp, cmnd);  		if (!cmdinfo->cmd_urb)  			return SCSI_MLQUEUE_DEVICE_BUSY;  		cmdinfo->state &= ~ALLOC_CMD_URB;  	}  	if (cmdinfo->state & SUBMIT_CMD_URB) { -		usb_get_urb(cmdinfo->cmd_urb); -		if (usb_submit_urb(cmdinfo->cmd_urb, gfp)) { +		usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs); +		err = usb_submit_urb(cmdinfo->cmd_urb, gfp); +		if (err) { +			usb_unanchor_urb(cmdinfo->cmd_urb); +			uas_log_cmd_state(cmnd, __func__);  			scmd_printk(KERN_INFO, cmnd, -					"cmd urb submission failure\n"); +				    "cmd urb submission error %d\n", err);  			return SCSI_MLQUEUE_DEVICE_BUSY;  		} -		usb_anchor_urb(cmdinfo->cmd_urb, &devinfo->cmd_urbs); -		usb_put_urb(cmdinfo->cmd_urb);  		cmdinfo->cmd_urb = NULL;  		cmdinfo->state &= ~SUBMIT_CMD_URB;  		cmdinfo->state |= COMMAND_INFLIGHT; @@ -644,18 +714,22 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,  	BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer)); +	spin_lock_irqsave(&devinfo->lock, flags); +  	if (devinfo->resetting) {  		cmnd->result = DID_ERROR << 16;  		cmnd->scsi_done(cmnd); +		spin_unlock_irqrestore(&devinfo->lock, flags);  		return 0;  	} -	spin_lock_irqsave(&devinfo->lock, flags);  	if (devinfo->cmnd) {  		spin_unlock_irqrestore(&devinfo->lock, flags);  		return SCSI_MLQUEUE_DEVICE_BUSY;  	} +	memset(cmdinfo, 0, sizeof(*cmdinfo)); +  	if (blk_rq_tagged(cmnd->request)) {  		cmdinfo->stream = cmnd->request->tag + 2;  	} else { @@ -692,13 +766,10 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,  			spin_unlock_irqrestore(&devinfo->lock, flags);  			return SCSI_MLQUEUE_DEVICE_BUSY;  		} -		spin_lock(&uas_work_lock); -		list_add_tail(&cmdinfo->list, &uas_work_list); -		cmdinfo->state |= IS_IN_WORK_LIST; -		spin_unlock(&uas_work_lock); -		schedule_work(&uas_work); +		uas_add_work(cmdinfo);  	} +	list_add_tail(&cmdinfo->list, &devinfo->inflight_list);  	spin_unlock_irqrestore(&devinfo->lock, flags);  	return 0;  } @@ -709,16 +780,36 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,  			    const char *fname, u8 function)  {  	struct Scsi_Host *shost = cmnd->device->host; -	struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; -	u16 tag = devinfo->qdepth - 1; +	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; +	u16 tag = devinfo->qdepth;  	unsigned long flags; +	struct urb *sense_urb; +	int result = SUCCESS;  	spin_lock_irqsave(&devinfo->lock, flags); + +	if (devinfo->resetting) { +		spin_unlock_irqrestore(&devinfo->lock, flags); +		return FAILED; +	} + +	if (devinfo->running_task) { +		shost_printk(KERN_INFO, shost, +			     "%s: %s: error already running a task\n", +			     __func__, fname); +		spin_unlock_irqrestore(&devinfo->lock, flags); +		return FAILED; +	} + +	devinfo->running_task = 1;  	memset(&devinfo->response, 0, sizeof(devinfo->response)); -	if (uas_submit_sense_urb(shost, GFP_ATOMIC, tag)) { +	sense_urb = uas_submit_sense_urb(cmnd, GFP_ATOMIC, +					 devinfo->use_streams ? tag : 0); +	if (!sense_urb) {  		shost_printk(KERN_INFO, shost,  			     "%s: %s: submit sense urb failed\n",  			     __func__, fname); +		devinfo->running_task = 0;  		spin_unlock_irqrestore(&devinfo->lock, flags);  		return FAILED;  	} @@ -726,29 +817,41 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd,  		shost_printk(KERN_INFO, shost,  			     "%s: %s: submit task mgmt urb failed\n",  			     __func__, fname); +		devinfo->running_task = 0;  		spin_unlock_irqrestore(&devinfo->lock, flags); +		usb_kill_urb(sense_urb);  		return FAILED;  	}  	spin_unlock_irqrestore(&devinfo->lock, flags);  	if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 3000) == 0) { +		/* +		 * Note we deliberately do not clear running_task here. If we +		 * allow new tasks to be submitted, there is no way to figure +		 * out if a received response_iu is for the failed task or for +		 * the new one. A bus-reset will eventually clear running_task. +		 */  		shost_printk(KERN_INFO, shost,  			     "%s: %s timed out\n", __func__, fname);  		return FAILED;  	} + +	spin_lock_irqsave(&devinfo->lock, flags); +	devinfo->running_task = 0;  	if (be16_to_cpu(devinfo->response.tag) != tag) {  		shost_printk(KERN_INFO, shost,  			     "%s: %s failed (wrong tag %d/%d)\n", __func__,  			     fname, be16_to_cpu(devinfo->response.tag), tag); -		return FAILED; -	} -	if (devinfo->response.response_code != RC_TMF_COMPLETE) { +		result = FAILED; +	} else if (devinfo->response.response_code != RC_TMF_COMPLETE) {  		shost_printk(KERN_INFO, shost,  			     "%s: %s failed (rc 0x%x)\n", __func__,  			     fname, devinfo->response.response_code); -		return FAILED; +		result = FAILED;  	} -	return SUCCESS; +	spin_unlock_irqrestore(&devinfo->lock, flags); + +	return result;  }  static int uas_eh_abort_handler(struct scsi_cmnd *cmnd) @@ -758,22 +861,19 @@ static int uas_eh_abort_handler(struct scsi_cmnd *cmnd)  	unsigned long flags;  	int ret; -	uas_log_cmd_state(cmnd, __func__);  	spin_lock_irqsave(&devinfo->lock, flags); -	cmdinfo->state |= COMMAND_ABORTED; -	if (cmdinfo->state & IS_IN_WORK_LIST) { -		spin_lock(&uas_work_lock); -		list_del(&cmdinfo->list); -		cmdinfo->state &= ~IS_IN_WORK_LIST; -		spin_unlock(&uas_work_lock); + +	if (devinfo->resetting) { +		spin_unlock_irqrestore(&devinfo->lock, flags); +		return FAILED;  	} + +	uas_mark_cmd_dead(devinfo, cmdinfo, DID_ABORT, __func__);  	if (cmdinfo->state & COMMAND_INFLIGHT) {  		spin_unlock_irqrestore(&devinfo->lock, flags);  		ret = uas_eh_task_mgmt(cmnd, "ABORT TASK", TMF_ABORT_TASK);  	} else { -		spin_unlock_irqrestore(&devinfo->lock, flags); -		uas_unlink_data_urbs(devinfo, cmdinfo); -		spin_lock_irqsave(&devinfo->lock, flags); +		uas_unlink_data_urbs(devinfo, cmdinfo, &flags);  		uas_try_complete(cmnd, __func__);  		spin_unlock_irqrestore(&devinfo->lock, flags);  		ret = SUCCESS; @@ -795,14 +895,25 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)  	struct usb_device *udev = devinfo->udev;  	int err; +	err = usb_lock_device_for_reset(udev, devinfo->intf); +	if (err) { +		shost_printk(KERN_ERR, sdev->host, +			     "%s FAILED to get lock err %d\n", __func__, err); +		return FAILED; +	} + +	shost_printk(KERN_INFO, sdev->host, "%s start\n", __func__);  	devinfo->resetting = 1; -	uas_abort_work(devinfo); +	uas_abort_inflight(devinfo, DID_RESET, __func__);  	usb_kill_anchored_urbs(&devinfo->cmd_urbs);  	usb_kill_anchored_urbs(&devinfo->sense_urbs);  	usb_kill_anchored_urbs(&devinfo->data_urbs); +	uas_zap_dead(devinfo);  	err = usb_reset_device(udev);  	devinfo->resetting = 0; +	usb_unlock_device(udev); +  	if (err) {  		shost_printk(KERN_INFO, sdev->host, "%s FAILED\n", __func__);  		return FAILED; @@ -814,7 +925,25 @@ static int uas_eh_bus_reset_handler(struct scsi_cmnd *cmnd)  static int uas_slave_alloc(struct scsi_device *sdev)  { -	sdev->hostdata = (void *)sdev->host->hostdata[0]; +	sdev->hostdata = (void *)sdev->host->hostdata; + +	/* USB has unusual DMA-alignment requirements: Although the +	 * starting address of each scatter-gather element doesn't matter, +	 * the length of each element except the last must be divisible +	 * by the Bulk maxpacket value.  There's currently no way to +	 * express this by block-layer constraints, so we'll cop out +	 * and simply require addresses to be aligned at 512-byte +	 * boundaries.  This is okay since most block I/O involves +	 * hardware sectors that are multiples of 512 bytes in length, +	 * and since host controllers up through USB 2.0 have maxpacket +	 * values no larger than 512. +	 * +	 * But it doesn't suffice for Wireless USB, where Bulk maxpacket +	 * values can be as large as 2048.  To make that work properly +	 * will require changes to the block layer. +	 */ +	blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); +  	return 0;  } @@ -822,7 +951,7 @@ static int uas_slave_configure(struct scsi_device *sdev)  {  	struct uas_dev_info *devinfo = sdev->hostdata;  	scsi_set_tag_type(sdev, MSG_ORDERED_TAG); -	scsi_activate_tcq(sdev, devinfo->qdepth - 3); +	scsi_activate_tcq(sdev, devinfo->qdepth - 2);  	return 0;  } @@ -843,7 +972,14 @@ static struct scsi_host_template uas_host_template = {  	.ordered_tag = 1,  }; +#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ +		    vendorName, productName, useProtocol, useTransport, \ +		    initFunction, flags) \ +{ USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ +	.driver_info = (flags) } +  static struct usb_device_id uas_usb_ids[] = { +#	include "unusual_uas.h"  	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_BULK) },  	{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, USB_SC_SCSI, USB_PR_UAS) },  	/* 0xaa is a prototype device I happen to have access to */ @@ -852,105 +988,55 @@ static struct usb_device_id uas_usb_ids[] = {  };  MODULE_DEVICE_TABLE(usb, uas_usb_ids); -static int uas_is_interface(struct usb_host_interface *intf) -{ -	return (intf->desc.bInterfaceClass == USB_CLASS_MASS_STORAGE && -		intf->desc.bInterfaceSubClass == USB_SC_SCSI && -		intf->desc.bInterfaceProtocol == USB_PR_UAS); -} - -static int uas_isnt_supported(struct usb_device *udev) -{ -	struct usb_hcd *hcd = bus_to_hcd(udev->bus); - -	dev_warn(&udev->dev, "The driver for the USB controller %s does not " -			"support scatter-gather which is\n", -			hcd->driver->description); -	dev_warn(&udev->dev, "required by the UAS driver. Please try an" -			"alternative USB controller if you wish to use UAS.\n"); -	return -ENODEV; -} +#undef UNUSUAL_DEV  static int uas_switch_interface(struct usb_device *udev, -						struct usb_interface *intf) +				struct usb_interface *intf)  { -	int i; -	int sg_supported = udev->bus->sg_tablesize != 0; - -	for (i = 0; i < intf->num_altsetting; i++) { -		struct usb_host_interface *alt = &intf->altsetting[i]; - -		if (uas_is_interface(alt)) { -			if (!sg_supported) -				return uas_isnt_supported(udev); -			return usb_set_interface(udev, -						alt->desc.bInterfaceNumber, -						alt->desc.bAlternateSetting); -		} -	} +	int alt; + +	alt = uas_find_uas_alt_setting(intf); +	if (alt < 0) +		return alt; -	return -ENODEV; +	return usb_set_interface(udev, +			intf->altsetting[0].desc.bInterfaceNumber, alt);  } -static void uas_configure_endpoints(struct uas_dev_info *devinfo) +static int uas_configure_endpoints(struct uas_dev_info *devinfo)  {  	struct usb_host_endpoint *eps[4] = { }; -	struct usb_interface *intf = devinfo->intf;  	struct usb_device *udev = devinfo->udev; -	struct usb_host_endpoint *endpoint = intf->cur_altsetting->endpoint; -	unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints; +	int r;  	devinfo->uas_sense_old = 0;  	devinfo->cmnd = NULL; -	for (i = 0; i < n_endpoints; i++) { -		unsigned char *extra = endpoint[i].extra; -		int len = endpoint[i].extralen; -		while (len > 1) { -			if (extra[1] == USB_DT_PIPE_USAGE) { -				unsigned pipe_id = extra[2]; -				if (pipe_id > 0 && pipe_id < 5) -					eps[pipe_id - 1] = &endpoint[i]; -				break; -			} -			len -= extra[0]; -			extra += extra[0]; -		} -	} +	r = uas_find_endpoints(devinfo->intf->cur_altsetting, eps); +	if (r) +		return r; -	/* -	 * Assume that if we didn't find a control pipe descriptor, we're -	 * using a device with old firmware that happens to be set up like -	 * this. -	 */ -	if (!eps[0]) { -		devinfo->cmd_pipe = usb_sndbulkpipe(udev, 1); -		devinfo->status_pipe = usb_rcvbulkpipe(udev, 1); -		devinfo->data_in_pipe = usb_rcvbulkpipe(udev, 2); -		devinfo->data_out_pipe = usb_sndbulkpipe(udev, 2); - -		eps[1] = usb_pipe_endpoint(udev, devinfo->status_pipe); -		eps[2] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); -		eps[3] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); -	} else { -		devinfo->cmd_pipe = usb_sndbulkpipe(udev, -						eps[0]->desc.bEndpointAddress); -		devinfo->status_pipe = usb_rcvbulkpipe(udev, -						eps[1]->desc.bEndpointAddress); -		devinfo->data_in_pipe = usb_rcvbulkpipe(udev, -						eps[2]->desc.bEndpointAddress); -		devinfo->data_out_pipe = usb_sndbulkpipe(udev, -						eps[3]->desc.bEndpointAddress); -	} +	devinfo->cmd_pipe = usb_sndbulkpipe(udev, +					    usb_endpoint_num(&eps[0]->desc)); +	devinfo->status_pipe = usb_rcvbulkpipe(udev, +					    usb_endpoint_num(&eps[1]->desc)); +	devinfo->data_in_pipe = usb_rcvbulkpipe(udev, +					    usb_endpoint_num(&eps[2]->desc)); +	devinfo->data_out_pipe = usb_sndbulkpipe(udev, +					    usb_endpoint_num(&eps[3]->desc)); -	devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1, 3, 256, -								GFP_KERNEL); -	if (devinfo->qdepth < 0) { +	if (udev->speed != USB_SPEED_SUPER) {  		devinfo->qdepth = 256;  		devinfo->use_streams = 0;  	} else { +		devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1, +						    3, 256, GFP_NOIO); +		if (devinfo->qdepth < 0) +			return devinfo->qdepth;  		devinfo->use_streams = 1;  	} + +	return 0;  }  static void uas_free_streams(struct uas_dev_info *devinfo) @@ -961,33 +1047,26 @@ static void uas_free_streams(struct uas_dev_info *devinfo)  	eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);  	eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);  	eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); -	usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL); +	usb_free_streams(devinfo->intf, eps, 3, GFP_NOIO);  } -/* - * XXX: What I'd like to do here is register a SCSI host for each USB host in - * the system.  Follow usb-storage's design of registering a SCSI host for - * each USB device for the moment.  Can implement this by walking up the - * USB hierarchy until we find a USB host. - */  static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)  { -	int result; -	struct Scsi_Host *shost; +	int result = -ENOMEM; +	struct Scsi_Host *shost = NULL;  	struct uas_dev_info *devinfo;  	struct usb_device *udev = interface_to_usbdev(intf); -	if (uas_switch_interface(udev, intf)) +	if (!uas_use_uas_driver(intf, id))  		return -ENODEV; -	devinfo = kmalloc(sizeof(struct uas_dev_info), GFP_KERNEL); -	if (!devinfo) -		return -ENOMEM; +	if (uas_switch_interface(udev, intf)) +		return -ENODEV; -	result = -ENOMEM; -	shost = scsi_host_alloc(&uas_host_template, sizeof(void *)); +	shost = scsi_host_alloc(&uas_host_template, +				sizeof(struct uas_dev_info));  	if (!shost) -		goto free; +		goto set_alt0;  	shost->max_cmd_len = 16 + 252;  	shost->max_id = 1; @@ -995,33 +1074,41 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)  	shost->max_channel = 0;  	shost->sg_tablesize = udev->bus->sg_tablesize; +	devinfo = (struct uas_dev_info *)shost->hostdata;  	devinfo->intf = intf;  	devinfo->udev = udev;  	devinfo->resetting = 0; +	devinfo->running_task = 0; +	devinfo->shutdown = 0;  	init_usb_anchor(&devinfo->cmd_urbs);  	init_usb_anchor(&devinfo->sense_urbs);  	init_usb_anchor(&devinfo->data_urbs);  	spin_lock_init(&devinfo->lock); -	uas_configure_endpoints(devinfo); +	INIT_WORK(&devinfo->work, uas_do_work); +	INIT_LIST_HEAD(&devinfo->inflight_list); +	INIT_LIST_HEAD(&devinfo->dead_list); -	result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 3); +	result = uas_configure_endpoints(devinfo);  	if (result) -		goto free; +		goto set_alt0; -	result = scsi_add_host(shost, &intf->dev); +	result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);  	if (result) -		goto deconfig_eps; +		goto free_streams; -	shost->hostdata[0] = (unsigned long)devinfo; +	usb_set_intfdata(intf, shost); +	result = scsi_add_host(shost, &intf->dev); +	if (result) +		goto free_streams;  	scsi_scan_host(shost); -	usb_set_intfdata(intf, shost);  	return result; -deconfig_eps: +free_streams:  	uas_free_streams(devinfo); - free: -	kfree(devinfo); +	usb_set_intfdata(intf, NULL); +set_alt0: +	usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0);  	if (shost)  		scsi_host_put(shost);  	return result; @@ -1029,45 +1116,146 @@ deconfig_eps:  static int uas_pre_reset(struct usb_interface *intf)  { -/* XXX: Need to return 1 if it's not our device in error handling */ +	struct Scsi_Host *shost = usb_get_intfdata(intf); +	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; +	unsigned long flags; + +	if (devinfo->shutdown) +		return 0; + +	/* Block new requests */ +	spin_lock_irqsave(shost->host_lock, flags); +	scsi_block_requests(shost); +	spin_unlock_irqrestore(shost->host_lock, flags); + +	/* Wait for any pending requests to complete */ +	flush_work(&devinfo->work); +	if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 5000) == 0) { +		shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__); +		return 1; +	} + +	uas_free_streams(devinfo); +  	return 0;  }  static int uas_post_reset(struct usb_interface *intf)  { -/* XXX: Need to return 1 if it's not our device in error handling */ +	struct Scsi_Host *shost = usb_get_intfdata(intf); +	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; +	unsigned long flags; + +	if (devinfo->shutdown) +		return 0; + +	if (uas_configure_endpoints(devinfo) != 0) { +		shost_printk(KERN_ERR, shost, +			     "%s: alloc streams error after reset", __func__); +		return 1; +	} + +	spin_lock_irqsave(shost->host_lock, flags); +	scsi_report_bus_reset(shost, 0); +	spin_unlock_irqrestore(shost->host_lock, flags); + +	scsi_unblock_requests(shost); + +	return 0; +} + +static int uas_suspend(struct usb_interface *intf, pm_message_t message) +{ +	struct Scsi_Host *shost = usb_get_intfdata(intf); +	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; + +	/* Wait for any pending requests to complete */ +	flush_work(&devinfo->work); +	if (usb_wait_anchor_empty_timeout(&devinfo->sense_urbs, 5000) == 0) { +		shost_printk(KERN_ERR, shost, "%s: timed out\n", __func__); +		return -ETIME; +	} + +	return 0; +} + +static int uas_resume(struct usb_interface *intf) +{ +	return 0; +} + +static int uas_reset_resume(struct usb_interface *intf) +{ +	struct Scsi_Host *shost = usb_get_intfdata(intf); +	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; +	unsigned long flags; + +	if (uas_configure_endpoints(devinfo) != 0) { +		shost_printk(KERN_ERR, shost, +			     "%s: alloc streams error after reset", __func__); +		return -EIO; +	} + +	spin_lock_irqsave(shost->host_lock, flags); +	scsi_report_bus_reset(shost, 0); +	spin_unlock_irqrestore(shost->host_lock, flags); +  	return 0;  }  static void uas_disconnect(struct usb_interface *intf)  {  	struct Scsi_Host *shost = usb_get_intfdata(intf); -	struct uas_dev_info *devinfo = (void *)shost->hostdata[0]; +	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata;  	devinfo->resetting = 1; -	uas_abort_work(devinfo); +	cancel_work_sync(&devinfo->work); +	uas_abort_inflight(devinfo, DID_NO_CONNECT, __func__);  	usb_kill_anchored_urbs(&devinfo->cmd_urbs);  	usb_kill_anchored_urbs(&devinfo->sense_urbs);  	usb_kill_anchored_urbs(&devinfo->data_urbs); +	uas_zap_dead(devinfo);  	scsi_remove_host(shost);  	uas_free_streams(devinfo); -	kfree(devinfo); +	scsi_host_put(shost);  }  /* - * XXX: Should this plug into libusual so we can auto-upgrade devices from - * Bulk-Only to UAS? + * Put the device back in usb-storage mode on shutdown, as some BIOS-es + * hang on reboot when the device is still in uas mode. Note the reset is + * necessary as some devices won't revert to usb-storage mode without it.   */ +static void uas_shutdown(struct device *dev) +{ +	struct usb_interface *intf = to_usb_interface(dev); +	struct usb_device *udev = interface_to_usbdev(intf); +	struct Scsi_Host *shost = usb_get_intfdata(intf); +	struct uas_dev_info *devinfo = (struct uas_dev_info *)shost->hostdata; + +	if (system_state != SYSTEM_RESTART) +		return; + +	devinfo->shutdown = 1; +	uas_free_streams(devinfo); +	usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0); +	usb_reset_device(udev); +} +  static struct usb_driver uas_driver = {  	.name = "uas",  	.probe = uas_probe,  	.disconnect = uas_disconnect,  	.pre_reset = uas_pre_reset,  	.post_reset = uas_post_reset, +	.suspend = uas_suspend, +	.resume = uas_resume, +	.reset_resume = uas_reset_resume, +	.drvwrap.driver.shutdown = uas_shutdown,  	.id_table = uas_usb_ids,  };  module_usb_driver(uas_driver);  MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Matthew Wilcox and Sarah Sharp"); +MODULE_AUTHOR( +	"Hans de Goede <hdegoede@redhat.com>, Matthew Wilcox and Sarah Sharp"); diff --git a/drivers/usb/storage/unusual_cypress.h b/drivers/usb/storage/unusual_cypress.h index 65a6a75066a..82e8ed0324e 100644 --- a/drivers/usb/storage/unusual_cypress.h +++ b/drivers/usb/storage/unusual_cypress.h @@ -31,7 +31,7 @@ UNUSUAL_DEV(  0x04b4, 0x6831, 0x0000, 0x9999,  		"Cypress ISD-300LP",  		USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0), -UNUSUAL_DEV( 0x14cd, 0x6116, 0x0000, 0x0219, +UNUSUAL_DEV( 0x14cd, 0x6116, 0x0160, 0x0160,  		"Super Top",  		"USB 2.0  SATA BRIDGE",  		USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0), diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index c015f2c1672..80a5b366255 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -234,6 +234,27 @@ UNUSUAL_DEV(  0x0421, 0x0495, 0x0370, 0x0370,  		USB_SC_DEVICE, USB_PR_DEVICE, NULL,  		US_FL_MAX_SECTORS_64 ), +/* Reported by Daniele Forsi <dforsi@gmail.com> */ +UNUSUAL_DEV(  0x0421, 0x04b9, 0x0350, 0x0350, +		"Nokia", +		"5300", +		USB_SC_DEVICE, USB_PR_DEVICE, NULL, +		US_FL_MAX_SECTORS_64 ), + +/* Patch submitted by Victor A. Santos <victoraur.santos@gmail.com> */ +UNUSUAL_DEV(  0x0421, 0x05af, 0x0742, 0x0742, +		"Nokia", +		"305", +		USB_SC_DEVICE, USB_PR_DEVICE, NULL, +		US_FL_MAX_SECTORS_64), + +/* Patch submitted by Mikhail Zolotaryov <lebon@lebon.org.ua> */ +UNUSUAL_DEV(  0x0421, 0x06aa, 0x1110, 0x1110, +		"Nokia", +		"502", +		USB_SC_DEVICE, USB_PR_DEVICE, NULL, +		US_FL_MAX_SECTORS_64 ), +  #ifdef NO_SDDR09  UNUSUAL_DEV(  0x0436, 0x0005, 0x0100, 0x0100,  		"Microtech", @@ -1448,6 +1469,13 @@ UNUSUAL_DEV( 0x0f88, 0x042e, 0x0100, 0x0100,  		USB_SC_DEVICE, USB_PR_DEVICE, NULL,  		US_FL_FIX_CAPACITY ), +/* Reported by Moritz Moeller-Herrmann <moritz-kernel@moeller-herrmann.de> */ +UNUSUAL_DEV(  0x0fca, 0x8004, 0x0201, 0x0201, +		"Research In Motion", +		"BlackBerry Bold 9000", +		USB_SC_DEVICE, USB_PR_DEVICE, NULL, +		US_FL_MAX_SECTORS_64 ), +  /* Reported by Michael Stattmann <michael@stattmann.com> */  UNUSUAL_DEV(  0x0fce, 0xd008, 0x0000, 0x0000,  		"Sony Ericsson", @@ -1908,6 +1936,13 @@ UNUSUAL_DEV(  0x14cd, 0x6600, 0x0201, 0x0201,  		USB_SC_DEVICE, USB_PR_DEVICE, NULL,  		US_FL_IGNORE_RESIDUE ), +/* Reported by Michael Büsch <m@bues.ch> */ +UNUSUAL_DEV(  0x152d, 0x0567, 0x0114, 0x0114, +		"JMicron", +		"USB to ATA/ATAPI Bridge", +		USB_SC_DEVICE, USB_PR_DEVICE, NULL, +		US_FL_BROKEN_FUA ), +  /* Reported by Alexandre Oliva <oliva@lsd.ic.unicamp.br>   * JMicron responds to USN and several other SCSI ioctls with a   * residue that causes subsequent I/O requests to fail.  */ @@ -1925,6 +1960,13 @@ UNUSUAL_DEV(  0x1652, 0x6600, 0x0201, 0x0201,  		USB_SC_DEVICE, USB_PR_DEVICE, NULL,  		US_FL_IGNORE_RESIDUE ), +/* Reported by Oliver Neukum <oneukum@suse.com> */ +UNUSUAL_DEV(  0x174c, 0x55aa, 0x0100, 0x0100, +		"ASMedia", +		"AS2105", +		USB_SC_DEVICE, USB_PR_DEVICE, NULL, +		US_FL_NEEDS_CAP16), +  /* Reported by Jesse Feddema <jdfeddema@gmail.com> */  UNUSUAL_DEV(  0x177f, 0x0400, 0x0000, 0x0000,  		"Yarvik", @@ -2065,6 +2107,11 @@ UNUSUAL_DEV( 0xed10, 0x7636, 0x0001, 0x0001,  		"Digital MP3 Audio Player",  		USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_NOT_LOCKABLE ), +/* Unusual uas devices */ +#if IS_ENABLED(CONFIG_USB_UAS) +#include "unusual_uas.h" +#endif +  /* Control/Bulk transport for all SubClass values */  USUAL_DEV(USB_SC_RBC, USB_PR_CB),  USUAL_DEV(USB_SC_8020, USB_PR_CB), diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h new file mode 100644 index 00000000000..7244444df8e --- /dev/null +++ b/drivers/usb/storage/unusual_uas.h @@ -0,0 +1,52 @@ +/* Driver for USB Attached SCSI devices - Unusual Devices File + * + *   (c) 2013 Hans de Goede <hdegoede@redhat.com> + * + * Based on the same file for the usb-storage driver, which is: + *   (c) 2000-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net) + *   (c) 2000 Adam J. Richter (adam@yggdrasil.com), Yggdrasil Computing, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* + * IMPORTANT NOTE: This file must be included in another file which defines + * a UNUSUAL_DEV macro before this file is included. + */ + +/* + * If you edit this file, please try to keep it sorted first by VendorID, + * then by ProductID. + * + * If you want to add an entry for this file, be sure to include the + * following information: + *	- a patch that adds the entry for your device, including your + *	  email address right above the entry (plus maybe a brief + *	  explanation of the reason for the entry), + *	- lsusb -v output for the device + * Send your submission to Hans de Goede <hdegoede@redhat.com> + * and don't forget to CC: the USB development list <linux-usb@vger.kernel.org> + */ + +/* + * This is an example entry for the US_FL_IGNORE_UAS flag. Once we have an + * actual entry using US_FL_IGNORE_UAS this entry should be removed. + * + * UNUSUAL_DEV(  0xabcd, 0x1234, 0x0100, 0x0100, + *		"Example", + *		"Storage with broken UAS", + *		USB_SC_DEVICE, USB_PR_DEVICE, NULL, + *		US_FL_IGNORE_UAS), + */ diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 5c4fe0749af..f1c96261a50 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -53,7 +53,6 @@  #include <linux/errno.h>  #include <linux/freezer.h>  #include <linux/module.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/kthread.h>  #include <linux/mutex.h> @@ -73,6 +72,10 @@  #include "sierra_ms.h"  #include "option_ms.h" +#if IS_ENABLED(CONFIG_USB_UAS) +#include "uas-detect.h" +#endif +  /* Some informational data */  MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");  MODULE_DESCRIPTION("USB Mass Storage driver for Linux"); @@ -460,14 +463,14 @@ static int associate_dev(struct us_data *us, struct usb_interface *intf)  #define TOLOWER(x) ((x) | 0x20)  /* Adjust device flags based on the "quirks=" module parameter */ -static void adjust_quirks(struct us_data *us) +void usb_stor_adjust_quirks(struct usb_device *udev, unsigned long *fflags)  {  	char *p; -	u16 vid = le16_to_cpu(us->pusb_dev->descriptor.idVendor); -	u16 pid = le16_to_cpu(us->pusb_dev->descriptor.idProduct); +	u16 vid = le16_to_cpu(udev->descriptor.idVendor); +	u16 pid = le16_to_cpu(udev->descriptor.idProduct);  	unsigned f = 0;  	unsigned int mask = (US_FL_SANE_SENSE | US_FL_BAD_SENSE | -			US_FL_FIX_CAPACITY | +			US_FL_FIX_CAPACITY | US_FL_IGNORE_UAS |  			US_FL_CAPACITY_HEURISTICS | US_FL_IGNORE_DEVICE |  			US_FL_NOT_LOCKABLE | US_FL_MAX_SECTORS_64 |  			US_FL_CAPACITY_OK | US_FL_IGNORE_RESIDUE | @@ -538,14 +541,18 @@ static void adjust_quirks(struct us_data *us)  		case 's':  			f |= US_FL_SINGLE_LUN;  			break; +		case 'u': +			f |= US_FL_IGNORE_UAS; +			break;  		case 'w':  			f |= US_FL_NO_WP_DETECT;  			break;  		/* Ignore unrecognized flag characters */  		}  	} -	us->fflags = (us->fflags & ~mask) | f; +	*fflags = (*fflags & ~mask) | f;  } +EXPORT_SYMBOL_GPL(usb_stor_adjust_quirks);  /* Get the unusual_devs entries and the string descriptors */  static int get_device_info(struct us_data *us, const struct usb_device_id *id, @@ -565,7 +572,7 @@ static int get_device_info(struct us_data *us, const struct usb_device_id *id,  			idesc->bInterfaceProtocol :  			unusual_dev->useTransport;  	us->fflags = id->driver_info; -	adjust_quirks(us); +	usb_stor_adjust_quirks(us->pusb_dev, &us->fflags);  	if (us->fflags & US_FL_IGNORE_DEVICE) {  		dev_info(pdev, "device ignored\n"); @@ -1036,6 +1043,12 @@ static int storage_probe(struct usb_interface *intf,  	int result;  	int size; +	/* If uas is enabled and this device can do uas then ignore it. */ +#if IS_ENABLED(CONFIG_USB_UAS) +	if (uas_use_uas_driver(intf, id)) +		return -ENXIO; +#endif +  	/*  	 * If the device isn't standard (is handled by a subdriver  	 * module) then don't accept it. diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h index 75f70f04f37..307e339a947 100644 --- a/drivers/usb/storage/usb.h +++ b/drivers/usb/storage/usb.h @@ -201,4 +201,7 @@ extern int usb_stor_probe1(struct us_data **pus,  extern int usb_stor_probe2(struct us_data *us);  extern void usb_stor_disconnect(struct usb_interface *intf); +extern void usb_stor_adjust_quirks(struct usb_device *dev, +		unsigned long *fflags); +  #endif diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index ff97652343a..545d09b8081 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -14,7 +14,6 @@  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/slab.h>  #include <linux/module.h>  #include <linux/kref.h> diff --git a/drivers/usb/wusbcore/cbaf.c b/drivers/usb/wusbcore/cbaf.c index 7f78f300f8f..da1b872918b 100644 --- a/drivers/usb/wusbcore/cbaf.c +++ b/drivers/usb/wusbcore/cbaf.c @@ -144,7 +144,7 @@ static int cbaf_check(struct cbaf *cbaf)  		CBAF_REQ_GET_ASSOCIATION_INFORMATION,  		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  		0, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, -		cbaf->buffer, cbaf->buffer_size, 1000 /* FIXME: arbitrary */); +		cbaf->buffer, cbaf->buffer_size, USB_CTRL_GET_TIMEOUT);  	if (result < 0) {  		dev_err(dev, "Cannot get available association types: %d\n",  			result); @@ -184,7 +184,7 @@ static int cbaf_check(struct cbaf *cbaf)  		assoc_request = itr;  		if (top - itr < sizeof(*assoc_request)) { -			dev_err(dev, "Not enough data to decode associaton " +			dev_err(dev, "Not enough data to decode association "  				"request (%zu vs %zu bytes needed)\n",  				top - itr, sizeof(*assoc_request));  			break; @@ -208,9 +208,9 @@ static int cbaf_check(struct cbaf *cbaf)  				ar_name = "ASSOCIATE";  				ar_assoc = 1;  				break; -			}; +			}  			break; -		}; +		}  		dev_dbg(dev, "Association request #%02u: 0x%04x/%04x "  			 "(%zu bytes): %s\n", @@ -235,7 +235,7 @@ static int cbaf_check(struct cbaf *cbaf)  static const struct wusb_cbaf_host_info cbaf_host_info_defaults = {  	.AssociationTypeId_hdr    = WUSB_AR_AssociationTypeId, -	.AssociationTypeId    	  = cpu_to_le16(AR_TYPE_WUSB), +	.AssociationTypeId	  = cpu_to_le16(AR_TYPE_WUSB),  	.AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,  	.AssociationSubTypeId = cpu_to_le16(AR_TYPE_WUSB_RETRIEVE_HOST_INFO),  	.CHID_hdr                 = WUSB_AR_CHID, @@ -260,12 +260,13 @@ static int cbaf_send_host_info(struct cbaf *cbaf)  	hi->HostFriendlyName_hdr.len = cpu_to_le16(name_len);  	hi_size = sizeof(*hi) + name_len; -	return usb_control_msg(cbaf->usb_dev, usb_sndctrlpipe(cbaf->usb_dev, 0), +	return usb_control_msg(cbaf->usb_dev, +			usb_sndctrlpipe(cbaf->usb_dev, 0),  			CBAF_REQ_SET_ASSOCIATION_RESPONSE,  			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  			0x0101,  			cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, -			hi, hi_size, 1000 /* FIXME: arbitrary */); +			hi, hi_size, USB_CTRL_SET_TIMEOUT);  }  /* @@ -288,9 +289,10 @@ static int cbaf_cdid_get(struct cbaf *cbaf)  		CBAF_REQ_GET_ASSOCIATION_REQUEST,  		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  		0x0200, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, -		di, cbaf->buffer_size, 1000 /* FIXME: arbitrary */); +		di, cbaf->buffer_size, USB_CTRL_GET_TIMEOUT);  	if (result < 0) { -		dev_err(dev, "Cannot request device information: %d\n", result); +		dev_err(dev, "Cannot request device information: %d\n", +			result);  		return result;  	} @@ -491,11 +493,11 @@ static DEVICE_ATTR(wusb_device_name, 0600, cbaf_wusb_device_name_show, NULL);  static const struct wusb_cbaf_cc_data cbaf_cc_data_defaults = {  	.AssociationTypeId_hdr    = WUSB_AR_AssociationTypeId, -	.AssociationTypeId    	  = cpu_to_le16(AR_TYPE_WUSB), +	.AssociationTypeId	  = cpu_to_le16(AR_TYPE_WUSB),  	.AssociationSubTypeId_hdr = WUSB_AR_AssociationSubTypeId,  	.AssociationSubTypeId     = cpu_to_le16(AR_TYPE_WUSB_ASSOCIATE),  	.Length_hdr               = WUSB_AR_Length, -	.Length               	  = cpu_to_le32(sizeof(struct wusb_cbaf_cc_data)), +	.Length		= cpu_to_le32(sizeof(struct wusb_cbaf_cc_data)),  	.ConnectionContext_hdr    = WUSB_AR_ConnectionContext,  	.BandGroups_hdr           = WUSB_AR_BandGroups,  }; @@ -536,7 +538,7 @@ static int cbaf_cc_upload(struct cbaf *cbaf)  		CBAF_REQ_SET_ASSOCIATION_RESPONSE,  		USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  		0x0201, cbaf->usb_iface->cur_altsetting->desc.bInterfaceNumber, -		ccd, sizeof(*ccd), 1000 /* FIXME: arbitrary */); +		ccd, sizeof(*ccd), USB_CTRL_SET_TIMEOUT);  	return result;  } @@ -623,6 +625,8 @@ static int cbaf_probe(struct usb_interface *iface,  error_create_group:  error_check: +	usb_put_intf(iface); +	usb_put_dev(cbaf->usb_dev);  	kfree(cbaf->buffer);  error_kmalloc_buffer:  	kfree(cbaf); @@ -637,6 +641,7 @@ static void cbaf_disconnect(struct usb_interface *iface)  	sysfs_remove_group(&dev->kobj, &cbaf_dev_attr_group);  	usb_set_intfdata(iface, NULL);  	usb_put_intf(iface); +	usb_put_dev(cbaf->usb_dev);  	kfree(cbaf->buffer);  	/* paranoia: clean up crypto keys */  	kzfree(cbaf); diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c index 7e4bf95f8f7..9a95b2dc6d1 100644 --- a/drivers/usb/wusbcore/crypto.c +++ b/drivers/usb/wusbcore/crypto.c @@ -87,7 +87,7 @@ struct aes_ccm_block {   * B1 contains l(a), the MAC header, the encryption offset and padding.   *   * If EO is nonzero, additional blocks are built from payload bytes - * until EO is exahusted (FIXME: padding to 16 bytes, I guess). The + * until EO is exhausted (FIXME: padding to 16 bytes, I guess). The   * padding is not xmitted.   */ diff --git a/drivers/usb/wusbcore/devconnect.c b/drivers/usb/wusbcore/devconnect.c index 33a12788f9c..0677139c606 100644 --- a/drivers/usb/wusbcore/devconnect.c +++ b/drivers/usb/wusbcore/devconnect.c @@ -97,18 +97,12 @@ static void wusbhc_devconnect_acked_work(struct work_struct *work);  static void wusb_dev_free(struct wusb_dev *wusb_dev)  { -	if (wusb_dev) { -		kfree(wusb_dev->set_gtk_req); -		usb_free_urb(wusb_dev->set_gtk_urb); -		kfree(wusb_dev); -	} +	kfree(wusb_dev);  }  static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc)  {  	struct wusb_dev *wusb_dev; -	struct urb *urb; -	struct usb_ctrlrequest *req;  	wusb_dev = kzalloc(sizeof(*wusb_dev), GFP_KERNEL);  	if (wusb_dev == NULL) @@ -118,22 +112,6 @@ static struct wusb_dev *wusb_dev_alloc(struct wusbhc *wusbhc)  	INIT_WORK(&wusb_dev->devconnect_acked_work, wusbhc_devconnect_acked_work); -	urb = usb_alloc_urb(0, GFP_KERNEL); -	if (urb == NULL) -		goto err; -	wusb_dev->set_gtk_urb = urb; - -	req = kmalloc(sizeof(*req), GFP_KERNEL); -	if (req == NULL) -		goto err; -	wusb_dev->set_gtk_req = req; - -	req->bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; -	req->bRequest = USB_REQ_SET_DESCRIPTOR; -	req->wValue = cpu_to_le16(USB_DT_KEY << 8 | wusbhc->gtk_index); -	req->wIndex = 0; -	req->wLength = cpu_to_le16(wusbhc->gtk.descr.bLength); -  	return wusb_dev;  err:  	wusb_dev_free(wusb_dev); @@ -287,9 +265,9 @@ static void wusbhc_devconnect_acked_work(struct work_struct *work)   * Addresses: because WUSB hosts have no downstream hubs, we can do a   *            1:1 mapping between 'port number' and device   *            address. This simplifies many things, as during this - *            initial connect phase the USB stack has no knoledge of + *            initial connect phase the USB stack has no knowledge of   *            the device and hasn't assigned an address yet--we know - *            USB's choose_address() will use the same euristics we + *            USB's choose_address() will use the same heuristics we   *            use here, so we can assume which address will be assigned.   *   *            USB stack always assigns address 1 to the root hub, so @@ -306,7 +284,7 @@ void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc,  	struct device *dev = wusbhc->dev;  	struct wusb_dev *wusb_dev;  	struct wusb_port *port; -	unsigned idx, devnum; +	unsigned idx;  	mutex_lock(&wusbhc->mutex); @@ -334,8 +312,6 @@ void wusbhc_devconnect_ack(struct wusbhc *wusbhc, struct wusb_dn_connect *dnc,  		goto error_unlock;  	} -	devnum = idx + 2; -  	/* Make sure we are using no crypto on that "virtual port" */  	wusbhc->set_ptk(wusbhc, idx, 0, NULL, 0); @@ -411,9 +387,6 @@ static void __wusbhc_dev_disconnect(struct wusbhc *wusbhc,  /*   * Refresh the list of keep alives to emit in the MMC   * - * Some devices don't respond to keep alives unless they've been - * authenticated, so skip unauthenticated devices. - *   * We only publish the first four devices that have a coming timeout   * condition. Then when we are done processing those, we go for the   * next ones. We ignore the ones that have timed out already (they'll @@ -448,7 +421,7 @@ static void __wusbhc_keep_alive(struct wusbhc *wusbhc)  		if (wusb_dev == NULL)  			continue; -		if (wusb_dev->usb_dev == NULL || !wusb_dev->usb_dev->authenticated) +		if (wusb_dev->usb_dev == NULL)  			continue;  		if (time_after(jiffies, wusb_dev->entry_ts + tt)) { @@ -524,11 +497,19 @@ static struct wusb_dev *wusbhc_find_dev_by_addr(struct wusbhc *wusbhc, u8 addr)   *   * @wusbhc shall be referenced and unlocked   */ -static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) +static void wusbhc_handle_dn_alive(struct wusbhc *wusbhc, u8 srcaddr)  { +	struct wusb_dev *wusb_dev; +  	mutex_lock(&wusbhc->mutex); -	wusb_dev->entry_ts = jiffies; -	__wusbhc_keep_alive(wusbhc); +	wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr); +	if (wusb_dev == NULL) { +		dev_dbg(wusbhc->dev, "ignoring DN_Alive from unconnected device %02x\n", +			srcaddr); +	} else { +		wusb_dev->entry_ts = jiffies; +		__wusbhc_keep_alive(wusbhc); +	}  	mutex_unlock(&wusbhc->mutex);  } @@ -582,14 +563,22 @@ static void wusbhc_handle_dn_connect(struct wusbhc *wusbhc,   *   * @wusbhc shall be referenced and unlocked   */ -static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev) +static void wusbhc_handle_dn_disconnect(struct wusbhc *wusbhc, u8 srcaddr)  {  	struct device *dev = wusbhc->dev; - -	dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n", wusb_dev->addr); +	struct wusb_dev *wusb_dev;  	mutex_lock(&wusbhc->mutex); -	__wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, wusb_dev->port_idx)); +	wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr); +	if (wusb_dev == NULL) { +		dev_dbg(dev, "ignoring DN DISCONNECT from unconnected device %02x\n", +			srcaddr); +	} else { +		dev_info(dev, "DN DISCONNECT: device 0x%02x going down\n", +			wusb_dev->addr); +		__wusbhc_dev_disconnect(wusbhc, wusb_port_by_idx(wusbhc, +			wusb_dev->port_idx)); +	}  	mutex_unlock(&wusbhc->mutex);  } @@ -611,30 +600,21 @@ void wusbhc_handle_dn(struct wusbhc *wusbhc, u8 srcaddr,  		      struct wusb_dn_hdr *dn_hdr, size_t size)  {  	struct device *dev = wusbhc->dev; -	struct wusb_dev *wusb_dev;  	if (size < sizeof(struct wusb_dn_hdr)) {  		dev_err(dev, "DN data shorter than DN header (%d < %d)\n",  			(int)size, (int)sizeof(struct wusb_dn_hdr));  		return;  	} - -	wusb_dev = wusbhc_find_dev_by_addr(wusbhc, srcaddr); -	if (wusb_dev == NULL && dn_hdr->bType != WUSB_DN_CONNECT) { -		dev_dbg(dev, "ignoring DN %d from unconnected device %02x\n", -			dn_hdr->bType, srcaddr); -		return; -	} -  	switch (dn_hdr->bType) {  	case WUSB_DN_CONNECT:  		wusbhc_handle_dn_connect(wusbhc, dn_hdr, size);  		break;  	case WUSB_DN_ALIVE: -		wusbhc_handle_dn_alive(wusbhc, wusb_dev); +		wusbhc_handle_dn_alive(wusbhc, srcaddr);  		break;  	case WUSB_DN_DISCONNECT: -		wusbhc_handle_dn_disconnect(wusbhc, wusb_dev); +		wusbhc_handle_dn_disconnect(wusbhc, srcaddr);  		break;  	case WUSB_DN_MASAVAILCHANGED:  	case WUSB_DN_RWAKE: @@ -973,7 +953,7 @@ int wusb_usb_ncb(struct notifier_block *nb, unsigned long val,  	default:  		WARN_ON(1);  		result = NOTIFY_BAD; -	}; +	}  	return result;  } diff --git a/drivers/usb/wusbcore/mmc.c b/drivers/usb/wusbcore/mmc.c index b71760c8d3a..3f485df9622 100644 --- a/drivers/usb/wusbcore/mmc.c +++ b/drivers/usb/wusbcore/mmc.c @@ -206,13 +206,15 @@ int wusbhc_start(struct wusbhc *wusbhc)  	result = wusbhc_devconnect_start(wusbhc);  	if (result < 0) { -		dev_err(dev, "error enabling device connections: %d\n", result); +		dev_err(dev, "error enabling device connections: %d\n", +			result);  		goto error_devconnect_start;  	}  	result = wusbhc_sec_start(wusbhc);  	if (result < 0) { -		dev_err(dev, "error starting security in the HC: %d\n", result); +		dev_err(dev, "error starting security in the HC: %d\n", +			result);  		goto error_sec_start;  	} @@ -284,7 +286,8 @@ int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)  		wusbhc->uwb_rc = uwb_rc_get_by_grandpa(wusbhc->dev->parent);  		if (wusbhc->uwb_rc == NULL) {  			result = -ENODEV; -			dev_err(wusbhc->dev, "Cannot get associated UWB Host Controller\n"); +			dev_err(wusbhc->dev, +				"Cannot get associated UWB Host Controller\n");  			goto error_rc_get;  		} @@ -298,7 +301,7 @@ int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)  	if (chid)  		result = uwb_radio_start(&wusbhc->pal); -	else +	else if (wusbhc->uwb_rc)  		uwb_radio_stop(&wusbhc->pal);  	return result; diff --git a/drivers/usb/wusbcore/pal.c b/drivers/usb/wusbcore/pal.c index 59e100c2eb5..090f27371a8 100644 --- a/drivers/usb/wusbcore/pal.c +++ b/drivers/usb/wusbcore/pal.c @@ -22,6 +22,7 @@ static void wusbhc_channel_changed(struct uwb_pal *pal, int channel)  {  	struct wusbhc *wusbhc = container_of(pal, struct wusbhc, pal); +	dev_dbg(wusbhc->dev, "%s: channel = %d\n", __func__, channel);  	if (channel < 0)  		wusbhc_stop(wusbhc);  	else diff --git a/drivers/usb/wusbcore/reservation.c b/drivers/usb/wusbcore/reservation.c index ead79f79392..d5efd0f07d2 100644 --- a/drivers/usb/wusbcore/reservation.c +++ b/drivers/usb/wusbcore/reservation.c @@ -51,6 +51,7 @@ static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv)  	struct uwb_mas_bm mas;  	char buf[72]; +	dev_dbg(dev, "%s: state = %d\n", __func__, rsv->state);  	switch (rsv->state) {  	case UWB_RSV_STATE_O_ESTABLISHED:  		uwb_rsv_get_usable_mas(rsv, &mas); diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c index dd88441c8f7..95be9953cd4 100644 --- a/drivers/usb/wusbcore/security.c +++ b/drivers/usb/wusbcore/security.c @@ -29,19 +29,17 @@  #include <linux/export.h>  #include "wusbhc.h" -static void wusbhc_set_gtk_callback(struct urb *urb); -static void wusbhc_gtk_rekey_done_work(struct work_struct *work); +static void wusbhc_gtk_rekey_work(struct work_struct *work);  int wusbhc_sec_create(struct wusbhc *wusbhc)  { -	wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) + sizeof(wusbhc->gtk.data); +	wusbhc->gtk.descr.bLength = sizeof(wusbhc->gtk.descr) + +		sizeof(wusbhc->gtk.data);  	wusbhc->gtk.descr.bDescriptorType = USB_DT_KEY;  	wusbhc->gtk.descr.bReserved = 0; +	wusbhc->gtk_index = 0; -	wusbhc->gtk_index = wusb_key_index(0, WUSB_KEY_INDEX_TYPE_GTK, -					   WUSB_KEY_INDEX_ORIGINATOR_HOST); - -	INIT_WORK(&wusbhc->gtk_rekey_done_work, wusbhc_gtk_rekey_done_work); +	INIT_WORK(&wusbhc->gtk_rekey_work, wusbhc_gtk_rekey_work);  	return 0;  } @@ -59,7 +57,7 @@ void wusbhc_sec_destroy(struct wusbhc *wusbhc)   * @wusb_dev: the device whose PTK the TKID is for   *            (or NULL for a TKID for a GTK)   * - * The generated TKID consist of two parts: the device's authenicated + * The generated TKID consists of two parts: the device's authenticated   * address (or 0 or a GTK); and an incrementing number.  This ensures   * that TKIDs cannot be shared between devices and by the time the   * incrementing number wraps around the older TKIDs will no longer be @@ -113,7 +111,7 @@ int wusbhc_sec_start(struct wusbhc *wusbhc)  	wusbhc_generate_gtk(wusbhc);  	result = wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, -				 &wusbhc->gtk.descr.bKeyData, key_size); +				&wusbhc->gtk.descr.bKeyData, key_size);  	if (result < 0)  		dev_err(wusbhc->dev, "cannot set GTK for the host: %d\n",  			result); @@ -129,7 +127,7 @@ int wusbhc_sec_start(struct wusbhc *wusbhc)   */  void wusbhc_sec_stop(struct wusbhc *wusbhc)  { -	cancel_work_sync(&wusbhc->gtk_rekey_done_work); +	cancel_work_sync(&wusbhc->gtk_rekey_work);  } @@ -141,7 +139,7 @@ const char *wusb_et_name(u8 x)  	case USB_ENC_TYPE_WIRED:	return "wired";  	case USB_ENC_TYPE_CCM_1:	return "CCM-1";  	case USB_ENC_TYPE_RSA_1:	return "RSA-1"; -	default: 			return "unknown"; +	default:			return "unknown";  	}  }  EXPORT_SYMBOL_GPL(wusb_et_name); @@ -168,7 +166,7 @@ static int wusb_dev_set_encryption(struct usb_device *usb_dev, int value)  	result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),  			USB_REQ_SET_ENCRYPTION,  			USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, -			value, 0, NULL, 0, 1000 /* FIXME: arbitrary */); +			value, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);  	if (result < 0)  		dev_err(dev, "Can't set device's WUSB encryption to "  			"%s (value %d): %d\n", @@ -185,14 +183,16 @@ static int wusb_dev_set_encryption(struct usb_device *usb_dev, int value)  static int wusb_dev_set_gtk(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)  {  	struct usb_device *usb_dev = wusb_dev->usb_dev; +	u8 key_index = wusb_key_index(wusbhc->gtk_index, +		WUSB_KEY_INDEX_TYPE_GTK, WUSB_KEY_INDEX_ORIGINATOR_HOST);  	return usb_control_msg(  		usb_dev, usb_sndctrlpipe(usb_dev, 0),  		USB_REQ_SET_DESCRIPTOR,  		USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, -		USB_DT_KEY << 8 | wusbhc->gtk_index, 0, +		USB_DT_KEY << 8 | key_index, 0,  		&wusbhc->gtk.descr, wusbhc->gtk.descr.bLength, -		1000); +		USB_CTRL_SET_TIMEOUT);  } @@ -223,7 +223,8 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc,  	secd_size = le16_to_cpu(secd->wTotalLength);  	new_secd = krealloc(secd, secd_size, GFP_KERNEL);  	if (new_secd == NULL) { -		dev_err(dev, "Can't allocate space for security descriptors\n"); +		dev_err(dev, +			"Can't allocate space for security descriptors\n");  		goto out;  	}  	secd = new_secd; @@ -302,8 +303,9 @@ int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)  	/* Set address 0 */  	result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), -				 USB_REQ_SET_ADDRESS, 0, -				 0, 0, NULL, 0, 1000 /* FIXME: arbitrary */); +			USB_REQ_SET_ADDRESS, +			USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, +			 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);  	if (result < 0) {  		dev_err(dev, "auth failed: can't set address 0: %d\n",  			result); @@ -317,9 +319,10 @@ int wusb_dev_update_address(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)  	/* Set new (authenticated) address. */  	result = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), -				 USB_REQ_SET_ADDRESS, 0, -				 new_address, 0, NULL, 0, -				 1000 /* FIXME: arbitrary */); +			USB_REQ_SET_ADDRESS, +			USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, +			new_address, 0, NULL, 0, +			USB_CTRL_SET_TIMEOUT);  	if (result < 0) {  		dev_err(dev, "auth failed: can't set address %u: %d\n",  			new_address, result); @@ -376,13 +379,13 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,  	hs[0].bReserved = 0;  	memcpy(hs[0].CDID, &wusb_dev->cdid, sizeof(hs[0].CDID));  	get_random_bytes(&hs[0].nonce, sizeof(hs[0].nonce)); -	memset(hs[0].MIC, 0, sizeof(hs[0].MIC));	/* Per WUSB1.0[T7-22] */ +	memset(hs[0].MIC, 0, sizeof(hs[0].MIC)); /* Per WUSB1.0[T7-22] */  	result = usb_control_msg(  		usb_dev, usb_sndctrlpipe(usb_dev, 0),  		USB_REQ_SET_HANDSHAKE,  		USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, -		1, 0, &hs[0], sizeof(hs[0]), 1000 /* FIXME: arbitrary */); +		1, 0, &hs[0], sizeof(hs[0]), USB_CTRL_SET_TIMEOUT);  	if (result < 0) {  		dev_err(dev, "Handshake1: request failed: %d\n", result);  		goto error_hs1; @@ -393,7 +396,7 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,  		usb_dev, usb_rcvctrlpipe(usb_dev, 0),  		USB_REQ_GET_HANDSHAKE,  		USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, -		2, 0, &hs[1], sizeof(hs[1]), 1000 /* FIXME: arbitrary */); +		2, 0, &hs[1], sizeof(hs[1]), USB_CTRL_GET_TIMEOUT);  	if (result < 0) {  		dev_err(dev, "Handshake2: request failed: %d\n", result);  		goto error_hs2; @@ -423,7 +426,7 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,  	}  	/* Setup the CCM nonce */ -	memset(&ccm_n.sfn, 0, sizeof(ccm_n.sfn));	/* Per WUSB1.0[6.5.2] */ +	memset(&ccm_n.sfn, 0, sizeof(ccm_n.sfn)); /* Per WUSB1.0[6.5.2] */  	memcpy(ccm_n.tkid, &tkid_le, sizeof(ccm_n.tkid));  	ccm_n.src_addr = wusbhc->uwb_rc->uwb_dev.dev_addr;  	ccm_n.dest_addr.data[0] = wusb_dev->addr; @@ -470,7 +473,7 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,  		usb_dev, usb_sndctrlpipe(usb_dev, 0),  		USB_REQ_SET_HANDSHAKE,  		USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE, -		3, 0, &hs[2], sizeof(hs[2]), 1000 /* FIXME: arbitrary */); +		3, 0, &hs[2], sizeof(hs[2]), USB_CTRL_SET_TIMEOUT);  	if (result < 0) {  		dev_err(dev, "Handshake3: request failed: %d\n", result);  		goto error_hs3; @@ -520,24 +523,57 @@ error_kzalloc:   * Once all connected and authenticated devices have received the new   * GTK, switch the host to using it.   */ -static void wusbhc_gtk_rekey_done_work(struct work_struct *work) +static void wusbhc_gtk_rekey_work(struct work_struct *work)  { -	struct wusbhc *wusbhc = container_of(work, struct wusbhc, gtk_rekey_done_work); +	struct wusbhc *wusbhc = container_of(work, +					struct wusbhc, gtk_rekey_work);  	size_t key_size = sizeof(wusbhc->gtk.data); +	int port_idx; +	struct wusb_dev *wusb_dev, *wusb_dev_next; +	LIST_HEAD(rekey_list);  	mutex_lock(&wusbhc->mutex); +	/* generate the new key */ +	wusbhc_generate_gtk(wusbhc); +	/* roll the gtk index. */ +	wusbhc->gtk_index = (wusbhc->gtk_index + 1) % (WUSB_KEY_INDEX_MAX + 1); +	/* +	 * Save all connected devices on a list while holding wusbhc->mutex and +	 * take a reference to each one.  Then submit the set key request to +	 * them after releasing the lock in order to avoid a deadlock. +	 */ +	for (port_idx = 0; port_idx < wusbhc->ports_max; port_idx++) { +		wusb_dev = wusbhc->port[port_idx].wusb_dev; +		if (!wusb_dev || !wusb_dev->usb_dev +			|| !wusb_dev->usb_dev->authenticated) +			continue; -	if (--wusbhc->pending_set_gtks == 0) -		wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size); - +		wusb_dev_get(wusb_dev); +		list_add_tail(&wusb_dev->rekey_node, &rekey_list); +	}  	mutex_unlock(&wusbhc->mutex); -} -static void wusbhc_set_gtk_callback(struct urb *urb) -{ -	struct wusbhc *wusbhc = urb->context; +	/* Submit the rekey requests without holding wusbhc->mutex. */ +	list_for_each_entry_safe(wusb_dev, wusb_dev_next, &rekey_list, +		rekey_node) { +		list_del_init(&wusb_dev->rekey_node); +		dev_dbg(&wusb_dev->usb_dev->dev, +			"%s: rekey device at port %d\n", +			__func__, wusb_dev->port_idx); + +		if (wusb_dev_set_gtk(wusbhc, wusb_dev) < 0) { +			dev_err(&wusb_dev->usb_dev->dev, +				"%s: rekey device at port %d failed\n", +				__func__, wusb_dev->port_idx); +		} +		wusb_dev_put(wusb_dev); +	} -	queue_work(wusbd, &wusbhc->gtk_rekey_done_work); +	/* Switch the host controller to use the new GTK. */ +	mutex_lock(&wusbhc->mutex); +	wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, +		&wusbhc->gtk.descr.bKeyData, key_size); +	mutex_unlock(&wusbhc->mutex);  }  /** @@ -553,26 +589,12 @@ static void wusbhc_set_gtk_callback(struct urb *urb)   */  void wusbhc_gtk_rekey(struct wusbhc *wusbhc)  { -	static const size_t key_size = sizeof(wusbhc->gtk.data); -	int p; - -	wusbhc_generate_gtk(wusbhc); - -	for (p = 0; p < wusbhc->ports_max; p++) { -		struct wusb_dev *wusb_dev; - -		wusb_dev = wusbhc->port[p].wusb_dev; -		if (!wusb_dev || !wusb_dev->usb_dev || !wusb_dev->usb_dev->authenticated) -			continue; - -		usb_fill_control_urb(wusb_dev->set_gtk_urb, wusb_dev->usb_dev, -				     usb_sndctrlpipe(wusb_dev->usb_dev, 0), -				     (void *)wusb_dev->set_gtk_req, -				     &wusbhc->gtk.descr, wusbhc->gtk.descr.bLength, -				     wusbhc_set_gtk_callback, wusbhc); -		if (usb_submit_urb(wusb_dev->set_gtk_urb, GFP_KERNEL) == 0) -			wusbhc->pending_set_gtks++; -	} -	if (wusbhc->pending_set_gtks == 0) -		wusbhc->set_gtk(wusbhc, wusbhc->gtk_tkid, &wusbhc->gtk.descr.bKeyData, key_size); +	/* +	 * We need to submit a URB to the downstream WUSB devices in order to +	 * change the group key.  This can't be done while holding the +	 * wusbhc->mutex since that is also taken in the urb_enqueue routine +	 * and will cause a deadlock.  Instead, queue a work item to do +	 * it when the lock is not held +	 */ +	queue_work(wusbd, &wusbhc->gtk_rekey_work);  } diff --git a/drivers/usb/wusbcore/wa-hc.c b/drivers/usb/wusbcore/wa-hc.c index a09b65ebd9b..252c7bd9218 100644 --- a/drivers/usb/wusbcore/wa-hc.c +++ b/drivers/usb/wusbcore/wa-hc.c @@ -33,7 +33,8 @@   * wa->usb_dev and wa->usb_iface initialized and refcounted,   * wa->wa_descr initialized.   */ -int wa_create(struct wahc *wa, struct usb_interface *iface) +int wa_create(struct wahc *wa, struct usb_interface *iface, +	kernel_ulong_t quirks)  {  	int result;  	struct device *dev = &iface->dev; @@ -41,14 +42,15 @@ int wa_create(struct wahc *wa, struct usb_interface *iface)  	result = wa_rpipes_create(wa);  	if (result < 0)  		goto error_rpipes_create; +	wa->quirks = quirks;  	/* Fill up Data Transfer EP pointers */  	wa->dti_epd = &iface->cur_altsetting->endpoint[1].desc;  	wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc; -	wa->xfer_result_size = usb_endpoint_maxp(wa->dti_epd); -	wa->xfer_result = kmalloc(wa->xfer_result_size, GFP_KERNEL); -	if (wa->xfer_result == NULL) { +	wa->dti_buf_size = usb_endpoint_maxp(wa->dti_epd); +	wa->dti_buf = kmalloc(wa->dti_buf_size, GFP_KERNEL); +	if (wa->dti_buf == NULL) {  		result = -ENOMEM; -		goto error_xfer_result_alloc; +		goto error_dti_buf_alloc;  	}  	result = wa_nep_create(wa, iface);  	if (result < 0) { @@ -59,8 +61,8 @@ int wa_create(struct wahc *wa, struct usb_interface *iface)  	return 0;  error_nep_create: -	kfree(wa->xfer_result); -error_xfer_result_alloc: +	kfree(wa->dti_buf); +error_dti_buf_alloc:  	wa_rpipes_destroy(wa);  error_rpipes_create:  	return result; @@ -73,10 +75,8 @@ void __wa_destroy(struct wahc *wa)  	if (wa->dti_urb) {  		usb_kill_urb(wa->dti_urb);  		usb_put_urb(wa->dti_urb); -		usb_kill_urb(wa->buf_in_urb); -		usb_put_urb(wa->buf_in_urb);  	} -	kfree(wa->xfer_result); +	kfree(wa->dti_buf);  	wa_nep_destroy(wa);  	wa_rpipes_destroy(wa);  } diff --git a/drivers/usb/wusbcore/wa-hc.h b/drivers/usb/wusbcore/wa-hc.h index cf250c21e94..f2a8d29e17b 100644 --- a/drivers/usb/wusbcore/wa-hc.h +++ b/drivers/usb/wusbcore/wa-hc.h @@ -36,7 +36,7 @@   *   *  hcd        glue with the USB API Host Controller Interface API.   * - *  nep        Notification EndPoint managent: collect notifications + *  nep        Notification EndPoint management: collect notifications   *             and queue them with the workqueue daemon.   *   *             Handle notifications as coming from the NEP. Sends them @@ -117,11 +117,38 @@ struct wa_rpipe {  	struct wahc *wa;  	spinlock_t seg_lock;  	struct list_head seg_list; +	struct list_head list_node;  	atomic_t segs_available;  	u8 buffer[1];	/* For reads/writes on USB */  }; +enum wa_dti_state { +	WA_DTI_TRANSFER_RESULT_PENDING, +	WA_DTI_ISOC_PACKET_STATUS_PENDING, +	WA_DTI_BUF_IN_DATA_PENDING +}; + +enum wa_quirks { +	/* +	 * The Alereon HWA expects the data frames in isochronous transfer +	 * requests to be concatenated and not sent as separate packets. +	 */ +	WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC	= 0x01, +	/* +	 * The Alereon HWA can be instructed to not send transfer notifications +	 * as an optimization. +	 */ +	WUSB_QUIRK_ALEREON_HWA_DISABLE_XFER_NOTIFICATIONS	= 0x02, +}; + +enum wa_vendor_specific_requests { +	WA_REQ_ALEREON_DISABLE_XFER_NOTIFICATIONS = 0x4C, +	WA_REQ_ALEREON_FEATURE_SET = 0x01, +	WA_REQ_ALEREON_FEATURE_CLEAR = 0x00, +}; + +#define WA_MAX_BUF_IN_URBS	4  /**   * Instance of a HWA Host Controller   * @@ -130,7 +157,7 @@ struct wa_rpipe {   *   * @wa_descr  Can be accessed without locking because it is in   *            the same area where the device descriptors were - *            read, so it is guaranteed to exist umodified while + *            read, so it is guaranteed to exist unmodified while   *            the device exists.   *   *            Endianess has been converted to CPU's. @@ -153,8 +180,8 @@ struct wa_rpipe {   *                       submitted from an atomic context).   *   * FIXME: this needs to be layered up: a wusbhc layer (for sharing - *        comonalities with WHCI), a wa layer (for sharing - *        comonalities with DWA-RC). + *        commonalities with WHCI), a wa layer (for sharing + *        commonalities with DWA-RC).   */  struct wahc {  	struct usb_device *usb_dev; @@ -178,14 +205,28 @@ struct wahc {  	u16 rpipes;  	unsigned long *rpipe_bm;	/* rpipe usage bitmap */ -	spinlock_t rpipe_bm_lock;	/* protect rpipe_bm */ +	struct list_head rpipe_delayed_list;	/* delayed RPIPES. */ +	spinlock_t rpipe_lock;	/* protect rpipe_bm and delayed list */  	struct mutex rpipe_mutex;	/* assigning resources to endpoints */ +	/* +	 * dti_state is used to track the state of the dti_urb. When dti_state +	 * is WA_DTI_ISOC_PACKET_STATUS_PENDING, dti_isoc_xfer_in_progress and +	 * dti_isoc_xfer_seg identify which xfer the incoming isoc packet +	 * status refers to. +	 */ +	enum wa_dti_state dti_state; +	u32 dti_isoc_xfer_in_progress; +	u8  dti_isoc_xfer_seg;  	struct urb *dti_urb;		/* URB for reading xfer results */ -	struct urb *buf_in_urb;		/* URB for reading data in */ +					/* URBs for reading data in */ +	struct urb buf_in_urbs[WA_MAX_BUF_IN_URBS]; +	int active_buf_in_urbs;		/* number of buf_in_urbs active. */  	struct edc dti_edc;		/* DTI error density counter */ -	struct wa_xfer_result *xfer_result; /* real size = dti_ep maxpktsize */ -	size_t xfer_result_size; +	void *dti_buf; +	size_t dti_buf_size; + +	unsigned long dto_in_use;	/* protect dto endoint serialization */  	s32 status;			/* For reading status */ @@ -200,11 +241,15 @@ struct wahc {  	struct work_struct xfer_enqueue_work;  	struct work_struct xfer_error_work;  	atomic_t xfer_id_count; + +	kernel_ulong_t	quirks;  }; -extern int wa_create(struct wahc *wa, struct usb_interface *iface); +extern int wa_create(struct wahc *wa, struct usb_interface *iface, +	kernel_ulong_t);  extern void __wa_destroy(struct wahc *wa); +extern int wa_dti_start(struct wahc *wa);  void wa_reset_all(struct wahc *wa); @@ -239,14 +284,18 @@ static inline void wa_nep_disarm(struct wahc *wa)  /* RPipes */  static inline void wa_rpipe_init(struct wahc *wa)  { -	spin_lock_init(&wa->rpipe_bm_lock); +	INIT_LIST_HEAD(&wa->rpipe_delayed_list); +	spin_lock_init(&wa->rpipe_lock);  	mutex_init(&wa->rpipe_mutex);  }  static inline void wa_init(struct wahc *wa)  { +	int index; +  	edc_init(&wa->nep_edc);  	atomic_set(&wa->notifs_queued, 0); +	wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING;  	wa_rpipe_init(wa);  	edc_init(&wa->dti_edc);  	INIT_LIST_HEAD(&wa->xfer_list); @@ -255,7 +304,12 @@ static inline void wa_init(struct wahc *wa)  	spin_lock_init(&wa->xfer_list_lock);  	INIT_WORK(&wa->xfer_enqueue_work, wa_urb_enqueue_run);  	INIT_WORK(&wa->xfer_error_work, wa_process_errored_transfers_run); +	wa->dto_in_use = 0;  	atomic_set(&wa->xfer_id_count, 1); +	/* init the buf in URBs */ +	for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index) +		usb_init_urb(&(wa->buf_in_urbs[index])); +	wa->active_buf_in_urbs = 0;  }  /** @@ -300,7 +354,7 @@ static inline int rpipe_avail_inc(struct wa_rpipe *rpipe)  /* Transferring data */  extern int wa_urb_enqueue(struct wahc *, struct usb_host_endpoint *,  			  struct urb *, gfp_t); -extern int wa_urb_dequeue(struct wahc *, struct urb *); +extern int wa_urb_dequeue(struct wahc *, struct urb *, int);  extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *); @@ -313,7 +367,7 @@ extern void wa_handle_notif_xfer(struct wahc *, struct wa_notif_hdr *);   *        it...no RC specific function is called...unless I miss   *        something.   * - * FIXME: has to go away in favour of an 'struct' hcd based sollution + * FIXME: has to go away in favour of a 'struct' hcd based solution   */  static inline struct wahc *wa_get(struct wahc *wa)  { @@ -334,7 +388,7 @@ static inline int __wa_feature(struct wahc *wa, unsigned op, u16 feature)  			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  			feature,  			wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, -			NULL, 0, 1000 /* FIXME: arbitrary */); +			NULL, 0, USB_CTRL_SET_TIMEOUT);  } @@ -368,8 +422,7 @@ s32 __wa_get_status(struct wahc *wa)  		USB_REQ_GET_STATUS,  		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,  		0, wa->usb_iface->cur_altsetting->desc.bInterfaceNumber, -		&wa->status, sizeof(wa->status), -		1000 /* FIXME: arbitrary */); +		&wa->status, sizeof(wa->status), USB_CTRL_GET_TIMEOUT);  	if (result >= 0)  		result = wa->status;  	return result; diff --git a/drivers/usb/wusbcore/wa-nep.c b/drivers/usb/wusbcore/wa-nep.c index ada4e087062..60a10d21947 100644 --- a/drivers/usb/wusbcore/wa-nep.c +++ b/drivers/usb/wusbcore/wa-nep.c @@ -69,8 +69,8 @@ struct wa_notif_work {   * [the wuswad daemon, basically]   *   * @_nw:	Pointer to a descriptor which has the pointer to the - * 		@wa, the size of the buffer and the work queue - * 		structure (so we can free all when done). + *		@wa, the size of the buffer and the work queue + *		structure (so we can free all when done).   * @returns     0 if ok, < 0 errno code on error.   *   * All notifications follow the same format; they need to start with a @@ -93,7 +93,8 @@ static void wa_notif_dispatch(struct work_struct *ws)  {  	void *itr;  	u8 missing = 0; -	struct wa_notif_work *nw = container_of(ws, struct wa_notif_work, work); +	struct wa_notif_work *nw = container_of(ws, struct wa_notif_work, +						work);  	struct wahc *wa = nw->wa;  	struct wa_notif_hdr *notif_hdr;  	size_t size; @@ -271,7 +272,8 @@ int wa_nep_create(struct wahc *wa, struct usb_interface *iface)  	wa->nep_buffer_size = 1024;  	wa->nep_buffer = kmalloc(wa->nep_buffer_size, GFP_KERNEL);  	if (wa->nep_buffer == NULL) { -		dev_err(dev, "Unable to allocate notification's read buffer\n"); +		dev_err(dev, +			"Unable to allocate notification's read buffer\n");  		goto error_nep_buffer;  	}  	wa->nep_urb = usb_alloc_urb(0, GFP_KERNEL); diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c index fd4f1ce6256..a80c5d284b5 100644 --- a/drivers/usb/wusbcore/wa-rpipe.c +++ b/drivers/usb/wusbcore/wa-rpipe.c @@ -57,7 +57,6 @@   *  urb->dev->devnum, to make sure that we always have the right   *  destination address.   */ -#include <linux/init.h>  #include <linux/atomic.h>  #include <linux/bitmap.h>  #include <linux/slab.h> @@ -80,7 +79,7 @@ static int __rpipe_get_descr(struct wahc *wa,  		USB_REQ_GET_DESCRIPTOR,  		USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_RPIPE,  		USB_DT_RPIPE<<8, index, descr, sizeof(*descr), -		1000 /* FIXME: arbitrary */); +		USB_CTRL_GET_TIMEOUT);  	if (result < 0) {  		dev_err(dev, "rpipe %u: get descriptor failed: %d\n",  			index, (int)result); @@ -118,7 +117,7 @@ static int __rpipe_set_descr(struct wahc *wa,  		USB_REQ_SET_DESCRIPTOR,  		USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE,  		USB_DT_RPIPE<<8, index, descr, sizeof(*descr), -		HZ / 10); +		USB_CTRL_SET_TIMEOUT);  	if (result < 0) {  		dev_err(dev, "rpipe %u: set descriptor failed: %d\n",  			index, (int)result); @@ -143,17 +142,18 @@ static void rpipe_init(struct wa_rpipe *rpipe)  	kref_init(&rpipe->refcnt);  	spin_lock_init(&rpipe->seg_lock);  	INIT_LIST_HEAD(&rpipe->seg_list); +	INIT_LIST_HEAD(&rpipe->list_node);  }  static unsigned rpipe_get_idx(struct wahc *wa, unsigned rpipe_idx)  {  	unsigned long flags; -	spin_lock_irqsave(&wa->rpipe_bm_lock, flags); +	spin_lock_irqsave(&wa->rpipe_lock, flags);  	rpipe_idx = find_next_zero_bit(wa->rpipe_bm, wa->rpipes, rpipe_idx);  	if (rpipe_idx < wa->rpipes)  		set_bit(rpipe_idx, wa->rpipe_bm); -	spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags); +	spin_unlock_irqrestore(&wa->rpipe_lock, flags);  	return rpipe_idx;  } @@ -162,9 +162,9 @@ static void rpipe_put_idx(struct wahc *wa, unsigned rpipe_idx)  {  	unsigned long flags; -	spin_lock_irqsave(&wa->rpipe_bm_lock, flags); +	spin_lock_irqsave(&wa->rpipe_lock, flags);  	clear_bit(rpipe_idx, wa->rpipe_bm); -	spin_unlock_irqrestore(&wa->rpipe_bm_lock, flags); +	spin_unlock_irqrestore(&wa->rpipe_lock, flags);  }  void rpipe_destroy(struct kref *_rpipe) @@ -183,7 +183,7 @@ EXPORT_SYMBOL_GPL(rpipe_destroy);  /*   * Locate an idle rpipe, create an structure for it and return it   * - * @wa 	  is referenced and unlocked + * @wa	  is referenced and unlocked   * @crs   enum rpipe_attr, required endpoint characteristics   *   * The rpipe can be used only sequentially (not in parallel). @@ -236,7 +236,7 @@ static int __rpipe_reset(struct wahc *wa, unsigned index)  		wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),  		USB_REQ_RPIPE_RESET,  		USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, -		0, index, NULL, 0, 1000 /* FIXME: arbitrary */); +		0, index, NULL, 0, USB_CTRL_SET_TIMEOUT);  	if (result < 0)  		dev_err(dev, "rpipe %u: reset failed: %d\n",  			index, result); @@ -298,7 +298,7 @@ static struct usb_wireless_ep_comp_descriptor *rpipe_epc_find(  			break;  		}  		itr += hdr->bLength; -		itr_size -= hdr->bDescriptorType; +		itr_size -= hdr->bLength;  	}  out:  	return epcd; @@ -307,7 +307,7 @@ out:  /*   * Aim an rpipe to its device & endpoint destination   * - * Make sure we change the address to unauthenticathed if the device + * Make sure we change the address to unauthenticated if the device   * is WUSB and it is not authenticated.   */  static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa, @@ -328,12 +328,16 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa,  	}  	unauth = usb_dev->wusb && !usb_dev->authenticated ? 0x80 : 0;  	__rpipe_reset(wa, le16_to_cpu(rpipe->descr.wRPipeIndex)); -	atomic_set(&rpipe->segs_available, le16_to_cpu(rpipe->descr.wRequests)); +	atomic_set(&rpipe->segs_available, +		le16_to_cpu(rpipe->descr.wRequests));  	/* FIXME: block allocation system; request with queuing and timeout */  	/* FIXME: compute so seg_size > ep->maxpktsize */  	rpipe->descr.wBlocks = cpu_to_le16(16);		/* given */  	/* ep0 maxpktsize is 0x200 (WUSB1.0[4.8.1]) */ -	rpipe->descr.wMaxPacketSize = cpu_to_le16(ep->desc.wMaxPacketSize); +	if (usb_endpoint_xfer_isoc(&ep->desc)) +		rpipe->descr.wMaxPacketSize = epcd->wOverTheAirPacketSize; +	else +		rpipe->descr.wMaxPacketSize = ep->desc.wMaxPacketSize;  	rpipe->descr.hwa_bMaxBurst = max(min_t(unsigned int,  				epcd->bMaxBurst, 16U), 1U); @@ -361,8 +365,10 @@ static int rpipe_aim(struct wa_rpipe *rpipe, struct wahc *wa,  			epcd->bMaxSequence, 32U), 2U);  	rpipe->descr.bMaxDataSequence = epcd_max_sequence - 1;  	rpipe->descr.bInterval = ep->desc.bInterval; -	/* FIXME: bOverTheAirInterval */ -	rpipe->descr.bOverTheAirInterval = 0;	/* 0 if not isoc */ +	if (usb_endpoint_xfer_isoc(&ep->desc)) +		rpipe->descr.bOverTheAirInterval = epcd->bOverTheAirInterval; +	else +		rpipe->descr.bOverTheAirInterval = 0;	/* 0 if not isoc */  	/* FIXME: xmit power & preamble blah blah */  	rpipe->descr.bmAttribute = (ep->desc.bmAttributes &  					USB_ENDPOINT_XFERTYPE_MASK); @@ -477,7 +483,7 @@ error:   */  int wa_rpipes_create(struct wahc *wa)  { -	wa->rpipes = wa->wa_descr->wNumRPipes; +	wa->rpipes = le16_to_cpu(wa->wa_descr->wNumRPipes);  	wa->rpipe_bm = kzalloc(BITS_TO_LONGS(wa->rpipes)*sizeof(unsigned long),  			       GFP_KERNEL);  	if (wa->rpipe_bm == NULL) @@ -518,10 +524,10 @@ void rpipe_ep_disable(struct wahc *wa, struct usb_host_endpoint *ep)  		u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);  		usb_control_msg( -			wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), +			wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),  			USB_REQ_RPIPE_ABORT,  			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, -			0, index, NULL, 0, 1000 /* FIXME: arbitrary */); +			0, index, NULL, 0, USB_CTRL_SET_TIMEOUT);  		rpipe_put(rpipe);  	}  	mutex_unlock(&wa->rpipe_mutex); @@ -539,12 +545,11 @@ void rpipe_clear_feature_stalled(struct wahc *wa, struct usb_host_endpoint *ep)  		u16 index = le16_to_cpu(rpipe->descr.wRPipeIndex);  		usb_control_msg( -			wa->usb_dev, usb_rcvctrlpipe(wa->usb_dev, 0), +			wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0),  			USB_REQ_CLEAR_FEATURE,  			USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_RPIPE, -			RPIPE_STALL, index, NULL, 0, 1000); +			RPIPE_STALL, index, NULL, 0, USB_CTRL_SET_TIMEOUT);  	}  	mutex_unlock(&wa->rpipe_mutex);  }  EXPORT_SYMBOL_GPL(rpipe_clear_feature_stalled); - diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index 6ad02f57c36..3e2e4ed2015 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -79,7 +79,6 @@   *     availability of the different required components (blocks,   *     rpipes, segment slots, etc), we go scheduling them. Painful.   */ -#include <linux/init.h>  #include <linux/spinlock.h>  #include <linux/slab.h>  #include <linux/hash.h> @@ -91,7 +90,8 @@  #include "wusbhc.h"  enum { -	WA_SEGS_MAX = 255, +	/* [WUSB] section 8.3.3 allocates 7 bits for the segment index. */ +	WA_SEGS_MAX = 128,  };  enum wa_seg_status { @@ -107,6 +107,7 @@ enum wa_seg_status {  };  static void wa_xfer_delayed_run(struct wa_rpipe *); +static int __wa_xfer_delayed_run(struct wa_rpipe *rpipe, int *dto_waiting);  /*   * Life cycle governed by 'struct urb' (the refcount of the struct is @@ -114,24 +115,29 @@ static void wa_xfer_delayed_run(struct wa_rpipe *);   * struct).   */  struct wa_seg { -	struct urb urb; -	struct urb *dto_urb;		/* for data output? */ +	struct urb tr_urb;		/* transfer request urb. */ +	struct urb *isoc_pack_desc_urb;	/* for isoc packet descriptor. */ +	struct urb *dto_urb;		/* for data output. */  	struct list_head list_node;	/* for rpipe->req_list */  	struct wa_xfer *xfer;		/* out xfer */  	u8 index;			/* which segment we are */ +	int isoc_frame_count;	/* number of isoc frames in this segment. */ +	int isoc_frame_offset;	/* starting frame offset in the xfer URB. */ +	/* Isoc frame that the current transfer buffer corresponds to. */ +	int isoc_frame_index; +	int isoc_size;	/* size of all isoc frames sent by this seg. */  	enum wa_seg_status status;  	ssize_t result;			/* bytes xfered or error */  	struct wa_xfer_hdr xfer_hdr; -	u8 xfer_extra[];		/* xtra space for xfer_hdr_ctl */  };  static inline void wa_seg_init(struct wa_seg *seg)  { -	usb_init_urb(&seg->urb); +	usb_init_urb(&seg->tr_urb);  	/* set the remaining memory to 0. */ -	memset(((void *)seg) + sizeof(seg->urb), 0, -		sizeof(*seg) - sizeof(seg->urb)); +	memset(((void *)seg) + sizeof(seg->tr_urb), 0, +		sizeof(*seg) - sizeof(seg->tr_urb));  }  /* @@ -159,6 +165,11 @@ struct wa_xfer {  	struct wusb_dev *wusb_dev;	/* for activity timestamps */  }; +static void __wa_populate_dto_urb_isoc(struct wa_xfer *xfer, +	struct wa_seg *seg, int curr_iso_frame); +static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer, +		int starting_index, enum wa_seg_status status); +  static inline void wa_xfer_init(struct wa_xfer *xfer)  {  	kref_init(&xfer->refcnt); @@ -169,7 +180,7 @@ static inline void wa_xfer_init(struct wa_xfer *xfer)  /*   * Destroy a transfer structure   * - * Note that freeing xfer->seg[cnt]->urb will free the containing + * Note that freeing xfer->seg[cnt]->tr_urb will free the containing   * xfer->seg[cnt] memory that was allocated by __wa_xfer_setup_segs.   */  static void wa_xfer_destroy(struct kref *_xfer) @@ -178,9 +189,17 @@ static void wa_xfer_destroy(struct kref *_xfer)  	if (xfer->seg) {  		unsigned cnt;  		for (cnt = 0; cnt < xfer->segs; cnt++) { -			usb_free_urb(xfer->seg[cnt]->dto_urb); -			usb_free_urb(&xfer->seg[cnt]->urb); +			struct wa_seg *seg = xfer->seg[cnt]; +			if (seg) { +				usb_free_urb(seg->isoc_pack_desc_urb); +				if (seg->dto_urb) { +					kfree(seg->dto_urb->sg); +					usb_free_urb(seg->dto_urb); +				} +				usb_free_urb(&seg->tr_urb); +			}  		} +		kfree(xfer->seg);  	}  	kfree(xfer);  } @@ -196,6 +215,59 @@ static void wa_xfer_put(struct wa_xfer *xfer)  }  /* + * Try to get exclusive access to the DTO endpoint resource.  Return true + * if successful. + */ +static inline int __wa_dto_try_get(struct wahc *wa) +{ +	return (test_and_set_bit(0, &wa->dto_in_use) == 0); +} + +/* Release the DTO endpoint resource. */ +static inline void __wa_dto_put(struct wahc *wa) +{ +	clear_bit_unlock(0, &wa->dto_in_use); +} + +/* Service RPIPEs that are waiting on the DTO resource. */ +static void wa_check_for_delayed_rpipes(struct wahc *wa) +{ +	unsigned long flags; +	int dto_waiting = 0; +	struct wa_rpipe *rpipe; + +	spin_lock_irqsave(&wa->rpipe_lock, flags); +	while (!list_empty(&wa->rpipe_delayed_list) && !dto_waiting) { +		rpipe = list_first_entry(&wa->rpipe_delayed_list, +				struct wa_rpipe, list_node); +		__wa_xfer_delayed_run(rpipe, &dto_waiting); +		/* remove this RPIPE from the list if it is not waiting. */ +		if (!dto_waiting) { +			pr_debug("%s: RPIPE %d serviced and removed from delayed list.\n", +				__func__, +				le16_to_cpu(rpipe->descr.wRPipeIndex)); +			list_del_init(&rpipe->list_node); +		} +	} +	spin_unlock_irqrestore(&wa->rpipe_lock, flags); +} + +/* add this RPIPE to the end of the delayed RPIPE list. */ +static void wa_add_delayed_rpipe(struct wahc *wa, struct wa_rpipe *rpipe) +{ +	unsigned long flags; + +	spin_lock_irqsave(&wa->rpipe_lock, flags); +	/* add rpipe to the list if it is not already on it. */ +	if (list_empty(&rpipe->list_node)) { +		pr_debug("%s: adding RPIPE %d to the delayed list.\n", +			__func__, le16_to_cpu(rpipe->descr.wRPipeIndex)); +		list_add_tail(&rpipe->list_node, &wa->rpipe_delayed_list); +	} +	spin_unlock_irqrestore(&wa->rpipe_lock, flags); +} + +/*   * xfer is referenced   *   * xfer->lock has to be unlocked @@ -211,6 +283,7 @@ static void wa_xfer_giveback(struct wa_xfer *xfer)  	spin_lock_irqsave(&xfer->wa->xfer_list_lock, flags);  	list_del_init(&xfer->list_node); +	usb_hcd_unlink_urb_from_ep(&(xfer->wa->wusb->usb_hcd), xfer->urb);  	spin_unlock_irqrestore(&xfer->wa->xfer_list_lock, flags);  	/* FIXME: segmentation broken -- kills DWA */  	wusbhc_giveback_urb(xfer->wa->wusb, xfer->urb, xfer->result); @@ -232,6 +305,31 @@ static void wa_xfer_completion(struct wa_xfer *xfer)  }  /* + * Initialize a transfer's ID + * + * We need to use a sequential number; if we use the pointer or the + * hash of the pointer, it can repeat over sequential transfers and + * then it will confuse the HWA....wonder why in hell they put a 32 + * bit handle in there then. + */ +static void wa_xfer_id_init(struct wa_xfer *xfer) +{ +	xfer->id = atomic_add_return(1, &xfer->wa->xfer_id_count); +} + +/* Return the xfer's ID. */ +static inline u32 wa_xfer_id(struct wa_xfer *xfer) +{ +	return xfer->id; +} + +/* Return the xfer's ID in transport format (little endian). */ +static inline __le32 wa_xfer_id_le32(struct wa_xfer *xfer) +{ +	return cpu_to_le32(xfer->id); +} + +/*   * If transfer is done, wrap it up and return true   *   * xfer->lock has to be locked @@ -253,33 +351,37 @@ static unsigned __wa_xfer_is_done(struct wa_xfer *xfer)  		switch (seg->status) {  		case WA_SEG_DONE:  			if (found_short && seg->result > 0) { -				dev_dbg(dev, "xfer %p#%u: bad short segments (%zu)\n", -					xfer, cnt, seg->result); +				dev_dbg(dev, "xfer %p ID %08X#%u: bad short segments (%zu)\n", +					xfer, wa_xfer_id(xfer), cnt, +					seg->result);  				urb->status = -EINVAL;  				goto out;  			}  			urb->actual_length += seg->result; -			if (seg->result < xfer->seg_size +			if (!(usb_pipeisoc(xfer->urb->pipe)) +				&& seg->result < xfer->seg_size  			    && cnt != xfer->segs-1)  				found_short = 1; -			dev_dbg(dev, "xfer %p#%u: DONE short %d " +			dev_dbg(dev, "xfer %p ID %08X#%u: DONE short %d "  				"result %zu urb->actual_length %d\n", -				xfer, seg->index, found_short, seg->result, -				urb->actual_length); +				xfer, wa_xfer_id(xfer), seg->index, found_short, +				seg->result, urb->actual_length);  			break;  		case WA_SEG_ERROR:  			xfer->result = seg->result; -			dev_dbg(dev, "xfer %p#%u: ERROR result %zu\n", -				xfer, seg->index, seg->result); +			dev_dbg(dev, "xfer %p ID %08X#%u: ERROR result %zi(0x%08zX)\n", +				xfer, wa_xfer_id(xfer), seg->index, seg->result, +				seg->result);  			goto out;  		case WA_SEG_ABORTED: -			dev_dbg(dev, "xfer %p#%u ABORTED: result %d\n", -				xfer, seg->index, urb->status); -			xfer->result = urb->status; +			xfer->result = seg->result; +			dev_dbg(dev, "xfer %p ID %08X#%u: ABORTED result %zi(0x%08zX)\n", +				xfer, wa_xfer_id(xfer), seg->index, seg->result, +				seg->result);  			goto out;  		default: -			dev_warn(dev, "xfer %p#%u: is_done bad state %d\n", -				 xfer, cnt, seg->status); +			dev_warn(dev, "xfer %p ID %08X#%u: is_done bad state %d\n", +				 xfer, wa_xfer_id(xfer), cnt, seg->status);  			xfer->result = -EINVAL;  			goto out;  		} @@ -290,26 +392,21 @@ out:  }  /* - * Initialize a transfer's ID + * Mark the given segment as done.  Return true if this completes the xfer. + * This should only be called for segs that have been submitted to an RPIPE. + * Delayed segs are not marked as submitted so they do not need to be marked + * as done when cleaning up.   * - * We need to use a sequential number; if we use the pointer or the - * hash of the pointer, it can repeat over sequential transfers and - * then it will confuse the HWA....wonder why in hell they put a 32 - * bit handle in there then. + * xfer->lock has to be locked   */ -static void wa_xfer_id_init(struct wa_xfer *xfer) +static unsigned __wa_xfer_mark_seg_as_done(struct wa_xfer *xfer, +	struct wa_seg *seg, enum wa_seg_status status)  { -	xfer->id = atomic_add_return(1, &xfer->wa->xfer_id_count); -} +	seg->status = status; +	xfer->segs_done++; -/* - * Return the xfer's ID associated with xfer - * - * Need to generate a - */ -static u32 wa_xfer_id(struct wa_xfer *xfer) -{ -	return xfer->id; +	/* check for done. */ +	return __wa_xfer_is_done(xfer);  }  /* @@ -339,12 +436,51 @@ out:  struct wa_xfer_abort_buffer {  	struct urb urb; +	struct wahc *wa;  	struct wa_xfer_abort cmd;  };  static void __wa_xfer_abort_cb(struct urb *urb)  {  	struct wa_xfer_abort_buffer *b = urb->context; +	struct wahc *wa = b->wa; + +	/* +	 * If the abort request URB failed, then the HWA did not get the abort +	 * command.  Forcibly clean up the xfer without waiting for a Transfer +	 * Result from the HWA. +	 */ +	if (urb->status < 0) { +		struct wa_xfer *xfer; +		struct device *dev = &wa->usb_iface->dev; + +		xfer = wa_xfer_get_by_id(wa, le32_to_cpu(b->cmd.dwTransferID)); +		dev_err(dev, "%s: Transfer Abort request failed. result: %d\n", +			__func__, urb->status); +		if (xfer) { +			unsigned long flags; +			int done; +			struct wa_rpipe *rpipe = xfer->ep->hcpriv; + +			dev_err(dev, "%s: cleaning up xfer %p ID 0x%08X.\n", +				__func__, xfer, wa_xfer_id(xfer)); +			spin_lock_irqsave(&xfer->lock, flags); +			/* mark all segs as aborted. */ +			wa_complete_remaining_xfer_segs(xfer, 0, +				WA_SEG_ABORTED); +			done = __wa_xfer_is_done(xfer); +			spin_unlock_irqrestore(&xfer->lock, flags); +			if (done) +				wa_xfer_completion(xfer); +			wa_xfer_delayed_run(rpipe); +			wa_xfer_put(xfer); +		} else { +			dev_err(dev, "%s: xfer ID 0x%08X already gone.\n", +				 __func__, le32_to_cpu(b->cmd.dwTransferID)); +		} +	} + +	wa_put(wa);	/* taken in __wa_xfer_abort */  	usb_put_urb(&b->urb);  } @@ -356,15 +492,11 @@ static void __wa_xfer_abort_cb(struct urb *urb)   *   * The callback (see above) does nothing but freeing up the data by   * putting the URB. Because the URB is allocated at the head of the - * struct, the whole space we allocated is kfreed. - * - * We'll get an 'aborted transaction' xfer result on DTI, that'll - * politely ignore because at this point the transaction has been - * marked as aborted already. + * struct, the whole space we allocated is kfreed. *   */ -static void __wa_xfer_abort(struct wa_xfer *xfer) +static int __wa_xfer_abort(struct wa_xfer *xfer)  { -	int result; +	int result = -ENOMEM;  	struct device *dev = &xfer->wa->usb_iface->dev;  	struct wa_xfer_abort_buffer *b;  	struct wa_rpipe *rpipe = xfer->ep->hcpriv; @@ -375,7 +507,8 @@ static void __wa_xfer_abort(struct wa_xfer *xfer)  	b->cmd.bLength =  sizeof(b->cmd);  	b->cmd.bRequestType = WA_XFER_ABORT;  	b->cmd.wRPipe = rpipe->descr.wRPipeIndex; -	b->cmd.dwTransferID = wa_xfer_id(xfer); +	b->cmd.dwTransferID = wa_xfer_id_le32(xfer); +	b->wa = wa_get(xfer->wa);  	usb_init_urb(&b->urb);  	usb_fill_bulk_urb(&b->urb, xfer->wa->usb_dev, @@ -385,20 +518,63 @@ static void __wa_xfer_abort(struct wa_xfer *xfer)  	result = usb_submit_urb(&b->urb, GFP_ATOMIC);  	if (result < 0)  		goto error_submit; -	return;				/* callback frees! */ +	return result;				/* callback frees! */  error_submit: +	wa_put(xfer->wa);  	if (printk_ratelimit())  		dev_err(dev, "xfer %p: Can't submit abort request: %d\n",  			xfer, result);  	kfree(b);  error_kmalloc: -	return; +	return result;  }  /* + * Calculate the number of isoc frames starting from isoc_frame_offset + * that will fit a in transfer segment. + */ +static int __wa_seg_calculate_isoc_frame_count(struct wa_xfer *xfer, +	int isoc_frame_offset, int *total_size) +{ +	int segment_size = 0, frame_count = 0; +	int index = isoc_frame_offset; +	struct usb_iso_packet_descriptor *iso_frame_desc = +		xfer->urb->iso_frame_desc; + +	while ((index < xfer->urb->number_of_packets) +		&& ((segment_size + iso_frame_desc[index].length) +				<= xfer->seg_size)) { +		/* +		 * For Alereon HWA devices, only include an isoc frame in an +		 * out segment if it is physically contiguous with the previous +		 * frame.  This is required because those devices expect +		 * the isoc frames to be sent as a single USB transaction as +		 * opposed to one transaction per frame with standard HWA. +		 */ +		if ((xfer->wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC) +			&& (xfer->is_inbound == 0) +			&& (index > isoc_frame_offset) +			&& ((iso_frame_desc[index - 1].offset + +				iso_frame_desc[index - 1].length) != +				iso_frame_desc[index].offset)) +			break; + +		/* this frame fits. count it. */ +		++frame_count; +		segment_size += iso_frame_desc[index].length; + +		/* move to the next isoc frame. */ +		++index; +	} + +	*total_size = segment_size; +	return frame_count; +} + +/*   *   * @returns < 0 on error, transfer segment request size if ok   */ @@ -422,43 +598,85 @@ static ssize_t __wa_xfer_setup_sizes(struct wa_xfer *xfer,  		result = sizeof(struct wa_xfer_bi);  		break;  	case USB_ENDPOINT_XFER_ISOC: -		dev_err(dev, "FIXME: ISOC not implemented\n"); -		result = -ENOSYS; -		goto error; +		*pxfer_type = WA_XFER_TYPE_ISO; +		result = sizeof(struct wa_xfer_hwaiso); +		break;  	default:  		/* never happens */  		BUG();  		result = -EINVAL;	/* shut gcc up */ -	}; +	}  	xfer->is_inbound = urb->pipe & USB_DIR_IN ? 1 : 0;  	xfer->is_dma = urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP ? 1 : 0; + +	maxpktsize = le16_to_cpu(rpipe->descr.wMaxPacketSize);  	xfer->seg_size = le16_to_cpu(rpipe->descr.wBlocks)  		* 1 << (xfer->wa->wa_descr->bRPipeBlockSize - 1);  	/* Compute the segment size and make sure it is a multiple of  	 * the maxpktsize (WUSB1.0[8.3.3.1])...not really too much of  	 * a check (FIXME) */ -	maxpktsize = le16_to_cpu(rpipe->descr.wMaxPacketSize);  	if (xfer->seg_size < maxpktsize) { -		dev_err(dev, "HW BUG? seg_size %zu smaller than maxpktsize " -			"%zu\n", xfer->seg_size, maxpktsize); +		dev_err(dev, +			"HW BUG? seg_size %zu smaller than maxpktsize %zu\n", +			xfer->seg_size, maxpktsize);  		result = -EINVAL;  		goto error;  	}  	xfer->seg_size = (xfer->seg_size / maxpktsize) * maxpktsize; -	xfer->segs = DIV_ROUND_UP(urb->transfer_buffer_length, xfer->seg_size); -	if (xfer->segs >= WA_SEGS_MAX) { -		dev_err(dev, "BUG? ops, number of segments %d bigger than %d\n", -			(int)(urb->transfer_buffer_length / xfer->seg_size), +	if ((rpipe->descr.bmAttribute & 0x3) == USB_ENDPOINT_XFER_ISOC) { +		int index = 0; + +		xfer->segs = 0; +		/* +		 * loop over urb->number_of_packets to determine how many +		 * xfer segments will be needed to send the isoc frames. +		 */ +		while (index < urb->number_of_packets) { +			int seg_size; /* don't care. */ +			index += __wa_seg_calculate_isoc_frame_count(xfer, +					index, &seg_size); +			++xfer->segs; +		} +	} else { +		xfer->segs = DIV_ROUND_UP(urb->transfer_buffer_length, +						xfer->seg_size); +		if (xfer->segs == 0 && *pxfer_type == WA_XFER_TYPE_CTL) +			xfer->segs = 1; +	} + +	if (xfer->segs > WA_SEGS_MAX) { +		dev_err(dev, "BUG? oops, number of segments %zu bigger than %d\n", +			(urb->transfer_buffer_length/xfer->seg_size),  			WA_SEGS_MAX);  		result = -EINVAL;  		goto error;  	} -	if (xfer->segs == 0 && *pxfer_type == WA_XFER_TYPE_CTL) -		xfer->segs = 1;  error:  	return result;  } +static void __wa_setup_isoc_packet_descr( +		struct wa_xfer_packet_info_hwaiso *packet_desc, +		struct wa_xfer *xfer, +		struct wa_seg *seg) { +	struct usb_iso_packet_descriptor *iso_frame_desc = +		xfer->urb->iso_frame_desc; +	int frame_index; + +	/* populate isoc packet descriptor. */ +	packet_desc->bPacketType = WA_XFER_ISO_PACKET_INFO; +	packet_desc->wLength = cpu_to_le16(sizeof(*packet_desc) + +		(sizeof(packet_desc->PacketLength[0]) * +			seg->isoc_frame_count)); +	for (frame_index = 0; frame_index < seg->isoc_frame_count; +		++frame_index) { +		int offset_index = frame_index + seg->isoc_frame_offset; +		packet_desc->PacketLength[frame_index] = +			cpu_to_le16(iso_frame_desc[offset_index].length); +	} +} + +  /* Fill in the common request header and xfer-type specific data. */  static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer,  				 struct wa_xfer_hdr *xfer_hdr0, @@ -466,12 +684,13 @@ static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer,  				 size_t xfer_hdr_size)  {  	struct wa_rpipe *rpipe = xfer->ep->hcpriv; +	struct wa_seg *seg = xfer->seg[0]; -	xfer_hdr0 = &xfer->seg[0]->xfer_hdr; +	xfer_hdr0 = &seg->xfer_hdr;  	xfer_hdr0->bLength = xfer_hdr_size;  	xfer_hdr0->bRequestType = xfer_type;  	xfer_hdr0->wRPipe = rpipe->descr.wRPipeIndex; -	xfer_hdr0->dwTransferID = wa_xfer_id(xfer); +	xfer_hdr0->dwTransferID = wa_xfer_id_le32(xfer);  	xfer_hdr0->bTransferSegment = 0;  	switch (xfer_type) {  	case WA_XFER_TYPE_CTL: { @@ -484,8 +703,18 @@ static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer,  	}  	case WA_XFER_TYPE_BI:  		break; -	case WA_XFER_TYPE_ISO: -		printk(KERN_ERR "FIXME: ISOC not implemented\n"); +	case WA_XFER_TYPE_ISO: { +		struct wa_xfer_hwaiso *xfer_iso = +			container_of(xfer_hdr0, struct wa_xfer_hwaiso, hdr); +		struct wa_xfer_packet_info_hwaiso *packet_desc = +			((void *)xfer_iso) + xfer_hdr_size; + +		/* populate the isoc section of the transfer request. */ +		xfer_iso->dwNumOfPackets = cpu_to_le32(seg->isoc_frame_count); +		/* populate isoc packet descriptor. */ +		__wa_setup_isoc_packet_descr(packet_desc, xfer, seg); +		break; +	}  	default:  		BUG();  	}; @@ -494,12 +723,12 @@ static void __wa_xfer_setup_hdr0(struct wa_xfer *xfer,  /*   * Callback for the OUT data phase of the segment request   * - * Check wa_seg_cb(); most comments also apply here because this + * Check wa_seg_tr_cb(); most comments also apply here because this   * function does almost the same thing and they work closely   * together.   *   * If the seg request has failed but this DTO phase has succeeded, - * wa_seg_cb() has already failed the segment and moved the + * wa_seg_tr_cb() has already failed the segment and moved the   * status to WA_SEG_ERROR, so this will go through 'case 0' and   * effectively do nothing.   */ @@ -512,6 +741,143 @@ static void wa_seg_dto_cb(struct urb *urb)  	struct wa_rpipe *rpipe;  	unsigned long flags;  	unsigned rpipe_ready = 0; +	int data_send_done = 1, release_dto = 0, holding_dto = 0; +	u8 done = 0; +	int result; + +	/* free the sg if it was used. */ +	kfree(urb->sg); +	urb->sg = NULL; + +	spin_lock_irqsave(&xfer->lock, flags); +	wa = xfer->wa; +	dev = &wa->usb_iface->dev; +	if (usb_pipeisoc(xfer->urb->pipe)) { +		/* Alereon HWA sends all isoc frames in a single transfer. */ +		if (wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC) +			seg->isoc_frame_index += seg->isoc_frame_count; +		else +			seg->isoc_frame_index += 1; +		if (seg->isoc_frame_index < seg->isoc_frame_count) { +			data_send_done = 0; +			holding_dto = 1; /* checked in error cases. */ +			/* +			 * if this is the last isoc frame of the segment, we +			 * can release DTO after sending this frame. +			 */ +			if ((seg->isoc_frame_index + 1) >= +				seg->isoc_frame_count) +				release_dto = 1; +		} +		dev_dbg(dev, "xfer 0x%08X#%u: isoc frame = %d, holding_dto = %d, release_dto = %d.\n", +			wa_xfer_id(xfer), seg->index, seg->isoc_frame_index, +			holding_dto, release_dto); +	} +	spin_unlock_irqrestore(&xfer->lock, flags); + +	switch (urb->status) { +	case 0: +		spin_lock_irqsave(&xfer->lock, flags); +		seg->result += urb->actual_length; +		if (data_send_done) { +			dev_dbg(dev, "xfer 0x%08X#%u: data out done (%zu bytes)\n", +				wa_xfer_id(xfer), seg->index, seg->result); +			if (seg->status < WA_SEG_PENDING) +				seg->status = WA_SEG_PENDING; +		} else { +			/* should only hit this for isoc xfers. */ +			/* +			 * Populate the dto URB with the next isoc frame buffer, +			 * send the URB and release DTO if we no longer need it. +			 */ +			 __wa_populate_dto_urb_isoc(xfer, seg, +				seg->isoc_frame_offset + seg->isoc_frame_index); + +			/* resubmit the URB with the next isoc frame. */ +			/* take a ref on resubmit. */ +			wa_xfer_get(xfer); +			result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC); +			if (result < 0) { +				dev_err(dev, "xfer 0x%08X#%u: DTO submit failed: %d\n", +				       wa_xfer_id(xfer), seg->index, result); +				spin_unlock_irqrestore(&xfer->lock, flags); +				goto error_dto_submit; +			} +		} +		spin_unlock_irqrestore(&xfer->lock, flags); +		if (release_dto) { +			__wa_dto_put(wa); +			wa_check_for_delayed_rpipes(wa); +		} +		break; +	case -ECONNRESET:	/* URB unlinked; no need to do anything */ +	case -ENOENT:		/* as it was done by the who unlinked us */ +		if (holding_dto) { +			__wa_dto_put(wa); +			wa_check_for_delayed_rpipes(wa); +		} +		break; +	default:		/* Other errors ... */ +		dev_err(dev, "xfer 0x%08X#%u: data out error %d\n", +			wa_xfer_id(xfer), seg->index, urb->status); +		goto error_default; +	} + +	/* taken when this URB was submitted. */ +	wa_xfer_put(xfer); +	return; + +error_dto_submit: +	/* taken on resubmit attempt. */ +	wa_xfer_put(xfer); +error_default: +	spin_lock_irqsave(&xfer->lock, flags); +	rpipe = xfer->ep->hcpriv; +	if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS, +		    EDC_ERROR_TIMEFRAME)){ +		dev_err(dev, "DTO: URB max acceptable errors exceeded, resetting device\n"); +		wa_reset_all(wa); +	} +	if (seg->status != WA_SEG_ERROR) { +		seg->result = urb->status; +		__wa_xfer_abort(xfer); +		rpipe_ready = rpipe_avail_inc(rpipe); +		done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_ERROR); +	} +	spin_unlock_irqrestore(&xfer->lock, flags); +	if (holding_dto) { +		__wa_dto_put(wa); +		wa_check_for_delayed_rpipes(wa); +	} +	if (done) +		wa_xfer_completion(xfer); +	if (rpipe_ready) +		wa_xfer_delayed_run(rpipe); +	/* taken when this URB was submitted. */ +	wa_xfer_put(xfer); +} + +/* + * Callback for the isoc packet descriptor phase of the segment request + * + * Check wa_seg_tr_cb(); most comments also apply here because this + * function does almost the same thing and they work closely + * together. + * + * If the seg request has failed but this phase has succeeded, + * wa_seg_tr_cb() has already failed the segment and moved the + * status to WA_SEG_ERROR, so this will go through 'case 0' and + * effectively do nothing. + */ +static void wa_seg_iso_pack_desc_cb(struct urb *urb) +{ +	struct wa_seg *seg = urb->context; +	struct wa_xfer *xfer = seg->xfer; +	struct wahc *wa; +	struct device *dev; +	struct wa_rpipe *rpipe; +	unsigned long flags; +	unsigned rpipe_ready = 0;  	u8 done = 0;  	switch (urb->status) { @@ -519,11 +885,10 @@ static void wa_seg_dto_cb(struct urb *urb)  		spin_lock_irqsave(&xfer->lock, flags);  		wa = xfer->wa;  		dev = &wa->usb_iface->dev; -		dev_dbg(dev, "xfer %p#%u: data out done (%d bytes)\n", -			xfer, seg->index, urb->actual_length); -		if (seg->status < WA_SEG_PENDING) +		dev_dbg(dev, "iso xfer %08X#%u: packet descriptor done\n", +			wa_xfer_id(xfer), seg->index); +		if (xfer->is_inbound && seg->status < WA_SEG_PENDING)  			seg->status = WA_SEG_PENDING; -		seg->result = urb->actual_length;  		spin_unlock_irqrestore(&xfer->lock, flags);  		break;  	case -ECONNRESET:	/* URB unlinked; no need to do anything */ @@ -534,21 +899,20 @@ static void wa_seg_dto_cb(struct urb *urb)  		wa = xfer->wa;  		dev = &wa->usb_iface->dev;  		rpipe = xfer->ep->hcpriv; -		dev_dbg(dev, "xfer %p#%u: data out error %d\n", -			xfer, seg->index, urb->status); +		pr_err_ratelimited("iso xfer %08X#%u: packet descriptor error %d\n", +				wa_xfer_id(xfer), seg->index, urb->status);  		if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,  			    EDC_ERROR_TIMEFRAME)){ -			dev_err(dev, "DTO: URB max acceptable errors " -				"exceeded, resetting device\n"); +			dev_err(dev, "iso xfer: URB max acceptable errors exceeded, resetting device\n");  			wa_reset_all(wa);  		}  		if (seg->status != WA_SEG_ERROR) { -			seg->status = WA_SEG_ERROR; +			usb_unlink_urb(seg->dto_urb);  			seg->result = urb->status; -			xfer->segs_done++;  			__wa_xfer_abort(xfer);  			rpipe_ready = rpipe_avail_inc(rpipe); -			done = __wa_xfer_is_done(xfer); +			done = __wa_xfer_mark_seg_as_done(xfer, seg, +					WA_SEG_ERROR);  		}  		spin_unlock_irqrestore(&xfer->lock, flags);  		if (done) @@ -556,6 +920,8 @@ static void wa_seg_dto_cb(struct urb *urb)  		if (rpipe_ready)  			wa_xfer_delayed_run(rpipe);  	} +	/* taken when this URB was submitted. */ +	wa_xfer_put(xfer);  }  /* @@ -572,11 +938,11 @@ static void wa_seg_dto_cb(struct urb *urb)   * We have to check before setting the status to WA_SEG_PENDING   * because sometimes the xfer result callback arrives before this   * callback (geeeeeeze), so it might happen that we are already in - * another state. As well, we don't set it if the transfer is inbound, + * another state. As well, we don't set it if the transfer is not inbound,   * as in that case, wa_seg_dto_cb will do it when the OUT data phase   * finishes.   */ -static void wa_seg_cb(struct urb *urb) +static void wa_seg_tr_cb(struct urb *urb)  {  	struct wa_seg *seg = urb->context;  	struct wa_xfer *xfer = seg->xfer; @@ -592,8 +958,11 @@ static void wa_seg_cb(struct urb *urb)  		spin_lock_irqsave(&xfer->lock, flags);  		wa = xfer->wa;  		dev = &wa->usb_iface->dev; -		dev_dbg(dev, "xfer %p#%u: request done\n", xfer, seg->index); -		if (xfer->is_inbound && seg->status < WA_SEG_PENDING) +		dev_dbg(dev, "xfer %p ID 0x%08X#%u: request done\n", +			xfer, wa_xfer_id(xfer), seg->index); +		if (xfer->is_inbound && +			seg->status < WA_SEG_PENDING && +			!(usb_pipeisoc(xfer->urb->pipe)))  			seg->status = WA_SEG_PENDING;  		spin_unlock_irqrestore(&xfer->lock, flags);  		break; @@ -606,35 +975,39 @@ static void wa_seg_cb(struct urb *urb)  		dev = &wa->usb_iface->dev;  		rpipe = xfer->ep->hcpriv;  		if (printk_ratelimit()) -			dev_err(dev, "xfer %p#%u: request error %d\n", -				xfer, seg->index, urb->status); +			dev_err(dev, "xfer %p ID 0x%08X#%u: request error %d\n", +				xfer, wa_xfer_id(xfer), seg->index, +				urb->status);  		if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,  			    EDC_ERROR_TIMEFRAME)){  			dev_err(dev, "DTO: URB max acceptable errors "  				"exceeded, resetting device\n");  			wa_reset_all(wa);  		} +		usb_unlink_urb(seg->isoc_pack_desc_urb);  		usb_unlink_urb(seg->dto_urb); -		seg->status = WA_SEG_ERROR;  		seg->result = urb->status; -		xfer->segs_done++;  		__wa_xfer_abort(xfer);  		rpipe_ready = rpipe_avail_inc(rpipe); -		done = __wa_xfer_is_done(xfer); +		done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_ERROR);  		spin_unlock_irqrestore(&xfer->lock, flags);  		if (done)  			wa_xfer_completion(xfer);  		if (rpipe_ready)  			wa_xfer_delayed_run(rpipe);  	} +	/* taken when this URB was submitted. */ +	wa_xfer_put(xfer);  } -/* allocate an SG list to store bytes_to_transfer bytes and copy the +/* + * Allocate an SG list to store bytes_to_transfer bytes and copy the   * subset of the in_sg that matches the buffer subset - * we are about to transfer. */ + * we are about to transfer. + */  static struct scatterlist *wa_xfer_create_subset_sg(struct scatterlist *in_sg,  	const unsigned int bytes_transferred, -	const unsigned int bytes_to_transfer, unsigned int *out_num_sgs) +	const unsigned int bytes_to_transfer, int *out_num_sgs)  {  	struct scatterlist *out_sg;  	unsigned int bytes_processed = 0, offset_into_current_page_data = 0, @@ -710,6 +1083,75 @@ static struct scatterlist *wa_xfer_create_subset_sg(struct scatterlist *in_sg,  }  /* + * Populate DMA buffer info for the isoc dto urb. + */ +static void __wa_populate_dto_urb_isoc(struct wa_xfer *xfer, +	struct wa_seg *seg, int curr_iso_frame) +{ +	seg->dto_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +	seg->dto_urb->sg = NULL; +	seg->dto_urb->num_sgs = 0; +	/* dto urb buffer address pulled from iso_frame_desc. */ +	seg->dto_urb->transfer_dma = xfer->urb->transfer_dma + +		xfer->urb->iso_frame_desc[curr_iso_frame].offset; +	/* The Alereon HWA sends a single URB with all isoc segs. */ +	if (xfer->wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC) +		seg->dto_urb->transfer_buffer_length = seg->isoc_size; +	else +		seg->dto_urb->transfer_buffer_length = +			xfer->urb->iso_frame_desc[curr_iso_frame].length; +} + +/* + * Populate buffer ptr and size, DMA buffer or SG list for the dto urb. + */ +static int __wa_populate_dto_urb(struct wa_xfer *xfer, +	struct wa_seg *seg, size_t buf_itr_offset, size_t buf_itr_size) +{ +	int result = 0; + +	if (xfer->is_dma) { +		seg->dto_urb->transfer_dma = +			xfer->urb->transfer_dma + buf_itr_offset; +		seg->dto_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +		seg->dto_urb->sg = NULL; +		seg->dto_urb->num_sgs = 0; +	} else { +		/* do buffer or SG processing. */ +		seg->dto_urb->transfer_flags &= +			~URB_NO_TRANSFER_DMA_MAP; +		/* this should always be 0 before a resubmit. */ +		seg->dto_urb->num_mapped_sgs = 0; + +		if (xfer->urb->transfer_buffer) { +			seg->dto_urb->transfer_buffer = +				xfer->urb->transfer_buffer + +				buf_itr_offset; +			seg->dto_urb->sg = NULL; +			seg->dto_urb->num_sgs = 0; +		} else { +			seg->dto_urb->transfer_buffer = NULL; + +			/* +			 * allocate an SG list to store seg_size bytes +			 * and copy the subset of the xfer->urb->sg that +			 * matches the buffer subset we are about to +			 * read. +			 */ +			seg->dto_urb->sg = wa_xfer_create_subset_sg( +				xfer->urb->sg, +				buf_itr_offset, buf_itr_size, +				&(seg->dto_urb->num_sgs)); +			if (!(seg->dto_urb->sg)) +				result = -ENOMEM; +		} +	} +	seg->dto_urb->transfer_buffer_length = buf_itr_size; + +	return result; +} + +/*   * Allocate the segs array and initialize each of them   *   * The segments are freed by wa_xfer_destroy() when the xfer use count @@ -719,7 +1161,7 @@ static struct scatterlist *wa_xfer_create_subset_sg(struct scatterlist *in_sg,   */  static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)  { -	int result, cnt; +	int result, cnt, isoc_frame_offset = 0;  	size_t alloc_size = sizeof(*xfer->seg[0])  		- sizeof(xfer->seg[0]->xfer_hdr) + xfer_hdr_size;  	struct usb_device *usb_dev = xfer->wa->usb_dev; @@ -734,18 +1176,63 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)  	buf_itr = 0;  	buf_size = xfer->urb->transfer_buffer_length;  	for (cnt = 0; cnt < xfer->segs; cnt++) { -		seg = xfer->seg[cnt] = kmalloc(alloc_size, GFP_ATOMIC); +		size_t iso_pkt_descr_size = 0; +		int seg_isoc_frame_count = 0, seg_isoc_size = 0; + +		/* +		 * Adjust the size of the segment object to contain space for +		 * the isoc packet descriptor buffer. +		 */ +		if (usb_pipeisoc(xfer->urb->pipe)) { +			seg_isoc_frame_count = +				__wa_seg_calculate_isoc_frame_count(xfer, +					isoc_frame_offset, &seg_isoc_size); + +			iso_pkt_descr_size = +				sizeof(struct wa_xfer_packet_info_hwaiso) + +				(seg_isoc_frame_count * sizeof(__le16)); +		} +		seg = xfer->seg[cnt] = kmalloc(alloc_size + iso_pkt_descr_size, +						GFP_ATOMIC);  		if (seg == NULL)  			goto error_seg_kmalloc;  		wa_seg_init(seg);  		seg->xfer = xfer;  		seg->index = cnt; -		usb_fill_bulk_urb(&seg->urb, usb_dev, +		usb_fill_bulk_urb(&seg->tr_urb, usb_dev,  				  usb_sndbulkpipe(usb_dev,  						  dto_epd->bEndpointAddress),  				  &seg->xfer_hdr, xfer_hdr_size, -				  wa_seg_cb, seg); +				  wa_seg_tr_cb, seg);  		buf_itr_size = min(buf_size, xfer->seg_size); + +		if (usb_pipeisoc(xfer->urb->pipe)) { +			seg->isoc_frame_count = seg_isoc_frame_count; +			seg->isoc_frame_offset = isoc_frame_offset; +			seg->isoc_size = seg_isoc_size; +			/* iso packet descriptor. */ +			seg->isoc_pack_desc_urb = +					usb_alloc_urb(0, GFP_ATOMIC); +			if (seg->isoc_pack_desc_urb == NULL) +				goto error_iso_pack_desc_alloc; +			/* +			 * The buffer for the isoc packet descriptor starts +			 * after the transfer request header in the +			 * segment object memory buffer. +			 */ +			usb_fill_bulk_urb( +				seg->isoc_pack_desc_urb, usb_dev, +				usb_sndbulkpipe(usb_dev, +					dto_epd->bEndpointAddress), +				(void *)(&seg->xfer_hdr) + +					xfer_hdr_size, +				iso_pkt_descr_size, +				wa_seg_iso_pack_desc_cb, seg); + +			/* adjust starting frame offset for next seg. */ +			isoc_frame_offset += seg_isoc_frame_count; +		} +  		if (xfer->is_inbound == 0 && buf_size > 0) {  			/* outbound data. */  			seg->dto_urb = usb_alloc_urb(0, GFP_ATOMIC); @@ -756,69 +1243,44 @@ static int __wa_xfer_setup_segs(struct wa_xfer *xfer, size_t xfer_hdr_size)  				usb_sndbulkpipe(usb_dev,  						dto_epd->bEndpointAddress),  				NULL, 0, wa_seg_dto_cb, seg); -			if (xfer->is_dma) { -				seg->dto_urb->transfer_dma = -					xfer->urb->transfer_dma + buf_itr; -				seg->dto_urb->transfer_flags |= -					URB_NO_TRANSFER_DMA_MAP; -				seg->dto_urb->transfer_buffer = NULL; -				seg->dto_urb->sg = NULL; -				seg->dto_urb->num_sgs = 0; + +			if (usb_pipeisoc(xfer->urb->pipe)) { +				/* +				 * Fill in the xfer buffer information for the +				 * first isoc frame.  Subsequent frames in this +				 * segment will be filled in and sent from the +				 * DTO completion routine, if needed. +				 */ +				__wa_populate_dto_urb_isoc(xfer, seg, +					seg->isoc_frame_offset);  			} else { -				/* do buffer or SG processing. */ -				seg->dto_urb->transfer_flags &= -					~URB_NO_TRANSFER_DMA_MAP; -				/* this should always be 0 before a resubmit. */ -				seg->dto_urb->num_mapped_sgs = 0; - -				if (xfer->urb->transfer_buffer) { -					seg->dto_urb->transfer_buffer = -						xfer->urb->transfer_buffer + -						buf_itr; -					seg->dto_urb->sg = NULL; -					seg->dto_urb->num_sgs = 0; -				} else { -					/* allocate an SG list to store seg_size -					    bytes and copy the subset of the -					    xfer->urb->sg that matches the -					    buffer subset we are about to read. -					*/ -					seg->dto_urb->sg = -						wa_xfer_create_subset_sg( -						xfer->urb->sg, -						buf_itr, buf_itr_size, -						&(seg->dto_urb->num_sgs)); - -					if (!(seg->dto_urb->sg)) { -						seg->dto_urb->num_sgs	= 0; -						goto error_sg_alloc; -					} - -					seg->dto_urb->transfer_buffer = NULL; -				} +				/* fill in the xfer buffer information. */ +				result = __wa_populate_dto_urb(xfer, seg, +							buf_itr, buf_itr_size); +				if (result < 0) +					goto error_seg_outbound_populate; + +				buf_itr += buf_itr_size; +				buf_size -= buf_itr_size;  			} -			seg->dto_urb->transfer_buffer_length = buf_itr_size;  		}  		seg->status = WA_SEG_READY; -		buf_itr += buf_itr_size; -		buf_size -= buf_itr_size;  	}  	return 0; -error_sg_alloc: +	/* +	 * Free the memory for the current segment which failed to init. +	 * Use the fact that cnt is left at were it failed.  The remaining +	 * segments will be cleaned up by wa_xfer_destroy. +	 */ +error_seg_outbound_populate:  	usb_free_urb(xfer->seg[cnt]->dto_urb);  error_dto_alloc: +	usb_free_urb(xfer->seg[cnt]->isoc_pack_desc_urb); +error_iso_pack_desc_alloc:  	kfree(xfer->seg[cnt]); -	cnt--; +	xfer->seg[cnt] = NULL;  error_seg_kmalloc: -	/* use the fact that cnt is left at were it failed */ -	for (; cnt >= 0; cnt--) { -		if (xfer->seg[cnt] && xfer->is_inbound == 0) { -			usb_free_urb(xfer->seg[cnt]->dto_urb); -			kfree(xfer->seg[cnt]->dto_urb->sg); -		} -		kfree(xfer->seg[cnt]); -	}  error_segs_kzalloc:  	return result;  } @@ -856,21 +1318,50 @@ static int __wa_xfer_setup(struct wa_xfer *xfer, struct urb *urb)  	wa_xfer_id_init(xfer);  	__wa_xfer_setup_hdr0(xfer, xfer_hdr0, xfer_type, xfer_hdr_size); -	/* Fill remainig headers */ +	/* Fill remaining headers */  	xfer_hdr = xfer_hdr0; -	transfer_size = urb->transfer_buffer_length; -	xfer_hdr0->dwTransferLength = transfer_size > xfer->seg_size ? -		xfer->seg_size : transfer_size; -	transfer_size -=  xfer->seg_size; -	for (cnt = 1; cnt < xfer->segs; cnt++) { -		xfer_hdr = &xfer->seg[cnt]->xfer_hdr; -		memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size); -		xfer_hdr->bTransferSegment = cnt; -		xfer_hdr->dwTransferLength = transfer_size > xfer->seg_size ? -			cpu_to_le32(xfer->seg_size) -			: cpu_to_le32(transfer_size); -		xfer->seg[cnt]->status = WA_SEG_READY; +	if (xfer_type == WA_XFER_TYPE_ISO) { +		xfer_hdr0->dwTransferLength = +			cpu_to_le32(xfer->seg[0]->isoc_size); +		for (cnt = 1; cnt < xfer->segs; cnt++) { +			struct wa_xfer_packet_info_hwaiso *packet_desc; +			struct wa_seg *seg = xfer->seg[cnt]; +			struct wa_xfer_hwaiso *xfer_iso; + +			xfer_hdr = &seg->xfer_hdr; +			xfer_iso = container_of(xfer_hdr, +						struct wa_xfer_hwaiso, hdr); +			packet_desc = ((void *)xfer_hdr) + xfer_hdr_size; +			/* +			 * Copy values from the 0th header. Segment specific +			 * values are set below. +			 */ +			memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size); +			xfer_hdr->bTransferSegment = cnt; +			xfer_hdr->dwTransferLength = +				cpu_to_le32(seg->isoc_size); +			xfer_iso->dwNumOfPackets = +					cpu_to_le32(seg->isoc_frame_count); +			__wa_setup_isoc_packet_descr(packet_desc, xfer, seg); +			seg->status = WA_SEG_READY; +		} +	} else { +		transfer_size = urb->transfer_buffer_length; +		xfer_hdr0->dwTransferLength = transfer_size > xfer->seg_size ? +			cpu_to_le32(xfer->seg_size) : +			cpu_to_le32(transfer_size);  		transfer_size -=  xfer->seg_size; +		for (cnt = 1; cnt < xfer->segs; cnt++) { +			xfer_hdr = &xfer->seg[cnt]->xfer_hdr; +			memcpy(xfer_hdr, xfer_hdr0, xfer_hdr_size); +			xfer_hdr->bTransferSegment = cnt; +			xfer_hdr->dwTransferLength = +				transfer_size > xfer->seg_size ? +					cpu_to_le32(xfer->seg_size) +					: cpu_to_le32(transfer_size); +			xfer->seg[cnt]->status = WA_SEG_READY; +			transfer_size -=  xfer->seg_size; +		}  	}  	xfer_hdr->bTransferSegment |= 0x80;	/* this is the last segment */  	result = 0; @@ -885,70 +1376,161 @@ error_setup_sizes:   * rpipe->seg_lock is held!   */  static int __wa_seg_submit(struct wa_rpipe *rpipe, struct wa_xfer *xfer, -			   struct wa_seg *seg) +			   struct wa_seg *seg, int *dto_done)  {  	int result; -	result = usb_submit_urb(&seg->urb, GFP_ATOMIC); + +	/* default to done unless we encounter a multi-frame isoc segment. */ +	*dto_done = 1; + +	/* +	 * Take a ref for each segment urb so the xfer cannot disappear until +	 * all of the callbacks run. +	 */ +	wa_xfer_get(xfer); +	/* submit the transfer request. */ +	seg->status = WA_SEG_SUBMITTED; +	result = usb_submit_urb(&seg->tr_urb, GFP_ATOMIC);  	if (result < 0) { -		printk(KERN_ERR "xfer %p#%u: REQ submit failed: %d\n", -		       xfer, seg->index, result); -		goto error_seg_submit; +		pr_err("%s: xfer %p#%u: REQ submit failed: %d\n", +		       __func__, xfer, seg->index, result); +		wa_xfer_put(xfer); +		goto error_tr_submit;  	} +	/* submit the isoc packet descriptor if present. */ +	if (seg->isoc_pack_desc_urb) { +		wa_xfer_get(xfer); +		result = usb_submit_urb(seg->isoc_pack_desc_urb, GFP_ATOMIC); +		seg->isoc_frame_index = 0; +		if (result < 0) { +			pr_err("%s: xfer %p#%u: ISO packet descriptor submit failed: %d\n", +			       __func__, xfer, seg->index, result); +			wa_xfer_put(xfer); +			goto error_iso_pack_desc_submit; +		} +	} +	/* submit the out data if this is an out request. */  	if (seg->dto_urb) { +		struct wahc *wa = xfer->wa; +		wa_xfer_get(xfer);  		result = usb_submit_urb(seg->dto_urb, GFP_ATOMIC);  		if (result < 0) { -			printk(KERN_ERR "xfer %p#%u: DTO submit failed: %d\n", -			       xfer, seg->index, result); +			pr_err("%s: xfer %p#%u: DTO submit failed: %d\n", +			       __func__, xfer, seg->index, result); +			wa_xfer_put(xfer);  			goto error_dto_submit;  		} +		/* +		 * If this segment contains more than one isoc frame, hold +		 * onto the dto resource until we send all frames. +		 * Only applies to non-Alereon devices. +		 */ +		if (((wa->quirks & WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC) == 0) +			&& (seg->isoc_frame_count > 1)) +			*dto_done = 0;  	} -	seg->status = WA_SEG_SUBMITTED;  	rpipe_avail_dec(rpipe);  	return 0;  error_dto_submit: -	usb_unlink_urb(&seg->urb); -error_seg_submit: +	usb_unlink_urb(seg->isoc_pack_desc_urb); +error_iso_pack_desc_submit: +	usb_unlink_urb(&seg->tr_urb); +error_tr_submit:  	seg->status = WA_SEG_ERROR;  	seg->result = result; +	*dto_done = 1;  	return result;  }  /* - * Execute more queued request segments until the maximum concurrent allowed + * Execute more queued request segments until the maximum concurrent allowed. + * Return true if the DTO resource was acquired and released.   *   * The ugly unlock/lock sequence on the error path is needed as the   * xfer->lock normally nests the seg_lock and not viceversa. - *   */ -static void wa_xfer_delayed_run(struct wa_rpipe *rpipe) +static int __wa_xfer_delayed_run(struct wa_rpipe *rpipe, int *dto_waiting)  { -	int result; +	int result, dto_acquired = 0, dto_done = 0;  	struct device *dev = &rpipe->wa->usb_iface->dev;  	struct wa_seg *seg;  	struct wa_xfer *xfer;  	unsigned long flags; +	*dto_waiting = 0; +  	spin_lock_irqsave(&rpipe->seg_lock, flags);  	while (atomic_read(&rpipe->segs_available) > 0 -	      && !list_empty(&rpipe->seg_list)) { +	      && !list_empty(&rpipe->seg_list) +	      && (dto_acquired = __wa_dto_try_get(rpipe->wa))) {  		seg = list_first_entry(&(rpipe->seg_list), struct wa_seg,  				 list_node);  		list_del(&seg->list_node);  		xfer = seg->xfer; -		result = __wa_seg_submit(rpipe, xfer, seg); -		dev_dbg(dev, "xfer %p#%u submitted from delayed [%d segments available] %d\n", -			xfer, seg->index, atomic_read(&rpipe->segs_available), result); +		/* +		 * Get a reference to the xfer in case the callbacks for the +		 * URBs submitted by __wa_seg_submit attempt to complete +		 * the xfer before this function completes. +		 */ +		wa_xfer_get(xfer); +		result = __wa_seg_submit(rpipe, xfer, seg, &dto_done); +		/* release the dto resource if this RPIPE is done with it. */ +		if (dto_done) +			__wa_dto_put(rpipe->wa); +		dev_dbg(dev, "xfer %p ID %08X#%u submitted from delayed [%d segments available] %d\n", +			xfer, wa_xfer_id(xfer), seg->index, +			atomic_read(&rpipe->segs_available), result);  		if (unlikely(result < 0)) { +			int done; +  			spin_unlock_irqrestore(&rpipe->seg_lock, flags);  			spin_lock_irqsave(&xfer->lock, flags);  			__wa_xfer_abort(xfer); +			/* +			 * This seg was marked as submitted when it was put on +			 * the RPIPE seg_list.  Mark it done. +			 */  			xfer->segs_done++; +			done = __wa_xfer_is_done(xfer);  			spin_unlock_irqrestore(&xfer->lock, flags); +			if (done) +				wa_xfer_completion(xfer);  			spin_lock_irqsave(&rpipe->seg_lock, flags);  		} +		wa_xfer_put(xfer);  	} +	/* +	 * Mark this RPIPE as waiting if dto was not acquired, there are +	 * delayed segs and no active transfers to wake us up later. +	 */ +	if (!dto_acquired && !list_empty(&rpipe->seg_list) +		&& (atomic_read(&rpipe->segs_available) == +			le16_to_cpu(rpipe->descr.wRequests))) +		*dto_waiting = 1; +  	spin_unlock_irqrestore(&rpipe->seg_lock, flags); + +	return dto_done; +} + +static void wa_xfer_delayed_run(struct wa_rpipe *rpipe) +{ +	int dto_waiting; +	int dto_done = __wa_xfer_delayed_run(rpipe, &dto_waiting); + +	/* +	 * If this RPIPE is waiting on the DTO resource, add it to the tail of +	 * the waiting list. +	 * Otherwise, if the WA DTO resource was acquired and released by +	 *  __wa_xfer_delayed_run, another RPIPE may have attempted to acquire +	 * DTO and failed during that time.  Check the delayed list and process +	 * any waiters.  Start searching from the next RPIPE index. +	 */ +	if (dto_waiting) +		wa_add_delayed_rpipe(rpipe->wa, rpipe); +	else if (dto_done) +		wa_check_for_delayed_rpipes(rpipe->wa);  }  /* @@ -960,7 +1542,7 @@ static void wa_xfer_delayed_run(struct wa_rpipe *rpipe)   */  static int __wa_xfer_submit(struct wa_xfer *xfer)  { -	int result; +	int result, dto_acquired = 0, dto_done = 0, dto_waiting = 0;  	struct wahc *wa = xfer->wa;  	struct device *dev = &wa->usb_iface->dev;  	unsigned cnt; @@ -979,27 +1561,58 @@ static int __wa_xfer_submit(struct wa_xfer *xfer)  	result = 0;  	spin_lock_irqsave(&rpipe->seg_lock, flags);  	for (cnt = 0; cnt < xfer->segs; cnt++) { +		int delay_seg = 1; +  		available = atomic_read(&rpipe->segs_available);  		empty = list_empty(&rpipe->seg_list);  		seg = xfer->seg[cnt]; -		dev_dbg(dev, "xfer %p#%u: available %u empty %u (%s)\n", -			xfer, cnt, available, empty, -			available == 0 || !empty ? "delayed" : "submitted"); -		if (available == 0 || !empty) { -			dev_dbg(dev, "xfer %p#%u: delayed\n", xfer, cnt); +		if (available && empty) { +			/* +			 * Only attempt to acquire DTO if we have a segment +			 * to send. +			 */ +			dto_acquired = __wa_dto_try_get(rpipe->wa); +			if (dto_acquired) { +				delay_seg = 0; +				result = __wa_seg_submit(rpipe, xfer, seg, +							&dto_done); +				dev_dbg(dev, "xfer %p ID 0x%08X#%u: available %u empty %u submitted\n", +					xfer, wa_xfer_id(xfer), cnt, available, +					empty); +				if (dto_done) +					__wa_dto_put(rpipe->wa); + +				if (result < 0) { +					__wa_xfer_abort(xfer); +					goto error_seg_submit; +				} +			} +		} + +		if (delay_seg) { +			dev_dbg(dev, "xfer %p ID 0x%08X#%u: available %u empty %u delayed\n", +				xfer, wa_xfer_id(xfer), cnt, available,  empty);  			seg->status = WA_SEG_DELAYED;  			list_add_tail(&seg->list_node, &rpipe->seg_list); -		} else { -			result = __wa_seg_submit(rpipe, xfer, seg); -			if (result < 0) { -				__wa_xfer_abort(xfer); -				goto error_seg_submit; -			}  		}  		xfer->segs_submitted++;  	}  error_seg_submit: +	/* +	 * Mark this RPIPE as waiting if dto was not acquired, there are +	 * delayed segs and no active transfers to wake us up later. +	 */ +	if (!dto_acquired && !list_empty(&rpipe->seg_list) +		&& (atomic_read(&rpipe->segs_available) == +			le16_to_cpu(rpipe->descr.wRequests))) +		dto_waiting = 1;  	spin_unlock_irqrestore(&rpipe->seg_lock, flags); + +	if (dto_waiting) +		wa_add_delayed_rpipe(rpipe->wa, rpipe); +	else if (dto_done) +		wa_check_for_delayed_rpipes(rpipe->wa); +  	return result;  } @@ -1025,7 +1638,7 @@ error_seg_submit:   * result never kicks in, the xfer will timeout from the USB code and   * dequeue() will be called.   */ -static void wa_urb_enqueue_b(struct wa_xfer *xfer) +static int wa_urb_enqueue_b(struct wa_xfer *xfer)  {  	int result;  	unsigned long flags; @@ -1036,18 +1649,23 @@ static void wa_urb_enqueue_b(struct wa_xfer *xfer)  	unsigned done;  	result = rpipe_get_by_ep(wa, xfer->ep, urb, xfer->gfp); -	if (result < 0) +	if (result < 0) { +		pr_err("%s: error_rpipe_get\n", __func__);  		goto error_rpipe_get; +	}  	result = -ENODEV;  	/* FIXME: segmentation broken -- kills DWA */  	mutex_lock(&wusbhc->mutex);		/* get a WUSB dev */  	if (urb->dev == NULL) {  		mutex_unlock(&wusbhc->mutex); +		pr_err("%s: error usb dev gone\n", __func__);  		goto error_dev_gone;  	}  	wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev);  	if (wusb_dev == NULL) {  		mutex_unlock(&wusbhc->mutex); +		dev_err(&(urb->dev->dev), "%s: error wusb dev gone\n", +			__func__);  		goto error_dev_gone;  	}  	mutex_unlock(&wusbhc->mutex); @@ -1055,21 +1673,35 @@ static void wa_urb_enqueue_b(struct wa_xfer *xfer)  	spin_lock_irqsave(&xfer->lock, flags);  	xfer->wusb_dev = wusb_dev;  	result = urb->status; -	if (urb->status != -EINPROGRESS) +	if (urb->status != -EINPROGRESS) { +		dev_err(&(urb->dev->dev), "%s: error_dequeued\n", __func__);  		goto error_dequeued; +	}  	result = __wa_xfer_setup(xfer, urb); -	if (result < 0) +	if (result < 0) { +		dev_err(&(urb->dev->dev), "%s: error_xfer_setup\n", __func__);  		goto error_xfer_setup; +	} +	/* +	 * Get a xfer reference since __wa_xfer_submit starts asynchronous +	 * operations that may try to complete the xfer before this function +	 * exits. +	 */ +	wa_xfer_get(xfer);  	result = __wa_xfer_submit(xfer); -	if (result < 0) +	if (result < 0) { +		dev_err(&(urb->dev->dev), "%s: error_xfer_submit\n", __func__);  		goto error_xfer_submit; +	}  	spin_unlock_irqrestore(&xfer->lock, flags); -	return; +	wa_xfer_put(xfer); +	return 0; -	/* this is basically wa_xfer_completion() broken up wa_xfer_giveback() -	 * does a wa_xfer_put() that will call wa_xfer_destroy() and clean -	 * upundo setup(). +	/* +	 * this is basically wa_xfer_completion() broken up wa_xfer_giveback() +	 * does a wa_xfer_put() that will call wa_xfer_destroy() and undo +	 * setup().  	 */  error_xfer_setup:  error_dequeued: @@ -1081,8 +1713,7 @@ error_dev_gone:  	rpipe_put(xfer->ep->hcpriv);  error_rpipe_get:  	xfer->result = result; -	wa_xfer_giveback(xfer); -	return; +	return result;  error_xfer_submit:  	done = __wa_xfer_is_done(xfer); @@ -1090,6 +1721,9 @@ error_xfer_submit:  	spin_unlock_irqrestore(&xfer->lock, flags);  	if (done)  		wa_xfer_completion(xfer); +	wa_xfer_put(xfer); +	/* return success since the completion routine will run. */ +	return 0;  }  /* @@ -1123,7 +1757,8 @@ void wa_urb_enqueue_run(struct work_struct *ws)  		list_del_init(&xfer->list_node);  		urb = xfer->urb; -		wa_urb_enqueue_b(xfer); +		if (wa_urb_enqueue_b(xfer) < 0) +			wa_xfer_giveback(xfer);  		usb_put_urb(urb);	/* taken when queuing */  	}  } @@ -1201,6 +1836,12 @@ int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep,  		dump_stack();  	} +	spin_lock_irqsave(&wa->xfer_list_lock, my_flags); +	result = usb_hcd_link_urb_to_ep(&(wa->wusb->usb_hcd), urb); +	spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags); +	if (result < 0) +		goto error_link_urb; +  	result = -ENOMEM;  	xfer = kzalloc(sizeof(*xfer), gfp);  	if (xfer == NULL) @@ -1229,13 +1870,32 @@ int wa_urb_enqueue(struct wahc *wa, struct usb_host_endpoint *ep,  		spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags);  		queue_work(wusbd, &wa->xfer_enqueue_work);  	} else { -		wa_urb_enqueue_b(xfer); +		result = wa_urb_enqueue_b(xfer); +		if (result < 0) { +			/* +			 * URB submit/enqueue failed.  Clean up, return an +			 * error and do not run the callback.  This avoids +			 * an infinite submit/complete loop. +			 */ +			dev_err(dev, "%s: URB enqueue failed: %d\n", +			   __func__, result); +			wa_put(xfer->wa); +			wa_xfer_put(xfer); +			spin_lock_irqsave(&wa->xfer_list_lock, my_flags); +			usb_hcd_unlink_urb_from_ep(&(wa->wusb->usb_hcd), urb); +			spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags); +			return result; +		}  	}  	return 0;  error_dequeued:  	kfree(xfer);  error_kmalloc: +	spin_lock_irqsave(&wa->xfer_list_lock, my_flags); +	usb_hcd_unlink_urb_from_ep(&(wa->wusb->usb_hcd), urb); +	spin_unlock_irqrestore(&wa->xfer_list_lock, my_flags); +error_link_urb:  	return result;  }  EXPORT_SYMBOL_GPL(wa_urb_enqueue); @@ -1258,31 +1918,51 @@ EXPORT_SYMBOL_GPL(wa_urb_enqueue);   * asynch request] and then make sure we cancel each segment.   *   */ -int wa_urb_dequeue(struct wahc *wa, struct urb *urb) +int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)  {  	unsigned long flags, flags2;  	struct wa_xfer *xfer;  	struct wa_seg *seg;  	struct wa_rpipe *rpipe; -	unsigned cnt; +	unsigned cnt, done = 0, xfer_abort_pending;  	unsigned rpipe_ready = 0; +	int result; -	xfer = urb->hcpriv; -	if (xfer == NULL) { +	/* check if it is safe to unlink. */ +	spin_lock_irqsave(&wa->xfer_list_lock, flags); +	result = usb_hcd_check_unlink_urb(&(wa->wusb->usb_hcd), urb, status); +	if ((result == 0) && urb->hcpriv) {  		/* -		 * Nothing setup yet enqueue will see urb->status != -		 * -EINPROGRESS (by hcd layer) and bail out with -		 * error, no need to do completion +		 * Get a xfer ref to prevent a race with wa_xfer_giveback +		 * cleaning up the xfer while we are working with it.  		 */ -		BUG_ON(urb->status == -EINPROGRESS); -		goto out; +		wa_xfer_get(urb->hcpriv);  	} +	spin_unlock_irqrestore(&wa->xfer_list_lock, flags); +	if (result) +		return result; + +	xfer = urb->hcpriv; +	if (xfer == NULL) +		return -ENOENT;  	spin_lock_irqsave(&xfer->lock, flags); +	pr_debug("%s: DEQUEUE xfer id 0x%08X\n", __func__, wa_xfer_id(xfer));  	rpipe = xfer->ep->hcpriv;  	if (rpipe == NULL) { -		pr_debug("%s: xfer id 0x%08X has no RPIPE.  %s", -			__func__, wa_xfer_id(xfer), +		pr_debug("%s: xfer %p id 0x%08X has no RPIPE.  %s", +			__func__, xfer, wa_xfer_id(xfer),  			"Probably already aborted.\n" ); +		result = -ENOENT; +		goto out_unlock; +	} +	/* +	 * Check for done to avoid racing with wa_xfer_giveback and completing +	 * twice. +	 */ +	if (__wa_xfer_is_done(xfer)) { +		pr_debug("%s: xfer %p id 0x%08X already done.\n", __func__, +			xfer, wa_xfer_id(xfer)); +		result = -ENOENT;  		goto out_unlock;  	}  	/* Check the delayed list -> if there, release and complete */ @@ -1293,9 +1973,16 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb)  	if (xfer->seg == NULL)  	/* still hasn't reached */  		goto out_unlock;	/* setup(), enqueue_b() completes */  	/* Ok, the xfer is in flight already, it's been setup and submitted.*/ -	__wa_xfer_abort(xfer); +	xfer_abort_pending = __wa_xfer_abort(xfer) >= 0; +	/* +	 * grab the rpipe->seg_lock here to prevent racing with +	 * __wa_xfer_delayed_run. +	 */ +	spin_lock(&rpipe->seg_lock);  	for (cnt = 0; cnt < xfer->segs; cnt++) {  		seg = xfer->seg[cnt]; +		pr_debug("%s: xfer id 0x%08X#%d status = %d\n", +			__func__, wa_xfer_id(xfer), cnt, seg->status);  		switch (seg->status) {  		case WA_SEG_NOTREADY:  		case WA_SEG_READY: @@ -1304,50 +1991,68 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb)  			WARN_ON(1);  			break;  		case WA_SEG_DELAYED: +			/* +			 * delete from rpipe delayed list.  If no segments on +			 * this xfer have been submitted, __wa_xfer_is_done will +			 * trigger a giveback below.  Otherwise, the submitted +			 * segments will be completed in the DTI interrupt. +			 */  			seg->status = WA_SEG_ABORTED; -			spin_lock_irqsave(&rpipe->seg_lock, flags2); +			seg->result = -ENOENT;  			list_del(&seg->list_node);  			xfer->segs_done++; -			rpipe_ready = rpipe_avail_inc(rpipe); -			spin_unlock_irqrestore(&rpipe->seg_lock, flags2); -			break; -		case WA_SEG_SUBMITTED: -			seg->status = WA_SEG_ABORTED; -			usb_unlink_urb(&seg->urb); -			if (xfer->is_inbound == 0) -				usb_unlink_urb(seg->dto_urb); -			xfer->segs_done++; -			rpipe_ready = rpipe_avail_inc(rpipe); -			break; -		case WA_SEG_PENDING: -			seg->status = WA_SEG_ABORTED; -			xfer->segs_done++; -			rpipe_ready = rpipe_avail_inc(rpipe); -			break; -		case WA_SEG_DTI_PENDING: -			usb_unlink_urb(wa->dti_urb); -			seg->status = WA_SEG_ABORTED; -			xfer->segs_done++; -			rpipe_ready = rpipe_avail_inc(rpipe);  			break;  		case WA_SEG_DONE:  		case WA_SEG_ERROR:  		case WA_SEG_ABORTED:  			break; +			/* +			 * The buf_in data for a segment in the +			 * WA_SEG_DTI_PENDING state is actively being read. +			 * Let wa_buf_in_cb handle it since it will be called +			 * and will increment xfer->segs_done.  Cleaning up +			 * here could cause wa_buf_in_cb to access the xfer +			 * after it has been completed/freed. +			 */ +		case WA_SEG_DTI_PENDING: +			break; +			/* +			 * In the states below, the HWA device already knows +			 * about the transfer.  If an abort request was sent, +			 * allow the HWA to process it and wait for the +			 * results.  Otherwise, the DTI state and seg completed +			 * counts can get out of sync. +			 */ +		case WA_SEG_SUBMITTED: +		case WA_SEG_PENDING: +			/* +			 * Check if the abort was successfully sent.  This could +			 * be false if the HWA has been removed but we haven't +			 * gotten the disconnect notification yet. +			 */ +			if (!xfer_abort_pending) { +				seg->status = WA_SEG_ABORTED; +				rpipe_ready = rpipe_avail_inc(rpipe); +				xfer->segs_done++; +			} +			break;  		}  	} +	spin_unlock(&rpipe->seg_lock);  	xfer->result = urb->status;	/* -ENOENT or -ECONNRESET */ -	__wa_xfer_is_done(xfer); +	done = __wa_xfer_is_done(xfer);  	spin_unlock_irqrestore(&xfer->lock, flags); -	wa_xfer_completion(xfer); +	if (done) +		wa_xfer_completion(xfer);  	if (rpipe_ready)  		wa_xfer_delayed_run(rpipe); -	return 0; +	wa_xfer_put(xfer); +	return result;  out_unlock:  	spin_unlock_irqrestore(&xfer->lock, flags); -out: -	return 0; +	wa_xfer_put(xfer); +	return result;  dequeue_delayed:  	list_del_init(&xfer->list_node); @@ -1355,6 +2060,7 @@ dequeue_delayed:  	xfer->result = urb->status;  	spin_unlock_irqrestore(&xfer->lock, flags);  	wa_xfer_giveback(xfer); +	wa_xfer_put(xfer);  	usb_put_urb(urb);		/* we got a ref in enqueue() */  	return 0;  } @@ -1383,7 +2089,7 @@ static int wa_xfer_status_to_errno(u8 status)  		[WA_XFER_STATUS_NOT_FOUND] =		0,  		[WA_XFER_STATUS_INSUFFICIENT_RESOURCE] = -ENOMEM,  		[WA_XFER_STATUS_TRANSACTION_ERROR] = 	-EILSEQ, -		[WA_XFER_STATUS_ABORTED] = 		-EINTR, +		[WA_XFER_STATUS_ABORTED] =		-ENOENT,  		[WA_XFER_STATUS_RPIPE_NOT_READY] = 	EINVAL,  		[WA_XFER_INVALID_FORMAT] = 		EINVAL,  		[WA_XFER_UNEXPECTED_SEGMENT_NUMBER] = 	EINVAL, @@ -1410,24 +2116,178 @@ static int wa_xfer_status_to_errno(u8 status)  }  /* + * If a last segment flag and/or a transfer result error is encountered, + * no other segment transfer results will be returned from the device. + * Mark the remaining submitted or pending xfers as completed so that + * the xfer will complete cleanly. + * + * xfer->lock must be held + * + */ +static void wa_complete_remaining_xfer_segs(struct wa_xfer *xfer, +		int starting_index, enum wa_seg_status status) +{ +	int index; +	struct wa_rpipe *rpipe = xfer->ep->hcpriv; + +	for (index = starting_index; index < xfer->segs_submitted; index++) { +		struct wa_seg *current_seg = xfer->seg[index]; + +		BUG_ON(current_seg == NULL); + +		switch (current_seg->status) { +		case WA_SEG_SUBMITTED: +		case WA_SEG_PENDING: +		case WA_SEG_DTI_PENDING: +			rpipe_avail_inc(rpipe); +		/* +		 * do not increment RPIPE avail for the WA_SEG_DELAYED case +		 * since it has not been submitted to the RPIPE. +		 */ +		case WA_SEG_DELAYED: +			xfer->segs_done++; +			current_seg->status = status; +			break; +		case WA_SEG_ABORTED: +			break; +		default: +			WARN(1, "%s: xfer 0x%08X#%d. bad seg status = %d\n", +				__func__, wa_xfer_id(xfer), index, +				current_seg->status); +			break; +		} +	} +} + +/* Populate the given urb based on the current isoc transfer state. */ +static int __wa_populate_buf_in_urb_isoc(struct wahc *wa, +	struct urb *buf_in_urb, struct wa_xfer *xfer, struct wa_seg *seg) +{ +	int urb_start_frame = seg->isoc_frame_index + seg->isoc_frame_offset; +	int seg_index, total_len = 0, urb_frame_index = urb_start_frame; +	struct usb_iso_packet_descriptor *iso_frame_desc = +						xfer->urb->iso_frame_desc; +	const int dti_packet_size = usb_endpoint_maxp(wa->dti_epd); +	int next_frame_contiguous; +	struct usb_iso_packet_descriptor *iso_frame; + +	BUG_ON(buf_in_urb->status == -EINPROGRESS); + +	/* +	 * If the current frame actual_length is contiguous with the next frame +	 * and actual_length is a multiple of the DTI endpoint max packet size, +	 * combine the current frame with the next frame in a single URB.  This +	 * reduces the number of URBs that must be submitted in that case. +	 */ +	seg_index = seg->isoc_frame_index; +	do { +		next_frame_contiguous = 0; + +		iso_frame = &iso_frame_desc[urb_frame_index]; +		total_len += iso_frame->actual_length; +		++urb_frame_index; +		++seg_index; + +		if (seg_index < seg->isoc_frame_count) { +			struct usb_iso_packet_descriptor *next_iso_frame; + +			next_iso_frame = &iso_frame_desc[urb_frame_index]; + +			if ((iso_frame->offset + iso_frame->actual_length) == +				next_iso_frame->offset) +				next_frame_contiguous = 1; +		} +	} while (next_frame_contiguous +			&& ((iso_frame->actual_length % dti_packet_size) == 0)); + +	/* this should always be 0 before a resubmit. */ +	buf_in_urb->num_mapped_sgs	= 0; +	buf_in_urb->transfer_dma = xfer->urb->transfer_dma + +		iso_frame_desc[urb_start_frame].offset; +	buf_in_urb->transfer_buffer_length = total_len; +	buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +	buf_in_urb->transfer_buffer = NULL; +	buf_in_urb->sg = NULL; +	buf_in_urb->num_sgs = 0; +	buf_in_urb->context = seg; + +	/* return the number of frames included in this URB. */ +	return seg_index - seg->isoc_frame_index; +} + +/* Populate the given urb based on the current transfer state. */ +static int wa_populate_buf_in_urb(struct urb *buf_in_urb, struct wa_xfer *xfer, +	unsigned int seg_idx, unsigned int bytes_transferred) +{ +	int result = 0; +	struct wa_seg *seg = xfer->seg[seg_idx]; + +	BUG_ON(buf_in_urb->status == -EINPROGRESS); +	/* this should always be 0 before a resubmit. */ +	buf_in_urb->num_mapped_sgs	= 0; + +	if (xfer->is_dma) { +		buf_in_urb->transfer_dma = xfer->urb->transfer_dma +			+ (seg_idx * xfer->seg_size); +		buf_in_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; +		buf_in_urb->transfer_buffer = NULL; +		buf_in_urb->sg = NULL; +		buf_in_urb->num_sgs = 0; +	} else { +		/* do buffer or SG processing. */ +		buf_in_urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP; + +		if (xfer->urb->transfer_buffer) { +			buf_in_urb->transfer_buffer = +				xfer->urb->transfer_buffer +				+ (seg_idx * xfer->seg_size); +			buf_in_urb->sg = NULL; +			buf_in_urb->num_sgs = 0; +		} else { +			/* allocate an SG list to store seg_size bytes +				and copy the subset of the xfer->urb->sg +				that matches the buffer subset we are +				about to read. */ +			buf_in_urb->sg = wa_xfer_create_subset_sg( +				xfer->urb->sg, +				seg_idx * xfer->seg_size, +				bytes_transferred, +				&(buf_in_urb->num_sgs)); + +			if (!(buf_in_urb->sg)) { +				buf_in_urb->num_sgs	= 0; +				result = -ENOMEM; +			} +			buf_in_urb->transfer_buffer = NULL; +		} +	} +	buf_in_urb->transfer_buffer_length = bytes_transferred; +	buf_in_urb->context = seg; + +	return result; +} + +/*   * Process a xfer result completion message   * - * inbound transfers: need to schedule a DTI read + * inbound transfers: need to schedule a buf_in_urb read   *   * FIXME: this function needs to be broken up in parts   */ -static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer) +static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer, +		struct wa_xfer_result *xfer_result)  {  	int result;  	struct device *dev = &wa->usb_iface->dev;  	unsigned long flags; -	u8 seg_idx; +	unsigned int seg_idx;  	struct wa_seg *seg;  	struct wa_rpipe *rpipe; -	struct wa_xfer_result *xfer_result = wa->xfer_result; -	u8 done = 0; +	unsigned done = 0;  	u8 usb_status;  	unsigned rpipe_ready = 0; +	unsigned bytes_transferred = le32_to_cpu(xfer_result->dwTransferLength); +	struct urb *buf_in_urb = &(wa->buf_in_urbs[0]);  	spin_lock_irqsave(&xfer->lock, flags);  	seg_idx = xfer_result->bTransferSegment & 0x7f; @@ -1436,8 +2296,8 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer)  	seg = xfer->seg[seg_idx];  	rpipe = xfer->ep->hcpriv;  	usb_status = xfer_result->bTransferStatus; -	dev_dbg(dev, "xfer %p#%u: bTransferStatus 0x%02x (seg status %u)\n", -		xfer, seg_idx, usb_status, seg->status); +	dev_dbg(dev, "xfer %p ID 0x%08X#%u: bTransferStatus 0x%02x (seg status %u)\n", +		xfer, wa_xfer_id(xfer), seg_idx, usb_status, seg->status);  	if (seg->status == WA_SEG_ABORTED  	    || seg->status == WA_SEG_ERROR)	/* already handled */  		goto segment_aborted; @@ -1451,71 +2311,48 @@ static void wa_xfer_result_chew(struct wahc *wa, struct wa_xfer *xfer)  	}  	if (usb_status & 0x80) {  		seg->result = wa_xfer_status_to_errno(usb_status); -		dev_err(dev, "DTI: xfer %p#:%08X:%u failed (0x%02x)\n", +		dev_err(dev, "DTI: xfer %p 0x%08X:#%u failed (0x%02x)\n",  			xfer, xfer->id, seg->index, usb_status); +		seg->status = ((usb_status & 0x7F) == WA_XFER_STATUS_ABORTED) ? +			WA_SEG_ABORTED : WA_SEG_ERROR;  		goto error_complete;  	}  	/* FIXME: we ignore warnings, tally them for stats */  	if (usb_status & 0x40) 		/* Warning?... */  		usb_status = 0;		/* ... pass */ -	if (xfer->is_inbound) {	/* IN data phase: read to buffer */ +	/* +	 * If the last segment bit is set, complete the remaining segments. +	 * When the current segment is completed, either in wa_buf_in_cb for +	 * transfers with data or below for no data, the xfer will complete. +	 */ +	if (xfer_result->bTransferSegment & 0x80) +		wa_complete_remaining_xfer_segs(xfer, seg->index + 1, +			WA_SEG_DONE); +	if (usb_pipeisoc(xfer->urb->pipe) +		&& (le32_to_cpu(xfer_result->dwNumOfPackets) > 0)) { +		/* set up WA state to read the isoc packet status next. */ +		wa->dti_isoc_xfer_in_progress = wa_xfer_id(xfer); +		wa->dti_isoc_xfer_seg = seg_idx; +		wa->dti_state = WA_DTI_ISOC_PACKET_STATUS_PENDING; +	} else if (xfer->is_inbound && !usb_pipeisoc(xfer->urb->pipe) +			&& (bytes_transferred > 0)) { +		/* IN data phase: read to buffer */  		seg->status = WA_SEG_DTI_PENDING; -		BUG_ON(wa->buf_in_urb->status == -EINPROGRESS); -		/* this should always be 0 before a resubmit. */ -		wa->buf_in_urb->num_mapped_sgs	= 0; - -		if (xfer->is_dma) { -			wa->buf_in_urb->transfer_dma = -				xfer->urb->transfer_dma -				+ (seg_idx * xfer->seg_size); -			wa->buf_in_urb->transfer_flags -				|= URB_NO_TRANSFER_DMA_MAP; -			wa->buf_in_urb->transfer_buffer = NULL; -			wa->buf_in_urb->sg = NULL; -			wa->buf_in_urb->num_sgs = 0; -		} else { -			/* do buffer or SG processing. */ -			wa->buf_in_urb->transfer_flags -				&= ~URB_NO_TRANSFER_DMA_MAP; - -			if (xfer->urb->transfer_buffer) { -				wa->buf_in_urb->transfer_buffer = -					xfer->urb->transfer_buffer -					+ (seg_idx * xfer->seg_size); -				wa->buf_in_urb->sg = NULL; -				wa->buf_in_urb->num_sgs = 0; -			} else { -				/* allocate an SG list to store seg_size bytes -					and copy the subset of the xfer->urb->sg -					that matches the buffer subset we are -					about to read. */ -				wa->buf_in_urb->sg = wa_xfer_create_subset_sg( -					xfer->urb->sg, -					seg_idx * xfer->seg_size, -					le32_to_cpu( -						xfer_result->dwTransferLength), -					&(wa->buf_in_urb->num_sgs)); - -				if (!(wa->buf_in_urb->sg)) { -					wa->buf_in_urb->num_sgs	= 0; -					goto error_sg_alloc; -				} -				wa->buf_in_urb->transfer_buffer = NULL; -			} -		} -		wa->buf_in_urb->transfer_buffer_length = -			le32_to_cpu(xfer_result->dwTransferLength); -		wa->buf_in_urb->context = seg; -		result = usb_submit_urb(wa->buf_in_urb, GFP_ATOMIC); +		result = wa_populate_buf_in_urb(buf_in_urb, xfer, seg_idx, +			bytes_transferred);  		if (result < 0) +			goto error_buf_in_populate; +		++(wa->active_buf_in_urbs); +		result = usb_submit_urb(buf_in_urb, GFP_ATOMIC); +		if (result < 0) { +			--(wa->active_buf_in_urbs);  			goto error_submit_buf_in; +		}  	} else { -		/* OUT data phase, complete it -- */ -		seg->status = WA_SEG_DONE; -		seg->result = le32_to_cpu(xfer_result->dwTransferLength); -		xfer->segs_done++; +		/* OUT data phase or no data, complete it -- */ +		seg->result = bytes_transferred;  		rpipe_ready = rpipe_avail_inc(rpipe); -		done = __wa_xfer_is_done(xfer); +		done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_DONE);  	}  	spin_unlock_irqrestore(&xfer->lock, flags);  	if (done) @@ -1534,13 +2371,15 @@ error_submit_buf_in:  		dev_err(dev, "xfer %p#%u: can't submit DTI data phase: %d\n",  			xfer, seg_idx, result);  	seg->result = result; -	kfree(wa->buf_in_urb->sg); -error_sg_alloc: +	kfree(buf_in_urb->sg); +	buf_in_urb->sg = NULL; +error_buf_in_populate:  	__wa_xfer_abort(xfer); -error_complete:  	seg->status = WA_SEG_ERROR; +error_complete:  	xfer->segs_done++;  	rpipe_ready = rpipe_avail_inc(rpipe); +	wa_complete_remaining_xfer_segs(xfer, seg->index + 1, seg->status);  	done = __wa_xfer_is_done(xfer);  	/*  	 * queue work item to clear STALL for control endpoints. @@ -1551,12 +2390,10 @@ error_complete:  		done) {  		dev_info(dev, "Control EP stall.  Queue delayed work.\n"); -		spin_lock_irq(&wa->xfer_list_lock); -		/* remove xfer from xfer_list. */ -		list_del(&xfer->list_node); -		/* add xfer to xfer_errored_list. */ -		list_add_tail(&xfer->list_node, &wa->xfer_errored_list); -		spin_unlock_irq(&wa->xfer_list_lock); +		spin_lock(&wa->xfer_list_lock); +		/* move xfer from xfer_list to xfer_errored_list. */ +		list_move_tail(&xfer->list_node, &wa->xfer_errored_list); +		spin_unlock(&wa->xfer_list_lock);  		spin_unlock_irqrestore(&xfer->lock, flags);  		queue_work(wusbd, &wa->xfer_error_work);  	} else { @@ -1571,7 +2408,7 @@ error_complete:  error_bad_seg:  	spin_unlock_irqrestore(&xfer->lock, flags); -	wa_urb_dequeue(wa, xfer->urb); +	wa_urb_dequeue(wa, xfer->urb, -ENOENT);  	if (printk_ratelimit())  		dev_err(dev, "xfer %p#%u: bad segment\n", xfer, seg_idx);  	if (edc_inc(&wa->dti_edc, EDC_MAX_ERRORS, EDC_ERROR_TIMEFRAME)) { @@ -1587,6 +2424,154 @@ segment_aborted:  }  /* + * Process a isochronous packet status message + * + * inbound transfers: need to schedule a buf_in_urb read + */ +static int wa_process_iso_packet_status(struct wahc *wa, struct urb *urb) +{ +	struct device *dev = &wa->usb_iface->dev; +	struct wa_xfer_packet_status_hwaiso *packet_status; +	struct wa_xfer_packet_status_len_hwaiso *status_array; +	struct wa_xfer *xfer; +	unsigned long flags; +	struct wa_seg *seg; +	struct wa_rpipe *rpipe; +	unsigned done = 0, dti_busy = 0, data_frame_count = 0, seg_index; +	unsigned first_frame_index = 0, rpipe_ready = 0; +	int expected_size; + +	/* We have a xfer result buffer; check it */ +	dev_dbg(dev, "DTI: isoc packet status %d bytes at %p\n", +		urb->actual_length, urb->transfer_buffer); +	packet_status = (struct wa_xfer_packet_status_hwaiso *)(wa->dti_buf); +	if (packet_status->bPacketType != WA_XFER_ISO_PACKET_STATUS) { +		dev_err(dev, "DTI Error: isoc packet status--bad type 0x%02x\n", +			packet_status->bPacketType); +		goto error_parse_buffer; +	} +	xfer = wa_xfer_get_by_id(wa, wa->dti_isoc_xfer_in_progress); +	if (xfer == NULL) { +		dev_err(dev, "DTI Error: isoc packet status--unknown xfer 0x%08x\n", +			wa->dti_isoc_xfer_in_progress); +		goto error_parse_buffer; +	} +	spin_lock_irqsave(&xfer->lock, flags); +	if (unlikely(wa->dti_isoc_xfer_seg >= xfer->segs)) +		goto error_bad_seg; +	seg = xfer->seg[wa->dti_isoc_xfer_seg]; +	rpipe = xfer->ep->hcpriv; +	expected_size = sizeof(*packet_status) + +			(sizeof(packet_status->PacketStatus[0]) * +			seg->isoc_frame_count); +	if (urb->actual_length != expected_size) { +		dev_err(dev, "DTI Error: isoc packet status--bad urb length (%d bytes vs %d needed)\n", +			urb->actual_length, expected_size); +		goto error_bad_seg; +	} +	if (le16_to_cpu(packet_status->wLength) != expected_size) { +		dev_err(dev, "DTI Error: isoc packet status--bad length %u\n", +			le16_to_cpu(packet_status->wLength)); +		goto error_bad_seg; +	} +	/* write isoc packet status and lengths back to the xfer urb. */ +	status_array = packet_status->PacketStatus; +	xfer->urb->start_frame = +		wa->wusb->usb_hcd.driver->get_frame_number(&wa->wusb->usb_hcd); +	for (seg_index = 0; seg_index < seg->isoc_frame_count; ++seg_index) { +		struct usb_iso_packet_descriptor *iso_frame_desc = +			xfer->urb->iso_frame_desc; +		const int xfer_frame_index = +			seg->isoc_frame_offset + seg_index; + +		iso_frame_desc[xfer_frame_index].status = +			wa_xfer_status_to_errno( +			le16_to_cpu(status_array[seg_index].PacketStatus)); +		iso_frame_desc[xfer_frame_index].actual_length = +			le16_to_cpu(status_array[seg_index].PacketLength); +		/* track the number of frames successfully transferred. */ +		if (iso_frame_desc[xfer_frame_index].actual_length > 0) { +			/* save the starting frame index for buf_in_urb. */ +			if (!data_frame_count) +				first_frame_index = seg_index; +			++data_frame_count; +		} +	} + +	if (xfer->is_inbound && data_frame_count) { +		int result, total_frames_read = 0, urb_index = 0; +		struct urb *buf_in_urb; + +		/* IN data phase: read to buffer */ +		seg->status = WA_SEG_DTI_PENDING; + +		/* start with the first frame with data. */ +		seg->isoc_frame_index = first_frame_index; +		/* submit up to WA_MAX_BUF_IN_URBS read URBs. */ +		do { +			int urb_frame_index, urb_frame_count; +			struct usb_iso_packet_descriptor *iso_frame_desc; + +			buf_in_urb = &(wa->buf_in_urbs[urb_index]); +			urb_frame_count = __wa_populate_buf_in_urb_isoc(wa, +				buf_in_urb, xfer, seg); +			/* advance frame index to start of next read URB. */ +			seg->isoc_frame_index += urb_frame_count; +			total_frames_read += urb_frame_count; + +			++(wa->active_buf_in_urbs); +			result = usb_submit_urb(buf_in_urb, GFP_ATOMIC); + +			/* skip 0-byte frames. */ +			urb_frame_index = +				seg->isoc_frame_offset + seg->isoc_frame_index; +			iso_frame_desc = +				&(xfer->urb->iso_frame_desc[urb_frame_index]); +			while ((seg->isoc_frame_index < +						seg->isoc_frame_count) && +				 (iso_frame_desc->actual_length == 0)) { +				++(seg->isoc_frame_index); +				++iso_frame_desc; +			} +			++urb_index; + +		} while ((result == 0) && (urb_index < WA_MAX_BUF_IN_URBS) +				&& (seg->isoc_frame_index < +						seg->isoc_frame_count)); + +		if (result < 0) { +			--(wa->active_buf_in_urbs); +			dev_err(dev, "DTI Error: Could not submit buf in URB (%d)", +				result); +			wa_reset_all(wa); +		} else if (data_frame_count > total_frames_read) +			/* If we need to read more frames, set DTI busy. */ +			dti_busy = 1; +	} else { +		/* OUT transfer or no more IN data, complete it -- */ +		rpipe_ready = rpipe_avail_inc(rpipe); +		done = __wa_xfer_mark_seg_as_done(xfer, seg, WA_SEG_DONE); +	} +	spin_unlock_irqrestore(&xfer->lock, flags); +	if (dti_busy) +		wa->dti_state = WA_DTI_BUF_IN_DATA_PENDING; +	else +		wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING; +	if (done) +		wa_xfer_completion(xfer); +	if (rpipe_ready) +		wa_xfer_delayed_run(rpipe); +	wa_xfer_put(xfer); +	return dti_busy; + +error_bad_seg: +	spin_unlock_irqrestore(&xfer->lock, flags); +	wa_xfer_put(xfer); +error_parse_buffer: +	return dti_busy; +} + +/*   * Callback for the IN data phase   *   * If successful transition state; otherwise, take a note of the @@ -1603,27 +2588,86 @@ static void wa_buf_in_cb(struct urb *urb)  	struct wahc *wa;  	struct device *dev;  	struct wa_rpipe *rpipe; -	unsigned rpipe_ready; +	unsigned rpipe_ready = 0, isoc_data_frame_count = 0;  	unsigned long flags; +	int resubmit_dti = 0, active_buf_in_urbs;  	u8 done = 0;  	/* free the sg if it was used. */  	kfree(urb->sg);  	urb->sg = NULL; +	spin_lock_irqsave(&xfer->lock, flags); +	wa = xfer->wa; +	dev = &wa->usb_iface->dev; +	--(wa->active_buf_in_urbs); +	active_buf_in_urbs = wa->active_buf_in_urbs; + +	if (usb_pipeisoc(xfer->urb->pipe)) { +		struct usb_iso_packet_descriptor *iso_frame_desc = +			xfer->urb->iso_frame_desc; +		int	seg_index; + +		/* +		 * Find the next isoc frame with data and count how many +		 * frames with data remain. +		 */ +		seg_index = seg->isoc_frame_index; +		while (seg_index < seg->isoc_frame_count) { +			const int urb_frame_index = +				seg->isoc_frame_offset + seg_index; + +			if (iso_frame_desc[urb_frame_index].actual_length > 0) { +				/* save the index of the next frame with data */ +				if (!isoc_data_frame_count) +					seg->isoc_frame_index = seg_index; +				++isoc_data_frame_count; +			} +			++seg_index; +		} +	} +	spin_unlock_irqrestore(&xfer->lock, flags); +  	switch (urb->status) {  	case 0:  		spin_lock_irqsave(&xfer->lock, flags); -		wa = xfer->wa; -		dev = &wa->usb_iface->dev; -		rpipe = xfer->ep->hcpriv; -		dev_dbg(dev, "xfer %p#%u: data in done (%zu bytes)\n", -			xfer, seg->index, (size_t)urb->actual_length); -		seg->status = WA_SEG_DONE; -		seg->result = urb->actual_length; -		xfer->segs_done++; -		rpipe_ready = rpipe_avail_inc(rpipe); -		done = __wa_xfer_is_done(xfer); + +		seg->result += urb->actual_length; +		if (isoc_data_frame_count > 0) { +			int result, urb_frame_count; + +			/* submit a read URB for the next frame with data. */ +			urb_frame_count = __wa_populate_buf_in_urb_isoc(wa, urb, +				 xfer, seg); +			/* advance index to start of next read URB. */ +			seg->isoc_frame_index += urb_frame_count; +			++(wa->active_buf_in_urbs); +			result = usb_submit_urb(urb, GFP_ATOMIC); +			if (result < 0) { +				--(wa->active_buf_in_urbs); +				dev_err(dev, "DTI Error: Could not submit buf in URB (%d)", +					result); +				wa_reset_all(wa); +			} +			/* +			 * If we are in this callback and +			 * isoc_data_frame_count > 0, it means that the dti_urb +			 * submission was delayed in wa_dti_cb.  Once +			 * we submit the last buf_in_urb, we can submit the +			 * delayed dti_urb. +			 */ +			  resubmit_dti = (isoc_data_frame_count == +							urb_frame_count); +		} else if (active_buf_in_urbs == 0) { +			rpipe = xfer->ep->hcpriv; +			dev_dbg(dev, +				"xfer %p 0x%08X#%u: data in done (%zu bytes)\n", +				xfer, wa_xfer_id(xfer), seg->index, +				seg->result); +			rpipe_ready = rpipe_avail_inc(rpipe); +			done = __wa_xfer_mark_seg_as_done(xfer, seg, +					WA_SEG_DONE); +		}  		spin_unlock_irqrestore(&xfer->lock, flags);  		if (done)  			wa_xfer_completion(xfer); @@ -1634,31 +2678,50 @@ static void wa_buf_in_cb(struct urb *urb)  	case -ENOENT:		/* as it was done by the who unlinked us */  		break;  	default:		/* Other errors ... */ +		/* +		 * Error on data buf read.  Only resubmit DTI if it hasn't +		 * already been done by previously hitting this error or by a +		 * successful completion of the previous buf_in_urb. +		 */ +		resubmit_dti = wa->dti_state != WA_DTI_TRANSFER_RESULT_PENDING;  		spin_lock_irqsave(&xfer->lock, flags); -		wa = xfer->wa; -		dev = &wa->usb_iface->dev;  		rpipe = xfer->ep->hcpriv;  		if (printk_ratelimit()) -			dev_err(dev, "xfer %p#%u: data in error %d\n", -				xfer, seg->index, urb->status); +			dev_err(dev, "xfer %p 0x%08X#%u: data in error %d\n", +				xfer, wa_xfer_id(xfer), seg->index, +				urb->status);  		if (edc_inc(&wa->nep_edc, EDC_MAX_ERRORS,  			    EDC_ERROR_TIMEFRAME)){  			dev_err(dev, "DTO: URB max acceptable errors "  				"exceeded, resetting device\n");  			wa_reset_all(wa);  		} -		seg->status = WA_SEG_ERROR;  		seg->result = urb->status; -		xfer->segs_done++;  		rpipe_ready = rpipe_avail_inc(rpipe); -		__wa_xfer_abort(xfer); -		done = __wa_xfer_is_done(xfer); +		if (active_buf_in_urbs == 0) +			done = __wa_xfer_mark_seg_as_done(xfer, seg, +				WA_SEG_ERROR); +		else +			__wa_xfer_abort(xfer);  		spin_unlock_irqrestore(&xfer->lock, flags);  		if (done)  			wa_xfer_completion(xfer);  		if (rpipe_ready)  			wa_xfer_delayed_run(rpipe);  	} + +	if (resubmit_dti) { +		int result; + +		wa->dti_state = WA_DTI_TRANSFER_RESULT_PENDING; + +		result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC); +		if (result < 0) { +			dev_err(dev, "DTI Error: Could not submit DTI URB (%d)\n", +				result); +			wa_reset_all(wa); +		} +	}  }  /* @@ -1687,56 +2750,65 @@ static void wa_buf_in_cb(struct urb *urb)   * We go back to OFF when we detect a ENOENT or ESHUTDOWN (or too many   * errors) in the URBs.   */ -static void wa_xfer_result_cb(struct urb *urb) +static void wa_dti_cb(struct urb *urb)  { -	int result; +	int result, dti_busy = 0;  	struct wahc *wa = urb->context;  	struct device *dev = &wa->usb_iface->dev; -	struct wa_xfer_result *xfer_result;  	u32 xfer_id; -	struct wa_xfer *xfer;  	u8 usb_status;  	BUG_ON(wa->dti_urb != urb);  	switch (wa->dti_urb->status) {  	case 0: -		/* We have a xfer result buffer; check it */ -		dev_dbg(dev, "DTI: xfer result %d bytes at %p\n", -			urb->actual_length, urb->transfer_buffer); -		if (wa->dti_urb->actual_length != sizeof(*xfer_result)) { -			dev_err(dev, "DTI Error: xfer result--bad size " -				"xfer result (%d bytes vs %zu needed)\n", -				urb->actual_length, sizeof(*xfer_result)); -			break; -		} -		xfer_result = wa->xfer_result; -		if (xfer_result->hdr.bLength != sizeof(*xfer_result)) { -			dev_err(dev, "DTI Error: xfer result--" -				"bad header length %u\n", -				xfer_result->hdr.bLength); -			break; -		} -		if (xfer_result->hdr.bNotifyType != WA_XFER_RESULT) { -			dev_err(dev, "DTI Error: xfer result--" -				"bad header type 0x%02x\n", -				xfer_result->hdr.bNotifyType); -			break; -		} -		usb_status = xfer_result->bTransferStatus & 0x3f; -		if (usb_status == WA_XFER_STATUS_NOT_FOUND) -			/* taken care of already */ -			break; -		xfer_id = xfer_result->dwTransferID; -		xfer = wa_xfer_get_by_id(wa, xfer_id); -		if (xfer == NULL) { -			/* FIXME: transaction might have been cancelled */ -			dev_err(dev, "DTI Error: xfer result--" -				"unknown xfer 0x%08x (status 0x%02x)\n", -				xfer_id, usb_status); -			break; +		if (wa->dti_state == WA_DTI_TRANSFER_RESULT_PENDING) { +			struct wa_xfer_result *xfer_result; +			struct wa_xfer *xfer; + +			/* We have a xfer result buffer; check it */ +			dev_dbg(dev, "DTI: xfer result %d bytes at %p\n", +				urb->actual_length, urb->transfer_buffer); +			if (urb->actual_length != sizeof(*xfer_result)) { +				dev_err(dev, "DTI Error: xfer result--bad size xfer result (%d bytes vs %zu needed)\n", +					urb->actual_length, +					sizeof(*xfer_result)); +				break; +			} +			xfer_result = (struct wa_xfer_result *)(wa->dti_buf); +			if (xfer_result->hdr.bLength != sizeof(*xfer_result)) { +				dev_err(dev, "DTI Error: xfer result--bad header length %u\n", +					xfer_result->hdr.bLength); +				break; +			} +			if (xfer_result->hdr.bNotifyType != WA_XFER_RESULT) { +				dev_err(dev, "DTI Error: xfer result--bad header type 0x%02x\n", +					xfer_result->hdr.bNotifyType); +				break; +			} +			xfer_id = le32_to_cpu(xfer_result->dwTransferID); +			usb_status = xfer_result->bTransferStatus & 0x3f; +			if (usb_status == WA_XFER_STATUS_NOT_FOUND) { +				/* taken care of already */ +				dev_dbg(dev, "%s: xfer 0x%08X#%u not found.\n", +					__func__, xfer_id, +					xfer_result->bTransferSegment & 0x7f); +				break; +			} +			xfer = wa_xfer_get_by_id(wa, xfer_id); +			if (xfer == NULL) { +				/* FIXME: transaction not found. */ +				dev_err(dev, "DTI Error: xfer result--unknown xfer 0x%08x (status 0x%02x)\n", +					xfer_id, usb_status); +				break; +			} +			wa_xfer_result_chew(wa, xfer, xfer_result); +			wa_xfer_put(xfer); +		} else if (wa->dti_state == WA_DTI_ISOC_PACKET_STATUS_PENDING) { +			dti_busy = wa_process_iso_packet_status(wa, urb); +		} else { +			dev_err(dev, "DTI Error: unexpected EP state = %d\n", +				wa->dti_state);  		} -		wa_xfer_result_chew(wa, xfer); -		wa_xfer_put(xfer);  		break;  	case -ENOENT:		/* (we killed the URB)...so, no broadcast */  	case -ESHUTDOWN:	/* going away! */ @@ -1755,18 +2827,69 @@ static void wa_xfer_result_cb(struct urb *urb)  			dev_err(dev, "DTI: URB error %d\n", urb->status);  		break;  	} -	/* Resubmit the DTI URB */ -	result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC); -	if (result < 0) { -		dev_err(dev, "DTI Error: Could not submit DTI URB (%d), " -			"resetting\n", result); -		wa_reset_all(wa); + +	/* Resubmit the DTI URB if we are not busy processing isoc in frames. */ +	if (!dti_busy) { +		result = usb_submit_urb(wa->dti_urb, GFP_ATOMIC); +		if (result < 0) { +			dev_err(dev, "DTI Error: Could not submit DTI URB (%d)\n", +				result); +			wa_reset_all(wa); +		}  	}  out:  	return;  }  /* + * Initialize the DTI URB for reading transfer result notifications and also + * the buffer-in URB, for reading buffers. Then we just submit the DTI URB. + */ +int wa_dti_start(struct wahc *wa) +{ +	const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd; +	struct device *dev = &wa->usb_iface->dev; +	int result = -ENOMEM, index; + +	if (wa->dti_urb != NULL)	/* DTI URB already started */ +		goto out; + +	wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL); +	if (wa->dti_urb == NULL) { +		dev_err(dev, "Can't allocate DTI URB\n"); +		goto error_dti_urb_alloc; +	} +	usb_fill_bulk_urb( +		wa->dti_urb, wa->usb_dev, +		usb_rcvbulkpipe(wa->usb_dev, 0x80 | dti_epd->bEndpointAddress), +		wa->dti_buf, wa->dti_buf_size, +		wa_dti_cb, wa); + +	/* init the buf in URBs */ +	for (index = 0; index < WA_MAX_BUF_IN_URBS; ++index) { +		usb_fill_bulk_urb( +			&(wa->buf_in_urbs[index]), wa->usb_dev, +			usb_rcvbulkpipe(wa->usb_dev, +				0x80 | dti_epd->bEndpointAddress), +			NULL, 0, wa_buf_in_cb, wa); +	} +	result = usb_submit_urb(wa->dti_urb, GFP_KERNEL); +	if (result < 0) { +		dev_err(dev, "DTI Error: Could not submit DTI URB (%d) resetting\n", +			result); +		goto error_dti_urb_submit; +	} +out: +	return 0; + +error_dti_urb_submit: +	usb_put_urb(wa->dti_urb); +	wa->dti_urb = NULL; +error_dti_urb_alloc: +	return result; +} +EXPORT_SYMBOL_GPL(wa_dti_start); +/*   * Transfer complete notification   *   * Called from the notif.c code. We get a notification on EP2 saying @@ -1777,18 +2900,13 @@ out:   * don't really set it up and start it until the first xfer complete   * notification arrives, which is what we do here.   * - * Follow up in wa_xfer_result_cb(), as that's where the whole state + * Follow up in wa_dti_cb(), as that's where the whole state   * machine starts.   * - * So here we just initialize the DTI URB for reading transfer result - * notifications and also the buffer-in URB, for reading buffers. Then - * we just submit the DTI URB. - *   * @wa shall be referenced   */  void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr)  { -	int result;  	struct device *dev = &wa->usb_iface->dev;  	struct wa_notif_xfer *notif_xfer;  	const struct usb_endpoint_descriptor *dti_epd = wa->dti_epd; @@ -1802,44 +2920,13 @@ void wa_handle_notif_xfer(struct wahc *wa, struct wa_notif_hdr *notif_hdr)  			notif_xfer->bEndpoint, dti_epd->bEndpointAddress);  		goto error;  	} -	if (wa->dti_urb != NULL)	/* DTI URB already started */ -		goto out; -	wa->dti_urb = usb_alloc_urb(0, GFP_KERNEL); -	if (wa->dti_urb == NULL) { -		dev_err(dev, "Can't allocate DTI URB\n"); -		goto error_dti_urb_alloc; -	} -	usb_fill_bulk_urb( -		wa->dti_urb, wa->usb_dev, -		usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint), -		wa->xfer_result, wa->xfer_result_size, -		wa_xfer_result_cb, wa); +	/* attempt to start the DTI ep processing. */ +	if (wa_dti_start(wa) < 0) +		goto error; -	wa->buf_in_urb = usb_alloc_urb(0, GFP_KERNEL); -	if (wa->buf_in_urb == NULL) { -		dev_err(dev, "Can't allocate BUF-IN URB\n"); -		goto error_buf_in_urb_alloc; -	} -	usb_fill_bulk_urb( -		wa->buf_in_urb, wa->usb_dev, -		usb_rcvbulkpipe(wa->usb_dev, 0x80 | notif_xfer->bEndpoint), -		NULL, 0, wa_buf_in_cb, wa); -	result = usb_submit_urb(wa->dti_urb, GFP_KERNEL); -	if (result < 0) { -		dev_err(dev, "DTI Error: Could not submit DTI URB (%d), " -			"resetting\n", result); -		goto error_dti_urb_submit; -	} -out:  	return; -error_dti_urb_submit: -	usb_put_urb(wa->buf_in_urb); -error_buf_in_urb_alloc: -	usb_put_urb(wa->dti_urb); -	wa->dti_urb = NULL; -error_dti_urb_alloc:  error:  	wa_reset_all(wa);  } diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c index 742c607d1fa..3e1ba51d1a4 100644 --- a/drivers/usb/wusbcore/wusbhc.c +++ b/drivers/usb/wusbcore/wusbhc.c @@ -55,7 +55,8 @@ static struct wusbhc *usbhc_dev_to_wusbhc(struct device *dev)   * value of trust_timeout is jiffies.   */  static ssize_t wusb_trust_timeout_show(struct device *dev, -				       struct device_attribute *attr, char *buf) +					struct device_attribute *attr, +					char *buf)  {  	struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev); @@ -173,7 +174,8 @@ static ssize_t wusb_phy_rate_store(struct device *dev,  	wusbhc->phy_rate = phy_rate;  	return size;  } -static DEVICE_ATTR(wusb_phy_rate, 0644, wusb_phy_rate_show, wusb_phy_rate_store); +static DEVICE_ATTR(wusb_phy_rate, 0644, wusb_phy_rate_show, +			wusb_phy_rate_store);  static ssize_t wusb_dnts_show(struct device *dev,  				  struct device_attribute *attr, @@ -227,7 +229,8 @@ static ssize_t wusb_retry_count_store(struct device *dev,  	if (result != 1)  		return -EINVAL; -	wusbhc->retry_count = max_t(uint8_t, retry_count, WUSB_RETRY_COUNT_MAX); +	wusbhc->retry_count = max_t(uint8_t, retry_count, +					WUSB_RETRY_COUNT_MAX);  	return size;  } @@ -321,7 +324,8 @@ int wusbhc_b_create(struct wusbhc *wusbhc)  	result = sysfs_create_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);  	if (result < 0) { -		dev_err(dev, "Cannot register WUSBHC attributes: %d\n", result); +		dev_err(dev, "Cannot register WUSBHC attributes: %d\n", +			result);  		goto error_create_attr_group;  	} @@ -419,13 +423,14 @@ EXPORT_SYMBOL_GPL(wusb_cluster_id_put);   *  - After a successful transfer, update the trust timeout timestamp   *    for the WUSB device.   * - *  - [WUSB] sections 4.13 and 7.5.1 specifies the stop retrasmittion + *  - [WUSB] sections 4.13 and 7.5.1 specify the stop retransmission   *    condition for the WCONNECTACK_IE is that the host has observed   *    the associated device responding to a control transfer.   */  void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, int status)  { -	struct wusb_dev *wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, urb->dev); +	struct wusb_dev *wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc, +					urb->dev);  	if (status == 0 && wusb_dev) {  		wusb_dev->entry_ts = jiffies; diff --git a/drivers/usb/wusbcore/wusbhc.h b/drivers/usb/wusbcore/wusbhc.h index 711b1952b11..2384add4537 100644 --- a/drivers/usb/wusbcore/wusbhc.h +++ b/drivers/usb/wusbcore/wusbhc.h @@ -97,6 +97,7 @@ struct wusb_dev {  	struct kref refcnt;  	struct wusbhc *wusbhc;  	struct list_head cack_node;	/* Connect-Ack list */ +	struct list_head rekey_node;	/* GTK rekey list */  	u8 port_idx;  	u8 addr;  	u8 beacon_type:4; @@ -107,8 +108,6 @@ struct wusb_dev {  	struct usb_wireless_cap_descriptor *wusb_cap_descr;  	struct uwb_mas_bm availability;  	struct work_struct devconnect_acked_work; -	struct urb *set_gtk_urb; -	struct usb_ctrlrequest *set_gtk_req;  	struct usb_device *usb_dev;  }; @@ -165,7 +164,7 @@ struct wusb_port {   * functions/operations that only deal with general Wireless USB HC   * issues use this data type to refer to the host.   * - * @usb_hcd 	   Instantiation of a USB host controller + * @usb_hcd	   Instantiation of a USB host controller   *                 (initialized by upper layer [HWA=HC or WHCI].   *   * @dev		   Device that implements this; initialized by the @@ -197,7 +196,7 @@ struct wusb_port {   * @ports_max	   Number of simultaneous device connections (fake   *                 ports) this HC will take. Read-only.   * - * @port      	   Array of port status for each fake root port. Guaranteed to + * @port	   Array of port status for each fake root port. Guaranteed to   *                 always be the same length during device existence   *                 [this allows for some unlocked but referenced reading].   * @@ -296,8 +295,7 @@ struct wusbhc {  	} __attribute__((packed)) gtk;  	u8 gtk_index;  	u32 gtk_tkid; -	struct work_struct gtk_rekey_done_work; -	int pending_set_gtks; +	struct work_struct gtk_rekey_work;  	struct usb_encryption_descriptor *ccm1_etd;  }; @@ -331,7 +329,8 @@ void wusbhc_pal_unregister(struct wusbhc *wusbhc);   * This is a safe assumption as @usb_dev->bus is referenced all the   * time during the @usb_dev life cycle.   */ -static inline struct usb_hcd *usb_hcd_get_by_usb_dev(struct usb_device *usb_dev) +static inline +struct usb_hcd *usb_hcd_get_by_usb_dev(struct usb_device *usb_dev)  {  	struct usb_hcd *usb_hcd;  	usb_hcd = container_of(usb_dev->bus, struct usb_hcd, self);  | 
