提交 be90a49c 编写于 作者: L Linus Torvalds

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
  ...
......@@ -671,7 +671,7 @@ and is between 256 and 4096 characters. It is defined in the file
earlyprintk= [X86,SH,BLACKFIN]
earlyprintk=vga
earlyprintk=serial[,ttySn[,baudrate]]
earlyprintk=dbgp
earlyprintk=dbgp[debugController#]
Append ",keep" to not disable it when the real console
takes over.
......
......@@ -16,20 +16,20 @@ Usage:
Authorize a device to connect:
$ echo 1 > /sys/usb/devices/DEVICE/authorized
$ echo 1 > /sys/bus/usb/devices/DEVICE/authorized
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:
lock down):
$ echo 0 > /sys/bus/devices/usbX/authorized_default
$ echo 0 > /sys/bus/usb/devices/usbX/authorized_default
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
connect. Wireless USB hosts deauthorize by default all new connected
......@@ -47,7 +47,7 @@ USB port):
boot up
rc.local ->
for host in /sys/bus/devices/usb*
for host in /sys/bus/usb/devices/usb*
do
echo 0 > $host/authorized_default
done
......
......@@ -33,7 +33,7 @@ if usbmon is built into the kernel.
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
#
......@@ -58,11 +58,11 @@ Bus=03 means it's bus 3.
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:
# 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
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
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)
......
......@@ -7,7 +7,7 @@ and two USB cables, connected like this:
[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.
......@@ -42,7 +42,35 @@ and two USB cables, connected like this:
This is a small blue plastic connector with two 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:
......@@ -56,6 +84,13 @@ and two USB cables, connected like this:
(If you are using Grub, append it to the 'kernel' line in
/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
regular console is alive - use "earlyprintk=dbgp,keep" to keep
this channel open beyond early bootup. This can be useful for
......
......@@ -2107,12 +2107,12 @@ S: Supported
F: arch/powerpc/sysdev/qe_lib/
F: arch/powerpc/include/asm/*qe.h
FREESCALE HIGHSPEED USB DEVICE DRIVER
FREESCALE USB PERIPHERIAL DRIVERS
M: Li Yang <leoli@freescale.com>
L: linux-usb@vger.kernel.org
L: linuxppc-dev@ozlabs.org
S: Maintained
F: drivers/usb/gadget/fsl_usb2_udc.c
F: drivers/usb/gadget/fsl*
FREESCALE QUICC ENGINE UCC ETHERNET DRIVER
M: Li Yang <leoli@freescale.com>
......
......@@ -160,721 +160,6 @@ static struct console early_serial_console = {
.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 */
static struct console *early_console = &early_vga_console;
static int __initdata early_console_initialized;
......@@ -891,10 +176,19 @@ asmlinkage void early_printk(const char *fmt, ...)
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)
{
int keep_early;
int keep;
if (!buf)
return 0;
......@@ -903,42 +197,34 @@ static int __init setup_early_printk(char *buf)
return 0;
early_console_initialized = 1;
keep_early = (strstr(buf, "keep") != NULL);
if (!strncmp(buf, "serial", 6)) {
early_serial_init(buf + 6);
early_console = &early_serial_console;
} else if (!strncmp(buf, "ttyS", 4)) {
early_serial_init(buf);
early_console = &early_serial_console;
} else if (!strncmp(buf, "vga", 3)
&& boot_params.screen_info.orig_video_isVGA == 1) {
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 = &early_vga_console;
keep = (strstr(buf, "keep") != NULL);
while (*buf != '\0') {
if (!strncmp(buf, "serial", 6)) {
early_serial_init(buf + 6);
early_console_register(&early_serial_console, keep);
}
if (!strncmp(buf, "ttyS", 4)) {
early_serial_init(buf + 4);
early_console_register(&early_serial_console, keep);
}
if (!strncmp(buf, "vga", 3) &&
boot_params.screen_info.orig_video_isVGA == 1) {
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
} else if (!strncmp(buf, "dbgp", 4)) {
if (early_dbgp_init(buf+4) < 0)
return 0;
early_console = &early_dbgp_console;
/*
* usb subsys will reset ehci controller, so don't keep
* that early console
*/
keep_early = 0;
if (!strncmp(buf, "dbgp", 4) && !early_dbgp_init(buf + 4))
early_console_register(&early_dbgp_console, keep);
#endif
#ifdef CONFIG_HVC_XEN
} else if (!strncmp(buf, "xen", 3)) {
early_console = &xenboot_console;
if (!strncmp(buf, "xen", 3))
early_console_register(&xenboot_console, keep);
#endif
buf++;
}
if (keep_early)
early_console->flags &= ~CON_BOOT;
else
early_console->flags |= CON_BOOT;
register_console(early_console);
return 0;
}
......
......@@ -300,20 +300,23 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
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 Ethernet frame contains a calculated CRC:
* bmCRC = 1 : CRC is calculated
* bmCRC = 0 : CRC = 0xDEADBEEF
*/
if (header & BIT(14))
crc2 = ~crc32_le(~0, skb2->data, skb2->len);
else
if (header & BIT(14)) {
crc = get_unaligned_le32(skb2->data
+ 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;
}
skb_trim(skb2, len - ETH_FCS_LEN);
if (is_last)
return crc == crc2;
......
......@@ -39,6 +39,7 @@ config USB_ARCH_HAS_OHCI
default y if ARCH_AT91
default y if ARCH_PNX4008 && I2C
default y if MFD_TC6393XB
default y if ARCH_W90X900
# PPC:
default y if STB03xxx
default y if PPC_MPC52xx
......@@ -58,6 +59,8 @@ config USB_ARCH_HAS_EHCI
default y if PPC_83xx
default y if SOC_AU1200
default y if ARCH_IXP4XX
default y if ARCH_W90X900
default y if ARCH_AT91SAM9G45
default PCI
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
......
......@@ -16,6 +16,7 @@ obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_FHCI_HCD) += host/
obj-$(CONFIG_USB_XHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_ISP1362_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_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) += misc/
obj-y += early/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
......@@ -59,6 +59,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/serial.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
......@@ -609,6 +610,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
acm->throttle = 0;
tasklet_schedule(&acm->urb_task);
set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
rv = tty_port_block_til_ready(&acm->port, tty, filp);
done:
mutex_unlock(&acm->mutex);
......
......@@ -313,8 +313,13 @@ static ssize_t wdm_write
r = usb_autopm_get_interface(desc->intf);
if (r < 0)
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)
goto out;
......@@ -377,7 +382,7 @@ static ssize_t wdm_write
static ssize_t wdm_read
(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
int rv, cntr;
int rv, cntr = 0;
int i = 0;
struct wdm_device *desc = file->private_data;
......@@ -389,10 +394,23 @@ static ssize_t wdm_read
if (desc->length == 0) {
desc->read = 0;
retry:
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
rv = -ENODEV;
goto err;
}
i++;
rv = wait_event_interruptible(desc->wait,
test_bit(WDM_READ, &desc->flags));
if (file->f_flags & O_NONBLOCK) {
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)) {
rv = -ENODEV;
goto err;
......@@ -448,7 +466,7 @@ static ssize_t wdm_read
err:
mutex_unlock(&desc->rlock);
if (rv < 0)
if (rv < 0 && rv != -EAGAIN)
dev_err(&desc->intf->dev, "wdm_read: exit error\n");
return rv;
}
......
......@@ -57,7 +57,9 @@ MODULE_DEVICE_TABLE(usb, usbtmc_devices);
/*
* 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 {
__u8 interface_capabilities;
......@@ -86,6 +88,8 @@ struct usbtmc_device_data {
bool TermCharEnabled;
bool auto_abort;
bool zombie; /* fd of disconnected device */
struct usbtmc_dev_capabilities capabilities;
struct kref kref;
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 device *dev;
unsigned long int n_characters;
u32 n_characters;
u8 *buffer;
int actual;
int done;
int remaining;
size_t done;
size_t remaining;
int retval;
int this_part;
size_t this_part;
/* Get pointer to private data structure */
data = filp->private_data;
......@@ -384,6 +388,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
return -ENOMEM;
mutex_lock(&data->io_mutex);
if (data->zombie) {
retval = -ENODEV;
goto exit;
}
remaining = count;
done = 0;
......@@ -401,10 +409,10 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
buffer[1] = data->bTag;
buffer[2] = ~(data->bTag);
buffer[3] = 0; /* Reserved */
buffer[4] = (this_part - 12 - 3) & 255;
buffer[5] = ((this_part - 12 - 3) >> 8) & 255;
buffer[6] = ((this_part - 12 - 3) >> 16) & 255;
buffer[7] = ((this_part - 12 - 3) >> 24) & 255;
buffer[4] = (this_part) & 255;
buffer[5] = ((this_part) >> 8) & 255;
buffer[6] = ((this_part) >> 16) & 255;
buffer[7] = ((this_part) >> 24) & 255;
buffer[8] = data->TermCharEnabled * 2;
/* Use term character? */
buffer[9] = data->TermChar;
......@@ -455,6 +463,22 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
(buffer[6] << 16) +
(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 */
if (copy_to_user(buf + done, &buffer[12], n_characters)) {
/* 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;
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;
else
remaining -= n_characters;
}
/* Update file position value */
......@@ -496,6 +523,10 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
return -ENOMEM;
mutex_lock(&data->io_mutex);
if (data->zombie) {
retval = -ENODEV;
goto exit;
}
remaining = count;
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, "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) {
dev_err(dev, "GET_CAPABILITIES returned %x\n", buffer[0]);
rv = -EPERM;
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.device_capabilities = buffer[5];
data->capabilities.usb488_interface_capabilities = buffer[14];
data->capabilities.usb488_device_capabilities = buffer[15];
rv = 0;
err_out:
kfree(buffer);
......@@ -925,6 +957,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
data = file->private_data;
mutex_lock(&data->io_mutex);
if (data->zombie) {
retval = -ENODEV;
goto skip_io_on_zombie;
}
switch (cmd) {
case USBTMC_IOCTL_CLEAR_OUT_HALT:
......@@ -952,6 +988,7 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
skip_io_on_zombie:
mutex_unlock(&data->io_mutex);
return retval;
}
......@@ -995,6 +1032,7 @@ static int usbtmc_probe(struct usb_interface *intf,
usb_set_intfdata(intf, data);
kref_init(&data->kref);
mutex_init(&data->io_mutex);
data->zombie = 0;
/* Initialize USBTMC bTag and other fields */
data->bTag = 1;
......@@ -1065,14 +1103,30 @@ static void usbtmc_disconnect(struct usb_interface *intf)
usb_deregister_dev(intf, &usbtmc_class);
sysfs_remove_group(&intf->dev.kobj, &capability_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);
}
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 = {
.name = "usbtmc",
.id_table = usbtmc_devices,
.probe = usbtmc_probe,
.disconnect = usbtmc_disconnect
.disconnect = usbtmc_disconnect,
.suspend = usbtmc_suspend,
.resume = usbtmc_resume,
};
static int __init usbtmc_init(void)
......
......@@ -105,7 +105,7 @@ static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
ep->ss_ep_comp->extralen = i;
buffer += i;
size -= i;
retval = buffer - buffer_start + i;
retval = buffer - buffer_start;
if (num_skipped > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
num_skipped, plural(num_skipped),
......
......@@ -52,6 +52,7 @@
#include "hcd.h" /* for usbcore internals */
#include "usb.h"
#include "hub.h"
#define USB_MAXBUS 64
#define USB_DEVICE_MAX USB_MAXBUS * 128
......@@ -73,6 +74,7 @@ struct dev_state {
void __user *disccontext;
unsigned long ifclaimed;
u32 secid;
u32 disabled_bulk_eps;
};
struct async {
......@@ -87,6 +89,8 @@ struct async {
struct urb *urb;
int status;
u32 secid;
u8 bulk_addr;
u8 bulk_status;
};
static int usbfs_snoop;
......@@ -99,11 +103,15 @@ MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
dev_info(dev , format , ## arg); \
} while (0)
#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)
enum snoop_when {
SUBMIT, COMPLETE
};
#define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0)
#define MAX_USBFS_BUFFER_SIZE 16384
static int connected(struct dev_state *ps)
{
return (!list_empty(&ps->list) &&
......@@ -300,24 +308,79 @@ static struct async *async_getpending(struct dev_state *ps,
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;
unsigned char *data = urb->transfer_buffer;
static const char *types[] = {"isoc", "int", "ctrl", "bulk"};
static const char *dirs[] = {"out", "in"};
int ep;
const char *t, *d;
if (!usbfs_snoop)
return;
dev_info(&urb->dev->dev, "direction=%s\n",
usb_urb_dir_in(urb) ? "IN" : "OUT");
dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
dev_info(&urb->dev->dev, "transfer_buffer_length=%u\n",
urb->transfer_buffer_length);
dev_info(&urb->dev->dev, "actual_length=%u\n", urb->actual_length);
dev_info(&urb->dev->dev, "data: ");
for (j = 0; j < urb->transfer_buffer_length; ++j)
printk("%02x ", data[j]);
printk("\n");
ep = usb_pipeendpoint(pipe);
t = types[usb_pipetype(pipe)];
d = dirs[!!usb_pipein(pipe)];
if (userurb) { /* Async */
if (when == SUBMIT)
dev_info(&udev->dev, "userurb %p, ep%d %s-%s, "
"length %u\n",
userurb, ep, t, d, length);
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)
......@@ -346,7 +409,11 @@ static void async_completed(struct urb *urb)
secid = as->secid;
}
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);
if (signr)
......@@ -655,6 +722,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
struct async *as;
usb_lock_device(dev);
usb_hub_release_all_ports(dev, ps);
/* Protect against simultaneous open */
mutex_lock(&usbfs_mutex);
......@@ -688,7 +756,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)
unsigned int tmo;
unsigned char *tbuf;
unsigned wLength;
int i, j, ret;
int i, pipe, ret;
if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
return -EFAULT;
......@@ -708,24 +776,17 @@ static int proc_control(struct dev_state *ps, void __user *arg)
free_page((unsigned long)tbuf);
return -EINVAL;
}
snoop(&dev->dev, "control read: bRequest=%02x "
"bRrequestType=%02x wValue=%04x "
"wIndex=%04x wLength=%04x\n",
ctrl.bRequest, ctrl.bRequestType, ctrl.wValue,
ctrl.wIndex, ctrl.wLength);
pipe = usb_rcvctrlpipe(dev, 0);
snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
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,
tbuf, ctrl.wLength, tmo);
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
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)) {
free_page((unsigned long)tbuf);
return -EFAULT;
......@@ -738,22 +799,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
return -EFAULT;
}
}
snoop(&dev->dev, "control write: bRequest=%02x "
"bRrequestType=%02x wValue=%04x "
"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");
}
pipe = usb_sndctrlpipe(dev, 0);
snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
usb_unlock_device(dev);
i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
tbuf, ctrl.wLength, tmo);
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
}
free_page((unsigned long)tbuf);
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;
int len2;
unsigned char *tbuf;
int i, j, ret;
int i, ret;
if (copy_from_user(&bulk, arg, sizeof(bulk)))
return -EFAULT;
......@@ -799,18 +853,14 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
kfree(tbuf);
return -EINVAL;
}
snoop(&dev->dev, "bulk read: len=0x%02x timeout=%04d\n",
bulk.len, bulk.timeout);
snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
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)) {
kfree(tbuf);
return -EFAULT;
......@@ -823,17 +873,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
return -EFAULT;
}
}
snoop(&dev->dev, "bulk write: len=0x%02x timeout=%04d\n",
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");
}
snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
usb_unlock_device(dev);
i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
usb_lock_device(dev);
snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
}
kfree(tbuf);
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 |
USBDEVFS_URB_SHORT_NOT_OK |
USBDEVFS_URB_BULK_CONTINUATION |
USBDEVFS_URB_NO_FSBR |
USBDEVFS_URB_ZERO_PACKET |
USBDEVFS_URB_NO_INTERRUPT))
......@@ -1051,13 +1097,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
is_in = 0;
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;
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;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
snoop(&ps->dev->dev, "bulk urb\n");
break;
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;
}
if (totlen > 32768) {
/* 3072 * 64 microframes */
if (totlen > 196608) {
kfree(isopkt);
return -EINVAL;
}
uurb->buffer_length = totlen;
snoop(&ps->dev->dev, "iso urb\n");
break;
case USBDEVFS_URB_TYPE_INTERRUPT:
......@@ -1111,7 +1149,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
return -EINVAL;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
return -EINVAL;
snoop(&ps->dev->dev, "interrupt urb\n");
break;
default:
......@@ -1198,11 +1235,46 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
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);
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,
"usbfs: usb_submit_urb returned %d\n", ret);
snoop_urb(ps->dev, as->userurb, as->urb->pipe,
0, ret, COMPLETE);
async_removepending(as);
free_async(as);
return ret;
......@@ -1548,6 +1620,29 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
}
#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
* 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;
case USBDEVFS_REAPURBNDELAY32:
snoop(&dev->dev, "%s: REAPURBDELAY32\n", __func__);
snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
ret = proc_reapurbnonblock_compat(ps, p);
break;
......@@ -1666,7 +1761,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
break;
case USBDEVFS_REAPURBNDELAY:
snoop(&dev->dev, "%s: REAPURBDELAY\n", __func__);
snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
ret = proc_reapurbnonblock(ps, p);
break;
......@@ -1689,6 +1784,16 @@ static int usbdev_ioctl(struct inode *inode, struct file *file,
snoop(&dev->dev, "%s: IOCTL\n", __func__);
ret = proc_ioctl_default(ps, p);
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);
if (ret >= 0)
......
......@@ -207,6 +207,9 @@ static int usb_probe_interface(struct device *dev)
intf->needs_binding = 0;
if (usb_device_is_owned(udev))
return -ENODEV;
if (udev->authorized == 0) {
dev_err(&intf->dev, "Device is not authorized for usage\n");
return -ENODEV;
......@@ -232,28 +235,35 @@ static int usb_probe_interface(struct device *dev)
/* The interface should always appear to be in use
* 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 */
if (intf->needs_altsetting0) {
usb_set_interface(udev, intf->altsetting[0].
error = usb_set_interface(udev, intf->altsetting[0].
desc.bInterfaceNumber, 0);
if (error < 0)
goto err;
intf->needs_altsetting0 = 0;
}
error = driver->probe(intf, id);
if (error) {
mark_quiesced(intf);
intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
usb_cancel_queued_reset(intf);
} else
intf->condition = USB_INTERFACE_BOUND;
if (error)
goto err;
intf->condition = USB_INTERFACE_BOUND;
usb_autosuspend_device(udev);
}
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 */
......@@ -262,7 +272,7 @@ static int usb_unbind_interface(struct device *dev)
struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf = to_usb_interface(dev);
struct usb_device *udev;
int error;
int error, r;
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.
*/
usb_enable_interface(udev, intf, false);
} else if (!error && intf->dev.power.status == DPM_ON)
usb_set_interface(udev, intf->altsetting[0].
} else if (!error && intf->dev.power.status == DPM_ON) {
r = usb_set_interface(udev, intf->altsetting[0].
desc.bInterfaceNumber, 0);
else
if (r < 0)
intf->needs_altsetting0 = 1;
} else {
intf->needs_altsetting0 = 1;
}
usb_set_intfdata(intf, NULL);
intf->condition = USB_INTERFACE_UNBOUND;
......@@ -344,7 +357,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
usb_pm_lock(udev);
iface->condition = USB_INTERFACE_BOUND;
mark_active(iface);
iface->pm_usage_cnt = !(driver->supports_autosuspend);
atomic_set(&iface->pm_usage_cnt, !driver->supports_autosuspend);
usb_pm_unlock(udev);
/* 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];
if (!is_active(intf))
continue;
if (intf->pm_usage_cnt > 0)
if (atomic_read(&intf->pm_usage_cnt) > 0)
return -EBUSY;
if (intf->needs_remote_wakeup &&
!udev->do_remote_wakeup) {
......@@ -1461,17 +1474,19 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
status = -ENODEV;
else {
udev->auto_pm = 1;
intf->pm_usage_cnt += inc_usage_cnt;
atomic_add(inc_usage_cnt, &intf->pm_usage_cnt);
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)
status = usb_resume_both(udev,
PMSG_AUTO_RESUME);
if (status != 0)
intf->pm_usage_cnt -= inc_usage_cnt;
atomic_sub(inc_usage_cnt, &intf->pm_usage_cnt);
else
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);
}
}
......@@ -1516,7 +1531,7 @@ void usb_autopm_put_interface(struct usb_interface *intf)
status = usb_autopm_do_interface(intf, -1);
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);
......@@ -1544,10 +1559,10 @@ void usb_autopm_put_interface_async(struct usb_interface *intf)
status = -ENODEV;
} else {
udev->last_busy = jiffies;
--intf->pm_usage_cnt;
atomic_dec(&intf->pm_usage_cnt);
if (udev->autosuspend_disabled || udev->autosuspend_delay < 0)
status = -EPERM;
else if (intf->pm_usage_cnt <= 0 &&
else if (atomic_read(&intf->pm_usage_cnt) <= 0 &&
!timer_pending(&udev->autosuspend.timer)) {
queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
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",
__func__, status, intf->pm_usage_cnt);
__func__, status, atomic_read(&intf->pm_usage_cnt));
}
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);
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;
}
EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
......@@ -1627,10 +1642,14 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
status = -ENODEV;
else if (udev->autoresume_disabled)
status = -EPERM;
else if (++intf->pm_usage_cnt > 0 && udev->state == USB_STATE_SUSPENDED)
queue_work(ksuspend_usb_wq, &udev->autoresume);
else {
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",
__func__, status, intf->pm_usage_cnt);
__func__, status, atomic_read(&intf->pm_usage_cnt));
return status;
}
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);
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;
}
EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
......
......@@ -158,7 +158,9 @@ static int generic_probe(struct usb_device *udev)
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
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");
else {
c = usb_choose_configuration(udev);
......
......@@ -337,72 +337,89 @@ static const u8 ss_rh_config_descriptor[] = {
/*-------------------------------------------------------------------------*/
/*
* helper routine for returning string descriptors in UTF-16LE
* input can actually be ISO-8859-1; ASCII is its 7-bit subset
/**
* ascii2desc() - Helper routine for producing UTF-16LE string descriptors
* @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) {
*utf++ = *s++;
*utf++ = 0;
}
if (utfmax > 0) {
*utf = *s;
++retval;
if (t > 254)
t = 254; /* Longest possible UTF string descriptor */
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++;
}
return retval;
return len;
}
/*
* rh_string - provides manufacturer, product and serial strings for root hub
* @id: the string ID number (1: serial number, 2: product, 3: vendor)
/**
* rh_string() - provides string descriptors for root hub
* @id: the string ID number (0: langids, 1: serial #, 2: product, 3: vendor)
* @hcd: the host controller for this root hub
* @data: return packet in UTF-16 LE
* @len: length of the return packet
* @data: buffer for output packet
* @len: length of the provided buffer
*
* Produces either a manufacturer, product or serial number string for the
* 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
if (id == 0) {
buf[0] = 4; buf[1] = 3; /* 4 bytes string data */
buf[2] = 0x09; buf[3] = 0x04; /* MSFT-speak for "en-us" */
len = min_t(unsigned, len, 4);
memcpy (data, buf, len);
switch (id) {
case 0:
/* Array of LANGID codes (0x0409 is MSFT-speak for "en-us") */
/* See http://www.usb.org/developers/docs/USB_LANGIDs.pdf */
if (len > 4)
len = 4;
memcpy(data, langids, len);
return len;
// serial number
} else if (id == 1) {
strlcpy (buf, hcd->self.bus_name, sizeof buf);
// product description
} else if (id == 2) {
strlcpy (buf, hcd->product_desc, sizeof buf);
// id 3 == vendor description
} else if (id == 3) {
case 1:
/* Serial number */
s = hcd->self.bus_name;
break;
case 2:
/* Product name */
s = hcd->product_desc;
break;
case 3:
/* Manufacturer */
snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname,
init_utsname()->release, hcd->driver->description);
}
switch (len) { /* All cases fall through */
s = buf;
break;
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 */
/* Can't happen; caller guarantees it */
return 0;
}
return len;
return ascii2desc(s, data, len);
}
......
......@@ -267,6 +267,11 @@ struct hc_driver {
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
/* Returns the hardware-chosen device address */
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);
......
......@@ -78,6 +78,7 @@ struct usb_hub {
u8 indicator[USB_MAXCHILDREN];
struct delayed_work leds;
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! */
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]);
}
......@@ -372,7 +375,7 @@ static void kick_khubd(struct usb_hub *hub)
unsigned long flags;
/* 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);
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)
{
/* FIXME: What if hdev isn't bound to the hub driver? */
kick_khubd(hdev_to_hub(hdev));
struct usb_hub *hub = 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));
/* 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 */
} else {
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,
struct usb_endpoint_descriptor *endpoint)
{
struct usb_hcd *hcd;
struct usb_device *hdev = hub->hdev;
struct device *hub_dev = hub->intfdev;
u16 hubstatus, hubchange;
u16 wHubCharacteristics;
unsigned int pipe;
int maxp, ret;
char *message;
char *message = "out of memory";
hub->buffer = usb_buffer_alloc(hdev, sizeof(*hub->buffer), GFP_KERNEL,
&hub->buffer_dma);
if (!hub->buffer) {
message = "can't allocate hub irq buffer";
ret = -ENOMEM;
goto fail;
}
hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
if (!hub->status) {
message = "can't kmalloc hub status buffer";
ret = -ENOMEM;
goto fail;
}
......@@ -880,7 +885,6 @@ static int hub_configure(struct usb_hub *hub,
hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
if (!hub->descriptor) {
message = "can't kmalloc hub descriptor";
ret = -ENOMEM;
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,
(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);
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",
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);
if (ret < 0) {
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);
if (!hub->urb) {
message = "couldn't allocate interrupt urb";
ret = -ENOMEM;
goto fail;
}
......@@ -1131,11 +1153,13 @@ static void hub_disconnect(struct usb_interface *intf)
hub_quiesce(hub, HUB_DISCONNECT);
usb_set_intfdata (intf, NULL);
hub->hdev->maxchild = 0;
if (hub->hdev->speed == USB_SPEED_HIGH)
highspeed_hubs--;
usb_free_urb(hub->urb);
kfree(hub->port_owners);
kfree(hub->descriptor);
kfree(hub->status);
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)
{
......@@ -2849,14 +2946,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
/* For a suspended device, treat this as a
* remote wakeup event.
*/
if (udev->do_remote_wakeup)
status = remote_wakeup(udev);
/* Otherwise leave it be; devices can't tell the
* difference between suspended and disabled.
*/
else
status = 0;
status = remote_wakeup(udev);
#endif
} else {
......
......@@ -459,35 +459,23 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
io->urbs[i]->context = io;
/*
* Some systems need to revert to PIO when DMA is
* temporarily unavailable. For their sakes, both
* transfer_buffer and transfer_dma are set when
* possible. However this can only work on systems
* without:
* Some systems need to revert to PIO when DMA is temporarily
* unavailable. For their sakes, both transfer_buffer and
* transfer_dma are set when possible.
*
* - HIGHMEM, since DMA buffers located in high memory
* are not directly addressable by the CPU for PIO;
*
* - 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.
* Note that if IOMMU coalescing occurred, we cannot
* trust sg_page anymore, so check if S/G list shrunk.
*/
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) {
io->urbs[i]->transfer_dma = sg_dma_address(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 {
/* hc may use _only_ transfer_buffer */
io->urbs[i]->transfer_buffer = sg_virt(sg);
len = sg->length;
}
......
......@@ -413,8 +413,13 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
} else {
snprintf(dev->devpath, sizeof dev->devpath,
"%s.%d", parent->devpath, port1);
dev->route = parent->route +
(port1 << ((parent->level - 1)*4));
/* Route string assumes hubs have less than 16 ports */
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;
......@@ -914,11 +919,11 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
|| !(bus = dev->bus)
|| !(controller = bus->controller)
|| !controller->dma_mask)
return -1;
return -EINVAL;
/* FIXME generic api broken like pci, can't report errors */
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);
......
......@@ -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_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 void usb_hub_cleanup(void);
extern int usb_major_init(void);
......
#
# Makefile for early USB devices
#
obj-$(CONFIG_EARLY_PRINTK_DBGP) += ehci-dbgp.o
此差异已折叠。
......@@ -124,7 +124,7 @@ choice
config USB_GADGET_AT91
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
help
Many Atmel AT91 processors (such as the AT91RM2000) have a
......@@ -143,7 +143,7 @@ config USB_AT91
config USB_GADGET_ATMEL_USBA
boolean "Atmel USBA"
select USB_GADGET_DUALSPEED
depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL
depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
help
USBA is the integrated high-speed USB Device controller on
the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
......@@ -627,9 +627,10 @@ config USB_AUDIO
config USB_ETH
tristate "Ethernet Gadget (with CDC Ethernet support)"
depends on NET
select CRC32
help
This driver implements Ethernet style communication, in either
of two ways:
This driver implements Ethernet style communication, in one of
several ways:
- The "Communication Device Class" (CDC) Ethernet Control Model.
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
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
"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
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
tristate "Gadget Filesystem (EXPERIMENTAL)"
depends on EXPERIMENTAL
......
......@@ -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)) {
req = list_entry(ep->queue.next,
struct udc_request, queue);
if (req) {
/*
* length bytes transfered
* check dma done of last desc. in PPBDU mode
*/
if (use_dma_ppb_du) {
td = udc_get_last_dma_desc(req);
if (td) {
dma_done =
AMD_GETBITS(td->status,
UDC_DMA_IN_STS_BS);
/* don't care DMA done */
req->req.actual =
req->req.length;
}
} else {
/* assume all bytes transferred */
/*
* length bytes transfered
* check dma done of last desc. in PPBDU mode
*/
if (use_dma_ppb_du) {
td = udc_get_last_dma_desc(req);
if (td) {
dma_done =
AMD_GETBITS(td->status,
UDC_DMA_IN_STS_BS);
/* don't care DMA done */
req->req.actual = req->req.length;
}
} else {
/* assume all bytes transferred */
req->req.actual = req->req.length;
}
if (req->req.actual == req->req.length) {
/* complete req */
complete_req(ep, req, 0);
req->dma_going = 0;
/* further request available ? */
if (list_empty(&ep->queue)) {
/* disable interrupt */
tmp = readl(
&dev->regs->ep_irqmsk);
tmp |= AMD_BIT(ep->num);
writel(tmp,
&dev->regs->ep_irqmsk);
}
if (req->req.actual == req->req.length) {
/* complete req */
complete_req(ep, req, 0);
req->dma_going = 0;
/* further request available ? */
if (list_empty(&ep->queue)) {
/* disable interrupt */
tmp = readl(&dev->regs->ep_irqmsk);
tmp |= AMD_BIT(ep->num);
writel(tmp, &dev->regs->ep_irqmsk);
}
}
}
......
......@@ -1754,7 +1754,6 @@ static int __init at91udc_probe(struct platform_device *pdev)
IRQF_DISABLED, driver_name, udc)) {
DBG("request vbus irq %d failed\n",
udc->board.vbus_pin);
free_irq(udc->udp_irq, udc);
retval = -EBUSY;
goto fail3;
}
......
......@@ -106,20 +106,20 @@ static int audio_set_endpoint_req(struct usb_configuration *c,
ctrl->bRequest, w_value, len, ep);
switch (ctrl->bRequest) {
case SET_CUR:
case UAC_SET_CUR:
value = 0;
break;
case SET_MIN:
case UAC_SET_MIN:
break;
case SET_MAX:
case UAC_SET_MAX:
break;
case SET_RES:
case UAC_SET_RES:
break;
case SET_MEM:
case UAC_SET_MEM:
break;
default:
......@@ -142,13 +142,13 @@ static int audio_get_endpoint_req(struct usb_configuration *c,
ctrl->bRequest, w_value, len, ep);
switch (ctrl->bRequest) {
case GET_CUR:
case GET_MIN:
case GET_MAX:
case GET_RES:
case UAC_GET_CUR:
case UAC_GET_MIN:
case UAC_GET_MAX:
case UAC_GET_RES:
value = 3;
break;
case GET_MEM:
case UAC_GET_MEM:
break;
default:
break;
......@@ -171,11 +171,11 @@ audio_setup(struct usb_configuration *c, const struct usb_ctrlrequest *ctrl)
* Audio class messages; interface activation uses set_alt().
*/
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);
break;
case USB_AUDIO_GET_ENDPOINT:
case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT:
value = audio_get_endpoint_req(c, ctrl);
break;
......
......@@ -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;
if (!len)
return -EINVAL;
......
......@@ -1306,11 +1306,6 @@ static void dummy_timer (unsigned long _dum)
setup = *(struct usb_ctrlrequest*) urb->setup_packet;
w_index = le16_to_cpu(setup.wIndex);
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 */
list_for_each_entry (req, &ep->queue, queue) {
......
......@@ -61,6 +61,11 @@
* simpler, Microsoft pushes their own approach: RNDIS. The published
* RNDIS specs are ambiguous and appear to be incomplete, and are also
* 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"
......@@ -114,6 +119,7 @@ static inline bool has_rndis(void)
#include "f_rndis.c"
#include "rndis.c"
#endif
#include "f_eem.c"
#include "u_ether.c"
/*-------------------------------------------------------------------------*/
......@@ -150,6 +156,10 @@ static inline bool has_rndis(void)
#define RNDIS_VENDOR_NUM 0x0525 /* NetChip */
#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 = {
......@@ -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)
{
......@@ -258,7 +276,9 @@ static int __init eth_do_config(struct usb_configuration *c)
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);
else
return geth_bind_config(c, hostaddr);
......@@ -286,7 +306,12 @@ static int __init eth_bind(struct usb_composite_dev *cdev)
return status;
/* 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 */
eth_config_driver.label = "CDC Ethernet (ECM)";
} else {
......
......@@ -28,6 +28,9 @@ static int audio_buf_size = 48000;
module_param(audio_buf_size, int, S_IRUGO);
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
* configuration descriptors are built on demand.
......@@ -50,16 +53,16 @@ static struct usb_interface_descriptor ac_interface_desc __initdata = {
.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 */
static struct usb_ac_header_descriptor_2 ac_header_desc = {
.bLength = USB_DT_AC_HEADER_LENGH,
static struct uac_ac_header_descriptor_2 ac_header_desc = {
.bLength = UAC_DT_AC_HEADER_LENGTH,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = HEADER,
.bDescriptorSubtype = UAC_HEADER,
.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,
.baInterfaceNr = {
[0] = F_AUDIO_AC_INTERFACE,
......@@ -68,33 +71,33 @@ static struct usb_ac_header_descriptor_2 ac_header_desc = {
};
#define INPUT_TERMINAL_ID 1
static struct usb_input_terminal_descriptor input_terminal_desc = {
.bLength = USB_DT_AC_INPUT_TERMINAL_SIZE,
static struct uac_input_terminal_descriptor input_terminal_desc = {
.bLength = UAC_DT_INPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = INPUT_TERMINAL,
.bDescriptorSubtype = UAC_INPUT_TERMINAL,
.bTerminalID = INPUT_TERMINAL_ID,
.wTerminalType = USB_AC_TERMINAL_STREAMING,
.wTerminalType = UAC_TERMINAL_STREAMING,
.bAssocTerminal = 0,
.wChannelConfig = 0x3,
};
DECLARE_USB_AC_FEATURE_UNIT_DESCRIPTOR(0);
DECLARE_UAC_FEATURE_UNIT_DESCRIPTOR(0);
#define FEATURE_UNIT_ID 2
static struct usb_ac_feature_unit_descriptor_0 feature_unit_desc = {
.bLength = USB_DT_AC_FEATURE_UNIT_SIZE(0),
static struct uac_feature_unit_descriptor_0 feature_unit_desc = {
.bLength = UAC_DT_FEATURE_UNIT_SIZE(0),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = FEATURE_UNIT,
.bDescriptorSubtype = UAC_FEATURE_UNIT,
.bUnitID = FEATURE_UNIT_ID,
.bSourceID = INPUT_TERMINAL_ID,
.bControlSize = 2,
.bmaControls[0] = (FU_MUTE | FU_VOLUME),
.bmaControls[0] = (UAC_FU_MUTE | UAC_FU_VOLUME),
};
static struct usb_audio_control mute_control = {
.list = LIST_HEAD_INIT(mute_control.list),
.name = "Mute Control",
.type = MUTE_CONTROL,
.type = UAC_MUTE_CONTROL,
/* Todo: add real Mute control code */
.set = generic_set_cmd,
.get = generic_get_cmd,
......@@ -103,7 +106,7 @@ static struct usb_audio_control mute_control = {
static struct usb_audio_control volume_control = {
.list = LIST_HEAD_INIT(volume_control.list),
.name = "Volume Control",
.type = VOLUME_CONTROL,
.type = UAC_VOLUME_CONTROL,
/* Todo: add real Volume control code */
.set = generic_set_cmd,
.get = generic_get_cmd,
......@@ -113,17 +116,17 @@ static struct usb_audio_control_selector feature_unit = {
.list = LIST_HEAD_INIT(feature_unit.list),
.id = FEATURE_UNIT_ID,
.name = "Mute & Volume Control",
.type = FEATURE_UNIT,
.type = UAC_FEATURE_UNIT,
.desc = (struct usb_descriptor_header *)&feature_unit_desc,
};
#define OUTPUT_TERMINAL_ID 3
static struct usb_output_terminal_descriptor output_terminal_desc = {
.bLength = USB_DT_AC_OUTPUT_TERMINAL_SIZE,
static struct uac_output_terminal_descriptor output_terminal_desc = {
.bLength = UAC_DT_OUTPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = OUTPUT_TERMINAL,
.bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
.bTerminalID = OUTPUT_TERMINAL_ID,
.wTerminalType = USB_AC_OUTPUT_TERMINAL_SPEAKER,
.wTerminalType = UAC_OUTPUT_TERMINAL_SPEAKER,
.bAssocTerminal = 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 */
static struct usb_as_header_descriptor as_header_desc = {
.bLength = USB_DT_AS_HEADER_SIZE,
static struct uac_as_header_descriptor as_header_desc = {
.bLength = UAC_DT_AS_HEADER_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = AS_GENERAL,
.bDescriptorSubtype = UAC_AS_GENERAL,
.bTerminalLink = INPUT_TERMINAL_ID,
.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 = {
.bLength = USB_AS_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
static struct uac_format_type_i_discrete_descriptor_1 as_type_i_desc = {
.bLength = UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = FORMAT_TYPE,
.bFormatType = USB_AS_FORMAT_TYPE_I,
.bDescriptorSubtype = UAC_FORMAT_TYPE,
.bFormatType = UAC_FORMAT_TYPE_I,
.bSubframeSize = 2,
.bBitResolution = 16,
.bSamFreqType = 1,
......@@ -174,17 +177,17 @@ static struct usb_endpoint_descriptor as_out_ep_desc __initdata = {
.bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_AS_ENDPOINT_ADAPTIVE
.bmAttributes = USB_ENDPOINT_SYNC_ADAPTIVE
| USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = __constant_cpu_to_le16(OUT_EP_MAX_PACKET_SIZE),
.bInterval = 4,
};
/* Class-specific AS ISO OUT Endpoint Descriptor */
static struct usb_as_iso_endpoint_descriptor as_iso_out_desc __initdata = {
.bLength = USB_AS_ISO_ENDPOINT_DESC_SIZE,
static struct uac_iso_endpoint_descriptor as_iso_out_desc __initdata = {
.bLength = UAC_ISO_ENDPOINT_DESC_SIZE,
.bDescriptorType = USB_DT_CS_ENDPOINT,
.bDescriptorSubtype = EP_GENERAL,
.bDescriptorSubtype = UAC_EP_GENERAL,
.bmAttributes = 1,
.bLockDelayUnits = 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().
*/
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);
break;
case USB_AUDIO_GET_INTF:
case USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE:
value = audio_get_intf_req(f, ctrl);
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 */
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(&volume_control.list, &feature_unit.control);
volume_control.data[_CUR] = 0xffc0;
volume_control.data[_MIN] = 0xe3a0;
volume_control.data[_MAX] = 0xfff0;
volume_control.data[_RES] = 0x0030;
volume_control.data[UAC__CUR] = 0xffc0;
volume_control.data[UAC__MIN] = 0xe3a0;
volume_control.data[UAC__MAX] = 0xfff0;
volume_control.data[UAC__RES] = 0x0030;
return 0;
}
......
/*
* 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;
}
......@@ -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));
if (skb)
rndis_add_hdr(skb);
return skb;
struct sk_buff *skb2;
skb2 = skb_realloc_headroom(skb, sizeof(struct rndis_packet_msg_type));
if (skb2)
rndis_add_hdr(skb2);
dev_kfree_skb_any(skb);
return skb2;
}
static void rndis_response_available(void *_rndis)
......
......@@ -2750,6 +2750,10 @@ static int __devexit qe_udc_remove(struct of_device *ofdev)
/*-------------------------------------------------------------------------*/
static struct of_device_id __devinitdata qe_udc_match[] = {
{
.compatible = "fsl,mpc8323-qe-usb",
.data = (void *)PORT_QE,
},
{
.compatible = "fsl,mpc8360-qe-usb",
.data = (void *)PORT_QE,
......
......@@ -191,7 +191,7 @@ module_param(qlen, uint, S_IRUGO);
#define GMIDI_MS_INTERFACE 1
#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_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 */
static const struct usb_ac_header_descriptor_1 ac_header_desc = {
.bLength = USB_DT_AC_HEADER_SIZE(1),
static const struct uac_ac_header_descriptor_1 ac_header_desc = {
.bLength = UAC_DT_AC_HEADER_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = USB_MS_HEADER,
.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,
.baInterfaceNr = {
[0] = GMIDI_MS_INTERFACE,
......
......@@ -56,6 +56,7 @@
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
/*
* 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;
}
/* 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 = {
.get_frame = pxa25x_udc_get_frame,
.wakeup = pxa25x_udc_wakeup,
.vbus_session = pxa25x_udc_vbus_session,
.pullup = pxa25x_udc_pullup,
// .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.
.vbus_draw = pxa25x_udc_vbus_draw,
};
/*-------------------------------------------------------------------------*/
......@@ -1303,9 +1316,23 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
* for set_configuration as well as eventual disconnect.
*/
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);
dump_state(dev);
return 0;
bind_fail:
return retval;
}
EXPORT_SYMBOL(usb_gadget_register_driver);
......@@ -1351,6 +1378,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
stop_activity(dev, driver);
local_irq_enable();
if (dev->transceiver)
(void) otg_set_peripheral(dev->transceiver, NULL);
driver->unbind(&dev->gadget);
dev->gadget.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->mach = pdev->dev.platform_data;
dev->transceiver = otg_get_transceiver();
if (gpio_is_valid(dev->mach->gpio_vbus)) {
if ((retval = gpio_request(dev->mach->gpio_vbus,
"pxa25x_udc GPIO VBUS"))) {
......@@ -2264,6 +2296,10 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
if (gpio_is_valid(dev->mach->gpio_vbus))
gpio_free(dev->mach->gpio_vbus);
err_gpio_vbus:
if (dev->transceiver) {
otg_put_transceiver(dev->transceiver);
dev->transceiver = NULL;
}
clk_put(dev->clk);
err_clk:
return retval;
......@@ -2305,6 +2341,11 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
clk_put(dev->clk);
if (dev->transceiver) {
otg_put_transceiver(dev->transceiver);
dev->transceiver = NULL;
}
platform_set_drvdata(pdev, NULL);
the_controller = NULL;
return 0;
......
......@@ -128,6 +128,7 @@ struct pxa25x_udc {
struct device *dev;
struct clk *clk;
struct pxa2xx_udc_mach_info *mach;
struct otg_transceiver *transceiver;
u64 dma_mask;
struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS];
......
......@@ -1022,22 +1022,29 @@ static rndis_resp_t *rndis_add_response (int configNr, u32 length)
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 */
__le32 *tmp = (void *) skb->data;
/* MessageType, MessageLength */
if (cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
!= get_unaligned(tmp++))
!= get_unaligned(tmp++)) {
dev_kfree_skb_any(skb);
return -EINVAL;
}
tmp++;
/* 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;
}
skb_trim(skb, get_unaligned_le32(tmp++));
skb_queue_tail(list, skb);
return 0;
}
......
......@@ -251,7 +251,8 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID,
const char *vendorDescr);
int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
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);
void rndis_free_response (int configNr, u8 *buf);
......
......@@ -2392,7 +2392,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
grstctl = readl(hsotg->regs + S3C_GRSTCTL);
} 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");
return -EINVAL;
}
......@@ -2514,8 +2514,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
* DMA mode we may need this. */
writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk |
S3C_DOEPMSK_EPDisbldMsk |
using_dma(hsotg) ? (S3C_DIEPMSK_XferComplMsk |
S3C_DIEPMSK_TimeOUTMsk) : 0,
(using_dma(hsotg) ? (S3C_DIEPMSK_XferComplMsk |
S3C_DIEPMSK_TimeOUTMsk) : 0),
hsotg->regs + S3C_DOEPMSK);
writel(0, hsotg->regs + S3C_DAINTMSK);
......
......@@ -1703,8 +1703,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n",
driver->driver.name);
if (driver->disconnect)
driver->disconnect(&udc->gadget);
driver->unbind(&udc->gadget);
device_del(&udc->gadget.dev);
udc->driver = NULL;
......
......@@ -253,11 +253,13 @@ static int gaudio_open_snd_dev(struct gaudio *card)
snd->filp = filp_open(fn_cap, O_RDONLY, 0);
if (IS_ERR(snd->filp)) {
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;
}
......
......@@ -37,8 +37,9 @@
* one (!) network link through the USB gadget stack, normally "usb0".
*
* The control and data models are handled by the function driver which
* connects to this code; such as CDC Ethernet, "CDC Subset", or RNDIS.
* That includes all descriptor and endpoint management.
* connects to this code; such as CDC Ethernet (ECM or EEM),
* "CDC Subset", or RNDIS. That includes all descriptor and endpoint
* management.
*
* Link level addressing is handled by this component using module
* parameters; if no such parameters are provided, random link level
......@@ -68,9 +69,13 @@ struct eth_dev {
struct list_head tx_reqs, rx_reqs;
atomic_t tx_qlen;
struct sk_buff_head rx_frames;
unsigned header_len;
struct sk_buff *(*wrap)(struct sk_buff *skb);
int (*unwrap)(struct sk_buff *skb);
struct sk_buff *(*wrap)(struct gether *, struct sk_buff *skb);
int (*unwrap)(struct gether *,
struct sk_buff *skb,
struct sk_buff_head *list);
struct work_struct work;
......@@ -269,7 +274,7 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
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;
int status = req->status;
......@@ -278,26 +283,47 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req)
/* normal completion */
case 0:
skb_put(skb, req->actual);
if (dev->unwrap)
status = dev->unwrap(skb);
if (status < 0
|| ETH_HLEN > skb->len
|| skb->len > ETH_FRAME_LEN) {
dev->net->stats.rx_errors++;
dev->net->stats.rx_length_errors++;
DBG(dev, "rx length %d\n", skb->len);
break;
}
skb->protocol = eth_type_trans(skb, dev->net);
dev->net->stats.rx_packets++;
dev->net->stats.rx_bytes += skb->len;
if (dev->unwrap) {
unsigned long flags;
/* no buffer copies needed, unless hardware can't
* use skb buffers.
*/
status = netif_rx(skb);
spin_lock_irqsave(&dev->lock, flags);
if (dev->port_usb) {
status = dev->unwrap(dev->port_usb,
skb,
&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 = 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;
/* 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
*/
if (dev->wrap) {
struct sk_buff *skb_new;
unsigned long flags;
skb_new = dev->wrap(skb);
if (!skb_new)
spin_lock_irqsave(&dev->lock, flags);
if (dev->port_usb)
skb = dev->wrap(dev->port_usb, skb);
spin_unlock_irqrestore(&dev->lock, flags);
if (!skb)
goto drop;
dev_kfree_skb_any(skb);
skb = skb_new;
length = skb->len;
}
req->buf = skb->data;
......@@ -578,9 +605,9 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
}
if (retval) {
dev_kfree_skb_any(skb);
drop:
dev->net->stats.tx_dropped++;
dev_kfree_skb_any(skb);
spin_lock_irqsave(&dev->req_lock, flags);
if (list_empty(&dev->tx_reqs))
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->rx_reqs);
skb_queue_head_init(&dev->rx_frames);
/* network device setup */
dev->net = net;
strcpy(net->name, "usb%d");
......
......@@ -60,12 +60,13 @@ struct gether {
u16 cdc_filter;
/* hooks for added framing, as needed for RNDIS and EEM.
* we currently don't support multiple frames per SKB.
*/
/* hooks for added framing, as needed for RNDIS and EEM. */
u32 header_len;
struct sk_buff *(*wrap)(struct sk_buff *skb);
int (*unwrap)(struct sk_buff *skb);
struct sk_buff *(*wrap)(struct gether *port,
struct sk_buff *skb);
int (*unwrap)(struct gether *port,
struct sk_buff *skb,
struct sk_buff_head *list);
/* called on network open/close */
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 */
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 eem_bind_config(struct usb_configuration *c);
#ifdef CONFIG_USB_ETH_RNDIS
......
......@@ -1114,7 +1114,6 @@ int __init gserial_setup(struct usb_gadget *g, unsigned count)
/* export the driver ... */
status = tty_register_driver(gs_tty_driver);
if (status) {
put_tty_driver(gs_tty_driver);
pr_err("%s: cannot register, err %d\n",
__func__, status);
goto fail;
......
......@@ -113,6 +113,12 @@ config USB_EHCI_HCD_PPC_OF
Enables support for the USB controller present on the PowerPC
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
tristate "OXU210HP HCD support"
depends on USB
......@@ -153,6 +159,18 @@ config USB_ISP1760_HCD
To compile this driver as a module, choose M here: the
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
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI
......
......@@ -21,6 +21,7 @@ obj-$(CONFIG_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-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_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_FHCI_HCD) += fhci.o
......
此差异已折叠。
......@@ -199,10 +199,9 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
static int ehci_hcd_au1xxx_drv_suspend(struct platform_device *pdev,
pm_message_t message)
static int ehci_hcd_au1xxx_drv_suspend(struct device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
unsigned long flags;
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);
(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);
au1xxx_stop_ehc();
......@@ -248,10 +241,9 @@ static int ehci_hcd_au1xxx_drv_suspend(struct platform_device *pdev,
return rc;
}
static int ehci_hcd_au1xxx_drv_resume(struct platform_device *pdev)
static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
au1xxx_start_ehc();
......@@ -305,20 +297,25 @@ static int ehci_hcd_au1xxx_drv_resume(struct platform_device *pdev)
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
#define ehci_hcd_au1xxx_drv_suspend NULL
#define ehci_hcd_au1xxx_drv_resume NULL
#define AU1XXX_EHCI_PMOPS NULL
#endif
static struct platform_driver ehci_hcd_au1xxx_driver = {
.probe = ehci_hcd_au1xxx_drv_probe,
.remove = ehci_hcd_au1xxx_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.suspend = ehci_hcd_au1xxx_drv_suspend,
.resume = ehci_hcd_au1xxx_drv_resume,
.driver = {
.name = "au1xxx-ehci",
.owner = THIS_MODULE,
.pm = AU1XXX_EHCI_PMOPS,
}
};
......
......@@ -134,10 +134,11 @@ dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
static void __maybe_unused
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,
qh, qh->hw_next, qh->hw_info1, qh->hw_info2,
qh->hw_current);
dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next);
qh, hw->hw_next, hw->hw_info1, hw->hw_info2, hw->hw_current);
dbg_qtd("overlay", ehci, (struct ehci_qtd *) &hw->hw_qtd_next);
}
static void __maybe_unused
......@@ -400,31 +401,32 @@ static void qh_lines (
char *next = *nextp;
char mark;
__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 = '@';
else
mark = token_mark(ehci, qh->hw_token);
mark = token_mark(ehci, hw->hw_token);
if (mark == '/') { /* qh_alt_next controls qh advance? */
if ((qh->hw_alt_next & QTD_MASK(ehci))
== ehci->async->hw_alt_next)
if ((hw->hw_alt_next & QTD_MASK(ehci))
== ehci->async->hw->hw_alt_next)
mark = '#'; /* blocked */
else if (qh->hw_alt_next == list_end)
else if (hw->hw_alt_next == list_end)
mark = '.'; /* use hw_qtd_next */
/* else alt_next points to some other qtd */
}
scratch = hc32_to_cpup(ehci, &qh->hw_info1);
hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &qh->hw_current) : 0;
scratch = hc32_to_cpup(ehci, &hw->hw_info1);
hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &hw->hw_current) : 0;
temp = scnprintf (next, size,
"qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
qh, scratch & 0x007f,
speed_char (scratch),
(scratch >> 8) & 0x000f,
scratch, hc32_to_cpup(ehci, &qh->hw_info2),
hc32_to_cpup(ehci, &qh->hw_token), mark,
(cpu_to_hc32(ehci, QTD_TOGGLE) & qh->hw_token)
scratch, hc32_to_cpup(ehci, &hw->hw_info2),
hc32_to_cpup(ehci, &hw->hw_token), mark,
(cpu_to_hc32(ehci, QTD_TOGGLE) & hw->hw_token)
? "data1" : "data0",
(hc32_to_cpup(ehci, &qh->hw_alt_next) >> 1) & 0x0f);
(hc32_to_cpup(ehci, &hw->hw_alt_next) >> 1) & 0x0f);
size -= temp;
next += temp;
......@@ -435,10 +437,10 @@ static void qh_lines (
mark = ' ';
if (hw_curr == td->qtd_dma)
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 = '+';
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 = '#';
else if (td->hw_alt_next != list_end)
mark = '/';
......@@ -550,12 +552,15 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
next += temp;
do {
struct ehci_qh_hw *hw;
switch (hc32_to_cpu(ehci, tag)) {
case Q_TYPE_QH:
hw = p.qh->hw;
temp = scnprintf (next, size, " qh%d-%04x/%p",
p.qh->period,
hc32_to_cpup(ehci,
&p.qh->hw_info2)
&hw->hw_info2)
/* uframe masks */
& (QH_CMASK | QH_SMASK),
p.qh);
......@@ -576,7 +581,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
/* show more info the first time around */
if (temp == seen_count) {
u32 scratch = hc32_to_cpup(ehci,
&p.qh->hw_info1);
&hw->hw_info1);
struct ehci_qtd *qtd;
char *type = "";
......@@ -609,7 +614,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
} else
temp = 0;
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;
}
break;
......@@ -879,8 +884,7 @@ static int debug_close(struct inode *inode, struct file *file)
struct debug_buffer *buf = file->private_data;
if (buf) {
if (buf->output_buf)
vfree(buf->output_buf);
vfree(buf->output_buf);
kfree(buf);
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册