1*efbd65faSPatrick Delaunay /* 2*efbd65faSPatrick Delaunay * Copyright (c) 2021, STMicroelectronics - All Rights Reserved 3*efbd65faSPatrick Delaunay * 4*efbd65faSPatrick Delaunay * SPDX-License-Identifier: BSD-3-Clause 5*efbd65faSPatrick Delaunay */ 6*efbd65faSPatrick Delaunay 7*efbd65faSPatrick Delaunay #include <errno.h> 8*efbd65faSPatrick Delaunay #include <string.h> 9*efbd65faSPatrick Delaunay 10*efbd65faSPatrick Delaunay #include <common/debug.h> 11*efbd65faSPatrick Delaunay 12*efbd65faSPatrick Delaunay #include <platform_def.h> 13*efbd65faSPatrick Delaunay #include <usb_dfu.h> 14*efbd65faSPatrick Delaunay 15*efbd65faSPatrick Delaunay /* Device states as defined in DFU spec */ 16*efbd65faSPatrick Delaunay #define STATE_APP_IDLE 0 17*efbd65faSPatrick Delaunay #define STATE_APP_DETACH 1 18*efbd65faSPatrick Delaunay #define STATE_DFU_IDLE 2 19*efbd65faSPatrick Delaunay #define STATE_DFU_DNLOAD_SYNC 3 20*efbd65faSPatrick Delaunay #define STATE_DFU_DNLOAD_BUSY 4 21*efbd65faSPatrick Delaunay #define STATE_DFU_DNLOAD_IDLE 5 22*efbd65faSPatrick Delaunay #define STATE_DFU_MANIFEST_SYNC 6 23*efbd65faSPatrick Delaunay #define STATE_DFU_MANIFEST 7 24*efbd65faSPatrick Delaunay #define STATE_DFU_MANIFEST_WAIT_RESET 8 25*efbd65faSPatrick Delaunay #define STATE_DFU_UPLOAD_IDLE 9 26*efbd65faSPatrick Delaunay #define STATE_DFU_ERROR 10 27*efbd65faSPatrick Delaunay 28*efbd65faSPatrick Delaunay /* DFU errors */ 29*efbd65faSPatrick Delaunay #define DFU_ERROR_NONE 0x00 30*efbd65faSPatrick Delaunay #define DFU_ERROR_TARGET 0x01 31*efbd65faSPatrick Delaunay #define DFU_ERROR_FILE 0x02 32*efbd65faSPatrick Delaunay #define DFU_ERROR_WRITE 0x03 33*efbd65faSPatrick Delaunay #define DFU_ERROR_ERASE 0x04 34*efbd65faSPatrick Delaunay #define DFU_ERROR_CHECK_ERASED 0x05 35*efbd65faSPatrick Delaunay #define DFU_ERROR_PROG 0x06 36*efbd65faSPatrick Delaunay #define DFU_ERROR_VERIFY 0x07 37*efbd65faSPatrick Delaunay #define DFU_ERROR_ADDRESS 0x08 38*efbd65faSPatrick Delaunay #define DFU_ERROR_NOTDONE 0x09 39*efbd65faSPatrick Delaunay #define DFU_ERROR_FIRMWARE 0x0A 40*efbd65faSPatrick Delaunay #define DFU_ERROR_VENDOR 0x0B 41*efbd65faSPatrick Delaunay #define DFU_ERROR_USB 0x0C 42*efbd65faSPatrick Delaunay #define DFU_ERROR_POR 0x0D 43*efbd65faSPatrick Delaunay #define DFU_ERROR_UNKNOWN 0x0E 44*efbd65faSPatrick Delaunay #define DFU_ERROR_STALLEDPKT 0x0F 45*efbd65faSPatrick Delaunay 46*efbd65faSPatrick Delaunay /* DFU request */ 47*efbd65faSPatrick Delaunay #define DFU_DETACH 0 48*efbd65faSPatrick Delaunay #define DFU_DNLOAD 1 49*efbd65faSPatrick Delaunay #define DFU_UPLOAD 2 50*efbd65faSPatrick Delaunay #define DFU_GETSTATUS 3 51*efbd65faSPatrick Delaunay #define DFU_CLRSTATUS 4 52*efbd65faSPatrick Delaunay #define DFU_GETSTATE 5 53*efbd65faSPatrick Delaunay #define DFU_ABORT 6 54*efbd65faSPatrick Delaunay 55*efbd65faSPatrick Delaunay static bool usb_dfu_detach_req; 56*efbd65faSPatrick Delaunay 57*efbd65faSPatrick Delaunay /* 58*efbd65faSPatrick Delaunay * usb_dfu_init 59*efbd65faSPatrick Delaunay * Initialize the DFU interface 60*efbd65faSPatrick Delaunay * pdev: device instance 61*efbd65faSPatrick Delaunay * cfgidx: Configuration index 62*efbd65faSPatrick Delaunay * return: status 63*efbd65faSPatrick Delaunay */ 64*efbd65faSPatrick Delaunay static uint8_t usb_dfu_init(struct usb_handle *pdev, uint8_t cfgidx) 65*efbd65faSPatrick Delaunay { 66*efbd65faSPatrick Delaunay (void)pdev; 67*efbd65faSPatrick Delaunay (void)cfgidx; 68*efbd65faSPatrick Delaunay 69*efbd65faSPatrick Delaunay /* Nothing to do in this stage */ 70*efbd65faSPatrick Delaunay return USBD_OK; 71*efbd65faSPatrick Delaunay } 72*efbd65faSPatrick Delaunay 73*efbd65faSPatrick Delaunay /* 74*efbd65faSPatrick Delaunay * usb_dfu_de_init 75*efbd65faSPatrick Delaunay * De-Initialize the DFU layer 76*efbd65faSPatrick Delaunay * pdev: device instance 77*efbd65faSPatrick Delaunay * cfgidx: Configuration index 78*efbd65faSPatrick Delaunay * return: status 79*efbd65faSPatrick Delaunay */ 80*efbd65faSPatrick Delaunay static uint8_t usb_dfu_de_init(struct usb_handle *pdev, uint8_t cfgidx) 81*efbd65faSPatrick Delaunay { 82*efbd65faSPatrick Delaunay (void)pdev; 83*efbd65faSPatrick Delaunay (void)cfgidx; 84*efbd65faSPatrick Delaunay 85*efbd65faSPatrick Delaunay /* Nothing to do in this stage */ 86*efbd65faSPatrick Delaunay return USBD_OK; 87*efbd65faSPatrick Delaunay } 88*efbd65faSPatrick Delaunay 89*efbd65faSPatrick Delaunay /* 90*efbd65faSPatrick Delaunay * usb_dfu_data_in 91*efbd65faSPatrick Delaunay * handle data IN Stage 92*efbd65faSPatrick Delaunay * pdev: device instance 93*efbd65faSPatrick Delaunay * epnum: endpoint index 94*efbd65faSPatrick Delaunay * return: status 95*efbd65faSPatrick Delaunay */ 96*efbd65faSPatrick Delaunay static uint8_t usb_dfu_data_in(struct usb_handle *pdev, uint8_t epnum) 97*efbd65faSPatrick Delaunay { 98*efbd65faSPatrick Delaunay (void)pdev; 99*efbd65faSPatrick Delaunay (void)epnum; 100*efbd65faSPatrick Delaunay 101*efbd65faSPatrick Delaunay return USBD_OK; 102*efbd65faSPatrick Delaunay } 103*efbd65faSPatrick Delaunay 104*efbd65faSPatrick Delaunay /* 105*efbd65faSPatrick Delaunay * usb_dfu_ep0_rx_ready 106*efbd65faSPatrick Delaunay * handle EP0 Rx Ready event 107*efbd65faSPatrick Delaunay * pdev: device 108*efbd65faSPatrick Delaunay * return: status 109*efbd65faSPatrick Delaunay */ 110*efbd65faSPatrick Delaunay static uint8_t usb_dfu_ep0_rx_ready(struct usb_handle *pdev) 111*efbd65faSPatrick Delaunay { 112*efbd65faSPatrick Delaunay (void)pdev; 113*efbd65faSPatrick Delaunay 114*efbd65faSPatrick Delaunay return USBD_OK; 115*efbd65faSPatrick Delaunay } 116*efbd65faSPatrick Delaunay 117*efbd65faSPatrick Delaunay /* 118*efbd65faSPatrick Delaunay * usb_dfu_ep0_tx_ready 119*efbd65faSPatrick Delaunay * handle EP0 TRx Ready event 120*efbd65faSPatrick Delaunay * pdev: device instance 121*efbd65faSPatrick Delaunay * return: status 122*efbd65faSPatrick Delaunay */ 123*efbd65faSPatrick Delaunay static uint8_t usb_dfu_ep0_tx_ready(struct usb_handle *pdev) 124*efbd65faSPatrick Delaunay { 125*efbd65faSPatrick Delaunay (void)pdev; 126*efbd65faSPatrick Delaunay 127*efbd65faSPatrick Delaunay return USBD_OK; 128*efbd65faSPatrick Delaunay } 129*efbd65faSPatrick Delaunay 130*efbd65faSPatrick Delaunay /* 131*efbd65faSPatrick Delaunay * usb_dfu_sof 132*efbd65faSPatrick Delaunay * handle SOF event 133*efbd65faSPatrick Delaunay * pdev: device instance 134*efbd65faSPatrick Delaunay * return: status 135*efbd65faSPatrick Delaunay */ 136*efbd65faSPatrick Delaunay static uint8_t usb_dfu_sof(struct usb_handle *pdev) 137*efbd65faSPatrick Delaunay { 138*efbd65faSPatrick Delaunay (void)pdev; 139*efbd65faSPatrick Delaunay 140*efbd65faSPatrick Delaunay return USBD_OK; 141*efbd65faSPatrick Delaunay } 142*efbd65faSPatrick Delaunay 143*efbd65faSPatrick Delaunay /* 144*efbd65faSPatrick Delaunay * usb_dfu_iso_in_incomplete 145*efbd65faSPatrick Delaunay * handle data ISO IN Incomplete event 146*efbd65faSPatrick Delaunay * pdev: device instance 147*efbd65faSPatrick Delaunay * epnum: endpoint index 148*efbd65faSPatrick Delaunay * return: status 149*efbd65faSPatrick Delaunay */ 150*efbd65faSPatrick Delaunay static uint8_t usb_dfu_iso_in_incomplete(struct usb_handle *pdev, uint8_t epnum) 151*efbd65faSPatrick Delaunay { 152*efbd65faSPatrick Delaunay (void)pdev; 153*efbd65faSPatrick Delaunay (void)epnum; 154*efbd65faSPatrick Delaunay 155*efbd65faSPatrick Delaunay return USBD_OK; 156*efbd65faSPatrick Delaunay } 157*efbd65faSPatrick Delaunay 158*efbd65faSPatrick Delaunay /* 159*efbd65faSPatrick Delaunay * usb_dfu_iso_out_incomplete 160*efbd65faSPatrick Delaunay * handle data ISO OUT Incomplete event 161*efbd65faSPatrick Delaunay * pdev: device instance 162*efbd65faSPatrick Delaunay * epnum: endpoint index 163*efbd65faSPatrick Delaunay * return: status 164*efbd65faSPatrick Delaunay */ 165*efbd65faSPatrick Delaunay static uint8_t usb_dfu_iso_out_incomplete(struct usb_handle *pdev, 166*efbd65faSPatrick Delaunay uint8_t epnum) 167*efbd65faSPatrick Delaunay { 168*efbd65faSPatrick Delaunay (void)pdev; 169*efbd65faSPatrick Delaunay (void)epnum; 170*efbd65faSPatrick Delaunay 171*efbd65faSPatrick Delaunay return USBD_OK; 172*efbd65faSPatrick Delaunay } 173*efbd65faSPatrick Delaunay 174*efbd65faSPatrick Delaunay /* 175*efbd65faSPatrick Delaunay * usb_dfu_data_out 176*efbd65faSPatrick Delaunay * handle data OUT Stage 177*efbd65faSPatrick Delaunay * pdev: device instance 178*efbd65faSPatrick Delaunay * epnum: endpoint index 179*efbd65faSPatrick Delaunay * return: status 180*efbd65faSPatrick Delaunay */ 181*efbd65faSPatrick Delaunay static uint8_t usb_dfu_data_out(struct usb_handle *pdev, uint8_t epnum) 182*efbd65faSPatrick Delaunay { 183*efbd65faSPatrick Delaunay (void)pdev; 184*efbd65faSPatrick Delaunay (void)epnum; 185*efbd65faSPatrick Delaunay 186*efbd65faSPatrick Delaunay return USBD_OK; 187*efbd65faSPatrick Delaunay } 188*efbd65faSPatrick Delaunay 189*efbd65faSPatrick Delaunay /* 190*efbd65faSPatrick Delaunay * usb_dfu_detach 191*efbd65faSPatrick Delaunay * Handles the DFU DETACH request. 192*efbd65faSPatrick Delaunay * pdev: device instance 193*efbd65faSPatrick Delaunay * req: pointer to the request structure. 194*efbd65faSPatrick Delaunay */ 195*efbd65faSPatrick Delaunay static void usb_dfu_detach(struct usb_handle *pdev, struct usb_setup_req *req) 196*efbd65faSPatrick Delaunay { 197*efbd65faSPatrick Delaunay struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; 198*efbd65faSPatrick Delaunay 199*efbd65faSPatrick Delaunay INFO("Receive DFU Detach\n"); 200*efbd65faSPatrick Delaunay 201*efbd65faSPatrick Delaunay if ((hdfu->dev_state == STATE_DFU_IDLE) || 202*efbd65faSPatrick Delaunay (hdfu->dev_state == STATE_DFU_DNLOAD_SYNC) || 203*efbd65faSPatrick Delaunay (hdfu->dev_state == STATE_DFU_DNLOAD_IDLE) || 204*efbd65faSPatrick Delaunay (hdfu->dev_state == STATE_DFU_MANIFEST_SYNC) || 205*efbd65faSPatrick Delaunay (hdfu->dev_state == STATE_DFU_UPLOAD_IDLE)) { 206*efbd65faSPatrick Delaunay /* Update the state machine */ 207*efbd65faSPatrick Delaunay hdfu->dev_state = STATE_DFU_IDLE; 208*efbd65faSPatrick Delaunay hdfu->dev_status = DFU_ERROR_NONE; 209*efbd65faSPatrick Delaunay } 210*efbd65faSPatrick Delaunay 211*efbd65faSPatrick Delaunay usb_dfu_detach_req = true; 212*efbd65faSPatrick Delaunay } 213*efbd65faSPatrick Delaunay 214*efbd65faSPatrick Delaunay /* 215*efbd65faSPatrick Delaunay * usb_dfu_download 216*efbd65faSPatrick Delaunay * Handles the DFU DNLOAD request. 217*efbd65faSPatrick Delaunay * pdev: device instance 218*efbd65faSPatrick Delaunay * req: pointer to the request structure 219*efbd65faSPatrick Delaunay */ 220*efbd65faSPatrick Delaunay static void usb_dfu_download(struct usb_handle *pdev, struct usb_setup_req *req) 221*efbd65faSPatrick Delaunay { 222*efbd65faSPatrick Delaunay struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; 223*efbd65faSPatrick Delaunay uintptr_t data_ptr; 224*efbd65faSPatrick Delaunay uint32_t length; 225*efbd65faSPatrick Delaunay int ret; 226*efbd65faSPatrick Delaunay 227*efbd65faSPatrick Delaunay /* Data setup request */ 228*efbd65faSPatrick Delaunay if (req->length > 0) { 229*efbd65faSPatrick Delaunay /* Unsupported state */ 230*efbd65faSPatrick Delaunay if ((hdfu->dev_state != STATE_DFU_IDLE) && 231*efbd65faSPatrick Delaunay (hdfu->dev_state != STATE_DFU_DNLOAD_IDLE)) { 232*efbd65faSPatrick Delaunay /* Call the error management function (command will be nacked) */ 233*efbd65faSPatrick Delaunay usb_core_ctl_error(pdev); 234*efbd65faSPatrick Delaunay return; 235*efbd65faSPatrick Delaunay } 236*efbd65faSPatrick Delaunay 237*efbd65faSPatrick Delaunay /* Get the data address */ 238*efbd65faSPatrick Delaunay length = req->length; 239*efbd65faSPatrick Delaunay ret = hdfu->callback->download(hdfu->alt_setting, &data_ptr, 240*efbd65faSPatrick Delaunay &length, pdev->user_data); 241*efbd65faSPatrick Delaunay if (ret == 0U) { 242*efbd65faSPatrick Delaunay /* Update the state machine */ 243*efbd65faSPatrick Delaunay hdfu->dev_state = STATE_DFU_DNLOAD_SYNC; 244*efbd65faSPatrick Delaunay /* Start the transfer */ 245*efbd65faSPatrick Delaunay usb_core_receive_ep0(pdev, (uint8_t *)data_ptr, length); 246*efbd65faSPatrick Delaunay } else { 247*efbd65faSPatrick Delaunay usb_core_ctl_error(pdev); 248*efbd65faSPatrick Delaunay } 249*efbd65faSPatrick Delaunay } else { 250*efbd65faSPatrick Delaunay /* End of DNLOAD operation*/ 251*efbd65faSPatrick Delaunay if (hdfu->dev_state != STATE_DFU_DNLOAD_IDLE) { 252*efbd65faSPatrick Delaunay /* Call the error management function (command will be nacked) */ 253*efbd65faSPatrick Delaunay usb_core_ctl_error(pdev); 254*efbd65faSPatrick Delaunay return; 255*efbd65faSPatrick Delaunay } 256*efbd65faSPatrick Delaunay /* End of DNLOAD operation*/ 257*efbd65faSPatrick Delaunay hdfu->dev_state = STATE_DFU_MANIFEST_SYNC; 258*efbd65faSPatrick Delaunay ret = hdfu->callback->manifestation(hdfu->alt_setting, pdev->user_data); 259*efbd65faSPatrick Delaunay if (ret == 0U) { 260*efbd65faSPatrick Delaunay hdfu->dev_state = STATE_DFU_MANIFEST_SYNC; 261*efbd65faSPatrick Delaunay } else { 262*efbd65faSPatrick Delaunay usb_core_ctl_error(pdev); 263*efbd65faSPatrick Delaunay } 264*efbd65faSPatrick Delaunay } 265*efbd65faSPatrick Delaunay } 266*efbd65faSPatrick Delaunay 267*efbd65faSPatrick Delaunay /* 268*efbd65faSPatrick Delaunay * usb_dfu_upload 269*efbd65faSPatrick Delaunay * Handles the DFU UPLOAD request. 270*efbd65faSPatrick Delaunay * pdev: instance 271*efbd65faSPatrick Delaunay * req: pointer to the request structure 272*efbd65faSPatrick Delaunay */ 273*efbd65faSPatrick Delaunay static void usb_dfu_upload(struct usb_handle *pdev, struct usb_setup_req *req) 274*efbd65faSPatrick Delaunay { 275*efbd65faSPatrick Delaunay struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; 276*efbd65faSPatrick Delaunay uintptr_t data_ptr; 277*efbd65faSPatrick Delaunay uint32_t length; 278*efbd65faSPatrick Delaunay int ret; 279*efbd65faSPatrick Delaunay 280*efbd65faSPatrick Delaunay /* Data setup request */ 281*efbd65faSPatrick Delaunay if (req->length == 0) { 282*efbd65faSPatrick Delaunay /* No Data setup request */ 283*efbd65faSPatrick Delaunay hdfu->dev_state = STATE_DFU_IDLE; 284*efbd65faSPatrick Delaunay return; 285*efbd65faSPatrick Delaunay } 286*efbd65faSPatrick Delaunay 287*efbd65faSPatrick Delaunay /* Unsupported state */ 288*efbd65faSPatrick Delaunay if ((hdfu->dev_state != STATE_DFU_IDLE) && (hdfu->dev_state != STATE_DFU_UPLOAD_IDLE)) { 289*efbd65faSPatrick Delaunay ERROR("UPLOAD : Unsupported State\n"); 290*efbd65faSPatrick Delaunay /* Call the error management function (command will be nacked) */ 291*efbd65faSPatrick Delaunay usb_core_ctl_error(pdev); 292*efbd65faSPatrick Delaunay return; 293*efbd65faSPatrick Delaunay } 294*efbd65faSPatrick Delaunay 295*efbd65faSPatrick Delaunay /* Update the data address */ 296*efbd65faSPatrick Delaunay length = req->length; 297*efbd65faSPatrick Delaunay ret = hdfu->callback->upload(hdfu->alt_setting, &data_ptr, &length, pdev->user_data); 298*efbd65faSPatrick Delaunay if (ret == 0U) { 299*efbd65faSPatrick Delaunay /* Short frame */ 300*efbd65faSPatrick Delaunay hdfu->dev_state = (req->length > length) ? STATE_DFU_IDLE : STATE_DFU_UPLOAD_IDLE; 301*efbd65faSPatrick Delaunay 302*efbd65faSPatrick Delaunay /* Start the transfer */ 303*efbd65faSPatrick Delaunay usb_core_transmit_ep0(pdev, (uint8_t *)data_ptr, length); 304*efbd65faSPatrick Delaunay } else { 305*efbd65faSPatrick Delaunay ERROR("UPLOAD : bad block %i on alt %i\n", req->value, req->index); 306*efbd65faSPatrick Delaunay hdfu->dev_state = STATE_DFU_ERROR; 307*efbd65faSPatrick Delaunay hdfu->dev_status = DFU_ERROR_STALLEDPKT; 308*efbd65faSPatrick Delaunay 309*efbd65faSPatrick Delaunay /* Call the error management function (command will be nacked) */ 310*efbd65faSPatrick Delaunay usb_core_ctl_error(pdev); 311*efbd65faSPatrick Delaunay } 312*efbd65faSPatrick Delaunay } 313*efbd65faSPatrick Delaunay 314*efbd65faSPatrick Delaunay /* 315*efbd65faSPatrick Delaunay * usb_dfu_get_status 316*efbd65faSPatrick Delaunay * Handles the DFU GETSTATUS request. 317*efbd65faSPatrick Delaunay * pdev: instance 318*efbd65faSPatrick Delaunay */ 319*efbd65faSPatrick Delaunay static void usb_dfu_get_status(struct usb_handle *pdev) 320*efbd65faSPatrick Delaunay { 321*efbd65faSPatrick Delaunay struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; 322*efbd65faSPatrick Delaunay 323*efbd65faSPatrick Delaunay hdfu->status[0] = hdfu->dev_status; /* bStatus */ 324*efbd65faSPatrick Delaunay hdfu->status[1] = 0; /* bwPollTimeout[3] */ 325*efbd65faSPatrick Delaunay hdfu->status[2] = 0; 326*efbd65faSPatrick Delaunay hdfu->status[3] = 0; 327*efbd65faSPatrick Delaunay hdfu->status[4] = hdfu->dev_state; /* bState */ 328*efbd65faSPatrick Delaunay hdfu->status[5] = 0; /* iString */ 329*efbd65faSPatrick Delaunay 330*efbd65faSPatrick Delaunay /* next step */ 331*efbd65faSPatrick Delaunay switch (hdfu->dev_state) { 332*efbd65faSPatrick Delaunay case STATE_DFU_DNLOAD_SYNC: 333*efbd65faSPatrick Delaunay hdfu->dev_state = STATE_DFU_DNLOAD_IDLE; 334*efbd65faSPatrick Delaunay break; 335*efbd65faSPatrick Delaunay case STATE_DFU_MANIFEST_SYNC: 336*efbd65faSPatrick Delaunay /* the device is 'ManifestationTolerant' */ 337*efbd65faSPatrick Delaunay hdfu->status[4] = STATE_DFU_MANIFEST; 338*efbd65faSPatrick Delaunay hdfu->status[1] = 1U; /* bwPollTimeout = 1ms */ 339*efbd65faSPatrick Delaunay hdfu->dev_state = STATE_DFU_IDLE; 340*efbd65faSPatrick Delaunay break; 341*efbd65faSPatrick Delaunay 342*efbd65faSPatrick Delaunay default: 343*efbd65faSPatrick Delaunay break; 344*efbd65faSPatrick Delaunay } 345*efbd65faSPatrick Delaunay 346*efbd65faSPatrick Delaunay /* Start the transfer */ 347*efbd65faSPatrick Delaunay usb_core_transmit_ep0(pdev, (uint8_t *)&hdfu->status[0], sizeof(hdfu->status)); 348*efbd65faSPatrick Delaunay } 349*efbd65faSPatrick Delaunay 350*efbd65faSPatrick Delaunay /* 351*efbd65faSPatrick Delaunay * usb_dfu_clear_status 352*efbd65faSPatrick Delaunay * Handles the DFU CLRSTATUS request. 353*efbd65faSPatrick Delaunay * pdev: device instance 354*efbd65faSPatrick Delaunay */ 355*efbd65faSPatrick Delaunay static void usb_dfu_clear_status(struct usb_handle *pdev) 356*efbd65faSPatrick Delaunay { 357*efbd65faSPatrick Delaunay struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; 358*efbd65faSPatrick Delaunay 359*efbd65faSPatrick Delaunay if (hdfu->dev_state == STATE_DFU_ERROR) { 360*efbd65faSPatrick Delaunay hdfu->dev_state = STATE_DFU_IDLE; 361*efbd65faSPatrick Delaunay hdfu->dev_status = DFU_ERROR_NONE; 362*efbd65faSPatrick Delaunay } else { 363*efbd65faSPatrick Delaunay /* State Error */ 364*efbd65faSPatrick Delaunay hdfu->dev_state = STATE_DFU_ERROR; 365*efbd65faSPatrick Delaunay hdfu->dev_status = DFU_ERROR_UNKNOWN; 366*efbd65faSPatrick Delaunay } 367*efbd65faSPatrick Delaunay } 368*efbd65faSPatrick Delaunay 369*efbd65faSPatrick Delaunay /* 370*efbd65faSPatrick Delaunay * usb_dfu_get_state 371*efbd65faSPatrick Delaunay * Handles the DFU GETSTATE request. 372*efbd65faSPatrick Delaunay * pdev: device instance 373*efbd65faSPatrick Delaunay */ 374*efbd65faSPatrick Delaunay static void usb_dfu_get_state(struct usb_handle *pdev) 375*efbd65faSPatrick Delaunay { 376*efbd65faSPatrick Delaunay struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; 377*efbd65faSPatrick Delaunay 378*efbd65faSPatrick Delaunay /* Return the current state of the DFU interface */ 379*efbd65faSPatrick Delaunay usb_core_transmit_ep0(pdev, &hdfu->dev_state, 1); 380*efbd65faSPatrick Delaunay } 381*efbd65faSPatrick Delaunay 382*efbd65faSPatrick Delaunay /* 383*efbd65faSPatrick Delaunay * usb_dfu_abort 384*efbd65faSPatrick Delaunay * Handles the DFU ABORT request. 385*efbd65faSPatrick Delaunay * pdev: device instance 386*efbd65faSPatrick Delaunay */ 387*efbd65faSPatrick Delaunay static void usb_dfu_abort(struct usb_handle *pdev) 388*efbd65faSPatrick Delaunay { 389*efbd65faSPatrick Delaunay struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; 390*efbd65faSPatrick Delaunay 391*efbd65faSPatrick Delaunay if ((hdfu->dev_state == STATE_DFU_IDLE) || 392*efbd65faSPatrick Delaunay (hdfu->dev_state == STATE_DFU_DNLOAD_SYNC) || 393*efbd65faSPatrick Delaunay (hdfu->dev_state == STATE_DFU_DNLOAD_IDLE) || 394*efbd65faSPatrick Delaunay (hdfu->dev_state == STATE_DFU_MANIFEST_SYNC) || 395*efbd65faSPatrick Delaunay (hdfu->dev_state == STATE_DFU_UPLOAD_IDLE)) { 396*efbd65faSPatrick Delaunay hdfu->dev_state = STATE_DFU_IDLE; 397*efbd65faSPatrick Delaunay hdfu->dev_status = DFU_ERROR_NONE; 398*efbd65faSPatrick Delaunay } 399*efbd65faSPatrick Delaunay } 400*efbd65faSPatrick Delaunay 401*efbd65faSPatrick Delaunay /* 402*efbd65faSPatrick Delaunay * usb_dfu_setup 403*efbd65faSPatrick Delaunay * Handle the DFU specific requests 404*efbd65faSPatrick Delaunay * pdev: instance 405*efbd65faSPatrick Delaunay * req: usb requests 406*efbd65faSPatrick Delaunay * return: status 407*efbd65faSPatrick Delaunay */ 408*efbd65faSPatrick Delaunay static uint8_t usb_dfu_setup(struct usb_handle *pdev, struct usb_setup_req *req) 409*efbd65faSPatrick Delaunay { 410*efbd65faSPatrick Delaunay uint8_t *pbuf = NULL; 411*efbd65faSPatrick Delaunay uint16_t len = 0U; 412*efbd65faSPatrick Delaunay uint8_t ret = USBD_OK; 413*efbd65faSPatrick Delaunay struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; 414*efbd65faSPatrick Delaunay 415*efbd65faSPatrick Delaunay switch (req->bm_request & USB_REQ_TYPE_MASK) { 416*efbd65faSPatrick Delaunay case USB_REQ_TYPE_CLASS: 417*efbd65faSPatrick Delaunay switch (req->b_request) { 418*efbd65faSPatrick Delaunay case DFU_DNLOAD: 419*efbd65faSPatrick Delaunay usb_dfu_download(pdev, req); 420*efbd65faSPatrick Delaunay break; 421*efbd65faSPatrick Delaunay 422*efbd65faSPatrick Delaunay case DFU_UPLOAD: 423*efbd65faSPatrick Delaunay usb_dfu_upload(pdev, req); 424*efbd65faSPatrick Delaunay break; 425*efbd65faSPatrick Delaunay 426*efbd65faSPatrick Delaunay case DFU_GETSTATUS: 427*efbd65faSPatrick Delaunay usb_dfu_get_status(pdev); 428*efbd65faSPatrick Delaunay break; 429*efbd65faSPatrick Delaunay 430*efbd65faSPatrick Delaunay case DFU_CLRSTATUS: 431*efbd65faSPatrick Delaunay usb_dfu_clear_status(pdev); 432*efbd65faSPatrick Delaunay break; 433*efbd65faSPatrick Delaunay 434*efbd65faSPatrick Delaunay case DFU_GETSTATE: 435*efbd65faSPatrick Delaunay usb_dfu_get_state(pdev); 436*efbd65faSPatrick Delaunay break; 437*efbd65faSPatrick Delaunay 438*efbd65faSPatrick Delaunay case DFU_ABORT: 439*efbd65faSPatrick Delaunay usb_dfu_abort(pdev); 440*efbd65faSPatrick Delaunay break; 441*efbd65faSPatrick Delaunay 442*efbd65faSPatrick Delaunay case DFU_DETACH: 443*efbd65faSPatrick Delaunay usb_dfu_detach(pdev, req); 444*efbd65faSPatrick Delaunay break; 445*efbd65faSPatrick Delaunay 446*efbd65faSPatrick Delaunay default: 447*efbd65faSPatrick Delaunay ERROR("unknown request %x on alternate %i\n", 448*efbd65faSPatrick Delaunay req->b_request, hdfu->alt_setting); 449*efbd65faSPatrick Delaunay usb_core_ctl_error(pdev); 450*efbd65faSPatrick Delaunay ret = USBD_FAIL; 451*efbd65faSPatrick Delaunay break; 452*efbd65faSPatrick Delaunay } 453*efbd65faSPatrick Delaunay break; 454*efbd65faSPatrick Delaunay case USB_REQ_TYPE_STANDARD: 455*efbd65faSPatrick Delaunay switch (req->b_request) { 456*efbd65faSPatrick Delaunay case USB_REQ_GET_DESCRIPTOR: 457*efbd65faSPatrick Delaunay if (HIBYTE(req->value) == DFU_DESCRIPTOR_TYPE) { 458*efbd65faSPatrick Delaunay pbuf = pdev->desc->get_config_desc(&len); 459*efbd65faSPatrick Delaunay /* DFU descriptor at the end of the USB */ 460*efbd65faSPatrick Delaunay pbuf += len - 9U; 461*efbd65faSPatrick Delaunay len = 9U; 462*efbd65faSPatrick Delaunay len = MIN(len, req->length); 463*efbd65faSPatrick Delaunay } 464*efbd65faSPatrick Delaunay 465*efbd65faSPatrick Delaunay /* Start the transfer */ 466*efbd65faSPatrick Delaunay usb_core_transmit_ep0(pdev, pbuf, len); 467*efbd65faSPatrick Delaunay 468*efbd65faSPatrick Delaunay break; 469*efbd65faSPatrick Delaunay 470*efbd65faSPatrick Delaunay case USB_REQ_GET_INTERFACE: 471*efbd65faSPatrick Delaunay /* Start the transfer */ 472*efbd65faSPatrick Delaunay usb_core_transmit_ep0(pdev, (uint8_t *)&hdfu->alt_setting, 1U); 473*efbd65faSPatrick Delaunay break; 474*efbd65faSPatrick Delaunay 475*efbd65faSPatrick Delaunay case USB_REQ_SET_INTERFACE: 476*efbd65faSPatrick Delaunay hdfu->alt_setting = LOBYTE(req->value); 477*efbd65faSPatrick Delaunay break; 478*efbd65faSPatrick Delaunay 479*efbd65faSPatrick Delaunay default: 480*efbd65faSPatrick Delaunay usb_core_ctl_error(pdev); 481*efbd65faSPatrick Delaunay ret = USBD_FAIL; 482*efbd65faSPatrick Delaunay break; 483*efbd65faSPatrick Delaunay } 484*efbd65faSPatrick Delaunay default: 485*efbd65faSPatrick Delaunay break; 486*efbd65faSPatrick Delaunay } 487*efbd65faSPatrick Delaunay 488*efbd65faSPatrick Delaunay return ret; 489*efbd65faSPatrick Delaunay } 490*efbd65faSPatrick Delaunay 491*efbd65faSPatrick Delaunay static const struct usb_class usb_dfu = { 492*efbd65faSPatrick Delaunay .init = usb_dfu_init, 493*efbd65faSPatrick Delaunay .de_init = usb_dfu_de_init, 494*efbd65faSPatrick Delaunay .setup = usb_dfu_setup, 495*efbd65faSPatrick Delaunay .ep0_tx_sent = usb_dfu_ep0_tx_ready, 496*efbd65faSPatrick Delaunay .ep0_rx_ready = usb_dfu_ep0_rx_ready, 497*efbd65faSPatrick Delaunay .data_in = usb_dfu_data_in, 498*efbd65faSPatrick Delaunay .data_out = usb_dfu_data_out, 499*efbd65faSPatrick Delaunay .sof = usb_dfu_sof, 500*efbd65faSPatrick Delaunay .iso_in_incomplete = usb_dfu_iso_in_incomplete, 501*efbd65faSPatrick Delaunay .iso_out_incomplete = usb_dfu_iso_out_incomplete, 502*efbd65faSPatrick Delaunay }; 503*efbd65faSPatrick Delaunay 504*efbd65faSPatrick Delaunay void usb_dfu_register(struct usb_handle *pdev, struct usb_dfu_handle *phandle) 505*efbd65faSPatrick Delaunay { 506*efbd65faSPatrick Delaunay pdev->class = (struct usb_class *)&usb_dfu; 507*efbd65faSPatrick Delaunay pdev->class_data = phandle; 508*efbd65faSPatrick Delaunay 509*efbd65faSPatrick Delaunay phandle->dev_state = STATE_DFU_IDLE; 510*efbd65faSPatrick Delaunay phandle->dev_status = DFU_ERROR_NONE; 511*efbd65faSPatrick Delaunay } 512*efbd65faSPatrick Delaunay 513*efbd65faSPatrick Delaunay int usb_dfu_loop(struct usb_handle *pdev, const struct usb_dfu_media *pmedia) 514*efbd65faSPatrick Delaunay { 515*efbd65faSPatrick Delaunay uint32_t it_count; 516*efbd65faSPatrick Delaunay enum usb_status ret; 517*efbd65faSPatrick Delaunay struct usb_dfu_handle *hdfu = (struct usb_dfu_handle *)pdev->class_data; 518*efbd65faSPatrick Delaunay 519*efbd65faSPatrick Delaunay hdfu->callback = pmedia; 520*efbd65faSPatrick Delaunay usb_dfu_detach_req = false; 521*efbd65faSPatrick Delaunay /* Continue to handle USB core IT to assure complete data transmission */ 522*efbd65faSPatrick Delaunay it_count = 100U; 523*efbd65faSPatrick Delaunay 524*efbd65faSPatrick Delaunay /* DFU infinite loop until DETACH_REQ */ 525*efbd65faSPatrick Delaunay while (it_count != 0U) { 526*efbd65faSPatrick Delaunay ret = usb_core_handle_it(pdev); 527*efbd65faSPatrick Delaunay if (ret != USBD_OK) { 528*efbd65faSPatrick Delaunay return -EIO; 529*efbd65faSPatrick Delaunay } 530*efbd65faSPatrick Delaunay 531*efbd65faSPatrick Delaunay /* Detach request received */ 532*efbd65faSPatrick Delaunay if (usb_dfu_detach_req) { 533*efbd65faSPatrick Delaunay it_count--; 534*efbd65faSPatrick Delaunay } 535*efbd65faSPatrick Delaunay } 536*efbd65faSPatrick Delaunay 537*efbd65faSPatrick Delaunay return 0; 538*efbd65faSPatrick Delaunay } 539