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

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (142 commits)
  USB: Fix sysfs paths in documentation
  USB: skeleton: fix coding style issues.
  USB: O_NONBLOCK in read path of skeleton
  USB: make usb-skeleton honor O_NONBLOCK in write path
  USB: skel_read really sucks royally
  USB: Add hub descriptor update hook for xHCI
  USB: xhci: Support USB hubs.
  USB: xhci: Set multi-TT field for LS/FS devices under hubs.
  USB: xhci: Set route string for all devices.
  USB: xhci: Fix command wait list handling.
  USB: xhci: Change how xHCI commands are handled.
  USB: xhci: Refactor input device context setup.
  USB: xhci: Endpoint representation refactoring.
  USB: gadget: ether needs to select CRC32
  USB: fix USBTMC get_capabilities success handling
  USB: fix missing error check in probing
  USB: usbfs: add USBDEVFS_URB_BULK_CONTINUATION flag
  USB: support for autosuspend in sierra while online
  USB: ehci-dbgp,ehci: Allow dbpg to work with suspend/resume
  USB: ehci-dbgp,documentation: Documentation updates for ehci-dbgp
  ...
This commit is contained in:
Linus Torvalds 2009-09-23 09:25:16 -07:00
commit be90a49ca2
126 changed files with 9590 additions and 2124 deletions

View File

@ -671,7 +671,7 @@ and is between 256 and 4096 characters. It is defined in the file
earlyprintk= [X86,SH,BLACKFIN] earlyprintk= [X86,SH,BLACKFIN]
earlyprintk=vga earlyprintk=vga
earlyprintk=serial[,ttySn[,baudrate]] earlyprintk=serial[,ttySn[,baudrate]]
earlyprintk=dbgp earlyprintk=dbgp[debugController#]
Append ",keep" to not disable it when the real console Append ",keep" to not disable it when the real console
takes over. takes over.

View File

@ -16,20 +16,20 @@ Usage:
Authorize a device to connect: Authorize a device to connect:
$ echo 1 > /sys/usb/devices/DEVICE/authorized $ echo 1 > /sys/bus/usb/devices/DEVICE/authorized
Deauthorize a device: Deauthorize a device:
$ echo 0 > /sys/usb/devices/DEVICE/authorized $ echo 0 > /sys/bus/usb/devices/DEVICE/authorized
Set new devices connected to hostX to be deauthorized by default (ie: Set new devices connected to hostX to be deauthorized by default (ie:
lock down): lock down):
$ echo 0 > /sys/bus/devices/usbX/authorized_default $ echo 0 > /sys/bus/usb/devices/usbX/authorized_default
Remove the lock down: Remove the lock down:
$ echo 1 > /sys/bus/devices/usbX/authorized_default $ echo 1 > /sys/bus/usb/devices/usbX/authorized_default
By default, Wired USB devices are authorized by default to By default, Wired USB devices are authorized by default to
connect. Wireless USB hosts deauthorize by default all new connected connect. Wireless USB hosts deauthorize by default all new connected
@ -47,7 +47,7 @@ USB port):
boot up boot up
rc.local -> rc.local ->
for host in /sys/bus/devices/usb* for host in /sys/bus/usb/devices/usb*
do do
echo 0 > $host/authorized_default echo 0 > $host/authorized_default
done done

View File

@ -33,7 +33,7 @@ if usbmon is built into the kernel.
Verify that bus sockets are present. Verify that bus sockets are present.
# ls /sys/kernel/debug/usbmon # ls /sys/kernel/debug/usb/usbmon
0s 0u 1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u 0s 0u 1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u
# #
@ -58,11 +58,11 @@ Bus=03 means it's bus 3.
3. Start 'cat' 3. Start 'cat'
# cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out # cat /sys/kernel/debug/usb/usbmon/3u > /tmp/1.mon.out
to listen on a single bus, otherwise, to listen on all buses, type: to listen on a single bus, otherwise, to listen on all buses, type:
# cat /sys/kernel/debug/usbmon/0u > /tmp/1.mon.out # cat /sys/kernel/debug/usb/usbmon/0u > /tmp/1.mon.out
This process will be reading until killed. Naturally, the output can be This process will be reading until killed. Naturally, the output can be
redirected to a desirable location. This is preferred, because it is going redirected to a desirable location. This is preferred, because it is going
@ -305,7 +305,7 @@ 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 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. the data, if any. The event is removed from the kernel buffer.
The MON_IOCX_GET copies 48 bytes, MON_IOCX_GETX copies 64 bytes. The MON_IOCX_GET copies 48 bytes to hdr area, MON_IOCX_GETX copies 64 bytes.
MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg) MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg)

View File

@ -7,7 +7,7 @@ and two USB cables, connected like this:
[host/target] <-------> [USB debug key] <-------> [client/console] [host/target] <-------> [USB debug key] <-------> [client/console]
1. There are three specific hardware requirements: 1. There are a number of specific hardware requirements:
a.) Host/target system needs to have USB debug port capability. a.) Host/target system needs to have USB debug port capability.
@ -42,7 +42,35 @@ and two USB cables, connected like this:
This is a small blue plastic connector with two USB connections, This is a small blue plastic connector with two USB connections,
it draws power from its USB connections. it draws power from its USB connections.
c.) Thirdly, you need a second client/console system with a regular USB port. c.) You need a second client/console system with a high speed USB 2.0
port.
d.) The Netchip device must be plugged directly into the physical
debug port on the "host/target" system. You cannot use a USB hub in
between the physical debug port and the "host/target" system.
The EHCI debug controller is bound to a specific physical USB
port and the Netchip device will only work as an early printk
device in this port. The EHCI host controllers are electrically
wired such that the EHCI debug controller is hooked up to the
first physical and there is no way to change this via software.
You can find the physical port through experimentation by trying
each physical port on the system and rebooting. Or you can try
and use lsusb or look at the kernel info messages emitted by the
usb stack when you plug a usb device into various ports on the
"host/target" system.
Some hardware vendors do not expose the usb debug port with a
physical connector and if you find such a device send a complaint
to the hardware vendor, because there is no reason not to wire
this port into one of the physically accessible ports.
e.) It is also important to note, that many versions of the Netchip
device require the "client/console" system to be plugged into the
right and side of the device (with the product logo facing up and
readable left to right). The reason being is that the 5 volt
power supply is taken from only one side of the device and it
must be the side that does not get rebooted.
2. Software requirements: 2. Software requirements:
@ -56,6 +84,13 @@ and two USB cables, connected like this:
(If you are using Grub, append it to the 'kernel' line in (If you are using Grub, append it to the 'kernel' line in
/etc/grub.conf) /etc/grub.conf)
On systems with more than one EHCI debug controller you must
specify the correct EHCI debug controller number. The ordering
comes from the PCI bus enumeration of the EHCI controllers. The
default with no number argument is "0" the first EHCI debug
controller. To use the second EHCI debug controller, you would
use the command line: "earlyprintk=dbgp1"
NOTE: normally earlyprintk console gets turned off once the NOTE: normally earlyprintk console gets turned off once the
regular console is alive - use "earlyprintk=dbgp,keep" to keep regular console is alive - use "earlyprintk=dbgp,keep" to keep
this channel open beyond early bootup. This can be useful for this channel open beyond early bootup. This can be useful for

View File

@ -2107,12 +2107,12 @@ S: Supported
F: arch/powerpc/sysdev/qe_lib/ F: arch/powerpc/sysdev/qe_lib/
F: arch/powerpc/include/asm/*qe.h F: arch/powerpc/include/asm/*qe.h
FREESCALE HIGHSPEED USB DEVICE DRIVER FREESCALE USB PERIPHERIAL DRIVERS
M: Li Yang <leoli@freescale.com> M: Li Yang <leoli@freescale.com>
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
L: linuxppc-dev@ozlabs.org L: linuxppc-dev@ozlabs.org
S: Maintained S: Maintained
F: drivers/usb/gadget/fsl_usb2_udc.c F: drivers/usb/gadget/fsl*
FREESCALE QUICC ENGINE UCC ETHERNET DRIVER FREESCALE QUICC ENGINE UCC ETHERNET DRIVER
M: Li Yang <leoli@freescale.com> M: Li Yang <leoli@freescale.com>

View File

@ -160,721 +160,6 @@ static struct console early_serial_console = {
.index = -1, .index = -1,
}; };
#ifdef CONFIG_EARLY_PRINTK_DBGP
static struct ehci_caps __iomem *ehci_caps;
static struct ehci_regs __iomem *ehci_regs;
static struct ehci_dbg_port __iomem *ehci_debug;
static unsigned int dbgp_endpoint_out;
struct ehci_dev {
u32 bus;
u32 slot;
u32 func;
};
static struct ehci_dev ehci_dev;
#define USB_DEBUG_DEVNUM 127
#define DBGP_DATA_TOGGLE 0x8800
static inline u32 dbgp_pid_update(u32 x, u32 tok)
{
return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff);
}
static inline u32 dbgp_len_update(u32 x, u32 len)
{
return (x & ~0x0f) | (len & 0x0f);
}
/*
* USB Packet IDs (PIDs)
*/
/* token */
#define USB_PID_OUT 0xe1
#define USB_PID_IN 0x69
#define USB_PID_SOF 0xa5
#define USB_PID_SETUP 0x2d
/* handshake */
#define USB_PID_ACK 0xd2
#define USB_PID_NAK 0x5a
#define USB_PID_STALL 0x1e
#define USB_PID_NYET 0x96
/* data */
#define USB_PID_DATA0 0xc3
#define USB_PID_DATA1 0x4b
#define USB_PID_DATA2 0x87
#define USB_PID_MDATA 0x0f
/* Special */
#define USB_PID_PREAMBLE 0x3c
#define USB_PID_ERR 0x3c
#define USB_PID_SPLIT 0x78
#define USB_PID_PING 0xb4
#define USB_PID_UNDEF_0 0xf0
#define USB_PID_DATA_TOGGLE 0x88
#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE)
#define PCI_CAP_ID_EHCI_DEBUG 0xa
#define HUB_ROOT_RESET_TIME 50 /* times are in msec */
#define HUB_SHORT_RESET_TIME 10
#define HUB_LONG_RESET_TIME 200
#define HUB_RESET_TIMEOUT 500
#define DBGP_MAX_PACKET 8
static int dbgp_wait_until_complete(void)
{
u32 ctrl;
int loop = 0x100000;
do {
ctrl = readl(&ehci_debug->control);
/* Stop when the transaction is finished */
if (ctrl & DBGP_DONE)
break;
} while (--loop > 0);
if (!loop)
return -1;
/*
* Now that we have observed the completed transaction,
* clear the done bit.
*/
writel(ctrl | DBGP_DONE, &ehci_debug->control);
return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl);
}
static void __init dbgp_mdelay(int ms)
{
int i;
while (ms--) {
for (i = 0; i < 1000; i++)
outb(0x1, 0x80);
}
}
static void dbgp_breath(void)
{
/* Sleep to give the debug port a chance to breathe */
}
static int dbgp_wait_until_done(unsigned ctrl)
{
u32 pids, lpid;
int ret;
int loop = 3;
retry:
writel(ctrl | DBGP_GO, &ehci_debug->control);
ret = dbgp_wait_until_complete();
pids = readl(&ehci_debug->pids);
lpid = DBGP_PID_GET(pids);
if (ret < 0)
return ret;
/*
* If the port is getting full or it has dropped data
* start pacing ourselves, not necessary but it's friendly.
*/
if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET))
dbgp_breath();
/* If I get a NACK reissue the transmission */
if (lpid == USB_PID_NAK) {
if (--loop > 0)
goto retry;
}
return ret;
}
static void dbgp_set_data(const void *buf, int size)
{
const unsigned char *bytes = buf;
u32 lo, hi;
int i;
lo = hi = 0;
for (i = 0; i < 4 && i < size; i++)
lo |= bytes[i] << (8*i);
for (; i < 8 && i < size; i++)
hi |= bytes[i] << (8*(i - 4));
writel(lo, &ehci_debug->data03);
writel(hi, &ehci_debug->data47);
}
static void __init dbgp_get_data(void *buf, int size)
{
unsigned char *bytes = buf;
u32 lo, hi;
int i;
lo = readl(&ehci_debug->data03);
hi = readl(&ehci_debug->data47);
for (i = 0; i < 4 && i < size; i++)
bytes[i] = (lo >> (8*i)) & 0xff;
for (; i < 8 && i < size; i++)
bytes[i] = (hi >> (8*(i - 4))) & 0xff;
}
static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
const char *bytes, int size)
{
u32 pids, addr, ctrl;
int ret;
if (size > DBGP_MAX_PACKET)
return -1;
addr = DBGP_EPADDR(devnum, endpoint);
pids = readl(&ehci_debug->pids);
pids = dbgp_pid_update(pids, USB_PID_OUT);
ctrl = readl(&ehci_debug->control);
ctrl = dbgp_len_update(ctrl, size);
ctrl |= DBGP_OUT;
ctrl |= DBGP_GO;
dbgp_set_data(bytes, size);
writel(addr, &ehci_debug->address);
writel(pids, &ehci_debug->pids);
ret = dbgp_wait_until_done(ctrl);
if (ret < 0)
return ret;
return ret;
}
static int __init dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
int size)
{
u32 pids, addr, ctrl;
int ret;
if (size > DBGP_MAX_PACKET)
return -1;
addr = DBGP_EPADDR(devnum, endpoint);
pids = readl(&ehci_debug->pids);
pids = dbgp_pid_update(pids, USB_PID_IN);
ctrl = readl(&ehci_debug->control);
ctrl = dbgp_len_update(ctrl, size);
ctrl &= ~DBGP_OUT;
ctrl |= DBGP_GO;
writel(addr, &ehci_debug->address);
writel(pids, &ehci_debug->pids);
ret = dbgp_wait_until_done(ctrl);
if (ret < 0)
return ret;
if (size > ret)
size = ret;
dbgp_get_data(data, size);
return ret;
}
static int __init dbgp_control_msg(unsigned devnum, int requesttype,
int request, int value, int index, void *data, int size)
{
u32 pids, addr, ctrl;
struct usb_ctrlrequest req;
int read;
int ret;
read = (requesttype & USB_DIR_IN) != 0;
if (size > (read ? DBGP_MAX_PACKET:0))
return -1;
/* Compute the control message */
req.bRequestType = requesttype;
req.bRequest = request;
req.wValue = cpu_to_le16(value);
req.wIndex = cpu_to_le16(index);
req.wLength = cpu_to_le16(size);
pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP);
addr = DBGP_EPADDR(devnum, 0);
ctrl = readl(&ehci_debug->control);
ctrl = dbgp_len_update(ctrl, sizeof(req));
ctrl |= DBGP_OUT;
ctrl |= DBGP_GO;
/* Send the setup message */
dbgp_set_data(&req, sizeof(req));
writel(addr, &ehci_debug->address);
writel(pids, &ehci_debug->pids);
ret = dbgp_wait_until_done(ctrl);
if (ret < 0)
return ret;
/* Read the result */
return dbgp_bulk_read(devnum, 0, data, size);
}
/* Find a PCI capability */
static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap)
{
u8 pos;
int bytes;
if (!(read_pci_config_16(num, slot, func, PCI_STATUS) &
PCI_STATUS_CAP_LIST))
return 0;
pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST);
for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
u8 id;
pos &= ~3;
id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID);
if (id == 0xff)
break;
if (id == cap)
return pos;
pos = read_pci_config_byte(num, slot, func,
pos+PCI_CAP_LIST_NEXT);
}
return 0;
}
static u32 __init __find_dbgp(u32 bus, u32 slot, u32 func)
{
u32 class;
class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION);
if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI)
return 0;
return find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG);
}
static u32 __init find_dbgp(int ehci_num, u32 *rbus, u32 *rslot, u32 *rfunc)
{
u32 bus, slot, func;
for (bus = 0; bus < 256; bus++) {
for (slot = 0; slot < 32; slot++) {
for (func = 0; func < 8; func++) {
unsigned cap;
cap = __find_dbgp(bus, slot, func);
if (!cap)
continue;
if (ehci_num-- != 0)
continue;
*rbus = bus;
*rslot = slot;
*rfunc = func;
return cap;
}
}
}
return 0;
}
static int __init ehci_reset_port(int port)
{
u32 portsc;
u32 delay_time, delay;
int loop;
/* Reset the usb debug port */
portsc = readl(&ehci_regs->port_status[port - 1]);
portsc &= ~PORT_PE;
portsc |= PORT_RESET;
writel(portsc, &ehci_regs->port_status[port - 1]);
delay = HUB_ROOT_RESET_TIME;
for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT;
delay_time += delay) {
dbgp_mdelay(delay);
portsc = readl(&ehci_regs->port_status[port - 1]);
if (portsc & PORT_RESET) {
/* force reset to complete */
loop = 2;
writel(portsc & ~(PORT_RWC_BITS | PORT_RESET),
&ehci_regs->port_status[port - 1]);
do {
portsc = readl(&ehci_regs->port_status[port-1]);
} while ((portsc & PORT_RESET) && (--loop > 0));
}
/* Device went away? */
if (!(portsc & PORT_CONNECT))
return -ENOTCONN;
/* bomb out completely if something weird happend */
if ((portsc & PORT_CSC))
return -EINVAL;
/* If we've finished resetting, then break out of the loop */
if (!(portsc & PORT_RESET) && (portsc & PORT_PE))
return 0;
}
return -EBUSY;
}
static int __init ehci_wait_for_port(int port)
{
u32 status;
int ret, reps;
for (reps = 0; reps < 3; reps++) {
dbgp_mdelay(100);
status = readl(&ehci_regs->status);
if (status & STS_PCD) {
ret = ehci_reset_port(port);
if (ret == 0)
return 0;
}
}
return -ENOTCONN;
}
#ifdef DBGP_DEBUG
# define dbgp_printk early_printk
#else
static inline void dbgp_printk(const char *fmt, ...) { }
#endif
typedef void (*set_debug_port_t)(int port);
static void __init default_set_debug_port(int port)
{
}
static set_debug_port_t __initdata set_debug_port = default_set_debug_port;
static void __init nvidia_set_debug_port(int port)
{
u32 dword;
dword = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
0x74);
dword &= ~(0x0f<<12);
dword |= ((port & 0x0f)<<12);
write_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, 0x74,
dword);
dbgp_printk("set debug port to %d\n", port);
}
static void __init detect_set_debug_port(void)
{
u32 vendorid;
vendorid = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
0x00);
if ((vendorid & 0xffff) == 0x10de) {
dbgp_printk("using nvidia set_debug_port\n");
set_debug_port = nvidia_set_debug_port;
}
}
static int __init ehci_setup(void)
{
struct usb_debug_descriptor dbgp_desc;
u32 cmd, ctrl, status, portsc, hcs_params;
u32 debug_port, new_debug_port = 0, n_ports;
u32 devnum;
int ret, i;
int loop;
int port_map_tried;
int playtimes = 3;
try_next_time:
port_map_tried = 0;
try_next_port:
hcs_params = readl(&ehci_caps->hcs_params);
debug_port = HCS_DEBUG_PORT(hcs_params);
n_ports = HCS_N_PORTS(hcs_params);
dbgp_printk("debug_port: %d\n", debug_port);
dbgp_printk("n_ports: %d\n", n_ports);
for (i = 1; i <= n_ports; i++) {
portsc = readl(&ehci_regs->port_status[i-1]);
dbgp_printk("portstatus%d: %08x\n", i, portsc);
}
if (port_map_tried && (new_debug_port != debug_port)) {
if (--playtimes) {
set_debug_port(new_debug_port);
goto try_next_time;
}
return -1;
}
loop = 100000;
/* Reset the EHCI controller */
cmd = readl(&ehci_regs->command);
cmd |= CMD_RESET;
writel(cmd, &ehci_regs->command);
do {
cmd = readl(&ehci_regs->command);
} while ((cmd & CMD_RESET) && (--loop > 0));
if (!loop) {
dbgp_printk("can not reset ehci\n");
return -1;
}
dbgp_printk("ehci reset done\n");
/* Claim ownership, but do not enable yet */
ctrl = readl(&ehci_debug->control);
ctrl |= DBGP_OWNER;
ctrl &= ~(DBGP_ENABLED | DBGP_INUSE);
writel(ctrl, &ehci_debug->control);
/* Start the ehci running */
cmd = readl(&ehci_regs->command);
cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET);
cmd |= CMD_RUN;
writel(cmd, &ehci_regs->command);
/* Ensure everything is routed to the EHCI */
writel(FLAG_CF, &ehci_regs->configured_flag);
/* Wait until the controller is no longer halted */
loop = 10;
do {
status = readl(&ehci_regs->status);
} while ((status & STS_HALT) && (--loop > 0));
if (!loop) {
dbgp_printk("ehci can be started\n");
return -1;
}
dbgp_printk("ehci started\n");
/* Wait for a device to show up in the debug port */
ret = ehci_wait_for_port(debug_port);
if (ret < 0) {
dbgp_printk("No device found in debug port\n");
goto next_debug_port;
}
dbgp_printk("ehci wait for port done\n");
/* Enable the debug port */
ctrl = readl(&ehci_debug->control);
ctrl |= DBGP_CLAIM;
writel(ctrl, &ehci_debug->control);
ctrl = readl(&ehci_debug->control);
if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) {
dbgp_printk("No device in debug port\n");
writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control);
goto err;
}
dbgp_printk("debug ported enabled\n");
/* Completely transfer the debug device to the debug controller */
portsc = readl(&ehci_regs->port_status[debug_port - 1]);
portsc &= ~PORT_PE;
writel(portsc, &ehci_regs->port_status[debug_port - 1]);
dbgp_mdelay(100);
/* Find the debug device and make it device number 127 */
for (devnum = 0; devnum <= 127; devnum++) {
ret = dbgp_control_msg(devnum,
USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0,
&dbgp_desc, sizeof(dbgp_desc));
if (ret > 0)
break;
}
if (devnum > 127) {
dbgp_printk("Could not find attached debug device\n");
goto err;
}
if (ret < 0) {
dbgp_printk("Attached device is not a debug device\n");
goto err;
}
dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint;
/* Move the device to 127 if it isn't already there */
if (devnum != USB_DEBUG_DEVNUM) {
ret = dbgp_control_msg(devnum,
USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0);
if (ret < 0) {
dbgp_printk("Could not move attached device to %d\n",
USB_DEBUG_DEVNUM);
goto err;
}
devnum = USB_DEBUG_DEVNUM;
dbgp_printk("debug device renamed to 127\n");
}
/* Enable the debug interface */
ret = dbgp_control_msg(USB_DEBUG_DEVNUM,
USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0);
if (ret < 0) {
dbgp_printk(" Could not enable the debug device\n");
goto err;
}
dbgp_printk("debug interface enabled\n");
/* Perform a small write to get the even/odd data state in sync
*/
ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ", 1);
if (ret < 0) {
dbgp_printk("dbgp_bulk_write failed: %d\n", ret);
goto err;
}
dbgp_printk("small write doned\n");
return 0;
err:
/* Things didn't work so remove my claim */
ctrl = readl(&ehci_debug->control);
ctrl &= ~(DBGP_CLAIM | DBGP_OUT);
writel(ctrl, &ehci_debug->control);
return -1;
next_debug_port:
port_map_tried |= (1<<(debug_port - 1));
new_debug_port = ((debug_port-1+1)%n_ports) + 1;
if (port_map_tried != ((1<<n_ports) - 1)) {
set_debug_port(new_debug_port);
goto try_next_port;
}
if (--playtimes) {
set_debug_port(new_debug_port);
goto try_next_time;
}
return -1;
}
static int __init early_dbgp_init(char *s)
{
u32 debug_port, bar, offset;
u32 bus, slot, func, cap;
void __iomem *ehci_bar;
u32 dbgp_num;
u32 bar_val;
char *e;
int ret;
u8 byte;
if (!early_pci_allowed())
return -1;
dbgp_num = 0;
if (*s)
dbgp_num = simple_strtoul(s, &e, 10);
dbgp_printk("dbgp_num: %d\n", dbgp_num);
cap = find_dbgp(dbgp_num, &bus, &slot, &func);
if (!cap)
return -1;
dbgp_printk("Found EHCI debug port on %02x:%02x.%1x\n", bus, slot,
func);
debug_port = read_pci_config(bus, slot, func, cap);
bar = (debug_port >> 29) & 0x7;
bar = (bar * 4) + 0xc;
offset = (debug_port >> 16) & 0xfff;
dbgp_printk("bar: %02x offset: %03x\n", bar, offset);
if (bar != PCI_BASE_ADDRESS_0) {
dbgp_printk("only debug ports on bar 1 handled.\n");
return -1;
}
bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
dbgp_printk("bar_val: %02x offset: %03x\n", bar_val, offset);
if (bar_val & ~PCI_BASE_ADDRESS_MEM_MASK) {
dbgp_printk("only simple 32bit mmio bars supported\n");
return -1;
}
/* double check if the mem space is enabled */
byte = read_pci_config_byte(bus, slot, func, 0x04);
if (!(byte & 0x2)) {
byte |= 0x02;
write_pci_config_byte(bus, slot, func, 0x04, byte);
dbgp_printk("mmio for ehci enabled\n");
}
/*
* FIXME I don't have the bar size so just guess PAGE_SIZE is more
* than enough. 1K is the biggest I have seen.
*/
set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK);
ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE);
ehci_bar += bar_val & ~PAGE_MASK;
dbgp_printk("ehci_bar: %p\n", ehci_bar);
ehci_caps = ehci_bar;
ehci_regs = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase));
ehci_debug = ehci_bar + offset;
ehci_dev.bus = bus;
ehci_dev.slot = slot;
ehci_dev.func = func;
detect_set_debug_port();
ret = ehci_setup();
if (ret < 0) {
dbgp_printk("ehci_setup failed\n");
ehci_debug = NULL;
return -1;
}
return 0;
}
static void early_dbgp_write(struct console *con, const char *str, u32 n)
{
int chunk, ret;
if (!ehci_debug)
return;
while (n > 0) {
chunk = n;
if (chunk > DBGP_MAX_PACKET)
chunk = DBGP_MAX_PACKET;
ret = dbgp_bulk_write(USB_DEBUG_DEVNUM,
dbgp_endpoint_out, str, chunk);
str += chunk;
n -= chunk;
}
}
static struct console early_dbgp_console = {
.name = "earlydbg",
.write = early_dbgp_write,
.flags = CON_PRINTBUFFER,
.index = -1,
};
#endif
/* Direct interface for emergencies */ /* Direct interface for emergencies */
static struct console *early_console = &early_vga_console; static struct console *early_console = &early_vga_console;
static int __initdata early_console_initialized; static int __initdata early_console_initialized;
@ -891,10 +176,19 @@ asmlinkage void early_printk(const char *fmt, ...)
va_end(ap); va_end(ap);
} }
static inline void early_console_register(struct console *con, int keep_early)
{
early_console = con;
if (keep_early)
early_console->flags &= ~CON_BOOT;
else
early_console->flags |= CON_BOOT;
register_console(early_console);
}
static int __init setup_early_printk(char *buf) static int __init setup_early_printk(char *buf)
{ {
int keep_early; int keep;
if (!buf) if (!buf)
return 0; return 0;
@ -903,42 +197,34 @@ static int __init setup_early_printk(char *buf)
return 0; return 0;
early_console_initialized = 1; early_console_initialized = 1;
keep_early = (strstr(buf, "keep") != NULL); keep = (strstr(buf, "keep") != NULL);
if (!strncmp(buf, "serial", 6)) { while (*buf != '\0') {
early_serial_init(buf + 6); if (!strncmp(buf, "serial", 6)) {
early_console = &early_serial_console; early_serial_init(buf + 6);
} else if (!strncmp(buf, "ttyS", 4)) { early_console_register(&early_serial_console, keep);
early_serial_init(buf); }
early_console = &early_serial_console; if (!strncmp(buf, "ttyS", 4)) {
} else if (!strncmp(buf, "vga", 3) early_serial_init(buf + 4);
&& boot_params.screen_info.orig_video_isVGA == 1) { early_console_register(&early_serial_console, keep);
max_xpos = boot_params.screen_info.orig_video_cols; }
max_ypos = boot_params.screen_info.orig_video_lines; if (!strncmp(buf, "vga", 3) &&
current_ypos = boot_params.screen_info.orig_y; boot_params.screen_info.orig_video_isVGA == 1) {
early_console = &early_vga_console; max_xpos = boot_params.screen_info.orig_video_cols;
max_ypos = boot_params.screen_info.orig_video_lines;
current_ypos = boot_params.screen_info.orig_y;
early_console_register(&early_vga_console, keep);
}
#ifdef CONFIG_EARLY_PRINTK_DBGP #ifdef CONFIG_EARLY_PRINTK_DBGP
} else if (!strncmp(buf, "dbgp", 4)) { if (!strncmp(buf, "dbgp", 4) && !early_dbgp_init(buf + 4))
if (early_dbgp_init(buf+4) < 0) early_console_register(&early_dbgp_console, keep);
return 0;
early_console = &early_dbgp_console;
/*
* usb subsys will reset ehci controller, so don't keep
* that early console
*/
keep_early = 0;
#endif #endif
#ifdef CONFIG_HVC_XEN #ifdef CONFIG_HVC_XEN
} else if (!strncmp(buf, "xen", 3)) { if (!strncmp(buf, "xen", 3))
early_console = &xenboot_console; early_console_register(&xenboot_console, keep);
#endif #endif
buf++;
} }
if (keep_early)
early_console->flags &= ~CON_BOOT;
else
early_console->flags |= CON_BOOT;
register_console(early_console);
return 0; return 0;
} }

View File

@ -300,20 +300,23 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
return 0; return 0;
} }
crc = get_unaligned_le32(skb2->data
+ len - ETH_FCS_LEN);
skb_trim(skb2, len - ETH_FCS_LEN);
/* /*
* The bmCRC helps to denote when the CRC field in * The bmCRC helps to denote when the CRC field in
* the Ethernet frame contains a calculated CRC: * the Ethernet frame contains a calculated CRC:
* bmCRC = 1 : CRC is calculated * bmCRC = 1 : CRC is calculated
* bmCRC = 0 : CRC = 0xDEADBEEF * bmCRC = 0 : CRC = 0xDEADBEEF
*/ */
if (header & BIT(14)) if (header & BIT(14)) {
crc2 = ~crc32_le(~0, skb2->data, skb2->len); crc = get_unaligned_le32(skb2->data
else + len - ETH_FCS_LEN);
crc2 = ~crc32_le(~0, skb2->data, skb2->len
- ETH_FCS_LEN);
} else {
crc = get_unaligned_be32(skb2->data
+ len - ETH_FCS_LEN);
crc2 = 0xdeadbeef; crc2 = 0xdeadbeef;
}
skb_trim(skb2, len - ETH_FCS_LEN);
if (is_last) if (is_last)
return crc == crc2; return crc == crc2;

View File

@ -39,6 +39,7 @@ config USB_ARCH_HAS_OHCI
default y if ARCH_AT91 default y if ARCH_AT91
default y if ARCH_PNX4008 && I2C default y if ARCH_PNX4008 && I2C
default y if MFD_TC6393XB default y if MFD_TC6393XB
default y if ARCH_W90X900
# PPC: # PPC:
default y if STB03xxx default y if STB03xxx
default y if PPC_MPC52xx default y if PPC_MPC52xx
@ -58,6 +59,8 @@ config USB_ARCH_HAS_EHCI
default y if PPC_83xx default y if PPC_83xx
default y if SOC_AU1200 default y if SOC_AU1200
default y if ARCH_IXP4XX default y if ARCH_IXP4XX
default y if ARCH_W90X900
default y if ARCH_AT91SAM9G45
default PCI default PCI
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.

View File

@ -16,6 +16,7 @@ obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_FHCI_HCD) += host/ obj-$(CONFIG_USB_FHCI_HCD) += host/
obj-$(CONFIG_USB_XHCI_HCD) += host/ obj-$(CONFIG_USB_XHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/ obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_ISP1362_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/ obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/ obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_HWA_HCD) += host/ obj-$(CONFIG_USB_HWA_HCD) += host/
@ -39,6 +40,7 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB_SERIAL) += serial/
obj-$(CONFIG_USB) += misc/ obj-$(CONFIG_USB) += misc/
obj-y += early/
obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/

View File

@ -59,6 +59,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <linux/serial.h>
#include <linux/tty_driver.h> #include <linux/tty_driver.h>
#include <linux/tty_flip.h> #include <linux/tty_flip.h>
#include <linux/module.h> #include <linux/module.h>
@ -609,6 +610,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
acm->throttle = 0; acm->throttle = 0;
tasklet_schedule(&acm->urb_task); tasklet_schedule(&acm->urb_task);
set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
rv = tty_port_block_til_ready(&acm->port, tty, filp); rv = tty_port_block_til_ready(&acm->port, tty, filp);
done: done:
mutex_unlock(&acm->mutex); mutex_unlock(&acm->mutex);

View File

@ -313,8 +313,13 @@ static ssize_t wdm_write
r = usb_autopm_get_interface(desc->intf); r = usb_autopm_get_interface(desc->intf);
if (r < 0) if (r < 0)
goto outnp; goto outnp;
r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
&desc->flags)); if (!file->f_flags && O_NONBLOCK)
r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE,
&desc->flags));
else
if (test_bit(WDM_IN_USE, &desc->flags))
r = -EAGAIN;
if (r < 0) if (r < 0)
goto out; goto out;
@ -377,7 +382,7 @@ outnl:
static ssize_t wdm_read static ssize_t wdm_read
(struct file *file, char __user *buffer, size_t count, loff_t *ppos) (struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{ {
int rv, cntr; int rv, cntr = 0;
int i = 0; int i = 0;
struct wdm_device *desc = file->private_data; struct wdm_device *desc = file->private_data;
@ -389,10 +394,23 @@ static ssize_t wdm_read
if (desc->length == 0) { if (desc->length == 0) {
desc->read = 0; desc->read = 0;
retry: retry:
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
rv = -ENODEV;
goto err;
}
i++; i++;
rv = wait_event_interruptible(desc->wait, if (file->f_flags & O_NONBLOCK) {
test_bit(WDM_READ, &desc->flags)); if (!test_bit(WDM_READ, &desc->flags)) {
rv = cntr ? cntr : -EAGAIN;
goto err;
}
rv = 0;
} else {
rv = wait_event_interruptible(desc->wait,
test_bit(WDM_READ, &desc->flags));
}
/* may have happened while we slept */
if (test_bit(WDM_DISCONNECTING, &desc->flags)) { if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
rv = -ENODEV; rv = -ENODEV;
goto err; goto err;
@ -448,7 +466,7 @@ retry:
err: err:
mutex_unlock(&desc->rlock); mutex_unlock(&desc->rlock);
if (rv < 0) if (rv < 0 && rv != -EAGAIN)
dev_err(&desc->intf->dev, "wdm_read: exit error\n"); dev_err(&desc->intf->dev, "wdm_read: exit error\n");
return rv; return rv;
} }

View File

@ -57,7 +57,9 @@ MODULE_DEVICE_TABLE(usb, usbtmc_devices);
/* /*
* This structure is the capabilities for the device * This structure is the capabilities for the device
* See section 4.2.1.8 of the USBTMC specification for details. * See section 4.2.1.8 of the USBTMC specification,
* and section 4.2.2 of the USBTMC usb488 subclass
* specification for details.
*/ */
struct usbtmc_dev_capabilities { struct usbtmc_dev_capabilities {
__u8 interface_capabilities; __u8 interface_capabilities;
@ -86,6 +88,8 @@ struct usbtmc_device_data {
bool TermCharEnabled; bool TermCharEnabled;
bool auto_abort; bool auto_abort;
bool zombie; /* fd of disconnected device */
struct usbtmc_dev_capabilities capabilities; struct usbtmc_dev_capabilities capabilities;
struct kref kref; struct kref kref;
struct mutex io_mutex; /* only one i/o function running at a time */ struct mutex io_mutex; /* only one i/o function running at a time */
@ -367,13 +371,13 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
{ {
struct usbtmc_device_data *data; struct usbtmc_device_data *data;
struct device *dev; struct device *dev;
unsigned long int n_characters; u32 n_characters;
u8 *buffer; u8 *buffer;
int actual; int actual;
int done; size_t done;
int remaining; size_t remaining;
int retval; int retval;
int this_part; size_t this_part;
/* Get pointer to private data structure */ /* Get pointer to private data structure */
data = filp->private_data; data = filp->private_data;
@ -384,6 +388,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
return -ENOMEM; return -ENOMEM;
mutex_lock(&data->io_mutex); mutex_lock(&data->io_mutex);
if (data->zombie) {
retval = -ENODEV;
goto exit;
}
remaining = count; remaining = count;
done = 0; done = 0;
@ -401,10 +409,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
buffer[1] = data->bTag; buffer[1] = data->bTag;
buffer[2] = ~(data->bTag); buffer[2] = ~(data->bTag);
buffer[3] = 0; /* Reserved */ buffer[3] = 0; /* Reserved */
buffer[4] = (this_part - 12 - 3) & 255; buffer[4] = (this_part) & 255;
buffer[5] = ((this_part - 12 - 3) >> 8) & 255; buffer[5] = ((this_part) >> 8) & 255;
buffer[6] = ((this_part - 12 - 3) >> 16) & 255; buffer[6] = ((this_part) >> 16) & 255;
buffer[7] = ((this_part - 12 - 3) >> 24) & 255; buffer[7] = ((this_part) >> 24) & 255;
buffer[8] = data->TermCharEnabled * 2; buffer[8] = data->TermCharEnabled * 2;
/* Use term character? */ /* Use term character? */
buffer[9] = data->TermChar; buffer[9] = data->TermChar;
@ -455,6 +463,22 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
(buffer[6] << 16) + (buffer[6] << 16) +
(buffer[7] << 24); (buffer[7] << 24);
/* Ensure the instrument doesn't lie about it */
if(n_characters > actual - 12) {
dev_err(dev, "Device lies about message size: %u > %d\n", n_characters, actual - 12);
n_characters = actual - 12;
}
/* Ensure the instrument doesn't send more back than requested */
if(n_characters > this_part) {
dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part);
n_characters = this_part;
}
/* Bound amount of data received by amount of data requested */
if (n_characters > this_part)
n_characters = this_part;
/* Copy buffer to user space */ /* Copy buffer to user space */
if (copy_to_user(buf + done, &buffer[12], n_characters)) { if (copy_to_user(buf + done, &buffer[12], n_characters)) {
/* There must have been an addressing problem */ /* There must have been an addressing problem */
@ -463,8 +487,11 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
} }
done += n_characters; done += n_characters;
if (n_characters < USBTMC_SIZE_IOBUFFER) /* Terminate if end-of-message bit recieved from device */
if ((buffer[8] & 0x01) && (actual >= n_characters + 12))
remaining = 0; remaining = 0;
else
remaining -= n_characters;
} }
/* Update file position value */ /* Update file position value */
@ -496,6 +523,10 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
return -ENOMEM; return -ENOMEM;
mutex_lock(&data->io_mutex); mutex_lock(&data->io_mutex);
if (data->zombie) {
retval = -ENODEV;
goto exit;
}
remaining = count; remaining = count;
done = 0; done = 0;
@ -767,20 +798,21 @@ static int get_capabilities(struct usbtmc_device_data *data)
} }
dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); dev_dbg(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]);
dev_dbg(dev, "Device capabilities are %x\n", buffer[5]);
dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]);
dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]);
if (buffer[0] != USBTMC_STATUS_SUCCESS) { if (buffer[0] != USBTMC_STATUS_SUCCESS) {
dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]); dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
rv = -EPERM; rv = -EPERM;
goto err_out; goto err_out;
} }
dev_dbg(dev, "Interface capabilities are %x\n", buffer[4]);
dev_dbg(dev, "Device capabilities are %x\n", buffer[5]);
dev_dbg(dev, "USB488 interface capabilities are %x\n", buffer[14]);
dev_dbg(dev, "USB488 device capabilities are %x\n", buffer[15]);
data->capabilities.interface_capabilities = buffer[4]; data->capabilities.interface_capabilities = buffer[4];
data->capabilities.device_capabilities = buffer[5]; data->capabilities.device_capabilities = buffer[5];
data->capabilities.usb488_interface_capabilities = buffer[14]; data->capabilities.usb488_interface_capabilities = buffer[14];
data->capabilities.usb488_device_capabilities = buffer[15]; data->capabilities.usb488_device_capabilities = buffer[15];
rv = 0;
err_out: err_out:
kfree(buffer); kfree(buffer);
@ -925,6 +957,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
data = file->private_data; data = file->private_data;
mutex_lock(&data->io_mutex); mutex_lock(&data->io_mutex);
if (data->zombie) {
retval = -ENODEV;
goto skip_io_on_zombie;
}
switch (cmd) { switch (cmd) {
case USBTMC_IOCTL_CLEAR_OUT_HALT: case USBTMC_IOCTL_CLEAR_OUT_HALT:
@ -952,6 +988,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break; break;
} }
skip_io_on_zombie:
mutex_unlock(&data->io_mutex); mutex_unlock(&data->io_mutex);
return retval; return retval;
} }
@ -995,6 +1032,7 @@ static int usbtmc_probe(struct usb_interface *intf,
usb_set_intfdata(intf, data); usb_set_intfdata(intf, data);
kref_init(&data->kref); kref_init(&data->kref);
mutex_init(&data->io_mutex); mutex_init(&data->io_mutex);
data->zombie = 0;
/* Initialize USBTMC bTag and other fields */ /* Initialize USBTMC bTag and other fields */
data->bTag = 1; data->bTag = 1;
@ -1065,14 +1103,30 @@ static void usbtmc_disconnect(struct usb_interface *intf)
usb_deregister_dev(intf, &usbtmc_class); usb_deregister_dev(intf, &usbtmc_class);
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
mutex_lock(&data->io_mutex);
data->zombie = 1;
mutex_unlock(&data->io_mutex);
kref_put(&data->kref, usbtmc_delete); kref_put(&data->kref, usbtmc_delete);
} }
static int usbtmc_suspend (struct usb_interface *intf, pm_message_t message)
{
/* this driver does not have pending URBs */
return 0;
}
static int usbtmc_resume (struct usb_interface *intf)
{
return 0;
}
static struct usb_driver usbtmc_driver = { static struct usb_driver usbtmc_driver = {
.name = "usbtmc", .name = "usbtmc",
.id_table = usbtmc_devices, .id_table = usbtmc_devices,
.probe = usbtmc_probe, .probe = usbtmc_probe,
.disconnect = usbtmc_disconnect .disconnect = usbtmc_disconnect,
.suspend = usbtmc_suspend,
.resume = usbtmc_resume,
}; };
static int __init usbtmc_init(void) static int __init usbtmc_init(void)

View File

@ -105,7 +105,7 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
ep->ss_ep_comp->extralen = i; ep->ss_ep_comp->extralen = i;
buffer += i; buffer += i;
size -= i; size -= i;
retval = buffer - buffer_start + i; retval = buffer - buffer_start;
if (num_skipped > 0) if (num_skipped > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n", dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
num_skipped, plural(num_skipped), num_skipped, plural(num_skipped),

View File

@ -52,6 +52,7 @@
#include "hcd.h" /* for usbcore internals */ #include "hcd.h" /* for usbcore internals */
#include "usb.h" #include "usb.h"
#include "hub.h"
#define USB_MAXBUS 64 #define USB_MAXBUS 64
#define USB_DEVICE_MAX USB_MAXBUS * 128 #define USB_DEVICE_MAX USB_MAXBUS * 128
@ -73,6 +74,7 @@ struct dev_state {
void __user *disccontext; void __user *disccontext;
unsigned long ifclaimed; unsigned long ifclaimed;
u32 secid; u32 secid;
u32 disabled_bulk_eps;
}; };
struct async { struct async {
@ -87,6 +89,8 @@ struct async {
struct urb *urb; struct urb *urb;
int status; int status;
u32 secid; u32 secid;
u8 bulk_addr;
u8 bulk_status;
}; };
static int usbfs_snoop; static int usbfs_snoop;
@ -99,11 +103,15 @@ MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
dev_info(dev , format , ## arg); \ dev_info(dev , format , ## arg); \
} while (0) } while (0)
enum snoop_when {
SUBMIT, COMPLETE
};
#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)
#define MAX_USBFS_BUFFER_SIZE 16384 #define MAX_USBFS_BUFFER_SIZE 16384
static int connected(struct dev_state *ps) static int connected(struct dev_state *ps)
{ {
return (!list_empty(&ps->list) && return (!list_empty(&ps->list) &&
@ -300,24 +308,79 @@ static struct async *async_getpending(struct dev_state *ps,
return NULL; return NULL;
} }
static void snoop_urb(struct urb *urb, void __user *userurb) static void snoop_urb(struct usb_device *udev,
void __user *userurb, int pipe, unsigned length,
int timeout_or_status, enum snoop_when when)
{ {
unsigned j; static const char *types[] = {"isoc", "int", "ctrl", "bulk"};
unsigned char *data = urb->transfer_buffer; static const char *dirs[] = {"out", "in"};
int ep;
const char *t, *d;
if (!usbfs_snoop) if (!usbfs_snoop)
return; return;
dev_info(&urb->dev->dev, "direction=%s\n", ep = usb_pipeendpoint(pipe);
usb_urb_dir_in(urb) ? "IN" : "OUT"); t = types[usb_pipetype(pipe)];
dev_info(&urb->dev->dev, "userurb=%p\n", userurb); d = dirs[!!usb_pipein(pipe)];
dev_info(&urb->dev->dev, "transfer_buffer_length=%u\n",
urb->transfer_buffer_length); if (userurb) { /* Async */
dev_info(&urb->dev->dev, "actual_length=%u\n", urb->actual_length); if (when == SUBMIT)
dev_info(&urb->dev->dev, "data: "); dev_info(&udev->dev, "userurb %p, ep%d %s-%s, "
for (j = 0; j < urb->transfer_buffer_length; ++j) "length %u\n",
printk("%02x ", data[j]); userurb, ep, t, d, length);
printk("\n"); else
dev_info(&udev->dev, "userurb %p, ep%d %s-%s, "
"actual_length %u status %d\n",
userurb, ep, t, d, length,
timeout_or_status);
} else {
if (when == SUBMIT)
dev_info(&udev->dev, "ep%d %s-%s, length %u, "
"timeout %d\n",
ep, t, d, length, timeout_or_status);
else
dev_info(&udev->dev, "ep%d %s-%s, actual_length %u, "
"status %d\n",
ep, t, d, length, timeout_or_status);
}
}
#define AS_CONTINUATION 1
#define AS_UNLINK 2
static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr)
__releases(ps->lock)
__acquires(ps->lock)
{
struct async *as;
/* Mark all the pending URBs that match bulk_addr, up to but not
* including the first one without AS_CONTINUATION. If such an
* URB is encountered then a new transfer has already started so
* the endpoint doesn't need to be disabled; otherwise it does.
*/
list_for_each_entry(as, &ps->async_pending, asynclist) {
if (as->bulk_addr == bulk_addr) {
if (as->bulk_status != AS_CONTINUATION)
goto rescan;
as->bulk_status = AS_UNLINK;
as->bulk_addr = 0;
}
}
ps->disabled_bulk_eps |= (1 << bulk_addr);
/* Now carefully unlink all the marked pending URBs */
rescan:
list_for_each_entry(as, &ps->async_pending, asynclist) {
if (as->bulk_status == AS_UNLINK) {
as->bulk_status = 0; /* Only once */
spin_unlock(&ps->lock); /* Allow completions */
usb_unlink_urb(as->urb);
spin_lock(&ps->lock);
goto rescan;
}
}
} }
static void async_completed(struct urb *urb) static void async_completed(struct urb *urb)
@ -346,7 +409,11 @@ static void async_completed(struct urb *urb)
secid = as->secid; secid = as->secid;
} }
snoop(&urb->dev->dev, "urb complete\n"); snoop(&urb->dev->dev, "urb complete\n");
snoop_urb(urb, as->userurb); snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
as->status, COMPLETE);
if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
as->status != -ENOENT)
cancel_bulk_urbs(ps, as->bulk_addr);
spin_unlock(&ps->lock); spin_unlock(&ps->lock);
if (signr) if (signr)
@ -655,6 +722,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
struct async *as; struct async *as;
usb_lock_device(dev); usb_lock_device(dev);
usb_hub_release_all_ports(dev, ps);
/* Protect against simultaneous open */ /* Protect against simultaneous open */
mutex_lock(&usbfs_mutex); mutex_lock(&usbfs_mutex);
@ -688,7 +756,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)
unsigned int tmo; unsigned int tmo;
unsigned char *tbuf; unsigned char *tbuf;
unsigned wLength; unsigned wLength;
int i, j, ret; int i, pipe, ret;
if (copy_from_user(&ctrl, arg, sizeof(ctrl))) if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
return -EFAULT; return -EFAULT;
@ -708,24 +776,17 @@ static int proc_control(struct dev_state *ps, void __user *arg)
free_page((unsigned long)tbuf); free_page((unsigned long)tbuf);
return -EINVAL; return -EINVAL;
} }
snoop(&dev->dev, "control read: bRequest=%02x " pipe = usb_rcvctrlpipe(dev, 0);
"bRrequestType=%02x wValue=%04x " snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
"wIndex=%04x wLength=%04x\n",
ctrl.bRequest, ctrl.bRequestType, ctrl.wValue,
ctrl.wIndex, ctrl.wLength);
usb_unlock_device(dev); usb_unlock_device(dev);
i = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.bRequest, i = usb_control_msg(dev, pipe, ctrl.bRequest,
ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
tbuf, ctrl.wLength, tmo); tbuf, ctrl.wLength, tmo);
usb_lock_device(dev); usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
if ((i > 0) && ctrl.wLength) { if ((i > 0) && ctrl.wLength) {
if (usbfs_snoop) {
dev_info(&dev->dev, "control read: data ");
for (j = 0; j < i; ++j)
printk("%02x ", (u8)(tbuf)[j]);
printk("\n");
}
if (copy_to_user(ctrl.data, tbuf, i)) { if (copy_to_user(ctrl.data, tbuf, i)) {
free_page((unsigned long)tbuf); free_page((unsigned long)tbuf);
return -EFAULT; return -EFAULT;
@ -738,22 +799,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
return -EFAULT; return -EFAULT;
} }
} }
snoop(&dev->dev, "control write: bRequest=%02x " pipe = usb_sndctrlpipe(dev, 0);
"bRrequestType=%02x wValue=%04x " snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
"wIndex=%04x wLength=%04x\n",
ctrl.bRequest, ctrl.bRequestType, ctrl.wValue,
ctrl.wIndex, ctrl.wLength);
if (usbfs_snoop) {
dev_info(&dev->dev, "control write: data: ");
for (j = 0; j < ctrl.wLength; ++j)
printk("%02x ", (unsigned char)(tbuf)[j]);
printk("\n");
}
usb_unlock_device(dev); usb_unlock_device(dev);
i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest, i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
ctrl.bRequestType, ctrl.wValue, ctrl.wIndex, ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
tbuf, ctrl.wLength, tmo); tbuf, ctrl.wLength, tmo);
usb_lock_device(dev); usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
} }
free_page((unsigned long)tbuf); free_page((unsigned long)tbuf);
if (i < 0 && i != -EPIPE) { if (i < 0 && i != -EPIPE) {
@ -772,7 +826,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
unsigned int tmo, len1, pipe; unsigned int tmo, len1, pipe;
int len2; int len2;
unsigned char *tbuf; unsigned char *tbuf;
int i, j, ret; int i, ret;
if (copy_from_user(&bulk, arg, sizeof(bulk))) if (copy_from_user(&bulk, arg, sizeof(bulk)))
return -EFAULT; return -EFAULT;
@ -799,18 +853,14 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
kfree(tbuf); kfree(tbuf);
return -EINVAL; return -EINVAL;
} }
snoop(&dev->dev, "bulk read: len=0x%02x timeout=%04d\n", snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
bulk.len, bulk.timeout);
usb_unlock_device(dev); usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
usb_lock_device(dev); usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
if (!i && len2) { if (!i && len2) {
if (usbfs_snoop) {
dev_info(&dev->dev, "bulk read: data ");
for (j = 0; j < len2; ++j)
printk("%02x ", (u8)(tbuf)[j]);
printk("\n");
}
if (copy_to_user(bulk.data, tbuf, len2)) { if (copy_to_user(bulk.data, tbuf, len2)) {
kfree(tbuf); kfree(tbuf);
return -EFAULT; return -EFAULT;
@ -823,17 +873,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
return -EFAULT; return -EFAULT;
} }
} }
snoop(&dev->dev, "bulk write: len=0x%02x timeout=%04d\n", snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
bulk.len, bulk.timeout);
if (usbfs_snoop) {
dev_info(&dev->dev, "bulk write: data: ");
for (j = 0; j < len1; ++j)
printk("%02x ", (unsigned char)(tbuf)[j]);
printk("\n");
}
usb_unlock_device(dev); usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo); i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
usb_lock_device(dev); usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
} }
kfree(tbuf); kfree(tbuf);
if (i < 0) if (i < 0)
@ -991,6 +1036,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP | if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP |
USBDEVFS_URB_SHORT_NOT_OK | USBDEVFS_URB_SHORT_NOT_OK |
USBDEVFS_URB_BULK_CONTINUATION |
USBDEVFS_URB_NO_FSBR | USBDEVFS_URB_NO_FSBR |
USBDEVFS_URB_ZERO_PACKET | USBDEVFS_URB_ZERO_PACKET |
USBDEVFS_URB_NO_INTERRUPT)) USBDEVFS_URB_NO_INTERRUPT))
@ -1051,13 +1097,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
is_in = 0; is_in = 0;
uurb->endpoint &= ~USB_DIR_IN; uurb->endpoint &= ~USB_DIR_IN;
} }
snoop(&ps->dev->dev, "control urb: bRequest=%02x "
"bRrequestType=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
dr->bRequest, dr->bRequestType,
__le16_to_cpup(&dr->wValue),
__le16_to_cpup(&dr->wIndex),
__le16_to_cpup(&dr->wLength));
break; break;
case USBDEVFS_URB_TYPE_BULK: case USBDEVFS_URB_TYPE_BULK:
@ -1070,7 +1109,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
uurb->number_of_packets = 0; uurb->number_of_packets = 0;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL; return -EINVAL;
snoop(&ps->dev->dev, "bulk urb\n");
break; break;
case USBDEVFS_URB_TYPE_ISO: case USBDEVFS_URB_TYPE_ISO:
@ -1097,12 +1135,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
} }
totlen += isopkt[u].length; totlen += isopkt[u].length;
} }
if (totlen > 32768) { /* 3072 * 64 microframes */
if (totlen > 196608) {
kfree(isopkt); kfree(isopkt);
return -EINVAL; return -EINVAL;
} }
uurb->buffer_length = totlen; uurb->buffer_length = totlen;
snoop(&ps->dev->dev, "iso urb\n");
break; break;
case USBDEVFS_URB_TYPE_INTERRUPT: case USBDEVFS_URB_TYPE_INTERRUPT:
@ -1111,7 +1149,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -EINVAL; return -EINVAL;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE) if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL; return -EINVAL;
snoop(&ps->dev->dev, "interrupt urb\n");
break; break;
default: default:
@ -1198,11 +1235,46 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -EFAULT; return -EFAULT;
} }
} }
snoop_urb(as->urb, as->userurb); snoop_urb(ps->dev, as->userurb, as->urb->pipe,
as->urb->transfer_buffer_length, 0, SUBMIT);
async_newpending(as); async_newpending(as);
if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
if (usb_endpoint_xfer_bulk(&ep->desc)) {
spin_lock_irq(&ps->lock);
/* Not exactly the endpoint address; the direction bit is
* shifted to the 0x10 position so that the value will be
* between 0 and 31.
*/
as->bulk_addr = usb_endpoint_num(&ep->desc) |
((ep->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK)
>> 3);
/* If this bulk URB is the start of a new transfer, re-enable
* the endpoint. Otherwise mark it as a continuation URB.
*/
if (uurb->flags & USBDEVFS_URB_BULK_CONTINUATION)
as->bulk_status = AS_CONTINUATION;
else
ps->disabled_bulk_eps &= ~(1 << as->bulk_addr);
/* Don't accept continuation URBs if the endpoint is
* disabled because of an earlier error.
*/
if (ps->disabled_bulk_eps & (1 << as->bulk_addr))
ret = -EREMOTEIO;
else
ret = usb_submit_urb(as->urb, GFP_ATOMIC);
spin_unlock_irq(&ps->lock);
} else {
ret = usb_submit_urb(as->urb, GFP_KERNEL);
}
if (ret) {
dev_printk(KERN_DEBUG, &ps->dev->dev, dev_printk(KERN_DEBUG, &ps->dev->dev,
"usbfs: usb_submit_urb returned %d\n", ret); "usbfs: usb_submit_urb returned %d\n", ret);
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
0, ret, COMPLETE);
async_removepending(as); async_removepending(as);
free_async(as); free_async(as);
return ret; return ret;
@ -1548,6 +1620,29 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
} }
#endif #endif
static int proc_claim_port(struct dev_state *ps, void __user *arg)
{
unsigned portnum;
int rc;
if (get_user(portnum, (unsigned __user *) arg))
return -EFAULT;
rc = usb_hub_claim_port(ps->dev, portnum, ps);
if (rc == 0)
snoop(&ps->dev->dev, "port %d claimed by process %d: %s\n",
portnum, task_pid_nr(current), current->comm);
return rc;
}
static int proc_release_port(struct dev_state *ps, void __user *arg)
{
unsigned portnum;
if (get_user(portnum, (unsigned __user *) arg))
return -EFAULT;
return usb_hub_release_port(ps->dev, portnum, ps);
}
/* /*
* NOTE: All requests here that have interface numbers as parameters * NOTE: All requests here that have interface numbers as parameters
* are assuming that somehow the configuration has been prevented from * are assuming that somehow the configuration has been prevented from
@ -1645,7 +1740,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
break; break;
case USBDEVFS_REAPURBNDELAY32: case USBDEVFS_REAPURBNDELAY32:
snoop(&dev->dev, "%s: REAPURBDELAY32\n", __func__); snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
ret = proc_reapurbnonblock_compat(ps, p); ret = proc_reapurbnonblock_compat(ps, p);
break; break;
@ -1666,7 +1761,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
break; break;
case USBDEVFS_REAPURBNDELAY: case USBDEVFS_REAPURBNDELAY:
snoop(&dev->dev, "%s: REAPURBDELAY\n", __func__); snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
ret = proc_reapurbnonblock(ps, p); ret = proc_reapurbnonblock(ps, p);
break; break;
@ -1689,6 +1784,16 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
snoop(&dev->dev, "%s: IOCTL\n", __func__); snoop(&dev->dev, "%s: IOCTL\n", __func__);
ret = proc_ioctl_default(ps, p); ret = proc_ioctl_default(ps, p);
break; break;
case USBDEVFS_CLAIM_PORT:
snoop(&dev->dev, "%s: CLAIM_PORT\n", __func__);
ret = proc_claim_port(ps, p);
break;
case USBDEVFS_RELEASE_PORT:
snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__);
ret = proc_release_port(ps, p);
break;
} }
usb_unlock_device(dev); usb_unlock_device(dev);
if (ret >= 0) if (ret >= 0)

View File

@ -207,6 +207,9 @@ static int usb_probe_interface(struct device *dev)
intf->needs_binding = 0; intf->needs_binding = 0;
if (usb_device_is_owned(udev))
return -ENODEV;
if (udev->authorized == 0) { if (udev->authorized == 0) {
dev_err(&intf->dev, "Device is not authorized for usage\n"); dev_err(&intf->dev, "Device is not authorized for usage\n");
return -ENODEV; return -ENODEV;
@ -232,28 +235,35 @@ static int usb_probe_interface(struct device *dev)
/* The interface should always appear to be in use /* The interface should always appear to be in use
* unless the driver suports autosuspend. * unless the driver suports autosuspend.
*/ */
intf->pm_usage_cnt = !(driver->supports_autosuspend); atomic_set(&intf->pm_usage_cnt, !driver->supports_autosuspend);
/* Carry out a deferred switch to altsetting 0 */ /* Carry out a deferred switch to altsetting 0 */
if (intf->needs_altsetting0) { if (intf->needs_altsetting0) {
usb_set_interface(udev, intf->altsetting[0]. error = usb_set_interface(udev, intf->altsetting[0].
desc.bInterfaceNumber, 0); desc.bInterfaceNumber, 0);
if (error < 0)
goto err;
intf->needs_altsetting0 = 0; intf->needs_altsetting0 = 0;
} }
error = driver->probe(intf, id); error = driver->probe(intf, id);
if (error) { if (error)
mark_quiesced(intf); goto err;
intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
usb_cancel_queued_reset(intf);
} else
intf->condition = USB_INTERFACE_BOUND;
intf->condition = USB_INTERFACE_BOUND;
usb_autosuspend_device(udev); usb_autosuspend_device(udev);
} }
return error; return error;
err:
mark_quiesced(intf);
intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
usb_cancel_queued_reset(intf);
usb_autosuspend_device(udev);
return error;
} }
/* called from driver core with dev locked */ /* called from driver core with dev locked */
@ -262,7 +272,7 @@ static int usb_unbind_interface(struct device *dev)
struct usb_driver *driver = to_usb_driver(dev->driver); struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf = to_usb_interface(dev); struct usb_interface *intf = to_usb_interface(dev);
struct usb_device *udev; struct usb_device *udev;
int error; int error, r;
intf->condition = USB_INTERFACE_UNBINDING; intf->condition = USB_INTERFACE_UNBINDING;
@ -290,11 +300,14 @@ static int usb_unbind_interface(struct device *dev)
* Just re-enable it without affecting the endpoint toggles. * Just re-enable it without affecting the endpoint toggles.
*/ */
usb_enable_interface(udev, intf, false); usb_enable_interface(udev, intf, false);
} else if (!error && intf->dev.power.status == DPM_ON) } else if (!error && intf->dev.power.status == DPM_ON) {
usb_set_interface(udev, intf->altsetting[0]. r = usb_set_interface(udev, intf->altsetting[0].
desc.bInterfaceNumber, 0); desc.bInterfaceNumber, 0);
else if (r < 0)
intf->needs_altsetting0 = 1;
} else {
intf->needs_altsetting0 = 1; intf->needs_altsetting0 = 1;
}
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
intf->condition = USB_INTERFACE_UNBOUND; intf->condition = USB_INTERFACE_UNBOUND;
@ -344,7 +357,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
usb_pm_lock(udev); usb_pm_lock(udev);
iface->condition = USB_INTERFACE_BOUND; iface->condition = USB_INTERFACE_BOUND;
mark_active(iface); mark_active(iface);
iface->pm_usage_cnt = !(driver->supports_autosuspend); atomic_set(&iface->pm_usage_cnt, !driver->supports_autosuspend);
usb_pm_unlock(udev); usb_pm_unlock(udev);
/* if interface was already added, bind now; else let /* if interface was already added, bind now; else let
@ -1065,7 +1078,7 @@ static int autosuspend_check(struct usb_device *udev, int reschedule)
intf = udev->actconfig->interface[i]; intf = udev->actconfig->interface[i];
if (!is_active(intf)) if (!is_active(intf))
continue; continue;
if (intf->pm_usage_cnt > 0) if (atomic_read(&intf->pm_usage_cnt) > 0)
return -EBUSY; return -EBUSY;
if (intf->needs_remote_wakeup && if (intf->needs_remote_wakeup &&
!udev->do_remote_wakeup) { !udev->do_remote_wakeup) {
@ -1461,17 +1474,19 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
status = -ENODEV; status = -ENODEV;
else { else {
udev->auto_pm = 1; udev->auto_pm = 1;
intf->pm_usage_cnt += inc_usage_cnt; atomic_add(inc_usage_cnt, &intf->pm_usage_cnt);
udev->last_busy = jiffies; udev->last_busy = jiffies;
if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) { if (inc_usage_cnt >= 0 &&
atomic_read(&intf->pm_usage_cnt) > 0) {
if (udev->state == USB_STATE_SUSPENDED) if (udev->state == USB_STATE_SUSPENDED)
status = usb_resume_both(udev, status = usb_resume_both(udev,
PMSG_AUTO_RESUME); PMSG_AUTO_RESUME);
if (status != 0) if (status != 0)
intf->pm_usage_cnt -= inc_usage_cnt; atomic_sub(inc_usage_cnt, &intf->pm_usage_cnt);
else else
udev->last_busy = jiffies; udev->last_busy = jiffies;
} else if (inc_usage_cnt <= 0 && intf->pm_usage_cnt <= 0) { } else if (inc_usage_cnt <= 0 &&
atomic_read(&intf->pm_usage_cnt) <= 0) {
status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND); status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
} }
} }
@ -1516,7 +1531,7 @@ void usb_autopm_put_interface(struct usb_interface *intf)
status = usb_autopm_do_interface(intf, -1); status = usb_autopm_do_interface(intf, -1);
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
__func__, status, intf->pm_usage_cnt); __func__, status, atomic_read(&intf->pm_usage_cnt));
} }
EXPORT_SYMBOL_GPL(usb_autopm_put_interface); EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
@ -1544,10 +1559,10 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
status = -ENODEV; status = -ENODEV;
} else { } else {
udev->last_busy = jiffies; udev->last_busy = jiffies;
--intf->pm_usage_cnt; atomic_dec(&intf->pm_usage_cnt);
if (udev->autosuspend_disabled || udev->autosuspend_delay < 0) if (udev->autosuspend_disabled || udev->autosuspend_delay < 0)
status = -EPERM; status = -EPERM;
else if (intf->pm_usage_cnt <= 0 && else if (atomic_read(&intf->pm_usage_cnt) <= 0 &&
!timer_pending(&udev->autosuspend.timer)) { !timer_pending(&udev->autosuspend.timer)) {
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
round_jiffies_up_relative( round_jiffies_up_relative(
@ -1555,7 +1570,7 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
} }
} }
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
__func__, status, intf->pm_usage_cnt); __func__, status, atomic_read(&intf->pm_usage_cnt));
} }
EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async); EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
@ -1599,7 +1614,7 @@ int usb_autopm_get_interface(struct usb_interface *intf)
status = usb_autopm_do_interface(intf, 1); status = usb_autopm_do_interface(intf, 1);
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
__func__, status, intf->pm_usage_cnt); __func__, status, atomic_read(&intf->pm_usage_cnt));
return status; return status;
} }
EXPORT_SYMBOL_GPL(usb_autopm_get_interface); EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
@ -1627,10 +1642,14 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
status = -ENODEV; status = -ENODEV;
else if (udev->autoresume_disabled) else if (udev->autoresume_disabled)
status = -EPERM; status = -EPERM;
else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED) else {
queue_work(ksuspend_usb_wq, &udev->autoresume); atomic_inc(&intf->pm_usage_cnt);
if (atomic_read(&intf->pm_usage_cnt) > 0 &&
udev->state == USB_STATE_SUSPENDED)
queue_work(ksuspend_usb_wq, &udev->autoresume);
}
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
__func__, status, intf->pm_usage_cnt); __func__, status, atomic_read(&intf->pm_usage_cnt));
return status; return status;
} }
EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async); EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
@ -1652,7 +1671,7 @@ int usb_autopm_set_interface(struct usb_interface *intf)
status = usb_autopm_do_interface(intf, 0); status = usb_autopm_do_interface(intf, 0);
dev_vdbg(&intf->dev, "%s: status %d cnt %d\n", dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
__func__, status, intf->pm_usage_cnt); __func__, status, atomic_read(&intf->pm_usage_cnt));
return status; return status;
} }
EXPORT_SYMBOL_GPL(usb_autopm_set_interface); EXPORT_SYMBOL_GPL(usb_autopm_set_interface);

View File

@ -158,7 +158,9 @@ static int generic_probe(struct usb_device *udev)
/* Choose and set the configuration. This registers the interfaces /* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them. * with the driver core and lets interface drivers bind to them.
*/ */
if (udev->authorized == 0) if (usb_device_is_owned(udev))
; /* Don't configure if the device is owned */
else if (udev->authorized == 0)
dev_err(&udev->dev, "Device is not authorized for usage\n"); dev_err(&udev->dev, "Device is not authorized for usage\n");
else { else {
c = usb_choose_configuration(udev); c = usb_choose_configuration(udev);

View File

@ -337,72 +337,89 @@ static const u8 ss_rh_config_descriptor[] = {
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* /**
* helper routine for returning string descriptors in UTF-16LE * ascii2desc() - Helper routine for producing UTF-16LE string descriptors
* input can actually be ISO-8859-1; ASCII is its 7-bit subset * @s: Null-terminated ASCII (actually ISO-8859-1) string
* @buf: Buffer for USB string descriptor (header + UTF-16LE)
* @len: Length (in bytes; may be odd) of descriptor buffer.
*
* The return value is the number of bytes filled in: 2 + 2*strlen(s) or
* buflen, whichever is less.
*
* USB String descriptors can contain at most 126 characters; input
* strings longer than that are truncated.
*/ */
static unsigned ascii2utf(char *s, u8 *utf, int utfmax) static unsigned
ascii2desc(char const *s, u8 *buf, unsigned len)
{ {
unsigned retval; unsigned n, t = 2 + 2*strlen(s);
for (retval = 0; *s && utfmax > 1; utfmax -= 2, retval += 2) { if (t > 254)
*utf++ = *s++; t = 254; /* Longest possible UTF string descriptor */
*utf++ = 0; if (len > t)
len = t;
t += USB_DT_STRING << 8; /* Now t is first 16 bits to store */
n = len;
while (n--) {
*buf++ = t;
if (!n--)
break;
*buf++ = t >> 8;
t = (unsigned char)*s++;
} }
if (utfmax > 0) { return len;
*utf = *s;
++retval;
}
return retval;
} }
/* /**
* rh_string - provides manufacturer, product and serial strings for root hub * rh_string() - provides string descriptors for root hub
* @id: the string ID number (1: serial number, 2: product, 3: vendor) * @id: the string ID number (0: langids, 1: serial #, 2: product, 3: vendor)
* @hcd: the host controller for this root hub * @hcd: the host controller for this root hub
* @data: return packet in UTF-16 LE * @data: buffer for output packet
* @len: length of the return packet * @len: length of the provided buffer
* *
* Produces either a manufacturer, product or serial number string for the * Produces either a manufacturer, product or serial number string for the
* virtual root hub device. * virtual root hub device.
* Returns the number of bytes filled in: the length of the descriptor or
* of the provided buffer, whichever is less.
*/ */
static unsigned rh_string(int id, struct usb_hcd *hcd, u8 *data, unsigned len) static unsigned
rh_string(int id, struct usb_hcd const *hcd, u8 *data, unsigned len)
{ {
char buf [100]; char buf[100];
char const *s;
static char const langids[4] = {4, USB_DT_STRING, 0x09, 0x04};
// language ids // language ids
if (id == 0) { switch (id) {
buf[0] = 4; buf[1] = 3; /* 4 bytes string data */ case 0:
buf[2] = 0x09; buf[3] = 0x04; /* MSFT-speak for "en-us" */ /* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */
len = min_t(unsigned, len, 4); /* See http://www.usb.org/developers/docs/USB_LANGIDs.pdf */
memcpy (data, buf, len); if (len > 4)
len = 4;
memcpy(data, langids, len);
return len; return len;
case 1:
// serial number /* Serial number */
} else if (id == 1) { s = hcd->self.bus_name;
strlcpy (buf, hcd->self.bus_name, sizeof buf); break;
case 2:
// product description /* Product name */
} else if (id == 2) { s = hcd->product_desc;
strlcpy (buf, hcd->product_desc, sizeof buf); break;
case 3:
// id 3 == vendor description /* Manufacturer */
} else if (id == 3) {
snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname, snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname,
init_utsname()->release, hcd->driver->description); init_utsname()->release, hcd->driver->description);
s = buf;
break;
default:
/* Can't happen; caller guarantees it */
return 0;
} }
switch (len) { /* All cases fall through */ return ascii2desc(s, data, len);
default:
len = 2 + ascii2utf (buf, data + 2, len - 2);
case 2:
data [1] = 3; /* type == string */
case 1:
data [0] = 2 * (strlen (buf) + 1);
case 0:
; /* Compiler wants a statement here */
}
return len;
} }

View File

@ -267,6 +267,11 @@ struct hc_driver {
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
/* Returns the hardware-chosen device address */ /* Returns the hardware-chosen device address */
int (*address_device)(struct usb_hcd *, struct usb_device *udev); int (*address_device)(struct usb_hcd *, struct usb_device *udev);
/* Notifies the HCD after a hub descriptor is fetched.
* Will block.
*/
int (*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
}; };
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb); extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);

View File

@ -78,6 +78,7 @@ struct usb_hub {
u8 indicator[USB_MAXCHILDREN]; u8 indicator[USB_MAXCHILDREN];
struct delayed_work leds; struct delayed_work leds;
struct delayed_work init_work; struct delayed_work init_work;
void **port_owners;
}; };
@ -162,8 +163,10 @@ static inline char *portspeed(int portstatus)
} }
/* Note that hdev or one of its children must be locked! */ /* Note that hdev or one of its children must be locked! */
static inline struct usb_hub *hdev_to_hub(struct usb_device *hdev) static struct usb_hub *hdev_to_hub(struct usb_device *hdev)
{ {
if (!hdev || !hdev->actconfig)
return NULL;
return usb_get_intfdata(hdev->actconfig->interface[0]); return usb_get_intfdata(hdev->actconfig->interface[0]);
} }
@ -372,7 +375,7 @@ static void kick_khubd(struct usb_hub *hub)
unsigned long flags; unsigned long flags;
/* Suppress autosuspend until khubd runs */ /* Suppress autosuspend until khubd runs */
to_usb_interface(hub->intfdev)->pm_usage_cnt = 1; atomic_set(&to_usb_interface(hub->intfdev)->pm_usage_cnt, 1);
spin_lock_irqsave(&hub_event_lock, flags); spin_lock_irqsave(&hub_event_lock, flags);
if (!hub->disconnected && list_empty(&hub->event_list)) { if (!hub->disconnected && list_empty(&hub->event_list)) {
@ -384,8 +387,10 @@ static void kick_khubd(struct usb_hub *hub)
void usb_kick_khubd(struct usb_device *hdev) void usb_kick_khubd(struct usb_device *hdev)
{ {
/* FIXME: What if hdev isn't bound to the hub driver? */ struct usb_hub *hub = hdev_to_hub(hdev);
kick_khubd(hdev_to_hub(hdev));
if (hub)
kick_khubd(hub);
} }
@ -677,7 +682,8 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
msecs_to_jiffies(delay)); msecs_to_jiffies(delay));
/* Suppress autosuspend until init is done */ /* Suppress autosuspend until init is done */
to_usb_interface(hub->intfdev)->pm_usage_cnt = 1; atomic_set(&to_usb_interface(hub->intfdev)->
pm_usage_cnt, 1);
return; /* Continues at init2: below */ return; /* Continues at init2: below */
} else { } else {
hub_power_on(hub, true); hub_power_on(hub, true);
@ -854,25 +860,24 @@ static int hub_post_reset(struct usb_interface *intf)
static int hub_configure(struct usb_hub *hub, static int hub_configure(struct usb_hub *hub,
struct usb_endpoint_descriptor *endpoint) struct usb_endpoint_descriptor *endpoint)
{ {
struct usb_hcd *hcd;
struct usb_device *hdev = hub->hdev; struct usb_device *hdev = hub->hdev;
struct device *hub_dev = hub->intfdev; struct device *hub_dev = hub->intfdev;
u16 hubstatus, hubchange; u16 hubstatus, hubchange;
u16 wHubCharacteristics; u16 wHubCharacteristics;
unsigned int pipe; unsigned int pipe;
int maxp, ret; int maxp, ret;
char *message; char *message = "out of memory";
hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL, hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,
&hub->buffer_dma); &hub->buffer_dma);
if (!hub->buffer) { if (!hub->buffer) {
message = "can't allocate hub irq buffer";
ret = -ENOMEM; ret = -ENOMEM;
goto fail; goto fail;
} }
hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL); hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
if (!hub->status) { if (!hub->status) {
message = "can't kmalloc hub status buffer";
ret = -ENOMEM; ret = -ENOMEM;
goto fail; goto fail;
} }
@ -880,7 +885,6 @@ static int hub_configure(struct usb_hub *hub,
hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL); hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
if (!hub->descriptor) { if (!hub->descriptor) {
message = "can't kmalloc hub descriptor";
ret = -ENOMEM; ret = -ENOMEM;
goto fail; goto fail;
} }
@ -904,6 +908,12 @@ static int hub_configure(struct usb_hub *hub,
dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild, dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
(hdev->maxchild == 1) ? "" : "s"); (hdev->maxchild == 1) ? "" : "s");
hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
if (!hub->port_owners) {
ret = -ENOMEM;
goto fail;
}
wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
if (wHubCharacteristics & HUB_CHAR_COMPOUND) { if (wHubCharacteristics & HUB_CHAR_COMPOUND) {
@ -1052,6 +1062,19 @@ static int hub_configure(struct usb_hub *hub,
dev_dbg(hub_dev, "%umA bus power budget for each child\n", dev_dbg(hub_dev, "%umA bus power budget for each child\n",
hub->mA_per_port); hub->mA_per_port);
/* Update the HCD's internal representation of this hub before khubd
* starts getting port status changes for devices under the hub.
*/
hcd = bus_to_hcd(hdev->bus);
if (hcd->driver->update_hub_device) {
ret = hcd->driver->update_hub_device(hcd, hdev,
&hub->tt, GFP_KERNEL);
if (ret < 0) {
message = "can't update HCD hub info";
goto fail;
}
}
ret = hub_hub_status(hub, &hubstatus, &hubchange); ret = hub_hub_status(hub, &hubstatus, &hubchange);
if (ret < 0) { if (ret < 0) {
message = "can't get hub status"; message = "can't get hub status";
@ -1082,7 +1105,6 @@ static int hub_configure(struct usb_hub *hub,
hub->urb = usb_alloc_urb(0, GFP_KERNEL); hub->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!hub->urb) { if (!hub->urb) {
message = "couldn't allocate interrupt urb";
ret = -ENOMEM; ret = -ENOMEM;
goto fail; goto fail;
} }
@ -1131,11 +1153,13 @@ static void hub_disconnect(struct usb_interface *intf)
hub_quiesce(hub, HUB_DISCONNECT); hub_quiesce(hub, HUB_DISCONNECT);
usb_set_intfdata (intf, NULL); usb_set_intfdata (intf, NULL);
hub->hdev->maxchild = 0;
if (hub->hdev->speed == USB_SPEED_HIGH) if (hub->hdev->speed == USB_SPEED_HIGH)
highspeed_hubs--; highspeed_hubs--;
usb_free_urb(hub->urb); usb_free_urb(hub->urb);
kfree(hub->port_owners);
kfree(hub->descriptor); kfree(hub->descriptor);
kfree(hub->status); kfree(hub->status);
usb_buffer_free(hub->hdev, sizeof(*hub->buffer), hub->buffer, usb_buffer_free(hub->hdev, sizeof(*hub->buffer), hub->buffer,
@ -1250,6 +1274,79 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
} }
} }
/*
* Allow user programs to claim ports on a hub. When a device is attached
* to one of these "claimed" ports, the program will "own" the device.
*/
static int find_port_owner(struct usb_device *hdev, unsigned port1,
void ***ppowner)
{
if (hdev->state == USB_STATE_NOTATTACHED)
return -ENODEV;
if (port1 == 0 || port1 > hdev->maxchild)
return -EINVAL;
/* This assumes that devices not managed by the hub driver
* will always have maxchild equal to 0.
*/
*ppowner = &(hdev_to_hub(hdev)->port_owners[port1 - 1]);
return 0;
}
/* In the following three functions, the caller must hold hdev's lock */
int usb_hub_claim_port(struct usb_device *hdev, unsigned port1, void *owner)
{
int rc;
void **powner;
rc = find_port_owner(hdev, port1, &powner);
if (rc)
return rc;
if (*powner)
return -EBUSY;
*powner = owner;
return rc;
}
int usb_hub_release_port(struct usb_device *hdev, unsigned port1, void *owner)
{
int rc;
void **powner;
rc = find_port_owner(hdev, port1, &powner);
if (rc)
return rc;
if (*powner != owner)
return -ENOENT;
*powner = NULL;
return rc;
}
void usb_hub_release_all_ports(struct usb_device *hdev, void *owner)
{
int n;
void **powner;
n = find_port_owner(hdev, 1, &powner);
if (n == 0) {
for (; n < hdev->maxchild; (++n, ++powner)) {
if (*powner == owner)
*powner = NULL;
}
}
}
/* The caller must hold udev's lock */
bool usb_device_is_owned(struct usb_device *udev)
{
struct usb_hub *hub;
if (udev->state == USB_STATE_NOTATTACHED || !udev->parent)
return false;
hub = hdev_to_hub(udev->parent);
return !!hub->port_owners[udev->portnum - 1];
}
static void recursively_mark_NOTATTACHED(struct usb_device *udev) static void recursively_mark_NOTATTACHED(struct usb_device *udev)
{ {
@ -2849,14 +2946,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
/* For a suspended device, treat this as a /* For a suspended device, treat this as a
* remote wakeup event. * remote wakeup event.
*/ */
if (udev->do_remote_wakeup) status = remote_wakeup(udev);
status = remote_wakeup(udev);
/* Otherwise leave it be; devices can't tell the
* difference between suspended and disabled.
*/
else
status = 0;
#endif #endif
} else { } else {

View File

@ -459,35 +459,23 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
io->urbs[i]->context = io; io->urbs[i]->context = io;
/* /*
* Some systems need to revert to PIO when DMA is * Some systems need to revert to PIO when DMA is temporarily
* temporarily unavailable. For their sakes, both * unavailable. For their sakes, both transfer_buffer and
* transfer_buffer and transfer_dma are set when * transfer_dma are set when possible.
* possible. However this can only work on systems
* without:
* *
* - HIGHMEM, since DMA buffers located in high memory * Note that if IOMMU coalescing occurred, we cannot
* are not directly addressable by the CPU for PIO; * trust sg_page anymore, so check if S/G list shrunk.
*
* - IOMMU, since dma_map_sg() is allowed to use an
* IOMMU to make virtually discontiguous buffers be
* "dma-contiguous" so that PIO and DMA need diferent
* numbers of URBs.
*
* So when HIGHMEM or IOMMU are in use, transfer_buffer
* is NULL to prevent stale pointers and to help spot
* bugs.
*/ */
if (io->nents == io->entries && !PageHighMem(sg_page(sg)))
io->urbs[i]->transfer_buffer = sg_virt(sg);
else
io->urbs[i]->transfer_buffer = NULL;
if (dma) { if (dma) {
io->urbs[i]->transfer_dma = sg_dma_address(sg); io->urbs[i]->transfer_dma = sg_dma_address(sg);
len = sg_dma_len(sg); len = sg_dma_len(sg);
#if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU)
io->urbs[i]->transfer_buffer = NULL;
#else
io->urbs[i]->transfer_buffer = sg_virt(sg);
#endif
} else { } else {
/* hc may use _only_ transfer_buffer */ /* hc may use _only_ transfer_buffer */
io->urbs[i]->transfer_buffer = sg_virt(sg);
len = sg->length; len = sg->length;
} }

View File

@ -413,8 +413,13 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
} else { } else {
snprintf(dev->devpath, sizeof dev->devpath, snprintf(dev->devpath, sizeof dev->devpath,
"%s.%d", parent->devpath, port1); "%s.%d", parent->devpath, port1);
dev->route = parent->route + /* Route string assumes hubs have less than 16 ports */
(port1 << ((parent->level - 1)*4)); if (port1 < 15)
dev->route = parent->route +
(port1 << ((parent->level - 1)*4));
else
dev->route = parent->route +
(15 << ((parent->level - 1)*4));
} }
dev->dev.parent = &parent->dev; dev->dev.parent = &parent->dev;
@ -914,11 +919,11 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
|| !(bus = dev->bus) || !(bus = dev->bus)
|| !(controller = bus->controller) || !(controller = bus->controller)
|| !controller->dma_mask) || !controller->dma_mask)
return -1; return -EINVAL;
/* FIXME generic api broken like pci, can't report errors */ /* FIXME generic api broken like pci, can't report errors */
return dma_map_sg(controller, sg, nents, return dma_map_sg(controller, sg, nents,
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE); is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE) ? : -ENOMEM;
} }
EXPORT_SYMBOL_GPL(usb_buffer_map_sg); EXPORT_SYMBOL_GPL(usb_buffer_map_sg);

View File

@ -37,6 +37,13 @@ extern int usb_match_device(struct usb_device *dev,
extern void usb_forced_unbind_intf(struct usb_interface *intf); extern void usb_forced_unbind_intf(struct usb_interface *intf);
extern void usb_rebind_intf(struct usb_interface *intf); extern void usb_rebind_intf(struct usb_interface *intf);
extern int usb_hub_claim_port(struct usb_device *hdev, unsigned port,
void *owner);
extern int usb_hub_release_port(struct usb_device *hdev, unsigned port,
void *owner);
extern void usb_hub_release_all_ports(struct usb_device *hdev, void *owner);
extern bool usb_device_is_owned(struct usb_device *udev);
extern int usb_hub_init(void); extern int usb_hub_init(void);
extern void usb_hub_cleanup(void); extern void usb_hub_cleanup(void);
extern int usb_major_init(void); extern int usb_major_init(void);

View File

@ -0,0 +1,5 @@
#
# Makefile for early USB devices
#
obj-$(CONFIG_EARLY_PRINTK_DBGP) += ehci-dbgp.o

View File

@ -0,0 +1,996 @@
/*
* Standalone EHCI usb debug driver
*
* Originally written by:
* Eric W. Biederman" <ebiederm@xmission.com> and
* Yinghai Lu <yhlu.kernel@gmail.com>
*
* Changes for early/late printk and HW errata:
* Jason Wessel <jason.wessel@windriver.com>
* Copyright (C) 2009 Wind River Systems, Inc.
*
*/
#include <linux/console.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/pci_regs.h>
#include <linux/pci_ids.h>
#include <linux/usb/ch9.h>
#include <linux/usb/ehci_def.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/pci-direct.h>
#include <asm/fixmap.h>
/* The code here is intended to talk directly to the EHCI debug port
* and does not require that you have any kind of USB host controller
* drivers or USB device drivers compiled into the kernel.
*
* If you make a change to anything in here, the following test cases
* need to pass where a USB debug device works in the following
* configurations.
*
* 1. boot args: earlyprintk=dbgp
* o kernel compiled with # CONFIG_USB_EHCI_HCD is not set
* o kernel compiled with CONFIG_USB_EHCI_HCD=y
* 2. boot args: earlyprintk=dbgp,keep
* o kernel compiled with # CONFIG_USB_EHCI_HCD is not set
* o kernel compiled with CONFIG_USB_EHCI_HCD=y
* 3. boot args: earlyprintk=dbgp console=ttyUSB0
* o kernel has CONFIG_USB_EHCI_HCD=y and
* CONFIG_USB_SERIAL_DEBUG=y
* 4. boot args: earlyprintk=vga,dbgp
* o kernel compiled with # CONFIG_USB_EHCI_HCD is not set
* o kernel compiled with CONFIG_USB_EHCI_HCD=y
*
* For the 4th configuration you can turn on or off the DBGP_DEBUG
* such that you can debug the dbgp device's driver code.
*/
static int dbgp_phys_port = 1;
static struct ehci_caps __iomem *ehci_caps;
static struct ehci_regs __iomem *ehci_regs;
static struct ehci_dbg_port __iomem *ehci_debug;
static int dbgp_not_safe; /* Cannot use debug device during ehci reset */
static unsigned int dbgp_endpoint_out;
struct ehci_dev {
u32 bus;
u32 slot;
u32 func;
};
static struct ehci_dev ehci_dev;
#define USB_DEBUG_DEVNUM 127
#define DBGP_DATA_TOGGLE 0x8800
#ifdef DBGP_DEBUG
#define dbgp_printk printk
static void dbgp_ehci_status(char *str)
{
if (!ehci_debug)
return;
dbgp_printk("dbgp: %s\n", str);
dbgp_printk(" Debug control: %08x", readl(&ehci_debug->control));
dbgp_printk(" ehci cmd : %08x", readl(&ehci_regs->command));
dbgp_printk(" ehci conf flg: %08x\n",
readl(&ehci_regs->configured_flag));
dbgp_printk(" ehci status : %08x", readl(&ehci_regs->status));
dbgp_printk(" ehci portsc : %08x\n",
readl(&ehci_regs->port_status[dbgp_phys_port - 1]));
}
#else
static inline void dbgp_ehci_status(char *str) { }
static inline void dbgp_printk(const char *fmt, ...) { }
#endif
static inline u32 dbgp_pid_update(u32 x, u32 tok)
{
return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff);
}
static inline u32 dbgp_len_update(u32 x, u32 len)
{
return (x & ~0x0f) | (len & 0x0f);
}
/*
* USB Packet IDs (PIDs)
*/
/* token */
#define USB_PID_OUT 0xe1
#define USB_PID_IN 0x69
#define USB_PID_SOF 0xa5
#define USB_PID_SETUP 0x2d
/* handshake */
#define USB_PID_ACK 0xd2
#define USB_PID_NAK 0x5a
#define USB_PID_STALL 0x1e
#define USB_PID_NYET 0x96
/* data */
#define USB_PID_DATA0 0xc3
#define USB_PID_DATA1 0x4b
#define USB_PID_DATA2 0x87
#define USB_PID_MDATA 0x0f
/* Special */
#define USB_PID_PREAMBLE 0x3c
#define USB_PID_ERR 0x3c
#define USB_PID_SPLIT 0x78
#define USB_PID_PING 0xb4
#define USB_PID_UNDEF_0 0xf0
#define USB_PID_DATA_TOGGLE 0x88
#define DBGP_CLAIM (DBGP_OWNER | DBGP_ENABLED | DBGP_INUSE)
#define PCI_CAP_ID_EHCI_DEBUG 0xa
#define HUB_ROOT_RESET_TIME 50 /* times are in msec */
#define HUB_SHORT_RESET_TIME 10
#define HUB_LONG_RESET_TIME 200
#define HUB_RESET_TIMEOUT 500
#define DBGP_MAX_PACKET 8
#define DBGP_TIMEOUT (250 * 1000)
static int dbgp_wait_until_complete(void)
{
u32 ctrl;
int loop = DBGP_TIMEOUT;
do {
ctrl = readl(&ehci_debug->control);
/* Stop when the transaction is finished */
if (ctrl & DBGP_DONE)
break;
udelay(1);
} while (--loop > 0);
if (!loop)
return -DBGP_TIMEOUT;
/*
* Now that we have observed the completed transaction,
* clear the done bit.
*/
writel(ctrl | DBGP_DONE, &ehci_debug->control);
return (ctrl & DBGP_ERROR) ? -DBGP_ERRCODE(ctrl) : DBGP_LEN(ctrl);
}
static inline void dbgp_mdelay(int ms)
{
int i;
while (ms--) {
for (i = 0; i < 1000; i++)
outb(0x1, 0x80);
}
}
static void dbgp_breath(void)
{
/* Sleep to give the debug port a chance to breathe */
}
static int dbgp_wait_until_done(unsigned ctrl)
{
u32 pids, lpid;
int ret;
int loop = 3;
retry:
writel(ctrl | DBGP_GO, &ehci_debug->control);
ret = dbgp_wait_until_complete();
pids = readl(&ehci_debug->pids);
lpid = DBGP_PID_GET(pids);
if (ret < 0) {
/* A -DBGP_TIMEOUT failure here means the device has
* failed, perhaps because it was unplugged, in which
* case we do not want to hang the system so the dbgp
* will be marked as unsafe to use. EHCI reset is the
* only way to recover if you unplug the dbgp device.
*/
if (ret == -DBGP_TIMEOUT && !dbgp_not_safe)
dbgp_not_safe = 1;
return ret;
}
/*
* If the port is getting full or it has dropped data
* start pacing ourselves, not necessary but it's friendly.
*/
if ((lpid == USB_PID_NAK) || (lpid == USB_PID_NYET))
dbgp_breath();
/* If I get a NACK reissue the transmission */
if (lpid == USB_PID_NAK) {
if (--loop > 0)
goto retry;
}
return ret;
}
static inline void dbgp_set_data(const void *buf, int size)
{
const unsigned char *bytes = buf;
u32 lo, hi;
int i;
lo = hi = 0;
for (i = 0; i < 4 && i < size; i++)
lo |= bytes[i] << (8*i);
for (; i < 8 && i < size; i++)
hi |= bytes[i] << (8*(i - 4));
writel(lo, &ehci_debug->data03);
writel(hi, &ehci_debug->data47);
}
static inline void dbgp_get_data(void *buf, int size)
{
unsigned char *bytes = buf;
u32 lo, hi;
int i;
lo = readl(&ehci_debug->data03);
hi = readl(&ehci_debug->data47);
for (i = 0; i < 4 && i < size; i++)
bytes[i] = (lo >> (8*i)) & 0xff;
for (; i < 8 && i < size; i++)
bytes[i] = (hi >> (8*(i - 4))) & 0xff;
}
static int dbgp_out(u32 addr, const char *bytes, int size)
{
u32 pids, ctrl;
pids = readl(&ehci_debug->pids);
pids = dbgp_pid_update(pids, USB_PID_OUT);
ctrl = readl(&ehci_debug->control);
ctrl = dbgp_len_update(ctrl, size);
ctrl |= DBGP_OUT;
ctrl |= DBGP_GO;
dbgp_set_data(bytes, size);
writel(addr, &ehci_debug->address);
writel(pids, &ehci_debug->pids);
return dbgp_wait_until_done(ctrl);
}
static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
const char *bytes, int size)
{
int ret;
int loops = 5;
u32 addr;
if (size > DBGP_MAX_PACKET)
return -1;
addr = DBGP_EPADDR(devnum, endpoint);
try_again:
if (loops--) {
ret = dbgp_out(addr, bytes, size);
if (ret == -DBGP_ERR_BAD) {
int try_loops = 3;
do {
/* Emit a dummy packet to re-sync communication
* with the debug device */
if (dbgp_out(addr, "12345678", 8) >= 0) {
udelay(2);
goto try_again;
}
} while (try_loops--);
}
}
return ret;
}
static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
int size)
{
u32 pids, addr, ctrl;
int ret;
if (size > DBGP_MAX_PACKET)
return -1;
addr = DBGP_EPADDR(devnum, endpoint);
pids = readl(&ehci_debug->pids);
pids = dbgp_pid_update(pids, USB_PID_IN);
ctrl = readl(&ehci_debug->control);
ctrl = dbgp_len_update(ctrl, size);
ctrl &= ~DBGP_OUT;
ctrl |= DBGP_GO;
writel(addr, &ehci_debug->address);
writel(pids, &ehci_debug->pids);
ret = dbgp_wait_until_done(ctrl);
if (ret < 0)
return ret;
if (size > ret)
size = ret;
dbgp_get_data(data, size);
return ret;
}
static int dbgp_control_msg(unsigned devnum, int requesttype,
int request, int value, int index, void *data, int size)
{
u32 pids, addr, ctrl;
struct usb_ctrlrequest req;
int read;
int ret;
read = (requesttype & USB_DIR_IN) != 0;
if (size > (read ? DBGP_MAX_PACKET:0))
return -1;
/* Compute the control message */
req.bRequestType = requesttype;
req.bRequest = request;
req.wValue = cpu_to_le16(value);
req.wIndex = cpu_to_le16(index);
req.wLength = cpu_to_le16(size);
pids = DBGP_PID_SET(USB_PID_DATA0, USB_PID_SETUP);
addr = DBGP_EPADDR(devnum, 0);
ctrl = readl(&ehci_debug->control);
ctrl = dbgp_len_update(ctrl, sizeof(req));
ctrl |= DBGP_OUT;
ctrl |= DBGP_GO;
/* Send the setup message */
dbgp_set_data(&req, sizeof(req));
writel(addr, &ehci_debug->address);
writel(pids, &ehci_debug->pids);
ret = dbgp_wait_until_done(ctrl);
if (ret < 0)
return ret;
/* Read the result */
return dbgp_bulk_read(devnum, 0, data, size);
}
/* Find a PCI capability */
static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap)
{
u8 pos;
int bytes;
if (!(read_pci_config_16(num, slot, func, PCI_STATUS) &
PCI_STATUS_CAP_LIST))
return 0;
pos = read_pci_config_byte(num, slot, func, PCI_CAPABILITY_LIST);
for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
u8 id;
pos &= ~3;
id = read_pci_config_byte(num, slot, func, pos+PCI_CAP_LIST_ID);
if (id == 0xff)
break;
if (id == cap)
return pos;
pos = read_pci_config_byte(num, slot, func,
pos+PCI_CAP_LIST_NEXT);
}
return 0;
}
static u32 __init __find_dbgp(u32 bus, u32 slot, u32 func)
{
u32 class;
class = read_pci_config(bus, slot, func, PCI_CLASS_REVISION);
if ((class >> 8) != PCI_CLASS_SERIAL_USB_EHCI)
return 0;
return find_cap(bus, slot, func, PCI_CAP_ID_EHCI_DEBUG);
}
static u32 __init find_dbgp(int ehci_num, u32 *rbus, u32 *rslot, u32 *rfunc)
{
u32 bus, slot, func;
for (bus = 0; bus < 256; bus++) {
for (slot = 0; slot < 32; slot++) {
for (func = 0; func < 8; func++) {
unsigned cap;
cap = __find_dbgp(bus, slot, func);
if (!cap)
continue;
if (ehci_num-- != 0)
continue;
*rbus = bus;
*rslot = slot;
*rfunc = func;
return cap;
}
}
}
return 0;
}
static int dbgp_ehci_startup(void)
{
u32 ctrl, cmd, status;
int loop;
/* Claim ownership, but do not enable yet */
ctrl = readl(&ehci_debug->control);
ctrl |= DBGP_OWNER;
ctrl &= ~(DBGP_ENABLED | DBGP_INUSE);
writel(ctrl, &ehci_debug->control);
udelay(1);
dbgp_ehci_status("EHCI startup");
/* Start the ehci running */
cmd = readl(&ehci_regs->command);
cmd &= ~(CMD_LRESET | CMD_IAAD | CMD_PSE | CMD_ASE | CMD_RESET);
cmd |= CMD_RUN;
writel(cmd, &ehci_regs->command);
/* Ensure everything is routed to the EHCI */
writel(FLAG_CF, &ehci_regs->configured_flag);
/* Wait until the controller is no longer halted */
loop = 10;
do {
status = readl(&ehci_regs->status);
if (!(status & STS_HALT))
break;
udelay(1);
} while (--loop > 0);
if (!loop) {
dbgp_printk("ehci can not be started\n");
return -ENODEV;
}
dbgp_printk("ehci started\n");
return 0;
}
static int dbgp_ehci_controller_reset(void)
{
int loop = 250 * 1000;
u32 cmd;
/* Reset the EHCI controller */
cmd = readl(&ehci_regs->command);
cmd |= CMD_RESET;
writel(cmd, &ehci_regs->command);
do {
cmd = readl(&ehci_regs->command);
} while ((cmd & CMD_RESET) && (--loop > 0));
if (!loop) {
dbgp_printk("can not reset ehci\n");
return -1;
}
dbgp_ehci_status("ehci reset done");
return 0;
}
static int ehci_wait_for_port(int port);
/* Return 0 on success
* Return -ENODEV for any general failure
* Return -EIO if wait for port fails
*/
int dbgp_external_startup(void)
{
int devnum;
struct usb_debug_descriptor dbgp_desc;
int ret;
u32 ctrl, portsc, cmd;
int dbg_port = dbgp_phys_port;
int tries = 3;
int reset_port_tries = 1;
int try_hard_once = 1;
try_port_reset_again:
ret = dbgp_ehci_startup();
if (ret)
return ret;
/* Wait for a device to show up in the debug port */
ret = ehci_wait_for_port(dbg_port);
if (ret < 0) {
portsc = readl(&ehci_regs->port_status[dbg_port - 1]);
if (!(portsc & PORT_CONNECT) && try_hard_once) {
/* Last ditch effort to try to force enable
* the debug device by using the packet test
* ehci command to try and wake it up. */
try_hard_once = 0;
cmd = readl(&ehci_regs->command);
cmd &= ~CMD_RUN;
writel(cmd, &ehci_regs->command);
portsc = readl(&ehci_regs->port_status[dbg_port - 1]);
portsc |= PORT_TEST_PKT;
writel(portsc, &ehci_regs->port_status[dbg_port - 1]);
dbgp_ehci_status("Trying to force debug port online");
mdelay(50);
dbgp_ehci_controller_reset();
goto try_port_reset_again;
} else if (reset_port_tries--) {
goto try_port_reset_again;
}
dbgp_printk("No device found in debug port\n");
return -EIO;
}
dbgp_ehci_status("wait for port done");
/* Enable the debug port */
ctrl = readl(&ehci_debug->control);
ctrl |= DBGP_CLAIM;
writel(ctrl, &ehci_debug->control);
ctrl = readl(&ehci_debug->control);
if ((ctrl & DBGP_CLAIM) != DBGP_CLAIM) {
dbgp_printk("No device in debug port\n");
writel(ctrl & ~DBGP_CLAIM, &ehci_debug->control);
return -ENODEV;
}
dbgp_ehci_status("debug ported enabled");
/* Completely transfer the debug device to the debug controller */
portsc = readl(&ehci_regs->port_status[dbg_port - 1]);
portsc &= ~PORT_PE;
writel(portsc, &ehci_regs->port_status[dbg_port - 1]);
dbgp_mdelay(100);
try_again:
/* Find the debug device and make it device number 127 */
for (devnum = 0; devnum <= 127; devnum++) {
ret = dbgp_control_msg(devnum,
USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
USB_REQ_GET_DESCRIPTOR, (USB_DT_DEBUG << 8), 0,
&dbgp_desc, sizeof(dbgp_desc));
if (ret > 0)
break;
}
if (devnum > 127) {
dbgp_printk("Could not find attached debug device\n");
goto err;
}
if (ret < 0) {
dbgp_printk("Attached device is not a debug device\n");
goto err;
}
dbgp_endpoint_out = dbgp_desc.bDebugOutEndpoint;
/* Move the device to 127 if it isn't already there */
if (devnum != USB_DEBUG_DEVNUM) {
ret = dbgp_control_msg(devnum,
USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
USB_REQ_SET_ADDRESS, USB_DEBUG_DEVNUM, 0, NULL, 0);
if (ret < 0) {
dbgp_printk("Could not move attached device to %d\n",
USB_DEBUG_DEVNUM);
goto err;
}
devnum = USB_DEBUG_DEVNUM;
dbgp_printk("debug device renamed to 127\n");
}
/* Enable the debug interface */
ret = dbgp_control_msg(USB_DEBUG_DEVNUM,
USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
USB_REQ_SET_FEATURE, USB_DEVICE_DEBUG_MODE, 0, NULL, 0);
if (ret < 0) {
dbgp_printk(" Could not enable the debug device\n");
goto err;
}
dbgp_printk("debug interface enabled\n");
/* Perform a small write to get the even/odd data state in sync
*/
ret = dbgp_bulk_write(USB_DEBUG_DEVNUM, dbgp_endpoint_out, " ", 1);
if (ret < 0) {
dbgp_printk("dbgp_bulk_write failed: %d\n", ret);
goto err;
}
dbgp_printk("small write doned\n");
dbgp_not_safe = 0;
return 0;
err:
if (tries--)
goto try_again;
return -ENODEV;
}
EXPORT_SYMBOL_GPL(dbgp_external_startup);
static int __init ehci_reset_port(int port)
{
u32 portsc;
u32 delay_time, delay;
int loop;
dbgp_ehci_status("reset port");
/* Reset the usb debug port */
portsc = readl(&ehci_regs->port_status[port - 1]);
portsc &= ~PORT_PE;
portsc |= PORT_RESET;
writel(portsc, &ehci_regs->port_status[port - 1]);
delay = HUB_ROOT_RESET_TIME;
for (delay_time = 0; delay_time < HUB_RESET_TIMEOUT;
delay_time += delay) {
dbgp_mdelay(delay);
portsc = readl(&ehci_regs->port_status[port - 1]);
if (!(portsc & PORT_RESET))
break;
}
if (portsc & PORT_RESET) {
/* force reset to complete */
loop = 100 * 1000;
writel(portsc & ~(PORT_RWC_BITS | PORT_RESET),
&ehci_regs->port_status[port - 1]);
do {
udelay(1);
portsc = readl(&ehci_regs->port_status[port-1]);
} while ((portsc & PORT_RESET) && (--loop > 0));
}
/* Device went away? */
if (!(portsc & PORT_CONNECT))
return -ENOTCONN;
/* bomb out completely if something weird happend */
if ((portsc & PORT_CSC))
return -EINVAL;
/* If we've finished resetting, then break out of the loop */
if (!(portsc & PORT_RESET) && (portsc & PORT_PE))
return 0;
return -EBUSY;
}
static int ehci_wait_for_port(int port)
{
u32 status;
int ret, reps;
for (reps = 0; reps < 300; reps++) {
status = readl(&ehci_regs->status);
if (status & STS_PCD)
break;
dbgp_mdelay(1);
}
ret = ehci_reset_port(port);
if (ret == 0)
return 0;
return -ENOTCONN;
}
typedef void (*set_debug_port_t)(int port);
static void __init default_set_debug_port(int port)
{
}
static set_debug_port_t __initdata set_debug_port = default_set_debug_port;
static void __init nvidia_set_debug_port(int port)
{
u32 dword;
dword = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
0x74);
dword &= ~(0x0f<<12);
dword |= ((port & 0x0f)<<12);
write_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func, 0x74,
dword);
dbgp_printk("set debug port to %d\n", port);
}
static void __init detect_set_debug_port(void)
{
u32 vendorid;
vendorid = read_pci_config(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
0x00);
if ((vendorid & 0xffff) == 0x10de) {
dbgp_printk("using nvidia set_debug_port\n");
set_debug_port = nvidia_set_debug_port;
}
}
/* The code in early_ehci_bios_handoff() is derived from the usb pci
* quirk initialization, but altered so as to use the early PCI
* routines. */
#define EHCI_USBLEGSUP_BIOS (1 << 16) /* BIOS semaphore */
#define EHCI_USBLEGCTLSTS 4 /* legacy control/status */
static void __init early_ehci_bios_handoff(void)
{
u32 hcc_params = readl(&ehci_caps->hcc_params);
int offset = (hcc_params >> 8) & 0xff;
u32 cap;
int msec;
if (!offset)
return;
cap = read_pci_config(ehci_dev.bus, ehci_dev.slot,
ehci_dev.func, offset);
dbgp_printk("dbgp: ehci BIOS state %08x\n", cap);
if ((cap & 0xff) == 1 && (cap & EHCI_USBLEGSUP_BIOS)) {
dbgp_printk("dbgp: BIOS handoff\n");
write_pci_config_byte(ehci_dev.bus, ehci_dev.slot,
ehci_dev.func, offset + 3, 1);
}
/* if boot firmware now owns EHCI, spin till it hands it over. */
msec = 1000;
while ((cap & EHCI_USBLEGSUP_BIOS) && (msec > 0)) {
mdelay(10);
msec -= 10;
cap = read_pci_config(ehci_dev.bus, ehci_dev.slot,
ehci_dev.func, offset);
}
if (cap & EHCI_USBLEGSUP_BIOS) {
/* well, possibly buggy BIOS... try to shut it down,
* and hope nothing goes too wrong */
dbgp_printk("dbgp: BIOS handoff failed: %08x\n", cap);
write_pci_config_byte(ehci_dev.bus, ehci_dev.slot,
ehci_dev.func, offset + 2, 0);
}
/* just in case, always disable EHCI SMIs */
write_pci_config_byte(ehci_dev.bus, ehci_dev.slot, ehci_dev.func,
offset + EHCI_USBLEGCTLSTS, 0);
}
static int __init ehci_setup(void)
{
u32 ctrl, portsc, hcs_params;
u32 debug_port, new_debug_port = 0, n_ports;
int ret, i;
int port_map_tried;
int playtimes = 3;
early_ehci_bios_handoff();
try_next_time:
port_map_tried = 0;
try_next_port:
hcs_params = readl(&ehci_caps->hcs_params);
debug_port = HCS_DEBUG_PORT(hcs_params);
dbgp_phys_port = debug_port;
n_ports = HCS_N_PORTS(hcs_params);
dbgp_printk("debug_port: %d\n", debug_port);
dbgp_printk("n_ports: %d\n", n_ports);
dbgp_ehci_status("");
for (i = 1; i <= n_ports; i++) {
portsc = readl(&ehci_regs->port_status[i-1]);
dbgp_printk("portstatus%d: %08x\n", i, portsc);
}
if (port_map_tried && (new_debug_port != debug_port)) {
if (--playtimes) {
set_debug_port(new_debug_port);
goto try_next_time;
}
return -1;
}
/* Only reset the controller if it is not already in the
* configured state */
if (!(readl(&ehci_regs->configured_flag) & FLAG_CF)) {
if (dbgp_ehci_controller_reset() != 0)
return -1;
} else {
dbgp_ehci_status("ehci skip - already configured");
}
ret = dbgp_external_startup();
if (ret == -EIO)
goto next_debug_port;
if (ret < 0) {
/* Things didn't work so remove my claim */
ctrl = readl(&ehci_debug->control);
ctrl &= ~(DBGP_CLAIM | DBGP_OUT);
writel(ctrl, &ehci_debug->control);
return -1;
}
return 0;
next_debug_port:
port_map_tried |= (1<<(debug_port - 1));
new_debug_port = ((debug_port-1+1)%n_ports) + 1;
if (port_map_tried != ((1<<n_ports) - 1)) {
set_debug_port(new_debug_port);
goto try_next_port;
}
if (--playtimes) {
set_debug_port(new_debug_port);
goto try_next_time;
}
return -1;
}
int __init early_dbgp_init(char *s)
{
u32 debug_port, bar, offset;
u32 bus, slot, func, cap;
void __iomem *ehci_bar;
u32 dbgp_num;
u32 bar_val;
char *e;
int ret;
u8 byte;
if (!early_pci_allowed())
return -1;
dbgp_num = 0;
if (*s)
dbgp_num = simple_strtoul(s, &e, 10);
dbgp_printk("dbgp_num: %d\n", dbgp_num);
cap = find_dbgp(dbgp_num, &bus, &slot, &func);
if (!cap)
return -1;
dbgp_printk("Found EHCI debug port on %02x:%02x.%1x\n", bus, slot,
func);
debug_port = read_pci_config(bus, slot, func, cap);
bar = (debug_port >> 29) & 0x7;
bar = (bar * 4) + 0xc;
offset = (debug_port >> 16) & 0xfff;
dbgp_printk("bar: %02x offset: %03x\n", bar, offset);
if (bar != PCI_BASE_ADDRESS_0) {
dbgp_printk("only debug ports on bar 1 handled.\n");
return -1;
}
bar_val = read_pci_config(bus, slot, func, PCI_BASE_ADDRESS_0);
dbgp_printk("bar_val: %02x offset: %03x\n", bar_val, offset);
if (bar_val & ~PCI_BASE_ADDRESS_MEM_MASK) {
dbgp_printk("only simple 32bit mmio bars supported\n");
return -1;
}
/* double check if the mem space is enabled */
byte = read_pci_config_byte(bus, slot, func, 0x04);
if (!(byte & 0x2)) {
byte |= 0x02;
write_pci_config_byte(bus, slot, func, 0x04, byte);
dbgp_printk("mmio for ehci enabled\n");
}
/*
* FIXME I don't have the bar size so just guess PAGE_SIZE is more
* than enough. 1K is the biggest I have seen.
*/
set_fixmap_nocache(FIX_DBGP_BASE, bar_val & PAGE_MASK);
ehci_bar = (void __iomem *)__fix_to_virt(FIX_DBGP_BASE);
ehci_bar += bar_val & ~PAGE_MASK;
dbgp_printk("ehci_bar: %p\n", ehci_bar);
ehci_caps = ehci_bar;
ehci_regs = ehci_bar + HC_LENGTH(readl(&ehci_caps->hc_capbase));
ehci_debug = ehci_bar + offset;
ehci_dev.bus = bus;
ehci_dev.slot = slot;
ehci_dev.func = func;
detect_set_debug_port();
ret = ehci_setup();
if (ret < 0) {
dbgp_printk("ehci_setup failed\n");
ehci_debug = NULL;
return -1;
}
dbgp_ehci_status("early_init_complete");
return 0;
}
static void early_dbgp_write(struct console *con, const char *str, u32 n)
{
int chunk, ret;
char buf[DBGP_MAX_PACKET];
int use_cr = 0;
u32 cmd, ctrl;
int reset_run = 0;
if (!ehci_debug || dbgp_not_safe)
return;
cmd = readl(&ehci_regs->command);
if (unlikely(!(cmd & CMD_RUN))) {
/* If the ehci controller is not in the run state do extended
* checks to see if the acpi or some other initialization also
* reset the ehci debug port */
ctrl = readl(&ehci_debug->control);
if (!(ctrl & DBGP_ENABLED)) {
dbgp_not_safe = 1;
dbgp_external_startup();
} else {
cmd |= CMD_RUN;
writel(cmd, &ehci_regs->command);
reset_run = 1;
}
}
while (n > 0) {
for (chunk = 0; chunk < DBGP_MAX_PACKET && n > 0;
str++, chunk++, n--) {
if (!use_cr && *str == '\n') {
use_cr = 1;
buf[chunk] = '\r';
str--;
n++;
continue;
}
if (use_cr)
use_cr = 0;
buf[chunk] = *str;
}
if (chunk > 0) {
ret = dbgp_bulk_write(USB_DEBUG_DEVNUM,
dbgp_endpoint_out, buf, chunk);
}
}
if (unlikely(reset_run)) {
cmd = readl(&ehci_regs->command);
cmd &= ~CMD_RUN;
writel(cmd, &ehci_regs->command);
}
}
struct console early_dbgp_console = {
.name = "earlydbg",
.write = early_dbgp_write,
.flags = CON_PRINTBUFFER,
.index = -1,
};
int dbgp_reset_prep(void)
{
u32 ctrl;
dbgp_not_safe = 1;
if (!ehci_debug)
return 0;
if (early_dbgp_console.index != -1 &&
!(early_dbgp_console.flags & CON_BOOT))
return 1;
/* This means the console is not initialized, or should get
* shutdown so as to allow for reuse of the usb device, which
* means it is time to shutdown the usb debug port. */
ctrl = readl(&ehci_debug->control);
if (ctrl & DBGP_ENABLED) {
ctrl &= ~(DBGP_CLAIM);
writel(ctrl, &ehci_debug->control);
}
return 0;
}
EXPORT_SYMBOL_GPL(dbgp_reset_prep);

View File

@ -124,7 +124,7 @@ choice
config USB_GADGET_AT91 config USB_GADGET_AT91
boolean "Atmel AT91 USB Device Port" boolean "Atmel AT91 USB Device Port"
depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45
select USB_GADGET_SELECTED select USB_GADGET_SELECTED
help help
Many Atmel AT91 processors (such as the AT91RM2000) have a Many Atmel AT91 processors (such as the AT91RM2000) have a
@ -143,7 +143,7 @@ config USB_AT91
config USB_GADGET_ATMEL_USBA config USB_GADGET_ATMEL_USBA
boolean "Atmel USBA" boolean "Atmel USBA"
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
help help
USBA is the integrated high-speed USB Device controller on USBA is the integrated high-speed USB Device controller on
the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
@ -627,9 +627,10 @@ config USB_AUDIO
config USB_ETH config USB_ETH
tristate "Ethernet Gadget (with CDC Ethernet support)" tristate "Ethernet Gadget (with CDC Ethernet support)"
depends on NET depends on NET
select CRC32
help help
This driver implements Ethernet style communication, in either This driver implements Ethernet style communication, in one of
of two ways: several ways:
- The "Communication Device Class" (CDC) Ethernet Control Model. - The "Communication Device Class" (CDC) Ethernet Control Model.
That protocol is often avoided with pure Ethernet adapters, in That protocol is often avoided with pure Ethernet adapters, in
@ -639,7 +640,11 @@ config USB_ETH
- On hardware can't implement that protocol, a simple CDC subset - On hardware can't implement that protocol, a simple CDC subset
is used, placing fewer demands on USB. is used, placing fewer demands on USB.
RNDIS support is a third option, more demanding than that subset. - CDC Ethernet Emulation Model (EEM) is a newer standard that has
a simpler interface that can be used by more USB hardware.
RNDIS support is an additional option, more demanding than than
subset.
Within the USB device, this gadget driver exposes a network device Within the USB device, this gadget driver exposes a network device
"usbX", where X depends on what other networking devices you have. "usbX", where X depends on what other networking devices you have.
@ -672,6 +677,22 @@ config USB_ETH_RNDIS
XP, you'll need to download drivers from Microsoft's website; a URL XP, you'll need to download drivers from Microsoft's website; a URL
is given in comments found in that info file. is given in comments found in that info file.
config USB_ETH_EEM
bool "Ethernet Emulation Model (EEM) support"
depends on USB_ETH
default n
help
CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM
and therefore can be supported by more hardware. Technically ECM and
EEM are designed for different applications. The ECM model extends
the network interface to the target (e.g. a USB cable modem), and the
EEM model is for mobile devices to communicate with hosts using
ethernet over USB. For Linux gadgets, however, the interface with
the host is the same (a usbX device), so the differences are minimal.
If you say "y" here, the Ethernet gadget driver will use the EEM
protocol rather than ECM. If unsure, say "n".
config USB_GADGETFS config USB_GADGETFS
tristate "Gadget Filesystem (EXPERIMENTAL)" tristate "Gadget Filesystem (EXPERIMENTAL)"
depends on EXPERIMENTAL depends on EXPERIMENTAL

View File

@ -2378,40 +2378,34 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
if (!ep->cancel_transfer && !list_empty(&ep->queue)) { if (!ep->cancel_transfer && !list_empty(&ep->queue)) {
req = list_entry(ep->queue.next, req = list_entry(ep->queue.next,
struct udc_request, queue); struct udc_request, queue);
if (req) { /*
/* * length bytes transfered
* length bytes transfered * check dma done of last desc. in PPBDU mode
* check dma done of last desc. in PPBDU mode */
*/ if (use_dma_ppb_du) {
if (use_dma_ppb_du) { td = udc_get_last_dma_desc(req);
td = udc_get_last_dma_desc(req); if (td) {
if (td) { dma_done =
dma_done = AMD_GETBITS(td->status,
AMD_GETBITS(td->status, UDC_DMA_IN_STS_BS);
UDC_DMA_IN_STS_BS); /* don't care DMA done */
/* don't care DMA done */
req->req.actual =
req->req.length;
}
} else {
/* assume all bytes transferred */
req->req.actual = req->req.length; req->req.actual = req->req.length;
} }
} else {
/* assume all bytes transferred */
req->req.actual = req->req.length;
}
if (req->req.actual == req->req.length) { if (req->req.actual == req->req.length) {
/* complete req */ /* complete req */
complete_req(ep, req, 0); complete_req(ep, req, 0);
req->dma_going = 0; req->dma_going = 0;
/* further request available ? */ /* further request available ? */
if (list_empty(&ep->queue)) { if (list_empty(&ep->queue)) {
/* disable interrupt */ /* disable interrupt */
tmp = readl( tmp = readl(&dev->regs->ep_irqmsk);
&dev->regs->ep_irqmsk); tmp |= AMD_BIT(ep->num);
tmp |= AMD_BIT(ep->num); writel(tmp, &dev->regs->ep_irqmsk);
writel(tmp,
&dev->regs->ep_irqmsk);
}
} }
} }
} }

View File

@ -1754,7 +1754,6 @@ static int __init at91udc_probe(struct platform_device *pdev)
IRQF_DISABLED, driver_name, udc)) { IRQF_DISABLED, driver_name, udc)) {
DBG("request vbus irq %d failed\n", DBG("request vbus irq %d failed\n",
udc->board.vbus_pin); udc->board.vbus_pin);
free_irq(udc->udp_irq, udc);
retval = -EBUSY; retval = -EBUSY;
goto fail3; goto fail3;
} }

View File

@ -106,20 +106,20 @@ static int audio_set_endpoint_req(struct usb_configuration *c,
ctrl->bRequest, w_value, len, ep); ctrl->bRequest, w_value, len, ep);
switch (ctrl->bRequest) { switch (ctrl->bRequest) {
case SET_CUR: case UAC_SET_CUR:
value = 0; value = 0;
break; break;
case SET_MIN: case UAC_SET_MIN:
break; break;
case SET_MAX: case UAC_SET_MAX:
break; break;
case SET_RES: case UAC_SET_RES:
break; break;
case SET_MEM: case UAC_SET_MEM:
break; break;
default: default:
@ -142,13 +142,13 @@ static int audio_get_endpoint_req(struct usb_configuration *c,
ctrl->bRequest, w_value, len, ep); ctrl->bRequest, w_value, len, ep);
switch (ctrl->bRequest) { switch (ctrl->bRequest) {
case GET_CUR: case UAC_GET_CUR:
case GET_MIN: case UAC_GET_MIN:
case GET_MAX: case UAC_GET_MAX:
case GET_RES: case UAC_GET_RES:
value = 3; value = 3;
break; break;
case GET_MEM: case UAC_GET_MEM:
break; break;
default: default:
break; break;
@ -171,11 +171,11 @@ audio_setup(struct usb_configuration *c, const struct usb_ctrlrequest *ctrl)
* Audio class messages; interface activation uses set_alt(). * Audio class messages; interface activation uses set_alt().
*/ */
switch (ctrl->bRequestType) { switch (ctrl->bRequestType) {
case USB_AUDIO_SET_ENDPOINT: case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
value = audio_set_endpoint_req(c, ctrl); value = audio_set_endpoint_req(c, ctrl);
break; break;
case USB_AUDIO_GET_ENDPOINT: case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
value = audio_get_endpoint_req(c, ctrl); value = audio_get_endpoint_req(c, ctrl);
break; break;

View File

@ -602,7 +602,7 @@ static int get_string(struct usb_composite_dev *cdev,
} }
} }
for (len = 0; s->wData[len] && len <= 126; len++) for (len = 0; len <= 126 && s->wData[len]; len++)
continue; continue;
if (!len) if (!len)
return -EINVAL; return -EINVAL;

View File

@ -1306,11 +1306,6 @@ restart:
setup = *(struct usb_ctrlrequest*) urb->setup_packet; setup = *(struct usb_ctrlrequest*) urb->setup_packet;
w_index = le16_to_cpu(setup.wIndex); w_index = le16_to_cpu(setup.wIndex);
w_value = le16_to_cpu(setup.wValue); w_value = le16_to_cpu(setup.wValue);
if (le16_to_cpu(setup.wLength) !=
urb->transfer_buffer_length) {
status = -EOVERFLOW;
goto return_urb;
}
/* paranoia, in case of stale queued data */ /* paranoia, in case of stale queued data */
list_for_each_entry (req, &ep->queue, queue) { list_for_each_entry (req, &ep->queue, queue) {

View File

@ -61,6 +61,11 @@
* simpler, Microsoft pushes their own approach: RNDIS. The published * simpler, Microsoft pushes their own approach: RNDIS. The published
* RNDIS specs are ambiguous and appear to be incomplete, and are also * RNDIS specs are ambiguous and appear to be incomplete, and are also
* needlessly complex. They borrow more from CDC ACM than CDC ECM. * needlessly complex. They borrow more from CDC ACM than CDC ECM.
*
* While CDC ECM, CDC Subset, and RNDIS are designed to extend the ethernet
* interface to the target, CDC EEM was designed to use ethernet over the USB
* link between the host and target. CDC EEM is implemented as an alternative
* to those other protocols when that communication model is more appropriate
*/ */
#define DRIVER_DESC "Ethernet Gadget" #define DRIVER_DESC "Ethernet Gadget"
@ -114,6 +119,7 @@ static inline bool has_rndis(void)
#include "f_rndis.c" #include "f_rndis.c"
#include "rndis.c" #include "rndis.c"
#endif #endif
#include "f_eem.c"
#include "u_ether.c" #include "u_ether.c"
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@ -150,6 +156,10 @@ static inline bool has_rndis(void)
#define RNDIS_VENDOR_NUM 0x0525 /* NetChip */ #define RNDIS_VENDOR_NUM 0x0525 /* NetChip */
#define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */ #define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */
/* For EEM gadgets */
#define EEM_VENDOR_NUM 0x0525 /* INVALID - NEEDS TO BE ALLOCATED */
#define EEM_PRODUCT_NUM 0xa4a1 /* INVALID - NEEDS TO BE ALLOCATED */
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct usb_device_descriptor device_desc = { static struct usb_device_descriptor device_desc = {
@ -246,8 +256,16 @@ static struct usb_configuration rndis_config_driver = {
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#ifdef CONFIG_USB_ETH_EEM
static int use_eem = 1;
#else
static int use_eem;
#endif
module_param(use_eem, bool, 0);
MODULE_PARM_DESC(use_eem, "use CDC EEM mode");
/* /*
* We _always_ have an ECM or CDC Subset configuration. * We _always_ have an ECM, CDC Subset, or EEM configuration.
*/ */
static int __init eth_do_config(struct usb_configuration *c) static int __init eth_do_config(struct usb_configuration *c)
{ {
@ -258,7 +276,9 @@ static int __init eth_do_config(struct usb_configuration *c)
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP; c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
} }
if (can_support_ecm(c->cdev->gadget)) if (use_eem)
return eem_bind_config(c);
else if (can_support_ecm(c->cdev->gadget))
return ecm_bind_config(c, hostaddr); return ecm_bind_config(c, hostaddr);
else else
return geth_bind_config(c, hostaddr); return geth_bind_config(c, hostaddr);
@ -286,7 +306,12 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
return status; return status;
/* set up main config label and device descriptor */ /* set up main config label and device descriptor */
if (can_support_ecm(cdev->gadget)) { if (use_eem) {
/* EEM */
eth_config_driver.label = "CDC Ethernet (EEM)";
device_desc.idVendor = cpu_to_le16(EEM_VENDOR_NUM);
device_desc.idProduct = cpu_to_le16(EEM_PRODUCT_NUM);
} else if (can_support_ecm(cdev->gadget)) {
/* ECM */ /* ECM */
eth_config_driver.label = "CDC Ethernet (ECM)"; eth_config_driver.label = "CDC Ethernet (ECM)";
} else { } else {

View File

@ -28,6 +28,9 @@ static int audio_buf_size = 48000;
module_param(audio_buf_size, int, S_IRUGO); module_param(audio_buf_size, int, S_IRUGO);
MODULE_PARM_DESC(audio_buf_size, "Audio buffer size"); MODULE_PARM_DESC(audio_buf_size, "Audio buffer size");
static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value);
static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
/* /*
* DESCRIPTORS ... most are static, but strings and full * DESCRIPTORS ... most are static, but strings and full
* configuration descriptors are built on demand. * configuration descriptors are built on demand.
@ -50,16 +53,16 @@ static struct usb_interface_descriptor ac_interface_desc __initdata = {
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
}; };
DECLARE_USB_AC_HEADER_DESCRIPTOR(2); DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
#define USB_DT_AC_HEADER_LENGH USB_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES) #define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
/* B.3.2 Class-Specific AC Interface Descriptor */ /* B.3.2 Class-Specific AC Interface Descriptor */
static struct usb_ac_header_descriptor_2 ac_header_desc = { static struct uac_ac_header_descriptor_2 ac_header_desc = {
.bLength = USB_DT_AC_HEADER_LENGH, .bLength = UAC_DT_AC_HEADER_LENGTH,
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = HEADER, .bDescriptorSubtype = UAC_HEADER,
.bcdADC = __constant_cpu_to_le16(0x0100), .bcdADC = __constant_cpu_to_le16(0x0100),
.wTotalLength = __constant_cpu_to_le16(USB_DT_AC_HEADER_LENGH), .wTotalLength = __constant_cpu_to_le16(UAC_DT_AC_HEADER_LENGTH),
.bInCollection = F_AUDIO_NUM_INTERFACES, .bInCollection = F_AUDIO_NUM_INTERFACES,
.baInterfaceNr = { .baInterfaceNr = {
[0] = F_AUDIO_AC_INTERFACE, [0] = F_AUDIO_AC_INTERFACE,
@ -68,33 +71,33 @@ static struct usb_ac_header_descriptor_2 ac_header_desc = {
}; };
#define INPUT_TERMINAL_ID 1 #define INPUT_TERMINAL_ID 1
static struct usb_input_terminal_descriptor input_terminal_desc = { static struct uac_input_terminal_descriptor input_terminal_desc = {
.bLength = USB_DT_AC_INPUT_TERMINAL_SIZE, .bLength = UAC_DT_INPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = INPUT_TERMINAL, .bDescriptorSubtype = UAC_INPUT_TERMINAL,
.bTerminalID = INPUT_TERMINAL_ID, .bTerminalID = INPUT_TERMINAL_ID,
.wTerminalType = USB_AC_TERMINAL_STREAMING, .wTerminalType = UAC_TERMINAL_STREAMING,
.bAssocTerminal = 0, .bAssocTerminal = 0,
.wChannelConfig = 0x3, .wChannelConfig = 0x3,
}; };
DECLARE_USB_AC_FEATURE_UNIT_DESCRIPTOR(0); DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0);
#define FEATURE_UNIT_ID 2 #define FEATURE_UNIT_ID 2
static struct usb_ac_feature_unit_descriptor_0 feature_unit_desc = { static struct uac_feature_unit_descriptor_0 feature_unit_desc = {
.bLength = USB_DT_AC_FEATURE_UNIT_SIZE(0), .bLength = UAC_DT_FEATURE_UNIT_SIZE(0),
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = FEATURE_UNIT, .bDescriptorSubtype = UAC_FEATURE_UNIT,
.bUnitID = FEATURE_UNIT_ID, .bUnitID = FEATURE_UNIT_ID,
.bSourceID = INPUT_TERMINAL_ID, .bSourceID = INPUT_TERMINAL_ID,
.bControlSize = 2, .bControlSize = 2,
.bmaControls[0] = (FU_MUTE | FU_VOLUME), .bmaControls[0] = (UAC_FU_MUTE | UAC_FU_VOLUME),
}; };
static struct usb_audio_control mute_control = { static struct usb_audio_control mute_control = {
.list = LIST_HEAD_INIT(mute_control.list), .list = LIST_HEAD_INIT(mute_control.list),
.name = "Mute Control", .name = "Mute Control",
.type = MUTE_CONTROL, .type = UAC_MUTE_CONTROL,
/* Todo: add real Mute control code */ /* Todo: add real Mute control code */
.set = generic_set_cmd, .set = generic_set_cmd,
.get = generic_get_cmd, .get = generic_get_cmd,
@ -103,7 +106,7 @@ static struct usb_audio_control mute_control = {
static struct usb_audio_control volume_control = { static struct usb_audio_control volume_control = {
.list = LIST_HEAD_INIT(volume_control.list), .list = LIST_HEAD_INIT(volume_control.list),
.name = "Volume Control", .name = "Volume Control",
.type = VOLUME_CONTROL, .type = UAC_VOLUME_CONTROL,
/* Todo: add real Volume control code */ /* Todo: add real Volume control code */
.set = generic_set_cmd, .set = generic_set_cmd,
.get = generic_get_cmd, .get = generic_get_cmd,
@ -113,17 +116,17 @@ static struct usb_audio_control_selector feature_unit = {
.list = LIST_HEAD_INIT(feature_unit.list), .list = LIST_HEAD_INIT(feature_unit.list),
.id = FEATURE_UNIT_ID, .id = FEATURE_UNIT_ID,
.name = "Mute & Volume Control", .name = "Mute & Volume Control",
.type = FEATURE_UNIT, .type = UAC_FEATURE_UNIT,
.desc = (struct usb_descriptor_header *)&feature_unit_desc, .desc = (struct usb_descriptor_header *)&feature_unit_desc,
}; };
#define OUTPUT_TERMINAL_ID 3 #define OUTPUT_TERMINAL_ID 3
static struct usb_output_terminal_descriptor output_terminal_desc = { static struct uac_output_terminal_descriptor output_terminal_desc = {
.bLength = USB_DT_AC_OUTPUT_TERMINAL_SIZE, .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = OUTPUT_TERMINAL, .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
.bTerminalID = OUTPUT_TERMINAL_ID, .bTerminalID = OUTPUT_TERMINAL_ID,
.wTerminalType = USB_AC_OUTPUT_TERMINAL_SPEAKER, .wTerminalType = UAC_OUTPUT_TERMINAL_SPEAKER,
.bAssocTerminal = FEATURE_UNIT_ID, .bAssocTerminal = FEATURE_UNIT_ID,
.bSourceID = FEATURE_UNIT_ID, .bSourceID = FEATURE_UNIT_ID,
}; };
@ -148,22 +151,22 @@ static struct usb_interface_descriptor as_interface_alt_1_desc = {
}; };
/* B.4.2 Class-Specific AS Interface Descriptor */ /* B.4.2 Class-Specific AS Interface Descriptor */
static struct usb_as_header_descriptor as_header_desc = { static struct uac_as_header_descriptor as_header_desc = {
.bLength = USB_DT_AS_HEADER_SIZE, .bLength = UAC_DT_AS_HEADER_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = AS_GENERAL, .bDescriptorSubtype = UAC_AS_GENERAL,
.bTerminalLink = INPUT_TERMINAL_ID, .bTerminalLink = INPUT_TERMINAL_ID,
.bDelay = 1, .bDelay = 1,
.wFormatTag = USB_AS_AUDIO_FORMAT_TYPE_I_PCM, .wFormatTag = UAC_FORMAT_TYPE_I_PCM,
}; };
DECLARE_USB_AS_FORMAT_TYPE_I_DISCRETE_DESC(1); DECLARE_UAC_FORMAT_TYPE_I_DISCRETE_DESC(1);
static struct usb_as_formate_type_i_discrete_descriptor_1 as_type_i_desc = { static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = {
.bLength = USB_AS_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1), .bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = FORMAT_TYPE, .bDescriptorSubtype = UAC_FORMAT_TYPE,
.bFormatType = USB_AS_FORMAT_TYPE_I, .bFormatType = UAC_FORMAT_TYPE_I,
.bSubframeSize = 2, .bSubframeSize = 2,
.bBitResolution = 16, .bBitResolution = 16,
.bSamFreqType = 1, .bSamFreqType = 1,
@ -174,17 +177,17 @@ static struct usb_endpoint_descriptor as_out_ep_desc __initdata = {
.bLength = USB_DT_ENDPOINT_AUDIO_SIZE, .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
.bDescriptorType = USB_DT_ENDPOINT, .bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT, .bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_AS_ENDPOINT_ADAPTIVE .bmAttributes = USB_ENDPOINT_SYNC_ADAPTIVE
| USB_ENDPOINT_XFER_ISOC, | USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = __constant_cpu_to_le16(OUT_EP_MAX_PACKET_SIZE), .wMaxPacketSize = __constant_cpu_to_le16(OUT_EP_MAX_PACKET_SIZE),
.bInterval = 4, .bInterval = 4,
}; };
/* Class-specific AS ISO OUT Endpoint Descriptor */ /* Class-specific AS ISO OUT Endpoint Descriptor */
static struct usb_as_iso_endpoint_descriptor as_iso_out_desc __initdata = { static struct uac_iso_endpoint_descriptor as_iso_out_desc __initdata = {
.bLength = USB_AS_ISO_ENDPOINT_DESC_SIZE, .bLength = UAC_ISO_ENDPOINT_DESC_SIZE,
.bDescriptorType = USB_DT_CS_ENDPOINT, .bDescriptorType = USB_DT_CS_ENDPOINT,
.bDescriptorSubtype = EP_GENERAL, .bDescriptorSubtype = UAC_EP_GENERAL,
.bmAttributes = 1, .bmAttributes = 1,
.bLockDelayUnits = 1, .bLockDelayUnits = 1,
.wLockDelay = __constant_cpu_to_le16(1), .wLockDelay = __constant_cpu_to_le16(1),
@ -456,11 +459,11 @@ f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
* Audio class messages; interface activation uses set_alt(). * Audio class messages; interface activation uses set_alt().
*/ */
switch (ctrl->bRequestType) { switch (ctrl->bRequestType) {
case USB_AUDIO_SET_INTF: case USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
value = audio_set_intf_req(f, ctrl); value = audio_set_intf_req(f, ctrl);
break; break;
case USB_AUDIO_GET_INTF: case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
value = audio_get_intf_req(f, ctrl); value = audio_get_intf_req(f, ctrl);
break; break;
@ -632,6 +635,18 @@ f_audio_unbind(struct usb_configuration *c, struct usb_function *f)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static int generic_set_cmd(struct usb_audio_control *con, u8 cmd, int value)
{
con->data[cmd] = value;
return 0;
}
static int generic_get_cmd(struct usb_audio_control *con, u8 cmd)
{
return con->data[cmd];
}
/* Todo: add more control selecotor dynamically */ /* Todo: add more control selecotor dynamically */
int __init control_selector_init(struct f_audio *audio) int __init control_selector_init(struct f_audio *audio)
{ {
@ -642,10 +657,10 @@ int __init control_selector_init(struct f_audio *audio)
list_add(&mute_control.list, &feature_unit.control); list_add(&mute_control.list, &feature_unit.control);
list_add(&volume_control.list, &feature_unit.control); list_add(&volume_control.list, &feature_unit.control);
volume_control.data[_CUR] = 0xffc0; volume_control.data[UAC__CUR] = 0xffc0;
volume_control.data[_MIN] = 0xe3a0; volume_control.data[UAC__MIN] = 0xe3a0;
volume_control.data[_MAX] = 0xfff0; volume_control.data[UAC__MAX] = 0xfff0;
volume_control.data[_RES] = 0x0030; volume_control.data[UAC__RES] = 0x0030;
return 0; return 0;
} }

562
drivers/usb/gadget/f_eem.c Normal file
View File

@ -0,0 +1,562 @@
/*
* f_eem.c -- USB CDC Ethernet (EEM) link function driver
*
* Copyright (C) 2003-2005,2008 David Brownell
* Copyright (C) 2008 Nokia Corporation
* Copyright (C) 2009 EF Johnson Technologies
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/etherdevice.h>
#include <linux/crc32.h>
#include "u_ether.h"
#define EEM_HLEN 2
/*
* This function is a "CDC Ethernet Emulation Model" (CDC EEM)
* Ethernet link.
*/
struct eem_ep_descs {
struct usb_endpoint_descriptor *in;
struct usb_endpoint_descriptor *out;
};
struct f_eem {
struct gether port;
u8 ctrl_id;
struct eem_ep_descs fs;
struct eem_ep_descs hs;
};
static inline struct f_eem *func_to_eem(struct usb_function *f)
{
return container_of(f, struct f_eem, port.func);
}
/*-------------------------------------------------------------------------*/
/* interface descriptor: */
static struct usb_interface_descriptor eem_intf __initdata = {
.bLength = sizeof eem_intf,
.bDescriptorType = USB_DT_INTERFACE,
/* .bInterfaceNumber = DYNAMIC */
.bNumEndpoints = 2,
.bInterfaceClass = USB_CLASS_COMM,
.bInterfaceSubClass = USB_CDC_SUBCLASS_EEM,
.bInterfaceProtocol = USB_CDC_PROTO_EEM,
/* .iInterface = DYNAMIC */
};
/* full speed support: */
static struct usb_endpoint_descriptor eem_fs_in_desc __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
static struct usb_endpoint_descriptor eem_fs_out_desc __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
static struct usb_descriptor_header *eem_fs_function[] __initdata = {
/* CDC EEM control descriptors */
(struct usb_descriptor_header *) &eem_intf,
(struct usb_descriptor_header *) &eem_fs_in_desc,
(struct usb_descriptor_header *) &eem_fs_out_desc,
NULL,
};
/* high speed support: */
static struct usb_endpoint_descriptor eem_hs_in_desc __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_IN,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
};
static struct usb_endpoint_descriptor eem_hs_out_desc __initdata = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
.wMaxPacketSize = cpu_to_le16(512),
};
static struct usb_descriptor_header *eem_hs_function[] __initdata = {
/* CDC EEM control descriptors */
(struct usb_descriptor_header *) &eem_intf,
(struct usb_descriptor_header *) &eem_hs_in_desc,
(struct usb_descriptor_header *) &eem_hs_out_desc,
NULL,
};
/* string descriptors: */
static struct usb_string eem_string_defs[] = {
[0].s = "CDC Ethernet Emulation Model (EEM)",
{ } /* end of list */
};
static struct usb_gadget_strings eem_string_table = {
.language = 0x0409, /* en-us */
.strings = eem_string_defs,
};
static struct usb_gadget_strings *eem_strings[] = {
&eem_string_table,
NULL,
};
/*-------------------------------------------------------------------------*/
static int eem_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = f->config->cdev;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
DBG(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
/* device either stalls (value < 0) or reports success */
return value;
}
static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct f_eem *eem = func_to_eem(f);
struct usb_composite_dev *cdev = f->config->cdev;
struct net_device *net;
/* we know alt == 0, so this is an activation or a reset */
if (alt != 0)
goto fail;
if (intf == eem->ctrl_id) {
if (eem->port.in_ep->driver_data) {
DBG(cdev, "reset eem\n");
gether_disconnect(&eem->port);
}
if (!eem->port.in) {
DBG(cdev, "init eem\n");
eem->port.in = ep_choose(cdev->gadget,
eem->hs.in, eem->fs.in);
eem->port.out = ep_choose(cdev->gadget,
eem->hs.out, eem->fs.out);
}
/* zlps should not occur because zero-length EEM packets
* will be inserted in those cases where they would occur
*/
eem->port.is_zlp_ok = 1;
eem->port.cdc_filter = DEFAULT_FILTER;
DBG(cdev, "activate eem\n");
net = gether_connect(&eem->port);
if (IS_ERR(net))
return PTR_ERR(net);
} else
goto fail;
return 0;
fail:
return -EINVAL;
}
static void eem_disable(struct usb_function *f)
{
struct f_eem *eem = func_to_eem(f);
struct usb_composite_dev *cdev = f->config->cdev;
DBG(cdev, "eem deactivated\n");
if (eem->port.in_ep->driver_data)
gether_disconnect(&eem->port);
}
/*-------------------------------------------------------------------------*/
/* EEM function driver setup/binding */
static int __init
eem_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_eem *eem = func_to_eem(f);
int status;
struct usb_ep *ep;
/* allocate instance-specific interface IDs */
status = usb_interface_id(c, f);
if (status < 0)
goto fail;
eem->ctrl_id = status;
eem_intf.bInterfaceNumber = status;
status = -ENODEV;
/* allocate instance-specific endpoints */
ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_in_desc);
if (!ep)
goto fail;
eem->port.in_ep = ep;
ep->driver_data = cdev; /* claim */
ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_out_desc);
if (!ep)
goto fail;
eem->port.out_ep = ep;
ep->driver_data = cdev; /* claim */
status = -ENOMEM;
/* copy descriptors, and track endpoint copies */
f->descriptors = usb_copy_descriptors(eem_fs_function);
if (!f->descriptors)
goto fail;
eem->fs.in = usb_find_endpoint(eem_fs_function,
f->descriptors, &eem_fs_in_desc);
eem->fs.out = usb_find_endpoint(eem_fs_function,
f->descriptors, &eem_fs_out_desc);
/* support all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
* both speeds
*/
if (gadget_is_dualspeed(c->cdev->gadget)) {
eem_hs_in_desc.bEndpointAddress =
eem_fs_in_desc.bEndpointAddress;
eem_hs_out_desc.bEndpointAddress =
eem_fs_out_desc.bEndpointAddress;
/* copy descriptors, and track endpoint copies */
f->hs_descriptors = usb_copy_descriptors(eem_hs_function);
if (!f->hs_descriptors)
goto fail;
eem->hs.in = usb_find_endpoint(eem_hs_function,
f->hs_descriptors, &eem_hs_in_desc);
eem->hs.out = usb_find_endpoint(eem_hs_function,
f->hs_descriptors, &eem_hs_out_desc);
}
DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
eem->port.in_ep->name, eem->port.out_ep->name);
return 0;
fail:
if (f->descriptors)
usb_free_descriptors(f->descriptors);
/* we might as well release our claims on endpoints */
if (eem->port.out)
eem->port.out_ep->driver_data = NULL;
if (eem->port.in)
eem->port.in_ep->driver_data = NULL;
ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
return status;
}
static void
eem_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_eem *eem = func_to_eem(f);
DBG(c->cdev, "eem unbind\n");
if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors);
usb_free_descriptors(f->descriptors);
kfree(eem);
}
static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req)
{
}
/*
* Add the EEM header and ethernet checksum.
* We currently do not attempt to put multiple ethernet frames
* into a single USB transfer
*/
static struct sk_buff *eem_wrap(struct gether *port, struct sk_buff *skb)
{
struct sk_buff *skb2 = NULL;
struct usb_ep *in = port->in_ep;
int padlen = 0;
u16 len = skb->len;
if (!skb_cloned(skb)) {
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
/* When (len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) is 0,
* stick two bytes of zero-length EEM packet on the end.
*/
if (((len + EEM_HLEN + ETH_FCS_LEN) % in->maxpacket) == 0)
padlen += 2;
if ((tailroom >= (ETH_FCS_LEN + padlen)) &&
(headroom >= EEM_HLEN))
goto done;
}
skb2 = skb_copy_expand(skb, EEM_HLEN, ETH_FCS_LEN + padlen, GFP_ATOMIC);
dev_kfree_skb_any(skb);
skb = skb2;
if (!skb)
return skb;
done:
/* use the "no CRC" option */
put_unaligned_be32(0xdeadbeef, skb_put(skb, 4));
/* EEM packet header format:
* b0..13: length of ethernet frame
* b14: bmCRC (0 == sentinel CRC)
* b15: bmType (0 == data)
*/
len = skb->len;
put_unaligned_le16((len & 0x3FFF) | BIT(14), skb_push(skb, 2));
/* add a zero-length EEM packet, if needed */
if (padlen)
put_unaligned_le16(0, skb_put(skb, 2));
return skb;
}
/*
* Remove the EEM header. Note that there can be many EEM packets in a single
* USB transfer, so we need to break them out and handle them independently.
*/
static int eem_unwrap(struct gether *port,
struct sk_buff *skb,
struct sk_buff_head *list)
{
struct usb_composite_dev *cdev = port->func.config->cdev;
int status = 0;
do {
struct sk_buff *skb2;
u16 header;
u16 len = 0;
if (skb->len < EEM_HLEN) {
status = -EINVAL;
DBG(cdev, "invalid EEM header\n");
goto error;
}
/* remove the EEM header */
header = get_unaligned_le16(skb->data);
skb_pull(skb, EEM_HLEN);
/* EEM packet header format:
* b0..14: EEM type dependent (data or command)
* b15: bmType (0 == data, 1 == command)
*/
if (header & BIT(15)) {
struct usb_request *req = cdev->req;
u16 bmEEMCmd;
/* EEM command packet format:
* b0..10: bmEEMCmdParam
* b11..13: bmEEMCmd
* b14: reserved (must be zero)
* b15: bmType (1 == command)
*/
if (header & BIT(14))
continue;
bmEEMCmd = (header >> 11) & 0x7;
switch (bmEEMCmd) {
case 0: /* echo */
len = header & 0x7FF;
if (skb->len < len) {
status = -EOVERFLOW;
goto error;
}
skb2 = skb_clone(skb, GFP_ATOMIC);
if (unlikely(!skb2)) {
DBG(cdev, "EEM echo response error\n");
goto next;
}
skb_trim(skb2, len);
put_unaligned_le16(BIT(15) | BIT(11) | len,
skb_push(skb2, 2));
skb_copy_bits(skb, 0, req->buf, skb->len);
req->length = skb->len;
req->complete = eem_cmd_complete;
req->zero = 1;
if (usb_ep_queue(port->in_ep, req, GFP_ATOMIC))
DBG(cdev, "echo response queue fail\n");
break;
case 1: /* echo response */
case 2: /* suspend hint */
case 3: /* response hint */
case 4: /* response complete hint */
case 5: /* tickle */
default: /* reserved */
continue;
}
} else {
u32 crc, crc2;
struct sk_buff *skb3;
/* check for zero-length EEM packet */
if (header == 0)
continue;
/* EEM data packet format:
* b0..13: length of ethernet frame
* b14: bmCRC (0 == sentinel, 1 == calculated)
* b15: bmType (0 == data)
*/
len = header & 0x3FFF;
if ((skb->len < len)
|| (len < (ETH_HLEN + ETH_FCS_LEN))) {
status = -EINVAL;
goto error;
}
/* validate CRC */
crc = get_unaligned_le32(skb->data + len - ETH_FCS_LEN);
if (header & BIT(14)) {
crc = get_unaligned_le32(skb->data + len
- ETH_FCS_LEN);
crc2 = ~crc32_le(~0,
skb->data,
skb->len - ETH_FCS_LEN);
} else {
crc = get_unaligned_be32(skb->data + len
- ETH_FCS_LEN);
crc2 = 0xdeadbeef;
}
if (crc != crc2) {
DBG(cdev, "invalid EEM CRC\n");
goto next;
}
skb2 = skb_clone(skb, GFP_ATOMIC);
if (unlikely(!skb2)) {
DBG(cdev, "unable to unframe EEM packet\n");
continue;
}
skb_trim(skb2, len - ETH_FCS_LEN);
skb3 = skb_copy_expand(skb2,
NET_IP_ALIGN,
0,
GFP_ATOMIC);
if (unlikely(!skb3)) {
DBG(cdev, "unable to realign EEM packet\n");
dev_kfree_skb_any(skb2);
continue;
}
dev_kfree_skb_any(skb2);
skb_queue_tail(list, skb3);
}
next:
skb_pull(skb, len);
} while (skb->len);
error:
dev_kfree_skb_any(skb);
return status;
}
/**
* eem_bind_config - add CDC Ethernet (EEM) network link to a configuration
* @c: the configuration to support the network link
* Context: single threaded during gadget setup
*
* Returns zero on success, else negative errno.
*
* Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload.
*/
int __init eem_bind_config(struct usb_configuration *c)
{
struct f_eem *eem;
int status;
/* maybe allocate device-global string IDs */
if (eem_string_defs[0].id == 0) {
/* control interface label */
status = usb_string_id(c->cdev);
if (status < 0)
return status;
eem_string_defs[0].id = status;
eem_intf.iInterface = status;
}
/* allocate and initialize one new instance */
eem = kzalloc(sizeof *eem, GFP_KERNEL);
if (!eem)
return -ENOMEM;
eem->port.cdc_filter = DEFAULT_FILTER;
eem->port.func.name = "cdc_eem";
eem->port.func.strings = eem_strings;
/* descriptors are per-instance copies */
eem->port.func.bind = eem_bind;
eem->port.func.unbind = eem_unbind;
eem->port.func.set_alt = eem_set_alt;
eem->port.func.setup = eem_setup;
eem->port.func.disable = eem_disable;
eem->port.wrap = eem_wrap;
eem->port.unwrap = eem_unwrap;
eem->port.header_len = EEM_HLEN;
status = usb_add_function(c, &eem->port.func);
if (status)
kfree(eem);
return status;
}

View File

@ -286,12 +286,17 @@ static struct usb_gadget_strings *rndis_strings[] = {
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct sk_buff *rndis_add_header(struct sk_buff *skb) static struct sk_buff *rndis_add_header(struct gether *port,
struct sk_buff *skb)
{ {
skb = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type)); struct sk_buff *skb2;
if (skb)
rndis_add_hdr(skb); skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
return skb; if (skb2)
rndis_add_hdr(skb2);
dev_kfree_skb_any(skb);
return skb2;
} }
static void rndis_response_available(void *_rndis) static void rndis_response_available(void *_rndis)

View File

@ -2750,6 +2750,10 @@ static int __devexit qe_udc_remove(struct of_device *ofdev)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct of_device_id __devinitdata qe_udc_match[] = { static struct of_device_id __devinitdata qe_udc_match[] = {
{
.compatible = "fsl,mpc8323-qe-usb",
.data = (void *)PORT_QE,
},
{ {
.compatible = "fsl,mpc8360-qe-usb", .compatible = "fsl,mpc8360-qe-usb",
.data = (void *)PORT_QE, .data = (void *)PORT_QE,

View File

@ -191,7 +191,7 @@ module_param(qlen, uint, S_IRUGO);
#define GMIDI_MS_INTERFACE 1 #define GMIDI_MS_INTERFACE 1
#define GMIDI_NUM_INTERFACES 2 #define GMIDI_NUM_INTERFACES 2
DECLARE_USB_AC_HEADER_DESCRIPTOR(1); DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1); DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1);
@ -237,12 +237,12 @@ static const struct usb_interface_descriptor ac_interface_desc = {
}; };
/* B.3.2 Class-Specific AC Interface Descriptor */ /* B.3.2 Class-Specific AC Interface Descriptor */
static const struct usb_ac_header_descriptor_1 ac_header_desc = { static const struct uac_ac_header_descriptor_1 ac_header_desc = {
.bLength = USB_DT_AC_HEADER_SIZE(1), .bLength = UAC_DT_AC_HEADER_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE, .bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = USB_MS_HEADER, .bDescriptorSubtype = USB_MS_HEADER,
.bcdADC = cpu_to_le16(0x0100), .bcdADC = cpu_to_le16(0x0100),
.wTotalLength = cpu_to_le16(USB_DT_AC_HEADER_SIZE(1)), .wTotalLength = cpu_to_le16(UAC_DT_AC_HEADER_SIZE(1)),
.bInCollection = 1, .bInCollection = 1,
.baInterfaceNr = { .baInterfaceNr = {
[0] = GMIDI_MS_INTERFACE, [0] = GMIDI_MS_INTERFACE,

View File

@ -56,6 +56,7 @@
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
/* /*
* This driver is PXA25x only. Grab the right register definitions. * This driver is PXA25x only. Grab the right register definitions.
@ -1008,15 +1009,27 @@ static int pxa25x_udc_pullup(struct usb_gadget *_gadget, int is_active)
return 0; return 0;
} }
/* boards may consume current from VBUS, up to 100-500mA based on config.
* the 500uA suspend ceiling means that exclusively vbus-powered PXA designs
* violate USB specs.
*/
static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
{
struct pxa25x_udc *udc;
udc = container_of(_gadget, struct pxa25x_udc, gadget);
if (udc->transceiver)
return otg_set_power(udc->transceiver, mA);
return -EOPNOTSUPP;
}
static const struct usb_gadget_ops pxa25x_udc_ops = { static const struct usb_gadget_ops pxa25x_udc_ops = {
.get_frame = pxa25x_udc_get_frame, .get_frame = pxa25x_udc_get_frame,
.wakeup = pxa25x_udc_wakeup, .wakeup = pxa25x_udc_wakeup,
.vbus_session = pxa25x_udc_vbus_session, .vbus_session = pxa25x_udc_vbus_session,
.pullup = pxa25x_udc_pullup, .pullup = pxa25x_udc_pullup,
.vbus_draw = pxa25x_udc_vbus_draw,
// .vbus_draw ... boards may consume current from VBUS, up to
// 100-500mA based on config. the 500uA suspend ceiling means
// that exclusively vbus-powered PXA designs violate USB specs.
}; };
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@ -1303,9 +1316,23 @@ fail:
* for set_configuration as well as eventual disconnect. * for set_configuration as well as eventual disconnect.
*/ */
DMSG("registered gadget driver '%s'\n", driver->driver.name); DMSG("registered gadget driver '%s'\n", driver->driver.name);
/* connect to bus through transceiver */
if (dev->transceiver) {
retval = otg_set_peripheral(dev->transceiver, &dev->gadget);
if (retval) {
DMSG("can't bind to transceiver\n");
if (driver->unbind)
driver->unbind(&dev->gadget);
goto bind_fail;
}
}
pullup(dev); pullup(dev);
dump_state(dev); dump_state(dev);
return 0; return 0;
bind_fail:
return retval;
} }
EXPORT_SYMBOL(usb_gadget_register_driver); EXPORT_SYMBOL(usb_gadget_register_driver);
@ -1351,6 +1378,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
stop_activity(dev, driver); stop_activity(dev, driver);
local_irq_enable(); local_irq_enable();
if (dev->transceiver)
(void) otg_set_peripheral(dev->transceiver, NULL);
driver->unbind(&dev->gadget); driver->unbind(&dev->gadget);
dev->gadget.dev.driver = NULL; dev->gadget.dev.driver = NULL;
dev->driver = NULL; dev->driver = NULL;
@ -2162,6 +2192,8 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
dev->dev = &pdev->dev; dev->dev = &pdev->dev;
dev->mach = pdev->dev.platform_data; dev->mach = pdev->dev.platform_data;
dev->transceiver = otg_get_transceiver();
if (gpio_is_valid(dev->mach->gpio_vbus)) { if (gpio_is_valid(dev->mach->gpio_vbus)) {
if ((retval = gpio_request(dev->mach->gpio_vbus, if ((retval = gpio_request(dev->mach->gpio_vbus,
"pxa25x_udc GPIO VBUS"))) { "pxa25x_udc GPIO VBUS"))) {
@ -2264,6 +2296,10 @@ lubbock_fail0:
if (gpio_is_valid(dev->mach->gpio_vbus)) if (gpio_is_valid(dev->mach->gpio_vbus))
gpio_free(dev->mach->gpio_vbus); gpio_free(dev->mach->gpio_vbus);
err_gpio_vbus: err_gpio_vbus:
if (dev->transceiver) {
otg_put_transceiver(dev->transceiver);
dev->transceiver = NULL;
}
clk_put(dev->clk); clk_put(dev->clk);
err_clk: err_clk:
return retval; return retval;
@ -2305,6 +2341,11 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
clk_put(dev->clk); clk_put(dev->clk);
if (dev->transceiver) {
otg_put_transceiver(dev->transceiver);
dev->transceiver = NULL;
}
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
the_controller = NULL; the_controller = NULL;
return 0; return 0;

View File

@ -128,6 +128,7 @@ struct pxa25x_udc {
struct device *dev; struct device *dev;
struct clk *clk; struct clk *clk;
struct pxa2xx_udc_mach_info *mach; struct pxa2xx_udc_mach_info *mach;
struct otg_transceiver *transceiver;
u64 dma_mask; u64 dma_mask;
struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS]; struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS];

View File

@ -1022,22 +1022,29 @@ static rndis_resp_t *rndis_add_response (int configNr, u32 length)
return r; return r;
} }
int rndis_rm_hdr(struct sk_buff *skb) int rndis_rm_hdr(struct gether *port,
struct sk_buff *skb,
struct sk_buff_head *list)
{ {
/* tmp points to a struct rndis_packet_msg_type */ /* tmp points to a struct rndis_packet_msg_type */
__le32 *tmp = (void *) skb->data; __le32 *tmp = (void *) skb->data;
/* MessageType, MessageLength */ /* MessageType, MessageLength */
if (cpu_to_le32(REMOTE_NDIS_PACKET_MSG) if (cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
!= get_unaligned(tmp++)) != get_unaligned(tmp++)) {
dev_kfree_skb_any(skb);
return -EINVAL; return -EINVAL;
}
tmp++; tmp++;
/* DataOffset, DataLength */ /* DataOffset, DataLength */
if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8)) {
dev_kfree_skb_any(skb);
return -EOVERFLOW; return -EOVERFLOW;
}
skb_trim(skb, get_unaligned_le32(tmp++)); skb_trim(skb, get_unaligned_le32(tmp++));
skb_queue_tail(list, skb);
return 0; return 0;
} }

View File

@ -251,7 +251,8 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID,
const char *vendorDescr); const char *vendorDescr);
int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed); int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
void rndis_add_hdr (struct sk_buff *skb); void rndis_add_hdr (struct sk_buff *skb);
int rndis_rm_hdr (struct sk_buff *skb); int rndis_rm_hdr(struct gether *port, struct sk_buff *skb,
struct sk_buff_head *list);
u8 *rndis_get_next_response (int configNr, u32 *length); u8 *rndis_get_next_response (int configNr, u32 *length);
void rndis_free_response (int configNr, u8 *buf); void rndis_free_response (int configNr, u8 *buf);

View File

@ -2392,7 +2392,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
grstctl = readl(hsotg->regs + S3C_GRSTCTL); grstctl = readl(hsotg->regs + S3C_GRSTCTL);
} while (!(grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0); } while (!(grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0);
if (!grstctl & S3C_GRSTCTL_CSftRst) { if (!(grstctl & S3C_GRSTCTL_CSftRst)) {
dev_err(hsotg->dev, "Failed to get CSftRst asserted\n"); dev_err(hsotg->dev, "Failed to get CSftRst asserted\n");
return -EINVAL; return -EINVAL;
} }
@ -2514,8 +2514,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
* DMA mode we may need this. */ * DMA mode we may need this. */
writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk | writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk |
S3C_DOEPMSK_EPDisbldMsk | S3C_DOEPMSK_EPDisbldMsk |
using_dma(hsotg) ? (S3C_DIEPMSK_XferComplMsk | (using_dma(hsotg) ? (S3C_DIEPMSK_XferComplMsk |
S3C_DIEPMSK_TimeOUTMsk) : 0, S3C_DIEPMSK_TimeOUTMsk) : 0),
hsotg->regs + S3C_DOEPMSK); hsotg->regs + S3C_DOEPMSK);
writel(0, hsotg->regs + S3C_DAINTMSK); writel(0, hsotg->regs + S3C_DAINTMSK);

View File

@ -1703,8 +1703,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n", dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n",
driver->driver.name); driver->driver.name);
if (driver->disconnect) driver->unbind(&udc->gadget);
driver->disconnect(&udc->gadget);
device_del(&udc->gadget.dev); device_del(&udc->gadget.dev);
udc->driver = NULL; udc->driver = NULL;

View File

@ -253,11 +253,13 @@ static int gaudio_open_snd_dev(struct gaudio *card)
snd->filp = filp_open(fn_cap, O_RDONLY, 0); snd->filp = filp_open(fn_cap, O_RDONLY, 0);
if (IS_ERR(snd->filp)) { if (IS_ERR(snd->filp)) {
ERROR(card, "No such PCM capture device: %s\n", fn_cap); ERROR(card, "No such PCM capture device: %s\n", fn_cap);
snd->filp = NULL; snd->substream = NULL;
snd->card = NULL;
} else {
pcm_file = snd->filp->private_data;
snd->substream = pcm_file->substream;
snd->card = card;
} }
pcm_file = snd->filp->private_data;
snd->substream = pcm_file->substream;
snd->card = card;
return 0; return 0;
} }

View File

@ -37,8 +37,9 @@
* one (!) network link through the USB gadget stack, normally "usb0". * one (!) network link through the USB gadget stack, normally "usb0".
* *
* The control and data models are handled by the function driver which * The control and data models are handled by the function driver which
* connects to this code; such as CDC Ethernet, "CDC Subset", or RNDIS. * connects to this code; such as CDC Ethernet (ECM or EEM),
* That includes all descriptor and endpoint management. * "CDC Subset", or RNDIS. That includes all descriptor and endpoint
* management.
* *
* Link level addressing is handled by this component using module * Link level addressing is handled by this component using module
* parameters; if no such parameters are provided, random link level * parameters; if no such parameters are provided, random link level
@ -68,9 +69,13 @@ struct eth_dev {
struct list_head tx_reqs, rx_reqs; struct list_head tx_reqs, rx_reqs;
atomic_t tx_qlen; atomic_t tx_qlen;
struct sk_buff_head rx_frames;
unsigned header_len; unsigned header_len;
struct sk_buff *(*wrap)(struct sk_buff *skb); struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb);
int (*unwrap)(struct sk_buff *skb); int (*unwrap)(struct gether *,
struct sk_buff *skb,
struct sk_buff_head *list);
struct work_struct work; struct work_struct work;
@ -269,7 +274,7 @@ enomem:
static void rx_complete(struct usb_ep *ep, struct usb_request *req) static void rx_complete(struct usb_ep *ep, struct usb_request *req)
{ {
struct sk_buff *skb = req->context; struct sk_buff *skb = req->context, *skb2;
struct eth_dev *dev = ep->driver_data; struct eth_dev *dev = ep->driver_data;
int status = req->status; int status = req->status;
@ -278,26 +283,47 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
/* normal completion */ /* normal completion */
case 0: case 0:
skb_put(skb, req->actual); skb_put(skb, req->actual);
if (dev->unwrap)
status = dev->unwrap(skb); if (dev->unwrap) {
if (status < 0 unsigned long flags;
|| ETH_HLEN > skb->len
|| skb->len > ETH_FRAME_LEN) { spin_lock_irqsave(&dev->lock, flags);
dev->net->stats.rx_errors++; if (dev->port_usb) {
dev->net->stats.rx_length_errors++; status = dev->unwrap(dev->port_usb,
DBG(dev, "rx length %d\n", skb->len); skb,
break; &dev->rx_frames);
} else {
dev_kfree_skb_any(skb);
status = -ENOTCONN;
}
spin_unlock_irqrestore(&dev->lock, flags);
} else {
skb_queue_tail(&dev->rx_frames, skb);
} }
skb->protocol = eth_type_trans(skb, dev->net);
dev->net->stats.rx_packets++;
dev->net->stats.rx_bytes += skb->len;
/* no buffer copies needed, unless hardware can't
* use skb buffers.
*/
status = netif_rx(skb);
skb = NULL; skb = NULL;
skb2 = skb_dequeue(&dev->rx_frames);
while (skb2) {
if (status < 0
|| ETH_HLEN > skb2->len
|| skb2->len > ETH_FRAME_LEN) {
dev->net->stats.rx_errors++;
dev->net->stats.rx_length_errors++;
DBG(dev, "rx length %d\n", skb2->len);
dev_kfree_skb_any(skb2);
goto next_frame;
}
skb2->protocol = eth_type_trans(skb2, dev->net);
dev->net->stats.rx_packets++;
dev->net->stats.rx_bytes += skb2->len;
/* no buffer copies needed, unless hardware can't
* use skb buffers.
*/
status = netif_rx(skb2);
next_frame:
skb2 = skb_dequeue(&dev->rx_frames);
}
break; break;
/* software-driven interface shutdown */ /* software-driven interface shutdown */
@ -537,14 +563,15 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
* or there's not enough space for extra headers we need * or there's not enough space for extra headers we need
*/ */
if (dev->wrap) { if (dev->wrap) {
struct sk_buff *skb_new; unsigned long flags;
skb_new = dev->wrap(skb); spin_lock_irqsave(&dev->lock, flags);
if (!skb_new) if (dev->port_usb)
skb = dev->wrap(dev->port_usb, skb);
spin_unlock_irqrestore(&dev->lock, flags);
if (!skb)
goto drop; goto drop;
dev_kfree_skb_any(skb);
skb = skb_new;
length = skb->len; length = skb->len;
} }
req->buf = skb->data; req->buf = skb->data;
@ -578,9 +605,9 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
} }
if (retval) { if (retval) {
dev_kfree_skb_any(skb);
drop: drop:
dev->net->stats.tx_dropped++; dev->net->stats.tx_dropped++;
dev_kfree_skb_any(skb);
spin_lock_irqsave(&dev->req_lock, flags); spin_lock_irqsave(&dev->req_lock, flags);
if (list_empty(&dev->tx_reqs)) if (list_empty(&dev->tx_reqs))
netif_start_queue(net); netif_start_queue(net);
@ -753,6 +780,8 @@ int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
INIT_LIST_HEAD(&dev->tx_reqs); INIT_LIST_HEAD(&dev->tx_reqs);
INIT_LIST_HEAD(&dev->rx_reqs); INIT_LIST_HEAD(&dev->rx_reqs);
skb_queue_head_init(&dev->rx_frames);
/* network device setup */ /* network device setup */
dev->net = net; dev->net = net;
strcpy(net->name, "usb%d"); strcpy(net->name, "usb%d");

View File

@ -60,12 +60,13 @@ struct gether {
u16 cdc_filter; u16 cdc_filter;
/* hooks for added framing, as needed for RNDIS and EEM. /* hooks for added framing, as needed for RNDIS and EEM. */
* we currently don't support multiple frames per SKB.
*/
u32 header_len; u32 header_len;
struct sk_buff *(*wrap)(struct sk_buff *skb); struct sk_buff *(*wrap)(struct gether *port,
int (*unwrap)(struct sk_buff *skb); struct sk_buff *skb);
int (*unwrap)(struct gether *port,
struct sk_buff *skb,
struct sk_buff_head *list);
/* called on network open/close */ /* called on network open/close */
void (*open)(struct gether *); void (*open)(struct gether *);
@ -109,6 +110,7 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
/* each configuration may bind one instance of an ethernet link */ /* each configuration may bind one instance of an ethernet link */
int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); int ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]);
int eem_bind_config(struct usb_configuration *c);
#ifdef CONFIG_USB_ETH_RNDIS #ifdef CONFIG_USB_ETH_RNDIS

View File

@ -1114,7 +1114,6 @@ int __init gserial_setup(struct usb_gadget *g, unsigned count)
/* export the driver ... */ /* export the driver ... */
status = tty_register_driver(gs_tty_driver); status = tty_register_driver(gs_tty_driver);
if (status) { if (status) {
put_tty_driver(gs_tty_driver);
pr_err("%s: cannot register, err %d\n", pr_err("%s: cannot register, err %d\n",
__func__, status); __func__, status);
goto fail; goto fail;

View File

@ -113,6 +113,12 @@ config USB_EHCI_HCD_PPC_OF
Enables support for the USB controller present on the PowerPC Enables support for the USB controller present on the PowerPC
OpenFirmware platform bus. OpenFirmware platform bus.
config USB_W90X900_EHCI
bool "W90X900(W90P910) EHCI support"
depends on USB_EHCI_HCD && ARCH_W90X900
---help---
Enables support for the W90X900 USB controller
config USB_OXU210HP_HCD config USB_OXU210HP_HCD
tristate "OXU210HP HCD support" tristate "OXU210HP HCD support"
depends on USB depends on USB
@ -153,6 +159,18 @@ config USB_ISP1760_HCD
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called isp1760. module will be called isp1760.
config USB_ISP1362_HCD
tristate "ISP1362 HCD support"
depends on USB
default N
---help---
Supports the Philips ISP1362 chip as a host controller
This driver does not support isochronous transfers.
To compile this driver as a module, choose M here: the
module will be called isp1362-hcd.
config USB_OHCI_HCD config USB_OHCI_HCD
tristate "OHCI HCD support" tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI depends on USB && USB_ARCH_HAS_OHCI

View File

@ -21,6 +21,7 @@ obj-$(CONFIG_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o
obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
obj-$(CONFIG_USB_ISP1362_HCD) += isp1362-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_FHCI_HCD) += fhci.o obj-$(CONFIG_USB_FHCI_HCD) += fhci.o

View File

@ -0,0 +1,230 @@
/*
* Driver for EHCI UHP on Atmel chips
*
* Copyright (C) 2009 Atmel Corporation,
* Nicolas Ferre <nicolas.ferre@atmel.com>
*
* Based on various ehci-*.c drivers
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive for
* more details.
*/
#include <linux/clk.h>
#include <linux/platform_device.h>
/* interface and function clocks */
static struct clk *iclk, *fclk;
static int clocked;
/*-------------------------------------------------------------------------*/
static void atmel_start_clock(void)
{
clk_enable(iclk);
clk_enable(fclk);
clocked = 1;
}
static void atmel_stop_clock(void)
{
clk_disable(fclk);
clk_disable(iclk);
clocked = 0;
}
static void atmel_start_ehci(struct platform_device *pdev)
{
dev_dbg(&pdev->dev, "start\n");
atmel_start_clock();
}
static void atmel_stop_ehci(struct platform_device *pdev)
{
dev_dbg(&pdev->dev, "stop\n");
atmel_stop_clock();
}
/*-------------------------------------------------------------------------*/
static int ehci_atmel_setup(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval = 0;
/* registers start at offset 0x0 */
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");
/* cache this readonly data; minimize chip reads */
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
retval = ehci_halt(ehci);
if (retval)
return retval;
/* data structure init */
retval = ehci_init(hcd);
if (retval)
return retval;
ehci->sbrn = 0x20;
ehci_reset(ehci);
ehci_port_power(ehci, 0);
return retval;
}
static const struct hc_driver ehci_atmel_hc_driver = {
.description = hcd_name,
.product_desc = "Atmel EHCI UHP HS",
.hcd_priv_size = sizeof(struct ehci_hcd),
/* generic hardware linkage */
.irq = ehci_irq,
.flags = HCD_MEMORY | HCD_USB2,
/* basic lifecycle operations */
.reset = ehci_atmel_setup,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
/* managing i/o requests and associated device resources */
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
/* scheduling support */
.get_frame_number = ehci_get_frame,
/* root hub support */
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
};
static int __init ehci_atmel_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
const struct hc_driver *driver = &ehci_atmel_hc_driver;
struct resource *res;
int irq;
int retval;
if (usb_disabled())
return -ENODEV;
pr_debug("Initializing Atmel-SoC USB Host Controller\n");
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(&pdev->dev,
"Found HC with no IRQ. Check %s setup!\n",
dev_name(&pdev->dev));
retval = -ENODEV;
goto fail_create_hcd;
}
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
retval = -ENOMEM;
goto fail_create_hcd;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev,
"Found HC with no register addr. Check %s setup!\n",
dev_name(&pdev->dev));
retval = -ENODEV;
goto fail_request_resource;
}
hcd->rsrc_start = res->start;
hcd->rsrc_len = res->end - res->start + 1;
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
driver->description)) {
dev_dbg(&pdev->dev, "controller already in use\n");
retval = -EBUSY;
goto fail_request_resource;
}
hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
dev_dbg(&pdev->dev, "error mapping memory\n");
retval = -EFAULT;
goto fail_ioremap;
}
iclk = clk_get(&pdev->dev, "ehci_clk");
if (IS_ERR(iclk)) {
dev_err(&pdev->dev, "Error getting interface clock\n");
retval = -ENOENT;
goto fail_get_iclk;
}
fclk = clk_get(&pdev->dev, "uhpck");
if (IS_ERR(fclk)) {
dev_err(&pdev->dev, "Error getting function clock\n");
retval = -ENOENT;
goto fail_get_fclk;
}
atmel_start_ehci(pdev);
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval)
goto fail_add_hcd;
return retval;
fail_add_hcd:
atmel_stop_ehci(pdev);
clk_put(fclk);
fail_get_fclk:
clk_put(iclk);
fail_get_iclk:
iounmap(hcd->regs);
fail_ioremap:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
fail_request_resource:
usb_put_hcd(hcd);
fail_create_hcd:
dev_err(&pdev->dev, "init %s fail, %d\n",
dev_name(&pdev->dev), retval);
return retval;
}
static int __exit ehci_atmel_drv_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
ehci_shutdown(hcd);
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
atmel_stop_ehci(pdev);
clk_put(fclk);
clk_put(iclk);
fclk = iclk = NULL;
return 0;
}
static struct platform_driver ehci_atmel_driver = {
.probe = ehci_atmel_drv_probe,
.remove = __exit_p(ehci_atmel_drv_remove),
.shutdown = usb_hcd_platform_shutdown,
.driver.name = "atmel-ehci",
};

View File

@ -199,10 +199,9 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int ehci_hcd_au1xxx_drv_suspend(struct platform_device *pdev, static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
pm_message_t message)
{ {
struct usb_hcd *hcd = platform_get_drvdata(pdev); struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_hcd *ehci = hcd_to_ehci(hcd);
unsigned long flags; unsigned long flags;
int rc; int rc;
@ -229,12 +228,6 @@ static int ehci_hcd_au1xxx_drv_suspend(struct platform_device *pdev,
ehci_writel(ehci, 0, &ehci->regs->intr_enable); ehci_writel(ehci, 0, &ehci->regs->intr_enable);
(void)ehci_readl(ehci, &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) {
ehci_halt(ehci);
ehci_reset(ehci);
}
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
au1xxx_stop_ehc(); au1xxx_stop_ehc();
@ -248,10 +241,9 @@ bail:
return rc; return rc;
} }
static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
static int ehci_hcd_au1xxx_drv_resume(struct platform_device *pdev)
{ {
struct usb_hcd *hcd = platform_get_drvdata(pdev); struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_hcd *ehci = hcd_to_ehci(hcd);
au1xxx_start_ehc(); au1xxx_start_ehc();
@ -305,20 +297,25 @@ static int ehci_hcd_au1xxx_drv_resume(struct platform_device *pdev)
return 0; return 0;
} }
static struct dev_pm_ops au1xxx_ehci_pmops = {
.suspend = ehci_hcd_au1xxx_drv_suspend,
.resume = ehci_hcd_au1xxx_drv_resume,
};
#define AU1XXX_EHCI_PMOPS &au1xxx_ehci_pmops
#else #else
#define ehci_hcd_au1xxx_drv_suspend NULL #define AU1XXX_EHCI_PMOPS NULL
#define ehci_hcd_au1xxx_drv_resume NULL
#endif #endif
static struct platform_driver ehci_hcd_au1xxx_driver = { static struct platform_driver ehci_hcd_au1xxx_driver = {
.probe = ehci_hcd_au1xxx_drv_probe, .probe = ehci_hcd_au1xxx_drv_probe,
.remove = ehci_hcd_au1xxx_drv_remove, .remove = ehci_hcd_au1xxx_drv_remove,
.shutdown = usb_hcd_platform_shutdown, .shutdown = usb_hcd_platform_shutdown,
.suspend = ehci_hcd_au1xxx_drv_suspend,
.resume = ehci_hcd_au1xxx_drv_resume,
.driver = { .driver = {
.name = "au1xxx-ehci", .name = "au1xxx-ehci",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = AU1XXX_EHCI_PMOPS,
} }
}; };

View File

@ -134,10 +134,11 @@ dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
static void __maybe_unused static void __maybe_unused
dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh) dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
{ {
struct ehci_qh_hw *hw = qh->hw;
ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label, ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label,
qh, qh->hw_next, qh->hw_info1, qh->hw_info2, qh, hw->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current);
qh->hw_current); dbg_qtd("overlay", ehci, (struct ehci_qtd *) &hw->hw_qtd_next);
dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next);
} }
static void __maybe_unused static void __maybe_unused
@ -400,31 +401,32 @@ static void qh_lines (
char *next = *nextp; char *next = *nextp;
char mark; char mark;
__le32 list_end = EHCI_LIST_END(ehci); __le32 list_end = EHCI_LIST_END(ehci);
struct ehci_qh_hw *hw = qh->hw;
if (qh->hw_qtd_next == list_end) /* NEC does this */ if (hw->hw_qtd_next == list_end) /* NEC does this */
mark = '@'; mark = '@';
else else
mark = token_mark(ehci, qh->hw_token); mark = token_mark(ehci, hw->hw_token);
if (mark == '/') { /* qh_alt_next controls qh advance? */ if (mark == '/') { /* qh_alt_next controls qh advance? */
if ((qh->hw_alt_next & QTD_MASK(ehci)) if ((hw->hw_alt_next & QTD_MASK(ehci))
== ehci->async->hw_alt_next) == ehci->async->hw->hw_alt_next)
mark = '#'; /* blocked */ mark = '#'; /* blocked */
else if (qh->hw_alt_next == list_end) else if (hw->hw_alt_next == list_end)
mark = '.'; /* use hw_qtd_next */ mark = '.'; /* use hw_qtd_next */
/* else alt_next points to some other qtd */ /* else alt_next points to some other qtd */
} }
scratch = hc32_to_cpup(ehci, &qh->hw_info1); scratch = hc32_to_cpup(ehci, &hw->hw_info1);
hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &qh->hw_current) : 0; hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &hw->hw_current) : 0;
temp = scnprintf (next, size, temp = scnprintf (next, size,
"qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)", "qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
qh, scratch & 0x007f, qh, scratch & 0x007f,
speed_char (scratch), speed_char (scratch),
(scratch >> 8) & 0x000f, (scratch >> 8) & 0x000f,
scratch, hc32_to_cpup(ehci, &qh->hw_info2), scratch, hc32_to_cpup(ehci, &hw->hw_info2),
hc32_to_cpup(ehci, &qh->hw_token), mark, hc32_to_cpup(ehci, &hw->hw_token), mark,
(cpu_to_hc32(ehci, QTD_TOGGLE) & qh->hw_token) (cpu_to_hc32(ehci, QTD_TOGGLE) & hw->hw_token)
? "data1" : "data0", ? "data1" : "data0",
(hc32_to_cpup(ehci, &qh->hw_alt_next) >> 1) & 0x0f); (hc32_to_cpup(ehci, &hw->hw_alt_next) >> 1) & 0x0f);
size -= temp; size -= temp;
next += temp; next += temp;
@ -435,10 +437,10 @@ static void qh_lines (
mark = ' '; mark = ' ';
if (hw_curr == td->qtd_dma) if (hw_curr == td->qtd_dma)
mark = '*'; mark = '*';
else if (qh->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma)) else if (hw->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma))
mark = '+'; mark = '+';
else if (QTD_LENGTH (scratch)) { else if (QTD_LENGTH (scratch)) {
if (td->hw_alt_next == ehci->async->hw_alt_next) if (td->hw_alt_next == ehci->async->hw->hw_alt_next)
mark = '#'; mark = '#';
else if (td->hw_alt_next != list_end) else if (td->hw_alt_next != list_end)
mark = '/'; mark = '/';
@ -550,12 +552,15 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
next += temp; next += temp;
do { do {
struct ehci_qh_hw *hw;
switch (hc32_to_cpu(ehci, tag)) { switch (hc32_to_cpu(ehci, tag)) {
case Q_TYPE_QH: case Q_TYPE_QH:
hw = p.qh->hw;
temp = scnprintf (next, size, " qh%d-%04x/%p", temp = scnprintf (next, size, " qh%d-%04x/%p",
p.qh->period, p.qh->period,
hc32_to_cpup(ehci, hc32_to_cpup(ehci,
&p.qh->hw_info2) &hw->hw_info2)
/* uframe masks */ /* uframe masks */
& (QH_CMASK | QH_SMASK), & (QH_CMASK | QH_SMASK),
p.qh); p.qh);
@ -576,7 +581,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
/* show more info the first time around */ /* show more info the first time around */
if (temp == seen_count) { if (temp == seen_count) {
u32 scratch = hc32_to_cpup(ehci, u32 scratch = hc32_to_cpup(ehci,
&p.qh->hw_info1); &hw->hw_info1);
struct ehci_qtd *qtd; struct ehci_qtd *qtd;
char *type = ""; char *type = "";
@ -609,7 +614,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
} else } else
temp = 0; temp = 0;
if (p.qh) { if (p.qh) {
tag = Q_NEXT_TYPE(ehci, p.qh->hw_next); tag = Q_NEXT_TYPE(ehci, hw->hw_next);
p = p.qh->qh_next; p = p.qh->qh_next;
} }
break; break;
@ -879,8 +884,7 @@ static int debug_close(struct inode *inode, struct file *file)
struct debug_buffer *buf = file->private_data; struct debug_buffer *buf = file->private_data;
if (buf) { if (buf) {
if (buf->output_buf) vfree(buf->output_buf);
vfree(buf->output_buf);
kfree(buf); kfree(buf);
} }

View File

@ -30,7 +30,6 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
@ -127,6 +126,8 @@ timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
switch (action) { switch (action) {
case TIMER_IO_WATCHDOG: case TIMER_IO_WATCHDOG:
if (!ehci->need_io_watchdog)
return;
t = EHCI_IO_JIFFIES; t = EHCI_IO_JIFFIES;
break; break;
case TIMER_ASYNC_OFF: case TIMER_ASYNC_OFF:
@ -239,6 +240,11 @@ static int ehci_reset (struct ehci_hcd *ehci)
int retval; int retval;
u32 command = ehci_readl(ehci, &ehci->regs->command); u32 command = ehci_readl(ehci, &ehci->regs->command);
/* If the EHCI debug controller is active, special care must be
* taken before and after a host controller reset */
if (ehci->debug && !dbgp_reset_prep())
ehci->debug = NULL;
command |= CMD_RESET; command |= CMD_RESET;
dbg_cmd (ehci, "reset", command); dbg_cmd (ehci, "reset", command);
ehci_writel(ehci, command, &ehci->regs->command); ehci_writel(ehci, command, &ehci->regs->command);
@ -247,12 +253,21 @@ static int ehci_reset (struct ehci_hcd *ehci)
retval = handshake (ehci, &ehci->regs->command, retval = handshake (ehci, &ehci->regs->command,
CMD_RESET, 0, 250 * 1000); CMD_RESET, 0, 250 * 1000);
if (ehci->has_hostpc) {
ehci_writel(ehci, USBMODE_EX_HC | USBMODE_EX_VBPS,
(u32 __iomem *)(((u8 *)ehci->regs) + USBMODE_EX));
ehci_writel(ehci, TXFIFO_DEFAULT,
(u32 __iomem *)(((u8 *)ehci->regs) + TXFILLTUNING));
}
if (retval) if (retval)
return retval; return retval;
if (ehci_is_TDI(ehci)) if (ehci_is_TDI(ehci))
tdi_reset (ehci); tdi_reset (ehci);
if (ehci->debug)
dbgp_external_startup();
return retval; return retval;
} }
@ -505,9 +520,14 @@ static int ehci_init(struct usb_hcd *hcd)
u32 temp; u32 temp;
int retval; int retval;
u32 hcc_params; u32 hcc_params;
struct ehci_qh_hw *hw;
spin_lock_init(&ehci->lock); spin_lock_init(&ehci->lock);
/*
* keep io watchdog by default, those good HCDs could turn off it later
*/
ehci->need_io_watchdog = 1;
init_timer(&ehci->watchdog); init_timer(&ehci->watchdog);
ehci->watchdog.function = ehci_watchdog; ehci->watchdog.function = ehci_watchdog;
ehci->watchdog.data = (unsigned long) ehci; ehci->watchdog.data = (unsigned long) ehci;
@ -544,12 +564,13 @@ static int ehci_init(struct usb_hcd *hcd)
* from automatically advancing to the next td after short reads. * from automatically advancing to the next td after short reads.
*/ */
ehci->async->qh_next.qh = NULL; ehci->async->qh_next.qh = NULL;
ehci->async->hw_next = QH_NEXT(ehci, ehci->async->qh_dma); hw = ehci->async->hw;
ehci->async->hw_info1 = cpu_to_hc32(ehci, QH_HEAD); hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
ehci->async->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT); hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
ehci->async->hw_qtd_next = EHCI_LIST_END(ehci); hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
hw->hw_qtd_next = EHCI_LIST_END(ehci);
ehci->async->qh_state = QH_STATE_LINKED; ehci->async->qh_state = QH_STATE_LINKED;
ehci->async->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma); hw->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma);
/* clear interrupt enables, set irq latency */ /* clear interrupt enables, set irq latency */
if (log2_irq_thresh < 0 || log2_irq_thresh > 6) if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
@ -850,12 +871,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim) if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim)
end_unlink_async(ehci); end_unlink_async(ehci);
/* if it's not linked then there's nothing to do */ /* If the QH isn't linked then there's nothing we can do
if (qh->qh_state != QH_STATE_LINKED) * unless we were called during a giveback, in which case
; * qh_completions() has to deal with it.
*/
if (qh->qh_state != QH_STATE_LINKED) {
if (qh->qh_state == QH_STATE_COMPLETING)
qh->needs_rescan = 1;
return;
}
/* defer till later if busy */ /* defer till later if busy */
else if (ehci->reclaim) { if (ehci->reclaim) {
struct ehci_qh *last; struct ehci_qh *last;
for (last = ehci->reclaim; for (last = ehci->reclaim;
@ -915,8 +942,9 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
break; break;
switch (qh->qh_state) { switch (qh->qh_state) {
case QH_STATE_LINKED: case QH_STATE_LINKED:
case QH_STATE_COMPLETING:
intr_deschedule (ehci, qh); intr_deschedule (ehci, qh);
/* FALL THROUGH */ break;
case QH_STATE_IDLE: case QH_STATE_IDLE:
qh_completions (ehci, qh); qh_completions (ehci, qh);
break; break;
@ -925,23 +953,6 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
qh, qh->qh_state); qh, qh->qh_state);
goto done; goto done;
} }
/* reschedule QH iff another request is queued */
if (!list_empty (&qh->qtd_list)
&& HC_IS_RUNNING (hcd->state)) {
rc = qh_schedule(ehci, qh);
/* An error here likely indicates handshake failure
* or no space left in the schedule. Neither fault
* should happen often ...
*
* FIXME kill the now-dysfunctional queued urbs
*/
if (rc != 0)
ehci_err(ehci,
"can't reschedule qh %p, err %d",
qh, rc);
}
break; break;
case PIPE_ISOCHRONOUS: case PIPE_ISOCHRONOUS:
@ -979,7 +990,7 @@ rescan:
/* endpoints can be iso streams. for now, we don't /* endpoints can be iso streams. for now, we don't
* accelerate iso completions ... so spin a while. * accelerate iso completions ... so spin a while.
*/ */
if (qh->hw_info1 == 0) { if (qh->hw->hw_info1 == 0) {
ehci_vdbg (ehci, "iso delay\n"); ehci_vdbg (ehci, "iso delay\n");
goto idle_timeout; goto idle_timeout;
} }
@ -988,6 +999,7 @@ rescan:
qh->qh_state = QH_STATE_IDLE; qh->qh_state = QH_STATE_IDLE;
switch (qh->qh_state) { switch (qh->qh_state) {
case QH_STATE_LINKED: case QH_STATE_LINKED:
case QH_STATE_COMPLETING:
for (tmp = ehci->async->qh_next.qh; for (tmp = ehci->async->qh_next.qh;
tmp && tmp != qh; tmp && tmp != qh;
tmp = tmp->qh_next.qh) tmp = tmp->qh_next.qh)
@ -1052,18 +1064,17 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
usb_settoggle(qh->dev, epnum, is_out, 0); usb_settoggle(qh->dev, epnum, is_out, 0);
if (!list_empty(&qh->qtd_list)) { if (!list_empty(&qh->qtd_list)) {
WARN_ONCE(1, "clear_halt for a busy endpoint\n"); WARN_ONCE(1, "clear_halt for a busy endpoint\n");
} else if (qh->qh_state == QH_STATE_LINKED) { } else if (qh->qh_state == QH_STATE_LINKED ||
qh->qh_state == QH_STATE_COMPLETING) {
/* The toggle value in the QH can't be updated /* The toggle value in the QH can't be updated
* while the QH is active. Unlink it now; * while the QH is active. Unlink it now;
* re-linking will call qh_refresh(). * re-linking will call qh_refresh().
*/ */
if (eptype == USB_ENDPOINT_XFER_BULK) { if (eptype == USB_ENDPOINT_XFER_BULK)
unlink_async(ehci, qh); unlink_async(ehci, qh);
} else { else
intr_deschedule(ehci, qh); intr_deschedule(ehci, qh);
(void) qh_schedule(ehci, qh);
}
} }
} }
spin_unlock_irqrestore(&ehci->lock, flags); spin_unlock_irqrestore(&ehci->lock, flags);
@ -1117,6 +1128,16 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ixp4xx_ehci_driver #define PLATFORM_DRIVER ixp4xx_ehci_driver
#endif #endif
#ifdef CONFIG_USB_W90X900_EHCI
#include "ehci-w90x900.c"
#define PLATFORM_DRIVER ehci_hcd_w90x900_driver
#endif
#ifdef CONFIG_ARCH_AT91
#include "ehci-atmel.c"
#define PLATFORM_DRIVER ehci_atmel_driver
#endif
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \ #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
#error "missing bus glue for ehci-hcd" #error "missing bus glue for ehci-hcd"

View File

@ -111,6 +111,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci (hcd); struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int port; int port;
int mask; int mask;
u32 __iomem *hostpc_reg = NULL;
ehci_dbg(ehci, "suspend root hub\n"); ehci_dbg(ehci, "suspend root hub\n");
@ -142,6 +143,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
u32 t2 = t1; u32 t2 = t1;
if (ehci->has_hostpc)
hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
+ HOSTPC0 + 4 * (port & 0xff));
/* keep track of which ports we suspend */ /* keep track of which ports we suspend */
if (t1 & PORT_OWNER) if (t1 & PORT_OWNER)
set_bit(port, &ehci->owned_ports); set_bit(port, &ehci->owned_ports);
@ -151,15 +155,37 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
} }
/* enable remote wakeup on all ports */ /* enable remote wakeup on all ports */
if (hcd->self.root_hub->do_remote_wakeup) if (hcd->self.root_hub->do_remote_wakeup) {
t2 |= PORT_WAKE_BITS; /* only enable appropriate wake bits, otherwise the
else * hardware can not go phy low power mode. If a race
* condition happens here(connection change during bits
* set), the port change detection will finally fix it.
*/
if (t1 & PORT_CONNECT) {
t2 |= PORT_WKOC_E | PORT_WKDISC_E;
t2 &= ~PORT_WKCONN_E;
} else {
t2 |= PORT_WKOC_E | PORT_WKCONN_E;
t2 &= ~PORT_WKDISC_E;
}
} else
t2 &= ~PORT_WAKE_BITS; t2 &= ~PORT_WAKE_BITS;
if (t1 != t2) { if (t1 != t2) {
ehci_vdbg (ehci, "port %d, %08x -> %08x\n", ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
port + 1, t1, t2); port + 1, t1, t2);
ehci_writel(ehci, t2, reg); ehci_writel(ehci, t2, reg);
if (hostpc_reg) {
u32 t3;
msleep(5);/* 5ms for HCD enter low pwr mode */
t3 = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
t3 = ehci_readl(ehci, hostpc_reg);
ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
port, (t3 & HOSTPC_PHCD) ?
"succeeded" : "failed");
}
} }
} }
@ -183,6 +209,11 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci->next_statechange = jiffies + msecs_to_jiffies(10); ehci->next_statechange = jiffies + msecs_to_jiffies(10);
spin_unlock_irq (&ehci->lock); spin_unlock_irq (&ehci->lock);
/* ehci_work() may have re-enabled the watchdog timer, which we do not
* want, and so we must delete any pending watchdog timer events.
*/
del_timer_sync(&ehci->watchdog);
return 0; return 0;
} }
@ -204,6 +235,13 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
return -ESHUTDOWN; return -ESHUTDOWN;
} }
if (unlikely(ehci->debug)) {
if (ehci->debug && !dbgp_reset_prep())
ehci->debug = NULL;
else
dbgp_external_startup();
}
/* Ideally and we've got a real resume here, and no port's power /* Ideally and we've got a real resume here, and no port's power
* was lost. (For PCI, that means Vaux was maintained.) But we * was lost. (For PCI, that means Vaux was maintained.) But we
* could instead be restoring a swsusp snapshot -- so that BIOS was * could instead be restoring a swsusp snapshot -- so that BIOS was
@ -563,7 +601,8 @@ static int ehci_hub_control (
int ports = HCS_N_PORTS (ehci->hcs_params); int ports = HCS_N_PORTS (ehci->hcs_params);
u32 __iomem *status_reg = &ehci->regs->port_status[ u32 __iomem *status_reg = &ehci->regs->port_status[
(wIndex & 0xff) - 1]; (wIndex & 0xff) - 1];
u32 temp, status; u32 __iomem *hostpc_reg = NULL;
u32 temp, temp1, status;
unsigned long flags; unsigned long flags;
int retval = 0; int retval = 0;
unsigned selector; unsigned selector;
@ -575,6 +614,9 @@ static int ehci_hub_control (
* power, "this is the one", etc. EHCI spec supports this. * power, "this is the one", etc. EHCI spec supports this.
*/ */
if (ehci->has_hostpc)
hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
+ HOSTPC0 + 4 * ((wIndex & 0xff) - 1));
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
switch (typeReq) { switch (typeReq) {
case ClearHubFeature: case ClearHubFeature:
@ -773,7 +815,11 @@ static int ehci_hub_control (
if (temp & PORT_CONNECT) { if (temp & PORT_CONNECT) {
status |= 1 << USB_PORT_FEAT_CONNECTION; status |= 1 << USB_PORT_FEAT_CONNECTION;
// status may be from integrated TT // status may be from integrated TT
status |= ehci_port_speed(ehci, temp); if (ehci->has_hostpc) {
temp1 = ehci_readl(ehci, hostpc_reg);
status |= ehci_port_speed(ehci, temp1);
} else
status |= ehci_port_speed(ehci, temp);
} }
if (temp & PORT_PE) if (temp & PORT_PE)
status |= 1 << USB_PORT_FEAT_ENABLE; status |= 1 << USB_PORT_FEAT_ENABLE;
@ -816,6 +862,15 @@ static int ehci_hub_control (
case SetPortFeature: case SetPortFeature:
selector = wIndex >> 8; selector = wIndex >> 8;
wIndex &= 0xff; wIndex &= 0xff;
if (unlikely(ehci->debug)) {
/* If the debug port is active any port
* feature requests should get denied */
if (wIndex == HCS_DEBUG_PORT(ehci->hcs_params) &&
(readl(&ehci->debug->control) & DBGP_ENABLED)) {
retval = -ENODEV;
goto error_exit;
}
}
if (!wIndex || wIndex > ports) if (!wIndex || wIndex > ports)
goto error; goto error;
wIndex--; wIndex--;
@ -832,6 +887,24 @@ static int ehci_hub_control (
|| (temp & PORT_RESET) != 0) || (temp & PORT_RESET) != 0)
goto error; goto error;
ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
/* After above check the port must be connected.
* Set appropriate bit thus could put phy into low power
* mode if we have hostpc feature
*/
if (hostpc_reg) {
temp &= ~PORT_WKCONN_E;
temp |= (PORT_WKDISC_E | PORT_WKOC_E);
ehci_writel(ehci, temp | PORT_SUSPEND,
status_reg);
msleep(5);/* 5ms for HCD enter low pwr mode */
temp1 = ehci_readl(ehci, hostpc_reg);
ehci_writel(ehci, temp1 | HOSTPC_PHCD,
hostpc_reg);
temp1 = ehci_readl(ehci, hostpc_reg);
ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
wIndex, (temp1 & HOSTPC_PHCD) ?
"succeeded" : "failed");
}
set_bit(wIndex, &ehci->suspended_ports); set_bit(wIndex, &ehci->suspended_ports);
break; break;
case USB_PORT_FEAT_POWER: case USB_PORT_FEAT_POWER:
@ -894,6 +967,7 @@ error:
/* "stall" on error */ /* "stall" on error */
retval = -EPIPE; retval = -EPIPE;
} }
error_exit:
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
return retval; return retval;
} }

View File

@ -75,7 +75,8 @@ static void qh_destroy(struct ehci_qh *qh)
} }
if (qh->dummy) if (qh->dummy)
ehci_qtd_free (ehci, qh->dummy); ehci_qtd_free (ehci, qh->dummy);
dma_pool_free (ehci->qh_pool, qh, qh->qh_dma); dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma);
kfree(qh);
} }
static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
@ -83,12 +84,14 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
struct ehci_qh *qh; struct ehci_qh *qh;
dma_addr_t dma; dma_addr_t dma;
qh = (struct ehci_qh *) qh = kzalloc(sizeof *qh, GFP_ATOMIC);
dma_pool_alloc (ehci->qh_pool, flags, &dma);
if (!qh) if (!qh)
return qh; goto done;
qh->hw = (struct ehci_qh_hw *)
memset (qh, 0, sizeof *qh); dma_pool_alloc(ehci->qh_pool, flags, &dma);
if (!qh->hw)
goto fail;
memset(qh->hw, 0, sizeof *qh->hw);
qh->refcount = 1; qh->refcount = 1;
qh->ehci = ehci; qh->ehci = ehci;
qh->qh_dma = dma; qh->qh_dma = dma;
@ -99,10 +102,15 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
qh->dummy = ehci_qtd_alloc (ehci, flags); qh->dummy = ehci_qtd_alloc (ehci, flags);
if (qh->dummy == NULL) { if (qh->dummy == NULL) {
ehci_dbg (ehci, "no dummy td\n"); ehci_dbg (ehci, "no dummy td\n");
dma_pool_free (ehci->qh_pool, qh, qh->qh_dma); goto fail1;
qh = NULL;
} }
done:
return qh; return qh;
fail1:
dma_pool_free(ehci->qh_pool, qh->hw, qh->qh_dma);
fail:
kfree(qh);
return NULL;
} }
/* to share a qh (cpu threads, or hc) */ /* to share a qh (cpu threads, or hc) */
@ -180,7 +188,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
/* QHs for control/bulk/intr transfers */ /* QHs for control/bulk/intr transfers */
ehci->qh_pool = dma_pool_create ("ehci_qh", ehci->qh_pool = dma_pool_create ("ehci_qh",
ehci_to_hcd(ehci)->self.controller, ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_qh), sizeof(struct ehci_qh_hw),
32 /* byte alignment (for hw parts) */, 32 /* byte alignment (for hw parts) */,
4096 /* can't cross 4K */); 4096 /* can't cross 4K */);
if (!ehci->qh_pool) { if (!ehci->qh_pool) {

View File

@ -27,28 +27,8 @@
/* called after powerup, by probe or system-pm "wakeup" */ /* called after powerup, by probe or system-pm "wakeup" */
static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
{ {
u32 temp;
int retval; int retval;
/* optional debug port, normally in the first BAR */
temp = pci_find_capability(pdev, 0x0a);
if (temp) {
pci_read_config_dword(pdev, temp, &temp);
temp >>= 16;
if ((temp & (3 << 13)) == (1 << 13)) {
temp &= 0x1fff;
ehci->debug = ehci_to_hcd(ehci)->regs + temp;
temp = ehci_readl(ehci, &ehci->debug->control);
ehci_info(ehci, "debug port %d%s\n",
HCS_DEBUG_PORT(ehci->hcs_params),
(temp & DBGP_ENABLED)
? " IN USE"
: "");
if (!(temp & DBGP_ENABLED))
ehci->debug = NULL;
}
}
/* we expect static quirk code to handle the "extended capabilities" /* we expect static quirk code to handle the "extended capabilities"
* (currently just BIOS handoff) allowed starting with EHCI 0.96 * (currently just BIOS handoff) allowed starting with EHCI 0.96
*/ */
@ -129,6 +109,9 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
return retval; return retval;
switch (pdev->vendor) { switch (pdev->vendor) {
case PCI_VENDOR_ID_INTEL:
ehci->need_io_watchdog = 0;
break;
case PCI_VENDOR_ID_TDI: case PCI_VENDOR_ID_TDI:
if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) { if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
hcd->has_tt = 1; hcd->has_tt = 1;
@ -192,6 +175,25 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
break; break;
} }
/* optional debug port, normally in the first BAR */
temp = pci_find_capability(pdev, 0x0a);
if (temp) {
pci_read_config_dword(pdev, temp, &temp);
temp >>= 16;
if ((temp & (3 << 13)) == (1 << 13)) {
temp &= 0x1fff;
ehci->debug = ehci_to_hcd(ehci)->regs + temp;
temp = ehci_readl(ehci, &ehci->debug->control);
ehci_info(ehci, "debug port %d%s\n",
HCS_DEBUG_PORT(ehci->hcs_params),
(temp & DBGP_ENABLED)
? " IN USE"
: "");
if (!(temp & DBGP_ENABLED))
ehci->debug = NULL;
}
}
ehci_reset(ehci); ehci_reset(ehci);
/* at least the Genesys GL880S needs fixup here */ /* at least the Genesys GL880S needs fixup here */

View File

@ -87,31 +87,33 @@ qtd_fill(struct ehci_hcd *ehci, struct ehci_qtd *qtd, dma_addr_t buf,
static inline void static inline void
qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd) qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
{ {
struct ehci_qh_hw *hw = qh->hw;
/* writes to an active overlay are unsafe */ /* writes to an active overlay are unsafe */
BUG_ON(qh->qh_state != QH_STATE_IDLE); BUG_ON(qh->qh_state != QH_STATE_IDLE);
qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma); hw->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
qh->hw_alt_next = EHCI_LIST_END(ehci); hw->hw_alt_next = EHCI_LIST_END(ehci);
/* Except for control endpoints, we make hardware maintain data /* Except for control endpoints, we make hardware maintain data
* toggle (like OHCI) ... here (re)initialize the toggle in the QH, * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
* and set the pseudo-toggle in udev. Only usb_clear_halt() will * and set the pseudo-toggle in udev. Only usb_clear_halt() will
* ever clear it. * ever clear it.
*/ */
if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) { if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
unsigned is_out, epnum; unsigned is_out, epnum;
is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8)); is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f; epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f;
if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) { if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE); hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
usb_settoggle (qh->dev, epnum, is_out, 1); usb_settoggle (qh->dev, epnum, is_out, 1);
} }
} }
/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */ /* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
wmb (); wmb ();
qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING); hw->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
} }
/* if it weren't for a common silicon quirk (writing the dummy into the qh /* if it weren't for a common silicon quirk (writing the dummy into the qh
@ -129,7 +131,7 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
qtd = list_entry (qh->qtd_list.next, qtd = list_entry (qh->qtd_list.next,
struct ehci_qtd, qtd_list); struct ehci_qtd, qtd_list);
/* first qtd may already be partially processed */ /* first qtd may already be partially processed */
if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw_current) if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current)
qtd = NULL; qtd = NULL;
} }
@ -260,7 +262,7 @@ __acquires(ehci->lock)
struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv; struct ehci_qh *qh = (struct ehci_qh *) urb->hcpriv;
/* S-mask in a QH means it's an interrupt urb */ /* S-mask in a QH means it's an interrupt urb */
if ((qh->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) { if ((qh->hw->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) {
/* ... update hc-wide periodic stats (for usbfs) */ /* ... update hc-wide periodic stats (for usbfs) */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs--; ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
@ -297,7 +299,6 @@ __acquires(ehci->lock)
static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh); static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh); static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh); static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
/* /*
@ -308,13 +309,14 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
static unsigned static unsigned
qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
{ {
struct ehci_qtd *last = NULL, *end = qh->dummy; struct ehci_qtd *last, *end = qh->dummy;
struct list_head *entry, *tmp; struct list_head *entry, *tmp;
int last_status = -EINPROGRESS; int last_status;
int stopped; int stopped;
unsigned count = 0; unsigned count = 0;
u8 state; u8 state;
__le32 halt = HALT_BIT(ehci); const __le32 halt = HALT_BIT(ehci);
struct ehci_qh_hw *hw = qh->hw;
if (unlikely (list_empty (&qh->qtd_list))) if (unlikely (list_empty (&qh->qtd_list)))
return count; return count;
@ -324,11 +326,20 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
* they add urbs to this qh's queue or mark them for unlinking. * they add urbs to this qh's queue or mark them for unlinking.
* *
* NOTE: unlinking expects to be done in queue order. * NOTE: unlinking expects to be done in queue order.
*
* It's a bug for qh->qh_state to be anything other than
* QH_STATE_IDLE, unless our caller is scan_async() or
* scan_periodic().
*/ */
state = qh->qh_state; state = qh->qh_state;
qh->qh_state = QH_STATE_COMPLETING; qh->qh_state = QH_STATE_COMPLETING;
stopped = (state == QH_STATE_IDLE); stopped = (state == QH_STATE_IDLE);
rescan:
last = NULL;
last_status = -EINPROGRESS;
qh->needs_rescan = 0;
/* remove de-activated QTDs from front of queue. /* remove de-activated QTDs from front of queue.
* after faults (including short reads), cleanup this urb * after faults (including short reads), cleanup this urb
* then let the queue advance. * then let the queue advance.
@ -392,7 +403,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
qtd->hw_token = cpu_to_hc32(ehci, qtd->hw_token = cpu_to_hc32(ehci,
token); token);
wmb(); wmb();
qh->hw_token = cpu_to_hc32(ehci, token); hw->hw_token = cpu_to_hc32(ehci,
token);
goto retry_xacterr; goto retry_xacterr;
} }
stopped = 1; stopped = 1;
@ -435,8 +447,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* qh unlinked; token in overlay may be most current */ /* qh unlinked; token in overlay may be most current */
if (state == QH_STATE_IDLE if (state == QH_STATE_IDLE
&& cpu_to_hc32(ehci, qtd->qtd_dma) && cpu_to_hc32(ehci, qtd->qtd_dma)
== qh->hw_current) { == hw->hw_current) {
token = hc32_to_cpu(ehci, qh->hw_token); token = hc32_to_cpu(ehci, hw->hw_token);
/* An unlink may leave an incomplete /* An unlink may leave an incomplete
* async transaction in the TT buffer. * async transaction in the TT buffer.
@ -449,9 +461,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
* patch the qh later and so that completions can't * patch the qh later and so that completions can't
* activate it while we "know" it's stopped. * activate it while we "know" it's stopped.
*/ */
if ((halt & qh->hw_token) == 0) { if ((halt & hw->hw_token) == 0) {
halt: halt:
qh->hw_token |= halt; hw->hw_token |= halt;
wmb (); wmb ();
} }
} }
@ -503,6 +515,21 @@ halt:
ehci_qtd_free (ehci, last); ehci_qtd_free (ehci, last);
} }
/* Do we need to rescan for URBs dequeued during a giveback? */
if (unlikely(qh->needs_rescan)) {
/* If the QH is already unlinked, do the rescan now. */
if (state == QH_STATE_IDLE)
goto rescan;
/* Otherwise we have to wait until the QH is fully unlinked.
* Our caller will start an unlink if qh->needs_rescan is
* set. But if an unlink has already started, nothing needs
* to be done.
*/
if (state != QH_STATE_LINKED)
qh->needs_rescan = 0;
}
/* restore original state; caller must unlink or relink */ /* restore original state; caller must unlink or relink */
qh->qh_state = state; qh->qh_state = state;
@ -510,7 +537,7 @@ halt:
* it after fault cleanup, or recovering from silicon wrongly * it after fault cleanup, or recovering from silicon wrongly
* overlaying the dummy qtd (which reduces DMA chatter). * overlaying the dummy qtd (which reduces DMA chatter).
*/ */
if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END(ehci)) { if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) {
switch (state) { switch (state) {
case QH_STATE_IDLE: case QH_STATE_IDLE:
qh_refresh(ehci, qh); qh_refresh(ehci, qh);
@ -527,12 +554,9 @@ halt:
* That should be rare for interrupt transfers, * That should be rare for interrupt transfers,
* except maybe high bandwidth ... * except maybe high bandwidth ...
*/ */
if ((cpu_to_hc32(ehci, QH_SMASK)
& qh->hw_info2) != 0) { /* Tell the caller to start an unlink */
intr_deschedule (ehci, qh); qh->needs_rescan = 1;
(void) qh_schedule (ehci, qh);
} else
unlink_async (ehci, qh);
break; break;
/* otherwise, unlink already started */ /* otherwise, unlink already started */
} }
@ -649,7 +673,7 @@ qh_urb_transaction (
* (this will usually be overridden later.) * (this will usually be overridden later.)
*/ */
if (is_input) if (is_input)
qtd->hw_alt_next = ehci->async->hw_alt_next; qtd->hw_alt_next = ehci->async->hw->hw_alt_next;
/* qh makes control packets use qtd toggle; maybe switch it */ /* qh makes control packets use qtd toggle; maybe switch it */
if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0) if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
@ -744,6 +768,7 @@ qh_make (
int is_input, type; int is_input, type;
int maxp = 0; int maxp = 0;
struct usb_tt *tt = urb->dev->tt; struct usb_tt *tt = urb->dev->tt;
struct ehci_qh_hw *hw;
if (!qh) if (!qh)
return qh; return qh;
@ -890,8 +915,9 @@ done:
/* init as live, toggle clear, advance to dummy */ /* init as live, toggle clear, advance to dummy */
qh->qh_state = QH_STATE_IDLE; qh->qh_state = QH_STATE_IDLE;
qh->hw_info1 = cpu_to_hc32(ehci, info1); hw = qh->hw;
qh->hw_info2 = cpu_to_hc32(ehci, info2); hw->hw_info1 = cpu_to_hc32(ehci, info1);
hw->hw_info2 = cpu_to_hc32(ehci, info2);
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
qh_refresh (ehci, qh); qh_refresh (ehci, qh);
return qh; return qh;
@ -910,6 +936,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (unlikely(qh->clearing_tt)) if (unlikely(qh->clearing_tt))
return; return;
WARN_ON(qh->qh_state != QH_STATE_IDLE);
/* (re)start the async schedule? */ /* (re)start the async schedule? */
head = ehci->async; head = ehci->async;
timer_action_done (ehci, TIMER_ASYNC_OFF); timer_action_done (ehci, TIMER_ASYNC_OFF);
@ -928,16 +956,15 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
} }
/* clear halt and/or toggle; and maybe recover from silicon quirk */ /* clear halt and/or toggle; and maybe recover from silicon quirk */
if (qh->qh_state == QH_STATE_IDLE) qh_refresh(ehci, qh);
qh_refresh (ehci, qh);
/* splice right after start */ /* splice right after start */
qh->qh_next = head->qh_next; qh->qh_next = head->qh_next;
qh->hw_next = head->hw_next; qh->hw->hw_next = head->hw->hw_next;
wmb (); wmb ();
head->qh_next.qh = qh; head->qh_next.qh = qh;
head->hw_next = dma; head->hw->hw_next = dma;
qh_get(qh); qh_get(qh);
qh->xacterrs = 0; qh->xacterrs = 0;
@ -984,7 +1011,7 @@ static struct ehci_qh *qh_append_tds (
/* usb_reset_device() briefly reverts to address 0 */ /* usb_reset_device() briefly reverts to address 0 */
if (usb_pipedevice (urb->pipe) == 0) if (usb_pipedevice (urb->pipe) == 0)
qh->hw_info1 &= ~qh_addr_mask; qh->hw->hw_info1 &= ~qh_addr_mask;
} }
/* just one way to queue requests: swap with the dummy qtd. /* just one way to queue requests: swap with the dummy qtd.
@ -1169,7 +1196,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
while (prev->qh_next.qh != qh) while (prev->qh_next.qh != qh)
prev = prev->qh_next.qh; prev = prev->qh_next.qh;
prev->hw_next = qh->hw_next; prev->hw->hw_next = qh->hw->hw_next;
prev->qh_next = qh->qh_next; prev->qh_next = qh->qh_next;
wmb (); wmb ();
@ -1214,6 +1241,8 @@ rescan:
qh = qh_get (qh); qh = qh_get (qh);
qh->stamp = ehci->stamp; qh->stamp = ehci->stamp;
temp = qh_completions (ehci, qh); temp = qh_completions (ehci, qh);
if (qh->needs_rescan)
unlink_async(ehci, qh);
qh_put (qh); qh_put (qh);
if (temp != 0) { if (temp != 0) {
goto rescan; goto rescan;

View File

@ -60,6 +60,20 @@ periodic_next_shadow(struct ehci_hcd *ehci, union ehci_shadow *periodic,
} }
} }
static __hc32 *
shadow_next_periodic(struct ehci_hcd *ehci, union ehci_shadow *periodic,
__hc32 tag)
{
switch (hc32_to_cpu(ehci, tag)) {
/* our ehci_shadow.qh is actually software part */
case Q_TYPE_QH:
return &periodic->qh->hw->hw_next;
/* others are hw parts */
default:
return periodic->hw_next;
}
}
/* caller must hold ehci->lock */ /* caller must hold ehci->lock */
static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr) static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
{ {
@ -71,7 +85,8 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
while (here.ptr && here.ptr != ptr) { while (here.ptr && here.ptr != ptr) {
prev_p = periodic_next_shadow(ehci, prev_p, prev_p = periodic_next_shadow(ehci, prev_p,
Q_NEXT_TYPE(ehci, *hw_p)); Q_NEXT_TYPE(ehci, *hw_p));
hw_p = here.hw_next; hw_p = shadow_next_periodic(ehci, &here,
Q_NEXT_TYPE(ehci, *hw_p));
here = *prev_p; here = *prev_p;
} }
/* an interrupt entry (at list end) could have been shared */ /* an interrupt entry (at list end) could have been shared */
@ -83,7 +98,7 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
*/ */
*prev_p = *periodic_next_shadow(ehci, &here, *prev_p = *periodic_next_shadow(ehci, &here,
Q_NEXT_TYPE(ehci, *hw_p)); Q_NEXT_TYPE(ehci, *hw_p));
*hw_p = *here.hw_next; *hw_p = *shadow_next_periodic(ehci, &here, Q_NEXT_TYPE(ehci, *hw_p));
} }
/* how many of the uframe's 125 usecs are allocated? */ /* how many of the uframe's 125 usecs are allocated? */
@ -93,18 +108,20 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
__hc32 *hw_p = &ehci->periodic [frame]; __hc32 *hw_p = &ehci->periodic [frame];
union ehci_shadow *q = &ehci->pshadow [frame]; union ehci_shadow *q = &ehci->pshadow [frame];
unsigned usecs = 0; unsigned usecs = 0;
struct ehci_qh_hw *hw;
while (q->ptr) { while (q->ptr) {
switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) { switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) {
case Q_TYPE_QH: case Q_TYPE_QH:
hw = q->qh->hw;
/* is it in the S-mask? */ /* is it in the S-mask? */
if (q->qh->hw_info2 & cpu_to_hc32(ehci, 1 << uframe)) if (hw->hw_info2 & cpu_to_hc32(ehci, 1 << uframe))
usecs += q->qh->usecs; usecs += q->qh->usecs;
/* ... or C-mask? */ /* ... or C-mask? */
if (q->qh->hw_info2 & cpu_to_hc32(ehci, if (hw->hw_info2 & cpu_to_hc32(ehci,
1 << (8 + uframe))) 1 << (8 + uframe)))
usecs += q->qh->c_usecs; usecs += q->qh->c_usecs;
hw_p = &q->qh->hw_next; hw_p = &hw->hw_next;
q = &q->qh->qh_next; q = &q->qh->qh_next;
break; break;
// case Q_TYPE_FSTN: // case Q_TYPE_FSTN:
@ -237,10 +254,10 @@ periodic_tt_usecs (
continue; continue;
case Q_TYPE_QH: case Q_TYPE_QH:
if (same_tt(dev, q->qh->dev)) { if (same_tt(dev, q->qh->dev)) {
uf = tt_start_uframe(ehci, q->qh->hw_info2); uf = tt_start_uframe(ehci, q->qh->hw->hw_info2);
tt_usecs[uf] += q->qh->tt_usecs; tt_usecs[uf] += q->qh->tt_usecs;
} }
hw_p = &q->qh->hw_next; hw_p = &q->qh->hw->hw_next;
q = &q->qh->qh_next; q = &q->qh->qh_next;
continue; continue;
case Q_TYPE_SITD: case Q_TYPE_SITD:
@ -375,6 +392,7 @@ static int tt_no_collision (
for (; frame < ehci->periodic_size; frame += period) { for (; frame < ehci->periodic_size; frame += period) {
union ehci_shadow here; union ehci_shadow here;
__hc32 type; __hc32 type;
struct ehci_qh_hw *hw;
here = ehci->pshadow [frame]; here = ehci->pshadow [frame];
type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]); type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]);
@ -385,17 +403,18 @@ static int tt_no_collision (
here = here.itd->itd_next; here = here.itd->itd_next;
continue; continue;
case Q_TYPE_QH: case Q_TYPE_QH:
hw = here.qh->hw;
if (same_tt (dev, here.qh->dev)) { if (same_tt (dev, here.qh->dev)) {
u32 mask; u32 mask;
mask = hc32_to_cpu(ehci, mask = hc32_to_cpu(ehci,
here.qh->hw_info2); hw->hw_info2);
/* "knows" no gap is needed */ /* "knows" no gap is needed */
mask |= mask >> 8; mask |= mask >> 8;
if (mask & uf_mask) if (mask & uf_mask)
break; break;
} }
type = Q_NEXT_TYPE(ehci, here.qh->hw_next); type = Q_NEXT_TYPE(ehci, hw->hw_next);
here = here.qh->qh_next; here = here.qh->qh_next;
continue; continue;
case Q_TYPE_SITD: case Q_TYPE_SITD:
@ -498,7 +517,8 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
dev_dbg (&qh->dev->dev, dev_dbg (&qh->dev->dev,
"link qh%d-%04x/%p start %d [%d/%d us]\n", "link qh%d-%04x/%p start %d [%d/%d us]\n",
period, hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK), period, hc32_to_cpup(ehci, &qh->hw->hw_info2)
& (QH_CMASK | QH_SMASK),
qh, qh->start, qh->usecs, qh->c_usecs); qh, qh->start, qh->usecs, qh->c_usecs);
/* high bandwidth, or otherwise every microframe */ /* high bandwidth, or otherwise every microframe */
@ -517,7 +537,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (type == cpu_to_hc32(ehci, Q_TYPE_QH)) if (type == cpu_to_hc32(ehci, Q_TYPE_QH))
break; break;
prev = periodic_next_shadow(ehci, prev, type); prev = periodic_next_shadow(ehci, prev, type);
hw_p = &here.qh->hw_next; hw_p = shadow_next_periodic(ehci, &here, type);
here = *prev; here = *prev;
} }
@ -528,14 +548,14 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (qh->period > here.qh->period) if (qh->period > here.qh->period)
break; break;
prev = &here.qh->qh_next; prev = &here.qh->qh_next;
hw_p = &here.qh->hw_next; hw_p = &here.qh->hw->hw_next;
here = *prev; here = *prev;
} }
/* link in this qh, unless some earlier pass did that */ /* link in this qh, unless some earlier pass did that */
if (qh != here.qh) { if (qh != here.qh) {
qh->qh_next = here; qh->qh_next = here;
if (here.qh) if (here.qh)
qh->hw_next = *hw_p; qh->hw->hw_next = *hw_p;
wmb (); wmb ();
prev->qh = qh; prev->qh = qh;
*hw_p = QH_NEXT (ehci, qh->qh_dma); *hw_p = QH_NEXT (ehci, qh->qh_dma);
@ -581,7 +601,7 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
dev_dbg (&qh->dev->dev, dev_dbg (&qh->dev->dev,
"unlink qh%d-%04x/%p start %d [%d/%d us]\n", "unlink qh%d-%04x/%p start %d [%d/%d us]\n",
qh->period, qh->period,
hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK), hc32_to_cpup(ehci, &qh->hw->hw_info2) & (QH_CMASK | QH_SMASK),
qh, qh->start, qh->usecs, qh->c_usecs); qh, qh->start, qh->usecs, qh->c_usecs);
/* qh->qh_next still "live" to HC */ /* qh->qh_next still "live" to HC */
@ -595,7 +615,19 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
{ {
unsigned wait; unsigned wait;
struct ehci_qh_hw *hw = qh->hw;
int rc;
/* If the QH isn't linked then there's nothing we can do
* unless we were called during a giveback, in which case
* qh_completions() has to deal with it.
*/
if (qh->qh_state != QH_STATE_LINKED) {
if (qh->qh_state == QH_STATE_COMPLETING)
qh->needs_rescan = 1;
return;
}
qh_unlink_periodic (ehci, qh); qh_unlink_periodic (ehci, qh);
@ -606,15 +638,33 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
*/ */
if (list_empty (&qh->qtd_list) if (list_empty (&qh->qtd_list)
|| (cpu_to_hc32(ehci, QH_CMASK) || (cpu_to_hc32(ehci, QH_CMASK)
& qh->hw_info2) != 0) & hw->hw_info2) != 0)
wait = 2; wait = 2;
else else
wait = 55; /* worst case: 3 * 1024 */ wait = 55; /* worst case: 3 * 1024 */
udelay (wait); udelay (wait);
qh->qh_state = QH_STATE_IDLE; qh->qh_state = QH_STATE_IDLE;
qh->hw_next = EHCI_LIST_END(ehci); hw->hw_next = EHCI_LIST_END(ehci);
wmb (); wmb ();
qh_completions(ehci, qh);
/* reschedule QH iff another request is queued */
if (!list_empty(&qh->qtd_list) &&
HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
rc = qh_schedule(ehci, qh);
/* An error here likely indicates handshake failure
* or no space left in the schedule. Neither fault
* should happen often ...
*
* FIXME kill the now-dysfunctional queued urbs
*/
if (rc != 0)
ehci_err(ehci, "can't reschedule qh %p, err %d\n",
qh, rc);
}
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@ -739,14 +789,15 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
unsigned uframe; unsigned uframe;
__hc32 c_mask; __hc32 c_mask;
unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */ unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
struct ehci_qh_hw *hw = qh->hw;
qh_refresh(ehci, qh); qh_refresh(ehci, qh);
qh->hw_next = EHCI_LIST_END(ehci); hw->hw_next = EHCI_LIST_END(ehci);
frame = qh->start; frame = qh->start;
/* reuse the previous schedule slots, if we can */ /* reuse the previous schedule slots, if we can */
if (frame < qh->period) { if (frame < qh->period) {
uframe = ffs(hc32_to_cpup(ehci, &qh->hw_info2) & QH_SMASK); uframe = ffs(hc32_to_cpup(ehci, &hw->hw_info2) & QH_SMASK);
status = check_intr_schedule (ehci, frame, --uframe, status = check_intr_schedule (ehci, frame, --uframe,
qh, &c_mask); qh, &c_mask);
} else { } else {
@ -784,11 +835,11 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->start = frame; qh->start = frame;
/* reset S-frame and (maybe) C-frame masks */ /* reset S-frame and (maybe) C-frame masks */
qh->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK)); hw->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK));
qh->hw_info2 |= qh->period hw->hw_info2 |= qh->period
? cpu_to_hc32(ehci, 1 << uframe) ? cpu_to_hc32(ehci, 1 << uframe)
: cpu_to_hc32(ehci, QH_SMASK); : cpu_to_hc32(ehci, QH_SMASK);
qh->hw_info2 |= c_mask; hw->hw_info2 |= c_mask;
} else } else
ehci_dbg (ehci, "reused qh %p schedule\n", qh); ehci_dbg (ehci, "reused qh %p schedule\n", qh);
@ -2188,10 +2239,11 @@ restart:
case Q_TYPE_QH: case Q_TYPE_QH:
/* handle any completions */ /* handle any completions */
temp.qh = qh_get (q.qh); temp.qh = qh_get (q.qh);
type = Q_NEXT_TYPE(ehci, q.qh->hw_next); type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
q = q.qh->qh_next; q = q.qh->qh_next;
modified = qh_completions (ehci, temp.qh); modified = qh_completions (ehci, temp.qh);
if (unlikely (list_empty (&temp.qh->qtd_list))) if (unlikely(list_empty(&temp.qh->qtd_list) ||
temp.qh->needs_rescan))
intr_deschedule (ehci, temp.qh); intr_deschedule (ehci, temp.qh);
qh_put (temp.qh); qh_put (temp.qh);
break; break;

View File

@ -0,0 +1,181 @@
/*
* linux/driver/usb/host/ehci-w90x900.c
*
* Copyright (c) 2008 Nuvoton technology corporation.
*
* Wan ZongShun <mcuos.com@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation;version 2 of the License.
*
*/
#include <linux/platform_device.h>
/*ebable phy0 and phy1 for w90p910*/
#define ENPHY (0x01<<8)
#define PHY0_CTR (0xA4)
#define PHY1_CTR (0xA8)
static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
struct platform_device *pdev)
{
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
struct resource *res;
int retval = 0, irq;
unsigned long val;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
retval = -ENXIO;
goto err1;
}
hcd = usb_create_hcd(driver, &pdev->dev, "w90x900 EHCI");
if (!hcd) {
retval = -ENOMEM;
goto err1;
}
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)) {
retval = -EBUSY;
goto err2;
}
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
if (hcd->regs == NULL) {
retval = -EFAULT;
goto err3;
}
ehci = hcd_to_ehci(hcd);
ehci->caps = hcd->regs;
ehci->regs = hcd->regs +
HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
/* enable PHY 0,1,the regs only apply to w90p910
* 0xA4,0xA8 were offsets of PHY0 and PHY1 controller of
* w90p910 IC relative to ehci->regs.
*/
val = __raw_readl(ehci->regs+PHY0_CTR);
val |= ENPHY;
__raw_writel(val, ehci->regs+PHY0_CTR);
val = __raw_readl(ehci->regs+PHY1_CTR);
val |= ENPHY;
__raw_writel(val, ehci->regs+PHY1_CTR);
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
ehci->sbrn = 0x20;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
goto err4;
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval != 0)
goto err4;
ehci_writel(ehci, 1, &ehci->regs->configured_flag);
return retval;
err4:
iounmap(hcd->regs);
err3:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err2:
usb_put_hcd(hcd);
err1:
return retval;
}
static
void usb_w90x900_remove(struct usb_hcd *hcd, struct platform_device *pdev)
{
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
}
static const struct hc_driver ehci_w90x900_hc_driver = {
.description = hcd_name,
.product_desc = "Nuvoton w90x900 EHCI Host Controller",
.hcd_priv_size = sizeof(struct ehci_hcd),
/*
* generic hardware linkage
*/
.irq = ehci_irq,
.flags = HCD_USB2|HCD_MEMORY,
/*
* basic lifecycle operations
*/
.reset = ehci_init,
.start = ehci_run,
.stop = ehci_stop,
.shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
/*
* scheduling support
*/
.get_frame_number = ehci_get_frame,
/*
* root hub support
*/
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,
#ifdef CONFIG_PM
.bus_suspend = ehci_bus_suspend,
.bus_resume = ehci_bus_resume,
#endif
.relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over,
};
static int __devinit ehci_w90x900_probe(struct platform_device *pdev)
{
if (usb_disabled())
return -ENODEV;
return usb_w90x900_probe(&ehci_w90x900_hc_driver, pdev);
}
static int __devexit ehci_w90x900_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_w90x900_remove(hcd, pdev);
return 0;
}
static struct platform_driver ehci_hcd_w90x900_driver = {
.probe = ehci_w90x900_probe,
.remove = __devexit_p(ehci_w90x900_remove),
.driver = {
.name = "w90x900-ehci",
.owner = THIS_MODULE,
},
};
MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
MODULE_DESCRIPTION("w90p910 usb ehci driver!");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:w90p910-ehci");

View File

@ -126,6 +126,7 @@ struct ehci_hcd { /* one per controller */
unsigned big_endian_mmio:1; unsigned big_endian_mmio:1;
unsigned big_endian_desc:1; unsigned big_endian_desc:1;
unsigned has_amcc_usb23:1; unsigned has_amcc_usb23:1;
unsigned need_io_watchdog:1;
/* required for usb32 quirk */ /* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6) #define OHCI_CTRL_HCFS (3 << 6)
@ -135,6 +136,7 @@ struct ehci_hcd { /* one per controller */
#define OHCI_HCCTRL_OFFSET 0x4 #define OHCI_HCCTRL_OFFSET 0x4
#define OHCI_HCCTRL_LEN 0x4 #define OHCI_HCCTRL_LEN 0x4
__hc32 *ohci_hcctrl_reg; __hc32 *ohci_hcctrl_reg;
unsigned has_hostpc:1;
u8 sbrn; /* packed release number */ u8 sbrn; /* packed release number */
@ -298,8 +300,8 @@ union ehci_shadow {
* These appear in both the async and (for interrupt) periodic schedules. * These appear in both the async and (for interrupt) periodic schedules.
*/ */
struct ehci_qh { /* first part defined by EHCI spec */
/* first part defined by EHCI spec */ struct ehci_qh_hw {
__hc32 hw_next; /* see EHCI 3.6.1 */ __hc32 hw_next; /* see EHCI 3.6.1 */
__hc32 hw_info1; /* see EHCI 3.6.2 */ __hc32 hw_info1; /* see EHCI 3.6.2 */
#define QH_HEAD 0x00008000 #define QH_HEAD 0x00008000
@ -317,7 +319,10 @@ struct ehci_qh {
__hc32 hw_token; __hc32 hw_token;
__hc32 hw_buf [5]; __hc32 hw_buf [5];
__hc32 hw_buf_hi [5]; __hc32 hw_buf_hi [5];
} __attribute__ ((aligned(32)));
struct ehci_qh {
struct ehci_qh_hw *hw;
/* the rest is HCD-private */ /* the rest is HCD-private */
dma_addr_t qh_dma; /* address of qh */ dma_addr_t qh_dma; /* address of qh */
union ehci_shadow qh_next; /* ptr to qh; or periodic */ union ehci_shadow qh_next; /* ptr to qh; or periodic */
@ -336,6 +341,7 @@ struct ehci_qh {
u32 refcount; u32 refcount;
unsigned stamp; unsigned stamp;
u8 needs_rescan; /* Dequeue during giveback */
u8 qh_state; u8 qh_state;
#define QH_STATE_LINKED 1 /* HC sees this */ #define QH_STATE_LINKED 1 /* HC sees this */
#define QH_STATE_UNLINK 2 /* HC may still see this */ #define QH_STATE_UNLINK 2 /* HC may still see this */
@ -357,7 +363,7 @@ struct ehci_qh {
struct usb_device *dev; /* access to TT */ struct usb_device *dev; /* access to TT */
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
} __attribute__ ((aligned (32))); };
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
@ -544,7 +550,7 @@ static inline unsigned int
ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc) ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
{ {
if (ehci_is_TDI(ehci)) { if (ehci_is_TDI(ehci)) {
switch ((portsc>>26)&3) { switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) {
case 0: case 0:
return 0; return 0;
case 1: case 1:

File diff suppressed because it is too large Load Diff

1079
drivers/usb/host/isp1362.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -386,6 +386,10 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
hwmode |= HW_DACK_POL_HIGH; hwmode |= HW_DACK_POL_HIGH;
if (priv->devflags & ISP1760_FLAG_DREQ_POL_HIGH) if (priv->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
hwmode |= HW_DREQ_POL_HIGH; hwmode |= HW_DREQ_POL_HIGH;
if (priv->devflags & ISP1760_FLAG_INTR_POL_HIGH)
hwmode |= HW_INTR_HIGH_ACT;
if (priv->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
hwmode |= HW_INTR_EDGE_TRIG;
/* /*
* We have to set this first in case we're in 16-bit mode. * We have to set this first in case we're in 16-bit mode.

View File

@ -142,6 +142,8 @@ typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
#define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */ #define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */
#define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */ #define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */
#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */ #define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
/* chip memory management */ /* chip memory management */
struct memory_chunk { struct memory_chunk {

View File

@ -3,6 +3,7 @@
* Currently there is support for * Currently there is support for
* - OpenFirmware * - OpenFirmware
* - PCI * - PCI
* - PDEV (generic platform device centralized driver model)
* *
* (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
* *
@ -11,6 +12,7 @@
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/usb/isp1760.h>
#include "../core/hcd.h" #include "../core/hcd.h"
#include "isp1760-hcd.h" #include "isp1760-hcd.h"
@ -308,6 +310,8 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev)
struct resource *mem_res; struct resource *mem_res;
struct resource *irq_res; struct resource *irq_res;
resource_size_t mem_size; resource_size_t mem_size;
struct isp1760_platform_data *priv = pdev->dev.platform_data;
unsigned int devflags = 0;
unsigned long irqflags = IRQF_SHARED | IRQF_DISABLED; unsigned long irqflags = IRQF_SHARED | IRQF_DISABLED;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -330,8 +334,23 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev)
} }
irqflags |= irq_res->flags & IRQF_TRIGGER_MASK; irqflags |= irq_res->flags & IRQF_TRIGGER_MASK;
if (priv) {
if (priv->is_isp1761)
devflags |= ISP1760_FLAG_ISP1761;
if (priv->bus_width_16)
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
if (priv->port1_otg)
devflags |= ISP1760_FLAG_OTG_EN;
if (priv->analog_oc)
devflags |= ISP1760_FLAG_ANALOG_OC;
if (priv->dack_polarity_high)
devflags |= ISP1760_FLAG_DACK_POL_HIGH;
if (priv->dreq_polarity_high)
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
}
hcd = isp1760_register(mem_res->start, mem_size, irq_res->start, hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
irqflags, &pdev->dev, dev_name(&pdev->dev), 0); irqflags, &pdev->dev, dev_name(&pdev->dev), devflags);
if (IS_ERR(hcd)) { if (IS_ERR(hcd)) {
pr_warning("isp1760: Failed to register the HCD device\n"); pr_warning("isp1760: Failed to register the HCD device\n");
ret = -ENODEV; ret = -ENODEV;

View File

@ -148,7 +148,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
at91_start_hc(pdev); at91_start_hc(pdev);
ohci_hcd_init(hcd_to_ohci(hcd)); ohci_hcd_init(hcd_to_ohci(hcd));
retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED); retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_SHARED);
if (retval == 0) if (retval == 0)
return retval; return retval;

View File

@ -248,10 +248,9 @@ static int ohci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int ohci_hcd_au1xxx_drv_suspend(struct platform_device *pdev, static int ohci_hcd_au1xxx_drv_suspend(struct device *dev)
pm_message_t message)
{ {
struct usb_hcd *hcd = platform_get_drvdata(pdev); struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct ohci_hcd *ohci = hcd_to_ohci(hcd);
unsigned long flags; unsigned long flags;
int rc; int rc;
@ -274,10 +273,6 @@ static int ohci_hcd_au1xxx_drv_suspend(struct platform_device *pdev,
ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
(void)ohci_readl(ohci, &ohci->regs->intrdisable); (void)ohci_readl(ohci, &ohci->regs->intrdisable);
/* make sure snapshot being resumed re-enumerates everything */
if (message.event == PM_EVENT_PRETHAW)
ohci_usb_reset(ohci);
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
au1xxx_stop_ohc(); au1xxx_stop_ohc();
@ -287,9 +282,9 @@ bail:
return rc; return rc;
} }
static int ohci_hcd_au1xxx_drv_resume(struct platform_device *pdev) static int ohci_hcd_au1xxx_drv_resume(struct device *dev)
{ {
struct usb_hcd *hcd = platform_get_drvdata(pdev); struct usb_hcd *hcd = dev_get_drvdata(dev);
au1xxx_start_ohc(); au1xxx_start_ohc();
@ -298,20 +293,26 @@ static int ohci_hcd_au1xxx_drv_resume(struct platform_device *pdev)
return 0; return 0;
} }
static struct dev_pm_ops au1xxx_ohci_pmops = {
.suspend = ohci_hcd_au1xxx_drv_suspend,
.resume = ohci_hcd_au1xxx_drv_resume,
};
#define AU1XXX_OHCI_PMOPS &au1xxx_ohci_pmops
#else #else
#define ohci_hcd_au1xxx_drv_suspend NULL #define AU1XXX_OHCI_PMOPS NULL
#define ohci_hcd_au1xxx_drv_resume NULL
#endif #endif
static struct platform_driver ohci_hcd_au1xxx_driver = { static struct platform_driver ohci_hcd_au1xxx_driver = {
.probe = ohci_hcd_au1xxx_drv_probe, .probe = ohci_hcd_au1xxx_drv_probe,
.remove = ohci_hcd_au1xxx_drv_remove, .remove = ohci_hcd_au1xxx_drv_remove,
.shutdown = usb_hcd_platform_shutdown, .shutdown = usb_hcd_platform_shutdown,
.suspend = ohci_hcd_au1xxx_drv_suspend,
.resume = ohci_hcd_au1xxx_drv_resume,
.driver = { .driver = {
.name = "au1xxx-ohci", .name = "au1xxx-ohci",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = AU1XXX_OHCI_PMOPS,
}, },
}; };

View File

@ -188,7 +188,6 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev)
{ {
struct usb_hcd *hcd = platform_get_drvdata(pdev); struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd); struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int status;
if (time_before(jiffies, ohci->next_statechange)) if (time_before(jiffies, ohci->next_statechange))
msleep(5); msleep(5);

View File

@ -34,7 +34,6 @@
#include <linux/usb/otg.h> #include <linux/usb/otg.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/dmapool.h> #include <linux/dmapool.h>
#include <linux/reboot.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/debugfs.h> #include <linux/debugfs.h>

View File

@ -177,9 +177,13 @@ static inline void pxa27x_setup_hc(struct pxa27x_ohci *ohci,
if (inf->flags & NO_OC_PROTECTION) if (inf->flags & NO_OC_PROTECTION)
uhcrhda |= UHCRHDA_NOCP; uhcrhda |= UHCRHDA_NOCP;
else
uhcrhda &= ~UHCRHDA_NOCP;
if (inf->flags & OC_MODE_PERPORT) if (inf->flags & OC_MODE_PERPORT)
uhcrhda |= UHCRHDA_OCPM; uhcrhda |= UHCRHDA_OCPM;
else
uhcrhda &= ~UHCRHDA_OCPM;
if (inf->power_on_delay) { if (inf->power_on_delay) {
uhcrhda &= ~UHCRHDA_POTPGT(0xff); uhcrhda &= ~UHCRHDA_POTPGT(0xff);

View File

@ -33,7 +33,6 @@
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>

View File

@ -475,4 +475,4 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI) else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI)
quirk_usb_handoff_xhci(pdev); quirk_usb_handoff_xhci(pdev);
} }
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff); DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);

View File

@ -719,8 +719,12 @@ retry:
/* port status seems weird until after reset, so /* port status seems weird until after reset, so
* force the reset and make khubd clean up later. * force the reset and make khubd clean up later.
*/ */
sl811->port1 |= (1 << USB_PORT_FEAT_C_CONNECTION) if (sl811->stat_insrmv & 1)
| (1 << USB_PORT_FEAT_CONNECTION); sl811->port1 |= 1 << USB_PORT_FEAT_CONNECTION;
else
sl811->port1 &= ~(1 << USB_PORT_FEAT_CONNECTION);
sl811->port1 |= 1 << USB_PORT_FEAT_C_CONNECTION;
} else if (irqstat & SL11H_INTMASK_RD) { } else if (irqstat & SL11H_INTMASK_RD) {
if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)) { if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)) {

View File

@ -1422,7 +1422,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
goto err_submit_failed; goto err_submit_failed;
/* Add this URB to the QH */ /* Add this URB to the QH */
urbp->qh = qh;
list_add_tail(&urbp->node, &qh->queue); list_add_tail(&urbp->node, &qh->queue);
/* If the new URB is the first and only one on this QH then either /* If the new URB is the first and only one on this QH then either

View File

@ -227,11 +227,21 @@ void scan_async_work(struct work_struct *work)
/* /*
* Now that the ASL is updated, complete the removal of any * Now that the ASL is updated, complete the removal of any
* removed qsets. * removed qsets.
*
* If the qset was to be reset, do so and reinsert it into the
* ASL if it has pending transfers.
*/ */
spin_lock_irq(&whc->lock); spin_lock_irq(&whc->lock);
list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) { list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) {
qset_remove_complete(whc, qset); qset_remove_complete(whc, qset);
if (qset->reset) {
qset_reset(whc, qset);
if (!list_empty(&qset->stds)) {
asl_qset_insert_begin(whc, qset);
queue_work(whc->workqueue, &whc->async_work);
}
}
} }
spin_unlock_irq(&whc->lock); spin_unlock_irq(&whc->lock);
@ -267,7 +277,7 @@ int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
else else
err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
if (!err) { if (!err) {
if (!qset->in_sw_list) if (!qset->in_sw_list && !qset->remove)
asl_qset_insert_begin(whc, qset); asl_qset_insert_begin(whc, qset);
} else } else
usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);

View File

@ -192,19 +192,23 @@ static void whc_endpoint_reset(struct usb_hcd *usb_hcd,
struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
struct whc *whc = wusbhc_to_whc(wusbhc); struct whc *whc = wusbhc_to_whc(wusbhc);
struct whc_qset *qset; struct whc_qset *qset;
unsigned long flags;
spin_lock_irqsave(&whc->lock, flags);
qset = ep->hcpriv; qset = ep->hcpriv;
if (qset) { if (qset) {
qset->remove = 1; qset->remove = 1;
qset->reset = 1;
if (usb_endpoint_xfer_bulk(&ep->desc) if (usb_endpoint_xfer_bulk(&ep->desc)
|| usb_endpoint_xfer_control(&ep->desc)) || usb_endpoint_xfer_control(&ep->desc))
queue_work(whc->workqueue, &whc->async_work); queue_work(whc->workqueue, &whc->async_work);
else else
queue_work(whc->workqueue, &whc->periodic_work); queue_work(whc->workqueue, &whc->periodic_work);
qset_reset(whc, qset);
} }
spin_unlock_irqrestore(&whc->lock, flags);
} }

View File

@ -255,11 +255,21 @@ void scan_periodic_work(struct work_struct *work)
/* /*
* Now that the PZL is updated, complete the removal of any * Now that the PZL is updated, complete the removal of any
* removed qsets. * removed qsets.
*
* If the qset was to be reset, do so and reinsert it into the
* PZL if it has pending transfers.
*/ */
spin_lock_irq(&whc->lock); spin_lock_irq(&whc->lock);
list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) { list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) {
qset_remove_complete(whc, qset); qset_remove_complete(whc, qset);
if (qset->reset) {
qset_reset(whc, qset);
if (!list_empty(&qset->stds)) {
qset_insert_in_sw_list(whc, qset);
queue_work(whc->workqueue, &whc->periodic_work);
}
}
} }
spin_unlock_irq(&whc->lock); spin_unlock_irq(&whc->lock);
@ -295,7 +305,7 @@ int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags)
else else
err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); err = qset_add_urb(whc, qset, urb, GFP_ATOMIC);
if (!err) { if (!err) {
if (!qset->in_sw_list) if (!qset->in_sw_list && !qset->remove)
qset_insert_in_sw_list(whc, qset); qset_insert_in_sw_list(whc, qset);
} else } else
usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb);

View File

@ -103,7 +103,6 @@ static void qset_fill_qh(struct whc_qset *qset, struct urb *urb)
void qset_clear(struct whc *whc, struct whc_qset *qset) void qset_clear(struct whc *whc, struct whc_qset *qset)
{ {
qset->td_start = qset->td_end = qset->ntds = 0; qset->td_start = qset->td_end = qset->ntds = 0;
qset->remove = 0;
qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T);
qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK; qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK;
@ -125,7 +124,7 @@ void qset_clear(struct whc *whc, struct whc_qset *qset)
*/ */
void qset_reset(struct whc *whc, struct whc_qset *qset) void qset_reset(struct whc *whc, struct whc_qset *qset)
{ {
wait_for_completion(&qset->remove_complete); qset->reset = 0;
qset->qh.status &= ~QH_STATUS_SEQ_MASK; qset->qh.status &= ~QH_STATUS_SEQ_MASK;
qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1);
@ -156,6 +155,7 @@ struct whc_qset *get_qset(struct whc *whc, struct urb *urb,
void qset_remove_complete(struct whc *whc, struct whc_qset *qset) void qset_remove_complete(struct whc *whc, struct whc_qset *qset)
{ {
qset->remove = 0;
list_del_init(&qset->list_node); list_del_init(&qset->list_node);
complete(&qset->remove_complete); complete(&qset->remove_complete);
} }

View File

@ -264,6 +264,7 @@ struct whc_qset {
unsigned in_sw_list:1; unsigned in_sw_list:1;
unsigned in_hw_list:1; unsigned in_hw_list:1;
unsigned remove:1; unsigned remove:1;
unsigned reset:1;
struct urb *pause_after_urb; struct urb *pause_after_urb;
struct completion remove_complete; struct completion remove_complete;
int max_burst; int max_burst;

View File

@ -413,7 +413,8 @@ void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
int i; int i;
struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx); struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
dma_addr_t dma = ctx->dma + ((unsigned long)slot_ctx - (unsigned long)ctx); dma_addr_t dma = ctx->dma +
((unsigned long)slot_ctx - (unsigned long)ctx->bytes);
int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params); int csz = HCC_64BYTE_CONTEXT(xhci->hcc_params);
xhci_dbg(xhci, "Slot Context:\n"); xhci_dbg(xhci, "Slot Context:\n");
@ -459,7 +460,7 @@ void xhci_dbg_ep_ctx(struct xhci_hcd *xhci,
for (i = 0; i < last_ep_ctx; ++i) { for (i = 0; i < last_ep_ctx; ++i) {
struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i); struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i);
dma_addr_t dma = ctx->dma + dma_addr_t dma = ctx->dma +
((unsigned long)ep_ctx - (unsigned long)ctx); ((unsigned long)ep_ctx - (unsigned long)ctx->bytes);
xhci_dbg(xhci, "Endpoint %02d Context:\n", i); xhci_dbg(xhci, "Endpoint %02d Context:\n", i);
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n", xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n",

View File

@ -22,12 +22,18 @@
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h>
#include "xhci.h" #include "xhci.h"
#define DRIVER_AUTHOR "Sarah Sharp" #define DRIVER_AUTHOR "Sarah Sharp"
#define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver" #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver"
/* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */
static int link_quirk;
module_param(link_quirk, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(link_quirk, "Don't clear the chain bit on a link TRB");
/* TODO: copied from ehci-hcd.c - can this be refactored? */ /* TODO: copied from ehci-hcd.c - can this be refactored? */
/* /*
* handshake - spin reading hc until handshake completes or fails * handshake - spin reading hc until handshake completes or fails
@ -214,6 +220,12 @@ int xhci_init(struct usb_hcd *hcd)
xhci_dbg(xhci, "xhci_init\n"); xhci_dbg(xhci, "xhci_init\n");
spin_lock_init(&xhci->lock); spin_lock_init(&xhci->lock);
if (link_quirk) {
xhci_dbg(xhci, "QUIRK: Not clearing Link TRB chain bits.\n");
xhci->quirks |= XHCI_LINK_TRB_QUIRK;
} else {
xhci_dbg(xhci, "xHCI doesn't need link TRB QUIRK\n");
}
retval = xhci_mem_init(xhci, GFP_KERNEL); retval = xhci_mem_init(xhci, GFP_KERNEL);
xhci_dbg(xhci, "Finished xhci_init\n"); xhci_dbg(xhci, "Finished xhci_init\n");
@ -339,13 +351,14 @@ void xhci_event_ring_work(unsigned long arg)
xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring); xhci_dbg_ring_ptrs(xhci, xhci->cmd_ring);
xhci_dbg_cmd_ptrs(xhci); xhci_dbg_cmd_ptrs(xhci);
for (i = 0; i < MAX_HC_SLOTS; ++i) { for (i = 0; i < MAX_HC_SLOTS; ++i) {
if (xhci->devs[i]) { if (!xhci->devs[i])
for (j = 0; j < 31; ++j) { continue;
if (xhci->devs[i]->ep_rings[j]) { for (j = 0; j < 31; ++j) {
xhci_dbg(xhci, "Dev %d endpoint ring %d:\n", i, j); struct xhci_ring *ring = xhci->devs[i]->eps[j].ring;
xhci_debug_segment(xhci, xhci->devs[i]->ep_rings[j]->deq_seg); if (!ring)
} continue;
} xhci_dbg(xhci, "Dev %d endpoint ring %d:\n", i, j);
xhci_debug_segment(xhci, ring->deq_seg);
} }
} }
@ -555,13 +568,22 @@ unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc)
return 1 << (xhci_get_endpoint_index(desc) + 1); return 1 << (xhci_get_endpoint_index(desc) + 1);
} }
/* Find the flag for this endpoint (for use in the control context). Use the
* endpoint index to create a bitmask. The slot context is bit 0, endpoint 0 is
* bit 1, etc.
*/
unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index)
{
return 1 << (ep_index + 1);
}
/* Compute the last valid endpoint context index. Basically, this is the /* Compute the last valid endpoint context index. Basically, this is the
* endpoint index plus one. For slot contexts with more than valid endpoint, * endpoint index plus one. For slot contexts with more than valid endpoint,
* we find the most significant bit set in the added contexts flags. * we find the most significant bit set in the added contexts flags.
* e.g. ep 1 IN (with epnum 0x81) => added_ctxs = 0b1000 * e.g. ep 1 IN (with epnum 0x81) => added_ctxs = 0b1000
* fls(0b1000) = 4, but the endpoint context index is 3, so subtract one. * fls(0b1000) = 4, but the endpoint context index is 3, so subtract one.
*/ */
static inline unsigned int xhci_last_valid_endpoint(u32 added_ctxs) unsigned int xhci_last_valid_endpoint(u32 added_ctxs)
{ {
return fls(added_ctxs) - 1; return fls(added_ctxs) - 1;
} }
@ -589,6 +611,71 @@ int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
return 1; return 1;
} }
static int xhci_configure_endpoint(struct xhci_hcd *xhci,
struct usb_device *udev, struct xhci_command *command,
bool ctx_change, bool must_succeed);
/*
* Full speed devices may have a max packet size greater than 8 bytes, but the
* USB core doesn't know that until it reads the first 8 bytes of the
* descriptor. If the usb_device's max packet size changes after that point,
* we need to issue an evaluate context command and wait on it.
*/
static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
unsigned int ep_index, struct urb *urb)
{
struct xhci_container_ctx *in_ctx;
struct xhci_container_ctx *out_ctx;
struct xhci_input_control_ctx *ctrl_ctx;
struct xhci_ep_ctx *ep_ctx;
int max_packet_size;
int hw_max_packet_size;
int ret = 0;
out_ctx = xhci->devs[slot_id]->out_ctx;
ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
hw_max_packet_size = MAX_PACKET_DECODED(ep_ctx->ep_info2);
max_packet_size = urb->dev->ep0.desc.wMaxPacketSize;
if (hw_max_packet_size != max_packet_size) {
xhci_dbg(xhci, "Max Packet Size for ep 0 changed.\n");
xhci_dbg(xhci, "Max packet size in usb_device = %d\n",
max_packet_size);
xhci_dbg(xhci, "Max packet size in xHCI HW = %d\n",
hw_max_packet_size);
xhci_dbg(xhci, "Issuing evaluate context command.\n");
/* Set up the modified control endpoint 0 */
xhci_endpoint_copy(xhci, xhci->devs[slot_id]->in_ctx,
xhci->devs[slot_id]->out_ctx, ep_index);
in_ctx = xhci->devs[slot_id]->in_ctx;
ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index);
ep_ctx->ep_info2 &= ~MAX_PACKET_MASK;
ep_ctx->ep_info2 |= MAX_PACKET(max_packet_size);
/* Set up the input context flags for the command */
/* FIXME: This won't work if a non-default control endpoint
* changes max packet sizes.
*/
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
ctrl_ctx->add_flags = EP0_FLAG;
ctrl_ctx->drop_flags = 0;
xhci_dbg(xhci, "Slot %d input context\n", slot_id);
xhci_dbg_ctx(xhci, in_ctx, ep_index);
xhci_dbg(xhci, "Slot %d output context\n", slot_id);
xhci_dbg_ctx(xhci, out_ctx, ep_index);
ret = xhci_configure_endpoint(xhci, urb->dev, NULL,
true, false);
/* Clean up the input context for later use by bandwidth
* functions.
*/
ctrl_ctx->add_flags = SLOT_FLAG;
}
return ret;
}
/* /*
* non-error returns are a promise to giveback() the urb later * non-error returns are a promise to giveback() the urb later
* we drop ownership so next owner (or urb unlink) can get it * we drop ownership so next owner (or urb unlink) can get it
@ -600,13 +687,13 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
int ret = 0; int ret = 0;
unsigned int slot_id, ep_index; unsigned int slot_id, ep_index;
if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0) if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0)
return -EINVAL; return -EINVAL;
slot_id = urb->dev->slot_id; slot_id = urb->dev->slot_id;
ep_index = xhci_get_endpoint_index(&urb->ep->desc); ep_index = xhci_get_endpoint_index(&urb->ep->desc);
spin_lock_irqsave(&xhci->lock, flags);
if (!xhci->devs || !xhci->devs[slot_id]) { if (!xhci->devs || !xhci->devs[slot_id]) {
if (!in_interrupt()) if (!in_interrupt())
dev_warn(&urb->dev->dev, "WARN: urb submitted for dev with no Slot ID\n"); dev_warn(&urb->dev->dev, "WARN: urb submitted for dev with no Slot ID\n");
@ -619,19 +706,38 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
ret = -ESHUTDOWN; ret = -ESHUTDOWN;
goto exit; goto exit;
} }
if (usb_endpoint_xfer_control(&urb->ep->desc)) if (usb_endpoint_xfer_control(&urb->ep->desc)) {
/* Check to see if the max packet size for the default control
* endpoint changed during FS device enumeration
*/
if (urb->dev->speed == USB_SPEED_FULL) {
ret = xhci_check_maxpacket(xhci, slot_id,
ep_index, urb);
if (ret < 0)
return ret;
}
/* We have a spinlock and interrupts disabled, so we must pass /* We have a spinlock and interrupts disabled, so we must pass
* atomic context to this function, which may allocate memory. * atomic context to this function, which may allocate memory.
*/ */
spin_lock_irqsave(&xhci->lock, flags);
ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb, ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index); slot_id, ep_index);
else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) spin_unlock_irqrestore(&xhci->lock, flags);
} else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) {
spin_lock_irqsave(&xhci->lock, flags);
ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index); slot_id, ep_index);
else spin_unlock_irqrestore(&xhci->lock, flags);
} else if (usb_endpoint_xfer_int(&urb->ep->desc)) {
spin_lock_irqsave(&xhci->lock, flags);
ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
spin_unlock_irqrestore(&xhci->lock, flags);
} else {
ret = -EINVAL; ret = -EINVAL;
}
exit: exit:
spin_unlock_irqrestore(&xhci->lock, flags);
return ret; return ret;
} }
@ -674,6 +780,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
struct xhci_td *td; struct xhci_td *td;
unsigned int ep_index; unsigned int ep_index;
struct xhci_ring *ep_ring; struct xhci_ring *ep_ring;
struct xhci_virt_ep *ep;
xhci = hcd_to_xhci(hcd); xhci = hcd_to_xhci(hcd);
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
@ -686,17 +793,18 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
xhci_dbg(xhci, "Event ring:\n"); xhci_dbg(xhci, "Event ring:\n");
xhci_debug_ring(xhci, xhci->event_ring); xhci_debug_ring(xhci, xhci->event_ring);
ep_index = xhci_get_endpoint_index(&urb->ep->desc); ep_index = xhci_get_endpoint_index(&urb->ep->desc);
ep_ring = xhci->devs[urb->dev->slot_id]->ep_rings[ep_index]; ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];
ep_ring = ep->ring;
xhci_dbg(xhci, "Endpoint ring:\n"); xhci_dbg(xhci, "Endpoint ring:\n");
xhci_debug_ring(xhci, ep_ring); xhci_debug_ring(xhci, ep_ring);
td = (struct xhci_td *) urb->hcpriv; td = (struct xhci_td *) urb->hcpriv;
ep_ring->cancels_pending++; ep->cancels_pending++;
list_add_tail(&td->cancelled_td_list, &ep_ring->cancelled_td_list); list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list);
/* Queue a stop endpoint command, but only if this is /* Queue a stop endpoint command, but only if this is
* the first cancellation to be handled. * the first cancellation to be handled.
*/ */
if (ep_ring->cancels_pending == 1) { if (ep->cancels_pending == 1) {
xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index); xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index);
xhci_ring_cmd_db(xhci); xhci_ring_cmd_db(xhci);
} }
@ -930,6 +1038,141 @@ static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *vir
} }
} }
static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
struct usb_device *udev, int *cmd_status)
{
int ret;
switch (*cmd_status) {
case COMP_ENOMEM:
dev_warn(&udev->dev, "Not enough host controller resources "
"for new device state.\n");
ret = -ENOMEM;
/* FIXME: can we allocate more resources for the HC? */
break;
case COMP_BW_ERR:
dev_warn(&udev->dev, "Not enough bandwidth "
"for new device state.\n");
ret = -ENOSPC;
/* FIXME: can we go back to the old state? */
break;
case COMP_TRB_ERR:
/* the HCD set up something wrong */
dev_warn(&udev->dev, "ERROR: Endpoint drop flag = 0, "
"add flag = 1, "
"and endpoint is not disabled.\n");
ret = -EINVAL;
break;
case COMP_SUCCESS:
dev_dbg(&udev->dev, "Successful Endpoint Configure command\n");
ret = 0;
break;
default:
xhci_err(xhci, "ERROR: unexpected command completion "
"code 0x%x.\n", *cmd_status);
ret = -EINVAL;
break;
}
return ret;
}
static int xhci_evaluate_context_result(struct xhci_hcd *xhci,
struct usb_device *udev, int *cmd_status)
{
int ret;
struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id];
switch (*cmd_status) {
case COMP_EINVAL:
dev_warn(&udev->dev, "WARN: xHCI driver setup invalid evaluate "
"context command.\n");
ret = -EINVAL;
break;
case COMP_EBADSLT:
dev_warn(&udev->dev, "WARN: slot not enabled for"
"evaluate context command.\n");
case COMP_CTX_STATE:
dev_warn(&udev->dev, "WARN: invalid context state for "
"evaluate context command.\n");
xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1);
ret = -EINVAL;
break;
case COMP_SUCCESS:
dev_dbg(&udev->dev, "Successful evaluate context command\n");
ret = 0;
break;
default:
xhci_err(xhci, "ERROR: unexpected command completion "
"code 0x%x.\n", *cmd_status);
ret = -EINVAL;
break;
}
return ret;
}
/* Issue a configure endpoint command or evaluate context command
* and wait for it to finish.
*/
static int xhci_configure_endpoint(struct xhci_hcd *xhci,
struct usb_device *udev,
struct xhci_command *command,
bool ctx_change, bool must_succeed)
{
int ret;
int timeleft;
unsigned long flags;
struct xhci_container_ctx *in_ctx;
struct completion *cmd_completion;
int *cmd_status;
struct xhci_virt_device *virt_dev;
spin_lock_irqsave(&xhci->lock, flags);
virt_dev = xhci->devs[udev->slot_id];
if (command) {
in_ctx = command->in_ctx;
cmd_completion = command->completion;
cmd_status = &command->status;
command->command_trb = xhci->cmd_ring->enqueue;
list_add_tail(&command->cmd_list, &virt_dev->cmd_list);
} else {
in_ctx = virt_dev->in_ctx;
cmd_completion = &virt_dev->cmd_completion;
cmd_status = &virt_dev->cmd_status;
}
if (!ctx_change)
ret = xhci_queue_configure_endpoint(xhci, in_ctx->dma,
udev->slot_id, must_succeed);
else
ret = xhci_queue_evaluate_context(xhci, in_ctx->dma,
udev->slot_id);
if (ret < 0) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
return -ENOMEM;
}
xhci_ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);
/* Wait for the configure endpoint command to complete */
timeleft = wait_for_completion_interruptible_timeout(
cmd_completion,
USB_CTRL_SET_TIMEOUT);
if (timeleft <= 0) {
xhci_warn(xhci, "%s while waiting for %s command\n",
timeleft == 0 ? "Timeout" : "Signal",
ctx_change == 0 ?
"configure endpoint" :
"evaluate context");
/* FIXME cancel the configure endpoint command */
return -ETIME;
}
if (!ctx_change)
return xhci_configure_endpoint_result(xhci, udev, cmd_status);
return xhci_evaluate_context_result(xhci, udev, cmd_status);
}
/* Called after one or more calls to xhci_add_endpoint() or /* Called after one or more calls to xhci_add_endpoint() or
* xhci_drop_endpoint(). If this call fails, the USB core is expected * xhci_drop_endpoint(). If this call fails, the USB core is expected
* to call xhci_reset_bandwidth(). * to call xhci_reset_bandwidth().
@ -944,8 +1187,6 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
{ {
int i; int i;
int ret = 0; int ret = 0;
int timeleft;
unsigned long flags;
struct xhci_hcd *xhci; struct xhci_hcd *xhci;
struct xhci_virt_device *virt_dev; struct xhci_virt_device *virt_dev;
struct xhci_input_control_ctx *ctrl_ctx; struct xhci_input_control_ctx *ctrl_ctx;
@ -975,56 +1216,8 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
xhci_dbg_ctx(xhci, virt_dev->in_ctx, xhci_dbg_ctx(xhci, virt_dev->in_ctx,
LAST_CTX_TO_EP_NUM(slot_ctx->dev_info)); LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));
spin_lock_irqsave(&xhci->lock, flags); ret = xhci_configure_endpoint(xhci, udev, NULL,
ret = xhci_queue_configure_endpoint(xhci, virt_dev->in_ctx->dma, false, false);
udev->slot_id);
if (ret < 0) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
return -ENOMEM;
}
xhci_ring_cmd_db(xhci);
spin_unlock_irqrestore(&xhci->lock, flags);
/* Wait for the configure endpoint command to complete */
timeleft = wait_for_completion_interruptible_timeout(
&virt_dev->cmd_completion,
USB_CTRL_SET_TIMEOUT);
if (timeleft <= 0) {
xhci_warn(xhci, "%s while waiting for configure endpoint command\n",
timeleft == 0 ? "Timeout" : "Signal");
/* FIXME cancel the configure endpoint command */
return -ETIME;
}
switch (virt_dev->cmd_status) {
case COMP_ENOMEM:
dev_warn(&udev->dev, "Not enough host controller resources "
"for new device state.\n");
ret = -ENOMEM;
/* FIXME: can we allocate more resources for the HC? */
break;
case COMP_BW_ERR:
dev_warn(&udev->dev, "Not enough bandwidth "
"for new device state.\n");
ret = -ENOSPC;
/* FIXME: can we go back to the old state? */
break;
case COMP_TRB_ERR:
/* the HCD set up something wrong */
dev_warn(&udev->dev, "ERROR: Endpoint drop flag = 0, add flag = 1, "
"and endpoint is not disabled.\n");
ret = -EINVAL;
break;
case COMP_SUCCESS:
dev_dbg(&udev->dev, "Successful Endpoint Configure command\n");
break;
default:
xhci_err(xhci, "ERROR: unexpected command completion "
"code 0x%x.\n", virt_dev->cmd_status);
ret = -EINVAL;
break;
}
if (ret) { if (ret) {
/* Callee should call reset_bandwidth() */ /* Callee should call reset_bandwidth() */
return ret; return ret;
@ -1037,10 +1230,10 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
xhci_zero_in_ctx(xhci, virt_dev); xhci_zero_in_ctx(xhci, virt_dev);
/* Free any old rings */ /* Free any old rings */
for (i = 1; i < 31; ++i) { for (i = 1; i < 31; ++i) {
if (virt_dev->new_ep_rings[i]) { if (virt_dev->eps[i].new_ring) {
xhci_ring_free(xhci, virt_dev->ep_rings[i]); xhci_ring_free(xhci, virt_dev->eps[i].ring);
virt_dev->ep_rings[i] = virt_dev->new_ep_rings[i]; virt_dev->eps[i].ring = virt_dev->eps[i].new_ring;
virt_dev->new_ep_rings[i] = NULL; virt_dev->eps[i].new_ring = NULL;
} }
} }
@ -1067,14 +1260,93 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
virt_dev = xhci->devs[udev->slot_id]; virt_dev = xhci->devs[udev->slot_id];
/* Free any rings allocated for added endpoints */ /* Free any rings allocated for added endpoints */
for (i = 0; i < 31; ++i) { for (i = 0; i < 31; ++i) {
if (virt_dev->new_ep_rings[i]) { if (virt_dev->eps[i].new_ring) {
xhci_ring_free(xhci, virt_dev->new_ep_rings[i]); xhci_ring_free(xhci, virt_dev->eps[i].new_ring);
virt_dev->new_ep_rings[i] = NULL; virt_dev->eps[i].new_ring = NULL;
} }
} }
xhci_zero_in_ctx(xhci, virt_dev); xhci_zero_in_ctx(xhci, virt_dev);
} }
static void xhci_setup_input_ctx_for_config_ep(struct xhci_hcd *xhci,
struct xhci_container_ctx *in_ctx,
struct xhci_container_ctx *out_ctx,
u32 add_flags, u32 drop_flags)
{
struct xhci_input_control_ctx *ctrl_ctx;
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
ctrl_ctx->add_flags = add_flags;
ctrl_ctx->drop_flags = drop_flags;
xhci_slot_copy(xhci, in_ctx, out_ctx);
ctrl_ctx->add_flags |= SLOT_FLAG;
xhci_dbg(xhci, "Input Context:\n");
xhci_dbg_ctx(xhci, in_ctx, xhci_last_valid_endpoint(add_flags));
}
void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
struct xhci_dequeue_state *deq_state)
{
struct xhci_container_ctx *in_ctx;
struct xhci_ep_ctx *ep_ctx;
u32 added_ctxs;
dma_addr_t addr;
xhci_endpoint_copy(xhci, xhci->devs[slot_id]->in_ctx,
xhci->devs[slot_id]->out_ctx, ep_index);
in_ctx = xhci->devs[slot_id]->in_ctx;
ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index);
addr = xhci_trb_virt_to_dma(deq_state->new_deq_seg,
deq_state->new_deq_ptr);
if (addr == 0) {
xhci_warn(xhci, "WARN Cannot submit config ep after "
"reset ep command\n");
xhci_warn(xhci, "WARN deq seg = %p, deq ptr = %p\n",
deq_state->new_deq_seg,
deq_state->new_deq_ptr);
return;
}
ep_ctx->deq = addr | deq_state->new_cycle_state;
added_ctxs = xhci_get_endpoint_flag_from_index(ep_index);
xhci_setup_input_ctx_for_config_ep(xhci, xhci->devs[slot_id]->in_ctx,
xhci->devs[slot_id]->out_ctx, added_ctxs, added_ctxs);
}
void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
struct usb_device *udev, unsigned int ep_index)
{
struct xhci_dequeue_state deq_state;
struct xhci_virt_ep *ep;
xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n");
ep = &xhci->devs[udev->slot_id]->eps[ep_index];
/* We need to move the HW's dequeue pointer past this TD,
* or it will attempt to resend it on the next doorbell ring.
*/
xhci_find_new_dequeue_state(xhci, udev->slot_id,
ep_index, ep->stopped_td,
&deq_state);
/* HW with the reset endpoint quirk will use the saved dequeue state to
* issue a configure endpoint command later.
*/
if (!(xhci->quirks & XHCI_RESET_EP_QUIRK)) {
xhci_dbg(xhci, "Queueing new dequeue state\n");
xhci_queue_new_dequeue_state(xhci, udev->slot_id,
ep_index, &deq_state);
} else {
/* Better hope no one uses the input context between now and the
* reset endpoint completion!
*/
xhci_dbg(xhci, "Setting up input context for "
"configure endpoint command\n");
xhci_setup_input_ctx_for_quirk(xhci, udev->slot_id,
ep_index, &deq_state);
}
}
/* Deal with stalled endpoints. The core should have sent the control message /* Deal with stalled endpoints. The core should have sent the control message
* to clear the halt condition. However, we need to make the xHCI hardware * to clear the halt condition. However, we need to make the xHCI hardware
* reset its sequence number, since a device will expect a sequence number of * reset its sequence number, since a device will expect a sequence number of
@ -1089,8 +1361,7 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
unsigned int ep_index; unsigned int ep_index;
unsigned long flags; unsigned long flags;
int ret; int ret;
struct xhci_dequeue_state deq_state; struct xhci_virt_ep *virt_ep;
struct xhci_ring *ep_ring;
xhci = hcd_to_xhci(hcd); xhci = hcd_to_xhci(hcd);
udev = (struct usb_device *) ep->hcpriv; udev = (struct usb_device *) ep->hcpriv;
@ -1100,12 +1371,16 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
if (!ep->hcpriv) if (!ep->hcpriv)
return; return;
ep_index = xhci_get_endpoint_index(&ep->desc); ep_index = xhci_get_endpoint_index(&ep->desc);
ep_ring = xhci->devs[udev->slot_id]->ep_rings[ep_index]; virt_ep = &xhci->devs[udev->slot_id]->eps[ep_index];
if (!ep_ring->stopped_td) { if (!virt_ep->stopped_td) {
xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n", xhci_dbg(xhci, "Endpoint 0x%x not halted, refusing to reset.\n",
ep->desc.bEndpointAddress); ep->desc.bEndpointAddress);
return; return;
} }
if (usb_endpoint_xfer_control(&ep->desc)) {
xhci_dbg(xhci, "Control endpoint stall already handled.\n");
return;
}
xhci_dbg(xhci, "Queueing reset endpoint command\n"); xhci_dbg(xhci, "Queueing reset endpoint command\n");
spin_lock_irqsave(&xhci->lock, flags); spin_lock_irqsave(&xhci->lock, flags);
@ -1116,17 +1391,8 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
* command. Better hope that last command worked! * command. Better hope that last command worked!
*/ */
if (!ret) { if (!ret) {
xhci_dbg(xhci, "Cleaning up stalled endpoint ring\n"); xhci_cleanup_stalled_ring(xhci, udev, ep_index);
/* We need to move the HW's dequeue pointer past this TD, kfree(virt_ep->stopped_td);
* or it will attempt to resend it on the next doorbell ring.
*/
xhci_find_new_dequeue_state(xhci, udev->slot_id,
ep_index, ep_ring->stopped_td, &deq_state);
xhci_dbg(xhci, "Queueing new dequeue state\n");
xhci_queue_new_dequeue_state(xhci, ep_ring,
udev->slot_id,
ep_index, &deq_state);
kfree(ep_ring->stopped_td);
xhci_ring_cmd_db(xhci); xhci_ring_cmd_db(xhci);
} }
spin_unlock_irqrestore(&xhci->lock, flags); spin_unlock_irqrestore(&xhci->lock, flags);
@ -1328,6 +1594,88 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
return 0; return 0;
} }
/* Once a hub descriptor is fetched for a device, we need to update the xHC's
* internal data structures for the device.
*/
int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct xhci_virt_device *vdev;
struct xhci_command *config_cmd;
struct xhci_input_control_ctx *ctrl_ctx;
struct xhci_slot_ctx *slot_ctx;
unsigned long flags;
unsigned think_time;
int ret;
/* Ignore root hubs */
if (!hdev->parent)
return 0;
vdev = xhci->devs[hdev->slot_id];
if (!vdev) {
xhci_warn(xhci, "Cannot update hub desc for unknown device.\n");
return -EINVAL;
}
config_cmd = xhci_alloc_command(xhci, true, mem_flags);
if (!config_cmd) {
xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
return -ENOMEM;
}
spin_lock_irqsave(&xhci->lock, flags);
xhci_slot_copy(xhci, config_cmd->in_ctx, vdev->out_ctx);
ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx);
ctrl_ctx->add_flags |= SLOT_FLAG;
slot_ctx = xhci_get_slot_ctx(xhci, config_cmd->in_ctx);
slot_ctx->dev_info |= DEV_HUB;
if (tt->multi)
slot_ctx->dev_info |= DEV_MTT;
if (xhci->hci_version > 0x95) {
xhci_dbg(xhci, "xHCI version %x needs hub "
"TT think time and number of ports\n",
(unsigned int) xhci->hci_version);
slot_ctx->dev_info2 |= XHCI_MAX_PORTS(hdev->maxchild);
/* Set TT think time - convert from ns to FS bit times.
* 0 = 8 FS bit times, 1 = 16 FS bit times,
* 2 = 24 FS bit times, 3 = 32 FS bit times.
*/
think_time = tt->think_time;
if (think_time != 0)
think_time = (think_time / 666) - 1;
slot_ctx->tt_info |= TT_THINK_TIME(think_time);
} else {
xhci_dbg(xhci, "xHCI version %x doesn't need hub "
"TT think time or number of ports\n",
(unsigned int) xhci->hci_version);
}
slot_ctx->dev_state = 0;
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "Set up %s for hub device.\n",
(xhci->hci_version > 0x95) ?
"configure endpoint" : "evaluate context");
xhci_dbg(xhci, "Slot %u Input Context:\n", hdev->slot_id);
xhci_dbg_ctx(xhci, config_cmd->in_ctx, 0);
/* Issue and wait for the configure endpoint or
* evaluate context command.
*/
if (xhci->hci_version > 0x95)
ret = xhci_configure_endpoint(xhci, hdev, config_cmd,
false, false);
else
ret = xhci_configure_endpoint(xhci, hdev, config_cmd,
true, false);
xhci_dbg(xhci, "Slot %u Output Context:\n", hdev->slot_id);
xhci_dbg_ctx(xhci, vdev->out_ctx, 0);
xhci_free_command(xhci, config_cmd);
return ret;
}
int xhci_get_frame(struct usb_hcd *hcd) int xhci_get_frame(struct usb_hcd *hcd)
{ {
struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct xhci_hcd *xhci = hcd_to_xhci(hcd);

View File

@ -94,6 +94,9 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
val = prev->trbs[TRBS_PER_SEGMENT-1].link.control; val = prev->trbs[TRBS_PER_SEGMENT-1].link.control;
val &= ~TRB_TYPE_BITMASK; val &= ~TRB_TYPE_BITMASK;
val |= TRB_TYPE(TRB_LINK); val |= TRB_TYPE(TRB_LINK);
/* Always set the chain bit with 0.95 hardware */
if (xhci_link_trb_quirk(xhci))
val |= TRB_CHAIN;
prev->trbs[TRBS_PER_SEGMENT-1].link.control = val; prev->trbs[TRBS_PER_SEGMENT-1].link.control = val;
} }
xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n", xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n",
@ -141,7 +144,6 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
return 0; return 0;
INIT_LIST_HEAD(&ring->td_list); INIT_LIST_HEAD(&ring->td_list);
INIT_LIST_HEAD(&ring->cancelled_td_list);
if (num_segs == 0) if (num_segs == 0)
return ring; return ring;
@ -262,8 +264,8 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
return; return;
for (i = 0; i < 31; ++i) for (i = 0; i < 31; ++i)
if (dev->ep_rings[i]) if (dev->eps[i].ring)
xhci_ring_free(xhci, dev->ep_rings[i]); xhci_ring_free(xhci, dev->eps[i].ring);
if (dev->in_ctx) if (dev->in_ctx)
xhci_free_container_ctx(xhci, dev->in_ctx); xhci_free_container_ctx(xhci, dev->in_ctx);
@ -278,6 +280,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
struct usb_device *udev, gfp_t flags) struct usb_device *udev, gfp_t flags)
{ {
struct xhci_virt_device *dev; struct xhci_virt_device *dev;
int i;
/* Slot ID 0 is reserved */ /* Slot ID 0 is reserved */
if (slot_id == 0 || xhci->devs[slot_id]) { if (slot_id == 0 || xhci->devs[slot_id]) {
@ -306,12 +309,17 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id,
(unsigned long long)dev->in_ctx->dma); (unsigned long long)dev->in_ctx->dma);
/* Initialize the cancellation list for each endpoint */
for (i = 0; i < 31; i++)
INIT_LIST_HEAD(&dev->eps[i].cancelled_td_list);
/* Allocate endpoint 0 ring */ /* Allocate endpoint 0 ring */
dev->ep_rings[0] = xhci_ring_alloc(xhci, 1, true, flags); dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, flags);
if (!dev->ep_rings[0]) if (!dev->eps[0].ring)
goto fail; goto fail;
init_completion(&dev->cmd_completion); init_completion(&dev->cmd_completion);
INIT_LIST_HEAD(&dev->cmd_list);
/* Point to output device context in dcbaa. */ /* Point to output device context in dcbaa. */
xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma; xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma;
@ -352,9 +360,9 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
/* 3) Only the control endpoint is valid - one endpoint context */ /* 3) Only the control endpoint is valid - one endpoint context */
slot_ctx->dev_info |= LAST_CTX(1); slot_ctx->dev_info |= LAST_CTX(1);
slot_ctx->dev_info |= (u32) udev->route;
switch (udev->speed) { switch (udev->speed) {
case USB_SPEED_SUPER: case USB_SPEED_SUPER:
slot_ctx->dev_info |= (u32) udev->route;
slot_ctx->dev_info |= (u32) SLOT_SPEED_SS; slot_ctx->dev_info |= (u32) SLOT_SPEED_SS;
break; break;
case USB_SPEED_HIGH: case USB_SPEED_HIGH:
@ -382,14 +390,12 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum); xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum);
/* Is this a LS/FS device under a HS hub? */ /* Is this a LS/FS device under a HS hub? */
/*
* FIXME: I don't think this is right, where does the TT info for the
* roothub or parent hub come from?
*/
if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) && if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) &&
udev->tt) { udev->tt) {
slot_ctx->tt_info = udev->tt->hub->slot_id; slot_ctx->tt_info = udev->tt->hub->slot_id;
slot_ctx->tt_info |= udev->ttport << 8; slot_ctx->tt_info |= udev->ttport << 8;
if (udev->tt->multi)
slot_ctx->dev_info |= DEV_MTT;
} }
xhci_dbg(xhci, "udev->tt = %p\n", udev->tt); xhci_dbg(xhci, "udev->tt = %p\n", udev->tt);
xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport); xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport);
@ -398,22 +404,35 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
/* Step 5 */ /* Step 5 */
ep0_ctx->ep_info2 = EP_TYPE(CTRL_EP); ep0_ctx->ep_info2 = EP_TYPE(CTRL_EP);
/* /*
* See section 4.3 bullet 6:
* The default Max Packet size for ep0 is "8 bytes for a USB2
* LS/FS/HS device or 512 bytes for a USB3 SS device"
* XXX: Not sure about wireless USB devices. * XXX: Not sure about wireless USB devices.
*/ */
if (udev->speed == USB_SPEED_SUPER) switch (udev->speed) {
case USB_SPEED_SUPER:
ep0_ctx->ep_info2 |= MAX_PACKET(512); ep0_ctx->ep_info2 |= MAX_PACKET(512);
else break;
case USB_SPEED_HIGH:
/* USB core guesses at a 64-byte max packet first for FS devices */
case USB_SPEED_FULL:
ep0_ctx->ep_info2 |= MAX_PACKET(64);
break;
case USB_SPEED_LOW:
ep0_ctx->ep_info2 |= MAX_PACKET(8); ep0_ctx->ep_info2 |= MAX_PACKET(8);
break;
case USB_SPEED_VARIABLE:
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
return -EINVAL;
break;
default:
/* New speed? */
BUG();
}
/* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */ /* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */
ep0_ctx->ep_info2 |= MAX_BURST(0); ep0_ctx->ep_info2 |= MAX_BURST(0);
ep0_ctx->ep_info2 |= ERROR_COUNT(3); ep0_ctx->ep_info2 |= ERROR_COUNT(3);
ep0_ctx->deq = ep0_ctx->deq =
dev->ep_rings[0]->first_seg->dma; dev->eps[0].ring->first_seg->dma;
ep0_ctx->deq |= dev->ep_rings[0]->cycle_state; ep0_ctx->deq |= dev->eps[0].ring->cycle_state;
/* Steps 7 and 8 were done in xhci_alloc_virt_device() */ /* Steps 7 and 8 were done in xhci_alloc_virt_device() */
@ -523,10 +542,11 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
/* Set up the endpoint ring */ /* Set up the endpoint ring */
virt_dev->new_ep_rings[ep_index] = xhci_ring_alloc(xhci, 1, true, mem_flags); virt_dev->eps[ep_index].new_ring =
if (!virt_dev->new_ep_rings[ep_index]) xhci_ring_alloc(xhci, 1, true, mem_flags);
if (!virt_dev->eps[ep_index].new_ring)
return -ENOMEM; return -ENOMEM;
ep_ring = virt_dev->new_ep_rings[ep_index]; ep_ring = virt_dev->eps[ep_index].new_ring;
ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state; ep_ctx->deq = ep_ring->first_seg->dma | ep_ring->cycle_state;
ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep); ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep);
@ -598,6 +618,48 @@ void xhci_endpoint_zero(struct xhci_hcd *xhci,
*/ */
} }
/* Copy output xhci_ep_ctx to the input xhci_ep_ctx copy.
* Useful when you want to change one particular aspect of the endpoint and then
* issue a configure endpoint command.
*/
void xhci_endpoint_copy(struct xhci_hcd *xhci,
struct xhci_container_ctx *in_ctx,
struct xhci_container_ctx *out_ctx,
unsigned int ep_index)
{
struct xhci_ep_ctx *out_ep_ctx;
struct xhci_ep_ctx *in_ep_ctx;
out_ep_ctx = xhci_get_ep_ctx(xhci, out_ctx, ep_index);
in_ep_ctx = xhci_get_ep_ctx(xhci, in_ctx, ep_index);
in_ep_ctx->ep_info = out_ep_ctx->ep_info;
in_ep_ctx->ep_info2 = out_ep_ctx->ep_info2;
in_ep_ctx->deq = out_ep_ctx->deq;
in_ep_ctx->tx_info = out_ep_ctx->tx_info;
}
/* Copy output xhci_slot_ctx to the input xhci_slot_ctx.
* Useful when you want to change one particular aspect of the endpoint and then
* issue a configure endpoint command. Only the context entries field matters,
* but we'll copy the whole thing anyway.
*/
void xhci_slot_copy(struct xhci_hcd *xhci,
struct xhci_container_ctx *in_ctx,
struct xhci_container_ctx *out_ctx)
{
struct xhci_slot_ctx *in_slot_ctx;
struct xhci_slot_ctx *out_slot_ctx;
in_slot_ctx = xhci_get_slot_ctx(xhci, in_ctx);
out_slot_ctx = xhci_get_slot_ctx(xhci, out_ctx);
in_slot_ctx->dev_info = out_slot_ctx->dev_info;
in_slot_ctx->dev_info2 = out_slot_ctx->dev_info2;
in_slot_ctx->tt_info = out_slot_ctx->tt_info;
in_slot_ctx->dev_state = out_slot_ctx->dev_state;
}
/* Set up the scratchpad buffer array and scratchpad buffers, if needed. */ /* Set up the scratchpad buffer array and scratchpad buffers, if needed. */
static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags)
{ {
@ -695,6 +757,44 @@ static void scratchpad_free(struct xhci_hcd *xhci)
xhci->scratchpad = NULL; xhci->scratchpad = NULL;
} }
struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
bool allocate_completion, gfp_t mem_flags)
{
struct xhci_command *command;
command = kzalloc(sizeof(*command), mem_flags);
if (!command)
return NULL;
command->in_ctx =
xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, mem_flags);
if (!command->in_ctx)
return NULL;
if (allocate_completion) {
command->completion =
kzalloc(sizeof(struct completion), mem_flags);
if (!command->completion) {
xhci_free_container_ctx(xhci, command->in_ctx);
return NULL;
}
init_completion(command->completion);
}
command->status = 0;
INIT_LIST_HEAD(&command->cmd_list);
return command;
}
void xhci_free_command(struct xhci_hcd *xhci,
struct xhci_command *command)
{
xhci_free_container_ctx(xhci,
command->in_ctx);
kfree(command->completion);
kfree(command);
}
void xhci_mem_cleanup(struct xhci_hcd *xhci) void xhci_mem_cleanup(struct xhci_hcd *xhci)
{ {
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);

View File

@ -24,6 +24,10 @@
#include "xhci.h" #include "xhci.h"
/* Device for a quirk */
#define PCI_VENDOR_ID_FRESCO_LOGIC 0x1b73
#define PCI_DEVICE_ID_FRESCO_LOGIC_PDK 0x1000
static const char hcd_name[] = "xhci_hcd"; static const char hcd_name[] = "xhci_hcd";
/* called after powerup, by probe or system-pm "wakeup" */ /* called after powerup, by probe or system-pm "wakeup" */
@ -59,9 +63,20 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1);
xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2);
xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
xhci->hci_version = HC_VERSION(xhci->hcc_params);
xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params); xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
xhci_print_registers(xhci); xhci_print_registers(xhci);
/* Look for vendor-specific quirks */
if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC &&
pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK &&
pdev->revision == 0x0) {
xhci->quirks |= XHCI_RESET_EP_QUIRK;
xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure"
" endpoint cmd after reset endpoint\n");
}
/* Make sure the HC is halted. */ /* Make sure the HC is halted. */
retval = xhci_halt(xhci); retval = xhci_halt(xhci);
if (retval) if (retval)
@ -121,6 +136,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
.check_bandwidth = xhci_check_bandwidth, .check_bandwidth = xhci_check_bandwidth,
.reset_bandwidth = xhci_reset_bandwidth, .reset_bandwidth = xhci_reset_bandwidth,
.address_device = xhci_address_device, .address_device = xhci_address_device,
.update_hub_device = xhci_update_hub_device,
/* /*
* scheduling support * scheduling support

View File

@ -172,8 +172,9 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
* have their chain bit cleared (so that each Link TRB is a separate TD). * have their chain bit cleared (so that each Link TRB is a separate TD).
* *
* Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit * Section 6.4.4.1 of the 0.95 spec says link TRBs cannot have the chain bit
* set, but other sections talk about dealing with the chain bit set. * set, but other sections talk about dealing with the chain bit set. This was
* Assume section 6.4.4.1 is wrong, and the chain bit can be set in a Link TRB. * fixed in the 0.96 specification errata, but we have to assume that all 0.95
* xHCI hardware can't handle the chain bit being cleared on a link TRB.
*/ */
static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer) static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer)
{ {
@ -191,8 +192,14 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
while (last_trb(xhci, ring, ring->enq_seg, next)) { while (last_trb(xhci, ring, ring->enq_seg, next)) {
if (!consumer) { if (!consumer) {
if (ring != xhci->event_ring) { if (ring != xhci->event_ring) {
next->link.control &= ~TRB_CHAIN; /* If we're not dealing with 0.95 hardware,
next->link.control |= chain; * carry over the chain bit of the previous TRB
* (which may mean the chain bit is cleared).
*/
if (!xhci_link_trb_quirk(xhci)) {
next->link.control &= ~TRB_CHAIN;
next->link.control |= chain;
}
/* Give this link TRB to the hardware */ /* Give this link TRB to the hardware */
wmb(); wmb();
if (next->link.control & TRB_CYCLE) if (next->link.control & TRB_CYCLE)
@ -289,16 +296,18 @@ static void ring_ep_doorbell(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int slot_id,
unsigned int ep_index) unsigned int ep_index)
{ {
struct xhci_ring *ep_ring; struct xhci_virt_ep *ep;
unsigned int ep_state;
u32 field; u32 field;
__u32 __iomem *db_addr = &xhci->dba->doorbell[slot_id]; __u32 __iomem *db_addr = &xhci->dba->doorbell[slot_id];
ep_ring = xhci->devs[slot_id]->ep_rings[ep_index]; ep = &xhci->devs[slot_id]->eps[ep_index];
ep_state = ep->ep_state;
/* Don't ring the doorbell for this endpoint if there are pending /* Don't ring the doorbell for this endpoint if there are pending
* cancellations because the we don't want to interrupt processing. * cancellations because the we don't want to interrupt processing.
*/ */
if (!ep_ring->cancels_pending && !(ep_ring->state & SET_DEQ_PENDING) if (!ep->cancels_pending && !(ep_state & SET_DEQ_PENDING)
&& !(ep_ring->state & EP_HALTED)) { && !(ep_state & EP_HALTED)) {
field = xhci_readl(xhci, db_addr) & DB_MASK; field = xhci_readl(xhci, db_addr) & DB_MASK;
xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr); xhci_writel(xhci, field | EPI_TO_DB(ep_index), db_addr);
/* Flush PCI posted writes - FIXME Matthew Wilcox says this /* Flush PCI posted writes - FIXME Matthew Wilcox says this
@ -354,7 +363,7 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
struct xhci_td *cur_td, struct xhci_dequeue_state *state) struct xhci_td *cur_td, struct xhci_dequeue_state *state)
{ {
struct xhci_virt_device *dev = xhci->devs[slot_id]; struct xhci_virt_device *dev = xhci->devs[slot_id];
struct xhci_ring *ep_ring = dev->ep_rings[ep_index]; struct xhci_ring *ep_ring = dev->eps[ep_index].ring;
struct xhci_generic_trb *trb; struct xhci_generic_trb *trb;
struct xhci_ep_ctx *ep_ctx; struct xhci_ep_ctx *ep_ctx;
dma_addr_t addr; dma_addr_t addr;
@ -362,7 +371,7 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
state->new_cycle_state = 0; state->new_cycle_state = 0;
xhci_dbg(xhci, "Finding segment containing stopped TRB.\n"); xhci_dbg(xhci, "Finding segment containing stopped TRB.\n");
state->new_deq_seg = find_trb_seg(cur_td->start_seg, state->new_deq_seg = find_trb_seg(cur_td->start_seg,
ep_ring->stopped_trb, dev->eps[ep_index].stopped_trb,
&state->new_cycle_state); &state->new_cycle_state);
if (!state->new_deq_seg) if (!state->new_deq_seg)
BUG(); BUG();
@ -442,9 +451,11 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
union xhci_trb *deq_ptr, u32 cycle_state); union xhci_trb *deq_ptr, u32 cycle_state);
void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
struct xhci_ring *ep_ring, unsigned int slot_id, unsigned int slot_id, unsigned int ep_index,
unsigned int ep_index, struct xhci_dequeue_state *deq_state) struct xhci_dequeue_state *deq_state)
{ {
struct xhci_virt_ep *ep = &xhci->devs[slot_id]->eps[ep_index];
xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), " xhci_dbg(xhci, "Set TR Deq Ptr cmd, new deq seg = %p (0x%llx dma), "
"new deq ptr = %p (0x%llx dma), new cycle = %u\n", "new deq ptr = %p (0x%llx dma), new cycle = %u\n",
deq_state->new_deq_seg, deq_state->new_deq_seg,
@ -461,8 +472,7 @@ void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
* if the ring is running, and ringing the doorbell starts the * if the ring is running, and ringing the doorbell starts the
* ring running. * ring running.
*/ */
ep_ring->state |= SET_DEQ_PENDING; ep->ep_state |= SET_DEQ_PENDING;
xhci_ring_cmd_db(xhci);
} }
/* /*
@ -481,6 +491,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
unsigned int slot_id; unsigned int slot_id;
unsigned int ep_index; unsigned int ep_index;
struct xhci_ring *ep_ring; struct xhci_ring *ep_ring;
struct xhci_virt_ep *ep;
struct list_head *entry; struct list_head *entry;
struct xhci_td *cur_td = 0; struct xhci_td *cur_td = 0;
struct xhci_td *last_unlinked_td; struct xhci_td *last_unlinked_td;
@ -493,9 +504,10 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
memset(&deq_state, 0, sizeof(deq_state)); memset(&deq_state, 0, sizeof(deq_state));
slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
ep_ring = xhci->devs[slot_id]->ep_rings[ep_index]; ep = &xhci->devs[slot_id]->eps[ep_index];
ep_ring = ep->ring;
if (list_empty(&ep_ring->cancelled_td_list)) if (list_empty(&ep->cancelled_td_list))
return; return;
/* Fix up the ep ring first, so HW stops executing cancelled TDs. /* Fix up the ep ring first, so HW stops executing cancelled TDs.
@ -503,7 +515,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
* it. We're also in the event handler, so we can't get re-interrupted * it. We're also in the event handler, so we can't get re-interrupted
* if another Stop Endpoint command completes * if another Stop Endpoint command completes
*/ */
list_for_each(entry, &ep_ring->cancelled_td_list) { list_for_each(entry, &ep->cancelled_td_list) {
cur_td = list_entry(entry, struct xhci_td, cancelled_td_list); cur_td = list_entry(entry, struct xhci_td, cancelled_td_list);
xhci_dbg(xhci, "Cancelling TD starting at %p, 0x%llx (dma).\n", xhci_dbg(xhci, "Cancelling TD starting at %p, 0x%llx (dma).\n",
cur_td->first_trb, cur_td->first_trb,
@ -512,7 +524,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
* If we stopped on the TD we need to cancel, then we have to * If we stopped on the TD we need to cancel, then we have to
* move the xHC endpoint ring dequeue pointer past this TD. * move the xHC endpoint ring dequeue pointer past this TD.
*/ */
if (cur_td == ep_ring->stopped_td) if (cur_td == ep->stopped_td)
xhci_find_new_dequeue_state(xhci, slot_id, ep_index, cur_td, xhci_find_new_dequeue_state(xhci, slot_id, ep_index, cur_td,
&deq_state); &deq_state);
else else
@ -523,14 +535,15 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
* the cancelled TD list for URB completion later. * the cancelled TD list for URB completion later.
*/ */
list_del(&cur_td->td_list); list_del(&cur_td->td_list);
ep_ring->cancels_pending--; ep->cancels_pending--;
} }
last_unlinked_td = cur_td; last_unlinked_td = cur_td;
/* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */
if (deq_state.new_deq_ptr && deq_state.new_deq_seg) { if (deq_state.new_deq_ptr && deq_state.new_deq_seg) {
xhci_queue_new_dequeue_state(xhci, ep_ring, xhci_queue_new_dequeue_state(xhci,
slot_id, ep_index, &deq_state); slot_id, ep_index, &deq_state);
xhci_ring_cmd_db(xhci);
} else { } else {
/* Otherwise just ring the doorbell to restart the ring */ /* Otherwise just ring the doorbell to restart the ring */
ring_ep_doorbell(xhci, slot_id, ep_index); ring_ep_doorbell(xhci, slot_id, ep_index);
@ -543,7 +556,7 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
* So stop when we've completed the URB for the last TD we unlinked. * So stop when we've completed the URB for the last TD we unlinked.
*/ */
do { do {
cur_td = list_entry(ep_ring->cancelled_td_list.next, cur_td = list_entry(ep->cancelled_td_list.next,
struct xhci_td, cancelled_td_list); struct xhci_td, cancelled_td_list);
list_del(&cur_td->cancelled_td_list); list_del(&cur_td->cancelled_td_list);
@ -590,7 +603,7 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
dev = xhci->devs[slot_id]; dev = xhci->devs[slot_id];
ep_ring = dev->ep_rings[ep_index]; ep_ring = dev->eps[ep_index].ring;
ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index); ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, ep_index);
slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx); slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx);
@ -634,7 +647,7 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
ep_ctx->deq); ep_ctx->deq);
} }
ep_ring->state &= ~SET_DEQ_PENDING; dev->eps[ep_index].ep_state &= ~SET_DEQ_PENDING;
ring_ep_doorbell(xhci, slot_id, ep_index); ring_ep_doorbell(xhci, slot_id, ep_index);
} }
@ -644,18 +657,60 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci,
{ {
int slot_id; int slot_id;
unsigned int ep_index; unsigned int ep_index;
struct xhci_ring *ep_ring;
slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]); slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]); ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
/* This command will only fail if the endpoint wasn't halted, /* This command will only fail if the endpoint wasn't halted,
* but we don't care. * but we don't care.
*/ */
xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n", xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n",
(unsigned int) GET_COMP_CODE(event->status)); (unsigned int) GET_COMP_CODE(event->status));
/* Clear our internal halted state and restart the ring */ /* HW with the reset endpoint quirk needs to have a configure endpoint
xhci->devs[slot_id]->ep_rings[ep_index]->state &= ~EP_HALTED; * command complete before the endpoint can be used. Queue that here
ring_ep_doorbell(xhci, slot_id, ep_index); * because the HW can't handle two commands being queued in a row.
*/
if (xhci->quirks & XHCI_RESET_EP_QUIRK) {
xhci_dbg(xhci, "Queueing configure endpoint command\n");
xhci_queue_configure_endpoint(xhci,
xhci->devs[slot_id]->in_ctx->dma, slot_id,
false);
xhci_ring_cmd_db(xhci);
} else {
/* Clear our internal halted state and restart the ring */
xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED;
ring_ep_doorbell(xhci, slot_id, ep_index);
}
}
/* Check to see if a command in the device's command queue matches this one.
* Signal the completion or free the command, and return 1. Return 0 if the
* completed command isn't at the head of the command list.
*/
static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
struct xhci_event_cmd *event)
{
struct xhci_command *command;
if (list_empty(&virt_dev->cmd_list))
return 0;
command = list_entry(virt_dev->cmd_list.next,
struct xhci_command, cmd_list);
if (xhci->cmd_ring->dequeue != command->command_trb)
return 0;
command->status =
GET_COMP_CODE(event->status);
list_del(&command->cmd_list);
if (command->completion)
complete(command->completion);
else
xhci_free_command(xhci, command);
return 1;
} }
static void handle_cmd_completion(struct xhci_hcd *xhci, static void handle_cmd_completion(struct xhci_hcd *xhci,
@ -664,6 +719,11 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
int slot_id = TRB_TO_SLOT_ID(event->flags); int slot_id = TRB_TO_SLOT_ID(event->flags);
u64 cmd_dma; u64 cmd_dma;
dma_addr_t cmd_dequeue_dma; dma_addr_t cmd_dequeue_dma;
struct xhci_input_control_ctx *ctrl_ctx;
struct xhci_virt_device *virt_dev;
unsigned int ep_index;
struct xhci_ring *ep_ring;
unsigned int ep_state;
cmd_dma = event->cmd_trb; cmd_dma = event->cmd_trb;
cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
@ -691,6 +751,47 @@ static void handle_cmd_completion(struct xhci_hcd *xhci,
xhci_free_virt_device(xhci, slot_id); xhci_free_virt_device(xhci, slot_id);
break; break;
case TRB_TYPE(TRB_CONFIG_EP): case TRB_TYPE(TRB_CONFIG_EP):
virt_dev = xhci->devs[slot_id];
if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event))
break;
/*
* Configure endpoint commands can come from the USB core
* configuration or alt setting changes, or because the HW
* needed an extra configure endpoint command after a reset
* endpoint command. In the latter case, the xHCI driver is
* not waiting on the configure endpoint command.
*/
ctrl_ctx = xhci_get_input_control_ctx(xhci,
virt_dev->in_ctx);
/* Input ctx add_flags are the endpoint index plus one */
ep_index = xhci_last_valid_endpoint(ctrl_ctx->add_flags) - 1;
ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
if (!ep_ring) {
/* This must have been an initial configure endpoint */
xhci->devs[slot_id]->cmd_status =
GET_COMP_CODE(event->status);
complete(&xhci->devs[slot_id]->cmd_completion);
break;
}
ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state;
xhci_dbg(xhci, "Completed config ep cmd - last ep index = %d, "
"state = %d\n", ep_index, ep_state);
if (xhci->quirks & XHCI_RESET_EP_QUIRK &&
ep_state & EP_HALTED) {
/* Clear our internal halted state and restart ring */
xhci->devs[slot_id]->eps[ep_index].ep_state &=
~EP_HALTED;
ring_ep_doorbell(xhci, slot_id, ep_index);
} else {
xhci->devs[slot_id]->cmd_status =
GET_COMP_CODE(event->status);
complete(&xhci->devs[slot_id]->cmd_completion);
}
break;
case TRB_TYPE(TRB_EVAL_CONTEXT):
virt_dev = xhci->devs[slot_id];
if (handle_cmd_in_cmd_wait_list(xhci, virt_dev, event))
break;
xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status); xhci->devs[slot_id]->cmd_status = GET_COMP_CODE(event->status);
complete(&xhci->devs[slot_id]->cmd_completion); complete(&xhci->devs[slot_id]->cmd_completion);
break; break;
@ -805,7 +906,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
struct xhci_transfer_event *event) struct xhci_transfer_event *event)
{ {
struct xhci_virt_device *xdev; struct xhci_virt_device *xdev;
struct xhci_virt_ep *ep;
struct xhci_ring *ep_ring; struct xhci_ring *ep_ring;
unsigned int slot_id;
int ep_index; int ep_index;
struct xhci_td *td = 0; struct xhci_td *td = 0;
dma_addr_t event_dma; dma_addr_t event_dma;
@ -814,9 +917,11 @@ static int handle_tx_event(struct xhci_hcd *xhci,
struct urb *urb = 0; struct urb *urb = 0;
int status = -EINPROGRESS; int status = -EINPROGRESS;
struct xhci_ep_ctx *ep_ctx; struct xhci_ep_ctx *ep_ctx;
u32 trb_comp_code;
xhci_dbg(xhci, "In %s\n", __func__); xhci_dbg(xhci, "In %s\n", __func__);
xdev = xhci->devs[TRB_TO_SLOT_ID(event->flags)]; slot_id = TRB_TO_SLOT_ID(event->flags);
xdev = xhci->devs[slot_id];
if (!xdev) { if (!xdev) {
xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n"); xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n");
return -ENODEV; return -ENODEV;
@ -825,7 +930,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
/* Endpoint ID is 1 based, our index is zero based */ /* Endpoint ID is 1 based, our index is zero based */
ep_index = TRB_TO_EP_ID(event->flags) - 1; ep_index = TRB_TO_EP_ID(event->flags) - 1;
xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index); xhci_dbg(xhci, "%s - ep index = %d\n", __func__, ep_index);
ep_ring = xdev->ep_rings[ep_index]; ep = &xdev->eps[ep_index];
ep_ring = ep->ring;
ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
if (!ep_ring || (ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) { if (!ep_ring || (ep_ctx->ep_info & EP_STATE_MASK) == EP_STATE_DISABLED) {
xhci_err(xhci, "ERROR Transfer event pointed to disabled endpoint\n"); xhci_err(xhci, "ERROR Transfer event pointed to disabled endpoint\n");
@ -870,7 +976,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
(unsigned int) event->flags); (unsigned int) event->flags);
/* Look for common error cases */ /* Look for common error cases */
switch (GET_COMP_CODE(event->transfer_len)) { trb_comp_code = GET_COMP_CODE(event->transfer_len);
switch (trb_comp_code) {
/* Skip codes that require special handling depending on /* Skip codes that require special handling depending on
* transfer type * transfer type
*/ */
@ -885,7 +992,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
break; break;
case COMP_STALL: case COMP_STALL:
xhci_warn(xhci, "WARN: Stalled endpoint\n"); xhci_warn(xhci, "WARN: Stalled endpoint\n");
ep_ring->state |= EP_HALTED; ep->ep_state |= EP_HALTED;
status = -EPIPE; status = -EPIPE;
break; break;
case COMP_TRB_ERR: case COMP_TRB_ERR:
@ -913,7 +1020,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
/* Was this a control transfer? */ /* Was this a control transfer? */
if (usb_endpoint_xfer_control(&td->urb->ep->desc)) { if (usb_endpoint_xfer_control(&td->urb->ep->desc)) {
xhci_debug_trb(xhci, xhci->event_ring->dequeue); xhci_debug_trb(xhci, xhci->event_ring->dequeue);
switch (GET_COMP_CODE(event->transfer_len)) { switch (trb_comp_code) {
case COMP_SUCCESS: case COMP_SUCCESS:
if (event_trb == ep_ring->dequeue) { if (event_trb == ep_ring->dequeue) {
xhci_warn(xhci, "WARN: Success on ctrl setup TRB without IOC set??\n"); xhci_warn(xhci, "WARN: Success on ctrl setup TRB without IOC set??\n");
@ -928,8 +1035,37 @@ static int handle_tx_event(struct xhci_hcd *xhci,
break; break;
case COMP_SHORT_TX: case COMP_SHORT_TX:
xhci_warn(xhci, "WARN: short transfer on control ep\n"); xhci_warn(xhci, "WARN: short transfer on control ep\n");
status = -EREMOTEIO; if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
status = -EREMOTEIO;
else
status = 0;
break; break;
case COMP_BABBLE:
/* The 0.96 spec says a babbling control endpoint
* is not halted. The 0.96 spec says it is. Some HW
* claims to be 0.95 compliant, but it halts the control
* endpoint anyway. Check if a babble halted the
* endpoint.
*/
if (ep_ctx->ep_info != EP_STATE_HALTED)
break;
/* else fall through */
case COMP_STALL:
/* Did we transfer part of the data (middle) phase? */
if (event_trb != ep_ring->dequeue &&
event_trb != td->last_trb)
td->urb->actual_length =
td->urb->transfer_buffer_length
- TRB_LEN(event->transfer_len);
else
td->urb->actual_length = 0;
ep->stopped_td = td;
ep->stopped_trb = event_trb;
xhci_queue_reset_ep(xhci, slot_id, ep_index);
xhci_cleanup_stalled_ring(xhci, td->urb->dev, ep_index);
xhci_ring_cmd_db(xhci);
goto td_cleanup;
default: default:
/* Others already handled above */ /* Others already handled above */
break; break;
@ -943,7 +1079,10 @@ static int handle_tx_event(struct xhci_hcd *xhci,
if (event_trb == td->last_trb) { if (event_trb == td->last_trb) {
if (td->urb->actual_length != 0) { if (td->urb->actual_length != 0) {
/* Don't overwrite a previously set error code */ /* Don't overwrite a previously set error code */
if (status == -EINPROGRESS || status == 0) if ((status == -EINPROGRESS ||
status == 0) &&
(td->urb->transfer_flags
& URB_SHORT_NOT_OK))
/* Did we already see a short data stage? */ /* Did we already see a short data stage? */
status = -EREMOTEIO; status = -EREMOTEIO;
} else { } else {
@ -952,7 +1091,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
} }
} else { } else {
/* Maybe the event was for the data stage? */ /* Maybe the event was for the data stage? */
if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) { if (trb_comp_code != COMP_STOP_INVAL) {
/* We didn't stop on a link TRB in the middle */ /* We didn't stop on a link TRB in the middle */
td->urb->actual_length = td->urb->actual_length =
td->urb->transfer_buffer_length - td->urb->transfer_buffer_length -
@ -964,7 +1103,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
} }
} }
} else { } else {
switch (GET_COMP_CODE(event->transfer_len)) { switch (trb_comp_code) {
case COMP_SUCCESS: case COMP_SUCCESS:
/* Double check that the HW transferred everything. */ /* Double check that the HW transferred everything. */
if (event_trb != td->last_trb) { if (event_trb != td->last_trb) {
@ -975,7 +1114,12 @@ static int handle_tx_event(struct xhci_hcd *xhci,
else else
status = 0; status = 0;
} else { } else {
xhci_dbg(xhci, "Successful bulk transfer!\n"); if (usb_endpoint_xfer_bulk(&td->urb->ep->desc))
xhci_dbg(xhci, "Successful bulk "
"transfer!\n");
else
xhci_dbg(xhci, "Successful interrupt "
"transfer!\n");
status = 0; status = 0;
} }
break; break;
@ -1001,11 +1145,17 @@ static int handle_tx_event(struct xhci_hcd *xhci,
td->urb->actual_length = td->urb->actual_length =
td->urb->transfer_buffer_length - td->urb->transfer_buffer_length -
TRB_LEN(event->transfer_len); TRB_LEN(event->transfer_len);
if (td->urb->actual_length < 0) { if (td->urb->transfer_buffer_length <
td->urb->actual_length) {
xhci_warn(xhci, "HC gave bad length " xhci_warn(xhci, "HC gave bad length "
"of %d bytes left\n", "of %d bytes left\n",
TRB_LEN(event->transfer_len)); TRB_LEN(event->transfer_len));
td->urb->actual_length = 0; td->urb->actual_length = 0;
if (td->urb->transfer_flags &
URB_SHORT_NOT_OK)
status = -EREMOTEIO;
else
status = 0;
} }
/* Don't overwrite a previously set error code */ /* Don't overwrite a previously set error code */
if (status == -EINPROGRESS) { if (status == -EINPROGRESS) {
@ -1041,30 +1191,31 @@ static int handle_tx_event(struct xhci_hcd *xhci,
/* If the ring didn't stop on a Link or No-op TRB, add /* If the ring didn't stop on a Link or No-op TRB, add
* in the actual bytes transferred from the Normal TRB * in the actual bytes transferred from the Normal TRB
*/ */
if (GET_COMP_CODE(event->transfer_len) != COMP_STOP_INVAL) if (trb_comp_code != COMP_STOP_INVAL)
td->urb->actual_length += td->urb->actual_length +=
TRB_LEN(cur_trb->generic.field[2]) - TRB_LEN(cur_trb->generic.field[2]) -
TRB_LEN(event->transfer_len); TRB_LEN(event->transfer_len);
} }
} }
if (GET_COMP_CODE(event->transfer_len) == COMP_STOP_INVAL || if (trb_comp_code == COMP_STOP_INVAL ||
GET_COMP_CODE(event->transfer_len) == COMP_STOP) { trb_comp_code == COMP_STOP) {
/* The Endpoint Stop Command completion will take care of any /* The Endpoint Stop Command completion will take care of any
* stopped TDs. A stopped TD may be restarted, so don't update * stopped TDs. A stopped TD may be restarted, so don't update
* the ring dequeue pointer or take this TD off any lists yet. * the ring dequeue pointer or take this TD off any lists yet.
*/ */
ep_ring->stopped_td = td; ep->stopped_td = td;
ep_ring->stopped_trb = event_trb; ep->stopped_trb = event_trb;
} else { } else {
if (GET_COMP_CODE(event->transfer_len) == COMP_STALL) { if (trb_comp_code == COMP_STALL ||
trb_comp_code == COMP_BABBLE) {
/* The transfer is completed from the driver's /* The transfer is completed from the driver's
* perspective, but we need to issue a set dequeue * perspective, but we need to issue a set dequeue
* command for this stalled endpoint to move the dequeue * command for this stalled endpoint to move the dequeue
* pointer past the TD. We can't do that here because * pointer past the TD. We can't do that here because
* the halt condition must be cleared first. * the halt condition must be cleared first.
*/ */
ep_ring->stopped_td = td; ep->stopped_td = td;
ep_ring->stopped_trb = event_trb; ep->stopped_trb = event_trb;
} else { } else {
/* Update ring dequeue pointer */ /* Update ring dequeue pointer */
while (ep_ring->dequeue != td->last_trb) while (ep_ring->dequeue != td->last_trb)
@ -1072,16 +1223,41 @@ static int handle_tx_event(struct xhci_hcd *xhci,
inc_deq(xhci, ep_ring, false); inc_deq(xhci, ep_ring, false);
} }
td_cleanup:
/* Clean up the endpoint's TD list */ /* Clean up the endpoint's TD list */
urb = td->urb; urb = td->urb;
/* Do one last check of the actual transfer length.
* If the host controller said we transferred more data than
* the buffer length, urb->actual_length will be a very big
* number (since it's unsigned). Play it safe and say we didn't
* transfer anything.
*/
if (urb->actual_length > urb->transfer_buffer_length) {
xhci_warn(xhci, "URB transfer length is wrong, "
"xHC issue? req. len = %u, "
"act. len = %u\n",
urb->transfer_buffer_length,
urb->actual_length);
urb->actual_length = 0;
if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
status = -EREMOTEIO;
else
status = 0;
}
list_del(&td->td_list); list_del(&td->td_list);
/* Was this TD slated to be cancelled but completed anyway? */ /* Was this TD slated to be cancelled but completed anyway? */
if (!list_empty(&td->cancelled_td_list)) { if (!list_empty(&td->cancelled_td_list)) {
list_del(&td->cancelled_td_list); list_del(&td->cancelled_td_list);
ep_ring->cancels_pending--; ep->cancels_pending--;
} }
/* Leave the TD around for the reset endpoint function to use */ /* Leave the TD around for the reset endpoint function to use
if (GET_COMP_CODE(event->transfer_len) != COMP_STALL) { * (but only if it's not a control endpoint, since we already
* queued the Set TR dequeue pointer command for stalled
* control endpoints).
*/
if (usb_endpoint_xfer_control(&urb->ep->desc) ||
(trb_comp_code != COMP_STALL &&
trb_comp_code != COMP_BABBLE)) {
kfree(td); kfree(td);
} }
urb->hcpriv = NULL; urb->hcpriv = NULL;
@ -1094,7 +1270,7 @@ cleanup:
if (urb) { if (urb) {
usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb); usb_hcd_unlink_urb_from_ep(xhci_to_hcd(xhci), urb);
xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n", xhci_dbg(xhci, "Giveback URB %p, len = %d, status = %d\n",
urb, td->urb->actual_length, status); urb, urb->actual_length, status);
spin_unlock(&xhci->lock); spin_unlock(&xhci->lock);
usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status); usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, status);
spin_lock(&xhci->lock); spin_lock(&xhci->lock);
@ -1235,7 +1411,7 @@ static int prepare_transfer(struct xhci_hcd *xhci,
{ {
int ret; int ret;
struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index); struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
ret = prepare_ring(xhci, xdev->ep_rings[ep_index], ret = prepare_ring(xhci, xdev->eps[ep_index].ring,
ep_ctx->ep_info & EP_STATE_MASK, ep_ctx->ep_info & EP_STATE_MASK,
num_trbs, mem_flags); num_trbs, mem_flags);
if (ret) if (ret)
@ -1255,9 +1431,9 @@ static int prepare_transfer(struct xhci_hcd *xhci,
(*td)->urb = urb; (*td)->urb = urb;
urb->hcpriv = (void *) (*td); urb->hcpriv = (void *) (*td);
/* Add this TD to the tail of the endpoint ring's TD list */ /* Add this TD to the tail of the endpoint ring's TD list */
list_add_tail(&(*td)->td_list, &xdev->ep_rings[ep_index]->td_list); list_add_tail(&(*td)->td_list, &xdev->eps[ep_index].ring->td_list);
(*td)->start_seg = xdev->ep_rings[ep_index]->enq_seg; (*td)->start_seg = xdev->eps[ep_index].ring->enq_seg;
(*td)->first_trb = xdev->ep_rings[ep_index]->enqueue; (*td)->first_trb = xdev->eps[ep_index].ring->enqueue;
return 0; return 0;
} }
@ -1335,6 +1511,47 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
ring_ep_doorbell(xhci, slot_id, ep_index); ring_ep_doorbell(xhci, slot_id, ep_index);
} }
/*
* xHCI uses normal TRBs for both bulk and interrupt. When the interrupt
* endpoint is to be serviced, the xHC will consume (at most) one TD. A TD
* (comprised of sg list entries) can take several service intervals to
* transmit.
*/
int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index)
{
struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci,
xhci->devs[slot_id]->out_ctx, ep_index);
int xhci_interval;
int ep_interval;
xhci_interval = EP_INTERVAL_TO_UFRAMES(ep_ctx->ep_info);
ep_interval = urb->interval;
/* Convert to microframes */
if (urb->dev->speed == USB_SPEED_LOW ||
urb->dev->speed == USB_SPEED_FULL)
ep_interval *= 8;
/* FIXME change this to a warning and a suggestion to use the new API
* to set the polling interval (once the API is added).
*/
if (xhci_interval != ep_interval) {
if (!printk_ratelimit())
dev_dbg(&urb->dev->dev, "Driver uses different interval"
" (%d microframe%s) than xHCI "
"(%d microframe%s)\n",
ep_interval,
ep_interval == 1 ? "" : "s",
xhci_interval,
xhci_interval == 1 ? "" : "s");
urb->interval = xhci_interval;
/* Convert back to frames for LS/FS devices */
if (urb->dev->speed == USB_SPEED_LOW ||
urb->dev->speed == USB_SPEED_FULL)
urb->interval /= 8;
}
return xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
}
static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags, static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct urb *urb, int slot_id, unsigned int ep_index) struct urb *urb, int slot_id, unsigned int ep_index)
{ {
@ -1350,7 +1567,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
struct xhci_generic_trb *start_trb; struct xhci_generic_trb *start_trb;
int start_cycle; int start_cycle;
ep_ring = xhci->devs[slot_id]->ep_rings[ep_index]; ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
num_trbs = count_sg_trbs_needed(xhci, urb); num_trbs = count_sg_trbs_needed(xhci, urb);
num_sgs = urb->num_sgs; num_sgs = urb->num_sgs;
@ -1483,7 +1700,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
if (urb->sg) if (urb->sg)
return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index); return queue_bulk_sg_tx(xhci, mem_flags, urb, slot_id, ep_index);
ep_ring = xhci->devs[slot_id]->ep_rings[ep_index]; ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
num_trbs = 0; num_trbs = 0;
/* How much data is (potentially) left before the 64KB boundary? */ /* How much data is (potentially) left before the 64KB boundary? */
@ -1594,7 +1811,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
u32 field, length_field; u32 field, length_field;
struct xhci_td *td; struct xhci_td *td;
ep_ring = xhci->devs[slot_id]->ep_rings[ep_index]; ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
/* /*
* Need to copy setup packet into setup TRB, so we can't use the setup * Need to copy setup packet into setup TRB, so we can't use the setup
@ -1677,12 +1894,27 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/**** Command Ring Operations ****/ /**** Command Ring Operations ****/
/* Generic function for queueing a command TRB on the command ring */ /* Generic function for queueing a command TRB on the command ring.
static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, u32 field3, u32 field4) * Check to make sure there's room on the command ring for one command TRB.
* Also check that there's room reserved for commands that must not fail.
* If this is a command that must not fail, meaning command_must_succeed = TRUE,
* then only check for the number of reserved spots.
* Don't decrement xhci->cmd_ring_reserved_trbs after we've queued the TRB
* because the command event handler may want to resubmit a failed command.
*/
static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2,
u32 field3, u32 field4, bool command_must_succeed)
{ {
if (!room_on_ring(xhci, xhci->cmd_ring, 1)) { int reserved_trbs = xhci->cmd_ring_reserved_trbs;
if (!command_must_succeed)
reserved_trbs++;
if (!room_on_ring(xhci, xhci->cmd_ring, reserved_trbs)) {
if (!in_interrupt()) if (!in_interrupt())
xhci_err(xhci, "ERR: No room for command on command ring\n"); xhci_err(xhci, "ERR: No room for command on command ring\n");
if (command_must_succeed)
xhci_err(xhci, "ERR: Reserved TRB counting for "
"unfailable commands failed.\n");
return -ENOMEM; return -ENOMEM;
} }
queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3, queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3,
@ -1693,7 +1925,7 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2, u32 fiel
/* Queue a no-op command on the command ring */ /* Queue a no-op command on the command ring */
static int queue_cmd_noop(struct xhci_hcd *xhci) static int queue_cmd_noop(struct xhci_hcd *xhci)
{ {
return queue_command(xhci, 0, 0, 0, TRB_TYPE(TRB_CMD_NOOP)); return queue_command(xhci, 0, 0, 0, TRB_TYPE(TRB_CMD_NOOP), false);
} }
/* /*
@ -1712,7 +1944,7 @@ void *xhci_setup_one_noop(struct xhci_hcd *xhci)
int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id) int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id)
{ {
return queue_command(xhci, 0, 0, 0, return queue_command(xhci, 0, 0, 0,
TRB_TYPE(trb_type) | SLOT_ID_FOR_TRB(slot_id)); TRB_TYPE(trb_type) | SLOT_ID_FOR_TRB(slot_id), false);
} }
/* Queue an address device command TRB */ /* Queue an address device command TRB */
@ -1721,16 +1953,28 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
{ {
return queue_command(xhci, lower_32_bits(in_ctx_ptr), return queue_command(xhci, lower_32_bits(in_ctx_ptr),
upper_32_bits(in_ctx_ptr), 0, upper_32_bits(in_ctx_ptr), 0,
TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id)); TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id),
false);
} }
/* Queue a configure endpoint command TRB */ /* Queue a configure endpoint command TRB */
int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id, bool command_must_succeed)
{
return queue_command(xhci, lower_32_bits(in_ctx_ptr),
upper_32_bits(in_ctx_ptr), 0,
TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id),
command_must_succeed);
}
/* Queue an evaluate context command TRB */
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id) u32 slot_id)
{ {
return queue_command(xhci, lower_32_bits(in_ctx_ptr), return queue_command(xhci, lower_32_bits(in_ctx_ptr),
upper_32_bits(in_ctx_ptr), 0, upper_32_bits(in_ctx_ptr), 0,
TRB_TYPE(TRB_CONFIG_EP) | SLOT_ID_FOR_TRB(slot_id)); TRB_TYPE(TRB_EVAL_CONTEXT) | SLOT_ID_FOR_TRB(slot_id),
false);
} }
int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
@ -1741,7 +1985,7 @@ int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
u32 type = TRB_TYPE(TRB_STOP_RING); u32 type = TRB_TYPE(TRB_STOP_RING);
return queue_command(xhci, 0, 0, 0, return queue_command(xhci, 0, 0, 0,
trb_slot_id | trb_ep_index | type); trb_slot_id | trb_ep_index | type, false);
} }
/* Set Transfer Ring Dequeue Pointer command. /* Set Transfer Ring Dequeue Pointer command.
@ -1765,7 +2009,7 @@ static int queue_set_tr_deq(struct xhci_hcd *xhci, int slot_id,
} }
return queue_command(xhci, lower_32_bits(addr) | cycle_state, return queue_command(xhci, lower_32_bits(addr) | cycle_state,
upper_32_bits(addr), 0, upper_32_bits(addr), 0,
trb_slot_id | trb_ep_index | type); trb_slot_id | trb_ep_index | type, false);
} }
int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
@ -1775,5 +2019,6 @@ int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
u32 trb_ep_index = EP_ID_FOR_TRB(ep_index); u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
u32 type = TRB_TYPE(TRB_RESET_EP); u32 type = TRB_TYPE(TRB_RESET_EP);
return queue_command(xhci, 0, 0, 0, trb_slot_id | trb_ep_index | type); return queue_command(xhci, 0, 0, 0, trb_slot_id | trb_ep_index | type,
false);
} }

View File

@ -509,6 +509,8 @@ struct xhci_slot_ctx {
#define MAX_EXIT (0xffff) #define MAX_EXIT (0xffff)
/* Root hub port number that is needed to access the USB device */ /* Root hub port number that is needed to access the USB device */
#define ROOT_HUB_PORT(p) (((p) & 0xff) << 16) #define ROOT_HUB_PORT(p) (((p) & 0xff) << 16)
/* Maximum number of ports under a hub device */
#define XHCI_MAX_PORTS(p) (((p) & 0xff) << 24)
/* tt_info bitmasks */ /* tt_info bitmasks */
/* /*
@ -522,6 +524,7 @@ struct xhci_slot_ctx {
* '0' if the device is not low or full speed. * '0' if the device is not low or full speed.
*/ */
#define TT_PORT (0xff << 8) #define TT_PORT (0xff << 8)
#define TT_THINK_TIME(p) (((p) & 0x3) << 16)
/* dev_state bitmasks */ /* dev_state bitmasks */
/* USB device address - assigned by the HC */ /* USB device address - assigned by the HC */
@ -581,6 +584,7 @@ struct xhci_ep_ctx {
/* bit 15 is Linear Stream Array */ /* bit 15 is Linear Stream Array */
/* Interval - period between requests to an endpoint - 125u increments. */ /* Interval - period between requests to an endpoint - 125u increments. */
#define EP_INTERVAL(p) ((p & 0xff) << 16) #define EP_INTERVAL(p) ((p & 0xff) << 16)
#define EP_INTERVAL_TO_UFRAMES(p) (1 << (((p) >> 16) & 0xff))
/* ep_info2 bitmasks */ /* ep_info2 bitmasks */
/* /*
@ -589,6 +593,7 @@ struct xhci_ep_ctx {
*/ */
#define FORCE_EVENT (0x1) #define FORCE_EVENT (0x1)
#define ERROR_COUNT(p) (((p) & 0x3) << 1) #define ERROR_COUNT(p) (((p) & 0x3) << 1)
#define CTX_TO_EP_TYPE(p) (((p) >> 3) & 0x7)
#define EP_TYPE(p) ((p) << 3) #define EP_TYPE(p) ((p) << 3)
#define ISOC_OUT_EP 1 #define ISOC_OUT_EP 1
#define BULK_OUT_EP 2 #define BULK_OUT_EP 2
@ -601,6 +606,8 @@ struct xhci_ep_ctx {
/* bit 7 is Host Initiate Disable - for disabling stream selection */ /* bit 7 is Host Initiate Disable - for disabling stream selection */
#define MAX_BURST(p) (((p)&0xff) << 8) #define MAX_BURST(p) (((p)&0xff) << 8)
#define MAX_PACKET(p) (((p)&0xffff) << 16) #define MAX_PACKET(p) (((p)&0xffff) << 16)
#define MAX_PACKET_MASK (0xffff << 16)
#define MAX_PACKET_DECODED(p) (((p) >> 16) & 0xffff)
/** /**
@ -616,11 +623,44 @@ struct xhci_input_control_ctx {
u32 rsvd2[6]; u32 rsvd2[6];
}; };
/* Represents everything that is needed to issue a command on the command ring.
* It's useful to pre-allocate these for commands that cannot fail due to
* out-of-memory errors, like freeing streams.
*/
struct xhci_command {
/* Input context for changing device state */
struct xhci_container_ctx *in_ctx;
u32 status;
/* If completion is null, no one is waiting on this command
* and the structure can be freed after the command completes.
*/
struct completion *completion;
union xhci_trb *command_trb;
struct list_head cmd_list;
};
/* drop context bitmasks */ /* drop context bitmasks */
#define DROP_EP(x) (0x1 << x) #define DROP_EP(x) (0x1 << x)
/* add context bitmasks */ /* add context bitmasks */
#define ADD_EP(x) (0x1 << x) #define ADD_EP(x) (0x1 << x)
struct xhci_virt_ep {
struct xhci_ring *ring;
/* Temporary storage in case the configure endpoint command fails and we
* have to restore the device state to the previous state
*/
struct xhci_ring *new_ring;
unsigned int ep_state;
#define SET_DEQ_PENDING (1 << 0)
#define EP_HALTED (1 << 1)
/* ---- Related to URB cancellation ---- */
struct list_head cancelled_td_list;
unsigned int cancels_pending;
/* The TRB that was last reported in a stopped endpoint ring */
union xhci_trb *stopped_trb;
struct xhci_td *stopped_td;
};
struct xhci_virt_device { struct xhci_virt_device {
/* /*
* Commands to the hardware are passed an "input context" that * Commands to the hardware are passed an "input context" that
@ -633,16 +673,11 @@ struct xhci_virt_device {
struct xhci_container_ctx *out_ctx; struct xhci_container_ctx *out_ctx;
/* Used for addressing devices and configuration changes */ /* Used for addressing devices and configuration changes */
struct xhci_container_ctx *in_ctx; struct xhci_container_ctx *in_ctx;
struct xhci_virt_ep eps[31];
/* FIXME when stream support is added */
struct xhci_ring *ep_rings[31];
/* Temporary storage in case the configure endpoint command fails and we
* have to restore the device state to the previous state
*/
struct xhci_ring *new_ep_rings[31];
struct completion cmd_completion; struct completion cmd_completion;
/* Status of the last command issued for this device */ /* Status of the last command issued for this device */
u32 cmd_status; u32 cmd_status;
struct list_head cmd_list;
}; };
@ -905,6 +940,8 @@ union xhci_trb {
* It must also be greater than 16. * It must also be greater than 16.
*/ */
#define TRBS_PER_SEGMENT 64 #define TRBS_PER_SEGMENT 64
/* Allow two commands + a link TRB, along with any reserved command TRBs */
#define MAX_RSVD_CMD_TRBS (TRBS_PER_SEGMENT - 3)
#define SEGMENT_SIZE (TRBS_PER_SEGMENT*16) #define SEGMENT_SIZE (TRBS_PER_SEGMENT*16)
/* TRB buffer pointers can't cross 64KB boundaries */ /* TRB buffer pointers can't cross 64KB boundaries */
#define TRB_MAX_BUFF_SHIFT 16 #define TRB_MAX_BUFF_SHIFT 16
@ -926,6 +963,12 @@ struct xhci_td {
union xhci_trb *last_trb; union xhci_trb *last_trb;
}; };
struct xhci_dequeue_state {
struct xhci_segment *new_deq_seg;
union xhci_trb *new_deq_ptr;
int new_cycle_state;
};
struct xhci_ring { struct xhci_ring {
struct xhci_segment *first_seg; struct xhci_segment *first_seg;
union xhci_trb *enqueue; union xhci_trb *enqueue;
@ -935,15 +978,6 @@ struct xhci_ring {
struct xhci_segment *deq_seg; struct xhci_segment *deq_seg;
unsigned int deq_updates; unsigned int deq_updates;
struct list_head td_list; struct list_head td_list;
/* ---- Related to URB cancellation ---- */
struct list_head cancelled_td_list;
unsigned int cancels_pending;
unsigned int state;
#define SET_DEQ_PENDING (1 << 0)
#define EP_HALTED (1 << 1)
/* The TRB that was last reported in a stopped endpoint ring */
union xhci_trb *stopped_trb;
struct xhci_td *stopped_td;
/* /*
* Write the cycle state into the TRB cycle field to give ownership of * Write the cycle state into the TRB cycle field to give ownership of
* the TRB to the host controller (if we are the producer), or to check * the TRB to the host controller (if we are the producer), or to check
@ -952,12 +986,6 @@ struct xhci_ring {
u32 cycle_state; u32 cycle_state;
}; };
struct xhci_dequeue_state {
struct xhci_segment *new_deq_seg;
union xhci_trb *new_deq_ptr;
int new_cycle_state;
};
struct xhci_erst_entry { struct xhci_erst_entry {
/* 64-bit event ring segment address */ /* 64-bit event ring segment address */
u64 seg_addr; u64 seg_addr;
@ -1034,6 +1062,7 @@ struct xhci_hcd {
/* data structures */ /* data structures */
struct xhci_device_context_array *dcbaa; struct xhci_device_context_array *dcbaa;
struct xhci_ring *cmd_ring; struct xhci_ring *cmd_ring;
unsigned int cmd_ring_reserved_trbs;
struct xhci_ring *event_ring; struct xhci_ring *event_ring;
struct xhci_erst erst; struct xhci_erst erst;
/* Scratchpad */ /* Scratchpad */
@ -1058,6 +1087,9 @@ struct xhci_hcd {
int noops_submitted; int noops_submitted;
int noops_handled; int noops_handled;
int error_bitmask; int error_bitmask;
unsigned int quirks;
#define XHCI_LINK_TRB_QUIRK (1 << 0)
#define XHCI_RESET_EP_QUIRK (1 << 1)
}; };
/* For testing purposes */ /* For testing purposes */
@ -1136,6 +1168,13 @@ static inline void xhci_write_64(struct xhci_hcd *xhci,
writel(val_hi, ptr + 1); writel(val_hi, ptr + 1);
} }
static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci)
{
u32 temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
return ((HC_VERSION(temp) == 0x95) &&
(xhci->quirks & XHCI_LINK_TRB_QUIRK));
}
/* xHCI debugging */ /* xHCI debugging */
void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num); void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num);
void xhci_print_registers(struct xhci_hcd *xhci); void xhci_print_registers(struct xhci_hcd *xhci);
@ -1158,11 +1197,24 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device
int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev); int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev);
unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc); unsigned int xhci_get_endpoint_index(struct usb_endpoint_descriptor *desc);
unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc); unsigned int xhci_get_endpoint_flag(struct usb_endpoint_descriptor *desc);
unsigned int xhci_get_endpoint_flag_from_index(unsigned int ep_index);
unsigned int xhci_last_valid_endpoint(u32 added_ctxs);
void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep); void xhci_endpoint_zero(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, struct usb_host_endpoint *ep);
void xhci_endpoint_copy(struct xhci_hcd *xhci,
struct xhci_container_ctx *in_ctx,
struct xhci_container_ctx *out_ctx,
unsigned int ep_index);
void xhci_slot_copy(struct xhci_hcd *xhci,
struct xhci_container_ctx *in_ctx,
struct xhci_container_ctx *out_ctx);
int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev, int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev,
struct usb_device *udev, struct usb_host_endpoint *ep, struct usb_device *udev, struct usb_host_endpoint *ep,
gfp_t mem_flags); gfp_t mem_flags);
void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring); void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
bool allocate_completion, gfp_t mem_flags);
void xhci_free_command(struct xhci_hcd *xhci,
struct xhci_command *command);
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
/* xHCI PCI glue */ /* xHCI PCI glue */
@ -1182,6 +1234,8 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd);
int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev);
void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev); void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev);
int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev); int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev);
int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
struct usb_tt *tt, gfp_t mem_flags);
int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags); int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status); int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep); int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
@ -1205,7 +1259,11 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
int slot_id, unsigned int ep_index); int slot_id, unsigned int ep_index);
int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb, int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
int slot_id, unsigned int ep_index); int slot_id, unsigned int ep_index);
int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
int slot_id, unsigned int ep_index);
int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id, bool command_must_succeed);
int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id); u32 slot_id);
int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
unsigned int ep_index); unsigned int ep_index);
@ -1213,8 +1271,13 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index, unsigned int slot_id, unsigned int ep_index,
struct xhci_td *cur_td, struct xhci_dequeue_state *state); struct xhci_td *cur_td, struct xhci_dequeue_state *state);
void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci, void xhci_queue_new_dequeue_state(struct xhci_hcd *xhci,
struct xhci_ring *ep_ring, unsigned int slot_id, unsigned int slot_id, unsigned int ep_index,
unsigned int ep_index, struct xhci_dequeue_state *deq_state); struct xhci_dequeue_state *deq_state);
void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci,
struct usb_device *udev, unsigned int ep_index);
void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,
unsigned int slot_id, unsigned int ep_index,
struct xhci_dequeue_state *deq_state);
/* xHCI roothub code */ /* xHCI roothub code */
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,

View File

@ -653,33 +653,6 @@ static struct scsi_host_template mts_scsi_host_template = {
.max_sectors= 256, /* 128 K */ .max_sectors= 256, /* 128 K */
}; };
struct vendor_product
{
char* name;
enum
{
mts_sup_unknown=0,
mts_sup_alpha,
mts_sup_full
}
support_status;
} ;
/* These are taken from the msmUSB.inf file on the Windows driver CD */
static const struct vendor_product mts_supported_products[] =
{
{ "Phantom 336CX", mts_sup_unknown},
{ "Phantom 336CX", mts_sup_unknown},
{ "Scanmaker X6", mts_sup_alpha},
{ "Phantom C6", mts_sup_unknown},
{ "Phantom 336CX", mts_sup_unknown},
{ "ScanMaker V6USL", mts_sup_unknown},
{ "ScanMaker V6USL", mts_sup_unknown},
{ "Scanmaker V6UL", mts_sup_unknown},
{ "Scanmaker V6UPL", mts_sup_alpha},
};
/* The entries of microtek_table must correspond, line-by-line to /* The entries of microtek_table must correspond, line-by-line to
the entries of mts_supported_products[]. */ the entries of mts_supported_products[]. */
@ -711,7 +684,6 @@ static int mts_usb_probe(struct usb_interface *intf,
int err_retval = -ENOMEM; int err_retval = -ENOMEM;
struct mts_desc * new_desc; struct mts_desc * new_desc;
struct vendor_product const* p;
struct usb_device *dev = interface_to_usbdev (intf); struct usb_device *dev = interface_to_usbdev (intf);
/* the current altsetting on the interface we're probing */ /* the current altsetting on the interface we're probing */
@ -726,15 +698,6 @@ static int mts_usb_probe(struct usb_interface *intf,
MTS_DEBUG_GOT_HERE(); MTS_DEBUG_GOT_HERE();
p = &mts_supported_products[id - mts_usb_ids];
MTS_DEBUG_GOT_HERE();
MTS_DEBUG( "found model %s\n", p->name );
if ( p->support_status != mts_sup_full )
MTS_MESSAGE( "model %s is not known to be fully supported, reports welcome!\n",
p->name );
/* the current altsetting on the interface we're probing */ /* the current altsetting on the interface we're probing */
altsetting = intf->cur_altsetting; altsetting = intf->cur_altsetting;

View File

@ -96,6 +96,8 @@ static int idmouse_probe(struct usb_interface *interface,
const struct usb_device_id *id); const struct usb_device_id *id);
static void idmouse_disconnect(struct usb_interface *interface); static void idmouse_disconnect(struct usb_interface *interface);
static int idmouse_suspend(struct usb_interface *intf, pm_message_t message);
static int idmouse_resume(struct usb_interface *intf);
/* file operation pointers */ /* file operation pointers */
static const struct file_operations idmouse_fops = { static const struct file_operations idmouse_fops = {
@ -117,7 +119,11 @@ static struct usb_driver idmouse_driver = {
.name = DRIVER_SHORT, .name = DRIVER_SHORT,
.probe = idmouse_probe, .probe = idmouse_probe,
.disconnect = idmouse_disconnect, .disconnect = idmouse_disconnect,
.suspend = idmouse_suspend,
.resume = idmouse_resume,
.reset_resume = idmouse_resume,
.id_table = idmouse_table, .id_table = idmouse_table,
.supports_autosuspend = 1,
}; };
static int idmouse_create_image(struct usb_idmouse *dev) static int idmouse_create_image(struct usb_idmouse *dev)
@ -197,6 +203,17 @@ reset:
return result; return result;
} }
/* PM operations are nops as this driver does IO only during open() */
static int idmouse_suspend(struct usb_interface *intf, pm_message_t message)
{
return 0;
}
static int idmouse_resume(struct usb_interface *intf)
{
return 0;
}
static inline void idmouse_delete(struct usb_idmouse *dev) static inline void idmouse_delete(struct usb_idmouse *dev)
{ {
kfree(dev->bulk_in_buffer); kfree(dev->bulk_in_buffer);
@ -235,9 +252,13 @@ static int idmouse_open(struct inode *inode, struct file *file)
} else { } else {
/* create a new image and check for success */ /* create a new image and check for success */
result = usb_autopm_get_interface(interface);
if (result)
goto error;
result = idmouse_create_image (dev); result = idmouse_create_image (dev);
if (result) if (result)
goto error; goto error;
usb_autopm_put_interface(interface);
/* increment our usage count for the driver */ /* increment our usage count for the driver */
++dev->open; ++dev->open;

View File

@ -412,6 +412,9 @@ static unsigned int ld_usb_poll(struct file *file, poll_table *wait)
dev = file->private_data; dev = file->private_data;
if (!dev->intf)
return POLLERR | POLLHUP;
poll_wait(file, &dev->read_wait, wait); poll_wait(file, &dev->read_wait, wait);
poll_wait(file, &dev->write_wait, wait); poll_wait(file, &dev->write_wait, wait);
@ -767,6 +770,9 @@ static void ld_usb_disconnect(struct usb_interface *intf)
ld_usb_delete(dev); ld_usb_delete(dev);
} else { } else {
dev->intf = NULL; dev->intf = NULL;
/* wake up pollers */
wake_up_interruptible_all(&dev->read_wait);
wake_up_interruptible_all(&dev->write_wait);
mutex_unlock(&dev->mutex); mutex_unlock(&dev->mutex);
} }

View File

@ -552,6 +552,9 @@ static unsigned int tower_poll (struct file *file, poll_table *wait)
dev = file->private_data; dev = file->private_data;
if (!dev->udev)
return POLLERR | POLLHUP;
poll_wait(file, &dev->read_wait, wait); poll_wait(file, &dev->read_wait, wait);
poll_wait(file, &dev->write_wait, wait); poll_wait(file, &dev->write_wait, wait);
@ -1025,6 +1028,9 @@ static void tower_disconnect (struct usb_interface *interface)
tower_delete (dev); tower_delete (dev);
} else { } else {
dev->udev = NULL; dev->udev = NULL;
/* wake up pollers */
wake_up_interruptible_all(&dev->read_wait);
wake_up_interruptible_all(&dev->write_wait);
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
} }

View File

@ -79,14 +79,12 @@ sisusb_free_buffers(struct sisusb_usb_data *sisusb)
for (i = 0; i < NUMOBUFS; i++) { for (i = 0; i < NUMOBUFS; i++) {
if (sisusb->obuf[i]) { if (sisusb->obuf[i]) {
usb_buffer_free(sisusb->sisusb_dev, sisusb->obufsize, kfree(sisusb->obuf[i]);
sisusb->obuf[i], sisusb->transfer_dma_out[i]);
sisusb->obuf[i] = NULL; sisusb->obuf[i] = NULL;
} }
} }
if (sisusb->ibuf) { if (sisusb->ibuf) {
usb_buffer_free(sisusb->sisusb_dev, sisusb->ibufsize, kfree(sisusb->ibuf);
sisusb->ibuf, sisusb->transfer_dma_in);
sisusb->ibuf = NULL; sisusb->ibuf = NULL;
} }
} }
@ -230,8 +228,7 @@ sisusb_bulk_completeout(struct urb *urb)
static int static int
sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data, sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe, void *data,
int len, int *actual_length, int timeout, unsigned int tflags, int len, int *actual_length, int timeout, unsigned int tflags)
dma_addr_t transfer_dma)
{ {
struct urb *urb = sisusb->sisurbout[index]; struct urb *urb = sisusb->sisurbout[index];
int retval, byteswritten = 0; int retval, byteswritten = 0;
@ -245,9 +242,6 @@ sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe,
urb->transfer_flags |= tflags; urb->transfer_flags |= tflags;
urb->actual_length = 0; urb->actual_length = 0;
if ((urb->transfer_dma = transfer_dma))
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/* Set up context */ /* Set up context */
sisusb->urbout_context[index].actual_length = (timeout) ? sisusb->urbout_context[index].actual_length = (timeout) ?
NULL : actual_length; NULL : actual_length;
@ -297,8 +291,8 @@ sisusb_bulk_completein(struct urb *urb)
} }
static int static int
sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data, int len, sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data,
int *actual_length, int timeout, unsigned int tflags, dma_addr_t transfer_dma) int len, int *actual_length, int timeout, unsigned int tflags)
{ {
struct urb *urb = sisusb->sisurbin; struct urb *urb = sisusb->sisurbin;
int retval, readbytes = 0; int retval, readbytes = 0;
@ -311,9 +305,6 @@ sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data,
urb->transfer_flags |= tflags; urb->transfer_flags |= tflags;
urb->actual_length = 0; urb->actual_length = 0;
if ((urb->transfer_dma = transfer_dma))
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
sisusb->completein = 0; sisusb->completein = 0;
retval = usb_submit_urb(urb, GFP_ATOMIC); retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval == 0) { if (retval == 0) {
@ -422,8 +413,7 @@ static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
thispass, thispass,
&transferred_len, &transferred_len,
async ? 0 : 5 * HZ, async ? 0 : 5 * HZ,
tflags, tflags);
sisusb->transfer_dma_out[index]);
if (result == -ETIMEDOUT) { if (result == -ETIMEDOUT) {
@ -432,29 +422,16 @@ static int sisusb_send_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
return -ETIME; return -ETIME;
continue; continue;
}
} else if ((result == 0) && !async && transferred_len) { if ((result == 0) && !async && transferred_len) {
thispass -= transferred_len; thispass -= transferred_len;
if (thispass) { buffer += transferred_len;
if (sisusb->transfer_dma_out) {
/* If DMA, copy remaining
* to beginning of buffer
*/
memcpy(buffer,
buffer + transferred_len,
thispass);
} else {
/* If not DMA, simply increase
* the pointer
*/
buffer += transferred_len;
}
}
} else } else
break; break;
}; }
if (result) if (result)
return result; return result;
@ -530,8 +507,7 @@ static int sisusb_recv_bulk_msg(struct sisusb_usb_data *sisusb, int ep, int len,
thispass, thispass,
&transferred_len, &transferred_len,
5 * HZ, 5 * HZ,
tflags, tflags);
sisusb->transfer_dma_in);
if (transferred_len) if (transferred_len)
thispass = transferred_len; thispass = transferred_len;
@ -3132,8 +3108,7 @@ static int sisusb_probe(struct usb_interface *intf,
/* Allocate buffers */ /* Allocate buffers */
sisusb->ibufsize = SISUSB_IBUF_SIZE; sisusb->ibufsize = SISUSB_IBUF_SIZE;
if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE, if (!(sisusb->ibuf = kmalloc(SISUSB_IBUF_SIZE, GFP_KERNEL))) {
GFP_KERNEL, &sisusb->transfer_dma_in))) {
dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer"); dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer");
retval = -ENOMEM; retval = -ENOMEM;
goto error_2; goto error_2;
@ -3142,9 +3117,7 @@ static int sisusb_probe(struct usb_interface *intf,
sisusb->numobufs = 0; sisusb->numobufs = 0;
sisusb->obufsize = SISUSB_OBUF_SIZE; sisusb->obufsize = SISUSB_OBUF_SIZE;
for (i = 0; i < NUMOBUFS; i++) { for (i = 0; i < NUMOBUFS; i++) {
if (!(sisusb->obuf[i] = usb_buffer_alloc(dev, SISUSB_OBUF_SIZE, if (!(sisusb->obuf[i] = kmalloc(SISUSB_OBUF_SIZE, GFP_KERNEL))) {
GFP_KERNEL,
&sisusb->transfer_dma_out[i]))) {
if (i == 0) { if (i == 0) {
dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n"); dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
retval = -ENOMEM; retval = -ENOMEM;

View File

@ -123,8 +123,6 @@ struct sisusb_usb_data {
int numobufs; /* number of obufs = number of out urbs */ int numobufs; /* number of obufs = number of out urbs */
char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */ char *obuf[NUMOBUFS], *ibuf; /* transfer buffers */
int obufsize, ibufsize; int obufsize, ibufsize;
dma_addr_t transfer_dma_out[NUMOBUFS];
dma_addr_t transfer_dma_in;
struct urb *sisurbout[NUMOBUFS]; struct urb *sisurbout[NUMOBUFS];
struct urb *sisurbin; struct urb *sisurbin;
unsigned char urbstatus[NUMOBUFS]; unsigned char urbstatus[NUMOBUFS];

View File

@ -38,6 +38,7 @@ static char *display_textmodes[] = {"raw", "hex", "ascii", NULL};
struct usb_sevsegdev { struct usb_sevsegdev {
struct usb_device *udev; struct usb_device *udev;
struct usb_interface *intf;
u8 powered; u8 powered;
u8 mode_msb; u8 mode_msb;
@ -46,6 +47,8 @@ struct usb_sevsegdev {
u8 textmode; u8 textmode;
u8 text[MAXLEN]; u8 text[MAXLEN];
u16 textlength; u16 textlength;
u8 shadow_power; /* for PM */
}; };
/* sysfs_streq can't replace this completely /* sysfs_streq can't replace this completely
@ -65,6 +68,12 @@ static void update_display_powered(struct usb_sevsegdev *mydev)
{ {
int rc; int rc;
if (!mydev->shadow_power && mydev->powered) {
rc = usb_autopm_get_interface(mydev->intf);
if (rc < 0)
return;
}
rc = usb_control_msg(mydev->udev, rc = usb_control_msg(mydev->udev,
usb_sndctrlpipe(mydev->udev, 0), usb_sndctrlpipe(mydev->udev, 0),
0x12, 0x12,
@ -76,12 +85,18 @@ static void update_display_powered(struct usb_sevsegdev *mydev)
2000); 2000);
if (rc < 0) if (rc < 0)
dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc); dev_dbg(&mydev->udev->dev, "power retval = %d\n", rc);
if (mydev->shadow_power && !mydev->powered)
usb_autopm_put_interface(mydev->intf);
} }
static void update_display_mode(struct usb_sevsegdev *mydev) static void update_display_mode(struct usb_sevsegdev *mydev)
{ {
int rc; int rc;
if(mydev->shadow_power != 1)
return;
rc = usb_control_msg(mydev->udev, rc = usb_control_msg(mydev->udev,
usb_sndctrlpipe(mydev->udev, 0), usb_sndctrlpipe(mydev->udev, 0),
0x12, 0x12,
@ -96,14 +111,17 @@ static void update_display_mode(struct usb_sevsegdev *mydev)
dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc); dev_dbg(&mydev->udev->dev, "mode retval = %d\n", rc);
} }
static void update_display_visual(struct usb_sevsegdev *mydev) static void update_display_visual(struct usb_sevsegdev *mydev, gfp_t mf)
{ {
int rc; int rc;
int i; int i;
unsigned char *buffer; unsigned char *buffer;
u8 decimals = 0; u8 decimals = 0;
buffer = kzalloc(MAXLEN, GFP_KERNEL); if(mydev->shadow_power != 1)
return;
buffer = kzalloc(MAXLEN, mf);
if (!buffer) { if (!buffer) {
dev_err(&mydev->udev->dev, "out of memory\n"); dev_err(&mydev->udev->dev, "out of memory\n");
return; return;
@ -163,7 +181,7 @@ static ssize_t set_attr_##name(struct device *dev, \
struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \ struct usb_sevsegdev *mydev = usb_get_intfdata(intf); \
\ \
mydev->name = simple_strtoul(buf, NULL, 10); \ mydev->name = simple_strtoul(buf, NULL, 10); \
update_fcn(mydev); \ update_fcn(mydev); \
\ \
return count; \ return count; \
} \ } \
@ -194,7 +212,7 @@ static ssize_t set_attr_text(struct device *dev,
if (end > 0) if (end > 0)
memcpy(mydev->text, buf, end); memcpy(mydev->text, buf, end);
update_display_visual(mydev); update_display_visual(mydev, GFP_KERNEL);
return count; return count;
} }
@ -242,7 +260,7 @@ static ssize_t set_attr_decimals(struct device *dev,
if (buf[i] == '1') if (buf[i] == '1')
mydev->decimals[end-1-i] = 1; mydev->decimals[end-1-i] = 1;
update_display_visual(mydev); update_display_visual(mydev, GFP_KERNEL);
return count; return count;
} }
@ -286,7 +304,7 @@ static ssize_t set_attr_textmode(struct device *dev,
for (i = 0; display_textmodes[i]; i++) { for (i = 0; display_textmodes[i]; i++) {
if (sysfs_streq(display_textmodes[i], buf)) { if (sysfs_streq(display_textmodes[i], buf)) {
mydev->textmode = i; mydev->textmode = i;
update_display_visual(mydev); update_display_visual(mydev, GFP_KERNEL);
return count; return count;
} }
} }
@ -330,6 +348,7 @@ static int sevseg_probe(struct usb_interface *interface,
} }
mydev->udev = usb_get_dev(udev); mydev->udev = usb_get_dev(udev);
mydev->intf = interface;
usb_set_intfdata(interface, mydev); usb_set_intfdata(interface, mydev);
/*set defaults */ /*set defaults */
@ -364,11 +383,49 @@ static void sevseg_disconnect(struct usb_interface *interface)
dev_info(&interface->dev, "USB 7 Segment now disconnected\n"); dev_info(&interface->dev, "USB 7 Segment now disconnected\n");
} }
static int sevseg_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usb_sevsegdev *mydev;
mydev = usb_get_intfdata(intf);
mydev->shadow_power = 0;
return 0;
}
static int sevseg_resume(struct usb_interface *intf)
{
struct usb_sevsegdev *mydev;
mydev = usb_get_intfdata(intf);
mydev->shadow_power = 1;
update_display_mode(mydev);
update_display_visual(mydev, GFP_NOIO);
return 0;
}
static int sevseg_reset_resume(struct usb_interface *intf)
{
struct usb_sevsegdev *mydev;
mydev = usb_get_intfdata(intf);
mydev->shadow_power = 1;
update_display_mode(mydev);
update_display_visual(mydev, GFP_NOIO);
return 0;
}
static struct usb_driver sevseg_driver = { static struct usb_driver sevseg_driver = {
.name = "usbsevseg", .name = "usbsevseg",
.probe = sevseg_probe, .probe = sevseg_probe,
.disconnect = sevseg_disconnect, .disconnect = sevseg_disconnect,
.suspend = sevseg_suspend,
.resume = sevseg_resume,
.reset_resume = sevseg_reset_resume,
.id_table = id_table, .id_table = id_table,
.supports_autosuspend = 1,
}; };
static int __init usb_sevseg_init(void) static int __init usb_sevseg_init(void)

View File

@ -5,11 +5,9 @@
config USB_MON config USB_MON
tristate "USB Monitor" tristate "USB Monitor"
depends on USB depends on USB
default y if USB=y
default m if USB=m
help help
If you select this option, a component which captures the USB traffic If you select this option, a component which captures the USB traffic
between peripheral-specific drivers and HC drivers will be built. between peripheral-specific drivers and HC drivers will be built.
For more information, see <file:Documentation/usb/usbmon.txt>. For more information, see <file:Documentation/usb/usbmon.txt>.
If unsure, say Y (if allowed), otherwise M. If unsure, say Y, if allowed, otherwise M.

View File

@ -2,6 +2,6 @@
# Makefile for USB monitor # Makefile for USB monitor
# #
usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o
obj-$(CONFIG_USB_MON) += usbmon.o obj-$(CONFIG_USB_MON) += usbmon.o

View File

@ -220,9 +220,8 @@ static void mon_free_buff(struct mon_pgmap *map, int npages);
/* /*
* This is a "chunked memcpy". It does not manipulate any counters. * This is a "chunked memcpy". It does not manipulate any counters.
* But it returns the new offset for repeated application.
*/ */
unsigned int mon_copy_to_buff(const struct mon_reader_bin *this, static void mon_copy_to_buff(const struct mon_reader_bin *this,
unsigned int off, const unsigned char *from, unsigned int length) unsigned int off, const unsigned char *from, unsigned int length)
{ {
unsigned int step_len; unsigned int step_len;
@ -247,7 +246,6 @@ unsigned int mon_copy_to_buff(const struct mon_reader_bin *this,
from += step_len; from += step_len;
length -= step_len; length -= step_len;
} }
return off;
} }
/* /*
@ -400,15 +398,8 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp,
unsigned int offset, struct urb *urb, unsigned int length) unsigned int offset, struct urb *urb, unsigned int length)
{ {
if (urb->dev->bus->uses_dma &&
(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
mon_dmapeek_vec(rp, offset, urb->transfer_dma, length);
return 0;
}
if (urb->transfer_buffer == NULL) if (urb->transfer_buffer == NULL)
return 'Z'; return 'Z';
mon_copy_to_buff(rp, offset, urb->transfer_buffer, length); mon_copy_to_buff(rp, offset, urb->transfer_buffer, length);
return 0; return 0;
} }
@ -635,7 +626,6 @@ static int mon_bin_open(struct inode *inode, struct file *file)
spin_lock_init(&rp->b_lock); spin_lock_init(&rp->b_lock);
init_waitqueue_head(&rp->b_wait); init_waitqueue_head(&rp->b_wait);
mutex_init(&rp->fetch_lock); mutex_init(&rp->fetch_lock);
rp->b_size = BUFF_DFL; rp->b_size = BUFF_DFL;
size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE); size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE);

View File

@ -1,95 +0,0 @@
/*
* The USB Monitor, inspired by Dave Harding's USBMon.
*
* mon_dma.c: Library which snoops on DMA areas.
*
* Copyright (C) 2005 Pete Zaitcev (zaitcev@redhat.com)
*/
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/highmem.h>
#include <asm/page.h>
#include <linux/usb.h> /* Only needed for declarations in usb_mon.h */
#include "usb_mon.h"
/*
* PC-compatibles, are, fortunately, sufficiently cache-coherent for this.
*/
#if defined(__i386__) || defined(__x86_64__) /* CONFIG_ARCH_I386 doesn't exit */
#define MON_HAS_UNMAP 1
#define phys_to_page(phys) pfn_to_page((phys) >> PAGE_SHIFT)
char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
{
struct page *pg;
unsigned long flags;
unsigned char *map;
unsigned char *ptr;
/*
* On i386, a DMA handle is the "physical" address of a page.
* In other words, the bus address is equal to physical address.
* There is no IOMMU.
*/
pg = phys_to_page(dma_addr);
/*
* We are called from hardware IRQs in case of callbacks.
* But we can be called from softirq or process context in case
* of submissions. In such case, we need to protect KM_IRQ0.
*/
local_irq_save(flags);
map = kmap_atomic(pg, KM_IRQ0);
ptr = map + (dma_addr & (PAGE_SIZE-1));
memcpy(dst, ptr, len);
kunmap_atomic(map, KM_IRQ0);
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
char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
{
return 'D';
}
void mon_dmapeek_vec(const struct mon_reader_bin *rp,
unsigned int offset, dma_addr_t dma_addr, unsigned int length)
{
;
}
#endif /* MON_HAS_UNMAP */

View File

@ -361,7 +361,6 @@ static int __init mon_init(void)
} }
// MOD_INC_USE_COUNT(which_module?); // MOD_INC_USE_COUNT(which_module?);
mutex_lock(&usb_bus_list_lock); mutex_lock(&usb_bus_list_lock);
list_for_each_entry (ubus, &usb_bus_list, bus_list) { list_for_each_entry (ubus, &usb_bus_list, bus_list) {
mon_bus_init(ubus); mon_bus_init(ubus);

View File

@ -150,20 +150,6 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
return '>'; return '>';
} }
/*
* The check to see if it's safe to poke at data has an enormous
* number of corner cases, but it seems that the following is
* more or less safe.
*
* We do not even try to look at transfer_buffer, because it can
* contain non-NULL garbage in case the upper level promised to
* set DMA for the HCD.
*/
if (urb->dev->bus->uses_dma &&
(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) {
return mon_dmapeek(ep->data, urb->transfer_dma, len);
}
if (urb->transfer_buffer == NULL) if (urb->transfer_buffer == NULL)
return 'Z'; /* '0' would be not as pretty. */ return 'Z'; /* '0' would be not as pretty. */

View File

@ -64,20 +64,6 @@ void mon_text_exit(void);
int __init mon_bin_init(void); int __init mon_bin_init(void);
void mon_bin_exit(void); void 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 struct mutex mon_lock;

View File

@ -1850,6 +1850,10 @@ static void musb_free(struct musb *musb)
dma_controller_destroy(c); dma_controller_destroy(c);
} }
#ifdef CONFIG_USB_MUSB_OTG
put_device(musb->xceiv->dev);
#endif
musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
musb_platform_exit(musb); musb_platform_exit(musb);
musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
@ -1859,10 +1863,6 @@ static void musb_free(struct musb *musb)
clk_put(musb->clock); clk_put(musb->clock);
} }
#ifdef CONFIG_USB_MUSB_OTG
put_device(musb->xceiv->dev);
#endif
#ifdef CONFIG_USB_MUSB_HDRC_HCD #ifdef CONFIG_USB_MUSB_HDRC_HCD
usb_put_hcd(musb_to_hcd(musb)); usb_put_hcd(musb_to_hcd(musb));
#else #else

View File

@ -117,24 +117,7 @@ static void enable_vbus_draw(struct isp1301 *isp, unsigned mA)
pr_debug(" VBUS %d mA error %d\n", mA, status); pr_debug(" VBUS %d mA error %d\n", mA, status);
} }
static void enable_vbus_source(struct isp1301 *isp) #else
{
/* this board won't supply more than 8mA vbus power.
* some boards can switch a 100ma "unit load" (or more).
*/
}
/* products will deliver OTG messages with LEDs, GUI, etc */
static inline void notresponding(struct isp1301 *isp)
{
printk(KERN_NOTICE "OTG device not responding.\n");
}
#endif
#if defined(CONFIG_MACH_OMAP_H4)
static void enable_vbus_draw(struct isp1301 *isp, unsigned mA) static void enable_vbus_draw(struct isp1301 *isp, unsigned mA)
{ {
@ -144,6 +127,8 @@ static void enable_vbus_draw(struct isp1301 *isp, unsigned mA)
*/ */
} }
#endif
static void enable_vbus_source(struct isp1301 *isp) static void enable_vbus_source(struct isp1301 *isp)
{ {
/* this board won't supply more than 8mA vbus power. /* this board won't supply more than 8mA vbus power.
@ -159,8 +144,6 @@ static inline void notresponding(struct isp1301 *isp)
} }
#endif
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
static struct i2c_driver isp1301_driver; static struct i2c_driver isp1301_driver;

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