提交 6c90bbd0 编写于 作者: L Linus Torvalds

Merge tag 'usb-5.4-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Here are a lot of small USB driver fixes for 5.4-rc3.

  syzbot has stepped up its testing of the USB driver stack, now able to
  trigger fun race conditions between disconnect and probe functions.
  Because of that we have a lot of fixes in here from Johan and others
  fixing these reported issues that have been around since almost all
  time.

  We also are just deleting the rio500 driver, making all of the syzbot
  bugs found in it moot as it turns out no one has been using it for
  years as there is a userspace version that is being used instead.

  There are also a number of other small fixes in here, all resolving
  reported issues or regressions.

  All have been in linux-next without any reported issues"

* tag 'usb-5.4-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (65 commits)
  USB: yurex: fix NULL-derefs on disconnect
  USB: iowarrior: use pr_err()
  USB: iowarrior: drop redundant iowarrior mutex
  USB: iowarrior: drop redundant disconnect mutex
  USB: iowarrior: fix use-after-free after driver unbind
  USB: iowarrior: fix use-after-free on release
  USB: iowarrior: fix use-after-free on disconnect
  USB: chaoskey: fix use-after-free on release
  USB: adutux: fix use-after-free on release
  USB: ldusb: fix NULL-derefs on driver unbind
  USB: legousbtower: fix use-after-free on release
  usb: cdns3: Fix for incorrect DMA mask.
  usb: cdns3: fix cdns3_core_init_role()
  usb: cdns3: gadget: Fix full-speed mode
  USB: usb-skeleton: drop redundant in-urb check
  USB: usb-skeleton: fix use-after-free after driver unbind
  USB: usb-skeleton: fix NULL-deref on disconnect
  usb:cdns3: Fix for CV CH9 running with g_zero driver.
  usb: dwc3: Remove dev_err() on platform_get_irq() failure
  usb: dwc3: Switch to platform_get_irq_byname_optional()
  ...
