Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (148 commits)
  USB: serial: fix stalled writes
  USB: remove fake "address-of" expressions
  USB: fix thread-unsafe anchor utiliy routines
  USB: usbtest: support test device with only one iso-in or iso-out endpoint
  USB: usbtest: avoid to free coherent buffer in atomic context
  USB: xhci: Set DMA mask for host.
  USB: xhci: Don't flush doorbell writes.
  USB: xhci: Reduce reads and writes of interrupter registers.
  USB: xhci: Make xhci_set_hc_event_deq() static.
  USB: xhci: Minimize HW event ring dequeue pointer writes.
  USB: xhci: Make xhci_handle_event() static.
  USB: xhci: Remove unnecessary reads of IRQ_PENDING register.
  USB: xhci: Performance - move xhci_work() into xhci_irq()
  USB: xhci: Performance - move interrupt handlers into xhci-ring.c
  USB: xhci: Performance - move functions that find ep ring.
  USB:: fix linux/usb.h kernel-doc warnings
  USB: add USB serial ssu100 driver
  USB: usb-storage: implement autosuspend
  USB: ehci: fix remove of ehci debugfs dir
  USB: Add USB 2.0 to ssb ohci driver
  ...
This commit is contained in:
Linus Torvalds 2010-08-10 15:05:02 -07:00
commit 9895850b23
140 changed files with 5024 additions and 2131 deletions

View File

@ -7,3 +7,15 @@ Description:
0 -> resumed
(_UDC_ is the name of the USB Device Controller driver)
What: /sys/devices/platform/_UDC_/gadget/gadget-lunX/nofua
Date: July 2010
Contact: Andy Shevchenko <andy.shevchenko@gmail.com>
Description:
Show or set the reaction on the FUA (Force Unit Access) bit in
the SCSI WRITE(10,12) commands when a gadget in USB Mass
Storage mode.
Possible values are:
1 -> ignore the FUA flag
0 -> obey the FUA flag

View File

