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