...@@ -85,8 +85,8 @@ A child node must exist to represent the core DWC2 IP block. The name of ...@@ -85,8 +85,8 @@ A child node must exist to represent the core DWC2 IP block. The name of
the node is not important. The content of the node is defined in dwc2.txt. the node is not important. The content of the node is defined in dwc2.txt.
PHY documentation is provided in the following places: PHY documentation is provided in the following places:
- Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt - Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb2-phy.yaml
- Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt - Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb3-pcie-phy.yaml
Example device nodes: Example device nodes:
usb: usb@ffe09000 { usb: usb@ffe09000 {
......
...@@ -63,7 +63,11 @@ properties: ...@@ -63,7 +63,11 @@ properties:
description: description:
Set this flag to force EHCI reset after resume. Set this flag to force EHCI reset after resume.
phys: true phys:
description: PHY specifier for the USB PHY
phy-names:
const: usb
required: required:
- compatible - compatible
...@@ -89,6 +93,7 @@ examples: ...@@ -89,6 +93,7 @@ examples:
interrupts = <39>; interrupts = <39>;
clocks = <&ahb_gates 1>; clocks = <&ahb_gates 1>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
}; };
... ...
...@@ -67,7 +67,11 @@ properties: ...@@ -67,7 +67,11 @@ properties:
description: description:
Overrides the detected port count Overrides the detected port count
phys: true phys:
description: PHY specifier for the USB PHY
phy-names:
const: usb
required: required:
- compatible - compatible
...@@ -84,6 +88,7 @@ examples: ...@@ -84,6 +88,7 @@ examples:
interrupts = <64>; interrupts = <64>;
clocks = <&usb_clk 6>, <&ahb_gates 2>; clocks = <&usb_clk 6>, <&ahb_gates 2>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
}; };
... ...
...@@ -33,7 +33,7 @@ Required properties: ...@@ -33,7 +33,7 @@ Required properties:
"dma_ck": dma_bus clock for data transfer by DMA, "dma_ck": dma_bus clock for data transfer by DMA,
"xhci_ck": controller clock "xhci_ck": controller clock
- phys : see usb-hcd.txt in the current directory - phys : see usb-hcd.yaml in the current directory
Optional properties: Optional properties:
- wakeup-source : enable USB remote wakeup; - wakeup-source : enable USB remote wakeup;
...@@ -53,7 +53,7 @@ Optional properties: ...@@ -53,7 +53,7 @@ Optional properties:
See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
- imod-interval-ns: default interrupt moderation interval is 5000ns - imod-interval-ns: default interrupt moderation interval is 5000ns
additionally the properties from usb-hcd.txt (in the current directory) are additionally the properties from usb-hcd.yaml (in the current directory) are
supported. supported.
Example: Example:
......
...@@ -17,7 +17,7 @@ Required properties: ...@@ -17,7 +17,7 @@ Required properties:
- clock-names : must contain "sys_ck" for clock of controller, - clock-names : must contain "sys_ck" for clock of controller,
the following clocks are optional: the following clocks are optional:
"ref_ck", "mcu_ck" and "dma_ck"; "ref_ck", "mcu_ck" and "dma_ck";
- phys : see usb-hcd.txt in the current directory - phys : see usb-hcd.yaml in the current directory
- dr_mode : should be one of "host", "peripheral" or "otg", - dr_mode : should be one of "host", "peripheral" or "otg",
refer to usb/generic.txt refer to usb/generic.txt
...@@ -60,7 +60,7 @@ Optional properties: ...@@ -60,7 +60,7 @@ Optional properties:
- mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0, - mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0,
bit1 for u3port1, ... etc; bit1 for u3port1, ... etc;
additionally the properties from usb-hcd.txt (in the current directory) are additionally the properties from usb-hcd.yaml (in the current directory) are
supported. supported.
Sub-nodes: Sub-nodes:
......
...@@ -18,8 +18,13 @@ properties: ...@@ -18,8 +18,13 @@ properties:
description: description:
List of all the USB PHYs on this HCD List of all the USB PHYs on this HCD
phy-names:
description:
Name specifier for the USB PHY
examples: examples:
- | - |
usb { usb {
phys = <&usb2_phy1>, <&usb3_phy1>; phys = <&usb2_phy1>, <&usb3_phy1>;
phy-names = "usb";
}; };
...@@ -6,7 +6,7 @@ Required properties: ...@@ -6,7 +6,7 @@ Required properties:
- reg : Should contain 1 register ranges(address and length) - reg : Should contain 1 register ranges(address and length)
- interrupts : UHCI controller interrupt - interrupts : UHCI controller interrupt
additionally the properties from usb-hcd.txt (in the current directory) are additionally the properties from usb-hcd.yaml (in the current directory) are
supported. supported.
Example: Example:
......
...@@ -41,9 +41,9 @@ Optional properties: ...@@ -41,9 +41,9 @@ Optional properties:
- usb3-lpm-capable: determines if platform is USB3 LPM capable - usb3-lpm-capable: determines if platform is USB3 LPM capable
- quirk-broken-port-ped: set if the controller has broken port disable mechanism - quirk-broken-port-ped: set if the controller has broken port disable mechanism
- imod-interval-ns: default interrupt moderation interval is 5000ns - imod-interval-ns: default interrupt moderation interval is 5000ns
- phys : see usb-hcd.txt in the current directory - phys : see usb-hcd.yaml in the current directory
additionally the properties from usb-hcd.txt (in the current directory) are additionally the properties from usb-hcd.yaml (in the current directory) are
supported. supported.
......
============
Diamonds Rio
============
Copyright (C) 1999, 2000 Bruce Tenison
Portions Copyright (C) 1999, 2000 David Nelson
Thanks to David Nelson for guidance and the usage of the scanner.txt
and scanner.c files to model our driver and this informative file.
Mar. 2, 2000
Changes
=======
- Initial Revision
Overview
========
This README will address issues regarding how to configure the kernel
to access a RIO 500 mp3 player.
Before I explain how to use this to access the Rio500 please be warned:
.. warning::
Please note that this software is still under development. The authors
are in no way responsible for any damage that may occur, no matter how
inconsequential.
It seems that the Rio has a problem when sending .mp3 with low batteries.
I suggest when the batteries are low and you want to transfer stuff that you
replace it with a fresh one. In my case, what happened is I lost two 16kb
blocks (they are no longer usable to store information to it). But I don't
know if that's normal or not; it could simply be a problem with the flash
memory.
In an extreme case, I left my Rio playing overnight and the batteries wore
down to nothing and appear to have corrupted the flash memory. My RIO
needed to be replaced as a result. Diamond tech support is aware of the
problem. Do NOT allow your batteries to wear down to nothing before
changing them. It appears RIO 500 firmware does not handle low battery
power well at all.
On systems with OHCI controllers, the kernel OHCI code appears to have
power on problems with some chipsets. If you are having problems
connecting to your RIO 500, try turning it on first and then plugging it
into the USB cable.
Contact Information
-------------------
The main page for the project is hosted at sourceforge.net in the following
URL: <http://rio500.sourceforge.net>. You can also go to the project's
sourceforge home page at: <http://sourceforge.net/projects/rio500/>.
There is also a mailing list: rio500-users@lists.sourceforge.net
Authors
-------
Most of the code was written by Cesar Miquel <miquel@df.uba.ar>. Keith
Clayton <kclayton@jps.net> is incharge of the PPC port and making sure
things work there. Bruce Tenison <btenison@dibbs.net> is adding support
for .fon files and also does testing. The program will mostly sure be
re-written and Pete Ikusz along with the rest will re-design it. I would
also like to thank Tri Nguyen <tmn_3022000@hotmail.com> who provided use
with some important information regarding the communication with the Rio.
Additional Information and userspace tools
http://rio500.sourceforge.net/
Requirements
============
A host with a USB port running a Linux kernel with RIO 500 support enabled.
The driver is a module called rio500, which should be automatically loaded
as you plug in your device. If that fails you can manually load it with
modprobe rio500
Udev should automatically create a device node as soon as plug in your device.
If that fails, you can manually add a device for the USB rio500::
mknod /dev/usb/rio500 c 180 64
In that case, set appropriate permissions for /dev/usb/rio500 (don't forget
about group and world permissions). Both read and write permissions are
required for proper operation.
That's it. The Rio500 Utils at: http://rio500.sourceforge.net should
be able to access the rio500.
Limits
======
You can use only a single rio500 device at a time with your computer.
Bugs
====
If you encounter any problems feel free to drop me an email.
Bruce Tenison
btenison@dibbs.net
...@@ -16764,13 +16764,6 @@ W: http://www.linux-usb.org/usbnet ...@@ -16764,13 +16764,6 @@ W: http://www.linux-usb.org/usbnet
S: Maintained S: Maintained
F: drivers/net/usb/dm9601.c F: drivers/net/usb/dm9601.c
USB DIAMOND RIO500 DRIVER
M: Cesar Miquel <miquel@df.uba.ar>
L: rio500-users@lists.sourceforge.net
W: http://rio500.sourceforge.net
S: Maintained
F: drivers/usb/misc/rio500*
USB EHCI DRIVER USB EHCI DRIVER
M: Alan Stern <stern@rowland.harvard.edu> M: Alan Stern <stern@rowland.harvard.edu>
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
......
...@@ -520,6 +520,7 @@ ...@@ -520,6 +520,7 @@
interrupts = <39>; interrupts = <39>;
clocks = <&ccu CLK_AHB_EHCI0>; clocks = <&ccu CLK_AHB_EHCI0>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -529,6 +530,7 @@ ...@@ -529,6 +530,7 @@
interrupts = <64>; interrupts = <64>;
clocks = <&ccu CLK_USB_OHCI0>, <&ccu CLK_AHB_OHCI0>; clocks = <&ccu CLK_USB_OHCI0>, <&ccu CLK_AHB_OHCI0>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -608,6 +610,7 @@ ...@@ -608,6 +610,7 @@
interrupts = <40>; interrupts = <40>;
clocks = <&ccu CLK_AHB_EHCI1>; clocks = <&ccu CLK_AHB_EHCI1>;
phys = <&usbphy 2>; phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -617,6 +620,7 @@ ...@@ -617,6 +620,7 @@
interrupts = <65>; interrupts = <65>;
clocks = <&ccu CLK_USB_OHCI1>, <&ccu CLK_AHB_OHCI1>; clocks = <&ccu CLK_USB_OHCI1>, <&ccu CLK_AHB_OHCI1>;
phys = <&usbphy 2>; phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
......
...@@ -391,6 +391,7 @@ ...@@ -391,6 +391,7 @@
interrupts = <39>; interrupts = <39>;
clocks = <&ccu CLK_AHB_EHCI>; clocks = <&ccu CLK_AHB_EHCI>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -400,6 +401,7 @@ ...@@ -400,6 +401,7 @@
interrupts = <40>; interrupts = <40>;
clocks = <&ccu CLK_USB_OHCI>, <&ccu CLK_AHB_OHCI>; clocks = <&ccu CLK_USB_OHCI>, <&ccu CLK_AHB_OHCI>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
......
...@@ -545,6 +545,7 @@ ...@@ -545,6 +545,7 @@
clocks = <&ccu CLK_AHB1_EHCI0>; clocks = <&ccu CLK_AHB1_EHCI0>;
resets = <&ccu RST_AHB1_EHCI0>; resets = <&ccu RST_AHB1_EHCI0>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -555,6 +556,7 @@ ...@@ -555,6 +556,7 @@
clocks = <&ccu CLK_AHB1_OHCI0>, <&ccu CLK_USB_OHCI0>; clocks = <&ccu CLK_AHB1_OHCI0>, <&ccu CLK_USB_OHCI0>;
resets = <&ccu RST_AHB1_OHCI0>; resets = <&ccu RST_AHB1_OHCI0>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -565,6 +567,7 @@ ...@@ -565,6 +567,7 @@
clocks = <&ccu CLK_AHB1_EHCI1>; clocks = <&ccu CLK_AHB1_EHCI1>;
resets = <&ccu RST_AHB1_EHCI1>; resets = <&ccu RST_AHB1_EHCI1>;
phys = <&usbphy 2>; phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -575,6 +578,7 @@ ...@@ -575,6 +578,7 @@
clocks = <&ccu CLK_AHB1_OHCI1>, <&ccu CLK_USB_OHCI1>; clocks = <&ccu CLK_AHB1_OHCI1>, <&ccu CLK_USB_OHCI1>;
resets = <&ccu RST_AHB1_OHCI1>; resets = <&ccu RST_AHB1_OHCI1>;
phys = <&usbphy 2>; phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
......
...@@ -623,6 +623,7 @@ ...@@ -623,6 +623,7 @@
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_AHB_EHCI0>; clocks = <&ccu CLK_AHB_EHCI0>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -632,6 +633,7 @@ ...@@ -632,6 +633,7 @@
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_USB_OHCI0>, <&ccu CLK_AHB_OHCI0>; clocks = <&ccu CLK_USB_OHCI0>, <&ccu CLK_AHB_OHCI0>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -714,6 +716,7 @@ ...@@ -714,6 +716,7 @@
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_AHB_EHCI1>; clocks = <&ccu CLK_AHB_EHCI1>;
phys = <&usbphy 2>; phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -723,6 +726,7 @@ ...@@ -723,6 +726,7 @@
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_USB_OHCI1>, <&ccu CLK_AHB_OHCI1>; clocks = <&ccu CLK_USB_OHCI1>, <&ccu CLK_AHB_OHCI1>;
phys = <&usbphy 2>; phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
......
...@@ -307,6 +307,7 @@ ...@@ -307,6 +307,7 @@
clocks = <&ccu CLK_BUS_EHCI>; clocks = <&ccu CLK_BUS_EHCI>;
resets = <&ccu RST_BUS_EHCI>; resets = <&ccu RST_BUS_EHCI>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -317,6 +318,7 @@ ...@@ -317,6 +318,7 @@
clocks = <&ccu CLK_BUS_OHCI>, <&ccu CLK_USB_OHCI>; clocks = <&ccu CLK_BUS_OHCI>, <&ccu CLK_USB_OHCI>;
resets = <&ccu RST_BUS_OHCI>; resets = <&ccu RST_BUS_OHCI>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
......
...@@ -632,6 +632,7 @@ ...@@ -632,6 +632,7 @@
clocks = <&ccu CLK_BUS_EHCI0>; clocks = <&ccu CLK_BUS_EHCI0>;
resets = <&ccu RST_BUS_EHCI0>; resets = <&ccu RST_BUS_EHCI0>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -643,6 +644,7 @@ ...@@ -643,6 +644,7 @@
clocks = <&ccu CLK_BUS_OHCI0>, <&ccu CLK_USB_OHCI0>; clocks = <&ccu CLK_BUS_OHCI0>, <&ccu CLK_USB_OHCI0>;
resets = <&ccu RST_BUS_OHCI0>; resets = <&ccu RST_BUS_OHCI0>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -654,6 +656,7 @@ ...@@ -654,6 +656,7 @@
clocks = <&ccu CLK_BUS_EHCI1>; clocks = <&ccu CLK_BUS_EHCI1>;
resets = <&ccu RST_BUS_EHCI1>; resets = <&ccu RST_BUS_EHCI1>;
phys = <&usbphy 2>; phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
......
...@@ -273,6 +273,7 @@ ...@@ -273,6 +273,7 @@
clocks = <&ccu CLK_BUS_EHCI1>; clocks = <&ccu CLK_BUS_EHCI1>;
resets = <&ccu RST_BUS_EHCI1>; resets = <&ccu RST_BUS_EHCI1>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -284,6 +285,7 @@ ...@@ -284,6 +285,7 @@
<&ccu CLK_USB_OHCI1>; <&ccu CLK_USB_OHCI1>;
resets = <&ccu RST_BUS_OHCI1>; resets = <&ccu RST_BUS_OHCI1>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -294,6 +296,7 @@ ...@@ -294,6 +296,7 @@
clocks = <&ccu CLK_BUS_EHCI2>; clocks = <&ccu CLK_BUS_EHCI2>;
resets = <&ccu RST_BUS_EHCI2>; resets = <&ccu RST_BUS_EHCI2>;
phys = <&usbphy 2>; phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -305,6 +308,7 @@ ...@@ -305,6 +308,7 @@
<&ccu CLK_USB_OHCI2>; <&ccu CLK_USB_OHCI2>;
resets = <&ccu RST_BUS_OHCI2>; resets = <&ccu RST_BUS_OHCI2>;
phys = <&usbphy 2>; phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
......
...@@ -346,6 +346,7 @@ ...@@ -346,6 +346,7 @@
clocks = <&usb_clocks CLK_BUS_HCI0>; clocks = <&usb_clocks CLK_BUS_HCI0>;
resets = <&usb_clocks RST_USB0_HCI>; resets = <&usb_clocks RST_USB0_HCI>;
phys = <&usbphy1>; phys = <&usbphy1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -357,6 +358,7 @@ ...@@ -357,6 +358,7 @@
<&usb_clocks CLK_USB_OHCI0>; <&usb_clocks CLK_USB_OHCI0>;
resets = <&usb_clocks RST_USB0_HCI>; resets = <&usb_clocks RST_USB0_HCI>;
phys = <&usbphy1>; phys = <&usbphy1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -378,6 +380,7 @@ ...@@ -378,6 +380,7 @@
clocks = <&usb_clocks CLK_BUS_HCI1>; clocks = <&usb_clocks CLK_BUS_HCI1>;
resets = <&usb_clocks RST_USB1_HCI>; resets = <&usb_clocks RST_USB1_HCI>;
phys = <&usbphy2>; phys = <&usbphy2>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -407,6 +410,7 @@ ...@@ -407,6 +410,7 @@
clocks = <&usb_clocks CLK_BUS_HCI2>; clocks = <&usb_clocks CLK_BUS_HCI2>;
resets = <&usb_clocks RST_USB2_HCI>; resets = <&usb_clocks RST_USB2_HCI>;
phys = <&usbphy3>; phys = <&usbphy3>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -418,6 +422,7 @@ ...@@ -418,6 +422,7 @@
<&usb_clocks CLK_USB_OHCI2>; <&usb_clocks CLK_USB_OHCI2>;
resets = <&usb_clocks RST_USB2_HCI>; resets = <&usb_clocks RST_USB2_HCI>;
phys = <&usbphy3>; phys = <&usbphy3>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
......
...@@ -304,6 +304,7 @@ ...@@ -304,6 +304,7 @@
clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>; clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>;
resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>; resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -315,6 +316,7 @@ ...@@ -315,6 +316,7 @@
<&ccu CLK_USB_OHCI1>; <&ccu CLK_USB_OHCI1>;
resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>; resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -325,6 +327,7 @@ ...@@ -325,6 +327,7 @@
clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>; clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>;
resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>; resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>;
phys = <&usbphy 2>; phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -336,6 +339,7 @@ ...@@ -336,6 +339,7 @@
<&ccu CLK_USB_OHCI2>; <&ccu CLK_USB_OHCI2>;
resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>; resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>;
phys = <&usbphy 2>; phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -346,6 +350,7 @@ ...@@ -346,6 +350,7 @@
clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>; clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>;
resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>; resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>;
phys = <&usbphy 3>; phys = <&usbphy 3>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -357,6 +362,7 @@ ...@@ -357,6 +362,7 @@
<&ccu CLK_USB_OHCI3>; <&ccu CLK_USB_OHCI3>;
resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>; resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>;
phys = <&usbphy 3>; phys = <&usbphy 3>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
......
...@@ -91,7 +91,6 @@ CONFIG_USB_SERIAL_PL2303=m ...@@ -91,7 +91,6 @@ CONFIG_USB_SERIAL_PL2303=m
CONFIG_USB_SERIAL_CYBERJACK=m CONFIG_USB_SERIAL_CYBERJACK=m
CONFIG_USB_SERIAL_XIRCOM=m CONFIG_USB_SERIAL_XIRCOM=m
CONFIG_USB_SERIAL_OMNINET=m CONFIG_USB_SERIAL_OMNINET=m
CONFIG_USB_RIO500=m
CONFIG_EXT2_FS=m CONFIG_EXT2_FS=m
CONFIG_EXT3_FS=m CONFIG_EXT3_FS=m
CONFIG_MSDOS_FS=y CONFIG_MSDOS_FS=y
......
...@@ -195,7 +195,6 @@ CONFIG_USB_SERIAL_XIRCOM=m ...@@ -195,7 +195,6 @@ CONFIG_USB_SERIAL_XIRCOM=m
CONFIG_USB_SERIAL_OMNINET=m CONFIG_USB_SERIAL_OMNINET=m
CONFIG_USB_EMI62=m CONFIG_USB_EMI62=m
CONFIG_USB_EMI26=m CONFIG_USB_EMI26=m
CONFIG_USB_RIO500=m
CONFIG_USB_LEGOTOWER=m CONFIG_USB_LEGOTOWER=m
CONFIG_USB_LCD=m CONFIG_USB_LCD=m
CONFIG_USB_CYTHERM=m CONFIG_USB_CYTHERM=m
......
...@@ -581,7 +581,6 @@ CONFIG_USB_SERIAL_XIRCOM=m ...@@ -581,7 +581,6 @@ CONFIG_USB_SERIAL_XIRCOM=m
CONFIG_USB_SERIAL_OMNINET=m CONFIG_USB_SERIAL_OMNINET=m
CONFIG_USB_EMI62=m CONFIG_USB_EMI62=m
CONFIG_USB_EMI26=m CONFIG_USB_EMI26=m
CONFIG_USB_RIO500=m
CONFIG_USB_LEGOTOWER=m CONFIG_USB_LEGOTOWER=m
CONFIG_USB_LCD=m CONFIG_USB_LCD=m
CONFIG_USB_CYTHERM=m CONFIG_USB_CYTHERM=m
......
...@@ -327,7 +327,6 @@ CONFIG_USB_EMI62=m ...@@ -327,7 +327,6 @@ CONFIG_USB_EMI62=m
CONFIG_USB_EMI26=m CONFIG_USB_EMI26=m
CONFIG_USB_ADUTUX=m CONFIG_USB_ADUTUX=m
CONFIG_USB_SEVSEG=m CONFIG_USB_SEVSEG=m
CONFIG_USB_RIO500=m
CONFIG_USB_LEGOTOWER=m CONFIG_USB_LEGOTOWER=m
CONFIG_USB_LCD=m CONFIG_USB_LCD=m
CONFIG_USB_CYPRESS_CY7C63=m CONFIG_USB_CYPRESS_CY7C63=m
......
...@@ -189,7 +189,6 @@ CONFIG_USB_SERIAL_XIRCOM=m ...@@ -189,7 +189,6 @@ CONFIG_USB_SERIAL_XIRCOM=m
CONFIG_USB_SERIAL_OMNINET=m CONFIG_USB_SERIAL_OMNINET=m
CONFIG_USB_EMI62=m CONFIG_USB_EMI62=m
CONFIG_USB_EMI26=m CONFIG_USB_EMI26=m
CONFIG_USB_RIO500=m
CONFIG_USB_LEGOTOWER=m CONFIG_USB_LEGOTOWER=m
CONFIG_USB_LCD=m CONFIG_USB_LCD=m
CONFIG_USB_CYTHERM=m CONFIG_USB_CYTHERM=m
......
...@@ -104,6 +104,7 @@ ...@@ -104,6 +104,7 @@
&ehci0 { &ehci0 {
phys = <&usbphy 0>; phys = <&usbphy 0>;
phy-names = "usb";
status = "okay"; status = "okay";
}; };
...@@ -150,6 +151,7 @@ ...@@ -150,6 +151,7 @@
&ohci0 { &ohci0 {
phys = <&usbphy 0>; phys = <&usbphy 0>;
phy-names = "usb";
status = "okay"; status = "okay";
}; };
......
...@@ -553,6 +553,7 @@ ...@@ -553,6 +553,7 @@
resets = <&ccu RST_BUS_OHCI1>, resets = <&ccu RST_BUS_OHCI1>,
<&ccu RST_BUS_EHCI1>; <&ccu RST_BUS_EHCI1>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -564,6 +565,7 @@ ...@@ -564,6 +565,7 @@
<&ccu CLK_USB_OHCI1>; <&ccu CLK_USB_OHCI1>;
resets = <&ccu RST_BUS_OHCI1>; resets = <&ccu RST_BUS_OHCI1>;
phys = <&usbphy 1>; phys = <&usbphy 1>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
......
...@@ -547,6 +547,7 @@ ...@@ -547,6 +547,7 @@
resets = <&ccu RST_BUS_OHCI3>, resets = <&ccu RST_BUS_OHCI3>,
<&ccu RST_BUS_EHCI3>; <&ccu RST_BUS_EHCI3>;
phys = <&usb2phy 3>; phys = <&usb2phy 3>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
...@@ -558,6 +559,7 @@ ...@@ -558,6 +559,7 @@
<&ccu CLK_USB_OHCI3>; <&ccu CLK_USB_OHCI3>;
resets = <&ccu RST_BUS_OHCI3>; resets = <&ccu RST_BUS_OHCI3>;
phys = <&usb2phy 3>; phys = <&usb2phy 3>;
phy-names = "usb";
status = "disabled"; status = "disabled";
}; };
......
...@@ -571,7 +571,6 @@ CONFIG_USB_SERIAL_OMNINET=m ...@@ -571,7 +571,6 @@ CONFIG_USB_SERIAL_OMNINET=m
CONFIG_USB_EMI62=m CONFIG_USB_EMI62=m
CONFIG_USB_EMI26=m CONFIG_USB_EMI26=m
CONFIG_USB_ADUTUX=m CONFIG_USB_ADUTUX=m
CONFIG_USB_RIO500=m
CONFIG_USB_LEGOTOWER=m CONFIG_USB_LEGOTOWER=m
CONFIG_USB_LCD=m CONFIG_USB_LCD=m
CONFIG_USB_CYPRESS_CY7C63=m CONFIG_USB_CYPRESS_CY7C63=m
......
...@@ -314,7 +314,6 @@ CONFIG_USB_SERIAL_SAFE_PADDED=y ...@@ -314,7 +314,6 @@ CONFIG_USB_SERIAL_SAFE_PADDED=y
CONFIG_USB_SERIAL_CYBERJACK=m CONFIG_USB_SERIAL_CYBERJACK=m
CONFIG_USB_SERIAL_XIRCOM=m CONFIG_USB_SERIAL_XIRCOM=m
CONFIG_USB_SERIAL_OMNINET=m CONFIG_USB_SERIAL_OMNINET=m
CONFIG_USB_RIO500=m
CONFIG_USB_LEGOTOWER=m CONFIG_USB_LEGOTOWER=m
CONFIG_USB_LCD=m CONFIG_USB_LCD=m
CONFIG_USB_CYTHERM=m CONFIG_USB_CYTHERM=m
......
...@@ -241,12 +241,8 @@ struct resource *platform_get_resource_byname(struct platform_device *dev, ...@@ -241,12 +241,8 @@ struct resource *platform_get_resource_byname(struct platform_device *dev,
} }
EXPORT_SYMBOL_GPL(platform_get_resource_byname); EXPORT_SYMBOL_GPL(platform_get_resource_byname);
/** static int __platform_get_irq_byname(struct platform_device *dev,
* platform_get_irq_byname - get an IRQ for a device by name const char *name)
* @dev: platform device
* @name: IRQ name
*/
int platform_get_irq_byname(struct platform_device *dev, const char *name)
{ {
struct resource *r; struct resource *r;
...@@ -262,11 +258,47 @@ int platform_get_irq_byname(struct platform_device *dev, const char *name) ...@@ -262,11 +258,47 @@ int platform_get_irq_byname(struct platform_device *dev, const char *name)
if (r) if (r)
return r->start; return r->start;
dev_err(&dev->dev, "IRQ %s not found\n", name);
return -ENXIO; return -ENXIO;
} }
/**
* platform_get_irq_byname - get an IRQ for a device by name
* @dev: platform device
* @name: IRQ name
*
* Get an IRQ like platform_get_irq(), but then by name rather then by index.
*
* Return: IRQ number on success, negative error number on failure.
*/
int platform_get_irq_byname(struct platform_device *dev, const char *name)
{
int ret;
ret = __platform_get_irq_byname(dev, name);
if (ret < 0 && ret != -EPROBE_DEFER)
dev_err(&dev->dev, "IRQ %s not found\n", name);
return ret;
}
EXPORT_SYMBOL_GPL(platform_get_irq_byname); EXPORT_SYMBOL_GPL(platform_get_irq_byname);
/**
* platform_get_irq_byname_optional - get an optional IRQ for a device by name
* @dev: platform device
* @name: IRQ name
*
* Get an optional IRQ by name like platform_get_irq_byname(). Except that it
* does not print an error message if an IRQ can not be obtained.
*
* Return: IRQ number on success, negative error number on failure.
*/
int platform_get_irq_byname_optional(struct platform_device *dev,
const char *name)
{
return __platform_get_irq_byname(dev, name);
}
EXPORT_SYMBOL_GPL(platform_get_irq_byname_optional);
/** /**
* platform_add_devices - add a numbers of platform devices * platform_add_devices - add a numbers of platform devices
* @devs: array of platform devices to add * @devs: array of platform devices to add
......
...@@ -643,8 +643,7 @@ static int v4l_stk_release(struct file *fp) ...@@ -643,8 +643,7 @@ static int v4l_stk_release(struct file *fp)
dev->owner = NULL; dev->owner = NULL;
} }
if (is_present(dev)) usb_autopm_put_interface(dev->interface);
usb_autopm_put_interface(dev->interface);
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
return v4l2_fh_release(fp); return v4l2_fh_release(fp);
} }
......
...@@ -159,8 +159,9 @@ static int cdns3_pci_probe(struct pci_dev *pdev, ...@@ -159,8 +159,9 @@ static int cdns3_pci_probe(struct pci_dev *pdev,
wrap->plat_dev = platform_device_register_full(&plat_info); wrap->plat_dev = platform_device_register_full(&plat_info);
if (IS_ERR(wrap->plat_dev)) { if (IS_ERR(wrap->plat_dev)) {
pci_disable_device(pdev); pci_disable_device(pdev);
err = PTR_ERR(wrap->plat_dev);
kfree(wrap); kfree(wrap);
return PTR_ERR(wrap->plat_dev); return err;
} }
} }
......
...@@ -160,10 +160,28 @@ static int cdns3_core_init_role(struct cdns3 *cdns) ...@@ -160,10 +160,28 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
if (ret) if (ret)
goto err; goto err;
if (cdns->dr_mode != USB_DR_MODE_OTG) { /* Initialize idle role to start with */
ret = cdns3_role_start(cdns, USB_ROLE_NONE);
if (ret)
goto err;
switch (cdns->dr_mode) {
case USB_DR_MODE_UNKNOWN:
case USB_DR_MODE_OTG:
ret = cdns3_hw_role_switch(cdns); ret = cdns3_hw_role_switch(cdns);
if (ret) if (ret)
goto err; goto err;
break;
case USB_DR_MODE_PERIPHERAL:
ret = cdns3_role_start(cdns, USB_ROLE_DEVICE);
if (ret)
goto err;
break;
case USB_DR_MODE_HOST:
ret = cdns3_role_start(cdns, USB_ROLE_HOST);
if (ret)
goto err;
break;
} }
return ret; return ret;
......
...@@ -234,9 +234,11 @@ static int cdns3_req_ep0_set_address(struct cdns3_device *priv_dev, ...@@ -234,9 +234,11 @@ static int cdns3_req_ep0_set_address(struct cdns3_device *priv_dev,
static int cdns3_req_ep0_get_status(struct cdns3_device *priv_dev, static int cdns3_req_ep0_get_status(struct cdns3_device *priv_dev,
struct usb_ctrlrequest *ctrl) struct usb_ctrlrequest *ctrl)
{ {
struct cdns3_endpoint *priv_ep;
__le16 *response_pkt; __le16 *response_pkt;
u16 usb_status = 0; u16 usb_status = 0;
u32 recip; u32 recip;
u8 index;
recip = ctrl->bRequestType & USB_RECIP_MASK; recip = ctrl->bRequestType & USB_RECIP_MASK;
...@@ -262,9 +264,13 @@ static int cdns3_req_ep0_get_status(struct cdns3_device *priv_dev, ...@@ -262,9 +264,13 @@ static int cdns3_req_ep0_get_status(struct cdns3_device *priv_dev,
case USB_RECIP_INTERFACE: case USB_RECIP_INTERFACE:
return cdns3_ep0_delegate_req(priv_dev, ctrl); return cdns3_ep0_delegate_req(priv_dev, ctrl);
case USB_RECIP_ENDPOINT: case USB_RECIP_ENDPOINT:
/* check if endpoint is stalled */ index = cdns3_ep_addr_to_index(ctrl->wIndex);
priv_ep = priv_dev->eps[index];
/* check if endpoint is stalled or stall is pending */
cdns3_select_ep(priv_dev, ctrl->wIndex); cdns3_select_ep(priv_dev, ctrl->wIndex);
if (EP_STS_STALL(readl(&priv_dev->regs->ep_sts))) if (EP_STS_STALL(readl(&priv_dev->regs->ep_sts)) ||
(priv_ep->flags & EP_STALL_PENDING))
usb_status = BIT(USB_ENDPOINT_HALT); usb_status = BIT(USB_ENDPOINT_HALT);
break; break;
default: default:
...@@ -332,7 +338,7 @@ static int cdns3_ep0_feature_handle_device(struct cdns3_device *priv_dev, ...@@ -332,7 +338,7 @@ static int cdns3_ep0_feature_handle_device(struct cdns3_device *priv_dev,
* for sending status stage. * for sending status stage.
* This time should be less then 3ms. * This time should be less then 3ms.
*/ */
usleep_range(1000, 2000); mdelay(1);
cdns3_set_register_bit(&priv_dev->regs->usb_cmd, cdns3_set_register_bit(&priv_dev->regs->usb_cmd,
USB_CMD_STMODE | USB_CMD_STMODE |
USB_STS_TMODE_SEL(tmode - 1)); USB_STS_TMODE_SEL(tmode - 1));
......
...@@ -2571,6 +2571,7 @@ static int cdns3_gadget_start(struct cdns3 *cdns) ...@@ -2571,6 +2571,7 @@ static int cdns3_gadget_start(struct cdns3 *cdns)
switch (max_speed) { switch (max_speed) {
case USB_SPEED_FULL: case USB_SPEED_FULL:
writel(USB_CONF_SFORCE_FS, &priv_dev->regs->usb_conf); writel(USB_CONF_SFORCE_FS, &priv_dev->regs->usb_conf);
writel(USB_CONF_USB3DIS, &priv_dev->regs->usb_conf);
break; break;
case USB_SPEED_HIGH: case USB_SPEED_HIGH:
writel(USB_CONF_USB3DIS, &priv_dev->regs->usb_conf); writel(USB_CONF_USB3DIS, &priv_dev->regs->usb_conf);
...@@ -2662,6 +2663,13 @@ static int __cdns3_gadget_init(struct cdns3 *cdns) ...@@ -2662,6 +2663,13 @@ static int __cdns3_gadget_init(struct cdns3 *cdns)
{ {
int ret = 0; int ret = 0;
/* Ensure 32-bit DMA Mask in case we switched back from Host mode */
ret = dma_set_mask_and_coherent(cdns->dev, DMA_BIT_MASK(32));
if (ret) {
dev_err(cdns->dev, "Failed to set dma mask: %d\n", ret);
return ret;
}
cdns3_drd_switch_gadget(cdns, 1); cdns3_drd_switch_gadget(cdns, 1);
pm_runtime_get_sync(cdns->dev); pm_runtime_get_sync(cdns->dev);
......
...@@ -461,10 +461,12 @@ static int usblp_release(struct inode *inode, struct file *file) ...@@ -461,10 +461,12 @@ static int usblp_release(struct inode *inode, struct file *file)
mutex_lock(&usblp_mutex); mutex_lock(&usblp_mutex);
usblp->used = 0; usblp->used = 0;
if (usblp->present) { if (usblp->present)
usblp_unlink_urbs(usblp); usblp_unlink_urbs(usblp);
usb_autopm_put_interface(usblp->intf);
} else /* finish cleanup from disconnect */ usb_autopm_put_interface(usblp->intf);
if (!usblp->present) /* finish cleanup from disconnect */
usblp_cleanup(usblp); usblp_cleanup(usblp);
mutex_unlock(&usblp_mutex); mutex_unlock(&usblp_mutex);
return 0; return 0;
......
...@@ -139,14 +139,14 @@ static int dwc3_otg_get_irq(struct dwc3 *dwc) ...@@ -139,14 +139,14 @@ static int dwc3_otg_get_irq(struct dwc3 *dwc)
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
int irq; int irq;
irq = platform_get_irq_byname(dwc3_pdev, "otg"); irq = platform_get_irq_byname_optional(dwc3_pdev, "otg");
if (irq > 0) if (irq > 0)
goto out; goto out;
if (irq == -EPROBE_DEFER) if (irq == -EPROBE_DEFER)
goto out; goto out;
irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3"); irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
if (irq > 0) if (irq > 0)
goto out; goto out;
...@@ -157,9 +157,6 @@ static int dwc3_otg_get_irq(struct dwc3 *dwc) ...@@ -157,9 +157,6 @@ static int dwc3_otg_get_irq(struct dwc3 *dwc)
if (irq > 0) if (irq > 0)
goto out; goto out;
if (irq != -EPROBE_DEFER)
dev_err(dwc->dev, "missing OTG IRQ\n");
if (!irq) if (!irq)
irq = -EINVAL; irq = -EINVAL;
......
...@@ -3264,14 +3264,14 @@ static int dwc3_gadget_get_irq(struct dwc3 *dwc) ...@@ -3264,14 +3264,14 @@ static int dwc3_gadget_get_irq(struct dwc3 *dwc)
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
int irq; int irq;
irq = platform_get_irq_byname(dwc3_pdev, "peripheral"); irq = platform_get_irq_byname_optional(dwc3_pdev, "peripheral");
if (irq > 0) if (irq > 0)
goto out; goto out;
if (irq == -EPROBE_DEFER) if (irq == -EPROBE_DEFER)
goto out; goto out;
irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3"); irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
if (irq > 0) if (irq > 0)
goto out; goto out;
...@@ -3282,9 +3282,6 @@ static int dwc3_gadget_get_irq(struct dwc3 *dwc) ...@@ -3282,9 +3282,6 @@ static int dwc3_gadget_get_irq(struct dwc3 *dwc)
if (irq > 0) if (irq > 0)
goto out; goto out;
if (irq != -EPROBE_DEFER)
dev_err(dwc->dev, "missing peripheral IRQ\n");
if (!irq) if (!irq)
irq = -EINVAL; irq = -EINVAL;
......
...@@ -16,14 +16,14 @@ static int dwc3_host_get_irq(struct dwc3 *dwc) ...@@ -16,14 +16,14 @@ static int dwc3_host_get_irq(struct dwc3 *dwc)
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
int irq; int irq;
irq = platform_get_irq_byname(dwc3_pdev, "host"); irq = platform_get_irq_byname_optional(dwc3_pdev, "host");
if (irq > 0) if (irq > 0)
goto out; goto out;
if (irq == -EPROBE_DEFER) if (irq == -EPROBE_DEFER)
goto out; goto out;
irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3"); irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
if (irq > 0) if (irq > 0)
goto out; goto out;
...@@ -34,9 +34,6 @@ static int dwc3_host_get_irq(struct dwc3 *dwc) ...@@ -34,9 +34,6 @@ static int dwc3_host_get_irq(struct dwc3 *dwc)
if (irq > 0) if (irq > 0)
goto out; goto out;
if (irq != -EPROBE_DEFER)
dev_err(dwc->dev, "missing host IRQ\n");
if (!irq) if (!irq)
irq = -EINVAL; irq = -EINVAL;
......
...@@ -45,7 +45,7 @@ config USB_AT91 ...@@ -45,7 +45,7 @@ config USB_AT91
config USB_LPC32XX config USB_LPC32XX
tristate "LPC32XX USB Peripheral Controller" tristate "LPC32XX USB Peripheral Controller"
depends on ARCH_LPC32XX depends on ARCH_LPC32XX || COMPILE_TEST
depends on I2C depends on I2C
select USB_ISP1301 select USB_ISP1301
help help
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#define DRIVER_VERSION "02 May 2005" #define DRIVER_VERSION "02 May 2005"
#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */ #define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
#define POWER_BUDGET_3 900 /* in mA */
static const char driver_name[] = "dummy_hcd"; static const char driver_name[] = "dummy_hcd";
static const char driver_desc[] = "USB Host+Gadget Emulator"; static const char driver_desc[] = "USB Host+Gadget Emulator";
...@@ -2432,7 +2433,7 @@ static int dummy_start_ss(struct dummy_hcd *dum_hcd) ...@@ -2432,7 +2433,7 @@ static int dummy_start_ss(struct dummy_hcd *dum_hcd)
dum_hcd->rh_state = DUMMY_RH_RUNNING; dum_hcd->rh_state = DUMMY_RH_RUNNING;
dum_hcd->stream_en_ep = 0; dum_hcd->stream_en_ep = 0;
INIT_LIST_HEAD(&dum_hcd->urbp_list); INIT_LIST_HEAD(&dum_hcd->urbp_list);
dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET; dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET_3;
dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING; dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1; dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
#ifdef CONFIG_USB_OTG #ifdef CONFIG_USB_OTG
......
...@@ -1151,7 +1151,7 @@ static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes) ...@@ -1151,7 +1151,7 @@ static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
u32 *p32, tmp, cbytes; u32 *p32, tmp, cbytes;
/* Use optimal data transfer method based on source address and size */ /* Use optimal data transfer method based on source address and size */
switch (((u32) data) & 0x3) { switch (((uintptr_t) data) & 0x3) {
case 0: /* 32-bit aligned */ case 0: /* 32-bit aligned */
p32 = (u32 *) data; p32 = (u32 *) data;
cbytes = (bytes & ~0x3); cbytes = (bytes & ~0x3);
...@@ -1252,7 +1252,7 @@ static void udc_stuff_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes) ...@@ -1252,7 +1252,7 @@ static void udc_stuff_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
u32 *p32, tmp, cbytes; u32 *p32, tmp, cbytes;
/* Use optimal data transfer method based on source address and size */ /* Use optimal data transfer method based on source address and size */
switch (((u32) data) & 0x3) { switch (((uintptr_t) data) & 0x3) {
case 0: /* 32-bit aligned */ case 0: /* 32-bit aligned */
p32 = (u32 *) data; p32 = (u32 *) data;
cbytes = (bytes & ~0x3); cbytes = (bytes & ~0x3);
......
...@@ -57,6 +57,7 @@ static int xhci_create_intel_xhci_sw_pdev(struct xhci_hcd *xhci, u32 cap_offset) ...@@ -57,6 +57,7 @@ static int xhci_create_intel_xhci_sw_pdev(struct xhci_hcd *xhci, u32 cap_offset)
ret = platform_device_add_properties(pdev, role_switch_props); ret = platform_device_add_properties(pdev, role_switch_props);
if (ret) { if (ret) {
dev_err(dev, "failed to register device properties\n"); dev_err(dev, "failed to register device properties\n");
platform_device_put(pdev);
return ret; return ret;
} }
} }
......
...@@ -3202,10 +3202,10 @@ static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len, ...@@ -3202,10 +3202,10 @@ static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len,
if (usb_urb_dir_out(urb)) { if (usb_urb_dir_out(urb)) {
len = sg_pcopy_to_buffer(urb->sg, urb->num_sgs, len = sg_pcopy_to_buffer(urb->sg, urb->num_sgs,
seg->bounce_buf, new_buff_len, enqd_len); seg->bounce_buf, new_buff_len, enqd_len);
if (len != seg->bounce_len) if (len != new_buff_len)
xhci_warn(xhci, xhci_warn(xhci,
"WARN Wrong bounce buffer write length: %zu != %d\n", "WARN Wrong bounce buffer write length: %zu != %d\n",
len, seg->bounce_len); len, new_buff_len);
seg->bounce_dma = dma_map_single(dev, seg->bounce_buf, seg->bounce_dma = dma_map_single(dev, seg->bounce_buf,
max_pkt, DMA_TO_DEVICE); max_pkt, DMA_TO_DEVICE);
} else { } else {
......
...@@ -1032,7 +1032,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) ...@@ -1032,7 +1032,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
writel(command, &xhci->op_regs->command); writel(command, &xhci->op_regs->command);
xhci->broken_suspend = 0; xhci->broken_suspend = 0;
if (xhci_handshake(&xhci->op_regs->status, if (xhci_handshake(&xhci->op_regs->status,
STS_SAVE, 0, 10 * 1000)) { STS_SAVE, 0, 20 * 1000)) {
/* /*
* AMD SNPS xHC 3.0 occasionally does not clear the * AMD SNPS xHC 3.0 occasionally does not clear the
* SSS bit of USBSTS and when driver tries to poll * SSS bit of USBSTS and when driver tries to poll
...@@ -1108,6 +1108,18 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) ...@@ -1108,6 +1108,18 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
hibernated = true; hibernated = true;
if (!hibernated) { if (!hibernated) {
/*
* Some controllers might lose power during suspend, so wait
* for controller not ready bit to clear, just as in xHC init.
*/
retval = xhci_handshake(&xhci->op_regs->status,
STS_CNR, 0, 10 * 1000 * 1000);
if (retval) {
xhci_warn(xhci, "Controller not ready at resume %d\n",
retval);
spin_unlock_irq(&xhci->lock);
return retval;
}
/* step 1: restore register */ /* step 1: restore register */
xhci_restore_registers(xhci); xhci_restore_registers(xhci);
/* step 2: initialize command ring buffer */ /* step 2: initialize command ring buffer */
...@@ -3083,6 +3095,7 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd, ...@@ -3083,6 +3095,7 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
unsigned int ep_index; unsigned int ep_index;
unsigned long flags; unsigned long flags;
u32 ep_flag; u32 ep_flag;
int err;
xhci = hcd_to_xhci(hcd); xhci = hcd_to_xhci(hcd);
if (!host_ep->hcpriv) if (!host_ep->hcpriv)
...@@ -3142,7 +3155,17 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd, ...@@ -3142,7 +3155,17 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
xhci_free_command(xhci, cfg_cmd); xhci_free_command(xhci, cfg_cmd);
goto cleanup; goto cleanup;
} }
xhci_queue_stop_endpoint(xhci, stop_cmd, udev->slot_id, ep_index, 0);
err = xhci_queue_stop_endpoint(xhci, stop_cmd, udev->slot_id,
ep_index, 0);
if (err < 0) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_free_command(xhci, cfg_cmd);
xhci_dbg(xhci, "%s: Failed to queue stop ep command, %d ",
__func__, err);
goto cleanup;
}
xhci_ring_cmd_db(xhci); xhci_ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
...@@ -3156,8 +3179,16 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd, ...@@ -3156,8 +3179,16 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
ctrl_ctx, ep_flag, ep_flag); ctrl_ctx, ep_flag, ep_flag);
xhci_endpoint_copy(xhci, cfg_cmd->in_ctx, vdev->out_ctx, ep_index); xhci_endpoint_copy(xhci, cfg_cmd->in_ctx, vdev->out_ctx, ep_index);
xhci_queue_configure_endpoint(xhci, cfg_cmd, cfg_cmd->in_ctx->dma, err = xhci_queue_configure_endpoint(xhci, cfg_cmd, cfg_cmd->in_ctx->dma,
udev->slot_id, false); udev->slot_id, false);
if (err < 0) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_free_command(xhci, cfg_cmd);
xhci_dbg(xhci, "%s: Failed to queue config ep command, %d ",
__func__, err);
goto cleanup;
}
xhci_ring_cmd_db(xhci); xhci_ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
...@@ -4674,12 +4705,12 @@ static int xhci_update_timeout_for_endpoint(struct xhci_hcd *xhci, ...@@ -4674,12 +4705,12 @@ static int xhci_update_timeout_for_endpoint(struct xhci_hcd *xhci,
alt_timeout = xhci_call_host_update_timeout_for_endpoint(xhci, udev, alt_timeout = xhci_call_host_update_timeout_for_endpoint(xhci, udev,
desc, state, timeout); desc, state, timeout);
/* If we found we can't enable hub-initiated LPM, or /* If we found we can't enable hub-initiated LPM, and
* the U1 or U2 exit latency was too high to allow * the U1 or U2 exit latency was too high to allow
* device-initiated LPM as well, just stop searching. * device-initiated LPM as well, then we will disable LPM
* for this device, so stop searching any further.
*/ */
if (alt_timeout == USB3_LPM_DISABLED || if (alt_timeout == USB3_LPM_DISABLED) {
alt_timeout == USB3_LPM_DEVICE_INITIATED) {
*timeout = alt_timeout; *timeout = alt_timeout;
return -E2BIG; return -E2BIG;
} }
...@@ -4790,10 +4821,12 @@ static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd, ...@@ -4790,10 +4821,12 @@ static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd,
if (intf->dev.driver) { if (intf->dev.driver) {
driver = to_usb_driver(intf->dev.driver); driver = to_usb_driver(intf->dev.driver);
if (driver && driver->disable_hub_initiated_lpm) { if (driver && driver->disable_hub_initiated_lpm) {
dev_dbg(&udev->dev, "Hub-initiated %s disabled " dev_dbg(&udev->dev, "Hub-initiated %s disabled at request of driver %s\n",
"at request of driver %s\n", state_name, driver->name);
state_name, driver->name); timeout = xhci_get_timeout_no_hub_lpm(udev,
return xhci_get_timeout_no_hub_lpm(udev, state); state);
if (timeout == USB3_LPM_DISABLED)
return timeout;
} }
} }
...@@ -5077,11 +5110,18 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) ...@@ -5077,11 +5110,18 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
hcd->has_tt = 1; hcd->has_tt = 1;
} else { } else {
/* /*
* Some 3.1 hosts return sbrn 0x30, use xhci supported protocol * Early xHCI 1.1 spec did not mention USB 3.1 capable hosts
* minor revision instead of sbrn. Minor revision is a two digit * should return 0x31 for sbrn, or that the minor revision
* BCD containing minor and sub-minor numbers, only show minor. * is a two digit BCD containig minor and sub-minor numbers.
* This was later clarified in xHCI 1.2.
*
* Some USB 3.1 capable hosts therefore have sbrn 0x30, and
* minor revision set to 0x1 instead of 0x10.
*/ */
minor_rev = xhci->usb3_rhub.min_rev / 0x10; if (xhci->usb3_rhub.min_rev == 0x1)
minor_rev = 1;
else
minor_rev = xhci->usb3_rhub.min_rev / 0x10;
switch (minor_rev) { switch (minor_rev) {
case 2: case 2:
...@@ -5198,8 +5238,16 @@ static void xhci_clear_tt_buffer_complete(struct usb_hcd *hcd, ...@@ -5198,8 +5238,16 @@ static void xhci_clear_tt_buffer_complete(struct usb_hcd *hcd,
unsigned int ep_index; unsigned int ep_index;
unsigned long flags; unsigned long flags;
/*
* udev might be NULL if tt buffer is cleared during a failed device
* enumeration due to a halted control endpoint. Usb core might
* have allocated a new udev for the next enumeration attempt.
*/
xhci = hcd_to_xhci(hcd); xhci = hcd_to_xhci(hcd);
udev = (struct usb_device *)ep->hcpriv; udev = (struct usb_device *)ep->hcpriv;
if (!udev)
return;
slot_id = udev->slot_id; slot_id = udev->slot_id;
ep_index = xhci_get_endpoint_index(&ep->desc); ep_index = xhci_get_endpoint_index(&ep->desc);
......
...@@ -716,6 +716,10 @@ static int mts_usb_probe(struct usb_interface *intf, ...@@ -716,6 +716,10 @@ static int mts_usb_probe(struct usb_interface *intf,
} }
if (ep_in_current != &ep_in_set[2]) {
MTS_WARNING("couldn't find two input bulk endpoints. Bailing out.\n");
return -ENODEV;
}
if ( ep_out == -1 ) { if ( ep_out == -1 ) {
MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" ); MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" );
......
...@@ -47,16 +47,6 @@ config USB_SEVSEG ...@@ -47,16 +47,6 @@ config USB_SEVSEG
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called usbsevseg. module will be called usbsevseg.
config USB_RIO500
tristate "USB Diamond Rio500 support"
help
Say Y here if you want to connect a USB Rio500 mp3 player to your
computer's USB port. Please read <file:Documentation/usb/rio.rst>
for more information.
To compile this driver as a module, choose M here: the
module will be called rio500.
config USB_LEGOTOWER config USB_LEGOTOWER
tristate "USB Lego Infrared Tower support" tristate "USB Lego Infrared Tower support"
help help
......
...@@ -17,7 +17,6 @@ obj-$(CONFIG_USB_ISIGHTFW) += isight_firmware.o ...@@ -17,7 +17,6 @@ obj-$(CONFIG_USB_ISIGHTFW) += isight_firmware.o
obj-$(CONFIG_USB_LCD) += usblcd.o obj-$(CONFIG_USB_LCD) += usblcd.o
obj-$(CONFIG_USB_LD) += ldusb.o obj-$(CONFIG_USB_LD) += ldusb.o
obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o
obj-$(CONFIG_USB_RIO500) += rio500.o
obj-$(CONFIG_USB_TEST) += usbtest.o obj-$(CONFIG_USB_TEST) += usbtest.o
obj-$(CONFIG_USB_EHSET_TEST_FIXTURE) += ehset.o obj-$(CONFIG_USB_EHSET_TEST_FIXTURE) += ehset.o
obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
......
...@@ -75,6 +75,7 @@ struct adu_device { ...@@ -75,6 +75,7 @@ struct adu_device {
char serial_number[8]; char serial_number[8];
int open_count; /* number of times this port has been opened */ int open_count; /* number of times this port has been opened */
unsigned long disconnected:1;
char *read_buffer_primary; char *read_buffer_primary;
int read_buffer_length; int read_buffer_length;
...@@ -116,7 +117,7 @@ static void adu_abort_transfers(struct adu_device *dev) ...@@ -116,7 +117,7 @@ static void adu_abort_transfers(struct adu_device *dev)
{ {
unsigned long flags; unsigned long flags;
if (dev->udev == NULL) if (dev->disconnected)
return; return;
/* shutdown transfer */ /* shutdown transfer */
...@@ -148,6 +149,7 @@ static void adu_delete(struct adu_device *dev) ...@@ -148,6 +149,7 @@ static void adu_delete(struct adu_device *dev)
kfree(dev->read_buffer_secondary); kfree(dev->read_buffer_secondary);
kfree(dev->interrupt_in_buffer); kfree(dev->interrupt_in_buffer);
kfree(dev->interrupt_out_buffer); kfree(dev->interrupt_out_buffer);
usb_put_dev(dev->udev);
kfree(dev); kfree(dev);
} }
...@@ -243,7 +245,7 @@ static int adu_open(struct inode *inode, struct file *file) ...@@ -243,7 +245,7 @@ static int adu_open(struct inode *inode, struct file *file)
} }
dev = usb_get_intfdata(interface); dev = usb_get_intfdata(interface);
if (!dev || !dev->udev) { if (!dev) {
retval = -ENODEV; retval = -ENODEV;
goto exit_no_device; goto exit_no_device;
} }
...@@ -326,7 +328,7 @@ static int adu_release(struct inode *inode, struct file *file) ...@@ -326,7 +328,7 @@ static int adu_release(struct inode *inode, struct file *file)
} }
adu_release_internal(dev); adu_release_internal(dev);
if (dev->udev == NULL) { if (dev->disconnected) {
/* the device was unplugged before the file was released */ /* the device was unplugged before the file was released */
if (!dev->open_count) /* ... and we're the last user */ if (!dev->open_count) /* ... and we're the last user */
adu_delete(dev); adu_delete(dev);
...@@ -354,7 +356,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, ...@@ -354,7 +356,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
return -ERESTARTSYS; return -ERESTARTSYS;
/* verify that the device wasn't unplugged */ /* verify that the device wasn't unplugged */
if (dev->udev == NULL) { if (dev->disconnected) {
retval = -ENODEV; retval = -ENODEV;
pr_err("No device or device unplugged %d\n", retval); pr_err("No device or device unplugged %d\n", retval);
goto exit; goto exit;
...@@ -518,7 +520,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer, ...@@ -518,7 +520,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
goto exit_nolock; goto exit_nolock;
/* verify that the device wasn't unplugged */ /* verify that the device wasn't unplugged */
if (dev->udev == NULL) { if (dev->disconnected) {
retval = -ENODEV; retval = -ENODEV;
pr_err("No device or device unplugged %d\n", retval); pr_err("No device or device unplugged %d\n", retval);
goto exit; goto exit;
...@@ -663,7 +665,7 @@ static int adu_probe(struct usb_interface *interface, ...@@ -663,7 +665,7 @@ static int adu_probe(struct usb_interface *interface,
mutex_init(&dev->mtx); mutex_init(&dev->mtx);
spin_lock_init(&dev->buflock); spin_lock_init(&dev->buflock);
dev->udev = udev; dev->udev = usb_get_dev(udev);
init_waitqueue_head(&dev->read_wait); init_waitqueue_head(&dev->read_wait);
init_waitqueue_head(&dev->write_wait); init_waitqueue_head(&dev->write_wait);
...@@ -762,14 +764,18 @@ static void adu_disconnect(struct usb_interface *interface) ...@@ -762,14 +764,18 @@ static void adu_disconnect(struct usb_interface *interface)
dev = usb_get_intfdata(interface); dev = usb_get_intfdata(interface);
mutex_lock(&dev->mtx); /* not interruptible */
dev->udev = NULL; /* poison */
usb_deregister_dev(interface, &adu_class); usb_deregister_dev(interface, &adu_class);
mutex_unlock(&dev->mtx);
usb_poison_urb(dev->interrupt_in_urb);
usb_poison_urb(dev->interrupt_out_urb);
mutex_lock(&adutux_mutex); mutex_lock(&adutux_mutex);
usb_set_intfdata(interface, NULL); usb_set_intfdata(interface, NULL);
mutex_lock(&dev->mtx); /* not interruptible */
dev->disconnected = 1;
mutex_unlock(&dev->mtx);
/* if the device is not opened, then we clean up right now */ /* if the device is not opened, then we clean up right now */
if (!dev->open_count) if (!dev->open_count)
adu_delete(dev); adu_delete(dev);
......
...@@ -98,6 +98,7 @@ static void chaoskey_free(struct chaoskey *dev) ...@@ -98,6 +98,7 @@ static void chaoskey_free(struct chaoskey *dev)
usb_free_urb(dev->urb); usb_free_urb(dev->urb);
kfree(dev->name); kfree(dev->name);
kfree(dev->buf); kfree(dev->buf);
usb_put_intf(dev->interface);
kfree(dev); kfree(dev);
} }
} }
...@@ -145,6 +146,8 @@ static int chaoskey_probe(struct usb_interface *interface, ...@@ -145,6 +146,8 @@ static int chaoskey_probe(struct usb_interface *interface,
if (dev == NULL) if (dev == NULL)
goto out; goto out;
dev->interface = usb_get_intf(interface);
dev->buf = kmalloc(size, GFP_KERNEL); dev->buf = kmalloc(size, GFP_KERNEL);
if (dev->buf == NULL) if (dev->buf == NULL)
...@@ -174,8 +177,6 @@ static int chaoskey_probe(struct usb_interface *interface, ...@@ -174,8 +177,6 @@ static int chaoskey_probe(struct usb_interface *interface,
goto out; goto out;
} }
dev->interface = interface;
dev->in_ep = in_ep; dev->in_ep = in_ep;
if (le16_to_cpu(udev->descriptor.idVendor) != ALEA_VENDOR_ID) if (le16_to_cpu(udev->descriptor.idVendor) != ALEA_VENDOR_ID)
......
...@@ -54,11 +54,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR); ...@@ -54,11 +54,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* Module parameters */
static DEFINE_MUTEX(iowarrior_mutex);
static struct usb_driver iowarrior_driver; static struct usb_driver iowarrior_driver;
static DEFINE_MUTEX(iowarrior_open_disc_lock);
/*--------------*/ /*--------------*/
/* data */ /* data */
...@@ -87,6 +83,7 @@ struct iowarrior { ...@@ -87,6 +83,7 @@ struct iowarrior {
char chip_serial[9]; /* the serial number string of the chip connected */ char chip_serial[9]; /* the serial number string of the chip connected */
int report_size; /* number of bytes in a report */ int report_size; /* number of bytes in a report */
u16 product_id; u16 product_id;
struct usb_anchor submitted;
}; };
/*--------------*/ /*--------------*/
...@@ -243,6 +240,7 @@ static inline void iowarrior_delete(struct iowarrior *dev) ...@@ -243,6 +240,7 @@ static inline void iowarrior_delete(struct iowarrior *dev)
kfree(dev->int_in_buffer); kfree(dev->int_in_buffer);
usb_free_urb(dev->int_in_urb); usb_free_urb(dev->int_in_urb);
kfree(dev->read_queue); kfree(dev->read_queue);
usb_put_intf(dev->interface);
kfree(dev); kfree(dev);
} }
...@@ -424,11 +422,13 @@ static ssize_t iowarrior_write(struct file *file, ...@@ -424,11 +422,13 @@ static ssize_t iowarrior_write(struct file *file,
retval = -EFAULT; retval = -EFAULT;
goto error; goto error;
} }
usb_anchor_urb(int_out_urb, &dev->submitted);
retval = usb_submit_urb(int_out_urb, GFP_KERNEL); retval = usb_submit_urb(int_out_urb, GFP_KERNEL);
if (retval) { if (retval) {
dev_dbg(&dev->interface->dev, dev_dbg(&dev->interface->dev,
"submit error %d for urb nr.%d\n", "submit error %d for urb nr.%d\n",
retval, atomic_read(&dev->write_busy)); retval, atomic_read(&dev->write_busy));
usb_unanchor_urb(int_out_urb);
goto error; goto error;
} }
/* submit was ok */ /* submit was ok */
...@@ -477,8 +477,6 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, ...@@ -477,8 +477,6 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
if (!buffer) if (!buffer)
return -ENOMEM; return -ENOMEM;
/* lock this object */
mutex_lock(&iowarrior_mutex);
mutex_lock(&dev->mutex); mutex_lock(&dev->mutex);
/* verify that the device wasn't unplugged */ /* verify that the device wasn't unplugged */
...@@ -571,7 +569,6 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, ...@@ -571,7 +569,6 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
error_out: error_out:
/* unlock the device */ /* unlock the device */
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
mutex_unlock(&iowarrior_mutex);
kfree(buffer); kfree(buffer);
return retval; return retval;
} }
...@@ -586,27 +583,20 @@ static int iowarrior_open(struct inode *inode, struct file *file) ...@@ -586,27 +583,20 @@ static int iowarrior_open(struct inode *inode, struct file *file)
int subminor; int subminor;
int retval = 0; int retval = 0;
mutex_lock(&iowarrior_mutex);
subminor = iminor(inode); subminor = iminor(inode);
interface = usb_find_interface(&iowarrior_driver, subminor); interface = usb_find_interface(&iowarrior_driver, subminor);
if (!interface) { if (!interface) {
mutex_unlock(&iowarrior_mutex); pr_err("%s - error, can't find device for minor %d\n",
printk(KERN_ERR "%s - error, can't find device for minor %d\n",
__func__, subminor); __func__, subminor);
return -ENODEV; return -ENODEV;
} }
mutex_lock(&iowarrior_open_disc_lock);
dev = usb_get_intfdata(interface); dev = usb_get_intfdata(interface);
if (!dev) { if (!dev)
mutex_unlock(&iowarrior_open_disc_lock);
mutex_unlock(&iowarrior_mutex);
return -ENODEV; return -ENODEV;
}
mutex_lock(&dev->mutex); mutex_lock(&dev->mutex);
mutex_unlock(&iowarrior_open_disc_lock);
/* Only one process can open each device, no sharing. */ /* Only one process can open each device, no sharing. */
if (dev->opened) { if (dev->opened) {
...@@ -628,7 +618,6 @@ static int iowarrior_open(struct inode *inode, struct file *file) ...@@ -628,7 +618,6 @@ static int iowarrior_open(struct inode *inode, struct file *file)
out: out:
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
mutex_unlock(&iowarrior_mutex);
return retval; return retval;
} }
...@@ -764,11 +753,13 @@ static int iowarrior_probe(struct usb_interface *interface, ...@@ -764,11 +753,13 @@ static int iowarrior_probe(struct usb_interface *interface,
init_waitqueue_head(&dev->write_wait); init_waitqueue_head(&dev->write_wait);
dev->udev = udev; dev->udev = udev;
dev->interface = interface; dev->interface = usb_get_intf(interface);
iface_desc = interface->cur_altsetting; iface_desc = interface->cur_altsetting;
dev->product_id = le16_to_cpu(udev->descriptor.idProduct); dev->product_id = le16_to_cpu(udev->descriptor.idProduct);
init_usb_anchor(&dev->submitted);
res = usb_find_last_int_in_endpoint(iface_desc, &dev->int_in_endpoint); res = usb_find_last_int_in_endpoint(iface_desc, &dev->int_in_endpoint);
if (res) { if (res) {
dev_err(&interface->dev, "no interrupt-in endpoint found\n"); dev_err(&interface->dev, "no interrupt-in endpoint found\n");
...@@ -836,7 +827,6 @@ static int iowarrior_probe(struct usb_interface *interface, ...@@ -836,7 +827,6 @@ static int iowarrior_probe(struct usb_interface *interface,
if (retval) { if (retval) {
/* something prevented us from registering this driver */ /* something prevented us from registering this driver */
dev_err(&interface->dev, "Not able to get a minor for this device.\n"); dev_err(&interface->dev, "Not able to get a minor for this device.\n");
usb_set_intfdata(interface, NULL);
goto error; goto error;
} }
...@@ -860,26 +850,15 @@ static int iowarrior_probe(struct usb_interface *interface, ...@@ -860,26 +850,15 @@ static int iowarrior_probe(struct usb_interface *interface,
*/ */
static void iowarrior_disconnect(struct usb_interface *interface) static void iowarrior_disconnect(struct usb_interface *interface)
{ {
struct iowarrior *dev; struct iowarrior *dev = usb_get_intfdata(interface);
int minor; int minor = dev->minor;
dev = usb_get_intfdata(interface);
mutex_lock(&iowarrior_open_disc_lock);
usb_set_intfdata(interface, NULL);
/* prevent device read, write and ioctl */
dev->present = 0;
minor = dev->minor;
mutex_unlock(&iowarrior_open_disc_lock);
/* give back our minor - this will call close() locks need to be dropped at this point*/
usb_deregister_dev(interface, &iowarrior_class); usb_deregister_dev(interface, &iowarrior_class);
mutex_lock(&dev->mutex); mutex_lock(&dev->mutex);
/* prevent device read, write and ioctl */ /* prevent device read, write and ioctl */
dev->present = 0;
mutex_unlock(&dev->mutex);
if (dev->opened) { if (dev->opened) {
/* There is a process that holds a filedescriptor to the device , /* There is a process that holds a filedescriptor to the device ,
...@@ -887,10 +866,13 @@ static void iowarrior_disconnect(struct usb_interface *interface) ...@@ -887,10 +866,13 @@ static void iowarrior_disconnect(struct usb_interface *interface)
Deleting the device is postponed until close() was called. Deleting the device is postponed until close() was called.
*/ */
usb_kill_urb(dev->int_in_urb); usb_kill_urb(dev->int_in_urb);
usb_kill_anchored_urbs(&dev->submitted);
wake_up_interruptible(&dev->read_wait); wake_up_interruptible(&dev->read_wait);
wake_up_interruptible(&dev->write_wait); wake_up_interruptible(&dev->write_wait);
mutex_unlock(&dev->mutex);
} else { } else {
/* no process is using the device, cleanup now */ /* no process is using the device, cleanup now */
mutex_unlock(&dev->mutex);
iowarrior_delete(dev); iowarrior_delete(dev);
} }
......
...@@ -153,6 +153,7 @@ MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in ...@@ -153,6 +153,7 @@ MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in
struct ld_usb { struct ld_usb {
struct mutex mutex; /* locks this structure */ struct mutex mutex; /* locks this structure */
struct usb_interface *intf; /* save off the usb interface pointer */ struct usb_interface *intf; /* save off the usb interface pointer */
unsigned long disconnected:1;
int open_count; /* number of times this port has been opened */ int open_count; /* number of times this port has been opened */
...@@ -192,12 +193,10 @@ static void ld_usb_abort_transfers(struct ld_usb *dev) ...@@ -192,12 +193,10 @@ static void ld_usb_abort_transfers(struct ld_usb *dev)
/* shutdown transfer */ /* shutdown transfer */
if (dev->interrupt_in_running) { if (dev->interrupt_in_running) {
dev->interrupt_in_running = 0; dev->interrupt_in_running = 0;
if (dev->intf) usb_kill_urb(dev->interrupt_in_urb);
usb_kill_urb(dev->interrupt_in_urb);
} }
if (dev->interrupt_out_busy) if (dev->interrupt_out_busy)
if (dev->intf) usb_kill_urb(dev->interrupt_out_urb);
usb_kill_urb(dev->interrupt_out_urb);
} }
/** /**
...@@ -205,8 +204,6 @@ static void ld_usb_abort_transfers(struct ld_usb *dev) ...@@ -205,8 +204,6 @@ static void ld_usb_abort_transfers(struct ld_usb *dev)
*/ */
static void ld_usb_delete(struct ld_usb *dev) static void ld_usb_delete(struct ld_usb *dev)
{ {
ld_usb_abort_transfers(dev);
/* free data structures */ /* free data structures */
usb_free_urb(dev->interrupt_in_urb); usb_free_urb(dev->interrupt_in_urb);
usb_free_urb(dev->interrupt_out_urb); usb_free_urb(dev->interrupt_out_urb);
...@@ -263,7 +260,7 @@ static void ld_usb_interrupt_in_callback(struct urb *urb) ...@@ -263,7 +260,7 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
resubmit: resubmit:
/* resubmit if we're still running */ /* resubmit if we're still running */
if (dev->interrupt_in_running && !dev->buffer_overflow && dev->intf) { if (dev->interrupt_in_running && !dev->buffer_overflow) {
retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC);
if (retval) { if (retval) {
dev_err(&dev->intf->dev, dev_err(&dev->intf->dev,
...@@ -392,7 +389,7 @@ static int ld_usb_release(struct inode *inode, struct file *file) ...@@ -392,7 +389,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
retval = -ENODEV; retval = -ENODEV;
goto unlock_exit; goto unlock_exit;
} }
if (dev->intf == NULL) { if (dev->disconnected) {
/* the device was unplugged before the file was released */ /* the device was unplugged before the file was released */
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
/* unlock here as ld_usb_delete frees dev */ /* unlock here as ld_usb_delete frees dev */
...@@ -423,7 +420,7 @@ static __poll_t ld_usb_poll(struct file *file, poll_table *wait) ...@@ -423,7 +420,7 @@ static __poll_t ld_usb_poll(struct file *file, poll_table *wait)
dev = file->private_data; dev = file->private_data;
if (!dev->intf) if (dev->disconnected)
return EPOLLERR | EPOLLHUP; return EPOLLERR | EPOLLHUP;
poll_wait(file, &dev->read_wait, wait); poll_wait(file, &dev->read_wait, wait);
...@@ -462,7 +459,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, ...@@ -462,7 +459,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
} }
/* verify that the device wasn't unplugged */ /* verify that the device wasn't unplugged */
if (dev->intf == NULL) { if (dev->disconnected) {
retval = -ENODEV; retval = -ENODEV;
printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval); printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
goto unlock_exit; goto unlock_exit;
...@@ -542,7 +539,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, ...@@ -542,7 +539,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
} }
/* verify that the device wasn't unplugged */ /* verify that the device wasn't unplugged */
if (dev->intf == NULL) { if (dev->disconnected) {
retval = -ENODEV; retval = -ENODEV;
printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval); printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
goto unlock_exit; goto unlock_exit;
...@@ -764,6 +761,9 @@ static void ld_usb_disconnect(struct usb_interface *intf) ...@@ -764,6 +761,9 @@ static void ld_usb_disconnect(struct usb_interface *intf)
/* give back our minor */ /* give back our minor */
usb_deregister_dev(intf, &ld_usb_class); usb_deregister_dev(intf, &ld_usb_class);
usb_poison_urb(dev->interrupt_in_urb);
usb_poison_urb(dev->interrupt_out_urb);
mutex_lock(&dev->mutex); mutex_lock(&dev->mutex);
/* if the device is not opened, then we clean up right now */ /* if the device is not opened, then we clean up right now */
...@@ -771,7 +771,7 @@ static void ld_usb_disconnect(struct usb_interface *intf) ...@@ -771,7 +771,7 @@ static void ld_usb_disconnect(struct usb_interface *intf)
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
ld_usb_delete(dev); ld_usb_delete(dev);
} else { } else {
dev->intf = NULL; dev->disconnected = 1;
/* wake up pollers */ /* wake up pollers */
wake_up_interruptible_all(&dev->read_wait); wake_up_interruptible_all(&dev->read_wait);
wake_up_interruptible_all(&dev->write_wait); wake_up_interruptible_all(&dev->write_wait);
......
...@@ -179,7 +179,6 @@ static const struct usb_device_id tower_table[] = { ...@@ -179,7 +179,6 @@ static const struct usb_device_id tower_table[] = {
}; };
MODULE_DEVICE_TABLE (usb, tower_table); MODULE_DEVICE_TABLE (usb, tower_table);
static DEFINE_MUTEX(open_disc_mutex);
#define LEGO_USB_TOWER_MINOR_BASE 160 #define LEGO_USB_TOWER_MINOR_BASE 160
...@@ -191,6 +190,7 @@ struct lego_usb_tower { ...@@ -191,6 +190,7 @@ struct lego_usb_tower {
unsigned char minor; /* the starting minor number for this device */ unsigned char minor; /* the starting minor number for this device */
int open_count; /* number of times this port has been opened */ int open_count; /* number of times this port has been opened */
unsigned long disconnected:1;
char* read_buffer; char* read_buffer;
size_t read_buffer_length; /* this much came in */ size_t read_buffer_length; /* this much came in */
...@@ -290,14 +290,13 @@ static inline void lego_usb_tower_debug_data(struct device *dev, ...@@ -290,14 +290,13 @@ static inline void lego_usb_tower_debug_data(struct device *dev,
*/ */
static inline void tower_delete (struct lego_usb_tower *dev) static inline void tower_delete (struct lego_usb_tower *dev)
{ {
tower_abort_transfers (dev);
/* free data structures */ /* free data structures */
usb_free_urb(dev->interrupt_in_urb); usb_free_urb(dev->interrupt_in_urb);
usb_free_urb(dev->interrupt_out_urb); usb_free_urb(dev->interrupt_out_urb);
kfree (dev->read_buffer); kfree (dev->read_buffer);
kfree (dev->interrupt_in_buffer); kfree (dev->interrupt_in_buffer);
kfree (dev->interrupt_out_buffer); kfree (dev->interrupt_out_buffer);
usb_put_dev(dev->udev);
kfree (dev); kfree (dev);
} }
...@@ -332,18 +331,14 @@ static int tower_open (struct inode *inode, struct file *file) ...@@ -332,18 +331,14 @@ static int tower_open (struct inode *inode, struct file *file)
goto exit; goto exit;
} }
mutex_lock(&open_disc_mutex);
dev = usb_get_intfdata(interface); dev = usb_get_intfdata(interface);
if (!dev) { if (!dev) {
mutex_unlock(&open_disc_mutex);
retval = -ENODEV; retval = -ENODEV;
goto exit; goto exit;
} }
/* lock this device */ /* lock this device */
if (mutex_lock_interruptible(&dev->lock)) { if (mutex_lock_interruptible(&dev->lock)) {
mutex_unlock(&open_disc_mutex);
retval = -ERESTARTSYS; retval = -ERESTARTSYS;
goto exit; goto exit;
} }
...@@ -351,12 +346,9 @@ static int tower_open (struct inode *inode, struct file *file) ...@@ -351,12 +346,9 @@ static int tower_open (struct inode *inode, struct file *file)
/* allow opening only once */ /* allow opening only once */
if (dev->open_count) { if (dev->open_count) {
mutex_unlock(&open_disc_mutex);
retval = -EBUSY; retval = -EBUSY;
goto unlock_exit; goto unlock_exit;
} }
dev->open_count = 1;
mutex_unlock(&open_disc_mutex);
/* reset the tower */ /* reset the tower */
result = usb_control_msg (dev->udev, result = usb_control_msg (dev->udev,
...@@ -396,13 +388,14 @@ static int tower_open (struct inode *inode, struct file *file) ...@@ -396,13 +388,14 @@ static int tower_open (struct inode *inode, struct file *file)
dev_err(&dev->udev->dev, dev_err(&dev->udev->dev,
"Couldn't submit interrupt_in_urb %d\n", retval); "Couldn't submit interrupt_in_urb %d\n", retval);
dev->interrupt_in_running = 0; dev->interrupt_in_running = 0;
dev->open_count = 0;
goto unlock_exit; goto unlock_exit;
} }
/* save device in the file's private structure */ /* save device in the file's private structure */
file->private_data = dev; file->private_data = dev;
dev->open_count = 1;
unlock_exit: unlock_exit:
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
...@@ -423,10 +416,9 @@ static int tower_release (struct inode *inode, struct file *file) ...@@ -423,10 +416,9 @@ static int tower_release (struct inode *inode, struct file *file)
if (dev == NULL) { if (dev == NULL) {
retval = -ENODEV; retval = -ENODEV;
goto exit_nolock; goto exit;
} }
mutex_lock(&open_disc_mutex);
if (mutex_lock_interruptible(&dev->lock)) { if (mutex_lock_interruptible(&dev->lock)) {
retval = -ERESTARTSYS; retval = -ERESTARTSYS;
goto exit; goto exit;
...@@ -438,7 +430,8 @@ static int tower_release (struct inode *inode, struct file *file) ...@@ -438,7 +430,8 @@ static int tower_release (struct inode *inode, struct file *file)
retval = -ENODEV; retval = -ENODEV;
goto unlock_exit; goto unlock_exit;
} }
if (dev->udev == NULL) {
if (dev->disconnected) {
/* the device was unplugged before the file was released */ /* the device was unplugged before the file was released */
/* unlock here as tower_delete frees dev */ /* unlock here as tower_delete frees dev */
...@@ -456,10 +449,7 @@ static int tower_release (struct inode *inode, struct file *file) ...@@ -456,10 +449,7 @@ static int tower_release (struct inode *inode, struct file *file)
unlock_exit: unlock_exit:
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
exit: exit:
mutex_unlock(&open_disc_mutex);
exit_nolock:
return retval; return retval;
} }
...@@ -477,10 +467,9 @@ static void tower_abort_transfers (struct lego_usb_tower *dev) ...@@ -477,10 +467,9 @@ static void tower_abort_transfers (struct lego_usb_tower *dev)
if (dev->interrupt_in_running) { if (dev->interrupt_in_running) {
dev->interrupt_in_running = 0; dev->interrupt_in_running = 0;
mb(); mb();
if (dev->udev) usb_kill_urb(dev->interrupt_in_urb);
usb_kill_urb (dev->interrupt_in_urb);
} }
if (dev->interrupt_out_busy && dev->udev) if (dev->interrupt_out_busy)
usb_kill_urb(dev->interrupt_out_urb); usb_kill_urb(dev->interrupt_out_urb);
} }
...@@ -516,7 +505,7 @@ static __poll_t tower_poll (struct file *file, poll_table *wait) ...@@ -516,7 +505,7 @@ static __poll_t tower_poll (struct file *file, poll_table *wait)
dev = file->private_data; dev = file->private_data;
if (!dev->udev) if (dev->disconnected)
return EPOLLERR | EPOLLHUP; return EPOLLERR | EPOLLHUP;
poll_wait(file, &dev->read_wait, wait); poll_wait(file, &dev->read_wait, wait);
...@@ -563,7 +552,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, ...@@ -563,7 +552,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count,
} }
/* verify that the device wasn't unplugged */ /* verify that the device wasn't unplugged */
if (dev->udev == NULL) { if (dev->disconnected) {
retval = -ENODEV; retval = -ENODEV;
pr_err("No device or device unplugged %d\n", retval); pr_err("No device or device unplugged %d\n", retval);
goto unlock_exit; goto unlock_exit;
...@@ -649,7 +638,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t ...@@ -649,7 +638,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t
} }
/* verify that the device wasn't unplugged */ /* verify that the device wasn't unplugged */
if (dev->udev == NULL) { if (dev->disconnected) {
retval = -ENODEV; retval = -ENODEV;
pr_err("No device or device unplugged %d\n", retval); pr_err("No device or device unplugged %d\n", retval);
goto unlock_exit; goto unlock_exit;
...@@ -759,7 +748,7 @@ static void tower_interrupt_in_callback (struct urb *urb) ...@@ -759,7 +748,7 @@ static void tower_interrupt_in_callback (struct urb *urb)
resubmit: resubmit:
/* resubmit if we're still running */ /* resubmit if we're still running */
if (dev->interrupt_in_running && dev->udev) { if (dev->interrupt_in_running) {
retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC); retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC);
if (retval) if (retval)
dev_err(&dev->udev->dev, dev_err(&dev->udev->dev,
...@@ -822,8 +811,9 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device ...@@ -822,8 +811,9 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
mutex_init(&dev->lock); mutex_init(&dev->lock);
dev->udev = udev; dev->udev = usb_get_dev(udev);
dev->open_count = 0; dev->open_count = 0;
dev->disconnected = 0;
dev->read_buffer = NULL; dev->read_buffer = NULL;
dev->read_buffer_length = 0; dev->read_buffer_length = 0;
...@@ -891,8 +881,10 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device ...@@ -891,8 +881,10 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
get_version_reply, get_version_reply,
sizeof(*get_version_reply), sizeof(*get_version_reply),
1000); 1000);
if (result < 0) { if (result < sizeof(*get_version_reply)) {
dev_err(idev, "LEGO USB Tower get version control request failed\n"); if (result >= 0)
result = -EIO;
dev_err(idev, "get version request failed: %d\n", result);
retval = result; retval = result;
goto error; goto error;
} }
...@@ -910,7 +902,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device ...@@ -910,7 +902,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
if (retval) { if (retval) {
/* something prevented us from registering this driver */ /* something prevented us from registering this driver */
dev_err(idev, "Not able to get a minor for this device.\n"); dev_err(idev, "Not able to get a minor for this device.\n");
usb_set_intfdata (interface, NULL);
goto error; goto error;
} }
dev->minor = interface->minor; dev->minor = interface->minor;
...@@ -942,23 +933,24 @@ static void tower_disconnect (struct usb_interface *interface) ...@@ -942,23 +933,24 @@ static void tower_disconnect (struct usb_interface *interface)
int minor; int minor;
dev = usb_get_intfdata (interface); dev = usb_get_intfdata (interface);
mutex_lock(&open_disc_mutex);
usb_set_intfdata (interface, NULL);
minor = dev->minor; minor = dev->minor;
/* give back our minor */ /* give back our minor and prevent further open() */
usb_deregister_dev (interface, &tower_class); usb_deregister_dev (interface, &tower_class);
/* stop I/O */
usb_poison_urb(dev->interrupt_in_urb);
usb_poison_urb(dev->interrupt_out_urb);
mutex_lock(&dev->lock); mutex_lock(&dev->lock);
mutex_unlock(&open_disc_mutex);
/* if the device is not opened, then we clean up right now */ /* if the device is not opened, then we clean up right now */
if (!dev->open_count) { if (!dev->open_count) {
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
tower_delete (dev); tower_delete (dev);
} else { } else {
dev->udev = NULL; dev->disconnected = 1;
/* wake up pollers */ /* wake up pollers */
wake_up_interruptible_all(&dev->read_wait); wake_up_interruptible_all(&dev->read_wait);
wake_up_interruptible_all(&dev->write_wait); wake_up_interruptible_all(&dev->write_wait);
......
// SPDX-License-Identifier: GPL-2.0+
/* -*- linux-c -*- */
/*
* Driver for USB Rio 500
*
* Cesar Miquel (miquel@df.uba.ar)
*
* based on hp_scanner.c by David E. Nelson (dnelson@jump.net)
*
* Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee).
*
* Changelog:
* 30/05/2003 replaced lock/unlock kernel with up/down
* Daniele Bellucci bellucda@tiscali.it
* */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/sched/signal.h>
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/random.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
#include <linux/wait.h>
#include "rio500_usb.h"
#define DRIVER_AUTHOR "Cesar Miquel <miquel@df.uba.ar>"
#define DRIVER_DESC "USB Rio 500 driver"
#define RIO_MINOR 64
/* stall/wait timeout for rio */
#define NAK_TIMEOUT (HZ)
#define IBUF_SIZE 0x1000
/* Size of the rio buffer */
#define OBUF_SIZE 0x10000
struct rio_usb_data {
struct usb_device *rio_dev; /* init: probe_rio */
unsigned int ifnum; /* Interface number of the USB device */
int isopen; /* nz if open */
int present; /* Device is present on the bus */
char *obuf, *ibuf; /* transfer buffers */
char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */
wait_queue_head_t wait_q; /* for timeouts */
};
static DEFINE_MUTEX(rio500_mutex);
static struct rio_usb_data rio_instance;
static int open_rio(struct inode *inode, struct file *file)
{
struct rio_usb_data *rio = &rio_instance;
/* against disconnect() */
mutex_lock(&rio500_mutex);
if (rio->isopen || !rio->present) {
mutex_unlock(&rio500_mutex);
return -EBUSY;
}
rio->isopen = 1;
init_waitqueue_head(&rio->wait_q);
dev_info(&rio->rio_dev->dev, "Rio opened.\n");
mutex_unlock(&rio500_mutex);
return 0;
}
static int close_rio(struct inode *inode, struct file *file)
{
struct rio_usb_data *rio = &rio_instance;
/* against disconnect() */
mutex_lock(&rio500_mutex);
rio->isopen = 0;
if (!rio->present) {
/* cleanup has been delayed */
kfree(rio->ibuf);
kfree(rio->obuf);
rio->ibuf = NULL;
rio->obuf = NULL;
} else {
dev_info(&rio->rio_dev->dev, "Rio closed.\n");
}
mutex_unlock(&rio500_mutex);
return 0;
}
static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
{
struct RioCommand rio_cmd;
struct rio_usb_data *rio = &rio_instance;
void __user *data;
unsigned char *buffer;
int result, requesttype;
int retries;
int retval=0;
mutex_lock(&rio500_mutex);
/* Sanity check to make sure rio is connected, powered, etc */
if (rio->present == 0 || rio->rio_dev == NULL) {
retval = -ENODEV;
goto err_out;
}
switch (cmd) {
case RIO_RECV_COMMAND:
data = (void __user *) arg;
if (data == NULL)
break;
if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) {
retval = -EFAULT;
goto err_out;
}
if (rio_cmd.length < 0 || rio_cmd.length > PAGE_SIZE) {
retval = -EINVAL;
goto err_out;
}
buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
if (buffer == NULL) {
retval = -ENOMEM;
goto err_out;
}
if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) {
retval = -EFAULT;
free_page((unsigned long) buffer);
goto err_out;
}
requesttype = rio_cmd.requesttype | USB_DIR_IN |
USB_TYPE_VENDOR | USB_RECIP_DEVICE;
dev_dbg(&rio->rio_dev->dev,
"sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
requesttype, rio_cmd.request, rio_cmd.value,
rio_cmd.index, rio_cmd.length);
/* Send rio control message */
retries = 3;
while (retries) {
result = usb_control_msg(rio->rio_dev,
usb_rcvctrlpipe(rio-> rio_dev, 0),
rio_cmd.request,
requesttype,
rio_cmd.value,
rio_cmd.index, buffer,
rio_cmd.length,
jiffies_to_msecs(rio_cmd.timeout));
if (result == -ETIMEDOUT)
retries--;
else if (result < 0) {
dev_err(&rio->rio_dev->dev,
"Error executing ioctrl. code = %d\n",
result);
retries = 0;
} else {
dev_dbg(&rio->rio_dev->dev,
"Executed ioctl. Result = %d (data=%02x)\n",
result, buffer[0]);
if (copy_to_user(rio_cmd.buffer, buffer,
rio_cmd.length)) {
free_page((unsigned long) buffer);
retval = -EFAULT;
goto err_out;
}
retries = 0;
}
/* rio_cmd.buffer contains a raw stream of single byte
data which has been returned from rio. Data is
interpreted at application level. For data that
will be cast to data types longer than 1 byte, data
will be little_endian and will potentially need to
be swapped at the app level */
}
free_page((unsigned long) buffer);
break;
case RIO_SEND_COMMAND:
data = (void __user *) arg;
if (data == NULL)
break;
if (copy_from_user(&rio_cmd, data, sizeof(struct RioCommand))) {
retval = -EFAULT;
goto err_out;
}
if (rio_cmd.length < 0 || rio_cmd.length > PAGE_SIZE) {
retval = -EINVAL;
goto err_out;
}
buffer = (unsigned char *) __get_free_page(GFP_KERNEL);
if (buffer == NULL) {
retval = -ENOMEM;
goto err_out;
}
if (copy_from_user(buffer, rio_cmd.buffer, rio_cmd.length)) {
free_page((unsigned long)buffer);
retval = -EFAULT;
goto err_out;
}
requesttype = rio_cmd.requesttype | USB_DIR_OUT |
USB_TYPE_VENDOR | USB_RECIP_DEVICE;
dev_dbg(&rio->rio_dev->dev,
"sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n",
requesttype, rio_cmd.request, rio_cmd.value,
rio_cmd.index, rio_cmd.length);
/* Send rio control message */
retries = 3;
while (retries) {
result = usb_control_msg(rio->rio_dev,
usb_sndctrlpipe(rio-> rio_dev, 0),
rio_cmd.request,
requesttype,
rio_cmd.value,
rio_cmd.index, buffer,
rio_cmd.length,
jiffies_to_msecs(rio_cmd.timeout));
if (result == -ETIMEDOUT)
retries--;
else if (result < 0) {
dev_err(&rio->rio_dev->dev,
"Error executing ioctrl. code = %d\n",
result);
retries = 0;
} else {
dev_dbg(&rio->rio_dev->dev,
"Executed ioctl. Result = %d\n", result);
retries = 0;
}
}
free_page((unsigned long) buffer);
break;
default:
retval = -ENOTTY;
break;
}
err_out:
mutex_unlock(&rio500_mutex);
return retval;
}
static ssize_t
write_rio(struct file *file, const char __user *buffer,
size_t count, loff_t * ppos)
{
DEFINE_WAIT(wait);
struct rio_usb_data *rio = &rio_instance;
unsigned long copy_size;
unsigned long bytes_written = 0;
unsigned int partial;
int result = 0;
int maxretry;
int errn = 0;
int intr;
intr = mutex_lock_interruptible(&rio500_mutex);
if (intr)
return -EINTR;
/* Sanity check to make sure rio is connected, powered, etc */
if (rio->present == 0 || rio->rio_dev == NULL) {
mutex_unlock(&rio500_mutex);
return -ENODEV;
}
do {
unsigned long thistime;
char *obuf = rio->obuf;
thistime = copy_size =
(count >= OBUF_SIZE) ? OBUF_SIZE : count;
if (copy_from_user(rio->obuf, buffer, copy_size)) {
errn = -EFAULT;
goto error;
}
maxretry = 5;
while (thistime) {
if (!rio->rio_dev) {
errn = -ENODEV;
goto error;
}
if (signal_pending(current)) {
mutex_unlock(&rio500_mutex);
return bytes_written ? bytes_written : -EINTR;
}
result = usb_bulk_msg(rio->rio_dev,
usb_sndbulkpipe(rio->rio_dev, 2),
obuf, thistime, &partial, 5000);
dev_dbg(&rio->rio_dev->dev,
"write stats: result:%d thistime:%lu partial:%u\n",
result, thistime, partial);
if (result == -ETIMEDOUT) { /* NAK - so hold for a while */
if (!maxretry--) {
errn = -ETIME;
goto error;
}
prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE);
schedule_timeout(NAK_TIMEOUT);
finish_wait(&rio->wait_q, &wait);
continue;
} else if (!result && partial) {
obuf += partial;
thistime -= partial;
} else
break;
}
if (result) {
dev_err(&rio->rio_dev->dev, "Write Whoops - %x\n",
result);
errn = -EIO;
goto error;
}
bytes_written += copy_size;
count -= copy_size;
buffer += copy_size;
} while (count > 0);
mutex_unlock(&rio500_mutex);
return bytes_written ? bytes_written : -EIO;
error:
mutex_unlock(&rio500_mutex);
return errn;
}
static ssize_t
read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
{
DEFINE_WAIT(wait);
struct rio_usb_data *rio = &rio_instance;
ssize_t read_count;
unsigned int partial;
int this_read;
int result;
int maxretry = 10;
char *ibuf;
int intr;
intr = mutex_lock_interruptible(&rio500_mutex);
if (intr)
return -EINTR;
/* Sanity check to make sure rio is connected, powered, etc */
if (rio->present == 0 || rio->rio_dev == NULL) {
mutex_unlock(&rio500_mutex);
return -ENODEV;
}
ibuf = rio->ibuf;
read_count = 0;
while (count > 0) {
if (signal_pending(current)) {
mutex_unlock(&rio500_mutex);
return read_count ? read_count : -EINTR;
}
if (!rio->rio_dev) {
mutex_unlock(&rio500_mutex);
return -ENODEV;
}
this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
result = usb_bulk_msg(rio->rio_dev,
usb_rcvbulkpipe(rio->rio_dev, 1),
ibuf, this_read, &partial,
8000);
dev_dbg(&rio->rio_dev->dev,
"read stats: result:%d this_read:%u partial:%u\n",
result, this_read, partial);
if (partial) {
count = this_read = partial;
} else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */
if (!maxretry--) {
mutex_unlock(&rio500_mutex);
dev_err(&rio->rio_dev->dev,
"read_rio: maxretry timeout\n");
return -ETIME;
}
prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE);
schedule_timeout(NAK_TIMEOUT);
finish_wait(&rio->wait_q, &wait);
continue;
} else if (result != -EREMOTEIO) {
mutex_unlock(&rio500_mutex);
dev_err(&rio->rio_dev->dev,
"Read Whoops - result:%d partial:%u this_read:%u\n",
result, partial, this_read);
return -EIO;
} else {
mutex_unlock(&rio500_mutex);
return (0);
}
if (this_read) {
if (copy_to_user(buffer, ibuf, this_read)) {
mutex_unlock(&rio500_mutex);
return -EFAULT;
}
count -= this_read;
read_count += this_read;
buffer += this_read;
}
}
mutex_unlock(&rio500_mutex);
return read_count;
}
static const struct file_operations usb_rio_fops = {
.owner = THIS_MODULE,
.read = read_rio,
.write = write_rio,
.unlocked_ioctl = ioctl_rio,
.open = open_rio,
.release = close_rio,
.llseek = noop_llseek,
};
static struct usb_class_driver usb_rio_class = {
.name = "rio500%d",
.fops = &usb_rio_fops,
.minor_base = RIO_MINOR,
};
static int probe_rio(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct rio_usb_data *rio = &rio_instance;
int retval = -ENOMEM;
char *ibuf, *obuf;
if (rio->present) {
dev_info(&intf->dev, "Second USB Rio at address %d refused\n", dev->devnum);
return -EBUSY;
}
dev_info(&intf->dev, "USB Rio found at address %d\n", dev->devnum);
obuf = kmalloc(OBUF_SIZE, GFP_KERNEL);
if (!obuf) {
dev_err(&dev->dev,
"probe_rio: Not enough memory for the output buffer\n");
goto err_obuf;
}
dev_dbg(&intf->dev, "obuf address: %p\n", obuf);
ibuf = kmalloc(IBUF_SIZE, GFP_KERNEL);
if (!ibuf) {
dev_err(&dev->dev,
"probe_rio: Not enough memory for the input buffer\n");
goto err_ibuf;
}
dev_dbg(&intf->dev, "ibuf address: %p\n", ibuf);
mutex_lock(&rio500_mutex);
rio->rio_dev = dev;
rio->ibuf = ibuf;
rio->obuf = obuf;
rio->present = 1;
mutex_unlock(&rio500_mutex);
retval = usb_register_dev(intf, &usb_rio_class);
if (retval) {
dev_err(&dev->dev,
"Not able to get a minor for this device.\n");
goto err_register;
}
usb_set_intfdata(intf, rio);
return retval;
err_register:
mutex_lock(&rio500_mutex);
rio->present = 0;
mutex_unlock(&rio500_mutex);
err_ibuf:
kfree(obuf);
err_obuf:
return retval;
}
static void disconnect_rio(struct usb_interface *intf)
{
struct rio_usb_data *rio = usb_get_intfdata (intf);
usb_set_intfdata (intf, NULL);
if (rio) {
usb_deregister_dev(intf, &usb_rio_class);
mutex_lock(&rio500_mutex);
if (rio->isopen) {
rio->isopen = 0;
/* better let it finish - the release will do whats needed */
rio->rio_dev = NULL;
mutex_unlock(&rio500_mutex);
return;
}
kfree(rio->ibuf);
kfree(rio->obuf);
dev_info(&intf->dev, "USB Rio disconnected.\n");
rio->present = 0;
mutex_unlock(&rio500_mutex);
}
}
static const struct usb_device_id rio_table[] = {
{ USB_DEVICE(0x0841, 1) }, /* Rio 500 */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, rio_table);
static struct usb_driver rio_driver = {
.name = "rio500",
.probe = probe_rio,
.disconnect = disconnect_rio,
.id_table = rio_table,
};
module_usb_driver(rio_driver);
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
// SPDX-License-Identifier: GPL-2.0+
/* ----------------------------------------------------------------------
Copyright (C) 2000 Cesar Miquel (miquel@df.uba.ar)
---------------------------------------------------------------------- */
#define RIO_SEND_COMMAND 0x1
#define RIO_RECV_COMMAND 0x2
#define RIO_DIR_OUT 0x0
#define RIO_DIR_IN 0x1
struct RioCommand {
short length;
int request;
int requesttype;
int value;
int index;
void __user *buffer;
int timeout;
};
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/rwsem.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/usb.h> #include <linux/usb.h>
...@@ -29,16 +30,12 @@ ...@@ -29,16 +30,12 @@
#define IOCTL_GET_DRV_VERSION 2 #define IOCTL_GET_DRV_VERSION 2
static DEFINE_MUTEX(lcd_mutex);
static const struct usb_device_id id_table[] = { static const struct usb_device_id id_table[] = {
{ .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, }, { .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
{ }, { },
}; };
MODULE_DEVICE_TABLE(usb, id_table); MODULE_DEVICE_TABLE(usb, id_table);
static DEFINE_MUTEX(open_disc_mutex);
struct usb_lcd { struct usb_lcd {
struct usb_device *udev; /* init: probe_lcd */ struct usb_device *udev; /* init: probe_lcd */
struct usb_interface *interface; /* the interface for struct usb_interface *interface; /* the interface for
...@@ -57,6 +54,8 @@ struct usb_lcd { ...@@ -57,6 +54,8 @@ struct usb_lcd {
using up all RAM */ using up all RAM */
struct usb_anchor submitted; /* URBs to wait for struct usb_anchor submitted; /* URBs to wait for
before suspend */ before suspend */
struct rw_semaphore io_rwsem;
unsigned long disconnected:1;
}; };
#define to_lcd_dev(d) container_of(d, struct usb_lcd, kref) #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
...@@ -81,40 +80,29 @@ static int lcd_open(struct inode *inode, struct file *file) ...@@ -81,40 +80,29 @@ static int lcd_open(struct inode *inode, struct file *file)
struct usb_interface *interface; struct usb_interface *interface;
int subminor, r; int subminor, r;
mutex_lock(&lcd_mutex);
subminor = iminor(inode); subminor = iminor(inode);
interface = usb_find_interface(&lcd_driver, subminor); interface = usb_find_interface(&lcd_driver, subminor);
if (!interface) { if (!interface) {
mutex_unlock(&lcd_mutex); pr_err("USBLCD: %s - error, can't find device for minor %d\n",
printk(KERN_ERR "USBLCD: %s - error, can't find device for minor %d\n",
__func__, subminor); __func__, subminor);
return -ENODEV; return -ENODEV;
} }
mutex_lock(&open_disc_mutex);
dev = usb_get_intfdata(interface); dev = usb_get_intfdata(interface);
if (!dev) {
mutex_unlock(&open_disc_mutex);
mutex_unlock(&lcd_mutex);
return -ENODEV;
}
/* increment our usage count for the device */ /* increment our usage count for the device */
kref_get(&dev->kref); kref_get(&dev->kref);
mutex_unlock(&open_disc_mutex);
/* grab a power reference */ /* grab a power reference */
r = usb_autopm_get_interface(interface); r = usb_autopm_get_interface(interface);
if (r < 0) { if (r < 0) {
kref_put(&dev->kref, lcd_delete); kref_put(&dev->kref, lcd_delete);
mutex_unlock(&lcd_mutex);
return r; return r;
} }
/* save our object in the file's private structure */ /* save our object in the file's private structure */
file->private_data = dev; file->private_data = dev;
mutex_unlock(&lcd_mutex);
return 0; return 0;
} }
...@@ -142,6 +130,13 @@ static ssize_t lcd_read(struct file *file, char __user * buffer, ...@@ -142,6 +130,13 @@ static ssize_t lcd_read(struct file *file, char __user * buffer,
dev = file->private_data; dev = file->private_data;
down_read(&dev->io_rwsem);
if (dev->disconnected) {
retval = -ENODEV;
goto out_up_io;
}
/* do a blocking bulk read to get data from the device */ /* do a blocking bulk read to get data from the device */
retval = usb_bulk_msg(dev->udev, retval = usb_bulk_msg(dev->udev,
usb_rcvbulkpipe(dev->udev, usb_rcvbulkpipe(dev->udev,
...@@ -158,6 +153,9 @@ static ssize_t lcd_read(struct file *file, char __user * buffer, ...@@ -158,6 +153,9 @@ static ssize_t lcd_read(struct file *file, char __user * buffer,
retval = bytes_read; retval = bytes_read;
} }
out_up_io:
up_read(&dev->io_rwsem);
return retval; return retval;
} }
...@@ -173,14 +171,12 @@ static long lcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -173,14 +171,12 @@ static long lcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
switch (cmd) { switch (cmd) {
case IOCTL_GET_HARD_VERSION: case IOCTL_GET_HARD_VERSION:
mutex_lock(&lcd_mutex);
bcdDevice = le16_to_cpu((dev->udev)->descriptor.bcdDevice); bcdDevice = le16_to_cpu((dev->udev)->descriptor.bcdDevice);
sprintf(buf, "%1d%1d.%1d%1d", sprintf(buf, "%1d%1d.%1d%1d",
(bcdDevice & 0xF000)>>12, (bcdDevice & 0xF000)>>12,
(bcdDevice & 0xF00)>>8, (bcdDevice & 0xF00)>>8,
(bcdDevice & 0xF0)>>4, (bcdDevice & 0xF0)>>4,
(bcdDevice & 0xF)); (bcdDevice & 0xF));
mutex_unlock(&lcd_mutex);
if (copy_to_user((void __user *)arg, buf, strlen(buf)) != 0) if (copy_to_user((void __user *)arg, buf, strlen(buf)) != 0)
return -EFAULT; return -EFAULT;
break; break;
...@@ -237,11 +233,18 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, ...@@ -237,11 +233,18 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
if (r < 0) if (r < 0)
return -EINTR; return -EINTR;
down_read(&dev->io_rwsem);
if (dev->disconnected) {
retval = -ENODEV;
goto err_up_io;
}
/* 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 */
urb = usb_alloc_urb(0, GFP_KERNEL); urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) { if (!urb) {
retval = -ENOMEM; retval = -ENOMEM;
goto err_no_buf; goto err_up_io;
} }
buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL, buf = usb_alloc_coherent(dev->udev, count, GFP_KERNEL,
...@@ -278,6 +281,7 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, ...@@ -278,6 +281,7 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
the USB core will eventually free it entirely */ the USB core will eventually free it entirely */
usb_free_urb(urb); usb_free_urb(urb);
up_read(&dev->io_rwsem);
exit: exit:
return count; return count;
error_unanchor: error_unanchor:
...@@ -285,7 +289,8 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, ...@@ -285,7 +289,8 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
error: error:
usb_free_coherent(dev->udev, count, buf, urb->transfer_dma); usb_free_coherent(dev->udev, count, buf, urb->transfer_dma);
usb_free_urb(urb); usb_free_urb(urb);
err_no_buf: err_up_io:
up_read(&dev->io_rwsem);
up(&dev->limit_sem); up(&dev->limit_sem);
return retval; return retval;
} }
...@@ -325,6 +330,7 @@ static int lcd_probe(struct usb_interface *interface, ...@@ -325,6 +330,7 @@ static int lcd_probe(struct usb_interface *interface,
kref_init(&dev->kref); kref_init(&dev->kref);
sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES); sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES);
init_rwsem(&dev->io_rwsem);
init_usb_anchor(&dev->submitted); init_usb_anchor(&dev->submitted);
dev->udev = usb_get_dev(interface_to_usbdev(interface)); dev->udev = usb_get_dev(interface_to_usbdev(interface));
...@@ -365,7 +371,6 @@ static int lcd_probe(struct usb_interface *interface, ...@@ -365,7 +371,6 @@ static int lcd_probe(struct usb_interface *interface,
/* something prevented us from registering this driver */ /* something prevented us from registering this driver */
dev_err(&interface->dev, dev_err(&interface->dev,
"Not able to get a minor for this device.\n"); "Not able to get a minor for this device.\n");
usb_set_intfdata(interface, NULL);
goto error; goto error;
} }
...@@ -411,17 +416,18 @@ static int lcd_resume(struct usb_interface *intf) ...@@ -411,17 +416,18 @@ static int lcd_resume(struct usb_interface *intf)
static void lcd_disconnect(struct usb_interface *interface) static void lcd_disconnect(struct usb_interface *interface)
{ {
struct usb_lcd *dev; struct usb_lcd *dev = usb_get_intfdata(interface);
int minor = interface->minor; int minor = interface->minor;
mutex_lock(&open_disc_mutex);
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
mutex_unlock(&open_disc_mutex);
/* give back our minor */ /* give back our minor */
usb_deregister_dev(interface, &lcd_class); usb_deregister_dev(interface, &lcd_class);
down_write(&dev->io_rwsem);
dev->disconnected = 1;
up_write(&dev->io_rwsem);
usb_kill_anchored_urbs(&dev->submitted);
/* decrement our usage count */ /* decrement our usage count */
kref_put(&dev->kref, lcd_delete); kref_put(&dev->kref, lcd_delete);
......
...@@ -60,6 +60,7 @@ struct usb_yurex { ...@@ -60,6 +60,7 @@ struct usb_yurex {
struct kref kref; struct kref kref;
struct mutex io_mutex; struct mutex io_mutex;
unsigned long disconnected:1;
struct fasync_struct *async_queue; struct fasync_struct *async_queue;
wait_queue_head_t waitq; wait_queue_head_t waitq;
...@@ -107,6 +108,7 @@ static void yurex_delete(struct kref *kref) ...@@ -107,6 +108,7 @@ static void yurex_delete(struct kref *kref)
dev->int_buffer, dev->urb->transfer_dma); dev->int_buffer, dev->urb->transfer_dma);
usb_free_urb(dev->urb); usb_free_urb(dev->urb);
} }
usb_put_intf(dev->interface);
usb_put_dev(dev->udev); usb_put_dev(dev->udev);
kfree(dev); kfree(dev);
} }
...@@ -132,6 +134,7 @@ static void yurex_interrupt(struct urb *urb) ...@@ -132,6 +134,7 @@ static void yurex_interrupt(struct urb *urb)
switch (status) { switch (status) {
case 0: /*success*/ case 0: /*success*/
break; break;
/* The device is terminated or messed up, give up */
case -EOVERFLOW: case -EOVERFLOW:
dev_err(&dev->interface->dev, dev_err(&dev->interface->dev,
"%s - overflow with length %d, actual length is %d\n", "%s - overflow with length %d, actual length is %d\n",
...@@ -140,12 +143,13 @@ static void yurex_interrupt(struct urb *urb) ...@@ -140,12 +143,13 @@ static void yurex_interrupt(struct urb *urb)
case -ENOENT: case -ENOENT:
case -ESHUTDOWN: case -ESHUTDOWN:
case -EILSEQ: case -EILSEQ:
/* The device is terminated, clean up */ case -EPROTO:
case -ETIME:
return; return;
default: default:
dev_err(&dev->interface->dev, dev_err(&dev->interface->dev,
"%s - unknown status received: %d\n", __func__, status); "%s - unknown status received: %d\n", __func__, status);
goto exit; return;
} }
/* handle received message */ /* handle received message */
...@@ -177,7 +181,6 @@ static void yurex_interrupt(struct urb *urb) ...@@ -177,7 +181,6 @@ static void yurex_interrupt(struct urb *urb)
break; break;
} }
exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC); retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval) { if (retval) {
dev_err(&dev->interface->dev, "%s - usb_submit_urb failed: %d\n", dev_err(&dev->interface->dev, "%s - usb_submit_urb failed: %d\n",
...@@ -204,7 +207,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ ...@@ -204,7 +207,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
init_waitqueue_head(&dev->waitq); init_waitqueue_head(&dev->waitq);
dev->udev = usb_get_dev(interface_to_usbdev(interface)); dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface; dev->interface = usb_get_intf(interface);
/* set up the endpoint information */ /* set up the endpoint information */
iface_desc = interface->cur_altsetting; iface_desc = interface->cur_altsetting;
...@@ -315,8 +318,9 @@ static void yurex_disconnect(struct usb_interface *interface) ...@@ -315,8 +318,9 @@ static void yurex_disconnect(struct usb_interface *interface)
/* prevent more I/O from starting */ /* prevent more I/O from starting */
usb_poison_urb(dev->urb); usb_poison_urb(dev->urb);
usb_poison_urb(dev->cntl_urb);
mutex_lock(&dev->io_mutex); mutex_lock(&dev->io_mutex);
dev->interface = NULL; dev->disconnected = 1;
mutex_unlock(&dev->io_mutex); mutex_unlock(&dev->io_mutex);
/* wakeup waiters */ /* wakeup waiters */
...@@ -404,7 +408,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count, ...@@ -404,7 +408,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
dev = file->private_data; dev = file->private_data;
mutex_lock(&dev->io_mutex); mutex_lock(&dev->io_mutex);
if (!dev->interface) { /* already disconnected */ if (dev->disconnected) { /* already disconnected */
mutex_unlock(&dev->io_mutex); mutex_unlock(&dev->io_mutex);
return -ENODEV; return -ENODEV;
} }
...@@ -439,7 +443,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer, ...@@ -439,7 +443,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
goto error; goto error;
mutex_lock(&dev->io_mutex); mutex_lock(&dev->io_mutex);
if (!dev->interface) { /* already disconnected */ if (dev->disconnected) { /* already disconnected */
mutex_unlock(&dev->io_mutex); mutex_unlock(&dev->io_mutex);
retval = -ENODEV; retval = -ENODEV;
goto error; goto error;
......
...@@ -211,6 +211,7 @@ struct usbhs_priv; ...@@ -211,6 +211,7 @@ struct usbhs_priv;
/* DCPCTR */ /* DCPCTR */
#define BSTS (1 << 15) /* Buffer Status */ #define BSTS (1 << 15) /* Buffer Status */
#define SUREQ (1 << 14) /* Sending SETUP Token */ #define SUREQ (1 << 14) /* Sending SETUP Token */
#define INBUFM (1 << 14) /* (PIPEnCTR) Transfer Buffer Monitor */
#define CSSTS (1 << 12) /* CSSTS Status */ #define CSSTS (1 << 12) /* CSSTS Status */
#define ACLRM (1 << 9) /* Buffer Auto-Clear Mode */ #define ACLRM (1 << 9) /* Buffer Auto-Clear Mode */
#define SQCLR (1 << 8) /* Toggle Bit Clear */ #define SQCLR (1 << 8) /* Toggle Bit Clear */
......
...@@ -89,7 +89,7 @@ static void __usbhsf_pkt_del(struct usbhs_pkt *pkt) ...@@ -89,7 +89,7 @@ static void __usbhsf_pkt_del(struct usbhs_pkt *pkt)
list_del_init(&pkt->node); list_del_init(&pkt->node);
} }
static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe) struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe)
{ {
return list_first_entry_or_null(&pipe->list, struct usbhs_pkt, node); return list_first_entry_or_null(&pipe->list, struct usbhs_pkt, node);
} }
......
...@@ -97,5 +97,6 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt, ...@@ -97,5 +97,6 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
void *buf, int len, int zero, int sequence); void *buf, int len, int zero, int sequence);
struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt); struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt);
void usbhs_pkt_start(struct usbhs_pipe *pipe); void usbhs_pkt_start(struct usbhs_pipe *pipe);
struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe);
#endif /* RENESAS_USB_FIFO_H */ #endif /* RENESAS_USB_FIFO_H */
...@@ -722,8 +722,7 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge) ...@@ -722,8 +722,7 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge)
struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
struct device *dev = usbhsg_gpriv_to_dev(gpriv); struct device *dev = usbhsg_gpriv_to_dev(gpriv);
unsigned long flags; unsigned long flags;
int ret = 0;
usbhsg_pipe_disable(uep);
dev_dbg(dev, "set halt %d (pipe %d)\n", dev_dbg(dev, "set halt %d (pipe %d)\n",
halt, usbhs_pipe_number(pipe)); halt, usbhs_pipe_number(pipe));
...@@ -731,6 +730,18 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge) ...@@ -731,6 +730,18 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge)
/******************** spin lock ********************/ /******************** spin lock ********************/
usbhs_lock(priv, flags); usbhs_lock(priv, flags);
/*
* According to usb_ep_set_halt()'s description, this function should
* return -EAGAIN if the IN endpoint has any queue or data. Note
* that the usbhs_pipe_is_dir_in() returns false if the pipe is an
* IN endpoint in the gadget mode.
*/
if (!usbhs_pipe_is_dir_in(pipe) && (__usbhsf_pkt_get(pipe) ||
usbhs_pipe_contains_transmittable_data(pipe))) {
ret = -EAGAIN;
goto out;
}
if (halt) if (halt)
usbhs_pipe_stall(pipe); usbhs_pipe_stall(pipe);
else else
...@@ -741,10 +752,11 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge) ...@@ -741,10 +752,11 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge)
else else
usbhsg_status_clr(gpriv, USBHSG_STATUS_WEDGE); usbhsg_status_clr(gpriv, USBHSG_STATUS_WEDGE);
out:
usbhs_unlock(priv, flags); usbhs_unlock(priv, flags);
/******************** spin unlock ******************/ /******************** spin unlock ******************/
return 0; return ret;
} }
static int usbhsg_ep_set_halt(struct usb_ep *ep, int value) static int usbhsg_ep_set_halt(struct usb_ep *ep, int value)
......
...@@ -277,6 +277,21 @@ int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe) ...@@ -277,6 +277,21 @@ int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe)
return -EBUSY; return -EBUSY;
} }
bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe)
{
u16 val;
/* Do not support for DCP pipe */
if (usbhs_pipe_is_dcp(pipe))
return false;
val = usbhsp_pipectrl_get(pipe);
if (val & INBUFM)
return true;
return false;
}
/* /*
* PID ctrl * PID ctrl
*/ */
......
...@@ -83,6 +83,7 @@ void usbhs_pipe_clear(struct usbhs_pipe *pipe); ...@@ -83,6 +83,7 @@ void usbhs_pipe_clear(struct usbhs_pipe *pipe);
void usbhs_pipe_clear_without_sequence(struct usbhs_pipe *pipe, void usbhs_pipe_clear_without_sequence(struct usbhs_pipe *pipe,
int needs_bfre, int bfre_enable); int needs_bfre, int bfre_enable);
int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe); int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe);
bool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe);
void usbhs_pipe_enable(struct usbhs_pipe *pipe); void usbhs_pipe_enable(struct usbhs_pipe *pipe);
void usbhs_pipe_disable(struct usbhs_pipe *pipe); void usbhs_pipe_disable(struct usbhs_pipe *pipe);
void usbhs_pipe_stall(struct usbhs_pipe *pipe); void usbhs_pipe_stall(struct usbhs_pipe *pipe);
......
...@@ -1030,6 +1030,9 @@ static const struct usb_device_id id_table_combined[] = { ...@@ -1030,6 +1030,9 @@ static const struct usb_device_id id_table_combined[] = {
/* EZPrototypes devices */ /* EZPrototypes devices */
{ USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) }, { USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) },
{ USB_DEVICE_INTERFACE_NUMBER(UNJO_VID, UNJO_ISODEBUG_V1_PID, 1) }, { USB_DEVICE_INTERFACE_NUMBER(UNJO_VID, UNJO_ISODEBUG_V1_PID, 1) },
/* Sienna devices */
{ USB_DEVICE(FTDI_VID, FTDI_SIENNA_PID) },
{ USB_DEVICE(ECHELON_VID, ECHELON_U20_PID) },
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
......
...@@ -39,6 +39,9 @@ ...@@ -39,6 +39,9 @@
#define FTDI_LUMEL_PD12_PID 0x6002 #define FTDI_LUMEL_PD12_PID 0x6002
/* Sienna Serial Interface by Secyourit GmbH */
#define FTDI_SIENNA_PID 0x8348
/* Cyber Cortex AV by Fabulous Silicon (http://fabuloussilicon.com) */ /* Cyber Cortex AV by Fabulous Silicon (http://fabuloussilicon.com) */
#define CYBER_CORTEX_AV_PID 0x8698 #define CYBER_CORTEX_AV_PID 0x8698
...@@ -688,6 +691,12 @@ ...@@ -688,6 +691,12 @@
#define BANDB_TTL3USB9M_PID 0xAC50 #define BANDB_TTL3USB9M_PID 0xAC50
#define BANDB_ZZ_PROG1_USB_PID 0xBA02 #define BANDB_ZZ_PROG1_USB_PID 0xBA02
/*
* Echelon USB Serial Interface
*/
#define ECHELON_VID 0x0920
#define ECHELON_U20_PID 0x7500
/* /*
* Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI * Intrepid Control Systems (http://www.intrepidcs.com/) ValueCAN and NeoVI
*/ */
......
...@@ -1741,8 +1741,8 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint, ...@@ -1741,8 +1741,8 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
ep_desc = find_ep(serial, endpoint); ep_desc = find_ep(serial, endpoint);
if (!ep_desc) { if (!ep_desc) {
/* leak the urb, something's wrong and the callers don't care */ usb_free_urb(urb);
return urb; return NULL;
} }
if (usb_endpoint_xfer_int(ep_desc)) { if (usb_endpoint_xfer_int(ep_desc)) {
ep_type_name = "INT"; ep_type_name = "INT";
......
...@@ -419,6 +419,7 @@ static void option_instat_callback(struct urb *urb); ...@@ -419,6 +419,7 @@ static void option_instat_callback(struct urb *urb);
#define CINTERION_PRODUCT_PH8_AUDIO 0x0083 #define CINTERION_PRODUCT_PH8_AUDIO 0x0083
#define CINTERION_PRODUCT_AHXX_2RMNET 0x0084 #define CINTERION_PRODUCT_AHXX_2RMNET 0x0084
#define CINTERION_PRODUCT_AHXX_AUDIO 0x0085 #define CINTERION_PRODUCT_AHXX_AUDIO 0x0085
#define CINTERION_PRODUCT_CLS8 0x00b0
/* Olivetti products */ /* Olivetti products */
#define OLIVETTI_VENDOR_ID 0x0b3c #define OLIVETTI_VENDOR_ID 0x0b3c
...@@ -1154,6 +1155,14 @@ static const struct usb_device_id option_ids[] = { ...@@ -1154,6 +1155,14 @@ static const struct usb_device_id option_ids[] = {
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) }, .driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff), { USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff),
.driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) }, .driver_info = RSVD(0) | RSVD(1) | NCTRL(2) | RSVD(3) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1050, 0xff), /* Telit FN980 (rmnet) */
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1051, 0xff), /* Telit FN980 (MBIM) */
.driver_info = NCTRL(0) | RSVD(1) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1052, 0xff), /* Telit FN980 (RNDIS) */
.driver_info = NCTRL(2) | RSVD(3) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x1053, 0xff), /* Telit FN980 (ECM) */
.driver_info = NCTRL(0) | RSVD(1) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910), { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910),
.driver_info = NCTRL(0) | RSVD(1) | RSVD(3) }, .driver_info = NCTRL(0) | RSVD(1) | RSVD(3) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM), { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM),
...@@ -1847,6 +1856,8 @@ static const struct usb_device_id option_ids[] = { ...@@ -1847,6 +1856,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = RSVD(4) }, .driver_info = RSVD(4) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_2RMNET, 0xff) }, { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_2RMNET, 0xff) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_AUDIO, 0xff) }, { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX_AUDIO, 0xff) },
{ USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_CLS8, 0xff),
.driver_info = RSVD(0) | RSVD(4) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) },
{ USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDMNET) },
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) }, { USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) },
......
...@@ -314,10 +314,7 @@ static void serial_cleanup(struct tty_struct *tty) ...@@ -314,10 +314,7 @@ static void serial_cleanup(struct tty_struct *tty)
serial = port->serial; serial = port->serial;
owner = serial->type->driver.owner; owner = serial->type->driver.owner;
mutex_lock(&serial->disc_mutex); usb_autopm_put_interface(serial->interface);
if (!serial->disconnected)
usb_autopm_put_interface(serial->interface);
mutex_unlock(&serial->disc_mutex);
usb_serial_put(serial); usb_serial_put(serial);
module_put(owner); module_put(owner);
......
...@@ -4409,18 +4409,20 @@ static int tcpm_fw_get_caps(struct tcpm_port *port, ...@@ -4409,18 +4409,20 @@ static int tcpm_fw_get_caps(struct tcpm_port *port,
/* USB data support is optional */ /* USB data support is optional */
ret = fwnode_property_read_string(fwnode, "data-role", &cap_str); ret = fwnode_property_read_string(fwnode, "data-role", &cap_str);
if (ret == 0) { if (ret == 0) {
port->typec_caps.data = typec_find_port_data_role(cap_str); ret = typec_find_port_data_role(cap_str);
if (port->typec_caps.data < 0) if (ret < 0)
return -EINVAL; return ret;
port->typec_caps.data = ret;
} }
ret = fwnode_property_read_string(fwnode, "power-role", &cap_str); ret = fwnode_property_read_string(fwnode, "power-role", &cap_str);
if (ret < 0) if (ret < 0)
return ret; return ret;
port->typec_caps.type = typec_find_port_power_role(cap_str); ret = typec_find_port_power_role(cap_str);
if (port->typec_caps.type < 0) if (ret < 0)
return -EINVAL; return ret;
port->typec_caps.type = ret;
port->port_type = port->typec_caps.type; port->port_type = port->typec_caps.type;
if (port->port_type == TYPEC_PORT_SNK) if (port->port_type == TYPEC_PORT_SNK)
......
...@@ -75,6 +75,8 @@ static int ucsi_displayport_enter(struct typec_altmode *alt) ...@@ -75,6 +75,8 @@ static int ucsi_displayport_enter(struct typec_altmode *alt)
if (cur != 0xff) { if (cur != 0xff) {
mutex_unlock(&dp->con->lock); mutex_unlock(&dp->con->lock);
if (dp->con->port_altmode[cur] == alt)
return 0;
return -EBUSY; return -EBUSY;
} }
......
...@@ -195,7 +195,6 @@ struct ucsi_ccg { ...@@ -195,7 +195,6 @@ struct ucsi_ccg {
/* fw build with vendor information */ /* fw build with vendor information */
u16 fw_build; u16 fw_build;
bool run_isr; /* flag to call ISR routine during resume */
struct work_struct pm_work; struct work_struct pm_work;
}; };
...@@ -224,18 +223,6 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) ...@@ -224,18 +223,6 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
if (quirks && quirks->max_read_len) if (quirks && quirks->max_read_len)
max_read_len = quirks->max_read_len; max_read_len = quirks->max_read_len;
if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
uc->fw_version <= CCG_OLD_FW_VERSION) {
mutex_lock(&uc->lock);
/*
* Do not schedule pm_work to run ISR in
* ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
* since we are already in ISR path.
*/
uc->run_isr = false;
mutex_unlock(&uc->lock);
}
pm_runtime_get_sync(uc->dev); pm_runtime_get_sync(uc->dev);
while (rem_len > 0) { while (rem_len > 0) {
msgs[1].buf = &data[len - rem_len]; msgs[1].buf = &data[len - rem_len];
...@@ -278,18 +265,6 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) ...@@ -278,18 +265,6 @@ static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
msgs[0].len = len + sizeof(rab); msgs[0].len = len + sizeof(rab);
msgs[0].buf = buf; msgs[0].buf = buf;
if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
uc->fw_version <= CCG_OLD_FW_VERSION) {
mutex_lock(&uc->lock);
/*
* Do not schedule pm_work to run ISR in
* ucsi_ccg_runtime_resume() after pm_runtime_get_sync()
* since we are already in ISR path.
*/
uc->run_isr = false;
mutex_unlock(&uc->lock);
}
pm_runtime_get_sync(uc->dev); pm_runtime_get_sync(uc->dev);
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (status < 0) { if (status < 0) {
...@@ -1130,7 +1105,6 @@ static int ucsi_ccg_probe(struct i2c_client *client, ...@@ -1130,7 +1105,6 @@ static int ucsi_ccg_probe(struct i2c_client *client,
uc->ppm.sync = ucsi_ccg_sync; uc->ppm.sync = ucsi_ccg_sync;
uc->dev = dev; uc->dev = dev;
uc->client = client; uc->client = client;
uc->run_isr = true;
mutex_init(&uc->lock); mutex_init(&uc->lock);
INIT_WORK(&uc->work, ccg_update_firmware); INIT_WORK(&uc->work, ccg_update_firmware);
INIT_WORK(&uc->pm_work, ccg_pm_workaround_work); INIT_WORK(&uc->pm_work, ccg_pm_workaround_work);
...@@ -1188,6 +1162,8 @@ static int ucsi_ccg_probe(struct i2c_client *client, ...@@ -1188,6 +1162,8 @@ static int ucsi_ccg_probe(struct i2c_client *client,
pm_runtime_set_active(uc->dev); pm_runtime_set_active(uc->dev);
pm_runtime_enable(uc->dev); pm_runtime_enable(uc->dev);
pm_runtime_use_autosuspend(uc->dev);
pm_runtime_set_autosuspend_delay(uc->dev, 5000);
pm_runtime_idle(uc->dev); pm_runtime_idle(uc->dev);
return 0; return 0;
...@@ -1229,7 +1205,6 @@ static int ucsi_ccg_runtime_resume(struct device *dev) ...@@ -1229,7 +1205,6 @@ static int ucsi_ccg_runtime_resume(struct device *dev)
{ {
struct i2c_client *client = to_i2c_client(dev); struct i2c_client *client = to_i2c_client(dev);
struct ucsi_ccg *uc = i2c_get_clientdata(client); struct ucsi_ccg *uc = i2c_get_clientdata(client);
bool schedule = true;
/* /*
* Firmware version 3.1.10 or earlier, built for NVIDIA has known issue * Firmware version 3.1.10 or earlier, built for NVIDIA has known issue
...@@ -1237,17 +1212,8 @@ static int ucsi_ccg_runtime_resume(struct device *dev) ...@@ -1237,17 +1212,8 @@ static int ucsi_ccg_runtime_resume(struct device *dev)
* Schedule a work to call ISR as a workaround. * Schedule a work to call ISR as a workaround.
*/ */
if (uc->fw_build == CCG_FW_BUILD_NVIDIA && if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
uc->fw_version <= CCG_OLD_FW_VERSION) { uc->fw_version <= CCG_OLD_FW_VERSION)
mutex_lock(&uc->lock); schedule_work(&uc->pm_work);
if (!uc->run_isr) {
uc->run_isr = true;
schedule = false;
}
mutex_unlock(&uc->lock);
if (schedule)
schedule_work(&uc->pm_work);
}
return 0; return 0;
} }
......
...@@ -61,6 +61,7 @@ struct usb_skel { ...@@ -61,6 +61,7 @@ struct usb_skel {
spinlock_t err_lock; /* lock for errors */ spinlock_t err_lock; /* lock for errors */
struct kref kref; struct kref kref;
struct mutex io_mutex; /* synchronize I/O with disconnect */ struct mutex io_mutex; /* synchronize I/O with disconnect */
unsigned long disconnected:1;
wait_queue_head_t bulk_in_wait; /* to wait for an ongoing read */ wait_queue_head_t bulk_in_wait; /* to wait for an ongoing read */
}; };
#define to_skel_dev(d) container_of(d, struct usb_skel, kref) #define to_skel_dev(d) container_of(d, struct usb_skel, kref)
...@@ -73,6 +74,7 @@ static void skel_delete(struct kref *kref) ...@@ -73,6 +74,7 @@ static void skel_delete(struct kref *kref)
struct usb_skel *dev = to_skel_dev(kref); struct usb_skel *dev = to_skel_dev(kref);
usb_free_urb(dev->bulk_in_urb); usb_free_urb(dev->bulk_in_urb);
usb_put_intf(dev->interface);
usb_put_dev(dev->udev); usb_put_dev(dev->udev);
kfree(dev->bulk_in_buffer); kfree(dev->bulk_in_buffer);
kfree(dev); kfree(dev);
...@@ -124,10 +126,7 @@ static int skel_release(struct inode *inode, struct file *file) ...@@ -124,10 +126,7 @@ static int skel_release(struct inode *inode, struct file *file)
return -ENODEV; return -ENODEV;
/* allow the device to be autosuspended */ /* allow the device to be autosuspended */
mutex_lock(&dev->io_mutex); usb_autopm_put_interface(dev->interface);
if (dev->interface)
usb_autopm_put_interface(dev->interface);
mutex_unlock(&dev->io_mutex);
/* decrement the count on our device */ /* decrement the count on our device */
kref_put(&dev->kref, skel_delete); kref_put(&dev->kref, skel_delete);
...@@ -231,8 +230,7 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count, ...@@ -231,8 +230,7 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count,
dev = file->private_data; dev = file->private_data;
/* if we cannot read at all, return EOF */ if (!count)
if (!dev->bulk_in_urb || !count)
return 0; return 0;
/* no concurrent readers */ /* no concurrent readers */
...@@ -240,7 +238,7 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count, ...@@ -240,7 +238,7 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count,
if (rv < 0) if (rv < 0)
return rv; return rv;
if (!dev->interface) { /* disconnect() was called */ if (dev->disconnected) { /* disconnect() was called */
rv = -ENODEV; rv = -ENODEV;
goto exit; goto exit;
} }
...@@ -422,7 +420,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, ...@@ -422,7 +420,7 @@ static ssize_t skel_write(struct file *file, const char *user_buffer,
/* this lock makes sure we don't submit URBs to gone devices */ /* this lock makes sure we don't submit URBs to gone devices */
mutex_lock(&dev->io_mutex); mutex_lock(&dev->io_mutex);
if (!dev->interface) { /* disconnect() was called */ if (dev->disconnected) { /* disconnect() was called */
mutex_unlock(&dev->io_mutex); mutex_unlock(&dev->io_mutex);
retval = -ENODEV; retval = -ENODEV;
goto error; goto error;
...@@ -507,7 +505,7 @@ static int skel_probe(struct usb_interface *interface, ...@@ -507,7 +505,7 @@ static int skel_probe(struct usb_interface *interface,
init_waitqueue_head(&dev->bulk_in_wait); init_waitqueue_head(&dev->bulk_in_wait);
dev->udev = usb_get_dev(interface_to_usbdev(interface)); dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface; dev->interface = usb_get_intf(interface);
/* set up the endpoint information */ /* set up the endpoint information */
/* use only the first bulk-in and bulk-out endpoints */ /* use only the first bulk-in and bulk-out endpoints */
...@@ -573,9 +571,10 @@ static void skel_disconnect(struct usb_interface *interface) ...@@ -573,9 +571,10 @@ static void skel_disconnect(struct usb_interface *interface)
/* prevent more I/O from starting */ /* prevent more I/O from starting */
mutex_lock(&dev->io_mutex); mutex_lock(&dev->io_mutex);
dev->interface = NULL; dev->disconnected = 1;
mutex_unlock(&dev->io_mutex); mutex_unlock(&dev->io_mutex);
usb_kill_urb(dev->bulk_in_urb);
usb_kill_anchored_urbs(&dev->submitted); usb_kill_anchored_urbs(&dev->submitted);
/* decrement our usage count */ /* decrement our usage count */
......
...@@ -1195,12 +1195,12 @@ static int vhci_start(struct usb_hcd *hcd) ...@@ -1195,12 +1195,12 @@ static int vhci_start(struct usb_hcd *hcd)
if (id == 0 && usb_hcd_is_primary_hcd(hcd)) { if (id == 0 && usb_hcd_is_primary_hcd(hcd)) {
err = vhci_init_attr_group(); err = vhci_init_attr_group();
if (err) { if (err) {
pr_err("init attr group\n"); dev_err(hcd_dev(hcd), "init attr group failed, err = %d\n", err);
return err; return err;
} }
err = sysfs_create_group(&hcd_dev(hcd)->kobj, &vhci_attr_group); err = sysfs_create_group(&hcd_dev(hcd)->kobj, &vhci_attr_group);
if (err) { if (err) {
pr_err("create sysfs files\n"); dev_err(hcd_dev(hcd), "create sysfs files failed, err = %d\n", err);
vhci_finish_attr_group(); vhci_finish_attr_group();
return err; return err;
} }
......
...@@ -64,6 +64,8 @@ extern struct resource *platform_get_resource_byname(struct platform_device *, ...@@ -64,6 +64,8 @@ extern struct resource *platform_get_resource_byname(struct platform_device *,
unsigned int, unsigned int,
const char *); const char *);
extern int platform_get_irq_byname(struct platform_device *, const char *); extern int platform_get_irq_byname(struct platform_device *, const char *);
extern int platform_get_irq_byname_optional(struct platform_device *dev,
const char *name);
extern int platform_add_devices(struct platform_device **, int); extern int platform_add_devices(struct platform_device **, int);
struct platform_device_info { struct platform_device_info {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册