dect
/
linux-2.6
Archived
13
0
Fork 0

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: (220 commits)
  USB: backlight, appledisplay: fix incomplete registration failure handling
  USB: pl2303: remove unnecessary reset of usb_device in urbs
  USB: ftdi_sio: remove obsolete check in unthrottle
  USB: ftdi_sio: remove unused tx_bytes counter
  USB: qcaux: driver for auxiliary serial ports on Qualcomm devices
  USB: pl2303: initial TIOCGSERIAL support
  USB: option: add Longcheer/Longsung vendor ID
  USB: fix I2C API usage in ohci-pnx4008.
  USB: usbmon: mask seconds properly in text API
  USB: sisusbvga: no unnecessary GFP_ATOMIC
  USB: storage: onetouch: unnecessary GFP_ATOMIC
  USB: serial: ftdi: add CONTEC vendor and product id
  USB: remove references to port->port.count from the serial drivers
  USB: tty: Prune uses of tty_request_room in the USB layer
  USB: tty: Add a function to insert a string of characters with the same flag
  USB: don't read past config->interface[] if usb_control_msg() fails in usb_reset_configuration()
  USB: tty: kill request_room for USB ACM class
  USB: tty: sort out the request_room handling for whiteheat
  USB: storage: fix misplaced parenthesis
  USB: vstusb.c: removal of driver for Vernier Software & Technology, Inc., devices and spectrometers
  ...
This commit is contained in:
Linus Torvalds 2010-03-03 08:48:58 -08:00
commit 7f5b09c15a
218 changed files with 7446 additions and 3687 deletions

View File

@ -159,3 +159,14 @@ Description:
device. This is useful to ensure auto probing won't
match the driver to the device. For example:
# echo "046d c315" > /sys/bus/usb/drivers/foo/remove_id
What: /sys/bus/usb/device/.../avoid_reset
Date: December 2009
Contact: Oliver Neukum <oliver@neukum.org>
Description:
Writing 1 to this file tells the kernel that this
device will morph into another mode when it is reset.
Drivers will not use reset for error handling for
such devices.
Users:
usb_modeswitch

View File

@ -139,7 +139,6 @@ Code Seq#(hex) Include File Comments
'K' all linux/kd.h
'L' 00-1F linux/loop.h conflict!
'L' 10-1F drivers/scsi/mpt2sas/mpt2sas_ctl.h conflict!
'L' 20-2F linux/usb/vstusb.h
'L' E0-FF linux/ppdd.h encrypted disk device driver
<http://linux01.gwdg.de/~alatham/ppdd.html>
'M' all linux/soundcard.h conflict!

View File

@ -32,6 +32,8 @@ cs89x0.txt
- the Crystal LAN (CS8900/20-based) Ethernet ISA adapter driver
cxacru.txt
- Conexant AccessRunner USB ADSL Modem
cxacru-cf.py
- Conexant AccessRunner USB ADSL Modem configuration file parser
de4x5.txt
- the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver
decnet.txt

View File

@ -0,0 +1,48 @@
#!/usr/bin/env python
# Copyright 2009 Simon Arlott
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59
# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Usage: cxacru-cf.py < cxacru-cf.bin
# Output: values string suitable for the sysfs adsl_config attribute
#
# Warning: cxacru-cf.bin with MD5 hash cdbac2689969d5ed5d4850f117702110
# contains mis-aligned values which will stop the modem from being able
# to make a connection. If the first and last two bytes are removed then
# the values become valid, but the modulation will be forced to ANSI
# T1.413 only which may not be appropriate.
#
# The original binary format is a packed list of le32 values.
import sys
import struct
i = 0
while True:
buf = sys.stdin.read(4)
if len(buf) == 0:
break
elif len(buf) != 4:
sys.stdout.write("\n")
sys.stderr.write("Error: read {0} not 4 bytes\n".format(len(buf)))
sys.exit(1)
if i > 0:
sys.stdout.write(" ")
sys.stdout.write("{0:x}={1}".format(i, struct.unpack("<I", buf)[0]))
i += 1
sys.stdout.write("\n")

View File

@ -4,6 +4,12 @@ While it is capable of managing/maintaining the ADSL connection without the
module loaded, the device will sometimes stop responding after unloading the
driver and it is necessary to unplug/remove power to the device to fix this.
Note: support for cxacru-cf.bin has been removed. It was not loaded correctly
so it had no effect on the device configuration. Fixing it could have stopped
existing devices working when an invalid configuration is supplied.
There is a script cxacru-cf.py to convert an existing file to the sysfs form.
Detected devices will appear as ATM devices named "cxacru". In /sys/class/atm/
these are directories named cxacruN where N is the device number. A symlink
named device points to the USB interface device's directory which contains
@ -15,6 +21,15 @@ several sysfs attribute files for retrieving device statistics:
* adsl_headend_environment
Information about the remote headend.
* adsl_config
Configuration writing interface.
Write parameters in hexadecimal format <index>=<value>,
separated by whitespace, e.g.:
"1=0 a=5"
Up to 7 parameters at a time will be sent and the modem will restart
the ADSL connection when any value is set. These are logged for future
reference.
* downstream_attenuation (dB)
* downstream_bits_per_frame
* downstream_rate (kbps)
@ -61,6 +76,7 @@ several sysfs attribute files for retrieving device statistics:
* mac_address
* modulation
"" (when not connected)
"ANSI T1.413"
"ITU-T G.992.1 (G.DMT)"
"ITU-T G.992.2 (G.LITE)"

View File

@ -41,8 +41,8 @@ USB-specific:
-EFBIG Host controller driver can't schedule that many ISO frames.
-EPIPE Specified endpoint is stalled. For non-control endpoints,
reset this status with usb_clear_halt().
-EPIPE The pipe type specified in the URB doesn't match the
endpoint's actual type.
-EMSGSIZE (a) endpoint maxpacket size is zero; it is not usable
in the current interface altsetting.
@ -60,6 +60,8 @@ USB-specific:
-EHOSTUNREACH URB was rejected because the device is suspended.
-ENOEXEC A control URB doesn't contain a Setup packet.
**************************************************************************
* Error codes returned by in urb->status *

View File

