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

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (142 commits)
  USB: fix race in autosuspend reschedule
  atmel_usba_udc: Keep track of the device status
  USB: Nikon D40X unusual_devs entry
  USB: serial core should respect driver requirements
  USB: documentation for USB power management
  USB: skip autosuspended devices during system resume
  USB: mutual exclusion for EHCI init and port resets
  USB: allow usbstorage to have LUNS greater than 2Tb
  USB: Adding support for SHARP WS011SH to ipaq.c
  USB: add atmel_usba_udc driver
  USB: ohci SSB bus glue
  USB: ehci build fixes on au1xxx, ppc-soc
  USB: add runtime frame_no quirk for big-endian OHCI
  USB: funsoft: Fix termios
  USB: visor: termios bits
  USB: unusual_devs entry for Nikon DSC D2Xs
  USB: re-remove <linux/usb_sl811.h>
  USB: move <linux/usb_gadget.h> to <linux/usb/gadget.h>
  USB: Export URB statistics for powertop
  USB: serial gadget: Disable endpoints on unload
  ...
This commit is contained in:
Linus Torvalds 2007-10-12 15:49:10 -07:00
commit 117494a1b6
117 changed files with 8626 additions and 3859 deletions

View File

@ -0,0 +1,92 @@
Authorizing (or not) your USB devices to connect to the system
(C) 2007 Inaky Perez-Gonzalez <inaky@linux.intel.com> Intel Corporation
This feature allows you to control if a USB device can be used (or
not) in a system. This feature will allow you to implement a lock-down
of USB devices, fully controlled by user space.
As of now, when a USB device is connected it is configured and
it's interfaces inmediately made available to the users. With this
modification, only if root authorizes the device to be configured will
then it be possible to use it.
Usage:
Authorize a device to connect:
$ echo 1 > /sys/usb/devices/DEVICE/authorized
Deauthorize a device:
$ echo 0 > /sys/usb/devices/DEVICE/authorized
Set new devices connected to hostX to be deauthorized by default (ie:
lock down):
$ echo 0 > /sys/bus/devices/usbX/authorized_default
Remove the lock down:
$ echo 1 > /sys/bus/devices/usbX/authorized_default
By default, Wired USB devices are authorized by default to
connect. Wireless USB hosts deauthorize by default all new connected
devices (this is so because we need to do an authentication phase
before authorizing).
Example system lockdown (lame)
-----------------------
Imagine you want to implement a lockdown so only devices of type XYZ
can be connected (for example, it is a kiosk machine with a visible
USB port):
boot up
rc.local ->
for host in /sys/bus/devices/usb*
do
echo 0 > $host/authorized_default
done
Hookup an script to udev, for new USB devices
if device_is_my_type $DEV
then
echo 1 > $device_path/authorized
done
Now, device_is_my_type() is where the juice for a lockdown is. Just
checking if the class, type and protocol match something is the worse
security verification you can make (or the best, for someone willing
to break it). If you need something secure, use crypto and Certificate
Authentication or stuff like that. Something simple for an storage key
could be:
function device_is_my_type()
{
echo 1 > authorized # temporarily authorize it
# FIXME: make sure none can mount it
mount DEVICENODE /mntpoint
sum=$(md5sum /mntpoint/.signature)
if [ $sum = $(cat /etc/lockdown/keysum) ]
then
echo "We are good, connected"
umount /mntpoint
# Other stuff so others can use it
else
echo 0 > authorized
fi
}
Of course, this is lame, you'd want to do a real certificate
verification stuff with PKI, so you don't depend on a shared secret,
etc, but you get the idea. Anybody with access to a device gadget kit
can fake descriptors and device info. Don't trust that. You are
welcome.

View File

@ -0,0 +1,517 @@
Power Management for USB
Alan Stern <stern@rowland.harvard.edu>
October 5, 2007
What is Power Management?
-------------------------
Power Management (PM) is the practice of saving energy by suspending
parts of a computer system when they aren't being used. While a
component is "suspended" it is in a nonfunctional low-power state; it
might even be turned off completely. A suspended component can be
"resumed" (returned to a functional full-power state) when the kernel
needs to use it. (There also are forms of PM in which components are
placed in a less functional but still usable state instead of being
suspended; an example would be reducing the CPU's clock rate. This
document will not discuss those other forms.)
When the parts being suspended include the CPU and most of the rest of
the system, we speak of it as a "system suspend". When a particular
device is turned off while the system as a whole remains running, we
call it a "dynamic suspend" (also known as a "runtime suspend" or
"selective suspend"). This document concentrates mostly on how
dynamic PM is implemented in the USB subsystem, although system PM is
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.
What is Remote Wakeup?
----------------------
When a device has been suspended, it generally doesn't resume until
the computer tells it to. Likewise, if the entire computer has been
suspended, it generally doesn't resume until the user tells it to, say
by pressing a power button or opening the cover.
However some devices have the capability of resuming by themselves, or
asking the kernel to resume them, or even telling the entire computer
to resume. This capability goes by several names such as "Wake On
LAN"; we will refer to it generically as "remote wakeup". When a
device is enabled for remote wakeup and it is suspended, it may resume
itself (or send a request to be resumed) in response to some external
event. Examples include a suspended keyboard resuming when a key is
pressed, or a suspended USB hub resuming when a device is plugged in.
When is a USB device idle?
--------------------------
A device is idle whenever the kernel thinks it's not busy doing
anything important and thus is a candidate for being suspended. The
exact definition depends on the device's driver; drivers are allowed
to declare that a device isn't idle even when there's no actual
communication taking place. (For example, a hub isn't considered idle
unless all the devices plugged into that hub are already suspended.)
In addition, a device isn't considered idle so long as a program keeps
its usbfs file open, whether or not any I/O is going on.
If a USB device has no driver, its usbfs file isn't open, and it isn't
being accessed through sysfs, then it definitely is idle.
Forms of dynamic PM
-------------------
Dynamic suspends can occur in two ways: manual and automatic.
"Manual" means that the user has told the kernel to suspend a device,
whereas "automatic" means that the kernel has decided all by itself to
suspend a device. Automatic suspend is called "autosuspend" for
short. In general, a device won't be autosuspended unless it has been
idle for some minimum period of time, the so-called idle-delay time.
Of course, nothing the kernel does on its own initiative should
prevent the computer or its devices from working properly. If a
device has been autosuspended and a program tries to use it, the
kernel will automatically resume the device (autoresume). For the
same reason, an autosuspended device will usually have remote wakeup
enabled, if the device supports remote wakeup.
It is worth mentioning that many USB drivers don't support
autosuspend. In fact, at the time of this writing (Linux 2.6.23) the
only drivers which do support it are the hub driver, kaweth, asix,
usblp, usblcd, and usb-skeleton (which doesn't count). If a
non-supporting driver is bound to a device, the device won't be
autosuspended. In effect, the kernel pretends the device is never
idle.
We can categorize power management events in two broad classes:
external and internal. External events are those triggered by some
agent outside the USB stack: system suspend/resume (triggered by
userspace), manual dynamic suspend/resume (also triggered by
userspace), and remote wakeup (triggered by the device). Internal
events are those triggered within the USB stack: autosuspend and
autoresume.
The user interface for dynamic PM
---------------------------------
The user interface for controlling dynamic PM is located in the power/
subdirectory of each USB device's sysfs directory, that is, in
/sys/bus/usb/devices/.../power/ where "..." is the device's ID. The
relevant attribute files are: wakeup, level, and autosuspend.
power/wakeup
This file is empty if the device does not support
remote wakeup. Otherwise the file contains either the
word "enabled" or the word "disabled", and you can
write those words to the file. The setting determines
whether or not remote wakeup will be enabled when the
device is next suspended. (If the setting is changed
while the device is suspended, the change won't take
effect until the following suspend.)
power/level
This file contains one of three words: "on", "auto",
or "suspend". You can write those words to the file
to change the device's setting.
"on" means that the device should be resumed and
autosuspend is not allowed. (Of course, system
suspends are still allowed.)
"auto" is the normal state in which the kernel is
allowed to autosuspend and autoresume the device.
"suspend" means that the device should remain
suspended, and autoresume is not allowed. (But remote
wakeup may still be allowed, since it is controlled
separately by the power/wakeup attribute.)
power/autosuspend
This file contains an integer value, which is the
number of seconds the device should remain idle before
the kernel will autosuspend it (the idle-delay time).
The default is 2. 0 means to autosuspend as soon as
the device becomes idle, and -1 means never to
autosuspend. You can write a number to the file to
change the autosuspend idle-delay time.
Writing "-1" to power/autosuspend and writing "on" to power/level do
essentially the same thing -- they both prevent the device from being
autosuspended. Yes, this is a redundancy in the API.
(In 2.6.21 writing "0" to power/autosuspend would prevent the device
from being autosuspended; the behavior was changed in 2.6.22. The
power/autosuspend attribute did not exist prior to 2.6.21, and the
power/level attribute did not exist prior to 2.6.22.)
Changing the default idle-delay time
------------------------------------
The default autosuspend idle-delay time is controlled by a module
parameter in usbcore. You can specify the value when usbcore is
loaded. For example, to set it to 5 seconds instead of 2 you would
do:
modprobe usbcore autosuspend=5
Equivalently, you could add to /etc/modprobe.conf a line saying:
options usbcore autosuspend=5
Some distributions load the usbcore module very early during the boot
process, by means of a program or script running from an initramfs
image. To alter the parameter value you would have to rebuild that
image.
If usbcore is compiled into the kernel rather than built as a loadable
module, you can add
usbcore.autosuspend=5
to the kernel's boot command line.
Finally, the parameter value can be changed while the system is
running. If you do:
echo 5 >/sys/module/usbcore/parameters/autosuspend
then each new USB device will have its autosuspend idle-delay
initialized to 5. (The idle-delay values for already existing devices
will not be affected.)
Setting the initial default idle-delay to -1 will prevent any
autosuspend of any USB device. This is a simple alternative to
disabling CONFIG_USB_SUSPEND and rebuilding the kernel, and it has the
added benefit of allowing you to enable autosuspend for selected
devices.
Warnings
--------
The USB specification states that all USB devices must support power
management. Nevertheless, the sad fact is that many devices do not
support it very well. You can suspend them all right, but when you
try to resume them they disconnect themselves from the USB bus or
they stop working entirely. This seems to be especially prevalent
among printers and scanners, but plenty of other types of device have
the same deficiency.
For this reason, by default the kernel disables autosuspend (the
power/level attribute is initialized to "on") for all devices other
than hubs. Hubs, at least, appear to be reasonably well-behaved in
this regard.
(In 2.6.21 and 2.6.22 this wasn't the case. Autosuspend was enabled
by default for almost all USB devices. A number of people experienced
problems as a result.)
This means that non-hub devices won't be autosuspended unless the user
or a program explicitly enables it. As of this writing there aren't
any widespread programs which will do this; we hope that in the near
future device managers such as HAL will take on this added
responsibility. In the meantime you can always carry out the
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.
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,
which manages keyboards and mice, among other things. Tests with a
number of keyboards showed that typing on a suspended keyboard, while
causing the keyboard to do a remote wakeup all right, would
nonetheless frequently result in lost keystrokes. Tests with mice
showed that some of them would issue a remote-wakeup request in
response to button presses but not to motion, and some in response to
neither.
The kernel will not prevent you from enabling autosuspend on devices
that can't handle it. It is even possible in theory to damage a
device by suspending it at the wrong time -- for example, suspending a
USB hard disk might cause it to spin down without parking the heads.
(Highly unlikely, but possible.) Take care.
The driver interface for Power Management
-----------------------------------------
The requirements for a USB driver to support external power management
are pretty modest; the driver need only define
.suspend
.resume
.reset_resume
methods in its usb_driver structure, and the reset_resume method is
optional. The methods' jobs are quite simple:
The suspend method is called to warn the driver that the
device is going to be suspended. If the driver returns a
negative error code, the suspend will be aborted. Normally
the driver will return 0, in which case it must cancel all
outstanding URBs (usb_kill_urb()) and not submit any more.
The resume method is called to tell the driver that the
device has been resumed and the driver can return to normal
operation. URBs may once more be submitted.
The reset_resume method is called to tell the driver that
the device has been resumed and it also has been reset.
The driver should redo any necessary device initialization,
since the device has probably lost most or all of its state
(although the interfaces will be in the same altsettings as
before the suspend).
The reset_resume method is used by the USB Persist facility (see
Documentation/usb/persist.txt) and it can also be used under certain
circumstances when CONFIG_USB_PERSIST is not enabled. Currently, if a
device is reset during a resume and the driver does not have a
reset_resume method, the driver won't receive any notification about
the resume. Later kernels will call the driver's disconnect method;
2.6.23 doesn't do this.
USB drivers are bound to interfaces, so their suspend and resume
methods get called when the interfaces are suspended or resumed. In
principle one might want to suspend some interfaces on a device (i.e.,
force the drivers for those interface to stop all activity) without
suspending the other interfaces. The USB core doesn't allow this; all
interfaces are suspended when the device itself is suspended and all
interfaces are resumed when the device is resumed. It isn't possible
to suspend or resume some but not all of a device's interfaces. The
closest you can come is to unbind the interfaces' drivers.
The driver interface for autosuspend and autoresume
---------------------------------------------------
To support autosuspend and autoresume, a driver should implement all
three of the methods listed above. In addition, a driver indicates
that it supports autosuspend by setting the .supports_autosuspend flag
in its usb_driver structure. It is then responsible for informing the
USB core whenever one of its interfaces becomes busy or idle. The
driver does so by calling these three functions:
int usb_autopm_get_interface(struct usb_interface *intf);
void usb_autopm_put_interface(struct usb_interface *intf);
int usb_autopm_set_interface(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.
(There is a similar pm_usage_count 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.)
The driver owns intf->pm_usage_count; it can modify the value however
and whenever it likes. A nice aspect of the usb_autopm_* routines is
that the changes they make are protected by the usb_device structure's
PM mutex (udev->pm_mutex); however drivers may change pm_usage_count
without holding the mutex.
usb_autopm_get_interface() increments pm_usage_count and
attempts an autoresume if the new value is > 0 and the
device is suspended.
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_set_interface() leaves pm_usage_count alone.
It attempts an autoresume if the value is > 0 and the device
is suspended, and it attempts an autosuspend if the value is
<= 0 and the device isn't suspended.
There also are a couple of utility routines drivers can use:
usb_autopm_enable() sets pm_usage_cnt to 1 and then calls
usb_autopm_set_interface(), which will attempt an autoresume.
usb_autopm_disable() sets pm_usage_cnt to 0 and then calls
usb_autopm_set_interface(), which will attempt an autosuspend.
The conventional 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.
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.
Autoresume attempts also can fail. This will happen if power/level is
set to "suspend" or if the device doesn't manage to resume properly.
Unlike autosuspend, there's no delay for an autoresume.
Other parts of the driver interface
-----------------------------------
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
remote wakeup by typing on it. If the driver sets
intf->needs_remote_wakeup to 1, the kernel won't autosuspend the
device if remote wakeup isn't available or has been disabled through
the power/wakeup attribute. (If the device is already autosuspended,
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 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:
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.
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.
External suspend calls should never be allowed to fail in this way,
only autosuspend calls. The driver can tell them apart by checking
udev->auto_pm; this flag will be set to 1 for internal PM events
(autosuspend or autoresume) and 0 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 (usb_mark_last_busy() and udev->auto_pm) 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.
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.
If a driver wants to block all suspend/resume calls during some
critical section, it can simply acquire udev->pm_mutex.
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.
Interaction between dynamic PM and system PM
--------------------------------------------
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.)
Secondly, a dynamic power-management event may occur as a system
suspend is underway. The window for this is short, since system
suspends don't take long (a few seconds usually), but it can happen.
For example, a suspended device may send a remote-wakeup signal while
the system is suspending. The remote wakeup may succeed, which would
cause the system suspend to abort. If the remote wakeup doesn't
succeed, it may still remain active and thus cause the system to
resume as soon as the system suspend is complete. Or the remote
wakeup may fail and get lost. Which outcome occurs depends on timing
and on the hardware and firmware design.
More interestingly, a device might undergo a manual resume or
autoresume during system suspend. With current kernels this shouldn't
happen, because manual resumes must be initiated by userspace and
autoresumes happen in response to I/O requests, but all user processes
and I/O should be quiescent during a system suspend -- thanks to the
freezer. However there are plans to do away with the freezer, which
would mean these things would become possible. If and when this comes
about, the USB core will carefully arrange matters so that either type
of resume will block until the entire system has resumed.

View File

@ -428,6 +428,17 @@ Options supported:
See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
information on this driver.
Winchiphead CH341 Driver
This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip
also implements an IEEE 1284 parallel port, I2C and SPI, but that is not
supported by the driver. The protocol was analyzed from the behaviour
of the Windows driver, no datasheet is available at present.
The manufacturer's website: http://www.winchiphead.com/.
For any questions or problems with this driver, please contact
frank@kingswood-consulting.co.uk.
Generic Serial driver
If your device is not one of the above listed devices, compatible with

View File

@ -34,9 +34,12 @@ if usbmon is built into the kernel.
Verify that bus sockets are present.
# ls /sys/kernel/debug/usbmon
1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u
0s 0t 0u 1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u
#
Now you can choose to either use the sockets numbered '0' (to capture packets on
all buses), and skip to step #3, or find the bus used by your device with step #2.
2. Find which bus connects to the desired device
Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
@ -56,6 +59,10 @@ Bus=03 means it's bus 3.
# cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out
to listen on a single bus, otherwise, to listen on all buses, type:
# cat /sys/kernel/debug/usbmon/0u > /tmp/1.mon.out
This process will be reading until killed. Naturally, the output can be
redirected to a desirable location. This is preferred, because it is going
to be quite long.

View File

@ -677,6 +677,13 @@ P: Haavard Skinnemoen
M: hskinnemoen@atmel.com
S: Supported
ATMEL USBA UDC DRIVER
P: Haavard Skinnemoen
M: hskinnemoen@atmel.com
L: kernel@avr32linux.org
W: http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver
S: Supported
ATMEL WIRELESS DRIVER
P: Simon Kelley
M: simon@thekelleys.org.uk

View File

@ -40,7 +40,7 @@
#include <linux/pata_platform.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/usb_sl811.h>
#include <linux/usb/sl811.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
#include <asm/reboot.h>

View File

@ -40,7 +40,7 @@
#include <linux/irq.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
#include <linux/usb_sl811.h>
#include <linux/usb/sl811.h>
#include <linux/spi/ad7877.h>

View File

@ -40,7 +40,7 @@
#include <linux/pata_platform.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/usb_sl811.h>
#include <linux/usb/sl811.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
#include <asm/reboot.h>

View File

@ -28,27 +28,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB_ADUTUX) += misc/
obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
obj-$(CONFIG_USB_AUERSWALD) += misc/
obj-$(CONFIG_USB_BERRY_CHARGE) += misc/
obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
obj-$(CONFIG_USB_CYTHERM) += misc/
obj-$(CONFIG_USB_EMI26) += misc/
obj-$(CONFIG_USB_EMI62) += misc/
obj-$(CONFIG_USB_FTDI_ELAN) += misc/
obj-$(CONFIG_USB_IDMOUSE) += misc/
obj-$(CONFIG_USB_LCD) += misc/
obj-$(CONFIG_USB_LD) += misc/
obj-$(CONFIG_USB_LED) += misc/
obj-$(CONFIG_USB_LEGOTOWER) += misc/
obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
obj-$(CONFIG_USB_RIO500) += misc/
obj-$(CONFIG_USB_SISUSBVGA) += misc/
obj-$(CONFIG_USB_TEST) += misc/
obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
obj-$(CONFIG_USB_USS720) += misc/
obj-$(CONFIG_USB_IOWARRIOR) += misc/
obj-$(CONFIG_USB) += misc/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/

View File

@ -482,7 +482,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
dbg("too big transfer requested");
if (printk_ratelimit())
usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n",
wbuflen, rbuflen);
ret = -ENOMEM;
goto fail;
}
@ -493,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
init_completion(&instance->rcv_done);
ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
if (ret < 0) {
dbg("submitting read urb for cm %#x failed", cm);
ret = ret;
if (printk_ratelimit())
usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n",
cm, ret);
goto fail;
}
@ -510,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
init_completion(&instance->snd_done);
ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
if (ret < 0) {
dbg("submitting write urb for cm %#x failed", cm);
ret = ret;
if (printk_ratelimit())
usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n",
cm, ret);
goto fail;
}
ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
if (ret < 0) {
dbg("sending cm %#x failed", cm);
ret = ret;
if (printk_ratelimit())
usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret);
goto fail;
}
ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
if (ret < 0) {
dbg("receiving cm %#x failed", cm);
ret = ret;
if (printk_ratelimit())
usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret);
goto fail;
}
if (actlen % CMD_PACKET_SIZE || !actlen) {
dbg("response is not a positive multiple of %d: %#x",
CMD_PACKET_SIZE, actlen);
if (printk_ratelimit())
usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n",
cm, actlen);
ret = -EIO;
goto fail;
}
@ -538,12 +543,16 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
/* check the return status and copy the data to the output buffer, if needed */
for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
if (rbuf[offb] != cm) {
dbg("wrong cm %#x in response", rbuf[offb]);
if (printk_ratelimit())
usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n",
rbuf[offb], cm);
ret = -EIO;
goto fail;
}
if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
dbg("response failed: %#x", rbuf[offb + 1]);
if (printk_ratelimit())
usb_err(instance->usbatm, "response to cm %#x failed: %#x\n",
cm, rbuf[offb + 1]);
ret = -EIO;
goto fail;
}
@ -582,14 +591,18 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
for (offb = 0; offb < len; ) {
int l = le32_to_cpu(buf[offb++]);
if (l > stride || l > (len - offb) / 2) {
dbg("wrong data length %#x in response", l);
if (printk_ratelimit())
usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
cm, l);
ret = -EIO;
goto cleanup;
}
while (l--) {
offd = le32_to_cpu(buf[offb++]);
if (offd >= size) {
dbg("wrong index %#x in response", offd);
if (printk_ratelimit())
usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n",
offd, cm);
ret = -EIO;
goto cleanup;
}

View File

@ -251,7 +251,6 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
{
unsigned char *buffer;
struct usbatm_data *usbatm = instance->usbatm;
struct usb_interface *intf;
struct usb_device *usb_dev = usbatm->usb_dev;
int actual_length;
int ret = 0;
@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
goto out;
}
if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
if (!usb_ifnum_to_if(usb_dev, 2)) {
ret = -ENODEV;
usb_dbg(usbatm, "%s: interface not found!\n", __func__);
goto out_free;

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@
* v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
* v0.13 - alloc space for statusbuf (<status> not on stack);
* use usb_buffer_alloc() for read buf & write buf;
* none - Maintained in Linux kernel after v0.13
*/
/*
@ -69,7 +70,6 @@
#define USBLP_DEVICE_ID_SIZE 1024
/* ioctls: */
#define LPGETSTATUS 0x060b /* same as in drivers/char/lp.c */
#define IOCNR_GET_DEVICE_ID 1
#define IOCNR_GET_PROTOCOLS 2
#define IOCNR_SET_PROTOCOL 3
@ -115,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
#define USBLP_MINORS 16
#define USBLP_MINOR_BASE 0
#define USBLP_WRITE_TIMEOUT (5000) /* 5 seconds */
#define USBLP_CTL_TIMEOUT 5000 /* 5 seconds */
#define USBLP_FIRST_PROTOCOL 1
#define USBLP_LAST_PROTOCOL 3
@ -159,10 +159,12 @@ struct usblp {
int wstatus; /* bytes written or error */
int rstatus; /* bytes ready or error */
unsigned int quirks; /* quirks flags */
unsigned int flags; /* mode flags */
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 */
};
@ -259,7 +261,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
retval = usb_control_msg(usblp->dev,
dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
request, !!dir, recip, value, index, len, retval);
return retval < 0 ? retval : 0;
@ -325,13 +327,11 @@ static void usblp_bulk_write(struct urb *urb)
usblp->wstatus = status;
else
usblp->wstatus = urb->actual_length;
usblp->no_paper = 0;
usblp->wcomplete = 1;
wake_up(&usblp->wwait);
spin_unlock(&usblp->lock);
/* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */
kfree(urb->transfer_buffer);
urb->transfer_buffer = NULL; /* Not refcounted, so to be safe... */
usb_free_urb(urb);
}
@ -346,16 +346,17 @@ static int usblp_check_status(struct usblp *usblp, int err)
unsigned char status, newerr = 0;
int error;
error = usblp_read_status (usblp, usblp->statusbuf);
if (error < 0) {
mutex_lock(&usblp->mut);
if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
mutex_unlock(&usblp->mut);
if (printk_ratelimit())
printk(KERN_ERR
"usblp%d: error %d reading printer status\n",
usblp->minor, error);
return 0;
}
status = *usblp->statusbuf;
mutex_unlock(&usblp->mut);
if (~status & LP_PERRORP)
newerr = 3;
@ -411,18 +412,10 @@ static int usblp_open(struct inode *inode, struct file *file)
goto out;
/*
* TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
* This is #if 0-ed because we *don't* want to fail an open
* just because the printer is off-line.
* We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
* - We do not want persistent state which close(2) does not clear
* - It is not used anyway, according to CUPS people
*/
#if 0
if ((retval = usblp_check_status(usblp, 0))) {
retval = retval > 1 ? -EIO : -ENOSPC;
goto out;
}
#else
retval = 0;
#endif
retval = usb_autopm_get_interface(intf);
if (retval < 0)
@ -463,6 +456,8 @@ static int usblp_release(struct inode *inode, struct file *file)
{
struct usblp *usblp = file->private_data;
usblp->flags &= ~LP_ABORT;
mutex_lock (&usblp_mutex);
usblp->used = 0;
if (usblp->present) {
@ -485,8 +480,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
poll_wait(file, &usblp->rwait, wait);
poll_wait(file, &usblp->wwait, wait);
spin_lock_irqsave(&usblp->lock, flags);
ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM)
| (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN | POLLRDNORM : 0) |
((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0);
spin_unlock_irqrestore(&usblp->lock, flags);
return ret;
}
@ -675,6 +670,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
retval = -EFAULT;
break;
case LPABORT:
if (arg)
usblp->flags |= LP_ABORT;
else
usblp->flags &= ~LP_ABORT;
break;
default:
retval = -ENOTTY;
}
@ -684,10 +686,30 @@ done:
return retval;
}
static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
{
struct urb *urb;
char *writebuf;
if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL)
return NULL;
if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
kfree(writebuf);
return NULL;
}
usb_fill_bulk_urb(urb, usblp->dev,
usb_sndbulkpipe(usblp->dev,
usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
writebuf, transfer_length, usblp_bulk_write, usblp);
urb->transfer_flags |= URB_FREE_BUFFER;
return urb;
}
static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
char *writebuf;
struct urb *writeurb;
int rv;
int transfer_length;
@ -708,17 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
transfer_length = USBLP_BUF_SIZE;
rv = -ENOMEM;
if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
goto raise_buf;
if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL)
goto raise_urb;
usb_fill_bulk_urb(writeurb, usblp->dev,
usb_sndbulkpipe(usblp->dev,
usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
writebuf, transfer_length, usblp_bulk_write, usblp);
usb_anchor_urb(writeurb, &usblp->urbs);
if (copy_from_user(writebuf,
if (copy_from_user(writeurb->transfer_buffer,
buffer + writecount, transfer_length)) {
rv = -EFAULT;
goto raise_badaddr;
@ -730,6 +746,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
usblp->wstatus = 0;
spin_lock_irq(&usblp->lock);
usblp->no_paper = 0;
usblp->wcomplete = 1;
wake_up(&usblp->wwait);
spin_unlock_irq(&usblp->lock);
@ -747,12 +764,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
/* Presume that it's going to complete well. */
writecount += transfer_length;
}
if (rv == -ENOSPC) {
spin_lock_irq(&usblp->lock);
usblp->no_paper = 1; /* Mark for poll(2) */
spin_unlock_irq(&usblp->lock);
writecount += transfer_length;
}
/* Leave URB dangling, to be cleaned on close. */
goto collect_error;
}
if (usblp->wstatus < 0) {
usblp_check_status(usblp, 0);
rv = -EIO;
goto collect_error;
}
@ -771,8 +793,6 @@ raise_badaddr:
usb_unanchor_urb(writeurb);
usb_free_urb(writeurb);
raise_urb:
kfree(writebuf);
raise_buf:
raise_wait:
collect_error: /* Out of raise sequence */
mutex_unlock(&usblp->wmut);
@ -838,32 +858,36 @@ done:
* when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
* select(2) or poll(2) to wait for the buffer to drain before closing.
* Alternatively, set blocking mode with fcntl and issue a zero-size write.
*
* Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot
* to check the return code for timeout expiration, so it had no effect.
* Apparently, it was intended to check for error conditons, such as out
* of paper. It is going to return when we settle things with CUPS. XXX
*/
static int usblp_wwait(struct usblp *usblp, int nonblock)
{
DECLARE_WAITQUEUE(waita, current);
int rc;
int err = 0;
add_wait_queue(&usblp->wwait, &waita);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
if (mutex_lock_interruptible(&usblp->mut)) {
rc = -EINTR;
break;
}
set_current_state(TASK_INTERRUPTIBLE);
if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
mutex_unlock(&usblp->mut);
break;
}
rc = usblp_wtest(usblp, nonblock);
mutex_unlock(&usblp->mut);
if (rc == 0)
if (rc <= 0)
break;
schedule();
if (usblp->flags & LP_ABORT) {
if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
err = usblp_check_status(usblp, err);
if (err == 1) { /* Paper out */
rc = -ENOSPC;
break;
}
}
} else {
schedule();
}
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&usblp->wwait, &waita);

View File

@ -507,18 +507,30 @@ void usb_destroy_configuration(struct usb_device *dev)
}
// hub-only!! ... and only in reset path, or usb_new_device()
// (used by real hubs and virtual root hubs)
/*
* Get the USB config descriptors, cache and parse'em
*
* hub-only!! ... and only in reset path, or usb_new_device()
* (used by real hubs and virtual root hubs)
*
* NOTE: if this is a WUSB device and is not authorized, we skip the
* whole thing. A non-authorized USB device has no
* configurations.
*/
int usb_get_configuration(struct usb_device *dev)
{
struct device *ddev = &dev->dev;
int ncfg = dev->descriptor.bNumConfigurations;
int result = -ENOMEM;
int result = 0;
unsigned int cfgno, length;
unsigned char *buffer;
unsigned char *bigbuffer;
struct usb_config_descriptor *desc;
cfgno = 0;
if (dev->authorized == 0) /* Not really an error */
goto out_not_authorized;
result = -ENOMEM;
if (ncfg > USB_MAXCONFIG) {
dev_warn(ddev, "too many configurations: %d, "
"using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev)
goto err2;
desc = (struct usb_config_descriptor *)buffer;
for (cfgno = 0; cfgno < ncfg; cfgno++) {
result = 0;
for (; cfgno < ncfg; cfgno++) {
/* We grab just the first descriptor so we know how long
* the whole configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
buffer, USB_DT_CONFIG_SIZE);
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
"descriptor/%s\n", cfgno, "start");
"descriptor/%s: %d\n", cfgno, "start", result);
dev_err(ddev, "chopping to %d config(s)\n", cfgno);
dev->descriptor.bNumConfigurations = cfgno;
break;
@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev)
err:
kfree(buffer);
out_not_authorized:
dev->descriptor.bNumConfigurations = cfgno;
err2:
if (result == -ENOMEM)

View File

@ -71,6 +71,7 @@ struct async {
void __user *userbuffer;
void __user *userurb;
struct urb *urb;
int status;
u32 secid;
};
@ -289,10 +290,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
if (!usbfs_snoop)
return;
if (urb->pipe & USB_DIR_IN)
dev_info(&urb->dev->dev, "direction=IN\n");
else
dev_info(&urb->dev->dev, "direction=OUT\n");
dev_info(&urb->dev->dev, "direction=%s\n",
usb_urb_dir_in(urb) ? "IN" : "OUT");
dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
urb->transfer_buffer_length);
@ -312,9 +311,10 @@ static void async_completed(struct urb *urb)
spin_lock(&ps->lock);
list_move_tail(&as->asynclist, &ps->async_completed);
spin_unlock(&ps->lock);
as->status = urb->status;
if (as->signr) {
sinfo.si_signo = as->signr;
sinfo.si_errno = as->urb->status;
sinfo.si_errno = as->status;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb;
kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
@ -910,6 +910,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
struct usb_ctrlrequest *dr = NULL;
unsigned int u, totlen, isofrmlen;
int ret, ifnum = -1;
int is_in;
if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
URB_NO_FSBR|URB_ZERO_PACKET))
@ -924,16 +925,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
if ((ret = checkintf(ps, ifnum)))
return ret;
}
if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0)
ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
else
ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
is_in = 1;
ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
} else {
is_in = 0;
ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
}
if (!ep)
return -ENOENT;
switch(uurb->type) {
case USBDEVFS_URB_TYPE_CONTROL:
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_CONTROL)
if (!usb_endpoint_xfer_control(&ep->desc))
return -EINVAL;
/* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
@ -952,23 +955,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
kfree(dr);
return ret;
}
uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
uurb->number_of_packets = 0;
uurb->buffer_length = le16_to_cpup(&dr->wLength);
uurb->buffer += 8;
if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) {
if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
is_in = 1;
uurb->endpoint |= USB_DIR_IN;
} else {
is_in = 0;
uurb->endpoint &= ~USB_DIR_IN;
}
if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
uurb->buffer, uurb->buffer_length)) {
kfree(dr);
return -EFAULT;
}
snoop(&ps->dev->dev, "control urb: bRequest=%02x "
"bRrequestType=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
dr->bRequest, dr->bRequestType, dr->wValue,
dr->wIndex, dr->wLength);
dr->bRequest, dr->bRequestType,
__le16_to_cpup(&dr->wValue),
__le16_to_cpup(&dr->wIndex),
__le16_to_cpup(&dr->wLength));
break;
case USBDEVFS_URB_TYPE_BULK:
switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
switch (usb_endpoint_type(&ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_ISOC:
return -EINVAL;
@ -977,7 +989,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
uurb->number_of_packets = 0;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
uurb->buffer, uurb->buffer_length))
return -EFAULT;
snoop(&ps->dev->dev, "bulk urb\n");
break;
@ -986,8 +999,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
/* arbitrary limit */
if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
return -EINVAL;
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_ISOC)
if (!usb_endpoint_xfer_isoc(&ep->desc))
return -EINVAL;
isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
@ -1014,12 +1026,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
case USBDEVFS_URB_TYPE_INTERRUPT:
uurb->number_of_packets = 0;
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_INT)
if (!usb_endpoint_xfer_int(&ep->desc))
return -EINVAL;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
uurb->buffer, uurb->buffer_length))
return -EFAULT;
snoop(&ps->dev->dev, "interrupt urb\n");
break;
@ -1039,8 +1051,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -ENOMEM;
}
as->urb->dev = ps->dev;
as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
as->urb->transfer_flags = uurb->flags;
as->urb->pipe = (uurb->type << 30) |
__create_pipe(ps->dev, uurb->endpoint & 0xf) |
(uurb->endpoint & USB_DIR_IN);
as->urb->transfer_flags = uurb->flags |
(is_in ? URB_DIR_IN : URB_DIR_OUT);
as->urb->transfer_buffer_length = uurb->buffer_length;
as->urb->setup_packet = (unsigned char*)dr;
as->urb->start_frame = uurb->start_frame;
@ -1070,13 +1085,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->uid = current->uid;
as->euid = current->euid;
security_task_getsecid(current, &as->secid);
if (!(uurb->endpoint & USB_DIR_IN)) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
if (!is_in) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
as->urb->transfer_buffer_length)) {
free_async(as);
return -EFAULT;
}
}
snoop(&as->urb->dev->dev, "submit urb\n");
snoop_urb(as->urb, as->userurb);
async_newpending(as);
if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
@ -1119,14 +1134,14 @@ static int processcompl(struct async *as, void __user * __user *arg)
if (as->userbuffer)
if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
return -EFAULT;
if (put_user(urb->status, &userurb->status))
if (put_user(as->status, &userurb->status))
return -EFAULT;
if (put_user(urb->actual_length, &userurb->actual_length))
return -EFAULT;
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
if (usb_pipeisoc(urb->pipe)) {
if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))
@ -1233,14 +1248,14 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
if (as->userbuffer)
if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
return -EFAULT;
if (put_user(urb->status, &userurb->status))
if (put_user(as->status, &userurb->status))
return -EFAULT;
if (put_user(urb->actual_length, &userurb->actual_length))
return -EFAULT;
if (put_user(urb->error_count, &userurb->error_count))
return -EFAULT;
if (usb_pipeisoc(urb->pipe)) {
if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
for (i = 0; i < urb->number_of_packets; i++) {
if (put_user(urb->iso_frame_desc[i].actual_length,
&userurb->iso_frame_desc[i].actual_length))

View File

@ -202,6 +202,11 @@ static int usb_probe_interface(struct device *dev)
intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf);
if (udev->authorized == 0) {
dev_err(&intf->dev, "Device is not authorized for usage\n");
return -ENODEV;
}
id = usb_match_id(intf, driver->id_table);
if (!id)
id = usb_match_dynamic_id(intf, driver);
@ -945,11 +950,11 @@ done:
#ifdef CONFIG_USB_SUSPEND
/* Internal routine to check whether we may autosuspend a device. */
static int autosuspend_check(struct usb_device *udev)
static int autosuspend_check(struct usb_device *udev, int reschedule)
{
int i;
struct usb_interface *intf;
unsigned long suspend_time;
unsigned long suspend_time, j;
/* For autosuspend, fail fast if anything is in use or autosuspend
* is disabled. Also fail if any interfaces require remote wakeup
@ -991,20 +996,20 @@ static int autosuspend_check(struct usb_device *udev)
}
/* If everything is okay but the device hasn't been idle for long
* enough, queue a delayed autosuspend request.
* enough, queue a delayed autosuspend request. If the device
* _has_ been idle for long enough and the reschedule flag is set,
* likewise queue a delayed (1 second) autosuspend request.
*/
if (time_after(suspend_time, jiffies)) {
j = jiffies;
if (time_before(j, suspend_time))
reschedule = 1;
else
suspend_time = j + HZ;
if (reschedule) {
if (!timer_pending(&udev->autosuspend.timer)) {
/* The value of jiffies may change between the
* time_after() comparison above and the subtraction
* below. That's okay; the system behaves sanely
* when a timer is registered for the present moment
* or for the past.
*/
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
round_jiffies_relative(suspend_time - jiffies));
}
round_jiffies_relative(suspend_time - j));
}
return -EAGAIN;
}
return 0;
@ -1012,7 +1017,7 @@ static int autosuspend_check(struct usb_device *udev)
#else
static inline int autosuspend_check(struct usb_device *udev)
static inline int autosuspend_check(struct usb_device *udev, int reschedule)
{
return 0;
}
@ -1069,7 +1074,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
if (udev->auto_pm) {
status = autosuspend_check(udev);
status = autosuspend_check(udev, 0);
if (status < 0)
goto done;
}
@ -1083,15 +1088,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
break;
}
}
if (status == 0) {
/* Non-root devices don't need to do anything for FREEZE
* or PRETHAW. */
if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
msg.event == PM_EVENT_PRETHAW))
goto done;
if (status == 0)
status = usb_suspend_device(udev, msg);
}
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
@ -1102,12 +1100,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
/* Try another autosuspend when the interfaces aren't busy */
if (udev->auto_pm)
autosuspend_check(udev);
autosuspend_check(udev, status == -EBUSY);
/* If the suspend succeeded, propagate it up the tree */
/* If the suspend succeeded then prevent any more URB submissions,
* flush any outstanding URBs, and propagate the suspend up the tree.
*/
} else {
cancel_delayed_work(&udev->autosuspend);
if (parent)
udev->can_submit = 0;
for (i = 0; i < 16; ++i) {
usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
}
/* If this is just a FREEZE or a PRETHAW, udev might
* not really be suspended. Only true suspends get
* propagated up the device tree.
*/
if (parent && udev->state == USB_STATE_SUSPENDED)
usb_autosuspend_device(parent);
}
@ -1156,6 +1166,7 @@ static int usb_resume_both(struct usb_device *udev)
status = -ENODEV;
goto done;
}
udev->can_submit = 1;
/* Propagate the resume up the tree, if necessary */
if (udev->state == USB_STATE_SUSPENDED) {
@ -1529,9 +1540,21 @@ int usb_external_resume_device(struct usb_device *udev)
static int usb_suspend(struct device *dev, pm_message_t message)
{
struct usb_device *udev;
if (!is_usb_device(dev)) /* Ignore PM for interfaces */
return 0;
return usb_external_suspend_device(to_usb_device(dev), message);
udev = to_usb_device(dev);
/* If udev is already suspended, we can skip this suspend and
* we should also skip the upcoming system resume. */
if (udev->state == USB_STATE_SUSPENDED) {
udev->skip_sys_resume = 1;
return 0;
}
udev->skip_sys_resume = 0;
return usb_external_suspend_device(udev, message);
}
static int usb_resume(struct device *dev)
@ -1542,13 +1565,14 @@ static int usb_resume(struct device *dev)
return 0;
udev = to_usb_device(dev);
/* If autoresume is disabled then we also want to prevent resume
* during system wakeup. However, a "persistent-device" reset-resume
* after power loss counts as a wakeup event. So allow a
* reset-resume to occur if remote wakeup is enabled. */
if (udev->autoresume_disabled) {
/* If udev->skip_sys_resume is set then udev was already suspended
* when the system suspend started, so we don't want to resume
* udev during this system wakeup. However a reset-resume counts
* as a wakeup event, so allow a reset-resume to occur if remote
* wakeup is enabled. */
if (udev->skip_sys_resume) {
if (!(udev->reset_resume && udev->do_remote_wakeup))
return -EPERM;
return -EHOSTUNREACH;
}
return usb_external_resume_device(udev);
}

View File

@ -267,7 +267,6 @@ static void ep_device_release(struct device *dev)
{
struct ep_device *ep_dev = to_ep_device(dev);
dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
endpoint_free_minor(ep_dev);
kfree(ep_dev);
}

View File

@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc)
&& desc->bInterfaceProtocol == 1;
}
static int choose_configuration(struct usb_device *udev)
int usb_choose_configuration(struct usb_device *udev)
{
int i;
int num_configs;
@ -161,17 +161,20 @@ static int generic_probe(struct usb_device *udev)
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
c = choose_configuration(udev);
if (c >= 0) {
err = usb_set_configuration(udev, c);
if (err) {
dev_err(&udev->dev, "can't set config #%d, error %d\n",
if (udev->authorized == 0)
dev_err(&udev->dev, "Device is not authorized for usage\n");
else {
c = usb_choose_configuration(udev);
if (c >= 0) {
err = usb_set_configuration(udev, c);
if (err) {
dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
/* This need not be fatal. The user can try to
* set other configurations. */
/* This need not be fatal. The user can try to
* set other configurations. */
}
}
}
/* USB device state == configured ... usable */
usb_notify_add_device(udev);
@ -203,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
*/
if (!udev->parent)
rc = hcd_bus_suspend(udev);
/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
rc = 0;
else
rc = usb_port_suspend(udev);
return rc;
}

View File

@ -356,10 +356,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
const u8 *bufp = tbuf;
int len = 0;
int patch_wakeup = 0;
unsigned long flags;
int status = 0;
int status;
int n;
might_sleep();
spin_lock_irq(&hcd_root_hub_lock);
status = usb_hcd_link_urb_to_ep(hcd, urb);
spin_unlock_irq(&hcd_root_hub_lock);
if (status)
return status;
urb->hcpriv = hcd; /* Indicate it's queued */
cmd = (struct usb_ctrlrequest *) urb->setup_packet;
typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
wValue = le16_to_cpu (cmd->wValue);
@ -523,13 +531,18 @@ error:
}
/* any errors get returned through the urb completion */
local_irq_save (flags);
spin_lock (&urb->lock);
if (urb->status == -EINPROGRESS)
urb->status = status;
spin_unlock (&urb->lock);
usb_hcd_giveback_urb (hcd, urb);
local_irq_restore (flags);
spin_lock_irq(&hcd_root_hub_lock);
usb_hcd_unlink_urb_from_ep(hcd, urb);
/* This peculiar use of spinlocks echoes what real HC drivers do.
* Avoiding calls to local_irq_disable/enable makes the code
* RT-friendly.
*/
spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb, status);
spin_lock(&hcd_root_hub_lock);
spin_unlock_irq(&hcd_root_hub_lock);
return 0;
}
@ -559,31 +572,23 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
if (length > 0) {
/* try to complete the status urb */
local_irq_save (flags);
spin_lock(&hcd_root_hub_lock);
spin_lock_irqsave(&hcd_root_hub_lock, flags);
urb = hcd->status_urb;
if (urb) {
spin_lock(&urb->lock);
if (urb->status == -EINPROGRESS) {
hcd->poll_pending = 0;
hcd->status_urb = NULL;
urb->status = 0;
urb->hcpriv = NULL;
urb->actual_length = length;
memcpy(urb->transfer_buffer, buffer, length);
} else /* urb has been unlinked */
length = 0;
spin_unlock(&urb->lock);
} else
length = 0;
spin_unlock(&hcd_root_hub_lock);
hcd->poll_pending = 0;
hcd->status_urb = NULL;
urb->actual_length = length;
memcpy(urb->transfer_buffer, buffer, length);
/* local irqs are always blocked in completions */
if (length > 0)
usb_hcd_giveback_urb (hcd, urb);
else
usb_hcd_unlink_urb_from_ep(hcd, urb);
spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb, 0);
spin_lock(&hcd_root_hub_lock);
} else {
length = 0;
hcd->poll_pending = 1;
local_irq_restore (flags);
}
spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
}
/* The USB 2.0 spec says 256 ms. This is close enough and won't
@ -611,33 +616,35 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
int len = 1 + (urb->dev->maxchild / 8);
spin_lock_irqsave (&hcd_root_hub_lock, flags);
if (urb->status != -EINPROGRESS) /* already unlinked */
retval = urb->status;
else if (hcd->status_urb || urb->transfer_buffer_length < len) {
if (hcd->status_urb || urb->transfer_buffer_length < len) {
dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
retval = -EINVAL;
} else {
hcd->status_urb = urb;
urb->hcpriv = hcd; /* indicate it's queued */
if (!hcd->uses_new_polling)
mod_timer (&hcd->rh_timer,
(jiffies/(HZ/4) + 1) * (HZ/4));
/* If a status change has already occurred, report it ASAP */
else if (hcd->poll_pending)
mod_timer (&hcd->rh_timer, jiffies);
retval = 0;
goto done;
}
retval = usb_hcd_link_urb_to_ep(hcd, urb);
if (retval)
goto done;
hcd->status_urb = urb;
urb->hcpriv = hcd; /* indicate it's queued */
if (!hcd->uses_new_polling)
mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
/* If a status change has already occurred, report it ASAP */
else if (hcd->poll_pending)
mod_timer(&hcd->rh_timer, jiffies);
retval = 0;
done:
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
return retval;
}
static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
{
if (usb_pipeint (urb->pipe))
if (usb_endpoint_xfer_int(&urb->ep->desc))
return rh_queue_status (hcd, urb);
if (usb_pipecontrol (urb->pipe))
if (usb_endpoint_xfer_control(&urb->ep->desc))
return rh_call_control (hcd, urb);
return -EINVAL;
}
@ -647,32 +654,96 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
/* Unlinks of root-hub control URBs are legal, but they don't do anything
* since these URBs always execute synchronously.
*/
static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
unsigned long flags;
int rc;
if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
spin_lock_irqsave(&hcd_root_hub_lock, flags);
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (rc)
goto done;
if (usb_endpoint_num(&urb->ep->desc) == 0) { /* Control URB */
; /* Do nothing */
} else { /* Status URB */
if (!hcd->uses_new_polling)
del_timer (&hcd->rh_timer);
local_irq_save (flags);
spin_lock (&hcd_root_hub_lock);
if (urb == hcd->status_urb) {
hcd->status_urb = NULL;
urb->hcpriv = NULL;
} else
urb = NULL; /* wasn't fully queued */
spin_unlock (&hcd_root_hub_lock);
if (urb)
usb_hcd_giveback_urb (hcd, urb);
local_irq_restore (flags);
}
usb_hcd_unlink_urb_from_ep(hcd, urb);
return 0;
spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb, status);
spin_lock(&hcd_root_hub_lock);
}
}
done:
spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
return rc;
}
/*
* Show & store the current value of authorized_default
*/
static ssize_t usb_host_authorized_default_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct usb_device *rh_usb_dev = to_usb_device(dev);
struct usb_bus *usb_bus = rh_usb_dev->bus;
struct usb_hcd *usb_hcd;
if (usb_bus == NULL) /* FIXME: not sure if this case is possible */
return -ENODEV;
usb_hcd = bus_to_hcd(usb_bus);
return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
}
static ssize_t usb_host_authorized_default_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
ssize_t result;
unsigned val;
struct usb_device *rh_usb_dev = to_usb_device(dev);
struct usb_bus *usb_bus = rh_usb_dev->bus;
struct usb_hcd *usb_hcd;
if (usb_bus == NULL) /* FIXME: not sure if this case is possible */
return -ENODEV;
usb_hcd = bus_to_hcd(usb_bus);
result = sscanf(buf, "%u\n", &val);
if (result == 1) {
usb_hcd->authorized_default = val? 1 : 0;
result = size;
}
else
result = -EINVAL;
return result;
}
static DEVICE_ATTR(authorized_default, 0644,
usb_host_authorized_default_show,
usb_host_authorized_default_store);
/* Group all the USB bus attributes */
static struct attribute *usb_bus_attrs[] = {
&dev_attr_authorized_default.attr,
NULL,
};
static struct attribute_group usb_bus_attr_group = {
.name = NULL, /* we want them in the same directory */
.attrs = usb_bus_attrs,
};
/*-------------------------------------------------------------------------*/
static struct class *usb_host_class;
@ -726,27 +797,23 @@ static void usb_bus_init (struct usb_bus *bus)
*/
static int usb_register_bus(struct usb_bus *bus)
{
int result = -E2BIG;
int busnum;
mutex_lock(&usb_bus_list_lock);
busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
if (busnum < USB_MAXBUS) {
set_bit (busnum, busmap.busmap);
bus->busnum = busnum;
} else {
if (busnum >= USB_MAXBUS) {
printk (KERN_ERR "%s: too many buses\n", usbcore_name);
mutex_unlock(&usb_bus_list_lock);
return -E2BIG;
goto error_find_busnum;
}
set_bit (busnum, busmap.busmap);
bus->busnum = busnum;
bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
bus->controller, "usb_host%d", busnum);
if (IS_ERR(bus->class_dev)) {
clear_bit(busnum, busmap.busmap);
mutex_unlock(&usb_bus_list_lock);
return PTR_ERR(bus->class_dev);
}
bus->controller, "usb_host%d",
busnum);
result = PTR_ERR(bus->class_dev);
if (IS_ERR(bus->class_dev))
goto error_create_class_dev;
class_set_devdata(bus->class_dev, bus);
/* Add it to the local list of buses */
@ -755,8 +822,15 @@ static int usb_register_bus(struct usb_bus *bus)
usb_notify_add_bus(bus);
dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
dev_info (bus->controller, "new USB bus registered, assigned bus "
"number %d\n", bus->busnum);
return 0;
error_create_class_dev:
clear_bit(busnum, busmap.busmap);
error_find_busnum:
mutex_unlock(&usb_bus_list_lock);
return result;
}
/**
@ -908,103 +982,145 @@ EXPORT_SYMBOL (usb_calc_bus_time);
/*-------------------------------------------------------------------------*/
static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
{
unsigned long flags;
/* clear all state linking urb to this dev (and hcd) */
spin_lock_irqsave(&hcd_urb_list_lock, flags);
list_del_init (&urb->urb_list);
spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
if (usb_pipecontrol (urb->pipe)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
dma_unmap_single (hcd->self.controller, urb->setup_dma,
sizeof (struct usb_ctrlrequest),
DMA_TO_DEVICE);
if (urb->transfer_buffer_length != 0
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
dma_unmap_single (hcd->self.controller,
urb->transfer_dma,
urb->transfer_buffer_length,
usb_pipein (urb->pipe)
? DMA_FROM_DEVICE
: DMA_TO_DEVICE);
}
}
/* may be called in any context with a valid urb->dev usecount
* caller surrenders "ownership" of urb
* expects usb_submit_urb() to have sanity checked and conditioned all
* inputs in the urb
/**
* usb_hcd_link_urb_to_ep - add an URB to its endpoint queue
* @hcd: host controller to which @urb was submitted
* @urb: URB being submitted
*
* Host controller drivers should call this routine in their enqueue()
* method. The HCD's private spinlock must be held and interrupts must
* be disabled. The actions carried out here are required for URB
* submission, as well as for endpoint shutdown and for usb_kill_urb.
*
* Returns 0 for no error, otherwise a negative error code (in which case
* the enqueue() method must fail). If no error occurs but enqueue() fails
* anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
* the private spinlock and returning.
*/
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
{
int status;
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
struct usb_host_endpoint *ep;
unsigned long flags;
int rc = 0;
if (!hcd)
return -ENODEV;
spin_lock(&hcd_urb_list_lock);
usbmon_urb_submit(&hcd->self, urb);
/*
* Atomically queue the urb, first to our records, then to the HCD.
* Access to urb->status is controlled by urb->lock ... changes on
* i/o completion (normal or fault) or unlinking.
*/
// FIXME: verify that quiescing hc works right (RH cleans up)
spin_lock_irqsave(&hcd_urb_list_lock, flags);
ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
[usb_pipeendpoint(urb->pipe)];
if (unlikely (!ep))
status = -ENOENT;
else if (unlikely (urb->reject))
status = -EPERM;
else switch (hcd->state) {
case HC_STATE_RUNNING:
case HC_STATE_RESUMING:
list_add_tail (&urb->urb_list, &ep->urb_list);
status = 0;
break;
default:
status = -ESHUTDOWN;
break;
}
spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
if (status) {
INIT_LIST_HEAD (&urb->urb_list);
usbmon_urb_submit_error(&hcd->self, urb, status);
return status;
}
/* increment urb's reference count as part of giving it to the HCD
* (which now controls it). HCD guarantees that it either returns
* an error or calls giveback(), but not both.
*/
urb = usb_get_urb (urb);
atomic_inc (&urb->use_count);
if (is_root_hub(urb->dev)) {
/* NOTE: requirement on hub callers (usbfs and the hub
* driver, for now) that URBs' urb->transfer_buffer be
* valid and usb_buffer_{sync,unmap}() not be needed, since
* they could clobber root hub response data.
*/
status = rh_urb_enqueue (hcd, urb);
/* Check that the URB isn't being killed */
if (unlikely(urb->reject)) {
rc = -EPERM;
goto done;
}
/* lower level hcd code should use *_dma exclusively,
if (unlikely(!urb->ep->enabled)) {
rc = -ENOENT;
goto done;
}
if (unlikely(!urb->dev->can_submit)) {
rc = -EHOSTUNREACH;
goto done;
}
/*
* Check the host controller's state and add the URB to the
* endpoint's queue.
*/
switch (hcd->state) {
case HC_STATE_RUNNING:
case HC_STATE_RESUMING:
urb->unlinked = 0;
list_add_tail(&urb->urb_list, &urb->ep->urb_list);
break;
default:
rc = -ESHUTDOWN;
goto done;
}
done:
spin_unlock(&hcd_urb_list_lock);
return rc;
}
EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
/**
* usb_hcd_check_unlink_urb - check whether an URB may be unlinked
* @hcd: host controller to which @urb was submitted
* @urb: URB being checked for unlinkability
* @status: error code to store in @urb if the unlink succeeds
*
* Host controller drivers should call this routine in their dequeue()
* method. The HCD's private spinlock must be held and interrupts must
* be disabled. The actions carried out here are required for making
* sure than an unlink is valid.
*
* Returns 0 for no error, otherwise a negative error code (in which case
* the dequeue() method must fail). The possible error codes are:
*
* -EIDRM: @urb was not submitted or has already completed.
* The completion function may not have been called yet.
*
* -EBUSY: @urb has already been unlinked.
*/
int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
int status)
{
struct list_head *tmp;
/* insist the urb is still queued */
list_for_each(tmp, &urb->ep->urb_list) {
if (tmp == &urb->urb_list)
break;
}
if (tmp != &urb->urb_list)
return -EIDRM;
/* Any status except -EINPROGRESS means something already started to
* unlink this URB from the hardware. So there's no more work to do.
*/
if (urb->unlinked)
return -EBUSY;
urb->unlinked = status;
/* IRQ setup can easily be broken so that USB controllers
* never get completion IRQs ... maybe even the ones we need to
* finish unlinking the initial failed usb_set_address()
* or device descriptor fetch.
*/
if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
!is_root_hub(urb->dev)) {
dev_warn(hcd->self.controller, "Unlink after no-IRQ? "
"Controller is probably using the wrong IRQ.\n");
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
}
return 0;
}
EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
/**
* usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
* @hcd: host controller to which @urb was submitted
* @urb: URB being unlinked
*
* Host controller drivers should call this routine before calling
* usb_hcd_giveback_urb(). The HCD's private spinlock must be held and
* interrupts must be disabled. The actions carried out here are required
* for URB completion.
*/
void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
{
/* clear all state linking urb to this dev (and hcd) */
spin_lock(&hcd_urb_list_lock);
list_del_init(&urb->urb_list);
spin_unlock(&hcd_urb_list_lock);
}
EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
/* Map the URB's buffers for DMA access.
* Lower level HCD code should use *_dma exclusively,
* unless it uses pio or talks to another transport.
*/
if (hcd->self.uses_dma) {
if (usb_pipecontrol (urb->pipe)
if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
if (usb_endpoint_xfer_control(&urb->ep->desc)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
urb->setup_dma = dma_map_single (
hcd->self.controller,
@ -1017,20 +1133,75 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
hcd->self.controller,
urb->transfer_buffer,
urb->transfer_buffer_length,
usb_pipein (urb->pipe)
usb_urb_dir_in(urb)
? DMA_FROM_DEVICE
: DMA_TO_DEVICE);
}
}
status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
done:
if (unlikely (status)) {
urb_unlink(hcd, urb);
atomic_dec (&urb->use_count);
if (urb->reject)
wake_up (&usb_kill_urb_queue);
static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
{
if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
if (usb_endpoint_xfer_control(&urb->ep->desc)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
dma_unmap_single(hcd->self.controller, urb->setup_dma,
sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
if (urb->transfer_buffer_length != 0
&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
dma_unmap_single(hcd->self.controller,
urb->transfer_dma,
urb->transfer_buffer_length,
usb_urb_dir_in(urb)
? DMA_FROM_DEVICE
: DMA_TO_DEVICE);
}
}
/*-------------------------------------------------------------------------*/
/* may be called in any context with a valid urb->dev usecount
* caller surrenders "ownership" of urb
* expects usb_submit_urb() to have sanity checked and conditioned all
* inputs in the urb
*/
int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
{
int status;
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
/* increment urb's reference count as part of giving it to the HCD
* (which will control it). HCD guarantees that it either returns
* an error or calls giveback(), but not both.
*/
usb_get_urb(urb);
atomic_inc(&urb->use_count);
atomic_inc(&urb->dev->urbnum);
usbmon_urb_submit(&hcd->self, urb);
/* NOTE requirements on root-hub callers (usbfs and the hub
* driver, for now): URBs' urb->transfer_buffer must be
* valid and usb_buffer_{sync,unmap}() not be needed, since
* they could clobber root hub response data. Also, control
* URBs must be submitted in process context with interrupts
* enabled.
*/
map_urb_for_dma(hcd, urb);
if (is_root_hub(urb->dev))
status = rh_urb_enqueue(hcd, urb);
else
status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
if (unlikely(status)) {
usbmon_urb_submit_error(&hcd->self, urb, status);
usb_put_urb (urb);
unmap_urb_for_dma(hcd, urb);
urb->hcpriv = NULL;
INIT_LIST_HEAD(&urb->urb_list);
atomic_dec(&urb->use_count);
atomic_dec(&urb->dev->urbnum);
if (urb->reject)
wake_up(&usb_kill_urb_queue);
usb_put_urb(urb);
}
return status;
}
@ -1042,24 +1213,19 @@ done:
* soon as practical. we've already set up the urb's return status,
* but we can't know if the callback completed already.
*/
static int
unlink1 (struct usb_hcd *hcd, struct urb *urb)
static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
{
int value;
if (is_root_hub(urb->dev))
value = usb_rh_urb_dequeue (hcd, urb);
value = usb_rh_urb_dequeue(hcd, urb, status);
else {
/* The only reason an HCD might fail this call is if
* it has not yet fully queued the urb to begin with.
* Such failures should be harmless. */
value = hcd->driver->urb_dequeue (hcd, urb);
value = hcd->driver->urb_dequeue(hcd, urb, status);
}
if (value != 0)
dev_dbg (hcd->self.controller, "dequeue %p --> %d\n",
urb, value);
return value;
}
@ -1071,88 +1237,17 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
*/
int usb_hcd_unlink_urb (struct urb *urb, int status)
{
struct usb_host_endpoint *ep;
struct usb_hcd *hcd = NULL;
struct device *sys = NULL;
unsigned long flags;
struct list_head *tmp;
int retval;
struct usb_hcd *hcd;
int retval;
if (!urb)
return -EINVAL;
if (!urb->dev || !urb->dev->bus)
return -ENODEV;
ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
[usb_pipeendpoint(urb->pipe)];
if (!ep)
return -ENODEV;
/*
* we contend for urb->status with the hcd core,
* which changes it while returning the urb.
*
* Caller guaranteed that the urb pointer hasn't been freed, and
* that it was submitted. But as a rule it can't know whether or
* not it's already been unlinked ... so we respect the reversed
* lock sequence needed for the usb_hcd_giveback_urb() code paths
* (urb lock, then hcd_urb_list_lock) in case some other CPU is now
* unlinking it.
*/
spin_lock_irqsave (&urb->lock, flags);
spin_lock(&hcd_urb_list_lock);
sys = &urb->dev->dev;
hcd = bus_to_hcd(urb->dev->bus);
if (hcd == NULL) {
retval = -ENODEV;
goto done;
}
retval = unlink1(hcd, urb, status);
/* insist the urb is still queued */
list_for_each(tmp, &ep->urb_list) {
if (tmp == &urb->urb_list)
break;
}
if (tmp != &urb->urb_list) {
retval = -EIDRM;
goto done;
}
/* Any status except -EINPROGRESS means something already started to
* unlink this URB from the hardware. So there's no more work to do.
*/
if (urb->status != -EINPROGRESS) {
retval = -EBUSY;
goto done;
}
/* IRQ setup can easily be broken so that USB controllers
* never get completion IRQs ... maybe even the ones we need to
* finish unlinking the initial failed usb_set_address()
* or device descriptor fetch.
*/
if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
!is_root_hub(urb->dev)) {
dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
"Controller is probably using the wrong IRQ.\n");
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
}
urb->status = status;
spin_unlock(&hcd_urb_list_lock);
spin_unlock_irqrestore (&urb->lock, flags);
retval = unlink1 (hcd, urb);
if (retval == 0)
retval = -EINPROGRESS;
return retval;
done:
spin_unlock(&hcd_urb_list_lock);
spin_unlock_irqrestore (&urb->lock, flags);
if (retval != -EIDRM && sys && sys->driver)
dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
else if (retval != -EIDRM && retval != -EBUSY)
dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
urb, retval);
return retval;
}
@ -1162,6 +1257,7 @@ done:
* usb_hcd_giveback_urb - return URB from HCD to device driver
* @hcd: host controller returning the URB
* @urb: urb being returned to the USB device driver.
* @status: completion status code for the URB.
* Context: in_interrupt()
*
* This hands the URB from HCD to its USB device driver, using its
@ -1169,14 +1265,27 @@ done:
* (and is done using urb->hcpriv). It also released all HCD locks;
* the device driver won't cause problems if it frees, modifies,
* or resubmits this URB.
*
* If @urb was unlinked, the value of @status will be overridden by
* @urb->unlinked. Erroneous short transfers are detected in case
* the HCD hasn't checked for them.
*/
void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
{
urb_unlink(hcd, urb);
usbmon_urb_complete (&hcd->self, urb);
urb->hcpriv = NULL;
if (unlikely(urb->unlinked))
status = urb->unlinked;
else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
urb->actual_length < urb->transfer_buffer_length &&
!status))
status = -EREMOTEIO;
unmap_urb_for_dma(hcd, urb);
usbmon_urb_complete(&hcd->self, urb, status);
usb_unanchor_urb(urb);
/* pass ownership to the completion handler */
urb->status = status;
urb->complete (urb);
atomic_dec (&urb->use_count);
if (unlikely (urb->reject))
@ -1187,78 +1296,61 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb);
/*-------------------------------------------------------------------------*/
/* disables the endpoint: cancels any pending urbs, then synchronizes with
* the hcd to make sure all endpoint state is gone from hardware, and then
* waits until the endpoint's queue is completely drained. use for
* set_configuration, set_interface, driver removal, physical disconnect.
*
* example: a qh stored in ep->hcpriv, holding state related to endpoint
* type, maxpacket size, toggle, halt status, and scheduling.
/* Cancel all URBs pending on this endpoint and wait for the endpoint's
* queue to drain completely. The caller must first insure that no more
* URBs can be submitted for this endpoint.
*/
void usb_hcd_endpoint_disable (struct usb_device *udev,
void usb_hcd_flush_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
struct usb_hcd *hcd;
struct urb *urb;
if (!ep)
return;
might_sleep();
hcd = bus_to_hcd(udev->bus);
local_irq_disable ();
/* ep is already gone from udev->ep_{in,out}[]; no more submits */
/* No more submits can occur */
rescan:
spin_lock(&hcd_urb_list_lock);
spin_lock_irq(&hcd_urb_list_lock);
list_for_each_entry (urb, &ep->urb_list, urb_list) {
int tmp;
int is_in;
/* the urb may already have been unlinked */
if (urb->status != -EINPROGRESS)
if (urb->unlinked)
continue;
usb_get_urb (urb);
is_in = usb_urb_dir_in(urb);
spin_unlock(&hcd_urb_list_lock);
spin_lock (&urb->lock);
tmp = urb->status;
if (tmp == -EINPROGRESS)
urb->status = -ESHUTDOWN;
spin_unlock (&urb->lock);
/* kick hcd */
unlink1(hcd, urb, -ESHUTDOWN);
dev_dbg (hcd->self.controller,
"shutdown urb %p ep%d%s%s\n",
urb, usb_endpoint_num(&ep->desc),
is_in ? "in" : "out",
({ char *s;
/* kick hcd unless it's already returning this */
if (tmp == -EINPROGRESS) {
tmp = urb->pipe;
unlink1 (hcd, urb);
dev_dbg (hcd->self.controller,
"shutdown urb %p pipe %08x ep%d%s%s\n",
urb, tmp, usb_pipeendpoint (tmp),
(tmp & USB_DIR_IN) ? "in" : "out",
({ char *s; \
switch (usb_pipetype (tmp)) { \
case PIPE_CONTROL: s = ""; break; \
case PIPE_BULK: s = "-bulk"; break; \
case PIPE_INTERRUPT: s = "-intr"; break; \
default: s = "-iso"; break; \
}; s;}));
}
switch (usb_endpoint_type(&ep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
s = ""; break;
case USB_ENDPOINT_XFER_BULK:
s = "-bulk"; break;
case USB_ENDPOINT_XFER_INT:
s = "-intr"; break;
default:
s = "-iso"; break;
};
s;
}));
usb_put_urb (urb);
/* list contents may have changed */
goto rescan;
}
spin_unlock(&hcd_urb_list_lock);
local_irq_enable ();
spin_unlock_irq(&hcd_urb_list_lock);
/* synchronize with the hardware, so old configuration state
* clears out immediately (and will be freed).
*/
might_sleep ();
if (hcd->driver->endpoint_disable)
hcd->driver->endpoint_disable (hcd, ep);
/* Wait until the endpoint queue is completely empty. Most HCDs
* will have done this already in their endpoint_disable method,
* but some might not. And there could be root-hub control URBs
* still pending since they aren't affected by the HCDs'
* endpoint_disable methods.
*/
/* Wait until the endpoint queue is completely empty */
while (!list_empty (&ep->urb_list)) {
spin_lock_irq(&hcd_urb_list_lock);
@ -1278,6 +1370,25 @@ rescan:
}
}
/* Disables the endpoint: synchronizes with the hcd to make sure all
* endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
* have been called previously. Use for set_configuration, set_interface,
* driver removal, physical disconnect.
*
* example: a qh stored in ep->hcpriv, holding state related to endpoint
* type, maxpacket size, toggle, halt status, and scheduling.
*/
void usb_hcd_disable_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
struct usb_hcd *hcd;
might_sleep();
hcd = bus_to_hcd(udev->bus);
if (hcd->driver->endpoint_disable)
hcd->driver->endpoint_disable(hcd, ep);
}
/*-------------------------------------------------------------------------*/
/* called in any context */
@ -1525,7 +1636,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
hcd->driver = driver;
hcd->product_desc = (driver->product_desc) ? driver->product_desc :
"USB Host Controller";
return hcd;
}
EXPORT_SYMBOL (usb_create_hcd);
@ -1570,6 +1680,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
hcd->authorized_default = hcd->wireless? 0 : 1;
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
/* HC is in reset state, but accessible. Now do the one-time init,
@ -1646,10 +1757,20 @@ int usb_add_hcd(struct usb_hcd *hcd,
if ((retval = register_root_hub(hcd)) != 0)
goto err_register_root_hub;
retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
if (retval < 0) {
printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
retval);
goto error_create_attr_group;
}
if (hcd->uses_new_polling && hcd->poll_rh)
usb_hcd_poll_rh_status(hcd);
return retval;
error_create_attr_group:
mutex_lock(&usb_bus_list_lock);
usb_disconnect(&hcd->self.root_hub);
mutex_unlock(&usb_bus_list_lock);
err_register_root_hub:
hcd->driver->stop(hcd);
err_hcd_driver_start:
@ -1691,6 +1812,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
cancel_work_sync(&hcd->wakeup_work);
#endif
sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
mutex_lock(&usb_bus_list_lock);
usb_disconnect(&hcd->self.root_hub);
mutex_unlock(&usb_bus_list_lock);

View File

@ -19,6 +19,8 @@
#ifdef __KERNEL__
#include <linux/rwsem.h>
/* This file contains declarations of usbcore internals that are mostly
* used or exposed by Host Controller Drivers.
*/
@ -51,6 +53,12 @@
*
* Since "struct usb_bus" is so thin, you can't share much code in it.
* This framework is a layer over that, and should be more sharable.
*
* @authorized_default: Specifies if new devices are authorized to
* connect by default or they require explicit
* user space authorization; this bit is settable
* through /sys/class/usb_host/X/authorized_default.
* For the rest is RO, so we don't lock to r/w it.
*/
/*-------------------------------------------------------------------------*/
@ -90,6 +98,7 @@ struct usb_hcd {
unsigned poll_rh:1; /* poll for rh status? */
unsigned poll_pending:1; /* status has changed? */
unsigned wireless:1; /* Wireless USB HCD */
unsigned authorized_default:1;
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
@ -182,11 +191,10 @@ struct hc_driver {
int (*get_frame_number) (struct usb_hcd *hcd);
/* manage i/o requests, device state */
int (*urb_enqueue) (struct usb_hcd *hcd,
struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags);
int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
int (*urb_enqueue)(struct usb_hcd *hcd,
struct urb *urb, gfp_t mem_flags);
int (*urb_dequeue)(struct usb_hcd *hcd,
struct urb *urb, int status);
/* hw synch, freeing endpoint resources that urb_dequeue can't */
void (*endpoint_disable)(struct usb_hcd *hcd,
@ -204,10 +212,18 @@ struct hc_driver {
/* Needed only if port-change IRQs are level-triggered */
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
int status);
extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
extern int usb_hcd_unlink_urb (struct urb *urb, int status);
extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
extern void usb_hcd_endpoint_disable (struct usb_device *udev,
extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
int status);
extern void usb_hcd_flush_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
extern void usb_hcd_disable_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
extern int usb_hcd_get_frame_number (struct usb_device *udev);
@ -402,7 +418,7 @@ static inline void usbfs_cleanup(void) { }
struct usb_mon_operations {
void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status);
/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
};
@ -421,10 +437,11 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
(*mon_ops->urb_submit_error)(bus, urb, error);
}
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
int status)
{
if (bus->monitored)
(*mon_ops->urb_complete)(bus, urb);
(*mon_ops->urb_complete)(bus, urb, status);
}
int usb_mon_register(struct usb_mon_operations *ops);
@ -435,7 +452,8 @@ void usb_mon_deregister(void);
static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
int error) {}
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
int status) {}
#endif /* CONFIG_USB_MON */
@ -454,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
: (in_interrupt () ? "in_interrupt" : "can sleep"))
#endif /* __KERNEL__ */
/* This rwsem is for use only by the hub driver and ehci-hcd.
* Nobody else should touch it.
*/
extern struct rw_semaphore ehci_cf_port_reset_rwsem;
#endif /* __KERNEL__ */

View File

@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes,
"try the other device initialization scheme if the "
"first one fails");
/* Mutual exclusion for EHCI CF initialization. This interferes with
* port reset on some companion controllers.
*/
DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
static inline char *portspeed(int portstatus)
{
@ -347,11 +353,11 @@ void usb_kick_khubd(struct usb_device *hdev)
static void hub_irq(struct urb *urb)
{
struct usb_hub *hub = urb->context;
int status;
int status = urb->status;
int i;
unsigned long bits;
switch (urb->status) {
switch (status) {
case -ENOENT: /* synchronous unlink */
case -ECONNRESET: /* async unlink */
case -ESHUTDOWN: /* hardware going away */
@ -359,10 +365,10 @@ static void hub_irq(struct urb *urb)
default: /* presumably an error */
/* Cause a hub reset after 10 consecutive errors */
dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status);
dev_dbg (hub->intfdev, "transfer --> %d\n", status);
if ((++hub->nerrors < 10) || hub->error)
goto resubmit;
hub->error = urb->status;
hub->error = status;
/* FALL THROUGH */
/* let khubd handle things */
@ -1220,54 +1226,14 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
#endif
/**
* usb_new_device - perform initial device setup (usbcore-internal)
* usb_configure_device_otg - FIXME (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
* This is called with devices which have been enumerated, but not yet
* configured. The device descriptor is available, but not descriptors
* for any device configuration. The caller must have locked either
* the parent hub (if udev is a normal device) or else the
* usb_bus_list_lock (if udev is a root hub). The parent's pointer to
* udev has already been installed, but udev is not yet visible through
* sysfs or other filesystem code.
*
* It will return if the device is configured properly or not. Zero if
* the interface was registered with the driver core; else a negative
* errno value.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver or root-hub registrar should ever call this.
* Do configuration for On-The-Go devices
*/
int usb_new_device(struct usb_device *udev)
static int usb_configure_device_otg(struct usb_device *udev)
{
int err;
/* Determine quirks */
usb_detect_quirks(udev);
err = usb_get_configuration(udev);
if (err < 0) {
dev_err(&udev->dev, "can't read configurations, error %d\n",
err);
goto fail;
}
/* read the standard strings and cache them if present */
udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
udev->manufacturer = usb_cache_string(udev,
udev->descriptor.iManufacturer);
udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
/* Tell the world! */
dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
"SerialNumber=%d\n",
udev->descriptor.iManufacturer,
udev->descriptor.iProduct,
udev->descriptor.iSerialNumber);
show_string(udev, "Product", udev->product);
show_string(udev, "Manufacturer", udev->manufacturer);
show_string(udev, "SerialNumber", udev->serial);
int err = 0;
#ifdef CONFIG_USB_OTG
/*
@ -1329,8 +1295,82 @@ int usb_new_device(struct usb_device *udev)
err = -ENOTSUPP;
goto fail;
}
fail:
#endif
return err;
}
/**
* usb_configure_device - Detect and probe device intfs/otg (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
* This is only called by usb_new_device() and usb_authorize_device()
* and FIXME -- all comments that apply to them apply here wrt to
* environment.
*
* If the device is WUSB and not authorized, we don't attempt to read
* the string descriptors, as they will be errored out by the device
* until it has been authorized.
*/
static int usb_configure_device(struct usb_device *udev)
{
int err;
if (udev->config == NULL) {
err = usb_get_configuration(udev);
if (err < 0) {
dev_err(&udev->dev, "can't read configurations, error %d\n",
err);
goto fail;
}
}
if (udev->wusb == 1 && udev->authorized == 0) {
udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
}
else {
/* read the standard strings and cache them if present */
udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
udev->manufacturer = usb_cache_string(udev,
udev->descriptor.iManufacturer);
udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
}
err = usb_configure_device_otg(udev);
fail:
return err;
}
/**
* usb_new_device - perform initial device setup (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
* This is called with devices which have been enumerated, but not yet
* configured. The device descriptor is available, but not descriptors
* for any device configuration. The caller must have locked either
* the parent hub (if udev is a normal device) or else the
* usb_bus_list_lock (if udev is a root hub). The parent's pointer to
* udev has already been installed, but udev is not yet visible through
* sysfs or other filesystem code.
*
* It will return if the device is configured properly or not. Zero if
* the interface was registered with the driver core; else a negative
* errno value.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver or root-hub registrar should ever call this.
*/
int usb_new_device(struct usb_device *udev)
{
int err;
usb_detect_quirks(udev); /* Determine quirks */
err = usb_configure_device(udev); /* detect & probe dev/intfs */
if (err < 0)
goto fail;
/* export the usbdev device-node for libusb */
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
@ -1346,19 +1386,106 @@ int usb_new_device(struct usb_device *udev)
err = device_add(&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
if (udev->parent)
usb_autosuspend_device(udev->parent);
goto fail;
}
exit:
/* Tell the world! */
dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
"SerialNumber=%d\n",
udev->descriptor.iManufacturer,
udev->descriptor.iProduct,
udev->descriptor.iSerialNumber);
show_string(udev, "Product", udev->product);
show_string(udev, "Manufacturer", udev->manufacturer);
show_string(udev, "SerialNumber", udev->serial);
return err;
fail:
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
goto exit;
return err;
}
/**
* Similar to usb_disconnect()
*
* We share a lock (that we have) with device_del(), so we need to
* defer its call.
*/
int usb_deauthorize_device(struct usb_device *usb_dev)
{
unsigned cnt;
usb_lock_device(usb_dev);
if (usb_dev->authorized == 0)
goto out_unauthorized;
usb_dev->authorized = 0;
usb_set_configuration(usb_dev, -1);
usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
kfree(usb_dev->config);
usb_dev->config = NULL;
for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
kfree(usb_dev->rawdescriptors[cnt]);
usb_dev->descriptor.bNumConfigurations = 0;
kfree(usb_dev->rawdescriptors);
out_unauthorized:
usb_unlock_device(usb_dev);
return 0;
}
int usb_authorize_device(struct usb_device *usb_dev)
{
int result = 0, c;
usb_lock_device(usb_dev);
if (usb_dev->authorized == 1)
goto out_authorized;
kfree(usb_dev->product);
usb_dev->product = NULL;
kfree(usb_dev->manufacturer);
usb_dev->manufacturer = NULL;
kfree(usb_dev->serial);
usb_dev->serial = NULL;
result = usb_autoresume_device(usb_dev);
if (result < 0) {
dev_err(&usb_dev->dev,
"can't autoresume for authorization: %d\n", result);
goto error_autoresume;
}
result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
if (result < 0) {
dev_err(&usb_dev->dev, "can't re-read device descriptor for "
"authorization: %d\n", result);
goto error_device_descriptor;
}
usb_dev->authorized = 1;
result = usb_configure_device(usb_dev);
if (result < 0)
goto error_configure;
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
c = usb_choose_configuration(usb_dev);
if (c >= 0) {
result = usb_set_configuration(usb_dev, c);
if (result) {
dev_err(&usb_dev->dev,
"can't set config #%d, error %d\n", c, result);
/* This need not be fatal. The user can try to
* set other configurations. */
}
}
dev_info(&usb_dev->dev, "authorized to connect\n");
error_configure:
error_device_descriptor:
error_autoresume:
out_authorized:
usb_unlock_device(usb_dev); // complements locktree
return result;
}
static int hub_port_status(struct usb_hub *hub, int port1,
u16 *status, u16 *change)
{
@ -1460,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
{
int i, status;
/* Block EHCI CF initialization during the port reset.
* Some companion controllers don't like it when they mix.
*/
down_read(&ehci_cf_port_reset_rwsem);
/* Reset the port */
for (i = 0; i < PORT_RESET_TRIES; i++) {
status = set_port_feature(hub->hdev,
@ -1481,6 +1613,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
case 0:
/* TRSTRCY = 10 ms; plus some extra */
msleep(10 + 40);
udev->devnum = 0; /* Device now at address 0 */
/* FALL THROUGH */
case -ENOTCONN:
case -ENODEV:
@ -1490,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
usb_set_device_state(udev, status
? USB_STATE_NOTATTACHED
: USB_STATE_DEFAULT);
return status;
goto done;
}
dev_dbg (hub->intfdev,
@ -1503,6 +1636,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
"Cannot enable port %i. Maybe the USB cable is bad?\n",
port1);
done:
up_read(&ehci_cf_port_reset_rwsem);
return status;
}
@ -1833,14 +1968,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_device *udev;
udev = hdev->children [port1-1];
if (udev && msg.event == PM_EVENT_SUSPEND &&
#ifdef CONFIG_USB_SUSPEND
udev->state != USB_STATE_SUSPENDED
#else
udev->dev.power.power_state.event
== PM_EVENT_ON
#endif
) {
if (udev && udev->can_submit) {
if (!hdev->auto_pm)
dev_dbg(&intf->dev, "port %d nyet suspended\n",
port1);
@ -1999,26 +2127,27 @@ static void ep0_reinit(struct usb_device *udev)
{
usb_disable_endpoint(udev, 0 + USB_DIR_IN);
usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;
usb_enable_endpoint(udev, &udev->ep0);
}
#define usb_sndaddr0pipe() (PIPE_CONTROL << 30)
#define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN)
static int hub_set_address(struct usb_device *udev)
static int hub_set_address(struct usb_device *udev, int devnum)
{
int retval;
if (udev->devnum == 0)
if (devnum <= 1)
return -EINVAL;
if (udev->state == USB_STATE_ADDRESS)
return 0;
if (udev->state != USB_STATE_DEFAULT)
return -EINVAL;
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
USB_REQ_SET_ADDRESS, 0, devnum, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval == 0) {
udev->devnum = devnum; /* Device now using proper address */
usb_set_device_state(udev, USB_STATE_ADDRESS);
ep0_reinit(udev);
}
@ -2045,6 +2174,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
char *speed, *type;
int devnum = udev->devnum;
/* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5)
@ -2074,7 +2204,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}
oldspeed = udev->speed;
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
* For Wireless USB devices, ep0 max packet is always 512 (tho
@ -2115,7 +2245,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
dev_info (&udev->dev,
"%s %s speed %sUSB device using %s and address %d\n",
(udev->config) ? "reset" : "new", speed, type,
udev->bus->controller->driver->name, udev->devnum);
udev->bus->controller->driver->name, devnum);
/* Set up TT records, if needed */
if (hdev->tt) {
@ -2202,7 +2332,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
}
for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
retval = hub_set_address(udev);
retval = hub_set_address(udev, devnum);
if (retval >= 0)
break;
msleep(200);
@ -2210,7 +2340,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval < 0) {
dev_err(&udev->dev,
"device not accepting address %d, error %d\n",
udev->devnum, retval);
devnum, retval);
goto fail;
}
@ -2263,8 +2393,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
retval = 0;
fail:
if (retval)
if (retval) {
hub_port_disable(hub, port1, 0);
udev->devnum = devnum; /* for disconnect processing */
}
mutex_unlock(&usb_address0_mutex);
return retval;
}
@ -2699,9 +2831,9 @@ static void hub_events(void)
clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
if (hubstatus & HUB_STATUS_LOCAL_POWER)
/* FIXME: Is this always true? */
hub->limited_power = 0;
else
hub->limited_power = 1;
else
hub->limited_power = 0;
}
if (hubchange & HUB_CHANGE_OVERCURRENT) {
dev_dbg (hub_dev, "overcurrent change\n");

View File

@ -59,8 +59,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
dev_dbg(&urb->dev->dev,
"%s timed out on ep%d%s len=%d/%d\n",
current->comm,
usb_pipeendpoint(urb->pipe),
usb_pipein(urb->pipe) ? "in" : "out",
usb_endpoint_num(&urb->ep->desc),
usb_urb_dir_in(urb) ? "in" : "out",
urb->actual_length,
urb->transfer_buffer_length);
} else
@ -250,7 +250,8 @@ static void sg_clean (struct usb_sg_request *io)
io->urbs = NULL;
}
if (io->dev->dev.dma_mask != NULL)
usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe),
io->sg, io->nents);
io->dev = NULL;
}
@ -278,8 +279,8 @@ static void sg_complete (struct urb *urb)
dev_err (io->dev->bus->controller,
"dev %s ep%d%s scatterlist error %d/%d\n",
io->dev->devpath,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
usb_endpoint_num(&urb->ep->desc),
usb_urb_dir_in(urb) ? "in" : "out",
status, io->status);
// BUG ();
}
@ -379,7 +380,8 @@ int usb_sg_init (
*/
dma = (dev->dev.dma_mask != NULL);
if (dma)
io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
sg, nents);
else
io->entries = nents;
@ -1013,8 +1015,11 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
ep = dev->ep_in[epnum];
dev->ep_in[epnum] = NULL;
}
if (ep && dev->bus)
usb_hcd_endpoint_disable(dev, ep);
if (ep) {
ep->enabled = 0;
usb_hcd_flush_endpoint(dev, ep);
usb_hcd_disable_endpoint(dev, ep);
}
}
/**
@ -1096,23 +1101,21 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
* Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
* For control endpoints, both the input and output sides are handled.
*/
static void
usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
{
unsigned int epaddr = ep->desc.bEndpointAddress;
unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
int is_control;
int epnum = usb_endpoint_num(&ep->desc);
int is_out = usb_endpoint_dir_out(&ep->desc);
int is_control = usb_endpoint_xfer_control(&ep->desc);
is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_CONTROL);
if (usb_endpoint_out(epaddr) || is_control) {
if (is_out || is_control) {
usb_settoggle(dev, epnum, 1, 0);
dev->ep_out[epnum] = ep;
}
if (!usb_endpoint_out(epaddr) || is_control) {
if (!is_out || is_control) {
usb_settoggle(dev, epnum, 0, 0);
dev->ep_in[epnum] = ep;
}
ep->enabled = 1;
}
/*
@ -1171,6 +1174,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
struct usb_host_interface *alt;
int ret;
int manual = 0;
int changed;
if (dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
@ -1210,7 +1214,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
*/
/* prevent submissions using previous endpoint settings */
if (device_is_registered(&iface->dev))
changed = (iface->cur_altsetting != alt);
if (changed && device_is_registered(&iface->dev))
usb_remove_sysfs_intf_files(iface);
usb_disable_interface(dev, iface);
@ -1247,7 +1252,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
* (Likewise, EP0 never "halts" on well designed devices.)
*/
usb_enable_interface(dev, iface);
if (device_is_registered(&iface->dev))
if (changed && device_is_registered(&iface->dev))
usb_create_sysfs_intf_files(iface);
return 0;
@ -1328,7 +1333,7 @@ int usb_reset_configuration(struct usb_device *dev)
return 0;
}
void usb_release_interface(struct device *dev)
static void usb_release_interface(struct device *dev)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_interface_cache *intfc =
@ -1481,6 +1486,9 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
* channels are available independently; and choosing between open
* standard device protocols (like CDC) or proprietary ones.
*
* Note that a non-authorized device (dev->authorized == 0) will only
* be put in unconfigured mode.
*
* Note that USB has an additional level of device configurability,
* associated with interfaces. That configurability is accessed using
* usb_set_interface().
@ -1502,7 +1510,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
struct usb_interface **new_interfaces = NULL;
int n, nintf;
if (configuration == -1)
if (dev->authorized == 0 || configuration == -1)
configuration = 0;
else {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {

View File

@ -32,52 +32,6 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
/* HP 5300/5370C scanner */
{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
/* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */
{ USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* SGS Thomson Microelectronics 4in1 card reader */
{ USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */
{ USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Benq S2W 3300U */
{ USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Canon, Inc. CanoScan N1240U/LiDE30 */
{ USB_DEVICE(0x04a9, 0x220e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Canon, Inc. CanoScan N650U/N656U */
{ USB_DEVICE(0x04a9, 0x2206), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Canon, Inc. CanoScan 1220U */
{ USB_DEVICE(0x04a9, 0x2207), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Canon, Inc. CanoScan N670U/N676U/LiDE 20 */
{ USB_DEVICE(0x04a9, 0x220d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* old Cannon scanner */
{ USB_DEVICE(0x04a9, 0x2220), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Seiko Epson Corp. Perfection 1200 */
{ USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Seiko Epson Corp. Perfection 660 */
{ USB_DEVICE(0x04b8, 0x0114), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Epson Perfection 1260 Photo */
{ USB_DEVICE(0x04b8, 0x011d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Seiko Epson Corp - Perfection 1670 */
{ USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* EPSON Perfection 2480 */
{ USB_DEVICE(0x04b8, 0x0121), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Seiko Epson Corp.*/
{ USB_DEVICE(0x04b8, 0x0122), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Samsung ML-2010 printer */
{ USB_DEVICE(0x04e8, 0x326c), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Samsung ML-2510 Series printer */
{ USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Elsa MicroLink 56k (V.250) */
{ USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Ultima Electronics Corp.*/
{ USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Genesys USB-to-IDE */
{ USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* USB Graphical LCD - EEH Datalink GmbH */
{ USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* INTEL VALUE SSD */
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
@ -85,44 +39,15 @@ static const struct usb_device_id usb_quirk_list[] = {
/* M-Systems Flash Disk Pioneers */
{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
/* Agfa Snapscan1212u */
{ USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Seagate RSS LLC */
{ USB_DEVICE(0x0bc2, 0x3000), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Umax [hex] Astra 3400U */
{ USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Philips PSC805 audio device */
{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
/* Alcor multi-card reader */
{ USB_DEVICE(0x058f, 0x6366), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Canon EOS 5D in PC Connection mode */
{ USB_DEVICE(0x04a9, 0x3101), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* RIM Blackberry */
{ USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
{ USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
{ USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* Apple iPhone */
{ USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
/* SKYMEDI USB_DRIVE */
{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
{ } /* terminating entry must be last */
};
static void usb_autosuspend_quirk(struct usb_device *udev)
{
#ifdef CONFIG_USB_SUSPEND
/* disable autosuspend, but allow the user to re-enable it via sysfs */
udev->autosuspend_disabled = 1;
#endif
}
static const struct usb_device_id *find_id(struct usb_device *udev)
{
const struct usb_device_id *id = usb_quirk_list;
@ -149,13 +74,9 @@ void usb_detect_quirks(struct usb_device *udev)
dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
udev->quirks);
/* do any special quirk handling here if needed */
if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
usb_autosuspend_quirk(udev);
/* By default, disable autosuspend for all non-hubs */
#ifdef CONFIG_USB_SUSPEND
if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
udev->autosuspend_delay = -1;
udev->autosuspend_disabled = 1;
#endif
}

View File

@ -169,6 +169,16 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
static ssize_t
show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
udev = to_usb_device(dev);
return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
}
static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
#if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
static const char power_group[] = "power";
@ -413,6 +423,44 @@ usb_descriptor_attr(bDeviceProtocol, "%02x\n")
usb_descriptor_attr(bNumConfigurations, "%d\n")
usb_descriptor_attr(bMaxPacketSize0, "%d\n")
/* show if the device is authorized (1) or not (0) */
static ssize_t usb_dev_authorized_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct usb_device *usb_dev = to_usb_device(dev);
return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
}
/*
* Authorize a device to be used in the system
*
* Writing a 0 deauthorizes the device, writing a 1 authorizes it.
*/
static ssize_t usb_dev_authorized_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
ssize_t result;
struct usb_device *usb_dev = to_usb_device(dev);
unsigned val;
result = sscanf(buf, "%u\n", &val);
if (result != 1)
result = -EINVAL;
else if (val == 0)
result = usb_deauthorize_device(usb_dev);
else
result = usb_authorize_device(usb_dev);
return result < 0? result : size;
}
static DEVICE_ATTR(authorized, 0644,
usb_dev_authorized_show, usb_dev_authorized_store);
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
&dev_attr_configuration.attr,
@ -420,6 +468,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_bConfigurationValue.attr,
&dev_attr_bmAttributes.attr,
&dev_attr_bMaxPower.attr,
&dev_attr_urbnum.attr,
/* device attributes */
&dev_attr_idVendor.attr,
&dev_attr_idProduct.attr,
@ -435,6 +484,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_version.attr,
&dev_attr_maxchild.attr,
&dev_attr_quirks.attr,
&dev_attr_authorized.attr,
NULL,
};
static struct attribute_group dev_attr_grp = {

View File

@ -3,6 +3,7 @@
#include <linux/bitops.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/log2.h>
#include <linux/usb.h>
#include <linux/wait.h>
#include "hcd.h"
@ -38,7 +39,6 @@ void usb_init_urb(struct urb *urb)
if (urb) {
memset(urb, 0, sizeof(*urb));
kref_init(&urb->kref);
spin_lock_init(&urb->lock);
INIT_LIST_HEAD(&urb->anchor_list);
}
}
@ -277,44 +277,58 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
*/
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
int pipe, temp, max;
struct usb_device *dev;
int is_out;
int xfertype, max;
struct usb_device *dev;
struct usb_host_endpoint *ep;
int is_out;
if (!urb || urb->hcpriv || !urb->complete)
return -EINVAL;
if (!(dev = urb->dev) ||
(dev->state < USB_STATE_DEFAULT) ||
(!dev->bus) || (dev->devnum <= 0))
if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
return -ENODEV;
if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
|| dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
/* For now, get the endpoint from the pipe. Eventually drivers
* will be required to set urb->ep directly and we will eliminate
* urb->pipe.
*/
ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
[usb_pipeendpoint(urb->pipe)];
if (!ep)
return -ENOENT;
urb->ep = ep;
urb->status = -EINPROGRESS;
urb->actual_length = 0;
/* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/
pipe = urb->pipe;
temp = usb_pipetype(pipe);
is_out = usb_pipeout(pipe);
xfertype = usb_endpoint_type(&ep->desc);
if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
struct usb_ctrlrequest *setup =
(struct usb_ctrlrequest *) urb->setup_packet;
if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
if (!setup)
return -ENOEXEC;
is_out = !(setup->bRequestType & USB_DIR_IN) ||
!setup->wLength;
} else {
is_out = usb_endpoint_dir_out(&ep->desc);
}
/* Cache the direction for later use */
urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
(is_out ? URB_DIR_OUT : URB_DIR_IN);
if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
/* FIXME there should be a sharable lock protecting us against
* config/altsetting changes and disconnects, kicking in here.
* (here == before maxpacket, and eventually endpoint type,
* checks get made.)
*/
max = usb_maxpacket(dev, pipe, is_out);
max = le16_to_cpu(ep->desc.wMaxPacketSize);
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
usb_pipeendpoint(pipe), is_out ? "out" : "in",
usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
__FUNCTION__, max);
return -EMSGSIZE;
}
@ -323,7 +337,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* but drivers only control those sizes for ISO.
* while we're checking, initialize return status.
*/
if (temp == PIPE_ISOCHRONOUS) {
if (xfertype == USB_ENDPOINT_XFER_ISOC) {
int n, len;
/* "high bandwidth" mode, 1-3 packets/uframe? */
@ -358,20 +372,20 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
/* enforce simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
URB_NO_INTERRUPT);
switch (temp) {
case PIPE_BULK:
URB_NO_INTERRUPT | URB_DIR_MASK);
switch (xfertype) {
case USB_ENDPOINT_XFER_BULK:
if (is_out)
allowed |= URB_ZERO_PACKET;
/* FALLTHROUGH */
case PIPE_CONTROL:
case USB_ENDPOINT_XFER_CONTROL:
allowed |= URB_NO_FSBR; /* only affects UHCI */
/* FALLTHROUGH */
default: /* all non-iso endpoints */
if (!is_out)
allowed |= URB_SHORT_NOT_OK;
break;
case PIPE_ISOCHRONOUS:
case USB_ENDPOINT_XFER_ISOC:
allowed |= URB_ISO_ASAP;
break;
}
@ -393,9 +407,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* supports different values... this uses EHCI/UHCI defaults (and
* EHCI can use smaller non-default values).
*/
switch (temp) {
case PIPE_ISOCHRONOUS:
case PIPE_INTERRUPT:
switch (xfertype) {
case USB_ENDPOINT_XFER_ISOC:
case USB_ENDPOINT_XFER_INT:
/* too small? */
if (urb->interval <= 0)
return -EINVAL;
@ -405,29 +419,27 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
// NOTE usb handles 2^15
if (urb->interval > (1024 * 8))
urb->interval = 1024 * 8;
temp = 1024 * 8;
max = 1024 * 8;
break;
case USB_SPEED_FULL: /* units are frames/msec */
case USB_SPEED_LOW:
if (temp == PIPE_INTERRUPT) {
if (xfertype == USB_ENDPOINT_XFER_INT) {
if (urb->interval > 255)
return -EINVAL;
// NOTE ohci only handles up to 32
temp = 128;
max = 128;
} else {
if (urb->interval > 1024)
urb->interval = 1024;
// NOTE usb and ohci handle up to 2^15
temp = 1024;
max = 1024;
}
break;
default:
return -EINVAL;
}
/* power of two? */
while (temp > urb->interval)
temp >>= 1;
urb->interval = temp;
/* Round down to a power of 2, no more than max */
urb->interval = min(max, 1 << ilog2(urb->interval));
}
return usb_hcd_submit_urb(urb, mem_flags);
@ -496,8 +508,10 @@ int usb_unlink_urb(struct urb *urb)
{
if (!urb)
return -EINVAL;
if (!(urb->dev && urb->dev->bus))
if (!urb->dev)
return -ENODEV;
if (!urb->ep)
return -EIDRM;
return usb_hcd_unlink_urb(urb, -ECONNRESET);
}
@ -523,19 +537,21 @@ int usb_unlink_urb(struct urb *urb)
*/
void usb_kill_urb(struct urb *urb)
{
static DEFINE_MUTEX(reject_mutex);
might_sleep();
if (!(urb && urb->dev && urb->dev->bus))
if (!(urb && urb->dev && urb->ep))
return;
spin_lock_irq(&urb->lock);
mutex_lock(&reject_mutex);
++urb->reject;
spin_unlock_irq(&urb->lock);
mutex_unlock(&reject_mutex);
usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
spin_lock_irq(&urb->lock);
mutex_lock(&reject_mutex);
--urb->reject;
spin_unlock_irq(&urb->lock);
mutex_unlock(&reject_mutex);
}
/**

View File

@ -223,6 +223,15 @@ static void ksuspend_usb_cleanup(void)
#endif /* CONFIG_PM */
/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
static unsigned usb_bus_is_wusb(struct usb_bus *bus)
{
struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self);
return hcd->wireless;
}
/**
* usb_alloc_dev - usb device constructor (usbcore-internal)
* @parent: hub to which device is connected; null to allocate a root hub
@ -239,6 +248,8 @@ struct usb_device *
usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
{
struct usb_device *dev;
struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
unsigned root_hub = 0;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
@ -255,12 +266,14 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->dev.dma_mask = bus->controller->dma_mask;
set_dev_node(&dev->dev, dev_to_node(bus->controller));
dev->state = USB_STATE_ATTACHED;
atomic_set(&dev->urbnum, 0);
INIT_LIST_HEAD(&dev->ep0.urb_list);
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
/* ep0 maxpacket comes later, from device descriptor */
dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
usb_enable_endpoint(dev, &dev->ep0);
dev->can_submit = 1;
/* Save readable and stable topology id, distinguishing devices
* by location for diagnostics, tools, driver model, etc. The
@ -275,6 +288,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->dev.parent = bus->controller;
sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
root_hub = 1;
} else {
/* match any labeling on the hubs; it's one-based */
if (parent->devpath[0] == '0')
@ -301,6 +315,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
dev->autosuspend_delay = usb_autosuspend_delay * HZ;
#endif
if (root_hub) /* Root hub always ok [and always wired] */
dev->authorized = 1;
else {
dev->authorized = usb_hcd->authorized_default;
dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
}
return dev;
}
@ -748,7 +768,7 @@ void usb_buffer_unmap(struct urb *urb)
/**
* usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
* @dev: device to which the scatterlist will be mapped
* @pipe: endpoint defining the mapping direction
* @is_in: mapping transfer direction
* @sg: the scatterlist to map
* @nents: the number of entries in the scatterlist
*
@ -771,14 +791,13 @@ void usb_buffer_unmap(struct urb *urb)
*
* Reverse the effect of this call with usb_buffer_unmap_sg().
*/
int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int nents)
{
struct usb_bus *bus;
struct device *controller;
if (!dev
|| usb_pipecontrol(pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
@ -786,7 +805,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
// FIXME generic api broken like pci, can't report errors
return dma_map_sg(controller, sg, nents,
usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* XXX DISABLED, no users currently. If you wish to re-enable this
@ -799,14 +818,14 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
/**
* usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
* @dev: device to which the scatterlist will be mapped
* @pipe: endpoint defining the mapping direction
* @is_in: mapping transfer direction
* @sg: the scatterlist to synchronize
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Use this when you are re-using a scatterlist's data buffers for
* another USB request.
*/
void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
@ -819,20 +838,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
return;
dma_sync_sg(controller, sg, n_hw_ents,
usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
#endif
/**
* usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
* @dev: device to which the scatterlist will be mapped
* @pipe: endpoint defining the mapping direction
* @is_in: mapping transfer direction
* @sg: the scatterlist to unmap
* @n_hw_ents: the positive return value from usb_buffer_map_sg
*
* Reverses the effect of usb_buffer_map_sg().
*/
void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
@ -845,7 +864,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
return;
dma_unmap_sg(controller, sg, n_hw_ents,
usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* format to disable USB on kernel command line is: nousb */

View File

@ -8,17 +8,22 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *
struct usb_device *udev);
extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
extern void usb_enable_endpoint(struct usb_device *dev,
struct usb_host_endpoint *ep);
extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
extern void usb_disable_interface (struct usb_device *dev,
struct usb_interface *intf);
extern void usb_release_interface_cache(struct kref *ref);
extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
extern int usb_deauthorize_device (struct usb_device *);
extern int usb_authorize_device (struct usb_device *);
extern void usb_detect_quirks(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev,
unsigned int size);
extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern int usb_choose_configuration(struct usb_device *udev);
extern void usb_kick_khubd(struct usb_device *dev);
extern int usb_match_device(struct usb_device *dev,

View File

@ -67,6 +67,17 @@ config USB_GADGET_DEBUG_FILES
driver on a new board. Enable these files by choosing "Y"
here. If in doubt, or to conserve kernel memory, say "N".
config USB_GADGET_DEBUG_FS
boolean "Debugging information files in debugfs"
depends on USB_GADGET && DEBUG_FS
help
Some of the drivers in the "gadget" framework can expose
debugging information in files under /sys/kernel/debug/.
The information in these files may help when you're
troubleshooting or bringing up a driver on a new board.
Enable these files by choosing "Y" here. If in doubt, or
to conserve kernel memory, say "N".
config USB_GADGET_SELECTED
boolean
@ -103,6 +114,20 @@ config USB_AMD5536UDC
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_ATMEL_USBA
boolean "Atmel USBA"
select USB_GADGET_DUALSPEED
depends on AVR32
help
USBA is the integrated high-speed USB Device controller on
the AT32AP700x processors from Atmel.
config USB_ATMEL_USBA
tristate
depends on USB_GADGET_ATMEL_USBA
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_FSL_USB2
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on MPC834x || PPC_MPC831x
@ -228,7 +253,6 @@ config USB_LH7A40X
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_OMAP
boolean "OMAP USB Device Controller"
depends on ARCH_OMAP

View File

@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
obj-$(CONFIG_USB_AT91) += at91_udc.o
obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o

View File

@ -69,7 +69,7 @@
/* gadget stack */
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
/* udc specific */
#include "amd5536udc.h"
@ -3244,7 +3244,6 @@ static int udc_pci_probe(
retval = -ENOMEM;
goto finished;
}
memset(dev, 0, sizeof(struct udc));
/* pci setup */
if (pci_enable_device(pdev) < 0) {
@ -3286,14 +3285,12 @@ static int udc_pci_probe(
pci_set_drvdata(pdev, dev);
/* chip revision */
dev->chiprev = 0;
/* chip revision for Hs AMD5536 */
dev->chiprev = pdev->revision;
pci_set_master(pdev);
pci_set_mwi(pdev);
/* chip rev for Hs AMD5536 */
pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
/* init dma pools */
if (use_dma) {
retval = init_dma_pools(dev);

View File

@ -38,7 +38,7 @@
#include <linux/proc_fs.h>
#include <linux/clk.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/hardware.h>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,352 @@
/*
* Driver for the Atmel USBA high speed USB device controller
*
* Copyright (C) 2005-2007 Atmel Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_USB_GADGET_USBA_UDC_H__
#define __LINUX_USB_GADGET_USBA_UDC_H__
/* USB register offsets */
#define USBA_CTRL 0x0000
#define USBA_FNUM 0x0004
#define USBA_INT_ENB 0x0010
#define USBA_INT_STA 0x0014
#define USBA_INT_CLR 0x0018
#define USBA_EPT_RST 0x001c
#define USBA_TST 0x00e0
/* USB endpoint register offsets */
#define USBA_EPT_CFG 0x0000
#define USBA_EPT_CTL_ENB 0x0004
#define USBA_EPT_CTL_DIS 0x0008
#define USBA_EPT_CTL 0x000c
#define USBA_EPT_SET_STA 0x0014
#define USBA_EPT_CLR_STA 0x0018
#define USBA_EPT_STA 0x001c
/* USB DMA register offsets */
#define USBA_DMA_NXT_DSC 0x0000
#define USBA_DMA_ADDRESS 0x0004
#define USBA_DMA_CONTROL 0x0008
#define USBA_DMA_STATUS 0x000c
/* Bitfields in CTRL */
#define USBA_DEV_ADDR_OFFSET 0
#define USBA_DEV_ADDR_SIZE 7
#define USBA_FADDR_EN (1 << 7)
#define USBA_EN_USBA (1 << 8)
#define USBA_DETACH (1 << 9)
#define USBA_REMOTE_WAKE_UP (1 << 10)
/* Bitfields in FNUM */
#define USBA_MICRO_FRAME_NUM_OFFSET 0
#define USBA_MICRO_FRAME_NUM_SIZE 3
#define USBA_FRAME_NUMBER_OFFSET 3
#define USBA_FRAME_NUMBER_SIZE 11
#define USBA_FRAME_NUM_ERROR (1 << 31)
/* Bitfields in INT_ENB/INT_STA/INT_CLR */
#define USBA_HIGH_SPEED (1 << 0)
#define USBA_DET_SUSPEND (1 << 1)
#define USBA_MICRO_SOF (1 << 2)
#define USBA_SOF (1 << 3)
#define USBA_END_OF_RESET (1 << 4)
#define USBA_WAKE_UP (1 << 5)
#define USBA_END_OF_RESUME (1 << 6)
#define USBA_UPSTREAM_RESUME (1 << 7)
#define USBA_EPT_INT_OFFSET 8
#define USBA_EPT_INT_SIZE 16
#define USBA_DMA_INT_OFFSET 24
#define USBA_DMA_INT_SIZE 8
/* Bitfields in EPT_RST */
#define USBA_RST_OFFSET 0
#define USBA_RST_SIZE 16
/* Bitfields in USBA_TST */
#define USBA_SPEED_CFG_OFFSET 0
#define USBA_SPEED_CFG_SIZE 2
#define USBA_TST_J_MODE (1 << 2)
#define USBA_TST_K_MODE (1 << 3)
#define USBA_TST_PKT_MODE (1 << 4)
#define USBA_OPMODE2 (1 << 5)
/* Bitfields in EPT_CFG */
#define USBA_EPT_SIZE_OFFSET 0
#define USBA_EPT_SIZE_SIZE 3
#define USBA_EPT_DIR_IN (1 << 3)
#define USBA_EPT_TYPE_OFFSET 4
#define USBA_EPT_TYPE_SIZE 2
#define USBA_BK_NUMBER_OFFSET 6
#define USBA_BK_NUMBER_SIZE 2
#define USBA_NB_TRANS_OFFSET 8
#define USBA_NB_TRANS_SIZE 2
#define USBA_EPT_MAPPED (1 << 31)
/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */
#define USBA_EPT_ENABLE (1 << 0)
#define USBA_AUTO_VALID (1 << 1)
#define USBA_INTDIS_DMA (1 << 3)
#define USBA_NYET_DIS (1 << 4)
#define USBA_DATAX_RX (1 << 6)
#define USBA_MDATA_RX (1 << 7)
/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */
#define USBA_BUSY_BANK_IE (1 << 18)
/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */
#define USBA_FORCE_STALL (1 << 5)
#define USBA_TOGGLE_CLR (1 << 6)
#define USBA_TOGGLE_SEQ_OFFSET 6
#define USBA_TOGGLE_SEQ_SIZE 2
#define USBA_ERR_OVFLW (1 << 8)
#define USBA_RX_BK_RDY (1 << 9)
#define USBA_KILL_BANK (1 << 9)
#define USBA_TX_COMPLETE (1 << 10)
#define USBA_TX_PK_RDY (1 << 11)
#define USBA_ISO_ERR_TRANS (1 << 11)
#define USBA_RX_SETUP (1 << 12)
#define USBA_ISO_ERR_FLOW (1 << 12)
#define USBA_STALL_SENT (1 << 13)
#define USBA_ISO_ERR_CRC (1 << 13)
#define USBA_ISO_ERR_NBTRANS (1 << 13)
#define USBA_NAK_IN (1 << 14)
#define USBA_ISO_ERR_FLUSH (1 << 14)
#define USBA_NAK_OUT (1 << 15)
#define USBA_CURRENT_BANK_OFFSET 16
#define USBA_CURRENT_BANK_SIZE 2
#define USBA_BUSY_BANKS_OFFSET 18
#define USBA_BUSY_BANKS_SIZE 2
#define USBA_BYTE_COUNT_OFFSET 20
#define USBA_BYTE_COUNT_SIZE 11
#define USBA_SHORT_PACKET (1 << 31)
/* Bitfields in DMA_CONTROL */
#define USBA_DMA_CH_EN (1 << 0)
#define USBA_DMA_LINK (1 << 1)
#define USBA_DMA_END_TR_EN (1 << 2)
#define USBA_DMA_END_BUF_EN (1 << 3)
#define USBA_DMA_END_TR_IE (1 << 4)
#define USBA_DMA_END_BUF_IE (1 << 5)
#define USBA_DMA_DESC_LOAD_IE (1 << 6)
#define USBA_DMA_BURST_LOCK (1 << 7)
#define USBA_DMA_BUF_LEN_OFFSET 16
#define USBA_DMA_BUF_LEN_SIZE 16
/* Bitfields in DMA_STATUS */
#define USBA_DMA_CH_ACTIVE (1 << 1)
#define USBA_DMA_END_TR_ST (1 << 4)
#define USBA_DMA_END_BUF_ST (1 << 5)
#define USBA_DMA_DESC_LOAD_ST (1 << 6)
/* Constants for SPEED_CFG */
#define USBA_SPEED_CFG_NORMAL 0
#define USBA_SPEED_CFG_FORCE_HIGH 2
#define USBA_SPEED_CFG_FORCE_FULL 3
/* Constants for EPT_SIZE */
#define USBA_EPT_SIZE_8 0
#define USBA_EPT_SIZE_16 1
#define USBA_EPT_SIZE_32 2
#define USBA_EPT_SIZE_64 3
#define USBA_EPT_SIZE_128 4
#define USBA_EPT_SIZE_256 5
#define USBA_EPT_SIZE_512 6
#define USBA_EPT_SIZE_1024 7
/* Constants for EPT_TYPE */
#define USBA_EPT_TYPE_CONTROL 0
#define USBA_EPT_TYPE_ISO 1
#define USBA_EPT_TYPE_BULK 2
#define USBA_EPT_TYPE_INT 3
/* Constants for BK_NUMBER */
#define USBA_BK_NUMBER_ZERO 0
#define USBA_BK_NUMBER_ONE 1
#define USBA_BK_NUMBER_DOUBLE 2
#define USBA_BK_NUMBER_TRIPLE 3
/* Bit manipulation macros */
#define USBA_BF(name, value) \
(((value) & ((1 << USBA_##name##_SIZE) - 1)) \
<< USBA_##name##_OFFSET)
#define USBA_BFEXT(name, value) \
(((value) >> USBA_##name##_OFFSET) \
& ((1 << USBA_##name##_SIZE) - 1))
#define USBA_BFINS(name, value, old) \
(((old) & ~(((1 << USBA_##name##_SIZE) - 1) \
<< USBA_##name##_OFFSET)) \
| USBA_BF(name, value))
/* Register access macros */
#define usba_readl(udc, reg) \
__raw_readl((udc)->regs + USBA_##reg)
#define usba_writel(udc, reg, value) \
__raw_writel((value), (udc)->regs + USBA_##reg)
#define usba_ep_readl(ep, reg) \
__raw_readl((ep)->ep_regs + USBA_EPT_##reg)
#define usba_ep_writel(ep, reg, value) \
__raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
#define usba_dma_readl(ep, reg) \
__raw_readl((ep)->dma_regs + USBA_DMA_##reg)
#define usba_dma_writel(ep, reg, value) \
__raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
/* Calculate base address for a given endpoint or DMA controller */
#define USBA_EPT_BASE(x) (0x100 + (x) * 0x20)
#define USBA_DMA_BASE(x) (0x300 + (x) * 0x10)
#define USBA_FIFO_BASE(x) ((x) << 16)
/* Synth parameters */
#define USBA_NR_ENDPOINTS 7
#define EP0_FIFO_SIZE 64
#define EP0_EPT_SIZE USBA_EPT_SIZE_64
#define EP0_NR_BANKS 1
/*
* REVISIT: Try to eliminate this value. Can we rely on req->mapped to
* provide this information?
*/
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define FIFO_IOMEM_ID 0
#define CTRL_IOMEM_ID 1
#ifdef DEBUG
#define DBG_ERR 0x0001 /* report all error returns */
#define DBG_HW 0x0002 /* debug hardware initialization */
#define DBG_GADGET 0x0004 /* calls to/from gadget driver */
#define DBG_INT 0x0008 /* interrupts */
#define DBG_BUS 0x0010 /* report changes in bus state */
#define DBG_QUEUE 0x0020 /* debug request queue processing */
#define DBG_FIFO 0x0040 /* debug FIFO contents */
#define DBG_DMA 0x0080 /* debug DMA handling */
#define DBG_REQ 0x0100 /* print out queued request length */
#define DBG_ALL 0xffff
#define DBG_NONE 0x0000
#define DEBUG_LEVEL (DBG_ERR)
#define DBG(level, fmt, ...) \
do { \
if ((level) & DEBUG_LEVEL) \
printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__); \
} while (0)
#else
#define DBG(level, fmt...)
#endif
enum usba_ctrl_state {
WAIT_FOR_SETUP,
DATA_STAGE_IN,
DATA_STAGE_OUT,
STATUS_STAGE_IN,
STATUS_STAGE_OUT,
STATUS_STAGE_ADDR,
STATUS_STAGE_TEST,
};
/*
EP_STATE_IDLE,
EP_STATE_SETUP,
EP_STATE_IN_DATA,
EP_STATE_OUT_DATA,
EP_STATE_SET_ADDR_STATUS,
EP_STATE_RX_STATUS,
EP_STATE_TX_STATUS,
EP_STATE_HALT,
*/
struct usba_dma_desc {
dma_addr_t next;
dma_addr_t addr;
u32 ctrl;
};
struct usba_ep {
int state;
void __iomem *ep_regs;
void __iomem *dma_regs;
void __iomem *fifo;
struct usb_ep ep;
struct usba_udc *udc;
struct list_head queue;
const struct usb_endpoint_descriptor *desc;
u16 fifo_size;
u8 nr_banks;
u8 index;
unsigned int can_dma:1;
unsigned int can_isoc:1;
unsigned int is_isoc:1;
unsigned int is_in:1;
#ifdef CONFIG_USB_GADGET_DEBUG_FS
u32 last_dma_status;
struct dentry *debugfs_dir;
struct dentry *debugfs_queue;
struct dentry *debugfs_dma_status;
struct dentry *debugfs_state;
#endif
};
struct usba_request {
struct usb_request req;
struct list_head queue;
u32 ctrl;
unsigned int submitted:1;
unsigned int last_transaction:1;
unsigned int using_dma:1;
unsigned int mapped:1;
};
struct usba_udc {
/* Protect hw registers from concurrent modifications */
spinlock_t lock;
void __iomem *regs;
void __iomem *fifo;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct platform_device *pdev;
int irq;
int vbus_pin;
struct clk *pclk;
struct clk *hclk;
u16 devstatus;
u16 test_mode;
int vbus_prev;
#ifdef CONFIG_USB_GADGET_DEBUG_FS
struct dentry *debugfs_root;
struct dentry *debugfs_regs;
#endif
};
static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
{
return container_of(ep, struct usba_ep, ep);
}
static inline struct usba_request *to_usba_req(struct usb_request *req)
{
return container_of(req, struct usba_request, req);
}
static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget)
{
return container_of(gadget, struct usba_udc, gadget);
}
#define ep_is_control(ep) ((ep)->index == 0)
#define ep_is_idle(ep) ((ep)->state == EP_STATE_IDLE)
#endif /* __LINUX_USB_GADGET_USBA_UDC_H */

View File

@ -25,7 +25,7 @@
#include <linux/device.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
/**

View File

@ -46,7 +46,7 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/usb.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@ -962,13 +962,13 @@ static struct platform_driver dummy_udc_driver = {
static int dummy_urb_enqueue (
struct usb_hcd *hcd,
struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
struct dummy *dum;
struct urbp *urbp;
unsigned long flags;
int rc;
if (!urb->transfer_buffer && urb->transfer_buffer_length)
return -EINVAL;
@ -980,6 +980,11 @@ static int dummy_urb_enqueue (
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
rc = usb_hcd_link_urb_to_ep(hcd, urb);
if (rc) {
kfree(urbp);
goto done;
}
if (!dum->udev) {
dum->udev = urb->dev;
@ -996,36 +1001,35 @@ static int dummy_urb_enqueue (
if (!timer_pending (&dum->timer))
mod_timer (&dum->timer, jiffies + 1);
spin_unlock_irqrestore (&dum->lock, flags);
return 0;
done:
spin_unlock_irqrestore(&dum->lock, flags);
return rc;
}
static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct dummy *dum;
unsigned long flags;
int rc;
/* giveback happens automatically in timer callback,
* so make sure the callback happens */
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
mod_timer (&dum->timer, jiffies);
spin_unlock_irqrestore (&dum->lock, flags);
return 0;
}
static void maybe_set_status (struct urb *urb, int status)
{
spin_lock (&urb->lock);
if (urb->status == -EINPROGRESS)
urb->status = status;
spin_unlock (&urb->lock);
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
!list_empty(&dum->urbp_list))
mod_timer (&dum->timer, jiffies);
spin_unlock_irqrestore (&dum->lock, flags);
return rc;
}
/* transfer up to a frame's worth; caller must own lock */
static int
transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
int *status)
{
struct dummy_request *req;
@ -1088,24 +1092,20 @@ top:
*
* partially filling a buffer optionally blocks queue advances
* (so completion handlers can clean up the queue) but we don't
* need to emulate such data-in-flight. so we only show part
* of the URB_SHORT_NOT_OK effect: completion status.
* need to emulate such data-in-flight.
*/
if (is_short) {
if (host_len == dev_len) {
req->req.status = 0;
maybe_set_status (urb, 0);
*status = 0;
} else if (to_host) {
req->req.status = 0;
if (dev_len > host_len)
maybe_set_status (urb, -EOVERFLOW);
*status = -EOVERFLOW;
else
maybe_set_status (urb,
(urb->transfer_flags
& URB_SHORT_NOT_OK)
? -EREMOTEIO : 0);
*status = 0;
} else if (!to_host) {
maybe_set_status (urb, 0);
*status = 0;
if (host_len > dev_len)
req->req.status = -EOVERFLOW;
else
@ -1119,9 +1119,8 @@ top:
req->req.status = 0;
if (urb->transfer_buffer_length == urb->actual_length
&& !(urb->transfer_flags
& URB_ZERO_PACKET)) {
maybe_set_status (urb, 0);
}
& URB_ZERO_PACKET))
*status = 0;
}
/* device side completion --> continuable */
@ -1137,7 +1136,7 @@ top:
}
/* host side completion --> terminate */
if (urb->status != -EINPROGRESS)
if (*status != -EINPROGRESS)
break;
/* rescan to continue with any other queued i/o */
@ -1248,12 +1247,12 @@ restart:
u8 address;
struct dummy_ep *ep = NULL;
int type;
int status = -EINPROGRESS;
urb = urbp->urb;
if (urb->status != -EINPROGRESS) {
/* likely it was just unlinked */
if (urb->unlinked)
goto return_urb;
} else if (dum->rh_state != DUMMY_RH_RUNNING)
else if (dum->rh_state != DUMMY_RH_RUNNING)
continue;
type = usb_pipetype (urb->pipe);
@ -1274,7 +1273,7 @@ restart:
dev_dbg (dummy_dev(dum),
"no ep configured for urb %p\n",
urb);
maybe_set_status (urb, -EPROTO);
status = -EPROTO;
goto return_urb;
}
@ -1289,7 +1288,7 @@ restart:
/* NOTE: must not be iso! */
dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
ep->ep.name, urb);
maybe_set_status (urb, -EPIPE);
status = -EPIPE;
goto return_urb;
}
/* FIXME make sure both ends agree on maxpacket */
@ -1307,7 +1306,7 @@ restart:
w_value = le16_to_cpu(setup.wValue);
if (le16_to_cpu(setup.wLength) !=
urb->transfer_buffer_length) {
maybe_set_status (urb, -EOVERFLOW);
status = -EOVERFLOW;
goto return_urb;
}
@ -1337,7 +1336,7 @@ restart:
if (setup.bRequestType != Dev_Request)
break;
dum->address = w_value;
maybe_set_status (urb, 0);
status = 0;
dev_dbg (udc_dev(dum), "set_address = %d\n",
w_value);
value = 0;
@ -1364,7 +1363,7 @@ restart:
if (value == 0) {
dum->devstatus |=
(1 << w_value);
maybe_set_status (urb, 0);
status = 0;
}
} else if (setup.bRequestType == Ep_Request) {
@ -1376,7 +1375,7 @@ restart:
}
ep2->halted = 1;
value = 0;
maybe_set_status (urb, 0);
status = 0;
}
break;
case USB_REQ_CLEAR_FEATURE:
@ -1386,7 +1385,7 @@ restart:
dum->devstatus &= ~(1 <<
USB_DEVICE_REMOTE_WAKEUP);
value = 0;
maybe_set_status (urb, 0);
status = 0;
break;
default:
value = -EOPNOTSUPP;
@ -1401,7 +1400,7 @@ restart:
}
ep2->halted = 0;
value = 0;
maybe_set_status (urb, 0);
status = 0;
}
break;
case USB_REQ_GET_STATUS:
@ -1438,7 +1437,7 @@ restart:
urb->actual_length = min (2,
urb->transfer_buffer_length);
value = 0;
maybe_set_status (urb, 0);
status = 0;
}
break;
}
@ -1465,7 +1464,7 @@ restart:
dev_dbg (udc_dev(dum),
"setup --> %d\n",
value);
maybe_set_status (urb, -EPIPE);
status = -EPIPE;
urb->actual_length = 0;
}
@ -1482,7 +1481,7 @@ restart:
* report random errors, to debug drivers.
*/
limit = max (limit, periodic_bytes (dum, ep));
maybe_set_status (urb, -ENOSYS);
status = -ENOSYS;
break;
case PIPE_INTERRUPT:
@ -1496,23 +1495,23 @@ restart:
default:
treat_control_like_bulk:
ep->last_io = jiffies;
total = transfer (dum, urb, ep, limit);
total = transfer(dum, urb, ep, limit, &status);
break;
}
/* incomplete transfer? */
if (urb->status == -EINPROGRESS)
if (status == -EINPROGRESS)
continue;
return_urb:
urb->hcpriv = NULL;
list_del (&urbp->urbp_list);
kfree (urbp);
if (ep)
ep->already_seen = ep->setup_stage = 0;
usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
spin_unlock (&dum->lock);
usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
spin_lock (&dum->lock);
goto restart;

View File

@ -28,7 +28,7 @@
#include <linux/string.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include "gadget_chips.h"

View File

@ -19,40 +19,18 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* #define VERBOSE_DEBUG */
// #define DEBUG 1
// #define VERBOSE
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/utsname.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/ctype.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
#include <linux/usb_gadget.h>
#include <linux/random.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/usb/gadget.h>
#include "gadget_chips.h"
@ -356,15 +334,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR);
#define qlen(gadget) \
(DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
/* also defer IRQs on highspeed TX */
#define TX_DELAY qmult
static inline int BITRATE(struct usb_gadget *g)
{
return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
}
#else /* full speed (low speed doesn't do bulk) */
#define qmult 1
#define DEVSPEED USB_SPEED_FULL
#define qlen(gadget) DEFAULT_QLEN
@ -390,7 +368,7 @@ static inline int BITRATE(struct usb_gadget *g)
do { } while (0)
#endif /* DEBUG */
#ifdef VERBOSE
#ifdef VERBOSE_DEBUG
#define VDEBUG DEBUG
#else
#define VDEBUG(dev,fmt,args...) \
@ -830,8 +808,6 @@ static const struct usb_descriptor_header *fs_rndis_function [] = {
};
#endif
#ifdef CONFIG_USB_GADGET_DUALSPEED
/*
* usb 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@ -934,18 +910,15 @@ static const struct usb_descriptor_header *hs_rndis_function [] = {
/* maxpacket and other transfer characteristics vary by speed. */
#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
#else
/* if there's no high speed support, maxpacket doesn't change. */
#define ep_desc(g,hs,fs) (((void)(g)), (fs))
static inline void __init hs_subset_descriptors(void)
static inline struct usb_endpoint_descriptor *
ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
struct usb_endpoint_descriptor *fs)
{
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
}
#endif /* !CONFIG_USB_GADGET_DUALSPEED */
/*-------------------------------------------------------------------------*/
@ -989,22 +962,19 @@ static struct usb_gadget_strings stringtab = {
* complications: class descriptors, and an altsetting.
*/
static int
config_buf (enum usb_device_speed speed,
u8 *buf, u8 type,
unsigned index, int is_otg)
config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg)
{
int len;
const struct usb_config_descriptor *config;
const struct usb_descriptor_header **function;
#ifdef CONFIG_USB_GADGET_DUALSPEED
int hs = (speed == USB_SPEED_HIGH);
int hs = 0;
if (type == USB_DT_OTHER_SPEED_CONFIG)
hs = !hs;
if (gadget_is_dualspeed(g)) {
hs = (g->speed == USB_SPEED_HIGH);
if (type == USB_DT_OTHER_SPEED_CONFIG)
hs = !hs;
}
#define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function)
#else
#define which_fn(t) (fs_ ## t ## _function)
#endif
if (index >= device_desc.bNumConfigurations)
return -EINVAL;
@ -1217,7 +1187,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags)
if (number)
eth_reset_config (dev);
usb_gadget_vbus_draw(dev->gadget,
dev->gadget->is_otg ? 8 : 100);
gadget_is_otg(dev->gadget) ? 8 : 100);
} else {
char *speed;
unsigned power;
@ -1399,24 +1369,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min (wLength, (u16) sizeof device_desc);
memcpy (req->buf, &device_desc, value);
break;
#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
if (!gadget->is_dualspeed)
if (!gadget_is_dualspeed(gadget))
break;
value = min (wLength, (u16) sizeof dev_qualifier);
memcpy (req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
if (!gadget->is_dualspeed)
if (!gadget_is_dualspeed(gadget))
break;
// FALLTHROUGH
#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
value = config_buf (gadget->speed, req->buf,
value = config_buf(gadget, req->buf,
wValue >> 8,
wValue & 0xff,
gadget->is_otg);
gadget_is_otg(gadget));
if (value >= 0)
value = min (wLength, (u16) value);
break;
@ -1585,12 +1553,12 @@ done_set_intf:
&& rndis_control_intf.bInterfaceNumber
== wIndex) {
u8 *buf;
u32 n;
/* return the result */
buf = rndis_get_next_response (dev->rndis_config,
&value);
buf = rndis_get_next_response(dev->rndis_config, &n);
if (buf) {
memcpy (req->buf, buf, value);
memcpy(req->buf, buf, n);
req->complete = rndis_response_complete;
rndis_free_response(dev->rndis_config, buf);
}
@ -1989,8 +1957,20 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
}
spin_lock_irqsave(&dev->req_lock, flags);
/*
* this freelist can be empty if an interrupt triggered disconnect()
* and reconfigured the gadget (shutting down this queue) after the
* network stack decided to xmit but before we got the spinlock.
*/
if (list_empty(&dev->tx_reqs)) {
spin_unlock_irqrestore(&dev->req_lock, flags);
return 1;
}
req = container_of (dev->tx_reqs.next, struct usb_request, list);
list_del (&req->list);
/* temporarily stop TX queue when the freelist empties */
if (list_empty (&dev->tx_reqs))
netif_stop_queue (net);
spin_unlock_irqrestore(&dev->req_lock, flags);
@ -2026,12 +2006,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
req->length = length;
#ifdef CONFIG_USB_GADGET_DUALSPEED
/* throttle highspeed IRQ rate back slightly */
req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
: 0;
#endif
if (gadget_is_dualspeed(dev->gadget))
req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
: 0;
retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
switch (retval) {
@ -2188,8 +2167,7 @@ static int eth_stop (struct net_device *net)
}
if (rndis_active(dev)) {
rndis_set_param_medium (dev->rndis_config,
NDIS_MEDIUM_802_3, 0);
rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0);
(void) rndis_signal_disconnect (dev->rndis_config);
}
@ -2443,26 +2421,28 @@ autoconf_fail:
if (rndis)
device_desc.bNumConfigurations = 2;
#ifdef CONFIG_USB_GADGET_DUALSPEED
if (rndis)
dev_qualifier.bNumConfigurations = 2;
else if (!cdc)
dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
if (gadget_is_dualspeed(gadget)) {
if (rndis)
dev_qualifier.bNumConfigurations = 2;
else if (!cdc)
dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
/* assumes ep0 uses the same value for both speeds ... */
dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
/* assumes ep0 uses the same value for both speeds ... */
dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
/* and that all endpoints are dual-speed */
hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
/* and that all endpoints are dual-speed */
hs_source_desc.bEndpointAddress =
fs_source_desc.bEndpointAddress;
hs_sink_desc.bEndpointAddress =
fs_sink_desc.bEndpointAddress;
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
if (status_ep)
hs_status_desc.bEndpointAddress =
fs_status_desc.bEndpointAddress;
if (status_ep)
hs_status_desc.bEndpointAddress =
fs_status_desc.bEndpointAddress;
#endif
#endif /* DUALSPEED */
}
if (gadget->is_otg) {
if (gadget_is_otg(gadget)) {
otg_descriptor.bmAttributes |= USB_OTG_HNP,
eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
eth_config.bMaxPower = 4;
@ -2598,12 +2578,11 @@ fail0:
if (rndis_set_param_dev (dev->rndis_config, dev->net,
&dev->stats, &dev->cdc_filter))
goto fail0;
if (rndis_set_param_vendor (dev->rndis_config, vendorID,
manufacturer))
if (rndis_set_param_vendor(dev->rndis_config, vendorID,
manufacturer))
goto fail0;
if (rndis_set_param_medium (dev->rndis_config,
NDIS_MEDIUM_802_3,
0))
if (rndis_set_param_medium(dev->rndis_config,
NDIS_MEDIUM_802_3, 0))
goto fail0;
INFO (dev, "RNDIS ready\n");
}

View File

@ -1,7 +1,7 @@
/*
* file_storage.c -- File-backed USB Storage Gadget, for USB development
*
* Copyright (C) 2003-2005 Alan Stern
* Copyright (C) 2003-2007 Alan Stern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -217,17 +217,11 @@
*/
#undef DEBUG
#undef VERBOSE
#undef DUMP_MSGS
/* #define VERBOSE_DEBUG */
/* #define DUMP_MSGS */
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/bitops.h>
#include <linux/blkdev.h>
#include <linux/compiler.h>
#include <linux/completion.h>
#include <linux/dcache.h>
#include <linux/delay.h>
@ -235,18 +229,10 @@
#include <linux/fcntl.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/kthread.h>
#include <linux/limits.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pagemap.h>
#include <linux/rwsem.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
@ -254,7 +240,7 @@
#include <linux/utsname.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include "gadget_chips.h"
@ -263,7 +249,7 @@
#define DRIVER_DESC "File-backed Storage Gadget"
#define DRIVER_NAME "g_file_storage"
#define DRIVER_VERSION "28 November 2005"
#define DRIVER_VERSION "7 August 2007"
static const char longname[] = DRIVER_DESC;
static const char shortname[] = DRIVER_NAME;
@ -289,57 +275,48 @@ MODULE_LICENSE("Dual BSD/GPL");
/*-------------------------------------------------------------------------*/
#define xprintk(f,level,fmt,args...) \
dev_printk(level , &(f)->gadget->dev , fmt , ## args)
#define yprintk(l,level,fmt,args...) \
dev_printk(level , &(l)->dev , fmt , ## args)
#ifdef DEBUG
#define DBG(fsg,fmt,args...) \
xprintk(fsg , KERN_DEBUG , fmt , ## args)
#define LDBG(lun,fmt,args...) \
yprintk(lun , KERN_DEBUG , fmt , ## args)
dev_dbg(&(lun)->dev , fmt , ## args)
#define MDBG(fmt,args...) \
printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
#else
#define DBG(fsg,fmt,args...) \
do { } while (0)
#define LDBG(lun,fmt,args...) \
do { } while (0)
#define MDBG(fmt,args...) \
do { } while (0)
#undef VERBOSE
#undef VERBOSE_DEBUG
#undef DUMP_MSGS
#endif /* DEBUG */
#ifdef VERBOSE
#define VDBG DBG
#ifdef VERBOSE_DEBUG
#define VLDBG LDBG
#else
#define VDBG(fsg,fmt,args...) \
do { } while (0)
#define VLDBG(lun,fmt,args...) \
do { } while (0)
#endif /* VERBOSE */
#endif /* VERBOSE_DEBUG */
#define ERROR(fsg,fmt,args...) \
xprintk(fsg , KERN_ERR , fmt , ## args)
#define LERROR(lun,fmt,args...) \
yprintk(lun , KERN_ERR , fmt , ## args)
#define WARN(fsg,fmt,args...) \
xprintk(fsg , KERN_WARNING , fmt , ## args)
dev_err(&(lun)->dev , fmt , ## args)
#define LWARN(lun,fmt,args...) \
yprintk(lun , KERN_WARNING , fmt , ## args)
#define INFO(fsg,fmt,args...) \
xprintk(fsg , KERN_INFO , fmt , ## args)
dev_warn(&(lun)->dev , fmt , ## args)
#define LINFO(lun,fmt,args...) \
yprintk(lun , KERN_INFO , fmt , ## args)
dev_info(&(lun)->dev , fmt , ## args)
#define MINFO(fmt,args...) \
printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
#define DBG(d, fmt, args...) \
dev_dbg(&(d)->gadget->dev , fmt , ## args)
#define VDBG(d, fmt, args...) \
dev_vdbg(&(d)->gadget->dev , fmt , ## args)
#define ERROR(d, fmt, args...) \
dev_err(&(d)->gadget->dev , fmt , ## args)
#define WARN(d, fmt, args...) \
dev_warn(&(d)->gadget->dev , fmt , ## args)
#define INFO(d, fmt, args...) \
dev_info(&(d)->gadget->dev , fmt , ## args)
/*-------------------------------------------------------------------------*/
@ -350,8 +327,8 @@ MODULE_LICENSE("Dual BSD/GPL");
static struct {
char *file[MAX_LUNS];
int ro[MAX_LUNS];
int num_filenames;
int num_ros;
unsigned int num_filenames;
unsigned int num_ros;
unsigned int nluns;
int removable;
@ -578,7 +555,7 @@ struct lun {
#define backing_file_is_open(curlun) ((curlun)->filp != NULL)
static inline struct lun *dev_to_lun(struct device *dev)
static struct lun *dev_to_lun(struct device *dev)
{
return container_of(dev, struct lun, dev);
}
@ -711,13 +688,13 @@ struct fsg_dev {
typedef void (*fsg_routine_t)(struct fsg_dev *);
static int inline exception_in_progress(struct fsg_dev *fsg)
static int exception_in_progress(struct fsg_dev *fsg)
{
return (fsg->state > FSG_STATE_IDLE);
}
/* Make bulk-out requests be divisible by the maxpacket size */
static void inline set_bulk_out_req_length(struct fsg_dev *fsg,
static void set_bulk_out_req_length(struct fsg_dev *fsg,
struct fsg_buffhd *bh, unsigned int length)
{
unsigned int rem;
@ -743,50 +720,36 @@ static void close_all_backing_files(struct fsg_dev *fsg);
static void dump_msg(struct fsg_dev *fsg, const char *label,
const u8 *buf, unsigned int length)
{
unsigned int start, num, i;
char line[52], *p;
if (length >= 512)
return;
DBG(fsg, "%s, length %u:\n", label, length);
start = 0;
while (length > 0) {
num = min(length, 16u);
p = line;
for (i = 0; i < num; ++i) {
if (i == 8)
*p++ = ' ';
sprintf(p, " %02x", buf[i]);
p += 3;
}
*p = 0;
printk(KERN_DEBUG "%6x: %s\n", start, line);
buf += num;
start += num;
length -= num;
if (length < 512) {
DBG(fsg, "%s, length %u:\n", label, length);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,
16, 1, buf, length, 0);
}
}
static void inline dump_cdb(struct fsg_dev *fsg)
static void dump_cdb(struct fsg_dev *fsg)
{}
#else
static void inline dump_msg(struct fsg_dev *fsg, const char *label,
static void dump_msg(struct fsg_dev *fsg, const char *label,
const u8 *buf, unsigned int length)
{}
static void inline dump_cdb(struct fsg_dev *fsg)
{
int i;
char cmdbuf[3*MAX_COMMAND_SIZE + 1];
#ifdef VERBOSE_DEBUG
for (i = 0; i < fsg->cmnd_size; ++i)
sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]);
VDBG(fsg, "SCSI CDB: %s\n", cmdbuf);
static void dump_cdb(struct fsg_dev *fsg)
{
print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,
16, 1, fsg->cmnd, fsg->cmnd_size, 0);
}
#else
static void dump_cdb(struct fsg_dev *fsg)
{}
#endif /* VERBOSE_DEBUG */
#endif /* DUMP_MSGS */
@ -809,24 +772,24 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
/* Routines for unaligned data access */
static u16 inline get_be16(u8 *buf)
static u16 get_be16(u8 *buf)
{
return ((u16) buf[0] << 8) | ((u16) buf[1]);
}
static u32 inline get_be32(u8 *buf)
static u32 get_be32(u8 *buf)
{
return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) |
((u32) buf[2] << 8) | ((u32) buf[3]);
}
static void inline put_be16(u8 *buf, u16 val)
static void put_be16(u8 *buf, u16 val)
{
buf[0] = val >> 8;
buf[1] = val;
}
static void inline put_be32(u8 *buf, u32 val)
static void put_be32(u8 *buf, u32 val)
{
buf[0] = val >> 24;
buf[1] = val >> 16;
@ -950,8 +913,6 @@ static const struct usb_descriptor_header *fs_function[] = {
#define FS_FUNCTION_PRE_EP_ENTRIES 2
#ifdef CONFIG_USB_GADGET_DUALSPEED
/*
* USB 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@ -1014,14 +975,14 @@ static const struct usb_descriptor_header *hs_function[] = {
#define HS_FUNCTION_PRE_EP_ENTRIES 2
/* Maxpacket and other transfer characteristics vary by speed. */
#define ep_desc(g,fs,hs) (((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs))
#else
/* If there's no high speed support, always use the full-speed descriptor. */
#define ep_desc(g,fs,hs) fs
#endif /* !CONFIG_USB_GADGET_DUALSPEED */
static struct usb_endpoint_descriptor *
ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
struct usb_endpoint_descriptor *hs)
{
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
}
/* The CBI specification limits the serial string to 12 uppercase hexadecimal
@ -1053,26 +1014,22 @@ static struct usb_gadget_strings stringtab = {
static int populate_config_buf(struct usb_gadget *gadget,
u8 *buf, u8 type, unsigned index)
{
#ifdef CONFIG_USB_GADGET_DUALSPEED
enum usb_device_speed speed = gadget->speed;
#endif
int len;
const struct usb_descriptor_header **function;
if (index > 0)
return -EINVAL;
#ifdef CONFIG_USB_GADGET_DUALSPEED
if (type == USB_DT_OTHER_SPEED_CONFIG)
if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
if (speed == USB_SPEED_HIGH)
if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH)
function = hs_function;
else
#endif
function = fs_function;
/* for now, don't advertise srp-only devices */
if (!gadget->is_otg)
if (!gadget_is_otg(gadget))
function++;
len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
@ -1394,10 +1351,9 @@ static int standard_setup_req(struct fsg_dev *fsg,
value = sizeof device_desc;
memcpy(req->buf, &device_desc, value);
break;
#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
VDBG(fsg, "get device qualifier\n");
if (!fsg->gadget->is_dualspeed)
if (!gadget_is_dualspeed(fsg->gadget))
break;
value = sizeof dev_qualifier;
memcpy(req->buf, &dev_qualifier, value);
@ -1405,15 +1361,12 @@ static int standard_setup_req(struct fsg_dev *fsg,
case USB_DT_OTHER_SPEED_CONFIG:
VDBG(fsg, "get other-speed config descriptor\n");
if (!fsg->gadget->is_dualspeed)
if (!gadget_is_dualspeed(fsg->gadget))
break;
goto get_config;
#endif
case USB_DT_CONFIG:
VDBG(fsg, "get configuration descriptor\n");
#ifdef CONFIG_USB_GADGET_DUALSPEED
get_config:
#endif
get_config:
value = populate_config_buf(fsg->gadget,
req->buf,
w_value >> 8,
@ -1646,7 +1599,8 @@ static int do_read(struct fsg_dev *fsg)
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
if ((rc = sleep_thread(fsg)) != 0)
rc = sleep_thread(fsg);
if (rc)
return rc;
}
@ -1885,7 +1839,8 @@ static int do_write(struct fsg_dev *fsg)
}
/* Wait for something to happen */
if ((rc = sleep_thread(fsg)) != 0)
rc = sleep_thread(fsg);
if (rc)
return rc;
}
@ -2369,7 +2324,8 @@ static int pad_with_zeros(struct fsg_dev *fsg)
/* Wait for the next buffer to be free */
while (bh->state != BUF_STATE_EMPTY) {
if ((rc = sleep_thread(fsg)) != 0)
rc = sleep_thread(fsg);
if (rc)
return rc;
}
@ -2429,7 +2385,8 @@ static int throw_away_data(struct fsg_dev *fsg)
}
/* Otherwise wait for something to happen */
if ((rc = sleep_thread(fsg)) != 0)
rc = sleep_thread(fsg);
if (rc)
return rc;
}
return 0;
@ -2551,7 +2508,8 @@ static int send_status(struct fsg_dev *fsg)
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
if ((rc = sleep_thread(fsg)) != 0)
rc = sleep_thread(fsg);
if (rc)
return rc;
}
@ -2771,9 +2729,10 @@ static int do_scsi_command(struct fsg_dev *fsg)
/* Wait for the next buffer to become available for data or status */
bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
if ((rc = sleep_thread(fsg)) != 0)
rc = sleep_thread(fsg);
if (rc)
return rc;
}
}
fsg->phase_error = 0;
fsg->short_packet_received = 0;
@ -3005,7 +2964,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
/* Is the CBW meaningful? */
if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) {
cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
"cmdlen %u\n",
cbw->Lun, cbw->Flags, cbw->Length);
@ -3045,9 +3004,10 @@ static int get_next_command(struct fsg_dev *fsg)
/* Wait for the next buffer to become available */
bh = fsg->next_buffhd_to_fill;
while (bh->state != BUF_STATE_EMPTY) {
if ((rc = sleep_thread(fsg)) != 0)
rc = sleep_thread(fsg);
if (rc)
return rc;
}
}
/* Queue a request to read a Bulk-only CBW */
set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
@ -3061,9 +3021,10 @@ static int get_next_command(struct fsg_dev *fsg)
/* Wait for the CBW to arrive */
while (bh->state != BUF_STATE_FULL) {
if ((rc = sleep_thread(fsg)) != 0)
rc = sleep_thread(fsg);
if (rc)
return rc;
}
}
smp_rmb();
rc = received_cbw(fsg, bh);
bh->state = BUF_STATE_EMPTY;
@ -3072,9 +3033,10 @@ static int get_next_command(struct fsg_dev *fsg)
/* Wait for the next command to arrive */
while (fsg->cbbuf_cmnd_size == 0) {
if ((rc = sleep_thread(fsg)) != 0)
rc = sleep_thread(fsg);
if (rc)
return rc;
}
}
/* Is the previous status interrupt request still busy?
* The host is allowed to skip reading the status,
@ -3595,7 +3557,8 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
return sprintf(buf, "%d\n", curlun->ro);
}
static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t show_file(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = dev_get_drvdata(dev);
@ -3604,8 +3567,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
down_read(&fsg->filesem);
if (backing_file_is_open(curlun)) { // Get the complete pathname
p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt,
buf, PAGE_SIZE - 1);
p = d_path(curlun->filp->f_path.dentry,
curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1);
if (IS_ERR(p))
rc = PTR_ERR(p);
else {
@ -3623,7 +3586,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
}
static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
static ssize_t store_ro(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
ssize_t rc = count;
struct lun *curlun = dev_to_lun(dev);
@ -3647,7 +3611,8 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
return rc;
}
static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
static ssize_t store_file(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = dev_get_drvdata(dev);
@ -3859,7 +3824,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
/* Find out how many LUNs there should be */
i = mod_data.nluns;
if (i == 0)
i = max(mod_data.num_filenames, 1);
i = max(mod_data.num_filenames, 1u);
if (i > MAX_LUNS) {
ERROR(fsg, "invalid number of LUNs: %d\n", i);
rc = -EINVAL;
@ -3944,22 +3909,24 @@ static int __init fsg_bind(struct usb_gadget *gadget)
intf_desc.bInterfaceProtocol = mod_data.transport_type;
fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
#ifdef CONFIG_USB_GADGET_DUALSPEED
hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
if (gadget_is_dualspeed(gadget)) {
hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
/* Assume ep0 uses the same maxpacket value for both speeds */
dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
/* Assume ep0 uses the same maxpacket value for both speeds */
dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
/* Assume that all endpoint addresses are the same for both speeds */
hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress;
hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress;
hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress;
#endif
if (gadget->is_otg) {
otg_desc.bmAttributes |= USB_OTG_HNP;
/* Assume endpoint addresses are the same for both speeds */
hs_bulk_in_desc.bEndpointAddress =
fs_bulk_in_desc.bEndpointAddress;
hs_bulk_out_desc.bEndpointAddress =
fs_bulk_out_desc.bEndpointAddress;
hs_intr_in_desc.bEndpointAddress =
fs_intr_in_desc.bEndpointAddress;
}
if (gadget_is_otg(gadget))
otg_desc.bmAttributes |= USB_OTG_HNP;
rc = -ENOMEM;
/* Allocate the request and buffer for endpoint 0 */

View File

@ -35,7 +35,7 @@
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
@ -1090,14 +1090,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
*/
static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
{
#ifdef CONFIG_USB_OTG
struct fsl_udc *udc;
udc = container_of(gadget, struct fsl_udc, gadget);
if (udc->transceiver)
return otg_set_power(udc->transceiver, mA);
#endif
return -ENOTSUPP;
}
@ -1120,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
return 0;
}
/* defined in usb_gadget.h */
/* defined in gadget.h */
static struct usb_gadget_ops fsl_gadget_ops = {
.get_frame = fsl_get_frame,
.wakeup = fsl_wakeup,
@ -1321,7 +1318,7 @@ static void setup_received_irq(struct fsl_udc *udc,
| USB_TYPE_STANDARD)) {
/* Note: The driver has not include OTG support yet.
* This will be set when OTG support is added */
if (!udc->gadget.is_otg)
if (!gadget_is_otg(udc->gadget))
break;
else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
udc->gadget.b_hnp_enable = 1;
@ -1330,6 +1327,8 @@ static void setup_received_irq(struct fsl_udc *udc,
else if (setup->bRequest ==
USB_DEVICE_A_ALT_HNP_SUPPORT)
udc->gadget.a_alt_hnp_support = 1;
else
break;
rc = 0;
} else
break;
@ -1840,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
if (!driver || driver != udc_controller->driver || !driver->unbind)
return -EINVAL;
#ifdef CONFIG_USB_OTG
if (udc_controller->transceiver)
(void)otg_set_peripheral(udc_controller->transceiver, 0);
#endif
/* stop DR, disable intr */
dr_controller_stop(udc_controller);

View File

@ -18,17 +18,11 @@
* http://www.usb.org/developers/devclass_docs/midi10.pdf
*/
#define DEBUG 1
// #define VERBOSE
/* #define VERBOSE_DEBUG */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/utsname.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <sound/driver.h>
#include <sound/core.h>
@ -36,7 +30,7 @@
#include <sound/rawmidi.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include <linux/usb/audio.h>
#include <linux/usb/midi.h>
@ -139,30 +133,16 @@ struct gmidi_device {
static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
#define xprintk(d,level,fmt,args...) \
dev_printk(level , &(d)->gadget->dev , fmt , ## args)
#ifdef DEBUG
#define DBG(dev,fmt,args...) \
xprintk(dev , KERN_DEBUG , fmt , ## args)
#else
#define DBG(dev,fmt,args...) \
do { } while (0)
#endif /* DEBUG */
#ifdef VERBOSE
#define VDBG DBG
#else
#define VDBG(dev,fmt,args...) \
do { } while (0)
#endif /* VERBOSE */
#define ERROR(dev,fmt,args...) \
xprintk(dev , KERN_ERR , fmt , ## args)
#define WARN(dev,fmt,args...) \
xprintk(dev , KERN_WARNING , fmt , ## args)
#define INFO(dev,fmt,args...) \
xprintk(dev , KERN_INFO , fmt , ## args)
#define DBG(d, fmt, args...) \
dev_dbg(&(d)->gadget->dev , fmt , ## args)
#define VDBG(d, fmt, args...) \
dev_vdbg(&(d)->gadget->dev , fmt , ## args)
#define ERROR(d, fmt, args...) \
dev_err(&(d)->gadget->dev , fmt , ## args)
#define WARN(d, fmt, args...) \
dev_warn(&(d)->gadget->dev , fmt , ## args)
#define INFO(d, fmt, args...) \
dev_info(&(d)->gadget->dev , fmt , ## args)
static unsigned buflen = 256;
@ -425,7 +405,7 @@ static int config_buf(struct usb_gadget *gadget,
return len;
}
static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length)
static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
{
struct usb_request *req;
@ -455,7 +435,7 @@ static const uint8_t gmidi_cin_length[] = {
* Receives a chunk of MIDI data.
*/
static void gmidi_read_data(struct usb_ep *ep, int cable,
uint8_t* data, int length)
uint8_t *data, int length)
{
struct gmidi_device *dev = ep->driver_data;
/* cable is ignored, because for now we only have one. */
@ -541,7 +521,7 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
{
int err = 0;
struct usb_request *req;
struct usb_ep* ep;
struct usb_ep *ep;
unsigned i;
err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
@ -628,7 +608,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
if (gadget_is_sa1100(gadget) && dev->config) {
/* tx fifo is full, but we can't clear it...*/
INFO(dev, "can't change configurations\n");
ERROR(dev, "can't change configurations\n");
return -ESPIPE;
}
gmidi_reset_config(dev);
@ -843,7 +823,7 @@ static void gmidi_disconnect(struct usb_gadget *gadget)
static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
{
struct gmidi_device *dev = get_gadget_data(gadget);
struct snd_card* card;
struct snd_card *card;
DBG(dev, "unbind\n");
@ -867,12 +847,12 @@ static int gmidi_snd_free(struct snd_device *device)
return 0;
}
static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0,
uint8_t p1, uint8_t p2, uint8_t p3)
{
unsigned length = req->length;
u8 *buf = (u8 *)req->buf + length;
uint8_t* buf = (uint8_t*)req->buf + length;
buf[0] = p0;
buf[1] = p1;
buf[2] = p2;
@ -883,8 +863,8 @@ static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
/*
* Converts MIDI commands to USB MIDI packets.
*/
static void gmidi_transmit_byte(struct usb_request* req,
struct gmidi_in_port* port, uint8_t b)
static void gmidi_transmit_byte(struct usb_request *req,
struct gmidi_in_port *port, uint8_t b)
{
uint8_t p0 = port->cable;
@ -981,10 +961,10 @@ static void gmidi_transmit_byte(struct usb_request* req,
}
}
static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req)
{
struct usb_ep* ep = dev->in_ep;
struct gmidi_in_port* port = &dev->in_port;
struct usb_ep *ep = dev->in_ep;
struct gmidi_in_port *port = &dev->in_port;
if (!ep) {
return;
@ -1020,14 +1000,14 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
static void gmidi_in_tasklet(unsigned long data)
{
struct gmidi_device* dev = (struct gmidi_device*)data;
struct gmidi_device *dev = (struct gmidi_device *)data;
gmidi_transmit(dev, NULL);
}
static int gmidi_in_open(struct snd_rawmidi_substream *substream)
{
struct gmidi_device* dev = substream->rmidi->private_data;
struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_in_open\n");
dev->in_substream = substream;
@ -1037,13 +1017,15 @@ static int gmidi_in_open(struct snd_rawmidi_substream *substream)
static int gmidi_in_close(struct snd_rawmidi_substream *substream)
{
struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_in_close\n");
return 0;
}
static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
{
struct gmidi_device* dev = substream->rmidi->private_data;
struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_in_trigger %d\n", up);
dev->in_port.active = up;
@ -1054,7 +1036,7 @@ static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
static int gmidi_out_open(struct snd_rawmidi_substream *substream)
{
struct gmidi_device* dev = substream->rmidi->private_data;
struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_out_open\n");
dev->out_substream = substream;
@ -1063,13 +1045,15 @@ static int gmidi_out_open(struct snd_rawmidi_substream *substream)
static int gmidi_out_close(struct snd_rawmidi_substream *substream)
{
struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_out_close\n");
return 0;
}
static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
{
struct gmidi_device* dev = substream->rmidi->private_data;
struct gmidi_device *dev = substream->rmidi->private_data;
VDBG(dev, "gmidi_out_trigger %d\n", up);
if (up) {

View File

@ -37,7 +37,7 @@
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>

View File

@ -20,8 +20,7 @@
*/
// #define DEBUG /* data to help fault diagnosis */
// #define VERBOSE /* extra debug messages (success too) */
/* #define VERBOSE_DEBUG */
#include <linux/init.h>
#include <linux/module.h>
@ -38,7 +37,7 @@
#include <linux/moduleparam.h>
#include <linux/usb/gadgetfs.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
/*
@ -253,7 +252,7 @@ static const char *CHIP;
do { } while (0)
#endif /* DEBUG */
#ifdef VERBOSE
#ifdef VERBOSE_DEBUG
#define VDEBUG DBG
#else
#define VDEBUG(dev,fmt,args...) \
@ -1010,11 +1009,12 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
/* assume that was SET_CONFIGURATION */
if (dev->current_config) {
unsigned power;
#ifdef CONFIG_USB_GADGET_DUALSPEED
if (dev->gadget->speed == USB_SPEED_HIGH)
if (gadget_is_dualspeed(dev->gadget)
&& (dev->gadget->speed
== USB_SPEED_HIGH))
power = dev->hs_config->bMaxPower;
else
#endif
power = dev->config->bMaxPower;
usb_gadget_vbus_draw(dev->gadget, 2 * power);
}
@ -1355,24 +1355,21 @@ static int
config_buf (struct dev_data *dev, u8 type, unsigned index)
{
int len;
#ifdef CONFIG_USB_GADGET_DUALSPEED
int hs;
#endif
int hs = 0;
/* only one configuration */
if (index > 0)
return -EINVAL;
#ifdef CONFIG_USB_GADGET_DUALSPEED
hs = (dev->gadget->speed == USB_SPEED_HIGH);
if (type == USB_DT_OTHER_SPEED_CONFIG)
hs = !hs;
if (gadget_is_dualspeed(dev->gadget)) {
hs = (dev->gadget->speed == USB_SPEED_HIGH);
if (type == USB_DT_OTHER_SPEED_CONFIG)
hs = !hs;
}
if (hs) {
dev->req->buf = dev->hs_config;
len = le16_to_cpu(dev->hs_config->wTotalLength);
} else
#endif
{
} else {
dev->req->buf = dev->config;
len = le16_to_cpu(dev->config->wTotalLength);
}
@ -1393,13 +1390,13 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
spin_lock (&dev->lock);
dev->setup_abort = 0;
if (dev->state == STATE_DEV_UNCONNECTED) {
#ifdef CONFIG_USB_GADGET_DUALSPEED
if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == NULL) {
if (gadget_is_dualspeed(gadget)
&& gadget->speed == USB_SPEED_HIGH
&& dev->hs_config == NULL) {
spin_unlock(&dev->lock);
ERROR (dev, "no high speed config??\n");
return -EINVAL;
}
#endif /* CONFIG_USB_GADGET_DUALSPEED */
dev->state = STATE_DEV_CONNECTED;
dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
@ -1469,13 +1466,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
// user mode expected to disable endpoints
} else {
u8 config, power;
#ifdef CONFIG_USB_GADGET_DUALSPEED
if (gadget->speed == USB_SPEED_HIGH) {
if (gadget_is_dualspeed(gadget)
&& gadget->speed == USB_SPEED_HIGH) {
config = dev->hs_config->bConfigurationValue;
power = dev->hs_config->bMaxPower;
} else
#endif
{
} else {
config = dev->config->bConfigurationValue;
power = dev->config->bMaxPower;
}

View File

@ -50,7 +50,7 @@
#include <asm/hardware.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
/*
* Memory map

View File

@ -27,7 +27,7 @@
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include "m66592-udc.h"

View File

@ -62,7 +62,7 @@
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>

View File

@ -38,7 +38,7 @@
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <linux/clk.h>
@ -1241,19 +1241,15 @@ static void pullup_enable(struct omap_udc *udc)
udc->gadget.dev.parent->power.power_state = PMSG_ON;
udc->gadget.dev.power.power_state = PMSG_ON;
UDC_SYSCON1_REG |= UDC_PULLUP_EN;
#ifndef CONFIG_USB_OTG
if (!cpu_is_omap15xx())
if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
OTG_CTRL_REG |= OTG_BSESSVLD;
#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
}
static void pullup_disable(struct omap_udc *udc)
{
#ifndef CONFIG_USB_OTG
if (!cpu_is_omap15xx())
if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
OTG_CTRL_REG &= ~OTG_BSESSVLD;
#endif
UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
}
@ -1390,7 +1386,7 @@ static void update_otg(struct omap_udc *udc)
{
u16 devstat;
if (!udc->gadget.is_otg)
if (!gadget_is_otg(udc->gadget))
return;
if (OTG_CTRL_REG & OTG_ID)

View File

@ -54,7 +54,7 @@
#include <asm/hardware.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include <asm/mach/udc_pxa2xx.h>

View File

@ -42,7 +42,7 @@
#include <linux/seq_file.h>
#include <linux/usb.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
#include <asm/io.h>

View File

@ -17,34 +17,15 @@
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/utsname.h>
#include <linux/wait.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/mutex.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/uaccess.h>
#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include "gadget_chips.h"
@ -89,30 +70,29 @@
#define GS_DEFAULT_PARITY USB_CDC_NO_PARITY
#define GS_DEFAULT_CHAR_FORMAT USB_CDC_1_STOP_BITS
/* select highspeed/fullspeed, hiding highspeed if not configured */
#ifdef CONFIG_USB_GADGET_DUALSPEED
#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs))
#else
#define GS_SPEED_SELECT(is_hs,hs,fs) (fs)
#endif /* CONFIG_USB_GADGET_DUALSPEED */
/* maxpacket and other transfer characteristics vary by speed. */
static inline struct usb_endpoint_descriptor *
choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
struct usb_endpoint_descriptor *fs)
{
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
}
/* debug settings */
#ifdef GS_DEBUG
#ifdef DEBUG
static int debug = 1;
#else
#define debug 0
#endif
#define gs_debug(format, arg...) \
do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
#define gs_debug_level(level, format, arg...) \
do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
#else
#define gs_debug(format, arg...) \
do { } while(0)
#define gs_debug_level(level, format, arg...) \
do { } while(0)
#endif /* GS_DEBUG */
/* Thanks to NetChip Technologies for donating this product ID.
*
@ -147,10 +127,10 @@ struct gs_req_entry {
/* the port structure holds info for each port, one for each minor number */
struct gs_port {
struct gs_dev *port_dev; /* pointer to device struct */
struct gs_dev *port_dev; /* pointer to device struct */
struct tty_struct *port_tty; /* pointer to tty struct */
spinlock_t port_lock;
int port_num;
int port_num;
int port_open_count;
int port_in_use; /* open/close in progress */
wait_queue_head_t port_write_wait;/* waiting to write */
@ -188,7 +168,7 @@ static void __exit gs_module_exit(void);
/* tty driver */
static int gs_open(struct tty_struct *tty, struct file *file);
static void gs_close(struct tty_struct *tty, struct file *file);
static int gs_write(struct tty_struct *tty,
static int gs_write(struct tty_struct *tty,
const unsigned char *buf, int count);
static void gs_put_char(struct tty_struct *tty, unsigned char ch);
static void gs_flush_chars(struct tty_struct *tty);
@ -222,7 +202,7 @@ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
static void gs_disconnect(struct usb_gadget *gadget);
static int gs_set_config(struct gs_dev *dev, unsigned config);
static void gs_reset_config(struct gs_dev *dev);
static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
u8 type, unsigned int index, int is_otg);
static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
@ -415,18 +395,18 @@ static const struct usb_cdc_header_desc gs_header_desc = {
};
static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
.bLength = sizeof(gs_call_mgmt_descriptor),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
.bmCapabilities = 0,
.bDataInterface = 1, /* index of data interface */
.bLength = sizeof(gs_call_mgmt_descriptor),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE,
.bmCapabilities = 0,
.bDataInterface = 1, /* index of data interface */
};
static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
.bLength = sizeof(gs_acm_descriptor),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_ACM_TYPE,
.bmCapabilities = 0,
.bLength = sizeof(gs_acm_descriptor),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_ACM_TYPE,
.bmCapabilities = 0,
};
static const struct usb_cdc_union_desc gs_union_desc = {
@ -436,7 +416,7 @@ static const struct usb_cdc_union_desc gs_union_desc = {
.bMasterInterface0 = 0, /* index of control interface */
.bSlaveInterface0 = 1, /* index of data interface */
};
static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -482,7 +462,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
NULL,
};
#ifdef CONFIG_USB_GADGET_DUALSPEED
static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@ -536,15 +515,13 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
NULL,
};
#endif /* CONFIG_USB_GADGET_DUALSPEED */
/* Module */
MODULE_DESCRIPTION(GS_LONG_NAME);
MODULE_AUTHOR("Al Borchers");
MODULE_LICENSE("GPL");
#ifdef GS_DEBUG
#ifdef DEBUG
module_param(debug, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
#endif
@ -915,7 +892,8 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
return;
}
gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2));
gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
port->port_num, tty, ch, __builtin_return_address(0));
spin_lock_irqsave(&port->port_lock, flags);
@ -1116,7 +1094,11 @@ static int gs_send(struct gs_dev *dev)
len = gs_send_packet(dev, req->buf, ep->maxpacket);
if (len > 0) {
gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
gs_debug_level(3, "gs_send: len=%d, 0x%2.2x "
"0x%2.2x 0x%2.2x ...\n", len,
*((unsigned char *)req->buf),
*((unsigned char *)req->buf+1),
*((unsigned char *)req->buf+2));
list_del(&req_entry->re_entry);
req->length = len;
spin_unlock_irqrestore(&dev->dev_lock, flags);
@ -1269,7 +1251,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
switch(req->status) {
case 0:
/* normal completion */
/* normal completion */
gs_recv_packet(dev, req->buf, req->actual);
requeue:
req->length = ep->maxpacket;
@ -1406,23 +1388,24 @@ static int __init gs_bind(struct usb_gadget *gadget)
? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
#ifdef CONFIG_USB_GADGET_DUALSPEED
gs_qualifier_desc.bDeviceClass = use_acm
? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
/* assume ep0 uses the same packet size for both speeds */
gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0;
/* assume endpoints are dual-speed */
gs_highspeed_notify_desc.bEndpointAddress =
gs_fullspeed_notify_desc.bEndpointAddress;
gs_highspeed_in_desc.bEndpointAddress =
gs_fullspeed_in_desc.bEndpointAddress;
gs_highspeed_out_desc.bEndpointAddress =
gs_fullspeed_out_desc.bEndpointAddress;
#endif /* CONFIG_USB_GADGET_DUALSPEED */
if (gadget_is_dualspeed(gadget)) {
gs_qualifier_desc.bDeviceClass = use_acm
? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
/* assume ep0 uses the same packet size for both speeds */
gs_qualifier_desc.bMaxPacketSize0 =
gs_device_desc.bMaxPacketSize0;
/* assume endpoints are dual-speed */
gs_highspeed_notify_desc.bEndpointAddress =
gs_fullspeed_notify_desc.bEndpointAddress;
gs_highspeed_in_desc.bEndpointAddress =
gs_fullspeed_in_desc.bEndpointAddress;
gs_highspeed_out_desc.bEndpointAddress =
gs_fullspeed_out_desc.bEndpointAddress;
}
usb_gadget_set_selfpowered(gadget);
if (gadget->is_otg) {
if (gadget_is_otg(gadget)) {
gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@ -1487,6 +1470,12 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
dev->dev_ctrl_req = NULL;
}
gs_free_ports(dev);
if (dev->dev_notify_ep)
usb_ep_disable(dev->dev_notify_ep);
if (dev->dev_in_ep)
usb_ep_disable(dev->dev_in_ep);
if (dev->dev_out_ep)
usb_ep_disable(dev->dev_out_ep);
kfree(dev);
set_gadget_data(gadget, NULL);
}
@ -1570,9 +1559,8 @@ static int gs_setup_standard(struct usb_gadget *gadget,
memcpy(req->buf, &gs_device_desc, ret);
break;
#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
if (!gadget->is_dualspeed)
if (!gadget_is_dualspeed(gadget))
break;
ret = min(wLength,
(u16)sizeof(struct usb_qualifier_descriptor));
@ -1580,14 +1568,13 @@ static int gs_setup_standard(struct usb_gadget *gadget,
break;
case USB_DT_OTHER_SPEED_CONFIG:
if (!gadget->is_dualspeed)
if (!gadget_is_dualspeed(gadget))
break;
/* fall through */
#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
ret = gs_build_config_buf(req->buf, gadget->speed,
ret = gs_build_config_buf(req->buf, gadget,
wValue >> 8, wValue & 0xff,
gadget->is_otg);
gadget_is_otg(gadget));
if (ret >= 0)
ret = min(wLength, (u16)ret);
break;
@ -1827,8 +1814,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
if (EP_NOTIFY_NAME
&& strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
ep_desc = GS_SPEED_SELECT(
gadget->speed == USB_SPEED_HIGH,
ep_desc = choose_ep_desc(gadget,
&gs_highspeed_notify_desc,
&gs_fullspeed_notify_desc);
ret = usb_ep_enable(ep,ep_desc);
@ -1844,9 +1830,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
}
else if (strcmp(ep->name, EP_IN_NAME) == 0) {
ep_desc = GS_SPEED_SELECT(
gadget->speed == USB_SPEED_HIGH,
&gs_highspeed_in_desc,
ep_desc = choose_ep_desc(gadget,
&gs_highspeed_in_desc,
&gs_fullspeed_in_desc);
ret = usb_ep_enable(ep,ep_desc);
if (ret == 0) {
@ -1861,8 +1846,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
}
else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
ep_desc = GS_SPEED_SELECT(
gadget->speed == USB_SPEED_HIGH,
ep_desc = choose_ep_desc(gadget,
&gs_highspeed_out_desc,
&gs_fullspeed_out_desc);
ret = usb_ep_enable(ep,ep_desc);
@ -1981,11 +1965,11 @@ static void gs_reset_config(struct gs_dev *dev)
* Builds the config descriptors in the given buffer and returns the
* length, or a negative error number.
*/
static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
u8 type, unsigned int index, int is_otg)
{
int len;
int high_speed;
int high_speed = 0;
const struct usb_config_descriptor *config_desc;
const struct usb_descriptor_header **function;
@ -1993,20 +1977,22 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
return -EINVAL;
/* other speed switches high and full speed */
high_speed = (speed == USB_SPEED_HIGH);
if (type == USB_DT_OTHER_SPEED_CONFIG)
high_speed = !high_speed;
if (gadget_is_dualspeed(g)) {
high_speed = (g->speed == USB_SPEED_HIGH);
if (type == USB_DT_OTHER_SPEED_CONFIG)
high_speed = !high_speed;
}
if (use_acm) {
config_desc = &gs_acm_config_desc;
function = GS_SPEED_SELECT(high_speed,
gs_acm_highspeed_function,
gs_acm_fullspeed_function);
function = high_speed
? gs_acm_highspeed_function
: gs_acm_fullspeed_function;
} else {
config_desc = &gs_bulk_config_desc;
function = GS_SPEED_SELECT(high_speed,
gs_bulk_highspeed_function,
gs_bulk_fullspeed_function);
function = high_speed
? gs_bulk_highspeed_function
: gs_bulk_fullspeed_function;
}
/* for now, don't advertise srp-only devices */

View File

@ -15,7 +15,7 @@
#include <linux/init.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include <asm/unaligned.h>

View File

@ -1,38 +1,22 @@
/*
* zero.c -- Gadget Zero, for USB development
*
* Copyright (C) 2003-2004 David Brownell
* Copyright (C) 2003-2007 David Brownell
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the above-listed copyright holders may not be used
* to endorse or promote products derived from this software without
* specific prior written permission.
* 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.
*
* ALTERNATIVELY, this software may be distributed under the terms of the
* GNU General Public License ("GPL") as published by the Free Software
* Foundation, either version 2 of that 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* 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
*/
@ -57,40 +41,28 @@
* Many drivers will only have one configuration, letting them be much
* simpler if they also don't support high speed operation (like this
* driver does).
*
* Why is *this* driver using two configurations, rather than setting up
* two interfaces with different functions? To help verify that multiple
* configuration infrastucture is working correctly; also, so that it can
* work with low capability USB controllers without four bulk endpoints.
*/
#define DEBUG 1
// #define VERBOSE
/* #define VERBOSE_DEBUG */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/utsname.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/gadget.h>
#include "gadget_chips.h"
/*-------------------------------------------------------------------------*/
#define DRIVER_VERSION "St Patrick's Day 2004"
#define DRIVER_VERSION "Lughnasadh, 2007"
static const char shortname [] = "zero";
static const char longname [] = "Gadget Zero";
@ -131,30 +103,16 @@ struct zero_dev {
struct timer_list resume;
};
#define xprintk(d,level,fmt,args...) \
dev_printk(level , &(d)->gadget->dev , fmt , ## args)
#ifdef DEBUG
#define DBG(dev,fmt,args...) \
xprintk(dev , KERN_DEBUG , fmt , ## args)
#else
#define DBG(dev,fmt,args...) \
do { } while (0)
#endif /* DEBUG */
#ifdef VERBOSE
#define VDBG DBG
#else
#define VDBG(dev,fmt,args...) \
do { } while (0)
#endif /* VERBOSE */
#define ERROR(dev,fmt,args...) \
xprintk(dev , KERN_ERR , fmt , ## args)
#define WARN(dev,fmt,args...) \
xprintk(dev , KERN_WARNING , fmt , ## args)
#define INFO(dev,fmt,args...) \
xprintk(dev , KERN_INFO , fmt , ## args)
#define DBG(d, fmt, args...) \
dev_dbg(&(d)->gadget->dev , fmt , ## args)
#define VDBG(d, fmt, args...) \
dev_vdbg(&(d)->gadget->dev , fmt , ## args)
#define ERROR(d, fmt, args...) \
dev_err(&(d)->gadget->dev , fmt , ## args)
#define WARN(d, fmt, args...) \
dev_warn(&(d)->gadget->dev , fmt , ## args)
#define INFO(d, fmt, args...) \
dev_info(&(d)->gadget->dev , fmt , ## args)
/*-------------------------------------------------------------------------*/
@ -326,8 +284,6 @@ static const struct usb_descriptor_header *fs_loopback_function [] = {
NULL,
};
#ifdef CONFIG_USB_GADGET_DUALSPEED
/*
* usb 2.0 devices need to expose both high speed and full speed
* descriptors, unless they only run at full speed.
@ -383,17 +339,20 @@ static const struct usb_descriptor_header *hs_loopback_function [] = {
};
/* maxpacket and other transfer characteristics vary by speed. */
#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
static inline struct usb_endpoint_descriptor *
ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
struct usb_endpoint_descriptor *fs)
{
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
}
#else
static char manufacturer[50];
/* if there's no high speed support, maxpacket doesn't change. */
#define ep_desc(g,hs,fs) fs
/* default serial number takes at least two packets */
static char serial[] = "0123456789.0123456789.0123456789";
#endif /* !CONFIG_USB_GADGET_DUALSPEED */
static char manufacturer [50];
static char serial [40];
/* static strings, in UTF-8 */
static struct usb_string strings [] = {
@ -435,30 +394,29 @@ config_buf (struct usb_gadget *gadget,
int is_source_sink;
int len;
const struct usb_descriptor_header **function;
#ifdef CONFIG_USB_GADGET_DUALSPEED
int hs = (gadget->speed == USB_SPEED_HIGH);
#endif
int hs = 0;
/* two configurations will always be index 0 and index 1 */
if (index > 1)
return -EINVAL;
is_source_sink = loopdefault ? (index == 1) : (index == 0);
#ifdef CONFIG_USB_GADGET_DUALSPEED
if (type == USB_DT_OTHER_SPEED_CONFIG)
hs = !hs;
if (gadget_is_dualspeed(gadget)) {
hs = (gadget->speed == USB_SPEED_HIGH);
if (type == USB_DT_OTHER_SPEED_CONFIG)
hs = !hs;
}
if (hs)
function = is_source_sink
? hs_source_sink_function
: hs_loopback_function;
else
#endif
function = is_source_sink
? fs_source_sink_function
: fs_loopback_function;
/* for now, don't advertise srp-only devices */
if (!gadget->is_otg)
if (!gadget_is_otg(gadget))
function++;
len = usb_gadget_config_buf (is_source_sink
@ -498,6 +456,19 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
/*-------------------------------------------------------------------------*/
/*
* SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals,
* this just sinks bulk packets OUT to the peripheral and sources them IN
* to the host, optionally with specific data patterns.
*
* In terms of control messaging, this supports all the standard requests
* plus two that support control-OUT tests.
*
* Note that because this doesn't queue more than one request at a time,
* some other function must be used to test queueing logic. The network
* link (g_ether) is probably the best option for that.
*/
/* optionally require specific source/sink data patterns */
static int
@ -534,12 +505,7 @@ check_read_data (
return 0;
}
static void
reinit_write_data (
struct zero_dev *dev,
struct usb_ep *ep,
struct usb_request *req
)
static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
{
unsigned i;
u8 *buf = req->buf;
@ -566,16 +532,16 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
switch (status) {
case 0: /* normal completion? */
case 0: /* normal completion? */
if (ep == dev->out_ep) {
check_read_data (dev, ep, req);
memset (req->buf, 0x55, req->length);
} else
reinit_write_data (dev, ep, req);
reinit_write_data(ep, req);
break;
/* this endpoint is normally active while we're configured */
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
@ -607,8 +573,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
}
}
static struct usb_request *
source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
{
struct usb_request *req;
int status;
@ -621,11 +586,11 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
req->complete = source_sink_complete;
if (strcmp (ep->name, EP_IN_NAME) == 0)
reinit_write_data (ep->driver_data, ep, req);
reinit_write_data(ep, req);
else
memset (req->buf, 0x55, req->length);
status = usb_ep_queue (ep, req, gfp_flags);
status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status) {
struct zero_dev *dev = ep->driver_data;
@ -637,8 +602,7 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
return req;
}
static int
set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
static int set_source_sink_config(struct zero_dev *dev)
{
int result = 0;
struct usb_ep *ep;
@ -653,8 +617,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
result = usb_ep_enable (ep, d);
if (result == 0) {
ep->driver_data = dev;
if (source_sink_start_ep(ep, gfp_flags)
!= NULL) {
if (source_sink_start_ep(ep) != NULL) {
dev->in_ep = ep;
continue;
}
@ -668,8 +631,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
result = usb_ep_enable (ep, d);
if (result == 0) {
ep->driver_data = dev;
if (source_sink_start_ep(ep, gfp_flags)
!= NULL) {
if (source_sink_start_ep(ep) != NULL) {
dev->out_ep = ep;
continue;
}
@ -701,7 +663,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
switch (status) {
case 0: /* normal completion? */
case 0: /* normal completion? */
if (ep == dev->out_ep) {
/* loop this OUT packet back IN to the host */
req->zero = (req->actual < req->length);
@ -735,7 +697,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
* rely on the hardware driver to clean up on disconnect or
* endpoint disable.
*/
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
free_ep_req (ep, req);
@ -743,8 +705,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
}
}
static int
set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags)
static int set_loopback_config(struct zero_dev *dev)
{
int result = 0;
struct usb_ep *ep;
@ -844,8 +805,7 @@ static void zero_reset_config (struct zero_dev *dev)
* code can do, perhaps by disallowing more than one configuration or
* by limiting configuration choices (like the pxa2xx).
*/
static int
zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
static int zero_set_config(struct zero_dev *dev, unsigned number)
{
int result = 0;
struct usb_gadget *gadget = dev->gadget;
@ -855,17 +815,17 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
if (gadget_is_sa1100 (gadget) && dev->config) {
/* tx fifo is full, but we can't clear it...*/
INFO (dev, "can't change configurations\n");
ERROR(dev, "can't change configurations\n");
return -ESPIPE;
}
zero_reset_config (dev);
switch (number) {
case CONFIG_SOURCE_SINK:
result = set_source_sink_config (dev, gfp_flags);
result = set_source_sink_config(dev);
break;
case CONFIG_LOOPBACK:
result = set_loopback_config (dev, gfp_flags);
result = set_loopback_config(dev);
break;
default:
result = -EINVAL;
@ -885,7 +845,7 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break;
case USB_SPEED_HIGH: speed = "high"; break;
default: speed = "?"; break;
default: speed = "?"; break;
}
dev->config = number;
@ -938,19 +898,17 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
value = min (w_length, (u16) sizeof device_desc);
memcpy (req->buf, &device_desc, value);
break;
#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
if (!gadget->is_dualspeed)
if (!gadget_is_dualspeed(gadget))
break;
value = min (w_length, (u16) sizeof dev_qualifier);
memcpy (req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
if (!gadget->is_dualspeed)
if (!gadget_is_dualspeed(gadget))
break;
// FALLTHROUGH
#endif /* CONFIG_USB_GADGET_DUALSPEED */
case USB_DT_CONFIG:
value = config_buf (gadget, req->buf,
w_value >> 8,
@ -984,7 +942,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
else
VDBG (dev, "HNP inactive\n");
spin_lock (&dev->lock);
value = zero_set_config (dev, w_value, GFP_ATOMIC);
value = zero_set_config(dev, w_value);
spin_unlock (&dev->lock);
break;
case USB_REQ_GET_CONFIGURATION:
@ -1013,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
* use this "reset the config" shortcut.
*/
zero_reset_config (dev);
zero_set_config (dev, config, GFP_ATOMIC);
zero_set_config(dev, config);
value = 0;
}
spin_unlock (&dev->lock);
@ -1163,7 +1121,7 @@ autoconf_fail:
}
EP_IN_NAME = ep->name;
ep->driver_data = ep; /* claim */
ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
if (!ep)
goto autoconf_fail;
@ -1207,16 +1165,18 @@ autoconf_fail:
device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
#ifdef CONFIG_USB_GADGET_DUALSPEED
/* assume ep0 uses the same value for both speeds ... */
dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
if (gadget_is_dualspeed(gadget)) {
/* assume ep0 uses the same value for both speeds ... */
dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
/* and that all endpoints are dual-speed */
hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
#endif
/* and that all endpoints are dual-speed */
hs_source_desc.bEndpointAddress =
fs_source_desc.bEndpointAddress;
hs_sink_desc.bEndpointAddress =
fs_sink_desc.bEndpointAddress;
}
if (gadget->is_otg) {
if (gadget_is_otg(gadget)) {
otg_descriptor.bmAttributes |= USB_OTG_HNP,
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@ -1294,23 +1254,18 @@ static struct usb_gadget_driver zero_driver = {
.suspend = zero_suspend,
.resume = zero_resume,
.driver = {
.driver = {
.name = (char *) shortname,
.owner = THIS_MODULE,
},
};
MODULE_AUTHOR ("David Brownell");
MODULE_LICENSE ("Dual BSD/GPL");
MODULE_AUTHOR("David Brownell");
MODULE_LICENSE("GPL");
static int __init init (void)
{
/* a real value would likely come through some id prom
* or module option. this one takes at least two packets.
*/
strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial);
return usb_gadget_register_driver (&zero_driver);
}
module_init (init);

View File

@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI
Enables support for PCI-bus plug-in USB controller cards.
If unsure, say Y.
config USB_OHCI_HCD_SSB
bool "OHCI support for Broadcom SSB OHCI core"
depends on USB_OHCI_HCD && SSB && EXPERIMENTAL
default n
---help---
Support for the Sonics Silicon Backplane (SSB) attached
Broadcom USB OHCI core.
This device is present in some embedded devices with
Broadcom based SSB bus.
If unsure, say N.
config USB_OHCI_BIG_ENDIAN_DESC
bool
depends on USB_OHCI_HCD

View File

@ -220,10 +220,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
#ifdef CONFIG_PM
.hub_suspend = ehci_hub_suspend,
.hub_resume = ehci_hub_resume,
#endif
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
};
/*-------------------------------------------------------------------------*/

View File

@ -570,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd)
* are explicitly handed to companion controller(s), so no TT is
* involved with the root hub. (Except where one is integrated,
* and there's no companion controller unless maybe for USB OTG.)
*
* Turning on the CF flag will transfer ownership of all ports
* from the companions to the EHCI controller. If any of the
* companions are in the middle of a port reset at the time, it
* could cause trouble. Write-locking ehci_cf_port_reset_rwsem
* guarantees that no resets are in progress.
*/
down_write(&ehci_cf_port_reset_rwsem);
hcd->state = HC_STATE_RUNNING;
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
up_write(&ehci_cf_port_reset_rwsem);
temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info (ehci,
@ -719,7 +727,6 @@ dead:
*/
static int ehci_urb_enqueue (
struct usb_hcd *hcd,
struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
@ -734,12 +741,12 @@ static int ehci_urb_enqueue (
default:
if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;
return submit_async (ehci, ep, urb, &qtd_list, mem_flags);
return submit_async(ehci, urb, &qtd_list, mem_flags);
case PIPE_INTERRUPT:
if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
return -ENOMEM;
return intr_submit (ehci, ep, urb, &qtd_list, mem_flags);
return intr_submit(ehci, urb, &qtd_list, mem_flags);
case PIPE_ISOCHRONOUS:
if (urb->dev->speed == USB_SPEED_HIGH)
@ -777,13 +784,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
* completions normally happen asynchronously
*/
static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct ehci_qh *qh;
unsigned long flags;
int rc;
spin_lock_irqsave (&ehci->lock, flags);
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (rc)
goto done;
switch (usb_pipetype (urb->pipe)) {
// case PIPE_CONTROL:
// case PIPE_BULK:
@ -838,7 +850,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
}
done:
spin_unlock_irqrestore (&ehci->lock, flags);
return 0;
return rc;
}
/*-------------------------------------------------------------------------*/

View File

@ -58,8 +58,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
if (!retval)
ehci_dbg(ehci, "MWI active\n");
ehci_port_power(ehci, 0);
return 0;
}
@ -156,8 +154,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
break;
}
if (ehci_is_TDI(ehci))
ehci_reset(ehci);
ehci_reset(ehci);
/* at least the Genesys GL880S needs fixup here */
temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);

View File

@ -160,10 +160,8 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = {
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
#ifdef CONFIG_PM
.hub_suspend = ehci_hub_suspend,
.hub_resume = ehci_hub_resume,
#endif
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
};
static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)

View File

@ -47,7 +47,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
if (result)
return result;
ehci_port_power(ehci, 0);
ehci_reset(ehci);
return result;
}

View File

@ -139,63 +139,65 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
static void qtd_copy_status (
static int qtd_copy_status (
struct ehci_hcd *ehci,
struct urb *urb,
size_t length,
u32 token
)
{
int status = -EINPROGRESS;
/* count IN/OUT bytes, not SETUP (even short packets) */
if (likely (QTD_PID (token) != 2))
urb->actual_length += length - QTD_LENGTH (token);
/* don't modify error codes */
if (unlikely (urb->status != -EINPROGRESS))
return;
if (unlikely(urb->unlinked))
return status;
/* force cleanup after short read; not always an error */
if (unlikely (IS_SHORT_READ (token)))
urb->status = -EREMOTEIO;
status = -EREMOTEIO;
/* serious "can't proceed" faults reported by the hardware */
if (token & QTD_STS_HALT) {
if (token & QTD_STS_BABBLE) {
/* FIXME "must" disable babbling device's port too */
urb->status = -EOVERFLOW;
status = -EOVERFLOW;
} else if (token & QTD_STS_MMF) {
/* fs/ls interrupt xfer missed the complete-split */
urb->status = -EPROTO;
status = -EPROTO;
} else if (token & QTD_STS_DBE) {
urb->status = (QTD_PID (token) == 1) /* IN ? */
status = (QTD_PID (token) == 1) /* IN ? */
? -ENOSR /* hc couldn't read data */
: -ECOMM; /* hc couldn't write data */
} else if (token & QTD_STS_XACT) {
/* timeout, bad crc, wrong PID, etc; retried */
if (QTD_CERR (token))
urb->status = -EPIPE;
status = -EPIPE;
else {
ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
urb->dev->devpath,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out");
urb->status = -EPROTO;
status = -EPROTO;
}
/* CERR nonzero + no errors + halt --> stall */
} else if (QTD_CERR (token))
urb->status = -EPIPE;
status = -EPIPE;
else /* unknown */
urb->status = -EPROTO;
status = -EPROTO;
ehci_vdbg (ehci,
"dev%d ep%d%s qtd token %08x --> status %d\n",
usb_pipedevice (urb->pipe),
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
token, urb->status);
token, status);
/* if async CSPLIT failed, try cleaning out the TT buffer */
if (urb->status != -EPIPE
if (status != -EPIPE
&& urb->dev->tt && !usb_pipeint (urb->pipe)
&& ((token & QTD_STS_MMF) != 0
|| QTD_CERR(token) == 0)
@ -212,10 +214,12 @@ static void qtd_copy_status (
usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
}
}
return status;
}
static void
ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
__releases(ehci->lock)
__acquires(ehci->lock)
{
@ -231,25 +235,13 @@ __acquires(ehci->lock)
qh_put (qh);
}
spin_lock (&urb->lock);
urb->hcpriv = NULL;
switch (urb->status) {
case -EINPROGRESS: /* success */
urb->status = 0;
default: /* fault */
COUNT (ehci->stats.complete);
break;
case -EREMOTEIO: /* fault or normal */
if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
urb->status = 0;
COUNT (ehci->stats.complete);
break;
case -ECONNRESET: /* canceled */
case -ENOENT:
COUNT (ehci->stats.unlink);
break;
if (unlikely(urb->unlinked)) {
COUNT(ehci->stats.unlink);
} else {
if (likely(status == -EINPROGRESS))
status = 0;
COUNT(ehci->stats.complete);
}
spin_unlock (&urb->lock);
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
@ -257,13 +249,14 @@ __acquires(ehci->lock)
__FUNCTION__, urb->dev->devpath, urb,
usb_pipeendpoint (urb->pipe),
usb_pipein (urb->pipe) ? "in" : "out",
urb->status,
status,
urb->actual_length, urb->transfer_buffer_length);
#endif
/* complete() can reenter this HCD */
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
spin_unlock (&ehci->lock);
usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb);
usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
spin_lock (&ehci->lock);
}
@ -283,6 +276,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
struct ehci_qtd *last = NULL, *end = qh->dummy;
struct list_head *entry, *tmp;
int last_status = -EINPROGRESS;
int stopped;
unsigned count = 0;
int do_status = 0;
@ -311,6 +305,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
struct ehci_qtd *qtd;
struct urb *urb;
u32 token = 0;
int qtd_status;
qtd = list_entry (entry, struct ehci_qtd, qtd_list);
urb = qtd->urb;
@ -318,11 +313,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* clean up any state from previous QTD ...*/
if (last) {
if (likely (last->urb != urb)) {
ehci_urb_done (ehci, last->urb);
ehci_urb_done(ehci, last->urb, last_status);
count++;
}
ehci_qtd_free (ehci, last);
last = NULL;
last_status = -EINPROGRESS;
}
/* ignore urbs submitted during completions we reported */
@ -358,13 +354,14 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
stopped = 1;
if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
urb->status = -ESHUTDOWN;
last_status = -ESHUTDOWN;
/* ignore active urbs unless some previous qtd
* for the urb faulted (including short read) or
* its urb was canceled. we may patch qh or qtds.
*/
if (likely (urb->status == -EINPROGRESS))
if (likely(last_status == -EINPROGRESS &&
!urb->unlinked))
continue;
/* issue status after short control reads */
@ -392,11 +389,14 @@ halt:
}
/* remove it from the queue */
spin_lock (&urb->lock);
qtd_copy_status (ehci, urb, qtd->length, token);
do_status = (urb->status == -EREMOTEIO)
&& usb_pipecontrol (urb->pipe);
spin_unlock (&urb->lock);
qtd_status = qtd_copy_status(ehci, urb, qtd->length, token);
if (unlikely(qtd_status == -EREMOTEIO)) {
do_status = (!urb->unlinked &&
usb_pipecontrol(urb->pipe));
qtd_status = 0;
}
if (likely(last_status == -EINPROGRESS))
last_status = qtd_status;
if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
last = list_entry (qtd->qtd_list.prev,
@ -409,7 +409,7 @@ halt:
/* last urb's completion might still need calling */
if (likely (last != NULL)) {
ehci_urb_done (ehci, last->urb);
ehci_urb_done(ehci, last->urb, last_status);
count++;
ehci_qtd_free (ehci, last);
}
@ -913,7 +913,6 @@ static struct ehci_qh *qh_append_tds (
static int
submit_async (
struct ehci_hcd *ehci,
struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
gfp_t mem_flags
@ -922,10 +921,10 @@ submit_async (
int epnum;
unsigned long flags;
struct ehci_qh *qh = NULL;
int rc = 0;
int rc;
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
epnum = ep->desc.bEndpointAddress;
epnum = urb->ep->desc.bEndpointAddress;
#ifdef EHCI_URB_TRACE
ehci_dbg (ehci,
@ -933,7 +932,7 @@ submit_async (
__FUNCTION__, urb->dev->devpath, urb,
epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
urb->transfer_buffer_length,
qtd, ep->hcpriv);
qtd, urb->ep->hcpriv);
#endif
spin_lock_irqsave (&ehci->lock, flags);
@ -942,9 +941,13 @@ submit_async (
rc = -ESHUTDOWN;
goto done;
}
rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
if (unlikely(rc))
goto done;
qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
if (unlikely(qh == NULL)) {
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
rc = -ENOMEM;
goto done;
}

View File

@ -797,7 +797,6 @@ done:
static int intr_submit (
struct ehci_hcd *ehci,
struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
gfp_t mem_flags
@ -805,23 +804,26 @@ static int intr_submit (
unsigned epnum;
unsigned long flags;
struct ehci_qh *qh;
int status = 0;
int status;
struct list_head empty;
/* get endpoint and transfer/schedule data */
epnum = ep->desc.bEndpointAddress;
epnum = urb->ep->desc.bEndpointAddress;
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
goto done;
goto done_not_linked;
}
status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
if (unlikely(status))
goto done_not_linked;
/* get qh and force any scheduling errors */
INIT_LIST_HEAD (&empty);
qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv);
if (qh == NULL) {
status = -ENOMEM;
goto done;
@ -832,13 +834,16 @@ static int intr_submit (
}
/* then queue the urb's tds to the qh */
qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
BUG_ON (qh == NULL);
/* ... update usbfs periodic stats */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
done:
if (unlikely(status))
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
if (status)
qtd_list_free (ehci, urb, qtd_list);
@ -1622,7 +1627,7 @@ itd_complete (
/* give urb back to the driver ... can be out-of-order */
dev = urb->dev;
ehci_urb_done (ehci, urb);
ehci_urb_done(ehci, urb, 0);
urb = NULL;
/* defer stopping schedule; completion can submit */
@ -1686,12 +1691,19 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags)))
&ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
else
status = iso_stream_schedule (ehci, urb, stream);
goto done_not_linked;
}
status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
if (unlikely(status))
goto done_not_linked;
status = iso_stream_schedule(ehci, urb, stream);
if (likely (status == 0))
itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
else
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
done:
@ -1988,7 +2000,7 @@ sitd_complete (
/* give urb back to the driver */
dev = urb->dev;
ehci_urb_done (ehci, urb);
ehci_urb_done(ehci, urb, 0);
urb = NULL;
/* defer stopping schedule; completion can submit */
@ -2049,12 +2061,19 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags)))
&ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
else
status = iso_stream_schedule (ehci, urb, stream);
goto done_not_linked;
}
status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
if (unlikely(status))
goto done_not_linked;
status = iso_stream_schedule(ehci, urb, stream);
if (status == 0)
sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
else
usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
done_not_linked:
spin_unlock_irqrestore (&ehci->lock, flags);
done:

View File

@ -277,12 +277,11 @@ static void preproc_atl_queue(struct isp116x *isp116x)
processed urbs.
*/
static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
struct urb *urb)
struct urb *urb, int status)
__releases(isp116x->lock) __acquires(isp116x->lock)
{
unsigned i;
urb->hcpriv = NULL;
ep->error_count = 0;
if (usb_pipecontrol(urb->pipe))
@ -290,8 +289,9 @@ __releases(isp116x->lock) __acquires(isp116x->lock)
urb_dbg(urb, "Finish");
usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb);
spin_unlock(&isp116x->lock);
usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status);
spin_lock(&isp116x->lock);
/* take idle endpoints out of the schedule */
@ -445,12 +445,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
if (PTD_GET_ACTIVE(ptd)
|| (cc != TD_CC_NOERROR && cc < 0x0E))
break;
if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
urb->actual_length <
urb->transfer_buffer_length)
status = -EREMOTEIO;
else
status = 0;
status = 0;
ep->nextpid = 0;
break;
default:
@ -458,14 +453,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
}
done:
if (status != -EINPROGRESS) {
spin_lock(&urb->lock);
if (urb->status == -EINPROGRESS)
urb->status = status;
spin_unlock(&urb->lock);
}
if (urb->status != -EINPROGRESS)
finish_request(isp116x, ep, urb);
if (status != -EINPROGRESS || urb->unlinked)
finish_request(isp116x, ep, urb, status);
}
}
@ -673,7 +662,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load)
/*-----------------------------------------------------------------*/
static int isp116x_urb_enqueue(struct usb_hcd *hcd,
struct usb_host_endpoint *hep, struct urb *urb,
struct urb *urb,
gfp_t mem_flags)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
@ -682,6 +671,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
int is_out = !usb_pipein(pipe);
int type = usb_pipetype(pipe);
int epnum = usb_pipeendpoint(pipe);
struct usb_host_endpoint *hep = urb->ep;
struct isp116x_ep *ep = NULL;
unsigned long flags;
int i;
@ -705,7 +695,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
if (!HC_IS_RUNNING(hcd->state)) {
kfree(ep);
ret = -ENODEV;
goto fail;
goto fail_not_linked;
}
ret = usb_hcd_link_urb_to_ep(hcd, urb);
if (ret) {
kfree(ep);
goto fail_not_linked;
}
if (hep->hcpriv)
@ -808,16 +803,13 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
}
}
/* in case of unlink-during-submit */
if (urb->status != -EINPROGRESS) {
finish_request(isp116x, ep, urb);
ret = 0;
goto fail;
}
urb->hcpriv = hep;
start_atl_transfers(isp116x);
fail:
if (ret)
usb_hcd_unlink_urb_from_ep(hcd, urb);
fail_not_linked:
spin_unlock_irqrestore(&isp116x->lock, flags);
return ret;
}
@ -825,20 +817,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
/*
Dequeue URBs.
*/
static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
int status)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
struct usb_host_endpoint *hep;
struct isp116x_ep *ep, *ep_act;
unsigned long flags;
int rc;
spin_lock_irqsave(&isp116x->lock, flags);
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (rc)
goto done;
hep = urb->hcpriv;
/* URB already unlinked (or never linked)? */
if (!hep) {
spin_unlock_irqrestore(&isp116x->lock, flags);
return 0;
}
ep = hep->hcpriv;
WARN_ON(hep != ep->hep);
@ -855,10 +848,10 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
}
if (urb)
finish_request(isp116x, ep, urb);
finish_request(isp116x, ep, urb, status);
done:
spin_unlock_irqrestore(&isp116x->lock, flags);
return 0;
return rc;
}
static void isp116x_endpoint_disable(struct usb_hcd *hcd,

View File

@ -24,7 +24,7 @@
* small: 0) header + data packets 1) just header
*/
static void __maybe_unused
urb_print (struct urb * urb, char * str, int small)
urb_print(struct urb * urb, char * str, int small, int status)
{
unsigned int pipe= urb->pipe;
@ -34,7 +34,7 @@ urb_print (struct urb * urb, char * str, int small)
}
#ifndef OHCI_VERBOSE_DEBUG
if (urb->status != 0)
if (status != 0)
#endif
dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
str,
@ -46,7 +46,7 @@ urb_print (struct urb * urb, char * str, int small)
urb->transfer_flags,
urb->actual_length,
urb->transfer_buffer_length,
urb->status);
status);
#ifdef OHCI_VERBOSE_DEBUG
if (!small) {
@ -66,7 +66,7 @@ urb_print (struct urb * urb, char * str, int small)
urb->transfer_buffer_length: urb->actual_length;
for (i = 0; i < 16 && i < len; i++)
printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
printk ("%s stat:%d\n", i < len? "...": "", urb->status);
printk ("%s stat:%d\n", i < len? "...": "", status);
}
}
#endif

View File

@ -81,7 +81,6 @@ static void ohci_dump (struct ohci_hcd *ohci, int verbose);
static int ohci_init (struct ohci_hcd *ohci);
static void ohci_stop (struct usb_hcd *hcd);
static int ohci_restart (struct ohci_hcd *ohci);
static void ohci_quirk_nec_worker (struct work_struct *work);
#include "ohci-hub.c"
#include "ohci-dbg.c"
@ -118,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
*/
static int ohci_urb_enqueue (
struct usb_hcd *hcd,
struct usb_host_endpoint *ep,
struct urb *urb,
gfp_t mem_flags
) {
@ -131,11 +129,11 @@ static int ohci_urb_enqueue (
int retval = 0;
#ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "SUB", usb_pipein (pipe));
urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS);
#endif
/* every endpoint has a ed, locate and maybe (re)initialize it */
if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
return -ENOMEM;
/* for the private part of the URB we need the number of TDs (size) */
@ -200,22 +198,17 @@ static int ohci_urb_enqueue (
retval = -ENODEV;
goto fail;
}
/* in case of unlink-during-submit */
spin_lock (&urb->lock);
if (urb->status != -EINPROGRESS) {
spin_unlock (&urb->lock);
urb->hcpriv = urb_priv;
finish_urb (ohci, urb);
retval = 0;
retval = usb_hcd_link_urb_to_ep(hcd, urb);
if (retval)
goto fail;
}
/* schedule the ed if needed */
if (ed->state == ED_IDLE) {
retval = ed_schedule (ohci, ed);
if (retval < 0)
goto fail0;
if (retval < 0) {
usb_hcd_unlink_urb_from_ep(hcd, urb);
goto fail;
}
if (ed->type == PIPE_ISOCHRONOUS) {
u16 frame = ohci_frame_no(ohci);
@ -239,8 +232,6 @@ static int ohci_urb_enqueue (
urb->hcpriv = urb_priv;
td_submit_urb (ohci, urb);
fail0:
spin_unlock (&urb->lock);
fail:
if (retval)
urb_free_priv (ohci, urb_priv);
@ -249,22 +240,26 @@ fail:
}
/*
* decouple the URB from the HC queues (TDs, urb_priv); it's
* already marked using urb->status. reporting is always done
* decouple the URB from the HC queues (TDs, urb_priv).
* reporting is always done
* asynchronously, and we might be dealing with an urb that's
* partially transferred, or an ED with other urbs being unlinked.
*/
static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags;
int rc;
#ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "UNLINK", 1);
urb_print(urb, "UNLINK", 1, status);
#endif
spin_lock_irqsave (&ohci->lock, flags);
if (HC_IS_RUNNING(hcd->state)) {
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (rc) {
; /* Do nothing */
} else if (HC_IS_RUNNING(hcd->state)) {
urb_priv_t *urb_priv;
/* Unless an IRQ completed the unlink while it was being
@ -282,10 +277,10 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
* any more ... just clean up every urb's memory.
*/
if (urb->hcpriv)
finish_urb (ohci, urb);
finish_urb(ohci, urb, status);
}
spin_unlock_irqrestore (&ohci->lock, flags);
return 0;
return rc;
}
/*-------------------------------------------------------------------------*/
@ -314,6 +309,8 @@ rescan:
if (!HC_IS_RUNNING (hcd->state)) {
sanitize:
ed->state = ED_IDLE;
if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
ohci->eds_scheduled--;
finish_unlinks (ohci, 0);
}
@ -321,7 +318,12 @@ sanitize:
case ED_UNLINK: /* wait for hw to finish? */
/* major IRQ delivery trouble loses INTR_SF too... */
if (limit-- == 0) {
ohci_warn (ohci, "IRQ INTR_SF lossage\n");
ohci_warn(ohci, "ED unlink timeout\n");
if (quirk_zfmicro(ohci)) {
ohci_warn(ohci, "Attempting ZF TD recovery\n");
ohci->ed_to_check = ed;
ohci->zf_delay = 2;
}
goto sanitize;
}
spin_unlock_irqrestore (&ohci->lock, flags);
@ -379,6 +381,93 @@ ohci_shutdown (struct usb_hcd *hcd)
(void) ohci_readl (ohci, &ohci->regs->control);
}
static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
{
return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0
&& (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK)
== (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK)
&& !list_empty(&ed->td_list);
}
/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes
* an interrupt TD but neglects to add it to the donelist. On systems with
* this chipset, we need to periodically check the state of the queues to look
* for such "lost" TDs.
*/
static void unlink_watchdog_func(unsigned long _ohci)
{
long flags;
unsigned max;
unsigned seen_count = 0;
unsigned i;
struct ed **seen = NULL;
struct ohci_hcd *ohci = (struct ohci_hcd *) _ohci;
spin_lock_irqsave(&ohci->lock, flags);
max = ohci->eds_scheduled;
if (!max)
goto done;
if (ohci->ed_to_check)
goto out;
seen = kcalloc(max, sizeof *seen, GFP_ATOMIC);
if (!seen)
goto out;
for (i = 0; i < NUM_INTS; i++) {
struct ed *ed = ohci->periodic[i];
while (ed) {
unsigned temp;
/* scan this branch of the periodic schedule tree */
for (temp = 0; temp < seen_count; temp++) {
if (seen[temp] == ed) {
/* we've checked it and what's after */
ed = NULL;
break;
}
}
if (!ed)
break;
seen[seen_count++] = ed;
if (!check_ed(ohci, ed)) {
ed = ed->ed_next;
continue;
}
/* HC's TD list is empty, but HCD sees at least one
* TD that's not been sent through the donelist.
*/
ohci->ed_to_check = ed;
ohci->zf_delay = 2;
/* The HC may wait until the next frame to report the
* TD as done through the donelist and INTR_WDH. (We
* just *assume* it's not a multi-TD interrupt URB;
* those could defer the IRQ more than one frame, using
* DI...) Check again after the next INTR_SF.
*/
ohci_writel(ohci, OHCI_INTR_SF,
&ohci->regs->intrstatus);
ohci_writel(ohci, OHCI_INTR_SF,
&ohci->regs->intrenable);
/* flush those writes */
(void) ohci_readl(ohci, &ohci->regs->control);
goto out;
}
}
out:
kfree(seen);
if (ohci->eds_scheduled)
mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
done:
spin_unlock_irqrestore(&ohci->lock, flags);
}
/*-------------------------------------------------------------------------*
* HC functions
*-------------------------------------------------------------------------*/
@ -616,6 +705,15 @@ retry:
mdelay ((temp >> 23) & 0x1fe);
hcd->state = HC_STATE_RUNNING;
if (quirk_zfmicro(ohci)) {
/* Create timer to watch for bad queue state on ZF Micro */
setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func,
(unsigned long) ohci);
ohci->eds_scheduled = 0;
ohci->ed_to_check = NULL;
}
ohci_dump (ohci, 1);
return 0;
@ -629,10 +727,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct ohci_regs __iomem *regs = ohci->regs;
int ints;
int ints;
/* we can eliminate a (slow) ohci_readl()
if _only_ WDH caused this irq */
* if _only_ WDH caused this irq
*/
if ((ohci->hcca->done_head != 0)
&& ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
& 0x01)) {
@ -651,7 +750,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
if (ints & OHCI_INTR_UE) {
// e.g. due to PCI Master/Target Abort
if (ohci->flags & OHCI_QUIRK_NEC) {
if (quirk_nec(ohci)) {
/* Workaround for a silicon bug in some NEC chips used
* in Apple's PowerBooks. Adapted from Darwin code.
*/
@ -713,6 +812,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
}
if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
spin_lock(&ohci->lock);
if (ohci->ed_to_check) {
struct ed *ed = ohci->ed_to_check;
if (check_ed(ohci, ed)) {
/* HC thinks the TD list is empty; HCD knows
* at least one TD is outstanding
*/
if (--ohci->zf_delay == 0) {
struct td *td = list_entry(
ed->td_list.next,
struct td, td_list);
ohci_warn(ohci,
"Reclaiming orphan TD %p\n",
td);
takeback_td(ohci, td);
ohci->ed_to_check = NULL;
}
} else
ohci->ed_to_check = NULL;
}
spin_unlock(&ohci->lock);
}
/* could track INTR_SO to reduce available PCI/... bandwidth */
/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
@ -721,7 +845,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
spin_lock (&ohci->lock);
if (ohci->ed_rm_list)
finish_unlinks (ohci, ohci_frame_no(ohci));
if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
if ((ints & OHCI_INTR_SF) != 0
&& !ohci->ed_rm_list
&& !ohci->ed_to_check
&& HC_IS_RUNNING(hcd->state))
ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
spin_unlock (&ohci->lock);
@ -751,6 +877,9 @@ static void ohci_stop (struct usb_hcd *hcd)
free_irq(hcd->irq, hcd);
hcd->irq = -1;
if (quirk_zfmicro(ohci))
del_timer(&ohci->unlink_watchdog);
remove_debug_files (ohci);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
@ -798,9 +927,8 @@ static int ohci_restart (struct ohci_hcd *ohci)
ed, ed->state);
}
spin_lock (&urb->lock);
urb->status = -ESHUTDOWN;
spin_unlock (&urb->lock);
if (!urb->unlinked)
urb->unlinked = -ESHUTDOWN;
}
finish_unlinks (ohci, 0);
spin_unlock_irq(&ohci->lock);
@ -828,27 +956,6 @@ static int ohci_restart (struct ohci_hcd *ohci)
/*-------------------------------------------------------------------------*/
/* NEC workaround */
static void ohci_quirk_nec_worker(struct work_struct *work)
{
struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
int status;
status = ohci_init(ohci);
if (status != 0) {
ohci_err(ohci, "Restarting NEC controller failed "
"in ohci_init, %d\n", status);
return;
}
status = ohci_restart(ohci);
if (status != 0)
ohci_err(ohci, "Restarting NEC controller failed "
"in ohci_restart, %d\n", status);
}
/*-------------------------------------------------------------------------*/
#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
MODULE_AUTHOR (DRIVER_AUTHOR);
@ -926,11 +1033,17 @@ MODULE_LICENSE ("GPL");
#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver
#endif
#ifdef CONFIG_USB_OHCI_HCD_SSB
#include "ohci-ssb.c"
#define SSB_OHCI_DRIVER ssb_ohci_driver
#endif
#if !defined(PCI_DRIVER) && \
!defined(PLATFORM_DRIVER) && \
!defined(OF_PLATFORM_DRIVER) && \
!defined(SA1111_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER)
!defined(PS3_SYSTEM_BUS_DRIVER) && \
!defined(SSB_OHCI_DRIVER)
#error "missing bus glue for ohci-hcd"
#endif
@ -975,10 +1088,20 @@ static int __init ohci_hcd_mod_init(void)
goto error_pci;
#endif
#ifdef SSB_OHCI_DRIVER
retval = ssb_driver_register(&SSB_OHCI_DRIVER);
if (retval)
goto error_ssb;
#endif
return retval;
/* Error path */
#ifdef SSB_OHCI_DRIVER
error_ssb:
#endif
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
error_pci:
#endif
#ifdef SA1111_DRIVER
@ -1003,6 +1126,9 @@ module_init(ohci_hcd_mod_init);
static void __exit ohci_hcd_mod_exit(void)
{
#ifdef SSB_OHCI_DRIVER
ssb_driver_unregister(&SSB_OHCI_DRIVER);
#endif
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
#endif

View File

@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
ohci->next_statechange = jiffies;
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
}
/*-------------------------------------------------------------------------*/

View File

@ -84,7 +84,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci->flags |= OHCI_QUIRK_ZFMICRO;
ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n");
return 0;
}
@ -113,11 +113,31 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
/* Check for NEC chip and apply quirk for allegedly lost interrupts.
*/
static void ohci_quirk_nec_worker(struct work_struct *work)
{
struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
int status;
status = ohci_init(ohci);
if (status != 0) {
ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
"ohci_init", status);
return;
}
status = ohci_restart(ohci);
if (status != 0)
ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
"ohci_restart", status);
}
static int ohci_quirk_nec(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci->flags |= OHCI_QUIRK_NEC;
INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker);
ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
return 0;

View File

@ -134,8 +134,11 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
}
ohci = hcd_to_ohci(hcd);
if (is_bigendian)
if (is_bigendian) {
ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
if (of_device_is_compatible(dn, "mpc5200-ohci"))
ohci->flags |= OHCI_QUIRK_FRAME_NO;
}
ohci_hcd_init(ohci);

View File

@ -73,6 +73,11 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
ohci = hcd_to_ohci(hcd);
ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
#ifdef CONFIG_PPC_MPC52xx
/* MPC52xx doesn't need frame_no shift */
ohci->flags |= OHCI_QUIRK_FRAME_NO;
#endif
ohci_hcd_init(ohci);
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);

View File

@ -36,29 +36,15 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
* PRECONDITION: ohci lock held, irqs blocked.
*/
static void
finish_urb (struct ohci_hcd *ohci, struct urb *urb)
finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status)
__releases(ohci->lock)
__acquires(ohci->lock)
{
// ASSERT (urb->hcpriv != 0);
urb_free_priv (ohci, urb->hcpriv);
urb->hcpriv = NULL;
spin_lock (&urb->lock);
if (likely (urb->status == -EINPROGRESS))
urb->status = 0;
/* report short control reads right even though the data TD always
* has TD_R set. (much simpler, but creates the 1-td limit.)
*/
if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK)
&& unlikely (usb_pipecontrol (urb->pipe))
&& urb->actual_length < urb->transfer_buffer_length
&& usb_pipein (urb->pipe)
&& urb->status == 0) {
urb->status = -EREMOTEIO;
}
spin_unlock (&urb->lock);
if (likely(status == -EINPROGRESS))
status = 0;
switch (usb_pipetype (urb->pipe)) {
case PIPE_ISOCHRONOUS:
@ -70,12 +56,13 @@ __acquires(ohci->lock)
}
#ifdef OHCI_VERBOSE_DEBUG
urb_print (urb, "RET", usb_pipeout (urb->pipe));
urb_print(urb, "RET", usb_pipeout (urb->pipe), status);
#endif
/* urb->complete() can reenter this HCD */
usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb);
spin_unlock (&ohci->lock);
usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status);
spin_lock (&ohci->lock);
/* stop periodic dma if it's not needed */
@ -179,6 +166,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
ed->ed_prev = NULL;
ed->ed_next = NULL;
ed->hwNextED = 0;
if (quirk_zfmicro(ohci)
&& (ed->type == PIPE_INTERRUPT)
&& !(ohci->eds_scheduled++))
mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
wmb ();
/* we care about rm_list when setting CLE/BLE in case the HC was at
@ -708,19 +699,18 @@ static void td_submit_urb (
* Done List handling functions
*-------------------------------------------------------------------------*/
/* calculate transfer length/status and update the urb
* PRECONDITION: irqsafe (only for urb->status locking)
*/
static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
/* calculate transfer length/status and update the urb */
static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td)
{
u32 tdINFO = hc32_to_cpup (ohci, &td->hwINFO);
int cc = 0;
int status = -EINPROGRESS;
list_del (&td->td_list);
/* ISO ... drivers see per-TD length/status */
if (tdINFO & TD_ISO) {
u16 tdPSW = ohci_hwPSW (ohci, td, 0);
u16 tdPSW = ohci_hwPSW(ohci, td, 0);
int dlen = 0;
/* NOTE: assumes FC in tdINFO == 0, and that
@ -729,7 +719,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
cc = (tdPSW >> 12) & 0xF;
if (tdINFO & TD_CC) /* hc didn't touch? */
return;
return status;
if (usb_pipeout (urb->pipe))
dlen = urb->iso_frame_desc [td->index].length;
@ -762,12 +752,8 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
if (cc == TD_DATAUNDERRUN
&& !(urb->transfer_flags & URB_SHORT_NOT_OK))
cc = TD_CC_NOERROR;
if (cc != TD_CC_NOERROR && cc < 0x0E) {
spin_lock (&urb->lock);
if (urb->status == -EINPROGRESS)
urb->status = cc_to_error [cc];
spin_unlock (&urb->lock);
}
if (cc != TD_CC_NOERROR && cc < 0x0E)
status = cc_to_error[cc];
/* count all non-empty packets except control SETUP packet */
if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
@ -786,14 +772,15 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
urb->actual_length,
urb->transfer_buffer_length);
}
return status;
}
/*-------------------------------------------------------------------------*/
static inline struct td *
ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc)
{
struct urb *urb = td->urb;
urb_priv_t *urb_priv = urb->hcpriv;
struct ed *ed = td->ed;
struct list_head *tmp = td->td_list.next;
__hc32 toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
@ -805,13 +792,12 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
wmb ();
ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
/* put any later tds from this urb onto the donelist, after 'td',
* order won't matter here: no errors, and nothing was transferred.
* also patch the ed so it looks as if those tds completed normally.
/* Get rid of all later tds from this urb. We don't have
* to be careful: no errors and nothing was transferred.
* Also patch the ed so it looks as if those tds completed normally.
*/
while (tmp != &ed->td_list) {
struct td *next;
__hc32 info;
next = list_entry (tmp, struct td, td_list);
tmp = next->td_list.next;
@ -826,14 +812,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
* then we need to leave the control STATUS packet queued
* and clear ED_SKIP.
*/
info = next->hwINFO;
info |= cpu_to_hc32 (ohci, TD_DONE);
info &= ~cpu_to_hc32 (ohci, TD_CC);
next->hwINFO = info;
next->next_dl_td = rev;
rev = next;
list_del(&next->td_list);
urb_priv->td_cnt++;
ed->hwHeadP = next->hwNextTD | toggle;
}
@ -859,8 +840,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
hc32_to_cpu (ohci, td->hwINFO),
cc, cc_to_error [cc]);
}
return rev;
}
/* replies to the request have to be on a FIFO basis so
@ -897,7 +876,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
*/
if (cc != TD_CC_NOERROR
&& (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
td_rev = ed_halted (ohci, td, cc, td_rev);
ed_halted(ohci, td, cc);
td->next_dl_td = td_rev;
td_rev = td;
@ -940,8 +919,12 @@ skip_ed:
TD_MASK;
/* INTR_WDH may need to clean up first */
if (td->td_dma != head)
goto skip_ed;
if (td->td_dma != head) {
if (ed == ohci->ed_to_check)
ohci->ed_to_check = NULL;
else
goto skip_ed;
}
}
}
@ -974,7 +957,7 @@ rescan_this:
urb = td->urb;
urb_priv = td->urb->hcpriv;
if (urb->status == -EINPROGRESS) {
if (!urb->unlinked) {
prev = &td->hwNextTD;
continue;
}
@ -990,7 +973,7 @@ rescan_this:
/* if URB is done, clean up */
if (urb_priv->td_cnt == urb_priv->length) {
modified = completed = 1;
finish_urb (ohci, urb);
finish_urb(ohci, urb, 0);
}
}
if (completed && !list_empty (&ed->td_list))
@ -998,6 +981,8 @@ rescan_this:
/* ED's now officially unlinked, hc doesn't see */
ed->state = ED_IDLE;
if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
ohci->eds_scheduled--;
ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
ed->hwNextED = 0;
wmb ();
@ -1021,7 +1006,7 @@ rescan_this:
if (ohci->ed_controltail) {
command |= OHCI_CLF;
if (ohci->flags & OHCI_QUIRK_ZFMICRO)
if (quirk_zfmicro(ohci))
mdelay(1);
if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
control |= OHCI_CTRL_CLE;
@ -1031,7 +1016,7 @@ rescan_this:
}
if (ohci->ed_bulktail) {
command |= OHCI_BLF;
if (ohci->flags & OHCI_QUIRK_ZFMICRO)
if (quirk_zfmicro(ohci))
mdelay(1);
if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
control |= OHCI_CTRL_BLE;
@ -1043,13 +1028,13 @@ rescan_this:
/* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
if (control) {
ohci->hc_control |= control;
if (ohci->flags & OHCI_QUIRK_ZFMICRO)
if (quirk_zfmicro(ohci))
mdelay(1);
ohci_writel (ohci, ohci->hc_control,
&ohci->regs->control);
}
if (command) {
if (ohci->flags & OHCI_QUIRK_ZFMICRO)
if (quirk_zfmicro(ohci))
mdelay(1);
ohci_writel (ohci, command, &ohci->regs->cmdstatus);
}
@ -1060,12 +1045,61 @@ rescan_this:
/*-------------------------------------------------------------------------*/
/*
* Used to take back a TD from the host controller. This would normally be
* called from within dl_done_list, however it may be called directly if the
* HC no longer sees the TD and it has not appeared on the donelist (after
* two frames). This bug has been observed on ZF Micro systems.
*/
static void takeback_td(struct ohci_hcd *ohci, struct td *td)
{
struct urb *urb = td->urb;
urb_priv_t *urb_priv = urb->hcpriv;
struct ed *ed = td->ed;
int status;
/* update URB's length and status from TD */
status = td_done(ohci, urb, td);
urb_priv->td_cnt++;
/* If all this urb's TDs are done, call complete() */
if (urb_priv->td_cnt == urb_priv->length)
finish_urb(ohci, urb, status);
/* clean schedule: unlink EDs that are no longer busy */
if (list_empty(&ed->td_list)) {
if (ed->state == ED_OPER)
start_ed_unlink(ohci, ed);
/* ... reenabling halted EDs only after fault cleanup */
} else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE))
== cpu_to_hc32(ohci, ED_SKIP)) {
td = list_entry(ed->td_list.next, struct td, td_list);
if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) {
ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP);
/* ... hc may need waking-up */
switch (ed->type) {
case PIPE_CONTROL:
ohci_writel(ohci, OHCI_CLF,
&ohci->regs->cmdstatus);
break;
case PIPE_BULK:
ohci_writel(ohci, OHCI_BLF,
&ohci->regs->cmdstatus);
break;
}
}
}
}
/*
* Process normal completions (error or success) and clean the schedules.
*
* This is the main path for handing urbs back to drivers. The only other
* path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
* scanning the (re-reversed) donelist as this does.
* normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
* instead of scanning the (re-reversed) donelist as this does. There's
* an abnormal path too, handling a quirk in some Compaq silicon: URBs
* with TDs that appear to be orphaned are directly reclaimed.
*/
static void
dl_done_list (struct ohci_hcd *ohci)
@ -1074,44 +1108,7 @@ dl_done_list (struct ohci_hcd *ohci)
while (td) {
struct td *td_next = td->next_dl_td;
struct urb *urb = td->urb;
urb_priv_t *urb_priv = urb->hcpriv;
struct ed *ed = td->ed;
/* update URB's length and status from TD */
td_done (ohci, urb, td);
urb_priv->td_cnt++;
/* If all this urb's TDs are done, call complete() */
if (urb_priv->td_cnt == urb_priv->length)
finish_urb (ohci, urb);
/* clean schedule: unlink EDs that are no longer busy */
if (list_empty (&ed->td_list)) {
if (ed->state == ED_OPER)
start_ed_unlink (ohci, ed);
/* ... reenabling halted EDs only after fault cleanup */
} else if ((ed->hwINFO & cpu_to_hc32 (ohci,
ED_SKIP | ED_DEQUEUE))
== cpu_to_hc32 (ohci, ED_SKIP)) {
td = list_entry (ed->td_list.next, struct td, td_list);
if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
/* ... hc may need waking-up */
switch (ed->type) {
case PIPE_CONTROL:
ohci_writel (ohci, OHCI_CLF,
&ohci->regs->cmdstatus);
break;
case PIPE_BULK:
ohci_writel (ohci, OHCI_BLF,
&ohci->regs->cmdstatus);
break;
}
}
}
takeback_td(ohci, td);
td = td_next;
}
}

247
drivers/usb/host/ohci-ssb.c Normal file
View File

@ -0,0 +1,247 @@
/*
* Sonics Silicon Backplane
* Broadcom USB-core OHCI driver
*
* Copyright 2007 Michael Buesch <mb@bu3sch.de>
*
* Derived from the OHCI-PCI driver
* Copyright 1999 Roman Weissgaerber
* Copyright 2000-2002 David Brownell
* Copyright 1999 Linus Torvalds
* Copyright 1999 Gregory P. Smith
*
* Derived from the USBcore related parts of Broadcom-SB
* Copyright 2005 Broadcom Corporation
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include <linux/ssb/ssb.h>
#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29)
struct ssb_ohci_device {
struct ohci_hcd ohci; /* _must_ be at the beginning. */
u32 enable_flags;
};
static inline
struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
{
return (struct ssb_ohci_device *)(hcd->hcd_priv);
}
static int ssb_ohci_reset(struct usb_hcd *hcd)
{
struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
struct ohci_hcd *ohci = &ohcidev->ohci;
int err;
ohci_hcd_init(ohci);
err = ohci_init(ohci);
return err;
}
static int ssb_ohci_start(struct usb_hcd *hcd)
{
struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
struct ohci_hcd *ohci = &ohcidev->ohci;
int err;
err = ohci_run(ohci);
if (err < 0) {
ohci_err(ohci, "can't start\n");
ohci_stop(hcd);
}
return err;
}
#ifdef CONFIG_PM
static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
{
struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
struct ohci_hcd *ohci = &ohcidev->ohci;
unsigned long flags;
spin_lock_irqsave(&ohci->lock, flags);
ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */
/* make sure snapshot being resumed re-enumerates everything */
if (message.event == PM_EVENT_PRETHAW)
ohci_usb_reset(ohci);
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
spin_unlock_irqrestore(&ohci->lock, flags);
return 0;
}
static int ssb_ohci_hcd_resume(struct usb_hcd *hcd)
{
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
usb_hcd_resume_root_hub(hcd);
return 0;
}
#endif /* CONFIG_PM */
static const struct hc_driver ssb_ohci_hc_driver = {
.description = "ssb-usb-ohci",
.product_desc = "SSB OHCI Controller",
.hcd_priv_size = sizeof(struct ssb_ohci_device),
.irq = ohci_irq,
.flags = HCD_MEMORY | HCD_USB11,
.reset = ssb_ohci_reset,
.start = ssb_ohci_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
#ifdef CONFIG_PM
.suspend = ssb_ohci_hcd_suspend,
.resume = ssb_ohci_hcd_resume,
#endif
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,
.get_frame_number = ohci_get_frame,
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
.start_port_reset = ohci_start_port_reset,
};
static void ssb_ohci_detach(struct ssb_device *dev)
{
struct usb_hcd *hcd = ssb_get_drvdata(dev);
usb_remove_hcd(hcd);
iounmap(hcd->regs);
usb_put_hcd(hcd);
ssb_device_disable(dev, 0);
}
static int ssb_ohci_attach(struct ssb_device *dev)
{
struct ssb_ohci_device *ohcidev;
struct usb_hcd *hcd;
int err = -ENOMEM;
u32 tmp, flags = 0;
if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
flags |= SSB_OHCI_TMSLOW_HOSTMODE;
ssb_device_enable(dev, flags);
hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
dev->dev->bus_id);
if (!hcd)
goto err_dev_disable;
ohcidev = hcd_to_ssb_ohci(hcd);
ohcidev->enable_flags = flags;
tmp = ssb_read32(dev, SSB_ADMATCH0);
hcd->rsrc_start = ssb_admatch_base(tmp);
hcd->rsrc_len = ssb_admatch_size(tmp);
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs)
goto err_put_hcd;
err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
if (err)
goto err_iounmap;
ssb_set_drvdata(dev, hcd);
return err;
err_iounmap:
iounmap(hcd->regs);
err_put_hcd:
usb_put_hcd(hcd);
err_dev_disable:
ssb_device_disable(dev, flags);
return err;
}
static int ssb_ohci_probe(struct ssb_device *dev,
const struct ssb_device_id *id)
{
int err;
u16 chipid_top;
/* USBcores are only connected on embedded devices. */
chipid_top = (dev->bus->chip_id & 0xFF00);
if (chipid_top != 0x4700 && chipid_top != 0x5300)
return -ENODEV;
/* TODO: Probably need checks here; is the core connected? */
if (usb_disabled())
return -ENODEV;
/* We currently always attach SSB_DEV_USB11_HOSTDEV
* as HOST OHCI. If we want to attach it as Client device,
* we must branch here and call into the (yet to
* be written) Client mode driver. Same for remove(). */
err = ssb_ohci_attach(dev);
return err;
}
static void ssb_ohci_remove(struct ssb_device *dev)
{
ssb_ohci_detach(dev);
}
#ifdef CONFIG_PM
static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
{
ssb_device_disable(dev, 0);
return 0;
}
static int ssb_ohci_resume(struct ssb_device *dev)
{
struct usb_hcd *hcd = ssb_get_drvdata(dev);
struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
ssb_device_enable(dev, ohcidev->enable_flags);
return 0;
}
#else /* !CONFIG_PM */
#define ssb_ohci_suspend NULL
#define ssb_ohci_resume NULL
#endif /* CONFIG_PM */
static const struct ssb_device_id ssb_ohci_table[] = {
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
SSB_DEVTABLE_END
};
MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
static struct ssb_driver ssb_ohci_driver = {
.name = KBUILD_MODNAME,
.id_table = ssb_ohci_table,
.probe = ssb_ohci_probe,
.remove = ssb_ohci_remove,
.suspend = ssb_ohci_suspend,
.resume = ssb_ohci_resume,
};

View File

@ -398,11 +398,38 @@ struct ohci_hcd {
#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */
#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/
#define OHCI_QUIRK_NEC 0x40 /* lost interrupts */
#define OHCI_QUIRK_FRAME_NO 0x80 /* no big endian frame_no shift */
// there are also chip quirks/bugs in init logic
struct work_struct nec_work; /* Worker for NEC quirk */
/* Needed for ZF Micro quirk */
struct timer_list unlink_watchdog;
unsigned eds_scheduled;
struct ed *ed_to_check;
unsigned zf_delay;
};
#ifdef CONFIG_PCI
static inline int quirk_nec(struct ohci_hcd *ohci)
{
return ohci->flags & OHCI_QUIRK_NEC;
}
static inline int quirk_zfmicro(struct ohci_hcd *ohci)
{
return ohci->flags & OHCI_QUIRK_ZFMICRO;
}
#else
static inline int quirk_nec(struct ohci_hcd *ohci)
{
return 0;
}
static inline int quirk_zfmicro(struct ohci_hcd *ohci)
{
return 0;
}
#endif
/* convert between an hcd pointer and the corresponding ohci_hcd */
static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd)
{
@ -607,15 +634,12 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
* hardware handles 16 bit reads. That creates a different confusion on
* some big-endian SOC implementations. Same thing happens with PSW access.
*
* FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
* to arch/powerpc
*/
#ifdef CONFIG_STB03xxx
#define OHCI_BE_FRAME_NO_SHIFT 16
#ifdef CONFIG_PPC_MPC52xx
#define big_endian_frame_no_quirk(ohci) (ohci->flags & OHCI_QUIRK_FRAME_NO)
#else
#define OHCI_BE_FRAME_NO_SHIFT 0
#define big_endian_frame_no_quirk(ohci) 0
#endif
static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
@ -623,7 +647,8 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
u32 tmp;
if (big_endian_desc(ohci)) {
tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
tmp >>= OHCI_BE_FRAME_NO_SHIFT;
if (!big_endian_frame_no_quirk(ohci))
tmp >>= 16;
} else
tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);

View File

@ -782,10 +782,12 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
kfree(td);
if (urb) {
urb->status = -ENODEV;
urb->hcpriv = NULL;
usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
urb);
spin_unlock(&r8a66597->lock);
usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb);
usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb,
-ENODEV);
spin_lock(&r8a66597->lock);
}
break;
@ -832,7 +834,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
info.pipenum = get_empty_pipenum(r8a66597, ep);
info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
info.maxpacket = ep->wMaxPacketSize;
info.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
info.type = get_r8a66597_type(ep->bmAttributes
& USB_ENDPOINT_XFERTYPE_MASK);
info.bufnum = get_bufnum(info.pipenum);
@ -923,7 +925,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597,
r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
for (i = 0; i < 4; i++) {
r8a66597_write(r8a66597, p[i], setup_addr);
r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr);
setup_addr += 2;
}
r8a66597_write(r8a66597, SUREQ, DCPCTR);
@ -1032,6 +1034,15 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
pipe_start(r8a66597, td->pipe);
}
static int is_set_address(unsigned char *setup_packet)
{
if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) &&
setup_packet[1] == USB_REQ_SET_ADDRESS)
return 1;
else
return 0;
}
/* this function must be called with interrupt disabled */
static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
{
@ -1039,7 +1050,7 @@ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
switch (td->type) {
case USB_PID_SETUP:
if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) {
if (is_set_address(td->urb->setup_packet)) {
td->set_address = 1;
td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
td->urb);
@ -1106,8 +1117,9 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
}
/* this function must be called with interrupt disabled */
static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
u16 pipenum, struct urb *urb)
static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
u16 pipenum, struct urb *urb, int status)
__releases(r8a66597->lock) __acquires(r8a66597->lock)
{
int restart = 0;
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
@ -1115,7 +1127,7 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
r8a66597->timeout_map &= ~(1 << pipenum);
if (likely(td)) {
if (td->set_address && urb->status != 0)
if (td->set_address && (status != 0 || urb->unlinked))
r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
pipe_toggle_save(r8a66597, td->pipe, urb);
@ -1130,9 +1142,9 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
if (usb_pipeisoc(urb->pipe))
urb->start_frame = r8a66597_get_frame(hcd);
urb->hcpriv = NULL;
usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
spin_unlock(&r8a66597->lock);
usb_hcd_giveback_urb(hcd, urb);
usb_hcd_giveback_urb(hcd, urb, status);
spin_lock(&r8a66597->lock);
}
@ -1146,14 +1158,6 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
}
}
/* this function must be called with interrupt disabled */
static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
u16 pipenum, struct urb *urb)
__releases(r8a66597->lock) __acquires(r8a66597->lock)
{
done(r8a66597, td, pipenum, urb);
}
static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
{
u16 tmp;
@ -1162,6 +1166,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
struct urb *urb;
int finish = 0;
int status = 0;
if (unlikely(!td))
return;
@ -1170,17 +1175,15 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
fifo_change_from_pipe(r8a66597, td->pipe);
tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
if (unlikely((tmp & FRDY) == 0)) {
urb->status = -EPIPE;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
err("in fifo not ready (%d)", pipenum);
finish_request(r8a66597, td, pipenum, td->urb);
finish_request(r8a66597, td, pipenum, td->urb, -EPIPE);
return;
}
/* prepare parameters */
rcv_len = tmp & DTLN;
bufsize = td->maxpacket;
if (usb_pipeisoc(urb->pipe)) {
buf = (u16 *)(urb->transfer_buffer +
urb->iso_frame_desc[td->iso_cnt].offset);
@ -1189,29 +1192,31 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
buf = (void *)urb->transfer_buffer + urb->actual_length;
urb_len = urb->transfer_buffer_length - urb->actual_length;
}
if (rcv_len < bufsize)
size = min(rcv_len, urb_len);
else
size = min(bufsize, urb_len);
bufsize = min(urb_len, (int) td->maxpacket);
if (rcv_len <= bufsize) {
size = rcv_len;
} else {
size = bufsize;
status = -EOVERFLOW;
finish = 1;
}
/* update parameters */
urb->actual_length += size;
if (rcv_len == 0)
td->zero_packet = 1;
if ((size % td->maxpacket) > 0) {
if (rcv_len < bufsize) {
td->short_packet = 1;
if (urb->transfer_buffer_length != urb->actual_length &&
urb->transfer_flags & URB_SHORT_NOT_OK)
td->urb->status = -EREMOTEIO;
}
if (usb_pipeisoc(urb->pipe)) {
urb->iso_frame_desc[td->iso_cnt].actual_length = size;
urb->iso_frame_desc[td->iso_cnt].status = 0;
urb->iso_frame_desc[td->iso_cnt].status = status;
td->iso_cnt++;
finish = 0;
}
/* check transfer finish */
if (check_transfer_finish(td, urb)) {
if (finish || check_transfer_finish(td, urb)) {
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
finish = 1;
@ -1226,11 +1231,8 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
buf, size);
}
if (finish && pipenum != 0) {
if (td->urb->status == -EINPROGRESS)
td->urb->status = 0;
finish_request(r8a66597, td, pipenum, urb);
}
if (finish && pipenum != 0)
finish_request(r8a66597, td, pipenum, urb, status);
}
static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
@ -1248,11 +1250,10 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
fifo_change_from_pipe(r8a66597, td->pipe);
tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
if (unlikely((tmp & FRDY) == 0)) {
urb->status = -EPIPE;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, pipenum);
err("out write fifo not ready. (%d)", pipenum);
finish_request(r8a66597, td, pipenum, td->urb);
finish_request(r8a66597, td, pipenum, urb, -EPIPE);
return;
}
@ -1297,7 +1298,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
}
static void check_next_phase(struct r8a66597 *r8a66597)
static void check_next_phase(struct r8a66597 *r8a66597, int status)
{
struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
struct urb *urb;
@ -1310,49 +1311,41 @@ static void check_next_phase(struct r8a66597 *r8a66597)
switch (td->type) {
case USB_PID_IN:
case USB_PID_OUT:
if (urb->status != -EINPROGRESS) {
finish = 1;
break;
}
if (check_transfer_finish(td, urb))
td->type = USB_PID_ACK;
break;
case USB_PID_SETUP:
if (urb->status != -EINPROGRESS)
finish = 1;
else if (urb->transfer_buffer_length == urb->actual_length) {
if (urb->transfer_buffer_length == urb->actual_length)
td->type = USB_PID_ACK;
urb->status = 0;
} else if (usb_pipeout(urb->pipe))
else if (usb_pipeout(urb->pipe))
td->type = USB_PID_OUT;
else
td->type = USB_PID_IN;
break;
case USB_PID_ACK:
finish = 1;
if (urb->status == -EINPROGRESS)
urb->status = 0;
break;
}
if (finish)
finish_request(r8a66597, td, 0, urb);
if (finish || status != 0 || urb->unlinked)
finish_request(r8a66597, td, 0, urb, status);
else
start_transfer(r8a66597, td);
}
static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
{
struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
if (td && td->urb) {
if (td) {
u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
if (pid == PID_NAK)
td->urb->status = -ECONNRESET;
return -ECONNRESET;
else
td->urb->status = -EPIPE;
return -EPIPE;
}
return 0;
}
static void irq_pipe_ready(struct r8a66597 *r8a66597)
@ -1371,7 +1364,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597)
packet_read(r8a66597, 0);
else
pipe_irq_disable(r8a66597, 0);
check_next_phase(r8a66597);
check_next_phase(r8a66597, 0);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@ -1405,7 +1398,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
td = r8a66597_get_td(r8a66597, 0);
if (td && td->type != USB_PID_OUT)
disable_irq_empty(r8a66597, 0);
check_next_phase(r8a66597);
check_next_phase(r8a66597, 0);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@ -1420,9 +1413,8 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
if ((tmp & INBUFM) == 0) {
disable_irq_empty(r8a66597, pipenum);
pipe_irq_disable(r8a66597, pipenum);
if (td->urb->status == -EINPROGRESS)
td->urb->status = 0;
finish_request(r8a66597, td, pipenum, td->urb);
finish_request(r8a66597, td, pipenum, td->urb,
0);
}
}
}
@ -1433,15 +1425,16 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
u16 check;
u16 pipenum;
u16 mask;
int status;
mask = r8a66597_read(r8a66597, NRDYSTS)
& r8a66597_read(r8a66597, NRDYENB);
r8a66597_write(r8a66597, ~mask, NRDYSTS);
if (mask & NRDY0) {
cfifo_change(r8a66597, 0);
set_urb_error(r8a66597, 0);
status = get_urb_error(r8a66597, 0);
pipe_irq_disable(r8a66597, 0);
check_next_phase(r8a66597);
check_next_phase(r8a66597, status);
}
for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@ -1452,10 +1445,10 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
if (unlikely(!td))
continue;
set_urb_error(r8a66597, pipenum);
status = get_urb_error(r8a66597, pipenum);
pipe_irq_disable(r8a66597, pipenum);
pipe_stop(r8a66597, td->pipe);
finish_request(r8a66597, td, pipenum, td->urb);
finish_request(r8a66597, td, pipenum, td->urb, status);
}
}
}
@ -1475,6 +1468,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
u16 intsts0, intsts1, intsts2;
u16 intenb0, intenb1, intenb2;
u16 mask0, mask1, mask2;
int status;
spin_lock(&r8a66597->lock);
@ -1518,12 +1512,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
}
if (mask1 & SIGN) {
r8a66597_write(r8a66597, ~SIGN, INTSTS1);
set_urb_error(r8a66597, 0);
check_next_phase(r8a66597);
status = get_urb_error(r8a66597, 0);
check_next_phase(r8a66597, status);
}
if (mask1 & SACK) {
r8a66597_write(r8a66597, ~SACK, INTSTS1);
check_next_phase(r8a66597);
check_next_phase(r8a66597, 0);
}
}
if (mask0) {
@ -1722,21 +1716,25 @@ static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
}
static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
struct usb_host_endpoint *hep,
struct urb *urb,
gfp_t mem_flags)
{
struct usb_host_endpoint *hep = urb->ep;
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
struct r8a66597_td *td = NULL;
int ret = 0, request = 0;
int ret, request = 0;
unsigned long flags;
spin_lock_irqsave(&r8a66597->lock, flags);
if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
ret = -ENODEV;
goto error;
goto error_not_linked;
}
ret = usb_hcd_link_urb_to_ep(hcd, urb);
if (ret)
goto error_not_linked;
if (!hep->hcpriv) {
hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
GFP_ATOMIC);
@ -1761,15 +1759,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
request = 1;
list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
spin_lock(&urb->lock);
if (urb->status != -EINPROGRESS) {
spin_unlock(&urb->lock);
ret = -EPIPE;
goto error;
}
urb->hcpriv = td;
spin_unlock(&urb->lock);
if (request) {
ret = start_transfer(r8a66597, td);
@ -1781,26 +1771,36 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
set_td_timer(r8a66597, td);
error:
if (ret)
usb_hcd_unlink_urb_from_ep(hcd, urb);
error_not_linked:
spin_unlock_irqrestore(&r8a66597->lock, flags);
return ret;
}
static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
int status)
{
struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
struct r8a66597_td *td;
unsigned long flags;
int rc;
spin_lock_irqsave(&r8a66597->lock, flags);
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (rc)
goto done;
if (urb->hcpriv) {
td = urb->hcpriv;
pipe_stop(r8a66597, td->pipe);
pipe_irq_disable(r8a66597, td->pipenum);
disable_irq_empty(r8a66597, td->pipenum);
done(r8a66597, td, td->pipenum, urb);
finish_request(r8a66597, td, td->pipenum, urb, status);
}
done:
spin_unlock_irqrestore(&r8a66597->lock, flags);
return 0;
return rc;
}
static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
@ -1830,7 +1830,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
td = r8a66597_get_td(r8a66597, pipenum);
if (td)
urb = td->urb;
done(r8a66597, td, pipenum, urb);
finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN);
kfree(hep->hcpriv);
hep->hcpriv = NULL;
spin_unlock_irqrestore(&r8a66597->lock, flags);
@ -2027,7 +2027,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case GetPortStatus:
if (wIndex > R8A66597_MAX_ROOT_HUB)
goto error;
*(u32 *)buf = rh->port;
*(u32 *)buf = cpu_to_le32(rh->port);
break;
case SetPortFeature:
if (wIndex > R8A66597_MAX_ROOT_HUB)
@ -2126,8 +2126,8 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
del_timer_sync(&r8a66597->rh_timer);
iounmap((void *)r8a66597->reg);
usb_remove_hcd(hcd);
iounmap((void *)r8a66597->reg);
usb_put_hcd(hcd);
return 0;
}

View File

@ -435,14 +435,9 @@ static void finish_request(
if (usb_pipecontrol(urb->pipe))
ep->nextpid = USB_PID_SETUP;
spin_lock(&urb->lock);
if (urb->status == -EINPROGRESS)
urb->status = status;
urb->hcpriv = NULL;
spin_unlock(&urb->lock);
usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb);
spin_unlock(&sl811->lock);
usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb);
usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status);
spin_lock(&sl811->lock);
/* leave active endpoints in the schedule */
@ -538,35 +533,21 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
bank + SL11H_XFERCNTREG);
if (len > ep->length) {
len = ep->length;
urb->status = -EOVERFLOW;
urbstat = -EOVERFLOW;
}
urb->actual_length += len;
sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0),
buf, len);
usb_dotoggle(udev, ep->epnum, 0);
if (urb->actual_length == urb->transfer_buffer_length)
urbstat = 0;
else if (len < ep->maxpacket) {
if (urb->transfer_flags & URB_SHORT_NOT_OK)
urbstat = -EREMOTEIO;
if (urbstat == -EINPROGRESS &&
(len < ep->maxpacket ||
urb->actual_length ==
urb->transfer_buffer_length)) {
if (usb_pipecontrol(urb->pipe))
ep->nextpid = USB_PID_ACK;
else
urbstat = 0;
}
if (usb_pipecontrol(urb->pipe)
&& (urbstat == -EREMOTEIO
|| urbstat == 0)) {
/* NOTE if the status stage STALLs (why?),
* this reports the wrong urb status.
*/
spin_lock(&urb->lock);
if (urb->status == -EINPROGRESS)
urb->status = urbstat;
spin_unlock(&urb->lock);
urb = NULL;
ep->nextpid = USB_PID_ACK;
}
break;
case USB_PID_SETUP:
// PACKET("...ACK/setup_%02x qh%p\n", bank, ep);
@ -605,7 +586,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
bank, status, ep, urbstat);
}
if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS))
if (urbstat != -EINPROGRESS || urb->unlinked)
finish_request(sl811, ep, urb, urbstat);
}
@ -807,7 +788,6 @@ static int balance(struct sl811 *sl811, u16 period, u16 load)
static int sl811h_urb_enqueue(
struct usb_hcd *hcd,
struct usb_host_endpoint *hep,
struct urb *urb,
gfp_t mem_flags
) {
@ -820,7 +800,8 @@ static int sl811h_urb_enqueue(
struct sl811h_ep *ep = NULL;
unsigned long flags;
int i;
int retval = 0;
int retval;
struct usb_host_endpoint *hep = urb->ep;
#ifdef DISABLE_ISO
if (type == PIPE_ISOCHRONOUS)
@ -838,7 +819,12 @@ static int sl811h_urb_enqueue(
|| !HC_IS_RUNNING(hcd->state)) {
retval = -ENODEV;
kfree(ep);
goto fail;
goto fail_not_linked;
}
retval = usb_hcd_link_urb_to_ep(hcd, urb);
if (retval) {
kfree(ep);
goto fail_not_linked;
}
if (hep->hcpriv) {
@ -951,37 +937,31 @@ static int sl811h_urb_enqueue(
sofirq_on(sl811);
}
/* in case of unlink-during-submit */
spin_lock(&urb->lock);
if (urb->status != -EINPROGRESS) {
spin_unlock(&urb->lock);
finish_request(sl811, ep, urb, 0);
retval = 0;
goto fail;
}
urb->hcpriv = hep;
spin_unlock(&urb->lock);
start_transfer(sl811);
sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
fail:
if (retval)
usb_hcd_unlink_urb_from_ep(hcd, urb);
fail_not_linked:
spin_unlock_irqrestore(&sl811->lock, flags);
return retval;
}
static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct sl811 *sl811 = hcd_to_sl811(hcd);
struct usb_host_endpoint *hep;
unsigned long flags;
struct sl811h_ep *ep;
int retval = 0;
int retval;
spin_lock_irqsave(&sl811->lock, flags);
hep = urb->hcpriv;
if (!hep)
retval = usb_hcd_check_unlink_urb(hcd, urb, status);
if (retval)
goto fail;
hep = urb->hcpriv;
ep = hep->hcpriv;
if (ep) {
/* finish right away if this urb can't be active ...
@ -1029,8 +1009,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
(sl811->active_a == ep) ? "A" : "B");
} else
fail:
retval = -EINVAL;
fail:
spin_unlock_irqrestore(&sl811->lock, flags);
return retval;
}

View File

@ -51,7 +51,6 @@
#include <linux/usb.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/pci_ids.h>
#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/irq.h>
@ -184,7 +183,7 @@ struct u132_ring {
struct u132 {
struct kref kref;
struct list_head u132_list;
struct semaphore sw_lock;
struct mutex sw_lock;
struct semaphore scheduler_lock;
struct u132_platform_data *board;
struct platform_device *platform_dev;
@ -493,20 +492,20 @@ static void u132_hcd_monitor_work(struct work_struct *work)
return;
} else {
int retval;
down(&u132->sw_lock);
mutex_lock(&u132->sw_lock);
retval = read_roothub_info(u132);
if (retval) {
struct usb_hcd *hcd = u132_to_hcd(u132);
u132_disable(u132);
u132->going = 1;
up(&u132->sw_lock);
mutex_unlock(&u132->sw_lock);
usb_hc_died(hcd);
ftdi_elan_gone_away(u132->platform_dev);
u132_monitor_put_kref(u132);
return;
} else {
u132_monitor_requeue_work(u132, 500);
up(&u132->sw_lock);
mutex_unlock(&u132->sw_lock);
return;
}
}
@ -519,9 +518,8 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
unsigned long irqs;
struct usb_hcd *hcd = u132_to_hcd(u132);
urb->error_count = 0;
urb->status = status;
urb->hcpriv = NULL;
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
usb_hcd_unlink_urb_from_ep(hcd, urb);
endp->queue_next += 1;
if (ENDP_QUEUE_SIZE > --endp->queue_size) {
endp->active = 0;
@ -543,7 +541,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
u132_ring_queue_work(u132, ring, 0);
up(&u132->scheduler_lock);
u132_endp_put_kref(u132, endp);
usb_hcd_giveback_urb(hcd, urb);
usb_hcd_giveback_urb(hcd, urb, status);
return;
}
@ -559,9 +557,8 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
unsigned long irqs;
struct usb_hcd *hcd = u132_to_hcd(u132);
urb->error_count = 0;
urb->status = status;
urb->hcpriv = NULL;
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
usb_hcd_unlink_urb_from_ep(hcd, urb);
endp->queue_next += 1;
if (ENDP_QUEUE_SIZE > --endp->queue_size) {
endp->active = 0;
@ -576,7 +573,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
endp->active = 0;
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
kfree(urbq);
} usb_hcd_giveback_urb(hcd, urb);
} usb_hcd_giveback_urb(hcd, urb, status);
return;
}
@ -646,12 +643,12 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed urb="
"%p status=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
} else if (urb->status == -EINPROGRESS) {
} else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer + urb->actual_length;
u8 *b = buf;
@ -717,10 +714,10 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
"s=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, urb->status);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@ -745,12 +742,12 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed urb="
"%p status=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
} else if (urb->status == -EINPROGRESS) {
} else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
urb->actual_length += len;
endp->toggle_bits = toggle_bits;
@ -769,10 +766,10 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
"s=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, urb->status);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@ -798,12 +795,12 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed urb="
"%p status=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
} else if (urb->status == -EINPROGRESS) {
} else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer + urb->actual_length;
u8 *b = buf;
@ -872,10 +869,10 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
"s=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, urb->status);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@ -899,20 +896,20 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed urb="
"%p status=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
} else if (urb->status == -EINPROGRESS) {
} else if (!urb->unlinked) {
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
"s=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, urb->status);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@ -937,12 +934,12 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed urb="
"%p status=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
} else if (urb->status == -EINPROGRESS) {
} else if (!urb->unlinked) {
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer;
u8 *b = buf;
@ -981,10 +978,10 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
"s=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, urb->status);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@ -1008,20 +1005,20 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed urb="
"%p status=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
} else if (urb->status == -EINPROGRESS) {
} else if (!urb->unlinked) {
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
"s=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, urb->status);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@ -1046,12 +1043,12 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed urb="
"%p status=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
} else if (urb->status == -EINPROGRESS) {
} else if (!urb->unlinked) {
if (usb_pipein(urb->pipe)) {
int retval;
struct u132_ring *ring = endp->ring;
@ -1078,10 +1075,10 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
return;
}
} else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
"s=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, urb->status);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@ -1107,22 +1104,22 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed urb="
"%p status=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
} else if (urb->status == -EINPROGRESS) {
} else if (!urb->unlinked) {
u132->addr[0].address = 0;
endp->usb_addr = udev->usb_addr;
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
"s=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, urb->status);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@ -1146,12 +1143,12 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed urb="
"%p status=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
} else if (urb->status == -EINPROGRESS) {
} else if (!urb->unlinked) {
int retval;
struct u132_ring *ring = endp->ring;
up(&u132->scheduler_lock);
@ -1163,10 +1160,10 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
u132_hcd_giveback_urb(u132, endp, urb, retval);
return;
} else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
"s=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, urb->status);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@ -1190,20 +1187,20 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed urb="
"%p status=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
} else if (urb->status == -EINPROGRESS) {
} else if (!urb->unlinked) {
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
} else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
"s=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, urb->status);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@ -1228,12 +1225,12 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed urb="
"%p status=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
} else if (urb->status == -EINPROGRESS) {
} else if (!urb->unlinked) {
int retval;
struct u132_ring *ring = endp->ring;
u8 *u = urb->transfer_buffer;
@ -1252,10 +1249,10 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, retval);
return;
} else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
"s=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, urb->status);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@ -1280,12 +1277,12 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
return;
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed urb="
"%p status=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
return;
} else if (urb->status == -EINPROGRESS) {
} else if (!urb->unlinked) {
int retval;
struct u132_ring *ring = endp->ring;
up(&u132->scheduler_lock);
@ -1297,10 +1294,10 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
u132_hcd_giveback_urb(u132, endp, urb, retval);
return;
} else {
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
"s=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
"unlinked=%d\n", urb, urb->unlinked);
up(&u132->scheduler_lock);
u132_hcd_giveback_urb(u132, endp, urb, urb->status);
u132_hcd_giveback_urb(u132, endp, urb, 0);
return;
}
}
@ -1805,10 +1802,10 @@ static void u132_hcd_stop(struct usb_hcd *hcd)
dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
"ed\n", hcd);
} else {
down(&u132->sw_lock);
mutex_lock(&u132->sw_lock);
msleep(100);
u132_power(u132, 0);
up(&u132->sw_lock);
mutex_unlock(&u132->sw_lock);
}
}
@ -1830,7 +1827,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
(pdev->dev.platform_data))->vendor;
u16 device = ((struct u132_platform_data *)
(pdev->dev.platform_data))->device;
down(&u132->sw_lock);
mutex_lock(&u132->sw_lock);
msleep(10);
if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
u132->flags = OHCI_QUIRK_AMD756;
@ -1845,7 +1842,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
u132->going = 1;
}
msleep(100);
up(&u132->sw_lock);
mutex_unlock(&u132->sw_lock);
return retval;
} else {
dev_err(&u132->platform_dev->dev, "platform_device missing\n");
@ -1865,32 +1862,44 @@ static int u132_hcd_reset(struct usb_hcd *hcd)
return -ESHUTDOWN;
} else {
int retval;
down(&u132->sw_lock);
mutex_lock(&u132->sw_lock);
retval = u132_init(u132);
if (retval) {
u132_disable(u132);
u132->going = 1;
}
up(&u132->sw_lock);
mutex_unlock(&u132->sw_lock);
return retval;
}
}
static int create_endpoint_and_queue_int(struct u132 *u132,
struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
struct u132_udev *udev, struct urb *urb,
struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
gfp_t mem_flags)
{
struct u132_ring *ring;
unsigned long irqs;
u8 endp_number = ++u132->num_endpoints;
struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
kmalloc(sizeof(struct u132_endp), mem_flags);
int rc;
u8 endp_number;
struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
if (!endp) {
return -ENOMEM;
}
spin_lock_init(&endp->queue_lock.slock);
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
if (rc) {
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
kfree(endp);
return rc;
}
endp_number = ++u132->num_endpoints;
urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
spin_lock_init(&endp->queue_lock.slock);
INIT_LIST_HEAD(&endp->urb_more);
ring = endp->ring = &u132->ring[0];
if (ring->curr_endp) {
@ -1906,7 +1915,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
endp->delayed = 0;
endp->endp_number = endp_number;
endp->u132 = u132;
endp->hep = hep;
endp->hep = urb->ep;
endp->pipetype = usb_pipetype(urb->pipe);
u132_endp_init_kref(u132, endp);
if (usb_pipein(urb->pipe)) {
@ -1925,7 +1934,6 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
u132_udev_get_kref(u132, udev);
}
urb->hcpriv = u132;
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->delayed = 1;
endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
endp->udev_number = address;
@ -1940,8 +1948,8 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
return 0;
}
static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
struct usb_host_endpoint *hep, struct urb *urb,
static int queue_int_on_old_endpoint(struct u132 *u132,
struct u132_udev *udev, struct urb *urb,
struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
u8 usb_endp, u8 address)
{
@ -1965,21 +1973,33 @@ static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
}
static int create_endpoint_and_queue_bulk(struct u132 *u132,
struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
struct u132_udev *udev, struct urb *urb,
struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
gfp_t mem_flags)
{
int ring_number;
struct u132_ring *ring;
unsigned long irqs;
u8 endp_number = ++u132->num_endpoints;
struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
kmalloc(sizeof(struct u132_endp), mem_flags);
int rc;
u8 endp_number;
struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
if (!endp) {
return -ENOMEM;
}
spin_lock_init(&endp->queue_lock.slock);
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
if (rc) {
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
kfree(endp);
return rc;
}
endp_number = ++u132->num_endpoints;
urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
spin_lock_init(&endp->queue_lock.slock);
INIT_LIST_HEAD(&endp->urb_more);
endp->dequeueing = 0;
endp->edset_flush = 0;
@ -1987,7 +2007,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
endp->delayed = 0;
endp->endp_number = endp_number;
endp->u132 = u132;
endp->hep = hep;
endp->hep = urb->ep;
endp->pipetype = usb_pipetype(urb->pipe);
u132_endp_init_kref(u132, endp);
if (usb_pipein(urb->pipe)) {
@ -2016,7 +2036,6 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
}
ring->length += 1;
urb->hcpriv = u132;
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->udev_number = address;
endp->usb_addr = usb_addr;
endp->usb_endp = usb_endp;
@ -2030,7 +2049,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
}
static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
struct usb_host_endpoint *hep, struct urb *urb,
struct urb *urb,
struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
u8 usb_endp, u8 address)
{
@ -2052,19 +2071,32 @@ static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
}
static int create_endpoint_and_queue_control(struct u132 *u132,
struct usb_host_endpoint *hep, struct urb *urb,
struct urb *urb,
struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
gfp_t mem_flags)
{
struct u132_ring *ring;
u8 endp_number = ++u132->num_endpoints;
struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
kmalloc(sizeof(struct u132_endp), mem_flags);
unsigned long irqs;
int rc;
u8 endp_number;
struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
if (!endp) {
return -ENOMEM;
}
spin_lock_init(&endp->queue_lock.slock);
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
if (rc) {
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
kfree(endp);
return rc;
}
endp_number = ++u132->num_endpoints;
urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
spin_lock_init(&endp->queue_lock.slock);
INIT_LIST_HEAD(&endp->urb_more);
ring = endp->ring = &u132->ring[0];
if (ring->curr_endp) {
@ -2080,11 +2112,10 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
endp->delayed = 0;
endp->endp_number = endp_number;
endp->u132 = u132;
endp->hep = hep;
endp->hep = urb->ep;
u132_endp_init_kref(u132, endp);
u132_endp_get_kref(u132, endp);
if (usb_addr == 0) {
unsigned long irqs;
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
endp->udev_number = address;
@ -2098,7 +2129,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
udev->endp_number_in[usb_endp] = endp_number;
udev->endp_number_out[usb_endp] = endp_number;
urb->hcpriv = u132;
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->queue_size = 1;
endp->queue_last = 0;
endp->queue_next = 0;
@ -2107,7 +2137,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
u132_endp_queue_work(u132, endp, 0);
return 0;
} else { /*(usb_addr > 0) */
unsigned long irqs;
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
endp->udev_number = address;
@ -2121,7 +2150,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
udev->endp_number_in[usb_endp] = endp_number;
udev->endp_number_out[usb_endp] = endp_number;
urb->hcpriv = u132;
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
endp->queue_size = 1;
endp->queue_last = 0;
endp->queue_next = 0;
@ -2133,7 +2161,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
}
static int queue_control_on_old_endpoint(struct u132 *u132,
struct usb_host_endpoint *hep, struct urb *urb,
struct urb *urb,
struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
u8 usb_endp)
{
@ -2233,8 +2261,8 @@ static int queue_control_on_old_endpoint(struct u132 *u132,
}
}
static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
struct urb *urb, gfp_t mem_flags)
static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
gfp_t mem_flags)
{
struct u132 *u132 = hcd_to_u132(hcd);
if (irqs_disabled()) {
@ -2249,8 +2277,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
, u132->going);
return -ENODEV;
} else if (u132->going > 0) {
dev_err(&u132->platform_dev->dev, "device is being removed urb="
"%p status=%d\n", urb, urb->status);
dev_err(&u132->platform_dev->dev, "device is being removed "
"urb=%p\n", urb);
return -ESHUTDOWN;
} else {
u8 usb_addr = usb_pipedevice(urb->pipe);
@ -2259,16 +2287,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
struct u132_endp *endp = hep->hcpriv;
struct u132_endp *endp = urb->ep->hcpriv;
urb->actual_length = 0;
if (endp) {
unsigned long irqs;
int retval;
spin_lock_irqsave(&endp->queue_lock.slock,
irqs);
retval = queue_int_on_old_endpoint(u132, udev,
hep, urb, usb_dev, endp, usb_addr,
usb_endp, address);
retval = usb_hcd_link_urb_to_ep(hcd, urb);
if (retval == 0) {
retval = queue_int_on_old_endpoint(
u132, udev, urb,
usb_dev, endp,
usb_addr, usb_endp,
address);
if (retval)
usb_hcd_unlink_urb_from_ep(
hcd, urb);
}
spin_unlock_irqrestore(&endp->queue_lock.slock,
irqs);
if (retval) {
@ -2283,8 +2319,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
return -EINVAL;
} else { /*(endp == NULL) */
return create_endpoint_and_queue_int(u132, udev,
hep, urb, usb_dev, usb_addr, usb_endp,
address, mem_flags);
urb, usb_dev, usb_addr,
usb_endp, address, mem_flags);
}
} else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
dev_err(&u132->platform_dev->dev, "the hardware does no"
@ -2293,16 +2329,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
} else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
u8 address = u132->addr[usb_addr].address;
struct u132_udev *udev = &u132->udev[address];
struct u132_endp *endp = hep->hcpriv;
struct u132_endp *endp = urb->ep->hcpriv;
urb->actual_length = 0;
if (endp) {
unsigned long irqs;
int retval;
spin_lock_irqsave(&endp->queue_lock.slock,
irqs);
retval = queue_bulk_on_old_endpoint(u132, udev,
hep, urb, usb_dev, endp, usb_addr,
usb_endp, address);
retval = usb_hcd_link_urb_to_ep(hcd, urb);
if (retval == 0) {
retval = queue_bulk_on_old_endpoint(
u132, udev, urb,
usb_dev, endp,
usb_addr, usb_endp,
address);
if (retval)
usb_hcd_unlink_urb_from_ep(
hcd, urb);
}
spin_unlock_irqrestore(&endp->queue_lock.slock,
irqs);
if (retval) {
@ -2315,10 +2359,10 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
return -EINVAL;
} else
return create_endpoint_and_queue_bulk(u132,
udev, hep, urb, usb_dev, usb_addr,
udev, urb, usb_dev, usb_addr,
usb_endp, address, mem_flags);
} else {
struct u132_endp *endp = hep->hcpriv;
struct u132_endp *endp = urb->ep->hcpriv;
u16 urb_size = 8;
u8 *b = urb->setup_packet;
int i = 0;
@ -2341,9 +2385,16 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
int retval;
spin_lock_irqsave(&endp->queue_lock.slock,
irqs);
retval = queue_control_on_old_endpoint(u132,
hep, urb, usb_dev, endp, usb_addr,
usb_endp);
retval = usb_hcd_link_urb_to_ep(hcd, urb);
if (retval == 0) {
retval = queue_control_on_old_endpoint(
u132, urb, usb_dev,
endp, usb_addr,
usb_endp);
if (retval)
usb_hcd_unlink_urb_from_ep(
hcd, urb);
}
spin_unlock_irqrestore(&endp->queue_lock.slock,
irqs);
if (retval) {
@ -2356,7 +2407,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
return -EINVAL;
} else
return create_endpoint_and_queue_control(u132,
hep, urb, usb_dev, usb_addr, usb_endp,
urb, usb_dev, usb_addr, usb_endp,
mem_flags);
}
}
@ -2375,8 +2426,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
list_del(scan);
endp->queue_size -= 1;
urb->error_count = 0;
urb->hcpriv = NULL;
usb_hcd_giveback_urb(hcd, urb);
usb_hcd_giveback_urb(hcd, urb, 0);
return 0;
} else
continue;
@ -2391,10 +2441,17 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
}
static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
struct urb *urb)
struct urb *urb, int status)
{
unsigned long irqs;
int rc;
spin_lock_irqsave(&endp->queue_lock.slock, irqs);
rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
if (rc) {
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
return rc;
}
if (endp->queue_size == 0) {
dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
"=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
@ -2410,11 +2467,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
endp->edset_flush = 1;
u132_endp_queue_work(u132, endp, 0);
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
urb->hcpriv = NULL;
return 0;
} else {
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
u132_hcd_abandon_urb(u132, endp, urb, urb->status);
u132_hcd_abandon_urb(u132, endp, urb, status);
return 0;
}
} else {
@ -2439,6 +2495,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
}
if (urb_slot) {
struct usb_hcd *hcd = u132_to_hcd(u132);
usb_hcd_unlink_urb_from_ep(hcd, urb);
endp->queue_size -= 1;
if (list_empty(&endp->urb_more)) {
spin_unlock_irqrestore(&endp->queue_lock.slock,
@ -2453,8 +2511,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
irqs);
kfree(urbq);
} urb->error_count = 0;
urb->hcpriv = NULL;
usb_hcd_giveback_urb(hcd, urb);
usb_hcd_giveback_urb(hcd, urb, status);
return 0;
} else if (list_empty(&endp->urb_more)) {
dev_err(&u132->platform_dev->dev, "urb=%p not found in "
@ -2468,7 +2525,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
return -EINVAL;
} else {
int retval = dequeue_from_overflow_chain(u132, endp,
int retval;
usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
retval = dequeue_from_overflow_chain(u132, endp,
urb);
spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
return retval;
@ -2476,7 +2536,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
}
}
static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct u132 *u132 = hcd_to_u132(hcd);
if (u132->going > 2) {
@ -2491,11 +2551,11 @@ static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
if (usb_pipein(urb->pipe)) {
u8 endp_number = udev->endp_number_in[usb_endp];
struct u132_endp *endp = u132->endp[endp_number - 1];
return u132_endp_urb_dequeue(u132, endp, urb);
return u132_endp_urb_dequeue(u132, endp, urb, status);
} else {
u8 endp_number = udev->endp_number_out[usb_endp];
struct u132_endp *endp = u132->endp[endp_number - 1];
return u132_endp_urb_dequeue(u132, endp, urb);
return u132_endp_urb_dequeue(u132, endp, urb, status);
}
}
}
@ -2805,7 +2865,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
return -ESHUTDOWN;
} else {
int retval = 0;
down(&u132->sw_lock);
mutex_lock(&u132->sw_lock);
switch (typeReq) {
case ClearHubFeature:
switch (wValue) {
@ -2868,7 +2928,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
stall:retval = -EPIPE;
break;
}
up(&u132->sw_lock);
mutex_unlock(&u132->sw_lock);
return retval;
}
}
@ -3004,7 +3064,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
dev_err(&u132->platform_dev->dev, "removing device u132"
".%d\n", u132->sequence_num);
msleep(100);
down(&u132->sw_lock);
mutex_lock(&u132->sw_lock);
u132_monitor_cancel_work(u132);
while (rings-- > 0) {
struct u132_ring *ring = &u132->ring[rings];
@ -3017,7 +3077,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
u132->going += 1;
printk(KERN_INFO "removing device u132.%d\n",
u132->sequence_num);
up(&u132->sw_lock);
mutex_unlock(&u132->sw_lock);
usb_remove_hcd(hcd);
u132_u132_put_kref(u132);
return 0;
@ -3037,7 +3097,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
u132->platform_dev = pdev;
u132->power = 0;
u132->reset = 0;
init_MUTEX(&u132->sw_lock);
mutex_init(&u132->sw_lock);
init_MUTEX(&u132->scheduler_lock);
while (rings-- > 0) {
struct u132_ring *ring = &u132->ring[rings];
@ -3047,7 +3107,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
ring->curr_endp = NULL;
INIT_DELAYED_WORK(&ring->scheduler,
u132_hcd_ring_work_scheduler);
} down(&u132->sw_lock);
} mutex_lock(&u132->sw_lock);
INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
while (ports-- > 0) {
struct u132_port *port = &u132->port[ports];
@ -3077,7 +3137,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
while (endps-- > 0) {
u132->endp[endps] = NULL;
}
up(&u132->sw_lock);
mutex_unlock(&u132->sw_lock);
return;
}

View File

@ -120,8 +120,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
if (urbp->urb->status != -EINPROGRESS)
out += sprintf(out, " Status=%d", urbp->urb->status);
if (urbp->urb->unlinked)
out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
out += sprintf(out, "\n");
i = nactive = ninactive = 0;

View File

@ -146,7 +146,6 @@ struct uhci_qh {
short phase; /* Between 0 and period-1 */
short load; /* Periodic time requirement, in us */
unsigned int iso_frame; /* Frame # for iso_packet_desc */
int iso_status; /* Status for Isochronous URBs */
int state; /* QH_STATE_xxx; see above */
int type; /* Queue type (control, bulk, etc) */
@ -457,21 +456,6 @@ struct urb_priv {
};
/*
* Locking in uhci.c
*
* Almost everything relating to the hardware schedule and processing
* of URBs is protected by uhci->lock. urb->status is protected by
* urb->lock; that's the one exception.
*
* To prevent deadlocks, never lock uhci->lock while holding urb->lock.
* The safe order of locking is:
*
* #1 uhci->lock
* #2 urb->lock
*/
/* Some special IDs */
#define PCI_VENDOR_ID_GENESYS 0x17a0

View File

@ -757,7 +757,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
uhci_free_td(uhci, td);
}
urbp->urb->hcpriv = NULL;
kmem_cache_free(uhci_up_cachep, urbp);
}
@ -1324,7 +1323,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
if (list_empty(&qh->queue)) {
qh->iso_packet_desc = &urb->iso_frame_desc[0];
qh->iso_frame = urb->start_frame;
qh->iso_status = 0;
}
qh->skel = SKEL_ISO;
@ -1361,22 +1359,18 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
qh->iso_packet_desc->actual_length = actlength;
qh->iso_packet_desc->status = status;
}
if (status) {
if (status)
urb->error_count++;
qh->iso_status = status;
}
uhci_remove_td_from_urbp(td);
uhci_free_td(uhci, td);
qh->iso_frame += qh->period;
++qh->iso_packet_desc;
}
return qh->iso_status;
return 0;
}
static int uhci_urb_enqueue(struct usb_hcd *hcd,
struct usb_host_endpoint *hep,
struct urb *urb, gfp_t mem_flags)
{
int ret;
@ -1387,19 +1381,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
spin_lock_irqsave(&uhci->lock, flags);
ret = urb->status;
if (ret != -EINPROGRESS) /* URB already unlinked! */
goto done;
ret = usb_hcd_link_urb_to_ep(hcd, urb);
if (ret)
goto done_not_linked;
ret = -ENOMEM;
urbp = uhci_alloc_urb_priv(uhci, urb);
if (!urbp)
goto done;
if (hep->hcpriv)
qh = (struct uhci_qh *) hep->hcpriv;
if (urb->ep->hcpriv)
qh = urb->ep->hcpriv;
else {
qh = uhci_alloc_qh(uhci, urb->dev, hep);
qh = uhci_alloc_qh(uhci, urb->dev, urb->ep);
if (!qh)
goto err_no_qh;
}
@ -1440,27 +1434,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
err_submit_failed:
if (qh->state == QH_STATE_IDLE)
uhci_make_qh_idle(uhci, qh); /* Reclaim unused QH */
err_no_qh:
uhci_free_urb_priv(uhci, urbp);
done:
if (ret)
usb_hcd_unlink_urb_from_ep(hcd, urb);
done_not_linked:
spin_unlock_irqrestore(&uhci->lock, flags);
return ret;
}
static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags;
struct urb_priv *urbp;
struct uhci_qh *qh;
int rc;
spin_lock_irqsave(&uhci->lock, flags);
urbp = urb->hcpriv;
if (!urbp) /* URB was never linked! */
rc = usb_hcd_check_unlink_urb(hcd, urb, status);
if (rc)
goto done;
qh = urbp->qh;
qh = ((struct urb_priv *) urb->hcpriv)->qh;
/* Remove Isochronous TDs from the frame list ASAP */
if (qh->type == USB_ENDPOINT_XFER_ISOC) {
@ -1477,14 +1473,14 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
done:
spin_unlock_irqrestore(&uhci->lock, flags);
return 0;
return rc;
}
/*
* Finish unlinking an URB and give it back
*/
static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
struct urb *urb)
struct urb *urb, int status)
__releases(uhci->lock)
__acquires(uhci->lock)
{
@ -1497,13 +1493,6 @@ __acquires(uhci->lock)
* unlinked first. Regardless, don't confuse people with a
* negative length. */
urb->actual_length = max(urb->actual_length, 0);
/* Report erroneous short transfers */
if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
urb->actual_length <
urb->transfer_buffer_length &&
urb->status == 0))
urb->status = -EREMOTEIO;
}
/* When giving back the first URB in an Isochronous queue,
@ -1516,7 +1505,6 @@ __acquires(uhci->lock)
qh->iso_packet_desc = &nurb->iso_frame_desc[0];
qh->iso_frame = nurb->start_frame;
qh->iso_status = 0;
}
/* Take the URB off the QH's queue. If the queue is now empty,
@ -1529,9 +1517,10 @@ __acquires(uhci->lock)
}
uhci_free_urb_priv(uhci, urbp);
usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb);
spin_unlock(&uhci->lock);
usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status);
spin_lock(&uhci->lock);
/* If the queue is now empty, we can unlink the QH and give up its
@ -1567,24 +1556,17 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
if (status == -EINPROGRESS)
break;
spin_lock(&urb->lock);
if (urb->status == -EINPROGRESS) /* Not dequeued */
urb->status = status;
else
status = ECONNRESET; /* Not -ECONNRESET */
spin_unlock(&urb->lock);
/* Dequeued but completed URBs can't be given back unless
* the QH is stopped or has finished unlinking. */
if (status == ECONNRESET) {
if (urb->unlinked) {
if (QH_FINISHED_UNLINKING(qh))
qh->is_stopped = 1;
else if (!qh->is_stopped)
return;
}
uhci_giveback_urb(uhci, qh, urb);
if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC)
uhci_giveback_urb(uhci, qh, urb, status);
if (status < 0)
break;
}
@ -1599,7 +1581,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
restart:
list_for_each_entry(urbp, &qh->queue, node) {
urb = urbp->urb;
if (urb->status != -EINPROGRESS) {
if (urb->unlinked) {
/* Fix up the TD links and save the toggles for
* non-Isochronous queues. For Isochronous queues,
@ -1608,7 +1590,7 @@ restart:
qh->is_stopped = 0;
return;
}
uhci_giveback_urb(uhci, qh, urb);
uhci_giveback_urb(uhci, qh, urb, 0);
goto restart;
}
}

View File

@ -188,7 +188,8 @@ static void adu_interrupt_in_callback(struct urb *urb)
spin_lock(&dev->buflock);
if (status != 0) {
if ((status != -ENOENT) && (status != -ECONNRESET)) {
if ((status != -ENOENT) && (status != -ECONNRESET) &&
(status != -ESHUTDOWN)) {
dbg(1," %s : nonzero status received: %d",
__FUNCTION__, status);
}

View File

@ -71,7 +71,7 @@ static int magic_charge(struct usb_device *udev)
if (retval != 2) {
dev_err(&udev->dev, "First magic command failed: %d.\n",
retval);
return retval;
goto exit;
}
dbg(&udev->dev, "Sending second magic command\n");
@ -80,7 +80,7 @@ static int magic_charge(struct usb_device *udev)
if (retval != 0) {
dev_err(&udev->dev, "Second magic command failed: %d.\n",
retval);
return retval;
goto exit;
}
dbg(&udev->dev, "Calling set_configuration\n");
@ -88,6 +88,8 @@ static int magic_charge(struct usb_device *udev)
if (retval)
dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
exit:
kfree(dummy_buffer);
return retval;
}
@ -112,6 +114,7 @@ static int magic_dual_mode(struct usb_device *udev)
if (retval)
dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
kfree(dummy_buffer);
return retval;
}

View File

@ -2777,12 +2777,14 @@ static int ftdi_elan_probe(struct usb_interface *interface,
size_t buffer_size;
int i;
int retval = -ENOMEM;
struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
if (ftdi == NULL) {
struct usb_ftdi *ftdi;
ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
if (!ftdi) {
printk(KERN_ERR "Out of memory\n");
return -ENOMEM;
}
memset(ftdi, 0x00, sizeof(struct usb_ftdi));
mutex_lock(&ftdi_module_lock);
list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
ftdi->sequence_num = ++ftdi_instances;

View File

@ -32,7 +32,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Author: Thomas Winischhofer <thomas@winischhofer.net>
* Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@ -962,12 +962,12 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
packet.address = 0x00000194;
packet.data = addr;
ret = sisusb_send_bridge_packet(sisusb, 10,
&packet, 0);
&packet, 0);
packet.header = 0x001f;
packet.address = 0x00000190;
packet.data = (length & ~3);
ret |= sisusb_send_bridge_packet(sisusb, 10,
&packet, 0);
&packet, 0);
if (sisusb->flagb0 != 0x16) {
packet.header = 0x001f;
packet.address = 0x00000180;
@ -1003,23 +1003,17 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
if (ret) {
msgcount++;
if (msgcount < 500)
printk(KERN_ERR
"sisusbvga[%d]: Wrote %zd of "
"%d bytes, error %d\n",
sisusb->minor, *bytes_written,
length, ret);
dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n",
*bytes_written, length, ret);
else if (msgcount == 500)
printk(KERN_ERR
"sisusbvga[%d]: Too many errors"
", logging stopped\n",
sisusb->minor);
dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n");
}
addr += (*bytes_written);
length -= (*bytes_written);
}
if (ret)
break;
break;
}
@ -1261,51 +1255,10 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
addr += 4;
length -= 4;
}
#if 0 /* That does not work, as EP 2 is an OUT EP! */
default:
CLEARPACKET(&packet);
packet.header = 0x001f;
packet.address = 0x000001a0;
packet.data = 0x00000006;
ret |= sisusb_send_bridge_packet(sisusb, 10,
&packet, 0);
packet.header = 0x001f;
packet.address = 0x000001b0;
packet.data = (length & ~3) | 0x40000000;
ret |= sisusb_send_bridge_packet(sisusb, 10,
&packet, 0);
packet.header = 0x001f;
packet.address = 0x000001b4;
packet.data = addr;
ret |= sisusb_send_bridge_packet(sisusb, 10,
&packet, 0);
packet.header = 0x001f;
packet.address = 0x000001a4;
packet.data = 0x00000001;
ret |= sisusb_send_bridge_packet(sisusb, 10,
&packet, 0);
if (userbuffer) {
ret |= sisusb_recv_bulk_msg(sisusb,
SISUSB_EP_GFX_BULK_IN,
(length & ~3),
NULL, userbuffer,
bytes_read, 0);
if (!ret) userbuffer += (*bytes_read);
} else {
ret |= sisusb_recv_bulk_msg(sisusb,
SISUSB_EP_GFX_BULK_IN,
(length & ~3),
kernbuffer, NULL,
bytes_read, 0);
if (!ret) kernbuffer += (*bytes_read);
}
addr += (*bytes_read);
length -= (*bytes_read);
#endif
}
if (ret)
break;
break;
}
return ret;
@ -1401,22 +1354,6 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
}
#if 0
int
sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
{
return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
}
int
sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
{
return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
}
#endif /* 0 */
int
sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
u32 dest, int length, size_t *bytes_written)
@ -1446,10 +1383,10 @@ sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
for(i = 1; i <= 7; i++) {
printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i);
sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
for(j = 0; j < i; j++) {
printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]);
}
}
}
@ -1533,9 +1470,9 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
#define SETIREGAND(r,i,a) sisusb_setidxregand(sisusb, r, i, a)
#define SETIREGANDOR(r,i,a,o) sisusb_setidxregandor(sisusb, r, i, a, o)
#define READL(a,d) sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
#define WRITEL(a,d) sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
#define READB(a,d) sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
#define WRITEB(a,d) sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
static int
sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
@ -2008,7 +1945,7 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
SETIREG(SISSR, 0x26, 0x00);
}
SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
SETIREG(SISCR, 0x34, 0x44); /* we just set std mode #44 */
return ret;
}
@ -2168,17 +2105,12 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
if (ramtype <= 1) {
ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
if (iret) {
printk(KERN_ERR "sisusbvga[%d]: RAM size "
"detection failed, "
"assuming 8MB video RAM\n",
sisusb->minor);
dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n");
ret |= SETIREG(SISSR,0x14,0x31);
/* TODO */
}
} else {
printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
"assuming 8MB video RAM\n",
sisusb->minor);
dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n");
ret |= SETIREG(SISSR,0x14,0x31);
/* *** TODO *** */
}
@ -2249,8 +2181,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
break;
}
printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1,
ramtypetext2[ramtype], bw);
}
@ -2509,11 +2440,8 @@ sisusb_open(struct inode *inode, struct file *file)
struct usb_interface *interface;
int subminor = iminor(inode);
if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
subminor);
if (!(interface = usb_find_interface(&sisusb_driver, subminor)))
return -ENODEV;
}
if (!(sisusb = usb_get_intfdata(interface)))
return -ENODEV;
@ -2534,18 +2462,12 @@ sisusb_open(struct inode *inode, struct file *file)
if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
if (sisusb_init_gfxdevice(sisusb, 0)) {
mutex_unlock(&sisusb->lock);
printk(KERN_ERR
"sisusbvga[%d]: Failed to initialize "
"device\n",
sisusb->minor);
dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
return -EIO;
}
} else {
mutex_unlock(&sisusb->lock);
printk(KERN_ERR
"sisusbvga[%d]: Device not attached to "
"USB 2.0 hub\n",
sisusb->minor);
dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
return -EIO;
}
}
@ -2586,7 +2508,6 @@ static int
sisusb_release(struct inode *inode, struct file *file)
{
struct sisusb_usb_data *sisusb;
int myminor;
if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
return -ENODEV;
@ -2599,8 +2520,6 @@ sisusb_release(struct inode *inode, struct file *file)
sisusb_kill_all_busy(sisusb);
}
myminor = sisusb->minor;
sisusb->isopen = 0;
file->private_data = NULL;
@ -2942,7 +2861,7 @@ static int
sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
unsigned long arg)
{
int retval, port, length;
int retval, port, length;
u32 address;
/* All our commands require the device
@ -3065,12 +2984,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
static int
sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
unsigned long arg)
{
struct sisusb_usb_data *sisusb;
struct sisusb_info x;
struct sisusb_command y;
int retval = 0;
int retval = 0;
u32 __user *argp = (u32 __user *)arg;
if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
@ -3095,7 +3014,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
case SISUSB_GET_CONFIG:
x.sisusb_id = SISUSB_ID;
x.sisusb_id = SISUSB_ID;
x.sisusb_version = SISUSB_VERSION;
x.sisusb_revision = SISUSB_REVISION;
x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
@ -3164,7 +3083,7 @@ static const struct file_operations usb_sisusb_fops = {
.release = sisusb_release,
.read = sisusb_read,
.write = sisusb_write,
.llseek = sisusb_lseek,
.llseek = sisusb_lseek,
#ifdef SISUSB_NEW_CONFIG_COMPAT
.compat_ioctl = sisusb_compat_ioctl,
#endif
@ -3183,17 +3102,13 @@ static int sisusb_probe(struct usb_interface *intf,
struct usb_device *dev = interface_to_usbdev(intf);
struct sisusb_usb_data *sisusb;
int retval = 0, i;
const char *memfail =
KERN_ERR
"sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
dev_info(&dev->dev, "USB2VGA dongle found at address %d\n",
dev->devnum);
/* Allocate memory for our private */
if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
printk(KERN_ERR
"sisusb: Failed to allocate memory for private data\n");
dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n");
return -ENOMEM;
}
kref_init(&sisusb->kref);
@ -3202,8 +3117,7 @@ static int sisusb_probe(struct usb_interface *intf,
/* Register device */
if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
printk(KERN_ERR
"sisusb: Failed to get a minor for device %d\n",
dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n",
dev->devnum);
retval = -ENODEV;
goto error_1;
@ -3221,7 +3135,7 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->ibufsize = SISUSB_IBUF_SIZE;
if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
GFP_KERNEL, &sisusb->transfer_dma_in))) {
printk(memfail, "input", sisusb->minor);
dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer");
retval = -ENOMEM;
goto error_2;
}
@ -3233,7 +3147,7 @@ static int sisusb_probe(struct usb_interface *intf,
GFP_KERNEL,
&sisusb->transfer_dma_out[i]))) {
if (i == 0) {
printk(memfail, "output", sisusb->minor);
dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
retval = -ENOMEM;
goto error_3;
}
@ -3245,9 +3159,7 @@ static int sisusb_probe(struct usb_interface *intf,
/* Allocate URBs */
if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
printk(KERN_ERR
"sisusbvga[%d]: Failed to allocate URBs\n",
sisusb->minor);
dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
retval = -ENOMEM;
goto error_3;
}
@ -3255,9 +3167,7 @@ static int sisusb_probe(struct usb_interface *intf,
for (i = 0; i < sisusb->numobufs; i++) {
if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
printk(KERN_ERR
"sisusbvga[%d]: Failed to allocate URBs\n",
sisusb->minor);
dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
retval = -ENOMEM;
goto error_4;
}
@ -3266,15 +3176,12 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->urbstatus[i] = 0;
}
printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
sisusb->minor, sisusb->numobufs);
dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs);
#ifdef INCL_SISUSB_CON
/* Allocate our SiS_Pr */
if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
printk(KERN_ERR
"sisusbvga[%d]: Failed to allocate SiS_Pr\n",
sisusb->minor);
dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n");
}
#endif
@ -3296,10 +3203,7 @@ static int sisusb_probe(struct usb_interface *intf,
ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG, NULL);
ret |= register_ioctl32_conversion(SISUSB_COMMAND, NULL);
if (ret)
printk(KERN_ERR
"sisusbvga[%d]: Error registering ioctl32 "
"translations\n",
sisusb->minor);
dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n");
else
sisusb->ioctl32registered = 1;
}
@ -3315,23 +3219,17 @@ static int sisusb_probe(struct usb_interface *intf,
initscreen = 0;
#endif
if (sisusb_init_gfxdevice(sisusb, initscreen))
printk(KERN_ERR
"sisusbvga[%d]: Failed to early "
"initialize device\n",
sisusb->minor);
dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n");
} else
printk(KERN_INFO
"sisusbvga[%d]: Not attached to USB 2.0 hub, "
"deferring init\n",
sisusb->minor);
dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n");
sisusb->ready = 1;
#ifdef SISUSBENDIANTEST
printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n");
sisusb_testreadwrite(sisusb);
printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n");
#endif
#ifdef INCL_SISUSB_CON
@ -3354,7 +3252,6 @@ error_1:
static void sisusb_disconnect(struct usb_interface *intf)
{
struct sisusb_usb_data *sisusb;
int minor;
/* This should *not* happen */
if (!(sisusb = usb_get_intfdata(intf)))
@ -3364,8 +3261,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
sisusb_console_exit(sisusb);
#endif
minor = sisusb->minor;
usb_deregister_dev(intf, &usb_sisusb_class);
mutex_lock(&sisusb->lock);
@ -3384,10 +3279,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
if (ret) {
printk(KERN_ERR
"sisusbvga[%d]: Error unregistering "
"ioctl32 translations\n",
minor);
dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n");
}
}
#endif
@ -3400,7 +3292,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
/* decrement our usage count */
kref_put(&sisusb->kref, sisusb_delete);
printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
}
static struct usb_device_id sisusb_table [] = {
@ -3424,22 +3316,12 @@ static struct usb_driver sisusb_driver = {
static int __init usb_sisusb_init(void)
{
int retval;
#ifdef INCL_SISUSB_CON
sisusb_init_concode();
#endif
if (!(retval = usb_register(&sisusb_driver))) {
printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
printk(KERN_INFO
"sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
}
return retval;
return usb_register(&sisusb_driver);
}
static void __exit usb_sisusb_exit(void)

View File

@ -8,29 +8,29 @@
*
* Otherwise, the following license terms apply:
*
* * Redistribution and use in source and binary forms, with or without
* * modification, are permitted provided that the following conditions
* * are met:
* * 1) Redistributions of source code must retain the above copyright
* * notice, this list of conditions and the following disclaimer.
* * 2) Redistributions in binary form must reproduce the above copyright
* * notice, this list of conditions and the following disclaimer in the
* * documentation and/or other materials provided with the distribution.
* * 3) The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission.
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
* * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1) Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2) Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3) The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* Author: Thomas Winischhofer <thomas@winischhofer.net>
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@ -44,16 +44,14 @@
#include <linux/mutex.h>
/* For older kernels, support for text consoles is by default
* off. To ensable text console support, change the following:
* off. To enable text console support, change the following:
*/
#if 0
#define CONFIG_USB_SISUSBVGA_CON
#endif
/* #define CONFIG_USB_SISUSBVGA_CON */
/* Version Information */
#define SISUSB_VERSION 0
#define SISUSB_REVISION 0
#define SISUSB_REVISION 0
#define SISUSB_PATCHLEVEL 8
/* Include console and mode switching code? */
@ -74,7 +72,7 @@
#define SISUSB_IBUF_SIZE 0x01000
#define SISUSB_OBUF_SIZE 0x10000 /* fixed */
#define NUMOBUFS 8 /* max number of output buffers/output URBs */
#define NUMOBUFS 8 /* max number of output buffers/output URBs */
/* About endianness:
*
@ -93,7 +91,7 @@
*/
#ifdef __BIG_ENDIAN
#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \
#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) \
do { \
p->header = cpu_to_le16(p->header); \
p->address = cpu_to_le32(p->address); \
@ -105,7 +103,7 @@
struct sisusb_usb_data;
struct sisusb_urb_context { /* urb->context for outbound bulk URBs */
struct sisusb_urb_context { /* urb->context for outbound bulk URBs */
struct sisusb_usb_data *sisusb;
int urbindex;
int *actual_length;
@ -116,16 +114,16 @@ struct sisusb_usb_data {
struct usb_interface *interface;
struct kref kref;
wait_queue_head_t wait_q; /* for syncind and timeouts */
struct mutex lock; /* general race avoidance */
unsigned int ifnum; /* interface number of the USB device */
int minor; /* minor (for logging clarity) */
int isopen; /* !=0 if open */
int present; /* !=0 if device is present on the bus */
int ready; /* !=0 if device is ready for userland */
struct mutex lock; /* general race avoidance */
unsigned int ifnum; /* interface number of the USB device */
int minor; /* minor (for logging clarity) */
int isopen; /* !=0 if open */
int present; /* !=0 if device is present on the bus */
int ready; /* !=0 if device is ready for userland */
#ifdef SISUSB_OLD_CONFIG_COMPAT
int ioctl32registered;
#endif
int numobufs; /* number of obufs = number of out urbs */
int numobufs; /* number of obufs = number of out urbs */
char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */
int obufsize, ibufsize;
dma_addr_t transfer_dma_out[NUMOBUFS];
@ -136,13 +134,13 @@ struct sisusb_usb_data {
unsigned char completein;
struct sisusb_urb_context urbout_context[NUMOBUFS];
unsigned long flagb0;
unsigned long vrambase; /* framebuffer base */
unsigned int vramsize; /* framebuffer size (bytes) */
unsigned long vrambase; /* framebuffer base */
unsigned int vramsize; /* framebuffer size (bytes) */
unsigned long mmiobase;
unsigned int mmiosize;
unsigned long ioportbase;
unsigned char devinit; /* device initialized? */
unsigned char gfxinit; /* graphics core initialized? */
unsigned char devinit; /* device initialized? */
unsigned char gfxinit; /* graphics core initialized? */
unsigned short chipid, chipvendor;
unsigned short chiprevision;
#ifdef INCL_SISUSB_CON
@ -152,7 +150,7 @@ struct sisusb_usb_data {
int haveconsole, con_first, con_last;
int havethisconsole[MAX_NR_CONSOLES];
int textmodedestroyed;
unsigned int sisusb_num_columns; /* real number, not vt's idea */
unsigned int sisusb_num_columns; /* real number, not vt's idea */
int cur_start_addr, con_rolled_over;
int sisusb_cursor_loc, bad_cursor_pos;
int sisusb_cursor_size_from;
@ -197,7 +195,7 @@ struct sisusb_packet {
unsigned short header;
u32 address;
u32 data;
} __attribute__((__packed__));
} __attribute__ ((__packed__));
#define CLEARPACKET(packet) memset(packet, 0, 10)
@ -265,36 +263,36 @@ struct sisusb_packet {
/* Structure argument for SISUSB_GET_INFO ioctl */
struct sisusb_info {
__u32 sisusb_id; /* for identifying sisusb */
#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */
__u8 sisusb_version;
__u8 sisusb_revision;
__u8 sisusb_patchlevel;
__u8 sisusb_gfxinit; /* graphics core initialized? */
__u32 sisusb_id; /* for identifying sisusb */
#define SISUSB_ID 0x53495355 /* Identify myself with 'SISU' */
__u8 sisusb_version;
__u8 sisusb_revision;
__u8 sisusb_patchlevel;
__u8 sisusb_gfxinit; /* graphics core initialized? */
__u32 sisusb_vrambase;
__u32 sisusb_mmiobase;
__u32 sisusb_iobase;
__u32 sisusb_pcibase;
__u32 sisusb_vrambase;
__u32 sisusb_mmiobase;
__u32 sisusb_iobase;
__u32 sisusb_pcibase;
__u32 sisusb_vramsize; /* framebuffer size in bytes */
__u32 sisusb_vramsize; /* framebuffer size in bytes */
__u32 sisusb_minor;
__u32 sisusb_minor;
__u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */
__u32 sisusb_fbdevactive; /* != 0 if framebuffer device active */
__u32 sisusb_conactive; /* != 0 if console driver active */
__u32 sisusb_conactive; /* != 0 if console driver active */
__u8 sisusb_reserved[28]; /* for future use */
__u8 sisusb_reserved[28]; /* for future use */
};
struct sisusb_command {
__u8 operation; /* see below */
__u8 data0; /* operation dependent */
__u8 data1; /* operation dependent */
__u8 data2; /* operation dependent */
__u32 data3; /* operation dependent */
__u32 data4; /* for future use */
__u8 operation; /* see below */
__u8 data0; /* operation dependent */
__u8 data1; /* operation dependent */
__u8 data2; /* operation dependent */
__u32 data3; /* operation dependent */
__u32 data4; /* for future use */
};
#define SUCMD_GET 0x01 /* for all: data0 = index, data3 = port */
@ -306,7 +304,7 @@ struct sisusb_command {
#define SUCMD_CLRSCR 0x07 /* data0:1:2 = length, data3 = address */
#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
#define SUCMD_SETMODE 0x09 /* Set a display mode (data3 = SiS mode) */
#define SUCMD_SETVESAMODE 0x0a /* Set a display mode (data3 = VESA mode) */
@ -315,6 +313,4 @@ struct sisusb_command {
#define SISUSB_GET_CONFIG_SIZE _IOR(0xF3,0x3E,__u32)
#define SISUSB_GET_CONFIG _IOR(0xF3,0x3F,struct sisusb_info)
#endif /* SISUSB_H */

View File

@ -52,6 +52,7 @@
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/fs.h>
#include <linux/usb.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
@ -373,14 +374,6 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
return;
/* sisusb->lock is down */
/* Don't need to put the character into buffer ourselves,
* because the vt does this BEFORE calling us.
*/
#if 0
sisusbcon_writew(ch, SISUSB_VADDR(x, y));
#endif
if (sisusb_is_inactive(c, sisusb)) {
mutex_unlock(&sisusb->lock);
return;
@ -490,10 +483,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
struct sisusb_usb_data *sisusb;
ssize_t written;
int cols, length;
#if 0
u16 *src, *dest;
int i;
#endif
if (width <= 0 || height <= 0)
return;
@ -505,41 +494,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
cols = sisusb->sisusb_num_columns;
/* Don't need to move data outselves, because
* vt does this BEFORE calling us.
* This is only used by vt's insert/deletechar.
*/
#if 0
if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) {
sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy),
height * width * 2);
} else if (dy < sy || (dy == sy && dx < sx)) {
src = SISUSB_VADDR(sx, sy);
dest = SISUSB_VADDR(dx, dy);
for (i = height; i > 0; i--) {
sisusbcon_memmovew(dest, src, width * 2);
src += cols;
dest += cols;
}
} else {
src = SISUSB_VADDR(sx, sy + height - 1);
dest = SISUSB_VADDR(dx, dy + height - 1);
for (i = height; i > 0; i--) {
sisusbcon_memmovew(dest, src, width * 2);
src -= cols;
dest -= cols;
}
}
#endif
if (sisusb_is_inactive(c, sisusb)) {
mutex_unlock(&sisusb->lock);
return;
@ -584,7 +538,7 @@ sisusbcon_switch(struct vc_data *c)
*/
if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
mutex_unlock(&sisusb->lock);
printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n");
return 0;
}
@ -1475,7 +1429,7 @@ static const struct consw sisusb_dummy_con = {
int
sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
{
int i, ret, minor = sisusb->minor;
int i, ret;
mutex_lock(&sisusb->lock);
@ -1508,9 +1462,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
/* Set up text mode (and upload default font) */
if (sisusb_reset_text_mode(sisusb, 1)) {
mutex_unlock(&sisusb->lock);
printk(KERN_ERR
"sisusbvga[%d]: Failed to set up text mode\n",
minor);
dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n");
return 1;
}
@ -1531,9 +1483,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
/* Allocate screen buffer */
if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
mutex_unlock(&sisusb->lock);
printk(KERN_ERR
"sisusbvga[%d]: Failed to allocate screen buffer\n",
minor);
dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n");
return 1;
}

View File

@ -32,7 +32,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Author: Thomas Winischhofer <thomas@winischhofer.net>
* Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@ -55,131 +55,39 @@
/* POINTER INITIALIZATION */
/*********************************************/
static void
SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
{
SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
}
/*********************************************/
/* HELPER: Get ModeID */
/*********************************************/
#if 0
unsigned short
SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
{
unsigned short ModeIndex = 0;
switch (HDisplay)
{
case 320:
if (VDisplay == 200)
ModeIndex = ModeIndex_320x200[Depth];
else if (VDisplay == 240)
ModeIndex = ModeIndex_320x240[Depth];
break;
case 400:
if (VDisplay == 300)
ModeIndex = ModeIndex_400x300[Depth];
break;
case 512:
if (VDisplay == 384)
ModeIndex = ModeIndex_512x384[Depth];
break;
case 640:
if (VDisplay == 480)
ModeIndex = ModeIndex_640x480[Depth];
else if (VDisplay == 400)
ModeIndex = ModeIndex_640x400[Depth];
break;
case 720:
if (VDisplay == 480)
ModeIndex = ModeIndex_720x480[Depth];
else if (VDisplay == 576)
ModeIndex = ModeIndex_720x576[Depth];
break;
case 768:
if (VDisplay == 576)
ModeIndex = ModeIndex_768x576[Depth];
break;
case 800:
if (VDisplay == 600)
ModeIndex = ModeIndex_800x600[Depth];
else if (VDisplay == 480)
ModeIndex = ModeIndex_800x480[Depth];
break;
case 848:
if (VDisplay == 480)
ModeIndex = ModeIndex_848x480[Depth];
break;
case 856:
if (VDisplay == 480)
ModeIndex = ModeIndex_856x480[Depth];
break;
case 960:
if (VDisplay == 540)
ModeIndex = ModeIndex_960x540[Depth];
else if (VDisplay == 600)
ModeIndex = ModeIndex_960x600[Depth];
break;
case 1024:
if (VDisplay == 576)
ModeIndex = ModeIndex_1024x576[Depth];
else if (VDisplay == 768)
ModeIndex = ModeIndex_1024x768[Depth];
break;
case 1152:
if (VDisplay == 864)
ModeIndex = ModeIndex_1152x864[Depth];
break;
case 1280:
switch (VDisplay) {
case 720:
ModeIndex = ModeIndex_1280x720[Depth];
break;
case 768:
ModeIndex = ModeIndex_1280x768[Depth];
break;
case 1024:
ModeIndex = ModeIndex_1280x1024[Depth];
break;
}
}
return ModeIndex;
}
#endif /* 0 */
/*********************************************/
/* HELPER: SetReg, GetReg */
/*********************************************/
static void
SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
unsigned short index, unsigned short data)
unsigned short index, unsigned short data)
{
sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
}
static void
SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
unsigned short data)
unsigned short data)
{
sisusb_setreg(SiS_Pr->sisusb, port, data);
}
static unsigned char
SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port,
unsigned short index)
SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index)
{
u8 data;
@ -200,22 +108,22 @@ SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port)
static void
SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
unsigned short index, unsigned short DataAND,
unsigned short DataOR)
unsigned short index, unsigned short DataAND,
unsigned short DataOR)
{
sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
}
static void
SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
unsigned short index, unsigned short DataAND)
unsigned short index, unsigned short DataAND)
{
sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
}
static void
SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
unsigned short index, unsigned short DataOR)
SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port,
unsigned short index, unsigned short DataOR)
{
sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
}
@ -224,8 +132,7 @@ SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
/* HELPER: DisplayOn, DisplayOff */
/*********************************************/
static void
SiS_DisplayOn(struct SiS_Private *SiS_Pr)
static void SiS_DisplayOn(struct SiS_Private *SiS_Pr)
{
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
}
@ -234,8 +141,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr)
/* HELPER: Init Port Addresses */
/*********************************************/
static void
SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
{
SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
@ -258,8 +164,7 @@ SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
/* HELPER: GetSysFlags */
/*********************************************/
static void
SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
{
SiS_Pr->SiS_MyCR63 = 0x63;
}
@ -268,8 +173,7 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
/* HELPER: Init PCI & Engines */
/*********************************************/
static void
SiSInitPCIetc(struct SiS_Private *SiS_Pr)
static void SiSInitPCIetc(struct SiS_Private *SiS_Pr)
{
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
/* - Enable 2D (0x40)
@ -285,8 +189,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr)
/* HELPER: SET SEGMENT REGISTERS */
/*********************************************/
static void
SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
{
unsigned short temp;
@ -299,8 +202,7 @@ SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
}
static void
SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
{
unsigned short temp;
@ -313,15 +215,13 @@ SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
}
static void
SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
{
SiS_SetSegRegLower(SiS_Pr, value);
SiS_SetSegRegUpper(SiS_Pr, value);
}
static void
SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
{
SiS_SetSegmentReg(SiS_Pr, 0);
}
@ -337,14 +237,12 @@ SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
SiS_SetSegmentReg(SiS_Pr, value);
}
static void
SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
{
SiS_SetSegmentRegOver(SiS_Pr, 0);
}
static void
SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
{
SiS_ResetSegmentReg(SiS_Pr);
SiS_ResetSegmentRegOver(SiS_Pr);
@ -356,7 +254,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
static int
SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
unsigned short *ModeIdIndex)
unsigned short *ModeIdIndex)
{
if ((*ModeNo) <= 0x13) {
@ -367,12 +265,14 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
} else {
for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo))
if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
(*ModeNo))
break;
if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
0xFF)
return 0;
}
@ -385,8 +285,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
/* HELPER: ENABLE CRT1 */
/*********************************************/
static void
SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
{
/* Enable CRT1 gating */
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
@ -398,9 +297,9 @@ SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
static unsigned short
SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex)
unsigned short ModeIdIndex)
{
static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
unsigned short modeflag;
short index;
@ -411,7 +310,8 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
}
index = (modeflag & ModeTypeMask) - ModeEGA;
if (index < 0) index = 0;
if (index < 0)
index = 0;
return ColorDepth[index];
}
@ -421,7 +321,7 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static unsigned short
SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex, unsigned short rrti)
unsigned short ModeIdIndex, unsigned short rrti)
{
unsigned short xres, temp, colordepth, infoflag;
@ -458,8 +358,8 @@ SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
for(i = 2; i <= 4; i++) {
SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
for (i = 2; i <= 4; i++) {
SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1];
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
}
}
@ -488,7 +388,7 @@ SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
for(i = 0; i <= 0x18; i++) {
for (i = 0; i <= 0x18; i++) {
CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
}
@ -504,7 +404,7 @@ SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
unsigned char ARdata;
unsigned short i;
for(i = 0; i <= 0x13; i++) {
for (i = 0; i <= 0x13; i++) {
ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
@ -529,7 +429,7 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
unsigned char GRdata;
unsigned short i;
for(i = 0; i <= 0x08; i++) {
for (i = 0; i <= 0x08; i++) {
GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
}
@ -544,12 +444,11 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
/* CLEAR EXTENDED REGISTERS */
/*********************************************/
static void
SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
int i;
for(i = 0x0A; i <= 0x0E; i++) {
for (i = 0x0A; i <= 0x0E; i++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
}
@ -562,15 +461,16 @@ SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
static unsigned short
SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex)
unsigned short ModeIdIndex)
{
unsigned short rrti, i, index, temp;
if (ModeNo <= 0x13)
return 0xFFFF;
index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
if (index > 0) index--;
index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
if (index > 0)
index--;
rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
@ -580,13 +480,14 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
break;
temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
temp =
SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
if (temp < SiS_Pr->SiS_ModeType)
break;
i++;
index--;
} while(index != 0xFFFF);
} while (index != 0xFFFF);
i--;
@ -597,8 +498,7 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
/* SYNC */
/*********************************************/
static void
SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
{
unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
sync &= 0xC0;
@ -612,39 +512,40 @@ SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
static void
SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex, unsigned short rrti)
unsigned short ModeIdIndex, unsigned short rrti)
{
unsigned char index;
unsigned char index;
unsigned short temp, i, j, modeflag;
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f);
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
for(i = 0,j = 0; i <= 7; i++, j++) {
for (i = 0, j = 0; i <= 7; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
SiS_Pr->SiS_CRT1Table[index].CR[i]);
SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
for(j = 0x10; i <= 10; i++, j++) {
for (j = 0x10; i <= 10; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
SiS_Pr->SiS_CRT1Table[index].CR[i]);
SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
for(j = 0x15; i <= 12; i++, j++) {
for (j = 0x15; i <= 12; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
SiS_Pr->SiS_CRT1Table[index].CR[i]);
SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
for(j = 0x0A; i <= 15; i++, j++) {
for (j = 0x0A; i <= 15; i++, j++) {
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
SiS_Pr->SiS_CRT1Table[index].CR[i]);
SiS_Pr->SiS_CRT1Table[index].CR[i]);
}
temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp);
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp);
temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
if (modeflag & DoubleScanMode) temp |= 0x80;
if (modeflag & DoubleScanMode)
temp |= 0x80;
SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
if (SiS_Pr->SiS_ModeType > ModeVGA)
@ -659,10 +560,10 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex, unsigned short rrti)
unsigned short ModeIdIndex, unsigned short rrti)
{
unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
unsigned short temp;
temp = (du >> 8) & 0x0f;
@ -670,11 +571,13 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
if (infoflag & InterlaceMode) du >>= 1;
if (infoflag & InterlaceMode)
du >>= 1;
du <<= 5;
temp = (du >> 8) & 0xff;
if (du & 0xff) temp++;
if (du & 0xff)
temp++;
temp++;
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
}
@ -685,17 +588,17 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short rrti)
unsigned short rrti)
{
unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF);
SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF);
SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka);
SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb);
SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01);
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka);
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb);
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01);
}
/*********************************************/
@ -704,7 +607,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short mi)
unsigned short mi)
{
unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
@ -729,7 +632,7 @@ SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short rrti)
unsigned short rrti)
{
unsigned short data = 0, VCLK = 0, index = 0;
@ -738,7 +641,8 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
}
if (VCLK >= 166) data |= 0x0c;
if (VCLK >= 166)
data |= 0x0c;
SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
if (VCLK >= 166)
@ -758,7 +662,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex, unsigned short rrti)
unsigned short ModeIdIndex, unsigned short rrti)
{
unsigned short data, infoflag = 0, modeflag;
@ -778,17 +682,22 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
data |= 0x02;
data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
}
if (infoflag & InterlaceMode) data |= 0x20;
if (infoflag & InterlaceMode)
data |= 0x20;
}
SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
data = 0;
if (infoflag & InterlaceMode) {
/* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3;
unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5;
unsigned short hrs =
(SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2))
- 3;
unsigned short hto =
(SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8))
+ 5;
data = hrs - (hto >> 1) + 3;
}
SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
@ -829,20 +738,26 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
static void
SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
unsigned short shiftflag, unsigned short dl, unsigned short ah,
unsigned short al, unsigned short dh)
unsigned short shiftflag, unsigned short dl, unsigned short ah,
unsigned short al, unsigned short dh)
{
unsigned short d1, d2, d3;
switch (dl) {
case 0:
d1 = dh; d2 = ah; d3 = al;
break;
case 1:
d1 = ah; d2 = al; d3 = dh;
break;
default:
d1 = al; d2 = dh; d3 = ah;
case 0:
d1 = dh;
d2 = ah;
d3 = al;
break;
case 1:
d1 = ah;
d2 = al;
d3 = dh;
break;
default:
d1 = al;
d2 = dh;
d3 = ah;
}
SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
@ -850,7 +765,8 @@ SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
}
static void
SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi)
SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short mi)
{
unsigned short data, data2, time, i, j, k, m, n, o;
unsigned short si, di, bx, sf;
@ -884,41 +800,45 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
for(i = 0; i < j; i++) {
for (i = 0; i < j; i++) {
data = table[i];
for(k = 0; k < 3; k++) {
for (k = 0; k < 3; k++) {
data2 = 0;
if (data & 0x01) data2 += 0x2A;
if (data & 0x02) data2 += 0x15;
if (data & 0x01)
data2 += 0x2A;
if (data & 0x02)
data2 += 0x15;
SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
data >>= 2;
}
}
if (time == 256) {
for(i = 16; i < 32; i++) {
for (i = 16; i < 32; i++) {
data = table[i] << sf;
for(k = 0; k < 3; k++)
for (k = 0; k < 3; k++)
SiS_SetRegByte(SiS_Pr, DACData, data);
}
si = 32;
for(m = 0; m < 9; m++) {
for (m = 0; m < 9; m++) {
di = si;
bx = si + 4;
for(n = 0; n < 3; n++) {
for(o = 0; o < 5; o++) {
for (n = 0; n < 3; n++) {
for (o = 0; o < 5; o++) {
SiS_WriteDAC(SiS_Pr, DACData, sf, n,
table[di], table[bx], table[si]);
table[di], table[bx],
table[si]);
si++;
}
si -= 2;
for(o = 0; o < 3; o++) {
for (o = 0; o < 3; o++) {
SiS_WriteDAC(SiS_Pr, DACData, sf, n,
table[di], table[si], table[bx]);
table[di], table[si],
table[bx]);
si--;
}
}
si += 5;
si += 5;
}
}
}
@ -929,7 +849,7 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
static void
SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
unsigned short ModeIdIndex)
unsigned short ModeIdIndex)
{
unsigned short StandTableIndex, rrti;
@ -970,11 +890,10 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
/* SiSSetMode() */
/*********************************************/
int
SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
{
unsigned short ModeIdIndex;
unsigned long BaseAddr = SiS_Pr->IOAddress;
unsigned long BaseAddr = SiS_Pr->IOAddress;
SiSUSB_InitPtr(SiS_Pr);
SiSUSBRegInit(SiS_Pr, BaseAddr);
@ -990,7 +909,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
ModeNo &= 0x7f;
SiS_Pr->SiS_ModeType =
SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
SiS_Pr->SiS_SetFlag = LowModeTests;
@ -1008,8 +927,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
return 1;
}
int
SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
{
unsigned short ModeNo = 0;
int i;
@ -1041,7 +959,3 @@ SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
}
#endif /* INCL_SISUSB_CON */

File diff suppressed because it is too large Load Diff

View File

@ -44,7 +44,7 @@
* * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Author: Thomas Winischhofer <thomas@winischhofer.net>
* Author: Thomas Winischhofer <thomas@winischhofer.net>
*
*/
@ -52,85 +52,78 @@
#define _SISUSB_STRUCT_H_
struct SiS_St {
unsigned char St_ModeID;
unsigned short St_ModeFlag;
unsigned char St_StTableIndex;
unsigned char St_CRT2CRTC;
unsigned char St_ResInfo;
unsigned char VB_StTVFlickerIndex;
unsigned char VB_StTVEdgeIndex;
unsigned char VB_StTVYFilterIndex;
unsigned char St_PDC;
unsigned char St_ModeID;
unsigned short St_ModeFlag;
unsigned char St_StTableIndex;
unsigned char St_CRT2CRTC;
unsigned char St_ResInfo;
unsigned char VB_StTVFlickerIndex;
unsigned char VB_StTVEdgeIndex;
unsigned char VB_StTVYFilterIndex;
unsigned char St_PDC;
};
struct SiS_StandTable
{
unsigned char CRT_COLS;
unsigned char ROWS;
unsigned char CHAR_HEIGHT;
unsigned short CRT_LEN;
unsigned char SR[4];
unsigned char MISC;
unsigned char CRTC[0x19];
unsigned char ATTR[0x14];
unsigned char GRC[9];
struct SiS_StandTable {
unsigned char CRT_COLS;
unsigned char ROWS;
unsigned char CHAR_HEIGHT;
unsigned short CRT_LEN;
unsigned char SR[4];
unsigned char MISC;
unsigned char CRTC[0x19];
unsigned char ATTR[0x14];
unsigned char GRC[9];
};
struct SiS_StResInfo_S {
unsigned short HTotal;
unsigned short VTotal;
unsigned short HTotal;
unsigned short VTotal;
};
struct SiS_Ext
{
unsigned char Ext_ModeID;
unsigned short Ext_ModeFlag;
unsigned short Ext_VESAID;
unsigned char Ext_RESINFO;
unsigned char VB_ExtTVFlickerIndex;
unsigned char VB_ExtTVEdgeIndex;
unsigned char VB_ExtTVYFilterIndex;
unsigned char VB_ExtTVYFilterIndexROM661;
unsigned char REFindex;
char ROMMODEIDX661;
struct SiS_Ext {
unsigned char Ext_ModeID;
unsigned short Ext_ModeFlag;
unsigned short Ext_VESAID;
unsigned char Ext_RESINFO;
unsigned char VB_ExtTVFlickerIndex;
unsigned char VB_ExtTVEdgeIndex;
unsigned char VB_ExtTVYFilterIndex;
unsigned char VB_ExtTVYFilterIndexROM661;
unsigned char REFindex;
char ROMMODEIDX661;
};
struct SiS_Ext2
{
unsigned short Ext_InfoFlag;
unsigned char Ext_CRT1CRTC;
unsigned char Ext_CRTVCLK;
unsigned char Ext_CRT2CRTC;
unsigned char Ext_CRT2CRTC_NS;
unsigned char ModeID;
unsigned short XRes;
unsigned short YRes;
unsigned char Ext_PDC;
unsigned char Ext_FakeCRT2CRTC;
unsigned char Ext_FakeCRT2Clk;
struct SiS_Ext2 {
unsigned short Ext_InfoFlag;
unsigned char Ext_CRT1CRTC;
unsigned char Ext_CRTVCLK;
unsigned char Ext_CRT2CRTC;
unsigned char Ext_CRT2CRTC_NS;
unsigned char ModeID;
unsigned short XRes;
unsigned short YRes;
unsigned char Ext_PDC;
unsigned char Ext_FakeCRT2CRTC;
unsigned char Ext_FakeCRT2Clk;
};
struct SiS_CRT1Table
{
unsigned char CR[17];
struct SiS_CRT1Table {
unsigned char CR[17];
};
struct SiS_VCLKData
{
unsigned char SR2B,SR2C;
unsigned short CLOCK;
struct SiS_VCLKData {
unsigned char SR2B, SR2C;
unsigned short CLOCK;
};
struct SiS_ModeResInfo
{
unsigned short HTotal;
unsigned short VTotal;
unsigned char XChar;
unsigned char YChar;
struct SiS_ModeResInfo {
unsigned short HTotal;
unsigned short VTotal;
unsigned char XChar;
unsigned char YChar;
};
struct SiS_Private
{
struct SiS_Private {
void *sisusb;
unsigned long IOAddress;
@ -151,19 +144,18 @@ struct SiS_Private
unsigned long SiS_P3da;
unsigned long SiS_Part1Port;
unsigned char SiS_MyCR63;
unsigned short SiS_CRT1Mode;
unsigned short SiS_ModeType;
unsigned short SiS_SetFlag;
unsigned char SiS_MyCR63;
unsigned short SiS_CRT1Mode;
unsigned short SiS_ModeType;
unsigned short SiS_SetFlag;
const struct SiS_StandTable *SiS_StandTable;
const struct SiS_St *SiS_SModeIDTable;
const struct SiS_Ext *SiS_EModeIDTable;
const struct SiS_Ext2 *SiS_RefIndex;
const struct SiS_CRT1Table *SiS_CRT1Table;
const struct SiS_VCLKData *SiS_VCLKData;
const struct SiS_ModeResInfo *SiS_ModeResInfo;
const struct SiS_StandTable *SiS_StandTable;
const struct SiS_St *SiS_SModeIDTable;
const struct SiS_Ext *SiS_EModeIDTable;
const struct SiS_Ext2 *SiS_RefIndex;
const struct SiS_CRT1Table *SiS_CRT1Table;
const struct SiS_VCLKData *SiS_VCLKData;
const struct SiS_ModeResInfo *SiS_ModeResInfo;
};
#endif

View File

@ -172,6 +172,10 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0)
static unsigned char xfer_to_pipe[4] = {
PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
};
static struct class *mon_bin_class;
static dev_t mon_bin_dev0;
static struct cdev mon_bin_cdev;
@ -354,13 +358,9 @@ static inline char mon_bin_get_setup(unsigned char *setupb,
const struct urb *urb, char ev_type)
{
if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S')
return '-';
if (urb->dev->bus->uses_dma &&
(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
}
if (urb->setup_packet == NULL)
return 'Z';
@ -386,13 +386,15 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp,
}
static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
char ev_type)
char ev_type, int status)
{
const struct usb_endpoint_descriptor *epd = &urb->ep->desc;
unsigned long flags;
struct timeval ts;
unsigned int urb_length;
unsigned int offset;
unsigned int length;
unsigned char dir;
struct mon_bin_hdr *ep;
char data_tag = 0;
@ -410,16 +412,19 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
if (length >= rp->b_size/5)
length = rp->b_size/5;
if (usb_pipein(urb->pipe)) {
if (usb_urb_dir_in(urb)) {
if (ev_type == 'S') {
length = 0;
data_tag = '<';
}
/* Cannot rely on endpoint number in case of control ep.0 */
dir = USB_DIR_IN;
} else {
if (ev_type == 'C') {
length = 0;
data_tag = '>';
}
dir = 0;
}
if (rp->mmap_active)
@ -440,15 +445,14 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
*/
memset(ep, 0, PKT_SIZE);
ep->type = ev_type;
ep->xfer_type = usb_pipetype(urb->pipe);
/* We use the fact that usb_pipein() returns 0x80 */
ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
ep->devnum = usb_pipedevice(urb->pipe);
ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)];
ep->epnum = dir | usb_endpoint_num(epd);
ep->devnum = urb->dev->devnum;
ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->ts_sec = ts.tv_sec;
ep->ts_usec = ts.tv_usec;
ep->status = urb->status;
ep->status = status;
ep->len_urb = urb_length;
ep->len_cap = length;
@ -471,13 +475,13 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
static void mon_bin_submit(void *data, struct urb *urb)
{
struct mon_reader_bin *rp = data;
mon_bin_event(rp, urb, 'S');
mon_bin_event(rp, urb, 'S', -EINPROGRESS);
}
static void mon_bin_complete(void *data, struct urb *urb)
static void mon_bin_complete(void *data, struct urb *urb, int status)
{
struct mon_reader_bin *rp = data;
mon_bin_event(rp, urb, 'C');
mon_bin_event(rp, urb, 'C', status);
}
static void mon_bin_error(void *data, struct urb *urb, int error)
@ -500,10 +504,10 @@ static void mon_bin_error(void *data, struct urb *urb, int error)
memset(ep, 0, PKT_SIZE);
ep->type = 'E';
ep->xfer_type = usb_pipetype(urb->pipe);
/* We use the fact that usb_pipein() returns 0x80 */
ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
ep->devnum = usb_pipedevice(urb->pipe);
ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)];
ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0;
ep->epnum |= usb_endpoint_num(&urb->ep->desc);
ep->devnum = urb->dev->devnum;
ep->busnum = urb->dev->bus->busnum;
ep->id = (unsigned long) urb;
ep->status = error;

View File

@ -129,7 +129,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
/*
*/
static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb,
int status)
{
unsigned long flags;
struct list_head *pos;
@ -139,28 +140,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
mbus->cnt_events++;
list_for_each (pos, &mbus->r_list) {
r = list_entry(pos, struct mon_reader, r_link);
r->rnf_complete(r->r_data, urb);
r->rnf_complete(r->r_data, urb, status);
}
spin_unlock_irqrestore(&mbus->lock, flags);
}
static void mon_complete(struct usb_bus *ubus, struct urb *urb)
static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status)
{
struct mon_bus *mbus;
mbus = ubus->mon_bus;
if (mbus == NULL) {
/*
* This should not happen.
* At this point we do not even know the bus number...
*/
printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n",
urb->pipe);
return;
}
mon_bus_complete(mbus, urb);
mon_bus_complete(&mon_bus0, urb);
if ((mbus = ubus->mon_bus) != NULL)
mon_bus_complete(mbus, urb, status);
mon_bus_complete(&mon_bus0, urb, status);
}
/* int (*unlink_urb) (struct urb *urb, int status); */
@ -170,7 +161,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb)
*/
static void mon_stop(struct mon_bus *mbus)
{
struct usb_bus *ubus = mbus->u_bus;
struct usb_bus *ubus;
struct list_head *p;
if (mbus == &mon_bus0) {

View File

@ -50,10 +50,13 @@ struct mon_iso_desc {
struct mon_event_text {
struct list_head e_link;
int type; /* submit, complete, etc. */
unsigned int pipe; /* Pipe */
unsigned long id; /* From pointer, most of the time */
unsigned int tstamp;
int busnum;
char devnum;
char epnum;
char is_in;
char xfertype;
int length; /* Depends on type: xfer length or act length */
int status;
int interval;
@ -121,13 +124,9 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
struct urb *urb, char ev_type, struct mon_bus *mbus)
{
if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S')
return '-';
if (urb->dev->bus->uses_dma &&
(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
}
if (urb->setup_packet == NULL)
return 'Z'; /* '0' would be not as pretty. */
@ -138,14 +137,12 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
int len, char ev_type, struct mon_bus *mbus)
{
int pipe = urb->pipe;
if (len <= 0)
return 'L';
if (len >= DATA_MAX)
len = DATA_MAX;
if (usb_pipein(pipe)) {
if (ep->is_in) {
if (ev_type != 'C')
return '<';
} else {
@ -186,7 +183,7 @@ static inline unsigned int mon_get_timestamp(void)
}
static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
char ev_type)
char ev_type, int status)
{
struct mon_event_text *ep;
unsigned int stamp;
@ -203,24 +200,28 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
}
ep->type = ev_type;
ep->pipe = urb->pipe;
ep->id = (unsigned long) urb;
ep->busnum = urb->dev->bus->busnum;
ep->devnum = urb->dev->devnum;
ep->epnum = usb_endpoint_num(&urb->ep->desc);
ep->xfertype = usb_endpoint_type(&urb->ep->desc);
ep->is_in = usb_urb_dir_in(urb);
ep->tstamp = stamp;
ep->length = (ev_type == 'S') ?
urb->transfer_buffer_length : urb->actual_length;
/* Collecting status makes debugging sense for submits, too */
ep->status = urb->status;
ep->status = status;
if (usb_pipeint(urb->pipe)) {
if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
ep->interval = urb->interval;
} else if (usb_pipeisoc(urb->pipe)) {
} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
ep->interval = urb->interval;
ep->start_frame = urb->start_frame;
ep->error_count = urb->error_count;
}
ep->numdesc = urb->number_of_packets;
if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) {
if (ep->xfertype == USB_ENDPOINT_XFER_ISOC &&
urb->number_of_packets > 0) {
if ((ndesc = urb->number_of_packets) > ISODESC_MAX)
ndesc = ISODESC_MAX;
fp = urb->iso_frame_desc;
@ -247,13 +248,13 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
static void mon_text_submit(void *data, struct urb *urb)
{
struct mon_reader_text *rp = data;
mon_text_event(rp, urb, 'S');
mon_text_event(rp, urb, 'S', -EINPROGRESS);
}
static void mon_text_complete(void *data, struct urb *urb)
static void mon_text_complete(void *data, struct urb *urb, int status)
{
struct mon_reader_text *rp = data;
mon_text_event(rp, urb, 'C');
mon_text_event(rp, urb, 'C', status);
}
static void mon_text_error(void *data, struct urb *urb, int error)
@ -268,9 +269,12 @@ static void mon_text_error(void *data, struct urb *urb, int error)
}
ep->type = 'E';
ep->pipe = urb->pipe;
ep->id = (unsigned long) urb;
ep->busnum = 0;
ep->devnum = urb->dev->devnum;
ep->epnum = usb_endpoint_num(&urb->ep->desc);
ep->xfertype = usb_endpoint_type(&urb->ep->desc);
ep->is_in = usb_urb_dir_in(urb);
ep->tstamp = 0;
ep->length = 0;
ep->status = error;
@ -413,10 +417,10 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf,
mon_text_read_head_u(rp, &ptr, ep);
if (ep->type == 'E') {
mon_text_read_statset(rp, &ptr, ep);
} else if (usb_pipeisoc(ep->pipe)) {
} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
mon_text_read_isostat(rp, &ptr, ep);
mon_text_read_isodesc(rp, &ptr, ep);
} else if (usb_pipeint(ep->pipe)) {
} else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
mon_text_read_intstat(rp, &ptr, ep);
} else {
mon_text_read_statset(rp, &ptr, ep);
@ -468,18 +472,17 @@ static void mon_text_read_head_t(struct mon_reader_text *rp,
{
char udir, utype;
udir = usb_pipein(ep->pipe) ? 'i' : 'o';
switch (usb_pipetype(ep->pipe)) {
case PIPE_ISOCHRONOUS: utype = 'Z'; break;
case PIPE_INTERRUPT: utype = 'I'; break;
case PIPE_CONTROL: utype = 'C'; break;
udir = (ep->is_in ? 'i' : 'o');
switch (ep->xfertype) {
case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break;
case USB_ENDPOINT_XFER_INT: utype = 'I'; break;
case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
default: /* PIPE_BULK */ utype = 'B';
}
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
"%lx %u %c %c%c:%03u:%02u",
ep->id, ep->tstamp, ep->type,
utype, udir,
usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
utype, udir, ep->devnum, ep->epnum);
}
static void mon_text_read_head_u(struct mon_reader_text *rp,
@ -487,18 +490,17 @@ static void mon_text_read_head_u(struct mon_reader_text *rp,
{
char udir, utype;
udir = usb_pipein(ep->pipe) ? 'i' : 'o';
switch (usb_pipetype(ep->pipe)) {
case PIPE_ISOCHRONOUS: utype = 'Z'; break;
case PIPE_INTERRUPT: utype = 'I'; break;
case PIPE_CONTROL: utype = 'C'; break;
udir = (ep->is_in ? 'i' : 'o');
switch (ep->xfertype) {
case USB_ENDPOINT_XFER_ISOC: utype = 'Z'; break;
case USB_ENDPOINT_XFER_INT: utype = 'I'; break;
case USB_ENDPOINT_XFER_CONTROL: utype = 'C'; break;
default: /* PIPE_BULK */ utype = 'B';
}
p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
"%lx %u %c %c%c:%d:%03u:%u",
ep->id, ep->tstamp, ep->type,
utype, udir,
ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
utype, udir, ep->busnum, ep->devnum, ep->epnum);
}
static void mon_text_read_statset(struct mon_reader_text *rp,

View File

@ -46,7 +46,7 @@ struct mon_reader {
void (*rnf_submit)(void *data, struct urb *urb);
void (*rnf_error)(void *data, struct urb *urb, int error);
void (*rnf_complete)(void *data, struct urb *urb);
void (*rnf_complete)(void *data, struct urb *urb, int status);
};
void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);

View File

@ -92,6 +92,16 @@ config USB_SERIAL_BELKIN
To compile this driver as a module, choose M here: the
module will be called belkin_sa.
config USB_SERIAL_CH341
tristate "USB Winchiphead CH341 Single Port Serial Driver"
depends on USB_SERIAL
help
Say Y here if you want to use a Winchiphead CH341 single port
USB to serial adapter.
To compile this driver as a module, choose M here: the
module will be called ch341.
config USB_SERIAL_WHITEHEAT
tristate "USB ConnectTech WhiteHEAT Serial Driver"
depends on USB_SERIAL

View File

@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o
obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o
obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
obj-$(CONFIG_USB_SERIAL_CH341) += ch341.o
obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o
obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o
obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o

View File

@ -172,11 +172,6 @@ static void ark3116_set_termios(struct usb_serial_port *port,
dbg("%s - port %d", __FUNCTION__, port->number);
if (!port->tty || !port->tty->termios) {
dbg("%s - no tty structures", __FUNCTION__);
return;
}
spin_lock_irqsave(&priv->lock, flags);
if (!priv->termios_initialized) {
*(port->tty->termios) = tty_std_termios;

View File

@ -36,6 +36,16 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *dr
return 0;
}
static ssize_t show_port_number(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct usb_serial_port *port = to_usb_serial_port(dev);
return sprintf(buf, "%d\n", port->number - port->serial->minor);
}
static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL);
static int usb_serial_device_probe (struct device *dev)
{
struct usb_serial_driver *driver;
@ -62,6 +72,10 @@ static int usb_serial_device_probe (struct device *dev)
goto exit;
}
retval = device_create_file(dev, &dev_attr_port_number);
if (retval)
goto exit;
minor = port->number;
tty_register_device (usb_serial_tty_driver, minor, dev);
dev_info(&port->serial->dev->dev,
@ -84,6 +98,8 @@ static int usb_serial_device_remove (struct device *dev)
return -ENODEV;
}
device_remove_file(&port->dev, &dev_attr_port_number);
driver = port->serial->type;
if (driver->port_remove) {
if (!try_module_get(driver->driver.owner)) {

354
drivers/usb/serial/ch341.c Normal file
View File

@ -0,0 +1,354 @@
/*
* Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk>
*
* ch341.c implements a serial port driver for the Winchiphead CH341.
*
* The CH341 device can be used to implement an RS232 asynchronous
* serial port, an IEEE-1284 parallel printer port or a memory-like
* interface. In all cases the CH341 supports an I2C interface as well.
* This driver only supports the asynchronous serial interface.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/serial.h>
#define DEFAULT_BAUD_RATE 2400
#define DEFAULT_TIMEOUT 1000
static int debug;
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x4348, 0x5523) },
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
struct ch341_private {
unsigned baud_rate;
u8 dtr;
u8 rts;
};
static int ch341_control_out(struct usb_device *dev, u8 request,
u16 value, u16 index)
{
int r;
dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40,
(int)request, (int)value, (int)index);
r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
value, index, NULL, 0, DEFAULT_TIMEOUT);
return r;
}
static int ch341_control_in(struct usb_device *dev,
u8 request, u16 value, u16 index,
char *buf, unsigned bufsize)
{
int r;
dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40,
(int)request, (int)value, (int)index, buf, (int)bufsize);
r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
value, index, buf, bufsize, DEFAULT_TIMEOUT);
return r;
}
static int ch341_set_baudrate(struct usb_device *dev,
struct ch341_private *priv)
{
short a, b;
int r;
dbg("ch341_set_baudrate(%d)", priv->baud_rate);
switch (priv->baud_rate) {
case 2400:
a = 0xd901;
b = 0x0038;
break;
case 4800:
a = 0x6402;
b = 0x001f;
break;
case 9600:
a = 0xb202;
b = 0x0013;
break;
case 19200:
a = 0xd902;
b = 0x000d;
break;
case 38400:
a = 0x6403;
b = 0x000a;
break;
case 115200:
a = 0xcc03;
b = 0x0008;
break;
default:
return -EINVAL;
}
r = ch341_control_out(dev, 0x9a, 0x1312, a);
if (!r)
r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
return r;
}
static int ch341_set_handshake(struct usb_device *dev,
struct ch341_private *priv)
{
dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts);
return ch341_control_out(dev, 0xa4,
~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0);
}
static int ch341_get_status(struct usb_device *dev)
{
char *buffer;
int r;
const unsigned size = 8;
dbg("ch341_get_status()");
buffer = kmalloc(size, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
if ( r < 0)
goto out;
/* Not having the datasheet for the CH341, we ignore the bytes returned
* from the device. Return error if the device did not respond in time.
*/
r = 0;
out: kfree(buffer);
return r;
}
/* -------------------------------------------------------------------------- */
static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
{
char *buffer;
int r;
const unsigned size = 8;
dbg("ch341_configure()");
buffer = kmalloc(size, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
/* expect two bytes 0x27 0x00 */
r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size);
if (r < 0)
goto out;
r = ch341_control_out(dev, 0xa1, 0, 0);
if (r < 0)
goto out;
r = ch341_set_baudrate(dev, priv);
if (r < 0)
goto out;
/* expect two bytes 0x56 0x00 */
r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size);
if (r < 0)
goto out;
r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050);
if (r < 0)
goto out;
/* expect 0xff 0xee */
r = ch341_get_status(dev);
if (r < 0)
goto out;
r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a);
if (r < 0)
goto out;
r = ch341_set_baudrate(dev, priv);
if (r < 0)
goto out;
r = ch341_set_handshake(dev, priv);
if (r < 0)
goto out;
/* expect 0x9f 0xee */
r = ch341_get_status(dev);
out: kfree(buffer);
return r;
}
/* allocate private data */
static int ch341_attach(struct usb_serial *serial)
{
struct ch341_private *priv;
int r;
dbg("ch341_attach()");
/* private data */
priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->baud_rate = DEFAULT_BAUD_RATE;
priv->dtr = 1;
priv->rts = 1;
r = ch341_configure(serial->dev, priv);
if (r < 0)
goto error;
usb_set_serial_port_data(serial->port[0], priv);
return 0;
error: kfree(priv);
return r;
}
/* open this device, set default parameters */
static int ch341_open(struct usb_serial_port *port, struct file *filp)
{
struct usb_serial *serial = port->serial;
struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
int r;
dbg("ch341_open()");
priv->baud_rate = DEFAULT_BAUD_RATE;
priv->dtr = 1;
priv->rts = 1;
r = ch341_configure(serial->dev, priv);
if (r)
goto out;
r = ch341_set_handshake(serial->dev, priv);
if (r)
goto out;
r = ch341_set_baudrate(serial->dev, priv);
if (r)
goto out;
r = usb_serial_generic_open(port, filp);
out: return r;
}
/* Old_termios contains the original termios settings and
* tty->termios contains the new setting to be used.
*/
static void ch341_set_termios(struct usb_serial_port *port,
struct ktermios *old_termios)
{
struct ch341_private *priv = usb_get_serial_port_data(port);
struct tty_struct *tty = port->tty;
unsigned baud_rate;
dbg("ch341_set_termios()");
if (!tty || !tty->termios)
return;
baud_rate = tty_get_baud_rate(tty);
switch (baud_rate) {
case 2400:
case 4800:
case 9600:
case 19200:
case 38400:
case 115200:
priv->baud_rate = baud_rate;
break;
default:
dbg("Rate %d not supported, using %d",
baud_rate, DEFAULT_BAUD_RATE);
priv->baud_rate = DEFAULT_BAUD_RATE;
}
ch341_set_baudrate(port->serial->dev, priv);
/* Unimplemented:
* (cflag & CSIZE) : data bits [5, 8]
* (cflag & PARENB) : parity {NONE, EVEN, ODD}
* (cflag & CSTOPB) : stop bits [1, 2]
*/
}
static struct usb_driver ch341_driver = {
.name = "ch341",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
.no_dynamic_id = 1,
};
static struct usb_serial_driver ch341_device = {
.driver = {
.owner = THIS_MODULE,
.name = "ch341-uart",
},
.id_table = id_table,
.usb_driver = &ch341_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = 1,
.num_bulk_out = 1,
.num_ports = 1,
.open = ch341_open,
.set_termios = ch341_set_termios,
.attach = ch341_attach,
};
static int __init ch341_init(void)
{
int retval;
retval = usb_serial_register(&ch341_device);
if (retval)
return retval;
retval = usb_register(&ch341_driver);
if (retval)
usb_serial_deregister(&ch341_device);
return retval;
}
static void __exit ch341_exit(void)
{
usb_deregister(&ch341_driver);
usb_serial_deregister(&ch341_device);
}
module_init(ch341_init);
module_exit(ch341_exit);
MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
/* EOF ch341.c */

View File

@ -53,6 +53,7 @@ static void cp2101_shutdown(struct usb_serial*);
static int debug;
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
@ -521,7 +522,7 @@ static void cp2101_set_termios (struct usb_serial_port *port,
dbg("%s - port %d", __FUNCTION__, port->number);
if ((!port->tty) || (!port->tty->termios)) {
if (!port->tty || !port->tty->termios) {
dbg("%s - no tty structures", __FUNCTION__);
return;
}

View File

@ -1169,7 +1169,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
/* XXX see create_sysfs_attrs */
if (priv->chip_type != SIO) {
device_remove_file(&port->dev, &dev_attr_event_char);
if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
if (priv->chip_type == FT232BM ||
priv->chip_type == FT2232C ||
priv->chip_type == FT232RL) {
device_remove_file(&port->dev, &dev_attr_latency_timer);
}
}
@ -2102,6 +2104,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
case FT8U232AM:
case FT232BM:
case FT2232C:
case FT232RL:
/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
format as the data returned from the in point */
if ((ret = usb_control_msg(port->serial->dev,

View File

@ -24,26 +24,6 @@ static struct usb_device_id id_table [] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
static int funsoft_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct ktermios t;
dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd);
if (cmd == TCSETSF) {
if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg))
return -EFAULT;
dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__,
t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
if (!(t.c_lflag & ICANON))
return -EINVAL;
}
return -ENOIOCTLCMD;
}
static struct usb_driver funsoft_driver = {
.name = "funsoft",
.probe = usb_serial_probe,
@ -63,7 +43,6 @@ static struct usb_serial_driver funsoft_device = {
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
.num_ports = 1,
.ioctl = funsoft_ioctl,
};
static int __init funsoft_init(void)

View File

@ -256,6 +256,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */
{ USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
{ USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */
{ USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */
{ USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
@ -646,11 +647,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
kfree(port->bulk_out_buffer);
port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
if (port->bulk_in_buffer == NULL) {
port->bulk_out_buffer = NULL; /* prevent double free */
goto enomem;
}
port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
if (port->bulk_out_buffer == NULL) {
kfree(port->bulk_in_buffer);
port->bulk_in_buffer = NULL;
goto enomem;
}
port->read_urb->transfer_buffer = port->bulk_in_buffer;

View File

@ -728,24 +728,32 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
#endif
}
switch(cflag & CBAUD) {
case B0: /* handled below */
switch(tty_get_baud_rate(port->tty)) {
case 0: /* handled below */
break;
case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200;
case 1200:
priv->cfg.baudrate = kl5kusb105a_sio_b1200;
break;
case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400;
case 2400:
priv->cfg.baudrate = kl5kusb105a_sio_b2400;
break;
case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800;
case 4800:
priv->cfg.baudrate = kl5kusb105a_sio_b4800;
break;
case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600;
case 9600:
priv->cfg.baudrate = kl5kusb105a_sio_b9600;
break;
case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200;
case 19200:
priv->cfg.baudrate = kl5kusb105a_sio_b19200;
break;
case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400;
case 38400:
priv->cfg.baudrate = kl5kusb105a_sio_b38400;
break;
case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600;
case 57600:
priv->cfg.baudrate = kl5kusb105a_sio_b57600;
break;
case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200;
case 115200:
priv->cfg.baudrate = kl5kusb105a_sio_b115200;
break;
default:
err("KLSI USB->Serial converter:"

View File

@ -82,6 +82,7 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear);
static void kobil_read_int_callback( struct urb *urb );
static void kobil_write_callback( struct urb *purb );
static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old);
static struct usb_device_id id_table [] = {
@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = {
.attach = kobil_startup,
.shutdown = kobil_shutdown,
.ioctl = kobil_ioctl,
.set_termios = kobil_set_termios,
.tiocmget = kobil_tiocmget,
.tiocmset = kobil_tiocmset,
.open = kobil_open,
@ -137,7 +139,6 @@ struct kobil_private {
int cur_pos; // index of the next char to send in buf
__u16 device_type;
int line_state;
struct ktermios internal_termios;
};
@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial)
static int kobil_open (struct usb_serial_port *port, struct file *filp)
{
int i, result = 0;
int result = 0;
struct kobil_private *priv;
unsigned char *transfer_buffer;
int transfer_buffer_length = 8;
@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
// set up internal termios structure
priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
for (i=0; i<NCCS; i++) {
priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
}
// allocate memory for transfer buffer
transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
if (! transfer_buffer) {
@ -607,102 +598,79 @@ static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
return (result < 0) ? result : 0;
}
static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg)
static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old)
{
struct kobil_private * priv;
int result;
unsigned short urb_val = 0;
unsigned char *transfer_buffer;
int transfer_buffer_length = 8;
char *settings;
void __user *user_arg = (void __user *)arg;
int c_cflag = port->tty->termios->c_cflag;
speed_t speed;
void * settings;
priv = usb_get_serial_port_data(port);
if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
// This device doesn't support ioctl calls
return 0;
}
return;
switch (cmd) {
case TCGETS: // 0x5401
if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) {
dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
return -EFAULT;
}
if (kernel_termios_to_user_termios((struct ktermios __user *)arg,
&priv->internal_termios))
return -EFAULT;
return 0;
case TCSETS: // 0x5402
if (!(port->tty->termios)) {
dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
return -ENOTTY;
}
if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) {
dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
return -EFAULT;
}
if (user_termios_to_kernel_termios(&priv->internal_termios,
(struct ktermios __user *)arg))
return -EFAULT;
settings = kzalloc(50, GFP_KERNEL);
if (! settings) {
return -ENOBUFS;
}
switch (priv->internal_termios.c_cflag & CBAUD) {
case B1200:
switch (speed = tty_get_baud_rate(port->tty)) {
case 1200:
urb_val = SUSBCR_SBR_1200;
strcat(settings, "1200 ");
break;
case B9600:
case 9600:
default:
urb_val = SUSBCR_SBR_9600;
strcat(settings, "9600 ");
break;
}
}
urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit ");
settings = kzalloc(50, GFP_KERNEL);
if (! settings)
return;
if (priv->internal_termios.c_cflag & PARENB) {
if (priv->internal_termios.c_cflag & PARODD) {
urb_val |= SUSBCR_SPASB_OddParity;
strcat(settings, "Odd Parity");
} else {
urb_val |= SUSBCR_SPASB_EvenParity;
strcat(settings, "Even Parity");
}
sprintf(settings, "%d ", speed);
if (c_cflag & PARENB) {
if (c_cflag & PARODD) {
urb_val |= SUSBCR_SPASB_OddParity;
strcat(settings, "Odd Parity");
} else {
urb_val |= SUSBCR_SPASB_NoParity;
strcat(settings, "No Parity");
urb_val |= SUSBCR_SPASB_EvenParity;
strcat(settings, "Even Parity");
}
dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings );
} else {
urb_val |= SUSBCR_SPASB_NoParity;
strcat(settings, "No Parity");
}
result = usb_control_msg( port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0 ),
SUSBCRequest_SetBaudRateParityAndStopBits,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
urb_val,
0,
settings,
0,
KOBIL_TIMEOUT
);
result = usb_control_msg( port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0 ),
SUSBCRequest_SetBaudRateParityAndStopBits,
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
urb_val,
0,
settings,
0,
KOBIL_TIMEOUT
);
kfree(settings);
}
dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
kfree(settings);
static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
{
struct kobil_private * priv = usb_get_serial_port_data(port);
unsigned char *transfer_buffer;
int transfer_buffer_length = 8;
int result;
if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
// This device doesn't support ioctl calls
return 0;
switch (cmd) {
case TCFLSH: // 0x540B
transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
if (! transfer_buffer) {
if (! transfer_buffer)
return -ENOBUFS;
}
result = usb_control_msg( port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0 ),
@ -716,15 +684,13 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
);
dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
kfree(transfer_buffer);
return ((result < 0) ? -EFAULT : 0);
return (result < 0) ? -EFAULT : 0;
default:
return -ENOIOCTLCMD;
}
return -ENOIOCTLCMD;
}
static int __init kobil_init (void)
{
int retval;

View File

@ -206,20 +206,20 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value
}
} else {
switch (value) {
case 300: break;
case 600: break;
case 1200: break;
case 2400: break;
case 4800: break;
case 9600: break;
case 19200: break;
case 38400: break;
case 57600: break;
case 115200: break;
default:
err("MCT USB-RS232: unsupported baudrate request 0x%x,"
" using default of B9600", value);
value = 9600;
case 300: break;
case 600: break;
case 1200: break;
case 2400: break;
case 4800: break;
case 9600: break;
case 19200: break;
case 38400: break;
case 57600: break;
case 115200: break;
default:
err("MCT USB-RS232: unsupported baudrate request 0x%x,"
" using default of B9600", value);
value = 9600;
}
return 115200/value;
}

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