@ -0,0 +1,150 @@
-*- org -*-
* Overview
The Multifunction Composite Gadget (or g_multi) is a composite gadget
that makes extensive use of the composite framework to provide
a... multifunction gadget.
In it's standard configuration it provides a single USB configuration
with RNDIS[1] (that is Ethernet), USB CDC[2] ACM (that is serial) and
USB Mass Storage functions.
A CDC ECM (Ethernet) function may be turned on via a Kconfig option
and RNDIS can be turned off. If they are both enabled the gadget will
have two configurations -- one with RNDIS and another with CDC ECM[3].
Please not that if you use non-standard configuration (that is enable
CDC ECM) you may need to change vendor and/or product ID.
* Host drivers
To make use of the gadget one needs to make it work on host side --
without that there's no hope of achieving anything with the gadget.
As one might expect, things one need to do very from system to system.
** Linux host drivers
Since the gadget uses standard composite framework and appears as such
to Linux host it does not need any additional drivers on Linux host
side. All the functions are handled by respective drivers developed
for them.
This is also true for two configuration set-up with RNDIS
configuration being the first one. Linux host will use the second
configuration with CDC ECM which should work better under Linux.
** Windows host drivers
For the gadget two work under Windows two conditions have to be met:
*** Detecting as composite gadget
First of all, Windows need to detect the gadget as an USB composite
gadget which on its own have some conditions[4]. If they are met,
Windows lets USB Generic Parent Driver[5] handle the device which then
tries to much drivers for each individual interface (sort of, don't
get into too many details).
The good news is: you do not have to worry about most of the
conditions!
The only thing to worry is that the gadget has to have a single
configuration so a dual RNDIS and CDC ECM gadget won't work unless you
create a proper INF -- and of course, if you do submit it!
*** Installing drivers for each function
The other, trickier thing is making Windows install drivers for each
individual function.
For mass storage it is trivial since Windows detect it's an interface
implementing USB Mass Storage class and selects appropriate driver.
Things are harder with RDNIS and CDC ACM.
**** RNDIS
To make Windows select RNDIS drivers for the first function in the
gadget, one needs to use the [[file:linux.inf]] file provided with this
document. It "attaches" Window's RNDIS driver to the first interface
of the gadget.
Please note, that while testing we encountered some issues[6] when
RNDIS was not the first interface. You do not need to worry abut it
unless you are trying to develop your own gadget in which case watch
out for this bug.
**** CDC ACM
Similarly, [[file:linux-cdc-acm.inf]] is provided for CDC ACM.
**** Customising the gadget
If you intend to hack the g_multi gadget be advised that rearranging
functions will obviously change interface numbers for each of the
functionality. As an effect provided INFs won't work since they have
interface numbers hard-coded in them (it's not hard to change those
though[7]).
This also means, that after experimenting with g_multi and changing
provided functions one should change gadget's vendor and/or product ID
so there will be no collision with other customised gadgets or the
original gadget.
Failing to comply may cause brain damage after wondering for hours why
things don't work as intended before realising Windows have cached
some drivers information (changing USB port may sometimes help plus
you might try using USBDeview[8] to remove the phantom device).
**** INF testing
Provided INF files have been tested on Windows XP SP3, Windows Vista
and Windows 7, all 32-bit versions. It should work on 64-bit versions
as well. It most likely won't work on Windows prior to Windows XP
SP2.
** Other systems
At this moment, drivers for any other systems have not been tested.
Knowing how MacOS is based on BSD and BSD is an Open Source it is
believed that it should (read: "I have no idea whether it will") work
out-of-the-box.
For more exotic systems I have even less to say...
Any testing and drivers *are* *welcome*!
* Authors
This document has been written by Michal Nazarewicz
([[mailto:mina86@mina86.com]]). INF files have been hacked with
support of Marek Szyprowski ([[mailto:m.szyprowski@samsung.com]]) and
Xiaofan Chen ([[mailto:xiaofanc@gmail.com]]) basing on the MS RNDIS
template[9], Microchip's CDC ACM INF file and David Brownell's
([[mailto:dbrownell@users.sourceforge.net]]) original INF files.
* Footnotes
[1] Remote Network Driver Interface Specification,
[[http://msdn.microsoft.com/en-us/library/ee484414.aspx]].
[2] Communications Device Class Abstract Control Model, spec for this
and other USB classes can be found at
[[http://www.usb.org/developers/devclass_docs/]].
[3] CDC Ethernet Control Model.
[4] [[http://msdn.microsoft.com/en-us/library/ff537109(v=VS.85).aspx]]
[5] [[http://msdn.microsoft.com/en-us/library/ff539234(v=VS.85).aspx]]
[6] To put it in some other nice words, Windows failed to respond to
any user input.
[7] You may find [[http://www.cygnal.org/ubb/Forum9/HTML/001050.html]]
useful.
[8] http://www.nirsoft.net/utils/usb_devices_view.html
[9] [[http://msdn.microsoft.com/en-us/library/ff570620.aspx]]

View File

@ -151,88 +151,23 @@ instructions below to install the host side driver.
Installing the Windows Host ACM Driver
--------------------------------------
To use the Windows ACM driver you must have the files "gserial.inf"
and "usbser.sys" together in a folder on the Windows machine.
The "gserial.inf" file is given here.
-------------------- CUT HERE --------------------
[Version]
Signature="$Windows NT$"
Class=Ports
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
Provider=%LINUX%
DriverVer=08/17/2004,0.0.2.0
; Copyright (C) 2004 Al Borchers (alborchers@steinerpoint.com)
[Manufacturer]
%LINUX%=GSerialDeviceList
[GSerialDeviceList]
%GSERIAL%=GSerialInstall, USB\VID_0525&PID_A4A7
[DestinationDirs]
DefaultDestDir=10,System32\Drivers
[GSerialInstall]
CopyFiles=GSerialCopyFiles
AddReg=GSerialAddReg
[GSerialCopyFiles]
usbser.sys
[GSerialAddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,usbser.sys
HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
[GSerialInstall.Services]
AddService = usbser,0x0002,GSerialService
[GSerialService]
DisplayName = %GSERIAL_DISPLAY_NAME%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 1 ; SERVICE_ERROR_NORMAL
ServiceBinary = %10%\System32\Drivers\usbser.sys
LoadOrderGroup = Base
[Strings]
LINUX = "Linux"
GSERIAL = "Gadget Serial"
GSERIAL_DISPLAY_NAME = "USB Gadget Serial Driver"
-------------------- CUT HERE --------------------
The "usbser.sys" file comes with various versions of Windows.
For example, it can be found on Windows XP typically in
C:\WINDOWS\Driver Cache\i386\driver.cab
Or it can be found on the Windows 98SE CD in the "win98" folder
in the "DRIVER11.CAB" through "DRIVER20.CAB" cab files. You will
need the DOS "expand" program, the Cygwin "cabextract" program, or
a similar program to unpack these cab files and extract "usbser.sys".
For example, to extract "usbser.sys" into the current directory
on Windows XP, open a DOS window and run a command like
expand C:\WINDOWS\Driver~1\i386\driver.cab -F:usbser.sys .
(Thanks to Nishant Kamat for pointing out this DOS command.)
To use the Windows ACM driver you must have the "linux-cdc-acm.inf"
file (provided along this document) which supports all recent versions
of Windows.
When the gadget serial driver is loaded and the USB device connected
to the Windows host with a USB cable, Windows should recognize the
gadget serial device and ask for a driver. Tell Windows to find the
driver in the folder that contains "gserial.inf" and "usbser.sys".
driver in the folder that contains the "linux-cdc-acm.inf" file.
For example, on Windows XP, when the gadget serial device is first
plugged in, the "Found New Hardware Wizard" starts up. Select
"Install from a list or specific location (Advanced)", then on
the next screen select "Include this location in the search" and
enter the path or browse to the folder containing "gserial.inf" and
"usbser.sys". Windows will complain that the Gadget Serial driver
has not passed Windows Logo testing, but select "Continue anyway"
and finish the driver installation.
"Install from a list or specific location (Advanced)", then on the
next screen select "Include this location in the search" and enter the
path or browse to the folder containing the "linux-cdc-acm.inf" file.
Windows will complain that the Gadget Serial driver has not passed
Windows Logo testing, but select "Continue anyway" and finish the
driver installation.
On Windows XP, in the "Device Manager" (under "Control Panel",
"System", "Hardware") expand the "Ports (COM & LPT)" entry and you
@ -345,5 +280,3 @@ you should be able to send data back and forth between the gadget
side and host side systems. Anything you type on the terminal
window on the gadget side should appear in the terminal window on
the host side and vice versa.

View File

@ -0,0 +1,107 @@
; Windows USB CDC ACM Setup File
; Based on INF template which was:
; Copyright (c) 2000 Microsoft Corporation
; Copyright (c) 2007 Microchip Technology Inc.
; likely to be covered by the MLPL as found at:
; <http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL>.
; For use only on Windows operating systems.
[Version]
Signature="$Windows NT$"
Class=Ports
ClassGuid={4D36E978-E325-11CE-BFC1-08002BE10318}
Provider=%Linux%
DriverVer=11/15/2007,5.1.2600.0
[Manufacturer]
%Linux%=DeviceList, NTamd64
[DestinationDirs]
DefaultDestDir=12
;------------------------------------------------------------------------------
; Windows 2000/XP/Vista-32bit Sections
;------------------------------------------------------------------------------
[DriverInstall.nt]
include=mdmcpq.inf
CopyFiles=DriverCopyFiles.nt
AddReg=DriverInstall.nt.AddReg
[DriverCopyFiles.nt]
usbser.sys,,,0x20
[DriverInstall.nt.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,USBSER.sys
HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
[DriverInstall.nt.Services]
AddService=usbser, 0x00000002, DriverService.nt
[DriverService.nt]
DisplayName=%SERVICE%
ServiceType=1
StartType=3
ErrorControl=1
ServiceBinary=%12%\USBSER.sys
;------------------------------------------------------------------------------
; Vista-64bit Sections
;------------------------------------------------------------------------------
[DriverInstall.NTamd64]
include=mdmcpq.inf
CopyFiles=DriverCopyFiles.NTamd64
AddReg=DriverInstall.NTamd64.AddReg
[DriverCopyFiles.NTamd64]
USBSER.sys,,,0x20
[DriverInstall.NTamd64.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,USBSER.sys
HKR,,EnumPropPages32,,"MsPorts.dll,SerialPortPropPageProvider"
[DriverInstall.NTamd64.Services]
AddService=usbser, 0x00000002, DriverService.NTamd64
[DriverService.NTamd64]
DisplayName=%SERVICE%
ServiceType=1
StartType=3
ErrorControl=1
ServiceBinary=%12%\USBSER.sys
;------------------------------------------------------------------------------
; Vendor and Product ID Definitions
;------------------------------------------------------------------------------
; When developing your USB device, the VID and PID used in the PC side
; application program and the firmware on the microcontroller must match.
; Modify the below line to use your VID and PID. Use the format as shown
; below.
; Note: One INF file can be used for multiple devices with different
; VID and PIDs. For each supported device, append
; ",USB\VID_xxxx&PID_yyyy" to the end of the line.
;------------------------------------------------------------------------------
[SourceDisksFiles]
[SourceDisksNames]
[DeviceList]
%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_0525&PID_A4AB&MI_02
[DeviceList.NTamd64]
%DESCRIPTION%=DriverInstall, USB\VID_0525&PID_A4A7, USB\VID_0525&PID_A4AB&MI_02
;------------------------------------------------------------------------------
; String Definitions
;------------------------------------------------------------------------------
;Modify these strings to customize your device
;------------------------------------------------------------------------------
[Strings]
Linux = "Linux Developer Community"
DESCRIPTION = "Gadget Serial"
SERVICE = "USB RS-232 Emulation Driver"

View File

@ -1,200 +1,66 @@
; MS-Windows driver config matching some basic modes of the
; Linux-USB Ethernet/RNDIS gadget firmware:
;
; - RNDIS plus CDC Ethernet ... this may be familiar as a DOCSIS
; cable modem profile, and supports most non-Microsoft USB hosts
;
; - RNDIS plus CDC Subset ... used by hardware that incapable of
; full CDC Ethernet support.
;
; Microsoft only directly supports RNDIS drivers, and bundled them into XP.
; The Microsoft "Remote NDIS USB Driver Kit" is currently found at:
; http://www.microsoft.com/whdc/device/network/ndis/rmndis.mspx
; Based on template INF file found at
; <http://msdn.microsoft.com/en-us/library/ff570620.aspx>
; which was:
; Copyright (c) Microsoft Corporation
; and released under the MLPL as found at:
; <http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL>.
; For use only on Windows operating systems.
[Version]
Signature = "$CHICAGO$"
Signature = "$Windows NT$"
Class = Net
ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
Provider = %Linux%
Compatible = 1
MillenniumPreferred = .ME
DriverVer = 03/30/2004,0.0.0.0
; catalog file would be used by WHQL
;CatalogFile = Linux.cat
DriverVer = 06/21/2006,6.0.6000.16384
[Manufacturer]
%Linux% = LinuxDevices,NT.5.1
%Linux% = LinuxDevices,NTx86,NTamd64,NTia64
[LinuxDevices]
; NetChip IDs, used by both firmware modes
%LinuxDevice% = RNDIS, USB\VID_0525&PID_a4a2
; Decoration for x86 architecture
[LinuxDevices.NTx86]
%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00
[LinuxDevices.NT.5.1]
%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2
; Decoration for x64 architecture
[LinuxDevices.NTamd64]
%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00
; Decoration for ia64 architecture
[LinuxDevices.NTia64]
%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00
;@@@ This is the common setting for setup
[ControlFlags]
ExcludeFromSelect=*
; Windows 98, Windows 98 Second Edition specific sections --------
[RNDIS]
DeviceID = usb8023
MaxInstance = 512
DriverVer = 03/30/2004,0.0.0.0
AddReg = RNDIS_AddReg_98, RNDIS_AddReg_Common
[RNDIS_AddReg_98]
HKR, , DevLoader, 0, *ndis
HKR, , DeviceVxDs, 0, usb8023.sys
HKR, NDIS, LogDriverName, 0, "usb8023"
HKR, NDIS, MajorNdisVersion, 1, 5
HKR, NDIS, MinorNdisVersion, 1, 0
HKR, Ndi\Interfaces, DefUpper, 0, "ndis3,ndis4,ndis5"
HKR, Ndi\Interfaces, DefLower, 0, "ethernet"
HKR, Ndi\Interfaces, UpperRange, 0, "ndis3,ndis4,ndis5"
HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
HKR, Ndi\Install, ndis3, 0, "RNDIS_Install_98"
HKR, Ndi\Install, ndis4, 0, "RNDIS_Install_98"
HKR, Ndi\Install, ndis5, 0, "RNDIS_Install_98"
HKR, Ndi, DeviceId, 0, "USB\VID_0525&PID_a4a2"
[RNDIS_Install_98]
CopyFiles=RNDIS_CopyFiles_98
[RNDIS_CopyFiles_98]
usb8023.sys, usb8023w.sys, , 0
rndismp.sys, rndismpw.sys, , 0
; Windows Millennium Edition specific sections --------------------
[RNDIS.ME]
DeviceID = usb8023
MaxInstance = 512
DriverVer = 03/30/2004,0.0.0.0
AddReg = RNDIS_AddReg_ME, RNDIS_AddReg_Common
Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
BusType = 15
[RNDIS_AddReg_ME]
HKR, , DevLoader, 0, *ndis
HKR, , DeviceVxDs, 0, usb8023.sys
HKR, NDIS, LogDriverName, 0, "usb8023"
HKR, NDIS, MajorNdisVersion, 1, 5
HKR, NDIS, MinorNdisVersion, 1, 0
HKR, Ndi\Interfaces, DefUpper, 0, "ndis3,ndis4,ndis5"
HKR, Ndi\Interfaces, DefLower, 0, "ethernet"
HKR, Ndi\Interfaces, UpperRange, 0, "ndis3,ndis4,ndis5"
HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
HKR, Ndi\Install, ndis3, 0, "RNDIS_Install_ME"
HKR, Ndi\Install, ndis4, 0, "RNDIS_Install_ME"
HKR, Ndi\Install, ndis5, 0, "RNDIS_Install_ME"
HKR, Ndi, DeviceId, 0, "USB\VID_0525&PID_a4a2"
[RNDIS_Install_ME]
CopyFiles=RNDIS_CopyFiles_ME
[RNDIS_CopyFiles_ME]
usb8023.sys, usb8023m.sys, , 0
rndismp.sys, rndismpm.sys, , 0
; Windows 2000 specific sections ---------------------------------
[RNDIS.NT]
Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
BusType = 15
DriverVer = 03/30/2004,0.0.0.0
AddReg = RNDIS_AddReg_NT, RNDIS_AddReg_Common
CopyFiles = RNDIS_CopyFiles_NT
[RNDIS.NT.Services]
AddService = USB_RNDIS, 2, RNDIS_ServiceInst_NT, RNDIS_EventLog
[RNDIS_CopyFiles_NT]
; no rename of files on Windows 2000, use the 'k' names as is
usb8023k.sys, , , 0
rndismpk.sys, , , 0
[RNDIS_ServiceInst_NT]
DisplayName = %ServiceDisplayName%
ServiceType = 1
StartType = 3
ErrorControl = 1
ServiceBinary = %12%\usb8023k.sys
LoadOrderGroup = NDIS
AddReg = RNDIS_WMI_AddReg_NT
[RNDIS_WMI_AddReg_NT]
HKR, , MofImagePath, 0x00020000, "System32\drivers\rndismpk.sys"
; Windows XP specific sections -----------------------------------
; DDInstall section
; References the in-build Netrndis.inf
[RNDIS.NT.5.1]
Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
BusType = 15
DriverVer = 03/30/2004,0.0.0.0
AddReg = RNDIS_AddReg_NT, RNDIS_AddReg_Common
; no copyfiles - the files are already in place
Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
BusType = 15
; NEVER REMOVE THE FOLLOWING REFERENCE FOR NETRNDIS.INF
include = netrndis.inf
needs = Usb_Rndis.ndi
AddReg = Rndis_AddReg_Vista
; DDInstal.Services section
[RNDIS.NT.5.1.Services]
AddService = USB_RNDIS, 2, RNDIS_ServiceInst_51, RNDIS_EventLog
include = netrndis.inf
needs = Usb_Rndis.ndi.Services
[RNDIS_ServiceInst_51]
DisplayName = %ServiceDisplayName%
ServiceType = 1
StartType = 3
ErrorControl = 1
ServiceBinary = %12%\usb8023.sys
LoadOrderGroup = NDIS
AddReg = RNDIS_WMI_AddReg_51
; Optional registry settings. You can modify as needed.
[RNDIS_AddReg_Vista]
HKR, NDI\params\VistaProperty, ParamDesc, 0, %Vista_Property%
HKR, NDI\params\VistaProperty, type, 0, "edit"
HKR, NDI\params\VistaProperty, LimitText, 0, "12"
HKR, NDI\params\VistaProperty, UpperCase, 0, "1"
HKR, NDI\params\VistaProperty, default, 0, " "
HKR, NDI\params\VistaProperty, optional, 0, "1"
[RNDIS_WMI_AddReg_51]
HKR, , MofImagePath, 0x00020000, "System32\drivers\rndismp.sys"
; Windows 2000 and Windows XP common sections --------------------
[RNDIS_AddReg_NT]
HKR, Ndi, Service, 0, "USB_RNDIS"
HKR, Ndi\Interfaces, UpperRange, 0, "ndis5"
HKR, Ndi\Interfaces, LowerRange, 0, "ethernet"
[RNDIS_EventLog]
AddReg = RNDIS_EventLog_AddReg
[RNDIS_EventLog_AddReg]
HKR, , EventMessageFile, 0x00020000, "%%SystemRoot%%\System32\netevent.dll"
HKR, , TypesSupported, 0x00010001, 7
; Common Sections -------------------------------------------------
[RNDIS_AddReg_Common]
HKR, NDI\params\NetworkAddress, ParamDesc, 0, %NetworkAddress%
HKR, NDI\params\NetworkAddress, type, 0, "edit"
HKR, NDI\params\NetworkAddress, LimitText, 0, "12"
HKR, NDI\params\NetworkAddress, UpperCase, 0, "1"
HKR, NDI\params\NetworkAddress, default, 0, " "
HKR, NDI\params\NetworkAddress, optional, 0, "1"
[SourceDisksNames]
1=%SourceDisk%,,1
[SourceDisksFiles]
usb8023m.sys=1
rndismpm.sys=1
usb8023w.sys=1
rndismpw.sys=1
usb8023k.sys=1
rndismpk.sys=1
[DestinationDirs]
RNDIS_CopyFiles_98 = 10, system32/drivers
RNDIS_CopyFiles_ME = 10, system32/drivers
RNDIS_CopyFiles_NT = 12
; No sys copyfiles - the sys files are already in-build
; (part of the operating system).
; We do not support XP SP1-, 2003 SP1-, ME, 9x.
[Strings]
ServiceDisplayName = "USB Remote NDIS Network Device Driver"
NetworkAddress = "Network Address"
Linux = "Linux Developer Community"
LinuxDevice = "Linux USB Ethernet/RNDIS Gadget"
SourceDisk = "Ethernet/RNDIS Gadget Driver Install Disk"
Vista_Property = "Optional Vista Property"

View File

@ -551,9 +551,9 @@ static void __init armadillo5x0_init(void)
/* USB */
#if defined(CONFIG_USB_ULPI)
usbotg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
mxc_register_device(&mxc_otg_host, &usbotg_pdata);
mxc_register_device(&mxc_usbh2, &usbh2_pdata);

View File

@ -245,9 +245,9 @@ static struct mxc_usbh_platform_data usbh2_pdata = {
static void lilly1131_usb_init(void)
{
usbotg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
mxc_register_device(&mxc_usbh1, &usbh1_pdata);
mxc_register_device(&mxc_usbh2, &usbh2_pdata);

View File

@ -256,7 +256,7 @@ static void __init mxc_board_init(void)
#if defined(CONFIG_USB_ULPI)
/* USB */
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
mxc_register_device(&mxc_usbh2, &usbh2_pdata);
#endif

View File

@ -412,7 +412,7 @@ static struct mxc_usbh_platform_data usbh2_pdata = {
static int __init moboard_usbh2_init(void)
{
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
return mxc_register_device(&mxc_usbh2, &usbh2_pdata);
}

View File

@ -654,13 +654,13 @@ static void __init mxc_board_init(void)
#if defined(CONFIG_USB_ULPI)
if (otg_mode_host) {
otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
mxc_register_device(&mxc_otg_host, &otg_pdata);
}
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
mxc_register_device(&mxc_usbh2, &usbh2_pdata);
#endif

View File

@ -378,7 +378,7 @@ static void __init mxc_board_init(void)
#if defined(CONFIG_USB_ULPI)
if (otg_mode_host) {
otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
mxc_register_device(&mxc_otg_host, &otg_pdata);
}

View File

@ -134,7 +134,7 @@ static struct mxc_usbh_platform_data otg_host_pdata = {
static int __init smartbot_otg_host_init(void)
{
otg_host_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
return mxc_register_device(&mxc_otg_host, &otg_host_pdata);
}

View File

@ -226,6 +226,7 @@
#define S3C_DIEPMSK S3C_HSOTG_REG(0x810)
#define S3C_DIEPMSK_TxFIFOEmpty (1 << 7)
#define S3C_DIEPMSK_INEPNakEffMsk (1 << 6)
#define S3C_DIEPMSK_INTknEPMisMsk (1 << 5)
#define S3C_DIEPMSK_INTknTXFEmpMsk (1 << 4)
@ -371,6 +372,7 @@
#define S3C_DIEPDMA(_a) S3C_HSOTG_REG(0x914 + ((_a) * 0x20))
#define S3C_DOEPDMA(_a) S3C_HSOTG_REG(0xB14 + ((_a) * 0x20))
#define S3C_DTXFSTS(_a) S3C_HSOTG_REG(0x918 + ((_a) * 0x20))
#define S3C_EPFIFO(_a) S3C_HSOTG_REG(0x1000 + ((_a) * 0x1000))

View File

@ -215,7 +215,7 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf)
vhci = hcd_to_vhci(hcd);
spin_lock_irqsave(&vhci->lock, flags);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
if (!HCD_HW_ACCESSIBLE(hcd)) {
usbip_dbg_vhci_rh("hw accessible flag in on?\n");
goto done;
}
@ -269,7 +269,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u32 prev_port_status[VHCI_NPORTS];
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
if (!HCD_HW_ACCESSIBLE(hcd))
return -ETIMEDOUT;
/*
@ -1041,7 +1041,7 @@ static int vhci_bus_resume(struct usb_hcd *hcd)
dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
spin_lock_irq(&vhci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
if (!HCD_HW_ACCESSIBLE(hcd)) {
rc = -ESHUTDOWN;
} else {
/* vhci->rh_state = DUMMY_RH_RUNNING;

View File

@ -41,7 +41,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB) += misc/
obj-y += early/
obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/

View File

@ -564,7 +564,7 @@ static void cxacru_timeout_kill(unsigned long data)
}
static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
int* actual_length)
int *actual_length)
{
struct timer_list timer;
@ -952,7 +952,7 @@ static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw,
put_unaligned(cpu_to_le32(addr), (__le32 *)(buf + offb));
offb += 4;
addr += l;
if(l)
if (l)
memcpy(buf + offb, data + offd, l);
if (l < stride)
memset(buf + offb + l, 0, stride - l);
@ -967,7 +967,7 @@ static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw,
}
offb = 0;
}
} while(offd < size);
} while (offd < size);
dbg("sent fw %#x", fw);
ret = 0;
@ -1043,8 +1043,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
if (instance->modem_type->boot_rom_patch) {
val = cpu_to_le32(BR_ADDR);
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4);
}
else {
} else {
ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0);
}
if (ret) {
@ -1068,7 +1067,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
}
static int cxacru_find_firmware(struct cxacru_data *instance,
char* phase, const struct firmware **fw_p)
char *phase, const struct firmware **fw_p)
{
struct usbatm_data *usbatm = instance->usbatm;
struct device *dev = &usbatm->usb_intf->dev;

View File

@ -753,11 +753,13 @@ static struct usb_driver speedtch_usb_driver = {
.id_table = speedtch_usb_ids
};
static void speedtch_release_interfaces(struct usb_device *usb_dev, int num_interfaces) {
static void speedtch_release_interfaces(struct usb_device *usb_dev,
int num_interfaces)
{
struct usb_interface *cur_intf;
int i;
for(i = 0; i < num_interfaces; i++)
for (i = 0; i < num_interfaces; i++)
if ((cur_intf = usb_ifnum_to_if(usb_dev, i))) {
usb_set_intfdata(cur_intf, NULL);
usb_driver_release_interface(&speedtch_usb_driver, cur_intf);
@ -792,7 +794,7 @@ static int speedtch_bind(struct usbatm_data *usbatm,
/* claim all interfaces */
for (i=0; i < num_interfaces; i++) {
for (i = 0; i < num_interfaces; i++) {
cur_intf = usb_ifnum_to_if(usb_dev, i);
if ((i != ifnum) && cur_intf) {
@ -842,7 +844,7 @@ static int speedtch_bind(struct usbatm_data *usbatm,
use_isoc = 0; /* fall back to bulk if endpoint not found */
for (i=0; i<desc->desc.bNumEndpoints; i++) {
for (i = 0; i < desc->desc.bNumEndpoints; i++) {
const struct usb_endpoint_descriptor *endpoint_desc = &desc->endpoint[i].desc;
if ((endpoint_desc->bEndpointAddress == target_address)) {

View File

@ -67,6 +67,7 @@
#include <linux/mutex.h>
#include <linux/freezer.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include <asm/unaligned.h>
@ -2436,7 +2437,6 @@ UEA_ATTR(firmid, 0);
/* Retrieve the device End System Identifier (MAC) */
#define htoi(x) (isdigit(x) ? x-'0' : toupper(x)-'A'+10)
static int uea_getesi(struct uea_softc *sc, u_char * esi)
{
unsigned char mac_str[2 * ETH_ALEN + 1];
@ -2447,7 +2447,8 @@ static int uea_getesi(struct uea_softc *sc, u_char * esi)
return 1;
for (i = 0; i < ETH_ALEN; i++)
esi[i] = htoi(mac_str[2 * i]) * 16 + htoi(mac_str[2 * i + 1]);
esi[i] = hex_to_bin(mac_str[2 * i]) * 16 +
hex_to_bin(mac_str[2 * i + 1]);
return 0;
}

View File

@ -84,8 +84,8 @@
#ifdef VERBOSE_DEBUG
static int usbatm_print_packet(const unsigned char *data, int len);
#define PACKETDEBUG(arg...) usbatm_print_packet (arg)
#define vdbg(arg...) dbg (arg)
#define PACKETDEBUG(arg...) usbatm_print_packet(arg)
#define vdbg(arg...) dbg(arg)
#else
#define PACKETDEBUG(arg...)
#define vdbg(arg...)
@ -273,8 +273,7 @@ static void usbatm_complete(struct urb *urb)
if (unlikely(status) &&
(!(channel->usbatm->flags & UDSL_IGNORE_EILSEQ) ||
status != -EILSEQ ))
{
status != -EILSEQ)) {
if (status == -ESHUTDOWN)
return;
@ -494,7 +493,7 @@ static unsigned int usbatm_write_cells(struct usbatm_data *instance,
ptr += data_len;
__skb_pull(skb, data_len);
if(!left)
if (!left)
continue;
memset(ptr, 0, left);
@ -506,7 +505,7 @@ static unsigned int usbatm_write_cells(struct usbatm_data *instance,
trailer[2] = ctrl->len >> 8;
trailer[3] = ctrl->len;
ctrl->crc = ~ crc32_be(ctrl->crc, ptr, left - 4);
ctrl->crc = ~crc32_be(ctrl->crc, ptr, left - 4);
trailer[4] = ctrl->crc >> 24;
trailer[5] = ctrl->crc >> 16;
@ -516,8 +515,7 @@ static unsigned int usbatm_write_cells(struct usbatm_data *instance,
target[3] |= 0x2; /* adjust PTI */
ctrl->len = 0; /* tag this skb finished */
}
else
} else
ctrl->crc = crc32_be(ctrl->crc, ptr, left);
}
@ -1146,7 +1144,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
instance->tx_channel.endpoint = usb_sndbulkpipe(usb_dev, driver->bulk_out);
/* tx buffer size must be a positive multiple of the stride */
instance->tx_channel.buf_size = max (instance->tx_channel.stride,
instance->tx_channel.buf_size = max(instance->tx_channel.stride,
snd_buf_bytes - (snd_buf_bytes % instance->tx_channel.stride));
/* rx buffer size must be a positive multiple of the endpoint maxpacket */
@ -1159,7 +1157,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
goto fail_unbind;
}
num_packets = max (1U, (rcv_buf_bytes + maxpacket / 2) / maxpacket); /* round */
num_packets = max(1U, (rcv_buf_bytes + maxpacket / 2) / maxpacket); /* round */
if (num_packets * maxpacket > UDSL_MAX_BUF_SIZE)
num_packets--;
@ -1262,7 +1260,7 @@ int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
usb_free_urb(instance->urbs[i]);
}
kfree (instance);
kfree(instance);
return error;
}
@ -1390,9 +1388,8 @@ static int usbatm_print_packet(const unsigned char *data, int len)
for (i = 0; i < len;) {
buffer[0] = '\0';
sprintf(buffer, "%.3d :", i);
for (j = 0; (j < 16) && (i < len); j++, i++) {
for (j = 0; (j < 16) && (i < len); j++, i++)
sprintf(buffer, "%s %2.2x", buffer, data[i]);
}
dbg("%s", buffer);
}
return i;

View File

@ -48,7 +48,7 @@
dev_warn(&(instance)->usb_intf->dev, \
"failed assertion '%s' at line %d", \
__stringify(x), __LINE__); \
} while(0)
} while (0)
#endif
#define usb_err(instance, format, arg...) \
@ -59,7 +59,7 @@
dev_warn(&(instance)->usb_intf->dev , format , ## arg)
#ifdef DEBUG
#define usb_dbg(instance, format, arg...) \
dev_printk(KERN_DEBUG , &(instance)->usb_intf->dev , format , ## arg)
dev_printk(KERN_DEBUG , &(instance)->usb_intf->dev , format , ## arg)
#else
#define usb_dbg(instance, format, arg...) \
do {} while (0)
@ -104,21 +104,21 @@ struct usbatm_data;
/*
* Assuming all methods exist and succeed, they are called in this order:
*
* bind, heavy_init, atm_start, ..., atm_stop, unbind
* bind, heavy_init, atm_start, ..., atm_stop, unbind
*/
struct usbatm_driver {
const char *driver_name;
/* init device ... can sleep, or cause probe() failure */
int (*bind) (struct usbatm_data *, struct usb_interface *,
int (*bind) (struct usbatm_data *, struct usb_interface *,
const struct usb_device_id *id);
/* additional device initialization that is too slow to be done in probe() */
int (*heavy_init) (struct usbatm_data *, struct usb_interface *);
int (*heavy_init) (struct usbatm_data *, struct usb_interface *);
/* cleanup device ... can sleep, but can't fail */
void (*unbind) (struct usbatm_data *, struct usb_interface *);
void (*unbind) (struct usbatm_data *, struct usb_interface *);
/* init ATM device ... can sleep, or cause ATM initialization failure */
int (*atm_start) (struct usbatm_data *, struct atm_dev *);
@ -126,9 +126,9 @@ struct usbatm_driver {
/* cleanup ATM device ... can sleep, but can't fail */
void (*atm_stop) (struct usbatm_data *, struct atm_dev *);
int bulk_in; /* bulk rx endpoint */
int isoc_in; /* isochronous rx endpoint */
int bulk_out; /* bulk tx endpoint */
int bulk_in; /* bulk rx endpoint */
int isoc_in; /* isochronous rx endpoint */
int bulk_out; /* bulk tx endpoint */
unsigned rx_padding;
unsigned tx_padding;
@ -156,7 +156,7 @@ struct usbatm_channel {
struct usbatm_data {
/******************
* public fields *
******************/
******************/
/* mini driver */
struct usbatm_driver *driver;
@ -174,7 +174,7 @@ struct usbatm_data {
/********************************
* private fields - do not use *
********************************/
********************************/
struct kref refcount;
struct mutex serialize;

View File

@ -49,13 +49,13 @@ static struct usbatm_driver xusbatm_drivers[XUSBATM_DRIVERS_MAX];
static struct usb_device_id xusbatm_usb_ids[XUSBATM_DRIVERS_MAX + 1];
static struct usb_driver xusbatm_usb_driver;
static struct usb_interface *xusbatm_find_intf (struct usb_device *usb_dev, int altsetting, u8 ep)
static struct usb_interface *xusbatm_find_intf(struct usb_device *usb_dev, int altsetting, u8 ep)
{
struct usb_host_interface *alt;
struct usb_interface *intf;
int i, j;
for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++)
for (i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++)
if ((intf = usb_dev->actconfig->interface[i]) && (alt = usb_altnum_to_altsetting(intf, altsetting)))
for (j = 0; j < alt->desc.bNumEndpoints; j++)
if (alt->endpoint[j].desc.bEndpointAddress == ep)
@ -63,7 +63,7 @@ static struct usb_interface *xusbatm_find_intf (struct usb_device *usb_dev, int
return NULL;
}
static int xusbatm_capture_intf (struct usbatm_data *usbatm, struct usb_device *usb_dev,
static int xusbatm_capture_intf(struct usbatm_data *usbatm, struct usb_device *usb_dev,
struct usb_interface *intf, int altsetting, int claim)
{
int ifnum = intf->altsetting->desc.bInterfaceNumber;
@ -80,7 +80,7 @@ static int xusbatm_capture_intf (struct usbatm_data *usbatm, struct usb_device *
return 0;
}
static void xusbatm_release_intf (struct usb_device *usb_dev, struct usb_interface *intf, int claimed)
static void xusbatm_release_intf(struct usb_device *usb_dev, struct usb_interface *intf, int claimed)
{
if (claimed) {
usb_set_intfdata(intf, NULL);
@ -147,7 +147,7 @@ static void xusbatm_unbind(struct usbatm_data *usbatm,
usb_dbg(usbatm, "%s entered\n", __func__);
for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) {
for (i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *cur_intf = usb_dev->actconfig->interface[i];
if (cur_intf && (usb_get_intfdata(cur_intf) == usbatm)) {

View File

@ -264,7 +264,7 @@ static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg)
if (unlikely(hcd->state == HC_STATE_HALT))
return;
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
if (!HCD_HW_ACCESSIBLE(hcd))
return;
/* Handle Start of frame events */
@ -282,7 +282,7 @@ static int c67x00_hcd_start(struct usb_hcd *hcd)
{
hcd->uses_new_polling = 1;
hcd->state = HC_STATE_RUNNING;
hcd->poll_rh = 1;
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
return 0;
}

View File

@ -135,7 +135,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
* ->lock locks what interrupt accesses.
*/
struct usblp {
struct usb_device *dev; /* USB device */
struct usb_device *dev; /* USB device */
struct mutex wmut;
struct mutex mut;
spinlock_t lock; /* locks rcomplete, wcomplete */
@ -169,7 +169,8 @@ struct usblp {
};
#ifdef DEBUG
static void usblp_dump(struct usblp *usblp) {
static void usblp_dump(struct usblp *usblp)
{
int p;
dbg("usblp=0x%p", usblp);
@ -254,9 +255,8 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
/* High byte has the interface index.
Low byte has the alternate setting.
*/
if ((request == USBLP_REQ_GET_ID) && (type == USB_TYPE_CLASS)) {
index = (usblp->ifnum<<8)|usblp->protocol[usblp->current_protocol].alt_setting;
}
if ((request == USBLP_REQ_GET_ID) && (type == USB_TYPE_CLASS))
index = (usblp->ifnum<<8)|usblp->protocol[usblp->current_protocol].alt_setting;
retval = usb_control_msg(usblp->dev,
dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
@ -372,7 +372,7 @@ static int usblp_check_status(struct usblp *usblp, int err)
return newerr;
}
static int handle_bidir (struct usblp *usblp)
static int handle_bidir(struct usblp *usblp)
{
if (usblp->bidir && usblp->used) {
if (usblp_submit_read(usblp) < 0)
@ -395,14 +395,13 @@ static int usblp_open(struct inode *inode, struct file *file)
if (minor < 0)
return -ENODEV;
mutex_lock (&usblp_mutex);
mutex_lock(&usblp_mutex);
retval = -ENODEV;
intf = usb_find_interface(&usblp_driver, minor);
if (!intf) {
if (!intf)
goto out;
}
usblp = usb_get_intfdata (intf);
usblp = usb_get_intfdata(intf);
if (!usblp || !usblp->dev || !usblp->present)
goto out;
@ -433,18 +432,18 @@ static int usblp_open(struct inode *inode, struct file *file)
retval = -EIO;
}
out:
mutex_unlock (&usblp_mutex);
mutex_unlock(&usblp_mutex);
return retval;
}
static void usblp_cleanup (struct usblp *usblp)
static void usblp_cleanup(struct usblp *usblp)
{
printk(KERN_INFO "usblp%d: removed\n", usblp->minor);
kfree(usblp->readbuf);
kfree (usblp->device_id_string);
kfree (usblp->statusbuf);
kfree (usblp);
kfree(usblp->device_id_string);
kfree(usblp->statusbuf);
kfree(usblp);
}
static void usblp_unlink_urbs(struct usblp *usblp)
@ -458,14 +457,14 @@ static int usblp_release(struct inode *inode, struct file *file)
usblp->flags &= ~LP_ABORT;
mutex_lock (&usblp_mutex);
mutex_lock(&usblp_mutex);
usblp->used = 0;
if (usblp->present) {
usblp_unlink_urbs(usblp);
usb_autopm_put_interface(usblp->intf);
} else /* finish cleanup from disconnect */
usblp_cleanup (usblp);
mutex_unlock (&usblp_mutex);
} else /* finish cleanup from disconnect */
usblp_cleanup(usblp);
mutex_unlock(&usblp_mutex);
return 0;
}
@ -495,190 +494,190 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int twoints[2];
int retval = 0;
mutex_lock (&usblp->mut);
mutex_lock(&usblp->mut);
if (!usblp->present) {
retval = -ENODEV;
goto done;
}
dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd));
if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */
switch (_IOC_NR(cmd)) {
case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
if (_IOC_DIR(cmd) != _IOC_READ) {
retval = -EINVAL;
goto done;
}
case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
if (_IOC_DIR(cmd) != _IOC_READ) {
retval = -EINVAL;
goto done;
}
length = usblp_cache_device_id_string(usblp);
if (length < 0) {
retval = length;
goto done;
}
if (length > _IOC_SIZE(cmd))
length = _IOC_SIZE(cmd); /* truncate */
length = usblp_cache_device_id_string(usblp);
if (length < 0) {
retval = length;
goto done;
}
if (length > _IOC_SIZE(cmd))
length = _IOC_SIZE(cmd); /* truncate */
if (copy_to_user((void __user *) arg,
usblp->device_id_string,
(unsigned long) length)) {
retval = -EFAULT;
goto done;
}
if (copy_to_user((void __user *) arg,
usblp->device_id_string,
(unsigned long) length)) {
retval = -EFAULT;
goto done;
}
break;
break;
case IOCNR_GET_PROTOCOLS:
if (_IOC_DIR(cmd) != _IOC_READ ||
_IOC_SIZE(cmd) < sizeof(twoints)) {
retval = -EINVAL;
goto done;
}
case IOCNR_GET_PROTOCOLS:
if (_IOC_DIR(cmd) != _IOC_READ ||
_IOC_SIZE(cmd) < sizeof(twoints)) {
retval = -EINVAL;
goto done;
}
twoints[0] = usblp->current_protocol;
twoints[1] = 0;
for (i = USBLP_FIRST_PROTOCOL;
i <= USBLP_LAST_PROTOCOL; i++) {
if (usblp->protocol[i].alt_setting >= 0)
twoints[1] |= (1<<i);
}
twoints[0] = usblp->current_protocol;
twoints[1] = 0;
for (i = USBLP_FIRST_PROTOCOL;
i <= USBLP_LAST_PROTOCOL; i++) {
if (usblp->protocol[i].alt_setting >= 0)
twoints[1] |= (1<<i);
}
if (copy_to_user((void __user *)arg,
(unsigned char *)twoints,
sizeof(twoints))) {
retval = -EFAULT;
goto done;
}
if (copy_to_user((void __user *)arg,
(unsigned char *)twoints,
sizeof(twoints))) {
retval = -EFAULT;
goto done;
}
break;
break;
case IOCNR_SET_PROTOCOL:
if (_IOC_DIR(cmd) != _IOC_WRITE) {
retval = -EINVAL;
goto done;
}
case IOCNR_SET_PROTOCOL:
if (_IOC_DIR(cmd) != _IOC_WRITE) {
retval = -EINVAL;
goto done;
}
#ifdef DEBUG
if (arg == -10) {
usblp_dump(usblp);
break;
}
if (arg == -10) {
usblp_dump(usblp);
break;
}
#endif
usblp_unlink_urbs(usblp);
retval = usblp_set_protocol(usblp, arg);
if (retval < 0) {
usblp_set_protocol(usblp,
usblp->current_protocol);
}
break;
usblp_unlink_urbs(usblp);
retval = usblp_set_protocol(usblp, arg);
if (retval < 0) {
usblp_set_protocol(usblp,
usblp->current_protocol);
}
break;
case IOCNR_HP_SET_CHANNEL:
if (_IOC_DIR(cmd) != _IOC_WRITE ||
le16_to_cpu(usblp->dev->descriptor.idVendor) != 0x03F0 ||
usblp->quirks & USBLP_QUIRK_BIDIR) {
retval = -EINVAL;
goto done;
}
case IOCNR_HP_SET_CHANNEL:
if (_IOC_DIR(cmd) != _IOC_WRITE ||
le16_to_cpu(usblp->dev->descriptor.idVendor) != 0x03F0 ||
usblp->quirks & USBLP_QUIRK_BIDIR) {
retval = -EINVAL;
goto done;
}
err = usblp_hp_channel_change_request(usblp,
arg, &newChannel);
if (err < 0) {
dev_err(&usblp->dev->dev,
"usblp%d: error = %d setting "
"HP channel\n",
usblp->minor, err);
retval = -EIO;
goto done;
}
err = usblp_hp_channel_change_request(usblp,
arg, &newChannel);
if (err < 0) {
dev_err(&usblp->dev->dev,
"usblp%d: error = %d setting "
"HP channel\n",
usblp->minor, err);
retval = -EIO;
goto done;
}
dbg("usblp%d requested/got HP channel %ld/%d",
usblp->minor, arg, newChannel);
break;
dbg("usblp%d requested/got HP channel %ld/%d",
usblp->minor, arg, newChannel);
break;
case IOCNR_GET_BUS_ADDRESS:
if (_IOC_DIR(cmd) != _IOC_READ ||
_IOC_SIZE(cmd) < sizeof(twoints)) {
retval = -EINVAL;
goto done;
}
case IOCNR_GET_BUS_ADDRESS:
if (_IOC_DIR(cmd) != _IOC_READ ||
_IOC_SIZE(cmd) < sizeof(twoints)) {
retval = -EINVAL;
goto done;
}
twoints[0] = usblp->dev->bus->busnum;
twoints[1] = usblp->dev->devnum;
if (copy_to_user((void __user *)arg,
(unsigned char *)twoints,
sizeof(twoints))) {
retval = -EFAULT;
goto done;
}
twoints[0] = usblp->dev->bus->busnum;
twoints[1] = usblp->dev->devnum;
if (copy_to_user((void __user *)arg,
(unsigned char *)twoints,
sizeof(twoints))) {
retval = -EFAULT;
goto done;
}
dbg("usblp%d is bus=%d, device=%d",
usblp->minor, twoints[0], twoints[1]);
break;
dbg("usblp%d is bus=%d, device=%d",
usblp->minor, twoints[0], twoints[1]);
break;
case IOCNR_GET_VID_PID:
if (_IOC_DIR(cmd) != _IOC_READ ||
_IOC_SIZE(cmd) < sizeof(twoints)) {
retval = -EINVAL;
goto done;
}
case IOCNR_GET_VID_PID:
if (_IOC_DIR(cmd) != _IOC_READ ||
_IOC_SIZE(cmd) < sizeof(twoints)) {
retval = -EINVAL;
goto done;
}
twoints[0] = le16_to_cpu(usblp->dev->descriptor.idVendor);
twoints[1] = le16_to_cpu(usblp->dev->descriptor.idProduct);
if (copy_to_user((void __user *)arg,
(unsigned char *)twoints,
sizeof(twoints))) {
retval = -EFAULT;
goto done;
}
twoints[0] = le16_to_cpu(usblp->dev->descriptor.idVendor);
twoints[1] = le16_to_cpu(usblp->dev->descriptor.idProduct);
if (copy_to_user((void __user *)arg,
(unsigned char *)twoints,
sizeof(twoints))) {
retval = -EFAULT;
goto done;
}
dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X",
usblp->minor, twoints[0], twoints[1]);
break;
dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X",
usblp->minor, twoints[0], twoints[1]);
break;
case IOCNR_SOFT_RESET:
if (_IOC_DIR(cmd) != _IOC_NONE) {
retval = -EINVAL;
goto done;
}
retval = usblp_reset(usblp);
break;
default:
retval = -ENOTTY;
case IOCNR_SOFT_RESET:
if (_IOC_DIR(cmd) != _IOC_NONE) {
retval = -EINVAL;
goto done;
}
retval = usblp_reset(usblp);
break;
default:
retval = -ENOTTY;
}
else /* old-style ioctl value */
switch (cmd) {
case LPGETSTATUS:
if ((retval = usblp_read_status(usblp, usblp->statusbuf))) {
if (printk_ratelimit())
printk(KERN_ERR "usblp%d:"
"failed reading printer status (%d)\n",
usblp->minor, retval);
retval = -EIO;
goto done;
}
status = *usblp->statusbuf;
if (copy_to_user ((void __user *)arg, &status, sizeof(int)))
retval = -EFAULT;
break;
case LPGETSTATUS:
if ((retval = usblp_read_status(usblp, usblp->statusbuf))) {
if (printk_ratelimit())
printk(KERN_ERR "usblp%d:"
"failed reading printer status (%d)\n",
usblp->minor, retval);
retval = -EIO;
goto done;
}
status = *usblp->statusbuf;
if (copy_to_user((void __user *)arg, &status, sizeof(int)))
retval = -EFAULT;
break;
case LPABORT:
if (arg)
usblp->flags |= LP_ABORT;
else
usblp->flags &= ~LP_ABORT;
break;
case LPABORT:
if (arg)
usblp->flags |= LP_ABORT;
else
usblp->flags &= ~LP_ABORT;
break;
default:
retval = -ENOTTY;
default:
retval = -ENOTTY;
}
done:
mutex_unlock (&usblp->mut);
mutex_unlock(&usblp->mut);
return retval;
}
@ -840,7 +839,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, lo
}
done:
mutex_unlock (&usblp->mut);
mutex_unlock(&usblp->mut);
return count;
}
@ -1023,7 +1022,7 @@ raise_urb:
* while you are sending print data, and you don't try to query the
* printer status every couple of milliseconds, you will probably be OK.
*/
static unsigned int usblp_quirks (__u16 vendor, __u16 product)
static unsigned int usblp_quirks(__u16 vendor, __u16 product)
{
int i;
@ -1031,7 +1030,7 @@ static unsigned int usblp_quirks (__u16 vendor, __u16 product)
if (vendor == quirk_printers[i].vendorId &&
product == quirk_printers[i].productId)
return quirk_printers[i].quirks;
}
}
return 0;
}
@ -1061,7 +1060,7 @@ static struct usb_class_driver usblp_class = {
static ssize_t usblp_show_ieee1284_id(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usblp *usblp = usb_get_intfdata (intf);
struct usblp *usblp = usb_get_intfdata(intf);
if (usblp->device_id_string[0] == 0 &&
usblp->device_id_string[1] == 0)
@ -1075,7 +1074,7 @@ static DEVICE_ATTR(ieee1284_id, S_IRUGO, usblp_show_ieee1284_id, NULL);
static int usblp_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev (intf);
struct usb_device *dev = interface_to_usbdev(intf);
struct usblp *usblp;
int protocol;
int retval;
@ -1089,7 +1088,7 @@ static int usblp_probe(struct usb_interface *intf,
}
usblp->dev = dev;
mutex_init(&usblp->wmut);
mutex_init (&usblp->mut);
mutex_init(&usblp->mut);
spin_lock_init(&usblp->lock);
init_waitqueue_head(&usblp->rwait);
init_waitqueue_head(&usblp->wwait);
@ -1153,7 +1152,7 @@ static int usblp_probe(struct usb_interface *intf,
usblp_check_status(usblp, 0);
#endif
usb_set_intfdata (intf, usblp);
usb_set_intfdata(intf, usblp);
usblp->present = 1;
@ -1177,7 +1176,7 @@ static int usblp_probe(struct usb_interface *intf,
return 0;
abort_intfdata:
usb_set_intfdata (intf, NULL);
usb_set_intfdata(intf, NULL);
device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
abort:
kfree(usblp->readbuf);
@ -1340,35 +1339,35 @@ static int usblp_cache_device_id_string(struct usblp *usblp)
static void usblp_disconnect(struct usb_interface *intf)
{
struct usblp *usblp = usb_get_intfdata (intf);
struct usblp *usblp = usb_get_intfdata(intf);
usb_deregister_dev(intf, &usblp_class);
if (!usblp || !usblp->dev) {
dev_err(&intf->dev, "bogus disconnect\n");
BUG ();
BUG();
}
device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
mutex_lock (&usblp_mutex);
mutex_lock (&usblp->mut);
mutex_lock(&usblp_mutex);
mutex_lock(&usblp->mut);
usblp->present = 0;
wake_up(&usblp->wwait);
wake_up(&usblp->rwait);
usb_set_intfdata (intf, NULL);
usb_set_intfdata(intf, NULL);
usblp_unlink_urbs(usblp);
mutex_unlock (&usblp->mut);
mutex_unlock(&usblp->mut);
if (!usblp->used)
usblp_cleanup (usblp);
mutex_unlock (&usblp_mutex);
usblp_cleanup(usblp);
mutex_unlock(&usblp_mutex);
}
static int usblp_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usblp *usblp = usb_get_intfdata (intf);
struct usblp *usblp = usb_get_intfdata(intf);
usblp_unlink_urbs(usblp);
#if 0 /* XXX Do we want this? What if someone is reading, should we fail? */
@ -1382,10 +1381,10 @@ static int usblp_suspend(struct usb_interface *intf, pm_message_t message)
static int usblp_resume(struct usb_interface *intf)
{
struct usblp *usblp = usb_get_intfdata (intf);
struct usblp *usblp = usb_get_intfdata(intf);
int r;
r = handle_bidir (usblp);
r = handle_bidir(usblp);
return r;
}
@ -1401,7 +1400,7 @@ static const struct usb_device_id usblp_ids[] = {
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, usblp_ids);
MODULE_DEVICE_TABLE(usb, usblp_ids);
static struct usb_driver usblp_driver = {
.name = "usblp",
@ -1426,8 +1425,8 @@ static void __exit usblp_exit(void)
module_init(usblp_init);
module_exit(usblp_exit);
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
module_param(proto_bias, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(proto_bias, "Favourite protocol number");
MODULE_LICENSE("GPL");

View File

@ -1668,13 +1668,10 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
default:
if (intf->dev.driver)
driver = to_usb_driver(intf->dev.driver);
if (driver == NULL || driver->ioctl == NULL) {
if (driver == NULL || driver->unlocked_ioctl == NULL) {
retval = -ENOTTY;
} else {
/* keep API that guarantees BKL */
lock_kernel();
retval = driver->ioctl(intf, ctl->ioctl_code, buf);
unlock_kernel();
retval = driver->unlocked_ioctl(intf, ctl->ioctl_code, buf);
if (retval == -ENOIOCTLCMD)
retval = -ENOTTY;
}

View File

@ -1742,9 +1742,8 @@ static int usb_runtime_suspend(struct device *dev)
}
/* Prevent the parent from suspending immediately after */
else if (udev->parent) {
else if (udev->parent)
udev->parent->last_busy = jiffies;
}
}
/* Runtime suspend for a USB interface doesn't mean anything. */
@ -1786,21 +1785,19 @@ static int usb_runtime_idle(struct device *dev)
return 0;
}
static struct dev_pm_ops usb_bus_pm_ops = {
static const struct dev_pm_ops usb_bus_pm_ops = {
.runtime_suspend = usb_runtime_suspend,
.runtime_resume = usb_runtime_resume,
.runtime_idle = usb_runtime_idle,
};
#else
#define usb_bus_pm_ops (*(struct dev_pm_ops *) NULL)
#endif /* CONFIG_USB_SUSPEND */
struct bus_type usb_bus_type = {
.name = "usb",
.match = usb_device_match,
.uevent = usb_uevent,
#ifdef CONFIG_USB_SUSPEND
.pm = &usb_bus_pm_ops,
#endif
};

View File

@ -96,16 +96,21 @@ static ssize_t show_ep_interval(struct device *dev,
switch (usb_endpoint_type(ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
if (ep->udev->speed == USB_SPEED_HIGH) /* uframes per NAK */
if (ep->udev->speed == USB_SPEED_HIGH)
/* uframes per NAK */
interval = ep->desc->bInterval;
break;
case USB_ENDPOINT_XFER_ISOC:
interval = 1 << (ep->desc->bInterval - 1);
break;
case USB_ENDPOINT_XFER_BULK:
if (ep->udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */
if (ep->udev->speed == USB_SPEED_HIGH && !in)
/* uframes per NAK */
interval = ep->desc->bInterval;
break;
case USB_ENDPOINT_XFER_INT:
if (ep->udev->speed == USB_SPEED_HIGH)
interval = 1 << (ep->desc->bInterval - 1);

View File

@ -105,8 +105,10 @@ int usb_choose_configuration(struct usb_device *udev)
/* When the first config's first interface is one of Microsoft's
* pet nonstandard Ethernet-over-USB protocols, ignore it unless
* this kernel has enabled the necessary host side driver.
* But: Don't ignore it if it's the only config.
*/
if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) {
if (i == 0 && num_configs > 1 && desc &&
(is_rndis(desc) || is_activesync(desc))) {
#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
continue;
#else

View File

@ -66,10 +66,7 @@ static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd,
* vice versa.
*/
companion = NULL;
for (;;) {
companion = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, companion);
if (!companion)
break;
for_each_pci_dev(companion) {
if (companion->bus != pdev->bus ||
PCI_SLOT(companion->devfn) != slot)
continue;
@ -250,6 +247,9 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (retval != 0)
goto err4;
set_hs_companion(dev, hcd);
if (pci_dev_run_wake(dev))
pm_runtime_put_noidle(&dev->dev);
return retval;
err4:
@ -292,6 +292,17 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
if (!hcd)
return;
if (pci_dev_run_wake(dev))
pm_runtime_get_noresume(&dev->dev);
/* Fake an interrupt request in order to give the driver a chance
* to test whether the controller hardware has been removed (e.g.,
* cardbus physical eject).
*/
local_irq_disable();
usb_hcd_irq(0, hcd);
local_irq_enable();
usb_remove_hcd(hcd);
if (hcd->driver->flags & HCD_MEMORY) {
iounmap(hcd->regs);
@ -317,12 +328,34 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev)
if (!hcd)
return;
if (hcd->driver->shutdown)
if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) &&
hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
}
EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
#ifdef CONFIG_PM_SLEEP
#ifdef CONFIG_PM_OPS
#ifdef CONFIG_PPC_PMAC
static void powermac_set_asic(struct pci_dev *pci_dev, int enable)
{
/* Enanble or disable ASIC clocks for USB */
if (machine_is(powermac)) {
struct device_node *of_node;
of_node = pci_device_to_OF_node(pci_dev);
if (of_node)
pmac_call_feature(PMAC_FTR_USB_ENABLE,
of_node, 0, enable);
}
}
#else
static inline void powermac_set_asic(struct pci_dev *pci_dev, int enable)
{}
#endif /* CONFIG_PPC_PMAC */
static int check_root_hub_suspended(struct device *dev)
{
@ -337,7 +370,7 @@ static int check_root_hub_suspended(struct device *dev)
return 0;
}
static int hcd_pci_suspend(struct device *dev)
static int suspend_common(struct device *dev, bool do_wakeup)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
@ -352,13 +385,21 @@ static int hcd_pci_suspend(struct device *dev)
if (retval)
return retval;
/* We might already be suspended (runtime PM -- not yet written) */
if (pci_dev->current_state != PCI_D0)
return retval;
if (hcd->driver->pci_suspend) {
retval = hcd->driver->pci_suspend(hcd);
/* Optimization: Don't suspend if a root-hub wakeup is
* pending and it would cause the HCD to wake up anyway.
*/
if (do_wakeup && HCD_WAKEUP_PENDING(hcd))
return -EBUSY;
retval = hcd->driver->pci_suspend(hcd, do_wakeup);
suspend_report_result(hcd->driver->pci_suspend, retval);
/* Check again in case wakeup raced with pci_suspend */
if (retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) {
if (hcd->driver->pci_resume)
hcd->driver->pci_resume(hcd, false);
retval = -EBUSY;
}
if (retval)
return retval;
}
@ -374,6 +415,48 @@ static int hcd_pci_suspend(struct device *dev)
return retval;
}
static int resume_common(struct device *dev, int event)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
int retval;
if (hcd->state != HC_STATE_SUSPENDED) {
dev_dbg(dev, "can't resume, not suspended!\n");
return 0;
}
retval = pci_enable_device(pci_dev);
if (retval < 0) {
dev_err(dev, "can't re-enable after resume, %d!\n", retval);
return retval;
}
pci_set_master(pci_dev);
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
if (hcd->driver->pci_resume) {
if (event != PM_EVENT_AUTO_RESUME)
wait_for_companions(pci_dev, hcd);
retval = hcd->driver->pci_resume(hcd,
event == PM_EVENT_RESTORE);
if (retval) {
dev_err(dev, "PCI post-resume error %d!\n", retval);
usb_hc_died(hcd);
}
}
return retval;
}
#ifdef CONFIG_PM_SLEEP
static int hcd_pci_suspend(struct device *dev)
{
return suspend_common(dev, device_may_wakeup(dev));
}
static int hcd_pci_suspend_noirq(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
@ -408,16 +491,7 @@ static int hcd_pci_suspend_noirq(struct device *dev)
return retval;
}
#ifdef CONFIG_PPC_PMAC
/* Disable ASIC clocks for USB */
if (machine_is(powermac)) {
struct device_node *of_node;
of_node = pci_device_to_OF_node(pci_dev);
if (of_node)
pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
}
#endif
powermac_set_asic(pci_dev, 0);
return retval;
}
@ -425,69 +499,63 @@ static int hcd_pci_resume_noirq(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
#ifdef CONFIG_PPC_PMAC
/* Reenable ASIC clocks for USB */
if (machine_is(powermac)) {
struct device_node *of_node;
of_node = pci_device_to_OF_node(pci_dev);
if (of_node)
pmac_call_feature(PMAC_FTR_USB_ENABLE,
of_node, 0, 1);
}
#endif
powermac_set_asic(pci_dev, 1);
/* Go back to D0 and disable remote wakeup */
pci_back_from_sleep(pci_dev);
return 0;
}
static int resume_common(struct device *dev, bool hibernated)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
int retval;
if (hcd->state != HC_STATE_SUSPENDED) {
dev_dbg(dev, "can't resume, not suspended!\n");
return 0;
}
retval = pci_enable_device(pci_dev);
if (retval < 0) {
dev_err(dev, "can't re-enable after resume, %d!\n", retval);
return retval;
}
pci_set_master(pci_dev);
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
if (hcd->driver->pci_resume) {
/* This call should be made only during system resume,
* not during runtime resume.
*/
wait_for_companions(pci_dev, hcd);
retval = hcd->driver->pci_resume(hcd, hibernated);
if (retval) {
dev_err(dev, "PCI post-resume error %d!\n", retval);
usb_hc_died(hcd);
}
}
return retval;
}
static int hcd_pci_resume(struct device *dev)
{
return resume_common(dev, false);
return resume_common(dev, PM_EVENT_RESUME);
}
static int hcd_pci_restore(struct device *dev)
{
return resume_common(dev, true);
return resume_common(dev, PM_EVENT_RESTORE);
}
#else
#define hcd_pci_suspend NULL
#define hcd_pci_suspend_noirq NULL
#define hcd_pci_resume_noirq NULL
#define hcd_pci_resume NULL
#define hcd_pci_restore NULL
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_RUNTIME
static int hcd_pci_runtime_suspend(struct device *dev)
{
int retval;
retval = suspend_common(dev, true);
if (retval == 0)
powermac_set_asic(to_pci_dev(dev), 0);
dev_dbg(dev, "hcd_pci_runtime_suspend: %d\n", retval);
return retval;
}
static int hcd_pci_runtime_resume(struct device *dev)
{
int retval;
powermac_set_asic(to_pci_dev(dev), 1);
retval = resume_common(dev, PM_EVENT_AUTO_RESUME);
dev_dbg(dev, "hcd_pci_runtime_resume: %d\n", retval);
return retval;
}
#else
#define hcd_pci_runtime_suspend NULL
#define hcd_pci_runtime_resume NULL
#endif /* CONFIG_PM_RUNTIME */
const struct dev_pm_ops usb_hcd_pci_pm_ops = {
.suspend = hcd_pci_suspend,
.suspend_noirq = hcd_pci_suspend_noirq,
@ -501,7 +569,9 @@ const struct dev_pm_ops usb_hcd_pci_pm_ops = {
.poweroff_noirq = hcd_pci_suspend_noirq,
.restore_noirq = hcd_pci_resume_noirq,
.restore = hcd_pci_restore,
.runtime_suspend = hcd_pci_runtime_suspend,
.runtime_resume = hcd_pci_runtime_resume,
};
EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops);
#endif /* CONFIG_PM_SLEEP */
#endif /* CONFIG_PM_OPS */

View File

@ -667,7 +667,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
unsigned long flags;
char buffer[6]; /* Any root hubs with > 31 ports? */
if (unlikely(!hcd->rh_registered))
if (unlikely(!hcd->rh_pollable))
return;
if (!hcd->uses_new_polling && !hcd->status_urb)
return;
@ -679,7 +679,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
spin_lock_irqsave(&hcd_root_hub_lock, flags);
urb = hcd->status_urb;
if (urb) {
hcd->poll_pending = 0;
clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
hcd->status_urb = NULL;
urb->actual_length = length;
memcpy(urb->transfer_buffer, buffer, length);
@ -690,7 +690,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
spin_lock(&hcd_root_hub_lock);
} else {
length = 0;
hcd->poll_pending = 1;
set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
}
spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
}
@ -699,7 +699,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
* exceed that limit if HZ is 100. The math is more clunky than
* maybe expected, this is to make sure that all timers for USB devices
* fire at the same time to give the CPU a break inbetween */
if (hcd->uses_new_polling ? hcd->poll_rh :
if (hcd->uses_new_polling ? HCD_POLL_RH(hcd) :
(length == 0 && hcd->status_urb != NULL))
mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
}
@ -736,7 +736,7 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
/* If a status change has already occurred, report it ASAP */
else if (hcd->poll_pending)
else if (HCD_POLL_PENDING(hcd))
mod_timer(&hcd->rh_timer, jiffies);
retval = 0;
done:
@ -1150,8 +1150,7 @@ int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
* finish unlinking the initial failed usb_set_address()
* or device descriptor fetch.
*/
if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
!is_root_hub(urb->dev)) {
if (!HCD_SAW_IRQ(hcd) && !is_root_hub(urb->dev)) {
dev_warn(hcd->self.controller, "Unlink after no-IRQ? "
"Controller is probably using the wrong IRQ.\n");
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
@ -1219,6 +1218,11 @@ static int hcd_alloc_coherent(struct usb_bus *bus,
{
unsigned char *vaddr;
if (*vaddr_handle == NULL) {
WARN_ON_ONCE(1);
return -EFAULT;
}
vaddr = hcd_buffer_alloc(bus, size + sizeof(vaddr),
mem_flags, dma_handle);
if (!vaddr)
@ -1941,6 +1945,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
dev_dbg(&rhdev->dev, "usb %s%s\n",
(msg.event & PM_EVENT_AUTO ? "auto-" : ""), "resume");
clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
if (!hcd->driver->bus_resume)
return -ENOENT;
if (hcd->state == HC_STATE_RUNNING)
@ -1994,8 +1999,10 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
unsigned long flags;
spin_lock_irqsave (&hcd_root_hub_lock, flags);
if (hcd->rh_registered)
if (hcd->rh_registered) {
set_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
queue_work(pm_wq, &hcd->wakeup_work);
}
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
}
EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
@ -2063,8 +2070,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
*/
local_irq_save(flags);
if (unlikely(hcd->state == HC_STATE_HALT ||
!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
if (unlikely(hcd->state == HC_STATE_HALT || !HCD_HW_ACCESSIBLE(hcd))) {
rc = IRQ_NONE;
} else if (hcd->driver->irq(hcd) == IRQ_NONE) {
rc = IRQ_NONE;
@ -2079,6 +2085,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
local_irq_restore(flags);
return rc;
}
EXPORT_SYMBOL_GPL(usb_hcd_irq);
/*-------------------------------------------------------------------------*/
@ -2098,7 +2105,7 @@ void usb_hc_died (struct usb_hcd *hcd)
spin_lock_irqsave (&hcd_root_hub_lock, flags);
if (hcd->rh_registered) {
hcd->poll_rh = 0;
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
/* make khubd clean up old urbs and devices */
usb_set_device_state (hcd->self.root_hub,
@ -2217,6 +2224,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
retval = -ENOMEM;
goto err_allocate_root_hub;
}
hcd->self.root_hub = rhdev;
switch (hcd->driver->flags & HCD_MASK) {
case HCD_USB11:
@ -2229,9 +2237,8 @@ int usb_add_hcd(struct usb_hcd *hcd,
rhdev->speed = USB_SPEED_SUPER;
break;
default:
goto err_allocate_root_hub;
goto err_set_rh_speed;
}
hcd->self.root_hub = rhdev;
/* wakeup flag init defaults to "everything works" for root hubs,
* but drivers can override it in reset() if needed, along with
@ -2246,6 +2253,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
dev_err(hcd->self.controller, "can't setup\n");
goto err_hcd_driver_setup;
}
hcd->rh_pollable = 1;
/* NOTE: root hub and controller capabilities may not be the same */
if (device_can_wakeup(hcd->self.controller)
@ -2300,23 +2308,38 @@ int usb_add_hcd(struct usb_hcd *hcd,
retval);
goto error_create_attr_group;
}
if (hcd->uses_new_polling && hcd->poll_rh)
if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
usb_hcd_poll_rh_status(hcd);
return retval;
error_create_attr_group:
if (HC_IS_RUNNING(hcd->state))
hcd->state = HC_STATE_QUIESCING;
spin_lock_irq(&hcd_root_hub_lock);
hcd->rh_registered = 0;
spin_unlock_irq(&hcd_root_hub_lock);
#ifdef CONFIG_USB_SUSPEND
cancel_work_sync(&hcd->wakeup_work);
#endif
mutex_lock(&usb_bus_list_lock);
usb_disconnect(&hcd->self.root_hub);
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
mutex_unlock(&usb_bus_list_lock);
err_register_root_hub:
hcd->rh_pollable = 0;
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
del_timer_sync(&hcd->rh_timer);
hcd->driver->stop(hcd);
hcd->state = HC_STATE_HALT;
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
del_timer_sync(&hcd->rh_timer);
err_hcd_driver_start:
if (hcd->irq >= 0)
free_irq(irqnum, hcd);
err_request_irq:
err_hcd_driver_setup:
hcd->self.root_hub = NULL;
usb_put_dev(rhdev);
err_set_rh_speed:
usb_put_dev(hcd->self.root_hub);
err_allocate_root_hub:
usb_deregister_bus(&hcd->self);
err_register_bus:
@ -2335,8 +2358,13 @@ EXPORT_SYMBOL_GPL(usb_add_hcd);
*/
void usb_remove_hcd(struct usb_hcd *hcd)
{
struct usb_device *rhdev = hcd->self.root_hub;
dev_info(hcd->self.controller, "remove, state %x\n", hcd->state);
usb_get_dev(rhdev);
sysfs_remove_group(&rhdev->dev.kobj, &usb_bus_attr_group);
if (HC_IS_RUNNING (hcd->state))
hcd->state = HC_STATE_QUIESCING;
@ -2349,19 +2377,30 @@ void usb_remove_hcd(struct usb_hcd *hcd)
cancel_work_sync(&hcd->wakeup_work);
#endif
sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
mutex_lock(&usb_bus_list_lock);
usb_disconnect(&hcd->self.root_hub);
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
mutex_unlock(&usb_bus_list_lock);
/* Prevent any more root-hub status calls from the timer.
* The HCD might still restart the timer (if a port status change
* interrupt occurs), but usb_hcd_poll_rh_status() won't invoke
* the hub_status_data() callback.
*/
hcd->rh_pollable = 0;
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
del_timer_sync(&hcd->rh_timer);
hcd->driver->stop(hcd);
hcd->state = HC_STATE_HALT;
hcd->poll_rh = 0;
/* In case the HCD restarted the timer, stop it again. */
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
del_timer_sync(&hcd->rh_timer);
if (hcd->irq >= 0)
free_irq(hcd->irq, hcd);
usb_put_dev(hcd->self.root_hub);
usb_deregister_bus(&hcd->self);
hcd_buffer_destroy(hcd);
}

View File

@ -20,6 +20,7 @@
#include <linux/usb.h>
#include <linux/usbdevice_fs.h>
#include <linux/usb/hcd.h>
#include <linux/usb/quirks.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/freezer.h>
@ -1294,6 +1295,7 @@ descriptor_error:
return -ENODEV;
}
/* No BKL needed */
static int
hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
{
@ -1801,7 +1803,6 @@ int usb_new_device(struct usb_device *udev)
pm_runtime_set_active(&udev->dev);
pm_runtime_enable(&udev->dev);
usb_detect_quirks(udev);
err = usb_enumerate_device(udev); /* Read descriptors */
if (err < 0)
goto fail;
@ -2880,7 +2881,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
}
retval = 0;
/* notify HCD that we have a device connected and addressed */
if (hcd->driver->update_device)
hcd->driver->update_device(hcd, udev);
fail:
if (retval) {
hub_port_disable(hub, port1, 0);
@ -3111,6 +3114,10 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
if (status < 0)
goto loop;
usb_detect_quirks(udev);
if (udev->quirks & USB_QUIRK_DELAY_INIT)
msleep(1000);
/* consecutive bus-powered hubs aren't reliable; they can
* violate the voltage drop budget. if the new child has
* a "powered" LED, users should notice we didn't enable it
@ -3463,7 +3470,7 @@ static struct usb_driver hub_driver = {
.reset_resume = hub_reset_resume,
.pre_reset = hub_pre_reset,
.post_reset = hub_post_reset,
.ioctl = hub_ioctl,
.unlocked_ioctl = hub_ioctl,
.id_table = hub_id_table,
.supports_autosuspend = 1,
};

View File

@ -265,13 +265,9 @@ static int remount(struct super_block *sb, int *flags, char *data)
return -EINVAL;
}
lock_kernel();
if (usbfs_mount && usbfs_mount->mnt_sb)
update_sb(usbfs_mount->mnt_sb);
unlock_kernel();
return 0;
}

View File

@ -38,6 +38,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Creative SB Audigy 2 NX */
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
/* Logitech Harmony 700-series */
{ USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT },
/* Philips PSC805 audio device */
{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },

View File

@ -137,6 +137,16 @@ void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)
}
EXPORT_SYMBOL_GPL(usb_anchor_urb);
/* Callers must hold anchor->lock */
static void __usb_unanchor_urb(struct urb *urb, struct usb_anchor *anchor)
{
urb->anchor = NULL;
list_del(&urb->anchor_list);
usb_put_urb(urb);
if (list_empty(&anchor->urb_list))
wake_up(&anchor->wait);
}
/**
* usb_unanchor_urb - unanchors an URB
* @urb: pointer to the urb to anchor
@ -156,17 +166,14 @@ void usb_unanchor_urb(struct urb *urb)
return;
spin_lock_irqsave(&anchor->lock, flags);
if (unlikely(anchor != urb->anchor)) {
/* we've lost the race to another thread */
spin_unlock_irqrestore(&anchor->lock, flags);
return;
}
urb->anchor = NULL;
list_del(&urb->anchor_list);
/*
* At this point, we could be competing with another thread which
* has the same intention. To protect the urb from being unanchored
* twice, only the winner of the race gets the job.
*/
if (likely(anchor == urb->anchor))
__usb_unanchor_urb(urb, anchor);
spin_unlock_irqrestore(&anchor->lock, flags);
usb_put_urb(urb);
if (list_empty(&anchor->urb_list))
wake_up(&anchor->wait);
}
EXPORT_SYMBOL_GPL(usb_unanchor_urb);
@ -749,20 +756,11 @@ EXPORT_SYMBOL_GPL(usb_unpoison_anchored_urbs);
void usb_unlink_anchored_urbs(struct usb_anchor *anchor)
{
struct urb *victim;
unsigned long flags;
spin_lock_irqsave(&anchor->lock, flags);
while (!list_empty(&anchor->urb_list)) {
victim = list_entry(anchor->urb_list.prev, struct urb,
anchor_list);
usb_get_urb(victim);
spin_unlock_irqrestore(&anchor->lock, flags);
/* this will unanchor the URB */
while ((victim = usb_get_from_anchor(anchor)) != NULL) {
usb_unlink_urb(victim);
usb_put_urb(victim);
spin_lock_irqsave(&anchor->lock, flags);
}
spin_unlock_irqrestore(&anchor->lock, flags);
}
EXPORT_SYMBOL_GPL(usb_unlink_anchored_urbs);
@ -799,12 +797,11 @@ struct urb *usb_get_from_anchor(struct usb_anchor *anchor)
victim = list_entry(anchor->urb_list.next, struct urb,
anchor_list);
usb_get_urb(victim);
spin_unlock_irqrestore(&anchor->lock, flags);
usb_unanchor_urb(victim);
__usb_unanchor_urb(victim, anchor);
} else {
spin_unlock_irqrestore(&anchor->lock, flags);
victim = NULL;
}
spin_unlock_irqrestore(&anchor->lock, flags);
return victim;
}
@ -826,12 +823,7 @@ void usb_scuttle_anchored_urbs(struct usb_anchor *anchor)
while (!list_empty(&anchor->urb_list)) {
victim = list_entry(anchor->urb_list.prev, struct urb,
anchor_list);
usb_get_urb(victim);
spin_unlock_irqrestore(&anchor->lock, flags);
/* this may free the URB */
usb_unanchor_urb(victim);
usb_put_urb(victim);
spin_lock_irqsave(&anchor->lock, flags);
__usb_unanchor_urb(victim, anchor);
}
spin_unlock_irqrestore(&anchor->lock, flags);
}

View File

@ -317,10 +317,6 @@ static const struct dev_pm_ops usb_device_pm_ops = {
.restore = usb_dev_restore,
};
#else
#define usb_device_pm_ops (*(struct dev_pm_ops *) NULL)
#endif /* CONFIG_PM */
@ -338,7 +334,9 @@ struct device_type usb_device_type = {
.release = usb_release_dev,
.uevent = usb_dev_uevent,
.devnode = usb_devnode,
#ifdef CONFIG_PM
.pm = &usb_device_pm_ops,
#endif
};

View File

@ -714,6 +714,7 @@ config USB_GADGETFS
config USB_FUNCTIONFS
tristate "Function Filesystem (EXPERIMENTAL)"
depends on EXPERIMENTAL
select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)
help
The Function Filesystem (FunctioFS) lets one create USB
composite functions in user space in the same way as GadgetFS
@ -722,31 +723,31 @@ config USB_FUNCTIONFS
implemented in kernel space (for instance Ethernet, serial or
mass storage) and other are implemented in user space.
If you say "y" or "m" here you will be able what kind of
configurations the gadget will provide.
Say "y" to link the driver statically, or "m" to build
a dynamically linked module called "g_ffs".
config USB_FUNCTIONFS_ETH
bool "Include CDC ECM (Ethernet) function"
bool "Include configuration with CDC ECM (Ethernet)"
depends on USB_FUNCTIONFS && NET
help
Include an CDC ECM (Ethernet) funcion in the CDC ECM (Funcion)
Filesystem. If you also say "y" to the RNDIS query below the
gadget will have two configurations.
Include a configuration with CDC ECM funcion (Ethernet) and the
Funcion Filesystem.
config USB_FUNCTIONFS_RNDIS
bool "Include RNDIS (Ethernet) function"
bool "Include configuration with RNDIS (Ethernet)"
depends on USB_FUNCTIONFS && NET
help
Include an RNDIS (Ethernet) funcion in the Funcion Filesystem.
If you also say "y" to the CDC ECM query above the gadget will
have two configurations.
Include a configuration with RNDIS funcion (Ethernet) and the Filesystem.
config USB_FUNCTIONFS_GENERIC
bool "Include 'pure' configuration"
depends on USB_FUNCTIONFS && (USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)
depends on USB_FUNCTIONFS
help
Include a configuration with FunctionFS and no Ethernet
configuration.
Include a configuration with the Function Filesystem alone with
no Ethernet interface.
config USB_FILE_STORAGE
tristate "File-backed Storage Gadget"
@ -863,6 +864,7 @@ config USB_G_NOKIA
config USB_G_MULTI
tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
depends on BLOCK && NET
select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
help
The Multifunction Composite Gadget provides Ethernet (RNDIS
and/or CDC Ethernet), mass storage and ACM serial link
@ -913,6 +915,34 @@ config USB_G_HID
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_hid".
config USB_G_DBGP
tristate "EHCI Debug Device Gadget"
help
This gadget emulates an EHCI Debug device. This is useful when you want
to interact with an EHCI Debug Port.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_dbgp".
if USB_G_DBGP
choice
prompt "EHCI Debug Device mode"
default USB_G_DBGP_SERIAL
config USB_G_DBGP_PRINTK
depends on USB_G_DBGP
bool "printk"
help
Directly printk() received data. No interaction.
config USB_G_DBGP_SERIAL
depends on USB_G_DBGP
bool "serial"
help
Userland can interact using /dev/ttyGSxxx.
endchoice
endif
# put drivers that need isochronous transfer support (for audio
# or video class gadget drivers), or specific hardware, here.
config USB_G_WEBCAM

View File

@ -44,6 +44,7 @@ g_printer-objs := printer.o
g_cdc-objs := cdc2.o
g_multi-objs := multi.o
g_hid-objs := hid.o
g_dbgp-objs := dbgp.o
g_nokia-objs := nokia.o
g_webcam-objs := webcam.o
@ -52,7 +53,6 @@ obj-$(CONFIG_USB_AUDIO) += g_audio.o
obj-$(CONFIG_USB_ETH) += g_ether.o
obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
obj-$(CONFIG_USB_FUNCTIONFS) += g_ffs.o
obj-$(CONFIG_USB_ETH_FUNCTIONFS) += g_eth_ffs.o
obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o
obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
@ -60,6 +60,7 @@ obj-$(CONFIG_USB_G_PRINTER) += g_printer.o
obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
obj-$(CONFIG_USB_G_HID) += g_hid.o
obj-$(CONFIG_USB_G_DBGP) += g_dbgp.o
obj-$(CONFIG_USB_G_MULTI) += g_multi.o
obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o

View File

@ -89,7 +89,7 @@ static const struct usb_descriptor_header *otg_desc[] = {
/*-------------------------------------------------------------------------*/
static int __init audio_do_config(struct usb_configuration *c)
static int __ref audio_do_config(struct usb_configuration *c)
{
/* FIXME alloc iConfiguration string, set it in c->strings */
@ -113,7 +113,7 @@ static struct usb_configuration audio_config_driver = {
/*-------------------------------------------------------------------------*/
static int __init audio_bind(struct usb_composite_dev *cdev)
static int __ref audio_bind(struct usb_composite_dev *cdev)
{
int gcnum;
int status;

View File

@ -129,7 +129,7 @@ static u8 hostaddr[ETH_ALEN];
/*
* We _always_ have both CDC ECM and CDC ACM functions.
*/
static int __init cdc_do_config(struct usb_configuration *c)
static int __ref cdc_do_config(struct usb_configuration *c)
{
int status;
@ -159,7 +159,7 @@ static struct usb_configuration cdc_config_driver = {
/*-------------------------------------------------------------------------*/
static int __init cdc_bind(struct usb_composite_dev *cdev)
static int __ref cdc_bind(struct usb_composite_dev *cdev)
{
int gcnum;
struct usb_gadget *gadget = cdev->gadget;

View File

@ -673,20 +673,83 @@ static int get_string(struct usb_composite_dev *cdev,
* string IDs. Drivers for functions, configurations, or gadgets will
* then store that ID in the appropriate descriptors and string table.
*
* All string identifier should be allocated using this routine, to
* ensure that for example different functions don't wrongly assign
* different meanings to the same identifier.
* All string identifier should be allocated using this,
* @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure
* that for example different functions don't wrongly assign different
* meanings to the same identifier.
*/
int usb_string_id(struct usb_composite_dev *cdev)
{
if (cdev->next_string_id < 254) {
/* string id 0 is reserved */
/* string id 0 is reserved by USB spec for list of
* supported languages */
/* 255 reserved as well? -- mina86 */
cdev->next_string_id++;
return cdev->next_string_id;
}
return -ENODEV;
}
/**
* usb_string_ids() - allocate unused string IDs in batch
* @cdev: the device whose string descriptor IDs are being allocated
* @str: an array of usb_string objects to assign numbers to
* Context: single threaded during gadget setup
*
* @usb_string_ids() is called from bind() callbacks to allocate
* string IDs. Drivers for functions, configurations, or gadgets will
* then copy IDs from the string table to the appropriate descriptors
* and string table for other languages.
*
* All string identifier should be allocated using this,
* @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
* example different functions don't wrongly assign different meanings
* to the same identifier.
*/
int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str)
{
int next = cdev->next_string_id;
for (; str->s; ++str) {
if (unlikely(next >= 254))
return -ENODEV;
str->id = ++next;
}
cdev->next_string_id = next;
return 0;
}
/**
* usb_string_ids_n() - allocate unused string IDs in batch
* @cdev: the device whose string descriptor IDs are being allocated
* @n: number of string IDs to allocate
* Context: single threaded during gadget setup
*
* Returns the first requested ID. This ID and next @n-1 IDs are now
* valid IDs. At least providind that @n is non zore because if it
* is, returns last requested ID which is now very useful information.
*
* @usb_string_ids_n() is called from bind() callbacks to allocate
* string IDs. Drivers for functions, configurations, or gadgets will
* then store that ID in the appropriate descriptors and string table.
*
* All string identifier should be allocated using this,
* @usb_string_id() or @usb_string_ids_n() routine, to ensure that for
* example different functions don't wrongly assign different meanings
* to the same identifier.
*/
int usb_string_ids_n(struct usb_composite_dev *c, unsigned n)
{
unsigned next = c->next_string_id;
if (unlikely(n > 254 || (unsigned)next + n > 254))
return -ENODEV;
c->next_string_id += n;
return next + 1;
}
/*-------------------------------------------------------------------------*/
static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req)
@ -893,6 +956,8 @@ static void composite_disconnect(struct usb_gadget *gadget)
spin_lock_irqsave(&cdev->lock, flags);
if (cdev->config)
reset_config(cdev);
if (composite->disconnect)
composite->disconnect(cdev);
spin_unlock_irqrestore(&cdev->lock, flags);
}

434
drivers/usb/gadget/dbgp.c Normal file
View File

@ -0,0 +1,434 @@
/*
* dbgp.c -- EHCI Debug Port device gadget
*
* Copyright (C) 2010 Stephane Duverger
*
* Released under the GPLv2.
*
*/
/* verbose messages */
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
/* See comments in "zero.c" */
#include "epautoconf.c"
#ifdef CONFIG_USB_G_DBGP_SERIAL
#include "u_serial.c"
#endif
#define DRIVER_VENDOR_ID 0x0525 /* NetChip */
#define DRIVER_PRODUCT_ID 0xc0de /* undefined */
#define USB_DEBUG_MAX_PACKET_SIZE 8
#define DBGP_REQ_EP0_LEN 128
#define DBGP_REQ_LEN 512
static struct dbgp {
struct usb_gadget *gadget;
struct usb_request *req;
struct usb_ep *i_ep;
struct usb_ep *o_ep;
#ifdef CONFIG_USB_G_DBGP_SERIAL
struct gserial *serial;
#endif
} dbgp;
static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = __constant_cpu_to_le16(0x0200),
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
.idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_ID),
.idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_ID),
.bNumConfigurations = 1,
};
static struct usb_debug_descriptor dbg_desc = {
.bLength = sizeof dbg_desc,
.bDescriptorType = USB_DT_DEBUG,
};
static struct usb_endpoint_descriptor i_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.bEndpointAddress = USB_DIR_IN,
};
static struct usb_endpoint_descriptor o_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.bEndpointAddress = USB_DIR_OUT,
};
#ifdef CONFIG_USB_G_DBGP_PRINTK
static int dbgp_consume(char *buf, unsigned len)
{
char c;
if (!len)
return 0;
c = buf[len-1];
if (c != 0)
buf[len-1] = 0;
printk(KERN_NOTICE "%s%c", buf, c);
return 0;
}
static void __disable_ep(struct usb_ep *ep)
{
if (ep && ep->driver_data == dbgp.gadget) {
usb_ep_disable(ep);
ep->driver_data = NULL;
}
}
static void dbgp_disable_ep(void)
{
__disable_ep(dbgp.i_ep);
__disable_ep(dbgp.o_ep);
}
static void dbgp_complete(struct usb_ep *ep, struct usb_request *req)
{
int stp;
int err = 0;
int status = req->status;
if (ep == dbgp.i_ep) {
stp = 1;
goto fail;
}
if (status != 0) {
stp = 2;
goto release_req;
}
dbgp_consume(req->buf, req->actual);
req->length = DBGP_REQ_LEN;
err = usb_ep_queue(ep, req, GFP_ATOMIC);
if (err < 0) {
stp = 3;
goto release_req;
}
return;
release_req:
kfree(req->buf);
usb_ep_free_request(dbgp.o_ep, req);
dbgp_disable_ep();
fail:
dev_dbg(&dbgp.gadget->dev,
"complete: failure (%d:%d) ==> %d\n", stp, err, status);
}
static int dbgp_enable_ep_req(struct usb_ep *ep)
{
int err, stp;
struct usb_request *req;
req = usb_ep_alloc_request(ep, GFP_KERNEL);
if (!req) {
err = -ENOMEM;
stp = 1;
goto fail_1;
}
req->buf = kmalloc(DBGP_REQ_LEN, GFP_KERNEL);
if (!req->buf) {
err = -ENOMEM;
stp = 2;
goto fail_2;
}
req->complete = dbgp_complete;
req->length = DBGP_REQ_LEN;
err = usb_ep_queue(ep, req, GFP_ATOMIC);
if (err < 0) {
stp = 3;
goto fail_3;
}
return 0;
fail_3:
kfree(req->buf);
fail_2:
usb_ep_free_request(dbgp.o_ep, req);
fail_1:
dev_dbg(&dbgp.gadget->dev,
"enable ep req: failure (%d:%d)\n", stp, err);
return err;
}
static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
{
int err = usb_ep_enable(ep, desc);
ep->driver_data = dbgp.gadget;
return err;
}
static int dbgp_enable_ep(void)
{
int err, stp;
err = __enable_ep(dbgp.i_ep, &i_desc);
if (err < 0) {
stp = 1;
goto fail_1;
}
err = __enable_ep(dbgp.o_ep, &o_desc);
if (err < 0) {
stp = 2;
goto fail_2;
}
err = dbgp_enable_ep_req(dbgp.o_ep);
if (err < 0) {
stp = 3;
goto fail_3;
}
return 0;
fail_3:
__disable_ep(dbgp.o_ep);
fail_2:
__disable_ep(dbgp.i_ep);
fail_1:
dev_dbg(&dbgp.gadget->dev, "enable ep: failure (%d:%d)\n", stp, err);
return err;
}
#endif
static void dbgp_disconnect(struct usb_gadget *gadget)
{
#ifdef CONFIG_USB_G_DBGP_PRINTK
dbgp_disable_ep();
#else
gserial_disconnect(dbgp.serial);
#endif
}
static void dbgp_unbind(struct usb_gadget *gadget)
{
#ifdef CONFIG_USB_G_DBGP_SERIAL
kfree(dbgp.serial);
#endif
if (dbgp.req) {
kfree(dbgp.req->buf);
usb_ep_free_request(gadget->ep0, dbgp.req);
}
gadget->ep0->driver_data = NULL;
}
static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
{
int stp;
usb_ep_autoconfig_reset(gadget);
dbgp.i_ep = usb_ep_autoconfig(gadget, &i_desc);
if (!dbgp.i_ep) {
stp = 1;
goto fail_1;
}
dbgp.i_ep->driver_data = gadget;
i_desc.wMaxPacketSize =
__constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
dbgp.o_ep = usb_ep_autoconfig(gadget, &o_desc);
if (!dbgp.o_ep) {
dbgp.i_ep->driver_data = NULL;
stp = 2;
goto fail_2;
}
dbgp.o_ep->driver_data = gadget;
o_desc.wMaxPacketSize =
__constant_cpu_to_le16(USB_DEBUG_MAX_PACKET_SIZE);
dbg_desc.bDebugInEndpoint = i_desc.bEndpointAddress & 0x7f;
dbg_desc.bDebugOutEndpoint = o_desc.bEndpointAddress & 0x7f;
#ifdef CONFIG_USB_G_DBGP_SERIAL
dbgp.serial->in = dbgp.i_ep;
dbgp.serial->out = dbgp.o_ep;
dbgp.serial->in_desc = &i_desc;
dbgp.serial->out_desc = &o_desc;
if (gserial_setup(gadget, 1) < 0) {
stp = 3;
goto fail_3;
}
return 0;
fail_3:
dbgp.o_ep->driver_data = NULL;
#else
return 0;
#endif
fail_2:
dbgp.i_ep->driver_data = NULL;
fail_1:
dev_dbg(&dbgp.gadget->dev, "ep config: failure (%d)\n", stp);
return -ENODEV;
}
static int __init dbgp_bind(struct usb_gadget *gadget)
{
int err, stp;
dbgp.gadget = gadget;
dbgp.req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
if (!dbgp.req) {
err = -ENOMEM;
stp = 1;
goto fail;
}
dbgp.req->buf = kmalloc(DBGP_REQ_EP0_LEN, GFP_KERNEL);
if (!dbgp.req->buf) {
err = -ENOMEM;
stp = 2;
goto fail;
}
dbgp.req->length = DBGP_REQ_EP0_LEN;
gadget->ep0->driver_data = gadget;
#ifdef CONFIG_USB_G_DBGP_SERIAL
dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
if (!dbgp.serial) {
stp = 3;
err = -ENOMEM;
goto fail;
}
#endif
err = dbgp_configure_endpoints(gadget);
if (err < 0) {
stp = 4;
goto fail;
}
dev_dbg(&dbgp.gadget->dev, "bind: success\n");
return 0;
fail:
dev_dbg(&gadget->dev, "bind: failure (%d:%d)\n", stp, err);
dbgp_unbind(gadget);
return err;
}
static void dbgp_setup_complete(struct usb_ep *ep,
struct usb_request *req)
{
dev_dbg(&dbgp.gadget->dev, "setup complete: %d, %d/%d\n",
req->status, req->actual, req->length);
}
static int dbgp_setup(struct usb_gadget *gadget,
const struct usb_ctrlrequest *ctrl)
{
struct usb_request *req = dbgp.req;
u8 request = ctrl->bRequest;
u16 value = le16_to_cpu(ctrl->wValue);
u16 length = le16_to_cpu(ctrl->wLength);
int err = 0;
void *data;
u16 len;
gadget->ep0->driver_data = gadget;
if (request == USB_REQ_GET_DESCRIPTOR) {
switch (value>>8) {
case USB_DT_DEVICE:
dev_dbg(&dbgp.gadget->dev, "setup: desc device\n");
len = sizeof device_desc;
data = &device_desc;
break;
case USB_DT_DEBUG:
dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n");
len = sizeof dbg_desc;
data = &dbg_desc;
break;
default:
goto fail;
}
} else if (request == USB_REQ_SET_FEATURE &&
value == USB_DEVICE_DEBUG_MODE) {
len = 0;
data = NULL;
dev_dbg(&dbgp.gadget->dev, "setup: feat debug\n");
#ifdef CONFIG_USB_G_DBGP_PRINTK
err = dbgp_enable_ep();
#else
err = gserial_connect(dbgp.serial, 0);
#endif
if (err < 0)
goto fail;
} else
goto fail;
if (len >= 0) {
req->length = min(length, len);
req->zero = len < req->length;
if (data && req->length)
memcpy(req->buf, data, req->length);
req->complete = dbgp_setup_complete;
return usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
}
fail:
dev_dbg(&dbgp.gadget->dev,
"setup: failure req %x v %x\n", request, value);
return err;
}
static struct usb_gadget_driver dbgp_driver = {
.function = "dbgp",
.speed = USB_SPEED_HIGH,
.bind = dbgp_bind,
.unbind = dbgp_unbind,
.setup = dbgp_setup,
.disconnect = dbgp_disconnect,
.driver = {
.owner = THIS_MODULE,
.name = "dbgp"
},
};
static int __init dbgp_init(void)
{
return usb_gadget_register_driver(&dbgp_driver);
}
static void __exit dbgp_exit(void)
{
usb_gadget_unregister_driver(&dbgp_driver);
#ifdef CONFIG_USB_G_DBGP_SERIAL
gserial_cleanup();
#endif
}
MODULE_AUTHOR("Stephane Duverger");
MODULE_LICENSE("GPL");
module_init(dbgp_init);
module_exit(dbgp_exit);

View File

@ -1542,7 +1542,7 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
if (!HCD_HW_ACCESSIBLE(hcd))
goto done;
if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
@ -1588,7 +1588,7 @@ static int dummy_hub_control (
int retval = 0;
unsigned long flags;
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
if (!HCD_HW_ACCESSIBLE(hcd))
return -ETIMEDOUT;
dum = hcd_to_dummy (hcd);
@ -1739,7 +1739,7 @@ static int dummy_bus_resume (struct usb_hcd *hcd)
dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
spin_lock_irq (&dum->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
if (!HCD_HW_ACCESSIBLE(hcd)) {
rc = -ESHUTDOWN;
} else {
dum->rh_state = DUMMY_RH_RUNNING;

View File

@ -237,7 +237,7 @@ static u8 hostaddr[ETH_ALEN];
* the first one present. That's to make Microsoft's drivers happy,
* and to follow DOCSIS 1.0 (cable modem standard).
*/
static int __init rndis_do_config(struct usb_configuration *c)
static int __ref rndis_do_config(struct usb_configuration *c)
{
/* FIXME alloc iConfiguration string, set it in c->strings */
@ -270,7 +270,7 @@ MODULE_PARM_DESC(use_eem, "use CDC EEM mode");
/*
* We _always_ have an ECM, CDC Subset, or EEM configuration.
*/
static int __init eth_do_config(struct usb_configuration *c)
static int __ref eth_do_config(struct usb_configuration *c)
{
/* FIXME alloc iConfiguration string, set it in c->strings */
@ -297,7 +297,7 @@ static struct usb_configuration eth_config_driver = {
/*-------------------------------------------------------------------------*/
static int __init eth_bind(struct usb_composite_dev *cdev)
static int __ref eth_bind(struct usb_composite_dev *cdev)
{
int gcnum;
struct usb_gadget *gadget = cdev->gadget;

View File

@ -714,9 +714,7 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
struct ffs_function *func = ffs->func;
ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV;
} else if (gadget->ops->ioctl) {
lock_kernel();
ret = gadget->ops->ioctl(gadget, code, value);
unlock_kernel();
} else {
ret = -ENOTTY;
}
@ -1377,7 +1375,8 @@ static void ffs_data_reset(struct ffs_data *ffs)
static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
{
unsigned i, count;
struct usb_gadget_strings **lang;
int first_id;
ENTER();
@ -1385,7 +1384,9 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
|| test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
return -EBADFD;
ffs_data_get(ffs);
first_id = usb_string_ids_n(cdev, ffs->strings_count);
if (unlikely(first_id < 0))
return first_id;
ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
if (unlikely(!ffs->ep0req))
@ -1393,25 +1394,16 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev)
ffs->ep0req->complete = ffs_ep0_complete;
ffs->ep0req->context = ffs;
/* Get strings identifiers */
for (count = ffs->strings_count, i = 0; i < count; ++i) {
struct usb_gadget_strings **lang;
int id = usb_string_id(cdev);
if (unlikely(id < 0)) {
usb_ep_free_request(cdev->gadget->ep0, ffs->ep0req);
ffs->ep0req = NULL;
return id;
}
lang = ffs->stringtabs;
do {
(*lang)->strings[i].id = id;
++lang;
} while (*lang);
lang = ffs->stringtabs;
for (lang = ffs->stringtabs; *lang; ++lang) {
struct usb_string *str = (*lang)->strings;
int id = first_id;
for (; str->s; ++id, ++str)
str->id = id;
}
ffs->gadget = cdev->gadget;
ffs_data_get(ffs);
return 0;
}
@ -1480,9 +1472,9 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
}
static int functionfs_add(struct usb_composite_dev *cdev,
struct usb_configuration *c,
struct ffs_data *ffs)
static int functionfs_bind_config(struct usb_composite_dev *cdev,
struct usb_configuration *c,
struct ffs_data *ffs)
{
struct ffs_function *func;
int ret;

View File

@ -142,7 +142,7 @@ static struct usb_descriptor_header *hidg_fs_descriptors[] = {
static ssize_t f_hidg_read(struct file *file, char __user *buffer,
size_t count, loff_t *ptr)
{
struct f_hidg *hidg = (struct f_hidg *)file->private_data;
struct f_hidg *hidg = file->private_data;
char *tmp_buff = NULL;
unsigned long flags;
@ -200,7 +200,7 @@ static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req)
static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
size_t count, loff_t *offp)
{
struct f_hidg *hidg = (struct f_hidg *)file->private_data;
struct f_hidg *hidg = file->private_data;
ssize_t status = -ENOMEM;
if (!access_ok(VERIFY_READ, buffer, count))
@ -257,7 +257,7 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
static unsigned int f_hidg_poll(struct file *file, poll_table *wait)
{
struct f_hidg *hidg = (struct f_hidg *)file->private_data;
struct f_hidg *hidg = file->private_data;
unsigned int ret = 0;
poll_wait(file, &hidg->read_queue, wait);

View File

@ -324,7 +324,7 @@ static void loopback_disable(struct usb_function *f)
/*-------------------------------------------------------------------------*/
static int __init loopback_bind_config(struct usb_configuration *c)
static int __ref loopback_bind_config(struct usb_configuration *c)
{
struct f_loopback *loop;
int status;
@ -346,7 +346,7 @@ static int __init loopback_bind_config(struct usb_configuration *c)
return status;
}
static struct usb_configuration loopback_driver = {
static struct usb_configuration loopback_driver = {
.label = "loopback",
.strings = loopback_strings,
.bind = loopback_bind_config,

View File

@ -316,6 +316,27 @@ static const char fsg_string_interface[] = "Mass Storage";
/*-------------------------------------------------------------------------*/
struct fsg_dev;
struct fsg_common;
/* FSF callback functions */
struct fsg_operations {
/* Callback function to call when thread exits. If no
* callback is set or it returns value lower then zero MSF
* will force eject all LUNs it operates on (including those
* marked as non-removable or with prevent_medium_removal flag
* set). */
int (*thread_exits)(struct fsg_common *common);
/* Called prior to ejection. Negative return means error,
* zero means to continue with ejection, positive means not to
* eject. */
int (*pre_eject)(struct fsg_common *common,
struct fsg_lun *lun, int num);
/* Called after ejection. Negative return means error, zero
* or positive is just a success. */
int (*post_eject)(struct fsg_common *common,
struct fsg_lun *lun, int num);
};
/* Data shared by all the FSG instances. */
@ -333,7 +354,6 @@ struct fsg_common {
struct usb_ep *ep0; /* Copy of gadget->ep0 */
struct usb_request *ep0req; /* Copy of cdev->req */
unsigned int ep0_req_tag;
const char *ep0req_name;
struct fsg_buffhd *next_buffhd_to_fill;
struct fsg_buffhd *next_buffhd_to_drain;
@ -369,8 +389,8 @@ struct fsg_common {
struct completion thread_notifier;
struct task_struct *thread_task;
/* Callback function to call when thread exits. */
int (*thread_exits)(struct fsg_common *common);
/* Callback functions. */
const struct fsg_operations *ops;
/* Gadget's private data. */
void *private_data;
@ -394,12 +414,8 @@ struct fsg_config {
const char *lun_name_format;
const char *thread_name;
/* Callback function to call when thread exits. If no
* callback is set or it returns value lower then zero MSF
* will force eject all LUNs it operates on (including those
* marked as non-removable or with prevent_medium_removal flag
* set). */
int (*thread_exits)(struct fsg_common *common);
/* Callback functions. */
const struct fsg_operations *ops;
/* Gadget's private data. */
void *private_data;
@ -435,6 +451,7 @@ static inline int __fsg_is_set(struct fsg_common *common,
if (common->fsg)
return 1;
ERROR(common, "common->fsg is NULL in %s at %u\n", func, line);
WARN_ON(1);
return 0;
}
@ -623,8 +640,6 @@ static int fsg_setup(struct usb_function *f,
/* Respond with data/status */
req->length = min((u16)1, w_length);
fsg->common->ep0req_name =
ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out";
return ep0_queue(fsg->common);
}
@ -1395,43 +1410,55 @@ static int do_start_stop(struct fsg_common *common)
} else if (!curlun->removable) {
curlun->sense_data = SS_INVALID_COMMAND;
return -EINVAL;
}
loej = common->cmnd[4] & 0x02;
start = common->cmnd[4] & 0x01;
/* eject code from file_storage.c:do_start_stop() */
if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
(common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
} else if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
(common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
return -EINVAL;
}
if (!start) {
/* Are we allowed to unload the media? */
if (curlun->prevent_medium_removal) {
LDBG(curlun, "unload attempt prevented\n");
curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
return -EINVAL;
}
if (loej) { /* Simulate an unload/eject */
up_read(&common->filesem);
down_write(&common->filesem);
fsg_lun_close(curlun);
up_write(&common->filesem);
down_read(&common->filesem);
}
} else {
loej = common->cmnd[4] & 0x02;
start = common->cmnd[4] & 0x01;
/* Our emulation doesn't support mounting; the medium is
* available for use as soon as it is loaded. */
/* Our emulation doesn't support mounting; the medium is
* available for use as soon as it is loaded. */
if (start) {
if (!fsg_lun_is_open(curlun)) {
curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
return -EINVAL;
}
return 0;
}
return 0;
/* Are we allowed to unload the media? */
if (curlun->prevent_medium_removal) {
LDBG(curlun, "unload attempt prevented\n");
curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED;
return -EINVAL;
}
if (!loej)
return 0;
/* Simulate an unload/eject */
if (common->ops && common->ops->pre_eject) {
int r = common->ops->pre_eject(common, curlun,
curlun - common->luns);
if (unlikely(r < 0))
return r;
else if (r)
return 0;
}
up_read(&common->filesem);
down_write(&common->filesem);
fsg_lun_close(curlun);
up_write(&common->filesem);
down_read(&common->filesem);
return common->ops && common->ops->post_eject
? min(0, common->ops->post_eject(common, curlun,
curlun - common->luns))
: 0;
}
@ -2610,7 +2637,8 @@ static int fsg_main_thread(void *common_)
common->thread_task = NULL;
spin_unlock_irq(&common->lock);
if (!common->thread_exits || common->thread_exits(common) < 0) {
if (!common->ops || !common->ops->thread_exits
|| common->ops->thread_exits(common) < 0) {
struct fsg_lun *curlun = common->luns;
unsigned i = common->nluns;
@ -2686,6 +2714,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
common->free_storage_on_release = 0;
}
common->ops = cfg->ops;
common->private_data = cfg->private_data;
common->gadget = gadget;
@ -2807,7 +2836,6 @@ buffhds_first_it:
/* Tell the thread to start working */
common->thread_exits = cfg->thread_exits;
common->thread_task =
kthread_create(fsg_main_thread, common,
OR(cfg->thread_name, "file-storage"));
@ -2990,9 +3018,9 @@ static struct usb_gadget_strings *fsg_strings_array[] = {
NULL,
};
static int fsg_add(struct usb_composite_dev *cdev,
struct usb_configuration *c,
struct fsg_common *common)
static int fsg_bind_config(struct usb_composite_dev *cdev,
struct usb_configuration *c,
struct fsg_common *common)
{
struct fsg_dev *fsg;
int rc;
@ -3024,6 +3052,13 @@ static int fsg_add(struct usb_composite_dev *cdev,
return rc;
}
static inline int __deprecated __maybe_unused
fsg_add(struct usb_composite_dev *cdev,
struct usb_configuration *c,
struct fsg_common *common)
{
return fsg_bind_config(cdev, c, common);
}
/************************* Module parameters *************************/
@ -3096,8 +3131,8 @@ fsg_config_from_params(struct fsg_config *cfg,
cfg->product_name = 0;
cfg->release = 0xffff;
cfg->thread_exits = 0;
cfg->private_data = 0;
cfg->ops = NULL;
cfg->private_data = NULL;
/* Finalise */
cfg->can_stall = params->stall;

View File

@ -404,7 +404,7 @@ static void sourcesink_disable(struct usb_function *f)
/*-------------------------------------------------------------------------*/
static int __init sourcesink_bind_config(struct usb_configuration *c)
static int __ref sourcesink_bind_config(struct usb_configuration *c)
{
struct f_sourcesink *ss;
int status;

View File

@ -56,7 +56,7 @@
* following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
* UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
* the optional "protocol" module parameter. In addition, the default
* Vendor ID, Product ID, and release number can be overridden.
* Vendor ID, Product ID, release number and serial number can be overridden.
*
* There is support for multiple logical units (LUNs), each of which has
* its own backing file. The number of LUNs can be set using the optional
@ -93,6 +93,8 @@
* removable Default false, boolean for removable media
* luns=N Default N = number of filenames, number of
* LUNs to support
* nofua=b[,b...] Default false, booleans for ignore FUA flag
* in SCSI WRITE(10,12) commands
* stall Default determined according to the type of
* USB device controller (usually true),
* boolean to permit the driver to halt
@ -106,17 +108,18 @@
* vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
* product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
* release=0xRRRR Override the USB release number (bcdDevice)
* serial=HHHH... Override serial number (string of hex chars)
* buflen=N Default N=16384, buffer size used (will be
* rounded down to a multiple of
* PAGE_CACHE_SIZE)
*
* If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro",
* "removable", "luns", "stall", and "cdrom" options are available; default
* values are used for everything else.
* "removable", "luns", "nofua", "stall", and "cdrom" options are available;
* default values are used for everything else.
*
* The pathnames of the backing files and the ro settings are available in
* the attribute files "file" and "ro" in the lun<n> subdirectory of the
* gadget's sysfs directory. If the "removable" option is set, writing to
* the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of
* the gadget's sysfs directory. If the "removable" option is set, writing to
* these files will simulate ejecting/loading the medium (writing an empty
* line means eject) and adjusting a write-enable tab. Changes to the ro
* setting are not allowed when the medium is loaded or if CD-ROM emulation
@ -270,6 +273,8 @@
#define DRIVER_DESC "File-backed Storage Gadget"
#define DRIVER_NAME "g_file_storage"
/* DRIVER_VERSION must be at least 6 characters long, as it is used
* to generate a fallback serial number. */
#define DRIVER_VERSION "20 November 2008"
static char fsg_string_manufacturer[64];
@ -301,8 +306,10 @@ MODULE_LICENSE("Dual BSD/GPL");
static struct {
char *file[FSG_MAX_LUNS];
int ro[FSG_MAX_LUNS];
int nofua[FSG_MAX_LUNS];
unsigned int num_filenames;
unsigned int num_ros;
unsigned int num_nofuas;
unsigned int nluns;
int removable;
@ -314,6 +321,7 @@ static struct {
unsigned short vendor;
unsigned short product;
unsigned short release;
char *serial;
unsigned int buflen;
int transport_type;
@ -341,6 +349,10 @@ MODULE_PARM_DESC(file, "names of backing files or devices");
module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
MODULE_PARM_DESC(ro, "true to force read-only");
module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas,
S_IRUGO);
MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit");
module_param_named(luns, mod_data.nluns, uint, S_IRUGO);
MODULE_PARM_DESC(luns, "number of LUNs");
@ -353,6 +365,8 @@ MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
module_param_named(serial, mod_data.serial, charp, S_IRUGO);
MODULE_PARM_DESC(serial, "USB serial number");
/* In the non-TEST version, only the module parameters listed above
* are available. */
@ -1272,7 +1286,8 @@ static int do_write(struct fsg_dev *fsg)
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
return -EINVAL;
}
if (fsg->cmnd[1] & 0x08) { // FUA
/* FUA */
if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) {
spin_lock(&curlun->filp->f_lock);
curlun->filp->f_flags |= O_DSYNC;
spin_unlock(&curlun->filp->f_lock);
@ -3126,6 +3141,7 @@ static int fsg_main_thread(void *fsg_)
/* The write permissions and store_xxx pointers are set in fsg_bind() */
static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL);
static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL);
static DEVICE_ATTR(file, 0444, fsg_show_file, NULL);
@ -3197,6 +3213,7 @@ static int __init check_parameters(struct fsg_dev *fsg)
{
int prot;
int gcnum;
int i;
/* Store the default values */
mod_data.transport_type = USB_PR_BULK;
@ -3272,13 +3289,65 @@ static int __init check_parameters(struct fsg_dev *fsg)
ERROR(fsg, "invalid buflen\n");
return -ETOOSMALL;
}
#endif /* CONFIG_USB_FILE_STORAGE_TEST */
/* Serial string handling.
* On a real device, the serial string would be loaded
* from permanent storage. */
if (mod_data.serial) {
const char *ch;
unsigned len = 0;
/* Sanity check :
* The CB[I] specification limits the serial string to
* 12 uppercase hexadecimal characters.
* BBB need at least 12 uppercase hexadecimal characters,
* with a maximum of 126. */
for (ch = mod_data.serial; *ch; ++ch) {
++len;
if ((*ch < '0' || *ch > '9') &&
(*ch < 'A' || *ch > 'F')) { /* not uppercase hex */
WARNING(fsg,
"Invalid serial string character: %c; "
"Failing back to default\n",
*ch);
goto fill_serial;
}
}
if (len > 126 ||
(mod_data.transport_type == USB_PR_BULK && len < 12) ||
(mod_data.transport_type != USB_PR_BULK && len > 12)) {
WARNING(fsg,
"Invalid serial string length; "
"Failing back to default\n");
goto fill_serial;
}
fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial;
} else {
WARNING(fsg,
"Userspace failed to provide serial number; "
"Failing back to default\n");
fill_serial:
/* Serial number not specified or invalid, make our own.
* We just encode it from the driver version string,
* 12 characters to comply with both CB[I] and BBB spec.
* Warning : Two devices running the same kernel will have
* the same fallback serial number. */
for (i = 0; i < 12; i += 2) {
unsigned char c = DRIVER_VERSION[i / 2];
if (!c)
break;
sprintf(&fsg_string_serial[i], "%02X", c);
}
}
return 0;
}
static int __init fsg_bind(struct usb_gadget *gadget)
static int __ref fsg_bind(struct usb_gadget *gadget)
{
struct fsg_dev *fsg = the_fsg;
int rc;
@ -3305,6 +3374,10 @@ static int __init fsg_bind(struct usb_gadget *gadget)
}
}
/* Only for removable media? */
dev_attr_nofua.attr.mode = 0644;
dev_attr_nofua.store = fsg_store_nofua;
/* Find out how many LUNs there should be */
i = mod_data.nluns;
if (i == 0)
@ -3330,6 +3403,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
curlun->ro = mod_data.cdrom || mod_data.ro[i];
curlun->initially_ro = curlun->ro;
curlun->removable = mod_data.removable;
curlun->nofua = mod_data.nofua[i];
curlun->dev.release = lun_release;
curlun->dev.parent = &gadget->dev;
curlun->dev.driver = &fsg_driver.driver;
@ -3343,6 +3417,8 @@ static int __init fsg_bind(struct usb_gadget *gadget)
}
if ((rc = device_create_file(&curlun->dev,
&dev_attr_ro)) != 0 ||
(rc = device_create_file(&curlun->dev,
&dev_attr_nofua)) != 0 ||
(rc = device_create_file(&curlun->dev,
&dev_attr_file)) != 0) {
device_unregister(&curlun->dev);
@ -3447,16 +3523,6 @@ static int __init fsg_bind(struct usb_gadget *gadget)
init_utsname()->sysname, init_utsname()->release,
gadget->name);
/* On a real device, serial[] would be loaded from permanent
* storage. We just encode it from the driver version string. */
for (i = 0; i < sizeof fsg_string_serial - 2; i += 2) {
unsigned char c = DRIVER_VERSION[i / 2];
if (!c)
break;
sprintf(&fsg_string_serial[i], "%02X", c);
}
fsg->thread_task = kthread_create(fsg_main_thread, fsg,
"file-storage-gadget");
if (IS_ERR(fsg->thread_task)) {
@ -3478,8 +3544,8 @@ static int __init fsg_bind(struct usb_gadget *gadget)
if (IS_ERR(p))
p = NULL;
}
LINFO(curlun, "ro=%d, file: %s\n",
curlun->ro, (p ? p : "(error)"));
LINFO(curlun, "ro=%d, nofua=%d, file: %s\n",
curlun->ro, curlun->nofua, (p ? p : "(error)"));
}
}
kfree(pathbuf);

View File

@ -32,12 +32,13 @@
# include "u_ether.c"
static u8 gfs_hostaddr[ETH_ALEN];
#else
# if !defined CONFIG_USB_FUNCTIONFS_GENERIC
# define CONFIG_USB_FUNCTIONFS_GENERIC
# ifdef CONFIG_USB_FUNCTIONFS_ETH
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
# endif
#else
# define gether_cleanup() do { } while (0)
# define gether_setup(gadget, hostaddr) ((int)0)
# define gfs_hostaddr NULL
#endif
#include "f_fs.c"
@ -107,15 +108,7 @@ static const struct usb_descriptor_header *gfs_otg_desc[] = {
enum {
GFS_STRING_MANUFACTURER_IDX,
GFS_STRING_PRODUCT_IDX,
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
GFS_STRING_RNDIS_CONFIG_IDX,
#endif
#ifdef CONFIG_USB_FUNCTIONFS_ETH
GFS_STRING_ECM_CONFIG_IDX,
#endif
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
GFS_STRING_GENERIC_CONFIG_IDX,
#endif
GFS_STRING_FIRST_CONFIG_IDX,
};
static char gfs_manufacturer[50];
@ -126,13 +119,13 @@ static struct usb_string gfs_strings[] = {
[GFS_STRING_MANUFACTURER_IDX].s = gfs_manufacturer,
[GFS_STRING_PRODUCT_IDX].s = gfs_driver_desc,
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
[GFS_STRING_RNDIS_CONFIG_IDX].s = "FunctionFS + RNDIS",
{ .s = "FunctionFS + RNDIS" },
#endif
#ifdef CONFIG_USB_FUNCTIONFS_ETH
[GFS_STRING_ECM_CONFIG_IDX].s = "FunctionFS + ECM",
{ .s = "FunctionFS + ECM" },
#endif
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
[GFS_STRING_GENERIC_CONFIG_IDX].s = "FunctionFS",
{ .s = "FunctionFS" },
#endif
{ } /* end of list */
};
@ -146,59 +139,33 @@ static struct usb_gadget_strings *gfs_dev_strings[] = {
};
struct gfs_configuration {
struct usb_configuration c;
int (*eth)(struct usb_configuration *c, u8 *ethaddr);
} gfs_configurations[] = {
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
static int gfs_do_rndis_config(struct usb_configuration *c);
static struct usb_configuration gfs_rndis_config_driver = {
.label = "FunctionFS + RNDIS",
.bind = gfs_do_rndis_config,
.bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
};
# define gfs_add_rndis_config(cdev) \
usb_add_config(cdev, &gfs_rndis_config_driver)
#else
# define gfs_add_rndis_config(cdev) 0
{
.eth = rndis_bind_config,
},
#endif
#ifdef CONFIG_USB_FUNCTIONFS_ETH
static int gfs_do_ecm_config(struct usb_configuration *c);
static struct usb_configuration gfs_ecm_config_driver = {
.label = "FunctionFS + ECM",
.bind = gfs_do_ecm_config,
.bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
};
# define gfs_add_ecm_config(cdev) \
usb_add_config(cdev, &gfs_ecm_config_driver)
#else
# define gfs_add_ecm_config(cdev) 0
{
.eth = eth_bind_config,
},
#endif
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
static int gfs_do_generic_config(struct usb_configuration *c);
static struct usb_configuration gfs_generic_config_driver = {
.label = "FunctionFS",
.bind = gfs_do_generic_config,
.bConfigurationValue = 2,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
};
# define gfs_add_generic_config(cdev) \
usb_add_config(cdev, &gfs_generic_config_driver)
#else
# define gfs_add_generic_config(cdev) 0
{
},
#endif
};
static int gfs_bind(struct usb_composite_dev *cdev);
static int gfs_unbind(struct usb_composite_dev *cdev);
static int gfs_do_config(struct usb_configuration *c);
static struct usb_composite_driver gfs_driver = {
.name = gfs_short_name,
@ -267,7 +234,7 @@ static int functionfs_check_dev_callback(const char *dev_name)
static int gfs_bind(struct usb_composite_dev *cdev)
{
int ret;
int ret, i;
ENTER();
@ -284,57 +251,32 @@ static int gfs_bind(struct usb_composite_dev *cdev)
snprintf(gfs_manufacturer, sizeof gfs_manufacturer, "%s %s with %s",
init_utsname()->sysname, init_utsname()->release,
cdev->gadget->name);
ret = usb_string_id(cdev);
if (unlikely(ret < 0))
goto error;
gfs_strings[GFS_STRING_MANUFACTURER_IDX].id = ret;
gfs_dev_desc.iManufacturer = ret;
ret = usb_string_id(cdev);
ret = usb_string_ids_tab(cdev, gfs_strings);
if (unlikely(ret < 0))
goto error;
gfs_strings[GFS_STRING_PRODUCT_IDX].id = ret;
gfs_dev_desc.iProduct = ret;
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
ret = usb_string_id(cdev);
if (unlikely(ret < 0))
goto error;
gfs_strings[GFS_STRING_RNDIS_CONFIG_IDX].id = ret;
gfs_rndis_config_driver.iConfiguration = ret;
#endif
#ifdef CONFIG_USB_FUNCTIONFS_ETH
ret = usb_string_id(cdev);
if (unlikely(ret < 0))
goto error;
gfs_strings[GFS_STRING_ECM_CONFIG_IDX].id = ret;
gfs_ecm_config_driver.iConfiguration = ret;
#endif
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
ret = usb_string_id(cdev);
if (unlikely(ret < 0))
goto error;
gfs_strings[GFS_STRING_GENERIC_CONFIG_IDX].id = ret;
gfs_generic_config_driver.iConfiguration = ret;
#endif
gfs_dev_desc.iManufacturer = gfs_strings[GFS_STRING_MANUFACTURER_IDX].id;
gfs_dev_desc.iProduct = gfs_strings[GFS_STRING_PRODUCT_IDX].id;
ret = functionfs_bind(gfs_ffs_data, cdev);
if (unlikely(ret < 0))
goto error;
ret = gfs_add_rndis_config(cdev);
if (unlikely(ret < 0))
goto error_unbind;
for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
struct gfs_configuration *c = gfs_configurations + i;
ret = gfs_add_ecm_config(cdev);
if (unlikely(ret < 0))
goto error_unbind;
ret = GFS_STRING_FIRST_CONFIG_IDX + i;
c->c.label = gfs_strings[ret].s;
c->c.iConfiguration = gfs_strings[ret].id;
c->c.bind = gfs_do_config;
c->c.bConfigurationValue = 1 + i;
c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER;
ret = gfs_add_generic_config(cdev);
if (unlikely(ret < 0))
goto error_unbind;
ret = usb_add_config(cdev, &c->c);
if (unlikely(ret < 0))
goto error_unbind;
}
return 0;
@ -368,10 +310,10 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
}
static int __gfs_do_config(struct usb_configuration *c,
int (*eth)(struct usb_configuration *c, u8 *ethaddr),
u8 *ethaddr)
static int gfs_do_config(struct usb_configuration *c)
{
struct gfs_configuration *gc =
container_of(c, struct gfs_configuration, c);
int ret;
if (WARN_ON(!gfs_ffs_data))
@ -382,13 +324,13 @@ static int __gfs_do_config(struct usb_configuration *c,
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
if (eth) {
ret = eth(c, ethaddr);
if (gc->eth) {
ret = gc->eth(c, gfs_hostaddr);
if (unlikely(ret < 0))
return ret;
}
ret = functionfs_add(c->cdev, c, gfs_ffs_data);
ret = functionfs_bind_config(c->cdev, c, gfs_ffs_data);
if (unlikely(ret < 0))
return ret;
@ -406,32 +348,12 @@ static int __gfs_do_config(struct usb_configuration *c,
return 0;
}
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
static int gfs_do_rndis_config(struct usb_configuration *c)
{
ENTER();
return __gfs_do_config(c, rndis_bind_config, gfs_hostaddr);
}
#endif
#ifdef CONFIG_USB_FUNCTIONFS_ETH
static int gfs_do_ecm_config(struct usb_configuration *c)
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
{
ENTER();
return __gfs_do_config(c,
can_support_ecm(c->cdev->gadget)
? ecm_bind_config : geth_bind_config,
gfs_hostaddr);
}
#endif
#ifdef CONFIG_USB_FUNCTIONFS_GENERIC
static int gfs_do_generic_config(struct usb_configuration *c)
{
ENTER();
return __gfs_do_config(c, NULL, NULL);
return can_support_ecm(c->cdev->gadget)
? ecm_bind_config(c, ethaddr)
: geth_bind_config(c, ethaddr);
}
#endif

View File

@ -1157,7 +1157,7 @@ fail:
/*
* Creates an output endpoint, and initializes output ports.
*/
static int __init gmidi_bind(struct usb_gadget *gadget)
static int __ref gmidi_bind(struct usb_gadget *gadget)
{
struct gmidi_device *dev;
struct usb_ep *in_ep, *out_ep;

View File

@ -127,7 +127,7 @@ static struct usb_gadget_strings *dev_strings[] = {
/****************************** Configurations ******************************/
static int __init do_config(struct usb_configuration *c)
static int __ref do_config(struct usb_configuration *c)
{
struct hidg_func_node *e;
int func = 0, status = 0;
@ -156,7 +156,7 @@ static struct usb_configuration config_driver = {
/****************************** Gadget Bind ******************************/
static int __init hid_bind(struct usb_composite_dev *cdev)
static int __ref hid_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
struct list_head *tmp;

View File

@ -1299,11 +1299,9 @@ static long dev_ioctl (struct file *fd, unsigned code, unsigned long value)
struct usb_gadget *gadget = dev->gadget;
long ret = -ENOTTY;
if (gadget->ops->ioctl) {
lock_kernel();
if (gadget->ops->ioctl)
ret = gadget->ops->ioctl (gadget, code, value);
unlock_kernel();
}
return ret;
}
@ -1867,13 +1865,9 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
buf += 4;
length -= 4;
kbuf = kmalloc (length, GFP_KERNEL);
if (!kbuf)
return -ENOMEM;
if (copy_from_user (kbuf, buf, length)) {
kfree (kbuf);
return -EFAULT;
}
kbuf = memdup_user(buf, length);
if (IS_ERR(kbuf))
return PTR_ERR(kbuf);
spin_lock_irq (&dev->lock);
value = -EINVAL;

View File

@ -842,9 +842,9 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
VDBG(dev, "req->mapped = 0\n");
}
DBG(dev, "%s queue req %p, len %u, buf %p, dma 0x%08x\n",
_ep->name,
_req, _req->length, _req->buf, _req->dma);
DBG(dev, "%s queue req %p, len %u, buf %p, dma 0x%08llx\n",
_ep->name,
_req, _req->length, _req->buf, (unsigned long long)_req->dma);
_req->status = -EINPROGRESS;
_req->actual = 0;

View File

@ -141,9 +141,14 @@ static int msg_thread_exits(struct fsg_common *common)
return 0;
}
static int __init msg_do_config(struct usb_configuration *c)
static int __ref msg_do_config(struct usb_configuration *c)
{
struct fsg_common *common;
static const struct fsg_operations ops = {
.thread_exits = msg_thread_exits,
};
static struct fsg_common common;
struct fsg_common *retp;
struct fsg_config config;
int ret;
@ -153,13 +158,14 @@ static int __init msg_do_config(struct usb_configuration *c)
}
fsg_config_from_params(&config, &mod_data);
config.thread_exits = msg_thread_exits;
common = fsg_common_init(0, c->cdev, &config);
if (IS_ERR(common))
return PTR_ERR(common);
config.ops = &ops;
ret = fsg_add(c->cdev, c, common);
fsg_common_put(common);
retp = fsg_common_init(&common, c->cdev, &config);
if (IS_ERR(retp))
return PTR_ERR(retp);
ret = fsg_bind_config(c->cdev, c, &common);
fsg_common_put(&common);
return ret;
}
@ -176,7 +182,7 @@ static struct usb_configuration msg_config_driver = {
/****************************** Gadget Bind ******************************/
static int __init msg_bind(struct usb_composite_dev *cdev)
static int __ref msg_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
int status;

View File

@ -24,6 +24,7 @@
#include <linux/kernel.h>
#include <linux/utsname.h>
#include <linux/module.h>
#if defined USB_ETH_RNDIS
@ -35,14 +36,13 @@
#define DRIVER_DESC "Multifunction Composite Gadget"
#define DRIVER_VERSION "2009/07/21"
/*-------------------------------------------------------------------------*/
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Michal Nazarewicz");
MODULE_LICENSE("GPL");
#define MULTI_VENDOR_NUM 0x0525 /* XXX NetChip */
#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */
/*-------------------------------------------------------------------------*/
/***************************** All the files... *****************************/
/*
* kbuild is not very cooperative with respect to linking separately
@ -57,6 +57,8 @@
#include "config.c"
#include "epautoconf.c"
#include "f_mass_storage.c"
#include "u_serial.c"
#include "f_acm.c"
@ -68,13 +70,24 @@
#endif
#include "u_ether.c"
#undef DBG /* u_ether.c has broken idea about macros */
#undef VDBG /* so clean up after it */
#undef ERROR
#undef INFO
#include "f_mass_storage.c"
/*-------------------------------------------------------------------------*/
/***************************** Device Descriptor ****************************/
#define MULTI_VENDOR_NUM 0x0525 /* XXX NetChip */
#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */
enum {
__MULTI_NO_CONFIG,
#ifdef CONFIG_USB_G_MULTI_RNDIS
MULTI_RNDIS_CONFIG_NUM,
#endif
#ifdef CONFIG_USB_G_MULTI_CDC
MULTI_CDC_CONFIG_NUM,
#endif
};
static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
@ -82,80 +95,82 @@ static struct usb_device_descriptor device_desc = {
.bcdUSB = cpu_to_le16(0x0200),
/* .bDeviceClass = USB_CLASS_COMM, */
/* .bDeviceSubClass = 0, */
/* .bDeviceProtocol = 0, */
.bDeviceClass = 0xEF,
.bDeviceClass = USB_CLASS_MISC /* 0xEF */,
.bDeviceSubClass = 2,
.bDeviceProtocol = 1,
/* .bMaxPacketSize0 = f(hardware) */
/* Vendor and product id can be overridden by module parameters. */
.idVendor = cpu_to_le16(MULTI_VENDOR_NUM),
.idProduct = cpu_to_le16(MULTI_PRODUCT_NUM),
/* .bcdDevice = f(hardware) */
/* .iManufacturer = DYNAMIC */
/* .iProduct = DYNAMIC */
/* NO SERIAL NUMBER */
.bNumConfigurations = 1,
};
static struct usb_otg_descriptor otg_descriptor = {
.bLength = sizeof otg_descriptor,
.bDescriptorType = USB_DT_OTG,
/* REVISIT SRP-only hardware is possible, although
* it would not be called "OTG" ...
*/
.bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
};
static const struct usb_descriptor_header *otg_desc[] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &(struct usb_otg_descriptor){
.bLength = sizeof(struct usb_otg_descriptor),
.bDescriptorType = USB_DT_OTG,
/*
* REVISIT SRP-only hardware is possible, although
* it would not be called "OTG" ...
*/
.bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
},
NULL,
};
/* string IDs are assigned dynamically */
#define STRING_MANUFACTURER_IDX 0
#define STRING_PRODUCT_IDX 1
enum {
MULTI_STRING_MANUFACTURER_IDX,
MULTI_STRING_PRODUCT_IDX,
#ifdef CONFIG_USB_G_MULTI_RNDIS
MULTI_STRING_RNDIS_CONFIG_IDX,
#endif
#ifdef CONFIG_USB_G_MULTI_CDC
MULTI_STRING_CDC_CONFIG_IDX,
#endif
};
static char manufacturer[50];
static struct usb_string strings_dev[] = {
[STRING_MANUFACTURER_IDX].s = manufacturer,
[STRING_PRODUCT_IDX].s = DRIVER_DESC,
[MULTI_STRING_MANUFACTURER_IDX].s = manufacturer,
[MULTI_STRING_PRODUCT_IDX].s = DRIVER_DESC,
#ifdef CONFIG_USB_G_MULTI_RNDIS
[MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
#endif
#ifdef CONFIG_USB_G_MULTI_CDC
[MULTI_STRING_CDC_CONFIG_IDX].s = "Multifunction with CDC ECM",
#endif
{ } /* end of list */
};
static struct usb_gadget_strings stringtab_dev = {
.language = 0x0409, /* en-us */
.strings = strings_dev,
};
static struct usb_gadget_strings *dev_strings[] = {
&stringtab_dev,
&(struct usb_gadget_strings){
.language = 0x0409, /* en-us */
.strings = strings_dev,
},
NULL,
};
static u8 hostaddr[ETH_ALEN];
/****************************** Configurations ******************************/
static struct fsg_module_parameters mod_data = {
.stall = 1
};
FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
static struct fsg_common *fsg_common;
static struct fsg_common fsg_common;
static u8 hostaddr[ETH_ALEN];
/********** RNDIS **********/
#ifdef USB_ETH_RNDIS
static int __init rndis_do_config(struct usb_configuration *c)
static __ref int rndis_do_config(struct usb_configuration *c)
{
int ret;
@ -172,26 +187,42 @@ static int __init rndis_do_config(struct usb_configuration *c)
if (ret < 0)
return ret;
ret = fsg_add(c->cdev, c, fsg_common);
ret = fsg_bind_config(c->cdev, c, &fsg_common);
if (ret < 0)
return ret;
return 0;
}
static struct usb_configuration rndis_config_driver = {
.label = "Multifunction Composite (RNDIS + MS + ACM)",
.bind = rndis_do_config,
.bConfigurationValue = 2,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
};
static int rndis_config_register(struct usb_composite_dev *cdev)
{
static struct usb_configuration config = {
.bind = rndis_do_config,
.bConfigurationValue = MULTI_RNDIS_CONFIG_NUM,
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
};
config.label = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s;
config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id;
return usb_add_config(cdev, &config);
}
#else
static int rndis_config_register(struct usb_composite_dev *cdev)
{
return 0;
}
#endif
/********** CDC ECM **********/
#ifdef CONFIG_USB_G_MULTI_CDC
static int __init cdc_do_config(struct usb_configuration *c)
static __ref int cdc_do_config(struct usb_configuration *c)
{
int ret;
@ -208,20 +239,33 @@ static int __init cdc_do_config(struct usb_configuration *c)
if (ret < 0)
return ret;
ret = fsg_add(c->cdev, c, fsg_common);
ret = fsg_bind_config(c->cdev, c, &fsg_common);
if (ret < 0)
return ret;
return 0;
}
static struct usb_configuration cdc_config_driver = {
.label = "Multifunction Composite (CDC + MS + ACM)",
.bind = cdc_do_config,
.bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
};
static int cdc_config_register(struct usb_composite_dev *cdev)
{
static struct usb_configuration config = {
.bind = cdc_do_config,
.bConfigurationValue = MULTI_CDC_CONFIG_NUM,
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
};
config.label = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s;
config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id;
return usb_add_config(cdev, &config);
}
#else
static int cdc_config_register(struct usb_composite_dev *cdev)
{
return 0;
}
#endif
@ -230,7 +274,7 @@ static struct usb_configuration cdc_config_driver = {
/****************************** Gadget Bind ******************************/
static int __init multi_bind(struct usb_composite_dev *cdev)
static int __ref multi_bind(struct usb_composite_dev *cdev)
{
struct usb_gadget *gadget = cdev->gadget;
int status, gcnum;
@ -252,67 +296,56 @@ static int __init multi_bind(struct usb_composite_dev *cdev)
goto fail0;
/* set up mass storage function */
fsg_common = fsg_common_from_params(0, cdev, &mod_data);
if (IS_ERR(fsg_common)) {
status = PTR_ERR(fsg_common);
goto fail1;
{
void *retp;
retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
if (IS_ERR(retp)) {
status = PTR_ERR(retp);
goto fail1;
}
}
/* set bcdDevice */
gcnum = usb_gadget_controller_number(gadget);
if (gcnum >= 0)
if (gcnum >= 0) {
device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
else {
/* We assume that can_support_ecm() tells the truth;
* but if the controller isn't recognized at all then
* that assumption is a bit more likely to be wrong.
*/
WARNING(cdev, "controller '%s' not recognized\n",
gadget->name);
} else {
WARNING(cdev, "controller '%s' not recognized\n", gadget->name);
device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
}
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
*/
/* device descriptor strings: manufacturer, product */
/* allocate string descriptor numbers */
snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
init_utsname()->sysname, init_utsname()->release,
gadget->name);
status = usb_string_id(cdev);
if (status < 0)
goto fail2;
strings_dev[STRING_MANUFACTURER_IDX].id = status;
device_desc.iManufacturer = status;
status = usb_string_id(cdev);
if (status < 0)
status = usb_string_ids_tab(cdev, strings_dev);
if (unlikely(status < 0))
goto fail2;
strings_dev[STRING_PRODUCT_IDX].id = status;
device_desc.iProduct = status;
#ifdef USB_ETH_RNDIS
/* register our first configuration */
status = usb_add_config(cdev, &rndis_config_driver);
if (status < 0)
device_desc.iManufacturer =
strings_dev[MULTI_STRING_MANUFACTURER_IDX].id;
device_desc.iProduct =
strings_dev[MULTI_STRING_PRODUCT_IDX].id;
/* register configurations */
status = rndis_config_register(cdev);
if (unlikely(status < 0))
goto fail2;
#endif
#ifdef CONFIG_USB_G_MULTI_CDC
/* register our second configuration */
status = usb_add_config(cdev, &cdc_config_driver);
if (status < 0)
status = cdc_config_register(cdev);
if (unlikely(status < 0))
goto fail2;
#endif
dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
fsg_common_put(fsg_common);
/* we're done */
dev_info(&gadget->dev, DRIVER_DESC "\n");
fsg_common_put(&fsg_common);
return 0;
/* error recovery */
fail2:
fsg_common_put(fsg_common);
fsg_common_put(&fsg_common);
fail1:
gserial_cleanup();
fail0:
@ -339,18 +372,15 @@ static struct usb_composite_driver multi_driver = {
.unbind = __exit_p(multi_unbind),
};
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Michal Nazarewicz");
MODULE_LICENSE("GPL");
static int __init g_multi_init(void)
static int __init multi_init(void)
{
return usb_composite_register(&multi_driver);
}
module_init(g_multi_init);
module_init(multi_init);
static void __exit g_multi_cleanup(void)
static void __exit multi_exit(void)
{
usb_composite_unregister(&multi_driver);
}
module_exit(g_multi_cleanup);
module_exit(multi_exit);

View File

@ -25,7 +25,7 @@
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
@ -70,6 +70,7 @@
#define DRIVER_DESC "Printer Gadget"
#define DRIVER_VERSION "2007 OCT 06"
static DEFINE_MUTEX(printer_mutex);
static const char shortname [] = "printer";
static const char driver_desc [] = DRIVER_DESC;
@ -476,7 +477,7 @@ printer_open(struct inode *inode, struct file *fd)
unsigned long flags;
int ret = -EBUSY;
lock_kernel();
mutex_lock(&printer_mutex);
dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev);
spin_lock_irqsave(&dev->lock, flags);
@ -492,7 +493,7 @@ printer_open(struct inode *inode, struct file *fd)
spin_unlock_irqrestore(&dev->lock, flags);
DBG(dev, "printer_open returned %x\n", ret);
unlock_kernel();
mutex_unlock(&printer_mutex);
return ret;
}
@ -1346,7 +1347,7 @@ printer_unbind(struct usb_gadget *gadget)
set_gadget_data(gadget, NULL);
}
static int __init
static int __ref
printer_bind(struct usb_gadget *gadget)
{
struct printer_dev *dev;

View File

@ -12,6 +12,8 @@
* published by the Free Software Foundation.
*/
#define DEBUG
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
@ -23,6 +25,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@ -33,6 +36,7 @@
#include <plat/regs-usb-hsotg.h>
#include <mach/regs-sys.h>
#include <plat/udc-hs.h>
#include <plat/cpu.h>
#define DMA_ADDR_INVALID (~((dma_addr_t)0))
@ -91,7 +95,9 @@ struct s3c_hsotg_req;
* For periodic IN endpoints, we have fifo_size and fifo_load to try
* and keep track of the amount of data in the periodic FIFO for each
* of these as we don't have a status register that tells us how much
* is in each of them.
* is in each of them. (note, this may actually be useless information
* as in shared-fifo mode periodic in acts like a single-frame packet
* buffer than a fifo)
*/
struct s3c_hsotg_ep {
struct usb_ep ep;
@ -128,6 +134,7 @@ struct s3c_hsotg_ep {
* @regs: The memory area mapped for accessing registers.
* @regs_res: The resource that was allocated when claiming register space.
* @irq: The IRQ number we are using
* @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
* @debug_root: root directrory for debugfs.
* @debug_file: main status file for debugfs.
* @debug_fifo: FIFO status file for debugfs.
@ -145,6 +152,9 @@ struct s3c_hsotg {
void __iomem *regs;
struct resource *regs_res;
int irq;
struct clk *clk;
unsigned int dedicated_fifos:1;
struct dentry *debug_root;
struct dentry *debug_file;
@ -310,11 +320,11 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
hsotg->regs + S3C_GNPTXFSIZ);
*/
/* set FIFO sizes to 2048/0x1C0 */
/* set FIFO sizes to 2048/1024 */
writel(2048, hsotg->regs + S3C_GRXFSIZ);
writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) |
S3C_GNPTXFSIZ_NPTxFDep(0x1C0),
S3C_GNPTXFSIZ_NPTxFDep(1024),
hsotg->regs + S3C_GNPTXFSIZ);
/* arange all the rest of the TX FIFOs, as some versions of this
@ -464,7 +474,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
if (to_write == 0)
return 0;
if (periodic) {
if (periodic && !hsotg->dedicated_fifos) {
u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index));
int size_left;
int size_done;
@ -474,6 +484,14 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
/* if shared fifo, we cannot write anything until the
* previous data has been completely sent.
*/
if (hs_ep->fifo_load != 0) {
s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
return -ENOSPC;
}
dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n",
__func__, size_left,
hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size);
@ -494,6 +512,11 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
return -ENOSPC;
}
} else if (hsotg->dedicated_fifos && hs_ep->index != 0) {
can_write = readl(hsotg->regs + S3C_DTXFSTS(hs_ep->index));
can_write &= 0xffff;
can_write *= 4;
} else {
if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) {
dev_dbg(hsotg->dev,
@ -505,6 +528,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
}
can_write = S3C_GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts);
can_write *= 4; /* fifo size is in 32bit quantities. */
}
dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n",
@ -517,6 +541,17 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
if (can_write > 512)
can_write = 512;
/* limit the write to one max-packet size worth of data, but allow
* the transfer to return that it did not run out of fifo space
* doing it. */
if (to_write > hs_ep->ep.maxpacket) {
to_write = hs_ep->ep.maxpacket;
s3c_hsotg_en_gsint(hsotg,
periodic ? S3C_GINTSTS_PTxFEmp :
S3C_GINTSTS_NPTxFEmp);
}
/* see if we can write data */
if (to_write > can_write) {
@ -579,12 +614,10 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep)
maxsize = S3C_DxEPTSIZ_XferSize_LIMIT + 1;
maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1;
} else {
maxsize = 64+64;
if (hs_ep->dir_in) {
/* maxsize = S3C_DIEPTSIZ0_XferSize_LIMIT + 1; */
maxsize = 64+64+1;
maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1;
} else {
maxsize = 0x3f;
maxpkt = 2;
}
}
@ -1353,6 +1386,9 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
read_ptr = hs_req->req.actual;
max_req = hs_req->req.length - read_ptr;
dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n",
__func__, to_read, max_req, read_ptr, hs_req->req.length);
if (to_read > max_req) {
/* more data appeared than we where willing
* to deal with in this request.
@ -1362,9 +1398,6 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size)
WARN_ON_ONCE(1);
}
dev_dbg(hsotg->dev, "%s: read %d/%d, done %d/%d\n",
__func__, to_read, max_req, read_ptr, hs_req->req.length);
hs_ep->total_data += to_read;
hs_req->req.actual += to_read;
to_read = DIV_ROUND_UP(to_read, 4);
@ -1433,9 +1466,11 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg,
static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
int epnum, bool was_setup)
{
u32 epsize = readl(hsotg->regs + S3C_DOEPTSIZ(epnum));
struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum];
struct s3c_hsotg_req *hs_req = hs_ep->req;
struct usb_request *req = &hs_req->req;
unsigned size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
int result = 0;
if (!hs_req) {
@ -1444,9 +1479,7 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
}
if (using_dma(hsotg)) {
u32 epsize = readl(hsotg->regs + S3C_DOEPTSIZ(epnum));
unsigned size_done;
unsigned size_left;
/* Calculate the size of the transfer by checking how much
* is left in the endpoint size register and then working it
@ -1456,14 +1489,18 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
* so may overshoot/undershoot the transfer.
*/
size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
size_done = hs_ep->size_loaded - size_left;
size_done += hs_ep->last_load;
req->actual = size_done;
}
/* if there is more request to do, schedule new transfer */
if (req->actual < req->length && size_left == 0) {
s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true);
return;
}
if (req->actual < req->length && req->short_not_ok) {
dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n",
__func__, req->actual, req->length);
@ -1758,7 +1795,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
if (dir_in) {
s3c_hsotg_complete_in(hsotg, hs_ep);
if (idx == 0)
if (idx == 0 && !hs_ep->req)
s3c_hsotg_enqueue_setup(hsotg);
} else if (using_dma(hsotg)) {
/* We're using DMA, we need to fire an OutDone here
@ -1818,6 +1855,15 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
__func__, idx);
clear |= S3C_DIEPMSK_INTknEPMisMsk;
}
/* FIFO has space or is empty (see GAHBCFG) */
if (hsotg->dedicated_fifos &&
ints & S3C_DIEPMSK_TxFIFOEmpty) {
dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",
__func__, idx);
s3c_hsotg_trytx(hsotg, hs_ep);
clear |= S3C_DIEPMSK_TxFIFOEmpty;
}
}
writel(clear, hsotg->regs + epint_reg);
@ -2071,17 +2117,12 @@ irq_retry:
kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true);
/* it seems after a reset we can end up with a situation
* where the TXFIFO still has data in it... try flushing
* it to remove anything that may still be in it.
* where the TXFIFO still has data in it... the docs
* suggest resetting all the fifos, so use the init_fifo
* code to relayout and flush the fifos.
*/
if (1) {
writel(S3C_GRSTCTL_TxFNum(0) | S3C_GRSTCTL_TxFFlsh,
hsotg->regs + S3C_GRSTCTL);
dev_info(hsotg->dev, "GNPTXSTS=%08x\n",
readl(hsotg->regs + S3C_GNPTXSTS));
}
s3c_hsotg_init_fifo(hsotg);
s3c_hsotg_enqueue_setup(hsotg);
@ -2274,6 +2315,12 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
break;
}
/* if the hardware has dedicated fifos, we must give each IN EP
* a unique tx-fifo even if it is non-periodic.
*/
if (dir_in && hsotg->dedicated_fifos)
epctrl |= S3C_DxEPCTL_TxFNum(index);
/* for non control endpoints, set PID to D0 */
if (index)
epctrl |= S3C_DxEPCTL_SetD0PID;
@ -2563,7 +2610,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk |
S3C_DIEPMSK_INTknEPMisMsk |
S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk,
S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk |
((hsotg->dedicated_fifos) ? S3C_DIEPMSK_TxFIFOEmpty : 0),
hsotg->regs + S3C_DIEPMSK);
/* don't need XferCompl, we get that from RXFIFO in slave mode. In
@ -2732,7 +2780,7 @@ static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg,
*/
ptxfifo = readl(hsotg->regs + S3C_DPTXFSIZn(epnum));
hs_ep->fifo_size = S3C_DPTXFSIZn_DPTxFSize_GET(ptxfifo);
hs_ep->fifo_size = S3C_DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4;
/* if we're using dma, we need to set the next-endpoint pointer
* to be something valid.
@ -2753,13 +2801,33 @@ static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg,
*/
static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg)
{
u32 osc;
struct clk *xusbxti;
u32 pwr, osc;
writel(0, S3C_PHYPWR);
pwr = readl(S3C_PHYPWR);
pwr &= ~0x19;
writel(pwr, S3C_PHYPWR);
mdelay(1);
osc = hsotg->plat->is_osc ? S3C_PHYCLK_EXT_OSC : 0;
xusbxti = clk_get(hsotg->dev, "xusbxti");
if (xusbxti && !IS_ERR(xusbxti)) {
switch (clk_get_rate(xusbxti)) {
case 12*MHZ:
osc |= S3C_PHYCLK_CLKSEL_12M;
break;
case 24*MHZ:
osc |= S3C_PHYCLK_CLKSEL_24M;
break;
default:
case 48*MHZ:
/* default reference clock */
break;
}
clk_put(xusbxti);
}
writel(osc | 0x10, S3C_PHYCLK);
/* issue a full set of resets to the otg and core */
@ -2772,6 +2840,8 @@ static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg)
static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
{
u32 cfg4;
/* unmask subset of endpoint interrupts */
writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk |
@ -2807,6 +2877,14 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0,
hsotg->regs + S3C_GAHBCFG);
/* check hardware configuration */
cfg4 = readl(hsotg->regs + 0x50);
hsotg->dedicated_fifos = (cfg4 >> 25) & 1;
dev_info(hsotg->dev, "%s fifos\n",
hsotg->dedicated_fifos ? "dedicated" : "shared");
}
static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)
@ -3181,13 +3259,20 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
hsotg->dev = dev;
hsotg->plat = plat;
hsotg->clk = clk_get(&pdev->dev, "otg");
if (IS_ERR(hsotg->clk)) {
dev_err(dev, "cannot get otg clock\n");
ret = -EINVAL;
goto err_mem;
}
platform_set_drvdata(pdev, hsotg);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(dev, "cannot find register resource 0\n");
ret = -EINVAL;
goto err_mem;
goto err_clk;
}
hsotg->regs_res = request_mem_region(res->start, resource_size(res),
@ -3195,7 +3280,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
if (!hsotg->regs_res) {
dev_err(dev, "cannot reserve registers\n");
ret = -ENOENT;
goto err_mem;
goto err_clk;
}
hsotg->regs = ioremap(res->start, resource_size(res));
@ -3248,6 +3333,8 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
/* reset the system */
clk_enable(hsotg->clk);
s3c_hsotg_gate(pdev, true);
s3c_hsotg_otgreset(hsotg);
@ -3271,7 +3358,8 @@ err_regs:
err_regs_res:
release_resource(hsotg->regs_res);
kfree(hsotg->regs_res);
err_clk:
clk_put(hsotg->clk);
err_mem:
kfree(hsotg);
return ret;
@ -3293,6 +3381,9 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
s3c_hsotg_gate(pdev, false);
clk_disable(hsotg->clk);
clk_put(hsotg->clk);
kfree(hsotg);
return 0;
}

View File

@ -137,7 +137,7 @@ MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
/*-------------------------------------------------------------------------*/
static int __init serial_bind_config(struct usb_configuration *c)
static int __ref serial_bind_config(struct usb_configuration *c)
{
unsigned i;
int status = 0;
@ -161,7 +161,7 @@ static struct usb_configuration serial_config_driver = {
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
};
static int __init gs_bind(struct usb_composite_dev *cdev)
static int __ref gs_bind(struct usb_composite_dev *cdev)
{
int gcnum;
struct usb_gadget *gadget = cdev->gadget;

View File

@ -57,10 +57,12 @@
#include <asm/unaligned.h>
/* Thanks to NetChip Technologies for donating this product ID.
/*
* Thanks to NetChip Technologies for donating this product ID.
*
* DO NOT REUSE THESE IDs with any other driver!! Ever!!
* Instead: allocate your own, using normal USB-IF procedures. */
* Instead: allocate your own, using normal USB-IF procedures.
*/
#define FSG_VENDOR_ID 0x0525 /* NetChip */
#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */
@ -84,14 +86,27 @@
#define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args)
#define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args)
/* Keep those macros in sync with thos in
* include/linux/ubs/composite.h or else GCC will complain. If they
/*
* Keep those macros in sync with those in
* include/linux/usb/composite.h or else GCC will complain. If they
* are identical (the same names of arguments, white spaces in the
* same places) GCC will allow redefinition otherwise (even if some
* white space is removed or added) warning will be issued. No
* checking if those symbols is defined is performed because warning
* is desired when those macros were defined by someone else to mean
* something else. */
* white space is removed or added) warning will be issued.
*
* Those macros are needed here because File Storage Gadget does not
* include the composite.h header. For composite gadgets those macros
* are redundant since composite.h is included any way.
*
* One could check whether those macros are already defined (which
* would indicate composite.h had been included) or not (which would
* indicate we were in FSG) but this is not done because a warning is
* desired if definitions here differ from the ones in composite.h.
*
* We want the definitions to match and be the same in File Storage
* Gadget as well as Mass Storage Function (and so composite gadgets
* using MSF). If someone changes them in composite.h it will produce
* a warning in this file when building MSF.
*/
#define DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args)
#define VDBG(d, fmt, args...) dev_vdbg(&(d)->gadget->dev , fmt , ## args)
#define ERROR(d, fmt, args...) dev_err(&(d)->gadget->dev , fmt , ## args)
@ -269,6 +284,7 @@ struct fsg_lun {
unsigned int prevent_medium_removal:1;
unsigned int registered:1;
unsigned int info_valid:1;
unsigned int nofua:1;
u32 sense_data;
u32 sense_data_info;
@ -313,9 +329,11 @@ struct fsg_buffhd {
enum fsg_buffer_state state;
struct fsg_buffhd *next;
/* The NetChip 2280 is faster, and handles some protocol faults
/*
* The NetChip 2280 is faster, and handles some protocol faults
* better, if we don't submit any short bulk-out read requests.
* So we will record the intended request length here. */
* So we will record the intended request length here.
*/
unsigned int bulk_out_intended_length;
struct usb_request *inreq;
@ -395,8 +413,10 @@ fsg_intf_desc = {
.iInterface = FSG_STRING_INTERFACE,
};
/* Three full-speed endpoint descriptors: bulk-in, bulk-out,
* and interrupt-in. */
/*
* Three full-speed endpoint descriptors: bulk-in, bulk-out, and
* interrupt-in.
*/
static struct usb_endpoint_descriptor
fsg_fs_bulk_in_desc = {
@ -459,7 +479,7 @@ static struct usb_descriptor_header *fsg_fs_function[] = {
*
* That means alternate endpoint descriptors (bigger packets)
* and a "device qualifier" ... plus more construction options
* for the config descriptor.
* for the configuration descriptor.
*/
static struct usb_endpoint_descriptor
fsg_hs_bulk_in_desc = {
@ -547,8 +567,10 @@ static struct usb_gadget_strings fsg_stringtab = {
/*-------------------------------------------------------------------------*/
/* If the next two routines are called while the gadget is registered,
* the caller must own fsg->filesem for writing. */
/*
* If the next two routines are called while the gadget is registered,
* the caller must own fsg->filesem for writing.
*/
static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
{
@ -587,8 +609,10 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename)
goto out;
}
/* If we can't read the file, it's no good.
* If we can't write the file, use it read-only. */
/*
* If we can't read the file, it's no good.
* If we can't write the file, use it read-only.
*/
if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) {
LINFO(curlun, "file not readable: %s\n", filename);
goto out;
@ -646,8 +670,10 @@ static void fsg_lun_close(struct fsg_lun *curlun)
/*-------------------------------------------------------------------------*/
/* Sync the file data, don't bother with the metadata.
* This code was copied from fs/buffer.c:sys_fdatasync(). */
/*
* Sync the file data, don't bother with the metadata.
* This code was copied from fs/buffer.c:sys_fdatasync().
*/
static int fsg_lun_fsync_sub(struct fsg_lun *curlun)
{
struct file *filp = curlun->filp;
@ -689,6 +715,14 @@ static ssize_t fsg_show_ro(struct device *dev, struct device_attribute *attr,
: curlun->initially_ro);
}
static ssize_t fsg_show_nofua(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
return sprintf(buf, "%u\n", curlun->nofua);
}
static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
char *buf)
{
@ -723,26 +757,47 @@ static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
ssize_t rc = count;
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
struct rw_semaphore *filesem = dev_get_drvdata(dev);
int i;
unsigned long ro;
if (sscanf(buf, "%d", &i) != 1)
if (strict_strtoul(buf, 2, &ro))
return -EINVAL;
/* Allow the write-enable status to change only while the backing file
* is closed. */
/*
* Allow the write-enable status to change only while the
* backing file is closed.
*/
down_read(filesem);
if (fsg_lun_is_open(curlun)) {
LDBG(curlun, "read-only status change prevented\n");
rc = -EBUSY;
} else {
curlun->ro = !!i;
curlun->initially_ro = !!i;
curlun->ro = ro;
curlun->initially_ro = ro;
LDBG(curlun, "read-only status set to %d\n", curlun->ro);
}
up_read(filesem);
return rc;
}
static ssize_t fsg_store_nofua(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct fsg_lun *curlun = fsg_lun_from_dev(dev);
unsigned long nofua;
if (strict_strtoul(buf, 2, &nofua))
return -EINVAL;
/* Sync data when switching from async mode to sync */
if (!nofua && curlun->nofua)
fsg_lun_fsync_sub(curlun);
curlun->nofua = nofua;
return count;
}
static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{

View File

@ -704,17 +704,6 @@ static char *host_addr;
module_param(host_addr, charp, S_IRUGO);
MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
static u8 __init nibble(unsigned char c)
{
if (isdigit(c))
return c - '0';
c = toupper(c);
if (isxdigit(c))
return 10 + c - 'A';
return 0;
}
static int get_ether_addr(const char *str, u8 *dev_addr)
{
if (str) {
@ -725,8 +714,8 @@ static int get_ether_addr(const char *str, u8 *dev_addr)
if ((*str == '.') || (*str == ':'))
str++;
num = nibble(*str++) << 4;
num |= (nibble(*str++));
num = hex_to_bin(*str++) << 4;
num |= hex_to_bin(*str++);
dev_addr [i] = num;
}
if (is_valid_ether_addr(dev_addr))

View File

@ -18,6 +18,7 @@
/* #define VERBOSE_DEBUG */
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/delay.h>

View File

@ -308,7 +308,7 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
* USB configuration
*/
static int __init
static int __ref
webcam_config_bind(struct usb_configuration *c)
{
return uvc_bind_config(c, uvc_control_cls, uvc_fs_streaming_cls,
@ -330,7 +330,7 @@ webcam_unbind(struct usb_composite_dev *cdev)
return 0;
}
static int __init
static int __ref
webcam_bind(struct usb_composite_dev *cdev)
{
int ret;

View File

@ -264,7 +264,7 @@ static void zero_resume(struct usb_composite_dev *cdev)
/*-------------------------------------------------------------------------*/
static int __init zero_bind(struct usb_composite_dev *cdev)
static int __ref zero_bind(struct usb_composite_dev *cdev)
{
int gcnum;
struct usb_gadget *gadget = cdev->gadget;

View File

@ -72,8 +72,9 @@ config USB_EHCI_ROOT_HUB_TT
from ARC, and has since changed hands a few times.
config USB_EHCI_TT_NEWSCHED
bool "Improved Transaction Translator scheduling (EXPERIMENTAL)"
depends on USB_EHCI_HCD && EXPERIMENTAL
bool "Improved Transaction Translator scheduling"
depends on USB_EHCI_HCD
default y
---help---
This changes the periodic scheduling code to fill more of the low
and full speed bandwidth available from the Transaction Translator
@ -84,9 +85,11 @@ config USB_EHCI_TT_NEWSCHED
If you have multiple periodic low/fullspeed devices connected to a
highspeed USB hub which is connected to a highspeed USB Host
Controller, and some of those devices will not work correctly
(possibly due to "ENOSPC" or "-28" errors), say Y.
(possibly due to "ENOSPC" or "-28" errors), say Y. Conversely, if
you have only one such device and it doesn't work, you could try
saying N.
If unsure, say N.
If unsure, say Y.
config USB_EHCI_BIG_ENDIAN_MMIO
bool

View File

@ -228,7 +228,7 @@ static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
* the root hub is either suspended or stopped.
*/
spin_lock_irqsave(&ehci->lock, flags);
ehci_prepare_ports_for_controller_suspend(ehci);
ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
(void)ehci_readl(ehci, &ehci->regs->intr_enable);

View File

@ -98,13 +98,18 @@ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
} else {
ehci_dbg (ehci,
"%s hcc_params %04x thresh %d uframes %s%s%s\n",
"%s hcc_params %04x thresh %d uframes %s%s%s%s%s%s%s\n",
label,
params,
HCC_ISOC_THRES(params),
HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
HCC_CANPARK(params) ? " park" : "",
HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
HCC_64BIT_ADDR(params) ? " 64 bit addr" : "",
HCC_LPM(params) ? " LPM" : "",
HCC_PER_PORT_CHANGE_EVENT(params) ? " ppce" : "",
HCC_HW_PREFETCH(params) ? " hw prefetch" : "",
HCC_32FRAME_PERIODIC_LIST(params) ?
" 32 peridic list" : "");
}
}
#else
@ -191,8 +196,9 @@ static int __maybe_unused
dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
{
return scnprintf (buf, len,
"%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s",
"%s%sstatus %04x%s%s%s%s%s%s%s%s%s%s%s",
label, label [0] ? " " : "", status,
(status & STS_PPCE_MASK) ? " PPCE" : "",
(status & STS_ASS) ? " Async" : "",
(status & STS_PSS) ? " Periodic" : "",
(status & STS_RECL) ? " Recl" : "",
@ -210,8 +216,9 @@ static int __maybe_unused
dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
{
return scnprintf (buf, len,
"%s%sintrenable %02x%s%s%s%s%s%s",
"%s%sintrenable %02x%s%s%s%s%s%s%s",
label, label [0] ? " " : "", enable,
(enable & STS_PPCE_MASK) ? " PPCE" : "",
(enable & STS_IAA) ? " IAA" : "",
(enable & STS_FATAL) ? " FATAL" : "",
(enable & STS_FLR) ? " FLR" : "",
@ -228,9 +235,15 @@ static int
dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
{
return scnprintf (buf, len,
"%s%scommand %06x %s=%d ithresh=%d%s%s%s%s period=%s%s %s",
"%s%scommand %07x %s%s%s%s%s%s=%d ithresh=%d%s%s%s%s "
"period=%s%s %s",
label, label [0] ? " " : "", command,
(command & CMD_PARK) ? "park" : "(park)",
(command & CMD_HIRD) ? " HIRD" : "",
(command & CMD_PPCEE) ? " PPCEE" : "",
(command & CMD_FSP) ? " FSP" : "",
(command & CMD_ASPE) ? " ASPE" : "",
(command & CMD_PSPE) ? " PSPE" : "",
(command & CMD_PARK) ? " park" : "(park)",
CMD_PARK_CNT (command),
(command >> 16) & 0x3f,
(command & CMD_LRESET) ? " LReset" : "",
@ -257,11 +270,22 @@ dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
}
return scnprintf (buf, len,
"%s%sport %d status %06x%s%s sig=%s%s%s%s%s%s%s%s%s%s",
"%s%sport:%d status %06x %d %s%s%s%s%s%s "
"sig=%s%s%s%s%s%s%s%s%s%s%s",
label, label [0] ? " " : "", port, status,
status>>25,/*device address */
(status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_ACK ?
" ACK" : "",
(status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_NYET ?
" NYET" : "",
(status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_STALL ?
" STALL" : "",
(status & PORT_SSTS)>>23 == PORTSC_SUSPEND_STS_ERR ?
" ERR" : "",
(status & PORT_POWER) ? " POWER" : "",
(status & PORT_OWNER) ? " OWNER" : "",
sig,
(status & PORT_LPM) ? " LPM" : "",
(status & PORT_RESET) ? " RESET" : "",
(status & PORT_SUSPEND) ? " SUSPEND" : "",
(status & PORT_RESUME) ? " RESUME" : "",
@ -330,6 +354,13 @@ static int debug_async_open(struct inode *, struct file *);
static int debug_periodic_open(struct inode *, struct file *);
static int debug_registers_open(struct inode *, struct file *);
static int debug_async_open(struct inode *, struct file *);
static int debug_lpm_open(struct inode *, struct file *);
static ssize_t debug_lpm_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos);
static ssize_t debug_lpm_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos);
static int debug_lpm_close(struct inode *inode, struct file *file);
static ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
static int debug_close(struct inode *, struct file *);
@ -351,6 +382,13 @@ static const struct file_operations debug_registers_fops = {
.read = debug_output,
.release = debug_close,
};
static const struct file_operations debug_lpm_fops = {
.owner = THIS_MODULE,
.open = debug_lpm_open,
.read = debug_lpm_read,
.write = debug_lpm_write,
.release = debug_lpm_close,
};
static struct dentry *ehci_debug_root;
@ -674,7 +712,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
spin_lock_irqsave (&ehci->lock, flags);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
if (!HCD_HW_ACCESSIBLE(hcd)) {
size = scnprintf (next, size,
"bus %s, device %s\n"
"%s\n"
@ -917,51 +955,127 @@ static int debug_registers_open(struct inode *inode, struct file *file)
return file->private_data ? 0 : -ENOMEM;
}
static int debug_lpm_open(struct inode *inode, struct file *file)
{
file->private_data = inode->i_private;
return 0;
}
static int debug_lpm_close(struct inode *inode, struct file *file)
{
return 0;
}
static ssize_t debug_lpm_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
/* TODO: show lpm stats */
return 0;
}
static ssize_t debug_lpm_write(struct file *file, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
char buf[50];
size_t len;
u32 temp;
unsigned long port;
u32 __iomem *portsc ;
u32 params;
hcd = bus_to_hcd(file->private_data);
ehci = hcd_to_ehci(hcd);
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (len > 0 && buf[len - 1] == '\n')
buf[len - 1] = '\0';
if (strncmp(buf, "enable", 5) == 0) {
if (strict_strtoul(buf + 7, 10, &port))
return -EINVAL;
params = ehci_readl(ehci, &ehci->caps->hcs_params);
if (port > HCS_N_PORTS(params)) {
ehci_dbg(ehci, "ERR: LPM on bad port %lu\n", port);
return -ENODEV;
}
portsc = &ehci->regs->port_status[port-1];
temp = ehci_readl(ehci, portsc);
if (!(temp & PORT_DEV_ADDR)) {
ehci_dbg(ehci, "LPM: no device attached\n");
return -ENODEV;
}
temp |= PORT_LPM;
ehci_writel(ehci, temp, portsc);
printk(KERN_INFO "force enable LPM for port %lu\n", port);
} else if (strncmp(buf, "hird=", 5) == 0) {
unsigned long hird;
if (strict_strtoul(buf + 5, 16, &hird))
return -EINVAL;
printk(KERN_INFO "setting hird %s %lu\n", buf + 6, hird);
temp = ehci_readl(ehci, &ehci->regs->command);
temp &= ~CMD_HIRD;
temp |= hird << 24;
ehci_writel(ehci, temp, &ehci->regs->command);
} else if (strncmp(buf, "disable", 7) == 0) {
if (strict_strtoul(buf + 8, 10, &port))
return -EINVAL;
params = ehci_readl(ehci, &ehci->caps->hcs_params);
if (port > HCS_N_PORTS(params)) {
ehci_dbg(ehci, "ERR: LPM off bad port %lu\n", port);
return -ENODEV;
}
portsc = &ehci->regs->port_status[port-1];
temp = ehci_readl(ehci, portsc);
if (!(temp & PORT_DEV_ADDR)) {
ehci_dbg(ehci, "ERR: no device attached\n");
return -ENODEV;
}
temp &= ~PORT_LPM;
ehci_writel(ehci, temp, portsc);
printk(KERN_INFO "disabled LPM for port %lu\n", port);
} else
return -EOPNOTSUPP;
return count;
}
static inline void create_debug_files (struct ehci_hcd *ehci)
{
struct usb_bus *bus = &ehci_to_hcd(ehci)->self;
ehci->debug_dir = debugfs_create_dir(bus->bus_name, ehci_debug_root);
if (!ehci->debug_dir)
goto dir_error;
return;
ehci->debug_async = debugfs_create_file("async", S_IRUGO,
ehci->debug_dir, bus,
&debug_async_fops);
if (!ehci->debug_async)
goto async_error;
if (!debugfs_create_file("async", S_IRUGO, ehci->debug_dir, bus,
&debug_async_fops))
goto file_error;
ehci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
ehci->debug_dir, bus,
&debug_periodic_fops);
if (!ehci->debug_periodic)
goto periodic_error;
if (!debugfs_create_file("periodic", S_IRUGO, ehci->debug_dir, bus,
&debug_periodic_fops))
goto file_error;
if (!debugfs_create_file("registers", S_IRUGO, ehci->debug_dir, bus,
&debug_registers_fops))
goto file_error;
if (!debugfs_create_file("lpm", S_IRUGO|S_IWUGO, ehci->debug_dir, bus,
&debug_lpm_fops))
goto file_error;
ehci->debug_registers = debugfs_create_file("registers", S_IRUGO,
ehci->debug_dir, bus,
&debug_registers_fops);
if (!ehci->debug_registers)
goto registers_error;
return;
registers_error:
debugfs_remove(ehci->debug_periodic);
periodic_error:
debugfs_remove(ehci->debug_async);
async_error:
debugfs_remove(ehci->debug_dir);
dir_error:
ehci->debug_periodic = NULL;
ehci->debug_async = NULL;
ehci->debug_dir = NULL;
file_error:
debugfs_remove_recursive(ehci->debug_dir);
}
static inline void remove_debug_files (struct ehci_hcd *ehci)
{
debugfs_remove(ehci->debug_registers);
debugfs_remove(ehci->debug_periodic);
debugfs_remove(ehci->debug_async);
debugfs_remove(ehci->debug_dir);
debugfs_remove_recursive(ehci->debug_dir);
}
#endif /* STUB_DEBUG_FILES */

View File

@ -313,7 +313,8 @@ static int ehci_fsl_drv_suspend(struct device *dev)
struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
void __iomem *non_ehci = hcd->regs;
ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd));
ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd),
device_may_wakeup(dev));
if (!fsl_deep_sleep())
return 0;

View File

@ -36,6 +36,7 @@
#include <linux/dma-mapping.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@ -78,7 +79,13 @@ static const char hcd_name [] = "ehci_hcd";
#define EHCI_TUNE_RL_TT 0
#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
#define EHCI_TUNE_MULT_TT 1
#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
/*
* Some drivers think it's safe to schedule isochronous transfers more than
* 256 ms into the future (partly as a result of an old bug in the scheduling
* code). In an attempt to avoid trouble, we will use a minimum scheduling
* length of 512 frames instead of 256.
*/
#define EHCI_TUNE_FLS 1 /* (medium) 512-frame schedule */
#define EHCI_IAA_MSECS 10 /* arbitrary */
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
@ -100,6 +107,11 @@ static int ignore_oc = 0;
module_param (ignore_oc, bool, S_IRUGO);
MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
/* for link power management(LPM) feature */
static unsigned int hird;
module_param(hird, int, S_IRUGO);
MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us\n");
#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
/*-------------------------------------------------------------------------*/
@ -304,6 +316,7 @@ static void end_unlink_async(struct ehci_hcd *ehci);
static void ehci_work(struct ehci_hcd *ehci);
#include "ehci-hub.c"
#include "ehci-lpm.c"
#include "ehci-mem.c"
#include "ehci-q.c"
#include "ehci-sched.c"
@ -577,6 +590,11 @@ static int ehci_init(struct usb_hcd *hcd)
if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
log2_irq_thresh = 0;
temp = 1 << (16 + log2_irq_thresh);
if (HCC_PER_PORT_CHANGE_EVENT(hcc_params)) {
ehci->has_ppcd = 1;
ehci_dbg(ehci, "enable per-port change event\n");
temp |= CMD_PPCEE;
}
if (HCC_CANPARK(hcc_params)) {
/* HW default park == 3, on hardware that supports it (like
* NVidia and ALI silicon), maximizes throughput on the async
@ -603,10 +621,22 @@ static int ehci_init(struct usb_hcd *hcd)
default: BUG();
}
}
if (HCC_LPM(hcc_params)) {
/* support link power management EHCI 1.1 addendum */
ehci_dbg(ehci, "support lpm\n");
ehci->has_lpm = 1;
if (hird > 0xf) {
ehci_dbg(ehci, "hird %d invalid, use default 0",
hird);
hird = 0;
}
temp |= hird << 24;
}
ehci->command = temp;
/* Accept arbitrarily long scatter-gather lists */
hcd->self.sg_tablesize = ~0;
if (!(hcd->driver->flags & HCD_LOCAL_MEM))
hcd->self.sg_tablesize = ~0;
return 0;
}
@ -619,7 +649,6 @@ static int ehci_run (struct usb_hcd *hcd)
u32 hcc_params;
hcd->uses_new_polling = 1;
hcd->poll_rh = 0;
/* EHCI spec section 4.1 */
if ((retval = ehci_reset(ehci)) != 0) {
@ -764,6 +793,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* remote wakeup [4.3.1] */
if (status & STS_PCD) {
unsigned i = HCS_N_PORTS (ehci->hcs_params);
u32 ppcd = 0;
/* kick root hub later */
pcd_status = status;
@ -772,9 +802,18 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
if (!(cmd & CMD_RUN))
usb_hcd_resume_root_hub(hcd);
/* get per-port change detect bits */
if (ehci->has_ppcd)
ppcd = status >> 16;
while (i--) {
int pstatus = ehci_readl(ehci,
&ehci->regs->port_status [i]);
int pstatus;
/* leverage per-port change bits feature */
if (ehci->has_ppcd && !(ppcd & (1 << i)))
continue;
pstatus = ehci_readl(ehci,
&ehci->regs->port_status[i]);
if (pstatus & PORT_OWNER)
continue;

View File

@ -107,7 +107,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
}
static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
bool suspending)
bool suspending, bool do_wakeup)
{
int port;
u32 temp;
@ -117,8 +117,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
* when the controller is suspended or resumed. In all other
* cases they don't need to be changed.
*/
if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup ||
device_may_wakeup(ehci_to_hcd(ehci)->self.controller))
if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup)
return;
/* clear phy low-power mode before changing wakeup flags */
@ -167,6 +166,10 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg);
}
}
/* Does the root hub have a port wakeup pending? */
if (!suspending && (ehci_readl(ehci, &ehci->regs->status) & STS_PCD))
usb_hcd_resume_root_hub(ehci_to_hcd(ehci));
}
static int ehci_bus_suspend (struct usb_hcd *hcd)
@ -316,7 +319,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
if (time_before (jiffies, ehci->next_statechange))
msleep(5);
spin_lock_irq (&ehci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
if (!HCD_HW_ACCESSIBLE(hcd)) {
spin_unlock_irq(&ehci->lock);
return -ESHUTDOWN;
}
@ -603,6 +606,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
u32 mask;
int ports, i, retval = 1;
unsigned long flags;
u32 ppcd = 0;
/* if !USB_SUSPEND, root hub timers won't get shut down ... */
if (!HC_IS_RUNNING(hcd->state))
@ -632,7 +636,15 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
/* port N changes (bit N)? */
spin_lock_irqsave (&ehci->lock, flags);
/* get per-port change detect bits */
if (ehci->has_ppcd)
ppcd = ehci_readl(ehci, &ehci->regs->status) >> 16;
for (i = 0; i < ports; i++) {
/* leverage per-port change bits feature */
if (ehci->has_ppcd && !(ppcd & (1 << i)))
continue;
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
/*
@ -790,6 +802,11 @@ static int ehci_hub_control (
status_reg);
break;
case USB_PORT_FEAT_C_CONNECTION:
if (ehci->has_lpm) {
/* clear PORTSC bits on disconnect */
temp &= ~PORT_LPM;
temp &= ~PORT_DEV_ADDR;
}
ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
status_reg);
break;

View File

@ -0,0 +1,83 @@
/* ehci-lpm.c EHCI HCD LPM support code
* Copyright (c) 2008 - 2010, Intel Corporation.
* Author: Jacob Pan <jacob.jun.pan@intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* this file is part of ehci-hcd.c */
static int ehci_lpm_set_da(struct ehci_hcd *ehci, int dev_addr, int port_num)
{
u32 __iomem portsc;
ehci_dbg(ehci, "set dev address %d for port %d\n", dev_addr, port_num);
if (port_num > HCS_N_PORTS(ehci->hcs_params)) {
ehci_dbg(ehci, "invalid port number %d\n", port_num);
return -ENODEV;
}
portsc = ehci_readl(ehci, &ehci->regs->port_status[port_num-1]);
portsc &= ~PORT_DEV_ADDR;
portsc |= dev_addr<<25;
ehci_writel(ehci, portsc, &ehci->regs->port_status[port_num-1]);
return 0;
}
/*
* this function is used to check if the device support LPM
* if yes, mark the PORTSC register with PORT_LPM bit
*/
static int ehci_lpm_check(struct ehci_hcd *ehci, int port)
{
u32 __iomem *portsc ;
u32 val32;
int retval;
portsc = &ehci->regs->port_status[port-1];
val32 = ehci_readl(ehci, portsc);
if (!(val32 & PORT_DEV_ADDR)) {
ehci_dbg(ehci, "LPM: no device attached\n");
return -ENODEV;
}
val32 |= PORT_LPM;
ehci_writel(ehci, val32, portsc);
msleep(5);
val32 |= PORT_SUSPEND;
ehci_dbg(ehci, "Sending LPM 0x%08x to port %d\n", val32, port);
ehci_writel(ehci, val32, portsc);
/* wait for ACK */
msleep(10);
retval = handshake(ehci, &ehci->regs->port_status[port-1], PORT_SSTS,
PORTSC_SUSPEND_STS_ACK, 125);
dbg_port(ehci, "LPM", port, val32);
if (retval != -ETIMEDOUT) {
ehci_dbg(ehci, "LPM: device ACK for LPM\n");
val32 |= PORT_LPM;
/*
* now device should be in L1 sleep, let's wake up the device
* so that we can complete enumeration.
*/
ehci_writel(ehci, val32, portsc);
msleep(10);
val32 |= PORT_RESUME;
ehci_writel(ehci, val32, portsc);
} else {
ehci_dbg(ehci, "LPM: device does not ACK, disable LPM %d\n",
retval);
val32 &= ~PORT_LPM;
retval = -ETIMEDOUT;
ehci_writel(ehci, val32, portsc);
}
return retval;
}

View File

@ -38,6 +38,7 @@
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/usb/ulpi.h>
#include <plat/usb.h>
/*
@ -236,6 +237,35 @@ static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, u8 tll_channel_mask)
/*-------------------------------------------------------------------------*/
static void omap_ehci_soft_phy_reset(struct ehci_hcd_omap *omap, u8 port)
{
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
unsigned reg = 0;
reg = ULPI_FUNC_CTRL_RESET
/* FUNCTION_CTRL_SET register */
| (ULPI_SET(ULPI_FUNC_CTRL) << EHCI_INSNREG05_ULPI_REGADD_SHIFT)
/* Write */
| (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT)
/* PORTn */
| ((port + 1) << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT)
/* start ULPI access*/
| (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT);
ehci_omap_writel(omap->ehci_base, EHCI_INSNREG05_ULPI, reg);
/* Wait for ULPI access completion */
while ((ehci_omap_readl(omap->ehci_base, EHCI_INSNREG05_ULPI)
& (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) {
cpu_relax();
if (time_after(jiffies, timeout)) {
dev_dbg(omap->dev, "phy reset operation timed out\n");
break;
}
}
}
/* omap_start_ehc
* - Start the TI USBHOST controller
*/
@ -425,6 +455,12 @@ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd)
gpio_set_value(omap->reset_gpio_port[1], 1);
}
/* Soft reset the PHY using PHY reset command over ULPI */
if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)
omap_ehci_soft_phy_reset(omap, 0);
if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)
omap_ehci_soft_phy_reset(omap, 1);
return 0;
err_sys_status:

View File

@ -114,6 +114,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
break;
case PCI_VENDOR_ID_INTEL:
ehci->need_io_watchdog = 0;
ehci->fs_i_thresh = 1;
if (pdev->device == 0x27cc) {
ehci->broken_periodic = 1;
ehci_info(ehci, "using broken periodic workaround\n");
@ -277,7 +278,7 @@ done:
* Also they depend on separate root hub suspend/resume.
*/
static int ehci_pci_suspend(struct usb_hcd *hcd)
static int ehci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
unsigned long flags;
@ -291,7 +292,7 @@ static int ehci_pci_suspend(struct usb_hcd *hcd)
* the root hub is either suspended or stopped.
*/
spin_lock_irqsave (&ehci->lock, flags);
ehci_prepare_ports_for_controller_suspend(ehci);
ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup);
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
@ -361,6 +362,22 @@ static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
}
#endif
static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int rc = 0;
if (!udev->parent) /* udev is root hub itself, impossible */
rc = -1;
/* we only support lpm device connected to root hub yet */
if (ehci->has_lpm && !udev->parent->parent) {
rc = ehci_lpm_set_da(ehci, udev->devnum, udev->portnum);
if (!rc)
rc = ehci_lpm_check(ehci, udev->portnum);
}
return rc;
}
static const struct hc_driver ehci_pci_hc_driver = {
.description = hcd_name,
.product_desc = "EHCI Host Controller",
@ -407,6 +424,11 @@ static const struct hc_driver ehci_pci_hc_driver = {
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
/*
* call back when device connected and addressed
*/
.update_device = ehci_update_device,
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};

View File

@ -1126,8 +1126,7 @@ submit_async (
#endif
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags))) {
if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) {
rc = -ESHUTDOWN;
goto done;
}

View File

@ -880,8 +880,7 @@ static int intr_submit (
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags))) {
if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) {
status = -ESHUTDOWN;
goto done_not_linked;
}
@ -1075,15 +1074,6 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
if (stream->ep)
stream->ep->hcpriv = NULL;
if (stream->rescheduled) {
ehci_info (ehci, "ep%d%s-iso rescheduled "
"%lu times in %lu seconds\n",
stream->bEndpointAddress, is_in ? "in" : "out",
stream->rescheduled,
((jiffies - stream->start)/HZ)
);
}
kfree(stream);
}
}
@ -1396,30 +1386,25 @@ iso_stream_schedule (
struct ehci_iso_stream *stream
)
{
u32 now, next, start, period;
u32 now, next, start, period, span;
int status;
unsigned mod = ehci->periodic_size << 3;
struct ehci_iso_sched *sched = urb->hcpriv;
struct pci_dev *pdev;
if (sched->span > (mod - SCHEDULE_SLOP)) {
period = urb->interval;
span = sched->span;
if (!stream->highspeed) {
period <<= 3;
span <<= 3;
}
if (span > mod - SCHEDULE_SLOP) {
ehci_dbg (ehci, "iso request %p too long\n", urb);
status = -EFBIG;
goto fail;
}
if ((stream->depth + sched->span) > mod) {
ehci_dbg (ehci, "request %p would overflow (%d+%d>%d)\n",
urb, stream->depth, sched->span, mod);
status = -EFBIG;
goto fail;
}
period = urb->interval;
if (!stream->highspeed)
period <<= 3;
now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1);
/* Typical case: reuse current schedule, stream is still active.
* Hopefully there are no gaps from the host falling behind
@ -1427,34 +1412,35 @@ iso_stream_schedule (
* slot in the schedule, implicitly assuming URB_ISO_ASAP.
*/
if (likely (!list_empty (&stream->td_list))) {
pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
start = stream->next_uframe;
u32 excess;
/* For high speed devices, allow scheduling within the
* isochronous scheduling threshold. For full speed devices,
* don't. (Work around for Intel ICH9 bug.)
* isochronous scheduling threshold. For full speed devices
* and Intel PCI-based controllers, don't (work around for
* Intel ICH9 bug).
*/
if (!stream->highspeed &&
pdev->vendor == PCI_VENDOR_ID_INTEL)
if (!stream->highspeed && ehci->fs_i_thresh)
next = now + ehci->i_thresh;
else
next = now;
/* Fell behind (by up to twice the slop amount)? */
if (((start - next) & (mod - 1)) >=
mod - 2 * SCHEDULE_SLOP)
start += period * DIV_ROUND_UP(
(next - start) & (mod - 1),
period);
/* Tried to schedule too far into the future? */
if (unlikely(((start - now) & (mod - 1)) + sched->span
>= mod - 2 * SCHEDULE_SLOP)) {
/* Fell behind (by up to twice the slop amount)?
* We decide based on the time of the last currently-scheduled
* slot, not the time of the next available slot.
*/
excess = (stream->next_uframe - period - next) & (mod - 1);
if (excess >= mod - 2 * SCHEDULE_SLOP)
start = next + excess - mod + period *
DIV_ROUND_UP(mod - excess, period);
else
start = next + excess + period;
if (start - now >= mod) {
ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n",
urb, start - now - period, period,
mod);
status = -EFBIG;
goto fail;
}
stream->next_uframe = start;
goto ready;
}
/* need to schedule; when's the next (u)frame we could start?
@ -1463,51 +1449,60 @@ iso_stream_schedule (
* can also help high bandwidth if the dma and irq loads don't
* jump until after the queue is primed.
*/
start = SCHEDULE_SLOP + (now & ~0x07);
start %= mod;
stream->next_uframe = start;
else {
start = SCHEDULE_SLOP + (now & ~0x07);
/* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */
/* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */
/* find a uframe slot with enough bandwidth */
for (; start < (stream->next_uframe + period); start++) {
int enough_space;
/* find a uframe slot with enough bandwidth */
next = start + period;
for (; start < next; start++) {
/* check schedule: enough space? */
if (stream->highspeed)
enough_space = itd_slot_ok (ehci, mod, start,
stream->usecs, period);
else {
if ((start % 8) >= 6)
continue;
enough_space = sitd_slot_ok (ehci, mod, stream,
start, sched, period);
/* check schedule: enough space? */
if (stream->highspeed) {
if (itd_slot_ok(ehci, mod, start,
stream->usecs, period))
break;
} else {
if ((start % 8) >= 6)
continue;
if (sitd_slot_ok(ehci, mod, stream,
start, sched, period))
break;
}
}
/* schedule it here if there's enough bandwidth */
if (enough_space) {
stream->next_uframe = start % mod;
goto ready;
/* no room in the schedule */
if (start == next) {
ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n",
urb, now, now + mod);
status = -ENOSPC;
goto fail;
}
}
/* no room in the schedule */
ehci_dbg (ehci, "iso %ssched full %p (now %d max %d)\n",
list_empty (&stream->td_list) ? "" : "re",
urb, now, now + mod);
status = -ENOSPC;
/* Tried to schedule too far into the future? */
if (unlikely(start - now + span - period
>= mod - 2 * SCHEDULE_SLOP)) {
ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n",
urb, start - now, span - period,
mod - 2 * SCHEDULE_SLOP);
status = -EFBIG;
goto fail;
}
fail:
iso_sched_free (stream, sched);
urb->hcpriv = NULL;
return status;
stream->next_uframe = start & (mod - 1);
ready:
/* report high speed start in uframes; full speed, in frames */
urb->start_frame = stream->next_uframe;
if (!stream->highspeed)
urb->start_frame >>= 3;
return 0;
fail:
iso_sched_free(stream, sched);
urb->hcpriv = NULL;
return status;
}
/*-------------------------------------------------------------------------*/
@ -1602,7 +1597,7 @@ itd_link_urb (
struct ehci_iso_sched *iso_sched = urb->hcpriv;
struct ehci_itd *itd;
next_uframe = stream->next_uframe % mod;
next_uframe = stream->next_uframe & (mod - 1);
if (unlikely (list_empty(&stream->td_list))) {
ehci_to_hcd(ehci)->self.bandwidth_allocated
@ -1613,7 +1608,6 @@ itd_link_urb (
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
urb->interval,
next_uframe >> 3, next_uframe & 0x7);
stream->start = jiffies;
}
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
@ -1639,14 +1633,13 @@ itd_link_urb (
itd_patch(ehci, itd, iso_sched, packet, uframe);
next_uframe += stream->interval;
stream->depth += stream->interval;
next_uframe %= mod;
next_uframe &= mod - 1;
packet++;
/* link completed itds into the schedule */
if (((next_uframe >> 3) != frame)
|| packet == urb->number_of_packets) {
itd_link (ehci, frame % ehci->periodic_size, itd);
itd_link(ehci, frame & (ehci->periodic_size - 1), itd);
itd = NULL;
}
}
@ -1695,7 +1688,6 @@ itd_complete (
t = hc32_to_cpup(ehci, &itd->hw_transaction [uframe]);
itd->hw_transaction [uframe] = 0;
stream->depth -= stream->interval;
/* report transfer status */
if (unlikely (t & ISO_ERRS)) {
@ -1815,8 +1807,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags))) {
if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) {
status = -ESHUTDOWN;
goto done_not_linked;
}
@ -2024,9 +2015,8 @@ sitd_link_urb (
"sched devp %s ep%d%s-iso [%d] %dms/%04x\n",
urb->dev->devpath, stream->bEndpointAddress & 0x0f,
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
(next_uframe >> 3) % ehci->periodic_size,
(next_uframe >> 3) & (ehci->periodic_size - 1),
stream->interval, hc32_to_cpu(ehci, stream->splits));
stream->start = jiffies;
}
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
@ -2047,13 +2037,12 @@ sitd_link_urb (
sitd->urb = urb;
sitd_patch(ehci, stream, sitd, sched, packet);
sitd_link (ehci, (next_uframe >> 3) % ehci->periodic_size,
sitd_link(ehci, (next_uframe >> 3) & (ehci->periodic_size - 1),
sitd);
next_uframe += stream->interval << 3;
stream->depth += stream->interval << 3;
}
stream->next_uframe = next_uframe % mod;
stream->next_uframe = next_uframe & (mod - 1);
/* don't need that schedule data any more */
iso_sched_free (stream, sched);
@ -2111,7 +2100,6 @@ sitd_complete (
desc->actual_length = desc->length - SITD_LENGTH(t);
urb->actual_length += desc->actual_length;
}
stream->depth -= stream->interval << 3;
/* handle completion now? */
if ((urb_index + 1) != urb->number_of_packets)
@ -2201,8 +2189,7 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags))) {
if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) {
status = -ESHUTDOWN;
goto done_not_linked;
}
@ -2263,7 +2250,7 @@ scan_periodic (struct ehci_hcd *ehci)
now_uframe = ehci->next_uframe;
if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
clock = ehci_readl(ehci, &ehci->regs->frame_index);
clock_frame = (clock >> 3) % ehci->periodic_size;
clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
} else {
clock = now_uframe + mod - 1;
clock_frame = -1;
@ -2272,7 +2259,7 @@ scan_periodic (struct ehci_hcd *ehci)
free_cached_lists(ehci);
ehci->clock_frame = clock_frame;
}
clock %= mod;
clock &= mod - 1;
clock_frame = clock >> 3;
for (;;) {
@ -2361,7 +2348,7 @@ restart:
* frame is current.
*/
if (((frame == clock_frame) ||
(((frame + 1) % ehci->periodic_size)
(((frame + 1) & (ehci->periodic_size - 1))
== clock_frame))
&& live
&& (q.sitd->hw_results &
@ -2428,7 +2415,8 @@ restart:
|| ehci->periodic_sched == 0)
break;
ehci->next_uframe = now_uframe;
now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
now = ehci_readl(ehci, &ehci->regs->frame_index) &
(mod - 1);
if (now_uframe == now)
break;
@ -2441,7 +2429,7 @@ restart:
}
} else {
now_uframe++;
now_uframe %= mod;
now_uframe &= mod - 1;
}
}
}

View File

@ -130,6 +130,7 @@ struct ehci_hcd { /* one per controller */
unsigned has_amcc_usb23:1;
unsigned need_io_watchdog:1;
unsigned broken_periodic:1;
unsigned fs_i_thresh:1; /* Intel iso scheduling */
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
@ -140,7 +141,8 @@ struct ehci_hcd { /* one per controller */
#define OHCI_HCCTRL_LEN 0x4
__hc32 *ohci_hcctrl_reg;
unsigned has_hostpc:1;
unsigned has_lpm:1; /* support link power management */
unsigned has_ppcd:1; /* support per-port change bits */
u8 sbrn; /* packed release number */
/* irq statistics */
@ -154,9 +156,6 @@ struct ehci_hcd { /* one per controller */
/* debug files */
#ifdef DEBUG
struct dentry *debug_dir;
struct dentry *debug_async;
struct dentry *debug_periodic;
struct dentry *debug_registers;
#endif
};
@ -401,15 +400,12 @@ struct ehci_iso_stream {
u32 refcount;
u8 bEndpointAddress;
u8 highspeed;
u16 depth; /* depth in uframes */
struct list_head td_list; /* queued itds/sitds */
struct list_head free_list; /* list of unused itds/sitds */
struct usb_device *udev;
struct usb_host_endpoint *ep;
/* output of (re)scheduling */
unsigned long start; /* jiffies */
unsigned long rescheduled;
int next_uframe;
__hc32 splits;
@ -538,11 +534,11 @@ struct ehci_fstn {
/* Prepare the PORTSC wakeup flags during controller suspend/resume */
#define ehci_prepare_ports_for_controller_suspend(ehci) \
ehci_adjust_port_wakeup_flags(ehci, true);
#define ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup) \
ehci_adjust_port_wakeup_flags(ehci, true, do_wakeup);
#define ehci_prepare_ports_for_controller_resume(ehci) \
ehci_adjust_port_wakeup_flags(ehci, false);
#define ehci_prepare_ports_for_controller_resume(ehci) \
ehci_adjust_port_wakeup_flags(ehci, false, false);
/*-------------------------------------------------------------------------*/

View File

@ -159,7 +159,7 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd)
goto error_set_cluster_id;
usb_hcd->uses_new_polling = 1;
usb_hcd->poll_rh = 1;
set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
usb_hcd->state = HC_STATE_RUNNING;
result = 0;
out:
@ -776,7 +776,7 @@ static int hwahc_probe(struct usb_interface *usb_iface,
goto error_alloc;
}
usb_hcd->wireless = 1;
usb_hcd->flags |= HCD_FLAG_SAW_IRQ;
set_bit(HCD_FLAG_SAW_IRQ, &usb_hcd->flags);
wusbhc = usb_hcd_to_wusbhc(usb_hcd);
hwahc = container_of(wusbhc, struct hwahc, wusbhc);
hwahc_init(hwahc);

View File

@ -1521,7 +1521,7 @@ static int imx21_hc_reset(struct usb_hcd *hcd)
return -ETIMEDOUT;
}
spin_unlock_irq(&imx21->lock);
schedule_timeout(1);
schedule_timeout_uninterruptible(1);
spin_lock_irq(&imx21->lock);
}
spin_unlock_irqrestore(&imx21->lock, flags);

View File

@ -8,29 +8,7 @@
/*
* Platform specific compile time options
*/
#if defined(CONFIG_ARCH_KARO)
#include <asm/arch/hardware.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/karo.h>
#define USE_32BIT 1
/* These options are mutually eclusive */
#define USE_PLATFORM_DELAY 1
#define USE_NDELAY 0
/*
* MAX_ROOT_PORTS: Number of downstream ports
*
* The chip has two USB ports, one of which can be configured as
* an USB device port, so the value of this constant is implementation
* specific.
*/
#define MAX_ROOT_PORTS 2
#define DUMMY_DELAY_ACCESS do {} while (0)
/* insert platform specific definitions for other machines here */
#elif defined(CONFIG_BLACKFIN)
#if defined(CONFIG_BLACKFIN)
#include <linux/io.h>
#define USE_32BIT 0

View File

@ -482,7 +482,6 @@ static int isp1760_run(struct usb_hcd *hcd)
u32 chipid;
hcd->uses_new_polling = 1;
hcd->poll_rh = 0;
hcd->state = HC_STATE_RUNNING;
isp1760_enable_interrupts(hcd);
@ -1450,7 +1449,7 @@ static int isp1760_prepare_enqueue(struct isp1760_hcd *priv, struct urb *urb,
epnum = urb->ep->desc.bEndpointAddress;
spin_lock_irqsave(&priv->lock, flags);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &priv_to_hcd(priv)->flags)) {
if (!HCD_HW_ACCESSIBLE(priv_to_hcd(priv))) {
rc = -ESHUTDOWN;
goto done;
}

View File

@ -645,7 +645,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
hcd->product_desc,
hcd_name);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
if (!HCD_HW_ACCESSIBLE(hcd)) {
size -= scnprintf (next, size,
"SUSPENDED (no register access)\n");
goto done;
@ -687,7 +687,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
next += temp;
temp = scnprintf (next, size, "hub poll timer %s\n",
ohci_to_hcd(ohci)->poll_rh ? "ON" : "off");
HCD_POLL_RH(ohci_to_hcd(ohci)) ? "ON" : "off");
size -= temp;
next += temp;

View File

@ -212,7 +212,7 @@ static int ohci_urb_enqueue (
spin_lock_irqsave (&ohci->lock, flags);
/* don't submit to a dead HC */
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
if (!HCD_HW_ACCESSIBLE(hcd)) {
retval = -ENODEV;
goto fail;
}
@ -685,7 +685,7 @@ retry:
}
/* use rhsc irqs after khubd is fully initialized */
hcd->poll_rh = 1;
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
hcd->uses_new_polling = 1;
/* start controller operations */
@ -822,7 +822,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
else if (ints & OHCI_INTR_RD) {
ohci_vdbg(ohci, "resume detect\n");
ohci_writel(ohci, OHCI_INTR_RD, &regs->intrstatus);
hcd->poll_rh = 1;
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
if (ohci->autostop) {
spin_lock (&ohci->lock);
ohci_rh_resume (ohci);

View File

@ -284,7 +284,7 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
spin_lock_irq (&ohci->lock);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
if (unlikely(!HCD_HW_ACCESSIBLE(hcd)))
rc = -ESHUTDOWN;
else
rc = ohci_rh_suspend (ohci, 0);
@ -302,7 +302,7 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
spin_lock_irq (&ohci->lock);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
if (unlikely(!HCD_HW_ACCESSIBLE(hcd)))
rc = -ESHUTDOWN;
else
rc = ohci_rh_resume (ohci);
@ -355,6 +355,11 @@ static void ohci_finish_controller_resume(struct usb_hcd *hcd)
ohci_readl(ohci, &ohci->regs->intrenable);
msleep(20);
}
/* Does the root hub have a port wakeup pending? */
if (ohci_readl(ohci, &ohci->regs->intrstatus) &
(OHCI_INTR_RD | OHCI_INTR_RHSC))
usb_hcd_resume_root_hub(hcd);
}
/* Carry out polling-, autostop-, and autoresume-related state changes */
@ -364,7 +369,7 @@ static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
int poll_rh = 1;
int rhsc_enable;
/* Some broken controllers never turn off RHCS in the interrupt
/* Some broken controllers never turn off RHSC in the interrupt
* status register. For their sake we won't re-enable RHSC
* interrupts if the interrupt bit is already active.
*/
@ -489,7 +494,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
unsigned long flags;
spin_lock_irqsave (&ohci->lock, flags);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
if (!HCD_HW_ACCESSIBLE(hcd))
goto done;
/* undocumented erratum seen on at least rev D */
@ -533,8 +538,12 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
}
}
hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed,
any_connected, rhsc_status);
if (ohci_root_hub_state_changes(ohci, changed,
any_connected, rhsc_status))
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
else
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
done:
spin_unlock_irqrestore (&ohci->lock, flags);
@ -701,7 +710,7 @@ static int ohci_hub_control (
u32 temp;
int retval = 0;
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
if (unlikely(!HCD_HW_ACCESSIBLE(hcd)))
return -ESHUTDOWN;
switch (typeReq) {

View File

@ -392,7 +392,7 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd)
#ifdef CONFIG_PM
static int ohci_pci_suspend(struct usb_hcd *hcd)
static int ohci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags;

View File

@ -93,8 +93,11 @@ static void ssb_ohci_detach(struct ssb_device *dev)
{
struct usb_hcd *hcd = ssb_get_drvdata(dev);
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
ssb_device_disable(dev, 0);
}
@ -106,10 +109,52 @@ static int ssb_ohci_attach(struct ssb_device *dev)
int err = -ENOMEM;
u32 tmp, flags = 0;
if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
flags |= SSB_OHCI_TMSLOW_HOSTMODE;
if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32)))
return -EOPNOTSUPP;
ssb_device_enable(dev, flags);
if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) {
/* Put the device into host-mode. */
flags |= SSB_OHCI_TMSLOW_HOSTMODE;
ssb_device_enable(dev, flags);
} else if (dev->id.coreid == SSB_DEV_USB20_HOST) {
/*
* USB 2.0 special considerations:
*
* In addition to the standard SSB reset sequence, the Host
* Control Register must be programmed to bring the USB core
* and various phy components out of reset.
*/
ssb_device_enable(dev, 0);
ssb_write32(dev, 0x200, 0x7ff);
/* Change Flush control reg */
tmp = ssb_read32(dev, 0x400);
tmp &= ~8;
ssb_write32(dev, 0x400, tmp);
tmp = ssb_read32(dev, 0x400);
/* Change Shim control reg */
tmp = ssb_read32(dev, 0x304);
tmp &= ~0x100;
ssb_write32(dev, 0x304, tmp);
tmp = ssb_read32(dev, 0x304);
udelay(1);
/* Work around for 5354 failures */
if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) {
/* Change syn01 reg */
tmp = 0x00fe00fe;
ssb_write32(dev, 0x894, tmp);
/* Change syn03 reg */
tmp = ssb_read32(dev, 0x89c);
tmp |= 0x1;
ssb_write32(dev, 0x89c, tmp);
}
} else
ssb_device_enable(dev, 0);
hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
dev_name(dev->dev));
@ -200,6 +245,7 @@ static int ssb_ohci_resume(struct ssb_device *dev)
static const struct ssb_device_id ssb_ohci_table[] = {
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
SSB_DEVTABLE_END
};
MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);

View File

@ -1641,8 +1641,7 @@ static int submit_async(struct oxu_hcd *oxu, struct urb *urb,
#endif
spin_lock_irqsave(&oxu->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&oxu_to_hcd(oxu)->flags))) {
if (unlikely(!HCD_HW_ACCESSIBLE(oxu_to_hcd(oxu)))) {
rc = -ESHUTDOWN;
goto done;
}
@ -2209,8 +2208,7 @@ static int intr_submit(struct oxu_hcd *oxu, struct urb *urb,
spin_lock_irqsave(&oxu->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&oxu_to_hcd(oxu)->flags))) {
if (unlikely(!HCD_HW_ACCESSIBLE(oxu_to_hcd(oxu)))) {
status = -ESHUTDOWN;
goto done;
}
@ -2715,7 +2713,6 @@ static int oxu_run(struct usb_hcd *hcd)
u32 temp, hcc_params;
hcd->uses_new_polling = 1;
hcd->poll_rh = 0;
/* EHCI spec section 4.1 */
retval = ehci_reset(oxu);

View File

@ -813,8 +813,11 @@ static int sl811h_urb_enqueue(
#endif
/* avoid all allocations within spinlocks */
if (!hep->hcpriv)
if (!hep->hcpriv) {
ep = kzalloc(sizeof *ep, mem_flags);
if (ep == NULL)
return -ENOMEM;
}
spin_lock_irqsave(&sl811->lock, flags);

View File

@ -17,7 +17,6 @@
#include "uhci-hcd.h"
#define uhci_debug_operations (* (const struct file_operations *) NULL)
static struct dentry *uhci_debugfs_root;
#ifdef DEBUG
@ -495,18 +494,16 @@ static int uhci_debug_open(struct inode *inode, struct file *file)
{
struct uhci_hcd *uhci = inode->i_private;
struct uhci_debug *up;
int ret = -ENOMEM;
unsigned long flags;
lock_kernel();
up = kmalloc(sizeof(*up), GFP_KERNEL);
if (!up)
goto out;
return -ENOMEM;
up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
if (!up->data) {
kfree(up);
goto out;
return -ENOMEM;
}
up->size = 0;
@ -517,10 +514,7 @@ static int uhci_debug_open(struct inode *inode, struct file *file)
file->private_data = up;
ret = 0;
out:
unlock_kernel();
return ret;
return 0;
}
static loff_t uhci_debug_lseek(struct file *file, loff_t off, int whence)
@ -528,9 +522,9 @@ static loff_t uhci_debug_lseek(struct file *file, loff_t off, int whence)
struct uhci_debug *up;
loff_t new = -1;
lock_kernel();
up = file->private_data;
/* XXX: atomic 64bit seek access, but that needs to be fixed in the VFS */
switch (whence) {
case 0:
new = off;
@ -539,11 +533,10 @@ static loff_t uhci_debug_lseek(struct file *file, loff_t off, int whence)
new = file->f_pos + off;
break;
}
if (new < 0 || new > up->size) {
unlock_kernel();
if (new < 0 || new > up->size)
return -EINVAL;
}
unlock_kernel();
return (file->f_pos = new);
}
@ -564,7 +557,6 @@ static int uhci_debug_release(struct inode *inode, struct file *file)
return 0;
}
#undef uhci_debug_operations
static const struct file_operations uhci_debug_operations = {
.owner = THIS_MODULE,
.open = uhci_debug_open,
@ -572,6 +564,7 @@ static const struct file_operations uhci_debug_operations = {
.read = uhci_debug_read,
.release = uhci_debug_release,
};
#define UHCI_DEBUG_OPS
#endif /* CONFIG_DEBUG_FS */

View File

@ -140,7 +140,7 @@ static void finish_reset(struct uhci_hcd *uhci)
uhci->rh_state = UHCI_RH_RESET;
uhci->is_stopped = UHCI_IS_STOPPED;
uhci_to_hcd(uhci)->state = HC_STATE_HALT;
uhci_to_hcd(uhci)->poll_rh = 0;
clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
uhci->dead = 0; /* Full reset resurrects the controller */
}
@ -176,6 +176,8 @@ static void check_and_reset_hc(struct uhci_hcd *uhci)
*/
static void configure_hc(struct uhci_hcd *uhci)
{
struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
/* Set the frame length to the default: 1 ms exactly */
outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
@ -191,8 +193,11 @@ static void configure_hc(struct uhci_hcd *uhci)
mb();
/* Enable PIRQ */
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
USBLEGSUP_DEFAULT);
pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
/* Disable platform-specific non-PME# wakeup */
if (pdev->vendor == PCI_VENDOR_ID_INTEL)
pci_write_config_byte(pdev, USBRES_INTEL, 0);
}
@ -344,7 +349,10 @@ __acquires(uhci->lock)
/* If interrupts don't work and remote wakeup is enabled then
* the suspended root hub needs to be polled.
*/
uhci_to_hcd(uhci)->poll_rh = (!int_enable && wakeup_enable);
if (!int_enable && wakeup_enable)
set_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
else
clear_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
uhci_scan_schedule(uhci);
uhci_fsbr_off(uhci);
@ -363,7 +371,7 @@ static void start_rh(struct uhci_hcd *uhci)
uhci->io_addr + USBINTR);
mb();
uhci->rh_state = UHCI_RH_RUNNING;
uhci_to_hcd(uhci)->poll_rh = 1;
set_bit(HCD_FLAG_POLL_RH, &uhci_to_hcd(uhci)->flags);
}
static void wakeup_rh(struct uhci_hcd *uhci)
@ -589,7 +597,7 @@ static int uhci_start(struct usb_hcd *hcd)
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int retval = -EBUSY;
int i;
struct dentry *dentry;
struct dentry __maybe_unused *dentry;
hcd->uses_new_polling = 1;
@ -599,18 +607,16 @@ static int uhci_start(struct usb_hcd *hcd)
INIT_LIST_HEAD(&uhci->idle_qh_list);
init_waitqueue_head(&uhci->waitqh);
if (DEBUG_CONFIGURED) {
dentry = debugfs_create_file(hcd->self.bus_name,
S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root,
uhci, &uhci_debug_operations);
if (!dentry) {
dev_err(uhci_dev(uhci), "couldn't create uhci "
"debugfs entry\n");
retval = -ENOMEM;
goto err_create_debug_entry;
}
uhci->dentry = dentry;
#ifdef UHCI_DEBUG_OPS
dentry = debugfs_create_file(hcd->self.bus_name,
S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root,
uhci, &uhci_debug_operations);
if (!dentry) {
dev_err(uhci_dev(uhci), "couldn't create uhci debugfs entry\n");
return -ENOMEM;
}
uhci->dentry = dentry;
#endif
uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
UHCI_NUMFRAMES * sizeof(*uhci->frame),
@ -691,7 +697,9 @@ static int uhci_start(struct usb_hcd *hcd)
configure_hc(uhci);
uhci->is_initialized = 1;
spin_lock_irq(&uhci->lock);
start_rh(uhci);
spin_unlock_irq(&uhci->lock);
return 0;
/*
@ -722,7 +730,6 @@ err_alloc_frame_cpu:
err_alloc_frame:
debugfs_remove(uhci->dentry);
err_create_debug_entry:
return retval;
}
@ -731,7 +738,7 @@ static void uhci_stop(struct usb_hcd *hcd)
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
spin_lock_irq(&uhci->lock);
if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && !uhci->dead)
if (HCD_HW_ACCESSIBLE(hcd) && !uhci->dead)
uhci_hc_died(uhci);
uhci_scan_schedule(uhci);
spin_unlock_irq(&uhci->lock);
@ -748,7 +755,7 @@ static int uhci_rh_suspend(struct usb_hcd *hcd)
int rc = 0;
spin_lock_irq(&uhci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
if (!HCD_HW_ACCESSIBLE(hcd))
rc = -ESHUTDOWN;
else if (uhci->dead)
; /* Dead controllers tell no tales */
@ -775,7 +782,7 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
int rc = 0;
spin_lock_irq(&uhci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
if (!HCD_HW_ACCESSIBLE(hcd))
rc = -ESHUTDOWN;
else if (!uhci->dead)
wakeup_rh(uhci);
@ -783,15 +790,16 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
return rc;
}
static int uhci_pci_suspend(struct usb_hcd *hcd)
static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
int rc = 0;
dev_dbg(uhci_dev(uhci), "%s\n", __func__);
spin_lock_irq(&uhci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)
if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead)
goto done_okay; /* Already suspended or dead */
if (uhci->rh_state > UHCI_RH_SUSPENDED) {
@ -803,11 +811,15 @@ static int uhci_pci_suspend(struct usb_hcd *hcd)
/* All PCI host controllers are required to disable IRQ generation
* at the source, so we must turn off PIRQ.
*/
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
mb();
hcd->poll_rh = 0;
pci_write_config_word(pdev, USBLEGSUP, 0);
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
/* FIXME: Enable non-PME# remote wakeup? */
/* Enable platform-specific non-PME# wakeup */
if (do_wakeup) {
if (pdev->vendor == PCI_VENDOR_ID_INTEL)
pci_write_config_byte(pdev, USBRES_INTEL,
USBPORT1EN | USBPORT2EN);
}
done_okay:
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
@ -826,7 +838,6 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
* even if the controller was dead.
*/
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
mb();
spin_lock_irq(&uhci->lock);
@ -834,8 +845,6 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
if (hibernated)
uhci_hc_died(uhci);
/* FIXME: Disable non-PME# remote wakeup? */
/* The firmware or a boot kernel may have changed the controller
* settings during a system wakeup. Check it and reconfigure
* to avoid problems.
@ -845,22 +854,20 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
/* If the controller was dead before, it's back alive now */
configure_hc(uhci);
if (uhci->rh_state == UHCI_RH_RESET) {
/* The controller had to be reset */
/* Tell the core if the controller had to be reset */
if (uhci->rh_state == UHCI_RH_RESET)
usb_root_hub_lost_power(hcd->self.root_hub);
suspend_rh(uhci, UHCI_RH_SUSPENDED);
}
spin_unlock_irq(&uhci->lock);
/* If interrupts don't work and remote wakeup is enabled then
* the suspended root hub needs to be polled.
*/
if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) {
hcd->poll_rh = 1;
usb_hcd_poll_rh_status(hcd);
}
if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup)
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
/* Does the root hub have a port wakeup pending? */
usb_hcd_poll_rh_status(hcd);
return 0;
}
#endif

View File

@ -67,12 +67,17 @@
#define USBPORTSC_RES3 0x4000 /* reserved, write zeroes */
#define USBPORTSC_RES4 0x8000 /* reserved, write zeroes */
/* Legacy support register */
/* PCI legacy support register */
#define USBLEGSUP 0xc0
#define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
#define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */
#define USBLEGSUP_RO 0x5040 /* R/O and reserved bits */
/* PCI Intel-specific resume-enable register */
#define USBRES_INTEL 0xc4
#define USBPORT1EN 0x01
#define USBPORT2EN 0x02
#define UHCI_PTR_BITS cpu_to_le32(0x000F)
#define UHCI_PTR_TERM cpu_to_le32(0x0001)
#define UHCI_PTR_QH cpu_to_le32(0x0002)

View File

@ -190,7 +190,7 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
spin_lock_irqsave(&uhci->lock, flags);
uhci_scan_schedule(uhci);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)
if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead)
goto done;
uhci_check_ports(uhci);
@ -200,7 +200,7 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
case UHCI_RH_SUSPENDING:
case UHCI_RH_SUSPENDED:
/* if port change, ask to be resumed */
if (status)
if (status || uhci->resuming_ports)
usb_hcd_resume_root_hub(hcd);
break;
@ -246,7 +246,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wPortChange, wPortStatus;
unsigned long flags;
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)
if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead)
return -ETIMEDOUT;
spin_lock_irqsave(&uhci->lock, flags);

View File

@ -565,7 +565,7 @@ static void uhci_unlink_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
qh->unlink_frame = uhci->frame_number;
/* Force an interrupt so we know when the QH is fully unlinked */
if (list_empty(&uhci->skel_unlink_qh->node))
if (list_empty(&uhci->skel_unlink_qh->node) || uhci->is_stopped)
uhci_set_next_interrupt(uhci);
/* Move the QH from its old list to the end of the unlinking list */
@ -1667,7 +1667,7 @@ static int uhci_advance_check(struct uhci_hcd *uhci, struct uhci_qh *qh)
qh->advance_jiffies = jiffies;
goto done;
}
ret = 0;
ret = uhci->is_stopped;
}
/* The queue hasn't advanced; check for timeout */

View File

@ -68,7 +68,7 @@ static int whc_start(struct usb_hcd *usb_hcd)
whc_write_wusbcmd(whc, WUSBCMD_RUN, WUSBCMD_RUN);
usb_hcd->uses_new_polling = 1;
usb_hcd->poll_rh = 1;
set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
usb_hcd->state = HC_STATE_RUNNING;
out:

View File

@ -475,7 +475,7 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u
|| (prev_end & (WHCI_PAGE_SIZE-1))
|| (dma_addr & (WHCI_PAGE_SIZE-1))
|| std->len + WHCI_PAGE_SIZE > QTD_MAX_XFER_SIZE) {
if (std->len % qset->max_packet != 0)
if (std && std->len % qset->max_packet != 0)
return -EINVAL;
std = qset_new_std(whc, qset, urb, mem_flags);
if (std == NULL) {

View File

@ -391,49 +391,6 @@ struct xhci_ring *xhci_stream_id_to_ring(
return ep->stream_info->stream_rings[stream_id];
}
struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
unsigned int stream_id)
{
struct xhci_virt_ep *ep;
ep = &xhci->devs[slot_id]->eps[ep_index];
/* Common case: no streams */
if (!(ep->ep_state & EP_HAS_STREAMS))
return ep->ring;
if (stream_id == 0) {
xhci_warn(xhci,
"WARN: Slot ID %u, ep index %u has streams, "
"but URB has no stream ID.\n",
slot_id, ep_index);
return NULL;
}
if (stream_id < ep->stream_info->num_streams)
return ep->stream_info->stream_rings[stream_id];
xhci_warn(xhci,
"WARN: Slot ID %u, ep index %u has "
"stream IDs 1 to %u allocated, "
"but stream ID %u is requested.\n",
slot_id, ep_index,
ep->stream_info->num_streams - 1,
stream_id);
return NULL;
}
/* Get the right ring for the given URB.
* If the endpoint supports streams, boundary check the URB's stream ID.
* If the endpoint doesn't support streams, return the singular endpoint ring.
*/
struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
struct urb *urb)
{
return xhci_triad_to_transfer_ring(xhci, urb->dev->slot_id,
xhci_get_endpoint_index(&urb->ep->desc), urb->stream_id);
}
#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
static int xhci_test_radix_tree(struct xhci_hcd *xhci,
unsigned int num_streams,
@ -1112,8 +1069,18 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
/* Set up the endpoint ring */
virt_dev->eps[ep_index].new_ring =
xhci_ring_alloc(xhci, 1, true, mem_flags);
/*
* Isochronous endpoint ring needs bigger size because one isoc URB
* carries multiple packets and it will insert multiple tds to the
* ring.
* This should be replaced with dynamic ring resizing in the future.
*/
if (usb_endpoint_xfer_isoc(&ep->desc))
virt_dev->eps[ep_index].new_ring =
xhci_ring_alloc(xhci, 8, true, mem_flags);
else
virt_dev->eps[ep_index].new_ring =
xhci_ring_alloc(xhci, 1, true, mem_flags);
if (!virt_dev->eps[ep_index].new_ring) {
/* Attempt to use the ring cache */
if (virt_dev->num_rings_cached == 0)
@ -1124,6 +1091,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
virt_dev->num_rings_cached--;
xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring);
}
virt_dev->eps[ep_index].skip = false;
ep_ring = virt_dev->eps[ep_index].new_ring;
ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state;
@ -1389,6 +1357,22 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
return command;
}
void xhci_urb_free_priv(struct xhci_hcd *xhci, struct urb_priv *urb_priv)
{
int last;
if (!urb_priv)
return;
last = urb_priv->length - 1;
if (last >= 0) {
int i;
for (i = 0; i <= last; i++)
kfree(urb_priv->td[i]);
}
kfree(urb_priv);
}
void xhci_free_command(struct xhci_hcd *xhci,
struct xhci_command *command)
{
@ -1588,7 +1572,7 @@ static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci, gfp_t mem_flags)
unsigned int num_tests;
int i, ret;
num_tests = sizeof(simple_test_vector) / sizeof(simple_test_vector[0]);
num_tests = ARRAY_SIZE(simple_test_vector);
for (i = 0; i < num_tests; i++) {
ret = xhci_test_trb_in_td(xhci,
xhci->event_ring->first_seg,
@ -1601,7 +1585,7 @@ static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci, gfp_t mem_flags)
return ret;
}
num_tests = sizeof(complex_test_vector) / sizeof(complex_test_vector[0]);
num_tests = ARRAY_SIZE(complex_test_vector);
for (i = 0; i < num_tests; i++) {
ret = xhci_test_trb_in_td(xhci,
complex_test_vector[i].input_seg,
@ -1617,6 +1601,29 @@ static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci, gfp_t mem_flags)
return 0;
}
static void xhci_set_hc_event_deq(struct xhci_hcd *xhci)
{
u64 temp;
dma_addr_t deq;
deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg,
xhci->event_ring->dequeue);
if (deq == 0 && !in_interrupt())
xhci_warn(xhci, "WARN something wrong with SW event ring "
"dequeue ptr.\n");
/* Update HC event ring dequeue pointer */
temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
temp &= ERST_PTR_MASK;
/* Don't clear the EHB bit (which is RW1C) because
* there might be more events to service.
*/
temp &= ~ERST_EHB;
xhci_dbg(xhci, "// Write event ring dequeue pointer, "
"preserving EHB bit\n");
xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp,
&xhci->ir_set->erst_dequeue);
}
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
{

View File

@ -53,6 +53,7 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
int retval;
u32 temp;
hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2;
@ -93,6 +94,14 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
return retval;
xhci_dbg(xhci, "Reset complete\n");
temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
if (HCC_64BIT_ADDR(temp)) {
xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n");
dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64));
} else {
dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32));
}
xhci_dbg(xhci, "Calling HCD init\n");
/* Initialize HCD and host controller data structures. */
retval = xhci_init(hcd);

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/pci.h>
#include <linux/irq.h>
#include <linux/log2.h>
#include <linux/module.h>
@ -171,22 +172,84 @@ int xhci_reset(struct xhci_hcd *xhci)
return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
}
#if 0
/* Set up MSI-X table for entry 0 (may claim other entries later) */
static int xhci_setup_msix(struct xhci_hcd *xhci)
/*
* Free IRQs
* free all IRQs request
*/
static void xhci_free_irq(struct xhci_hcd *xhci)
{
int ret;
int i;
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
xhci->msix_count = 0;
/* XXX: did I do this right? ixgbe does kcalloc for more than one */
xhci->msix_entries = kmalloc(sizeof(struct msix_entry), GFP_KERNEL);
/* return if using legacy interrupt */
if (xhci_to_hcd(xhci)->irq >= 0)
return;
if (xhci->msix_entries) {
for (i = 0; i < xhci->msix_count; i++)
if (xhci->msix_entries[i].vector)
free_irq(xhci->msix_entries[i].vector,
xhci_to_hcd(xhci));
} else if (pdev->irq >= 0)
free_irq(pdev->irq, xhci_to_hcd(xhci));
return;
}
/*
* Set up MSI
*/
static int xhci_setup_msi(struct xhci_hcd *xhci)
{
int ret;
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
ret = pci_enable_msi(pdev);
if (ret) {
xhci_err(xhci, "failed to allocate MSI entry\n");
return ret;
}
ret = request_irq(pdev->irq, (irq_handler_t)xhci_msi_irq,
0, "xhci_hcd", xhci_to_hcd(xhci));
if (ret) {
xhci_err(xhci, "disable MSI interrupt\n");
pci_disable_msi(pdev);
}
return ret;
}
/*
* Set up MSI-X
*/
static int xhci_setup_msix(struct xhci_hcd *xhci)
{
int i, ret = 0;
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
/*
* calculate number of msi-x vectors supported.
* - HCS_MAX_INTRS: the max number of interrupts the host can handle,
* with max number of interrupters based on the xhci HCSPARAMS1.
* - num_online_cpus: maximum msi-x vectors per CPUs core.
* Add additional 1 vector to ensure always available interrupt.
*/
xhci->msix_count = min(num_online_cpus() + 1,
HCS_MAX_INTRS(xhci->hcs_params1));
xhci->msix_entries =
kmalloc((sizeof(struct msix_entry))*xhci->msix_count,
GFP_KERNEL);
if (!xhci->msix_entries) {
xhci_err(xhci, "Failed to allocate MSI-X entries\n");
return -ENOMEM;
}
xhci->msix_entries[0].entry = 0;
for (i = 0; i < xhci->msix_count; i++) {
xhci->msix_entries[i].entry = i;
xhci->msix_entries[i].vector = 0;
}
ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count);
if (ret) {
@ -194,20 +257,19 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
goto free_entries;
}
/*
* Pass the xhci pointer value as the request_irq "cookie".
* If more irqs are added, this will need to be unique for each one.
*/
ret = request_irq(xhci->msix_entries[0].vector, &xhci_irq, 0,
"xHCI", xhci_to_hcd(xhci));
if (ret) {
xhci_err(xhci, "Failed to allocate MSI-X interrupt\n");
goto disable_msix;
for (i = 0; i < xhci->msix_count; i++) {
ret = request_irq(xhci->msix_entries[i].vector,
(irq_handler_t)xhci_msi_irq,
0, "xhci_hcd", xhci_to_hcd(xhci));
if (ret)
goto disable_msix;
}
xhci_dbg(xhci, "Finished setting up MSI-X\n");
return 0;
return ret;
disable_msix:
xhci_err(xhci, "disable MSI-X interrupt\n");
xhci_free_irq(xhci);
pci_disable_msix(pdev);
free_entries:
kfree(xhci->msix_entries);
@ -215,21 +277,23 @@ free_entries:
return ret;
}
/* XXX: code duplication; can xhci_setup_msix call this? */
/* Free any IRQs and disable MSI-X */
static void xhci_cleanup_msix(struct xhci_hcd *xhci)
{
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
if (!xhci->msix_entries)
return;
free_irq(xhci->msix_entries[0].vector, xhci);
pci_disable_msix(pdev);
kfree(xhci->msix_entries);
xhci->msix_entries = NULL;
xhci_dbg(xhci, "Finished cleaning up MSI-X\n");
xhci_free_irq(xhci);
if (xhci->msix_entries) {
pci_disable_msix(pdev);
kfree(xhci->msix_entries);
xhci->msix_entries = NULL;
} else {
pci_disable_msi(pdev);
}
return;
}
#endif
/*
* Initialize memory for HCD and xHC (one-time init).
@ -257,100 +321,8 @@ int xhci_init(struct usb_hcd *hcd)
return retval;
}
/*
* Called in interrupt context when there might be work
* queued on the event ring
*
* xhci->lock must be held by caller.
*/
static void xhci_work(struct xhci_hcd *xhci)
{
u32 temp;
u64 temp_64;
/*
* Clear the op reg interrupt status first,
* so we can receive interrupts from other MSI-X interrupters.
* Write 1 to clear the interrupt status.
*/
temp = xhci_readl(xhci, &xhci->op_regs->status);
temp |= STS_EINT;
xhci_writel(xhci, temp, &xhci->op_regs->status);
/* FIXME when MSI-X is supported and there are multiple vectors */
/* Clear the MSI-X event interrupt status */
/* Acknowledge the interrupt */
temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
temp |= 0x3;
xhci_writel(xhci, temp, &xhci->ir_set->irq_pending);
/* Flush posted writes */
xhci_readl(xhci, &xhci->ir_set->irq_pending);
if (xhci->xhc_state & XHCI_STATE_DYING)
xhci_dbg(xhci, "xHCI dying, ignoring interrupt. "
"Shouldn't IRQs be disabled?\n");
else
/* FIXME this should be a delayed service routine
* that clears the EHB.
*/
xhci_handle_event(xhci);
/* Clear the event handler busy flag (RW1C); the event ring should be empty. */
temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue);
/* Flush posted writes -- FIXME is this necessary? */
xhci_readl(xhci, &xhci->ir_set->irq_pending);
}
/*-------------------------------------------------------------------------*/
/*
* xHCI spec says we can get an interrupt, and if the HC has an error condition,
* we might get bad data out of the event ring. Section 4.10.2.7 has a list of
* indicators of an event TRB error, but we check the status *first* to be safe.
*/
irqreturn_t xhci_irq(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
u32 temp, temp2;
union xhci_trb *trb;
spin_lock(&xhci->lock);
trb = xhci->event_ring->dequeue;
/* Check if the xHC generated the interrupt, or the irq is shared */
temp = xhci_readl(xhci, &xhci->op_regs->status);
temp2 = xhci_readl(xhci, &xhci->ir_set->irq_pending);
if (temp == 0xffffffff && temp2 == 0xffffffff)
goto hw_died;
if (!(temp & STS_EINT) && !ER_IRQ_PENDING(temp2)) {
spin_unlock(&xhci->lock);
return IRQ_NONE;
}
xhci_dbg(xhci, "op reg status = %08x\n", temp);
xhci_dbg(xhci, "ir set irq_pending = %08x\n", temp2);
xhci_dbg(xhci, "Event ring dequeue ptr:\n");
xhci_dbg(xhci, "@%llx %08x %08x %08x %08x\n",
(unsigned long long)xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, trb),
lower_32_bits(trb->link.segment_ptr),
upper_32_bits(trb->link.segment_ptr),
(unsigned int) trb->link.intr_target,
(unsigned int) trb->link.control);
if (temp & STS_FATAL) {
xhci_warn(xhci, "WARNING: Host System Error\n");
xhci_halt(xhci);
hw_died:
xhci_to_hcd(xhci)->state = HC_STATE_HALT;
spin_unlock(&xhci->lock);
return -ESHUTDOWN;
}
xhci_work(xhci);
spin_unlock(&xhci->lock);
return IRQ_HANDLED;
}
#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
void xhci_event_ring_work(unsigned long arg)
@ -423,21 +395,36 @@ int xhci_run(struct usb_hcd *hcd)
{
u32 temp;
u64 temp_64;
u32 ret;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
void (*doorbell)(struct xhci_hcd *) = NULL;
hcd->uses_new_polling = 1;
hcd->poll_rh = 0;
xhci_dbg(xhci, "xhci_run\n");
#if 0 /* FIXME: MSI not setup yet */
/* Do this at the very last minute */
ret = xhci_setup_msix(xhci);
if (!ret)
return ret;
/* unregister the legacy interrupt */
if (hcd->irq)
free_irq(hcd->irq, hcd);
hcd->irq = -1;
ret = xhci_setup_msix(xhci);
if (ret)
/* fall back to msi*/
ret = xhci_setup_msi(xhci);
if (ret) {
/* fall back to legacy interrupt*/
ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
hcd->irq_descr, hcd);
if (ret) {
xhci_err(xhci, "request interrupt %d failed\n",
pdev->irq);
return ret;
}
hcd->irq = pdev->irq;
}
return -ENOSYS;
#endif
#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
init_timer(&xhci->event_ring_timer);
xhci->event_ring_timer.data = (unsigned long) xhci;
@ -495,7 +482,6 @@ int xhci_run(struct usb_hcd *hcd)
return -ENODEV;
}
xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp);
if (doorbell)
(*doorbell)(xhci);
if (xhci->quirks & XHCI_NEC_HOST)
@ -522,11 +508,9 @@ void xhci_stop(struct usb_hcd *hcd)
spin_lock_irq(&xhci->lock);
xhci_halt(xhci);
xhci_reset(xhci);
xhci_cleanup_msix(xhci);
spin_unlock_irq(&xhci->lock);
#if 0 /* No MSI yet */
xhci_cleanup_msix(xhci);
#endif
#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
/* Tell the event ring poll function not to reschedule */
xhci->zombie = 1;
@ -560,11 +544,8 @@ void xhci_shutdown(struct usb_hcd *hcd)
spin_lock_irq(&xhci->lock);
xhci_halt(xhci);
spin_unlock_irq(&xhci->lock);
#if 0
xhci_cleanup_msix(xhci);
#endif
spin_unlock_irq(&xhci->lock);
xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n",
xhci_readl(xhci, &xhci->op_regs->status));
@ -720,7 +701,8 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
unsigned long flags;
int ret = 0;
unsigned int slot_id, ep_index;
struct urb_priv *urb_priv;
int size, i;
if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0)
return -EINVAL;
@ -734,12 +716,36 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
ret = -EINVAL;
goto exit;
}
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
if (!HCD_HW_ACCESSIBLE(hcd)) {
if (!in_interrupt())
xhci_dbg(xhci, "urb submitted during PCI suspend\n");
ret = -ESHUTDOWN;
goto exit;
}
if (usb_endpoint_xfer_isoc(&urb->ep->desc))
size = urb->number_of_packets;
else
size = 1;
urb_priv = kzalloc(sizeof(struct urb_priv) +
size * sizeof(struct xhci_td *), mem_flags);
if (!urb_priv)
return -ENOMEM;
for (i = 0; i < size; i++) {
urb_priv->td[i] = kzalloc(sizeof(struct xhci_td), mem_flags);
if (!urb_priv->td[i]) {
urb_priv->length = i;
xhci_urb_free_priv(xhci, urb_priv);
return -ENOMEM;
}
}
urb_priv->length = size;
urb_priv->td_cnt = 0;
urb->hcpriv = urb_priv;
if (usb_endpoint_xfer_control(&urb->ep->desc)) {
/* Check to see if the max packet size for the default control
* endpoint changed during FS device enumeration
@ -788,11 +794,18 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
slot_id, ep_index);
spin_unlock_irqrestore(&xhci->lock, flags);
} else {
ret = -EINVAL;
spin_lock_irqsave(&xhci->lock, flags);
if (xhci->xhc_state & XHCI_STATE_DYING)
goto dying;
ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
spin_unlock_irqrestore(&xhci->lock, flags);
}
exit:
return ret;
dying:
xhci_urb_free_priv(xhci, urb_priv);
urb->hcpriv = NULL;
xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for "
"non-responsive xHCI host.\n",
urb->ep->desc.bEndpointAddress, urb);
@ -800,6 +813,47 @@ dying:
return -ESHUTDOWN;
}
/* Get the right ring for the given URB.
* If the endpoint supports streams, boundary check the URB's stream ID.
* If the endpoint doesn't support streams, return the singular endpoint ring.
*/
static struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
struct urb *urb)
{
unsigned int slot_id;
unsigned int ep_index;
unsigned int stream_id;
struct xhci_virt_ep *ep;
slot_id = urb->dev->slot_id;
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
stream_id = urb->stream_id;
ep = &xhci->devs[slot_id]->eps[ep_index];
/* Common case: no streams */
if (!(ep->ep_state & EP_HAS_STREAMS))
return ep->ring;
if (stream_id == 0) {
xhci_warn(xhci,
"WARN: Slot ID %u, ep index %u has streams, "
"but URB has no stream ID.\n",
slot_id, ep_index);
return NULL;
}
if (stream_id < ep->stream_info->num_streams)
return ep->stream_info->stream_rings[stream_id];
xhci_warn(xhci,
"WARN: Slot ID %u, ep index %u has "
"stream IDs 1 to %u allocated, "
"but stream ID %u is requested.\n",
slot_id, ep_index,
ep->stream_info->num_streams - 1,
stream_id);
return NULL;
}
/*
* Remove the URB's TD from the endpoint ring. This may cause the HC to stop
* USB transfers, potentially stopping in the middle of a TRB buffer. The HC
@ -834,9 +888,10 @@ dying:
int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
unsigned long flags;
int ret;
int ret, i;
u32 temp;
struct xhci_hcd *xhci;
struct urb_priv *urb_priv;
struct xhci_td *td;
unsigned int ep_index;
struct xhci_ring *ep_ring;
@ -851,12 +906,12 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
temp = xhci_readl(xhci, &xhci->op_regs->status);
if (temp == 0xffffffff) {
xhci_dbg(xhci, "HW died, freeing TD.\n");
td = (struct xhci_td *) urb->hcpriv;
urb_priv = urb->hcpriv;
usb_hcd_unlink_urb_from_ep(hcd, urb);
spin_unlock_irqrestore(&xhci->lock, flags);
usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, -ESHUTDOWN);
kfree(td);
xhci_urb_free_priv(xhci, urb_priv);
return ret;
}
if (xhci->xhc_state & XHCI_STATE_DYING) {
@ -884,9 +939,14 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
xhci_dbg(xhci, "Endpoint ring:\n");
xhci_debug_ring(xhci, ep_ring);
td = (struct xhci_td *) urb->hcpriv;
list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list);
urb_priv = urb->hcpriv;
for (i = urb_priv->td_cnt; i < urb_priv->length; i++) {
td = urb_priv->td[i];
list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list);
}
/* Queue a stop endpoint command, but only if this is
* the first cancellation to be handled.
*/

View File

@ -720,6 +720,14 @@ struct xhci_virt_ep {
struct timer_list stop_cmd_timer;
int stop_cmds_pending;
struct xhci_hcd *xhci;
/*
* Sometimes the xHC can not process isochronous endpoint ring quickly
* enough, and it will miss some isoc tds on the ring and generate
* a Missed Service Error Event.
* Set skip flag when receive a Missed Service Error Event and
* process the missed tds on the endpoint ring.
*/
bool skip;
};
struct xhci_virt_device {
@ -911,6 +919,9 @@ struct xhci_event_cmd {
/* Control transfer TRB specific fields */
#define TRB_DIR_IN (1<<16)
/* Isochronous TRB specific fields */
#define TRB_SIA (1<<31)
struct xhci_generic_trb {
u32 field[4];
};
@ -1082,6 +1093,12 @@ struct xhci_scratchpad {
dma_addr_t *sp_dma_buffers;
};
struct urb_priv {
int length;
int td_cnt;
struct xhci_td *td[0];
};
/*
* Each segment table entry is 4*32bits long. 1K seems like an ok size:
* (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
@ -1130,7 +1147,7 @@ struct xhci_hcd {
int page_size;
/* Valid values are 12 to 20, inclusive */
int page_shift;
/* only one MSI vector for now, but might need more later */
/* msi-x vectors */
int msix_count;
struct msix_entry *msix_entries;
/* data structures */
@ -1327,11 +1344,6 @@ void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
struct xhci_ring *xhci_dma_to_transfer_ring(
struct xhci_virt_ep *ep,
u64 address);
struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci,
struct urb *urb);
struct xhci_ring *xhci_triad_to_transfer_ring(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
unsigned int stream_id);
struct xhci_ring *xhci_stream_id_to_ring(
struct xhci_virt_device *dev,
unsigned int ep_index,
@ -1339,6 +1351,7 @@ struct xhci_ring *xhci_stream_id_to_ring(
struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
bool allocate_in_ctx, bool allocate_completion,
gfp_t mem_flags);
void xhci_urb_free_priv(struct xhci_hcd *xhci, struct urb_priv *urb_priv);
void xhci_free_command(struct xhci_hcd *xhci,
struct xhci_command *command);
@ -1358,6 +1371,7 @@ void xhci_stop(struct usb_hcd *hcd);
void xhci_shutdown(struct usb_hcd *hcd);
int xhci_get_frame(struct usb_hcd *hcd);
irqreturn_t xhci_irq(struct usb_hcd *hcd);
irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd);
int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev);
void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev);
int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
@ -1386,8 +1400,6 @@ struct xhci_segment *trb_in_td(struct xhci_segment *start_seg,
int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code);
void xhci_ring_cmd_db(struct xhci_hcd *xhci);
void *xhci_setup_one_noop(struct xhci_hcd *xhci);
void xhci_handle_event(struct xhci_hcd *xhci);
void xhci_set_hc_event_deq(struct xhci_hcd *xhci);
int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id);
int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id);
@ -1401,6 +1413,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
int slot_id, unsigned int ep_index);
int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
int slot_id, unsigned int ep_index);
int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index);
int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id, bool command_must_succeed);
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,

View File

@ -650,7 +650,7 @@ static int ftdi_elan_open(struct inode *inode, struct file *file)
static int ftdi_elan_release(struct inode *inode, struct file *file)
{
struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data;
struct usb_ftdi *ftdi = file->private_data;
if (ftdi == NULL)
return -ENODEV;
up(&ftdi->sw_lock); /* decrement the count on our device */
@ -673,7 +673,7 @@ static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
int bytes_read = 0;
int retry_on_empty = 10;
int retry_on_timeout = 5;
struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data;
struct usb_ftdi *ftdi = file->private_data;
if (ftdi->disconnected > 0) {
return -ENODEV;
}

View File

@ -18,7 +18,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/usb/iowarrior.h>
@ -61,6 +61,7 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/* Module parameters */
static DEFINE_MUTEX(iowarrior_mutex);
static int debug = 0;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "debug=1 enables debugging messages");
@ -282,7 +283,7 @@ static ssize_t iowarrior_read(struct file *file, char __user *buffer,
int read_idx;
int offset;
dev = (struct iowarrior *)file->private_data;
dev = file->private_data;
/* verify that the device wasn't unplugged */
if (dev == NULL || !dev->present)
@ -348,7 +349,7 @@ static ssize_t iowarrior_write(struct file *file,
char *buf = NULL; /* for IOW24 and IOW56 we need a buffer */
struct urb *int_out_urb = NULL;
dev = (struct iowarrior *)file->private_data;
dev = file->private_data;
mutex_lock(&dev->mutex);
/* verify that the device wasn't unplugged */
@ -483,7 +484,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
int retval;
int io_res; /* checks for bytes read/written and copy_to/from_user results */
dev = (struct iowarrior *)file->private_data;
dev = file->private_data;
if (dev == NULL) {
return -ENODEV;
}
@ -493,7 +494,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
return -ENOMEM;
/* lock this object */
lock_kernel();
mutex_lock(&iowarrior_mutex);
mutex_lock(&dev->mutex);
/* verify that the device wasn't unplugged */
@ -585,7 +586,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
error_out:
/* unlock the device */
mutex_unlock(&dev->mutex);
unlock_kernel();
mutex_unlock(&iowarrior_mutex);
kfree(buffer);
return retval;
}
@ -602,12 +603,12 @@ static int iowarrior_open(struct inode *inode, struct file *file)
dbg("%s", __func__);
lock_kernel();
mutex_lock(&iowarrior_mutex);
subminor = iminor(inode);
interface = usb_find_interface(&iowarrior_driver, subminor);
if (!interface) {
unlock_kernel();
mutex_unlock(&iowarrior_mutex);
err("%s - error, can't find device for minor %d", __func__,
subminor);
return -ENODEV;
@ -617,7 +618,7 @@ static int iowarrior_open(struct inode *inode, struct file *file)
dev = usb_get_intfdata(interface);
if (!dev) {
mutex_unlock(&iowarrior_open_disc_lock);
unlock_kernel();
mutex_unlock(&iowarrior_mutex);
return -ENODEV;
}
@ -644,7 +645,7 @@ static int iowarrior_open(struct inode *inode, struct file *file)
out:
mutex_unlock(&dev->mutex);
unlock_kernel();
mutex_unlock(&iowarrior_mutex);
return retval;
}
@ -656,7 +657,7 @@ static int iowarrior_release(struct inode *inode, struct file *file)
struct iowarrior *dev;
int retval = 0;
dev = (struct iowarrior *)file->private_data;
dev = file->private_data;
if (dev == NULL) {
return -ENODEV;
}

Some files were not shown because too many files have changed in this diff Show More