diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/core/hub.c | 33 | ||||
-rw-r--r-- | drivers/usb/core/message.c | 1 | ||||
-rw-r--r-- | drivers/usb/core/usb.c | 65 | ||||
-rw-r--r-- | drivers/usb/core/usb.h | 18 | ||||
-rw-r--r-- | drivers/usb/input/hid-core.c | 2 | ||||
-rw-r--r-- | drivers/usb/misc/usbtest.c | 10 | ||||
-rw-r--r-- | drivers/usb/net/pegasus.c | 2 | ||||
-rw-r--r-- | drivers/usb/net/usbnet.c | 2 |
8 files changed, 85 insertions, 48 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index c3e2024c4347..61341d2f3c0e 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
@@ -1624,7 +1624,7 @@ static int __usb_suspend_device (struct usb_device *udev, int port1, | |||
1624 | struct usb_driver *driver; | 1624 | struct usb_driver *driver; |
1625 | 1625 | ||
1626 | intf = udev->actconfig->interface[i]; | 1626 | intf = udev->actconfig->interface[i]; |
1627 | if (state.event <= intf->dev.power.power_state.event) | 1627 | if (!is_active(intf)) |
1628 | continue; | 1628 | continue; |
1629 | if (!intf->dev.driver) | 1629 | if (!intf->dev.driver) |
1630 | continue; | 1630 | continue; |
@@ -1632,11 +1632,12 @@ static int __usb_suspend_device (struct usb_device *udev, int port1, | |||
1632 | 1632 | ||
1633 | if (driver->suspend) { | 1633 | if (driver->suspend) { |
1634 | status = driver->suspend(intf, state); | 1634 | status = driver->suspend(intf, state); |
1635 | if (intf->dev.power.power_state.event != state.event | 1635 | if (status == 0) |
1636 | || status) | 1636 | mark_quiesced(intf); |
1637 | else | ||
1637 | dev_err(&intf->dev, | 1638 | dev_err(&intf->dev, |
1638 | "suspend %d fail, code %d\n", | 1639 | "suspend error %d\n", |
1639 | state.event, status); | 1640 | status); |
1640 | } | 1641 | } |
1641 | 1642 | ||
1642 | /* only drivers with suspend() can ever resume(); | 1643 | /* only drivers with suspend() can ever resume(); |
@@ -1787,7 +1788,7 @@ static int finish_port_resume(struct usb_device *udev) | |||
1787 | struct usb_driver *driver; | 1788 | struct usb_driver *driver; |
1788 | 1789 | ||
1789 | intf = udev->actconfig->interface[i]; | 1790 | intf = udev->actconfig->interface[i]; |
1790 | if (intf->dev.power.power_state.event == PM_EVENT_ON) | 1791 | if (is_active(intf)) |
1791 | continue; | 1792 | continue; |
1792 | if (!intf->dev.driver) { | 1793 | if (!intf->dev.driver) { |
1793 | /* FIXME maybe force to alt 0 */ | 1794 | /* FIXME maybe force to alt 0 */ |
@@ -1800,12 +1801,14 @@ static int finish_port_resume(struct usb_device *udev) | |||
1800 | continue; | 1801 | continue; |
1801 | 1802 | ||
1802 | /* can we do better than just logging errors? */ | 1803 | /* can we do better than just logging errors? */ |
1804 | mark_active(intf); | ||
1803 | status = driver->resume(intf); | 1805 | status = driver->resume(intf); |
1804 | if (intf->dev.power.power_state.event != PM_EVENT_ON | 1806 | if (status < 0) { |
1805 | || status) | 1807 | mark_quiesced(intf); |
1806 | dev_dbg(&intf->dev, | 1808 | dev_dbg(&intf->dev, |
1807 | "resume fail, state %d code %d\n", | 1809 | "resume error %d\n", |
1808 | intf->dev.power.power_state.event, status); | 1810 | status); |
1811 | } | ||
1809 | } | 1812 | } |
1810 | status = 0; | 1813 | status = 0; |
1811 | 1814 | ||
@@ -1952,7 +1955,7 @@ static int remote_wakeup(struct usb_device *udev) | |||
1952 | return status; | 1955 | return status; |
1953 | } | 1956 | } |
1954 | 1957 | ||
1955 | static int hub_suspend(struct usb_interface *intf, pm_message_t state) | 1958 | static int hub_suspend(struct usb_interface *intf, pm_message_t msg) |
1956 | { | 1959 | { |
1957 | struct usb_hub *hub = usb_get_intfdata (intf); | 1960 | struct usb_hub *hub = usb_get_intfdata (intf); |
1958 | struct usb_device *hdev = hub->hdev; | 1961 | struct usb_device *hdev = hub->hdev; |
@@ -1970,14 +1973,13 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t state) | |||
1970 | if (!udev) | 1973 | if (!udev) |
1971 | continue; | 1974 | continue; |
1972 | down(&udev->serialize); | 1975 | down(&udev->serialize); |
1973 | status = __usb_suspend_device(udev, port1, state); | 1976 | status = __usb_suspend_device(udev, port1, msg); |
1974 | up(&udev->serialize); | 1977 | up(&udev->serialize); |
1975 | if (status < 0) | 1978 | if (status < 0) |
1976 | dev_dbg(&intf->dev, "suspend port %d --> %d\n", | 1979 | dev_dbg(&intf->dev, "suspend port %d --> %d\n", |
1977 | port1, status); | 1980 | port1, status); |
1978 | } | 1981 | } |
1979 | 1982 | ||
1980 | intf->dev.power.power_state = state; | ||
1981 | return 0; | 1983 | return 0; |
1982 | } | 1984 | } |
1983 | 1985 | ||
@@ -1988,9 +1990,6 @@ static int hub_resume(struct usb_interface *intf) | |||
1988 | unsigned port1; | 1990 | unsigned port1; |
1989 | int status; | 1991 | int status; |
1990 | 1992 | ||
1991 | if (intf->dev.power.power_state.event == PM_EVENT_ON) | ||
1992 | return 0; | ||
1993 | |||
1994 | for (port1 = 1; port1 <= hdev->maxchild; port1++) { | 1993 | for (port1 = 1; port1 <= hdev->maxchild; port1++) { |
1995 | struct usb_device *udev; | 1994 | struct usb_device *udev; |
1996 | u16 portstat, portchange; | 1995 | u16 portstat, portchange; |
@@ -2024,8 +2023,6 @@ static int hub_resume(struct usb_interface *intf) | |||
2024 | } | 2023 | } |
2025 | up(&udev->serialize); | 2024 | up(&udev->serialize); |
2026 | } | 2025 | } |
2027 | intf->dev.power.power_state = PMSG_ON; | ||
2028 | |||
2029 | hub->resume_root_hub = 0; | 2026 | hub->resume_root_hub = 0; |
2030 | hub_activate(hub); | 2027 | hub_activate(hub); |
2031 | return 0; | 2028 | return 0; |
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index f9a81e84dbdf..ebf59ea99263 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c | |||
@@ -1393,6 +1393,7 @@ free_interfaces: | |||
1393 | intf->dev.dma_mask = dev->dev.dma_mask; | 1393 | intf->dev.dma_mask = dev->dev.dma_mask; |
1394 | intf->dev.release = release_interface; | 1394 | intf->dev.release = release_interface; |
1395 | device_initialize (&intf->dev); | 1395 | device_initialize (&intf->dev); |
1396 | mark_quiesced(intf); | ||
1396 | sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", | 1397 | sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d", |
1397 | dev->bus->busnum, dev->devpath, | 1398 | dev->bus->busnum, dev->devpath, |
1398 | configuration, | 1399 | configuration, |
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 4c57f3f649ed..6ecfdce4f848 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c | |||
@@ -107,10 +107,19 @@ static int usb_probe_interface(struct device *dev) | |||
107 | id = usb_match_id (intf, driver->id_table); | 107 | id = usb_match_id (intf, driver->id_table); |
108 | if (id) { | 108 | if (id) { |
109 | dev_dbg (dev, "%s - got id\n", __FUNCTION__); | 109 | dev_dbg (dev, "%s - got id\n", __FUNCTION__); |
110 | |||
111 | /* Interface "power state" doesn't correspond to any hardware | ||
112 | * state whatsoever. We use it to record when it's bound to | ||
113 | * a driver that may start I/0: it's not frozen/quiesced. | ||
114 | */ | ||
115 | mark_active(intf); | ||
110 | intf->condition = USB_INTERFACE_BINDING; | 116 | intf->condition = USB_INTERFACE_BINDING; |
111 | error = driver->probe (intf, id); | 117 | error = driver->probe (intf, id); |
112 | intf->condition = error ? USB_INTERFACE_UNBOUND : | 118 | if (error) { |
113 | USB_INTERFACE_BOUND; | 119 | mark_quiesced(intf); |
120 | intf->condition = USB_INTERFACE_UNBOUND; | ||
121 | } else | ||
122 | intf->condition = USB_INTERFACE_BOUND; | ||
114 | } | 123 | } |
115 | 124 | ||
116 | return error; | 125 | return error; |
@@ -136,6 +145,7 @@ static int usb_unbind_interface(struct device *dev) | |||
136 | 0); | 145 | 0); |
137 | usb_set_intfdata(intf, NULL); | 146 | usb_set_intfdata(intf, NULL); |
138 | intf->condition = USB_INTERFACE_UNBOUND; | 147 | intf->condition = USB_INTERFACE_UNBOUND; |
148 | mark_quiesced(intf); | ||
139 | 149 | ||
140 | return 0; | 150 | return 0; |
141 | } | 151 | } |
@@ -299,6 +309,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, | |||
299 | dev->driver = &driver->driver; | 309 | dev->driver = &driver->driver; |
300 | usb_set_intfdata(iface, priv); | 310 | usb_set_intfdata(iface, priv); |
301 | iface->condition = USB_INTERFACE_BOUND; | 311 | iface->condition = USB_INTERFACE_BOUND; |
312 | mark_active(iface); | ||
302 | 313 | ||
303 | /* if interface was already added, bind now; else let | 314 | /* if interface was already added, bind now; else let |
304 | * the future device_add() bind it, bypassing probe() | 315 | * the future device_add() bind it, bypassing probe() |
@@ -345,6 +356,7 @@ void usb_driver_release_interface(struct usb_driver *driver, | |||
345 | dev->driver = NULL; | 356 | dev->driver = NULL; |
346 | usb_set_intfdata(iface, NULL); | 357 | usb_set_intfdata(iface, NULL); |
347 | iface->condition = USB_INTERFACE_UNBOUND; | 358 | iface->condition = USB_INTERFACE_UNBOUND; |
359 | mark_quiesced(iface); | ||
348 | } | 360 | } |
349 | 361 | ||
350 | /** | 362 | /** |
@@ -1404,8 +1416,9 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe, | |||
1404 | 1416 | ||
1405 | static int usb_generic_suspend(struct device *dev, pm_message_t message) | 1417 | static int usb_generic_suspend(struct device *dev, pm_message_t message) |
1406 | { | 1418 | { |
1407 | struct usb_interface *intf; | 1419 | struct usb_interface *intf; |
1408 | struct usb_driver *driver; | 1420 | struct usb_driver *driver; |
1421 | int status; | ||
1409 | 1422 | ||
1410 | if (dev->driver == &usb_generic_driver) | 1423 | if (dev->driver == &usb_generic_driver) |
1411 | return usb_suspend_device (to_usb_device(dev), message); | 1424 | return usb_suspend_device (to_usb_device(dev), message); |
@@ -1417,21 +1430,34 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message) | |||
1417 | intf = to_usb_interface(dev); | 1430 | intf = to_usb_interface(dev); |
1418 | driver = to_usb_driver(dev->driver); | 1431 | driver = to_usb_driver(dev->driver); |
1419 | 1432 | ||
1420 | /* there's only one USB suspend state */ | 1433 | /* with no hardware, USB interfaces only use FREEZE and ON states */ |
1421 | if (intf->dev.power.power_state.event) | 1434 | if (!is_active(intf)) |
1422 | return 0; | 1435 | return 0; |
1423 | 1436 | ||
1424 | if (driver->suspend) | 1437 | if (driver->suspend && driver->resume) { |
1425 | return driver->suspend(intf, message); | 1438 | status = driver->suspend(intf, message); |
1426 | return 0; | 1439 | if (status) |
1440 | dev_err(dev, "%s error %d\n", "suspend", status); | ||
1441 | else | ||
1442 | mark_quiesced(intf); | ||
1443 | } else { | ||
1444 | // FIXME else if there's no suspend method, disconnect... | ||
1445 | dev_warn(dev, "no %s?\n", "suspend"); | ||
1446 | status = 0; | ||
1447 | } | ||
1448 | return status; | ||
1427 | } | 1449 | } |
1428 | 1450 | ||
1429 | static int usb_generic_resume(struct device *dev) | 1451 | static int usb_generic_resume(struct device *dev) |
1430 | { | 1452 | { |
1431 | struct usb_interface *intf; | 1453 | struct usb_interface *intf; |
1432 | struct usb_driver *driver; | 1454 | struct usb_driver *driver; |
1455 | int status; | ||
1456 | |||
1457 | if (dev->power.power_state.event == PM_EVENT_ON) | ||
1458 | return 0; | ||
1433 | 1459 | ||
1434 | /* devices resume through their hub */ | 1460 | /* devices resume through their hubs */ |
1435 | if (dev->driver == &usb_generic_driver) | 1461 | if (dev->driver == &usb_generic_driver) |
1436 | return usb_resume_device (to_usb_device(dev)); | 1462 | return usb_resume_device (to_usb_device(dev)); |
1437 | 1463 | ||
@@ -1442,8 +1468,19 @@ static int usb_generic_resume(struct device *dev) | |||
1442 | intf = to_usb_interface(dev); | 1468 | intf = to_usb_interface(dev); |
1443 | driver = to_usb_driver(dev->driver); | 1469 | driver = to_usb_driver(dev->driver); |
1444 | 1470 | ||
1445 | if (driver->resume) | 1471 | /* if driver was suspended, it has a resume method; |
1446 | return driver->resume(intf); | 1472 | * however, sysfs can wrongly mark things as suspended |
1473 | * (on the "no suspend method" FIXME path above) | ||
1474 | */ | ||
1475 | mark_active(intf); | ||
1476 | if (driver->resume) { | ||
1477 | status = driver->resume(intf); | ||
1478 | if (status) { | ||
1479 | dev_err(dev, "%s error %d\n", "resume", status); | ||
1480 | mark_quiesced(intf); | ||
1481 | } | ||
1482 | } else | ||
1483 | dev_warn(dev, "no %s?\n", "resume"); | ||
1447 | return 0; | 1484 | return 0; |
1448 | } | 1485 | } |
1449 | 1486 | ||
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index e6504f3370ad..3741a990403e 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h | |||
@@ -28,6 +28,24 @@ extern void usb_major_cleanup(void); | |||
28 | extern int usb_host_init(void); | 28 | extern int usb_host_init(void); |
29 | extern void usb_host_cleanup(void); | 29 | extern void usb_host_cleanup(void); |
30 | 30 | ||
31 | /* Interfaces and their "power state" are owned by usbcore */ | ||
32 | |||
33 | static inline void mark_active(struct usb_interface *f) | ||
34 | { | ||
35 | f->dev.power.power_state.event = PM_EVENT_ON; | ||
36 | } | ||
37 | |||
38 | static inline void mark_quiesced(struct usb_interface *f) | ||
39 | { | ||
40 | f->dev.power.power_state.event = PM_EVENT_FREEZE; | ||
41 | } | ||
42 | |||
43 | static inline int is_active(struct usb_interface *f) | ||
44 | { | ||
45 | return f->dev.power.power_state.event == PM_EVENT_ON; | ||
46 | } | ||
47 | |||
48 | |||
31 | /* for labeling diagnostics */ | 49 | /* for labeling diagnostics */ |
32 | extern const char *usbcore_name; | 50 | extern const char *usbcore_name; |
33 | 51 | ||
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 411a0645a7a3..f7fcce731f54 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c | |||
@@ -1887,7 +1887,6 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) | |||
1887 | struct hid_device *hid = usb_get_intfdata (intf); | 1887 | struct hid_device *hid = usb_get_intfdata (intf); |
1888 | 1888 | ||
1889 | usb_kill_urb(hid->urbin); | 1889 | usb_kill_urb(hid->urbin); |
1890 | intf->dev.power.power_state = PMSG_SUSPEND; | ||
1891 | dev_dbg(&intf->dev, "suspend\n"); | 1890 | dev_dbg(&intf->dev, "suspend\n"); |
1892 | return 0; | 1891 | return 0; |
1893 | } | 1892 | } |
@@ -1897,7 +1896,6 @@ static int hid_resume(struct usb_interface *intf) | |||
1897 | struct hid_device *hid = usb_get_intfdata (intf); | 1896 | struct hid_device *hid = usb_get_intfdata (intf); |
1898 | int status; | 1897 | int status; |
1899 | 1898 | ||
1900 | intf->dev.power.power_state = PMSG_ON; | ||
1901 | if (hid->open) | 1899 | if (hid->open) |
1902 | status = usb_submit_urb(hid->urbin, GFP_NOIO); | 1900 | status = usb_submit_urb(hid->urbin, GFP_NOIO); |
1903 | else | 1901 | else |
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 54799eb0bc60..d055196533af 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c | |||
@@ -1948,21 +1948,11 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) | |||
1948 | 1948 | ||
1949 | static int usbtest_suspend (struct usb_interface *intf, pm_message_t message) | 1949 | static int usbtest_suspend (struct usb_interface *intf, pm_message_t message) |
1950 | { | 1950 | { |
1951 | struct usbtest_dev *dev = usb_get_intfdata (intf); | ||
1952 | |||
1953 | down (&dev->sem); | ||
1954 | intf->dev.power.power_state = PMSG_SUSPEND; | ||
1955 | up (&dev->sem); | ||
1956 | return 0; | 1951 | return 0; |
1957 | } | 1952 | } |
1958 | 1953 | ||
1959 | static int usbtest_resume (struct usb_interface *intf) | 1954 | static int usbtest_resume (struct usb_interface *intf) |
1960 | { | 1955 | { |
1961 | struct usbtest_dev *dev = usb_get_intfdata (intf); | ||
1962 | |||
1963 | down (&dev->sem); | ||
1964 | intf->dev.power.power_state = PMSG_ON; | ||
1965 | up (&dev->sem); | ||
1966 | return 0; | 1956 | return 0; |
1967 | } | 1957 | } |
1968 | 1958 | ||
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 6a4ffe6c3977..537eb181d985 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c | |||
@@ -1384,7 +1384,6 @@ static int pegasus_suspend (struct usb_interface *intf, pm_message_t message) | |||
1384 | usb_kill_urb(pegasus->rx_urb); | 1384 | usb_kill_urb(pegasus->rx_urb); |
1385 | usb_kill_urb(pegasus->intr_urb); | 1385 | usb_kill_urb(pegasus->intr_urb); |
1386 | } | 1386 | } |
1387 | intf->dev.power.power_state = PMSG_SUSPEND; | ||
1388 | return 0; | 1387 | return 0; |
1389 | } | 1388 | } |
1390 | 1389 | ||
@@ -1392,7 +1391,6 @@ static int pegasus_resume (struct usb_interface *intf) | |||
1392 | { | 1391 | { |
1393 | struct pegasus *pegasus = usb_get_intfdata(intf); | 1392 | struct pegasus *pegasus = usb_get_intfdata(intf); |
1394 | 1393 | ||
1395 | intf->dev.power.power_state = PMSG_ON; | ||
1396 | netif_device_attach (pegasus->net); | 1394 | netif_device_attach (pegasus->net); |
1397 | if (netif_running(pegasus->net)) { | 1395 | if (netif_running(pegasus->net)) { |
1398 | pegasus->rx_urb->status = 0; | 1396 | pegasus->rx_urb->status = 0; |
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index fce81d738933..74f05c9c84d5 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c | |||
@@ -1185,7 +1185,6 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message) | |||
1185 | netif_device_detach (dev->net); | 1185 | netif_device_detach (dev->net); |
1186 | (void) unlink_urbs (dev, &dev->rxq); | 1186 | (void) unlink_urbs (dev, &dev->rxq); |
1187 | (void) unlink_urbs (dev, &dev->txq); | 1187 | (void) unlink_urbs (dev, &dev->txq); |
1188 | intf->dev.power.power_state = PMSG_SUSPEND; | ||
1189 | return 0; | 1188 | return 0; |
1190 | } | 1189 | } |
1191 | EXPORT_SYMBOL_GPL(usbnet_suspend); | 1190 | EXPORT_SYMBOL_GPL(usbnet_suspend); |
@@ -1194,7 +1193,6 @@ int usbnet_resume (struct usb_interface *intf) | |||
1194 | { | 1193 | { |
1195 | struct usbnet *dev = usb_get_intfdata(intf); | 1194 | struct usbnet *dev = usb_get_intfdata(intf); |
1196 | 1195 | ||
1197 | intf->dev.power.power_state = PMSG_ON; | ||
1198 | netif_device_attach (dev->net); | 1196 | netif_device_attach (dev->net); |
1199 | tasklet_schedule (&dev->bh); | 1197 | tasklet_schedule (&dev->bh); |
1200 | return 0; | 1198 | return 0; |