Commit f8e98843 authored by Linus Torvalds's avatar Linus Torvalds

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

parents c801147c 8926bfa7
...@@ -46,8 +46,9 @@ USB-specific: ...@@ -46,8 +46,9 @@ USB-specific:
-EMSGSIZE (a) endpoint maxpacket size is zero; it is not usable -EMSGSIZE (a) endpoint maxpacket size is zero; it is not usable
in the current interface altsetting. in the current interface altsetting.
(b) ISO packet is biger than endpoint maxpacket (b) ISO packet is larger than the endpoint maxpacket.
(c) requested data transfer size is invalid (negative) (c) requested data transfer length is invalid: negative
or too large for the host controller.
-ENOSPC This request would overcommit the usb bandwidth reserved -ENOSPC This request would overcommit the usb bandwidth reserved
for periodic transfers (interrupt, isochronous). for periodic transfers (interrupt, isochronous).
......
...@@ -193,6 +193,7 @@ static const u8 W83792D_REG_LEVELS[3][4] = { ...@@ -193,6 +193,7 @@ static const u8 W83792D_REG_LEVELS[3][4] = {
0xE2 } /* (bit3-0) SmartFanII: Fan3 Level 3 */ 0xE2 } /* (bit3-0) SmartFanII: Fan3 Level 3 */
}; };
#define W83792D_REG_GPIO_EN 0x1A
#define W83792D_REG_CONFIG 0x40 #define W83792D_REG_CONFIG 0x40
#define W83792D_REG_VID_FANDIV 0x47 #define W83792D_REG_VID_FANDIV 0x47
#define W83792D_REG_CHIPID 0x49 #define W83792D_REG_CHIPID 0x49
...@@ -257,7 +258,7 @@ DIV_TO_REG(long val) ...@@ -257,7 +258,7 @@ DIV_TO_REG(long val)
{ {
int i; int i;
val = SENSORS_LIMIT(val, 1, 128) >> 1; val = SENSORS_LIMIT(val, 1, 128) >> 1;
for (i = 0; i < 6; i++) { for (i = 0; i < 7; i++) {
if (val == 0) if (val == 0)
break; break;
val >>= 1; val >>= 1;
...@@ -1282,8 +1283,8 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) ...@@ -1282,8 +1283,8 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
w83792d_init_client(new_client); w83792d_init_client(new_client);
/* A few vars need to be filled upon startup */ /* A few vars need to be filled upon startup */
for (i = 1; i <= 7; i++) { for (i = 0; i < 7; i++) {
data->fan_min[i - 1] = w83792d_read_value(new_client, data->fan_min[i] = w83792d_read_value(new_client,
W83792D_REG_FAN_MIN[i]); W83792D_REG_FAN_MIN[i]);
} }
...@@ -1306,10 +1307,20 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind) ...@@ -1306,10 +1307,20 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
device_create_file_fan(new_client, 1); device_create_file_fan(new_client, 1);
device_create_file_fan(new_client, 2); device_create_file_fan(new_client, 2);
device_create_file_fan(new_client, 3); device_create_file_fan(new_client, 3);
device_create_file_fan(new_client, 4);
device_create_file_fan(new_client, 5); /* Read GPIO enable register to check if pins for fan 4,5 are used as
device_create_file_fan(new_client, 6); GPIO */
device_create_file_fan(new_client, 7); val1 = w83792d_read_value(new_client, W83792D_REG_GPIO_EN);
if (!(val1 & 0x40))
device_create_file_fan(new_client, 4);
if (!(val1 & 0x20))
device_create_file_fan(new_client, 5);
val1 = w83792d_read_value(new_client, W83792D_REG_PIN);
if (val1 & 0x40)
device_create_file_fan(new_client, 6);
if (val1 & 0x04)
device_create_file_fan(new_client, 7);
device_create_file_temp1(new_client); /* Temp1 */ device_create_file_temp1(new_client); /* Temp1 */
device_create_file_temp_add(new_client, 2); /* Temp2 */ device_create_file_temp_add(new_client, 2); /* Temp2 */
......
...@@ -787,6 +787,9 @@ static const struct usb_device_id cxacru_usb_ids[] = { ...@@ -787,6 +787,9 @@ static const struct usb_device_id cxacru_usb_ids[] = {
{ /* V = Conexant P = ADSL modem (Hasbani project) */ { /* V = Conexant P = ADSL modem (Hasbani project) */
USB_DEVICE(0x0572, 0xcb00), .driver_info = (unsigned long) &cxacru_cb00 USB_DEVICE(0x0572, 0xcb00), .driver_info = (unsigned long) &cxacru_cb00
}, },
{ /* V = Conexant P = ADSL modem (Well PTI-800 */
USB_DEVICE(0x0572, 0xcb02), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Conexant P = ADSL modem */ { /* V = Conexant P = ADSL modem */
USB_DEVICE(0x0572, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00 USB_DEVICE(0x0572, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00
}, },
......
...@@ -219,6 +219,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message) ...@@ -219,6 +219,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
goto done; goto done;
} }
} }
synchronize_irq(dev->irq);
/* FIXME until the generic PM interfaces change a lot more, this /* FIXME until the generic PM interfaces change a lot more, this
* can't use PCI D1 and D2 states. For example, the confusion * can't use PCI D1 and D2 states. For example, the confusion
...@@ -392,7 +393,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev) ...@@ -392,7 +393,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
dev->dev.power.power_state = PMSG_ON; dev->dev.power.power_state = PMSG_ON;
hcd->saw_irq = 0; clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
if (hcd->driver->resume) { if (hcd->driver->resume) {
retval = hcd->driver->resume(hcd); retval = hcd->driver->resume(hcd);
......
...@@ -1315,11 +1315,12 @@ static int hcd_unlink_urb (struct urb *urb, int status) ...@@ -1315,11 +1315,12 @@ static int hcd_unlink_urb (struct urb *urb, int status)
* finish unlinking the initial failed usb_set_address() * finish unlinking the initial failed usb_set_address()
* or device descriptor fetch. * or device descriptor fetch.
*/ */
if (!hcd->saw_irq && hcd->self.root_hub != urb->dev) { if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags)
&& hcd->self.root_hub != urb->dev) {
dev_warn (hcd->self.controller, "Unlink after no-IRQ? " dev_warn (hcd->self.controller, "Unlink after no-IRQ? "
"Controller is probably using the wrong IRQ." "Controller is probably using the wrong IRQ."
"\n"); "\n");
hcd->saw_irq = 1; set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
} }
urb->status = status; urb->status = status;
...@@ -1649,13 +1650,15 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r) ...@@ -1649,13 +1650,15 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
struct usb_hcd *hcd = __hcd; struct usb_hcd *hcd = __hcd;
int start = hcd->state; int start = hcd->state;
if (start == HC_STATE_HALT) if (unlikely(start == HC_STATE_HALT ||
!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
return IRQ_NONE; return IRQ_NONE;
if (hcd->driver->irq (hcd, r) == IRQ_NONE) if (hcd->driver->irq (hcd, r) == IRQ_NONE)
return IRQ_NONE; return IRQ_NONE;
hcd->saw_irq = 1; set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
if (hcd->state == HC_STATE_HALT)
if (unlikely(hcd->state == HC_STATE_HALT))
usb_hc_died (hcd); usb_hc_died (hcd);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -1768,6 +1771,8 @@ int usb_add_hcd(struct usb_hcd *hcd, ...@@ -1768,6 +1771,8 @@ int usb_add_hcd(struct usb_hcd *hcd,
dev_info(hcd->self.controller, "%s\n", hcd->product_desc); dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
/* till now HC has been in an indeterminate state ... */ /* till now HC has been in an indeterminate state ... */
if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) { if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
dev_err(hcd->self.controller, "can't reset\n"); dev_err(hcd->self.controller, "can't reset\n");
......
...@@ -72,7 +72,12 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */ ...@@ -72,7 +72,12 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
* hardware info/state * hardware info/state
*/ */
const struct hc_driver *driver; /* hw-specific hooks */ const struct hc_driver *driver; /* hw-specific hooks */
unsigned saw_irq : 1;
/* Flags that need to be manipulated atomically */
unsigned long flags;
#define HCD_FLAG_HW_ACCESSIBLE 0x00000001
#define HCD_FLAG_SAW_IRQ 0x00000002
unsigned can_wakeup:1; /* hw supports wakeup? */ unsigned can_wakeup:1; /* hw supports wakeup? */
unsigned remote_wakeup:1;/* sw should use wakeup? */ unsigned remote_wakeup:1;/* sw should use wakeup? */
unsigned rh_registered:1;/* is root hub registered? */ unsigned rh_registered:1;/* is root hub registered? */
......
...@@ -121,8 +121,8 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev) ...@@ -121,8 +121,8 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
return 0; return 0;
} }
/* called by khubd or root hub (re)init threads; leaves HC in halt state */ /* called during probe() after chip reset completes */
static int ehci_pci_reset(struct usb_hcd *hcd) static int ehci_pci_setup(struct usb_hcd *hcd)
{ {
struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller); struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
...@@ -141,6 +141,11 @@ static int ehci_pci_reset(struct usb_hcd *hcd) ...@@ -141,6 +141,11 @@ static int ehci_pci_reset(struct usb_hcd *hcd)
if (retval) if (retval)
return retval; return retval;
/* data structure init */
retval = ehci_init(hcd);
if (retval)
return retval;
/* NOTE: only the parts below this line are PCI-specific */ /* NOTE: only the parts below this line are PCI-specific */
switch (pdev->vendor) { switch (pdev->vendor) {
...@@ -154,7 +159,8 @@ static int ehci_pci_reset(struct usb_hcd *hcd) ...@@ -154,7 +159,8 @@ static int ehci_pci_reset(struct usb_hcd *hcd)
/* AMD8111 EHCI doesn't work, according to AMD errata */ /* AMD8111 EHCI doesn't work, according to AMD errata */
if (pdev->device == 0x7463) { if (pdev->device == 0x7463) {
ehci_info(ehci, "ignoring AMD8111 (errata)\n"); ehci_info(ehci, "ignoring AMD8111 (errata)\n");
return -EIO; retval = -EIO;
goto done;
} }
break; break;
case PCI_VENDOR_ID_NVIDIA: case PCI_VENDOR_ID_NVIDIA:
...@@ -207,9 +213,8 @@ static int ehci_pci_reset(struct usb_hcd *hcd) ...@@ -207,9 +213,8 @@ static int ehci_pci_reset(struct usb_hcd *hcd)
/* REVISIT: per-port wake capability (PCI 0x62) currently unused */ /* REVISIT: per-port wake capability (PCI 0x62) currently unused */
retval = ehci_pci_reinit(ehci, pdev); retval = ehci_pci_reinit(ehci, pdev);
done:
/* finish init */ return retval;
return ehci_init(hcd);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
...@@ -228,14 +233,36 @@ static int ehci_pci_reset(struct usb_hcd *hcd) ...@@ -228,14 +233,36 @@ static int ehci_pci_reset(struct usb_hcd *hcd)
static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
{ {
struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_hcd *ehci = hcd_to_ehci(hcd);
unsigned long flags;
int rc = 0;
if (time_before(jiffies, ehci->next_statechange)) if (time_before(jiffies, ehci->next_statechange))
msleep(10); msleep(10);
/* Root hub was already suspended. Disable irq emission and
* mark HW unaccessible, bail out if RH has been resumed. Use
* the spinlock to properly synchronize with possible pending
* RH suspend or resume activity.
*
* This is still racy as hcd->state is manipulated outside of
* any locks =P But that will be a different fix.
*/
spin_lock_irqsave (&ehci->lock, flags);
if (hcd->state != HC_STATE_SUSPENDED) {
rc = -EINVAL;
goto bail;
}
writel (0, &ehci->regs->intr_enable);
(void)readl(&ehci->regs->intr_enable);
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
bail:
spin_unlock_irqrestore (&ehci->lock, flags);
// could save FLADJ in case of Vaux power loss // could save FLADJ in case of Vaux power loss
// ... we'd only use it to handle clock skew // ... we'd only use it to handle clock skew
return 0; return rc;
} }
static int ehci_pci_resume(struct usb_hcd *hcd) static int ehci_pci_resume(struct usb_hcd *hcd)
...@@ -251,6 +278,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd) ...@@ -251,6 +278,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
if (time_before(jiffies, ehci->next_statechange)) if (time_before(jiffies, ehci->next_statechange))
msleep(100); msleep(100);
/* Mark hardware accessible again as we are out of D3 state by now */
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
/* If CF is clear, we lost PCI Vaux power and need to restart. */ /* If CF is clear, we lost PCI Vaux power and need to restart. */
if (readl(&ehci->regs->configured_flag) != FLAG_CF) if (readl(&ehci->regs->configured_flag) != FLAG_CF)
goto restart; goto restart;
...@@ -319,7 +349,7 @@ static const struct hc_driver ehci_pci_hc_driver = { ...@@ -319,7 +349,7 @@ static const struct hc_driver ehci_pci_hc_driver = {
/* /*
* basic lifecycle operations * basic lifecycle operations
*/ */
.reset = ehci_pci_reset, .reset = ehci_pci_setup,
.start = ehci_run, .start = ehci_run,
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = ehci_pci_suspend, .suspend = ehci_pci_suspend,
......
...@@ -912,6 +912,7 @@ submit_async ( ...@@ -912,6 +912,7 @@ submit_async (
int epnum; int epnum;
unsigned long flags; unsigned long flags;
struct ehci_qh *qh = NULL; struct ehci_qh *qh = NULL;
int rc = 0;
qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list); qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
epnum = ep->desc.bEndpointAddress; epnum = ep->desc.bEndpointAddress;
...@@ -926,21 +927,28 @@ submit_async ( ...@@ -926,21 +927,28 @@ submit_async (
#endif #endif
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags))) {
rc = -ESHUTDOWN;
goto done;
}
qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv); qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
if (unlikely(qh == NULL)) {
rc = -ENOMEM;
goto done;
}
/* Control/bulk operations through TTs don't need scheduling, /* Control/bulk operations through TTs don't need scheduling,
* the HC and TT handle it when the TT has a buffer ready. * the HC and TT handle it when the TT has a buffer ready.
*/ */
if (likely (qh != NULL)) { if (likely (qh->qh_state == QH_STATE_IDLE))
if (likely (qh->qh_state == QH_STATE_IDLE)) qh_link_async (ehci, qh_get (qh));
qh_link_async (ehci, qh_get (qh)); done:
}
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
if (unlikely (qh == NULL)) { if (unlikely (qh == NULL))
qtd_list_free (ehci, urb, qtd_list); qtd_list_free (ehci, urb, qtd_list);
return -ENOMEM; return rc;
}
return 0;
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -602,6 +602,12 @@ static int intr_submit ( ...@@ -602,6 +602,12 @@ static int intr_submit (
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags))) {
status = -ESHUTDOWN;
goto done;
}
/* get qh and force any scheduling errors */ /* get qh and force any scheduling errors */
INIT_LIST_HEAD (&empty); INIT_LIST_HEAD (&empty);
qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv); qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
...@@ -1456,7 +1462,11 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, ...@@ -1456,7 +1462,11 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */ /* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
status = iso_stream_schedule (ehci, urb, stream); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags)))
status = -ESHUTDOWN;
else
status = iso_stream_schedule (ehci, urb, stream);
if (likely (status == 0)) if (likely (status == 0))
itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
...@@ -1815,7 +1825,11 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, ...@@ -1815,7 +1825,11 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
/* schedule ... need to lock */ /* schedule ... need to lock */
spin_lock_irqsave (&ehci->lock, flags); spin_lock_irqsave (&ehci->lock, flags);
status = iso_stream_schedule (ehci, urb, stream); if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
&ehci_to_hcd(ehci)->flags)))
status = -ESHUTDOWN;
else
status = iso_stream_schedule (ehci, urb, stream);
if (status == 0) if (status == 0)
sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream); sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
spin_unlock_irqrestore (&ehci->lock, flags); spin_unlock_irqrestore (&ehci->lock, flags);
......
...@@ -115,7 +115,7 @@ ...@@ -115,7 +115,7 @@
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
// #define OHCI_VERBOSE_DEBUG /* not always helpful */ #undef OHCI_VERBOSE_DEBUG /* not always helpful */
/* For initializing controller (mask in an HCFS mode too) */ /* For initializing controller (mask in an HCFS mode too) */
#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR #define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
...@@ -253,6 +253,10 @@ static int ohci_urb_enqueue ( ...@@ -253,6 +253,10 @@ static int ohci_urb_enqueue (
spin_lock_irqsave (&ohci->lock, flags); spin_lock_irqsave (&ohci->lock, flags);
/* don't submit to a dead HC */ /* don't submit to a dead HC */
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
retval = -ENODEV;
goto fail;
}
if (!HC_IS_RUNNING(hcd->state)) { if (!HC_IS_RUNNING(hcd->state)) {
retval = -ENODEV; retval = -ENODEV;
goto fail; goto fail;
......
...@@ -53,6 +53,11 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) ...@@ -53,6 +53,11 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
spin_lock_irqsave (&ohci->lock, flags); spin_lock_irqsave (&ohci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
spin_unlock_irqrestore (&ohci->lock, flags);
return -ESHUTDOWN;
}
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
switch (ohci->hc_control & OHCI_CTRL_HCFS) { switch (ohci->hc_control & OHCI_CTRL_HCFS) {
case OHCI_USB_RESUME: case OHCI_USB_RESUME:
...@@ -140,11 +145,19 @@ static int ohci_bus_resume (struct usb_hcd *hcd) ...@@ -140,11 +145,19 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd); struct ohci_hcd *ohci = hcd_to_ohci (hcd);
u32 temp, enables; u32 temp, enables;
int status = -EINPROGRESS; int status = -EINPROGRESS;
unsigned long flags;
if (time_before (jiffies, ohci->next_statechange)) if (time_before (jiffies, ohci->next_statechange))
msleep(5); msleep(5);
spin_lock_irq (&ohci->lock); spin_lock_irqsave (&ohci->lock, flags);
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
spin_unlock_irqrestore (&ohci->lock, flags);
return -ESHUTDOWN;
}
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
...@@ -179,7 +192,7 @@ static int ohci_bus_resume (struct usb_hcd *hcd) ...@@ -179,7 +192,7 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
ohci_dbg (ohci, "lost power\n"); ohci_dbg (ohci, "lost power\n");
status = -EBUSY; status = -EBUSY;
} }
spin_unlock_irq (&ohci->lock); spin_unlock_irqrestore (&ohci->lock, flags);
if (status == -EBUSY) { if (status == -EBUSY) {
(void) ohci_init (ohci); (void) ohci_init (ohci);
return ohci_restart (ohci); return ohci_restart (ohci);
...@@ -297,8 +310,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) ...@@ -297,8 +310,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
/* handle autosuspended root: finish resuming before /* handle autosuspended root: finish resuming before
* letting khubd or root hub timer see state changes. * letting khubd or root hub timer see state changes.
*/ */
if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER
|| !HC_IS_RUNNING(hcd->state)) { || !HC_IS_RUNNING(hcd->state))) {
can_suspend = 0; can_suspend = 0;
goto done; goto done;
} }
...@@ -508,6 +521,9 @@ static int ohci_hub_control ( ...@@ -508,6 +521,9 @@ static int ohci_hub_control (
u32 temp; u32 temp;
int retval = 0; int retval = 0;
if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
return -ESHUTDOWN;
switch (typeReq) { switch (typeReq) {
case ClearHubFeature: case ClearHubFeature:
switch (wValue) { switch (wValue) {
......
...@@ -105,13 +105,36 @@ ohci_pci_start (struct usb_hcd *hcd) ...@@ -105,13 +105,36 @@ ohci_pci_start (struct usb_hcd *hcd)
static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message) static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
{ {
/* root hub was already suspended */ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
return 0; unsigned long flags;
int rc = 0;
/* Root hub was already suspended. Disable irq emission and
* mark HW unaccessible, bail out if RH has been resumed. Use
* the spinlock to properly synchronize with possible pending
* RH suspend or resume activity.
*
* This is still racy as hcd->state is manipulated outside of
* any locks =P But that will be a different fix.
*/
spin_lock_irqsave (&ohci->lock, flags);
if (hcd->state != HC_STATE_SUSPENDED) {
rc = -EINVAL;
goto bail;
}
ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
(void)ohci_readl(ohci, &ohci->regs->intrdisable);
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
bail:
spin_unlock_irqrestore (&ohci->lock, flags);
return rc;
} }
static int ohci_pci_resume (struct usb_hcd *hcd) static int ohci_pci_resume (struct usb_hcd *hcd)
{ {
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
usb_hcd_resume_root_hub(hcd); usb_hcd_resume_root_hub(hcd);
return 0; return 0;
} }
......
...@@ -717,6 +717,7 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message) ...@@ -717,6 +717,7 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
* at the source, so we must turn off PIRQ. * at the source, so we must turn off PIRQ.
*/ */
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0); pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
uhci->hc_inaccessible = 1; uhci->hc_inaccessible = 1;
hcd->poll_rh = 0; hcd->poll_rh = 0;
...@@ -733,6 +734,11 @@ static int uhci_resume(struct usb_hcd *hcd) ...@@ -733,6 +734,11 @@ static int uhci_resume(struct usb_hcd *hcd)
dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__); dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
/* We aren't in D3 state anymore, we do that even if dead as I
* really don't want to keep a stale HCD_FLAG_HW_ACCESSIBLE=0
*/
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
if (uhci->rh_state == UHCI_RH_RESET) /* Dead */ if (uhci->rh_state == UHCI_RH_RESET) /* Dead */
return 0; return 0;
spin_lock_irq(&uhci->lock); spin_lock_irq(&uhci->lock);
......
...@@ -387,7 +387,6 @@ ...@@ -387,7 +387,6 @@
#define PCI_DEVICE_ID_NS_SC1100_SMI 0x0511 #define PCI_DEVICE_ID_NS_SC1100_SMI 0x0511
#define PCI_DEVICE_ID_NS_SC1100_XBUS 0x0515 #define PCI_DEVICE_ID_NS_SC1100_XBUS 0x0515
#define PCI_DEVICE_ID_NS_87410 0xd001 #define PCI_DEVICE_ID_NS_87410 0xd001
#define PCI_DEVICE_ID_NS_CS5535_IDE 0x002d
#define PCI_VENDOR_ID_TSENG 0x100c #define PCI_VENDOR_ID_TSENG 0x100c
#define PCI_DEVICE_ID_TSENG_W32P_2 0x3202 #define PCI_DEVICE_ID_TSENG_W32P_2 0x3202
...@@ -489,8 +488,6 @@ ...@@ -489,8 +488,6 @@
#define PCI_DEVICE_ID_AMD_8151_0 0x7454 #define PCI_DEVICE_ID_AMD_8151_0 0x7454
#define PCI_DEVICE_ID_AMD_8131_APIC 0x7450 #define PCI_DEVICE_ID_AMD_8131_APIC 0x7450
#define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A
#define PCI_VENDOR_ID_TRIDENT 0x1023 #define PCI_VENDOR_ID_TRIDENT 0x1023
#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000 #define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000
#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001 #define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001
......
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