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 <mmc.h> 25 #include <fat.h> 26 #include <dfu.h> 27 #include <linux/list.h> 28 #include <linux/compiler.h> 29 30 static LIST_HEAD(dfu_list); 31 static int dfu_alt_num; 32 33 static int dfu_find_alt_num(const char *s) 34 { 35 int i = 0; 36 37 for (; *s; s++) 38 if (*s == ';') 39 i++; 40 41 return ++i; 42 } 43 44 static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE) 45 dfu_buf[DFU_DATA_BUF_SIZE]; 46 47 int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) 48 { 49 static unsigned char *i_buf; 50 static int i_blk_seq_num; 51 long w_size = 0; 52 int ret = 0; 53 54 debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x i_buf: 0x%p\n", 55 __func__, dfu->name, buf, size, blk_seq_num, i_buf); 56 57 if (blk_seq_num == 0) { 58 i_buf = dfu_buf; 59 i_blk_seq_num = 0; 60 } 61 62 if (i_blk_seq_num++ != blk_seq_num) { 63 printf("%s: Wrong sequence number! [%d] [%d]\n", 64 __func__, i_blk_seq_num, blk_seq_num); 65 return -1; 66 } 67 68 memcpy(i_buf, buf, size); 69 i_buf += size; 70 71 if (size == 0) { 72 /* Integrity check (if needed) */ 73 debug("%s: %s %d [B] CRC32: 0x%x\n", __func__, dfu->name, 74 i_buf - dfu_buf, crc32(0, dfu_buf, i_buf - dfu_buf)); 75 76 w_size = i_buf - dfu_buf; 77 ret = dfu->write_medium(dfu, dfu_buf, &w_size); 78 if (ret) 79 debug("%s: Write error!\n", __func__); 80 81 i_blk_seq_num = 0; 82 i_buf = NULL; 83 return ret; 84 } 85 86 return ret; 87 } 88 89 int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) 90 { 91 static unsigned char *i_buf; 92 static int i_blk_seq_num; 93 static long r_size; 94 static u32 crc; 95 int ret = 0; 96 97 debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x i_buf: 0x%p\n", 98 __func__, dfu->name, buf, size, blk_seq_num, i_buf); 99 100 if (blk_seq_num == 0) { 101 i_buf = dfu_buf; 102 ret = dfu->read_medium(dfu, i_buf, &r_size); 103 debug("%s: %s %ld [B]\n", __func__, dfu->name, r_size); 104 i_blk_seq_num = 0; 105 /* Integrity check (if needed) */ 106 crc = crc32(0, dfu_buf, r_size); 107 } 108 109 if (i_blk_seq_num++ != blk_seq_num) { 110 printf("%s: Wrong sequence number! [%d] [%d]\n", 111 __func__, i_blk_seq_num, blk_seq_num); 112 return -1; 113 } 114 115 if (r_size >= size) { 116 memcpy(buf, i_buf, size); 117 i_buf += size; 118 r_size -= size; 119 return size; 120 } else { 121 memcpy(buf, i_buf, r_size); 122 i_buf += r_size; 123 debug("%s: %s CRC32: 0x%x\n", __func__, dfu->name, crc); 124 puts("UPLOAD ... done\nCtrl+C to exit ...\n"); 125 126 i_buf = NULL; 127 i_blk_seq_num = 0; 128 crc = 0; 129 return r_size; 130 } 131 return ret; 132 } 133 134 static int dfu_fill_entity(struct dfu_entity *dfu, char *s, int alt, 135 char *interface, int num) 136 { 137 char *st; 138 139 debug("%s: %s interface: %s num: %d\n", __func__, s, interface, num); 140 st = strsep(&s, " "); 141 strcpy(dfu->name, st); 142 143 dfu->dev_num = num; 144 dfu->alt = alt; 145 146 /* Specific for mmc device */ 147 if (strcmp(interface, "mmc") == 0) { 148 if (dfu_fill_entity_mmc(dfu, s)) 149 return -1; 150 } else { 151 printf("%s: Device %s not (yet) supported!\n", 152 __func__, interface); 153 return -1; 154 } 155 156 return 0; 157 } 158 159 void dfu_free_entities(void) 160 { 161 struct dfu_entity *dfu, *p, *t = NULL; 162 163 list_for_each_entry_safe_reverse(dfu, p, &dfu_list, list) { 164 list_del(&dfu->list); 165 t = dfu; 166 } 167 if (t) 168 free(t); 169 INIT_LIST_HEAD(&dfu_list); 170 } 171 172 int dfu_config_entities(char *env, char *interface, int num) 173 { 174 struct dfu_entity *dfu; 175 int i, ret; 176 char *s; 177 178 dfu_alt_num = dfu_find_alt_num(env); 179 debug("%s: dfu_alt_num=%d\n", __func__, dfu_alt_num); 180 181 dfu = calloc(sizeof(*dfu), dfu_alt_num); 182 if (!dfu) 183 return -1; 184 for (i = 0; i < dfu_alt_num; i++) { 185 186 s = strsep(&env, ";"); 187 ret = dfu_fill_entity(&dfu[i], s, i, interface, num); 188 if (ret) 189 return -1; 190 191 list_add_tail(&dfu[i].list, &dfu_list); 192 } 193 194 return 0; 195 } 196 197 const char *dfu_get_dev_type(enum dfu_device_type t) 198 { 199 const char *dev_t[] = {NULL, "eMMC", "OneNAND", "NAND" }; 200 return dev_t[t]; 201 } 202 203 const char *dfu_get_layout(enum dfu_layout l) 204 { 205 const char *dfu_layout[] = {NULL, "RAW_ADDR", "FAT", "EXT2", 206 "EXT3", "EXT4" }; 207 return dfu_layout[l]; 208 } 209 210 void dfu_show_entities(void) 211 { 212 struct dfu_entity *dfu; 213 214 puts("DFU alt settings list:\n"); 215 216 list_for_each_entry(dfu, &dfu_list, list) { 217 printf("dev: %s alt: %d name: %s layout: %s\n", 218 dfu_get_dev_type(dfu->dev_type), dfu->alt, 219 dfu->name, dfu_get_layout(dfu->layout)); 220 } 221 } 222 223 int dfu_get_alt_number(void) 224 { 225 return dfu_alt_num; 226 } 227 228 struct dfu_entity *dfu_get_entity(int alt) 229 { 230 struct dfu_entity *dfu; 231 232 list_for_each_entry(dfu, &dfu_list, list) { 233 if (dfu->alt == alt) 234 return dfu; 235 } 236 237 return NULL; 238 } 239