Commit f5510e19 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/greg/linux/BK/bleed-2.6

into kroah.com:/home/greg/linux/BK/usb-2.6
parents 141baf80 7e0cb221
CHANGES
- Created based off of scanner & INSTALL from the original touchscreen
- 0.3 - Created based off of scanner & INSTALL from the original touchscreen
driver on freshmeat (http://freshmeat.net/projects/3mtouchscreendriver)
- Amended for linux-2.4.18, then 2.4.19
- Complete rewrite using Linux Input in 2.6.3
- 0.5 - Complete rewrite using Linux Input in 2.6.3
Unfortunately no calibration support at this time
- 1.4 - Multiple changes to support the EXII 5000UC and house cleaning
Changed reset from standard USB dev reset to vendor reset
Changed data sent to host from compensated to raw coordinates
Eliminated vendor/product module params
Performed multiple successfull tests with an EXII-5010UC
DRIVER NOTES:
SUPPORTED HARDWARE:
All controllers have the Vendor: 0x0596 & Product: 0x0001
Installation is simple, you only need to add Linux Input, Linux USB, and the
driver to the kernel. The driver can also be optionally built as a module.
If you have another MicroTouch device that you wish to experiment with
or try using this driver with, but the Vendor and Product ID's are not
coded in, don't despair. If the driver was compiled as a module, you can
pass options to the driver. Simply try:
Controller Description Part Number
------------------------------------------------------
/sbin/modprobe mtouchusb vendor=0x#### product=0x****
USB Capacitive - Pearl Case 14-205 (Discontinued)
USB Capacitive - Black Case 14-124 (Discontinued)
USB Capacitive - No Case 14-206 (Discontinued)
If it works, send me the iVendor & iProduct (or a patch) and I will add...
USB Capacitive - Pearl Case EXII-5010UC
USB Capacitive - Black Case EXII-5030UC
USB Capacitive - No Case EXII-5050UC
DRIVER NOTES:
Installation is simple, you only need to add Linux Input, Linux USB, and the
driver to the kernel. The driver can also be optionally built as a module.
This driver appears to be one of possible 2 Linux USB Input Touchscreen
drivers. Although 3M produces a binary only driver available for
......@@ -28,53 +40,28 @@ download, I persist in updating this driver since I would like to use the
touchscreen for embedded apps using QTEmbedded, DirectFB, etc. So I feel the
logical choice is to use Linux Imput.
A little info about the MicroTouch USB controller (14-206):
Y is inverted, and the device has a total possible resolution of 0 - 65535.
Y is inverted by the driver by:
input.absmin[ABS_Y] = MTOUCHUSB_MAX_YC;
input.absmax[ABS_Y] = MTOUCHUSB_MIN_YC;
absmin & absmax are also used to scale the data, sine it is rather high
resolution.
---------------touch screen area-----------------
I MicroTouch (xmax,ymax) @I
I X I
I ########visible monitor area############## I
I #@ (xmin,ymin) # I
I # # I
I # # I
I # # I
I # # I
I # # I
I Y # # I
I # # I
I # # I
I # # I
I # # I
I # # I
I # (xmax,ymax) @# I
I ########################################## I
I I
I@ MicroTouch (xmin,ymin) I
-------------------------------------------------
Currently there is no way to calibrate the device via this driver. Perhaps
at some point an abstract function will be placed into evdev so generic
functions like calibrations, resets, and vendor information can be requested
(And the drivers would handle the vendor specific tasks).
ADDITIONAL INFORMATION/UPDATES:
Currently there is no way to calibrate the device via this driver. Even if
the device could be calibrated, the driver pulls to raw coordinate data from
the controller. This means calibration must be performed within the
userspace.
The controller screen resolution is now 0 to 16384 for both X and Y reporting
the raw touch data. This is the same for the old and new capacitive USB
controllers.
Perhaps at some point an abstract function will be placed into evdev so
generic functions like calibrations, resets, and vendor information can be
requested from the userspace (And the drivers would handle the vendor specific
tasks).
ADDITIONAL INFORMATION/UPDATES/X CONFIGURATION EXAMPLE:
http://groomlakelabs.com/grandamp/code/microtouch/
TODO:
Implement a control urb again to handle requests to and from the device
such as calibration, etc.
such as calibration, etc once/if it becomes available.
DISCLAMER:
......@@ -83,3 +70,7 @@ this driver! If you want touch drivers only supported within X, please go to:
http://www.3m.com/3MTouchSystems/downloads/
THANKS:
A huge thank you to 3M Touch Systems for the EXII-5010UC controllers for
testing!
......@@ -1229,6 +1229,13 @@ M: James.Bottomley@HansenPartnership.com
L: linux-scsi@vger.kernel.org
S: Maintained
LEGO USB Tower driver
P: Juergen Stuber
M: starblue@users.sourceforge.net
L: legousb-devel@lists.sourceforge.net
W: http://legousb.sourceforge.net/
S: Maintained
LINUX FOR IBM pSERIES (RS/6000)
P: Paul Mackerras
M: paulus@au.ibm.com
......
......@@ -98,14 +98,6 @@ struct bfusb_scb {
static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs);
static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs);
static inline void bfusb_wait_for_urb(struct urb *urb)
{
while (atomic_read(&urb->count) > 1) {
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((5 * HZ + 999) / 1000);
}
}
static struct urb *bfusb_get_completed(struct bfusb *bfusb)
{
struct sk_buff *skb;
......@@ -132,7 +124,6 @@ static void bfusb_unlink_urbs(struct bfusb *bfusb)
while ((skb = skb_dequeue(&bfusb->pending_q))) {
urb = ((struct bfusb_scb *) skb->cb)->urb;
usb_unlink_urb(urb);
bfusb_wait_for_urb(urb);
skb_queue_tail(&bfusb->completed_q, skb);
}
......
......@@ -342,7 +342,7 @@ static int hci_usb_flush(struct hci_dev *hdev)
static inline void hci_usb_wait_for_urb(struct urb *urb)
{
while (atomic_read(&urb->count) > 1) {
while (atomic_read(&urb->kref.refcount) > 1) {
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout((5 * HZ + 999) / 1000);
}
......
......@@ -257,13 +257,18 @@ static void st5481B_mode(struct st5481_bcs *bcs, int mode)
static int st5481_setup_b_out(struct st5481_bcs *bcs)
{
struct usb_device *dev = bcs->adapter->usb_dev;
struct usb_host_interface *altsetting;
struct usb_interface *intf;
struct usb_host_interface *altsetting = NULL;
struct usb_host_endpoint *endpoint;
struct st5481_b_out *b_out = &bcs->b_out;
DBG(4,"");
altsetting = &(dev->config->interface[0]->altsetting[3]);
intf = usb_ifnum_to_if(dev, 0);
if (intf)
altsetting = usb_altnum_to_altsetting(intf, 3);
if (!altsetting)
return -ENXIO;
// Allocate URBs and buffers for the B channel out
endpoint = &altsetting->endpoint[EP_B1_OUT - 1 + bcs->channel * 2];
......
......@@ -652,13 +652,18 @@ static void ph_disconnect(struct st5481_adapter *adapter)
static int st5481_setup_d_out(struct st5481_adapter *adapter)
{
struct usb_device *dev = adapter->usb_dev;
struct usb_host_interface *altsetting;
struct usb_interface *intf;
struct usb_host_interface *altsetting = NULL;
struct usb_host_endpoint *endpoint;
struct st5481_d_out *d_out = &adapter->d_out;
DBG(2,"");
altsetting = &(dev->config->interface[0]->altsetting[3]);
intf = usb_ifnum_to_if(dev, 0);
if (intf)
altsetting = usb_altnum_to_altsetting(intf, 3);
if (!altsetting)
return -ENXIO;
// Allocate URBs and buffers for the D channel out
endpoint = &altsetting->endpoint[EP_D_OUT-1];
......
......@@ -244,7 +244,8 @@ int st5481_setup_usb(struct st5481_adapter *adapter)
struct usb_device *dev = adapter->usb_dev;
struct st5481_ctrl *ctrl = &adapter->ctrl;
struct st5481_intr *intr = &adapter->intr;
struct usb_host_interface *altsetting;
struct usb_interface *intf;
struct usb_host_interface *altsetting = NULL;
struct usb_host_endpoint *endpoint;
int status;
struct urb *urb;
......@@ -257,8 +258,11 @@ int st5481_setup_usb(struct st5481_adapter *adapter)
return status;
}
altsetting = &(dev->config->interface[0]->altsetting[3]);
intf = usb_ifnum_to_if(dev, 0);
if (intf)
altsetting = usb_altnum_to_altsetting(intf, 3);
if (!altsetting)
return -ENXIO;
// Check if the config is sane
if ( altsetting->desc.bNumEndpoints != 7 ) {
......
......@@ -499,7 +499,7 @@ static int cpia_probe(struct usb_interface *intf,
if (udev->descriptor.bNumConfigurations != 1)
return -ENODEV;
interface = &intf->altsetting[0];
interface = intf->cur_altsetting;
printk(KERN_INFO "USB CPiA camera found\n");
......@@ -620,8 +620,6 @@ static void cpia_disconnect(struct usb_interface *intf)
wake_up_interruptible(&ucpia->wq_stream);
udev = interface_to_usbdev(intf);
usb_driver_release_interface(&cpia_driver,
udev->actconfig->interface[0]);
ucpia->curbuff = ucpia->workbuff = NULL;
......
......@@ -1421,7 +1421,7 @@ static int irda_usb_probe(struct usb_interface *intf,
}
/* Find our endpoints */
interface = &intf->altsetting[0];
interface = intf->cur_altsetting;
if(!irda_usb_parse_endpoints(self, interface->endpoint,
interface->desc.bNumEndpoints)) {
ERROR("%s(), Bogus endpoints...\n", __FUNCTION__);
......
......@@ -66,3 +66,4 @@ obj-$(CONFIG_USB_SPEEDTOUCH) += misc/
obj-$(CONFIG_USB_TEST) += misc/
obj-$(CONFIG_USB_TIGL) += misc/
obj-$(CONFIG_USB_USS720) += misc/
obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
......@@ -1234,7 +1234,7 @@ static struct tty_operations bluetooth_ops = {
.chars_in_buffer = bluetooth_chars_in_buffer,
};
int usb_bluetooth_init(void)
static int usb_bluetooth_init(void)
{
int i;
int result;
......@@ -1283,7 +1283,7 @@ int usb_bluetooth_init(void)
}
void usb_bluetooth_exit(void)
static void usb_bluetooth_exit(void)
{
usb_deregister(&usb_bluetooth_driver);
tty_unregister_driver(bluetooth_tty_driver);
......
......@@ -567,6 +567,8 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_
* USB probe and disconnect routines.
*/
#define CHECK_XFERTYPE(descr, xfer_type) (((descr)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == xfer_type)
static int acm_probe (struct usb_interface *intf,
const struct usb_device_id *id)
{
......@@ -583,143 +585,150 @@ static int acm_probe (struct usb_interface *intf,
dev = interface_to_usbdev (intf);
cfacm = dev->actconfig;
/* We know we're probe()d with the control interface. */
ifcom = intf->cur_altsetting;
/* ACM doesn't guarantee the data interface is
* adjacent to the control interface, or that if one
* is there it's not for call management ... so find
* it
*/
for (j = 0; j < cfacm->desc.bNumInterfaces; j++) {
ifdata = cfacm->interface[j]->cur_altsetting;
data = cfacm->interface[j];
if (ifdata->desc.bInterfaceClass == 10 &&
ifdata->desc.bNumEndpoints == 2) {
epctrl = &ifcom->endpoint[0].desc;
epread = &ifdata->endpoint[0].desc;
epwrite = &ifdata->endpoint[1].desc;
if ((epctrl->bEndpointAddress & 0x80) != 0x80 ||
(epctrl->bmAttributes & 3) != 3 ||
(epread->bmAttributes & 3) != 2 ||
(epwrite->bmAttributes & 3) != 2 ||
((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
goto next_interface;
if ((epread->bEndpointAddress & 0x80) != 0x80) {
epread = &ifdata->endpoint[1].desc;
epwrite = &ifdata->endpoint[0].desc;
}
dbg("found data interface at %d\n", j);
break;
} else {
next_interface:
ifdata = NULL;
data = NULL;
}
cfacm = dev->actconfig;
/* We know we're probe()d with the control interface. */
ifcom = intf->cur_altsetting;
/* ACM doesn't guarantee the data interface is
* adjacent to the control interface, or that if one
* is there it's not for call management ... so find
* it
*/
for (j = 0; j < cfacm->desc.bNumInterfaces; j++) {
ifdata = cfacm->interface[j]->cur_altsetting;
data = cfacm->interface[j];
if (ifdata->desc.bInterfaceClass == USB_CLASS_CDC_DATA
&& ifdata->desc.bNumEndpoints == 2) {
epctrl = &ifcom->endpoint[0].desc;
epread = &ifdata->endpoint[0].desc;
epwrite = &ifdata->endpoint[1].desc;
if ((epctrl->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN
|| !CHECK_XFERTYPE(epctrl, USB_ENDPOINT_XFER_INT)
|| !CHECK_XFERTYPE(epread, USB_ENDPOINT_XFER_BULK)
|| !CHECK_XFERTYPE(epwrite, USB_ENDPOINT_XFER_BULK)
|| ((epread->bEndpointAddress & USB_DIR_IN)
^ (epwrite->bEndpointAddress & USB_DIR_IN)) != USB_DIR_IN) {
/* not suitable */
goto next_interface;
}
if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) {
/* descriptors are swapped */
epread = &ifdata->endpoint[1].desc;
epwrite = &ifdata->endpoint[0].desc;
}
dev_dbg(&intf->dev, "found data interface at %d\n", j);
break;
} else {
next_interface:
ifdata = NULL;
data = NULL;
}
}
/* there's been a problem */
if (!ifdata) {
dbg("interface not found (%p)\n", ifdata);
return -ENODEV;
/* there's been a problem */
if (!ifdata) {
dev_dbg(&intf->dev, "data interface not found\n");
return -ENODEV;
}
}
for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
if (acm_table[minor]) {
err("no more free acm devices");
return -ENODEV;
}
for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
if (acm_table[minor]) {
err("no more free acm devices");
return -ENODEV;
}
if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
err("out of memory");
return -ENOMEM;
}
memset(acm, 0, sizeof(struct acm));
ctrlsize = epctrl->wMaxPacketSize;
readsize = epread->wMaxPacketSize;
acm->writesize = epwrite->wMaxPacketSize;
acm->control = intf;
acm->data = data;
acm->minor = minor;
acm->dev = dev;
acm->bh.func = acm_rx_tasklet;
acm->bh.data = (unsigned long) acm;
INIT_WORK(&acm->work, acm_softint, acm);
if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
err("out of memory");
kfree(acm);
return -ENOMEM;
}
if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
dev_dbg(&intf->dev, "out of memory (acm kmalloc)\n");
return -ENOMEM;
}
memset(acm, 0, sizeof(struct acm));
ctrlsize = epctrl->wMaxPacketSize;
readsize = epread->wMaxPacketSize;
acm->writesize = epwrite->wMaxPacketSize;
acm->control = intf;
acm->data = data;
acm->minor = minor;
acm->dev = dev;
acm->bh.func = acm_rx_tasklet;
acm->bh.data = (unsigned long) acm;
INIT_WORK(&acm->work, acm_softint, acm);
if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
dev_dbg(&intf->dev, "out of memory (buf kmalloc)\n");
kfree(acm);
return -ENOMEM;
}
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->ctrlurb) {
err("out of memory");
kfree(acm);
kfree(buf);
return -ENOMEM;
}
acm->readurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->readurb) {
err("out of memory");
usb_free_urb(acm->ctrlurb);
kfree(acm);
kfree(buf);
return -ENOMEM;
}
acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->writeurb) {
err("out of memory");
usb_free_urb(acm->readurb);
usb_free_urb(acm->ctrlurb);
kfree(acm);
kfree(buf);
return -ENOMEM;
}
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->ctrlurb) {
dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
kfree(acm);
kfree(buf);
return -ENOMEM;
}
acm->readurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->readurb) {
dev_dbg(&intf->dev, "out of memory (readurb kmalloc)\n");
usb_free_urb(acm->ctrlurb);
kfree(acm);
kfree(buf);
return -ENOMEM;
}
acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->writeurb) {
dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n");
usb_free_urb(acm->readurb);
usb_free_urb(acm->ctrlurb);
kfree(acm);
kfree(buf);
return -ENOMEM;
}
usb_fill_int_urb(acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
usb_fill_int_urb(acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
usb_fill_bulk_urb(acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
buf += ctrlsize, readsize, acm_read_bulk, acm);
acm->readurb->transfer_flags |= URB_NO_FSBR;
usb_fill_bulk_urb(acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
buf += ctrlsize, readsize, acm_read_bulk, acm);
acm->readurb->transfer_flags |= URB_NO_FSBR;
usb_fill_bulk_urb(acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
buf += readsize, acm->writesize, acm_write_bulk, acm);
acm->writeurb->transfer_flags |= URB_NO_FSBR;
usb_fill_bulk_urb(acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
buf += readsize, acm->writesize, acm_write_bulk, acm);
acm->writeurb->transfer_flags |= URB_NO_FSBR;
dev_info(&intf->dev, "ttyACM%d: USB ACM device", minor);
if ( (j = usb_driver_claim_interface(&acm_driver, data, acm)) != 0) {
err("claim failed");
usb_free_urb(acm->ctrlurb);
usb_free_urb(acm->readurb);
usb_free_urb(acm->writeurb);
kfree(acm);
kfree(buf);
return j;
}
acm_set_control(acm, acm->ctrlout);
tty_register_device(acm_tty_driver, minor, &intf->dev);
acm->line.speed = cpu_to_le32(9600);
acm->line.databits = 8;
acm_set_line(acm, &acm->line);
dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
if ( (j = usb_driver_claim_interface(&acm_driver, data, acm)) != 0) {
err("claim failed");
usb_free_urb(acm->ctrlurb);
usb_free_urb(acm->readurb);
usb_free_urb(acm->writeurb);
kfree(acm);
kfree(buf);
return j;
}
acm_set_control(acm, acm->ctrlout);
tty_register_device(acm_tty_driver, minor, &intf->dev);
acm->line.speed = cpu_to_le32(9600);
acm->line.databits = 8;
acm_set_line(acm, &acm->line);
acm_table[minor] = acm;
usb_set_intfdata (intf, acm);
return 0;
acm_table[minor] = acm;
usb_set_intfdata (intf, acm);
return 0;
}
#undef CHECK_XFERTYPE
static void acm_disconnect(struct usb_interface *intf)
{
......
This diff is collapsed.
......@@ -232,13 +232,21 @@ static char *usb_dump_endpoint_descriptor (
return start;
}
static char *usb_dump_interface_descriptor(char *start, char *end, const struct usb_interface *iface, int setno)
static char *usb_dump_interface_descriptor(char *start, char *end,
const struct usb_interface_cache *intfc,
const struct usb_interface *iface,
int setno)
{
struct usb_interface_descriptor *desc = &iface->altsetting[setno].desc;
const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
char *driver_name = "";
if (start > end)
return start;
down_read(&usb_bus_type.subsys.rwsem);
if (iface)
driver_name = (iface->dev.driver
? iface->dev.driver->name
: "(none)");
start += sprintf(start, format_iface,
desc->bInterfaceNumber,
desc->bAlternateSetting,
......@@ -247,9 +255,7 @@ static char *usb_dump_interface_descriptor(char *start, char *end, const struct
class_decode(desc->bInterfaceClass),
desc->bInterfaceSubClass,
desc->bInterfaceProtocol,
iface->dev.driver
? iface->dev.driver->name
: "(none)");
driver_name);
up_read(&usb_bus_type.subsys.rwsem);
return start;
}
......@@ -258,13 +264,14 @@ static char *usb_dump_interface(
int speed,
char *start,
char *end,
const struct usb_interface_cache *intfc,
const struct usb_interface *iface,
int setno
) {
struct usb_host_interface *desc = &iface->altsetting[setno];
const struct usb_host_interface *desc = &intfc->altsetting[setno];
int i;
start = usb_dump_interface_descriptor(start, end, iface, setno);
start = usb_dump_interface_descriptor(start, end, intfc, iface, setno);
for (i = 0; i < desc->desc.bNumEndpoints; i++) {
if (start > end)
return start;
......@@ -303,6 +310,7 @@ static char *usb_dump_config (
)
{
int i, j;
struct usb_interface_cache *intfc;
struct usb_interface *interface;
if (start > end)
......@@ -311,14 +319,13 @@ static char *usb_dump_config (
return start + sprintf(start, "(null Cfg. desc.)\n");
start = usb_dump_config_descriptor(start, end, &config->desc, active);
for (i = 0; i < config->desc.bNumInterfaces; i++) {
intfc = config->intf_cache[i];
interface = config->interface[i];
if (!interface)
break;
for (j = 0; j < interface->num_altsetting; j++) {
for (j = 0; j < intfc->num_altsetting; j++) {
if (start > end)
return start;
start = usb_dump_interface(speed,
start, end, interface, j);
start, end, intfc, interface, j);
}
}
return start;
......@@ -395,7 +402,7 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
return start;
start = usb_dump_device_strings (start, end, dev);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (start > end)
return start;
......@@ -445,6 +452,7 @@ static char *usb_dump_string(char *start, char *end, const struct usb_device *de
* nbytes - the maximum number of bytes to write
* skip_bytes - the number of bytes to skip before writing anything
* file_offset - the offset into the devices file on completion
* The caller must own the usbdev->serialize semaphore.
*/
static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *skip_bytes, loff_t *file_offset,
struct usb_device *usbdev, struct usb_bus *bus, int level, int index, int count)
......@@ -545,9 +553,13 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski
/* Now look at all of this device's children. */
for (chix = 0; chix < usbdev->maxchild; chix++) {
if (usbdev->children[chix]) {
ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, usbdev->children[chix],
struct usb_device *childdev = usbdev->children[chix];
if (childdev) {
down(&childdev->serialize);
ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, childdev,
bus, level + 1, chix, ++cnt);
up(&childdev->serialize);
if (ret == -EFAULT)
return total_written;
total_written += ret;
......@@ -575,8 +587,11 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) {
/* print devices for this bus */
bus = list_entry(buslist, struct usb_bus, bus_list);
/* recurse through all children of the root hub */
down(&bus->root_hub->serialize);
ret = usb_device_dump(&buf, &nbytes, &skip_bytes, ppos, bus->root_hub, bus, 0, 0, 0);
up(&bus->root_hub->serialize);
if (ret < 0) {
up(&usb_bus_list_lock);
return ret;
......
This diff is collapsed.
......@@ -279,41 +279,53 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, u32 state)
{
struct usb_hcd *hcd;
int retval = 0;
int has_pci_pm;
hcd = pci_get_drvdata(dev);
dev_dbg (hcd->self.controller, "suspend D%d --> D%d\n",
dev->current_state, state);
if (pci_find_capability(dev, PCI_CAP_ID_PM)) {
dev_dbg(hcd->self.controller, "No PM capability\n");
return 0;
}
/* even when the PCI layer rejects some of the PCI calls
* below, HCs can try global suspend and reduce DMA traffic.
* PM-sensitive HCDs may already have done this.
*/
has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
if (has_pci_pm)
dev_dbg(hcd->self.controller, "suspend D%d --> D%d\n",
dev->current_state, state);
switch (hcd->state) {
case USB_STATE_HALT:
dev_dbg (hcd->self.controller, "halted; hcd not suspended\n");
break;
case USB_STATE_SUSPENDED:
case HCD_STATE_SUSPENDED:
dev_dbg (hcd->self.controller, "hcd already suspended\n");
break;
default:
/* remote wakeup needs hub->suspend() cooperation */
// pci_enable_wake (dev, 3, 1);
pci_save_state (dev, hcd->pci_state);
/* driver may want to disable DMA etc */
hcd->state = USB_STATE_QUIESCING;
retval = hcd->driver->suspend (hcd, state);
if (retval)
dev_dbg (hcd->self.controller,
"suspend fail, retval %d\n",
retval);
else
hcd->state = USB_STATE_SUSPENDED;
else {
hcd->state = HCD_STATE_SUSPENDED;
pci_save_state (dev, hcd->pci_state);
#ifdef CONFIG_USB_SUSPEND
pci_enable_wake (dev, state, hcd->remote_wakeup);
pci_enable_wake (dev, 4, hcd->remote_wakeup);
#endif
/* no DMA or IRQs except in D0 */
pci_disable_device (dev);
free_irq (hcd->irq, hcd);
if (has_pci_pm)
retval = pci_set_power_state (dev, state);
if (retval < 0) {
dev_dbg (&dev->dev,
"PCI suspend fail, %d\n",
retval);
(void) usb_hcd_pci_resume (dev);
}
}
}
pci_set_power_state (dev, state);
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_suspend);
......@@ -328,23 +340,36 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
{
struct usb_hcd *hcd;
int retval;
int has_pci_pm;
hcd = pci_get_drvdata(dev);
dev_dbg (hcd->self.controller, "resume from state D%d\n",
dev->current_state);
has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
if (has_pci_pm)
dev_dbg(hcd->self.controller, "resume from state D%d\n",
dev->current_state);
if (hcd->state != USB_STATE_SUSPENDED) {
if (hcd->state != HCD_STATE_SUSPENDED) {
dev_dbg (hcd->self.controller,
"can't resume, not suspended!\n");
return -EL3HLT;
}
hcd->state = USB_STATE_RESUMING;
pci_set_power_state (dev, 0);
if (has_pci_pm)
pci_set_power_state (dev, 0);
retval = request_irq (dev->irq, usb_hcd_irq, SA_SHIRQ,
hcd->description, hcd);
if (retval < 0) {
dev_err (hcd->self.controller,
"can't restore IRQ after resume!\n");
return retval;
}
pci_set_master (dev);
pci_restore_state (dev, hcd->pci_state);
/* remote wakeup needs hub->suspend() cooperation */
// pci_enable_wake (dev, 3, 0);
#ifdef CONFIG_USB_SUSPEND
pci_enable_wake (dev, dev->current_state, 0);
pci_enable_wake (dev, 4, 0);
#endif
retval = hcd->driver->resume (hcd);
if (!HCD_IS_RUNNING (hcd->state)) {
......
......@@ -171,10 +171,10 @@ static const u8 fs_rh_config_descriptor [] = {
0x01, /* __u8 bNumInterfaces; (1) */
0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */
0x40, /* __u8 bmAttributes;
Bit 7: Bus-powered,
0xc0, /* __u8 bmAttributes;
Bit 7: must be set,
6: Self-powered,
5 Remote-wakwup,
5: Remote wakeup,
4..0: resvd */
0x00, /* __u8 MaxPower; */
......@@ -218,10 +218,10 @@ static const u8 hs_rh_config_descriptor [] = {
0x01, /* __u8 bNumInterfaces; (1) */
0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */
0x40, /* __u8 bmAttributes;
Bit 7: Bus-powered,
0xc0, /* __u8 bmAttributes;
Bit 7: must be set,
6: Self-powered,
5 Remote-wakwup,
5: Remote wakeup,
4..0: resvd */
0x00, /* __u8 MaxPower; */
......@@ -324,13 +324,15 @@ static int rh_string (
/* Root hub control transfers execute synchronously */
static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
{
struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
struct usb_ctrlrequest *cmd;
u16 typeReq, wValue, wIndex, wLength;
const u8 *bufp = 0;
u8 *ubuf = urb->transfer_buffer;
int len = 0;
int patch_wakeup = 0;
unsigned long flags;
cmd = (struct usb_ctrlrequest *) urb->setup_packet;
typeReq = (cmd->bRequestType << 8) | cmd->bRequest;
wValue = le16_to_cpu (cmd->wValue);
wIndex = le16_to_cpu (cmd->wIndex);
......@@ -347,13 +349,21 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
/* DEVICE REQUESTS */
case DeviceRequest | USB_REQ_GET_STATUS:
// DEVICE_REMOTE_WAKEUP
ubuf [0] = 1; // selfpowered
ubuf [0] = (hcd->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP)
| (1 << USB_DEVICE_SELF_POWERED);
ubuf [1] = 0;
/* FALLTHROUGH */
break;
case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
if (wValue == USB_DEVICE_REMOTE_WAKEUP)
hcd->remote_wakeup = 0;
else
goto error;
break;
case DeviceOutRequest | USB_REQ_SET_FEATURE:
dev_dbg (hcd->self.controller, "no device features yet yet\n");
if (hcd->can_wakeup && wValue == USB_DEVICE_REMOTE_WAKEUP)
hcd->remote_wakeup = 1;
else
goto error;
break;
case DeviceRequest | USB_REQ_GET_CONFIGURATION:
ubuf [0] = 1;
......@@ -379,6 +389,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
bufp = fs_rh_config_descriptor;
len = sizeof fs_rh_config_descriptor;
}
if (hcd->can_wakeup)
patch_wakeup = 1;
break;
case USB_DT_STRING << 8:
urb->actual_length = rh_string (
......@@ -444,6 +456,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
urb->actual_length = len;
// always USB_DIR_IN, toward host
memcpy (ubuf, bufp, len);
/* report whether RH hardware supports remote wakeup */
if (patch_wakeup)
((struct usb_config_descriptor *)ubuf)->bmAttributes
|= USB_CONFIG_ATT_WAKEUP;
}
/* any errors get returned through the urb completion */
......@@ -762,10 +779,22 @@ int usb_register_root_hub (struct usb_device *usb_dev, struct device *parent_dev
set_bit (devnum, usb_dev->bus->devmap.devicemap);
usb_dev->state = USB_STATE_ADDRESS;
usb_dev->epmaxpacketin[0] = usb_dev->epmaxpacketout[0] = 64;
retval = usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);
if (retval != sizeof usb_dev->descriptor) {
dev_dbg (parent_dev, "can't read %s device descriptor %d\n",
usb_dev->dev.bus_id, retval);
return (retval < 0) ? retval : -EMSGSIZE;
}
(void) usb_get_dev (usb_dev);
down (&usb_dev->serialize);
retval = usb_new_device (usb_dev);
if (retval)
dev_err (parent_dev, "can't register root hub for %s, %d\n",
usb_dev->dev.bus_id, retval);
up (&usb_dev->serialize);
usb_put_dev (usb_dev);
return retval;
}
EXPORT_SYMBOL (usb_register_root_hub);
......
......@@ -74,6 +74,8 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
*/
struct hc_driver *driver; /* hw-specific hooks */
unsigned saw_irq : 1;
unsigned can_wakeup:1; /* hw supports wakeup? */
unsigned remote_wakeup:1;/* sw should use wakeup? */
int irq; /* irq allocated */
void *regs; /* device memory/io */
......@@ -94,7 +96,7 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
# define USB_STATE_RUNNING (__ACTIVE)
# define USB_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
# define USB_STATE_RESUMING (__SUSPEND|__TRANSIENT)
# define USB_STATE_SUSPENDED (__SUSPEND)
# define HCD_STATE_SUSPENDED (__SUSPEND)
#define HCD_IS_RUNNING(state) ((state) & __ACTIVE)
#define HCD_IS_SUSPENDED(state) ((state) & __SUSPEND)
......@@ -344,9 +346,16 @@ extern void usb_deregister_bus (struct usb_bus *);
extern int usb_register_root_hub (struct usb_device *usb_dev,
struct device *parent_dev);
/* for portability to 2.4, hcds should call this */
static inline int hcd_register_root (struct usb_hcd *hcd)
{
/* hcd->driver->start() reported can_wakeup, probably with
* assistance from board's boot firmware.
* NOTE: normal devices won't enable wakeup by default.
*/
if (hcd->can_wakeup)
dev_dbg (hcd->self.controller, "supports USB remote wakeup\n");
hcd->remote_wakeup = hcd->can_wakeup;
return usb_register_root_hub (
hcd_to_bus (hcd)->root_hub, hcd->self.controller);
}
......
This diff is collapsed.
......@@ -209,6 +209,8 @@ struct usb_hub {
struct semaphore khubd_sem;
struct usb_tt tt; /* Transaction Translator */
u8 power_budget; /* in 2mA units; or zero */
unsigned has_indicators:1;
enum hub_led_mode indicator[USB_MAXCHILDREN];
struct work_struct leds;
......
......@@ -717,9 +717,6 @@ void usbfs_remove_device(struct usb_device *dev)
while (!list_empty(&dev->filelist)) {
ds = list_entry(dev->filelist.next, struct dev_state, list);
list_del_init(&ds->list);
down_write(&ds->devsem);
ds->dev = NULL;
up_write(&ds->devsem);
if (ds->discsignr) {
sinfo.si_signo = SIGPIPE;
sinfo.si_errno = EPIPE;
......
......@@ -796,10 +796,6 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf)
}
}
static void release_interface(struct device *dev)
{
}
/*
* usb_disable_device - Disable all the endpoints for a USB device
* @dev: the device whose endpoints are being disabled
......@@ -835,6 +831,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
dev_dbg (&dev->dev, "unregistering interface %s\n",
interface->dev.bus_id);
device_unregister (&interface->dev);
dev->actconfig->interface[i] = NULL;
}
dev->actconfig = 0;
if (dev->state == USB_STATE_CONFIGURED)
......@@ -1071,6 +1068,16 @@ int usb_reset_configuration(struct usb_device *dev)
return 0;
}
static void release_interface(struct device *dev)
{
struct usb_interface *intf = to_usb_interface(dev);
struct usb_interface_cache *intfc =
altsetting_to_usb_interface_cache(intf->altsetting);
kref_put(&intfc->ref);
kfree(intf);
}
/*
* usb_set_configuration - Makes a particular device setting be current
* @dev: the device whose configuration is being updated
......@@ -1109,19 +1116,19 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
{
int i, ret;
struct usb_host_config *cp = NULL;
struct usb_interface **new_interfaces = NULL;
int n, nintf;
/* dev->serialize guards all config changes */
for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
if (dev->config[i].desc.bConfigurationValue == configuration) {
cp = &dev->config[i];
break;
}
}
if ((!cp && configuration != 0)) {
ret = -EINVAL;
goto out;
}
if ((!cp && configuration != 0))
return -EINVAL;
/* The USB spec says configuration 0 means unconfigured.
* But if a device includes a configuration numbered 0,
......@@ -1130,6 +1137,34 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
if (cp && configuration == 0)
dev_warn(&dev->dev, "config 0 descriptor??\n");
/* Allocate memory for new interfaces before doing anything else,
* so that if we run out then nothing will have changed. */
n = nintf = 0;
if (cp) {
nintf = cp->desc.bNumInterfaces;
new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),
GFP_KERNEL);
if (!new_interfaces) {
dev_err(&dev->dev, "Out of memory");
return -ENOMEM;
}
for (; n < nintf; ++n) {
new_interfaces[n] = kmalloc(
sizeof(struct usb_interface),
GFP_KERNEL);
if (!new_interfaces[n]) {
dev_err(&dev->dev, "Out of memory");
ret = -ENOMEM;
free_interfaces:
while (--n >= 0)
kfree(new_interfaces[n]);
kfree(new_interfaces);
return ret;
}
}
}
/* if it's already configured, clear out old state first.
* getting rid of old interfaces means unbinding their drivers.
*/
......@@ -1139,7 +1174,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
NULL, 0, HZ * USB_CTRL_SET_TIMEOUT)) < 0)
goto out;
goto free_interfaces;
dev->actconfig = cp;
if (!cp)
......@@ -1147,14 +1182,21 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
else {
dev->state = USB_STATE_CONFIGURED;
/* re-initialize hc/hcd/usbcore interface/endpoint state.
* this triggers binding of drivers to interfaces; and
* maybe probe() calls will choose different altsettings.
/* Initialize the new interface structures and the
* hc/hcd/usbcore interface/endpoint state.
*/
for (i = 0; i < cp->desc.bNumInterfaces; ++i) {
struct usb_interface *intf = cp->interface[i];
for (i = 0; i < nintf; ++i) {
struct usb_interface_cache *intfc;
struct usb_interface *intf;
struct usb_host_interface *alt;
cp->interface[i] = intf = new_interfaces[i];
memset(intf, 0, sizeof(*intf));
intfc = cp->intf_cache[i];
intf->altsetting = intfc->altsetting;
intf->num_altsetting = intfc->num_altsetting;
kref_get(&intfc->ref);
alt = usb_altnum_to_altsetting(intf, 0);
/* No altsetting 0? We'll assume the first altsetting.
......@@ -1178,12 +1220,15 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
configuration,
alt->desc.bInterfaceNumber);
}
kfree(new_interfaces);
/* Now that all interfaces are setup, probe() calls
* may claim() any interface that's not yet bound.
* Many class drivers need that: CDC, audio, video, etc.
/* Now that all the interfaces are set up, register them
* to trigger binding of drivers to interfaces. probe()
* routines may install different altsettings and may
* claim() any interfaces not yet bound. Many class drivers
* need that: CDC, audio, video, etc.
*/
for (i = 0; i < cp->desc.bNumInterfaces; ++i) {
for (i = 0; i < nintf; ++i) {
struct usb_interface *intf = cp->interface[i];
struct usb_interface_descriptor *desc;
......@@ -1204,7 +1249,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
}
}
out:
return ret;
}
......
......@@ -13,6 +13,14 @@
#include <linux/usb.h>
#include "hcd.h"
#define to_urb(d) container_of(d, struct urb, kref)
static void urb_destroy(struct kref *kref)
{
struct urb *urb = to_urb(kref);
kfree(urb);
}
/**
* usb_init_urb - initializes a urb so that it can be used by a USB driver
* @urb: pointer to the urb to initialize
......@@ -31,7 +39,7 @@ void usb_init_urb(struct urb *urb)
{
if (urb) {
memset(urb, 0, sizeof(*urb));
urb->count = (atomic_t)ATOMIC_INIT(1);
kref_init(&urb->kref, urb_destroy);
spin_lock_init(&urb->lock);
}
}
......@@ -80,8 +88,7 @@ struct urb *usb_alloc_urb(int iso_packets, int mem_flags)
void usb_free_urb(struct urb *urb)
{
if (urb)
if (atomic_dec_and_test(&urb->count))
kfree(urb);
kref_put(&urb->kref);
}
/**
......@@ -96,11 +103,9 @@ void usb_free_urb(struct urb *urb)
*/
struct urb * usb_get_urb(struct urb *urb)
{
if (urb) {
atomic_inc(&urb->count);
return urb;
} else
return NULL;
if (urb)
kref_get(&urb->kref);
return urb;
}
......@@ -232,6 +237,8 @@ int usb_submit_urb(struct urb *urb, int mem_flags)
(dev->state < USB_STATE_DEFAULT) ||
(!dev->bus) || (dev->devnum <= 0))
return -ENODEV;
if (dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
if (!(op = dev->bus->op) || !op->submit_urb)
return -ENODEV;
......
......@@ -1064,92 +1064,29 @@ static inline void usb_show_string(struct usb_device *dev, char *id, int index)
}
/*
* By the time we get here, we chose a new device address
* and is in the default state. We need to identify the thing and
* get the ball rolling..
* usb_new_device - perform initial device setup (usbcore-internal)
* @dev: newly addressed device (in ADDRESS state)
*
* Returns 0 for success, != 0 for error.
* This is called with devices which have been enumerated, but not yet
* configured. The device descriptor is available, but not descriptors
* for any device configuration. The caller owns dev->serialize, and
* the device is not visible through sysfs or other filesystem code.
*
* Returns 0 for success (device is configured and listed, with its
* interfaces, in sysfs); else a negative errno value. On error, one
* reference count to the device has been dropped.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver should ever call this; root hub registration
* uses it only indirectly.
*/
#define NEW_DEVICE_RETRYS 2
#define SET_ADDRESS_RETRYS 2
int usb_new_device(struct usb_device *dev)
{
int err = -EINVAL;
int err;
int i;
int j;
int config;
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
*/
switch (dev->speed) {
case USB_SPEED_HIGH: /* fixed at 64 */
i = 64;
break;
case USB_SPEED_FULL: /* 8, 16, 32, or 64 */
/* to determine the ep0 maxpacket size, read the first 8
* bytes from the device descriptor to get bMaxPacketSize0;
* then correct our initial (small) guess.
*/
// FALLTHROUGH
case USB_SPEED_LOW: /* fixed at 8 */
i = 8;
break;
default:
goto fail;
}
dev->epmaxpacketin [0] = i;
dev->epmaxpacketout[0] = i;
for (i = 0; i < NEW_DEVICE_RETRYS; ++i) {
for (j = 0; j < SET_ADDRESS_RETRYS; ++j) {
err = usb_set_address(dev);
if (err >= 0)
break;
wait_ms(200);
}
if (err < 0) {
dev_err(&dev->dev,
"device not accepting address %d, error %d\n",
dev->devnum, err);
goto fail;
}
wait_ms(10); /* Let the SET_ADDRESS settle */
/* high and low speed devices don't need this... */
err = usb_get_device_descriptor(dev, 8);
if (err >= 8)
break;
wait_ms(100);
}
if (err < 8) {
dev_err(&dev->dev, "device descriptor read/8, error %d\n", err);
goto fail;
}
if (dev->speed == USB_SPEED_FULL) {
usb_disable_endpoint(dev, 0);
usb_endpoint_running(dev, 0, 1);
usb_endpoint_running(dev, 0, 0);
dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
}
/* USB device state == addressed ... still not usable */
err = usb_get_device_descriptor(dev, sizeof(dev->descriptor));
if (err != (signed)sizeof(dev->descriptor)) {
dev_err(&dev->dev, "device descriptor read/all, error %d\n", err);
goto fail;
}
err = usb_get_configuration(dev);
if (err < 0) {
dev_err(&dev->dev, "can't read configurations, error %d\n",
......@@ -1170,13 +1107,10 @@ int usb_new_device(struct usb_device *dev)
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
#endif
down(&dev->serialize);
/* put device-specific files into sysfs */
err = device_add (&dev->dev);
if (err) {
dev_err(&dev->dev, "can't device_add, error %d\n", err);
up(&dev->serialize);
goto fail;
}
usb_create_driverfs_dev_files (dev);
......@@ -1193,7 +1127,7 @@ int usb_new_device(struct usb_device *dev)
/* heuristic: Linux is more likely to have class
* drivers, so avoid vendor-specific interfaces.
*/
desc = &dev->config[i].interface[0]
desc = &dev->config[i].intf_cache[0]
->altsetting->desc;
if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
continue;
......@@ -1211,7 +1145,6 @@ int usb_new_device(struct usb_device *dev)
dev->descriptor.bNumConfigurations);
}
err = usb_set_configuration(dev, config);
up(&dev->serialize);
if (err) {
dev_err(&dev->dev, "can't set config #%d, error %d\n",
config, err);
......@@ -1226,9 +1159,10 @@ int usb_new_device(struct usb_device *dev)
return 0;
fail:
dev->state = USB_STATE_DEFAULT;
dev->state = USB_STATE_NOTATTACHED;
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
usb_put_dev(dev);
return err;
}
......@@ -1577,20 +1511,40 @@ int usb_disabled(void)
*/
static int __init usb_init(void)
{
int retval;
if (nousb) {
pr_info ("%s: USB support disabled\n", usbcore_name);
return 0;
}
bus_register(&usb_bus_type);
retval = bus_register(&usb_bus_type);
if (retval)
goto out;
usb_host_init();
usb_major_init();
usbfs_init();
usb_hub_init();
driver_register(&usb_generic_driver);
retval = usb_major_init();
if (retval)
goto major_init_failed;
retval = usbfs_init();
if (retval)
goto fs_init_failed;
retval = usb_hub_init();
if (retval)
goto hub_init_failed;
retval = driver_register(&usb_generic_driver);
if (!retval)
goto out;
return 0;
usb_hub_cleanup();
hub_init_failed:
usbfs_cleanup();
fs_init_failed:
usb_major_cleanup();
major_init_failed:
usb_host_cleanup();
bus_unregister(&usb_bus_type);
out:
return retval;
}
/*
......
......@@ -144,6 +144,7 @@ struct dummy {
struct usb_gadget_driver *driver;
struct dummy_request fifo_req;
u8 fifo_buf [FIFO_SIZE];
u16 devstatus;
struct hcd_dev *hdev;
......@@ -156,6 +157,8 @@ struct dummy {
u32 port_status;
int started;
struct completion released;
unsigned resuming:1;
unsigned long re_timeout;
};
static struct dummy *the_controller;
......@@ -556,8 +559,37 @@ static int dummy_g_get_frame (struct usb_gadget *_gadget)
return tv.tv_usec / 1000;
}
static int dummy_wakeup (struct usb_gadget *_gadget)
{
struct dummy *dum;
dum = container_of (_gadget, struct dummy, gadget);
if ((dum->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) == 0
|| !(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)))
return -EINVAL;
/* hub notices our request, issues downstream resume, etc */
dum->resuming = 1;
dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
return 0;
}
static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
{
struct dummy *dum;
dum = container_of (_gadget, struct dummy, gadget);
if (value)
dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
else
dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
return 0;
}
static const struct usb_gadget_ops dummy_ops = {
.get_frame = dummy_g_get_frame,
.wakeup = dummy_wakeup,
.set_selfpowered = dummy_set_selfpowered,
};
/*-------------------------------------------------------------------------*/
......@@ -653,6 +685,9 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
dum->gadget.ops = &dummy_ops;
dum->gadget.is_dualspeed = 1;
dum->devstatus = 0;
dum->resuming = 0;
INIT_LIST_HEAD (&dum->gadget.ep_list);
for (i = 0; i < DUMMY_ENDPOINTS; i++) {
struct dummy_ep *ep = &dum->ep [i];
......@@ -1130,8 +1165,19 @@ static void dummy_timer (unsigned long _dum)
break;
case USB_REQ_SET_FEATURE:
if (setup.bRequestType == Dev_Request) {
// remote wakeup, and (hs) test mode
value = -EOPNOTSUPP;
value = 0;
switch (setup.wValue) {
case USB_DEVICE_REMOTE_WAKEUP:
break;
default:
value = -EOPNOTSUPP;
}
if (value == 0) {
dum->devstatus |=
(1 << setup.wValue);
maybe_set_status (urb, 0);
}
} else if (setup.bRequestType == Ep_Request) {
// endpoint halt
ep2 = find_endpoint (dum,
......@@ -1147,9 +1193,17 @@ static void dummy_timer (unsigned long _dum)
break;
case USB_REQ_CLEAR_FEATURE:
if (setup.bRequestType == Dev_Request) {
// remote wakeup
value = 0;
maybe_set_status (urb, 0);
switch (setup.wValue) {
case USB_DEVICE_REMOTE_WAKEUP:
dum->devstatus &= ~(1 <<
USB_DEVICE_REMOTE_WAKEUP);
value = 0;
maybe_set_status (urb, 0);
break;
default:
value = -EOPNOTSUPP;
break;
}
} else if (setup.bRequestType == Ep_Request) {
// endpoint halt
ep2 = find_endpoint (dum,
......@@ -1185,6 +1239,10 @@ static void dummy_timer (unsigned long _dum)
break;
}
buf [0] = ep2->halted;
} else if (setup.bRequestType ==
Dev_InRequest) {
buf [0] = (u8)
dum->devstatus;
} else
buf [0] = 0;
}
......@@ -1338,8 +1396,21 @@ static int dummy_hub_control (
case ClearHubFeature:
break;
case ClearPortFeature:
// FIXME won't some of these need special handling?
dum->port_status &= ~(1 << wValue);
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
/* 20msec resume signaling */
dum->resuming = 1;
dum->re_timeout = jiffies + ((HZ * 20)/1000);
break;
case USB_PORT_FEAT_POWER:
dum->port_status = 0;
dum->address = 0;
dum->hdev = 0;
dum->resuming = 0;
break;
default:
dum->port_status &= ~(1 << wValue);
}
break;
case GetHubDescriptor:
hub_descriptor ((struct usb_hub_descriptor *) buf);
......@@ -1350,33 +1421,28 @@ static int dummy_hub_control (
case GetPortStatus:
if (wIndex != 1)
retval = -EPIPE;
((u16 *) buf)[0] = cpu_to_le16 (dum->port_status);
((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
break;
case SetHubFeature:
retval = -EPIPE;
break;
case SetPortFeature:
if (wValue == USB_PORT_FEAT_RESET) {
/* if it's already running, disconnect first */
if (dum->port_status & USB_PORT_STAT_ENABLE) {
dum->port_status &= ~(USB_PORT_STAT_ENABLE
| USB_PORT_STAT_LOW_SPEED
| USB_PORT_STAT_HIGH_SPEED);
if (dum->driver) {
dev_dbg (hardware, "disconnect\n");
stop_activity (dum, dum->driver);
}
/* FIXME test that code path! */
} else
dum->port_status |=
(1 << USB_PORT_FEAT_C_ENABLE);
dum->port_status |= USB_PORT_STAT_ENABLE |
(1 << USB_PORT_FEAT_C_RESET);
/* whoever resets or resumes must GetPortStatus to
* complete it!!
*/
if (dum->resuming && time_after (jiffies, dum->re_timeout)) {
dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND);
dum->resuming = 0;
dum->re_timeout = 0;
if (dum->driver->resume) {
spin_unlock (&dum->lock);
dum->driver->resume (&dum->gadget);
spin_lock (&dum->lock);
}
}
if ((dum->port_status & (1 << USB_PORT_FEAT_RESET)) != 0
&& time_after (jiffies, dum->re_timeout)) {
dum->port_status |= (1 << USB_PORT_FEAT_C_RESET);
dum->port_status &= ~(1 << USB_PORT_FEAT_RESET);
dum->re_timeout = 0;
if (dum->driver) {
dum->port_status |= USB_PORT_STAT_ENABLE;
/* give it the best speed we agree on */
dum->gadget.speed = dum->driver->speed;
dum->gadget.ep0->maxpacket = 64;
......@@ -1395,8 +1461,42 @@ static int dummy_hub_control (
break;
}
}
} else
}
((u16 *) buf)[0] = cpu_to_le16 (dum->port_status);
((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
break;
case SetHubFeature:
retval = -EPIPE;
break;
case SetPortFeature:
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
dum->port_status |= (1 << USB_PORT_FEAT_SUSPEND);
if (dum->driver->suspend) {
spin_unlock (&dum->lock);
dum->driver->suspend (&dum->gadget);
spin_lock (&dum->lock);
}
break;
case USB_PORT_FEAT_RESET:
/* if it's already running, disconnect first */
if (dum->port_status & USB_PORT_STAT_ENABLE) {
dum->port_status &= ~(USB_PORT_STAT_ENABLE
| USB_PORT_STAT_LOW_SPEED
| USB_PORT_STAT_HIGH_SPEED);
if (dum->driver) {
dev_dbg (hardware, "disconnect\n");
stop_activity (dum, dum->driver);
}
/* FIXME test that code path! */
}
/* 50msec reset signaling */
dum->re_timeout = jiffies + ((HZ * 50)/1000);
/* FALLTHROUGH */
default:
dum->port_status |= (1 << wValue);
}
break;
default:
......
......@@ -2054,7 +2054,7 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
buf[0] = 0x80 | 0x70; // Valid, current error
buf[2] = SK(sd);
put_be32(&buf[3], sdinfo); // Sense information
buf[7] = 18 - 7; // Additional sense length
buf[7] = 18 - 8; // Additional sense length
buf[12] = ASC(sd);
buf[13] = ASCQ(sd);
return 18;
......
......@@ -20,7 +20,7 @@
#define gadget_is_dummy(g) 0
#endif
#ifdef CONFIG_USB_GADGET_PXA
#ifdef CONFIG_USB_GADGET_PXA2XX
#define gadget_is_pxa(g) !strcmp("pxa2xx_udc", (g)->name)
#else
#define gadget_is_pxa(g) 0
......
......@@ -157,8 +157,12 @@ do { \
/* debug macro */
#if G_SERIAL_DEBUG
static int debug = G_SERIAL_DEBUG;
#else
static int debug = 0;
#endif
#if G_SERIAL_DEBUG
#define gs_debug(format, arg...) \
do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
......
......@@ -130,6 +130,9 @@ struct zero_dev {
*/
u8 config;
struct usb_ep *in_ep, *out_ep;
/* autoresume timer */
struct timer_list resume;
};
#define xprintk(d,level,fmt,args...) \
......@@ -167,6 +170,12 @@ module_param (buflen, uint, S_IRUGO|S_IWUSR);
module_param (qlen, uint, S_IRUGO|S_IWUSR);
module_param (pattern, uint, S_IRUGO|S_IWUSR);
/*
* if it's nonzero, autoresume says how many seconds to wait
* before trying to wake up the host after suspend.
*/
static unsigned autoresume = 0;
module_param (autoresume, uint, 0);
/*
* Normally the "loopback" configuration is second (index 1) so
......@@ -224,7 +233,7 @@ device_desc = {
.bNumConfigurations = 2,
};
static const struct usb_config_descriptor
static struct usb_config_descriptor
source_sink_config = {
.bLength = sizeof source_sink_config,
.bDescriptorType = USB_DT_CONFIG,
......@@ -237,7 +246,7 @@ source_sink_config = {
.bMaxPower = 1, /* self-powered */
};
static const struct usb_config_descriptor
static struct usb_config_descriptor
loopback_config = {
.bLength = sizeof loopback_config,
.bDescriptorType = USB_DT_CONFIG,
......@@ -1060,6 +1069,19 @@ zero_disconnect (struct usb_gadget *gadget)
*/
}
static void
zero_autoresume (unsigned long _dev)
{
struct zero_dev *dev = (struct zero_dev *) _dev;
int status;
/* normally the host would be woken up for something
* more significant than just a timer firing...
*/
status = usb_gadget_wakeup (dev->gadget);
DBG (dev, "wakeup --> %d\n", status);
}
/*-------------------------------------------------------------------------*/
static void
......@@ -1072,6 +1094,7 @@ zero_unbind (struct usb_gadget *gadget)
/* we've already been disconnected ... no i/o is active */
if (dev->req)
free_ep_req (gadget->ep0, dev->req);
del_timer_sync (&dev->resume);
kfree (dev);
set_gadget_data (gadget, 0);
}
......@@ -1176,6 +1199,14 @@ zero_bind (struct usb_gadget *gadget)
usb_gadget_set_selfpowered (gadget);
init_timer (&dev->resume);
dev->resume.function = zero_autoresume;
dev->resume.data = (unsigned long) dev;
if (autoresume) {
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
gadget->ep0->driver_data = dev;
INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
......@@ -1193,6 +1224,33 @@ zero_bind (struct usb_gadget *gadget)
return -ENOMEM;
}
/*-------------------------------------------------------------------------*/
static void
zero_suspend (struct usb_gadget *gadget)
{
struct zero_dev *dev = get_gadget_data (gadget);
if (gadget->speed == USB_SPEED_UNKNOWN)
return;
if (autoresume) {
mod_timer (&dev->resume, jiffies + (HZ * autoresume));
DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
} else
DBG (dev, "suspend\n");
}
static void
zero_resume (struct usb_gadget *gadget)
{
struct zero_dev *dev = get_gadget_data (gadget);
DBG (dev, "resume\n");
del_timer (&dev->resume);
}
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver zero_driver = {
......@@ -1208,6 +1266,9 @@ static struct usb_gadget_driver zero_driver = {
.setup = zero_setup,
.disconnect = zero_disconnect,
.suspend = zero_suspend,
.resume = zero_resume,
.driver = {
.name = (char *) shortname,
// .shutdown = ...
......
......@@ -170,6 +170,20 @@ dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
itd->index[6], itd->index[7]);
}
static void __attribute__((__unused__))
dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
{
ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
label, sitd->frame, sitd, le32_to_cpu(sitd->hw_next), sitd->urb);
ehci_dbg (ehci,
" addr %08x sched %04x result %08x buf %08x %08x\n",
le32_to_cpu(sitd->hw_fullspeed_ep),
le32_to_cpu(sitd->hw_uframe),
le32_to_cpu(sitd->hw_results),
le32_to_cpu(sitd->hw_buf [0]),
le32_to_cpu(sitd->hw_buf [1]));
}
static int __attribute__((__unused__))
dbg_status_buf (char *buf, unsigned len, char *label, u32 status)
{
......@@ -625,11 +639,20 @@ show_registers (struct class_device *class_dev, char *buf)
spin_lock_irqsave (&ehci->lock, flags);
if (bus->controller->power.power_state) {
size = scnprintf (next, size,
"bus %s, device %s (driver " DRIVER_VERSION ")\n"
"SUSPENDED (no register access)\n",
hcd->self.controller->bus->name,
hcd->self.controller->bus_id);
goto done;
}
/* Capability Registers */
i = HC_VERSION(readl (&ehci->caps->hc_capbase));
temp = scnprintf (next, size,
"bus %s device %s\n"
"EHCI %x.%02x, hcd state %d (driver " DRIVER_VERSION ")\n",
"bus %s, device %s (driver " DRIVER_VERSION ")\n"
"EHCI %x.%02x, hcd state %d\n",
hcd->self.controller->bus->name,
hcd->self.controller->bus_id,
i >> 8, i & 0x0ff, ehci->hcd.state);
......@@ -672,7 +695,7 @@ show_registers (struct class_device *class_dev, char *buf)
next += temp;
for (i = 0; i < HCS_N_PORTS (ehci->hcs_params); i++) {
temp = dbg_port_buf (scratch, sizeof scratch, label, i,
temp = dbg_port_buf (scratch, sizeof scratch, label, i + 1,
readl (&ehci->regs->port_status [i]));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
......@@ -701,6 +724,7 @@ show_registers (struct class_device *class_dev, char *buf)
next += temp;
#endif
done:
spin_unlock_irqrestore (&ehci->lock, flags);
return PAGE_SIZE - size;
......
/*
* Copyright (c) 2000-2002 by David Brownell
* Copyright (c) 2000-2004 by David Brownell
*
* 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
......@@ -69,6 +69,7 @@
*
* HISTORY:
*
* 2004-05-10 Root hub and PCI suspend/resume support; remote wakeup. (db)
* 2004-02-24 Replace pci_* with generic dma_* API calls (dsaxena@plexity.net)
* 2003-12-29 Rewritten high speed iso transfer support (by Michal Sojka,
* <sojkam@centrum.cz>, updates by DB).
......@@ -96,7 +97,7 @@
* 2001-June Works with usb-storage and NEC EHCI on 2.4
*/
#define DRIVER_VERSION "2003-Dec-29"
#define DRIVER_VERSION "2004-May-10"
#define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
......@@ -128,7 +129,7 @@ static int log2_irq_thresh = 0; // 0 to 6
module_param (log2_irq_thresh, int, S_IRUGO);
MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes");
#define INTR_MASK (STS_IAA | STS_FATAL | STS_ERR | STS_INT)
#define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
/*-------------------------------------------------------------------------*/
......@@ -201,6 +202,7 @@ static int ehci_reset (struct ehci_hcd *ehci)
dbg_cmd (ehci, "reset", command);
writel (command, &ehci->regs->command);
ehci->hcd.state = USB_STATE_HALT;
ehci->next_statechange = jiffies;
return handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
}
......@@ -241,6 +243,8 @@ static void ehci_ready (struct ehci_hcd *ehci)
/*-------------------------------------------------------------------------*/
static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
#include "ehci-hub.c"
#include "ehci-mem.c"
#include "ehci-q.c"
......@@ -248,8 +252,6 @@ static void ehci_ready (struct ehci_hcd *ehci)
/*-------------------------------------------------------------------------*/
static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
static void ehci_watchdog (unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
......@@ -428,12 +430,17 @@ static int ehci_start (struct usb_hcd *hcd)
#ifdef CONFIG_PCI
if (hcd->self.controller->bus == &pci_bus_type) {
struct pci_dev *pdev;
u16 port_wake;
pdev = to_pci_dev(hcd->self.controller);
/* Serial Bus Release Number is at PCI 0x60 offset */
pci_read_config_byte(pdev, 0x60, &sbrn);
/* port wake capability, reported by boot firmware */
pci_read_config_word(pdev, 0x62, &port_wake);
hcd->can_wakeup = (port_wake & 1) != 0;
/* help hc dma work well with cachelines */
pci_set_mwi (pdev);
......@@ -615,41 +622,26 @@ static int ehci_get_frame (struct usb_hcd *hcd)
/* suspend/resume, section 4.3 */
/* These routines rely on PCI to handle powerdown and wakeup, and
* transceivers that don't need any software attention to set up
* the right sort of wakeup.
*/
static int ehci_suspend (struct usb_hcd *hcd, u32 state)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int ports;
int i;
ehci_dbg (ehci, "suspend to %d\n", state);
ports = HCS_N_PORTS (ehci->hcs_params);
// FIXME: This assumes what's probably a D3 level suspend...
while (time_before (jiffies, ehci->next_statechange))
msec_delay (100);
// FIXME: usb wakeup events on this bus should resume the machine.
// pci config register PORTWAKECAP controls which ports can do it;
// bios may have initted the register...
/* suspend each port, then stop the hc */
for (i = 0; i < ports; i++) {
int temp = readl (&ehci->regs->port_status [i]);
if ((temp & PORT_PE) == 0
|| (temp & PORT_OWNER) != 0)
continue;
ehci_dbg (ehci, "suspend port %d", i);
temp |= PORT_SUSPEND;
writel (temp, &ehci->regs->port_status [i]);
}
if (hcd->state == USB_STATE_RUNNING)
ehci_ready (ehci);
writel (readl (&ehci->regs->command) & ~CMD_RUN, &ehci->regs->command);
// save pci FLADJ value
#ifdef CONFIG_USB_SUSPEND
(void) usb_suspend_device (hcd->self.root_hub);
#else
/* FIXME lock root hub */
(void) ehci_hub_suspend (hcd);
#endif
/* who tells PCI to reduce power consumption? */
// save (PCI) FLADJ in case of Vaux power loss
return 0;
}
......@@ -657,40 +649,22 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state)
static int ehci_resume (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int ports;
int i;
ehci_dbg (ehci, "resume\n");
ports = HCS_N_PORTS (ehci->hcs_params);
// FIXME: if controller didn't retain state,
// return and let generic code clean it up
// test configured_flag ?
/* resume HC and each port */
// restore pci FLADJ value
// khubd and drivers will set HC running, if needed;
hcd->state = USB_STATE_RUNNING;
// FIXME Philips/Intel/... etc don't really have a "READY"
// state ... turn on CMD_RUN too
for (i = 0; i < ports; i++) {
int temp = readl (&ehci->regs->port_status [i]);
if ((temp & PORT_PE) == 0
|| (temp & PORT_SUSPEND) != 0)
continue;
ehci_dbg (ehci, "resume port %d", i);
temp |= PORT_RESUME;
writel (temp, &ehci->regs->port_status [i]);
readl (&ehci->regs->command); /* unblock posted writes */
wait_ms (20);
temp &= ~PORT_RESUME;
writel (temp, &ehci->regs->port_status [i]);
}
readl (&ehci->regs->command); /* unblock posted writes */
return 0;
int retval;
// maybe restore (PCI) FLADJ
while (time_before (jiffies, ehci->next_statechange))
msec_delay (100);
#ifdef CONFIG_USB_SUSPEND
retval = usb_resume_device (hcd->self.root_hub);
#else
/* FIXME lock root hub */
retval = ehci_hub_resume (hcd);
#endif
if (retval == 0)
hcd->self.controller->power.power_state = 0;
return retval;
}
#endif
......@@ -752,7 +726,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
bh = 0;
#ifdef EHCI_VERBOSE_DEBUG
/* unrequested/ignored: Port Change Detect, Frame List Rollover */
/* unrequested/ignored: Frame List Rollover */
dbg_status (ehci, "irq", status);
#endif
......@@ -774,6 +748,34 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
bh = 1;
}
/* remote wakeup [4.3.1] */
if ((status & STS_PCD) && ehci->hcd.remote_wakeup) {
unsigned i = HCS_N_PORTS (ehci->hcs_params);
/* resume root hub? */
status = readl (&ehci->regs->command);
if (!(status & CMD_RUN))
writel (status | CMD_RUN, &ehci->regs->command);
while (i--) {
status = readl (&ehci->regs->port_status [i]);
if (status & PORT_OWNER)
continue;
if (!(status & PORT_RESUME)
|| ehci->reset_done [i] != 0)
continue;
/* start 20 msec resume signaling from this port,
* and make khubd collect PORT_STAT_C_SUSPEND to
* stop that signaling.
*/
ehci->reset_done [i] = jiffies + MSEC_TO_JIFFIES (20);
mod_timer (&ehci->hcd.rh_timer,
ehci->reset_done [i] + 1);
ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
}
}
/* PCI errors [4.15.2.4] */
if (unlikely ((status & STS_FATAL) != 0)) {
ehci_err (ehci, "fatal error\n");
......@@ -814,7 +816,6 @@ static int ehci_urb_enqueue (
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct list_head qtd_list;
urb->transfer_flags &= ~EHCI_STATE_UNLINK;
INIT_LIST_HEAD (&qtd_list);
switch (usb_pipetype (urb->pipe)) {
......@@ -914,7 +915,6 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
// wait till next completion, do it then.
// completion irqs can wait up to 1024 msec,
urb->transfer_flags |= EHCI_STATE_UNLINK;
break;
}
spin_unlock_irqrestore (&ehci->lock, flags);
......@@ -965,7 +965,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct hcd_dev *dev, int ep)
goto rescan;
case QH_STATE_IDLE: /* fully unlinked */
if (list_empty (&qh->qtd_list)) {
qh_put (ehci, qh);
qh_put (qh);
break;
}
/* else FALL THROUGH */
......
......@@ -28,6 +28,131 @@
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_PM
static int ehci_hub_suspend (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct usb_device *root = hcd_to_bus (&ehci->hcd)->root_hub;
int port;
int status = 0;
if (root->dev.power.power_state != 0)
return 0;
if (time_before (jiffies, ehci->next_statechange))
return -EAGAIN;
port = HCS_N_PORTS (ehci->hcs_params);
spin_lock_irq (&ehci->lock);
/* suspend any active/unsuspended ports, maybe allow wakeup */
while (port--) {
u32 t1 = readl (&ehci->regs->port_status [port]);
u32 t2 = t1;
if ((t1 & PORT_PE) && !(t1 & PORT_OWNER))
t2 |= PORT_SUSPEND;
if (ehci->hcd.remote_wakeup)
t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
else
t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
if (t1 != t2) {
ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
port + 1, t1, t2);
writel (t2, &ehci->regs->port_status [port]);
}
}
/* stop schedules, then turn off HC and clean any completed work */
if (hcd->state == USB_STATE_RUNNING)
ehci_ready (ehci);
ehci->command = readl (&ehci->regs->command);
writel (ehci->command & ~CMD_RUN, &ehci->regs->command);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
ehci_work (ehci, 0);
(void) handshake (&ehci->regs->status, STS_HALT, STS_HALT, 2000);
root->dev.power.power_state = 3;
ehci->next_statechange = jiffies + MSEC_TO_JIFFIES(10);
spin_unlock_irq (&ehci->lock);
return status;
}
/* caller owns root->serialize, and should reset/reinit on error */
static int ehci_hub_resume (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct usb_device *root = hcd_to_bus (&ehci->hcd)->root_hub;
u32 temp;
int i;
if (!root->dev.power.power_state)
return 0;
if (time_before (jiffies, ehci->next_statechange))
return -EAGAIN;
/* re-init operational registers in case we lost power */
if (readl (&ehci->regs->intr_enable) == 0) {
writel (INTR_MASK, &ehci->regs->intr_enable);
writel (0, &ehci->regs->segment);
writel (ehci->periodic_dma, &ehci->regs->frame_list);
writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
/* FIXME will this work even (pci) vAUX was lost? */
}
/* restore CMD_RUN, framelist size, and irq threshold */
writel (ehci->command, &ehci->regs->command);
/* take ports out of suspend */
i = HCS_N_PORTS (ehci->hcs_params);
while (i--) {
temp = readl (&ehci->regs->port_status [i]);
temp &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
if (temp & PORT_SUSPEND) {
ehci->reset_done [i] = jiffies + MSEC_TO_JIFFIES (20);
temp |= PORT_RESUME;
}
writel (temp, &ehci->regs->port_status [i]);
}
i = HCS_N_PORTS (ehci->hcs_params);
wait_ms (20);
while (i--) {
temp = readl (&ehci->regs->port_status [i]);
if ((temp & PORT_SUSPEND) == 0)
continue;
temp &= ~PORT_RESUME;
writel (temp, &ehci->regs->port_status [i]);
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
}
(void) readl (&ehci->regs->command);
/* maybe re-activate the schedule(s) */
temp = 0;
if (ehci->async->qh_next.qh)
temp |= CMD_ASE;
if (ehci->periodic_sched)
temp |= CMD_PSE;
if (temp)
writel (ehci->command | temp, &ehci->regs->command);
root->dev.power.power_state = 0;
ehci->next_statechange = jiffies + MSEC_TO_JIFFIES(5);
ehci->hcd.state = USB_STATE_RUNNING;
return 0;
}
#else
#define ehci_hub_suspend 0
#define ehci_hub_resume 0
#endif /* CONFIG_PM */
/*-------------------------------------------------------------------------*/
static int check_reset_complete (
struct ehci_hcd *ehci,
int index,
......@@ -99,7 +224,11 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
}
if (!(temp & PORT_CONNECT))
ehci->reset_done [i] = 0;
if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0) {
if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0
// PORT_STAT_C_SUSPEND?
|| ((temp & PORT_RESUME) != 0
&& time_after (jiffies,
ehci->reset_done [i]))) {
if (i < 7)
buf [0] |= 1 << (i + 1);
else
......@@ -143,6 +272,8 @@ ehci_hub_descriptor (
/*-------------------------------------------------------------------------*/
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
static int ehci_hub_control (
struct usb_hcd *hcd,
u16 typeReq,
......@@ -194,8 +325,20 @@ static int ehci_hub_control (
&ehci->regs->port_status [wIndex]);
break;
case USB_PORT_FEAT_SUSPEND:
if (temp & PORT_RESET)
goto error;
if (temp & PORT_SUSPEND) {
if ((temp & PORT_PE) == 0)
goto error;
/* resume signaling for 20 msec */
writel ((temp & ~PORT_WAKE_BITS) | PORT_RESUME,
&ehci->regs->port_status [wIndex]);
ehci->reset_done [wIndex] = jiffies
+ MSEC_TO_JIFFIES (20);
}
break;
case USB_PORT_FEAT_C_SUSPEND:
/* ? */
/* we auto-clear this feature */
break;
case USB_PORT_FEAT_POWER:
if (HCS_PPC (ehci->hcs_params))
......@@ -239,15 +382,37 @@ static int ehci_hub_control (
status |= 1 << USB_PORT_FEAT_C_CONNECTION;
if (temp & PORT_PEC)
status |= 1 << USB_PORT_FEAT_C_ENABLE;
// USB_PORT_FEAT_C_SUSPEND
if (temp & PORT_OCC)
status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
/* whoever resumes must GetPortStatus to complete it!! */
if ((temp & PORT_RESUME)
&& time_after (jiffies,
ehci->reset_done [wIndex])) {
status |= 1 << USB_PORT_FEAT_C_SUSPEND;
ehci->reset_done [wIndex] = 0;
/* stop resume signaling */
temp = readl (&ehci->regs->port_status [wIndex]);
writel (temp & ~PORT_RESUME,
&ehci->regs->port_status [wIndex]);
retval = handshake (
&ehci->regs->port_status [wIndex],
PORT_RESUME, 0, 2000 /* 2msec */);
if (retval != 0) {
ehci_err (ehci, "port %d resume error %d\n",
wIndex + 1, retval);
goto error;
}
temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
}
/* whoever resets must GetPortStatus to complete it!! */
if ((temp & PORT_RESET)
&& time_after (jiffies,
ehci->reset_done [wIndex])) {
status |= 1 << USB_PORT_FEAT_C_RESET;
ehci->reset_done [wIndex] = 0;
/* force reset to complete */
writel (temp & ~PORT_RESET,
......@@ -275,7 +440,7 @@ static int ehci_hub_control (
}
if (temp & PORT_PE)
status |= 1 << USB_PORT_FEAT_ENABLE;
if (temp & PORT_SUSPEND)
if (temp & (PORT_SUSPEND|PORT_RESUME))
status |= 1 << USB_PORT_FEAT_SUSPEND;
if (temp & PORT_OC)
status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
......@@ -312,6 +477,11 @@ static int ehci_hub_control (
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
if ((temp & PORT_PE) == 0
|| (temp & PORT_RESET) != 0)
goto error;
if (ehci->hcd.remote_wakeup)
temp |= PORT_WAKE_BITS;
writel (temp | PORT_SUSPEND,
&ehci->regs->port_status [wIndex]);
break;
......@@ -321,6 +491,8 @@ static int ehci_hub_control (
&ehci->regs->port_status [wIndex]);
break;
case USB_PORT_FEAT_RESET:
if (temp & PORT_RESUME)
goto error;
/* line status bits may report this as low speed,
* which can be fine if this root hub has a
* transaction translator built in.
......@@ -342,7 +514,7 @@ static int ehci_hub_control (
* usb 2.0 spec says 50 ms resets on root
*/
ehci->reset_done [wIndex] = jiffies
+ ((50 /* msec */ * HZ) / 1000);
+ MSEC_TO_JIFFIES (50);
}
writel (temp, &ehci->regs->port_status [wIndex]);
break;
......
......@@ -87,6 +87,22 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
}
static void qh_destroy (struct kref *kref)
{
struct ehci_qh *qh = container_of(kref, struct ehci_qh, kref);
struct ehci_hcd *ehci = qh->ehci;
/* clean qtds first, and know this is not linked */
if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
ehci_dbg (ehci, "unused qh not empty!\n");
BUG ();
}
if (qh->dummy)
ehci_qtd_free (ehci, qh->dummy);
usb_put_dev (qh->dev);
dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
}
static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
{
struct ehci_qh *qh;
......@@ -98,7 +114,8 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
return qh;
memset (qh, 0, sizeof *qh);
atomic_set (&qh->refcount, 1);
kref_init(&qh->kref, qh_destroy);
qh->ehci = ehci;
qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD (&qh->qtd_list);
......@@ -114,25 +131,15 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, int flags)
}
/* to share a qh (cpu threads, or hc) */
static inline struct ehci_qh *qh_get (/* ehci, */ struct ehci_qh *qh)
static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
{
atomic_inc (&qh->refcount);
kref_get(&qh->kref);
return qh;
}
static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh)
static inline void qh_put (struct ehci_qh *qh)
{
if (!atomic_dec_and_test (&qh->refcount))
return;
/* clean qtds first, and know this is not linked */
if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
ehci_dbg (ehci, "unused qh not empty!\n");
BUG ();
}
if (qh->dummy)
ehci_qtd_free (ehci, qh->dummy);
usb_put_dev (qh->dev);
dma_pool_free (ehci->qh_pool, qh, qh->qh_dma);
kref_put(&qh->kref);
}
/*-------------------------------------------------------------------------*/
......@@ -145,7 +152,7 @@ static void qh_put (struct ehci_hcd *ehci, struct ehci_qh *qh)
static void ehci_mem_cleanup (struct ehci_hcd *ehci)
{
if (ehci->async)
qh_put (ehci, ehci->async);
qh_put (ehci->async);
ehci->async = 0;
/* DMA consistent memory and pools */
......
......@@ -193,7 +193,7 @@ ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
/* ... update hc-wide periodic stats (for usbfs) */
hcd_to_bus (&ehci->hcd)->bandwidth_int_reqs--;
}
qh_put (ehci, qh);
qh_put (qh);
}
spin_lock (&urb->lock);
......@@ -708,7 +708,7 @@ qh_make (
default:
dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
done:
qh_put (ehci, qh);
qh_put (qh);
return 0;
}
......@@ -951,7 +951,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
// qh->hw_next = cpu_to_le32 (qh->qh_dma);
qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = 0;
qh_put (ehci, qh); // refcount from reclaim
qh_put (qh); // refcount from reclaim
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim;
......@@ -965,7 +965,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
&& HCD_IS_RUNNING (ehci->hcd.state))
qh_link_async (ehci, qh);
else {
qh_put (ehci, qh); // refcount from async list
qh_put (qh); // refcount from async list
/* it's not free to turn the async schedule on/off; leave it
* active but idle for a while once it empties.
......@@ -1067,7 +1067,7 @@ scan_async (struct ehci_hcd *ehci, struct pt_regs *regs)
qh = qh_get (qh);
qh->stamp = ehci->stamp;
temp = qh_completions (ehci, qh, regs);
qh_put (ehci, qh);
qh_put (qh);
if (temp != 0) {
goto rescan;
}
......
......@@ -312,7 +312,7 @@ static void intr_deschedule (
do {
periodic_unlink (ehci, frame, qh);
qh_put (ehci, qh);
qh_put (qh);
frame += qh->period;
} while (frame < ehci->periodic_size);
......@@ -355,7 +355,7 @@ static void intr_deschedule (
dbg ("descheduled qh %p, period = %d frame = %d count = %d, urbs = %d",
qh, qh->period, frame,
atomic_read (&qh->refcount), ehci->periodic_sched);
atomic_read (&qh->kref.refcount), ehci->periodic_sched);
}
static int check_period (
......@@ -1846,7 +1846,7 @@ scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
modified = qh_completions (ehci, temp.qh, regs);
if (unlikely (list_empty (&temp.qh->qtd_list)))
intr_deschedule (ehci, temp.qh, 0);
qh_put (ehci, temp.qh);
qh_put (temp.qh);
break;
case Q_TYPE_FSTN:
/* for "save place" FSTNs, look at QH entries
......
......@@ -84,6 +84,8 @@ struct ehci_hcd { /* one per controller */
struct notifier_block reboot_notifier;
unsigned long actions;
unsigned stamp;
unsigned long next_statechange;
u32 command;
unsigned is_arc_rh_tt:1; /* ARC roothub with TT */
......@@ -99,8 +101,6 @@ struct ehci_hcd { /* one per controller */
/* unwrap an HCD pointer to get an EHCI_HCD pointer */
#define hcd_to_ehci(hcd_ptr) container_of(hcd_ptr, struct ehci_hcd, hcd)
/* NOTE: urb->transfer_flags expected to not use this bit !!! */
#define EHCI_STATE_UNLINK 0x8000 /* urb being unlinked */
enum ehci_timer_action {
TIMER_IO_WATCHDOG,
......@@ -221,7 +221,7 @@ struct ehci_regs {
u32 segment; /* address bits 63:32 if needed */
/* PERIODICLISTBASE: offset 0x14 */
u32 frame_list; /* points to periodic list */
/* ASYNCICLISTADDR: offset 0x18 */
/* ASYNCLISTADDR: offset 0x18 */
u32 async_next; /* address of next async queue head */
u32 reserved [9];
......@@ -237,7 +237,10 @@ struct ehci_regs {
#define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */
#define PORT_WKCONN_E (1<<20) /* wake on connect (enable) */
/* 19:16 for port testing */
/* 15:14 for using port indicator leds (if HCS_INDICATOR allows) */
#define PORT_LED_OFF (0<<14)
#define PORT_LED_AMBER (1<<14)
#define PORT_LED_GREEN (2<<14)
#define PORT_LED_MASK (3<<14)
#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
#define PORT_POWER (1<<12) /* true: has power (see PPC) */
#define PORT_USB11(x) (((x)&(3<<10))==(1<<10)) /* USB 1.1 device */
......@@ -366,7 +369,8 @@ struct ehci_qh {
struct ehci_qtd *dummy;
struct ehci_qh *reclaim; /* next to reclaim */
atomic_t refcount;
struct ehci_hcd *ehci;
struct kref kref;
unsigned stamp;
u8 qh_state;
......@@ -592,6 +596,14 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
/*-------------------------------------------------------------------------*/
#define MSEC_TO_JIFFIES(msec) ((HZ * (msec) + 999) / 1000)
static inline void msec_delay(int msec)
{
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(MSEC_TO_JIFFIES(msec));
}
#ifndef DEBUG
#define STUB_DEBUG_FILES
#endif /* DEBUG */
......
......@@ -617,7 +617,17 @@ show_registers (struct class_device *class_dev, char *buf)
/* dump driver info, then registers in spec order */
ohci_dbg_sw (ohci, &next, &size,
"%s version " DRIVER_VERSION "\n", hcd_name);
"bus %s, device %s\n"
"%s version " DRIVER_VERSION "\n",
hcd->self.controller->bus->name,
hcd->self.controller->bus_id,
hcd_name);
if (bus->controller->power.power_state) {
size -= scnprintf (next, size,
"SUSPENDED (no register access)\n");
goto done;
}
ohci_dump_status(ohci, &next, &size);
......@@ -657,8 +667,8 @@ show_registers (struct class_device *class_dev, char *buf)
/* roothub */
ohci_dump_roothub (ohci, 1, &next, &size);
done:
spin_unlock_irqrestore (&ohci->lock, flags);
return PAGE_SIZE - size;
}
static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
......
......@@ -117,8 +117,8 @@
/* For initializing controller (mask in an HCFS mode too) */
#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
#define OHCI_UNLINK_TIMEOUT (HZ / 10)
#define OHCI_INTR_INIT \
(OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_WDH)
/*-------------------------------------------------------------------------*/
......@@ -126,11 +126,6 @@ static const char hcd_name [] = "ohci_hcd";
#include "ohci.h"
static inline void disable (struct ohci_hcd *ohci)
{
ohci->hcd.state = USB_STATE_HALT;
}
#include "ohci-hub.c"
#include "ohci-dbg.c"
#include "ohci-mem.c"
......@@ -206,8 +201,7 @@ static int ohci_urb_enqueue (
if (!urb_priv)
return -ENOMEM;
memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
/* fill the private part of the URB */
INIT_LIST_HEAD (&urb_priv->pending);
urb_priv->length = size;
urb_priv->ed = ed;
......@@ -397,6 +391,16 @@ static int hc_reset (struct ohci_hcd *ohci)
{
u32 temp;
/* boot firmware should have set this up (5.1.1.3.1) */
if (!ohci->fminterval) {
temp = readl (&ohci->regs->fminterval);
if (temp & 0x3fff0000)
ohci->fminterval = temp;
else
ohci->fminterval = DEFAULT_FMINTERVAL;
/* also: power/overcurrent flags in roothub.a */
}
/* SMM owns the HC? not for long!
* On PA-RISC, PDC can leave IR set incorrectly; ignore it there.
*/
......@@ -413,7 +417,7 @@ static int hc_reset (struct ohci_hcd *ohci)
writel (OHCI_INTR_OC, &ohci->regs->intrenable);
writel (OHCI_OCR, &ohci->regs->cmdstatus);
while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
wait_ms (10);
msec_delay (10);
if (--temp == 0) {
ohci_err (ohci, "USB HC TakeOver failed!\n");
return -1;
......@@ -430,9 +434,12 @@ static int hc_reset (struct ohci_hcd *ohci)
/* Reset USB (needed by some controllers); RemoteWakeupConnected
* saved if boot firmware (BIOS/SMM/...) told us it's connected
* (for OHCI integrated on mainboard, it normally is)
*/
ohci->hc_control = readl (&ohci->regs->control);
ohci->hc_control &= OHCI_CTRL_RWC; /* hcfs 0 = RESET */
if (ohci->hc_control)
ohci->hcd.can_wakeup = 1;
writel (ohci->hc_control, &ohci->regs->control);
if (power_switching) {
unsigned ports = roothub_a (ohci) & RH_A_NDP;
......@@ -444,7 +451,7 @@ static int hc_reset (struct ohci_hcd *ohci)
}
// flush those pci writes
(void) readl (&ohci->regs->control);
wait_ms (50);
msec_delay (50);
/* HC Reset requires max 10 us delay */
writel (OHCI_HCR, &ohci->regs->cmdstatus);
......@@ -473,9 +480,6 @@ static int hc_reset (struct ohci_hcd *ohci)
/*-------------------------------------------------------------------------*/
#define FI 0x2edf /* 12000 bits per frame (-1) */
#define LSTHRESH 0x628 /* lowspeed bit threshold */
/* Start an OHCI controller, set the BUS operational
* enable interrupts
* connect the virtual root hub
......@@ -486,7 +490,6 @@ static int hc_start (struct ohci_hcd *ohci)
struct usb_device *udev;
struct usb_bus *bus;
spin_lock_init (&ohci->lock);
disable (ohci);
/* Tell the controller where the control and bulk lists are
......@@ -497,12 +500,7 @@ static int hc_start (struct ohci_hcd *ohci)
/* a reset clears this */
writel ((u32) ohci->hcca_dma, &ohci->regs->hcca);
/* force default fmInterval (we won't adjust it); init thresholds
* for last FS and LS packets, reserve 90% for periodic.
*/
writel ((((6 * (FI - 210)) / 7) << 16) | FI, &ohci->regs->fminterval);
writel (((9 * FI) / 10) & 0x3fff, &ohci->regs->periodicstart);
writel (LSTHRESH, &ohci->regs->lsthresh);
periodic_reinit (ohci);
/* some OHCI implementations are finicky about how they init.
* bogus values here mean not even enumeration could work.
......@@ -519,8 +517,11 @@ static int hc_start (struct ohci_hcd *ohci)
writel (ohci->hc_control, &ohci->regs->control);
ohci->hcd.state = USB_STATE_RUNNING;
/* wake on ConnectStatusChange, matching external hubs */
writel (RH_HS_DRWE, &ohci->regs->roothub.status);
/* Choose the interrupts we care about now, others later on demand */
mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH;
mask = OHCI_INTR_INIT;
writel (mask, &ohci->regs->intrstatus);
writel (mask, &ohci->regs->intrenable);
......@@ -551,9 +552,14 @@ static int hc_start (struct ohci_hcd *ohci)
// POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
bus = hcd_to_bus (&ohci->hcd);
if (bus->root_hub) {
ohci->hcd.state = USB_STATE_RUNNING;
return 0;
}
/* connect the virtual root hub */
bus = hcd_to_bus (&ohci->hcd);
bus->root_hub = udev = usb_alloc_dev (NULL, bus, 0);
ohci->hcd.state = USB_STATE_RUNNING;
if (!udev) {
......@@ -610,11 +616,18 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
ohci_dump (ohci, 1);
hc_reset (ohci);
}
if (ints & OHCI_INTR_RD) {
ohci_vdbg (ohci, "resume detect\n");
schedule_work(&ohci->rh_resume);
}
if (ints & OHCI_INTR_WDH) {
if (HCD_IS_RUNNING(hcd->state))
writel (OHCI_INTR_WDH, &regs->intrdisable);
dl_done_list (ohci, dl_reverse_done_list (ohci), ptregs);
spin_lock (&ohci->lock);
dl_done_list (ohci, ptregs);
spin_unlock (&ohci->lock);
if (HCD_IS_RUNNING(hcd->state))
writel (OHCI_INTR_WDH, &regs->intrenable);
}
......@@ -654,6 +667,7 @@ static void ohci_stop (struct usb_hcd *hcd)
ohci->hcd.state);
ohci_dump (ohci, 1);
flush_scheduled_work();
if (HCD_IS_RUNNING(ohci->hcd.state))
hc_reset (ohci);
......@@ -670,22 +684,68 @@ static void ohci_stop (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
// FIXME: this restart logic should be generic,
// and handle full hcd state cleanup
/* controller died; cleanup debris, then restart */
/* must not be called from interrupt context */
#ifdef CONFIG_PM
static void mark_children_gone (struct usb_device *dev)
{
unsigned i;
for (i = 0; i < dev->maxchild; i++) {
if (dev->children [i] == 0)
continue;
dev->children [i]->state = USB_STATE_NOTATTACHED;
mark_children_gone (dev->children [i]);
}
}
static int hc_restart (struct ohci_hcd *ohci)
{
int temp;
int i;
struct urb_priv *priv;
/* mark any devices gone, so they do nothing till khubd disconnects.
* recycle any "live" eds/tds (and urbs) right away.
* later, khubd disconnect processing will recycle the other state,
* (either as disconnect/reconnect, or maybe someday as a reset).
*/
spin_lock_irq(&ohci->lock);
disable (ohci);
if (hcd_to_bus (&ohci->hcd)->root_hub)
usb_disconnect (&hcd_to_bus (&ohci->hcd)->root_hub);
mark_children_gone (ohci->hcd.self.root_hub);
if (!list_empty (&ohci->pending))
ohci_dbg(ohci, "abort schedule...\n");
list_for_each_entry (priv, &ohci->pending, pending) {
struct urb *urb = priv->td[0]->urb;
struct ed *ed = priv->ed;
switch (ed->state) {
case ED_OPER:
ed->state = ED_UNLINK;
ed->hwINFO |= ED_DEQUEUE;
ed_deschedule (ohci, ed);
ed->ed_next = ohci->ed_rm_list;
ed->ed_prev = 0;
ohci->ed_rm_list = ed;
/* FALLTHROUGH */
case ED_UNLINK:
break;
default:
ohci_dbg(ohci, "bogus ed %p state %d\n",
ed, ed->state);
}
spin_lock (&urb->lock);
urb->status = -ESHUTDOWN;
spin_unlock (&urb->lock);
}
finish_unlinks (ohci, 0, 0);
spin_unlock_irq(&ohci->lock);
/* paranoia, in case that didn't work: */
/* empty the interrupt branches */
for (i = 0; i < NUM_INTS; i++) ohci->load [i] = 0;
for (i = 0; i < NUM_INTS; i++) ohci->hcca->int_table [i] = 0;
......@@ -700,8 +760,20 @@ static int hc_restart (struct ohci_hcd *ohci)
if ((temp = hc_reset (ohci)) < 0 || (temp = hc_start (ohci)) < 0) {
ohci_err (ohci, "can't restart, %d\n", temp);
return temp;
} else
} else {
/* here we "know" root ports should always stay powered,
* and that if we try to turn them back on the root hub
* will respond to CSC processing.
*/
i = roothub_a (ohci) & RH_A_NDP;
while (i--)
writel (RH_PS_PSS,
&ohci->regs->roothub.portstatus [temp]);
ohci->hcd.self.root_hub->dev.power.power_state = 0;
ohci->hcd.state = USB_STATE_RUNNING;
ohci_dbg (ohci, "restart complete\n");
ohci_dump (ohci, 1);
}
return 0;
}
#endif
......
......@@ -60,6 +60,261 @@ static u32 roothub_portstatus (struct ohci_hcd *hc, int i)
(temp & RH_PS_CCS) ? " CCS" : "" \
);
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
#define OHCI_SCHED_ENABLES \
(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
static void dl_done_list (struct ohci_hcd *, struct pt_regs *);
static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *);
static int ohci_hub_suspend (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct usb_device *root = hcd_to_bus (&ohci->hcd)->root_hub;
int status = 0;
if (root->dev.power.power_state != 0)
return 0;
if (time_before (jiffies, ohci->next_statechange))
return -EAGAIN;
spin_lock_irq (&ohci->lock);
ohci->hc_control = readl (&ohci->regs->control);
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
case OHCI_USB_RESUME:
ohci_dbg (ohci, "resume/suspend?\n");
ohci->hc_control &= ~OHCI_CTRL_HCFS;
ohci->hc_control |= OHCI_USB_RESET;
writel (ohci->hc_control, &ohci->regs->control);
(void) readl (&ohci->regs->control);
/* FALL THROUGH */
case OHCI_USB_RESET:
status = -EBUSY;
ohci_dbg (ohci, "needs reinit!\n");
goto done;
case OHCI_USB_SUSPEND:
ohci_dbg (ohci, "already suspended?\n");
goto succeed;
}
ohci_dbg (ohci, "suspend root hub\n");
/* First stop any processing */
ohci->hcd.state = USB_STATE_QUIESCING;
if (ohci->hc_control & OHCI_SCHED_ENABLES) {
int limit;
ohci->hc_control &= ~OHCI_SCHED_ENABLES;
writel (ohci->hc_control, &ohci->regs->control);
ohci->hc_control = readl (&ohci->regs->control);
writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
/* sched disables take effect on the next frame,
* then the last WDH could take 6+ msec
*/
ohci_dbg (ohci, "stopping schedules ...\n");
limit = 2000;
while (limit > 0) {
udelay (250);
limit =- 250;
if (readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
break;
}
dl_done_list (ohci, 0);
mdelay (7);
}
dl_done_list (ohci, 0);
finish_unlinks (ohci, OHCI_FRAME_NO(ohci->hcca), 0);
writel (readl (&ohci->regs->intrstatus), &ohci->regs->intrstatus);
/* maybe resume can wake root hub */
if (ohci->hcd.remote_wakeup)
ohci->hc_control |= OHCI_CTRL_RWE;
else
ohci->hc_control &= ~OHCI_CTRL_RWE;
/* Suspend hub */
ohci->hc_control &= ~OHCI_CTRL_HCFS;
ohci->hc_control |= OHCI_USB_SUSPEND;
writel (ohci->hc_control, &ohci->regs->control);
(void) readl (&ohci->regs->control);
/* no resumes until devices finish suspending */
ohci->next_statechange = jiffies + MSEC_TO_JIFFIES (5);
succeed:
/* it's not USB_STATE_SUSPENDED unless access to this
* hub from the non-usb side (PCI, SOC, etc) stopped
*/
root->dev.power.power_state = 3;
done:
spin_unlock_irq (&ohci->lock);
return status;
}
static inline struct ed *find_head (struct ed *ed)
{
/* for bulk and control lists */
while (ed->ed_prev)
ed = ed->ed_prev;
return ed;
}
static int hc_restart (struct ohci_hcd *ohci);
/* caller owns root->serialize */
static int ohci_hub_resume (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct usb_device *root = hcd_to_bus (&ohci->hcd)->root_hub;
u32 temp, enables;
int status = -EINPROGRESS;
if (!root->dev.power.power_state)
return 0;
if (time_before (jiffies, ohci->next_statechange))
return -EAGAIN;
spin_lock_irq (&ohci->lock);
ohci->hc_control = readl (&ohci->regs->control);
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
case OHCI_USB_SUSPEND:
ohci->hc_control &= ~(OHCI_CTRL_HCFS|OHCI_SCHED_ENABLES);
ohci->hc_control |= OHCI_USB_RESUME;
writel (ohci->hc_control, &ohci->regs->control);
(void) readl (&ohci->regs->control);
ohci_dbg (ohci, "resume root hub\n");
break;
case OHCI_USB_RESUME:
/* HCFS changes sometime after INTR_RD */
ohci_info (ohci, "remote wakeup\n");
break;
case OHCI_USB_OPER:
ohci_dbg (ohci, "odd resume\n");
root->dev.power.power_state = 0;
status = 0;
break;
default: /* RESET, we lost power */
ohci_dbg (ohci, "root hub hardware reset\n");
status = -EBUSY;
}
spin_unlock_irq (&ohci->lock);
if (status == -EBUSY)
return hc_restart (ohci);
if (status != -EINPROGRESS)
return status;
temp = roothub_a (ohci) & RH_A_NDP;
enables = 0;
while (temp--) {
u32 stat = readl (&ohci->regs->roothub.portstatus [temp]);
/* force global, not selective, resume */
if (!(stat & RH_PS_PSS))
continue;
writel (RH_PS_POCI, &ohci->regs->roothub.portstatus [temp]);
}
/* Some controllers (lucent) need extra-long delays */
ohci->hcd.state = USB_STATE_RESUMING;
mdelay (20 /* usb 11.5.1.10 */ + 15);
temp = readl (&ohci->regs->control);
temp &= OHCI_CTRL_HCFS;
if (temp != OHCI_USB_RESUME) {
ohci_err (ohci, "controller won't resume\n");
return -EBUSY;
}
/* disable old schedule state, reinit from scratch */
writel (0, &ohci->regs->ed_controlhead);
writel (0, &ohci->regs->ed_controlcurrent);
writel (0, &ohci->regs->ed_bulkhead);
writel (0, &ohci->regs->ed_bulkcurrent);
writel (0, &ohci->regs->ed_periodcurrent);
writel ((u32) ohci->hcca_dma, &ohci->regs->hcca);
periodic_reinit (ohci);
/* interrupts might have been disabled */
writel (OHCI_INTR_INIT, &ohci->regs->intrenable);
if (ohci->ed_rm_list)
writel (OHCI_INTR_SF, &ohci->regs->intrenable);
writel (readl (&ohci->regs->intrstatus), &ohci->regs->intrstatus);
/* Then re-enable operations */
writel (OHCI_USB_OPER, &ohci->regs->control);
(void) readl (&ohci->regs->control);
msec_delay (3);
temp = OHCI_CONTROL_INIT | OHCI_USB_OPER;
if (ohci->hcd.can_wakeup)
temp |= OHCI_CTRL_RWC;
ohci->hc_control = temp;
writel (temp, &ohci->regs->control);
(void) readl (&ohci->regs->control);
/* TRSMRCY */
msec_delay (10);
root->dev.power.power_state = 0;
/* keep it alive for ~5x suspend + resume costs */
ohci->next_statechange = jiffies + MSEC_TO_JIFFIES (250);
/* maybe turn schedules back on */
enables = 0;
temp = 0;
if (!ohci->ed_rm_list) {
if (ohci->ed_controltail) {
writel (find_head (ohci->ed_controltail)->dma,
&ohci->regs->ed_controlhead);
enables |= OHCI_CTRL_CLE;
temp |= OHCI_CLF;
}
if (ohci->ed_bulktail) {
writel (find_head (ohci->ed_bulktail)->dma,
&ohci->regs->ed_bulkhead);
enables |= OHCI_CTRL_BLE;
temp |= OHCI_BLF;
}
}
if (hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs
|| hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs)
enables |= OHCI_CTRL_PLE|OHCI_CTRL_IE;
if (enables) {
ohci_dbg (ohci, "restarting schedules ... %08x\n", enables);
ohci->hc_control |= enables;
writel (ohci->hc_control, &ohci->regs->control);
if (temp)
writel (status, &ohci->regs->cmdstatus);
(void) readl (&ohci->regs->control);
}
ohci->hcd.state = USB_STATE_RUNNING;
return 0;
}
static void ohci_rh_resume (void *_hcd)
{
struct usb_hcd *hcd = _hcd;
down (&hcd->self.root_hub->serialize);
(void) ohci_hub_resume (hcd);
up (&hcd->self.root_hub->serialize);
}
#else
static void ohci_rh_resume (void *_hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci_dbg(ohci, "rh_resume ??\n");
}
#endif /* CONFIG_USB_SUSPEND || CONFIG_PM */
/*-------------------------------------------------------------------------*/
......@@ -70,6 +325,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ports, i, changed = 0, length = 1;
int can_suspend = 1;
ports = roothub_a (ohci) & RH_A_NDP;
if (ports > MAX_ROOT_PORTS) {
......@@ -95,16 +351,44 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
for (i = 0; i < ports; i++) {
u32 status = roothub_portstatus (ohci, i);
status &= RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
| RH_PS_OCIC | RH_PS_PRSC;
if (status) {
if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
| RH_PS_OCIC | RH_PS_PRSC)) {
changed = 1;
if (i < 7)
buf [0] |= 1 << (i + 1);
else
buf [1] |= 1 << (i - 7);
continue;
}
/* can suspend if no ports are enabled; or if all all
* enabled ports are suspended AND remote wakeup is on.
*/
if (!(status & RH_PS_CCS))
continue;
if ((status & RH_PS_PSS) && ohci->hcd.remote_wakeup)
continue;
can_suspend = 0;
}
#ifdef CONFIG_PM
/* save power by suspending idle root hubs;
* INTR_RD wakes us when there's work
*/
if (can_suspend
&& !changed
&& !ohci->ed_rm_list
&& ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES)
& ohci->hc_control)
== OHCI_USB_OPER
&& down_trylock (&hcd->self.root_hub->serialize) == 0
) {
ohci_vdbg (ohci, "autosuspend\n");
(void) ohci_hub_suspend (&ohci->hcd);
up (&hcd->self.root_hub->serialize);
}
#endif
return changed ? length : 0;
}
......@@ -188,6 +472,9 @@ static int ohci_hub_control (
break;
case USB_PORT_FEAT_SUSPEND:
temp = RH_PS_POCI;
if ((ohci->hc_control & OHCI_CTRL_HCFS)
!= OHCI_USB_OPER)
schedule_work (&ohci->rh_resume);
break;
case USB_PORT_FEAT_C_SUSPEND:
temp = RH_PS_PSSC;
......
......@@ -31,6 +31,9 @@ static struct usb_hcd *ohci_hcd_alloc (void)
if (ohci != 0) {
memset (ohci, 0, sizeof (struct ohci_hcd));
ohci->hcd.product_desc = "OHCI Host Controller";
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
INIT_WORK (&ohci->rh_resume, ohci_rh_resume, &ohci->hcd);
return &ohci->hcd;
}
return 0;
......
......@@ -36,6 +36,7 @@ ohci_pci_reset (struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
ohci->regs = hcd->regs;
ohci->next_statechange = jiffies;
return hc_reset (ohci);
}
......@@ -118,74 +119,25 @@ ohci_pci_start (struct usb_hcd *hcd)
static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
u16 cmd;
u32 tmp;
if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
ohci_dbg (ohci, "can't suspend (state is %s)\n",
hcfs2string (ohci->hc_control & OHCI_CTRL_HCFS));
return -EIO;
}
/* suspend root hub, hoping it keeps power during suspend */
while (time_before (jiffies, ohci->next_statechange))
msec_delay (100);
#ifdef CONFIG_USB_SUSPEND
(void) usb_suspend_device (hcd->self.root_hub);
#else
/* FIXME lock root hub */
(void) ohci_hub_suspend (hcd);
#endif
/* act as if usb suspend can always be used */
ohci_dbg (ohci, "suspend to %d\n", state);
/* let things settle down a bit */
msec_delay (100);
/* First stop processing */
spin_lock_irq (&ohci->lock);
ohci->hc_control &=
~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
writel (ohci->hc_control, &ohci->regs->control);
writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
(void) readl (&ohci->regs->intrstatus);
spin_unlock_irq (&ohci->lock);
/* Wait a frame or two */
mdelay (1);
if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
mdelay (1);
#ifdef CONFIG_PMAC_PBOOK
if (_machine == _MACH_Pmac)
disable_irq ((to_pci_dev(hcd->self.controller))->irq);
/* else, 2.4 assumes shared irqs -- don't disable */
#endif
/* Enable remote wakeup */
writel (readl (&ohci->regs->intrenable) | OHCI_INTR_RD,
&ohci->regs->intrenable);
/* Suspend chip and let things settle down a bit */
spin_lock_irq (&ohci->lock);
ohci->hc_control = OHCI_USB_SUSPEND;
writel (ohci->hc_control, &ohci->regs->control);
(void) readl (&ohci->regs->control);
spin_unlock_irq (&ohci->lock);
set_current_state (TASK_UNINTERRUPTIBLE);
schedule_timeout (HZ/2);
tmp = readl (&ohci->regs->control) | OHCI_CTRL_HCFS;
switch (tmp) {
case OHCI_USB_RESET:
case OHCI_USB_RESUME:
case OHCI_USB_OPER:
ohci_err (ohci, "can't suspend; hcfs %d\n", tmp);
break;
case OHCI_USB_SUSPEND:
ohci_dbg (ohci, "suspended\n");
break;
}
/* In some rare situations, Apple's OHCI have happily trashed
* memory during sleep. We disable its bus master bit during
* suspend
*/
pci_read_config_word (to_pci_dev(hcd->self.controller), PCI_COMMAND,
&cmd);
cmd &= ~PCI_COMMAND_MASTER;
pci_write_config_word (to_pci_dev(hcd->self.controller), PCI_COMMAND,
cmd);
#ifdef CONFIG_PMAC_PBOOK
{
struct device_node *of_node;
......@@ -202,7 +154,6 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
static int ohci_pci_resume (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int temp;
int retval = 0;
#ifdef CONFIG_PMAC_PBOOK
......@@ -215,90 +166,25 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
}
#endif
/* did we suspend, or were we powered off? */
ohci->hc_control = readl (&ohci->regs->control);
temp = ohci->hc_control & OHCI_CTRL_HCFS;
#ifdef DEBUG
/* the registers may look crazy here */
ohci_dump_status (ohci, 0, 0);
/* resume root hub */
while (time_before (jiffies, ohci->next_statechange))
msec_delay (100);
#ifdef CONFIG_USB_SUSPEND
/* get extra cleanup even if remote wakeup isn't in use */
retval = usb_resume_device (hcd->self.root_hub);
#else
down (&hcd->self.root_hub->serialize);
retval = ohci_hub_resume (hcd);
up (&hcd->self.root_hub->serialize);
#endif
/* Re-enable bus mastering */
pci_set_master (to_pci_dev(ohci->hcd.self.controller));
switch (temp) {
case OHCI_USB_RESET: // lost power
restart:
ohci_info (ohci, "USB restart\n");
retval = hc_restart (ohci);
break;
case OHCI_USB_SUSPEND: // host wakeup
case OHCI_USB_RESUME: // remote wakeup
ohci_info (ohci, "USB continue from %s wakeup\n",
(temp == OHCI_USB_SUSPEND)
? "host" : "remote");
/* we "should" only need RESUME if we're SUSPENDed ... */
ohci->hc_control = OHCI_USB_RESUME;
writel (ohci->hc_control, &ohci->regs->control);
(void) readl (&ohci->regs->control);
/* Some controllers (lucent) need extra-long delays */
mdelay (35); /* no schedule here ! */
temp = readl (&ohci->regs->control);
temp = ohci->hc_control & OHCI_CTRL_HCFS;
if (temp != OHCI_USB_RESUME) {
ohci_err (ohci, "controller won't resume\n");
/* maybe we can reset */
goto restart;
}
/* Then re-enable operations */
writel (OHCI_USB_OPER, &ohci->regs->control);
(void) readl (&ohci->regs->control);
mdelay (3);
spin_lock_irq (&ohci->lock);
ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
if (!ohci->ed_rm_list) {
if (ohci->ed_controltail)
ohci->hc_control |= OHCI_CTRL_CLE;
if (ohci->ed_bulktail)
ohci->hc_control |= OHCI_CTRL_BLE;
}
if (hcd_to_bus (&ohci->hcd)->bandwidth_isoc_reqs
|| hcd_to_bus (&ohci->hcd)->bandwidth_int_reqs)
ohci->hc_control |= OHCI_CTRL_PLE|OHCI_CTRL_IE;
hcd->state = USB_STATE_RUNNING;
writel (ohci->hc_control, &ohci->regs->control);
/* trigger a start-frame interrupt (why?) */
writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
writel (OHCI_INTR_SF, &ohci->regs->intrenable);
writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);
(void) readl (&ohci->regs->intrdisable);
spin_unlock_irq (&ohci->lock);
if (retval == 0) {
hcd->self.controller->power.power_state = 0;
#ifdef CONFIG_PMAC_PBOOK
if (_machine == _MACH_Pmac)
enable_irq (to_pci_dev(hcd->self.controller)->irq);
#endif
/* Check for a pending done list */
if (ohci->hcca->done_head)
dl_done_list (ohci, dl_reverse_done_list (ohci), NULL);
writel (OHCI_INTR_WDH, &ohci->regs->intrenable);
/* assume there are TDs on the bulk and control lists */
writel (OHCI_BLF | OHCI_CLF, &ohci->regs->cmdstatus);
break;
default:
ohci_warn (ohci, "odd PCI resume\n");
}
return retval;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -80,7 +80,7 @@
#define CAN_SCHEDULE_FRAMES 1000 /* how far future frames can be scheduled */
struct uhci_frame_list {
__u32 frame[UHCI_NUMFRAMES];
u32 frame[UHCI_NUMFRAMES];
void *frame_cpu[UHCI_NUMFRAMES];
......@@ -105,8 +105,8 @@ struct urb_priv;
*/
struct uhci_qh {
/* Hardware fields */
__u32 link; /* Next queue */
__u32 element; /* Queue element pointer */
u32 link; /* Next queue */
u32 element; /* Queue element pointer */
/* Software fields */
dma_addr_t dma_handle;
......@@ -185,10 +185,10 @@ struct uhci_qh {
*/
struct uhci_td {
/* Hardware fields */
__u32 link;
__u32 status;
__u32 token;
__u32 buffer;
u32 link;
u32 status;
u32 token;
u32 buffer;
/* Software fields */
dma_addr_t dma_handle;
......@@ -370,6 +370,8 @@ struct uhci_hcd {
int rh_numports;
struct timer_list stall_timer;
wait_queue_head_t waitqh; /* endpoint_disable waiters */
};
struct urb_priv {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -15,3 +15,4 @@ obj-$(CONFIG_USB_SPEEDTOUCH) += speedtch.o
obj-$(CONFIG_USB_TEST) += usbtest.o
obj-$(CONFIG_USB_TIGL) += tiglusb.o
obj-$(CONFIG_USB_USS720) += uss720.o
obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment