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: (70 commits)
  USB: remove duplicate device id from zc0301
  USB: remove duplicate device id from usb_storage
  USB: remove duplicate device id from keyspan
  USB: remove duplicate device id from ftdi_sio
  USB: remove duplicate device id from visor
  USB: a bit more coding style cleanup
  usbcore: trivial whitespace fixes
  usb-storage: use first bulk endpoints, not last
  EHCI: fix interrupt-driven remote wakeup
  USB: switch ehci-hcd to new polling scheme
  USB: autosuspend for usb printer driver
  USB Input: Added kernel module to support all GTCO CalComp USB InterWrite School products
  USB: Sierra Wireless auto set D0
  USB: usb ethernet gadget recognizes HUSB2DEV
  USB: list atmel husb2_udc gadget controller
  USB: gadgetfs AIO tweaks
  USB: gadgetfs behaves better on userspace init bug
  USB: gadgetfs race fix
  USB: gadgetfs simplifications
  USB: gadgetfs cleanups
  ...
This commit is contained in:
Linus Torvalds 2007-02-07 19:23:21 -08:00
commit c96e2c9207
139 changed files with 5825 additions and 1568 deletions

View File

@ -213,15 +213,16 @@ C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
Interface descriptor info (can be multiple per Config):
I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
| | | | | | | |__Driver name
| | | | | | | or "(none)"
| | | | | | |__InterfaceProtocol
| | | | | |__InterfaceSubClass
| | | | |__InterfaceClass
| | | |__NumberOfEndpoints
| | |__AlternateSettingNumber
| |__InterfaceNumber
I:* If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
| | | | | | | | |__Driver name
| | | | | | | | or "(none)"
| | | | | | | |__InterfaceProtocol
| | | | | | |__InterfaceSubClass
| | | | | |__InterfaceClass
| | | | |__NumberOfEndpoints
| | | |__AlternateSettingNumber
| | |__InterfaceNumber
| |__ "*" indicates the active altsetting (others are " ")
|__Interface info tag
A given interface may have one or more "alternate" settings.
@ -277,7 +278,7 @@ of the USB devices on a system's root hub. (See more below
on how to do this.)
The Interface lines can be used to determine what driver is
being used for each device.
being used for each device, and which altsetting it activated.
The Configuration lines could be used to list maximum power
(in milliamps) that a system's USB devices are using.

View File

@ -77,7 +77,7 @@ that the file size is not excessive for your favourite editor.
The '1t' type data consists of a stream of events, such as URB submission,
URB callback, submission error. Every event is a text line, which consists
of whitespace separated words. The number of position of words may depend
of whitespace separated words. The number or position of words may depend
on the event type, but there is a set of words, common for all types.
Here is the list of words, from left to right:
@ -170,4 +170,152 @@ dd65f0e8 4128379808 C Bo:005:02 0 31 >
* Raw binary format and API
TBD
The overall architecture of the API is about the same as the one above,
only the events are delivered in binary format. Each event is sent in
the following structure (its name is made up, so that we can refer to it):
struct usbmon_packet {
u64 id; /* 0: URB ID - from submission to callback */
unsigned char type; /* 8: Same as text; extensible. */
unsigned char xfer_type; /* ISO (0), Intr, Control, Bulk (3) */
unsigned char epnum; /* Endpoint number and transfer direction */
unsigned char devnum; /* Device address */
u16 busnum; /* 12: Bus number */
char flag_setup; /* 14: Same as text */
char flag_data; /* 15: Same as text; Binary zero is OK. */
s64 ts_sec; /* 16: gettimeofday */
s32 ts_usec; /* 24: gettimeofday */
int status; /* 28: */
unsigned int length; /* 32: Length of data (submitted or actual) */
unsigned int len_cap; /* 36: Delivered length */
unsigned char setup[8]; /* 40: Only for Control 'S' */
}; /* 48 bytes total */
These events can be received from a character device by reading with read(2),
with an ioctl(2), or by accessing the buffer with mmap.
The character device is usually called /dev/usbmonN, where N is the USB bus
number. Number zero (/dev/usbmon0) is special and means "all buses".
However, this feature is not implemented yet. Note that specific naming
policy is set by your Linux distribution.
If you create /dev/usbmon0 by hand, make sure that it is owned by root
and has mode 0600. Otherwise, unpriviledged users will be able to snoop
keyboard traffic.
The following ioctl calls are available, with MON_IOC_MAGIC 0x92:
MON_IOCQ_URB_LEN, defined as _IO(MON_IOC_MAGIC, 1)
This call returns the length of data in the next event. Note that majority of
events contain no data, so if this call returns zero, it does not mean that
no events are available.
MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
The argument is a pointer to the following structure:
struct mon_bin_stats {
u32 queued;
u32 dropped;
};
The member "queued" refers to the number of events currently queued in the
buffer (and not to the number of events processed since the last reset).
The member "dropped" is the number of events lost since the last call
to MON_IOCG_STATS.
MON_IOCT_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 4)
This call sets the buffer size. The argument is the size in bytes.
The size may be rounded down to the next chunk (or page). If the requested
size is out of [unspecified] bounds for this kernel, the call fails with
-EINVAL.
MON_IOCQ_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 5)
This call returns the current size of the buffer in bytes.
MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg)
This call waits for events to arrive if none were in the kernel buffer,
then returns the first event. Its argument is a pointer to the following
structure:
struct mon_get_arg {
struct usbmon_packet *hdr;
void *data;
size_t alloc; /* Length of data (can be zero) */
};
Before the call, hdr, data, and alloc should be filled. Upon return, the area
pointed by hdr contains the next event structure, and the data buffer contains
the data, if any. The event is removed from the kernel buffer.
MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg)
This ioctl is primarily used when the application accesses the buffer
with mmap(2). Its argument is a pointer to the following structure:
struct mon_mfetch_arg {
uint32_t *offvec; /* Vector of events fetched */
uint32_t nfetch; /* Number of events to fetch (out: fetched) */
uint32_t nflush; /* Number of events to flush */
};
The ioctl operates in 3 stages.
First, it removes and discards up to nflush events from the kernel buffer.
The actual number of events discarded is returned in nflush.
Second, it waits for an event to be present in the buffer, unless the pseudo-
device is open with O_NONBLOCK.
Third, it extracts up to nfetch offsets into the mmap buffer, and stores
them into the offvec. The actual number of event offsets is stored into
the nfetch.
MON_IOCH_MFLUSH, defined as _IO(MON_IOC_MAGIC, 8)
This call removes a number of events from the kernel buffer. Its argument
is the number of events to remove. If the buffer contains fewer events
than requested, all events present are removed, and no error is reported.
This works when no events are available too.
FIONBIO
The ioctl FIONBIO may be implemented in the future, if there's a need.
In addition to ioctl(2) and read(2), the special file of binary API can
be polled with select(2) and poll(2). But lseek(2) does not work.
* Memory-mapped access of the kernel buffer for the binary API
The basic idea is simple:
To prepare, map the buffer by getting the current size, then using mmap(2).
Then, execute a loop similar to the one written in pseudo-code below:
struct mon_mfetch_arg fetch;
struct usbmon_packet *hdr;
int nflush = 0;
for (;;) {
fetch.offvec = vec; // Has N 32-bit words
fetch.nfetch = N; // Or less than N
fetch.nflush = nflush;
ioctl(fd, MON_IOCX_MFETCH, &fetch); // Process errors, too
nflush = fetch.nfetch; // This many packets to flush when done
for (i = 0; i < nflush; i++) {
hdr = (struct ubsmon_packet *) &mmap_area[vec[i]];
if (hdr->type == '@') // Filler packet
continue;
caddr_t data = &mmap_area[vec[i]] + 64;
process_packet(hdr, data);
}
}
Thus, the main idea is to execute only one ioctl per N events.
Although the buffer is circular, the returned headers and data do not cross
the end of the buffer, so the above pseudo-code does not need any gathering.

View File

@ -529,6 +529,11 @@ config PPC_PS3
bool "Sony PS3 (incomplete)"
depends on PPC_MULTIPLATFORM && PPC64
select PPC_CELL
select USB_ARCH_HAS_OHCI
select USB_OHCI_LITTLE_ENDIAN
select USB_OHCI_BIG_ENDIAN_MMIO
select USB_ARCH_HAS_EHCI
select USB_EHCI_BIG_ENDIAN_MMIO
help
This option enables support for the Sony PS3 game console
and other platforms using the PS3 hypervisor.

View File

@ -27,7 +27,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb.h>
#include <linux/usb/otg.h>

View File

