e1d7469b53157eb220d5155b4b8c6276bf991168
[rtmpclient.git] / app / src / main / jni / libuvc / src / ctrl.c
1 /*********************************************************************
2  * add some functions unsupported on original libuvc library
3  * and fixed some issues
4  * Copyright (C) 2014-2015 saki@serenegiant All rights reserved.
5  *********************************************************************/
6 /*********************************************************************
7  * Software License Agreement (BSD License)
8  *
9  *  Copyright (C) 2010-2012 Ken Tossell
10  *  All rights reserved.
11  *
12  *  Redistribution and use in source and binary forms, with or without
13  *  modification, are permitted provided that the following conditions
14  *  are met:
15  *
16  *   * Redistributions of source code must retain the above copyright
17  *     notice, this list of conditions and the following disclaimer.
18  *   * Redistributions in binary form must reproduce the above
19  *     copyright notice, this list of conditions and the following
20  *     disclaimer in the documentation and/or other materials provided
21  *     with the distribution.
22  *   * Neither the name of the author nor other contributors may be
23  *     used to endorse or promote products derived from this software
24  *     without specific prior written permission.
25  *
26  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
29  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
32  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
34  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
36  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  *  POSSIBILITY OF SUCH DAMAGE.
38  *********************************************************************/
39 /**
40  * @defgroup ctrl Video capture and processing controls
41  * @brief Functions for manipulating device settings and stream parameters
42  *
43  * The `uvc_get_*` and `uvc_set_*` functions are used to read and write the settings associated
44  * with the device's input, processing and output units.
45  */
46
47 #include "libuvc/libuvc.h"
48 #include "libuvc/libuvc_internal.h"
49
50 static const int REQ_TYPE_SET = 0x21;
51 static const int REQ_TYPE_GET = 0xa1;
52
53 #define CTRL_TIMEOUT_MILLIS 0
54
55 /***** GENERIC CONTROLS *****/
56 /**
57  * @brief Get the length of a control on a terminal or unit.
58  * 
59  * @param devh UVC device handle
60  * @param unit Unit or Terminal ID; obtain this from the uvc_extension_unit_t describing the extension unit
61  * @param ctrl Vendor-specific control number to query
62  * @return On success, the length of the control as reported by the device. Otherwise,
63  *   a uvc_error_t error describing the error encountered.
64  * @ingroup ctrl
65  */
66 int uvc_get_ctrl_len(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl) {
67         unsigned char buf[2];
68
69         int ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, UVC_GET_LEN,
70                         ctrl << 8,
71                         unit << 8,      // FIXME this will work wrong, invalid wIndex value
72                         buf, 2, CTRL_TIMEOUT_MILLIS);
73
74         if (UNLIKELY(ret < 0))
75                 return ret;
76         else
77                 return (unsigned short) SW_TO_SHORT(buf);
78 }
79
80 /**
81  * @brief Perform a GET_* request from an extension unit.
82  * 
83  * @param devh UVC device handle
84  * @param unit Unit ID; obtain this from the uvc_extension_unit_t describing the extension unit
85  * @param ctrl Control number to query
86  * @param data Data buffer to be filled by the device
87  * @param len Size of data buffer
88  * @param req_code GET_* request to execute
89  * @return On success, the number of bytes actually transferred. Otherwise,
90  *   a uvc_error_t error describing the error encountered.
91  * @ingroup ctrl
92  */
93 int uvc_get_ctrl(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl,
94                 void *data, int len, enum uvc_req_code req_code) {
95         return libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
96                         ctrl << 8,
97                         unit << 8,      // FIXME this will work wrong, invalid wIndex value
98                         data, len, CTRL_TIMEOUT_MILLIS);
99 }
100
101 /**
102  * @brief Perform a SET_CUR request to a terminal or unit.
103  * 
104  * @param devh UVC device handle
105  * @param unit Unit or Terminal ID
106  * @param ctrl Control number to set
107  * @param data Data buffer to be sent to the device
108  * @param len Size of data buffer
109  * @return On success, the number of bytes actually transferred. Otherwise,
110  *   a uvc_error_t error describing the error encountered.
111  * @ingroup ctrl
112  */
113 int uvc_set_ctrl(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl,
114                 void *data, int len) {
115         return libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
116                         ctrl << 8,
117                         unit << 8,      // FIXME this will work wrong, invalid wIndex value
118                         data, len, CTRL_TIMEOUT_MILLIS);
119 }
120
121 /***** INTERFACE CONTROLS *****/
122 /** VC Request Error Code Control (UVC 4.2.1.2) */ // XXX added saki
123 uvc_error_t uvc_vc_get_error_code(uvc_device_handle_t *devh,
124                 uvc_vc_error_code_control_t *error_code, enum uvc_req_code req_code) {
125         uint8_t error_char = 0;
126         uvc_error_t ret = UVC_SUCCESS;
127
128         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
129                         UVC_VC_REQUEST_ERROR_CODE_CONTROL << 8,
130                         devh->info->ctrl_if.bInterfaceNumber,   // XXX saki
131                         &error_char, sizeof(error_char), CTRL_TIMEOUT_MILLIS);
132
133         if (LIKELY(ret == 1)) {
134                 *error_code = error_char;
135                 return UVC_SUCCESS;
136         } else {
137                 return ret;
138         }
139 }
140
141 /** VS Request Error Code Control */ // XXX added saki
142 uvc_error_t uvc_vs_get_error_code(uvc_device_handle_t *devh,
143                 uvc_vs_error_code_control_t *error_code, enum uvc_req_code req_code) {
144         uint8_t error_char = 0;
145         uvc_error_t ret = UVC_SUCCESS;
146
147 #if 0 // This code may cause hang-up on some combinations of device and camera and temporary disabled.
148         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
149                         UVC_VS_STREAM_ERROR_CODE_CONTROL << 8,
150                         devh->info->stream_ifs->bInterfaceNumber,       // XXX is this OK?
151                         &error_char, sizeof(error_char), CTRL_TIMEOUT_MILLIS);
152
153         if (LIKELY(ret == 1)) {
154                 *error_code = error_char;
155                 return UVC_SUCCESS;
156         } else {
157                 return ret;
158         }
159 #else
160         return ret;
161 #endif
162 }
163
164 uvc_error_t uvc_get_power_mode(uvc_device_handle_t *devh,
165                 enum uvc_device_power_mode *mode, enum uvc_req_code req_code) {
166         uint8_t mode_char = 0;
167         uvc_error_t ret;
168
169         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
170                         UVC_VC_VIDEO_POWER_MODE_CONTROL << 8,
171                         devh->info->ctrl_if.bInterfaceNumber,   // XXX saki
172                         &mode_char, sizeof(mode_char), CTRL_TIMEOUT_MILLIS);
173
174         if (LIKELY(ret == 1)) {
175                 *mode = mode_char;
176                 return UVC_SUCCESS;
177         } else {
178                 return ret;
179         }
180 }
181
182 uvc_error_t uvc_set_power_mode(uvc_device_handle_t *devh,
183                 enum uvc_device_power_mode mode) {
184         uint8_t mode_char = mode;
185         uvc_error_t ret;
186
187         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
188                         UVC_VC_VIDEO_POWER_MODE_CONTROL << 8,
189                         devh->info->ctrl_if.bInterfaceNumber,   // XXX saki
190                         &mode_char, sizeof(mode_char), CTRL_TIMEOUT_MILLIS);
191
192         if (LIKELY(ret == 1))
193                 return UVC_SUCCESS;
194         else
195                 return ret;
196 }
197
198 /***** CAMERA TERMINAL CONTROLS *****/
199 uvc_error_t uvc_get_ae_mode(uvc_device_handle_t *devh, uint8_t *mode,
200                 enum uvc_req_code req_code) {
201         uint8_t data[1];
202         uvc_error_t ret;
203
204         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
205                         UVC_CT_AE_MODE_CONTROL << 8,
206 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
207                         devh->info->ctrl_if.input_term_descs->request,
208                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
209
210         if (LIKELY(ret == sizeof(data))) {
211                 *mode = data[0];
212                 return UVC_SUCCESS;
213         } else {
214                 return ret;
215         }
216 }
217
218 uvc_error_t uvc_set_ae_mode(uvc_device_handle_t *devh, uint8_t mode) {
219         uint8_t data[1];
220         uvc_error_t ret;
221
222         data[0] = mode;
223
224         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
225                         UVC_CT_AE_MODE_CONTROL << 8,
226 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
227                         devh->info->ctrl_if.input_term_descs->request,
228                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
229
230         if (LIKELY(ret == sizeof(data)))
231                 return UVC_SUCCESS;
232         else
233                 return ret;
234 }
235
236 //----------------------------------------------------------------------
237 uvc_error_t uvc_get_ae_priority(uvc_device_handle_t *devh, uint8_t *priority,
238                 enum uvc_req_code req_code) {
239         uint8_t data[1];
240         uvc_error_t ret;
241
242         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
243                         UVC_CT_AE_PRIORITY_CONTROL << 8,
244 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
245                         devh->info->ctrl_if.input_term_descs->request,
246                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
247
248         if (LIKELY(ret == sizeof(data))) {
249                 *priority = data[0];
250                 return UVC_SUCCESS;
251         } else {
252                 return ret;
253         }
254 }
255
256 uvc_error_t uvc_set_ae_priority(uvc_device_handle_t *devh, uint8_t priority) {
257         uint8_t data[1];
258         uvc_error_t ret;
259
260         data[0] = priority;
261
262         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
263                         UVC_CT_AE_PRIORITY_CONTROL << 8,
264 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
265                         devh->info->ctrl_if.input_term_descs->request,
266                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
267
268         if (LIKELY(ret == sizeof(data)))
269                 return UVC_SUCCESS;
270         else
271                 return ret;
272 }
273
274 //----------------------------------------------------------------------
275 uvc_error_t uvc_get_exposure_abs(uvc_device_handle_t *devh, int *time,
276                 enum uvc_req_code req_code) {
277         uint8_t data[4];
278         uvc_error_t ret;
279
280         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
281                         UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL << 8,
282 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
283                         devh->info->ctrl_if.input_term_descs->request,
284                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
285
286         if (LIKELY(ret == sizeof(data))) {
287                 *time = DW_TO_INT(data);
288                 return UVC_SUCCESS;
289         } else {
290                 return ret;
291         }
292 }
293
294 uvc_error_t uvc_set_exposure_abs(uvc_device_handle_t *devh, int time) {
295         uint8_t data[4];
296         uvc_error_t ret;
297
298         INT_TO_DW(time, data);
299
300         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
301                         UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL << 8,
302 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
303                         devh->info->ctrl_if.input_term_descs->request,
304                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
305
306         if (LIKELY(ret == sizeof(data)))
307                 return UVC_SUCCESS;
308         else
309                 return ret;
310 }
311
312 uvc_error_t uvc_get_exposure_rel(uvc_device_handle_t *devh, int *step,
313                 enum uvc_req_code req_code) {
314         uint8_t data[1];
315         uvc_error_t ret;
316
317         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
318                         UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL << 8,
319 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
320                         devh->info->ctrl_if.input_term_descs->request,
321                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
322
323         if (LIKELY(ret == sizeof(data))) {
324                 *step = data[0];
325                 return UVC_SUCCESS;
326         } else {
327                 return ret;
328         }
329 }
330
331 uvc_error_t uvc_set_exposure_rel(uvc_device_handle_t *devh, int step) {
332         uint8_t data[1];
333         uvc_error_t ret;
334
335         data[0] = step;
336
337         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
338                         UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL << 8,
339 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
340                         devh->info->ctrl_if.input_term_descs->request,
341                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
342
343         if (LIKELY(ret == sizeof(data)))
344                 return UVC_SUCCESS;
345         else
346                 return ret;
347 }
348
349 //----------------------------------------------------------------------
350 uvc_error_t uvc_get_scanning_mode(uvc_device_handle_t *devh, uint8_t *mode,
351                 enum uvc_req_code req_code) {
352         uint8_t data[1];
353         uvc_error_t ret;
354
355         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
356                         UVC_CT_SCANNING_MODE_CONTROL << 8,
357 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
358                         devh->info->ctrl_if.input_term_descs->request,
359                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
360
361         if (LIKELY(ret == sizeof(data))) {
362                 *mode = data[0];
363                 return UVC_SUCCESS;
364         } else {
365                 return ret;
366         }
367 }
368
369 uvc_error_t uvc_set_scanning_mode(uvc_device_handle_t *devh, uint8_t mode) {
370         uint8_t data[1];
371         uvc_error_t ret;
372
373         data[0] = mode;
374
375         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
376                         UVC_CT_SCANNING_MODE_CONTROL << 8,
377 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
378                         devh->info->ctrl_if.input_term_descs->request,
379                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
380
381         if (LIKELY(ret == sizeof(data)))
382                 return UVC_SUCCESS;
383         else
384                 return ret;
385 }
386
387 //----------------------------------------------------------------------
388 uvc_error_t uvc_get_focus_auto(uvc_device_handle_t *devh, uint8_t *autofocus,
389                 enum uvc_req_code req_code) {
390         uint8_t data[1];
391         uvc_error_t ret;
392
393         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
394                         UVC_CT_FOCUS_AUTO_CONTROL << 8,
395 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
396                         devh->info->ctrl_if.input_term_descs->request,
397                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
398
399         if (LIKELY(ret == sizeof(data))) {
400                 *autofocus = data[0];
401                 return UVC_SUCCESS;
402         } else {
403                 return ret;
404         }
405 }
406
407 uvc_error_t uvc_set_focus_auto(uvc_device_handle_t *devh, uint8_t autofocus) {
408         uint8_t data[1];
409         uvc_error_t ret;
410
411         data[0] = autofocus;
412
413         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
414                         UVC_CT_FOCUS_AUTO_CONTROL << 8,
415 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
416                         devh->info->ctrl_if.input_term_descs->request,
417                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
418
419         if (LIKELY(ret == sizeof(data)))
420                 return UVC_SUCCESS;
421         else
422                 return ret;
423 }
424
425 //----------------------------------------------------------------------
426 uvc_error_t uvc_get_focus_abs(uvc_device_handle_t *devh, short *focus,
427                 enum uvc_req_code req_code) {
428         uint8_t data[2];
429         uvc_error_t ret;
430
431         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
432                         UVC_CT_FOCUS_ABSOLUTE_CONTROL << 8,
433 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
434                         devh->info->ctrl_if.input_term_descs->request,
435                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
436
437         if (LIKELY(ret == sizeof(data))) {
438                 *focus = SW_TO_SHORT(data);
439                 return UVC_SUCCESS;
440         } else {
441                 return ret;
442         }
443 }
444
445 uvc_error_t uvc_set_focus_abs(uvc_device_handle_t *devh, short focus) {
446         uint8_t data[2];
447         uvc_error_t ret;
448
449         SHORT_TO_SW(focus, data);
450
451         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
452                         UVC_CT_FOCUS_ABSOLUTE_CONTROL << 8,
453 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
454                         devh->info->ctrl_if.input_term_descs->request,
455                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
456
457         if (LIKELY(ret == sizeof(data)))
458                 return UVC_SUCCESS;
459         else
460                 return ret;
461 }
462
463 uvc_error_t uvc_get_focus_rel(uvc_device_handle_t *devh, int8_t *focus, uint8_t *speed,
464                 enum uvc_req_code req_code) {
465         uint8_t data[2];
466         uvc_error_t ret;
467
468         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
469                         UVC_CT_FOCUS_RELATIVE_CONTROL << 8,
470 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
471                         devh->info->ctrl_if.input_term_descs->request,
472                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
473
474         if (LIKELY(ret == sizeof(data))) {
475                 *focus = data[0];
476                 *speed = data[1];
477                 return UVC_SUCCESS;
478         } else {
479                 return ret;
480         }
481 }
482
483 uvc_error_t uvc_set_focus_rel(uvc_device_handle_t *devh, int8_t focus, uint8_t speed) {
484         uint8_t data[2];
485         uvc_error_t ret;
486
487         data[0] = focus;
488         data[1] = speed;
489
490         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
491                         UVC_CT_FOCUS_RELATIVE_CONTROL << 8,
492 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
493                         devh->info->ctrl_if.input_term_descs->request,
494                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
495
496         if (LIKELY(ret == sizeof(data)))
497                 return UVC_SUCCESS;
498         else
499                 return ret;
500 }
501
502 //----------------------------------------------------------------------
503 uvc_error_t uvc_get_iris_abs(uvc_device_handle_t *devh, uint16_t *iris,
504                 enum uvc_req_code req_code) {
505         uint8_t data[2];
506         uvc_error_t ret;
507
508         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
509                         UVC_CT_FOCUS_ABSOLUTE_CONTROL << 8,
510 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
511                         devh->info->ctrl_if.input_term_descs->request,
512                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
513
514         if (LIKELY(ret == sizeof(data))) {
515                 *iris = SW_TO_SHORT(data);
516                 return UVC_SUCCESS;
517         } else {
518                 return ret;
519         }
520 }
521
522 uvc_error_t uvc_set_iris_abs(uvc_device_handle_t *devh, uint16_t iris) {
523         uint8_t data[2];
524         uvc_error_t ret;
525
526         SHORT_TO_SW(iris, data);
527
528         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
529                         UVC_CT_FOCUS_ABSOLUTE_CONTROL << 8,
530 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
531                         devh->info->ctrl_if.input_term_descs->request,
532                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
533
534         if (LIKELY(ret == sizeof(data)))
535                 return UVC_SUCCESS;
536         else
537                 return ret;
538 }
539
540 uvc_error_t uvc_get_iris_rel(uvc_device_handle_t *devh, uint8_t *iris,
541                 enum uvc_req_code req_code) {
542         uint8_t data[1];
543         uvc_error_t ret;
544
545         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
546                         UVC_CT_FOCUS_RELATIVE_CONTROL << 8,
547 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
548                         devh->info->ctrl_if.input_term_descs->request,
549                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
550
551         if (LIKELY(ret == sizeof(data))) {
552                 *iris = data[0];
553                 return UVC_SUCCESS;
554         } else {
555                 return ret;
556         }
557 }
558
559 uvc_error_t uvc_set_iris_rel(uvc_device_handle_t *devh, uint8_t iris) {
560         uint8_t data[1];
561         uvc_error_t ret;
562
563         data[0] = iris;
564
565         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
566                         UVC_CT_FOCUS_RELATIVE_CONTROL << 8,
567 //                      1 << 8, /* = fixed ID(00) and wrong VideoControl interface descriptor subtype(UVC_VC_HEADER) on original libuvc */
568                         devh->info->ctrl_if.input_term_descs->request,
569                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
570
571         if (LIKELY(ret == sizeof(data)))
572                 return UVC_SUCCESS;
573         else
574                 return ret;
575 }
576
577 //----------------------------------------------------------------------
578 uvc_error_t uvc_get_zoom_abs(uvc_device_handle_t *devh, uint16_t *zoom,
579                 enum uvc_req_code req_code) {
580         uint8_t data[2];
581         uvc_error_t ret;
582
583         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
584                         UVC_CT_ZOOM_ABSOLUTE_CONTROL << 8,
585                         devh->info->ctrl_if.input_term_descs->request,
586                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
587
588         if (LIKELY(ret == sizeof(data))) {
589                 *zoom = SW_TO_SHORT(data);
590                 return UVC_SUCCESS;
591         } else {
592                 return ret;
593         }
594 }
595
596 uvc_error_t uvc_set_zoom_abs(uvc_device_handle_t *devh, uint16_t zoom) {
597         uint8_t data[2];
598         uvc_error_t ret;
599
600         SHORT_TO_SW(zoom, data);
601
602         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
603                         UVC_CT_ZOOM_ABSOLUTE_CONTROL << 8,
604                         devh->info->ctrl_if.input_term_descs->request,
605                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
606
607         if (LIKELY(ret == sizeof(data)))
608                 return UVC_SUCCESS;
609         else
610                 return ret;
611 }
612
613 uvc_error_t uvc_get_zoom_rel(uvc_device_handle_t *devh, int8_t *zoom, uint8_t *isdigital, uint8_t *speed,
614                 enum uvc_req_code req_code) {
615         uint8_t data[3];
616         uvc_error_t ret;
617
618         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
619                         UVC_CT_ZOOM_RELATIVE_CONTROL << 8,
620                         devh->info->ctrl_if.input_term_descs->request,
621                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
622
623         if (LIKELY(ret == sizeof(data))) {
624                 *zoom = data[0];
625                 *isdigital = data[1];
626                 *speed = data[2];
627                 return UVC_SUCCESS;
628         } else {
629                 return ret;
630         }
631 }
632
633 uvc_error_t uvc_set_zoom_rel(uvc_device_handle_t *devh, int8_t zoom, uint8_t isdigital, uint8_t speed) {
634         uint8_t data[3];
635         uvc_error_t ret;
636
637         data[0] = zoom;
638         data[1] = isdigital;
639         data[2] = speed;
640
641         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
642                         UVC_CT_ZOOM_RELATIVE_CONTROL << 8,
643                         devh->info->ctrl_if.input_term_descs->request,
644                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
645
646         if (LIKELY(ret == sizeof(data)))
647                 return UVC_SUCCESS;
648         else
649                 return ret;
650 }
651
652 //----------------------------------------------------------------------
653 uvc_error_t uvc_get_pantilt_abs(uvc_device_handle_t *devh, int32_t *pan, int32_t *tilt,
654         enum uvc_req_code req_code) {
655
656         uint8_t data[8];
657         uvc_error_t ret;
658
659         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
660                         UVC_CT_PANTILT_ABSOLUTE_CONTROL << 8,
661                         devh->info->ctrl_if.input_term_descs->request,
662                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
663
664         if (LIKELY(ret == sizeof(data))) {
665                 *pan = DW_TO_INT(data);
666                 *tilt = DW_TO_INT(data + 4);
667                 return UVC_SUCCESS;
668         } else {
669                 return ret;
670         }
671 }
672
673 uvc_error_t uvc_set_pantilt_abs(uvc_device_handle_t *devh, int32_t pan, int32_t tilt) {
674         uint8_t data[8];
675         uvc_error_t ret;
676
677         INT_TO_DW(pan, data);
678         INT_TO_DW(tilt, data + 4);
679
680         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
681                         UVC_CT_PANTILT_ABSOLUTE_CONTROL << 8,
682                         devh->info->ctrl_if.input_term_descs->request,
683                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
684
685         if (LIKELY(ret == sizeof(data)))
686                 return UVC_SUCCESS;
687         else
688                 return ret;
689 }
690
691 uvc_error_t uvc_get_pantilt_rel(uvc_device_handle_t *devh,
692         int8_t *pan_rel, uint8_t *pan_speed,
693         int8_t* tilt_rel, uint8_t* tilt_speed,
694         enum uvc_req_code req_code) {
695
696         uint8_t data[4];
697         uvc_error_t ret;
698
699         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
700                         UVC_CT_PANTILT_RELATIVE_CONTROL << 8,
701                         devh->info->ctrl_if.input_term_descs->request,
702                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
703
704         if (LIKELY(ret == sizeof(data))) {
705                 *pan_rel = data[0];
706                 *pan_speed = data[1];
707                 *tilt_rel = data[2];
708                 *tilt_speed = data[3];
709                 return UVC_SUCCESS;
710         } else {
711                 return ret;
712         }
713 }
714
715 uvc_error_t uvc_set_pantilt_rel(uvc_device_handle_t *devh,
716         int8_t pan_rel, uint8_t pan_speed,
717         int8_t tilt_rel, uint8_t tilt_speed) {
718
719         uint8_t data[4];
720         uvc_error_t ret;
721
722         data[0] = pan_rel;
723         data[1] = pan_speed;
724         data[2] = tilt_rel;
725         data[3] = tilt_speed;
726
727         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
728                         UVC_CT_PANTILT_RELATIVE_CONTROL << 8,
729                         devh->info->ctrl_if.input_term_descs->request,
730                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
731
732         if (LIKELY(ret == sizeof(data)))
733                 return UVC_SUCCESS;
734         else
735                 return ret;
736 }
737
738 uvc_error_t uvc_get_roll_abs(uvc_device_handle_t *devh, int16_t *roll,
739         enum uvc_req_code req_code) {
740
741         uint8_t data[2];
742         uvc_error_t ret;
743
744         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
745                         UVC_CT_ROLL_ABSOLUTE_CONTROL << 8,
746                         devh->info->ctrl_if.input_term_descs->request,
747                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
748
749         if (LIKELY(ret == sizeof(data))) {
750                 *roll = SW_TO_SHORT(data + 0);
751                 return UVC_SUCCESS;
752         } else {
753                 return ret;
754         }
755 }
756
757 uvc_error_t uvc_set_roll_abs(uvc_device_handle_t *devh, int16_t roll) {
758
759         uint8_t data[2];
760         uvc_error_t ret;
761
762         SHORT_TO_SW(roll, data + 0);
763
764         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
765                         UVC_CT_ROLL_ABSOLUTE_CONTROL << 8,
766                         devh->info->ctrl_if.input_term_descs->request,
767                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
768
769         if (LIKELY(ret == sizeof(data)))
770                 return UVC_SUCCESS;
771         else
772                 return ret;
773 }
774
775 /** @ingroup ctrl
776  * @brief Reads the ROLL_RELATIVE control.
777  * @param devh UVC device handle
778  * @param[out] roll_rel TODO
779  * @param[out] speed TODO
780  * @param req_code UVC_GET_* request to execute
781  */
782 uvc_error_t uvc_get_roll_rel(uvc_device_handle_t *devh, int8_t *roll_rel, uint8_t *speed,
783         enum uvc_req_code req_code) {
784
785         uint8_t data[2];
786         uvc_error_t ret;
787
788         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
789                         UVC_CT_ROLL_RELATIVE_CONTROL << 8,
790                         devh->info->ctrl_if.input_term_descs->request,
791                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
792
793         if (LIKELY(ret == sizeof(data))) {
794                 *roll_rel = data[0];
795                 *speed = data[1];
796                 return UVC_SUCCESS;
797         } else {
798                 return ret;
799         }
800 }
801
802
803 /** @ingroup ctrl
804  * @brief Sets the ROLL_RELATIVE control.
805  * @param devh UVC device handle
806  * @param roll_rel TODO
807  * @param speed TODO
808  */
809 uvc_error_t uvc_set_roll_rel(uvc_device_handle_t *devh, int8_t roll_rel, uint8_t speed) {
810
811         uint8_t data[2];
812         uvc_error_t ret;
813
814         data[0] = roll_rel;
815         data[1] = speed;
816
817         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
818                         UVC_CT_ROLL_RELATIVE_CONTROL << 8,
819                         devh->info->ctrl_if.input_term_descs->request,
820                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
821
822         if (LIKELY(ret == sizeof(data)))
823                 return UVC_SUCCESS;
824         else
825                 return ret;
826 }
827
828 /** @ingroup ctrl
829  * @brief Reads the PRIVACY control.
830  * @param devh UVC device handle
831  * @param[out] privacy TODO
832  * @param req_code UVC_GET_* request to execute
833  */
834 uvc_error_t uvc_get_privacy(uvc_device_handle_t *devh, uint8_t *privacy,
835         enum uvc_req_code req_code) {
836
837         uint8_t data[1];
838         uvc_error_t ret;
839
840         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
841                         UVC_CT_PRIVACY_CONTROL << 8,
842                         devh->info->ctrl_if.input_term_descs->request,
843                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
844
845         if (LIKELY(ret == sizeof(data))) {
846                 *privacy = data[0];
847                 return UVC_SUCCESS;
848         } else {
849                 return ret;
850         }
851 }
852
853
854 /** @ingroup ctrl
855  * @brief Sets the PRIVACY control.
856  * @param devh UVC device handle
857  * @param privacy TODO
858  */
859 uvc_error_t uvc_set_privacy(uvc_device_handle_t *devh, uint8_t privacy) {
860
861         uint8_t data[1];
862         uvc_error_t ret;
863
864         data[0] = privacy;
865
866         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
867                         UVC_CT_PRIVACY_CONTROL << 8,
868                         devh->info->ctrl_if.input_term_descs->request,
869                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
870
871         if (LIKELY(ret == sizeof(data)))
872                 return UVC_SUCCESS;
873         else
874                 return ret;
875 }
876
877 /** @ingroup ctrl
878  * @brief Reads the DIGITAL_WINDOW control.
879  * @param devh UVC device handle
880  * @param[out] window_top TODO
881  * @param[out] window_left TODO
882  * @param[out] window_bottom TODO
883  * @param[out] window_right TODO
884  * @param[out] num_steps TODO
885  * @param[out] num_steps_units TODO
886  * @param req_code UVC_GET_* request to execute
887  */
888 uvc_error_t uvc_get_digital_window(uvc_device_handle_t *devh,
889         uint16_t *window_top, uint16_t *window_left,
890         uint16_t *window_bottom, uint16_t *window_right,
891         uint16_t *num_steps, uint16_t *num_steps_units,
892         enum uvc_req_code req_code) {
893
894         uint8_t data[12];
895         uvc_error_t ret;
896
897         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
898                         UVC_CT_DIGITAL_WINDOW_CONTROL << 8,
899                         devh->info->ctrl_if.input_term_descs->request,
900                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
901
902         if (LIKELY(ret == sizeof(data))) {
903                 *window_top = SW_TO_SHORT(data + 0);
904                 *window_left = SW_TO_SHORT(data + 2);
905                 *window_bottom = SW_TO_SHORT(data + 4);
906                 *window_right = SW_TO_SHORT(data + 6);
907                 *num_steps = SW_TO_SHORT(data + 8);
908                 *num_steps_units = SW_TO_SHORT(data + 10);
909                 return UVC_SUCCESS;
910         } else {
911                 return ret;
912         }
913 }
914
915
916 /** @ingroup ctrl
917  * @brief Sets the DIGITAL_WINDOW control.
918  * @param devh UVC device handle
919  * @param window_top TODO
920  * @param window_left TODO
921  * @param window_bottom TODO
922  * @param window_right TODO
923  * @param num_steps TODO
924  * @param num_steps_units TODO
925  */
926 uvc_error_t uvc_set_digital_window(uvc_device_handle_t *devh,
927         uint16_t window_top, uint16_t window_left,
928         uint16_t window_bottom, uint16_t window_right,
929         uint16_t num_steps, uint16_t num_steps_units) {
930
931         uint8_t data[12];
932         uvc_error_t ret;
933
934         SHORT_TO_SW(window_top, data + 0);
935         SHORT_TO_SW(window_left, data + 2);
936         SHORT_TO_SW(window_bottom, data + 4);
937         SHORT_TO_SW(window_right, data + 6);
938         SHORT_TO_SW(num_steps, data + 8);
939         SHORT_TO_SW(num_steps_units, data + 10);
940
941         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
942                         UVC_CT_DIGITAL_WINDOW_CONTROL << 8,
943                         devh->info->ctrl_if.input_term_descs->request,
944                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
945
946         if (LIKELY(ret == sizeof(data)))
947                 return UVC_SUCCESS;
948         else
949                 return ret;
950 }
951
952 /** @ingroup ctrl
953  * @brief Reads the REGION_OF_INTEREST control.
954  * @param devh UVC device handle
955  * @param[out] roi_top TODO
956  * @param[out] roi_left TODO
957  * @param[out] roi_bottom TODO
958  * @param[out] roi_right TODO
959  * @param[out] auto_controls TODO
960  * @param req_code UVC_GET_* request to execute
961  */
962 uvc_error_t uvc_get_digital_roi(uvc_device_handle_t *devh,
963         uint16_t *roi_top, uint16_t *roi_left,
964         uint16_t* roi_bottom, uint16_t *roi_right, uint16_t *auto_controls,
965         enum uvc_req_code req_code) {
966
967         uint8_t data[10];
968         uvc_error_t ret;
969
970         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
971                         UVC_CT_REGION_OF_INTEREST_CONTROL << 8,
972                         devh->info->ctrl_if.input_term_descs->request,
973                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
974
975         if (LIKELY(ret == sizeof(data))) {
976                 *roi_top = SW_TO_SHORT(data + 0);
977                 *roi_left = SW_TO_SHORT(data + 2);
978                 *roi_bottom = SW_TO_SHORT(data + 4);
979                 *roi_right = SW_TO_SHORT(data + 6);
980                 *auto_controls = SW_TO_SHORT(data + 8);
981                 return UVC_SUCCESS;
982         } else {
983                 return ret;
984         }
985 }
986
987
988 /** @ingroup ctrl
989  * @brief Sets the REGION_OF_INTEREST control.
990  * @param devh UVC device handle
991  * @param roi_top TODO
992  * @param roi_left TODO
993  * @param roi_bottom TODO
994  * @param roi_right TODO
995  * @param auto_controls TODO
996  */
997 uvc_error_t uvc_set_digital_roi(uvc_device_handle_t *devh,
998         uint16_t roi_top, uint16_t roi_left,
999         uint16_t roi_bottom, uint16_t roi_right, uint16_t auto_controls) {
1000
1001         uint8_t data[10];
1002         uvc_error_t ret;
1003
1004         SHORT_TO_SW(roi_top, data + 0);
1005         SHORT_TO_SW(roi_left, data + 2);
1006         SHORT_TO_SW(roi_bottom, data + 4);
1007         SHORT_TO_SW(roi_right, data + 6);
1008         SHORT_TO_SW(auto_controls, data + 8);
1009
1010         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1011                         UVC_CT_REGION_OF_INTEREST_CONTROL << 8,
1012                         devh->info->ctrl_if.input_term_descs->request,
1013                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1014
1015         if (LIKELY(ret == sizeof(data)))
1016                 return UVC_SUCCESS;
1017         else
1018                 return ret;
1019 }
1020
1021 /***** SELECTOR UNIT CONTROLS *****/
1022
1023 /** @todo input_select */
1024
1025 /***** PROCESSING UNIT CONTROLS *****/
1026 uvc_error_t uvc_get_backlight_compensation(uvc_device_handle_t *devh, short *comp,
1027                 enum uvc_req_code req_code) {
1028         uint8_t data[2];
1029         uvc_error_t ret;
1030
1031         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1032                         UVC_PU_BACKLIGHT_COMPENSATION_CONTROL << 8,
1033                         devh->info->ctrl_if.processing_unit_descs->request,
1034                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1035
1036         if (LIKELY(ret == sizeof(data))) {
1037                 *comp = SW_TO_SHORT(data);
1038                 return UVC_SUCCESS;
1039         } else {
1040                 return ret;
1041         }
1042         RETURN(-1, uvc_error_t);
1043 }
1044
1045 uvc_error_t uvc_set_backlight_compensation(uvc_device_handle_t *devh, short comp) {
1046         uint8_t data[2];
1047         uvc_error_t ret;
1048
1049         SHORT_TO_SW(comp, data);
1050
1051         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1052                         UVC_PU_BACKLIGHT_COMPENSATION_CONTROL << 8,
1053                         devh->info->ctrl_if.processing_unit_descs->request,
1054                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1055
1056         if (LIKELY(ret == sizeof(data)))
1057                 return UVC_SUCCESS;
1058         else
1059                 return ret;
1060 }
1061
1062 uvc_error_t uvc_get_brightness(uvc_device_handle_t *devh, short *brightness,
1063                 enum uvc_req_code req_code) {
1064         uint8_t data[2];
1065         uvc_error_t ret;
1066
1067         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1068                         UVC_PU_BRIGHTNESS_CONTROL << 8,
1069                         devh->info->ctrl_if.processing_unit_descs->request,
1070                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1071
1072         if (LIKELY(ret == sizeof(data))) {
1073                 *brightness = SW_TO_SHORT(data);
1074                 return UVC_SUCCESS;
1075         } else {
1076                 return ret;
1077         }
1078         RETURN(-1, uvc_error_t);
1079 }
1080
1081 uvc_error_t uvc_set_brightness(uvc_device_handle_t *devh, short brightness) {
1082         uint8_t data[2];
1083         uvc_error_t ret;
1084
1085         SHORT_TO_SW(brightness, data);
1086
1087         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1088                         UVC_PU_BRIGHTNESS_CONTROL << 8,
1089                         devh->info->ctrl_if.processing_unit_descs->request,
1090                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1091
1092         if (LIKELY(ret == sizeof(data)))
1093                 return UVC_SUCCESS;
1094         else
1095                 return ret;
1096 }
1097
1098 uvc_error_t uvc_get_contrast(uvc_device_handle_t *devh, uint16_t *contrast,
1099                 enum uvc_req_code req_code) {
1100         uint8_t data[2];
1101         uvc_error_t ret;
1102
1103         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1104                         UVC_PU_CONTRAST_CONTROL << 8,
1105                         devh->info->ctrl_if.processing_unit_descs->request,
1106                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1107
1108         if (LIKELY(ret == sizeof(data))) {
1109                 *contrast = SW_TO_SHORT(data);
1110                 return UVC_SUCCESS;
1111         } else {
1112                 return ret;
1113         }
1114         RETURN(-1, uvc_error_t);
1115 }
1116
1117 uvc_error_t uvc_set_contrast(uvc_device_handle_t *devh, uint16_t contrast) {
1118         uint8_t data[2];
1119         uvc_error_t ret;
1120
1121         SHORT_TO_SW(contrast, data);
1122
1123         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1124                         UVC_PU_CONTRAST_CONTROL << 8,
1125                         devh->info->ctrl_if.processing_unit_descs->request,
1126                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1127
1128         if (LIKELY(ret == sizeof(data)))
1129                 return UVC_SUCCESS;
1130         else
1131                 return ret;
1132 }
1133
1134 uvc_error_t uvc_get_contrast_auto(uvc_device_handle_t *devh, uint8_t *autoContrast,
1135                 enum uvc_req_code req_code) {
1136         uint8_t data[1];
1137         uvc_error_t ret;
1138
1139         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1140                         UVC_PU_CONTRAST_AUTO_CONTROL << 8,
1141                         devh->info->ctrl_if.processing_unit_descs->request,
1142                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1143
1144         if (LIKELY(ret == sizeof(data))) {
1145                 *autoContrast = data[0];
1146                 return UVC_SUCCESS;
1147         } else {
1148                 return ret;
1149         }
1150         RETURN(-1, uvc_error_t);
1151 }
1152
1153 uvc_error_t uvc_set_contrast_auto(uvc_device_handle_t *devh, uint8_t autoContrast) {
1154         uint8_t data[1];
1155         uvc_error_t ret;
1156
1157         data[0] = autoContrast ? 1 : 0;
1158
1159         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1160                         UVC_PU_CONTRAST_AUTO_CONTROL << 8,
1161                         devh->info->ctrl_if.processing_unit_descs->request,
1162                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1163
1164         if (LIKELY(ret == sizeof(data)))
1165                 return UVC_SUCCESS;
1166         else
1167                 return ret;
1168 }
1169
1170 uvc_error_t uvc_get_gain(uvc_device_handle_t *devh, uint16_t *gain,
1171                 enum uvc_req_code req_code) {
1172         uint8_t data[2];
1173         uvc_error_t ret;
1174
1175         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1176                         UVC_PU_GAIN_CONTROL << 8,
1177                         devh->info->ctrl_if.processing_unit_descs->request,
1178                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1179
1180         if (LIKELY(ret == sizeof(data))) {
1181                 *gain = SW_TO_SHORT(data);
1182                 return UVC_SUCCESS;
1183         } else {
1184                 return ret;
1185         }
1186         RETURN(-1, uvc_error_t);
1187 }
1188
1189 uvc_error_t uvc_set_gain(uvc_device_handle_t *devh, uint16_t gain) {
1190         uint8_t data[2];
1191         uvc_error_t ret;
1192
1193         SHORT_TO_SW(gain, data);
1194
1195         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1196                         UVC_PU_GAIN_CONTROL << 8,
1197                         devh->info->ctrl_if.processing_unit_descs->request,
1198                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1199
1200         if (LIKELY(ret == sizeof(data)))
1201                 return UVC_SUCCESS;
1202         else
1203                 return ret;
1204 }
1205
1206 uvc_error_t uvc_get_powerline_freqency(uvc_device_handle_t *devh, uint8_t *freq,
1207                 enum uvc_req_code req_code) {
1208         uint8_t data[1];
1209         uvc_error_t ret;
1210
1211         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1212                         UVC_PU_POWER_LINE_FREQUENCY_CONTROL << 8,
1213                         devh->info->ctrl_if.processing_unit_descs->request,
1214                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1215
1216         if (LIKELY(ret == sizeof(data))) {
1217                 *freq = data[0];
1218                 return UVC_SUCCESS;
1219         } else {
1220                 return ret;
1221         }
1222         RETURN(-1, uvc_error_t);
1223 }
1224
1225 uvc_error_t uvc_set_powerline_freqency(uvc_device_handle_t *devh, uint8_t freq) {
1226         uint8_t data[1];
1227         uvc_error_t ret;
1228
1229         // XXX AUTO(0x03) is only available for UVC1.5.
1230         if ( ((freq & 0xff) == 0xff)
1231                 || (((freq & 0x03) == 0x03) && (devh->info->ctrl_if.bcdUVC < 0x0150)) ) {
1232
1233                 ret = uvc_get_powerline_freqency(devh, &freq, UVC_GET_DEF);
1234                 if (UNLIKELY(ret)) {
1235                         LOGE("failed to uvc_get_powerline_freqency:err=%d", ret);
1236                         return ret;
1237                 }
1238         }
1239
1240         data[0] = freq & 0x03;
1241
1242         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1243                         UVC_PU_POWER_LINE_FREQUENCY_CONTROL << 8,
1244                         devh->info->ctrl_if.processing_unit_descs->request,
1245                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1246
1247         if (LIKELY(ret == sizeof(data)))
1248                 return UVC_SUCCESS;
1249         else
1250                 return ret;
1251 }
1252
1253 uvc_error_t uvc_get_hue(uvc_device_handle_t *devh, short *hue,
1254                 enum uvc_req_code req_code) {
1255         uint8_t data[2];
1256         uvc_error_t ret;
1257
1258         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1259                         UVC_PU_HUE_CONTROL << 8,
1260                         devh->info->ctrl_if.processing_unit_descs->request,
1261                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1262
1263         if (LIKELY(ret == sizeof(data))) {
1264                 *hue = SW_TO_SHORT(data);
1265                 return UVC_SUCCESS;
1266         } else {
1267                 return ret;
1268         }
1269         RETURN(-1, uvc_error_t);
1270 }
1271
1272 uvc_error_t uvc_set_hue(uvc_device_handle_t *devh, short hue) {
1273         uint8_t data[2];
1274         uvc_error_t ret;
1275
1276         SHORT_TO_SW(hue, data);
1277
1278         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1279                         UVC_PU_HUE_CONTROL << 8,
1280                         devh->info->ctrl_if.processing_unit_descs->request,
1281                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1282
1283         if (LIKELY(ret == sizeof(data)))
1284                 return UVC_SUCCESS;
1285         else
1286                 return ret;
1287 }
1288
1289 uvc_error_t uvc_get_hue_auto(uvc_device_handle_t *devh, uint8_t *autoHue,
1290                 enum uvc_req_code req_code) {
1291         uint8_t data[1];
1292         uvc_error_t ret;
1293
1294         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1295                         UVC_PU_HUE_AUTO_CONTROL << 8,
1296                         devh->info->ctrl_if.processing_unit_descs->request,
1297                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1298
1299         if (LIKELY(ret == sizeof(data))) {
1300                 *autoHue = data[0];
1301                 return UVC_SUCCESS;
1302         } else {
1303                 return ret;
1304         }
1305         RETURN(-1, uvc_error_t);
1306 }
1307
1308 uvc_error_t uvc_set_hue_auto(uvc_device_handle_t *devh, uint8_t autoHue) {
1309         uint8_t data[1];
1310         uvc_error_t ret;
1311
1312         data[0] = autoHue ? 1 : 0;
1313
1314         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1315                         UVC_PU_HUE_AUTO_CONTROL << 8,
1316                         devh->info->ctrl_if.processing_unit_descs->request,
1317                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1318
1319         if (LIKELY(ret == sizeof(data)))
1320                 return UVC_SUCCESS;
1321         else
1322                 return ret;
1323 }
1324
1325 uvc_error_t uvc_get_saturation(uvc_device_handle_t *devh, uint16_t *saturation,
1326                 enum uvc_req_code req_code) {
1327         uint8_t data[2];
1328         uvc_error_t ret;
1329
1330         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1331                         UVC_PU_SATURATION_CONTROL << 8,
1332                         devh->info->ctrl_if.processing_unit_descs->request,
1333                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1334
1335         if (LIKELY(ret == sizeof(data))) {
1336                 *saturation = SW_TO_SHORT(data);
1337                 return UVC_SUCCESS;
1338         } else {
1339                 return ret;
1340         }
1341         RETURN(-1, uvc_error_t);
1342 }
1343
1344 uvc_error_t uvc_set_saturation(uvc_device_handle_t *devh, uint16_t saturation) {
1345         uint8_t data[2];
1346         uvc_error_t ret;
1347
1348         SHORT_TO_SW(saturation, data);
1349
1350         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1351                         UVC_PU_SATURATION_CONTROL << 8,
1352                         devh->info->ctrl_if.processing_unit_descs->request,
1353                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1354
1355         if (LIKELY(ret == sizeof(data)))
1356                 return UVC_SUCCESS;
1357         else
1358                 return ret;
1359 }
1360
1361 uvc_error_t uvc_get_sharpness(uvc_device_handle_t *devh, uint16_t *sharpness,
1362                 enum uvc_req_code req_code) {
1363         uint8_t data[2];
1364         uvc_error_t ret;
1365
1366         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1367                         UVC_PU_SHARPNESS_CONTROL << 8,
1368                         devh->info->ctrl_if.processing_unit_descs->request,
1369                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1370
1371         if (LIKELY(ret == sizeof(data))) {
1372                 *sharpness = SW_TO_SHORT(data);
1373                 return UVC_SUCCESS;
1374         } else {
1375                 return ret;
1376         }
1377         RETURN(-1, uvc_error_t);
1378 }
1379
1380 uvc_error_t uvc_set_sharpness(uvc_device_handle_t *devh, uint16_t sharpness) {
1381         uint8_t data[2];
1382         uvc_error_t ret;
1383
1384         SHORT_TO_SW(sharpness, data);
1385
1386         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1387                         UVC_PU_SHARPNESS_CONTROL << 8,
1388                         devh->info->ctrl_if.processing_unit_descs->request,
1389                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1390
1391         if (LIKELY(ret == sizeof(data)))
1392                 return UVC_SUCCESS;
1393         else
1394                 return ret;
1395 }
1396
1397 uvc_error_t uvc_get_gamma(uvc_device_handle_t *devh, uint16_t *gamma,
1398                 enum uvc_req_code req_code) {
1399         uint8_t data[2];
1400         uvc_error_t ret;
1401
1402         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1403                         UVC_PU_GAMMA_CONTROL << 8,
1404                         devh->info->ctrl_if.processing_unit_descs->request,
1405                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1406
1407         if (LIKELY(ret == sizeof(data))) {
1408                 *gamma = SW_TO_SHORT(data);
1409                 return UVC_SUCCESS;
1410         } else {
1411                 return ret;
1412         }
1413         RETURN(-1, uvc_error_t);
1414 }
1415
1416 uvc_error_t uvc_set_gamma(uvc_device_handle_t *devh, uint16_t gamma) {
1417         uint8_t data[2];
1418         uvc_error_t ret;
1419
1420         SHORT_TO_SW(gamma, data);
1421
1422         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1423                         UVC_PU_GAMMA_CONTROL << 8,
1424                         devh->info->ctrl_if.processing_unit_descs->request,
1425                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1426
1427         if (LIKELY(ret == sizeof(data)))
1428                 return UVC_SUCCESS;
1429         else
1430                 return ret;
1431 }
1432
1433 uvc_error_t uvc_get_white_balance_temperature(uvc_device_handle_t *devh, uint16_t *wb_temperature,
1434                 enum uvc_req_code req_code) {
1435         uint8_t data[2];
1436         uvc_error_t ret;
1437
1438         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1439                         UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL << 8,
1440                         devh->info->ctrl_if.processing_unit_descs->request,
1441                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1442
1443         if (LIKELY(ret == sizeof(data))) {
1444                 *wb_temperature = SW_TO_SHORT(data);
1445                 return UVC_SUCCESS;
1446         } else {
1447                 return ret;
1448         }
1449         RETURN(-1, uvc_error_t);
1450 }
1451
1452 uvc_error_t uvc_set_white_balance_temperature(uvc_device_handle_t *devh, uint16_t wb_temperature) {
1453         uint8_t data[2];
1454         uvc_error_t ret;
1455
1456         SHORT_TO_SW(wb_temperature, data);
1457
1458         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1459                         UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL << 8,
1460                         devh->info->ctrl_if.processing_unit_descs->request,
1461                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1462
1463         if (LIKELY(ret == sizeof(data)))
1464                 return UVC_SUCCESS;
1465         else
1466                 return ret;
1467 }
1468
1469 uvc_error_t uvc_get_white_balance_temperature_auto(uvc_device_handle_t *devh, uint8_t *autoWbTemp,
1470                 enum uvc_req_code req_code) {
1471         uint8_t data[1];
1472         uvc_error_t ret;
1473
1474         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1475                         UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL << 8,
1476                         devh->info->ctrl_if.processing_unit_descs->request,
1477                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1478
1479         if (LIKELY(ret == sizeof(data))) {
1480                 *autoWbTemp = data[0];
1481                 return UVC_SUCCESS;
1482         } else {
1483                 return ret;
1484         }
1485         RETURN(-1, uvc_error_t);
1486 }
1487
1488 uvc_error_t uvc_set_white_balance_temperature_auto(uvc_device_handle_t *devh, uint8_t autoWbTemp) {
1489         uint8_t data[1];
1490         uvc_error_t ret;
1491
1492         data[0] = autoWbTemp ? 1 : 0;
1493
1494         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1495                         UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL << 8,
1496                         devh->info->ctrl_if.processing_unit_descs->request,
1497                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1498
1499         if (LIKELY(ret == sizeof(data)))
1500                 return UVC_SUCCESS;
1501         else
1502                 return ret;
1503 }
1504
1505 uvc_error_t uvc_get_white_balance_component(uvc_device_handle_t *devh, uint32_t *wb_compo,
1506                 enum uvc_req_code req_code) {
1507         uint8_t data[4];
1508         uvc_error_t ret;
1509
1510         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1511                         UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL << 8,
1512                         devh->info->ctrl_if.processing_unit_descs->request,
1513                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1514
1515         if (LIKELY(ret == sizeof(data))) {
1516                 *wb_compo = DW_TO_INT(data);
1517                 return UVC_SUCCESS;
1518         } else {
1519                 return ret;
1520         }
1521         RETURN(-1, uvc_error_t);
1522 }
1523
1524 uvc_error_t uvc_set_white_balance_component(uvc_device_handle_t *devh, uint32_t wb_compo) {
1525         uint8_t data[4];
1526         uvc_error_t ret;
1527
1528         INT_TO_DW(wb_compo, data);
1529
1530         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1531                         UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL << 8,
1532                         devh->info->ctrl_if.processing_unit_descs->request,
1533                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1534
1535         if (LIKELY(ret == sizeof(data)))
1536                 return UVC_SUCCESS;
1537         else
1538                 return ret;
1539 }
1540
1541 uvc_error_t uvc_get_white_balance_component_auto(uvc_device_handle_t *devh, uint8_t *autoWbCompo,
1542                 enum uvc_req_code req_code) {
1543         uint8_t data[1];
1544         uvc_error_t ret;
1545
1546         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1547                         UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL << 8,
1548                         devh->info->ctrl_if.processing_unit_descs->request,
1549                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1550
1551         if (LIKELY(ret == sizeof(data))) {
1552                 *autoWbCompo = data[0];
1553                 return UVC_SUCCESS;
1554         } else {
1555                 return ret;
1556         }
1557         RETURN(-1, uvc_error_t);
1558 }
1559
1560 uvc_error_t uvc_set_white_balance_component_auto(uvc_device_handle_t *devh, uint8_t autoWbCompo) {
1561         uint8_t data[1];
1562         uvc_error_t ret;
1563
1564         data[0] = autoWbCompo ? 1 : 0;
1565
1566         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1567                         UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL << 8,
1568                         devh->info->ctrl_if.processing_unit_descs->request,
1569                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1570
1571         if (LIKELY(ret == sizeof(data)))
1572                 return UVC_SUCCESS;
1573         else
1574                 return ret;
1575 }
1576
1577 uvc_error_t uvc_get_digital_multiplier(uvc_device_handle_t *devh, uint16_t *multiplier,
1578                 enum uvc_req_code req_code) {
1579         uint8_t data[2];
1580         uvc_error_t ret;
1581
1582         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1583                         UVC_PU_DIGITAL_MULTIPLIER_CONTROL << 8,
1584                         devh->info->ctrl_if.processing_unit_descs->request,
1585                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1586
1587         if (LIKELY(ret == sizeof(data))) {
1588                 *multiplier = SW_TO_SHORT(data);
1589                 return UVC_SUCCESS;
1590         } else {
1591                 return ret;
1592         }
1593         RETURN(-1, uvc_error_t);
1594 }
1595
1596 uvc_error_t uvc_set_digital_multiplier(uvc_device_handle_t *devh, uint16_t multiplier) {
1597         uint8_t data[2];
1598         uvc_error_t ret;
1599
1600         SHORT_TO_SW(multiplier, data);
1601
1602         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1603                         UVC_PU_DIGITAL_MULTIPLIER_CONTROL << 8,
1604                         devh->info->ctrl_if.processing_unit_descs->request,
1605                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1606
1607         if (LIKELY(ret == sizeof(data)))
1608                 return UVC_SUCCESS;
1609         else
1610                 return ret;
1611 }
1612
1613 uvc_error_t uvc_get_digital_multiplier_limit(uvc_device_handle_t *devh, uint16_t *limit,
1614                 enum uvc_req_code req_code) {
1615         uint8_t data[2];
1616         uvc_error_t ret;
1617
1618         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1619                         UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL << 8,
1620                         devh->info->ctrl_if.processing_unit_descs->request,
1621                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1622
1623         if (LIKELY(ret == sizeof(data))) {
1624                 *limit = SW_TO_SHORT(data);
1625                 return UVC_SUCCESS;
1626         } else {
1627                 return ret;
1628         }
1629         RETURN(-1, uvc_error_t);
1630 }
1631
1632 uvc_error_t uvc_set_digital_multiplier_limit(uvc_device_handle_t *devh, uint16_t limit) {
1633         uint8_t data[2];
1634         uvc_error_t ret;
1635
1636         SHORT_TO_SW(limit, data);
1637
1638         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1639                         UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL << 8,
1640                         devh->info->ctrl_if.processing_unit_descs->request,
1641                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1642
1643         if (LIKELY(ret == sizeof(data)))
1644                 return UVC_SUCCESS;
1645         else
1646                 return ret;
1647 }
1648
1649 uvc_error_t uvc_get_analog_video_standard(uvc_device_handle_t *devh, uint8_t *standard,
1650                 enum uvc_req_code req_code) {
1651         uint8_t data[1];
1652         uvc_error_t ret;
1653
1654         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1655                         UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL << 8,
1656                         devh->info->ctrl_if.processing_unit_descs->request,
1657                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1658
1659         if (LIKELY(ret == sizeof(data))) {
1660                 *standard = data[0];
1661                 return UVC_SUCCESS;
1662         } else {
1663                 return ret;
1664         }
1665         RETURN(-1, uvc_error_t);
1666 }
1667
1668 uvc_error_t uvc_set_analog_video_standard(uvc_device_handle_t *devh, uint8_t standard) {
1669         uint8_t data[1];
1670         uvc_error_t ret;
1671
1672         data[0] = standard;
1673
1674         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1675                         UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL << 8,
1676                         devh->info->ctrl_if.processing_unit_descs->request,
1677                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1678
1679         if (LIKELY(ret == sizeof(data)))
1680                 return UVC_SUCCESS;
1681         else
1682                 return ret;
1683 }
1684
1685 uvc_error_t uvc_get_analog_video_lockstate(uvc_device_handle_t *devh, uint8_t *lock_state,
1686                 enum uvc_req_code req_code) {
1687         uint8_t data[1];
1688         uvc_error_t ret;
1689
1690         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_GET, req_code,
1691                         UVC_PU_ANALOG_LOCK_STATUS_CONTROL << 8,
1692                         devh->info->ctrl_if.processing_unit_descs->request,
1693                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1694
1695         if (LIKELY(ret == sizeof(data))) {
1696                 *lock_state = data[0];
1697                 return UVC_SUCCESS;
1698         } else {
1699                 return ret;
1700         }
1701         RETURN(-1, uvc_error_t);
1702 }
1703
1704 uvc_error_t uvc_set_analog_video_lockstate(uvc_device_handle_t *devh, uint8_t lock_state) {
1705         uint8_t data[1];
1706         uvc_error_t ret;
1707
1708         data[0] = lock_state;
1709
1710         ret = libusb_control_transfer(devh->usb_devh, REQ_TYPE_SET, UVC_SET_CUR,
1711                         UVC_PU_ANALOG_LOCK_STATUS_CONTROL << 8,
1712                         devh->info->ctrl_if.processing_unit_descs->request,
1713                         data, sizeof(data), CTRL_TIMEOUT_MILLIS);
1714
1715         if (LIKELY(ret == sizeof(data)))
1716                 return UVC_SUCCESS;
1717         else
1718                 return ret;
1719 }