Root/jzboot/src/usbdev.c

1/*
2 * JzBoot: an USB bootloader for JZ series of Ingenic(R) microprocessors.
3 * Copyright (C) 2010 Sergey Gridassov <grindars@gmail.com>,
4 * Peter Zotov <whitequark@whitequark.org>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <errno.h>
21#include <libusb.h>
22
23#include "usbdev.h"
24#include "debug.h"
25#include "devmgr.h"
26
27#define CONTROL_TIMEOUT 5000
28
29static libusb_context *ctx = NULL;
30
31static int translate_libusb(int code);
32
33int usbdev_enumerate() {
34    libusb_device **list;
35    ssize_t devices_count = libusb_get_device_list(ctx, &list);
36
37    if(devices_count < 0)
38        return translate_libusb(devices_count);
39
40    for(int i = 0; i < devices_count; i++) {
41        struct libusb_device_descriptor descr;
42
43        int ret = libusb_get_device_descriptor(list[i], &descr);
44
45        if(ret != LIBUSB_SUCCESS) {
46            libusb_free_device_list(list, 1);
47
48            return translate_libusb(ret);
49        }
50
51        if(is_ingenic(descr.idVendor, descr.idProduct)) {
52            add_device(descr.idVendor, descr.idProduct, libusb_ref_device(list[i]));
53        }
54    }
55
56    libusb_free_device_list(list, 1);
57
58    return 0;
59}
60
61int usbdev_init() {
62    if(translate_libusb(libusb_init(&ctx)) == -1)
63        return -1;
64
65    libusb_set_debug(ctx, get_debug_level());
66
67    return 0;
68}
69
70void usbdev_fini() {
71    libusb_exit(ctx);
72    ctx = NULL;
73}
74
75void *usbdev_open(void *dev) {
76    libusb_device_handle *hndl;
77
78    if(translate_libusb(libusb_open(dev, &hndl)) == -1)
79        return NULL;
80
81    int ret = libusb_kernel_driver_active(hndl, INTERFACE_BOOT);
82
83    if(ret < 0) {
84        libusb_close(hndl);
85
86        translate_libusb(ret);
87
88        return NULL;
89
90    } else if(ret == 1) {
91        debug(LEVEL_INFO, "Deactivating kernel driver\n");
92
93        if(translate_libusb(libusb_detach_kernel_driver(hndl, INTERFACE_BOOT)) == -1) {
94            libusb_close(hndl);
95
96            return NULL;
97        }
98    }
99
100    if(translate_libusb(libusb_claim_interface(hndl, INTERFACE_BOOT)) == -1) {
101        libusb_close(hndl);
102
103        return NULL;
104    }
105
106    debug(LEVEL_DEBUG, "Device open\n");
107
108    return hndl;
109}
110
111void usbdev_close(void *_hndl) {
112    libusb_device_handle *hndl = _hndl;
113
114    libusb_release_interface(hndl, INTERFACE_BOOT);
115
116    libusb_close(hndl);
117
118    debug(LEVEL_DEBUG, "Device closed\n");
119}
120
121int usbdev_vendor(void *_hndl, int direction, uint8_t req, uint16_t value, uint16_t index, void *data, uint16_t size) {
122    libusb_device_handle *hndl = _hndl;
123
124    uint8_t type = LIBUSB_REQUEST_TYPE_VENDOR;
125
126    if(direction == USBDEV_FROMDEV)
127        type |= LIBUSB_ENDPOINT_IN;
128
129    debug(LEVEL_DEBUG, "Control: type %02hhX, request %hhu, value %hu, index %hu, data %p, size %hu\n", type, req, value, index, data, size);
130
131    int ret = libusb_control_transfer(hndl, type, req, value, index, data, size, CONTROL_TIMEOUT);
132
133    if(ret >= 0)
134        return ret;
135    else
136        return translate_libusb(ret);
137}
138
139int usbdev_sendbulk(void *hndl, void *data, int size) {
140    int trans;
141
142    debug(LEVEL_DEBUG, "Bulk: writing data %p, size %d\n", data, size);
143
144    if(translate_libusb(libusb_bulk_transfer(hndl, ENDPOINT_OUT, data, size, &trans, CONTROL_TIMEOUT)) == -1) {
145        return -1;
146    }
147
148    if(trans != size) {
149        debug(LEVEL_WARNING, "Bulk data truncated: requested %d, sent %d\n", size, trans);
150
151        errno = EIO;
152
153        return -1;
154    }
155
156    return 0;
157}
158
159int usbdev_recvbulk(void *hndl, void *data, int size) {
160    int trans;
161
162    debug(LEVEL_DEBUG, "Bulk: reading data %p, size %d\n", data, size);
163
164    int ret = translate_libusb(libusb_bulk_transfer(hndl, ENDPOINT_IN, data, size, &trans, CONTROL_TIMEOUT));
165
166    return ret == -1 ? -1 : trans;
167}
168
169static int translate_libusb(int code) {
170    switch(code) {
171    case LIBUSB_SUCCESS:
172        return 0;
173
174    case LIBUSB_ERROR_IO:
175        errno = EIO;
176
177        break;
178
179    case LIBUSB_ERROR_INVALID_PARAM:
180        errno = EINVAL;
181
182        break;
183
184    case LIBUSB_ERROR_ACCESS:
185        errno = EACCES;
186
187        break;
188
189    case LIBUSB_ERROR_NO_DEVICE:
190    case LIBUSB_ERROR_NOT_FOUND:
191        errno = ENOENT;
192
193        break;
194
195    case LIBUSB_ERROR_BUSY:
196        errno = EBUSY;
197
198        break;
199
200    case LIBUSB_ERROR_TIMEOUT:
201        errno = ETIMEDOUT;
202
203        break;
204
205    case LIBUSB_ERROR_OVERFLOW:
206        errno = EOVERFLOW;
207
208        break;
209
210    case LIBUSB_ERROR_PIPE:
211        errno = EPIPE;
212
213        break;
214
215    case LIBUSB_ERROR_INTERRUPTED:
216        errno = EINTR;
217
218        break;
219
220    case LIBUSB_ERROR_NO_MEM:
221        errno = ENOMEM;
222
223        break;
224
225    case LIBUSB_ERROR_NOT_SUPPORTED:
226        errno = ENOTSUP;
227
228        break;
229
230
231    case LIBUSB_ERROR_OTHER:
232    default:
233        errno = EFAULT;
234    }
235
236    debug(LEVEL_DEBUG, "Translated libusb return %d to %d\n", code, errno);
237
238    return -1;
239}
240

Archive Download this file



interactive