@ -75,7 +75,6 @@ static const struct usb_device_id zc0301_id_table[] = { \
{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
{ ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */ \
{ ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */ \
{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \
{ ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */ \
{ ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \

View File

@ -36,7 +36,7 @@
#include <linux/stat.h>
#include <linux/timer.h>
#include <linux/types.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/workqueue.h>
#include "usbatm.h"

View File

@ -398,6 +398,9 @@ static int usblp_open(struct inode *inode, struct file *file)
retval = 0;
#endif
retval = usb_autopm_get_interface(intf);
if (retval < 0)
goto out;
usblp->used = 1;
file->private_data = usblp;
@ -442,6 +445,7 @@ static int usblp_release(struct inode *inode, struct file *file)
usblp->used = 0;
if (usblp->present) {
usblp_unlink_urbs(usblp);
usb_autopm_put_interface(usblp->intf);
} else /* finish cleanup from disconnect */
usblp_cleanup (usblp);
mutex_unlock (&usblp_mutex);
@ -1203,14 +1207,9 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
{
struct usblp *usblp = usb_get_intfdata (intf);
/* this races against normal access and open */
mutex_lock (&usblp_mutex);
mutex_lock (&usblp->mut);
/* we take no more IO */
usblp->sleeping = 1;
usblp_unlink_urbs(usblp);
mutex_unlock (&usblp->mut);
mutex_unlock (&usblp_mutex);
return 0;
}
@ -1220,15 +1219,9 @@ static int usblp_resume (struct usb_interface *intf)
struct usblp *usblp = usb_get_intfdata (intf);
int r;
mutex_lock (&usblp_mutex);
mutex_lock (&usblp->mut);
usblp->sleeping = 0;
r = handle_bidir (usblp);
mutex_unlock (&usblp->mut);
mutex_unlock (&usblp_mutex);
return r;
}
@ -1251,6 +1244,7 @@ static struct usb_driver usblp_driver = {
.suspend = usblp_suspend,
.resume = usblp_resume,
.id_table = usblp_ids,
.supports_autosuspend = 1,
};
static int __init usblp_init(void)

View File

@ -33,19 +33,6 @@ config USB_DEVICEFS
Most users want to say Y here.
config USB_BANDWIDTH
bool "Enforce USB bandwidth allocation (EXPERIMENTAL)"
depends on USB && EXPERIMENTAL
help
If you say Y here, the USB subsystem enforces USB bandwidth
allocation and will prevent some device opens from succeeding
if they would cause USB bandwidth usage to go above 90% of
the bus bandwidth.
If you say N here, these conditions will cause warning messages
about USB bandwidth usage to be logged and some devices or
drivers may not work correctly.
config USB_DYNAMIC_MINORS
bool "Dynamic USB minor allocation (EXPERIMENTAL)"
depends on USB && EXPERIMENTAL

View File

@ -49,9 +49,9 @@ static const size_t pool_max [HCD_BUFFER_POOLS] = {
*
* Call hcd_buffer_destroy() to clean up after using those pools.
*/
int hcd_buffer_create (struct usb_hcd *hcd)
int hcd_buffer_create(struct usb_hcd *hcd)
{
char name [16];
char name[16];
int i, size;
if (!hcd->self.controller->dma_mask)
@ -60,11 +60,11 @@ int hcd_buffer_create (struct usb_hcd *hcd)
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (!(size = pool_max [i]))
continue;
snprintf (name, sizeof name, "buffer-%d", size);
hcd->pool [i] = dma_pool_create (name, hcd->self.controller,
snprintf(name, sizeof name, "buffer-%d", size);
hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
size, size, 0);
if (!hcd->pool [i]) {
hcd_buffer_destroy (hcd);
hcd_buffer_destroy(hcd);
return -ENOMEM;
}
}
@ -79,14 +79,14 @@ int hcd_buffer_create (struct usb_hcd *hcd)
*
* This frees the buffer pools created by hcd_buffer_create().
*/
void hcd_buffer_destroy (struct usb_hcd *hcd)
void hcd_buffer_destroy(struct usb_hcd *hcd)
{
int i;
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
struct dma_pool *pool = hcd->pool [i];
struct dma_pool *pool = hcd->pool[i];
if (pool) {
dma_pool_destroy (pool);
dma_pool_destroy(pool);
hcd->pool[i] = NULL;
}
}
@ -97,8 +97,8 @@ void hcd_buffer_destroy (struct usb_hcd *hcd)
* better sharing and to leverage mm/slab.c intelligence.
*/
void *hcd_buffer_alloc (
struct usb_bus *bus,
void *hcd_buffer_alloc(
struct usb_bus *bus,
size_t size,
gfp_t mem_flags,
dma_addr_t *dma
@ -110,18 +110,18 @@ void *hcd_buffer_alloc (
/* some USB hosts just use PIO */
if (!bus->controller->dma_mask) {
*dma = ~(dma_addr_t) 0;
return kmalloc (size, mem_flags);
return kmalloc(size, mem_flags);
}
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i])
return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
return dma_pool_alloc(hcd->pool [i], mem_flags, dma);
}
return dma_alloc_coherent (hcd->self.controller, size, dma, 0);
return dma_alloc_coherent(hcd->self.controller, size, dma, 0);
}
void hcd_buffer_free (
struct usb_bus *bus,
void hcd_buffer_free(
struct usb_bus *bus,
size_t size,
void *addr,
dma_addr_t dma
@ -134,15 +134,15 @@ void hcd_buffer_free (
return;
if (!bus->controller->dma_mask) {
kfree (addr);
kfree(addr);
return;
}
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
if (size <= pool_max [i]) {
dma_pool_free (hcd->pool [i], addr, dma);
dma_pool_free(hcd->pool [i], addr, dma);
return;
}
}
dma_free_coherent (hcd->self.controller, size, addr, dma);
dma_free_coherent(hcd->self.controller, size, addr, dma);
}

View File

@ -104,7 +104,7 @@ static const char *format_config =
static const char *format_iface =
/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
"I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
"I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
static const char *format_endpt =
/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
@ -164,10 +164,10 @@ static const char *class_decode(const int class)
for (ix = 0; clas_info[ix].class != -1; ix++)
if (clas_info[ix].class == class)
break;
return (clas_info[ix].class_name);
return clas_info[ix].class_name;
}
static char *usb_dump_endpoint_descriptor (
static char *usb_dump_endpoint_descriptor(
int speed,
char *start,
char *end,
@ -212,9 +212,9 @@ static char *usb_dump_endpoint_descriptor (
break;
case USB_ENDPOINT_XFER_INT:
type = "Int.";
if (speed == USB_SPEED_HIGH) {
if (speed == USB_SPEED_HIGH)
interval = 1 << (desc->bInterval - 1);
} else
else
interval = desc->bInterval;
break;
default: /* "can't happen" */
@ -242,15 +242,19 @@ static char *usb_dump_interface_descriptor(char *start, char *end,
{
const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
const char *driver_name = "";
int active = 0;
if (start > end)
return start;
down_read(&usb_bus_type.subsys.rwsem);
if (iface)
if (iface) {
driver_name = (iface->dev.driver
? iface->dev.driver->name
: "(none)");
active = (desc == &iface->cur_altsetting->desc);
}
start += sprintf(start, format_iface,
active ? '*' : ' ', /* mark active altsetting */
desc->bInterfaceNumber,
desc->bAlternateSetting,
desc->bNumEndpoints,
@ -343,7 +347,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
if (start > end)
return start;
start += sprintf (start, format_device1,
start += sprintf(start, format_device1,
bcdUSB >> 8, bcdUSB & 0xff,
desc->bDeviceClass,
class_decode (desc->bDeviceClass),
@ -363,7 +367,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
/*
* Dump the different strings that this device holds.
*/
static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev)
{
if (start > end)
return start;
@ -395,7 +399,7 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
if (start > end)
return start;
start = usb_dump_device_strings (start, end, dev);
start = usb_dump_device_strings(start, end, dev);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (start > end)

View File

@ -522,19 +522,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
static struct usb_device *usbdev_lookup_minor(int minor)
{
struct class_device *class_dev;
struct usb_device *dev = NULL;
struct device *device;
struct usb_device *udev = NULL;
down(&usb_device_class->sem);
list_for_each_entry(class_dev, &usb_device_class->children, node) {
if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
dev = class_dev->class_data;
list_for_each_entry(device, &usb_device_class->devices, node) {
if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
udev = device->platform_data;
break;
}
}
up(&usb_device_class->sem);
return dev;
return udev;
};
/*
@ -570,6 +570,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
ps->dev = dev;
ps->file = file;
spin_lock_init(&ps->lock);
INIT_LIST_HEAD(&ps->list);
INIT_LIST_HEAD(&ps->async_pending);
INIT_LIST_HEAD(&ps->async_completed);
init_waitqueue_head(&ps->wait);
@ -1596,19 +1597,19 @@ static int usbdev_add(struct usb_device *dev)
{
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
dev->class_dev = class_device_create(usb_device_class, NULL,
MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
MKDEV(USB_DEVICE_MAJOR, minor),
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
if (IS_ERR(dev->class_dev))
return PTR_ERR(dev->class_dev);
if (IS_ERR(dev->usbfs_dev))
return PTR_ERR(dev->usbfs_dev);
dev->class_dev->class_data = dev;
dev->usbfs_dev->platform_data = dev;
return 0;
}
static void usbdev_remove(struct usb_device *dev)
{
class_device_unregister(dev->class_dev);
device_unregister(dev->usbfs_dev);
}
static int usbdev_notify(struct notifier_block *self, unsigned long action,

View File

@ -28,24 +28,16 @@
#include "hcd.h"
#include "usb.h"
static int usb_match_one_id(struct usb_interface *interface,
const struct usb_device_id *id);
struct usb_dynid {
struct list_head node;
struct usb_device_id id;
};
#ifdef CONFIG_HOTPLUG
/*
* Adds a new dynamic USBdevice ID to this driver,
* and cause the driver to probe for all devices again.
*/
static ssize_t store_new_id(struct device_driver *driver,
const char *buf, size_t count)
ssize_t usb_store_new_id(struct usb_dynids *dynids,
struct device_driver *driver,
const char *buf, size_t count)
{
struct usb_driver *usb_drv = to_usb_driver(driver);
struct usb_dynid *dynid;
u32 idVendor = 0;
u32 idProduct = 0;
@ -65,9 +57,9 @@ static ssize_t store_new_id(struct device_driver *driver,
dynid->id.idProduct = idProduct;
dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
spin_lock(&usb_drv->dynids.lock);
list_add_tail(&usb_drv->dynids.list, &dynid->node);
spin_unlock(&usb_drv->dynids.lock);
spin_lock(&dynids->lock);
list_add_tail(&dynids->list, &dynid->node);
spin_unlock(&dynids->lock);
if (get_driver(driver)) {
retval = driver_attach(driver);
@ -78,6 +70,15 @@ static ssize_t store_new_id(struct device_driver *driver,
return retval;
return count;
}
EXPORT_SYMBOL_GPL(usb_store_new_id);
static ssize_t store_new_id(struct device_driver *driver,
const char *buf, size_t count)
{
struct usb_driver *usb_drv = to_usb_driver(driver);
return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
}
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
static int usb_create_newid_file(struct usb_driver *usb_drv)
@ -365,8 +366,8 @@ void usb_driver_release_interface(struct usb_driver *driver,
EXPORT_SYMBOL(usb_driver_release_interface);
/* returns 0 if no match, 1 if match */
static int usb_match_one_id(struct usb_interface *interface,
const struct usb_device_id *id)
int usb_match_one_id(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_host_interface *intf;
struct usb_device *dev;
@ -432,6 +433,8 @@ static int usb_match_one_id(struct usb_interface *interface,
return 1;
}
EXPORT_SYMBOL_GPL(usb_match_one_id);
/**
* usb_match_id - find first usb_device_id matching device or interface
* @interface: the interface of interest

View File

@ -194,14 +194,13 @@ int usb_register_dev(struct usb_interface *intf,
++temp;
else
temp = name;
intf->class_dev = class_device_create(usb_class->class, NULL,
MKDEV(USB_MAJOR, minor),
&intf->dev, "%s", temp);
if (IS_ERR(intf->class_dev)) {
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);
usb_minors[intf->minor] = NULL;
spin_unlock (&minor_lock);
retval = PTR_ERR(intf->class_dev);
retval = PTR_ERR(intf->usb_dev);
}
exit:
return retval;
@ -242,8 +241,8 @@ void usb_deregister_dev(struct usb_interface *intf,
spin_unlock (&minor_lock);
snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
intf->class_dev = NULL;
device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
intf->usb_dev = NULL;
intf->minor = -1;
destroy_usb_class();
}

View File

@ -25,6 +25,20 @@ static inline const char *plural(int n)
return (n == 1 ? "" : "s");
}
static int is_rndis(struct usb_interface_descriptor *desc)
{
return desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
&& desc->bInterfaceProtocol == 0xff;
}
static int is_activesync(struct usb_interface_descriptor *desc)
{
return desc->bInterfaceClass == USB_CLASS_MISC
&& desc->bInterfaceSubClass == 1
&& desc->bInterfaceProtocol == 1;
}
static int choose_configuration(struct usb_device *udev)
{
int i;
@ -87,14 +101,12 @@ static int choose_configuration(struct usb_device *udev)
continue;
}
/* If the first config's first interface is COMM/2/0xff
* (MSFT RNDIS), rule it out unless Linux has host-side
* RNDIS support. */
if (i == 0 && desc
&& desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
&& desc->bInterfaceProtocol == 0xff) {
#ifndef CONFIG_USB_NET_RNDIS_HOST
/* When the first config's first interface is one of Microsoft's
* pet nonstandard Ethernet-over-USB protocols, ignore it unless
* this kernel has enabled the necessary host side driver.
*/
if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) {
#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
continue;
#else
best = c;

View File

@ -45,8 +45,6 @@
#include "hub.h"
// #define USB_BANDWIDTH_MESSAGES
/*-------------------------------------------------------------------------*/
/*
@ -891,136 +889,6 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
}
EXPORT_SYMBOL (usb_calc_bus_time);
/*
* usb_check_bandwidth():
*
* old_alloc is from host_controller->bandwidth_allocated in microseconds;
* bustime is from calc_bus_time(), but converted to microseconds.
*
* returns <bustime in us> if successful,
* or -ENOSPC if bandwidth request fails.
*
* FIXME:
* This initial implementation does not use Endpoint.bInterval
* in managing bandwidth allocation.
* It probably needs to be expanded to use Endpoint.bInterval.
* This can be done as a later enhancement (correction).
*
* This will also probably require some kind of
* frame allocation tracking...meaning, for example,
* that if multiple drivers request interrupts every 10 USB frames,
* they don't all have to be allocated at
* frame numbers N, N+10, N+20, etc. Some of them could be at
* N+11, N+21, N+31, etc., and others at
* N+12, N+22, N+32, etc.
*
* Similarly for isochronous transfers...
*
* Individual HCDs can schedule more directly ... this logic
* is not correct for high speed transfers.
*/
int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
{
unsigned int pipe = urb->pipe;
long bustime;
int is_in = usb_pipein (pipe);
int is_iso = usb_pipeisoc (pipe);
int old_alloc = dev->bus->bandwidth_allocated;
int new_alloc;
bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso,
usb_maxpacket (dev, pipe, !is_in)));
if (is_iso)
bustime /= urb->number_of_packets;
new_alloc = old_alloc + (int) bustime;
if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) {
#ifdef DEBUG
char *mode =
#ifdef CONFIG_USB_BANDWIDTH
"";
#else
"would have ";
#endif
dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n",
mode, old_alloc, bustime, new_alloc);
#endif
#ifdef CONFIG_USB_BANDWIDTH
bustime = -ENOSPC; /* report error */
#endif
}
return bustime;
}
EXPORT_SYMBOL (usb_check_bandwidth);
/**
* usb_claim_bandwidth - records bandwidth for a periodic transfer
* @dev: source/target of request
* @urb: request (urb->dev == dev)
* @bustime: bandwidth consumed, in (average) microseconds per frame
* @isoc: true iff the request is isochronous
*
* Bus bandwidth reservations are recorded purely for diagnostic purposes.
* HCDs are expected not to overcommit periodic bandwidth, and to record such
* reservations whenever endpoints are added to the periodic schedule.
*
* FIXME averaging per-frame is suboptimal. Better to sum over the HCD's
* entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable
* for EHCI (256/512/1024 frames, default 1024) and have the bus expose how
* large its periodic schedule is.
*/
void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
{
dev->bus->bandwidth_allocated += bustime;
if (isoc)
dev->bus->bandwidth_isoc_reqs++;
else
dev->bus->bandwidth_int_reqs++;
urb->bandwidth = bustime;
#ifdef USB_BANDWIDTH_MESSAGES
dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n",
bustime,
isoc ? "ISOC" : "INTR",
dev->bus->bandwidth_allocated,
dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
#endif
}
EXPORT_SYMBOL (usb_claim_bandwidth);
/**
* usb_release_bandwidth - reverses effect of usb_claim_bandwidth()
* @dev: source/target of request
* @urb: request (urb->dev == dev)
* @isoc: true iff the request is isochronous
*
* This records that previously allocated bandwidth has been released.
* Bandwidth is released when endpoints are removed from the host controller's
* periodic schedule.
*/
void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
{
dev->bus->bandwidth_allocated -= urb->bandwidth;
if (isoc)
dev->bus->bandwidth_isoc_reqs--;
else
dev->bus->bandwidth_int_reqs--;
#ifdef USB_BANDWIDTH_MESSAGES
dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n",
urb->bandwidth,
isoc ? "ISOC" : "INTR",
dev->bus->bandwidth_allocated,
dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
#endif
urb->bandwidth = 0;
}
EXPORT_SYMBOL (usb_release_bandwidth);
/*-------------------------------------------------------------------------*/
@ -1034,11 +902,6 @@ static void urb_unlink (struct urb *urb)
{
unsigned long flags;
/* Release any periodic transfer bandwidth */
if (urb->bandwidth)
usb_release_bandwidth (urb->dev, urb,
usb_pipeisoc (urb->pipe));
/* clear all state linking urb to this dev (and hcd) */
spin_lock_irqsave (&hcd_data_lock, flags);

View File

@ -308,10 +308,6 @@ extern void usb_destroy_configuration(struct usb_device *dev);
#define NS_TO_US(ns) ((ns + 500L) / 1000L)
/* convert & round nanoseconds to microseconds */
extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
int bustime, int isoc);
extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
int isoc);
/*
* Full/low speed bandwidth allocation constants/support.
@ -324,8 +320,6 @@ extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
#define FRAME_TIME_MAX_BITS_ALLOC (90L * FRAME_TIME_BITS / 100L)
#define FRAME_TIME_MAX_USECS_ALLOC (90L * FRAME_TIME_USECS / 100L)
extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
/*
* Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
* ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed

View File

@ -87,9 +87,6 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
static struct task_struct *khubd_task;
/* multithreaded probe logic */
static int multithread_probe = 0;
/* cycle leds on hubs that aren't blinking for attention */
static int blinkenlights = 0;
module_param (blinkenlights, bool, S_IRUGO);
@ -1256,9 +1253,28 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
static int __usb_port_suspend(struct usb_device *, int port1);
#endif
static int __usb_new_device(void *void_data)
/**
* usb_new_device - perform initial device setup (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
* This is called with devices which have been enumerated, but not yet
* configured. The device descriptor is available, but not descriptors
* for any device configuration. The caller must have locked either
* the parent hub (if udev is a normal device) or else the
* usb_bus_list_lock (if udev is a root hub). The parent's pointer to
* udev has already been installed, but udev is not yet visible through
* sysfs or other filesystem code.
*
* It will return if the device is configured properly or not. Zero if
* the interface was registered with the driver core; else a negative
* errno value.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver or root-hub registrar should ever call this.
*/
int usb_new_device(struct usb_device *udev)
{
struct usb_device *udev = void_data;
int err;
/* Lock ourself into memory in order to keep a probe sequence
@ -1375,44 +1391,6 @@ static int __usb_new_device(void *void_data)
goto exit;
}
/**
* usb_new_device - perform initial device setup (usbcore-internal)
* @udev: newly addressed device (in ADDRESS state)
*
* This is called with devices which have been enumerated, but not yet
* configured. The device descriptor is available, but not descriptors
* for any device configuration. The caller must have locked either
* the parent hub (if udev is a normal device) or else the
* usb_bus_list_lock (if udev is a root hub). The parent's pointer to
* udev has already been installed, but udev is not yet visible through
* sysfs or other filesystem code.
*
* The return value for this function depends on if the
* multithread_probe variable is set or not. If it's set, it will
* return a if the probe thread was successfully created or not. If the
* variable is not set, it will return if the device is configured
* properly or not. interfaces, in sysfs); else a negative errno value.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver or root-hub registrar should ever call this.
*/
int usb_new_device(struct usb_device *udev)
{
struct task_struct *probe_task;
int ret = 0;
if (multithread_probe) {
probe_task = kthread_run(__usb_new_device, udev,
"usb-probe-%s", udev->devnum);
if (IS_ERR(probe_task))
ret = PTR_ERR(probe_task);
} else
ret = __usb_new_device(udev);
return ret;
}
static int hub_port_status(struct usb_hub *hub, int port1,
u16 *status, u16 *change)
{

View File

@ -1545,11 +1545,7 @@ int usb_driver_set_configuration(struct usb_device *udev, int config)
INIT_WORK(&req->work, driver_set_config_work);
usb_get_dev(udev);
if (!schedule_work(&req->work)) {
usb_put_dev(udev);
kfree(req);
return -EINVAL;
}
schedule_work(&req->work);
return 0;
}
EXPORT_SYMBOL_GPL(usb_driver_set_configuration);

View File

@ -16,16 +16,16 @@
/* Active configuration fields */
#define usb_actconfig_show(field, multiplier, format_string) \
static ssize_t show_##field (struct device *dev, \
static ssize_t show_##field(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct usb_device *udev; \
struct usb_host_config *actconfig; \
\
udev = to_usb_device (dev); \
udev = to_usb_device(dev); \
actconfig = udev->actconfig; \
if (actconfig) \
return sprintf (buf, format_string, \
return sprintf(buf, format_string, \
actconfig->desc.field * multiplier); \
else \
return 0; \
@ -35,9 +35,9 @@ static ssize_t show_##field (struct device *dev, \
usb_actconfig_show(field, multiplier, format_string) \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
usb_actconfig_attr (bmAttributes, 1, "%2x\n")
usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
usb_actconfig_attr(bmAttributes, 1, "%2x\n")
usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
static ssize_t show_configuration_string(struct device *dev,
struct device_attribute *attr, char *buf)
@ -45,7 +45,7 @@ static ssize_t show_configuration_string(struct device *dev,
struct usb_device *udev;
struct usb_host_config *actconfig;
udev = to_usb_device (dev);
udev = to_usb_device(dev);
actconfig = udev->actconfig;
if ((!actconfig) || (!actconfig->string))
return 0;
@ -57,16 +57,16 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
usb_actconfig_show(bConfigurationValue, 1, "%u\n");
static ssize_t
set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct usb_device *udev = to_usb_device (dev);
struct usb_device *udev = to_usb_device(dev);
int config, value;
if (sscanf (buf, "%u", &config) != 1 || config > 255)
if (sscanf(buf, "%u", &config) != 1 || config > 255)
return -EINVAL;
usb_lock_device(udev);
value = usb_set_configuration (udev, config);
value = usb_set_configuration(udev, config);
usb_unlock_device(udev);
return (value < 0) ? value : count;
}
@ -81,7 +81,7 @@ static ssize_t show_##name(struct device *dev, \
{ \
struct usb_device *udev; \
\
udev = to_usb_device (dev); \
udev = to_usb_device(dev); \
return sprintf(buf, "%s\n", udev->name); \
} \
static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
@ -91,12 +91,12 @@ usb_string_attr(manufacturer);
usb_string_attr(serial);
static ssize_t
show_speed (struct device *dev, struct device_attribute *attr, char *buf)
show_speed(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
char *speed;
udev = to_usb_device (dev);
udev = to_usb_device(dev);
switch (udev->speed) {
case USB_SPEED_LOW:
@ -112,22 +112,22 @@ show_speed (struct device *dev, struct device_attribute *attr, char *buf)
default:
speed = "unknown";
}
return sprintf (buf, "%s\n", speed);
return sprintf(buf, "%s\n", speed);
}
static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
static ssize_t
show_devnum (struct device *dev, struct device_attribute *attr, char *buf)
show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
udev = to_usb_device (dev);
return sprintf (buf, "%d\n", udev->devnum);
udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->devnum);
}
static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
static ssize_t
show_version (struct device *dev, struct device_attribute *attr, char *buf)
show_version(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
u16 bcdUSB;
@ -139,25 +139,25 @@ show_version (struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
static ssize_t
show_maxchild (struct device *dev, struct device_attribute *attr, char *buf)
show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
{
struct usb_device *udev;
udev = to_usb_device (dev);
return sprintf (buf, "%d\n", udev->maxchild);
udev = to_usb_device(dev);
return sprintf(buf, "%d\n", udev->maxchild);
}
static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
/* Descriptor fields */
#define usb_descriptor_attr_le16(field, format_string) \
static ssize_t \
show_##field (struct device *dev, struct device_attribute *attr, \
show_##field(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_device *udev; \
\
udev = to_usb_device (dev); \
return sprintf (buf, format_string, \
udev = to_usb_device(dev); \
return sprintf(buf, format_string, \
le16_to_cpu(udev->descriptor.field)); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
@ -168,21 +168,21 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n")
#define usb_descriptor_attr(field, format_string) \
static ssize_t \
show_##field (struct device *dev, struct device_attribute *attr, \
show_##field(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_device *udev; \
\
udev = to_usb_device (dev); \
return sprintf (buf, format_string, udev->descriptor.field); \
udev = to_usb_device(dev); \
return sprintf(buf, format_string, udev->descriptor.field); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
usb_descriptor_attr (bDeviceClass, "%02x\n")
usb_descriptor_attr (bDeviceSubClass, "%02x\n")
usb_descriptor_attr (bDeviceProtocol, "%02x\n")
usb_descriptor_attr (bNumConfigurations, "%d\n")
usb_descriptor_attr (bMaxPacketSize0, "%d\n")
usb_descriptor_attr(bDeviceClass, "%02x\n")
usb_descriptor_attr(bDeviceSubClass, "%02x\n")
usb_descriptor_attr(bDeviceProtocol, "%02x\n")
usb_descriptor_attr(bNumConfigurations, "%d\n")
usb_descriptor_attr(bMaxPacketSize0, "%d\n")
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
@ -220,17 +220,17 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
return retval;
if (udev->manufacturer) {
retval = device_create_file (dev, &dev_attr_manufacturer);
retval = device_create_file(dev, &dev_attr_manufacturer);
if (retval)
goto error;
}
if (udev->product) {
retval = device_create_file (dev, &dev_attr_product);
retval = device_create_file(dev, &dev_attr_product);
if (retval)
goto error;
}
if (udev->serial) {
retval = device_create_file (dev, &dev_attr_serial);
retval = device_create_file(dev, &dev_attr_serial);
if (retval)
goto error;
}
@ -246,7 +246,7 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
return retval;
}
void usb_remove_sysfs_dev_files (struct usb_device *udev)
void usb_remove_sysfs_dev_files(struct usb_device *udev)
{
struct device *dev = &udev->dev;
@ -264,22 +264,22 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev)
/* Interface fields */
#define usb_intf_attr(field, format_string) \
static ssize_t \
show_##field (struct device *dev, struct device_attribute *attr, \
show_##field(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
struct usb_interface *intf = to_usb_interface (dev); \
struct usb_interface *intf = to_usb_interface(dev); \
\
return sprintf (buf, format_string, \
return sprintf(buf, format_string, \
intf->cur_altsetting->desc.field); \
} \
static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
usb_intf_attr (bInterfaceNumber, "%02x\n")
usb_intf_attr (bAlternateSetting, "%2d\n")
usb_intf_attr (bNumEndpoints, "%02x\n")
usb_intf_attr (bInterfaceClass, "%02x\n")
usb_intf_attr (bInterfaceSubClass, "%02x\n")
usb_intf_attr (bInterfaceProtocol, "%02x\n")
usb_intf_attr(bInterfaceNumber, "%02x\n")
usb_intf_attr(bAlternateSetting, "%2d\n")
usb_intf_attr(bNumEndpoints, "%02x\n")
usb_intf_attr(bInterfaceClass, "%02x\n")
usb_intf_attr(bInterfaceSubClass, "%02x\n")
usb_intf_attr(bInterfaceProtocol, "%02x\n")
static ssize_t show_interface_string(struct device *dev,
struct device_attribute *attr, char *buf)
@ -288,8 +288,8 @@ static ssize_t show_interface_string(struct device *dev,
struct usb_device *udev;
int len;
intf = to_usb_interface (dev);
udev = interface_to_usbdev (intf);
intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf);
len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
if (len < 0)
return 0;
@ -384,7 +384,7 @@ int usb_create_sysfs_intf_files(struct usb_interface *intf)
return retval;
}
void usb_remove_sysfs_intf_files (struct usb_interface *intf)
void usb_remove_sysfs_intf_files(struct usb_interface *intf)
{
usb_remove_intf_ep_files(intf);
sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);

View File

@ -235,16 +235,15 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb->status = -EINPROGRESS;
urb->actual_length = 0;
urb->bandwidth = 0;
/* Lots of sanity checks, so HCDs can rely on clean data
* and don't need to duplicate tests
*/
pipe = urb->pipe;
temp = usb_pipetype (pipe);
is_out = usb_pipeout (pipe);
temp = usb_pipetype(pipe);
is_out = usb_pipeout(pipe);
if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED)
if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
return -ENODEV;
/* FIXME there should be a sharable lock protecting us against
@ -253,11 +252,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* checks get made.)
*/
max = usb_maxpacket (dev, pipe, is_out);
max = usb_maxpacket(dev, pipe, is_out);
if (max <= 0) {
dev_dbg(&dev->dev,
"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
usb_pipeendpoint (pipe), is_out ? "out" : "in",
usb_pipeendpoint(pipe), is_out ? "out" : "in",
__FUNCTION__, max);
return -EMSGSIZE;
}
@ -279,11 +278,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (urb->number_of_packets <= 0)
return -EINVAL;
for (n = 0; n < urb->number_of_packets; n++) {
len = urb->iso_frame_desc [n].length;
len = urb->iso_frame_desc[n].length;
if (len < 0 || len > max)
return -EMSGSIZE;
urb->iso_frame_desc [n].status = -EXDEV;
urb->iso_frame_desc [n].actual_length = 0;
urb->iso_frame_desc[n].status = -EXDEV;
urb->iso_frame_desc[n].actual_length = 0;
}
}
@ -322,7 +321,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
/* fail if submitter gave bogus flags */
if (urb->transfer_flags != orig_flags) {
err ("BOGUS urb flags, %x --> %x",
err("BOGUS urb flags, %x --> %x",
orig_flags, urb->transfer_flags);
return -EINVAL;
}
@ -373,7 +372,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb->interval = temp;
}
return usb_hcd_submit_urb (urb, mem_flags);
return usb_hcd_submit_urb(urb, mem_flags);
}
/*-------------------------------------------------------------------*/

View File

@ -233,7 +233,7 @@ static void usb_autosuspend_work(struct work_struct *work)
* @parent: hub to which device is connected; null to allocate a root hub
* @bus: bus used to access the device
* @port1: one-based index of port; ignored for root hubs
* Context: !in_interrupt ()
* Context: !in_interrupt()
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
@ -277,22 +277,22 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
* as stable: bus->busnum changes easily from modprobe order,
* cardbus or pci hotplugging, and so on.
*/
if (unlikely (!parent)) {
dev->devpath [0] = '0';
if (unlikely(!parent)) {
dev->devpath[0] = '0';
dev->dev.parent = bus->controller;
sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum);
sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
} else {
/* match any labeling on the hubs; it's one-based */
if (parent->devpath [0] == '0')
snprintf (dev->devpath, sizeof dev->devpath,
if (parent->devpath[0] == '0')
snprintf(dev->devpath, sizeof dev->devpath,
"%d", port1);
else
snprintf (dev->devpath, sizeof dev->devpath,
snprintf(dev->devpath, sizeof dev->devpath,
"%s.%d", parent->devpath, port1);
dev->dev.parent = &parent->dev;
sprintf (&dev->dev.bus_id[0], "%d-%s",
sprintf(&dev->dev.bus_id[0], "%d-%s",
bus->busnum, dev->devpath);
/* hub driver sets up TT records */
@ -463,7 +463,7 @@ static struct usb_device *match_device(struct usb_device *dev,
/* see if this device matches */
if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
(product_id == le16_to_cpu(dev->descriptor.idProduct))) {
dev_dbg (&dev->dev, "matched this device!\n");
dev_dbg(&dev->dev, "matched this device!\n");
ret_dev = usb_get_dev(dev);
goto exit;
}
@ -535,7 +535,7 @@ struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
*/
int usb_get_current_frame_number(struct usb_device *dev)
{
return usb_hcd_get_frame_number (dev);
return usb_hcd_get_frame_number(dev);
}
/*-------------------------------------------------------------------*/
@ -593,7 +593,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
*
* When the buffer is no longer used, free it with usb_buffer_free().
*/
void *usb_buffer_alloc (
void *usb_buffer_alloc(
struct usb_device *dev,
size_t size,
gfp_t mem_flags,
@ -602,7 +602,7 @@ void *usb_buffer_alloc (
{
if (!dev || !dev->bus)
return NULL;
return hcd_buffer_alloc (dev->bus, size, mem_flags, dma);
return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
}
/**
@ -616,7 +616,7 @@ void *usb_buffer_alloc (
* been allocated using usb_buffer_alloc(), and the parameters must match
* those provided in that allocation request.
*/
void usb_buffer_free (
void usb_buffer_free(
struct usb_device *dev,
size_t size,
void *addr,
@ -627,7 +627,7 @@ void usb_buffer_free (
return;
if (!addr)
return;
hcd_buffer_free (dev->bus, size, addr, dma);
hcd_buffer_free(dev->bus, size, addr, dma);
}
/**
@ -647,7 +647,7 @@ void usb_buffer_free (
* Reverse the effect of this call with usb_buffer_unmap().
*/
#if 0
struct urb *usb_buffer_map (struct urb *urb)
struct urb *usb_buffer_map(struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
@ -659,14 +659,14 @@ struct urb *usb_buffer_map (struct urb *urb)
return NULL;
if (controller->dma_mask) {
urb->transfer_dma = dma_map_single (controller,
urb->transfer_dma = dma_map_single(controller,
urb->transfer_buffer, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
usb_pipein(urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (usb_pipecontrol (urb->pipe))
urb->setup_dma = dma_map_single (controller,
if (usb_pipecontrol(urb->pipe))
urb->setup_dma = dma_map_single(controller,
urb->setup_packet,
sizeof (struct usb_ctrlrequest),
sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
// FIXME generic api broken like pci, can't report errors
// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
@ -689,7 +689,7 @@ struct urb *usb_buffer_map (struct urb *urb)
* usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
* @urb: urb whose transfer_buffer/setup_packet will be synchronized
*/
void usb_buffer_dmasync (struct urb *urb)
void usb_buffer_dmasync(struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
@ -702,14 +702,14 @@ void usb_buffer_dmasync (struct urb *urb)
return;
if (controller->dma_mask) {
dma_sync_single (controller,
dma_sync_single(controller,
urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
usb_pipein(urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (usb_pipecontrol (urb->pipe))
dma_sync_single (controller,
if (usb_pipecontrol(urb->pipe))
dma_sync_single(controller,
urb->setup_dma,
sizeof (struct usb_ctrlrequest),
sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
}
}
@ -722,7 +722,7 @@ void usb_buffer_dmasync (struct urb *urb)
* Reverses the effect of usb_buffer_map().
*/
#if 0
void usb_buffer_unmap (struct urb *urb)
void usb_buffer_unmap(struct urb *urb)
{
struct usb_bus *bus;
struct device *controller;
@ -735,14 +735,14 @@ void usb_buffer_unmap (struct urb *urb)
return;
if (controller->dma_mask) {
dma_unmap_single (controller,
dma_unmap_single(controller,
urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein (urb->pipe)
usb_pipein(urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (usb_pipecontrol (urb->pipe))
dma_unmap_single (controller,
if (usb_pipecontrol(urb->pipe))
dma_unmap_single(controller,
urb->setup_dma,
sizeof (struct usb_ctrlrequest),
sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
}
urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
@ -783,15 +783,15 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
struct device *controller;
if (!dev
|| usb_pipecontrol (pipe)
|| usb_pipecontrol(pipe)
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return -1;
// FIXME generic api broken like pci, can't report errors
return dma_map_sg (controller, sg, nents,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
return dma_map_sg(controller, sg, nents,
usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* XXX DISABLED, no users currently. If you wish to re-enable this
@ -823,8 +823,8 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
|| !controller->dma_mask)
return;
dma_sync_sg (controller, sg, n_hw_ents,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
dma_sync_sg(controller, sg, n_hw_ents,
usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
#endif
@ -849,8 +849,8 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
|| !controller->dma_mask)
return;
dma_unmap_sg (controller, sg, n_hw_ents,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
dma_unmap_sg(controller, sg, n_hw_ents,
usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
/* format to disable USB on kernel command line is: nousb */
@ -871,7 +871,7 @@ static int __init usb_init(void)
{
int retval;
if (nousb) {
pr_info ("%s: USB support disabled\n", usbcore_name);
pr_info("%s: USB support disabled\n", usbcore_name);
return 0;
}
@ -971,19 +971,19 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor);
EXPORT_SYMBOL(usb_find_device);
EXPORT_SYMBOL(usb_get_current_frame_number);
EXPORT_SYMBOL (usb_buffer_alloc);
EXPORT_SYMBOL (usb_buffer_free);
EXPORT_SYMBOL(usb_buffer_alloc);
EXPORT_SYMBOL(usb_buffer_free);
#if 0
EXPORT_SYMBOL (usb_buffer_map);
EXPORT_SYMBOL (usb_buffer_dmasync);
EXPORT_SYMBOL (usb_buffer_unmap);
EXPORT_SYMBOL(usb_buffer_map);
EXPORT_SYMBOL(usb_buffer_dmasync);
EXPORT_SYMBOL(usb_buffer_unmap);
#endif
EXPORT_SYMBOL (usb_buffer_map_sg);
EXPORT_SYMBOL(usb_buffer_map_sg);
#if 0
EXPORT_SYMBOL (usb_buffer_dmasync_sg);
EXPORT_SYMBOL(usb_buffer_dmasync_sg);
#endif
EXPORT_SYMBOL (usb_buffer_unmap_sg);
EXPORT_SYMBOL(usb_buffer_unmap_sg);
MODULE_LICENSE("GPL");

View File

@ -39,7 +39,7 @@
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/clk.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/byteorder.h>
@ -1807,16 +1807,13 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg)
|| !wake
|| at91_suspend_entering_slow_clock()) {
pullup(udc, 0);
disable_irq_wake(udc->udp_irq);
wake = 0;
} else
enable_irq_wake(udc->udp_irq);
if (udc->board.vbus_pin > 0) {
if (wake)
enable_irq_wake(udc->board.vbus_pin);
else
disable_irq_wake(udc->board.vbus_pin);
}
udc->active_suspend = wake;
if (udc->board.vbus_pin > 0 && wake)
enable_irq_wake(udc->board.vbus_pin);
return 0;
}
@ -1824,8 +1821,14 @@ static int at91udc_resume(struct platform_device *pdev)
{
struct at91_udc *udc = platform_get_drvdata(pdev);
if (udc->board.vbus_pin > 0 && udc->active_suspend)
disable_irq_wake(udc->board.vbus_pin);
/* maybe reconnect to host; if so, clocks on */
pullup(udc, 1);
if (udc->active_suspend)
disable_irq_wake(udc->udp_irq);
else
pullup(udc, 1);
return 0;
}
#else

View File

@ -136,6 +136,7 @@ struct at91_udc {
unsigned wait_for_addr_ack:1;
unsigned wait_for_config_ack:1;
unsigned selfpowered:1;
unsigned active_suspend:1;
u8 addr;
struct at91_udc_data board;
struct clk *iclk, *fclk;

View File

@ -24,7 +24,7 @@
#include <linux/string.h>
#include <linux/device.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>

View File

@ -27,7 +27,7 @@
#include <linux/ctype.h>
#include <linux/string.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"

View File

@ -47,7 +47,7 @@
#include <asm/uaccess.h>
#include <asm/unaligned.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
#include <linux/usb_gadget.h>
@ -72,9 +72,18 @@
*
* There's some hardware that can't talk CDC. We make that hardware
* implement a "minimalist" vendor-agnostic CDC core: same framing, but
* link-level setup only requires activating the configuration.
* Linux supports it, but other host operating systems may not.
* (This is a subset of CDC Ethernet.)
* link-level setup only requires activating the configuration. Only the
* endpoint descriptors, and product/vendor IDs, are relevant; no control
* operations are available. Linux supports it, but other host operating
* systems may not. (This is a subset of CDC Ethernet.)
*
* It turns out that if you add a few descriptors to that "CDC Subset",
* (Windows) host side drivers from MCCI can treat it as one submode of
* a proprietary scheme called "SAFE" ... without needing to know about
* specific product/vendor IDs. So we do that, making it easier to use
* those MS-Windows drivers. Those added descriptors make it resemble a
* CDC MDLM device, but they don't change device behavior at all. (See
* MCCI Engineering report 950198 "SAFE Networking Functions".)
*
* A third option is also in use. Rather than CDC Ethernet, or something
* simpler, Microsoft pushes their own approach: RNDIS. The published
@ -254,6 +263,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
#ifdef CONFIG_USB_GADGET_S3C2410
#define DEV_CONFIG_CDC
#endif
#ifdef CONFIG_USB_GADGET_AT91
#define DEV_CONFIG_CDC
#endif
@ -266,6 +279,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
#ifdef CONFIG_USB_GADGET_HUSB2DEV
#define DEV_CONFIG_CDC
#endif
/* For CDC-incapable hardware, choose the simple cdc subset.
* Anything that talks bulk (without notable bugs) can do this.
@ -283,9 +300,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_SUBSET
#endif
#ifdef CONFIG_USB_GADGET_S3C2410
#define DEV_CONFIG_CDC
#endif
/*-------------------------------------------------------------------------*/
@ -487,8 +501,17 @@ rndis_config = {
* endpoint. Both have a "data" interface and two bulk endpoints.
* There are also differences in how control requests are handled.
*
* RNDIS shares a lot with CDC-Ethernet, since it's a variant of
* the CDC-ACM (modem) spec.
* RNDIS shares a lot with CDC-Ethernet, since it's a variant of the
* CDC-ACM (modem) spec. Unfortunately MSFT's RNDIS driver is buggy; it
* may hang or oops. Since bugfixes (or accurate specs, letting Linux
* work around those bugs) are unlikely to ever come from MSFT, you may
* wish to avoid using RNDIS.
*
* MCCI offers an alternative to RNDIS if you need to connect to Windows
* but have hardware that can't support CDC Ethernet. We add descriptors
* to present the CDC Subset as a (nonconformant) CDC MDLM variant called
* "SAFE". That borrows from both CDC Ethernet and CDC MDLM. You can
* get those drivers from MCCI, or bundled with various products.
*/
#ifdef DEV_CONFIG_CDC
@ -522,8 +545,6 @@ rndis_control_intf = {
};
#endif
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
static const struct usb_cdc_header_desc header_desc = {
.bLength = sizeof header_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
@ -532,6 +553,8 @@ static const struct usb_cdc_header_desc header_desc = {
.bcdCDC = __constant_cpu_to_le16 (0x0110),
};
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
static const struct usb_cdc_union_desc union_desc = {
.bLength = sizeof union_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
@ -564,7 +587,40 @@ static const struct usb_cdc_acm_descriptor acm_descriptor = {
#endif
#ifdef DEV_CONFIG_CDC
#ifndef DEV_CONFIG_CDC
/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various
* ways: data endpoints live in the control interface, there's no data
* interface, and it's not used to talk to a cell phone radio.
*/
static const struct usb_cdc_mdlm_desc mdlm_desc = {
.bLength = sizeof mdlm_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_MDLM_TYPE,
.bcdVersion = __constant_cpu_to_le16(0x0100),
.bGUID = {
0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
},
};
/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we
* can't really use its struct. All we do here is say that we're using
* the submode of "SAFE" which directly matches the CDC Subset.
*/
static const u8 mdlm_detail_desc[] = {
6,
USB_DT_CS_INTERFACE,
USB_CDC_MDLM_DETAIL_TYPE,
0, /* "SAFE" */
0, /* network control capabilities (none) */
0, /* network data capabilities ("raw" encapsulation) */
};
#endif
static const struct usb_cdc_ether_desc ether_desc = {
.bLength = sizeof ether_desc,
@ -579,7 +635,6 @@ static const struct usb_cdc_ether_desc ether_desc = {
.bNumberPowerFilters = 0,
};
#endif
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
@ -672,6 +727,9 @@ rndis_data_intf = {
/*
* "Simple" CDC-subset option is a simple vendor-neutral model that most
* full speed controllers can handle: one interface, two bulk endpoints.
*
* To assist host side drivers, we fancy it up a bit, and add descriptors
* so some host side drivers will understand it as a "SAFE" variant.
*/
static const struct usb_interface_descriptor
@ -682,8 +740,8 @@ subset_data_intf = {
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceSubClass = 0,
.bInterfaceClass = USB_CLASS_COMM,
.bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM,
.bInterfaceProtocol = 0,
.iInterface = STRING_DATA,
};
@ -731,10 +789,15 @@ static const struct usb_descriptor_header *fs_eth_function [11] = {
static inline void __init fs_subset_descriptors(void)
{
#ifdef DEV_CONFIG_SUBSET
/* behavior is "CDC Subset"; extra descriptors say "SAFE" */
fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
fs_eth_function[4] = NULL;
fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
fs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc;
fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc;
fs_eth_function[8] = NULL;
#else
fs_eth_function[1] = NULL;
#endif
@ -828,10 +891,15 @@ static const struct usb_descriptor_header *hs_eth_function [11] = {
static inline void __init hs_subset_descriptors(void)
{
#ifdef DEV_CONFIG_SUBSET
/* behavior is "CDC Subset"; extra descriptors say "SAFE" */
hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
hs_eth_function[4] = NULL;
hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
hs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc;
hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc;
hs_eth_function[8] = NULL;
#else
hs_eth_function[1] = NULL;
#endif
@ -878,10 +946,8 @@ static char manufacturer [50];
static char product_desc [40] = DRIVER_DESC;
static char serial_number [20];
#ifdef DEV_CONFIG_CDC
/* address that the host will use ... usually assigned at random */
static char ethaddr [2 * ETH_ALEN + 1];
#endif
/* static strings, in UTF-8 */
static struct usb_string strings [] = {
@ -889,9 +955,9 @@ static struct usb_string strings [] = {
{ STRING_PRODUCT, product_desc, },
{ STRING_SERIALNUMBER, serial_number, },
{ STRING_DATA, "Ethernet Data", },
{ STRING_ETHADDR, ethaddr, },
#ifdef DEV_CONFIG_CDC
{ STRING_CDC, "CDC Ethernet", },
{ STRING_ETHADDR, ethaddr, },
{ STRING_CONTROL, "CDC Communications Control", },
#endif
#ifdef DEV_CONFIG_SUBSET
@ -986,10 +1052,10 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags)
}
#endif
dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
dev->in_ep->driver_data = dev;
dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
dev->out_ep->driver_data = dev;
/* With CDC, the host isn't allowed to use these two data
@ -2278,10 +2344,10 @@ eth_bind (struct usb_gadget *gadget)
"RNDIS/%s", driver_desc);
/* CDC subset ... recognized by Linux since 2.4.10, but Windows
* drivers aren't widely available.
* drivers aren't widely available. (That may be improved by
* supporting one submode of the "SAFE" variant of MDLM.)
*/
} else if (!cdc) {
device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
device_desc.idVendor =
__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
device_desc.idProduct =
@ -2352,6 +2418,10 @@ eth_bind (struct usb_gadget *gadget)
if (!cdc) {
eth_config.bNumInterfaces = 1;
eth_config.iConfiguration = STRING_SUBSET;
/* use functions to set these up, in case we're built to work
* with multiple controllers and must override CDC Ethernet.
*/
fs_subset_descriptors();
hs_subset_descriptors();
}
@ -2415,22 +2485,20 @@ eth_bind (struct usb_gadget *gadget)
/* Module params for these addresses should come from ID proms.
* The host side address is used with CDC and RNDIS, and commonly
* ends up in a persistent config database.
* ends up in a persistent config database. It's not clear if
* host side code for the SAFE thing cares -- its original BLAN
* thing didn't, Sharp never assigned those addresses on Zaurii.
*/
if (get_ether_addr(dev_addr, net->dev_addr))
dev_warn(&gadget->dev,
"using random %s ethernet address\n", "self");
if (cdc || rndis) {
if (get_ether_addr(host_addr, dev->host_mac))
dev_warn(&gadget->dev,
"using random %s ethernet address\n", "host");
#ifdef DEV_CONFIG_CDC
snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
dev->host_mac [0], dev->host_mac [1],
dev->host_mac [2], dev->host_mac [3],
dev->host_mac [4], dev->host_mac [5]);
#endif
}
if (get_ether_addr(host_addr, dev->host_mac))
dev_warn(&gadget->dev,
"using random %s ethernet address\n", "host");
snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
dev->host_mac [0], dev->host_mac [1],
dev->host_mac [2], dev->host_mac [3],
dev->host_mac [4], dev->host_mac [5]);
if (rndis) {
status = rndis_init();

View File

@ -253,7 +253,7 @@
#include <linux/freezer.h>
#include <linux/utsname.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"
@ -1148,7 +1148,7 @@ static int ep0_queue(struct fsg_dev *fsg)
static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
{
struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
struct fsg_dev *fsg = ep->driver_data;
if (req->actual > 0)
dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
@ -1170,8 +1170,8 @@ static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
{
struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context;
struct fsg_dev *fsg = ep->driver_data;
struct fsg_buffhd *bh = req->context;
if (req->status || req->actual != req->length)
DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@ -1190,8 +1190,8 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
{
struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context;
struct fsg_dev *fsg = ep->driver_data;
struct fsg_buffhd *bh = req->context;
dump_msg(fsg, "bulk-out", req->buf, req->actual);
if (req->status || req->actual != bh->bulk_out_intended_length)
@ -1214,8 +1214,8 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
#ifdef CONFIG_USB_FILE_STORAGE_TEST
static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
{
struct fsg_dev *fsg = (struct fsg_dev *) ep->driver_data;
struct fsg_buffhd *bh = (struct fsg_buffhd *) req->context;
struct fsg_dev *fsg = ep->driver_data;
struct fsg_buffhd *bh = req->context;
if (req->status || req->actual != req->length)
DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@ -2577,7 +2577,7 @@ static int send_status(struct fsg_dev *fsg)
}
if (transport_is_bbb()) {
struct bulk_cs_wrap *csw = (struct bulk_cs_wrap *) bh->buf;
struct bulk_cs_wrap *csw = bh->buf;
/* Store and send the Bulk-only CSW */
csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
@ -2596,8 +2596,7 @@ static int send_status(struct fsg_dev *fsg)
return 0;
} else { // USB_PR_CBI
struct interrupt_data *buf = (struct interrupt_data *)
bh->buf;
struct interrupt_data *buf = bh->buf;
/* Store and send the Interrupt data. UFI sends the ASC
* and ASCQ bytes. Everything else sends a Type (which
@ -2982,7 +2981,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
struct usb_request *req = bh->outreq;
struct bulk_cb_wrap *cbw = (struct bulk_cb_wrap *) req->buf;
struct bulk_cb_wrap *cbw = req->buf;
/* Was this a real packet? */
if (req->status)
@ -3428,7 +3427,7 @@ static void handle_exception(struct fsg_dev *fsg)
static int fsg_main_thread(void *fsg_)
{
struct fsg_dev *fsg = (struct fsg_dev *) fsg_;
struct fsg_dev *fsg = fsg_;
/* Allow the thread to be killed by a signal, but set the signal mask
* to block everything but INT, TERM, KILL, and USR1. */
@ -3600,7 +3599,7 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
{
struct lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
struct fsg_dev *fsg = dev_get_drvdata(dev);
char *p;
ssize_t rc;
@ -3629,7 +3628,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
{
ssize_t rc = count;
struct lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
struct fsg_dev *fsg = dev_get_drvdata(dev);
int i;
if (sscanf(buf, "%d", &i) != 1)
@ -3652,7 +3651,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct lun *curlun = dev_to_lun(dev);
struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
struct fsg_dev *fsg = dev_get_drvdata(dev);
int rc = 0;
if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) {
@ -3700,7 +3699,7 @@ static void fsg_release(struct kref *ref)
static void lun_release(struct device *dev)
{
struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
struct fsg_dev *fsg = dev_get_drvdata(dev);
kref_put(&fsg->ref, fsg_release);
}

View File

@ -75,6 +75,12 @@
#define gadget_is_pxa27x(g) 0
#endif
#ifdef CONFIG_USB_GADGET_HUSB2DEV
#define gadget_is_husb2dev(g) !strcmp("husb2_udc", (g)->name)
#else
#define gadget_is_husb2dev(g) 0
#endif
#ifdef CONFIG_USB_GADGET_S3C2410
#define gadget_is_s3c2410(g) !strcmp("s3c2410_udc", (g)->name)
#else
@ -169,5 +175,7 @@ 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))
return 0x18;
return -ENOENT;
}

View File

@ -35,7 +35,7 @@
#include <sound/initval.h>
#include <sound/rawmidi.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/audio.h>
#include <linux/usb/midi.h>

View File

@ -39,7 +39,7 @@
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/byteorder.h>

View File

@ -20,7 +20,7 @@
*/
// #define DEBUG /* data to help fault diagnosis */
// #define DEBUG /* data to help fault diagnosis */
// #define VERBOSE /* extra debug messages (success too) */
#include <linux/init.h>
@ -59,11 +59,11 @@
* may serve as a source of device events, used to handle all control
* requests other than basic enumeration.
*
* - Then either immediately, or after a SET_CONFIGURATION control request,
* ep_config() is called when each /dev/gadget/ep* file is configured
* (by writing endpoint descriptors). Afterwards these files are used
* to write() IN data or to read() OUT data. To halt the endpoint, a
* "wrong direction" request is issued (like reading an IN endpoint).
* - Then, after a SET_CONFIGURATION control request, ep_config() is
* called when each /dev/gadget/ep* file is configured (by writing
* endpoint descriptors). Afterwards these files are used to write()
* IN data or to read() OUT data. To halt the endpoint, a "wrong
* direction" request is issued (like reading an IN endpoint).
*
* Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
* not possible on all hardware. For example, precise fault handling with
@ -98,16 +98,16 @@ enum ep0_state {
* must always write descriptors to initialize the device, then
* the device becomes UNCONNECTED until enumeration.
*/
STATE_OPENED,
STATE_DEV_OPENED,
/* From then on, ep0 fd is in either of two basic modes:
* - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
* - SETUP: read/write will transfer control data and succeed;
* or if "wrong direction", performs protocol stall
*/
STATE_UNCONNECTED,
STATE_CONNECTED,
STATE_SETUP,
STATE_DEV_UNCONNECTED,
STATE_DEV_CONNECTED,
STATE_DEV_SETUP,
/* UNBOUND means the driver closed ep0, so the device won't be
* accessible again (DEV_DISABLED) until all fds are closed.
@ -121,7 +121,7 @@ enum ep0_state {
struct dev_data {
spinlock_t lock;
atomic_t count;
enum ep0_state state;
enum ep0_state state; /* P: lock */
struct usb_gadgetfs_event event [N_EVENT];
unsigned ev_next;
struct fasync_struct *fasync;
@ -188,7 +188,6 @@ static struct dev_data *dev_new (void)
enum ep_state {
STATE_EP_DISABLED = 0,
STATE_EP_READY,
STATE_EP_DEFER_ENABLE,
STATE_EP_ENABLED,
STATE_EP_UNBOUND,
};
@ -313,18 +312,10 @@ get_ready_ep (unsigned f_flags, struct ep_data *epdata)
if ((val = down_interruptible (&epdata->lock)) < 0)
return val;
newstate:
switch (epdata->state) {
case STATE_EP_ENABLED:
break;
case STATE_EP_DEFER_ENABLE:
DBG (epdata->dev, "%s wait for host\n", epdata->name);
if ((val = wait_event_interruptible (epdata->wait,
epdata->state != STATE_EP_DEFER_ENABLE
|| epdata->dev->state == STATE_DEV_UNBOUND
)) < 0)
goto fail;
goto newstate;
// case STATE_EP_DISABLED: /* "can't happen" */
// case STATE_EP_READY: /* "can't happen" */
default: /* error! */
@ -333,7 +324,6 @@ get_ready_ep (unsigned f_flags, struct ep_data *epdata)
// FALLTHROUGH
case STATE_EP_UNBOUND: /* clean disconnect */
val = -ENODEV;
fail:
up (&epdata->lock);
}
return val;
@ -565,29 +555,28 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
ssize_t len, total;
int i;
/* we "retry" to get the right mm context for this: */
/* we "retry" to get the right mm context for this: */
/* copy stuff into user buffers */
total = priv->actual;
len = 0;
for (i=0; i < priv->nr_segs; i++) {
ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
/* copy stuff into user buffers */
total = priv->actual;
len = 0;
for (i=0; i < priv->nr_segs; i++) {
ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
if (len == 0)
len = -EFAULT;
break;
}
if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
if (len == 0)
len = -EFAULT;
break;
}
total -= this;
len += this;
if (total == 0)
break;
}
kfree(priv->buf);
kfree(priv);
aio_put_req(iocb);
return len;
total -= this;
len += this;
if (total == 0)
break;
}
kfree(priv->buf);
kfree(priv);
return len;
}
static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
@ -600,18 +589,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
spin_lock(&epdata->dev->lock);
priv->req = NULL;
priv->epdata = NULL;
if (priv->iv == NULL
|| unlikely(req->actual == 0)
|| unlikely(kiocbIsCancelled(iocb))) {
/* if this was a write or a read returning no data then we
* don't need to copy anything to userspace, so we can
* complete the aio request immediately.
*/
if (priv->iv == NULL || unlikely(req->actual == 0)) {
kfree(req->buf);
kfree(priv);
iocb->private = NULL;
/* aio_complete() reports bytes-transferred _and_ faults */
if (unlikely(kiocbIsCancelled(iocb)))
aio_put_req(iocb);
else
aio_complete(iocb,
req->actual ? req->actual : req->status,
aio_complete(iocb, req->actual ? req->actual : req->status,
req->status);
} else {
/* retry() won't report both; so we hide some faults */
@ -636,7 +624,7 @@ ep_aio_rwtail(
size_t len,
struct ep_data *epdata,
const struct iovec *iv,
unsigned long nr_segs
unsigned long nr_segs
)
{
struct kiocb_priv *priv;
@ -852,9 +840,9 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
break;
#endif
default:
DBG (data->dev, "unconnected, %s init deferred\n",
DBG(data->dev, "unconnected, %s init abandoned\n",
data->name);
data->state = STATE_EP_DEFER_ENABLE;
value = -EINVAL;
}
if (value == 0) {
fd->f_op = &ep_io_operations;
@ -943,22 +931,24 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req)
static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
{
struct dev_data *dev = ep->driver_data;
unsigned long flags;
int free = 1;
/* for control OUT, data must still get to userspace */
spin_lock_irqsave(&dev->lock, flags);
if (!dev->setup_in) {
dev->setup_out_error = (req->status != 0);
if (!dev->setup_out_error)
free = 0;
dev->setup_out_ready = 1;
ep0_readable (dev);
} else if (dev->state == STATE_SETUP)
dev->state = STATE_CONNECTED;
}
/* clean up as appropriate */
if (free && req->buf != &dev->rbuf)
clean_req (ep, req);
req->complete = epio_complete;
spin_unlock_irqrestore(&dev->lock, flags);
}
static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
@ -998,13 +988,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
}
/* control DATA stage */
if ((state = dev->state) == STATE_SETUP) {
if ((state = dev->state) == STATE_DEV_SETUP) {
if (dev->setup_in) { /* stall IN */
VDEBUG(dev, "ep0in stall\n");
(void) usb_ep_set_halt (dev->gadget->ep0);
retval = -EL2HLT;
dev->state = STATE_CONNECTED;
dev->state = STATE_DEV_CONNECTED;
} else if (len == 0) { /* ack SET_CONFIGURATION etc */
struct usb_ep *ep = dev->gadget->ep0;
@ -1012,7 +1002,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
if ((retval = setup_req (ep, req, 0)) == 0)
retval = usb_ep_queue (ep, req, GFP_ATOMIC);
dev->state = STATE_CONNECTED;
dev->state = STATE_DEV_CONNECTED;
/* assume that was SET_CONFIGURATION */
if (dev->current_config) {
@ -1040,6 +1030,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
spin_lock_irq (&dev->lock);
if (retval)
goto done;
if (dev->state != STATE_DEV_SETUP) {
retval = -ECANCELED;
goto done;
}
dev->state = STATE_DEV_CONNECTED;
if (dev->setup_out_error)
retval = -EIO;
else {
@ -1066,39 +1063,36 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
/* return queued events right away */
if (dev->ev_next != 0) {
unsigned i, n;
int tmp = dev->ev_next;
len = min (len, tmp * sizeof (struct usb_gadgetfs_event));
n = len / sizeof (struct usb_gadgetfs_event);
if (dev->ev_next < n)
n = dev->ev_next;
/* ep0 can't deliver events when STATE_SETUP */
/* ep0 i/o has special semantics during STATE_DEV_SETUP */
for (i = 0; i < n; i++) {
if (dev->event [i].type == GADGETFS_SETUP) {
len = i + 1;
len *= sizeof (struct usb_gadgetfs_event);
n = 0;
dev->state = STATE_DEV_SETUP;
n = i + 1;
break;
}
}
spin_unlock_irq (&dev->lock);
len = n * sizeof (struct usb_gadgetfs_event);
if (copy_to_user (buf, &dev->event, len))
retval = -EFAULT;
else
retval = len;
if (len > 0) {
len /= sizeof (struct usb_gadgetfs_event);
/* NOTE this doesn't guard against broken drivers;
* concurrent ep0 readers may lose events.
*/
spin_lock_irq (&dev->lock);
dev->ev_next -= len;
if (dev->ev_next != 0)
memmove (&dev->event, &dev->event [len],
if (dev->ev_next > n) {
memmove(&dev->event[0], &dev->event[n],
sizeof (struct usb_gadgetfs_event)
* (tmp - len));
if (n == 0)
dev->state = STATE_SETUP;
* (dev->ev_next - n));
}
dev->ev_next -= n;
spin_unlock_irq (&dev->lock);
}
return retval;
@ -1113,8 +1107,8 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
DBG (dev, "fail %s, state %d\n", __FUNCTION__, state);
retval = -ESRCH;
break;
case STATE_UNCONNECTED:
case STATE_CONNECTED:
case STATE_DEV_UNCONNECTED:
case STATE_DEV_CONNECTED:
spin_unlock_irq (&dev->lock);
DBG (dev, "%s wait\n", __FUNCTION__);
@ -1141,7 +1135,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
switch (type) {
/* these events purge the queue */
case GADGETFS_DISCONNECT:
if (dev->state == STATE_SETUP)
if (dev->state == STATE_DEV_SETUP)
dev->setup_abort = 1;
// FALL THROUGH
case GADGETFS_CONNECT:
@ -1153,7 +1147,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
for (i = 0; i != dev->ev_next; i++) {
if (dev->event [i].type != type)
continue;
DBG (dev, "discard old event %d\n", type);
DBG(dev, "discard old event[%d] %d\n", i, type);
dev->ev_next--;
if (i == dev->ev_next)
break;
@ -1166,9 +1160,9 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
default:
BUG ();
}
VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type);
event = &dev->event [dev->ev_next++];
BUG_ON (dev->ev_next > N_EVENT);
VDEBUG (dev, "ev %d, next %d\n", type, dev->ev_next);
memset (event, 0, sizeof *event);
event->type = type;
return event;
@ -1188,12 +1182,13 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
retval = -EIDRM;
/* data and/or status stage for control request */
} else if (dev->state == STATE_SETUP) {
} else if (dev->state == STATE_DEV_SETUP) {
/* IN DATA+STATUS caller makes len <= wLength */
if (dev->setup_in) {
retval = setup_req (dev->gadget->ep0, dev->req, len);
if (retval == 0) {
dev->state = STATE_DEV_CONNECTED;
spin_unlock_irq (&dev->lock);
if (copy_from_user (dev->req->buf, buf, len))
retval = -EFAULT;
@ -1219,7 +1214,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
VDEBUG(dev, "ep0out stall\n");
(void) usb_ep_set_halt (dev->gadget->ep0);
retval = -EL2HLT;
dev->state = STATE_CONNECTED;
dev->state = STATE_DEV_CONNECTED;
} else {
DBG(dev, "bogus ep0out stall!\n");
}
@ -1261,7 +1256,9 @@ dev_release (struct inode *inode, struct file *fd)
put_dev (dev);
/* other endpoints were all decoupled from this device */
spin_lock_irq(&dev->lock);
dev->state = STATE_DEV_DISABLED;
spin_unlock_irq(&dev->lock);
return 0;
}
@ -1282,7 +1279,7 @@ ep0_poll (struct file *fd, poll_table *wait)
goto out;
}
if (dev->state == STATE_SETUP) {
if (dev->state == STATE_DEV_SETUP) {
if (dev->setup_in || dev->setup_can_stall)
mask = POLLOUT;
} else {
@ -1392,52 +1389,29 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
spin_lock (&dev->lock);
dev->setup_abort = 0;
if (dev->state == STATE_UNCONNECTED) {
struct usb_ep *ep;
struct ep_data *data;
dev->state = STATE_CONNECTED;
dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
if (dev->state == STATE_DEV_UNCONNECTED) {
#ifdef CONFIG_USB_GADGET_DUALSPEED
if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) {
spin_unlock(&dev->lock);
ERROR (dev, "no high speed config??\n");
return -EINVAL;
}
#endif /* CONFIG_USB_GADGET_DUALSPEED */
dev->state = STATE_DEV_CONNECTED;
dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
INFO (dev, "connected\n");
event = next_event (dev, GADGETFS_CONNECT);
event->u.speed = gadget->speed;
ep0_readable (dev);
list_for_each_entry (ep, &gadget->ep_list, ep_list) {
data = ep->driver_data;
/* ... down_trylock (&data->lock) ... */
if (data->state != STATE_EP_DEFER_ENABLE)
continue;
#ifdef CONFIG_USB_GADGET_DUALSPEED
if (gadget->speed == USB_SPEED_HIGH)
value = usb_ep_enable (ep, &data->hs_desc);
else
#endif /* CONFIG_USB_GADGET_DUALSPEED */
value = usb_ep_enable (ep, &data->desc);
if (value) {
ERROR (dev, "deferred %s enable --> %d\n",
data->name, value);
continue;
}
data->state = STATE_EP_ENABLED;
wake_up (&data->wait);
DBG (dev, "woke up %s waiters\n", data->name);
}
/* host may have given up waiting for response. we can miss control
* requests handled lower down (device/endpoint status and features);
* then ep0_{read,write} will report the wrong status. controller
* driver will have aborted pending i/o.
*/
} else if (dev->state == STATE_SETUP)
} else if (dev->state == STATE_DEV_SETUP)
dev->setup_abort = 1;
req->buf = dev->rbuf;
@ -1583,7 +1557,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
}
/* proceed with data transfer and status phases? */
if (value >= 0 && dev->state != STATE_SETUP) {
if (value >= 0 && dev->state != STATE_DEV_SETUP) {
req->length = value;
req->zero = value < w_length;
value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
@ -1747,7 +1721,9 @@ gadgetfs_bind (struct usb_gadget *gadget)
goto enomem;
INFO (dev, "bound to %s driver\n", gadget->name);
dev->state = STATE_UNCONNECTED;
spin_lock_irq(&dev->lock);
dev->state = STATE_DEV_UNCONNECTED;
spin_unlock_irq(&dev->lock);
get_dev (dev);
return 0;
@ -1762,11 +1738,9 @@ gadgetfs_disconnect (struct usb_gadget *gadget)
struct dev_data *dev = get_gadget_data (gadget);
spin_lock (&dev->lock);
if (dev->state == STATE_UNCONNECTED) {
DBG (dev, "already unconnected\n");
if (dev->state == STATE_DEV_UNCONNECTED)
goto exit;
}
dev->state = STATE_UNCONNECTED;
dev->state = STATE_DEV_UNCONNECTED;
INFO (dev, "disconnected\n");
next_event (dev, GADGETFS_DISCONNECT);
@ -1783,9 +1757,9 @@ gadgetfs_suspend (struct usb_gadget *gadget)
INFO (dev, "suspended from state %d\n", dev->state);
spin_lock (&dev->lock);
switch (dev->state) {
case STATE_SETUP: // VERY odd... host died??
case STATE_CONNECTED:
case STATE_UNCONNECTED:
case STATE_DEV_SETUP: // VERY odd... host died??
case STATE_DEV_CONNECTED:
case STATE_DEV_UNCONNECTED:
next_event (dev, GADGETFS_SUSPEND);
ep0_readable (dev);
/* FALLTHROUGH */
@ -1808,7 +1782,7 @@ static struct usb_gadget_driver gadgetfs_driver = {
.disconnect = gadgetfs_disconnect,
.suspend = gadgetfs_suspend,
.driver = {
.driver = {
.name = (char *) shortname,
},
};
@ -1829,7 +1803,7 @@ static struct usb_gadget_driver probe_driver = {
.unbind = gadgetfs_nop,
.setup = (void *)gadgetfs_nop,
.disconnect = gadgetfs_nop,
.driver = {
.driver = {
.name = "nop",
},
};
@ -1849,19 +1823,16 @@ static struct usb_gadget_driver probe_driver = {
* . full/low speed config ... all wTotalLength bytes (with interface,
* class, altsetting, endpoint, and other descriptors)
* . high speed config ... all descriptors, for high speed operation;
* this one's optional except for high-speed hardware
* this one's optional except for high-speed hardware
* . device descriptor
*
* Endpoints are not yet enabled. Drivers may want to immediately
* initialize them, using the /dev/gadget/ep* files that are available
* as soon as the kernel sees the configuration, or they can wait
* until device configuration and interface altsetting changes create
* Endpoints are not yet enabled. Drivers must wait until device
* configuration and interface altsetting changes create
* the need to configure (or unconfigure) them.
*
* After initialization, the device stays active for as long as that
* $CHIP file is open. Events may then be read from that descriptor,
* such as configuration notifications. More complex drivers will handle
* some control requests in user space.
* $CHIP file is open. Events must then be read from that descriptor,
* such as configuration notifications.
*/
static int is_valid_config (struct usb_config_descriptor *config)
@ -1884,9 +1855,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
u32 tag;
char *kbuf;
if (dev->state != STATE_OPENED)
return -EEXIST;
if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
return -EINVAL;
@ -1978,13 +1946,15 @@ dev_open (struct inode *inode, struct file *fd)
struct dev_data *dev = inode->i_private;
int value = -EBUSY;
spin_lock_irq(&dev->lock);
if (dev->state == STATE_DEV_DISABLED) {
dev->ev_next = 0;
dev->state = STATE_OPENED;
dev->state = STATE_DEV_OPENED;
fd->private_data = dev;
get_dev (dev);
value = 0;
}
spin_unlock_irq(&dev->lock);
return value;
}

View File

@ -49,7 +49,7 @@
#include <asm/unaligned.h>
#include <asm/hardware.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
/*

View File

@ -63,7 +63,7 @@
#include <linux/interrupt.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/byteorder.h>

View File

@ -38,7 +38,7 @@
#include <linux/mm.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>

View File

@ -56,7 +56,7 @@
#include <asm/arch/pxa-regs.h>
#endif
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/arch/udc.h>

View File

@ -43,7 +43,7 @@
#include <asm/unaligned.h>
#include <asm/uaccess.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
#include <linux/usb_gadget.h>

View File

@ -14,7 +14,7 @@
#include <linux/device.h>
#include <linux/init.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <asm/unaligned.h>

View File

@ -84,7 +84,7 @@
#include <asm/system.h>
#include <asm/unaligned.h>
#include <linux/usb_ch9.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include "gadget_chips.h"

View File

@ -67,6 +67,11 @@ config USB_EHCI_TT_NEWSCHED
If unsure, say N.
config USB_EHCI_BIG_ENDIAN_MMIO
bool
depends on USB_EHCI_HCD
default n
config USB_ISP116X_HCD
tristate "ISP116X HCD support"
depends on USB
@ -101,21 +106,48 @@ config USB_OHCI_HCD_PPC_SOC
bool "OHCI support for on-chip PPC USB controller"
depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
default y
select USB_OHCI_BIG_ENDIAN
select USB_OHCI_BIG_ENDIAN_DESC
select USB_OHCI_BIG_ENDIAN_MMIO
---help---
Enables support for the USB controller on the MPC52xx or
STB03xxx processor chip. If unsure, say Y.
config USB_OHCI_HCD_PPC_OF
bool "OHCI support for PPC USB controller on OF platform bus"
depends on USB_OHCI_HCD && PPC_OF
default y
---help---
Enables support for the USB controller PowerPC present on the
OpenFirmware platform bus.
config USB_OHCI_HCD_PPC_OF_BE
bool "Support big endian HC"
depends on USB_OHCI_HCD_PPC_OF
default y
select USB_OHCI_BIG_ENDIAN_DESC
select USB_OHCI_BIG_ENDIAN_MMIO
config USB_OHCI_HCD_PPC_OF_LE
bool "Support little endian HC"
depends on USB_OHCI_HCD_PPC_OF
default n
select USB_OHCI_LITTLE_ENDIAN
config USB_OHCI_HCD_PCI
bool "OHCI support for PCI-bus USB controllers"
depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
default y
select USB_OHCI_LITTLE_ENDIAN
---help---
Enables support for PCI-bus plug-in USB controller cards.
If unsure, say Y.
config USB_OHCI_BIG_ENDIAN
config USB_OHCI_BIG_ENDIAN_DESC
bool
depends on USB_OHCI_HCD
default n
config USB_OHCI_BIG_ENDIAN_MMIO
bool
depends on USB_OHCI_HCD
default n

View File

@ -43,7 +43,7 @@
*/
static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
{
u32 params = readl (&ehci->caps->hcs_params);
u32 params = ehci_readl(ehci, &ehci->caps->hcs_params);
ehci_dbg (ehci,
"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
@ -87,7 +87,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
* */
static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
{
u32 params = readl (&ehci->caps->hcc_params);
u32 params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_ISOC_CACHE (params)) {
ehci_dbg (ehci,
@ -653,7 +653,7 @@ show_registers (struct class_device *class_dev, char *buf)
}
/* Capability Registers */
i = HC_VERSION(readl (&ehci->caps->hc_capbase));
i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
temp = scnprintf (next, size,
"bus %s, device %s (driver " DRIVER_VERSION ")\n"
"%s\n"
@ -673,7 +673,7 @@ 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 (readl (&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) {
@ -704,50 +704,50 @@ show_registers (struct class_device *class_dev, char *buf)
#endif
// FIXME interpret both types of params
i = readl (&ehci->caps->hcs_params);
i = ehci_readl(ehci, &ehci->caps->hcs_params);
temp = scnprintf (next, size, "structural params 0x%08x\n", i);
size -= temp;
next += temp;
i = readl (&ehci->caps->hcc_params);
i = ehci_readl(ehci, &ehci->caps->hcc_params);
temp = scnprintf (next, size, "capability params 0x%08x\n", i);
size -= temp;
next += temp;
/* Operational Registers */
temp = dbg_status_buf (scratch, sizeof scratch, label,
readl (&ehci->regs->status));
ehci_readl(ehci, &ehci->regs->status));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
temp = dbg_command_buf (scratch, sizeof scratch, label,
readl (&ehci->regs->command));
ehci_readl(ehci, &ehci->regs->command));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
temp = dbg_intr_buf (scratch, sizeof scratch, label,
readl (&ehci->regs->intr_enable));
ehci_readl(ehci, &ehci->regs->intr_enable));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
temp = scnprintf (next, size, "uframe %04x\n",
readl (&ehci->regs->frame_index));
ehci_readl(ehci, &ehci->regs->frame_index));
size -= temp;
next += temp;
for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
temp = dbg_port_buf (scratch, sizeof scratch, label, i,
readl (&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",
readl (&ehci->debug->control));
ehci_readl(ehci, &ehci->debug->control));
size -= temp;
next += temp;
}

View File

@ -177,7 +177,7 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
case FSL_USB2_PHY_NONE:
break;
}
writel(portsc, &ehci->regs->port_status[port_offset]);
ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
}
static void mpc83xx_usb_setup(struct usb_hcd *hcd)
@ -214,7 +214,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
}
/* put controller in host mode. */
writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
@ -238,12 +238,12 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
/* EHCI registers start at offset 0x100 */
ehci->caps = hcd->regs + 0x100;
ehci->regs = hcd->regs + 0x100 +
HC_LENGTH(readl(&ehci->caps->hc_capbase));
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = readl(&ehci->caps->hcs_params);
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
retval = ehci_halt(ehci);
if (retval)

View File

@ -157,12 +157,13 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
* before driver shutdown. But it also seems to be caused by bugs in cardbus
* bridge shutdown: shutting down the bridge before the devices using it.
*/
static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
u32 mask, u32 done, int usec)
{
u32 result;
do {
result = readl (ptr);
result = ehci_readl(ehci, ptr);
if (result == ~(u32)0) /* card removed */
return -ENODEV;
result &= mask;
@ -177,18 +178,19 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
/* force HC to halt state from unknown (EHCI spec section 2.3) */
static int ehci_halt (struct ehci_hcd *ehci)
{
u32 temp = readl (&ehci->regs->status);
u32 temp = ehci_readl(ehci, &ehci->regs->status);
/* disable any irqs left enabled by previous code */
writel (0, &ehci->regs->intr_enable);
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
if ((temp & STS_HALT) != 0)
return 0;
temp = readl (&ehci->regs->command);
temp = ehci_readl(ehci, &ehci->regs->command);
temp &= ~CMD_RUN;
writel (temp, &ehci->regs->command);
return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
ehci_writel(ehci, temp, &ehci->regs->command);
return handshake (ehci, &ehci->regs->status,
STS_HALT, STS_HALT, 16 * 125);
}
/* put TDI/ARC silicon into EHCI mode */
@ -198,23 +200,24 @@ static void tdi_reset (struct ehci_hcd *ehci)
u32 tmp;
reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
tmp = readl (reg_ptr);
tmp = ehci_readl(ehci, reg_ptr);
tmp |= 0x3;
writel (tmp, reg_ptr);
ehci_writel(ehci, tmp, reg_ptr);
}
/* reset a non-running (STS_HALT == 1) controller */
static int ehci_reset (struct ehci_hcd *ehci)
{
int retval;
u32 command = readl (&ehci->regs->command);
u32 command = ehci_readl(ehci, &ehci->regs->command);
command |= CMD_RESET;
dbg_cmd (ehci, "reset", command);
writel (command, &ehci->regs->command);
ehci_writel(ehci, command, &ehci->regs->command);
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
ehci->next_statechange = jiffies;
retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
retval = handshake (ehci, &ehci->regs->command,
CMD_RESET, 0, 250 * 1000);
if (retval)
return retval;
@ -236,21 +239,21 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
#endif
/* wait for any schedule enables/disables to take effect */
temp = readl (&ehci->regs->command) << 10;
temp = ehci_readl(ehci, &ehci->regs->command) << 10;
temp &= STS_ASS | STS_PSS;
if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
temp, 16 * 125) != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return;
}
/* then disable anything that's still active */
temp = readl (&ehci->regs->command);
temp = ehci_readl(ehci, &ehci->regs->command);
temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
writel (temp, &ehci->regs->command);
ehci_writel(ehci, temp, &ehci->regs->command);
/* hardware can take 16 microframes to turn off ... */
if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
0, 16 * 125) != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return;
@ -277,11 +280,11 @@ static void ehci_watchdog (unsigned long param)
/* lost IAA irqs wedge things badly; seen with a vt8235 */
if (ehci->reclaim) {
u32 status = readl (&ehci->regs->status);
u32 status = ehci_readl(ehci, &ehci->regs->status);
if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa);
writel (STS_IAA, &ehci->regs->status);
ehci_writel(ehci, STS_IAA, &ehci->regs->status);
ehci->reclaim_ready = 1;
}
}
@ -309,7 +312,7 @@ ehci_shutdown (struct usb_hcd *hcd)
(void) ehci_halt (ehci);
/* make BIOS/etc use companion controller during reboot */
writel (0, &ehci->regs->configured_flag);
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
}
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@ -379,12 +382,13 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci_quiesce (ehci);
ehci_reset (ehci);
writel (0, &ehci->regs->intr_enable);
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
spin_unlock_irq(&ehci->lock);
/* let companion controllers work when we aren't */
writel (0, &ehci->regs->configured_flag);
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
remove_companion_file(ehci);
remove_debug_files (ehci);
/* root hub is shut down separately (first, when possible) */
@ -402,7 +406,8 @@ static void ehci_stop (struct usb_hcd *hcd)
ehci->stats.complete, ehci->stats.unlink);
#endif
dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
dbg_status (ehci, "ehci_stop completed",
ehci_readl(ehci, &ehci->regs->status));
}
/* one-time init, only for memory state */
@ -428,7 +433,7 @@ static int ehci_init(struct usb_hcd *hcd)
return retval;
/* controllers may cache some of the periodic schedule ... */
hcc_params = readl(&ehci->caps->hcc_params);
hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_ISOC_CACHE(hcc_params)) // full frame cache
ehci->i_thresh = 8;
else // N microframes cached
@ -496,13 +501,16 @@ static int ehci_run (struct usb_hcd *hcd)
u32 temp;
u32 hcc_params;
hcd->uses_new_polling = 1;
hcd->poll_rh = 0;
/* EHCI spec section 4.1 */
if ((retval = ehci_reset(ehci)) != 0) {
ehci_mem_cleanup(ehci);
return retval;
}
writel(ehci->periodic_dma, &ehci->regs->frame_list);
writel((u32)ehci->async->qh_dma, &ehci->regs->async_next);
ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
/*
* hcc_params controls whether ehci->regs->segment must (!!!)
@ -516,9 +524,9 @@ static int ehci_run (struct usb_hcd *hcd)
* Scsi_Host.highmem_io, and so forth. It's readonly to all
* host side drivers though.
*/
hcc_params = readl(&ehci->caps->hcc_params);
hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
if (HCC_64BIT_ADDR(hcc_params)) {
writel(0, &ehci->regs->segment);
ehci_writel(ehci, 0, &ehci->regs->segment);
#if 0
// this is deeply broken on almost all architectures
if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK))
@ -531,7 +539,7 @@ static int ehci_run (struct usb_hcd *hcd)
// root hub will detect new devices (why?); NEC doesn't
ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
ehci->command |= CMD_RUN;
writel (ehci->command, &ehci->regs->command);
ehci_writel(ehci, ehci->command, &ehci->regs->command);
dbg_cmd (ehci, "init", ehci->command);
/*
@ -541,23 +549,25 @@ static int ehci_run (struct usb_hcd *hcd)
* and there's no companion controller unless maybe for USB OTG.)
*/
hcd->state = HC_STATE_RUNNING;
writel (FLAG_CF, &ehci->regs->configured_flag);
readl (&ehci->regs->command); /* unblock posted writes */
ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
ehci_info (ehci,
"USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
temp >> 8, temp & 0xff, DRIVER_VERSION,
ignore_oc ? ", overcurrent ignored" : "");
writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
ehci_writel(ehci, INTR_MASK,
&ehci->regs->intr_enable); /* Turn On Interrupts */
/* GRR this is run-once init(), being done every time the HC starts.
* So long as they're part of class devices, we can't do it init()
* since the class device isn't created that early.
*/
create_debug_files(ehci);
create_companion_file(ehci);
return 0;
}
@ -567,12 +577,12 @@ static int ehci_run (struct usb_hcd *hcd)
static irqreturn_t ehci_irq (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 status;
u32 status, pcd_status = 0;
int bh;
spin_lock (&ehci->lock);
status = readl (&ehci->regs->status);
status = ehci_readl(ehci, &ehci->regs->status);
/* e.g. cardbus physical eject */
if (status == ~(u32) 0) {
@ -587,8 +597,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
}
/* clear (just) interrupts */
writel (status, &ehci->regs->status);
readl (&ehci->regs->command); /* unblock posted write */
ehci_writel(ehci, status, &ehci->regs->status);
ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
bh = 0;
#ifdef EHCI_VERBOSE_DEBUG
@ -617,13 +627,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* remote wakeup [4.3.1] */
if (status & STS_PCD) {
unsigned i = HCS_N_PORTS (ehci->hcs_params);
pcd_status = status;
/* resume root hub? */
if (!(readl(&ehci->regs->command) & CMD_RUN))
if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN))
usb_hcd_resume_root_hub(hcd);
while (i--) {
int pstatus = readl (&ehci->regs->port_status [i]);
int pstatus = ehci_readl(ehci,
&ehci->regs->port_status [i]);
if (pstatus & PORT_OWNER)
continue;
@ -643,14 +655,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
/* PCI errors [4.15.2.4] */
if (unlikely ((status & STS_FATAL) != 0)) {
/* bogus "fatal" IRQs appear on some chips... why? */
status = readl (&ehci->regs->status);
dbg_cmd (ehci, "fatal", readl (&ehci->regs->command));
status = ehci_readl(ehci, &ehci->regs->status);
dbg_cmd (ehci, "fatal", ehci_readl(ehci,
&ehci->regs->command));
dbg_status (ehci, "fatal", status);
if (status & STS_HALT) {
ehci_err (ehci, "fatal error\n");
dead:
ehci_reset (ehci);
writel (0, &ehci->regs->configured_flag);
ehci_writel(ehci, 0, &ehci->regs->configured_flag);
/* generic layer kills/unlinks all urbs, then
* uses ehci_stop to clean up the rest
*/
@ -661,6 +674,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
if (bh)
ehci_work (ehci);
spin_unlock (&ehci->lock);
if (pcd_status & STS_PCD)
usb_hcd_poll_rh_status(hcd);
return IRQ_HANDLED;
}
@ -873,7 +888,8 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
static int ehci_get_frame (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
ehci->periodic_size;
}
/*-------------------------------------------------------------------------*/
@ -899,7 +915,13 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_hcd_au1xxx_driver
#endif
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
#ifdef CONFIG_PPC_PS3
#include "ehci-ps3.c"
#define PS3_SYSTEM_BUS_DRIVER ps3_ehci_sb_driver
#endif
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER)
#error "missing bus glue for ehci-hcd"
#endif
@ -924,6 +946,20 @@ static int __init ehci_hcd_init(void)
#ifdef PLATFORM_DRIVER
platform_driver_unregister(&PLATFORM_DRIVER);
#endif
return retval;
}
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
if (retval < 0) {
#ifdef PLATFORM_DRIVER
platform_driver_unregister(&PLATFORM_DRIVER);
#endif
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
#endif
return retval;
}
#endif
@ -939,6 +975,9 @@ static void __exit ehci_hcd_cleanup(void)
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
#endif
}
module_exit(ehci_hcd_cleanup);

View File

@ -47,7 +47,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci_quiesce (ehci);
hcd->state = HC_STATE_QUIESCING;
}
ehci->command = readl (&ehci->regs->command);
ehci->command = ehci_readl(ehci, &ehci->regs->command);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
ehci_work(ehci);
@ -60,7 +60,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci->bus_suspended = 0;
while (port--) {
u32 __iomem *reg = &ehci->regs->port_status [port];
u32 t1 = readl (reg) & ~PORT_RWC_BITS;
u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
u32 t2 = t1;
/* keep track of which ports we suspend */
@ -79,7 +79,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
if (t1 != t2) {
ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
port + 1, t1, t2);
writel (t2, reg);
ehci_writel(ehci, t2, reg);
}
}
@ -92,8 +92,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
mask = INTR_MASK;
if (!device_may_wakeup(&hcd->self.root_hub->dev))
mask &= ~STS_PCD;
writel(mask, &ehci->regs->intr_enable);
readl(&ehci->regs->intr_enable);
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
ehci_readl(ehci, &ehci->regs->intr_enable);
ehci->next_statechange = jiffies + msecs_to_jiffies(10);
spin_unlock_irq (&ehci->lock);
@ -118,26 +118,26 @@ 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 = readl(&ehci->regs->intr_enable);
temp = ehci_readl(ehci, &ehci->regs->intr_enable);
ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
/* at least some APM implementations will try to deliver
* IRQs right away, so delay them until we're ready.
*/
writel(0, &ehci->regs->intr_enable);
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
/* re-init operational registers */
writel(0, &ehci->regs->segment);
writel(ehci->periodic_dma, &ehci->regs->frame_list);
writel((u32) ehci->async->qh_dma, &ehci->regs->async_next);
ehci_writel(ehci, 0, &ehci->regs->segment);
ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
/* restore CMD_RUN, framelist size, and irq threshold */
writel (ehci->command, &ehci->regs->command);
ehci_writel(ehci, ehci->command, &ehci->regs->command);
/* manually resume the ports we suspended during bus_suspend() */
i = HCS_N_PORTS (ehci->hcs_params);
while (i--) {
temp = readl (&ehci->regs->port_status [i]);
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
temp &= ~(PORT_RWC_BITS
| PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
if (test_bit(i, &ehci->bus_suspended) &&
@ -145,20 +145,20 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
temp |= PORT_RESUME;
}
writel (temp, &ehci->regs->port_status [i]);
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
}
i = HCS_N_PORTS (ehci->hcs_params);
mdelay (20);
while (i--) {
temp = readl (&ehci->regs->port_status [i]);
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
if (test_bit(i, &ehci->bus_suspended) &&
(temp & PORT_SUSPEND)) {
temp &= ~(PORT_RWC_BITS | PORT_RESUME);
writel (temp, &ehci->regs->port_status [i]);
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
}
}
(void) readl (&ehci->regs->command);
(void) ehci_readl(ehci, &ehci->regs->command);
/* maybe re-activate the schedule(s) */
temp = 0;
@ -168,14 +168,14 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
temp |= CMD_PSE;
if (temp) {
ehci->command |= temp;
writel (ehci->command, &ehci->regs->command);
ehci_writel(ehci, ehci->command, &ehci->regs->command);
}
ehci->next_statechange = jiffies + msecs_to_jiffies(5);
hcd->state = HC_STATE_RUNNING;
/* Now we can safely re-enable irqs */
writel(INTR_MASK, &ehci->regs->intr_enable);
ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
spin_unlock_irq (&ehci->lock);
return 0;
@ -188,11 +188,109 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
#endif /* CONFIG_PM */
/*-------------------------------------------------------------------------*/
/* Display the ports dedicated to the companion controller */
static ssize_t show_companion(struct class_device *class_dev, char *buf)
{
struct ehci_hcd *ehci;
int nports, index, n;
int count = PAGE_SIZE;
char *ptr = buf;
ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
nports = HCS_N_PORTS(ehci->hcs_params);
for (index = 0; index < nports; ++index) {
if (test_bit(index, &ehci->companion_ports)) {
n = scnprintf(ptr, count, "%d\n", index + 1);
ptr += n;
count -= n;
}
}
return ptr - buf;
}
/*
* Dedicate or undedicate a port to the companion controller.
* Syntax is "[-]portnum", where a leading '-' sign means
* return control of the port to the EHCI controller.
*/
static ssize_t store_companion(struct class_device *class_dev,
const char *buf, size_t count)
{
struct ehci_hcd *ehci;
int portnum, new_owner, try;
u32 __iomem *status_reg;
u32 port_status;
ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
new_owner = PORT_OWNER; /* Owned by companion */
if (sscanf(buf, "%d", &portnum) != 1)
return -EINVAL;
if (portnum < 0) {
portnum = - portnum;
new_owner = 0; /* Owned by EHCI */
}
if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
return -ENOENT;
status_reg = &ehci->regs->port_status[--portnum];
if (new_owner)
set_bit(portnum, &ehci->companion_ports);
else
clear_bit(portnum, &ehci->companion_ports);
/*
* The controller won't set the OWNER bit if the port is
* enabled, so this loop will sometimes require at least two
* iterations: one to disable the port and one to set OWNER.
*/
for (try = 4; try > 0; --try) {
spin_lock_irq(&ehci->lock);
port_status = ehci_readl(ehci, status_reg);
if ((port_status & PORT_OWNER) == new_owner
|| (port_status & (PORT_OWNER | PORT_CONNECT))
== 0)
try = 0;
else {
port_status ^= PORT_OWNER;
port_status &= ~(PORT_PE | PORT_RWC_BITS);
ehci_writel(ehci, port_status, status_reg);
}
spin_unlock_irq(&ehci->lock);
if (try > 1)
msleep(5);
}
return count;
}
static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
static inline void create_companion_file(struct ehci_hcd *ehci)
{
int i;
/* with integrated TT there is no companion! */
if (!ehci_is_TDI(ehci))
i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev,
&class_device_attr_companion);
}
static inline void remove_companion_file(struct ehci_hcd *ehci)
{
/* with integrated TT there is no companion! */
if (!ehci_is_TDI(ehci))
class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev,
&class_device_attr_companion);
}
/*-------------------------------------------------------------------------*/
static int check_reset_complete (
struct ehci_hcd *ehci,
int index,
u32 __iomem *status_reg,
int port_status
) {
if (!(port_status & PORT_CONNECT)) {
@ -217,7 +315,7 @@ static int check_reset_complete (
// what happens if HCS_N_CC(params) == 0 ?
port_status |= PORT_OWNER;
port_status &= ~PORT_RWC_BITS;
writel (port_status, &ehci->regs->port_status [index]);
ehci_writel(ehci, port_status, status_reg);
} else
ehci_dbg (ehci, "port %d high speed\n", index + 1);
@ -268,22 +366,21 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
/* port N changes (bit N)? */
spin_lock_irqsave (&ehci->lock, flags);
for (i = 0; i < ports; i++) {
temp = readl (&ehci->regs->port_status [i]);
if (temp & PORT_OWNER) {
/* don't report this in GetPortStatus */
if (temp & PORT_CSC) {
temp &= ~PORT_RWC_BITS;
temp |= PORT_CSC;
writel (temp, &ehci->regs->port_status [i]);
}
continue;
}
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
/*
* Return status information even for ports with OWNER set.
* Otherwise khubd wouldn't see the disconnect event when a
* high-speed device is switched over to the companion
* controller by the user.
*/
if (!(temp & PORT_CONNECT))
ehci->reset_done [i] = 0;
if ((temp & mask) != 0
|| ((temp & PORT_RESUME) != 0
&& time_after (jiffies,
ehci->reset_done [i]))) {
&& time_after_eq(jiffies,
ehci->reset_done[i]))) {
if (i < 7)
buf [0] |= 1 << (i + 1);
else
@ -345,6 +442,7 @@ 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 temp, status;
unsigned long flags;
int retval = 0;
@ -373,18 +471,22 @@ static int ehci_hub_control (
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
temp = readl (&ehci->regs->port_status [wIndex]);
if (temp & PORT_OWNER)
break;
temp = ehci_readl(ehci, status_reg);
/*
* Even if OWNER is set, so the port is owned by the
* companion controller, khubd needs to be able to clear
* the port-change status bits (especially
* USB_PORT_FEAT_C_CONNECTION).
*/
switch (wValue) {
case USB_PORT_FEAT_ENABLE:
writel (temp & ~PORT_PE,
&ehci->regs->port_status [wIndex]);
ehci_writel(ehci, temp & ~PORT_PE, status_reg);
break;
case USB_PORT_FEAT_C_ENABLE:
writel((temp & ~PORT_RWC_BITS) | PORT_PEC,
&ehci->regs->port_status [wIndex]);
ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
status_reg);
break;
case USB_PORT_FEAT_SUSPEND:
if (temp & PORT_RESET)
@ -396,8 +498,8 @@ static int ehci_hub_control (
goto error;
/* resume signaling for 20 msec */
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
writel (temp | PORT_RESUME,
&ehci->regs->port_status [wIndex]);
ehci_writel(ehci, temp | PORT_RESUME,
status_reg);
ehci->reset_done [wIndex] = jiffies
+ msecs_to_jiffies (20);
}
@ -407,16 +509,17 @@ static int ehci_hub_control (
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params))
writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
&ehci->regs->port_status [wIndex]);
ehci_writel(ehci,
temp & ~(PORT_RWC_BITS | PORT_POWER),
status_reg);
break;
case USB_PORT_FEAT_C_CONNECTION:
writel((temp & ~PORT_RWC_BITS) | PORT_CSC,
&ehci->regs->port_status [wIndex]);
ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
status_reg);
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
writel((temp & ~PORT_RWC_BITS) | PORT_OCC,
&ehci->regs->port_status [wIndex]);
ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
status_reg);
break;
case USB_PORT_FEAT_C_RESET:
/* GetPortStatus clears reset */
@ -424,7 +527,7 @@ static int ehci_hub_control (
default:
goto error;
}
readl (&ehci->regs->command); /* unblock posted write */
ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
break;
case GetHubDescriptor:
ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
@ -440,7 +543,7 @@ static int ehci_hub_control (
goto error;
wIndex--;
status = 0;
temp = readl (&ehci->regs->port_status [wIndex]);
temp = ehci_readl(ehci, status_reg);
// wPortChange bits
if (temp & PORT_CSC)
@ -451,42 +554,55 @@ static int ehci_hub_control (
status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
/* whoever resumes must GetPortStatus to complete it!! */
if ((temp & PORT_RESUME)
&& time_after (jiffies,
ehci->reset_done [wIndex])) {
status |= 1 << USB_PORT_FEAT_C_SUSPEND;
ehci->reset_done [wIndex] = 0;
if (temp & PORT_RESUME) {
/* stop resume signaling */
temp = readl (&ehci->regs->port_status [wIndex]);
writel (temp & ~(PORT_RWC_BITS | PORT_RESUME),
&ehci->regs->port_status [wIndex]);
retval = handshake (
&ehci->regs->port_status [wIndex],
PORT_RESUME, 0, 2000 /* 2msec */);
if (retval != 0) {
ehci_err (ehci, "port %d resume error %d\n",
wIndex + 1, retval);
goto error;
/* Remote Wakeup received? */
if (!ehci->reset_done[wIndex]) {
/* resume signaling for 20 msec */
ehci->reset_done[wIndex] = jiffies
+ msecs_to_jiffies(20);
/* check the port again */
mod_timer(&ehci_to_hcd(ehci)->rh_timer,
ehci->reset_done[wIndex]);
}
/* resume completed? */
else if (time_after_eq(jiffies,
ehci->reset_done[wIndex])) {
status |= 1 << USB_PORT_FEAT_C_SUSPEND;
ehci->reset_done[wIndex] = 0;
/* stop resume signaling */
temp = ehci_readl(ehci, status_reg);
ehci_writel(ehci,
temp & ~(PORT_RWC_BITS | PORT_RESUME),
status_reg);
retval = handshake(ehci, status_reg,
PORT_RESUME, 0, 2000 /* 2msec */);
if (retval != 0) {
ehci_err(ehci,
"port %d resume error %d\n",
wIndex + 1, retval);
goto error;
}
temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
}
temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
}
/* whoever resets must GetPortStatus to complete it!! */
if ((temp & PORT_RESET)
&& time_after (jiffies,
ehci->reset_done [wIndex])) {
&& time_after_eq(jiffies,
ehci->reset_done[wIndex])) {
status |= 1 << USB_PORT_FEAT_C_RESET;
ehci->reset_done [wIndex] = 0;
/* force reset to complete */
writel (temp & ~(PORT_RWC_BITS | PORT_RESET),
&ehci->regs->port_status [wIndex]);
ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
status_reg);
/* REVISIT: some hardware needs 550+ usec to clear
* this bit; seems too long to spin routinely...
*/
retval = handshake (
&ehci->regs->port_status [wIndex],
retval = handshake(ehci, status_reg,
PORT_RESET, 0, 750);
if (retval != 0) {
ehci_err (ehci, "port %d reset error %d\n",
@ -495,29 +611,42 @@ static int ehci_hub_control (
}
/* see what we found out */
temp = check_reset_complete (ehci, wIndex,
readl (&ehci->regs->port_status [wIndex]));
temp = check_reset_complete (ehci, wIndex, status_reg,
ehci_readl(ehci, status_reg));
}
// don't show wPortStatus if it's owned by a companion hc
if (!(temp & PORT_OWNER)) {
if (temp & PORT_CONNECT) {
status |= 1 << USB_PORT_FEAT_CONNECTION;
// status may be from integrated TT
status |= ehci_port_speed(ehci, temp);
}
if (temp & PORT_PE)
status |= 1 << USB_PORT_FEAT_ENABLE;
if (temp & (PORT_SUSPEND|PORT_RESUME))
status |= 1 << USB_PORT_FEAT_SUSPEND;
if (temp & PORT_OC)
status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
if (temp & PORT_RESET)
status |= 1 << USB_PORT_FEAT_RESET;
if (temp & PORT_POWER)
status |= 1 << USB_PORT_FEAT_POWER;
/* transfer dedicated ports to the companion hc */
if ((temp & PORT_CONNECT) &&
test_bit(wIndex, &ehci->companion_ports)) {
temp &= ~PORT_RWC_BITS;
temp |= PORT_OWNER;
ehci_writel(ehci, temp, status_reg);
ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1);
temp = ehci_readl(ehci, status_reg);
}
/*
* Even if OWNER is set, there's no harm letting khubd
* see the wPortStatus values (they should all be 0 except
* for PORT_POWER anyway).
*/
if (temp & PORT_CONNECT) {
status |= 1 << USB_PORT_FEAT_CONNECTION;
// status may be from integrated TT
status |= ehci_port_speed(ehci, temp);
}
if (temp & PORT_PE)
status |= 1 << USB_PORT_FEAT_ENABLE;
if (temp & (PORT_SUSPEND|PORT_RESUME))
status |= 1 << USB_PORT_FEAT_SUSPEND;
if (temp & PORT_OC)
status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
if (temp & PORT_RESET)
status |= 1 << USB_PORT_FEAT_RESET;
if (temp & PORT_POWER)
status |= 1 << USB_PORT_FEAT_POWER;
#ifndef EHCI_VERBOSE_DEBUG
if (status & ~0xffff) /* only if wPortChange is interesting */
#endif
@ -541,7 +670,7 @@ static int ehci_hub_control (
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
temp = readl (&ehci->regs->port_status [wIndex]);
temp = ehci_readl(ehci, status_reg);
if (temp & PORT_OWNER)
break;
@ -555,13 +684,12 @@ static int ehci_hub_control (
goto error;
if (device_may_wakeup(&hcd->self.root_hub->dev))
temp |= PORT_WAKE_BITS;
writel (temp | PORT_SUSPEND,
&ehci->regs->port_status [wIndex]);
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params))
writel (temp | PORT_POWER,
&ehci->regs->port_status [wIndex]);
ehci_writel(ehci, temp | PORT_POWER,
status_reg);
break;
case USB_PORT_FEAT_RESET:
if (temp & PORT_RESUME)
@ -589,7 +717,7 @@ static int ehci_hub_control (
ehci->reset_done [wIndex] = jiffies
+ msecs_to_jiffies (50);
}
writel (temp, &ehci->regs->port_status [wIndex]);
ehci_writel(ehci, temp, status_reg);
break;
/* For downstream facing ports (these): one hub port is put
@ -604,13 +732,13 @@ static int ehci_hub_control (
ehci_quiesce(ehci);
ehci_halt(ehci);
temp |= selector << 16;
writel (temp, &ehci->regs->port_status [wIndex]);
ehci_writel(ehci, temp, status_reg);
break;
default:
goto error;
}
readl (&ehci->regs->command); /* unblock posted writes */
ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
break;
default:

View File

@ -38,7 +38,7 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
if ((temp & (3 << 13)) == (1 << 13)) {
temp &= 0x1fff;
ehci->debug = ehci_to_hcd(ehci)->regs + temp;
temp = readl(&ehci->debug->control);
temp = ehci_readl(ehci, &ehci->debug->control);
ehci_info(ehci, "debug port %d%s\n",
HCS_DEBUG_PORT(ehci->hcs_params),
(temp & DBGP_ENABLED)
@ -71,8 +71,24 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
u32 temp;
int retval;
switch (pdev->vendor) {
case PCI_VENDOR_ID_TOSHIBA_2:
/* celleb's companion chip */
if (pdev->device == 0x01b5) {
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
ehci->big_endian_mmio = 1;
#else
ehci_warn(ehci,
"unsupported big endian Toshiba quirk\n");
#endif
}
break;
}
ehci->caps = hcd->regs;
ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
ehci->regs = hcd->regs +
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
@ -101,7 +117,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
}
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = readl(&ehci->caps->hcs_params);
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
retval = ehci_halt(ehci);
if (retval)
@ -235,8 +251,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
rc = -EINVAL;
goto bail;
}
writel (0, &ehci->regs->intr_enable);
(void)readl(&ehci->regs->intr_enable);
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
/* make sure snapshot being resumed re-enumerates everything */
if (message.event == PM_EVENT_PRETHAW) {
@ -270,13 +286,13 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* If CF is still set, we maintained PCI Vaux power.
* Just undo the effect of ehci_pci_suspend().
*/
if (readl(&ehci->regs->configured_flag) == FLAG_CF) {
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
int mask = INTR_MASK;
if (!device_may_wakeup(&hcd->self.root_hub->dev))
mask &= ~STS_PCD;
writel(mask, &ehci->regs->intr_enable);
readl(&ehci->regs->intr_enable);
ehci_writel(ehci, mask, &ehci->regs->intr_enable);
ehci_readl(ehci, &ehci->regs->intr_enable);
return 0;
}
@ -300,9 +316,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* here we "know" root ports should always stay powered */
ehci_port_power(ehci, 1);
writel(ehci->command, &ehci->regs->command);
writel(FLAG_CF, &ehci->regs->configured_flag);
readl(&ehci->regs->command); /* unblock posted writes */
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 */
hcd->state = HC_STATE_SUSPENDED;
return 0;

193
drivers/usb/host/ehci-ps3.c Normal file
View File

@ -0,0 +1,193 @@
/*
* PS3 EHCI Host Controller driver
*
* Copyright (C) 2006 Sony Computer Entertainment Inc.
* Copyright 2006 Sony Corp.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/ps3.h>
static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
{
int result;
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
ehci->big_endian_mmio = 1;
ehci->caps = hcd->regs;
ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
&ehci->caps->hc_capbase));
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
result = ehci_halt(ehci);
if (result)
return result;
result = ehci_init(hcd);
if (result)
return result;
ehci_port_power(ehci, 0);
return result;
}
static const struct hc_driver ps3_ehci_hc_driver = {
.description = hcd_name,
.product_desc = "PS3 EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
.irq = ehci_irq,
.flags = HCD_MEMORY | HCD_USB2,
.reset = ps3_ehci_hc_reset,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.get_frame_number = ehci_get_frame,
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
#if defined(CONFIG_PM)
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
#endif
};
#if !defined(DEBUG)
#undef dev_dbg
static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
const struct device *_dev, const char *fmt, ...) {return 0;}
#endif
static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
{
int result;
struct usb_hcd *hcd;
unsigned int virq;
static u64 dummy_mask = DMA_32BIT_MASK;
if (usb_disabled()) {
result = -ENODEV;
goto fail_start;
}
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;
}
dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
__LINE__, dev->m_region->lpar_addr);
result = ps3_alloc_io_irq(dev->interrupt_id, &virq);
if (result) {
dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
__func__, __LINE__, virq);
result = -EPERM;
goto fail_irq;
}
dev->core.power.power_state = PMSG_ON;
dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id);
if (!hcd) {
dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
__LINE__);
result = -ENOMEM;
goto fail_create_hcd;
}
hcd->rsrc_start = dev->m_region->lpar_addr;
hcd->rsrc_len = dev->m_region->len;
hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
if (!hcd->regs) {
dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
__LINE__);
result = -EPERM;
goto fail_ioremap;
}
dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
(unsigned long)hcd->rsrc_start);
dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__,
(unsigned long)hcd->rsrc_len);
dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__,
(unsigned long)hcd->regs);
dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
(unsigned long)virq);
ps3_system_bus_set_driver_data(dev, hcd);
result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
if (result) {
dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
__func__, __LINE__, result);
goto fail_add_hcd;
}
return result;
fail_add_hcd:
iounmap(hcd->regs);
fail_ioremap:
usb_put_hcd(hcd);
fail_create_hcd:
ps3_free_io_irq(virq);
fail_irq:
ps3_free_mmio_region(dev->m_region);
fail_mmio:
fail_start:
return result;
}
static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
{
struct usb_hcd *hcd =
(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
usb_put_hcd(hcd);
ps3_system_bus_set_driver_data(dev, NULL);
return 0;
}
MODULE_ALIAS("ps3-ehci");
static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
.match_id = PS3_MATCH_ID_EHCI,
.core = {
.name = "ps3-ehci-driver",
},
.probe = ps3_ehci_sb_probe,
.remove = ps3_ehci_sb_remove,
};

View File

@ -789,13 +789,14 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
head = ehci->async;
timer_action_done (ehci, TIMER_ASYNC_OFF);
if (!head->qh_next.qh) {
u32 cmd = readl (&ehci->regs->command);
u32 cmd = ehci_readl(ehci, &ehci->regs->command);
if (!(cmd & CMD_ASE)) {
/* in case a clear of CMD_ASE didn't take yet */
(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
(void)handshake(ehci, &ehci->regs->status,
STS_ASS, 0, 150);
cmd |= CMD_ASE | CMD_RUN;
writel (cmd, &ehci->regs->command);
ehci_writel(ehci, cmd, &ehci->regs->command);
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
/* posted write need not be known to HC yet ... */
}
@ -1007,7 +1008,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
int cmd = readl (&ehci->regs->command);
int cmd = ehci_readl(ehci, &ehci->regs->command);
struct ehci_qh *prev;
#ifdef DEBUG
@ -1025,7 +1026,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
&& !ehci->reclaim) {
/* ... and CMD_IAAD clear */
writel (cmd & ~CMD_ASE, &ehci->regs->command);
ehci_writel(ehci, cmd & ~CMD_ASE,
&ehci->regs->command);
wmb ();
// handshake later, if we need to
timer_action_done (ehci, TIMER_ASYNC_OFF);
@ -1054,8 +1056,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
ehci->reclaim_ready = 0;
cmd |= CMD_IAAD;
writel (cmd, &ehci->regs->command);
(void) readl (&ehci->regs->command);
ehci_writel(ehci, cmd, &ehci->regs->command);
(void)ehci_readl(ehci, &ehci->regs->command);
timer_action (ehci, TIMER_IAA_WATCHDOG);
}

View File

@ -433,20 +433,20 @@ static int enable_periodic (struct ehci_hcd *ehci)
/* did clearing PSE did take effect yet?
* takes effect only at frame boundaries...
*/
status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125);
if (status != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return status;
}
cmd = readl (&ehci->regs->command) | CMD_PSE;
writel (cmd, &ehci->regs->command);
cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... PSS happens later */
ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
/* make sure ehci_work scans these */
ehci->next_uframe = readl (&ehci->regs->frame_index)
% (ehci->periodic_size << 3);
ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
% (ehci->periodic_size << 3);
return 0;
}
@ -458,14 +458,14 @@ static int disable_periodic (struct ehci_hcd *ehci)
/* did setting PSE not take effect yet?
* takes effect only at frame boundaries...
*/
status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
if (status != 0) {
ehci_to_hcd(ehci)->state = HC_STATE_HALT;
return status;
}
cmd = readl (&ehci->regs->command) & ~CMD_PSE;
writel (cmd, &ehci->regs->command);
cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
ehci_writel(ehci, cmd, &ehci->regs->command);
/* posted write ... */
ehci->next_uframe = -1;
@ -1336,7 +1336,7 @@ iso_stream_schedule (
goto fail;
}
now = readl (&ehci->regs->frame_index) % mod;
now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
/* when's the last uframe this urb could start? */
max = now + mod;
@ -2088,7 +2088,7 @@ scan_periodic (struct ehci_hcd *ehci)
*/
now_uframe = ehci->next_uframe;
if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
clock = readl (&ehci->regs->frame_index);
clock = ehci_readl(ehci, &ehci->regs->frame_index);
else
clock = now_uframe + mod - 1;
clock %= mod;
@ -2213,7 +2213,7 @@ scan_periodic (struct ehci_hcd *ehci)
if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
break;
ehci->next_uframe = now_uframe;
now = readl (&ehci->regs->frame_index) % mod;
now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
if (now_uframe == now)
break;

View File

@ -74,7 +74,11 @@ struct ehci_hcd { /* one per controller */
/* per root hub port */
unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
unsigned long bus_suspended;
/* 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 */
/* per-HC memory pools (could be per-bus, but ...) */
struct dma_pool *qh_pool; /* qh per active urb */
@ -92,6 +96,7 @@ struct ehci_hcd { /* one per controller */
unsigned is_tdi_rh_tt:1; /* TDI roothub with TT */
unsigned no_selective_suspend:1;
unsigned has_fsl_port_bug:1; /* FreeScale */
unsigned big_endian_mmio:1;
u8 sbrn; /* packed release number */
@ -651,6 +656,45 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
#define ehci_has_fsl_portno_bug(e) (0)
#endif
/*
* While most USB host controllers implement their registers in
* little-endian format, a minority (celleb companion chip) implement
* them in big endian format.
*
* This attempts to support either format at compile time without a
* runtime penalty, or both formats with the additional overhead
* of checking a flag bit.
*/
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio)
#else
#define ehci_big_endian_mmio(e) 0
#endif
static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
__u32 __iomem * regs)
{
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
return ehci_big_endian_mmio(ehci) ?
readl_be((__force u32 *)regs) :
readl((__force u32 *)regs);
#else
return readl((__force u32 *)regs);
#endif
}
static inline void ehci_writel (const struct ehci_hcd *ehci,
const unsigned int val, __u32 __iomem *regs)
{
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
ehci_big_endian_mmio(ehci) ?
writel_be(val, (__force u32 *)regs) :
writel(val, (__force u32 *)regs);
#else
writel(val, (__force u32 *)regs);
#endif
}
/*-------------------------------------------------------------------------*/

View File

@ -170,7 +170,6 @@ static int usb_hcd_at91_remove(struct usb_hcd *hcd,
at91_stop_hc(pdev);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
disable_irq_wake(hcd->irq);
clk_put(fclk);
clk_put(iclk);
@ -271,8 +270,6 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(hcd->irq);
else
disable_irq_wake(hcd->irq);
/*
* The integrated transceivers seem unable to notice disconnect,
@ -293,6 +290,11 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
if (device_may_wakeup(&pdev->dev))
disable_irq_wake(hcd->irq);
if (!clocked) {
clk_enable(iclk);
clk_enable(fclk);
@ -320,18 +322,3 @@ static struct platform_driver ohci_hcd_at91_driver = {
},
};
static int __init ohci_hcd_at91_init (void)
{
if (usb_disabled())
return -ENODEV;
return platform_driver_register(&ohci_hcd_at91_driver);
}
static void __exit ohci_hcd_at91_cleanup (void)
{
platform_driver_unregister(&ohci_hcd_at91_driver);
}
module_init (ohci_hcd_at91_init);
module_exit (ohci_hcd_at91_cleanup);

View File

@ -345,19 +345,3 @@ static struct platform_driver ohci_hcd_au1xxx_driver = {
},
};
static int __init ohci_hcd_au1xxx_init (void)
{
pr_debug (DRIVER_INFO " (Au1xxx)");
pr_debug ("block sizes: ed %d td %d\n",
sizeof (struct ed), sizeof (struct td));
return platform_driver_register(&ohci_hcd_au1xxx_driver);
}
static void __exit ohci_hcd_au1xxx_cleanup (void)
{
platform_driver_unregister(&ohci_hcd_au1xxx_driver);
}
module_init (ohci_hcd_au1xxx_init);
module_exit (ohci_hcd_au1xxx_cleanup);

View File

@ -214,15 +214,3 @@ static struct platform_driver ohci_hcd_ep93xx_driver = {
},
};
static int __init ohci_hcd_ep93xx_init(void)
{
return platform_driver_register(&ohci_hcd_ep93xx_driver);
}
static void __exit ohci_hcd_ep93xx_cleanup(void)
{
platform_driver_unregister(&ohci_hcd_ep93xx_driver);
}
module_init(ohci_hcd_ep93xx_init);
module_exit(ohci_hcd_ep93xx_cleanup);

View File

@ -855,63 +855,167 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_PCI
#include "ohci-pci.c"
#define PCI_DRIVER ohci_pci_driver
#endif
#ifdef CONFIG_SA1111
#include "ohci-sa1111.c"
#define SA1111_DRIVER ohci_hcd_sa1111_driver
#endif
#ifdef CONFIG_ARCH_S3C2410
#include "ohci-s3c2410.c"
#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver
#endif
#ifdef CONFIG_ARCH_OMAP
#include "ohci-omap.c"
#define PLATFORM_DRIVER ohci_hcd_omap_driver
#endif
#ifdef CONFIG_ARCH_LH7A404
#include "ohci-lh7a404.c"
#define PLATFORM_DRIVER ohci_hcd_lh7a404_driver
#endif
#ifdef CONFIG_PXA27x
#include "ohci-pxa27x.c"
#define PLATFORM_DRIVER ohci_hcd_pxa27x_driver
#endif
#ifdef CONFIG_ARCH_EP93XX
#include "ohci-ep93xx.c"
#define PLATFORM_DRIVER ohci_hcd_ep93xx_driver
#endif
#ifdef CONFIG_SOC_AU1X00
#include "ohci-au1xxx.c"
#define PLATFORM_DRIVER ohci_hcd_au1xxx_driver
#endif
#ifdef CONFIG_PNX8550
#include "ohci-pnx8550.c"
#define PLATFORM_DRIVER ohci_hcd_pnx8550_driver
#endif
#ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
#include "ohci-ppc-soc.c"
#define PLATFORM_DRIVER ohci_hcd_ppc_soc_driver
#endif
#ifdef CONFIG_ARCH_AT91
#include "ohci-at91.c"
#define PLATFORM_DRIVER ohci_hcd_at91_driver
#endif
#ifdef CONFIG_ARCH_PNX4008
#include "ohci-pnx4008.c"
#define PLATFORM_DRIVER usb_hcd_pnx4008_driver
#endif
#if !(defined(CONFIG_PCI) \
|| defined(CONFIG_SA1111) \
|| defined(CONFIG_ARCH_S3C2410) \
|| defined(CONFIG_ARCH_OMAP) \
|| defined (CONFIG_ARCH_LH7A404) \
|| defined (CONFIG_PXA27x) \
|| defined (CONFIG_ARCH_EP93XX) \
|| defined (CONFIG_SOC_AU1X00) \
|| defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
|| defined (CONFIG_ARCH_AT91) \
|| defined (CONFIG_ARCH_PNX4008) \
)
#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
#include "ohci-ppc-of.c"
#define OF_PLATFORM_DRIVER ohci_hcd_ppc_of_driver
#endif
#ifdef CONFIG_PPC_PS3
#include "ohci-ps3.c"
#define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_driver
#endif
#if !defined(PCI_DRIVER) && \
!defined(PLATFORM_DRIVER) && \
!defined(OF_PLATFORM_DRIVER) && \
!defined(SA1111_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER)
#error "missing bus glue for ohci-hcd"
#endif
static int __init ohci_hcd_mod_init(void)
{
int retval = 0;
if (usb_disabled())
return -ENODEV;
printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name);
pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
sizeof (struct ed), sizeof (struct td));
#ifdef PS3_SYSTEM_BUS_DRIVER
retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
if (retval < 0)
goto error_ps3;
#endif
#ifdef PLATFORM_DRIVER
retval = platform_driver_register(&PLATFORM_DRIVER);
if (retval < 0)
goto error_platform;
#endif
#ifdef OF_PLATFORM_DRIVER
retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
if (retval < 0)
goto error_of_platform;
#endif
#ifdef SA1111_DRIVER
retval = sa1111_driver_register(&SA1111_DRIVER);
if (retval < 0)
goto error_sa1111;
#endif
#ifdef PCI_DRIVER
retval = pci_register_driver(&PCI_DRIVER);
if (retval < 0)
goto error_pci;
#endif
return retval;
/* Error path */
#ifdef PCI_DRIVER
error_pci:
#endif
#ifdef SA1111_DRIVER
sa1111_driver_unregister(&SA1111_DRIVER);
error_sa1111:
#endif
#ifdef OF_PLATFORM_DRIVER
of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
error_of_platform:
#endif
#ifdef PLATFORM_DRIVER
platform_driver_unregister(&PLATFORM_DRIVER);
error_platform:
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
error_ps3:
#endif
return retval;
}
module_init(ohci_hcd_mod_init);
static void __exit ohci_hcd_mod_exit(void)
{
#ifdef PCI_DRIVER
pci_unregister_driver(&PCI_DRIVER);
#endif
#ifdef SA1111_DRIVER
sa1111_driver_unregister(&SA1111_DRIVER);
#endif
#ifdef OF_PLATFORM_DRIVER
of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
#endif
#ifdef PLATFORM_DRIVER
platform_driver_unregister(&PLATFORM_DRIVER);
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
#endif
}
module_exit(ohci_hcd_mod_exit);

View File

@ -251,19 +251,3 @@ static struct platform_driver ohci_hcd_lh7a404_driver = {
},
};
static int __init ohci_hcd_lh7a404_init (void)
{
pr_debug (DRIVER_INFO " (LH7A404)");
pr_debug ("block sizes: ed %d td %d\n",
sizeof (struct ed), sizeof (struct td));
return platform_driver_register(&ohci_hcd_lh7a404_driver);
}
static void __exit ohci_hcd_lh7a404_cleanup (void)
{
platform_driver_unregister(&ohci_hcd_lh7a404_driver);
}
module_init (ohci_hcd_lh7a404_init);
module_exit (ohci_hcd_lh7a404_cleanup);

View File

@ -544,22 +544,3 @@ static struct platform_driver ohci_hcd_omap_driver = {
},
};
static int __init ohci_hcd_omap_init (void)
{
printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name);
if (usb_disabled())
return -ENODEV;
pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
sizeof (struct ed), sizeof (struct td));
return platform_driver_register(&ohci_hcd_omap_driver);
}
static void __exit ohci_hcd_omap_cleanup (void)
{
platform_driver_unregister(&ohci_hcd_omap_driver);
}
module_init (ohci_hcd_omap_init);
module_exit (ohci_hcd_omap_cleanup);

View File

@ -20,80 +20,155 @@
/*-------------------------------------------------------------------------*/
static int
ohci_pci_reset (struct usb_hcd *hcd)
/* AMD 756, for most chips (early revs), corrupts register
* values on read ... so enable the vendor workaround.
*/
static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci_hcd_init (ohci);
return ohci_init (ohci);
ohci->flags = OHCI_QUIRK_AMD756;
ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
/* also erratum 10 (suspend/resume issues) */
device_init_wakeup(&hcd->self.root_hub->dev, 0);
return 0;
}
static int __devinit
ohci_pci_start (struct usb_hcd *hcd)
/* Apple's OHCI driver has a lot of bizarre workarounds
* for this chip. Evidently control and bulk lists
* can get confused. (B&W G3 models, and ...)
*/
static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n");
return 0;
}
/* Check for NSC87560. We have to look at the bridge (fn1) to
* identify the USB (fn2). This quirk might apply to more or
* even all NSC stuff.
*/
static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
{
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
struct pci_dev *b;
b = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
&& b->vendor == PCI_VENDOR_ID_NS) {
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci->flags |= OHCI_QUIRK_SUPERIO;
ohci_dbg (ohci, "Using NSC SuperIO setup\n");
}
pci_dev_put(b);
return 0;
}
/* Check for Compaq's ZFMicro chipset, which needs short
* delays before control or bulk queues get re-activated
* in finish_unlinks()
*/
static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci->flags |= OHCI_QUIRK_ZFMICRO;
ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
return 0;
}
/* Check for Toshiba SCC OHCI which has big endian registers
* and little endian in memory data structures
*/
static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
/* That chip is only present in the southbridge of some
* cell based platforms which are supposed to select
* CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if
* that was the case though.
*/
#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
ohci->flags |= OHCI_QUIRK_BE_MMIO;
ohci_dbg (ohci, "enabled big endian Toshiba quirk\n");
return 0;
#else
ohci_err (ohci, "unsupported big endian Toshiba quirk\n");
return -ENXIO;
#endif
}
/* List of quirks for OHCI */
static const struct pci_device_id ohci_pci_quirks[] = {
{
PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c),
.driver_data = (unsigned long)ohci_quirk_amd756,
},
{
PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861),
.driver_data = (unsigned long)ohci_quirk_opti,
},
{
PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID),
.driver_data = (unsigned long)ohci_quirk_ns,
},
{
PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8),
.driver_data = (unsigned long)ohci_quirk_zfmicro,
},
{
PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
.driver_data = (unsigned long)ohci_quirk_toshiba_scc,
},
/* FIXME for some of the early AMD 760 southbridges, OHCI
* won't work at all. blacklist them.
*/
{},
};
static int ohci_pci_reset (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret = 0;
if (hcd->self.controller) {
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
const struct pci_device_id *quirk_id;
quirk_id = pci_match_id(ohci_pci_quirks, pdev);
if (quirk_id != NULL) {
int (*quirk)(struct usb_hcd *ohci);
quirk = (void *)quirk_id->driver_data;
ret = quirk(hcd);
}
}
if (ret == 0) {
ohci_hcd_init (ohci);
return ohci_init (ohci);
}
return ret;
}
static int __devinit ohci_pci_start (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret;
/* REVISIT this whole block should move to reset(), which handles
* all the other one-time init.
*/
#ifdef CONFIG_PM /* avoid warnings about unused pdev */
if (hcd->self.controller) {
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
/* AMD 756, for most chips (early revs), corrupts register
* values on read ... so enable the vendor workaround.
*/
if (pdev->vendor == PCI_VENDOR_ID_AMD
&& pdev->device == 0x740c) {
ohci->flags = OHCI_QUIRK_AMD756;
ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
/* also erratum 10 (suspend/resume issues) */
device_init_wakeup(&hcd->self.root_hub->dev, 0);
}
/* FIXME for some of the early AMD 760 southbridges, OHCI
* won't work at all. blacklist them.
*/
/* Apple's OHCI driver has a lot of bizarre workarounds
* for this chip. Evidently control and bulk lists
* can get confused. (B&W G3 models, and ...)
*/
else if (pdev->vendor == PCI_VENDOR_ID_OPTI
&& pdev->device == 0xc861) {
ohci_dbg (ohci,
"WARNING: OPTi workarounds unavailable\n");
}
/* Check for NSC87560. We have to look at the bridge (fn1) to
* identify the USB (fn2). This quirk might apply to more or
* even all NSC stuff.
*/
else if (pdev->vendor == PCI_VENDOR_ID_NS) {
struct pci_dev *b;
b = pci_get_slot (pdev->bus,
PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
&& b->vendor == PCI_VENDOR_ID_NS) {
ohci->flags |= OHCI_QUIRK_SUPERIO;
ohci_dbg (ohci, "Using NSC SuperIO setup\n");
}
pci_dev_put(b);
}
/* Check for Compaq's ZFMicro chipset, which needs short
* delays before control or bulk queues get re-activated
* in finish_unlinks()
*/
else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ
&& pdev->device == 0xa0f8) {
ohci->flags |= OHCI_QUIRK_ZFMICRO;
ohci_dbg (ohci,
"enabled Compaq ZFMicro chipset quirk\n");
}
/* RWC may not be set for add-in PCI cards, since boot
* firmware probably ignored them. This transfers PCI
* PM wakeup capabilities (once the PCI layer is fixed).
@ -101,16 +176,14 @@ ohci_pci_start (struct usb_hcd *hcd)
if (device_may_wakeup(&pdev->dev))
ohci->hc_control |= OHCI_CTRL_RWC;
}
#endif /* CONFIG_PM */
/* NOTE: there may have already been a first reset, to
* keep bios/smm irqs from making trouble
*/
if ((ret = ohci_run (ohci)) < 0) {
ret = ohci_run (ohci);
if (ret < 0) {
ohci_err (ohci, "can't start\n");
ohci_stop (hcd);
return ret;
}
return 0;
return ret;
}
#ifdef CONFIG_PM
@ -238,23 +311,3 @@ static struct pci_driver ohci_pci_driver = {
.shutdown = usb_hcd_pci_shutdown,
};
static int __init ohci_hcd_pci_init (void)
{
printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
if (usb_disabled())
return -ENODEV;
pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
sizeof (struct ed), sizeof (struct td));
return pci_register_driver (&ohci_pci_driver);
}
module_init (ohci_hcd_pci_init);
/*-------------------------------------------------------------------------*/
static void __exit ohci_hcd_pci_cleanup (void)
{
pci_unregister_driver (&ohci_pci_driver);
}
module_exit (ohci_hcd_pci_cleanup);

View File

@ -465,15 +465,3 @@ static struct platform_driver usb_hcd_pnx4008_driver = {
.remove = usb_hcd_pnx4008_remove,
};
static int __init usb_hcd_pnx4008_init(void)
{
return platform_driver_register(&usb_hcd_pnx4008_driver);
}
static void __exit usb_hcd_pnx4008_cleanup(void)
{
return platform_driver_unregister(&usb_hcd_pnx4008_driver);
}
module_init(usb_hcd_pnx4008_init);
module_exit(usb_hcd_pnx4008_cleanup);

View File

@ -240,19 +240,3 @@ static struct platform_driver ohci_hcd_pnx8550_driver = {
.remove = ohci_hcd_pnx8550_drv_remove,
};
static int __init ohci_hcd_pnx8550_init (void)
{
pr_debug (DRIVER_INFO " (pnx8550)");
pr_debug ("block sizes: ed %d td %d\n",
sizeof (struct ed), sizeof (struct td));
return platform_driver_register(&ohci_hcd_pnx8550_driver);
}
static void __exit ohci_hcd_pnx8550_cleanup (void)
{
platform_driver_unregister(&ohci_hcd_pnx8550_driver);
}
module_init (ohci_hcd_pnx8550_init);
module_exit (ohci_hcd_pnx8550_cleanup);

View File

@ -0,0 +1,232 @@
/*
* OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
* (C) Copyright 2002 Hewlett-Packard Company
* (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
*
* Bus glue for OHCI HC on the of_platform bus
*
* Modified for of_platform bus from ohci-sa1111.c
*
* This file is licenced under the GPL.
*/
#include <linux/signal.h>
#include <asm/of_platform.h>
#include <asm/prom.h>
static int __devinit
ohci_ppc_of_start(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int ret;
if ((ret = ohci_init(ohci)) < 0)
return ret;
if ((ret = ohci_run(ohci)) < 0) {
err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
ohci_stop(hcd);
return ret;
}
return 0;
}
static const struct hc_driver ohci_ppc_of_hc_driver = {
.description = hcd_name,
.product_desc = "OF OHCI",
.hcd_priv_size = sizeof(struct ohci_hcd),
/*
* generic hardware linkage
*/
.irq = ohci_irq,
.flags = HCD_USB11 | HCD_MEMORY,
/*
* basic lifecycle operations
*/
.start = ohci_ppc_of_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,
/*
* scheduling support
*/
.get_frame_number = ohci_get_frame,
/*
* root hub support
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
#endif
.start_port_reset = ohci_start_port_reset,
};
static int __devinit
ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
{
struct device_node *dn = op->node;
struct usb_hcd *hcd;
struct ohci_hcd *ohci;
struct resource res;
int irq;
int rv;
int is_bigendian;
if (usb_disabled())
return -ENODEV;
is_bigendian =
device_is_compatible(dn, "ohci-bigendian") ||
device_is_compatible(dn, "ohci-be");
dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
rv = of_address_to_resource(dn, 0, &res);
if (rv)
return rv;
hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
if (!hcd)
return -ENOMEM;
hcd->rsrc_start = res.start;
hcd->rsrc_len = res.end - res.start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
rv = -EBUSY;
goto err_rmr;
}
irq = irq_of_parse_and_map(dn, 0);
if (irq == NO_IRQ) {
printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
rv = -EBUSY;
goto err_irq;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (!hcd->regs) {
printk(KERN_ERR __FILE__ ": ioremap failed\n");
rv = -ENOMEM;
goto err_ioremap;
}
ohci = hcd_to_ohci(hcd);
if (is_bigendian)
ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
ohci_hcd_init(ohci);
rv = usb_add_hcd(hcd, irq, 0);
if (rv == 0)
return 0;
iounmap(hcd->regs);
err_ioremap:
irq_dispose_mapping(irq);
err_irq:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err_rmr:
usb_put_hcd(hcd);
return rv;
}
static int ohci_hcd_ppc_of_remove(struct of_device *op)
{
struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
dev_set_drvdata(&op->dev, NULL);
dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
usb_remove_hcd(hcd);
iounmap(hcd->regs);
irq_dispose_mapping(hcd->irq);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
return 0;
}
static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
{
struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
if (hcd->driver->shutdown)
hcd->driver->shutdown(hcd);
return 0;
}
static struct of_device_id ohci_hcd_ppc_of_match[] = {
#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
{
.name = "usb",
.compatible = "ohci-bigendian",
},
{
.name = "usb",
.compatible = "ohci-be",
},
#endif
#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
{
.name = "usb",
.compatible = "ohci-littledian",
},
{
.name = "usb",
.compatible = "ohci-le",
},
#endif
{},
};
MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
#if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
!defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
#error "No endianess selected for ppc-of-ohci"
#endif
static struct of_platform_driver ohci_hcd_ppc_of_driver = {
.name = "ppc-of-ohci",
.match_table = ohci_hcd_ppc_of_match,
.probe = ohci_hcd_ppc_of_probe,
.remove = ohci_hcd_ppc_of_remove,
.shutdown = ohci_hcd_ppc_of_shutdown,
#ifdef CONFIG_PM
/*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
/*.resume = ohci_hcd_ppc_soc_drv_resume,*/
#endif
.driver = {
.name = "ppc-of-ohci",
.owner = THIS_MODULE,
},
};

View File

@ -72,7 +72,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
}
ohci = hcd_to_ohci(hcd);
ohci->flags |= OHCI_BIG_ENDIAN;
ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
ohci_hcd_init(ohci);
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
@ -208,19 +208,3 @@ static struct platform_driver ohci_hcd_ppc_soc_driver = {
},
};
static int __init ohci_hcd_ppc_soc_init(void)
{
pr_debug(DRIVER_INFO " (PPC SOC)\n");
pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
sizeof(struct td));
return platform_driver_register(&ohci_hcd_ppc_soc_driver);
}
static void __exit ohci_hcd_ppc_soc_cleanup(void)
{
platform_driver_unregister(&ohci_hcd_ppc_soc_driver);
}
module_init(ohci_hcd_ppc_soc_init);
module_exit(ohci_hcd_ppc_soc_cleanup);

196
drivers/usb/host/ohci-ps3.c Normal file
View File

@ -0,0 +1,196 @@
/*
* PS3 OHCI Host Controller driver
*
* Copyright (C) 2006 Sony Computer Entertainment Inc.
* Copyright 2006 Sony Corp.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <asm/ps3.h>
static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
ohci->flags |= OHCI_QUIRK_BE_MMIO;
ohci_hcd_init(ohci);
return ohci_init(ohci);
}
static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd)
{
int result;
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
/* Handle root hub init quirk in spider south bridge. */
/* Also set PwrOn2PwrGood to 0x7f (254ms). */
ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM,
&ohci->regs->roothub.a);
ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b);
result = ohci_run(ohci);
if (result < 0) {
err("can't start %s", hcd->self.bus_name);
ohci_stop(hcd);
}
return result;
}
static const struct hc_driver ps3_ohci_hc_driver = {
.description = hcd_name,
.product_desc = "PS3 OHCI Host Controller",
.hcd_priv_size = sizeof(struct ohci_hcd),
.irq = ohci_irq,
.flags = HCD_MEMORY | HCD_USB11,
.reset = ps3_ohci_hc_reset,
.start = ps3_ohci_hc_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,
.get_frame_number = ohci_get_frame,
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
.hub_irq_enable = ohci_rhsc_enable,
.start_port_reset = ohci_start_port_reset,
#if defined(CONFIG_PM)
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
#endif
};
/* redefine dev_dbg to do a syntax check */
#if !defined(DEBUG)
#undef dev_dbg
static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
const struct device *_dev, const char *fmt, ...) {return 0;}
#endif
static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
{
int result;
struct usb_hcd *hcd;
unsigned int virq;
static u64 dummy_mask = DMA_32BIT_MASK;
if (usb_disabled()) {
result = -ENODEV;
goto fail_start;
}
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;
}
dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
__LINE__, dev->m_region->lpar_addr);
result = ps3_alloc_io_irq(dev->interrupt_id, &virq);
if (result) {
dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
__func__, __LINE__, virq);
result = -EPERM;
goto fail_irq;
}
dev->core.power.power_state = PMSG_ON;
dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id);
if (!hcd) {
dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
__LINE__);
result = -ENOMEM;
goto fail_create_hcd;
}
hcd->rsrc_start = dev->m_region->lpar_addr;
hcd->rsrc_len = dev->m_region->len;
hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
if (!hcd->regs) {
dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
__LINE__);
result = -EPERM;
goto fail_ioremap;
}
dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
(unsigned long)hcd->rsrc_start);
dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len %lxh\n", __func__, __LINE__,
(unsigned long)hcd->rsrc_len);
dev_dbg(&dev->core, "%s:%d: hcd->regs %lxh\n", __func__, __LINE__,
(unsigned long)hcd->regs);
dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__,
(unsigned long)virq);
ps3_system_bus_set_driver_data(dev, hcd);
result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
if (result) {
dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
__func__, __LINE__, result);
goto fail_add_hcd;
}
return result;
fail_add_hcd:
iounmap(hcd->regs);
fail_ioremap:
usb_put_hcd(hcd);
fail_create_hcd:
ps3_free_io_irq(virq);
fail_irq:
ps3_free_mmio_region(dev->m_region);
fail_mmio:
fail_start:
return result;
}
static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
{
struct usb_hcd *hcd =
(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
usb_put_hcd(hcd);
ps3_system_bus_set_driver_data(dev, NULL);
return 0;
}
MODULE_ALIAS("ps3-ohci");
static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
.match_id = PS3_MATCH_ID_OHCI,
.core = {
.name = "ps3-ohci-driver",
},
.probe = ps3_ohci_sb_probe,
.remove = ps3_ohci_sb_remove,
};

View File

@ -369,19 +369,3 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {
},
};
static int __init ohci_hcd_pxa27x_init (void)
{
pr_debug (DRIVER_INFO " (pxa27x)");
pr_debug ("block sizes: ed %d td %d\n",
sizeof (struct ed), sizeof (struct td));
return platform_driver_register(&ohci_hcd_pxa27x_driver);
}
static void __exit ohci_hcd_pxa27x_cleanup (void)
{
platform_driver_unregister(&ohci_hcd_pxa27x_driver);
}
module_init (ohci_hcd_pxa27x_init);
module_exit (ohci_hcd_pxa27x_cleanup);

View File

@ -501,15 +501,3 @@ static struct platform_driver ohci_hcd_s3c2410_driver = {
},
};
static int __init ohci_hcd_s3c2410_init (void)
{
return platform_driver_register(&ohci_hcd_s3c2410_driver);
}
static void __exit ohci_hcd_s3c2410_cleanup (void)
{
platform_driver_unregister(&ohci_hcd_s3c2410_driver);
}
module_init (ohci_hcd_s3c2410_init);
module_exit (ohci_hcd_s3c2410_cleanup);

View File

@ -269,19 +269,3 @@ static struct sa1111_driver ohci_hcd_sa1111_driver = {
.remove = ohci_hcd_sa1111_drv_remove,
};
static int __init ohci_hcd_sa1111_init (void)
{
dbg (DRIVER_INFO " (SA-1111)");
dbg ("block sizes: ed %d td %d",
sizeof (struct ed), sizeof (struct td));
return sa1111_driver_register(&ohci_hcd_sa1111_driver);
}
static void __exit ohci_hcd_sa1111_cleanup (void)
{
sa1111_driver_unregister(&ohci_hcd_sa1111_driver);
}
module_init (ohci_hcd_sa1111_init);
module_exit (ohci_hcd_sa1111_cleanup);

View File

@ -394,8 +394,9 @@ struct ohci_hcd {
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
#define OHCI_QUIRK_SUPERIO 0x02 /* natsemi */
#define OHCI_QUIRK_INITRESET 0x04 /* SiS, OPTi, ... */
#define OHCI_BIG_ENDIAN 0x08 /* big endian HC */
#define OHCI_QUIRK_ZFMICRO 0x10 /* Compaq ZFMicro chipset*/
#define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */
#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */
#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/
// there are also chip quirks/bugs in init logic
};
@ -439,117 +440,164 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci)
* a minority (notably the IBM STB04XXX and the Motorola MPC5200
* processors) implement them in big endian format.
*
* In addition some more exotic implementations like the Toshiba
* Spider (aka SCC) cell southbridge are "mixed" endian, that is,
* they have a different endianness for registers vs. in-memory
* descriptors.
*
* This attempts to support either format at compile time without a
* runtime penalty, or both formats with the additional overhead
* of checking a flag bit.
*
* That leads to some tricky Kconfig rules howevber. There are
* different defaults based on some arch/ppc platforms, though
* the basic rules are:
*
* Controller type Kconfig options needed
* --------------- ----------------------
* little endian CONFIG_USB_OHCI_LITTLE_ENDIAN
*
* fully big endian CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_
* CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
*
* mixed endian CONFIG_USB_OHCI_LITTLE_ENDIAN _and_
* CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC}
*
* (If you have a mixed endian controller, you -must- also define
* CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building
* both your mixed endian and a fully big endian controller support in
* the same kernel image).
*/
#ifdef CONFIG_USB_OHCI_BIG_ENDIAN
#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
#define big_endian(ohci) (ohci->flags & OHCI_BIG_ENDIAN) /* either */
#define big_endian_desc(ohci) (ohci->flags & OHCI_QUIRK_BE_DESC)
#else
#define big_endian(ohci) 1 /* only big endian */
#define big_endian_desc(ohci) 1 /* only big endian */
#endif
#else
#define big_endian_desc(ohci) 0 /* only little endian */
#endif
#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
#define big_endian_mmio(ohci) (ohci->flags & OHCI_QUIRK_BE_MMIO)
#else
#define big_endian_mmio(ohci) 1 /* only big endian */
#endif
#else
#define big_endian_mmio(ohci) 0 /* only little endian */
#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 STB04xxx support is
* finally ported over.
*/
#if defined(CONFIG_PPC)
#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
#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 ohci_readl (const struct ohci_hcd *ohci,
__hc32 __iomem * regs)
static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
__hc32 __iomem * regs)
{
return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs);
#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
return big_endian_mmio(ohci) ?
readl_be ((__force u32 *)regs) :
readl ((__force u32 *)regs);
#else
return readl ((__force u32 *)regs);
#endif
}
static inline void ohci_writel (const struct ohci_hcd *ohci,
const unsigned int val, __hc32 __iomem *regs)
static inline void _ohci_writel (const struct ohci_hcd *ohci,
const unsigned int val, __hc32 __iomem *regs)
{
big_endian(ohci) ? writel_be (val, regs) :
writel (val, (__force u32 *)regs);
#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
big_endian_mmio(ohci) ?
writel_be (val, (__force u32 *)regs) :
writel (val, (__force u32 *)regs);
#else
writel (val, (__force u32 *)regs);
#endif
}
#else /* !CONFIG_USB_OHCI_BIG_ENDIAN */
#define big_endian(ohci) 0 /* only little endian */
#ifdef CONFIG_ARCH_LH7A404
/* Marc Singer: at the time this code was written, the LH7A404
* had a problem reading the USB host registers. This
* implementation of the ohci_readl function performs the read
* twice as a work-around.
*/
static inline unsigned int
ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs)
{
*(volatile __force unsigned int*) regs;
return *(volatile __force unsigned int*) regs;
}
/* Marc Singer: at the time this code was written, the LH7A404
* had a problem reading the USB host registers. This
* implementation of the ohci_readl function performs the read
* twice as a work-around.
*/
#define ohci_readl(o,r) (_ohci_readl(o,r),_ohci_readl(o,r))
#define ohci_writel(o,v,r) _ohci_writel(o,v,r)
#else
/* Standard version of ohci_readl uses standard, platform
* specific implementation. */
static inline unsigned int
ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs)
{
return readl(regs);
}
#define ohci_readl(o,r) _ohci_readl(o,r)
#define ohci_writel(o,v,r) _ohci_writel(o,v,r)
#endif
static inline void ohci_writel (const struct ohci_hcd *ohci,
const unsigned int val, __hc32 __iomem *regs)
{
writel (val, regs);
}
#endif /* !CONFIG_USB_OHCI_BIG_ENDIAN */
/*-------------------------------------------------------------------------*/
/* cpu to ohci */
static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
{
return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x);
return big_endian_desc(ohci) ?
(__force __hc16)cpu_to_be16(x) :
(__force __hc16)cpu_to_le16(x);
}
static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
{
return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x);
return big_endian_desc(ohci) ?
cpu_to_be16p(x) :
cpu_to_le16p(x);
}
static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
{
return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x);
return big_endian_desc(ohci) ?
(__force __hc32)cpu_to_be32(x) :
(__force __hc32)cpu_to_le32(x);
}
static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
{
return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x);
return big_endian_desc(ohci) ?
cpu_to_be32p(x) :
cpu_to_le32p(x);
}
/* ohci to cpu */
static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
{
return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x);
return big_endian_desc(ohci) ?
be16_to_cpu((__force __be16)x) :
le16_to_cpu((__force __le16)x);
}
static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
{
return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x);
return big_endian_desc(ohci) ?
be16_to_cpup((__force __be16 *)x) :
le16_to_cpup((__force __le16 *)x);
}
static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
{
return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x);
return big_endian_desc(ohci) ?
be32_to_cpu((__force __be32)x) :
le32_to_cpu((__force __le32)x);
}
static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
{
return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x);
return big_endian_desc(ohci) ?
be32_to_cpup((__force __be32 *)x) :
le32_to_cpup((__force __le32 *)x);
}
/*-------------------------------------------------------------------------*/
@ -557,6 +605,9 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
/* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
* hardware handles 16 bit reads. That creates a different confusion on
* some big-endian SOC implementations. Same thing happens with PSW access.
*
* FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
* to arch/powerpc
*/
#ifdef CONFIG_STB03xxx
@ -568,7 +619,7 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
{
u32 tmp;
if (big_endian(ohci)) {
if (big_endian_desc(ohci)) {
tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
tmp >>= OHCI_BE_FRAME_NO_SHIFT;
} else
@ -580,7 +631,7 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
const struct td *td, int index)
{
return (__hc16 *)(big_endian(ohci) ?
return (__hc16 *)(big_endian_desc(ohci) ?
&td->hwPSW[index ^ 1] : &td->hwPSW[index]);
}

View File

@ -168,9 +168,13 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
space, "", qh, qtype,
le32_to_cpu(qh->link), le32_to_cpu(element));
if (qh->type == USB_ENDPOINT_XFER_ISOC)
out += sprintf(out, "%*s period %d frame %x desc [%p]\n",
space, "", qh->period, qh->iso_frame,
qh->iso_packet_desc);
out += sprintf(out, "%*s period %d phase %d load %d us, "
"frame %x desc [%p]\n",
space, "", qh->period, qh->phase, qh->load,
qh->iso_frame, qh->iso_packet_desc);
else if (qh->type == USB_ENDPOINT_XFER_INT)
out += sprintf(out, "%*s period %d phase %d load %d us\n",
space, "", qh->period, qh->phase, qh->load);
if (element & UHCI_PTR_QH)
out += sprintf(out, "%*s Element points to QH (bug?)\n", space, "");
@ -208,7 +212,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
space, "", nurbs);
}
if (qh->udev) {
if (qh->dummy_td) {
out += sprintf(out, "%*s Dummy TD\n", space, "");
out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
}
@ -347,31 +351,80 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
struct uhci_qh *qh;
struct uhci_td *td;
struct list_head *tmp, *head;
int nframes, nerrs;
out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
out += sprintf(out, "HC status\n");
out += uhci_show_status(uhci, out, len - (out - buf));
out += sprintf(out, "Periodic load table\n");
for (i = 0; i < MAX_PHASE; ++i) {
out += sprintf(out, "\t%d", uhci->load[i]);
if (i % 8 == 7)
*out++ = '\n';
}
out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n",
uhci->total_load,
uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
if (debug <= 1)
return out - buf;
out += sprintf(out, "Frame List\n");
nframes = 10;
nerrs = 0;
for (i = 0; i < UHCI_NUMFRAMES; ++i) {
td = uhci->frame_cpu[i];
if (!td)
continue;
__le32 link, qh_dma;
out += sprintf(out, "- Frame %d\n", i); \
if (td->dma_handle != (dma_addr_t)uhci->frame[i])
out += sprintf(out, " frame list does not match td->dma_handle!\n");
j = 0;
td = uhci->frame_cpu[i];
link = uhci->frame[i];
if (!td)
goto check_link;
if (nframes > 0) {
out += sprintf(out, "- Frame %d -> (%08x)\n",
i, le32_to_cpu(link));
j = 1;
}
head = &td->fl_list;
tmp = head;
do {
td = list_entry(tmp, struct uhci_td, fl_list);
tmp = tmp->next;
out += uhci_show_td(td, out, len - (out - buf), 4);
if (cpu_to_le32(td->dma_handle) != link) {
if (nframes > 0)
out += sprintf(out, " link does "
"not match list entry!\n");
else
++nerrs;
}
if (nframes > 0)
out += uhci_show_td(td, out,
len - (out - buf), 4);
link = td->link;
} while (tmp != head);
check_link:
qh_dma = uhci_frame_skel_link(uhci, i);
if (link != qh_dma) {
if (nframes > 0) {
if (!j) {
out += sprintf(out,
"- Frame %d -> (%08x)\n",
i, le32_to_cpu(link));
j = 1;
}
out += sprintf(out, " link does not match "
"QH (%08x)!\n", le32_to_cpu(qh_dma));
} else
++nerrs;
}
nframes -= j;
}
if (nerrs > 0)
out += sprintf(out, "Skipped %d bad links\n", nerrs);
out += sprintf(out, "Skeleton QHs\n");

View File

@ -92,6 +92,34 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
static void wakeup_rh(struct uhci_hcd *uhci);
static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
/*
* Calculate the link pointer DMA value for the first Skeleton QH in a frame.
*/
static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
{
int skelnum;
/*
* The interrupt queues will be interleaved as evenly as possible.
* There's not much to be done about period-1 interrupts; they have
* to occur in every frame. But we can schedule period-2 interrupts
* in odd-numbered frames, period-4 interrupts in frames congruent
* to 2 (mod 4), and so on. This way each frame only has two
* interrupt QHs, which will help spread out bandwidth utilization.
*
* ffs (Find First bit Set) does exactly what we need:
* 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8],
* 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
* ffs >= 7 => not on any high-period queue, so use
* skel_int1_qh = skelqh[9].
* Add in UHCI_NUMFRAMES to insure at least one bit is set.
*/
skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
if (skelnum <= 1)
skelnum = 9;
return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle);
}
#include "uhci-debug.c"
#include "uhci-q.c"
#include "uhci-hub.c"
@ -631,32 +659,11 @@ static int uhci_start(struct usb_hcd *hcd)
/*
* Fill the frame list: make all entries point to the proper
* interrupt queue.
*
* The interrupt queues will be interleaved as evenly as possible.
* There's not much to be done about period-1 interrupts; they have
* to occur in every frame. But we can schedule period-2 interrupts
* in odd-numbered frames, period-4 interrupts in frames congruent
* to 2 (mod 4), and so on. This way each frame only has two
* interrupt QHs, which will help spread out bandwidth utilization.
*/
for (i = 0; i < UHCI_NUMFRAMES; i++) {
int irq;
/*
* ffs (Find First bit Set) does exactly what we need:
* 1,3,5,... => ffs = 0 => use skel_int2_qh = skelqh[8],
* 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
* ffs >= 7 => not on any high-period queue, so use
* skel_int1_qh = skelqh[9].
* Add UHCI_NUMFRAMES to insure at least one bit is set.
*/
irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
if (irq <= 1)
irq = 9;
/* Only place we don't use the frame list routines */
uhci->frame[i] = UHCI_PTR_QH |
cpu_to_le32(uhci->skelqh[irq]->dma_handle);
uhci->frame[i] = uhci_frame_skel_link(uhci, i);
}
/*

View File

@ -83,6 +83,7 @@
#define UHCI_MAX_SOF_NUMBER 2047 /* in an SOF packet */
#define CAN_SCHEDULE_FRAMES 1000 /* how far in the future frames
* can be scheduled */
#define MAX_PHASE 32 /* Periodic scheduling length */
/* When no queues need Full-Speed Bandwidth Reclamation,
* delay this long before turning FSBR off */
@ -141,6 +142,8 @@ struct uhci_qh {
unsigned long advance_jiffies; /* Time of last queue advance */
unsigned int unlink_frame; /* When the QH was unlinked */
unsigned int period; /* For Interrupt and Isochronous QHs */
short phase; /* Between 0 and period-1 */
short load; /* Periodic time requirement, in us */
unsigned int iso_frame; /* Frame # for iso_packet_desc */
int iso_status; /* Status for Isochronous URBs */
@ -153,6 +156,8 @@ struct uhci_qh {
unsigned int needs_fixup:1; /* Must fix the TD toggle values */
unsigned int is_stopped:1; /* Queue was stopped by error/unlink */
unsigned int wait_expired:1; /* QH_WAIT_TIMEOUT has expired */
unsigned int bandwidth_reserved:1; /* Periodic bandwidth has
* been allocated */
} __attribute__((aligned(16)));
/*
@ -414,6 +419,9 @@ struct uhci_hcd {
wait_queue_head_t waitqh; /* endpoint_disable waiters */
int num_waiting; /* Number of waiters */
int total_load; /* Sum of array values */
short load[MAX_PHASE]; /* Periodic allocations */
};
/* Convert between a usb_hcd pointer and the corresponding uhci_hcd */

View File

@ -248,16 +248,26 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
INIT_LIST_HEAD(&qh->node);
if (udev) { /* Normal QH */
qh->dummy_td = uhci_alloc_td(uhci);
if (!qh->dummy_td) {
dma_pool_free(uhci->qh_pool, qh, dma_handle);
return NULL;
qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
if (qh->type != USB_ENDPOINT_XFER_ISOC) {
qh->dummy_td = uhci_alloc_td(uhci);
if (!qh->dummy_td) {
dma_pool_free(uhci->qh_pool, qh, dma_handle);
return NULL;
}
}
qh->state = QH_STATE_IDLE;
qh->hep = hep;
qh->udev = udev;
hep->hcpriv = qh;
qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
if (qh->type == USB_ENDPOINT_XFER_INT ||
qh->type == USB_ENDPOINT_XFER_ISOC)
qh->load = usb_calc_bus_time(udev->speed,
usb_endpoint_dir_in(&hep->desc),
qh->type == USB_ENDPOINT_XFER_ISOC,
le16_to_cpu(hep->desc.wMaxPacketSize))
/ 1000 + 1;
} else { /* Skeleton QH */
qh->state = QH_STATE_ACTIVE;
@ -275,7 +285,8 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
list_del(&qh->node);
if (qh->udev) {
qh->hep->hcpriv = NULL;
uhci_free_td(uhci, qh->dummy_td);
if (qh->dummy_td)
uhci_free_td(uhci, qh->dummy_td);
}
dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
}
@ -327,7 +338,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
goto done;
qh->element = UHCI_PTR_TERM;
/* Control pipes have to worry about toggles */
/* Control pipes don't have to worry about toggles */
if (qh->type == USB_ENDPOINT_XFER_CONTROL)
goto done;
@ -493,6 +504,121 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh)
wake_up_all(&uhci->waitqh);
}
/*
* Find the highest existing bandwidth load for a given phase and period.
*/
static int uhci_highest_load(struct uhci_hcd *uhci, int phase, int period)
{
int highest_load = uhci->load[phase];
for (phase += period; phase < MAX_PHASE; phase += period)
highest_load = max_t(int, highest_load, uhci->load[phase]);
return highest_load;
}
/*
* Set qh->phase to the optimal phase for a periodic transfer and
* check whether the bandwidth requirement is acceptable.
*/
static int uhci_check_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
int minimax_load;
/* Find the optimal phase (unless it is already set) and get
* its load value. */
if (qh->phase >= 0)
minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
else {
int phase, load;
int max_phase = min_t(int, MAX_PHASE, qh->period);
qh->phase = 0;
minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
for (phase = 1; phase < max_phase; ++phase) {
load = uhci_highest_load(uhci, phase, qh->period);
if (load < minimax_load) {
minimax_load = load;
qh->phase = phase;
}
}
}
/* Maximum allowable periodic bandwidth is 90%, or 900 us per frame */
if (minimax_load + qh->load > 900) {
dev_dbg(uhci_dev(uhci), "bandwidth allocation failed: "
"period %d, phase %d, %d + %d us\n",
qh->period, qh->phase, minimax_load, qh->load);
return -ENOSPC;
}
return 0;
}
/*
* Reserve a periodic QH's bandwidth in the schedule
*/
static void uhci_reserve_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
int i;
int load = qh->load;
char *p = "??";
for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
uhci->load[i] += load;
uhci->total_load += load;
}
uhci_to_hcd(uhci)->self.bandwidth_allocated =
uhci->total_load / MAX_PHASE;
switch (qh->type) {
case USB_ENDPOINT_XFER_INT:
++uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
p = "INT";
break;
case USB_ENDPOINT_XFER_ISOC:
++uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
p = "ISO";
break;
}
qh->bandwidth_reserved = 1;
dev_dbg(uhci_dev(uhci),
"%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
"reserve", qh->udev->devnum,
qh->hep->desc.bEndpointAddress, p,
qh->period, qh->phase, load);
}
/*
* Release a periodic QH's bandwidth reservation
*/
static void uhci_release_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
int i;
int load = qh->load;
char *p = "??";
for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
uhci->load[i] -= load;
uhci->total_load -= load;
}
uhci_to_hcd(uhci)->self.bandwidth_allocated =
uhci->total_load / MAX_PHASE;
switch (qh->type) {
case USB_ENDPOINT_XFER_INT:
--uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
p = "INT";
break;
case USB_ENDPOINT_XFER_ISOC:
--uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
p = "ISO";
break;
}
qh->bandwidth_reserved = 0;
dev_dbg(uhci_dev(uhci),
"%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
"release", qh->udev->devnum,
qh->hep->desc.bEndpointAddress, p,
qh->period, qh->phase, load);
}
static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
struct urb *urb)
{
@ -796,7 +922,6 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
wmb();
qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
qh->dummy_td = td;
qh->period = urb->interval;
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
usb_pipeout(urb->pipe), toggle);
@ -827,28 +952,42 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
struct uhci_qh *qh)
{
int exponent;
int ret;
/* USB 1.1 interrupt transfers only involve one packet per interval.
* Drivers can submit URBs of any length, but longer ones will need
* multiple intervals to complete.
*/
/* Figure out which power-of-two queue to use */
for (exponent = 7; exponent >= 0; --exponent) {
if ((1 << exponent) <= urb->interval)
break;
}
if (exponent < 0)
return -EINVAL;
urb->interval = 1 << exponent;
if (!qh->bandwidth_reserved) {
int exponent;
if (qh->period == 0)
/* Figure out which power-of-two queue to use */
for (exponent = 7; exponent >= 0; --exponent) {
if ((1 << exponent) <= urb->interval)
break;
}
if (exponent < 0)
return -EINVAL;
qh->period = 1 << exponent;
qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
else if (qh->period != urb->interval)
return -EINVAL; /* Can't change the period */
return uhci_submit_common(uhci, urb, qh);
/* For now, interrupt phase is fixed by the layout
* of the QH lists. */
qh->phase = (qh->period / 2) & (MAX_PHASE - 1);
ret = uhci_check_bandwidth(uhci, qh);
if (ret)
return ret;
} else if (qh->period > urb->interval)
return -EINVAL; /* Can't decrease the period */
ret = uhci_submit_common(uhci, urb, qh);
if (ret == 0) {
urb->interval = qh->period;
if (!qh->bandwidth_reserved)
uhci_reserve_bandwidth(uhci, qh);
}
return ret;
}
/*
@ -995,15 +1134,32 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
return -EFBIG;
/* Check the period and figure out the starting frame number */
if (qh->period == 0) {
if (!qh->bandwidth_reserved) {
qh->period = urb->interval;
if (urb->transfer_flags & URB_ISO_ASAP) {
qh->phase = -1; /* Find the best phase */
i = uhci_check_bandwidth(uhci, qh);
if (i)
return i;
/* Allow a little time to allocate the TDs */
uhci_get_current_frame_number(uhci);
urb->start_frame = uhci->frame_number + 10;
frame = uhci->frame_number + 10;
/* Move forward to the first frame having the
* correct phase */
urb->start_frame = frame + ((qh->phase - frame) &
(qh->period - 1));
} else {
i = urb->start_frame - uhci->last_iso_frame;
if (i <= 0 || i >= UHCI_NUMFRAMES)
return -EINVAL;
qh->phase = urb->start_frame & (qh->period - 1);
i = uhci_check_bandwidth(uhci, qh);
if (i)
return i;
}
} else if (qh->period != urb->interval) {
return -EINVAL; /* Can't change the period */
@ -1049,9 +1205,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
/* Set the interrupt-on-completion flag on the last packet. */
td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
qh->skel = uhci->skel_iso_qh;
qh->period = urb->interval;
/* Add the TDs to the frame list */
frame = urb->start_frame;
list_for_each_entry(td, &urbp->td_list, list) {
@ -1065,6 +1218,9 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
qh->iso_status = 0;
}
qh->skel = uhci->skel_iso_qh;
if (!qh->bandwidth_reserved)
uhci_reserve_bandwidth(uhci, qh);
return 0;
}
@ -1119,7 +1275,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
unsigned long flags;
struct urb_priv *urbp;
struct uhci_qh *qh;
int bustime;
spin_lock_irqsave(&uhci->lock, flags);
@ -1149,35 +1304,11 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
ret = uhci_submit_bulk(uhci, urb, qh);
break;
case USB_ENDPOINT_XFER_INT:
if (list_empty(&qh->queue)) {
bustime = usb_check_bandwidth(urb->dev, urb);
if (bustime < 0)
ret = bustime;
else {
ret = uhci_submit_interrupt(uhci, urb, qh);
if (ret == 0)
usb_claim_bandwidth(urb->dev, urb, bustime, 0);
}
} else { /* inherit from parent */
struct urb_priv *eurbp;
eurbp = list_entry(qh->queue.prev, struct urb_priv,
node);
urb->bandwidth = eurbp->urb->bandwidth;
ret = uhci_submit_interrupt(uhci, urb, qh);
}
ret = uhci_submit_interrupt(uhci, urb, qh);
break;
case USB_ENDPOINT_XFER_ISOC:
urb->error_count = 0;
bustime = usb_check_bandwidth(urb->dev, urb);
if (bustime < 0) {
ret = bustime;
break;
}
ret = uhci_submit_isochronous(uhci, urb, qh);
if (ret == 0)
usb_claim_bandwidth(urb->dev, urb, bustime, 1);
break;
}
if (ret != 0)
@ -1274,24 +1405,6 @@ __acquires(uhci->lock)
uhci_free_urb_priv(uhci, urbp);
switch (qh->type) {
case USB_ENDPOINT_XFER_ISOC:
/* Release bandwidth for Interrupt or Isoc. transfers */
if (urb->bandwidth)
usb_release_bandwidth(urb->dev, urb, 1);
break;
case USB_ENDPOINT_XFER_INT:
/* Release bandwidth for Interrupt or Isoc. transfers */
/* Make sure we don't release if we have a queued URB */
if (list_empty(&qh->queue) && urb->bandwidth)
usb_release_bandwidth(urb->dev, urb, 0);
else
/* bandwidth was passed on to queued URB, */
/* so don't let usb_unlink_urb() release it */
urb->bandwidth = 0;
break;
}
spin_unlock(&uhci->lock);
usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
spin_lock(&uhci->lock);
@ -1300,9 +1413,8 @@ __acquires(uhci->lock)
* reserved bandwidth. */
if (list_empty(&qh->queue)) {
uhci_unlink_qh(uhci, qh);
/* Bandwidth stuff not yet implemented */
qh->period = 0;
if (qh->bandwidth_reserved)
uhci_release_bandwidth(uhci, qh);
}
}