@ -2,7 +2,7 @@
Alan Stern <stern@rowland.harvard.edu>
November 10, 2009
December 11, 2009
@ -29,9 +29,9 @@ covered to some extent (see Documentation/power/*.txt for more
information about system PM).
Note: Dynamic PM support for USB is present only if the kernel was
built with CONFIG_USB_SUSPEND enabled. System PM support is present
only if the kernel was built with CONFIG_SUSPEND or CONFIG_HIBERNATION
enabled.
built with CONFIG_USB_SUSPEND enabled (which depends on
CONFIG_PM_RUNTIME). System PM support is present only if the kernel
was built with CONFIG_SUSPEND or CONFIG_HIBERNATION enabled.
What is Remote Wakeup?
@ -229,6 +229,11 @@ necessary operations by hand or add them to a udev script. You can
also change the idle-delay time; 2 seconds is not the best choice for
every device.
If a driver knows that its device has proper suspend/resume support,
it can enable autosuspend all by itself. For example, the video
driver for a laptop's webcam might do this, since these devices are
rarely used and so should normally be autosuspended.
Sometimes it turns out that even when a device does work okay with
autosuspend there are still problems. For example, there are
experimental patches adding autosuspend support to the usbhid driver,
@ -321,69 +326,81 @@ driver does so by calling these six functions:
void usb_autopm_get_interface_no_resume(struct usb_interface *intf);
void usb_autopm_put_interface_no_suspend(struct usb_interface *intf);
The functions work by maintaining a counter in the usb_interface
structure. When intf->pm_usage_count is > 0 then the interface is
deemed to be busy, and the kernel will not autosuspend the interface's
device. When intf->pm_usage_count is <= 0 then the interface is
considered to be idle, and the kernel may autosuspend the device.
The functions work by maintaining a usage counter in the
usb_interface's embedded device structure. When the counter is > 0
then the interface is deemed to be busy, and the kernel will not
autosuspend the interface's device. When the usage counter is = 0
then the interface is considered to be idle, and the kernel may
autosuspend the device.
(There is a similar pm_usage_count field in struct usb_device,
(There is a similar usage counter field in struct usb_device,
associated with the device itself rather than any of its interfaces.
This field is used only by the USB core.)
This counter is used only by the USB core.)
Drivers must not modify intf->pm_usage_count directly; its value
should be changed only be using the functions listed above. Drivers
are responsible for insuring that the overall change to pm_usage_count
during their lifetime balances out to 0 (it may be necessary for the
disconnect method to call usb_autopm_put_interface() one or more times
to fulfill this requirement). The first two routines use the PM mutex
in struct usb_device for mutual exclusion; drivers using the async
routines are responsible for their own synchronization and mutual
exclusion.
Drivers need not be concerned about balancing changes to the usage
counter; the USB core will undo any remaining "get"s when a driver
is unbound from its interface. As a corollary, drivers must not call
any of the usb_autopm_* functions after their diconnect() routine has
returned.
usb_autopm_get_interface() increments pm_usage_count and
attempts an autoresume if the new value is > 0 and the
device is suspended.
Drivers using the async routines are responsible for their own
synchronization and mutual exclusion.
usb_autopm_put_interface() decrements pm_usage_count and
attempts an autosuspend if the new value is <= 0 and the
device isn't suspended.
usb_autopm_get_interface() increments the usage counter and
does an autoresume if the device is suspended. If the
autoresume fails, the counter is decremented back.
usb_autopm_put_interface() decrements the usage counter and
attempts an autosuspend if the new value is = 0.
usb_autopm_get_interface_async() and
usb_autopm_put_interface_async() do almost the same things as
their non-async counterparts. The differences are: they do
not acquire the PM mutex, and they use a workqueue to do their
their non-async counterparts. The big difference is that they
use a workqueue to do the resume or suspend part of their
jobs. As a result they can be called in an atomic context,
such as an URB's completion handler, but when they return the
device will not generally not yet be in the desired state.
device will generally not yet be in the desired state.
usb_autopm_get_interface_no_resume() and
usb_autopm_put_interface_no_suspend() merely increment or
decrement the pm_usage_count value; they do not attempt to
carry out an autoresume or an autosuspend. Hence they can be
called in an atomic context.
decrement the usage counter; they do not attempt to carry out
an autoresume or an autosuspend. Hence they can be called in
an atomic context.
The conventional usage pattern is that a driver calls
The simplest usage pattern is that a driver calls
usb_autopm_get_interface() in its open routine and
usb_autopm_put_interface() in its close or release routine. But
other patterns are possible.
usb_autopm_put_interface() in its close or release routine. But other
patterns are possible.
The autosuspend attempts mentioned above will often fail for one
reason or another. For example, the power/level attribute might be
set to "on", or another interface in the same device might not be
idle. This is perfectly normal. If the reason for failure was that
the device hasn't been idle for long enough, a delayed workqueue
routine is automatically set up to carry out the operation when the
autosuspend idle-delay has expired.
the device hasn't been idle for long enough, a timer is scheduled to
carry out the operation automatically when the autosuspend idle-delay
has expired.
Autoresume attempts also can fail, although failure would mean that
the device is no longer present or operating properly. Unlike
autosuspend, there's no delay for an autoresume.
autosuspend, there's no idle-delay for an autoresume.
Other parts of the driver interface
-----------------------------------
Drivers can enable autosuspend for their devices by calling
usb_enable_autosuspend(struct usb_device *udev);
in their probe() routine, if they know that the device is capable of
suspending and resuming correctly. This is exactly equivalent to
writing "auto" to the device's power/level attribute. Likewise,
drivers can disable autosuspend by calling
usb_disable_autosuspend(struct usb_device *udev);
This is exactly the same as writing "on" to the power/level attribute.
Sometimes a driver needs to make sure that remote wakeup is enabled
during autosuspend. For example, there's not much point
autosuspending a keyboard if the user can't cause the keyboard to do a
@ -395,26 +412,27 @@ though, setting this flag won't cause the kernel to autoresume it.
Normally a driver would set this flag in its probe method, at which
time the device is guaranteed not to be autosuspended.)
The synchronous usb_autopm_* routines have to run in a sleepable
process context; they must not be called from an interrupt handler or
while holding a spinlock. In fact, the entire autosuspend mechanism
is not well geared toward interrupt-driven operation. However there
is one thing a driver can do in an interrupt handler:
If a driver does its I/O asynchronously in interrupt context, it
should call usb_autopm_get_interface_async() before starting output and
usb_autopm_put_interface_async() when the output queue drains. When
it receives an input event, it should call
usb_mark_last_busy(struct usb_device *udev);
This sets udev->last_busy to the current time. udev->last_busy is the
field used for idle-delay calculations; updating it will cause any
pending autosuspend to be moved back. The usb_autopm_* routines will
also set the last_busy field to the current time.
in the event handler. This sets udev->last_busy to the current time.
udev->last_busy is the field used for idle-delay calculations;
updating it will cause any pending autosuspend to be moved back. Most
of the usb_autopm_* routines will also set the last_busy field to the
current time.
Calling urb_mark_last_busy() from within an URB completion handler is
subject to races: The kernel may have just finished deciding the
device has been idle for long enough but not yet gotten around to
calling the driver's suspend method. The driver would have to be
responsible for synchronizing its suspend method with its URB
completion handler and causing the autosuspend to fail with -EBUSY if
an URB had completed too recently.
Asynchronous operation is always subject to races. For example, a
driver may call one of the usb_autopm_*_interface_async() routines at
a time when the core has just finished deciding the device has been
idle for long enough but not yet gotten around to calling the driver's
suspend method. The suspend method must be responsible for
synchronizing with the output request routine and the URB completion
handler; it should cause autosuspends to fail with -EBUSY if the
driver needs to use the device.
External suspend calls should never be allowed to fail in this way,
only autosuspend calls. The driver can tell them apart by checking
@ -422,75 +440,23 @@ the PM_EVENT_AUTO bit in the message.event argument to the suspend
method; this bit will be set for internal PM events (autosuspend) and
clear for external PM events.
Many of the ingredients in the autosuspend framework are oriented
towards interfaces: The usb_interface structure contains the
pm_usage_cnt field, and the usb_autopm_* routines take an interface
pointer as their argument. But somewhat confusingly, a few of the
pieces (i.e., usb_mark_last_busy()) use the usb_device structure
instead. Drivers need to keep this straight; they can call
interface_to_usbdev() to find the device structure for a given
interface.
Mutual exclusion
----------------
Locking requirements
--------------------
All three suspend/resume methods are always called while holding the
usb_device's PM mutex. For external events -- but not necessarily for
autosuspend or autoresume -- the device semaphore (udev->dev.sem) will
also be held. This implies that external suspend/resume events are
mutually exclusive with calls to probe, disconnect, pre_reset, and
post_reset; the USB core guarantees that this is true of internal
suspend/resume events as well.
For external events -- but not necessarily for autosuspend or
autoresume -- the device semaphore (udev->dev.sem) will be held when a
suspend or resume method is called. This implies that external
suspend/resume events are mutually exclusive with calls to probe,
disconnect, pre_reset, and post_reset; the USB core guarantees that
this is true of autosuspend/autoresume events as well.
If a driver wants to block all suspend/resume calls during some
critical section, it can simply acquire udev->pm_mutex. Note that
calls to resume may be triggered indirectly. Block IO due to memory
allocations can make the vm subsystem resume a device. Thus while
holding this lock you must not allocate memory with GFP_KERNEL or
GFP_NOFS.
Alternatively, if the critical section might call some of the
usb_autopm_* routines, the driver can avoid deadlock by doing:
down(&udev->dev.sem);
rc = usb_autopm_get_interface(intf);
and at the end of the critical section:
if (!rc)
usb_autopm_put_interface(intf);
up(&udev->dev.sem);
Holding the device semaphore will block all external PM calls, and the
usb_autopm_get_interface() will prevent any internal PM calls, even if
it fails. (Exercise: Why?)
The rules for locking order are:
Never acquire any device semaphore while holding any PM mutex.
Never acquire udev->pm_mutex while holding the PM mutex for
a device that isn't a descendant of udev.
In other words, PM mutexes should only be acquired going up the device
tree, and they should be acquired only after locking all the device
semaphores you need to hold. These rules don't matter to drivers very
much; they usually affect just the USB core.
Still, drivers do need to be careful. For example, many drivers use a
private mutex to synchronize their normal I/O activities with their
disconnect method. Now if the driver supports autosuspend then it
must call usb_autopm_put_interface() from somewhere -- maybe from its
close method. It should make the call while holding the private mutex,
since a driver shouldn't call any of the usb_autopm_* functions for an
interface from which it has been unbound.
But the usb_autpm_* routines always acquire the device's PM mutex, and
consequently the locking order has to be: private mutex first, PM
mutex second. Since the suspend method is always called with the PM
mutex held, it mustn't try to acquire the private mutex. It has to
synchronize with the driver's I/O activities in some other way.
critical section, the best way is to lock the device and call
usb_autopm_get_interface() (and do the reverse at the end of the
critical section). Holding the device semaphore will block all
external PM calls, and the usb_autopm_get_interface() will prevent any
internal PM calls, even if it fails. (Exercise: Why?)
Interaction between dynamic PM and system PM
@ -499,22 +465,11 @@ synchronize with the driver's I/O activities in some other way.
Dynamic power management and system power management can interact in
a couple of ways.
Firstly, a device may already be manually suspended or autosuspended
when a system suspend occurs. Since system suspends are supposed to
be as transparent as possible, the device should remain suspended
following the system resume. The 2.6.23 kernel obeys this principle
for manually suspended devices but not for autosuspended devices; they
do get resumed when the system wakes up. (Presumably they will be
autosuspended again after their idle-delay time expires.) In later
kernels this behavior will be fixed.
(There is an exception. If a device would undergo a reset-resume
instead of a normal resume, and the device is enabled for remote
wakeup, then the reset-resume takes place even if the device was
already suspended when the system suspend began. The justification is
that a reset-resume is a kind of remote-wakeup event. Or to put it
another way, a device which needs a reset won't be able to generate
normal remote-wakeup signals, so it ought to be resumed immediately.)
Firstly, a device may already be autosuspended when a system suspend
occurs. Since system suspends are supposed to be as transparent as
possible, the device should remain suspended following the system
resume. But this theory may not work out well in practice; over time
the kernel's behavior in this regard has changed.
Secondly, a dynamic power-management event may occur as a system
suspend is underway. The window for this is short, since system

View File

@ -445,6 +445,8 @@ CONFIG_IP_NF_FILTER=m
# CONFIG_LAPB is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
CONFIG_PHONET=y
# CONFIG_IEEE802154 is not set
# CONFIG_NET_SCHED is not set
# CONFIG_DCB is not set
@ -1325,27 +1327,34 @@ CONFIG_USB_GADGET_SELECTED=y
# CONFIG_USB_GADGET_LH7A40X is not set
# CONFIG_USB_GADGET_OMAP is not set
# CONFIG_USB_GADGET_PXA25X is not set
# CONFIG_USB_GADGET_R8A66597 is not set
# CONFIG_USB_GADGET_PXA27X is not set
# CONFIG_USB_GADGET_S3C2410 is not set
# CONFIG_USB_GADGET_S3C_HSOTG is not set
# CONFIG_USB_GADGET_IMX is not set
# CONFIG_USB_GADGET_S3C2410 is not set
# CONFIG_USB_GADGET_M66592 is not set
# CONFIG_USB_GADGET_AMD5536UDC is not set
# CONFIG_USB_GADGET_FSL_QE is not set
# CONFIG_USB_GADGET_CI13XXX is not set
# CONFIG_USB_GADGET_NET2280 is not set
# CONFIG_USB_GADGET_GOKU is not set
# CONFIG_USB_GADGET_LANGWELL is not set
# CONFIG_USB_GADGET_DUMMY_HCD is not set
CONFIG_USB_GADGET_DUALSPEED=y
CONFIG_USB_ZERO=m
# CONFIG_USB_ZERO_HNPTEST is not set
# CONFIG_USB_AUDIO is not set
# CONFIG_USB_ETH is not set
# CONFIG_USB_GADGETFS is not set
CONFIG_USB_FILE_STORAGE=m
# CONFIG_USB_FILE_STORAGE_TEST is not set
# CONFIG_USB_MASS_STORAGE is not set
# CONFIG_USB_G_SERIAL is not set
# CONFIG_USB_MIDI_GADGET is not set
# CONFIG_USB_G_PRINTER is not set
# CONFIG_USB_CDC_COMPOSITE is not set
CONFIG_USB_G_NOKIA=m
# CONFIG_USB_G_MULTI is not set
#
# OTG and related infrastructure

View File

@ -31,6 +31,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/dma-mapping.h>
#include <mach/irqs.h>
#include <mach/hardware.h>
@ -292,7 +293,7 @@ struct platform_device mxc_fb_device = {
.num_resources = ARRAY_SIZE(mxc_fb),
.resource = mxc_fb,
.dev = {
.coherent_dma_mask = 0xFFFFFFFF,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
@ -395,17 +396,17 @@ static struct resource mxc_sdhc1_resources[] = {
},
};
static u64 mxc_sdhc1_dmamask = 0xffffffffUL;
static u64 mxc_sdhc1_dmamask = DMA_BIT_MASK(32);
struct platform_device mxc_sdhc_device0 = {
.name = "mxc-mmc",
.id = 0,
.dev = {
.dma_mask = &mxc_sdhc1_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(mxc_sdhc1_resources),
.resource = mxc_sdhc1_resources,
.name = "mxc-mmc",
.id = 0,
.dev = {
.dma_mask = &mxc_sdhc1_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(mxc_sdhc1_resources),
.resource = mxc_sdhc1_resources,
};
static struct resource mxc_sdhc2_resources[] = {
@ -424,17 +425,17 @@ static struct resource mxc_sdhc2_resources[] = {
},
};
static u64 mxc_sdhc2_dmamask = 0xffffffffUL;
static u64 mxc_sdhc2_dmamask = DMA_BIT_MASK(32);
struct platform_device mxc_sdhc_device1 = {
.name = "mxc-mmc",
.id = 1,
.dev = {
.dma_mask = &mxc_sdhc2_dmamask,
.coherent_dma_mask = 0xffffffff,
},
.num_resources = ARRAY_SIZE(mxc_sdhc2_resources),
.resource = mxc_sdhc2_resources,
.name = "mxc-mmc",
.id = 1,
.dev = {
.dma_mask = &mxc_sdhc2_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(mxc_sdhc2_resources),
.resource = mxc_sdhc2_resources,
};
#ifdef CONFIG_MACH_MX27
@ -450,7 +451,7 @@ static struct resource otg_resources[] = {
},
};
static u64 otg_dmamask = 0xffffffffUL;
static u64 otg_dmamask = DMA_BIT_MASK(32);
/* OTG gadget device */
struct platform_device mxc_otg_udc_device = {
@ -458,7 +459,7 @@ struct platform_device mxc_otg_udc_device = {
.id = -1,
.dev = {
.dma_mask = &otg_dmamask,
.coherent_dma_mask = 0xffffffffUL,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.resource = otg_resources,
.num_resources = ARRAY_SIZE(otg_resources),
@ -469,7 +470,7 @@ struct platform_device mxc_otg_host = {
.name = "mxc-ehci",
.id = 0,
.dev = {
.coherent_dma_mask = 0xffffffff,
.coherent_dma_mask = DMA_BIT_MASK(32),
.dma_mask = &otg_dmamask,
},
.resource = otg_resources,
@ -478,7 +479,7 @@ struct platform_device mxc_otg_host = {
/* USB host 1 */
static u64 usbh1_dmamask = 0xffffffffUL;
static u64 usbh1_dmamask = DMA_BIT_MASK(32);
static struct resource mxc_usbh1_resources[] = {
{
@ -496,7 +497,7 @@ struct platform_device mxc_usbh1 = {
.name = "mxc-ehci",
.id = 1,
.dev = {
.coherent_dma_mask = 0xffffffff,
.coherent_dma_mask = DMA_BIT_MASK(32),
.dma_mask = &usbh1_dmamask,
},
.resource = mxc_usbh1_resources,
@ -504,7 +505,7 @@ struct platform_device mxc_usbh1 = {
};
/* USB host 2 */
static u64 usbh2_dmamask = 0xffffffffUL;
static u64 usbh2_dmamask = DMA_BIT_MASK(32);
static struct resource mxc_usbh2_resources[] = {
{
@ -522,7 +523,7 @@ struct platform_device mxc_usbh2 = {
.name = "mxc-ehci",
.id = 2,
.dev = {
.coherent_dma_mask = 0xffffffff,
.coherent_dma_mask = DMA_BIT_MASK(32),
.dma_mask = &usbh2_dmamask,
},
.resource = mxc_usbh2_resources,
@ -642,3 +643,30 @@ int __init mxc_register_gpios(void)
{
return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
}
#ifdef CONFIG_MACH_MX21
static struct resource mx21_usbhc_resources[] = {
{
.start = USBOTG_BASE_ADDR,
.end = USBOTG_BASE_ADDR + 0x1FFF,
.flags = IORESOURCE_MEM,
},
{
.start = MXC_INT_USBHOST,
.end = MXC_INT_USBHOST,
.flags = IORESOURCE_IRQ,
},
};
struct platform_device mx21_usbhc_device = {
.name = "imx21-hcd",
.id = 0,
.dev = {
.dma_mask = &mx21_usbhc_device.dev.coherent_dma_mask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(mx21_usbhc_resources),
.resource = mx21_usbhc_resources,
};
#endif

View File

@ -26,5 +26,6 @@ extern struct platform_device mxc_usbh2;
extern struct platform_device mxc_spi_device0;
extern struct platform_device mxc_spi_device1;
extern struct platform_device mxc_spi_device2;
extern struct platform_device mx21_usbhc_device;
extern struct platform_device imx_ssi_device0;
extern struct platform_device imx_ssi_device1;

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2009 Martin Fuzzey <mfuzzey@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __ASM_ARCH_MX21_USBH
#define __ASM_ARCH_MX21_USBH
enum mx21_usbh_xcvr {
/* Values below as used by hardware (HWMODE register) */
MX21_USBXCVR_TXDIF_RXDIF = 0,
MX21_USBXCVR_TXDIF_RXSE = 1,
MX21_USBXCVR_TXSE_RXDIF = 2,
MX21_USBXCVR_TXSE_RXSE = 3,
};
struct mx21_usbh_platform_data {
enum mx21_usbh_xcvr host_xcvr; /* tranceiver mode host 1,2 ports */
enum mx21_usbh_xcvr otg_xcvr; /* tranceiver mode otg (as host) port */
u16 enable_host1:1,
enable_host2:1,
enable_otg_host:1, /* enable "OTG" port (as host) */
host1_xcverless:1, /* traceiverless host1 port */
host1_txenoe:1, /* output enable host1 transmit enable */
otg_ext_xcvr:1, /* external tranceiver for OTG port */
unused:10;
};
#endif /* __ASM_ARCH_MX21_USBH */

View File

@ -1770,10 +1770,13 @@ at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
ARRAY_SIZE(usba0_resource)))
goto out_free_pdev;
if (data)
if (data) {
usba_data.pdata.vbus_pin = data->vbus_pin;
else
usba_data.pdata.vbus_pin_inverted = data->vbus_pin_inverted;
} else {
usba_data.pdata.vbus_pin = -EINVAL;
usba_data.pdata.vbus_pin_inverted = -EINVAL;
}
data = &usba_data.pdata;
data->num_ep = ARRAY_SIZE(at32_usba_ep);

View File

@ -231,9 +231,10 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
/**
* tty_insert_flip_string - Add characters to the tty buffer
* tty_insert_flip_string_fixed_flag - Add characters to the tty buffer
* @tty: tty structure
* @chars: characters
* @flag: flag value for each character
* @size: size
*
* Queue a series of bytes to the tty buffering. All the characters
@ -242,8 +243,8 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room);
* Locking: Called functions may take tty->buf.lock
*/
int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
size_t size)
int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
const unsigned char *chars, char flag, size_t size)
{
int copied = 0;
do {
@ -254,7 +255,7 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
if (unlikely(space == 0))
break;
memcpy(tb->char_buf_ptr + tb->used, chars, space);
memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
memset(tb->flag_buf_ptr + tb->used, flag, space);
tb->used += space;
copied += space;
chars += space;
@ -263,7 +264,7 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
} while (unlikely(size > copied));
return copied;
}
EXPORT_SYMBOL(tty_insert_flip_string);
EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
/**
* tty_insert_flip_string_flags - Add characters to the tty buffer

View File

@ -265,9 +265,10 @@ static int hiddev_release(struct inode * inode, struct file * file)
static int hiddev_open(struct inode *inode, struct file *file)
{
struct hiddev_list *list;
int res;
int res, i;
int i = iminor(inode) - HIDDEV_MINOR_BASE;
lock_kernel();
i = iminor(inode) - HIDDEV_MINOR_BASE;
if (i >= HIDDEV_MINORS || i < 0 || !hiddev_table[i])
return -ENODEV;
@ -313,10 +314,12 @@ static int hiddev_open(struct inode *inode, struct file *file)
usbhid_open(hid);
}
unlock_kernel();
return 0;
bail:
file->private_data = NULL;
kfree(list);
unlock_kernel();
return res;
}

View File

@ -616,10 +616,12 @@ static int dabusb_open (struct inode *inode, struct file *file)
{
int devnum = iminor(inode);
pdabusb_t s;
int r;
if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
return -EIO;
lock_kernel();
s = &dabusb[devnum - DABUSB_MINOR];
dbg("dabusb_open");
@ -634,6 +636,7 @@ static int dabusb_open (struct inode *inode, struct file *file)
msleep_interruptible(500);
if (signal_pending (current)) {
unlock_kernel();
return -EAGAIN;
}
mutex_lock(&s->mutex);
@ -641,6 +644,7 @@ static int dabusb_open (struct inode *inode, struct file *file)
if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
mutex_unlock(&s->mutex);
dev_err(&s->usbdev->dev, "set_interface failed\n");
unlock_kernel();
return -EINVAL;
}
s->opened = 1;
@ -649,7 +653,9 @@ static int dabusb_open (struct inode *inode, struct file *file)
file->f_pos = 0;
file->private_data = s;
return nonseekable_open(inode, file);
r = nonseekable_open(inode, file);
unlock_kernel();
return r;
}
static int dabusb_release (struct inode *inode, struct file *file)

View File

@ -144,7 +144,7 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed)
case USB_SPEED_LOW:
case USB_SPEED_FULL:
case USB_SPEED_HIGH:
case USB_SPEED_VARIABLE:
case USB_SPEED_WIRELESS:
break;
default:
usbip_uerr("speed %d\n", speed);

View File

@ -21,6 +21,7 @@ config USB_ARCH_HAS_HCD
default y if USB_ARCH_HAS_EHCI
default y if PCMCIA && !M32R # sl811_cs
default y if ARM # SL-811
default y if BLACKFIN # SL-811
default y if SUPERH # r8a66597-hcd
default PCI
@ -39,6 +40,7 @@ config USB_ARCH_HAS_OHCI
default y if ARCH_PNX4008 && I2C
default y if MFD_TC6393XB
default y if ARCH_W90X900
default y if ARCH_DAVINCI_DA8XX
# PPC:
default y if STB03xxx
default y if PPC_MPC52xx

View File

@ -21,6 +21,7 @@ obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_HWA_HCD) += host/
obj-$(CONFIG_USB_ISP1760_HCD) += host/
obj-$(CONFIG_USB_IMX21_HCD) += host/
obj-$(CONFIG_USB_C67X00_HCD) += c67x00/

View File

@ -5,6 +5,7 @@
* Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan
* Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
* Copyright (C) 2007 Simon Arlott
* Copyright (C) 2009 Simon Arlott
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
@ -43,7 +44,7 @@
#include "usbatm.h"
#define DRIVER_AUTHOR "Roman Kagan, David Woodhouse, Duncan Sands, Simon Arlott"
#define DRIVER_VERSION "0.3"
#define DRIVER_VERSION "0.4"
#define DRIVER_DESC "Conexant AccessRunner ADSL USB modem driver"
static const char cxacru_driver_name[] = "cxacru";
@ -52,6 +53,7 @@ static const char cxacru_driver_name[] = "cxacru";
#define CXACRU_EP_DATA 0x02 /* Bulk in/out */
#define CMD_PACKET_SIZE 64 /* Should be maxpacket(ep)? */
#define CMD_MAX_CONFIG ((CMD_PACKET_SIZE / 4 - 1) / 2)
/* Addresses */
#define PLLFCLK_ADDR 0x00350068
@ -105,6 +107,26 @@ enum cxacru_cm_request {
CM_REQUEST_MAX,
};
/* commands for interaction with the flash memory
*
* read: response is the contents of the first 60 bytes of flash memory
* write: request contains the 60 bytes of data to write to flash memory
* response is the contents of the first 60 bytes of flash memory
*
* layout: PP PP VV VV MM MM MM MM MM MM ?? ?? SS SS SS SS SS SS SS SS
* SS SS SS SS SS SS SS SS 00 00 00 00 00 00 00 00 00 00 00 00
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*
* P: le16 USB Product ID
* V: le16 USB Vendor ID
* M: be48 MAC Address
* S: le16 ASCII Serial Number
*/
enum cxacru_cm_flash {
CM_FLASH_READ = 0xa1,
CM_FLASH_WRITE = 0xa2
};
/* reply codes to the commands above */
enum cxacru_cm_status {
CM_STATUS_UNDEFINED,
@ -196,23 +218,32 @@ static DEVICE_ATTR(_name, S_IRUGO, cxacru_sysfs_show_##_name, NULL)
static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, \
cxacru_sysfs_show_##_name, cxacru_sysfs_store_##_name)
#define CXACRU_SET_INIT(_name) \
static DEVICE_ATTR(_name, S_IWUSR, \
NULL, cxacru_sysfs_store_##_name)
#define CXACRU_ATTR_INIT(_value, _type, _name) \
static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_interface *intf = to_usb_interface(dev); \
struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); \
struct cxacru_data *instance = usbatm_instance->driver_data; \
struct cxacru_data *instance = to_usbatm_driver_data(\
to_usb_interface(dev)); \
\
if (instance == NULL) \
return -ENODEV; \
\
return cxacru_sysfs_showattr_##_type(instance->card_info[_value], buf); \
} \
CXACRU__ATTR_INIT(_name)
#define CXACRU_ATTR_CREATE(_v, _t, _name) CXACRU_DEVICE_CREATE_FILE(_name)
#define CXACRU_CMD_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)
#define CXACRU_SET_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)
#define CXACRU__ATTR_CREATE(_name) CXACRU_DEVICE_CREATE_FILE(_name)
#define CXACRU_ATTR_REMOVE(_v, _t, _name) CXACRU_DEVICE_REMOVE_FILE(_name)
#define CXACRU_CMD_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)
#define CXACRU_SET_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)
#define CXACRU__ATTR_REMOVE(_name) CXACRU_DEVICE_REMOVE_FILE(_name)
static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf)
@ -267,12 +298,12 @@ static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf)
static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
{
static char *str[] = {
NULL,
"",
"ANSI T1.413",
"ITU-T G.992.1 (G.DMT)",
"ITU-T G.992.2 (G.LITE)"
};
if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL))
if (unlikely(value >= ARRAY_SIZE(str)))
return snprintf(buf, PAGE_SIZE, "%u\n", value);
return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
}
@ -288,22 +319,28 @@ static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
static ssize_t cxacru_sysfs_show_mac_address(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
struct atm_dev *atm_dev = usbatm_instance->atm_dev;
struct cxacru_data *instance = to_usbatm_driver_data(
to_usb_interface(dev));
return snprintf(buf, PAGE_SIZE, "%pM\n", atm_dev->esi);
if (instance == NULL || instance->usbatm->atm_dev == NULL)
return -ENODEV;
return snprintf(buf, PAGE_SIZE, "%pM\n",
instance->usbatm->atm_dev->esi);
}
static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
struct cxacru_data *instance = usbatm_instance->driver_data;
u32 value = instance->card_info[CXINF_LINE_STARTABLE];
static char *str[] = { "running", "stopped" };
struct cxacru_data *instance = to_usbatm_driver_data(
to_usb_interface(dev));
u32 value;
if (instance == NULL)
return -ENODEV;
value = instance->card_info[CXINF_LINE_STARTABLE];
if (unlikely(value >= ARRAY_SIZE(str)))
return snprintf(buf, PAGE_SIZE, "%u\n", value);
return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
@ -312,9 +349,8 @@ static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
struct cxacru_data *instance = usbatm_instance->driver_data;
struct cxacru_data *instance = to_usbatm_driver_data(
to_usb_interface(dev));
int ret;
int poll = -1;
char str_cmd[8];
@ -328,13 +364,16 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
return -EINVAL;
ret = 0;
if (instance == NULL)
return -ENODEV;
if (mutex_lock_interruptible(&instance->adsl_state_serialize))
return -ERESTARTSYS;
if (!strcmp(str_cmd, "stop") || !strcmp(str_cmd, "restart")) {
ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_STOP, NULL, 0, NULL, 0);
if (ret < 0) {
atm_err(usbatm_instance, "change adsl state:"
atm_err(instance->usbatm, "change adsl state:"
" CHIP_ADSL_LINE_STOP returned %d\n", ret);
ret = -EIO;
@ -354,7 +393,7 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
if (!strcmp(str_cmd, "start") || !strcmp(str_cmd, "restart")) {
ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
if (ret < 0) {
atm_err(usbatm_instance, "change adsl state:"
atm_err(instance->usbatm, "change adsl state:"
" CHIP_ADSL_LINE_START returned %d\n", ret);
ret = -EIO;
@ -407,6 +446,72 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
return ret;
}
/* CM_REQUEST_CARD_DATA_GET times out, so no show attribute */
static ssize_t cxacru_sysfs_store_adsl_config(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct cxacru_data *instance = to_usbatm_driver_data(
to_usb_interface(dev));
int len = strlen(buf);
int ret, pos, num;
__le32 data[CMD_PACKET_SIZE / 4];
if (!capable(CAP_NET_ADMIN))
return -EACCES;
if (instance == NULL)
return -ENODEV;
pos = 0;
num = 0;
while (pos < len) {
int tmp;
u32 index;
u32 value;
ret = sscanf(buf + pos, "%x=%x%n", &index, &value, &tmp);
if (ret < 2)
return -EINVAL;
if (index < 0 || index > 0x7f)
return -EINVAL;
pos += tmp;
/* skip trailing newline */
if (buf[pos] == '\n' && pos == len-1)
pos++;
data[num * 2 + 1] = cpu_to_le32(index);
data[num * 2 + 2] = cpu_to_le32(value);
num++;
/* send config values when data buffer is full
* or no more data
*/
if (pos >= len || num >= CMD_MAX_CONFIG) {
char log[CMD_MAX_CONFIG * 12 + 1]; /* %02x=%08x */
data[0] = cpu_to_le32(num);
ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET,
(u8 *) data, 4 + num * 8, NULL, 0);
if (ret < 0) {
atm_err(instance->usbatm,
"set card data returned %d\n", ret);
return -EIO;
}
for (tmp = 0; tmp < num; tmp++)
snprintf(log + tmp*12, 13, " %02x=%08x",
le32_to_cpu(data[tmp * 2 + 1]),
le32_to_cpu(data[tmp * 2 + 2]));
atm_info(instance->usbatm, "config%s\n", log);
num = 0;
}
}
return len;
}
/*
* All device attributes are included in CXACRU_ALL_FILES
* so that the same list can be used multiple times:
@ -442,7 +547,8 @@ CXACRU_ATTR_##_action(CXINF_MODULATION, MODU, modulation); \
CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND, u32, adsl_headend); \
CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND_ENVIRONMENT, u32, adsl_headend_environment); \
CXACRU_ATTR_##_action(CXINF_CONTROLLER_VERSION, u32, adsl_controller_version); \
CXACRU_CMD_##_action( adsl_state);
CXACRU_CMD_##_action( adsl_state); \
CXACRU_SET_##_action( adsl_config);
CXACRU_ALL_FILES(INIT);
@ -596,7 +702,7 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
len = ret / 4;
for (offb = 0; offb < len; ) {
int l = le32_to_cpu(buf[offb++]);
if (l > stride || l > (len - offb) / 2) {
if (l < 0 || l > stride || l > (len - offb) / 2) {
if (printk_ratelimit())
usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
cm, l);
@ -649,9 +755,6 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
{
struct cxacru_data *instance = usbatm_instance->driver_data;
struct usb_interface *intf = usbatm_instance->usb_intf;
/*
struct atm_dev *atm_dev = usbatm_instance->atm_dev;
*/
int ret;
int start_polling = 1;
@ -697,6 +800,9 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
mutex_unlock(&instance->poll_state_serialize);
mutex_unlock(&instance->adsl_state_serialize);
printk(KERN_INFO "%s%d: %s %pM\n", atm_dev->type, atm_dev->number,
usbatm_instance->description, atm_dev->esi);
if (start_polling)
cxacru_poll_status(&instance->poll_work.work);
return 0;
@ -873,11 +979,9 @@ cleanup:
static void cxacru_upload_firmware(struct cxacru_data *instance,
const struct firmware *fw,
const struct firmware *bp,
const struct firmware *cf)
const struct firmware *bp)
{
int ret;
int off;
struct usbatm_data *usbatm = instance->usbatm;
struct usb_device *usb_dev = usbatm->usb_dev;
__le16 signature[] = { usb_dev->descriptor.idVendor,
@ -911,6 +1015,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
}
/* Firmware */
usb_info(usbatm, "loading firmware\n");
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size);
if (ret) {
usb_err(usbatm, "Firmware upload failed: %d\n", ret);
@ -919,6 +1024,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
/* Boot ROM patch */
if (instance->modem_type->boot_rom_patch) {
usb_info(usbatm, "loading boot ROM patch\n");
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size);
if (ret) {
usb_err(usbatm, "Boot ROM patching failed: %d\n", ret);
@ -933,6 +1039,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
return;
}
usb_info(usbatm, "starting device\n");
if (instance->modem_type->boot_rom_patch) {
val = cpu_to_le32(BR_ADDR);
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4);
@ -958,26 +1065,6 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
usb_err(usbatm, "modem failed to initialize: %d\n", ret);
return;
}
/* Load config data (le32), doing one packet at a time */
if (cf)
for (off = 0; off < cf->size / 4; ) {
__le32 buf[CMD_PACKET_SIZE / 4 - 1];
int i, len = min_t(int, cf->size / 4 - off, CMD_PACKET_SIZE / 4 / 2 - 1);
buf[0] = cpu_to_le32(len);
for (i = 0; i < len; i++, off++) {
buf[i * 2 + 1] = cpu_to_le32(off);
memcpy(buf + i * 2 + 2, cf->data + off * 4, 4);
}
ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET,
(u8 *) buf, len, NULL, 0);
if (ret < 0) {
usb_err(usbatm, "load config data failed: %d\n", ret);
return;
}
}
msleep_interruptible(4000);
}
static int cxacru_find_firmware(struct cxacru_data *instance,
@ -1003,7 +1090,7 @@ static int cxacru_find_firmware(struct cxacru_data *instance,
static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
struct usb_interface *usb_intf)
{
const struct firmware *fw, *bp, *cf;
const struct firmware *fw, *bp;
struct cxacru_data *instance = usbatm_instance->driver_data;
int ret = cxacru_find_firmware(instance, "fw", &fw);
@ -1021,13 +1108,8 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
}
}
if (cxacru_find_firmware(instance, "cf", &cf)) /* optional */
cf = NULL;
cxacru_upload_firmware(instance, fw, bp);
cxacru_upload_firmware(instance, fw, bp, cf);
if (cf)
release_firmware(cf);
if (instance->modem_type->boot_rom_patch)
release_firmware(bp);
release_firmware(fw);

View File

@ -1333,6 +1333,7 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
if (instance->atm_dev) {
sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device");
atm_dev_deregister(instance->atm_dev);
instance->atm_dev = NULL;
}
usbatm_put_instance(instance); /* taken in usbatm_usb_probe */
@ -1348,7 +1349,7 @@ static int __init usbatm_usb_init(void)
{
dbg("%s: driver version %s", __func__, DRIVER_VERSION);
if (sizeof(struct usbatm_control) > sizeof(((struct sk_buff *) 0)->cb)) {
if (sizeof(struct usbatm_control) > FIELD_SIZEOF(struct sk_buff, cb)) {
printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name);
return -EIO;
}

View File

@ -204,4 +204,19 @@ struct usbatm_data {
struct urb *urbs[0];
};
static inline void *to_usbatm_driver_data(struct usb_interface *intf)
{
struct usbatm_data *usbatm_instance;
if (intf == NULL)
return NULL;
usbatm_instance = usb_get_intfdata(intf);
if (usbatm_instance == NULL) /* set NULL before unbind() */
return NULL;
return usbatm_instance->driver_data; /* set NULL after unbind() */
}
#endif /* _USBATM_H_ */

View File

@ -137,13 +137,13 @@ static int __devinit c67x00_drv_probe(struct platform_device *pdev)
if (!c67x00)
return -ENOMEM;
if (!request_mem_region(res->start, res->end - res->start + 1,
if (!request_mem_region(res->start, resource_size(res),
pdev->name)) {
dev_err(&pdev->dev, "Memory region busy\n");
ret = -EBUSY;
goto request_mem_failed;
}
c67x00->hpi.base = ioremap(res->start, res->end - res->start + 1);
c67x00->hpi.base = ioremap(res->start, resource_size(res));
if (!c67x00->hpi.base) {
dev_err(&pdev->dev, "Unable to map HPI registers\n");
ret = -EIO;
@ -182,7 +182,7 @@ static int __devinit c67x00_drv_probe(struct platform_device *pdev)
request_irq_failed:
iounmap(c67x00->hpi.base);
map_failed:
release_mem_region(res->start, res->end - res->start + 1);
release_mem_region(res->start, resource_size(res));
request_mem_failed:
kfree(c67x00);
@ -208,7 +208,7 @@ static int __devexit c67x00_drv_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res)
release_mem_region(res->start, res->end - res->start + 1);
release_mem_region(res->start, resource_size(res));
kfree(c67x00);

View File

@ -170,6 +170,7 @@ static void acm_write_done(struct acm *acm, struct acm_wb *wb)
{
wb->use = 0;
acm->transmitting--;
usb_autopm_put_interface_async(acm->control);
}
/*
@ -211,9 +212,12 @@ static int acm_write_start(struct acm *acm, int wbn)
}
dbg("%s susp_count: %d", __func__, acm->susp_count);
usb_autopm_get_interface_async(acm->control);
if (acm->susp_count) {
acm->delayed_wb = wb;
schedule_work(&acm->waker);
if (!acm->delayed_wb)
acm->delayed_wb = wb;
else
usb_autopm_put_interface_async(acm->control);
spin_unlock_irqrestore(&acm->write_lock, flags);
return 0; /* A white lie */
}
@ -424,7 +428,6 @@ next_buffer:
throttled = acm->throttle;
spin_unlock_irqrestore(&acm->throttle_lock, flags);
if (!throttled) {
tty_buffer_request_room(tty, buf->size);
tty_insert_flip_string(tty, buf->base, buf->size);
tty_flip_buffer_push(tty);
} else {
@ -534,23 +537,6 @@ static void acm_softint(struct work_struct *work)
tty_kref_put(tty);
}
static void acm_waker(struct work_struct *waker)
{
struct acm *acm = container_of(waker, struct acm, waker);
int rv;
rv = usb_autopm_get_interface(acm->control);
if (rv < 0) {
dev_err(&acm->dev->dev, "Autopm failure in %s\n", __func__);
return;
}
if (acm->delayed_wb) {
acm_start_wb(acm, acm->delayed_wb);
acm->delayed_wb = NULL;
}
usb_autopm_put_interface(acm->control);
}
/*
* TTY handlers
*/
@ -566,7 +552,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
acm = acm_table[tty->index];
if (!acm || !acm->dev)
goto err_out;
goto out;
else
rv = 0;
@ -582,8 +568,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
mutex_lock(&acm->mutex);
if (acm->port.count++) {
mutex_unlock(&acm->mutex);
usb_autopm_put_interface(acm->control);
goto done;
goto out;
}
acm->ctrlurb->dev = acm->dev;
@ -612,18 +599,18 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
rv = tty_port_block_til_ready(&acm->port, tty, filp);
tasklet_schedule(&acm->urb_task);
done:
mutex_unlock(&acm->mutex);
err_out:
out:
mutex_unlock(&open_mutex);
return rv;
full_bailout:
usb_kill_urb(acm->ctrlurb);
bail_out:
usb_autopm_put_interface(acm->control);
acm->port.count--;
mutex_unlock(&acm->mutex);
usb_autopm_put_interface(acm->control);
early_bail:
mutex_unlock(&open_mutex);
tty_port_tty_set(&acm->port, NULL);
@ -1023,7 +1010,7 @@ static int acm_probe(struct usb_interface *intf,
case USB_CDC_CALL_MANAGEMENT_TYPE:
call_management_function = buffer[3];
call_interface_num = buffer[4];
if ((call_management_function & 3) != 3)
if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
break;
default:
@ -1178,7 +1165,6 @@ made_compressed_probe:
acm->urb_task.func = acm_rx_tasklet;
acm->urb_task.data = (unsigned long) acm;
INIT_WORK(&acm->work, acm_softint);
INIT_WORK(&acm->waker, acm_waker);
init_waitqueue_head(&acm->drain_wait);
spin_lock_init(&acm->throttle_lock);
spin_lock_init(&acm->write_lock);
@ -1343,7 +1329,6 @@ static void stop_data_traffic(struct acm *acm)
tasklet_enable(&acm->urb_task);
cancel_work_sync(&acm->work);
cancel_work_sync(&acm->waker);
}
static void acm_disconnect(struct usb_interface *intf)
@ -1435,6 +1420,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
static int acm_resume(struct usb_interface *intf)
{
struct acm *acm = usb_get_intfdata(intf);
struct acm_wb *wb;
int rv = 0;
int cnt;
@ -1449,6 +1435,21 @@ static int acm_resume(struct usb_interface *intf)
mutex_lock(&acm->mutex);
if (acm->port.count) {
rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
spin_lock_irq(&acm->write_lock);
if (acm->delayed_wb) {
wb = acm->delayed_wb;
acm->delayed_wb = NULL;
spin_unlock_irq(&acm->write_lock);
acm_start_wb(acm, acm->delayed_wb);
} else {
spin_unlock_irq(&acm->write_lock);
}
/*
* delayed error checking because we must
* do the write path at all cost
*/
if (rv < 0)
goto err_out;
@ -1460,6 +1461,23 @@ err_out:
return rv;
}
static int acm_reset_resume(struct usb_interface *intf)
{
struct acm *acm = usb_get_intfdata(intf);
struct tty_struct *tty;
mutex_lock(&acm->mutex);
if (acm->port.count) {
tty = tty_port_tty_get(&acm->port);
if (tty) {
tty_hangup(tty);
tty_kref_put(tty);
}
}
mutex_unlock(&acm->mutex);
return acm_resume(intf);
}
#endif /* CONFIG_PM */
#define NOKIA_PCSUITE_ACM_INFO(x) \
@ -1471,7 +1489,7 @@ err_out:
* USB driver structure.
*/
static struct usb_device_id acm_ids[] = {
static const struct usb_device_id acm_ids[] = {
/* quirky and broken devices */
{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
@ -1576,6 +1594,11 @@ static struct usb_device_id acm_ids[] = {
/* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
/* Support Lego NXT using pbLua firmware */
{ USB_DEVICE(0x0694, 0xff00),
.driver_info = NOT_A_MODEM,
},
/* control interfaces with various AT-command sets */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_ACM_PROTO_AT_V25TER) },
@ -1602,6 +1625,7 @@ static struct usb_driver acm_driver = {
#ifdef CONFIG_PM
.suspend = acm_suspend,
.resume = acm_resume,
.reset_resume = acm_reset_resume,
#endif
.id_table = acm_ids,
#ifdef CONFIG_PM

View File

@ -112,7 +112,6 @@ struct acm {
struct mutex mutex;
struct usb_cdc_line_coding line; /* bits, stop, parity */
struct work_struct work; /* work queue entry for line discipline waking up */
struct work_struct waker;
wait_queue_head_t drain_wait; /* close processing */
struct tasklet_struct urb_task; /* rx processing */
spinlock_t throttle_lock; /* synchronize throtteling and read callback */
@ -137,3 +136,4 @@ struct acm {
#define NO_UNION_NORMAL 1
#define SINGLE_RX_URB 2
#define NO_CAP_LINE 4
#define NOT_A_MODEM 8

View File

@ -31,7 +31,7 @@
#define DRIVER_AUTHOR "Oliver Neukum"
#define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
static struct usb_device_id wdm_ids[] = {
static const struct usb_device_id wdm_ids[] = {
{
.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS,

View File

@ -163,7 +163,6 @@ struct usblp {
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
unsigned char bidir; /* interface is bidirectional */
unsigned char sleeping; /* interface is suspended */
unsigned char no_paper; /* Paper Out happened */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
/* first 2 bytes are (big-endian) length */
@ -191,7 +190,6 @@ static void usblp_dump(struct usblp *usblp) {
dbg("quirks=%d", usblp->quirks);
dbg("used=%d", usblp->used);
dbg("bidir=%d", usblp->bidir);
dbg("sleeping=%d", usblp->sleeping);
dbg("device_id_string=\"%s\"",
usblp->device_id_string ?
usblp->device_id_string + 2 :
@ -376,7 +374,7 @@ static int usblp_check_status(struct usblp *usblp, int err)
static int handle_bidir (struct usblp *usblp)
{
if (usblp->bidir && usblp->used && !usblp->sleeping) {
if (usblp->bidir && usblp->used) {
if (usblp_submit_read(usblp) < 0)
return -EIO;
}
@ -503,11 +501,6 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto done;
}
if (usblp->sleeping) {
retval = -ENODEV;
goto done;
}
dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
@ -914,8 +907,6 @@ static int usblp_wtest(struct usblp *usblp, int nonblock)
return 0;
}
spin_unlock_irqrestore(&usblp->lock, flags);
if (usblp->sleeping)
return -ENODEV;
if (nonblock)
return -EAGAIN;
return 1;
@ -968,8 +959,6 @@ static int usblp_rtest(struct usblp *usblp, int nonblock)
return 0;
}
spin_unlock_irqrestore(&usblp->lock, flags);
if (usblp->sleeping)
return -ENODEV;
if (nonblock)
return -EAGAIN;
return 1;
@ -1377,12 +1366,10 @@ static void usblp_disconnect(struct usb_interface *intf)
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);
/* we take no more IO */
usblp->sleeping = 1;
usblp_unlink_urbs(usblp);
#if 0 /* XXX Do we want this? What if someone is reading, should we fail? */
/* not strictly necessary, but just in case */
@ -1393,18 +1380,17 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
return 0;
}
static int usblp_resume (struct usb_interface *intf)
static int usblp_resume(struct usb_interface *intf)
{
struct usblp *usblp = usb_get_intfdata (intf);
int r;
usblp->sleeping = 0;
r = handle_bidir (usblp);
return r;
}
static struct usb_device_id usblp_ids [] = {
static const struct usb_device_id usblp_ids[] = {
{ USB_DEVICE_INFO(7, 1, 1) },
{ USB_DEVICE_INFO(7, 1, 2) },
{ USB_DEVICE_INFO(7, 1, 3) },

View File

@ -48,7 +48,7 @@
*/
#define USBTMC_MAX_READS_TO_CLEAR_BULK_IN 100
static struct usb_device_id usbtmc_devices[] = {
static const struct usb_device_id usbtmc_devices[] = {
{ USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 0), },
{ USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 1), },
{ 0, } /* terminating entry */

View File

@ -91,8 +91,8 @@ config USB_DYNAMIC_MINORS
If you are unsure about this, say N here.
config USB_SUSPEND
bool "USB selective suspend/resume and wakeup"
depends on USB && PM
bool "USB runtime power management (suspend/resume and wakeup)"
depends on USB && PM_RUNTIME
help
If you say Y here, you can use driver calls or the sysfs
"power/level" file to suspend or resume individual USB

View File

@ -118,6 +118,7 @@ static const char *format_endpt =
*/
static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
/* guarded by usbfs_mutex */
static unsigned int conndiscevcnt;
/* this struct stores the poll state for <mountpoint>/devices pollers */
@ -156,7 +157,9 @@ static const struct class_info clas_info[] =
void usbfs_conn_disc_event(void)
{
mutex_lock(&usbfs_mutex);
conndiscevcnt++;
mutex_unlock(&usbfs_mutex);
wake_up(&deviceconndiscwq);
}
@ -629,42 +632,29 @@ static ssize_t usb_device_read(struct file *file, char __user *buf,
static unsigned int usb_device_poll(struct file *file,
struct poll_table_struct *wait)
{
struct usb_device_status *st = file->private_data;
struct usb_device_status *st;
unsigned int mask = 0;
lock_kernel();
mutex_lock(&usbfs_mutex);
st = file->private_data;
if (!st) {
st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
/* we may have dropped BKL -
* need to check for having lost the race */
if (file->private_data) {
kfree(st);
st = file->private_data;
goto lost_race;
}
/* we haven't lost - check for allocation failure now */
if (!st) {
unlock_kernel();
mutex_unlock(&usbfs_mutex);
return POLLIN;
}
/*
* need to prevent the module from being unloaded, since
* proc_unregister does not call the release method and
* we would have a memory leak
*/
st->lastev = conndiscevcnt;
file->private_data = st;
mask = POLLIN;
}
lost_race:
if (file->f_mode & FMODE_READ)
poll_wait(file, &deviceconndiscwq, wait);
if (st->lastev != conndiscevcnt)
mask |= POLLIN;
st->lastev = conndiscevcnt;
unlock_kernel();
mutex_unlock(&usbfs_mutex);
return mask;
}
@ -685,7 +675,7 @@ static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
{
loff_t ret;
lock_kernel();
mutex_lock(&file->f_dentry->d_inode->i_mutex);
switch (orig) {
case 0:
@ -701,7 +691,7 @@ static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
ret = -EINVAL;
}
unlock_kernel();
mutex_unlock(&file->f_dentry->d_inode->i_mutex);
return ret;
}

View File

@ -122,7 +122,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
{
loff_t ret;
lock_kernel();
mutex_lock(&file->f_dentry->d_inode->i_mutex);
switch (orig) {
case 0:
@ -138,7 +138,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
ret = -EINVAL;
}
unlock_kernel();
mutex_unlock(&file->f_dentry->d_inode->i_mutex);
return ret;
}
@ -310,7 +310,8 @@ static struct async *async_getpending(struct dev_state *ps,
static void snoop_urb(struct usb_device *udev,
void __user *userurb, int pipe, unsigned length,
int timeout_or_status, enum snoop_when when)
int timeout_or_status, enum snoop_when when,
unsigned char *data, unsigned data_len)
{
static const char *types[] = {"isoc", "int", "ctrl", "bulk"};
static const char *dirs[] = {"out", "in"};
@ -344,6 +345,11 @@ static void snoop_urb(struct usb_device *udev,
"status %d\n",
ep, t, d, length, timeout_or_status);
}
if (data && data_len > 0) {
print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
data, data_len, 1);
}
}
#define AS_CONTINUATION 1
@ -410,7 +416,9 @@ static void async_completed(struct urb *urb)
}
snoop(&urb->dev->dev, "urb complete\n");
snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
as->status, COMPLETE);
as->status, COMPLETE,
((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_OUT) ?
NULL : urb->transfer_buffer, urb->actual_length);
if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
as->status != -ENOENT)
cancel_bulk_urbs(ps, as->bulk_addr);
@ -653,20 +661,20 @@ static int usbdev_open(struct inode *inode, struct file *file)
const struct cred *cred = current_cred();
int ret;
lock_kernel();
/* Protect against simultaneous removal or release */
mutex_lock(&usbfs_mutex);
ret = -ENOMEM;
ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL);
if (!ps)
goto out;
goto out_free_ps;
ret = -ENODEV;
/* Protect against simultaneous removal or release */
mutex_lock(&usbfs_mutex);
/* usbdev device-node */
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_by_devt(inode->i_rdev);
#ifdef CONFIG_USB_DEVICEFS
/* procfs file */
if (!dev) {
@ -678,13 +686,19 @@ static int usbdev_open(struct inode *inode, struct file *file)
dev = NULL;
}
#endif
if (!dev || dev->state == USB_STATE_NOTATTACHED)
goto out;
mutex_unlock(&usbfs_mutex);
if (!dev)
goto out_free_ps;
usb_lock_device(dev);
if (dev->state == USB_STATE_NOTATTACHED)
goto out_unlock_device;
ret = usb_autoresume_device(dev);
if (ret)
goto out;
goto out_unlock_device;
ret = 0;
ps->dev = dev;
ps->file = file;
spin_lock_init(&ps->lock);
@ -702,15 +716,16 @@ static int usbdev_open(struct inode *inode, struct file *file)
smp_wmb();
list_add_tail(&ps->list, &dev->filelist);
file->private_data = ps;
usb_unlock_device(dev);
snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current),
current->comm);
out:
if (ret) {
kfree(ps);
usb_put_dev(dev);
}
mutex_unlock(&usbfs_mutex);
unlock_kernel();
return ret;
out_unlock_device:
usb_unlock_device(dev);
usb_put_dev(dev);
out_free_ps:
kfree(ps);
return ret;
}
@ -724,10 +739,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
usb_lock_device(dev);
usb_hub_release_all_ports(dev, ps);
/* Protect against simultaneous open */
mutex_lock(&usbfs_mutex);
list_del_init(&ps->list);
mutex_unlock(&usbfs_mutex);
for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
ifnum++) {
@ -770,6 +782,13 @@ static int proc_control(struct dev_state *ps, void __user *arg)
if (!tbuf)
return -ENOMEM;
tmo = ctrl.timeout;
snoop(&dev->dev, "control urb: bRequestType=%02x "
"bRequest=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
ctrl.bRequestType, ctrl.bRequest,
__le16_to_cpup(&ctrl.wValue),
__le16_to_cpup(&ctrl.wIndex),
__le16_to_cpup(&ctrl.wLength));
if (ctrl.bRequestType & 0x80) {
if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,
ctrl.wLength)) {
@ -777,15 +796,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
return -EINVAL;
}
pipe = usb_rcvctrlpipe(dev, 0);
snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0);
usb_unlock_device(dev);
i = usb_control_msg(dev, pipe, ctrl.bRequest,
ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
tbuf, ctrl.wLength, tmo);
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE,
tbuf, i);
if ((i > 0) && ctrl.wLength) {
if (copy_to_user(ctrl.data, tbuf, i)) {
free_page((unsigned long)tbuf);
@ -800,14 +819,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
}
}
pipe = usb_sndctrlpipe(dev, 0);
snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT,
tbuf, ctrl.wLength);
usb_unlock_device(dev);
i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
tbuf, ctrl.wLength, tmo);
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0);
}
free_page((unsigned long)tbuf);
if (i < 0 && i != -EPIPE) {
@ -853,12 +873,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
kfree(tbuf);
return -EINVAL;
}
snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);
usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2);
if (!i && len2) {
if (copy_to_user(bulk.data, tbuf, len2)) {
@ -873,12 +893,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
return -EFAULT;
}
}
snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);
usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);
}
kfree(tbuf);
if (i < 0)
@ -1097,6 +1117,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
is_in = 0;
uurb->endpoint &= ~USB_DIR_IN;
}
snoop(&ps->dev->dev, "control urb: bRequestType=%02x "
"bRequest=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
dr->bRequestType, dr->bRequest,
__le16_to_cpup(&dr->wValue),
__le16_to_cpup(&dr->wIndex),
__le16_to_cpup(&dr->wLength));
break;
case USBDEVFS_URB_TYPE_BULK:
@ -1104,13 +1131,25 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_ISOC:
return -EINVAL;
/* allow single-shot interrupt transfers, at bogus rates */
case USB_ENDPOINT_XFER_INT:
/* allow single-shot interrupt transfers */
uurb->type = USBDEVFS_URB_TYPE_INTERRUPT;
goto interrupt_urb;
}
uurb->number_of_packets = 0;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
break;
case USBDEVFS_URB_TYPE_INTERRUPT:
if (!usb_endpoint_xfer_int(&ep->desc))
return -EINVAL;
interrupt_urb:
uurb->number_of_packets = 0;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
break;
case USBDEVFS_URB_TYPE_ISO:
/* arbitrary limit */
if (uurb->number_of_packets < 1 ||
@ -1143,14 +1182,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
uurb->buffer_length = totlen;
break;
case USBDEVFS_URB_TYPE_INTERRUPT:
uurb->number_of_packets = 0;
if (!usb_endpoint_xfer_int(&ep->desc))
return -EINVAL;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
break;
default:
return -EINVAL;
}
@ -1236,7 +1267,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
}
}
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
as->urb->transfer_buffer_length, 0, SUBMIT);
as->urb->transfer_buffer_length, 0, SUBMIT,
is_in ? NULL : as->urb->transfer_buffer,
uurb->buffer_length);
async_newpending(as);
if (usb_endpoint_xfer_bulk(&ep->desc)) {
@ -1274,7 +1307,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
dev_printk(KERN_DEBUG, &ps->dev->dev,
"usbfs: usb_submit_urb returned %d\n", ret);
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
0, ret, COMPLETE);
0, ret, COMPLETE, NULL, 0);
async_removepending(as);
free_async(as);
return ret;
@ -1628,7 +1661,10 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
if (driver == NULL || driver->ioctl == NULL) {
retval = -ENOTTY;
} else {
/* keep API that guarantees BKL */
lock_kernel();
retval = driver->ioctl(intf, ctl->ioctl_code, buf);
unlock_kernel();
if (retval == -ENOIOCTLCMD)
retval = -ENOTTY;
}
@ -1711,6 +1747,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
usb_lock_device(dev);
if (!connected(ps)) {
usb_unlock_device(dev);
@ -1877,9 +1914,7 @@ static long usbdev_ioctl(struct file *file, unsigned int cmd,
{
int ret;
lock_kernel();
ret = usbdev_do_ioctl(file, cmd, (void __user *)arg);
unlock_kernel();
return ret;
}
@ -1890,9 +1925,7 @@ static long usbdev_compat_ioctl(struct file *file, unsigned int cmd,
{
int ret;
lock_kernel();
ret = usbdev_do_ioctl(file, cmd, compat_ptr(arg));
unlock_kernel();
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@ -34,7 +34,6 @@ static int usb_open(struct inode * inode, struct file * file)
int err = -ENODEV;
const struct file_operations *old_fops, *new_fops = NULL;
lock_kernel();
down_read(&minor_rwsem);
c = usb_minors[minor];
@ -53,7 +52,6 @@ static int usb_open(struct inode * inode, struct file * file)
fops_put(old_fops);
done:
up_read(&minor_rwsem);
unlock_kernel();
return err;
}

View File

@ -39,6 +39,7 @@
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <linux/pm_runtime.h>
#include <linux/usb.h>
@ -141,7 +142,7 @@ static const u8 usb3_rh_dev_descriptor[18] = {
0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
0x02, 0x00, /* __le16 idProduct; device 0x0002 */
0x03, 0x00, /* __le16 idProduct; device 0x0003 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
0x03, /* __u8 iManufacturer; */
@ -1670,11 +1671,16 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev,
}
}
for (i = 0; i < num_intfs; ++i) {
struct usb_host_interface *first_alt;
int iface_num;
first_alt = &new_config->intf_cache[i]->altsetting[0];
iface_num = first_alt->desc.bInterfaceNumber;
/* Set up endpoints for alternate interface setting 0 */
alt = usb_find_alt_setting(new_config, i, 0);
alt = usb_find_alt_setting(new_config, iface_num, 0);
if (!alt)
/* No alt setting 0? Pick the first setting. */
alt = &new_config->intf_cache[i]->altsetting[0];
alt = first_alt;
for (j = 0; j < alt->desc.bNumEndpoints; j++) {
ret = hcd->driver->add_endpoint(hcd, udev, &alt->endpoint[j]);
@ -1853,6 +1859,10 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
return status;
}
#endif /* CONFIG_PM */
#ifdef CONFIG_USB_SUSPEND
/* Workqueue routine for root-hub remote wakeup */
static void hcd_resume_work(struct work_struct *work)
{
@ -1860,8 +1870,7 @@ static void hcd_resume_work(struct work_struct *work)
struct usb_device *udev = hcd->self.root_hub;
usb_lock_device(udev);
usb_mark_last_busy(udev);
usb_external_resume_device(udev, PMSG_REMOTE_RESUME);
usb_remote_wakeup(udev);
usb_unlock_device(udev);
}
@ -1880,12 +1889,12 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
spin_lock_irqsave (&hcd_root_hub_lock, flags);
if (hcd->rh_registered)
queue_work(ksuspend_usb_wq, &hcd->wakeup_work);
queue_work(pm_wq, &hcd->wakeup_work);
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
}
EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
#endif
#endif /* CONFIG_USB_SUSPEND */
/*-------------------------------------------------------------------------*/
@ -2030,7 +2039,7 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
hcd->rh_timer.data = (unsigned long) hcd;
#ifdef CONFIG_PM
#ifdef CONFIG_USB_SUSPEND
INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
#endif
mutex_init(&hcd->bandwidth_mutex);
@ -2230,7 +2239,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
hcd->rh_registered = 0;
spin_unlock_irq (&hcd_root_hub_lock);
#ifdef CONFIG_PM
#ifdef CONFIG_USB_SUSPEND
cancel_work_sync(&hcd->wakeup_work);
#endif

View File

@ -80,7 +80,7 @@ struct usb_hcd {
struct timer_list rh_timer; /* drives root-hub polling */
struct urb *status_urb; /* the current status urb */
#ifdef CONFIG_PM
#ifdef CONFIG_USB_SUSPEND
struct work_struct wakeup_work; /* for remote wakeup */
#endif
@ -248,7 +248,7 @@ struct hc_driver {
/* xHCI specific functions */
/* Called by usb_alloc_dev to alloc HC device structures */
int (*alloc_dev)(struct usb_hcd *, struct usb_device *);
/* Called by usb_release_dev to free HC device structures */
/* Called by usb_disconnect to free HC device structures */
void (*free_dev)(struct usb_hcd *, struct usb_device *);
/* Bandwidth computation functions */
@ -286,6 +286,7 @@ struct hc_driver {
*/
int (*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
int (*reset_device)(struct usb_hcd *, struct usb_device *);
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
@ -463,16 +464,20 @@ extern int usb_find_interface_driver(struct usb_device *dev,
#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
#ifdef CONFIG_PM
extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
extern void usb_root_hub_lost_power(struct usb_device *rhdev);
extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg);
#endif /* CONFIG_PM */
#ifdef CONFIG_USB_SUSPEND
extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
#else
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
{
return;
}
#endif /* CONFIG_PM */
#endif /* CONFIG_USB_SUSPEND */
/*
* USB device fs stuff

View File

@ -22,6 +22,7 @@
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/freezer.h>
#include <linux/pm_runtime.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
@ -71,7 +72,6 @@ struct usb_hub {
unsigned mA_per_port; /* current for each child */
unsigned init_done:1;
unsigned limited_power:1;
unsigned quiescing:1;
unsigned disconnected:1;
@ -820,7 +820,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
}
init3:
hub->quiescing = 0;
hub->init_done = 1;
status = usb_submit_urb(hub->urb, GFP_NOIO);
if (status < 0)
@ -861,11 +860,6 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
int i;
cancel_delayed_work_sync(&hub->init_work);
if (!hub->init_done) {
hub->init_done = 1;
usb_autopm_put_interface_no_suspend(
to_usb_interface(hub->intfdev));
}
/* khubd and related activity won't re-trigger */
hub->quiescing = 1;
@ -1224,6 +1218,9 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
desc = intf->cur_altsetting;
hdev = interface_to_usbdev(intf);
/* Hubs have proper suspend/resume support */
usb_enable_autosuspend(hdev);
if (hdev->level == MAX_TOPO_LEVEL) {
dev_err(&intf->dev,
"Unsupported bus topology: hub nested too deep\n");
@ -1402,10 +1399,8 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev)
if (udev->children[i])
recursively_mark_NOTATTACHED(udev->children[i]);
}
if (udev->state == USB_STATE_SUSPENDED) {
udev->discon_suspended = 1;
if (udev->state == USB_STATE_SUSPENDED)
udev->active_duration -= jiffies;
}
udev->state = USB_STATE_NOTATTACHED;
}
@ -1448,11 +1443,11 @@ void usb_set_device_state(struct usb_device *udev,
|| new_state == USB_STATE_SUSPENDED)
; /* No change to wakeup settings */
else if (new_state == USB_STATE_CONFIGURED)
device_init_wakeup(&udev->dev,
device_set_wakeup_capable(&udev->dev,
(udev->actconfig->desc.bmAttributes
& USB_CONFIG_ATT_WAKEUP));
else
device_init_wakeup(&udev->dev, 0);
device_set_wakeup_capable(&udev->dev, 0);
}
if (udev->state == USB_STATE_SUSPENDED &&
new_state != USB_STATE_SUSPENDED)
@ -1529,31 +1524,15 @@ static void update_address(struct usb_device *udev, int devnum)
udev->devnum = devnum;
}
#ifdef CONFIG_USB_SUSPEND
static void usb_stop_pm(struct usb_device *udev)
static void hub_free_dev(struct usb_device *udev)
{
/* Synchronize with the ksuspend thread to prevent any more
* autosuspend requests from being submitted, and decrement
* the parent's count of unsuspended children.
*/
usb_pm_lock(udev);
if (udev->parent && !udev->discon_suspended)
usb_autosuspend_device(udev->parent);
usb_pm_unlock(udev);
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
/* Stop any autosuspend or autoresume requests already submitted */
cancel_delayed_work_sync(&udev->autosuspend);
cancel_work_sync(&udev->autoresume);
/* Root hubs aren't real devices, so don't free HCD resources */
if (hcd->driver->free_dev && udev->parent)
hcd->driver->free_dev(hcd, udev);
}
#else
static inline void usb_stop_pm(struct usb_device *udev)
{ }
#endif
/**
* usb_disconnect - disconnect a device (usbcore-internal)
* @pdev: pointer to device being disconnected
@ -1622,7 +1601,7 @@ void usb_disconnect(struct usb_device **pdev)
*pdev = NULL;
spin_unlock_irq(&device_state_lock);
usb_stop_pm(udev);
hub_free_dev(udev);
put_device(&udev->dev);
}
@ -1799,9 +1778,18 @@ int usb_new_device(struct usb_device *udev)
{
int err;
/* Increment the parent's count of unsuspended children */
if (udev->parent)
usb_autoresume_device(udev->parent);
if (udev->parent) {
/* Initialize non-root-hub device wakeup to disabled;
* device (un)configuration controls wakeup capable
* sysfs power/wakeup controls wakeup enabled/disabled
*/
device_init_wakeup(&udev->dev, 0);
device_set_wakeup_enable(&udev->dev, 1);
}
/* Tell the runtime-PM framework the device is active */
pm_runtime_set_active(&udev->dev);
pm_runtime_enable(&udev->dev);
usb_detect_quirks(udev);
err = usb_enumerate_device(udev); /* Read descriptors */
@ -1833,7 +1821,8 @@ int usb_new_device(struct usb_device *udev)
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
usb_stop_pm(udev);
pm_runtime_disable(&udev->dev);
pm_runtime_set_suspended(&udev->dev);
return err;
}
@ -1982,7 +1971,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
if (!(portstatus & USB_PORT_STAT_RESET) &&
(portstatus & USB_PORT_STAT_ENABLE)) {
if (hub_is_wusb(hub))
udev->speed = USB_SPEED_VARIABLE;
udev->speed = USB_SPEED_WIRELESS;
else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
udev->speed = USB_SPEED_HIGH;
else if (portstatus & USB_PORT_STAT_LOW_SPEED)
@ -2008,7 +1997,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
struct usb_device *udev, unsigned int delay)
{
int i, status;
struct usb_hcd *hcd;
hcd = bus_to_hcd(udev->bus);
/* Block EHCI CF initialization during the port reset.
* Some companion controllers don't like it when they mix.
*/
@ -2036,6 +2027,14 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
/* TRSTRCY = 10 ms; plus some extra */
msleep(10 + 40);
update_address(udev, 0);
if (hcd->driver->reset_device) {
status = hcd->driver->reset_device(hcd, udev);
if (status < 0) {
dev_err(&udev->dev, "Cannot reset "
"HCD device state\n");
break;
}
}
/* FALL THROUGH */
case -ENOTCONN:
case -ENODEV:
@ -2381,14 +2380,17 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
}
/* caller has locked udev */
static int remote_wakeup(struct usb_device *udev)
int usb_remote_wakeup(struct usb_device *udev)
{
int status = 0;
if (udev->state == USB_STATE_SUSPENDED) {
dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
usb_mark_last_busy(udev);
status = usb_external_resume_device(udev, PMSG_REMOTE_RESUME);
status = usb_autoresume_device(udev);
if (status == 0) {
/* Let the drivers do their thing, then... */
usb_autosuspend_device(udev);
}
}
return status;
}
@ -2425,11 +2427,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
return status;
}
static inline int remote_wakeup(struct usb_device *udev)
{
return 0;
}
#endif
static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
@ -2496,11 +2493,6 @@ EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
#else /* CONFIG_PM */
static inline int remote_wakeup(struct usb_device *udev)
{
return 0;
}
#define hub_suspend NULL
#define hub_resume NULL
#define hub_reset_resume NULL
@ -2645,14 +2637,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
mutex_lock(&usb_address0_mutex);
if ((hcd->driver->flags & HCD_USB3) && udev->config) {
/* FIXME this will need special handling by the xHCI driver. */
dev_dbg(&udev->dev,
"xHCI reset of configured device "
"not supported yet.\n");
retval = -EINVAL;
goto fail;
} else if (!udev->config && oldspeed == USB_SPEED_SUPER) {
if (!udev->config && oldspeed == USB_SPEED_SUPER) {
/* Don't reset USB 3.0 devices during an initial setup */
usb_set_device_state(udev, USB_STATE_DEFAULT);
} else {
@ -2678,7 +2663,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
*/
switch (udev->speed) {
case USB_SPEED_SUPER:
case USB_SPEED_VARIABLE: /* fixed at 512 */
case USB_SPEED_WIRELESS: /* fixed at 512 */
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
break;
case USB_SPEED_HIGH: /* fixed at 64 */
@ -2706,7 +2691,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
case USB_SPEED_SUPER:
speed = "super";
break;
case USB_SPEED_VARIABLE:
case USB_SPEED_WIRELESS:
speed = "variable";
type = "Wireless ";
break;
@ -3006,7 +2991,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
/* For a suspended device, treat this as a
* remote wakeup event.
*/
status = remote_wakeup(udev);
status = usb_remote_wakeup(udev);
#endif
} else {
@ -3192,6 +3177,7 @@ loop_disable:
loop:
usb_ep0_reinit(udev);
release_address(udev);
hub_free_dev(udev);
usb_put_dev(udev);
if ((status == -ENOTCONN) || (status == -ENOTSUPP))
break;
@ -3259,7 +3245,7 @@ static void hub_events(void)
* disconnected while waiting for the lock to succeed. */
usb_lock_device(hdev);
if (unlikely(hub->disconnected))
goto loop2;
goto loop_disconnected;
/* If the hub has died, clean up after it */
if (hdev->state == USB_STATE_NOTATTACHED) {
@ -3352,7 +3338,7 @@ static void hub_events(void)
msleep(10);
usb_lock_device(udev);
ret = remote_wakeup(hdev->
ret = usb_remote_wakeup(hdev->
children[i-1]);
usb_unlock_device(udev);
if (ret < 0)
@ -3419,7 +3405,7 @@ static void hub_events(void)
* kick_khubd() and allow autosuspend.
*/
usb_autopm_put_interface(intf);
loop2:
loop_disconnected:
usb_unlock_device(hdev);
kref_put(&hub->kref, hub_release);
@ -3446,7 +3432,7 @@ static int hub_thread(void *__unused)
return 0;
}
static struct usb_device_id hub_id_table [] = {
static const struct usb_device_id hub_id_table[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
.bDeviceClass = USB_CLASS_HUB},
{ .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,

View File

@ -1316,7 +1316,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
alt = usb_altnum_to_altsetting(iface, alternate);
if (!alt) {
dev_warn(&dev->dev, "selecting invalid altsetting %d",
dev_warn(&dev->dev, "selecting invalid altsetting %d\n",
alternate);
return -EINVAL;
}
@ -1471,7 +1471,7 @@ int usb_reset_configuration(struct usb_device *dev)
/* If not, reinstate the old alternate settings */
if (retval < 0) {
reset_old_alts:
for (; i >= 0; i--) {
for (i--; i >= 0; i--) {
struct usb_interface *intf = config->interface[i];
struct usb_host_interface *alt;
@ -1843,7 +1843,6 @@ free_interfaces:
intf->dev.dma_mask = dev->dev.dma_mask;
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
device_initialize(&intf->dev);
mark_quiesced(intf);
dev_set_name(&intf->dev, "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration, alt->desc.bInterfaceNumber);

View File

@ -103,10 +103,19 @@ void usb_detect_quirks(struct usb_device *udev)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks);
/* By default, disable autosuspend for all non-hubs */
#ifdef CONFIG_USB_SUSPEND
if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
udev->autosuspend_disabled = 1;
/* By default, disable autosuspend for all devices. The hub driver
* will enable it for hubs.
*/
usb_disable_autosuspend(udev);
/* Autosuspend can also be disabled if the initial autosuspend_delay
* is negative.
*/
if (udev->autosuspend_delay < 0)
usb_autoresume_device(udev);
#endif
/* For the present, all devices default to USB-PERSIST enabled */
@ -120,6 +129,7 @@ void usb_detect_quirks(struct usb_device *udev)
* for all devices. It will affect things like hub resets
* and EMF-related port disables.
*/
udev->persist_enabled = 1;
if (!(udev->quirks & USB_QUIRK_RESET_MORPHS))
udev->persist_enabled = 1;
#endif /* CONFIG_PM */
}

View File

@ -115,7 +115,7 @@ show_speed(struct device *dev, struct device_attribute *attr, char *buf)
case USB_SPEED_HIGH:
speed = "480";
break;
case USB_SPEED_VARIABLE:
case USB_SPEED_WIRELESS:
speed = "480";
break;
case USB_SPEED_SUPER:
@ -190,6 +190,36 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
static ssize_t
show_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
udev = to_usb_device(dev);
return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET_MORPHS));
}
static ssize_t
set_avoid_reset_quirk(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
int config;
if (sscanf(buf, "%d", &config) != 1 || config < 0 || config > 1)
return -EINVAL;
usb_lock_device(udev);
if (config)
udev->quirks |= USB_QUIRK_RESET_MORPHS;
else
udev->quirks &= ~USB_QUIRK_RESET_MORPHS;
usb_unlock_device(udev);
return count;
}
static DEVICE_ATTR(avoid_reset_quirk, S_IRUGO | S_IWUSR,
show_avoid_reset_quirk, set_avoid_reset_quirk);
static ssize_t
show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
{
@ -226,9 +256,10 @@ set_persist(struct device *dev, struct device_attribute *attr,
if (sscanf(buf, "%d", &value) != 1)
return -EINVAL;
usb_pm_lock(udev);
usb_lock_device(udev);
udev->persist_enabled = !!value;
usb_pm_unlock(udev);
usb_unlock_device(udev);
return count;
}
@ -315,20 +346,34 @@ set_autosuspend(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
int value;
int value, old_delay;
int rc;
if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ ||
value <= - INT_MAX/HZ)
return -EINVAL;
value *= HZ;
usb_lock_device(udev);
old_delay = udev->autosuspend_delay;
udev->autosuspend_delay = value;
if (value >= 0)
usb_try_autosuspend_device(udev);
else {
if (usb_autoresume_device(udev) == 0)
if (old_delay < 0) { /* Autosuspend wasn't allowed */
if (value >= 0)
usb_autosuspend_device(udev);
} else { /* Autosuspend was allowed */
if (value < 0) {
rc = usb_autoresume_device(udev);
if (rc < 0) {
count = rc;
udev->autosuspend_delay = old_delay;
}
} else {
usb_try_autosuspend_device(udev);
}
}
usb_unlock_device(udev);
return count;
}
@ -356,34 +401,25 @@ set_level(struct device *dev, struct device_attribute *attr,
struct usb_device *udev = to_usb_device(dev);
int len = count;
char *cp;
int rc = 0;
int old_autosuspend_disabled;
int rc;
cp = memchr(buf, '\n', count);
if (cp)
len = cp - buf;
usb_lock_device(udev);
old_autosuspend_disabled = udev->autosuspend_disabled;
/* Setting the flags without calling usb_pm_lock is a subject to
* races, but who cares...
*/
if (len == sizeof on_string - 1 &&
strncmp(buf, on_string, len) == 0) {
udev->autosuspend_disabled = 1;
rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
strncmp(buf, on_string, len) == 0)
rc = usb_disable_autosuspend(udev);
} else if (len == sizeof auto_string - 1 &&
strncmp(buf, auto_string, len) == 0) {
udev->autosuspend_disabled = 0;
rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
else if (len == sizeof auto_string - 1 &&
strncmp(buf, auto_string, len) == 0)
rc = usb_enable_autosuspend(udev);
} else
else
rc = -EINVAL;
if (rc)
udev->autosuspend_disabled = old_autosuspend_disabled;
usb_unlock_device(udev);
return (rc < 0 ? rc : count);
}
@ -558,6 +594,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_version.attr,
&dev_attr_maxchild.attr,
&dev_attr_quirks.attr,
&dev_attr_avoid_reset_quirk.attr,
&dev_attr_authorized.attr,
&dev_attr_remove.attr,
NULL,

View File

@ -387,6 +387,13 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
unsigned int orig_flags = urb->transfer_flags;
unsigned int allowed;
static int pipetypes[4] = {
PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
};
/* Check that the pipe's type matches the endpoint's type */
if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
return -EPIPE; /* The most suitable error code :-) */
/* enforce simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
@ -430,7 +437,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
case USB_ENDPOINT_XFER_INT:
/* too small? */
switch (dev->speed) {
case USB_SPEED_VARIABLE:
case USB_SPEED_WIRELESS:
if (urb->interval < 6)
return -EINVAL;
break;
@ -446,7 +453,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (urb->interval > (1 << 15))
return -EINVAL;
max = 1 << 15;
case USB_SPEED_VARIABLE:
case USB_SPEED_WIRELESS:
if (urb->interval > 16)
return -EINVAL;
break;
@ -473,7 +480,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
default:
return -EINVAL;
}
if (dev->speed != USB_SPEED_VARIABLE) {
if (dev->speed != USB_SPEED_WIRELESS) {
/* Round down to a power of 2, no more than max */
urb->interval = min(max, 1 << ilog2(urb->interval));
}

View File

@ -49,9 +49,6 @@ const char *usbcore_name = "usbcore";
static int nousb; /* Disable USB when built into kernel image */
/* Workqueue for autosuspend and for remote wakeup of root hubs */
struct workqueue_struct *ksuspend_usb_wq;
#ifdef CONFIG_USB_SUSPEND
static int usb_autosuspend_delay = 2; /* Default delay value,
* in seconds */
@ -228,9 +225,6 @@ static void usb_release_dev(struct device *dev)
hcd = bus_to_hcd(udev->bus);
usb_destroy_configuration(udev);
/* Root hubs aren't real devices, so don't free HCD resources */
if (hcd->driver->free_dev && udev->parent)
hcd->driver->free_dev(hcd, udev);
usb_put_hcd(hcd);
kfree(udev->product);
kfree(udev->manufacturer);
@ -264,23 +258,6 @@ static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
#ifdef CONFIG_PM
static int ksuspend_usb_init(void)
{
/* This workqueue is supposed to be both freezable and
* singlethreaded. Its job doesn't justify running on more
* than one CPU.
*/
ksuspend_usb_wq = create_freezeable_workqueue("ksuspend_usbd");
if (!ksuspend_usb_wq)
return -ENOMEM;
return 0;
}
static void ksuspend_usb_cleanup(void)
{
destroy_workqueue(ksuspend_usb_wq);
}
/* USB device Power-Management thunks.
* There's no need to distinguish here between quiescing a USB device
* and powering it down; the generic_suspend() routine takes care of
@ -296,7 +273,7 @@ static int usb_dev_prepare(struct device *dev)
static void usb_dev_complete(struct device *dev)
{
/* Currently used only for rebinding interfaces */
usb_resume(dev, PMSG_RESUME); /* Message event is meaningless */
usb_resume(dev, PMSG_ON); /* FIXME: change to PMSG_COMPLETE */
}
static int usb_dev_suspend(struct device *dev)
@ -342,9 +319,7 @@ static const struct dev_pm_ops usb_device_pm_ops = {
#else
#define ksuspend_usb_init() 0
#define ksuspend_usb_cleanup() do {} while (0)
#define usb_device_pm_ops (*(struct dev_pm_ops *)0)
#define usb_device_pm_ops (*(struct dev_pm_ops *) NULL)
#endif /* CONFIG_PM */
@ -472,9 +447,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
INIT_LIST_HEAD(&dev->filelist);
#ifdef CONFIG_PM
mutex_init(&dev->pm_mutex);
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
INIT_WORK(&dev->autoresume, usb_autoresume_work);
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
dev->connect_time = jiffies;
dev->active_duration = -jiffies;
@ -1117,9 +1089,6 @@ static int __init usb_init(void)
if (retval)
goto out;
retval = ksuspend_usb_init();
if (retval)
goto out;
retval = bus_register(&usb_bus_type);
if (retval)
goto bus_register_failed;
@ -1159,7 +1128,7 @@ major_init_failed:
bus_notifier_failed:
bus_unregister(&usb_bus_type);
bus_register_failed:
ksuspend_usb_cleanup();
usb_debugfs_cleanup();
out:
return retval;
}
@ -1181,7 +1150,6 @@ static void __exit usb_exit(void)
usb_hub_cleanup();
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
bus_unregister(&usb_bus_type);
ksuspend_usb_cleanup();
usb_debugfs_cleanup();
}

View File

@ -55,24 +55,8 @@ extern void usb_major_cleanup(void);
extern int usb_suspend(struct device *dev, pm_message_t msg);
extern int usb_resume(struct device *dev, pm_message_t msg);
extern void usb_autosuspend_work(struct work_struct *work);
extern void usb_autoresume_work(struct work_struct *work);
extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);
extern int usb_external_suspend_device(struct usb_device *udev,
pm_message_t msg);
extern int usb_external_resume_device(struct usb_device *udev,
pm_message_t msg);
static inline void usb_pm_lock(struct usb_device *udev)
{
mutex_lock_nested(&udev->pm_mutex, udev->level);
}
static inline void usb_pm_unlock(struct usb_device *udev)
{
mutex_unlock(&udev->pm_mutex);
}
#else
@ -86,9 +70,6 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
return 0;
}
static inline void usb_pm_lock(struct usb_device *udev) {}
static inline void usb_pm_unlock(struct usb_device *udev) {}
#endif
#ifdef CONFIG_USB_SUSPEND
@ -96,6 +77,7 @@ static inline void usb_pm_unlock(struct usb_device *udev) {}
extern void usb_autosuspend_device(struct usb_device *udev);
extern void usb_try_autosuspend_device(struct usb_device *udev);
extern int usb_autoresume_device(struct usb_device *udev);
extern int usb_remote_wakeup(struct usb_device *dev);
#else
@ -106,9 +88,13 @@ static inline int usb_autoresume_device(struct usb_device *udev)
return 0;
}
static inline int usb_remote_wakeup(struct usb_device *udev)
{
return 0;
}
#endif
extern struct workqueue_struct *ksuspend_usb_wq;
extern struct bus_type usb_bus_type;
extern struct device_type usb_device_type;
extern struct device_type usb_if_device_type;
@ -138,23 +124,6 @@ static inline int is_usb_device_driver(struct device_driver *drv)
for_devices;
}
/* Interfaces and their "power state" are owned by usbcore */
static inline void mark_active(struct usb_interface *f)
{
f->is_active = 1;
}
static inline void mark_quiesced(struct usb_interface *f)
{
f->is_active = 0;
}
static inline int is_active(const struct usb_interface *f)
{
return f->is_active;
}
/* for labeling diagnostics */
extern const char *usbcore_name;

View File

@ -66,8 +66,6 @@ static struct ehci_dev ehci_dev;
#define USB_DEBUG_DEVNUM 127
#define DBGP_DATA_TOGGLE 0x8800
#ifdef DBGP_DEBUG
#define dbgp_printk printk
static void dbgp_ehci_status(char *str)
@ -88,11 +86,6 @@ static inline void dbgp_ehci_status(char *str) { }
static inline void dbgp_printk(const char *fmt, ...) { }
#endif
static inline u32 dbgp_pid_update(u32 x, u32 tok)
{
return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff);
}
static inline u32 dbgp_len_update(u32 x, u32 len)
{
return (x & ~0x0f) | (len & 0x0f);
@ -136,6 +129,19 @@ static inline u32 dbgp_len_update(u32 x, u32 len)
#define DBGP_MAX_PACKET 8
#define DBGP_TIMEOUT (250 * 1000)
#define DBGP_LOOPS 1000
static inline u32 dbgp_pid_write_update(u32 x, u32 tok)
{
static int data0 = USB_PID_DATA1;
data0 ^= USB_PID_DATA_TOGGLE;
return (x & 0xffff0000) | (data0 << 8) | (tok & 0xff);
}
static inline u32 dbgp_pid_read_update(u32 x, u32 tok)
{
return (x & 0xffff0000) | (USB_PID_DATA0 << 8) | (tok & 0xff);
}
static int dbgp_wait_until_complete(void)
{
@ -180,7 +186,7 @@ static int dbgp_wait_until_done(unsigned ctrl)
{
u32 pids, lpid;
int ret;
int loop = 3;
int loop = DBGP_LOOPS;
retry:
writel(ctrl | DBGP_GO, &ehci_debug->control);
@ -197,6 +203,8 @@ retry:
*/
if (ret == -DBGP_TIMEOUT && !dbgp_not_safe)
dbgp_not_safe = 1;
if (ret == -DBGP_ERR_BAD && --loop > 0)
goto retry;
return ret;
}
@ -245,12 +253,20 @@ static inline void dbgp_get_data(void *buf, int size)
bytes[i] = (hi >> (8*(i - 4))) & 0xff;
}
static int dbgp_out(u32 addr, const char *bytes, int size)
static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
const char *bytes, int size)
{
int ret;
u32 addr;
u32 pids, ctrl;
if (size > DBGP_MAX_PACKET)
return -1;
addr = DBGP_EPADDR(devnum, endpoint);
pids = readl(&ehci_debug->pids);
pids = dbgp_pid_update(pids, USB_PID_OUT);
pids = dbgp_pid_write_update(pids, USB_PID_OUT);
ctrl = readl(&ehci_debug->control);
ctrl = dbgp_len_update(ctrl, size);
@ -260,34 +276,7 @@ static int dbgp_out(u32 addr, const char *bytes, int size)
dbgp_set_data(bytes, size);
writel(addr, &ehci_debug->address);
writel(pids, &ehci_debug->pids);
return dbgp_wait_until_done(ctrl);
}
static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
const char *bytes, int size)
{
int ret;
int loops = 5;
u32 addr;
if (size > DBGP_MAX_PACKET)
return -1;
addr = DBGP_EPADDR(devnum, endpoint);
try_again:
if (loops--) {
ret = dbgp_out(addr, bytes, size);
if (ret == -DBGP_ERR_BAD) {
int try_loops = 3;
do {
/* Emit a dummy packet to re-sync communication
* with the debug device */
if (dbgp_out(addr, "12345678", 8) >= 0) {
udelay(2);
goto try_again;
}
} while (try_loops--);
}
}
ret = dbgp_wait_until_done(ctrl);
return ret;
}
@ -304,7 +293,7 @@ static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
addr = DBGP_EPADDR(devnum, endpoint);
pids = readl(&ehci_debug->pids);
pids = dbgp_pid_update(pids, USB_PID_IN);
pids = dbgp_pid_read_update(pids, USB_PID_IN);
ctrl = readl(&ehci_debug->control);
ctrl = dbgp_len_update(ctrl, size);
@ -362,7 +351,6 @@ static int dbgp_control_msg(unsigned devnum, int requesttype,
return dbgp_bulk_read(devnum, 0, data, size);
}
/* Find a PCI capability */
static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap)
{

View File

@ -812,6 +812,16 @@ config USB_CDC_COMPOSITE
Say "y" to link the driver statically, or "m" to build a
dynamically linked module.
config USB_G_NOKIA
tristate "Nokia composite gadget"
depends on PHONET
help
The Nokia composite gadget provides support for acm, obex
and phonet in only one composite gadget driver.
It's only really useful for N900 hardware. If you're building
a kernel for N900, say Y or M here. If unsure, say N.
config USB_G_MULTI
tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
depends on BLOCK && NET

View File

@ -43,6 +43,7 @@ g_mass_storage-objs := mass_storage.o
g_printer-objs := printer.o
g_cdc-objs := cdc2.o
g_multi-objs := multi.o
g_nokia-objs := nokia.o
obj-$(CONFIG_USB_ZERO) += g_zero.o
obj-$(CONFIG_USB_AUDIO) += g_audio.o
@ -55,4 +56,5 @@ obj-$(CONFIG_USB_G_PRINTER) += g_printer.o
obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
obj-$(CONFIG_USB_G_MULTI) += g_multi.o
obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o

View File

@ -1656,9 +1656,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
if (!res)
return -ENXIO;
if (!request_mem_region(res->start,
res->end - res->start + 1,
driver_name)) {
if (!request_mem_region(res->start, resource_size(res), driver_name)) {
DBG("someone's using UDC memory\n");
return -EBUSY;
}
@ -1699,7 +1697,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
udc->ep[3].maxpacket = 64;
}
udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
udc->udp_baseaddr = ioremap(res->start, resource_size(res));
if (!udc->udp_baseaddr) {
retval = -ENOMEM;
goto fail0a;
@ -1781,7 +1779,7 @@ fail0a:
if (cpu_is_at91rm9200())
gpio_free(udc->board.pullup_pin);
fail0:
release_mem_region(res->start, res->end - res->start + 1);
release_mem_region(res->start, resource_size(res));
DBG("%s probe failed, %d\n", driver_name, retval);
return retval;
}
@ -1813,7 +1811,7 @@ static int __exit at91udc_remove(struct platform_device *pdev)
gpio_free(udc->board.pullup_pin);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, res->end - res->start + 1);
release_mem_region(res->start, resource_size(res));
clk_put(udc->iclk);
clk_put(udc->fclk);

