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