📄 uboot-dfu.patch
字号:
+ return rc;+ printf("Starting DFU DOWNLOAD to partition '%s'\n",+ ds->part->name);+ }++ size = ds->nand->erasesize;+ remain_len = ds->buf + size - ds->ptr;+ if (remain_len < len)+ actual_len = remain_len;++ memcpy(ds->ptr, urb->buffer, actual_len);+ ds->ptr += actual_len;++ /* check partition end */+ if (ds->off + (ds->ptr - ds->buf) > ds->part->offset + ds->part->size) {+ printf("End of write exceeds partition end\n");+ dev->dfu_state = DFU_STATE_dfuERROR;+ dev->dfu_status = DFU_STATUS_errADDRESS;+ return RET_STALL;+ }++ if (ds->ptr >= ds->buf + size) {+ rc = erase_flash_verify_nand(urb, ds,+ ds->nand->erasesize,+ ds->nand->erasesize);+ if (rc)+ return rc;+ /* copy remainder of data into buffer */+ memcpy(ds->ptr, urb->buffer + actual_len, len - actual_len);+ ds->ptr += (len - actual_len);+ }+ break;+ }++ return RET_ZLP;+}++static int handle_upload(struct urb *urb, u_int16_t val, u_int16_t len, int first)+{+ struct usb_device_instance *dev = urb->device;+ struct dnload_state *ds = &_dnstate;+ unsigned int remain;+ int rc;++ debug("upload(val=0x%02x, len=%u, first=%u) ", val, len, first);++ if (len > CONFIG_USBD_DFU_XFER_SIZE) {+ /* Too big */+ dev->dfu_state = DFU_STATE_dfuERROR;+ dev->dfu_status = DFU_STATUS_errADDRESS;+ //udc_ep0_send_stall();+ debug("Error: Transfer size > CONFIG_USBD_DFU_XFER_SIZE ");+ return -EINVAL;+ }++ switch (dev->alternate) {+ case 0:+ if (first) {+ printf("Starting DFU Upload of RAM (0x%08p)\n",+ LOAD_ADDR);+ ds->ptr = ds->buf;+ }++ /* FIXME: end at some more dynamic point */+ if (ds->ptr + len > LOAD_ADDR + 0x200000)+ len = (LOAD_ADDR + 0x200000) - ds->ptr;++ urb->buffer = ds->ptr;+ urb->actual_length = len;+ ds->ptr += len;+ break;+ default:+ if (first) {+ rc = initialize_ds_nand(dev, ds);+ if (rc)+ return -EINVAL;+ printf("Starting DFU Upload of partition '%s'\n",+ ds->part->name);+ rc = read_next_nand(urb, ds);+ if (rc)+ return -EINVAL;+ }++ if (len > ds->nand->erasesize) {+ printf("We don't support transfers bigger than %u\n",+ ds->nand->erasesize);+ len = ds->nand->erasesize;+ }++ remain = ds->nand->erasesize - (ds->ptr - ds->buf);+ if (len < remain)+ remain = len;++ debug("copying %u bytes ", remain);+ urb->buffer = ds->ptr;+ ds->ptr += remain;+ urb->actual_length = remain;++ if (ds->ptr >= ds->buf + ds->nand->erasesize &&+ ds->off < ds->part->offset + ds->part->size) {+ rc = read_next_nand(urb, ds);+ if (rc)+ return -EINVAL;+ if (len > remain) {+ debug("copying another %u bytes ", len - remain);+ memcpy(urb->buffer + remain, ds->ptr, len - remain);+ ds->ptr += (len - remain);+ urb->actual_length += (len - remain);+ }+ }+ break;+ }++ debug("returning len=%u\n", len);+ return len;+}++static void handle_getstatus(struct urb *urb, int max)+{+ struct usb_device_instance *dev = urb->device;+ struct dfu_status *dstat = (struct dfu_status *) urb->buffer;++ debug("getstatus ");++ if (!urb->buffer || urb->buffer_length < sizeof(*dstat)) {+ debug("invalid urb! ");+ return;+ }++ switch (dev->dfu_state) {+ case DFU_STATE_dfuDNLOAD_SYNC:+ case DFU_STATE_dfuDNBUSY:+#if 0+ if (fsr & AT91C_MC_PROGE) {+ debug("errPROG ");+ dev->dfu_status = DFU_STATUS_errPROG;+ dev->dfu_state = DFU_STATE_dfuERROR;+ } else if (fsr & AT91C_MC_LOCKE) {+ debug("errWRITE ");+ dev->dfu_status = DFU_STATUS_errWRITE;+ dev->dfu_state = DFU_STATE_dfuERROR;+ } else if (fsr & AT91C_MC_FRDY) {+#endif+ debug("DNLOAD_IDLE ");+ dev->dfu_state = DFU_STATE_dfuDNLOAD_IDLE;+#if 0+ } else {+ debug("DNBUSY ");+ dev->dfu_state = DFU_STATE_dfuDNBUSY;+ }+#endif+ break;+ case DFU_STATE_dfuMANIFEST_SYNC:+ break;+ default:+ //return;+ break;+ }++ /* send status response */+ dstat->bStatus = dev->dfu_status;+ dstat->bState = dev->dfu_state;+ dstat->iString = 0;+ /* FIXME: set dstat->bwPollTimeout */+ urb->actual_length = MIN(sizeof(*dstat), max);++ /* we don't need to explicitly send data here, will+ * be done by the original caller! */+}++static void handle_getstate(struct urb *urb, int max)+{+ debug("getstate ");++ if (!urb->buffer || urb->buffer_length < sizeof(u_int8_t)) {+ debug("invalid urb! ");+ return;+ }++ urb->buffer[0] = urb->device->dfu_state & 0xff;+ urb->actual_length = sizeof(u_int8_t);+}++#ifndef CONFIG_USBD_PRODUCTID_DFU+#define CONFIG_USBD_PRODUCTID_DFU CONFIG_USBD_PRODUCTID_CDCACM+#endif++static const struct usb_device_descriptor dfu_dev_descriptor = {+ .bLength = USB_DT_DEVICE_SIZE,+ .bDescriptorType = USB_DT_DEVICE,+ .bcdUSB = 0x0100,+ .bDeviceClass = 0x00,+ .bDeviceSubClass = 0x00,+ .bDeviceProtocol = 0x00,+ .bMaxPacketSize0 = EP0_MAX_PACKET_SIZE,+ .idVendor = CONFIG_USBD_VENDORID,+ .idProduct = CONFIG_USBD_PRODUCTID_DFU,+ .bcdDevice = 0x0000,+ .iManufacturer = DFU_STR_MANUFACTURER,+ .iProduct = DFU_STR_PRODUCT,+ .iSerialNumber = DFU_STR_SERIAL,+ .bNumConfigurations = 0x01,+};++static struct _dfu_desc dfu_cfg_descriptor = {+ .ucfg = {+ .bLength = USB_DT_CONFIG_SIZE,+ .bDescriptorType = USB_DT_CONFIG,+ .wTotalLength = USB_DT_CONFIG_SIZE ++ DFU_NUM_ALTERNATES * USB_DT_INTERFACE_SIZE ++ USB_DT_DFU_SIZE,+ .bNumInterfaces = 1,+ .bConfigurationValue = 1,+ .iConfiguration = DFU_STR_CONFIG,+ .bmAttributes = BMATTRIBUTE_RESERVED,+ .bMaxPower = 50,+ },+ .func_dfu = DFU_FUNC_DESC,+};++int dfu_ep0_handler(struct urb *urb)+{+ int rc, ret = RET_NOTHING;+ u_int8_t req = urb->device_request.bRequest;+ u_int16_t val = urb->device_request.wValue;+ u_int16_t len = urb->device_request.wLength;+ struct usb_device_instance *dev = urb->device;++ debug("dfu_ep0(req=0x%x, val=0x%x, len=%u) old_state = %u ",+ req, val, len, dev->dfu_state);++ switch (dev->dfu_state) {+ case DFU_STATE_appIDLE:+ switch (req) {+ case USB_REQ_DFU_GETSTATUS:+ handle_getstatus(urb, len);+ break;+ case USB_REQ_DFU_GETSTATE:+ handle_getstate(urb, len);+ break;+ case USB_REQ_DFU_DETACH:+ dev->dfu_state = DFU_STATE_appDETACH;+ ret = RET_ZLP;+ goto out;+ break;+ default:+ ret = RET_STALL;+ }+ break;+ case DFU_STATE_appDETACH:+ switch (req) {+ case USB_REQ_DFU_GETSTATUS:+ handle_getstatus(urb, len);+ break;+ case USB_REQ_DFU_GETSTATE:+ handle_getstate(urb, len);+ break;+ default:+ dev->dfu_state = DFU_STATE_appIDLE;+ ret = RET_STALL;+ goto out;+ break;+ }+ /* FIXME: implement timer to return to appIDLE */+ break;+ case DFU_STATE_dfuIDLE:+ switch (req) {+ case USB_REQ_DFU_DNLOAD:+ if (len == 0) {+ dev->dfu_state = DFU_STATE_dfuERROR;+ ret = RET_STALL;+ goto out;+ }+ dev->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;+ ret = handle_dnload(urb, val, len, 1);+ break;+ case USB_REQ_DFU_UPLOAD:+ dev->dfu_state = DFU_STATE_dfuUPLOAD_IDLE;+ handle_upload(urb, val, len, 1);+ break;+ case USB_REQ_DFU_ABORT:+ /* no zlp? */+ ret = RET_ZLP;+ break;+ case USB_REQ_DFU_GETSTATUS:+ handle_getstatus(urb, len);+ break;+ case USB_REQ_DFU_GETSTATE:+ handle_getstate(urb, len);+ break;+ case USB_REQ_DFU_DETACH:+ /* Proprietary extension: 'detach' from idle mode and+ * get back to runtime mode in case of USB Reset. As+ * much as I dislike this, we just can't use every USB+ * bus reset to switch back to runtime mode, since at+ * least the Linux USB stack likes to send a number of resets+ * in a row :( */+ dev->dfu_state = DFU_STATE_dfuMANIFEST_WAIT_RST;+ break;+ default:+ dev->dfu_state = DFU_STATE_dfuERROR;+ ret = RET_STALL;+ goto out;+ break;+ }+ break;+ case DFU_STATE_dfuDNLOAD_SYNC:+ switch (req) {+ case USB_REQ_DFU_GETSTATUS:+ handle_getstatus(urb, len);+ /* FIXME: state transition depending on block completeness */+ break;+ case USB_REQ_DFU_GETSTATE:+ handle_getstate(urb, len);+ break;+ default:+ dev->dfu_state = DFU_STATE_dfuERROR;+ ret = RET_STALL;+ goto out;+ }+ break;+ case DFU_STATE_dfuDNBUSY:+ switch (req) {+ case USB_REQ_DFU_GETSTATUS:+ /* FIXME: only accept getstatus if bwPollTimeout+ * has elapsed */+ handle_getstatus(urb, len);+ break;+ default:+ dev->dfu_state = DFU_STATE_dfuERROR;+ ret = RET_STALL;+ goto out;+ }+ break;+ case DFU_STATE_dfuDNLOAD_IDLE:+ switch (req) {+ case USB_REQ_DFU_DNLOAD:+ dev->dfu_state = DFU_STATE_dfuDNLOAD_SYNC;+ ret = handle_dnload(urb, val, len, 0);+ break;+ case USB_REQ_DFU_ABORT:+ dev->dfu_state = DFU_STATE_dfuIDLE;+ ret = RET_ZLP;+ break;+ case USB_REQ_DFU_GETSTATUS:+ handle_getstatus(urb, len);+ break;+ case USB_REQ_DFU_GETSTATE:+ handle_getstate(urb, len);+ break;+ default:+ dev->dfu_state = DFU_STATE_dfuERROR;+ ret = RET_STALL;+ break;+ }+ break;+ case DFU_STATE_dfuMANIFEST_SYNC:+ switch (req) {+ case USB_REQ_DFU_GETSTATUS:+ /* We're MainfestationTolerant */+ dev->dfu_state = DFU_STATE_dfuIDLE;+ handle_getstatus(urb, len);+ break;+ case USB_REQ_DFU_GETSTATE:+ handle_getstate(urb, len);+ break;+ default:+ dev->dfu_state = DFU_STATE_dfuERROR;+ ret = RET_STALL;+ break;+ }+ break;+ case DFU_STATE_dfuMANIFEST:+ /* we should never go here */+ dev->dfu_state = DFU_STATE_dfuERROR;+ ret = RET_STALL;+ break;+ case DFU_STATE_dfuMANIFEST_WAIT_RST:+ /* we should never go here */+ break;+ case DFU_STATE_dfuUPLOAD_IDLE:+ switch (req) {+ case USB_REQ_DFU_UPLOAD:+ /* state transition if less data then requested */+ rc = handle_upload(urb, val, len, 0);+ if (rc >= 0 && rc < len)+ dev->dfu_state = DFU_STATE_dfuIDLE;+ break;+ case USB_REQ_DFU_ABORT:+ dev->dfu_state = DFU_STATE_dfuIDLE;+ /* no zlp? */+ ret = RET_ZLP;+ break;+ case USB_REQ_DFU_GETSTATUS:+ handle_getstatus(urb, len);+ break;+ case USB_REQ_DFU_GETSTATE:+ handle_getstate(urb, len);+ break;+ default:+ dev->dfu_state = DFU_STATE_dfuERROR;+ ret = RET_STALL;+ break;+ }+ break;+ case DFU_STATE_dfuERROR:+ switch (req) {+ case USB_REQ_DFU_GETSTATUS:+ handle_getstatus(urb, len);+ break;+ case USB_REQ_DFU_GETSTATE:+ handle_getstate(urb, len);+ break;+ case USB_REQ_DFU_CLRSTATUS:+ dev->dfu_state = DFU_STATE_dfuIDLE;+ dev->dfu_status = DFU_STATUS_OK;+ /* no zlp? */+ ret = RET_ZLP;+ break;+ default:+ dev->dfu_state = DFU_STATE_dfuERROR;+ ret = RET_STALL;+ break;+ }+ break;+ default:+ return DFU_EP0_UNHANDLED;+ break;+ }++out:+ debug("new_state = %u, ret = %u\n", dev->dfu_state, ret);++ switch (ret) {+ case RET_ZLP:+ //udc_ep0_send_zlp();+ urb->actual_length = 0;+ return DFU_EP0_ZLP;+ break;+ case RET_STALL:+ //udc_ep0_send_stall();+ return DFU_EP0_STALL;+ break;+ case RET_NOTHING:+ break;+ }++ return DFU_EP0_DATA;+}++void str2wide (char *str, u16 * wide);+static struct usb_string_descriptor *create_usbstring(char *string)+{+ struct usb_string_descriptor *strdesc;+ int size = sizeof(*strdesc) + strlen(string)*2;++ if (size > 255)+ return NULL;++ strdesc = malloc(size);+ if (!strdesc)+ return NULL;++ strdesc->bLength = size;+ strdesc->bDescriptorType = USB_DT_STRING;+ str2wide(string, strdesc->wData);++ return strdesc;+}+++static void dfu_init_strings(struct usb_device_instance *dev)+{+ int i;+ struct usb_string_descriptor *strdesc;++ strdesc = create_usbstring(CONFIG_DFU_CFG_STR);+ usb_strings[DFU_STR_CONFIG] = strdesc;++ for (i = 0; i < DFU_NUM_ALTERNATES; i++) {+ if (i == 0) {+ strdesc = create_usbstring(CONFIG_DFU_ALT0_STR);+ } else {+ struct part_info *part = get_partition_nand(i-1);++ if (part)+ strdesc = create_usbstring(part->name);+ else+ strdesc =+ create_usbstring("undefined partition");+ }+ if (!strdesc)+ continue;+ usb_strings[STR_COUNT+i+1] = strdesc;+ }+}+++#ifdef CONFIG_NAND_DYNPART++void dfu_update_strings(void)+{+ int i;++ if (!system_dfu_state) {+ printf("NASTY SURPRISE: system_dfu_state not set\n");+ return;+ }++ for (i = 1; i != DFU_NUM_ALTERNATES; i++) {+ struct part_info *part = get_partition_nand(i-1);+ struct usb_string_descriptor *strdesc, **slot;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -