aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video')
-rw-r--r--drivers/media/video/usbvideo/Kconfig12
-rw-r--r--drivers/media/video/usbvideo/Makefile1
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c1120
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.h126
4 files changed, 1259 insertions, 0 deletions
diff --git a/drivers/media/video/usbvideo/Kconfig b/drivers/media/video/usbvideo/Kconfig
index 39269a2c5635..59fb899f31f3 100644
--- a/drivers/media/video/usbvideo/Kconfig
+++ b/drivers/media/video/usbvideo/Kconfig
@@ -36,3 +36,15 @@ config USB_KONICAWC
36 36
37 To compile this driver as a module, choose M here: the 37 To compile this driver as a module, choose M here: the
38 module will be called konicawc. 38 module will be called konicawc.
39
40config USB_QUICKCAM_MESSENGER
41 tristate "USB Logitech Quickcam Messenger"
42 depends on USB && VIDEO_DEV
43 select VIDEO_USBVIDEO
44 ---help---
45 Say Y or M here to enable support for the USB Logitech Quickcam
46 Messenger webcam.
47
48 To compile this driver as a module, choose M here: the
49 module will be called quickcam_messenger.
50
diff --git a/drivers/media/video/usbvideo/Makefile b/drivers/media/video/usbvideo/Makefile
index bb52eb8dc2f9..4a1b144bee4d 100644
--- a/drivers/media/video/usbvideo/Makefile
+++ b/drivers/media/video/usbvideo/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_VIDEO_USBVIDEO) += usbvideo.o
2obj-$(CONFIG_USB_IBMCAM) += ibmcam.o ultracam.o 2obj-$(CONFIG_USB_IBMCAM) += ibmcam.o ultracam.o
3obj-$(CONFIG_USB_KONICAWC) += konicawc.o 3obj-$(CONFIG_USB_KONICAWC) += konicawc.o
4obj-$(CONFIG_USB_VICAM) += vicam.o 4obj-$(CONFIG_USB_VICAM) += vicam.o
5obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += quickcam_messenger.o
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
new file mode 100644
index 000000000000..8ad9f6af89af
--- /dev/null
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -0,0 +1,1120 @@
1/*
2 * Driver for Logitech Quickcam Messenger usb video camera
3 * Copyright (C) Jaya Kumar
4 *
5 * This work was sponsored by CIS(M) Sdn Bhd.
6 * History:
7 * 05/08/2006 - Jaya Kumar
8 * I wrote this based on the konicawc by Simon Evans.
9 * -
10 * Full credit for reverse engineering and creating an initial
11 * working linux driver for the VV6422 goes to the qce-ga project by
12 * Tuukka Toivonen, Jochen Hoenicke, Peter McConnell,
13 * Cristiano De Michele, Georg Acher, Jean-Frederic Clere as well as
14 * others.
15 * ---
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 *
30 */
31
32#include <linux/kernel.h>
33#include <linux/module.h>
34#include <linux/init.h>
35#include <linux/input.h>
36#include <linux/usb_input.h>
37
38#include "usbvideo.h"
39#include "quickcam_messenger.h"
40
41/*
42 * Version Information
43 */
44
45#ifdef CONFIG_USB_DEBUG
46static int debug;
47#define DEBUG(n, format, arg...) \
48 if (n <= debug) { \
49 printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
50 }
51#else
52#define DEBUG(n, arg...)
53static const int debug = 0;
54#endif
55
56#define DRIVER_VERSION "v0.01"
57#define DRIVER_DESC "Logitech Quickcam Messenger USB"
58
59#define USB_LOGITECH_VENDOR_ID 0x046D
60#define USB_QCM_PRODUCT_ID 0x08F0
61
62#define MAX_CAMERAS 1
63
64#define MAX_COLOUR 32768
65#define MAX_HUE 32768
66#define MAX_BRIGHTNESS 32768
67#define MAX_CONTRAST 32768
68#define MAX_WHITENESS 32768
69
70static int size = SIZE_320X240;
71static int colour = MAX_COLOUR;
72static int hue = MAX_HUE;
73static int brightness = MAX_BRIGHTNESS;
74static int contrast = MAX_CONTRAST;
75static int whiteness = MAX_WHITENESS;
76
77static struct usbvideo *cams;
78
79static struct usb_device_id qcm_table [] = {
80 { USB_DEVICE(USB_LOGITECH_VENDOR_ID, USB_QCM_PRODUCT_ID) },
81 { }
82};
83MODULE_DEVICE_TABLE(usb, qcm_table);
84
85#ifdef CONFIG_INPUT
86static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
87{
88 struct input_dev *input_dev;
89
90 usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
91 strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
92
93 cam->input = input_dev = input_allocate_device();
94 if (!input_dev) {
95 warn("insufficient mem for cam input device");
96 return;
97 }
98
99 input_dev->name = "QCM button";
100 input_dev->phys = cam->input_physname;
101 usb_to_input_id(dev, &input_dev->id);
102 input_dev->cdev.dev = &dev->dev;
103
104 input_dev->evbit[0] = BIT(EV_KEY);
105 input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
106
107 input_dev->private = cam;
108
109 input_register_device(cam->input);
110}
111
112static void qcm_unregister_input(struct qcm *cam)
113{
114 if (cam->input) {
115 input_unregister_device(cam->input);
116 cam->input = NULL;
117 }
118}
119
120static void qcm_report_buttonstat(struct qcm *cam)
121{
122 if (cam->input) {
123 input_report_key(cam->input, BTN_0, cam->button_sts);
124 input_sync(cam->input);
125 }
126}
127
128static void qcm_int_irq(struct urb *urb, struct pt_regs *regs)
129{
130 int ret;
131 struct uvd *uvd = urb->context;
132 struct qcm *cam;
133
134 if (!CAMERA_IS_OPERATIONAL(uvd))
135 return;
136
137 if (!uvd->streaming)
138 return;
139
140 uvd->stats.urb_count++;
141
142 if (urb->status < 0)
143 uvd->stats.iso_err_count++;
144 else {
145 if (urb->actual_length > 0 ) {
146 cam = (struct qcm *) uvd->user_data;
147 if (cam->button_sts_buf == 0x88)
148 cam->button_sts = 0x0;
149 else if (cam->button_sts_buf == 0x80)
150 cam->button_sts = 0x1;
151 qcm_report_buttonstat(cam);
152 }
153 }
154
155 ret = usb_submit_urb(urb, GFP_ATOMIC);
156 if (ret < 0)
157 err("usb_submit_urb error (%d)", ret);
158}
159
160static int qcm_setup_input_int(struct qcm *cam, struct uvd *uvd)
161{
162 int errflag;
163 usb_fill_int_urb(cam->button_urb, uvd->dev,
164 usb_rcvintpipe(uvd->dev, uvd->video_endp + 1),
165 &cam->button_sts_buf,
166 1,
167 qcm_int_irq,
168 uvd, 16);
169
170 errflag = usb_submit_urb(cam->button_urb, GFP_KERNEL);
171 if (errflag)
172 err ("usb_submit_int ret %d", errflag);
173 return errflag;
174}
175
176static void qcm_stop_int_data(struct qcm *cam)
177{
178 usb_kill_urb(cam->button_urb);
179}
180
181static int qcm_alloc_int_urb(struct qcm *cam)
182{
183 cam->button_urb = usb_alloc_urb(0, GFP_KERNEL);
184
185 if (!cam->button_urb)
186 return -ENOMEM;
187
188 return 0;
189}
190
191static void qcm_free_int(struct qcm *cam)
192{
193 if (cam->button_urb)
194 usb_free_urb(cam->button_urb);
195}
196#endif /* CONFIG_INPUT */
197
198static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val)
199{
200 int ret;
201
202 /* we'll wait up to 3 slices but no more */
203 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
204 0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
205 reg, 0, &val, 1, 3*HZ);
206 return ret;
207}
208
209static int qcm_stv_setw(struct usb_device *dev, u16 reg, u16 val)
210{
211 int ret;
212
213 /* we'll wait up to 3 slices but no more */
214 ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
215 0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
216 reg, 0, &val, 2, 3*HZ);
217 return ret;
218}
219
220static int qcm_stv_getw(struct usb_device *dev, unsigned short reg,
221 __le16 *val)
222{
223 int ret;
224
225 /* we'll wait up to 3 slices but no more */
226 ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
227 0x04, USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
228 reg, 0, val, 2, 3*HZ);
229 return ret;
230}
231
232static int qcm_camera_on(struct uvd *uvd)
233{
234 int ret;
235 CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x01));
236 return 0;
237}
238
239static int qcm_camera_off(struct uvd *uvd)
240{
241 int ret;
242 CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
243 return 0;
244}
245
246static void qcm_hsv2rgb(u16 hue, u16 sat, u16 val, u16 *r, u16 *g, u16 *b)
247{
248 unsigned int segment, valsat;
249 signed int h = (signed int) hue;
250 unsigned int s = (sat - 32768) * 2; /* rescale */
251 unsigned int v = val;
252 unsigned int p;
253
254 /*
255 the registers controling gain are 8 bit of which
256 we affect only the last 4 bits with our gain.
257 we know that if saturation is 0, (unsaturated) then
258 we're grayscale (center axis of the colour cone) so
259 we set rgb=value. we use a formula obtained from
260 wikipedia to map the cone to the RGB plane. it's
261 as follows for the human value case of h=0..360,
262 s=0..1, v=0..1
263 h_i = h/60 % 6 , f = h/60 - h_i , p = v(1-s)
264 q = v(1 - f*s) , t = v(1 - (1-f)s)
265 h_i==0 => r=v , g=t, b=p
266 h_i==1 => r=q , g=v, b=p
267 h_i==2 => r=p , g=v, b=t
268 h_i==3 => r=p , g=q, b=v
269 h_i==4 => r=t , g=p, b=v
270 h_i==5 => r=v , g=p, b=q
271 the bottom side (the point) and the stuff just up
272 of that is black so we simplify those two cases.
273 */
274 if (sat < 32768) {
275 /* anything less than this is unsaturated */
276 *r = val;
277 *g = val;
278 *b = val;
279 return;
280 }
281 if (val <= (0xFFFF/8)) {
282 /* anything less than this is black */
283 *r = 0;
284 *g = 0;
285 *b = 0;
286 return;
287 }
288
289 /* the rest of this code is copying tukkat's
290 implementation of the hsv2rgb conversion as taken
291 from qc-usb-messenger code. the 10923 is 0xFFFF/6
292 to divide the cone into 6 sectors. */
293
294 segment = (h + 10923) & 0xFFFF;
295 segment = segment*3 >> 16; /* 0..2: 0=R, 1=G, 2=B */
296 hue -= segment * 21845; /* -10923..10923 */
297 h = hue;
298 h *= 3;
299 valsat = v*s >> 16; /* 0..65534 */
300 p = v - valsat;
301 if (h >= 0) {
302 unsigned int t = v - (valsat * (32769 - h) >> 15);
303 switch (segment) {
304 case 0: /* R-> */
305 *r = v;
306 *g = t;
307 *b = p;
308 break;
309 case 1: /* G-> */
310 *r = p;
311 *g = v;
312 *b = t;
313 break;
314 case 2: /* B-> */
315 *r = t;
316 *g = p;
317 *b = v;
318 break;
319 }
320 } else {
321 unsigned int q = v - (valsat * (32769 + h) >> 15);
322 switch (segment) {
323 case 0: /* ->R */
324 *r = v;
325 *g = p;
326 *b = q;
327 break;
328 case 1: /* ->G */
329 *r = q;
330 *g = v;
331 *b = p;
332 break;
333 case 2: /* ->B */
334 *r = p;
335 *g = q;
336 *b = v;
337 break;
338 }
339 }
340}
341
342static int qcm_sensor_set_gains(struct uvd *uvd, u16 hue,
343 u16 saturation, u16 value)
344{
345 int ret;
346 u16 r,g,b;
347
348 /* this code is based on qc-usb-messenger */
349 qcm_hsv2rgb(hue, saturation, value, &r, &g, &b);
350
351 r >>= 12;
352 g >>= 12;
353 b >>= 12;
354
355 /* min val is 8 */
356 r = max((u16) 8, r);
357 g = max((u16) 8, g);
358 b = max((u16) 8, b);
359
360 r |= 0x30;
361 g |= 0x30;
362 b |= 0x30;
363
364 /* set the r,g,b gain registers */
365 CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x0509, r));
366 CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050A, g));
367 CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050B, b));
368
369 /* doing as qc-usb did */
370 CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050C, 0x2A));
371 CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050D, 0x01));
372 CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
373
374 return 0;
375}
376
377static int qcm_sensor_set_exposure(struct uvd *uvd, int exposure)
378{
379 int ret;
380 int formedval;
381
382 /* calculation was from qc-usb-messenger driver */
383 formedval = ( exposure >> 12 );
384
385 /* max value for formedval is 14 */
386 formedval = min(formedval, 14);
387
388 CHECK_RET(ret, qcm_stv_setb(uvd->dev,
389 0x143A, 0xF0 | formedval));
390 CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
391 return 0;
392}
393
394static int qcm_sensor_setlevels(struct uvd *uvd, int brightness, int contrast,
395 int hue, int colour)
396{
397 int ret;
398 /* brightness is exposure, contrast is gain, colour is saturation */
399 CHECK_RET(ret,
400 qcm_sensor_set_exposure(uvd, brightness));
401 CHECK_RET(ret, qcm_sensor_set_gains(uvd, hue, colour, contrast));
402
403 return 0;
404}
405
406static int qcm_sensor_setsize(struct uvd *uvd, u8 size)
407{
408 int ret;
409
410 CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x1505, size));
411 return 0;
412}
413
414static int qcm_sensor_set_shutter(struct uvd *uvd, int whiteness)
415{
416 int ret;
417 /* some rescaling as done by the qc-usb-messenger code */
418 if (whiteness > 0xC000)
419 whiteness = 0xC000 + (whiteness & 0x3FFF)*8;
420
421 CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143D,
422 (whiteness >> 8) & 0xFF));
423 CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143E,
424 (whiteness >> 16) & 0x03));
425 CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
426
427 return 0;
428}
429
430static int qcm_sensor_init(struct uvd *uvd)
431{
432 struct qcm *cam = (struct qcm *) uvd->user_data;
433 int ret;
434 int i;
435
436 for (i=0; i < sizeof(regval_table)/sizeof(regval_table[0]) ; i++) {
437 CHECK_RET(ret, qcm_stv_setb(uvd->dev,
438 regval_table[i].reg,
439 regval_table[i].val));
440 }
441
442 CHECK_RET(ret, qcm_stv_setw(uvd->dev, 0x15c1,
443 cpu_to_le16(ISOC_PACKET_SIZE)));
444 CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x15c3, 0x08));
445 CHECK_RET(ret, ret = qcm_stv_setb(uvd->dev, 0x143f, 0x01));
446
447 CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
448
449 CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
450
451 CHECK_RET(ret, qcm_sensor_setlevels(uvd, uvd->vpic.brightness,
452 uvd->vpic.contrast, uvd->vpic.hue, uvd->vpic.colour));
453
454 CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
455 CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
456
457 return 0;
458}
459
460static int qcm_set_camera_size(struct uvd *uvd)
461{
462 int ret;
463 struct qcm *cam = (struct qcm *) uvd->user_data;
464
465 CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
466 cam->width = camera_sizes[cam->size].width;
467 cam->height = camera_sizes[cam->size].height;
468 uvd->videosize = VIDEOSIZE(cam->width, cam->height);
469
470 return 0;
471}
472
473static int qcm_setup_on_open(struct uvd *uvd)
474{
475 int ret;
476
477 CHECK_RET(ret, qcm_sensor_set_gains(uvd, uvd->vpic.hue,
478 uvd->vpic.colour, uvd->vpic.contrast));
479 CHECK_RET(ret, qcm_sensor_set_exposure(uvd, uvd->vpic.brightness));
480 CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
481 CHECK_RET(ret, qcm_set_camera_size(uvd));
482 CHECK_RET(ret, qcm_camera_on(uvd));
483 return 0;
484}
485
486static void qcm_adjust_picture(struct uvd *uvd)
487{
488 int ret;
489 struct qcm *cam = (struct qcm *) uvd->user_data;
490
491 ret = qcm_camera_off(uvd);
492 if (ret) {
493 err("can't turn camera off. abandoning pic adjustment");
494 return;
495 }
496
497 /* if there's been a change in contrast, hue, or
498 colour then we need to recalculate hsv in order
499 to update gains */
500 if ((cam->contrast != uvd->vpic.contrast) ||
501 (cam->hue != uvd->vpic.hue) ||
502 (cam->colour != uvd->vpic.colour)) {
503 cam->contrast = uvd->vpic.contrast;
504 cam->hue = uvd->vpic.hue;
505 cam->colour = uvd->vpic.colour;
506 ret = qcm_sensor_set_gains(uvd, cam->hue, cam->colour,
507 cam->contrast);
508 if (ret) {
509 err("can't set gains. abandoning pic adjustment");
510 return;
511 }
512 }
513
514 if (cam->brightness != uvd->vpic.brightness) {
515 cam->brightness = uvd->vpic.brightness;
516 ret = qcm_sensor_set_exposure(uvd, cam->brightness);
517 if (ret) {
518 err("can't set exposure. abandoning pic adjustment");
519 return;
520 }
521 }
522
523 if (cam->whiteness != uvd->vpic.whiteness) {
524 cam->whiteness = uvd->vpic.whiteness;
525 qcm_sensor_set_shutter(uvd, cam->whiteness);
526 if (ret) {
527 err("can't set shutter. abandoning pic adjustment");
528 return;
529 }
530 }
531
532 ret = qcm_camera_on(uvd);
533 if (ret) {
534 err("can't reenable camera. pic adjustment failed");
535 return;
536 }
537}
538
539static int qcm_process_frame(struct uvd *uvd, u8 *cdata, int framelen)
540{
541 int datalen;
542 int totaldata;
543 struct framehdr {
544 __be16 id;
545 __be16 len;
546 };
547 struct framehdr *fhdr;
548
549 totaldata = 0;
550 while (framelen) {
551 fhdr = (struct framehdr *) cdata;
552 datalen = be16_to_cpu(fhdr->len);
553 framelen -= 4;
554 cdata += 4;
555
556 if ((fhdr->id) == cpu_to_be16(0x8001)) {
557 RingQueue_Enqueue(&uvd->dp, marker, 4);
558 totaldata += 4;
559 continue;
560 }
561 if ((fhdr->id & cpu_to_be16(0xFF00)) == cpu_to_be16(0x0200)) {
562 RingQueue_Enqueue(&uvd->dp, cdata, datalen);
563 totaldata += datalen;
564 }
565 framelen -= datalen;
566 cdata += datalen;
567 }
568 return totaldata;
569}
570
571static int qcm_compress_iso(struct uvd *uvd, struct urb *dataurb)
572{
573 int totlen;
574 int i;
575 unsigned char *cdata;
576
577 totlen=0;
578 for (i = 0; i < dataurb->number_of_packets; i++) {
579 int n = dataurb->iso_frame_desc[i].actual_length;
580 int st = dataurb->iso_frame_desc[i].status;
581
582 cdata = dataurb->transfer_buffer +
583 dataurb->iso_frame_desc[i].offset;
584
585 if (st < 0) {
586 warn("Data error: packet=%d. len=%d. status=%d.",
587 i, n, st);
588 uvd->stats.iso_err_count++;
589 continue;
590 }
591 if (!n)
592 continue;
593
594 totlen += qcm_process_frame(uvd, cdata, n);
595 }
596 return totlen;
597}
598
599static void resubmit_urb(struct uvd *uvd, struct urb *urb)
600{
601 int ret;
602
603 urb->dev = uvd->dev;
604 ret = usb_submit_urb(urb, GFP_ATOMIC);
605 if (ret)
606 err("usb_submit_urb error (%d)", ret);
607}
608
609static void qcm_isoc_irq(struct urb *urb, struct pt_regs *regs)
610{
611 int len;
612 struct uvd *uvd = urb->context;
613
614 if (!CAMERA_IS_OPERATIONAL(uvd))
615 return;
616
617 if (!uvd->streaming)
618 return;
619
620 uvd->stats.urb_count++;
621
622 if (!urb->actual_length) {
623 resubmit_urb(uvd, urb);
624 return;
625 }
626
627 len = qcm_compress_iso(uvd, urb);
628 resubmit_urb(uvd, urb);
629 uvd->stats.urb_length = len;
630 uvd->stats.data_count += len;
631 if (len)
632 RingQueue_WakeUpInterruptible(&uvd->dp);
633}
634
635static int qcm_start_data(struct uvd *uvd)
636{
637 struct qcm *cam = (struct qcm *) uvd->user_data;
638 int i;
639 int errflag;
640 int pktsz;
641 int err;
642
643 pktsz = uvd->iso_packet_len;
644 if (!CAMERA_IS_OPERATIONAL(uvd)) {
645 err("Camera is not operational");
646 return -EFAULT;
647 }
648
649 err = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltActive);
650 if (err < 0) {
651 err("usb_set_interface error");
652 uvd->last_error = err;
653 return -EBUSY;
654 }
655
656 for (i=0; i < USBVIDEO_NUMSBUF; i++) {
657 int j, k;
658 struct urb *urb = uvd->sbuf[i].urb;
659 urb->dev = uvd->dev;
660 urb->context = uvd;
661 urb->pipe = usb_rcvisocpipe(uvd->dev, uvd->video_endp);
662 urb->interval = 1;
663 urb->transfer_flags = URB_ISO_ASAP;
664 urb->transfer_buffer = uvd->sbuf[i].data;
665 urb->complete = qcm_isoc_irq;
666 urb->number_of_packets = FRAMES_PER_DESC;
667 urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
668 for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
669 urb->iso_frame_desc[j].offset = k;
670 urb->iso_frame_desc[j].length = pktsz;
671 }
672 }
673
674 uvd->streaming = 1;
675 uvd->curframe = -1;
676 for (i=0; i < USBVIDEO_NUMSBUF; i++) {
677 errflag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
678 if (errflag)
679 err ("usb_submit_isoc(%d) ret %d", i, errflag);
680 }
681
682 CHECK_RET(err, qcm_setup_input_int(cam, uvd));
683 CHECK_RET(err, qcm_camera_on(uvd));
684 return 0;
685}
686
687static void qcm_stop_data(struct uvd *uvd)
688{
689 struct qcm *cam = (struct qcm *) uvd->user_data;
690 int i, j;
691 int ret;
692
693 if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
694 return;
695
696 ret = qcm_camera_off(uvd);
697 if (ret)
698 warn("couldn't turn the cam off.");
699
700 uvd->streaming = 0;
701
702 /* Unschedule all of the iso td's */
703 for (i=0; i < USBVIDEO_NUMSBUF; i++)
704 usb_kill_urb(uvd->sbuf[i].urb);
705
706 qcm_stop_int_data(cam);
707
708 if (!uvd->remove_pending) {
709 /* Set packet size to 0 */
710 j = usb_set_interface(uvd->dev, uvd->iface,
711 uvd->ifaceAltInactive);
712 if (j < 0) {
713 err("usb_set_interface() error %d.", j);
714 uvd->last_error = j;
715 }
716 }
717}
718
719static void qcm_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
720{
721 struct qcm *cam = (struct qcm *) uvd->user_data;
722 int x;
723 struct rgb *rgbL0;
724 struct rgb *rgbL1;
725 struct bayL0 *bayL0;
726 struct bayL1 *bayL1;
727 int hor,ver,hordel,verdel;
728 assert(frame != NULL);
729
730 switch (cam->size) {
731 case SIZE_160X120:
732 hor = 162; ver = 124; hordel = 1; verdel = 2;
733 break;
734 case SIZE_320X240:
735 default:
736 hor = 324; ver = 248; hordel = 2; verdel = 4;
737 break;
738 }
739
740 if (frame->scanstate == ScanState_Scanning) {
741 while (RingQueue_GetLength(&uvd->dp) >=
742 4 + (hor*verdel + hordel)) {
743 if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
744 (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
745 (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
746 (RING_QUEUE_PEEK(&uvd->dp, 3) == 0xff)) {
747 frame->curline = 0;
748 frame->scanstate = ScanState_Lines;
749 frame->frameState = FrameState_Grabbing;
750 RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
751 /*
752 * if we're starting, we need to discard the first
753 * 4 lines of y bayer data
754 * and the first 2 gr elements of x bayer data
755 */
756 RING_QUEUE_DEQUEUE_BYTES(&uvd->dp,
757 (hor*verdel + hordel));
758 break;
759 }
760 RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
761 }
762 }
763
764 if (frame->scanstate == ScanState_Scanning)
765 return;
766
767 /* now we can start processing bayer data so long as we have at least
768 * 2 lines worth of data. this is the simplest demosaicing method that
769 * I could think of. I use each 2x2 bayer element without interpolation
770 * to generate 4 rgb pixels.
771 */
772 while ( frame->curline < cam->height &&
773 (RingQueue_GetLength(&uvd->dp) >= hor*2)) {
774 /* get 2 lines of bayer for demosaicing
775 * into 2 lines of RGB */
776 RingQueue_Dequeue(&uvd->dp, cam->scratch, hor*2);
777 bayL0 = (struct bayL0 *) cam->scratch;
778 bayL1 = (struct bayL1 *) (cam->scratch + hor);
779 /* frame->curline is the rgb y line */
780 rgbL0 = (struct rgb *)
781 ( frame->data + (cam->width*3*frame->curline));
782 /* w/2 because we're already doing 2 pixels */
783 rgbL1 = rgbL0 + (cam->width/2);
784
785 for (x=0; x < cam->width; x+=2) {
786 rgbL0->r = bayL0->r;
787 rgbL0->g = bayL0->g;
788 rgbL0->b = bayL1->b;
789
790 rgbL0->r2 = bayL0->r;
791 rgbL0->g2 = bayL1->g;
792 rgbL0->b2 = bayL1->b;
793
794 rgbL1->r = bayL0->r;
795 rgbL1->g = bayL1->g;
796 rgbL1->b = bayL1->b;
797
798 rgbL1->r2 = bayL0->r;
799 rgbL1->g2 = bayL1->g;
800 rgbL1->b2 = bayL1->b;
801
802 rgbL0++;
803 rgbL1++;
804
805 bayL0++;
806 bayL1++;
807 }
808
809 frame->seqRead_Length += cam->width*3*2;
810 frame->curline += 2;
811 }
812 /* See if we filled the frame */
813 if (frame->curline == cam->height) {
814 frame->frameState = FrameState_Done_Hold;
815 frame->curline = 0;
816 uvd->curframe = -1;
817 uvd->stats.frame_num++;
818 }
819}
820
821/* taken from konicawc */
822static int qcm_set_video_mode(struct uvd *uvd, struct video_window *vw)
823{
824 int ret;
825 int newsize;
826 int oldsize;
827 int x = vw->width;
828 int y = vw->height;
829 struct qcm *cam = (struct qcm *) uvd->user_data;
830
831 if (x > 0 && y > 0) {
832 DEBUG(2, "trying to find size %d,%d", x, y);
833 for (newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
834 if ((camera_sizes[newsize].width == x) &&
835 (camera_sizes[newsize].height == y))
836 break;
837 }
838 } else
839 newsize = cam->size;
840
841 if (newsize > MAX_FRAME_SIZE) {
842 DEBUG(1, "couldn't find size %d,%d", x, y);
843 return -EINVAL;
844 }
845
846 if (newsize == cam->size) {
847 DEBUG(1, "Nothing to do");
848 return 0;
849 }
850
851 qcm_stop_data(uvd);
852
853 if (cam->size != newsize) {
854 oldsize = cam->size;
855 cam->size = newsize;
856 ret = qcm_set_camera_size(uvd);
857 if (ret) {
858 err("Couldn't set camera size, err=%d",ret);
859 /* restore the original size */
860 cam->size = oldsize;
861 return ret;
862 }
863 }
864
865 /* Flush the input queue and clear any current frame in progress */
866
867 RingQueue_Flush(&uvd->dp);
868 if (uvd->curframe != -1) {
869 uvd->frame[uvd->curframe].curline = 0;
870 uvd->frame[uvd->curframe].seqRead_Length = 0;
871 uvd->frame[uvd->curframe].seqRead_Index = 0;
872 }
873
874 CHECK_RET(ret, qcm_start_data(uvd));
875 return 0;
876}
877
878static int qcm_configure_video(struct uvd *uvd)
879{
880 int ret;
881 memset(&uvd->vpic, 0, sizeof(uvd->vpic));
882 memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
883
884 uvd->vpic.colour = colour;
885 uvd->vpic.hue = hue;
886 uvd->vpic.brightness = brightness;
887 uvd->vpic.contrast = contrast;
888 uvd->vpic.whiteness = whiteness;
889 uvd->vpic.depth = 24;
890 uvd->vpic.palette = VIDEO_PALETTE_RGB24;
891
892 memset(&uvd->vcap, 0, sizeof(uvd->vcap));
893 strcpy(uvd->vcap.name, "QCM USB Camera");
894 uvd->vcap.type = VID_TYPE_CAPTURE;
895 uvd->vcap.channels = 1;
896 uvd->vcap.audios = 0;
897
898 uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
899 uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
900 uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
901 uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
902
903 memset(&uvd->vchan, 0, sizeof(uvd->vchan));
904 uvd->vchan.flags = 0 ;
905 uvd->vchan.tuners = 0;
906 uvd->vchan.channel = 0;
907 uvd->vchan.type = VIDEO_TYPE_CAMERA;
908 strcpy(uvd->vchan.name, "Camera");
909
910 CHECK_RET(ret, qcm_sensor_init(uvd));
911 return 0;
912}
913
914static int qcm_probe(struct usb_interface *intf,
915 const struct usb_device_id *devid)
916{
917 int err;
918 struct uvd *uvd;
919 struct usb_device *dev = interface_to_usbdev(intf);
920 struct qcm *cam;
921 size_t buffer_size;
922 unsigned char video_ep;
923 struct usb_host_interface *interface;
924 struct usb_endpoint_descriptor *endpoint;
925 int i,j;
926 unsigned int ifacenum, ifacenum_inact=0;
927 __le16 sensor_id;
928
929 /* we don't support multiconfig cams */
930 if (dev->descriptor.bNumConfigurations != 1)
931 return -ENODEV;
932
933 /* first check for the video interface and not
934 * the audio interface */
935 interface = &intf->cur_altsetting[0];
936 if ((interface->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
937 || (interface->desc.bInterfaceSubClass !=
938 USB_CLASS_VENDOR_SPEC))
939 return -ENODEV;
940
941 /*
942 walk through each endpoint in each setting in the interface
943 stop when we find the one that's an isochronous IN endpoint.
944 */
945 for (i=0; i < intf->num_altsetting; i++) {
946 interface = &intf->cur_altsetting[i];
947 ifacenum = interface->desc.bAlternateSetting;
948 /* walk the end points */
949 for (j=0; j < interface->desc.bNumEndpoints; j++) {
950 endpoint = &interface->endpoint[j].desc;
951
952 if ((endpoint->bEndpointAddress &
953 USB_ENDPOINT_DIR_MASK) != USB_DIR_IN)
954 continue; /* not input then not good */
955
956 buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
957 if (!buffer_size) {
958 ifacenum_inact = ifacenum;
959 continue; /* 0 pkt size is not what we want */
960 }
961
962 if ((endpoint->bmAttributes &
963 USB_ENDPOINT_XFERTYPE_MASK) ==
964 USB_ENDPOINT_XFER_ISOC) {
965 video_ep = endpoint->bEndpointAddress;
966 /* break out of the search */
967 goto good_videoep;
968 }
969 }
970 }
971 /* failed out since nothing useful was found */
972 err("No suitable endpoint was found\n");
973 return -ENODEV;
974
975good_videoep:
976 /* disable isochronous stream before doing anything else */
977 err = qcm_stv_setb(dev, STV_ISO_ENABLE, 0);
978 if (err < 0) {
979 err("Failed to disable sensor stream");
980 return -EIO;
981 }
982
983 /*
984 Check that this is the same unknown sensor that is known to work. This
985 sensor is suspected to be the ST VV6422C001. I'll check the same value
986 that the qc-usb driver checks. This value is probably not even the
987 sensor ID since it matches the USB dev ID. Oh well. If it doesn't
988 match, it's probably a diff sensor so exit and apologize.
989 */
990 err = qcm_stv_getw(dev, CMOS_SENSOR_IDREV, &sensor_id);
991 if (err < 0) {
992 err("Couldn't read sensor values. Err %d\n",err);
993 return err;
994 }
995 if (sensor_id != cpu_to_le16(0x08F0)) {
996 err("Sensor ID %x != %x. Unsupported. Sorry\n",
997 le16_to_cpu(sensor_id), (0x08F0));
998 return -ENODEV;
999 }
1000
1001 uvd = usbvideo_AllocateDevice(cams);
1002 if (!uvd)
1003 return -ENOMEM;
1004
1005 cam = (struct qcm *) uvd->user_data;
1006
1007 /* buf for doing demosaicing */
1008 cam->scratch = kmalloc(324*2, GFP_KERNEL);
1009 if (!cam->scratch) /* uvd freed in dereg */
1010 return -ENOMEM;
1011
1012 /* yes, if we fail after here, cam->scratch gets freed
1013 by qcm_free_uvd */
1014
1015 err = qcm_alloc_int_urb(cam);
1016 if (err < 0)
1017 return err;
1018
1019 /* yes, if we fail after here, int urb gets freed
1020 by qcm_free_uvd */
1021
1022 RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
1023 cam->width = camera_sizes[size].width;
1024 cam->height = camera_sizes[size].height;
1025 cam->size = size;
1026
1027 uvd->debug = debug;
1028 uvd->flags = 0;
1029 uvd->dev = dev;
1030 uvd->iface = intf->altsetting->desc.bInterfaceNumber;
1031 uvd->ifaceAltActive = ifacenum;
1032 uvd->ifaceAltInactive = ifacenum_inact;
1033 uvd->video_endp = video_ep;
1034 uvd->iso_packet_len = buffer_size;
1035 uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
1036 uvd->defaultPalette = VIDEO_PALETTE_RGB24;
1037 uvd->canvas = VIDEOSIZE(320, 240);
1038 uvd->videosize = VIDEOSIZE(cam->width, cam->height);
1039 err = qcm_configure_video(uvd);
1040 if (err) {
1041 err("failed to configure video settings");
1042 return err;
1043 }
1044
1045 err = usbvideo_RegisterVideoDevice(uvd);
1046 if (err) { /* the uvd gets freed in Deregister */
1047 err("usbvideo_RegisterVideoDevice() failed.");
1048 return err;
1049 }
1050
1051 uvd->max_frame_size = (320 * 240 * 3);
1052 qcm_register_input(cam, dev);
1053 usb_set_intfdata(intf, uvd);
1054 return 0;
1055}
1056
1057static void qcm_free_uvd(struct uvd *uvd)
1058{
1059 struct qcm *cam = (struct qcm *) uvd->user_data;
1060
1061 kfree(cam->scratch);
1062 qcm_unregister_input(cam);
1063 qcm_free_int(cam);
1064}
1065
1066static struct usbvideo_cb qcm_driver = {
1067 .probe = qcm_probe,
1068 .setupOnOpen = qcm_setup_on_open,
1069 .processData = qcm_process_isoc,
1070 .setVideoMode = qcm_set_video_mode,
1071 .startDataPump = qcm_start_data,
1072 .stopDataPump = qcm_stop_data,
1073 .adjustPicture = qcm_adjust_picture,
1074 .userFree = qcm_free_uvd
1075};
1076
1077static int __init qcm_init(void)
1078{
1079 info(DRIVER_DESC " " DRIVER_VERSION);
1080
1081 return usbvideo_register(
1082 &cams,
1083 MAX_CAMERAS,
1084 sizeof(struct qcm),
1085 "QCM",
1086 &qcm_driver,
1087 THIS_MODULE,
1088 qcm_table);
1089}
1090
1091static void __exit qcm_exit(void)
1092{
1093 usbvideo_Deregister(&cams);
1094}
1095
1096module_param(size, int, 0);
1097MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 320x240");
1098module_param(colour, int, 0);
1099MODULE_PARM_DESC(colour, "Initial colour");
1100module_param(hue, int, 0);
1101MODULE_PARM_DESC(hue, "Initial hue");
1102module_param(brightness, int, 0);
1103MODULE_PARM_DESC(brightness, "Initial brightness");
1104module_param(contrast, int, 0);
1105MODULE_PARM_DESC(contrast, "Initial contrast");
1106module_param(whiteness, int, 0);
1107MODULE_PARM_DESC(whiteness, "Initial whiteness");
1108
1109#ifdef CONFIG_USB_DEBUG
1110module_param(debug, int, S_IRUGO | S_IWUSR);
1111MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
1112#endif
1113
1114module_init(qcm_init);
1115module_exit(qcm_exit);
1116
1117MODULE_LICENSE("GPL");
1118MODULE_AUTHOR("Jaya Kumar");
1119MODULE_DESCRIPTION("QCM USB Camera");
1120MODULE_SUPPORTED_DEVICE("QCM USB Camera");
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.h b/drivers/media/video/usbvideo/quickcam_messenger.h
new file mode 100644
index 000000000000..baab9c081b52
--- /dev/null
+++ b/drivers/media/video/usbvideo/quickcam_messenger.h
@@ -0,0 +1,126 @@
1#ifndef quickcam_messenger_h
2#define quickcam_messenger_h
3
4#ifndef CONFIG_INPUT
5/* if we're not using input we dummy out these functions */
6#define qcm_register_input(...)
7#define qcm_unregister_input(...)
8#define qcm_report_buttonstat(...)
9#define qcm_setup_input_int(...) 0
10#define qcm_stop_int_data(...)
11#define qcm_alloc_int_urb(...) 0
12#define qcm_free_int(...)
13#endif
14
15
16#define CHECK_RET(ret, expr) \
17 if ((ret = expr) < 0) return ret
18
19/* Control Registers for the STVV6422 ASIC
20 * - this define is taken from the qc-usb-messenger code
21 */
22#define STV_ISO_ENABLE 0x1440
23#define ISOC_PACKET_SIZE 1023
24
25/* Chip identification number including revision indicator */
26#define CMOS_SENSOR_IDREV 0xE00A
27
28struct rgb {
29 u8 b;
30 u8 g;
31 u8 r;
32 u8 b2;
33 u8 g2;
34 u8 r2;
35};
36
37struct bayL0 {
38#ifdef __BIG_ENDIAN
39 u8 r;
40 u8 g;
41#elif __LITTLE_ENDIAN
42 u8 g;
43 u8 r;
44#else
45#error not byte order defined
46#endif
47};
48
49struct bayL1 {
50#ifdef __BIG_ENDIAN
51 u8 g;
52 u8 b;
53#elif __LITTLE_ENDIAN
54 u8 b;
55 u8 g;
56#else
57#error not byte order defined
58#endif
59};
60
61struct cam_size {
62 u16 width;
63 u16 height;
64 u8 cmd;
65};
66
67static const struct cam_size camera_sizes[] = {
68 { 160, 120, 0xf },
69 { 320, 240, 0x2 },
70};
71
72enum frame_sizes {
73 SIZE_160X120 = 0,
74 SIZE_320X240 = 1,
75};
76
77#define MAX_FRAME_SIZE SIZE_320X240
78
79struct qcm {
80 u16 colour;
81 u16 hue;
82 u16 brightness;
83 u16 contrast;
84 u16 whiteness;
85
86 u8 size;
87 int height;
88 int width;
89 u8 *scratch;
90 struct urb *button_urb;
91 u8 button_sts;
92 u8 button_sts_buf;
93
94#ifdef CONFIG_INPUT
95 struct input_dev *input;
96 char input_physname[64];
97#endif
98};
99
100struct regval {
101 u16 reg;
102 u8 val;
103};
104/* this table is derived from the
105qc-usb-messenger code */
106static const struct regval regval_table[] = {
107 { STV_ISO_ENABLE, 0x00 },
108 { 0x1436, 0x00 }, { 0x1432, 0x03 },
109 { 0x143a, 0xF9 }, { 0x0509, 0x38 },
110 { 0x050a, 0x38 }, { 0x050b, 0x38 },
111 { 0x050c, 0x2A }, { 0x050d, 0x01 },
112 { 0x1431, 0x00 }, { 0x1433, 0x34 },
113 { 0x1438, 0x18 }, { 0x1439, 0x00 },
114 { 0x143b, 0x05 }, { 0x143c, 0x00 },
115 { 0x143e, 0x01 }, { 0x143d, 0x00 },
116 { 0x1442, 0xe2 }, { 0x1500, 0xd0 },
117 { 0x1500, 0xd0 }, { 0x1500, 0x50 },
118 { 0x1501, 0xaf }, { 0x1502, 0xc2 },
119 { 0x1503, 0x45 }, { 0x1505, 0x02 },
120 { 0x150e, 0x8e }, { 0x150f, 0x37 },
121 { 0x15c0, 0x00 },
122};
123
124static const unsigned char marker[] = { 0x00, 0xff, 0x00, 0xFF };
125
126#endif /* quickcam_messenger_h */