Hi Stefan, On 15/08/2017 23:54, Stefan Agner wrote: >> >> It looks like that I am again out of sync with documentation. Where is >> defined SDP_SKIP_DCD_HEADER ? It is undefined for MX6Q/D, Solo and DL. >> > > This is only available in newer SoC's e.g. i.MX 7.
ok > > It allows to skip the DCD header in a downloaded image. Since the DCD > header is anyway ignored by this SDP implementation, the command is kind > of useless. I still think it is a good idea to have the command type > define for completeness... I agree with you - I just wanted to understand. >And I think also some SDP host side > implementation might issue the command... That's ok, thanks for clarification. >> >> It is fine, but I am just missing if this is a use case. DCD is >> interpreted by boot ROM, and we are here already over in SPL. >> > > I also don't have a use case currently, but it is rather cheap so why > don't? Yes, that's fine. > > Note that the SDP_READ_REGISTER command is actually used by the > sb_loader to do some verification whether the image got correctly > downloaded... But I don't think it required DCD_WRITE for something, but > I would have to retest. > >>> + case SDP_JUMP_ADDRESS: >>> + sdp->always_send_status = false; >>> + sdp->error_status = 0; >>> + >>> + sdp->jmp_address = be32_to_cpu(cmd->addr); >>> + sdp->state = SDP_STATE_TX_SEC_CONF; >>> + sdp->next_state = SDP_STATE_JUMP; >>> + break; >>> + case SDP_SKIP_DCD_HEADER: >>> + sdp->always_send_status = true; >>> + sdp->error_status = SDP_SKIP_DCD_HEADER_COMPLETE; >>> + >>> + /* Ignore command, DCD not supported anyway */ >> >> Right - we load a file, we do not need a DCD. >> >>> + sdp->state = SDP_STATE_TX_SEC_CONF; >>> + sdp->next_state = SDP_STATE_IDLE; >>> + break; >>> + default: >>> + error("Unknown command: %08x\n", be16_to_cpu(cmd->cmd)); >>> + } >>> +} >>> + >>> +static void sdp_rx_data_complete(struct usb_ep *ep, struct usb_request >>> *req) >>> +{ >>> + struct f_sdp *sdp = req->context; >>> + int status = req->status; >>> + u8 *data = req->buf; >>> + u8 report = data[0]; >>> + int datalen = req->length - 1; >>> + >>> + if (status != 0) { >>> + error("Status: %d", status); >>> + return; >>> + } >>> + >>> + if (report != 2) { >>> + error("Unexpected report %d", report); >>> + return; >>> + } >>> + >>> + if (sdp->dnl_bytes_remaining < datalen) { >>> + /* >>> + * Some USB stacks require to send a complete buffer as >>> + * specified in the HID descriptor. This leads to longer >>> + * transfers than the file length, no problem for us. >>> + */ >>> + sdp->dnl_bytes_remaining = 0; >>> + } else { >>> + sdp->dnl_bytes_remaining -= datalen; >>> + } >>> + >>> + if (sdp->state == SDP_STATE_RX_FILE_DATA) { >>> + memcpy((void *)sdp->dnl_address, req->buf + 1, datalen); >>> + sdp->dnl_address += datalen; >>> + } >>> + >>> + if (sdp->dnl_bytes_remaining) >>> + return; >>> + >>> + printf("done\n"); >>> + >>> + switch (sdp->state) { >>> + case SDP_STATE_RX_FILE_DATA: >>> + sdp->state = SDP_STATE_TX_SEC_CONF; >>> + break; >>> + case SDP_STATE_RX_DCD_DATA: >>> + sdp->state = SDP_STATE_TX_SEC_CONF; >>> + break; >>> + default: >>> + error("Invalid state: %d", sdp->state); >>> + } >>> +} >>> + >>> + >>> + >>> +static void sdp_tx_complete(struct usb_ep *ep, struct usb_request *req) >>> +{ >>> + struct f_sdp *sdp = req->context; >>> + int status = req->status; >>> + >>> + if (status != 0) { >>> + error("Status: %d", status); >>> + return; >>> + } >>> + >>> + switch (sdp->state) { >>> + case SDP_STATE_TX_SEC_CONF_BUSY: >>> + /* Not all commands require status report */ >>> + if (sdp->always_send_status || sdp->error_status) >>> + sdp->state = SDP_STATE_TX_STATUS; >>> + else >>> + sdp->state = sdp->next_state; >>> + >>> + break; >>> + case SDP_STATE_TX_STATUS_BUSY: >>> + sdp->state = sdp->next_state; >>> + break; >>> + case SDP_STATE_TX_REGISTER_BUSY: >>> + if (sdp->dnl_bytes_remaining) >>> + sdp->state = SDP_STATE_TX_REGISTER; >>> + else >>> + sdp->state = SDP_STATE_IDLE; >>> + break; >>> + default: >>> + error("Wrong State: %d", sdp->state); >>> + sdp->state = SDP_STATE_IDLE; >>> + break; >>> + } >>> + debug("%s complete --> %d, %d/%d\n", ep->name, >>> + status, req->actual, req->length); >>> +} >>> + >>> +static int sdp_setup(struct usb_function *f, const struct usb_ctrlrequest >>> *ctrl) >>> +{ >>> + struct usb_gadget *gadget = f->config->cdev->gadget; >>> + struct usb_request *req = f->config->cdev->req; >>> + struct f_sdp *sdp = f->config->cdev->req->context; >>> + u16 len = le16_to_cpu(ctrl->wLength); >>> + u16 w_value = le16_to_cpu(ctrl->wValue); >>> + int value = 0; >>> + u8 req_type = ctrl->bRequestType & USB_TYPE_MASK; >>> + >>> + debug("w_value: 0x%x len: 0x%x\n", w_value, len); >>> + debug("req_type: 0x%x ctrl->bRequest: 0x%x sdp->state: %d\n", >>> + req_type, ctrl->bRequest, sdp->state); >>> + >>> + if (req_type == USB_TYPE_STANDARD) { >>> + if (ctrl->bRequest == USB_REQ_GET_DESCRIPTOR) { >>> + /* Send HID report descriptor */ >>> + value = min(len, (u16) sizeof(sdp_hid_report)); >>> + memcpy(req->buf, &sdp_hid_report, value); >>> + sdp->configuration_done = true; >>> + } >>> + } >>> + >>> + if (req_type == USB_TYPE_CLASS) { >>> + int report = w_value & HID_REPORT_ID_MASK; >>> + >>> + /* HID (SDP) request */ >>> + switch (ctrl->bRequest) { >>> + case HID_REQ_SET_REPORT: >>> + switch (report) { >>> + case 1: >>> + value = SDP_COMMAND_LEN + 1; >>> + req->complete = sdp_rx_command_complete; >>> + break; >>> + case 2: >>> + value = len; >>> + req->complete = sdp_rx_data_complete; >>> + break; >>> + } >>> + } >>> + } >>> + >>> + if (value >= 0) { >>> + req->length = value; >>> + req->zero = value < len; >>> + value = usb_ep_queue(gadget->ep0, req, 0); >>> + if (value < 0) { >>> + debug("ep_queue --> %d\n", value); >>> + req->status = 0; >>> + } >>> + } >>> + >>> + return value; >>> +} >>> + >>> +static int sdp_bind(struct usb_configuration *c, struct usb_function *f) >>> +{ >>> + struct usb_gadget *gadget = c->cdev->gadget; >>> + struct usb_composite_dev *cdev = c->cdev; >>> + struct f_sdp *sdp = func_to_sdp(f); >>> + int rv = 0, id; >>> + >>> + id = usb_interface_id(c, f); >>> + if (id < 0) >>> + return id; >>> + sdp_intf_runtime.bInterfaceNumber = id; >>> + >>> + struct usb_ep *ep; >>> + >>> + /* allocate instance-specific endpoints */ >>> + ep = usb_ep_autoconfig(gadget, &in_desc); >>> + if (!ep) { >>> + rv = -ENODEV; >>> + goto error; >>> + } >>> + >>> + sdp->in_ep = ep; /* Store IN EP for enabling @ setup */ >>> + >>> + cdev->req->context = sdp; >>> + >>> +error: >>> + return rv; >>> +} >>> + >>> +static void sdp_unbind(struct usb_configuration *c, struct usb_function *f) >>> +{ >>> + free(sdp_func); >>> + sdp_func = NULL; >>> +} >>> + >>> +static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) >>> +{ >>> + struct usb_request *req; >>> + >>> + req = usb_ep_alloc_request(ep, 0); >>> + if (!req) >>> + return req; >>> + >>> + req->length = length; >>> + req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, length); >>> + if (!req->buf) { >>> + usb_ep_free_request(ep, req); >>> + req = NULL; >>> + } >>> + >>> + return req; >>> +} >>> + >>> + >>> +static struct usb_request *sdp_start_ep(struct usb_ep *ep) >>> +{ >>> + struct usb_request *req; >>> + >>> + req = alloc_ep_req(ep, 64); >>> + debug("%s: ep:%p req:%p\n", __func__, ep, req); >>> + >>> + if (!req) >>> + return NULL; >>> + >>> + memset(req->buf, 0, req->length); >>> + req->complete = sdp_tx_complete; >>> + >>> + return req; >>> +} >>> +static int sdp_set_alt(struct usb_function *f, unsigned intf, unsigned alt) >>> +{ >>> + struct f_sdp *sdp = func_to_sdp(f); >>> + struct usb_composite_dev *cdev = f->config->cdev; >>> + int result; >>> + >>> + debug("%s: intf: %d alt: %d\n", __func__, intf, alt); >>> + >>> + result = usb_ep_enable(sdp->in_ep, &in_desc); >>> + if (result) >>> + return result; >>> + sdp->in_req = sdp_start_ep(sdp->in_ep); >>> + sdp->in_req->context = sdp; >>> + >>> + sdp->in_ep->driver_data = cdev; /* claim */ >>> + >>> + sdp->altsetting = alt; >>> + sdp->state = SDP_STATE_IDLE; >>> + >>> + return 0; >>> +} >>> + >>> +static int sdp_get_alt(struct usb_function *f, unsigned intf) >>> +{ >>> + struct f_sdp *sdp = func_to_sdp(f); >>> + >>> + return sdp->altsetting; >>> +} >>> + >>> +static void sdp_disable(struct usb_function *f) >>> +{ >>> + struct f_sdp *sdp = func_to_sdp(f); >>> + >>> + usb_ep_disable(sdp->in_ep); >>> + >>> + if (sdp->in_req) { >>> + free(sdp->in_req); >>> + sdp->in_req = NULL; >>> + } >>> +} >>> + >>> +static int sdp_bind_config(struct usb_configuration *c) >>> +{ >>> + int status; >>> + >>> + if (!sdp_func) { >>> + sdp_func = memalign(CONFIG_SYS_CACHELINE_SIZE, >>> sizeof(*sdp_func)); >>> + if (!sdp_func) >>> + return -ENOMEM; >>> + } >>> + >>> + memset(sdp_func, 0, sizeof(*sdp_func)); >>> + >>> + sdp_func->usb_function.name = "sdp"; >>> + sdp_func->usb_function.hs_descriptors = sdp_runtime_descs; >>> + sdp_func->usb_function.descriptors = sdp_runtime_descs; >>> + sdp_func->usb_function.bind = sdp_bind; >>> + sdp_func->usb_function.unbind = sdp_unbind; >>> + sdp_func->usb_function.set_alt = sdp_set_alt; >>> + sdp_func->usb_function.get_alt = sdp_get_alt; >>> + sdp_func->usb_function.disable = sdp_disable; >>> + sdp_func->usb_function.strings = sdp_generic_strings; >>> + sdp_func->usb_function.setup = sdp_setup; >>> + >>> + status = usb_add_function(c, &sdp_func->usb_function); >>> + >>> + return status; >>> +} >>> + >>> +int sdp_init(void) >>> +{ >>> + printf("SDP: initialize...\n"); >>> + while (!sdp_func->configuration_done) { >>> + if (ctrlc()) { >>> + puts("\rCTRL+C - Operation aborted.\n"); >>> + return 0; >>> + } >>> + usb_gadget_handle_interrupts(0); >>> + } >>> + >>> + return 0; >>> +} >>> + >>> +static u32 sdp_jump_imxheader(void *address) >>> +{ >>> + flash_header_v2_t *headerv2 = address; >>> + ulong (*entry)(void); >>> + >>> + if (headerv2->header.tag != IVT_HEADER_TAG) { >>> + printf("Header Tag is not a IMX image\n"); >>> + return SDP_ERROR_IMXHEADER; >>> + } >>> + >>> + printf("Jumping to 0x%08x\n", headerv2->entry); >>> + entry = (void *)headerv2->entry; >>> + entry(); >>> + >>> + /* The image probably never returns hence we wont reach that point */ >>> + return 0; >>> +} >>> + >>> +static void sdp_handle_in_ep(void) >>> +{ >>> + u8 *data = sdp_func->in_req->buf; >>> + u32 status; >>> + int datalen; >>> + >>> + switch (sdp_func->state) { >>> + case SDP_STATE_TX_SEC_CONF: >>> + debug("Report 3: HAB security\n"); >>> + data[0] = 3; >>> + >>> + data[1] = 0x56; >>> + data[2] = 0x78; >>> + data[3] = 0x78; >>> + data[4] = 0x56; >> >> I am quite lost here - can you explain what are these magic numbers, and >> maybe add a comment for it (or self explaining defines) ? >> > > Yeah protocol specific magic number: > HAB security > configuration. Device > sends 0x12343412 in > closed mode and > 0x56787856 in open > mode. > > > We always assume open. Not sure what kind of implication that can have, > I think imx_usb basically just prints out what the device says. > > Will create proper defines. Thanks. Best regards, Stefano -- ===================================================================== DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sba...@denx.de ===================================================================== _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot