| .. | .. |
|---|
| 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 | { |
|---|