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 0 -> resumed
(_UDC_ is the name of the USB Device Controller driver) (_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

@ -9,7 +9,7 @@ compatible with the USB 1.1 standard. It defines three transfer speeds:
- "Low Speed" 1.5 Mbit/sec - "Low Speed" 1.5 Mbit/sec
USB 1.1 only addressed full speed and low speed. High speed devices USB 1.1 only addressed full speed and low speed. High speed devices
can be used on USB 1.1 systems, but they slow down to USB 1.1 speeds. can be used on USB 1.1 systems, but they slow down to USB 1.1 speeds.
USB 1.1 devices may also be used on USB 2.0 systems. When plugged USB 1.1 devices may also be used on USB 2.0 systems. When plugged
into an EHCI controller, they are given to a USB 1.1 "companion" into an EHCI controller, they are given to a USB 1.1 "companion"

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 Installing the Windows Host ACM Driver
-------------------------------------- --------------------------------------
To use the Windows ACM driver you must have the files "gserial.inf" To use the Windows ACM driver you must have the "linux-cdc-acm.inf"
and "usbser.sys" together in a folder on the Windows machine. file (provided along this document) which supports all recent versions
of Windows.
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.)
When the gadget serial driver is loaded and the USB device connected When the gadget serial driver is loaded and the USB device connected
to the Windows host with a USB cable, Windows should recognize the 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 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 For example, on Windows XP, when the gadget serial device is first
plugged in, the "Found New Hardware Wizard" starts up. Select plugged in, the "Found New Hardware Wizard" starts up. Select
"Install from a list or specific location (Advanced)", then on "Install from a list or specific location (Advanced)", then on the
the next screen select "Include this location in the search" and next screen select "Include this location in the search" and enter the
enter the path or browse to the folder containing "gserial.inf" and path or browse to the folder containing the "linux-cdc-acm.inf" file.
"usbser.sys". Windows will complain that the Gadget Serial driver Windows will complain that the Gadget Serial driver has not passed
has not passed Windows Logo testing, but select "Continue anyway" Windows Logo testing, but select "Continue anyway" and finish the
and finish the driver installation. driver installation.
On Windows XP, in the "Device Manager" (under "Control Panel", On Windows XP, in the "Device Manager" (under "Control Panel",
"System", "Hardware") expand the "Ports (COM & LPT)" entry and you "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 side and host side systems. Anything you type on the terminal
window on the gadget side should appear in the terminal window on window on the gadget side should appear in the terminal window on
the host side and vice versa. the host side and vice versa.

View File

@ -10,7 +10,7 @@ immediately usable. That means the system must do many things, including:
- Bind a driver to that device. Bus frameworks do that using a - Bind a driver to that device. Bus frameworks do that using a
device driver's probe() routine. device driver's probe() routine.
- Tell other subsystems to configure the new device. Print - Tell other subsystems to configure the new device. Print
queues may need to be enabled, networks brought up, disk queues may need to be enabled, networks brought up, disk
partitions mounted, and so on. In some cases these will partitions mounted, and so on. In some cases these will
@ -84,7 +84,7 @@ USB MODUTILS SUPPORT
Current versions of module-init-tools will create a "modules.usbmap" file Current versions of module-init-tools will create a "modules.usbmap" file
which contains the entries from each driver's MODULE_DEVICE_TABLE. Such which contains the entries from each driver's MODULE_DEVICE_TABLE. Such
files can be used by various user mode policy agents to make sure all the files can be used by various user mode policy agents to make sure all the
right driver modules get loaded, either at boot time or later. right driver modules get loaded, either at boot time or later.
See <linux/usb.h> for full information about such table entries; or look See <linux/usb.h> for full information about such table entries; or look
at existing drivers. Each table entry describes one or more criteria to at existing drivers. Each table entry describes one or more criteria to

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 ; Based on template INF file found at
; Linux-USB Ethernet/RNDIS gadget firmware: ; <http://msdn.microsoft.com/en-us/library/ff570620.aspx>
; ; which was:
; - RNDIS plus CDC Ethernet ... this may be familiar as a DOCSIS ; Copyright (c) Microsoft Corporation
; cable modem profile, and supports most non-Microsoft USB hosts ; and released under the MLPL as found at:
; ; <http://msdn.microsoft.com/en-us/cc300389.aspx#MLPL>.
; - RNDIS plus CDC Subset ... used by hardware that incapable of ; For use only on Windows operating systems.
; 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
[Version] [Version]
Signature = "$CHICAGO$" Signature = "$Windows NT$"
Class = Net Class = Net
ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318} ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
Provider = %Linux% Provider = %Linux%
Compatible = 1 DriverVer = 06/21/2006,6.0.6000.16384
MillenniumPreferred = .ME
DriverVer = 03/30/2004,0.0.0.0
; catalog file would be used by WHQL
;CatalogFile = Linux.cat
[Manufacturer] [Manufacturer]
%Linux% = LinuxDevices,NT.5.1 %Linux% = LinuxDevices,NTx86,NTamd64,NTia64
[LinuxDevices] ; Decoration for x86 architecture
; NetChip IDs, used by both firmware modes [LinuxDevices.NTx86]
%LinuxDevice% = RNDIS, USB\VID_0525&PID_a4a2 %LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2, USB\VID_0525&PID_a4ab&MI_00
[LinuxDevices.NT.5.1] ; Decoration for x64 architecture
%LinuxDevice% = RNDIS.NT.5.1, USB\VID_0525&PID_a4a2 [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] [ControlFlags]
ExcludeFromSelect=* ExcludeFromSelect=*
; Windows 98, Windows 98 Second Edition specific sections -------- ; DDInstall section
; References the in-build Netrndis.inf
[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 -----------------------------------
[RNDIS.NT.5.1] [RNDIS.NT.5.1]
Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI Characteristics = 0x84 ; NCF_PHYSICAL + NCF_HAS_UI
BusType = 15 BusType = 15
DriverVer = 03/30/2004,0.0.0.0 ; NEVER REMOVE THE FOLLOWING REFERENCE FOR NETRNDIS.INF
AddReg = RNDIS_AddReg_NT, RNDIS_AddReg_Common include = netrndis.inf
; no copyfiles - the files are already in place needs = Usb_Rndis.ndi
AddReg = Rndis_AddReg_Vista
; DDInstal.Services section
[RNDIS.NT.5.1.Services] [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] ; Optional registry settings. You can modify as needed.
DisplayName = %ServiceDisplayName% [RNDIS_AddReg_Vista]
ServiceType = 1 HKR, NDI\params\VistaProperty, ParamDesc, 0, %Vista_Property%
StartType = 3 HKR, NDI\params\VistaProperty, type, 0, "edit"
ErrorControl = 1 HKR, NDI\params\VistaProperty, LimitText, 0, "12"
ServiceBinary = %12%\usb8023.sys HKR, NDI\params\VistaProperty, UpperCase, 0, "1"
LoadOrderGroup = NDIS HKR, NDI\params\VistaProperty, default, 0, " "
AddReg = RNDIS_WMI_AddReg_51 HKR, NDI\params\VistaProperty, optional, 0, "1"
[RNDIS_WMI_AddReg_51] ; No sys copyfiles - the sys files are already in-build
HKR, , MofImagePath, 0x00020000, "System32\drivers\rndismp.sys" ; (part of the operating system).
; We do not support XP SP1-, 2003 SP1-, ME, 9x.
; 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
[Strings] [Strings]
ServiceDisplayName = "USB Remote NDIS Network Device Driver"
NetworkAddress = "Network Address"
Linux = "Linux Developer Community" Linux = "Linux Developer Community"
LinuxDevice = "Linux USB Ethernet/RNDIS Gadget" 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 */ /* USB */
#if defined(CONFIG_USB_ULPI) #if defined(CONFIG_USB_ULPI)
usbotg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, 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, 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_otg_host, &usbotg_pdata);
mxc_register_device(&mxc_usbh2, &usbh2_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) static void lilly1131_usb_init(void)
{ {
usbotg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, 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, 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_usbh1, &usbh1_pdata);
mxc_register_device(&mxc_usbh2, &usbh2_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) #if defined(CONFIG_USB_ULPI)
/* USB */ /* USB */
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, 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); mxc_register_device(&mxc_usbh2, &usbh2_pdata);
#endif #endif

View File

@ -412,7 +412,7 @@ static struct mxc_usbh_platform_data usbh2_pdata = {
static int __init moboard_usbh2_init(void) static int __init moboard_usbh2_init(void)
{ {
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, 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); 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 defined(CONFIG_USB_ULPI)
if (otg_mode_host) { if (otg_mode_host) {
otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, 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); mxc_register_device(&mxc_otg_host, &otg_pdata);
} }
usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, 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); mxc_register_device(&mxc_usbh2, &usbh2_pdata);
#endif #endif

View File

@ -378,7 +378,7 @@ static void __init mxc_board_init(void)
#if defined(CONFIG_USB_ULPI) #if defined(CONFIG_USB_ULPI)
if (otg_mode_host) { if (otg_mode_host) {
otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, 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); 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) static int __init smartbot_otg_host_init(void)
{ {
otg_host_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops, 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); 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 S3C_HSOTG_REG(0x810)
#define S3C_DIEPMSK_TxFIFOEmpty (1 << 7)
#define S3C_DIEPMSK_INEPNakEffMsk (1 << 6) #define S3C_DIEPMSK_INEPNakEffMsk (1 << 6)
#define S3C_DIEPMSK_INTknEPMisMsk (1 << 5) #define S3C_DIEPMSK_INTknEPMisMsk (1 << 5)
#define S3C_DIEPMSK_INTknTXFEmpMsk (1 << 4) #define S3C_DIEPMSK_INTknTXFEmpMsk (1 << 4)
@ -371,6 +372,7 @@
#define S3C_DIEPDMA(_a) S3C_HSOTG_REG(0x914 + ((_a) * 0x20)) #define S3C_DIEPDMA(_a) S3C_HSOTG_REG(0x914 + ((_a) * 0x20))
#define S3C_DOEPDMA(_a) S3C_HSOTG_REG(0xB14 + ((_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)) #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); vhci = hcd_to_vhci(hcd);
spin_lock_irqsave(&vhci->lock, flags); 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"); usbip_dbg_vhci_rh("hw accessible flag in on?\n");
goto done; 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]; u32 prev_port_status[VHCI_NPORTS];
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) if (!HCD_HW_ACCESSIBLE(hcd))
return -ETIMEDOUT; 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__); dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
spin_lock_irq(&vhci->lock); spin_lock_irq(&vhci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { if (!HCD_HW_ACCESSIBLE(hcd)) {
rc = -ESHUTDOWN; rc = -ESHUTDOWN;
} else { } else {
/* vhci->rh_state = DUMMY_RH_RUNNING; /* 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_SERIAL) += serial/
obj-$(CONFIG_USB) += misc/ obj-$(CONFIG_USB) += misc/
obj-y += early/ obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/
obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += 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, static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
int* actual_length) int *actual_length)
{ {
struct timer_list timer; 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)); put_unaligned(cpu_to_le32(addr), (__le32 *)(buf + offb));
offb += 4; offb += 4;
addr += l; addr += l;
if(l) if (l)
memcpy(buf + offb, data + offd, l); memcpy(buf + offb, data + offd, l);
if (l < stride) if (l < stride)
memset(buf + offb + l, 0, stride - l); 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; offb = 0;
} }
} while(offd < size); } while (offd < size);
dbg("sent fw %#x", fw); dbg("sent fw %#x", fw);
ret = 0; ret = 0;
@ -1043,8 +1043,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
if (instance->modem_type->boot_rom_patch) { if (instance->modem_type->boot_rom_patch) {
val = cpu_to_le32(BR_ADDR); val = cpu_to_le32(BR_ADDR);
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4); 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); ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0);
} }
if (ret) { if (ret) {
@ -1068,7 +1067,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
} }
static int cxacru_find_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 usbatm_data *usbatm = instance->usbatm;
struct device *dev = &usbatm->usb_intf->dev; 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 .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; struct usb_interface *cur_intf;
int i; 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))) { if ((cur_intf = usb_ifnum_to_if(usb_dev, i))) {
usb_set_intfdata(cur_intf, NULL); usb_set_intfdata(cur_intf, NULL);
usb_driver_release_interface(&speedtch_usb_driver, cur_intf); usb_driver_release_interface(&speedtch_usb_driver, cur_intf);
@ -792,7 +794,7 @@ static int speedtch_bind(struct usbatm_data *usbatm,
/* claim all interfaces */ /* 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); cur_intf = usb_ifnum_to_if(usb_dev, i);
if ((i != ifnum) && cur_intf) { 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 */ 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; const struct usb_endpoint_descriptor *endpoint_desc = &desc->endpoint[i].desc;
if ((endpoint_desc->bEndpointAddress == target_address)) { if ((endpoint_desc->bEndpointAddress == target_address)) {

View File

@ -67,6 +67,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kernel.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
@ -2436,7 +2437,6 @@ UEA_ATTR(firmid, 0);
/* Retrieve the device End System Identifier (MAC) */ /* 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) static int uea_getesi(struct uea_softc *sc, u_char * esi)
{ {
unsigned char mac_str[2 * ETH_ALEN + 1]; 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; return 1;
for (i = 0; i < ETH_ALEN; i++) 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; return 0;
} }

View File

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

View File

@ -48,7 +48,7 @@
dev_warn(&(instance)->usb_intf->dev, \ dev_warn(&(instance)->usb_intf->dev, \
"failed assertion '%s' at line %d", \ "failed assertion '%s' at line %d", \
__stringify(x), __LINE__); \ __stringify(x), __LINE__); \
} while(0) } while (0)
#endif #endif
#define usb_err(instance, format, arg...) \ #define usb_err(instance, format, arg...) \
@ -59,7 +59,7 @@
dev_warn(&(instance)->usb_intf->dev , format , ## arg) dev_warn(&(instance)->usb_intf->dev , format , ## arg)
#ifdef DEBUG #ifdef DEBUG
#define usb_dbg(instance, format, arg...) \ #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 #else
#define usb_dbg(instance, format, arg...) \ #define usb_dbg(instance, format, arg...) \
do {} while (0) do {} while (0)
@ -104,21 +104,21 @@ struct usbatm_data;
/* /*
* Assuming all methods exist and succeed, they are called in this order: * 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 { struct usbatm_driver {
const char *driver_name; const char *driver_name;
/* init device ... can sleep, or cause probe() failure */ /* 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); const struct usb_device_id *id);
/* additional device initialization that is too slow to be done in probe() */ /* 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 */ /* 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 */ /* init ATM device ... can sleep, or cause ATM initialization failure */
int (*atm_start) (struct usbatm_data *, struct atm_dev *); 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 */ /* cleanup ATM device ... can sleep, but can't fail */
void (*atm_stop) (struct usbatm_data *, struct atm_dev *); void (*atm_stop) (struct usbatm_data *, struct atm_dev *);
int bulk_in; /* bulk rx endpoint */ int bulk_in; /* bulk rx endpoint */
int isoc_in; /* isochronous rx endpoint */ int isoc_in; /* isochronous rx endpoint */
int bulk_out; /* bulk tx endpoint */ int bulk_out; /* bulk tx endpoint */
unsigned rx_padding; unsigned rx_padding;
unsigned tx_padding; unsigned tx_padding;
@ -156,7 +156,7 @@ struct usbatm_channel {
struct usbatm_data { struct usbatm_data {
/****************** /******************
* public fields * * public fields *
******************/ ******************/
/* mini driver */ /* mini driver */
struct usbatm_driver *driver; struct usbatm_driver *driver;
@ -174,7 +174,7 @@ struct usbatm_data {
/******************************** /********************************
* private fields - do not use * * private fields - do not use *
********************************/ ********************************/
struct kref refcount; struct kref refcount;
struct mutex serialize; 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_device_id xusbatm_usb_ids[XUSBATM_DRIVERS_MAX + 1];
static struct usb_driver xusbatm_usb_driver; 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_host_interface *alt;
struct usb_interface *intf; struct usb_interface *intf;
int i, j; 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))) if ((intf = usb_dev->actconfig->interface[i]) && (alt = usb_altnum_to_altsetting(intf, altsetting)))
for (j = 0; j < alt->desc.bNumEndpoints; j++) for (j = 0; j < alt->desc.bNumEndpoints; j++)
if (alt->endpoint[j].desc.bEndpointAddress == ep) 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; 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) struct usb_interface *intf, int altsetting, int claim)
{ {
int ifnum = intf->altsetting->desc.bInterfaceNumber; int ifnum = intf->altsetting->desc.bInterfaceNumber;
@ -80,7 +80,7 @@ static int xusbatm_capture_intf (struct usbatm_data *usbatm, struct usb_device *
return 0; 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) { if (claimed) {
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
@ -147,7 +147,7 @@ static void xusbatm_unbind(struct usbatm_data *usbatm,
usb_dbg(usbatm, "%s entered\n", __func__); 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]; struct usb_interface *cur_intf = usb_dev->actconfig->interface[i];
if (cur_intf && (usb_get_intfdata(cur_intf) == usbatm)) { 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)) if (unlikely(hcd->state == HC_STATE_HALT))
return; return;
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) if (!HCD_HW_ACCESSIBLE(hcd))
return; return;
/* Handle Start of frame events */ /* Handle Start of frame events */
@ -282,7 +282,7 @@ static int c67x00_hcd_start(struct usb_hcd *hcd)
{ {
hcd->uses_new_polling = 1; hcd->uses_new_polling = 1;
hcd->state = HC_STATE_RUNNING; hcd->state = HC_STATE_RUNNING;
hcd->poll_rh = 1; set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
return 0; 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. * ->lock locks what interrupt accesses.
*/ */
struct usblp { struct usblp {
struct usb_device *dev; /* USB device */ struct usb_device *dev; /* USB device */
struct mutex wmut; struct mutex wmut;
struct mutex mut; struct mutex mut;
spinlock_t lock; /* locks rcomplete, wcomplete */ spinlock_t lock; /* locks rcomplete, wcomplete */
@ -169,7 +169,8 @@ struct usblp {
}; };
#ifdef DEBUG #ifdef DEBUG
static void usblp_dump(struct usblp *usblp) { static void usblp_dump(struct usblp *usblp)
{
int p; int p;
dbg("usblp=0x%p", usblp); dbg("usblp=0x%p", usblp);
@ -216,8 +217,8 @@ static const struct quirk_printer_struct quirk_printers[] = {
{ 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */ { 0x03f0, 0x0304, USBLP_QUIRK_BIDIR }, /* HP DeskJet 810C/812C */
{ 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */ { 0x03f0, 0x0404, USBLP_QUIRK_BIDIR }, /* HP DeskJet 830C */
{ 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */ { 0x03f0, 0x0504, USBLP_QUIRK_BIDIR }, /* HP DeskJet 885C */
{ 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */ { 0x03f0, 0x0604, USBLP_QUIRK_BIDIR }, /* HP DeskJet 840C */
{ 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */ { 0x03f0, 0x0804, USBLP_QUIRK_BIDIR }, /* HP DeskJet 816C */
{ 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */ { 0x03f0, 0x1104, USBLP_QUIRK_BIDIR }, /* HP Deskjet 959C */
{ 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */ { 0x0409, 0xefbe, USBLP_QUIRK_BIDIR }, /* NEC Picty900 (HP OEM) */
{ 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */ { 0x0409, 0xbef4, USBLP_QUIRK_BIDIR }, /* NEC Picty760 (HP OEM) */
@ -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. /* High byte has the interface index.
Low byte has the alternate setting. Low byte has the alternate setting.
*/ */
if ((request == USBLP_REQ_GET_ID) && (type == USB_TYPE_CLASS)) { if ((request == USBLP_REQ_GET_ID) && (type == USB_TYPE_CLASS))
index = (usblp->ifnum<<8)|usblp->protocol[usblp->current_protocol].alt_setting; index = (usblp->ifnum<<8)|usblp->protocol[usblp->current_protocol].alt_setting;
}
retval = usb_control_msg(usblp->dev, retval = usb_control_msg(usblp->dev,
dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), 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; return newerr;
} }
static int handle_bidir (struct usblp *usblp) static int handle_bidir(struct usblp *usblp)
{ {
if (usblp->bidir && usblp->used) { if (usblp->bidir && usblp->used) {
if (usblp_submit_read(usblp) < 0) if (usblp_submit_read(usblp) < 0)
@ -395,14 +395,13 @@ static int usblp_open(struct inode *inode, struct file *file)
if (minor < 0) if (minor < 0)
return -ENODEV; return -ENODEV;
mutex_lock (&usblp_mutex); mutex_lock(&usblp_mutex);
retval = -ENODEV; retval = -ENODEV;
intf = usb_find_interface(&usblp_driver, minor); intf = usb_find_interface(&usblp_driver, minor);
if (!intf) { if (!intf)
goto out; goto out;
} usblp = usb_get_intfdata(intf);
usblp = usb_get_intfdata (intf);
if (!usblp || !usblp->dev || !usblp->present) if (!usblp || !usblp->dev || !usblp->present)
goto out; goto out;
@ -433,18 +432,18 @@ static int usblp_open(struct inode *inode, struct file *file)
retval = -EIO; retval = -EIO;
} }
out: out:
mutex_unlock (&usblp_mutex); mutex_unlock(&usblp_mutex);
return retval; 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); printk(KERN_INFO "usblp%d: removed\n", usblp->minor);
kfree(usblp->readbuf); kfree(usblp->readbuf);
kfree (usblp->device_id_string); kfree(usblp->device_id_string);
kfree (usblp->statusbuf); kfree(usblp->statusbuf);
kfree (usblp); kfree(usblp);
} }
static void usblp_unlink_urbs(struct usblp *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; usblp->flags &= ~LP_ABORT;
mutex_lock (&usblp_mutex); mutex_lock(&usblp_mutex);
usblp->used = 0; usblp->used = 0;
if (usblp->present) { if (usblp->present) {
usblp_unlink_urbs(usblp); usblp_unlink_urbs(usblp);
usb_autopm_put_interface(usblp->intf); usb_autopm_put_interface(usblp->intf);
} else /* finish cleanup from disconnect */ } else /* finish cleanup from disconnect */
usblp_cleanup (usblp); usblp_cleanup(usblp);
mutex_unlock (&usblp_mutex); mutex_unlock(&usblp_mutex);
return 0; return 0;
} }
@ -495,190 +494,190 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int twoints[2]; int twoints[2];
int retval = 0; int retval = 0;
mutex_lock (&usblp->mut); mutex_lock(&usblp->mut);
if (!usblp->present) { if (!usblp->present) {
retval = -ENODEV; retval = -ENODEV;
goto done; goto done;
} }
dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd), 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 */ if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */
switch (_IOC_NR(cmd)) { switch (_IOC_NR(cmd)) {
case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */ case IOCNR_GET_DEVICE_ID: /* get the DEVICE_ID string */
if (_IOC_DIR(cmd) != _IOC_READ) { if (_IOC_DIR(cmd) != _IOC_READ) {
retval = -EINVAL; retval = -EINVAL;
goto done; goto done;
} }
length = usblp_cache_device_id_string(usblp); length = usblp_cache_device_id_string(usblp);
if (length < 0) { if (length < 0) {
retval = length; retval = length;
goto done; goto done;
} }
if (length > _IOC_SIZE(cmd)) if (length > _IOC_SIZE(cmd))
length = _IOC_SIZE(cmd); /* truncate */ length = _IOC_SIZE(cmd); /* truncate */
if (copy_to_user((void __user *) arg, if (copy_to_user((void __user *) arg,
usblp->device_id_string, usblp->device_id_string,
(unsigned long) length)) { (unsigned long) length)) {
retval = -EFAULT; retval = -EFAULT;
goto done; goto done;
} }
break; break;
case IOCNR_GET_PROTOCOLS: case IOCNR_GET_PROTOCOLS:
if (_IOC_DIR(cmd) != _IOC_READ || if (_IOC_DIR(cmd) != _IOC_READ ||
_IOC_SIZE(cmd) < sizeof(twoints)) { _IOC_SIZE(cmd) < sizeof(twoints)) {
retval = -EINVAL; retval = -EINVAL;
goto done; goto done;
} }
twoints[0] = usblp->current_protocol; twoints[0] = usblp->current_protocol;
twoints[1] = 0; twoints[1] = 0;
for (i = USBLP_FIRST_PROTOCOL; for (i = USBLP_FIRST_PROTOCOL;
i <= USBLP_LAST_PROTOCOL; i++) { i <= USBLP_LAST_PROTOCOL; i++) {
if (usblp->protocol[i].alt_setting >= 0) if (usblp->protocol[i].alt_setting >= 0)
twoints[1] |= (1<<i); twoints[1] |= (1<<i);
} }
if (copy_to_user((void __user *)arg, if (copy_to_user((void __user *)arg,
(unsigned char *)twoints, (unsigned char *)twoints,
sizeof(twoints))) { sizeof(twoints))) {
retval = -EFAULT; retval = -EFAULT;
goto done; goto done;
} }
break; break;
case IOCNR_SET_PROTOCOL: case IOCNR_SET_PROTOCOL:
if (_IOC_DIR(cmd) != _IOC_WRITE) { if (_IOC_DIR(cmd) != _IOC_WRITE) {
retval = -EINVAL; retval = -EINVAL;
goto done; goto done;
} }
#ifdef DEBUG #ifdef DEBUG
if (arg == -10) { if (arg == -10) {
usblp_dump(usblp); usblp_dump(usblp);
break; break;
} }
#endif #endif
usblp_unlink_urbs(usblp); usblp_unlink_urbs(usblp);
retval = usblp_set_protocol(usblp, arg); retval = usblp_set_protocol(usblp, arg);
if (retval < 0) { if (retval < 0) {
usblp_set_protocol(usblp, usblp_set_protocol(usblp,
usblp->current_protocol); usblp->current_protocol);
} }
break; break;
case IOCNR_HP_SET_CHANNEL: case IOCNR_HP_SET_CHANNEL:
if (_IOC_DIR(cmd) != _IOC_WRITE || if (_IOC_DIR(cmd) != _IOC_WRITE ||
le16_to_cpu(usblp->dev->descriptor.idVendor) != 0x03F0 || le16_to_cpu(usblp->dev->descriptor.idVendor) != 0x03F0 ||
usblp->quirks & USBLP_QUIRK_BIDIR) { usblp->quirks & USBLP_QUIRK_BIDIR) {
retval = -EINVAL; retval = -EINVAL;
goto done; goto done;
} }
err = usblp_hp_channel_change_request(usblp, err = usblp_hp_channel_change_request(usblp,
arg, &newChannel); arg, &newChannel);
if (err < 0) { if (err < 0) {
dev_err(&usblp->dev->dev, dev_err(&usblp->dev->dev,
"usblp%d: error = %d setting " "usblp%d: error = %d setting "
"HP channel\n", "HP channel\n",
usblp->minor, err); usblp->minor, err);
retval = -EIO; retval = -EIO;
goto done; goto done;
} }
dbg("usblp%d requested/got HP channel %ld/%d", dbg("usblp%d requested/got HP channel %ld/%d",
usblp->minor, arg, newChannel); usblp->minor, arg, newChannel);
break; break;
case IOCNR_GET_BUS_ADDRESS: case IOCNR_GET_BUS_ADDRESS:
if (_IOC_DIR(cmd) != _IOC_READ || if (_IOC_DIR(cmd) != _IOC_READ ||
_IOC_SIZE(cmd) < sizeof(twoints)) { _IOC_SIZE(cmd) < sizeof(twoints)) {
retval = -EINVAL; retval = -EINVAL;
goto done; goto done;
} }
twoints[0] = usblp->dev->bus->busnum; twoints[0] = usblp->dev->bus->busnum;
twoints[1] = usblp->dev->devnum; twoints[1] = usblp->dev->devnum;
if (copy_to_user((void __user *)arg, if (copy_to_user((void __user *)arg,
(unsigned char *)twoints, (unsigned char *)twoints,
sizeof(twoints))) { sizeof(twoints))) {
retval = -EFAULT; retval = -EFAULT;
goto done; goto done;
} }
dbg("usblp%d is bus=%d, device=%d", dbg("usblp%d is bus=%d, device=%d",
usblp->minor, twoints[0], twoints[1]); usblp->minor, twoints[0], twoints[1]);
break; break;
case IOCNR_GET_VID_PID: case IOCNR_GET_VID_PID:
if (_IOC_DIR(cmd) != _IOC_READ || if (_IOC_DIR(cmd) != _IOC_READ ||
_IOC_SIZE(cmd) < sizeof(twoints)) { _IOC_SIZE(cmd) < sizeof(twoints)) {
retval = -EINVAL; retval = -EINVAL;
goto done; goto done;
} }
twoints[0] = le16_to_cpu(usblp->dev->descriptor.idVendor); twoints[0] = le16_to_cpu(usblp->dev->descriptor.idVendor);
twoints[1] = le16_to_cpu(usblp->dev->descriptor.idProduct); twoints[1] = le16_to_cpu(usblp->dev->descriptor.idProduct);
if (copy_to_user((void __user *)arg, if (copy_to_user((void __user *)arg,
(unsigned char *)twoints, (unsigned char *)twoints,
sizeof(twoints))) { sizeof(twoints))) {
retval = -EFAULT; retval = -EFAULT;
goto done; goto done;
} }
dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X", dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X",
usblp->minor, twoints[0], twoints[1]); usblp->minor, twoints[0], twoints[1]);
break; break;
case IOCNR_SOFT_RESET: case IOCNR_SOFT_RESET:
if (_IOC_DIR(cmd) != _IOC_NONE) { if (_IOC_DIR(cmd) != _IOC_NONE) {
retval = -EINVAL; retval = -EINVAL;
goto done; goto done;
} }
retval = usblp_reset(usblp); retval = usblp_reset(usblp);
break; break;
default: default:
retval = -ENOTTY; retval = -ENOTTY;
} }
else /* old-style ioctl value */ else /* old-style ioctl value */
switch (cmd) { switch (cmd) {
case LPGETSTATUS: case LPGETSTATUS:
if ((retval = usblp_read_status(usblp, usblp->statusbuf))) { if ((retval = usblp_read_status(usblp, usblp->statusbuf))) {
if (printk_ratelimit()) if (printk_ratelimit())
printk(KERN_ERR "usblp%d:" printk(KERN_ERR "usblp%d:"
"failed reading printer status (%d)\n", "failed reading printer status (%d)\n",
usblp->minor, retval); usblp->minor, retval);
retval = -EIO; retval = -EIO;
goto done; goto done;
} }
status = *usblp->statusbuf; status = *usblp->statusbuf;
if (copy_to_user ((void __user *)arg, &status, sizeof(int))) if (copy_to_user((void __user *)arg, &status, sizeof(int)))
retval = -EFAULT; retval = -EFAULT;
break; break;
case LPABORT: case LPABORT:
if (arg) if (arg)
usblp->flags |= LP_ABORT; usblp->flags |= LP_ABORT;
else else
usblp->flags &= ~LP_ABORT; usblp->flags &= ~LP_ABORT;
break; break;
default: default:
retval = -ENOTTY; retval = -ENOTTY;
} }
done: done:
mutex_unlock (&usblp->mut); mutex_unlock(&usblp->mut);
return retval; return retval;
} }
@ -840,7 +839,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, lo
} }
done: done:
mutex_unlock (&usblp->mut); mutex_unlock(&usblp->mut);
return count; return count;
} }
@ -1023,7 +1022,7 @@ raise_urb:
* while you are sending print data, and you don't try to query the * 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. * 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; int i;
@ -1031,7 +1030,7 @@ static unsigned int usblp_quirks (__u16 vendor, __u16 product)
if (vendor == quirk_printers[i].vendorId && if (vendor == quirk_printers[i].vendorId &&
product == quirk_printers[i].productId) product == quirk_printers[i].productId)
return quirk_printers[i].quirks; return quirk_printers[i].quirks;
} }
return 0; 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) 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 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 && if (usblp->device_id_string[0] == 0 &&
usblp->device_id_string[1] == 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, static int usblp_probe(struct usb_interface *intf,
const struct usb_device_id *id) 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; struct usblp *usblp;
int protocol; int protocol;
int retval; int retval;
@ -1089,7 +1088,7 @@ static int usblp_probe(struct usb_interface *intf,
} }
usblp->dev = dev; usblp->dev = dev;
mutex_init(&usblp->wmut); mutex_init(&usblp->wmut);
mutex_init (&usblp->mut); mutex_init(&usblp->mut);
spin_lock_init(&usblp->lock); spin_lock_init(&usblp->lock);
init_waitqueue_head(&usblp->rwait); init_waitqueue_head(&usblp->rwait);
init_waitqueue_head(&usblp->wwait); init_waitqueue_head(&usblp->wwait);
@ -1153,7 +1152,7 @@ static int usblp_probe(struct usb_interface *intf,
usblp_check_status(usblp, 0); usblp_check_status(usblp, 0);
#endif #endif
usb_set_intfdata (intf, usblp); usb_set_intfdata(intf, usblp);
usblp->present = 1; usblp->present = 1;
@ -1177,7 +1176,7 @@ static int usblp_probe(struct usb_interface *intf,
return 0; return 0;
abort_intfdata: abort_intfdata:
usb_set_intfdata (intf, NULL); usb_set_intfdata(intf, NULL);
device_remove_file(&intf->dev, &dev_attr_ieee1284_id); device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
abort: abort:
kfree(usblp->readbuf); 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) 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); usb_deregister_dev(intf, &usblp_class);
if (!usblp || !usblp->dev) { if (!usblp || !usblp->dev) {
dev_err(&intf->dev, "bogus disconnect\n"); dev_err(&intf->dev, "bogus disconnect\n");
BUG (); BUG();
} }
device_remove_file(&intf->dev, &dev_attr_ieee1284_id); device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
mutex_lock (&usblp_mutex); mutex_lock(&usblp_mutex);
mutex_lock (&usblp->mut); mutex_lock(&usblp->mut);
usblp->present = 0; usblp->present = 0;
wake_up(&usblp->wwait); wake_up(&usblp->wwait);
wake_up(&usblp->rwait); wake_up(&usblp->rwait);
usb_set_intfdata (intf, NULL); usb_set_intfdata(intf, NULL);
usblp_unlink_urbs(usblp); usblp_unlink_urbs(usblp);
mutex_unlock (&usblp->mut); mutex_unlock(&usblp->mut);
if (!usblp->used) if (!usblp->used)
usblp_cleanup (usblp); usblp_cleanup(usblp);
mutex_unlock (&usblp_mutex); mutex_unlock(&usblp_mutex);
} }
static int usblp_suspend(struct usb_interface *intf, pm_message_t message) 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); usblp_unlink_urbs(usblp);
#if 0 /* XXX Do we want this? What if someone is reading, should we fail? */ #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) static int usblp_resume(struct usb_interface *intf)
{ {
struct usblp *usblp = usb_get_intfdata (intf); struct usblp *usblp = usb_get_intfdata(intf);
int r; int r;
r = handle_bidir (usblp); r = handle_bidir(usblp);
return r; return r;
} }
@ -1401,7 +1400,7 @@ static const struct usb_device_id usblp_ids[] = {
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
MODULE_DEVICE_TABLE (usb, usblp_ids); MODULE_DEVICE_TABLE(usb, usblp_ids);
static struct usb_driver usblp_driver = { static struct usb_driver usblp_driver = {
.name = "usblp", .name = "usblp",
@ -1426,8 +1425,8 @@ static void __exit usblp_exit(void)
module_init(usblp_init); module_init(usblp_init);
module_exit(usblp_exit); module_exit(usblp_exit);
MODULE_AUTHOR( DRIVER_AUTHOR ); MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION( DRIVER_DESC ); MODULE_DESCRIPTION(DRIVER_DESC);
module_param(proto_bias, int, S_IRUGO | S_IWUSR); module_param(proto_bias, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(proto_bias, "Favourite protocol number"); MODULE_PARM_DESC(proto_bias, "Favourite protocol number");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

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

View File

@ -1742,9 +1742,8 @@ static int usb_runtime_suspend(struct device *dev)
} }
/* Prevent the parent from suspending immediately after */ /* Prevent the parent from suspending immediately after */
else if (udev->parent) { else if (udev->parent)
udev->parent->last_busy = jiffies; udev->parent->last_busy = jiffies;
}
} }
/* Runtime suspend for a USB interface doesn't mean anything. */ /* Runtime suspend for a USB interface doesn't mean anything. */
@ -1786,21 +1785,19 @@ static int usb_runtime_idle(struct device *dev)
return 0; 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_suspend = usb_runtime_suspend,
.runtime_resume = usb_runtime_resume, .runtime_resume = usb_runtime_resume,
.runtime_idle = usb_runtime_idle, .runtime_idle = usb_runtime_idle,
}; };
#else
#define usb_bus_pm_ops (*(struct dev_pm_ops *) NULL)
#endif /* CONFIG_USB_SUSPEND */ #endif /* CONFIG_USB_SUSPEND */
struct bus_type usb_bus_type = { struct bus_type usb_bus_type = {
.name = "usb", .name = "usb",
.match = usb_device_match, .match = usb_device_match,
.uevent = usb_uevent, .uevent = usb_uevent,
#ifdef CONFIG_USB_SUSPEND
.pm = &usb_bus_pm_ops, .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)) { switch (usb_endpoint_type(ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL: 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; interval = ep->desc->bInterval;
break; break;
case USB_ENDPOINT_XFER_ISOC: case USB_ENDPOINT_XFER_ISOC:
interval = 1 << (ep->desc->bInterval - 1); interval = 1 << (ep->desc->bInterval - 1);
break; break;
case USB_ENDPOINT_XFER_BULK: 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; interval = ep->desc->bInterval;
break; break;
case USB_ENDPOINT_XFER_INT: case USB_ENDPOINT_XFER_INT:
if (ep->udev->speed == USB_SPEED_HIGH) if (ep->udev->speed == USB_SPEED_HIGH)
interval = 1 << (ep->desc->bInterval - 1); 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 /* When the first config's first interface is one of Microsoft's
* pet nonstandard Ethernet-over-USB protocols, ignore it unless * pet nonstandard Ethernet-over-USB protocols, ignore it unless
* this kernel has enabled the necessary host side driver. * 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) #if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
continue; continue;
#else #else

View File

@ -66,10 +66,7 @@ static void companion_common(struct pci_dev *pdev, struct usb_hcd *hcd,
* vice versa. * vice versa.
*/ */
companion = NULL; companion = NULL;
for (;;) { for_each_pci_dev(companion) {
companion = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, companion);
if (!companion)
break;
if (companion->bus != pdev->bus || if (companion->bus != pdev->bus ||
PCI_SLOT(companion->devfn) != slot) PCI_SLOT(companion->devfn) != slot)
continue; continue;
@ -250,6 +247,9 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (retval != 0) if (retval != 0)
goto err4; goto err4;
set_hs_companion(dev, hcd); set_hs_companion(dev, hcd);
if (pci_dev_run_wake(dev))
pm_runtime_put_noidle(&dev->dev);
return retval; return retval;
err4: err4:
@ -292,6 +292,17 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
if (!hcd) if (!hcd)
return; 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); usb_remove_hcd(hcd);
if (hcd->driver->flags & HCD_MEMORY) { if (hcd->driver->flags & HCD_MEMORY) {
iounmap(hcd->regs); iounmap(hcd->regs);
@ -317,12 +328,34 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev)
if (!hcd) if (!hcd)
return; return;
if (hcd->driver->shutdown) if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) &&
hcd->driver->shutdown)
hcd->driver->shutdown(hcd); hcd->driver->shutdown(hcd);
} }
EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown); 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) static int check_root_hub_suspended(struct device *dev)
{ {
@ -337,7 +370,7 @@ static int check_root_hub_suspended(struct device *dev)
return 0; 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 pci_dev *pci_dev = to_pci_dev(dev);
struct usb_hcd *hcd = pci_get_drvdata(pci_dev); struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
@ -352,13 +385,21 @@ static int hcd_pci_suspend(struct device *dev)
if (retval) if (retval)
return 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) { 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); 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) if (retval)
return retval; return retval;
} }
@ -374,6 +415,48 @@ static int hcd_pci_suspend(struct device *dev)
return retval; 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) static int hcd_pci_suspend_noirq(struct device *dev)
{ {
struct pci_dev *pci_dev = to_pci_dev(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; return retval;
} }
#ifdef CONFIG_PPC_PMAC powermac_set_asic(pci_dev, 0);
/* 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
return retval; return retval;
} }
@ -425,69 +499,63 @@ static int hcd_pci_resume_noirq(struct device *dev)
{ {
struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_dev *pci_dev = to_pci_dev(dev);
#ifdef CONFIG_PPC_PMAC powermac_set_asic(pci_dev, 1);
/* 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
/* Go back to D0 and disable remote wakeup */ /* Go back to D0 and disable remote wakeup */
pci_back_from_sleep(pci_dev); pci_back_from_sleep(pci_dev);
return 0; 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) 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) 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 = { const struct dev_pm_ops usb_hcd_pci_pm_ops = {
.suspend = hcd_pci_suspend, .suspend = hcd_pci_suspend,
.suspend_noirq = hcd_pci_suspend_noirq, .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, .poweroff_noirq = hcd_pci_suspend_noirq,
.restore_noirq = hcd_pci_resume_noirq, .restore_noirq = hcd_pci_resume_noirq,
.restore = hcd_pci_restore, .restore = hcd_pci_restore,
.runtime_suspend = hcd_pci_runtime_suspend,
.runtime_resume = hcd_pci_runtime_resume,
}; };
EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops); 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; unsigned long flags;
char buffer[6]; /* Any root hubs with > 31 ports? */ char buffer[6]; /* Any root hubs with > 31 ports? */
if (unlikely(!hcd->rh_registered)) if (unlikely(!hcd->rh_pollable))
return; return;
if (!hcd->uses_new_polling && !hcd->status_urb) if (!hcd->uses_new_polling && !hcd->status_urb)
return; return;
@ -679,7 +679,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
spin_lock_irqsave(&hcd_root_hub_lock, flags); spin_lock_irqsave(&hcd_root_hub_lock, flags);
urb = hcd->status_urb; urb = hcd->status_urb;
if (urb) { if (urb) {
hcd->poll_pending = 0; clear_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
hcd->status_urb = NULL; hcd->status_urb = NULL;
urb->actual_length = length; urb->actual_length = length;
memcpy(urb->transfer_buffer, buffer, 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); spin_lock(&hcd_root_hub_lock);
} else { } else {
length = 0; length = 0;
hcd->poll_pending = 1; set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
} }
spin_unlock_irqrestore(&hcd_root_hub_lock, 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 * 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 * 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 */ * 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)) (length == 0 && hcd->status_urb != NULL))
mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4)); 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)); mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
/* If a status change has already occurred, report it ASAP */ /* 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); mod_timer(&hcd->rh_timer, jiffies);
retval = 0; retval = 0;
done: 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() * finish unlinking the initial failed usb_set_address()
* or device descriptor fetch. * or device descriptor fetch.
*/ */
if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) && if (!HCD_SAW_IRQ(hcd) && !is_root_hub(urb->dev)) {
!is_root_hub(urb->dev)) {
dev_warn(hcd->self.controller, "Unlink after no-IRQ? " dev_warn(hcd->self.controller, "Unlink after no-IRQ? "
"Controller is probably using the wrong IRQ.\n"); "Controller is probably using the wrong IRQ.\n");
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
@ -1219,6 +1218,11 @@ static int hcd_alloc_coherent(struct usb_bus *bus,
{ {
unsigned char *vaddr; unsigned char *vaddr;
if (*vaddr_handle == NULL) {
WARN_ON_ONCE(1);
return -EFAULT;
}
vaddr = hcd_buffer_alloc(bus, size + sizeof(vaddr), vaddr = hcd_buffer_alloc(bus, size + sizeof(vaddr),
mem_flags, dma_handle); mem_flags, dma_handle);
if (!vaddr) 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", dev_dbg(&rhdev->dev, "usb %s%s\n",
(msg.event & PM_EVENT_AUTO ? "auto-" : ""), "resume"); (msg.event & PM_EVENT_AUTO ? "auto-" : ""), "resume");
clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
if (!hcd->driver->bus_resume) if (!hcd->driver->bus_resume)
return -ENOENT; return -ENOENT;
if (hcd->state == HC_STATE_RUNNING) if (hcd->state == HC_STATE_RUNNING)
@ -1994,8 +1999,10 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
unsigned long flags; unsigned long flags;
spin_lock_irqsave (&hcd_root_hub_lock, 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); queue_work(pm_wq, &hcd->wakeup_work);
}
spin_unlock_irqrestore (&hcd_root_hub_lock, flags); spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
} }
EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub); 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); local_irq_save(flags);
if (unlikely(hcd->state == HC_STATE_HALT || if (unlikely(hcd->state == HC_STATE_HALT || !HCD_HW_ACCESSIBLE(hcd))) {
!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
rc = IRQ_NONE; rc = IRQ_NONE;
} else if (hcd->driver->irq(hcd) == IRQ_NONE) { } else if (hcd->driver->irq(hcd) == IRQ_NONE) {
rc = IRQ_NONE; rc = IRQ_NONE;
@ -2079,6 +2085,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
local_irq_restore(flags); local_irq_restore(flags);
return rc; 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); spin_lock_irqsave (&hcd_root_hub_lock, flags);
if (hcd->rh_registered) { if (hcd->rh_registered) {
hcd->poll_rh = 0; clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
/* make khubd clean up old urbs and devices */ /* make khubd clean up old urbs and devices */
usb_set_device_state (hcd->self.root_hub, usb_set_device_state (hcd->self.root_hub,
@ -2217,6 +2224,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
retval = -ENOMEM; retval = -ENOMEM;
goto err_allocate_root_hub; goto err_allocate_root_hub;
} }
hcd->self.root_hub = rhdev;
switch (hcd->driver->flags & HCD_MASK) { switch (hcd->driver->flags & HCD_MASK) {
case HCD_USB11: case HCD_USB11:
@ -2229,9 +2237,8 @@ int usb_add_hcd(struct usb_hcd *hcd,
rhdev->speed = USB_SPEED_SUPER; rhdev->speed = USB_SPEED_SUPER;
break; break;
default: 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, /* wakeup flag init defaults to "everything works" for root hubs,
* but drivers can override it in reset() if needed, along with * 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"); dev_err(hcd->self.controller, "can't setup\n");
goto err_hcd_driver_setup; goto err_hcd_driver_setup;
} }
hcd->rh_pollable = 1;
/* NOTE: root hub and controller capabilities may not be the same */ /* NOTE: root hub and controller capabilities may not be the same */
if (device_can_wakeup(hcd->self.controller) if (device_can_wakeup(hcd->self.controller)
@ -2300,23 +2308,38 @@ int usb_add_hcd(struct usb_hcd *hcd,
retval); retval);
goto error_create_attr_group; 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); usb_hcd_poll_rh_status(hcd);
return retval; return retval;
error_create_attr_group: 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); 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); mutex_unlock(&usb_bus_list_lock);
err_register_root_hub: 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->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: err_hcd_driver_start:
if (hcd->irq >= 0) if (hcd->irq >= 0)
free_irq(irqnum, hcd); free_irq(irqnum, hcd);
err_request_irq: err_request_irq:
err_hcd_driver_setup: err_hcd_driver_setup:
hcd->self.root_hub = NULL; err_set_rh_speed:
usb_put_dev(rhdev); usb_put_dev(hcd->self.root_hub);
err_allocate_root_hub: err_allocate_root_hub:
usb_deregister_bus(&hcd->self); usb_deregister_bus(&hcd->self);
err_register_bus: err_register_bus:
@ -2335,8 +2358,13 @@ EXPORT_SYMBOL_GPL(usb_add_hcd);
*/ */
void usb_remove_hcd(struct usb_hcd *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); 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)) if (HC_IS_RUNNING (hcd->state))
hcd->state = HC_STATE_QUIESCING; hcd->state = HC_STATE_QUIESCING;
@ -2349,19 +2377,30 @@ void usb_remove_hcd(struct usb_hcd *hcd)
cancel_work_sync(&hcd->wakeup_work); cancel_work_sync(&hcd->wakeup_work);
#endif #endif
sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
mutex_lock(&usb_bus_list_lock); 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); 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->driver->stop(hcd);
hcd->state = HC_STATE_HALT; 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); del_timer_sync(&hcd->rh_timer);
if (hcd->irq >= 0) if (hcd->irq >= 0)
free_irq(hcd->irq, hcd); free_irq(hcd->irq, hcd);
usb_put_dev(hcd->self.root_hub);
usb_deregister_bus(&hcd->self); usb_deregister_bus(&hcd->self);
hcd_buffer_destroy(hcd); hcd_buffer_destroy(hcd);
} }

