blob: 93fb04ed99a040d2e28512e21505e424f3133e69 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Endpoints (formerly known as AOX) se401 USB Camera Driver
3 *
4 * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
5 *
6 * Still somewhat based on the Linux ov511 driver.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 *
23 * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on
24 * their chipset available and supporting me while writing this driver.
25 * - Jeroen Vreeken
26 */
27
28static const char version[] = "0.24";
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31#include <linux/init.h>
32#include <linux/vmalloc.h>
33#include <linux/slab.h>
34#include <linux/pagemap.h>
35#include <linux/usb.h>
36#include "se401.h"
37
38static int flickerless=0;
39static int video_nr = -1;
40
41static struct usb_device_id device_table [] = {
42 { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
43 { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
44 { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
45 { USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */
46 { USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */
47 { }
48};
49
50MODULE_DEVICE_TABLE(usb, device_table);
51
52MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
53MODULE_DESCRIPTION("SE401 USB Camera Driver");
54MODULE_LICENSE("GPL");
55module_param(flickerless, int, 0);
56MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)");
57module_param(video_nr, int, 0);
58
59static struct usb_driver se401_driver;
60
61
62/**********************************************************************
63 *
64 * Memory management
65 *
66 **********************************************************************/
67static void *rvmalloc(unsigned long size)
68{
69 void *mem;
70 unsigned long adr;
71
72 size = PAGE_ALIGN(size);
73 mem = vmalloc_32(size);
74 if (!mem)
75 return NULL;
76
77 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
78 adr = (unsigned long) mem;
79 while (size > 0) {
80 SetPageReserved(vmalloc_to_page((void *)adr));
81 adr += PAGE_SIZE;
82 size -= PAGE_SIZE;
83 }
84
85 return mem;
86}
87
88static void rvfree(void *mem, unsigned long size)
89{
90 unsigned long adr;
91
92 if (!mem)
93 return;
94
95 adr = (unsigned long) mem;
96 while ((long) size > 0) {
97 ClearPageReserved(vmalloc_to_page((void *)adr));
98 adr += PAGE_SIZE;
99 size -= PAGE_SIZE;
100 }
101 vfree(mem);
102}
103
104
105
106/****************************************************************************
107 *
108 * se401 register read/write functions
109 *
110 ***************************************************************************/
111
112static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
113 unsigned short value, unsigned char *cp, int size)
114{
115 return usb_control_msg (
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300116 se401->dev,
117 set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
118 req,
119 (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
120 value,
121 0,
122 cp,
123 size,
124 1000
125 );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126}
127
128static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
129 unsigned short param)
130{
131 /* specs say that the selector (address) should go in the value field
132 and the param in index, but in the logs of the windows driver they do
133 this the other way around...
134 */
135 return usb_control_msg (
136 se401->dev,
137 usb_sndctrlpipe(se401->dev, 0),
138 SE401_REQ_SET_EXT_FEATURE,
139 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
140 param,
141 selector,
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300142 NULL,
143 0,
144 1000
145 );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146}
147
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300148static unsigned short se401_get_feature(struct usb_se401 *se401,
149 unsigned short selector)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150{
151 /* For 'set' the selecetor should be in index, not sure if the spec is
152 wrong here to....
153 */
154 unsigned char cp[2];
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300155 usb_control_msg (
156 se401->dev,
157 usb_rcvctrlpipe(se401->dev, 0),
158 SE401_REQ_GET_EXT_FEATURE,
159 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
160 0,
161 selector,
162 cp,
163 2,
164 1000
165 );
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 return cp[0]+cp[1]*256;
167}
168
169/****************************************************************************
170 *
171 * Camera control
172 *
173 ***************************************************************************/
174
175
176static int se401_send_pict(struct usb_se401 *se401)
177{
178 se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);/* integration time low */
179 se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);/* integration time mid */
180 se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);/* integration time mid */
181 se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);/* reset level value */
182 se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);/* red color gain */
183 se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);/* green color gain */
184 se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);/* blue color gain */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300185
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 return 0;
187}
188
189static void se401_set_exposure(struct usb_se401 *se401, int brightness)
190{
191 int integration=brightness<<5;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300192
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 if (flickerless==50) {
194 integration=integration-integration%106667;
195 }
196 if (flickerless==60) {
197 integration=integration-integration%88889;
198 }
199 se401->brightness=integration>>5;
200 se401->expose_h=(integration>>16)&0xff;
201 se401->expose_m=(integration>>8)&0xff;
202 se401->expose_l=integration&0xff;
203}
204
205static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
206{
207 p->brightness=se401->brightness;
208 if (se401->enhance) {
209 p->whiteness=32768;
210 } else {
211 p->whiteness=0;
212 }
213 p->colour=65535;
214 p->contrast=65535;
215 p->hue=se401->rgain<<10;
216 p->palette=se401->palette;
217 p->depth=3; /* rgb24 */
218 return 0;
219}
220
221
222static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
223{
224 if (p->palette != VIDEO_PALETTE_RGB24)
225 return 1;
226 se401->palette=p->palette;
227 if (p->hue!=se401->hue) {
228 se401->rgain= p->hue>>10;
229 se401->bgain= 0x40-(p->hue>>10);
230 se401->hue=p->hue;
231 }
232 if (p->brightness!=se401->brightness) {
233 se401_set_exposure(se401, p->brightness);
234 }
235 if (p->whiteness>=32768) {
236 se401->enhance=1;
237 } else {
238 se401->enhance=0;
239 }
240 se401_send_pict(se401);
241 se401_send_pict(se401);
242 return 0;
243}
244
245/*
246 Hyundai have some really nice docs about this and other sensor related
247 stuff on their homepage: www.hei.co.kr
248*/
249static void se401_auto_resetlevel(struct usb_se401 *se401)
250{
251 unsigned int ahrc, alrc;
252 int oldreset=se401->resetlevel;
253
254 /* For some reason this normally read-only register doesn't get reset
255 to zero after reading them just once...
256 */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300257 se401_get_feature(se401, HV7131_REG_HIREFNOH);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 se401_get_feature(se401, HV7131_REG_HIREFNOL);
259 se401_get_feature(se401, HV7131_REG_LOREFNOH);
260 se401_get_feature(se401, HV7131_REG_LOREFNOL);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300261 ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) +
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 se401_get_feature(se401, HV7131_REG_HIREFNOL);
263 alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
264 se401_get_feature(se401, HV7131_REG_LOREFNOL);
265
266 /* Not an exact science, but it seems to work pretty well... */
267 if (alrc > 10) {
268 while (alrc>=10 && se401->resetlevel < 63) {
269 se401->resetlevel++;
270 alrc /=2;
271 }
272 } else if (ahrc > 20) {
273 while (ahrc>=20 && se401->resetlevel > 0) {
274 se401->resetlevel--;
275 ahrc /=2;
276 }
277 }
278 if (se401->resetlevel!=oldreset)
279 se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
280
281 return;
282}
283
284/* irq handler for snapshot button */
David Howells7d12e782006-10-05 14:55:46 +0100285static void se401_button_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286{
287 struct usb_se401 *se401 = urb->context;
288 int status;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300289
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 if (!se401->dev) {
291 info("ohoh: device vapourished");
292 return;
293 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300294
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 switch (urb->status) {
296 case 0:
297 /* success */
298 break;
299 case -ECONNRESET:
300 case -ENOENT:
301 case -ESHUTDOWN:
302 /* this urb is terminated, clean up */
303 dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
304 return;
305 default:
306 dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
307 goto exit;
308 }
309
310 if (urb->actual_length >=2) {
311 if (se401->button)
312 se401->buttonpressed=1;
313 }
314exit:
315 status = usb_submit_urb (urb, GFP_ATOMIC);
316 if (status)
317 err ("%s - usb_submit_urb failed with result %d",
318 __FUNCTION__, status);
319}
320
David Howells7d12e782006-10-05 14:55:46 +0100321static void se401_video_irq(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
323 struct usb_se401 *se401 = urb->context;
324 int length = urb->actual_length;
325
326 /* ohoh... */
327 if (!se401->streaming)
328 return;
329
330 if (!se401->dev) {
331 info ("ohoh: device vapourished");
332 return;
333 }
334
335 /* 0 sized packets happen if we are to fast, but sometimes the camera
336 keeps sending them forever...
337 */
338 if (length && !urb->status) {
339 se401->nullpackets=0;
340 switch(se401->scratch[se401->scratch_next].state) {
341 case BUFFER_READY:
342 case BUFFER_BUSY: {
343 se401->dropped++;
344 break;
345 }
346 case BUFFER_UNUSED: {
347 memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length);
348 se401->scratch[se401->scratch_next].state=BUFFER_READY;
349 se401->scratch[se401->scratch_next].offset=se401->bayeroffset;
350 se401->scratch[se401->scratch_next].length=length;
351 if (waitqueue_active(&se401->wq)) {
352 wake_up_interruptible(&se401->wq);
353 }
354 se401->scratch_overflow=0;
355 se401->scratch_next++;
356 if (se401->scratch_next>=SE401_NUMSCRATCH)
357 se401->scratch_next=0;
358 break;
359 }
360 }
361 se401->bayeroffset+=length;
362 if (se401->bayeroffset>=se401->cheight*se401->cwidth) {
363 se401->bayeroffset=0;
364 }
365 } else {
366 se401->nullpackets++;
367 if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
368 if (waitqueue_active(&se401->wq)) {
369 wake_up_interruptible(&se401->wq);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 }
372 }
373
374 /* Resubmit urb for new data */
375 urb->status=0;
376 urb->dev=se401->dev;
377 if(usb_submit_urb(urb, GFP_KERNEL))
378 info("urb burned down");
379 return;
380}
381
382static void se401_send_size(struct usb_se401 *se401, int width, int height)
383{
384 int i=0;
385 int mode=0x03; /* No compression */
386 int sendheight=height;
387 int sendwidth=width;
388
389 /* JangGu compression can only be used with the camera supported sizes,
390 but bayer seems to work with any size that fits on the sensor.
391 We check if we can use compression with the current size with either
392 4 or 16 times subcapturing, if not we use uncompressed bayer data
393 but this will result in cutouts of the maximum size....
394 */
395 while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height))
396 i++;
397 while (i<se401->sizes) {
398 if (se401->width[i]==width*2 && se401->height[i]==height*2) {
399 sendheight=se401->height[i];
400 sendwidth=se401->width[i];
401 mode=0x40;
402 }
403 if (se401->width[i]==width*4 && se401->height[i]==height*4) {
404 sendheight=se401->height[i];
405 sendwidth=se401->width[i];
406 mode=0x42;
407 }
408 i++;
409 }
410
411 se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0);
412 se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
413 se401_set_feature(se401, SE401_OPERATINGMODE, mode);
414
415 if (mode==0x03) {
416 se401->format=FMT_BAYER;
417 } else {
418 se401->format=FMT_JANGGU;
419 }
420
421 return;
422}
423
424/*
425 In this function se401_send_pict is called several times,
426 for some reason (depending on the state of the sensor and the phase of
427 the moon :) doing this only in either place doesn't always work...
428*/
429static int se401_start_stream(struct usb_se401 *se401)
430{
431 struct urb *urb;
432 int err=0, i;
433 se401->streaming=1;
434
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300435 se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
436 se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437
438 /* Set picture settings */
439 se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);/*windowed + pix intg */
440 se401_send_pict(se401);
441
442 se401_send_size(se401, se401->cwidth, se401->cheight);
443
444 se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0);
445
446 /* Do some memory allocation */
447 for (i=0; i<SE401_NUMFRAMES; i++) {
448 se401->frame[i].data=se401->fbuf + i * se401->maxframesize;
449 se401->frame[i].curpix=0;
450 }
451 for (i=0; i<SE401_NUMSBUF; i++) {
452 se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
Amit Choudharyfd51c692007-03-30 17:48:59 -0300453 if (!se401->sbuf[i].data) {
454 for(i = i - 1; i >= 0; i--) {
455 kfree(se401->sbuf[i].data);
456 se401->sbuf[i].data = NULL;
457 }
458 return -ENOMEM;
459 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 }
461
462 se401->bayeroffset=0;
463 se401->scratch_next=0;
464 se401->scratch_use=0;
465 se401->scratch_overflow=0;
466 for (i=0; i<SE401_NUMSCRATCH; i++) {
467 se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
Amit Choudharyfd51c692007-03-30 17:48:59 -0300468 if (!se401->scratch[i].data) {
469 for(i = i - 1; i >= 0; i--) {
470 kfree(se401->scratch[i].data);
471 se401->scratch[i].data = NULL;
472 }
473 goto nomem_sbuf;
474 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 se401->scratch[i].state=BUFFER_UNUSED;
476 }
477
478 for (i=0; i<SE401_NUMSBUF; i++) {
479 urb=usb_alloc_urb(0, GFP_KERNEL);
Amit Choudharyfd51c692007-03-30 17:48:59 -0300480 if(!urb) {
481 for(i = i - 1; i >= 0; i--) {
482 usb_kill_urb(se401->urb[i]);
483 usb_free_urb(se401->urb[i]);
484 se401->urb[i] = NULL;
485 }
486 goto nomem_scratch;
487 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
489 usb_fill_bulk_urb(urb, se401->dev,
490 usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT),
491 se401->sbuf[i].data, SE401_PACKETSIZE,
492 se401_video_irq,
493 se401);
494
495 se401->urb[i]=urb;
496
497 err=usb_submit_urb(se401->urb[i], GFP_KERNEL);
498 if(err)
499 err("urb burned down");
500 }
501
502 se401->framecount=0;
503
504 return 0;
Amit Choudharyfd51c692007-03-30 17:48:59 -0300505
506 nomem_scratch:
507 for (i=0; i<SE401_NUMSCRATCH; i++) {
508 kfree(se401->scratch[i].data);
509 se401->scratch[i].data = NULL;
510 }
511 nomem_sbuf:
512 for (i=0; i<SE401_NUMSBUF; i++) {
513 kfree(se401->sbuf[i].data);
514 se401->sbuf[i].data = NULL;
515 }
516 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517}
518
519static int se401_stop_stream(struct usb_se401 *se401)
520{
521 int i;
522
523 if (!se401->streaming || !se401->dev)
524 return 1;
525
526 se401->streaming=0;
527
528 se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
529
530 se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
531 se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
532
533 for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
534 usb_kill_urb(se401->urb[i]);
535 usb_free_urb(se401->urb[i]);
536 se401->urb[i]=NULL;
537 kfree(se401->sbuf[i].data);
538 }
539 for (i=0; i<SE401_NUMSCRATCH; i++) {
540 kfree(se401->scratch[i].data);
541 se401->scratch[i].data=NULL;
542 }
543
544 return 0;
545}
546
547static int se401_set_size(struct usb_se401 *se401, int width, int height)
548{
549 int wasstreaming=se401->streaming;
550 /* Check to see if we need to change */
551 if (se401->cwidth==width && se401->cheight==height)
552 return 0;
553
554 /* Check for a valid mode */
555 if (!width || !height)
556 return 1;
557 if ((width & 1) || (height & 1))
558 return 1;
559 if (width>se401->width[se401->sizes-1])
560 return 1;
561 if (height>se401->height[se401->sizes-1])
562 return 1;
563
564 /* Stop a current stream and start it again at the new size */
565 if (wasstreaming)
566 se401_stop_stream(se401);
567 se401->cwidth=width;
568 se401->cheight=height;
569 if (wasstreaming)
570 se401_start_stream(se401);
571 return 0;
572}
573
574
575/****************************************************************************
576 *
577 * Video Decoding
578 *
579 ***************************************************************************/
580
581/*
582 This shouldn't really be done in a v4l driver....
583 But it does make the image look a lot more usable.
584 Basically it lifts the dark pixels more than the light pixels.
585*/
586static inline void enhance_picture(unsigned char *frame, int len)
587{
588 while (len--) {
589 *frame=(((*frame^255)*(*frame^255))/255)^255;
590 frame++;
591 }
592}
593
594static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
595{
596 struct se401_frame *frame=&se401->frame[se401->curframe];
597 int linelength=se401->cwidth*3;
598
599 if (frame->curlinepix >= linelength) {
600 frame->curlinepix=0;
601 frame->curline+=linelength;
602 }
603
604 /* First three are absolute, all others relative.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300605 * Format is rgb from right to left (mirrorred image),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 * we flip it to get bgr from left to right. */
607 if (frame->curlinepix < 3) {
608 *(frame->curline-frame->curlinepix)=1+data*4;
609 } else {
610 *(frame->curline-frame->curlinepix)=
611 *(frame->curline-frame->curlinepix+3)+data*4;
612 }
613 frame->curlinepix++;
614}
615
616static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength)
617{
618 int pos=0;
619 int vlc_cod=0;
620 int vlc_size=0;
621 int vlc_data=0;
622 int bit_cur;
623 int bit;
624 data+=4;
625 while (pos < packetlength) {
626 bit_cur=8;
627 while (bit_cur && bit_exp) {
628 bit=((*data)>>(bit_cur-1))&1;
629 if (!vlc_cod) {
630 if (bit) {
631 vlc_size++;
632 } else {
633 if (!vlc_size) {
634 decode_JangGu_integrate(se401, 0);
635 } else {
636 vlc_cod=2;
637 vlc_data=0;
638 }
639 }
640 } else {
641 if (vlc_cod==2) {
642 if (!bit)
643 vlc_data = -(1<<vlc_size) + 1;
644 vlc_cod--;
645 }
646 vlc_size--;
647 vlc_data+=bit<<vlc_size;
648 if (!vlc_size) {
649 decode_JangGu_integrate(se401, vlc_data);
650 vlc_cod=0;
651 }
652 }
653 bit_cur--;
654 bit_exp--;
655 }
656 pos++;
657 data++;
658 }
659}
660
661static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer)
662{
663 unsigned char *data=buffer->data;
664 int len=buffer->length;
665 int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size;
666 int datapos=0;
667
668 /* New image? */
669 if (!se401->frame[se401->curframe].curpix) {
670 se401->frame[se401->curframe].curlinepix=0;
671 se401->frame[se401->curframe].curline=
672 se401->frame[se401->curframe].data+
673 se401->cwidth*3-1;
674 if (se401->frame[se401->curframe].grabstate==FRAME_READY)
675 se401->frame[se401->curframe].grabstate=FRAME_GRABBING;
676 se401->vlcdatapos=0;
677 }
678 while (datapos < len) {
679 size=1024-se401->vlcdatapos;
680 if (size+datapos > len)
681 size=len-datapos;
682 memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
683 se401->vlcdatapos+=size;
684 packetlength=0;
685 if (se401->vlcdatapos >= 4) {
686 bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8);
687 pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8);
688 frameinfo=se401->vlcdata[0]&0xc0;
689 packetlength=((bit_exp+47)>>4)<<1;
690 if (packetlength > 1024) {
691 se401->vlcdatapos=0;
692 datapos=len;
693 packetlength=0;
694 se401->error++;
695 se401->frame[se401->curframe].curpix=0;
696 }
697 }
698 if (packetlength && se401->vlcdatapos >= packetlength) {
699 decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength);
700 se401->frame[se401->curframe].curpix+=pix_exp*3;
701 datapos+=size-(se401->vlcdatapos-packetlength);
702 se401->vlcdatapos=0;
703 if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) {
704 if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) {
705 if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) {
706 se401->frame[se401->curframe].grabstate=FRAME_DONE;
707 se401->framecount++;
708 se401->readcount++;
709 }
710 if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
711 se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
712 }
713 } else {
714 se401->error++;
715 }
716 se401->frame[se401->curframe].curpix=0;
717 datapos=len;
718 }
719 } else {
720 datapos+=size;
721 }
722 }
723}
724
725static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer)
726{
727 unsigned char *data=buffer->data;
728 int len=buffer->length;
729 int offset=buffer->offset;
730 int datasize=se401->cwidth*se401->cheight;
731 struct se401_frame *frame=&se401->frame[se401->curframe];
732
733 unsigned char *framedata=frame->data, *curline, *nextline;
734 int width=se401->cwidth;
735 int blineoffset=0, bline;
736 int linelength=width*3, i;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300737
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 if (frame->curpix==0) {
740 if (frame->grabstate==FRAME_READY) {
741 frame->grabstate=FRAME_GRABBING;
742 }
743 frame->curline=framedata+linelength;
744 frame->curlinepix=0;
745 }
746
747 if (offset!=frame->curpix) {
748 /* Regard frame as lost :( */
749 frame->curpix=0;
750 se401->error++;
751 return;
752 }
753
754 /* Check if we have to much data */
755 if (frame->curpix+len > datasize) {
756 len=datasize-frame->curpix;
757 }
758 if (se401->cheight%4)
759 blineoffset=1;
760 bline=frame->curpix/se401->cwidth+blineoffset;
761
762 curline=frame->curline;
763 nextline=curline+linelength;
764 if (nextline >= framedata+datasize*3)
765 nextline=curline;
766 while (len) {
767 if (frame->curlinepix>=width) {
768 frame->curlinepix-=width;
769 bline=frame->curpix/width+blineoffset;
770 curline+=linelength*2;
771 nextline+=linelength*2;
772 if (curline >= framedata+datasize*3) {
773 frame->curlinepix++;
774 curline-=3;
775 nextline-=3;
776 len--;
777 data++;
778 frame->curpix++;
779 }
780 if (nextline >= framedata+datasize*3)
781 nextline=curline;
782 }
783 if ((bline&1)) {
784 if ((frame->curlinepix&1)) {
785 *(curline+2)=*data;
786 *(curline-1)=*data;
787 *(nextline+2)=*data;
788 *(nextline-1)=*data;
789 } else {
790 *(curline+1)=
791 (*(curline+1)+*data)/2;
792 *(curline-2)=
793 (*(curline-2)+*data)/2;
794 *(nextline+1)=*data;
795 *(nextline-2)=*data;
796 }
797 } else {
798 if ((frame->curlinepix&1)) {
799 *(curline+1)=
800 (*(curline+1)+*data)/2;
801 *(curline-2)=
802 (*(curline-2)+*data)/2;
803 *(nextline+1)=*data;
804 *(nextline-2)=*data;
805 } else {
806 *curline=*data;
807 *(curline-3)=*data;
808 *nextline=*data;
809 *(nextline-3)=*data;
810 }
811 }
812 frame->curlinepix++;
813 curline-=3;
814 nextline-=3;
815 len--;
816 data++;
817 frame->curpix++;
818 }
819 frame->curline=curline;
820
821 if (frame->curpix>=datasize) {
822 /* Fix the top line */
823 framedata+=linelength;
824 for (i=0; i<linelength; i++) {
825 framedata--;
826 *framedata=*(framedata+linelength);
827 }
828 /* Fix the left side (green is already present) */
829 for (i=0; i<se401->cheight; i++) {
830 *framedata=*(framedata+3);
831 *(framedata+1)=*(framedata+4);
832 *(framedata+2)=*(framedata+5);
833 framedata+=linelength;
834 }
835 frame->curpix=0;
836 frame->grabstate=FRAME_DONE;
837 se401->framecount++;
838 se401->readcount++;
839 if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
840 se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
841 }
842 }
843}
844
845static int se401_newframe(struct usb_se401 *se401, int framenr)
846{
847 DECLARE_WAITQUEUE(wait, current);
848 int errors=0;
849
850 while (se401->streaming &&
851 (se401->frame[framenr].grabstate==FRAME_READY ||
852 se401->frame[framenr].grabstate==FRAME_GRABBING) ) {
853 if(!se401->frame[framenr].curpix) {
854 errors++;
855 }
856 wait_interruptible(
857 se401->scratch[se401->scratch_use].state!=BUFFER_READY,
858 &se401->wq,
859 &wait
860 );
861 if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
862 se401->nullpackets=0;
863 info("to many null length packets, restarting capture");
864 se401_stop_stream(se401);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300865 se401_start_stream(se401);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 } else {
867 if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) {
868 se401->frame[framenr].grabstate=FRAME_ERROR;
869 return -EIO;
870 }
871 se401->scratch[se401->scratch_use].state=BUFFER_BUSY;
872 if (se401->format==FMT_JANGGU) {
873 decode_JangGu(se401, &se401->scratch[se401->scratch_use]);
874 } else {
875 decode_bayer(se401, &se401->scratch[se401->scratch_use]);
876 }
877 se401->scratch[se401->scratch_use].state=BUFFER_UNUSED;
878 se401->scratch_use++;
879 if (se401->scratch_use>=SE401_NUMSCRATCH)
880 se401->scratch_use=0;
881 if (errors > SE401_MAX_ERRORS) {
882 errors=0;
883 info("to much errors, restarting capture");
884 se401_stop_stream(se401);
885 se401_start_stream(se401);
886 }
887 }
888 }
889
890 if (se401->frame[framenr].grabstate==FRAME_DONE)
891 if (se401->enhance)
892 enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3);
893 return 0;
894}
895
896static void usb_se401_remove_disconnected (struct usb_se401 *se401)
897{
898 int i;
899
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300900 se401->dev = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901
Jesper Juhl1bc3c9e2005-04-18 17:39:34 -0700902 for (i=0; i<SE401_NUMSBUF; i++)
903 if (se401->urb[i]) {
904 usb_kill_urb(se401->urb[i]);
905 usb_free_urb(se401->urb[i]);
906 se401->urb[i] = NULL;
907 kfree(se401->sbuf[i].data);
908 }
909 for (i=0; i<SE401_NUMSCRATCH; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 kfree(se401->scratch[i].data);
911 }
912 if (se401->inturb) {
913 usb_kill_urb(se401->inturb);
914 usb_free_urb(se401->inturb);
915 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300916 info("%s disconnected", se401->camera_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300918 /* Free the memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 kfree(se401->width);
920 kfree(se401->height);
921 kfree(se401);
922}
923
924
925
926/****************************************************************************
927 *
928 * Video4Linux
929 *
930 ***************************************************************************/
931
932
933static int se401_open(struct inode *inode, struct file *file)
934{
935 struct video_device *dev = video_devdata(file);
936 struct usb_se401 *se401 = (struct usb_se401 *)dev;
937 int err = 0;
938
939 if (se401->user)
940 return -EBUSY;
941 se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
942 if (se401->fbuf)
943 file->private_data = dev;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300944 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945 err = -ENOMEM;
946 se401->user = !err;
947
948 return err;
949}
950
951static int se401_close(struct inode *inode, struct file *file)
952{
953 struct video_device *dev = file->private_data;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300954 struct usb_se401 *se401 = (struct usb_se401 *)dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955 int i;
956
957 rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300958 if (se401->removed) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 usb_se401_remove_disconnected(se401);
960 info("device unregistered");
961 } else {
962 for (i=0; i<SE401_NUMFRAMES; i++)
963 se401->frame[i].grabstate=FRAME_UNUSED;
964 if (se401->streaming)
965 se401_stop_stream(se401);
966 se401->user=0;
967 }
968 file->private_data = NULL;
969 return 0;
970}
971
972static int se401_do_ioctl(struct inode *inode, struct file *file,
973 unsigned int cmd, void *arg)
974{
975 struct video_device *vdev = file->private_data;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300976 struct usb_se401 *se401 = (struct usb_se401 *)vdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300978 if (!se401->dev)
979 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300981 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 case VIDIOCGCAP:
983 {
984 struct video_capability *b = arg;
985 strcpy(b->name, se401->camera_name);
986 b->type = VID_TYPE_CAPTURE;
987 b->channels = 1;
988 b->audios = 0;
989 b->maxwidth = se401->width[se401->sizes-1];
990 b->maxheight = se401->height[se401->sizes-1];
991 b->minwidth = se401->width[0];
992 b->minheight = se401->height[0];
993 return 0;
994 }
995 case VIDIOCGCHAN:
996 {
997 struct video_channel *v = arg;
998
999 if (v->channel != 0)
1000 return -EINVAL;
1001 v->flags = 0;
1002 v->tuners = 0;
1003 v->type = VIDEO_TYPE_CAMERA;
1004 strcpy(v->name, "Camera");
1005 return 0;
1006 }
1007 case VIDIOCSCHAN:
1008 {
1009 struct video_channel *v = arg;
1010
1011 if (v->channel != 0)
1012 return -EINVAL;
1013 return 0;
1014 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001015 case VIDIOCGPICT:
1016 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 struct video_picture *p = arg;
1018
1019 se401_get_pict(se401, p);
1020 return 0;
1021 }
1022 case VIDIOCSPICT:
1023 {
1024 struct video_picture *p = arg;
1025
1026 if (se401_set_pict(se401, p))
1027 return -EINVAL;
1028 return 0;
1029 }
1030 case VIDIOCSWIN:
1031 {
1032 struct video_window *vw = arg;
1033
1034 if (vw->flags)
1035 return -EINVAL;
1036 if (vw->clipcount)
1037 return -EINVAL;
1038 if (se401_set_size(se401, vw->width, vw->height))
1039 return -EINVAL;
1040 return 0;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 case VIDIOCGWIN:
1043 {
1044 struct video_window *vw = arg;
1045
1046 vw->x = 0; /* FIXME */
1047 vw->y = 0;
1048 vw->chromakey = 0;
1049 vw->flags = 0;
1050 vw->clipcount = 0;
1051 vw->width = se401->cwidth;
1052 vw->height = se401->cheight;
1053 return 0;
1054 }
1055 case VIDIOCGMBUF:
1056 {
1057 struct video_mbuf *vm = arg;
1058 int i;
1059
1060 memset(vm, 0, sizeof(*vm));
1061 vm->size = SE401_NUMFRAMES * se401->maxframesize;
1062 vm->frames = SE401_NUMFRAMES;
1063 for (i=0; i<SE401_NUMFRAMES; i++)
1064 vm->offsets[i] = se401->maxframesize * i;
1065 return 0;
1066 }
1067 case VIDIOCMCAPTURE:
1068 {
1069 struct video_mmap *vm = arg;
1070
1071 if (vm->format != VIDEO_PALETTE_RGB24)
1072 return -EINVAL;
1073 if (vm->frame >= SE401_NUMFRAMES)
1074 return -EINVAL;
1075 if (se401->frame[vm->frame].grabstate != FRAME_UNUSED)
1076 return -EBUSY;
1077
1078 /* Is this according to the v4l spec??? */
1079 if (se401_set_size(se401, vm->width, vm->height))
1080 return -EINVAL;
1081 se401->frame[vm->frame].grabstate=FRAME_READY;
1082
1083 if (!se401->streaming)
1084 se401_start_stream(se401);
1085
1086 /* Set the picture properties */
1087 if (se401->framecount==0)
1088 se401_send_pict(se401);
1089 /* Calibrate the reset level after a few frames. */
1090 if (se401->framecount%20==1)
1091 se401_auto_resetlevel(se401);
1092
1093 return 0;
1094 }
1095 case VIDIOCSYNC:
1096 {
1097 int *frame = arg;
1098 int ret=0;
1099
1100 if(*frame <0 || *frame >= SE401_NUMFRAMES)
1101 return -EINVAL;
1102
1103 ret=se401_newframe(se401, *frame);
1104 se401->frame[*frame].grabstate=FRAME_UNUSED;
1105 return ret;
1106 }
1107 case VIDIOCGFBUF:
1108 {
1109 struct video_buffer *vb = arg;
1110
1111 memset(vb, 0, sizeof(*vb));
1112 return 0;
1113 }
1114 case VIDIOCKEY:
1115 return 0;
1116 case VIDIOCCAPTURE:
1117 return -EINVAL;
1118 case VIDIOCSFBUF:
1119 return -EINVAL;
1120 case VIDIOCGTUNER:
1121 case VIDIOCSTUNER:
1122 return -EINVAL;
1123 case VIDIOCGFREQ:
1124 case VIDIOCSFREQ:
1125 return -EINVAL;
1126 case VIDIOCGAUDIO:
1127 case VIDIOCSAUDIO:
1128 return -EINVAL;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001129 default:
1130 return -ENOIOCTLCMD;
1131 } /* end switch */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001133 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134}
1135
1136static int se401_ioctl(struct inode *inode, struct file *file,
1137 unsigned int cmd, unsigned long arg)
1138{
1139 return video_usercopy(inode, file, cmd, arg, se401_do_ioctl);
1140}
1141
1142static ssize_t se401_read(struct file *file, char __user *buf,
1143 size_t count, loff_t *ppos)
1144{
1145 int realcount=count, ret=0;
1146 struct video_device *dev = file->private_data;
1147 struct usb_se401 *se401 = (struct usb_se401 *)dev;
1148
1149
1150 if (se401->dev == NULL)
1151 return -EIO;
1152 if (realcount > se401->cwidth*se401->cheight*3)
1153 realcount=se401->cwidth*se401->cheight*3;
1154
1155 /* Shouldn't happen: */
1156 if (se401->frame[0].grabstate==FRAME_GRABBING)
1157 return -EBUSY;
1158 se401->frame[0].grabstate=FRAME_READY;
1159 se401->frame[1].grabstate=FRAME_UNUSED;
1160 se401->curframe=0;
1161
1162 if (!se401->streaming)
1163 se401_start_stream(se401);
1164
1165 /* Set the picture properties */
1166 if (se401->framecount==0)
1167 se401_send_pict(se401);
1168 /* Calibrate the reset level after a few frames. */
1169 if (se401->framecount%20==1)
1170 se401_auto_resetlevel(se401);
1171
1172 ret=se401_newframe(se401, 0);
1173
1174 se401->frame[0].grabstate=FRAME_UNUSED;
1175 if (ret)
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001176 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 if (copy_to_user(buf, se401->frame[0].data, realcount))
1178 return -EFAULT;
1179
1180 return realcount;
1181}
1182
1183static int se401_mmap(struct file *file, struct vm_area_struct *vma)
1184{
1185 struct video_device *dev = file->private_data;
1186 struct usb_se401 *se401 = (struct usb_se401 *)dev;
1187 unsigned long start = vma->vm_start;
1188 unsigned long size = vma->vm_end-vma->vm_start;
1189 unsigned long page, pos;
1190
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001191 mutex_lock(&se401->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
1193 if (se401->dev == NULL) {
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001194 mutex_unlock(&se401->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 return -EIO;
1196 }
1197 if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001198 mutex_unlock(&se401->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 return -EINVAL;
1200 }
1201 pos = (unsigned long)se401->fbuf;
1202 while (size > 0) {
1203 page = vmalloc_to_pfn((void *)pos);
1204 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001205 mutex_unlock(&se401->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 return -EAGAIN;
1207 }
1208 start += PAGE_SIZE;
1209 pos += PAGE_SIZE;
1210 if (size > PAGE_SIZE)
1211 size -= PAGE_SIZE;
1212 else
1213 size = 0;
1214 }
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001215 mutex_unlock(&se401->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001217 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218}
1219
Arjan van de Venfa027c22007-02-12 00:55:33 -08001220static const struct file_operations se401_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 .owner = THIS_MODULE,
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001222 .open = se401_open,
1223 .release = se401_close,
1224 .read = se401_read,
1225 .mmap = se401_mmap,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 .ioctl = se401_ioctl,
Arnd Bergmann0d0fbf82006-01-09 15:24:57 -02001227 .compat_ioctl = v4l_compat_ioctl32,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 .llseek = no_llseek,
1229};
1230static struct video_device se401_template = {
1231 .owner = THIS_MODULE,
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001232 .name = "se401 USB camera",
1233 .type = VID_TYPE_CAPTURE,
1234 .hardware = VID_HARDWARE_SE401,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235 .fops = &se401_fops,
1236};
1237
1238
1239
1240/***************************/
1241static int se401_init(struct usb_se401 *se401, int button)
1242{
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001243 int i=0, rc;
1244 unsigned char cp[0x40];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 char temp[200];
1246
1247 /* led on */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001248 se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250 /* get camera descriptor */
1251 rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp));
1252 if (cp[1]!=0x41) {
1253 err("Wrong descriptor type");
1254 return 1;
1255 }
1256 sprintf (temp, "ExtraFeatures: %d", cp[3]);
1257
1258 se401->sizes=cp[4]+cp[5]*256;
1259 se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
1260 if (!se401->width)
1261 return 1;
1262 se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
1263 if (!se401->height) {
1264 kfree(se401->width);
1265 return 1;
1266 }
1267 for (i=0; i<se401->sizes; i++) {
1268 se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256;
1269 se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256;
1270 }
1271 sprintf (temp, "%s Sizes:", temp);
1272 for (i=0; i<se401->sizes; i++) {
1273 sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
1274 }
1275 info("%s", temp);
1276 se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
1277
1278 rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
1279 se401->cwidth=cp[0]+cp[1]*256;
1280 rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
1281 se401->cheight=cp[0]+cp[1]*256;
1282
1283 if (!cp[2] && SE401_FORMAT_BAYER) {
1284 err("Bayer format not supported!");
1285 return 1;
1286 }
1287 /* set output mode (BAYER) */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001288 se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
1290 rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
1291 se401->brightness=cp[0]+cp[1]*256;
1292 /* some default values */
1293 se401->resetlevel=0x2d;
1294 se401->rgain=0x20;
1295 se401->ggain=0x20;
1296 se401->bgain=0x20;
1297 se401_set_exposure(se401, 20000);
1298 se401->palette=VIDEO_PALETTE_RGB24;
1299 se401->enhance=1;
1300 se401->dropped=0;
1301 se401->error=0;
1302 se401->framecount=0;
1303 se401->readcount=0;
1304
1305 /* Start interrupt transfers for snapshot button */
1306 if (button) {
1307 se401->inturb=usb_alloc_urb(0, GFP_KERNEL);
1308 if (!se401->inturb) {
1309 info("Allocation of inturb failed");
1310 return 1;
1311 }
1312 usb_fill_int_urb(se401->inturb, se401->dev,
1313 usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT),
1314 &se401->button, sizeof(se401->button),
1315 se401_button_irq,
1316 se401,
1317 8
1318 );
1319 if (usb_submit_urb(se401->inturb, GFP_KERNEL)) {
1320 info("int urb burned down");
1321 return 1;
1322 }
1323 } else
1324 se401->inturb=NULL;
1325
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001326 /* Flash the led */
1327 se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
1328 se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
1329 se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330 se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
1331
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001332 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333}
1334
1335static int se401_probe(struct usb_interface *intf,
1336 const struct usb_device_id *id)
1337{
1338 struct usb_device *dev = interface_to_usbdev(intf);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001339 struct usb_interface_descriptor *interface;
1340 struct usb_se401 *se401;
1341 char *camera_name=NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 int button=1;
1343
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001344 /* We don't handle multi-config cameras */
1345 if (dev->descriptor.bNumConfigurations != 1)
1346 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001348 interface = &intf->cur_altsetting->desc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001350 /* Is it an se401? */
1351 if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 &&
1352 le16_to_cpu(dev->descriptor.idProduct) == 0x0004) {
1353 camera_name="Endpoints/Aox SE401";
1354 } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 &&
1355 le16_to_cpu(dev->descriptor.idProduct) == 0x030b) {
1356 camera_name="Philips PCVC665K";
1357 } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 le16_to_cpu(dev->descriptor.idProduct) == 0x5001) {
1359 camera_name="Kensington VideoCAM 67014";
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001360 } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 le16_to_cpu(dev->descriptor.idProduct) == 0x5002) {
1362 camera_name="Kensington VideoCAM 6701(5/7)";
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001363 } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 le16_to_cpu(dev->descriptor.idProduct) == 0x5003) {
1365 camera_name="Kensington VideoCAM 67016";
1366 button=0;
1367 } else
1368 return -ENODEV;
1369
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001370 /* Checking vendor/product should be enough, but what the hell */
1371 if (interface->bInterfaceClass != 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 return -ENODEV;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001373 if (interface->bInterfaceSubClass != 0x00)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 return -ENODEV;
1375
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001376 /* We found one */
1377 info("SE401 camera found: %s", camera_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001379 if ((se401 = kzalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
1380 err("couldn't kmalloc se401 struct");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 return -ENOMEM;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001384 se401->dev = dev;
1385 se401->iface = interface->bInterfaceNumber;
1386 se401->camera_name = camera_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387
1388 info("firmware version: %02x", le16_to_cpu(dev->descriptor.bcdDevice) & 255);
1389
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001390 if (se401_init(se401, button)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 kfree(se401);
1392 return -EIO;
1393 }
1394
1395 memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
1396 memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
1397 init_waitqueue_head(&se401->wq);
Arjan van de Ven4186ecf2006-01-11 15:55:29 +01001398 mutex_init(&se401->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 wmb();
1400
1401 if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
1402 kfree(se401);
1403 err("video_register_device failed");
1404 return -EIO;
1405 }
1406 info("registered new video device: video%d", se401->vdev.minor);
1407
1408 usb_set_intfdata (intf, se401);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001409 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410}
1411
1412static void se401_disconnect(struct usb_interface *intf)
1413{
1414 struct usb_se401 *se401 = usb_get_intfdata (intf);
1415
1416 usb_set_intfdata (intf, NULL);
1417 if (se401) {
1418 video_unregister_device(&se401->vdev);
1419 if (!se401->user){
1420 usb_se401_remove_disconnected(se401);
1421 } else {
1422 se401->frame[0].grabstate = FRAME_ERROR;
1423 se401->frame[0].grabstate = FRAME_ERROR;
1424
1425 se401->streaming = 0;
1426
1427 wake_up_interruptible(&se401->wq);
1428 se401->removed = 1;
1429 }
1430 }
1431}
1432
1433static struct usb_driver se401_driver = {
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001434 .name = "se401",
1435 .id_table = device_table,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001436 .probe = se401_probe,
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001437 .disconnect = se401_disconnect,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438};
1439
1440
1441
1442/****************************************************************************
1443 *
1444 * Module routines
1445 *
1446 ***************************************************************************/
1447
1448static int __init usb_se401_init(void)
1449{
1450 info("SE401 usb camera driver version %s registering", version);
1451 if (flickerless)
1452 if (flickerless!=50 && flickerless!=60) {
1453 info("Invallid flickerless value, use 0, 50 or 60.");
1454 return -1;
1455 }
1456 return usb_register(&se401_driver);
1457}
1458
1459static void __exit usb_se401_exit(void)
1460{
1461 usb_deregister(&se401_driver);
1462 info("SE401 driver deregistered");
1463}
1464
1465module_init(usb_se401_init);
1466module_exit(usb_se401_exit);