1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#ifdef __KERNEL__
30#include <asm/uaccess.h>
31#endif
32#include <asm/errno.h>
33
34#include "pwc.h"
35#include "pwc-ioctl.h"
36#include "pwc-uncompress.h"
37
38
39#define SET_LUM_CTL 0x01
40#define GET_LUM_CTL 0x02
41#define SET_CHROM_CTL 0x03
42#define GET_CHROM_CTL 0x04
43#define SET_STATUS_CTL 0x05
44#define GET_STATUS_CTL 0x06
45#define SET_EP_STREAM_CTL 0x07
46#define GET_EP_STREAM_CTL 0x08
47
48
49#define AGC_MODE_FORMATTER 0x2000
50#define PRESET_AGC_FORMATTER 0x2100
51#define SHUTTER_MODE_FORMATTER 0x2200
52#define PRESET_SHUTTER_FORMATTER 0x2300
53#define PRESET_CONTOUR_FORMATTER 0x2400
54#define AUTO_CONTOUR_FORMATTER 0x2500
55#define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600
56#define CONTRAST_FORMATTER 0x2700
57#define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800
58#define FLICKERLESS_MODE_FORMATTER 0x2900
59#define AE_CONTROL_SPEED 0x2A00
60#define BRIGHTNESS_FORMATTER 0x2B00
61#define GAMMA_FORMATTER 0x2C00
62
63
64#define WB_MODE_FORMATTER 0x1000
65#define AWB_CONTROL_SPEED_FORMATTER 0x1100
66#define AWB_CONTROL_DELAY_FORMATTER 0x1200
67#define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300
68#define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400
69#define COLOUR_MODE_FORMATTER 0x1500
70#define SATURATION_MODE_FORMATTER1 0x1600
71#define SATURATION_MODE_FORMATTER2 0x1700
72
73
74#define SAVE_USER_DEFAULTS_FORMATTER 0x0200
75#define RESTORE_USER_DEFAULTS_FORMATTER 0x0300
76#define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400
77#define READ_AGC_FORMATTER 0x0500
78#define READ_SHUTTER_FORMATTER 0x0600
79#define READ_RED_GAIN_FORMATTER 0x0700
80#define READ_BLUE_GAIN_FORMATTER 0x0800
81#define SENSOR_TYPE_FORMATTER1 0x0C00
82#define READ_RAW_Y_MEAN_FORMATTER 0x3100
83#define SET_POWER_SAVE_MODE_FORMATTER 0x3200
84#define MIRROR_IMAGE_FORMATTER 0x3300
85#define LED_FORMATTER 0x3400
86#define SENSOR_TYPE_FORMATTER2 0x3700
87
88
89#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100
90
91static char *size2name[PSZ_MAX] =
92{
93 "subQCIF",
94 "QSIF",
95 "QCIF",
96 "SIF",
97 "CIF",
98 "VGA",
99};
100
101
102
103
104
105
106
107
108
109struct Nala_table_entry {
110 char alternate;
111 int compressed;
112
113 unsigned char mode[3];
114};
115
116static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
117{
118#include "pwc_nala.h"
119};
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135struct Timon_table_entry
136{
137 char alternate;
138 unsigned short packetsize;
139 unsigned short bandlength;
140 unsigned char mode[13];
141};
142
143static struct Timon_table_entry Timon_table[PSZ_MAX][6][4] =
144{
145#include "pwc_timon.h"
146};
147
148
149
150struct Kiara_table_entry
151{
152 char alternate;
153 unsigned short packetsize;
154 unsigned short bandlength;
155 unsigned char mode[12];
156};
157
158static struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] =
159{
160#include "pwc_kiara.h"
161};
162
163
164
165
166
167#define SendControlMsg(request, value, buflen) \
168 usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \
169 request, \
170 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
171 value, \
172 pdev->vcinterface, \
173 &buf, buflen, HZ / 2)
174
175#define RecvControlMsg(request, value, buflen) \
176 usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \
177 request, \
178 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \
179 value, \
180 pdev->vcinterface, \
181 &buf, buflen, HZ / 2)
182
183
184#if PWC_DEBUG
185void pwc_hexdump(void *p, int len)
186{
187 int i;
188 unsigned char *s;
189 char buf[100], *d;
190
191 s = (unsigned char *)p;
192 d = buf;
193 *d = '\0';
194 Debug("Doing hexdump @ %p, %d bytes.\n", p, len);
195 for (i = 0; i < len; i++) {
196 d += sprintf(d, "%02X ", *s++);
197 if ((i & 0xF) == 0xF) {
198 Debug("%s\n", buf);
199 d = buf;
200 *d = '\0';
201 }
202 }
203 if ((i & 0xF) != 0)
204 Debug("%s\n", buf);
205}
206#endif
207
208static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
209{
210 return usb_control_msg(udev,
211 usb_sndctrlpipe(udev, 0),
212 SET_EP_STREAM_CTL,
213 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
214 VIDEO_OUTPUT_CONTROL_FORMATTER,
215 index,
216 buf, buflen, HZ);
217}
218
219
220
221static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
222{
223 unsigned char buf[3];
224 int ret, fps;
225 struct Nala_table_entry *pEntry;
226 int frames2frames[31] =
227 {
228 0, 0, 0, 0, 4,
229 5, 5, 7, 7, 10,
230 10, 10, 12, 12, 15,
231 15, 15, 15, 20, 20,
232 20, 20, 20, 24, 24,
233 24, 24, 24, 24, 24,
234 24
235 };
236 int frames2table[31] =
237 { 0, 0, 0, 0, 0,
238 1, 1, 1, 2, 2,
239 3, 3, 4, 4, 4,
240 5, 5, 5, 5, 5,
241 6, 6, 6, 6, 7,
242 7, 7, 7, 7, 7,
243 7
244 };
245
246 if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25)
247 return -EINVAL;
248 frames = frames2frames[frames];
249 fps = frames2table[frames];
250 pEntry = &Nala_table[size][fps];
251 if (pEntry->alternate == 0)
252 return -EINVAL;
253
254 if (pEntry->compressed && pdev->decompressor == NULL)
255 return -ENOENT;
256
257 memcpy(buf, pEntry->mode, 3);
258 ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
259 if (ret < 0) {
260 Debug("Failed to send video command... %d\n", ret);
261 return ret;
262 }
263 if (pEntry->compressed && pdev->decompressor != NULL)
264 pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
265
266
267 pdev->vframes = frames;
268 pdev->vsize = size;
269 pdev->valternate = pEntry->alternate;
270 pdev->image = pwc_image_sizes[size];
271 pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
272 if (pEntry->compressed) {
273 if (pdev->release < 5) {
274 pdev->vbandlength = 528;
275 pdev->frame_size /= 4;
276 }
277 else {
278 pdev->vbandlength = 704;
279 pdev->frame_size /= 3;
280 }
281 }
282 else
283 pdev->vbandlength = 0;
284 return 0;
285}
286
287
288static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
289{
290 unsigned char buf[13];
291 struct Timon_table_entry *pChoose;
292 int ret, fps;
293
294 if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
295 return -EINVAL;
296 if (size == PSZ_VGA && frames > 15)
297 return -EINVAL;
298 fps = (frames / 5) - 1;
299
300
301
302
303 pChoose = NULL;
304 if (pdev->decompressor == NULL) {
305#if PWC_DEBUG
306 Debug("Trying to find uncompressed mode.\n");
307#endif
308 pChoose = &Timon_table[size][fps][0];
309 }
310 else {
311 while (compression <= 3) {
312 pChoose = &Timon_table[size][fps][compression];
313 if (pChoose->alternate != 0)
314 break;
315 compression++;
316 }
317 }
318 if (pChoose == NULL || pChoose->alternate == 0)
319 return -ENOENT;
320
321 memcpy(buf, pChoose->mode, 13);
322 if (snapshot)
323 buf[0] |= 0x80;
324 ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13);
325 if (ret < 0)
326 return ret;
327
328 if (pChoose->bandlength > 0)
329 pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
330
331
332 pdev->vframes = frames;
333 pdev->vsize = size;
334 pdev->vsnapshot = snapshot;
335 pdev->valternate = pChoose->alternate;
336 pdev->image = pwc_image_sizes[size];
337 pdev->vbandlength = pChoose->bandlength;
338 if (pChoose->bandlength > 0)
339 pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
340 else
341 pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
342 return 0;
343}
344
345
346static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
347{
348 struct Kiara_table_entry *pChoose;
349 int fps, ret;
350 unsigned char buf[12];
351
352 if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
353 return -EINVAL;
354 if (size == PSZ_VGA && frames > 15)
355 return -EINVAL;
356 fps = (frames / 5) - 1;
357
358
359
360
361 pChoose = NULL;
362 if (pdev->decompressor == NULL) {
363#if PWC_DEBUG
364 Debug("Trying to find uncompressed mode.\n");
365#endif
366 pChoose = &Kiara_table[size][fps][0];
367 }
368 else {
369 while (compression <= 3) {
370 pChoose = &Kiara_table[size][fps][compression];
371 if (pChoose->alternate != 0)
372 break;
373 compression++;
374 }
375 }
376 if (pChoose == NULL || pChoose->alternate == 0)
377 return -ENOENT;
378
379
380 memcpy(buf, pChoose->mode, 12);
381 if (snapshot)
382 buf[0] |= 0x80;
383
384
385 ret = send_video_command(pdev->udev, 4 , buf, 12);
386 if (ret < 0)
387 return ret;
388
389 if (pChoose->bandlength > 0)
390 pdev->decompressor->init(pdev->release, buf, pdev->decompress_data);
391
392
393 pdev->vframes = frames;
394 pdev->vsize = size;
395 pdev->vsnapshot = snapshot;
396 pdev->valternate = pChoose->alternate;
397 pdev->image = pwc_image_sizes[size];
398 pdev->vbandlength = pChoose->bandlength;
399 if (pChoose->bandlength > 0)
400 pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
401 else
402 pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
403 pdev->frame_size += (pdev->frame_header_size + pdev->frame_trailer_size);
404 return 0;
405}
406
407
408
409
410
411
412
413
414
415
416int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot)
417{
418 int ret, size;
419
420 size = pwc_decode_size(pdev, width, height);
421 if (size < 0) {
422 Debug("Could not find suitable size.\n");
423 return -ERANGE;
424 }
425 ret = -EINVAL;
426 switch(pdev->type) {
427 case 645:
428 case 646:
429 ret = set_video_mode_Nala(pdev, size, frames);
430 break;
431
432 case 675:
433 case 680:
434 case 690:
435 ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
436 break;
437
438 case 730:
439 case 740:
440 case 750:
441 ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
442 break;
443 }
444 if (ret < 0) {
445 if (ret == -ENOENT)
446 Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
447 else {
448 Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
449 }
450 return ret;
451 }
452 pdev->view.x = width;
453 pdev->view.y = height;
454 pwc_set_image_buffer_size(pdev);
455 Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
456 return 0;
457}
458
459
460void pwc_set_image_buffer_size(struct pwc_device *pdev)
461{
462 int factor, i, filler = 0;
463
464
465 factor = 6;
466 filler = 128;
467
468
469 pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
470 pdev->view.size = pdev->view.x * pdev->view.y * factor / 4;
471
472
473
474
475
476
477 pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
478 pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
479
480
481 for (i = 0; i < MAX_IMAGES; i++) {
482 if (pdev->image_ptr[i] != NULL)
483 memset(pdev->image_ptr[i], filler, pdev->view.size);
484 }
485}
486
487
488
489
490
491int pwc_get_brightness(struct pwc_device *pdev)
492{
493 char buf;
494 int ret;
495
496 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
497 GET_LUM_CTL,
498 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
499 BRIGHTNESS_FORMATTER,
500 pdev->vcinterface,
501 &buf, 1, HZ / 2);
502 if (ret < 0)
503 return ret;
504 return buf << 9;
505}
506
507int pwc_set_brightness(struct pwc_device *pdev, int value)
508{
509 char buf;
510
511 if (value < 0)
512 value = 0;
513 if (value > 0xffff)
514 value = 0xffff;
515 buf = (value >> 9) & 0x7f;
516 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
517 SET_LUM_CTL,
518 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
519 BRIGHTNESS_FORMATTER,
520 pdev->vcinterface,
521 &buf, 1, HZ / 2);
522}
523
524
525
526int pwc_get_contrast(struct pwc_device *pdev)
527{
528 char buf;
529 int ret;
530
531 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
532 GET_LUM_CTL,
533 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
534 CONTRAST_FORMATTER,
535 pdev->vcinterface,
536 &buf, 1, HZ / 2);
537 if (ret < 0)
538 return ret;
539 return buf << 10;
540}
541
542int pwc_set_contrast(struct pwc_device *pdev, int value)
543{
544 char buf;
545
546 if (value < 0)
547 value = 0;
548 if (value > 0xffff)
549 value = 0xffff;
550 buf = (value >> 10) & 0x3f;
551 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
552 SET_LUM_CTL,
553 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
554 CONTRAST_FORMATTER,
555 pdev->vcinterface,
556 &buf, 1, HZ / 2);
557}
558
559
560
561int pwc_get_gamma(struct pwc_device *pdev)
562{
563 char buf;
564 int ret;
565
566 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
567 GET_LUM_CTL,
568 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
569 GAMMA_FORMATTER,
570 pdev->vcinterface,
571 &buf, 1, HZ / 2);
572 if (ret < 0)
573 return ret;
574 return buf << 11;
575}
576
577int pwc_set_gamma(struct pwc_device *pdev, int value)
578{
579 char buf;
580
581 if (value < 0)
582 value = 0;
583 if (value > 0xffff)
584 value = 0xffff;
585 buf = (value >> 11) & 0x1f;
586 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
587 SET_LUM_CTL,
588 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
589 GAMMA_FORMATTER,
590 pdev->vcinterface,
591 &buf, 1, HZ / 2);
592}
593
594
595
596
597int pwc_get_saturation(struct pwc_device *pdev)
598{
599 char buf;
600 int ret;
601
602 if (pdev->type < 675)
603 return -1;
604 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
605 GET_CHROM_CTL,
606 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
607 pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1,
608 pdev->vcinterface,
609 &buf, 1, HZ / 2);
610 if (ret < 0)
611 return ret;
612 return 32768 + buf * 327;
613}
614
615int pwc_set_saturation(struct pwc_device *pdev, int value)
616{
617 char buf;
618
619 if (pdev->type < 675)
620 return -EINVAL;
621 if (value < 0)
622 value = 0;
623 if (value > 0xffff)
624 value = 0xffff;
625
626 buf = (value - 32768) / 327;
627 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
628 SET_CHROM_CTL,
629 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
630 pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1,
631 pdev->vcinterface,
632 &buf, 1, HZ / 2);
633}
634
635
636
637static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
638{
639 char buf;
640 int ret;
641
642 if (mode)
643 buf = 0x0;
644 else
645 buf = 0xff;
646
647 ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
648 SET_LUM_CTL,
649 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
650 AGC_MODE_FORMATTER,
651 pdev->vcinterface,
652 &buf, 1, HZ / 2);
653
654 if (!mode && ret >= 0) {
655 if (value < 0)
656 value = 0;
657 if (value > 0xffff)
658 value = 0xffff;
659 buf = (value >> 10) & 0x3F;
660 ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
661 SET_LUM_CTL,
662 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
663 PRESET_AGC_FORMATTER,
664 pdev->vcinterface,
665 &buf, 1, HZ / 2);
666 }
667 if (ret < 0)
668 return ret;
669 return 0;
670}
671
672static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
673{
674 unsigned char buf;
675 int ret;
676
677 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
678 GET_LUM_CTL,
679 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
680 AGC_MODE_FORMATTER,
681 pdev->vcinterface,
682 &buf, 1, HZ / 2);
683 if (ret < 0)
684 return ret;
685
686 if (buf != 0) {
687 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
688 GET_LUM_CTL,
689 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
690 PRESET_AGC_FORMATTER,
691 pdev->vcinterface,
692 &buf, 1, HZ / 2);
693 if (ret < 0)
694 return ret;
695 if (buf > 0x3F)
696 buf = 0x3F;
697 *value = (buf << 10);
698 }
699 else {
700 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
701 GET_STATUS_CTL,
702 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
703 READ_AGC_FORMATTER,
704 pdev->vcinterface,
705 &buf, 1, HZ / 2);
706 if (ret < 0)
707 return ret;
708
709 if (buf > 0x9F)
710 buf = 0x9F;
711 *value = -(48 + buf * 409);
712 }
713
714 return 0;
715}
716
717static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
718{
719 char buf[2];
720 int speed, ret;
721
722
723 if (mode)
724 buf[0] = 0x0;
725 else
726 buf[0] = 0xff;
727
728 ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
729 SET_LUM_CTL,
730 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
731 SHUTTER_MODE_FORMATTER,
732 pdev->vcinterface,
733 buf, 1, HZ / 2);
734
735 if (!mode && ret >= 0) {
736 if (value < 0)
737 value = 0;
738 if (value > 0xffff)
739 value = 0xffff;
740 switch(pdev->type) {
741 case 675:
742 case 680:
743 case 690:
744
745 speed = (value / 100);
746 buf[1] = speed >> 8;
747 buf[0] = speed & 0xff;
748 break;
749 case 730:
750 case 740:
751 case 750:
752
753 buf[1] = 0;
754 buf[0] = value >> 8;
755 break;
756 }
757
758 ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
759 SET_LUM_CTL,
760 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
761 PRESET_SHUTTER_FORMATTER,
762 pdev->vcinterface,
763 &buf, 2, HZ / 2);
764 }
765 return ret;
766}
767
768
769
770
771int pwc_camera_power(struct pwc_device *pdev, int power)
772{
773 char buf;
774
775 if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
776 return 0;
777
778 if (power)
779 buf = 0x00;
780 else
781 buf = 0xFF;
782 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
783 SET_STATUS_CTL,
784 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
785 SET_POWER_SAVE_MODE_FORMATTER,
786 pdev->vcinterface,
787 &buf, 1, HZ / 2);
788}
789
790
791
792
793
794static inline int pwc_restore_user(struct pwc_device *pdev)
795{
796 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
797 SET_STATUS_CTL,
798 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
799 RESTORE_USER_DEFAULTS_FORMATTER,
800 pdev->vcinterface,
801 NULL, 0, HZ / 2);
802}
803
804static inline int pwc_save_user(struct pwc_device *pdev)
805{
806 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
807 SET_STATUS_CTL,
808 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
809 SAVE_USER_DEFAULTS_FORMATTER,
810 pdev->vcinterface,
811 NULL, 0, HZ / 2);
812}
813
814static inline int pwc_restore_factory(struct pwc_device *pdev)
815{
816 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
817 SET_STATUS_CTL,
818 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
819 RESTORE_FACTORY_DEFAULTS_FORMATTER,
820 pdev->vcinterface,
821 NULL, 0, HZ / 2);
822}
823
824
825
826
827
828
829
830
831
832
833
834
835
836static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
837{
838 char buf;
839 int ret;
840
841 if (mode < 0)
842 mode = 0;
843
844 if (mode > 4)
845 mode = 4;
846
847 buf = mode & 0x07;
848
849 ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
850 SET_CHROM_CTL,
851 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
852 WB_MODE_FORMATTER,
853 pdev->vcinterface,
854 &buf, 1, HZ / 2);
855
856 if (ret < 0)
857 return ret;
858 return 0;
859}
860
861static inline int pwc_get_awb(struct pwc_device *pdev)
862{
863 unsigned char buf;
864 int ret;
865
866 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
867 GET_CHROM_CTL,
868 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
869 WB_MODE_FORMATTER,
870 pdev->vcinterface,
871 &buf, 1, HZ / 2);
872
873 if (ret < 0)
874 return ret;
875 return buf;
876}
877
878static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
879{
880 unsigned char buf;
881
882 if (value < 0)
883 value = 0;
884 if (value > 0xffff)
885 value = 0xffff;
886
887
888 buf = value >> 8;
889
890 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
891 SET_CHROM_CTL,
892 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
893 PRESET_MANUAL_RED_GAIN_FORMATTER,
894 pdev->vcinterface,
895 &buf, 1, HZ / 2);
896}
897
898static inline int pwc_get_red_gain(struct pwc_device *pdev)
899{
900 unsigned char buf;
901 int ret;
902
903 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
904 GET_CHROM_CTL,
905 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
906 PRESET_MANUAL_RED_GAIN_FORMATTER,
907 pdev->vcinterface,
908 &buf, 1, HZ / 2);
909
910 if (ret < 0)
911 return ret;
912
913 return (buf << 8);
914}
915
916
917static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
918{
919 unsigned char buf;
920
921 if (value < 0)
922 value = 0;
923 if (value > 0xffff)
924 value = 0xffff;
925
926
927 buf = (value >> 8);
928
929 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
930 SET_CHROM_CTL,
931 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
932 PRESET_MANUAL_BLUE_GAIN_FORMATTER,
933 pdev->vcinterface,
934 &buf, 1, HZ / 2);
935}
936
937static inline int pwc_get_blue_gain(struct pwc_device *pdev)
938{
939 unsigned char buf;
940 int ret;
941
942 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
943 GET_CHROM_CTL,
944 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
945 PRESET_MANUAL_BLUE_GAIN_FORMATTER,
946 pdev->vcinterface,
947 &buf, 1, HZ / 2);
948
949 if (ret < 0)
950 return ret;
951
952 return (buf << 8);
953}
954
955
956
957
958
959
960static inline int pwc_read_red_gain(struct pwc_device *pdev)
961{
962 unsigned char buf;
963 int ret;
964
965 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
966 GET_STATUS_CTL,
967 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
968 READ_RED_GAIN_FORMATTER,
969 pdev->vcinterface,
970 &buf, 1, HZ / 2);
971
972 if (ret < 0)
973 return ret;
974
975 return (buf << 8);
976}
977
978static inline int pwc_read_blue_gain(struct pwc_device *pdev)
979{
980 unsigned char buf;
981 int ret;
982
983 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
984 GET_STATUS_CTL,
985 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
986 READ_BLUE_GAIN_FORMATTER,
987 pdev->vcinterface,
988 &buf, 1, HZ / 2);
989
990 if (ret < 0)
991 return ret;
992
993 return (buf << 8);
994}
995
996
997static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
998{
999 unsigned char buf;
1000
1001
1002 buf = speed / 0x7f0;
1003 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1004 SET_CHROM_CTL,
1005 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1006 AWB_CONTROL_SPEED_FORMATTER,
1007 pdev->vcinterface,
1008 &buf, 1, HZ / 2);
1009}
1010
1011static inline int pwc_get_wb_speed(struct pwc_device *pdev)
1012{
1013 unsigned char buf;
1014 int ret;
1015
1016 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1017 GET_CHROM_CTL,
1018 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1019 AWB_CONTROL_SPEED_FORMATTER,
1020 pdev->vcinterface,
1021 &buf, 1, HZ / 2);
1022 if (ret < 0)
1023 return ret;
1024 return (buf * 0x7f0);
1025}
1026
1027
1028static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
1029{
1030 unsigned char buf;
1031
1032
1033 buf = (delay >> 10);
1034 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1035 SET_CHROM_CTL,
1036 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1037 AWB_CONTROL_DELAY_FORMATTER,
1038 pdev->vcinterface,
1039 &buf, 1, HZ / 2);
1040}
1041
1042static inline int pwc_get_wb_delay(struct pwc_device *pdev)
1043{
1044 unsigned char buf;
1045 int ret;
1046
1047 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1048 GET_CHROM_CTL,
1049 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1050 AWB_CONTROL_DELAY_FORMATTER,
1051 pdev->vcinterface,
1052 &buf, 1, HZ / 2);
1053 if (ret < 0)
1054 return ret;
1055 return (buf << 10);
1056}
1057
1058
1059int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
1060{
1061 unsigned char buf[2];
1062
1063 if (pdev->type < 730)
1064 return 0;
1065 on_value /= 100;
1066 off_value /= 100;
1067 if (on_value < 0)
1068 on_value = 0;
1069 if (on_value > 0xff)
1070 on_value = 0xff;
1071 if (off_value < 0)
1072 off_value = 0;
1073 if (off_value > 0xff)
1074 off_value = 0xff;
1075
1076 buf[0] = on_value;
1077 buf[1] = off_value;
1078
1079 return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2);
1080}
1081
1082int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
1083{
1084 unsigned char buf[2];
1085 int ret;
1086
1087 if (pdev->type < 730) {
1088 *on_value = -1;
1089 *off_value = -1;
1090 return 0;
1091 }
1092
1093 ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2);
1094 if (ret < 0)
1095 return ret;
1096 *on_value = buf[0] * 100;
1097 *off_value = buf[1] * 100;
1098 return 0;
1099}
1100
1101static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
1102{
1103 unsigned char buf;
1104 int ret;
1105
1106 if (contour < 0)
1107 buf = 0xff;
1108 else
1109 buf = 0x0;
1110 ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1111 SET_LUM_CTL,
1112 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1113 AUTO_CONTOUR_FORMATTER,
1114 pdev->vcinterface,
1115 &buf, 1, HZ / 2);
1116 if (ret < 0)
1117 return ret;
1118
1119 if (contour < 0)
1120 return 0;
1121 if (contour > 0xffff)
1122 contour = 0xffff;
1123
1124 buf = (contour >> 10);
1125 ret = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1126 SET_LUM_CTL,
1127 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1128 PRESET_CONTOUR_FORMATTER,
1129 pdev->vcinterface,
1130 &buf, 1, HZ / 2);
1131 if (ret < 0)
1132 return ret;
1133 return 0;
1134}
1135
1136static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
1137{
1138 unsigned char buf;
1139 int ret;
1140
1141 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1142 GET_LUM_CTL,
1143 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1144 AUTO_CONTOUR_FORMATTER,
1145 pdev->vcinterface,
1146 &buf, 1, HZ / 2);
1147 if (ret < 0)
1148 return ret;
1149
1150 if (buf == 0) {
1151
1152 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1153 GET_LUM_CTL,
1154 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1155 PRESET_CONTOUR_FORMATTER,
1156 pdev->vcinterface,
1157 &buf, 1, HZ / 2);
1158 if (ret < 0)
1159 return ret;
1160 *contour = (buf << 10);
1161 }
1162 else
1163 *contour = -1;
1164 return 0;
1165}
1166
1167
1168static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
1169{
1170 unsigned char buf;
1171
1172 if (backlight)
1173 buf = 0xff;
1174 else
1175 buf = 0x0;
1176 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
1177 SET_LUM_CTL,
1178 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1179 BACK_LIGHT_COMPENSATION_FORMATTER,
1180 pdev->vcinterface,
1181 &buf, 1, HZ / 2);
1182}
1183
1184static inline int pwc_get_backlight(struct pwc_device *pdev)
1185{
1186 int ret;
1187 unsigned char buf;
1188
1189 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1190 GET_LUM_CTL,
1191 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1192 BACK_LIGHT_COMPENSATION_FORMATTER,
1193 pdev->vcinterface,
1194 &buf, 1, HZ / 2);
1195 if (ret < 0)
1196 return ret;
1197 return buf;
1198}
1199
1200
1201static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
1202{
1203 unsigned char buf;
1204
1205 if (flicker)
1206 buf = 0xff;
1207 else
1208 buf = 0x0;
1209 return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
1210}
1211
1212static inline int pwc_get_flicker(struct pwc_device *pdev)
1213{
1214 int ret;
1215 unsigned char buf;
1216
1217 ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
1218 if (ret < 0)
1219 return ret;
1220 return buf;
1221}
1222
1223
1224static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
1225{
1226 unsigned char buf;
1227
1228 if (noise < 0)
1229 noise = 0;
1230 if (noise > 3)
1231 noise = 3;
1232 buf = noise;
1233 return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
1234}
1235
1236static inline int pwc_get_dynamic_noise(struct pwc_device *pdev)
1237{
1238 int ret;
1239 unsigned char buf;
1240
1241 ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
1242 if (ret < 0)
1243 return ret;
1244 return buf;
1245}
1246
1247
1248int pwc_get_cmos_sensor(struct pwc_device *pdev)
1249{
1250 unsigned char buf;
1251 int ret = -1, request;
1252
1253 if (pdev->type < 675)
1254 request = SENSOR_TYPE_FORMATTER1;
1255 else if (pdev->type < 730)
1256 return -1;
1257 else
1258 request = SENSOR_TYPE_FORMATTER2;
1259
1260 ret = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
1261 GET_STATUS_CTL,
1262 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1263 request,
1264 pdev->vcinterface,
1265 &buf, 1, HZ / 2);
1266 if (ret < 0)
1267 return ret;
1268 if (pdev->type < 675)
1269 return buf | 0x100;
1270 else
1271 return buf;
1272}
1273
1274
1275
1276
1277
1278int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
1279{
1280 int ret = 0;
1281
1282 switch(cmd) {
1283 case VIDIOCPWCRUSER:
1284 {
1285 if (pwc_restore_user(pdev))
1286 ret = -EINVAL;
1287 break;
1288 }
1289
1290 case VIDIOCPWCSUSER:
1291 {
1292 if (pwc_save_user(pdev))
1293 ret = -EINVAL;
1294 break;
1295 }
1296
1297 case VIDIOCPWCFACTORY:
1298 {
1299 if (pwc_restore_factory(pdev))
1300 ret = -EINVAL;
1301 break;
1302 }
1303
1304 case VIDIOCPWCSCQUAL:
1305 {
1306 int qual;
1307
1308 if (copy_from_user(&qual, arg, sizeof(int)))
1309 ret = -EFAULT;
1310 else {
1311 if (qual < 0 || qual > 3)
1312 ret = -EINVAL;
1313 else
1314 ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, qual, pdev->vsnapshot);
1315 if (ret >= 0)
1316 pdev->vcompression = qual;
1317 }
1318 break;
1319 }
1320
1321 case VIDIOCPWCGCQUAL:
1322 {
1323 if (copy_to_user(arg, &pdev->vcompression, sizeof(int)))
1324 ret = -EFAULT;
1325 break;
1326 }
1327
1328 case VIDIOCPWCPROBE:
1329 {
1330 struct pwc_probe probe;
1331
1332 strcpy(probe.name, pdev->vdev.name);
1333 probe.type = pdev->type;
1334 if (copy_to_user(arg, &probe, sizeof(probe)))
1335 ret = -EFAULT;
1336 break;
1337 }
1338
1339 case VIDIOCPWCSAGC:
1340 {
1341 int agc;
1342
1343 if (copy_from_user(&agc, arg, sizeof(agc)))
1344 ret = -EFAULT;
1345 else {
1346 if (pwc_set_agc(pdev, agc < 0 ? 1 : 0, agc))
1347 ret = -EINVAL;
1348 }
1349 break;
1350 }
1351
1352 case VIDIOCPWCGAGC:
1353 {
1354 int agc;
1355
1356 if (pwc_get_agc(pdev, &agc))
1357 ret = -EINVAL;
1358 else
1359 if (copy_to_user(arg, &agc, sizeof(agc)))
1360 ret = -EFAULT;
1361 break;
1362 }
1363
1364 case VIDIOCPWCSSHUTTER:
1365 {
1366 int shutter_speed;
1367
1368 if (copy_from_user(&shutter_speed, arg, sizeof(shutter_speed)))
1369 ret = -EFAULT;
1370 else
1371 ret = pwc_set_shutter_speed(pdev, shutter_speed < 0 ? 1 : 0, shutter_speed);
1372 break;
1373 }
1374
1375 case VIDIOCPWCSAWB:
1376 {
1377 struct pwc_whitebalance wb;
1378
1379 if (copy_from_user(&wb, arg, sizeof(wb)))
1380 ret = -EFAULT;
1381 else {
1382 ret = pwc_set_awb(pdev, wb.mode);
1383 if (ret >= 0 && wb.mode == PWC_WB_MANUAL) {
1384 pwc_set_red_gain(pdev, wb.manual_red);
1385 pwc_set_blue_gain(pdev, wb.manual_blue);
1386 }
1387 }
1388 break;
1389 }
1390
1391 case VIDIOCPWCGAWB:
1392 {
1393 struct pwc_whitebalance wb;
1394
1395 memset(&wb, 0, sizeof(wb));
1396 wb.mode = pwc_get_awb(pdev);
1397 if (wb.mode < 0)
1398 ret = -EINVAL;
1399 else {
1400 if (wb.mode == PWC_WB_MANUAL) {
1401 wb.manual_red = pwc_get_red_gain(pdev);
1402 wb.manual_blue = pwc_get_blue_gain(pdev);
1403 }
1404 if (wb.mode == PWC_WB_AUTO) {
1405 wb.read_red = pwc_read_red_gain(pdev);
1406 wb.read_blue = pwc_read_blue_gain(pdev);
1407 }
1408 if (copy_to_user(arg, &wb, sizeof(wb)))
1409 ret= -EFAULT;
1410 }
1411 break;
1412 }
1413
1414 case VIDIOCPWCSAWBSPEED:
1415 {
1416 struct pwc_wb_speed wbs;
1417
1418 if (copy_from_user(&wbs, arg, sizeof(wbs)))
1419 ret = -EFAULT;
1420 else {
1421 if (wbs.control_speed > 0) {
1422 ret = pwc_set_wb_speed(pdev, wbs.control_speed);
1423 }
1424 if (wbs.control_delay > 0) {
1425 ret = pwc_set_wb_delay(pdev, wbs.control_delay);
1426 }
1427 }
1428 break;
1429 }
1430
1431 case VIDIOCPWCGAWBSPEED:
1432 {
1433 struct pwc_wb_speed wbs;
1434
1435 ret = pwc_get_wb_speed(pdev);
1436 if (ret < 0)
1437 break;
1438 wbs.control_speed = ret;
1439 ret = pwc_get_wb_delay(pdev);
1440 if (ret < 0)
1441 break;
1442 wbs.control_delay = ret;
1443 if (copy_to_user(arg, &wbs, sizeof(wbs)))
1444 ret = -EFAULT;
1445 break;
1446 }
1447
1448 case VIDIOCPWCSLED:
1449 {
1450 struct pwc_leds leds;
1451
1452 if (copy_from_user(&leds, arg, sizeof(leds)))
1453 ret = -EFAULT;
1454 else
1455 ret = pwc_set_leds(pdev, leds.led_on, leds.led_off);
1456 break;
1457 }
1458
1459
1460 case VIDIOCPWCGLED:
1461 {
1462 struct pwc_leds leds;
1463
1464 ret = pwc_get_leds(pdev, &leds.led_on, &leds.led_off);
1465 if (ret < 0)
1466 break;
1467 if (copy_to_user(arg, &leds, sizeof(leds)))
1468 ret = -EFAULT;
1469 break;
1470 }
1471
1472 case VIDIOCPWCSCONTOUR:
1473 {
1474 int contour;
1475
1476 if (copy_from_user(&contour, arg, sizeof(contour)))
1477 ret = -EFAULT;
1478 else
1479 ret = pwc_set_contour(pdev, contour);
1480 break;
1481 }
1482
1483 case VIDIOCPWCGCONTOUR:
1484 {
1485 int contour;
1486
1487 ret = pwc_get_contour(pdev, &contour);
1488 if (ret < 0)
1489 break;
1490
1491 if (copy_to_user(arg, &contour, sizeof(contour)))
1492 ret = -EFAULT;
1493 break;
1494 }
1495
1496 case VIDIOCPWCSBACKLIGHT:
1497 {
1498 int backlight;
1499
1500 if (copy_from_user(&backlight, arg, sizeof(backlight)))
1501 ret = -EFAULT;
1502 else
1503 ret = pwc_set_backlight(pdev, backlight);
1504 break;
1505 }
1506
1507 case VIDIOCPWCGBACKLIGHT:
1508 {
1509 ret = pwc_get_backlight(pdev);
1510 if (ret < 0)
1511 break;
1512 if (copy_to_user(arg, &ret, sizeof(ret)))
1513 ret = -EFAULT;
1514 break;
1515 }
1516
1517 case VIDIOCPWCSFLICKER:
1518 {
1519 int flicker;
1520
1521 if (copy_from_user(&flicker, arg, sizeof(flicker)))
1522 ret = -EFAULT;
1523 else
1524 ret = pwc_set_flicker(pdev, flicker);
1525 break;
1526 }
1527
1528 case VIDIOCPWCGFLICKER:
1529 {
1530 ret = pwc_get_flicker(pdev);
1531 if (ret < 0)
1532 break;
1533 if (copy_to_user(arg, &ret, sizeof(ret)))
1534 ret = -EFAULT;
1535 break;
1536 }
1537
1538 case VIDIOCPWCSDYNNOISE:
1539 {
1540 int dynnoise;
1541
1542 if (copy_from_user(&dynnoise, arg, sizeof(dynnoise)))
1543 ret = -EFAULT;
1544 else
1545 ret = pwc_set_dynamic_noise(pdev, dynnoise);
1546 break;
1547 }
1548
1549 case VIDIOCPWCGDYNNOISE:
1550 {
1551 ret = pwc_get_dynamic_noise(pdev);
1552 if (ret < 0)
1553 break;
1554 if (copy_to_user(arg, &ret, sizeof(ret)))
1555 ret = -EFAULT;
1556 break;
1557 }
1558
1559 case VIDIOCPWCGREALSIZE:
1560 {
1561 struct pwc_imagesize size;
1562
1563 size.width = pdev->image.x;
1564 size.height = pdev->image.y;
1565 if (copy_to_user(arg, &size, sizeof(size)))
1566 ret = -EFAULT;
1567 break;
1568 }
1569
1570 default:
1571 ret = -ENOIOCTLCMD;
1572 break;
1573 }
1574
1575 if (ret > 0)
1576 return 0;
1577 return ret;
1578}
1579
1580
1581
1582