Home | History | Annotate | Download | only in fastboot
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
     19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
     22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #define min(a, b) \
     30     ({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
     31 #define round_down(a, b) \
     32     ({ typeof(a) _a = (a); typeof(b) _b = (b); _a - (_a % _b); })
     33 
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #include <errno.h>
     38 
     39 #include <sparse/sparse.h>
     40 
     41 #include "fastboot.h"
     42 
     43 static char ERROR[128];
     44 
     45 char *fb_get_error(void)
     46 {
     47     return ERROR;
     48 }
     49 
     50 static int check_response(usb_handle *usb, unsigned int size, char *response)
     51 {
     52     unsigned char status[65];
     53     int r;
     54 
     55     for(;;) {
     56         r = usb_read(usb, status, 64);
     57         if(r < 0) {
     58             sprintf(ERROR, "status read failed (%s)", strerror(errno));
     59             usb_close(usb);
     60             return -1;
     61         }
     62         status[r] = 0;
     63 
     64         if(r < 4) {
     65             sprintf(ERROR, "status malformed (%d bytes)", r);
     66             usb_close(usb);
     67             return -1;
     68         }
     69 
     70         if(!memcmp(status, "INFO", 4)) {
     71             fprintf(stderr,"(bootloader) %s\n", status + 4);
     72             continue;
     73         }
     74 
     75         if(!memcmp(status, "OKAY", 4)) {
     76             if(response) {
     77                 strcpy(response, (char*) status + 4);
     78             }
     79             return 0;
     80         }
     81 
     82         if(!memcmp(status, "FAIL", 4)) {
     83             if(r > 4) {
     84                 sprintf(ERROR, "remote: %s", status + 4);
     85             } else {
     86                 strcpy(ERROR, "remote failure");
     87             }
     88             return -1;
     89         }
     90 
     91         if(!memcmp(status, "DATA", 4) && size > 0){
     92             unsigned dsize = strtoul((char*) status + 4, 0, 16);
     93             if(dsize > size) {
     94                 strcpy(ERROR, "data size too large");
     95                 usb_close(usb);
     96                 return -1;
     97             }
     98             return dsize;
     99         }
    100 
    101         strcpy(ERROR,"unknown status code");
    102         usb_close(usb);
    103         break;
    104     }
    105 
    106     return -1;
    107 }
    108 
    109 static int _command_start(usb_handle *usb, const char *cmd, unsigned size,
    110                           char *response)
    111 {
    112     int cmdsize = strlen(cmd);
    113 
    114     if(response) {
    115         response[0] = 0;
    116     }
    117 
    118     if(cmdsize > 64) {
    119         sprintf(ERROR,"command too large");
    120         return -1;
    121     }
    122 
    123     if(usb_write(usb, cmd, cmdsize) != cmdsize) {
    124         sprintf(ERROR,"command write failed (%s)", strerror(errno));
    125         usb_close(usb);
    126         return -1;
    127     }
    128 
    129     return check_response(usb, size, response);
    130 }
    131 
    132 static int _command_data(usb_handle *usb, const void *data, unsigned size)
    133 {
    134     int r;
    135 
    136     r = usb_write(usb, data, size);
    137     if(r < 0) {
    138         sprintf(ERROR, "data transfer failure (%s)", strerror(errno));
    139         usb_close(usb);
    140         return -1;
    141     }
    142     if(r != ((int) size)) {
    143         sprintf(ERROR, "data transfer failure (short transfer)");
    144         usb_close(usb);
    145         return -1;
    146     }
    147 
    148     return r;
    149 }
    150 
    151 static int _command_end(usb_handle *usb)
    152 {
    153     int r;
    154     r = check_response(usb, 0, 0);
    155     if(r < 0) {
    156         return -1;
    157     }
    158     return 0;
    159 }
    160 
    161 static int _command_send(usb_handle *usb, const char *cmd,
    162                          const void *data, unsigned size,
    163                          char *response)
    164 {
    165     int r;
    166     if (size == 0) {
    167         return -1;
    168     }
    169 
    170     r = _command_start(usb, cmd, size, response);
    171     if (r < 0) {
    172         return -1;
    173     }
    174 
    175     r = _command_data(usb, data, size);
    176     if (r < 0) {
    177         return -1;
    178     }
    179 
    180     r = _command_end(usb);
    181     if(r < 0) {
    182         return -1;
    183     }
    184 
    185     return size;
    186 }
    187 
    188 static int _command_send_no_data(usb_handle *usb, const char *cmd,
    189                                  char *response)
    190 {
    191     return _command_start(usb, cmd, 0, response);
    192 }
    193 
    194 int fb_command(usb_handle *usb, const char *cmd)
    195 {
    196     return _command_send_no_data(usb, cmd, 0);
    197 }
    198 
    199 int fb_command_response(usb_handle *usb, const char *cmd, char *response)
    200 {
    201     return _command_send_no_data(usb, cmd, response);
    202 }
    203 
    204 int fb_download_data(usb_handle *usb, const void *data, unsigned size)
    205 {
    206     char cmd[64];
    207     int r;
    208 
    209     sprintf(cmd, "download:%08x", size);
    210     r = _command_send(usb, cmd, data, size, 0);
    211 
    212     if(r < 0) {
    213         return -1;
    214     } else {
    215         return 0;
    216     }
    217 }
    218 
    219 #define USB_BUF_SIZE 1024
    220 static char usb_buf[USB_BUF_SIZE];
    221 static int usb_buf_len;
    222 
    223 static int fb_download_data_sparse_write(void *priv, const void *data, int len)
    224 {
    225     int r;
    226     usb_handle *usb = priv;
    227     int to_write;
    228     const char *ptr = data;
    229 
    230     if (usb_buf_len) {
    231         to_write = min(USB_BUF_SIZE - usb_buf_len, len);
    232 
    233         memcpy(usb_buf + usb_buf_len, ptr, to_write);
    234         usb_buf_len += to_write;
    235         ptr += to_write;
    236         len -= to_write;
    237     }
    238 
    239     if (usb_buf_len == USB_BUF_SIZE) {
    240         r = _command_data(usb, usb_buf, USB_BUF_SIZE);
    241         if (r != USB_BUF_SIZE) {
    242             return -1;
    243         }
    244         usb_buf_len = 0;
    245     }
    246 
    247     if (len > USB_BUF_SIZE) {
    248         if (usb_buf_len > 0) {
    249             sprintf(ERROR, "internal error: usb_buf not empty\n");
    250             return -1;
    251         }
    252         to_write = round_down(len, USB_BUF_SIZE);
    253         r = _command_data(usb, ptr, to_write);
    254         if (r != to_write) {
    255             return -1;
    256         }
    257         ptr += to_write;
    258         len -= to_write;
    259     }
    260 
    261     if (len > 0) {
    262         if (len > USB_BUF_SIZE) {
    263             sprintf(ERROR, "internal error: too much left for usb_buf\n");
    264             return -1;
    265         }
    266         memcpy(usb_buf, ptr, len);
    267         usb_buf_len = len;
    268     }
    269 
    270     return 0;
    271 }
    272 
    273 static int fb_download_data_sparse_flush(usb_handle *usb)
    274 {
    275     int r;
    276 
    277     if (usb_buf_len > 0) {
    278         r = _command_data(usb, usb_buf, usb_buf_len);
    279         if (r != usb_buf_len) {
    280             return -1;
    281         }
    282         usb_buf_len = 0;
    283     }
    284 
    285     return 0;
    286 }
    287 
    288 int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s)
    289 {
    290     char cmd[64];
    291     int r;
    292     int size = sparse_file_len(s, true, false);
    293     if (size <= 0) {
    294         return -1;
    295     }
    296 
    297     sprintf(cmd, "download:%08x", size);
    298     r = _command_start(usb, cmd, size, 0);
    299     if (r < 0) {
    300         return -1;
    301     }
    302 
    303     r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, usb);
    304     if (r < 0) {
    305         return -1;
    306     }
    307 
    308     r = fb_download_data_sparse_flush(usb);
    309     if (r < 0) {
    310         return -1;
    311     }
    312 
    313     return _command_end(usb);
    314 }
    315