[U-Boot] [PATCH v1 2/7] usb: gadget: add SDP driver
Stefano Babic
sbabic at denx.de
Wed Aug 16 09:49:12 UTC 2017
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: sbabic at denx.de
=====================================================================
More information about the U-Boot
mailing list