View File

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

View File

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

View File

@ -38,6 +38,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Creative SB Audigy 2 NX */ /* Creative SB Audigy 2 NX */
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, { 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 */ /* Philips PSC805 audio device */
{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME }, { 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); 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 * usb_unanchor_urb - unanchors an URB
* @urb: pointer to the urb to anchor * @urb: pointer to the urb to anchor
@ -156,17 +166,14 @@ void usb_unanchor_urb(struct urb *urb)
return; return;
spin_lock_irqsave(&anchor->lock, flags); spin_lock_irqsave(&anchor->lock, flags);
if (unlikely(anchor != urb->anchor)) { /*
/* we've lost the race to another thread */ * At this point, we could be competing with another thread which
spin_unlock_irqrestore(&anchor->lock, flags); * has the same intention. To protect the urb from being unanchored
return; * twice, only the winner of the race gets the job.
} */
urb->anchor = NULL; if (likely(anchor == urb->anchor))
list_del(&urb->anchor_list); __usb_unanchor_urb(urb, anchor);
spin_unlock_irqrestore(&anchor->lock, flags); 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); 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) void usb_unlink_anchored_urbs(struct usb_anchor *anchor)
{ {
struct urb *victim; struct urb *victim;
unsigned long flags;
spin_lock_irqsave(&anchor->lock, flags); while ((victim = usb_get_from_anchor(anchor)) != NULL) {
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 */
usb_unlink_urb(victim); usb_unlink_urb(victim);
usb_put_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); 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, victim = list_entry(anchor->urb_list.next, struct urb,
anchor_list); anchor_list);
usb_get_urb(victim); usb_get_urb(victim);
spin_unlock_irqrestore(&anchor->lock, flags); __usb_unanchor_urb(victim, anchor);
usb_unanchor_urb(victim);
} else { } else {
spin_unlock_irqrestore(&anchor->lock, flags);
victim = NULL; victim = NULL;
} }
spin_unlock_irqrestore(&anchor->lock, flags);
return victim; return victim;
} }
@ -826,12 +823,7 @@ void usb_scuttle_anchored_urbs(struct usb_anchor *anchor)
while (!list_empty(&anchor->urb_list)) { while (!list_empty(&anchor->urb_list)) {
victim = list_entry(anchor->urb_list.prev, struct urb, victim = list_entry(anchor->urb_list.prev, struct urb,
anchor_list); anchor_list);
usb_get_urb(victim); __usb_unanchor_urb(victim, anchor);
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);
} }
spin_unlock_irqrestore(&anchor->lock, flags); 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, .restore = usb_dev_restore,
}; };
#else
#define usb_device_pm_ops (*(struct dev_pm_ops *) NULL)
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
@ -338,7 +334,9 @@ struct device_type usb_device_type = {
.release = usb_release_dev, .release = usb_release_dev,
.uevent = usb_dev_uevent, .uevent = usb_dev_uevent,
.devnode = usb_devnode, .devnode = usb_devnode,
#ifdef CONFIG_PM
.pm = &usb_device_pm_ops, .pm = &usb_device_pm_ops,
#endif
}; };

View File

@ -714,6 +714,7 @@ config USB_GADGETFS
config USB_FUNCTIONFS config USB_FUNCTIONFS
tristate "Function Filesystem (EXPERIMENTAL)" tristate "Function Filesystem (EXPERIMENTAL)"
depends on EXPERIMENTAL depends on EXPERIMENTAL
select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)
help help
The Function Filesystem (FunctioFS) lets one create USB The Function Filesystem (FunctioFS) lets one create USB
composite functions in user space in the same way as GadgetFS 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 implemented in kernel space (for instance Ethernet, serial or
mass storage) and other are implemented in user space. 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 Say "y" to link the driver statically, or "m" to build
a dynamically linked module called "g_ffs". a dynamically linked module called "g_ffs".
config USB_FUNCTIONFS_ETH config USB_FUNCTIONFS_ETH
bool "Include CDC ECM (Ethernet) function" bool "Include configuration with CDC ECM (Ethernet)"
depends on USB_FUNCTIONFS && NET depends on USB_FUNCTIONFS && NET
help help
Include an CDC ECM (Ethernet) funcion in the CDC ECM (Funcion) Include a configuration with CDC ECM funcion (Ethernet) and the
Filesystem. If you also say "y" to the RNDIS query below the Funcion Filesystem.
gadget will have two configurations.
config USB_FUNCTIONFS_RNDIS config USB_FUNCTIONFS_RNDIS
bool "Include RNDIS (Ethernet) function" bool "Include configuration with RNDIS (Ethernet)"
depends on USB_FUNCTIONFS && NET depends on USB_FUNCTIONFS && NET
help help
Include an RNDIS (Ethernet) funcion in the Funcion Filesystem. Include a configuration with RNDIS funcion (Ethernet) and the Filesystem.
If you also say "y" to the CDC ECM query above the gadget will
have two configurations.
config USB_FUNCTIONFS_GENERIC config USB_FUNCTIONFS_GENERIC
bool "Include 'pure' configuration" bool "Include 'pure' configuration"
depends on USB_FUNCTIONFS && (USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS) depends on USB_FUNCTIONFS
help help
Include a configuration with FunctionFS and no Ethernet Include a configuration with the Function Filesystem alone with
configuration. no Ethernet interface.
config USB_FILE_STORAGE config USB_FILE_STORAGE
tristate "File-backed Storage Gadget" tristate "File-backed Storage Gadget"
@ -863,6 +864,7 @@ config USB_G_NOKIA
config USB_G_MULTI config USB_G_MULTI
tristate "Multifunction Composite Gadget (EXPERIMENTAL)" tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
depends on BLOCK && NET depends on BLOCK && NET
select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS
help help
The Multifunction Composite Gadget provides Ethernet (RNDIS The Multifunction Composite Gadget provides Ethernet (RNDIS
and/or CDC Ethernet), mass storage and ACM serial link 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 Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_hid". 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 # put drivers that need isochronous transfer support (for audio
# or video class gadget drivers), or specific hardware, here. # or video class gadget drivers), or specific hardware, here.
config USB_G_WEBCAM config USB_G_WEBCAM

View File

@ -44,6 +44,7 @@ g_printer-objs := printer.o
g_cdc-objs := cdc2.o g_cdc-objs := cdc2.o
g_multi-objs := multi.o g_multi-objs := multi.o
g_hid-objs := hid.o g_hid-objs := hid.o
g_dbgp-objs := dbgp.o
g_nokia-objs := nokia.o g_nokia-objs := nokia.o
g_webcam-objs := webcam.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_ETH) += g_ether.o
obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
obj-$(CONFIG_USB_FUNCTIONFS) += g_ffs.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_FILE_STORAGE) += g_file_storage.o
obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o obj-$(CONFIG_USB_MASS_STORAGE) += g_mass_storage.o
obj-$(CONFIG_USB_G_SERIAL) += g_serial.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_MIDI_GADGET) += g_midi.o
obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
obj-$(CONFIG_USB_G_HID) += g_hid.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_MULTI) += g_multi.o
obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.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 */ /* 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 gcnum;
int status; int status;

View File

@ -129,7 +129,7 @@ static u8 hostaddr[ETH_ALEN];
/* /*
* We _always_ have both CDC ECM and CDC ACM functions. * 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; 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; int gcnum;
struct usb_gadget *gadget = cdev->gadget; 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 * string IDs. Drivers for functions, configurations, or gadgets will
* then store that ID in the appropriate descriptors and string table. * then store that ID in the appropriate descriptors and string table.
* *
* All string identifier should be allocated using this routine, to * All string identifier should be allocated using this,
* ensure that for example different functions don't wrongly assign * @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure
* different meanings to the same identifier. * that for example different functions don't wrongly assign different
* meanings to the same identifier.
*/ */
int usb_string_id(struct usb_composite_dev *cdev) int usb_string_id(struct usb_composite_dev *cdev)
{ {
if (cdev->next_string_id < 254) { 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++; cdev->next_string_id++;
return cdev->next_string_id; return cdev->next_string_id;
} }
return -ENODEV; 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) 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); spin_lock_irqsave(&cdev->lock, flags);
if (cdev->config) if (cdev->config)
reset_config(cdev); reset_config(cdev);
if (composite->disconnect)
composite->disconnect(cdev);
spin_unlock_irqrestore(&cdev->lock, flags); 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); dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags); spin_lock_irqsave (&dum->lock, flags);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) if (!HCD_HW_ACCESSIBLE(hcd))
goto done; goto done;
if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) { if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
@ -1588,7 +1588,7 @@ static int dummy_hub_control (
int retval = 0; int retval = 0;
unsigned long flags; unsigned long flags;
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) if (!HCD_HW_ACCESSIBLE(hcd))
return -ETIMEDOUT; return -ETIMEDOUT;
dum = hcd_to_dummy (hcd); 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__); dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
spin_lock_irq (&dum->lock); spin_lock_irq (&dum->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { if (!HCD_HW_ACCESSIBLE(hcd)) {
rc = -ESHUTDOWN; rc = -ESHUTDOWN;
} else { } else {
dum->rh_state = DUMMY_RH_RUNNING; 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, * the first one present. That's to make Microsoft's drivers happy,
* and to follow DOCSIS 1.0 (cable modem standard). * 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 */ /* 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. * 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 */ /* 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; int gcnum;
struct usb_gadget *gadget = cdev->gadget; 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; struct ffs_function *func = ffs->func;
ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV; ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV;
} else if (gadget->ops->ioctl) { } else if (gadget->ops->ioctl) {
lock_kernel();
ret = gadget->ops->ioctl(gadget, code, value); ret = gadget->ops->ioctl(gadget, code, value);
unlock_kernel();
} else { } else {
ret = -ENOTTY; 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) 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(); 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))) || test_and_set_bit(FFS_FL_BOUND, &ffs->flags)))
return -EBADFD; 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); ffs->ep0req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
if (unlikely(!ffs->ep0req)) 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->complete = ffs_ep0_complete;
ffs->ep0req->context = ffs; ffs->ep0req->context = ffs;
/* Get strings identifiers */ lang = ffs->stringtabs;
for (count = ffs->strings_count, i = 0; i < count; ++i) { for (lang = ffs->stringtabs; *lang; ++lang) {
struct usb_gadget_strings **lang; struct usb_string *str = (*lang)->strings;
int id = first_id;
int id = usb_string_id(cdev); for (; str->s; ++id, ++str)
if (unlikely(id < 0)) { str->id = id;
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);
} }
ffs->gadget = cdev->gadget; ffs->gadget = cdev->gadget;
ffs_data_get(ffs);
return 0; 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, static int functionfs_bind_config(struct usb_composite_dev *cdev,
struct usb_configuration *c, struct usb_configuration *c,
struct ffs_data *ffs) struct ffs_data *ffs)
{ {
struct ffs_function *func; struct ffs_function *func;
int ret; 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, static ssize_t f_hidg_read(struct file *file, char __user *buffer,
size_t count, loff_t *ptr) 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; char *tmp_buff = NULL;
unsigned long flags; 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, static ssize_t f_hidg_write(struct file *file, const char __user *buffer,
size_t count, loff_t *offp) 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; ssize_t status = -ENOMEM;
if (!access_ok(VERIFY_READ, buffer, count)) 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) 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; unsigned int ret = 0;
poll_wait(file, &hidg->read_queue, wait); 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; struct f_loopback *loop;
int status; int status;
@ -346,7 +346,7 @@ static int __init loopback_bind_config(struct usb_configuration *c)
return status; return status;
} }
static struct usb_configuration loopback_driver = { static struct usb_configuration loopback_driver = {
.label = "loopback", .label = "loopback",
.strings = loopback_strings, .strings = loopback_strings,
.bind = loopback_bind_config, .bind = loopback_bind_config,

View File

@ -316,6 +316,27 @@ static const char fsg_string_interface[] = "Mass Storage";
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
struct fsg_dev; 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. */ /* Data shared by all the FSG instances. */
@ -333,7 +354,6 @@ struct fsg_common {
struct usb_ep *ep0; /* Copy of gadget->ep0 */ struct usb_ep *ep0; /* Copy of gadget->ep0 */
struct usb_request *ep0req; /* Copy of cdev->req */ struct usb_request *ep0req; /* Copy of cdev->req */
unsigned int ep0_req_tag; unsigned int ep0_req_tag;
const char *ep0req_name;
struct fsg_buffhd *next_buffhd_to_fill; struct fsg_buffhd *next_buffhd_to_fill;
struct fsg_buffhd *next_buffhd_to_drain; struct fsg_buffhd *next_buffhd_to_drain;
@ -369,8 +389,8 @@ struct fsg_common {
struct completion thread_notifier; struct completion thread_notifier;
struct task_struct *thread_task; struct task_struct *thread_task;
/* Callback function to call when thread exits. */ /* Callback functions. */
int (*thread_exits)(struct fsg_common *common); const struct fsg_operations *ops;
/* Gadget's private data. */ /* Gadget's private data. */
void *private_data; void *private_data;
@ -394,12 +414,8 @@ struct fsg_config {
const char *lun_name_format; const char *lun_name_format;
const char *thread_name; const char *thread_name;
/* Callback function to call when thread exits. If no /* Callback functions. */
* callback is set or it returns value lower then zero MSF const struct fsg_operations *ops;
* 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);
/* Gadget's private data. */ /* Gadget's private data. */
void *private_data; void *private_data;
@ -435,6 +451,7 @@ static inline int __fsg_is_set(struct fsg_common *common,
if (common->fsg) if (common->fsg)
return 1; return 1;
ERROR(common, "common->fsg is NULL in %s at %u\n", func, line); ERROR(common, "common->fsg is NULL in %s at %u\n", func, line);
WARN_ON(1);
return 0; return 0;
} }
@ -623,8 +640,6 @@ static int fsg_setup(struct usb_function *f,
/* Respond with data/status */ /* Respond with data/status */
req->length = min((u16)1, w_length); 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); return ep0_queue(fsg->common);
} }
@ -1395,43 +1410,55 @@ static int do_start_stop(struct fsg_common *common)
} else if (!curlun->removable) { } else if (!curlun->removable) {
curlun->sense_data = SS_INVALID_COMMAND; curlun->sense_data = SS_INVALID_COMMAND;
return -EINVAL; return -EINVAL;
} } else if ((common->cmnd[1] & ~0x01) != 0 || /* Mask away Immed */
(common->cmnd[4] & ~0x03) != 0) { /* Mask LoEj, Start */
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 */
curlun->sense_data = SS_INVALID_FIELD_IN_CDB; curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
return -EINVAL; return -EINVAL;
} }
if (!start) { loej = common->cmnd[4] & 0x02;
/* Are we allowed to unload the media? */ start = common->cmnd[4] & 0x01;
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 {
/* Our emulation doesn't support mounting; the medium is /* Our emulation doesn't support mounting; the medium is
* available for use as soon as it is loaded. */ * available for use as soon as it is loaded. */
if (start) {
if (!fsg_lun_is_open(curlun)) { if (!fsg_lun_is_open(curlun)) {
curlun->sense_data = SS_MEDIUM_NOT_PRESENT; curlun->sense_data = SS_MEDIUM_NOT_PRESENT;
return -EINVAL; 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; common->thread_task = NULL;
spin_unlock_irq(&common->lock); 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; struct fsg_lun *curlun = common->luns;
unsigned i = common->nluns; 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->free_storage_on_release = 0;
} }
common->ops = cfg->ops;
common->private_data = cfg->private_data; common->private_data = cfg->private_data;
common->gadget = gadget; common->gadget = gadget;
@ -2807,7 +2836,6 @@ buffhds_first_it:
/* Tell the thread to start working */ /* Tell the thread to start working */
common->thread_exits = cfg->thread_exits;
common->thread_task = common->thread_task =
kthread_create(fsg_main_thread, common, kthread_create(fsg_main_thread, common,
OR(cfg->thread_name, "file-storage")); OR(cfg->thread_name, "file-storage"));
@ -2990,9 +3018,9 @@ static struct usb_gadget_strings *fsg_strings_array[] = {
NULL, NULL,
}; };
static int fsg_add(struct usb_composite_dev *cdev, static int fsg_bind_config(struct usb_composite_dev *cdev,
struct usb_configuration *c, struct usb_configuration *c,
struct fsg_common *common) struct fsg_common *common)
{ {
struct fsg_dev *fsg; struct fsg_dev *fsg;
int rc; int rc;
@ -3024,6 +3052,13 @@ static int fsg_add(struct usb_composite_dev *cdev,
return rc; 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 *************************/ /************************* Module parameters *************************/
@ -3096,8 +3131,8 @@ fsg_config_from_params(struct fsg_config *cfg,
cfg->product_name = 0; cfg->product_name = 0;
cfg->release = 0xffff; cfg->release = 0xffff;
cfg->thread_exits = 0; cfg->ops = NULL;
cfg->private_data = 0; cfg->private_data = NULL;
/* Finalise */ /* Finalise */
cfg->can_stall = params->stall; 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; struct f_sourcesink *ss;
int status; int status;

View File

@ -56,7 +56,7 @@
* following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03),
* UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by
* the optional "protocol" module parameter. In addition, the default * 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 * 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 * 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 * removable Default false, boolean for removable media
* luns=N Default N = number of filenames, number of * luns=N Default N = number of filenames, number of
* LUNs to support * 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 * stall Default determined according to the type of
* USB device controller (usually true), * USB device controller (usually true),
* boolean to permit the driver to halt * boolean to permit the driver to halt
@ -106,17 +108,18 @@
* vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
* product=0xPPPP Default 0xa4a5 (FSG), USB Product ID * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
* release=0xRRRR Override the USB release number (bcdDevice) * 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 * buflen=N Default N=16384, buffer size used (will be
* rounded down to a multiple of * rounded down to a multiple of
* PAGE_CACHE_SIZE) * PAGE_CACHE_SIZE)
* *
* If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro", * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro",
* "removable", "luns", "stall", and "cdrom" options are available; default * "removable", "luns", "nofua", "stall", and "cdrom" options are available;
* values are used for everything else. * default values are used for everything else.
* *
* The pathnames of the backing files and the ro settings are available in * 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 * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of
* gadget's sysfs directory. If the "removable" option is set, writing to * the gadget's sysfs directory. If the "removable" option is set, writing to
* these files will simulate ejecting/loading the medium (writing an empty * these files will simulate ejecting/loading the medium (writing an empty
* line means eject) and adjusting a write-enable tab. Changes to the ro * 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 * 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_DESC "File-backed Storage Gadget"
#define DRIVER_NAME "g_file_storage" #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" #define DRIVER_VERSION "20 November 2008"
static char fsg_string_manufacturer[64]; static char fsg_string_manufacturer[64];
@ -301,8 +306,10 @@ MODULE_LICENSE("Dual BSD/GPL");
static struct { static struct {
char *file[FSG_MAX_LUNS]; char *file[FSG_MAX_LUNS];
int ro[FSG_MAX_LUNS]; int ro[FSG_MAX_LUNS];
int nofua[FSG_MAX_LUNS];
unsigned int num_filenames; unsigned int num_filenames;
unsigned int num_ros; unsigned int num_ros;
unsigned int num_nofuas;
unsigned int nluns; unsigned int nluns;
int removable; int removable;
@ -314,6 +321,7 @@ static struct {
unsigned short vendor; unsigned short vendor;
unsigned short product; unsigned short product;
unsigned short release; unsigned short release;
char *serial;
unsigned int buflen; unsigned int buflen;
int transport_type; 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_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
MODULE_PARM_DESC(ro, "true to force read-only"); 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_param_named(luns, mod_data.nluns, uint, S_IRUGO);
MODULE_PARM_DESC(luns, "number of LUNs"); 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_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk"); 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 /* In the non-TEST version, only the module parameters listed above
* are available. */ * are available. */
@ -1272,7 +1286,8 @@ static int do_write(struct fsg_dev *fsg)
curlun->sense_data = SS_INVALID_FIELD_IN_CDB; curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
return -EINVAL; return -EINVAL;
} }
if (fsg->cmnd[1] & 0x08) { // FUA /* FUA */
if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) {
spin_lock(&curlun->filp->f_lock); spin_lock(&curlun->filp->f_lock);
curlun->filp->f_flags |= O_DSYNC; curlun->filp->f_flags |= O_DSYNC;
spin_unlock(&curlun->filp->f_lock); 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() */ /* The write permissions and store_xxx pointers are set in fsg_bind() */
static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL); 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); 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 prot;
int gcnum; int gcnum;
int i;
/* Store the default values */ /* Store the default values */
mod_data.transport_type = USB_PR_BULK; 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"); ERROR(fsg, "invalid buflen\n");
return -ETOOSMALL; return -ETOOSMALL;
} }
#endif /* CONFIG_USB_FILE_STORAGE_TEST */ #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; 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; struct fsg_dev *fsg = the_fsg;
int rc; 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 */ /* Find out how many LUNs there should be */
i = mod_data.nluns; i = mod_data.nluns;
if (i == 0) 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->ro = mod_data.cdrom || mod_data.ro[i];
curlun->initially_ro = curlun->ro; curlun->initially_ro = curlun->ro;
curlun->removable = mod_data.removable; curlun->removable = mod_data.removable;
curlun->nofua = mod_data.nofua[i];
curlun->dev.release = lun_release; curlun->dev.release = lun_release;
curlun->dev.parent = &gadget->dev; curlun->dev.parent = &gadget->dev;
curlun->dev.driver = &fsg_driver.driver; 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, if ((rc = device_create_file(&curlun->dev,
&dev_attr_ro)) != 0 || &dev_attr_ro)) != 0 ||
(rc = device_create_file(&curlun->dev,
&dev_attr_nofua)) != 0 ||
(rc = device_create_file(&curlun->dev, (rc = device_create_file(&curlun->dev,
&dev_attr_file)) != 0) { &dev_attr_file)) != 0) {
device_unregister(&curlun->dev); device_unregister(&curlun->dev);
@ -3447,16 +3523,6 @@ static int __init fsg_bind(struct usb_gadget *gadget)
init_utsname()->sysname, init_utsname()->release, init_utsname()->sysname, init_utsname()->release,
gadget->name); 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, fsg->thread_task = kthread_create(fsg_main_thread, fsg,
"file-storage-gadget"); "file-storage-gadget");
if (IS_ERR(fsg->thread_task)) { if (IS_ERR(fsg->thread_task)) {
@ -3478,8 +3544,8 @@ static int __init fsg_bind(struct usb_gadget *gadget)
if (IS_ERR(p)) if (IS_ERR(p))
p = NULL; p = NULL;
} }
LINFO(curlun, "ro=%d, file: %s\n", LINFO(curlun, "ro=%d, nofua=%d, file: %s\n",
curlun->ro, (p ? p : "(error)")); curlun->ro, curlun->nofua, (p ? p : "(error)"));
} }
} }
kfree(pathbuf); kfree(pathbuf);

View File

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

View File

@ -1157,7 +1157,7 @@ fail:
/* /*
* Creates an output endpoint, and initializes output ports. * 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 gmidi_device *dev;
struct usb_ep *in_ep, *out_ep; struct usb_ep *in_ep, *out_ep;

View File

@ -127,7 +127,7 @@ static struct usb_gadget_strings *dev_strings[] = {
/****************************** Configurations ******************************/ /****************************** Configurations ******************************/
static int __init do_config(struct usb_configuration *c) static int __ref do_config(struct usb_configuration *c)
{ {
struct hidg_func_node *e; struct hidg_func_node *e;
int func = 0, status = 0; int func = 0, status = 0;
@ -156,7 +156,7 @@ static struct usb_configuration config_driver = {
/****************************** Gadget Bind ******************************/ /****************************** 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 usb_gadget *gadget = cdev->gadget;
struct list_head *tmp; 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; struct usb_gadget *gadget = dev->gadget;
long ret = -ENOTTY; long ret = -ENOTTY;
if (gadget->ops->ioctl) { if (gadget->ops->ioctl)
lock_kernel();
ret = gadget->ops->ioctl (gadget, code, value); ret = gadget->ops->ioctl (gadget, code, value);
unlock_kernel();
}
return ret; return ret;
} }
@ -1867,13 +1865,9 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
buf += 4; buf += 4;
length -= 4; length -= 4;
kbuf = kmalloc (length, GFP_KERNEL); kbuf = memdup_user(buf, length);
if (!kbuf) if (IS_ERR(kbuf))
return -ENOMEM; return PTR_ERR(kbuf);
if (copy_from_user (kbuf, buf, length)) {
kfree (kbuf);
return -EFAULT;
}
spin_lock_irq (&dev->lock); spin_lock_irq (&dev->lock);
value = -EINVAL; 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"); VDBG(dev, "req->mapped = 0\n");
} }
DBG(dev, "%s queue req %p, len %u, buf %p, dma 0x%08x\n", DBG(dev, "%s queue req %p, len %u, buf %p, dma 0x%08llx\n",
_ep->name, _ep->name,
_req, _req->length, _req->buf, _req->dma); _req, _req->length, _req->buf, (unsigned long long)_req->dma);
_req->status = -EINPROGRESS; _req->status = -EINPROGRESS;
_req->actual = 0; _req->actual = 0;

View File

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

View File

@ -24,6 +24,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/utsname.h> #include <linux/utsname.h>
#include <linux/module.h>
#if defined USB_ETH_RNDIS #if defined USB_ETH_RNDIS
@ -35,14 +36,13 @@
#define DRIVER_DESC "Multifunction Composite Gadget" #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 * kbuild is not very cooperative with respect to linking separately
@ -57,6 +57,8 @@
#include "config.c" #include "config.c"
#include "epautoconf.c" #include "epautoconf.c"
#include "f_mass_storage.c"
#include "u_serial.c" #include "u_serial.c"
#include "f_acm.c" #include "f_acm.c"
@ -68,13 +70,24 @@
#endif #endif
#include "u_ether.c" #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 = { static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc, .bLength = sizeof device_desc,
@ -82,80 +95,82 @@ static struct usb_device_descriptor device_desc = {
.bcdUSB = cpu_to_le16(0x0200), .bcdUSB = cpu_to_le16(0x0200),
/* .bDeviceClass = USB_CLASS_COMM, */ .bDeviceClass = USB_CLASS_MISC /* 0xEF */,
/* .bDeviceSubClass = 0, */
/* .bDeviceProtocol = 0, */
.bDeviceClass = 0xEF,
.bDeviceSubClass = 2, .bDeviceSubClass = 2,
.bDeviceProtocol = 1, .bDeviceProtocol = 1,
/* .bMaxPacketSize0 = f(hardware) */
/* Vendor and product id can be overridden by module parameters. */ /* Vendor and product id can be overridden by module parameters. */
.idVendor = cpu_to_le16(MULTI_VENDOR_NUM), .idVendor = cpu_to_le16(MULTI_VENDOR_NUM),
.idProduct = cpu_to_le16(MULTI_PRODUCT_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[] = { 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, NULL,
}; };
/* string IDs are assigned dynamically */ enum {
MULTI_STRING_MANUFACTURER_IDX,
#define STRING_MANUFACTURER_IDX 0 MULTI_STRING_PRODUCT_IDX,
#define STRING_PRODUCT_IDX 1 #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 char manufacturer[50];
static struct usb_string strings_dev[] = { static struct usb_string strings_dev[] = {
[STRING_MANUFACTURER_IDX].s = manufacturer, [MULTI_STRING_MANUFACTURER_IDX].s = manufacturer,
[STRING_PRODUCT_IDX].s = DRIVER_DESC, [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 */ { } /* end of list */
}; };
static struct usb_gadget_strings stringtab_dev = {
.language = 0x0409, /* en-us */
.strings = strings_dev,
};
static struct usb_gadget_strings *dev_strings[] = { static struct usb_gadget_strings *dev_strings[] = {
&stringtab_dev, &(struct usb_gadget_strings){
.language = 0x0409, /* en-us */
.strings = strings_dev,
},
NULL, NULL,
}; };
static u8 hostaddr[ETH_ALEN];
/****************************** Configurations ******************************/ /****************************** Configurations ******************************/
static struct fsg_module_parameters mod_data = { static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
.stall = 1 FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
};
FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
static struct fsg_common *fsg_common; static struct fsg_common fsg_common;
static u8 hostaddr[ETH_ALEN];
/********** RNDIS **********/
#ifdef USB_ETH_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; int ret;
@ -172,26 +187,42 @@ static int __init rndis_do_config(struct usb_configuration *c)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = fsg_add(c->cdev, c, fsg_common); ret = fsg_bind_config(c->cdev, c, &fsg_common);
if (ret < 0) if (ret < 0)
return ret; return ret;
return 0; return 0;
} }
static struct usb_configuration rndis_config_driver = { static int rndis_config_register(struct usb_composite_dev *cdev)
.label = "Multifunction Composite (RNDIS + MS + ACM)", {
.bind = rndis_do_config, static struct usb_configuration config = {
.bConfigurationValue = 2, .bind = rndis_do_config,
/* .iConfiguration = DYNAMIC */ .bConfigurationValue = MULTI_RNDIS_CONFIG_NUM,
.bmAttributes = USB_CONFIG_ATT_SELFPOWER, .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 #endif
/********** CDC ECM **********/
#ifdef CONFIG_USB_G_MULTI_CDC #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; int ret;
@ -208,20 +239,33 @@ static int __init cdc_do_config(struct usb_configuration *c)
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = fsg_add(c->cdev, c, fsg_common); ret = fsg_bind_config(c->cdev, c, &fsg_common);
if (ret < 0) if (ret < 0)
return ret; return ret;
return 0; return 0;
} }
static struct usb_configuration cdc_config_driver = { static int cdc_config_register(struct usb_composite_dev *cdev)
.label = "Multifunction Composite (CDC + MS + ACM)", {
.bind = cdc_do_config, static struct usb_configuration config = {
.bConfigurationValue = 1, .bind = cdc_do_config,
/* .iConfiguration = DYNAMIC */ .bConfigurationValue = MULTI_CDC_CONFIG_NUM,
.bmAttributes = USB_CONFIG_ATT_SELFPOWER, .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 #endif
@ -230,7 +274,7 @@ static struct usb_configuration cdc_config_driver = {
/****************************** Gadget Bind ******************************/ /****************************** 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; struct usb_gadget *gadget = cdev->gadget;
int status, gcnum; int status, gcnum;
@ -252,67 +296,56 @@ static int __init multi_bind(struct usb_composite_dev *cdev)
goto fail0; goto fail0;
/* set up mass storage function */ /* set up mass storage function */
fsg_common = fsg_common_from_params(0, cdev, &mod_data); {
if (IS_ERR(fsg_common)) { void *retp;
status = PTR_ERR(fsg_common); retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
goto fail1; if (IS_ERR(retp)) {
status = PTR_ERR(retp);
goto fail1;
}
} }
/* set bcdDevice */
gcnum = usb_gadget_controller_number(gadget); gcnum = usb_gadget_controller_number(gadget);
if (gcnum >= 0) if (gcnum >= 0) {
device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum); device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
else { } else {
/* We assume that can_support_ecm() tells the truth; WARNING(cdev, "controller '%s' not recognized\n", gadget->name);
* 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);
device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099); device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
} }
/* allocate string descriptor numbers */
/* Allocate string descriptor numbers ... note that string
* contents can be overridden by the composite_dev glue.
*/
/* device descriptor strings: manufacturer, product */
snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
init_utsname()->sysname, init_utsname()->release, init_utsname()->sysname, init_utsname()->release,
gadget->name); 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); status = usb_string_ids_tab(cdev, strings_dev);
if (status < 0) if (unlikely(status < 0))
goto fail2; goto fail2;
strings_dev[STRING_PRODUCT_IDX].id = status;
device_desc.iProduct = status;
#ifdef USB_ETH_RNDIS device_desc.iManufacturer =
/* register our first configuration */ strings_dev[MULTI_STRING_MANUFACTURER_IDX].id;
status = usb_add_config(cdev, &rndis_config_driver); device_desc.iProduct =
if (status < 0) strings_dev[MULTI_STRING_PRODUCT_IDX].id;
/* register configurations */
status = rndis_config_register(cdev);
if (unlikely(status < 0))
goto fail2; goto fail2;
#endif
#ifdef CONFIG_USB_G_MULTI_CDC status = cdc_config_register(cdev);
/* register our second configuration */ if (unlikely(status < 0))
status = usb_add_config(cdev, &cdc_config_driver);
if (status < 0)
goto fail2; goto fail2;
#endif
dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); /* we're done */
fsg_common_put(fsg_common); dev_info(&gadget->dev, DRIVER_DESC "\n");
fsg_common_put(&fsg_common);
return 0; return 0;
/* error recovery */
fail2: fail2:
fsg_common_put(fsg_common); fsg_common_put(&fsg_common);
fail1: fail1:
gserial_cleanup(); gserial_cleanup();
fail0: fail0:
@ -339,18 +372,15 @@ static struct usb_composite_driver multi_driver = {
.unbind = __exit_p(multi_unbind), .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); 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); 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/ioport.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp_lock.h> #include <linux/mutex.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/timer.h> #include <linux/timer.h>
@ -70,6 +70,7 @@
#define DRIVER_DESC "Printer Gadget" #define DRIVER_DESC "Printer Gadget"
#define DRIVER_VERSION "2007 OCT 06" #define DRIVER_VERSION "2007 OCT 06"
static DEFINE_MUTEX(printer_mutex);
static const char shortname [] = "printer"; static const char shortname [] = "printer";
static const char driver_desc [] = DRIVER_DESC; static const char driver_desc [] = DRIVER_DESC;
@ -476,7 +477,7 @@ printer_open(struct inode *inode, struct file *fd)
unsigned long flags; unsigned long flags;
int ret = -EBUSY; int ret = -EBUSY;
lock_kernel(); mutex_lock(&printer_mutex);
dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev); dev = container_of(inode->i_cdev, struct printer_dev, printer_cdev);
spin_lock_irqsave(&dev->lock, flags); spin_lock_irqsave(&dev->lock, flags);
@ -492,7 +493,7 @@ printer_open(struct inode *inode, struct file *fd)
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
DBG(dev, "printer_open returned %x\n", ret); DBG(dev, "printer_open returned %x\n", ret);
unlock_kernel(); mutex_unlock(&printer_mutex);
return ret; return ret;
} }
@ -1346,7 +1347,7 @@ printer_unbind(struct usb_gadget *gadget)
set_gadget_data(gadget, NULL); set_gadget_data(gadget, NULL);
} }
static int __init static int __ref
printer_bind(struct usb_gadget *gadget) printer_bind(struct usb_gadget *gadget)
{ {
struct printer_dev *dev; struct printer_dev *dev;

View File

@ -12,6 +12,8 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define DEBUG
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
@ -23,6 +25,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/clk.h>
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
@ -33,6 +36,7 @@
#include <plat/regs-usb-hsotg.h> #include <plat/regs-usb-hsotg.h>
#include <mach/regs-sys.h> #include <mach/regs-sys.h>
#include <plat/udc-hs.h> #include <plat/udc-hs.h>
#include <plat/cpu.h>
#define DMA_ADDR_INVALID (~((dma_addr_t)0)) #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 * 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 * 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 * 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 s3c_hsotg_ep {
struct usb_ep ep; struct usb_ep ep;
@ -128,6 +134,7 @@ struct s3c_hsotg_ep {
* @regs: The memory area mapped for accessing registers. * @regs: The memory area mapped for accessing registers.
* @regs_res: The resource that was allocated when claiming register space. * @regs_res: The resource that was allocated when claiming register space.
* @irq: The IRQ number we are using * @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_root: root directrory for debugfs.
* @debug_file: main status file for debugfs. * @debug_file: main status file for debugfs.
* @debug_fifo: FIFO status file for debugfs. * @debug_fifo: FIFO status file for debugfs.
@ -145,6 +152,9 @@ struct s3c_hsotg {
void __iomem *regs; void __iomem *regs;
struct resource *regs_res; struct resource *regs_res;
int irq; int irq;
struct clk *clk;
unsigned int dedicated_fifos:1;
struct dentry *debug_root; struct dentry *debug_root;
struct dentry *debug_file; struct dentry *debug_file;
@ -310,11 +320,11 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
hsotg->regs + S3C_GNPTXFSIZ); hsotg->regs + S3C_GNPTXFSIZ);
*/ */
/* set FIFO sizes to 2048/0x1C0 */ /* set FIFO sizes to 2048/1024 */
writel(2048, hsotg->regs + S3C_GRXFSIZ); writel(2048, hsotg->regs + S3C_GRXFSIZ);
writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) | writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) |
S3C_GNPTXFSIZ_NPTxFDep(0x1C0), S3C_GNPTXFSIZ_NPTxFDep(1024),
hsotg->regs + S3C_GNPTXFSIZ); hsotg->regs + S3C_GNPTXFSIZ);
/* arange all the rest of the TX FIFOs, as some versions of this /* 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) if (to_write == 0)
return 0; return 0;
if (periodic) { if (periodic && !hsotg->dedicated_fifos) {
u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index)); u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index));
int size_left; int size_left;
int size_done; int size_done;
@ -474,6 +484,14 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); 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", dev_dbg(hsotg->dev, "%s: left=%d, load=%d, fifo=%d, size %d\n",
__func__, size_left, __func__, size_left,
hs_ep->size_loaded, hs_ep->fifo_load, hs_ep->fifo_size); 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); s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
return -ENOSPC; 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 { } else {
if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) {
dev_dbg(hsotg->dev, 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 = 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", 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) if (can_write > 512)
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 */ /* see if we can write data */
if (to_write > can_write) { 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; maxsize = S3C_DxEPTSIZ_XferSize_LIMIT + 1;
maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1; maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1;
} else { } else {
maxsize = 64+64;
if (hs_ep->dir_in) { if (hs_ep->dir_in) {
/* maxsize = S3C_DIEPTSIZ0_XferSize_LIMIT + 1; */
maxsize = 64+64+1;
maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1; maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1;
} else { } else {
maxsize = 0x3f;
maxpkt = 2; 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; read_ptr = hs_req->req.actual;
max_req = hs_req->req.length - read_ptr; 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) { if (to_read > max_req) {
/* more data appeared than we where willing /* more data appeared than we where willing
* to deal with in this request. * 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); 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_ep->total_data += to_read;
hs_req->req.actual += to_read; hs_req->req.actual += to_read;
to_read = DIV_ROUND_UP(to_read, 4); 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, static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
int epnum, bool was_setup) 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_ep *hs_ep = &hsotg->eps[epnum];
struct s3c_hsotg_req *hs_req = hs_ep->req; struct s3c_hsotg_req *hs_req = hs_ep->req;
struct usb_request *req = &hs_req->req; struct usb_request *req = &hs_req->req;
unsigned size_left = S3C_DxEPTSIZ_XferSize_GET(epsize);
int result = 0; int result = 0;
if (!hs_req) { if (!hs_req) {
@ -1444,9 +1479,7 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg,
} }
if (using_dma(hsotg)) { if (using_dma(hsotg)) {
u32 epsize = readl(hsotg->regs + S3C_DOEPTSIZ(epnum));
unsigned size_done; unsigned size_done;
unsigned size_left;
/* Calculate the size of the transfer by checking how much /* Calculate the size of the transfer by checking how much
* is left in the endpoint size register and then working it * 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. * 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->size_loaded - size_left;
size_done += hs_ep->last_load; size_done += hs_ep->last_load;
req->actual = size_done; 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) { if (req->actual < req->length && req->short_not_ok) {
dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n",
__func__, req->actual, req->length); __func__, req->actual, req->length);
@ -1758,7 +1795,7 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
if (dir_in) { if (dir_in) {
s3c_hsotg_complete_in(hsotg, hs_ep); s3c_hsotg_complete_in(hsotg, hs_ep);
if (idx == 0) if (idx == 0 && !hs_ep->req)
s3c_hsotg_enqueue_setup(hsotg); s3c_hsotg_enqueue_setup(hsotg);
} else if (using_dma(hsotg)) { } else if (using_dma(hsotg)) {
/* We're using DMA, we need to fire an OutDone here /* 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); __func__, idx);
clear |= S3C_DIEPMSK_INTknEPMisMsk; 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); writel(clear, hsotg->regs + epint_reg);
@ -2071,17 +2117,12 @@ irq_retry:
kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true); kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true);
/* it seems after a reset we can end up with a situation /* it seems after a reset we can end up with a situation
* where the TXFIFO still has data in it... try flushing * where the TXFIFO still has data in it... the docs
* it to remove anything that may still be in it. * suggest resetting all the fifos, so use the init_fifo
* code to relayout and flush the fifos.
*/ */
if (1) { s3c_hsotg_init_fifo(hsotg);
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_enqueue_setup(hsotg); s3c_hsotg_enqueue_setup(hsotg);
@ -2274,6 +2315,12 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
break; 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 */ /* for non control endpoints, set PID to D0 */
if (index) if (index)
epctrl |= S3C_DxEPCTL_SetD0PID; 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 | writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk |
S3C_DIEPMSK_INTknEPMisMsk | 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); hsotg->regs + S3C_DIEPMSK);
/* don't need XferCompl, we get that from RXFIFO in slave mode. In /* 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)); 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 /* if we're using dma, we need to set the next-endpoint pointer
* to be something valid. * 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) 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); mdelay(1);
osc = hsotg->plat->is_osc ? S3C_PHYCLK_EXT_OSC : 0; 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); writel(osc | 0x10, S3C_PHYCLK);
/* issue a full set of resets to the otg and core */ /* 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) static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
{ {
u32 cfg4;
/* unmask subset of endpoint interrupts */ /* unmask subset of endpoint interrupts */
writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | 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, writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0,
hsotg->regs + S3C_GAHBCFG); 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) 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->dev = dev;
hsotg->plat = plat; 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); platform_set_drvdata(pdev, hsotg);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { if (!res) {
dev_err(dev, "cannot find register resource 0\n"); dev_err(dev, "cannot find register resource 0\n");
ret = -EINVAL; ret = -EINVAL;
goto err_mem; goto err_clk;
} }
hsotg->regs_res = request_mem_region(res->start, resource_size(res), 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) { if (!hsotg->regs_res) {
dev_err(dev, "cannot reserve registers\n"); dev_err(dev, "cannot reserve registers\n");
ret = -ENOENT; ret = -ENOENT;
goto err_mem; goto err_clk;
} }
hsotg->regs = ioremap(res->start, resource_size(res)); 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 */ /* reset the system */
clk_enable(hsotg->clk);
s3c_hsotg_gate(pdev, true); s3c_hsotg_gate(pdev, true);
s3c_hsotg_otgreset(hsotg); s3c_hsotg_otgreset(hsotg);
@ -3271,7 +3358,8 @@ err_regs:
err_regs_res: err_regs_res:
release_resource(hsotg->regs_res); release_resource(hsotg->regs_res);
kfree(hsotg->regs_res); kfree(hsotg->regs_res);
err_clk:
clk_put(hsotg->clk);
err_mem: err_mem:
kfree(hsotg); kfree(hsotg);
return ret; return ret;
@ -3293,6 +3381,9 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
s3c_hsotg_gate(pdev, false); s3c_hsotg_gate(pdev, false);
clk_disable(hsotg->clk);
clk_put(hsotg->clk);
kfree(hsotg); kfree(hsotg);
return 0; 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; unsigned i;
int status = 0; int status = 0;
@ -161,7 +161,7 @@ static struct usb_configuration serial_config_driver = {
.bmAttributes = USB_CONFIG_ATT_SELFPOWER, .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; int gcnum;
struct usb_gadget *gadget = cdev->gadget; struct usb_gadget *gadget = cdev->gadget;

View File

@ -57,10 +57,12 @@
#include <asm/unaligned.h> #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!! * 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_VENDOR_ID 0x0525 /* NetChip */
#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */ #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 LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args)
#define LINFO(lun, fmt, args...) dev_info(&(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 * are identical (the same names of arguments, white spaces in the
* same places) GCC will allow redefinition otherwise (even if some * same places) GCC will allow redefinition otherwise (even if some
* white space is removed or added) warning will be issued. No * white space is removed or added) warning will be issued.
* checking if those symbols is defined is performed because warning *
* is desired when those macros were defined by someone else to mean * Those macros are needed here because File Storage Gadget does not
* something else. */ * 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 DBG(d, fmt, args...) dev_dbg(&(d)->gadget->dev , fmt , ## args)
#define VDBG(d, fmt, args...) dev_vdbg(&(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) #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 prevent_medium_removal:1;
unsigned int registered:1; unsigned int registered:1;
unsigned int info_valid:1; unsigned int info_valid:1;
unsigned int nofua:1;
u32 sense_data; u32 sense_data;
u32 sense_data_info; u32 sense_data_info;
@ -313,9 +329,11 @@ struct fsg_buffhd {
enum fsg_buffer_state state; enum fsg_buffer_state state;
struct fsg_buffhd *next; 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. * 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; unsigned int bulk_out_intended_length;
struct usb_request *inreq; struct usb_request *inreq;
@ -395,8 +413,10 @@ fsg_intf_desc = {
.iInterface = FSG_STRING_INTERFACE, .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 static struct usb_endpoint_descriptor
fsg_fs_bulk_in_desc = { fsg_fs_bulk_in_desc = {
@ -459,7 +479,7 @@ static struct usb_descriptor_header *fsg_fs_function[] = {
* *
* That means alternate endpoint descriptors (bigger packets) * That means alternate endpoint descriptors (bigger packets)
* and a "device qualifier" ... plus more construction options * and a "device qualifier" ... plus more construction options
* for the config descriptor. * for the configuration descriptor.
*/ */
static struct usb_endpoint_descriptor static struct usb_endpoint_descriptor
fsg_hs_bulk_in_desc = { 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) 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; 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)) { if (!filp->f_op || !(filp->f_op->read || filp->f_op->aio_read)) {
LINFO(curlun, "file not readable: %s\n", filename); LINFO(curlun, "file not readable: %s\n", filename);
goto out; 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) static int fsg_lun_fsync_sub(struct fsg_lun *curlun)
{ {
struct file *filp = curlun->filp; 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); : 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, static ssize_t fsg_show_file(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
@ -723,26 +757,47 @@ static ssize_t fsg_store_ro(struct device *dev, struct device_attribute *attr,
ssize_t rc = count; ssize_t rc = count;
struct fsg_lun *curlun = fsg_lun_from_dev(dev); struct fsg_lun *curlun = fsg_lun_from_dev(dev);
struct rw_semaphore *filesem = dev_get_drvdata(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; 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); down_read(filesem);
if (fsg_lun_is_open(curlun)) { if (fsg_lun_is_open(curlun)) {
LDBG(curlun, "read-only status change prevented\n"); LDBG(curlun, "read-only status change prevented\n");
rc = -EBUSY; rc = -EBUSY;
} else { } else {
curlun->ro = !!i; curlun->ro = ro;
curlun->initially_ro = !!i; curlun->initially_ro = ro;
LDBG(curlun, "read-only status set to %d\n", curlun->ro); LDBG(curlun, "read-only status set to %d\n", curlun->ro);
} }
up_read(filesem); up_read(filesem);
return rc; 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, static ssize_t fsg_store_file(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {

View File

@ -704,17 +704,6 @@ static char *host_addr;
module_param(host_addr, charp, S_IRUGO); module_param(host_addr, charp, S_IRUGO);
MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); 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) static int get_ether_addr(const char *str, u8 *dev_addr)
{ {
if (str) { if (str) {
@ -725,8 +714,8 @@ static int get_ether_addr(const char *str, u8 *dev_addr)
if ((*str == '.') || (*str == ':')) if ((*str == '.') || (*str == ':'))
str++; str++;
num = nibble(*str++) << 4; num = hex_to_bin(*str++) << 4;
num |= (nibble(*str++)); num |= hex_to_bin(*str++);
dev_addr [i] = num; dev_addr [i] = num;
} }
if (is_valid_ether_addr(dev_addr)) if (is_valid_ether_addr(dev_addr))

View File

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

View File

@ -308,7 +308,7 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
* USB configuration * USB configuration
*/ */
static int __init static int __ref
webcam_config_bind(struct usb_configuration *c) webcam_config_bind(struct usb_configuration *c)
{ {
return uvc_bind_config(c, uvc_control_cls, uvc_fs_streaming_cls, 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; return 0;
} }
static int __init static int __ref
webcam_bind(struct usb_composite_dev *cdev) webcam_bind(struct usb_composite_dev *cdev)
{ {
int ret; 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; int gcnum;
struct usb_gadget *gadget = cdev->gadget; 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. from ARC, and has since changed hands a few times.
config USB_EHCI_TT_NEWSCHED config USB_EHCI_TT_NEWSCHED
bool "Improved Transaction Translator scheduling (EXPERIMENTAL)" bool "Improved Transaction Translator scheduling"
depends on USB_EHCI_HCD && EXPERIMENTAL depends on USB_EHCI_HCD
default y
---help--- ---help---
This changes the periodic scheduling code to fill more of the low This changes the periodic scheduling code to fill more of the low
and full speed bandwidth available from the Transaction Translator 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 If you have multiple periodic low/fullspeed devices connected to a
highspeed USB hub which is connected to a highspeed USB Host highspeed USB hub which is connected to a highspeed USB Host
Controller, and some of those devices will not work correctly 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 config USB_EHCI_BIG_ENDIAN_MMIO
bool 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. * the root hub is either suspended or stopped.
*/ */
spin_lock_irqsave(&ehci->lock, flags); 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); ehci_writel(ehci, 0, &ehci->regs->intr_enable);
(void)ehci_readl(ehci, &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" : ""); HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
} else { } else {
ehci_dbg (ehci, 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, label,
params, params,
HCC_ISOC_THRES(params), HCC_ISOC_THRES(params),
HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024", HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
HCC_CANPARK(params) ? " park" : "", 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 #else
@ -191,8 +196,9 @@ static int __maybe_unused
dbg_status_buf (char *buf, unsigned len, const char *label, u32 status) dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
{ {
return scnprintf (buf, len, 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, label, label [0] ? " " : "", status,
(status & STS_PPCE_MASK) ? " PPCE" : "",
(status & STS_ASS) ? " Async" : "", (status & STS_ASS) ? " Async" : "",
(status & STS_PSS) ? " Periodic" : "", (status & STS_PSS) ? " Periodic" : "",
(status & STS_RECL) ? " Recl" : "", (status & STS_RECL) ? " Recl" : "",
@ -210,8 +216,9 @@ static int __maybe_unused
dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable) dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
{ {
return scnprintf (buf, len, 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, label, label [0] ? " " : "", enable,
(enable & STS_PPCE_MASK) ? " PPCE" : "",
(enable & STS_IAA) ? " IAA" : "", (enable & STS_IAA) ? " IAA" : "",
(enable & STS_FATAL) ? " FATAL" : "", (enable & STS_FATAL) ? " FATAL" : "",
(enable & STS_FLR) ? " FLR" : "", (enable & STS_FLR) ? " FLR" : "",
@ -228,9 +235,15 @@ static int
dbg_command_buf (char *buf, unsigned len, const char *label, u32 command) dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
{ {
return scnprintf (buf, len, 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, 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), CMD_PARK_CNT (command),
(command >> 16) & 0x3f, (command >> 16) & 0x3f,
(command & CMD_LRESET) ? " LReset" : "", (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, 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, 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_POWER) ? " POWER" : "",
(status & PORT_OWNER) ? " OWNER" : "", (status & PORT_OWNER) ? " OWNER" : "",
sig, sig,
(status & PORT_LPM) ? " LPM" : "",
(status & PORT_RESET) ? " RESET" : "", (status & PORT_RESET) ? " RESET" : "",
(status & PORT_SUSPEND) ? " SUSPEND" : "", (status & PORT_SUSPEND) ? " SUSPEND" : "",
(status & PORT_RESUME) ? " RESUME" : "", (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_periodic_open(struct inode *, struct file *);
static int debug_registers_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_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 ssize_t debug_output(struct file*, char __user*, size_t, loff_t*);
static int debug_close(struct inode *, struct file *); static int debug_close(struct inode *, struct file *);
@ -351,6 +382,13 @@ static const struct file_operations debug_registers_fops = {
.read = debug_output, .read = debug_output,
.release = debug_close, .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; 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); spin_lock_irqsave (&ehci->lock, flags);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { if (!HCD_HW_ACCESSIBLE(hcd)) {
size = scnprintf (next, size, size = scnprintf (next, size,
"bus %s, device %s\n" "bus %s, device %s\n"
"%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; 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) static inline void create_debug_files (struct ehci_hcd *ehci)
{ {
struct usb_bus *bus = &ehci_to_hcd(ehci)->self; struct usb_bus *bus = &ehci_to_hcd(ehci)->self;
ehci->debug_dir = debugfs_create_dir(bus->bus_name, ehci_debug_root); ehci->debug_dir = debugfs_create_dir(bus->bus_name, ehci_debug_root);
if (!ehci->debug_dir) if (!ehci->debug_dir)
goto dir_error; return;
ehci->debug_async = debugfs_create_file("async", S_IRUGO, if (!debugfs_create_file("async", S_IRUGO, ehci->debug_dir, bus,
ehci->debug_dir, bus, &debug_async_fops))
&debug_async_fops); goto file_error;
if (!ehci->debug_async)
goto async_error;
ehci->debug_periodic = debugfs_create_file("periodic", S_IRUGO, if (!debugfs_create_file("periodic", S_IRUGO, ehci->debug_dir, bus,
ehci->debug_dir, bus, &debug_periodic_fops))
&debug_periodic_fops); goto file_error;
if (!ehci->debug_periodic)
goto periodic_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; return;
registers_error: file_error:
debugfs_remove(ehci->debug_periodic); debugfs_remove_recursive(ehci->debug_dir);
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;
} }
static inline void remove_debug_files (struct ehci_hcd *ehci) static inline void remove_debug_files (struct ehci_hcd *ehci)
{ {
debugfs_remove(ehci->debug_registers); debugfs_remove_recursive(ehci->debug_dir);
debugfs_remove(ehci->debug_periodic);
debugfs_remove(ehci->debug_async);
debugfs_remove(ehci->debug_dir);
} }
#endif /* STUB_DEBUG_FILES */ #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); struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
void __iomem *non_ehci = hcd->regs; 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()) if (!fsl_deep_sleep())
return 0; return 0;

View File

@ -36,6 +36,7 @@
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/uaccess.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/io.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_RL_TT 0
#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */ #define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
#define EHCI_TUNE_MULT_TT 1 #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_IAA_MSECS 10 /* arbitrary */
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ #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_param (ignore_oc, bool, S_IRUGO);
MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); 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) #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); static void ehci_work(struct ehci_hcd *ehci);
#include "ehci-hub.c" #include "ehci-hub.c"
#include "ehci-lpm.c"
#include "ehci-mem.c" #include "ehci-mem.c"
#include "ehci-q.c" #include "ehci-q.c"
#include "ehci-sched.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) if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
log2_irq_thresh = 0; log2_irq_thresh = 0;
temp = 1 << (16 + log2_irq_thresh); 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)) { if (HCC_CANPARK(hcc_params)) {
/* HW default park == 3, on hardware that supports it (like /* HW default park == 3, on hardware that supports it (like
* NVidia and ALI silicon), maximizes throughput on the async * NVidia and ALI silicon), maximizes throughput on the async
@ -603,10 +621,22 @@ static int ehci_init(struct usb_hcd *hcd)
default: BUG(); 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; ehci->command = temp;
/* Accept arbitrarily long scatter-gather lists */ /* 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; return 0;
} }
@ -619,7 +649,6 @@ static int ehci_run (struct usb_hcd *hcd)
u32 hcc_params; u32 hcc_params;
hcd->uses_new_polling = 1; hcd->uses_new_polling = 1;
hcd->poll_rh = 0;
/* EHCI spec section 4.1 */ /* EHCI spec section 4.1 */
if ((retval = ehci_reset(ehci)) != 0) { if ((retval = ehci_reset(ehci)) != 0) {
@ -764,6 +793,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* remote wakeup [4.3.1] */ /* remote wakeup [4.3.1] */
if (status & STS_PCD) { if (status & STS_PCD) {
unsigned i = HCS_N_PORTS (ehci->hcs_params); unsigned i = HCS_N_PORTS (ehci->hcs_params);
u32 ppcd = 0;
/* kick root hub later */ /* kick root hub later */
pcd_status = status; pcd_status = status;
@ -772,9 +802,18 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
if (!(cmd & CMD_RUN)) if (!(cmd & CMD_RUN))
usb_hcd_resume_root_hub(hcd); usb_hcd_resume_root_hub(hcd);
/* get per-port change detect bits */
if (ehci->has_ppcd)
ppcd = status >> 16;
while (i--) { while (i--) {
int pstatus = ehci_readl(ehci, int pstatus;
&ehci->regs->port_status [i]);
/* 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) if (pstatus & PORT_OWNER)
continue; 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, static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
bool suspending) bool suspending, bool do_wakeup)
{ {
int port; int port;
u32 temp; 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 * when the controller is suspended or resumed. In all other
* cases they don't need to be changed. * cases they don't need to be changed.
*/ */
if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup)
device_may_wakeup(ehci_to_hcd(ehci)->self.controller))
return; return;
/* clear phy low-power mode before changing wakeup flags */ /* 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); 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) 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)) if (time_before (jiffies, ehci->next_statechange))
msleep(5); msleep(5);
spin_lock_irq (&ehci->lock); spin_lock_irq (&ehci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { if (!HCD_HW_ACCESSIBLE(hcd)) {
spin_unlock_irq(&ehci->lock); spin_unlock_irq(&ehci->lock);
return -ESHUTDOWN; return -ESHUTDOWN;
} }
@ -603,6 +606,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
u32 mask; u32 mask;
int ports, i, retval = 1; int ports, i, retval = 1;
unsigned long flags; unsigned long flags;
u32 ppcd = 0;
/* if !USB_SUSPEND, root hub timers won't get shut down ... */ /* if !USB_SUSPEND, root hub timers won't get shut down ... */
if (!HC_IS_RUNNING(hcd->state)) 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)? */ /* port N changes (bit N)? */
spin_lock_irqsave (&ehci->lock, flags); 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++) { 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]); temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
/* /*
@ -790,6 +802,11 @@ static int ehci_hub_control (
status_reg); status_reg);
break; break;
case USB_PORT_FEAT_C_CONNECTION: 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, ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
status_reg); status_reg);
break; 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/gpio.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb/ulpi.h>
#include <plat/usb.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 /* omap_start_ehc
* - Start the TI USBHOST controller * - 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); 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; return 0;
err_sys_status: err_sys_status:

View File

@ -114,6 +114,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
break; break;
case PCI_VENDOR_ID_INTEL: case PCI_VENDOR_ID_INTEL:
ehci->need_io_watchdog = 0; ehci->need_io_watchdog = 0;
ehci->fs_i_thresh = 1;
if (pdev->device == 0x27cc) { if (pdev->device == 0x27cc) {
ehci->broken_periodic = 1; ehci->broken_periodic = 1;
ehci_info(ehci, "using broken periodic workaround\n"); ehci_info(ehci, "using broken periodic workaround\n");
@ -277,7 +278,7 @@ done:
* Also they depend on separate root hub suspend/resume. * 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); struct ehci_hcd *ehci = hcd_to_ehci(hcd);
unsigned long flags; unsigned long flags;
@ -291,7 +292,7 @@ static int ehci_pci_suspend(struct usb_hcd *hcd)
* the root hub is either suspended or stopped. * the root hub is either suspended or stopped.
*/ */
spin_lock_irqsave (&ehci->lock, flags); 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); ehci_writel(ehci, 0, &ehci->regs->intr_enable);
(void)ehci_readl(ehci, &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 #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 = { static const struct hc_driver ehci_pci_hc_driver = {
.description = hcd_name, .description = hcd_name,
.product_desc = "EHCI Host Controller", .product_desc = "EHCI Host Controller",
@ -407,6 +424,11 @@ static const struct hc_driver ehci_pci_hc_driver = {
.relinquish_port = ehci_relinquish_port, .relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over, .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, .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
}; };

View File

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

View File

@ -880,8 +880,7 @@ static int intr_submit (
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) {
&ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN; status = -ESHUTDOWN;
goto done_not_linked; goto done_not_linked;
} }
@ -1075,15 +1074,6 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
if (stream->ep) if (stream->ep)
stream->ep->hcpriv = NULL; 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); kfree(stream);
} }
} }
@ -1396,30 +1386,25 @@ iso_stream_schedule (
struct ehci_iso_stream *stream struct ehci_iso_stream *stream
) )
{ {
u32 now, next, start, period; u32 now, next, start, period, span;
int status; int status;
unsigned mod = ehci->periodic_size << 3; unsigned mod = ehci->periodic_size << 3;
struct ehci_iso_sched *sched = urb->hcpriv; 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); ehci_dbg (ehci, "iso request %p too long\n", urb);
status = -EFBIG; status = -EFBIG;
goto fail; goto fail;
} }
if ((stream->depth + sched->span) > mod) { now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1);
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;
/* Typical case: reuse current schedule, stream is still active. /* Typical case: reuse current schedule, stream is still active.
* Hopefully there are no gaps from the host falling behind * 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. * slot in the schedule, implicitly assuming URB_ISO_ASAP.
*/ */
if (likely (!list_empty (&stream->td_list))) { if (likely (!list_empty (&stream->td_list))) {
pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); u32 excess;
start = stream->next_uframe;
/* For high speed devices, allow scheduling within the /* For high speed devices, allow scheduling within the
* isochronous scheduling threshold. For full speed devices, * isochronous scheduling threshold. For full speed devices
* don't. (Work around for Intel ICH9 bug.) * and Intel PCI-based controllers, don't (work around for
* Intel ICH9 bug).
*/ */
if (!stream->highspeed && if (!stream->highspeed && ehci->fs_i_thresh)
pdev->vendor == PCI_VENDOR_ID_INTEL)
next = now + ehci->i_thresh; next = now + ehci->i_thresh;
else else
next = now; next = now;
/* Fell behind (by up to twice the slop amount)? */ /* Fell behind (by up to twice the slop amount)?
if (((start - next) & (mod - 1)) >= * We decide based on the time of the last currently-scheduled
mod - 2 * SCHEDULE_SLOP) * slot, not the time of the next available slot.
start += period * DIV_ROUND_UP( */
(next - start) & (mod - 1), excess = (stream->next_uframe - period - next) & (mod - 1);
period); if (excess >= mod - 2 * SCHEDULE_SLOP)
start = next + excess - mod + period *
/* Tried to schedule too far into the future? */ DIV_ROUND_UP(mod - excess, period);
if (unlikely(((start - now) & (mod - 1)) + sched->span else
>= mod - 2 * SCHEDULE_SLOP)) { 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; status = -EFBIG;
goto fail; goto fail;
} }
stream->next_uframe = start;
goto ready;
} }
/* need to schedule; when's the next (u)frame we could start? /* 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 * can also help high bandwidth if the dma and irq loads don't
* jump until after the queue is primed. * jump until after the queue is primed.
*/ */
start = SCHEDULE_SLOP + (now & ~0x07); else {
start %= mod; start = SCHEDULE_SLOP + (now & ~0x07);
stream->next_uframe = start;
/* 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 */ /* find a uframe slot with enough bandwidth */
for (; start < (stream->next_uframe + period); start++) { next = start + period;
int enough_space; for (; start < next; start++) {
/* check schedule: enough space? */ /* check schedule: enough space? */
if (stream->highspeed) if (stream->highspeed) {
enough_space = itd_slot_ok (ehci, mod, start, if (itd_slot_ok(ehci, mod, start,
stream->usecs, period); stream->usecs, period))
else { break;
if ((start % 8) >= 6) } else {
continue; if ((start % 8) >= 6)
enough_space = sitd_slot_ok (ehci, mod, stream, continue;
start, sched, period); if (sitd_slot_ok(ehci, mod, stream,
start, sched, period))
break;
}
} }
/* schedule it here if there's enough bandwidth */ /* no room in the schedule */
if (enough_space) { if (start == next) {
stream->next_uframe = start % mod; ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n",
goto ready; urb, now, now + mod);
status = -ENOSPC;
goto fail;
} }
} }
/* no room in the schedule */ /* Tried to schedule too far into the future? */
ehci_dbg (ehci, "iso %ssched full %p (now %d max %d)\n", if (unlikely(start - now + span - period
list_empty (&stream->td_list) ? "" : "re", >= mod - 2 * SCHEDULE_SLOP)) {
urb, now, now + mod); ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n",
status = -ENOSPC; urb, start - now, span - period,
mod - 2 * SCHEDULE_SLOP);
status = -EFBIG;
goto fail;
}
fail: stream->next_uframe = start & (mod - 1);
iso_sched_free (stream, sched);
urb->hcpriv = NULL;
return status;
ready:
/* report high speed start in uframes; full speed, in frames */ /* report high speed start in uframes; full speed, in frames */
urb->start_frame = stream->next_uframe; urb->start_frame = stream->next_uframe;
if (!stream->highspeed) if (!stream->highspeed)
urb->start_frame >>= 3; urb->start_frame >>= 3;
return 0; 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_iso_sched *iso_sched = urb->hcpriv;
struct ehci_itd *itd; struct ehci_itd *itd;
next_uframe = stream->next_uframe % mod; next_uframe = stream->next_uframe & (mod - 1);
if (unlikely (list_empty(&stream->td_list))) { if (unlikely (list_empty(&stream->td_list))) {
ehci_to_hcd(ehci)->self.bandwidth_allocated ehci_to_hcd(ehci)->self.bandwidth_allocated
@ -1613,7 +1608,6 @@ itd_link_urb (
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
urb->interval, urb->interval,
next_uframe >> 3, next_uframe & 0x7); next_uframe >> 3, next_uframe & 0x7);
stream->start = jiffies;
} }
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
@ -1639,14 +1633,13 @@ itd_link_urb (
itd_patch(ehci, itd, iso_sched, packet, uframe); itd_patch(ehci, itd, iso_sched, packet, uframe);
next_uframe += stream->interval; next_uframe += stream->interval;
stream->depth += stream->interval; next_uframe &= mod - 1;
next_uframe %= mod;
packet++; packet++;
/* link completed itds into the schedule */ /* link completed itds into the schedule */
if (((next_uframe >> 3) != frame) if (((next_uframe >> 3) != frame)
|| packet == urb->number_of_packets) { || packet == urb->number_of_packets) {
itd_link (ehci, frame % ehci->periodic_size, itd); itd_link(ehci, frame & (ehci->periodic_size - 1), itd);
itd = NULL; itd = NULL;
} }
} }
@ -1695,7 +1688,6 @@ itd_complete (
t = hc32_to_cpup(ehci, &itd->hw_transaction [uframe]); t = hc32_to_cpup(ehci, &itd->hw_transaction [uframe]);
itd->hw_transaction [uframe] = 0; itd->hw_transaction [uframe] = 0;
stream->depth -= stream->interval;
/* report transfer status */ /* report transfer status */
if (unlikely (t & ISO_ERRS)) { if (unlikely (t & ISO_ERRS)) {
@ -1815,8 +1807,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */ /* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) {
&ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN; status = -ESHUTDOWN;
goto done_not_linked; goto done_not_linked;
} }
@ -2024,9 +2015,8 @@ sitd_link_urb (
"sched devp %s ep%d%s-iso [%d] %dms/%04x\n", "sched devp %s ep%d%s-iso [%d] %dms/%04x\n",
urb->dev->devpath, stream->bEndpointAddress & 0x0f, urb->dev->devpath, stream->bEndpointAddress & 0x0f,
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", (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->interval, hc32_to_cpu(ehci, stream->splits));
stream->start = jiffies;
} }
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
@ -2047,13 +2037,12 @@ sitd_link_urb (
sitd->urb = urb; sitd->urb = urb;
sitd_patch(ehci, stream, sitd, sched, packet); 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); sitd);
next_uframe += stream->interval << 3; 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 */ /* don't need that schedule data any more */
iso_sched_free (stream, sched); iso_sched_free (stream, sched);
@ -2111,7 +2100,6 @@ sitd_complete (
desc->actual_length = desc->length - SITD_LENGTH(t); desc->actual_length = desc->length - SITD_LENGTH(t);
urb->actual_length += desc->actual_length; urb->actual_length += desc->actual_length;
} }
stream->depth -= stream->interval << 3;
/* handle completion now? */ /* handle completion now? */
if ((urb_index + 1) != urb->number_of_packets) 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 */ /* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) {
&ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN; status = -ESHUTDOWN;
goto done_not_linked; goto done_not_linked;
} }
@ -2263,7 +2250,7 @@ scan_periodic (struct ehci_hcd *ehci)
now_uframe = ehci->next_uframe; now_uframe = ehci->next_uframe;
if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) { if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
clock = ehci_readl(ehci, &ehci->regs->frame_index); clock = ehci_readl(ehci, &ehci->regs->frame_index);
clock_frame = (clock >> 3) % ehci->periodic_size; clock_frame = (clock >> 3) & (ehci->periodic_size - 1);
} else { } else {
clock = now_uframe + mod - 1; clock = now_uframe + mod - 1;
clock_frame = -1; clock_frame = -1;
@ -2272,7 +2259,7 @@ scan_periodic (struct ehci_hcd *ehci)
free_cached_lists(ehci); free_cached_lists(ehci);
ehci->clock_frame = clock_frame; ehci->clock_frame = clock_frame;
} }
clock %= mod; clock &= mod - 1;
clock_frame = clock >> 3; clock_frame = clock >> 3;
for (;;) { for (;;) {
@ -2361,7 +2348,7 @@ restart:
* frame is current. * frame is current.
*/ */
if (((frame == clock_frame) || if (((frame == clock_frame) ||
(((frame + 1) % ehci->periodic_size) (((frame + 1) & (ehci->periodic_size - 1))
== clock_frame)) == clock_frame))
&& live && live
&& (q.sitd->hw_results & && (q.sitd->hw_results &
@ -2428,7 +2415,8 @@ restart:
|| ehci->periodic_sched == 0) || ehci->periodic_sched == 0)
break; break;
ehci->next_uframe = now_uframe; 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) if (now_uframe == now)
break; break;
@ -2441,7 +2429,7 @@ restart:
} }
} else { } else {
now_uframe++; 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 has_amcc_usb23:1;
unsigned need_io_watchdog:1; unsigned need_io_watchdog:1;
unsigned broken_periodic:1; unsigned broken_periodic:1;
unsigned fs_i_thresh:1; /* Intel iso scheduling */
/* required for usb32 quirk */ /* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6) #define OHCI_CTRL_HCFS (3 << 6)
@ -140,7 +141,8 @@ struct ehci_hcd { /* one per controller */
#define OHCI_HCCTRL_LEN 0x4 #define OHCI_HCCTRL_LEN 0x4
__hc32 *ohci_hcctrl_reg; __hc32 *ohci_hcctrl_reg;
unsigned has_hostpc:1; 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 */ u8 sbrn; /* packed release number */
/* irq statistics */ /* irq statistics */
@ -154,9 +156,6 @@ struct ehci_hcd { /* one per controller */
/* debug files */ /* debug files */
#ifdef DEBUG #ifdef DEBUG
struct dentry *debug_dir; struct dentry *debug_dir;
struct dentry *debug_async;
struct dentry *debug_periodic;
struct dentry *debug_registers;
#endif #endif
}; };
@ -401,15 +400,12 @@ struct ehci_iso_stream {
u32 refcount; u32 refcount;
u8 bEndpointAddress; u8 bEndpointAddress;
u8 highspeed; u8 highspeed;
u16 depth; /* depth in uframes */
struct list_head td_list; /* queued itds/sitds */ struct list_head td_list; /* queued itds/sitds */
struct list_head free_list; /* list of unused itds/sitds */ struct list_head free_list; /* list of unused itds/sitds */
struct usb_device *udev; struct usb_device *udev;
struct usb_host_endpoint *ep; struct usb_host_endpoint *ep;
/* output of (re)scheduling */ /* output of (re)scheduling */
unsigned long start; /* jiffies */
unsigned long rescheduled;
int next_uframe; int next_uframe;
__hc32 splits; __hc32 splits;
@ -538,11 +534,11 @@ struct ehci_fstn {
/* Prepare the PORTSC wakeup flags during controller suspend/resume */ /* Prepare the PORTSC wakeup flags during controller suspend/resume */
#define ehci_prepare_ports_for_controller_suspend(ehci) \ #define ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup) \
ehci_adjust_port_wakeup_flags(ehci, true); ehci_adjust_port_wakeup_flags(ehci, true, do_wakeup);
#define ehci_prepare_ports_for_controller_resume(ehci) \ #define ehci_prepare_ports_for_controller_resume(ehci) \
ehci_adjust_port_wakeup_flags(ehci, false); 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; goto error_set_cluster_id;
usb_hcd->uses_new_polling = 1; 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; usb_hcd->state = HC_STATE_RUNNING;
result = 0; result = 0;
out: out:
@ -776,7 +776,7 @@ static int hwahc_probe(struct usb_interface *usb_iface,
goto error_alloc; goto error_alloc;
} }
usb_hcd->wireless = 1; 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); wusbhc = usb_hcd_to_wusbhc(usb_hcd);
hwahc = container_of(wusbhc, struct hwahc, wusbhc); hwahc = container_of(wusbhc, struct hwahc, wusbhc);
hwahc_init(hwahc); hwahc_init(hwahc);

View File

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

View File

@ -8,29 +8,7 @@
/* /*
* Platform specific compile time options * Platform specific compile time options
*/ */
#if defined(CONFIG_ARCH_KARO) #if defined(CONFIG_BLACKFIN)
#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)
#include <linux/io.h> #include <linux/io.h>
#define USE_32BIT 0 #define USE_32BIT 0

View File

@ -482,7 +482,6 @@ static int isp1760_run(struct usb_hcd *hcd)
u32 chipid; u32 chipid;
hcd->uses_new_polling = 1; hcd->uses_new_polling = 1;
hcd->poll_rh = 0;
hcd->state = HC_STATE_RUNNING; hcd->state = HC_STATE_RUNNING;
isp1760_enable_interrupts(hcd); 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; epnum = urb->ep->desc.bEndpointAddress;
spin_lock_irqsave(&priv->lock, flags); 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; rc = -ESHUTDOWN;
goto done; goto done;
} }

View File

@ -645,7 +645,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
hcd->product_desc, hcd->product_desc,
hcd_name); hcd_name);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { if (!HCD_HW_ACCESSIBLE(hcd)) {
size -= scnprintf (next, size, size -= scnprintf (next, size,
"SUSPENDED (no register access)\n"); "SUSPENDED (no register access)\n");
goto done; goto done;
@ -687,7 +687,7 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
next += temp; next += temp;
temp = scnprintf (next, size, "hub poll timer %s\n", 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; size -= temp;
next += temp; next += temp;

View File

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

View File

@ -284,7 +284,7 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
spin_lock_irq (&ohci->lock); spin_lock_irq (&ohci->lock);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) if (unlikely(!HCD_HW_ACCESSIBLE(hcd)))
rc = -ESHUTDOWN; rc = -ESHUTDOWN;
else else
rc = ohci_rh_suspend (ohci, 0); rc = ohci_rh_suspend (ohci, 0);
@ -302,7 +302,7 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
spin_lock_irq (&ohci->lock); spin_lock_irq (&ohci->lock);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) if (unlikely(!HCD_HW_ACCESSIBLE(hcd)))
rc = -ESHUTDOWN; rc = -ESHUTDOWN;
else else
rc = ohci_rh_resume (ohci); 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); ohci_readl(ohci, &ohci->regs->intrenable);
msleep(20); 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 */ /* 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 poll_rh = 1;
int rhsc_enable; 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 * status register. For their sake we won't re-enable RHSC
* interrupts if the interrupt bit is already active. * 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; unsigned long flags;
spin_lock_irqsave (&ohci->lock, flags); spin_lock_irqsave (&ohci->lock, flags);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) if (!HCD_HW_ACCESSIBLE(hcd))
goto done; goto done;
/* undocumented erratum seen on at least rev D */ /* 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, if (ohci_root_hub_state_changes(ohci, changed,
any_connected, rhsc_status); any_connected, rhsc_status))
set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
else
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
done: done:
spin_unlock_irqrestore (&ohci->lock, flags); spin_unlock_irqrestore (&ohci->lock, flags);
@ -701,7 +710,7 @@ static int ohci_hub_control (
u32 temp; u32 temp;
int retval = 0; int retval = 0;
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) if (unlikely(!HCD_HW_ACCESSIBLE(hcd)))
return -ESHUTDOWN; return -ESHUTDOWN;
switch (typeReq) { switch (typeReq) {

View File

@ -392,7 +392,7 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd)
#ifdef CONFIG_PM #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); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags; 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); struct usb_hcd *hcd = ssb_get_drvdata(dev);
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
usb_remove_hcd(hcd); usb_remove_hcd(hcd);
iounmap(hcd->regs); iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd); usb_put_hcd(hcd);
ssb_device_disable(dev, 0); ssb_device_disable(dev, 0);
} }
@ -106,10 +109,52 @@ static int ssb_ohci_attach(struct ssb_device *dev)
int err = -ENOMEM; int err = -ENOMEM;
u32 tmp, flags = 0; u32 tmp, flags = 0;
if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) ||
flags |= SSB_OHCI_TMSLOW_HOSTMODE; 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, hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
dev_name(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[] = { 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_HOSTDEV, SSB_ANY_REV),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, 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 SSB_DEVTABLE_END
}; };
MODULE_DEVICE_TABLE(ssb, ssb_ohci_table); 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 #endif
spin_lock_irqsave(&oxu->lock, flags); spin_lock_irqsave(&oxu->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, if (unlikely(!HCD_HW_ACCESSIBLE(oxu_to_hcd(oxu)))) {
&oxu_to_hcd(oxu)->flags))) {
rc = -ESHUTDOWN; rc = -ESHUTDOWN;
goto done; goto done;
} }
@ -2209,8 +2208,7 @@ static int intr_submit(struct oxu_hcd *oxu, struct urb *urb,
spin_lock_irqsave(&oxu->lock, flags); spin_lock_irqsave(&oxu->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, if (unlikely(!HCD_HW_ACCESSIBLE(oxu_to_hcd(oxu)))) {
&oxu_to_hcd(oxu)->flags))) {
status = -ESHUTDOWN; status = -ESHUTDOWN;
goto done; goto done;
} }
@ -2715,7 +2713,6 @@ static int oxu_run(struct usb_hcd *hcd)
u32 temp, hcc_params; u32 temp, hcc_params;
hcd->uses_new_polling = 1; hcd->uses_new_polling = 1;
hcd->poll_rh = 0;
/* EHCI spec section 4.1 */ /* EHCI spec section 4.1 */
retval = ehci_reset(oxu); retval = ehci_reset(oxu);

View File

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

View File

@ -17,7 +17,6 @@
#include "uhci-hcd.h" #include "uhci-hcd.h"
#define uhci_debug_operations (* (const struct file_operations *) NULL)
static struct dentry *uhci_debugfs_root; static struct dentry *uhci_debugfs_root;
#ifdef DEBUG #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_hcd *uhci = inode->i_private;
struct uhci_debug *up; struct uhci_debug *up;
int ret = -ENOMEM;
unsigned long flags; unsigned long flags;
lock_kernel();
up = kmalloc(sizeof(*up), GFP_KERNEL); up = kmalloc(sizeof(*up), GFP_KERNEL);
if (!up) if (!up)
goto out; return -ENOMEM;
up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL); up->data = kmalloc(MAX_OUTPUT, GFP_KERNEL);
if (!up->data) { if (!up->data) {
kfree(up); kfree(up);
goto out; return -ENOMEM;
} }
up->size = 0; up->size = 0;
@ -517,10 +514,7 @@ static int uhci_debug_open(struct inode *inode, struct file *file)
file->private_data = up; file->private_data = up;
ret = 0; return 0;
out:
unlock_kernel();
return ret;
} }
static loff_t uhci_debug_lseek(struct file *file, loff_t off, int whence) 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; struct uhci_debug *up;
loff_t new = -1; loff_t new = -1;
lock_kernel();
up = file->private_data; up = file->private_data;
/* XXX: atomic 64bit seek access, but that needs to be fixed in the VFS */
switch (whence) { switch (whence) {
case 0: case 0:
new = off; 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; new = file->f_pos + off;
break; break;
} }
if (new < 0 || new > up->size) {
unlock_kernel(); if (new < 0 || new > up->size)
return -EINVAL; return -EINVAL;
}
unlock_kernel();
return (file->f_pos = new); return (file->f_pos = new);
} }
@ -564,7 +557,6 @@ static int uhci_debug_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
#undef uhci_debug_operations
static const struct file_operations uhci_debug_operations = { static const struct file_operations uhci_debug_operations = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = uhci_debug_open, .open = uhci_debug_open,
@ -572,6 +564,7 @@ static const struct file_operations uhci_debug_operations = {
.read = uhci_debug_read, .read = uhci_debug_read,
.release = uhci_debug_release, .release = uhci_debug_release,
}; };
#define UHCI_DEBUG_OPS
#endif /* CONFIG_DEBUG_FS */ #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->rh_state = UHCI_RH_RESET;
uhci->is_stopped = UHCI_IS_STOPPED; uhci->is_stopped = UHCI_IS_STOPPED;
uhci_to_hcd(uhci)->state = HC_STATE_HALT; 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 */ 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) 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 */ /* Set the frame length to the default: 1 ms exactly */
outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF); outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
@ -191,8 +193,11 @@ static void configure_hc(struct uhci_hcd *uhci)
mb(); mb();
/* Enable PIRQ */ /* Enable PIRQ */
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, pci_write_config_word(pdev, USBLEGSUP, USBLEGSUP_DEFAULT);
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 /* If interrupts don't work and remote wakeup is enabled then
* the suspended root hub needs to be polled. * 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_scan_schedule(uhci);
uhci_fsbr_off(uhci); uhci_fsbr_off(uhci);
@ -363,7 +371,7 @@ static void start_rh(struct uhci_hcd *uhci)
uhci->io_addr + USBINTR); uhci->io_addr + USBINTR);
mb(); mb();
uhci->rh_state = UHCI_RH_RUNNING; 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) 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); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int retval = -EBUSY; int retval = -EBUSY;
int i; int i;
struct dentry *dentry; struct dentry __maybe_unused *dentry;
hcd->uses_new_polling = 1; 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_LIST_HEAD(&uhci->idle_qh_list);
init_waitqueue_head(&uhci->waitqh); init_waitqueue_head(&uhci->waitqh);
if (DEBUG_CONFIGURED) { #ifdef UHCI_DEBUG_OPS
dentry = debugfs_create_file(hcd->self.bus_name, dentry = debugfs_create_file(hcd->self.bus_name,
S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root,
uhci, &uhci_debug_operations); uhci, &uhci_debug_operations);
if (!dentry) { if (!dentry) {
dev_err(uhci_dev(uhci), "couldn't create uhci " dev_err(uhci_dev(uhci), "couldn't create uhci debugfs entry\n");
"debugfs entry\n"); return -ENOMEM;
retval = -ENOMEM;
goto err_create_debug_entry;
}
uhci->dentry = dentry;
} }
uhci->dentry = dentry;
#endif
uhci->frame = dma_alloc_coherent(uhci_dev(uhci), uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
UHCI_NUMFRAMES * sizeof(*uhci->frame), UHCI_NUMFRAMES * sizeof(*uhci->frame),
@ -691,7 +697,9 @@ static int uhci_start(struct usb_hcd *hcd)
configure_hc(uhci); configure_hc(uhci);
uhci->is_initialized = 1; uhci->is_initialized = 1;
spin_lock_irq(&uhci->lock);
start_rh(uhci); start_rh(uhci);
spin_unlock_irq(&uhci->lock);
return 0; return 0;
/* /*
@ -722,7 +730,6 @@ err_alloc_frame_cpu:
err_alloc_frame: err_alloc_frame:
debugfs_remove(uhci->dentry); debugfs_remove(uhci->dentry);
err_create_debug_entry:
return retval; return retval;
} }
@ -731,7 +738,7 @@ static void uhci_stop(struct usb_hcd *hcd)
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
spin_lock_irq(&uhci->lock); 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_hc_died(uhci);
uhci_scan_schedule(uhci); uhci_scan_schedule(uhci);
spin_unlock_irq(&uhci->lock); spin_unlock_irq(&uhci->lock);
@ -748,7 +755,7 @@ static int uhci_rh_suspend(struct usb_hcd *hcd)
int rc = 0; int rc = 0;
spin_lock_irq(&uhci->lock); spin_lock_irq(&uhci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) if (!HCD_HW_ACCESSIBLE(hcd))
rc = -ESHUTDOWN; rc = -ESHUTDOWN;
else if (uhci->dead) else if (uhci->dead)
; /* Dead controllers tell no tales */ ; /* Dead controllers tell no tales */
@ -775,7 +782,7 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
int rc = 0; int rc = 0;
spin_lock_irq(&uhci->lock); spin_lock_irq(&uhci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) if (!HCD_HW_ACCESSIBLE(hcd))
rc = -ESHUTDOWN; rc = -ESHUTDOWN;
else if (!uhci->dead) else if (!uhci->dead)
wakeup_rh(uhci); wakeup_rh(uhci);
@ -783,15 +790,16 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
return rc; 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 uhci_hcd *uhci = hcd_to_uhci(hcd);
struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci));
int rc = 0; int rc = 0;
dev_dbg(uhci_dev(uhci), "%s\n", __func__); dev_dbg(uhci_dev(uhci), "%s\n", __func__);
spin_lock_irq(&uhci->lock); 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 */ goto done_okay; /* Already suspended or dead */
if (uhci->rh_state > UHCI_RH_SUSPENDED) { 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 /* All PCI host controllers are required to disable IRQ generation
* at the source, so we must turn off PIRQ. * at the source, so we must turn off PIRQ.
*/ */
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); pci_write_config_word(pdev, USBLEGSUP, 0);
mb(); clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
hcd->poll_rh = 0;
/* 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: done_okay:
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); 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. * even if the controller was dead.
*/ */
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
mb();
spin_lock_irq(&uhci->lock); spin_lock_irq(&uhci->lock);
@ -834,8 +845,6 @@ static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
if (hibernated) if (hibernated)
uhci_hc_died(uhci); uhci_hc_died(uhci);
/* FIXME: Disable non-PME# remote wakeup? */
/* The firmware or a boot kernel may have changed the controller /* The firmware or a boot kernel may have changed the controller
* settings during a system wakeup. Check it and reconfigure * settings during a system wakeup. Check it and reconfigure
* to avoid problems. * 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 */ /* If the controller was dead before, it's back alive now */
configure_hc(uhci); configure_hc(uhci);
if (uhci->rh_state == UHCI_RH_RESET) { /* Tell the core if the controller had to be reset */
if (uhci->rh_state == UHCI_RH_RESET)
/* The controller had to be reset */
usb_root_hub_lost_power(hcd->self.root_hub); usb_root_hub_lost_power(hcd->self.root_hub);
suspend_rh(uhci, UHCI_RH_SUSPENDED);
}
spin_unlock_irq(&uhci->lock); spin_unlock_irq(&uhci->lock);
/* If interrupts don't work and remote wakeup is enabled then /* If interrupts don't work and remote wakeup is enabled then
* the suspended root hub needs to be polled. * the suspended root hub needs to be polled.
*/ */
if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) { if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup)
hcd->poll_rh = 1; set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
usb_hcd_poll_rh_status(hcd);
} /* Does the root hub have a port wakeup pending? */
usb_hcd_poll_rh_status(hcd);
return 0; return 0;
} }
#endif #endif