View File

@ -320,7 +320,7 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc)
static int vbus_is_present(struct usba_udc *udc)
{
if (gpio_is_valid(udc->vbus_pin))
return gpio_get_value(udc->vbus_pin);
return gpio_get_value(udc->vbus_pin) ^ udc->vbus_pin_inverted;
/* No Vbus detection: Assume always present */
return 1;
@ -1763,7 +1763,7 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
if (!udc->driver)
goto out;
vbus = gpio_get_value(udc->vbus_pin);
vbus = vbus_is_present(udc);
if (vbus != udc->vbus_prev) {
if (vbus) {
toggle_bias(1);
@ -1914,14 +1914,14 @@ static int __init usba_udc_probe(struct platform_device *pdev)
udc->vbus_pin = -ENODEV;
ret = -ENOMEM;
udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
udc->regs = ioremap(regs->start, resource_size(regs));
if (!udc->regs) {
dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
goto err_map_regs;
}
dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
(unsigned long)regs->start, udc->regs);
udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1);
udc->fifo = ioremap(fifo->start, resource_size(fifo));
if (!udc->fifo) {
dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
goto err_map_fifo;
@ -2000,6 +2000,7 @@ static int __init usba_udc_probe(struct platform_device *pdev)
if (gpio_is_valid(pdata->vbus_pin)) {
if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
udc->vbus_pin = pdata->vbus_pin;
udc->vbus_pin_inverted = pdata->vbus_pin_inverted;
ret = request_irq(gpio_to_irq(udc->vbus_pin),
usba_vbus_irq, 0,

View File

@ -323,6 +323,7 @@ struct usba_udc {
struct platform_device *pdev;
int irq;
int vbus_pin;
int vbus_pin_inverted;
struct clk *pclk;
struct clk *hclk;

View File

@ -265,16 +265,24 @@ struct usb_ep * __init usb_ep_autoconfig (
return ep;
}
} else if (gadget_is_sh (gadget) && USB_ENDPOINT_XFER_INT == type) {
/* single buffering is enough; maybe 8 byte fifo is too */
ep = find_ep (gadget, "ep3in-bulk");
if (ep && ep_matches (gadget, ep, desc))
return ep;
} else if (gadget_is_mq11xx (gadget) && USB_ENDPOINT_XFER_INT == type) {
ep = find_ep (gadget, "ep1-bulk");
#ifdef CONFIG_BLACKFIN
} else if (gadget_is_musbhsfc(gadget) || gadget_is_musbhdrc(gadget)) {
if ((USB_ENDPOINT_XFER_BULK == type) ||
(USB_ENDPOINT_XFER_ISOC == type)) {
if (USB_DIR_IN & desc->bEndpointAddress)
ep = find_ep (gadget, "ep5in");
else
ep = find_ep (gadget, "ep6out");
} else if (USB_ENDPOINT_XFER_INT == type) {
if (USB_DIR_IN & desc->bEndpointAddress)
ep = find_ep(gadget, "ep1in");
else
ep = find_ep(gadget, "ep2out");
} else
ep = NULL;
if (ep && ep_matches (gadget, ep, desc))
return ep;
#endif
}
/* Second, look at endpoints until an unclaimed one looks usable */

View File

@ -259,7 +259,7 @@ static struct usb_configuration rndis_config_driver = {
/*-------------------------------------------------------------------------*/
#ifdef USB_ETH_EEM
#ifdef CONFIG_USB_ETH_EEM
static int use_eem = 1;
#else
static int use_eem;

View File

@ -702,14 +702,6 @@ acm_unbind(struct usb_configuration *c, struct usb_function *f)
/* Some controllers can't support CDC ACM ... */
static inline bool can_support_cdc(struct usb_configuration *c)
{
/* SH3 doesn't support multiple interfaces */
if (gadget_is_sh(c->cdev->gadget))
return false;
/* sa1100 doesn't have a third interrupt endpoint */
if (gadget_is_sa1100(c->cdev->gadget))
return false;
/* everything else is *probably* fine ... */
return true;
}

View File

@ -497,12 +497,9 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
struct net_device *net;
/* Enable zlps by default for ECM conformance;
* override for musb_hdrc (avoids txdma ovhead)
* and sa1100 (can't).
* override for musb_hdrc (avoids txdma ovhead).
*/
ecm->port.is_zlp_ok = !(
gadget_is_sa1100(cdev->gadget)
|| gadget_is_musbhdrc(cdev->gadget)
ecm->port.is_zlp_ok = !(gadget_is_musbhdrc(cdev->gadget)
);
ecm->port.cdc_filter = DEFAULT_FILTER;
DBG(cdev, "activate ecm\n");

View File

@ -368,7 +368,7 @@ struct fsg_common {
struct task_struct *thread_task;
/* Callback function to call when thread exits. */
void (*thread_exits)(struct fsg_common *common);
int (*thread_exits)(struct fsg_common *common);
/* Gadget's private data. */
void *private_data;
@ -392,8 +392,12 @@ struct fsg_config {
const char *lun_name_format;
const char *thread_name;
/* Callback function to call when thread exits. */
void (*thread_exits)(struct fsg_common *common);
/* 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);
/* Gadget's private data. */
void *private_data;
@ -614,7 +618,12 @@ static int fsg_setup(struct usb_function *f,
return -EDOM;
VDBG(fsg, "get max LUN\n");
*(u8 *) req->buf = fsg->common->nluns - 1;
return 1;
/* Respond with data/status */
req->length = min((u16)1, w_length);
fsg->common->ep0req_name =
ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out";
return ep0_queue(fsg->common);
}
VDBG(fsg,
@ -2524,14 +2533,6 @@ static void handle_exception(struct fsg_common *common)
case FSG_STATE_CONFIG_CHANGE:
rc = do_set_config(common, new_config);
if (common->ep0_req_tag != exception_req_tag)
break;
if (rc != 0) { /* STALL on errors */
DBG(common, "ep0 set halt\n");
usb_ep_set_halt(common->ep0);
} else { /* Complete the status stage */
ep0_queue(common);
}
break;
case FSG_STATE_EXIT:
@ -2615,8 +2616,20 @@ static int fsg_main_thread(void *common_)
common->thread_task = NULL;
spin_unlock_irq(&common->lock);
if (common->thread_exits)
common->thread_exits(common);
if (!common->thread_exits || common->thread_exits(common) < 0) {
struct fsg_lun *curlun = common->luns;
unsigned i = common->nluns;
down_write(&common->filesem);
for (; i--; ++curlun) {
if (!fsg_lun_is_open(curlun))
continue;
fsg_lun_close(curlun);
curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
}
up_write(&common->filesem);
}
/* Let the unbind and cleanup routines know the thread has exited */
complete_and_exit(&common->thread_notifier, 0);
@ -2763,10 +2776,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
if (cfg->release != 0xffff) {
i = cfg->release;
} else {
/* The sa1100 controller is not supported */
i = gadget_is_sa1100(gadget)
? -1
: usb_gadget_controller_number(gadget);
i = usb_gadget_controller_number(gadget);
if (i >= 0) {
i = 0x0300 + i;
} else {
@ -2791,8 +2801,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
* disable stalls.
*/
common->can_stall = cfg->can_stall &&
!(gadget_is_sh(common->gadget) ||
gadget_is_at91(common->gadget));
!(gadget_is_at91(common->gadget));
spin_lock_init(&common->lock);
@ -2852,7 +2861,6 @@ error_release:
/* Call fsg_common_release() directly, ref might be not
* initialised */
fsg_common_release(&common->ref);
complete(&common->thread_notifier);
return ERR_PTR(rc);
}

View File

@ -769,10 +769,6 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
/* Some controllers can't support RNDIS ... */
static inline bool can_support_rndis(struct usb_configuration *c)
{
/* only two endpoints on sa1100 */
if (gadget_is_sa1100(c->cdev->gadget))
return false;
/* everything else is *presumably* fine */
return true;
}

View File

@ -3208,15 +3208,11 @@ static int __init check_parameters(struct fsg_dev *fsg)
* halt bulk endpoints correctly. If one of them is present,
* disable stalls.
*/
if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget))
if (gadget_is_at91(fsg->gadget))
mod_data.can_stall = 0;
if (mod_data.release == 0xffff) { // Parameter wasn't set
/* The sa1100 controller is not supported */
if (gadget_is_sa1100(fsg->gadget))
gcnum = -1;
else
gcnum = usb_gadget_controller_number(fsg->gadget);
gcnum = usb_gadget_controller_number(fsg->gadget);
if (gcnum >= 0)
mod_data.release = 0x0300 + gcnum;
else {

View File

@ -2749,7 +2749,7 @@ static int __devexit qe_udc_remove(struct of_device *ofdev)
}
/*-------------------------------------------------------------------------*/
static struct of_device_id __devinitdata qe_udc_match[] = {
static const struct of_device_id qe_udc_match[] __devinitconst = {
{
.compatible = "fsl,mpc8323-qe-usb",
.data = (void *)PORT_QE,

View File

@ -45,46 +45,18 @@
#define gadget_is_goku(g) 0
#endif
/* SH3 UDC -- not yet ported 2.4 --> 2.6 */
#ifdef CONFIG_USB_GADGET_SUPERH
#define gadget_is_sh(g) !strcmp("sh_udc", (g)->name)
#else
#define gadget_is_sh(g) 0
#endif
/* not yet stable on 2.6 (would help "original Zaurus") */
#ifdef CONFIG_USB_GADGET_SA1100
#define gadget_is_sa1100(g) !strcmp("sa1100_udc", (g)->name)
#else
#define gadget_is_sa1100(g) 0
#endif
#ifdef CONFIG_USB_GADGET_LH7A40X
#define gadget_is_lh7a40x(g) !strcmp("lh7a40x_udc", (g)->name)
#else
#define gadget_is_lh7a40x(g) 0
#endif
/* handhelds.org tree (?) */
#ifdef CONFIG_USB_GADGET_MQ11XX
#define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name)
#else
#define gadget_is_mq11xx(g) 0
#endif
#ifdef CONFIG_USB_GADGET_OMAP
#define gadget_is_omap(g) !strcmp("omap_udc", (g)->name)
#else
#define gadget_is_omap(g) 0
#endif
/* not yet ported 2.4 --> 2.6 */
#ifdef CONFIG_USB_GADGET_N9604
#define gadget_is_n9604(g) !strcmp("n9604_udc", (g)->name)
#else
#define gadget_is_n9604(g) 0
#endif
/* various unstable versions available */
#ifdef CONFIG_USB_GADGET_PXA27X
#define gadget_is_pxa27x(g) !strcmp("pxa27x_udc", (g)->name)
@ -122,14 +94,6 @@
#define gadget_is_fsl_usb2(g) 0
#endif
/* Mentor high speed function controller */
/* from Montavista kernel (?) */
#ifdef CONFIG_USB_GADGET_MUSBHSFC
#define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name)
#else
#define gadget_is_musbhsfc(g) 0
#endif
/* Mentor high speed "dual role" controller, in peripheral role */
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
#define gadget_is_musbhdrc(g) !strcmp("musb_hdrc", (g)->name)
@ -143,13 +107,6 @@
#define gadget_is_langwell(g) 0
#endif
/* from Montavista kernel (?) */
#ifdef CONFIG_USB_GADGET_MPC8272
#define gadget_is_mpc8272(g) !strcmp("mpc8272_udc", (g)->name)
#else
#define gadget_is_mpc8272(g) 0
#endif
#ifdef CONFIG_USB_GADGET_M66592
#define gadget_is_m66592(g) !strcmp("m66592_udc", (g)->name)
#else
@ -203,20 +160,12 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x02;
else if (gadget_is_pxa(gadget))
return 0x03;
else if (gadget_is_sh(gadget))
return 0x04;
else if (gadget_is_sa1100(gadget))
return 0x05;
else if (gadget_is_goku(gadget))
return 0x06;
else if (gadget_is_mq11xx(gadget))
return 0x07;
else if (gadget_is_omap(gadget))
return 0x08;
else if (gadget_is_lh7a40x(gadget))
return 0x09;
else if (gadget_is_n9604(gadget))
return 0x10;
else if (gadget_is_pxa27x(gadget))
return 0x11;
else if (gadget_is_s3c2410(gadget))
@ -225,12 +174,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x13;
else if (gadget_is_imx(gadget))
return 0x14;
else if (gadget_is_musbhsfc(gadget))
return 0x15;
else if (gadget_is_musbhdrc(gadget))
return 0x16;
else if (gadget_is_mpc8272(gadget))
return 0x17;
else if (gadget_is_atmel_usba(gadget))
return 0x18;
else if (gadget_is_fsl_usb2(gadget))
@ -265,10 +210,6 @@ static inline bool gadget_supports_altsettings(struct usb_gadget *gadget)
if (gadget_is_pxa27x(gadget))
return false;
/* SH3 hardware just doesn't do altsettings */
if (gadget_is_sh(gadget))
return false;
/* Everything else is *presumably* fine ... */
return true;
}

View File

@ -618,11 +618,6 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
}
#endif
if (gadget_is_sa1100(gadget) && dev->config) {
/* tx fifo is full, but we can't clear it...*/
ERROR(dev, "can't change configurations\n");
return -ESPIPE;
}
gmidi_reset_config(dev);
switch (number) {

View File

@ -1859,7 +1859,7 @@ done:
/*-------------------------------------------------------------------------*/
static struct pci_device_id pci_ids [] = { {
static const struct pci_device_id pci_ids[] = { {
.class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
.class_mask = ~0,
.vendor = 0x102f, /* Toshiba */

View File

@ -194,7 +194,7 @@ enum ep_state {
};
struct ep_data {
struct semaphore lock;
struct mutex lock;
enum ep_state state;
atomic_t count;
struct dev_data *dev;
@ -298,10 +298,10 @@ get_ready_ep (unsigned f_flags, struct ep_data *epdata)
int val;
if (f_flags & O_NONBLOCK) {
if (down_trylock (&epdata->lock) != 0)
if (!mutex_trylock(&epdata->lock))
goto nonblock;
if (epdata->state != STATE_EP_ENABLED) {
up (&epdata->lock);
mutex_unlock(&epdata->lock);
nonblock:
val = -EAGAIN;
} else
@ -309,7 +309,8 @@ nonblock:
return val;
}
if ((val = down_interruptible (&epdata->lock)) < 0)
val = mutex_lock_interruptible(&epdata->lock);
if (val < 0)
return val;
switch (epdata->state) {
@ -323,7 +324,7 @@ nonblock:
// FALLTHROUGH
case STATE_EP_UNBOUND: /* clean disconnect */
val = -ENODEV;
up (&epdata->lock);
mutex_unlock(&epdata->lock);
}
return val;
}
@ -393,7 +394,7 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
if (likely (data->ep != NULL))
usb_ep_set_halt (data->ep);
spin_unlock_irq (&data->dev->lock);
up (&data->lock);
mutex_unlock(&data->lock);
return -EBADMSG;
}
@ -411,7 +412,7 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
value = -EFAULT;
free1:
up (&data->lock);
mutex_unlock(&data->lock);
kfree (kbuf);
return value;
}
@ -436,7 +437,7 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
if (likely (data->ep != NULL))
usb_ep_set_halt (data->ep);
spin_unlock_irq (&data->dev->lock);
up (&data->lock);
mutex_unlock(&data->lock);
return -EBADMSG;
}
@ -455,7 +456,7 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
VDEBUG (data->dev, "%s write %zu IN, status %d\n",
data->name, len, (int) value);
free1:
up (&data->lock);
mutex_unlock(&data->lock);
kfree (kbuf);
return value;
}
@ -466,7 +467,8 @@ ep_release (struct inode *inode, struct file *fd)
struct ep_data *data = fd->private_data;
int value;
if ((value = down_interruptible(&data->lock)) < 0)
value = mutex_lock_interruptible(&data->lock);
if (value < 0)
return value;
/* clean up if this can be reopened */
@ -476,7 +478,7 @@ ep_release (struct inode *inode, struct file *fd)
data->hs_desc.bDescriptorType = 0;
usb_ep_disable(data->ep);
}
up (&data->lock);
mutex_unlock(&data->lock);
put_ep (data);
return 0;
}
@ -507,7 +509,7 @@ static long ep_ioctl(struct file *fd, unsigned code, unsigned long value)
} else
status = -ENODEV;
spin_unlock_irq (&data->dev->lock);
up (&data->lock);
mutex_unlock(&data->lock);
return status;
}
@ -673,7 +675,7 @@ fail:
value = -ENODEV;
spin_unlock_irq(&epdata->dev->lock);
up(&epdata->lock);
mutex_unlock(&epdata->lock);
if (unlikely(value)) {
kfree(priv);
@ -765,7 +767,8 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
u32 tag;
int value, length = len;
if ((value = down_interruptible (&data->lock)) < 0)
value = mutex_lock_interruptible(&data->lock);
if (value < 0)
return value;
if (data->state != STATE_EP_READY) {
@ -854,7 +857,7 @@ fail:
data->desc.bDescriptorType = 0;
data->hs_desc.bDescriptorType = 0;
}
up (&data->lock);
mutex_unlock(&data->lock);
return value;
fail0:
value = -EINVAL;
@ -870,7 +873,7 @@ ep_open (struct inode *inode, struct file *fd)
struct ep_data *data = inode->i_private;
int value = -EBUSY;
if (down_interruptible (&data->lock) != 0)
if (mutex_lock_interruptible(&data->lock) != 0)
return -EINTR;
spin_lock_irq (&data->dev->lock);
if (data->dev->state == STATE_DEV_UNBOUND)
@ -885,7 +888,7 @@ ep_open (struct inode *inode, struct file *fd)
DBG (data->dev, "%s state %d\n",
data->name, data->state);
spin_unlock_irq (&data->dev->lock);
up (&data->lock);
mutex_unlock(&data->lock);
return value;
}
@ -1631,7 +1634,7 @@ static int activate_ep_files (struct dev_data *dev)
if (!data)
goto enomem0;
data->state = STATE_EP_DISABLED;
init_MUTEX (&data->lock);
mutex_init(&data->lock);
init_waitqueue_head (&data->wait);
strncpy (data->name, ep->name, sizeof (data->name) - 1);

View File

@ -135,6 +135,12 @@ FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
static unsigned long msg_registered = 0;
static void msg_cleanup(void);
static int msg_thread_exits(struct fsg_common *common)
{
msg_cleanup();
return 0;
}
static int __init msg_do_config(struct usb_configuration *c)
{
struct fsg_common *common;
@ -147,7 +153,7 @@ static int __init msg_do_config(struct usb_configuration *c)
}
fsg_config_from_params(&config, &mod_data);
config.thread_exits = (void(*)(struct fsg_common*))&msg_cleanup;
config.thread_exits = msg_thread_exits;
common = fsg_common_init(0, c->cdev, &config);
if (IS_ERR(common))
return PTR_ERR(common);

259
drivers/usb/gadget/nokia.c Normal file
View File

@ -0,0 +1,259 @@
/*
* nokia.c -- Nokia Composite Gadget Driver
*
* Copyright (C) 2008-2010 Nokia Corporation
* Contact: Felipe Balbi <felipe.balbi@nokia.com>
*
* This gadget driver borrows from serial.c which is:
*
* Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
* Copyright (C) 2008 by David Brownell
* Copyright (C) 2008 by Nokia Corporation
*
* This software is distributed under the terms of the GNU General
* Public License ("GPL") as published by the Free Software Foundation,
* version 2 of that License.
*/
#include <linux/kernel.h>
#include <linux/utsname.h>
#include <linux/device.h>
#include "u_serial.h"
#include "u_ether.h"
#include "u_phonet.h"
#include "gadget_chips.h"
/* Defines */
#define NOKIA_VERSION_NUM 0x0211
#define NOKIA_LONG_NAME "N900 (PC-Suite Mode)"
/*-------------------------------------------------------------------------*/
/*
* Kbuild is not very cooperative with respect to linking separately
* compiled library objects into one module. So for now we won't use
* separate compilation ... ensuring init/exit sections work to shrink
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
#include "composite.c"
#include "usbstring.c"
#include "config.c"
#include "epautoconf.c"
#include "u_serial.c"
#include "f_acm.c"
#include "f_ecm.c"
#include "f_obex.c"
#include "f_serial.c"
#include "f_phonet.c"
#include "u_ether.c"
/*-------------------------------------------------------------------------*/
#define NOKIA_VENDOR_ID 0x0421 /* Nokia */
#define NOKIA_PRODUCT_ID 0x01c8 /* Nokia Gadget */
/* string IDs are assigned dynamically */
#define STRING_MANUFACTURER_IDX 0
#define STRING_PRODUCT_IDX 1
#define STRING_DESCRIPTION_IDX 2
static char manufacturer_nokia[] = "Nokia";
static const char product_nokia[] = NOKIA_LONG_NAME;
static const char description_nokia[] = "PC-Suite Configuration";
static struct usb_string strings_dev[] = {
[STRING_MANUFACTURER_IDX].s = manufacturer_nokia,
[STRING_PRODUCT_IDX].s = NOKIA_LONG_NAME,
[STRING_DESCRIPTION_IDX].s = description_nokia,
{ } /* end of list */
};
static struct usb_gadget_strings stringtab_dev = {
.language = 0x0409, /* en-us */
.strings = strings_dev,
};
static struct usb_gadget_strings *dev_strings[] = {
&stringtab_dev,
NULL,
};
static struct usb_device_descriptor device_desc = {
.bLength = USB_DT_DEVICE_SIZE,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = __constant_cpu_to_le16(0x0200),
.bDeviceClass = USB_CLASS_COMM,
.idVendor = __constant_cpu_to_le16(NOKIA_VENDOR_ID),
.idProduct = __constant_cpu_to_le16(NOKIA_PRODUCT_ID),
/* .iManufacturer = DYNAMIC */
/* .iProduct = DYNAMIC */
.bNumConfigurations = 1,
};
/*-------------------------------------------------------------------------*/
/* Module */
MODULE_DESCRIPTION("Nokia composite gadget driver for N900");
MODULE_AUTHOR("Felipe Balbi");
MODULE_LICENSE("GPL");
/*-------------------------------------------------------------------------*/
static u8 hostaddr[ETH_ALEN];
static int __init nokia_bind_config(struct usb_configuration *c)
{
int status = 0;
status = phonet_bind_config(c);
if (status)
printk(KERN_DEBUG "could not bind phonet config\n");
status = obex_bind_config(c, 0);
if (status)
printk(KERN_DEBUG "could not bind obex config %d\n", 0);
status = obex_bind_config(c, 1);
if (status)
printk(KERN_DEBUG "could not bind obex config %d\n", 0);
status = acm_bind_config(c, 2);
if (status)
printk(KERN_DEBUG "could not bind acm config\n");
status = ecm_bind_config(c, hostaddr);
if (status)
printk(KERN_DEBUG "could not bind ecm config\n");
return status;
}
static struct usb_configuration nokia_config_500ma_driver = {
.label = "Bus Powered",
.bind = nokia_bind_config,
.bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_ONE,
.bMaxPower = 250, /* 500mA */
};
static struct usb_configuration nokia_config_100ma_driver = {
.label = "Self Powered",
.bind = nokia_bind_config,
.bConfigurationValue = 2,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
.bMaxPower = 50, /* 100 mA */
};
static int __init nokia_bind(struct usb_composite_dev *cdev)
{
int gcnum;
struct usb_gadget *gadget = cdev->gadget;
int status;
status = gphonet_setup(cdev->gadget);
if (status < 0)
goto err_phonet;
status = gserial_setup(cdev->gadget, 3);
if (status < 0)
goto err_serial;
status = gether_setup(cdev->gadget, hostaddr);
if (status < 0)
goto err_ether;
status = usb_string_id(cdev);
if (status < 0)
goto err_usb;
strings_dev[STRING_MANUFACTURER_IDX].id = status;
device_desc.iManufacturer = status;
status = usb_string_id(cdev);
if (status < 0)
goto err_usb;
strings_dev[STRING_PRODUCT_IDX].id = status;
device_desc.iProduct = status;
/* config description */
status = usb_string_id(cdev);
if (status < 0)
goto err_usb;
strings_dev[STRING_DESCRIPTION_IDX].id = status;
nokia_config_500ma_driver.iConfiguration = status;
nokia_config_100ma_driver.iConfiguration = status;
/* set up other descriptors */
gcnum = usb_gadget_controller_number(gadget);
if (gcnum >= 0)
device_desc.bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM);
else {
/* this should only work with hw that supports altsettings
* and several endpoints, anything else, panic.
*/
pr_err("nokia_bind: controller '%s' not recognized\n",
gadget->name);
goto err_usb;
}
/* finaly register the configuration */
status = usb_add_config(cdev, &nokia_config_500ma_driver);
if (status < 0)
goto err_usb;
status = usb_add_config(cdev, &nokia_config_100ma_driver);
if (status < 0)
goto err_usb;
dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
return 0;
err_usb:
gether_cleanup();
err_ether:
gserial_cleanup();
err_serial:
gphonet_cleanup();
err_phonet:
return status;
}
static int __exit nokia_unbind(struct usb_composite_dev *cdev)
{
gphonet_cleanup();
gserial_cleanup();
gether_cleanup();
return 0;
}
static struct usb_composite_driver nokia_driver = {
.name = "g_nokia",
.dev = &device_desc,
.strings = dev_strings,
.bind = nokia_bind,
.unbind = __exit_p(nokia_unbind),
};
static int __init nokia_init(void)
{
return usb_composite_register(&nokia_driver);
}
module_init(nokia_init);
static void __exit nokia_cleanup(void)
{
usb_composite_unregister(&nokia_driver);
}
module_exit(nokia_cleanup);

View File

@ -949,12 +949,6 @@ printer_set_config(struct printer_dev *dev, unsigned number)
int result = 0;
struct usb_gadget *gadget = dev->gadget;
if (gadget_is_sa1100(gadget) && dev->config) {
/* tx fifo is full, but we can't clear it...*/
INFO(dev, "can't change configurations\n");
return -ESPIPE;
}
switch (number) {
case DEV_CONFIG_VALUE:
result = 0;
@ -1033,12 +1027,6 @@ set_interface(struct printer_dev *dev, unsigned number)
{
int result = 0;
if (gadget_is_sa1100(dev->gadget) && dev->interface < 0) {
/* tx fifo is full, but we can't clear it...*/
INFO(dev, "can't change interfaces\n");
return -ESPIPE;
}
/* Free the current interface */
switch (dev->interface) {
case PRINTER_INTERFACE:
@ -1392,12 +1380,6 @@ printer_bind(struct usb_gadget *gadget)
goto fail;
}
if (gadget_is_sa1100(gadget)) {
/* hardware can't write zero length packets. */
ERROR(dev, "SA1100 controller is unsupport by this driver\n");
goto fail;
}
gcnum = usb_gadget_controller_number(gadget);
if (gcnum >= 0) {
device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);

View File

@ -742,13 +742,17 @@ static void ep_del_request(struct pxa_ep *ep, struct pxa27x_request *req)
* @ep: pxa physical endpoint
* @req: pxa request
* @status: usb request status sent to gadget API
* @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
*
* Context: ep->lock held
* Context: ep->lock held if flags not NULL, else ep->lock released
*
* Retire a pxa27x usb request. Endpoint must be locked.
*/
static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status)
static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status,
unsigned long *pflags)
{
unsigned long flags;
ep_del_request(ep, req);
if (likely(req->req.status == -EINPROGRESS))
req->req.status = status;
@ -760,38 +764,48 @@ static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status)
&req->req, status,
req->req.actual, req->req.length);
if (pflags)
spin_unlock_irqrestore(&ep->lock, *pflags);
local_irq_save(flags);
req->req.complete(&req->udc_usb_ep->usb_ep, &req->req);
local_irq_restore(flags);
if (pflags)
spin_lock_irqsave(&ep->lock, *pflags);
}
/**
* ep_end_out_req - Ends endpoint OUT request
* @ep: physical endpoint
* @req: pxa request
* @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
*
* Context: ep->lock held
* Context: ep->lock held or released (see req_done())
*
* Ends endpoint OUT request (completes usb request).
*/
static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req,
unsigned long *pflags)
{
inc_ep_stats_reqs(ep, !USB_DIR_IN);
req_done(ep, req, 0);
req_done(ep, req, 0, pflags);
}
/**
* ep0_end_out_req - Ends control endpoint OUT request (ends data stage)
* @ep: physical endpoint
* @req: pxa request
* @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
*
* Context: ep->lock held
* Context: ep->lock held or released (see req_done())
*
* Ends control endpoint OUT request (completes usb request), and puts
* control endpoint into idle state
*/
static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req,
unsigned long *pflags)
{
set_ep0state(ep->dev, OUT_STATUS_STAGE);
ep_end_out_req(ep, req);
ep_end_out_req(ep, req, pflags);
ep0_idle(ep->dev);
}
@ -799,31 +813,35 @@ static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
* ep_end_in_req - Ends endpoint IN request
* @ep: physical endpoint
* @req: pxa request
* @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
*
* Context: ep->lock held
* Context: ep->lock held or released (see req_done())
*
* Ends endpoint IN request (completes usb request).
*/
static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req,
unsigned long *pflags)
{
inc_ep_stats_reqs(ep, USB_DIR_IN);
req_done(ep, req, 0);
req_done(ep, req, 0, pflags);
}
/**
* ep0_end_in_req - Ends control endpoint IN request (ends data stage)
* @ep: physical endpoint
* @req: pxa request
* @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
*
* Context: ep->lock held
* Context: ep->lock held or released (see req_done())
*
* Ends control endpoint IN request (completes usb request), and puts
* control endpoint into status state
*/
static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req,
unsigned long *pflags)
{
set_ep0state(ep->dev, IN_STATUS_STAGE);
ep_end_in_req(ep, req);
ep_end_in_req(ep, req, pflags);
}
/**
@ -831,19 +849,22 @@ static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
* @ep: pxa endpoint
* @status: usb request status
*
* Context: ep->lock held
* Context: ep->lock released
*
* Dequeues all requests on an endpoint. As a side effect, interrupts will be
* disabled on that endpoint (because no more requests).
*/
static void nuke(struct pxa_ep *ep, int status)
{
struct pxa27x_request *req;
struct pxa27x_request *req;
unsigned long flags;
spin_lock_irqsave(&ep->lock, flags);
while (!list_empty(&ep->queue)) {
req = list_entry(ep->queue.next, struct pxa27x_request, queue);
req_done(ep, req, status);
req_done(ep, req, status, &flags);
}
spin_unlock_irqrestore(&ep->lock, flags);
}
/**
@ -1123,6 +1144,7 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
int rc = 0;
int is_first_req;
unsigned length;
int recursion_detected;
req = container_of(_req, struct pxa27x_request, req);
udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
@ -1152,6 +1174,7 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
return -EMSGSIZE;
spin_lock_irqsave(&ep->lock, flags);
recursion_detected = ep->in_handle_ep;
is_first_req = list_empty(&ep->queue);
ep_dbg(ep, "queue req %p(first=%s), len %d buf %p\n",
@ -1161,12 +1184,12 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
if (!ep->enabled) {
_req->status = -ESHUTDOWN;
rc = -ESHUTDOWN;
goto out;
goto out_locked;
}
if (req->in_use) {
ep_err(ep, "refusing to queue req %p (already queued)\n", req);
goto out;
goto out_locked;
}
length = _req->length;
@ -1174,12 +1197,13 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
_req->actual = 0;
ep_add_request(ep, req);
spin_unlock_irqrestore(&ep->lock, flags);
if (is_ep0(ep)) {
switch (dev->ep0state) {
case WAIT_ACK_SET_CONF_INTERF:
if (length == 0) {
ep_end_in_req(ep, req);
ep_end_in_req(ep, req, NULL);
} else {
ep_err(ep, "got a request of %d bytes while"
"in state WAIT_ACK_SET_CONF_INTERF\n",
@ -1192,12 +1216,12 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
case IN_DATA_STAGE:
if (!ep_is_full(ep))
if (write_ep0_fifo(ep, req))
ep0_end_in_req(ep, req);
ep0_end_in_req(ep, req, NULL);
break;
case OUT_DATA_STAGE:
if ((length == 0) || !epout_has_pkt(ep))
if (read_ep0_fifo(ep, req))
ep0_end_out_req(ep, req);
ep0_end_out_req(ep, req, NULL);
break;
default:
ep_err(ep, "odd state %s to send me a request\n",
@ -1207,12 +1231,15 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
break;
}
} else {
handle_ep(ep);
if (!recursion_detected)
handle_ep(ep);
}
out:
spin_unlock_irqrestore(&ep->lock, flags);
return rc;
out_locked:
spin_unlock_irqrestore(&ep->lock, flags);
goto out;
}
/**
@ -1242,13 +1269,14 @@ static int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
/* make sure it's actually queued on this endpoint */
list_for_each_entry(req, &ep->queue, queue) {
if (&req->req == _req) {
req_done(ep, req, -ECONNRESET);
rc = 0;
break;
}
}
spin_unlock_irqrestore(&ep->lock, flags);
if (!rc)
req_done(ep, req, -ECONNRESET, NULL);
return rc;
}
@ -1445,7 +1473,6 @@ static int pxa_ep_disable(struct usb_ep *_ep)
{
struct pxa_ep *ep;
struct udc_usb_ep *udc_usb_ep;
unsigned long flags;
if (!_ep)
return -EINVAL;
@ -1455,10 +1482,8 @@ static int pxa_ep_disable(struct usb_ep *_ep)
if (!ep || is_ep0(ep) || !list_empty(&ep->queue))
return -EINVAL;
spin_lock_irqsave(&ep->lock, flags);
ep->enabled = 0;
nuke(ep, -ESHUTDOWN);
spin_unlock_irqrestore(&ep->lock, flags);
pxa_ep_fifo_flush(_ep);
udc_usb_ep->pxa_ep = NULL;
@ -1907,8 +1932,10 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc,
} u;
int i;
int have_extrabytes = 0;
unsigned long flags;
nuke(ep, -EPROTO);
spin_lock_irqsave(&ep->lock, flags);
/*
* In the PXA320 manual, in the section about Back-to-Back setup
@ -1947,10 +1974,13 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc,
/* Tell UDC to enter Data Stage */
ep_write_UDCCSR(ep, UDCCSR0_SA | UDCCSR0_OPC);
spin_unlock_irqrestore(&ep->lock, flags);
i = udc->driver->setup(&udc->gadget, &u.r);
spin_lock_irqsave(&ep->lock, flags);
if (i < 0)
goto stall;
out:
spin_unlock_irqrestore(&ep->lock, flags);
return;
stall:
ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n",
@ -2055,13 +2085,13 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
if (req && !ep_is_full(ep))
completed = write_ep0_fifo(ep, req);
if (completed)
ep0_end_in_req(ep, req);
ep0_end_in_req(ep, req, NULL);
break;
case OUT_DATA_STAGE: /* SET_DESCRIPTOR */
if (epout_has_pkt(ep) && req)
completed = read_ep0_fifo(ep, req);
if (completed)
ep0_end_out_req(ep, req);
ep0_end_out_req(ep, req, NULL);
break;
case STALL:
ep_write_UDCCSR(ep, UDCCSR0_FST);
@ -2091,7 +2121,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
* Tries to transfer all pending request data into the endpoint and/or
* transfer all pending data in the endpoint into usb requests.
*
* Is always called when in_interrupt() or with ep->lock held.
* Is always called when in_interrupt() and with ep->lock released.
*/
static void handle_ep(struct pxa_ep *ep)
{
@ -2100,10 +2130,17 @@ static void handle_ep(struct pxa_ep *ep)
u32 udccsr;
int is_in = ep->dir_in;
int loop = 0;
unsigned long flags;
spin_lock_irqsave(&ep->lock, flags);
if (ep->in_handle_ep)
goto recursion_detected;
ep->in_handle_ep = 1;
do {
completed = 0;
udccsr = udc_ep_readl(ep, UDCCSR);
if (likely(!list_empty(&ep->queue)))
req = list_entry(ep->queue.next,
struct pxa27x_request, queue);
@ -2122,15 +2159,22 @@ static void handle_ep(struct pxa_ep *ep)
if (unlikely(is_in)) {
if (likely(!ep_is_full(ep)))
completed = write_fifo(ep, req);
if (completed)
ep_end_in_req(ep, req);
} else {
if (likely(epout_has_pkt(ep)))
completed = read_fifo(ep, req);
if (completed)
ep_end_out_req(ep, req);
}
if (completed) {
if (is_in)
ep_end_in_req(ep, req, &flags);
else
ep_end_out_req(ep, req, &flags);
}
} while (completed);
ep->in_handle_ep = 0;
recursion_detected:
spin_unlock_irqrestore(&ep->lock, flags);
}
/**
@ -2218,9 +2262,13 @@ static void irq_handle_data(int irq, struct pxa_udc *udc)
continue;
udc_writel(udc, UDCISR0, UDCISR_INT(i, UDCISR_INT_MASK));
ep = &udc->pxa_ep[i];
ep->stats.irqs++;
handle_ep(ep);
WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep));
if (i < ARRAY_SIZE(udc->pxa_ep)) {
ep = &udc->pxa_ep[i];
ep->stats.irqs++;
handle_ep(ep);
}
}
for (i = 16; udcisr1 != 0 && i < 24; udcisr1 >>= 2, i++) {
@ -2228,9 +2276,12 @@ static void irq_handle_data(int irq, struct pxa_udc *udc)
if (!(udcisr1 & UDCISR_INT_MASK))
continue;
ep = &udc->pxa_ep[i];
ep->stats.irqs++;
handle_ep(ep);
WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep));
if (i < ARRAY_SIZE(udc->pxa_ep)) {
ep = &udc->pxa_ep[i];
ep->stats.irqs++;
handle_ep(ep);
}
}
}
@ -2439,7 +2490,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
}
retval = -ENOMEM;
udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
udc->regs = ioremap(regs->start, resource_size(regs));
if (!udc->regs) {
dev_err(&pdev->dev, "Unable to map UDC I/O memory\n");
goto err_map;

View File

@ -318,6 +318,11 @@ struct udc_usb_ep {
* @queue: requests queue
* @lock: lock to pxa_ep data (queues and stats)
* @enabled: true when endpoint enabled (not stopped by gadget layer)
* @in_handle_ep: number of recursions of handle_ep() function
* Prevents deadlocks or infinite recursions of types :
* irq->handle_ep()->req_done()->req.complete()->pxa_ep_queue()->handle_ep()
* or
* pxa_ep_queue()->handle_ep()->req_done()->req.complete()->pxa_ep_queue()
* @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX)
* @name: endpoint name (for trace/debug purpose)
* @dir_in: 1 if IN endpoint, 0 if OUT endpoint
@ -346,6 +351,7 @@ struct pxa_ep {
spinlock_t lock; /* Protects this structure */
/* (queues, stats) */
unsigned enabled:1;
unsigned in_handle_ep:1;
unsigned idx:5;
char *name;

