diff options
| author | 2009-04-28 19:01:12 +0200 | |
|---|---|---|
| committer | 2009-04-28 19:01:12 +0200 | |
| commit | 53fb582e7729d5b7ed40ff04d912fcf5add7ce1c (patch) | |
| tree | 8dd1f4d5426421a3a84a9d5df43f2fba48d12143 | |
| parent | c2d46d901822c54a0677318522db62f30b8d5f04 (diff) | |
| download | usbmuxd-53fb582e7729d5b7ed40ff04d912fcf5add7ce1c.tar.gz usbmuxd-53fb582e7729d5b7ed40ff04d912fcf5add7ce1c.tar.bz2 | |
USB TX/RX, device framework, version packets
| -rw-r--r-- | client.c | 1 | ||||
| -rw-r--r-- | client.h | 7 | ||||
| -rw-r--r-- | device.c | 225 | ||||
| -rw-r--r-- | device.h | 6 | ||||
| -rw-r--r-- | log.h | 4 | ||||
| -rw-r--r-- | main.c | 15 | ||||
| -rw-r--r-- | usb-linux.c | 152 | ||||
| -rw-r--r-- | usb.h | 3 |
8 files changed, 384 insertions, 29 deletions
| @@ -24,4 +24,5 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| 24 | 24 | ||
| 25 | #include "log.h" | 25 | #include "log.h" |
| 26 | #include "usb.h" | 26 | #include "usb.h" |
| 27 | #include "client.h" | ||
| 27 | 28 | ||
| @@ -18,7 +18,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| 18 | 18 | ||
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #ifndef __MUX_H__ | 21 | #ifndef __CLIENT_H__ |
| 22 | #define __MUX_H__ | 22 | #define __CLIENT_H__ |
| 23 | 23 | ||
| 24 | #endif | 24 | #endif |
| 25 | |||
| 26 | void client_accept(int fd); | ||
| 27 | void client_get_fds(struct fdlist *list); | ||
| @@ -18,39 +18,242 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| 18 | 18 | ||
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #define _BSD_SOURCE | ||
| 22 | |||
| 21 | #ifdef HAVE_CONFIG_H | 23 | #ifdef HAVE_CONFIG_H |
| 22 | #include <config.h> | 24 | #include <config.h> |
| 23 | #endif | 25 | #endif |
| 24 | 26 | ||
| 27 | #include <netinet/in.h> | ||
| 28 | #include <netinet/tcp.h> | ||
| 25 | #include <stdlib.h> | 29 | #include <stdlib.h> |
| 30 | #include <string.h> | ||
| 26 | #include "device.h" | 31 | #include "device.h" |
| 27 | #include "usb.h" | 32 | #include "usb.h" |
| 28 | #include "log.h" | 33 | #include "log.h" |
| 29 | 34 | ||
| 30 | int device_id; | 35 | int next_device_id; |
| 31 | /* | 36 | |
| 32 | int get_next_device_id(void) | 37 | enum mux_protocol { |
| 38 | MUX_PROTO_VERSION = 0, | ||
| 39 | MUX_PROTO_TCP = IPPROTO_TCP, | ||
| 40 | }; | ||
| 41 | |||
| 42 | enum mux_dev_state { | ||
| 43 | MUXDEV_INIT, | ||
| 44 | MUXDEV_ACTIVE, | ||
| 45 | MUXDEV_DEAD | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct mux_header | ||
| 49 | { | ||
| 50 | uint32_t protocol; | ||
| 51 | uint32_t length; | ||
| 52 | }; | ||
| 53 | |||
| 54 | struct version_header | ||
| 55 | { | ||
| 56 | uint32_t major; | ||
| 57 | uint32_t minor; | ||
| 58 | uint32_t padding; | ||
| 59 | }; | ||
| 60 | |||
| 61 | struct mux_device | ||
| 62 | { | ||
| 63 | struct usb_device *usbdev; | ||
| 64 | int id; | ||
| 65 | enum mux_dev_state state; | ||
| 66 | }; | ||
| 67 | |||
| 68 | static int num_devs; | ||
| 69 | static struct mux_device *device_list; | ||
| 70 | |||
| 71 | static int alloc_device(void) | ||
| 72 | { | ||
| 73 | int i; | ||
| 74 | for(i=0; i<num_devs; i++) { | ||
| 75 | if(!device_list[i].usbdev) | ||
| 76 | return i; | ||
| 77 | } | ||
| 78 | num_devs++; | ||
| 79 | device_list = realloc(device_list, sizeof(*device_list) * num_devs); | ||
| 80 | memset(&device_list[num_devs-1], 0, sizeof(*device_list)); | ||
| 81 | return num_devs - 1; | ||
| 82 | } | ||
| 83 | |||
| 84 | static int get_next_device_id(void) | ||
| 33 | { | 85 | { |
| 34 | int i; | 86 | int i; |
| 35 | while(1) { | 87 | while(1) { |
| 36 | for(i=0; i<num_devs; i++) { | 88 | for(i=0; i<num_devs; i++) { |
| 37 | if(device_list[i].dev && device_list[i].id == device_id) { | 89 | if(device_list[i].usbdev && device_list[i].id == next_device_id) { |
| 38 | device_id++; | 90 | next_device_id++; |
| 39 | break; | 91 | break; |
| 40 | } | 92 | } |
| 41 | } | 93 | } |
| 42 | if(i < num_devs) | 94 | if(i >= num_devs) |
| 95 | return next_device_id++; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | int send_packet(struct mux_device *dev, enum mux_protocol proto, void *header, void *data, int length) | ||
| 100 | { | ||
| 101 | unsigned char *buffer; | ||
| 102 | int hdrlen; | ||
| 103 | int res; | ||
| 104 | |||
| 105 | switch(proto) { | ||
| 106 | case MUX_PROTO_VERSION: | ||
| 107 | hdrlen = sizeof(struct version_header); | ||
| 43 | break; | 108 | break; |
| 109 | case MUX_PROTO_TCP: | ||
| 110 | hdrlen = sizeof(struct tcphdr); | ||
| 111 | break; | ||
| 112 | default: | ||
| 113 | usbmuxd_log(LL_ERROR, "Invalid protocol %d for outgoing packet (dev %d hdr %p data %p len %d)", proto, dev->id, header, data, length); | ||
| 114 | return -1; | ||
| 115 | } | ||
| 116 | usbmuxd_log(LL_SPEW, "send_packet(%d, 0x%x, %p, %p, %d)", dev->id, proto, header, data, length); | ||
| 117 | |||
| 118 | int total = sizeof(struct mux_header) + hdrlen + length; | ||
| 119 | |||
| 120 | if(total > USB_MTU) { | ||
| 121 | usbmuxd_log(LL_ERROR, "Tried to send packet larger than USB MTU (hdr %d data %d total %d) to device %d", hdrlen, length, total, dev->id); | ||
| 122 | return -1; | ||
| 44 | } | 123 | } |
| 45 | return device_id++; | 124 | |
| 125 | buffer = malloc(total); | ||
| 126 | struct mux_header *mhdr = (struct mux_header *)buffer; | ||
| 127 | mhdr->protocol = htonl(proto); | ||
| 128 | mhdr->length = htonl(total);; | ||
| 129 | memcpy(buffer + sizeof(struct mux_header), header, hdrlen); | ||
| 130 | if(data && length) | ||
| 131 | memcpy(buffer + sizeof(struct mux_header) + hdrlen, data, length); | ||
| 132 | |||
| 133 | if((res = usb_send(dev->usbdev, buffer, total)) < 0) { | ||
| 134 | usbmuxd_log(LL_ERROR, "usb_send failed while sending packet (len %d) to device %d: %d", total, dev->id, res); | ||
| 135 | free(buffer); | ||
| 136 | return res; | ||
| 137 | } | ||
| 138 | return mhdr->length; | ||
| 46 | } | 139 | } |
| 47 | */ | 140 | |
| 48 | void device_add(struct usb_device *dev) | 141 | static void device_version_input(struct mux_device *dev, struct version_header *vh) |
| 142 | { | ||
| 143 | if(dev->state != MUXDEV_INIT) { | ||
| 144 | usbmuxd_log(LL_WARNING, "Version packet from already initialized device %d", dev->id); | ||
| 145 | return; | ||
| 146 | } | ||
| 147 | vh->major = ntohl(vh->major); | ||
| 148 | vh->minor = ntohl(vh->minor); | ||
| 149 | if(vh->major != 1 || vh->minor != 0) { | ||
| 150 | usbmuxd_log(LL_ERROR, "Device %d has unknown version %d.%d\n", dev->id, vh->major, vh->minor); | ||
| 151 | return; | ||
| 152 | } | ||
| 153 | usbmuxd_log(LL_NOTICE, "Connected to v%d.%d device %d on location 0x%x with serial number %s", vh->major, vh->minor, dev->id, usb_get_location(dev->usbdev), usb_get_serial(dev->usbdev)); | ||
| 154 | } | ||
| 155 | |||
| 156 | static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned char *payload, int payload_length) | ||
| 157 | { | ||
| 158 | |||
| 159 | } | ||
| 160 | |||
| 161 | |||
| 162 | void device_data_input(struct usb_device *usbdev, unsigned char *buffer, int length) | ||
| 163 | { | ||
| 164 | int i; | ||
| 165 | struct mux_device *dev; | ||
| 166 | for(i=0; i<num_devs; i++) { | ||
| 167 | if(device_list[i].usbdev == usbdev) { | ||
| 168 | dev = &device_list[i]; | ||
| 169 | break; | ||
| 170 | } | ||
| 171 | } | ||
| 172 | if(i >= num_devs) { | ||
| 173 | usbmuxd_log(LL_WARNING, "Cannot find device entry for RX input from USB device %p on location 0x%x", usbdev, usb_get_location(usbdev)); | ||
| 174 | return; | ||
| 175 | } | ||
| 176 | |||
| 177 | usbmuxd_log(LL_SPEW, "Mux data input for device %p: %p len %d", dev, buffer, length); | ||
| 178 | |||
| 179 | struct mux_header *mhdr = (struct mux_header *)buffer; | ||
| 180 | |||
| 181 | if(ntohl(mhdr->length) != length) { | ||
| 182 | usbmuxd_log(LL_ERROR, "Incoming packet size mismatch (dev %d, expected %d, got %d)", dev->id, ntohl(mhdr->length), length); | ||
| 183 | return; | ||
| 184 | } | ||
| 185 | |||
| 186 | struct tcphdr *th; | ||
| 187 | unsigned char *payload; | ||
| 188 | int payload_length; | ||
| 189 | |||
| 190 | switch(ntohl(mhdr->protocol)) { | ||
| 191 | case MUX_PROTO_VERSION: | ||
| 192 | device_version_input(dev, (struct version_header *)(mhdr+1)); | ||
| 193 | break; | ||
| 194 | case MUX_PROTO_TCP: | ||
| 195 | th = (struct tcphdr *)(mhdr+1); | ||
| 196 | payload = (unsigned char *)(th+1); | ||
| 197 | payload_length = length - sizeof(struct tcphdr) - sizeof(struct mux_header); | ||
| 198 | device_tcp_input(dev, (struct tcphdr *)(mhdr+1), payload, payload_length); | ||
| 199 | break; | ||
| 200 | default: | ||
| 201 | usbmuxd_log(LL_ERROR, "Incoming packet for device %d has unknown protocol 0x%x)", dev->id, ntohl(mhdr->protocol)); | ||
| 202 | break; | ||
| 203 | } | ||
| 204 | |||
| 205 | } | ||
| 206 | |||
| 207 | int device_add(struct usb_device *dev) | ||
| 49 | { | 208 | { |
| 50 | usbmuxd_log(LL_NOTICE, "Connected to new device on location 0x%x with serial number %s", usb_get_location(dev), usb_get_serial(dev)); | 209 | int res; |
| 210 | int id = get_next_device_id(); | ||
| 211 | int idx = alloc_device(); | ||
| 212 | usbmuxd_log(LL_NOTICE, "Connecting to new device on location 0x%x as ID %d", usb_get_location(dev), id); | ||
| 213 | device_list[idx].id = id; | ||
| 214 | device_list[idx].usbdev = dev; | ||
| 215 | device_list[idx].state = MUXDEV_INIT; | ||
| 216 | struct version_header vh; | ||
| 217 | vh.major = htonl(1); | ||
| 218 | vh.minor = htonl(0); | ||
| 219 | vh.padding = 0; | ||
| 220 | if((res = send_packet(&device_list[idx], MUX_PROTO_VERSION, &vh, NULL, 0)) < 0) { | ||
| 221 | usbmuxd_log(LL_ERROR, "Error sending version request packet to device %d\n", id); | ||
| 222 | device_list[idx].usbdev = NULL; | ||
| 223 | device_list[idx].state = MUXDEV_DEAD; | ||
| 224 | return res; | ||
| 225 | } | ||
| 226 | return 0; | ||
| 51 | } | 227 | } |
| 52 | 228 | ||
| 53 | void device_remove(struct usb_device *dev) | 229 | void device_remove(struct usb_device *dev) |
| 54 | { | 230 | { |
| 55 | usbmuxd_log(LL_NOTICE, "Removed device on location 0x%x with serial number %s", usb_get_location(dev), usb_get_serial(dev)); | 231 | int i; |
| 232 | for(i=0; i<num_devs; i++) { | ||
| 233 | if(device_list[i].usbdev == dev) { | ||
| 234 | usbmuxd_log(LL_NOTICE, "Removed device %d on location 0x%x", device_list[i].id, usb_get_location(dev)); | ||
| 235 | device_list[i].usbdev = NULL; | ||
| 236 | return; | ||
| 237 | } | ||
| 238 | } | ||
| 239 | usbmuxd_log(LL_WARNING, "Cannot find device entry while removing USB device %p on location 0x%x", dev, usb_get_location(dev)); | ||
| 240 | } | ||
| 241 | |||
| 242 | void device_init(void) | ||
| 243 | { | ||
| 244 | usbmuxd_log(LL_DEBUG, "device_init"); | ||
| 245 | num_devs = 1; | ||
| 246 | device_list = malloc(sizeof(*device_list) * num_devs); | ||
| 247 | memset(device_list, 0, sizeof(*device_list) * num_devs); | ||
| 248 | next_device_id = 1; | ||
| 249 | } | ||
| 250 | |||
| 251 | void device_shutdown(void) | ||
| 252 | { | ||
| 253 | int i; | ||
| 254 | usbmuxd_log(LL_DEBUG, "device_shutdown"); | ||
| 255 | for(i=0; i<num_devs; i++) | ||
| 256 | device_remove(device_list[i].usbdev); | ||
| 257 | free(device_list); | ||
| 258 | device_list = NULL; | ||
| 56 | } | 259 | } |
| @@ -23,7 +23,11 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| 23 | 23 | ||
| 24 | #include "usb.h" | 24 | #include "usb.h" |
| 25 | 25 | ||
| 26 | void device_add(struct usb_device *dev); | 26 | void device_data_input(struct usb_device *dev, unsigned char *buf, int length); |
| 27 | |||
| 28 | int device_add(struct usb_device *dev); | ||
| 27 | void device_remove(struct usb_device *dev); | 29 | void device_remove(struct usb_device *dev); |
| 28 | 30 | ||
| 31 | void device_init(void); | ||
| 32 | void device_shutdown(void); | ||
| 29 | #endif | 33 | #endif |
| @@ -29,10 +29,12 @@ enum loglevel { | |||
| 29 | LL_INFO, | 29 | LL_INFO, |
| 30 | LL_DEBUG, | 30 | LL_DEBUG, |
| 31 | LL_SPEW, | 31 | LL_SPEW, |
| 32 | LL_FLOOD, | ||
| 32 | }; | 33 | }; |
| 33 | 34 | ||
| 34 | extern int log_level; | 35 | extern int log_level; |
| 35 | 36 | ||
| 36 | void usbmuxd_log(enum loglevel level, const char *fmt, ...); | 37 | void usbmuxd_log(enum loglevel level, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); |
| 38 | |||
| 37 | 39 | ||
| 38 | #endif | 40 | #endif |
| @@ -34,8 +34,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| 34 | 34 | ||
| 35 | #include "log.h" | 35 | #include "log.h" |
| 36 | #include "usb.h" | 36 | #include "usb.h" |
| 37 | #include "device.h" | ||
| 37 | 38 | ||
| 38 | const char *socket_path = "/tmp/usbmuxd"; //TODO: CHANGEME | 39 | static const char *socket_path = "/tmp/usbmuxd"; //TODO: CHANGEME |
| 39 | 40 | ||
| 40 | int create_socket(void) { | 41 | int create_socket(void) { |
| 41 | struct sockaddr_un bind_addr; | 42 | struct sockaddr_un bind_addr; |
| @@ -75,17 +76,17 @@ int main_loop(int listenfd) | |||
| 75 | struct fdlist pollfds; | 76 | struct fdlist pollfds; |
| 76 | 77 | ||
| 77 | while(1) { | 78 | while(1) { |
| 78 | usbmuxd_log(LL_SPEW, "main_loop iteration"); | 79 | usbmuxd_log(LL_FLOOD, "main_loop iteration"); |
| 79 | to = usb_get_timeout(); | 80 | to = usb_get_timeout(); |
| 80 | usbmuxd_log(LL_SPEW, "USB timeout is %d ms", to); | 81 | usbmuxd_log(LL_FLOOD, "USB timeout is %d ms", to); |
| 81 | 82 | ||
| 82 | fdlist_create(&pollfds); | 83 | fdlist_create(&pollfds); |
| 83 | fdlist_add(&pollfds, FD_LISTEN, listenfd, POLLIN); | 84 | fdlist_add(&pollfds, FD_LISTEN, listenfd, POLLIN); |
| 84 | usb_get_fds(&pollfds); | 85 | usb_get_fds(&pollfds); |
| 85 | usbmuxd_log(LL_SPEW, "fd count is %d", pollfds.count); | 86 | usbmuxd_log(LL_FLOOD, "fd count is %d", pollfds.count); |
| 86 | 87 | ||
| 87 | cnt = poll(pollfds.fds, pollfds.count, to); | 88 | cnt = poll(pollfds.fds, pollfds.count, to); |
| 88 | usbmuxd_log(LL_SPEW, "poll() returned %d", cnt); | 89 | usbmuxd_log(LL_FLOOD, "poll() returned %d", cnt); |
| 89 | 90 | ||
| 90 | if(cnt == 0) { | 91 | if(cnt == 0) { |
| 91 | if(usb_process() < 0) { | 92 | if(usb_process() < 0) { |
| @@ -122,6 +123,7 @@ int main(int argc, char *argv[]) | |||
| 122 | if(listenfd < 0) | 123 | if(listenfd < 0) |
| 123 | return 1; | 124 | return 1; |
| 124 | 125 | ||
| 126 | device_init(); | ||
| 125 | usbmuxd_log(LL_INFO, "Initializing USB"); | 127 | usbmuxd_log(LL_INFO, "Initializing USB"); |
| 126 | if((res = usb_init()) < 0) | 128 | if((res = usb_init()) < 0) |
| 127 | return 2; | 129 | return 2; |
| @@ -135,8 +137,9 @@ int main(int argc, char *argv[]) | |||
| 135 | 137 | ||
| 136 | usbmuxd_log(LL_NOTICE, "usbmux shutting down"); | 138 | usbmuxd_log(LL_NOTICE, "usbmux shutting down"); |
| 137 | usb_shutdown(); | 139 | usb_shutdown(); |
| 140 | device_shutdown(); | ||
| 138 | usbmuxd_log(LL_NOTICE, "Shutdown complete"); | 141 | usbmuxd_log(LL_NOTICE, "Shutdown complete"); |
| 139 | 142 | ||
| 140 | if(res < 0) | 143 | if(res < 0) |
| 141 | return -res; | 144 | return -res; |
| 142 | return 0; | 145 | return 0; |
diff --git a/usb-linux.c b/usb-linux.c index 0820ed9..27a7bb1 100644 --- a/usb-linux.c +++ b/usb-linux.c | |||
| @@ -42,13 +42,13 @@ struct usb_device { | |||
| 42 | uint8_t bus, address; | 42 | uint8_t bus, address; |
| 43 | char serial[256]; | 43 | char serial[256]; |
| 44 | int alive; | 44 | int alive; |
| 45 | struct libusb_transfer *rx_xfer; | ||
| 45 | }; | 46 | }; |
| 46 | 47 | ||
| 47 | int num_devs; | 48 | static int num_devs; |
| 48 | int device_id; | 49 | static struct usb_device *device_list; |
| 49 | struct usb_device *device_list; | ||
| 50 | 50 | ||
| 51 | struct timeval next_dev_poll_time; | 51 | static struct timeval next_dev_poll_time; |
| 52 | 52 | ||
| 53 | static int alloc_device(void) | 53 | static int alloc_device(void) |
| 54 | { | 54 | { |
| @@ -68,11 +68,130 @@ static void usb_disconnect(struct usb_device *dev) | |||
| 68 | if(!dev->dev) { | 68 | if(!dev->dev) { |
| 69 | return; | 69 | return; |
| 70 | } | 70 | } |
| 71 | if(dev->rx_xfer) { | ||
| 72 | // kill the rx xfer and try to make sure the rx callback gets called before we free the device | ||
| 73 | struct timeval tv; | ||
| 74 | int res; | ||
| 75 | // TODO: BUG: outstanding TX xfers are not listed but we need to free them | ||
| 76 | libusb_cancel_transfer(dev->rx_xfer); | ||
| 77 | tv.tv_sec = tv.tv_usec = 0; | ||
| 78 | if((res = libusb_handle_events_timeout(NULL, &tv)) < 0) { | ||
| 79 | usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout for device removal failed: %d", res); | ||
| 80 | } | ||
| 81 | } | ||
| 71 | libusb_release_interface(dev->dev, USB_INTERFACE); | 82 | libusb_release_interface(dev->dev, USB_INTERFACE); |
| 72 | libusb_close(dev->dev); | 83 | libusb_close(dev->dev); |
| 73 | dev->dev = NULL; | 84 | dev->dev = NULL; |
| 74 | } | 85 | } |
| 75 | 86 | ||
| 87 | static void tx_callback(struct libusb_transfer *xfer) | ||
| 88 | { | ||
| 89 | struct usb_device *dev = xfer->user_data; | ||
| 90 | usbmuxd_log(LL_SPEW, "TX callback dev %d-%d len %d -> %d status %d", dev->bus, dev->address, xfer->length, xfer->actual_length, xfer->status); | ||
| 91 | if(xfer->status != LIBUSB_TRANSFER_COMPLETED) { | ||
| 92 | switch(xfer->status) { | ||
| 93 | case LIBUSB_TRANSFER_COMPLETED: //shut up compiler | ||
| 94 | case LIBUSB_TRANSFER_ERROR: | ||
| 95 | // funny, this happens when we disconnect the device while waiting for a transfer, sometimes | ||
| 96 | usbmuxd_log(LL_INFO, "Device %d-%d TX aborted due to error or disconnect", dev->bus, dev->address); | ||
| 97 | break; | ||
| 98 | case LIBUSB_TRANSFER_TIMED_OUT: | ||
| 99 | usbmuxd_log(LL_ERROR, "TX transfer timed out for device %d-%d", dev->bus, dev->address); | ||
| 100 | break; | ||
| 101 | case LIBUSB_TRANSFER_CANCELLED: | ||
| 102 | usbmuxd_log(LL_ERROR, "TX transfer cancelled for device %d-%d", dev->bus, dev->address); | ||
| 103 | break; | ||
| 104 | case LIBUSB_TRANSFER_STALL: | ||
| 105 | usbmuxd_log(LL_ERROR, "TX transfer stalled for device %d-%d", dev->bus, dev->address); | ||
| 106 | break; | ||
| 107 | case LIBUSB_TRANSFER_NO_DEVICE: | ||
| 108 | // other times, this happens, and also even when we abort the transfer after device removal | ||
| 109 | usbmuxd_log(LL_INFO, "Device %d-%d TX aborted due to disconnect", dev->bus, dev->address); | ||
| 110 | break; | ||
| 111 | case LIBUSB_TRANSFER_OVERFLOW: | ||
| 112 | usbmuxd_log(LL_ERROR, "TX transfer overflow for device %d-%d", dev->bus, dev->address); | ||
| 113 | break; | ||
| 114 | // and nothing happens (this never gets called) if the device is freed after a disconnect! (bad) | ||
| 115 | } | ||
| 116 | // we can't usb_disconnect here due to a deadlock, so instead mark it as dead and reap it after processing events | ||
| 117 | // we'll do device_remove there too | ||
| 118 | dev->alive = 0; | ||
| 119 | } | ||
| 120 | free(xfer->buffer); | ||
| 121 | libusb_free_transfer(xfer); | ||
| 122 | } | ||
| 123 | |||
| 124 | int usb_send(struct usb_device *dev, const unsigned char *buf, int length) | ||
| 125 | { | ||
| 126 | int res; | ||
| 127 | struct libusb_transfer *xfer = libusb_alloc_transfer(0); | ||
| 128 | libusb_fill_bulk_transfer(xfer, dev->dev, BULK_OUT, (void*)buf, length, tx_callback, dev, 0); | ||
| 129 | xfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK; | ||
| 130 | if((res = libusb_submit_transfer(xfer)) < 0) { | ||
| 131 | usbmuxd_log(LL_ERROR, "Failed to submit TX transfer %p len %d to device %d-%d: %d", buf, length, dev->bus, dev->address, res); | ||
| 132 | libusb_free_transfer(xfer); | ||
| 133 | return res; | ||
| 134 | } | ||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | |||
| 138 | static void rx_callback(struct libusb_transfer *xfer) | ||
| 139 | { | ||
| 140 | struct usb_device *dev = xfer->user_data; | ||
| 141 | usbmuxd_log(LL_SPEW, "RX callback dev %d-%d len %d status %d", dev->bus, dev->address, xfer->actual_length, xfer->status); | ||
| 142 | if(xfer->status == LIBUSB_TRANSFER_COMPLETED) { | ||
| 143 | device_data_input(dev, xfer->buffer, xfer->actual_length); | ||
| 144 | libusb_submit_transfer(xfer); | ||
| 145 | } else { | ||
| 146 | switch(xfer->status) { | ||
| 147 | case LIBUSB_TRANSFER_COMPLETED: //shut up compiler | ||
| 148 | case LIBUSB_TRANSFER_ERROR: | ||
| 149 | // funny, this happens when we disconnect the device while waiting for a transfer, sometimes | ||
| 150 | usbmuxd_log(LL_INFO, "Device %d-%d RX aborted due to error or disconnect", dev->bus, dev->address); | ||
| 151 | break; | ||
| 152 | case LIBUSB_TRANSFER_TIMED_OUT: | ||
| 153 | usbmuxd_log(LL_ERROR, "RX transfer timed out for device %d-%d", dev->bus, dev->address); | ||
| 154 | break; | ||
| 155 | case LIBUSB_TRANSFER_CANCELLED: | ||
| 156 | usbmuxd_log(LL_ERROR, "RX transfer cancelled for device %d-%d", dev->bus, dev->address); | ||
| 157 | break; | ||
| 158 | case LIBUSB_TRANSFER_STALL: | ||
| 159 | usbmuxd_log(LL_ERROR, "RX transfer stalled for device %d-%d", dev->bus, dev->address); | ||
| 160 | break; | ||
| 161 | case LIBUSB_TRANSFER_NO_DEVICE: | ||
| 162 | // other times, this happens, and also even when we abort the transfer after device removal | ||
| 163 | usbmuxd_log(LL_INFO, "Device %d-%d RX aborted due to disconnect", dev->bus, dev->address); | ||
| 164 | break; | ||
| 165 | case LIBUSB_TRANSFER_OVERFLOW: | ||
| 166 | usbmuxd_log(LL_ERROR, "RX transfer overflow for device %d-%d", dev->bus, dev->address); | ||
| 167 | break; | ||
| 168 | // and nothing happens (this never gets called) if the device is freed after a disconnect! (bad) | ||
| 169 | } | ||
| 170 | free(xfer->buffer); | ||
| 171 | dev->rx_xfer = NULL; | ||
| 172 | libusb_free_transfer(xfer); | ||
| 173 | // we can't usb_disconnect here due to a deadlock, so instead mark it as dead and reap it after processing events | ||
| 174 | // we'll do device_remove there too | ||
| 175 | dev->alive = 0; | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | static int start_rx(struct usb_device *dev) | ||
| 180 | { | ||
| 181 | int res; | ||
| 182 | void *buf; | ||
| 183 | dev->rx_xfer = libusb_alloc_transfer(0); | ||
| 184 | buf = malloc(USB_MTU); | ||
| 185 | libusb_fill_bulk_transfer(dev->rx_xfer, dev->dev, BULK_IN, buf, USB_MTU, rx_callback, dev, 0); | ||
| 186 | if((res = libusb_submit_transfer(dev->rx_xfer)) != 0) { | ||
| 187 | usbmuxd_log(LL_ERROR, "Failed to submit RX transfer to device %d-%d: %d", dev->bus, dev->address, res); | ||
| 188 | libusb_free_transfer(dev->rx_xfer); | ||
| 189 | dev->rx_xfer = NULL; | ||
| 190 | return res; | ||
| 191 | } | ||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | |||
| 76 | static int usb_discover(void) | 195 | static int usb_discover(void) |
| 77 | { | 196 | { |
| 78 | int cnt, i, j, res; | 197 | int cnt, i, j, res; |
| @@ -135,7 +254,8 @@ static int usb_discover(void) | |||
| 135 | int idx = alloc_device(); | 254 | int idx = alloc_device(); |
| 136 | 255 | ||
| 137 | if((res = libusb_get_string_descriptor_ascii(handle, devdesc.iSerialNumber, (uint8_t *)device_list[idx].serial, 256)) <= 0) { | 256 | 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); | 257 | usbmuxd_log(LL_WARNING, "Could not get serial number for device %d-%d: %d", bus, address, res); |
| 258 | libusb_release_interface(handle, USB_INTERFACE); | ||
| 139 | libusb_close(handle); | 259 | libusb_close(handle); |
| 140 | continue; | 260 | continue; |
| 141 | } | 261 | } |
| @@ -145,7 +265,15 @@ static int usb_discover(void) | |||
| 145 | device_list[idx].dev = handle; | 265 | device_list[idx].dev = handle; |
| 146 | device_list[idx].alive = 1; | 266 | device_list[idx].alive = 1; |
| 147 | 267 | ||
| 148 | device_add(&device_list[idx]); | 268 | if(device_add(&device_list[idx]) < 0) { |
| 269 | usb_disconnect(&device_list[j]); | ||
| 270 | continue; | ||
| 271 | } | ||
| 272 | if(start_rx(&device_list[idx]) < 0) { | ||
| 273 | device_remove(&device_list[j]); | ||
| 274 | usb_disconnect(&device_list[j]); | ||
| 275 | continue; | ||
| 276 | } | ||
| 149 | valid_count++; | 277 | valid_count++; |
| 150 | } | 278 | } |
| 151 | for(j=0; j<num_devs; j++) { | 279 | for(j=0; j<num_devs; j++) { |
| @@ -232,7 +360,7 @@ int usb_get_timeout(void) | |||
| 232 | 360 | ||
| 233 | int usb_process(void) | 361 | int usb_process(void) |
| 234 | { | 362 | { |
| 235 | int res; | 363 | int i, res; |
| 236 | struct timeval tv; | 364 | struct timeval tv; |
| 237 | tv.tv_sec = tv.tv_usec = 0; | 365 | tv.tv_sec = tv.tv_usec = 0; |
| 238 | res = libusb_handle_events_timeout(NULL, &tv); | 366 | res = libusb_handle_events_timeout(NULL, &tv); |
| @@ -240,6 +368,14 @@ int usb_process(void) | |||
| 240 | usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %d", res); | 368 | usbmuxd_log(LL_ERROR, "libusb_handle_events_timeout failed: %d", res); |
| 241 | return res; | 369 | return res; |
| 242 | } | 370 | } |
| 371 | // reap devices marked dead due to an RX error | ||
| 372 | for(i=0; i<num_devs; i++) { | ||
| 373 | if(device_list[i].dev && !device_list[i].alive) { | ||
| 374 | device_remove(&device_list[i]); | ||
| 375 | usb_disconnect(&device_list[i]); | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 243 | if(dev_poll_remain_ms() <= 0) { | 379 | if(dev_poll_remain_ms() <= 0) { |
| 244 | res = usb_discover(); | 380 | res = usb_discover(); |
| 245 | if(res < 0) { | 381 | if(res < 0) { |
| @@ -256,12 +392,12 @@ int usb_init(void) | |||
| 256 | usbmuxd_log(LL_DEBUG, "usb_init for linux / libusb 1.0"); | 392 | usbmuxd_log(LL_DEBUG, "usb_init for linux / libusb 1.0"); |
| 257 | 393 | ||
| 258 | res = libusb_init(NULL); | 394 | res = libusb_init(NULL); |
| 395 | //libusb_set_debug(NULL, 3); | ||
| 259 | if(res != 0) { | 396 | if(res != 0) { |
| 260 | usbmuxd_log(LL_FATAL, "libusb_init failed: %d", res); | 397 | usbmuxd_log(LL_FATAL, "libusb_init failed: %d", res); |
| 261 | return -1; | 398 | return -1; |
| 262 | } | 399 | } |
| 263 | 400 | ||
| 264 | device_id = 1; | ||
| 265 | num_devs = 1; | 401 | num_devs = 1; |
| 266 | device_list = malloc(sizeof(*device_list) * num_devs); | 402 | device_list = malloc(sizeof(*device_list) * num_devs); |
| 267 | memset(device_list, 0, sizeof(*device_list) * num_devs); | 403 | memset(device_list, 0, sizeof(*device_list) * num_devs); |
| @@ -26,6 +26,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||
| 26 | #define BULK_IN 0x85 | 26 | #define BULK_IN 0x85 |
| 27 | #define BULK_OUT 0x04 | 27 | #define BULK_OUT 0x04 |
| 28 | 28 | ||
| 29 | #define USB_MTU 65536 | ||
| 30 | |||
| 29 | #define VID_APPLE 0x5ac | 31 | #define VID_APPLE 0x5ac |
| 30 | #define PID_IPHONE2G 0x1290 | 32 | #define PID_IPHONE2G 0x1290 |
| 31 | #define PID_ITOUCH1G 0x1291 | 33 | #define PID_ITOUCH1G 0x1291 |
| @@ -42,6 +44,7 @@ const char *usb_get_serial(struct usb_device *dev); | |||
| 42 | int usb_get_location(struct usb_device *dev); | 44 | int usb_get_location(struct usb_device *dev); |
| 43 | void usb_get_fds(struct fdlist *list); | 45 | void usb_get_fds(struct fdlist *list); |
| 44 | int usb_get_timeout(void); | 46 | int usb_get_timeout(void); |
| 47 | int usb_send(struct usb_device *dev, const unsigned char *buf, int length); | ||
| 45 | int usb_process(void); | 48 | int usb_process(void); |
| 46 | 49 | ||
| 47 | #endif | 50 | #endif |
