• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
fb_get_error(void)45 char *fb_get_error(void)
46 {
47     return ERROR;
48 }
49 
check_response(usb_handle * usb,unsigned int size,char * response)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 
_command_start(usb_handle * usb,const char * cmd,unsigned size,char * response)109 static int _command_start(usb_handle *usb, const char *cmd, unsigned size,
110                           char *response)
111 {
112     int cmdsize = strlen(cmd);
113     int r;
114 
115     if(response) {
116         response[0] = 0;
117     }
118 
119     if(cmdsize > 64) {
120         sprintf(ERROR,"command too large");
121         return -1;
122     }
123 
124     if(usb_write(usb, cmd, cmdsize) != cmdsize) {
125         sprintf(ERROR,"command write failed (%s)", strerror(errno));
126         usb_close(usb);
127         return -1;
128     }
129 
130     return check_response(usb, size, response);
131 }
132 
_command_data(usb_handle * usb,const void * data,unsigned size)133 static int _command_data(usb_handle *usb, const void *data, unsigned size)
134 {
135     int r;
136 
137     r = usb_write(usb, data, size);
138     if(r < 0) {
139         sprintf(ERROR, "data transfer failure (%s)", strerror(errno));
140         usb_close(usb);
141         return -1;
142     }
143     if(r != ((int) size)) {
144         sprintf(ERROR, "data transfer failure (short transfer)");
145         usb_close(usb);
146         return -1;
147     }
148 
149     return r;
150 }
151 
_command_end(usb_handle * usb)152 static int _command_end(usb_handle *usb)
153 {
154     int r;
155     r = check_response(usb, 0, 0);
156     if(r < 0) {
157         return -1;
158     }
159     return 0;
160 }
161 
_command_send(usb_handle * usb,const char * cmd,const void * data,unsigned size,char * response)162 static int _command_send(usb_handle *usb, const char *cmd,
163                          const void *data, unsigned size,
164                          char *response)
165 {
166     int r;
167     if (size == 0) {
168         return -1;
169     }
170 
171     r = _command_start(usb, cmd, size, response);
172     if (r < 0) {
173         return -1;
174     }
175 
176     r = _command_data(usb, data, size);
177     if (r < 0) {
178         return -1;
179     }
180 
181     r = _command_end(usb);
182     if(r < 0) {
183         return -1;
184     }
185 
186     return size;
187 }
188 
_command_send_no_data(usb_handle * usb,const char * cmd,char * response)189 static int _command_send_no_data(usb_handle *usb, const char *cmd,
190                                  char *response)
191 {
192     int r;
193 
194     return _command_start(usb, cmd, 0, response);
195 }
196 
fb_command(usb_handle * usb,const char * cmd)197 int fb_command(usb_handle *usb, const char *cmd)
198 {
199     return _command_send_no_data(usb, cmd, 0);
200 }
201 
fb_command_response(usb_handle * usb,const char * cmd,char * response)202 int fb_command_response(usb_handle *usb, const char *cmd, char *response)
203 {
204     return _command_send_no_data(usb, cmd, response);
205 }
206 
fb_download_data(usb_handle * usb,const void * data,unsigned size)207 int fb_download_data(usb_handle *usb, const void *data, unsigned size)
208 {
209     char cmd[64];
210     int r;
211 
212     sprintf(cmd, "download:%08x", size);
213     r = _command_send(usb, cmd, data, size, 0);
214 
215     if(r < 0) {
216         return -1;
217     } else {
218         return 0;
219     }
220 }
221 
222 #define USB_BUF_SIZE 512
223 static char usb_buf[USB_BUF_SIZE];
224 static int usb_buf_len;
225 
fb_download_data_sparse_write(void * priv,const void * data,int len)226 static int fb_download_data_sparse_write(void *priv, const void *data, int len)
227 {
228     int r;
229     usb_handle *usb = priv;
230     int to_write;
231     const char *ptr = data;
232 
233     if (usb_buf_len) {
234         to_write = min(USB_BUF_SIZE - usb_buf_len, len);
235 
236         memcpy(usb_buf + usb_buf_len, ptr, to_write);
237         usb_buf_len += to_write;
238         ptr += to_write;
239         len -= to_write;
240     }
241 
242     if (usb_buf_len == USB_BUF_SIZE) {
243         r = _command_data(usb, usb_buf, USB_BUF_SIZE);
244         if (r != USB_BUF_SIZE) {
245             return -1;
246         }
247         usb_buf_len = 0;
248     }
249 
250     if (len > USB_BUF_SIZE) {
251         if (usb_buf_len > 0) {
252             sprintf(ERROR, "internal error: usb_buf not empty\n");
253             return -1;
254         }
255         to_write = round_down(len, USB_BUF_SIZE);
256         r = _command_data(usb, ptr, to_write);
257         if (r != to_write) {
258             return -1;
259         }
260         ptr += to_write;
261         len -= to_write;
262     }
263 
264     if (len > 0) {
265         if (len > USB_BUF_SIZE) {
266             sprintf(ERROR, "internal error: too much left for usb_buf\n");
267             return -1;
268         }
269         memcpy(usb_buf, ptr, len);
270         usb_buf_len = len;
271     }
272 
273     return 0;
274 }
275 
fb_download_data_sparse_flush(usb_handle * usb)276 static int fb_download_data_sparse_flush(usb_handle *usb)
277 {
278     int r;
279 
280     if (usb_buf_len > 0) {
281         r = _command_data(usb, usb_buf, usb_buf_len);
282         if (r != usb_buf_len) {
283             return -1;
284         }
285         usb_buf_len = 0;
286     }
287 
288     return 0;
289 }
290 
fb_download_data_sparse(usb_handle * usb,struct sparse_file * s)291 int fb_download_data_sparse(usb_handle *usb, struct sparse_file *s)
292 {
293     char cmd[64];
294     int r;
295     int size = sparse_file_len(s, true, false);
296     if (size <= 0) {
297         return -1;
298     }
299 
300     sprintf(cmd, "download:%08x", size);
301     r = _command_start(usb, cmd, size, 0);
302     if (r < 0) {
303         return -1;
304     }
305 
306     r = sparse_file_callback(s, true, false, fb_download_data_sparse_write, usb);
307     if (r < 0) {
308         return -1;
309     }
310 
311     fb_download_data_sparse_flush(usb);
312 
313     return _command_end(usb);
314 }
315