View File

@ -565,11 +565,15 @@ static void mdc800_usb_disconnect (struct usb_interface *intf)
usb_deregister_dev(intf, &mdc800_class);
/* must be under lock to make sure no URB
is submitted after usb_kill_urb() */
mutex_lock(&mdc800->io_lock);
mdc800->state=NOT_CONNECTED;
usb_kill_urb(mdc800->irq_urb);
usb_kill_urb(mdc800->write_urb);
usb_kill_urb(mdc800->download_urb);
mutex_unlock(&mdc800->io_lock);
mdc800->dev = NULL;
usb_set_intfdata(intf, NULL);

View File

@ -352,3 +352,15 @@ config USB_APPLETOUCH
To compile this driver as a module, choose M here: the
module will be called appletouch.
config USB_GTCO
tristate "GTCO CalComp/InterWrite USB Support"
depends on USB && INPUT
---help---
Say Y here if you want to use the USB version of the GTCO
CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support"
(CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
(CONFIG_INPUT_EVDEV) as well.
To compile this driver as a module, choose M here: the
module will be called gtco.

View File

@ -48,6 +48,7 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o
obj-$(CONFIG_USB_YEALINK) += yealink.o
obj-$(CONFIG_USB_XPAD) += xpad.o
obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o
obj-$(CONFIG_USB_GTCO) += gtco.o
ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG

1104
drivers/usb/input/gtco.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -768,6 +768,9 @@ void usbhid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_PANTHERLORD 0x0810
#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001
#define USB_VENDOR_ID_SONY 0x054c
#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
/*
* Alphabetically sorted blacklist by quirk type.
*/
@ -949,6 +952,8 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
{ 0, 0 }
};
@ -1013,6 +1018,32 @@ static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
}
}
/*
* Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
* to "operational". Without this, the ps3 controller will not report any
* events.
*/
static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
{
int result;
char *buf = kmalloc(18, GFP_KERNEL);
if (!buf)
return;
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
HID_REQ_GET_REPORT,
USB_DIR_IN | USB_TYPE_CLASS |
USB_RECIP_INTERFACE,
(3 << 8) | 0xf2, ifnum, buf, 17,
USB_CTRL_GET_TIMEOUT);
if (result < 0)
err("%s failed: %d\n", __func__, result);
kfree(buf);
}
static struct hid_device *usb_hid_configure(struct usb_interface *intf)
{
struct usb_host_interface *interface = intf->cur_altsetting;
@ -1303,6 +1334,10 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
if ((hid->claimed & HID_CLAIMED_INPUT))
hid_ff_init(hid);
if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
intf->cur_altsetting->desc.bInterfaceNumber);
printk(KERN_INFO);
if (hid->claimed & HID_CLAIMED_INPUT)

