Skip to content

Commit 56ffa1d

Browse files
author
Peter Chen
committed
usb: chipidea: udc: using the correct stall implementation
According to spec, there are functional and protocol stalls. For functional stall, it is for bulk and interrupt endpoints, below are cases for it: - Host sends SET_FEATURE request for Set-Halt, the udc driver needs to set stall, and return true unconditionally. - The gadget driver may call usb_ep_set_halt to stall certain endpoints, if there is a transfer in pending, the udc driver should not set stall, and return -EAGAIN accordingly. These two kinds of stall need to be cleared by host using CLEAR_FEATURE request (Clear-Halt). For protocol stall, it is for control endpoint, this stall will be set if the control request has failed. This stall will be cleared by next setup request (hardware will do it). It fixed usbtest (drivers/usb/misc/usbtest.c) Test 13 "set/clear halt" test failure, meanwhile, this change has been verified by USB2 CV Compliance Test and MSC Tests. Cc: <[email protected]> #3.10+ Cc: Alan Stern <[email protected]> Cc: Felipe Balbi <[email protected]> Signed-off-by: Peter Chen <[email protected]>
1 parent 6ff33f3 commit 56ffa1d

File tree

1 file changed

+44
-40
lines changed
  • drivers/usb/chipidea

1 file changed

+44
-40
lines changed

drivers/usb/chipidea/udc.c

Lines changed: 44 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,44 @@ __acquires(hwep->lock)
656656
return 0;
657657
}
658658

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+
659697
/**
660698
* _gadget_stop_activity: stops all USB activity, flushes & disables all endpts
661699
* @gadget: gadget
@@ -1051,7 +1089,7 @@ __acquires(ci->lock)
10511089
num += ci->hw_ep_max / 2;
10521090

10531091
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);
10551093
spin_lock(&ci->lock);
10561094
if (!err)
10571095
isr_setup_status_phase(ci);
@@ -1117,8 +1155,8 @@ __acquires(ci->lock)
11171155

11181156
if (err < 0) {
11191157
spin_unlock(&ci->lock);
1120-
if (usb_ep_set_halt(&hwep->ep))
1121-
dev_err(ci->dev, "error: ep_set_halt\n");
1158+
if (_ep_set_halt(&hwep->ep, 1, false))
1159+
dev_err(ci->dev, "error: _ep_set_halt\n");
11221160
spin_lock(&ci->lock);
11231161
}
11241162
}
@@ -1149,9 +1187,9 @@ __acquires(ci->lock)
11491187
err = isr_setup_status_phase(ci);
11501188
if (err < 0) {
11511189
spin_unlock(&ci->lock);
1152-
if (usb_ep_set_halt(&hwep->ep))
1190+
if (_ep_set_halt(&hwep->ep, 1, false))
11531191
dev_err(ci->dev,
1154-
"error: ep_set_halt\n");
1192+
"error: _ep_set_halt\n");
11551193
spin_lock(&ci->lock);
11561194
}
11571195
}
@@ -1397,41 +1435,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req)
13971435
*/
13981436
static int ep_set_halt(struct usb_ep *ep, int value)
13991437
{
1400-
struct ci_hw_ep *hwep = container_of(ep, struct ci_hw_ep, ep);
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;
1438+
return _ep_set_halt(ep, value, true);
14351439
}
14361440

14371441
/**

0 commit comments

Comments
 (0)