summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/irecovery.c92
-rw-r--r--src/libirecovery.c76
2 files changed, 108 insertions, 60 deletions
diff --git a/src/irecovery.c b/src/irecovery.c
index ae828af..2ab0aaa 100644
--- a/src/irecovery.c
+++ b/src/irecovery.c
@@ -23,44 +23,76 @@
23#include <readline/readline.h> 23#include <readline/readline.h>
24#include <readline/history.h> 24#include <readline/history.h>
25 25
26#define FILE_HISTORY_PATH "~/.irecovery/history"
27
26enum { 28enum {
27 kResetDevice, kStartShell, kSendCommand, kSendFile 29 kResetDevice, kStartShell, kSendCommand, kSendFile
28}; 30};
29 31
32static unsigned int exit_shell = 0;
33
30void print_shell_usage() { 34void print_shell_usage() {
31 printf("Usage:\n"); 35 printf("Usage:\n");
32 printf("\t:f <file>\tSend file to device.\n"); 36 printf("\t/upload <file>\tSend file to device.\n");
33 printf("\t:h\t\tShow this help.\n"); 37 printf("\t/help\t\tShow this help.\n");
34 printf("\t:q\t\tQuit interactive shell.\n"); 38 printf("\t/exit\t\tExit interactive shell.\n");
35} 39}
36 40
37void init_shell(irecv_device* device) { 41void parse_command(irecv_device_t* device, unsigned char* command, unsigned int size) {
38 int ret; 42 char* cmd = strtok(command, " ");
43 if(!strcmp(command, "/exit")) {
44 exit_shell = 1;
45 } else
46
47 if(!strcmp(command, "/help")) {
48 print_shell_usage();
49 } else
50
51 if(!strcmp(command, "/upload")) {
52 char* filename = strtok(0, " ");
53 if(filename != NULL) {
54 irecv_send_file(device, filename);
55 }
56 }
57}
39 58
40 for(;;) { 59int recv_callback(irecv_device_t* device, unsigned char* data, unsigned int size) {
41 char* cmd = readline("iRecovery> "); 60 int i = 0;
42 if(cmd && *cmd) { 61 for(i = 0; i < size; i++) {
43 add_history(cmd); 62 printf("%c", data[i]);
44 if(cmd[0] == ':') { 63 }
45 strtok(cmd, " "); 64 return size;
46 char* arg = strtok(0, " "); 65}
47
48 if(cmd[1] == 'q') {
49 free(cmd);
50 break;
51 } else if(cmd[1] == 'h') {
52 print_shell_usage();
53 } else if(cmd[1] == 'f') {
54 ret = irecv_send_file(device, arg);
55 // TODO: error messages
56 }
57 } else {
58 ret = irecv_send_command(device, cmd);
59 // TODO: error messages
60 }
61 66
67int send_callback(irecv_device_t* device, unsigned char* command, unsigned int size) {
68 if(command[0] == '/') {
69 parse_command(device, command, size);
70 return 0;
71 }
72 return size;
73}
74
75void load_command_history() {
76 read_history(FILE_HISTORY_PATH);
77}
78
79void append_command_to_history(char* cmd) {
80 add_history(cmd);
81 write_history(FILE_HISTORY_PATH);
82}
83
84void init_shell(irecv_device_t* device) {
85 load_command_history();
86 irecv_set_sender(device, &send_callback);
87 irecv_set_receiver(device, &recv_callback);
88 while(!exit_shell) {
89 char* cmd = readline("> ");
90 if(cmd && *cmd) {
91 irecv_send_command(device, cmd);
92 append_command_to_history(cmd);
62 free(cmd); 93 free(cmd);
63 } 94 }
95 irecv_update(device);
64 } 96 }
65} 97}
66 98
@@ -78,13 +110,14 @@ void print_usage() {
78 110
79int main(int argc, char** argv) { 111int main(int argc, char** argv) {
80 int opt = 0; 112 int opt = 0;
113 int debug = 0;
81 int action = 0; 114 int action = 0;
82 char* argument = NULL; 115 char* argument = NULL;
83 if(argc == 1) print_usage(); 116 if(argc == 1) print_usage();
84 while ((opt = getopt(argc, argv, "dhrsc:f:")) > 0) { 117 while ((opt = getopt(argc, argv, "dhrsc:f:")) > 0) {
85 switch (opt) { 118 switch (opt) {
86 case 'd': 119 case 'd':
87 irecv_set_debug(1); 120 debug = 1;
88 break; 121 break;
89 122
90 case 'h': 123 case 'h':
@@ -115,11 +148,12 @@ int main(int argc, char** argv) {
115 } 148 }
116 } 149 }
117 150
118 irecv_device* device = NULL; 151 irecv_device_t* device = irecv_init();
119 if(irecv_init(&device) < 0) { 152 if(device == NULL) {
120 fprintf(stderr, "Unable to initialize libirecovery\n"); 153 fprintf(stderr, "Unable to initialize libirecovery\n");
121 return -1; 154 return -1;
122 } 155 }
156 if(debug) irecv_set_debug(device, 1);
123 157
124 if(irecv_open(device) < 0) { 158 if(irecv_open(device) < 0) {
125 fprintf(stderr, "Unable to open device\n"); 159 fprintf(stderr, "Unable to open device\n");
diff --git a/src/libirecovery.c b/src/libirecovery.c
index 630a9b7..c31a424 100644
--- a/src/libirecovery.c
+++ b/src/libirecovery.c
@@ -23,27 +23,21 @@
23 23
24#include "libirecovery.h" 24#include "libirecovery.h"
25 25
26static unsigned int irecv_debug = 0; 26irecv_device_t* irecv_init() {
27
28int irecv_init(irecv_device** p_device) {
29 struct libusb_context* usb_context = NULL; 27 struct libusb_context* usb_context = NULL;
30 28
31 libusb_init(&usb_context); 29 libusb_init(&usb_context);
32 if (irecv_debug) libusb_set_debug(usb_context, 3); 30 irecv_device_t* device = (irecv_device_t*) malloc(sizeof(irecv_device_t));
33
34 irecv_device* device = (irecv_device*) malloc(sizeof(irecv_device));
35 if (device == NULL) { 31 if (device == NULL) {
36 *p_device = NULL; 32 return NULL;
37 return IRECV_ERROR_OUT_OF_MEMORY;
38 } 33 }
39 memset(device, '\0', sizeof(irecv_device)); 34 memset(device, '\0', sizeof(irecv_device_t));
40 device->context = usb_context; 35 device->context = usb_context;
41 36
42 *p_device = device; 37 return device;
43 return IRECV_SUCCESS;
44} 38}
45 39
46int irecv_open(irecv_device* device) { 40int irecv_open(irecv_device_t* device) {
47 int i = 0; 41 int i = 0;
48 int usb_device_count = 0; 42 int usb_device_count = 0;
49 struct libusb_device* usb_device = NULL; 43 struct libusb_device* usb_device = NULL;
@@ -77,7 +71,7 @@ int irecv_open(irecv_device* device) {
77 return IRECV_ERROR_NO_DEVICE; 71 return IRECV_ERROR_NO_DEVICE;
78} 72}
79 73
80int irecv_reset(irecv_device* device) { 74int irecv_reset(irecv_device_t* device) {
81 if (device == NULL || device->handle != NULL) { 75 if (device == NULL || device->handle != NULL) {
82 return IRECV_ERROR_NO_DEVICE; 76 return IRECV_ERROR_NO_DEVICE;
83 } 77 }
@@ -86,7 +80,7 @@ int irecv_reset(irecv_device* device) {
86 return IRECV_SUCCESS; 80 return IRECV_SUCCESS;
87} 81}
88 82
89int irecv_close(irecv_device* device) { 83int irecv_close(irecv_device_t* device) {
90 if (device == NULL || device->handle != NULL) { 84 if (device == NULL || device->handle != NULL) {
91 return IRECV_ERROR_NO_DEVICE; 85 return IRECV_ERROR_NO_DEVICE;
92 } 86 }
@@ -96,7 +90,7 @@ int irecv_close(irecv_device* device) {
96 return IRECV_SUCCESS; 90 return IRECV_SUCCESS;
97} 91}
98 92
99int irecv_exit(irecv_device* device) { 93int irecv_exit(irecv_device_t* device) {
100 if (device != NULL) { 94 if (device != NULL) {
101 if (device->handle != NULL) { 95 if (device->handle != NULL) {
102 libusb_close(device->handle); 96 libusb_close(device->handle);
@@ -115,12 +109,12 @@ int irecv_exit(irecv_device* device) {
115 return IRECV_SUCCESS; 109 return IRECV_SUCCESS;
116} 110}
117 111
118void irecv_set_debug(int level) { 112void irecv_set_debug(irecv_device_t* device, int level) {
119 printf("Debug has been set to %d\n", level); 113 libusb_set_debug(device->context, level);
120 irecv_debug = level; 114 device->debug = level;
121} 115}
122 116
123int irecv_send_command(irecv_device* device, const char* command) { 117int irecv_send_command(irecv_device_t* device, unsigned char* command) {
124 if(device == NULL || device->handle == NULL) { 118 if(device == NULL || device->handle == NULL) {
125 return IRECV_ERROR_NO_DEVICE; 119 return IRECV_ERROR_NO_DEVICE;
126 } 120 }
@@ -129,16 +123,23 @@ int irecv_send_command(irecv_device* device, const char* command) {
129 if(length >= 0x100) { 123 if(length >= 0x100) {
130 return IRECV_ERROR_INVALID_INPUT; 124 return IRECV_ERROR_INVALID_INPUT;
131 } 125 }
132 126
133 int ret = libusb_control_transfer(device->handle, 0x40, 0, 0, 0, (unsigned char*) command, length+1, 100); 127 if(device->send_callback != NULL) {
134 if(ret < 0) { 128 // Call our user defined callback first, this must return a number of bytes to send
135 return IRECV_ERROR_UNKNOWN; 129 // or zero to abort send.
130 length = device->send_callback(device, command, length);
131 if(length > 0) {
132 int ret = libusb_control_transfer(device->handle, 0x40, 0, 0, 0, (unsigned char*) command, length+1, 100);
133 if(ret < 0) {
134 return IRECV_ERROR_UNKNOWN;
135 }
136 }
136 } 137 }
137 138
138 return IRECV_SUCCESS; 139 return IRECV_SUCCESS;
139} 140}
140 141
141int irecv_send_file(irecv_device* device, const char* filename) { 142int irecv_send_file(irecv_device_t* device, const char* filename) {
142 FILE* file = fopen(filename, "rb"); 143 FILE* file = fopen(filename, "rb");
143 if (file == NULL) { 144 if (file == NULL) {
144 return IRECV_ERROR_FILE_NOT_FOUND; 145 return IRECV_ERROR_FILE_NOT_FOUND;
@@ -165,7 +166,7 @@ int irecv_send_file(irecv_device* device, const char* filename) {
165 return irecv_send_buffer(device, buffer, length); 166 return irecv_send_buffer(device, buffer, length);
166} 167}
167 168
168unsigned int irecv_get_status(irecv_device* device) { 169unsigned int irecv_get_status(irecv_device_t* device) {
169 unsigned char status[6]; 170 unsigned char status[6];
170 memset(status, '\0', 6); 171 memset(status, '\0', 6);
171 if(libusb_control_transfer(device->handle, 0xA1, 3, 0, 0, status, 6, 500) != 6) { 172 if(libusb_control_transfer(device->handle, 0xA1, 3, 0, 0, status, 6, 500) != 6) {
@@ -174,7 +175,7 @@ unsigned int irecv_get_status(irecv_device* device) {
174 return (unsigned int) status[4]; 175 return (unsigned int) status[4];
175} 176}
176 177
177int irecv_send_buffer(irecv_device* device, unsigned char* buffer, int length) { 178int irecv_send_buffer(irecv_device_t* device, unsigned char* buffer, int length) {
178 int last = length % 0x800; 179 int last = length % 0x800;
179 int packets = length / 0x800; 180 int packets = length / 0x800;
180 if (last != 0) { 181 if (last != 0) {
@@ -200,13 +201,26 @@ int irecv_send_buffer(irecv_device* device, unsigned char* buffer, int length) {
200 } 201 }
201 202
202 libusb_control_transfer(device->handle, 0x21, 1, i, 0, buffer, 0, 1000); 203 libusb_control_transfer(device->handle, 0x21, 1, i, 0, buffer, 0, 1000);
203 for (i = 6; i <= 8; i++) { 204 for (i = 0; i < 3; i++) {
204 if (irecv_get_status(device) != i) { 205 irecv_get_status(device);
205 free(buffer);
206 return IRECV_ERROR_USB_STATUS;
207 }
208 } 206 }
209 207
210 free(buffer); 208 free(buffer);
211 return IRECV_SUCCESS; 209 return IRECV_SUCCESS;
212} 210}
211
212void irecv_update(irecv_device_t* device) {
213 if(device->receive_callback == NULL) {
214 return;
215 }
216}
217
218int irecv_set_receiver(irecv_device_t* device, irecv_receive_callback callback) {
219 device->receive_callback = callback;
220 return IRECV_SUCCESS;
221}
222
223int irecv_set_sender(irecv_device_t* device, irecv_send_callback callback) {
224 device->send_callback = callback;
225 return IRECV_SUCCESS;
226}