diff options
Diffstat (limited to 'drivers/usb/chipidea/udc.c')
-rw-r--r-- | drivers/usb/chipidea/udc.c | 84 |
1 files changed, 44 insertions, 40 deletions
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index a637da25dda0..8223fe73ea85 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c | |||
@@ -656,6 +656,44 @@ __acquires(hwep->lock) | |||
656 | return 0; | 656 | return 0; |
657 | } | 657 | } |
658 | 658 | ||
659 | static int _ep_set_halt(struct usb_ep *ep, int value, bool check_transfer) | ||
660 | { | ||
661 | struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep); | ||
662 | int direction, retval = 0; | ||
663 | unsigned long flags; | ||
664 | |||
665 | if (ep == NULL || hwep->ep.desc == NULL) | ||
666 | return -EINVAL; | ||
667 | |||
668 | if (usb_endpoint_xfer_isoc(hwep->ep.desc)) | ||
669 | return -EOPNOTSUPP; | ||
670 | |||
671 | spin_lock_irqsave(hwep->lock, flags); | ||
672 | |||
673 | if (value && hwep->dir == TX && check_transfer && | ||
674 | !list_empty(&hwep->qh.queue) && | ||
675 | !usb_endpoint_xfer_control(hwep->ep.desc)) { | ||
676 | spin_unlock_irqrestore(hwep->lock, flags); | ||
677 | return -EAGAIN; | ||
678 | } | ||
679 | |||
680 | direction = hwep->dir; | ||
681 | do { | ||
682 | retval |= hw_ep_set_halt(hwep->ci, hwep->num, hwep->dir, value); | ||
683 | |||
684 | if (!value) | ||
685 | hwep->wedge = 0; | ||
686 | |||
687 | if (hwep->type == USB_ENDPOINT_XFER_CONTROL) | ||
688 | hwep->dir = (hwep->dir == TX) ? RX : TX; | ||
689 | |||
690 | } while (hwep->dir != direction); | ||
691 | |||
692 | spin_unlock_irqrestore(hwep->lock, flags); | ||
693 | return retval; | ||
694 | } | ||
695 | |||
696 | |||
659 | /** | 697 | /** |
660 | * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts | 698 | * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts |
661 | * @gadget: gadget | 699 | * @gadget: gadget |
@@ -1051,7 +1089,7 @@ __acquires(ci->lock) | |||
1051 | num += ci->hw_ep_max / 2; | 1089 | num += ci->hw_ep_max / 2; |
1052 | 1090 | ||
1053 | spin_unlock(&ci->lock); | 1091 | spin_unlock(&ci->lock); |
1054 | err = usb_ep_set_halt(&ci->ci_hw_ep[num].ep); | 1092 | err = _ep_set_halt(&ci->ci_hw_ep[num].ep, 1, false); |
1055 | spin_lock(&ci->lock); | 1093 | spin_lock(&ci->lock); |
1056 | if (!err) | 1094 | if (!err) |
1057 | isr_setup_status_phase(ci); | 1095 | isr_setup_status_phase(ci); |
@@ -1117,8 +1155,8 @@ delegate: | |||
1117 | 1155 | ||
1118 | if (err < 0) { | 1156 | if (err < 0) { |
1119 | spin_unlock(&ci->lock); | 1157 | spin_unlock(&ci->lock); |
1120 | if (usb_ep_set_halt(&hwep->ep)) | 1158 | if (_ep_set_halt(&hwep->ep, 1, false)) |
1121 | dev_err(ci->dev, "error: ep_set_halt\n"); | 1159 | dev_err(ci->dev, "error: _ep_set_halt\n"); |
1122 | spin_lock(&ci->lock); | 1160 | spin_lock(&ci->lock); |
1123 | } | 1161 | } |
1124 | } | 1162 | } |
@@ -1149,9 +1187,9 @@ __acquires(ci->lock) | |||
1149 | err = isr_setup_status_phase(ci); | 1187 | err = isr_setup_status_phase(ci); |
1150 | if (err < 0) { | 1188 | if (err < 0) { |
1151 | spin_unlock(&ci->lock); | 1189 | spin_unlock(&ci->lock); |
1152 | if (usb_ep_set_halt(&hwep->ep)) | 1190 | if (_ep_set_halt(&hwep->ep, 1, false)) |
1153 | dev_err(ci->dev, | 1191 | dev_err(ci->dev, |
1154 | "error: ep_set_halt\n"); | 1192 | "error: _ep_set_halt\n"); |
1155 | spin_lock(&ci->lock); | 1193 | spin_lock(&ci->lock); |
1156 | } | 1194 | } |
1157 | } | 1195 | } |
@@ -1397,41 +1435,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) | |||
1397 | */ | 1435 | */ |
1398 | static int ep_set_halt(struct usb_ep *ep, int value) | 1436 | static int ep_set_halt(struct usb_ep *ep, int value) |
1399 | { | 1437 | { |
1400 | struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep); | 1438 | return _ep_set_halt(ep, value, true); |
1401 | int direction, retval = 0; | ||
1402 | unsigned long flags; | ||
1403 | |||
1404 | if (ep == NULL || hwep->ep.desc == NULL) | ||
1405 | return -EINVAL; | ||
1406 | |||
1407 | if (usb_endpoint_xfer_isoc(hwep->ep.desc)) | ||
1408 | return -EOPNOTSUPP; | ||
1409 | |||
1410 | spin_lock_irqsave(hwep->lock, flags); | ||
1411 | |||
1412 | #ifndef STALL_IN | ||
1413 | /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */ | ||
1414 | if (value && hwep->type == USB_ENDPOINT_XFER_BULK && hwep->dir == TX && | ||
1415 | !list_empty(&hwep->qh.queue)) { | ||
1416 | spin_unlock_irqrestore(hwep->lock, flags); | ||
1417 | return -EAGAIN; | ||
1418 | } | ||
1419 | #endif | ||
1420 | |||
1421 | direction = hwep->dir; | ||
1422 | do { | ||
1423 | retval |= hw_ep_set_halt(hwep->ci, hwep->num, hwep->dir, value); | ||
1424 | |||
1425 | if (!value) | ||
1426 | hwep->wedge = 0; | ||
1427 | |||
1428 | if (hwep->type == USB_ENDPOINT_XFER_CONTROL) | ||
1429 | hwep->dir = (hwep->dir == TX) ? RX : TX; | ||
1430 | |||
1431 | } while (hwep->dir != direction); | ||
1432 | |||
1433 | spin_unlock_irqrestore(hwep->lock, flags); | ||
1434 | return retval; | ||
1435 | } | 1439 | } |
1436 | 1440 | ||
1437 | /** | 1441 | /** |