diff options
| -rw-r--r-- | drivers/usb/gadget/udc/dummy_hcd.c | 32 |
1 files changed, 30 insertions, 2 deletions
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index b2ab9cc33fec..b17618a55f1b 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c | |||
| @@ -255,11 +255,13 @@ struct dummy { | |||
| 255 | */ | 255 | */ |
| 256 | struct dummy_ep ep[DUMMY_ENDPOINTS]; | 256 | struct dummy_ep ep[DUMMY_ENDPOINTS]; |
| 257 | int address; | 257 | int address; |
| 258 | int callback_usage; | ||
| 258 | struct usb_gadget gadget; | 259 | struct usb_gadget gadget; |
| 259 | struct usb_gadget_driver *driver; | 260 | struct usb_gadget_driver *driver; |
| 260 | struct dummy_request fifo_req; | 261 | struct dummy_request fifo_req; |
| 261 | u8 fifo_buf[FIFO_SIZE]; | 262 | u8 fifo_buf[FIFO_SIZE]; |
| 262 | u16 devstatus; | 263 | u16 devstatus; |
| 264 | unsigned ints_enabled:1; | ||
| 263 | unsigned udc_suspended:1; | 265 | unsigned udc_suspended:1; |
| 264 | unsigned pullup:1; | 266 | unsigned pullup:1; |
| 265 | 267 | ||
| @@ -441,18 +443,27 @@ static void set_link_state(struct dummy_hcd *dum_hcd) | |||
| 441 | (~dum_hcd->old_status) & dum_hcd->port_status; | 443 | (~dum_hcd->old_status) & dum_hcd->port_status; |
| 442 | 444 | ||
| 443 | /* Report reset and disconnect events to the driver */ | 445 | /* Report reset and disconnect events to the driver */ |
| 444 | if (dum->driver && (disconnect || reset)) { | 446 | if (dum->ints_enabled && (disconnect || reset)) { |
| 445 | stop_activity(dum); | 447 | stop_activity(dum); |
| 448 | ++dum->callback_usage; | ||
| 449 | spin_unlock(&dum->lock); | ||
| 446 | if (reset) | 450 | if (reset) |
| 447 | usb_gadget_udc_reset(&dum->gadget, dum->driver); | 451 | usb_gadget_udc_reset(&dum->gadget, dum->driver); |
| 448 | else | 452 | else |
| 449 | dum->driver->disconnect(&dum->gadget); | 453 | dum->driver->disconnect(&dum->gadget); |
| 454 | spin_lock(&dum->lock); | ||
| 455 | --dum->callback_usage; | ||
| 450 | } | 456 | } |
| 451 | } else if (dum_hcd->active != dum_hcd->old_active) { | 457 | } else if (dum_hcd->active != dum_hcd->old_active && |
| 458 | dum->ints_enabled) { | ||
| 459 | ++dum->callback_usage; | ||
| 460 | spin_unlock(&dum->lock); | ||
| 452 | if (dum_hcd->old_active && dum->driver->suspend) | 461 | if (dum_hcd->old_active && dum->driver->suspend) |
| 453 | dum->driver->suspend(&dum->gadget); | 462 | dum->driver->suspend(&dum->gadget); |
| 454 | else if (!dum_hcd->old_active && dum->driver->resume) | 463 | else if (!dum_hcd->old_active && dum->driver->resume) |
| 455 | dum->driver->resume(&dum->gadget); | 464 | dum->driver->resume(&dum->gadget); |
| 465 | spin_lock(&dum->lock); | ||
| 466 | --dum->callback_usage; | ||
| 456 | } | 467 | } |
| 457 | 468 | ||
| 458 | dum_hcd->old_status = dum_hcd->port_status; | 469 | dum_hcd->old_status = dum_hcd->port_status; |
| @@ -973,8 +984,11 @@ static int dummy_udc_start(struct usb_gadget *g, | |||
| 973 | * can't enumerate without help from the driver we're binding. | 984 | * can't enumerate without help from the driver we're binding. |
| 974 | */ | 985 | */ |
| 975 | 986 | ||
| 987 | spin_lock_irq(&dum->lock); | ||
| 976 | dum->devstatus = 0; | 988 | dum->devstatus = 0; |
| 977 | dum->driver = driver; | 989 | dum->driver = driver; |
| 990 | dum->ints_enabled = 1; | ||
| 991 | spin_unlock_irq(&dum->lock); | ||
| 978 | 992 | ||
| 979 | return 0; | 993 | return 0; |
| 980 | } | 994 | } |
| @@ -985,6 +999,16 @@ static int dummy_udc_stop(struct usb_gadget *g) | |||
| 985 | struct dummy *dum = dum_hcd->dum; | 999 | struct dummy *dum = dum_hcd->dum; |
| 986 | 1000 | ||
| 987 | spin_lock_irq(&dum->lock); | 1001 | spin_lock_irq(&dum->lock); |
| 1002 | dum->ints_enabled = 0; | ||
| 1003 | stop_activity(dum); | ||
| 1004 | |||
| 1005 | /* emulate synchronize_irq(): wait for callbacks to finish */ | ||
| 1006 | while (dum->callback_usage > 0) { | ||
| 1007 | spin_unlock_irq(&dum->lock); | ||
| 1008 | usleep_range(1000, 2000); | ||
| 1009 | spin_lock_irq(&dum->lock); | ||
| 1010 | } | ||
| 1011 | |||
| 988 | dum->driver = NULL; | 1012 | dum->driver = NULL; |
| 989 | spin_unlock_irq(&dum->lock); | 1013 | spin_unlock_irq(&dum->lock); |
| 990 | 1014 | ||
| @@ -1529,6 +1553,8 @@ static struct dummy_ep *find_endpoint(struct dummy *dum, u8 address) | |||
| 1529 | if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ? | 1553 | if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ? |
| 1530 | dum->ss_hcd : dum->hs_hcd))) | 1554 | dum->ss_hcd : dum->hs_hcd))) |
| 1531 | return NULL; | 1555 | return NULL; |
| 1556 | if (!dum->ints_enabled) | ||
| 1557 | return NULL; | ||
| 1532 | if ((address & ~USB_DIR_IN) == 0) | 1558 | if ((address & ~USB_DIR_IN) == 0) |
| 1533 | return &dum->ep[0]; | 1559 | return &dum->ep[0]; |
| 1534 | for (i = 1; i < DUMMY_ENDPOINTS; i++) { | 1560 | for (i = 1; i < DUMMY_ENDPOINTS; i++) { |
| @@ -1870,10 +1896,12 @@ restart: | |||
| 1870 | * until setup() returns; no reentrancy issues etc. | 1896 | * until setup() returns; no reentrancy issues etc. |
| 1871 | */ | 1897 | */ |
| 1872 | if (value > 0) { | 1898 | if (value > 0) { |
| 1899 | ++dum->callback_usage; | ||
| 1873 | spin_unlock(&dum->lock); | 1900 | spin_unlock(&dum->lock); |
| 1874 | value = dum->driver->setup(&dum->gadget, | 1901 | value = dum->driver->setup(&dum->gadget, |
| 1875 | &setup); | 1902 | &setup); |
| 1876 | spin_lock(&dum->lock); | 1903 | spin_lock(&dum->lock); |
| 1904 | --dum->callback_usage; | ||
| 1877 | 1905 | ||
| 1878 | if (value >= 0) { | 1906 | if (value >= 0) { |
| 1879 | /* no delays (max 64KB data stage) */ | 1907 | /* no delays (max 64KB data stage) */ |