View File

@ -317,7 +317,8 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
*
* Allocate a new USB request structure appropriate for the specified endpoint
*/
struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, gfp_t flags)
static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep,
gfp_t flags)
{
struct s3c_hsotg_req *req;
@ -373,7 +374,7 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
req->dma = DMA_ADDR_INVALID;
hs_req->mapped = 0;
} else {
dma_sync_single(hsotg->dev, req->dma, req->length, dir);
dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
}
}
@ -755,7 +756,7 @@ static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg,
hs_req->mapped = 1;
req->dma = dma;
} else {
dma_sync_single(hsotg->dev, req->dma, req->length, dir);
dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
hs_req->mapped = 0;
}
@ -1460,7 +1461,7 @@ static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg)
* as the actual data should be sent to the memory directly and we turn
* on the completion interrupts to get notifications of transfer completion.
*/
void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
{
u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP);
u32 epnum, status, size;
@ -3094,7 +3095,7 @@ static void s3c_hsotg_gate(struct platform_device *pdev, bool on)
local_irq_restore(flags);
}
struct s3c_hsotg_plat s3c_hsotg_default_pdata;
static struct s3c_hsotg_plat s3c_hsotg_default_pdata;
static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
{

View File

@ -746,6 +746,10 @@ static const struct net_device_ops eth_netdev_ops = {
.ndo_validate_addr = eth_validate_addr,
};
static struct device_type gadget_type = {
.name = "gadget",
};
/**
* gether_setup - initialize one ethernet-over-usb link
* @g: gadget to associated with these links
@ -808,6 +812,7 @@ int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
dev->gadget = g;
SET_NETDEV_DEV(net, &g->dev);
SET_NETDEV_DEVTYPE(net, &gadget_type);
status = register_netdev(net);
if (status < 0) {

View File

@ -93,13 +93,6 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
if (!gadget_supports_altsettings(gadget))
return false;
/* SA1100 can do ECM, *without* status endpoint ... but we'll
* only use it in non-ECM mode for backwards compatibility
* (and since we currently require a status endpoint)
*/
if (gadget_is_sa1100(gadget))
return false;
/* Everything else is *presumably* fine ... but this is a bit
* chancy, so be **CERTAIN** there are no hardware issues with
* your controller. Add it above if it can't handle CDC.

View File

@ -297,12 +297,10 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
*/
if (loopdefault) {
loopback_add(cdev, autoresume != 0);
if (!gadget_is_sh(gadget))
sourcesink_add(cdev, autoresume != 0);
sourcesink_add(cdev, autoresume != 0);
} else {
sourcesink_add(cdev, autoresume != 0);
if (!gadget_is_sh(gadget))
loopback_add(cdev, autoresume != 0);
loopback_add(cdev, autoresume != 0);
}
gcnum = usb_gadget_controller_number(gadget);

View File

@ -399,3 +399,14 @@ config USB_HWA_HCD
To compile this driver a module, choose M here: the module
will be called "hwa-hc".
config USB_IMX21_HCD
tristate "iMX21 HCD support"
depends on USB && ARM && MACH_MX21
help
This driver enables support for the on-chip USB host in the
iMX21 processor.
To compile this driver as a module, choose M here: the
module will be called "imx21-hcd".

View File

@ -32,3 +32,5 @@ obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o

View File

@ -149,7 +149,7 @@ static int __init ehci_atmel_drv_probe(struct platform_device *pdev)
goto fail_request_resource;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = res->end - res->start + 1;
hcd->rsrc_len = resource_size(res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
driver->description)) {

View File

@ -121,6 +121,7 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
struct resource *res;
int ret;
if (usb_disabled())
@ -144,8 +145,9 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
if (!hcd)
return -ENOMEM;
hcd->rsrc_start = pdev->resource[0].start;
hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
pr_debug("request_mem_region failed");

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2005 MontaVista Software
* Copyright 2005-2009 MontaVista Software, Inc.
* Copyright 2008 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@ -17,17 +18,20 @@
*
* Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided
* by Hunter Wu.
* Power Management support by Dave Liu <daveliu@freescale.com>,
* Jerry Huang <Chang-Ming.Huang@freescale.com> and
* Anton Vorontsov <avorontsov@ru.mvista.com>.
*/
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include "ehci-fsl.h"
/* FIXME: Power Management is un-ported so temporarily disable it */
#undef CONFIG_PM
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
@ -40,8 +44,8 @@
* Allocates basic resources for this USB host controller.
*
*/
int usb_hcd_fsl_probe(const struct hc_driver *driver,
struct platform_device *pdev)
static int usb_hcd_fsl_probe(const struct hc_driver *driver,
struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata;
struct usb_hcd *hcd;
@ -147,7 +151,8 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
* Reverses the effect of usb_hcd_fsl_probe().
*
*/
void usb_hcd_fsl_remove(struct usb_hcd *hcd, struct platform_device *pdev)
static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
struct platform_device *pdev)
{
usb_remove_hcd(hcd);
iounmap(hcd->regs);
@ -284,10 +289,81 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
return retval;
}
struct ehci_fsl {
struct ehci_hcd ehci;
#ifdef CONFIG_PM
/* Saved USB PHY settings, need to restore after deep sleep. */
u32 usb_ctrl;
#endif
};
#ifdef CONFIG_PM
static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
return container_of(ehci, struct ehci_fsl, ehci);
}
static int ehci_fsl_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
void __iomem *non_ehci = hcd->regs;
if (!fsl_deep_sleep())
return 0;
ehci_fsl->usb_ctrl = in_be32(non_ehci + FSL_SOC_USB_CTRL);
return 0;
}
static int ehci_fsl_drv_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
void __iomem *non_ehci = hcd->regs;
if (!fsl_deep_sleep())
return 0;
usb_root_hub_lost_power(hcd->self.root_hub);
/* Restore USB PHY settings and enable the controller. */
out_be32(non_ehci + FSL_SOC_USB_CTRL, ehci_fsl->usb_ctrl);
ehci_reset(ehci);
ehci_fsl_reinit(ehci);
return 0;
}
static int ehci_fsl_drv_restore(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
usb_root_hub_lost_power(hcd->self.root_hub);
return 0;
}
static struct dev_pm_ops ehci_fsl_pm_ops = {
.suspend = ehci_fsl_drv_suspend,
.resume = ehci_fsl_drv_resume,
.restore = ehci_fsl_drv_restore,
};
#define EHCI_FSL_PM_OPS (&ehci_fsl_pm_ops)
#else
#define EHCI_FSL_PM_OPS NULL
#endif /* CONFIG_PM */
static const struct hc_driver ehci_fsl_hc_driver = {
.description = hcd_name,
.product_desc = "Freescale On-Chip EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
.hcd_priv_size = sizeof(struct ehci_fsl),
/*
* generic hardware linkage
@ -354,6 +430,7 @@ static struct platform_driver ehci_fsl_driver = {
.remove = ehci_fsl_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "fsl-ehci",
.name = "fsl-ehci",
.pm = EHCI_FSL_PM_OPS,
},
};

View File

@ -162,6 +162,17 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
goto err_ioremap;
}
/* call platform specific init function */
if (pdata->init) {
ret = pdata->init(pdev);
if (ret) {
dev_err(dev, "platform init failed\n");
goto err_init;
}
/* platforms need some time to settle changed IO settings */
mdelay(10);
}
/* enable clocks */
priv->usbclk = clk_get(dev, "usb");
if (IS_ERR(priv->usbclk)) {
@ -192,18 +203,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
if (ret < 0)
goto err_init;
/* call platform specific init function */
if (pdata->init) {
ret = pdata->init(pdev);
if (ret) {
dev_err(dev, "platform init failed\n");
goto err_init;
}
}
/* most platforms need some time to settle changed IO settings */
mdelay(10);
/* Initialize the transceiver */
if (pdata->otg) {
pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;

View File

@ -26,10 +26,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* TODO (last updated Feb 23rd, 2009):
* TODO (last updated Feb 12, 2010):
* - add kernel-doc
* - enable AUTOIDLE
* - move DPLL5 programming to clock fw
* - add suspend/resume
* - move workarounds to board-files
*/
@ -37,6 +36,7 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <plat/usb.h>
/*
@ -178,6 +178,11 @@ struct ehci_hcd_omap {
void __iomem *uhh_base;
void __iomem *tll_base;
void __iomem *ehci_base;
/* Regulators for USB PHYs.
* Each PHY can have a seperate regulator.
*/
struct regulator *regulator[OMAP3_HS_USB_PORTS];
};
/*-------------------------------------------------------------------------*/
@ -546,6 +551,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
int irq = platform_get_irq(pdev, 0);
int ret = -ENODEV;
int i;
char supply[7];
if (!pdata) {
dev_dbg(&pdev->dev, "missing platform_data\n");
@ -613,6 +620,21 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
goto err_tll_ioremap;
}
/* get ehci regulator and enable */
for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
if (omap->port_mode[i] != EHCI_HCD_OMAP_MODE_PHY) {
omap->regulator[i] = NULL;
continue;
}
snprintf(supply, sizeof(supply), "hsusb%d", i);
omap->regulator[i] = regulator_get(omap->dev, supply);
if (IS_ERR(omap->regulator[i]))
dev_dbg(&pdev->dev,
"failed to get ehci port%d regulator\n", i);
else
regulator_enable(omap->regulator[i]);
}
ret = omap_start_ehc(omap, hcd);
if (ret) {
dev_dbg(&pdev->dev, "failed to start ehci\n");
@ -622,13 +644,12 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
omap->ehci->regs = hcd->regs
+ HC_LENGTH(readl(&omap->ehci->caps->hc_capbase));
dbg_hcs_params(omap->ehci, "reset");
dbg_hcc_params(omap->ehci, "reset");
/* cache this readonly data; minimize chip reads */
omap->ehci->hcs_params = readl(&omap->ehci->caps->hcs_params);
/* SET 1 micro-frame Interrupt interval */
writel(readl(&omap->ehci->regs->command) | (1 << 16),
&omap->ehci->regs->command);
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
if (ret) {
dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
@ -641,6 +662,12 @@ err_add_hcd:
omap_stop_ehc(omap, hcd);
err_start:
for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
if (omap->regulator[i]) {
regulator_disable(omap->regulator[i]);
regulator_put(omap->regulator[i]);
}
}
iounmap(omap->tll_base);
err_tll_ioremap:
@ -674,13 +701,21 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
{
struct ehci_hcd_omap *omap = platform_get_drvdata(pdev);
struct usb_hcd *hcd = ehci_to_hcd(omap->ehci);
int i;
usb_remove_hcd(hcd);
omap_stop_ehc(omap, hcd);
iounmap(hcd->regs);
for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
if (omap->regulator[i]) {
regulator_disable(omap->regulator[i]);
regulator_put(omap->regulator[i]);
}
}
iounmap(omap->tll_base);
iounmap(omap->uhh_base);
usb_put_hcd(hcd);
kfree(omap);
return 0;
}

View File

@ -222,14 +222,14 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
goto err1;
}
if (!request_mem_region(res->start, res->end - res->start + 1,
if (!request_mem_region(res->start, resource_size(res),
ehci_orion_hc_driver.description)) {
dev_dbg(&pdev->dev, "controller already in use\n");
err = -EBUSY;
goto err1;
}
regs = ioremap(res->start, res->end - res->start + 1);
regs = ioremap(res->start, resource_size(res));
if (regs == NULL) {
dev_dbg(&pdev->dev, "error mapping memory\n");
err = -EFAULT;
@ -244,7 +244,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = res->end - res->start + 1;
hcd->rsrc_len = resource_size(res);
hcd->regs = regs;
ehci = hcd_to_ehci(hcd);
@ -287,7 +287,7 @@ err4:
err3:
iounmap(regs);
err2:
release_mem_region(res->start, res->end - res->start + 1);
release_mem_region(res->start, resource_size(res));
err1:
dev_err(&pdev->dev, "init %s fail, %d\n",
dev_name(&pdev->dev), err);

View File

@ -134,21 +134,21 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
hcd->rsrc_len = res.end - res.start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
rv = -EBUSY;
goto err_rmr;
}
irq = irq_of_parse_and_map(dn, 0);
if (irq == NO_IRQ) {
printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
rv = -EBUSY;
goto err_irq;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
printk(KERN_ERR __FILE__ ": ioremap failed\n");
printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
rv = -ENOMEM;
goto err_ioremap;
}
@ -161,9 +161,9 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
ehci->ohci_hcctrl_reg = ioremap(res.start +
OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN);
else
pr_debug(__FILE__ ": no ohci offset in fdt\n");
pr_debug("%s: no ohci offset in fdt\n", __FILE__);
if (!ehci->ohci_hcctrl_reg) {
pr_debug(__FILE__ ": ioremap for ohci hcctrl failed\n");
pr_debug("%s: ioremap for ohci hcctrl failed\n", __FILE__);
} else {
ehci->has_amcc_usb23 = 1;
}
@ -241,7 +241,7 @@ static int ehci_hcd_ppc_of_remove(struct of_device *op)
else
release_mem_region(res.start, 0x4);
else
pr_debug(__FILE__ ": no ohci offset in fdt\n");
pr_debug("%s: no ohci offset in fdt\n", __FILE__);
of_node_put(np);
}
@ -264,7 +264,7 @@ static int ehci_hcd_ppc_of_shutdown(struct of_device *op)
}
static struct of_device_id ehci_hcd_ppc_of_match[] = {
static const struct of_device_id ehci_hcd_ppc_of_match[] = {
{
.compatible = "usb-ehci",
},

View File

@ -510,6 +510,8 @@ static int disable_periodic (struct ehci_hcd *ehci)
ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... */
free_cached_itd_list(ehci);
ehci->next_uframe = -1;
return 0;
}
@ -2322,9 +2324,13 @@ restart:
* No need to check for activity unless the
* frame is current.
*/
if (frame == clock_frame && live &&
(q.sitd->hw_results &
SITD_ACTIVE(ehci))) {
if (((frame == clock_frame) ||
(((frame + 1) % ehci->periodic_size)
== clock_frame))
&& live
&& (q.sitd->hw_results &
SITD_ACTIVE(ehci))) {
incomplete = true;
q_p = &q.sitd->sitd_next;
hw_p = &q.sitd->hw_next;

View File

@ -177,21 +177,21 @@ ehci_hcd_xilinx_of_probe(struct of_device *op, const struct of_device_id *match)
hcd->rsrc_len = res.end - res.start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
rv = -EBUSY;
goto err_rmr;
}
irq = irq_of_parse_and_map(dn, 0);
if (irq == NO_IRQ) {
printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
rv = -EBUSY;
goto err_irq;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
printk(KERN_ERR __FILE__ ": ioremap failed\n");
printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
rv = -ENOMEM;
goto err_ioremap;
}
@ -281,7 +281,7 @@ static int ehci_hcd_xilinx_of_shutdown(struct of_device *op)
}
static struct of_device_id ehci_hcd_xilinx_of_match[] = {
static const struct of_device_id ehci_hcd_xilinx_of_match[] = {
{.compatible = "xlnx,xps-usb-host-1.00.a",},
{},
};

View File

@ -433,7 +433,7 @@ static int fhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
return -ENOMEM;
/* allocate the private part of the URB */
urb_priv->tds = kzalloc(size * sizeof(struct td), mem_flags);
urb_priv->tds = kcalloc(size, sizeof(*urb_priv->tds), mem_flags);
if (!urb_priv->tds) {
kfree(urb_priv);
return -ENOMEM;
@ -805,7 +805,7 @@ static int __devexit of_fhci_remove(struct of_device *ofdev)
return fhci_remove(&ofdev->dev);
}
static struct of_device_id of_fhci_match[] = {
static const struct of_device_id of_fhci_match[] = {
{ .compatible = "fsl,mpc8323-qe-usb", },
{},
};

View File

@ -0,0 +1,527 @@
/*
* Copyright (c) 2009 by Martin Fuzzey
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* this file is part of imx21-hcd.c */
#ifndef DEBUG
static inline void create_debug_files(struct imx21 *imx21) { }
static inline void remove_debug_files(struct imx21 *imx21) { }
static inline void debug_urb_submitted(struct imx21 *imx21, struct urb *urb) {}
static inline void debug_urb_completed(struct imx21 *imx21, struct urb *urb,
int status) {}
static inline void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb) {}
static inline void debug_urb_queued_for_etd(struct imx21 *imx21,
struct urb *urb) {}
static inline void debug_urb_queued_for_dmem(struct imx21 *imx21,
struct urb *urb) {}
static inline void debug_etd_allocated(struct imx21 *imx21) {}
static inline void debug_etd_freed(struct imx21 *imx21) {}
static inline void debug_dmem_allocated(struct imx21 *imx21, int size) {}
static inline void debug_dmem_freed(struct imx21 *imx21, int size) {}
static inline void debug_isoc_submitted(struct imx21 *imx21,
int frame, struct td *td) {}
static inline void debug_isoc_completed(struct imx21 *imx21,
int frame, struct td *td, int cc, int len) {}
#else
#include <linux/debugfs.h>
#include <linux/seq_file.h>
static const char *dir_labels[] = {
"TD 0",
"OUT",
"IN",
"TD 1"
};
static const char *speed_labels[] = {
"Full",
"Low"
};
static const char *format_labels[] = {
"Control",
"ISO",
"Bulk",
"Interrupt"
};
static inline struct debug_stats *stats_for_urb(struct imx21 *imx21,
struct urb *urb)
{
return usb_pipeisoc(urb->pipe) ?
&imx21->isoc_stats : &imx21->nonisoc_stats;
}
static void debug_urb_submitted(struct imx21 *imx21, struct urb *urb)
{
stats_for_urb(imx21, urb)->submitted++;
}
static void debug_urb_completed(struct imx21 *imx21, struct urb *urb, int st)
{
if (st)
stats_for_urb(imx21, urb)->completed_failed++;
else
stats_for_urb(imx21, urb)->completed_ok++;
}
static void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb)
{
stats_for_urb(imx21, urb)->unlinked++;
}
static void debug_urb_queued_for_etd(struct imx21 *imx21, struct urb *urb)
{
stats_for_urb(imx21, urb)->queue_etd++;
}
static void debug_urb_queued_for_dmem(struct imx21 *imx21, struct urb *urb)
{
stats_for_urb(imx21, urb)->queue_dmem++;
}
static inline void debug_etd_allocated(struct imx21 *imx21)
{
imx21->etd_usage.maximum = max(
++(imx21->etd_usage.value),
imx21->etd_usage.maximum);
}
static inline void debug_etd_freed(struct imx21 *imx21)
{
imx21->etd_usage.value--;
}
static inline void debug_dmem_allocated(struct imx21 *imx21, int size)
{
imx21->dmem_usage.value += size;
imx21->dmem_usage.maximum = max(
imx21->dmem_usage.value,
imx21->dmem_usage.maximum);
}
static inline void debug_dmem_freed(struct imx21 *imx21, int size)
{
imx21->dmem_usage.value -= size;
}
static void debug_isoc_submitted(struct imx21 *imx21,
int frame, struct td *td)
{
struct debug_isoc_trace *trace = &imx21->isoc_trace[
imx21->isoc_trace_index++];
imx21->isoc_trace_index %= ARRAY_SIZE(imx21->isoc_trace);
trace->schedule_frame = td->frame;
trace->submit_frame = frame;
trace->request_len = td->len;
trace->td = td;
}
static inline void debug_isoc_completed(struct imx21 *imx21,
int frame, struct td *td, int cc, int len)
{
struct debug_isoc_trace *trace, *trace_failed;
int i;
int found = 0;
trace = imx21->isoc_trace;
for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++) {
if (trace->td == td) {
trace->done_frame = frame;
trace->done_len = len;
trace->cc = cc;
trace->td = NULL;
found = 1;
break;
}
}
if (found && cc) {
trace_failed = &imx21->isoc_trace_failed[
imx21->isoc_trace_index_failed++];
imx21->isoc_trace_index_failed %= ARRAY_SIZE(
imx21->isoc_trace_failed);
*trace_failed = *trace;
}
}
static char *format_ep(struct usb_host_endpoint *ep, char *buf, int bufsize)
{
if (ep)
snprintf(buf, bufsize, "ep_%02x (type:%02X kaddr:%p)",
ep->desc.bEndpointAddress,
usb_endpoint_type(&ep->desc),
ep);
else
snprintf(buf, bufsize, "none");
return buf;
}
static char *format_etd_dword0(u32 value, char *buf, int bufsize)
{
snprintf(buf, bufsize,
"addr=%d ep=%d dir=%s speed=%s format=%s halted=%d",
value & 0x7F,
(value >> DW0_ENDPNT) & 0x0F,
dir_labels[(value >> DW0_DIRECT) & 0x03],
speed_labels[(value >> DW0_SPEED) & 0x01],
format_labels[(value >> DW0_FORMAT) & 0x03],
(value >> DW0_HALTED) & 0x01);
return buf;
}
static int debug_status_show(struct seq_file *s, void *v)
{
struct imx21 *imx21 = s->private;
int etds_allocated = 0;
int etds_sw_busy = 0;
int etds_hw_busy = 0;
int dmem_blocks = 0;
int queued_for_etd = 0;
int queued_for_dmem = 0;
unsigned int dmem_bytes = 0;
int i;
struct etd_priv *etd;
u32 etd_enable_mask;
unsigned long flags;
struct imx21_dmem_area *dmem;
struct ep_priv *ep_priv;
spin_lock_irqsave(&imx21->lock, flags);
etd_enable_mask = readl(imx21->regs + USBH_ETDENSET);
for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) {
if (etd->alloc)
etds_allocated++;
if (etd->urb)
etds_sw_busy++;
if (etd_enable_mask & (1<<i))
etds_hw_busy++;
}
list_for_each_entry(dmem, &imx21->dmem_list, list) {
dmem_bytes += dmem->size;
dmem_blocks++;
}
list_for_each_entry(ep_priv, &imx21->queue_for_etd, queue)
queued_for_etd++;
list_for_each_entry(etd, &imx21->queue_for_dmem, queue)
queued_for_dmem++;
spin_unlock_irqrestore(&imx21->lock, flags);
seq_printf(s,
"Frame: %d\n"
"ETDs allocated: %d/%d (max=%d)\n"
"ETDs in use sw: %d\n"
"ETDs in use hw: %d\n"
"DMEM alocated: %d/%d (max=%d)\n"
"DMEM blocks: %d\n"
"Queued waiting for ETD: %d\n"
"Queued waiting for DMEM: %d\n",
readl(imx21->regs + USBH_FRMNUB) & 0xFFFF,
etds_allocated, USB_NUM_ETD, imx21->etd_usage.maximum,
etds_sw_busy,
etds_hw_busy,
dmem_bytes, DMEM_SIZE, imx21->dmem_usage.maximum,
dmem_blocks,
queued_for_etd,
queued_for_dmem);
return 0;
}
static int debug_dmem_show(struct seq_file *s, void *v)
{
struct imx21 *imx21 = s->private;
struct imx21_dmem_area *dmem;
unsigned long flags;
char ep_text[40];
spin_lock_irqsave(&imx21->lock, flags);
list_for_each_entry(dmem, &imx21->dmem_list, list)
seq_printf(s,
"%04X: size=0x%X "
"ep=%s\n",
dmem->offset, dmem->size,
format_ep(dmem->ep, ep_text, sizeof(ep_text)));
spin_unlock_irqrestore(&imx21->lock, flags);
return 0;
}
static int debug_etd_show(struct seq_file *s, void *v)
{
struct imx21 *imx21 = s->private;
struct etd_priv *etd;
char buf[60];
u32 dword;
int i, j;
unsigned long flags;
spin_lock_irqsave(&imx21->lock, flags);
for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) {
int state = -1;
struct urb_priv *urb_priv;
if (etd->urb) {
urb_priv = etd->urb->hcpriv;
if (urb_priv)
state = urb_priv->state;
}
seq_printf(s,
"etd_num: %d\n"
"ep: %s\n"
"alloc: %d\n"
"len: %d\n"
"busy sw: %d\n"
"busy hw: %d\n"
"urb state: %d\n"
"current urb: %p\n",
i,
format_ep(etd->ep, buf, sizeof(buf)),
etd->alloc,
etd->len,
etd->urb != NULL,
(readl(imx21->regs + USBH_ETDENSET) & (1 << i)) > 0,
state,
etd->urb);
for (j = 0; j < 4; j++) {
dword = etd_readl(imx21, i, j);
switch (j) {
case 0:
format_etd_dword0(dword, buf, sizeof(buf));
break;
case 2:
snprintf(buf, sizeof(buf),
"cc=0X%02X", dword >> DW2_COMPCODE);
break;
default:
*buf = 0;
break;
}
seq_printf(s,
"dword %d: submitted=%08X cur=%08X [%s]\n",
j,
etd->submitted_dwords[j],
dword,
buf);
}
seq_printf(s, "\n");
}
spin_unlock_irqrestore(&imx21->lock, flags);
return 0;
}
static void debug_statistics_show_one(struct seq_file *s,
const char *name, struct debug_stats *stats)
{
seq_printf(s, "%s:\n"
"submitted URBs: %lu\n"
"completed OK: %lu\n"
"completed failed: %lu\n"
"unlinked: %lu\n"
"queued for ETD: %lu\n"
"queued for DMEM: %lu\n\n",
name,
stats->submitted,
stats->completed_ok,
stats->completed_failed,
stats->unlinked,
stats->queue_etd,
stats->queue_dmem);
}
static int debug_statistics_show(struct seq_file *s, void *v)
{
struct imx21 *imx21 = s->private;
unsigned long flags;
spin_lock_irqsave(&imx21->lock, flags);
debug_statistics_show_one(s, "nonisoc", &imx21->nonisoc_stats);
debug_statistics_show_one(s, "isoc", &imx21->isoc_stats);
seq_printf(s, "unblock kludge triggers: %lu\n", imx21->debug_unblocks);
spin_unlock_irqrestore(&imx21->lock, flags);
return 0;
}
static void debug_isoc_show_one(struct seq_file *s,
const char *name, int index, struct debug_isoc_trace *trace)
{
seq_printf(s, "%s %d:\n"
"cc=0X%02X\n"
"scheduled frame %d (%d)\n"
"submittted frame %d (%d)\n"
"completed frame %d (%d)\n"
"requested length=%d\n"
"completed length=%d\n\n",
name, index,
trace->cc,
trace->schedule_frame, trace->schedule_frame & 0xFFFF,
trace->submit_frame, trace->submit_frame & 0xFFFF,
trace->done_frame, trace->done_frame & 0xFFFF,
trace->request_len,
trace->done_len);
}
static int debug_isoc_show(struct seq_file *s, void *v)
{
struct imx21 *imx21 = s->private;
struct debug_isoc_trace *trace;
unsigned long flags;
int i;
spin_lock_irqsave(&imx21->lock, flags);
trace = imx21->isoc_trace_failed;
for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace_failed); i++, trace++)
debug_isoc_show_one(s, "isoc failed", i, trace);
trace = imx21->isoc_trace;
for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++)
debug_isoc_show_one(s, "isoc", i, trace);
spin_unlock_irqrestore(&imx21->lock, flags);
return 0;
}
static int debug_status_open(struct inode *inode, struct file *file)
{
return single_open(file, debug_status_show, inode->i_private);
}
static int debug_dmem_open(struct inode *inode, struct file *file)
{
return single_open(file, debug_dmem_show, inode->i_private);
}
static int debug_etd_open(struct inode *inode, struct file *file)
{
return single_open(file, debug_etd_show, inode->i_private);
}
static int debug_statistics_open(struct inode *inode, struct file *file)
{
return single_open(file, debug_statistics_show, inode->i_private);
}
static int debug_isoc_open(struct inode *inode, struct file *file)
{
return single_open(file, debug_isoc_show, inode->i_private);
}
static const struct file_operations debug_status_fops = {
.open = debug_status_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static const struct file_operations debug_dmem_fops = {
.open = debug_dmem_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static const struct file_operations debug_etd_fops = {
.open = debug_etd_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static const struct file_operations debug_statistics_fops = {
.open = debug_statistics_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static const struct file_operations debug_isoc_fops = {
.open = debug_isoc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static void create_debug_files(struct imx21 *imx21)
{
imx21->debug_root = debugfs_create_dir(dev_name(imx21->dev), NULL);
if (!imx21->debug_root)
goto failed_create_rootdir;
if (!debugfs_create_file("status", S_IRUGO,
imx21->debug_root, imx21, &debug_status_fops))
goto failed_create;
if (!debugfs_create_file("dmem", S_IRUGO,
imx21->debug_root, imx21, &debug_dmem_fops))
goto failed_create;
if (!debugfs_create_file("etd", S_IRUGO,
imx21->debug_root, imx21, &debug_etd_fops))
goto failed_create;
if (!debugfs_create_file("statistics", S_IRUGO,
imx21->debug_root, imx21, &debug_statistics_fops))
goto failed_create;
if (!debugfs_create_file("isoc", S_IRUGO,
imx21->debug_root, imx21, &debug_isoc_fops))
goto failed_create;
return;
failed_create:
debugfs_remove_recursive(imx21->debug_root);
failed_create_rootdir:
imx21->debug_root = NULL;
}
static void remove_debug_files(struct imx21 *imx21)
{
if (imx21->debug_root) {
debugfs_remove_recursive(imx21->debug_root);
imx21->debug_root = NULL;
}
}
#endif

1789
drivers/usb/host/imx21-hcd.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,436 @@
/*
* Macros and prototypes for i.MX21
*
* Copyright (C) 2006 Loping Dog Embedded Systems
* Copyright (C) 2009 Martin Fuzzey
* Originally written by Jay Monkman <jtm@lopingdog.com>
* Ported to 2.6.30, debugged and enhanced by Martin Fuzzey
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __LINUX_IMX21_HCD_H__
#define __LINUX_IMX21_HCD_H__
#include <mach/mx21-usbhost.h>
#define NUM_ISO_ETDS 2
#define USB_NUM_ETD 32
#define DMEM_SIZE 4096
/* Register definitions */
#define USBOTG_HWMODE 0x00
#define USBOTG_HWMODE_ANASDBEN (1 << 14)
#define USBOTG_HWMODE_OTGXCVR_SHIFT 6
#define USBOTG_HWMODE_OTGXCVR_MASK (3 << 6)
#define USBOTG_HWMODE_OTGXCVR_TD_RD (0 << 6)
#define USBOTG_HWMODE_OTGXCVR_TS_RD (2 << 6)
#define USBOTG_HWMODE_OTGXCVR_TD_RS (1 << 6)
#define USBOTG_HWMODE_OTGXCVR_TS_RS (3 << 6)
#define USBOTG_HWMODE_HOSTXCVR_SHIFT 4
#define USBOTG_HWMODE_HOSTXCVR_MASK (3 << 4)
#define USBOTG_HWMODE_HOSTXCVR_TD_RD (0 << 4)
#define USBOTG_HWMODE_HOSTXCVR_TS_RD (2 << 4)
#define USBOTG_HWMODE_HOSTXCVR_TD_RS (1 << 4)
#define USBOTG_HWMODE_HOSTXCVR_TS_RS (3 << 4)
#define USBOTG_HWMODE_CRECFG_MASK (3 << 0)
#define USBOTG_HWMODE_CRECFG_HOST (1 << 0)
#define USBOTG_HWMODE_CRECFG_FUNC (2 << 0)
#define USBOTG_HWMODE_CRECFG_HNP (3 << 0)
#define USBOTG_CINT_STAT 0x04
#define USBOTG_CINT_STEN 0x08
#define USBOTG_ASHNPINT (1 << 5)
#define USBOTG_ASFCINT (1 << 4)
#define USBOTG_ASHCINT (1 << 3)
#define USBOTG_SHNPINT (1 << 2)
#define USBOTG_FCINT (1 << 1)
#define USBOTG_HCINT (1 << 0)
#define USBOTG_CLK_CTRL 0x0c
#define USBOTG_CLK_CTRL_FUNC (1 << 2)
#define USBOTG_CLK_CTRL_HST (1 << 1)
#define USBOTG_CLK_CTRL_MAIN (1 << 0)
#define USBOTG_RST_CTRL 0x10
#define USBOTG_RST_RSTI2C (1 << 15)
#define USBOTG_RST_RSTCTRL (1 << 5)
#define USBOTG_RST_RSTFC (1 << 4)
#define USBOTG_RST_RSTFSKE (1 << 3)
#define USBOTG_RST_RSTRH (1 << 2)
#define USBOTG_RST_RSTHSIE (1 << 1)
#define USBOTG_RST_RSTHC (1 << 0)
#define USBOTG_FRM_INTVL 0x14
#define USBOTG_FRM_REMAIN 0x18
#define USBOTG_HNP_CSR 0x1c
#define USBOTG_HNP_ISR 0x2c
#define USBOTG_HNP_IEN 0x30
#define USBOTG_I2C_TXCVR_REG(x) (0x100 + (x))
#define USBOTG_I2C_XCVR_DEVAD 0x118
#define USBOTG_I2C_SEQ_OP_REG 0x119
#define USBOTG_I2C_SEQ_RD_STARTAD 0x11a
#define USBOTG_I2C_OP_CTRL_REG 0x11b
#define USBOTG_I2C_SCLK_TO_SCK_HPER 0x11e
#define USBOTG_I2C_MASTER_INT_REG 0x11f
#define USBH_HOST_CTRL 0x80
#define USBH_HOST_CTRL_HCRESET (1 << 31)
#define USBH_HOST_CTRL_SCHDOVR(x) ((x) << 16)
#define USBH_HOST_CTRL_RMTWUEN (1 << 4)
#define USBH_HOST_CTRL_HCUSBSTE_RESET (0 << 2)
#define USBH_HOST_CTRL_HCUSBSTE_RESUME (1 << 2)
#define USBH_HOST_CTRL_HCUSBSTE_OPERATIONAL (2 << 2)
#define USBH_HOST_CTRL_HCUSBSTE_SUSPEND (3 << 2)
#define USBH_HOST_CTRL_CTLBLKSR_1 (0 << 0)
#define USBH_HOST_CTRL_CTLBLKSR_2 (1 << 0)
#define USBH_HOST_CTRL_CTLBLKSR_3 (2 << 0)
#define USBH_HOST_CTRL_CTLBLKSR_4 (3 << 0)
#define USBH_SYSISR 0x88
#define USBH_SYSISR_PSCINT (1 << 6)
#define USBH_SYSISR_FMOFINT (1 << 5)
#define USBH_SYSISR_HERRINT (1 << 4)
#define USBH_SYSISR_RESDETINT (1 << 3)
#define USBH_SYSISR_SOFINT (1 << 2)
#define USBH_SYSISR_DONEINT (1 << 1)
#define USBH_SYSISR_SORINT (1 << 0)
#define USBH_SYSIEN 0x8c
#define USBH_SYSIEN_PSCINT (1 << 6)
#define USBH_SYSIEN_FMOFINT (1 << 5)
#define USBH_SYSIEN_HERRINT (1 << 4)
#define USBH_SYSIEN_RESDETINT (1 << 3)
#define USBH_SYSIEN_SOFINT (1 << 2)
#define USBH_SYSIEN_DONEINT (1 << 1)
#define USBH_SYSIEN_SORINT (1 << 0)
#define USBH_XBUFSTAT 0x98
#define USBH_YBUFSTAT 0x9c
#define USBH_XYINTEN 0xa0
#define USBH_XFILLSTAT 0xa8
#define USBH_YFILLSTAT 0xac
#define USBH_ETDENSET 0xc0
#define USBH_ETDENCLR 0xc4
#define USBH_IMMEDINT 0xcc
#define USBH_ETDDONESTAT 0xd0
#define USBH_ETDDONEEN 0xd4
#define USBH_FRMNUB 0xe0
#define USBH_LSTHRESH 0xe4
#define USBH_ROOTHUBA 0xe8
#define USBH_ROOTHUBA_PWRTOGOOD_MASK (0xff)
#define USBH_ROOTHUBA_PWRTOGOOD_SHIFT (24)
#define USBH_ROOTHUBA_NOOVRCURP (1 << 12)
#define USBH_ROOTHUBA_OVRCURPM (1 << 11)
#define USBH_ROOTHUBA_DEVTYPE (1 << 10)
#define USBH_ROOTHUBA_PWRSWTMD (1 << 9)
#define USBH_ROOTHUBA_NOPWRSWT (1 << 8)
#define USBH_ROOTHUBA_NDNSTMPRT_MASK (0xff)
#define USBH_ROOTHUBB 0xec
#define USBH_ROOTHUBB_PRTPWRCM(x) (1 << ((x) + 16))
#define USBH_ROOTHUBB_DEVREMOVE(x) (1 << (x))
#define USBH_ROOTSTAT 0xf0
#define USBH_ROOTSTAT_CLRRMTWUE (1 << 31)
#define USBH_ROOTSTAT_OVRCURCHG (1 << 17)
#define USBH_ROOTSTAT_DEVCONWUE (1 << 15)
#define USBH_ROOTSTAT_OVRCURI (1 << 1)
#define USBH_ROOTSTAT_LOCPWRS (1 << 0)
#define USBH_PORTSTAT(x) (0xf4 + ((x) * 4))
#define USBH_PORTSTAT_PRTRSTSC (1 << 20)
#define USBH_PORTSTAT_OVRCURIC (1 << 19)
#define USBH_PORTSTAT_PRTSTATSC (1 << 18)
#define USBH_PORTSTAT_PRTENBLSC (1 << 17)
#define USBH_PORTSTAT_CONNECTSC (1 << 16)
#define USBH_PORTSTAT_LSDEVCON (1 << 9)
#define USBH_PORTSTAT_PRTPWRST (1 << 8)
#define USBH_PORTSTAT_PRTRSTST (1 << 4)
#define USBH_PORTSTAT_PRTOVRCURI (1 << 3)
#define USBH_PORTSTAT_PRTSUSPST (1 << 2)
#define USBH_PORTSTAT_PRTENABST (1 << 1)
#define USBH_PORTSTAT_CURCONST (1 << 0)
#define USB_DMAREV 0x800
#define USB_DMAINTSTAT 0x804
#define USB_DMAINTSTAT_EPERR (1 << 1)
#define USB_DMAINTSTAT_ETDERR (1 << 0)
#define USB_DMAINTEN 0x808
#define USB_DMAINTEN_EPERRINTEN (1 << 1)
#define USB_DMAINTEN_ETDERRINTEN (1 << 0)
#define USB_ETDDMAERSTAT 0x80c
#define USB_EPDMAERSTAT 0x810
#define USB_ETDDMAEN 0x820
#define USB_EPDMAEN 0x824
#define USB_ETDDMAXTEN 0x828
#define USB_EPDMAXTEN 0x82c
#define USB_ETDDMAENXYT 0x830
#define USB_EPDMAENXYT 0x834
#define USB_ETDDMABST4EN 0x838
#define USB_EPDMABST4EN 0x83c
#define USB_MISCCONTROL 0x840
#define USB_MISCCONTROL_ISOPREVFRM (1 << 3)
#define USB_MISCCONTROL_SKPRTRY (1 << 2)
#define USB_MISCCONTROL_ARBMODE (1 << 1)
#define USB_MISCCONTROL_FILTCC (1 << 0)
#define USB_ETDDMACHANLCLR 0x848
#define USB_EPDMACHANLCLR 0x84c
#define USB_ETDSMSA(x) (0x900 + ((x) * 4))
#define USB_EPSMSA(x) (0x980 + ((x) * 4))
#define USB_ETDDMABUFPTR(x) (0xa00 + ((x) * 4))
#define USB_EPDMABUFPTR(x) (0xa80 + ((x) * 4))
#define USB_ETD_DWORD(x, w) (0x200 + ((x) * 16) + ((w) * 4))
#define DW0_ADDRESS 0
#define DW0_ENDPNT 7
#define DW0_DIRECT 11
#define DW0_SPEED 13
#define DW0_FORMAT 14
#define DW0_MAXPKTSIZ 16
#define DW0_HALTED 27
#define DW0_TOGCRY 28
#define DW0_SNDNAK 30
#define DW1_XBUFSRTAD 0
#define DW1_YBUFSRTAD 16
#define DW2_RTRYDELAY 0
#define DW2_POLINTERV 0
#define DW2_STARTFRM 0
#define DW2_RELPOLPOS 8
#define DW2_DIRPID 16
#define DW2_BUFROUND 18
#define DW2_DELAYINT 19
#define DW2_DATATOG 22
#define DW2_ERRORCNT 24
#define DW2_COMPCODE 28
#define DW3_TOTBYECNT 0
#define DW3_PKTLEN0 0
#define DW3_COMPCODE0 12
#define DW3_PKTLEN1 16
#define DW3_BUFSIZE 21
#define DW3_COMPCODE1 28
#define USBCTRL 0x600
#define USBCTRL_I2C_WU_INT_STAT (1 << 27)
#define USBCTRL_OTG_WU_INT_STAT (1 << 26)
#define USBCTRL_HOST_WU_INT_STAT (1 << 25)
#define USBCTRL_FNT_WU_INT_STAT (1 << 24)
#define USBCTRL_I2C_WU_INT_EN (1 << 19)
#define USBCTRL_OTG_WU_INT_EN (1 << 18)
#define USBCTRL_HOST_WU_INT_EN (1 << 17)
#define USBCTRL_FNT_WU_INT_EN (1 << 16)
#define USBCTRL_OTC_RCV_RXDP (1 << 13)
#define USBCTRL_HOST1_BYP_TLL (1 << 12)
#define USBCTRL_OTG_BYP_VAL(x) ((x) << 10)
#define USBCTRL_HOST1_BYP_VAL(x) ((x) << 8)
#define USBCTRL_OTG_PWR_MASK (1 << 6)
#define USBCTRL_HOST1_PWR_MASK (1 << 5)
#define USBCTRL_HOST2_PWR_MASK (1 << 4)
#define USBCTRL_USB_BYP (1 << 2)
#define USBCTRL_HOST1_TXEN_OE (1 << 1)
/* Values in TD blocks */
#define TD_DIR_SETUP 0
#define TD_DIR_OUT 1
#define TD_DIR_IN 2
#define TD_FORMAT_CONTROL 0
#define TD_FORMAT_ISO 1
#define TD_FORMAT_BULK 2
#define TD_FORMAT_INT 3
#define TD_TOGGLE_CARRY 0
#define TD_TOGGLE_DATA0 2
#define TD_TOGGLE_DATA1 3
/* control transfer states */
#define US_CTRL_SETUP 2
#define US_CTRL_DATA 1
#define US_CTRL_ACK 0
/* bulk transfer main state and 0-length packet */
#define US_BULK 1
#define US_BULK0 0
/*ETD format description*/
#define IMX_FMT_CTRL 0x0
#define IMX_FMT_ISO 0x1
#define IMX_FMT_BULK 0x2
#define IMX_FMT_INT 0x3
static char fmt_urb_to_etd[4] = {
/*PIPE_ISOCHRONOUS*/ IMX_FMT_ISO,
/*PIPE_INTERRUPT*/ IMX_FMT_INT,
/*PIPE_CONTROL*/ IMX_FMT_CTRL,
/*PIPE_BULK*/ IMX_FMT_BULK
};
/* condition (error) CC codes and mapping (OHCI like) */
#define TD_CC_NOERROR 0x00
#define TD_CC_CRC 0x01
#define TD_CC_BITSTUFFING 0x02
#define TD_CC_DATATOGGLEM 0x03
#define TD_CC_STALL 0x04
#define TD_DEVNOTRESP 0x05
#define TD_PIDCHECKFAIL 0x06
/*#define TD_UNEXPECTEDPID 0x07 - reserved, not active on MX2*/
#define TD_DATAOVERRUN 0x08
#define TD_DATAUNDERRUN 0x09
#define TD_BUFFEROVERRUN 0x0C
#define TD_BUFFERUNDERRUN 0x0D
#define TD_SCHEDULEOVERRUN 0x0E
#define TD_NOTACCESSED 0x0F
static const int cc_to_error[16] = {
/* No Error */ 0,
/* CRC Error */ -EILSEQ,
/* Bit Stuff */ -EPROTO,
/* Data Togg */ -EILSEQ,
/* Stall */ -EPIPE,
/* DevNotResp */ -ETIMEDOUT,
/* PIDCheck */ -EPROTO,
/* UnExpPID */ -EPROTO,
/* DataOver */ -EOVERFLOW,
/* DataUnder */ -EREMOTEIO,
/* (for hw) */ -EIO,
/* (for hw) */ -EIO,
/* BufferOver */ -ECOMM,
/* BuffUnder */ -ENOSR,
/* (for HCD) */ -ENOSPC,
/* (for HCD) */ -EALREADY
};
/* HCD data associated with a usb core URB */
struct urb_priv {
struct urb *urb;
struct usb_host_endpoint *ep;
int active;
int state;
struct td *isoc_td;
int isoc_remaining;
int isoc_status;
};
/* HCD data associated with a usb core endpoint */
struct ep_priv {
struct usb_host_endpoint *ep;
struct list_head td_list;
struct list_head queue;
int etd[NUM_ISO_ETDS];
int waiting_etd;
};
/* isoc packet */
struct td {
struct list_head list;
struct urb *urb;
struct usb_host_endpoint *ep;
dma_addr_t data;
unsigned long buf_addr;
int len;
int frame;
int isoc_index;
};
/* HCD data associated with a hardware ETD */
struct etd_priv {
struct usb_host_endpoint *ep;
struct urb *urb;
struct td *td;
struct list_head queue;
dma_addr_t dma_handle;
int alloc;
int len;
int dmem_size;
int dmem_offset;
int active_count;
#ifdef DEBUG
int activated_frame;
int disactivated_frame;
int last_int_frame;
int last_req_frame;
u32 submitted_dwords[4];
#endif
};
/* Hardware data memory info */
struct imx21_dmem_area {
struct usb_host_endpoint *ep;
unsigned int offset;
unsigned int size;
struct list_head list;
};
#ifdef DEBUG
struct debug_usage_stats {
unsigned int value;
unsigned int maximum;
};
struct debug_stats {
unsigned long submitted;
unsigned long completed_ok;
unsigned long completed_failed;
unsigned long unlinked;
unsigned long queue_etd;
unsigned long queue_dmem;
};
struct debug_isoc_trace {
int schedule_frame;
int submit_frame;
int request_len;
int done_frame;
int done_len;
int cc;
struct td *td;
};
#endif
/* HCD data structure */
struct imx21 {
spinlock_t lock;
struct device *dev;
struct mx21_usbh_platform_data *pdata;
struct list_head dmem_list;
struct list_head queue_for_etd; /* eps queued due to etd shortage */
struct list_head queue_for_dmem; /* etds queued due to dmem shortage */
struct etd_priv etd[USB_NUM_ETD];
struct clk *clk;
void __iomem *regs;
#ifdef DEBUG
struct dentry *debug_root;
struct debug_stats nonisoc_stats;
struct debug_stats isoc_stats;
struct debug_usage_stats etd_usage;
struct debug_usage_stats dmem_usage;
struct debug_isoc_trace isoc_trace[20];
struct debug_isoc_trace isoc_trace_failed[20];
unsigned long debug_unblocks;
int isoc_trace_index;
int isoc_trace_index_failed;
#endif
};
#endif

View File

@ -1257,7 +1257,7 @@ static int isp1362_urb_enqueue(struct usb_hcd *hcd,
/* avoid all allocations within spinlocks: request or endpoint */
if (!hep->hcpriv) {
ep = kcalloc(1, sizeof *ep, mem_flags);
ep = kzalloc(sizeof *ep, mem_flags);
if (!ep)
return -ENOMEM;
}
@ -2719,24 +2719,11 @@ static int __init isp1362_probe(struct platform_device *pdev)
}
irq = irq_res->start;
#ifdef CONFIG_USB_HCD_DMA
if (pdev->dev.dma_mask) {
struct resource *dma_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
if (!dma_res) {
retval = -ENODEV;
goto err1;
}
isp1362_hcd->data_dma = dma_res->start;
isp1362_hcd->max_dma_size = resource_len(dma_res);
}
#else
if (pdev->dev.dma_mask) {
DBG(1, "won't do DMA");
retval = -ENODEV;
goto err1;
}
#endif
if (!request_mem_region(addr->start, resource_len(addr), hcd_name)) {
retval = -EBUSY;

View File

@ -17,7 +17,9 @@
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/mm.h>
#include <asm/unaligned.h>
#include <asm/cacheflush.h>
#include "../core/hcd.h"
#include "isp1760-hcd.h"
@ -904,6 +906,14 @@ __acquires(priv->lock)
status = 0;
}
if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) {
void *ptr;
for (ptr = urb->transfer_buffer;
ptr < urb->transfer_buffer + urb->transfer_buffer_length;
ptr += PAGE_SIZE)
flush_dcache_page(virt_to_page(ptr));
}
/* complete() can reenter this HCD */
usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
spin_unlock(&priv->lock);

View File

@ -109,7 +109,7 @@ static int of_isp1760_remove(struct of_device *dev)
return 0;
}
static struct of_device_id of_isp1760_match[] = {
static const struct of_device_id of_isp1760_match[] = {
{
.compatible = "nxp,usb-isp1760",
},

View File

@ -0,0 +1,456 @@
/*
* OHCI HCD (Host Controller Driver) for USB.
*
* TI DA8xx (OMAP-L1x) Bus Glue
*
* Derived from: ohci-omap.c and ohci-s3c2410.c
* Copyright (C) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <mach/da8xx.h>
#include <mach/usb.h>
#ifndef CONFIG_ARCH_DAVINCI_DA8XX
#error "This file is DA8xx bus glue. Define CONFIG_ARCH_DAVINCI_DA8XX."
#endif
#define CFGCHIP2 DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG)
static struct clk *usb11_clk;
static struct clk *usb20_clk;
/* Over-current indicator change bitmask */
static volatile u16 ocic_mask;
static void ohci_da8xx_clock(int on)
{
u32 cfgchip2;
cfgchip2 = __raw_readl(CFGCHIP2);
if (on) {
clk_enable(usb11_clk);
/*
* If USB 1.1 reference clock is sourced from USB 2.0 PHY, we
* need to enable the USB 2.0 module clocking, start its PHY,
* and not allow it to stop the clock during USB 2.0 suspend.
*/
if (!(cfgchip2 & CFGCHIP2_USB1PHYCLKMUX)) {
clk_enable(usb20_clk);
cfgchip2 &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN);
cfgchip2 |= CFGCHIP2_PHY_PLLON;
__raw_writel(cfgchip2, CFGCHIP2);
pr_info("Waiting for USB PHY clock good...\n");
while (!(__raw_readl(CFGCHIP2) & CFGCHIP2_PHYCLKGD))
cpu_relax();
}
/* Enable USB 1.1 PHY */
cfgchip2 |= CFGCHIP2_USB1SUSPENDM;
} else {
clk_disable(usb11_clk);
if (!(cfgchip2 & CFGCHIP2_USB1PHYCLKMUX))
clk_disable(usb20_clk);
/* Disable USB 1.1 PHY */
cfgchip2 &= ~CFGCHIP2_USB1SUSPENDM;
}
__raw_writel(cfgchip2, CFGCHIP2);
}
/*
* Handle the port over-current indicator change.
*/
static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub,
unsigned port)
{
ocic_mask |= 1 << port;
/* Once over-current is detected, the port needs to be powered down */
if (hub->get_oci(port) > 0)
hub->set_power(port, 0);
}
static int ohci_da8xx_init(struct usb_hcd *hcd)
{
struct device *dev = hcd->self.controller;
struct da8xx_ohci_root_hub *hub = dev->platform_data;
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int result;
u32 rh_a;
dev_dbg(dev, "starting USB controller\n");
ohci_da8xx_clock(1);
/*
* DA8xx only have 1 port connected to the pins but the HC root hub
* register A reports 2 ports, thus we'll have to override it...
*/
ohci->num_ports = 1;
result = ohci_init(ohci);
if (result < 0)
return result;
/*
* Since we're providing a board-specific root hub port power control
* and over-current reporting, we have to override the HC root hub A
* register's default value, so that ohci_hub_control() could return
* the correct hub descriptor...
*/
rh_a = ohci_readl(ohci, &ohci->regs->roothub.a);
if (hub->set_power) {
rh_a &= ~RH_A_NPS;
rh_a |= RH_A_PSM;
}
if (hub->get_oci) {
rh_a &= ~RH_A_NOCP;
rh_a |= RH_A_OCPM;
}
rh_a &= ~RH_A_POTPGT;
rh_a |= hub->potpgt << 24;
ohci_writel(ohci, rh_a, &ohci->regs->roothub.a);
return result;
}
static void ohci_da8xx_stop(struct usb_hcd *hcd)
{
ohci_stop(hcd);
ohci_da8xx_clock(0);
}
static int ohci_da8xx_start(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int result;
result = ohci_run(ohci);
if (result < 0)
ohci_da8xx_stop(hcd);
return result;
}
/*
* Update the status data from the hub with the over-current indicator change.
*/
static int ohci_da8xx_hub_status_data(struct usb_hcd *hcd, char *buf)
{
int length = ohci_hub_status_data(hcd, buf);
/* See if we have OCIC bit set on port 1 */
if (ocic_mask & (1 << 1)) {
dev_dbg(hcd->self.controller, "over-current indicator change "
"on port 1\n");
if (!length)
length = 1;
buf[0] |= 1 << 1;
}
return length;
}
/*
* Look at the control requests to the root hub and see if we need to override.
*/
static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
struct device *dev = hcd->self.controller;
struct da8xx_ohci_root_hub *hub = dev->platform_data;
int temp;
switch (typeReq) {
case GetPortStatus:
/* Check the port number */
if (wIndex != 1)
break;
dev_dbg(dev, "GetPortStatus(%u)\n", wIndex);
temp = roothub_portstatus(hcd_to_ohci(hcd), wIndex - 1);
/* The port power status (PPS) bit defaults to 1 */
if (hub->get_power && hub->get_power(wIndex) == 0)
temp &= ~RH_PS_PPS;
/* The port over-current indicator (POCI) bit is always 0 */
if (hub->get_oci && hub->get_oci(wIndex) > 0)
temp |= RH_PS_POCI;
/* The over-current indicator change (OCIC) bit is 0 too */
if (ocic_mask & (1 << wIndex))
temp |= RH_PS_OCIC;
put_unaligned(cpu_to_le32(temp), (__le32 *)buf);
return 0;
case SetPortFeature:
temp = 1;
goto check_port;
case ClearPortFeature:
temp = 0;
check_port:
/* Check the port number */
if (wIndex != 1)
break;
switch (wValue) {
case USB_PORT_FEAT_POWER:
dev_dbg(dev, "%sPortFeature(%u): %s\n",
temp ? "Set" : "Clear", wIndex, "POWER");
if (!hub->set_power)
return -EPIPE;
return hub->set_power(wIndex, temp) ? -EPIPE : 0;
case USB_PORT_FEAT_C_OVER_CURRENT:
dev_dbg(dev, "%sPortFeature(%u): %s\n",
temp ? "Set" : "Clear", wIndex,
"C_OVER_CURRENT");
if (temp)
ocic_mask |= 1 << wIndex;
else
ocic_mask &= ~(1 << wIndex);
return 0;
}
}
return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
}
static const struct hc_driver ohci_da8xx_hc_driver = {
.description = hcd_name,
.product_desc = "DA8xx OHCI",
.hcd_priv_size = sizeof(struct ohci_hcd),
/*
* generic hardware linkage
*/
.irq = ohci_irq,
.flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
*/
.reset = ohci_da8xx_init,
.start = ohci_da8xx_start,
.stop = ohci_da8xx_stop,
.shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,
/*
* scheduling support
*/
.get_frame_number = ohci_get_frame,
/*
* root hub support
*/
.hub_status_data = ohci_da8xx_hub_status_data,
.hub_control = ohci_da8xx_hub_control,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
#endif
.start_port_reset = ohci_start_port_reset,
};
/*-------------------------------------------------------------------------*/
/**
* usb_hcd_da8xx_probe - initialize DA8xx-based HCDs
* Context: !in_interrupt()
*
* Allocates basic resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
*/
static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
struct platform_device *pdev)
{
struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data;
struct usb_hcd *hcd;
struct resource *mem;
int error, irq;
if (hub == NULL)
return -ENODEV;
usb11_clk = clk_get(&pdev->dev, "usb11");
if (IS_ERR(usb11_clk))
return PTR_ERR(usb11_clk);
usb20_clk = clk_get(&pdev->dev, "usb20");
if (IS_ERR(usb20_clk)) {
error = PTR_ERR(usb20_clk);
goto err0;
}
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
error = -ENOMEM;
goto err1;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
error = -ENODEV;
goto err2;
}
hcd->rsrc_start = mem->start;
hcd->rsrc_len = mem->end - mem->start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
dev_dbg(&pdev->dev, "request_mem_region failed\n");
error = -EBUSY;
goto err2;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
dev_err(&pdev->dev, "ioremap failed\n");
error = -ENOMEM;
goto err3;
}
ohci_hcd_init(hcd_to_ohci(hcd));
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
error = -ENODEV;
goto err4;
}
error = usb_add_hcd(hcd, irq, IRQF_DISABLED);
if (error)
goto err4;
if (hub->ocic_notify) {
error = hub->ocic_notify(ohci_da8xx_ocic_handler);
if (!error)
return 0;
}
usb_remove_hcd(hcd);
err4:
iounmap(hcd->regs);
err3:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err2:
usb_put_hcd(hcd);
err1:
clk_put(usb20_clk);
err0:
clk_put(usb11_clk);
return error;
}
/**
* usb_hcd_da8xx_remove - shutdown processing for DA8xx-based HCDs
* @dev: USB Host Controller being removed
* Context: !in_interrupt()
*
* Reverses the effect of usb_hcd_da8xx_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
* context, normally "rmmod", "apmd", or something similar.
*/
static inline void
usb_hcd_da8xx_remove(struct usb_hcd *hcd, struct platform_device *pdev)
{
struct da8xx_ohci_root_hub *hub = pdev->dev.platform_data;
hub->ocic_notify(NULL);
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
clk_put(usb20_clk);
clk_put(usb11_clk);
}
static int ohci_hcd_da8xx_drv_probe(struct platform_device *dev)
{
return usb_hcd_da8xx_probe(&ohci_da8xx_hc_driver, dev);
}
static int ohci_hcd_da8xx_drv_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
usb_hcd_da8xx_remove(hcd, dev);
platform_set_drvdata(dev, NULL);
return 0;
}
#ifdef CONFIG_PM
static int ohci_da8xx_suspend(struct platform_device *dev, pm_message_t message)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
if (time_before(jiffies, ohci->next_statechange))
msleep(5);
ohci->next_statechange = jiffies;
ohci_da8xx_clock(0);
hcd->state = HC_STATE_SUSPENDED;
dev->dev.power.power_state = PMSG_SUSPEND;
return 0;
}
static int ohci_da8xx_resume(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
if (time_before(jiffies, ohci->next_statechange))
msleep(5);
ohci->next_statechange = jiffies;
ohci_da8xx_clock(1);
dev->dev.power.power_state = PMSG_ON;
usb_hcd_resume_root_hub(hcd);
return 0;
}
#endif
/*
* Driver definition to register with platform structure.
*/
static struct platform_driver ohci_hcd_da8xx_driver = {
.probe = ohci_hcd_da8xx_drv_probe,
.remove = ohci_hcd_da8xx_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_da8xx_suspend,
.resume = ohci_da8xx_resume,
#endif
.driver = {
.owner = THIS_MODULE,
.name = "ohci",
},
};

