1f22b11c1SLukasz Majewski /* 2f22b11c1SLukasz Majewski * dfu.c -- DFU back-end routines 3f22b11c1SLukasz Majewski * 4f22b11c1SLukasz Majewski * Copyright (C) 2012 Samsung Electronics 5f22b11c1SLukasz Majewski * author: Lukasz Majewski <l.majewski@samsung.com> 6f22b11c1SLukasz Majewski * 7f22b11c1SLukasz Majewski * This program is free software; you can redistribute it and/or modify 8f22b11c1SLukasz Majewski * it under the terms of the GNU General Public License as published by 9f22b11c1SLukasz Majewski * the Free Software Foundation; either version 2 of the License, or 10f22b11c1SLukasz Majewski * (at your option) any later version. 11f22b11c1SLukasz Majewski * 12f22b11c1SLukasz Majewski * This program is distributed in the hope that it will be useful, 13f22b11c1SLukasz Majewski * but WITHOUT ANY WARRANTY; without even the implied warranty of 14f22b11c1SLukasz Majewski * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15f22b11c1SLukasz Majewski * GNU General Public License for more details. 16f22b11c1SLukasz Majewski * 17f22b11c1SLukasz Majewski * You should have received a copy of the GNU General Public License 18f22b11c1SLukasz Majewski * along with this program; if not, write to the Free Software 19f22b11c1SLukasz Majewski * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20f22b11c1SLukasz Majewski */ 21f22b11c1SLukasz Majewski 22f22b11c1SLukasz Majewski #include <common.h> 23f22b11c1SLukasz Majewski #include <malloc.h> 24f22b11c1SLukasz Majewski #include <mmc.h> 25f22b11c1SLukasz Majewski #include <fat.h> 26f22b11c1SLukasz Majewski #include <dfu.h> 27f22b11c1SLukasz Majewski #include <linux/list.h> 28f22b11c1SLukasz Majewski #include <linux/compiler.h> 29f22b11c1SLukasz Majewski 30f22b11c1SLukasz Majewski static LIST_HEAD(dfu_list); 31f22b11c1SLukasz Majewski static int dfu_alt_num; 32f22b11c1SLukasz Majewski 33f22b11c1SLukasz Majewski static int dfu_find_alt_num(const char *s) 34f22b11c1SLukasz Majewski { 35f22b11c1SLukasz Majewski int i = 0; 36f22b11c1SLukasz Majewski 37f22b11c1SLukasz Majewski for (; *s; s++) 38f22b11c1SLukasz Majewski if (*s == ';') 39f22b11c1SLukasz Majewski i++; 40f22b11c1SLukasz Majewski 41f22b11c1SLukasz Majewski return ++i; 42f22b11c1SLukasz Majewski } 43f22b11c1SLukasz Majewski 44f22b11c1SLukasz Majewski static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE) 45f22b11c1SLukasz Majewski dfu_buf[DFU_DATA_BUF_SIZE]; 46f22b11c1SLukasz Majewski 47*ea2453d5SPantelis Antoniou static int dfu_write_buffer_drain(struct dfu_entity *dfu) 48f22b11c1SLukasz Majewski { 49*ea2453d5SPantelis Antoniou long w_size; 50*ea2453d5SPantelis Antoniou int ret; 51f22b11c1SLukasz Majewski 52*ea2453d5SPantelis Antoniou /* flush size? */ 53*ea2453d5SPantelis Antoniou w_size = dfu->i_buf - dfu->i_buf_start; 54*ea2453d5SPantelis Antoniou if (w_size == 0) 55*ea2453d5SPantelis Antoniou return 0; 56f22b11c1SLukasz Majewski 57*ea2453d5SPantelis Antoniou /* update CRC32 */ 58*ea2453d5SPantelis Antoniou dfu->crc = crc32(dfu->crc, dfu->i_buf_start, w_size); 59f22b11c1SLukasz Majewski 60*ea2453d5SPantelis Antoniou ret = dfu->write_medium(dfu, dfu->offset, dfu->i_buf_start, &w_size); 61f22b11c1SLukasz Majewski if (ret) 62f22b11c1SLukasz Majewski debug("%s: Write error!\n", __func__); 63f22b11c1SLukasz Majewski 64*ea2453d5SPantelis Antoniou /* point back */ 65*ea2453d5SPantelis Antoniou dfu->i_buf = dfu->i_buf_start; 66*ea2453d5SPantelis Antoniou 67*ea2453d5SPantelis Antoniou /* update offset */ 68*ea2453d5SPantelis Antoniou dfu->offset += w_size; 69*ea2453d5SPantelis Antoniou 70*ea2453d5SPantelis Antoniou puts("#"); 71*ea2453d5SPantelis Antoniou 72f22b11c1SLukasz Majewski return ret; 73f22b11c1SLukasz Majewski } 74f22b11c1SLukasz Majewski 75*ea2453d5SPantelis Antoniou int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) 76*ea2453d5SPantelis Antoniou { 77*ea2453d5SPantelis Antoniou int ret = 0; 78*ea2453d5SPantelis Antoniou int tret; 79*ea2453d5SPantelis Antoniou 80*ea2453d5SPantelis Antoniou debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x offset: 0x%llx bufoffset: 0x%x\n", 81*ea2453d5SPantelis Antoniou __func__, dfu->name, buf, size, blk_seq_num, dfu->offset, 82*ea2453d5SPantelis Antoniou dfu->i_buf - dfu->i_buf_start); 83*ea2453d5SPantelis Antoniou 84*ea2453d5SPantelis Antoniou if (!dfu->inited) { 85*ea2453d5SPantelis Antoniou /* initial state */ 86*ea2453d5SPantelis Antoniou dfu->crc = 0; 87*ea2453d5SPantelis Antoniou dfu->offset = 0; 88*ea2453d5SPantelis Antoniou dfu->i_blk_seq_num = 0; 89*ea2453d5SPantelis Antoniou dfu->i_buf_start = dfu_buf; 90*ea2453d5SPantelis Antoniou dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); 91*ea2453d5SPantelis Antoniou dfu->i_buf = dfu->i_buf_start; 92*ea2453d5SPantelis Antoniou 93*ea2453d5SPantelis Antoniou dfu->inited = 1; 94*ea2453d5SPantelis Antoniou } 95*ea2453d5SPantelis Antoniou 96*ea2453d5SPantelis Antoniou if (dfu->i_blk_seq_num != blk_seq_num) { 97*ea2453d5SPantelis Antoniou printf("%s: Wrong sequence number! [%d] [%d]\n", 98*ea2453d5SPantelis Antoniou __func__, dfu->i_blk_seq_num, blk_seq_num); 99*ea2453d5SPantelis Antoniou return -1; 100*ea2453d5SPantelis Antoniou } 101*ea2453d5SPantelis Antoniou 102*ea2453d5SPantelis Antoniou /* DFU 1.1 standard says: 103*ea2453d5SPantelis Antoniou * The wBlockNum field is a block sequence number. It increments each 104*ea2453d5SPantelis Antoniou * time a block is transferred, wrapping to zero from 65,535. It is used 105*ea2453d5SPantelis Antoniou * to provide useful context to the DFU loader in the device." 106*ea2453d5SPantelis Antoniou * 107*ea2453d5SPantelis Antoniou * This means that it's a 16 bit counter that roll-overs at 108*ea2453d5SPantelis Antoniou * 0xffff -> 0x0000. By having a typical 4K transfer block 109*ea2453d5SPantelis Antoniou * we roll-over at exactly 256MB. Not very fun to debug. 110*ea2453d5SPantelis Antoniou * 111*ea2453d5SPantelis Antoniou * Handling rollover, and having an inited variable, 112*ea2453d5SPantelis Antoniou * makes things work. 113*ea2453d5SPantelis Antoniou */ 114*ea2453d5SPantelis Antoniou 115*ea2453d5SPantelis Antoniou /* handle rollover */ 116*ea2453d5SPantelis Antoniou dfu->i_blk_seq_num = (dfu->i_blk_seq_num + 1) & 0xffff; 117*ea2453d5SPantelis Antoniou 118*ea2453d5SPantelis Antoniou /* flush buffer if overflow */ 119*ea2453d5SPantelis Antoniou if ((dfu->i_buf + size) > dfu->i_buf_end) { 120*ea2453d5SPantelis Antoniou tret = dfu_write_buffer_drain(dfu); 121*ea2453d5SPantelis Antoniou if (ret == 0) 122*ea2453d5SPantelis Antoniou ret = tret; 123*ea2453d5SPantelis Antoniou } 124*ea2453d5SPantelis Antoniou 125*ea2453d5SPantelis Antoniou /* we should be in buffer now (if not then size too large) */ 126*ea2453d5SPantelis Antoniou if ((dfu->i_buf + size) > dfu->i_buf_end) { 127*ea2453d5SPantelis Antoniou printf("%s: Wrong size! [%d] [%d] - %d\n", 128*ea2453d5SPantelis Antoniou __func__, dfu->i_blk_seq_num, blk_seq_num, size); 129*ea2453d5SPantelis Antoniou return -1; 130*ea2453d5SPantelis Antoniou } 131*ea2453d5SPantelis Antoniou 132*ea2453d5SPantelis Antoniou memcpy(dfu->i_buf, buf, size); 133*ea2453d5SPantelis Antoniou dfu->i_buf += size; 134*ea2453d5SPantelis Antoniou 135*ea2453d5SPantelis Antoniou /* if end or if buffer full flush */ 136*ea2453d5SPantelis Antoniou if (size == 0 || (dfu->i_buf + size) > dfu->i_buf_end) { 137*ea2453d5SPantelis Antoniou tret = dfu_write_buffer_drain(dfu); 138*ea2453d5SPantelis Antoniou if (ret == 0) 139*ea2453d5SPantelis Antoniou ret = tret; 140*ea2453d5SPantelis Antoniou } 141*ea2453d5SPantelis Antoniou 142*ea2453d5SPantelis Antoniou /* end? */ 143*ea2453d5SPantelis Antoniou if (size == 0) { 144*ea2453d5SPantelis Antoniou /* Now try and flush to the medium if needed. */ 145*ea2453d5SPantelis Antoniou if (dfu->flush_medium) 146*ea2453d5SPantelis Antoniou ret = dfu->flush_medium(dfu); 147*ea2453d5SPantelis Antoniou printf("\nDFU complete CRC32: 0x%08x\n", dfu->crc); 148*ea2453d5SPantelis Antoniou 149*ea2453d5SPantelis Antoniou /* clear everything */ 150*ea2453d5SPantelis Antoniou dfu->crc = 0; 151*ea2453d5SPantelis Antoniou dfu->offset = 0; 152*ea2453d5SPantelis Antoniou dfu->i_blk_seq_num = 0; 153*ea2453d5SPantelis Antoniou dfu->i_buf_start = dfu_buf; 154*ea2453d5SPantelis Antoniou dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); 155*ea2453d5SPantelis Antoniou dfu->i_buf = dfu->i_buf_start; 156*ea2453d5SPantelis Antoniou 157*ea2453d5SPantelis Antoniou dfu->inited = 0; 158*ea2453d5SPantelis Antoniou 159*ea2453d5SPantelis Antoniou } 160*ea2453d5SPantelis Antoniou 161*ea2453d5SPantelis Antoniou return ret = 0 ? size : ret; 162*ea2453d5SPantelis Antoniou } 163*ea2453d5SPantelis Antoniou 164*ea2453d5SPantelis Antoniou static int dfu_read_buffer_fill(struct dfu_entity *dfu, void *buf, int size) 165*ea2453d5SPantelis Antoniou { 166*ea2453d5SPantelis Antoniou long chunk; 167*ea2453d5SPantelis Antoniou int ret, readn; 168*ea2453d5SPantelis Antoniou 169*ea2453d5SPantelis Antoniou readn = 0; 170*ea2453d5SPantelis Antoniou while (size > 0) { 171*ea2453d5SPantelis Antoniou /* get chunk that can be read */ 172*ea2453d5SPantelis Antoniou chunk = min(size, dfu->b_left); 173*ea2453d5SPantelis Antoniou /* consume */ 174*ea2453d5SPantelis Antoniou if (chunk > 0) { 175*ea2453d5SPantelis Antoniou memcpy(buf, dfu->i_buf, chunk); 176*ea2453d5SPantelis Antoniou dfu->crc = crc32(dfu->crc, buf, chunk); 177*ea2453d5SPantelis Antoniou dfu->i_buf += chunk; 178*ea2453d5SPantelis Antoniou dfu->b_left -= chunk; 179*ea2453d5SPantelis Antoniou size -= chunk; 180*ea2453d5SPantelis Antoniou buf += chunk; 181*ea2453d5SPantelis Antoniou readn += chunk; 182*ea2453d5SPantelis Antoniou } 183*ea2453d5SPantelis Antoniou 184*ea2453d5SPantelis Antoniou /* all done */ 185*ea2453d5SPantelis Antoniou if (size > 0) { 186*ea2453d5SPantelis Antoniou /* no more to read */ 187*ea2453d5SPantelis Antoniou if (dfu->r_left == 0) 188*ea2453d5SPantelis Antoniou break; 189*ea2453d5SPantelis Antoniou 190*ea2453d5SPantelis Antoniou dfu->i_buf = dfu->i_buf_start; 191*ea2453d5SPantelis Antoniou dfu->b_left = dfu->i_buf_end - dfu->i_buf_start; 192*ea2453d5SPantelis Antoniou 193*ea2453d5SPantelis Antoniou /* got to read, but buffer is empty */ 194*ea2453d5SPantelis Antoniou if (dfu->b_left > dfu->r_left) 195*ea2453d5SPantelis Antoniou dfu->b_left = dfu->r_left; 196*ea2453d5SPantelis Antoniou ret = dfu->read_medium(dfu, dfu->offset, dfu->i_buf, 197*ea2453d5SPantelis Antoniou &dfu->b_left); 198*ea2453d5SPantelis Antoniou if (ret != 0) { 199*ea2453d5SPantelis Antoniou debug("%s: Read error!\n", __func__); 200f22b11c1SLukasz Majewski return ret; 201f22b11c1SLukasz Majewski } 202*ea2453d5SPantelis Antoniou dfu->offset += dfu->b_left; 203*ea2453d5SPantelis Antoniou dfu->r_left -= dfu->b_left; 204*ea2453d5SPantelis Antoniou 205*ea2453d5SPantelis Antoniou puts("#"); 206*ea2453d5SPantelis Antoniou } 207*ea2453d5SPantelis Antoniou } 208*ea2453d5SPantelis Antoniou 209*ea2453d5SPantelis Antoniou return readn; 210*ea2453d5SPantelis Antoniou } 211f22b11c1SLukasz Majewski 212f22b11c1SLukasz Majewski int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) 213f22b11c1SLukasz Majewski { 214f22b11c1SLukasz Majewski int ret = 0; 215f22b11c1SLukasz Majewski 216f22b11c1SLukasz Majewski debug("%s: name: %s buf: 0x%p size: 0x%x p_num: 0x%x i_buf: 0x%p\n", 217*ea2453d5SPantelis Antoniou __func__, dfu->name, buf, size, blk_seq_num, dfu->i_buf); 218f22b11c1SLukasz Majewski 219*ea2453d5SPantelis Antoniou if (!dfu->inited) { 220*ea2453d5SPantelis Antoniou ret = dfu->read_medium(dfu, 0, buf, &dfu->r_left); 221*ea2453d5SPantelis Antoniou if (ret != 0) { 222*ea2453d5SPantelis Antoniou debug("%s: failed to get r_left\n", __func__); 223*ea2453d5SPantelis Antoniou return ret; 224f22b11c1SLukasz Majewski } 225f22b11c1SLukasz Majewski 226*ea2453d5SPantelis Antoniou debug("%s: %s %ld [B]\n", __func__, dfu->name, dfu->r_left); 227*ea2453d5SPantelis Antoniou 228*ea2453d5SPantelis Antoniou dfu->i_blk_seq_num = 0; 229*ea2453d5SPantelis Antoniou dfu->crc = 0; 230*ea2453d5SPantelis Antoniou dfu->offset = 0; 231*ea2453d5SPantelis Antoniou dfu->i_buf_start = dfu_buf; 232*ea2453d5SPantelis Antoniou dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); 233*ea2453d5SPantelis Antoniou dfu->i_buf = dfu->i_buf_start; 234*ea2453d5SPantelis Antoniou dfu->b_left = 0; 235*ea2453d5SPantelis Antoniou 236*ea2453d5SPantelis Antoniou dfu->inited = 1; 237*ea2453d5SPantelis Antoniou } 238*ea2453d5SPantelis Antoniou 239*ea2453d5SPantelis Antoniou if (dfu->i_blk_seq_num != blk_seq_num) { 240f22b11c1SLukasz Majewski printf("%s: Wrong sequence number! [%d] [%d]\n", 241*ea2453d5SPantelis Antoniou __func__, dfu->i_blk_seq_num, blk_seq_num); 242*ea2453d5SPantelis Antoniou return -1; 243*ea2453d5SPantelis Antoniou } 244*ea2453d5SPantelis Antoniou /* handle rollover */ 245*ea2453d5SPantelis Antoniou dfu->i_blk_seq_num = (dfu->i_blk_seq_num + 1) & 0xffff; 246*ea2453d5SPantelis Antoniou 247*ea2453d5SPantelis Antoniou ret = dfu_read_buffer_fill(dfu, buf, size); 248*ea2453d5SPantelis Antoniou if (ret < 0) { 249*ea2453d5SPantelis Antoniou printf("%s: Failed to fill buffer\n", __func__); 250f22b11c1SLukasz Majewski return -1; 251f22b11c1SLukasz Majewski } 252f22b11c1SLukasz Majewski 253*ea2453d5SPantelis Antoniou if (ret < size) { 254*ea2453d5SPantelis Antoniou debug("%s: %s CRC32: 0x%x\n", __func__, dfu->name, dfu->crc); 255*ea2453d5SPantelis Antoniou puts("\nUPLOAD ... done\nCtrl+C to exit ...\n"); 256f22b11c1SLukasz Majewski 257*ea2453d5SPantelis Antoniou dfu->i_blk_seq_num = 0; 258*ea2453d5SPantelis Antoniou dfu->crc = 0; 259*ea2453d5SPantelis Antoniou dfu->offset = 0; 260*ea2453d5SPantelis Antoniou dfu->i_buf_start = dfu_buf; 261*ea2453d5SPantelis Antoniou dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); 262*ea2453d5SPantelis Antoniou dfu->i_buf = dfu->i_buf_start; 263*ea2453d5SPantelis Antoniou dfu->b_left = 0; 264*ea2453d5SPantelis Antoniou 265*ea2453d5SPantelis Antoniou dfu->inited = 0; 266f22b11c1SLukasz Majewski } 267*ea2453d5SPantelis Antoniou 268f22b11c1SLukasz Majewski return ret; 269f22b11c1SLukasz Majewski } 270f22b11c1SLukasz Majewski 271f22b11c1SLukasz Majewski static int dfu_fill_entity(struct dfu_entity *dfu, char *s, int alt, 272f22b11c1SLukasz Majewski char *interface, int num) 273f22b11c1SLukasz Majewski { 274f22b11c1SLukasz Majewski char *st; 275f22b11c1SLukasz Majewski 276f22b11c1SLukasz Majewski debug("%s: %s interface: %s num: %d\n", __func__, s, interface, num); 277f22b11c1SLukasz Majewski st = strsep(&s, " "); 278f22b11c1SLukasz Majewski strcpy(dfu->name, st); 279f22b11c1SLukasz Majewski 280f22b11c1SLukasz Majewski dfu->dev_num = num; 281f22b11c1SLukasz Majewski dfu->alt = alt; 282f22b11c1SLukasz Majewski 283f22b11c1SLukasz Majewski /* Specific for mmc device */ 284f22b11c1SLukasz Majewski if (strcmp(interface, "mmc") == 0) { 285f22b11c1SLukasz Majewski if (dfu_fill_entity_mmc(dfu, s)) 286f22b11c1SLukasz Majewski return -1; 287f22b11c1SLukasz Majewski } else { 288f22b11c1SLukasz Majewski printf("%s: Device %s not (yet) supported!\n", 289f22b11c1SLukasz Majewski __func__, interface); 290f22b11c1SLukasz Majewski return -1; 291f22b11c1SLukasz Majewski } 292f22b11c1SLukasz Majewski 293f22b11c1SLukasz Majewski return 0; 294f22b11c1SLukasz Majewski } 295f22b11c1SLukasz Majewski 296f22b11c1SLukasz Majewski void dfu_free_entities(void) 297f22b11c1SLukasz Majewski { 298f22b11c1SLukasz Majewski struct dfu_entity *dfu, *p, *t = NULL; 299f22b11c1SLukasz Majewski 300f22b11c1SLukasz Majewski list_for_each_entry_safe_reverse(dfu, p, &dfu_list, list) { 301f22b11c1SLukasz Majewski list_del(&dfu->list); 302f22b11c1SLukasz Majewski t = dfu; 303f22b11c1SLukasz Majewski } 304f22b11c1SLukasz Majewski if (t) 305f22b11c1SLukasz Majewski free(t); 306f22b11c1SLukasz Majewski INIT_LIST_HEAD(&dfu_list); 307f22b11c1SLukasz Majewski } 308f22b11c1SLukasz Majewski 309f22b11c1SLukasz Majewski int dfu_config_entities(char *env, char *interface, int num) 310f22b11c1SLukasz Majewski { 311f22b11c1SLukasz Majewski struct dfu_entity *dfu; 312f22b11c1SLukasz Majewski int i, ret; 313f22b11c1SLukasz Majewski char *s; 314f22b11c1SLukasz Majewski 315f22b11c1SLukasz Majewski dfu_alt_num = dfu_find_alt_num(env); 316f22b11c1SLukasz Majewski debug("%s: dfu_alt_num=%d\n", __func__, dfu_alt_num); 317f22b11c1SLukasz Majewski 318f22b11c1SLukasz Majewski dfu = calloc(sizeof(*dfu), dfu_alt_num); 319f22b11c1SLukasz Majewski if (!dfu) 320f22b11c1SLukasz Majewski return -1; 321f22b11c1SLukasz Majewski for (i = 0; i < dfu_alt_num; i++) { 322f22b11c1SLukasz Majewski 323f22b11c1SLukasz Majewski s = strsep(&env, ";"); 324f22b11c1SLukasz Majewski ret = dfu_fill_entity(&dfu[i], s, i, interface, num); 325f22b11c1SLukasz Majewski if (ret) 326f22b11c1SLukasz Majewski return -1; 327f22b11c1SLukasz Majewski 328f22b11c1SLukasz Majewski list_add_tail(&dfu[i].list, &dfu_list); 329f22b11c1SLukasz Majewski } 330f22b11c1SLukasz Majewski 331f22b11c1SLukasz Majewski return 0; 332f22b11c1SLukasz Majewski } 333f22b11c1SLukasz Majewski 334f22b11c1SLukasz Majewski const char *dfu_get_dev_type(enum dfu_device_type t) 335f22b11c1SLukasz Majewski { 336f22b11c1SLukasz Majewski const char *dev_t[] = {NULL, "eMMC", "OneNAND", "NAND" }; 337f22b11c1SLukasz Majewski return dev_t[t]; 338f22b11c1SLukasz Majewski } 339f22b11c1SLukasz Majewski 340f22b11c1SLukasz Majewski const char *dfu_get_layout(enum dfu_layout l) 341f22b11c1SLukasz Majewski { 342f22b11c1SLukasz Majewski const char *dfu_layout[] = {NULL, "RAW_ADDR", "FAT", "EXT2", 343f22b11c1SLukasz Majewski "EXT3", "EXT4" }; 344f22b11c1SLukasz Majewski return dfu_layout[l]; 345f22b11c1SLukasz Majewski } 346f22b11c1SLukasz Majewski 347f22b11c1SLukasz Majewski void dfu_show_entities(void) 348f22b11c1SLukasz Majewski { 349f22b11c1SLukasz Majewski struct dfu_entity *dfu; 350f22b11c1SLukasz Majewski 351f22b11c1SLukasz Majewski puts("DFU alt settings list:\n"); 352f22b11c1SLukasz Majewski 353f22b11c1SLukasz Majewski list_for_each_entry(dfu, &dfu_list, list) { 354f22b11c1SLukasz Majewski printf("dev: %s alt: %d name: %s layout: %s\n", 355f22b11c1SLukasz Majewski dfu_get_dev_type(dfu->dev_type), dfu->alt, 356f22b11c1SLukasz Majewski dfu->name, dfu_get_layout(dfu->layout)); 357f22b11c1SLukasz Majewski } 358f22b11c1SLukasz Majewski } 359f22b11c1SLukasz Majewski 360f22b11c1SLukasz Majewski int dfu_get_alt_number(void) 361f22b11c1SLukasz Majewski { 362f22b11c1SLukasz Majewski return dfu_alt_num; 363f22b11c1SLukasz Majewski } 364f22b11c1SLukasz Majewski 365f22b11c1SLukasz Majewski struct dfu_entity *dfu_get_entity(int alt) 366f22b11c1SLukasz Majewski { 367f22b11c1SLukasz Majewski struct dfu_entity *dfu; 368f22b11c1SLukasz Majewski 369f22b11c1SLukasz Majewski list_for_each_entry(dfu, &dfu_list, list) { 370f22b11c1SLukasz Majewski if (dfu->alt == alt) 371f22b11c1SLukasz Majewski return dfu; 372f22b11c1SLukasz Majewski } 373f22b11c1SLukasz Majewski 374f22b11c1SLukasz Majewski return NULL; 375f22b11c1SLukasz Majewski } 376