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