1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 *  Copyright (C) 2010-2012 Ken Tossell
5 *  All rights reserved.
6 *
7 *  Redistribution and use in source and binary forms, with or without
8 *  modification, are permitted provided that the following conditions
9 *  are met:
10 *
11 *   * Redistributions of source code must retain the above copyright
12 *     notice, this list of conditions and the following disclaimer.
13 *   * Redistributions in binary form must reproduce the above
14 *     copyright notice, this list of conditions and the following
15 *     disclaimer in the documentation and/or other materials provided
16 *     with the distribution.
17 *   * Neither the name of the author nor other contributors may be
18 *     used to endorse or promote products derived from this software
19 *     without specific prior written permission.
20 *
21 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 *  POSSIBILITY OF SUCH DAMAGE.
33 *********************************************************************/
34 /**
35  * @defgroup device Device handling and enumeration
36  * @brief Support for finding, inspecting and opening UVC devices
37  */
38 
39 #include "libuvc/libuvc.h"
40 #include "libuvc/libuvc_internal.h"
41 
42 int uvc_already_open(uvc_context_t *ctx, struct libusb_device *usb_dev);
43 void uvc_free_devh(uvc_device_handle_t *devh);
44 
45 uvc_error_t uvc_get_device_info(uvc_device_t *dev, uvc_device_info_t **info);
46 void uvc_free_device_info(uvc_device_info_t *info);
47 
48 uvc_error_t uvc_scan_control(uvc_device_t *dev, uvc_device_info_t *info);
49 uvc_error_t uvc_parse_vc(uvc_device_t *dev,
50 			 uvc_device_info_t *info,
51 			 const unsigned char *block, size_t block_size);
52 uvc_error_t uvc_parse_vc_selector_unit(uvc_device_t *dev,
53 					uvc_device_info_t *info,
54 					const unsigned char *block, size_t block_size);
55 uvc_error_t uvc_parse_vc_extension_unit(uvc_device_t *dev,
56 					uvc_device_info_t *info,
57 					const unsigned char *block,
58 					size_t block_size);
59 uvc_error_t uvc_parse_vc_header(uvc_device_t *dev,
60 				uvc_device_info_t *info,
61 				const unsigned char *block, size_t block_size);
62 uvc_error_t uvc_parse_vc_input_terminal(uvc_device_t *dev,
63 					uvc_device_info_t *info,
64 					const unsigned char *block,
65 					size_t block_size);
66 uvc_error_t uvc_parse_vc_processing_unit(uvc_device_t *dev,
67 					 uvc_device_info_t *info,
68 					 const unsigned char *block,
69 					 size_t block_size);
70 
71 uvc_error_t uvc_scan_streaming(uvc_device_t *dev,
72 			       uvc_device_info_t *info,
73 			       int interface_idx);
74 uvc_error_t uvc_parse_vs(uvc_device_t *dev,
75 			 uvc_device_info_t *info,
76 			 uvc_streaming_interface_t *stream_if,
77 			 const unsigned char *block, size_t block_size);
78 uvc_error_t uvc_parse_vs_format_uncompressed(uvc_streaming_interface_t *stream_if,
79 					     const unsigned char *block,
80 					     size_t block_size);
81 uvc_error_t uvc_parse_vs_format_mjpeg(uvc_streaming_interface_t *stream_if,
82 					     const unsigned char *block,
83 					     size_t block_size);
84 uvc_error_t uvc_parse_vs_frame_uncompressed(uvc_streaming_interface_t *stream_if,
85 					    const unsigned char *block,
86 					    size_t block_size);
87 uvc_error_t uvc_parse_vs_frame_format(uvc_streaming_interface_t *stream_if,
88 					    const unsigned char *block,
89 					    size_t block_size);
90 uvc_error_t uvc_parse_vs_frame_frame(uvc_streaming_interface_t *stream_if,
91 					    const unsigned char *block,
92 					    size_t block_size);
93 uvc_error_t uvc_parse_vs_input_header(uvc_streaming_interface_t *stream_if,
94 				      const unsigned char *block,
95 				      size_t block_size);
96 
97 void LIBUSB_CALL _uvc_status_callback(struct libusb_transfer *transfer);
98 
99 /** @internal
100  * @brief Test whether the specified USB device has been opened as a UVC device
101  * @ingroup device
102  *
103  * @param ctx Context in which to search for the UVC device
104  * @param usb_dev USB device to find
105  * @return true if the device is open in this context
106  */
uvc_already_open(uvc_context_t * ctx,struct libusb_device * usb_dev)107 int uvc_already_open(uvc_context_t *ctx, struct libusb_device *usb_dev) {
108   uvc_device_handle_t *devh;
109 
110   DL_FOREACH(ctx->open_devices, devh) {
111     if (usb_dev == devh->dev->usb_dev)
112       return 1;
113   }
114 
115   return 0;
116 }
117 
118 /** @brief Finds a camera identified by vendor, product and/or serial number
119  * @ingroup device
120  *
121  * @param[in] ctx UVC context in which to search for the camera
122  * @param[out] dev Reference to the camera, or NULL if not found
123  * @param[in] vid Vendor ID number, optional
124  * @param[in] pid Product ID number, optional
125  * @param[in] sn Serial number or NULL
126  * @return Error finding device or UVC_SUCCESS
127  */
uvc_find_device(uvc_context_t * ctx,uvc_device_t ** dev,int vid,int pid,const char * sn)128 uvc_error_t uvc_find_device(
129     uvc_context_t *ctx, uvc_device_t **dev,
130     int vid, int pid, const char *sn) {
131   uvc_error_t ret = UVC_SUCCESS;
132 
133   uvc_device_t **list;
134   uvc_device_t *test_dev;
135   int dev_idx;
136   int found_dev;
137 
138   UVC_ENTER();
139 
140   ret = uvc_get_device_list(ctx, &list);
141 
142   if (ret != UVC_SUCCESS) {
143     UVC_EXIT(ret);
144     return ret;
145   }
146 
147   dev_idx = 0;
148   found_dev = 0;
149 
150   while (!found_dev && (test_dev = list[dev_idx++]) != NULL) {
151     uvc_device_descriptor_t *desc;
152 
153     if (uvc_get_device_descriptor(test_dev, &desc) != UVC_SUCCESS)
154       continue;
155 
156     if ((!vid || desc->idVendor == vid)
157         && (!pid || desc->idProduct == pid)
158         && (!sn || (desc->serialNumber && !strcmp(desc->serialNumber, sn))))
159       found_dev = 1;
160 
161     uvc_free_device_descriptor(desc);
162   }
163 
164   if (found_dev)
165     uvc_ref_device(test_dev);
166 
167   uvc_free_device_list(list, 1);
168 
169   if (found_dev) {
170     *dev = test_dev;
171     UVC_EXIT(UVC_SUCCESS);
172     return UVC_SUCCESS;
173   } else {
174     UVC_EXIT(UVC_ERROR_NO_DEVICE);
175     return UVC_ERROR_NO_DEVICE;
176   }
177 }
178 
179 /** @brief Finds all cameras identified by vendor, product and/or serial number
180  * @ingroup device
181  *
182  * @param[in] ctx UVC context in which to search for the camera
183  * @param[out] devs List of matching cameras
184  * @param[in] vid Vendor ID number, optional
185  * @param[in] pid Product ID number, optional
186  * @param[in] sn Serial number or NULL
187  * @return Error finding device or UVC_SUCCESS
188  */
uvc_find_devices(uvc_context_t * ctx,uvc_device_t *** devs,int vid,int pid,const char * sn)189 uvc_error_t uvc_find_devices(
190     uvc_context_t *ctx, uvc_device_t ***devs,
191     int vid, int pid, const char *sn) {
192   uvc_error_t ret = UVC_SUCCESS;
193 
194   uvc_device_t **list;
195   uvc_device_t *test_dev;
196   int dev_idx;
197   int found_dev;
198 
199   uvc_device_t **list_internal;
200   int num_uvc_devices;
201 
202   UVC_ENTER();
203 
204   ret = uvc_get_device_list(ctx, &list);
205 
206   if (ret != UVC_SUCCESS) {
207     UVC_EXIT(ret);
208     return ret;
209   }
210 
211   num_uvc_devices = 0;
212   dev_idx = 0;
213   found_dev = 0;
214 
215   list_internal = malloc(sizeof(*list_internal));
216   *list_internal = NULL;
217 
218   while ((test_dev = list[dev_idx++]) != NULL) {
219     uvc_device_descriptor_t *desc;
220 
221     if (uvc_get_device_descriptor(test_dev, &desc) != UVC_SUCCESS)
222       continue;
223 
224     if ((!vid || desc->idVendor == vid)
225         && (!pid || desc->idProduct == pid)
226         && (!sn || (desc->serialNumber && !strcmp(desc->serialNumber, sn)))) {
227       found_dev = 1;
228       uvc_ref_device(test_dev);
229 
230       num_uvc_devices++;
231       list_internal = realloc(list_internal, (num_uvc_devices + 1) * sizeof(*list_internal));
232 
233       list_internal[num_uvc_devices - 1] = test_dev;
234       list_internal[num_uvc_devices] = NULL;
235     }
236 
237     uvc_free_device_descriptor(desc);
238   }
239 
240   uvc_free_device_list(list, 1);
241 
242   if (found_dev) {
243     *devs = list_internal;
244     UVC_EXIT(UVC_SUCCESS);
245     return UVC_SUCCESS;
246   } else {
247     UVC_EXIT(UVC_ERROR_NO_DEVICE);
248     return UVC_ERROR_NO_DEVICE;
249   }
250 }
251 
252 /** @brief Get the number of the bus to which the device is attached
253  * @ingroup device
254  */
uvc_get_bus_number(uvc_device_t * dev)255 uint8_t uvc_get_bus_number(uvc_device_t *dev) {
256   return libusb_get_bus_number(dev->usb_dev);
257 }
258 
259 /** @brief Get the number assigned to the device within its bus
260  * @ingroup device
261  */
uvc_get_device_address(uvc_device_t * dev)262 uint8_t uvc_get_device_address(uvc_device_t *dev) {
263   return libusb_get_device_address(dev->usb_dev);
264 }
265 
266 static uvc_error_t uvc_open_internal(uvc_device_t *dev, struct libusb_device_handle *usb_devh, uvc_device_handle_t **devh);
267 
268 #if LIBUSB_API_VERSION >= 0x01000107
269 /** @brief Wrap a platform-specific system device handle and obtain a UVC device handle.
270  * The handle allows you to use libusb to perform I/O on the device in question.
271  *
272  * On Linux, the system device handle must be a valid file descriptor opened on the device node.
273  *
274  * The system device handle must remain open until uvc_close() is called. The system device handle will not be closed by uvc_close().
275  * @ingroup device
276  *
277  * @param sys_dev the platform-specific system device handle
278  * @param context UVC context to prepare the device
279  * @param[out] devh Handle on opened device
280  * @return Error opening device or SUCCESS
281  */
uvc_wrap(int sys_dev,uvc_context_t * context,uvc_device_handle_t ** devh)282 uvc_error_t uvc_wrap(
283     int sys_dev,
284     uvc_context_t *context,
285     uvc_device_handle_t **devh) {
286   uvc_error_t ret;
287   struct libusb_device_handle *usb_devh;
288 
289   UVC_ENTER();
290 
291   uvc_device_t *dev = NULL;
292   ret = libusb_wrap_sys_device(context->usb_ctx, sys_dev, &usb_devh);
293   UVC_DEBUG("libusb_wrap_sys_device() = %d", ret);
294   if (ret != LIBUSB_SUCCESS) {
295     UVC_EXIT(ret);
296     return ret;
297   }
298 
299   dev = calloc(1, sizeof(uvc_device_t));
300   dev->ctx = context;
301   dev->usb_dev = libusb_get_device(usb_devh);
302 
303   ret = uvc_open_internal(dev, usb_devh, devh);
304   UVC_EXIT(ret);
305   return ret;
306 }
307 #endif
308 
309 /** @brief Open a UVC device
310  * @ingroup device
311  *
312  * @param dev Device to open
313  * @param[out] devh Handle on opened device
314  * @return Error opening device or SUCCESS
315  */
uvc_open(uvc_device_t * dev,uvc_device_handle_t ** devh)316 uvc_error_t uvc_open(
317     uvc_device_t *dev,
318     uvc_device_handle_t **devh) {
319   uvc_error_t ret;
320   struct libusb_device_handle *usb_devh;
321 
322   UVC_ENTER();
323 
324   ret = libusb_open(dev->usb_dev, &usb_devh);
325   UVC_DEBUG("libusb_open() = %d", ret);
326 
327   if (ret != UVC_SUCCESS) {
328     UVC_EXIT(ret);
329     return ret;
330   }
331 
332   ret = uvc_open_internal(dev, usb_devh, devh);
333   UVC_EXIT(ret);
334   return ret;
335 }
336 
uvc_open_internal(uvc_device_t * dev,struct libusb_device_handle * usb_devh,uvc_device_handle_t ** devh)337 static uvc_error_t uvc_open_internal(
338     uvc_device_t *dev,
339     struct libusb_device_handle *usb_devh,
340     uvc_device_handle_t **devh) {
341   uvc_error_t ret;
342   uvc_device_handle_t *internal_devh;
343   struct libusb_device_descriptor desc;
344 
345   UVC_ENTER();
346 
347   uvc_ref_device(dev);
348 
349   internal_devh = calloc(1, sizeof(*internal_devh));
350   internal_devh->dev = dev;
351   internal_devh->usb_devh = usb_devh;
352 
353   ret = uvc_get_device_info(dev, &(internal_devh->info));
354 
355   if (ret != UVC_SUCCESS)
356     goto fail;
357 
358   UVC_DEBUG("claiming control interface %d", internal_devh->info->ctrl_if.bInterfaceNumber);
359   ret = uvc_claim_if(internal_devh, internal_devh->info->ctrl_if.bInterfaceNumber);
360   if (ret != UVC_SUCCESS)
361     goto fail;
362 
363   libusb_get_device_descriptor(dev->usb_dev, &desc);
364   internal_devh->is_isight = (desc.idVendor == 0x05ac && desc.idProduct == 0x8501);
365 
366   if (internal_devh->info->ctrl_if.bEndpointAddress) {
367     internal_devh->status_xfer = libusb_alloc_transfer(0);
368     if (!internal_devh->status_xfer) {
369       ret = UVC_ERROR_NO_MEM;
370       goto fail;
371     }
372 
373     libusb_fill_interrupt_transfer(internal_devh->status_xfer,
374                                    usb_devh,
375                                    internal_devh->info->ctrl_if.bEndpointAddress,
376                                    internal_devh->status_buf,
377                                    sizeof(internal_devh->status_buf),
378                                    _uvc_status_callback,
379                                    internal_devh,
380                                    0);
381     ret = libusb_submit_transfer(internal_devh->status_xfer);
382     UVC_DEBUG("libusb_submit_transfer() = %d", ret);
383 
384     if (ret) {
385       fprintf(stderr,
386               "uvc: device has a status interrupt endpoint, but unable to read from it\n");
387       goto fail;
388     }
389   }
390 
391   if (dev->ctx->own_usb_ctx && dev->ctx->open_devices == NULL) {
392     /* Since this is our first device, we need to spawn the event handler thread */
393     uvc_start_handler_thread(dev->ctx);
394   }
395 
396   DL_APPEND(dev->ctx->open_devices, internal_devh);
397   *devh = internal_devh;
398 
399   UVC_EXIT(ret);
400 
401   return ret;
402 
403  fail:
404   if ( internal_devh->info ) {
405     uvc_release_if(internal_devh, internal_devh->info->ctrl_if.bInterfaceNumber);
406   }
407   libusb_close(usb_devh);
408   uvc_unref_device(dev);
409   uvc_free_devh(internal_devh);
410 
411   UVC_EXIT(ret);
412 
413   return ret;
414 }
415 
416 /**
417  * @internal
418  * @brief Parses the complete device descriptor for a device
419  * @ingroup device
420  * @note Free *info with uvc_free_device_info when you're done
421  *
422  * @param dev Device to parse descriptor for
423  * @param info Where to store a pointer to the new info struct
424  */
uvc_get_device_info(uvc_device_t * dev,uvc_device_info_t ** info)425 uvc_error_t uvc_get_device_info(uvc_device_t *dev,
426 				uvc_device_info_t **info) {
427   uvc_error_t ret;
428   uvc_device_info_t *internal_info;
429 
430   UVC_ENTER();
431 
432   internal_info = calloc(1, sizeof(*internal_info));
433   if (!internal_info) {
434     UVC_EXIT(UVC_ERROR_NO_MEM);
435     return UVC_ERROR_NO_MEM;
436   }
437 
438   if (libusb_get_config_descriptor(dev->usb_dev,
439 				   0,
440 				   &(internal_info->config)) != 0) {
441     free(internal_info);
442     UVC_EXIT(UVC_ERROR_IO);
443     return UVC_ERROR_IO;
444   }
445 
446   ret = uvc_scan_control(dev, internal_info);
447   if (ret != UVC_SUCCESS) {
448     uvc_free_device_info(internal_info);
449     UVC_EXIT(ret);
450     return ret;
451   }
452 
453   *info = internal_info;
454 
455   UVC_EXIT(ret);
456   return ret;
457 }
458 
459 /**
460  * @internal
461  * @brief Frees the device descriptor for a device
462  * @ingroup device
463  *
464  * @param info Which device info block to free
465  */
uvc_free_device_info(uvc_device_info_t * info)466 void uvc_free_device_info(uvc_device_info_t *info) {
467   uvc_input_terminal_t *input_term, *input_term_tmp;
468   uvc_processing_unit_t *proc_unit, *proc_unit_tmp;
469   uvc_extension_unit_t *ext_unit, *ext_unit_tmp;
470 
471   uvc_streaming_interface_t *stream_if, *stream_if_tmp;
472   uvc_format_desc_t *format, *format_tmp;
473   uvc_frame_desc_t *frame, *frame_tmp;
474   uvc_still_frame_desc_t *still_frame, *still_frame_tmp;
475   uvc_still_frame_res_t *still_res, *still_res_tmp;
476 
477   UVC_ENTER();
478 
479   DL_FOREACH_SAFE(info->ctrl_if.input_term_descs, input_term, input_term_tmp) {
480     DL_DELETE(info->ctrl_if.input_term_descs, input_term);
481     free(input_term);
482   }
483 
484   DL_FOREACH_SAFE(info->ctrl_if.processing_unit_descs, proc_unit, proc_unit_tmp) {
485     DL_DELETE(info->ctrl_if.processing_unit_descs, proc_unit);
486     free(proc_unit);
487   }
488 
489   DL_FOREACH_SAFE(info->ctrl_if.extension_unit_descs, ext_unit, ext_unit_tmp) {
490     DL_DELETE(info->ctrl_if.extension_unit_descs, ext_unit);
491     free(ext_unit);
492   }
493 
494   DL_FOREACH_SAFE(info->stream_ifs, stream_if, stream_if_tmp) {
495     DL_FOREACH_SAFE(stream_if->format_descs, format, format_tmp) {
496       DL_FOREACH_SAFE(format->frame_descs, frame, frame_tmp) {
497         if (frame->intervals)
498           free(frame->intervals);
499 
500         DL_DELETE(format->frame_descs, frame);
501         free(frame);
502       }
503 
504       if(format->still_frame_desc) {
505         DL_FOREACH_SAFE(format->still_frame_desc, still_frame, still_frame_tmp) {
506           DL_FOREACH_SAFE(still_frame->imageSizePatterns, still_res, still_res_tmp) {
507             free(still_res);
508           }
509 
510           if(still_frame->bCompression) {
511               free(still_frame->bCompression);
512           }
513           free(still_frame);
514         }
515       }
516 
517       DL_DELETE(stream_if->format_descs, format);
518       free(format);
519     }
520 
521     DL_DELETE(info->stream_ifs, stream_if);
522     free(stream_if);
523   }
524 
525   if (info->config)
526     libusb_free_config_descriptor(info->config);
527 
528   free(info);
529 
530   UVC_EXIT_VOID();
531 }
532 
533 /**
534  * @brief Get a descriptor that contains the general information about
535  * a device
536  * @ingroup device
537  *
538  * Free *desc with uvc_free_device_descriptor when you're done.
539  *
540  * @param dev Device to fetch information about
541  * @param[out] desc Descriptor structure
542  * @return Error if unable to fetch information, else SUCCESS
543  */
uvc_get_device_descriptor(uvc_device_t * dev,uvc_device_descriptor_t ** desc)544 uvc_error_t uvc_get_device_descriptor(
545     uvc_device_t *dev,
546     uvc_device_descriptor_t **desc) {
547   uvc_device_descriptor_t *desc_internal;
548   struct libusb_device_descriptor usb_desc;
549   struct libusb_device_handle *usb_devh;
550   uvc_error_t ret;
551 
552   UVC_ENTER();
553 
554   ret = libusb_get_device_descriptor(dev->usb_dev, &usb_desc);
555 
556   if (ret != UVC_SUCCESS) {
557     UVC_EXIT(ret);
558     return ret;
559   }
560 
561   desc_internal = calloc(1, sizeof(*desc_internal));
562   desc_internal->idVendor = usb_desc.idVendor;
563   desc_internal->idProduct = usb_desc.idProduct;
564 
565   if (libusb_open(dev->usb_dev, &usb_devh) == 0) {
566     unsigned char buf[64];
567 
568     int bytes = libusb_get_string_descriptor_ascii(
569         usb_devh, usb_desc.iSerialNumber, buf, sizeof(buf));
570 
571     if (bytes > 0)
572       desc_internal->serialNumber = strdup((const char*) buf);
573 
574     bytes = libusb_get_string_descriptor_ascii(
575         usb_devh, usb_desc.iManufacturer, buf, sizeof(buf));
576 
577     if (bytes > 0)
578       desc_internal->manufacturer = strdup((const char*) buf);
579 
580     bytes = libusb_get_string_descriptor_ascii(
581         usb_devh, usb_desc.iProduct, buf, sizeof(buf));
582 
583     if (bytes > 0)
584       desc_internal->product = strdup((const char*) buf);
585 
586     libusb_close(usb_devh);
587   } else {
588     UVC_DEBUG("can't open device %04x:%04x, not fetching serial etc.",
589 	      usb_desc.idVendor, usb_desc.idProduct);
590   }
591 
592   *desc = desc_internal;
593 
594   UVC_EXIT(ret);
595   return ret;
596 }
597 
598 /**
599  * @brief Frees a device descriptor created with uvc_get_device_descriptor
600  * @ingroup device
601  *
602  * @param desc Descriptor to free
603  */
uvc_free_device_descriptor(uvc_device_descriptor_t * desc)604 void uvc_free_device_descriptor(
605     uvc_device_descriptor_t *desc) {
606   UVC_ENTER();
607 
608   if (desc->serialNumber)
609     free((void*) desc->serialNumber);
610 
611   if (desc->manufacturer)
612     free((void*) desc->manufacturer);
613 
614   if (desc->product)
615     free((void*) desc->product);
616 
617   free(desc);
618 
619   UVC_EXIT_VOID();
620 }
621 
622 /**
623  * @brief Get a list of the UVC devices attached to the system
624  * @ingroup device
625  *
626  * @note Free the list with uvc_free_device_list when you're done.
627  *
628  * @param ctx UVC context in which to list devices
629  * @param list List of uvc_device structures
630  * @return Error if unable to list devices, else SUCCESS
631  */
uvc_get_device_list(uvc_context_t * ctx,uvc_device_t *** list)632 uvc_error_t uvc_get_device_list(
633     uvc_context_t *ctx,
634     uvc_device_t ***list) {
635   struct libusb_device **usb_dev_list;
636   struct libusb_device *usb_dev;
637   int num_usb_devices;
638 
639   uvc_device_t **list_internal;
640   int num_uvc_devices;
641 
642   /* per device */
643   int dev_idx;
644   struct libusb_config_descriptor *config;
645   struct libusb_device_descriptor desc;
646   uint8_t got_interface;
647 
648   /* per interface */
649   int interface_idx;
650   const struct libusb_interface *interface;
651 
652   /* per altsetting */
653   int altsetting_idx;
654   const struct libusb_interface_descriptor *if_desc;
655 
656   UVC_ENTER();
657 
658   num_usb_devices = libusb_get_device_list(ctx->usb_ctx, &usb_dev_list);
659 
660   if (num_usb_devices < 0) {
661     UVC_EXIT(UVC_ERROR_IO);
662     return UVC_ERROR_IO;
663   }
664 
665   list_internal = malloc(sizeof(*list_internal));
666   *list_internal = NULL;
667 
668   num_uvc_devices = 0;
669   dev_idx = -1;
670 
671   while ((usb_dev = usb_dev_list[++dev_idx]) != NULL) {
672     got_interface = 0;
673 
674     if (libusb_get_config_descriptor(usb_dev, 0, &config) != 0)
675       continue;
676 
677     if ( libusb_get_device_descriptor ( usb_dev, &desc ) != LIBUSB_SUCCESS )
678       continue;
679 
680     for (interface_idx = 0;
681 	 !got_interface && interface_idx < config->bNumInterfaces;
682 	 ++interface_idx) {
683       interface = &config->interface[interface_idx];
684 
685       for (altsetting_idx = 0;
686 	   !got_interface && altsetting_idx < interface->num_altsetting;
687 	   ++altsetting_idx) {
688 	if_desc = &interface->altsetting[altsetting_idx];
689 
690         // Skip TIS cameras that definitely aren't UVC even though they might
691         // look that way
692 
693         if ( 0x199e == desc.idVendor && desc.idProduct  >= 0x8201 &&
694             desc.idProduct <= 0x8208 ) {
695           continue;
696         }
697 
698         // Special case for Imaging Source cameras
699 	/* Video, Streaming */
700         if ( 0x199e == desc.idVendor && ( 0x8101 == desc.idProduct ||
701             0x8102 == desc.idProduct ) &&
702             if_desc->bInterfaceClass == 255 &&
703             if_desc->bInterfaceSubClass == 2 ) {
704 	  got_interface = 1;
705 	}
706 
707 	/* Video, Streaming */
708 	if (if_desc->bInterfaceClass == 14 && if_desc->bInterfaceSubClass == 2) {
709 	  got_interface = 1;
710 	}
711       }
712     }
713 
714     libusb_free_config_descriptor(config);
715 
716     if (got_interface) {
717       uvc_device_t *uvc_dev = malloc(sizeof(*uvc_dev));
718       uvc_dev->ctx = ctx;
719       uvc_dev->ref = 0;
720       uvc_dev->usb_dev = usb_dev;
721       uvc_ref_device(uvc_dev);
722 
723       num_uvc_devices++;
724       list_internal = realloc(list_internal, (num_uvc_devices + 1) * sizeof(*list_internal));
725 
726       list_internal[num_uvc_devices - 1] = uvc_dev;
727       list_internal[num_uvc_devices] = NULL;
728 
729       UVC_DEBUG("    UVC: %d", dev_idx);
730     } else {
731       UVC_DEBUG("non-UVC: %d", dev_idx);
732     }
733   }
734 
735   libusb_free_device_list(usb_dev_list, 1);
736 
737   *list = list_internal;
738 
739   UVC_EXIT(UVC_SUCCESS);
740   return UVC_SUCCESS;
741 }
742 
743 /**
744  * @brief Frees a list of device structures created with uvc_get_device_list.
745  * @ingroup device
746  *
747  * @param list Device list to free
748  * @param unref_devices Decrement the reference counter for each device
749  * in the list, and destroy any entries that end up with zero references
750  */
uvc_free_device_list(uvc_device_t ** list,uint8_t unref_devices)751 void uvc_free_device_list(uvc_device_t **list, uint8_t unref_devices) {
752   uvc_device_t *dev;
753   int dev_idx = 0;
754 
755   UVC_ENTER();
756 
757   if (unref_devices) {
758     while ((dev = list[dev_idx++]) != NULL) {
759       uvc_unref_device(dev);
760     }
761   }
762 
763   free(list);
764 
765   UVC_EXIT_VOID();
766 }
767 
768 /**
769  * @brief Get the uvc_device_t corresponding to an open device
770  * @ingroup device
771  *
772  * @note Unref the uvc_device_t when you're done with it
773  *
774  * @param devh Device handle to an open UVC device
775  */
uvc_get_device(uvc_device_handle_t * devh)776 uvc_device_t *uvc_get_device(uvc_device_handle_t *devh) {
777   uvc_ref_device(devh->dev);
778   return devh->dev;
779 }
780 
781 /**
782  * @brief Get the underlying libusb device handle for an open device
783  * @ingroup device
784  *
785  * This can be used to access other interfaces on the same device, e.g.
786  * a webcam microphone.
787  *
788  * @note The libusb device handle is only valid while the UVC device is open;
789  * it will be invalidated upon calling uvc_close.
790  *
791  * @param devh UVC device handle to an open device
792  */
uvc_get_libusb_handle(uvc_device_handle_t * devh)793 libusb_device_handle *uvc_get_libusb_handle(uvc_device_handle_t *devh) {
794   return devh->usb_devh;
795 }
796 
797 /**
798  * @brief Get camera terminal descriptor for the open device.
799  *
800  * @note Do not modify the returned structure.
801  * @note The returned structure is part of a linked list, but iterating through
802  * it will make it no longer the camera terminal
803  *
804  * @param devh Device handle to an open UVC device
805  */
uvc_get_camera_terminal(uvc_device_handle_t * devh)806 const uvc_input_terminal_t *uvc_get_camera_terminal(uvc_device_handle_t *devh) {
807   const uvc_input_terminal_t *term = uvc_get_input_terminals(devh);
808   while(term != NULL) {
809     if (term->wTerminalType == UVC_ITT_CAMERA) {
810       break;
811     }
812     else {
813       term = term->next;
814     }
815   }
816   return term;
817 }
818 
819 
820 /**
821  * @brief Get input terminal descriptors for the open device.
822  *
823  * @note Do not modify the returned structure.
824  * @note The returned structure is part of a linked list. Iterate through
825  *       it by using the 'next' pointers.
826  *
827  * @param devh Device handle to an open UVC device
828  */
uvc_get_input_terminals(uvc_device_handle_t * devh)829 const uvc_input_terminal_t *uvc_get_input_terminals(uvc_device_handle_t *devh) {
830   return devh->info->ctrl_if.input_term_descs;
831 }
832 
833 /**
834  * @brief Get output terminal descriptors for the open device.
835  *
836  * @note Do not modify the returned structure.
837  * @note The returned structure is part of a linked list. Iterate through
838  *       it by using the 'next' pointers.
839  *
840  * @param devh Device handle to an open UVC device
841  */
uvc_get_output_terminals(uvc_device_handle_t * devh)842 const uvc_output_terminal_t *uvc_get_output_terminals(uvc_device_handle_t *devh) {
843   return NULL; /* @todo */
844 }
845 
846 /**
847  * @brief Get selector unit descriptors for the open device.
848  *
849  * @note Do not modify the returned structure.
850  * @note The returned structure is part of a linked list. Iterate through
851  *       it by using the 'next' pointers.
852  *
853  * @param devh Device handle to an open UVC device
854  */
uvc_get_selector_units(uvc_device_handle_t * devh)855 const uvc_selector_unit_t *uvc_get_selector_units(uvc_device_handle_t *devh) {
856   return devh->info->ctrl_if.selector_unit_descs;
857 }
858 
859 /**
860  * @brief Get processing unit descriptors for the open device.
861  *
862  * @note Do not modify the returned structure.
863  * @note The returned structure is part of a linked list. Iterate through
864  *       it by using the 'next' pointers.
865  *
866  * @param devh Device handle to an open UVC device
867  */
uvc_get_processing_units(uvc_device_handle_t * devh)868 const uvc_processing_unit_t *uvc_get_processing_units(uvc_device_handle_t *devh) {
869   return devh->info->ctrl_if.processing_unit_descs;
870 }
871 
872 /**
873  * @brief Get extension unit descriptors for the open device.
874  *
875  * @note Do not modify the returned structure.
876  * @note The returned structure is part of a linked list. Iterate through
877  *       it by using the 'next' pointers.
878  *
879  * @param devh Device handle to an open UVC device
880  */
uvc_get_extension_units(uvc_device_handle_t * devh)881 const uvc_extension_unit_t *uvc_get_extension_units(uvc_device_handle_t *devh) {
882   return devh->info->ctrl_if.extension_unit_descs;
883 }
884 
885 /**
886  * @brief Increment the reference count for a device
887  * @ingroup device
888  *
889  * @param dev Device to reference
890  */
uvc_ref_device(uvc_device_t * dev)891 void uvc_ref_device(uvc_device_t *dev) {
892   UVC_ENTER();
893 
894   dev->ref++;
895   libusb_ref_device(dev->usb_dev);
896 
897   UVC_EXIT_VOID();
898 }
899 
900 /**
901  * @brief Decrement the reference count for a device
902  * @ingropu device
903  * @note If the count reaches zero, the device will be discarded
904  *
905  * @param dev Device to unreference
906  */
uvc_unref_device(uvc_device_t * dev)907 void uvc_unref_device(uvc_device_t *dev) {
908   UVC_ENTER();
909 
910   libusb_unref_device(dev->usb_dev);
911   dev->ref--;
912 
913   if (dev->ref == 0)
914     free(dev);
915 
916   UVC_EXIT_VOID();
917 }
918 
919 /** @internal
920  * Claim a UVC interface, detaching the kernel driver if necessary.
921  * @ingroup device
922  *
923  * @param devh UVC device handle
924  * @param idx UVC interface index
925  */
uvc_claim_if(uvc_device_handle_t * devh,int idx)926 uvc_error_t uvc_claim_if(uvc_device_handle_t *devh, int idx) {
927   int ret = UVC_SUCCESS;
928 
929   UVC_ENTER();
930 
931   if ( devh->claimed & ( 1 << idx )) {
932     UVC_DEBUG("attempt to claim already-claimed interface %d\n", idx );
933     UVC_EXIT(ret);
934     return ret;
935   }
936 
937   /* Tell libusb to detach any active kernel drivers. libusb will keep track of whether
938    * it found a kernel driver for this interface. */
939   ret = libusb_detach_kernel_driver(devh->usb_devh, idx);
940 
941   if (ret == UVC_SUCCESS || ret == LIBUSB_ERROR_NOT_FOUND || ret == LIBUSB_ERROR_NOT_SUPPORTED) {
942     UVC_DEBUG("claiming interface %d", idx);
943     if (!( ret = libusb_claim_interface(devh->usb_devh, idx))) {
944       devh->claimed |= ( 1 << idx );
945     }
946   } else {
947     UVC_DEBUG("not claiming interface %d: unable to detach kernel driver (%s)",
948               idx, uvc_strerror(ret));
949   }
950 
951   UVC_EXIT(ret);
952   return ret;
953 }
954 
955 /** @internal
956  * Release a UVC interface.
957  * @ingroup device
958  *
959  * @param devh UVC device handle
960  * @param idx UVC interface index
961  */
uvc_release_if(uvc_device_handle_t * devh,int idx)962 uvc_error_t uvc_release_if(uvc_device_handle_t *devh, int idx) {
963   int ret = UVC_SUCCESS;
964 
965   UVC_ENTER();
966   UVC_DEBUG("releasing interface %d", idx);
967   if (!( devh->claimed & ( 1 << idx ))) {
968     UVC_DEBUG("attempt to release unclaimed interface %d\n", idx );
969     UVC_EXIT(ret);
970     return ret;
971   }
972 
973   /* libusb_release_interface *should* reset the alternate setting to the first available,
974      but sometimes (e.g. on Darwin) it doesn't. Thus, we do it explicitly here.
975      This is needed to de-initialize certain cameras. */
976   libusb_set_interface_alt_setting(devh->usb_devh, idx, 0);
977   ret = libusb_release_interface(devh->usb_devh, idx);
978 
979   if (UVC_SUCCESS == ret) {
980     devh->claimed &= ~( 1 << idx );
981     /* Reattach any kernel drivers that were disabled when we claimed this interface */
982     ret = libusb_attach_kernel_driver(devh->usb_devh, idx);
983 
984     if (ret == UVC_SUCCESS) {
985       UVC_DEBUG("reattached kernel driver to interface %d", idx);
986     } else if (ret == LIBUSB_ERROR_NOT_FOUND || ret == LIBUSB_ERROR_NOT_SUPPORTED) {
987       ret = UVC_SUCCESS;  /* NOT_FOUND and NOT_SUPPORTED are OK: nothing to do */
988     } else {
989       UVC_DEBUG("error reattaching kernel driver to interface %d: %s",
990                 idx, uvc_strerror(ret));
991     }
992   }
993 
994   UVC_EXIT(ret);
995   return ret;
996 }
997 
998 /** @internal
999  * Find a device's VideoControl interface and process its descriptor
1000  * @ingroup device
1001  */
uvc_scan_control(uvc_device_t * dev,uvc_device_info_t * info)1002 uvc_error_t uvc_scan_control(uvc_device_t *dev, uvc_device_info_t *info) {
1003   const struct libusb_interface_descriptor *if_desc;
1004   uvc_error_t parse_ret, ret;
1005   int interface_idx;
1006   const unsigned char *buffer;
1007   size_t buffer_left, block_size;
1008 
1009   UVC_ENTER();
1010 
1011   ret = UVC_SUCCESS;
1012   if_desc = NULL;
1013 
1014   uvc_device_descriptor_t* dev_desc;
1015   int haveTISCamera = 0;
1016   uvc_get_device_descriptor ( dev, &dev_desc );
1017   if ( 0x199e == dev_desc->idVendor && ( 0x8101 == dev_desc->idProduct ||
1018       0x8102 == dev_desc->idProduct )) {
1019     haveTISCamera = 1;
1020   }
1021   uvc_free_device_descriptor ( dev_desc );
1022 
1023   for (interface_idx = 0; interface_idx < info->config->bNumInterfaces; ++interface_idx) {
1024     if_desc = &info->config->interface[interface_idx].altsetting[0];
1025 
1026     if ( haveTISCamera && if_desc->bInterfaceClass == 255 && if_desc->bInterfaceSubClass == 1) // Video, Control
1027       break;
1028 
1029     if (if_desc->bInterfaceClass == 14 && if_desc->bInterfaceSubClass == 1) // Video, Control
1030       break;
1031 
1032     if_desc = NULL;
1033   }
1034 
1035   if (if_desc == NULL) {
1036     UVC_EXIT(UVC_ERROR_INVALID_DEVICE);
1037     return UVC_ERROR_INVALID_DEVICE;
1038   }
1039 
1040   info->ctrl_if.bInterfaceNumber = interface_idx;
1041   if (if_desc->bNumEndpoints != 0) {
1042     info->ctrl_if.bEndpointAddress = if_desc->endpoint[0].bEndpointAddress;
1043   }
1044 
1045   buffer = if_desc->extra;
1046   buffer_left = if_desc->extra_length;
1047 
1048   while (buffer_left >= 3) { // parseX needs to see buf[0,2] = length,type
1049     block_size = buffer[0];
1050     parse_ret = uvc_parse_vc(dev, info, buffer, block_size);
1051 
1052     if (parse_ret != UVC_SUCCESS) {
1053       ret = parse_ret;
1054       break;
1055     }
1056 
1057     buffer_left -= block_size;
1058     buffer += block_size;
1059   }
1060 
1061   UVC_EXIT(ret);
1062   return ret;
1063 }
1064 
1065 /** @internal
1066  * @brief Parse a VideoControl header.
1067  * @ingroup device
1068  */
uvc_parse_vc_header(uvc_device_t * dev,uvc_device_info_t * info,const unsigned char * block,size_t block_size)1069 uvc_error_t uvc_parse_vc_header(uvc_device_t *dev,
1070 				uvc_device_info_t *info,
1071 				const unsigned char *block, size_t block_size) {
1072   size_t i;
1073   uvc_error_t scan_ret, ret = UVC_SUCCESS;
1074 
1075   UVC_ENTER();
1076 
1077   /*
1078   int uvc_version;
1079   uvc_version = (block[4] >> 4) * 1000 + (block[4] & 0x0f) * 100
1080     + (block[3] >> 4) * 10 + (block[3] & 0x0f);
1081   */
1082 
1083   info->ctrl_if.bcdUVC = SW_TO_SHORT(&block[3]);
1084 
1085   switch (info->ctrl_if.bcdUVC) {
1086   case 0x0100:
1087     info->ctrl_if.dwClockFrequency = DW_TO_INT(block + 7);
1088   case 0x010a:
1089     info->ctrl_if.dwClockFrequency = DW_TO_INT(block + 7);
1090   case 0x0110:
1091     break;
1092   default:
1093     UVC_EXIT(UVC_ERROR_NOT_SUPPORTED);
1094     return UVC_ERROR_NOT_SUPPORTED;
1095   }
1096 
1097   for (i = 12; i < block_size; ++i) {
1098     scan_ret = uvc_scan_streaming(dev, info, block[i]);
1099     if (scan_ret != UVC_SUCCESS) {
1100       ret = scan_ret;
1101       break;
1102     }
1103   }
1104 
1105   UVC_EXIT(ret);
1106   return ret;
1107 }
1108 
1109 /** @internal
1110  * @brief Parse a VideoControl input terminal.
1111  * @ingroup device
1112  */
uvc_parse_vc_input_terminal(uvc_device_t * dev,uvc_device_info_t * info,const unsigned char * block,size_t block_size)1113 uvc_error_t uvc_parse_vc_input_terminal(uvc_device_t *dev,
1114 					uvc_device_info_t *info,
1115 					const unsigned char *block, size_t block_size) {
1116   uvc_input_terminal_t *term;
1117   size_t i;
1118 
1119   UVC_ENTER();
1120 
1121   /* only supporting camera-type input terminals */
1122   if (SW_TO_SHORT(&block[4]) != UVC_ITT_CAMERA) {
1123     UVC_EXIT(UVC_SUCCESS);
1124     return UVC_SUCCESS;
1125   }
1126 
1127   term = calloc(1, sizeof(*term));
1128 
1129   term->bTerminalID = block[3];
1130   term->wTerminalType = SW_TO_SHORT(&block[4]);
1131   term->wObjectiveFocalLengthMin = SW_TO_SHORT(&block[8]);
1132   term->wObjectiveFocalLengthMax = SW_TO_SHORT(&block[10]);
1133   term->wOcularFocalLength = SW_TO_SHORT(&block[12]);
1134 
1135   for (i = 14 + block[14]; i >= 15; --i)
1136     term->bmControls = block[i] + (term->bmControls << 8);
1137 
1138   DL_APPEND(info->ctrl_if.input_term_descs, term);
1139 
1140   UVC_EXIT(UVC_SUCCESS);
1141   return UVC_SUCCESS;
1142 }
1143 
1144 /** @internal
1145  * @brief Parse a VideoControl processing unit.
1146  * @ingroup device
1147  */
uvc_parse_vc_processing_unit(uvc_device_t * dev,uvc_device_info_t * info,const unsigned char * block,size_t block_size)1148 uvc_error_t uvc_parse_vc_processing_unit(uvc_device_t *dev,
1149 					 uvc_device_info_t *info,
1150 					 const unsigned char *block, size_t block_size) {
1151   uvc_processing_unit_t *unit;
1152   size_t i;
1153 
1154   UVC_ENTER();
1155 
1156   unit = calloc(1, sizeof(*unit));
1157   unit->bUnitID = block[3];
1158   unit->bSourceID = block[4];
1159 
1160   for (i = 7 + block[7]; i >= 8; --i)
1161     unit->bmControls = block[i] + (unit->bmControls << 8);
1162 
1163   DL_APPEND(info->ctrl_if.processing_unit_descs, unit);
1164 
1165   UVC_EXIT(UVC_SUCCESS);
1166   return UVC_SUCCESS;
1167 }
1168 
1169 /** @internal
1170  * @brief Parse a VideoControl selector unit.
1171  * @ingroup device
1172  */
uvc_parse_vc_selector_unit(uvc_device_t * dev,uvc_device_info_t * info,const unsigned char * block,size_t block_size)1173 uvc_error_t uvc_parse_vc_selector_unit(uvc_device_t *dev,
1174 					 uvc_device_info_t *info,
1175 					 const unsigned char *block, size_t block_size) {
1176   uvc_selector_unit_t *unit;
1177 
1178   UVC_ENTER();
1179 
1180   unit = calloc(1, sizeof(*unit));
1181   unit->bUnitID = block[3];
1182 
1183   DL_APPEND(info->ctrl_if.selector_unit_descs, unit);
1184 
1185   UVC_EXIT(UVC_SUCCESS);
1186   return UVC_SUCCESS;
1187 }
1188 
1189 /** @internal
1190  * @brief Parse a VideoControl extension unit.
1191  * @ingroup device
1192  */
uvc_parse_vc_extension_unit(uvc_device_t * dev,uvc_device_info_t * info,const unsigned char * block,size_t block_size)1193 uvc_error_t uvc_parse_vc_extension_unit(uvc_device_t *dev,
1194 					uvc_device_info_t *info,
1195 					const unsigned char *block, size_t block_size) {
1196   uvc_extension_unit_t *unit = calloc(1, sizeof(*unit));
1197   const uint8_t *start_of_controls;
1198   int size_of_controls, num_in_pins;
1199   int i;
1200 
1201   UVC_ENTER();
1202 
1203   unit->bUnitID = block[3];
1204   memcpy(unit->guidExtensionCode, &block[4], 16);
1205 
1206   num_in_pins = block[21];
1207   size_of_controls = block[22 + num_in_pins];
1208   start_of_controls = &block[23 + num_in_pins];
1209 
1210   for (i = size_of_controls - 1; i >= 0; --i)
1211     unit->bmControls = start_of_controls[i] + (unit->bmControls << 8);
1212 
1213   DL_APPEND(info->ctrl_if.extension_unit_descs, unit);
1214 
1215   UVC_EXIT(UVC_SUCCESS);
1216   return UVC_SUCCESS;
1217 }
1218 
1219 /** @internal
1220  * Process a single VideoControl descriptor block
1221  * @ingroup device
1222  */
uvc_parse_vc(uvc_device_t * dev,uvc_device_info_t * info,const unsigned char * block,size_t block_size)1223 uvc_error_t uvc_parse_vc(
1224     uvc_device_t *dev,
1225     uvc_device_info_t *info,
1226     const unsigned char *block, size_t block_size) {
1227   int descriptor_subtype;
1228   uvc_error_t ret = UVC_SUCCESS;
1229 
1230   UVC_ENTER();
1231 
1232   if (block[1] != 36) { // not a CS_INTERFACE descriptor??
1233     UVC_EXIT(UVC_SUCCESS);
1234     return UVC_SUCCESS; // UVC_ERROR_INVALID_DEVICE;
1235   }
1236 
1237   descriptor_subtype = block[2];
1238 
1239   switch (descriptor_subtype) {
1240   case UVC_VC_HEADER:
1241     ret = uvc_parse_vc_header(dev, info, block, block_size);
1242     break;
1243   case UVC_VC_INPUT_TERMINAL:
1244     ret = uvc_parse_vc_input_terminal(dev, info, block, block_size);
1245     break;
1246   case UVC_VC_OUTPUT_TERMINAL:
1247     break;
1248   case UVC_VC_SELECTOR_UNIT:
1249     ret = uvc_parse_vc_selector_unit(dev, info, block, block_size);
1250     break;
1251   case UVC_VC_PROCESSING_UNIT:
1252     ret = uvc_parse_vc_processing_unit(dev, info, block, block_size);
1253     break;
1254   case UVC_VC_EXTENSION_UNIT:
1255     ret = uvc_parse_vc_extension_unit(dev, info, block, block_size);
1256     break;
1257   default:
1258     ret = UVC_ERROR_INVALID_DEVICE;
1259   }
1260 
1261   UVC_EXIT(ret);
1262   return ret;
1263 }
1264 
1265 /** @internal
1266  * Process a VideoStreaming interface
1267  * @ingroup device
1268  */
uvc_scan_streaming(uvc_device_t * dev,uvc_device_info_t * info,int interface_idx)1269 uvc_error_t uvc_scan_streaming(uvc_device_t *dev,
1270 			       uvc_device_info_t *info,
1271 			       int interface_idx) {
1272   const struct libusb_interface_descriptor *if_desc;
1273   const unsigned char *buffer;
1274   size_t buffer_left, block_size;
1275   uvc_error_t ret, parse_ret;
1276   uvc_streaming_interface_t *stream_if;
1277 
1278   UVC_ENTER();
1279 
1280   ret = UVC_SUCCESS;
1281 
1282   if_desc = &(info->config->interface[interface_idx].altsetting[0]);
1283   buffer = if_desc->extra;
1284   buffer_left = if_desc->extra_length;
1285 
1286   stream_if = calloc(1, sizeof(*stream_if));
1287   stream_if->parent = info;
1288   stream_if->bInterfaceNumber = if_desc->bInterfaceNumber;
1289   DL_APPEND(info->stream_ifs, stream_if);
1290 
1291   while (buffer_left >= 3) {
1292     block_size = buffer[0];
1293     parse_ret = uvc_parse_vs(dev, info, stream_if, buffer, block_size);
1294 
1295     if (parse_ret != UVC_SUCCESS) {
1296       ret = parse_ret;
1297       break;
1298     }
1299 
1300     buffer_left -= block_size;
1301     buffer += block_size;
1302   }
1303 
1304   UVC_EXIT(ret);
1305   return ret;
1306 }
1307 
1308 /** @internal
1309  * @brief Parse a VideoStreaming header block.
1310  * @ingroup device
1311  */
uvc_parse_vs_input_header(uvc_streaming_interface_t * stream_if,const unsigned char * block,size_t block_size)1312 uvc_error_t uvc_parse_vs_input_header(uvc_streaming_interface_t *stream_if,
1313 				      const unsigned char *block,
1314 				      size_t block_size) {
1315   UVC_ENTER();
1316 
1317   stream_if->bEndpointAddress = block[6] & 0x8f;
1318   stream_if->bTerminalLink = block[8];
1319   stream_if->bStillCaptureMethod = block[9];
1320 
1321   UVC_EXIT(UVC_SUCCESS);
1322   return UVC_SUCCESS;
1323 }
1324 
1325 /** @internal
1326  * @brief Parse a VideoStreaming uncompressed format block.
1327  * @ingroup device
1328  */
uvc_parse_vs_format_uncompressed(uvc_streaming_interface_t * stream_if,const unsigned char * block,size_t block_size)1329 uvc_error_t uvc_parse_vs_format_uncompressed(uvc_streaming_interface_t *stream_if,
1330 					     const unsigned char *block,
1331 					     size_t block_size) {
1332   UVC_ENTER();
1333 
1334   uvc_format_desc_t *format = calloc(1, sizeof(*format));
1335 
1336   format->parent = stream_if;
1337   format->bDescriptorSubtype = block[2];
1338   format->bFormatIndex = block[3];
1339   //format->bmCapabilities = block[4];
1340   //format->bmFlags = block[5];
1341   memcpy(format->guidFormat, &block[5], 16);
1342   format->bBitsPerPixel = block[21];
1343   format->bDefaultFrameIndex = block[22];
1344   format->bAspectRatioX = block[23];
1345   format->bAspectRatioY = block[24];
1346   format->bmInterlaceFlags = block[25];
1347   format->bCopyProtect = block[26];
1348 
1349   DL_APPEND(stream_if->format_descs, format);
1350 
1351   UVC_EXIT(UVC_SUCCESS);
1352   return UVC_SUCCESS;
1353 }
1354 
1355 /** @internal
1356  * @brief Parse a VideoStreaming frame format block.
1357  * @ingroup device
1358  */
uvc_parse_vs_frame_format(uvc_streaming_interface_t * stream_if,const unsigned char * block,size_t block_size)1359 uvc_error_t uvc_parse_vs_frame_format(uvc_streaming_interface_t *stream_if,
1360 					     const unsigned char *block,
1361 					     size_t block_size) {
1362   UVC_ENTER();
1363 
1364   uvc_format_desc_t *format = calloc(1, sizeof(*format));
1365 
1366   format->parent = stream_if;
1367   format->bDescriptorSubtype = block[2];
1368   format->bFormatIndex = block[3];
1369   format->bNumFrameDescriptors = block[4];
1370   memcpy(format->guidFormat, &block[5], 16);
1371   format->bBitsPerPixel = block[21];
1372   format->bDefaultFrameIndex = block[22];
1373   format->bAspectRatioX = block[23];
1374   format->bAspectRatioY = block[24];
1375   format->bmInterlaceFlags = block[25];
1376   format->bCopyProtect = block[26];
1377   format->bVariableSize = block[27];
1378 
1379   DL_APPEND(stream_if->format_descs, format);
1380 
1381   UVC_EXIT(UVC_SUCCESS);
1382   return UVC_SUCCESS;
1383 }
1384 
1385 /** @internal
1386  * @brief Parse a VideoStreaming MJPEG format block.
1387  * @ingroup device
1388  */
uvc_parse_vs_format_mjpeg(uvc_streaming_interface_t * stream_if,const unsigned char * block,size_t block_size)1389 uvc_error_t uvc_parse_vs_format_mjpeg(uvc_streaming_interface_t *stream_if,
1390 					     const unsigned char *block,
1391 					     size_t block_size) {
1392   UVC_ENTER();
1393 
1394   uvc_format_desc_t *format = calloc(1, sizeof(*format));
1395 
1396   format->parent = stream_if;
1397   format->bDescriptorSubtype = block[2];
1398   format->bFormatIndex = block[3];
1399   memcpy(format->fourccFormat, "MJPG", 4);
1400   format->bmFlags = block[5];
1401   format->bBitsPerPixel = 0;
1402   format->bDefaultFrameIndex = block[6];
1403   format->bAspectRatioX = block[7];
1404   format->bAspectRatioY = block[8];
1405   format->bmInterlaceFlags = block[9];
1406   format->bCopyProtect = block[10];
1407 
1408   DL_APPEND(stream_if->format_descs, format);
1409 
1410   UVC_EXIT(UVC_SUCCESS);
1411   return UVC_SUCCESS;
1412 }
1413 
1414 /** @internal
1415  * @brief Parse a VideoStreaming uncompressed frame block.
1416  * @ingroup device
1417  */
uvc_parse_vs_frame_frame(uvc_streaming_interface_t * stream_if,const unsigned char * block,size_t block_size)1418 uvc_error_t uvc_parse_vs_frame_frame(uvc_streaming_interface_t *stream_if,
1419 					    const unsigned char *block,
1420 					    size_t block_size) {
1421   uvc_format_desc_t *format;
1422   uvc_frame_desc_t *frame;
1423 
1424   const unsigned char *p;
1425   int i;
1426 
1427   UVC_ENTER();
1428 
1429   format = stream_if->format_descs->prev;
1430   frame = calloc(1, sizeof(*frame));
1431 
1432   frame->parent = format;
1433 
1434   frame->bDescriptorSubtype = block[2];
1435   frame->bFrameIndex = block[3];
1436   frame->bmCapabilities = block[4];
1437   frame->wWidth = block[5] + (block[6] << 8);
1438   frame->wHeight = block[7] + (block[8] << 8);
1439   frame->dwMinBitRate = DW_TO_INT(&block[9]);
1440   frame->dwMaxBitRate = DW_TO_INT(&block[13]);
1441   frame->dwDefaultFrameInterval = DW_TO_INT(&block[17]);
1442   frame->bFrameIntervalType = block[21];
1443   frame->dwBytesPerLine = DW_TO_INT(&block[22]);
1444 
1445   if (block[21] == 0) {
1446     frame->dwMinFrameInterval = DW_TO_INT(&block[26]);
1447     frame->dwMaxFrameInterval = DW_TO_INT(&block[30]);
1448     frame->dwFrameIntervalStep = DW_TO_INT(&block[34]);
1449   } else {
1450     frame->intervals = calloc(block[21] + 1, sizeof(frame->intervals[0]));
1451     p = &block[26];
1452 
1453     for (i = 0; i < block[21]; ++i) {
1454       frame->intervals[i] = DW_TO_INT(p);
1455       p += 4;
1456     }
1457     frame->intervals[block[21]] = 0;
1458   }
1459 
1460   DL_APPEND(format->frame_descs, frame);
1461 
1462   UVC_EXIT(UVC_SUCCESS);
1463   return UVC_SUCCESS;
1464 }
1465 
1466 /** @internal
1467  * @brief Parse a VideoStreaming uncompressed frame block.
1468  * @ingroup device
1469  */
uvc_parse_vs_frame_uncompressed(uvc_streaming_interface_t * stream_if,const unsigned char * block,size_t block_size)1470 uvc_error_t uvc_parse_vs_frame_uncompressed(uvc_streaming_interface_t *stream_if,
1471 					    const unsigned char *block,
1472 					    size_t block_size) {
1473   uvc_format_desc_t *format;
1474   uvc_frame_desc_t *frame;
1475 
1476   const unsigned char *p;
1477   int i;
1478 
1479   UVC_ENTER();
1480 
1481   format = stream_if->format_descs->prev;
1482   frame = calloc(1, sizeof(*frame));
1483 
1484   frame->parent = format;
1485 
1486   frame->bDescriptorSubtype = block[2];
1487   frame->bFrameIndex = block[3];
1488   frame->bmCapabilities = block[4];
1489   frame->wWidth = block[5] + (block[6] << 8);
1490   frame->wHeight = block[7] + (block[8] << 8);
1491   frame->dwMinBitRate = DW_TO_INT(&block[9]);
1492   frame->dwMaxBitRate = DW_TO_INT(&block[13]);
1493   frame->dwMaxVideoFrameBufferSize = DW_TO_INT(&block[17]);
1494   frame->dwDefaultFrameInterval = DW_TO_INT(&block[21]);
1495   frame->bFrameIntervalType = block[25];
1496 
1497   if (block[25] == 0) {
1498     frame->dwMinFrameInterval = DW_TO_INT(&block[26]);
1499     frame->dwMaxFrameInterval = DW_TO_INT(&block[30]);
1500     frame->dwFrameIntervalStep = DW_TO_INT(&block[34]);
1501   } else {
1502     frame->intervals = calloc(block[25] + 1, sizeof(frame->intervals[0]));
1503     p = &block[26];
1504 
1505     for (i = 0; i < block[25]; ++i) {
1506       frame->intervals[i] = DW_TO_INT(p);
1507       p += 4;
1508     }
1509     frame->intervals[block[25]] = 0;
1510   }
1511 
1512   DL_APPEND(format->frame_descs, frame);
1513 
1514   UVC_EXIT(UVC_SUCCESS);
1515   return UVC_SUCCESS;
1516 }
1517 
1518 /** @internal
1519  * @brief Parse a VideoStreaming still iamge frame
1520  * @ingroup device
1521  */
uvc_parse_vs_still_image_frame(uvc_streaming_interface_t * stream_if,const unsigned char * block,size_t block_size)1522 uvc_error_t uvc_parse_vs_still_image_frame(uvc_streaming_interface_t *stream_if,
1523                         const unsigned char *block,
1524                         size_t block_size) {
1525 
1526   struct uvc_still_frame_desc* frame;
1527   uvc_format_desc_t *format;
1528 
1529   const unsigned char *p;
1530   int i;
1531 
1532   UVC_ENTER();
1533 
1534   format = stream_if->format_descs->prev;
1535   frame = calloc(1, sizeof(*frame));
1536 
1537   frame->parent = format;
1538 
1539   frame->bDescriptorSubtype = block[2];
1540   frame->bEndPointAddress   = block[3];
1541   uint8_t numImageSizePatterns = block[4];
1542 
1543   frame->imageSizePatterns = NULL;
1544 
1545   p = &block[5];
1546 
1547   for (i = 1; i <= numImageSizePatterns; ++i) {
1548     uvc_still_frame_res_t* res = calloc(1, sizeof(uvc_still_frame_res_t));
1549     res->bResolutionIndex = i;
1550     res->wWidth = SW_TO_SHORT(p);
1551     p += 2;
1552     res->wHeight = SW_TO_SHORT(p);
1553     p += 2;
1554 
1555     DL_APPEND(frame->imageSizePatterns, res);
1556   }
1557 
1558   p = &block[5+4*numImageSizePatterns];
1559   frame->bNumCompressionPattern = *p;
1560 
1561   if(frame->bNumCompressionPattern)
1562   {
1563       frame->bCompression = calloc(frame->bNumCompressionPattern, sizeof(frame->bCompression[0]));
1564       for(i = 0; i < frame->bNumCompressionPattern; ++i)
1565       {
1566           ++p;
1567           frame->bCompression[i] = *p;
1568       }
1569   }
1570   else
1571   {
1572       frame->bCompression = NULL;
1573   }
1574 
1575   DL_APPEND(format->still_frame_desc, frame);
1576 
1577   UVC_EXIT(UVC_SUCCESS);
1578   return UVC_SUCCESS;
1579 }
1580 
1581 /** @internal
1582  * Process a single VideoStreaming descriptor block
1583  * @ingroup device
1584  */
uvc_parse_vs(uvc_device_t * dev,uvc_device_info_t * info,uvc_streaming_interface_t * stream_if,const unsigned char * block,size_t block_size)1585 uvc_error_t uvc_parse_vs(
1586     uvc_device_t *dev,
1587     uvc_device_info_t *info,
1588     uvc_streaming_interface_t *stream_if,
1589     const unsigned char *block, size_t block_size) {
1590   uvc_error_t ret;
1591   int descriptor_subtype;
1592 
1593   UVC_ENTER();
1594 
1595   ret = UVC_SUCCESS;
1596   descriptor_subtype = block[2];
1597 
1598   switch (descriptor_subtype) {
1599   case UVC_VS_INPUT_HEADER:
1600     ret = uvc_parse_vs_input_header(stream_if, block, block_size);
1601     break;
1602   case UVC_VS_OUTPUT_HEADER:
1603     UVC_DEBUG("unsupported descriptor subtype VS_OUTPUT_HEADER");
1604     break;
1605   case UVC_VS_STILL_IMAGE_FRAME:
1606     ret = uvc_parse_vs_still_image_frame(stream_if, block, block_size);
1607     break;
1608   case UVC_VS_FORMAT_UNCOMPRESSED:
1609     ret = uvc_parse_vs_format_uncompressed(stream_if, block, block_size);
1610     break;
1611   case UVC_VS_FORMAT_MJPEG:
1612     ret = uvc_parse_vs_format_mjpeg(stream_if, block, block_size);
1613     break;
1614   case UVC_VS_FRAME_UNCOMPRESSED:
1615   case UVC_VS_FRAME_MJPEG:
1616     ret = uvc_parse_vs_frame_uncompressed(stream_if, block, block_size);
1617     break;
1618   case UVC_VS_FORMAT_MPEG2TS:
1619     UVC_DEBUG("unsupported descriptor subtype VS_FORMAT_MPEG2TS");
1620     break;
1621   case UVC_VS_FORMAT_DV:
1622     UVC_DEBUG("unsupported descriptor subtype VS_FORMAT_DV");
1623     break;
1624   case UVC_VS_COLORFORMAT:
1625     UVC_DEBUG("unsupported descriptor subtype VS_COLORFORMAT");
1626     break;
1627   case UVC_VS_FORMAT_FRAME_BASED:
1628     ret = uvc_parse_vs_frame_format ( stream_if, block, block_size );
1629     break;
1630   case UVC_VS_FRAME_FRAME_BASED:
1631     ret = uvc_parse_vs_frame_frame ( stream_if, block, block_size );
1632     break;
1633   case UVC_VS_FORMAT_STREAM_BASED:
1634     UVC_DEBUG("unsupported descriptor subtype VS_FORMAT_STREAM_BASED");
1635     break;
1636   default:
1637     /** @todo handle JPEG and maybe still frames or even DV... */
1638     //UVC_DEBUG("unsupported descriptor subtype: %d",descriptor_subtype);
1639     break;
1640   }
1641 
1642   UVC_EXIT(ret);
1643   return ret;
1644 }
1645 
1646 /** @internal
1647  * @brief Free memory associated with a UVC device
1648  * @pre Streaming must be stopped, and threads must have died
1649  */
uvc_free_devh(uvc_device_handle_t * devh)1650 void uvc_free_devh(uvc_device_handle_t *devh) {
1651   UVC_ENTER();
1652 
1653   if (devh->info)
1654     uvc_free_device_info(devh->info);
1655 
1656   if (devh->status_xfer)
1657     libusb_free_transfer(devh->status_xfer);
1658 
1659   free(devh);
1660 
1661   UVC_EXIT_VOID();
1662 }
1663 
1664 /** @brief Close a device
1665  *
1666  * @ingroup device
1667  *
1668  * Ends any stream that's in progress.
1669  *
1670  * The device handle and frame structures will be invalidated.
1671  */
uvc_close(uvc_device_handle_t * devh)1672 void uvc_close(uvc_device_handle_t *devh) {
1673   UVC_ENTER();
1674   uvc_context_t *ctx = devh->dev->ctx;
1675 
1676   if (devh->streams)
1677     uvc_stop_streaming(devh);
1678 
1679   uvc_release_if(devh, devh->info->ctrl_if.bInterfaceNumber);
1680 
1681   /* If we are managing the libusb context and this is the last open device,
1682    * then we need to cancel the handler thread. When we call libusb_close,
1683    * it'll cause a return from the thread's libusb_handle_events call, after
1684    * which the handler thread will check the flag we set and then exit. */
1685   if (ctx->own_usb_ctx && ctx->open_devices == devh && devh->next == NULL) {
1686     ctx->kill_handler_thread = 1;
1687     libusb_close(devh->usb_devh);
1688     pthread_join(ctx->handler_thread, NULL);
1689   } else {
1690     libusb_close(devh->usb_devh);
1691   }
1692 
1693   DL_DELETE(ctx->open_devices, devh);
1694 
1695   uvc_unref_device(devh->dev);
1696 
1697   uvc_free_devh(devh);
1698 
1699   UVC_EXIT_VOID();
1700 }
1701 
1702 /** @internal
1703  * @brief Get number of open devices
1704  */
uvc_num_devices(uvc_context_t * ctx)1705 size_t uvc_num_devices(uvc_context_t *ctx) {
1706   size_t count = 0;
1707 
1708   uvc_device_handle_t *devh;
1709 
1710   UVC_ENTER();
1711 
1712   DL_FOREACH(ctx->open_devices, devh) {
1713     count++;
1714   }
1715 
1716   UVC_EXIT((int) count);
1717   return count;
1718 }
1719 
uvc_process_control_status(uvc_device_handle_t * devh,unsigned char * data,int len)1720 void uvc_process_control_status(uvc_device_handle_t *devh, unsigned char *data, int len) {
1721   enum uvc_status_class status_class;
1722   uint8_t originator = 0, selector = 0, event = 0;
1723   enum uvc_status_attribute attribute = UVC_STATUS_ATTRIBUTE_UNKNOWN;
1724   void *content = NULL;
1725   size_t content_len = 0;
1726   int found_entity = 0;
1727   struct uvc_input_terminal *input_terminal;
1728   struct uvc_processing_unit *processing_unit;
1729 
1730   UVC_ENTER();
1731 
1732   if (len < 5) {
1733     UVC_DEBUG("Short read of VideoControl status update (%d bytes)", len);
1734     UVC_EXIT_VOID();
1735     return;
1736   }
1737 
1738   originator = data[1];
1739   event = data[2];
1740   selector = data[3];
1741 
1742   if (originator == 0) {
1743     UVC_DEBUG("Unhandled update from VC interface");
1744     UVC_EXIT_VOID();
1745     return;  /* @todo VideoControl virtual entity interface updates */
1746   }
1747 
1748   if (event != 0) {
1749     UVC_DEBUG("Unhandled VC event %d", (int) event);
1750     UVC_EXIT_VOID();
1751     return;
1752   }
1753 
1754   /* printf("bSelector: %d\n", selector); */
1755 
1756   DL_FOREACH(devh->info->ctrl_if.input_term_descs, input_terminal) {
1757     if (input_terminal->bTerminalID == originator) {
1758       status_class = UVC_STATUS_CLASS_CONTROL_CAMERA;
1759       found_entity = 1;
1760       break;
1761     }
1762   }
1763 
1764   if (!found_entity) {
1765     DL_FOREACH(devh->info->ctrl_if.processing_unit_descs, processing_unit) {
1766       if (processing_unit->bUnitID == originator) {
1767         status_class = UVC_STATUS_CLASS_CONTROL_PROCESSING;
1768         found_entity = 1;
1769         break;
1770       }
1771     }
1772   }
1773 
1774   if (!found_entity) {
1775     UVC_DEBUG("Got status update for unknown VideoControl entity %d",
1776   (int) originator);
1777     UVC_EXIT_VOID();
1778     return;
1779   }
1780 
1781   attribute = data[4];
1782   content = data + 5;
1783   content_len = len - 5;
1784 
1785   UVC_DEBUG("Event: class=%d, event=%d, selector=%d, attribute=%d, content_len=%zd",
1786     status_class, event, selector, attribute, content_len);
1787 
1788   if(devh->status_cb) {
1789     UVC_DEBUG("Running user-supplied status callback");
1790     devh->status_cb(status_class,
1791                     event,
1792                     selector,
1793                     attribute,
1794                     content, content_len,
1795                     devh->status_user_ptr);
1796   }
1797 
1798   UVC_EXIT_VOID();
1799 }
1800 
uvc_process_streaming_status(uvc_device_handle_t * devh,unsigned char * data,int len)1801 void uvc_process_streaming_status(uvc_device_handle_t *devh, unsigned char *data, int len) {
1802 
1803   UVC_ENTER();
1804 
1805   if (len < 3) {
1806     UVC_DEBUG("Invalid streaming status event received.\n");
1807     UVC_EXIT_VOID();
1808     return;
1809   }
1810 
1811   if (data[2] == 0) {
1812     if (len < 4) {
1813       UVC_DEBUG("Short read of status update (%d bytes)", len);
1814       UVC_EXIT_VOID();
1815       return;
1816     }
1817     UVC_DEBUG("Button (intf %u) %s len %d\n", data[1], data[3] ? "pressed" : "released", len);
1818 
1819     if(devh->button_cb) {
1820       UVC_DEBUG("Running user-supplied button callback");
1821       devh->button_cb(data[1],
1822                       data[3],
1823                       devh->button_user_ptr);
1824     }
1825   } else {
1826     UVC_DEBUG("Stream %u error event %02x %02x len %d.\n", data[1], data[2], data[3], len);
1827   }
1828 
1829   UVC_EXIT_VOID();
1830 }
1831 
uvc_process_status_xfer(uvc_device_handle_t * devh,struct libusb_transfer * transfer)1832 void uvc_process_status_xfer(uvc_device_handle_t *devh, struct libusb_transfer *transfer) {
1833 
1834   UVC_ENTER();
1835 
1836   /* printf("Got transfer of aLen = %d\n", transfer->actual_length); */
1837 
1838   if (transfer->actual_length > 0) {
1839     switch (transfer->buffer[0] & 0x0f) {
1840     case 1: /* VideoControl interface */
1841       uvc_process_control_status(devh, transfer->buffer, transfer->actual_length);
1842       break;
1843     case 2:  /* VideoStreaming interface */
1844       uvc_process_streaming_status(devh, transfer->buffer, transfer->actual_length);
1845       break;
1846     }
1847   }
1848 
1849   UVC_EXIT_VOID();
1850 }
1851 
1852 /** @internal
1853  * @brief Process asynchronous status updates from the device.
1854  */
_uvc_status_callback(struct libusb_transfer * transfer)1855 void LIBUSB_CALL _uvc_status_callback(struct libusb_transfer *transfer) {
1856   UVC_ENTER();
1857 
1858   uvc_device_handle_t *devh = (uvc_device_handle_t *) transfer->user_data;
1859 
1860   switch (transfer->status) {
1861   case LIBUSB_TRANSFER_ERROR:
1862   case LIBUSB_TRANSFER_CANCELLED:
1863   case LIBUSB_TRANSFER_NO_DEVICE:
1864     UVC_DEBUG("not processing/resubmitting, status = %d", transfer->status);
1865     UVC_EXIT_VOID();
1866     return;
1867   case LIBUSB_TRANSFER_COMPLETED:
1868     uvc_process_status_xfer(devh, transfer);
1869     break;
1870   case LIBUSB_TRANSFER_TIMED_OUT:
1871   case LIBUSB_TRANSFER_STALL:
1872   case LIBUSB_TRANSFER_OVERFLOW:
1873     UVC_DEBUG("retrying transfer, status = %d", transfer->status);
1874     break;
1875   }
1876 
1877 #ifdef UVC_DEBUGGING
1878   uvc_error_t ret =
1879 #endif
1880       libusb_submit_transfer(transfer);
1881   UVC_DEBUG("libusb_submit_transfer() = %d", ret);
1882 
1883   UVC_EXIT_VOID();
1884 }
1885 
1886 /** @brief Set a callback function to receive status updates
1887  *
1888  * @ingroup device
1889  */
uvc_set_status_callback(uvc_device_handle_t * devh,uvc_status_callback_t cb,void * user_ptr)1890 void uvc_set_status_callback(uvc_device_handle_t *devh,
1891                              uvc_status_callback_t cb,
1892                              void *user_ptr) {
1893   UVC_ENTER();
1894 
1895   devh->status_cb = cb;
1896   devh->status_user_ptr = user_ptr;
1897 
1898   UVC_EXIT_VOID();
1899 }
1900 
1901 /** @brief Set a callback function to receive button events
1902  *
1903  * @ingroup device
1904  */
uvc_set_button_callback(uvc_device_handle_t * devh,uvc_button_callback_t cb,void * user_ptr)1905 void uvc_set_button_callback(uvc_device_handle_t *devh,
1906                              uvc_button_callback_t cb,
1907                              void *user_ptr) {
1908   UVC_ENTER();
1909 
1910   devh->button_cb = cb;
1911   devh->button_user_ptr = user_ptr;
1912 
1913   UVC_EXIT_VOID();
1914 }
1915 
1916 /**
1917  * @brief Get format descriptions for the open device.
1918  *
1919  * @note Do not modify the returned structure.
1920  *
1921  * @param devh Device handle to an open UVC device
1922  */
uvc_get_format_descs(uvc_device_handle_t * devh)1923 const uvc_format_desc_t *uvc_get_format_descs(uvc_device_handle_t *devh) {
1924   return devh->info->stream_ifs->format_descs;
1925 }
1926 
1927