View File

@ -269,7 +269,7 @@ static int idmouse_release(struct inode *inode, struct file *file)
/* prevent a race condition with open() */
mutex_lock(&disconnect_mutex);
dev = (struct usb_idmouse *) file->private_data;
dev = file->private_data;
if (dev == NULL) {
mutex_unlock(&disconnect_mutex);
@ -304,17 +304,15 @@ static int idmouse_release(struct inode *inode, struct file *file)
static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count,
loff_t * ppos)
{
struct usb_idmouse *dev;
struct usb_idmouse *dev = file->private_data;
int result;
dev = (struct usb_idmouse *) file->private_data;
/* lock this object */
down (&dev->sem);
down(&dev->sem);
/* verify that the device wasn't unplugged */
if (!dev->present) {
up (&dev->sem);
up(&dev->sem);
return -ENODEV;
}

View File

@ -69,7 +69,7 @@ struct rio_usb_data {
char *obuf, *ibuf; /* transfer buffers */
char bulk_in_ep, bulk_out_ep; /* Endpoint assignments */
wait_queue_head_t wait_q; /* for timeouts */
struct semaphore lock; /* general race avoidance */
struct mutex lock; /* general race avoidance */
};
static struct rio_usb_data rio_instance;
@ -78,17 +78,17 @@ static int open_rio(struct inode *inode, struct file *file)
{
struct rio_usb_data *rio = &rio_instance;
down(&(rio->lock));
mutex_lock(&(rio->lock));
if (rio->isopen || !rio->present) {
up(&(rio->lock));
mutex_unlock(&(rio->lock));
return -EBUSY;
}
rio->isopen = 1;
init_waitqueue_head(&rio->wait_q);
up(&(rio->lock));
mutex_unlock(&(rio->lock));
info("Rio opened.");
@ -117,7 +117,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
int retries;
int retval=0;
down(&(rio->lock));
mutex_lock(&(rio->lock));
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
rio->present == 0 ||
@ -257,7 +257,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
err_out:
up(&(rio->lock));
mutex_unlock(&(rio->lock));
return retval;
}
@ -275,14 +275,17 @@ write_rio(struct file *file, const char __user *buffer,
int result = 0;
int maxretry;
int errn = 0;
int intr;
down(&(rio->lock));
intr = mutex_lock_interruptible(&(rio->lock));
if (intr)
return -EINTR;
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
rio->present == 0 ||
rio->rio_dev == NULL )
{
up(&(rio->lock));
mutex_unlock(&(rio->lock));
return -ENODEV;
}
@ -305,7 +308,7 @@ write_rio(struct file *file, const char __user *buffer,
goto error;
}
if (signal_pending(current)) {
up(&(rio->lock));
mutex_unlock(&(rio->lock));
return bytes_written ? bytes_written : -EINTR;
}
@ -341,12 +344,12 @@ write_rio(struct file *file, const char __user *buffer,
buffer += copy_size;
} while (count > 0);
up(&(rio->lock));
mutex_unlock(&(rio->lock));
return bytes_written ? bytes_written : -EIO;
error:
up(&(rio->lock));
mutex_unlock(&(rio->lock));
return errn;
}
@ -361,14 +364,17 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
int result;
int maxretry = 10;
char *ibuf;
int intr;
down(&(rio->lock));
intr = mutex_lock_interruptible(&(rio->lock));
if (intr)
return -EINTR;
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
rio->present == 0 ||
rio->rio_dev == NULL )
{
up(&(rio->lock));
mutex_unlock(&(rio->lock));
return -ENODEV;
}
@ -379,11 +385,11 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
while (count > 0) {
if (signal_pending(current)) {
up(&(rio->lock));
mutex_unlock(&(rio->lock));
return read_count ? read_count : -EINTR;
}
if (!rio->rio_dev) {
up(&(rio->lock));
mutex_unlock(&(rio->lock));
return -ENODEV;
}
this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
@ -400,7 +406,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
count = this_read = partial;
} else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */
if (!maxretry--) {
up(&(rio->lock));
mutex_unlock(&(rio->lock));
err("read_rio: maxretry timeout");
return -ETIME;
}
@ -409,18 +415,18 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
finish_wait(&rio->wait_q, &wait);
continue;
} else if (result != -EREMOTEIO) {
up(&(rio->lock));
mutex_unlock(&(rio->lock));
err("Read Whoops - result:%u partial:%u this_read:%u",
result, partial, this_read);
return -EIO;
} else {
up(&(rio->lock));
mutex_unlock(&(rio->lock));
return (0);
}
if (this_read) {
if (copy_to_user(buffer, ibuf, this_read)) {
up(&(rio->lock));
mutex_unlock(&(rio->lock));
return -EFAULT;
}
count -= this_read;
@ -428,7 +434,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
buffer += this_read;
}
}
up(&(rio->lock));
mutex_unlock(&(rio->lock));
return read_count;
}
@ -480,7 +486,7 @@ static int probe_rio(struct usb_interface *intf,
}
dbg("probe_rio: ibuf address:%p", rio->ibuf);
init_MUTEX(&(rio->lock));
mutex_init(&(rio->lock));
usb_set_intfdata (intf, rio);
rio->present = 1;
@ -496,12 +502,12 @@ static void disconnect_rio(struct usb_interface *intf)
if (rio) {
usb_deregister_dev(intf, &usb_rio_class);
down(&(rio->lock));
mutex_lock(&(rio->lock));
if (rio->isopen) {
rio->isopen = 0;
/* better let it finish - the release will do whats needed */
rio->rio_dev = NULL;
up(&(rio->lock));
mutex_unlock(&(rio->lock));
return;
}
kfree(rio->ibuf);
@ -510,7 +516,7 @@ static void disconnect_rio(struct usb_interface *intf)
info("USB Rio disconnected.");
rio->present = 0;
up(&(rio->lock));
mutex_unlock(&(rio->lock));
}
}

