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