.. | .. |
---|
105 | 105 | (crq.bRequestType & USB_DIR_IN) ? "in" : "out", |
---|
106 | 106 | ep->ep0.state); |
---|
107 | 107 | |
---|
108 | | - /* Check our state, cancel pending requests if needed */ |
---|
109 | | - if (ep->ep0.state != ep0_state_token) { |
---|
| 108 | + /* |
---|
| 109 | + * Check our state, cancel pending requests if needed |
---|
| 110 | + * |
---|
| 111 | + * Note: Under some circumstances, we can get a new setup |
---|
| 112 | + * packet while waiting for the stall ack, just accept it. |
---|
| 113 | + * |
---|
| 114 | + * In any case, a SETUP packet in wrong state should have |
---|
| 115 | + * reset the HW state machine, so let's just log, nuke |
---|
| 116 | + * requests, move on. |
---|
| 117 | + */ |
---|
| 118 | + if (ep->ep0.state != ep0_state_token && |
---|
| 119 | + ep->ep0.state != ep0_state_stall) { |
---|
110 | 120 | EPDBG(ep, "wrong state\n"); |
---|
111 | 121 | ast_vhub_nuke(ep, -EIO); |
---|
112 | | - |
---|
113 | | - /* |
---|
114 | | - * Accept the packet regardless, this seems to happen |
---|
115 | | - * when stalling a SETUP packet that has an OUT data |
---|
116 | | - * phase. |
---|
117 | | - */ |
---|
118 | | - ast_vhub_nuke(ep, 0); |
---|
119 | | - goto stall; |
---|
120 | 122 | } |
---|
121 | 123 | |
---|
122 | 124 | /* Calculate next state for EP0 */ |
---|
.. | .. |
---|
165 | 167 | stall: |
---|
166 | 168 | EPDBG(ep, "stalling\n"); |
---|
167 | 169 | writel(VHUB_EP0_CTRL_STALL, ep->ep0.ctlstat); |
---|
168 | | - ep->ep0.state = ep0_state_status; |
---|
| 170 | + ep->ep0.state = ep0_state_stall; |
---|
169 | 171 | ep->ep0.dir_in = false; |
---|
170 | 172 | return; |
---|
171 | 173 | |
---|
.. | .. |
---|
299 | 301 | if ((ep->ep0.dir_in && (stat & VHUB_EP0_TX_BUFF_RDY)) || |
---|
300 | 302 | (!ep->ep0.dir_in && (stat & VHUB_EP0_RX_BUFF_RDY)) || |
---|
301 | 303 | (ep->ep0.dir_in != in_ack)) { |
---|
| 304 | + /* In that case, ignore interrupt */ |
---|
302 | 305 | dev_warn(dev, "irq state mismatch"); |
---|
303 | | - stall = true; |
---|
304 | 306 | break; |
---|
305 | 307 | } |
---|
306 | 308 | /* |
---|
.. | .. |
---|
335 | 337 | dev_warn(dev, "status direction mismatch\n"); |
---|
336 | 338 | stall = true; |
---|
337 | 339 | } |
---|
| 340 | + break; |
---|
| 341 | + case ep0_state_stall: |
---|
| 342 | + /* |
---|
| 343 | + * There shouldn't be any request left, but nuke just in case |
---|
| 344 | + * otherwise the stale request will block subsequent ones |
---|
| 345 | + */ |
---|
| 346 | + ast_vhub_nuke(ep, -EIO); |
---|
| 347 | + break; |
---|
338 | 348 | } |
---|
339 | 349 | |
---|
340 | | - /* Reset to token state */ |
---|
341 | | - ep->ep0.state = ep0_state_token; |
---|
342 | | - if (stall) |
---|
| 350 | + /* Reset to token state or stall */ |
---|
| 351 | + if (stall) { |
---|
343 | 352 | writel(VHUB_EP0_CTRL_STALL, ep->ep0.ctlstat); |
---|
| 353 | + ep->ep0.state = ep0_state_stall; |
---|
| 354 | + } else |
---|
| 355 | + ep->ep0.state = ep0_state_token; |
---|
344 | 356 | } |
---|
345 | 357 | |
---|
346 | 358 | static int ast_vhub_ep0_queue(struct usb_ep* u_ep, struct usb_request *u_req, |
---|
.. | .. |
---|
367 | 379 | return -EINVAL; |
---|
368 | 380 | |
---|
369 | 381 | /* Disabled device */ |
---|
370 | | - if (ep->dev && (!ep->dev->enabled || ep->dev->suspended)) |
---|
| 382 | + if (ep->dev && !ep->dev->enabled) |
---|
371 | 383 | return -ESHUTDOWN; |
---|
372 | 384 | |
---|
373 | 385 | /* Data, no buffer and not internal ? */ |
---|
.. | .. |
---|
390 | 402 | spin_lock_irqsave(&vhub->lock, flags); |
---|
391 | 403 | |
---|
392 | 404 | /* EP0 can only support a single request at a time */ |
---|
393 | | - if (!list_empty(&ep->queue) || ep->ep0.state == ep0_state_token) { |
---|
| 405 | + if (!list_empty(&ep->queue) || |
---|
| 406 | + ep->ep0.state == ep0_state_token || |
---|
| 407 | + ep->ep0.state == ep0_state_stall) { |
---|
394 | 408 | dev_warn(dev, "EP0: Request in wrong state\n"); |
---|
| 409 | + EPVDBG(ep, "EP0: list_empty=%d state=%d\n", |
---|
| 410 | + list_empty(&ep->queue), ep->ep0.state); |
---|
395 | 411 | spin_unlock_irqrestore(&vhub->lock, flags); |
---|
396 | 412 | return -EBUSY; |
---|
397 | 413 | } |
---|
.. | .. |
---|
459 | 475 | .free_request = ast_vhub_free_request, |
---|
460 | 476 | }; |
---|
461 | 477 | |
---|
| 478 | +void ast_vhub_reset_ep0(struct ast_vhub_dev *dev) |
---|
| 479 | +{ |
---|
| 480 | + struct ast_vhub_ep *ep = &dev->ep0; |
---|
| 481 | + |
---|
| 482 | + ast_vhub_nuke(ep, -EIO); |
---|
| 483 | + ep->ep0.state = ep0_state_token; |
---|
| 484 | +} |
---|
| 485 | + |
---|
| 486 | + |
---|
462 | 487 | void ast_vhub_init_ep0(struct ast_vhub *vhub, struct ast_vhub_ep *ep, |
---|
463 | 488 | struct ast_vhub_dev *dev) |
---|
464 | 489 | { |
---|