View File

@ -2,7 +2,7 @@
# Makefile for USB Core files and filesystem
#
usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_dma.o
usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o
# This does not use CONFIG_USB_MON because we want this to use a tristate.
obj-$(CONFIG_USB) += usbmon.o

1172
drivers/usb/mon/mon_bin.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -48,6 +48,36 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
local_irq_restore(flags);
return 0;
}
void mon_dmapeek_vec(const struct mon_reader_bin *rp,
unsigned int offset, dma_addr_t dma_addr, unsigned int length)
{
unsigned long flags;
unsigned int step_len;
struct page *pg;
unsigned char *map;
unsigned long page_off, page_len;
local_irq_save(flags);
while (length) {
/* compute number of bytes we are going to copy in this page */
step_len = length;
page_off = dma_addr & (PAGE_SIZE-1);
page_len = PAGE_SIZE - page_off;
if (page_len < step_len)
step_len = page_len;
/* copy data and advance pointers */
pg = phys_to_page(dma_addr);
map = kmap_atomic(pg, KM_IRQ0);
offset = mon_copy_to_buff(rp, offset, map + page_off, step_len);
kunmap_atomic(map, KM_IRQ0);
dma_addr += step_len;
length -= step_len;
}
local_irq_restore(flags);
}
#endif /* __i386__ */
#ifndef MON_HAS_UNMAP
@ -55,4 +85,11 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
{
return 'D';
}
#endif
void mon_dmapeek_vec(const struct mon_reader_bin *rp,
unsigned int offset, dma_addr_t dma_addr, unsigned int length)
{
;
}
#endif /* MON_HAS_UNMAP */

