1 /* 2 * dfu.c -- DFU back-end routines 3 * 4 * Copyright (C) 2012 Samsung Electronics 5 * author: Lukasz Majewski <l.majewski@samsung.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22 #include <common.h> 23 #include <malloc.h> 24 #include <errno.h> 25 #include <dfu.h> 26 27 enum dfu_mmc_op { 28 DFU_OP_READ = 1, 29 DFU_OP_WRITE, 30 }; 31 32 static int mmc_block_op(enum dfu_mmc_op op, struct dfu_entity *dfu, 33 void *buf, long *len) 34 { 35 char cmd_buf[DFU_CMD_BUF_SIZE]; 36 37 sprintf(cmd_buf, "mmc %s 0x%x %x %x", 38 op == DFU_OP_READ ? "read" : "write", 39 (unsigned int) buf, 40 dfu->data.mmc.lba_start, 41 dfu->data.mmc.lba_size); 42 43 if (op == DFU_OP_READ) 44 *len = dfu->data.mmc.lba_blk_size * dfu->data.mmc.lba_size; 45 46 debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf); 47 return run_command(cmd_buf, 0); 48 } 49 50 static inline int mmc_block_write(struct dfu_entity *dfu, void *buf, long *len) 51 { 52 return mmc_block_op(DFU_OP_WRITE, dfu, buf, len); 53 } 54 55 static inline int mmc_block_read(struct dfu_entity *dfu, void *buf, long *len) 56 { 57 return mmc_block_op(DFU_OP_READ, dfu, buf, len); 58 } 59 60 static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu, 61 void *buf, long *len) 62 { 63 char cmd_buf[DFU_CMD_BUF_SIZE]; 64 char *str_env; 65 int ret; 66 67 switch (dfu->layout) { 68 case DFU_FS_FAT: 69 sprintf(cmd_buf, "fat%s mmc %d:%d 0x%x %s %lx", 70 op == DFU_OP_READ ? "load" : "write", 71 dfu->data.mmc.dev, dfu->data.mmc.part, 72 (unsigned int) buf, dfu->name, *len); 73 break; 74 case DFU_FS_EXT4: 75 sprintf(cmd_buf, "ext4%s mmc %d:%d /%s 0x%x %ld", 76 op == DFU_OP_READ ? "load" : "write", 77 dfu->data.mmc.dev, dfu->data.mmc.part, 78 dfu->name, (unsigned int) buf, *len); 79 break; 80 default: 81 printf("%s: Layout (%s) not (yet) supported!\n", __func__, 82 dfu_get_layout(dfu->layout)); 83 } 84 85 debug("%s: %s 0x%p\n", __func__, cmd_buf, cmd_buf); 86 87 ret = run_command(cmd_buf, 0); 88 if (ret) { 89 puts("dfu: Read error!\n"); 90 return ret; 91 } 92 93 if (dfu->layout != DFU_RAW_ADDR && op == DFU_OP_READ) { 94 str_env = getenv("filesize"); 95 if (str_env == NULL) { 96 puts("dfu: Wrong file size!\n"); 97 return -1; 98 } 99 *len = simple_strtoul(str_env, NULL, 16); 100 } 101 102 return ret; 103 } 104 105 static inline int mmc_file_write(struct dfu_entity *dfu, void *buf, long *len) 106 { 107 return mmc_file_op(DFU_OP_WRITE, dfu, buf, len); 108 } 109 110 static inline int mmc_file_read(struct dfu_entity *dfu, void *buf, long *len) 111 { 112 return mmc_file_op(DFU_OP_READ, dfu, buf, len); 113 } 114 115 int dfu_write_medium_mmc(struct dfu_entity *dfu, void *buf, long *len) 116 { 117 int ret = -1; 118 119 switch (dfu->layout) { 120 case DFU_RAW_ADDR: 121 ret = mmc_block_write(dfu, buf, len); 122 break; 123 case DFU_FS_FAT: 124 case DFU_FS_EXT4: 125 ret = mmc_file_write(dfu, buf, len); 126 break; 127 default: 128 printf("%s: Layout (%s) not (yet) supported!\n", __func__, 129 dfu_get_layout(dfu->layout)); 130 } 131 132 return ret; 133 } 134 135 int dfu_read_medium_mmc(struct dfu_entity *dfu, void *buf, long *len) 136 { 137 int ret = -1; 138 139 switch (dfu->layout) { 140 case DFU_RAW_ADDR: 141 ret = mmc_block_read(dfu, buf, len); 142 break; 143 case DFU_FS_FAT: 144 case DFU_FS_EXT4: 145 ret = mmc_file_read(dfu, buf, len); 146 break; 147 default: 148 printf("%s: Layout (%s) not (yet) supported!\n", __func__, 149 dfu_get_layout(dfu->layout)); 150 } 151 152 return ret; 153 } 154 155 int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *s) 156 { 157 int dev, part; 158 struct mmc *mmc; 159 block_dev_desc_t *blk_dev; 160 disk_partition_t partinfo; 161 char *st; 162 163 dfu->dev_type = DFU_DEV_MMC; 164 st = strsep(&s, " "); 165 if (!strcmp(st, "mmc")) { 166 dfu->layout = DFU_RAW_ADDR; 167 dfu->data.mmc.lba_start = simple_strtoul(s, &s, 16); 168 dfu->data.mmc.lba_size = simple_strtoul(++s, &s, 16); 169 dfu->data.mmc.lba_blk_size = get_mmc_blk_size(dfu->dev_num); 170 } else if (!strcmp(st, "fat")) { 171 dfu->layout = DFU_FS_FAT; 172 } else if (!strcmp(st, "ext4")) { 173 dfu->layout = DFU_FS_EXT4; 174 } else if (!strcmp(st, "part")) { 175 176 dfu->layout = DFU_RAW_ADDR; 177 178 dev = simple_strtoul(s, &s, 10); 179 s++; 180 part = simple_strtoul(s, &s, 10); 181 182 mmc = find_mmc_device(dev); 183 if (mmc == NULL || mmc_init(mmc)) { 184 printf("%s: could not find mmc device #%d!\n", __func__, dev); 185 return -ENODEV; 186 } 187 188 blk_dev = &mmc->block_dev; 189 if (get_partition_info(blk_dev, part, &partinfo) != 0) { 190 printf("%s: could not find partition #%d on mmc device #%d!\n", 191 __func__, part, dev); 192 return -ENODEV; 193 } 194 195 dfu->data.mmc.lba_start = partinfo.start; 196 dfu->data.mmc.lba_size = partinfo.size; 197 dfu->data.mmc.lba_blk_size = partinfo.blksz; 198 199 } else { 200 printf("%s: Memory layout (%s) not supported!\n", __func__, st); 201 return -ENODEV; 202 } 203 204 if (dfu->layout == DFU_FS_EXT4 || dfu->layout == DFU_FS_FAT) { 205 dfu->data.mmc.dev = simple_strtoul(s, &s, 10); 206 dfu->data.mmc.part = simple_strtoul(++s, &s, 10); 207 } 208 209 dfu->read_medium = dfu_read_medium_mmc; 210 dfu->write_medium = dfu_write_medium_mmc; 211 212 return 0; 213 } 214