View File

@ -67,12 +67,17 @@
#define USBPORTSC_RES3 0x4000 /* reserved, write zeroes */ #define USBPORTSC_RES3 0x4000 /* reserved, write zeroes */
#define USBPORTSC_RES4 0x8000 /* reserved, write zeroes */ #define USBPORTSC_RES4 0x8000 /* reserved, write zeroes */
/* Legacy support register */ /* PCI legacy support register */
#define USBLEGSUP 0xc0 #define USBLEGSUP 0xc0
#define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */ #define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
#define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */ #define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */
#define USBLEGSUP_RO 0x5040 /* R/O and reserved 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_BITS cpu_to_le32(0x000F)
#define UHCI_PTR_TERM cpu_to_le32(0x0001) #define UHCI_PTR_TERM cpu_to_le32(0x0001)
#define UHCI_PTR_QH cpu_to_le32(0x0002) #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); spin_lock_irqsave(&uhci->lock, flags);
uhci_scan_schedule(uhci); uhci_scan_schedule(uhci);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead) if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead)
goto done; goto done;
uhci_check_ports(uhci); 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_SUSPENDING:
case UHCI_RH_SUSPENDED: case UHCI_RH_SUSPENDED:
/* if port change, ask to be resumed */ /* if port change, ask to be resumed */
if (status) if (status || uhci->resuming_ports)
usb_hcd_resume_root_hub(hcd); usb_hcd_resume_root_hub(hcd);
break; break;
@ -246,7 +246,7 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wPortChange, wPortStatus; u16 wPortChange, wPortStatus;
unsigned long flags; unsigned long flags;
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead) if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead)
return -ETIMEDOUT; return -ETIMEDOUT;
spin_lock_irqsave(&uhci->lock, flags); 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; qh->unlink_frame = uhci->frame_number;
/* Force an interrupt so we know when the QH is fully unlinked */ /* 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); uhci_set_next_interrupt(uhci);
/* Move the QH from its old list to the end of the unlinking list */ /* 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; qh->advance_jiffies = jiffies;
goto done; goto done;
} }
ret = 0; ret = uhci->is_stopped;
} }
/* The queue hasn't advanced; check for timeout */ /* 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); whc_write_wusbcmd(whc, WUSBCMD_RUN, WUSBCMD_RUN);
usb_hcd->uses_new_polling = 1; 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; usb_hcd->state = HC_STATE_RUNNING;
out: 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)) || (prev_end & (WHCI_PAGE_SIZE-1))
|| (dma_addr & (WHCI_PAGE_SIZE-1)) || (dma_addr & (WHCI_PAGE_SIZE-1))
|| std->len + WHCI_PAGE_SIZE > QTD_MAX_XFER_SIZE) { || 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; return -EINVAL;
std = qset_new_std(whc, qset, urb, mem_flags); std = qset_new_std(whc, qset, urb, mem_flags);
if (std == NULL) { 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]; 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 #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
static int xhci_test_radix_tree(struct xhci_hcd *xhci, static int xhci_test_radix_tree(struct xhci_hcd *xhci,
unsigned int num_streams, 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); ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
/* Set up the endpoint ring */ /* 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) { if (!virt_dev->eps[ep_index].new_ring) {
/* Attempt to use the ring cache */ /* Attempt to use the ring cache */
if (virt_dev->num_rings_cached == 0) if (virt_dev->num_rings_cached == 0)
@ -1124,6 +1091,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
virt_dev->num_rings_cached--; virt_dev->num_rings_cached--;
xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring); 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_ring = virt_dev->eps[ep_index].new_ring;
ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state; 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; 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, void xhci_free_command(struct xhci_hcd *xhci,
struct xhci_command *command) 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; unsigned int num_tests;
int i, ret; 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++) { for (i = 0; i < num_tests; i++) {
ret = xhci_test_trb_in_td(xhci, ret = xhci_test_trb_in_td(xhci,
xhci->event_ring->first_seg, 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; 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++) { for (i = 0; i < num_tests; i++) {
ret = xhci_test_trb_in_td(xhci, ret = xhci_test_trb_in_td(xhci,
complex_test_vector[i].input_seg, 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; 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) 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 xhci_hcd *xhci = hcd_to_xhci(hcd);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller); struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
int retval; int retval;
u32 temp;
hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2;
@ -93,6 +94,14 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
return retval; return retval;
xhci_dbg(xhci, "Reset complete\n"); 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"); xhci_dbg(xhci, "Calling HCD init\n");
/* Initialize HCD and host controller data structures. */ /* Initialize HCD and host controller data structures. */
retval = xhci_init(hcd); 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. * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <linux/pci.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/module.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); return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
} }
/*
#if 0 * Free IRQs
/* Set up MSI-X table for entry 0 (may claim other entries later) */ * free all IRQs request
static int xhci_setup_msix(struct xhci_hcd *xhci) */
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); struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
xhci->msix_count = 0; /* return if using legacy interrupt */
/* XXX: did I do this right? ixgbe does kcalloc for more than one */ if (xhci_to_hcd(xhci)->irq >= 0)
xhci->msix_entries = kmalloc(sizeof(struct msix_entry), GFP_KERNEL); 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) { if (!xhci->msix_entries) {
xhci_err(xhci, "Failed to allocate MSI-X entries\n"); xhci_err(xhci, "Failed to allocate MSI-X entries\n");
return -ENOMEM; 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); ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count);
if (ret) { if (ret) {
@ -194,20 +257,19 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
goto free_entries; goto free_entries;
} }
/* for (i = 0; i < xhci->msix_count; i++) {
* Pass the xhci pointer value as the request_irq "cookie". ret = request_irq(xhci->msix_entries[i].vector,
* If more irqs are added, this will need to be unique for each one. (irq_handler_t)xhci_msi_irq,
*/ 0, "xhci_hcd", xhci_to_hcd(xhci));
ret = request_irq(xhci->msix_entries[0].vector, &xhci_irq, 0, if (ret)
"xHCI", xhci_to_hcd(xhci)); goto disable_msix;
if (ret) {
xhci_err(xhci, "Failed to allocate MSI-X interrupt\n");
goto disable_msix;
} }
xhci_dbg(xhci, "Finished setting up MSI-X\n");
return 0; return ret;
disable_msix: disable_msix:
xhci_err(xhci, "disable MSI-X interrupt\n");
xhci_free_irq(xhci);
pci_disable_msix(pdev); pci_disable_msix(pdev);
free_entries: free_entries:
kfree(xhci->msix_entries); kfree(xhci->msix_entries);
@ -215,21 +277,23 @@ free_entries:
return ret; return ret;
} }
/* XXX: code duplication; can xhci_setup_msix call this? */
/* Free any IRQs and disable MSI-X */ /* Free any IRQs and disable MSI-X */
static void xhci_cleanup_msix(struct xhci_hcd *xhci) static void xhci_cleanup_msix(struct xhci_hcd *xhci)
{ {
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); 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); xhci_free_irq(xhci);
pci_disable_msix(pdev);
kfree(xhci->msix_entries); if (xhci->msix_entries) {
xhci->msix_entries = NULL; pci_disable_msix(pdev);
xhci_dbg(xhci, "Finished cleaning up MSI-X\n"); kfree(xhci->msix_entries);
xhci->msix_entries = NULL;
} else {
pci_disable_msi(pdev);
}
return;
} }
#endif
/* /*
* Initialize memory for HCD and xHC (one-time init). * Initialize memory for HCD and xHC (one-time init).
@ -257,100 +321,8 @@ int xhci_init(struct usb_hcd *hcd)
return retval; 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 #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
void xhci_event_ring_work(unsigned long arg) void xhci_event_ring_work(unsigned long arg)
@ -423,21 +395,36 @@ int xhci_run(struct usb_hcd *hcd)
{ {
u32 temp; u32 temp;
u64 temp_64; u64 temp_64;
u32 ret;
struct xhci_hcd *xhci = hcd_to_xhci(hcd); 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; void (*doorbell)(struct xhci_hcd *) = NULL;
hcd->uses_new_polling = 1; hcd->uses_new_polling = 1;
hcd->poll_rh = 0;
xhci_dbg(xhci, "xhci_run\n"); xhci_dbg(xhci, "xhci_run\n");
#if 0 /* FIXME: MSI not setup yet */ /* unregister the legacy interrupt */
/* Do this at the very last minute */ if (hcd->irq)
ret = xhci_setup_msix(xhci); free_irq(hcd->irq, hcd);
if (!ret) hcd->irq = -1;
return ret;
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 #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
init_timer(&xhci->event_ring_timer); init_timer(&xhci->event_ring_timer);
xhci->event_ring_timer.data = (unsigned long) xhci; xhci->event_ring_timer.data = (unsigned long) xhci;
@ -495,7 +482,6 @@ int xhci_run(struct usb_hcd *hcd)
return -ENODEV; return -ENODEV;
} }
xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp);
if (doorbell) if (doorbell)
(*doorbell)(xhci); (*doorbell)(xhci);
if (xhci->quirks & XHCI_NEC_HOST) if (xhci->quirks & XHCI_NEC_HOST)
@ -522,11 +508,9 @@ void xhci_stop(struct usb_hcd *hcd)
spin_lock_irq(&xhci->lock); spin_lock_irq(&xhci->lock);
xhci_halt(xhci); xhci_halt(xhci);
xhci_reset(xhci); xhci_reset(xhci);
xhci_cleanup_msix(xhci);
spin_unlock_irq(&xhci->lock); spin_unlock_irq(&xhci->lock);
#if 0 /* No MSI yet */
xhci_cleanup_msix(xhci);
#endif
#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
/* Tell the event ring poll function not to reschedule */ /* Tell the event ring poll function not to reschedule */
xhci->zombie = 1; xhci->zombie = 1;
@ -560,11 +544,8 @@ void xhci_shutdown(struct usb_hcd *hcd)
spin_lock_irq(&xhci->lock); spin_lock_irq(&xhci->lock);
xhci_halt(xhci); xhci_halt(xhci);
spin_unlock_irq(&xhci->lock);
#if 0
xhci_cleanup_msix(xhci); xhci_cleanup_msix(xhci);
#endif spin_unlock_irq(&xhci->lock);
xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n", xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n",
xhci_readl(xhci, &xhci->op_regs->status)); 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; unsigned long flags;
int ret = 0; int ret = 0;
unsigned int slot_id, ep_index; 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) if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0)
return -EINVAL; return -EINVAL;
@ -734,12 +716,36 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
ret = -EINVAL; ret = -EINVAL;
goto exit; goto exit;
} }
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { if (!HCD_HW_ACCESSIBLE(hcd)) {
if (!in_interrupt()) if (!in_interrupt())
xhci_dbg(xhci, "urb submitted during PCI suspend\n"); xhci_dbg(xhci, "urb submitted during PCI suspend\n");
ret = -ESHUTDOWN; ret = -ESHUTDOWN;
goto exit; 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)) { if (usb_endpoint_xfer_control(&urb->ep->desc)) {
/* Check to see if the max packet size for the default control /* Check to see if the max packet size for the default control
* endpoint changed during FS device enumeration * 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); slot_id, ep_index);
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
} else { } 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: exit:
return ret; return ret;
dying: dying:
xhci_urb_free_priv(xhci, urb_priv);
urb->hcpriv = NULL;
xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for " xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for "
"non-responsive xHCI host.\n", "non-responsive xHCI host.\n",
urb->ep->desc.bEndpointAddress, urb); urb->ep->desc.bEndpointAddress, urb);
@ -800,6 +813,47 @@ dying:
return -ESHUTDOWN; 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 * 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 * 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) int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{ {
unsigned long flags; unsigned long flags;
int ret; int ret, i;
u32 temp; u32 temp;
struct xhci_hcd *xhci; struct xhci_hcd *xhci;
struct urb_priv *urb_priv;
struct xhci_td *td; struct xhci_td *td;
unsigned int ep_index; unsigned int ep_index;
struct xhci_ring *ep_ring; 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); temp = xhci_readl(xhci, &xhci->op_regs->status);
if (temp == 0xffffffff) { if (temp == 0xffffffff) {
xhci_dbg(xhci, "HW died, freeing TD.\n"); 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); usb_hcd_unlink_urb_from_ep(hcd, urb);
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, -ESHUTDOWN); usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, -ESHUTDOWN);
kfree(td); xhci_urb_free_priv(xhci, urb_priv);
return ret; return ret;
} }
if (xhci->xhc_state & XHCI_STATE_DYING) { 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_dbg(xhci, "Endpoint ring:\n");
xhci_debug_ring(xhci, ep_ring); 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 /* Queue a stop endpoint command, but only if this is
* the first cancellation to be handled. * the first cancellation to be handled.
*/ */

View File

@ -720,6 +720,14 @@ struct xhci_virt_ep {
struct timer_list stop_cmd_timer; struct timer_list stop_cmd_timer;
int stop_cmds_pending; int stop_cmds_pending;
struct xhci_hcd *xhci; 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 { struct xhci_virt_device {
@ -911,6 +919,9 @@ struct xhci_event_cmd {
/* Control transfer TRB specific fields */ /* Control transfer TRB specific fields */
#define TRB_DIR_IN (1<<16) #define TRB_DIR_IN (1<<16)
/* Isochronous TRB specific fields */
#define TRB_SIA (1<<31)
struct xhci_generic_trb { struct xhci_generic_trb {
u32 field[4]; u32 field[4];
}; };
@ -1082,6 +1093,12 @@ struct xhci_scratchpad {
dma_addr_t *sp_dma_buffers; 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: * 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, * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
@ -1130,7 +1147,7 @@ struct xhci_hcd {
int page_size; int page_size;
/* Valid values are 12 to 20, inclusive */ /* Valid values are 12 to 20, inclusive */
int page_shift; int page_shift;
/* only one MSI vector for now, but might need more later */ /* msi-x vectors */
int msix_count; int msix_count;
struct msix_entry *msix_entries; struct msix_entry *msix_entries;
/* data structures */ /* 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_ring *xhci_dma_to_transfer_ring(
struct xhci_virt_ep *ep, struct xhci_virt_ep *ep,
u64 address); 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_ring *xhci_stream_id_to_ring(
struct xhci_virt_device *dev, struct xhci_virt_device *dev,
unsigned int ep_index, 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, struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
bool allocate_in_ctx, bool allocate_completion, bool allocate_in_ctx, bool allocate_completion,
gfp_t mem_flags); 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, void xhci_free_command(struct xhci_hcd *xhci,
struct xhci_command *command); struct xhci_command *command);
@ -1358,6 +1371,7 @@ void xhci_stop(struct usb_hcd *hcd);
void xhci_shutdown(struct usb_hcd *hcd); void xhci_shutdown(struct usb_hcd *hcd);
int xhci_get_frame(struct usb_hcd *hcd); int xhci_get_frame(struct usb_hcd *hcd);
irqreturn_t xhci_irq(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); int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev);
void xhci_free_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, 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); 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_ring_cmd_db(struct xhci_hcd *xhci);
void *xhci_setup_one_noop(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_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, int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id); 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 slot_id, unsigned int ep_index);
int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
int slot_id, unsigned int ep_index); 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, int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id, bool command_must_succeed); u32 slot_id, bool command_must_succeed);
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,

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