162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * MUSB OTG peripheral driver ep0 handling 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2005 Mentor Graphics Corporation 662306a36Sopenharmony_ci * Copyright (C) 2005-2006 by Texas Instruments 762306a36Sopenharmony_ci * Copyright (C) 2006-2007 Nokia Corporation 862306a36Sopenharmony_ci * Copyright (C) 2008-2009 MontaVista Software, Inc. <source@mvista.com> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/list.h> 1362306a36Sopenharmony_ci#include <linux/timer.h> 1462306a36Sopenharmony_ci#include <linux/spinlock.h> 1562306a36Sopenharmony_ci#include <linux/device.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "musb_core.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* ep0 is always musb->endpoints[0].ep_in */ 2162306a36Sopenharmony_ci#define next_ep0_request(musb) next_in_request(&(musb)->endpoints[0]) 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* 2462306a36Sopenharmony_ci * locking note: we use only the controller lock, for simpler correctness. 2562306a36Sopenharmony_ci * It's always held with IRQs blocked. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * It protects the ep0 request queue as well as ep0_state, not just the 2862306a36Sopenharmony_ci * controller and indexed registers. And that lock stays held unless it 2962306a36Sopenharmony_ci * needs to be dropped to allow reentering this driver ... like upcalls to 3062306a36Sopenharmony_ci * the gadget driver, or adjusting endpoint halt status. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic char *decode_ep0stage(u8 stage) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci switch (stage) { 3662306a36Sopenharmony_ci case MUSB_EP0_STAGE_IDLE: return "idle"; 3762306a36Sopenharmony_ci case MUSB_EP0_STAGE_SETUP: return "setup"; 3862306a36Sopenharmony_ci case MUSB_EP0_STAGE_TX: return "in"; 3962306a36Sopenharmony_ci case MUSB_EP0_STAGE_RX: return "out"; 4062306a36Sopenharmony_ci case MUSB_EP0_STAGE_ACKWAIT: return "wait"; 4162306a36Sopenharmony_ci case MUSB_EP0_STAGE_STATUSIN: return "in/status"; 4262306a36Sopenharmony_ci case MUSB_EP0_STAGE_STATUSOUT: return "out/status"; 4362306a36Sopenharmony_ci default: return "?"; 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* handle a standard GET_STATUS request 4862306a36Sopenharmony_ci * Context: caller holds controller lock 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_cistatic int service_tx_status_request( 5162306a36Sopenharmony_ci struct musb *musb, 5262306a36Sopenharmony_ci const struct usb_ctrlrequest *ctrlrequest) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci void __iomem *mbase = musb->mregs; 5562306a36Sopenharmony_ci int handled = 1; 5662306a36Sopenharmony_ci u8 result[2], epnum = 0; 5762306a36Sopenharmony_ci const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci result[1] = 0; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci switch (recip) { 6262306a36Sopenharmony_ci case USB_RECIP_DEVICE: 6362306a36Sopenharmony_ci result[0] = musb->g.is_selfpowered << USB_DEVICE_SELF_POWERED; 6462306a36Sopenharmony_ci result[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP; 6562306a36Sopenharmony_ci if (musb->g.is_otg) { 6662306a36Sopenharmony_ci result[0] |= musb->g.b_hnp_enable 6762306a36Sopenharmony_ci << USB_DEVICE_B_HNP_ENABLE; 6862306a36Sopenharmony_ci result[0] |= musb->g.a_alt_hnp_support 6962306a36Sopenharmony_ci << USB_DEVICE_A_ALT_HNP_SUPPORT; 7062306a36Sopenharmony_ci result[0] |= musb->g.a_hnp_support 7162306a36Sopenharmony_ci << USB_DEVICE_A_HNP_SUPPORT; 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci break; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci case USB_RECIP_INTERFACE: 7662306a36Sopenharmony_ci result[0] = 0; 7762306a36Sopenharmony_ci break; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci case USB_RECIP_ENDPOINT: { 8062306a36Sopenharmony_ci int is_in; 8162306a36Sopenharmony_ci struct musb_ep *ep; 8262306a36Sopenharmony_ci u16 tmp; 8362306a36Sopenharmony_ci void __iomem *regs; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci epnum = (u8) ctrlrequest->wIndex; 8662306a36Sopenharmony_ci if (!epnum) { 8762306a36Sopenharmony_ci result[0] = 0; 8862306a36Sopenharmony_ci break; 8962306a36Sopenharmony_ci } 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci is_in = epnum & USB_DIR_IN; 9262306a36Sopenharmony_ci epnum &= 0x0f; 9362306a36Sopenharmony_ci if (epnum >= MUSB_C_NUM_EPS) { 9462306a36Sopenharmony_ci handled = -EINVAL; 9562306a36Sopenharmony_ci break; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (is_in) 9962306a36Sopenharmony_ci ep = &musb->endpoints[epnum].ep_in; 10062306a36Sopenharmony_ci else 10162306a36Sopenharmony_ci ep = &musb->endpoints[epnum].ep_out; 10262306a36Sopenharmony_ci regs = musb->endpoints[epnum].regs; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (!ep->desc) { 10562306a36Sopenharmony_ci handled = -EINVAL; 10662306a36Sopenharmony_ci break; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci musb_ep_select(mbase, epnum); 11062306a36Sopenharmony_ci if (is_in) 11162306a36Sopenharmony_ci tmp = musb_readw(regs, MUSB_TXCSR) 11262306a36Sopenharmony_ci & MUSB_TXCSR_P_SENDSTALL; 11362306a36Sopenharmony_ci else 11462306a36Sopenharmony_ci tmp = musb_readw(regs, MUSB_RXCSR) 11562306a36Sopenharmony_ci & MUSB_RXCSR_P_SENDSTALL; 11662306a36Sopenharmony_ci musb_ep_select(mbase, 0); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci result[0] = tmp ? 1 : 0; 11962306a36Sopenharmony_ci } break; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci default: 12262306a36Sopenharmony_ci /* class, vendor, etc ... delegate */ 12362306a36Sopenharmony_ci handled = 0; 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci /* fill up the fifo; caller updates csr0 */ 12862306a36Sopenharmony_ci if (handled > 0) { 12962306a36Sopenharmony_ci u16 len = le16_to_cpu(ctrlrequest->wLength); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (len > 2) 13262306a36Sopenharmony_ci len = 2; 13362306a36Sopenharmony_ci musb_write_fifo(&musb->endpoints[0], len, result); 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci return handled; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* 14062306a36Sopenharmony_ci * handle a control-IN request, the end0 buffer contains the current request 14162306a36Sopenharmony_ci * that is supposed to be a standard control request. Assumes the fifo to 14262306a36Sopenharmony_ci * be at least 2 bytes long. 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * @return 0 if the request was NOT HANDLED, 14562306a36Sopenharmony_ci * < 0 when error 14662306a36Sopenharmony_ci * > 0 when the request is processed 14762306a36Sopenharmony_ci * 14862306a36Sopenharmony_ci * Context: caller holds controller lock 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_cistatic int 15162306a36Sopenharmony_ciservice_in_request(struct musb *musb, const struct usb_ctrlrequest *ctrlrequest) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci int handled = 0; /* not handled */ 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if ((ctrlrequest->bRequestType & USB_TYPE_MASK) 15662306a36Sopenharmony_ci == USB_TYPE_STANDARD) { 15762306a36Sopenharmony_ci switch (ctrlrequest->bRequest) { 15862306a36Sopenharmony_ci case USB_REQ_GET_STATUS: 15962306a36Sopenharmony_ci handled = service_tx_status_request(musb, 16062306a36Sopenharmony_ci ctrlrequest); 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* case USB_REQ_SYNC_FRAME: */ 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci default: 16662306a36Sopenharmony_ci break; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci return handled; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* 17362306a36Sopenharmony_ci * Context: caller holds controller lock 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_cistatic void musb_g_ep0_giveback(struct musb *musb, struct usb_request *req) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci musb_g_giveback(&musb->endpoints[0].ep_in, req, 0); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/* 18162306a36Sopenharmony_ci * Tries to start B-device HNP negotiation if enabled via sysfs 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_cistatic inline void musb_try_b_hnp_enable(struct musb *musb) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci void __iomem *mbase = musb->mregs; 18662306a36Sopenharmony_ci u8 devctl; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci musb_dbg(musb, "HNP: Setting HR"); 18962306a36Sopenharmony_ci devctl = musb_readb(mbase, MUSB_DEVCTL); 19062306a36Sopenharmony_ci musb_writeb(mbase, MUSB_DEVCTL, devctl | MUSB_DEVCTL_HR); 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* 19462306a36Sopenharmony_ci * Handle all control requests with no DATA stage, including standard 19562306a36Sopenharmony_ci * requests such as: 19662306a36Sopenharmony_ci * USB_REQ_SET_CONFIGURATION, USB_REQ_SET_INTERFACE, unrecognized 19762306a36Sopenharmony_ci * always delegated to the gadget driver 19862306a36Sopenharmony_ci * USB_REQ_SET_ADDRESS, USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE 19962306a36Sopenharmony_ci * always handled here, except for class/vendor/... features 20062306a36Sopenharmony_ci * 20162306a36Sopenharmony_ci * Context: caller holds controller lock 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_cistatic int 20462306a36Sopenharmony_ciservice_zero_data_request(struct musb *musb, 20562306a36Sopenharmony_ci struct usb_ctrlrequest *ctrlrequest) 20662306a36Sopenharmony_ci__releases(musb->lock) 20762306a36Sopenharmony_ci__acquires(musb->lock) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci int handled = -EINVAL; 21062306a36Sopenharmony_ci void __iomem *mbase = musb->mregs; 21162306a36Sopenharmony_ci const u8 recip = ctrlrequest->bRequestType & USB_RECIP_MASK; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* the gadget driver handles everything except what we MUST handle */ 21462306a36Sopenharmony_ci if ((ctrlrequest->bRequestType & USB_TYPE_MASK) 21562306a36Sopenharmony_ci == USB_TYPE_STANDARD) { 21662306a36Sopenharmony_ci switch (ctrlrequest->bRequest) { 21762306a36Sopenharmony_ci case USB_REQ_SET_ADDRESS: 21862306a36Sopenharmony_ci /* change it after the status stage */ 21962306a36Sopenharmony_ci musb->set_address = true; 22062306a36Sopenharmony_ci musb->address = (u8) (ctrlrequest->wValue & 0x7f); 22162306a36Sopenharmony_ci handled = 1; 22262306a36Sopenharmony_ci break; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci case USB_REQ_CLEAR_FEATURE: 22562306a36Sopenharmony_ci switch (recip) { 22662306a36Sopenharmony_ci case USB_RECIP_DEVICE: 22762306a36Sopenharmony_ci if (ctrlrequest->wValue 22862306a36Sopenharmony_ci != USB_DEVICE_REMOTE_WAKEUP) 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci musb->may_wakeup = 0; 23162306a36Sopenharmony_ci handled = 1; 23262306a36Sopenharmony_ci break; 23362306a36Sopenharmony_ci case USB_RECIP_INTERFACE: 23462306a36Sopenharmony_ci break; 23562306a36Sopenharmony_ci case USB_RECIP_ENDPOINT:{ 23662306a36Sopenharmony_ci const u8 epnum = 23762306a36Sopenharmony_ci ctrlrequest->wIndex & 0x0f; 23862306a36Sopenharmony_ci struct musb_ep *musb_ep; 23962306a36Sopenharmony_ci struct musb_hw_ep *ep; 24062306a36Sopenharmony_ci struct musb_request *request; 24162306a36Sopenharmony_ci void __iomem *regs; 24262306a36Sopenharmony_ci int is_in; 24362306a36Sopenharmony_ci u16 csr; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (epnum == 0 || epnum >= MUSB_C_NUM_EPS || 24662306a36Sopenharmony_ci ctrlrequest->wValue != USB_ENDPOINT_HALT) 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci ep = musb->endpoints + epnum; 25062306a36Sopenharmony_ci regs = ep->regs; 25162306a36Sopenharmony_ci is_in = ctrlrequest->wIndex & USB_DIR_IN; 25262306a36Sopenharmony_ci if (is_in) 25362306a36Sopenharmony_ci musb_ep = &ep->ep_in; 25462306a36Sopenharmony_ci else 25562306a36Sopenharmony_ci musb_ep = &ep->ep_out; 25662306a36Sopenharmony_ci if (!musb_ep->desc) 25762306a36Sopenharmony_ci break; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci handled = 1; 26062306a36Sopenharmony_ci /* Ignore request if endpoint is wedged */ 26162306a36Sopenharmony_ci if (musb_ep->wedged) 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci musb_ep_select(mbase, epnum); 26562306a36Sopenharmony_ci if (is_in) { 26662306a36Sopenharmony_ci csr = musb_readw(regs, MUSB_TXCSR); 26762306a36Sopenharmony_ci csr |= MUSB_TXCSR_CLRDATATOG | 26862306a36Sopenharmony_ci MUSB_TXCSR_P_WZC_BITS; 26962306a36Sopenharmony_ci csr &= ~(MUSB_TXCSR_P_SENDSTALL | 27062306a36Sopenharmony_ci MUSB_TXCSR_P_SENTSTALL | 27162306a36Sopenharmony_ci MUSB_TXCSR_TXPKTRDY); 27262306a36Sopenharmony_ci musb_writew(regs, MUSB_TXCSR, csr); 27362306a36Sopenharmony_ci } else { 27462306a36Sopenharmony_ci csr = musb_readw(regs, MUSB_RXCSR); 27562306a36Sopenharmony_ci csr |= MUSB_RXCSR_CLRDATATOG | 27662306a36Sopenharmony_ci MUSB_RXCSR_P_WZC_BITS; 27762306a36Sopenharmony_ci csr &= ~(MUSB_RXCSR_P_SENDSTALL | 27862306a36Sopenharmony_ci MUSB_RXCSR_P_SENTSTALL); 27962306a36Sopenharmony_ci musb_writew(regs, MUSB_RXCSR, csr); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* Maybe start the first request in the queue */ 28362306a36Sopenharmony_ci request = next_request(musb_ep); 28462306a36Sopenharmony_ci if (!musb_ep->busy && request) { 28562306a36Sopenharmony_ci musb_dbg(musb, "restarting the request"); 28662306a36Sopenharmony_ci musb_ep_restart(musb, request); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci /* select ep0 again */ 29062306a36Sopenharmony_ci musb_ep_select(mbase, 0); 29162306a36Sopenharmony_ci } break; 29262306a36Sopenharmony_ci default: 29362306a36Sopenharmony_ci /* class, vendor, etc ... delegate */ 29462306a36Sopenharmony_ci handled = 0; 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci break; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci case USB_REQ_SET_FEATURE: 30062306a36Sopenharmony_ci switch (recip) { 30162306a36Sopenharmony_ci case USB_RECIP_DEVICE: 30262306a36Sopenharmony_ci handled = 1; 30362306a36Sopenharmony_ci switch (ctrlrequest->wValue) { 30462306a36Sopenharmony_ci case USB_DEVICE_REMOTE_WAKEUP: 30562306a36Sopenharmony_ci musb->may_wakeup = 1; 30662306a36Sopenharmony_ci break; 30762306a36Sopenharmony_ci case USB_DEVICE_TEST_MODE: 30862306a36Sopenharmony_ci if (musb->g.speed != USB_SPEED_HIGH) 30962306a36Sopenharmony_ci goto stall; 31062306a36Sopenharmony_ci if (ctrlrequest->wIndex & 0xff) 31162306a36Sopenharmony_ci goto stall; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci switch (ctrlrequest->wIndex >> 8) { 31462306a36Sopenharmony_ci case USB_TEST_J: 31562306a36Sopenharmony_ci pr_debug("USB_TEST_J\n"); 31662306a36Sopenharmony_ci musb->test_mode_nr = 31762306a36Sopenharmony_ci MUSB_TEST_J; 31862306a36Sopenharmony_ci break; 31962306a36Sopenharmony_ci case USB_TEST_K: 32062306a36Sopenharmony_ci pr_debug("USB_TEST_K\n"); 32162306a36Sopenharmony_ci musb->test_mode_nr = 32262306a36Sopenharmony_ci MUSB_TEST_K; 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci case USB_TEST_SE0_NAK: 32562306a36Sopenharmony_ci pr_debug("USB_TEST_SE0_NAK\n"); 32662306a36Sopenharmony_ci musb->test_mode_nr = 32762306a36Sopenharmony_ci MUSB_TEST_SE0_NAK; 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci case USB_TEST_PACKET: 33062306a36Sopenharmony_ci pr_debug("USB_TEST_PACKET\n"); 33162306a36Sopenharmony_ci musb->test_mode_nr = 33262306a36Sopenharmony_ci MUSB_TEST_PACKET; 33362306a36Sopenharmony_ci break; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci case 0xc0: 33662306a36Sopenharmony_ci /* TEST_FORCE_HS */ 33762306a36Sopenharmony_ci pr_debug("TEST_FORCE_HS\n"); 33862306a36Sopenharmony_ci musb->test_mode_nr = 33962306a36Sopenharmony_ci MUSB_TEST_FORCE_HS; 34062306a36Sopenharmony_ci break; 34162306a36Sopenharmony_ci case 0xc1: 34262306a36Sopenharmony_ci /* TEST_FORCE_FS */ 34362306a36Sopenharmony_ci pr_debug("TEST_FORCE_FS\n"); 34462306a36Sopenharmony_ci musb->test_mode_nr = 34562306a36Sopenharmony_ci MUSB_TEST_FORCE_FS; 34662306a36Sopenharmony_ci break; 34762306a36Sopenharmony_ci case 0xc2: 34862306a36Sopenharmony_ci /* TEST_FIFO_ACCESS */ 34962306a36Sopenharmony_ci pr_debug("TEST_FIFO_ACCESS\n"); 35062306a36Sopenharmony_ci musb->test_mode_nr = 35162306a36Sopenharmony_ci MUSB_TEST_FIFO_ACCESS; 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci case 0xc3: 35462306a36Sopenharmony_ci /* TEST_FORCE_HOST */ 35562306a36Sopenharmony_ci pr_debug("TEST_FORCE_HOST\n"); 35662306a36Sopenharmony_ci musb->test_mode_nr = 35762306a36Sopenharmony_ci MUSB_TEST_FORCE_HOST; 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci default: 36062306a36Sopenharmony_ci goto stall; 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* enter test mode after irq */ 36462306a36Sopenharmony_ci if (handled > 0) 36562306a36Sopenharmony_ci musb->test_mode = true; 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci case USB_DEVICE_B_HNP_ENABLE: 36862306a36Sopenharmony_ci if (!musb->g.is_otg) 36962306a36Sopenharmony_ci goto stall; 37062306a36Sopenharmony_ci musb->g.b_hnp_enable = 1; 37162306a36Sopenharmony_ci musb_try_b_hnp_enable(musb); 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci case USB_DEVICE_A_HNP_SUPPORT: 37462306a36Sopenharmony_ci if (!musb->g.is_otg) 37562306a36Sopenharmony_ci goto stall; 37662306a36Sopenharmony_ci musb->g.a_hnp_support = 1; 37762306a36Sopenharmony_ci break; 37862306a36Sopenharmony_ci case USB_DEVICE_A_ALT_HNP_SUPPORT: 37962306a36Sopenharmony_ci if (!musb->g.is_otg) 38062306a36Sopenharmony_ci goto stall; 38162306a36Sopenharmony_ci musb->g.a_alt_hnp_support = 1; 38262306a36Sopenharmony_ci break; 38362306a36Sopenharmony_ci case USB_DEVICE_DEBUG_MODE: 38462306a36Sopenharmony_ci handled = 0; 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_cistall: 38762306a36Sopenharmony_ci default: 38862306a36Sopenharmony_ci handled = -EINVAL; 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci case USB_RECIP_INTERFACE: 39462306a36Sopenharmony_ci break; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci case USB_RECIP_ENDPOINT:{ 39762306a36Sopenharmony_ci const u8 epnum = 39862306a36Sopenharmony_ci ctrlrequest->wIndex & 0x0f; 39962306a36Sopenharmony_ci struct musb_ep *musb_ep; 40062306a36Sopenharmony_ci struct musb_hw_ep *ep; 40162306a36Sopenharmony_ci void __iomem *regs; 40262306a36Sopenharmony_ci int is_in; 40362306a36Sopenharmony_ci u16 csr; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (epnum == 0 || epnum >= MUSB_C_NUM_EPS || 40662306a36Sopenharmony_ci ctrlrequest->wValue != USB_ENDPOINT_HALT) 40762306a36Sopenharmony_ci break; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci ep = musb->endpoints + epnum; 41062306a36Sopenharmony_ci regs = ep->regs; 41162306a36Sopenharmony_ci is_in = ctrlrequest->wIndex & USB_DIR_IN; 41262306a36Sopenharmony_ci if (is_in) 41362306a36Sopenharmony_ci musb_ep = &ep->ep_in; 41462306a36Sopenharmony_ci else 41562306a36Sopenharmony_ci musb_ep = &ep->ep_out; 41662306a36Sopenharmony_ci if (!musb_ep->desc) 41762306a36Sopenharmony_ci break; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci musb_ep_select(mbase, epnum); 42062306a36Sopenharmony_ci if (is_in) { 42162306a36Sopenharmony_ci csr = musb_readw(regs, MUSB_TXCSR); 42262306a36Sopenharmony_ci if (csr & MUSB_TXCSR_FIFONOTEMPTY) 42362306a36Sopenharmony_ci csr |= MUSB_TXCSR_FLUSHFIFO; 42462306a36Sopenharmony_ci csr |= MUSB_TXCSR_P_SENDSTALL 42562306a36Sopenharmony_ci | MUSB_TXCSR_CLRDATATOG 42662306a36Sopenharmony_ci | MUSB_TXCSR_P_WZC_BITS; 42762306a36Sopenharmony_ci musb_writew(regs, MUSB_TXCSR, csr); 42862306a36Sopenharmony_ci } else { 42962306a36Sopenharmony_ci csr = musb_readw(regs, MUSB_RXCSR); 43062306a36Sopenharmony_ci csr |= MUSB_RXCSR_P_SENDSTALL 43162306a36Sopenharmony_ci | MUSB_RXCSR_FLUSHFIFO 43262306a36Sopenharmony_ci | MUSB_RXCSR_CLRDATATOG 43362306a36Sopenharmony_ci | MUSB_RXCSR_P_WZC_BITS; 43462306a36Sopenharmony_ci musb_writew(regs, MUSB_RXCSR, csr); 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* select ep0 again */ 43862306a36Sopenharmony_ci musb_ep_select(mbase, 0); 43962306a36Sopenharmony_ci handled = 1; 44062306a36Sopenharmony_ci } break; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci default: 44362306a36Sopenharmony_ci /* class, vendor, etc ... delegate */ 44462306a36Sopenharmony_ci handled = 0; 44562306a36Sopenharmony_ci break; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci break; 44862306a36Sopenharmony_ci default: 44962306a36Sopenharmony_ci /* delegate SET_CONFIGURATION, etc */ 45062306a36Sopenharmony_ci handled = 0; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci } else 45362306a36Sopenharmony_ci handled = 0; 45462306a36Sopenharmony_ci return handled; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci/* we have an ep0out data packet 45862306a36Sopenharmony_ci * Context: caller holds controller lock 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_cistatic void ep0_rxstate(struct musb *musb) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci void __iomem *regs = musb->control_ep->regs; 46362306a36Sopenharmony_ci struct musb_request *request; 46462306a36Sopenharmony_ci struct usb_request *req; 46562306a36Sopenharmony_ci u16 count, csr; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci request = next_ep0_request(musb); 46862306a36Sopenharmony_ci req = &request->request; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* read packet and ack; or stall because of gadget driver bug: 47162306a36Sopenharmony_ci * should have provided the rx buffer before setup() returned. 47262306a36Sopenharmony_ci */ 47362306a36Sopenharmony_ci if (req) { 47462306a36Sopenharmony_ci void *buf = req->buf + req->actual; 47562306a36Sopenharmony_ci unsigned len = req->length - req->actual; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* read the buffer */ 47862306a36Sopenharmony_ci count = musb_readb(regs, MUSB_COUNT0); 47962306a36Sopenharmony_ci if (count > len) { 48062306a36Sopenharmony_ci req->status = -EOVERFLOW; 48162306a36Sopenharmony_ci count = len; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci if (count > 0) { 48462306a36Sopenharmony_ci musb_read_fifo(&musb->endpoints[0], count, buf); 48562306a36Sopenharmony_ci req->actual += count; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci csr = MUSB_CSR0_P_SVDRXPKTRDY; 48862306a36Sopenharmony_ci if (count < 64 || req->actual == req->length) { 48962306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_STATUSIN; 49062306a36Sopenharmony_ci csr |= MUSB_CSR0_P_DATAEND; 49162306a36Sopenharmony_ci } else 49262306a36Sopenharmony_ci req = NULL; 49362306a36Sopenharmony_ci } else 49462306a36Sopenharmony_ci csr = MUSB_CSR0_P_SVDRXPKTRDY | MUSB_CSR0_P_SENDSTALL; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* Completion handler may choose to stall, e.g. because the 49862306a36Sopenharmony_ci * message just received holds invalid data. 49962306a36Sopenharmony_ci */ 50062306a36Sopenharmony_ci if (req) { 50162306a36Sopenharmony_ci musb->ackpend = csr; 50262306a36Sopenharmony_ci musb_g_ep0_giveback(musb, req); 50362306a36Sopenharmony_ci if (!musb->ackpend) 50462306a36Sopenharmony_ci return; 50562306a36Sopenharmony_ci musb->ackpend = 0; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci musb_ep_select(musb->mregs, 0); 50862306a36Sopenharmony_ci musb_writew(regs, MUSB_CSR0, csr); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci/* 51262306a36Sopenharmony_ci * transmitting to the host (IN), this code might be called from IRQ 51362306a36Sopenharmony_ci * and from kernel thread. 51462306a36Sopenharmony_ci * 51562306a36Sopenharmony_ci * Context: caller holds controller lock 51662306a36Sopenharmony_ci */ 51762306a36Sopenharmony_cistatic void ep0_txstate(struct musb *musb) 51862306a36Sopenharmony_ci{ 51962306a36Sopenharmony_ci void __iomem *regs = musb->control_ep->regs; 52062306a36Sopenharmony_ci struct musb_request *req = next_ep0_request(musb); 52162306a36Sopenharmony_ci struct usb_request *request; 52262306a36Sopenharmony_ci u16 csr = MUSB_CSR0_TXPKTRDY; 52362306a36Sopenharmony_ci u8 *fifo_src; 52462306a36Sopenharmony_ci u8 fifo_count; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (!req) { 52762306a36Sopenharmony_ci /* WARN_ON(1); */ 52862306a36Sopenharmony_ci musb_dbg(musb, "odd; csr0 %04x", musb_readw(regs, MUSB_CSR0)); 52962306a36Sopenharmony_ci return; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci request = &req->request; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* load the data */ 53562306a36Sopenharmony_ci fifo_src = (u8 *) request->buf + request->actual; 53662306a36Sopenharmony_ci fifo_count = min((unsigned) MUSB_EP0_FIFOSIZE, 53762306a36Sopenharmony_ci request->length - request->actual); 53862306a36Sopenharmony_ci musb_write_fifo(&musb->endpoints[0], fifo_count, fifo_src); 53962306a36Sopenharmony_ci request->actual += fifo_count; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* update the flags */ 54262306a36Sopenharmony_ci if (fifo_count < MUSB_MAX_END0_PACKET 54362306a36Sopenharmony_ci || (request->actual == request->length 54462306a36Sopenharmony_ci && !request->zero)) { 54562306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT; 54662306a36Sopenharmony_ci csr |= MUSB_CSR0_P_DATAEND; 54762306a36Sopenharmony_ci } else 54862306a36Sopenharmony_ci request = NULL; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* report completions as soon as the fifo's loaded; there's no 55162306a36Sopenharmony_ci * win in waiting till this last packet gets acked. (other than 55262306a36Sopenharmony_ci * very precise fault reporting, needed by USB TMC; possible with 55362306a36Sopenharmony_ci * this hardware, but not usable from portable gadget drivers.) 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci if (request) { 55662306a36Sopenharmony_ci musb->ackpend = csr; 55762306a36Sopenharmony_ci musb_g_ep0_giveback(musb, request); 55862306a36Sopenharmony_ci if (!musb->ackpend) 55962306a36Sopenharmony_ci return; 56062306a36Sopenharmony_ci musb->ackpend = 0; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* send it out, triggering a "txpktrdy cleared" irq */ 56462306a36Sopenharmony_ci musb_ep_select(musb->mregs, 0); 56562306a36Sopenharmony_ci musb_writew(regs, MUSB_CSR0, csr); 56662306a36Sopenharmony_ci} 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci/* 56962306a36Sopenharmony_ci * Read a SETUP packet (struct usb_ctrlrequest) from the hardware. 57062306a36Sopenharmony_ci * Fields are left in USB byte-order. 57162306a36Sopenharmony_ci * 57262306a36Sopenharmony_ci * Context: caller holds controller lock. 57362306a36Sopenharmony_ci */ 57462306a36Sopenharmony_cistatic void 57562306a36Sopenharmony_cimusb_read_setup(struct musb *musb, struct usb_ctrlrequest *req) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci struct musb_request *r; 57862306a36Sopenharmony_ci void __iomem *regs = musb->control_ep->regs; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci musb_read_fifo(&musb->endpoints[0], sizeof *req, (u8 *)req); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* NOTE: earlier 2.6 versions changed setup packets to host 58362306a36Sopenharmony_ci * order, but now USB packets always stay in USB byte order. 58462306a36Sopenharmony_ci */ 58562306a36Sopenharmony_ci musb_dbg(musb, "SETUP req%02x.%02x v%04x i%04x l%d", 58662306a36Sopenharmony_ci req->bRequestType, 58762306a36Sopenharmony_ci req->bRequest, 58862306a36Sopenharmony_ci le16_to_cpu(req->wValue), 58962306a36Sopenharmony_ci le16_to_cpu(req->wIndex), 59062306a36Sopenharmony_ci le16_to_cpu(req->wLength)); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* clean up any leftover transfers */ 59362306a36Sopenharmony_ci r = next_ep0_request(musb); 59462306a36Sopenharmony_ci if (r) 59562306a36Sopenharmony_ci musb_g_ep0_giveback(musb, &r->request); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* For zero-data requests we want to delay the STATUS stage to 59862306a36Sopenharmony_ci * avoid SETUPEND errors. If we read data (OUT), delay accepting 59962306a36Sopenharmony_ci * packets until there's a buffer to store them in. 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci * If we write data, the controller acts happier if we enable 60262306a36Sopenharmony_ci * the TX FIFO right away, and give the controller a moment 60362306a36Sopenharmony_ci * to switch modes... 60462306a36Sopenharmony_ci */ 60562306a36Sopenharmony_ci musb->set_address = false; 60662306a36Sopenharmony_ci musb->ackpend = MUSB_CSR0_P_SVDRXPKTRDY; 60762306a36Sopenharmony_ci if (req->wLength == 0) { 60862306a36Sopenharmony_ci if (req->bRequestType & USB_DIR_IN) 60962306a36Sopenharmony_ci musb->ackpend |= MUSB_CSR0_TXPKTRDY; 61062306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_ACKWAIT; 61162306a36Sopenharmony_ci } else if (req->bRequestType & USB_DIR_IN) { 61262306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_TX; 61362306a36Sopenharmony_ci musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDRXPKTRDY); 61462306a36Sopenharmony_ci while ((musb_readw(regs, MUSB_CSR0) 61562306a36Sopenharmony_ci & MUSB_CSR0_RXPKTRDY) != 0) 61662306a36Sopenharmony_ci cpu_relax(); 61762306a36Sopenharmony_ci musb->ackpend = 0; 61862306a36Sopenharmony_ci } else 61962306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_RX; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic int 62362306a36Sopenharmony_ciforward_to_driver(struct musb *musb, const struct usb_ctrlrequest *ctrlrequest) 62462306a36Sopenharmony_ci__releases(musb->lock) 62562306a36Sopenharmony_ci__acquires(musb->lock) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci int retval; 62862306a36Sopenharmony_ci if (!musb->gadget_driver) 62962306a36Sopenharmony_ci return -EOPNOTSUPP; 63062306a36Sopenharmony_ci spin_unlock(&musb->lock); 63162306a36Sopenharmony_ci retval = musb->gadget_driver->setup(&musb->g, ctrlrequest); 63262306a36Sopenharmony_ci spin_lock(&musb->lock); 63362306a36Sopenharmony_ci return retval; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci/* 63762306a36Sopenharmony_ci * Handle peripheral ep0 interrupt 63862306a36Sopenharmony_ci * 63962306a36Sopenharmony_ci * Context: irq handler; we won't re-enter the driver that way. 64062306a36Sopenharmony_ci */ 64162306a36Sopenharmony_ciirqreturn_t musb_g_ep0_irq(struct musb *musb) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci u16 csr; 64462306a36Sopenharmony_ci u16 len; 64562306a36Sopenharmony_ci void __iomem *mbase = musb->mregs; 64662306a36Sopenharmony_ci void __iomem *regs = musb->endpoints[0].regs; 64762306a36Sopenharmony_ci irqreturn_t retval = IRQ_NONE; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci musb_ep_select(mbase, 0); /* select ep0 */ 65062306a36Sopenharmony_ci csr = musb_readw(regs, MUSB_CSR0); 65162306a36Sopenharmony_ci len = musb_readb(regs, MUSB_COUNT0); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci musb_dbg(musb, "csr %04x, count %d, ep0stage %s", 65462306a36Sopenharmony_ci csr, len, decode_ep0stage(musb->ep0_state)); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (csr & MUSB_CSR0_P_DATAEND) { 65762306a36Sopenharmony_ci /* 65862306a36Sopenharmony_ci * If DATAEND is set we should not call the callback, 65962306a36Sopenharmony_ci * hence the status stage is not complete. 66062306a36Sopenharmony_ci */ 66162306a36Sopenharmony_ci return IRQ_HANDLED; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* I sent a stall.. need to acknowledge it now.. */ 66562306a36Sopenharmony_ci if (csr & MUSB_CSR0_P_SENTSTALL) { 66662306a36Sopenharmony_ci musb_writew(regs, MUSB_CSR0, 66762306a36Sopenharmony_ci csr & ~MUSB_CSR0_P_SENTSTALL); 66862306a36Sopenharmony_ci retval = IRQ_HANDLED; 66962306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_IDLE; 67062306a36Sopenharmony_ci csr = musb_readw(regs, MUSB_CSR0); 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci /* request ended "early" */ 67462306a36Sopenharmony_ci if (csr & MUSB_CSR0_P_SETUPEND) { 67562306a36Sopenharmony_ci musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND); 67662306a36Sopenharmony_ci retval = IRQ_HANDLED; 67762306a36Sopenharmony_ci /* Transition into the early status phase */ 67862306a36Sopenharmony_ci switch (musb->ep0_state) { 67962306a36Sopenharmony_ci case MUSB_EP0_STAGE_TX: 68062306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT; 68162306a36Sopenharmony_ci break; 68262306a36Sopenharmony_ci case MUSB_EP0_STAGE_RX: 68362306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_STATUSIN; 68462306a36Sopenharmony_ci break; 68562306a36Sopenharmony_ci default: 68662306a36Sopenharmony_ci ERR("SetupEnd came in a wrong ep0stage %s\n", 68762306a36Sopenharmony_ci decode_ep0stage(musb->ep0_state)); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci csr = musb_readw(regs, MUSB_CSR0); 69062306a36Sopenharmony_ci /* NOTE: request may need completion */ 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* docs from Mentor only describe tx, rx, and idle/setup states. 69462306a36Sopenharmony_ci * we need to handle nuances around status stages, and also the 69562306a36Sopenharmony_ci * case where status and setup stages come back-to-back ... 69662306a36Sopenharmony_ci */ 69762306a36Sopenharmony_ci switch (musb->ep0_state) { 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci case MUSB_EP0_STAGE_TX: 70062306a36Sopenharmony_ci /* irq on clearing txpktrdy */ 70162306a36Sopenharmony_ci if ((csr & MUSB_CSR0_TXPKTRDY) == 0) { 70262306a36Sopenharmony_ci ep0_txstate(musb); 70362306a36Sopenharmony_ci retval = IRQ_HANDLED; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci break; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci case MUSB_EP0_STAGE_RX: 70862306a36Sopenharmony_ci /* irq on set rxpktrdy */ 70962306a36Sopenharmony_ci if (csr & MUSB_CSR0_RXPKTRDY) { 71062306a36Sopenharmony_ci ep0_rxstate(musb); 71162306a36Sopenharmony_ci retval = IRQ_HANDLED; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci break; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci case MUSB_EP0_STAGE_STATUSIN: 71662306a36Sopenharmony_ci /* end of sequence #2 (OUT/RX state) or #3 (no data) */ 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* update address (if needed) only @ the end of the 71962306a36Sopenharmony_ci * status phase per usb spec, which also guarantees 72062306a36Sopenharmony_ci * we get 10 msec to receive this irq... until this 72162306a36Sopenharmony_ci * is done we won't see the next packet. 72262306a36Sopenharmony_ci */ 72362306a36Sopenharmony_ci if (musb->set_address) { 72462306a36Sopenharmony_ci musb->set_address = false; 72562306a36Sopenharmony_ci musb_writeb(mbase, MUSB_FADDR, musb->address); 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* enter test mode if needed (exit by reset) */ 72962306a36Sopenharmony_ci else if (musb->test_mode) { 73062306a36Sopenharmony_ci musb_dbg(musb, "entering TESTMODE"); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (MUSB_TEST_PACKET == musb->test_mode_nr) 73362306a36Sopenharmony_ci musb_load_testpacket(musb); 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci musb_writeb(mbase, MUSB_TESTMODE, 73662306a36Sopenharmony_ci musb->test_mode_nr); 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci fallthrough; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci case MUSB_EP0_STAGE_STATUSOUT: 74162306a36Sopenharmony_ci /* end of sequence #1: write to host (TX state) */ 74262306a36Sopenharmony_ci { 74362306a36Sopenharmony_ci struct musb_request *req; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci req = next_ep0_request(musb); 74662306a36Sopenharmony_ci if (req) 74762306a36Sopenharmony_ci musb_g_ep0_giveback(musb, &req->request); 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci /* 75162306a36Sopenharmony_ci * In case when several interrupts can get coalesced, 75262306a36Sopenharmony_ci * check to see if we've already received a SETUP packet... 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_ci if (csr & MUSB_CSR0_RXPKTRDY) 75562306a36Sopenharmony_ci goto setup; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci retval = IRQ_HANDLED; 75862306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_IDLE; 75962306a36Sopenharmony_ci break; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci case MUSB_EP0_STAGE_IDLE: 76262306a36Sopenharmony_ci /* 76362306a36Sopenharmony_ci * This state is typically (but not always) indiscernible 76462306a36Sopenharmony_ci * from the status states since the corresponding interrupts 76562306a36Sopenharmony_ci * tend to happen within too little period of time (with only 76662306a36Sopenharmony_ci * a zero-length packet in between) and so get coalesced... 76762306a36Sopenharmony_ci */ 76862306a36Sopenharmony_ci retval = IRQ_HANDLED; 76962306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_SETUP; 77062306a36Sopenharmony_ci fallthrough; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci case MUSB_EP0_STAGE_SETUP: 77362306a36Sopenharmony_cisetup: 77462306a36Sopenharmony_ci if (csr & MUSB_CSR0_RXPKTRDY) { 77562306a36Sopenharmony_ci struct usb_ctrlrequest setup; 77662306a36Sopenharmony_ci int handled = 0; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci if (len != 8) { 77962306a36Sopenharmony_ci ERR("SETUP packet len %d != 8 ?\n", len); 78062306a36Sopenharmony_ci break; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci musb_read_setup(musb, &setup); 78362306a36Sopenharmony_ci retval = IRQ_HANDLED; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci /* sometimes the RESET won't be reported */ 78662306a36Sopenharmony_ci if (unlikely(musb->g.speed == USB_SPEED_UNKNOWN)) { 78762306a36Sopenharmony_ci u8 power; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci printk(KERN_NOTICE "%s: peripheral reset " 79062306a36Sopenharmony_ci "irq lost!\n", 79162306a36Sopenharmony_ci musb_driver_name); 79262306a36Sopenharmony_ci power = musb_readb(mbase, MUSB_POWER); 79362306a36Sopenharmony_ci musb->g.speed = (power & MUSB_POWER_HSMODE) 79462306a36Sopenharmony_ci ? USB_SPEED_HIGH : USB_SPEED_FULL; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci switch (musb->ep0_state) { 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci /* sequence #3 (no data stage), includes requests 80162306a36Sopenharmony_ci * we can't forward (notably SET_ADDRESS and the 80262306a36Sopenharmony_ci * device/endpoint feature set/clear operations) 80362306a36Sopenharmony_ci * plus SET_CONFIGURATION and others we must 80462306a36Sopenharmony_ci */ 80562306a36Sopenharmony_ci case MUSB_EP0_STAGE_ACKWAIT: 80662306a36Sopenharmony_ci handled = service_zero_data_request( 80762306a36Sopenharmony_ci musb, &setup); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci /* 81062306a36Sopenharmony_ci * We're expecting no data in any case, so 81162306a36Sopenharmony_ci * always set the DATAEND bit -- doing this 81262306a36Sopenharmony_ci * here helps avoid SetupEnd interrupt coming 81362306a36Sopenharmony_ci * in the idle stage when we're stalling... 81462306a36Sopenharmony_ci */ 81562306a36Sopenharmony_ci musb->ackpend |= MUSB_CSR0_P_DATAEND; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci /* status stage might be immediate */ 81862306a36Sopenharmony_ci if (handled > 0) 81962306a36Sopenharmony_ci musb->ep0_state = 82062306a36Sopenharmony_ci MUSB_EP0_STAGE_STATUSIN; 82162306a36Sopenharmony_ci break; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci /* sequence #1 (IN to host), includes GET_STATUS 82462306a36Sopenharmony_ci * requests that we can't forward, GET_DESCRIPTOR 82562306a36Sopenharmony_ci * and others that we must 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_ci case MUSB_EP0_STAGE_TX: 82862306a36Sopenharmony_ci handled = service_in_request(musb, &setup); 82962306a36Sopenharmony_ci if (handled > 0) { 83062306a36Sopenharmony_ci musb->ackpend = MUSB_CSR0_TXPKTRDY 83162306a36Sopenharmony_ci | MUSB_CSR0_P_DATAEND; 83262306a36Sopenharmony_ci musb->ep0_state = 83362306a36Sopenharmony_ci MUSB_EP0_STAGE_STATUSOUT; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci break; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci /* sequence #2 (OUT from host), always forward */ 83862306a36Sopenharmony_ci default: /* MUSB_EP0_STAGE_RX */ 83962306a36Sopenharmony_ci break; 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci musb_dbg(musb, "handled %d, csr %04x, ep0stage %s", 84362306a36Sopenharmony_ci handled, csr, 84462306a36Sopenharmony_ci decode_ep0stage(musb->ep0_state)); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci /* unless we need to delegate this to the gadget 84762306a36Sopenharmony_ci * driver, we know how to wrap this up: csr0 has 84862306a36Sopenharmony_ci * not yet been written. 84962306a36Sopenharmony_ci */ 85062306a36Sopenharmony_ci if (handled < 0) 85162306a36Sopenharmony_ci goto stall; 85262306a36Sopenharmony_ci else if (handled > 0) 85362306a36Sopenharmony_ci goto finish; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci handled = forward_to_driver(musb, &setup); 85662306a36Sopenharmony_ci if (handled < 0) { 85762306a36Sopenharmony_ci musb_ep_select(mbase, 0); 85862306a36Sopenharmony_cistall: 85962306a36Sopenharmony_ci musb_dbg(musb, "stall (%d)", handled); 86062306a36Sopenharmony_ci musb->ackpend |= MUSB_CSR0_P_SENDSTALL; 86162306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_IDLE; 86262306a36Sopenharmony_cifinish: 86362306a36Sopenharmony_ci musb_writew(regs, MUSB_CSR0, 86462306a36Sopenharmony_ci musb->ackpend); 86562306a36Sopenharmony_ci musb->ackpend = 0; 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci break; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci case MUSB_EP0_STAGE_ACKWAIT: 87162306a36Sopenharmony_ci /* This should not happen. But happens with tusb6010 with 87262306a36Sopenharmony_ci * g_file_storage and high speed. Do nothing. 87362306a36Sopenharmony_ci */ 87462306a36Sopenharmony_ci retval = IRQ_HANDLED; 87562306a36Sopenharmony_ci break; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci default: 87862306a36Sopenharmony_ci /* "can't happen" */ 87962306a36Sopenharmony_ci WARN_ON(1); 88062306a36Sopenharmony_ci musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL); 88162306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_IDLE; 88262306a36Sopenharmony_ci break; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci return retval; 88662306a36Sopenharmony_ci} 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_cistatic int 89062306a36Sopenharmony_cimusb_g_ep0_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci /* always enabled */ 89362306a36Sopenharmony_ci return -EINVAL; 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cistatic int musb_g_ep0_disable(struct usb_ep *e) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci /* always enabled */ 89962306a36Sopenharmony_ci return -EINVAL; 90062306a36Sopenharmony_ci} 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_cistatic int 90362306a36Sopenharmony_cimusb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci struct musb_ep *ep; 90662306a36Sopenharmony_ci struct musb_request *req; 90762306a36Sopenharmony_ci struct musb *musb; 90862306a36Sopenharmony_ci int status; 90962306a36Sopenharmony_ci unsigned long lockflags; 91062306a36Sopenharmony_ci void __iomem *regs; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (!e || !r) 91362306a36Sopenharmony_ci return -EINVAL; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci ep = to_musb_ep(e); 91662306a36Sopenharmony_ci musb = ep->musb; 91762306a36Sopenharmony_ci regs = musb->control_ep->regs; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci req = to_musb_request(r); 92062306a36Sopenharmony_ci req->musb = musb; 92162306a36Sopenharmony_ci req->request.actual = 0; 92262306a36Sopenharmony_ci req->request.status = -EINPROGRESS; 92362306a36Sopenharmony_ci req->tx = ep->is_in; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci spin_lock_irqsave(&musb->lock, lockflags); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if (!list_empty(&ep->req_list)) { 92862306a36Sopenharmony_ci status = -EBUSY; 92962306a36Sopenharmony_ci goto cleanup; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci switch (musb->ep0_state) { 93362306a36Sopenharmony_ci case MUSB_EP0_STAGE_RX: /* control-OUT data */ 93462306a36Sopenharmony_ci case MUSB_EP0_STAGE_TX: /* control-IN data */ 93562306a36Sopenharmony_ci case MUSB_EP0_STAGE_ACKWAIT: /* zero-length data */ 93662306a36Sopenharmony_ci status = 0; 93762306a36Sopenharmony_ci break; 93862306a36Sopenharmony_ci default: 93962306a36Sopenharmony_ci musb_dbg(musb, "ep0 request queued in state %d", 94062306a36Sopenharmony_ci musb->ep0_state); 94162306a36Sopenharmony_ci status = -EINVAL; 94262306a36Sopenharmony_ci goto cleanup; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* add request to the list */ 94662306a36Sopenharmony_ci list_add_tail(&req->list, &ep->req_list); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci musb_dbg(musb, "queue to %s (%s), length=%d", 94962306a36Sopenharmony_ci ep->name, ep->is_in ? "IN/TX" : "OUT/RX", 95062306a36Sopenharmony_ci req->request.length); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci musb_ep_select(musb->mregs, 0); 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci /* sequence #1, IN ... start writing the data */ 95562306a36Sopenharmony_ci if (musb->ep0_state == MUSB_EP0_STAGE_TX) 95662306a36Sopenharmony_ci ep0_txstate(musb); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /* sequence #3, no-data ... issue IN status */ 95962306a36Sopenharmony_ci else if (musb->ep0_state == MUSB_EP0_STAGE_ACKWAIT) { 96062306a36Sopenharmony_ci if (req->request.length) 96162306a36Sopenharmony_ci status = -EINVAL; 96262306a36Sopenharmony_ci else { 96362306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_STATUSIN; 96462306a36Sopenharmony_ci musb_writew(regs, MUSB_CSR0, 96562306a36Sopenharmony_ci musb->ackpend | MUSB_CSR0_P_DATAEND); 96662306a36Sopenharmony_ci musb->ackpend = 0; 96762306a36Sopenharmony_ci musb_g_ep0_giveback(ep->musb, r); 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* else for sequence #2 (OUT), caller provides a buffer 97162306a36Sopenharmony_ci * before the next packet arrives. deferred responses 97262306a36Sopenharmony_ci * (after SETUP is acked) are racey. 97362306a36Sopenharmony_ci */ 97462306a36Sopenharmony_ci } else if (musb->ackpend) { 97562306a36Sopenharmony_ci musb_writew(regs, MUSB_CSR0, musb->ackpend); 97662306a36Sopenharmony_ci musb->ackpend = 0; 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cicleanup: 98062306a36Sopenharmony_ci spin_unlock_irqrestore(&musb->lock, lockflags); 98162306a36Sopenharmony_ci return status; 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_cistatic int musb_g_ep0_dequeue(struct usb_ep *ep, struct usb_request *req) 98562306a36Sopenharmony_ci{ 98662306a36Sopenharmony_ci /* we just won't support this */ 98762306a36Sopenharmony_ci return -EINVAL; 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic int musb_g_ep0_halt(struct usb_ep *e, int value) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci struct musb_ep *ep; 99362306a36Sopenharmony_ci struct musb *musb; 99462306a36Sopenharmony_ci void __iomem *base, *regs; 99562306a36Sopenharmony_ci unsigned long flags; 99662306a36Sopenharmony_ci int status; 99762306a36Sopenharmony_ci u16 csr; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci if (!e || !value) 100062306a36Sopenharmony_ci return -EINVAL; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci ep = to_musb_ep(e); 100362306a36Sopenharmony_ci musb = ep->musb; 100462306a36Sopenharmony_ci base = musb->mregs; 100562306a36Sopenharmony_ci regs = musb->control_ep->regs; 100662306a36Sopenharmony_ci status = 0; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci spin_lock_irqsave(&musb->lock, flags); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci if (!list_empty(&ep->req_list)) { 101162306a36Sopenharmony_ci status = -EBUSY; 101262306a36Sopenharmony_ci goto cleanup; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci musb_ep_select(base, 0); 101662306a36Sopenharmony_ci csr = musb->ackpend; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci switch (musb->ep0_state) { 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci /* Stalls are usually issued after parsing SETUP packet, either 102162306a36Sopenharmony_ci * directly in irq context from setup() or else later. 102262306a36Sopenharmony_ci */ 102362306a36Sopenharmony_ci case MUSB_EP0_STAGE_TX: /* control-IN data */ 102462306a36Sopenharmony_ci case MUSB_EP0_STAGE_ACKWAIT: /* STALL for zero-length data */ 102562306a36Sopenharmony_ci case MUSB_EP0_STAGE_RX: /* control-OUT data */ 102662306a36Sopenharmony_ci csr = musb_readw(regs, MUSB_CSR0); 102762306a36Sopenharmony_ci fallthrough; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci /* It's also OK to issue stalls during callbacks when a non-empty 103062306a36Sopenharmony_ci * DATA stage buffer has been read (or even written). 103162306a36Sopenharmony_ci */ 103262306a36Sopenharmony_ci case MUSB_EP0_STAGE_STATUSIN: /* control-OUT status */ 103362306a36Sopenharmony_ci case MUSB_EP0_STAGE_STATUSOUT: /* control-IN status */ 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci csr |= MUSB_CSR0_P_SENDSTALL; 103662306a36Sopenharmony_ci musb_writew(regs, MUSB_CSR0, csr); 103762306a36Sopenharmony_ci musb->ep0_state = MUSB_EP0_STAGE_IDLE; 103862306a36Sopenharmony_ci musb->ackpend = 0; 103962306a36Sopenharmony_ci break; 104062306a36Sopenharmony_ci default: 104162306a36Sopenharmony_ci musb_dbg(musb, "ep0 can't halt in state %d", musb->ep0_state); 104262306a36Sopenharmony_ci status = -EINVAL; 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_cicleanup: 104662306a36Sopenharmony_ci spin_unlock_irqrestore(&musb->lock, flags); 104762306a36Sopenharmony_ci return status; 104862306a36Sopenharmony_ci} 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ciconst struct usb_ep_ops musb_g_ep0_ops = { 105162306a36Sopenharmony_ci .enable = musb_g_ep0_enable, 105262306a36Sopenharmony_ci .disable = musb_g_ep0_disable, 105362306a36Sopenharmony_ci .alloc_request = musb_alloc_request, 105462306a36Sopenharmony_ci .free_request = musb_free_request, 105562306a36Sopenharmony_ci .queue = musb_g_ep0_queue, 105662306a36Sopenharmony_ci .dequeue = musb_g_ep0_dequeue, 105762306a36Sopenharmony_ci .set_halt = musb_g_ep0_halt, 105862306a36Sopenharmony_ci}; 1059