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