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