View File

@ -53,13 +53,13 @@ urb_print(struct urb * urb, char * str, int small, int status)
int i, len;
if (usb_pipecontrol (pipe)) {
printk (KERN_DEBUG __FILE__ ": setup(8):");
printk (KERN_DEBUG "%s: setup(8):", __FILE__);
for (i = 0; i < 8 ; i++)
printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
printk ("\n");
}
if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
printk (KERN_DEBUG __FILE__ ": data(%d/%d):",
printk (KERN_DEBUG "%s: data(%d/%d):", __FILE__,
urb->actual_length,
urb->transfer_buffer_length);
len = usb_pipeout (pipe)?

View File

@ -1051,6 +1051,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER usb_hcd_pnx4008_driver
#endif
#ifdef CONFIG_ARCH_DAVINCI_DA8XX
#include "ohci-da8xx.c"
#define PLATFORM_DRIVER ohci_hcd_da8xx_driver
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_CPU_SUBTYPE_SH7763) || \

View File

@ -28,8 +28,8 @@ extern int usb_disabled(void);
static void lh7a404_start_hc(struct platform_device *dev)
{
printk(KERN_DEBUG __FILE__
": starting LH7A404 OHCI USB Controller\n");
printk(KERN_DEBUG "%s: starting LH7A404 OHCI USB Controller\n",
__FILE__);
/*
* Now, carefully enable the USB clock, and take
@ -39,14 +39,13 @@ static void lh7a404_start_hc(struct platform_device *dev)
udelay(1000);
USBH_CMDSTATUS = OHCI_HCR;
printk(KERN_DEBUG __FILE__
": Clock to USB host has been enabled \n");
printk(KERN_DEBUG "%s: Clock to USB host has been enabled \n", __FILE__);
}
static void lh7a404_stop_hc(struct platform_device *dev)
{
printk(KERN_DEBUG __FILE__
": stopping LH7A404 OHCI USB Controller\n");
printk(KERN_DEBUG "%s: stopping LH7A404 OHCI USB Controller\n",
__FILE__);
CSC_PWRCNT &= ~CSC_PWRCNT_USBH_EN; /* Disable clock */
}

