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