blob: 00c8a034d8fbe594e2e9afa35dbf15bfa9a9bc01 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/*
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
Anatol Pomazau5ae3f932012-02-28 07:21:08 -080012 * the documentation and/or other materials provided with the
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080013 * 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
Anatol Pomazau5ae3f932012-02-28 07:21:08 -080022 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080023 * 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
Colin Crossf8387882012-05-24 17:18:41 -070029#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
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080034#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <errno.h>
38
Colin Crossf8387882012-05-24 17:18:41 -070039#include <sparse/sparse.h>
40
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080041#include "fastboot.h"
42
43static char ERROR[128];
44
45char *fb_get_error(void)
46{
47 return ERROR;
48}
49
Colin Crossf8387882012-05-24 17:18:41 -070050static int check_response(usb_handle *usb, unsigned int size, char *response)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080051{
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)) {
Brian Swetland63e52052010-06-28 11:14:26 -070071 fprintf(stderr,"(bootloader) %s\n", status + 4);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080072 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
Colin Crossf8387882012-05-24 17:18:41 -070091 if(!memcmp(status, "DATA", 4) && size > 0){
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080092 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
Colin Crossf8387882012-05-24 17:18:41 -0700109static int _command_start(usb_handle *usb, const char *cmd, unsigned size,
110 char *response)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800111{
112 int cmdsize = strlen(cmd);
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800113
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800114 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
Colin Crossf8387882012-05-24 17:18:41 -0700129 return check_response(usb, size, response);
130}
131
132static 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;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800146 }
147
Colin Crossf8387882012-05-24 17:18:41 -0700148 return r;
149}
150
151static int _command_end(usb_handle *usb)
152{
153 int r;
154 r = check_response(usb, 0, 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800155 if(r < 0) {
156 return -1;
157 }
Colin Crossf8387882012-05-24 17:18:41 -0700158 return 0;
159}
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800160
Colin Crossf8387882012-05-24 17:18:41 -0700161static 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;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800168 }
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800169
Colin Crossf8387882012-05-24 17:18:41 -0700170 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);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800181 if(r < 0) {
182 return -1;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800183 }
Colin Crossf8387882012-05-24 17:18:41 -0700184
185 return size;
186}
187
188static int _command_send_no_data(usb_handle *usb, const char *cmd,
189 char *response)
190{
Colin Crossf8387882012-05-24 17:18:41 -0700191 return _command_start(usb, cmd, 0, response);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800192}
193
194int fb_command(usb_handle *usb, const char *cmd)
195{
Colin Crossf8387882012-05-24 17:18:41 -0700196 return _command_send_no_data(usb, cmd, 0);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800197}
198
199int fb_command_response(usb_handle *usb, const char *cmd, char *response)
200{
Colin Crossf8387882012-05-24 17:18:41 -0700201 return _command_send_no_data(usb, cmd, response);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800202}
203
204int fb_download_data(usb_handle *usb, const void *data, unsigned size)
205{
206 char cmd[64];
207 int r;
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800208
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800209 sprintf(cmd, "download:%08x", size);
210 r = _command_send(usb, cmd, data, size, 0);
Anatol Pomazau5ae3f932012-02-28 07:21:08 -0800211
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800212 if(r < 0) {
213 return -1;
214 } else {
215 return 0;
216 }
217}
218
Channagoud Kadabib2117732014-11-05 16:59:27 -0800219#define USB_BUF_SIZE 1024
Colin Crossf8387882012-05-24 17:18:41 -0700220static char usb_buf[USB_BUF_SIZE];
221static int usb_buf_len;
222
223static int fb_download_data_sparse_write(void *priv, const void *data, int len)
224{
225 int r;
Elliott Hughesb3748de2015-06-23 20:27:58 -0700226 usb_handle* usb = reinterpret_cast<usb_handle*>(priv);
Colin Crossf8387882012-05-24 17:18:41 -0700227 int to_write;
Elliott Hughesb3748de2015-06-23 20:27:58 -0700228 const char* ptr = reinterpret_cast<const char*>(data);
Colin Crossf8387882012-05-24 17:18:41 -0700229
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
273static 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
288int 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
Jeremy Compostella9f0d6bd2015-02-22 10:47:16 +0100308 r = fb_download_data_sparse_flush(usb);
309 if (r < 0) {
310 return -1;
311 }
Colin Crossf8387882012-05-24 17:18:41 -0700312
313 return _command_end(usb);
314}