View File

@ -327,7 +327,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
}
i2c_adap = i2c_get_adapter(2);
memset(&i2c_info, 0, sizeof(struct i2c_board_info));
strlcpy(i2c_info.name, "isp1301_pnx", I2C_NAME_SIZE);
strlcpy(i2c_info.type, "isp1301_pnx", I2C_NAME_SIZE);
isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
normal_i2c);
i2c_put_adapter(i2c_adap);
@ -411,7 +411,7 @@ out3:
out2:
clk_put(usb_clk);
out1:
i2c_unregister_client(isp1301_i2c_client);
i2c_unregister_device(isp1301_i2c_client);
isp1301_i2c_client = NULL;
out_i2c_driver:
i2c_del_driver(&isp1301_driver);
@ -430,7 +430,7 @@ static int usb_hcd_pnx4008_remove(struct platform_device *pdev)
pnx4008_unset_usb_bits();
clk_disable(usb_clk);
clk_put(usb_clk);
i2c_unregister_client(isp1301_i2c_client);
i2c_unregister_device(isp1301_i2c_client);
isp1301_i2c_client = NULL;
i2c_del_driver(&isp1301_driver);

View File

@ -114,21 +114,21 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
hcd->rsrc_len = res.end - res.start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
rv = -EBUSY;
goto err_rmr;
}
irq = irq_of_parse_and_map(dn, 0);
if (irq == NO_IRQ) {
printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
rv = -EBUSY;
goto err_irq;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
printk(KERN_ERR __FILE__ ": ioremap failed\n");
printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
rv = -ENOMEM;
goto err_ioremap;
}
@ -169,7 +169,7 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
} else
release_mem_region(res.start, 0x4);
} else
pr_debug(__FILE__ ": cannot get ehci offset from fdt\n");
pr_debug("%s: cannot get ehci offset from fdt\n", __FILE__);
}
iounmap(hcd->regs);
@ -212,7 +212,7 @@ static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
}
static struct of_device_id ohci_hcd_ppc_of_match[] = {
static const struct of_device_id ohci_hcd_ppc_of_match[] = {
#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
{
.name = "usb",

View File

@ -41,14 +41,14 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
pr_debug(__FILE__ ": no irq\n");
pr_debug("%s: no irq\n", __FILE__);
return -ENODEV;
}
irq = res->start;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
pr_debug(__FILE__ ": no reg addr\n");
pr_debug("%s: no reg addr\n", __FILE__);
return -ENODEV;
}
@ -59,14 +59,14 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
hcd->rsrc_len = res->end - res->start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
pr_debug(__FILE__ ": request_mem_region failed\n");
pr_debug("%s: request_mem_region failed\n", __FILE__);
retval = -EBUSY;
goto err1;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
pr_debug(__FILE__ ": ioremap failed\n");
pr_debug("%s: ioremap failed\n", __FILE__);
retval = -ENOMEM;
goto err2;
}

