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: (149 commits)
  USB: ohci-pnx4008: Remove unnecessary cast of return value of kzalloc
  USB: additions to the quirk list
  usb-storage: implement autosuspend
  USB: cdc-acm: add new device id to option driver
  USB: goku_udc trivial cleanups
  USB: usb gadget stack can now -DDEBUG with Kconfig
  usb gadget stack: remove usb_ep_*_buffer(), part 2
  usb gadget stack: remove usb_ep_*_buffer(), part 1
  USB: pxa2xx_udc -- cleanups, mostly removing dma hooks
  USB: pxa2xx_udc: use generic gpio layer
  USB: quirk for samsung printer
  USB: usb/dma doc updates
  USB: drivers/usb/storage/unusual_devs.h whitespace cleanup
  USB: remove Makefile reference to obsolete OHCI_AT91
  USB: io_*: remove bogus termios no change checks
  USB: mos7720: remove bogus no termios change check
  USB: visor and whiteheat: remove bogus termios change checks
  USB: pl2303: remove bogus checks and fix speed support to use tty_get_baud_rate()
  USB: mos7840.c: turn this into a serial driver
  USB: make the usb_device numa_node get assigned from controller
  ...
This commit is contained in:
Linus Torvalds 2007-07-12 16:46:58 -07:00
commit 9374430a52
147 changed files with 14876 additions and 4569 deletions

View file

@ -39,3 +39,16 @@ Description:
If you want to suspend a device immediately but leave it
free to wake up in response to I/O requests, you should
write "0" to power/autosuspend.
What: /sys/bus/usb/devices/.../power/persist
Date: May 2007
KernelVersion: 2.6.23
Contact: Alan Stern <stern@rowland.harvard.edu>
Description:
If CONFIG_USB_PERSIST is set, then each USB device directory
will contain a file named power/persist. The file holds a
boolean value (0 or 1) indicating whether or not the
"USB-Persist" facility is enabled for the device. Since the
facility is inherently dangerous, it is disabled by default
for all devices except hubs. For more information, see
Documentation/usb/persist.txt.

View file

@ -393,6 +393,9 @@ safest thing is to unmount all filesystems on removable media (such USB,
Firewire, CompactFlash, MMC, external SATA, or even IDE hotplug bays)
before suspending; then remount them after resuming.
There is a work-around for this problem. For more information, see
Documentation/usb/persist.txt.
Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were
compiled with the similar configuration files. Anyway I found that
suspend to disk (and resume) is much slower on 2.6.16 compared to

View file

@ -32,12 +32,15 @@ ELIMINATING COPIES
It's good to avoid making CPUs copy data needlessly. The costs can add up,
and effects like cache-trashing can impose subtle penalties.
- When you're allocating a buffer for DMA purposes anyway, use the buffer
primitives. Think of them as kmalloc and kfree that give you the right
kind of addresses to store in urb->transfer_buffer and urb->transfer_dma,
while guaranteeing that no hidden copies through DMA "bounce" buffers will
slow things down. You'd also set URB_NO_TRANSFER_DMA_MAP in
urb->transfer_flags:
- If you're doing lots of small data transfers from the same buffer all
the time, that can really burn up resources on systems which use an
IOMMU to manage the DMA mappings. It can cost MUCH more to set up and
tear down the IOMMU mappings with each request than perform the I/O!
For those specific cases, USB has primitives to allocate less expensive
memory. They work like kmalloc and kfree versions that give you the right
kind of addresses to store in urb->transfer_buffer and urb->transfer_dma.
You'd also set URB_NO_TRANSFER_DMA_MAP in urb->transfer_flags:
void *usb_buffer_alloc (struct usb_device *dev, size_t size,
int mem_flags, dma_addr_t *dma);
@ -45,6 +48,10 @@ and effects like cache-trashing can impose subtle penalties.
void usb_buffer_free (struct usb_device *dev, size_t size,
void *addr, dma_addr_t dma);
Most drivers should *NOT* be using these primitives; they don't need
to use this type of memory ("dma-coherent"), and memory returned from
kmalloc() will work just fine.
For control transfers you can use the buffer primitives or not for each
of the transfer buffer and setup buffer independently. Set the flag bits
URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP to indicate which
@ -54,29 +61,39 @@ and effects like cache-trashing can impose subtle penalties.
The memory buffer returned is "dma-coherent"; sometimes you might need to
force a consistent memory access ordering by using memory barriers. It's
not using a streaming DMA mapping, so it's good for small transfers on
systems where the I/O would otherwise tie up an IOMMU mapping. (See
systems where the I/O would otherwise thrash an IOMMU mapping. (See
Documentation/DMA-mapping.txt for definitions of "coherent" and "streaming"
DMA mappings.)
Asking for 1/Nth of a page (as well as asking for N pages) is reasonably
space-efficient.
On most systems the memory returned will be uncached, because the
semantics of dma-coherent memory require either bypassing CPU caches
or using cache hardware with bus-snooping support. While x86 hardware
has such bus-snooping, many other systems use software to flush cache
lines to prevent DMA conflicts.
- Devices on some EHCI controllers could handle DMA to/from high memory.
Driver probe() routines can notice this using a generic DMA call, then
tell higher level code (network, scsi, etc) about it like this:
if (dma_supported (&intf->dev, 0xffffffffffffffffULL))
net->features |= NETIF_F_HIGHDMA;
Unfortunately, the current Linux DMA infrastructure doesn't have a sane
way to expose these capabilities ... and in any case, HIGHMEM is mostly a
design wart specific to x86_32. So your best bet is to ensure you never
pass a highmem buffer into a USB driver. That's easy; it's the default
behavior. Just don't override it; e.g. with NETIF_F_HIGHDMA.
That can eliminate dma bounce buffering of requests that originate (or
terminate) in high memory, in cases where the buffers aren't allocated
with usb_buffer_alloc() but instead are dma-mapped.
This may force your callers to do some bounce buffering, copying from
high memory to "normal" DMA memory. If you can come up with a good way
to fix this issue (for x86_32 machines with over 1 GByte of memory),
feel free to submit patches.
WORKING WITH EXISTING BUFFERS
Existing buffers aren't usable for DMA without first being mapped into the
DMA address space of the device.
DMA address space of the device. However, most buffers passed to your
driver can safely be used with such DMA mapping. (See the first section
of DMA-mapping.txt, titled "What memory is DMA-able?")
- When you're using scatterlists, you can map everything at once. On some
systems, this kicks in an IOMMU and turns the scatterlists into single
@ -114,3 +131,8 @@ DMA address space of the device.
The calls manage urb->transfer_dma for you, and set URB_NO_TRANSFER_DMA_MAP
so that usbcore won't map or unmap the buffer. The same goes for
urb->setup_dma and URB_NO_SETUP_DMA_MAP for control requests.
Note that several of those interfaces are currently commented out, since
they don't have current users. See the source code. Other than the dmasync
calls (where the underlying DMA primitives have changed), most of them can
easily be commented back in if you want to use them.

View file

@ -0,0 +1,156 @@
USB device persistence during system suspend
Alan Stern <stern@rowland.harvard.edu>
September 2, 2006 (Updated May 29, 2007)
What is the problem?
According to the USB specification, when a USB bus is suspended the
bus must continue to supply suspend current (around 1-5 mA). This
is so that devices can maintain their internal state and hubs can
detect connect-change events (devices being plugged in or unplugged).
The technical term is "power session".
If a USB device's power session is interrupted then the system is
required to behave as though the device has been unplugged. It's a
conservative approach; in the absence of suspend current the computer
has no way to know what has actually happened. Perhaps the same
device is still attached or perhaps it was removed and a different
device plugged into the port. The system must assume the worst.
By default, Linux behaves according to the spec. If a USB host
controller loses power during a system suspend, then when the system
wakes up all the devices attached to that controller are treated as
though they had disconnected. This is always safe and it is the
"officially correct" thing to do.
For many sorts of devices this behavior doesn't matter in the least.
If the kernel wants to believe that your USB keyboard was unplugged
while the system was asleep and a new keyboard was plugged in when the
system woke up, who cares? It'll still work the same when you type on
it.
Unfortunately problems _can_ arise, particularly with mass-storage
devices. The effect is exactly the same as if the device really had
been unplugged while the system was suspended. If you had a mounted
filesystem on the device, you're out of luck -- everything in that
filesystem is now inaccessible. This is especially annoying if your
root filesystem was located on the device, since your system will
instantly crash.
Loss of power isn't the only mechanism to worry about. Anything that
interrupts a power session will have the same effect. For example,
even though suspend current may have been maintained while the system
was asleep, on many systems during the initial stages of wakeup the
firmware (i.e., the BIOS) resets the motherboard's USB host
controllers. Result: all the power sessions are destroyed and again
it's as though you had unplugged all the USB devices. Yes, it's
entirely the BIOS's fault, but that doesn't do _you_ any good unless
you can convince the BIOS supplier to fix the problem (lots of luck!).
On many systems the USB host controllers will get reset after a
suspend-to-RAM. On almost all systems, no suspend current is
available during hibernation (also known as swsusp or suspend-to-disk).
You can check the kernel log after resuming to see if either of these
has happened; look for lines saying "root hub lost power or was reset".
In practice, people are forced to unmount any filesystems on a USB
device before suspending. If the root filesystem is on a USB device,
the system can't be suspended at all. (All right, it _can_ be
suspended -- but it will crash as soon as it wakes up, which isn't
much better.)
What is the solution?
Setting CONFIG_USB_PERSIST will cause the kernel to work around these
issues. It enables a mode in which the core USB device data
structures are allowed to persist across a power-session disruption.
It works like this. If the kernel sees that a USB host controller is
not in the expected state during resume (i.e., if the controller was
reset or otherwise had lost power) then it applies a persistence check
to each of the USB devices below that controller for which the
"persist" attribute is set. It doesn't try to resume the device; that
can't work once the power session is gone. Instead it issues a USB
port reset and then re-enumerates the device. (This is exactly the
same thing that happens whenever a USB device is reset.) If the
re-enumeration shows that the device now attached to that port has the
same descriptors as before, including the Vendor and Product IDs, then
the kernel continues to use the same device structure. In effect, the
kernel treats the device as though it had merely been reset instead of
unplugged.
If no device is now attached to the port, or if the descriptors are
different from what the kernel remembers, then the treatment is what
you would expect. The kernel destroys the old device structure and
behaves as though the old device had been unplugged and a new device
plugged in, just as it would without the CONFIG_USB_PERSIST option.
The end result is that the USB device remains available and usable.
Filesystem mounts and memory mappings are unaffected, and the world is
now a good and happy place.
Note that even when CONFIG_USB_PERSIST is set, the "persist" feature
will be applied only to those devices for which it is enabled. You
can enable the feature by doing (as root):
echo 1 >/sys/bus/usb/devices/.../power/persist
where the "..." should be filled in the with the device's ID. Disable
the feature by writing 0 instead of 1. For hubs the feature is
automatically and permanently enabled, so you only have to worry about
setting it for devices where it really matters.
Is this the best solution?
Perhaps not. Arguably, keeping track of mounted filesystems and
memory mappings across device disconnects should be handled by a
centralized Logical Volume Manager. Such a solution would allow you
to plug in a USB flash device, create a persistent volume associated
with it, unplug the flash device, plug it back in later, and still
have the same persistent volume associated with the device. As such
it would be more far-reaching than CONFIG_USB_PERSIST.
On the other hand, writing a persistent volume manager would be a big
job and using it would require significant input from the user. This
solution is much quicker and easier -- and it exists now, a giant
point in its favor!
Furthermore, the USB_PERSIST option applies to _all_ USB devices, not
just mass-storage devices. It might turn out to be equally useful for
other device types, such as network interfaces.
WARNING: Using CONFIG_USB_PERSIST can be dangerous!!
When recovering an interrupted power session the kernel does its best
to make sure the USB device hasn't been changed; that is, the same
device is still plugged into the port as before. But the checks
aren't guaranteed to be 100% accurate.
If you replace one USB device with another of the same type (same
manufacturer, same IDs, and so on) there's an excellent chance the
kernel won't detect the change. Serial numbers and other strings are
not compared. In many cases it wouldn't help if they were, because
manufacturers frequently omit serial numbers entirely in their
devices.
Furthermore it's quite possible to leave a USB device exactly the same
while changing its media. If you replace the flash memory card in a
USB card reader while the system is asleep, the kernel will have no
way to know you did it. The kernel will assume that nothing has
happened and will continue to use the partition tables, inodes, and
memory mappings for the old card.
If the kernel gets fooled in this way, it's almost certain to cause
data corruption and to crash your system. You'll have no one to blame
but yourself.
YOU HAVE BEEN WARNED! USE AT YOUR OWN RISK!
That having been said, most of the time there shouldn't be any trouble
at all. The "persist" feature can be extremely useful. Make the most
of it.

View file

@ -3724,12 +3724,12 @@ L: netdev@vger.kernel.org
W: http://pegasus2.sourceforge.net/
S: Maintained
USB PRINTER DRIVER
P: Vojtech Pavlik
M: vojtech@suse.cz
USB PRINTER DRIVER (usblp)
P: Pete Zaitcev
M: zaitcev@redhat.com
L: linux-usb-users@lists.sourceforge.net
L: linux-usb-devel@lists.sourceforge.net
S: Maintained
S: Supported
USB RTL8150 DRIVER
P: Petko Manolov

View file

@ -1547,10 +1547,8 @@ static void ub_reset_enter(struct ub_dev *sc, int try)
#endif
#if 0 /* We let them stop themselves. */
struct list_head *p;
struct ub_lun *lun;
list_for_each(p, &sc->luns) {
lun = list_entry(p, struct ub_lun, link);
list_for_each_entry(lun, &sc->luns, link) {
blk_stop_queue(lun->disk->queue);
}
#endif
@ -1562,7 +1560,6 @@ static void ub_reset_task(struct work_struct *work)
{
struct ub_dev *sc = container_of(work, struct ub_dev, reset_work);
unsigned long flags;
struct list_head *p;
struct ub_lun *lun;
int lkr, rc;
@ -1608,8 +1605,7 @@ static void ub_reset_task(struct work_struct *work)
spin_lock_irqsave(sc->lock, flags);
sc->reset = 0;
tasklet_schedule(&sc->tasklet);
list_for_each(p, &sc->luns) {
lun = list_entry(p, struct ub_lun, link);
list_for_each_entry(lun, &sc->luns, link) {
blk_start_queue(lun->disk->queue);
}
wake_up(&sc->reset_wait);
@ -2348,7 +2344,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
static void ub_disconnect(struct usb_interface *intf)
{
struct ub_dev *sc = usb_get_intfdata(intf);
struct list_head *p;
struct ub_lun *lun;
unsigned long flags;
@ -2403,8 +2398,7 @@ static void ub_disconnect(struct usb_interface *intf)
/*
* Unregister the upper layer.
*/
list_for_each (p, &sc->luns) {
lun = list_entry(p, struct ub_lun, link);
list_for_each_entry(lun, &sc->luns, link) {
del_gendisk(lun->disk);
/*
* I wish I could do:

View file

@ -1009,20 +1009,22 @@ static int hid_resume(struct usb_interface *intf)
}
/* Treat USB reset pretty much the same as suspend/resume */
static void hid_pre_reset(struct usb_interface *intf)
static int hid_pre_reset(struct usb_interface *intf)
{
/* FIXME: What if the interface is already suspended? */
hid_suspend(intf, PMSG_ON);
return 0;
}
static void hid_post_reset(struct usb_interface *intf)
/* Same routine used for post_reset and reset_resume */
static int hid_post_reset(struct usb_interface *intf)
{
struct usb_device *dev = interface_to_usbdev (intf);
hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
/* FIXME: Any more reinitialization needed? */
hid_resume(intf);
return hid_resume(intf);
}
static struct usb_device_id hid_usb_ids [] = {
@ -1039,6 +1041,7 @@ static struct usb_driver hid_driver = {
.disconnect = hid_disconnect,
.suspend = hid_suspend,
.resume = hid_resume,
.reset_resume = hid_post_reset,
.pre_reset = hid_pre_reset,
.post_reset = hid_post_reset,
.id_table = hid_usb_ids,

View file

@ -2,9 +2,12 @@
# USB device configuration
#
menu "USB support"
menuconfig USB_SUPPORT
bool "USB support"
depends on HAS_IOMEM
if USB_SUPPORT
# Host-side USB depends on having a host controller
# NOTE: dummy_hcd is always an option, but it's ignored here ...
# NOTE: SL-811 option should be board-specific ...
@ -12,6 +15,7 @@ config USB_ARCH_HAS_HCD
boolean
default y if USB_ARCH_HAS_OHCI
default y if USB_ARCH_HAS_EHCI
default y if PCMCIA # sl811_cs
default y if ARM # SL-811
default PCI
@ -130,5 +134,4 @@ source "drivers/usb/atm/Kconfig"
source "drivers/usb/gadget/Kconfig"
endmenu
endif # USB_SUPPORT

View file

@ -15,7 +15,7 @@ obj-$(CONFIG_USB_OHCI_HCD) += host/
obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_OHCI_AT91) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_ACM) += class/
obj-$(CONFIG_USB_PRINTER) += class/

View file

@ -171,7 +171,7 @@ struct cxacru_data {
struct delayed_work poll_work;
u32 card_info[CXINF_MAX];
struct mutex poll_state_serialize;
int poll_state;
enum cxacru_poll_state poll_state;
/* contol handles */
struct mutex cm_serialize;
@ -226,58 +226,48 @@ static ssize_t cxacru_sysfs_showattr_s8(s8 value, char *buf)
static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf)
{
if (unlikely(value < 0)) {
return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
value / 100, -value % 100);
} else {
return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
value / 100, value % 100);
}
value / 100, abs(value) % 100);
}
static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf)
{
switch (value) {
case 0: return snprintf(buf, PAGE_SIZE, "no\n");
case 1: return snprintf(buf, PAGE_SIZE, "yes\n");
default: return 0;
}
static char *str[] = { "no", "yes" };
if (unlikely(value >= ARRAY_SIZE(str)))
return snprintf(buf, PAGE_SIZE, "%u\n", value);
return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
}
static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf)
{
switch (value) {
case 1: return snprintf(buf, PAGE_SIZE, "not connected\n");
case 2: return snprintf(buf, PAGE_SIZE, "connected\n");
case 3: return snprintf(buf, PAGE_SIZE, "lost\n");
default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
}
static char *str[] = { NULL, "not connected", "connected", "lost" };
if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL))
return snprintf(buf, PAGE_SIZE, "%u\n", value);
return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
}
static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf)
{
switch (value) {
case 0: return snprintf(buf, PAGE_SIZE, "down\n");
case 1: return snprintf(buf, PAGE_SIZE, "attempting to activate\n");
case 2: return snprintf(buf, PAGE_SIZE, "training\n");
case 3: return snprintf(buf, PAGE_SIZE, "channel analysis\n");
case 4: return snprintf(buf, PAGE_SIZE, "exchange\n");
case 5: return snprintf(buf, PAGE_SIZE, "up\n");
case 6: return snprintf(buf, PAGE_SIZE, "waiting\n");
case 7: return snprintf(buf, PAGE_SIZE, "initialising\n");
default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
}
static char *str[] = { "down", "attempting to activate",
"training", "channel analysis", "exchange", "up",
"waiting", "initialising"
};
if (unlikely(value >= ARRAY_SIZE(str)))
return snprintf(buf, PAGE_SIZE, "%u\n", value);
return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
}
static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
{
switch (value) {
case 0: return 0;
case 1: return snprintf(buf, PAGE_SIZE, "ANSI T1.413\n");
case 2: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.1 (G.DMT)\n");
case 3: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.2 (G.LITE)\n");
default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
}
static char *str[] = {
NULL,
"ANSI T1.413",
"ITU-T G.992.1 (G.DMT)",
"ITU-T G.992.2 (G.LITE)"
};
if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL))
return snprintf(buf, PAGE_SIZE, "%u\n", value);
return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
}
/*
@ -308,11 +298,10 @@ static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
struct cxacru_data *instance = usbatm_instance->driver_data;
u32 value = instance->card_info[CXINF_LINE_STARTABLE];
switch (value) {
case 0: return snprintf(buf, PAGE_SIZE, "running\n");
case 1: return snprintf(buf, PAGE_SIZE, "stopped\n");
default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
}
static char *str[] = { "running", "stopped" };
if (unlikely(value >= ARRAY_SIZE(str)))
return snprintf(buf, PAGE_SIZE, "%u\n", value);
return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
}
static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,

View file

@ -1157,6 +1157,9 @@ static struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
{ USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
{ USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},

View file

@ -1,5 +1,5 @@
/*
* usblp.c Version 0.13
* usblp.c
*
* Copyright (c) 1999 Michael Gee <michael@linuxspecific.com>
* Copyright (c) 1999 Pavel Machek <pavel@suse.cz>
@ -61,11 +61,11 @@
/*
* Version Information
*/
#define DRIVER_VERSION "v0.13"
#define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
#define DRIVER_DESC "USB Printer Device Class driver"
#define USBLP_BUF_SIZE 8192
#define USBLP_BUF_SIZE_IN 1024
#define USBLP_DEVICE_ID_SIZE 1024
/* ioctls: */
@ -127,14 +127,22 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
*/
#define STATUS_BUF_SIZE 8
/*
* Locks down the locking order:
* ->wmut locks wstatus.
* ->mut locks the whole usblp, except [rw]complete, and thus, by indirection,
* [rw]status. We only touch status when we know the side idle.
* ->lock locks what interrupt accesses.
*/
struct usblp {
struct usb_device *dev; /* USB device */
struct mutex mut; /* locks this struct, especially "dev" */
char *writebuf; /* write transfer_buffer */
struct mutex wmut;
struct mutex mut;
spinlock_t lock; /* locks rcomplete, wcomplete */
char *readbuf; /* read transfer_buffer */
char *statusbuf; /* status transfer_buffer */
struct urb *readurb, *writeurb; /* The urbs */
wait_queue_head_t wait; /* Zzzzz ... */
struct usb_anchor urbs;
wait_queue_head_t rwait, wwait;
int readcount; /* Counter for reads */
int ifnum; /* Interface number */
struct usb_interface *intf; /* The interface */
@ -147,8 +155,9 @@ struct usblp {
} protocol[USBLP_MAX_PROTOCOLS];
int current_protocol;
int minor; /* minor number of device */
int wcomplete; /* writing is completed */
int rcomplete; /* reading is completed */
int wcomplete, rcomplete;
int wstatus; /* bytes written or error */
int rstatus; /* bytes ready or error */
unsigned int quirks; /* quirks flags */
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
@ -166,9 +175,6 @@ static void usblp_dump(struct usblp *usblp) {
dbg("dev=0x%p", usblp->dev);
dbg("present=%d", usblp->present);
dbg("readbuf=0x%p", usblp->readbuf);
dbg("writebuf=0x%p", usblp->writebuf);
dbg("readurb=0x%p", usblp->readurb);
dbg("writeurb=0x%p", usblp->writeurb);
dbg("readcount=%d", usblp->readcount);
dbg("ifnum=%d", usblp->ifnum);
for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
@ -178,8 +184,8 @@ static void usblp_dump(struct usblp *usblp) {
}
dbg("current_protocol=%d", usblp->current_protocol);
dbg("minor=%d", usblp->minor);
dbg("wcomplete=%d", usblp->wcomplete);
dbg("rcomplete=%d", usblp->rcomplete);
dbg("wstatus=%d", usblp->wstatus);
dbg("rstatus=%d", usblp->rstatus);
dbg("quirks=%d", usblp->quirks);
dbg("used=%d", usblp->used);
dbg("bidir=%d", usblp->bidir);
@ -222,6 +228,11 @@ static const struct quirk_printer_struct quirk_printers[] = {
{ 0, 0 }
};
static int usblp_wwait(struct usblp *usblp, int nonblock);
static int usblp_wtest(struct usblp *usblp, int nonblock);
static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock);
static int usblp_rtest(struct usblp *usblp, int nonblock);
static int usblp_submit_read(struct usblp *usblp);
static int usblp_select_alts(struct usblp *usblp);
static int usblp_set_protocol(struct usblp *usblp, int protocol);
static int usblp_cache_device_id_string(struct usblp *usblp);
@ -279,33 +290,47 @@ static void usblp_bulk_read(struct urb *urb)
{
struct usblp *usblp = urb->context;
if (unlikely(!usblp || !usblp->dev || !usblp->used))
return;
if (unlikely(!usblp->present))
goto unplug;
if (unlikely(urb->status))
warn("usblp%d: nonzero read/write bulk status received: %d",
if (usblp->present && usblp->used) {
if (urb->status)
printk(KERN_WARNING "usblp%d: "
"nonzero read bulk status received: %d\n",
usblp->minor, urb->status);
}
spin_lock(&usblp->lock);
if (urb->status < 0)
usblp->rstatus = urb->status;
else
usblp->rstatus = urb->actual_length;
usblp->rcomplete = 1;
unplug:
wake_up_interruptible(&usblp->wait);
wake_up(&usblp->rwait);
spin_unlock(&usblp->lock);
usb_free_urb(urb);
}
static void usblp_bulk_write(struct urb *urb)
{
struct usblp *usblp = urb->context;
if (unlikely(!usblp || !usblp->dev || !usblp->used))
return;
if (unlikely(!usblp->present))
goto unplug;
if (unlikely(urb->status))
warn("usblp%d: nonzero read/write bulk status received: %d",
if (usblp->present && usblp->used) {
if (urb->status)
printk(KERN_WARNING "usblp%d: "
"nonzero write bulk status received: %d\n",
usblp->minor, urb->status);
}
spin_lock(&usblp->lock);
if (urb->status < 0)
usblp->wstatus = urb->status;
else
usblp->wstatus = urb->actual_length;
usblp->wcomplete = 1;
unplug:
wake_up_interruptible(&usblp->wait);
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);
}
/*
@ -322,7 +347,8 @@ static int usblp_check_status(struct usblp *usblp, int err)
error = usblp_read_status (usblp, usblp->statusbuf);
if (error < 0) {
if (printk_ratelimit())
err("usblp%d: error %d reading printer status",
printk(KERN_ERR
"usblp%d: error %d reading printer status\n",
usblp->minor, error);
return 0;
}
@ -336,8 +362,10 @@ static int usblp_check_status(struct usblp *usblp, int err)
if (~status & LP_PSELECD)
newerr = 2;
if (newerr != err)
info("usblp%d: %s", usblp->minor, usblp_messages[newerr]);
if (newerr != err) {
printk(KERN_INFO "usblp%d: %s\n",
usblp->minor, usblp_messages[newerr]);
}
return newerr;
}
@ -345,12 +373,9 @@ static int usblp_check_status(struct usblp *usblp, int err)
static int handle_bidir (struct usblp *usblp)
{
if (usblp->bidir && usblp->used && !usblp->sleeping) {
usblp->readcount = 0;
usblp->readurb->dev = usblp->dev;
if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0)
if (usblp_submit_read(usblp) < 0)
return -EIO;
}
return 0;
}
@ -403,11 +428,9 @@ static int usblp_open(struct inode *inode, struct file *file)
usblp->used = 1;
file->private_data = usblp;
usblp->writeurb->transfer_buffer_length = 0;
usblp->wcomplete = 1; /* we begin writeable */
usblp->wstatus = 0;
usblp->rcomplete = 0;
usblp->writeurb->status = 0;
usblp->readurb->status = 0;
if (handle_bidir(usblp) < 0) {
usblp->used = 0;
@ -421,20 +444,17 @@ static int usblp_open(struct inode *inode, struct file *file)
static void usblp_cleanup (struct usblp *usblp)
{
info("usblp%d: removed", usblp->minor);
printk(KERN_INFO "usblp%d: removed\n", usblp->minor);
kfree(usblp->readbuf);
kfree (usblp->device_id_string);
kfree (usblp->statusbuf);
usb_free_urb(usblp->writeurb);
usb_free_urb(usblp->readurb);
kfree (usblp);
}
static void usblp_unlink_urbs(struct usblp *usblp)
{
usb_kill_urb(usblp->writeurb);
if (usblp->bidir)
usb_kill_urb(usblp->readurb);
usb_kill_anchored_urbs(&usblp->urbs);
}
static int usblp_release(struct inode *inode, struct file *file)
@ -455,10 +475,18 @@ static int usblp_release(struct inode *inode, struct file *file)
/* No kernel lock - fine */
static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
{
int ret;
unsigned long flags;
struct usblp *usblp = file->private_data;
poll_wait(file, &usblp->wait, wait);
return ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN | POLLRDNORM)
/* Should we check file->f_mode & FMODE_WRITE before poll_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);
spin_unlock_irqrestore(&usblp->lock, flags);
return ret;
}
static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@ -632,10 +660,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
switch (cmd) {
case LPGETSTATUS:
if (usblp_read_status(usblp, usblp->statusbuf)) {
if ((retval = usblp_read_status(usblp, usblp->statusbuf))) {
if (printk_ratelimit())
err("usblp%d: failed reading printer status",
usblp->minor);
printk(KERN_ERR "usblp%d:"
"failed reading printer status (%d)\n",
usblp->minor, retval);
retval = -EIO;
goto done;
}
@ -656,160 +685,136 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
int timeout, intr, rv, err = 0, transfer_length = 0;
size_t writecount = 0;
char *writebuf;
struct urb *writeurb;
int rv;
int transfer_length;
ssize_t writecount = 0;
if (mutex_lock_interruptible(&usblp->wmut)) {
rv = -EINTR;
goto raise_biglock;
}
if ((rv = usblp_wwait(usblp, !!(file->f_flags & O_NONBLOCK))) < 0)
goto raise_wait;
while (writecount < count) {
if (!usblp->wcomplete) {
barrier();
if (file->f_flags & O_NONBLOCK) {
writecount += transfer_length;
return writecount ? writecount : -EAGAIN;
}
timeout = USBLP_WRITE_TIMEOUT;
rv = wait_event_interruptible_timeout(usblp->wait, usblp->wcomplete || !usblp->present , timeout);
if (rv < 0)
return writecount ? writecount : -EINTR;
}
intr = mutex_lock_interruptible (&usblp->mut);
if (intr)
return writecount ? writecount : -EINTR;
if (!usblp->present) {
mutex_unlock (&usblp->mut);
return -ENODEV;
}
if (usblp->sleeping) {
mutex_unlock (&usblp->mut);
return writecount ? writecount : -ENODEV;
}
if (usblp->writeurb->status != 0) {
if (usblp->quirks & USBLP_QUIRK_BIDIR) {
if (!usblp->wcomplete)
err("usblp%d: error %d writing to printer",
usblp->minor, usblp->writeurb->status);
err = usblp->writeurb->status;
} else
err = usblp_check_status(usblp, err);
mutex_unlock (&usblp->mut);
/* if the fault was due to disconnect, let khubd's
* call to usblp_disconnect() grab usblp->mut ...
/*
* Step 1: Submit next block.
*/
schedule ();
continue;
}
/* We must increment writecount here, and not at the
* end of the loop. Otherwise, the final loop iteration may
* be skipped, leading to incomplete printer output.
*/
writecount += transfer_length;
if (writecount == count) {
mutex_unlock(&usblp->mut);
break;
}
transfer_length=(count - writecount);
if (transfer_length > USBLP_BUF_SIZE)
if ((transfer_length = count - writecount) > USBLP_BUF_SIZE)
transfer_length = USBLP_BUF_SIZE;
usblp->writeurb->transfer_buffer_length = transfer_length;
rv = -ENOMEM;
if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
goto raise_buf;
if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == 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(usblp->writeurb->transfer_buffer,
if (copy_from_user(writebuf,
buffer + writecount, transfer_length)) {
mutex_unlock(&usblp->mut);
return writecount ? writecount : -EFAULT;
rv = -EFAULT;
goto raise_badaddr;
}
usblp->writeurb->dev = usblp->dev;
spin_lock_irq(&usblp->lock);
usblp->wcomplete = 0;
err = usb_submit_urb(usblp->writeurb, GFP_KERNEL);
if (err) {
spin_unlock_irq(&usblp->lock);
if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
usblp->wstatus = 0;
spin_lock_irq(&usblp->lock);
usblp->wcomplete = 1;
if (err != -ENOMEM)
count = -EIO;
else
count = writecount ? writecount : -ENOMEM;
mutex_unlock (&usblp->mut);
break;
}
mutex_unlock (&usblp->mut);
wake_up(&usblp->wwait);
spin_unlock_irq(&usblp->lock);
if (rv != -ENOMEM)
rv = -EIO;
goto raise_submit;
}
return count;
/*
* Step 2: Wait for transfer to end, collect results.
*/
rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK));
if (rv < 0) {
/*
* If interrupted, we simply leave the URB to dangle,
* so the ->release will call usb_kill_urb().
*/
goto collect_error;
}
static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
if (usblp->wstatus < 0) {
usblp_check_status(usblp, 0);
rv = -EIO;
goto collect_error;
}
/*
* This is critical: it must be our URB, not other writer's.
* The wmut exists mainly to cover us here.
*/
writecount += usblp->wstatus;
}
mutex_unlock(&usblp->wmut);
return writecount;
raise_submit:
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);
raise_biglock:
return writecount ? writecount : rv;
}
/*
* Notice that we fail to restart in a few cases: on EFAULT, on restart
* error, etc. This is the historical behaviour. In all such cases we return
* EIO, and applications loop in order to get the new read going.
*/
static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, loff_t *ppos)
{
struct usblp *usblp = file->private_data;
int rv, intr;
ssize_t count;
ssize_t avail;
int rv;
if (!usblp->bidir)
return -EINVAL;
intr = mutex_lock_interruptible (&usblp->mut);
if (intr)
return -EINTR;
if (!usblp->present) {
count = -ENODEV;
goto done;
}
rv = usblp_rwait_and_lock(usblp, !!(file->f_flags & O_NONBLOCK));
if (rv < 0)
return rv;
if (!usblp->rcomplete) {
barrier();
if (file->f_flags & O_NONBLOCK) {
count = -EAGAIN;
goto done;
}
mutex_unlock(&usblp->mut);
rv = wait_event_interruptible(usblp->wait, usblp->rcomplete || !usblp->present);
mutex_lock(&usblp->mut);
if (rv < 0) {
count = -EINTR;
goto done;
}
}
if (!usblp->present) {
count = -ENODEV;
goto done;
}
if (usblp->sleeping) {
count = -ENODEV;
goto done;
}
if (usblp->readurb->status) {
err("usblp%d: error %d reading from printer",
usblp->minor, usblp->readurb->status);
usblp->readurb->dev = usblp->dev;
usblp->readcount = 0;
usblp->rcomplete = 0;
if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0)
dbg("error submitting urb");
if ((avail = usblp->rstatus) < 0) {
printk(KERN_ERR "usblp%d: error %d reading from printer\n",
usblp->minor, (int)avail);
usblp_submit_read(usblp);
count = -EIO;
goto done;
}
count = count < usblp->readurb->actual_length - usblp->readcount ?
count : usblp->readurb->actual_length - usblp->readcount;
if (copy_to_user(buffer, usblp->readurb->transfer_buffer + usblp->readcount, count)) {
count = len < avail - usblp->readcount ? len : avail - usblp->readcount;
if (count != 0 &&
copy_to_user(buffer, usblp->readbuf + usblp->readcount, count)) {
count = -EFAULT;
goto done;
}
if ((usblp->readcount += count) == usblp->readurb->actual_length) {
usblp->readcount = 0;
usblp->readurb->dev = usblp->dev;
usblp->rcomplete = 0;
if (usb_submit_urb(usblp->readurb, GFP_KERNEL)) {
if ((usblp->readcount += count) == avail) {
if (usblp_submit_read(usblp) < 0) {
/* We don't want to leak USB return codes into errno. */
if (count == 0)
count = -EIO;
goto done;
}
@ -820,6 +825,165 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
return count;
}
/*
* Wait for the write path to come idle.
* This is called under the ->wmut, so the idle path stays idle.
*
* Our write path has a peculiar property: it does not buffer like a tty,
* but waits for the write to succeed. This allows our ->release to bug out
* without waiting for writes to drain. But it obviously does not work
* 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;
add_wait_queue(&usblp->wwait, &waita);
for (;;) {
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;
}
mutex_unlock(&usblp->mut);
if (rc == 0)
break;
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&usblp->wwait, &waita);
return rc;
}
static int usblp_wtest(struct usblp *usblp, int nonblock)
{
unsigned long flags;
if (!usblp->present)
return -ENODEV;
if (signal_pending(current))
return -EINTR;
spin_lock_irqsave(&usblp->lock, flags);
if (usblp->wcomplete) {
spin_unlock_irqrestore(&usblp->lock, flags);
return 0;
}
spin_unlock_irqrestore(&usblp->lock, flags);
if (usblp->sleeping)
return -ENODEV;
if (nonblock)
return -EAGAIN;
return 1;
}
/*
* Wait for read bytes to become available. This probably should have been
* called usblp_r_lock_and_wait(), because we lock first. But it's a traditional
* name for functions which lock and return.
*
* We do not use wait_event_interruptible because it makes locking iffy.
*/
static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock)
{
DECLARE_WAITQUEUE(waita, current);
int rc;
add_wait_queue(&usblp->rwait, &waita);
for (;;) {
if (mutex_lock_interruptible(&usblp->mut)) {
rc = -EINTR;
break;
}
set_current_state(TASK_INTERRUPTIBLE);
if ((rc = usblp_rtest(usblp, nonblock)) < 0) {
mutex_unlock(&usblp->mut);
break;
}
if (rc == 0) /* Keep it locked */
break;
mutex_unlock(&usblp->mut);
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&usblp->rwait, &waita);
return rc;
}
static int usblp_rtest(struct usblp *usblp, int nonblock)
{
unsigned long flags;
if (!usblp->present)
return -ENODEV;
if (signal_pending(current))
return -EINTR;
spin_lock_irqsave(&usblp->lock, flags);
if (usblp->rcomplete) {
spin_unlock_irqrestore(&usblp->lock, flags);
return 0;
}
spin_unlock_irqrestore(&usblp->lock, flags);
if (usblp->sleeping)
return -ENODEV;
if (nonblock)
return -EAGAIN;
return 1;
}
/*
* Please check ->bidir and other such things outside for now.
*/
static int usblp_submit_read(struct usblp *usblp)
{
struct urb *urb;
unsigned long flags;
int rc;
rc = -ENOMEM;
if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
goto raise_urb;
usb_fill_bulk_urb(urb, usblp->dev,
usb_rcvbulkpipe(usblp->dev,
usblp->protocol[usblp->current_protocol].epread->bEndpointAddress),
usblp->readbuf, USBLP_BUF_SIZE_IN,
usblp_bulk_read, usblp);
usb_anchor_urb(urb, &usblp->urbs);
spin_lock_irqsave(&usblp->lock, flags);
usblp->readcount = 0; /* XXX Why here? */
usblp->rcomplete = 0;
spin_unlock_irqrestore(&usblp->lock, flags);
if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
dbg("error submitting urb (%d)", rc);
spin_lock_irqsave(&usblp->lock, flags);
usblp->rstatus = rc;
usblp->rcomplete = 1;
spin_unlock_irqrestore(&usblp->lock, flags);
goto raise_submit;
}
return 0;
raise_submit:
usb_unanchor_urb(urb);
usb_free_urb(urb);
raise_urb:
return rc;
}
/*
* Checks for printers that have quirks, such as requiring unidirectional
* communication but reporting bidirectional; currently some HP printers
@ -891,55 +1055,41 @@ static int usblp_probe(struct usb_interface *intf,
/* Malloc and start initializing usblp structure so we can use it
* directly. */
if (!(usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL))) {
err("out of memory for usblp");
retval = -ENOMEM;
goto abort;
}
usblp->dev = dev;
mutex_init(&usblp->wmut);
mutex_init (&usblp->mut);
init_waitqueue_head(&usblp->wait);
spin_lock_init(&usblp->lock);
init_waitqueue_head(&usblp->rwait);
init_waitqueue_head(&usblp->wwait);
init_usb_anchor(&usblp->urbs);
usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
usblp->intf = intf;
usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
if (!usblp->writeurb) {
err("out of memory");
goto abort;
}
usblp->readurb = usb_alloc_urb(0, GFP_KERNEL);
if (!usblp->readurb) {
err("out of memory");
goto abort;
}
/* Malloc device ID string buffer to the largest expected length,
* since we can re-query it on an ioctl and a dynamic string
* could change in length. */
if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) {
err("out of memory for device_id_string");
retval = -ENOMEM;
goto abort;
}
usblp->writebuf = usblp->readbuf = NULL;
usblp->writeurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
usblp->readurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
/* Malloc write & read buffers. We somewhat wastefully
/*
* Allocate read buffer. We somewhat wastefully
* malloc both regardless of bidirectionality, because the
* alternate setting can be changed later via an ioctl. */
if (!(usblp->writebuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
GFP_KERNEL, &usblp->writeurb->transfer_dma))) {
err("out of memory for write buf");
goto abort;
}
if (!(usblp->readbuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
GFP_KERNEL, &usblp->readurb->transfer_dma))) {
err("out of memory for read buf");
* alternate setting can be changed later via an ioctl.
*/
if (!(usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL))) {
retval = -ENOMEM;
goto abort;
}
/* Allocate buffer for printer status */
usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
if (!usblp->statusbuf) {
err("out of memory for statusbuf");
retval = -ENOMEM;
goto abort;
}
@ -954,12 +1104,15 @@ static int usblp_probe(struct usb_interface *intf,
dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
retval = -ENODEV;
goto abort;
}
/* Setup the selected alternate setting and endpoints. */
if (usblp_set_protocol(usblp, protocol) < 0)
if (usblp_set_protocol(usblp, protocol) < 0) {
retval = -ENODEV; /* ->probe isn't ->ioctl */
goto abort;
}
/* Retrieve and store the device ID string. */
usblp_cache_device_id_string(usblp);
@ -977,12 +1130,14 @@ static int usblp_probe(struct usb_interface *intf,
retval = usb_register_dev(intf, &usblp_class);
if (retval) {
err("Not able to get a minor for this device.");
printk(KERN_ERR "usblp: Not able to get a minor"
" (base %u, slice default): %d\n",
USBLP_MINOR_BASE, retval);
goto abort_intfdata;
}
usblp->minor = intf->minor;
info("usblp%d: USB %sdirectional printer dev %d "
"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X",
printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d "
"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n",
usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
usblp->ifnum,
usblp->protocol[usblp->current_protocol].alt_setting,
@ -997,19 +1152,12 @@ static int usblp_probe(struct usb_interface *intf,
device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
abort:
if (usblp) {
if (usblp->writebuf)
usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
usblp->writebuf, usblp->writeurb->transfer_dma);
if (usblp->readbuf)
usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
usblp->readbuf, usblp->readurb->transfer_dma);
kfree(usblp->readbuf);
kfree(usblp->statusbuf);
kfree(usblp->device_id_string);
usb_free_urb(usblp->writeurb);
usb_free_urb(usblp->readurb);
kfree(usblp);
}
return -EIO;
return retval;
}
/*
@ -1078,8 +1226,9 @@ static int usblp_select_alts(struct usblp *usblp)
if (ifd->desc.bInterfaceProtocol == 1) {
epread = NULL;
} else if (usblp->quirks & USBLP_QUIRK_BIDIR) {
info("Disabling reads from problem bidirectional "
"printer on usblp%d", usblp->minor);
printk(KERN_INFO "usblp%d: Disabling reads from "
"problematic bidirectional printer\n",
usblp->minor);
epread = NULL;
}
@ -1119,25 +1268,12 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol)
return -EINVAL;
r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
if (r < 0) {
err("can't set desired altsetting %d on interface %d",
printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
alts, usblp->ifnum);
return r;
}
usb_fill_bulk_urb(usblp->writeurb, usblp->dev,
usb_sndbulkpipe(usblp->dev,
usblp->protocol[protocol].epwrite->bEndpointAddress),
usblp->writebuf, 0,
usblp_bulk_write, usblp);
usblp->bidir = (usblp->protocol[protocol].epread != NULL);
if (usblp->bidir)
usb_fill_bulk_urb(usblp->readurb, usblp->dev,
usb_rcvbulkpipe(usblp->dev,
usblp->protocol[protocol].epread->bEndpointAddress),
usblp->readbuf, USBLP_BUF_SIZE,
usblp_bulk_read, usblp);
usblp->current_protocol = protocol;
dbg("usblp%d set protocol %d", usblp->minor, protocol);
return 0;
@ -1190,13 +1326,11 @@ static void usblp_disconnect(struct usb_interface *intf)
mutex_lock (&usblp_mutex);
mutex_lock (&usblp->mut);
usblp->present = 0;
wake_up(&usblp->wwait);
wake_up(&usblp->rwait);
usb_set_intfdata (intf, NULL);
usblp_unlink_urbs(usblp);
usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
usblp->writebuf, usblp->writeurb->transfer_dma);
usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
usblp->readbuf, usblp->readurb->transfer_dma);
mutex_unlock (&usblp->mut);
if (!usblp->used)
@ -1211,6 +1345,11 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
/* we take no more IO */
usblp->sleeping = 1;
usblp_unlink_urbs(usblp);
#if 0 /* XXX Do we want this? What if someone is reading, should we fail? */
/* not strictly necessary, but just in case */
wake_up(&usblp->wwait);
wake_up(&usblp->rwait);
#endif
return 0;
}
@ -1251,12 +1390,7 @@ static struct usb_driver usblp_driver = {
static int __init usblp_init(void)
{
int retval;
retval = usb_register(&usblp_driver);
if (!retval)
info(DRIVER_VERSION ": " DRIVER_DESC);
return retval;
return usb_register(&usblp_driver);
}
static void __exit usblp_exit(void)

View file

@ -86,6 +86,31 @@ config USB_SUSPEND
If you are unsure about this, say N here.
config USB_PERSIST
bool "USB device persistence during system suspend (DANGEROUS)"
depends on USB && PM && EXPERIMENTAL
default n
help
If you say Y here and enable the "power/persist" attribute
for a USB device, the device's data structures will remain
persistent across system suspend, even if the USB bus loses
power. (This includes hibernation, also known as swsusp or
suspend-to-disk.) The devices will reappear as if by magic
when the system wakes up, with no need to unmount USB
filesystems, rmmod host-controller drivers, or do anything
else.
WARNING: This option can be dangerous!
If a USB device is replaced by another of the same type while
the system is asleep, there's a good chance the kernel won't
detect the change. Likewise if the media in a USB storage
device is replaced. When this happens it's almost certain to
cause data corruption and maybe even crash your system.
If you are unsure, say N here.
config USB_OTG
bool
depends on USB && EXPERIMENTAL

View file

@ -85,14 +85,20 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
memcpy(&endpoint->desc, d, n);
INIT_LIST_HEAD(&endpoint->urb_list);
/* If the bInterval value is outside the legal range,
* set it to a default value: 32 ms */
/* Fix up bInterval values outside the legal range. Use 32 ms if no
* proper value can be guessed. */
i = 0; /* i = min, j = max, n = default */
j = 255;
if (usb_endpoint_xfer_int(d)) {
i = 1;
switch (to_usb_device(ddev)->speed) {
case USB_SPEED_HIGH:
/* Many device manufacturers are using full-speed
* bInterval values in high-speed interrupt endpoint
* descriptors. Try to fix those and fall back to a
* 32 ms default value otherwise. */
n = fls(d->bInterval*8);
if (n == 0)
n = 9; /* 32 ms = 2^(9-1) uframes */
j = 16;
break;
@ -124,6 +130,21 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
endpoint->desc.bInterval = n;
}
/* Some buggy low-speed devices have Bulk endpoints, which is
* explicitly forbidden by the USB spec. In an attempt to make
* them usable, we will try treating them as Interrupt endpoints.
*/
if (to_usb_device(ddev)->speed == USB_SPEED_LOW &&
usb_endpoint_xfer_bulk(d)) {
dev_warn(ddev, "config %d interface %d altsetting %d "
"endpoint 0x%X is Bulk; changing to Interrupt\n",
cfgno, inum, asnum, d->bEndpointAddress);
endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
endpoint->desc.bInterval = 1;
if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8)
endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
}
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the next endpoint or interface descriptor */
endpoint->extra = buffer;
@ -274,6 +295,7 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
struct usb_descriptor_header *header;
int len, retval;
u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];
unsigned iad_num = 0;
memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
if (config->desc.bDescriptorType != USB_DT_CONFIG ||
@ -351,6 +373,20 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
++n;
}
} else if (header->bDescriptorType ==
USB_DT_INTERFACE_ASSOCIATION) {
if (iad_num == USB_MAXIADS) {
dev_warn(ddev, "found more Interface "
"Association Descriptors "
"than allocated for in "
"configuration %d\n", cfgno);
} else {
config->intf_assoc[iad_num] =
(struct usb_interface_assoc_descriptor
*)header;
iad_num++;
}
} else if (header->bDescriptorType == USB_DT_DEVICE ||
header->bDescriptorType == USB_DT_CONFIG)
dev_warn(ddev, "config %d contains an unexpected "

View file

@ -102,6 +102,10 @@ static const char *format_config =
/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
"C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
static const char *format_iad =
/* A: FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */
"A: FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
static const char *format_iface =
/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
"I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
@ -146,6 +150,7 @@ static const struct class_info clas_info[] =
{USB_CLASS_STILL_IMAGE, "still"},
{USB_CLASS_CSCID, "scard"},
{USB_CLASS_CONTENT_SEC, "c-sec"},
{USB_CLASS_VIDEO, "video"},
{-1, "unk."} /* leave as last */
};
@ -286,6 +291,21 @@ static char *usb_dump_interface(
return start;
}
static char *usb_dump_iad_descriptor(char *start, char *end,
const struct usb_interface_assoc_descriptor *iad)
{
if (start > end)
return start;
start += sprintf(start, format_iad,
iad->bFirstInterface,
iad->bInterfaceCount,
iad->bFunctionClass,
class_decode(iad->bFunctionClass),
iad->bFunctionSubClass,
iad->bFunctionProtocol);
return start;
}
/* TBD:
* 0. TBDs
* 1. marking active interface altsettings (code lists all, but should mark
@ -322,6 +342,12 @@ static char *usb_dump_config (
if (!config) /* getting these some in 2.3.7; none in 2.3.6 */
return start + sprintf(start, "(null Cfg. desc.)\n");
start = usb_dump_config_descriptor(start, end, &config->desc, active);
for (i = 0; i < USB_MAXIADS; i++) {
if (config->intf_assoc[i] == NULL)
break;
start = usb_dump_iad_descriptor(start, end,
config->intf_assoc[i]);
}
for (i = 0; i < config->desc.bNumInterfaces; i++) {
intfc = config->intf_cache[i];
interface = config->interface[i];

View file

@ -24,10 +24,19 @@
#include <linux/device.h>
#include <linux/usb.h>
#include <linux/usb/quirks.h>
#include <linux/workqueue.h>
#include "hcd.h"
#include "usb.h"
#define VERBOSE_DEBUG 0
#if VERBOSE_DEBUG
#define dev_vdbg dev_dbg
#else
#define dev_vdbg(dev, fmt, args...) do { } while (0)
#endif
#ifdef CONFIG_HOTPLUG
/*
@ -802,18 +811,17 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
udev->state == USB_STATE_SUSPENDED)
goto done;
/* For devices that don't have a driver, we do a standard suspend. */
if (udev->dev.driver == NULL) {
udev->do_remote_wakeup = 0;
status = usb_port_suspend(udev);
goto done;
}
/* For devices that don't have a driver, we do a generic suspend. */
if (udev->dev.driver)
udriver = to_usb_device_driver(udev->dev.driver);
else {
udev->do_remote_wakeup = 0;
udriver = &usb_generic_driver;
}
status = udriver->suspend(udev, msg);
done:
// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
if (status == 0)
udev->dev.power.power_state.event = msg.event;
return status;
@ -825,8 +833,9 @@ static int usb_resume_device(struct usb_device *udev)
struct usb_device_driver *udriver;
int status = 0;
if (udev->state == USB_STATE_NOTATTACHED ||
udev->state != USB_STATE_SUSPENDED)
if (udev->state == USB_STATE_NOTATTACHED)
goto done;
if (udev->state != USB_STATE_SUSPENDED && !udev->reset_resume)
goto done;
/* Can't resume it if it doesn't have a driver. */
@ -835,11 +844,14 @@ static int usb_resume_device(struct usb_device *udev)
goto done;
}
if (udev->quirks & USB_QUIRK_RESET_RESUME)
udev->reset_resume = 1;
udriver = to_usb_device_driver(udev->dev.driver);
status = udriver->resume(udev);
done:
// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
if (status == 0) {
udev->autoresume_disabled = 0;
udev->dev.power.power_state.event = PM_EVENT_ON;
@ -878,14 +890,12 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
}
done:
// dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
if (status == 0)
intf->dev.power.power_state.event = msg.event;
dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
return status;
}
/* Caller has locked intf's usb_device's pm_mutex */
static int usb_resume_interface(struct usb_interface *intf)
static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
{
struct usb_driver *driver;
int status = 0;
@ -905,23 +915,37 @@ static int usb_resume_interface(struct usb_interface *intf)
}
driver = to_usb_driver(intf->dev.driver);
if (reset_resume) {
if (driver->reset_resume) {
status = driver->reset_resume(intf);
if (status)
dev_err(&intf->dev, "%s error %d\n",
"reset_resume", status);
} else {
// status = -EOPNOTSUPP;
dev_warn(&intf->dev, "no %s for driver %s?\n",
"reset_resume", driver->name);
}
} else {
if (driver->resume) {
status = driver->resume(intf);
if (status)
dev_err(&intf->dev, "%s error %d\n",
"resume", status);
else
mark_active(intf);
} else {
dev_warn(&intf->dev, "no resume for driver %s?\n",
driver->name);
mark_active(intf);
// status = -EOPNOTSUPP;
dev_warn(&intf->dev, "no %s for driver %s?\n",
"resume", driver->name);
}
}
done:
// dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
if (status == 0)
intf->dev.power.power_state.event = PM_EVENT_ON;
mark_active(intf);
/* FIXME: Unbind the driver and reprobe if the resume failed
* (not possible if auto_pm is set) */
return status;
}
@ -958,6 +982,18 @@ static int autosuspend_check(struct usb_device *udev)
"for autosuspend\n");
return -EOPNOTSUPP;
}
/* Don't allow autosuspend if the device will need
* a reset-resume and any of its interface drivers
* doesn't include support.
*/
if (udev->quirks & USB_QUIRK_RESET_RESUME) {
struct usb_driver *driver;
driver = to_usb_driver(intf->dev.driver);
if (!driver->reset_resume)
return -EOPNOTSUPP;
}
}
}
@ -974,7 +1010,7 @@ static int autosuspend_check(struct usb_device *udev)
* or for the past.
*/
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
suspend_time - jiffies);
round_jiffies_relative(suspend_time - jiffies));
}
return -EAGAIN;
}
@ -1054,14 +1090,21 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
break;
}
}
if (status == 0)
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;
status = usb_suspend_device(udev, msg);
}
/* If the suspend failed, resume interfaces that did get suspended */
if (status != 0) {
while (--i >= 0) {
intf = udev->actconfig->interface[i];
usb_resume_interface(intf);
usb_resume_interface(intf, 0);
}
/* Try another autosuspend when the interfaces aren't busy */
@ -1076,7 +1119,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
}
done:
// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
return status;
}
@ -1131,7 +1174,8 @@ static int usb_resume_both(struct usb_device *udev)
status = usb_autoresume_device(parent);
if (status == 0) {
status = usb_resume_device(udev);
if (status) {
if (status || udev->state ==
USB_STATE_NOTATTACHED) {
usb_autosuspend_device(parent);
/* It's possible usb_resume_device()
@ -1152,28 +1196,25 @@ static int usb_resume_both(struct usb_device *udev)
/* We can't progagate beyond the USB subsystem,
* so if a root hub's controller is suspended
* then we're stuck. */
if (udev->dev.parent->power.power_state.event !=
PM_EVENT_ON)
status = -EHOSTUNREACH;
else
status = usb_resume_device(udev);
}
} else {
/* Needed only for setting udev->dev.power.power_state.event
* and for possible debugging message. */
/* Needed for setting udev->dev.power.power_state.event,
* for possible debugging message, and for reset_resume. */
status = usb_resume_device(udev);
}
if (status == 0 && udev->actconfig) {
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
intf = udev->actconfig->interface[i];
usb_resume_interface(intf);
usb_resume_interface(intf, udev->reset_resume);
}
}
done:
// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
udev->reset_resume = 0;
return status;
}
@ -1240,8 +1281,8 @@ void usb_autosuspend_device(struct usb_device *udev)
int status;
status = usb_autopm_do_device(udev, -1);
// dev_dbg(&udev->dev, "%s: cnt %d\n",
// __FUNCTION__, udev->pm_usage_cnt);
dev_vdbg(&udev->dev, "%s: cnt %d\n",
__FUNCTION__, udev->pm_usage_cnt);
}
/**
@ -1260,8 +1301,8 @@ void usb_autosuspend_device(struct usb_device *udev)
void usb_try_autosuspend_device(struct usb_device *udev)
{
usb_autopm_do_device(udev, 0);
// dev_dbg(&udev->dev, "%s: cnt %d\n",
// __FUNCTION__, udev->pm_usage_cnt);
dev_vdbg(&udev->dev, "%s: cnt %d\n",
__FUNCTION__, udev->pm_usage_cnt);
}
/**
@ -1288,8 +1329,8 @@ int usb_autoresume_device(struct usb_device *udev)
int status;
status = usb_autopm_do_device(udev, 1);
// dev_dbg(&udev->dev, "%s: status %d cnt %d\n",
// __FUNCTION__, status, udev->pm_usage_cnt);
dev_vdbg(&udev->dev, "%s: status %d cnt %d\n",
__FUNCTION__, status, udev->pm_usage_cnt);
return status;
}
@ -1361,8 +1402,8 @@ void usb_autopm_put_interface(struct usb_interface *intf)
int status;
status = usb_autopm_do_interface(intf, -1);
// dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
// __FUNCTION__, status, intf->pm_usage_cnt);
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
__FUNCTION__, status, intf->pm_usage_cnt);
}
EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
@ -1405,8 +1446,8 @@ int usb_autopm_get_interface(struct usb_interface *intf)
int status;
status = usb_autopm_do_interface(intf, 1);
// dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
// __FUNCTION__, status, intf->pm_usage_cnt);
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
__FUNCTION__, status, intf->pm_usage_cnt);
return status;
}
EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
@ -1427,8 +1468,8 @@ int usb_autopm_set_interface(struct usb_interface *intf)
int status;
status = usb_autopm_do_interface(intf, 0);
// dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
// __FUNCTION__, status, intf->pm_usage_cnt);
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
__FUNCTION__, status, intf->pm_usage_cnt);
return status;
}
EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
@ -1508,8 +1549,15 @@ static int usb_resume(struct device *dev)
if (!is_usb_device(dev)) /* Ignore PM for interfaces */
return 0;
udev = to_usb_device(dev);
if (udev->autoresume_disabled)
/* 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->reset_resume && udev->do_remote_wakeup))
return -EPERM;
}
return usb_external_resume_device(udev);
}

View file

@ -16,15 +16,15 @@
*/
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/rwsem.h>
#include <linux/usb.h>
#include "usb.h"
#define MAX_USB_MINORS 256
static const struct file_operations *usb_minors[MAX_USB_MINORS];
static DEFINE_SPINLOCK(minor_lock);
static DECLARE_RWSEM(minor_rwsem);
static int usb_open(struct inode * inode, struct file * file)
{
@ -33,14 +33,11 @@ static int usb_open(struct inode * inode, struct file * file)
int err = -ENODEV;
const struct file_operations *old_fops, *new_fops = NULL;
spin_lock (&minor_lock);
down_read(&minor_rwsem);
c = usb_minors[minor];
if (!c || !(new_fops = fops_get(c))) {
spin_unlock(&minor_lock);
return err;
}
spin_unlock(&minor_lock);
if (!c || !(new_fops = fops_get(c)))
goto done;
old_fops = file->f_op;
file->f_op = new_fops;
@ -52,6 +49,8 @@ static int usb_open(struct inode * inode, struct file * file)
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
done:
up_read(&minor_rwsem);
return err;
}
@ -166,7 +165,7 @@ int usb_register_dev(struct usb_interface *intf,
if (class_driver->fops == NULL)
goto exit;
spin_lock (&minor_lock);
down_write(&minor_rwsem);
for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
if (usb_minors[minor])
continue;
@ -176,7 +175,7 @@ int usb_register_dev(struct usb_interface *intf,
retval = 0;
break;
}
spin_unlock (&minor_lock);
up_write(&minor_rwsem);
if (retval)
goto exit;
@ -197,9 +196,9 @@ int usb_register_dev(struct usb_interface *intf,
intf->usb_dev = device_create(usb_class->class, &intf->dev,
MKDEV(USB_MAJOR, minor), "%s", temp);
if (IS_ERR(intf->usb_dev)) {
spin_lock (&minor_lock);
down_write(&minor_rwsem);
usb_minors[intf->minor] = NULL;
spin_unlock (&minor_lock);
up_write(&minor_rwsem);
retval = PTR_ERR(intf->usb_dev);
}
exit:
@ -236,9 +235,9 @@ void usb_deregister_dev(struct usb_interface *intf,
dbg ("removing %d minor", intf->minor);
spin_lock (&minor_lock);
down_write(&minor_rwsem);
usb_minors[intf->minor] = NULL;
spin_unlock (&minor_lock);
up_write(&minor_rwsem);
snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
@ -247,5 +246,3 @@ void usb_deregister_dev(struct usb_interface *intf,
destroy_usb_class();
}
EXPORT_SYMBOL(usb_deregister_dev);

View file

@ -19,6 +19,7 @@
#include <linux/usb.h>
#include "usb.h"
#include "hcd.h"
static inline const char *plural(int n)
{
@ -193,16 +194,34 @@ static void generic_disconnect(struct usb_device *udev)
static int generic_suspend(struct usb_device *udev, pm_message_t msg)
{
/* USB devices enter SUSPEND state through their hubs, but can be
* marked for FREEZE as soon as their children are already idled.
* But those semantics are useless, so we equate the two (sigh).
int rc;
/* Normal USB devices suspend through their upstream port.
* Root hubs don't have upstream ports to suspend,
* so we have to shut down their downstream HC-to-USB
* interfaces manually by doing a bus (or "global") suspend.
*/
return usb_port_suspend(udev);
if (!udev->parent)
rc = hcd_bus_suspend(udev);
else
rc = usb_port_suspend(udev);
return rc;
}
static int generic_resume(struct usb_device *udev)
{
return usb_port_resume(udev);
int rc;
/* Normal USB devices resume/reset through their upstream port.
* Root hubs don't have upstream ports to resume or reset,
* so we have to start up their downstream HC-to-USB
* interfaces manually by doing a bus (or "global") resume.
*/
if (!udev->parent)
rc = hcd_bus_resume(udev);
else
rc = usb_port_resume(udev);
return rc;
}
#endif /* CONFIG_PM */

View file

@ -207,7 +207,8 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
* We must ignore the FREEZE vs SUSPEND distinction here, because
* otherwise the swsusp will save (and restore) garbage state.
*/
if (hcd->self.root_hub->dev.power.power_state.event == PM_EVENT_ON)
if (!(hcd->state == HC_STATE_SUSPENDED ||
hcd->state == HC_STATE_HALT))
return -EBUSY;
if (hcd->driver->suspend) {

View file

@ -582,10 +582,12 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
}
/* The USB 2.0 spec says 256 ms. This is close enough and won't
* exceed that limit if HZ is 100. */
* exceed that limit if HZ is 100. The math is more clunky than
* maybe expected, this is to make sure that all timers for USB devices
* fire at the same time to give the CPU a break inbetween */
if (hcd->uses_new_polling ? hcd->poll_rh :
(length == 0 && hcd->status_urb != NULL))
mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250));
mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
}
EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status);
@ -614,8 +616,8 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
urb->hcpriv = hcd; /* indicate it's queued */
if (!hcd->uses_new_polling)
mod_timer (&hcd->rh_timer, jiffies +
msecs_to_jiffies(250));
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)
@ -901,17 +903,32 @@ EXPORT_SYMBOL (usb_calc_bus_time);
/*-------------------------------------------------------------------------*/
static void urb_unlink (struct urb *urb)
static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
{
unsigned long flags;
int at_root_hub = (urb->dev == hcd->self.root_hub);
/* clear all state linking urb to this dev (and hcd) */
spin_lock_irqsave (&hcd_data_lock, flags);
list_del_init (&urb->urb_list);
spin_unlock_irqrestore (&hcd_data_lock, flags);
}
if (hcd->self.uses_dma && !at_root_hub) {
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
@ -948,19 +965,9 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
else switch (hcd->state) {
case HC_STATE_RUNNING:
case HC_STATE_RESUMING:
doit:
list_add_tail (&urb->urb_list, &ep->urb_list);
status = 0;
break;
case HC_STATE_SUSPENDED:
/* HC upstream links (register access, wakeup signaling) can work
* even when the downstream links (and DMA etc) are quiesced; let
* usbcore talk to the root hub.
*/
if (hcd->self.controller->power.power_state.event == PM_EVENT_ON
&& urb->dev->parent == NULL)
goto doit;
/* FALL THROUGH */
default:
status = -ESHUTDOWN;
break;
@ -1014,7 +1021,7 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
done:
if (unlikely (status)) {
urb_unlink (urb);
urb_unlink(hcd, urb);
atomic_dec (&urb->use_count);
if (urb->reject)
wake_up (&usb_kill_urb_queue);
@ -1255,41 +1262,58 @@ void usb_hcd_endpoint_disable (struct usb_device *udev,
#ifdef CONFIG_PM
int hcd_bus_suspend (struct usb_bus *bus)
int hcd_bus_suspend(struct usb_device *rhdev)
{
struct usb_hcd *hcd;
struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
int status;
int old_state = hcd->state;
hcd = container_of (bus, struct usb_hcd, self);
if (!hcd->driver->bus_suspend)
return -ENOENT;
dev_dbg(&rhdev->dev, "bus %s%s\n",
rhdev->auto_pm ? "auto-" : "", "suspend");
if (!hcd->driver->bus_suspend) {
status = -ENOENT;
} else {
hcd->state = HC_STATE_QUIESCING;
status = hcd->driver->bus_suspend(hcd);
if (status == 0)
}
if (status == 0) {
usb_set_device_state(rhdev, USB_STATE_SUSPENDED);
hcd->state = HC_STATE_SUSPENDED;
else
dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n",
} else {
hcd->state = old_state;
dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
"suspend", status);
}
return status;
}
int hcd_bus_resume (struct usb_bus *bus)
int hcd_bus_resume(struct usb_device *rhdev)
{
struct usb_hcd *hcd;
struct usb_hcd *hcd = container_of(rhdev->bus, struct usb_hcd, self);
int status;
int old_state = hcd->state;
hcd = container_of (bus, struct usb_hcd, self);
dev_dbg(&rhdev->dev, "usb %s%s\n",
rhdev->auto_pm ? "auto-" : "", "resume");
if (!hcd->driver->bus_resume)
return -ENOENT;
if (hcd->state == HC_STATE_RUNNING)
return 0;
hcd->state = HC_STATE_RESUMING;
status = hcd->driver->bus_resume(hcd);
if (status == 0)
if (status == 0) {
/* TRSMRCY = 10 msec */
msleep(10);
usb_set_device_state(rhdev, rhdev->actconfig
? USB_STATE_CONFIGURED
: USB_STATE_ADDRESS);
hcd->state = HC_STATE_RUNNING;
else {
dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n",
} else {
hcd->state = old_state;
dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
"resume", status);
if (status != -ESHUTDOWN)
usb_hc_died(hcd);
}
return status;
@ -1384,30 +1408,10 @@ EXPORT_SYMBOL (usb_bus_start_enum);
*/
void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
{
int at_root_hub;
at_root_hub = (urb->dev == hcd->self.root_hub);
urb_unlink (urb);
/* lower level hcd code should use *_dma exclusively if the
* host controller does DMA */
if (hcd->self.uses_dma && !at_root_hub) {
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);
}
urb_unlink(hcd, urb);
usbmon_urb_complete (&hcd->self, urb);
usb_unanchor_urb(urb);
/* pass ownership to the completion handler */
urb->complete (urb);
atomic_dec (&urb->use_count);

View file

@ -364,23 +364,13 @@ extern int usb_find_interface_driver (struct usb_device *dev,
#ifdef CONFIG_PM
extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
extern void usb_root_hub_lost_power (struct usb_device *rhdev);
extern int hcd_bus_suspend (struct usb_bus *bus);
extern int hcd_bus_resume (struct usb_bus *bus);
extern int hcd_bus_suspend(struct usb_device *rhdev);
extern int hcd_bus_resume(struct usb_device *rhdev);
#else
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
{
return;
}
static inline int hcd_bus_suspend(struct usb_bus *bus)
{
return 0;
}
static inline int hcd_bus_resume (struct usb_bus *bus)
{
return 0;
}
#endif /* CONFIG_PM */
/*

View file

@ -31,9 +31,16 @@
#include "hcd.h"
#include "hub.h"
#ifdef CONFIG_USB_PERSIST
#define USB_PERSIST 1
#else
#define USB_PERSIST 0
#endif
struct usb_hub {
struct device *intfdev; /* the "interface" device */
struct usb_device *hdev;
struct kref kref;
struct urb *urb; /* for interrupt polling pipe */
/* buffer for urb ... with extra space in case of babble */
@ -66,6 +73,7 @@ struct usb_hub {
unsigned limited_power:1;
unsigned quiescing:1;
unsigned activating:1;
unsigned disconnected:1;
unsigned has_indicators:1;
u8 indicator[USB_MAXCHILDREN];
@ -321,7 +329,7 @@ static void kick_khubd(struct usb_hub *hub)
to_usb_interface(hub->intfdev)->pm_usage_cnt = 1;
spin_lock_irqsave(&hub_event_lock, flags);
if (list_empty(&hub->event_list)) {
if (!hub->disconnected & list_empty(&hub->event_list)) {
list_add_tail(&hub->event_list, &hub_event_list);
wake_up(&khubd_wait);
}
@ -330,6 +338,7 @@ static void kick_khubd(struct usb_hub *hub)
void usb_kick_khubd(struct usb_device *hdev)
{
/* FIXME: What if hdev isn't bound to the hub driver? */
kick_khubd(hdev_to_hub(hdev));
}
@ -400,9 +409,10 @@ static void hub_tt_kevent (struct work_struct *work)
struct usb_hub *hub =
container_of(work, struct usb_hub, tt.kevent);
unsigned long flags;
int limit = 100;
spin_lock_irqsave (&hub->tt.lock, flags);
while (!list_empty (&hub->tt.clear_list)) {
while (--limit && !list_empty (&hub->tt.clear_list)) {
struct list_head *temp;
struct usb_tt_clear *clear;
struct usb_device *hdev = hub->hdev;
@ -550,48 +560,68 @@ static int hub_hub_status(struct usb_hub *hub,
static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
{
struct usb_device *hdev = hub->hdev;
int ret;
int ret = 0;
if (hdev->children[port1-1] && set_state) {
if (hdev->children[port1-1] && set_state)
usb_set_device_state(hdev->children[port1-1],
USB_STATE_NOTATTACHED);
}
if (!hub->error)
ret = clear_port_feature(hdev, port1, USB_PORT_FEAT_ENABLE);
if (ret)
dev_err(hub->intfdev, "cannot disable port %d (err = %d)\n",
port1, ret);
return ret;
}
/*
* Disable a port and mark a logical connnect-change event, so that some
* time later khubd will disconnect() any existing usb_device on the port
* and will re-enumerate if there actually is a device attached.
*/
static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
{
dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1);
hub_port_disable(hub, port1, 1);
/* FIXME let caller ask to power down the port:
* - some devices won't enumerate without a VBUS power cycle
* - SRP saves power that way
* - ... new call, TBD ...
* That's easy if this hub can switch power per-port, and
* khubd reactivates the port later (timer, SRP, etc).
* Powerdown must be optional, because of reset/DFU.
*/
set_bit(port1, hub->change_bits);
kick_khubd(hub);
}
/* caller has locked the hub device */
static void hub_pre_reset(struct usb_interface *intf)
static int hub_pre_reset(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata(intf);
struct usb_device *hdev = hub->hdev;
int port1;
int i;
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
if (hdev->children[port1 - 1]) {
usb_disconnect(&hdev->children[port1 - 1]);
if (hub->error == 0)
hub_port_disable(hub, port1, 0);
}
/* Disconnect all the children */
for (i = 0; i < hdev->maxchild; ++i) {
if (hdev->children[i])
usb_disconnect(&hdev->children[i]);
}
hub_quiesce(hub);
return 0;
}
/* caller has locked the hub device */
static void hub_post_reset(struct usb_interface *intf)
static int hub_post_reset(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata(intf);
hub_activate(hub);
hub_power_on(hub);
hub_activate(hub);
return 0;
}
static int hub_configure(struct usb_hub *hub,
struct usb_endpoint_descriptor *endpoint)
{
@ -845,43 +875,42 @@ static int hub_configure(struct usb_hub *hub,
return ret;
}
static void hub_release(struct kref *kref)
{
struct usb_hub *hub = container_of(kref, struct usb_hub, kref);
usb_put_intf(to_usb_interface(hub->intfdev));
kfree(hub);
}
static unsigned highspeed_hubs;
static void hub_disconnect(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev;
/* Take the hub off the event list and don't let it be added again */
spin_lock_irq(&hub_event_lock);
list_del_init(&hub->event_list);
hub->disconnected = 1;
spin_unlock_irq(&hub_event_lock);
/* Disconnect all children and quiesce the hub */
hub->error = 0;
hub_pre_reset(intf);
usb_set_intfdata (intf, NULL);
hdev = hub->hdev;
if (hdev->speed == USB_SPEED_HIGH)
if (hub->hdev->speed == USB_SPEED_HIGH)
highspeed_hubs--;
usb_free_urb(hub->urb);
hub->urb = NULL;
spin_lock_irq(&hub_event_lock);
list_del_init(&hub->event_list);
spin_unlock_irq(&hub_event_lock);
kfree(hub->descriptor);
hub->descriptor = NULL;
kfree(hub->status);
hub->status = NULL;
if (hub->buffer) {
usb_buffer_free(hdev, sizeof(*hub->buffer), hub->buffer,
usb_buffer_free(hub->hdev, sizeof(*hub->buffer), hub->buffer,
hub->buffer_dma);
hub->buffer = NULL;
}
kfree(hub);
kref_put(&hub->kref, hub_release);
}
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
@ -929,10 +958,12 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
return -ENOMEM;
}
kref_init(&hub->kref);
INIT_LIST_HEAD(&hub->event_list);
hub->intfdev = &intf->dev;
hub->hdev = hdev;
INIT_DELAYED_WORK(&hub->leds, led_work);
usb_get_intf(intf);
usb_set_intfdata (intf, hub);
intf->needs_remote_wakeup = 1;
@ -982,49 +1013,6 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
}
/* grab device/port lock, returning index of that port (zero based).
* protects the upstream link used by this device from concurrent
* tree operations like suspend, resume, reset, and disconnect, which
* apply to everything downstream of a given port.
*/
static int locktree(struct usb_device *udev)
{
int t;
struct usb_device *hdev;
if (!udev)
return -ENODEV;
/* root hub is always the first lock in the series */
hdev = udev->parent;
if (!hdev) {
usb_lock_device(udev);
return 0;
}
/* on the path from root to us, lock everything from
* top down, dropping parent locks when not needed
*/
t = locktree(hdev);
if (t < 0)
return t;
/* everything is fail-fast once disconnect
* processing starts
*/
if (udev->state == USB_STATE_NOTATTACHED) {
usb_unlock_device(hdev);
return -ENODEV;
}
/* when everyone grabs locks top->bottom,
* non-overlapping work may be concurrent
*/
usb_lock_device(udev);
usb_unlock_device(hdev);
return udev->portnum;
}
static void recursively_mark_NOTATTACHED(struct usb_device *udev)
{
int i;
@ -1089,41 +1077,6 @@ void usb_set_device_state(struct usb_device *udev,
spin_unlock_irqrestore(&device_state_lock, flags);
}
#ifdef CONFIG_PM
/**
* usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
* @rhdev: struct usb_device for the root hub
*
* The USB host controller driver calls this function when its root hub
* is resumed and Vbus power has been interrupted or the controller
* has been reset. The routine marks all the children of the root hub
* as NOTATTACHED and marks logical connect-change events on their ports.
*/
void usb_root_hub_lost_power(struct usb_device *rhdev)
{
struct usb_hub *hub;
int port1;
unsigned long flags;
dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
spin_lock_irqsave(&device_state_lock, flags);
hub = hdev_to_hub(rhdev);
for (port1 = 1; port1 <= rhdev->maxchild; ++port1) {
if (rhdev->children[port1 - 1]) {
recursively_mark_NOTATTACHED(
rhdev->children[port1 - 1]);
set_bit(port1, hub->change_bits);
}
}
spin_unlock_irqrestore(&device_state_lock, flags);
}
EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
#endif /* CONFIG_PM */
static void choose_address(struct usb_device *udev)
{
int devnum;
@ -1264,7 +1217,6 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
#ifdef CONFIG_USB_OTG
#include "otg_whitelist.h"
static int __usb_port_suspend(struct usb_device *, int port1);
#endif
/**
@ -1370,11 +1322,11 @@ int usb_new_device(struct usb_device *udev)
* (Includes HNP test device.)
*/
if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
err = __usb_port_suspend(udev, udev->bus->otg_port);
err = usb_port_suspend(udev);
if (err < 0)
dev_dbg(&udev->dev, "HNP fail, %d\n", err);
}
err = -ENODEV;
err = -ENOTSUPP;
goto fail;
}
#endif
@ -1471,9 +1423,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
if (!(portstatus & USB_PORT_STAT_CONNECTION))
return -ENOTCONN;
/* bomb out completely if something weird happened */
/* bomb out completely if the connection bounced */
if ((portchange & USB_PORT_STAT_C_CONNECTION))
return -EINVAL;
return -ENOTCONN;
/* if we`ve finished resetting, then break out of the loop */
if (!(portstatus & USB_PORT_STAT_RESET) &&
@ -1552,34 +1504,24 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
return status;
}
/*
* Disable a port and mark a logical connnect-change event, so that some
* time later khubd will disconnect() any existing usb_device on the port
* and will re-enumerate if there actually is a device attached.
*/
static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
{
dev_dbg(hub->intfdev, "logical disconnect on port %d\n", port1);
hub_port_disable(hub, port1, 1);
/* FIXME let caller ask to power down the port:
* - some devices won't enumerate without a VBUS power cycle
* - SRP saves power that way
* - ... new call, TBD ...
* That's easy if this hub can switch power per-port, and
* khubd reactivates the port later (timer, SRP, etc).
* Powerdown must be optional, because of reset/DFU.
*/
set_bit(port1, hub->change_bits);
kick_khubd(hub);
}
#ifdef CONFIG_PM
#ifdef CONFIG_USB_SUSPEND
/*
* usb_port_suspend - suspend a usb device's upstream port
* @udev: device that's no longer in active use, not a root hub
* Context: must be able to sleep; device not locked; pm locks held
*
* Suspends a USB device that isn't in active use, conserving power.
* Devices may wake out of a suspend, if anything important happens,
* using the remote wakeup mechanism. They may also be taken out of
* suspend by the host, using usb_port_resume(). It's also routine
* to disconnect devices while they are suspended.
*
* This only affects the USB hardware for a device; its interfaces
* (and, for hubs, child devices) must already have been suspended.
*
* Selective port suspend reduces power; most suspended devices draw
* less than 500 uA. It's also used in OTG, along with remote wakeup.
* All devices below the suspended port are also suspended.
@ -1588,10 +1530,34 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
* also support "remote wakeup", where the device can activate the USB
* tree above them to deliver data, such as a keypress or packet. In
* some cases, this wakes the USB host.
*
* Suspending OTG devices may trigger HNP, if that's been enabled
* between a pair of dual-role devices. That will change roles, such
* as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
*
* Devices on USB hub ports have only one "suspend" state, corresponding
* to ACPI D2, "may cause the device to lose some context".
* State transitions include:
*
* - suspend, resume ... when the VBUS power link stays live
* - suspend, disconnect ... VBUS lost
*
* Once VBUS drop breaks the circuit, the port it's using has to go through
* normal re-enumeration procedures, starting with enabling VBUS power.
* Other than re-initializing the hub (plug/unplug, except for root hubs),
* Linux (2.6) currently has NO mechanisms to initiate that: no khubd
* timer, no SRP, no requests through sysfs.
*
* If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
* the root hub for their bus goes into global suspend ... so we don't
* (falsely) update the device power state to say it suspended.
*
* Returns 0 on success, else negative errno.
*/
static int hub_port_suspend(struct usb_hub *hub, int port1,
struct usb_device *udev)
int usb_port_suspend(struct usb_device *udev)
{
struct usb_hub *hub = hdev_to_hub(udev->parent);
int port1 = udev->portnum;
int status;
// dev_dbg(hub->intfdev, "suspend port %d\n", port1);
@ -1609,16 +1575,14 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
if (status)
dev_dbg(&udev->dev,
"won't remote wakeup, status %d\n",
dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
status);
}
/* see 7.1.7.6 */
status = set_port_feature(hub->hdev, port1, USB_PORT_FEAT_SUSPEND);
if (status) {
dev_dbg(hub->intfdev,
"can't suspend port %d, status %d\n",
dev_dbg(hub->intfdev, "can't suspend port %d, status %d\n",
port1, status);
/* paranoia: "should not happen" */
(void) usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
@ -1636,86 +1600,25 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
return status;
}
/*
* Devices on USB hub ports have only one "suspend" state, corresponding
* to ACPI D2, "may cause the device to lose some context".
* State transitions include:
*
* - suspend, resume ... when the VBUS power link stays live
* - suspend, disconnect ... VBUS lost
*
* Once VBUS drop breaks the circuit, the port it's using has to go through
* normal re-enumeration procedures, starting with enabling VBUS power.
* Other than re-initializing the hub (plug/unplug, except for root hubs),
* Linux (2.6) currently has NO mechanisms to initiate that: no khubd
* timer, no SRP, no requests through sysfs.
*
* If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
* the root hub for their bus goes into global suspend ... so we don't
* (falsely) update the device power state to say it suspended.
*/
static int __usb_port_suspend (struct usb_device *udev, int port1)
{
int status = 0;
/* caller owns the udev device lock */
if (port1 < 0)
return port1;
/* we change the device's upstream USB link,
* but root hubs have no upstream USB link.
*/
if (udev->parent)
status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
udev);
else {
dev_dbg(&udev->dev, "usb %ssuspend\n",
udev->auto_pm ? "auto-" : "");
usb_set_device_state(udev, USB_STATE_SUSPENDED);
}
return status;
}
/*
* usb_port_suspend - suspend a usb device's upstream port
* @udev: device that's no longer in active use
* Context: must be able to sleep; device not locked; pm locks held
*
* Suspends a USB device that isn't in active use, conserving power.
* Devices may wake out of a suspend, if anything important happens,
* using the remote wakeup mechanism. They may also be taken out of
* suspend by the host, using usb_port_resume(). It's also routine
* to disconnect devices while they are suspended.
*
* This only affects the USB hardware for a device; its interfaces
* (and, for hubs, child devices) must already have been suspended.
*
* Suspending OTG devices may trigger HNP, if that's been enabled
* between a pair of dual-role devices. That will change roles, such
* as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
*
* Returns 0 on success, else negative errno.
*/
int usb_port_suspend(struct usb_device *udev)
{
return __usb_port_suspend(udev, udev->portnum);
}
/*
* If the USB "suspend" state is in use (rather than "global suspend"),
* many devices will be individually taken out of suspend state using
* special" resume" signaling. These routines kick in shortly after
* special "resume" signaling. This routine kicks in shortly after
* hardware resume signaling is finished, either because of selective
* resume (by host) or remote wakeup (by device) ... now see what changed
* in the tree that's rooted at this device.
*
* If @udev->reset_resume is set then the device is reset before the
* status check is done.
*/
static int finish_port_resume(struct usb_device *udev)
{
int status;
int status = 0;
u16 devstatus;
/* caller owns the udev device lock */
dev_dbg(&udev->dev, "finish resume\n");
dev_dbg(&udev->dev, "finish %sresume\n",
udev->reset_resume ? "reset-" : "");
/* usb ch9 identifies four variants of SUSPENDED, based on what
* state the device resumes to. Linux currently won't see the
@ -1726,22 +1629,30 @@ static int finish_port_resume(struct usb_device *udev)
? USB_STATE_CONFIGURED
: USB_STATE_ADDRESS);
/* 10.5.4.5 says not to reset a suspended port if the attached
* device is enabled for remote wakeup. Hence the reset
* operation is carried out here, after the port has been
* resumed.
*/
if (udev->reset_resume)
status = usb_reset_device(udev);
/* 10.5.4.5 says be sure devices in the tree are still there.
* For now let's assume the device didn't go crazy on resume,
* and device drivers will know about any resume quirks.
*/
if (status == 0) {
status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
if (status >= 0)
status = (status == 2 ? 0 : -ENODEV);
}
if (status)
dev_dbg(&udev->dev,
"gone after usb resume? status %d\n",
if (status) {
dev_dbg(&udev->dev, "gone after usb resume? status %d\n",
status);
else if (udev->actconfig) {
} else if (udev->actconfig) {
le16_to_cpus(&devstatus);
if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
&& udev->parent) {
if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
status = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
USB_REQ_CLEAR_FEATURE,
@ -1754,19 +1665,52 @@ static int finish_port_resume(struct usb_device *udev)
"wakeup, status %d\n", status);
}
status = 0;
} else if (udev->devnum <= 0) {
dev_dbg(&udev->dev, "bogus resume!\n");
status = -EINVAL;
}
return status;
}
static int
hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
/*
* usb_port_resume - re-activate a suspended usb device's upstream port
* @udev: device to re-activate, not a root hub
* Context: must be able to sleep; device not locked; pm locks held
*
* This will re-activate the suspended device, increasing power usage
* while letting drivers communicate again with its endpoints.
* USB resume explicitly guarantees that the power session between
* the host and the device is the same as it was when the device
* suspended.
*
* If CONFIG_USB_PERSIST and @udev->reset_resume are both set then this
* routine won't check that the port is still enabled. Furthermore,
* if @udev->reset_resume is set then finish_port_resume() above will
* reset @udev. The end result is that a broken power session can be
* recovered and @udev will appear to persist across a loss of VBUS power.
*
* For example, if a host controller doesn't maintain VBUS suspend current
* during a system sleep or is reset when the system wakes up, all the USB
* power sessions below it will be broken. This is especially troublesome
* for mass-storage devices containing mounted filesystems, since the
* device will appear to have disconnected and all the memory mappings
* to it will be lost. Using the USB_PERSIST facility, the device can be
* made to appear as if it had not disconnected.
*
* This facility is inherently dangerous. Although usb_reset_device()
* makes every effort to insure that the same device is present after the
* reset as before, it cannot provide a 100% guarantee. Furthermore it's
* quite possible for a device to remain unaltered but its media to be
* changed. If the user replaces a flash memory card while the system is
* asleep, he will have only himself to blame when the filesystem on the
* new card is corrupted and the system crashes.
*
* Returns 0 on success, else negative errno.
*/
int usb_port_resume(struct usb_device *udev)
{
struct usb_hub *hub = hdev_to_hub(udev->parent);
int port1 = udev->portnum;
int status;
u16 portchange, portstatus;
unsigned mask_flags, want_flags;
/* Skip the initial Clear-Suspend step for a remote wakeup */
status = hub_port_status(hub, port1, &portstatus, &portchange);
@ -1781,30 +1725,31 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
status = clear_port_feature(hub->hdev,
port1, USB_PORT_FEAT_SUSPEND);
if (status) {
dev_dbg(hub->intfdev,
"can't resume port %d, status %d\n",
dev_dbg(hub->intfdev, "can't resume port %d, status %d\n",
port1, status);
} else {
/* drive resume for at least 20 msec */
if (udev)
dev_dbg(&udev->dev, "usb %sresume\n",
udev->auto_pm ? "auto-" : "");
msleep(25);
#define LIVE_FLAGS ( USB_PORT_STAT_POWER \
| USB_PORT_STAT_ENABLE \
| USB_PORT_STAT_CONNECTION)
/* Virtual root hubs can trigger on GET_PORT_STATUS to
* stop resume signaling. Then finish the resume
* sequence.
*/
status = hub_port_status(hub, port1, &portstatus, &portchange);
SuspendCleared:
if (status < 0
|| (portstatus & LIVE_FLAGS) != LIVE_FLAGS
|| (portstatus & USB_PORT_STAT_SUSPEND) != 0
) {
if (USB_PERSIST && udev->reset_resume)
want_flags = USB_PORT_STAT_POWER
| USB_PORT_STAT_CONNECTION;
else
want_flags = USB_PORT_STAT_POWER
| USB_PORT_STAT_CONNECTION
| USB_PORT_STAT_ENABLE;
mask_flags = want_flags | USB_PORT_STAT_SUSPEND;
if (status < 0 || (portstatus & mask_flags) != want_flags) {
dev_dbg(hub->intfdev,
"port %d status %04x.%04x after resume, %d\n",
port1, portchange, portstatus, status);
@ -1816,51 +1761,19 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
USB_PORT_FEAT_C_SUSPEND);
/* TRSMRCY = 10 msec */
msleep(10);
if (udev)
status = finish_port_resume(udev);
}
}
if (status < 0)
hub_port_logical_disconnect(hub, port1);
clear_bit(port1, hub->busy_bits);
if (!hub->hdev->parent && !hub->busy_bits[0])
usb_enable_root_hub_irq(hub->hdev->bus);
return status;
}
/*
* usb_port_resume - re-activate a suspended usb device's upstream port
* @udev: device to re-activate
* Context: must be able to sleep; device not locked; pm locks held
*
* This will re-activate the suspended device, increasing power usage
* while letting drivers communicate again with its endpoints.
* USB resume explicitly guarantees that the power session between
* the host and the device is the same as it was when the device
* suspended.
*
* Returns 0 on success, else negative errno.
*/
int usb_port_resume(struct usb_device *udev)
{
int status;
/* we change the device's upstream USB link,
* but root hubs have no upstream USB link.
*/
if (udev->parent) {
// NOTE this fails if parent is also suspended...
status = hub_port_resume(hdev_to_hub(udev->parent),
udev->portnum, udev);
} else {
dev_dbg(&udev->dev, "usb %sresume\n",
udev->auto_pm ? "auto-" : "");
if (status == 0)
status = finish_port_resume(udev);
}
if (status < 0)
if (status < 0) {
dev_dbg(&udev->dev, "can't resume, status %d\n", status);
hub_port_logical_disconnect(hub, port1);
}
return status;
}
@ -1887,21 +1800,16 @@ int usb_port_suspend(struct usb_device *udev)
return 0;
}
static inline int
finish_port_resume(struct usb_device *udev)
{
return 0;
}
static inline int
hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
{
return 0;
}
int usb_port_resume(struct usb_device *udev)
{
return 0;
int status = 0;
/* However we may need to do a reset-resume */
if (udev->reset_resume) {
dev_dbg(&udev->dev, "reset-resume\n");
status = usb_reset_device(udev);
}
return status;
}
static inline int remote_wakeup(struct usb_device *udev)
@ -1916,7 +1824,6 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev = hub->hdev;
unsigned port1;
int status = 0;
/* fail if children aren't already suspended */
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
@ -1942,49 +1849,75 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
/* stop khubd and related activity */
hub_quiesce(hub);
/* "global suspend" of the downstream HC-to-USB interface */
if (!hdev->parent) {
status = hcd_bus_suspend(hdev->bus);
if (status != 0) {
dev_dbg(&hdev->dev, "'global' suspend %d\n", status);
hub_activate(hub);
}
}
return status;
return 0;
}
static int hub_resume(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev = hub->hdev;
int status;
dev_dbg(&intf->dev, "%s\n", __FUNCTION__);
/* "global resume" of the downstream HC-to-USB interface */
if (!hdev->parent) {
struct usb_bus *bus = hdev->bus;
if (bus) {
status = hcd_bus_resume (bus);
if (status) {
dev_dbg(&intf->dev, "'global' resume %d\n",
status);
return status;
}
} else
return -EOPNOTSUPP;
if (status == 0) {
/* TRSMRCY = 10 msec */
msleep(10);
}
}
/* tell khubd to look for changes on this hub */
hub_activate(hub);
return 0;
}
static int hub_reset_resume(struct usb_interface *intf)
{
struct usb_hub *hub = usb_get_intfdata(intf);
struct usb_device *hdev = hub->hdev;
int port1;
hub_power_on(hub);
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
struct usb_device *child = hdev->children[port1-1];
if (child) {
/* For "USB_PERSIST"-enabled children we must
* mark the child device for reset-resume and
* turn off the connect-change status to prevent
* khubd from disconnecting it later.
*/
if (USB_PERSIST && child->persist_enabled) {
child->reset_resume = 1;
clear_port_feature(hdev, port1,
USB_PORT_FEAT_C_CONNECTION);
/* Otherwise we must disconnect the child,
* but as we may not lock the child device here
* we have to do a "logical" disconnect.
*/
} else {
hub_port_logical_disconnect(hub, port1);
}
}
}
hub_activate(hub);
return 0;
}
/**
* usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
* @rhdev: struct usb_device for the root hub
*
* The USB host controller driver calls this function when its root hub
* is resumed and Vbus power has been interrupted or the controller
* has been reset. The routine marks @rhdev as having lost power. When
* the hub driver is resumed it will take notice; if CONFIG_USB_PERSIST
* is enabled then it will carry out power-session recovery, otherwise
* it will disconnect all the child devices.
*/
void usb_root_hub_lost_power(struct usb_device *rhdev)
{
dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
rhdev->reset_resume = 1;
}
EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
#else /* CONFIG_PM */
static inline int remote_wakeup(struct usb_device *udev)
@ -1994,6 +1927,7 @@ static inline int remote_wakeup(struct usb_device *udev)
#define hub_suspend NULL
#define hub_resume NULL
#define hub_reset_resume NULL
#endif
@ -2456,19 +2390,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
return;
}
#ifdef CONFIG_USB_SUSPEND
/* If something is connected, but the port is suspended, wake it up. */
if (portstatus & USB_PORT_STAT_SUSPEND) {
status = hub_port_resume(hub, port1, NULL);
if (status < 0) {
dev_dbg(hub_dev,
"can't clear suspend on port %d; %d\n",
port1, status);
goto done;
}
}
#endif
for (i = 0; i < SET_CONFIG_TRIES; i++) {
struct usb_device *udev;
@ -2579,7 +2500,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
ep0_reinit(udev);
release_address(udev);
usb_put_dev(udev);
if (status == -ENOTCONN)
if ((status == -ENOTCONN) || (status == -ENOTSUPP))
break;
}
@ -2620,10 +2541,12 @@ static void hub_events(void)
list_del_init(tmp);
hub = list_entry(tmp, struct usb_hub, event_list);
hdev = hub->hdev;
intf = to_usb_interface(hub->intfdev);
hub_dev = &intf->dev;
kref_get(&hub->kref);
spin_unlock_irq(&hub_event_lock);
hdev = hub->hdev;
hub_dev = hub->intfdev;
intf = to_usb_interface(hub_dev);
dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
hdev->state, hub->descriptor
? hub->descriptor->bNbrPorts
@ -2632,16 +2555,10 @@ static void hub_events(void)
(u16) hub->change_bits[0],
(u16) hub->event_bits[0]);
usb_get_intf(intf);
spin_unlock_irq(&hub_event_lock);
/* Lock the device, then check to see if we were
* disconnected while waiting for the lock to succeed. */
if (locktree(hdev) < 0) {
usb_put_intf(intf);
continue;
}
if (hub != usb_get_intfdata(intf))
usb_lock_device(hdev);
if (unlikely(hub->disconnected))
goto loop;
/* If the hub has died, clean up after it */
@ -2804,7 +2721,7 @@ static void hub_events(void)
usb_autopm_enable(intf);
loop:
usb_unlock_device(hdev);
usb_put_intf(intf);
kref_put(&hub->kref, hub_release);
} /* end while (1) */
}
@ -2839,6 +2756,7 @@ static struct usb_driver hub_driver = {
.disconnect = hub_disconnect,
.suspend = hub_suspend,
.resume = hub_resume,
.reset_resume = hub_reset_resume,
.pre_reset = hub_pre_reset,
.post_reset = hub_post_reset,
.ioctl = hub_ioctl,
@ -2941,6 +2859,11 @@ static int config_descriptors_changed(struct usb_device *udev)
* this from a driver probe() routine after downloading new firmware.
* For calls that might not occur during probe(), drivers should lock
* the device using usb_lock_device_for_reset().
*
* Locking exception: This routine may also be called from within an
* autoresume handler. Such usage won't conflict with other tasks
* holding the device lock because these tasks should always call
* usb_autopm_resume_device(), thereby preventing any unwanted autoresume.
*/
int usb_reset_device(struct usb_device *udev)
{
@ -2971,7 +2894,7 @@ int usb_reset_device(struct usb_device *udev)
* Other endpoints will be handled by re-enumeration. */
ep0_reinit(udev);
ret = hub_port_init(parent_hub, udev, port1, i);
if (ret >= 0)
if (ret >= 0 || ret == -ENOTCONN || ret == -ENODEV)
break;
}
clear_bit(port1, parent_hub->busy_bits);
@ -3087,6 +3010,7 @@ int usb_reset_composite_device(struct usb_device *udev,
drv = to_usb_driver(cintf->dev.driver);
if (drv->pre_reset)
(drv->pre_reset)(cintf);
/* FIXME: Unbind if pre_reset returns an error or isn't defined */
}
}
}
@ -3105,6 +3029,7 @@ int usb_reset_composite_device(struct usb_device *udev,
drv = to_usb_driver(cintf->dev.driver);
if (drv->post_reset)
(drv->post_reset)(cintf);
/* FIXME: Unbind if post_reset returns an error or isn't defined */
}
if (cintf != iface)
up(&cintf->dev.sem);

View file

@ -404,8 +404,6 @@ int usb_sg_init (
io->urbs [i]->complete = sg_complete;
io->urbs [i]->context = io;
io->urbs [i]->status = -EINPROGRESS;
io->urbs [i]->actual_length = 0;
/*
* Some systems need to revert to PIO when DMA is temporarily
@ -499,7 +497,8 @@ void usb_sg_wait (struct usb_sg_request *io)
/* queue the urbs. */
spin_lock_irq (&io->lock);
for (i = 0; i < entries && !io->status; i++) {
i = 0;
while (i < entries && !io->status) {
int retval;
io->urbs [i]->dev = io->dev;
@ -516,7 +515,6 @@ void usb_sg_wait (struct usb_sg_request *io)
case -ENOMEM:
io->urbs[i]->dev = NULL;
retval = 0;
i--;
yield ();
break;
@ -527,6 +525,7 @@ void usb_sg_wait (struct usb_sg_request *io)
* URBs are queued at once; N milliseconds?
*/
case 0:
++i;
cpu_relax ();
break;
@ -1385,6 +1384,36 @@ struct device_type usb_if_device_type = {
.uevent = usb_if_uevent,
};
static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
struct usb_host_config *config,
u8 inum)
{
struct usb_interface_assoc_descriptor *retval = NULL;
struct usb_interface_assoc_descriptor *intf_assoc;
int first_intf;
int last_intf;
int i;
for (i = 0; (i < USB_MAXIADS && config->intf_assoc[i]); i++) {
intf_assoc = config->intf_assoc[i];
if (intf_assoc->bInterfaceCount == 0)
continue;
first_intf = intf_assoc->bFirstInterface;
last_intf = first_intf + (intf_assoc->bInterfaceCount - 1);
if (inum >= first_intf && inum <= last_intf) {
if (!retval)
retval = intf_assoc;
else
dev_err(&dev->dev, "Interface #%d referenced"
" by multiple IADs\n", inum);
}
}
return retval;
}
/*
* usb_set_configuration - Makes a particular device setting be current
* @dev: the device whose configuration is being updated
@ -1531,6 +1560,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
intfc = cp->intf_cache[i];
intf->altsetting = intfc->altsetting;
intf->num_altsetting = intfc->num_altsetting;
intf->intf_assoc = find_iad(dev, cp, i);
kref_get(&intfc->ref);
alt = usb_altnum_to_altsetting(intf, 0);

View file

@ -30,10 +30,28 @@
static const struct usb_device_id usb_quirk_list[] = {
/* HP 5300/5370C scanner */
{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
/* Benq S2W 3300U */
{ USB_DEVICE(0x04a5, 0x20b0), .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 1670 */
{ USB_DEVICE(0x04b8, 0x011f), .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 },
/* 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 },
/* 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 },
{ } /* terminating entry must be last */
};

View file

@ -169,6 +169,73 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
#if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
static const char power_group[] = "power";
#endif
#ifdef CONFIG_USB_PERSIST
static ssize_t
show_persist(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->persist_enabled);
}
static ssize_t
set_persist(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device(dev);
int value;
/* Hubs are always enabled for USB_PERSIST */
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
return -EPERM;
if (sscanf(buf, "%d", &value) != 1)
return -EINVAL;
usb_pm_lock(udev);
udev->persist_enabled = !!value;
usb_pm_unlock(udev);
return count;
}
static DEVICE_ATTR(persist, S_IRUGO | S_IWUSR, show_persist, set_persist);
static int add_persist_attributes(struct device *dev)
{
int rc = 0;
if (is_usb_device(dev)) {
struct usb_device *udev = to_usb_device(dev);
/* Hubs are automatically enabled for USB_PERSIST */
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
udev->persist_enabled = 1;
rc = sysfs_add_file_to_group(&dev->kobj,
&dev_attr_persist.attr,
power_group);
}
return rc;
}
static void remove_persist_attributes(struct device *dev)
{
sysfs_remove_file_from_group(&dev->kobj,
&dev_attr_persist.attr,
power_group);
}
#else
#define add_persist_attributes(dev) 0
#define remove_persist_attributes(dev) do {} while (0)
#endif /* CONFIG_USB_PERSIST */
#ifdef CONFIG_USB_SUSPEND
static ssize_t
@ -276,8 +343,6 @@ set_level(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
static char power_group[] = "power";
static int add_power_attributes(struct device *dev)
{
int rc = 0;
@ -311,6 +376,7 @@ static void remove_power_attributes(struct device *dev)
#endif /* CONFIG_USB_SUSPEND */
/* Descriptor fields */
#define usb_descriptor_attr_le16(field, format_string) \
static ssize_t \
@ -384,6 +450,10 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
if (retval)
return retval;
retval = add_persist_attributes(dev);
if (retval)
goto error;
retval = add_power_attributes(dev);
if (retval)
goto error;
@ -421,9 +491,29 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
device_remove_file(dev, &dev_attr_product);
device_remove_file(dev, &dev_attr_serial);
remove_power_attributes(dev);
remove_persist_attributes(dev);
sysfs_remove_group(&dev->kobj, &dev_attr_grp);
}
/* Interface Accociation Descriptor fields */
#define usb_intf_assoc_attr(field, format_string) \
static ssize_t \
show_iad_##field (struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_interface *intf = to_usb_interface (dev); \
\
return sprintf (buf, format_string, \
intf->intf_assoc->field); \
} \
static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL);
usb_intf_assoc_attr (bFirstInterface, "%02x\n")
usb_intf_assoc_attr (bInterfaceCount, "%02d\n")
usb_intf_assoc_attr (bFunctionClass, "%02x\n")
usb_intf_assoc_attr (bFunctionSubClass, "%02x\n")
usb_intf_assoc_attr (bFunctionProtocol, "%02x\n")
/* Interface fields */
#define usb_intf_attr(field, format_string) \
static ssize_t \
@ -487,6 +577,18 @@ static ssize_t show_modalias(struct device *dev,
}
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
static struct attribute *intf_assoc_attrs[] = {
&dev_attr_iad_bFirstInterface.attr,
&dev_attr_iad_bInterfaceCount.attr,
&dev_attr_iad_bFunctionClass.attr,
&dev_attr_iad_bFunctionSubClass.attr,
&dev_attr_iad_bFunctionProtocol.attr,
NULL,
};
static struct attribute_group intf_assoc_attr_grp = {
.attrs = intf_assoc_attrs,
};
static struct attribute *intf_attrs[] = {
&dev_attr_bInterfaceNumber.attr,
&dev_attr_bAlternateSetting.attr,
@ -538,6 +640,8 @@ int usb_create_sysfs_intf_files(struct usb_interface *intf)
alt->string = usb_cache_string(udev, alt->desc.iInterface);
if (alt->string)
retval = device_create_file(dev, &dev_attr_interface);
if (intf->intf_assoc)
retval = sysfs_create_group(&dev->kobj, &intf_assoc_attr_grp);
usb_create_intf_ep_files(intf, udev);
return 0;
}
@ -549,4 +653,5 @@ void usb_remove_sysfs_intf_files(struct usb_interface *intf)
usb_remove_intf_ep_files(intf);
device_remove_file(dev, &dev_attr_interface);
sysfs_remove_group(&dev->kobj, &intf_attr_grp);
sysfs_remove_group(&intf->dev.kobj, &intf_assoc_attr_grp);
}

View file

@ -4,6 +4,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/wait.h>
#include "hcd.h"
#define to_urb(d) container_of(d, struct urb, kref)
@ -11,6 +12,10 @@
static void urb_destroy(struct kref *kref)
{
struct urb *urb = to_urb(kref);
if (urb->transfer_flags & URB_FREE_BUFFER)
kfree(urb->transfer_buffer);
kfree(urb);
}
@ -34,6 +39,7 @@ void usb_init_urb(struct urb *urb)
memset(urb, 0, sizeof(*urb));
kref_init(&urb->kref);
spin_lock_init(&urb->lock);
INIT_LIST_HEAD(&urb->anchor_list);
}
}
@ -101,6 +107,58 @@ struct urb * usb_get_urb(struct urb *urb)
return urb;
}
/**
* usb_anchor_urb - anchors an URB while it is processed
* @urb: pointer to the urb to anchor
* @anchor: pointer to the anchor
*
* This can be called to have access to URBs which are to be executed
* without bothering to track them
*/
void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)
{
unsigned long flags;
spin_lock_irqsave(&anchor->lock, flags);
usb_get_urb(urb);
list_add_tail(&urb->anchor_list, &anchor->urb_list);
urb->anchor = anchor;
spin_unlock_irqrestore(&anchor->lock, flags);
}
EXPORT_SYMBOL_GPL(usb_anchor_urb);
/**
* usb_unanchor_urb - unanchors an URB
* @urb: pointer to the urb to anchor
*
* Call this to stop the system keeping track of this URB
*/
void usb_unanchor_urb(struct urb *urb)
{
unsigned long flags;
struct usb_anchor *anchor;
if (!urb)
return;
anchor = urb->anchor;
if (!anchor)
return;
spin_lock_irqsave(&anchor->lock, flags);
if (unlikely(anchor != urb->anchor)) {
/* we've lost the race to another thread */
spin_unlock_irqrestore(&anchor->lock, flags);
return;
}
urb->anchor = NULL;
list_del(&urb->anchor_list);
spin_unlock_irqrestore(&anchor->lock, flags);
usb_put_urb(urb);
if (list_empty(&anchor->urb_list))
wake_up(&anchor->wait);
}
EXPORT_SYMBOL_GPL(usb_unanchor_urb);
/*-------------------------------------------------------------------*/
@ -478,6 +536,48 @@ void usb_kill_urb(struct urb *urb)
spin_unlock_irq(&urb->lock);
}
/**
* usb_kill_anchored_urbs - cancel transfer requests en masse
* @anchor: anchor the requests are bound to
*
* this allows all outstanding URBs to be killed starting
* from the back of the queue
*/
void usb_kill_anchored_urbs(struct usb_anchor *anchor)
{
struct urb *victim;
spin_lock_irq(&anchor->lock);
while (!list_empty(&anchor->urb_list)) {
victim = list_entry(anchor->urb_list.prev, struct urb, anchor_list);
/* we must make sure the URB isn't freed before we kill it*/
usb_get_urb(victim);
spin_unlock_irq(&anchor->lock);
/* this will unanchor the URB */
usb_kill_urb(victim);
usb_put_urb(victim);
spin_lock_irq(&anchor->lock);
}
spin_unlock_irq(&anchor->lock);
}
EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs);
/**
* usb_wait_anchor_empty_timeout - wait for an anchor to be unused
* @anchor: the anchor you want to become unused
* @timeout: how long you are willing to wait in milliseconds
*
* Call this is you want to be sure all an anchor's
* URBs have finished
*/
int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
unsigned int timeout)
{
return wait_event_timeout(anchor->wait, list_empty(&anchor->urb_list),
msecs_to_jiffies(timeout));
}
EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout);
EXPORT_SYMBOL(usb_init_urb);
EXPORT_SYMBOL(usb_alloc_urb);
EXPORT_SYMBOL(usb_free_urb);
@ -485,4 +585,3 @@ EXPORT_SYMBOL(usb_get_urb);
EXPORT_SYMBOL(usb_submit_urb);
EXPORT_SYMBOL(usb_unlink_urb);
EXPORT_SYMBOL(usb_kill_urb);

View file

@ -253,6 +253,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->dev.bus = &usb_bus_type;
dev->dev.type = &usb_device_type;
dev->dev.dma_mask = bus->controller->dma_mask;
set_dev_node(&dev->dev, dev_to_node(bus->controller));
dev->state = USB_STATE_ATTACHED;
INIT_LIST_HEAD(&dev->ep0.urb_list);
@ -578,11 +579,12 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
* address (through the pointer provided).
*
* These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags
* to avoid behaviors like using "DMA bounce buffers", or tying down I/O
* mapping hardware for long idle periods. The implementation varies between
* to avoid behaviors like using "DMA bounce buffers", or thrashing IOMMU
* hardware during URB completion/resubmit. The implementation varies between
* platforms, depending on details of how DMA will work to this device.
* Using these buffers also helps prevent cacheline sharing problems on
* architectures where CPU caches are not DMA-coherent.
* Using these buffers also eliminates cacheline sharing problems on
* architectures where CPU caches are not DMA-coherent. On systems without
* bus-snooping caches, these buffers are uncached.
*
* When the buffer is no longer used, free it with usb_buffer_free().
*/

View file

@ -52,8 +52,16 @@ static inline void usb_pm_unlock(struct usb_device *udev)
#else
#define usb_port_suspend(dev) 0
#define usb_port_resume(dev) 0
static inline int usb_port_suspend(struct usb_device *udev)
{
return 0;
}
static inline int usb_port_resume(struct usb_device *udev)
{
return 0;
}
static inline void usb_pm_lock(struct usb_device *udev) {}
static inline void usb_pm_unlock(struct usb_device *udev) {}
@ -100,11 +108,13 @@ static inline int is_usb_device_driver(struct device_driver *drv)
static inline void mark_active(struct usb_interface *f)
{
f->is_active = 1;
f->dev.power.power_state.event = PM_EVENT_ON;
}
static inline void mark_quiesced(struct usb_interface *f)
{
f->is_active = 0;
f->dev.power.power_state.event = PM_EVENT_SUSPEND;
}
static inline int is_active(const struct usb_interface *f)

View file

@ -42,6 +42,20 @@ config USB_GADGET
For more information, see <http://www.linux-usb.org/gadget> and
the kernel DocBook documentation for this API.
config USB_GADGET_DEBUG
boolean "Debugging messages"
depends on USB_GADGET && DEBUG_KERNEL && EXPERIMENTAL
help
Many controller and gadget drivers will print some debugging
messages if you use this option to ask for those messages.
Avoid enabling these messages, even if you're actively
debugging such a driver. Many drivers will emit so many
messages that the driver timings are affected, which will
either create new failure modes or remove the one you're
trying to track down. Never enable these messages for a
production build.
config USB_GADGET_DEBUG_FILES
boolean "Debugging information files"
depends on USB_GADGET && PROC_FS
@ -208,6 +222,27 @@ config USB_OTG
Select this only if your OMAP board has a Mini-AB connector.
config USB_GADGET_S3C2410
boolean "S3C2410 USB Device Controller"
depends on ARCH_S3C2410
help
Samsung's S3C2410 is an ARM-4 processor with an integrated
full speed USB 1.1 device controller. It has 4 configurable
endpoints, as well as endpoint zero (for control transfers).
This driver has been tested on the S3C2410, S3C2412, and
S3C2440 processors.
config USB_S3C2410
tristate
depends on USB_GADGET_S3C2410
default USB_GADGET
select USB_GADGET_SELECTED
config USB_S3C2410_DEBUG
boolean "S3C2410 udc debug messages"
depends on USB_GADGET_S3C2410
config USB_GADGET_AT91
boolean "AT91 USB Device Port"
depends on ARCH_AT91 && !ARCH_AT91SAM9RL
@ -226,6 +261,24 @@ config USB_AT91
depends on USB_GADGET_AT91
default USB_GADGET
config USB_GADGET_M66592
boolean "M66592 driver"
select USB_GADGET_DUALSPEED
help
M66592 is a USB 2.0 peripheral controller.
It has seven configurable endpoints, and endpoint zero.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "m66592_udc" and force all
gadget drivers to also be dynamically linked.
config USB_M66592
tristate
depends on USB_GADGET_M66592
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_DUMMY_HCD
boolean "Dummy HCD (DEVELOPMENT)"
depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL

View file

@ -1,14 +1,20 @@
#
# USB peripheral controller drivers
#
ifeq ($(CONFIG_USB_GADGET_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2280) += net2280.o
obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o
obj-$(CONFIG_USB_GOKU) += goku_udc.o
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_FSL_USB2) += fsl_usb2_udc.o
obj-$(CONFIG_USB_M66592) += m66592-udc.o
#
# USB gadget drivers

View file

@ -601,25 +601,6 @@ static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
kfree(req);
}
static void *at91_ep_alloc_buffer(
struct usb_ep *_ep,
unsigned bytes,
dma_addr_t *dma,
gfp_t gfp_flags)
{
*dma = ~0;
return kmalloc(bytes, gfp_flags);
}
static void at91_ep_free_buffer(
struct usb_ep *ep,
void *buf,
dma_addr_t dma,
unsigned bytes)
{
kfree(buf);
}
static int at91_ep_queue(struct usb_ep *_ep,
struct usb_request *_req, gfp_t gfp_flags)
{
@ -788,8 +769,6 @@ static const struct usb_ep_ops at91_ep_ops = {
.disable = at91_ep_disable,
.alloc_request = at91_ep_alloc_request,
.free_request = at91_ep_free_request,
.alloc_buffer = at91_ep_alloc_buffer,
.free_buffer = at91_ep_free_buffer,
.queue = at91_ep_queue,
.dequeue = at91_ep_dequeue,
.set_halt = at91_ep_set_halt,

View file

@ -497,38 +497,6 @@ dummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
kfree (req);
}
static void *
dummy_alloc_buffer (
struct usb_ep *_ep,
unsigned bytes,
dma_addr_t *dma,
gfp_t mem_flags
) {
char *retval;
struct dummy_ep *ep;
struct dummy *dum;
ep = usb_ep_to_dummy_ep (_ep);
dum = ep_to_dummy (ep);
if (!dum->driver)
return NULL;
retval = kmalloc (bytes, mem_flags);
*dma = (dma_addr_t) retval;
return retval;
}
static void
dummy_free_buffer (
struct usb_ep *_ep,
void *buf,
dma_addr_t dma,
unsigned bytes
) {
if (bytes)
kfree (buf);
}
static void
fifo_complete (struct usb_ep *ep, struct usb_request *req)
{
@ -659,10 +627,6 @@ static const struct usb_ep_ops dummy_ep_ops = {
.alloc_request = dummy_alloc_request,
.free_request = dummy_free_request,
.alloc_buffer = dummy_alloc_buffer,
.free_buffer = dummy_free_buffer,
/* map, unmap, ... eventually hook the "generic" dma calls */
.queue = dummy_queue,
.dequeue = dummy_dequeue,
@ -1784,8 +1748,7 @@ static int dummy_bus_resume (struct usb_hcd *hcd)
spin_lock_irq (&dum->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
dev_warn (&hcd->self.root_hub->dev, "HC isn't running!\n");
rc = -ENODEV;
rc = -ESHUTDOWN;
} else {
dum->rh_state = DUMMY_RH_RUNNING;
set_link_state (dum);

View file

@ -277,7 +277,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
#ifdef CONFIG_USB_GADGET_HUSB2DEV
#ifdef CONFIG_USB_GADGET_ATMEL_USBA
#define DEV_CONFIG_CDC
#endif
@ -292,7 +292,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
#ifdef CONFIG_USB_GADGET_SH
#ifdef CONFIG_USB_GADGET_SUPERH
#define DEV_CONFIG_SUBSET
#endif
@ -301,6 +301,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
#ifdef CONFIG_USB_GADGET_M66592
#define DEV_CONFIG_CDC
#endif
/*-------------------------------------------------------------------------*/

View file

@ -3733,19 +3733,12 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
}
/* Free the data buffers */
for (i = 0; i < NUM_BUFFERS; ++i) {
struct fsg_buffhd *bh = &fsg->buffhds[i];
if (bh->buf)
usb_ep_free_buffer(fsg->bulk_in, bh->buf, bh->dma,
mod_data.buflen);
}
for (i = 0; i < NUM_BUFFERS; ++i)
kfree(fsg->buffhds[i].buf);
/* Free the request and buffer for endpoint 0 */
if (req) {
if (req->buf)
usb_ep_free_buffer(fsg->ep0, req->buf,
req->dma, EP0_BUFSIZE);
kfree(req->buf);
usb_ep_free_request(fsg->ep0, req);
}
@ -3963,8 +3956,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
#endif
if (gadget->is_otg) {
otg_desc.bmAttributes |= USB_OTG_HNP,
config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
otg_desc.bmAttributes |= USB_OTG_HNP;
}
rc = -ENOMEM;
@ -3973,8 +3965,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
if (!req)
goto out;
req->buf = usb_ep_alloc_buffer(fsg->ep0, EP0_BUFSIZE,
&req->dma, GFP_KERNEL);
req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
if (!req->buf)
goto out;
req->complete = ep0_complete;
@ -3986,8 +3977,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
/* Allocate for the bulk-in endpoint. We assume that
* the buffer will also work with the bulk-out (and
* interrupt-in) endpoint. */
bh->buf = usb_ep_alloc_buffer(fsg->bulk_in, mod_data.buflen,
&bh->dma, GFP_KERNEL);
bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
if (!bh->buf)
goto out;
bh->next = bh + 1;

View file

@ -228,7 +228,7 @@ static int dr_controller_setup(struct fsl_udc *udc)
/* Config PHY interface */
portctrl = fsl_readl(&dr_regs->portsc1);
portctrl &= ~(PORTSCX_PHY_TYPE_SEL & PORTSCX_PORT_WIDTH);
portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
switch (udc->phy_mode) {
case FSL_USB2_PHY_ULPI:
portctrl |= PORTSCX_PTS_ULPI;
@ -601,39 +601,6 @@ static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req)
kfree(req);
}
/*------------------------------------------------------------------
* Allocate an I/O buffer
*---------------------------------------------------------------------*/
static void *fsl_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
dma_addr_t *dma, gfp_t gfp_flags)
{
struct fsl_ep *ep;
if (!_ep)
return NULL;
ep = container_of(_ep, struct fsl_ep, ep);
return dma_alloc_coherent(ep->udc->gadget.dev.parent,
bytes, dma, gfp_flags);
}
/*------------------------------------------------------------------
* frees an i/o buffer
*---------------------------------------------------------------------*/
static void fsl_free_buffer(struct usb_ep *_ep, void *buf,
dma_addr_t dma, unsigned bytes)
{
struct fsl_ep *ep;
if (!_ep)
return;
ep = container_of(_ep, struct fsl_ep, ep);
dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma);
}
/*-------------------------------------------------------------------------*/
static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
{
@ -1047,9 +1014,6 @@ static struct usb_ep_ops fsl_ep_ops = {
.alloc_request = fsl_alloc_request,
.free_request = fsl_free_request,
.alloc_buffer = fsl_alloc_buffer,
.free_buffer = fsl_free_buffer,
.queue = fsl_ep_queue,
.dequeue = fsl_ep_dequeue,
@ -2189,27 +2153,19 @@ static void fsl_udc_release(struct device *dev)
* init resource for globle controller
* Return the udc handle on success or NULL on failure
------------------------------------------------------------------*/
static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev)
static int __init struct_udc_setup(struct fsl_udc *udc,
struct platform_device *pdev)
{
struct fsl_udc *udc;
struct fsl_usb2_platform_data *pdata;
size_t size;
udc = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
if (udc == NULL) {
ERR("malloc udc failed\n");
return NULL;
}
pdata = pdev->dev.platform_data;
udc->phy_mode = pdata->phy_mode;
/* max_ep_nr is bidirectional ep number, max_ep doubles the number */
udc->max_ep = pdata->max_ep_nr * 2;
udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL);
if (!udc->eps) {
ERR("malloc fsl_ep failed\n");
goto cleanup;
return -1;
}
/* initialized QHs, take care of alignment */
@ -2225,7 +2181,7 @@ static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev)
if (!udc->ep_qh) {
ERR("malloc QHs for udc failed\n");
kfree(udc->eps);
goto cleanup;
return -1;
}
udc->ep_qh_size = size;
@ -2244,11 +2200,7 @@ static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev)
udc->remote_wakeup = 0; /* default to 0 on reset */
spin_lock_init(&udc->lock);
return udc;
cleanup:
kfree(udc);
return NULL;
return 0;
}
/*----------------------------------------------------------------
@ -2287,35 +2239,37 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,
}
/* Driver probe function
* all intialize operations implemented here except enabling usb_intr reg
* all intialization operations implemented here except enabling usb_intr reg
* board setup should have been done in the platform code
*/
static int __init fsl_udc_probe(struct platform_device *pdev)
{
struct resource *res;
int ret = -ENODEV;
unsigned int i;
u32 dccparams;
if (strcmp(pdev->name, driver_name)) {
VDBG("Wrong device\n");
return -ENODEV;
}
/* board setup should have been done in the platform code */
/* Initialize the udc structure including QH member and other member */
udc_controller = struct_udc_setup(pdev);
if (!udc_controller) {
VDBG("udc_controller is NULL \n");
udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
if (udc_controller == NULL) {
ERR("malloc udc failed\n");
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
if (!res) {
kfree(udc_controller);
return -ENXIO;
}
if (!request_mem_region(res->start, res->end - res->start + 1,
driver_name)) {
ERR("request mem region for %s failed \n", pdev->name);
kfree(udc_controller);
return -EBUSY;
}
@ -2328,13 +2282,24 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
usb_sys_regs = (struct usb_sys_interface *)
((u32)dr_regs + USB_DR_SYS_OFFSET);
/* Read Device Controller Capability Parameters register */
dccparams = fsl_readl(&dr_regs->dccparams);
if (!(dccparams & DCCPARAMS_DC)) {
ERR("This SOC doesn't support device role\n");
ret = -ENODEV;
goto err2;
}
/* Get max device endpoints */
/* DEN is bidirectional ep number, max_ep doubles the number */
udc_controller->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2;
udc_controller->irq = platform_get_irq(pdev, 0);
if (!udc_controller->irq) {
ret = -ENODEV;
goto err2;
}
ret = request_irq(udc_controller->irq, fsl_udc_irq, SA_SHIRQ,
ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED,
driver_name, udc_controller);
if (ret != 0) {
ERR("cannot request irq %d err %d \n",
@ -2342,6 +2307,13 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
goto err2;
}
/* Initialize the udc structure including QH member and other member */
if (struct_udc_setup(udc_controller, pdev)) {
ERR("Can't initialize udc data structure\n");
ret = -ENOMEM;
goto err3;
}
/* initialize usb hw reg except for regs for EP,
* leave usbintr reg untouched */
dr_controller_setup(udc_controller);
@ -2403,6 +2375,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
iounmap(dr_regs);
err1:
release_mem_region(res->start, res->end - res->start + 1);
kfree(udc_controller);
return ret;
}

View file

@ -101,6 +101,10 @@ struct usb_sys_interface {
#define WAIT_FOR_OUT_STATUS 3
#define DATA_STATE_RECV 4
/* Device Controller Capability Parameter register */
#define DCCPARAMS_DC 0x00000080
#define DCCPARAMS_DEN_MASK 0x0000001f
/* Frame Index Register Bit Masks */
#define USB_FRINDEX_MASKS 0x3fff
/* USB CMD Register Bit Masks */

View file

@ -8,6 +8,8 @@
* (And avoiding all runtime comparisons in typical one-choice configs!)
*
* NOTE: some of these controller drivers may not be available yet.
* Some are available on 2.4 kernels; several are available, but not
* yet pushed in the 2.6 mainline tree.
*/
#ifdef CONFIG_USB_GADGET_NET2280
#define gadget_is_net2280(g) !strcmp("net2280", (g)->name)
@ -33,12 +35,14 @@
#define gadget_is_goku(g) 0
#endif
/* SH3 UDC -- not yet ported 2.4 --> 2.6 */
#ifdef CONFIG_USB_GADGET_SUPERH
#define gadget_is_sh(g) !strcmp("sh_udc", (g)->name)
#else
#define gadget_is_sh(g) 0
#endif
/* not yet stable on 2.6 (would help "original Zaurus") */
#ifdef CONFIG_USB_GADGET_SA1100
#define gadget_is_sa1100(g) !strcmp("sa1100_udc", (g)->name)
#else
@ -51,6 +55,7 @@
#define gadget_is_lh7a40x(g) 0
#endif
/* handhelds.org tree (?) */
#ifdef CONFIG_USB_GADGET_MQ11XX
#define gadget_is_mq11xx(g) !strcmp("mq11xx_udc", (g)->name)
#else
@ -63,22 +68,24 @@
#define gadget_is_omap(g) 0
#endif
/* not yet ported 2.4 --> 2.6 */
#ifdef CONFIG_USB_GADGET_N9604
#define gadget_is_n9604(g) !strcmp("n9604_udc", (g)->name)
#else
#define gadget_is_n9604(g) 0
#endif
/* various unstable versions available */
#ifdef CONFIG_USB_GADGET_PXA27X
#define gadget_is_pxa27x(g) !strcmp("pxa27x_udc", (g)->name)
#else
#define gadget_is_pxa27x(g) 0
#endif
#ifdef CONFIG_USB_GADGET_HUSB2DEV
#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name)
#ifdef CONFIG_USB_GADGET_ATMEL_USBA
#define gadget_is_atmel_usba(g) !strcmp("atmel_usba_udc", (g)->name)
#else
#define gadget_is_husb2dev(g) 0
#define gadget_is_atmel_usba(g) 0
#endif
#ifdef CONFIG_USB_GADGET_S3C2410
@ -93,6 +100,7 @@
#define gadget_is_at91(g) 0
#endif
/* status unclear */
#ifdef CONFIG_USB_GADGET_IMX
#define gadget_is_imx(g) !strcmp("imx_udc", (g)->name)
#else
@ -106,6 +114,7 @@
#endif
/* Mentor high speed function controller */
/* from Montavista kernel (?) */
#ifdef CONFIG_USB_GADGET_MUSBHSFC
#define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name)
#else
@ -119,12 +128,20 @@
#define gadget_is_musbhdrc(g) 0
#endif
/* from Montavista kernel (?) */
#ifdef CONFIG_USB_GADGET_MPC8272
#define gadget_is_mpc8272(g) !strcmp("mpc8272_udc", (g)->name)
#else
#define gadget_is_mpc8272(g) 0
#endif
#ifdef CONFIG_USB_GADGET_M66592
#define gadget_is_m66592(g) !strcmp("m66592_udc", (g)->name)
#else
#define gadget_is_m66592(g) 0
#endif
// CONFIG_USB_GADGET_SX2
// CONFIG_USB_GADGET_AU1X00
// ...
@ -181,9 +198,11 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x16;
else if (gadget_is_mpc8272(gadget))
return 0x17;
else if (gadget_is_husb2dev(gadget))
else if (gadget_is_atmel_usba(gadget))
return 0x18;
else if (gadget_is_fsl_usb2(gadget))
return 0x19;
else if (gadget_is_m66592(gadget))
return 0x20;
return -ENOENT;
}

View file

@ -1248,17 +1248,11 @@ static int __devinit gmidi_bind(struct usb_gadget *gadget)
tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev);
/* preallocate control response and buffer */
dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
dev->req = alloc_ep_req(gadget->ep0, USB_BUFSIZ);
if (!dev->req) {
err = -ENOMEM;
goto fail;
}
dev->req->buf = usb_ep_alloc_buffer(gadget->ep0, USB_BUFSIZ,
&dev->req->dma, GFP_KERNEL);
if (!dev->req->buf) {
err = -ENOMEM;
goto fail;
}
dev->req->complete = gmidi_setup_complete;

View file

@ -20,7 +20,6 @@
* - DMA works with ep1 (OUT transfers) and ep2 (IN transfers).
*/
#undef DEBUG
// #define VERBOSE /* extra debug messages (success too) */
// #define USB_TRACE /* packet-level success messages */
@ -296,51 +295,6 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req)
/*-------------------------------------------------------------------------*/
/* allocating buffers this way eliminates dma mapping overhead, which
* on some platforms will mean eliminating a per-io buffer copy. with
* some kinds of system caches, further tweaks may still be needed.
*/
static void *
goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
dma_addr_t *dma, gfp_t gfp_flags)
{
void *retval;
struct goku_ep *ep;
ep = container_of(_ep, struct goku_ep, ep);
if (!_ep)
return NULL;
*dma = DMA_ADDR_INVALID;
if (ep->dma) {
/* the main problem with this call is that it wastes memory
* on typical 1/N page allocations: it allocates 1-N pages.
*/
#warning Using dma_alloc_coherent even with buffers smaller than a page.
retval = dma_alloc_coherent(&ep->dev->pdev->dev,
bytes, dma, gfp_flags);
} else
retval = kmalloc(bytes, gfp_flags);
return retval;
}
static void
goku_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma, unsigned bytes)
{
/* free memory into the right allocator */
if (dma != DMA_ADDR_INVALID) {
struct goku_ep *ep;
ep = container_of(_ep, struct goku_ep, ep);
if (!_ep)
return;
dma_free_coherent(&ep->dev->pdev->dev, bytes, buf, dma);
} else
kfree (buf);
}
/*-------------------------------------------------------------------------*/
static void
done(struct goku_ep *ep, struct goku_request *req, int status)
{
@ -485,7 +439,7 @@ static int read_fifo(struct goku_ep *ep, struct goku_request *req)
/* use ep1/ep2 double-buffering for OUT */
if (!(size & PACKET_ACTIVE))
size = readl(&regs->EPxSizeLB[ep->num]);
if (!(size & PACKET_ACTIVE)) // "can't happen"
if (!(size & PACKET_ACTIVE)) /* "can't happen" */
break;
size &= DATASIZE; /* EPxSizeH == 0 */
@ -1026,9 +980,6 @@ static struct usb_ep_ops goku_ep_ops = {
.alloc_request = goku_alloc_request,
.free_request = goku_free_request,
.alloc_buffer = goku_alloc_buffer,
.free_buffer = goku_free_buffer,
.queue = goku_queue,
.dequeue = goku_dequeue,
@ -1140,17 +1091,17 @@ udc_proc_read(char *buffer, char **start, off_t off, int count,
is_usb_connected
? ((tmp & PW_PULLUP) ? "full speed" : "powered")
: "disconnected",
({char *tmp;
({char *state;
switch(dev->ep0state){
case EP0_DISCONNECT: tmp = "ep0_disconnect"; break;
case EP0_IDLE: tmp = "ep0_idle"; break;
case EP0_IN: tmp = "ep0_in"; break;
case EP0_OUT: tmp = "ep0_out"; break;
case EP0_STATUS: tmp = "ep0_status"; break;
case EP0_STALL: tmp = "ep0_stall"; break;
case EP0_SUSPEND: tmp = "ep0_suspend"; break;
default: tmp = "ep0_?"; break;
} tmp; })
case EP0_DISCONNECT: state = "ep0_disconnect"; break;
case EP0_IDLE: state = "ep0_idle"; break;
case EP0_IN: state = "ep0_in"; break;
case EP0_OUT: state = "ep0_out"; break;
case EP0_STATUS: state = "ep0_status"; break;
case EP0_STALL: state = "ep0_stall"; break;
case EP0_SUSPEND: state = "ep0_suspend"; break;
default: state = "ep0_?"; break;
} state; })
);
size -= t;
next += t;
@ -1195,7 +1146,6 @@ udc_proc_read(char *buffer, char **start, off_t off, int count,
for (i = 0; i < 4; i++) {
struct goku_ep *ep = &dev->ep [i];
struct goku_request *req;
int t;
if (i && !ep->desc)
continue;
@ -1896,8 +1846,8 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* done */
the_controller = dev;
device_register(&dev->gadget.dev);
retval = device_register(&dev->gadget.dev);
if (retval == 0)
return 0;
done:

View file

@ -41,8 +41,10 @@ struct goku_udc_regs {
#define INT_SYSERROR 0x40000
#define INT_PWRDETECT 0x80000
#define INT_DEVWIDE (INT_PWRDETECT|INT_SYSERROR/*|INT_ERR*/|INT_USBRESET|INT_SUSPEND)
#define INT_EP0 (INT_SETUP|INT_ENDPOINT0/*|INT_STATUS*/|INT_STATUSNAK)
#define INT_DEVWIDE \
(INT_PWRDETECT|INT_SYSERROR/*|INT_ERR*/|INT_USBRESET|INT_SUSPEND)
#define INT_EP0 \
(INT_SETUP|INT_ENDPOINT0/*|INT_STATUS*/|INT_STATUSNAK)
u32 dma_master;
#define MST_EOPB_DIS 0x0800

View file

@ -37,7 +37,7 @@
#include <linux/device.h>
#include <linux/moduleparam.h>
#include <linux/usb_gadgetfs.h>
#include <linux/usb/gadgetfs.h>
#include <linux/usb_gadget.h>
@ -923,7 +923,7 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req)
struct dev_data *dev = ep->driver_data;
if (req->buf != dev->rbuf) {
usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
kfree(req->buf);
req->buf = dev->rbuf;
req->dma = DMA_ADDR_INVALID;
}
@ -963,7 +963,7 @@ static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
return -EBUSY;
}
if (len > sizeof (dev->rbuf))
req->buf = usb_ep_alloc_buffer (ep, len, &req->dma, GFP_ATOMIC);
req->buf = kmalloc(len, GFP_ATOMIC);
if (req->buf == 0) {
req->buf = dev->rbuf;
return -ENOMEM;
@ -1505,7 +1505,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
}
break;
#ifndef CONFIG_USB_GADGETFS_PXA2XX
#ifndef CONFIG_USB_GADGET_PXA2XX
/* PXA automagically handles this request too */
case USB_REQ_GET_CONFIGURATION:
if (ctrl->bRequestType != 0x80)

View file

@ -75,10 +75,6 @@ static int lh7a40x_ep_enable(struct usb_ep *ep,
static int lh7a40x_ep_disable(struct usb_ep *ep);
static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, gfp_t);
static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *);
static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned, dma_addr_t *,
gfp_t);
static void lh7a40x_free_buffer(struct usb_ep *ep, void *, dma_addr_t,
unsigned);
static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, gfp_t);
static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *);
static int lh7a40x_set_halt(struct usb_ep *ep, int);
@ -104,9 +100,6 @@ static struct usb_ep_ops lh7a40x_ep_ops = {
.alloc_request = lh7a40x_alloc_request,
.free_request = lh7a40x_free_request,
.alloc_buffer = lh7a40x_alloc_buffer,
.free_buffer = lh7a40x_free_buffer,
.queue = lh7a40x_queue,
.dequeue = lh7a40x_dequeue,
@ -1134,26 +1127,6 @@ static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req)
kfree(req);
}
static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes,
dma_addr_t * dma, gfp_t gfp_flags)
{
char *retval;
DEBUG("%s (%p, %d, %d)\n", __FUNCTION__, ep, bytes, gfp_flags);
retval = kmalloc(bytes, gfp_flags & ~(__GFP_DMA | __GFP_HIGHMEM));
if (retval)
*dma = virt_to_bus(retval);
return retval;
}
static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma,
unsigned bytes)
{
DEBUG("%s, %p\n", __FUNCTION__, ep);
kfree(buf);
}
/** Queue one request
* Kickstart transfer if needed
* NOTE: Sets INDEX register

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,577 @@
/*
* M66592 UDC (USB gadget)
*
* Copyright (C) 2006-2007 Renesas Solutions Corp.
*
* Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef __M66592_UDC_H__
#define __M66592_UDC_H__
#define M66592_SYSCFG 0x00
#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */
#define M66592_XTAL48 0x8000 /* 48MHz */
#define M66592_XTAL24 0x4000 /* 24MHz */
#define M66592_XTAL12 0x0000 /* 12MHz */
#define M66592_XCKE 0x2000 /* b13: External clock enable */
#define M66592_RCKE 0x1000 /* b12: Register clock enable */
#define M66592_PLLC 0x0800 /* b11: PLL control */
#define M66592_SCKE 0x0400 /* b10: USB clock enable */
#define M66592_ATCKM 0x0100 /* b8: Automatic supply functional enable */
#define M66592_HSE 0x0080 /* b7: Hi-speed enable */
#define M66592_DCFM 0x0040 /* b6: Controller function select */
#define M66592_DMRPD 0x0020 /* b5: D- pull down control */
#define M66592_DPRPU 0x0010 /* b4: D+ pull up control */
#define M66592_FSRPC 0x0004 /* b2: Full-speed receiver enable */
#define M66592_PCUT 0x0002 /* b1: Low power sleep enable */
#define M66592_USBE 0x0001 /* b0: USB module operation enable */
#define M66592_SYSSTS 0x02
#define M66592_LNST 0x0003 /* b1-0: D+, D- line status */
#define M66592_SE1 0x0003 /* SE1 */
#define M66592_KSTS 0x0002 /* K State */
#define M66592_JSTS 0x0001 /* J State */
#define M66592_SE0 0x0000 /* SE0 */
#define M66592_DVSTCTR 0x04
#define M66592_WKUP 0x0100 /* b8: Remote wakeup */
#define M66592_RWUPE 0x0080 /* b7: Remote wakeup sense */
#define M66592_USBRST 0x0040 /* b6: USB reset enable */
#define M66592_RESUME 0x0020 /* b5: Resume enable */
#define M66592_UACT 0x0010 /* b4: USB bus enable */
#define M66592_RHST 0x0003 /* b1-0: Reset handshake status */
#define M66592_HSMODE 0x0003 /* Hi-Speed mode */
#define M66592_FSMODE 0x0002 /* Full-Speed mode */
#define M66592_HSPROC 0x0001 /* HS handshake is processing */
#define M66592_TESTMODE 0x06
#define M66592_UTST 0x000F /* b4-0: Test select */
#define M66592_H_TST_PACKET 0x000C /* HOST TEST Packet */
#define M66592_H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
#define M66592_H_TST_K 0x000A /* HOST TEST K */
#define M66592_H_TST_J 0x0009 /* HOST TEST J */
#define M66592_H_TST_NORMAL 0x0000 /* HOST Normal Mode */
#define M66592_P_TST_PACKET 0x0004 /* PERI TEST Packet */
#define M66592_P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
#define M66592_P_TST_K 0x0002 /* PERI TEST K */
#define M66592_P_TST_J 0x0001 /* PERI TEST J */
#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */
#define M66592_PINCFG 0x0A
#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */
#define M66592_BIGEND 0x0100 /* b8: Big endian mode */
#define M66592_DMA0CFG 0x0C
#define M66592_DMA1CFG 0x0E
#define M66592_DREQA 0x4000 /* b14: Dreq active select */
#define M66592_BURST 0x2000 /* b13: Burst mode */
#define M66592_DACKA 0x0400 /* b10: Dack active select */
#define M66592_DFORM 0x0380 /* b9-7: DMA mode select */
#define M66592_CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
#define M66592_CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
#define M66592_CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
#define M66592_SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
#define M66592_SPLIT_DACK_DSTB 0x0300 /* DACK + DSTB0 mode (SPLIT bus) */
#define M66592_DENDA 0x0040 /* b6: Dend active select */
#define M66592_PKTM 0x0020 /* b5: Packet mode */
#define M66592_DENDE 0x0010 /* b4: Dend enable */
#define M66592_OBUS 0x0004 /* b2: OUTbus mode */
#define M66592_CFIFO 0x10
#define M66592_D0FIFO 0x14
#define M66592_D1FIFO 0x18
#define M66592_CFIFOSEL 0x1E
#define M66592_D0FIFOSEL 0x24
#define M66592_D1FIFOSEL 0x2A
#define M66592_RCNT 0x8000 /* b15: Read count mode */
#define M66592_REW 0x4000 /* b14: Buffer rewind */
#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */
#define M66592_DREQE 0x1000 /* b12: DREQ output enable */
#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO access */
#define M66592_MBW_8 0x0000 /* 8bit */
#define M66592_MBW_16 0x0400 /* 16bit */
#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */
#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */
#define M66592_DEZPM 0x0080 /* b7: Zero-length packet additional mode */
#define M66592_ISEL 0x0020 /* b5: DCP FIFO port direction select */
#define M66592_CURPIPE 0x0007 /* b2-0: PIPE select */
#define M66592_CFIFOCTR 0x20
#define M66592_D0FIFOCTR 0x26
#define M66592_D1FIFOCTR 0x2c
#define M66592_BVAL 0x8000 /* b15: Buffer valid flag */
#define M66592_BCLR 0x4000 /* b14: Buffer clear */
#define M66592_FRDY 0x2000 /* b13: FIFO ready */
#define M66592_DTLN 0x0FFF /* b11-0: FIFO received data length */
#define M66592_CFIFOSIE 0x22
#define M66592_TGL 0x8000 /* b15: Buffer toggle */
#define M66592_SCLR 0x4000 /* b14: Buffer clear */
#define M66592_SBUSY 0x2000 /* b13: SIE_FIFO busy */
#define M66592_D0FIFOTRN 0x28
#define M66592_D1FIFOTRN 0x2E
#define M66592_TRNCNT 0xFFFF /* b15-0: Transaction counter */
#define M66592_INTENB0 0x30
#define M66592_VBSE 0x8000 /* b15: VBUS interrupt */
#define M66592_RSME 0x4000 /* b14: Resume interrupt */
#define M66592_SOFE 0x2000 /* b13: Frame update interrupt */
#define M66592_DVSE 0x1000 /* b12: Device state transition interrupt */
#define M66592_CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
#define M66592_BEMPE 0x0400 /* b10: Buffer empty interrupt */
#define M66592_NRDYE 0x0200 /* b9: Buffer not ready interrupt */
#define M66592_BRDYE 0x0100 /* b8: Buffer ready interrupt */
#define M66592_URST 0x0080 /* b7: USB reset detected interrupt */
#define M66592_SADR 0x0040 /* b6: Set address executed interrupt */
#define M66592_SCFG 0x0020 /* b5: Set configuration executed interrupt */
#define M66592_SUSP 0x0010 /* b4: Suspend detected interrupt */
#define M66592_WDST 0x0008 /* b3: Control write data stage completed interrupt */
#define M66592_RDST 0x0004 /* b2: Control read data stage completed interrupt */
#define M66592_CMPL 0x0002 /* b1: Control transfer complete interrupt */
#define M66592_SERR 0x0001 /* b0: Sequence error interrupt */
#define M66592_INTENB1 0x32
#define M66592_BCHGE 0x4000 /* b14: USB us chenge interrupt */
#define M66592_DTCHE 0x1000 /* b12: Detach sense interrupt */
#define M66592_SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
#define M66592_SACKE 0x0010 /* b4: SETUP ACK interrupt */
#define M66592_BRDYM 0x0004 /* b2: BRDY clear timing */
#define M66592_INTL 0x0002 /* b1: Interrupt sense select */
#define M66592_PCSE 0x0001 /* b0: PCUT enable by CS assert */
#define M66592_BRDYENB 0x36
#define M66592_BRDYSTS 0x46
#define M66592_BRDY7 0x0080 /* b7: PIPE7 */
#define M66592_BRDY6 0x0040 /* b6: PIPE6 */
#define M66592_BRDY5 0x0020 /* b5: PIPE5 */
#define M66592_BRDY4 0x0010 /* b4: PIPE4 */
#define M66592_BRDY3 0x0008 /* b3: PIPE3 */
#define M66592_BRDY2 0x0004 /* b2: PIPE2 */
#define M66592_BRDY1 0x0002 /* b1: PIPE1 */
#define M66592_BRDY0 0x0001 /* b1: PIPE0 */
#define M66592_NRDYENB 0x38
#define M66592_NRDYSTS 0x48
#define M66592_NRDY7 0x0080 /* b7: PIPE7 */
#define M66592_NRDY6 0x0040 /* b6: PIPE6 */
#define M66592_NRDY5 0x0020 /* b5: PIPE5 */
#define M66592_NRDY4 0x0010 /* b4: PIPE4 */
#define M66592_NRDY3 0x0008 /* b3: PIPE3 */
#define M66592_NRDY2 0x0004 /* b2: PIPE2 */
#define M66592_NRDY1 0x0002 /* b1: PIPE1 */
#define M66592_NRDY0 0x0001 /* b1: PIPE0 */
#define M66592_BEMPENB 0x3A
#define M66592_BEMPSTS 0x4A
#define M66592_BEMP7 0x0080 /* b7: PIPE7 */
#define M66592_BEMP6 0x0040 /* b6: PIPE6 */
#define M66592_BEMP5 0x0020 /* b5: PIPE5 */
#define M66592_BEMP4 0x0010 /* b4: PIPE4 */
#define M66592_BEMP3 0x0008 /* b3: PIPE3 */
#define M66592_BEMP2 0x0004 /* b2: PIPE2 */
#define M66592_BEMP1 0x0002 /* b1: PIPE1 */
#define M66592_BEMP0 0x0001 /* b0: PIPE0 */
#define M66592_SOFCFG 0x3C
#define M66592_SOFM 0x000C /* b3-2: SOF palse mode */
#define M66592_SOF_125US 0x0008 /* SOF OUT 125us uFrame Signal */
#define M66592_SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
#define M66592_SOF_DISABLE 0x0000 /* SOF OUT Disable */
#define M66592_INTSTS0 0x40
#define M66592_VBINT 0x8000 /* b15: VBUS interrupt */
#define M66592_RESM 0x4000 /* b14: Resume interrupt */
#define M66592_SOFR 0x2000 /* b13: SOF frame update interrupt */
#define M66592_DVST 0x1000 /* b12: Device state transition interrupt */
#define M66592_CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
#define M66592_BEMP 0x0400 /* b10: Buffer empty interrupt */
#define M66592_NRDY 0x0200 /* b9: Buffer not ready interrupt */
#define M66592_BRDY 0x0100 /* b8: Buffer ready interrupt */
#define M66592_VBSTS 0x0080 /* b7: VBUS input port */
#define M66592_DVSQ 0x0070 /* b6-4: Device state */
#define M66592_DS_SPD_CNFG 0x0070 /* Suspend Configured */
#define M66592_DS_SPD_ADDR 0x0060 /* Suspend Address */
#define M66592_DS_SPD_DFLT 0x0050 /* Suspend Default */
#define M66592_DS_SPD_POWR 0x0040 /* Suspend Powered */
#define M66592_DS_SUSP 0x0040 /* Suspend */
#define M66592_DS_CNFG 0x0030 /* Configured */
#define M66592_DS_ADDS 0x0020 /* Address */
#define M66592_DS_DFLT 0x0010 /* Default */
#define M66592_DS_POWR 0x0000 /* Powered */
#define M66592_DVSQS 0x0030 /* b5-4: Device state */
#define M66592_VALID 0x0008 /* b3: Setup packet detected flag */
#define M66592_CTSQ 0x0007 /* b2-0: Control transfer stage */
#define M66592_CS_SQER 0x0006 /* Sequence error */
#define M66592_CS_WRND 0x0005 /* Control write nodata status stage */
#define M66592_CS_WRSS 0x0004 /* Control write status stage */
#define M66592_CS_WRDS 0x0003 /* Control write data stage */
#define M66592_CS_RDSS 0x0002 /* Control read status stage */
#define M66592_CS_RDDS 0x0001 /* Control read data stage */
#define M66592_CS_IDST 0x0000 /* Idle or setup stage */
#define M66592_INTSTS1 0x42
#define M66592_BCHG 0x4000 /* b14: USB bus chenge interrupt */
#define M66592_DTCH 0x1000 /* b12: Detach sense interrupt */
#define M66592_SIGN 0x0020 /* b5: SETUP IGNORE interrupt */
#define M66592_SACK 0x0010 /* b4: SETUP ACK interrupt */
#define M66592_FRMNUM 0x4C
#define M66592_OVRN 0x8000 /* b15: Overrun error */
#define M66592_CRCE 0x4000 /* b14: Received data error */
#define M66592_SOFRM 0x0800 /* b11: SOF output mode */
#define M66592_FRNM 0x07FF /* b10-0: Frame number */
#define M66592_UFRMNUM 0x4E
#define M66592_UFRNM 0x0007 /* b2-0: Micro frame number */
#define M66592_RECOVER 0x50
#define M66592_STSRECOV 0x0700 /* Status recovery */
#define M66592_STSR_HI 0x0400 /* FULL(0) or HI(1) Speed */
#define M66592_STSR_DEFAULT 0x0100 /* Default state */
#define M66592_STSR_ADDRESS 0x0200 /* Address state */
#define M66592_STSR_CONFIG 0x0300 /* Configured state */
#define M66592_USBADDR 0x007F /* b6-0: USB address */
#define M66592_USBREQ 0x54
#define M66592_bRequest 0xFF00 /* b15-8: bRequest */
#define M66592_GET_STATUS 0x0000
#define M66592_CLEAR_FEATURE 0x0100
#define M66592_ReqRESERVED 0x0200
#define M66592_SET_FEATURE 0x0300
#define M66592_ReqRESERVED1 0x0400
#define M66592_SET_ADDRESS 0x0500
#define M66592_GET_DESCRIPTOR 0x0600
#define M66592_SET_DESCRIPTOR 0x0700
#define M66592_GET_CONFIGURATION 0x0800
#define M66592_SET_CONFIGURATION 0x0900
#define M66592_GET_INTERFACE 0x0A00
#define M66592_SET_INTERFACE 0x0B00
#define M66592_SYNCH_FRAME 0x0C00
#define M66592_bmRequestType 0x00FF /* b7-0: bmRequestType */
#define M66592_bmRequestTypeDir 0x0080 /* b7 : Data transfer direction */
#define M66592_HOST_TO_DEVICE 0x0000
#define M66592_DEVICE_TO_HOST 0x0080
#define M66592_bmRequestTypeType 0x0060 /* b6-5: Type */
#define M66592_STANDARD 0x0000
#define M66592_CLASS 0x0020
#define M66592_VENDOR 0x0040
#define M66592_bmRequestTypeRecip 0x001F /* b4-0: Recipient */
#define M66592_DEVICE 0x0000
#define M66592_INTERFACE 0x0001
#define M66592_ENDPOINT 0x0002
#define M66592_USBVAL 0x56
#define M66592_wValue 0xFFFF /* b15-0: wValue */
/* Standard Feature Selector */
#define M66592_ENDPOINT_HALT 0x0000
#define M66592_DEVICE_REMOTE_WAKEUP 0x0001
#define M66592_TEST_MODE 0x0002
/* Descriptor Types */
#define M66592_DT_TYPE 0xFF00
#define M66592_GET_DT_TYPE(v) (((v) & DT_TYPE) >> 8)
#define M66592_DT_DEVICE 0x01
#define M66592_DT_CONFIGURATION 0x02
#define M66592_DT_STRING 0x03
#define M66592_DT_INTERFACE 0x04
#define M66592_DT_ENDPOINT 0x05
#define M66592_DT_DEVICE_QUALIFIER 0x06
#define M66592_DT_OTHER_SPEED_CONFIGURATION 0x07
#define M66592_DT_INTERFACE_POWER 0x08
#define M66592_DT_INDEX 0x00FF
#define M66592_CONF_NUM 0x00FF
#define M66592_ALT_SET 0x00FF
#define M66592_USBINDEX 0x58
#define M66592_wIndex 0xFFFF /* b15-0: wIndex */
#define M66592_TEST_SELECT 0xFF00 /* b15-b8: Test Mode Selectors */
#define M66592_TEST_J 0x0100 /* Test_J */
#define M66592_TEST_K 0x0200 /* Test_K */
#define M66592_TEST_SE0_NAK 0x0300 /* Test_SE0_NAK */
#define M66592_TEST_PACKET 0x0400 /* Test_Packet */
#define M66592_TEST_FORCE_ENABLE 0x0500 /* Test_Force_Enable */
#define M66592_TEST_STSelectors 0x0600 /* Standard test selectors */
#define M66592_TEST_Reserved 0x4000 /* Reserved */
#define M66592_TEST_VSTModes 0xC000 /* Vendor-specific test modes */
#define M66592_EP_DIR 0x0080 /* b7: Endpoint Direction */
#define M66592_EP_DIR_IN 0x0080
#define M66592_EP_DIR_OUT 0x0000
#define M66592_USBLENG 0x5A
#define M66592_wLength 0xFFFF /* b15-0: wLength */
#define M66592_DCPCFG 0x5C
#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode select */
#define M66592_DIR 0x0010 /* b4: Control transfer DIR select */
#define M66592_DCPMAXP 0x5E
#define M66592_DEVSEL 0xC000 /* b15-14: Device address select */
#define M66592_DEVICE_0 0x0000 /* Device address 0 */
#define M66592_DEVICE_1 0x4000 /* Device address 1 */
#define M66592_DEVICE_2 0x8000 /* Device address 2 */
#define M66592_DEVICE_3 0xC000 /* Device address 3 */
#define M66592_MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
#define M66592_DCPCTR 0x60
#define M66592_BSTS 0x8000 /* b15: Buffer status */
#define M66592_SUREQ 0x4000 /* b14: Send USB request */
#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
#define M66592_CCPL 0x0004 /* b2: Enable control transfer complete */
#define M66592_PID 0x0003 /* b1-0: Response PID */
#define M66592_PID_STALL 0x0002 /* STALL */
#define M66592_PID_BUF 0x0001 /* BUF */
#define M66592_PID_NAK 0x0000 /* NAK */
#define M66592_PIPESEL 0x64
#define M66592_PIPENM 0x0007 /* b2-0: Pipe select */
#define M66592_PIPE0 0x0000 /* PIPE 0 */
#define M66592_PIPE1 0x0001 /* PIPE 1 */
#define M66592_PIPE2 0x0002 /* PIPE 2 */
#define M66592_PIPE3 0x0003 /* PIPE 3 */
#define M66592_PIPE4 0x0004 /* PIPE 4 */
#define M66592_PIPE5 0x0005 /* PIPE 5 */
#define M66592_PIPE6 0x0006 /* PIPE 6 */
#define M66592_PIPE7 0x0007 /* PIPE 7 */
#define M66592_PIPECFG 0x66
#define M66592_TYP 0xC000 /* b15-14: Transfer type */
#define M66592_ISO 0xC000 /* Isochronous */
#define M66592_INT 0x8000 /* Interrupt */
#define M66592_BULK 0x4000 /* Bulk */
#define M66592_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */
#define M66592_DBLB 0x0200 /* b9: Double buffer mode select */
#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode select */
#define M66592_SHTNAK 0x0080 /* b7: Transfer end NAK */
#define M66592_DIR 0x0010 /* b4: Transfer direction select */
#define M66592_DIR_H_OUT 0x0010 /* HOST OUT */
#define M66592_DIR_P_IN 0x0010 /* PERI IN */
#define M66592_DIR_H_IN 0x0000 /* HOST IN */
#define M66592_DIR_P_OUT 0x0000 /* PERI OUT */
#define M66592_EPNUM 0x000F /* b3-0: Eendpoint number select */
#define M66592_EP1 0x0001
#define M66592_EP2 0x0002
#define M66592_EP3 0x0003
#define M66592_EP4 0x0004
#define M66592_EP5 0x0005
#define M66592_EP6 0x0006
#define M66592_EP7 0x0007
#define M66592_EP8 0x0008
#define M66592_EP9 0x0009
#define M66592_EP10 0x000A
#define M66592_EP11 0x000B
#define M66592_EP12 0x000C
#define M66592_EP13 0x000D
#define M66592_EP14 0x000E
#define M66592_EP15 0x000F
#define M66592_PIPEBUF 0x68
#define M66592_BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
#define M66592_BUF_SIZE(x) ((((x) / 64) - 1) << 10)
#define M66592_BUFNMB 0x00FF /* b7-0: Pipe buffer number */
#define M66592_PIPEMAXP 0x6A
#define M66592_MXPS 0x07FF /* b10-0: Maxpacket size */
#define M66592_PIPEPERI 0x6C
#define M66592_IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
#define M66592_IITV 0x0007 /* b2-0: Isochronous interval */
#define M66592_PIPE1CTR 0x70
#define M66592_PIPE2CTR 0x72
#define M66592_PIPE3CTR 0x74
#define M66592_PIPE4CTR 0x76
#define M66592_PIPE5CTR 0x78
#define M66592_PIPE6CTR 0x7A
#define M66592_PIPE7CTR 0x7C
#define M66592_BSTS 0x8000 /* b15: Buffer status */
#define M66592_INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
#define M66592_ACLRM 0x0200 /* b9: Out buffer auto clear mode */
#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */
#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */
#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */
#define M66592_PID 0x0003 /* b1-0: Response PID */
#define M66592_INVALID_REG 0x7E
#define __iomem
#define get_pipectr_addr(pipenum) (M66592_PIPE1CTR + (pipenum - 1) * 2)
#define M66592_MAX_SAMPLING 10
#define M66592_MAX_NUM_PIPE 8
#define M66592_MAX_NUM_BULK 3
#define M66592_MAX_NUM_ISOC 2
#define M66592_MAX_NUM_INT 2
#define M66592_BASE_PIPENUM_BULK 3
#define M66592_BASE_PIPENUM_ISOC 1
#define M66592_BASE_PIPENUM_INT 6
#define M66592_BASE_BUFNUM 6
#define M66592_MAX_BUFNUM 0x4F
struct m66592_pipe_info {
u16 pipe;
u16 epnum;
u16 maxpacket;
u16 type;
u16 interval;
u16 dir_in;
};
struct m66592_request {
struct usb_request req;
struct list_head queue;
};
struct m66592_ep {
struct usb_ep ep;
struct m66592 *m66592;
struct list_head queue;
unsigned busy:1;
unsigned internal_ccpl:1; /* use only control */
/* this member can able to after m66592_enable */
unsigned use_dma:1;
u16 pipenum;
u16 type;
const struct usb_endpoint_descriptor *desc;
/* register address */
unsigned long fifoaddr;
unsigned long fifosel;
unsigned long fifoctr;
unsigned long fifotrn;
unsigned long pipectr;
};
struct m66592 {
spinlock_t lock;
void __iomem *reg;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct m66592_ep ep[M66592_MAX_NUM_PIPE];
struct m66592_ep *pipenum2ep[M66592_MAX_NUM_PIPE];
struct m66592_ep *epaddr2ep[16];
struct usb_request *ep0_req; /* for internal request */
u16 *ep0_buf; /* for internal request */
struct timer_list timer;
u16 old_vbus;
int scount;
int old_dvsq;
/* pipe config */
int bulk;
int interrupt;
int isochronous;
int num_dma;
int bi_bufnum; /* bulk and isochronous's bufnum */
};
#define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget)
#define m66592_to_gadget(m66592) (&m66592->gadget)
#define is_bulk_pipe(pipenum) \
((pipenum >= M66592_BASE_PIPENUM_BULK) && \
(pipenum < (M66592_BASE_PIPENUM_BULK + M66592_MAX_NUM_BULK)))
#define is_interrupt_pipe(pipenum) \
((pipenum >= M66592_BASE_PIPENUM_INT) && \
(pipenum < (M66592_BASE_PIPENUM_INT + M66592_MAX_NUM_INT)))
#define is_isoc_pipe(pipenum) \
((pipenum >= M66592_BASE_PIPENUM_ISOC) && \
(pipenum < (M66592_BASE_PIPENUM_ISOC + M66592_MAX_NUM_ISOC)))
#define enable_irq_ready(m66592, pipenum) \
enable_pipe_irq(m66592, pipenum, M66592_BRDYENB)
#define disable_irq_ready(m66592, pipenum) \
disable_pipe_irq(m66592, pipenum, M66592_BRDYENB)
#define enable_irq_empty(m66592, pipenum) \
enable_pipe_irq(m66592, pipenum, M66592_BEMPENB)
#define disable_irq_empty(m66592, pipenum) \
disable_pipe_irq(m66592, pipenum, M66592_BEMPENB)
#define enable_irq_nrdy(m66592, pipenum) \
enable_pipe_irq(m66592, pipenum, M66592_NRDYENB)
#define disable_irq_nrdy(m66592, pipenum) \
disable_pipe_irq(m66592, pipenum, M66592_NRDYENB)
/*-------------------------------------------------------------------------*/
static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset)
{
return inw((unsigned long)m66592->reg + offset);
}
static inline void m66592_read_fifo(struct m66592 *m66592,
unsigned long offset,
void *buf, unsigned long len)
{
unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
len = (len + 1) / 2;
insw(fifoaddr, buf, len);
}
static inline void m66592_write(struct m66592 *m66592, u16 val,
unsigned long offset)
{
outw(val, (unsigned long)m66592->reg + offset);
}
static inline void m66592_write_fifo(struct m66592 *m66592,
unsigned long offset,
void *buf, unsigned long len)
{
unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
unsigned long odd = len & 0x0001;
len = len / 2;
outsw(fifoaddr, buf, len);
if (odd) {
unsigned char *p = buf + len*2;
outb(*p, fifoaddr);
}
}
static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
unsigned long offset)
{
u16 tmp;
tmp = m66592_read(m66592, offset);
tmp = tmp & (~pat);
tmp = tmp | val;
m66592_write(m66592, tmp, offset);
}
#define m66592_bclr(m66592, val, offset) \
m66592_mdfy(m66592, 0, val, offset)
#define m66592_bset(m66592, val, offset) \
m66592_mdfy(m66592, val, 0, offset)
#endif /* ifndef __M66592_UDC_H__ */

View file

@ -450,100 +450,6 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
/*-------------------------------------------------------------------------*/
/*
* dma-coherent memory allocation (for dma-capable endpoints)
*
* NOTE: the dma_*_coherent() API calls suck. Most implementations are
* (a) page-oriented, so small buffers lose big; and (b) asymmetric with
* respect to calls with irqs disabled: alloc is safe, free is not.
* We currently work around (b), but not (a).
*/
static void *
net2280_alloc_buffer (
struct usb_ep *_ep,
unsigned bytes,
dma_addr_t *dma,
gfp_t gfp_flags
)
{
void *retval;
struct net2280_ep *ep;
ep = container_of (_ep, struct net2280_ep, ep);
if (!_ep)
return NULL;
*dma = DMA_ADDR_INVALID;
if (ep->dma)
retval = dma_alloc_coherent(&ep->dev->pdev->dev,
bytes, dma, gfp_flags);
else
retval = kmalloc(bytes, gfp_flags);
return retval;
}
static DEFINE_SPINLOCK(buflock);
static LIST_HEAD(buffers);
struct free_record {
struct list_head list;
struct device *dev;
unsigned bytes;
dma_addr_t dma;
};
static void do_free(unsigned long ignored)
{
spin_lock_irq(&buflock);
while (!list_empty(&buffers)) {
struct free_record *buf;
buf = list_entry(buffers.next, struct free_record, list);
list_del(&buf->list);
spin_unlock_irq(&buflock);
dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
spin_lock_irq(&buflock);
}
spin_unlock_irq(&buflock);
}
static DECLARE_TASKLET(deferred_free, do_free, 0);
static void
net2280_free_buffer (
struct usb_ep *_ep,
void *address,
dma_addr_t dma,
unsigned bytes
) {
/* free memory into the right allocator */
if (dma != DMA_ADDR_INVALID) {
struct net2280_ep *ep;
struct free_record *buf = address;
unsigned long flags;
ep = container_of(_ep, struct net2280_ep, ep);
if (!_ep)
return;
ep = container_of (_ep, struct net2280_ep, ep);
buf->dev = &ep->dev->pdev->dev;
buf->bytes = bytes;
buf->dma = dma;
spin_lock_irqsave(&buflock, flags);
list_add_tail(&buf->list, &buffers);
tasklet_schedule(&deferred_free);
spin_unlock_irqrestore(&buflock, flags);
} else
kfree (address);
}
/*-------------------------------------------------------------------------*/
/* load a packet into the fifo we use for usb IN transfers.
* works for all endpoints.
*
@ -1392,9 +1298,6 @@ static const struct usb_ep_ops net2280_ep_ops = {
.alloc_request = net2280_alloc_request,
.free_request = net2280_free_request,
.alloc_buffer = net2280_alloc_buffer,
.free_buffer = net2280_free_buffer,
.queue = net2280_queue,
.dequeue = net2280_dequeue,

View file

@ -296,111 +296,6 @@ omap_free_request(struct usb_ep *ep, struct usb_request *_req)
/*-------------------------------------------------------------------------*/
/*
* dma-coherent memory allocation (for dma-capable endpoints)
*
* NOTE: the dma_*_coherent() API calls suck. Most implementations are
* (a) page-oriented, so small buffers lose big; and (b) asymmetric with
* respect to calls with irqs disabled: alloc is safe, free is not.
* We currently work around (b), but not (a).
*/
static void *
omap_alloc_buffer(
struct usb_ep *_ep,
unsigned bytes,
dma_addr_t *dma,
gfp_t gfp_flags
)
{
void *retval;
struct omap_ep *ep;
if (!_ep)
return NULL;
ep = container_of(_ep, struct omap_ep, ep);
if (use_dma && ep->has_dma) {
static int warned;
if (!warned && bytes < PAGE_SIZE) {
dev_warn(ep->udc->gadget.dev.parent,
"using dma_alloc_coherent for "
"small allocations wastes memory\n");
warned++;
}
return dma_alloc_coherent(ep->udc->gadget.dev.parent,
bytes, dma, gfp_flags);
}
retval = kmalloc(bytes, gfp_flags);
if (retval)
*dma = virt_to_phys(retval);
return retval;
}
static DEFINE_SPINLOCK(buflock);
static LIST_HEAD(buffers);
struct free_record {
struct list_head list;
struct device *dev;
unsigned bytes;
dma_addr_t dma;
};
static void do_free(unsigned long ignored)
{
spin_lock_irq(&buflock);
while (!list_empty(&buffers)) {
struct free_record *buf;
buf = list_entry(buffers.next, struct free_record, list);
list_del(&buf->list);
spin_unlock_irq(&buflock);
dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
spin_lock_irq(&buflock);
}
spin_unlock_irq(&buflock);
}
static DECLARE_TASKLET(deferred_free, do_free, 0);
static void omap_free_buffer(
struct usb_ep *_ep,
void *buf,
dma_addr_t dma,
unsigned bytes
)
{
if (!_ep) {
WARN_ON(1);
return;
}
/* free memory into the right allocator */
if (dma != DMA_ADDR_INVALID) {
struct omap_ep *ep;
struct free_record *rec = buf;
unsigned long flags;
ep = container_of(_ep, struct omap_ep, ep);
rec->dev = ep->udc->gadget.dev.parent;
rec->bytes = bytes;
rec->dma = dma;
spin_lock_irqsave(&buflock, flags);
list_add_tail(&rec->list, &buffers);
tasklet_schedule(&deferred_free);
spin_unlock_irqrestore(&buflock, flags);
} else
kfree(buf);
}
/*-------------------------------------------------------------------------*/
static void
done(struct omap_ep *ep, struct omap_req *req, int status)
{
@ -1271,9 +1166,6 @@ static struct usb_ep_ops omap_ep_ops = {
.alloc_request = omap_alloc_request,
.free_request = omap_free_request,
.alloc_buffer = omap_alloc_buffer,
.free_buffer = omap_free_buffer,
.queue = omap_ep_queue,
.dequeue = omap_ep_dequeue,

View file

@ -24,9 +24,9 @@
*
*/
#undef DEBUG
// #define VERBOSE DBG_VERBOSE
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@ -46,19 +46,17 @@
#include <asm/byteorder.h>
#include <asm/dma.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <asm/unaligned.h>
#include <asm/hardware.h>
#ifdef CONFIG_ARCH_PXA
#include <asm/arch/pxa-regs.h>
#endif
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/arch/udc.h>
#include <asm/mach/udc_pxa2xx.h>
/*
@ -76,9 +74,17 @@
* it constrains the sorts of USB configuration change events that work.
* The errata for these chips are misleading; some "fixed" bugs from
* pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
*
* Note that the UDC hardware supports DMA (except on IXP) but that's
* not used here. IN-DMA (to host) is simple enough, when the data is
* suitably aligned (16 bytes) ... the network stack doesn't do that,
* other software can. OUT-DMA is buggy in most chip versions, as well
* as poorly designed (data toggle not automatic). So this driver won't
* bother using DMA. (Mostly-working IN-DMA support was available in
* kernels before 2.6.23, but was never enabled or well tested.)
*/
#define DRIVER_VERSION "4-May-2005"
#define DRIVER_VERSION "30-June-2007"
#define DRIVER_DESC "PXA 25x USB Device Controller driver"
@ -87,12 +93,9 @@ static const char driver_name [] = "pxa2xx_udc";
static const char ep0name [] = "ep0";
// #define USE_DMA
// #define USE_OUT_DMA
// #define DISABLE_TEST_MODE
#ifdef CONFIG_ARCH_IXP4XX
#undef USE_DMA
/* cpu-specific register addresses are compiled in to this code */
#ifdef CONFIG_ARCH_PXA
@ -104,25 +107,6 @@ static const char ep0name [] = "ep0";
#include "pxa2xx_udc.h"
#ifdef USE_DMA
static int use_dma = 1;
module_param(use_dma, bool, 0);
MODULE_PARM_DESC (use_dma, "true to use dma");
static void dma_nodesc_handler (int dmach, void *_ep);
static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req);
#ifdef USE_OUT_DMA
#define DMASTR " (dma support)"
#else
#define DMASTR " (dma in)"
#endif
#else /* !USE_DMA */
#define DMASTR " (pio only)"
#undef USE_OUT_DMA
#endif
#ifdef CONFIG_USB_PXA2XX_SMALL
#define SIZE_STR " (small)"
#else
@ -155,7 +139,7 @@ static int is_vbus_present(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_vbus)
return udc_gpio_get(mach->gpio_vbus);
return gpio_get_value(mach->gpio_vbus);
if (mach->udc_is_connected)
return mach->udc_is_connected();
return 1;
@ -167,7 +151,7 @@ static void pullup_off(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
udc_gpio_set(mach->gpio_pullup, 0);
gpio_set_value(mach->gpio_pullup, 0);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
@ -177,7 +161,7 @@ static void pullup_on(void)
struct pxa2xx_udc_mach_info *mach = the_controller->mach;
if (mach->gpio_pullup)
udc_gpio_set(mach->gpio_pullup, 1);
gpio_set_value(mach->gpio_pullup, 1);
else if (mach->udc_command)
mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
}
@ -281,9 +265,8 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
}
ep->desc = desc;
ep->dma = -1;
ep->stopped = 0;
ep->pio_irqs = ep->dma_irqs = 0;
ep->pio_irqs = 0;
ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);
/* flush fifo (mostly for OUT buffers) */
@ -291,30 +274,6 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
/* ... reset halt state too, if we could ... */
#ifdef USE_DMA
/* for (some) bulk and ISO endpoints, try to get a DMA channel and
* bind it to the endpoint. otherwise use PIO.
*/
switch (ep->bmAttributes) {
case USB_ENDPOINT_XFER_ISOC:
if (le16_to_cpu(desc->wMaxPacketSize) % 32)
break;
// fall through
case USB_ENDPOINT_XFER_BULK:
if (!use_dma || !ep->reg_drcmr)
break;
ep->dma = pxa_request_dma ((char *)_ep->name,
(le16_to_cpu (desc->wMaxPacketSize) > 64)
? DMA_PRIO_MEDIUM /* some iso */
: DMA_PRIO_LOW,
dma_nodesc_handler, ep);
if (ep->dma >= 0) {
*ep->reg_drcmr = DRCMR_MAPVLD | ep->dma;
DMSG("%s using dma%d\n", _ep->name, ep->dma);
}
}
#endif
DBG(DBG_VERBOSE, "enabled %s\n", _ep->name);
return 0;
}
@ -334,14 +293,6 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
nuke (ep, -ESHUTDOWN);
#ifdef USE_DMA
if (ep->dma >= 0) {
*ep->reg_drcmr = 0;
pxa_free_dma (ep->dma);
ep->dma = -1;
}
#endif
/* flush fifo (mostly for IN buffers) */
pxa2xx_ep_fifo_flush (_ep);
@ -390,35 +341,6 @@ pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req)
kfree(req);
}
/* PXA cache needs flushing with DMA I/O (it's dma-incoherent), but there's
* no device-affinity and the heap works perfectly well for i/o buffers.
* It wastes much less memory than dma_alloc_coherent() would, and even
* prevents cacheline (32 bytes wide) sharing problems.
*/
static void *
pxa2xx_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
dma_addr_t *dma, gfp_t gfp_flags)
{
char *retval;
retval = kmalloc (bytes, gfp_flags & ~(__GFP_DMA|__GFP_HIGHMEM));
if (retval)
#ifdef USE_DMA
*dma = virt_to_bus (retval);
#else
*dma = (dma_addr_t)~0;
#endif
return retval;
}
static void
pxa2xx_ep_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma,
unsigned bytes)
{
kfree (buf);
}
/*-------------------------------------------------------------------------*/
/*
@ -518,18 +440,8 @@ write_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
/* requests complete when all IN data is in the FIFO */
if (is_last) {
done (ep, req, 0);
if (list_empty(&ep->queue) || unlikely(ep->dma >= 0)) {
if (list_empty(&ep->queue))
pio_irq_disable (ep->bEndpointAddress);
#ifdef USE_DMA
/* unaligned data and zlps couldn't use dma */
if (unlikely(!list_empty(&ep->queue))) {
req = list_entry(ep->queue.next,
struct pxa2xx_request, queue);
kick_dma(ep,req);
return 0;
}
#endif
}
return 1;
}
@ -728,182 +640,6 @@ read_ep0_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
return 0;
}
#ifdef USE_DMA
#define MAX_IN_DMA ((DCMD_LENGTH + 1) - BULK_FIFO_SIZE)
static void
start_dma_nodesc(struct pxa2xx_ep *ep, struct pxa2xx_request *req, int is_in)
{
u32 dcmd = req->req.length;
u32 buf = req->req.dma;
u32 fifo = io_v2p ((u32)ep->reg_uddr);
/* caller guarantees there's a packet or more remaining
* - IN may end with a short packet (TSP set separately),
* - OUT is always full length
*/
buf += req->req.actual;
dcmd -= req->req.actual;
ep->dma_fixup = 0;
/* no-descriptor mode can be simple for bulk-in, iso-in, iso-out */
DCSR(ep->dma) = DCSR_NODESC;
if (is_in) {
DSADR(ep->dma) = buf;
DTADR(ep->dma) = fifo;
if (dcmd > MAX_IN_DMA)
dcmd = MAX_IN_DMA;
else
ep->dma_fixup = (dcmd % ep->ep.maxpacket) != 0;
dcmd |= DCMD_BURST32 | DCMD_WIDTH1
| DCMD_FLOWTRG | DCMD_INCSRCADDR;
} else {
#ifdef USE_OUT_DMA
DSADR(ep->dma) = fifo;
DTADR(ep->dma) = buf;
if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC)
dcmd = ep->ep.maxpacket;
dcmd |= DCMD_BURST32 | DCMD_WIDTH1
| DCMD_FLOWSRC | DCMD_INCTRGADDR;
#endif
}
DCMD(ep->dma) = dcmd;
DCSR(ep->dma) = DCSR_RUN | DCSR_NODESC
| (unlikely(is_in)
? DCSR_STOPIRQEN /* use dma_nodesc_handler() */
: 0); /* use handle_ep() */
}
static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req)
{
int is_in = ep->bEndpointAddress & USB_DIR_IN;
if (is_in) {
/* unaligned tx buffers and zlps only work with PIO */
if ((req->req.dma & 0x0f) != 0
|| unlikely((req->req.length - req->req.actual)
== 0)) {
pio_irq_enable(ep->bEndpointAddress);
if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0)
(void) write_fifo(ep, req);
} else {
start_dma_nodesc(ep, req, USB_DIR_IN);
}
} else {
if ((req->req.length - req->req.actual) < ep->ep.maxpacket) {
DMSG("%s short dma read...\n", ep->ep.name);
/* we're always set up for pio out */
read_fifo (ep, req);
} else {
*ep->reg_udccs = UDCCS_BO_DME
| (*ep->reg_udccs & UDCCS_BO_FST);
start_dma_nodesc(ep, req, USB_DIR_OUT);
}
}
}
static void cancel_dma(struct pxa2xx_ep *ep)
{
struct pxa2xx_request *req;
u32 tmp;
if (DCSR(ep->dma) == 0 || list_empty(&ep->queue))
return;
DCSR(ep->dma) = 0;
while ((DCSR(ep->dma) & DCSR_STOPSTATE) == 0)
cpu_relax();
req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
tmp = DCMD(ep->dma) & DCMD_LENGTH;
req->req.actual = req->req.length - (tmp & DCMD_LENGTH);
/* the last tx packet may be incomplete, so flush the fifo.
* FIXME correct req.actual if we can
*/
if (ep->bEndpointAddress & USB_DIR_IN)
*ep->reg_udccs = UDCCS_BI_FTF;
}
/* dma channel stopped ... normal tx end (IN), or on error (IN/OUT) */
static void dma_nodesc_handler(int dmach, void *_ep)
{
struct pxa2xx_ep *ep = _ep;
struct pxa2xx_request *req;
u32 tmp, completed;
local_irq_disable();
req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
ep->dma_irqs++;
ep->dev->stats.irqs++;
HEX_DISPLAY(ep->dev->stats.irqs);
/* ack/clear */
tmp = DCSR(ep->dma);
DCSR(ep->dma) = tmp;
if ((tmp & DCSR_STOPSTATE) == 0
|| (DDADR(ep->dma) & DDADR_STOP) != 0) {
DBG(DBG_VERBOSE, "%s, dcsr %08x ddadr %08x\n",
ep->ep.name, DCSR(ep->dma), DDADR(ep->dma));
goto done;
}
DCSR(ep->dma) = 0; /* clear DCSR_STOPSTATE */
/* update transfer status */
completed = tmp & DCSR_BUSERR;
if (ep->bEndpointAddress & USB_DIR_IN)
tmp = DSADR(ep->dma);
else
tmp = DTADR(ep->dma);
req->req.actual = tmp - req->req.dma;
/* FIXME seems we sometimes see partial transfers... */
if (unlikely(completed != 0))
req->req.status = -EIO;
else if (req->req.actual) {
/* these registers have zeroes in low bits; they miscount
* some (end-of-transfer) short packets: tx 14 as tx 12
*/
if (ep->dma_fixup)
req->req.actual = min(req->req.actual + 3,
req->req.length);
tmp = (req->req.length - req->req.actual);
completed = (tmp == 0);
if (completed && (ep->bEndpointAddress & USB_DIR_IN)) {
/* maybe validate final short packet ... */
if ((req->req.actual % ep->ep.maxpacket) != 0)
*ep->reg_udccs = UDCCS_BI_TSP/*|UDCCS_BI_TPC*/;
/* ... or zlp, using pio fallback */
else if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK
&& req->req.zero) {
DMSG("%s zlp terminate ...\n", ep->ep.name);
completed = 0;
}
}
}
if (likely(completed)) {
done(ep, req, 0);
/* maybe re-activate after completion */
if (ep->stopped || list_empty(&ep->queue))
goto done;
req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
}
kick_dma(ep, req);
done:
local_irq_enable();
}
#endif
/*-------------------------------------------------------------------------*/
static int
@ -942,17 +678,6 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
(ep->desc->wMaxPacketSize)))
return -EMSGSIZE;
#ifdef USE_DMA
// FIXME caller may already have done the dma mapping
if (ep->dma >= 0) {
_req->dma = dma_map_single(dev->dev,
_req->buf, _req->length,
((ep->bEndpointAddress & USB_DIR_IN) != 0)
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
}
#endif
DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
_ep->name, _req, _req->length, _req->buf);
@ -1002,11 +727,6 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
local_irq_restore (flags);
return -EL2HLT;
}
#ifdef USE_DMA
/* either start dma or prime pio pump */
} else if (ep->dma >= 0) {
kick_dma(ep, req);
#endif
/* can the FIFO can satisfy the request immediately? */
} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
@ -1017,7 +737,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req = NULL;
}
if (likely (req && ep->desc) && ep->dma < 0)
if (likely (req && ep->desc))
pio_irq_enable(ep->bEndpointAddress);
}
@ -1038,10 +758,6 @@ static void nuke(struct pxa2xx_ep *ep, int status)
struct pxa2xx_request *req;
/* called with irqs blocked */
#ifdef USE_DMA
if (ep->dma >= 0 && !ep->stopped)
cancel_dma(ep);
#endif
while (!list_empty(&ep->queue)) {
req = list_entry(ep->queue.next,
struct pxa2xx_request,
@ -1076,18 +792,6 @@ static int pxa2xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
return -EINVAL;
}
#ifdef USE_DMA
if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) {
cancel_dma(ep);
done(ep, req, -ECONNRESET);
/* restart i/o */
if (!list_empty(&ep->queue)) {
req = list_entry(ep->queue.next,
struct pxa2xx_request, queue);
kick_dma(ep, req);
}
} else
#endif
done(ep, req, -ECONNRESET);
local_irq_restore(flags);
@ -1203,9 +907,6 @@ static struct usb_ep_ops pxa2xx_ep_ops = {
.alloc_request = pxa2xx_ep_alloc_request,
.free_request = pxa2xx_ep_free_request,
.alloc_buffer = pxa2xx_ep_alloc_buffer,
.free_buffer = pxa2xx_ep_free_buffer,
.queue = pxa2xx_ep_queue,
.dequeue = pxa2xx_ep_dequeue,
@ -1325,7 +1026,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
/* basic device status */
t = scnprintf(next, size, DRIVER_DESC "\n"
"%s version: %s\nGadget driver: %s\nHost %s\n\n",
driver_name, DRIVER_VERSION SIZE_STR DMASTR,
driver_name, DRIVER_VERSION SIZE_STR "(pio)",
dev->driver ? dev->driver->driver.name : "(none)",
is_vbus_present() ? "full speed" : "disconnected");
size -= t;
@ -1390,7 +1091,6 @@ udc_proc_read(char *page, char **start, off_t off, int count,
for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
struct pxa2xx_ep *ep = &dev->ep [i];
struct pxa2xx_request *req;
int t;
if (i != 0) {
const struct usb_endpoint_descriptor *d;
@ -1400,10 +1100,9 @@ udc_proc_read(char *page, char **start, off_t off, int count,
continue;
tmp = *dev->ep [i].reg_udccs;
t = scnprintf(next, size,
"%s max %d %s udccs %02x irqs %lu/%lu\n",
"%s max %d %s udccs %02x irqs %lu\n",
ep->ep.name, le16_to_cpu (d->wMaxPacketSize),
(ep->dma >= 0) ? "dma" : "pio", tmp,
ep->pio_irqs, ep->dma_irqs);
"pio", tmp, ep->pio_irqs);
/* TODO translate all five groups of udccs bits! */
} else /* ep0 should only have one transfer queued */
@ -1423,18 +1122,6 @@ udc_proc_read(char *page, char **start, off_t off, int count,
continue;
}
list_for_each_entry(req, &ep->queue, queue) {
#ifdef USE_DMA
if (ep->dma >= 0 && req->queue.prev == &ep->queue)
t = scnprintf(next, size,
"\treq %p len %d/%d "
"buf %p (dma%d dcmd %08x)\n",
&req->req, req->req.actual,
req->req.length, req->req.buf,
ep->dma, DCMD(ep->dma)
// low 13 bits == bytes-to-go
);
else
#endif
t = scnprintf(next, size,
"\treq %p len %d/%d buf %p\n",
&req->req, req->req.actual,
@ -1488,7 +1175,6 @@ static void udc_disable(struct pxa2xx_udc *dev)
ep0_idle (dev);
dev->gadget.speed = USB_SPEED_UNKNOWN;
LED_CONNECTED_OFF;
}
@ -1514,7 +1200,7 @@ static void udc_reinit(struct pxa2xx_udc *dev)
ep->desc = NULL;
ep->stopped = 0;
INIT_LIST_HEAD (&ep->queue);
ep->pio_irqs = ep->dma_irqs = 0;
ep->pio_irqs = 0;
}
/* the rest was statically initialized, and is read-only */
@ -1666,7 +1352,6 @@ stop_activity(struct pxa2xx_udc *dev, struct usb_gadget_driver *driver)
del_timer_sync(&dev->timer);
/* report disconnect; the driver is already quiesced */
LED_CONNECTED_OFF;
if (driver)
driver->disconnect(&dev->gadget);
@ -1715,16 +1400,13 @@ lubbock_vbus_irq(int irq, void *_dev)
int vbus;
dev->stats.irqs++;
HEX_DISPLAY(dev->stats.irqs);
switch (irq) {
case LUBBOCK_USB_IRQ:
LED_CONNECTED_ON;
vbus = 1;
disable_irq(LUBBOCK_USB_IRQ);
enable_irq(LUBBOCK_USB_DISC_IRQ);
break;
case LUBBOCK_USB_DISC_IRQ:
LED_CONNECTED_OFF;
vbus = 0;
disable_irq(LUBBOCK_USB_DISC_IRQ);
enable_irq(LUBBOCK_USB_IRQ);
@ -1742,7 +1424,7 @@ lubbock_vbus_irq(int irq, void *_dev)
static irqreturn_t udc_vbus_irq(int irq, void *_dev)
{
struct pxa2xx_udc *dev = _dev;
int vbus = udc_gpio_get(dev->mach->gpio_vbus);
int vbus = gpio_get_value(dev->mach->gpio_vbus);
pxa2xx_udc_vbus_session(&dev->gadget, vbus);
return IRQ_HANDLED;
@ -2040,18 +1722,6 @@ static void handle_ep(struct pxa2xx_ep *ep)
/* fifos can hold packets, ready for reading... */
if (likely(req)) {
#ifdef USE_OUT_DMA
// TODO didn't yet debug out-dma. this approach assumes
// the worst about short packets and RPC; it might be better.
if (likely(ep->dma >= 0)) {
if (!(udccs & UDCCS_BO_RSP)) {
*ep->reg_udccs = UDCCS_BO_RPC;
ep->dma_irqs++;
return;
}
}
#endif
completed = read_fifo(ep, req);
} else
pio_irq_disable (ep->bEndpointAddress);
@ -2074,7 +1744,6 @@ pxa2xx_udc_irq(int irq, void *_dev)
int handled;
dev->stats.irqs++;
HEX_DISPLAY(dev->stats.irqs);
do {
u32 udccr = UDCCR;
@ -2125,7 +1794,6 @@ pxa2xx_udc_irq(int irq, void *_dev)
} else {
DBG(DBG_VERBOSE, "USB reset end\n");
dev->gadget.speed = USB_SPEED_FULL;
LED_CONNECTED_ON;
memset(&dev->stats, 0, sizeof dev->stats);
/* driver and endpoints are still reset */
}
@ -2217,7 +1885,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS1,
.reg_uddr = &UDDR1,
drcmr (25)
},
.ep[2] = {
.ep = {
@ -2232,7 +1899,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS2,
.reg_ubcr = &UBCR2,
.reg_uddr = &UDDR2,
drcmr (26)
},
#ifndef CONFIG_USB_PXA2XX_SMALL
.ep[3] = {
@ -2247,7 +1913,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS3,
.reg_uddr = &UDDR3,
drcmr (27)
},
.ep[4] = {
.ep = {
@ -2262,7 +1927,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS4,
.reg_ubcr = &UBCR4,
.reg_uddr = &UDDR4,
drcmr (28)
},
.ep[5] = {
.ep = {
@ -2291,7 +1955,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS6,
.reg_uddr = &UDDR6,
drcmr (30)
},
.ep[7] = {
.ep = {
@ -2306,7 +1969,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS7,
.reg_ubcr = &UBCR7,
.reg_uddr = &UDDR7,
drcmr (31)
},
.ep[8] = {
.ep = {
@ -2320,7 +1982,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS8,
.reg_uddr = &UDDR8,
drcmr (32)
},
.ep[9] = {
.ep = {
@ -2335,7 +1996,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS9,
.reg_ubcr = &UBCR9,
.reg_uddr = &UDDR9,
drcmr (33)
},
.ep[10] = {
.ep = {
@ -2364,7 +2024,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.reg_udccs = &UDCCS11,
.reg_uddr = &UDDR11,
drcmr (35)
},
.ep[12] = {
.ep = {
@ -2379,7 +2038,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS12,
.reg_ubcr = &UBCR12,
.reg_uddr = &UDDR12,
drcmr (36)
},
.ep[13] = {
.ep = {
@ -2393,7 +2051,6 @@ static struct pxa2xx_udc memory = {
.bmAttributes = USB_ENDPOINT_XFER_ISOC,
.reg_udccs = &UDCCS13,
.reg_uddr = &UDDR13,
drcmr (37)
},
.ep[14] = {
.ep = {
@ -2408,7 +2065,6 @@ static struct pxa2xx_udc memory = {
.reg_udccs = &UDCCS14,
.reg_ubcr = &UBCR14,
.reg_uddr = &UDDR14,
drcmr (38)
},
.ep[15] = {
.ep = {
@ -2466,7 +2122,7 @@ static struct pxa2xx_udc memory = {
static int __init pxa2xx_udc_probe(struct platform_device *pdev)
{
struct pxa2xx_udc *dev = &memory;
int retval, out_dma = 1, vbus_irq, irq;
int retval, vbus_irq, irq;
u32 chiprev;
/* insist on Intel/ARM/XScale */
@ -2489,7 +2145,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
case PXA250_B2: case PXA210_B2:
case PXA250_B1: case PXA210_B1:
case PXA250_B0: case PXA210_B0:
out_dma = 0;
/* OUT-DMA is broken ... */
/* fall through */
case PXA250_C0: case PXA210_C0:
break;
@ -2498,11 +2154,9 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
case IXP425_B0:
case IXP465_AD:
dev->has_cfr = 1;
out_dma = 0;
break;
#endif
default:
out_dma = 0;
printk(KERN_ERR "%s: unrecognized processor: %08x\n",
driver_name, chiprev);
/* iop3xx, ixp4xx, ... */
@ -2513,36 +2167,41 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
if (irq < 0)
return -ENODEV;
pr_debug("%s: IRQ %d%s%s%s\n", driver_name, irq,
pr_debug("%s: IRQ %d%s%s\n", driver_name, irq,
dev->has_cfr ? "" : " (!cfr)",
out_dma ? "" : " (broken dma-out)",
SIZE_STR DMASTR
SIZE_STR "(pio)"
);
#ifdef USE_DMA
#ifndef USE_OUT_DMA
out_dma = 0;
#endif
/* pxa 250 erratum 130 prevents using OUT dma (fixed C0) */
if (!out_dma) {
DMSG("disabled OUT dma\n");
dev->ep[ 2].reg_drcmr = dev->ep[ 4].reg_drcmr = 0;
dev->ep[ 7].reg_drcmr = dev->ep[ 9].reg_drcmr = 0;
dev->ep[12].reg_drcmr = dev->ep[14].reg_drcmr = 0;
}
#endif
/* other non-static parts of init */
dev->dev = &pdev->dev;
dev->mach = pdev->dev.platform_data;
if (dev->mach->gpio_vbus) {
udc_gpio_init_vbus(dev->mach->gpio_vbus);
vbus_irq = udc_gpio_to_irq(dev->mach->gpio_vbus);
if ((retval = gpio_request(dev->mach->gpio_vbus,
"pxa2xx_udc GPIO VBUS"))) {
dev_dbg(&pdev->dev,
"can't get vbus gpio %d, err: %d\n",
dev->mach->gpio_vbus, retval);
return -EBUSY;
}
gpio_direction_input(dev->mach->gpio_vbus);
vbus_irq = gpio_to_irq(dev->mach->gpio_vbus);
set_irq_type(vbus_irq, IRQT_BOTHEDGE);
} else
vbus_irq = 0;
if (dev->mach->gpio_pullup)
udc_gpio_init_pullup(dev->mach->gpio_pullup);
if (dev->mach->gpio_pullup) {
if ((retval = gpio_request(dev->mach->gpio_pullup,
"pca2xx_udc GPIO PULLUP"))) {
dev_dbg(&pdev->dev,
"can't get pullup gpio %d, err: %d\n",
dev->mach->gpio_pullup, retval);
if (dev->mach->gpio_vbus)
gpio_free(dev->mach->gpio_vbus);
return -EBUSY;
}
gpio_direction_output(dev->mach->gpio_pullup, 0);
}
init_timer(&dev->timer);
dev->timer.function = udc_watchdog;
@ -2566,6 +2225,10 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
if (retval != 0) {
printk(KERN_ERR "%s: can't get irq %d, err %d\n",
driver_name, irq, retval);
if (dev->mach->gpio_pullup)
gpio_free(dev->mach->gpio_pullup);
if (dev->mach->gpio_vbus)
gpio_free(dev->mach->gpio_vbus);
return -EBUSY;
}
dev->got_irq = 1;
@ -2581,6 +2244,10 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
driver_name, LUBBOCK_USB_DISC_IRQ, retval);
lubbock_fail0:
free_irq(irq, dev);
if (dev->mach->gpio_pullup)
gpio_free(dev->mach->gpio_pullup);
if (dev->mach->gpio_vbus)
gpio_free(dev->mach->gpio_vbus);
return -EBUSY;
}
retval = request_irq(LUBBOCK_USB_IRQ,
@ -2593,11 +2260,6 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
free_irq(LUBBOCK_USB_DISC_IRQ, dev);
goto lubbock_fail0;
}
#ifdef DEBUG
/* with U-Boot (but not BLOB), hex is off by default */
HEX_DISPLAY(dev->stats.irqs);
LUB_DISC_BLNK_LED &= 0xff;
#endif
} else
#endif
if (vbus_irq) {
@ -2608,6 +2270,10 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
printk(KERN_ERR "%s: can't get irq %i, err %d\n",
driver_name, vbus_irq, retval);
free_irq(irq, dev);
if (dev->mach->gpio_pullup)
gpio_free(dev->mach->gpio_pullup);
if (dev->mach->gpio_vbus)
gpio_free(dev->mach->gpio_vbus);
return -EBUSY;
}
}
@ -2641,8 +2307,13 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
free_irq(LUBBOCK_USB_IRQ, dev);
}
#endif
if (dev->mach->gpio_vbus)
free_irq(IRQ_GPIO(dev->mach->gpio_vbus), dev);
if (dev->mach->gpio_vbus) {
free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev);
gpio_free(dev->mach->gpio_vbus);
}
if (dev->mach->gpio_pullup)
gpio_free(dev->mach->gpio_pullup);
platform_set_drvdata(pdev, NULL);
the_controller = NULL;
return 0;

View file

@ -54,8 +54,6 @@ struct pxa2xx_ep {
const struct usb_endpoint_descriptor *desc;
struct list_head queue;
unsigned long pio_irqs;
unsigned long dma_irqs;
short dma;
unsigned short fifo_size;
u8 bEndpointAddress;
@ -72,12 +70,6 @@ struct pxa2xx_ep {
volatile u32 *reg_udccs;
volatile u32 *reg_ubcr;
volatile u32 *reg_uddr;
#ifdef USE_DMA
volatile u32 *reg_drcmr;
#define drcmr(n) .reg_drcmr = & DRCMR ## n ,
#else
#define drcmr(n)
#endif
};
struct pxa2xx_request {
@ -108,7 +100,6 @@ struct udc_stats {
#ifdef CONFIG_USB_PXA2XX_SMALL
/* when memory's tight, SMALL config saves code+data. */
#undef USE_DMA
#define PXA_UDC_NUM_ENDPOINTS 3
#endif
@ -144,37 +135,8 @@ struct pxa2xx_udc {
#ifdef CONFIG_ARCH_LUBBOCK
#include <asm/arch/lubbock.h>
/* lubbock can also report usb connect/disconnect irqs */
#ifdef DEBUG
#define HEX_DISPLAY(n) if (machine_is_lubbock()) { LUB_HEXLED = (n); }
#endif
#endif
/*-------------------------------------------------------------------------*/
/* LEDs are only for debug */
#ifndef HEX_DISPLAY
#define HEX_DISPLAY(n) do {} while(0)
#endif
#ifdef DEBUG
#include <asm/leds.h>
#define LED_CONNECTED_ON leds_event(led_green_on)
#define LED_CONNECTED_OFF do { \
leds_event(led_green_off); \
HEX_DISPLAY(0); \
} while(0)
#endif
#ifndef LED_CONNECTED_ON
#define LED_CONNECTED_ON do {} while(0)
#define LED_CONNECTED_OFF do {} while(0)
#endif
/*-------------------------------------------------------------------------*/
static struct pxa2xx_udc *the_controller;
/*-------------------------------------------------------------------------*/
@ -204,7 +166,7 @@ static const char *state_name[] = {
# define UDC_DEBUG DBG_NORMAL
#endif
static void __attribute__ ((__unused__))
static void __maybe_unused
dump_udccr(const char *label)
{
u32 udccr = UDCCR;
@ -220,7 +182,7 @@ dump_udccr(const char *label)
(udccr & UDCCR_UDE) ? " ude" : "");
}
static void __attribute__ ((__unused__))
static void __maybe_unused
dump_udccs0(const char *label)
{
u32 udccs0 = UDCCS0;
@ -237,7 +199,7 @@ dump_udccs0(const char *label)
(udccs0 & UDCCS0_OPR) ? " opr" : "");
}
static void __attribute__ ((__unused__))
static void __maybe_unused
dump_state(struct pxa2xx_udc *dev)
{
u32 tmp;

View file

@ -53,7 +53,7 @@
*/
#if 0
#define DEBUG(str,args...) do { \
#define DBG(str,args...) do { \
if (rndis_debug) \
printk(KERN_DEBUG str , ## args ); \
} while (0)
@ -65,7 +65,7 @@ MODULE_PARM_DESC (rndis_debug, "enable debugging");
#else
#define rndis_debug 0
#define DEBUG(str,args...) do{}while(0)
#define DBG(str,args...) do{}while(0)
#endif
#define RNDIS_MAX_CONFIGS 1
@ -183,9 +183,9 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
if (!resp) return -ENOMEM;
if (buf_len && rndis_debug > 1) {
DEBUG("query OID %08x value, len %d:\n", OID, buf_len);
DBG("query OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
DEBUG ("%03d: %08x %08x %08x %08x\n", i,
DBG("%03d: %08x %08x %08x %08x\n", i,
le32_to_cpu(get_unaligned((__le32 *)
&buf[i])),
le32_to_cpu(get_unaligned((__le32 *)
@ -207,7 +207,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_SUPPORTED_LIST:
DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
DBG("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
length = sizeof (oid_supported_list);
count = length / sizeof (u32);
for (i = 0; i < count; i++)
@ -217,7 +217,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_HARDWARE_STATUS:
DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
DBG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
/* Bogus question!
* Hardware must be ready to receive high level protocols.
* BTW:
@ -230,14 +230,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_MEDIA_SUPPORTED:
DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
DBG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
retval = 0;
break;
/* mandatory */
case OID_GEN_MEDIA_IN_USE:
DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
DBG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
/* one medium, one transport... (maybe you do it better) */
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
retval = 0;
@ -245,7 +245,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_MAXIMUM_FRAME_SIZE:
DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
DBG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
@ -256,7 +256,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_LINK_SPEED:
if (rndis_debug > 1)
DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
DBG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].media_state
== NDIS_MEDIA_STATE_DISCONNECTED)
*outbuf = __constant_cpu_to_le32 (0);
@ -268,7 +268,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_TRANSMIT_BLOCK_SIZE:
DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
DBG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
@ -278,7 +278,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RECEIVE_BLOCK_SIZE:
DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
DBG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
@ -288,7 +288,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_VENDOR_ID:
DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
DBG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].vendorID);
retval = 0;
@ -296,7 +296,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_VENDOR_DESCRIPTION:
DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
DBG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
length = strlen (rndis_per_dev_params [configNr].vendorDescr);
memcpy (outbuf,
rndis_per_dev_params [configNr].vendorDescr, length);
@ -304,7 +304,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_VENDOR_DRIVER_VERSION:
DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
DBG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
/* Created as LE */
*outbuf = rndis_driver_version;
retval = 0;
@ -312,14 +312,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_CURRENT_PACKET_FILTER:
DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
DBG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
*outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter);
retval = 0;
break;
/* mandatory */
case OID_GEN_MAXIMUM_TOTAL_SIZE:
DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
DBG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
retval = 0;
break;
@ -327,14 +327,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_MEDIA_CONNECT_STATUS:
if (rndis_debug > 1)
DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
DBG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.media_state);
retval = 0;
break;
case OID_GEN_PHYSICAL_MEDIUM:
DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
DBG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
@ -344,7 +344,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
* versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
*/
case OID_GEN_MAC_OPTIONS: /* from WinME */
DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
DBG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32(
NDIS_MAC_OPTION_RECEIVE_SERIALIZED
| NDIS_MAC_OPTION_FULL_DUPLEX);
@ -356,7 +356,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_XMIT_OK:
if (rndis_debug > 1)
DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
DBG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].stats->tx_packets -
@ -369,7 +369,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RCV_OK:
if (rndis_debug > 1)
DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
DBG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].stats->rx_packets -
@ -382,7 +382,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_XMIT_ERROR:
if (rndis_debug > 1)
DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
DBG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_errors);
@ -393,7 +393,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RCV_ERROR:
if (rndis_debug > 1)
DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
DBG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_errors);
@ -403,7 +403,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_GEN_RCV_NO_BUFFER:
DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
DBG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_dropped);
@ -413,7 +413,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
#ifdef RNDIS_OPTIONAL_STATS
case OID_GEN_DIRECTED_BYTES_XMIT:
DEBUG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__);
DBG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__);
/*
* Aunt Tilly's size of shoes
* minus antarctica count of penguins
@ -433,7 +433,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_DIRECTED_FRAMES_XMIT:
DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
DBG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
/* dito */
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (
@ -449,7 +449,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_MULTICAST_BYTES_XMIT:
DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
DBG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast*1234);
@ -458,7 +458,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_MULTICAST_FRAMES_XMIT:
DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
DBG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast);
@ -467,7 +467,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_BYTES_XMIT:
DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
DBG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_packets/42*255);
@ -476,7 +476,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_FRAMES_XMIT:
DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
DBG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_packets/42);
@ -485,19 +485,19 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_DIRECTED_BYTES_RCV:
DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
DBG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_DIRECTED_FRAMES_RCV:
DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
DBG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_MULTICAST_BYTES_RCV:
DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
DBG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast * 1111);
@ -506,7 +506,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_MULTICAST_FRAMES_RCV:
DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
DBG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast);
@ -515,7 +515,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_BYTES_RCV:
DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
DBG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42*255);
@ -524,7 +524,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_BROADCAST_FRAMES_RCV:
DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
DBG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42);
@ -533,7 +533,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_RCV_CRC_ERROR:
DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
DBG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_crc_errors);
@ -542,7 +542,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
break;
case OID_GEN_TRANSMIT_QUEUE_LENGTH:
DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
DBG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
@ -552,7 +552,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_PERMANENT_ADDRESS:
DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
DBG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
memcpy (outbuf,
@ -564,7 +564,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_CURRENT_ADDRESS:
DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
DBG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
memcpy (outbuf,
@ -576,7 +576,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_MULTICAST_LIST:
DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
/* Multicast base address only */
*outbuf = __constant_cpu_to_le32 (0xE0000000);
retval = 0;
@ -584,21 +584,21 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_MAXIMUM_LIST_SIZE:
DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
DBG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
/* Multicast base address only */
*outbuf = __constant_cpu_to_le32 (1);
retval = 0;
break;
case OID_802_3_MAC_OPTIONS:
DEBUG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__);
DBG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__);
break;
/* ieee802.3 statistics OIDs (table 4-4) */
/* mandatory */
case OID_802_3_RCV_ERROR_ALIGNMENT:
DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
DBG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_frame_errors);
@ -608,51 +608,51 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
/* mandatory */
case OID_802_3_XMIT_ONE_COLLISION:
DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
DBG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
/* mandatory */
case OID_802_3_XMIT_MORE_COLLISIONS:
DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
DBG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
#ifdef RNDIS_OPTIONAL_STATS
case OID_802_3_XMIT_DEFERRED:
DEBUG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__);
DBG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_MAX_COLLISIONS:
DEBUG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__);
DBG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_RCV_OVERRUN:
DEBUG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__);
DBG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_UNDERRUN:
DEBUG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__);
DBG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_HEARTBEAT_FAILURE:
DEBUG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__);
DBG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_TIMES_CRS_LOST:
DEBUG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__);
DBG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__);
/* TODO */
break;
case OID_802_3_XMIT_LATE_COLLISIONS:
DEBUG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__);
DBG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__);
/* TODO */
break;
#endif /* RNDIS_OPTIONAL_STATS */
@ -660,7 +660,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
#ifdef RNDIS_PM
/* power management OIDs (table 4-5) */
case OID_PNP_CAPABILITIES:
DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
DBG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
/* for now, no wakeup capabilities */
length = sizeof (struct NDIS_PNP_CAPABILITIES);
@ -668,7 +668,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
retval = 0;
break;
case OID_PNP_QUERY_POWER:
DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
DBG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
le32_to_cpu(get_unaligned((__le32 *)buf)) - 1);
/* only suspend is a real power state, and
* it can't be entered by OID_PNP_SET_POWER...
@ -705,9 +705,9 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
return -ENOMEM;
if (buf_len && rndis_debug > 1) {
DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
DBG("set OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
DEBUG ("%03d: %08x %08x %08x %08x\n", i,
DBG("%03d: %08x %08x %08x %08x\n", i,
le32_to_cpu(get_unaligned((__le32 *)
&buf[i])),
le32_to_cpu(get_unaligned((__le32 *)
@ -731,7 +731,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
*/
*params->filter = (u16) le32_to_cpu(get_unaligned(
(__le32 *)buf));
DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
DBG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
__FUNCTION__, *params->filter);
/* this call has a significant side effect: it's
@ -756,7 +756,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
case OID_802_3_MULTICAST_LIST:
/* I think we can ignore this */
DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
retval = 0;
break;
#if 0
@ -764,7 +764,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
{
struct rndis_config_parameter *param;
param = (struct rndis_config_parameter *) buf;
DEBUG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
DBG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
__FUNCTION__,
min(cpu_to_le32(param->ParameterNameLength),80),
buf + param->ParameterNameOffset);
@ -781,7 +781,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
* FIXME ... then things go batty; Windows wedges itself.
*/
i = le32_to_cpu(get_unaligned((__le32 *)buf));
DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
DBG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
switch (i) {
case NdisDeviceStateD0:
*params->filter = params->saved_filter;
@ -858,7 +858,7 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
rndis_query_cmplt_type *resp;
rndis_resp_t *r;
// DEBUG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID));
// DBG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID));
if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
/*
@ -911,15 +911,15 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
BufOffset = le32_to_cpu (buf->InformationBufferOffset);
#ifdef VERBOSE
DEBUG("%s: Length: %d\n", __FUNCTION__, BufLength);
DEBUG("%s: Offset: %d\n", __FUNCTION__, BufOffset);
DEBUG("%s: InfoBuffer: ", __FUNCTION__);
DBG("%s: Length: %d\n", __FUNCTION__, BufLength);
DBG("%s: Offset: %d\n", __FUNCTION__, BufOffset);
DBG("%s: InfoBuffer: ", __FUNCTION__);
for (i = 0; i < BufLength; i++) {
DEBUG ("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
DBG("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
}
DEBUG ("\n");
DBG("\n");
#endif
resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT);
@ -1082,14 +1082,14 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
/* For USB: responses may take up to 10 seconds */
switch (MsgType) {
case REMOTE_NDIS_INITIALIZE_MSG:
DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
DBG("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
__FUNCTION__ );
params->state = RNDIS_INITIALIZED;
return rndis_init_response (configNr,
(rndis_init_msg_type *) buf);
case REMOTE_NDIS_HALT_MSG:
DEBUG("%s: REMOTE_NDIS_HALT_MSG\n",
DBG("%s: REMOTE_NDIS_HALT_MSG\n",
__FUNCTION__ );
params->state = RNDIS_UNINITIALIZED;
if (params->dev) {
@ -1107,7 +1107,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
(rndis_set_msg_type *) buf);
case REMOTE_NDIS_RESET_MSG:
DEBUG("%s: REMOTE_NDIS_RESET_MSG\n",
DBG("%s: REMOTE_NDIS_RESET_MSG\n",
__FUNCTION__ );
return rndis_reset_response (configNr,
(rndis_reset_msg_type *) buf);
@ -1115,7 +1115,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
case REMOTE_NDIS_KEEPALIVE_MSG:
/* For USB: host does this every 5 seconds */
if (rndis_debug > 1)
DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
DBG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
__FUNCTION__ );
return rndis_keepalive_response (configNr,
(rndis_keepalive_msg_type *)
@ -1132,7 +1132,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
{
unsigned i;
for (i = 0; i < MsgLength; i += 16) {
DEBUG ("%03d: "
DBG("%03d: "
" %02x %02x %02x %02x"
" %02x %02x %02x %02x"
" %02x %02x %02x %02x"
@ -1163,18 +1163,18 @@ int rndis_register (int (* rndis_control_ack) (struct net_device *))
if (!rndis_per_dev_params [i].used) {
rndis_per_dev_params [i].used = 1;
rndis_per_dev_params [i].ack = rndis_control_ack;
DEBUG("%s: configNr = %d\n", __FUNCTION__, i);
DBG("%s: configNr = %d\n", __FUNCTION__, i);
return i;
}
}
DEBUG("failed\n");
DBG("failed\n");
return -1;
}
void rndis_deregister (int configNr)
{
DEBUG("%s: \n", __FUNCTION__ );
DBG("%s: \n", __FUNCTION__ );
if (configNr >= RNDIS_MAX_CONFIGS) return;
rndis_per_dev_params [configNr].used = 0;
@ -1186,7 +1186,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
struct net_device_stats *stats,
u16 *cdc_filter)
{
DEBUG("%s:\n", __FUNCTION__ );
DBG("%s:\n", __FUNCTION__ );
if (!dev || !stats) return -1;
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
@ -1199,7 +1199,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
{
DEBUG("%s:\n", __FUNCTION__ );
DBG("%s:\n", __FUNCTION__ );
if (!vendorDescr) return -1;
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
@ -1211,7 +1211,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
{
DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed);
DBG("%s: %u %u\n", __FUNCTION__, medium, speed);
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
rndis_per_dev_params [configNr].medium = medium;
@ -1390,7 +1390,7 @@ static int rndis_proc_write (struct file *file, const char __user *buffer,
break;
default:
if (fl_speed) p->speed = speed;
else DEBUG ("%c is not valid\n", c);
else DBG("%c is not valid\n", c);
break;
}
@ -1419,12 +1419,12 @@ int __devinit rndis_init (void)
if (!(rndis_connect_state [i]
= create_proc_entry (name, 0660, NULL)))
{
DEBUG ("%s :remove entries", __FUNCTION__);
DBG("%s :remove entries", __FUNCTION__);
while (i) {
sprintf (name, NAME_TEMPLATE, --i);
remove_proc_entry (name, NULL);
}
DEBUG ("\n");
DBG("\n");
return -EIO;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,110 @@
/*
* linux/drivers/usb/gadget/s3c2410_udc.h
* Samsung on-chip full speed USB device controllers
*
* Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard
* Additional cleanups by Ben Dooks <ben-linux@fluff.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef _S3C2410_UDC_H
#define _S3C2410_UDC_H
struct s3c2410_ep {
struct list_head queue;
unsigned long last_io; /* jiffies timestamp */
struct usb_gadget *gadget;
struct s3c2410_udc *dev;
const struct usb_endpoint_descriptor *desc;
struct usb_ep ep;
u8 num;
unsigned short fifo_size;
u8 bEndpointAddress;
u8 bmAttributes;
unsigned halted : 1;
unsigned already_seen : 1;
unsigned setup_stage : 1;
};
/* Warning : ep0 has a fifo of 16 bytes */
/* Don't try to set 32 or 64 */
/* also testusb 14 fails wit 16 but is */
/* fine with 8 */
#define EP0_FIFO_SIZE 8
#define EP_FIFO_SIZE 64
#define DEFAULT_POWER_STATE 0x00
#define S3C2440_EP_FIFO_SIZE 128
static const char ep0name [] = "ep0";
static const char *const ep_name[] = {
ep0name, /* everyone has ep0 */
/* s3c2410 four bidirectional bulk endpoints */
"ep1-bulk", "ep2-bulk", "ep3-bulk", "ep4-bulk",
};
#define S3C2410_ENDPOINTS ARRAY_SIZE(ep_name)
struct s3c2410_request {
struct list_head queue; /* ep's requests */
struct usb_request req;
};
enum ep0_state {
EP0_IDLE,
EP0_IN_DATA_PHASE,
EP0_OUT_DATA_PHASE,
EP0_END_XFER,
EP0_STALL,
};
static const char *ep0states[]= {
"EP0_IDLE",
"EP0_IN_DATA_PHASE",
"EP0_OUT_DATA_PHASE",
"EP0_END_XFER",
"EP0_STALL",
};
struct s3c2410_udc {
spinlock_t lock;
struct s3c2410_ep ep[S3C2410_ENDPOINTS];
int address;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct s3c2410_request fifo_req;
u8 fifo_buf[EP_FIFO_SIZE];
u16 devstatus;
u32 port_status;
int ep0state;
unsigned got_irq : 1;
unsigned req_std : 1;
unsigned req_config : 1;
unsigned req_pending : 1;
u8 vbus;
struct dentry *regs_info;
};
#endif

View file

@ -2215,7 +2215,7 @@ static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags)
*
* Free the buffer and all associated memory.
*/
void gs_buf_free(struct gs_buf *gb)
static void gs_buf_free(struct gs_buf *gb)
{
if (gb) {
kfree(gb->buf_buf);
@ -2228,7 +2228,7 @@ void gs_buf_free(struct gs_buf *gb)
*
* Clear out all data in the circular buffer.
*/
void gs_buf_clear(struct gs_buf *gb)
static void gs_buf_clear(struct gs_buf *gb)
{
if (gb != NULL)
gb->buf_get = gb->buf_put;
@ -2241,7 +2241,7 @@ void gs_buf_clear(struct gs_buf *gb)
* Return the number of bytes of data available in the circular
* buffer.
*/
unsigned int gs_buf_data_avail(struct gs_buf *gb)
static unsigned int gs_buf_data_avail(struct gs_buf *gb)
{
if (gb != NULL)
return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
@ -2255,7 +2255,7 @@ unsigned int gs_buf_data_avail(struct gs_buf *gb)
* Return the number of bytes of space available in the circular
* buffer.
*/
unsigned int gs_buf_space_avail(struct gs_buf *gb)
static unsigned int gs_buf_space_avail(struct gs_buf *gb)
{
if (gb != NULL)
return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
@ -2271,7 +2271,8 @@ unsigned int gs_buf_space_avail(struct gs_buf *gb)
*
* Return the number of bytes copied.
*/
unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
static unsigned int
gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
{
unsigned int len;
@ -2309,7 +2310,8 @@ unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
*
* Return the number of bytes copied.
*/
unsigned int gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
static unsigned int
gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
{
unsigned int len;

View file

@ -481,8 +481,7 @@ alloc_ep_req (struct usb_ep *ep, unsigned length)
req = usb_ep_alloc_request (ep, GFP_ATOMIC);
if (req) {
req->length = length;
req->buf = usb_ep_alloc_buffer (ep, length,
&req->dma, GFP_ATOMIC);
req->buf = kmalloc(length, GFP_ATOMIC);
if (!req->buf) {
usb_ep_free_request (ep, req);
req = NULL;
@ -493,8 +492,7 @@ alloc_ep_req (struct usb_ep *ep, unsigned length)
static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
{
if (req->buf)
usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
kfree(req->buf);
usb_ep_free_request (ep, req);
}
@ -1199,8 +1197,7 @@ zero_bind (struct usb_gadget *gadget)
dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
if (!dev->req)
goto enomem;
dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
&dev->req->dma, GFP_KERNEL);
dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
if (!dev->req->buf)
goto enomem;

View file

@ -69,8 +69,20 @@ config USB_EHCI_TT_NEWSCHED
config USB_EHCI_BIG_ENDIAN_MMIO
bool
depends on USB_EHCI_HCD
default n
depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX)
default y
config USB_EHCI_BIG_ENDIAN_DESC
bool
depends on USB_EHCI_HCD && 440EPX
default y
config USB_EHCI_FSL
bool
select USB_EHCI_ROOT_HUB_TT
default y if MPC834x || PPC_MPC831x
---help---
Variation of ARC USB block used in some Freescale chips.
config USB_ISP116X_HCD
tristate "ISP116X HCD support"
@ -224,3 +236,15 @@ config USB_SL811_CS
To compile this driver as a module, choose M here: the
module will be called "sl811_cs".
config USB_R8A66597_HCD
tristate "R8A66597 HCD suppoort"
depends on USB
help
The R8A66597 is a USB 2.0 host and peripheral controller.
Enable this option if your board has this chip, and you want
to use it as a host controller. If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called r8a66597-hcd.

View file

@ -15,3 +15,5 @@ obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o

View file

@ -115,23 +115,23 @@ static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
#ifdef DEBUG
static void __attribute__((__unused__))
static void __maybe_unused
dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
{
ehci_dbg(ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
le32_to_cpup (&qtd->hw_next),
le32_to_cpup (&qtd->hw_alt_next),
le32_to_cpup (&qtd->hw_token),
le32_to_cpup (&qtd->hw_buf [0]));
hc32_to_cpup(ehci, &qtd->hw_next),
hc32_to_cpup(ehci, &qtd->hw_alt_next),
hc32_to_cpup(ehci, &qtd->hw_token),
hc32_to_cpup(ehci, &qtd->hw_buf [0]));
if (qtd->hw_buf [1])
ehci_dbg(ehci, " p1=%08x p2=%08x p3=%08x p4=%08x\n",
le32_to_cpup (&qtd->hw_buf [1]),
le32_to_cpup (&qtd->hw_buf [2]),
le32_to_cpup (&qtd->hw_buf [3]),
le32_to_cpup (&qtd->hw_buf [4]));
hc32_to_cpup(ehci, &qtd->hw_buf[1]),
hc32_to_cpup(ehci, &qtd->hw_buf[2]),
hc32_to_cpup(ehci, &qtd->hw_buf[3]),
hc32_to_cpup(ehci, &qtd->hw_buf[4]));
}
static void __attribute__((__unused__))
static void __maybe_unused
dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
{
ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label,
@ -140,51 +140,53 @@ dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next);
}
static void __attribute__((__unused__))
static void __maybe_unused
dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
{
ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n",
label, itd->frame, itd, le32_to_cpu(itd->hw_next), itd->urb);
label, itd->frame, itd, hc32_to_cpu(ehci, itd->hw_next),
itd->urb);
ehci_dbg (ehci,
" trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
le32_to_cpu(itd->hw_transaction[0]),
le32_to_cpu(itd->hw_transaction[1]),
le32_to_cpu(itd->hw_transaction[2]),
le32_to_cpu(itd->hw_transaction[3]),
le32_to_cpu(itd->hw_transaction[4]),
le32_to_cpu(itd->hw_transaction[5]),
le32_to_cpu(itd->hw_transaction[6]),
le32_to_cpu(itd->hw_transaction[7]));
hc32_to_cpu(ehci, itd->hw_transaction[0]),
hc32_to_cpu(ehci, itd->hw_transaction[1]),
hc32_to_cpu(ehci, itd->hw_transaction[2]),
hc32_to_cpu(ehci, itd->hw_transaction[3]),
hc32_to_cpu(ehci, itd->hw_transaction[4]),
hc32_to_cpu(ehci, itd->hw_transaction[5]),
hc32_to_cpu(ehci, itd->hw_transaction[6]),
hc32_to_cpu(ehci, itd->hw_transaction[7]));
ehci_dbg (ehci,
" buf: %08x %08x %08x %08x %08x %08x %08x\n",
le32_to_cpu(itd->hw_bufp[0]),
le32_to_cpu(itd->hw_bufp[1]),
le32_to_cpu(itd->hw_bufp[2]),
le32_to_cpu(itd->hw_bufp[3]),
le32_to_cpu(itd->hw_bufp[4]),
le32_to_cpu(itd->hw_bufp[5]),
le32_to_cpu(itd->hw_bufp[6]));
hc32_to_cpu(ehci, itd->hw_bufp[0]),
hc32_to_cpu(ehci, itd->hw_bufp[1]),
hc32_to_cpu(ehci, itd->hw_bufp[2]),
hc32_to_cpu(ehci, itd->hw_bufp[3]),
hc32_to_cpu(ehci, itd->hw_bufp[4]),
hc32_to_cpu(ehci, itd->hw_bufp[5]),
hc32_to_cpu(ehci, itd->hw_bufp[6]));
ehci_dbg (ehci, " index: %d %d %d %d %d %d %d %d\n",
itd->index[0], itd->index[1], itd->index[2],
itd->index[3], itd->index[4], itd->index[5],
itd->index[6], itd->index[7]);
}
static void __attribute__((__unused__))
static void __maybe_unused
dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
{
ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
label, sitd->frame, sitd, le32_to_cpu(sitd->hw_next), sitd->urb);
label, sitd->frame, sitd, hc32_to_cpu(ehci, sitd->hw_next),
sitd->urb);
ehci_dbg (ehci,
" addr %08x sched %04x result %08x buf %08x %08x\n",
le32_to_cpu(sitd->hw_fullspeed_ep),
le32_to_cpu(sitd->hw_uframe),
le32_to_cpu(sitd->hw_results),
le32_to_cpu(sitd->hw_buf [0]),
le32_to_cpu(sitd->hw_buf [1]));
hc32_to_cpu(ehci, sitd->hw_fullspeed_ep),
hc32_to_cpu(ehci, sitd->hw_uframe),
hc32_to_cpu(ehci, sitd->hw_results),
hc32_to_cpu(ehci, sitd->hw_buf[0]),
hc32_to_cpu(ehci, sitd->hw_buf[1]));
}
static int __attribute__((__unused__))
static int __maybe_unused
dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
{
return scnprintf (buf, len,
@ -203,7 +205,7 @@ dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
);
}
static int __attribute__((__unused__))
static int __maybe_unused
dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
{
return scnprintf (buf, len,
@ -267,28 +269,27 @@ dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
(status & PORT_PEC) ? " PEC" : "",
(status & PORT_PE) ? " PE" : "",
(status & PORT_CSC) ? " CSC" : "",
(status & PORT_CONNECT) ? " CONNECT" : ""
);
(status & PORT_CONNECT) ? " CONNECT" : "");
}
#else
static inline void __attribute__((__unused__))
static inline void __maybe_unused
dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
{}
static inline int __attribute__((__unused__))
static inline int __maybe_unused
dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
{ return 0; }
static inline int __attribute__((__unused__))
static inline int __maybe_unused
dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
{ return 0; }
static inline int __attribute__((__unused__))
static inline int __maybe_unused
dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
{ return 0; }
static inline int __attribute__((__unused__))
static inline int __maybe_unused
dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
{ return 0; }
@ -332,9 +333,10 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
default: tmp = '?'; break; \
}; tmp; })
static inline char token_mark (__le32 token)
static inline char token_mark(struct ehci_hcd *ehci, __hc32 token)
{
__u32 v = le32_to_cpu (token);
__u32 v = hc32_to_cpu(ehci, token);
if (v & QTD_STS_ACTIVE)
return '*';
if (v & QTD_STS_HALT)
@ -360,46 +362,48 @@ static void qh_lines (
unsigned size = *sizep;
char *next = *nextp;
char mark;
u32 list_end = EHCI_LIST_END(ehci);
if (qh->hw_qtd_next == EHCI_LIST_END) /* NEC does this */
if (qh->hw_qtd_next == list_end) /* NEC does this */
mark = '@';
else
mark = token_mark (qh->hw_token);
mark = token_mark(ehci, qh->hw_token);
if (mark == '/') { /* qh_alt_next controls qh advance? */
if ((qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next)
if ((qh->hw_alt_next & QTD_MASK(ehci))
== ehci->async->hw_alt_next)
mark = '#'; /* blocked */
else if (qh->hw_alt_next == EHCI_LIST_END)
else if (qh->hw_alt_next == list_end)
mark = '.'; /* use hw_qtd_next */
/* else alt_next points to some other qtd */
}
scratch = le32_to_cpup (&qh->hw_info1);
hw_curr = (mark == '*') ? le32_to_cpup (&qh->hw_current) : 0;
scratch = hc32_to_cpup(ehci, &qh->hw_info1);
hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &qh->hw_current) : 0;
temp = scnprintf (next, size,
"qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
qh, scratch & 0x007f,
speed_char (scratch),
(scratch >> 8) & 0x000f,
scratch, le32_to_cpup (&qh->hw_info2),
le32_to_cpup (&qh->hw_token), mark,
(__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token)
scratch, hc32_to_cpup(ehci, &qh->hw_info2),
hc32_to_cpup(ehci, &qh->hw_token), mark,
(cpu_to_hc32(ehci, QTD_TOGGLE) & qh->hw_token)
? "data1" : "data0",
(le32_to_cpup (&qh->hw_alt_next) >> 1) & 0x0f);
(hc32_to_cpup(ehci, &qh->hw_alt_next) >> 1) & 0x0f);
size -= temp;
next += temp;
/* hc may be modifying the list as we read it ... */
list_for_each (entry, &qh->qtd_list) {
td = list_entry (entry, struct ehci_qtd, qtd_list);
scratch = le32_to_cpup (&td->hw_token);
scratch = hc32_to_cpup(ehci, &td->hw_token);
mark = ' ';
if (hw_curr == td->qtd_dma)
mark = '*';
else if (qh->hw_qtd_next == cpu_to_le32(td->qtd_dma))
else if (qh->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma))
mark = '+';
else if (QTD_LENGTH (scratch)) {
if (td->hw_alt_next == ehci->async->hw_alt_next)
mark = '#';
else if (td->hw_alt_next != EHCI_LIST_END)
else if (td->hw_alt_next != list_end)
mark = '/';
}
temp = snprintf (next, size,
@ -490,7 +494,7 @@ show_periodic (struct class_device *class_dev, char *buf)
unsigned temp, size, seen_count;
char *next;
unsigned i;
__le32 tag;
__hc32 tag;
if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC)))
return 0;
@ -514,18 +518,19 @@ show_periodic (struct class_device *class_dev, char *buf)
p = ehci->pshadow [i];
if (likely (!p.ptr))
continue;
tag = Q_NEXT_TYPE (ehci->periodic [i]);
tag = Q_NEXT_TYPE(ehci, ehci->periodic [i]);
temp = scnprintf (next, size, "%4d: ", i);
size -= temp;
next += temp;
do {
switch (tag) {
switch (hc32_to_cpu(ehci, tag)) {
case Q_TYPE_QH:
temp = scnprintf (next, size, " qh%d-%04x/%p",
p.qh->period,
le32_to_cpup (&p.qh->hw_info2)
hc32_to_cpup(ehci,
&p.qh->hw_info2)
/* uframe masks */
& (QH_CMASK | QH_SMASK),
p.qh);
@ -543,7 +548,7 @@ show_periodic (struct class_device *class_dev, char *buf)
}
/* show more info the first time around */
if (temp == seen_count && p.ptr) {
u32 scratch = le32_to_cpup (
u32 scratch = hc32_to_cpup(ehci,
&p.qh->hw_info1);
struct ehci_qtd *qtd;
char *type = "";
@ -554,7 +559,8 @@ show_periodic (struct class_device *class_dev, char *buf)
&p.qh->qtd_list,
qtd_list) {
temp++;
switch (0x03 & (le32_to_cpu (
switch (0x03 & (hc32_to_cpu(
ehci,
qtd->hw_token) >> 8)) {
case 0: type = "out"; continue;
case 1: type = "in"; continue;
@ -576,7 +582,7 @@ show_periodic (struct class_device *class_dev, char *buf)
} else
temp = 0;
if (p.qh) {
tag = Q_NEXT_TYPE (p.qh->hw_next);
tag = Q_NEXT_TYPE(ehci, p.qh->hw_next);
p = p.qh->qh_next;
}
break;
@ -584,23 +590,23 @@ show_periodic (struct class_device *class_dev, char *buf)
temp = scnprintf (next, size,
" fstn-%8x/%p", p.fstn->hw_prev,
p.fstn);
tag = Q_NEXT_TYPE (p.fstn->hw_next);
tag = Q_NEXT_TYPE(ehci, p.fstn->hw_next);
p = p.fstn->fstn_next;
break;
case Q_TYPE_ITD:
temp = scnprintf (next, size,
" itd/%p", p.itd);
tag = Q_NEXT_TYPE (p.itd->hw_next);
tag = Q_NEXT_TYPE(ehci, p.itd->hw_next);
p = p.itd->itd_next;
break;
case Q_TYPE_SITD:
temp = scnprintf (next, size,
" sitd%d-%04x/%p",
p.sitd->stream->interval,
le32_to_cpup (&p.sitd->hw_uframe)
hc32_to_cpup(ehci, &p.sitd->hw_uframe)
& 0x0000ffff,
p.sitd);
tag = Q_NEXT_TYPE (p.sitd->hw_next);
tag = Q_NEXT_TYPE(ehci, p.sitd->hw_next);
p = p.sitd->sitd_next;
break;
}
@ -673,7 +679,8 @@ show_registers (struct class_device *class_dev, char *buf)
unsigned count = 256/4;
pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params));
offset = HCC_EXT_CAPS(ehci_readl(ehci,
&ehci->caps->hcc_params));
while (offset && count--) {
pci_read_config_dword (pdev, offset, &cap);
switch (cap & 0xff) {
@ -740,14 +747,16 @@ show_registers (struct class_device *class_dev, char *buf)
for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
temp = dbg_port_buf (scratch, sizeof scratch, label, i,
ehci_readl(ehci, &ehci->regs->port_status [i - 1]));
ehci_readl(ehci,
&ehci->regs->port_status[i - 1]));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
temp = scnprintf (next, size,
" debug control %08x\n",
ehci_readl(ehci, &ehci->debug->control));
ehci_readl(ehci,
&ehci->debug->control));
size -= temp;
next += temp;
}

View file

@ -67,7 +67,8 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
* in host mode.
*/
if (!((pdata->operating_mode == FSL_USB2_DR_HOST) ||
(pdata->operating_mode == FSL_USB2_MPH_HOST))) {
(pdata->operating_mode == FSL_USB2_MPH_HOST) ||
(pdata->operating_mode == FSL_USB2_DR_OTG))) {
dev_err(&pdev->dev,
"Non Host Mode configured for %s. Wrong driver linked.\n",
pdev->dev.bus_id);
@ -185,12 +186,14 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct fsl_usb2_platform_data *pdata;
void __iomem *non_ehci = hcd->regs;
u32 temp;
pdata =
(struct fsl_usb2_platform_data *)hcd->self.controller->
platform_data;
/* Enable PHY interface in the control reg. */
out_be32(non_ehci + FSL_SOC_USB_CTRL, 0x00000004);
temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
@ -206,7 +209,8 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
#endif
if (pdata->operating_mode == FSL_USB2_DR_HOST)
if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
(pdata->operating_mode == FSL_USB2_DR_OTG))
mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
if (pdata->operating_mode == FSL_USB2_MPH_HOST) {

View file

@ -41,10 +41,6 @@
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
#ifdef CONFIG_PPC_PS3
#include <asm/firmware.h>
#endif
/*-------------------------------------------------------------------------*/
@ -201,9 +197,15 @@ static void tdi_reset (struct ehci_hcd *ehci)
u32 __iomem *reg_ptr;
u32 tmp;
reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE);
tmp = ehci_readl(ehci, reg_ptr);
tmp |= 0x3;
tmp |= USBMODE_CM_HC;
/* The default byte access to MMR space is LE after
* controller reset. Set the required endian mode
* for transfer buffers to match the host microprocessor
*/
if (ehci_big_endian_mmio(ehci))
tmp |= USBMODE_BE;
ehci_writel(ehci, tmp, reg_ptr);
}
@ -273,6 +275,58 @@ static void ehci_work(struct ehci_hcd *ehci);
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_CPU_FREQ
#include <linux/cpufreq.h>
static void ehci_cpufreq_pause (struct ehci_hcd *ehci)
{
unsigned long flags;
spin_lock_irqsave(&ehci->lock, flags);
if (!ehci->cpufreq_changing++)
qh_inactivate_split_intr_qhs(ehci);
spin_unlock_irqrestore(&ehci->lock, flags);
}
static void ehci_cpufreq_unpause (struct ehci_hcd *ehci)
{
unsigned long flags;
spin_lock_irqsave(&ehci->lock, flags);
if (!--ehci->cpufreq_changing)
qh_reactivate_split_intr_qhs(ehci);
spin_unlock_irqrestore(&ehci->lock, flags);
}
/*
* ehci_cpufreq_notifier is needed to avoid MMF errors that occur when
* EHCI controllers that don't cache many uframes get delayed trying to
* read main memory during CPU frequency transitions. This can cause
* split interrupt transactions to not be completed in the required uframe.
* This has been observed on the Broadcom/ServerWorks HT1000 controller.
*/
static int ehci_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
struct ehci_hcd *ehci = container_of(nb, struct ehci_hcd,
cpufreq_transition);
switch (val) {
case CPUFREQ_PRECHANGE:
ehci_cpufreq_pause(ehci);
break;
case CPUFREQ_POSTCHANGE:
ehci_cpufreq_unpause(ehci);
break;
}
return 0;
}
#endif
/*-------------------------------------------------------------------------*/
static void ehci_watchdog (unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
@ -347,6 +401,8 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
is_on ? SetPortFeature : ClearPortFeature,
USB_PORT_FEAT_POWER,
port--, NULL, 0);
/* Flush those writes */
ehci_readl(ehci, &ehci->regs->command);
msleep(20);
}
@ -404,6 +460,10 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
spin_unlock_irq(&ehci->lock);
#ifdef CONFIG_CPU_FREQ
cpufreq_unregister_notifier(&ehci->cpufreq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
#endif
/* let companion controllers work when we aren't */
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
@ -470,12 +530,12 @@ static int ehci_init(struct usb_hcd *hcd)
* from automatically advancing to the next td after short reads.
*/
ehci->async->qh_next.qh = NULL;
ehci->async->hw_next = QH_NEXT(ehci->async->qh_dma);
ehci->async->hw_info1 = cpu_to_le32(QH_HEAD);
ehci->async->hw_token = cpu_to_le32(QTD_STS_HALT);
ehci->async->hw_qtd_next = EHCI_LIST_END;
ehci->async->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
ehci->async->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
ehci->async->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
ehci->async->hw_qtd_next = EHCI_LIST_END(ehci);
ehci->async->qh_state = QH_STATE_LINKED;
ehci->async->hw_alt_next = QTD_NEXT(ehci->async->dummy->qtd_dma);
ehci->async->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma);
/* clear interrupt enables, set irq latency */
if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
@ -509,6 +569,17 @@ static int ehci_init(struct usb_hcd *hcd)
}
ehci->command = temp;
#ifdef CONFIG_CPU_FREQ
INIT_LIST_HEAD(&ehci->split_intr_qhs);
/*
* If the EHCI controller caches enough uframes, this probably
* isn't needed unless there are so many low/full speed devices
* that the controller's can't cache it all.
*/
ehci->cpufreq_transition.notifier_call = ehci_cpufreq_notifier;
cpufreq_register_notifier(&ehci->cpufreq_transition,
CPUFREQ_TRANSITION_NOTIFIER);
#endif
return 0;
}
@ -925,7 +996,7 @@ MODULE_LICENSE ("GPL");
#define PCI_DRIVER ehci_pci_driver
#endif
#ifdef CONFIG_MPC834x
#ifdef CONFIG_USB_EHCI_FSL
#include "ehci-fsl.c"
#define PLATFORM_DRIVER ehci_fsl_driver
#endif
@ -937,7 +1008,12 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_PPC_PS3
#include "ehci-ps3.c"
#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_sb_driver
#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver
#endif
#ifdef CONFIG_440EPX
#include "ehci-ppc-soc.c"
#define PLATFORM_DRIVER ehci_ppc_soc_driver
#endif
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
@ -971,9 +1047,7 @@ static int __init ehci_hcd_init(void)
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
retval = ps3_system_bus_driver_register(
&PS3_SYSTEM_BUS_DRIVER);
retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
if (retval < 0) {
#ifdef PLATFORM_DRIVER
platform_driver_unregister(&PLATFORM_DRIVER);
@ -983,7 +1057,6 @@ static int __init ehci_hcd_init(void)
#endif
return retval;
}
}
#endif
return retval;
@ -999,8 +1072,7 @@ static void __exit ehci_hcd_cleanup(void)
pci_unregister_driver(&PCI_DRIVER);
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
if (firmware_has_feature(FW_FEATURE_PS3_LV1))
ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
#endif
}
module_exit(ehci_hcd_cleanup);

View file

@ -28,6 +28,89 @@
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_USB_PERSIST
static int ehci_hub_control(
struct usb_hcd *hcd,
u16 typeReq,
u16 wValue,
u16 wIndex,
char *buf,
u16 wLength
);
/* After a power loss, ports that were owned by the companion must be
* reset so that the companion can still own them.
*/
static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
{
u32 __iomem *reg;
u32 status;
int port;
__le32 buf;
struct usb_hcd *hcd = ehci_to_hcd(ehci);
if (!ehci->owned_ports)
return;
/* Give the connections some time to appear */
msleep(20);
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
if (test_bit(port, &ehci->owned_ports)) {
reg = &ehci->regs->port_status[port];
status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
/* Port already owned by companion? */
if (status & PORT_OWNER)
clear_bit(port, &ehci->owned_ports);
else if (test_bit(port, &ehci->companion_ports))
ehci_writel(ehci, status & ~PORT_PE, reg);
else
ehci_hub_control(hcd, SetPortFeature,
USB_PORT_FEAT_RESET, port + 1,
NULL, 0);
}
}
if (!ehci->owned_ports)
return;
msleep(90); /* Wait for resets to complete */
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
if (test_bit(port, &ehci->owned_ports)) {
ehci_hub_control(hcd, GetPortStatus,
0, port + 1,
(char *) &buf, sizeof(buf));
/* The companion should now own the port,
* but if something went wrong the port must not
* remain enabled.
*/
reg = &ehci->regs->port_status[port];
status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
if (status & PORT_OWNER)
ehci_writel(ehci, status | PORT_CSC, reg);
else {
ehci_dbg(ehci, "failed handover port %d: %x\n",
port + 1, status);
ehci_writel(ehci, status & ~PORT_PE, reg);
}
}
}
ehci->owned_ports = 0;
}
#else /* CONFIG_USB_PERSIST */
static inline void ehci_handover_companion_ports(struct ehci_hcd *ehci)
{ }
#endif
#ifdef CONFIG_PM
static int ehci_bus_suspend (struct usb_hcd *hcd)
@ -60,14 +143,16 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
* then manually resume them in the bus_resume() routine.
*/
ehci->bus_suspended = 0;
ehci->owned_ports = 0;
while (port--) {
u32 __iomem *reg = &ehci->regs->port_status [port];
u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
u32 t2 = t1;
/* keep track of which ports we suspend */
if ((t1 & PORT_PE) && !(t1 & PORT_OWNER) &&
!(t1 & PORT_SUSPEND)) {
if (t1 & PORT_OWNER)
set_bit(port, &ehci->owned_ports);
else if ((t1 & PORT_PE) && !(t1 & PORT_SUSPEND)) {
t2 |= PORT_SUSPEND;
set_bit(port, &ehci->bus_suspended);
}
@ -108,11 +193,16 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 temp;
u32 power_okay;
int i;
if (time_before (jiffies, ehci->next_statechange))
msleep(5);
spin_lock_irq (&ehci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
spin_unlock_irq(&ehci->lock);
return -ESHUTDOWN;
}
/* Ideally and we've got a real resume here, and no port's power
* was lost. (For PCI, that means Vaux was maintained.) But we
@ -120,8 +210,9 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
* the last user of the controller, not reset/pm hardware keeping
* state we gave to it.
*/
temp = ehci_readl(ehci, &ehci->regs->intr_enable);
ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
power_okay = ehci_readl(ehci, &ehci->regs->intr_enable);
ehci_dbg(ehci, "resume root hub%s\n",
power_okay ? "" : " after power loss");
/* at least some APM implementations will try to deliver
* IRQs right away, so delay them until we're ready.
@ -184,6 +275,9 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
spin_unlock_irq (&ehci->lock);
if (!power_okay)
ehci_handover_companion_ports(ehci);
return 0;
}
@ -448,7 +542,8 @@ static int ehci_hub_control (
) {
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int ports = HCS_N_PORTS (ehci->hcs_params);
u32 __iomem *status_reg = &ehci->regs->port_status[wIndex - 1];
u32 __iomem *status_reg = &ehci->regs->port_status[
(wIndex & 0xff) - 1];
u32 temp, status;
unsigned long flags;
int retval = 0;
@ -556,9 +651,24 @@ static int ehci_hub_control (
status |= 1 << USB_PORT_FEAT_C_CONNECTION;
if (temp & PORT_PEC)
status |= 1 << USB_PORT_FEAT_C_ENABLE;
if ((temp & PORT_OCC) && !ignore_oc)
if ((temp & PORT_OCC) && !ignore_oc){
status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
/*
* Hubs should disable port power on over-current.
* However, not all EHCI implementations do this
* automatically, even if they _do_ support per-port
* power switching; they're allowed to just limit the
* current. khubd will turn the power back on.
*/
if (HCS_PPC (ehci->hcs_params)){
ehci_writel(ehci,
temp & ~(PORT_RWC_BITS | PORT_POWER),
status_reg);
}
}
/* whoever resumes must GetPortStatus to complete it!! */
if (temp & PORT_RESUME) {

View file

@ -27,7 +27,7 @@
* need to use dma_pool or dma_alloc_coherent
* - driver buffers, read/written by HC ... single shot DMA mapped
*
* There's also PCI "register" data, which is memory mapped.
* There's also "register" data (e.g. PCI or SOC), which is memory mapped.
* No memory seen by this driver is pageable.
*/
@ -35,13 +35,14 @@
/* Allocate the key transfer structures from the previously allocated pool */
static inline void ehci_qtd_init (struct ehci_qtd *qtd, dma_addr_t dma)
static inline void ehci_qtd_init(struct ehci_hcd *ehci, struct ehci_qtd *qtd,
dma_addr_t dma)
{
memset (qtd, 0, sizeof *qtd);
qtd->qtd_dma = dma;
qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
qtd->hw_next = EHCI_LIST_END;
qtd->hw_alt_next = EHCI_LIST_END;
qtd->hw_next = EHCI_LIST_END(ehci);
qtd->hw_alt_next = EHCI_LIST_END(ehci);
INIT_LIST_HEAD (&qtd->qtd_list);
}
@ -52,7 +53,7 @@ static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, gfp_t flags)
qtd = dma_pool_alloc (ehci->qtd_pool, flags, &dma);
if (qtd != NULL) {
ehci_qtd_init (qtd, dma);
ehci_qtd_init(ehci, qtd, dma);
}
return qtd;
}
@ -63,9 +64,8 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
}
static void qh_destroy (struct kref *kref)
static void qh_destroy(struct ehci_qh *qh)
{
struct ehci_qh *qh = container_of(kref, struct ehci_qh, kref);
struct ehci_hcd *ehci = qh->ehci;
/* clean qtds first, and know this is not linked */
@ -89,11 +89,14 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
return qh;
memset (qh, 0, sizeof *qh);
kref_init(&qh->kref);
qh->refcount = 1;
qh->ehci = ehci;
qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD (&qh->qtd_list);
#ifdef CONFIG_CPU_FREQ
INIT_LIST_HEAD (&qh->split_intr_qhs);
#endif
/* dummy td enables safe urb queuing */
qh->dummy = ehci_qtd_alloc (ehci, flags);
@ -108,13 +111,15 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
/* to share a qh (cpu threads, or hc) */
static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
{
kref_get(&qh->kref);
WARN_ON(!qh->refcount);
qh->refcount++;
return qh;
}
static inline void qh_put (struct ehci_qh *qh)
{
kref_put(&qh->kref, qh_destroy);
if (!--qh->refcount)
qh_destroy(qh);
}
/*-------------------------------------------------------------------------*/
@ -217,7 +222,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
goto fail;
}
for (i = 0; i < ehci->periodic_size; i++)
ehci->periodic [i] = EHCI_LIST_END;
ehci->periodic [i] = EHCI_LIST_END(ehci);
/* software shadow of hardware table */
ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);

View file

@ -312,13 +312,14 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
ehci_work(ehci);
spin_unlock_irq(&ehci->lock);
/* here we "know" root ports should always stay powered */
ehci_port_power(ehci, 1);
ehci_writel(ehci, ehci->command, &ehci->regs->command);
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
/* here we "know" root ports should always stay powered */
ehci_port_power(ehci, 1);
ehci_handover_companion_ports(ehci);
hcd->state = HC_STATE_SUSPENDED;
return 0;
}

View file

@ -0,0 +1,182 @@
/*
* EHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 2006-2007 Stefan Roese <sr@denx.de>, DENX Software Engineering
*
* Bus Glue for PPC On-Chip EHCI driver
* Tested on AMCC 440EPx
*
* Based on "ehci-au12xx.c" by David Brownell <dbrownell@users.sourceforge.net>
*
* This file is licenced under the GPL.
*/
#include <linux/platform_device.h>
extern int usb_disabled(void);
/**
* usb_ehci_ppc_soc_probe - initialize PPC-SoC-based HCDs
* Context: !in_interrupt()
*
* Allocates basic resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
*
*/
int usb_ehci_ppc_soc_probe(const struct hc_driver *driver,
struct usb_hcd **hcd_out,
struct platform_device *dev)
{
int retval;
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
if (dev->resource[1].flags != IORESOURCE_IRQ) {
pr_debug("resource[1] is not IORESOURCE_IRQ");
retval = -ENOMEM;
}
hcd = usb_create_hcd(driver, &dev->dev, "PPC-SOC EHCI");
if (!hcd)
return -ENOMEM;
hcd->rsrc_start = dev->resource[0].start;
hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
pr_debug("request_mem_region failed");
retval = -EBUSY;
goto err1;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
pr_debug("ioremap failed");
retval = -ENOMEM;
goto err2;
}
ehci = hcd_to_ehci(hcd);
ehci->big_endian_mmio = 1;
ehci->big_endian_desc = 1;
ehci->caps = hcd->regs;
ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
#if defined(CONFIG_440EPX)
/*
* 440EPx Errata USBH_3
* Fix: Enable Break Memory Transfer (BMT) in INSNREG3
*/
out_be32((void *)((ulong)(&ehci->regs->command) + 0x8c), (1 << 0));
ehci_dbg(ehci, "Break Memory Transfer (BMT) has beed enabled!\n");
#endif
retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
if (retval == 0)
return retval;
iounmap(hcd->regs);
err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
usb_put_hcd(hcd);
return retval;
}
/* may be called without controller electrically present */
/* may be called with controller, bus, and devices active */
/**
* usb_ehci_hcd_ppc_soc_remove - shutdown processing for PPC-SoC-based HCDs
* @dev: USB Host Controller being removed
* Context: !in_interrupt()
*
* Reverses the effect of usb_ehci_hcd_ppc_soc_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
* context, normally "rmmod", "apmd", or something similar.
*
*/
void usb_ehci_ppc_soc_remove(struct usb_hcd *hcd, struct platform_device *dev)
{
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
}
static const struct hc_driver ehci_ppc_soc_hc_driver = {
.description = hcd_name,
.product_desc = "PPC-SOC EHCI",
.hcd_priv_size = sizeof(struct ehci_hcd),
/*
* generic hardware linkage
*/
.irq = ehci_irq,
.flags = HCD_MEMORY | HCD_USB2,
/*
* basic lifecycle operations
*/
.reset = ehci_init,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
/*
* scheduling support
*/
.get_frame_number = ehci_get_frame,
/*
* root hub support
*/
.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
};
static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd = NULL;
int ret;
pr_debug("In ehci_hcd_ppc_soc_drv_probe\n");
if (usb_disabled())
return -ENODEV;
ret = usb_ehci_ppc_soc_probe(&ehci_ppc_soc_hc_driver, &hcd, pdev);
return ret;
}
static int ehci_hcd_ppc_soc_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_ehci_ppc_soc_remove(hcd, pdev);
return 0;
}
MODULE_ALIAS("ppc-soc-ehci");
static struct platform_driver ehci_ppc_soc_driver = {
.probe = ehci_hcd_ppc_soc_drv_probe,
.remove = ehci_hcd_ppc_soc_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ppc-soc-ehci",
.bus = &platform_bus_type
}
};

View file

@ -18,6 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/firmware.h>
#include <asm/ps3.h>
static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
@ -73,7 +74,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
#endif
};
static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
{
int result;
struct usb_hcd *hcd;
@ -85,13 +86,30 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
goto fail_start;
}
result = ps3_open_hv_device(dev);
if (result) {
dev_dbg(&dev->core, "%s:%d: ps3_open_hv_device failed\n",
__func__, __LINE__);
goto fail_open;
}
result = ps3_dma_region_create(dev->d_region);
if (result) {
dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: "
"(%d)\n", __func__, __LINE__, result);
BUG_ON("check region type");
goto fail_dma_region;
}
result = ps3_mmio_region_create(dev->m_region);
if (result) {
dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
__func__, __LINE__);
result = -EPERM;
goto fail_mmio;
goto fail_mmio_region;
}
dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
@ -120,6 +138,11 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
hcd->rsrc_start = dev->m_region->lpar_addr;
hcd->rsrc_len = dev->m_region->len;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name))
dev_dbg(&dev->core, "%s:%d: request_mem_region failed\n",
__func__, __LINE__);
hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
if (!hcd->regs) {
@ -153,34 +176,73 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
fail_add_hcd:
iounmap(hcd->regs);
fail_ioremap:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
fail_create_hcd:
ps3_io_irq_destroy(virq);
fail_irq:
ps3_free_mmio_region(dev->m_region);
fail_mmio:
fail_mmio_region:
ps3_dma_region_free(dev->d_region);
fail_dma_region:
ps3_close_hv_device(dev);
fail_open:
fail_start:
return result;
}
static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
{
unsigned int tmp;
struct usb_hcd *hcd =
(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
usb_put_hcd(hcd);
BUG_ON(!hcd);
dev_dbg(&dev->core, "%s:%d: regs %p\n", __func__, __LINE__, hcd->regs);
dev_dbg(&dev->core, "%s:%d: irq %u\n", __func__, __LINE__, hcd->irq);
tmp = hcd->irq;
usb_remove_hcd(hcd);
ps3_system_bus_set_driver_data(dev, NULL);
BUG_ON(!hcd->regs);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
ps3_io_irq_destroy(tmp);
ps3_free_mmio_region(dev->m_region);
ps3_dma_region_free(dev->d_region);
ps3_close_hv_device(dev);
return 0;
}
MODULE_ALIAS("ps3-ehci");
static int ps3_ehci_driver_register(struct ps3_system_bus_driver *drv)
{
return firmware_has_feature(FW_FEATURE_PS3_LV1)
? ps3_system_bus_driver_register(drv)
: 0;
}
static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
static void ps3_ehci_driver_unregister(struct ps3_system_bus_driver *drv)
{
if (firmware_has_feature(FW_FEATURE_PS3_LV1))
ps3_system_bus_driver_unregister(drv);
}
MODULE_ALIAS(PS3_MODULE_ALIAS_EHCI);
static struct ps3_system_bus_driver ps3_ehci_driver = {
.core.name = "ps3-ehci-driver",
.core.owner = THIS_MODULE,
.match_id = PS3_MATCH_ID_EHCI,
.core = {
.name = "ps3-ehci-driver",
},
.probe = ps3_ehci_sb_probe,
.remove = ps3_ehci_sb_remove,
.probe = ps3_ehci_probe,
.remove = ps3_ehci_remove,
.shutdown = ps3_ehci_remove,
};

View file

@ -43,15 +43,15 @@
/* fill a qtd, returning how much of the buffer we were able to queue up */
static int
qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
int token, int maxpacket)
qtd_fill(struct ehci_hcd *ehci, struct ehci_qtd *qtd, dma_addr_t buf,
size_t len, int token, int maxpacket)
{
int i, count;
u64 addr = buf;
/* one buffer entry per 4K ... first might be short or unaligned */
qtd->hw_buf [0] = cpu_to_le32 ((u32)addr);
qtd->hw_buf_hi [0] = cpu_to_le32 ((u32)(addr >> 32));
qtd->hw_buf[0] = cpu_to_hc32(ehci, (u32)addr);
qtd->hw_buf_hi[0] = cpu_to_hc32(ehci, (u32)(addr >> 32));
count = 0x1000 - (buf & 0x0fff); /* rest of that page */
if (likely (len < count)) /* ... iff needed */
count = len;
@ -62,8 +62,9 @@ qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
/* per-qtd limit: from 16K to 20K (best alignment) */
for (i = 1; count < len && i < 5; i++) {
addr = buf;
qtd->hw_buf [i] = cpu_to_le32 ((u32)addr);
qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32));
qtd->hw_buf[i] = cpu_to_hc32(ehci, (u32)addr);
qtd->hw_buf_hi[i] = cpu_to_hc32(ehci,
(u32)(addr >> 32));
buf += 0x1000;
if ((count + 0x1000) < len)
count += 0x1000;
@ -75,7 +76,7 @@ qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
if (count != len)
count -= (count % maxpacket);
}
qtd->hw_token = cpu_to_le32 ((count << 16) | token);
qtd->hw_token = cpu_to_hc32(ehci, (count << 16) | token);
qtd->length = count;
return count;
@ -89,28 +90,28 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
/* writes to an active overlay are unsafe */
BUG_ON(qh->qh_state != QH_STATE_IDLE);
qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
qh->hw_alt_next = EHCI_LIST_END;
qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
qh->hw_alt_next = EHCI_LIST_END(ehci);
/* Except for control endpoints, we make hardware maintain data
* toggle (like OHCI) ... here (re)initialize the toggle in the QH,
* and set the pseudo-toggle in udev. Only usb_clear_halt() will
* ever clear it.
*/
if (!(qh->hw_info1 & cpu_to_le32(1 << 14))) {
if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
unsigned is_out, epnum;
is_out = !(qtd->hw_token & cpu_to_le32(1 << 8));
epnum = (le32_to_cpup(&qh->hw_info1) >> 8) & 0x0f;
is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f;
if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE);
qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
usb_settoggle (qh->dev, epnum, is_out, 1);
}
}
/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
wmb ();
qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
}
/* if it weren't for a common silicon quirk (writing the dummy into the qh
@ -128,7 +129,7 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
qtd = list_entry (qh->qtd_list.next,
struct ehci_qtd, qtd_list);
/* first qtd may already be partially processed */
if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current)
if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw_current)
qtd = NULL;
}
@ -222,7 +223,7 @@ __acquires(ehci->lock)
struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
/* S-mask in a QH means it's an interrupt urb */
if ((qh->hw_info2 & __constant_cpu_to_le32 (QH_SMASK)) != 0) {
if ((qh->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) {
/* ... update hc-wide periodic stats (for usbfs) */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
@ -277,7 +278,6 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
* Chases up to qh->hw_current. Returns number of completions called,
* indicating how much "real" work we did.
*/
#define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
static unsigned
qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
@ -287,6 +287,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
unsigned count = 0;
int do_status = 0;
u8 state;
u32 halt = HALT_BIT(ehci);
if (unlikely (list_empty (&qh->qtd_list)))
return count;
@ -311,6 +312,10 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
struct urb *urb;
u32 token = 0;
/* ignore QHs that are currently inactive */
if (qh->hw_info1 & __constant_cpu_to_le32(QH_INACTIVATE))
break;
qtd = list_entry (entry, struct ehci_qtd, qtd_list);
urb = qtd->urb;
@ -330,7 +335,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* hardware copies qtd out of qh overlay */
rmb ();
token = le32_to_cpu (qtd->hw_token);
token = hc32_to_cpu(ehci, qtd->hw_token);
/* always clean up qtds the hc de-activated */
if ((token & QTD_STS_ACTIVE) == 0) {
@ -342,7 +347,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
* that silicon quirk can kick in with this dummy too.
*/
} else if (IS_SHORT_READ (token)
&& !(qtd->hw_alt_next & EHCI_LIST_END)) {
&& !(qtd->hw_alt_next
& EHCI_LIST_END(ehci))) {
stopped = 1;
goto halt;
}
@ -374,17 +380,17 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* token in overlay may be most current */
if (state == QH_STATE_IDLE
&& cpu_to_le32 (qtd->qtd_dma)
&& cpu_to_hc32(ehci, qtd->qtd_dma)
== qh->hw_current)
token = le32_to_cpu (qh->hw_token);
token = hc32_to_cpu(ehci, qh->hw_token);
/* force halt for unlinked or blocked qh, so we'll
* patch the qh later and so that completions can't
* activate it while we "know" it's stopped.
*/
if ((HALT_BIT & qh->hw_token) == 0) {
if ((halt & qh->hw_token) == 0) {
halt:
qh->hw_token |= HALT_BIT;
qh->hw_token |= halt;
wmb ();
}
}
@ -419,7 +425,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
* it after fault cleanup, or recovering from silicon wrongly
* overlaying the dummy qtd (which reduces DMA chatter).
*/
if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END) {
if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END(ehci)) {
switch (state) {
case QH_STATE_IDLE:
qh_refresh(ehci, qh);
@ -428,7 +434,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* should be rare for periodic transfers,
* except maybe high bandwidth ...
*/
if ((__constant_cpu_to_le32 (QH_SMASK)
if ((cpu_to_hc32(ehci, QH_SMASK)
& qh->hw_info2) != 0) {
intr_deschedule (ehci, qh);
(void) qh_schedule (ehci, qh);
@ -502,7 +508,8 @@ qh_urb_transaction (
is_input = usb_pipein (urb->pipe);
if (usb_pipecontrol (urb->pipe)) {
/* SETUP pid */
qtd_fill (qtd, urb->setup_dma, sizeof (struct usb_ctrlrequest),
qtd_fill(ehci, qtd, urb->setup_dma,
sizeof (struct usb_ctrlrequest),
token | (2 /* "setup" */ << 8), 8);
/* ... and always at least one more pid */
@ -512,7 +519,7 @@ qh_urb_transaction (
if (unlikely (!qtd))
goto cleanup;
qtd->urb = urb;
qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
list_add_tail (&qtd->qtd_list, head);
/* for zero length DATA stages, STATUS is always IN */
@ -539,7 +546,7 @@ qh_urb_transaction (
for (;;) {
int this_qtd_len;
this_qtd_len = qtd_fill (qtd, buf, len, token, maxpacket);
this_qtd_len = qtd_fill(ehci, qtd, buf, len, token, maxpacket);
len -= this_qtd_len;
buf += this_qtd_len;
if (is_input)
@ -557,7 +564,7 @@ qh_urb_transaction (
if (unlikely (!qtd))
goto cleanup;
qtd->urb = urb;
qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
list_add_tail (&qtd->qtd_list, head);
}
@ -566,7 +573,7 @@ qh_urb_transaction (
*/
if (likely ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
|| usb_pipecontrol (urb->pipe)))
qtd->hw_alt_next = EHCI_LIST_END;
qtd->hw_alt_next = EHCI_LIST_END(ehci);
/*
* control requests may need a terminating data "status" ack;
@ -590,17 +597,17 @@ qh_urb_transaction (
if (unlikely (!qtd))
goto cleanup;
qtd->urb = urb;
qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
list_add_tail (&qtd->qtd_list, head);
/* never any data in such packets */
qtd_fill (qtd, 0, 0, token, 0);
qtd_fill(ehci, qtd, 0, 0, token, 0);
}
}
/* by default, enable interrupt on urb completion */
if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC);
return head;
cleanup:
@ -769,8 +776,8 @@ qh_make (
/* init as live, toggle clear, advance to dummy */
qh->qh_state = QH_STATE_IDLE;
qh->hw_info1 = cpu_to_le32 (info1);
qh->hw_info2 = cpu_to_le32 (info2);
qh->hw_info1 = cpu_to_hc32(ehci, info1);
qh->hw_info2 = cpu_to_hc32(ehci, info2);
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
qh_refresh (ehci, qh);
return qh;
@ -782,7 +789,7 @@ qh_make (
static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
__le32 dma = QH_NEXT (qh->qh_dma);
__hc32 dma = QH_NEXT(ehci, qh->qh_dma);
struct ehci_qh *head;
/* (re)start the async schedule? */
@ -820,8 +827,6 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
#define QH_ADDR_MASK __constant_cpu_to_le32(0x7f)
/*
* For control/bulk/interrupt, return QH with these TDs appended.
* Allocates and initializes the QH if necessary.
@ -837,6 +842,7 @@ static struct ehci_qh *qh_append_tds (
)
{
struct ehci_qh *qh = NULL;
u32 qh_addr_mask = cpu_to_hc32(ehci, 0x7f);
qh = (struct ehci_qh *) *ptr;
if (unlikely (qh == NULL)) {
@ -858,7 +864,7 @@ static struct ehci_qh *qh_append_tds (
/* usb_reset_device() briefly reverts to address 0 */
if (usb_pipedevice (urb->pipe) == 0)
qh->hw_info1 &= ~QH_ADDR_MASK;
qh->hw_info1 &= ~qh_addr_mask;
}
/* just one way to queue requests: swap with the dummy qtd.
@ -867,7 +873,7 @@ static struct ehci_qh *qh_append_tds (
if (likely (qtd != NULL)) {
struct ehci_qtd *dummy;
dma_addr_t dma;
__le32 token;
__hc32 token;
/* to avoid racing the HC, use the dummy td instead of
* the first td of our list (becomes new dummy). both
@ -875,7 +881,7 @@ static struct ehci_qh *qh_append_tds (
* HC is allowed to fetch the old dummy (4.10.2).
*/
token = qtd->hw_token;
qtd->hw_token = HALT_BIT;
qtd->hw_token = HALT_BIT(ehci);
wmb ();
dummy = qh->dummy;
@ -887,14 +893,14 @@ static struct ehci_qh *qh_append_tds (
list_add (&dummy->qtd_list, qtd_list);
__list_splice (qtd_list, qh->qtd_list.prev);
ehci_qtd_init (qtd, qtd->qtd_dma);
ehci_qtd_init(ehci, qtd, qtd->qtd_dma);
qh->dummy = qtd;
/* hc must see the new dummy at list end */
dma = qtd->qtd_dma;
qtd = list_entry (qh->qtd_list.prev,
struct ehci_qtd, qtd_list);
qtd->hw_next = QTD_NEXT (dma);
qtd->hw_next = QTD_NEXT(ehci, dma);
/* let the hc process these next qtds */
wmb ();
@ -970,7 +976,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
timer_action_done (ehci, TIMER_IAA_WATCHDOG);
// qh->hw_next = cpu_to_le32 (qh->qh_dma);
// qh->hw_next = cpu_to_hc32(qh->qh_dma);
qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = NULL;
qh_put (qh); // refcount from reclaim

View file

@ -44,9 +44,10 @@ static int ehci_get_frame (struct usb_hcd *hcd);
* @tag: hardware tag for type of this record
*/
static union ehci_shadow *
periodic_next_shadow (union ehci_shadow *periodic, __le32 tag)
periodic_next_shadow(struct ehci_hcd *ehci, union ehci_shadow *periodic,
__hc32 tag)
{
switch (tag) {
switch (hc32_to_cpu(ehci, tag)) {
case Q_TYPE_QH:
return &periodic->qh->qh_next;
case Q_TYPE_FSTN:
@ -63,12 +64,13 @@ periodic_next_shadow (union ehci_shadow *periodic, __le32 tag)
static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
{
union ehci_shadow *prev_p = &ehci->pshadow[frame];
__le32 *hw_p = &ehci->periodic [frame];
__hc32 *hw_p = &ehci->periodic[frame];
union ehci_shadow here = *prev_p;
/* find predecessor of "ptr"; hw and shadow lists are in sync */
while (here.ptr && here.ptr != ptr) {
prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p));
prev_p = periodic_next_shadow(ehci, prev_p,
Q_NEXT_TYPE(ehci, *hw_p));
hw_p = here.hw_next;
here = *prev_p;
}
@ -79,7 +81,8 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
/* update shadow and hardware lists ... the old "next" pointers
* from ptr may still be in use, the caller updates them.
*/
*prev_p = *periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p));
*prev_p = *periodic_next_shadow(ehci, &here,
Q_NEXT_TYPE(ehci, *hw_p));
*hw_p = *here.hw_next;
}
@ -87,18 +90,19 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
static unsigned short
periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
{
__le32 *hw_p = &ehci->periodic [frame];
__hc32 *hw_p = &ehci->periodic [frame];
union ehci_shadow *q = &ehci->pshadow [frame];
unsigned usecs = 0;
while (q->ptr) {
switch (Q_NEXT_TYPE (*hw_p)) {
switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) {
case Q_TYPE_QH:
/* is it in the S-mask? */
if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe))
if (q->qh->hw_info2 & cpu_to_hc32(ehci, 1 << uframe))
usecs += q->qh->usecs;
/* ... or C-mask? */
if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe)))
if (q->qh->hw_info2 & cpu_to_hc32(ehci,
1 << (8 + uframe)))
usecs += q->qh->c_usecs;
hw_p = &q->qh->hw_next;
q = &q->qh->qh_next;
@ -108,7 +112,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
/* for "save place" FSTNs, count the relevant INTR
* bandwidth from the previous frame
*/
if (q->fstn->hw_prev != EHCI_LIST_END) {
if (q->fstn->hw_prev != EHCI_LIST_END(ehci)) {
ehci_dbg (ehci, "ignoring FSTN cost ...\n");
}
hw_p = &q->fstn->hw_next;
@ -121,9 +125,10 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
break;
case Q_TYPE_SITD:
/* is it in the S-mask? (count SPLIT, DATA) */
if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) {
if (q->sitd->hw_uframe & cpu_to_hc32(ehci,
1 << uframe)) {
if (q->sitd->hw_fullspeed_ep &
__constant_cpu_to_le32 (1<<31))
cpu_to_hc32(ehci, 1<<31))
usecs += q->sitd->stream->usecs;
else /* worst case for OUT start-split */
usecs += HS_USECS_ISO (188);
@ -131,7 +136,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
/* ... C-mask? (count CSPLIT, DATA) */
if (q->sitd->hw_uframe &
cpu_to_le32 (1 << (8 + uframe))) {
cpu_to_hc32(ehci, 1 << (8 + uframe))) {
/* worst case for IN complete-split */
usecs += q->sitd->stream->c_usecs;
}
@ -173,9 +178,9 @@ static int same_tt (struct usb_device *dev1, struct usb_device *dev2)
* will cause a transfer in "B-frame" uframe 0. "B-frames" lag
* "H-frames" by 1 uframe. See the EHCI spec sec 4.5 and figure 4.7.
*/
static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __le32 mask)
static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask)
{
unsigned char smask = QH_SMASK & le32_to_cpu(mask);
unsigned char smask = QH_SMASK & hc32_to_cpu(ehci, mask);
if (!smask) {
ehci_err(ehci, "invalid empty smask!\n");
/* uframe 7 can't have bw so this will indicate failure */
@ -217,14 +222,14 @@ periodic_tt_usecs (
unsigned short tt_usecs[8]
)
{
__le32 *hw_p = &ehci->periodic [frame];
__hc32 *hw_p = &ehci->periodic [frame];
union ehci_shadow *q = &ehci->pshadow [frame];
unsigned char uf;
memset(tt_usecs, 0, 16);
while (q->ptr) {
switch (Q_NEXT_TYPE(*hw_p)) {
switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) {
case Q_TYPE_ITD:
hw_p = &q->itd->hw_next;
q = &q->itd->itd_next;
@ -247,8 +252,8 @@ periodic_tt_usecs (
continue;
// case Q_TYPE_FSTN:
default:
ehci_dbg(ehci,
"ignoring periodic frame %d FSTN\n", frame);
ehci_dbg(ehci, "ignoring periodic frame %d FSTN\n",
frame);
hw_p = &q->fstn->hw_next;
q = &q->fstn->fstn_next;
}
@ -368,41 +373,42 @@ static int tt_no_collision (
*/
for (; frame < ehci->periodic_size; frame += period) {
union ehci_shadow here;
__le32 type;
__hc32 type;
here = ehci->pshadow [frame];
type = Q_NEXT_TYPE (ehci->periodic [frame]);
type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]);
while (here.ptr) {
switch (type) {
switch (hc32_to_cpu(ehci, type)) {
case Q_TYPE_ITD:
type = Q_NEXT_TYPE (here.itd->hw_next);
type = Q_NEXT_TYPE(ehci, here.itd->hw_next);
here = here.itd->itd_next;
continue;
case Q_TYPE_QH:
if (same_tt (dev, here.qh->dev)) {
u32 mask;
mask = le32_to_cpu (here.qh->hw_info2);
mask = hc32_to_cpu(ehci,
here.qh->hw_info2);
/* "knows" no gap is needed */
mask |= mask >> 8;
if (mask & uf_mask)
break;
}
type = Q_NEXT_TYPE (here.qh->hw_next);
type = Q_NEXT_TYPE(ehci, here.qh->hw_next);
here = here.qh->qh_next;
continue;
case Q_TYPE_SITD:
if (same_tt (dev, here.sitd->urb->dev)) {
u16 mask;
mask = le32_to_cpu (here.sitd
mask = hc32_to_cpu(ehci, here.sitd
->hw_uframe);
/* FIXME assumes no gap for IN! */
mask |= mask >> 8;
if (mask & uf_mask)
break;
}
type = Q_NEXT_TYPE (here.sitd->hw_next);
type = Q_NEXT_TYPE(ehci, here.sitd->hw_next);
here = here.sitd->sitd_next;
continue;
// case Q_TYPE_FSTN:
@ -473,6 +479,109 @@ static int disable_periodic (struct ehci_hcd *ehci)
}
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_CPU_FREQ
static int safe_to_modify_i (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
int now; /* current (frame * 8) + uframe */
int prev_start, next_start; /* uframes from/to split start */
int start_uframe = ffs(le32_to_cpup (&qh->hw_info2) & QH_SMASK);
int end_uframe = fls((le32_to_cpup (&qh->hw_info2) & QH_CMASK) >> 8);
int split_duration = end_uframe - start_uframe;
now = readl(&ehci->regs->frame_index) % (ehci->periodic_size << 3);
next_start = ((1024 << 3) + (qh->start << 3) + start_uframe - now)
% (qh->period << 3);
prev_start = (qh->period << 3) - next_start;
/*
* Make sure there will be at least one uframe when qh is safe.
*/
if ((qh->period << 3) <= (ehci->i_thresh + 2 + split_duration))
/* never safe */
return -EINVAL;
/*
* Wait 1 uframe after transaction should have started, to make
* sure controller has time to write back overlay, so we can
* check QTD_STS_STS to see if transaction is in progress.
*/
if ((next_start > ehci->i_thresh) && (prev_start > 1))
/* safe to set "i" bit if split isn't in progress */
return (qh->hw_token & STATUS_BIT(ehci)) ? 0 : 1;
else
return 0;
}
/* Set inactivate bit for all the split interrupt QHs. */
static void qh_inactivate_split_intr_qhs (struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
int not_done, safe;
u32 inactivate = INACTIVATE_BIT(ehci);
u32 active = ACTIVE_BIT(ehci);
do {
not_done = 0;
list_for_each_entry(qh, &ehci->split_intr_qhs,
split_intr_qhs) {
if (qh->hw_info1 & inactivate)
/* already off */
continue;
/*
* To avoid setting "I" after the start split happens,
* don't set it if the QH might be cached in the
* controller. Some HCs (Broadcom/ServerWorks HT1000)
* will stop in the middle of a split transaction when
* the "I" bit is set.
*/
safe = safe_to_modify_i(ehci, qh);
if (safe == 0) {
not_done = 1;
} else if (safe > 0) {
qh->was_active = qh->hw_token & active;
qh->hw_info1 |= inactivate;
}
}
} while (not_done);
wmb();
}
static void qh_reactivate_split_intr_qhs (struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
u32 token;
int not_done, safe;
u32 inactivate = INACTIVATE_BIT(ehci);
u32 active = ACTIVE_BIT(ehci);
u32 halt = HALT_BIT(ehci);
do {
not_done = 0;
list_for_each_entry(qh, &ehci->split_intr_qhs, split_intr_qhs) {
if (!(qh->hw_info1 & inactivate)) /* already on */
continue;
/*
* Don't reactivate if cached, or controller might
* overwrite overlay after we modify it!
*/
safe = safe_to_modify_i(ehci, qh);
if (safe == 0) {
not_done = 1;
} else if (safe > 0) {
/* See EHCI 1.0 section 4.15.2.4. */
token = qh->hw_token;
qh->hw_token = (token | halt) & ~active;
wmb();
qh->hw_info1 &= ~inactivate;
wmb();
qh->hw_token = (token & ~halt) | qh->was_active;
}
}
} while (not_done);
}
#endif
/* periodic schedule slots have iso tds (normal or split) first, then a
* sparse tree for active interrupt transfers.
@ -487,25 +596,36 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
dev_dbg (&qh->dev->dev,
"link qh%d-%04x/%p start %d [%d/%d us]\n",
period, le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK),
period, hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK),
qh, qh->start, qh->usecs, qh->c_usecs);
#ifdef CONFIG_CPU_FREQ
/*
* If low/full speed interrupt QHs are inactive (because of
* cpufreq changing processor speeds), start QH with I flag set--
* it will automatically be cleared when cpufreq is done.
*/
if (ehci->cpufreq_changing)
if (!(qh->hw_info1 & (cpu_to_le32(1 << 13))))
qh->hw_info1 |= INACTIVATE_BIT(ehci);
#endif
/* high bandwidth, or otherwise every microframe */
if (period == 0)
period = 1;
for (i = qh->start; i < ehci->periodic_size; i += period) {
union ehci_shadow *prev = &ehci->pshadow[i];
__le32 *hw_p = &ehci->periodic [i];
__hc32 *hw_p = &ehci->periodic[i];
union ehci_shadow here = *prev;
__le32 type = 0;
__hc32 type = 0;
/* skip the iso nodes at list head */
while (here.ptr) {
type = Q_NEXT_TYPE (*hw_p);
if (type == Q_TYPE_QH)
type = Q_NEXT_TYPE(ehci, *hw_p);
if (type == cpu_to_hc32(ehci, Q_TYPE_QH))
break;
prev = periodic_next_shadow (prev, type);
prev = periodic_next_shadow(ehci, prev, type);
hw_p = &here.qh->hw_next;
here = *prev;
}
@ -527,7 +647,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->hw_next = *hw_p;
wmb ();
prev->qh = qh;
*hw_p = QH_NEXT (qh->qh_dma);
*hw_p = QH_NEXT (ehci, qh->qh_dma);
}
}
qh->qh_state = QH_STATE_LINKED;
@ -538,6 +658,12 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
? ((qh->usecs + qh->c_usecs) / qh->period)
: (qh->usecs * 8);
#ifdef CONFIG_CPU_FREQ
/* add qh to list of low/full speed interrupt QHs, if applicable */
if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
list_add(&qh->split_intr_qhs, &ehci->split_intr_qhs);
}
#endif
/* maybe enable periodic schedule processing */
if (!ehci->periodic_sched++)
return enable_periodic (ehci);
@ -555,7 +681,14 @@ static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
// and this qh is active in the current uframe
// (and overlay token SplitXstate is false?)
// THEN
// qh->hw_info1 |= __constant_cpu_to_le32 (1 << 7 /* "ignore" */);
// qh->hw_info1 |= __constant_cpu_to_hc32(1 << 7 /* "ignore" */);
#ifdef CONFIG_CPU_FREQ
/* remove qh from list of low/full speed interrupt QHs */
if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
list_del_init(&qh->split_intr_qhs);
}
#endif
/* high bandwidth, or otherwise part of every microframe */
if ((period = qh->period) == 0)
@ -572,7 +705,7 @@ static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
dev_dbg (&qh->dev->dev,
"unlink qh%d-%04x/%p start %d [%d/%d us]\n",
qh->period,
le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK),
hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK),
qh, qh->start, qh->usecs, qh->c_usecs);
/* qh->qh_next still "live" to HC */
@ -598,7 +731,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
* active high speed queues may need bigger delays...
*/
if (list_empty (&qh->qtd_list)
|| (__constant_cpu_to_le32 (QH_CMASK)
|| (cpu_to_hc32(ehci, QH_CMASK)
& qh->hw_info2) != 0)
wait = 2;
else
@ -606,7 +739,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
udelay (wait);
qh->qh_state = QH_STATE_IDLE;
qh->hw_next = EHCI_LIST_END;
qh->hw_next = EHCI_LIST_END(ehci);
wmb ();
}
@ -663,7 +796,7 @@ static int check_intr_schedule (
unsigned frame,
unsigned uframe,
const struct ehci_qh *qh,
__le32 *c_maskp
__hc32 *c_maskp
)
{
int retval = -ENOSPC;
@ -695,7 +828,7 @@ static int check_intr_schedule (
retval = 0;
*c_maskp = cpu_to_le32 (mask << 8);
*c_maskp = cpu_to_hc32(ehci, mask << 8);
}
#else
/* Make sure this tt's buffer is also available for CSPLITs.
@ -706,7 +839,7 @@ static int check_intr_schedule (
* one smart pass...
*/
mask = 0x03 << (uframe + qh->gap_uf);
*c_maskp = cpu_to_le32 (mask << 8);
*c_maskp = cpu_to_hc32(ehci, mask << 8);
mask |= 1 << uframe;
if (tt_no_collision (ehci, qh->period, qh->dev, frame, mask)) {
@ -730,16 +863,16 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
int status;
unsigned uframe;
__le32 c_mask;
__hc32 c_mask;
unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
qh_refresh(ehci, qh);
qh->hw_next = EHCI_LIST_END;
qh->hw_next = EHCI_LIST_END(ehci);
frame = qh->start;
/* reuse the previous schedule slots, if we can */
if (frame < qh->period) {
uframe = ffs (le32_to_cpup (&qh->hw_info2) & QH_SMASK);
uframe = ffs(hc32_to_cpup(ehci, &qh->hw_info2) & QH_SMASK);
status = check_intr_schedule (ehci, frame, --uframe,
qh, &c_mask);
} else {
@ -775,10 +908,10 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->start = frame;
/* reset S-frame and (maybe) C-frame masks */
qh->hw_info2 &= __constant_cpu_to_le32(~(QH_CMASK | QH_SMASK));
qh->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK));
qh->hw_info2 |= qh->period
? cpu_to_le32 (1 << uframe)
: __constant_cpu_to_le32 (QH_SMASK);
? cpu_to_hc32(ehci, 1 << uframe)
: cpu_to_hc32(ehci, QH_SMASK);
qh->hw_info2 |= c_mask;
} else
ehci_dbg (ehci, "reused qh %p schedule\n", qh);
@ -898,9 +1031,9 @@ iso_stream_init (
buf1 |= maxp;
maxp *= multi;
stream->buf0 = cpu_to_le32 ((epnum << 8) | dev->devnum);
stream->buf1 = cpu_to_le32 (buf1);
stream->buf2 = cpu_to_le32 (multi);
stream->buf0 = cpu_to_hc32(ehci, (epnum << 8) | dev->devnum);
stream->buf1 = cpu_to_hc32(ehci, buf1);
stream->buf2 = cpu_to_hc32(ehci, multi);
/* usbfs wants to report the average usecs per frame tied up
* when transfers on this endpoint are scheduled ...
@ -943,7 +1076,7 @@ iso_stream_init (
bandwidth /= 1 << (interval + 2);
/* stream->splits gets created from raw_mask later */
stream->address = cpu_to_le32 (addr);
stream->address = cpu_to_hc32(ehci, addr);
}
stream->bandwidth = bandwidth;
@ -1078,6 +1211,7 @@ iso_sched_alloc (unsigned packets, gfp_t mem_flags)
static inline void
itd_sched_init(
struct ehci_hcd *ehci,
struct ehci_iso_sched *iso_sched,
struct ehci_iso_stream *stream,
struct urb *urb
@ -1107,7 +1241,7 @@ itd_sched_init (
&& !(urb->transfer_flags & URB_NO_INTERRUPT))
trans |= EHCI_ITD_IOC;
trans |= length << 16;
uframe->transaction = cpu_to_le32 (trans);
uframe->transaction = cpu_to_hc32(ehci, trans);
/* might need to cross a buffer page within a uframe */
uframe->bufp = (buf & ~(u64)0x0fff);
@ -1149,7 +1283,7 @@ itd_urb_transaction (
if (unlikely (sched == NULL))
return -ENOMEM;
itd_sched_init (sched, stream, urb);
itd_sched_init(ehci, sched, stream, urb);
if (urb->interval < 8)
num_itds = 1 + (sched->span + 7) / 8;
@ -1294,7 +1428,7 @@ sitd_slot_ok (
uframe += period_uframes;
} while (uframe < mod);
stream->splits = cpu_to_le32(stream->raw_mask << (uframe & 7));
stream->splits = cpu_to_hc32(ehci, stream->raw_mask << (uframe & 7));
return 1;
}
@ -1415,12 +1549,13 @@ iso_stream_schedule (
/*-------------------------------------------------------------------------*/
static inline void
itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd)
itd_init(struct ehci_hcd *ehci, struct ehci_iso_stream *stream,
struct ehci_itd *itd)
{
int i;
/* it's been recently zeroed */
itd->hw_next = EHCI_LIST_END;
itd->hw_next = EHCI_LIST_END(ehci);
itd->hw_bufp [0] = stream->buf0;
itd->hw_bufp [1] = stream->buf1;
itd->hw_bufp [2] = stream->buf2;
@ -1433,6 +1568,7 @@ itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd)
static inline void
itd_patch(
struct ehci_hcd *ehci,
struct ehci_itd *itd,
struct ehci_iso_sched *iso_sched,
unsigned index,
@ -1448,16 +1584,17 @@ itd_patch (
itd->index [uframe] = index;
itd->hw_transaction[uframe] = uf->transaction;
itd->hw_transaction [uframe] |= cpu_to_le32 (pg << 12);
itd->hw_bufp [pg] |= cpu_to_le32 (uf->bufp & ~(u32)0);
itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(uf->bufp >> 32));
itd->hw_transaction[uframe] |= cpu_to_hc32(ehci, pg << 12);
itd->hw_bufp[pg] |= cpu_to_hc32(ehci, uf->bufp & ~(u32)0);
itd->hw_bufp_hi[pg] |= cpu_to_hc32(ehci, (u32)(uf->bufp >> 32));
/* iso_frame_desc[].offset must be strictly increasing */
if (unlikely (uf->cross)) {
u64 bufp = uf->bufp + 4096;
itd->pg = ++pg;
itd->hw_bufp [pg] |= cpu_to_le32 (bufp & ~(u32)0);
itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(bufp >> 32));
itd->hw_bufp[pg] |= cpu_to_hc32(ehci, bufp & ~(u32)0);
itd->hw_bufp_hi[pg] |= cpu_to_hc32(ehci, (u32)(bufp >> 32));
}
}
@ -1470,7 +1607,7 @@ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
ehci->pshadow [frame].itd = itd;
itd->frame = frame;
wmb ();
ehci->periodic [frame] = cpu_to_le32 (itd->itd_dma) | Q_TYPE_ITD;
ehci->periodic[frame] = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);
}
/* fit urb's itds into the selected schedule slot; activate as needed */
@ -1515,14 +1652,14 @@ itd_link_urb (
list_move_tail (&itd->itd_list, &stream->td_list);
itd->stream = iso_stream_get (stream);
itd->urb = usb_get_urb (urb);
itd_init (stream, itd);
itd_init (ehci, stream, itd);
}
uframe = next_uframe & 0x07;
frame = next_uframe >> 3;
itd->usecs [uframe] = stream->usecs;
itd_patch (itd, iso_sched, packet, uframe);
itd_patch(ehci, itd, iso_sched, packet, uframe);
next_uframe += stream->interval;
stream->depth += stream->interval;
@ -1570,7 +1707,7 @@ itd_complete (
urb_index = itd->index[uframe];
desc = &urb->iso_frame_desc [urb_index];
t = le32_to_cpup (&itd->hw_transaction [uframe]);
t = hc32_to_cpup(ehci, &itd->hw_transaction [uframe]);
itd->hw_transaction [uframe] = 0;
stream->depth -= stream->interval;
@ -1701,6 +1838,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
static inline void
sitd_sched_init(
struct ehci_hcd *ehci,
struct ehci_iso_sched *iso_sched,
struct ehci_iso_stream *stream,
struct urb *urb
@ -1729,7 +1867,7 @@ sitd_sched_init (
&& !(urb->transfer_flags & URB_NO_INTERRUPT))
trans |= SITD_IOC;
trans |= length << 16;
packet->transaction = cpu_to_le32 (trans);
packet->transaction = cpu_to_hc32(ehci, trans);
/* might need to cross a buffer page within a td */
packet->bufp = buf;
@ -1765,7 +1903,7 @@ sitd_urb_transaction (
if (iso_sched == NULL)
return -ENOMEM;
sitd_sched_init (iso_sched, stream, urb);
sitd_sched_init(ehci, iso_sched, stream, urb);
/* allocate/init sITDs */
spin_lock_irqsave (&ehci->lock, flags);
@ -1818,6 +1956,7 @@ sitd_urb_transaction (
static inline void
sitd_patch(
struct ehci_hcd *ehci,
struct ehci_iso_stream *stream,
struct ehci_sitd *sitd,
struct ehci_iso_sched *iso_sched,
@ -1827,20 +1966,20 @@ sitd_patch (
struct ehci_iso_packet *uf = &iso_sched->packet [index];
u64 bufp = uf->bufp;
sitd->hw_next = EHCI_LIST_END;
sitd->hw_next = EHCI_LIST_END(ehci);
sitd->hw_fullspeed_ep = stream->address;
sitd->hw_uframe = stream->splits;
sitd->hw_results = uf->transaction;
sitd->hw_backpointer = EHCI_LIST_END;
sitd->hw_backpointer = EHCI_LIST_END(ehci);
bufp = uf->bufp;
sitd->hw_buf [0] = cpu_to_le32 (bufp);
sitd->hw_buf_hi [0] = cpu_to_le32 (bufp >> 32);
sitd->hw_buf[0] = cpu_to_hc32(ehci, bufp);
sitd->hw_buf_hi[0] = cpu_to_hc32(ehci, bufp >> 32);
sitd->hw_buf [1] = cpu_to_le32 (uf->buf1);
sitd->hw_buf[1] = cpu_to_hc32(ehci, uf->buf1);
if (uf->cross)
bufp += 4096;
sitd->hw_buf_hi [1] = cpu_to_le32 (bufp >> 32);
sitd->hw_buf_hi[1] = cpu_to_hc32(ehci, bufp >> 32);
sitd->index = index;
}
@ -1853,7 +1992,7 @@ sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
ehci->pshadow [frame].sitd = sitd;
sitd->frame = frame;
wmb ();
ehci->periodic [frame] = cpu_to_le32 (sitd->sitd_dma) | Q_TYPE_SITD;
ehci->periodic[frame] = cpu_to_hc32(ehci, sitd->sitd_dma | Q_TYPE_SITD);
}
/* fit urb's sitds into the selected schedule slot; activate as needed */
@ -1881,7 +2020,7 @@ sitd_link_urb (
urb->dev->devpath, stream->bEndpointAddress & 0x0f,
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
(next_uframe >> 3) % ehci->periodic_size,
stream->interval, le32_to_cpu (stream->splits));
stream->interval, hc32_to_cpu(ehci, stream->splits));
stream->start = jiffies;
}
ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
@ -1902,7 +2041,7 @@ sitd_link_urb (
sitd->stream = iso_stream_get (stream);
sitd->urb = usb_get_urb (urb);
sitd_patch (stream, sitd, sched, packet);
sitd_patch(ehci, stream, sitd, sched, packet);
sitd_link (ehci, (next_uframe >> 3) % ehci->periodic_size,
sitd);
@ -1940,7 +2079,7 @@ sitd_complete (
urb_index = sitd->index;
desc = &urb->iso_frame_desc [urb_index];
t = le32_to_cpup (&sitd->hw_results);
t = hc32_to_cpup(ehci, &sitd->hw_results);
/* report transfer status */
if (t & SITD_ERRS) {
@ -2095,7 +2234,7 @@ scan_periodic (struct ehci_hcd *ehci)
for (;;) {
union ehci_shadow q, *q_p;
__le32 type, *hw_p;
__hc32 type, *hw_p;
unsigned uframes;
/* don't scan past the live uframe */
@ -2113,7 +2252,7 @@ scan_periodic (struct ehci_hcd *ehci)
q_p = &ehci->pshadow [frame];
hw_p = &ehci->periodic [frame];
q.ptr = q_p->ptr;
type = Q_NEXT_TYPE (*hw_p);
type = Q_NEXT_TYPE(ehci, *hw_p);
modified = 0;
while (q.ptr != NULL) {
@ -2122,11 +2261,11 @@ scan_periodic (struct ehci_hcd *ehci)
int live;
live = HC_IS_RUNNING (ehci_to_hcd(ehci)->state);
switch (type) {
switch (hc32_to_cpu(ehci, type)) {
case Q_TYPE_QH:
/* handle any completions */
temp.qh = qh_get (q.qh);
type = Q_NEXT_TYPE (q.qh->hw_next);
type = Q_NEXT_TYPE(ehci, q.qh->hw_next);
q = q.qh->qh_next;
modified = qh_completions (ehci, temp.qh);
if (unlikely (list_empty (&temp.qh->qtd_list)))
@ -2137,10 +2276,10 @@ scan_periodic (struct ehci_hcd *ehci)
/* for "save place" FSTNs, look at QH entries
* in the previous frame for completions.
*/
if (q.fstn->hw_prev != EHCI_LIST_END) {
if (q.fstn->hw_prev != EHCI_LIST_END(ehci)) {
dbg ("ignoring completions from FSTNs");
}
type = Q_NEXT_TYPE (q.fstn->hw_next);
type = Q_NEXT_TYPE(ehci, q.fstn->hw_next);
q = q.fstn->fstn_next;
break;
case Q_TYPE_ITD:
@ -2148,11 +2287,12 @@ scan_periodic (struct ehci_hcd *ehci)
rmb ();
for (uf = live ? uframes : 8; uf < 8; uf++) {
if (0 == (q.itd->hw_transaction [uf]
& ITD_ACTIVE))
& ITD_ACTIVE(ehci)))
continue;
q_p = &q.itd->itd_next;
hw_p = &q.itd->hw_next;
type = Q_NEXT_TYPE (q.itd->hw_next);
type = Q_NEXT_TYPE(ehci,
q.itd->hw_next);
q = *q_p;
break;
}
@ -2164,23 +2304,24 @@ scan_periodic (struct ehci_hcd *ehci)
*/
*q_p = q.itd->itd_next;
*hw_p = q.itd->hw_next;
type = Q_NEXT_TYPE (q.itd->hw_next);
type = Q_NEXT_TYPE(ehci, q.itd->hw_next);
wmb();
modified = itd_complete (ehci, q.itd);
q = *q_p;
break;
case Q_TYPE_SITD:
if ((q.sitd->hw_results & SITD_ACTIVE)
if ((q.sitd->hw_results & SITD_ACTIVE(ehci))
&& live) {
q_p = &q.sitd->sitd_next;
hw_p = &q.sitd->hw_next;
type = Q_NEXT_TYPE (q.sitd->hw_next);
type = Q_NEXT_TYPE(ehci,
q.sitd->hw_next);
q = *q_p;
break;
}
*q_p = q.sitd->sitd_next;
*hw_p = q.sitd->hw_next;
type = Q_NEXT_TYPE (q.sitd->hw_next);
type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
wmb();
modified = sitd_complete (ehci, q.sitd);
q = *q_p;

View file

@ -21,6 +21,22 @@
/* definitions used for the EHCI driver */
/*
* __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
* __leXX (normally) or __beXX (given EHCI_BIG_ENDIAN_DESC), depending on
* the host controller implementation.
*
* To facilitate the strongest possible byte-order checking from "sparse"
* and so on, we use __leXX unless that's not practical.
*/
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
typedef __u32 __bitwise __hc32;
typedef __u16 __bitwise __hc16;
#else
#define __hc32 __le32
#define __hc16 __le16
#endif
/* statistics can be kept for for tuning/monitoring */
struct ehci_stats {
/* irq usage */
@ -55,6 +71,12 @@ struct ehci_hcd { /* one per controller */
__u32 hcs_params; /* cached register copy */
spinlock_t lock;
#ifdef CONFIG_CPU_FREQ
struct notifier_block cpufreq_transition;
int cpufreq_changing;
struct list_head split_intr_qhs;
#endif
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *reclaim;
@ -64,7 +86,7 @@ struct ehci_hcd { /* one per controller */
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
unsigned periodic_size;
__le32 *periodic; /* hw periodic table */
__hc32 *periodic; /* hw periodic table */
dma_addr_t periodic_dma;
unsigned i_thresh; /* uframes HC might cache */
@ -74,11 +96,14 @@ struct ehci_hcd { /* one per controller */
/* per root hub port */
unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
/* bit vectors (one bit per port) */
unsigned long bus_suspended; /* which ports were
already suspended at the start of a bus suspend */
unsigned long companion_ports; /* which ports are
dedicated to the companion controller */
unsigned long owned_ports; /* which ports are
owned by the companion during a bus suspend */
/* per-HC memory pools (could be per-bus, but ...) */
struct dma_pool *qh_pool; /* qh per active urb */
@ -97,6 +122,7 @@ struct ehci_hcd { /* one per controller */
unsigned no_selective_suspend:1;
unsigned has_fsl_port_bug:1; /* FreeScale */
unsigned big_endian_mmio:1;
unsigned big_endian_desc:1;
u8 sbrn; /* packed release number */
@ -276,6 +302,12 @@ struct ehci_regs {
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
} __attribute__ ((packed));
#define USBMODE 0x68 /* USB Device mode */
#define USBMODE_SDIS (1<<3) /* Stream disable */
#define USBMODE_BE (1<<2) /* BE/LE endianness select */
#define USBMODE_CM_HC (3<<0) /* host controller mode */
#define USBMODE_CM_IDLE (0<<0) /* idle state */
/* Appendix C, Debug port ... intended for use with special "debug devices"
* that can help if there's no serial console. (nonstandard enumeration.)
*/
@ -303,7 +335,7 @@ struct ehci_dbg_port {
/*-------------------------------------------------------------------------*/
#define QTD_NEXT(dma) cpu_to_le32((u32)dma)
#define QTD_NEXT(ehci, dma) cpu_to_hc32(ehci, (u32)dma)
/*
* EHCI Specification 0.95 Section 3.5
@ -315,9 +347,9 @@ struct ehci_dbg_port {
*/
struct ehci_qtd {
/* first part defined by EHCI spec */
__le32 hw_next; /* see EHCI 3.5.1 */
__le32 hw_alt_next; /* see EHCI 3.5.2 */
__le32 hw_token; /* see EHCI 3.5.3 */
__hc32 hw_next; /* see EHCI 3.5.1 */
__hc32 hw_alt_next; /* see EHCI 3.5.2 */
__hc32 hw_token; /* see EHCI 3.5.3 */
#define QTD_TOGGLE (1 << 31) /* data toggle */
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
#define QTD_IOC (1 << 15) /* interrupt on complete */
@ -331,8 +363,13 @@ struct ehci_qtd {
#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
#define QTD_STS_STS (1 << 1) /* split transaction state */
#define QTD_STS_PING (1 << 0) /* issue PING? */
__le32 hw_buf [5]; /* see EHCI 3.5.4 */
__le32 hw_buf_hi [5]; /* Appendix B */
#define ACTIVE_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_ACTIVE)
#define HALT_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_HALT)
#define STATUS_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_STS)
__hc32 hw_buf [5]; /* see EHCI 3.5.4 */
__hc32 hw_buf_hi [5]; /* Appendix B */
/* the rest is HCD-private */
dma_addr_t qtd_dma; /* qtd address */
@ -342,26 +379,33 @@ struct ehci_qtd {
} __attribute__ ((aligned (32)));
/* mask NakCnt+T in qh->hw_alt_next */
#define QTD_MASK __constant_cpu_to_le32 (~0x1f)
#define QTD_MASK(ehci) cpu_to_hc32 (ehci, ~0x1f)
#define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1)
/*-------------------------------------------------------------------------*/
/* type tag from {qh,itd,sitd,fstn}->hw_next */
#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1))
#define Q_NEXT_TYPE(ehci,dma) ((dma) & cpu_to_hc32(ehci, 3 << 1))
/*
* Now the following defines are not converted using the
* __constant_cpu_to_le32() macro anymore, since we have to support
* "dynamic" switching between be and le support, so that the driver
* can be used on one system with SoC EHCI controller using big-endian
* descriptors as well as a normal little-endian PCI EHCI controller.
*/
/* values for that type tag */
#define Q_TYPE_ITD __constant_cpu_to_le32 (0 << 1)
#define Q_TYPE_QH __constant_cpu_to_le32 (1 << 1)
#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1)
#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1)
#define Q_TYPE_ITD (0 << 1)
#define Q_TYPE_QH (1 << 1)
#define Q_TYPE_SITD (2 << 1)
#define Q_TYPE_FSTN (3 << 1)
/* next async queue entry, or pointer to interrupt/periodic QH */
#define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
#define QH_NEXT(ehci,dma) (cpu_to_hc32(ehci, (((u32)dma)&~0x01f)|Q_TYPE_QH))
/* for periodic/async schedules and qtd lists, mark end of list */
#define EHCI_LIST_END __constant_cpu_to_le32(1) /* "null pointer" to hw */
#define EHCI_LIST_END(ehci) cpu_to_hc32(ehci, 1) /* "null pointer" to hw */
/*
* Entries in periodic shadow table are pointers to one of four kinds
@ -376,7 +420,7 @@ union ehci_shadow {
struct ehci_itd *itd; /* Q_TYPE_ITD */
struct ehci_sitd *sitd; /* Q_TYPE_SITD */
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
__le32 *hw_next; /* (all types) */
__hc32 *hw_next; /* (all types) */
void *ptr;
};
@ -392,23 +436,27 @@ union ehci_shadow {
struct ehci_qh {
/* first part defined by EHCI spec */
__le32 hw_next; /* see EHCI 3.6.1 */
__le32 hw_info1; /* see EHCI 3.6.2 */
__hc32 hw_next; /* see EHCI 3.6.1 */
__hc32 hw_info1; /* see EHCI 3.6.2 */
#define QH_HEAD 0x00008000
__le32 hw_info2; /* see EHCI 3.6.2 */
#define QH_INACTIVATE 0x00000080
#define INACTIVATE_BIT(ehci) cpu_to_hc32(ehci, QH_INACTIVATE)
__hc32 hw_info2; /* see EHCI 3.6.2 */
#define QH_SMASK 0x000000ff
#define QH_CMASK 0x0000ff00
#define QH_HUBADDR 0x007f0000
#define QH_HUBPORT 0x3f800000
#define QH_MULT 0xc0000000
__le32 hw_current; /* qtd list - see EHCI 3.6.4 */
__hc32 hw_current; /* qtd list - see EHCI 3.6.4 */
/* qtd overlay (hardware parts of a struct ehci_qtd) */
__le32 hw_qtd_next;
__le32 hw_alt_next;
__le32 hw_token;
__le32 hw_buf [5];
__le32 hw_buf_hi [5];
__hc32 hw_qtd_next;
__hc32 hw_alt_next;
__hc32 hw_token;
__hc32 hw_buf [5];
__hc32 hw_buf_hi [5];
/* the rest is HCD-private */
dma_addr_t qh_dma; /* address of qh */
@ -418,7 +466,14 @@ struct ehci_qh {
struct ehci_qh *reclaim; /* next to reclaim */
struct ehci_hcd *ehci;
struct kref kref;
/*
* Do NOT use atomic operations for QH refcounting. On some CPUs
* (PPC7448 for example), atomic operations cannot be performed on
* memory that is cache-inhibited (i.e. being used for DMA).
* Spinlocks are used to protect all QH fields.
*/
u32 refcount;
unsigned stamp;
u8 qh_state;
@ -437,6 +492,10 @@ struct ehci_qh {
unsigned short start; /* where polling starts */
#define NO_FRAME ((unsigned short)~0) /* pick new start */
struct usb_device *dev; /* access to TT */
#ifdef CONFIG_CPU_FREQ
struct list_head split_intr_qhs; /* list of split qhs */
__le32 was_active; /* active bit before "i" set */
#endif
} __attribute__ ((aligned (32)));
/*-------------------------------------------------------------------------*/
@ -445,7 +504,7 @@ struct ehci_qh {
struct ehci_iso_packet {
/* These will be copied to iTD when scheduling */
u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */
__le32 transaction; /* itd->hw_transaction[i] |= */
__hc32 transaction; /* itd->hw_transaction[i] |= */
u8 cross; /* buf crosses pages */
/* for full speed OUT splits */
u32 buf1;
@ -467,8 +526,8 @@ struct ehci_iso_sched {
*/
struct ehci_iso_stream {
/* first two fields match QH, but info1 == 0 */
__le32 hw_next;
__le32 hw_info1;
__hc32 hw_next;
__hc32 hw_info1;
u32 refcount;
u8 bEndpointAddress;
@ -483,7 +542,7 @@ struct ehci_iso_stream {
unsigned long start; /* jiffies */
unsigned long rescheduled;
int next_uframe;
__le32 splits;
__hc32 splits;
/* the rest is derived from the endpoint descriptor,
* trusting urb->interval == f(epdesc->bInterval) and
@ -497,12 +556,12 @@ struct ehci_iso_stream {
unsigned bandwidth;
/* This is used to initialize iTD's hw_bufp fields */
__le32 buf0;
__le32 buf1;
__le32 buf2;
__hc32 buf0;
__hc32 buf1;
__hc32 buf2;
/* this is used to initialize sITD's tt info */
__le32 address;
__hc32 address;
};
/*-------------------------------------------------------------------------*/
@ -515,8 +574,8 @@ struct ehci_iso_stream {
*/
struct ehci_itd {
/* first part defined by EHCI spec */
__le32 hw_next; /* see EHCI 3.3.1 */
__le32 hw_transaction [8]; /* see EHCI 3.3.2 */
__hc32 hw_next; /* see EHCI 3.3.1 */
__hc32 hw_transaction [8]; /* see EHCI 3.3.2 */
#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */
#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */
@ -524,10 +583,10 @@ struct ehci_itd {
#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff)
#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */
#define ITD_ACTIVE __constant_cpu_to_le32(EHCI_ISOC_ACTIVE)
#define ITD_ACTIVE(ehci) cpu_to_hc32(ehci, EHCI_ISOC_ACTIVE)
__le32 hw_bufp [7]; /* see EHCI 3.3.3 */
__le32 hw_bufp_hi [7]; /* Appendix B */
__hc32 hw_bufp [7]; /* see EHCI 3.3.3 */
__hc32 hw_bufp_hi [7]; /* Appendix B */
/* the rest is HCD-private */
dma_addr_t itd_dma; /* for this itd */
@ -554,11 +613,11 @@ struct ehci_itd {
*/
struct ehci_sitd {
/* first part defined by EHCI spec */
__le32 hw_next;
__hc32 hw_next;
/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
__le32 hw_fullspeed_ep; /* EHCI table 3-9 */
__le32 hw_uframe; /* EHCI table 3-10 */
__le32 hw_results; /* EHCI table 3-11 */
__hc32 hw_fullspeed_ep; /* EHCI table 3-9 */
__hc32 hw_uframe; /* EHCI table 3-10 */
__hc32 hw_results; /* EHCI table 3-11 */
#define SITD_IOC (1 << 31) /* interrupt on completion */
#define SITD_PAGE (1 << 30) /* buffer 0/1 */
#define SITD_LENGTH(x) (0x3ff & ((x)>>16))
@ -570,11 +629,11 @@ struct ehci_sitd {
#define SITD_STS_MMF (1 << 2) /* incomplete split transaction */
#define SITD_STS_STS (1 << 1) /* split transaction state */
#define SITD_ACTIVE __constant_cpu_to_le32(SITD_STS_ACTIVE)
#define SITD_ACTIVE(ehci) cpu_to_hc32(ehci, SITD_STS_ACTIVE)
__le32 hw_buf [2]; /* EHCI table 3-12 */
__le32 hw_backpointer; /* EHCI table 3-13 */
__le32 hw_buf_hi [2]; /* Appendix B */
__hc32 hw_buf [2]; /* EHCI table 3-12 */
__hc32 hw_backpointer; /* EHCI table 3-13 */
__hc32 hw_buf_hi [2]; /* Appendix B */
/* the rest is HCD-private */
dma_addr_t sitd_dma;
@ -599,8 +658,8 @@ struct ehci_sitd {
* it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
*/
struct ehci_fstn {
__le32 hw_next; /* any periodic q entry */
__le32 hw_prev; /* qh or EHCI_LIST_END */
__hc32 hw_next; /* any periodic q entry */
__hc32 hw_prev; /* qh or EHCI_LIST_END */
/* the rest is HCD-private */
dma_addr_t fstn_dma;
@ -672,6 +731,19 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#define ehci_big_endian_mmio(e) 0
#endif
/*
* Big-endian read/write functions are arch-specific.
* Other arches can be added if/when they're needed.
*
* REVISIT: arch/powerpc now has readl/writel_be, so the
* definition below can die once the 4xx support is
* finally ported over.
*/
#if defined(CONFIG_PPC)
#define readl_be(addr) in_be32((__force unsigned *)addr)
#define writel_be(val, addr) out_be32((__force unsigned *)addr, val)
#endif
static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
__u32 __iomem * regs)
{
@ -698,6 +770,62 @@ static inline void ehci_writel (const struct ehci_hcd *ehci,
/*-------------------------------------------------------------------------*/
/*
* The AMCC 440EPx not only implements its EHCI registers in big-endian
* format, but also its DMA data structures (descriptors).
*
* EHCI controllers accessed through PCI work normally (little-endian
* everywhere), so we won't bother supporting a BE-only mode for now.
*/
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
#define ehci_big_endian_desc(e) ((e)->big_endian_desc)
/* cpu to ehci */
static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x)
{
return ehci_big_endian_desc(ehci)
? (__force __hc32)cpu_to_be32(x)
: (__force __hc32)cpu_to_le32(x);
}
/* ehci to cpu */
static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x)
{
return ehci_big_endian_desc(ehci)
? be32_to_cpu((__force __be32)x)
: le32_to_cpu((__force __le32)x);
}
static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
{
return ehci_big_endian_desc(ehci)
? be32_to_cpup((__force __be32 *)x)
: le32_to_cpup((__force __le32 *)x);
}
#else
/* cpu to ehci */
static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x)
{
return cpu_to_le32(x);
}
/* ehci to cpu */
static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x)
{
return le32_to_cpu(x);
}
static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
{
return le32_to_cpup(x);
}
#endif
/*-------------------------------------------------------------------------*/
#ifndef DEBUG
#define STUB_DEBUG_FILES
#endif /* DEBUG */

View file

@ -23,7 +23,7 @@
/* debug| print the main components of an URB
* small: 0) header + data packets 1) just header
*/
static void __attribute__((unused))
static void __maybe_unused
urb_print (struct urb * urb, char * str, int small)
{
unsigned int pipe= urb->pipe;
@ -338,7 +338,7 @@ static void ohci_dump_td (const struct ohci_hcd *ohci, const char *label,
}
/* caller MUST own hcd spinlock if verbose is set! */
static void __attribute__((unused))
static void __maybe_unused
ohci_dump_ed (const struct ohci_hcd *ohci, const char *label,
const struct ed *ed, int verbose)
{

View file

@ -35,15 +35,13 @@
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/reboot.h>
#include <linux/workqueue.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
#ifdef CONFIG_PPC_PS3
#include <asm/firmware.h>
#endif
#include "../core/hcd.h"
@ -82,6 +80,8 @@ static const char hcd_name [] = "ohci_hcd";
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"
@ -510,15 +510,7 @@ static int ohci_run (struct ohci_hcd *ohci)
// flush the writes
(void) ohci_readl (ohci, &ohci->regs->control);
msleep(temp);
temp = roothub_a (ohci);
if (!(temp & RH_A_NPS)) {
/* power down each port */
for (temp = 0; temp < ohci->num_ports; temp++)
ohci_writel (ohci, RH_PS_LSDA,
&ohci->regs->roothub.portstatus [temp]);
}
// flush those writes
(void) ohci_readl (ohci, &ohci->regs->control);
memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
/* 2msec timelimit here means no irqs/preempt */
@ -659,9 +651,20 @@ 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) {
/* Workaround for a silicon bug in some NEC chips used
* in Apple's PowerBooks. Adapted from Darwin code.
*/
ohci_err (ohci, "OHCI Unrecoverable Error, scheduling NEC chip restart\n");
ohci_writel (ohci, OHCI_INTR_UE, &regs->intrdisable);
schedule_work (&ohci->nec_work);
} else {
disable (ohci);
ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
// e.g. due to PCI Master/Target Abort
}
ohci_dump (ohci, 1);
ohci_usb_reset (ohci);
@ -763,23 +766,16 @@ static void ohci_stop (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
/* must not be called from interrupt context */
#ifdef CONFIG_PM
static int ohci_restart (struct ohci_hcd *ohci)
{
int temp;
int i;
struct urb_priv *priv;
/* mark any devices gone, so they do nothing till khubd disconnects.
* recycle any "live" eds/tds (and urbs) right away.
* later, khubd disconnect processing will recycle the other state,
* (either as disconnect/reconnect, or maybe someday as a reset).
*/
spin_lock_irq(&ohci->lock);
disable (ohci);
usb_root_hub_lost_power(ohci_to_hcd(ohci)->self.root_hub);
/* Recycle any "live" eds/tds (and urbs). */
if (!list_empty (&ohci->pending))
ohci_dbg(ohci, "abort schedule...\n");
list_for_each_entry (priv, &ohci->pending, pending) {
@ -826,20 +822,31 @@ static int ohci_restart (struct ohci_hcd *ohci)
if ((temp = ohci_run (ohci)) < 0) {
ohci_err (ohci, "can't restart, %d\n", temp);
return temp;
} else {
/* here we "know" root ports should always stay powered,
* and that if we try to turn them back on the root hub
* will respond to CSC processing.
*/
i = ohci->num_ports;
while (i--)
ohci_writel (ohci, RH_PS_PSS,
&ohci->regs->roothub.portstatus [i]);
ohci_dbg (ohci, "restart complete\n");
}
ohci_dbg(ohci, "restart complete\n");
return 0;
}
#endif
/*-------------------------------------------------------------------------*/
/* 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);
}
/*-------------------------------------------------------------------------*/
@ -917,7 +924,7 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_PPC_PS3
#include "ohci-ps3.c"
#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_driver
#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver
#endif
#if !defined(PCI_DRIVER) && \
@ -940,12 +947,9 @@ static int __init ohci_hcd_mod_init(void)
sizeof (struct ed), sizeof (struct td));
#ifdef PS3_SYSTEM_BUS_DRIVER
if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
retval = ps3_system_bus_driver_register(
&PS3_SYSTEM_BUS_DRIVER);
retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
if (retval < 0)
goto error_ps3;
}
#endif
#ifdef PLATFORM_DRIVER
@ -991,8 +995,7 @@ static int __init ohci_hcd_mod_init(void)
error_platform:
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
if (firmware_has_feature(FW_FEATURE_PS3_LV1))
ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
error_ps3:
#endif
return retval;
@ -1014,8 +1017,7 @@ static void __exit ohci_hcd_mod_exit(void)
platform_driver_unregister(&PLATFORM_DRIVER);
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
if (firmware_has_feature(FW_FEATURE_PS3_LV1))
ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
#endif
}
module_exit(ohci_hcd_mod_exit);

View file

@ -55,8 +55,6 @@ static void dl_done_list (struct ohci_hcd *);
static void finish_unlinks (struct ohci_hcd *, u16);
#ifdef CONFIG_PM
static int ohci_restart(struct ohci_hcd *ohci);
static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop)
__releases(ohci->lock)
__acquires(ohci->lock)
@ -191,6 +189,9 @@ __acquires(ohci->lock)
spin_unlock_irq (&ohci->lock);
(void) ohci_init (ohci);
status = ohci_restart (ohci);
usb_root_hub_lost_power(hcd->self.root_hub);
spin_lock_irq (&ohci->lock);
}
return status;

View file

@ -28,6 +28,7 @@ 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

@ -111,6 +111,18 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
#endif
}
/* Check for NEC chip and apply quirk for allegedly lost interrupts.
*/
static int ohci_quirk_nec(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci->flags |= OHCI_QUIRK_NEC;
ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
return 0;
}
/* List of quirks for OHCI */
static const struct pci_device_id ohci_pci_quirks[] = {
{
@ -133,6 +145,10 @@ static const struct pci_device_id ohci_pci_quirks[] = {
PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
.driver_data = (unsigned long)ohci_quirk_toshiba_scc,
},
{
PCI_DEVICE(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB),
.driver_data = (unsigned long)ohci_quirk_nec,
},
{
/* Toshiba portege 4000 */
.vendor = PCI_VENDOR_ID_AL,
@ -202,6 +218,42 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd)
return ret;
}
#if defined(CONFIG_USB_PERSIST) && (defined(CONFIG_USB_EHCI_HCD) || \
defined(CONFIG_USB_EHCI_HCD_MODULE))
/* Following a power loss, we must prepare to regain control of the ports
* we used to own. This means turning on the port power before ehci-hcd
* tries to switch ownership.
*
* This isn't a 100% perfect solution. On most systems the OHCI controllers
* lie at lower PCI addresses than the EHCI controller, so they will be
* discovered (and hence resumed) first. But there is no guarantee things
* will always work this way. If the EHCI controller is resumed first and
* the OHCI ports are unpowered, then the handover will fail.
*/
static void prepare_for_handover(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int port;
/* Here we "know" root ports should always stay powered */
ohci_dbg(ohci, "powerup ports\n");
for (port = 0; port < ohci->num_ports; port++)
ohci_writel(ohci, RH_PS_PPS,
&ohci->regs->roothub.portstatus[port]);
/* Flush those writes */
ohci_readl(ohci, &ohci->regs->control);
msleep(20);
}
#else
static inline void prepare_for_handover(struct usb_hcd *hcd)
{ }
#endif /* CONFIG_USB_PERSIST etc. */
#ifdef CONFIG_PM
static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
@ -241,7 +293,10 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
static int ohci_pci_resume (struct usb_hcd *hcd)
{
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
usb_hcd_resume_root_hub(hcd);
/* FIXME: we should try to detect loss of VBUS power here */
prepare_for_handover(hcd);
return 0;
}

View file

@ -134,7 +134,7 @@ static int isp1301_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct i2c_client *c;
c = (struct i2c_client *)kzalloc(sizeof(*c), GFP_KERNEL);
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return -ENOMEM;

View file

@ -18,6 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/firmware.h>
#include <asm/ps3.h>
static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
@ -75,7 +76,7 @@ static const struct hc_driver ps3_ohci_hc_driver = {
#endif
};
static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
static int ps3_ohci_probe(struct ps3_system_bus_device *dev)
{
int result;
struct usb_hcd *hcd;
@ -87,13 +88,31 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
goto fail_start;
}
result = ps3_open_hv_device(dev);
if (result) {
dev_dbg(&dev->core, "%s:%d: ps3_open_hv_device failed: %s\n",
__func__, __LINE__, ps3_result(result));
result = -EPERM;
goto fail_open;
}
result = ps3_dma_region_create(dev->d_region);
if (result) {
dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: "
"(%d)\n", __func__, __LINE__, result);
BUG_ON("check region type");
goto fail_dma_region;
}
result = ps3_mmio_region_create(dev->m_region);
if (result) {
dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
__func__, __LINE__);
result = -EPERM;
goto fail_mmio;
goto fail_mmio_region;
}
dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
@ -122,6 +141,11 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
hcd->rsrc_start = dev->m_region->lpar_addr;
hcd->rsrc_len = dev->m_region->len;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name))
dev_dbg(&dev->core, "%s:%d: request_mem_region failed\n",
__func__, __LINE__);
hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
if (!hcd->regs) {
@ -155,34 +179,73 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
fail_add_hcd:
iounmap(hcd->regs);
fail_ioremap:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
fail_create_hcd:
ps3_io_irq_destroy(virq);
fail_irq:
ps3_free_mmio_region(dev->m_region);
fail_mmio:
fail_mmio_region:
ps3_dma_region_free(dev->d_region);
fail_dma_region:
ps3_close_hv_device(dev);
fail_open:
fail_start:
return result;
}
static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
static int ps3_ohci_remove (struct ps3_system_bus_device *dev)
{
unsigned int tmp;
struct usb_hcd *hcd =
(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
usb_put_hcd(hcd);
BUG_ON(!hcd);
dev_dbg(&dev->core, "%s:%d: regs %p\n", __func__, __LINE__, hcd->regs);
dev_dbg(&dev->core, "%s:%d: irq %u\n", __func__, __LINE__, hcd->irq);
tmp = hcd->irq;
usb_remove_hcd(hcd);
ps3_system_bus_set_driver_data(dev, NULL);
BUG_ON(!hcd->regs);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
ps3_io_irq_destroy(tmp);
ps3_free_mmio_region(dev->m_region);
ps3_dma_region_free(dev->d_region);
ps3_close_hv_device(dev);
return 0;
}
MODULE_ALIAS("ps3-ohci");
static int ps3_ohci_driver_register(struct ps3_system_bus_driver *drv)
{
return firmware_has_feature(FW_FEATURE_PS3_LV1)
? ps3_system_bus_driver_register(drv)
: 0;
}
static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
static void ps3_ohci_driver_unregister(struct ps3_system_bus_driver *drv)
{
if (firmware_has_feature(FW_FEATURE_PS3_LV1))
ps3_system_bus_driver_unregister(drv);
}
MODULE_ALIAS(PS3_MODULE_ALIAS_OHCI);
static struct ps3_system_bus_driver ps3_ohci_driver = {
.core.name = "ps3-ohci-driver",
.core.owner = THIS_MODULE,
.match_id = PS3_MATCH_ID_OHCI,
.core = {
.name = "ps3-ohci-driver",
},
.probe = ps3_ohci_sb_probe,
.remove = ps3_ohci_sb_remove,
.probe = ps3_ohci_probe,
.remove = ps3_ohci_remove,
.shutdown = ps3_ohci_remove,
};

View file

@ -397,8 +397,10 @@ struct ohci_hcd {
#define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */
#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */
#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/
#define OHCI_QUIRK_NEC 0x40 /* lost interrupts */
// there are also chip quirks/bugs in init logic
struct work_struct nec_work; /* Worker for NEC quirk */
};
/* convert between an hcd pointer and the corresponding ohci_hcd */

File diff suppressed because it is too large Load diff

634
drivers/usb/host/r8a66597.h Normal file
View file

@ -0,0 +1,634 @@
/*
* R8A66597 HCD (Host Controller Driver)
*
* Copyright (C) 2006-2007 Renesas Solutions Corp.
* Portions Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
* Portions Copyright (C) 2004-2005 David Brownell
* Portions Copyright (C) 1999 Roman Weissgaerber
*
* Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef __R8A66597_H__
#define __R8A66597_H__
#define SYSCFG0 0x00
#define SYSCFG1 0x02
#define SYSSTS0 0x04
#define SYSSTS1 0x06
#define DVSTCTR0 0x08
#define DVSTCTR1 0x0A
#define TESTMODE 0x0C
#define PINCFG 0x0E
#define DMA0CFG 0x10
#define DMA1CFG 0x12
#define CFIFO 0x14
#define D0FIFO 0x18
#define D1FIFO 0x1C
#define CFIFOSEL 0x20
#define CFIFOCTR 0x22
#define CFIFOSIE 0x24
#define D0FIFOSEL 0x28
#define D0FIFOCTR 0x2A
#define D1FIFOSEL 0x2C
#define D1FIFOCTR 0x2E
#define INTENB0 0x30
#define INTENB1 0x32
#define INTENB2 0x34
#define BRDYENB 0x36
#define NRDYENB 0x38
#define BEMPENB 0x3A
#define SOFCFG 0x3C
#define INTSTS0 0x40
#define INTSTS1 0x42
#define INTSTS2 0x44
#define BRDYSTS 0x46
#define NRDYSTS 0x48
#define BEMPSTS 0x4A
#define FRMNUM 0x4C
#define UFRMNUM 0x4E
#define USBADDR 0x50
#define USBREQ 0x54
#define USBVAL 0x56
#define USBINDX 0x58
#define USBLENG 0x5A
#define DCPCFG 0x5C
#define DCPMAXP 0x5E
#define DCPCTR 0x60
#define PIPESEL 0x64
#define PIPECFG 0x68
#define PIPEBUF 0x6A
#define PIPEMAXP 0x6C
#define PIPEPERI 0x6E
#define PIPE1CTR 0x70
#define PIPE2CTR 0x72
#define PIPE3CTR 0x74
#define PIPE4CTR 0x76
#define PIPE5CTR 0x78
#define PIPE6CTR 0x7A
#define PIPE7CTR 0x7C
#define PIPE8CTR 0x7E
#define PIPE9CTR 0x80
#define PIPE1TRE 0x90
#define PIPE1TRN 0x92
#define PIPE2TRE 0x94
#define PIPE2TRN 0x96
#define PIPE3TRE 0x98
#define PIPE3TRN 0x9A
#define PIPE4TRE 0x9C
#define PIPE4TRN 0x9E
#define PIPE5TRE 0xA0
#define PIPE5TRN 0xA2
#define DEVADD0 0xD0
#define DEVADD1 0xD2
#define DEVADD2 0xD4
#define DEVADD3 0xD6
#define DEVADD4 0xD8
#define DEVADD5 0xDA
#define DEVADD6 0xDC
#define DEVADD7 0xDE
#define DEVADD8 0xE0
#define DEVADD9 0xE2
#define DEVADDA 0xE4
/* System Configuration Control Register */
#define XTAL 0xC000 /* b15-14: Crystal selection */
#define XTAL48 0x8000 /* 48MHz */
#define XTAL24 0x4000 /* 24MHz */
#define XTAL12 0x0000 /* 12MHz */
#define XCKE 0x2000 /* b13: External clock enable */
#define PLLC 0x0800 /* b11: PLL control */
#define SCKE 0x0400 /* b10: USB clock enable */
#define PCSDIS 0x0200 /* b9: not CS wakeup */
#define LPSME 0x0100 /* b8: Low power sleep mode */
#define HSE 0x0080 /* b7: Hi-speed enable */
#define DCFM 0x0040 /* b6: Controller function select */
#define DRPD 0x0020 /* b5: D+/- pull down control */
#define DPRPU 0x0010 /* b4: D+ pull up control */
#define USBE 0x0001 /* b0: USB module operation enable */
/* System Configuration Status Register */
#define OVCBIT 0x8000 /* b15-14: Over-current bit */
#define OVCMON 0xC000 /* b15-14: Over-current monitor */
#define SOFEA 0x0020 /* b5: SOF monitor */
#define IDMON 0x0004 /* b3: ID-pin monitor */
#define LNST 0x0003 /* b1-0: D+, D- line status */
#define SE1 0x0003 /* SE1 */
#define FS_KSTS 0x0002 /* Full-Speed K State */
#define FS_JSTS 0x0001 /* Full-Speed J State */
#define LS_JSTS 0x0002 /* Low-Speed J State */
#define LS_KSTS 0x0001 /* Low-Speed K State */
#define SE0 0x0000 /* SE0 */
/* Device State Control Register */
#define EXTLP0 0x0400 /* b10: External port */
#define VBOUT 0x0200 /* b9: VBUS output */
#define WKUP 0x0100 /* b8: Remote wakeup */
#define RWUPE 0x0080 /* b7: Remote wakeup sense */
#define USBRST 0x0040 /* b6: USB reset enable */
#define RESUME 0x0020 /* b5: Resume enable */
#define UACT 0x0010 /* b4: USB bus enable */
#define RHST 0x0007 /* b1-0: Reset handshake status */
#define HSPROC 0x0004 /* HS handshake is processing */
#define HSMODE 0x0003 /* Hi-Speed mode */
#define FSMODE 0x0002 /* Full-Speed mode */
#define LSMODE 0x0001 /* Low-Speed mode */
#define UNDECID 0x0000 /* Undecided */
/* Test Mode Register */
#define UTST 0x000F /* b3-0: Test select */
#define H_TST_PACKET 0x000C /* HOST TEST Packet */
#define H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
#define H_TST_K 0x000A /* HOST TEST K */
#define H_TST_J 0x0009 /* HOST TEST J */
#define H_TST_NORMAL 0x0000 /* HOST Normal Mode */
#define P_TST_PACKET 0x0004 /* PERI TEST Packet */
#define P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
#define P_TST_K 0x0002 /* PERI TEST K */
#define P_TST_J 0x0001 /* PERI TEST J */
#define P_TST_NORMAL 0x0000 /* PERI Normal Mode */
/* Data Pin Configuration Register */
#define LDRV 0x8000 /* b15: Drive Current Adjust */
#define VIF1 0x0000 /* VIF = 1.8V */
#define VIF3 0x8000 /* VIF = 3.3V */
#define INTA 0x0001 /* b1: USB INT-pin active */
/* DMAx Pin Configuration Register */
#define DREQA 0x4000 /* b14: Dreq active select */
#define BURST 0x2000 /* b13: Burst mode */
#define DACKA 0x0400 /* b10: Dack active select */
#define DFORM 0x0380 /* b9-7: DMA mode select */
#define CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
#define CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
#define CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
#define SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
#define DENDA 0x0040 /* b6: Dend active select */
#define PKTM 0x0020 /* b5: Packet mode */
#define DENDE 0x0010 /* b4: Dend enable */
#define OBUS 0x0004 /* b2: OUTbus mode */
/* CFIFO/DxFIFO Port Select Register */
#define RCNT 0x8000 /* b15: Read count mode */
#define REW 0x4000 /* b14: Buffer rewind */
#define DCLRM 0x2000 /* b13: DMA buffer clear mode */
#define DREQE 0x1000 /* b12: DREQ output enable */
#define MBW 0x0400 /* b10: Maximum bit width for FIFO access */
#define MBW_8 0x0000 /* 8bit */
#define MBW_16 0x0400 /* 16bit */
#define BIGEND 0x0100 /* b8: Big endian mode */
#define BYTE_LITTLE 0x0000 /* little dendian */
#define BYTE_BIG 0x0100 /* big endifan */
#define ISEL 0x0020 /* b5: DCP FIFO port direction select */
#define CURPIPE 0x000F /* b2-0: PIPE select */
/* CFIFO/DxFIFO Port Control Register */
#define BVAL 0x8000 /* b15: Buffer valid flag */
#define BCLR 0x4000 /* b14: Buffer clear */
#define FRDY 0x2000 /* b13: FIFO ready */
#define DTLN 0x0FFF /* b11-0: FIFO received data length */
/* Interrupt Enable Register 0 */
#define VBSE 0x8000 /* b15: VBUS interrupt */
#define RSME 0x4000 /* b14: Resume interrupt */
#define SOFE 0x2000 /* b13: Frame update interrupt */
#define DVSE 0x1000 /* b12: Device state transition interrupt */
#define CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
#define BEMPE 0x0400 /* b10: Buffer empty interrupt */
#define NRDYE 0x0200 /* b9: Buffer not ready interrupt */
#define BRDYE 0x0100 /* b8: Buffer ready interrupt */
/* Interrupt Enable Register 1 */
#define OVRCRE 0x8000 /* b15: Over-current interrupt */
#define BCHGE 0x4000 /* b14: USB us chenge interrupt */
#define DTCHE 0x1000 /* b12: Detach sense interrupt */
#define ATTCHE 0x0800 /* b11: Attach sense interrupt */
#define EOFERRE 0x0040 /* b6: EOF error interrupt */
#define SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
#define SACKE 0x0010 /* b4: SETUP ACK interrupt */
/* BRDY Interrupt Enable/Status Register */
#define BRDY9 0x0200 /* b9: PIPE9 */
#define BRDY8 0x0100 /* b8: PIPE8 */
#define BRDY7 0x0080 /* b7: PIPE7 */
#define BRDY6 0x0040 /* b6: PIPE6 */
#define BRDY5 0x0020 /* b5: PIPE5 */
#define BRDY4 0x0010 /* b4: PIPE4 */
#define BRDY3 0x0008 /* b3: PIPE3 */
#define BRDY2 0x0004 /* b2: PIPE2 */
#define BRDY1 0x0002 /* b1: PIPE1 */
#define BRDY0 0x0001 /* b1: PIPE0 */
/* NRDY Interrupt Enable/Status Register */
#define NRDY9 0x0200 /* b9: PIPE9 */
#define NRDY8 0x0100 /* b8: PIPE8 */
#define NRDY7 0x0080 /* b7: PIPE7 */
#define NRDY6 0x0040 /* b6: PIPE6 */
#define NRDY5 0x0020 /* b5: PIPE5 */
#define NRDY4 0x0010 /* b4: PIPE4 */
#define NRDY3 0x0008 /* b3: PIPE3 */
#define NRDY2 0x0004 /* b2: PIPE2 */
#define NRDY1 0x0002 /* b1: PIPE1 */
#define NRDY0 0x0001 /* b1: PIPE0 */
/* BEMP Interrupt Enable/Status Register */
#define BEMP9 0x0200 /* b9: PIPE9 */
#define BEMP8 0x0100 /* b8: PIPE8 */
#define BEMP7 0x0080 /* b7: PIPE7 */
#define BEMP6 0x0040 /* b6: PIPE6 */
#define BEMP5 0x0020 /* b5: PIPE5 */
#define BEMP4 0x0010 /* b4: PIPE4 */
#define BEMP3 0x0008 /* b3: PIPE3 */
#define BEMP2 0x0004 /* b2: PIPE2 */
#define BEMP1 0x0002 /* b1: PIPE1 */
#define BEMP0 0x0001 /* b0: PIPE0 */
/* SOF Pin Configuration Register */
#define TRNENSEL 0x0100 /* b8: Select transaction enable period */
#define BRDYM 0x0040 /* b6: BRDY clear timing */
#define INTL 0x0020 /* b5: Interrupt sense select */
#define EDGESTS 0x0010 /* b4: */
#define SOFMODE 0x000C /* b3-2: SOF pin select */
#define SOF_125US 0x0008 /* SOF OUT 125us Frame Signal */
#define SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
#define SOF_DISABLE 0x0000 /* SOF OUT Disable */
/* Interrupt Status Register 0 */
#define VBINT 0x8000 /* b15: VBUS interrupt */
#define RESM 0x4000 /* b14: Resume interrupt */
#define SOFR 0x2000 /* b13: SOF frame update interrupt */
#define DVST 0x1000 /* b12: Device state transition interrupt */
#define CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
#define BEMP 0x0400 /* b10: Buffer empty interrupt */
#define NRDY 0x0200 /* b9: Buffer not ready interrupt */
#define BRDY 0x0100 /* b8: Buffer ready interrupt */
#define VBSTS 0x0080 /* b7: VBUS input port */
#define DVSQ 0x0070 /* b6-4: Device state */
#define DS_SPD_CNFG 0x0070 /* Suspend Configured */
#define DS_SPD_ADDR 0x0060 /* Suspend Address */
#define DS_SPD_DFLT 0x0050 /* Suspend Default */
#define DS_SPD_POWR 0x0040 /* Suspend Powered */
#define DS_SUSP 0x0040 /* Suspend */
#define DS_CNFG 0x0030 /* Configured */
#define DS_ADDS 0x0020 /* Address */
#define DS_DFLT 0x0010 /* Default */
#define DS_POWR 0x0000 /* Powered */
#define DVSQS 0x0030 /* b5-4: Device state */
#define VALID 0x0008 /* b3: Setup packet detected flag */
#define CTSQ 0x0007 /* b2-0: Control transfer stage */
#define CS_SQER 0x0006 /* Sequence error */
#define CS_WRND 0x0005 /* Control write nodata status stage */
#define CS_WRSS 0x0004 /* Control write status stage */
#define CS_WRDS 0x0003 /* Control write data stage */
#define CS_RDSS 0x0002 /* Control read status stage */
#define CS_RDDS 0x0001 /* Control read data stage */
#define CS_IDST 0x0000 /* Idle or setup stage */
/* Interrupt Status Register 1 */
#define OVRCR 0x8000 /* b15: Over-current interrupt */
#define BCHG 0x4000 /* b14: USB bus chenge interrupt */
#define DTCH 0x1000 /* b12: Detach sense interrupt */
#define ATTCH 0x0800 /* b11: Attach sense interrupt */
#define EOFERR 0x0040 /* b6: EOF-error interrupt */
#define SIGN 0x0020 /* b5: Setup ignore interrupt */
#define SACK 0x0010 /* b4: Setup acknowledge interrupt */
/* Frame Number Register */
#define OVRN 0x8000 /* b15: Overrun error */
#define CRCE 0x4000 /* b14: Received data error */
#define FRNM 0x07FF /* b10-0: Frame number */
/* Micro Frame Number Register */
#define UFRNM 0x0007 /* b2-0: Micro frame number */
/* USB Address / Low Power Status Recovery Register */
//#define USBADDR 0x007F /* b6-0: USB address */
/* Default Control Pipe Maxpacket Size Register */
/* Pipe Maxpacket Size Register */
#define DEVSEL 0xF000 /* b15-14: Device address select */
#define MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
/* Default Control Pipe Control Register */
#define BSTS 0x8000 /* b15: Buffer status */
#define SUREQ 0x4000 /* b14: Send USB request */
#define CSCLR 0x2000 /* b13: complete-split status clear */
#define CSSTS 0x1000 /* b12: complete-split status */
#define SUREQCLR 0x0800 /* b11: stop setup request */
#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
#define SQSET 0x0080 /* b7: Sequence toggle bit set */
#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
#define PBUSY 0x0020 /* b5: pipe busy */
#define PINGE 0x0010 /* b4: ping enable */
#define CCPL 0x0004 /* b2: Enable control transfer complete */
#define PID 0x0003 /* b1-0: Response PID */
#define PID_STALL11 0x0003 /* STALL */
#define PID_STALL 0x0002 /* STALL */
#define PID_BUF 0x0001 /* BUF */
#define PID_NAK 0x0000 /* NAK */
/* Pipe Window Select Register */
#define PIPENM 0x0007 /* b2-0: Pipe select */
/* Pipe Configuration Register */
#define R8A66597_TYP 0xC000 /* b15-14: Transfer type */
#define R8A66597_ISO 0xC000 /* Isochronous */
#define R8A66597_INT 0x8000 /* Interrupt */
#define R8A66597_BULK 0x4000 /* Bulk */
#define R8A66597_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */
#define R8A66597_DBLB 0x0200 /* b9: Double buffer mode select */
#define R8A66597_CNTMD 0x0100 /* b8: Continuous transfer mode select */
#define R8A66597_SHTNAK 0x0080 /* b7: Transfer end NAK */
#define R8A66597_DIR 0x0010 /* b4: Transfer direction select */
#define R8A66597_EPNUM 0x000F /* b3-0: Eendpoint number select */
/* Pipe Buffer Configuration Register */
#define BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
#define BUFNMB 0x007F /* b6-0: Pipe buffer number */
#define PIPE0BUF 256
#define PIPExBUF 64
/* Pipe Maxpacket Size Register */
#define MXPS 0x07FF /* b10-0: Maxpacket size */
/* Pipe Cycle Configuration Register */
#define IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
#define IITV 0x0007 /* b2-0: Isochronous interval */
/* Pipex Control Register */
#define BSTS 0x8000 /* b15: Buffer status */
#define INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
#define CSCLR 0x2000 /* b13: complete-split status clear */
#define CSSTS 0x1000 /* b12: complete-split status */
#define ATREPM 0x0400 /* b10: Auto repeat mode */
#define ACLRM 0x0200 /* b9: Out buffer auto clear mode */
#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
#define SQSET 0x0080 /* b7: Sequence toggle bit set */
#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
#define PBUSY 0x0020 /* b5: pipe busy */
#define PID 0x0003 /* b1-0: Response PID */
/* PIPExTRE */
#define TRENB 0x0200 /* b9: Transaction counter enable */
#define TRCLR 0x0100 /* b8: Transaction counter clear */
/* PIPExTRN */
#define TRNCNT 0xFFFF /* b15-0: Transaction counter */
/* DEVADDx */
#define UPPHUB 0x7800
#define HUBPORT 0x0700
#define USBSPD 0x00C0
#define RTPORT 0x0001
#define R8A66597_MAX_NUM_PIPE 10
#define R8A66597_BUF_BSIZE 8
#define R8A66597_MAX_DEVICE 10
#define R8A66597_MAX_ROOT_HUB 2
#define R8A66597_MAX_SAMPLING 10
#define R8A66597_MAX_DMA_CHANNEL 2
#define R8A66597_PIPE_NO_DMA R8A66597_MAX_DMA_CHANNEL
#define check_bulk_or_isoc(pipenum) ((pipenum >= 1 && pipenum <= 5))
#define check_interrupt(pipenum) ((pipenum >= 6 && pipenum <= 9))
#define make_devsel(addr) (addr << 12)
struct r8a66597_pipe_info {
u16 pipenum;
u16 address; /* R8A66597 HCD usb addres */
u16 epnum;
u16 maxpacket;
u16 type;
u16 bufnum;
u16 buf_bsize;
u16 interval;
u16 dir_in;
};
struct r8a66597_pipe {
struct r8a66597_pipe_info info;
unsigned long fifoaddr;
unsigned long fifosel;
unsigned long fifoctr;
unsigned long pipectr;
unsigned long pipetre;
unsigned long pipetrn;
};
struct r8a66597_td {
struct r8a66597_pipe *pipe;
struct urb *urb;
struct list_head queue;
u16 type;
u16 pipenum;
int iso_cnt;
u16 address; /* R8A66597's USB address */
u16 maxpacket;
unsigned zero_packet:1;
unsigned short_packet:1;
unsigned set_address:1;
};
struct r8a66597_device {
u16 address; /* R8A66597's USB address */
u16 hub_port;
u16 root_port;
unsigned short ep_in_toggle;
unsigned short ep_out_toggle;
unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE];
unsigned char dma_map;
enum usb_device_state state;
struct usb_device *udev;
int usb_address;
struct list_head device_list;
};
struct r8a66597_root_hub {
u32 port;
u16 old_syssts;
int scount;
struct r8a66597_device *dev;
};
struct r8a66597 {
spinlock_t lock;
unsigned long reg;
struct r8a66597_device device0;
struct r8a66597_root_hub root_hub[R8A66597_MAX_ROOT_HUB];
struct list_head pipe_queue[R8A66597_MAX_NUM_PIPE];
struct timer_list rh_timer;
struct timer_list td_timer[R8A66597_MAX_NUM_PIPE];
unsigned short address_map;
unsigned short timeout_map;
unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE];
unsigned char dma_map;
struct list_head child_device;
unsigned long child_connect_map[4];
};
static inline struct r8a66597 *hcd_to_r8a66597(struct usb_hcd *hcd)
{
return (struct r8a66597 *)(hcd->hcd_priv);
}
static inline struct usb_hcd *r8a66597_to_hcd(struct r8a66597 *r8a66597)
{
return container_of((void *)r8a66597, struct usb_hcd, hcd_priv);
}
static inline struct r8a66597_td *r8a66597_get_td(struct r8a66597 *r8a66597,
u16 pipenum)
{
if (unlikely(list_empty(&r8a66597->pipe_queue[pipenum])))
return NULL;
return list_entry(r8a66597->pipe_queue[pipenum].next,
struct r8a66597_td, queue);
}
static inline struct urb *r8a66597_get_urb(struct r8a66597 *r8a66597,
u16 pipenum)
{
struct r8a66597_td *td;
td = r8a66597_get_td(r8a66597, pipenum);
return (td ? td->urb : NULL);
}
static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
{
return inw(r8a66597->reg + offset);
}
static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
unsigned long offset, u16 *buf,
int len)
{
len = (len + 1) / 2;
insw(r8a66597->reg + offset, buf, len);
}
static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
unsigned long offset)
{
outw(val, r8a66597->reg + offset);
}
static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
unsigned long offset, u16 *buf,
int len)
{
unsigned long fifoaddr = r8a66597->reg + offset;
int odd = len & 0x0001;
len = len / 2;
outsw(fifoaddr, buf, len);
if (unlikely(odd)) {
buf = &buf[len];
outb((unsigned char)*buf, fifoaddr);
}
}
static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
u16 val, u16 pat, unsigned long offset)
{
u16 tmp;
tmp = r8a66597_read(r8a66597, offset);
tmp = tmp & (~pat);
tmp = tmp | val;
r8a66597_write(r8a66597, tmp, offset);
}
#define r8a66597_bclr(r8a66597, val, offset) \
r8a66597_mdfy(r8a66597, 0, val, offset)
#define r8a66597_bset(r8a66597, val, offset) \
r8a66597_mdfy(r8a66597, val, 0, offset)
static inline unsigned long get_syscfg_reg(int port)
{
return port == 0 ? SYSCFG0 : SYSCFG1;
}
static inline unsigned long get_syssts_reg(int port)
{
return port == 0 ? SYSSTS0 : SYSSTS1;
}
static inline unsigned long get_dvstctr_reg(int port)
{
return port == 0 ? DVSTCTR0 : DVSTCTR1;
}
static inline unsigned long get_intenb_reg(int port)
{
return port == 0 ? INTENB1 : INTENB2;
}
static inline unsigned long get_intsts_reg(int port)
{
return port == 0 ? INTSTS1 : INTSTS2;
}
static inline u16 get_rh_usb_speed(struct r8a66597 *r8a66597, int port)
{
unsigned long dvstctr_reg = get_dvstctr_reg(port);
return r8a66597_read(r8a66597, dvstctr_reg) & RHST;
}
static inline void r8a66597_port_power(struct r8a66597 *r8a66597, int port,
int power)
{
unsigned long dvstctr_reg = get_dvstctr_reg(port);
if (power)
r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
else
r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
}
#define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2)
#define get_pipetre_addr(pipenum) (PIPE1TRE + (pipenum - 1) * 4)
#define get_pipetrn_addr(pipenum) (PIPE1TRN + (pipenum - 1) * 4)
#define get_devadd_addr(address) (DEVADD0 + address * 2)
#define enable_irq_ready(r8a66597, pipenum) \
enable_pipe_irq(r8a66597, pipenum, BRDYENB)
#define disable_irq_ready(r8a66597, pipenum) \
disable_pipe_irq(r8a66597, pipenum, BRDYENB)
#define enable_irq_empty(r8a66597, pipenum) \
enable_pipe_irq(r8a66597, pipenum, BEMPENB)
#define disable_irq_empty(r8a66597, pipenum) \
disable_pipe_irq(r8a66597, pipenum, BEMPENB)
#define enable_irq_nrdy(r8a66597, pipenum) \
enable_pipe_irq(r8a66597, pipenum, NRDYENB)
#define disable_irq_nrdy(r8a66597, pipenum) \
disable_pipe_irq(r8a66597, pipenum, NRDYENB)
#endif /* __R8A66597_H__ */

View file

@ -730,10 +730,9 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
int rc = 0;
spin_lock_irq(&uhci->lock);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
dev_warn(&hcd->self.root_hub->dev, "HC isn't running!\n");
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
rc = -ESHUTDOWN;
} else if (!uhci->dead)
else if (!uhci->dead)
wakeup_rh(uhci);
spin_unlock_irq(&uhci->lock);
return rc;

View file

@ -108,8 +108,6 @@ struct adu_device {
struct urb* interrupt_out_urb;
};
/* prevent races between open() and disconnect */
static DEFINE_MUTEX(disconnect_mutex);
static struct usb_driver adu_driver;
static void adu_debug_data(int level, const char *function, int size,
@ -256,8 +254,6 @@ static int adu_open(struct inode *inode, struct file *file)
subminor = iminor(inode);
mutex_lock(&disconnect_mutex);
interface = usb_find_interface(&adu_driver, subminor);
if (!interface) {
err("%s - error, can't find device for minor %d",
@ -306,7 +302,6 @@ static int adu_open(struct inode *inode, struct file *file)
up(&dev->sem);
exit_no_device:
mutex_unlock(&disconnect_mutex);
dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
return retval;
@ -318,12 +313,6 @@ static int adu_release_internal(struct adu_device *dev)
dbg(2," %s : enter", __FUNCTION__);
if (dev->udev == NULL) {
/* the device was unplugged before the file was released */
adu_delete(dev);
goto exit;
}
/* decrement our usage count for the device */
--dev->open_count;
dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
@ -332,7 +321,6 @@ static int adu_release_internal(struct adu_device *dev)
dev->open_count = 0;
}
exit:
dbg(2," %s : leave", __FUNCTION__);
return retval;
}
@ -367,8 +355,15 @@ static int adu_release(struct inode *inode, struct file *file)
goto exit;
}
if (dev->udev == NULL) {
/* the device was unplugged before the file was released */
up(&dev->sem);
adu_delete(dev);
dev = NULL;
} else {
/* do the work */
retval = adu_release_internal(dev);
}
exit:
if (dev)
@ -831,19 +826,17 @@ static void adu_disconnect(struct usb_interface *interface)
dbg(2," %s : enter", __FUNCTION__);
mutex_lock(&disconnect_mutex); /* not interruptible */
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
down(&dev->sem); /* not interruptible */
minor = dev->minor;
/* give back our minor */
usb_deregister_dev(interface, &adu_class);
dev->minor = 0;
down(&dev->sem); /* not interruptible */
/* if the device is not opened, then we clean up right now */
dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
if (!dev->open_count) {
@ -854,8 +847,6 @@ static void adu_disconnect(struct usb_interface *interface)
up(&dev->sem);
}
mutex_unlock(&disconnect_mutex);
dev_info(&interface->dev, "ADU device adutux%d now disconnected",
(minor - ADU_MINOR_BASE));

View file

@ -2034,12 +2034,12 @@ static void auerswald_disconnect (struct usb_interface *intf)
if (!cp)
return;
down (&cp->mutex);
info ("device /dev/%s now disconnecting", cp->name);
/* give back our USB minor number */
usb_deregister_dev(intf, &auerswald_class);
down (&cp->mutex);
info ("device /dev/%s now disconnecting", cp->name);
/* Stop the interrupt endpoint */
auerswald_int_release (cp);

View file

@ -26,8 +26,11 @@
#define RIM_VENDOR 0x0fca
#define BLACKBERRY 0x0001
#define BLACKBERRY_PEARL_DUAL 0x0004
#define BLACKBERRY_PEARL 0x0006
static int debug;
static int pearl_dual_mode = 1;
#ifdef dbg
#undef dbg
@ -38,6 +41,8 @@ static int debug;
static struct usb_device_id id_table [] = {
{ USB_DEVICE(RIM_VENDOR, BLACKBERRY) },
{ USB_DEVICE(RIM_VENDOR, BLACKBERRY_PEARL) },
{ USB_DEVICE(RIM_VENDOR, BLACKBERRY_PEARL_DUAL) },
{ }, /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);
@ -86,6 +91,30 @@ static int magic_charge(struct usb_device *udev)
return retval;
}
static int magic_dual_mode(struct usb_device *udev)
{
char *dummy_buffer = kzalloc(2, GFP_KERNEL);
int retval;
if (!dummy_buffer)
return -ENOMEM;
/* send magic command so that the Blackberry Pearl device exposes
* two interfaces: both the USB mass-storage one and one which can
* be used for database access. */
dbg(&udev->dev, "Sending magic pearl command\n");
retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
0xa9, 0xc0, 1, 1, dummy_buffer, 2, 100);
dbg(&udev->dev, "Magic pearl command returned %d\n", retval);
dbg(&udev->dev, "Calling set_configuration\n");
retval = usb_driver_set_configuration(udev, 1);
if (retval)
dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
return retval;
}
static int berry_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@ -105,6 +134,10 @@ static int berry_probe(struct usb_interface *intf,
/* turn the power on */
magic_charge(udev);
if ((le16_to_cpu(udev->descriptor.idProduct) == BLACKBERRY_PEARL) &&
(pearl_dual_mode))
magic_dual_mode(udev);
/* we don't really want to bind to the device, userspace programs can
* handle the syncing just fine, so get outta here. */
return -ENODEV;
@ -138,3 +171,5 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
module_param(pearl_dual_mode, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(pearl_dual_mode, "Change Blackberry Pearl to run in dual mode");

View file

@ -119,9 +119,6 @@ static struct usb_driver idmouse_driver = {
.id_table = idmouse_table,
};
/* prevent races between open() and disconnect() */
static DEFINE_MUTEX(disconnect_mutex);
static int idmouse_create_image(struct usb_idmouse *dev)
{
int bytes_read;
@ -211,21 +208,15 @@ static int idmouse_open(struct inode *inode, struct file *file)
struct usb_interface *interface;
int result;
/* prevent disconnects */
mutex_lock(&disconnect_mutex);
/* get the interface from minor number and driver information */
interface = usb_find_interface (&idmouse_driver, iminor (inode));
if (!interface) {
mutex_unlock(&disconnect_mutex);
if (!interface)
return -ENODEV;
}
/* get the device information block from the interface */
dev = usb_get_intfdata(interface);
if (!dev) {
mutex_unlock(&disconnect_mutex);
if (!dev)
return -ENODEV;
}
/* lock this device */
down(&dev->sem);
@ -255,9 +246,6 @@ static int idmouse_open(struct inode *inode, struct file *file)
/* unlock this device */
up(&dev->sem);
/* unlock the disconnect semaphore */
mutex_unlock(&disconnect_mutex);
return result;
}
@ -265,15 +253,10 @@ static int idmouse_release(struct inode *inode, struct file *file)
{
struct usb_idmouse *dev;
/* prevent a race condition with open() */
mutex_lock(&disconnect_mutex);
dev = file->private_data;
if (dev == NULL) {
mutex_unlock(&disconnect_mutex);
if (dev == NULL)
return -ENODEV;
}
/* lock our device */
down(&dev->sem);
@ -281,7 +264,6 @@ static int idmouse_release(struct inode *inode, struct file *file)
/* are we really open? */
if (dev->open <= 0) {
up(&dev->sem);
mutex_unlock(&disconnect_mutex);
return -ENODEV;
}
@ -291,12 +273,9 @@ static int idmouse_release(struct inode *inode, struct file *file)
/* the device was unplugged before the file was released */
up(&dev->sem);
idmouse_delete(dev);
mutex_unlock(&disconnect_mutex);
return 0;
}
} else {
up(&dev->sem);
mutex_unlock(&disconnect_mutex);
}
return 0;
}
@ -391,30 +370,27 @@ static void idmouse_disconnect(struct usb_interface *interface)
{
struct usb_idmouse *dev;
/* prevent races with open() */
mutex_lock(&disconnect_mutex);
/* get device structure */
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
/* lock it */
down(&dev->sem);
/* give back our minor */
usb_deregister_dev(interface, &idmouse_class);
/* lock it */
down(&dev->sem);
/* prevent device read, write and ioctl */
dev->present = 0;
/* if the device is opened, idmouse_release will clean this up */
if (!dev->open) {
up(&dev->sem);
idmouse_delete(dev);
} else {
/* unlock */
up(&dev->sem);
/* if the device is opened, idmouse_release will clean this up */
if (!dev->open)
idmouse_delete(dev);
mutex_unlock(&disconnect_mutex);
}
info("%s disconnected", DRIVER_DESC);
}

View file

@ -100,8 +100,6 @@ struct iowarrior {
/*--------------*/
/* globals */
/*--------------*/
/* prevent races between open() and disconnect() */
static DECLARE_MUTEX(disconnect_sem);
/*
* USB spec identifies 5 second timeouts.
@ -600,22 +598,18 @@ static int iowarrior_open(struct inode *inode, struct file *file)
subminor = iminor(inode);
/* prevent disconnects */
down(&disconnect_sem);
interface = usb_find_interface(&iowarrior_driver, subminor);
if (!interface) {
err("%s - error, can't find device for minor %d", __FUNCTION__,
subminor);
retval = -ENODEV;
goto out;
return -ENODEV;
}
dev = usb_get_intfdata(interface);
if (!dev) {
retval = -ENODEV;
goto out;
}
if (!dev)
return -ENODEV;
mutex_lock(&dev->mutex);
/* Only one process can open each device, no sharing. */
if (dev->opened) {
@ -636,7 +630,7 @@ static int iowarrior_open(struct inode *inode, struct file *file)
retval = 0;
out:
up(&disconnect_sem);
mutex_unlock(&dev->mutex);
return retval;
}
@ -868,19 +862,16 @@ static void iowarrior_disconnect(struct usb_interface *interface)
struct iowarrior *dev;
int minor;
/* prevent races with open() */
down(&disconnect_sem);
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
mutex_lock(&dev->mutex);
minor = dev->minor;
/* give back our minor */
usb_deregister_dev(interface, &iowarrior_class);
mutex_lock(&dev->mutex);
/* prevent device read, write and ioctl */
dev->present = 0;
@ -898,7 +889,6 @@ static void iowarrior_disconnect(struct usb_interface *interface)
/* no process is using the device, cleanup now */
iowarrior_delete(dev);
}
up(&disconnect_sem);
dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n",
minor - IOWARRIOR_MINOR_BASE);

View file

@ -176,9 +176,6 @@ struct ld_usb {
int interrupt_out_busy;
};
/* prevent races between open() and disconnect() */
static DEFINE_MUTEX(disconnect_mutex);
static struct usb_driver ld_usb_driver;
/**
@ -298,35 +295,28 @@ static int ld_usb_open(struct inode *inode, struct file *file)
{
struct ld_usb *dev;
int subminor;
int retval = 0;
int retval;
struct usb_interface *interface;
nonseekable_open(inode, file);
subminor = iminor(inode);
mutex_lock(&disconnect_mutex);
interface = usb_find_interface(&ld_usb_driver, subminor);
if (!interface) {
err("%s - error, can't find device for minor %d\n",
__FUNCTION__, subminor);
retval = -ENODEV;
goto unlock_disconnect_exit;
return -ENODEV;
}
dev = usb_get_intfdata(interface);
if (!dev) {
retval = -ENODEV;
goto unlock_disconnect_exit;
}
if (!dev)
return -ENODEV;
/* lock this device */
if (down_interruptible(&dev->sem)) {
retval = -ERESTARTSYS;
goto unlock_disconnect_exit;
}
if (down_interruptible(&dev->sem))
return -ERESTARTSYS;
/* allow opening only once */
if (dev->open_count) {
@ -366,9 +356,6 @@ static int ld_usb_open(struct inode *inode, struct file *file)
unlock_exit:
up(&dev->sem);
unlock_disconnect_exit:
mutex_unlock(&disconnect_mutex);
return retval;
}
@ -766,18 +753,16 @@ static void ld_usb_disconnect(struct usb_interface *intf)
struct ld_usb *dev;
int minor;
mutex_lock(&disconnect_mutex);
dev = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
down(&dev->sem);
minor = intf->minor;
/* give back our minor */
usb_deregister_dev(intf, &ld_usb_class);
down(&dev->sem);
/* if the device is not opened, then we clean up right now */
if (!dev->open_count) {
up(&dev->sem);
@ -787,8 +772,6 @@ static void ld_usb_disconnect(struct usb_interface *intf)
up(&dev->sem);
}
mutex_unlock(&disconnect_mutex);
dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
(minor - USB_LD_MINOR_BASE));
}

View file

@ -254,9 +254,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_devic
static void tower_disconnect (struct usb_interface *interface);
/* prevent races between open() and disconnect */
static DEFINE_MUTEX (disconnect_mutex);
/* file operations needed when we register this driver */
static const struct file_operations tower_fops = {
.owner = THIS_MODULE,
@ -344,28 +341,26 @@ static int tower_open (struct inode *inode, struct file *file)
nonseekable_open(inode, file);
subminor = iminor(inode);
mutex_lock (&disconnect_mutex);
interface = usb_find_interface (&tower_driver, subminor);
if (!interface) {
err ("%s - error, can't find device for minor %d",
__FUNCTION__, subminor);
retval = -ENODEV;
goto unlock_disconnect_exit;
goto exit;
}
dev = usb_get_intfdata(interface);
if (!dev) {
retval = -ENODEV;
goto unlock_disconnect_exit;
goto exit;
}
/* lock this device */
if (down_interruptible (&dev->sem)) {
retval = -ERESTARTSYS;
goto unlock_disconnect_exit;
goto exit;
}
/* allow opening only once */
@ -421,9 +416,7 @@ static int tower_open (struct inode *inode, struct file *file)
unlock_exit:
up (&dev->sem);
unlock_disconnect_exit:
mutex_unlock (&disconnect_mutex);
exit:
dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
return retval;
@ -993,19 +986,16 @@ static void tower_disconnect (struct usb_interface *interface)
dbg(2, "%s: enter", __FUNCTION__);
mutex_lock (&disconnect_mutex);
dev = usb_get_intfdata (interface);
usb_set_intfdata (interface, NULL);
down (&dev->sem);
minor = dev->minor;
/* give back our minor */
usb_deregister_dev (interface, &tower_class);
down (&dev->sem);
/* if the device is not opened, then we clean up right now */
if (!dev->open_count) {
up (&dev->sem);
@ -1015,8 +1005,6 @@ static void tower_disconnect (struct usb_interface *interface)
up (&dev->sem);
}
mutex_unlock (&disconnect_mutex);
info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
dbg(2, "%s: leave", __FUNCTION__);

View file

@ -72,8 +72,6 @@ MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES
static struct usb_driver sisusb_driver;
DEFINE_MUTEX(disconnect_mutex);
static void
sisusb_free_buffers(struct sisusb_usb_data *sisusb)
{
@ -2511,31 +2509,24 @@ sisusb_open(struct inode *inode, struct file *file)
struct usb_interface *interface;
int subminor = iminor(inode);
mutex_lock(&disconnect_mutex);
if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
subminor);
mutex_unlock(&disconnect_mutex);
return -ENODEV;
}
if (!(sisusb = usb_get_intfdata(interface))) {
mutex_unlock(&disconnect_mutex);
if (!(sisusb = usb_get_intfdata(interface)))
return -ENODEV;
}
mutex_lock(&sisusb->lock);
if (!sisusb->present || !sisusb->ready) {
mutex_unlock(&sisusb->lock);
mutex_unlock(&disconnect_mutex);
return -ENODEV;
}
if (sisusb->isopen) {
mutex_unlock(&sisusb->lock);
mutex_unlock(&disconnect_mutex);
return -EBUSY;
}
@ -2543,7 +2534,6 @@ 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);
mutex_unlock(&disconnect_mutex);
printk(KERN_ERR
"sisusbvga[%d]: Failed to initialize "
"device\n",
@ -2552,7 +2542,6 @@ sisusb_open(struct inode *inode, struct file *file)
}
} else {
mutex_unlock(&sisusb->lock);
mutex_unlock(&disconnect_mutex);
printk(KERN_ERR
"sisusbvga[%d]: Device not attached to "
"USB 2.0 hub\n",
@ -2570,8 +2559,6 @@ sisusb_open(struct inode *inode, struct file *file)
mutex_unlock(&sisusb->lock);
mutex_unlock(&disconnect_mutex);
return 0;
}
@ -2601,12 +2588,8 @@ sisusb_release(struct inode *inode, struct file *file)
struct sisusb_usb_data *sisusb;
int myminor;
mutex_lock(&disconnect_mutex);
if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
mutex_unlock(&disconnect_mutex);
if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
return -ENODEV;
}
mutex_lock(&sisusb->lock);
@ -2626,8 +2609,6 @@ sisusb_release(struct inode *inode, struct file *file)
/* decrement the usage count on our device */
kref_put(&sisusb->kref, sisusb_delete);
mutex_unlock(&disconnect_mutex);
return 0;
}
@ -3383,12 +3364,9 @@ static void sisusb_disconnect(struct usb_interface *intf)
sisusb_console_exit(sisusb);
#endif
/* The above code doesn't need the disconnect
* semaphore to be down; its meaning is to
* protect all other routines from the disconnect
* case, not the other way round.
*/
mutex_lock(&disconnect_mutex);
minor = sisusb->minor;
usb_deregister_dev(intf, &usb_sisusb_class);
mutex_lock(&sisusb->lock);
@ -3396,12 +3374,8 @@ static void sisusb_disconnect(struct usb_interface *intf)
if (!sisusb_wait_all_out_complete(sisusb))
sisusb_kill_all_busy(sisusb);
minor = sisusb->minor;
usb_set_intfdata(intf, NULL);
usb_deregister_dev(intf, &usb_sisusb_class);
#ifdef SISUSB_OLD_CONFIG_COMPAT
if (sisusb->ioctl32registered) {
int ret;
@ -3426,8 +3400,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
/* decrement our usage count */
kref_put(&sisusb->kref, sisusb_delete);
mutex_unlock(&disconnect_mutex);
printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
}

View file

@ -214,18 +214,13 @@ sisusbcon_init(struct vc_data *c, int init)
* are set up/restored.
*/
mutex_lock(&disconnect_mutex);
if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
mutex_unlock(&disconnect_mutex);
if (!(sisusb = sisusb_get_sisusb(c->vc_num)))
return;
}
mutex_lock(&sisusb->lock);
if (!sisusb_sisusb_valid(sisusb)) {
mutex_unlock(&sisusb->lock);
mutex_unlock(&disconnect_mutex);
return;
}
@ -264,8 +259,6 @@ sisusbcon_init(struct vc_data *c, int init)
mutex_unlock(&sisusb->lock);
mutex_unlock(&disconnect_mutex);
if (init) {
c->vc_cols = cols;
c->vc_rows = rows;
@ -284,12 +277,8 @@ sisusbcon_deinit(struct vc_data *c)
* and others, ie not under our control.
*/
mutex_lock(&disconnect_mutex);
if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
mutex_unlock(&disconnect_mutex);
if (!(sisusb = sisusb_get_sisusb(c->vc_num)))
return;
}
mutex_lock(&sisusb->lock);
@ -314,8 +303,6 @@ sisusbcon_deinit(struct vc_data *c)
/* decrement the usage count on our sisusb */
kref_put(&sisusb->kref, sisusb_delete);
mutex_unlock(&disconnect_mutex);
}
/* interface routine */
@ -1490,14 +1477,11 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
{
int i, ret, minor = sisusb->minor;
mutex_lock(&disconnect_mutex);
mutex_lock(&sisusb->lock);
/* Erm.. that should not happen */
if (sisusb->haveconsole || !sisusb->SiS_Pr) {
mutex_unlock(&sisusb->lock);
mutex_unlock(&disconnect_mutex);
return 1;
}
@ -1508,14 +1492,12 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
first > MAX_NR_CONSOLES ||
last > MAX_NR_CONSOLES) {
mutex_unlock(&sisusb->lock);
mutex_unlock(&disconnect_mutex);
return 1;
}
/* If gfxcore not initialized or no consoles given, quit graciously */
if (!sisusb->gfxinit || first < 1 || last < 1) {
mutex_unlock(&sisusb->lock);
mutex_unlock(&disconnect_mutex);
return 0;
}
@ -1526,7 +1508,6 @@ 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);
mutex_unlock(&disconnect_mutex);
printk(KERN_ERR
"sisusbvga[%d]: Failed to set up text mode\n",
minor);
@ -1550,7 +1531,6 @@ 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);
mutex_unlock(&disconnect_mutex);
printk(KERN_ERR
"sisusbvga[%d]: Failed to allocate screen buffer\n",
minor);
@ -1558,7 +1538,6 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
}
mutex_unlock(&sisusb->lock);
mutex_unlock(&disconnect_mutex);
/* Now grab the desired console(s) */
ret = take_over_console(&sisusb_con, first - 1, last - 1, 0);

View file

@ -808,8 +808,6 @@ static const struct SiS_VCLKData SiSUSB_VCLKData[] =
{ 0x2b,0xc2, 35} /* 0x71 768@576@60 */
};
extern struct mutex disconnect_mutex;
int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);

View file

@ -45,13 +45,13 @@ struct usb_lcd {
struct kref kref;
struct semaphore limit_sem; /* to stop writes at full throttle from
* using up all RAM */
struct usb_anchor submitted; /* URBs to wait for before suspend */
};
#define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
#define USB_LCD_CONCURRENT_WRITES 5
static struct usb_driver lcd_driver;
static DEFINE_MUTEX(usb_lcd_open_mutex);
static void lcd_delete(struct kref *kref)
@ -68,35 +68,35 @@ static int lcd_open(struct inode *inode, struct file *file)
{
struct usb_lcd *dev;
struct usb_interface *interface;
int subminor;
int retval = 0;
int subminor, r;
subminor = iminor(inode);
mutex_lock(&usb_lcd_open_mutex);
interface = usb_find_interface(&lcd_driver, subminor);
if (!interface) {
err ("USBLCD: %s - error, can't find device for minor %d",
__FUNCTION__, subminor);
retval = -ENODEV;
goto exit;
return -ENODEV;
}
dev = usb_get_intfdata(interface);
if (!dev) {
retval = -ENODEV;
goto exit;
}
if (!dev)
return -ENODEV;
/* increment our usage count for the device */
kref_get(&dev->kref);
/* grab a power reference */
r = usb_autopm_get_interface(interface);
if (r < 0) {
kref_put(&dev->kref, lcd_delete);
return r;
}
/* save our object in the file's private structure */
file->private_data = dev;
exit:
mutex_unlock(&usb_lcd_open_mutex);
return retval;
return 0;
}
static int lcd_release(struct inode *inode, struct file *file)
@ -108,6 +108,7 @@ static int lcd_release(struct inode *inode, struct file *file)
return -ENODEV;
/* decrement the count on our device */
usb_autopm_put_interface(dev->interface);
kref_put(&dev->kref, lcd_delete);
return 0;
}
@ -234,11 +235,13 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
buf, count, lcd_write_bulk_callback, dev);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(urb, &dev->submitted);
/* send the data out the bulk port */
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
err("USBLCD: %s - failed submitting write urb, error %d", __FUNCTION__, retval);
goto error;
goto error_unanchor;
}
/* release our reference to this urb, the USB core will eventually free it entirely */
@ -246,7 +249,8 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
exit:
return count;
error_unanchor:
usb_unanchor_urb(urb);
error:
usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
usb_free_urb(urb);
@ -291,6 +295,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
}
kref_init(&dev->kref);
sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES);
init_usb_anchor(&dev->submitted);
dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface;
@ -358,22 +363,41 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
return retval;
}
static void lcd_draw_down(struct usb_lcd *dev)
{
int time;
time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000);
if (!time)
usb_kill_anchored_urbs(&dev->submitted);
}
static int lcd_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usb_lcd *dev = usb_get_intfdata(intf);
if (!dev)
return 0;
lcd_draw_down(dev);
return 0;
}
static int lcd_resume (struct usb_interface *intf)
{
return 0;
}
static void lcd_disconnect(struct usb_interface *interface)
{
struct usb_lcd *dev;
int minor = interface->minor;
/* prevent skel_open() from racing skel_disconnect() */
mutex_lock(&usb_lcd_open_mutex);
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
/* give back our minor */
usb_deregister_dev(interface, &lcd_class);
mutex_unlock(&usb_lcd_open_mutex);
/* decrement our usage count */
kref_put(&dev->kref, lcd_delete);
@ -384,7 +408,10 @@ static struct usb_driver lcd_driver = {
.name = "usblcd",
.probe = lcd_probe,
.disconnect = lcd_disconnect,
.suspend = lcd_suspend,
.resume = lcd_resume,
.id_table = id_table,
.supports_autosuspend = 1,
};
static int __init usb_lcd_init(void)

View file

@ -4,7 +4,7 @@
* This is a binary format reader.
*
* Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it)
* Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com)
* Copyright (C) 2006,2007 Pete Zaitcev (zaitcev@redhat.com)
*/
#include <linux/kernel.h>
@ -172,6 +172,7 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
#define MON_RING_EMPTY(rp) ((rp)->b_cnt == 0)
static struct class *mon_bin_class;
static dev_t mon_bin_dev0;
static struct cdev mon_bin_cdev;
@ -1144,10 +1145,38 @@ static void mon_free_buff(struct mon_pgmap *map, int npages)
free_page((unsigned long) map[n].ptr);
}
int mon_bin_add(struct mon_bus *mbus, const struct usb_bus *ubus)
{
struct device *dev;
unsigned minor = ubus? ubus->busnum: 0;
if (minor >= MON_BIN_MAX_MINOR)
return 0;
dev = device_create(mon_bin_class, ubus? ubus->controller: NULL,
MKDEV(MAJOR(mon_bin_dev0), minor), "usbmon%d", minor);
if (IS_ERR(dev))
return 0;
mbus->classdev = dev;
return 1;
}
void mon_bin_del(struct mon_bus *mbus)
{
device_destroy(mon_bin_class, mbus->classdev->devt);
}
int __init mon_bin_init(void)
{
int rc;
mon_bin_class = class_create(THIS_MODULE, "usbmon");
if (IS_ERR(mon_bin_class)) {
rc = PTR_ERR(mon_bin_class);
goto err_class;
}
rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon");
if (rc < 0)
goto err_dev;
@ -1164,6 +1193,8 @@ int __init mon_bin_init(void)
err_add:
unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
err_dev:
class_destroy(mon_bin_class);
err_class:
return rc;
}
@ -1171,4 +1202,5 @@ void mon_bin_exit(void)
{
cdev_del(&mon_bin_cdev);
unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
class_destroy(mon_bin_class);
}

View file

@ -220,6 +220,8 @@ static void mon_bus_remove(struct usb_bus *ubus)
list_del(&mbus->bus_link);
if (mbus->text_inited)
mon_text_del(mbus);
if (mbus->bin_inited)
mon_bin_del(mbus);
mon_dissolve(mbus, ubus);
kref_put(&mbus->ref, mon_bus_drop);
@ -301,8 +303,8 @@ static void mon_bus_init(struct usb_bus *ubus)
mbus->u_bus = ubus;
ubus->mon_bus = mbus;
mbus->text_inited = mon_text_add(mbus, ubus->busnum);
// mon_bin_add(...)
mbus->text_inited = mon_text_add(mbus, ubus);
mbus->bin_inited = mon_bin_add(mbus, ubus);
mutex_lock(&mon_lock);
list_add_tail(&mbus->bus_link, &mon_buses);
@ -321,8 +323,8 @@ static void mon_bus0_init(void)
spin_lock_init(&mbus->lock);
INIT_LIST_HEAD(&mbus->r_list);
mbus->text_inited = mon_text_add(mbus, 0);
// mbus->bin_inited = mon_bin_add(mbus, 0);
mbus->text_inited = mon_text_add(mbus, NULL);
mbus->bin_inited = mon_bin_add(mbus, NULL);
}
/*
@ -403,6 +405,8 @@ static void __exit mon_exit(void)
if (mbus->text_inited)
mon_text_del(mbus);
if (mbus->bin_inited)
mon_bin_del(mbus);
/*
* This never happens, because the open/close paths in
@ -423,6 +427,8 @@ static void __exit mon_exit(void)
mbus = &mon_bus0;
if (mbus->text_inited)
mon_text_del(mbus);
if (mbus->bin_inited)
mon_bin_del(mbus);
mutex_unlock(&mon_lock);

View file

@ -655,20 +655,24 @@ static const struct file_operations mon_fops_text_u = {
.release = mon_text_release,
};
int mon_text_add(struct mon_bus *mbus, int busnum)
int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
{
struct dentry *d;
enum { NAMESZ = 10 };
char name[NAMESZ];
int busnum = ubus? ubus->busnum: 0;
int rc;
if (ubus != NULL) {
rc = snprintf(name, NAMESZ, "%dt", busnum);
if (rc <= 0 || rc >= NAMESZ)
goto err_print_t;
d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_t);
d = debugfs_create_file(name, 0600, mon_dir, mbus,
&mon_fops_text_t);
if (d == NULL)
goto err_create_t;
mbus->dent_t = d;
}
rc = snprintf(name, NAMESZ, "%du", busnum);
if (rc <= 0 || rc >= NAMESZ)
@ -694,8 +698,10 @@ int mon_text_add(struct mon_bus *mbus, int busnum)
mbus->dent_u = NULL;
err_create_u:
err_print_u:
if (ubus != NULL) {
debugfs_remove(mbus->dent_t);
mbus->dent_t = NULL;
}
err_create_t:
err_print_t:
return 0;
@ -704,6 +710,7 @@ int mon_text_add(struct mon_bus *mbus, int busnum)
void mon_text_del(struct mon_bus *mbus)
{
debugfs_remove(mbus->dent_u);
if (mbus->dent_t != NULL)
debugfs_remove(mbus->dent_t);
debugfs_remove(mbus->dent_s);
}

View file

@ -20,9 +20,11 @@ struct mon_bus {
struct usb_bus *u_bus;
int text_inited;
int bin_inited;
struct dentry *dent_s; /* Debugging file */
struct dentry *dent_t; /* Text interface file */
struct dentry *dent_u; /* Second text interface file */
struct device *classdev; /* Device in usbmon class */
/* Ref */
int nreaders; /* Under mon_lock AND mbus->lock */
@ -52,9 +54,10 @@ void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
struct mon_bus *mon_bus_lookup(unsigned int num);
int /*bool*/ mon_text_add(struct mon_bus *mbus, int busnum);
int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
void mon_text_del(struct mon_bus *mbus);
// void mon_bin_add(struct mon_bus *);
int /*bool*/ mon_bin_add(struct mon_bus *mbus, const struct usb_bus *ubus);
void mon_bin_del(struct mon_bus *mbus);
int __init mon_text_init(void);
void mon_text_exit(void);

View file

@ -464,6 +464,16 @@ config USB_SERIAL_PL2303
To compile this driver as a module, choose M here: the
module will be called pl2303.
config USB_SERIAL_OTI6858
tristate "USB Ours Technology Inc. OTi-6858 USB To RS232 Bridge Controller (EXPERIMENTAL)"
depends on USB_SERIAL
help
Say Y here if you want to use the OTi-6858 single port USB to serial
converter device.
To compile this driver as a module, choose M here: the
module will be called oti6858.
config USB_SERIAL_HP4X
tristate "USB HP4x Calculators support"
depends on USB_SERIAL

View file

@ -40,6 +40,7 @@ obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_OPTION) += option.o
obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o
obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o

View file

@ -411,12 +411,13 @@ static int aircable_write(struct usb_serial_port *port,
static void aircable_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
int status = urb->status;
int result;
dbg("%s - urb->status: %d", __FUNCTION__ , urb->status);
dbg("%s - urb status: %d", __FUNCTION__ , status);
/* This has been taken from cypress_m8.c cypress_write_int_callback */
switch (urb->status) {
switch (status) {
case 0:
/* success */
break;
@ -425,14 +426,14 @@ static void aircable_write_bulk_callback(struct urb *urb)
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
__FUNCTION__, urb->status);
__FUNCTION__, status);
port->write_urb_busy = 0;
return;
default:
/* error in the urb, so we have to resubmit it */
dbg("%s - Overflow in write", __FUNCTION__);
dbg("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
__FUNCTION__, status);
port->write_urb->transfer_buffer_length = 1;
port->write_urb->dev = port->serial->dev;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
@ -457,16 +458,17 @@ static void aircable_read_bulk_callback(struct urb *urb)
unsigned long no_packages, remaining, package_length, i;
int result, shift = 0;
unsigned char *temp;
int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
if (urb->status) {
dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
if (status) {
dbg("%s - urb status = %d", __FUNCTION__, status);
if (!port->open_count) {
dbg("%s - port is closed, exiting.", __FUNCTION__);
return;
}
if (urb->status == -EPROTO) {
if (status == -EPROTO) {
dbg("%s - caught -EPROTO, resubmitting the urb",
__FUNCTION__);
usb_fill_bulk_urb(port->read_urb, port->serial->dev,

View file

@ -82,12 +82,13 @@ static void airprime_read_bulk_callback(struct urb *urb)
unsigned char *data = urb->transfer_buffer;
struct tty_struct *tty;
int result;
int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
if (urb->status) {
if (status) {
dbg("%s - nonzero read bulk status received: %d",
__FUNCTION__, urb->status);
__FUNCTION__, status);
return;
}
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
@ -109,6 +110,7 @@ static void airprime_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct airprime_private *priv = usb_get_serial_port_data(port);
int status = urb->status;
unsigned long flags;
dbg("%s - port %d", __FUNCTION__, port->number);
@ -116,9 +118,9 @@ static void airprime_write_bulk_callback(struct urb *urb)
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree (urb->transfer_buffer);
if (urb->status)
if (status)
dbg("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
__FUNCTION__, status);
spin_lock_irqsave(&priv->lock, flags);
--priv->outstanding_urbs;
spin_unlock_irqrestore(&priv->lock, flags);

View file

@ -172,7 +172,7 @@ static void ark3116_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;
}
@ -188,16 +188,6 @@ static void ark3116_set_termios(struct usb_serial_port *port,
cflag = port->tty->termios->c_cflag;
/* check that they really want us to change something: */
if (old_termios) {
if ((cflag == old_termios->c_cflag) &&
(RELEVANT_IFLAG(port->tty->termios->c_iflag) ==
RELEVANT_IFLAG(old_termios->c_iflag))) {
dbg("%s - nothing to change...", __FUNCTION__);
return;
}
}
buf = kmalloc(1, GFP_KERNEL);
if (!buf) {
dbg("error kmalloc");
@ -220,7 +210,7 @@ static void ark3116_set_termios(struct usb_serial_port *port,
dbg("setting CS7");
break;
default:
err("CSIZE was set but not CS5-CS8, using CS8!");
dbg("CSIZE was set but not CS5-CS8, using CS8!");
/* fall through */
case CS8:
config |= 0x03;
@ -251,38 +241,33 @@ static void ark3116_set_termios(struct usb_serial_port *port,
}
/* set baudrate */
baud = 0;
switch (cflag & CBAUD) {
case B0:
err("can't set 0 baud, using 9600 instead");
break;
case B75: baud = 75; break;
case B150: baud = 150; break;
case B300: baud = 300; break;
case B600: baud = 600; break;
case B1200: baud = 1200; break;
case B1800: baud = 1800; break;
case B2400: baud = 2400; break;
case B4800: baud = 4800; break;
case B9600: baud = 9600; break;
case B19200: baud = 19200; break;
case B38400: baud = 38400; break;
case B57600: baud = 57600; break;
case B115200: baud = 115200; break;
case B230400: baud = 230400; break;
case B460800: baud = 460800; break;
default:
dbg("does not support the baudrate requested (fix it)");
break;
}
baud = tty_get_baud_rate(port->tty);
switch (baud) {
case 75:
case 150:
case 300:
case 600:
case 1200:
case 1800:
case 2400:
case 4800:
case 9600:
case 19200:
case 38400:
case 57600:
case 115200:
case 230400:
case 460800:
break;
/* set 9600 as default (if given baudrate is invalid for example) */
if (baud == 0)
default:
baud = 9600;
}
/*
* found by try'n'error, be careful, maybe there are other options
* for multiplicator etc!
* for multiplicator etc! (3.5 for example)
*/
if (baud == 460800)
/* strange, for 460800 the formula is wrong

View file

@ -255,9 +255,10 @@ static void belkin_sa_read_int_callback (struct urb *urb)
struct belkin_sa_private *priv;
unsigned char *data = urb->transfer_buffer;
int retval;
int status = urb->status;
unsigned long flags;
switch (urb->status) {
switch (status) {
case 0:
/* success */
break;
@ -265,10 +266,12 @@ static void belkin_sa_read_int_callback (struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
dbg("%s - urb shutting down with status: %d",
__FUNCTION__, status);
return;
default:
dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
dbg("%s - nonzero urb status received: %d",
__FUNCTION__, status);
goto exit;
}
@ -346,6 +349,7 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
unsigned long flags;
unsigned long control_state;
int bad_flow_control;
speed_t baud;
if ((!port->tty) || (!port->tty->termios)) {
dbg ("%s - no tty or termios structure", __FUNCTION__);
@ -361,16 +365,8 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
bad_flow_control = priv->bad_flow_control;
spin_unlock_irqrestore(&priv->lock, flags);
/* check that they really want us to change something */
if (old_termios) {
if ((cflag == old_termios->c_cflag) &&
(RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
dbg("%s - nothing to change...", __FUNCTION__);
return;
}
old_iflag = old_termios->c_iflag;
old_cflag = old_termios->c_cflag;
}
/* Set the baud rate */
if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
@ -384,23 +380,17 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0)
err("Set RTS error");
}
switch(cflag & CBAUD) {
case B0: /* handled below */ break;
case B300: urb_value = BELKIN_SA_BAUD(300); break;
case B600: urb_value = BELKIN_SA_BAUD(600); break;
case B1200: urb_value = BELKIN_SA_BAUD(1200); break;
case B2400: urb_value = BELKIN_SA_BAUD(2400); break;
case B4800: urb_value = BELKIN_SA_BAUD(4800); break;
case B9600: urb_value = BELKIN_SA_BAUD(9600); break;
case B19200: urb_value = BELKIN_SA_BAUD(19200); break;
case B38400: urb_value = BELKIN_SA_BAUD(38400); break;
case B57600: urb_value = BELKIN_SA_BAUD(57600); break;
case B115200: urb_value = BELKIN_SA_BAUD(115200); break;
case B230400: urb_value = BELKIN_SA_BAUD(230400); break;
default: err("BELKIN USB Serial Adapter: unsupported baudrate request, using default of 9600");
urb_value = BELKIN_SA_BAUD(9600); break;
}
baud = tty_get_baud_rate(port->tty);
urb_value = BELKIN_SA_BAUD(baud);
/* Clip to maximum speed */
if (urb_value == 0)
urb_value = 1;
/* Turn it back into a resulting real baud rate */
baud = BELKIN_SA_BAUD(urb_value);
/* FIXME: Once the tty updates are done then push this back to the tty */
if ((cflag & CBAUD) != B0 ) {
if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0)
err("Set baudrate error");
@ -408,7 +398,6 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
/* Disable flow control */
if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, BELKIN_SA_FLOW_NONE) < 0)
err("Disable flowcontrol error");
/* Drop RTS and DTR */
control_state &= ~(TIOCM_DTR | TIOCM_RTS);
if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0)
@ -416,7 +405,6 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0)
err("RTS LOW error");
}
}
/* set the parity */
if( (cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD)) ) {
@ -435,7 +423,7 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
case CS6: urb_value = BELKIN_SA_DATA_BITS(6); break;
case CS7: urb_value = BELKIN_SA_DATA_BITS(7); break;
case CS8: urb_value = BELKIN_SA_DATA_BITS(8); break;
default: err("CSIZE was not CS5-CS8, using default of 8");
default: dbg("CSIZE was not CS5-CS8, using default of 8");
urb_value = BELKIN_SA_DATA_BITS(8);
break;
}

View file

@ -305,12 +305,13 @@ static void cyberjack_read_int_callback( struct urb *urb )
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct cyberjack_private *priv = usb_get_serial_port_data(port);
unsigned char *data = urb->transfer_buffer;
int status = urb->status;
int result;
dbg("%s - port %d", __FUNCTION__, port->number);
/* the urb might have been killed. */
if (urb->status)
if (status)
return;
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
@ -365,12 +366,14 @@ static void cyberjack_read_bulk_callback (struct urb *urb)
unsigned char *data = urb->transfer_buffer;
short todo;
int result;
int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
if (urb->status) {
dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
if (status) {
dbg("%s - nonzero read bulk status received: %d",
__FUNCTION__, status);
return;
}
@ -411,12 +414,14 @@ static void cyberjack_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct cyberjack_private *priv = usb_get_serial_port_data(port);
int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
if (status) {
dbg("%s - nonzero write bulk status received: %d",
__FUNCTION__, status);
return;
}

View file

@ -1275,10 +1275,11 @@ static void cypress_read_int_callback(struct urb *urb)
int bytes = 0;
int result;
int i = 0;
int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
switch (urb->status) {
switch (status) {
case 0: /* success */
break;
case -ECONNRESET:
@ -1292,7 +1293,7 @@ static void cypress_read_int_callback(struct urb *urb)
default:
/* something ugly is going on... */
dev_err(&urb->dev->dev,"%s - unexpected nonzero read status received: %d\n",
__FUNCTION__,urb->status);
__FUNCTION__, status);
cypress_set_dead(port);
return;
}
@ -1419,10 +1420,11 @@ static void cypress_write_int_callback(struct urb *urb)
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct cypress_private *priv = usb_get_serial_port_data(port);
int result;
int status = urb->status;
dbg("%s - port %d", __FUNCTION__, port->number);
switch (urb->status) {
switch (status) {
case 0:
/* success */
break;
@ -1430,7 +1432,8 @@ static void cypress_write_int_callback(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
dbg("%s - urb shutting down with status: %d",
__FUNCTION__, status);
priv->write_urb_in_use = 0;
return;
case -EPIPE: /* no break needed; clear halt and resubmit */
@ -1438,7 +1441,8 @@ static void cypress_write_int_callback(struct urb *urb)
break;
usb_clear_halt(port->serial->dev, 0x02);
/* error in the urb, so we have to resubmit it */
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
dbg("%s - nonzero write bulk status received: %d",
__FUNCTION__, status);
port->interrupt_out_urb->transfer_buffer_length = 1;
port->interrupt_out_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
@ -1450,7 +1454,7 @@ static void cypress_write_int_callback(struct urb *urb)
break;
default:
dev_err(&urb->dev->dev,"%s - unexpected nonzero write status received: %d\n",
__FUNCTION__,urb->status);
__FUNCTION__, status);
cypress_set_dead(port);
break;
}

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