forked from Minki/linux
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:
commit
7f5b09c15a
@ -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
|
||||
|
@ -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!
|
||||
|
@ -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
|
||||
|
48
Documentation/networking/cxacru-cf.py
Normal file
48
Documentation/networking/cxacru-cf.py
Normal 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")
|
@ -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)"
|
||||
|
@ -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 *
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
38
arch/arm/plat-mxc/include/mach/mx21-usbhost.h
Normal file
38
arch/arm/plat-mxc/include/mach/mx21-usbhost.h
Normal 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 */
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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/
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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) },
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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
259
drivers/usb/gadget/nokia.c
Normal 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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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".
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)) {
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
},
|
||||
|
@ -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;
|
||||
|
@ -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",},
|
||||
{},
|
||||
};
|
||||
|
@ -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", },
|
||||
{},
|
||||
};
|
||||
|
527
drivers/usb/host/imx21-dbg.c
Normal file
527
drivers/usb/host/imx21-dbg.c
Normal 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
1789
drivers/usb/host/imx21-hcd.c
Normal file
File diff suppressed because it is too large
Load Diff
436
drivers/usb/host/imx21-hcd.h
Normal file
436
drivers/usb/host/imx21-hcd.h
Normal 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
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
},
|
||||
|
456
drivers/usb/host/ohci-da8xx.c
Normal file
456
drivers/usb/host/ohci-da8xx.c
Normal 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",
|
||||
},
|
||||
};
|
@ -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)?
|
||||
|
@ -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) || \
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user