View File

@ -31,8 +31,8 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
{
unsigned int usb_rst = 0;
printk(KERN_DEBUG __FILE__
": starting SA-1111 OHCI USB Controller\n");
printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n",
__FILE__);
#ifdef CONFIG_SA1100_BADGE4
if (machine_is_badge4()) {
@ -65,8 +65,8 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
static void sa1111_stop_hc(struct sa1111_dev *dev)
{
unsigned int usb_rst;
printk(KERN_DEBUG __FILE__
": stopping SA-1111 OHCI USB Controller\n");
printk(KERN_DEBUG "%s: stopping SA-1111 OHCI USB Controller\n",
__FILE__);
/*
* Put the USB host controller into reset.

View File

@ -51,6 +51,7 @@
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include "../core/hcd.h"
#include "sl811.h"
@ -1272,12 +1273,12 @@ sl811h_hub_control(
sl811h_hub_descriptor(sl811, (struct usb_hub_descriptor *) buf);
break;
case GetHubStatus:
*(__le32 *) buf = cpu_to_le32(0);
put_unaligned_le32(0, buf);
break;
case GetPortStatus:
if (wIndex != 1)
goto error;
*(__le32 *) buf = cpu_to_le32(sl811->port1);
put_unaligned_le32(sl811->port1, buf);
#ifndef VERBOSE
if (*(u16*)(buf+2)) /* only if wPortChange is interesting */

View File

@ -735,6 +735,7 @@ static void uhci_stop(struct usb_hcd *hcd)
uhci_hc_died(uhci);
uhci_scan_schedule(uhci);
spin_unlock_irq(&uhci->lock);
synchronize_irq(hcd->irq);
del_timer_sync(&uhci->fsbr_timer);
release_uhci(uhci);

View File

@ -406,6 +406,25 @@ static void dbg_rsvd64(struct xhci_hcd *xhci, u64 *ctx, dma_addr_t dma)
}
}
char *xhci_get_slot_state(struct xhci_hcd *xhci,
struct xhci_container_ctx *ctx)
{
struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
switch (GET_SLOT_STATE(slot_ctx->dev_state)) {
case 0:
return "enabled/disabled";
case 1:
return "default";
case 2:
return "addressed";
case 3:
return "configured";
default:
return "reserved";
}
}
void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
{
/* Fields are 32 bits wide, DMA addresses are in bytes */

View File

@ -101,12 +101,15 @@ static inline int xhci_find_next_cap_offset(void __iomem *base, int ext_offset)
next = readl(base + ext_offset);
if (ext_offset == XHCI_HCC_PARAMS_OFFSET)
if (ext_offset == XHCI_HCC_PARAMS_OFFSET) {
/* Find the first extended capability */
next = XHCI_HCC_EXT_CAPS(next);
else
ext_offset = 0;
} else {
/* Find the next extended capability */
next = XHCI_EXT_CAPS_NEXT(next);
}
if (!next)
return 0;
/*

View File

@ -1007,7 +1007,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
* for usb_set_interface() and usb_set_configuration() claim).
*/
if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id],
udev, ep, GFP_KERNEL) < 0) {
udev, ep, GFP_NOIO) < 0) {
dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n",
__func__, ep->desc.bEndpointAddress);
return -ENOMEM;
@ -1181,6 +1181,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
ret = xhci_queue_evaluate_context(xhci, in_ctx->dma,
udev->slot_id);
if (ret < 0) {
if (command)
list_del(&command->cmd_list);
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
return -ENOMEM;
@ -1264,30 +1266,13 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
xhci_zero_in_ctx(xhci, virt_dev);
/* Install new rings and free or cache any old rings */
for (i = 1; i < 31; ++i) {
int rings_cached;
if (!virt_dev->eps[i].new_ring)
continue;
/* Only cache or free the old ring if it exists.
* It may not if this is the first add of an endpoint.
*/
if (virt_dev->eps[i].ring) {
rings_cached = virt_dev->num_rings_cached;
if (rings_cached < XHCI_MAX_RINGS_CACHED) {
virt_dev->num_rings_cached++;
rings_cached = virt_dev->num_rings_cached;
virt_dev->ring_cache[rings_cached] =
virt_dev->eps[i].ring;
xhci_dbg(xhci, "Cached old ring, "
"%d ring%s cached\n",
rings_cached,
(rings_cached > 1) ? "s" : "");
} else {
xhci_ring_free(xhci, virt_dev->eps[i].ring);
xhci_dbg(xhci, "Ring cache full (%d rings), "
"freeing ring\n",
virt_dev->num_rings_cached);
}
xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
}
virt_dev->eps[i].ring = virt_dev->eps[i].new_ring;
virt_dev->eps[i].new_ring = NULL;
@ -1457,6 +1442,131 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
xhci_warn(xhci, "FIXME allocate a new ring segment\n");
}
/*
* This submits a Reset Device Command, which will set the device state to 0,
* set the device address to 0, and disable all the endpoints except the default
* control endpoint. The USB core should come back and call
* xhci_address_device(), and then re-set up the configuration. If this is
* called because of a usb_reset_and_verify_device(), then the old alternate
* settings will be re-installed through the normal bandwidth allocation
* functions.
*
* Wait for the Reset Device command to finish. Remove all structures
* associated with the endpoints that were disabled. Clear the input device
* structure? Cache the rings? Reset the control endpoint 0 max packet size?
*/
int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
{
int ret, i;
unsigned long flags;
struct xhci_hcd *xhci;
unsigned int slot_id;
struct xhci_virt_device *virt_dev;
struct xhci_command *reset_device_cmd;
int timeleft;
int last_freed_endpoint;
ret = xhci_check_args(hcd, udev, NULL, 0, __func__);
if (ret <= 0)
return ret;
xhci = hcd_to_xhci(hcd);
slot_id = udev->slot_id;
virt_dev = xhci->devs[slot_id];
if (!virt_dev) {
xhci_dbg(xhci, "%s called with invalid slot ID %u\n",
__func__, slot_id);
return -EINVAL;
}
xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id);
/* Allocate the command structure that holds the struct completion.
* Assume we're in process context, since the normal device reset
* process has to wait for the device anyway. Storage devices are
* reset as part of error handling, so use GFP_NOIO instead of
* GFP_KERNEL.
*/
reset_device_cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
if (!reset_device_cmd) {
xhci_dbg(xhci, "Couldn't allocate command structure.\n");
return -ENOMEM;
}
/* Attempt to submit the Reset Device command to the command ring */
spin_lock_irqsave(&xhci->lock, flags);
reset_device_cmd->command_trb = xhci->cmd_ring->enqueue;
list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list);
ret = xhci_queue_reset_device(xhci, slot_id);
if (ret) {
xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
list_del(&reset_device_cmd->cmd_list);
spin_unlock_irqrestore(&xhci->lock, flags);
goto command_cleanup;
}
xhci_ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);
/* Wait for the Reset Device command to finish */
timeleft = wait_for_completion_interruptible_timeout(
reset_device_cmd->completion,
USB_CTRL_SET_TIMEOUT);
if (timeleft <= 0) {
xhci_warn(xhci, "%s while waiting for reset device command\n",
timeleft == 0 ? "Timeout" : "Signal");
spin_lock_irqsave(&xhci->lock, flags);
/* The timeout might have raced with the event ring handler, so
* only delete from the list if the item isn't poisoned.
*/
if (reset_device_cmd->cmd_list.next != LIST_POISON1)
list_del(&reset_device_cmd->cmd_list);
spin_unlock_irqrestore(&xhci->lock, flags);
ret = -ETIME;
goto command_cleanup;
}
/* The Reset Device command can't fail, according to the 0.95/0.96 spec,
* unless we tried to reset a slot ID that wasn't enabled,
* or the device wasn't in the addressed or configured state.
*/
ret = reset_device_cmd->status;
switch (ret) {
case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */
case COMP_CTX_STATE: /* 0.96 completion code for same thing */
xhci_info(xhci, "Can't reset device (slot ID %u) in %s state\n",
slot_id,
xhci_get_slot_state(xhci, virt_dev->out_ctx));
xhci_info(xhci, "Not freeing device rings.\n");
/* Don't treat this as an error. May change my mind later. */
ret = 0;
goto command_cleanup;
case COMP_SUCCESS:
xhci_dbg(xhci, "Successful reset device command.\n");
break;
default:
if (xhci_is_vendor_info_code(xhci, ret))
break;
xhci_warn(xhci, "Unknown completion code %u for "
"reset device command.\n", ret);
ret = -EINVAL;
goto command_cleanup;
}
/* Everything but endpoint 0 is disabled, so free or cache the rings. */
last_freed_endpoint = 1;
for (i = 1; i < 31; ++i) {
if (!virt_dev->eps[i].ring)
continue;
xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
last_freed_endpoint = i;
}
xhci_dbg(xhci, "Output context after successful reset device cmd:\n");
xhci_dbg_ctx(xhci, virt_dev->out_ctx, last_freed_endpoint);
ret = 0;
command_cleanup:
xhci_free_command(xhci, reset_device_cmd);
return ret;
}
/*
* At this point, the struct usb_device is about to go away, the device has
* disconnected, and all traffic has been stopped and the endpoints have been
@ -1694,7 +1804,7 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
xhci_warn(xhci, "Cannot update hub desc for unknown device.\n");
return -EINVAL;
}
config_cmd = xhci_alloc_command(xhci, true, mem_flags);
config_cmd = xhci_alloc_command(xhci, true, true, mem_flags);
if (!config_cmd) {
xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
return -ENOMEM;

View File

@ -129,6 +129,50 @@ static u32 xhci_port_state_to_neutral(u32 state)
return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
}
static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex,
u32 __iomem *addr, u32 port_status)
{
/* Write 1 to disable the port */
xhci_writel(xhci, port_status | PORT_PE, addr);
port_status = xhci_readl(xhci, addr);
xhci_dbg(xhci, "disable port, actual port %d status = 0x%x\n",
wIndex, port_status);
}
static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
u16 wIndex, u32 __iomem *addr, u32 port_status)
{
char *port_change_bit;
u32 status;
switch (wValue) {
case USB_PORT_FEAT_C_RESET:
status = PORT_RC;
port_change_bit = "reset";
break;
case USB_PORT_FEAT_C_CONNECTION:
status = PORT_CSC;
port_change_bit = "connect";
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
status = PORT_OCC;
port_change_bit = "over-current";
break;
case USB_PORT_FEAT_C_ENABLE:
status = PORT_PEC;
port_change_bit = "enable/disable";
break;
default:
/* Should never happen */
return;
}
/* Change bits are all write 1 to clear */
xhci_writel(xhci, port_status | status, addr);
port_status = xhci_readl(xhci, addr);
xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n",
port_change_bit, wIndex, port_status);
}
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
@ -138,7 +182,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u32 temp, status;
int retval = 0;
u32 __iomem *addr;
char *port_change_bit;
ports = HCS_MAX_PORTS(xhci->hcs_params1);
@ -229,26 +272,18 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_port_state_to_neutral(temp);
switch (wValue) {
case USB_PORT_FEAT_C_RESET:
status = PORT_RC;
port_change_bit = "reset";
break;
case USB_PORT_FEAT_C_CONNECTION:
status = PORT_CSC;
port_change_bit = "connect";
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
status = PORT_OCC;
port_change_bit = "over-current";
case USB_PORT_FEAT_C_ENABLE:
xhci_clear_port_change_bit(xhci, wValue, wIndex,
addr, temp);
break;
case USB_PORT_FEAT_ENABLE:
xhci_disable_port(xhci, wIndex, addr, temp);
break;
default:
goto error;
}
/* Change bits are all write 1 to clear */
xhci_writel(xhci, temp | status, addr);
temp = xhci_readl(xhci, addr);
xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n",
port_change_bit, wIndex, temp);
temp = xhci_readl(xhci, addr); /* unblock any posted writes */
break;
default:
error:

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