diff options
Diffstat (limited to 'src/libirecovery.c')
| -rw-r--r-- | src/libirecovery.c | 161 |
1 files changed, 131 insertions, 30 deletions
diff --git a/src/libirecovery.c b/src/libirecovery.c index c31a424..21cdfcf 100644 --- a/src/libirecovery.c +++ b/src/libirecovery.c | |||
| @@ -19,10 +19,14 @@ | |||
| 19 | #include <stdio.h> | 19 | #include <stdio.h> |
| 20 | #include <stdlib.h> | 20 | #include <stdlib.h> |
| 21 | #include <string.h> | 21 | #include <string.h> |
| 22 | #include <unistd.h> | ||
| 22 | #include <libusb-1.0/libusb.h> | 23 | #include <libusb-1.0/libusb.h> |
| 23 | 24 | ||
| 24 | #include "libirecovery.h" | 25 | #include "libirecovery.h" |
| 25 | 26 | ||
| 27 | #define BUFFER_SIZE 0x1000 | ||
| 28 | #define debug(...) if(device->debug) fprintf(stderr, __VA_ARGS__) | ||
| 29 | |||
| 26 | irecv_device_t* irecv_init() { | 30 | irecv_device_t* irecv_init() { |
| 27 | struct libusb_context* usb_context = NULL; | 31 | struct libusb_context* usb_context = NULL; |
| 28 | 32 | ||
| @@ -37,7 +41,7 @@ irecv_device_t* irecv_init() { | |||
| 37 | return device; | 41 | return device; |
| 38 | } | 42 | } |
| 39 | 43 | ||
| 40 | int irecv_open(irecv_device_t* device) { | 44 | irecv_error_t irecv_open(irecv_device_t* device) { |
| 41 | int i = 0; | 45 | int i = 0; |
| 42 | int usb_device_count = 0; | 46 | int usb_device_count = 0; |
| 43 | struct libusb_device* usb_device = NULL; | 47 | struct libusb_device* usb_device = NULL; |
| @@ -49,6 +53,7 @@ int irecv_open(irecv_device_t* device) { | |||
| 49 | return IRECV_ERROR_NO_DEVICE; | 53 | return IRECV_ERROR_NO_DEVICE; |
| 50 | } | 54 | } |
| 51 | 55 | ||
| 56 | irecv_error_t error = 0; | ||
| 52 | usb_device_count = libusb_get_device_list(device->context, &usb_device_list); | 57 | usb_device_count = libusb_get_device_list(device->context, &usb_device_list); |
| 53 | for (i = 0; i < usb_device_count; i++) { | 58 | for (i = 0; i < usb_device_count; i++) { |
| 54 | usb_device = usb_device_list[i]; | 59 | usb_device = usb_device_list[i]; |
| @@ -60,10 +65,20 @@ int irecv_open(irecv_device_t* device) { | |||
| 60 | libusb_free_device_list(usb_device_list, 1); | 65 | libusb_free_device_list(usb_device_list, 1); |
| 61 | return IRECV_ERROR_UNABLE_TO_CONNECT; | 66 | return IRECV_ERROR_UNABLE_TO_CONNECT; |
| 62 | } | 67 | } |
| 63 | |||
| 64 | libusb_free_device_list(usb_device_list, 1); | 68 | libusb_free_device_list(usb_device_list, 1); |
| 65 | device->mode = usb_descriptor.idProduct; | 69 | |
| 66 | device->handle = usb_handle; | 70 | device->handle = usb_handle; |
| 71 | device->mode = (irecv_mode_t) usb_descriptor.idProduct; | ||
| 72 | error = irecv_set_configuration(device, 1); | ||
| 73 | if(error != IRECV_SUCCESS) { | ||
| 74 | return error; | ||
| 75 | } | ||
| 76 | |||
| 77 | error = irecv_set_interface(device, 1, 1); | ||
| 78 | if(error != IRECV_SUCCESS) { | ||
| 79 | return error; | ||
| 80 | } | ||
| 81 | |||
| 67 | return IRECV_SUCCESS; | 82 | return IRECV_SUCCESS; |
| 68 | } | 83 | } |
| 69 | } | 84 | } |
| @@ -71,7 +86,42 @@ int irecv_open(irecv_device_t* device) { | |||
| 71 | return IRECV_ERROR_NO_DEVICE; | 86 | return IRECV_ERROR_NO_DEVICE; |
| 72 | } | 87 | } |
| 73 | 88 | ||
| 74 | int irecv_reset(irecv_device_t* device) { | 89 | irecv_error_t irecv_set_configuration(irecv_device_t* device, int configuration) { |
| 90 | if(device == NULL || device->handle == NULL) { | ||
| 91 | return IRECV_ERROR_NO_DEVICE; | ||
| 92 | } | ||
| 93 | |||
| 94 | int current = 0; | ||
| 95 | libusb_get_configuration(device->handle, ¤t); | ||
| 96 | if(current != configuration) { | ||
| 97 | if (libusb_set_configuration(device->handle, configuration) < 0) { | ||
| 98 | return IRECV_ERROR_USB_CONFIGURATION; | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | device->config = configuration; | ||
| 103 | return IRECV_SUCCESS; | ||
| 104 | } | ||
| 105 | |||
| 106 | irecv_error_t irecv_set_interface(irecv_device_t* device, int interface, int alt_interface) { | ||
| 107 | if(device == NULL || device->handle == NULL) { | ||
| 108 | return IRECV_ERROR_NO_DEVICE; | ||
| 109 | } | ||
| 110 | |||
| 111 | if (libusb_claim_interface(device->handle, interface) < 0) { | ||
| 112 | return IRECV_ERROR_USB_INTERFACE; | ||
| 113 | } | ||
| 114 | |||
| 115 | if(libusb_set_interface_alt_setting(device->handle, interface, alt_interface) < 0) { | ||
| 116 | return IRECV_ERROR_USB_INTERFACE; | ||
| 117 | } | ||
| 118 | |||
| 119 | device->interface = interface; | ||
| 120 | device->alt_interface = alt_interface; | ||
| 121 | return IRECV_SUCCESS; | ||
| 122 | } | ||
| 123 | |||
| 124 | irecv_error_t irecv_reset(irecv_device_t* device) { | ||
| 75 | if (device == NULL || device->handle != NULL) { | 125 | if (device == NULL || device->handle != NULL) { |
| 76 | return IRECV_ERROR_NO_DEVICE; | 126 | return IRECV_ERROR_NO_DEVICE; |
| 77 | } | 127 | } |
| @@ -80,21 +130,25 @@ int irecv_reset(irecv_device_t* device) { | |||
| 80 | return IRECV_SUCCESS; | 130 | return IRECV_SUCCESS; |
| 81 | } | 131 | } |
| 82 | 132 | ||
| 83 | int irecv_close(irecv_device_t* device) { | 133 | irecv_error_t irecv_close(irecv_device_t* device) { |
| 84 | if (device == NULL || device->handle != NULL) { | 134 | if (device == NULL) { |
| 85 | return IRECV_ERROR_NO_DEVICE; | 135 | return IRECV_ERROR_NO_DEVICE; |
| 86 | } | 136 | } |
| 87 | 137 | ||
| 88 | libusb_close(device->handle); | 138 | if(device->handle != NULL) { |
| 89 | device->handle = NULL; | 139 | libusb_release_interface(device->handle, 0); |
| 140 | libusb_release_interface(device->handle, 1); | ||
| 141 | libusb_close(device->handle); | ||
| 142 | device->handle = NULL; | ||
| 143 | } | ||
| 144 | |||
| 90 | return IRECV_SUCCESS; | 145 | return IRECV_SUCCESS; |
| 91 | } | 146 | } |
| 92 | 147 | ||
| 93 | int irecv_exit(irecv_device_t* device) { | 148 | irecv_error_t irecv_exit(irecv_device_t* device) { |
| 94 | if (device != NULL) { | 149 | if (device != NULL) { |
| 95 | if (device->handle != NULL) { | 150 | if (device->handle != NULL) { |
| 96 | libusb_close(device->handle); | 151 | irecv_close(device); |
| 97 | device->handle = NULL; | ||
| 98 | } | 152 | } |
| 99 | 153 | ||
| 100 | if (device->context != NULL) { | 154 | if (device->context != NULL) { |
| @@ -109,12 +163,16 @@ int irecv_exit(irecv_device_t* device) { | |||
| 109 | return IRECV_SUCCESS; | 163 | return IRECV_SUCCESS; |
| 110 | } | 164 | } |
| 111 | 165 | ||
| 112 | void irecv_set_debug(irecv_device_t* device, int level) { | 166 | irecv_error_t irecv_set_debug(irecv_device_t* device, int level) { |
| 167 | if(device == NULL || device->context == NULL) { | ||
| 168 | return IRECV_ERROR_NO_DEVICE; | ||
| 169 | } | ||
| 170 | |||
| 113 | libusb_set_debug(device->context, level); | 171 | libusb_set_debug(device->context, level); |
| 114 | device->debug = level; | 172 | device->debug = level; |
| 115 | } | 173 | } |
| 116 | 174 | ||
| 117 | int irecv_send_command(irecv_device_t* device, unsigned char* command) { | 175 | irecv_error_t irecv_send_command(irecv_device_t* device, unsigned char* command) { |
| 118 | if(device == NULL || device->handle == NULL) { | 176 | if(device == NULL || device->handle == NULL) { |
| 119 | return IRECV_ERROR_NO_DEVICE; | 177 | return IRECV_ERROR_NO_DEVICE; |
| 120 | } | 178 | } |
| @@ -139,7 +197,11 @@ int irecv_send_command(irecv_device_t* device, unsigned char* command) { | |||
| 139 | return IRECV_SUCCESS; | 197 | return IRECV_SUCCESS; |
| 140 | } | 198 | } |
| 141 | 199 | ||
| 142 | int irecv_send_file(irecv_device_t* device, const char* filename) { | 200 | irecv_error_t irecv_send_file(irecv_device_t* device, const char* filename) { |
| 201 | if(device == NULL || device->handle == NULL) { | ||
| 202 | return IRECV_ERROR_NO_DEVICE; | ||
| 203 | } | ||
| 204 | |||
| 143 | FILE* file = fopen(filename, "rb"); | 205 | FILE* file = fopen(filename, "rb"); |
| 144 | if (file == NULL) { | 206 | if (file == NULL) { |
| 145 | return IRECV_ERROR_FILE_NOT_FOUND; | 207 | return IRECV_ERROR_FILE_NOT_FOUND; |
| @@ -166,16 +228,29 @@ int irecv_send_file(irecv_device_t* device, const char* filename) { | |||
| 166 | return irecv_send_buffer(device, buffer, length); | 228 | return irecv_send_buffer(device, buffer, length); |
| 167 | } | 229 | } |
| 168 | 230 | ||
| 169 | unsigned int irecv_get_status(irecv_device_t* device) { | 231 | irecv_error_t irecv_get_status(irecv_device_t* device, unsigned int* status) { |
| 170 | unsigned char status[6]; | 232 | if(device == NULL || device->handle == NULL) { |
| 171 | memset(status, '\0', 6); | 233 | *status = 0; |
| 172 | if(libusb_control_transfer(device->handle, 0xA1, 3, 0, 0, status, 6, 500) != 6) { | 234 | return IRECV_ERROR_NO_DEVICE; |
| 235 | } | ||
| 236 | |||
| 237 | unsigned char buffer[6]; | ||
| 238 | memset(buffer, '\0', 6); | ||
| 239 | if(libusb_control_transfer(device->handle, 0xA1, 3, 0, 0, buffer, 6, 500) != 6) { | ||
| 240 | *status = 0; | ||
| 173 | return IRECV_ERROR_USB_STATUS; | 241 | return IRECV_ERROR_USB_STATUS; |
| 174 | } | 242 | } |
| 175 | return (unsigned int) status[4]; | 243 | |
| 244 | *status = (unsigned int) buffer[4]; | ||
| 245 | return IRECV_SUCCESS; | ||
| 176 | } | 246 | } |
| 177 | 247 | ||
| 178 | int irecv_send_buffer(irecv_device_t* device, unsigned char* buffer, int length) { | 248 | irecv_error_t irecv_send_buffer(irecv_device_t* device, unsigned char* buffer, unsigned int length) { |
| 249 | irecv_error_t error = 0; | ||
| 250 | if(device == NULL || device->handle == NULL) { | ||
| 251 | return IRECV_ERROR_NO_DEVICE; | ||
| 252 | } | ||
| 253 | |||
| 179 | int last = length % 0x800; | 254 | int last = length % 0x800; |
| 180 | int packets = length / 0x800; | 255 | int packets = length / 0x800; |
| 181 | if (last != 0) { | 256 | if (last != 0) { |
| @@ -185,7 +260,7 @@ int irecv_send_buffer(irecv_device_t* device, unsigned char* buffer, int length) | |||
| 185 | } | 260 | } |
| 186 | 261 | ||
| 187 | int i = 0; | 262 | int i = 0; |
| 188 | char status[6]; | 263 | unsigned int status = 0; |
| 189 | for (i = 0; i < packets; i++) { | 264 | for (i = 0; i < packets; i++) { |
| 190 | int size = i + 1 < packets ? 0x800 : last; | 265 | int size = i + 1 < packets ? 0x800 : last; |
| 191 | int bytes = libusb_control_transfer(device->handle, 0x21, 1, i, 0, &buffer[i * 0x800], size, 500); | 266 | int bytes = libusb_control_transfer(device->handle, 0x21, 1, i, 0, &buffer[i * 0x800], size, 500); |
| @@ -193,34 +268,60 @@ int irecv_send_buffer(irecv_device_t* device, unsigned char* buffer, int length) | |||
| 193 | free(buffer); | 268 | free(buffer); |
| 194 | return IRECV_ERROR_USB_UPLOAD; | 269 | return IRECV_ERROR_USB_UPLOAD; |
| 195 | } | 270 | } |
| 196 | 271 | ||
| 197 | if (irecv_get_status(device) != 5) { | 272 | error = irecv_get_status(device, &status); |
| 273 | if (error != IRECV_SUCCESS || status != 5) { | ||
| 198 | free(buffer); | 274 | free(buffer); |
| 199 | return IRECV_ERROR_USB_STATUS; | 275 | return error; |
| 200 | } | 276 | } |
| 201 | } | 277 | } |
| 202 | 278 | ||
| 203 | libusb_control_transfer(device->handle, 0x21, 1, i, 0, buffer, 0, 1000); | 279 | libusb_control_transfer(device->handle, 0x21, 1, i, 0, buffer, 0, 1000); |
| 204 | for (i = 0; i < 3; i++) { | 280 | for (i = 0; i < 3; i++) { |
| 205 | irecv_get_status(device); | 281 | error = irecv_get_status(device, &status); |
| 282 | if(error != IRECV_SUCCESS) { | ||
| 283 | free(buffer); | ||
| 284 | return error; | ||
| 285 | } | ||
| 206 | } | 286 | } |
| 207 | 287 | ||
| 208 | free(buffer); | 288 | free(buffer); |
| 209 | return IRECV_SUCCESS; | 289 | return IRECV_SUCCESS; |
| 210 | } | 290 | } |
| 211 | 291 | ||
| 212 | void irecv_update(irecv_device_t* device) { | 292 | irecv_error_t irecv_update(irecv_device_t* device) { |
| 213 | if(device->receive_callback == NULL) { | 293 | unsigned char buffer[BUFFER_SIZE]; |
| 214 | return; | 294 | memset(buffer, '\0', BUFFER_SIZE); |
| 295 | if(device == NULL || device->handle == NULL) { | ||
| 296 | return IRECV_ERROR_NO_DEVICE; | ||
| 297 | } | ||
| 298 | |||
| 299 | int bytes = 0; | ||
| 300 | while(libusb_bulk_transfer(device->handle, 0x81, buffer, BUFFER_SIZE, &bytes, 100) == 0) { | ||
| 301 | if(bytes > 0) { | ||
| 302 | if(device->receive_callback(device, buffer, bytes) != bytes) { | ||
| 303 | return IRECV_ERROR_UNKNOWN; | ||
| 304 | } | ||
| 305 | } else break; | ||
| 215 | } | 306 | } |
| 307 | |||
| 308 | return IRECV_SUCCESS; | ||
| 216 | } | 309 | } |
| 217 | 310 | ||
| 218 | int irecv_set_receiver(irecv_device_t* device, irecv_receive_callback callback) { | 311 | irecv_error_t irecv_set_receiver(irecv_device_t* device, irecv_receive_callback callback) { |
| 312 | if(device == NULL) { | ||
| 313 | return IRECV_ERROR_NO_DEVICE; | ||
| 314 | } | ||
| 315 | |||
| 219 | device->receive_callback = callback; | 316 | device->receive_callback = callback; |
| 220 | return IRECV_SUCCESS; | 317 | return IRECV_SUCCESS; |
| 221 | } | 318 | } |
| 222 | 319 | ||
| 223 | int irecv_set_sender(irecv_device_t* device, irecv_send_callback callback) { | 320 | irecv_error_t irecv_set_sender(irecv_device_t* device, irecv_send_callback callback) { |
| 321 | if(device == NULL) { | ||
| 322 | return IRECV_ERROR_NO_DEVICE; | ||
| 323 | } | ||
| 324 | |||
| 224 | device->send_callback = callback; | 325 | device->send_callback = callback; |
| 225 | return IRECV_SUCCESS; | 326 | return IRECV_SUCCESS; |
| 226 | } | 327 | } |
