USB fixes for 5.4-rc3
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. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXaH78w8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yk7mACgygFyLQ6GRUTTnGDcohZu44cuMO4AnR/MTrRq /jiXPRUMsltMV7DHcq+S =QX4p -----END PGP SIGNATURE----- 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() ...
This commit is contained in:
commit
6c90bbd0a4
|
@ -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.
|
||||
|
||||
PHY documentation is provided in the following places:
|
||||
- Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt
|
||||
- Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt
|
||||
- Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb2-phy.yaml
|
||||
- Documentation/devicetree/bindings/phy/amlogic,meson-g12a-usb3-pcie-phy.yaml
|
||||
|
||||
Example device nodes:
|
||||
usb: usb@ffe09000 {
|
||||
|
|
|
@ -63,7 +63,11 @@ properties:
|
|||
description:
|
||||
Set this flag to force EHCI reset after resume.
|
||||
|
||||
phys: true
|
||||
phys:
|
||||
description: PHY specifier for the USB PHY
|
||||
|
||||
phy-names:
|
||||
const: usb
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
@ -89,6 +93,7 @@ examples:
|
|||
interrupts = <39>;
|
||||
clocks = <&ahb_gates 1>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
};
|
||||
|
||||
...
|
||||
|
|
|
@ -67,7 +67,11 @@ properties:
|
|||
description:
|
||||
Overrides the detected port count
|
||||
|
||||
phys: true
|
||||
phys:
|
||||
description: PHY specifier for the USB PHY
|
||||
|
||||
phy-names:
|
||||
const: usb
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
@ -84,6 +88,7 @@ examples:
|
|||
interrupts = <64>;
|
||||
clocks = <&usb_clk 6>, <&ahb_gates 2>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
};
|
||||
|
||||
...
|
||||
|
|
|
@ -33,7 +33,7 @@ Required properties:
|
|||
"dma_ck": dma_bus clock for data transfer by DMA,
|
||||
"xhci_ck": controller clock
|
||||
|
||||
- phys : see usb-hcd.txt in the current directory
|
||||
- phys : see usb-hcd.yaml in the current directory
|
||||
|
||||
Optional properties:
|
||||
- wakeup-source : enable USB remote wakeup;
|
||||
|
@ -53,7 +53,7 @@ Optional properties:
|
|||
See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
|
||||
- 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.
|
||||
|
||||
Example:
|
||||
|
|
|
@ -17,7 +17,7 @@ Required properties:
|
|||
- clock-names : must contain "sys_ck" for clock of controller,
|
||||
the following clocks are optional:
|
||||
"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",
|
||||
refer to usb/generic.txt
|
||||
|
||||
|
@ -60,7 +60,7 @@ Optional properties:
|
|||
- mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0,
|
||||
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.
|
||||
|
||||
Sub-nodes:
|
||||
|
|
|
@ -18,8 +18,13 @@ properties:
|
|||
description:
|
||||
List of all the USB PHYs on this HCD
|
||||
|
||||
phy-names:
|
||||
description:
|
||||
Name specifier for the USB PHY
|
||||
|
||||
examples:
|
||||
- |
|
||||
usb {
|
||||
phys = <&usb2_phy1>, <&usb3_phy1>;
|
||||
phy-names = "usb";
|
||||
};
|
||||
|
|
|
@ -6,7 +6,7 @@ Required properties:
|
|||
- reg : Should contain 1 register ranges(address and length)
|
||||
- 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.
|
||||
|
||||
Example:
|
||||
|
|
|
@ -41,9 +41,9 @@ Optional properties:
|
|||
- usb3-lpm-capable: determines if platform is USB3 LPM capable
|
||||
- quirk-broken-port-ped: set if the controller has broken port disable mechanism
|
||||
- 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.
|
||||
|
||||
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
============
|
||||
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
|
|||
S: Maintained
|
||||
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
|
||||
M: Alan Stern <stern@rowland.harvard.edu>
|
||||
L: linux-usb@vger.kernel.org
|
||||
|
|
|
@ -520,6 +520,7 @@
|
|||
interrupts = <39>;
|
||||
clocks = <&ccu CLK_AHB_EHCI0>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -529,6 +530,7 @@
|
|||
interrupts = <64>;
|
||||
clocks = <&ccu CLK_USB_OHCI0>, <&ccu CLK_AHB_OHCI0>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -608,6 +610,7 @@
|
|||
interrupts = <40>;
|
||||
clocks = <&ccu CLK_AHB_EHCI1>;
|
||||
phys = <&usbphy 2>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -617,6 +620,7 @@
|
|||
interrupts = <65>;
|
||||
clocks = <&ccu CLK_USB_OHCI1>, <&ccu CLK_AHB_OHCI1>;
|
||||
phys = <&usbphy 2>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -391,6 +391,7 @@
|
|||
interrupts = <39>;
|
||||
clocks = <&ccu CLK_AHB_EHCI>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -400,6 +401,7 @@
|
|||
interrupts = <40>;
|
||||
clocks = <&ccu CLK_USB_OHCI>, <&ccu CLK_AHB_OHCI>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -545,6 +545,7 @@
|
|||
clocks = <&ccu CLK_AHB1_EHCI0>;
|
||||
resets = <&ccu RST_AHB1_EHCI0>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -555,6 +556,7 @@
|
|||
clocks = <&ccu CLK_AHB1_OHCI0>, <&ccu CLK_USB_OHCI0>;
|
||||
resets = <&ccu RST_AHB1_OHCI0>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -565,6 +567,7 @@
|
|||
clocks = <&ccu CLK_AHB1_EHCI1>;
|
||||
resets = <&ccu RST_AHB1_EHCI1>;
|
||||
phys = <&usbphy 2>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -575,6 +578,7 @@
|
|||
clocks = <&ccu CLK_AHB1_OHCI1>, <&ccu CLK_USB_OHCI1>;
|
||||
resets = <&ccu RST_AHB1_OHCI1>;
|
||||
phys = <&usbphy 2>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -623,6 +623,7 @@
|
|||
interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ccu CLK_AHB_EHCI0>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -632,6 +633,7 @@
|
|||
interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ccu CLK_USB_OHCI0>, <&ccu CLK_AHB_OHCI0>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -714,6 +716,7 @@
|
|||
interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ccu CLK_AHB_EHCI1>;
|
||||
phys = <&usbphy 2>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -723,6 +726,7 @@
|
|||
interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&ccu CLK_USB_OHCI1>, <&ccu CLK_AHB_OHCI1>;
|
||||
phys = <&usbphy 2>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -307,6 +307,7 @@
|
|||
clocks = <&ccu CLK_BUS_EHCI>;
|
||||
resets = <&ccu RST_BUS_EHCI>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -317,6 +318,7 @@
|
|||
clocks = <&ccu CLK_BUS_OHCI>, <&ccu CLK_USB_OHCI>;
|
||||
resets = <&ccu RST_BUS_OHCI>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -632,6 +632,7 @@
|
|||
clocks = <&ccu CLK_BUS_EHCI0>;
|
||||
resets = <&ccu RST_BUS_EHCI0>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -643,6 +644,7 @@
|
|||
clocks = <&ccu CLK_BUS_OHCI0>, <&ccu CLK_USB_OHCI0>;
|
||||
resets = <&ccu RST_BUS_OHCI0>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -654,6 +656,7 @@
|
|||
clocks = <&ccu CLK_BUS_EHCI1>;
|
||||
resets = <&ccu RST_BUS_EHCI1>;
|
||||
phys = <&usbphy 2>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -273,6 +273,7 @@
|
|||
clocks = <&ccu CLK_BUS_EHCI1>;
|
||||
resets = <&ccu RST_BUS_EHCI1>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -284,6 +285,7 @@
|
|||
<&ccu CLK_USB_OHCI1>;
|
||||
resets = <&ccu RST_BUS_OHCI1>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -294,6 +296,7 @@
|
|||
clocks = <&ccu CLK_BUS_EHCI2>;
|
||||
resets = <&ccu RST_BUS_EHCI2>;
|
||||
phys = <&usbphy 2>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -305,6 +308,7 @@
|
|||
<&ccu CLK_USB_OHCI2>;
|
||||
resets = <&ccu RST_BUS_OHCI2>;
|
||||
phys = <&usbphy 2>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -346,6 +346,7 @@
|
|||
clocks = <&usb_clocks CLK_BUS_HCI0>;
|
||||
resets = <&usb_clocks RST_USB0_HCI>;
|
||||
phys = <&usbphy1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -357,6 +358,7 @@
|
|||
<&usb_clocks CLK_USB_OHCI0>;
|
||||
resets = <&usb_clocks RST_USB0_HCI>;
|
||||
phys = <&usbphy1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -378,6 +380,7 @@
|
|||
clocks = <&usb_clocks CLK_BUS_HCI1>;
|
||||
resets = <&usb_clocks RST_USB1_HCI>;
|
||||
phys = <&usbphy2>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -407,6 +410,7 @@
|
|||
clocks = <&usb_clocks CLK_BUS_HCI2>;
|
||||
resets = <&usb_clocks RST_USB2_HCI>;
|
||||
phys = <&usbphy3>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -418,6 +422,7 @@
|
|||
<&usb_clocks CLK_USB_OHCI2>;
|
||||
resets = <&usb_clocks RST_USB2_HCI>;
|
||||
phys = <&usbphy3>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -304,6 +304,7 @@
|
|||
clocks = <&ccu CLK_BUS_EHCI1>, <&ccu CLK_BUS_OHCI1>;
|
||||
resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -315,6 +316,7 @@
|
|||
<&ccu CLK_USB_OHCI1>;
|
||||
resets = <&ccu RST_BUS_EHCI1>, <&ccu RST_BUS_OHCI1>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -325,6 +327,7 @@
|
|||
clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>;
|
||||
resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>;
|
||||
phys = <&usbphy 2>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -336,6 +339,7 @@
|
|||
<&ccu CLK_USB_OHCI2>;
|
||||
resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>;
|
||||
phys = <&usbphy 2>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -346,6 +350,7 @@
|
|||
clocks = <&ccu CLK_BUS_EHCI3>, <&ccu CLK_BUS_OHCI3>;
|
||||
resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>;
|
||||
phys = <&usbphy 3>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -357,6 +362,7 @@
|
|||
<&ccu CLK_USB_OHCI3>;
|
||||
resets = <&ccu RST_BUS_EHCI3>, <&ccu RST_BUS_OHCI3>;
|
||||
phys = <&usbphy 3>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -91,7 +91,6 @@ CONFIG_USB_SERIAL_PL2303=m
|
|||
CONFIG_USB_SERIAL_CYBERJACK=m
|
||||
CONFIG_USB_SERIAL_XIRCOM=m
|
||||
CONFIG_USB_SERIAL_OMNINET=m
|
||||
CONFIG_USB_RIO500=m
|
||||
CONFIG_EXT2_FS=m
|
||||
CONFIG_EXT3_FS=m
|
||||
CONFIG_MSDOS_FS=y
|
||||
|
|
|
@ -195,7 +195,6 @@ CONFIG_USB_SERIAL_XIRCOM=m
|
|||
CONFIG_USB_SERIAL_OMNINET=m
|
||||
CONFIG_USB_EMI62=m
|
||||
CONFIG_USB_EMI26=m
|
||||
CONFIG_USB_RIO500=m
|
||||
CONFIG_USB_LEGOTOWER=m
|
||||
CONFIG_USB_LCD=m
|
||||
CONFIG_USB_CYTHERM=m
|
||||
|
|
|
@ -581,7 +581,6 @@ CONFIG_USB_SERIAL_XIRCOM=m
|
|||
CONFIG_USB_SERIAL_OMNINET=m
|
||||
CONFIG_USB_EMI62=m
|
||||
CONFIG_USB_EMI26=m
|
||||
CONFIG_USB_RIO500=m
|
||||
CONFIG_USB_LEGOTOWER=m
|
||||
CONFIG_USB_LCD=m
|
||||
CONFIG_USB_CYTHERM=m
|
||||
|
|
|
@ -327,7 +327,6 @@ CONFIG_USB_EMI62=m
|
|||
CONFIG_USB_EMI26=m
|
||||
CONFIG_USB_ADUTUX=m
|
||||
CONFIG_USB_SEVSEG=m
|
||||
CONFIG_USB_RIO500=m
|
||||
CONFIG_USB_LEGOTOWER=m
|
||||
CONFIG_USB_LCD=m
|
||||
CONFIG_USB_CYPRESS_CY7C63=m
|
||||
|
|
|
@ -189,7 +189,6 @@ CONFIG_USB_SERIAL_XIRCOM=m
|
|||
CONFIG_USB_SERIAL_OMNINET=m
|
||||
CONFIG_USB_EMI62=m
|
||||
CONFIG_USB_EMI26=m
|
||||
CONFIG_USB_RIO500=m
|
||||
CONFIG_USB_LEGOTOWER=m
|
||||
CONFIG_USB_LCD=m
|
||||
CONFIG_USB_CYTHERM=m
|
||||
|
|
|
@ -104,6 +104,7 @@
|
|||
|
||||
&ehci0 {
|
||||
phys = <&usbphy 0>;
|
||||
phy-names = "usb";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
@ -150,6 +151,7 @@
|
|||
|
||||
&ohci0 {
|
||||
phys = <&usbphy 0>;
|
||||
phy-names = "usb";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
|
|
|
@ -553,6 +553,7 @@
|
|||
resets = <&ccu RST_BUS_OHCI1>,
|
||||
<&ccu RST_BUS_EHCI1>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -564,6 +565,7 @@
|
|||
<&ccu CLK_USB_OHCI1>;
|
||||
resets = <&ccu RST_BUS_OHCI1>;
|
||||
phys = <&usbphy 1>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -547,6 +547,7 @@
|
|||
resets = <&ccu RST_BUS_OHCI3>,
|
||||
<&ccu RST_BUS_EHCI3>;
|
||||
phys = <&usb2phy 3>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
@ -558,6 +559,7 @@
|
|||
<&ccu CLK_USB_OHCI3>;
|
||||
resets = <&ccu RST_BUS_OHCI3>;
|
||||
phys = <&usb2phy 3>;
|
||||
phy-names = "usb";
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
|
|
|
@ -571,7 +571,6 @@ CONFIG_USB_SERIAL_OMNINET=m
|
|||
CONFIG_USB_EMI62=m
|
||||
CONFIG_USB_EMI26=m
|
||||
CONFIG_USB_ADUTUX=m
|
||||
CONFIG_USB_RIO500=m
|
||||
CONFIG_USB_LEGOTOWER=m
|
||||
CONFIG_USB_LCD=m
|
||||
CONFIG_USB_CYPRESS_CY7C63=m
|
||||
|
|
|
@ -314,7 +314,6 @@ CONFIG_USB_SERIAL_SAFE_PADDED=y
|
|||
CONFIG_USB_SERIAL_CYBERJACK=m
|
||||
CONFIG_USB_SERIAL_XIRCOM=m
|
||||
CONFIG_USB_SERIAL_OMNINET=m
|
||||
CONFIG_USB_RIO500=m
|
||||
CONFIG_USB_LEGOTOWER=m
|
||||
CONFIG_USB_LCD=m
|
||||
CONFIG_USB_CYTHERM=m
|
||||
|
|
|
@ -241,12 +241,8 @@ struct resource *platform_get_resource_byname(struct platform_device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(platform_get_resource_byname);
|
||||
|
||||
/**
|
||||
* platform_get_irq_byname - get an IRQ for a device by name
|
||||
* @dev: platform device
|
||||
* @name: IRQ name
|
||||
*/
|
||||
int platform_get_irq_byname(struct platform_device *dev, const char *name)
|
||||
static int __platform_get_irq_byname(struct platform_device *dev,
|
||||
const char *name)
|
||||
{
|
||||
struct resource *r;
|
||||
|
||||
|
@ -262,11 +258,47 @@ int platform_get_irq_byname(struct platform_device *dev, const char *name)
|
|||
if (r)
|
||||
return r->start;
|
||||
|
||||
dev_err(&dev->dev, "IRQ %s not found\n", name);
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @devs: array of platform devices to add
|
||||
|
|
|
@ -643,7 +643,6 @@ static int v4l_stk_release(struct file *fp)
|
|||
dev->owner = NULL;
|
||||
}
|
||||
|
||||
if (is_present(dev))
|
||||
usb_autopm_put_interface(dev->interface);
|
||||
mutex_unlock(&dev->lock);
|
||||
return v4l2_fh_release(fp);
|
||||
|
|
|
@ -159,8 +159,9 @@ static int cdns3_pci_probe(struct pci_dev *pdev,
|
|||
wrap->plat_dev = platform_device_register_full(&plat_info);
|
||||
if (IS_ERR(wrap->plat_dev)) {
|
||||
pci_disable_device(pdev);
|
||||
err = PTR_ERR(wrap->plat_dev);
|
||||
kfree(wrap);
|
||||
return PTR_ERR(wrap->plat_dev);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -160,10 +160,28 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
|
|||
if (ret)
|
||||
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);
|
||||
if (ret)
|
||||
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;
|
||||
|
|
|
@ -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,
|
||||
struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
struct cdns3_endpoint *priv_ep;
|
||||
__le16 *response_pkt;
|
||||
u16 usb_status = 0;
|
||||
u32 recip;
|
||||
u8 index;
|
||||
|
||||
recip = ctrl->bRequestType & USB_RECIP_MASK;
|
||||
|
||||
|
@ -262,9 +264,13 @@ static int cdns3_req_ep0_get_status(struct cdns3_device *priv_dev,
|
|||
case USB_RECIP_INTERFACE:
|
||||
return cdns3_ep0_delegate_req(priv_dev, ctrl);
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
|
@ -332,7 +338,7 @@ static int cdns3_ep0_feature_handle_device(struct cdns3_device *priv_dev,
|
|||
* for sending status stage.
|
||||
* This time should be less then 3ms.
|
||||
*/
|
||||
usleep_range(1000, 2000);
|
||||
mdelay(1);
|
||||
cdns3_set_register_bit(&priv_dev->regs->usb_cmd,
|
||||
USB_CMD_STMODE |
|
||||
USB_STS_TMODE_SEL(tmode - 1));
|
||||
|
|
|
@ -2571,6 +2571,7 @@ static int cdns3_gadget_start(struct cdns3 *cdns)
|
|||
switch (max_speed) {
|
||||
case USB_SPEED_FULL:
|
||||
writel(USB_CONF_SFORCE_FS, &priv_dev->regs->usb_conf);
|
||||
writel(USB_CONF_USB3DIS, &priv_dev->regs->usb_conf);
|
||||
break;
|
||||
case USB_SPEED_HIGH:
|
||||
writel(USB_CONF_USB3DIS, &priv_dev->regs->usb_conf);
|
||||
|
@ -2662,6 +2663,13 @@ static int __cdns3_gadget_init(struct cdns3 *cdns)
|
|||
{
|
||||
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);
|
||||
pm_runtime_get_sync(cdns->dev);
|
||||
|
||||
|
|
|
@ -461,10 +461,12 @@ static int usblp_release(struct inode *inode, struct file *file)
|
|||
|
||||
mutex_lock(&usblp_mutex);
|
||||
usblp->used = 0;
|
||||
if (usblp->present) {
|
||||
if (usblp->present)
|
||||
usblp_unlink_urbs(usblp);
|
||||
|
||||
usb_autopm_put_interface(usblp->intf);
|
||||
} else /* finish cleanup from disconnect */
|
||||
|
||||
if (!usblp->present) /* finish cleanup from disconnect */
|
||||
usblp_cleanup(usblp);
|
||||
mutex_unlock(&usblp_mutex);
|
||||
return 0;
|
||||
|
|
|
@ -139,14 +139,14 @@ static int dwc3_otg_get_irq(struct dwc3 *dwc)
|
|||
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
|
||||
int irq;
|
||||
|
||||
irq = platform_get_irq_byname(dwc3_pdev, "otg");
|
||||
irq = platform_get_irq_byname_optional(dwc3_pdev, "otg");
|
||||
if (irq > 0)
|
||||
goto out;
|
||||
|
||||
if (irq == -EPROBE_DEFER)
|
||||
goto out;
|
||||
|
||||
irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3");
|
||||
irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
|
||||
if (irq > 0)
|
||||
goto out;
|
||||
|
||||
|
@ -157,9 +157,6 @@ static int dwc3_otg_get_irq(struct dwc3 *dwc)
|
|||
if (irq > 0)
|
||||
goto out;
|
||||
|
||||
if (irq != -EPROBE_DEFER)
|
||||
dev_err(dwc->dev, "missing OTG IRQ\n");
|
||||
|
||||
if (!irq)
|
||||
irq = -EINVAL;
|
||||
|
||||
|
|
|
@ -3264,14 +3264,14 @@ static int dwc3_gadget_get_irq(struct dwc3 *dwc)
|
|||
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
|
||||
int irq;
|
||||
|
||||
irq = platform_get_irq_byname(dwc3_pdev, "peripheral");
|
||||
irq = platform_get_irq_byname_optional(dwc3_pdev, "peripheral");
|
||||
if (irq > 0)
|
||||
goto out;
|
||||
|
||||
if (irq == -EPROBE_DEFER)
|
||||
goto out;
|
||||
|
||||
irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3");
|
||||
irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
|
||||
if (irq > 0)
|
||||
goto out;
|
||||
|
||||
|
@ -3282,9 +3282,6 @@ static int dwc3_gadget_get_irq(struct dwc3 *dwc)
|
|||
if (irq > 0)
|
||||
goto out;
|
||||
|
||||
if (irq != -EPROBE_DEFER)
|
||||
dev_err(dwc->dev, "missing peripheral IRQ\n");
|
||||
|
||||
if (!irq)
|
||||
irq = -EINVAL;
|
||||
|
||||
|
|
|
@ -16,14 +16,14 @@ static int dwc3_host_get_irq(struct dwc3 *dwc)
|
|||
struct platform_device *dwc3_pdev = to_platform_device(dwc->dev);
|
||||
int irq;
|
||||
|
||||
irq = platform_get_irq_byname(dwc3_pdev, "host");
|
||||
irq = platform_get_irq_byname_optional(dwc3_pdev, "host");
|
||||
if (irq > 0)
|
||||
goto out;
|
||||
|
||||
if (irq == -EPROBE_DEFER)
|
||||
goto out;
|
||||
|
||||
irq = platform_get_irq_byname(dwc3_pdev, "dwc_usb3");
|
||||
irq = platform_get_irq_byname_optional(dwc3_pdev, "dwc_usb3");
|
||||
if (irq > 0)
|
||||
goto out;
|
||||
|
||||
|
@ -34,9 +34,6 @@ static int dwc3_host_get_irq(struct dwc3 *dwc)
|
|||
if (irq > 0)
|
||||
goto out;
|
||||
|
||||
if (irq != -EPROBE_DEFER)
|
||||
dev_err(dwc->dev, "missing host IRQ\n");
|
||||
|
||||
if (!irq)
|
||||
irq = -EINVAL;
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ config USB_AT91
|
|||
|
||||
config USB_LPC32XX
|
||||
tristate "LPC32XX USB Peripheral Controller"
|
||||
depends on ARCH_LPC32XX
|
||||
depends on ARCH_LPC32XX || COMPILE_TEST
|
||||
depends on I2C
|
||||
select USB_ISP1301
|
||||
help
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#define DRIVER_VERSION "02 May 2005"
|
||||
|
||||
#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_desc[] = "USB Host+Gadget Emulator";
|
||||
|
@ -2432,7 +2433,7 @@ static int dummy_start_ss(struct dummy_hcd *dum_hcd)
|
|||
dum_hcd->rh_state = DUMMY_RH_RUNNING;
|
||||
dum_hcd->stream_en_ep = 0;
|
||||
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)->uses_new_polling = 1;
|
||||
#ifdef CONFIG_USB_OTG
|
||||
|
|
|
@ -1151,7 +1151,7 @@ static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
|
|||
u32 *p32, tmp, cbytes;
|
||||
|
||||
/* 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 */
|
||||
p32 = (u32 *) data;
|
||||
cbytes = (bytes & ~0x3);
|
||||
|
@ -1252,7 +1252,7 @@ static void udc_stuff_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes)
|
|||
u32 *p32, tmp, cbytes;
|
||||
|
||||
/* 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 */
|
||||
p32 = (u32 *) data;
|
||||
cbytes = (bytes & ~0x3);
|
||||
|
|
|
@ -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);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register device properties\n");
|
||||
platform_device_put(pdev);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
len = sg_pcopy_to_buffer(urb->sg, urb->num_sgs,
|
||||
seg->bounce_buf, new_buff_len, enqd_len);
|
||||
if (len != seg->bounce_len)
|
||||
if (len != new_buff_len)
|
||||
xhci_warn(xhci,
|
||||
"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,
|
||||
max_pkt, DMA_TO_DEVICE);
|
||||
} else {
|
||||
|
|
|
@ -1032,7 +1032,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
|
|||
writel(command, &xhci->op_regs->command);
|
||||
xhci->broken_suspend = 0;
|
||||
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
|
||||
* SSS bit of USBSTS and when driver tries to poll
|
||||
|
@ -1108,6 +1108,18 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
|||
hibernated = true;
|
||||
|
||||
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 */
|
||||
xhci_restore_registers(xhci);
|
||||
/* step 2: initialize command ring buffer */
|
||||
|
@ -3083,6 +3095,7 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
|
|||
unsigned int ep_index;
|
||||
unsigned long flags;
|
||||
u32 ep_flag;
|
||||
int err;
|
||||
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
if (!host_ep->hcpriv)
|
||||
|
@ -3142,7 +3155,17 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
|
|||
xhci_free_command(xhci, cfg_cmd);
|
||||
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);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
|
||||
|
@ -3156,8 +3179,16 @@ static void xhci_endpoint_reset(struct usb_hcd *hcd,
|
|||
ctrl_ctx, ep_flag, ep_flag);
|
||||
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);
|
||||
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);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
|
||||
|
@ -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,
|
||||
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
|
||||
* 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 ||
|
||||
alt_timeout == USB3_LPM_DEVICE_INITIATED) {
|
||||
if (alt_timeout == USB3_LPM_DISABLED) {
|
||||
*timeout = alt_timeout;
|
||||
return -E2BIG;
|
||||
}
|
||||
|
@ -4790,10 +4821,12 @@ static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd,
|
|||
if (intf->dev.driver) {
|
||||
driver = to_usb_driver(intf->dev.driver);
|
||||
if (driver && driver->disable_hub_initiated_lpm) {
|
||||
dev_dbg(&udev->dev, "Hub-initiated %s disabled "
|
||||
"at request of driver %s\n",
|
||||
dev_dbg(&udev->dev, "Hub-initiated %s disabled at request of driver %s\n",
|
||||
state_name, driver->name);
|
||||
return xhci_get_timeout_no_hub_lpm(udev, state);
|
||||
timeout = xhci_get_timeout_no_hub_lpm(udev,
|
||||
state);
|
||||
if (timeout == USB3_LPM_DISABLED)
|
||||
return timeout;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5077,10 +5110,17 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
|
|||
hcd->has_tt = 1;
|
||||
} else {
|
||||
/*
|
||||
* Some 3.1 hosts return sbrn 0x30, use xhci supported protocol
|
||||
* minor revision instead of sbrn. Minor revision is a two digit
|
||||
* BCD containing minor and sub-minor numbers, only show minor.
|
||||
* Early xHCI 1.1 spec did not mention USB 3.1 capable hosts
|
||||
* should return 0x31 for sbrn, or that the minor revision
|
||||
* 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.
|
||||
*/
|
||||
if (xhci->usb3_rhub.min_rev == 0x1)
|
||||
minor_rev = 1;
|
||||
else
|
||||
minor_rev = xhci->usb3_rhub.min_rev / 0x10;
|
||||
|
||||
switch (minor_rev) {
|
||||
|
@ -5198,8 +5238,16 @@ static void xhci_clear_tt_buffer_complete(struct usb_hcd *hcd,
|
|||
unsigned int ep_index;
|
||||
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);
|
||||
udev = (struct usb_device *)ep->hcpriv;
|
||||
if (!udev)
|
||||
return;
|
||||
slot_id = udev->slot_id;
|
||||
ep_index = xhci_get_endpoint_index(&ep->desc);
|
||||
|
||||
|
|
|
@ -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 ) {
|
||||
MTS_WARNING( "couldn't find an output bulk endpoint. Bailing out.\n" );
|
||||
|
|
|
@ -47,16 +47,6 @@ config USB_SEVSEG
|
|||
To compile this driver as a module, choose M here: the
|
||||
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
|
||||
tristate "USB Lego Infrared Tower support"
|
||||
help
|
||||
|
|
|
@ -17,7 +17,6 @@ obj-$(CONFIG_USB_ISIGHTFW) += isight_firmware.o
|
|||
obj-$(CONFIG_USB_LCD) += usblcd.o
|
||||
obj-$(CONFIG_USB_LD) += ldusb.o
|
||||
obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o
|
||||
obj-$(CONFIG_USB_RIO500) += rio500.o
|
||||
obj-$(CONFIG_USB_TEST) += usbtest.o
|
||||
obj-$(CONFIG_USB_EHSET_TEST_FIXTURE) += ehset.o
|
||||
obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
|
||||
|
|
|
@ -75,6 +75,7 @@ struct adu_device {
|
|||
char serial_number[8];
|
||||
|
||||
int open_count; /* number of times this port has been opened */
|
||||
unsigned long disconnected:1;
|
||||
|
||||
char *read_buffer_primary;
|
||||
int read_buffer_length;
|
||||
|
@ -116,7 +117,7 @@ static void adu_abort_transfers(struct adu_device *dev)
|
|||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (dev->udev == NULL)
|
||||
if (dev->disconnected)
|
||||
return;
|
||||
|
||||
/* shutdown transfer */
|
||||
|
@ -148,6 +149,7 @@ static void adu_delete(struct adu_device *dev)
|
|||
kfree(dev->read_buffer_secondary);
|
||||
kfree(dev->interrupt_in_buffer);
|
||||
kfree(dev->interrupt_out_buffer);
|
||||
usb_put_dev(dev->udev);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
|
@ -243,7 +245,7 @@ static int adu_open(struct inode *inode, struct file *file)
|
|||
}
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
if (!dev || !dev->udev) {
|
||||
if (!dev) {
|
||||
retval = -ENODEV;
|
||||
goto exit_no_device;
|
||||
}
|
||||
|
@ -326,7 +328,7 @@ static int adu_release(struct inode *inode, struct file *file)
|
|||
}
|
||||
|
||||
adu_release_internal(dev);
|
||||
if (dev->udev == NULL) {
|
||||
if (dev->disconnected) {
|
||||
/* the device was unplugged before the file was released */
|
||||
if (!dev->open_count) /* ... and we're the last user */
|
||||
adu_delete(dev);
|
||||
|
@ -354,7 +356,7 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
|
|||
return -ERESTARTSYS;
|
||||
|
||||
/* verify that the device wasn't unplugged */
|
||||
if (dev->udev == NULL) {
|
||||
if (dev->disconnected) {
|
||||
retval = -ENODEV;
|
||||
pr_err("No device or device unplugged %d\n", retval);
|
||||
goto exit;
|
||||
|
@ -518,7 +520,7 @@ static ssize_t adu_write(struct file *file, const __user char *buffer,
|
|||
goto exit_nolock;
|
||||
|
||||
/* verify that the device wasn't unplugged */
|
||||
if (dev->udev == NULL) {
|
||||
if (dev->disconnected) {
|
||||
retval = -ENODEV;
|
||||
pr_err("No device or device unplugged %d\n", retval);
|
||||
goto exit;
|
||||
|
@ -663,7 +665,7 @@ static int adu_probe(struct usb_interface *interface,
|
|||
|
||||
mutex_init(&dev->mtx);
|
||||
spin_lock_init(&dev->buflock);
|
||||
dev->udev = udev;
|
||||
dev->udev = usb_get_dev(udev);
|
||||
init_waitqueue_head(&dev->read_wait);
|
||||
init_waitqueue_head(&dev->write_wait);
|
||||
|
||||
|
@ -762,14 +764,18 @@ static void adu_disconnect(struct usb_interface *interface)
|
|||
|
||||
dev = usb_get_intfdata(interface);
|
||||
|
||||
mutex_lock(&dev->mtx); /* not interruptible */
|
||||
dev->udev = NULL; /* poison */
|
||||
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);
|
||||
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 (!dev->open_count)
|
||||
adu_delete(dev);
|
||||
|
|
|
@ -98,6 +98,7 @@ static void chaoskey_free(struct chaoskey *dev)
|
|||
usb_free_urb(dev->urb);
|
||||
kfree(dev->name);
|
||||
kfree(dev->buf);
|
||||
usb_put_intf(dev->interface);
|
||||
kfree(dev);
|
||||
}
|
||||
}
|
||||
|
@ -145,6 +146,8 @@ static int chaoskey_probe(struct usb_interface *interface,
|
|||
if (dev == NULL)
|
||||
goto out;
|
||||
|
||||
dev->interface = usb_get_intf(interface);
|
||||
|
||||
dev->buf = kmalloc(size, GFP_KERNEL);
|
||||
|
||||
if (dev->buf == NULL)
|
||||
|
@ -174,8 +177,6 @@ static int chaoskey_probe(struct usb_interface *interface,
|
|||
goto out;
|
||||
}
|
||||
|
||||
dev->interface = interface;
|
||||
|
||||
dev->in_ep = in_ep;
|
||||
|
||||
if (le16_to_cpu(udev->descriptor.idVendor) != ALEA_VENDOR_ID)
|
||||
|
|
|
@ -54,11 +54,7 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
|
|||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* Module parameters */
|
||||
static DEFINE_MUTEX(iowarrior_mutex);
|
||||
|
||||
static struct usb_driver iowarrior_driver;
|
||||
static DEFINE_MUTEX(iowarrior_open_disc_lock);
|
||||
|
||||
/*--------------*/
|
||||
/* data */
|
||||
|
@ -87,6 +83,7 @@ struct iowarrior {
|
|||
char chip_serial[9]; /* the serial number string of the chip connected */
|
||||
int report_size; /* number of bytes in a report */
|
||||
u16 product_id;
|
||||
struct usb_anchor submitted;
|
||||
};
|
||||
|
||||
/*--------------*/
|
||||
|
@ -243,6 +240,7 @@ static inline void iowarrior_delete(struct iowarrior *dev)
|
|||
kfree(dev->int_in_buffer);
|
||||
usb_free_urb(dev->int_in_urb);
|
||||
kfree(dev->read_queue);
|
||||
usb_put_intf(dev->interface);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
|
@ -424,11 +422,13 @@ static ssize_t iowarrior_write(struct file *file,
|
|||
retval = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
usb_anchor_urb(int_out_urb, &dev->submitted);
|
||||
retval = usb_submit_urb(int_out_urb, GFP_KERNEL);
|
||||
if (retval) {
|
||||
dev_dbg(&dev->interface->dev,
|
||||
"submit error %d for urb nr.%d\n",
|
||||
retval, atomic_read(&dev->write_busy));
|
||||
usb_unanchor_urb(int_out_urb);
|
||||
goto error;
|
||||
}
|
||||
/* submit was ok */
|
||||
|
@ -477,8 +477,6 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
|
|||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
/* lock this object */
|
||||
mutex_lock(&iowarrior_mutex);
|
||||
mutex_lock(&dev->mutex);
|
||||
|
||||
/* verify that the device wasn't unplugged */
|
||||
|
@ -571,7 +569,6 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
|
|||
error_out:
|
||||
/* unlock the device */
|
||||
mutex_unlock(&dev->mutex);
|
||||
mutex_unlock(&iowarrior_mutex);
|
||||
kfree(buffer);
|
||||
return retval;
|
||||
}
|
||||
|
@ -586,27 +583,20 @@ static int iowarrior_open(struct inode *inode, struct file *file)
|
|||
int subminor;
|
||||
int retval = 0;
|
||||
|
||||
mutex_lock(&iowarrior_mutex);
|
||||
subminor = iminor(inode);
|
||||
|
||||
interface = usb_find_interface(&iowarrior_driver, subminor);
|
||||
if (!interface) {
|
||||
mutex_unlock(&iowarrior_mutex);
|
||||
printk(KERN_ERR "%s - error, can't find device for minor %d\n",
|
||||
pr_err("%s - error, can't find device for minor %d\n",
|
||||
__func__, subminor);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_lock(&iowarrior_open_disc_lock);
|
||||
dev = usb_get_intfdata(interface);
|
||||
if (!dev) {
|
||||
mutex_unlock(&iowarrior_open_disc_lock);
|
||||
mutex_unlock(&iowarrior_mutex);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
mutex_unlock(&iowarrior_open_disc_lock);
|
||||
|
||||
/* Only one process can open each device, no sharing. */
|
||||
if (dev->opened) {
|
||||
|
@ -628,7 +618,6 @@ static int iowarrior_open(struct inode *inode, struct file *file)
|
|||
|
||||
out:
|
||||
mutex_unlock(&dev->mutex);
|
||||
mutex_unlock(&iowarrior_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -764,11 +753,13 @@ static int iowarrior_probe(struct usb_interface *interface,
|
|||
init_waitqueue_head(&dev->write_wait);
|
||||
|
||||
dev->udev = udev;
|
||||
dev->interface = interface;
|
||||
dev->interface = usb_get_intf(interface);
|
||||
|
||||
iface_desc = interface->cur_altsetting;
|
||||
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);
|
||||
if (res) {
|
||||
dev_err(&interface->dev, "no interrupt-in endpoint found\n");
|
||||
|
@ -836,7 +827,6 @@ static int iowarrior_probe(struct usb_interface *interface,
|
|||
if (retval) {
|
||||
/* something prevented us from registering this driver */
|
||||
dev_err(&interface->dev, "Not able to get a minor for this device.\n");
|
||||
usb_set_intfdata(interface, NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -860,26 +850,15 @@ error:
|
|||
*/
|
||||
static void iowarrior_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct iowarrior *dev;
|
||||
int 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*/
|
||||
struct iowarrior *dev = usb_get_intfdata(interface);
|
||||
int minor = dev->minor;
|
||||
|
||||
usb_deregister_dev(interface, &iowarrior_class);
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
|
||||
/* prevent device read, write and ioctl */
|
||||
|
||||
mutex_unlock(&dev->mutex);
|
||||
dev->present = 0;
|
||||
|
||||
if (dev->opened) {
|
||||
/* There is a process that holds a filedescriptor to the device ,
|
||||
|
@ -887,10 +866,13 @@ static void iowarrior_disconnect(struct usb_interface *interface)
|
|||
Deleting the device is postponed until close() was called.
|
||||
*/
|
||||
usb_kill_urb(dev->int_in_urb);
|
||||
usb_kill_anchored_urbs(&dev->submitted);
|
||||
wake_up_interruptible(&dev->read_wait);
|
||||
wake_up_interruptible(&dev->write_wait);
|
||||
mutex_unlock(&dev->mutex);
|
||||
} else {
|
||||
/* no process is using the device, cleanup now */
|
||||
mutex_unlock(&dev->mutex);
|
||||
iowarrior_delete(dev);
|
||||
}
|
||||
|
||||
|
|
|
@ -153,6 +153,7 @@ MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in
|
|||
struct ld_usb {
|
||||
struct mutex mutex; /* locks this structure */
|
||||
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 */
|
||||
|
||||
|
@ -192,11 +193,9 @@ static void ld_usb_abort_transfers(struct ld_usb *dev)
|
|||
/* shutdown transfer */
|
||||
if (dev->interrupt_in_running) {
|
||||
dev->interrupt_in_running = 0;
|
||||
if (dev->intf)
|
||||
usb_kill_urb(dev->interrupt_in_urb);
|
||||
}
|
||||
if (dev->interrupt_out_busy)
|
||||
if (dev->intf)
|
||||
usb_kill_urb(dev->interrupt_out_urb);
|
||||
}
|
||||
|
||||
|
@ -205,8 +204,6 @@ static void ld_usb_abort_transfers(struct ld_usb *dev)
|
|||
*/
|
||||
static void ld_usb_delete(struct ld_usb *dev)
|
||||
{
|
||||
ld_usb_abort_transfers(dev);
|
||||
|
||||
/* free data structures */
|
||||
usb_free_urb(dev->interrupt_in_urb);
|
||||
usb_free_urb(dev->interrupt_out_urb);
|
||||
|
@ -263,7 +260,7 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
|
|||
|
||||
resubmit:
|
||||
/* 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);
|
||||
if (retval) {
|
||||
dev_err(&dev->intf->dev,
|
||||
|
@ -392,7 +389,7 @@ static int ld_usb_release(struct inode *inode, struct file *file)
|
|||
retval = -ENODEV;
|
||||
goto unlock_exit;
|
||||
}
|
||||
if (dev->intf == NULL) {
|
||||
if (dev->disconnected) {
|
||||
/* the device was unplugged before the file was released */
|
||||
mutex_unlock(&dev->mutex);
|
||||
/* unlock here as ld_usb_delete frees dev */
|
||||
|
@ -423,7 +420,7 @@ static __poll_t ld_usb_poll(struct file *file, poll_table *wait)
|
|||
|
||||
dev = file->private_data;
|
||||
|
||||
if (!dev->intf)
|
||||
if (dev->disconnected)
|
||||
return EPOLLERR | EPOLLHUP;
|
||||
|
||||
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,
|
|||
}
|
||||
|
||||
/* verify that the device wasn't unplugged */
|
||||
if (dev->intf == NULL) {
|
||||
if (dev->disconnected) {
|
||||
retval = -ENODEV;
|
||||
printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
|
||||
goto unlock_exit;
|
||||
|
@ -542,7 +539,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
|
|||
}
|
||||
|
||||
/* verify that the device wasn't unplugged */
|
||||
if (dev->intf == NULL) {
|
||||
if (dev->disconnected) {
|
||||
retval = -ENODEV;
|
||||
printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval);
|
||||
goto unlock_exit;
|
||||
|
@ -764,6 +761,9 @@ static void ld_usb_disconnect(struct usb_interface *intf)
|
|||
/* give back our minor */
|
||||
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);
|
||||
|
||||
/* 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)
|
|||
mutex_unlock(&dev->mutex);
|
||||
ld_usb_delete(dev);
|
||||
} else {
|
||||
dev->intf = NULL;
|
||||
dev->disconnected = 1;
|
||||
/* wake up pollers */
|
||||
wake_up_interruptible_all(&dev->read_wait);
|
||||
wake_up_interruptible_all(&dev->write_wait);
|
||||
|
|
|
@ -179,7 +179,6 @@ static const struct usb_device_id tower_table[] = {
|
|||
};
|
||||
|
||||
MODULE_DEVICE_TABLE (usb, tower_table);
|
||||
static DEFINE_MUTEX(open_disc_mutex);
|
||||
|
||||
#define LEGO_USB_TOWER_MINOR_BASE 160
|
||||
|
||||
|
@ -191,6 +190,7 @@ struct lego_usb_tower {
|
|||
unsigned char minor; /* the starting minor number for this device */
|
||||
|
||||
int open_count; /* number of times this port has been opened */
|
||||
unsigned long disconnected:1;
|
||||
|
||||
char* read_buffer;
|
||||
size_t read_buffer_length; /* this much came in */
|
||||
|
@ -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)
|
||||
{
|
||||
tower_abort_transfers (dev);
|
||||
|
||||
/* free data structures */
|
||||
usb_free_urb(dev->interrupt_in_urb);
|
||||
usb_free_urb(dev->interrupt_out_urb);
|
||||
kfree (dev->read_buffer);
|
||||
kfree (dev->interrupt_in_buffer);
|
||||
kfree (dev->interrupt_out_buffer);
|
||||
usb_put_dev(dev->udev);
|
||||
kfree (dev);
|
||||
}
|
||||
|
||||
|
@ -332,18 +331,14 @@ static int tower_open (struct inode *inode, struct file *file)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
mutex_lock(&open_disc_mutex);
|
||||
dev = usb_get_intfdata(interface);
|
||||
|
||||
if (!dev) {
|
||||
mutex_unlock(&open_disc_mutex);
|
||||
retval = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* lock this device */
|
||||
if (mutex_lock_interruptible(&dev->lock)) {
|
||||
mutex_unlock(&open_disc_mutex);
|
||||
retval = -ERESTARTSYS;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -351,12 +346,9 @@ static int tower_open (struct inode *inode, struct file *file)
|
|||
|
||||
/* allow opening only once */
|
||||
if (dev->open_count) {
|
||||
mutex_unlock(&open_disc_mutex);
|
||||
retval = -EBUSY;
|
||||
goto unlock_exit;
|
||||
}
|
||||
dev->open_count = 1;
|
||||
mutex_unlock(&open_disc_mutex);
|
||||
|
||||
/* reset the tower */
|
||||
result = usb_control_msg (dev->udev,
|
||||
|
@ -396,13 +388,14 @@ static int tower_open (struct inode *inode, struct file *file)
|
|||
dev_err(&dev->udev->dev,
|
||||
"Couldn't submit interrupt_in_urb %d\n", retval);
|
||||
dev->interrupt_in_running = 0;
|
||||
dev->open_count = 0;
|
||||
goto unlock_exit;
|
||||
}
|
||||
|
||||
/* save device in the file's private structure */
|
||||
file->private_data = dev;
|
||||
|
||||
dev->open_count = 1;
|
||||
|
||||
unlock_exit:
|
||||
mutex_unlock(&dev->lock);
|
||||
|
||||
|
@ -423,10 +416,9 @@ static int tower_release (struct inode *inode, struct file *file)
|
|||
|
||||
if (dev == NULL) {
|
||||
retval = -ENODEV;
|
||||
goto exit_nolock;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mutex_lock(&open_disc_mutex);
|
||||
if (mutex_lock_interruptible(&dev->lock)) {
|
||||
retval = -ERESTARTSYS;
|
||||
goto exit;
|
||||
|
@ -438,7 +430,8 @@ static int tower_release (struct inode *inode, struct file *file)
|
|||
retval = -ENODEV;
|
||||
goto unlock_exit;
|
||||
}
|
||||
if (dev->udev == NULL) {
|
||||
|
||||
if (dev->disconnected) {
|
||||
/* the device was unplugged before the file was released */
|
||||
|
||||
/* unlock here as tower_delete frees dev */
|
||||
|
@ -456,10 +449,7 @@ static int tower_release (struct inode *inode, struct file *file)
|
|||
|
||||
unlock_exit:
|
||||
mutex_unlock(&dev->lock);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&open_disc_mutex);
|
||||
exit_nolock:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -477,10 +467,9 @@ static void tower_abort_transfers (struct lego_usb_tower *dev)
|
|||
if (dev->interrupt_in_running) {
|
||||
dev->interrupt_in_running = 0;
|
||||
mb();
|
||||
if (dev->udev)
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -516,7 +505,7 @@ static __poll_t tower_poll (struct file *file, poll_table *wait)
|
|||
|
||||
dev = file->private_data;
|
||||
|
||||
if (!dev->udev)
|
||||
if (dev->disconnected)
|
||||
return EPOLLERR | EPOLLHUP;
|
||||
|
||||
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,
|
|||
}
|
||||
|
||||
/* verify that the device wasn't unplugged */
|
||||
if (dev->udev == NULL) {
|
||||
if (dev->disconnected) {
|
||||
retval = -ENODEV;
|
||||
pr_err("No device or device unplugged %d\n", retval);
|
||||
goto unlock_exit;
|
||||
|
@ -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 */
|
||||
if (dev->udev == NULL) {
|
||||
if (dev->disconnected) {
|
||||
retval = -ENODEV;
|
||||
pr_err("No device or device unplugged %d\n", retval);
|
||||
goto unlock_exit;
|
||||
|
@ -759,7 +748,7 @@ static void tower_interrupt_in_callback (struct urb *urb)
|
|||
|
||||
resubmit:
|
||||
/* 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);
|
||||
if (retval)
|
||||
dev_err(&dev->udev->dev,
|
||||
|
@ -822,8 +811,9 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
|
|||
|
||||
mutex_init(&dev->lock);
|
||||
|
||||
dev->udev = udev;
|
||||
dev->udev = usb_get_dev(udev);
|
||||
dev->open_count = 0;
|
||||
dev->disconnected = 0;
|
||||
|
||||
dev->read_buffer = NULL;
|
||||
dev->read_buffer_length = 0;
|
||||
|
@ -891,8 +881,10 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
|
|||
get_version_reply,
|
||||
sizeof(*get_version_reply),
|
||||
1000);
|
||||
if (result < 0) {
|
||||
dev_err(idev, "LEGO USB Tower get version control request failed\n");
|
||||
if (result < sizeof(*get_version_reply)) {
|
||||
if (result >= 0)
|
||||
result = -EIO;
|
||||
dev_err(idev, "get version request failed: %d\n", result);
|
||||
retval = result;
|
||||
goto error;
|
||||
}
|
||||
|
@ -910,7 +902,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
|
|||
if (retval) {
|
||||
/* something prevented us from registering this driver */
|
||||
dev_err(idev, "Not able to get a minor for this device.\n");
|
||||
usb_set_intfdata (interface, NULL);
|
||||
goto error;
|
||||
}
|
||||
dev->minor = interface->minor;
|
||||
|
@ -942,23 +933,24 @@ static void tower_disconnect (struct usb_interface *interface)
|
|||
int minor;
|
||||
|
||||
dev = usb_get_intfdata (interface);
|
||||
mutex_lock(&open_disc_mutex);
|
||||
usb_set_intfdata (interface, NULL);
|
||||
|
||||
minor = dev->minor;
|
||||
|
||||
/* give back our minor */
|
||||
/* give back our minor and prevent further open() */
|
||||
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_unlock(&open_disc_mutex);
|
||||
|
||||
/* if the device is not opened, then we clean up right now */
|
||||
if (!dev->open_count) {
|
||||
mutex_unlock(&dev->lock);
|
||||
tower_delete (dev);
|
||||
} else {
|
||||
dev->udev = NULL;
|
||||
dev->disconnected = 1;
|
||||
/* wake up pollers */
|
||||
wake_up_interruptible_all(&dev->read_wait);
|
||||
wake_up_interruptible_all(&dev->write_wait);
|
||||
|
|
|
@ -1,554 +0,0 @@
|
|||
// 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");
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
// 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 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
|
@ -29,16 +30,12 @@
|
|||
#define IOCTL_GET_DRV_VERSION 2
|
||||
|
||||
|
||||
static DEFINE_MUTEX(lcd_mutex);
|
||||
static const struct usb_device_id id_table[] = {
|
||||
{ .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, id_table);
|
||||
|
||||
static DEFINE_MUTEX(open_disc_mutex);
|
||||
|
||||
|
||||
struct usb_lcd {
|
||||
struct usb_device *udev; /* init: probe_lcd */
|
||||
struct usb_interface *interface; /* the interface for
|
||||
|
@ -57,6 +54,8 @@ struct usb_lcd {
|
|||
using up all RAM */
|
||||
struct usb_anchor submitted; /* URBs to wait for
|
||||
before suspend */
|
||||
struct rw_semaphore io_rwsem;
|
||||
unsigned long disconnected:1;
|
||||
};
|
||||
#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)
|
|||
struct usb_interface *interface;
|
||||
int subminor, r;
|
||||
|
||||
mutex_lock(&lcd_mutex);
|
||||
subminor = iminor(inode);
|
||||
|
||||
interface = usb_find_interface(&lcd_driver, subminor);
|
||||
if (!interface) {
|
||||
mutex_unlock(&lcd_mutex);
|
||||
printk(KERN_ERR "USBLCD: %s - error, can't find device for minor %d\n",
|
||||
pr_err("USBLCD: %s - error, can't find device for minor %d\n",
|
||||
__func__, subminor);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_lock(&open_disc_mutex);
|
||||
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 */
|
||||
kref_get(&dev->kref);
|
||||
mutex_unlock(&open_disc_mutex);
|
||||
|
||||
/* grab a power reference */
|
||||
r = usb_autopm_get_interface(interface);
|
||||
if (r < 0) {
|
||||
kref_put(&dev->kref, lcd_delete);
|
||||
mutex_unlock(&lcd_mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* save our object in the file's private structure */
|
||||
file->private_data = dev;
|
||||
mutex_unlock(&lcd_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -142,6 +130,13 @@ static ssize_t lcd_read(struct file *file, char __user * buffer,
|
|||
|
||||
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 */
|
||||
retval = usb_bulk_msg(dev->udev,
|
||||
usb_rcvbulkpipe(dev->udev,
|
||||
|
@ -158,6 +153,9 @@ static ssize_t lcd_read(struct file *file, char __user * buffer,
|
|||
retval = bytes_read;
|
||||
}
|
||||
|
||||
out_up_io:
|
||||
up_read(&dev->io_rwsem);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -173,14 +171,12 @@ static long lcd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
|
||||
switch (cmd) {
|
||||
case IOCTL_GET_HARD_VERSION:
|
||||
mutex_lock(&lcd_mutex);
|
||||
bcdDevice = le16_to_cpu((dev->udev)->descriptor.bcdDevice);
|
||||
sprintf(buf, "%1d%1d.%1d%1d",
|
||||
(bcdDevice & 0xF000)>>12,
|
||||
(bcdDevice & 0xF00)>>8,
|
||||
(bcdDevice & 0xF0)>>4,
|
||||
(bcdDevice & 0xF));
|
||||
mutex_unlock(&lcd_mutex);
|
||||
if (copy_to_user((void __user *)arg, buf, strlen(buf)) != 0)
|
||||
return -EFAULT;
|
||||
break;
|
||||
|
@ -237,11 +233,18 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer,
|
|||
if (r < 0)
|
||||
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 */
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb) {
|
||||
retval = -ENOMEM;
|
||||
goto err_no_buf;
|
||||
goto err_up_io;
|
||||
}
|
||||
|
||||
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,
|
|||
the USB core will eventually free it entirely */
|
||||
usb_free_urb(urb);
|
||||
|
||||
up_read(&dev->io_rwsem);
|
||||
exit:
|
||||
return count;
|
||||
error_unanchor:
|
||||
|
@ -285,7 +289,8 @@ error_unanchor:
|
|||
error:
|
||||
usb_free_coherent(dev->udev, count, buf, urb->transfer_dma);
|
||||
usb_free_urb(urb);
|
||||
err_no_buf:
|
||||
err_up_io:
|
||||
up_read(&dev->io_rwsem);
|
||||
up(&dev->limit_sem);
|
||||
return retval;
|
||||
}
|
||||
|
@ -325,6 +330,7 @@ static int lcd_probe(struct usb_interface *interface,
|
|||
|
||||
kref_init(&dev->kref);
|
||||
sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES);
|
||||
init_rwsem(&dev->io_rwsem);
|
||||
init_usb_anchor(&dev->submitted);
|
||||
|
||||
dev->udev = usb_get_dev(interface_to_usbdev(interface));
|
||||
|
@ -365,7 +371,6 @@ static int lcd_probe(struct usb_interface *interface,
|
|||
/* something prevented us from registering this driver */
|
||||
dev_err(&interface->dev,
|
||||
"Not able to get a minor for this device.\n");
|
||||
usb_set_intfdata(interface, NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -411,17 +416,18 @@ static int lcd_resume(struct usb_interface *intf)
|
|||
|
||||
static void lcd_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_lcd *dev;
|
||||
struct usb_lcd *dev = usb_get_intfdata(interface);
|
||||
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 */
|
||||
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 */
|
||||
kref_put(&dev->kref, lcd_delete);
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ struct usb_yurex {
|
|||
|
||||
struct kref kref;
|
||||
struct mutex io_mutex;
|
||||
unsigned long disconnected:1;
|
||||
struct fasync_struct *async_queue;
|
||||
wait_queue_head_t waitq;
|
||||
|
||||
|
@ -107,6 +108,7 @@ static void yurex_delete(struct kref *kref)
|
|||
dev->int_buffer, dev->urb->transfer_dma);
|
||||
usb_free_urb(dev->urb);
|
||||
}
|
||||
usb_put_intf(dev->interface);
|
||||
usb_put_dev(dev->udev);
|
||||
kfree(dev);
|
||||
}
|
||||
|
@ -132,6 +134,7 @@ static void yurex_interrupt(struct urb *urb)
|
|||
switch (status) {
|
||||
case 0: /*success*/
|
||||
break;
|
||||
/* The device is terminated or messed up, give up */
|
||||
case -EOVERFLOW:
|
||||
dev_err(&dev->interface->dev,
|
||||
"%s - overflow with length %d, actual length is %d\n",
|
||||
|
@ -140,12 +143,13 @@ static void yurex_interrupt(struct urb *urb)
|
|||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
case -EILSEQ:
|
||||
/* The device is terminated, clean up */
|
||||
case -EPROTO:
|
||||
case -ETIME:
|
||||
return;
|
||||
default:
|
||||
dev_err(&dev->interface->dev,
|
||||
"%s - unknown status received: %d\n", __func__, status);
|
||||
goto exit;
|
||||
return;
|
||||
}
|
||||
|
||||
/* handle received message */
|
||||
|
@ -177,7 +181,6 @@ static void yurex_interrupt(struct urb *urb)
|
|||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
|
||||
if (retval) {
|
||||
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_
|
|||
init_waitqueue_head(&dev->waitq);
|
||||
|
||||
dev->udev = usb_get_dev(interface_to_usbdev(interface));
|
||||
dev->interface = interface;
|
||||
dev->interface = usb_get_intf(interface);
|
||||
|
||||
/* set up the endpoint information */
|
||||
iface_desc = interface->cur_altsetting;
|
||||
|
@ -315,8 +318,9 @@ static void yurex_disconnect(struct usb_interface *interface)
|
|||
|
||||
/* prevent more I/O from starting */
|
||||
usb_poison_urb(dev->urb);
|
||||
usb_poison_urb(dev->cntl_urb);
|
||||
mutex_lock(&dev->io_mutex);
|
||||
dev->interface = NULL;
|
||||
dev->disconnected = 1;
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
|
||||
/* wakeup waiters */
|
||||
|
@ -404,7 +408,7 @@ static ssize_t yurex_read(struct file *file, char __user *buffer, size_t count,
|
|||
dev = file->private_data;
|
||||
|
||||
mutex_lock(&dev->io_mutex);
|
||||
if (!dev->interface) { /* already disconnected */
|
||||
if (dev->disconnected) { /* already disconnected */
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -439,7 +443,7 @@ static ssize_t yurex_write(struct file *file, const char __user *user_buffer,
|
|||
goto error;
|
||||
|
||||
mutex_lock(&dev->io_mutex);
|
||||
if (!dev->interface) { /* already disconnected */
|
||||
if (dev->disconnected) { /* already disconnected */
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
retval = -ENODEV;
|
||||
goto error;
|
||||
|
|
|
@ -211,6 +211,7 @@ struct usbhs_priv;
|
|||
/* DCPCTR */
|
||||
#define BSTS (1 << 15) /* Buffer Status */
|
||||
#define SUREQ (1 << 14) /* Sending SETUP Token */
|
||||
#define INBUFM (1 << 14) /* (PIPEnCTR) Transfer Buffer Monitor */
|
||||
#define CSSTS (1 << 12) /* CSSTS Status */
|
||||
#define ACLRM (1 << 9) /* Buffer Auto-Clear Mode */
|
||||
#define SQCLR (1 << 8) /* Toggle Bit Clear */
|
||||
|
|
|
@ -89,7 +89,7 @@ static void __usbhsf_pkt_del(struct usbhs_pkt *pkt)
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -97,5 +97,6 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
|
|||
void *buf, int len, int zero, int sequence);
|
||||
struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt);
|
||||
void usbhs_pkt_start(struct usbhs_pipe *pipe);
|
||||
struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe);
|
||||
|
||||
#endif /* RENESAS_USB_FIFO_H */
|
||||
|
|
|
@ -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 device *dev = usbhsg_gpriv_to_dev(gpriv);
|
||||
unsigned long flags;
|
||||
|
||||
usbhsg_pipe_disable(uep);
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(dev, "set halt %d (pipe %d)\n",
|
||||
halt, usbhs_pipe_number(pipe));
|
||||
|
@ -731,6 +730,18 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge)
|
|||
/******************** spin lock ********************/
|
||||
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)
|
||||
usbhs_pipe_stall(pipe);
|
||||
else
|
||||
|
@ -741,10 +752,11 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge)
|
|||
else
|
||||
usbhsg_status_clr(gpriv, USBHSG_STATUS_WEDGE);
|
||||
|
||||
out:
|
||||
usbhs_unlock(priv, flags);
|
||||
/******************** spin unlock ******************/
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
|||
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
|
||||
*/
|
||||
|
|
|
@ -83,6 +83,7 @@ void usbhs_pipe_clear(struct usbhs_pipe *pipe);
|
|||
void usbhs_pipe_clear_without_sequence(struct usbhs_pipe *pipe,
|
||||
int needs_bfre, int bfre_enable);
|
||||
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_disable(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[] = {
|
|||
/* EZPrototypes devices */
|
||||
{ USB_DEVICE(EZPROTOTYPES_VID, HJELMSLUND_USB485_ISO_PID) },
|
||||
{ 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 */
|
||||
};
|
||||
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
|
||||
#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) */
|
||||
#define CYBER_CORTEX_AV_PID 0x8698
|
||||
|
||||
|
@ -688,6 +691,12 @@
|
|||
#define BANDB_TTL3USB9M_PID 0xAC50
|
||||
#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
|
||||
*/
|
||||
|
|
|
@ -1741,8 +1741,8 @@ static struct urb *keyspan_setup_urb(struct usb_serial *serial, int endpoint,
|
|||
|
||||
ep_desc = find_ep(serial, endpoint);
|
||||
if (!ep_desc) {
|
||||
/* leak the urb, something's wrong and the callers don't care */
|
||||
return urb;
|
||||
usb_free_urb(urb);
|
||||
return NULL;
|
||||
}
|
||||
if (usb_endpoint_xfer_int(ep_desc)) {
|
||||
ep_type_name = "INT";
|
||||
|
|
|
@ -419,6 +419,7 @@ static void option_instat_callback(struct urb *urb);
|
|||
#define CINTERION_PRODUCT_PH8_AUDIO 0x0083
|
||||
#define CINTERION_PRODUCT_AHXX_2RMNET 0x0084
|
||||
#define CINTERION_PRODUCT_AHXX_AUDIO 0x0085
|
||||
#define CINTERION_PRODUCT_CLS8 0x00b0
|
||||
|
||||
/* Olivetti products */
|
||||
#define OLIVETTI_VENDOR_ID 0x0b3c
|
||||
|
@ -1154,6 +1155,14 @@ static const struct usb_device_id option_ids[] = {
|
|||
.driver_info = NCTRL(0) | RSVD(1) | RSVD(2) | RSVD(3) },
|
||||
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG5, 0xff),
|
||||
.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),
|
||||
.driver_info = NCTRL(0) | RSVD(1) | RSVD(3) },
|
||||
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_ME910_DUAL_MODEM),
|
||||
|
@ -1847,6 +1856,8 @@ static const struct usb_device_id option_ids[] = {
|
|||
.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_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_MDMNET) },
|
||||
{ USB_DEVICE(SIEMENS_VENDOR_ID, CINTERION_PRODUCT_HC25_MDM) },
|
||||
|
|
|
@ -314,10 +314,7 @@ static void serial_cleanup(struct tty_struct *tty)
|
|||
serial = port->serial;
|
||||
owner = serial->type->driver.owner;
|
||||
|
||||
mutex_lock(&serial->disc_mutex);
|
||||
if (!serial->disconnected)
|
||||
usb_autopm_put_interface(serial->interface);
|
||||
mutex_unlock(&serial->disc_mutex);
|
||||
|
||||
usb_serial_put(serial);
|
||||
module_put(owner);
|
||||
|
|
|
@ -4409,18 +4409,20 @@ static int tcpm_fw_get_caps(struct tcpm_port *port,
|
|||
/* USB data support is optional */
|
||||
ret = fwnode_property_read_string(fwnode, "data-role", &cap_str);
|
||||
if (ret == 0) {
|
||||
port->typec_caps.data = typec_find_port_data_role(cap_str);
|
||||
if (port->typec_caps.data < 0)
|
||||
return -EINVAL;
|
||||
ret = typec_find_port_data_role(cap_str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
port->typec_caps.data = ret;
|
||||
}
|
||||
|
||||
ret = fwnode_property_read_string(fwnode, "power-role", &cap_str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
port->typec_caps.type = typec_find_port_power_role(cap_str);
|
||||
if (port->typec_caps.type < 0)
|
||||
return -EINVAL;
|
||||
ret = typec_find_port_power_role(cap_str);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
port->typec_caps.type = ret;
|
||||
port->port_type = port->typec_caps.type;
|
||||
|
||||
if (port->port_type == TYPEC_PORT_SNK)
|
||||
|
|
|
@ -75,6 +75,8 @@ static int ucsi_displayport_enter(struct typec_altmode *alt)
|
|||
|
||||
if (cur != 0xff) {
|
||||
mutex_unlock(&dp->con->lock);
|
||||
if (dp->con->port_altmode[cur] == alt)
|
||||
return 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
|
|
@ -195,7 +195,6 @@ struct ucsi_ccg {
|
|||
|
||||
/* fw build with vendor information */
|
||||
u16 fw_build;
|
||||
bool run_isr; /* flag to call ISR routine during resume */
|
||||
struct work_struct pm_work;
|
||||
};
|
||||
|
||||
|
@ -224,18 +223,6 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len)
|
|||
if (quirks && 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);
|
||||
while (rem_len > 0) {
|
||||
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)
|
|||
msgs[0].len = len + sizeof(rab);
|
||||
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);
|
||||
status = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||
if (status < 0) {
|
||||
|
@ -1130,7 +1105,6 @@ static int ucsi_ccg_probe(struct i2c_client *client,
|
|||
uc->ppm.sync = ucsi_ccg_sync;
|
||||
uc->dev = dev;
|
||||
uc->client = client;
|
||||
uc->run_isr = true;
|
||||
mutex_init(&uc->lock);
|
||||
INIT_WORK(&uc->work, ccg_update_firmware);
|
||||
INIT_WORK(&uc->pm_work, ccg_pm_workaround_work);
|
||||
|
@ -1188,6 +1162,8 @@ static int ucsi_ccg_probe(struct i2c_client *client,
|
|||
|
||||
pm_runtime_set_active(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);
|
||||
|
||||
return 0;
|
||||
|
@ -1229,7 +1205,6 @@ static int ucsi_ccg_runtime_resume(struct device *dev)
|
|||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct ucsi_ccg *uc = i2c_get_clientdata(client);
|
||||
bool schedule = true;
|
||||
|
||||
/*
|
||||
* 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)
|
|||
* Schedule a work to call ISR as a workaround.
|
||||
*/
|
||||
if (uc->fw_build == CCG_FW_BUILD_NVIDIA &&
|
||||
uc->fw_version <= CCG_OLD_FW_VERSION) {
|
||||
mutex_lock(&uc->lock);
|
||||
if (!uc->run_isr) {
|
||||
uc->run_isr = true;
|
||||
schedule = false;
|
||||
}
|
||||
mutex_unlock(&uc->lock);
|
||||
|
||||
if (schedule)
|
||||
uc->fw_version <= CCG_OLD_FW_VERSION)
|
||||
schedule_work(&uc->pm_work);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ struct usb_skel {
|
|||
spinlock_t err_lock; /* lock for errors */
|
||||
struct kref kref;
|
||||
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 */
|
||||
};
|
||||
#define to_skel_dev(d) container_of(d, struct usb_skel, kref)
|
||||
|
@ -73,6 +74,7 @@ static void skel_delete(struct kref *kref)
|
|||
struct usb_skel *dev = to_skel_dev(kref);
|
||||
|
||||
usb_free_urb(dev->bulk_in_urb);
|
||||
usb_put_intf(dev->interface);
|
||||
usb_put_dev(dev->udev);
|
||||
kfree(dev->bulk_in_buffer);
|
||||
kfree(dev);
|
||||
|
@ -124,10 +126,7 @@ static int skel_release(struct inode *inode, struct file *file)
|
|||
return -ENODEV;
|
||||
|
||||
/* allow the device to be autosuspended */
|
||||
mutex_lock(&dev->io_mutex);
|
||||
if (dev->interface)
|
||||
usb_autopm_put_interface(dev->interface);
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
|
||||
/* decrement the count on our device */
|
||||
kref_put(&dev->kref, skel_delete);
|
||||
|
@ -231,8 +230,7 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count,
|
|||
|
||||
dev = file->private_data;
|
||||
|
||||
/* if we cannot read at all, return EOF */
|
||||
if (!dev->bulk_in_urb || !count)
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
/* no concurrent readers */
|
||||
|
@ -240,7 +238,7 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count,
|
|||
if (rv < 0)
|
||||
return rv;
|
||||
|
||||
if (!dev->interface) { /* disconnect() was called */
|
||||
if (dev->disconnected) { /* disconnect() was called */
|
||||
rv = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
@ -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 */
|
||||
mutex_lock(&dev->io_mutex);
|
||||
if (!dev->interface) { /* disconnect() was called */
|
||||
if (dev->disconnected) { /* disconnect() was called */
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
retval = -ENODEV;
|
||||
goto error;
|
||||
|
@ -507,7 +505,7 @@ static int skel_probe(struct usb_interface *interface,
|
|||
init_waitqueue_head(&dev->bulk_in_wait);
|
||||
|
||||
dev->udev = usb_get_dev(interface_to_usbdev(interface));
|
||||
dev->interface = interface;
|
||||
dev->interface = usb_get_intf(interface);
|
||||
|
||||
/* set up the endpoint information */
|
||||
/* use only the first bulk-in and bulk-out endpoints */
|
||||
|
@ -573,9 +571,10 @@ static void skel_disconnect(struct usb_interface *interface)
|
|||
|
||||
/* prevent more I/O from starting */
|
||||
mutex_lock(&dev->io_mutex);
|
||||
dev->interface = NULL;
|
||||
dev->disconnected = 1;
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
|
||||
usb_kill_urb(dev->bulk_in_urb);
|
||||
usb_kill_anchored_urbs(&dev->submitted);
|
||||
|
||||
/* decrement our usage count */
|
||||
|
|
|
@ -1195,12 +1195,12 @@ static int vhci_start(struct usb_hcd *hcd)
|
|||
if (id == 0 && usb_hcd_is_primary_hcd(hcd)) {
|
||||
err = vhci_init_attr_group();
|
||||
if (err) {
|
||||
pr_err("init attr group\n");
|
||||
dev_err(hcd_dev(hcd), "init attr group failed, err = %d\n", err);
|
||||
return err;
|
||||
}
|
||||
err = sysfs_create_group(&hcd_dev(hcd)->kobj, &vhci_attr_group);
|
||||
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();
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -64,6 +64,8 @@ extern struct resource *platform_get_resource_byname(struct platform_device *,
|
|||
unsigned int,
|
||||
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);
|
||||
|
||||
struct platform_device_info {
|
||||
|
|
Loading…
Reference in New Issue