1*df2069acSChunfeng Yun /* 2*df2069acSChunfeng Yun * mtu3_gadget_ep0.c - MediaTek USB3 DRD peripheral driver ep0 handling 3*df2069acSChunfeng Yun * 4*df2069acSChunfeng Yun * Copyright (c) 2016 MediaTek Inc. 5*df2069acSChunfeng Yun * 6*df2069acSChunfeng Yun * Author: Chunfeng.Yun <chunfeng.yun@mediatek.com> 7*df2069acSChunfeng Yun * 8*df2069acSChunfeng Yun * This software is licensed under the terms of the GNU General Public 9*df2069acSChunfeng Yun * License version 2, as published by the Free Software Foundation, and 10*df2069acSChunfeng Yun * may be copied, distributed, and modified under those terms. 11*df2069acSChunfeng Yun * 12*df2069acSChunfeng Yun * This program is distributed in the hope that it will be useful, 13*df2069acSChunfeng Yun * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*df2069acSChunfeng Yun * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*df2069acSChunfeng Yun * GNU General Public License for more details. 16*df2069acSChunfeng Yun * 17*df2069acSChunfeng Yun */ 18*df2069acSChunfeng Yun 19*df2069acSChunfeng Yun #include "mtu3.h" 20*df2069acSChunfeng Yun 21*df2069acSChunfeng Yun /* ep0 is always mtu3->in_eps[0] */ 22*df2069acSChunfeng Yun #define next_ep0_request(mtu) next_request((mtu)->ep0) 23*df2069acSChunfeng Yun 24*df2069acSChunfeng Yun /* for high speed test mode; see USB 2.0 spec 7.1.20 */ 25*df2069acSChunfeng Yun static const u8 mtu3_test_packet[53] = { 26*df2069acSChunfeng Yun /* implicit SYNC then DATA0 to start */ 27*df2069acSChunfeng Yun 28*df2069acSChunfeng Yun /* JKJKJKJK x9 */ 29*df2069acSChunfeng Yun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30*df2069acSChunfeng Yun /* JJKKJJKK x8 */ 31*df2069acSChunfeng Yun 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 32*df2069acSChunfeng Yun /* JJJJKKKK x8 */ 33*df2069acSChunfeng Yun 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 34*df2069acSChunfeng Yun /* JJJJJJJKKKKKKK x8 */ 35*df2069acSChunfeng Yun 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 36*df2069acSChunfeng Yun /* JJJJJJJK x8 */ 37*df2069acSChunfeng Yun 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 38*df2069acSChunfeng Yun /* JKKKKKKK x10, JK */ 39*df2069acSChunfeng Yun 0xfc, 0x7e, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0x7e, 40*df2069acSChunfeng Yun /* implicit CRC16 then EOP to end */ 41*df2069acSChunfeng Yun }; 42*df2069acSChunfeng Yun 43*df2069acSChunfeng Yun static char *decode_ep0_state(struct mtu3 *mtu) 44*df2069acSChunfeng Yun { 45*df2069acSChunfeng Yun switch (mtu->ep0_state) { 46*df2069acSChunfeng Yun case MU3D_EP0_STATE_SETUP: 47*df2069acSChunfeng Yun return "SETUP"; 48*df2069acSChunfeng Yun case MU3D_EP0_STATE_TX: 49*df2069acSChunfeng Yun return "IN"; 50*df2069acSChunfeng Yun case MU3D_EP0_STATE_RX: 51*df2069acSChunfeng Yun return "OUT"; 52*df2069acSChunfeng Yun case MU3D_EP0_STATE_TX_END: 53*df2069acSChunfeng Yun return "TX-END"; 54*df2069acSChunfeng Yun case MU3D_EP0_STATE_STALL: 55*df2069acSChunfeng Yun return "STALL"; 56*df2069acSChunfeng Yun default: 57*df2069acSChunfeng Yun return "??"; 58*df2069acSChunfeng Yun } 59*df2069acSChunfeng Yun } 60*df2069acSChunfeng Yun 61*df2069acSChunfeng Yun static void ep0_req_giveback(struct mtu3 *mtu, struct usb_request *req) 62*df2069acSChunfeng Yun { 63*df2069acSChunfeng Yun mtu3_req_complete(mtu->ep0, req, 0); 64*df2069acSChunfeng Yun } 65*df2069acSChunfeng Yun 66*df2069acSChunfeng Yun static int 67*df2069acSChunfeng Yun forward_to_driver(struct mtu3 *mtu, const struct usb_ctrlrequest *setup) 68*df2069acSChunfeng Yun __releases(mtu->lock) 69*df2069acSChunfeng Yun __acquires(mtu->lock) 70*df2069acSChunfeng Yun { 71*df2069acSChunfeng Yun int ret; 72*df2069acSChunfeng Yun 73*df2069acSChunfeng Yun if (!mtu->gadget_driver) 74*df2069acSChunfeng Yun return -EOPNOTSUPP; 75*df2069acSChunfeng Yun 76*df2069acSChunfeng Yun spin_unlock(&mtu->lock); 77*df2069acSChunfeng Yun ret = mtu->gadget_driver->setup(&mtu->g, setup); 78*df2069acSChunfeng Yun spin_lock(&mtu->lock); 79*df2069acSChunfeng Yun 80*df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s ret %d\n", __func__, ret); 81*df2069acSChunfeng Yun return ret; 82*df2069acSChunfeng Yun } 83*df2069acSChunfeng Yun 84*df2069acSChunfeng Yun static void ep0_write_fifo(struct mtu3_ep *mep, const u8 *src, u16 len) 85*df2069acSChunfeng Yun { 86*df2069acSChunfeng Yun void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0; 87*df2069acSChunfeng Yun u16 index = 0; 88*df2069acSChunfeng Yun 89*df2069acSChunfeng Yun dev_dbg(mep->mtu->dev, "%s: ep%din, len=%d, buf=%p\n", 90*df2069acSChunfeng Yun __func__, mep->epnum, len, src); 91*df2069acSChunfeng Yun 92*df2069acSChunfeng Yun if (len >= 4) { 93*df2069acSChunfeng Yun iowrite32_rep(fifo, src, len >> 2); 94*df2069acSChunfeng Yun index = len & ~0x03; 95*df2069acSChunfeng Yun } 96*df2069acSChunfeng Yun if (len & 0x02) { 97*df2069acSChunfeng Yun writew(*(u16 *)&src[index], fifo); 98*df2069acSChunfeng Yun index += 2; 99*df2069acSChunfeng Yun } 100*df2069acSChunfeng Yun if (len & 0x01) 101*df2069acSChunfeng Yun writeb(src[index], fifo); 102*df2069acSChunfeng Yun } 103*df2069acSChunfeng Yun 104*df2069acSChunfeng Yun static void ep0_read_fifo(struct mtu3_ep *mep, u8 *dst, u16 len) 105*df2069acSChunfeng Yun { 106*df2069acSChunfeng Yun void __iomem *fifo = mep->mtu->mac_base + U3D_FIFO0; 107*df2069acSChunfeng Yun u32 value; 108*df2069acSChunfeng Yun u16 index = 0; 109*df2069acSChunfeng Yun 110*df2069acSChunfeng Yun dev_dbg(mep->mtu->dev, "%s: ep%dout len=%d buf=%p\n", 111*df2069acSChunfeng Yun __func__, mep->epnum, len, dst); 112*df2069acSChunfeng Yun 113*df2069acSChunfeng Yun if (len >= 4) { 114*df2069acSChunfeng Yun ioread32_rep(fifo, dst, len >> 2); 115*df2069acSChunfeng Yun index = len & ~0x03; 116*df2069acSChunfeng Yun } 117*df2069acSChunfeng Yun if (len & 0x3) { 118*df2069acSChunfeng Yun value = readl(fifo); 119*df2069acSChunfeng Yun memcpy(&dst[index], &value, len & 0x3); 120*df2069acSChunfeng Yun } 121*df2069acSChunfeng Yun 122*df2069acSChunfeng Yun } 123*df2069acSChunfeng Yun 124*df2069acSChunfeng Yun static void ep0_load_test_packet(struct mtu3 *mtu) 125*df2069acSChunfeng Yun { 126*df2069acSChunfeng Yun /* 127*df2069acSChunfeng Yun * because the length of test packet is less than max packet of HS ep0, 128*df2069acSChunfeng Yun * write it into fifo directly. 129*df2069acSChunfeng Yun */ 130*df2069acSChunfeng Yun ep0_write_fifo(mtu->ep0, mtu3_test_packet, sizeof(mtu3_test_packet)); 131*df2069acSChunfeng Yun } 132*df2069acSChunfeng Yun 133*df2069acSChunfeng Yun /* 134*df2069acSChunfeng Yun * A. send STALL for setup transfer without data stage: 135*df2069acSChunfeng Yun * set SENDSTALL and SETUPPKTRDY at the same time; 136*df2069acSChunfeng Yun * B. send STALL for other cases: 137*df2069acSChunfeng Yun * set SENDSTALL only. 138*df2069acSChunfeng Yun */ 139*df2069acSChunfeng Yun static void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy) 140*df2069acSChunfeng Yun { 141*df2069acSChunfeng Yun struct mtu3 *mtu = mep0->mtu; 142*df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 143*df2069acSChunfeng Yun u32 csr; 144*df2069acSChunfeng Yun 145*df2069acSChunfeng Yun /* EP0_SENTSTALL is W1C */ 146*df2069acSChunfeng Yun csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS; 147*df2069acSChunfeng Yun if (set) 148*df2069acSChunfeng Yun csr |= EP0_SENDSTALL | pktrdy; 149*df2069acSChunfeng Yun else 150*df2069acSChunfeng Yun csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL; 151*df2069acSChunfeng Yun mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr); 152*df2069acSChunfeng Yun 153*df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_SETUP; 154*df2069acSChunfeng Yun 155*df2069acSChunfeng Yun dev_dbg(mtu->dev, "ep0: %s STALL, ep0_state: %s\n", 156*df2069acSChunfeng Yun set ? "SEND" : "CLEAR", decode_ep0_state(mtu)); 157*df2069acSChunfeng Yun } 158*df2069acSChunfeng Yun 159*df2069acSChunfeng Yun static int ep0_queue(struct mtu3_ep *mep0, struct mtu3_request *mreq); 160*df2069acSChunfeng Yun 161*df2069acSChunfeng Yun static void ep0_dummy_complete(struct usb_ep *ep, struct usb_request *req) 162*df2069acSChunfeng Yun {} 163*df2069acSChunfeng Yun 164*df2069acSChunfeng Yun static int 165*df2069acSChunfeng Yun ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup) 166*df2069acSChunfeng Yun { 167*df2069acSChunfeng Yun struct mtu3_ep *mep = NULL; 168*df2069acSChunfeng Yun int handled = 1; 169*df2069acSChunfeng Yun u8 result[2] = {0, 0}; 170*df2069acSChunfeng Yun u8 epnum = 0; 171*df2069acSChunfeng Yun int is_in; 172*df2069acSChunfeng Yun 173*df2069acSChunfeng Yun switch (setup->bRequestType & USB_RECIP_MASK) { 174*df2069acSChunfeng Yun case USB_RECIP_DEVICE: 175*df2069acSChunfeng Yun result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED; 176*df2069acSChunfeng Yun result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP; 177*df2069acSChunfeng Yun break; 178*df2069acSChunfeng Yun case USB_RECIP_INTERFACE: 179*df2069acSChunfeng Yun break; 180*df2069acSChunfeng Yun case USB_RECIP_ENDPOINT: 181*df2069acSChunfeng Yun epnum = (u8) le16_to_cpu(setup->wIndex); 182*df2069acSChunfeng Yun is_in = epnum & USB_DIR_IN; 183*df2069acSChunfeng Yun epnum &= USB_ENDPOINT_NUMBER_MASK; 184*df2069acSChunfeng Yun 185*df2069acSChunfeng Yun if (epnum >= mtu->num_eps) { 186*df2069acSChunfeng Yun handled = -EINVAL; 187*df2069acSChunfeng Yun break; 188*df2069acSChunfeng Yun } 189*df2069acSChunfeng Yun if (!epnum) 190*df2069acSChunfeng Yun break; 191*df2069acSChunfeng Yun 192*df2069acSChunfeng Yun mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum; 193*df2069acSChunfeng Yun if (!mep->desc) { 194*df2069acSChunfeng Yun handled = -EINVAL; 195*df2069acSChunfeng Yun break; 196*df2069acSChunfeng Yun } 197*df2069acSChunfeng Yun if (mep->flags & MTU3_EP_STALL) 198*df2069acSChunfeng Yun result[0] |= 1 << USB_ENDPOINT_HALT; 199*df2069acSChunfeng Yun 200*df2069acSChunfeng Yun break; 201*df2069acSChunfeng Yun default: 202*df2069acSChunfeng Yun /* class, vendor, etc ... delegate */ 203*df2069acSChunfeng Yun handled = 0; 204*df2069acSChunfeng Yun break; 205*df2069acSChunfeng Yun } 206*df2069acSChunfeng Yun 207*df2069acSChunfeng Yun if (handled > 0) { 208*df2069acSChunfeng Yun int ret; 209*df2069acSChunfeng Yun 210*df2069acSChunfeng Yun /* prepare a data stage for GET_STATUS */ 211*df2069acSChunfeng Yun dev_dbg(mtu->dev, "get_status=%x\n", *(u16 *)result); 212*df2069acSChunfeng Yun memcpy(mtu->setup_buf, result, sizeof(result)); 213*df2069acSChunfeng Yun mtu->ep0_req.mep = mtu->ep0; 214*df2069acSChunfeng Yun mtu->ep0_req.request.length = 2; 215*df2069acSChunfeng Yun mtu->ep0_req.request.buf = &mtu->setup_buf; 216*df2069acSChunfeng Yun mtu->ep0_req.request.complete = ep0_dummy_complete; 217*df2069acSChunfeng Yun ret = ep0_queue(mtu->ep0, &mtu->ep0_req); 218*df2069acSChunfeng Yun if (ret < 0) 219*df2069acSChunfeng Yun handled = ret; 220*df2069acSChunfeng Yun } 221*df2069acSChunfeng Yun return handled; 222*df2069acSChunfeng Yun } 223*df2069acSChunfeng Yun 224*df2069acSChunfeng Yun static int handle_test_mode(struct mtu3 *mtu, struct usb_ctrlrequest *setup) 225*df2069acSChunfeng Yun { 226*df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 227*df2069acSChunfeng Yun int handled = 1; 228*df2069acSChunfeng Yun 229*df2069acSChunfeng Yun switch (le16_to_cpu(setup->wIndex) >> 8) { 230*df2069acSChunfeng Yun case TEST_J: 231*df2069acSChunfeng Yun dev_dbg(mtu->dev, "TEST_J\n"); 232*df2069acSChunfeng Yun mtu->test_mode_nr = TEST_J_MODE; 233*df2069acSChunfeng Yun break; 234*df2069acSChunfeng Yun case TEST_K: 235*df2069acSChunfeng Yun dev_dbg(mtu->dev, "TEST_K\n"); 236*df2069acSChunfeng Yun mtu->test_mode_nr = TEST_K_MODE; 237*df2069acSChunfeng Yun break; 238*df2069acSChunfeng Yun case TEST_SE0_NAK: 239*df2069acSChunfeng Yun dev_dbg(mtu->dev, "TEST_SE0_NAK\n"); 240*df2069acSChunfeng Yun mtu->test_mode_nr = TEST_SE0_NAK_MODE; 241*df2069acSChunfeng Yun break; 242*df2069acSChunfeng Yun case TEST_PACKET: 243*df2069acSChunfeng Yun dev_dbg(mtu->dev, "TEST_PACKET\n"); 244*df2069acSChunfeng Yun mtu->test_mode_nr = TEST_PACKET_MODE; 245*df2069acSChunfeng Yun break; 246*df2069acSChunfeng Yun default: 247*df2069acSChunfeng Yun handled = -EINVAL; 248*df2069acSChunfeng Yun goto out; 249*df2069acSChunfeng Yun } 250*df2069acSChunfeng Yun 251*df2069acSChunfeng Yun mtu->test_mode = true; 252*df2069acSChunfeng Yun 253*df2069acSChunfeng Yun /* no TX completion interrupt, and need restart platform after test */ 254*df2069acSChunfeng Yun if (mtu->test_mode_nr == TEST_PACKET_MODE) 255*df2069acSChunfeng Yun ep0_load_test_packet(mtu); 256*df2069acSChunfeng Yun 257*df2069acSChunfeng Yun mtu3_writel(mbase, U3D_USB2_TEST_MODE, mtu->test_mode_nr); 258*df2069acSChunfeng Yun 259*df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_SETUP; 260*df2069acSChunfeng Yun 261*df2069acSChunfeng Yun out: 262*df2069acSChunfeng Yun return handled; 263*df2069acSChunfeng Yun } 264*df2069acSChunfeng Yun 265*df2069acSChunfeng Yun static int ep0_handle_feature_dev(struct mtu3 *mtu, 266*df2069acSChunfeng Yun struct usb_ctrlrequest *setup, bool set) 267*df2069acSChunfeng Yun { 268*df2069acSChunfeng Yun int handled = -EINVAL; 269*df2069acSChunfeng Yun 270*df2069acSChunfeng Yun switch (le16_to_cpu(setup->wValue)) { 271*df2069acSChunfeng Yun case USB_DEVICE_REMOTE_WAKEUP: 272*df2069acSChunfeng Yun mtu->may_wakeup = !!set; 273*df2069acSChunfeng Yun handled = 1; 274*df2069acSChunfeng Yun break; 275*df2069acSChunfeng Yun case USB_DEVICE_TEST_MODE: 276*df2069acSChunfeng Yun if (!set || (mtu->g.speed != USB_SPEED_HIGH) || 277*df2069acSChunfeng Yun (le16_to_cpu(setup->wIndex) & 0xff)) 278*df2069acSChunfeng Yun break; 279*df2069acSChunfeng Yun 280*df2069acSChunfeng Yun handled = handle_test_mode(mtu, setup); 281*df2069acSChunfeng Yun break; 282*df2069acSChunfeng Yun default: 283*df2069acSChunfeng Yun handled = -EINVAL; 284*df2069acSChunfeng Yun break; 285*df2069acSChunfeng Yun } 286*df2069acSChunfeng Yun return handled; 287*df2069acSChunfeng Yun } 288*df2069acSChunfeng Yun 289*df2069acSChunfeng Yun static int ep0_handle_feature(struct mtu3 *mtu, 290*df2069acSChunfeng Yun struct usb_ctrlrequest *setup, bool set) 291*df2069acSChunfeng Yun { 292*df2069acSChunfeng Yun struct mtu3_ep *mep; 293*df2069acSChunfeng Yun int handled = -EINVAL; 294*df2069acSChunfeng Yun int is_in; 295*df2069acSChunfeng Yun u16 value; 296*df2069acSChunfeng Yun u16 index; 297*df2069acSChunfeng Yun u8 epnum; 298*df2069acSChunfeng Yun 299*df2069acSChunfeng Yun value = le16_to_cpu(setup->wValue); 300*df2069acSChunfeng Yun index = le16_to_cpu(setup->wIndex); 301*df2069acSChunfeng Yun 302*df2069acSChunfeng Yun switch (setup->bRequestType & USB_RECIP_MASK) { 303*df2069acSChunfeng Yun case USB_RECIP_DEVICE: 304*df2069acSChunfeng Yun handled = ep0_handle_feature_dev(mtu, setup, set); 305*df2069acSChunfeng Yun break; 306*df2069acSChunfeng Yun case USB_RECIP_ENDPOINT: 307*df2069acSChunfeng Yun epnum = index & USB_ENDPOINT_NUMBER_MASK; 308*df2069acSChunfeng Yun if (epnum == 0 || epnum >= mtu->num_eps || 309*df2069acSChunfeng Yun value != USB_ENDPOINT_HALT) 310*df2069acSChunfeng Yun break; 311*df2069acSChunfeng Yun 312*df2069acSChunfeng Yun is_in = index & USB_DIR_IN; 313*df2069acSChunfeng Yun mep = (is_in ? mtu->in_eps : mtu->out_eps) + epnum; 314*df2069acSChunfeng Yun if (!mep->desc) 315*df2069acSChunfeng Yun break; 316*df2069acSChunfeng Yun 317*df2069acSChunfeng Yun handled = 1; 318*df2069acSChunfeng Yun /* ignore request if endpoint is wedged */ 319*df2069acSChunfeng Yun if (mep->wedged) 320*df2069acSChunfeng Yun break; 321*df2069acSChunfeng Yun 322*df2069acSChunfeng Yun mtu3_ep_stall_set(mep, set); 323*df2069acSChunfeng Yun break; 324*df2069acSChunfeng Yun default: 325*df2069acSChunfeng Yun /* class, vendor, etc ... delegate */ 326*df2069acSChunfeng Yun handled = 0; 327*df2069acSChunfeng Yun break; 328*df2069acSChunfeng Yun } 329*df2069acSChunfeng Yun return handled; 330*df2069acSChunfeng Yun } 331*df2069acSChunfeng Yun 332*df2069acSChunfeng Yun /* 333*df2069acSChunfeng Yun * handle all control requests can be handled 334*df2069acSChunfeng Yun * returns: 335*df2069acSChunfeng Yun * negative errno - error happened 336*df2069acSChunfeng Yun * zero - need delegate SETUP to gadget driver 337*df2069acSChunfeng Yun * positive - already handled 338*df2069acSChunfeng Yun */ 339*df2069acSChunfeng Yun static int handle_standard_request(struct mtu3 *mtu, 340*df2069acSChunfeng Yun struct usb_ctrlrequest *setup) 341*df2069acSChunfeng Yun { 342*df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 343*df2069acSChunfeng Yun enum usb_device_state state = mtu->g.state; 344*df2069acSChunfeng Yun int handled = -EINVAL; 345*df2069acSChunfeng Yun u32 dev_conf; 346*df2069acSChunfeng Yun u16 value; 347*df2069acSChunfeng Yun 348*df2069acSChunfeng Yun value = le16_to_cpu(setup->wValue); 349*df2069acSChunfeng Yun 350*df2069acSChunfeng Yun /* the gadget driver handles everything except what we must handle */ 351*df2069acSChunfeng Yun switch (setup->bRequest) { 352*df2069acSChunfeng Yun case USB_REQ_SET_ADDRESS: 353*df2069acSChunfeng Yun /* change it after the status stage */ 354*df2069acSChunfeng Yun mtu->address = (u8) (value & 0x7f); 355*df2069acSChunfeng Yun dev_dbg(mtu->dev, "set address to 0x%x\n", mtu->address); 356*df2069acSChunfeng Yun 357*df2069acSChunfeng Yun dev_conf = mtu3_readl(mbase, U3D_DEVICE_CONF); 358*df2069acSChunfeng Yun dev_conf &= ~DEV_ADDR_MSK; 359*df2069acSChunfeng Yun dev_conf |= DEV_ADDR(mtu->address); 360*df2069acSChunfeng Yun mtu3_writel(mbase, U3D_DEVICE_CONF, dev_conf); 361*df2069acSChunfeng Yun 362*df2069acSChunfeng Yun if (mtu->address) 363*df2069acSChunfeng Yun usb_gadget_set_state(&mtu->g, USB_STATE_ADDRESS); 364*df2069acSChunfeng Yun else 365*df2069acSChunfeng Yun usb_gadget_set_state(&mtu->g, USB_STATE_DEFAULT); 366*df2069acSChunfeng Yun 367*df2069acSChunfeng Yun handled = 1; 368*df2069acSChunfeng Yun break; 369*df2069acSChunfeng Yun case USB_REQ_SET_CONFIGURATION: 370*df2069acSChunfeng Yun if (state == USB_STATE_ADDRESS) { 371*df2069acSChunfeng Yun usb_gadget_set_state(&mtu->g, 372*df2069acSChunfeng Yun USB_STATE_CONFIGURED); 373*df2069acSChunfeng Yun } else if (state == USB_STATE_CONFIGURED) { 374*df2069acSChunfeng Yun /* 375*df2069acSChunfeng Yun * USB2 spec sec 9.4.7, if wValue is 0 then dev 376*df2069acSChunfeng Yun * is moved to addressed state 377*df2069acSChunfeng Yun */ 378*df2069acSChunfeng Yun if (!value) 379*df2069acSChunfeng Yun usb_gadget_set_state(&mtu->g, 380*df2069acSChunfeng Yun USB_STATE_ADDRESS); 381*df2069acSChunfeng Yun } 382*df2069acSChunfeng Yun handled = 0; 383*df2069acSChunfeng Yun break; 384*df2069acSChunfeng Yun case USB_REQ_CLEAR_FEATURE: 385*df2069acSChunfeng Yun handled = ep0_handle_feature(mtu, setup, 0); 386*df2069acSChunfeng Yun break; 387*df2069acSChunfeng Yun case USB_REQ_SET_FEATURE: 388*df2069acSChunfeng Yun handled = ep0_handle_feature(mtu, setup, 1); 389*df2069acSChunfeng Yun break; 390*df2069acSChunfeng Yun case USB_REQ_GET_STATUS: 391*df2069acSChunfeng Yun handled = ep0_get_status(mtu, setup); 392*df2069acSChunfeng Yun break; 393*df2069acSChunfeng Yun case USB_REQ_SET_ISOCH_DELAY: 394*df2069acSChunfeng Yun handled = 1; 395*df2069acSChunfeng Yun break; 396*df2069acSChunfeng Yun default: 397*df2069acSChunfeng Yun /* delegate SET_CONFIGURATION, etc */ 398*df2069acSChunfeng Yun handled = 0; 399*df2069acSChunfeng Yun } 400*df2069acSChunfeng Yun 401*df2069acSChunfeng Yun return handled; 402*df2069acSChunfeng Yun } 403*df2069acSChunfeng Yun 404*df2069acSChunfeng Yun /* receive an data packet (OUT) */ 405*df2069acSChunfeng Yun static void ep0_rx_state(struct mtu3 *mtu) 406*df2069acSChunfeng Yun { 407*df2069acSChunfeng Yun struct mtu3_request *mreq; 408*df2069acSChunfeng Yun struct usb_request *req; 409*df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 410*df2069acSChunfeng Yun u32 maxp; 411*df2069acSChunfeng Yun u32 csr; 412*df2069acSChunfeng Yun u16 count = 0; 413*df2069acSChunfeng Yun 414*df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s\n", __func__); 415*df2069acSChunfeng Yun 416*df2069acSChunfeng Yun csr = mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS; 417*df2069acSChunfeng Yun mreq = next_ep0_request(mtu); 418*df2069acSChunfeng Yun req = &mreq->request; 419*df2069acSChunfeng Yun 420*df2069acSChunfeng Yun /* read packet and ack; or stall because of gadget driver bug */ 421*df2069acSChunfeng Yun if (req) { 422*df2069acSChunfeng Yun void *buf = req->buf + req->actual; 423*df2069acSChunfeng Yun unsigned int len = req->length - req->actual; 424*df2069acSChunfeng Yun 425*df2069acSChunfeng Yun /* read the buffer */ 426*df2069acSChunfeng Yun count = mtu3_readl(mbase, U3D_RXCOUNT0); 427*df2069acSChunfeng Yun if (count > len) { 428*df2069acSChunfeng Yun req->status = -EOVERFLOW; 429*df2069acSChunfeng Yun count = len; 430*df2069acSChunfeng Yun } 431*df2069acSChunfeng Yun ep0_read_fifo(mtu->ep0, buf, count); 432*df2069acSChunfeng Yun req->actual += count; 433*df2069acSChunfeng Yun csr |= EP0_RXPKTRDY; 434*df2069acSChunfeng Yun 435*df2069acSChunfeng Yun maxp = mtu->g.ep0->maxpacket; 436*df2069acSChunfeng Yun if (count < maxp || req->actual == req->length) { 437*df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_SETUP; 438*df2069acSChunfeng Yun dev_dbg(mtu->dev, "ep0 state: %s\n", 439*df2069acSChunfeng Yun decode_ep0_state(mtu)); 440*df2069acSChunfeng Yun 441*df2069acSChunfeng Yun csr |= EP0_DATAEND; 442*df2069acSChunfeng Yun } else { 443*df2069acSChunfeng Yun req = NULL; 444*df2069acSChunfeng Yun } 445*df2069acSChunfeng Yun } else { 446*df2069acSChunfeng Yun csr |= EP0_RXPKTRDY | EP0_SENDSTALL; 447*df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s: SENDSTALL\n", __func__); 448*df2069acSChunfeng Yun } 449*df2069acSChunfeng Yun 450*df2069acSChunfeng Yun mtu3_writel(mbase, U3D_EP0CSR, csr); 451*df2069acSChunfeng Yun 452*df2069acSChunfeng Yun /* give back the request if have received all data */ 453*df2069acSChunfeng Yun if (req) 454*df2069acSChunfeng Yun ep0_req_giveback(mtu, req); 455*df2069acSChunfeng Yun 456*df2069acSChunfeng Yun } 457*df2069acSChunfeng Yun 458*df2069acSChunfeng Yun /* transmitting to the host (IN) */ 459*df2069acSChunfeng Yun static void ep0_tx_state(struct mtu3 *mtu) 460*df2069acSChunfeng Yun { 461*df2069acSChunfeng Yun struct mtu3_request *mreq = next_ep0_request(mtu); 462*df2069acSChunfeng Yun struct usb_request *req; 463*df2069acSChunfeng Yun u32 csr; 464*df2069acSChunfeng Yun u8 *src; 465*df2069acSChunfeng Yun u8 count; 466*df2069acSChunfeng Yun u32 maxp; 467*df2069acSChunfeng Yun 468*df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s\n", __func__); 469*df2069acSChunfeng Yun 470*df2069acSChunfeng Yun if (!mreq) 471*df2069acSChunfeng Yun return; 472*df2069acSChunfeng Yun 473*df2069acSChunfeng Yun maxp = mtu->g.ep0->maxpacket; 474*df2069acSChunfeng Yun req = &mreq->request; 475*df2069acSChunfeng Yun 476*df2069acSChunfeng Yun /* load the data */ 477*df2069acSChunfeng Yun src = (u8 *)req->buf + req->actual; 478*df2069acSChunfeng Yun count = min(maxp, req->length - req->actual); 479*df2069acSChunfeng Yun if (count) 480*df2069acSChunfeng Yun ep0_write_fifo(mtu->ep0, src, count); 481*df2069acSChunfeng Yun 482*df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s act=%d, len=%d, cnt=%d, maxp=%d zero=%d\n", 483*df2069acSChunfeng Yun __func__, req->actual, req->length, count, maxp, req->zero); 484*df2069acSChunfeng Yun 485*df2069acSChunfeng Yun req->actual += count; 486*df2069acSChunfeng Yun 487*df2069acSChunfeng Yun if ((count < maxp) 488*df2069acSChunfeng Yun || ((req->actual == req->length) && !req->zero)) 489*df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_TX_END; 490*df2069acSChunfeng Yun 491*df2069acSChunfeng Yun /* send it out, triggering a "txpktrdy cleared" irq */ 492*df2069acSChunfeng Yun csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS; 493*df2069acSChunfeng Yun mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr | EP0_TXPKTRDY); 494*df2069acSChunfeng Yun 495*df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s ep0csr=0x%x\n", __func__, 496*df2069acSChunfeng Yun mtu3_readl(mtu->mac_base, U3D_EP0CSR)); 497*df2069acSChunfeng Yun } 498*df2069acSChunfeng Yun 499*df2069acSChunfeng Yun static void ep0_read_setup(struct mtu3 *mtu, struct usb_ctrlrequest *setup) 500*df2069acSChunfeng Yun { 501*df2069acSChunfeng Yun struct mtu3_request *mreq; 502*df2069acSChunfeng Yun u32 count; 503*df2069acSChunfeng Yun u32 csr; 504*df2069acSChunfeng Yun 505*df2069acSChunfeng Yun csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS; 506*df2069acSChunfeng Yun count = mtu3_readl(mtu->mac_base, U3D_RXCOUNT0); 507*df2069acSChunfeng Yun 508*df2069acSChunfeng Yun ep0_read_fifo(mtu->ep0, (u8 *)setup, count); 509*df2069acSChunfeng Yun 510*df2069acSChunfeng Yun dev_dbg(mtu->dev, "SETUP req%02x.%02x v%04x i%04x l%04x\n", 511*df2069acSChunfeng Yun setup->bRequestType, setup->bRequest, 512*df2069acSChunfeng Yun le16_to_cpu(setup->wValue), le16_to_cpu(setup->wIndex), 513*df2069acSChunfeng Yun le16_to_cpu(setup->wLength)); 514*df2069acSChunfeng Yun 515*df2069acSChunfeng Yun /* clean up any leftover transfers */ 516*df2069acSChunfeng Yun mreq = next_ep0_request(mtu); 517*df2069acSChunfeng Yun if (mreq) 518*df2069acSChunfeng Yun ep0_req_giveback(mtu, &mreq->request); 519*df2069acSChunfeng Yun 520*df2069acSChunfeng Yun if (le16_to_cpu(setup->wLength) == 0) { 521*df2069acSChunfeng Yun ; /* no data stage, nothing to do */ 522*df2069acSChunfeng Yun } else if (setup->bRequestType & USB_DIR_IN) { 523*df2069acSChunfeng Yun mtu3_writel(mtu->mac_base, U3D_EP0CSR, 524*df2069acSChunfeng Yun csr | EP0_SETUPPKTRDY | EP0_DPHTX); 525*df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_TX; 526*df2069acSChunfeng Yun } else { 527*df2069acSChunfeng Yun mtu3_writel(mtu->mac_base, U3D_EP0CSR, 528*df2069acSChunfeng Yun (csr | EP0_SETUPPKTRDY) & (~EP0_DPHTX)); 529*df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_RX; 530*df2069acSChunfeng Yun } 531*df2069acSChunfeng Yun } 532*df2069acSChunfeng Yun 533*df2069acSChunfeng Yun static int ep0_handle_setup(struct mtu3 *mtu) 534*df2069acSChunfeng Yun __releases(mtu->lock) 535*df2069acSChunfeng Yun __acquires(mtu->lock) 536*df2069acSChunfeng Yun { 537*df2069acSChunfeng Yun struct usb_ctrlrequest setup; 538*df2069acSChunfeng Yun struct mtu3_request *mreq; 539*df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 540*df2069acSChunfeng Yun int handled = 0; 541*df2069acSChunfeng Yun 542*df2069acSChunfeng Yun ep0_read_setup(mtu, &setup); 543*df2069acSChunfeng Yun 544*df2069acSChunfeng Yun if ((setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) 545*df2069acSChunfeng Yun handled = handle_standard_request(mtu, &setup); 546*df2069acSChunfeng Yun 547*df2069acSChunfeng Yun dev_dbg(mtu->dev, "handled %d, ep0_state: %s\n", 548*df2069acSChunfeng Yun handled, decode_ep0_state(mtu)); 549*df2069acSChunfeng Yun 550*df2069acSChunfeng Yun if (handled < 0) 551*df2069acSChunfeng Yun goto stall; 552*df2069acSChunfeng Yun else if (handled > 0) 553*df2069acSChunfeng Yun goto finish; 554*df2069acSChunfeng Yun 555*df2069acSChunfeng Yun handled = forward_to_driver(mtu, &setup); 556*df2069acSChunfeng Yun if (handled < 0) { 557*df2069acSChunfeng Yun stall: 558*df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s stall (%d)\n", __func__, handled); 559*df2069acSChunfeng Yun 560*df2069acSChunfeng Yun ep0_stall_set(mtu->ep0, true, 561*df2069acSChunfeng Yun le16_to_cpu(setup.wLength) ? 0 : EP0_SETUPPKTRDY); 562*df2069acSChunfeng Yun 563*df2069acSChunfeng Yun return 0; 564*df2069acSChunfeng Yun } 565*df2069acSChunfeng Yun 566*df2069acSChunfeng Yun finish: 567*df2069acSChunfeng Yun if (mtu->test_mode) { 568*df2069acSChunfeng Yun ; /* nothing to do */ 569*df2069acSChunfeng Yun } else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */ 570*df2069acSChunfeng Yun 571*df2069acSChunfeng Yun mtu3_writel(mbase, U3D_EP0CSR, 572*df2069acSChunfeng Yun (mtu3_readl(mbase, U3D_EP0CSR) & EP0_W1C_BITS) 573*df2069acSChunfeng Yun | EP0_SETUPPKTRDY | EP0_DATAEND); 574*df2069acSChunfeng Yun 575*df2069acSChunfeng Yun /* complete zlp request directly */ 576*df2069acSChunfeng Yun mreq = next_ep0_request(mtu); 577*df2069acSChunfeng Yun if (mreq && !mreq->request.length) 578*df2069acSChunfeng Yun ep0_req_giveback(mtu, &mreq->request); 579*df2069acSChunfeng Yun } 580*df2069acSChunfeng Yun 581*df2069acSChunfeng Yun return 0; 582*df2069acSChunfeng Yun } 583*df2069acSChunfeng Yun 584*df2069acSChunfeng Yun irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu) 585*df2069acSChunfeng Yun { 586*df2069acSChunfeng Yun void __iomem *mbase = mtu->mac_base; 587*df2069acSChunfeng Yun struct mtu3_request *mreq; 588*df2069acSChunfeng Yun u32 int_status; 589*df2069acSChunfeng Yun irqreturn_t ret = IRQ_NONE; 590*df2069acSChunfeng Yun u32 csr; 591*df2069acSChunfeng Yun u32 len; 592*df2069acSChunfeng Yun 593*df2069acSChunfeng Yun int_status = mtu3_readl(mbase, U3D_EPISR); 594*df2069acSChunfeng Yun int_status &= mtu3_readl(mbase, U3D_EPIER); 595*df2069acSChunfeng Yun mtu3_writel(mbase, U3D_EPISR, int_status); /* W1C */ 596*df2069acSChunfeng Yun 597*df2069acSChunfeng Yun /* only handle ep0's */ 598*df2069acSChunfeng Yun if (!(int_status & EP0ISR)) 599*df2069acSChunfeng Yun return IRQ_NONE; 600*df2069acSChunfeng Yun 601*df2069acSChunfeng Yun csr = mtu3_readl(mbase, U3D_EP0CSR); 602*df2069acSChunfeng Yun 603*df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s csr=0x%x\n", __func__, csr); 604*df2069acSChunfeng Yun 605*df2069acSChunfeng Yun /* we sent a stall.. need to clear it now.. */ 606*df2069acSChunfeng Yun if (csr & EP0_SENTSTALL) { 607*df2069acSChunfeng Yun ep0_stall_set(mtu->ep0, false, 0); 608*df2069acSChunfeng Yun csr = mtu3_readl(mbase, U3D_EP0CSR); 609*df2069acSChunfeng Yun ret = IRQ_HANDLED; 610*df2069acSChunfeng Yun } 611*df2069acSChunfeng Yun dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu)); 612*df2069acSChunfeng Yun 613*df2069acSChunfeng Yun switch (mtu->ep0_state) { 614*df2069acSChunfeng Yun case MU3D_EP0_STATE_TX: 615*df2069acSChunfeng Yun /* irq on clearing txpktrdy */ 616*df2069acSChunfeng Yun if ((csr & EP0_FIFOFULL) == 0) { 617*df2069acSChunfeng Yun ep0_tx_state(mtu); 618*df2069acSChunfeng Yun ret = IRQ_HANDLED; 619*df2069acSChunfeng Yun } 620*df2069acSChunfeng Yun break; 621*df2069acSChunfeng Yun case MU3D_EP0_STATE_RX: 622*df2069acSChunfeng Yun /* irq on set rxpktrdy */ 623*df2069acSChunfeng Yun if (csr & EP0_RXPKTRDY) { 624*df2069acSChunfeng Yun ep0_rx_state(mtu); 625*df2069acSChunfeng Yun ret = IRQ_HANDLED; 626*df2069acSChunfeng Yun } 627*df2069acSChunfeng Yun break; 628*df2069acSChunfeng Yun case MU3D_EP0_STATE_TX_END: 629*df2069acSChunfeng Yun mtu3_writel(mbase, U3D_EP0CSR, 630*df2069acSChunfeng Yun (csr & EP0_W1C_BITS) | EP0_DATAEND); 631*df2069acSChunfeng Yun 632*df2069acSChunfeng Yun mreq = next_ep0_request(mtu); 633*df2069acSChunfeng Yun if (mreq) 634*df2069acSChunfeng Yun ep0_req_giveback(mtu, &mreq->request); 635*df2069acSChunfeng Yun 636*df2069acSChunfeng Yun mtu->ep0_state = MU3D_EP0_STATE_SETUP; 637*df2069acSChunfeng Yun ret = IRQ_HANDLED; 638*df2069acSChunfeng Yun dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu)); 639*df2069acSChunfeng Yun break; 640*df2069acSChunfeng Yun case MU3D_EP0_STATE_SETUP: 641*df2069acSChunfeng Yun if (!(csr & EP0_SETUPPKTRDY)) 642*df2069acSChunfeng Yun break; 643*df2069acSChunfeng Yun 644*df2069acSChunfeng Yun len = mtu3_readl(mbase, U3D_RXCOUNT0); 645*df2069acSChunfeng Yun if (len != 8) { 646*df2069acSChunfeng Yun dev_err(mtu->dev, "SETUP packet len %d != 8 ?\n", len); 647*df2069acSChunfeng Yun break; 648*df2069acSChunfeng Yun } 649*df2069acSChunfeng Yun 650*df2069acSChunfeng Yun ep0_handle_setup(mtu); 651*df2069acSChunfeng Yun ret = IRQ_HANDLED; 652*df2069acSChunfeng Yun break; 653*df2069acSChunfeng Yun default: 654*df2069acSChunfeng Yun /* can't happen */ 655*df2069acSChunfeng Yun ep0_stall_set(mtu->ep0, true, 0); 656*df2069acSChunfeng Yun WARN_ON(1); 657*df2069acSChunfeng Yun break; 658*df2069acSChunfeng Yun } 659*df2069acSChunfeng Yun 660*df2069acSChunfeng Yun return ret; 661*df2069acSChunfeng Yun } 662*df2069acSChunfeng Yun 663*df2069acSChunfeng Yun 664*df2069acSChunfeng Yun static int mtu3_ep0_enable(struct usb_ep *ep, 665*df2069acSChunfeng Yun const struct usb_endpoint_descriptor *desc) 666*df2069acSChunfeng Yun { 667*df2069acSChunfeng Yun /* always enabled */ 668*df2069acSChunfeng Yun return -EINVAL; 669*df2069acSChunfeng Yun } 670*df2069acSChunfeng Yun 671*df2069acSChunfeng Yun static int mtu3_ep0_disable(struct usb_ep *ep) 672*df2069acSChunfeng Yun { 673*df2069acSChunfeng Yun /* always enabled */ 674*df2069acSChunfeng Yun return -EINVAL; 675*df2069acSChunfeng Yun } 676*df2069acSChunfeng Yun 677*df2069acSChunfeng Yun static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq) 678*df2069acSChunfeng Yun { 679*df2069acSChunfeng Yun struct mtu3 *mtu = mep->mtu; 680*df2069acSChunfeng Yun 681*df2069acSChunfeng Yun mreq->mtu = mtu; 682*df2069acSChunfeng Yun mreq->request.actual = 0; 683*df2069acSChunfeng Yun mreq->request.status = -EINPROGRESS; 684*df2069acSChunfeng Yun 685*df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s %s (ep0_state: %s), len#%d\n", __func__, 686*df2069acSChunfeng Yun mep->name, decode_ep0_state(mtu), mreq->request.length); 687*df2069acSChunfeng Yun 688*df2069acSChunfeng Yun if (!list_empty(&mep->req_list)) 689*df2069acSChunfeng Yun return -EBUSY; 690*df2069acSChunfeng Yun 691*df2069acSChunfeng Yun switch (mtu->ep0_state) { 692*df2069acSChunfeng Yun case MU3D_EP0_STATE_SETUP: 693*df2069acSChunfeng Yun case MU3D_EP0_STATE_RX: /* control-OUT data */ 694*df2069acSChunfeng Yun case MU3D_EP0_STATE_TX: /* control-IN data */ 695*df2069acSChunfeng Yun break; 696*df2069acSChunfeng Yun default: 697*df2069acSChunfeng Yun dev_err(mtu->dev, "%s, error in ep0 state %s\n", __func__, 698*df2069acSChunfeng Yun decode_ep0_state(mtu)); 699*df2069acSChunfeng Yun return -EINVAL; 700*df2069acSChunfeng Yun } 701*df2069acSChunfeng Yun 702*df2069acSChunfeng Yun list_add_tail(&mreq->list, &mep->req_list); 703*df2069acSChunfeng Yun 704*df2069acSChunfeng Yun /* sequence #1, IN ... start writing the data */ 705*df2069acSChunfeng Yun if (mtu->ep0_state == MU3D_EP0_STATE_TX) 706*df2069acSChunfeng Yun ep0_tx_state(mtu); 707*df2069acSChunfeng Yun 708*df2069acSChunfeng Yun return 0; 709*df2069acSChunfeng Yun } 710*df2069acSChunfeng Yun 711*df2069acSChunfeng Yun static int mtu3_ep0_queue(struct usb_ep *ep, 712*df2069acSChunfeng Yun struct usb_request *req, gfp_t gfp) 713*df2069acSChunfeng Yun { 714*df2069acSChunfeng Yun struct mtu3_ep *mep; 715*df2069acSChunfeng Yun struct mtu3_request *mreq; 716*df2069acSChunfeng Yun struct mtu3 *mtu; 717*df2069acSChunfeng Yun unsigned long flags; 718*df2069acSChunfeng Yun int ret = 0; 719*df2069acSChunfeng Yun 720*df2069acSChunfeng Yun if (!ep || !req) 721*df2069acSChunfeng Yun return -EINVAL; 722*df2069acSChunfeng Yun 723*df2069acSChunfeng Yun mep = to_mtu3_ep(ep); 724*df2069acSChunfeng Yun mtu = mep->mtu; 725*df2069acSChunfeng Yun mreq = to_mtu3_request(req); 726*df2069acSChunfeng Yun 727*df2069acSChunfeng Yun spin_lock_irqsave(&mtu->lock, flags); 728*df2069acSChunfeng Yun ret = ep0_queue(mep, mreq); 729*df2069acSChunfeng Yun spin_unlock_irqrestore(&mtu->lock, flags); 730*df2069acSChunfeng Yun return ret; 731*df2069acSChunfeng Yun } 732*df2069acSChunfeng Yun 733*df2069acSChunfeng Yun static int mtu3_ep0_dequeue(struct usb_ep *ep, struct usb_request *req) 734*df2069acSChunfeng Yun { 735*df2069acSChunfeng Yun /* we just won't support this */ 736*df2069acSChunfeng Yun return -EINVAL; 737*df2069acSChunfeng Yun } 738*df2069acSChunfeng Yun 739*df2069acSChunfeng Yun static int mtu3_ep0_halt(struct usb_ep *ep, int value) 740*df2069acSChunfeng Yun { 741*df2069acSChunfeng Yun struct mtu3_ep *mep; 742*df2069acSChunfeng Yun struct mtu3 *mtu; 743*df2069acSChunfeng Yun unsigned long flags; 744*df2069acSChunfeng Yun int ret = 0; 745*df2069acSChunfeng Yun 746*df2069acSChunfeng Yun if (!ep || !value) 747*df2069acSChunfeng Yun return -EINVAL; 748*df2069acSChunfeng Yun 749*df2069acSChunfeng Yun mep = to_mtu3_ep(ep); 750*df2069acSChunfeng Yun mtu = mep->mtu; 751*df2069acSChunfeng Yun 752*df2069acSChunfeng Yun dev_dbg(mtu->dev, "%s\n", __func__); 753*df2069acSChunfeng Yun 754*df2069acSChunfeng Yun spin_lock_irqsave(&mtu->lock, flags); 755*df2069acSChunfeng Yun 756*df2069acSChunfeng Yun if (!list_empty(&mep->req_list)) { 757*df2069acSChunfeng Yun ret = -EBUSY; 758*df2069acSChunfeng Yun goto cleanup; 759*df2069acSChunfeng Yun } 760*df2069acSChunfeng Yun 761*df2069acSChunfeng Yun switch (mtu->ep0_state) { 762*df2069acSChunfeng Yun /* 763*df2069acSChunfeng Yun * stalls are usually issued after parsing SETUP packet, either 764*df2069acSChunfeng Yun * directly in irq context from setup() or else later. 765*df2069acSChunfeng Yun */ 766*df2069acSChunfeng Yun case MU3D_EP0_STATE_TX: 767*df2069acSChunfeng Yun case MU3D_EP0_STATE_TX_END: 768*df2069acSChunfeng Yun case MU3D_EP0_STATE_RX: 769*df2069acSChunfeng Yun case MU3D_EP0_STATE_SETUP: 770*df2069acSChunfeng Yun ep0_stall_set(mtu->ep0, true, 0); 771*df2069acSChunfeng Yun break; 772*df2069acSChunfeng Yun default: 773*df2069acSChunfeng Yun dev_dbg(mtu->dev, "ep0 can't halt in state %s\n", 774*df2069acSChunfeng Yun decode_ep0_state(mtu)); 775*df2069acSChunfeng Yun ret = -EINVAL; 776*df2069acSChunfeng Yun } 777*df2069acSChunfeng Yun 778*df2069acSChunfeng Yun cleanup: 779*df2069acSChunfeng Yun spin_unlock_irqrestore(&mtu->lock, flags); 780*df2069acSChunfeng Yun return ret; 781*df2069acSChunfeng Yun } 782*df2069acSChunfeng Yun 783*df2069acSChunfeng Yun const struct usb_ep_ops mtu3_ep0_ops = { 784*df2069acSChunfeng Yun .enable = mtu3_ep0_enable, 785*df2069acSChunfeng Yun .disable = mtu3_ep0_disable, 786*df2069acSChunfeng Yun .alloc_request = mtu3_alloc_request, 787*df2069acSChunfeng Yun .free_request = mtu3_free_request, 788*df2069acSChunfeng Yun .queue = mtu3_ep0_queue, 789*df2069acSChunfeng Yun .dequeue = mtu3_ep0_dequeue, 790*df2069acSChunfeng Yun .set_halt = mtu3_ep0_halt, 791*df2069acSChunfeng Yun }; 792