summaryrefslogtreecommitdiffstats
path: root/usb-linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'usb-linux.c')
-rw-r--r--usb-linux.c251
1 files changed, 249 insertions, 2 deletions
diff --git a/usb-linux.c b/usb-linux.c
index 221ce33..0820ed9 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -24,11 +24,258 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 24
25#include <stdio.h> 25#include <stdio.h>
26#include <stdlib.h> 26#include <stdlib.h>
27#include <stdlib.h> 27#include <stdint.h>
28#include <string.h>
28 29
29#include <libusb.h> 30#include <libusb.h>
30 31
31int usb_init(void) 32#include "usb.h"
33#include "log.h"
34#include "device.h"
35
36// interval for device connection/disconnection polling, in milliseconds
37// we need this because there is currently no asynchronous device discovery mechanism in libusb
38#define DEVICE_POLL_TIME 1000
39
40struct usb_device {
41 libusb_device_handle *dev;
42 uint8_t bus, address;
43 char serial[256];
44 int alive;
45};
46
47int num_devs;
48int device_id;
49struct usb_device *device_list;
50
51struct timeval next_dev_poll_time;
52
53static int alloc_device(void)
32{ 54{
55 int i;
56 for(i=0; i<num_devs; i++) {
57 if(!device_list[i].dev)
58 return i;
59 }
60 num_devs++;
61 device_list = realloc(device_list, sizeof(*device_list) * num_devs);
62 memset(&device_list[num_devs-1], 0, sizeof(*device_list));
63 return num_devs - 1;
64}
65
66static void usb_disconnect(struct usb_device *dev)
67{
68 if(!dev->dev) {
69 return;
70 }
71 libusb_release_interface(dev->dev, USB_INTERFACE);
72 libusb_close(dev->dev);
73 dev->dev = NULL;
74}
75
76static int usb_discover(void)
77{
78 int cnt, i, j, res;
79 int valid_count = 0;
80 libusb_device **devs;
81
82 cnt = libusb_get_device_list(NULL, &devs);
83 if(cnt < 0) {
84 usbmuxd_log(LL_FATAL, "Could not get device list: %d", cnt);
85 return cnt;
86 }
87
88 usbmuxd_log(LL_SPEW, "usb_discover: scanning %d devices", cnt);
89
90 for(j=0; j<num_devs; j++) {
91 device_list[j].alive = 0;
92 }
93 for(i=0; i<cnt; i++) {
94 // the following are non-blocking operations on the device list
95 libusb_device *dev = devs[i];
96 uint8_t bus = libusb_get_bus_number(dev);
97 uint8_t address = libusb_get_device_address(dev);
98 struct libusb_device_descriptor devdesc;
99 for(j=0; j<num_devs; j++) {
100 if(device_list[j].dev && device_list[j].bus == bus && device_list[j].address == address) {
101 valid_count++;
102 device_list[j].alive = 1;
103 break;
104 }
105 }
106 if(j < num_devs)
107 continue; //device already found
108 if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) {
109 usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %d", bus, address, res);
110 continue;
111 }
112 if(devdesc.idVendor != VID_APPLE)
113 continue;
114 if( (devdesc.idProduct != PID_IPHONE2G) &&
115 (devdesc.idProduct != PID_ITOUCH1G) &&
116 (devdesc.idProduct != PID_IPHONE3G))
117 continue;
118 libusb_device_handle *handle;
119 usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address);
120 // potentially blocking operations follow; they will only run when new devices are detected, which is acceptable
121 if((res = libusb_open(dev, &handle)) != 0) {
122 usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %d", bus, address, res);
123 continue;
124 }
125 if((res = libusb_set_configuration(handle, USB_CONFIGURATION)) != 0) {
126 usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %d", USB_CONFIGURATION, bus, address, res);
127 libusb_close(handle);
128 continue;
129 }
130 if((res = libusb_claim_interface(handle, USB_INTERFACE)) != 0) {
131 usbmuxd_log(LL_WARNING, "Could not claim interface %d for device %d-%d: %d", USB_INTERFACE, bus, address, res);
132 libusb_close(handle);
133 continue;
134 }
135 int idx = alloc_device();
136
137 if((res = libusb_get_string_descriptor_ascii(handle, devdesc.iSerialNumber, (uint8_t *)device_list[idx].serial, 256)) <= 0) {
138 usbmuxd_log(LL_WARNING, "Could not get serial number for device %d-%d: %d", USB_INTERFACE, bus, address, res);
139 libusb_close(handle);
140 continue;
141 }
142 device_list[idx].serial[res] = 0;
143 device_list[idx].bus = bus;
144 device_list[idx].address = address;
145 device_list[idx].dev = handle;
146 device_list[idx].alive = 1;
147
148 device_add(&device_list[idx]);
149 valid_count++;
150 }
151 for(j=0; j<num_devs; j++) {
152 if(device_list[j].dev && !device_list[j].alive) {
153 device_remove(&device_list[j]);
154 usb_disconnect(&device_list[j]);
155 }
156 }
157 libusb_free_device_list(devs, 1);
158
159 gettimeofday(&next_dev_poll_time, NULL);
160 next_dev_poll_time.tv_usec += DEVICE_POLL_TIME * 1000;
161 next_dev_poll_time.tv_sec += next_dev_poll_time.tv_usec / 1000000;
162 next_dev_poll_time.tv_usec = next_dev_poll_time.tv_usec % 1000000;
163
164 return valid_count;
165}
166
167const char *usb_get_serial(struct usb_device *dev)
168{
169 if(!dev->dev) {
170 return NULL;
171 }
172 return dev->serial;
173}
174
175int usb_get_location(struct usb_device *dev)
176{
177 if(!dev->dev) {
178 return 0;
179 }
180 return (dev->bus << 16) | dev->address;
181}
182
183void usb_get_fds(struct fdlist *list)
184{
185 const struct libusb_pollfd **usbfds;
186 const struct libusb_pollfd **p;
187 usbfds = libusb_get_pollfds(NULL);
188 if(!usbfds) {
189 usbmuxd_log(LL_ERROR, "libusb_get_pollfds failed");
190 return;
191 }
192 p = usbfds;
193 while(*p) {
194 fdlist_add(list, FD_USB, (*p)->fd, (*p)->events);
195 p++;
196 }
197 free(usbfds);
198}
199
200static int dev_poll_remain_ms(void)
201{
202 int msecs;
203 struct timeval tv;
204 gettimeofday(&tv, NULL);
205 msecs = (next_dev_poll_time.tv_sec - tv.tv_sec) * 1000;
206 msecs += (next_dev_poll_time.tv_usec - tv.tv_usec) / 1000;
207 if(msecs < 0)
208 return 0;
209 return msecs;
210}
211
212int usb_get_timeout(void)
213{
214 struct timeval tv;
215 int msec;
216 int res;
217 int pollrem;
218 pollrem = dev_poll_remain_ms();
219 res = libusb_get_next_timeout(NULL, &tv);
220 if(res == 0)
221 return pollrem;
222 if(res < 0) {
223 usbmuxd_log(LL_ERROR, "libusb_get_next_timeout failed: %d", res);
224 return pollrem;
225 }
226 msec = tv.tv_sec * 1000;
227 msec += tv.tv_usec / 1000;
228 if(msec > pollrem)
229 return pollrem;
230 return msec;
231}
232
233int usb_process(void)
234{
235 int res;
236 struct timeval tv;
237 tv.tv_sec = tv.tv_usec = 0;
238 res = libusb_handle_events_timeout(NULL, &tv);
239 if(res < 0) {
240 usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %d", res);
241 return res;
242 }
243 if(dev_poll_remain_ms() <= 0) {
244 res = usb_discover();
245 if(res < 0) {
246 usbmuxd_log(LL_ERROR, "usb_discover failed: %d", res);
247 return res;
248 }
249 }
33 return 0; 250 return 0;
34} 251}
252
253int usb_init(void)
254{
255 int res;
256 usbmuxd_log(LL_DEBUG, "usb_init for linux / libusb 1.0");
257
258 res = libusb_init(NULL);
259 if(res != 0) {
260 usbmuxd_log(LL_FATAL, "libusb_init failed: %d", res);
261 return -1;
262 }
263
264 device_id = 1;
265 num_devs = 1;
266 device_list = malloc(sizeof(*device_list) * num_devs);
267 memset(device_list, 0, sizeof(*device_list) * num_devs);
268
269 return usb_discover();
270}
271
272void usb_shutdown(void)
273{
274 int i;
275 usbmuxd_log(LL_DEBUG, "usb_shutdown");
276 for(i=0; i<num_devs; i++)
277 usb_disconnect(&device_list[i]);
278 free(device_list);
279 device_list = NULL;
280 libusb_exit(NULL);
281}