mirror of https://gitee.com/openkylin/linux.git
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:
commit
c96e2c9207
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 */ \
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------*/
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 *) ðer_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 *) ðer_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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
/*
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
};
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ",
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue