int usb_boot(struct usb_device *usbdev, u16 pid) { int i, ret = 0; struct file *filp = NULL; struct inode *inode = NULL; static mm_segment_t fs; struct img_header hdr; struct fw_info fw_info; loff_t pos = 0; char *img_name = UIMG_PATH; int len; tx_buf = (u8 *)kmalloc(DOWNLOAD_SIZE, GFP_KERNEL); if (tx_buf == NULL) { printk(KERN_ERR "Error: kmalloc\n"); return -ENOMEM; } fs = get_fs(); set_fs(get_ds()); filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0); if (IS_ERR(filp)) { printk(KERN_ERR "Can't find %s.\n", img_name); set_fs(fs); ret = -ENOENT; goto restore_fs; } if (filp->f_dentry) inode = filp->f_dentry->d_inode; if (!inode || !S_ISREG(inode->i_mode)) { printk(KERN_ERR "Invalid file type: %s\n", img_name); ret = -EINVAL; goto out; } len = filp->f_op->read(filp, (u8 *)&hdr, sizeof(hdr), &pos); if (len != sizeof(hdr)) { printk(KERN_ERR "gdmwm: Cannot read the image info.\n"); ret = -EIO; goto out; } array_le32_to_cpu((u32 *)&hdr, 19); #if 0 if (hdr.magic_code != 0x10767fff) { printk(KERN_ERR "gdmwm: Invalid magic code 0x%08x\n", hdr.magic_code); ret = -EINVAL; goto out; } #endif if (hdr.count > MAX_IMG_CNT) { printk(KERN_ERR "gdmwm: Too many images. %d\n", hdr.count); ret = -EINVAL; goto out; } for (i = 0; i < hdr.count; i++) { if (hdr.offset[i] > hdr.len) { printk(KERN_ERR "gdmwm: Invalid offset. Entry = %d Offset = 0x%08x Image length = 0x%08x\n", i, hdr.offset[i], hdr.len); ret = -EINVAL; goto out; } pos = hdr.offset[i]; len = filp->f_op->read(filp, (u8 *)&fw_info, sizeof(fw_info), &pos); if (len != sizeof(fw_info)) { printk(KERN_ERR "gdmwm: Cannot read the FW info.\n"); ret = -EIO; goto out; } array_le32_to_cpu((u32 *)&fw_info, 8); #if 0 if ((fw_info.id & 0xfffff000) != 0x10767000) { printk(KERN_ERR "gdmwm: Invalid FW id. 0x%08x\n", fw_info.id); ret = -EIO; goto out; } #endif if ((fw_info.id & 0xffff) != pid) continue; pos = hdr.offset[i] + fw_info.kernel_offset; ret = download_image(usbdev, filp, &pos, fw_info.kernel_len, DN_KERNEL_MAGIC_NUMBER); if (ret < 0) goto out; printk("GCT: Kernel download success.\n"); pos = hdr.offset[i] + fw_info.rootfs_offset; ret = download_image(usbdev, filp, &pos, fw_info.rootfs_len, DN_ROOTFS_MAGIC_NUMBER); if (ret < 0) goto out; printk("GCT: Filesystem download success.\n"); break; } if (i == hdr.count) { printk(KERN_ERR "Firmware for gsk%x is not installed.\n", pid); ret = -EINVAL; } out: filp_close(filp, current->files); restore_fs: set_fs(fs); kfree(tx_buf); return ret; }
int usb_boot(struct usb_device *usbdev, u16 pid) { int i, ret = 0; struct img_header hdr; struct fw_info fw_info; loff_t pos = 0; char *img_name = FW_DIR FW_UIMG; const struct firmware *firm; ret = request_firmware(&firm, img_name, &usbdev->dev); if (ret < 0) { dev_err(&usbdev->dev, "requesting firmware %s failed with error %d\n", img_name, ret); return ret; } tx_buf = kmalloc(DOWNLOAD_SIZE, GFP_KERNEL); if (tx_buf == NULL) return -ENOMEM; if (firm->size < sizeof(hdr)) { dev_err(&usbdev->dev, "Cannot read the image info.\n"); ret = -EIO; goto out; } memcpy(&hdr, firm->data, sizeof(hdr)); array_le32_to_cpu((u32 *)&hdr, 19); if (hdr.count > MAX_IMG_CNT) { dev_err(&usbdev->dev, "Too many images. %d\n", hdr.count); ret = -EINVAL; goto out; } for (i = 0; i < hdr.count; i++) { if (hdr.offset[i] > hdr.len) { dev_err(&usbdev->dev, "Invalid offset. Entry = %d Offset = 0x%08x Image length = 0x%08x\n", i, hdr.offset[i], hdr.len); ret = -EINVAL; goto out; } pos = hdr.offset[i]; if (firm->size < sizeof(fw_info) + pos) { dev_err(&usbdev->dev, "Cannot read the FW info.\n"); ret = -EIO; goto out; } memcpy(&fw_info, firm->data + pos, sizeof(fw_info)); array_le32_to_cpu((u32 *)&fw_info, 8); if ((fw_info.id & 0xffff) != pid) continue; pos = hdr.offset[i] + fw_info.kernel_offset; if (firm->size < fw_info.kernel_len + pos) { dev_err(&usbdev->dev, "Kernel FW is too small.\n"); goto out; } ret = download_image(usbdev, firm, pos, fw_info.kernel_len, DN_KERNEL_MAGIC_NUMBER); if (ret < 0) goto out; dev_info(&usbdev->dev, "GCT: Kernel download success.\n"); pos = hdr.offset[i] + fw_info.rootfs_offset; if (firm->size < fw_info.rootfs_len + pos) { dev_err(&usbdev->dev, "Filesystem FW is too small.\n"); goto out; } ret = download_image(usbdev, firm, pos, fw_info.rootfs_len, DN_ROOTFS_MAGIC_NUMBER); if (ret < 0) goto out; dev_info(&usbdev->dev, "GCT: Filesystem download success.\n"); break; } if (i == hdr.count) { dev_err(&usbdev->dev, "Firmware for gsk%x is not installed.\n", pid); ret = -EINVAL; } out: release_firmware(firm); kfree(tx_buf); return ret; }