View File

@ -9,7 +9,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/debugfs.h>
#include <linux/smp_lock.h>
#include <linux/notifier.h>
#include <linux/mutex.h>
@ -22,11 +21,10 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb);
static void mon_stop(struct mon_bus *mbus);
static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
static void mon_bus_drop(struct kref *r);
static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
static void mon_bus_init(struct usb_bus *ubus);
DEFINE_MUTEX(mon_lock);
static struct dentry *mon_dir; /* /dbg/usbmon */
static LIST_HEAD(mon_buses); /* All buses we know: struct mon_bus */
/*
@ -200,7 +198,7 @@ static void mon_stop(struct mon_bus *mbus)
*/
static void mon_bus_add(struct usb_bus *ubus)
{
mon_bus_init(mon_dir, ubus);
mon_bus_init(ubus);
}
/*
@ -212,8 +210,8 @@ static void mon_bus_remove(struct usb_bus *ubus)
mutex_lock(&mon_lock);
list_del(&mbus->bus_link);
debugfs_remove(mbus->dent_t);
debugfs_remove(mbus->dent_s);
if (mbus->text_inited)
mon_text_del(mbus);
mon_dissolve(mbus, ubus);
kref_put(&mbus->ref, mon_bus_drop);
@ -281,13 +279,9 @@ static void mon_bus_drop(struct kref *r)
* - refcount USB bus struct
* - link
*/
static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
static void mon_bus_init(struct usb_bus *ubus)
{
struct dentry *d;
struct mon_bus *mbus;
enum { NAMESZ = 10 };
char name[NAMESZ];
int rc;
if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
goto err_alloc;
@ -303,57 +297,54 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
ubus->mon_bus = mbus;
mbus->uses_dma = ubus->uses_dma;
rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
if (rc <= 0 || rc >= NAMESZ)
goto err_print_t;
d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text);
if (d == NULL)
goto err_create_t;
mbus->dent_t = d;
rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
if (rc <= 0 || rc >= NAMESZ)
goto err_print_s;
d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat);
if (d == NULL)
goto err_create_s;
mbus->dent_s = d;
mbus->text_inited = mon_text_add(mbus, ubus);
// mon_bin_add(...)
mutex_lock(&mon_lock);
list_add_tail(&mbus->bus_link, &mon_buses);
mutex_unlock(&mon_lock);
return;
err_create_s:
err_print_s:
debugfs_remove(mbus->dent_t);
err_create_t:
err_print_t:
kfree(mbus);
err_alloc:
return;
}
/*
* Search a USB bus by number. Notice that USB bus numbers start from one,
* which we may later use to identify "all" with zero.
*
* This function must be called with mon_lock held.
*
* This is obviously inefficient and may be revised in the future.
*/
struct mon_bus *mon_bus_lookup(unsigned int num)
{
struct list_head *p;
struct mon_bus *mbus;
list_for_each (p, &mon_buses) {
mbus = list_entry(p, struct mon_bus, bus_link);
if (mbus->u_bus->busnum == num) {
return mbus;
}
}
return NULL;
}
static int __init mon_init(void)
{
struct usb_bus *ubus;
struct dentry *mondir;
int rc;
mondir = debugfs_create_dir("usbmon", NULL);
if (IS_ERR(mondir)) {
printk(KERN_NOTICE TAG ": debugfs is not available\n");
return -ENODEV;
}
if (mondir == NULL) {
printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
return -ENODEV;
}
mon_dir = mondir;
if ((rc = mon_text_init()) != 0)
goto err_text;
if ((rc = mon_bin_init()) != 0)
goto err_bin;
if (usb_mon_register(&mon_ops_0) != 0) {
printk(KERN_NOTICE TAG ": unable to register with the core\n");
debugfs_remove(mondir);
return -ENODEV;
rc = -ENODEV;
goto err_reg;
}
// MOD_INC_USE_COUNT(which_module?);
@ -361,10 +352,17 @@ static int __init mon_init(void)
mutex_lock(&usb_bus_list_lock);
list_for_each_entry (ubus, &usb_bus_list, bus_list) {
mon_bus_init(mondir, ubus);
mon_bus_init(ubus);
}
mutex_unlock(&usb_bus_list_lock);
return 0;
err_reg:
mon_bin_exit();
err_bin:
mon_text_exit();
err_text:
return rc;
}
static void __exit mon_exit(void)
@ -381,8 +379,8 @@ static void __exit mon_exit(void)
mbus = list_entry(p, struct mon_bus, bus_link);
list_del(p);
debugfs_remove(mbus->dent_t);
debugfs_remove(mbus->dent_s);
if (mbus->text_inited)
mon_text_del(mbus);
/*
* This never happens, because the open/close paths in
@ -401,7 +399,8 @@ static void __exit mon_exit(void)
}
mutex_unlock(&mon_lock);
debugfs_remove(mon_dir);
mon_text_exit();
mon_bin_exit();
}
module_init(mon_init);

View File

@ -9,6 +9,7 @@
#include <linux/usb.h>
#include <linux/time.h>
#include <linux/mutex.h>
#include <linux/debugfs.h>
#include <asm/uaccess.h>
#include "usb_mon.h"
@ -63,6 +64,8 @@ struct mon_reader_text {
char slab_name[SLAB_NAME_SZ];
};
static struct dentry *mon_dir; /* Usually /sys/kernel/debug/usbmon */
static void mon_text_ctor(void *, struct kmem_cache *, unsigned long);
/*
@ -436,7 +439,7 @@ static int mon_text_release(struct inode *inode, struct file *file)
return 0;
}
const struct file_operations mon_fops_text = {
static const struct file_operations mon_fops_text = {
.owner = THIS_MODULE,
.open = mon_text_open,
.llseek = no_llseek,
@ -447,6 +450,47 @@ const struct file_operations mon_fops_text = {
.release = mon_text_release,
};
int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
{
struct dentry *d;
enum { NAMESZ = 10 };
char name[NAMESZ];
int rc;
rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
if (rc <= 0 || rc >= NAMESZ)
goto err_print_t;
d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text);
if (d == NULL)
goto err_create_t;
mbus->dent_t = d;
/* XXX The stats do not belong to here (text API), but oh well... */
rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
if (rc <= 0 || rc >= NAMESZ)
goto err_print_s;
d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat);
if (d == NULL)
goto err_create_s;
mbus->dent_s = d;
return 1;
err_create_s:
err_print_s:
debugfs_remove(mbus->dent_t);
mbus->dent_t = NULL;
err_create_t:
err_print_t:
return 0;
}
void mon_text_del(struct mon_bus *mbus)
{
debugfs_remove(mbus->dent_t);
debugfs_remove(mbus->dent_s);
}
/*
* Slab interface: constructor.
*/
@ -459,3 +503,24 @@ static void mon_text_ctor(void *mem, struct kmem_cache *slab, unsigned long sfla
memset(mem, 0xe5, sizeof(struct mon_event_text));
}
int __init mon_text_init(void)
{
struct dentry *mondir;
mondir = debugfs_create_dir("usbmon", NULL);
if (IS_ERR(mondir)) {
printk(KERN_NOTICE TAG ": debugfs is not available\n");
return -ENODEV;
}
if (mondir == NULL) {
printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
return -ENODEV;
}
mon_dir = mondir;
return 0;
}
void __exit mon_text_exit(void)
{
debugfs_remove(mon_dir);
}

View File

@ -17,9 +17,11 @@
struct mon_bus {
struct list_head bus_link;
spinlock_t lock;
struct usb_bus *u_bus;
int text_inited;
struct dentry *dent_s; /* Debugging file */
struct dentry *dent_t; /* Text interface file */
struct usb_bus *u_bus;
int uses_dma;
/* Ref */
@ -48,13 +50,35 @@ struct mon_reader {
void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
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, const struct usb_bus *ubus);
void mon_text_del(struct mon_bus *mbus);
// void mon_bin_add(struct mon_bus *);
int __init mon_text_init(void);
void __exit mon_text_exit(void);
int __init mon_bin_init(void);
void __exit mon_bin_exit(void);
/*
*/
* DMA interface.
*
* XXX The vectored side needs a serious re-thinking. Abstracting vectors,
* like in Paolo's original patch, produces a double pkmap. We need an idea.
*/
extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
struct mon_reader_bin;
extern void mon_dmapeek_vec(const struct mon_reader_bin *rp,
unsigned int offset, dma_addr_t dma_addr, unsigned int len);
extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp,
unsigned int offset, const unsigned char *from, unsigned int len);
/*
*/
extern struct mutex mon_lock;
extern const struct file_operations mon_fops_text;
extern const struct file_operations mon_fops_stat;
#endif /* __USB_MON_H */

View File

@ -222,13 +222,15 @@ config USB_NET_MCS7830
adapters marketed under the DeLOCK brand.
config USB_NET_RNDIS_HOST
tristate "Host for RNDIS devices (EXPERIMENTAL)"
tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)"
depends on USB_USBNET && EXPERIMENTAL
select USB_NET_CDCETHER
help
This option enables hosting "Remote NDIS" USB networking links,
as encouraged by Microsoft (instead of CDC Ethernet!) for use in
various devices that may only support this protocol.
various devices that may only support this protocol. A variant
of this protocol (with even less public documentation) seems to
be at the root of Microsoft's "ActiveSync" too.
Avoid using this protocol unless you have no better options.
The protocol specification is incomplete, and is controlled by

View File

@ -1,6 +1,7 @@
/*
* CDC Ethernet based networking peripherals
* Copyright (C) 2003-2005 by David Brownell
* Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
*
* 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
@ -35,6 +36,29 @@
#include "usbnet.h"
#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
static int is_rndis(struct usb_interface_descriptor *desc)
{
return desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
&& desc->bInterfaceProtocol == 0xff;
}
static int is_activesync(struct usb_interface_descriptor *desc)
{
return desc->bInterfaceClass == USB_CLASS_MISC
&& desc->bInterfaceSubClass == 1
&& desc->bInterfaceProtocol == 1;
}
#else
#define is_rndis(desc) 0
#define is_activesync(desc) 0
#endif
/*
* probes control interface, claims data interface, collects the bulk
* endpoints, activates data interface (if needed), maybe sets MTU.
@ -71,7 +95,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
/* this assumes that if there's a non-RNDIS vendor variant
* of cdc-acm, it'll fail RNDIS requests cleanly.
*/
rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
rndis = is_rndis(&intf->cur_altsetting->desc)
|| is_activesync(&intf->cur_altsetting->desc);
memset(info, 0, sizeof *info);
info->control = intf;
@ -99,6 +124,23 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
goto bad_desc;
}
break;
case USB_CDC_ACM_TYPE:
/* paranoia: disambiguate a "real" vendor-specific
* modem interface from an RNDIS non-modem.
*/
if (rndis) {
struct usb_cdc_acm_descriptor *d;
d = (void *) buf;
if (d->bmCapabilities) {
dev_dbg(&intf->dev,
"ACM capabilities %02x, "
"not really RNDIS?\n",
d->bmCapabilities);
goto bad_desc;
}
}
break;
case USB_CDC_UNION_TYPE:
if (info->u) {
dev_dbg(&intf->dev, "extra CDC union\n");
@ -171,7 +213,21 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
buf += buf [0];
}
if (!info->header || !info->u || (!rndis && !info->ether)) {
/* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
* so we'll hard-wire the interfaces and not check for descriptors.
*/
if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
info->control = usb_ifnum_to_if(dev->udev, 0);
info->data = usb_ifnum_to_if(dev->udev, 1);
if (!info->control || !info->data) {
dev_dbg(&intf->dev,
"activesync: master #0/%p slave #1/%p\n",
info->control,
info->data);
goto bad_desc;
}
} else if (!info->header || !info->u || (!rndis && !info->ether)) {
dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
info->header ? "" : "header ",
info->u ? "" : "union ",

View File

@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = {
.suspend = kaweth_suspend,
.resume = kaweth_resume,
.id_table = usb_klsi_table,
.supports_autosuspend = 1,
};
typedef __u8 eth_addr_t[6];
@ -225,6 +226,7 @@ struct kaweth_device
struct delayed_work lowmem_work;
struct usb_device *dev;
struct usb_interface *intf;
struct net_device *net;
wait_queue_head_t term_wait;
@ -662,9 +664,14 @@ static int kaweth_open(struct net_device *net)
dbg("Opening network device.");
res = usb_autopm_get_interface(kaweth->intf);
if (res) {
err("Interface cannot be resumed.");
return -EIO;
}
res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
if (res)
return -EIO;
goto err_out;
usb_fill_int_urb(
kaweth->irq_urb,
@ -681,7 +688,7 @@ static int kaweth_open(struct net_device *net)
res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
if (res) {
usb_kill_urb(kaweth->rx_urb);
return -EIO;
goto err_out;
}
kaweth->opened = 1;
@ -689,10 +696,14 @@ static int kaweth_open(struct net_device *net)
kaweth_async_set_rx_mode(kaweth);
return 0;
err_out:
usb_autopm_enable(kaweth->intf);
return -EIO;
}
/****************************************************************
* kaweth_close
* kaweth_kill_urbs
****************************************************************/
static void kaweth_kill_urbs(struct kaweth_device *kaweth)
{
@ -724,17 +735,29 @@ static int kaweth_close(struct net_device *net)
kaweth->status &= ~KAWETH_STATUS_CLOSING;
usb_autopm_enable(kaweth->intf);
return 0;
}
static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct kaweth_device *kaweth = netdev_priv(dev);
strlcpy(info->driver, driver_name, sizeof(info->driver));
usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info));
}
static u32 kaweth_get_link(struct net_device *dev)
{
struct kaweth_device *kaweth = netdev_priv(dev);
return kaweth->linkstate;
}
static struct ethtool_ops ops = {
.get_drvinfo = kaweth_get_drvinfo
.get_drvinfo = kaweth_get_drvinfo,
.get_link = kaweth_get_link
};
/****************************************************************
@ -908,6 +931,7 @@ static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
struct kaweth_device *kaweth = usb_get_intfdata(intf);
unsigned long flags;
dbg("Suspending device");
spin_lock_irqsave(&kaweth->device_lock, flags);
kaweth->status |= KAWETH_STATUS_SUSPENDING;
spin_unlock_irqrestore(&kaweth->device_lock, flags);
@ -924,6 +948,7 @@ static int kaweth_resume(struct usb_interface *intf)
struct kaweth_device *kaweth = usb_get_intfdata(intf);
unsigned long flags;
dbg("Resuming device");
spin_lock_irqsave(&kaweth->device_lock, flags);
kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
spin_unlock_irqrestore(&kaweth->device_lock, flags);
@ -1086,6 +1111,8 @@ static int kaweth_probe(
dbg("Initializing net device.");
kaweth->intf = intf;
kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kaweth->tx_urb)
goto err_free_netdev;
@ -1265,7 +1292,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
{
struct urb *urb;
int retv;
int length;
int length = 0; /* shut up GCC */
urb = usb_alloc_urb(0, GFP_NOIO);
if (!urb)

View File

@ -49,6 +49,8 @@
* - In some cases, MS-Windows will emit undocumented requests; this
* matters more to peripheral implementations than host ones.
*
* Moreover there's a no-open-specs variant of RNDIS called "ActiveSync".
*
* For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in
* favor of such non-proprietary alternatives as CDC Ethernet or the newer (and
* currently rare) "Ethernet Emulation Model" (EEM).
@ -61,6 +63,9 @@
* - control-in: GET_ENCAPSULATED
*
* We'll try to ignore the RESPONSE_AVAILABLE notifications.
*
* REVISIT some RNDIS implementations seem to have curious issues still
* to be resolved.
*/
struct rndis_msg_hdr {
__le32 msg_type; /* RNDIS_MSG_* */
@ -71,8 +76,14 @@ struct rndis_msg_hdr {
// ... and more
} __attribute__ ((packed));
/* RNDIS defines this (absurdly huge) control timeout */
#define RNDIS_CONTROL_TIMEOUT_MS (10 * 1000)
/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
#define CONTROL_BUFFER_SIZE 1025
/* RNDIS defines an (absurdly huge) 10 second control timeout,
* but ActiveSync seems to use a more usual 5 second timeout
* (which matches the USB 2.0 spec).
*/
#define RNDIS_CONTROL_TIMEOUT_MS (5 * 1000)
#define ccpu2 __constant_cpu_to_le32
@ -270,6 +281,7 @@ static void rndis_status(struct usbnet *dev, struct urb *urb)
static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
{
struct cdc_state *info = (void *) &dev->data;
int master_ifnum;
int retval;
unsigned count;
__le32 rsp;
@ -279,7 +291,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
* disconnect(): either serialize, or dispatch responses on xid
*/
/* Issue the request; don't bother byteswapping our xid */
/* Issue the request; xid is unique, don't bother byteswapping it */
if (likely(buf->msg_type != RNDIS_MSG_HALT
&& buf->msg_type != RNDIS_MSG_RESET)) {
xid = dev->xid++;
@ -287,11 +299,12 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
xid = dev->xid++;
buf->request_id = (__force __le32) xid;
}
master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber;
retval = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
USB_CDC_SEND_ENCAPSULATED_COMMAND,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, info->u->bMasterInterface0,
0, master_ifnum,
buf, le32_to_cpu(buf->msg_len),
RNDIS_CONTROL_TIMEOUT_MS);
if (unlikely(retval < 0 || xid == 0))
@ -306,13 +319,13 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
*/
rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
for (count = 0; count < 10; count++) {
memset(buf, 0, 1024);
memset(buf, 0, CONTROL_BUFFER_SIZE);
retval = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
USB_CDC_GET_ENCAPSULATED_RESPONSE,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, info->u->bMasterInterface0,
buf, 1024,
0, master_ifnum,
buf, CONTROL_BUFFER_SIZE,
RNDIS_CONTROL_TIMEOUT_MS);
if (likely(retval >= 8)) {
msg_len = le32_to_cpu(buf->msg_len);
@ -350,7 +363,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
usb_sndctrlpipe(dev->udev, 0),
USB_CDC_SEND_ENCAPSULATED_COMMAND,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, info->u->bMasterInterface0,
0, master_ifnum,
msg, sizeof *msg,
RNDIS_CONTROL_TIMEOUT_MS);
if (unlikely(retval < 0))
@ -393,38 +406,64 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
u32 tmp;
/* we can't rely on i/o from stack working, or stack allocation */
u.buf = kmalloc(1024, GFP_KERNEL);
u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
if (!u.buf)
return -ENOMEM;
retval = usbnet_generic_cdc_bind(dev, intf);
if (retval < 0)
goto fail;
net->hard_header_len += sizeof (struct rndis_data_hdr);
/* initialize; max transfer is 16KB at full speed */
u.init->msg_type = RNDIS_MSG_INIT;
u.init->msg_len = ccpu2(sizeof *u.init);
u.init->major_version = ccpu2(1);
u.init->minor_version = ccpu2(0);
u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len);
/* max transfer (in spec) is 0x4000 at full speed, but for
* TX we'll stick to one Ethernet packet plus RNDIS framing.
* For RX we handle drivers that zero-pad to end-of-packet.
* Don't let userspace change these settings.
*/
net->hard_header_len += sizeof (struct rndis_data_hdr);
dev->hard_mtu = net->mtu + net->hard_header_len;
dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
dev->rx_urb_size &= ~(dev->maxpacket - 1);
u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);
net->change_mtu = NULL;
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
/* it might not even be an RNDIS device!! */
dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
goto fail_and_release;
}
tmp = le32_to_cpu(u.init_c->max_transfer_size);
if (tmp < dev->hard_mtu) {
dev_err(&intf->dev,
"dev can't take %u byte packets (max %u)\n",
dev->hard_mtu, tmp);
goto fail_and_release;
}
dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size);
/* REVISIT: peripheral "alignment" request is ignored ... */
dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
dev_dbg(&intf->dev,
"hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
dev->hard_mtu, tmp, dev->rx_urb_size,
1 << le32_to_cpu(u.init_c->packet_alignment));
/* get designated host ethernet address */
memset(u.get, 0, sizeof *u.get);
/* Get designated host ethernet address.
*
* Adding a payload exactly the same size as the expected response
* payload is an evident requirement MSFT added for ActiveSync.
* This undocumented (and nonsensical) issue was found by sniffing
* protocol requests from the ActiveSync 4.1 Windows driver.
*/
memset(u.get, 0, sizeof *u.get + 48);
u.get->msg_type = RNDIS_MSG_QUERY;
u.get->msg_len = ccpu2(sizeof *u.get);
u.get->msg_len = ccpu2(sizeof *u.get + 48);
u.get->oid = OID_802_3_PERMANENT_ADDRESS;
u.get->len = ccpu2(48);
u.get->offset = ccpu2(20);
retval = rndis_command(dev, u.header);
if (unlikely(retval < 0)) {
@ -432,7 +471,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
goto fail_and_release;
}
tmp = le32_to_cpu(u.get_c->offset);
if (unlikely((tmp + 8) > (1024 - ETH_ALEN)
if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN)
|| u.get_c->len != ccpu2(ETH_ALEN))) {
dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
tmp, le32_to_cpu(u.get_c->len));
@ -598,6 +637,10 @@ static const struct usb_device_id products [] = {
/* RNDIS is MSFT's un-official variant of CDC ACM */
USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
.driver_info = (unsigned long) &rndis_info,
}, {
/* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
.driver_info = (unsigned long) &rndis_info,
},
{ }, // END
};

View File

@ -572,8 +572,20 @@ static void aircable_unthrottle(struct usb_serial_port *port)
schedule_work(&priv->rx_work);
}
static struct usb_driver aircable_driver = {
.name = "aircable",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
.no_dynamic_id = 1,
};
static struct usb_serial_driver aircable_device = {
.description = "aircable",
.driver = {
.owner = THIS_MODULE,
.name = "aircable",
},
.usb_driver = &aircable_driver,
.id_table = id_table,
.num_ports = 1,
.attach = aircable_attach,
@ -587,13 +599,6 @@ static struct usb_serial_driver aircable_device = {
.unthrottle = aircable_unthrottle,
};
static struct usb_driver aircable_driver = {
.name = "aircable",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
};
static int __init aircable_init (void)
{
int retval;

View File

@ -277,6 +277,7 @@ static struct usb_serial_driver airprime_device = {
.owner = THIS_MODULE,
.name = "airprime",
},
.usb_driver = &airprime_driver,
.id_table = id_table,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,

View File

@ -444,6 +444,7 @@ static struct usb_driver ark3116_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
.no_dynamic_id = 1,
};
static struct usb_serial_driver ark3116_device = {
@ -452,6 +453,7 @@ static struct usb_serial_driver ark3116_device = {
.name = "ark3116",
},
.id_table = id_table,
.usb_driver = &ark3116_driver,
.num_interrupt_in = 1,
.num_bulk_in = 1,
.num_bulk_out = 1,

View File

@ -126,6 +126,7 @@ static struct usb_serial_driver belkin_device = {
.name = "belkin",
},
.description = "Belkin / Peracom / GoHubs USB Serial Adapter",
.usb_driver = &belkin_driver,
.id_table = id_table_combined,
.num_interrupt_in = 1,
.num_bulk_in = 1,

View File

@ -103,11 +103,52 @@ static int usb_serial_device_remove (struct device *dev)
return retval;
}
#ifdef CONFIG_HOTPLUG
static ssize_t store_new_id(struct device_driver *driver,
const char *buf, size_t count)
{
struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
if (retval >= 0 && usb_drv->usb_driver != NULL)
retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
&usb_drv->usb_driver->drvwrap.driver,
buf, count);
return retval;
}
static struct driver_attribute drv_attrs[] = {
__ATTR(new_id, S_IWUSR, NULL, store_new_id),
__ATTR_NULL,
};
static void free_dynids(struct usb_serial_driver *drv)
{
struct usb_dynid *dynid, *n;
spin_lock(&drv->dynids.lock);
list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
list_del(&dynid->node);
kfree(dynid);
}
spin_unlock(&drv->dynids.lock);
}
#else
static struct driver_attribute drv_attrs[] = {
__ATTR_NULL,
};
static inline void free_dynids(struct usb_driver *drv)
{
}
#endif
struct bus_type usb_serial_bus_type = {
.name = "usb-serial",
.match = usb_serial_device_match,
.probe = usb_serial_device_probe,
.remove = usb_serial_device_remove,
.drv_attrs = drv_attrs,
};
int usb_serial_bus_register(struct usb_serial_driver *driver)
@ -115,6 +156,9 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
int retval;
driver->driver.bus = &usb_serial_bus_type;
spin_lock_init(&driver->dynids.lock);
INIT_LIST_HEAD(&driver->dynids.list);
retval = driver_register(&driver->driver);
return retval;
@ -122,6 +166,7 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
void usb_serial_bus_deregister(struct usb_serial_driver *driver)
{
free_dynids(driver);
driver_unregister(&driver->driver);
}

View File

@ -89,6 +89,7 @@ static struct usb_serial_driver cp2101_device = {
.owner = THIS_MODULE,
.name = "cp2101",
},
.usb_driver = &cp2101_driver,
.id_table = id_table,
.num_interrupt_in = 0,
.num_bulk_in = 0,

View File

@ -88,6 +88,7 @@ static struct usb_serial_driver cyberjack_device = {
.name = "cyberjack",
},
.description = "Reiner SCT Cyberjack USB card reader",
.usb_driver = &cyberjack_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@ -98,7 +99,7 @@ static struct usb_serial_driver cyberjack_device = {
.open = cyberjack_open,
.close = cyberjack_close,
.write = cyberjack_write,
.write_room = cyberjack_write_room,
.write_room = cyberjack_write_room,
.read_int_callback = cyberjack_read_int_callback,
.read_bulk_callback = cyberjack_read_bulk_callback,
.write_bulk_callback = cyberjack_write_bulk_callback,

View File

@ -193,6 +193,7 @@ static struct usb_serial_driver cypress_earthmate_device = {
.name = "earthmate",
},
.description = "DeLorme Earthmate USB",
.usb_driver = &cypress_driver,
.id_table = id_table_earthmate,
.num_interrupt_in = 1,
.num_interrupt_out = 1,
@ -222,6 +223,7 @@ static struct usb_serial_driver cypress_hidcom_device = {
.name = "cyphidcom",
},
.description = "HID->COM RS232 Adapter",
.usb_driver = &cypress_driver,
.id_table = id_table_cyphidcomrs232,
.num_interrupt_in = 1,
.num_interrupt_out = 1,
@ -251,6 +253,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.name = "nokiaca42v2",
},
.description = "Nokia CA-42 V2 Adapter",
.usb_driver = &cypress_driver,
.id_table = id_table_nokiaca42v2,
.num_interrupt_in = 1,
.num_interrupt_out = 1,

View File

@ -509,6 +509,7 @@ static struct usb_serial_driver digi_acceleport_2_device = {
.name = "digi_2",
},
.description = "Digi 2 port USB adapter",
.usb_driver = &digi_driver,
.id_table = id_table_2,
.num_interrupt_in = 0,
.num_bulk_in = 4,
@ -538,6 +539,7 @@ static struct usb_serial_driver digi_acceleport_4_device = {
.name = "digi_4",
},
.description = "Digi 4 port USB adapter",
.usb_driver = &digi_driver,
.id_table = id_table_4,
.num_interrupt_in = 0,
.num_bulk_in = 5,

View File

@ -117,6 +117,7 @@ static struct usb_serial_driver empeg_device = {
.name = "empeg",
},
.id_table = id_table,
.usb_driver = &empeg_driver,
.num_interrupt_in = 0,
.num_bulk_in = 1,
.num_bulk_out = 1,

View File

@ -464,7 +464,6 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
{ USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
@ -615,6 +614,7 @@ static struct usb_serial_driver ftdi_sio_device = {
.name = "ftdi_sio",
},
.description = "FTDI USB Serial Device",
.usb_driver = &ftdi_driver ,
.id_table = id_table_combined,
.num_interrupt_in = 0,
.num_bulk_in = 1,

View File

@ -364,7 +364,6 @@
* USB-TTY activ, USB-TTY passiv. Some PIDs are used by several devices
* and I'm not entirely sure which are used by which.
*/
#define FTDI_4N_GALAXY_DE_0_PID 0x8372
#define FTDI_4N_GALAXY_DE_1_PID 0xF3C0
#define FTDI_4N_GALAXY_DE_2_PID 0xF3C1

View File

@ -58,6 +58,7 @@ static struct usb_serial_driver funsoft_device = {
.name = "funsoft",
},
.id_table = id_table,
.usb_driver = &funsoft_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,

View File

@ -1566,6 +1566,7 @@ static struct usb_serial_driver garmin_device = {
.name = "garmin_gps",
},
.description = "Garmin GPS usb/tty",
.usb_driver = &garmin_driver,
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,

View File

@ -20,6 +20,10 @@
#include <linux/usb/serial.h>
#include <asm/uaccess.h>
static int generic_probe(struct usb_interface *interface,
const struct usb_device_id *id);
static int debug;
#ifdef CONFIG_USB_SERIAL_GENERIC
@ -34,6 +38,21 @@ MODULE_PARM_DESC(product, "User specified USB idProduct");
static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
/* we want to look at all devices, as the vendor/product id can change
* depending on the command line argument */
static struct usb_device_id generic_serial_ids[] = {
{.driver_info = 42},
{}
};
static struct usb_driver generic_driver = {
.name = "usbserial_generic",
.probe = generic_probe,
.disconnect = usb_serial_disconnect,
.id_table = generic_serial_ids,
.no_dynamic_id = 1,
};
/* All of the device info needed for the Generic Serial Converter */
struct usb_serial_driver usb_serial_generic_device = {
.driver = {
@ -41,6 +60,7 @@ struct usb_serial_driver usb_serial_generic_device = {
.name = "generic",
},
.id_table = generic_device_ids,
.usb_driver = &generic_driver,
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
@ -48,13 +68,6 @@ struct usb_serial_driver usb_serial_generic_device = {
.shutdown = usb_serial_generic_shutdown,
};
/* we want to look at all devices, as the vendor/product id can change
* depending on the command line argument */
static struct usb_device_id generic_serial_ids[] = {
{.driver_info = 42},
{}
};
static int generic_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
@ -65,14 +78,6 @@ static int generic_probe(struct usb_interface *interface,
return usb_serial_probe(interface, id);
return -ENODEV;
}
static struct usb_driver generic_driver = {
.name = "usbserial_generic",
.probe = generic_probe,
.disconnect = usb_serial_disconnect,
.id_table = generic_serial_ids,
.no_dynamic_id = 1,
};
#endif
int usb_serial_generic_register (int _debug)

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