|
28 | 28 | #include <stdbool.h> |
29 | 29 | #include <stdlib.h> |
30 | 30 | #include <string.h> |
| 31 | +#include <unistd.h> |
31 | 32 | #include <libusb-1.0/libusb.h> |
32 | 33 | #include "freenect_internal.h" |
| 34 | +#include "loader.h" |
33 | 35 |
|
34 | 36 | int fnusb_num_devices(fnusb_ctx *ctx) |
35 | 37 | { |
@@ -199,6 +201,95 @@ int fnusb_open_subdevices(freenect_device *dev, int index) |
199 | 201 | dev->usb_audio.dev = NULL; |
200 | 202 | break; |
201 | 203 | } |
| 204 | + // Using the device handle that we've claimed, see if this |
| 205 | + // device has already uploaded firmware (has 2 interfaces). If |
| 206 | + // not, save the serial number (by reading the appropriate |
| 207 | + // descriptor), upload the firmware, and then enter a loop |
| 208 | + // waiting for a device with the same serial number to |
| 209 | + // reappear. |
| 210 | + int num_interfaces = fnusb_num_interfaces(&dev->usb_audio); |
| 211 | + if (num_interfaces == 1) { |
| 212 | + // Read the serial number from the string descriptor and save it. |
| 213 | + unsigned char string_desc[256]; // String descriptors are at most 256 bytes |
| 214 | + res = libusb_get_string_descriptor_ascii(dev->usb_audio.dev, desc.iSerialNumber, string_desc, 256); |
| 215 | + if (res < 0) { |
| 216 | + FN_ERROR("Failed to retrieve serial number for audio device in bootloader state\n"); |
| 217 | + break; |
| 218 | + } |
| 219 | + char* audio_serial = strdup((char*)string_desc); |
| 220 | + |
| 221 | + FN_SPEW("Uploading firmware to audio device in bootloader state.\n"); |
| 222 | + res = upload_firmware(&dev->usb_audio); |
| 223 | + if (res < 0) { |
| 224 | + FN_ERROR("upload_firmware failed: %d\n", res); |
| 225 | + break; |
| 226 | + } |
| 227 | + libusb_close(dev->usb_audio.dev); |
| 228 | + dev->usb_audio.dev = NULL; |
| 229 | + // Wait for the device to reappear. |
| 230 | + int loops = 0; |
| 231 | + for (loops = 0; loops < 10; loops++) { // Loop for at most 10 tries. |
| 232 | + FN_SPEW("Try %d: Looking for new audio device matching serial %s\n", loops, audio_serial); |
| 233 | + // Scan devices. |
| 234 | + libusb_device **new_dev_list; |
| 235 | + int dev_index; |
| 236 | + ssize_t num_new_devs = libusb_get_device_list(ctx->usb.ctx, &new_dev_list); |
| 237 | + for (dev_index = 0; dev_index < num_new_devs; ++dev_index) { |
| 238 | + struct libusb_device_descriptor new_dev_desc; |
| 239 | + int r; |
| 240 | + r = libusb_get_device_descriptor (new_dev_list[dev_index], &new_dev_desc); |
| 241 | + if (r < 0) |
| 242 | + continue; |
| 243 | + // If this dev is a Kinect audio device, open device, read serial, and compare. |
| 244 | + if (new_dev_desc.idVendor == VID_MICROSOFT && new_dev_desc.idProduct == PID_NUI_AUDIO) { |
| 245 | + FN_SPEW("Matched VID/PID!\n"); |
| 246 | + libusb_device_handle* new_dev_handle; |
| 247 | + // Open device |
| 248 | + r = libusb_open(new_dev_list[dev_index], &new_dev_handle); |
| 249 | + if (r < 0) |
| 250 | + continue; |
| 251 | + // Read serial |
| 252 | + r = libusb_get_string_descriptor_ascii(new_dev_handle, new_dev_desc.iSerialNumber, string_desc, 256); |
| 253 | + if (r < 0) { |
| 254 | + FN_SPEW("Lost new audio device while fetching serial number.\n"); |
| 255 | + libusb_close(new_dev_handle); |
| 256 | + continue; |
| 257 | + } |
| 258 | + // Compare to expected serial |
| 259 | + if (r == strlen(audio_serial) && strcmp((char*)string_desc, audio_serial) == 0) { |
| 260 | + // We found it! |
| 261 | + r = libusb_claim_interface(new_dev_handle, 0); |
| 262 | + if (r != 0) { |
| 263 | + // Ouch, found the device but couldn't claim the interface. |
| 264 | + FN_SPEW("Device with serial %s reappeared but couldn't claim interface 0\n", audio_serial); |
| 265 | + libusb_close(new_dev_handle); |
| 266 | + continue; |
| 267 | + } |
| 268 | + // Save the device handle. |
| 269 | + dev->usb_audio.dev = new_dev_handle; |
| 270 | + // Verify that we've actually found a device running the right firmware. |
| 271 | + if (fnusb_num_interfaces(&dev->usb_audio) != 2) { |
| 272 | + FN_SPEW("Opened audio with matching serial but too few interfaces.\n"); |
| 273 | + dev->usb_audio.dev = NULL; |
| 274 | + libusb_close(new_dev_handle); |
| 275 | + continue; |
| 276 | + } |
| 277 | + break; |
| 278 | + } else { |
| 279 | + FN_SPEW("Got serial %s, expected serial %s\n", (char*)string_desc, audio_serial); |
| 280 | + } |
| 281 | + } |
| 282 | + } |
| 283 | + |
| 284 | + libusb_free_device_list(new_dev_list, 1); |
| 285 | + // If we found the right device, break out of this loop. |
| 286 | + if (dev->usb_audio.dev) |
| 287 | + break; |
| 288 | + // Sleep for a second to give the device more time to reenumerate. |
| 289 | + sleep(1); |
| 290 | + } |
| 291 | + free(audio_serial); |
| 292 | + } |
202 | 293 | } else { |
203 | 294 | nr_audio++; |
204 | 295 | } |
|
0 commit comments