summaryrefslogtreecommitdiffstats
path: root/src/iphone.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/iphone.c')
-rw-r--r--src/iphone.c295
1 files changed, 51 insertions, 244 deletions
diff --git a/src/iphone.c b/src/iphone.c
index 9dd3c07..9551173 100644
--- a/src/iphone.c
+++ b/src/iphone.c
@@ -19,200 +19,85 @@
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 20 */
21 21
22#include "usbmux.h"
23#include "iphone.h" 22#include "iphone.h"
24#include "utils.h" 23#include "utils.h"
25#include <arpa/inet.h>
26#include <usb.h>
27#include <stdio.h> 24#include <stdio.h>
28#include <stdlib.h> 25#include <stdlib.h>
29#include <string.h> 26#include <string.h>
27#include <errno.h>
28#include <libiphone/libiphone.h>
30 29
31/** 30/**
32 * This function sets the configuration of the given device to 3 31 * Retrieves a list of connected devices from usbmuxd and matches their
33 * and claims the interface 1. If usb_set_configuration fails, it detaches 32 * UUID with the given UUID. If the given UUID is NULL then the first
34 * the kernel driver that blocks the device, and retries configuration. 33 * device reported by usbmuxd is used.
35 * 34 *
36 * @param phone which device to configure 35 * @param device Upon calling this function, a pointer to a location of type
37 */ 36 * iphone_device_t, which must have the value NULL. On return, this location
38static void iphone_config_usb_device(iphone_device_t phone) 37 * will be filled with a handle to the device.
39{ 38 * @param uuid The UUID to match.
40 int ret;
41 int bytes;
42 unsigned char buf[512];
43
44 log_debug_msg("setting configuration... ");
45 ret = usb_set_configuration(phone->device, 3);
46 if (ret != 0) {
47 log_debug_msg("Hm, usb_set_configuration returned %d: %s, trying to fix:\n", ret, strerror(-ret));
48 log_debug_msg("-> detaching kernel driver... ");
49 ret =
50 usb_detach_kernel_driver_np(phone->device,
51 phone->__device->config->interface->altsetting->bInterfaceNumber);
52 if (ret != 0) {
53 log_debug_msg("usb_detach_kernel_driver_np returned %d: %s\n", ret, strerror(-ret));
54 } else {
55 log_debug_msg("done.\n");
56 log_debug_msg("setting configuration again... ");
57 ret = usb_set_configuration(phone->device, 3);
58 if (ret != 0) {
59 log_debug_msg("Error: usb_set_configuration returned %d: %s\n", ret, strerror(-ret));
60 } else {
61 log_debug_msg("done.\n");
62 }
63 }
64 } else {
65 log_debug_msg("done.\n");
66 }
67
68 log_debug_msg("claiming interface... ");
69 ret = usb_claim_interface(phone->device, 1);
70 if (ret != 0) {
71 log_debug_msg("Error: usb_claim_interface returned %d: %s\n", ret, strerror(-ret));
72 } else {
73 log_debug_msg("done.\n");
74 }
75
76 do {
77 bytes = usb_bulk_read(phone->device, BULKIN, (void *) &buf, 512, 800);
78 if (bytes > 0) {
79 log_debug_msg("iphone_config_usb_device: initial read returned %d bytes of data.\n", bytes);
80 log_debug_buffer(buf, bytes);
81 }
82 } while (bytes > 0);
83}
84
85/**
86 * Given a USB bus and device number, returns a device handle to the iPhone on
87 * that bus. To aid compatibility with future devices, this function does not
88 * check the vendor and device IDs! To do that, you should use
89 * iphone_get_device() or a system-specific API (e.g. HAL).
90 * 39 *
91 * @param bus_n The USB bus number.
92 * @param dev_n The USB device number.
93 * @param device A pointer to a iphone_device_t, which must be set to NULL upon
94 * calling iphone_get_specific_device, which will be filled with a device
95 * descriptor on return.
96 * @return IPHONE_E_SUCCESS if ok, otherwise an error code. 40 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
97 */ 41 */
98iphone_error_t iphone_get_specific_device(unsigned int bus_n, int dev_n, iphone_device_t * device) 42iphone_error_t iphone_get_device_by_uuid(iphone_device_t * device, const char *uuid)
99{ 43{
100 struct usb_bus *bus, *busses; 44 iphone_device_t phone;
101 struct usb_device *dev; 45 uint32_t handle = 0;
102 usbmux_version_header *version; 46 usbmuxd_scan_result *dev_list = NULL;
103 int bytes = 0; 47 int i;
104
105 //check we can actually write in device
106 if (!device || (device && *device))
107 return IPHONE_E_INVALID_ARG;
108
109 iphone_device_t phone = (iphone_device_t) malloc(sizeof(struct iphone_device_int));
110 48
111 // Initialize the struct 49 if (usbmuxd_scan(&dev_list) < 0) {
112 phone->device = NULL; 50 log_debug_msg("%s: usbmuxd_scan returned an error, is usbmuxd running?\n", __func__);
113 phone->__device = NULL; 51 }
114 phone->buffer = NULL; 52 if (dev_list && dev_list[0].handle > 0) {
115 53 if (!uuid) {
116 // Initialize libusb 54 // select first device found if no UUID specified
117 usb_init(); 55 handle = dev_list[0].handle;
118 usb_find_busses(); 56 } else {
119 usb_find_devices(); 57 // otherwise walk through the list
120 busses = usb_get_busses(); 58 for (i = 0; dev_list[i].handle > 0; i++) {
121 59 log_debug_msg("%s: device handle=%d, uuid=%s\n", __func__, dev_list[i].handle, dev_list[i].serial_number);
122 // Set the device configuration 60 if (strcasecmp(uuid, dev_list[i].serial_number) == 0) {
123 for (bus = busses; bus; bus = bus->next) 61 handle = dev_list[i].handle;
124 if (strtoul(bus->dirname, NULL, 10) == bus_n) 62 break;
125 for (dev = bus->devices; dev != NULL; dev = dev->next)
126 if (strtol(dev->filename, NULL, 10) == dev_n) {
127 phone->__device = dev;
128 phone->device = usb_open(phone->__device);
129 iphone_config_usb_device(phone);
130 goto found;
131 } 63 }
132 64 }
133 iphone_free_device(phone);
134
135 log_debug_msg("iphone_get_specific_device: iPhone not found\n");
136 return IPHONE_E_NO_DEVICE;
137
138 found:
139 // Send the version command to the phone
140 version = version_header();
141 bytes = usb_bulk_write(phone->device, BULKOUT, (char *) version, sizeof(*version), 800);
142 if (bytes < 20) {
143 log_debug_msg("get_iPhone(): libusb did NOT send enough!\n");
144 if (bytes < 0) {
145 log_debug_msg("get_iPhone(): libusb gave me the error %d: %s (%s)\n",
146 bytes, usb_strerror(), strerror(-bytes));
147 } 65 }
148 } 66 free(dev_list);
149 // Read the phone's response
150 bytes = usb_bulk_read(phone->device, BULKIN, (char *) version, sizeof(*version), 800);
151 67
152 // Check for bad response 68 if (handle > 0) {
153 if (bytes < 20) { 69 phone = (iphone_device_t) malloc(sizeof(struct iphone_device_int));
154 free(version); 70 phone->handle = handle;
155 iphone_free_device(phone); 71 *device = phone;
156 log_debug_msg("get_iPhone(): Invalid version message -- header too short.\n"); 72 return IPHONE_E_SUCCESS;
157 if (bytes < 0) 73 }
158 log_debug_msg("get_iPhone(): libusb error message %d: %s (%s)\n", bytes, usb_strerror(), strerror(-bytes));
159 return IPHONE_E_NOT_ENOUGH_DATA;
160 }
161 // Check for correct version
162 if (ntohl(version->major) == 1 && ntohl(version->minor) == 0) {
163 // We're all ready to roll.
164 log_debug_msg("get_iPhone() success\n");
165 free(version);
166 *device = phone;
167 return IPHONE_E_SUCCESS;
168 } else {
169 // Bad header
170 log_debug_msg("get_iPhone(): Received a bad header/invalid version number.\n");
171 log_debug_buffer((char *) version, sizeof(*version));
172 iphone_free_device(phone);
173 free(version);
174 return IPHONE_E_BAD_HEADER;
175 } 74 }
176 75
177 // If it got to this point it's gotta be bad 76 return IPHONE_E_NO_DEVICE;
178 log_debug_msg("get_iPhone(): Unknown error.\n");
179 iphone_free_device(phone);
180 free(version);
181 return IPHONE_E_UNKNOWN_ERROR; // if it got to this point it's gotta be bad
182} 77}
183 78
184/** 79/**
185 * Scans all USB busses and devices for a known AFC-compatible device and 80 * This function has the purpose to retrieve a handle to the first
186 * returns a handle to the first such device it finds. Known devices include 81 * attached iPhone/iPod reported by usbmuxd.
187 * those with vendor ID 0x05ac and product ID between 0x1290 and 0x1293
188 * inclusive.
189 * 82 *
190 * This function is convenient, but on systems where higher-level abstractions 83 * @param Upon calling this function, a pointer to a location of type
191 * (such as HAL) are available it may be preferable to use
192 * iphone_get_specific_device instead, because it can deal with multiple
193 * connected devices as well as devices not known to libiphone.
194 *
195 * @param device Upon calling this function, a pointer to a location of type
196 * iphone_device_t, which must have the value NULL. On return, this location 84 * iphone_device_t, which must have the value NULL. On return, this location
197 * will be filled with a handle to the device. 85 * will be filled with a handle to the device.
86 *
198 * @return IPHONE_E_SUCCESS if ok, otherwise an error code. 87 * @return IPHONE_E_SUCCESS if ok, otherwise an error code.
199 */ 88 */
200iphone_error_t iphone_get_device(iphone_device_t * device) 89iphone_error_t iphone_get_device(iphone_device_t * device)
201{ 90{
202 struct usb_bus *bus; 91 return iphone_get_device_by_uuid(device, NULL);
203 struct usb_device *dev; 92}
204
205 usb_init();
206 usb_find_busses();
207 usb_find_devices();
208
209 for (bus = usb_get_busses(); bus != NULL; bus = bus->next)
210 for (dev = bus->devices; dev != NULL; dev = dev->next)
211 if (dev->descriptor.idVendor == 0x05ac
212 && dev->descriptor.idProduct >= 0x1290 && dev->descriptor.idProduct <= 0x1293)
213 return iphone_get_specific_device(strtoul(bus->dirname, NULL, 10), strtol(dev->filename, NULL, 10), device);
214 93
215 return IPHONE_E_NO_DEVICE; 94uint32_t iphone_get_device_handle(iphone_device_t device)
95{
96 if (device) {
97 return device->handle;
98 } else {
99 return 0;
100 }
216} 101}
217 102
218/** Cleans up an iPhone structure, then frees the structure itself. 103/** Cleans up an iPhone structure, then frees the structure itself.
@@ -226,88 +111,10 @@ iphone_error_t iphone_free_device(iphone_device_t device)
226 if (!device) 111 if (!device)
227 return IPHONE_E_INVALID_ARG; 112 return IPHONE_E_INVALID_ARG;
228 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR; 113 iphone_error_t ret = IPHONE_E_UNKNOWN_ERROR;
229 int bytes;
230 unsigned char buf[512];
231 114
232 // read final package(s) 115 ret = IPHONE_E_SUCCESS;
233 if (device->device != NULL) {
234 do {
235 bytes = usb_bulk_read(device->device, BULKIN, (void *) &buf, 512, 800);
236 if (bytes > 0) {
237 log_debug_msg("iphone_free_device: final read returned\n");
238 log_debug_buffer(buf, bytes);
239 }
240 } while (bytes > 0);
241 }
242 116
243 if (device->buffer) {
244 free(device->buffer);
245 }
246 if (device->device) {
247 usb_release_interface(device->device, 1);
248 usb_close(device->device);
249 ret = IPHONE_E_SUCCESS;
250 }
251 free(device); 117 free(device);
252 return ret; 118 return ret;
253} 119}
254 120
255/** Sends data to the phone
256 * This is a low-level (i.e. directly to phone) function.
257 *
258 * @param phone The iPhone to send data to
259 * @param data The data to send to the iPhone
260 * @param datalen The length of the data
261 * @return The number of bytes sent, or -1 on error or something.
262 */
263int send_to_phone(iphone_device_t phone, char *data, int datalen)
264{
265 if (!phone)
266 return -1;
267 int bytes = 0;
268
269 if (!phone)
270 return -1;
271 log_debug_msg("send_to_phone: Attempting to send datalen = %i data = %p\n", datalen, data);
272
273 bytes = usb_bulk_write(phone->device, BULKOUT, data, datalen, 800);
274 if (bytes < datalen) {
275 if (bytes < 0)
276 log_debug_msg("send_to_iphone(): libusb gave me the error %d: %s - %s\n", bytes, usb_strerror(),
277 strerror(-bytes));
278 return -1;
279 } else {
280 return bytes;
281 }
282 /* Should not be reached */
283 return -1;
284}
285
286/** This function is a low-level (i.e. direct to iPhone) function.
287 *
288 * @param phone The iPhone to receive data from
289 * @param data Where to put data read
290 * @param datalen How much data to read in
291 * @param timeout How many milliseconds to wait for data
292 *
293 * @return How many bytes were read in, or -1 on error.
294 */
295int recv_from_phone(iphone_device_t phone, char *data, int datalen, int timeout)
296{
297 if (!phone)
298 return -1;
299 int bytes = 0;
300
301 if (!phone)
302 return -1;
303 log_debug_msg("recv_from_phone(): attempting to receive %i bytes\n", datalen);
304
305 bytes = usb_bulk_read(phone->device, BULKIN, data, datalen, timeout);
306 if (bytes < 0) {
307 log_debug_msg("recv_from_phone(): libusb gave me the error %d: %s (%s)\n", bytes, usb_strerror(),
308 strerror(-bytes));
309 return -1;
310 }
311
312 return bytes;
313}