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