Lines Matching +full:usb +full:- +full:sdp
2 * f_sdp.c -- USB HID Serial Download Protocol
7 * This file implements the Serial Download Protocol (SDP) as specified in
8 * the i.MX 6 Reference Manual. The SDP is a USB HID based protocol and
10 * works with the imx_loader (imx_usb) USB client software on host side.
17 * SPDX-License-Identifier: GPL-2.0+
25 #include <linux/usb/ch9.h>
26 #include <linux/usb/gadget.h>
27 #include <linux/usb/composite.h>
31 #include <sdp.h>
217 * static strings, in UTF-8
225 .language = 0x0409, /* en-us */
241 struct f_sdp *sdp = req->context; in sdp_rx_command_complete() local
242 int status = req->status; in sdp_rx_command_complete()
243 u8 *data = req->buf; in sdp_rx_command_complete()
256 struct sdp_command *cmd = req->buf + 1; in sdp_rx_command_complete()
259 __func__, be16_to_cpu(cmd->cmd), in sdp_rx_command_complete()
260 be32_to_cpu(cmd->addr), be32_to_cpu(cmd->cnt)); in sdp_rx_command_complete()
262 switch (be16_to_cpu(cmd->cmd)) { in sdp_rx_command_complete()
264 sdp->always_send_status = false; in sdp_rx_command_complete()
265 sdp->error_status = 0x0; in sdp_rx_command_complete()
267 sdp->state = SDP_STATE_TX_SEC_CONF; in sdp_rx_command_complete()
268 sdp->dnl_address = be32_to_cpu(cmd->addr); in sdp_rx_command_complete()
269 sdp->dnl_bytes_remaining = be32_to_cpu(cmd->cnt); in sdp_rx_command_complete()
270 sdp->next_state = SDP_STATE_TX_REGISTER; in sdp_rx_command_complete()
272 sdp->dnl_bytes_remaining, sdp->dnl_address); in sdp_rx_command_complete()
275 sdp->always_send_status = true; in sdp_rx_command_complete()
276 sdp->error_status = SDP_WRITE_FILE_COMPLETE; in sdp_rx_command_complete()
278 sdp->state = SDP_STATE_RX_FILE_DATA; in sdp_rx_command_complete()
279 sdp->dnl_address = be32_to_cpu(cmd->addr); in sdp_rx_command_complete()
280 sdp->dnl_bytes_remaining = be32_to_cpu(cmd->cnt); in sdp_rx_command_complete()
281 sdp->dnl_bytes = sdp->dnl_bytes_remaining; in sdp_rx_command_complete()
282 sdp->next_state = SDP_STATE_IDLE; in sdp_rx_command_complete()
285 sdp->dnl_bytes_remaining, sdp->dnl_address); in sdp_rx_command_complete()
289 sdp->always_send_status = true; in sdp_rx_command_complete()
290 sdp->error_status = 0; in sdp_rx_command_complete()
292 sdp->state = SDP_STATE_TX_SEC_CONF; in sdp_rx_command_complete()
293 sdp->next_state = SDP_STATE_IDLE; in sdp_rx_command_complete()
296 sdp->always_send_status = true; in sdp_rx_command_complete()
297 sdp->error_status = SDP_WRITE_REGISTER_COMPLETE; in sdp_rx_command_complete()
299 sdp->state = SDP_STATE_RX_DCD_DATA; in sdp_rx_command_complete()
300 sdp->dnl_bytes_remaining = be32_to_cpu(cmd->cnt); in sdp_rx_command_complete()
301 sdp->next_state = SDP_STATE_IDLE; in sdp_rx_command_complete()
304 sdp->always_send_status = false; in sdp_rx_command_complete()
305 sdp->error_status = 0; in sdp_rx_command_complete()
307 sdp->jmp_address = be32_to_cpu(cmd->addr); in sdp_rx_command_complete()
308 sdp->state = SDP_STATE_TX_SEC_CONF; in sdp_rx_command_complete()
309 sdp->next_state = SDP_STATE_JUMP; in sdp_rx_command_complete()
312 sdp->always_send_status = true; in sdp_rx_command_complete()
313 sdp->error_status = SDP_SKIP_DCD_HEADER_COMPLETE; in sdp_rx_command_complete()
316 sdp->state = SDP_STATE_TX_SEC_CONF; in sdp_rx_command_complete()
317 sdp->next_state = SDP_STATE_IDLE; in sdp_rx_command_complete()
320 pr_err("Unknown command: %04x\n", be16_to_cpu(cmd->cmd)); in sdp_rx_command_complete()
326 struct f_sdp *sdp = req->context; in sdp_rx_data_complete() local
327 int status = req->status; in sdp_rx_data_complete()
328 u8 *data = req->buf; in sdp_rx_data_complete()
330 int datalen = req->length - 1; in sdp_rx_data_complete()
342 if (sdp->dnl_bytes_remaining < datalen) { in sdp_rx_data_complete()
344 * Some USB stacks require to send a complete buffer as in sdp_rx_data_complete()
348 sdp->dnl_bytes_remaining = 0; in sdp_rx_data_complete()
350 sdp->dnl_bytes_remaining -= datalen; in sdp_rx_data_complete()
353 if (sdp->state == SDP_STATE_RX_FILE_DATA) { in sdp_rx_data_complete()
354 memcpy(sdp_ptr(sdp->dnl_address), req->buf + 1, datalen); in sdp_rx_data_complete()
355 sdp->dnl_address += datalen; in sdp_rx_data_complete()
358 if (sdp->dnl_bytes_remaining) in sdp_rx_data_complete()
362 env_set_hex("filesize", sdp->dnl_bytes); in sdp_rx_data_complete()
366 switch (sdp->state) { in sdp_rx_data_complete()
368 sdp->state = SDP_STATE_TX_SEC_CONF; in sdp_rx_data_complete()
371 sdp->state = SDP_STATE_TX_SEC_CONF; in sdp_rx_data_complete()
374 pr_err("Invalid state: %d\n", sdp->state); in sdp_rx_data_complete()
380 struct f_sdp *sdp = req->context; in sdp_tx_complete() local
381 int status = req->status; in sdp_tx_complete()
388 switch (sdp->state) { in sdp_tx_complete()
391 if (sdp->always_send_status || sdp->error_status) in sdp_tx_complete()
392 sdp->state = SDP_STATE_TX_STATUS; in sdp_tx_complete()
394 sdp->state = sdp->next_state; in sdp_tx_complete()
398 sdp->state = sdp->next_state; in sdp_tx_complete()
401 if (sdp->dnl_bytes_remaining) in sdp_tx_complete()
402 sdp->state = SDP_STATE_TX_REGISTER; in sdp_tx_complete()
404 sdp->state = SDP_STATE_IDLE; in sdp_tx_complete()
407 pr_err("Wrong State: %d\n", sdp->state); in sdp_tx_complete()
408 sdp->state = SDP_STATE_IDLE; in sdp_tx_complete()
411 debug("%s complete --> %d, %d/%d\n", ep->name, in sdp_tx_complete()
412 status, req->actual, req->length); in sdp_tx_complete()
417 struct usb_gadget *gadget = f->config->cdev->gadget; in sdp_setup()
418 struct usb_request *req = f->config->cdev->req; in sdp_setup()
419 struct f_sdp *sdp = f->config->cdev->req->context; in sdp_setup() local
420 u16 len = le16_to_cpu(ctrl->wLength); in sdp_setup()
421 u16 w_value = le16_to_cpu(ctrl->wValue); in sdp_setup()
423 u8 req_type = ctrl->bRequestType & USB_TYPE_MASK; in sdp_setup()
426 debug("req_type: 0x%02x ctrl->bRequest: 0x%02x sdp->state: %d\n", in sdp_setup()
427 req_type, ctrl->bRequest, sdp->state); in sdp_setup()
430 if (ctrl->bRequest == USB_REQ_GET_DESCRIPTOR) { in sdp_setup()
433 memcpy(req->buf, &sdp_hid_report, value); in sdp_setup()
434 sdp->configuration_done = true; in sdp_setup()
441 /* HID (SDP) request */ in sdp_setup()
442 switch (ctrl->bRequest) { in sdp_setup()
447 req->complete = sdp_rx_command_complete; in sdp_setup()
451 req->complete = sdp_rx_data_complete; in sdp_setup()
458 req->length = value; in sdp_setup()
459 req->zero = value < len; in sdp_setup()
460 value = usb_ep_queue(gadget->ep0, req, 0); in sdp_setup()
462 debug("ep_queue --> %d\n", value); in sdp_setup()
463 req->status = 0; in sdp_setup()
472 struct usb_gadget *gadget = c->cdev->gadget; in sdp_bind()
473 struct usb_composite_dev *cdev = c->cdev; in sdp_bind()
474 struct f_sdp *sdp = func_to_sdp(f); in sdp_bind() local
484 /* allocate instance-specific endpoints */ in sdp_bind()
487 rv = -ENODEV; in sdp_bind()
491 sdp->in_ep = ep; /* Store IN EP for enabling @ setup */ in sdp_bind()
493 cdev->req->context = sdp; in sdp_bind()
513 req->length = length; in alloc_ep_req()
514 req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, length); in alloc_ep_req()
515 if (!req->buf) { in alloc_ep_req()
534 memset(req->buf, 0, req->length); in sdp_start_ep()
535 req->complete = sdp_tx_complete; in sdp_start_ep()
541 struct f_sdp *sdp = func_to_sdp(f); in sdp_set_alt() local
542 struct usb_composite_dev *cdev = f->config->cdev; in sdp_set_alt()
547 result = usb_ep_enable(sdp->in_ep, &in_desc); in sdp_set_alt()
550 sdp->in_req = sdp_start_ep(sdp->in_ep); in sdp_set_alt()
551 sdp->in_req->context = sdp; in sdp_set_alt()
553 sdp->in_ep->driver_data = cdev; /* claim */ in sdp_set_alt()
555 sdp->altsetting = alt; in sdp_set_alt()
556 sdp->state = SDP_STATE_IDLE; in sdp_set_alt()
563 struct f_sdp *sdp = func_to_sdp(f); in sdp_get_alt() local
565 return sdp->altsetting; in sdp_get_alt()
570 struct f_sdp *sdp = func_to_sdp(f); in sdp_disable() local
572 usb_ep_disable(sdp->in_ep); in sdp_disable()
574 if (sdp->in_req) { in sdp_disable()
575 free(sdp->in_req); in sdp_disable()
576 sdp->in_req = NULL; in sdp_disable()
587 return -ENOMEM; in sdp_bind_config()
592 sdp_func->usb_function.name = "sdp"; in sdp_bind_config()
593 sdp_func->usb_function.hs_descriptors = sdp_runtime_descs; in sdp_bind_config()
594 sdp_func->usb_function.descriptors = sdp_runtime_descs; in sdp_bind_config()
595 sdp_func->usb_function.bind = sdp_bind; in sdp_bind_config()
596 sdp_func->usb_function.unbind = sdp_unbind; in sdp_bind_config()
597 sdp_func->usb_function.set_alt = sdp_set_alt; in sdp_bind_config()
598 sdp_func->usb_function.get_alt = sdp_get_alt; in sdp_bind_config()
599 sdp_func->usb_function.disable = sdp_disable; in sdp_bind_config()
600 sdp_func->usb_function.strings = sdp_generic_strings; in sdp_bind_config()
601 sdp_func->usb_function.setup = sdp_setup; in sdp_bind_config()
603 status = usb_add_function(c, &sdp_func->usb_function); in sdp_bind_config()
610 printf("SDP: initialize...\n"); in sdp_init()
611 while (!sdp_func->configuration_done) { in sdp_init()
613 puts("\rCTRL+C - Operation aborted.\n"); in sdp_init()
629 if (headerv2->header.tag != IVT_HEADER_TAG) { in sdp_jump_imxheader()
634 printf("Jumping to 0x%08x\n", headerv2->entry); in sdp_jump_imxheader()
635 entry = sdp_ptr(headerv2->entry); in sdp_jump_imxheader()
649 memcpy(buf, (void *)(load->dev + sector), count); in sdp_fit_read()
657 u8 *data = sdp_func->in_req->buf; in sdp_handle_in_ep()
661 switch (sdp_func->state) { in sdp_handle_in_ep()
668 sdp_func->in_req->length = 5; in sdp_handle_in_ep()
669 usb_ep_queue(sdp_func->in_ep, sdp_func->in_req, 0); in sdp_handle_in_ep()
670 sdp_func->state = SDP_STATE_TX_SEC_CONF_BUSY; in sdp_handle_in_ep()
677 memcpy(&data[1], &sdp_func->error_status, 4); in sdp_handle_in_ep()
678 sdp_func->in_req->length = 65; in sdp_handle_in_ep()
679 usb_ep_queue(sdp_func->in_ep, sdp_func->in_req, 0); in sdp_handle_in_ep()
680 sdp_func->state = SDP_STATE_TX_STATUS_BUSY; in sdp_handle_in_ep()
686 datalen = sdp_func->dnl_bytes_remaining; in sdp_handle_in_ep()
691 memcpy(&data[1], sdp_ptr(sdp_func->dnl_address), datalen); in sdp_handle_in_ep()
692 sdp_func->in_req->length = 65; in sdp_handle_in_ep()
694 sdp_func->dnl_bytes_remaining -= datalen; in sdp_handle_in_ep()
695 sdp_func->dnl_address += datalen; in sdp_handle_in_ep()
697 usb_ep_queue(sdp_func->in_ep, sdp_func->in_req, 0); in sdp_handle_in_ep()
698 sdp_func->state = SDP_STATE_TX_REGISTER_BUSY; in sdp_handle_in_ep()
701 printf("Jumping to header at 0x%08x\n", sdp_func->jmp_address); in sdp_handle_in_ep()
702 status = sdp_jump_imxheader(sdp_ptr(sdp_func->jmp_address)); in sdp_handle_in_ep()
704 /* If imx header fails, try some U-Boot specific headers */ in sdp_handle_in_ep()
708 sdp_ptr(sdp_func->jmp_address); in sdp_handle_in_ep()
723 /* In SPL, allow jumps to U-Boot images */ in sdp_handle_in_ep()
728 /* In U-Boot, allow jumps to scripts */ in sdp_handle_in_ep()
729 source(sdp_func->jmp_address, "script@1"); in sdp_handle_in_ep()
733 sdp_func->next_state = SDP_STATE_IDLE; in sdp_handle_in_ep()
734 sdp_func->error_status = status; in sdp_handle_in_ep()
738 sdp_func->state = SDP_STATE_TX_STATUS; in sdp_handle_in_ep()
740 sdp_func->state = SDP_STATE_IDLE; in sdp_handle_in_ep()
753 printf("SDP: handle requests...\n"); in sdp_handle()
756 puts("\rCTRL+C - Operation aborted.\n"); in sdp_handle()
757 return -EINVAL; in sdp_handle()
761 if (spl_image->flags & SPL_FIT_FOUND) in sdp_handle()
780 id = usb_string_id(c->cdev); in sdp_add()
786 debug("%s: cdev: %p gadget: %p gadget->ep0: %p\n", __func__, in sdp_add()
787 c->cdev, c->cdev->gadget, c->cdev->gadget->ep0); in sdp_add()