1859bfd8dSPatrick Delaunay /* 2*867cd155SPankaj Dev * Copyright (c) 2021-2025, STMicroelectronics - All Rights Reserved 3859bfd8dSPatrick Delaunay * 4859bfd8dSPatrick Delaunay * SPDX-License-Identifier: BSD-3-Clause 5859bfd8dSPatrick Delaunay */ 6859bfd8dSPatrick Delaunay 7859bfd8dSPatrick Delaunay #include <assert.h> 8859bfd8dSPatrick Delaunay #include <stdint.h> 9859bfd8dSPatrick Delaunay 10859bfd8dSPatrick Delaunay #include <common/debug.h> 11859bfd8dSPatrick Delaunay #include <drivers/usb_device.h> 12859bfd8dSPatrick Delaunay 13859bfd8dSPatrick Delaunay /* 14859bfd8dSPatrick Delaunay * Set a STALL condition over an endpoint 15859bfd8dSPatrick Delaunay * pdev: USB handle 16859bfd8dSPatrick Delaunay * ep_addr: endpoint address 17859bfd8dSPatrick Delaunay * return : status 18859bfd8dSPatrick Delaunay */ 19*867cd155SPankaj Dev static enum usb_status usb_core_set_stall(struct usb_handle *pdev, 20*867cd155SPankaj Dev uint8_t ep_addr) 21859bfd8dSPatrick Delaunay { 22859bfd8dSPatrick Delaunay struct usbd_ep *ep; 23859bfd8dSPatrick Delaunay struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data; 24859bfd8dSPatrick Delaunay uint8_t num; 25859bfd8dSPatrick Delaunay 26859bfd8dSPatrick Delaunay num = ep_addr & EP_NUM_MASK; 27859bfd8dSPatrick Delaunay if (num >= USBD_EP_NB) { 28859bfd8dSPatrick Delaunay return USBD_FAIL; 29859bfd8dSPatrick Delaunay } 30859bfd8dSPatrick Delaunay if ((EP_DIR_MASK & ep_addr) == EP_DIR_IN) { 31859bfd8dSPatrick Delaunay ep = &hpcd->in_ep[num]; 32859bfd8dSPatrick Delaunay ep->is_in = true; 33859bfd8dSPatrick Delaunay } else { 34859bfd8dSPatrick Delaunay ep = &hpcd->out_ep[num]; 35859bfd8dSPatrick Delaunay ep->is_in = false; 36859bfd8dSPatrick Delaunay } 37859bfd8dSPatrick Delaunay ep->num = num; 38859bfd8dSPatrick Delaunay 39859bfd8dSPatrick Delaunay pdev->driver->ep_set_stall(hpcd->instance, ep); 40*867cd155SPankaj Dev if (ep_addr == EP0_OUT) { 41859bfd8dSPatrick Delaunay pdev->driver->ep0_out_start(hpcd->instance); 42859bfd8dSPatrick Delaunay } 43859bfd8dSPatrick Delaunay 44859bfd8dSPatrick Delaunay return USBD_OK; 45859bfd8dSPatrick Delaunay } 46859bfd8dSPatrick Delaunay 47859bfd8dSPatrick Delaunay /* 48859bfd8dSPatrick Delaunay * usb_core_get_desc 49859bfd8dSPatrick Delaunay * Handle Get Descriptor requests 50859bfd8dSPatrick Delaunay * pdev : device instance 51859bfd8dSPatrick Delaunay * req : usb request 52859bfd8dSPatrick Delaunay */ 53*867cd155SPankaj Dev static void usb_core_get_desc(struct usb_handle *pdev, 54*867cd155SPankaj Dev struct usb_setup_req *req) 55859bfd8dSPatrick Delaunay { 56859bfd8dSPatrick Delaunay uint16_t len; 57859bfd8dSPatrick Delaunay uint8_t *pbuf; 58859bfd8dSPatrick Delaunay uint8_t desc_type = HIBYTE(req->value); 59859bfd8dSPatrick Delaunay uint8_t desc_idx = LOBYTE(req->value); 60859bfd8dSPatrick Delaunay 61859bfd8dSPatrick Delaunay switch (desc_type) { 62859bfd8dSPatrick Delaunay case USB_DESC_TYPE_DEVICE: 63859bfd8dSPatrick Delaunay pbuf = pdev->desc->get_device_desc(&len); 64859bfd8dSPatrick Delaunay break; 65859bfd8dSPatrick Delaunay 66859bfd8dSPatrick Delaunay case USB_DESC_TYPE_CONFIGURATION: 67025f5ef2SPatrick Delaunay pbuf = pdev->desc->get_config_desc(&len); 68859bfd8dSPatrick Delaunay break; 69859bfd8dSPatrick Delaunay 70859bfd8dSPatrick Delaunay case USB_DESC_TYPE_STRING: 71859bfd8dSPatrick Delaunay switch (desc_idx) { 72859bfd8dSPatrick Delaunay case USBD_IDX_LANGID_STR: 73859bfd8dSPatrick Delaunay pbuf = pdev->desc->get_lang_id_desc(&len); 74859bfd8dSPatrick Delaunay break; 75859bfd8dSPatrick Delaunay 76859bfd8dSPatrick Delaunay case USBD_IDX_MFC_STR: 77859bfd8dSPatrick Delaunay pbuf = pdev->desc->get_manufacturer_desc(&len); 78859bfd8dSPatrick Delaunay break; 79859bfd8dSPatrick Delaunay 80859bfd8dSPatrick Delaunay case USBD_IDX_PRODUCT_STR: 81859bfd8dSPatrick Delaunay pbuf = pdev->desc->get_product_desc(&len); 82859bfd8dSPatrick Delaunay break; 83859bfd8dSPatrick Delaunay 84859bfd8dSPatrick Delaunay case USBD_IDX_SERIAL_STR: 85859bfd8dSPatrick Delaunay pbuf = pdev->desc->get_serial_desc(&len); 86859bfd8dSPatrick Delaunay break; 87859bfd8dSPatrick Delaunay 88859bfd8dSPatrick Delaunay case USBD_IDX_CONFIG_STR: 89859bfd8dSPatrick Delaunay pbuf = pdev->desc->get_configuration_desc(&len); 90859bfd8dSPatrick Delaunay break; 91859bfd8dSPatrick Delaunay 92859bfd8dSPatrick Delaunay case USBD_IDX_INTERFACE_STR: 93859bfd8dSPatrick Delaunay pbuf = pdev->desc->get_interface_desc(&len); 94859bfd8dSPatrick Delaunay break; 95859bfd8dSPatrick Delaunay 96859bfd8dSPatrick Delaunay /* For all USER string */ 97859bfd8dSPatrick Delaunay case USBD_IDX_USER0_STR: 98859bfd8dSPatrick Delaunay default: 99*867cd155SPankaj Dev pbuf = pdev->desc->get_usr_desc( 100*867cd155SPankaj Dev desc_idx - USBD_IDX_USER0_STR, &len); 101859bfd8dSPatrick Delaunay break; 102859bfd8dSPatrick Delaunay } 103859bfd8dSPatrick Delaunay break; 104859bfd8dSPatrick Delaunay 105859bfd8dSPatrick Delaunay case USB_DESC_TYPE_DEVICE_QUALIFIER: 106025f5ef2SPatrick Delaunay pbuf = pdev->desc->get_device_qualifier_desc(&len); 107859bfd8dSPatrick Delaunay break; 108859bfd8dSPatrick Delaunay 109859bfd8dSPatrick Delaunay case USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION: 110216c1223SPatrick Delaunay if (pdev->desc->get_other_speed_config_desc == NULL) { 111216c1223SPatrick Delaunay usb_core_ctl_error(pdev); 112216c1223SPatrick Delaunay return; 113216c1223SPatrick Delaunay } 114216c1223SPatrick Delaunay pbuf = pdev->desc->get_other_speed_config_desc(&len); 115859bfd8dSPatrick Delaunay break; 116859bfd8dSPatrick Delaunay 117859bfd8dSPatrick Delaunay default: 118859bfd8dSPatrick Delaunay ERROR("Unknown request %i\n", desc_type); 119859bfd8dSPatrick Delaunay usb_core_ctl_error(pdev); 120859bfd8dSPatrick Delaunay return; 121859bfd8dSPatrick Delaunay } 122859bfd8dSPatrick Delaunay 123859bfd8dSPatrick Delaunay if ((len != 0U) && (req->length != 0U)) { 124859bfd8dSPatrick Delaunay len = MIN(len, req->length); 125859bfd8dSPatrick Delaunay 126859bfd8dSPatrick Delaunay /* Start the transfer */ 127859bfd8dSPatrick Delaunay usb_core_transmit_ep0(pdev, pbuf, len); 128859bfd8dSPatrick Delaunay } 129859bfd8dSPatrick Delaunay } 130859bfd8dSPatrick Delaunay 131859bfd8dSPatrick Delaunay /* 132859bfd8dSPatrick Delaunay * usb_core_set_config 133859bfd8dSPatrick Delaunay * Handle Set device configuration request 134859bfd8dSPatrick Delaunay * pdev : device instance 135859bfd8dSPatrick Delaunay * req : usb request 136859bfd8dSPatrick Delaunay */ 137*867cd155SPankaj Dev static void usb_core_set_config(struct usb_handle *pdev, 138*867cd155SPankaj Dev struct usb_setup_req *req) 139859bfd8dSPatrick Delaunay { 140859bfd8dSPatrick Delaunay static uint8_t cfgidx; 141859bfd8dSPatrick Delaunay 142859bfd8dSPatrick Delaunay cfgidx = LOBYTE(req->value); 143859bfd8dSPatrick Delaunay 144859bfd8dSPatrick Delaunay if (cfgidx > USBD_MAX_NUM_CONFIGURATION) { 145859bfd8dSPatrick Delaunay usb_core_ctl_error(pdev); 146859bfd8dSPatrick Delaunay return; 147859bfd8dSPatrick Delaunay } 148859bfd8dSPatrick Delaunay 149859bfd8dSPatrick Delaunay switch (pdev->dev_state) { 150859bfd8dSPatrick Delaunay case USBD_STATE_ADDRESSED: 151859bfd8dSPatrick Delaunay if (cfgidx != 0U) { 152859bfd8dSPatrick Delaunay pdev->dev_config = cfgidx; 153859bfd8dSPatrick Delaunay pdev->dev_state = USBD_STATE_CONFIGURED; 154859bfd8dSPatrick Delaunay if (!pdev->class) { 155859bfd8dSPatrick Delaunay usb_core_ctl_error(pdev); 156859bfd8dSPatrick Delaunay return; 157859bfd8dSPatrick Delaunay } 158859bfd8dSPatrick Delaunay /* Set configuration and Start the Class */ 159859bfd8dSPatrick Delaunay if (pdev->class->init(pdev, cfgidx) != 0U) { 160859bfd8dSPatrick Delaunay usb_core_ctl_error(pdev); 161859bfd8dSPatrick Delaunay return; 162859bfd8dSPatrick Delaunay } 163859bfd8dSPatrick Delaunay } 164859bfd8dSPatrick Delaunay break; 165859bfd8dSPatrick Delaunay 166859bfd8dSPatrick Delaunay case USBD_STATE_CONFIGURED: 167859bfd8dSPatrick Delaunay if (cfgidx == 0U) { 168859bfd8dSPatrick Delaunay pdev->dev_state = USBD_STATE_ADDRESSED; 169859bfd8dSPatrick Delaunay pdev->dev_config = cfgidx; 170859bfd8dSPatrick Delaunay pdev->class->de_init(pdev, cfgidx); 171859bfd8dSPatrick Delaunay } else if (cfgidx != pdev->dev_config) { 1720cb9870dSPatrick Delaunay if (pdev->class == NULL) { 173859bfd8dSPatrick Delaunay usb_core_ctl_error(pdev); 174859bfd8dSPatrick Delaunay return; 175859bfd8dSPatrick Delaunay } 176859bfd8dSPatrick Delaunay /* Clear old configuration */ 177859bfd8dSPatrick Delaunay pdev->class->de_init(pdev, pdev->dev_config); 178859bfd8dSPatrick Delaunay /* Set new configuration */ 179859bfd8dSPatrick Delaunay pdev->dev_config = cfgidx; 180859bfd8dSPatrick Delaunay /* Set configuration and start the USB class */ 181859bfd8dSPatrick Delaunay if (pdev->class->init(pdev, cfgidx) != 0U) { 182859bfd8dSPatrick Delaunay usb_core_ctl_error(pdev); 183859bfd8dSPatrick Delaunay return; 184859bfd8dSPatrick Delaunay } 185859bfd8dSPatrick Delaunay } 186859bfd8dSPatrick Delaunay break; 187859bfd8dSPatrick Delaunay 188859bfd8dSPatrick Delaunay default: 189859bfd8dSPatrick Delaunay usb_core_ctl_error(pdev); 190859bfd8dSPatrick Delaunay return; 191859bfd8dSPatrick Delaunay } 192859bfd8dSPatrick Delaunay 193859bfd8dSPatrick Delaunay /* Send status */ 194859bfd8dSPatrick Delaunay usb_core_transmit_ep0(pdev, NULL, 0U); 195859bfd8dSPatrick Delaunay } 196859bfd8dSPatrick Delaunay 197859bfd8dSPatrick Delaunay /* 198859bfd8dSPatrick Delaunay * usb_core_get_status 199859bfd8dSPatrick Delaunay * Handle Get Status request 200859bfd8dSPatrick Delaunay * pdev : device instance 201859bfd8dSPatrick Delaunay * req : usb request 202859bfd8dSPatrick Delaunay */ 203859bfd8dSPatrick Delaunay static void usb_core_get_status(struct usb_handle *pdev, 204859bfd8dSPatrick Delaunay struct usb_setup_req *req) 205859bfd8dSPatrick Delaunay { 206859bfd8dSPatrick Delaunay if ((pdev->dev_state != USBD_STATE_ADDRESSED) && 207859bfd8dSPatrick Delaunay (pdev->dev_state != USBD_STATE_CONFIGURED)) { 208859bfd8dSPatrick Delaunay usb_core_ctl_error(pdev); 209859bfd8dSPatrick Delaunay return; 210859bfd8dSPatrick Delaunay } 211859bfd8dSPatrick Delaunay 212859bfd8dSPatrick Delaunay pdev->dev_config_status = USB_CONFIG_SELF_POWERED; 213859bfd8dSPatrick Delaunay 214859bfd8dSPatrick Delaunay if (pdev->dev_remote_wakeup != 0U) { 215859bfd8dSPatrick Delaunay pdev->dev_config_status |= USB_CONFIG_REMOTE_WAKEUP; 216859bfd8dSPatrick Delaunay } 217859bfd8dSPatrick Delaunay 218859bfd8dSPatrick Delaunay /* Start the transfer */ 219859bfd8dSPatrick Delaunay usb_core_transmit_ep0(pdev, (uint8_t *)&pdev->dev_config_status, 2U); 220859bfd8dSPatrick Delaunay } 221859bfd8dSPatrick Delaunay 222859bfd8dSPatrick Delaunay /* 223859bfd8dSPatrick Delaunay * usb_core_set_address 224859bfd8dSPatrick Delaunay * Set device address 225859bfd8dSPatrick Delaunay * pdev : device instance 226859bfd8dSPatrick Delaunay * req : usb request 227859bfd8dSPatrick Delaunay */ 228859bfd8dSPatrick Delaunay static void usb_core_set_address(struct usb_handle *pdev, 229859bfd8dSPatrick Delaunay struct usb_setup_req *req) 230859bfd8dSPatrick Delaunay { 231859bfd8dSPatrick Delaunay uint8_t dev_addr; 232859bfd8dSPatrick Delaunay 233859bfd8dSPatrick Delaunay if ((req->index != 0U) || (req->length != 0U)) { 234859bfd8dSPatrick Delaunay usb_core_ctl_error(pdev); 235859bfd8dSPatrick Delaunay return; 236859bfd8dSPatrick Delaunay } 237859bfd8dSPatrick Delaunay 238859bfd8dSPatrick Delaunay dev_addr = req->value & ADDRESS_MASK; 239859bfd8dSPatrick Delaunay if (pdev->dev_state != USBD_STATE_DEFAULT) { 240859bfd8dSPatrick Delaunay usb_core_ctl_error(pdev); 241859bfd8dSPatrick Delaunay return; 242859bfd8dSPatrick Delaunay } 243859bfd8dSPatrick Delaunay 244859bfd8dSPatrick Delaunay pdev->dev_address = dev_addr; 245*867cd155SPankaj Dev pdev->driver->set_address(((struct pcd_handle *)(pdev->data))->instance, 246*867cd155SPankaj Dev dev_addr); 247859bfd8dSPatrick Delaunay 248859bfd8dSPatrick Delaunay /* Send status */ 249859bfd8dSPatrick Delaunay usb_core_transmit_ep0(pdev, NULL, 0U); 250859bfd8dSPatrick Delaunay 251859bfd8dSPatrick Delaunay if (dev_addr != 0U) { 252859bfd8dSPatrick Delaunay pdev->dev_state = USBD_STATE_ADDRESSED; 253859bfd8dSPatrick Delaunay } else { 254859bfd8dSPatrick Delaunay pdev->dev_state = USBD_STATE_DEFAULT; 255859bfd8dSPatrick Delaunay } 256859bfd8dSPatrick Delaunay } 257859bfd8dSPatrick Delaunay 258859bfd8dSPatrick Delaunay /* 259859bfd8dSPatrick Delaunay * usb_core_dev_req 260859bfd8dSPatrick Delaunay * Handle standard usb device requests 261859bfd8dSPatrick Delaunay * pdev : device instance 262859bfd8dSPatrick Delaunay * req : usb request 263859bfd8dSPatrick Delaunay * return : status 264859bfd8dSPatrick Delaunay */ 265859bfd8dSPatrick Delaunay static enum usb_status usb_core_dev_req(struct usb_handle *pdev, 266859bfd8dSPatrick Delaunay struct usb_setup_req *req) 267859bfd8dSPatrick Delaunay { 268859bfd8dSPatrick Delaunay VERBOSE("receive request %i\n", req->b_request); 269859bfd8dSPatrick Delaunay switch (req->b_request) { 270859bfd8dSPatrick Delaunay case USB_REQ_GET_DESCRIPTOR: 271859bfd8dSPatrick Delaunay usb_core_get_desc(pdev, req); 272859bfd8dSPatrick Delaunay break; 273859bfd8dSPatrick Delaunay 274859bfd8dSPatrick Delaunay case USB_REQ_SET_CONFIGURATION: 275859bfd8dSPatrick Delaunay usb_core_set_config(pdev, req); 276859bfd8dSPatrick Delaunay break; 277859bfd8dSPatrick Delaunay 278859bfd8dSPatrick Delaunay case USB_REQ_GET_STATUS: 279859bfd8dSPatrick Delaunay usb_core_get_status(pdev, req); 280859bfd8dSPatrick Delaunay break; 281859bfd8dSPatrick Delaunay 282859bfd8dSPatrick Delaunay case USB_REQ_SET_ADDRESS: 283859bfd8dSPatrick Delaunay usb_core_set_address(pdev, req); 284859bfd8dSPatrick Delaunay break; 285859bfd8dSPatrick Delaunay 286859bfd8dSPatrick Delaunay case USB_REQ_GET_CONFIGURATION: 287859bfd8dSPatrick Delaunay case USB_REQ_SET_FEATURE: 288859bfd8dSPatrick Delaunay case USB_REQ_CLEAR_FEATURE: 289859bfd8dSPatrick Delaunay default: 290859bfd8dSPatrick Delaunay ERROR("NOT SUPPORTED %i\n", req->b_request); 291859bfd8dSPatrick Delaunay usb_core_ctl_error(pdev); 292859bfd8dSPatrick Delaunay break; 293859bfd8dSPatrick Delaunay } 294859bfd8dSPatrick Delaunay 295859bfd8dSPatrick Delaunay return USBD_OK; 296859bfd8dSPatrick Delaunay } 297859bfd8dSPatrick Delaunay 298859bfd8dSPatrick Delaunay /* 299859bfd8dSPatrick Delaunay * usb_core_itf_req 300859bfd8dSPatrick Delaunay * Handle standard usb interface requests 301859bfd8dSPatrick Delaunay * pdev : device instance 302859bfd8dSPatrick Delaunay * req : usb request 303859bfd8dSPatrick Delaunay * return : status 304859bfd8dSPatrick Delaunay */ 305859bfd8dSPatrick Delaunay static enum usb_status usb_core_itf_req(struct usb_handle *pdev, 306859bfd8dSPatrick Delaunay struct usb_setup_req *req) 307859bfd8dSPatrick Delaunay { 308859bfd8dSPatrick Delaunay if (pdev->dev_state != USBD_STATE_CONFIGURED) { 309859bfd8dSPatrick Delaunay usb_core_ctl_error(pdev); 310859bfd8dSPatrick Delaunay return USBD_OK; 311859bfd8dSPatrick Delaunay } 312859bfd8dSPatrick Delaunay 313859bfd8dSPatrick Delaunay if (LOBYTE(req->index) <= USBD_MAX_NUM_INTERFACES) { 314859bfd8dSPatrick Delaunay pdev->class->setup(pdev, req); 315859bfd8dSPatrick Delaunay 316859bfd8dSPatrick Delaunay if (req->length == 0U) { 317859bfd8dSPatrick Delaunay usb_core_transmit_ep0(pdev, NULL, 0U); 318859bfd8dSPatrick Delaunay } 319859bfd8dSPatrick Delaunay } else { 320859bfd8dSPatrick Delaunay usb_core_ctl_error(pdev); 321859bfd8dSPatrick Delaunay } 322859bfd8dSPatrick Delaunay 323859bfd8dSPatrick Delaunay return USBD_OK; 324859bfd8dSPatrick Delaunay } 325859bfd8dSPatrick Delaunay 326859bfd8dSPatrick Delaunay /* 327859bfd8dSPatrick Delaunay * usb_core_setup_stage 328859bfd8dSPatrick Delaunay * Handle the setup stage 329859bfd8dSPatrick Delaunay * pdev: device instance 330859bfd8dSPatrick Delaunay * psetup : setup buffer 331859bfd8dSPatrick Delaunay * return : status 332859bfd8dSPatrick Delaunay */ 333859bfd8dSPatrick Delaunay static enum usb_status usb_core_setup_stage(struct usb_handle *pdev, 334859bfd8dSPatrick Delaunay uint8_t *psetup) 335859bfd8dSPatrick Delaunay { 336859bfd8dSPatrick Delaunay struct usb_setup_req *req = &pdev->request; 337859bfd8dSPatrick Delaunay 338859bfd8dSPatrick Delaunay /* Copy setup buffer into req structure */ 339859bfd8dSPatrick Delaunay req->bm_request = psetup[0]; 340859bfd8dSPatrick Delaunay req->b_request = psetup[1]; 341859bfd8dSPatrick Delaunay req->value = psetup[2] + (psetup[3] << 8); 342859bfd8dSPatrick Delaunay req->index = psetup[4] + (psetup[5] << 8); 343859bfd8dSPatrick Delaunay req->length = psetup[6] + (psetup[7] << 8); 344859bfd8dSPatrick Delaunay 345859bfd8dSPatrick Delaunay pdev->ep0_state = USBD_EP0_SETUP; 346859bfd8dSPatrick Delaunay pdev->ep0_data_len = pdev->request.length; 347859bfd8dSPatrick Delaunay 348859bfd8dSPatrick Delaunay switch (pdev->request.bm_request & USB_REQ_RECIPIENT_MASK) { 349859bfd8dSPatrick Delaunay case USB_REQ_RECIPIENT_DEVICE: 350859bfd8dSPatrick Delaunay usb_core_dev_req(pdev, &pdev->request); 351859bfd8dSPatrick Delaunay break; 352859bfd8dSPatrick Delaunay 353859bfd8dSPatrick Delaunay case USB_REQ_RECIPIENT_INTERFACE: 354859bfd8dSPatrick Delaunay usb_core_itf_req(pdev, &pdev->request); 355859bfd8dSPatrick Delaunay break; 356859bfd8dSPatrick Delaunay 357859bfd8dSPatrick Delaunay case USB_REQ_RECIPIENT_ENDPOINT: 358859bfd8dSPatrick Delaunay default: 359bd9cd63bSYann Gautier ERROR("receive unsupported request %u", 360859bfd8dSPatrick Delaunay pdev->request.bm_request & USB_REQ_RECIPIENT_MASK); 361*867cd155SPankaj Dev usb_core_set_stall(pdev, pdev->request.bm_request & 362*867cd155SPankaj Dev USB_REQ_DIRECTION); 363859bfd8dSPatrick Delaunay return USBD_FAIL; 364859bfd8dSPatrick Delaunay } 365859bfd8dSPatrick Delaunay 366859bfd8dSPatrick Delaunay return USBD_OK; 367859bfd8dSPatrick Delaunay } 368859bfd8dSPatrick Delaunay 369859bfd8dSPatrick Delaunay /* 370859bfd8dSPatrick Delaunay * usb_core_data_out 371859bfd8dSPatrick Delaunay * Handle data OUT stage 372859bfd8dSPatrick Delaunay * pdev: device instance 373859bfd8dSPatrick Delaunay * epnum: endpoint index 374859bfd8dSPatrick Delaunay * pdata: buffer to sent 375859bfd8dSPatrick Delaunay * return : status 376859bfd8dSPatrick Delaunay */ 377859bfd8dSPatrick Delaunay static enum usb_status usb_core_data_out(struct usb_handle *pdev, uint8_t epnum, 378859bfd8dSPatrick Delaunay uint8_t *pdata) 379859bfd8dSPatrick Delaunay { 380859bfd8dSPatrick Delaunay struct usb_endpoint *pep; 381859bfd8dSPatrick Delaunay 382859bfd8dSPatrick Delaunay if (epnum == 0U) { 383859bfd8dSPatrick Delaunay pep = &pdev->ep_out[0]; 384859bfd8dSPatrick Delaunay if (pdev->ep0_state == USBD_EP0_DATA_OUT) { 385859bfd8dSPatrick Delaunay if (pep->rem_length > pep->maxpacket) { 386859bfd8dSPatrick Delaunay pep->rem_length -= pep->maxpacket; 387859bfd8dSPatrick Delaunay 388859bfd8dSPatrick Delaunay usb_core_receive(pdev, 0U, pdata, 389859bfd8dSPatrick Delaunay MIN(pep->rem_length, 390859bfd8dSPatrick Delaunay pep->maxpacket)); 391859bfd8dSPatrick Delaunay } else { 392859bfd8dSPatrick Delaunay if (pdev->class->ep0_rx_ready && 393*867cd155SPankaj Dev (pdev->dev_state == 394*867cd155SPankaj Dev USBD_STATE_CONFIGURED)) { 395859bfd8dSPatrick Delaunay pdev->class->ep0_rx_ready(pdev); 396859bfd8dSPatrick Delaunay } 397859bfd8dSPatrick Delaunay 398859bfd8dSPatrick Delaunay usb_core_transmit_ep0(pdev, NULL, 0U); 399859bfd8dSPatrick Delaunay } 400859bfd8dSPatrick Delaunay } 401859bfd8dSPatrick Delaunay } else if (pdev->class->data_out != NULL && 402859bfd8dSPatrick Delaunay (pdev->dev_state == USBD_STATE_CONFIGURED)) { 403859bfd8dSPatrick Delaunay pdev->class->data_out(pdev, epnum); 404859bfd8dSPatrick Delaunay } 405859bfd8dSPatrick Delaunay 406859bfd8dSPatrick Delaunay return USBD_OK; 407859bfd8dSPatrick Delaunay } 408859bfd8dSPatrick Delaunay 409859bfd8dSPatrick Delaunay /* 410859bfd8dSPatrick Delaunay * usb_core_data_in 411859bfd8dSPatrick Delaunay * Handle data in stage 412859bfd8dSPatrick Delaunay * pdev: device instance 413859bfd8dSPatrick Delaunay * epnum: endpoint index 414859bfd8dSPatrick Delaunay * pdata: buffer to fill 415859bfd8dSPatrick Delaunay * return : status 416859bfd8dSPatrick Delaunay */ 417859bfd8dSPatrick Delaunay static enum usb_status usb_core_data_in(struct usb_handle *pdev, uint8_t epnum, 418859bfd8dSPatrick Delaunay uint8_t *pdata) 419859bfd8dSPatrick Delaunay { 420859bfd8dSPatrick Delaunay if (epnum == 0U) { 421859bfd8dSPatrick Delaunay struct usb_endpoint *pep = &pdev->ep_in[0]; 422859bfd8dSPatrick Delaunay 423859bfd8dSPatrick Delaunay if (pdev->ep0_state == USBD_EP0_DATA_IN) { 424859bfd8dSPatrick Delaunay if (pep->rem_length > pep->maxpacket) { 425859bfd8dSPatrick Delaunay pep->rem_length -= pep->maxpacket; 426859bfd8dSPatrick Delaunay 427859bfd8dSPatrick Delaunay usb_core_transmit(pdev, 0U, pdata, 428859bfd8dSPatrick Delaunay pep->rem_length); 429859bfd8dSPatrick Delaunay 430859bfd8dSPatrick Delaunay /* Prepare EP for premature end of transfer */ 431859bfd8dSPatrick Delaunay usb_core_receive(pdev, 0U, NULL, 0U); 432859bfd8dSPatrick Delaunay } else { 433859bfd8dSPatrick Delaunay /* Last packet is MPS multiple, send ZLP packet */ 434*867cd155SPankaj Dev if ((pep->total_length % pep->maxpacket == 435*867cd155SPankaj Dev 0U) && 436859bfd8dSPatrick Delaunay (pep->total_length >= pep->maxpacket) && 437859bfd8dSPatrick Delaunay (pep->total_length < pdev->ep0_data_len)) { 438859bfd8dSPatrick Delaunay usb_core_transmit(pdev, 0U, NULL, 0U); 439859bfd8dSPatrick Delaunay 440859bfd8dSPatrick Delaunay pdev->ep0_data_len = 0U; 441859bfd8dSPatrick Delaunay 442859bfd8dSPatrick Delaunay /* Prepare endpoint for premature end of transfer */ 443859bfd8dSPatrick Delaunay usb_core_receive(pdev, 0U, NULL, 0U); 444859bfd8dSPatrick Delaunay } else { 445859bfd8dSPatrick Delaunay if (pdev->class->ep0_tx_sent != NULL && 446859bfd8dSPatrick Delaunay (pdev->dev_state == 447859bfd8dSPatrick Delaunay USBD_STATE_CONFIGURED)) { 448859bfd8dSPatrick Delaunay pdev->class->ep0_tx_sent(pdev); 449859bfd8dSPatrick Delaunay } 450859bfd8dSPatrick Delaunay /* Start the transfer */ 451859bfd8dSPatrick Delaunay usb_core_receive_ep0(pdev, NULL, 0U); 452859bfd8dSPatrick Delaunay } 453859bfd8dSPatrick Delaunay } 454859bfd8dSPatrick Delaunay } 455859bfd8dSPatrick Delaunay } else if ((pdev->class->data_in != NULL) && 456859bfd8dSPatrick Delaunay (pdev->dev_state == USBD_STATE_CONFIGURED)) { 457859bfd8dSPatrick Delaunay pdev->class->data_in(pdev, epnum); 458859bfd8dSPatrick Delaunay } 459859bfd8dSPatrick Delaunay 460859bfd8dSPatrick Delaunay return USBD_OK; 461859bfd8dSPatrick Delaunay } 462859bfd8dSPatrick Delaunay 463859bfd8dSPatrick Delaunay /* 464859bfd8dSPatrick Delaunay * usb_core_suspend 465859bfd8dSPatrick Delaunay * Handle suspend event 466859bfd8dSPatrick Delaunay * pdev : device instance 467859bfd8dSPatrick Delaunay * return : status 468859bfd8dSPatrick Delaunay */ 469859bfd8dSPatrick Delaunay static enum usb_status usb_core_suspend(struct usb_handle *pdev) 470859bfd8dSPatrick Delaunay { 471859bfd8dSPatrick Delaunay INFO("USB Suspend mode\n"); 472859bfd8dSPatrick Delaunay pdev->dev_old_state = pdev->dev_state; 473859bfd8dSPatrick Delaunay pdev->dev_state = USBD_STATE_SUSPENDED; 474859bfd8dSPatrick Delaunay 475859bfd8dSPatrick Delaunay return USBD_OK; 476859bfd8dSPatrick Delaunay } 477859bfd8dSPatrick Delaunay 478859bfd8dSPatrick Delaunay /* 479859bfd8dSPatrick Delaunay * usb_core_resume 480859bfd8dSPatrick Delaunay * Handle resume event 481859bfd8dSPatrick Delaunay * pdev : device instance 482859bfd8dSPatrick Delaunay * return : status 483859bfd8dSPatrick Delaunay */ 484859bfd8dSPatrick Delaunay static enum usb_status usb_core_resume(struct usb_handle *pdev) 485859bfd8dSPatrick Delaunay { 486859bfd8dSPatrick Delaunay INFO("USB Resume\n"); 487859bfd8dSPatrick Delaunay pdev->dev_state = pdev->dev_old_state; 488859bfd8dSPatrick Delaunay 489859bfd8dSPatrick Delaunay return USBD_OK; 490859bfd8dSPatrick Delaunay } 491859bfd8dSPatrick Delaunay 492859bfd8dSPatrick Delaunay /* 493859bfd8dSPatrick Delaunay * usb_core_sof 494859bfd8dSPatrick Delaunay * Handle SOF event 495859bfd8dSPatrick Delaunay * pdev : device instance 496859bfd8dSPatrick Delaunay * return : status 497859bfd8dSPatrick Delaunay */ 498859bfd8dSPatrick Delaunay static enum usb_status usb_core_sof(struct usb_handle *pdev) 499859bfd8dSPatrick Delaunay { 500859bfd8dSPatrick Delaunay if (pdev->dev_state == USBD_STATE_CONFIGURED) { 501859bfd8dSPatrick Delaunay if (pdev->class->sof != NULL) { 502859bfd8dSPatrick Delaunay pdev->class->sof(pdev); 503859bfd8dSPatrick Delaunay } 504859bfd8dSPatrick Delaunay } 505859bfd8dSPatrick Delaunay 506859bfd8dSPatrick Delaunay return USBD_OK; 507859bfd8dSPatrick Delaunay } 508859bfd8dSPatrick Delaunay 509859bfd8dSPatrick Delaunay /* 510859bfd8dSPatrick Delaunay * usb_core_disconnect 511859bfd8dSPatrick Delaunay * Handle device disconnection event 512859bfd8dSPatrick Delaunay * pdev : device instance 513859bfd8dSPatrick Delaunay * return : status 514859bfd8dSPatrick Delaunay */ 515859bfd8dSPatrick Delaunay static enum usb_status usb_core_disconnect(struct usb_handle *pdev) 516859bfd8dSPatrick Delaunay { 517859bfd8dSPatrick Delaunay /* Free class resources */ 518859bfd8dSPatrick Delaunay pdev->dev_state = USBD_STATE_DEFAULT; 519859bfd8dSPatrick Delaunay pdev->class->de_init(pdev, pdev->dev_config); 520859bfd8dSPatrick Delaunay 521859bfd8dSPatrick Delaunay return USBD_OK; 522859bfd8dSPatrick Delaunay } 523859bfd8dSPatrick Delaunay 524859bfd8dSPatrick Delaunay enum usb_status usb_core_handle_it(struct usb_handle *pdev) 525859bfd8dSPatrick Delaunay { 526859bfd8dSPatrick Delaunay uint32_t param = 0U; 527859bfd8dSPatrick Delaunay uint32_t len = 0U; 528859bfd8dSPatrick Delaunay struct usbd_ep *ep; 529859bfd8dSPatrick Delaunay 530859bfd8dSPatrick Delaunay switch (pdev->driver->it_handler(pdev->data->instance, ¶m)) { 531859bfd8dSPatrick Delaunay case USB_DATA_OUT: 532859bfd8dSPatrick Delaunay usb_core_data_out(pdev, param, 533859bfd8dSPatrick Delaunay pdev->data->out_ep[param].xfer_buff); 534859bfd8dSPatrick Delaunay break; 535859bfd8dSPatrick Delaunay 536859bfd8dSPatrick Delaunay case USB_DATA_IN: 537859bfd8dSPatrick Delaunay usb_core_data_in(pdev, param, 538859bfd8dSPatrick Delaunay pdev->data->in_ep[param].xfer_buff); 539859bfd8dSPatrick Delaunay break; 540859bfd8dSPatrick Delaunay 541859bfd8dSPatrick Delaunay case USB_SETUP: 542859bfd8dSPatrick Delaunay usb_core_setup_stage(pdev, (uint8_t *)pdev->data->setup); 543859bfd8dSPatrick Delaunay break; 544859bfd8dSPatrick Delaunay 545859bfd8dSPatrick Delaunay case USB_ENUM_DONE: 546859bfd8dSPatrick Delaunay break; 547859bfd8dSPatrick Delaunay 548859bfd8dSPatrick Delaunay case USB_READ_DATA_PACKET: 549859bfd8dSPatrick Delaunay ep = &pdev->data->out_ep[param & USBD_OUT_EPNUM_MASK]; 550859bfd8dSPatrick Delaunay len = (param & USBD_OUT_COUNT_MASK) >> USBD_OUT_COUNT_SHIFT; 551*867cd155SPankaj Dev pdev->driver->read_packet(pdev->data->instance, ep->xfer_buff, 552*867cd155SPankaj Dev len); 553859bfd8dSPatrick Delaunay ep->xfer_buff += len; 554859bfd8dSPatrick Delaunay ep->xfer_count += len; 555859bfd8dSPatrick Delaunay break; 556859bfd8dSPatrick Delaunay 557859bfd8dSPatrick Delaunay case USB_READ_SETUP_PACKET: 558859bfd8dSPatrick Delaunay ep = &pdev->data->out_ep[param & USBD_OUT_EPNUM_MASK]; 559859bfd8dSPatrick Delaunay len = (param & USBD_OUT_COUNT_MASK) >> 0x10; 560859bfd8dSPatrick Delaunay pdev->driver->read_packet(pdev->data->instance, 561859bfd8dSPatrick Delaunay (uint8_t *)pdev->data->setup, 8); 562859bfd8dSPatrick Delaunay ep->xfer_count += len; 563859bfd8dSPatrick Delaunay break; 564859bfd8dSPatrick Delaunay 565859bfd8dSPatrick Delaunay case USB_RESET: 566859bfd8dSPatrick Delaunay pdev->dev_state = USBD_STATE_DEFAULT; 567859bfd8dSPatrick Delaunay break; 568859bfd8dSPatrick Delaunay 569859bfd8dSPatrick Delaunay case USB_RESUME: 570859bfd8dSPatrick Delaunay if (pdev->data->lpm_state == LPM_L1) { 571859bfd8dSPatrick Delaunay pdev->data->lpm_state = LPM_L0; 572859bfd8dSPatrick Delaunay } else { 573859bfd8dSPatrick Delaunay usb_core_resume(pdev); 574859bfd8dSPatrick Delaunay } 575859bfd8dSPatrick Delaunay break; 576859bfd8dSPatrick Delaunay 577859bfd8dSPatrick Delaunay case USB_SUSPEND: 578859bfd8dSPatrick Delaunay usb_core_suspend(pdev); 579859bfd8dSPatrick Delaunay break; 580859bfd8dSPatrick Delaunay 581859bfd8dSPatrick Delaunay case USB_LPM: 582859bfd8dSPatrick Delaunay if (pdev->data->lpm_state == LPM_L0) { 583859bfd8dSPatrick Delaunay pdev->data->lpm_state = LPM_L1; 584859bfd8dSPatrick Delaunay } else { 585859bfd8dSPatrick Delaunay usb_core_suspend(pdev); 586859bfd8dSPatrick Delaunay } 587859bfd8dSPatrick Delaunay break; 588859bfd8dSPatrick Delaunay 589859bfd8dSPatrick Delaunay case USB_SOF: 590859bfd8dSPatrick Delaunay usb_core_sof(pdev); 591859bfd8dSPatrick Delaunay break; 592859bfd8dSPatrick Delaunay 593859bfd8dSPatrick Delaunay case USB_DISCONNECT: 594859bfd8dSPatrick Delaunay usb_core_disconnect(pdev); 595859bfd8dSPatrick Delaunay break; 596859bfd8dSPatrick Delaunay 597859bfd8dSPatrick Delaunay case USB_WRITE_EMPTY: 598*867cd155SPankaj Dev pdev->driver->write_empty_tx_fifo( 599*867cd155SPankaj Dev pdev->data->instance, param, 600859bfd8dSPatrick Delaunay pdev->data->in_ep[param].xfer_len, 601859bfd8dSPatrick Delaunay (uint32_t *)&pdev->data->in_ep[param].xfer_count, 602859bfd8dSPatrick Delaunay pdev->data->in_ep[param].maxpacket, 603859bfd8dSPatrick Delaunay &pdev->data->in_ep[param].xfer_buff); 604859bfd8dSPatrick Delaunay break; 605859bfd8dSPatrick Delaunay 606859bfd8dSPatrick Delaunay case USB_NOTHING: 607859bfd8dSPatrick Delaunay default: 608859bfd8dSPatrick Delaunay break; 609859bfd8dSPatrick Delaunay } 610859bfd8dSPatrick Delaunay 611859bfd8dSPatrick Delaunay return USBD_OK; 612859bfd8dSPatrick Delaunay } 613859bfd8dSPatrick Delaunay 614*867cd155SPankaj Dev static void usb_core_start_xfer(struct usb_handle *pdev, void *handle, 6157ca49284SPatrick Delaunay struct usbd_ep *ep) 6167ca49284SPatrick Delaunay { 6177ca49284SPatrick Delaunay if (ep->num == 0U) { 6187ca49284SPatrick Delaunay pdev->driver->ep0_start_xfer(handle, ep); 6197ca49284SPatrick Delaunay } else { 6207ca49284SPatrick Delaunay pdev->driver->ep_start_xfer(handle, ep); 6217ca49284SPatrick Delaunay } 6227ca49284SPatrick Delaunay } 6237ca49284SPatrick Delaunay 624859bfd8dSPatrick Delaunay /* 625859bfd8dSPatrick Delaunay * usb_core_receive 626859bfd8dSPatrick Delaunay * Receive an amount of data 627859bfd8dSPatrick Delaunay * pdev: USB handle 628859bfd8dSPatrick Delaunay * ep_addr: endpoint address 629859bfd8dSPatrick Delaunay * buf: pointer to the reception buffer 630859bfd8dSPatrick Delaunay * len: amount of data to be received 631859bfd8dSPatrick Delaunay * return : status 632859bfd8dSPatrick Delaunay */ 633859bfd8dSPatrick Delaunay enum usb_status usb_core_receive(struct usb_handle *pdev, uint8_t ep_addr, 634859bfd8dSPatrick Delaunay uint8_t *buf, uint32_t len) 635859bfd8dSPatrick Delaunay { 636859bfd8dSPatrick Delaunay struct usbd_ep *ep; 637859bfd8dSPatrick Delaunay struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data; 638859bfd8dSPatrick Delaunay uint8_t num; 639859bfd8dSPatrick Delaunay 640859bfd8dSPatrick Delaunay num = ep_addr & EP_NUM_MASK; 641859bfd8dSPatrick Delaunay if (num >= USBD_EP_NB) { 642859bfd8dSPatrick Delaunay return USBD_FAIL; 643859bfd8dSPatrick Delaunay } 644859bfd8dSPatrick Delaunay ep = &hpcd->out_ep[num]; 645859bfd8dSPatrick Delaunay 646859bfd8dSPatrick Delaunay /* Setup and start the Xfer */ 647859bfd8dSPatrick Delaunay ep->xfer_buff = buf; 648859bfd8dSPatrick Delaunay ep->xfer_len = len; 649859bfd8dSPatrick Delaunay ep->xfer_count = 0U; 650859bfd8dSPatrick Delaunay ep->is_in = false; 651859bfd8dSPatrick Delaunay ep->num = num; 652859bfd8dSPatrick Delaunay 6537ca49284SPatrick Delaunay usb_core_start_xfer(pdev, hpcd->instance, ep); 654859bfd8dSPatrick Delaunay 655859bfd8dSPatrick Delaunay return USBD_OK; 656859bfd8dSPatrick Delaunay } 657859bfd8dSPatrick Delaunay 658859bfd8dSPatrick Delaunay /* 659859bfd8dSPatrick Delaunay * usb_core_transmit 660859bfd8dSPatrick Delaunay * Send an amount of data 661859bfd8dSPatrick Delaunay * pdev: USB handle 662859bfd8dSPatrick Delaunay * ep_addr: endpoint address 663859bfd8dSPatrick Delaunay * buf: pointer to the transmission buffer 664859bfd8dSPatrick Delaunay * len: amount of data to be sent 665859bfd8dSPatrick Delaunay * return : status 666859bfd8dSPatrick Delaunay */ 667859bfd8dSPatrick Delaunay enum usb_status usb_core_transmit(struct usb_handle *pdev, uint8_t ep_addr, 668859bfd8dSPatrick Delaunay uint8_t *buf, uint32_t len) 669859bfd8dSPatrick Delaunay { 670859bfd8dSPatrick Delaunay struct usbd_ep *ep; 671859bfd8dSPatrick Delaunay struct pcd_handle *hpcd = (struct pcd_handle *)pdev->data; 672859bfd8dSPatrick Delaunay uint8_t num; 673859bfd8dSPatrick Delaunay 674859bfd8dSPatrick Delaunay num = ep_addr & EP_NUM_MASK; 675859bfd8dSPatrick Delaunay if (num >= USBD_EP_NB) { 676859bfd8dSPatrick Delaunay return USBD_FAIL; 677859bfd8dSPatrick Delaunay } 678859bfd8dSPatrick Delaunay ep = &hpcd->in_ep[num]; 679859bfd8dSPatrick Delaunay 680859bfd8dSPatrick Delaunay /* Setup and start the Xfer */ 681859bfd8dSPatrick Delaunay ep->xfer_buff = buf; 682859bfd8dSPatrick Delaunay ep->xfer_len = len; 683859bfd8dSPatrick Delaunay ep->xfer_count = 0U; 684859bfd8dSPatrick Delaunay ep->is_in = true; 685859bfd8dSPatrick Delaunay ep->num = num; 686859bfd8dSPatrick Delaunay 6877ca49284SPatrick Delaunay usb_core_start_xfer(pdev, hpcd->instance, ep); 688859bfd8dSPatrick Delaunay 689859bfd8dSPatrick Delaunay return USBD_OK; 690859bfd8dSPatrick Delaunay } 691859bfd8dSPatrick Delaunay 692859bfd8dSPatrick Delaunay /* 693859bfd8dSPatrick Delaunay * usb_core_receive_ep0 694859bfd8dSPatrick Delaunay * Receive an amount of data on ep0 695859bfd8dSPatrick Delaunay * pdev: USB handle 696859bfd8dSPatrick Delaunay * buf: pointer to the reception buffer 697859bfd8dSPatrick Delaunay * len: amount of data to be received 698859bfd8dSPatrick Delaunay * return : status 699859bfd8dSPatrick Delaunay */ 700859bfd8dSPatrick Delaunay enum usb_status usb_core_receive_ep0(struct usb_handle *pdev, uint8_t *buf, 701859bfd8dSPatrick Delaunay uint32_t len) 702859bfd8dSPatrick Delaunay { 703859bfd8dSPatrick Delaunay /* Prepare the reception of the buffer over EP0 */ 704859bfd8dSPatrick Delaunay if (len != 0U) { 705859bfd8dSPatrick Delaunay pdev->ep0_state = USBD_EP0_DATA_OUT; 706859bfd8dSPatrick Delaunay } else { 707859bfd8dSPatrick Delaunay pdev->ep0_state = USBD_EP0_STATUS_OUT; 708859bfd8dSPatrick Delaunay } 709859bfd8dSPatrick Delaunay 710859bfd8dSPatrick Delaunay pdev->ep_out[0].total_length = len; 711*867cd155SPankaj Dev #ifdef USB_CORE_AVOID_PACKET_SPLIT_MPS 712*867cd155SPankaj Dev pdev->ep_out[0].rem_length = 0; 713*867cd155SPankaj Dev #else 714859bfd8dSPatrick Delaunay pdev->ep_out[0].rem_length = len; 715*867cd155SPankaj Dev #endif 716859bfd8dSPatrick Delaunay 717859bfd8dSPatrick Delaunay /* Start the transfer */ 718859bfd8dSPatrick Delaunay return usb_core_receive(pdev, 0U, buf, len); 719859bfd8dSPatrick Delaunay } 720859bfd8dSPatrick Delaunay 721859bfd8dSPatrick Delaunay /* 722859bfd8dSPatrick Delaunay * usb_core_transmit_ep0 723859bfd8dSPatrick Delaunay * Send an amount of data on ep0 724859bfd8dSPatrick Delaunay * pdev: USB handle 725859bfd8dSPatrick Delaunay * buf: pointer to the transmission buffer 726859bfd8dSPatrick Delaunay * len: amount of data to be sent 727859bfd8dSPatrick Delaunay * return : status 728859bfd8dSPatrick Delaunay */ 729859bfd8dSPatrick Delaunay enum usb_status usb_core_transmit_ep0(struct usb_handle *pdev, uint8_t *buf, 730859bfd8dSPatrick Delaunay uint32_t len) 731859bfd8dSPatrick Delaunay { 732859bfd8dSPatrick Delaunay /* Set EP0 State */ 733859bfd8dSPatrick Delaunay if (len != 0U) { 734859bfd8dSPatrick Delaunay pdev->ep0_state = USBD_EP0_DATA_IN; 735859bfd8dSPatrick Delaunay } else { 736859bfd8dSPatrick Delaunay pdev->ep0_state = USBD_EP0_STATUS_IN; 737859bfd8dSPatrick Delaunay } 738859bfd8dSPatrick Delaunay 739859bfd8dSPatrick Delaunay pdev->ep_in[0].total_length = len; 740*867cd155SPankaj Dev #ifdef USB_CORE_AVOID_PACKET_SPLIT_MPS 741*867cd155SPankaj Dev pdev->ep_in[0].rem_length = 0; 742*867cd155SPankaj Dev #else 743859bfd8dSPatrick Delaunay pdev->ep_in[0].rem_length = len; 744*867cd155SPankaj Dev #endif 745859bfd8dSPatrick Delaunay 746859bfd8dSPatrick Delaunay /* Start the transfer */ 747859bfd8dSPatrick Delaunay return usb_core_transmit(pdev, 0U, buf, len); 748859bfd8dSPatrick Delaunay } 749859bfd8dSPatrick Delaunay 750859bfd8dSPatrick Delaunay /* 751859bfd8dSPatrick Delaunay * usb_core_ctl_error 752859bfd8dSPatrick Delaunay * Handle USB low level error 753859bfd8dSPatrick Delaunay * pdev: device instance 754859bfd8dSPatrick Delaunay * req: usb request 755859bfd8dSPatrick Delaunay * return : None 756859bfd8dSPatrick Delaunay */ 757859bfd8dSPatrick Delaunay 758859bfd8dSPatrick Delaunay void usb_core_ctl_error(struct usb_handle *pdev) 759859bfd8dSPatrick Delaunay { 760859bfd8dSPatrick Delaunay ERROR("%s : Send an ERROR\n", __func__); 761859bfd8dSPatrick Delaunay usb_core_set_stall(pdev, EP0_IN); 762859bfd8dSPatrick Delaunay usb_core_set_stall(pdev, EP0_OUT); 763859bfd8dSPatrick Delaunay } 764859bfd8dSPatrick Delaunay 765859bfd8dSPatrick Delaunay /* 766859bfd8dSPatrick Delaunay * usb_core_start 767859bfd8dSPatrick Delaunay * Start the USB device core. 768859bfd8dSPatrick Delaunay * pdev: Device Handle 769859bfd8dSPatrick Delaunay * return : USBD Status 770859bfd8dSPatrick Delaunay */ 771859bfd8dSPatrick Delaunay enum usb_status usb_core_start(struct usb_handle *pdev) 772859bfd8dSPatrick Delaunay { 773859bfd8dSPatrick Delaunay /* Start the low level driver */ 774859bfd8dSPatrick Delaunay pdev->driver->start_device(pdev->data->instance); 775859bfd8dSPatrick Delaunay 776859bfd8dSPatrick Delaunay return USBD_OK; 777859bfd8dSPatrick Delaunay } 778859bfd8dSPatrick Delaunay 779859bfd8dSPatrick Delaunay /* 780859bfd8dSPatrick Delaunay * usb_core_stop 781859bfd8dSPatrick Delaunay * Stop the USB device core. 782859bfd8dSPatrick Delaunay * pdev: Device Handle 783859bfd8dSPatrick Delaunay * return : USBD Status 784859bfd8dSPatrick Delaunay */ 785859bfd8dSPatrick Delaunay enum usb_status usb_core_stop(struct usb_handle *pdev) 786859bfd8dSPatrick Delaunay { 787859bfd8dSPatrick Delaunay /* Free class resources */ 788859bfd8dSPatrick Delaunay pdev->class->de_init(pdev, pdev->dev_config); 789859bfd8dSPatrick Delaunay 790859bfd8dSPatrick Delaunay /* Stop the low level driver */ 791859bfd8dSPatrick Delaunay pdev->driver->stop_device(pdev->data->instance); 792859bfd8dSPatrick Delaunay 793859bfd8dSPatrick Delaunay return USBD_OK; 794859bfd8dSPatrick Delaunay } 795859bfd8dSPatrick Delaunay 796859bfd8dSPatrick Delaunay /* 797859bfd8dSPatrick Delaunay * register_usb_driver 798859bfd8dSPatrick Delaunay * Stop the USB device core. 799859bfd8dSPatrick Delaunay * pdev: Device Handle 800859bfd8dSPatrick Delaunay * pcd_handle: PCD handle 801859bfd8dSPatrick Delaunay * driver: USB driver 802859bfd8dSPatrick Delaunay * driver_handle: USB driver handle 803859bfd8dSPatrick Delaunay * return : USBD Status 804859bfd8dSPatrick Delaunay */ 805859bfd8dSPatrick Delaunay enum usb_status register_usb_driver(struct usb_handle *pdev, 806859bfd8dSPatrick Delaunay struct pcd_handle *pcd_handle, 807859bfd8dSPatrick Delaunay const struct usb_driver *driver, 808859bfd8dSPatrick Delaunay void *driver_handle) 809859bfd8dSPatrick Delaunay { 810859bfd8dSPatrick Delaunay uint8_t i; 811859bfd8dSPatrick Delaunay 812859bfd8dSPatrick Delaunay assert(pdev != NULL); 813859bfd8dSPatrick Delaunay assert(pcd_handle != NULL); 814859bfd8dSPatrick Delaunay assert(driver != NULL); 815859bfd8dSPatrick Delaunay assert(driver_handle != NULL); 816859bfd8dSPatrick Delaunay 817859bfd8dSPatrick Delaunay /* Free class resources */ 818859bfd8dSPatrick Delaunay pdev->driver = driver; 819859bfd8dSPatrick Delaunay pdev->data = pcd_handle; 820859bfd8dSPatrick Delaunay pdev->data->instance = driver_handle; 821859bfd8dSPatrick Delaunay pdev->dev_state = USBD_STATE_DEFAULT; 822859bfd8dSPatrick Delaunay pdev->ep0_state = USBD_EP0_IDLE; 823859bfd8dSPatrick Delaunay 824859bfd8dSPatrick Delaunay /* Copy endpoint information */ 825859bfd8dSPatrick Delaunay for (i = 0U; i < USBD_EP_NB; i++) { 826859bfd8dSPatrick Delaunay pdev->ep_in[i].maxpacket = pdev->data->in_ep[i].maxpacket; 827859bfd8dSPatrick Delaunay pdev->ep_out[i].maxpacket = pdev->data->out_ep[i].maxpacket; 828859bfd8dSPatrick Delaunay } 829859bfd8dSPatrick Delaunay 830859bfd8dSPatrick Delaunay return USBD_OK; 831859bfd8dSPatrick Delaunay } 832859bfd8dSPatrick Delaunay 833859bfd8dSPatrick Delaunay /* 834859bfd8dSPatrick Delaunay * register_platform 835859bfd8dSPatrick Delaunay * Register the USB device core. 836859bfd8dSPatrick Delaunay * pdev: Device Handle 837859bfd8dSPatrick Delaunay * plat_call_back: callback 838859bfd8dSPatrick Delaunay * return : USBD Status 839859bfd8dSPatrick Delaunay */ 840859bfd8dSPatrick Delaunay enum usb_status register_platform(struct usb_handle *pdev, 841859bfd8dSPatrick Delaunay const struct usb_desc *plat_call_back) 842859bfd8dSPatrick Delaunay { 843859bfd8dSPatrick Delaunay assert(pdev != NULL); 844859bfd8dSPatrick Delaunay assert(plat_call_back != NULL); 845859bfd8dSPatrick Delaunay 846859bfd8dSPatrick Delaunay /* Save platform info in class resources */ 847859bfd8dSPatrick Delaunay pdev->desc = plat_call_back; 848859bfd8dSPatrick Delaunay 849859bfd8dSPatrick Delaunay return USBD_OK; 850859bfd8dSPatrick Delaunay } 851