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
28static const char version[] = "0.23";
29
30#include <linux/config.h>
31#include <linux/module.h>
32#include <linux/version.h>
33#include <linux/init.h>
34#include <linux/fs.h>
35#include <linux/vmalloc.h>
36#include <linux/slab.h>
37#include <linux/proc_fs.h>
38#include <linux/pagemap.h>
39#include <linux/usb.h>
40#include <asm/io.h>
41#include <asm/semaphore.h>
42#include <linux/wrapper.h>
43
44#include "se401.h"
45
46static int flickerless=0;
47static int video_nr = -1;
48
49static struct usb_device_id device_table [] = {
50 { USB_DEVICE(0x03e8, 0x0004) },
51 { USB_DEVICE(0x0471, 0x030b) },
52 { USB_DEVICE(0x047d, 0x5001) },
53 { USB_DEVICE(0x047d, 0x5002) },
54 { USB_DEVICE(0x047d, 0x5003) },
55 { }
56};
57
58MODULE_DEVICE_TABLE(usb, device_table);
59
60MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
61MODULE_DESCRIPTION("SE401 USB Camera Driver");
62MODULE_LICENSE("GPL");
63MODULE_PARM(flickerless, "i");
64MODULE_PARM_DESC(flickerless, "Net frequency to adjust exposure time to (0/50/60)");
65MODULE_PARM(video_nr, "i");
66EXPORT_NO_SYMBOLS;
67
68
69static struct usb_driver se401_driver;
70
71
72
73
74
75
76
77
78
79
80
81static inline unsigned long kvirt_to_pa(unsigned long adr)
82{
83 unsigned long kva, ret;
84
85 kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
86 kva |= adr & (PAGE_SIZE-1);
87 ret = __pa(kva);
88 return ret;
89}
90
91static void *rvmalloc(unsigned long size)
92{
93 void *mem;
94 unsigned long adr;
95
96 size = PAGE_ALIGN(size);
97 mem = vmalloc_32(size);
98 if (!mem)
99 return NULL;
100
101 memset(mem, 0, size);
102 adr = (unsigned long) mem;
103 while (size > 0) {
104 mem_map_reserve(vmalloc_to_page((void *)adr));
105 adr += PAGE_SIZE;
106 size -= PAGE_SIZE;
107 }
108
109 return mem;
110}
111
112static void rvfree(void *mem, unsigned long size)
113{
114 unsigned long adr;
115
116 if (!mem)
117 return;
118
119 adr = (unsigned long) mem;
120 while ((long) size > 0) {
121 mem_map_unreserve(vmalloc_to_page((void *)adr));
122 adr += PAGE_SIZE;
123 size -= PAGE_SIZE;
124 }
125 vfree(mem);
126}
127
128
129
130
131
132
133
134
135
136#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
137
138static struct proc_dir_entry *se401_proc_entry = NULL;
139extern struct proc_dir_entry *video_proc_entry;
140
141#define YES_NO(x) ((x) ? "yes" : "no")
142
143static int se401_read_proc(char *page, char **start, off_t off, int count,
144 int *eof, void *data)
145{
146 char *out = page;
147 int i, len;
148 struct usb_se401 *se401 = data;
149
150
151
152 out+=sprintf(out, "driver_version : %s\n", version);
153 out+=sprintf(out, "model : %s\n", se401->camera_name);
154 out+=sprintf(out, "in use : %s\n", YES_NO (se401->user));
155 out+=sprintf(out, "streaming : %s\n", YES_NO (se401->streaming));
156 out+=sprintf(out, "button state : %s\n", YES_NO (se401->button));
157 out+=sprintf(out, "button pressed : %s\n", YES_NO (se401->buttonpressed));
158 out+=sprintf(out, "num_frames : %d\n", SE401_NUMFRAMES);
159
160 out+=sprintf(out, "Sizes :");
161 for (i=0; i<se401->sizes; i++) {
162 out+=sprintf(out, " %dx%d", se401->width[i],
163 se401->height[i]);
164 }
165 out+=sprintf(out, "\n");
166
167 out+=sprintf(out, "Frames total : %d\n", se401->readcount);
168 out+=sprintf(out, "Frames read : %d\n", se401->framecount);
169 out+=sprintf(out, "Packets dropped : %d\n", se401->dropped);
170 out+=sprintf(out, "Decoding Errors : %d\n", se401->error);
171
172 len = out - page;
173 len -= off;
174 if (len < count) {
175 *eof = 1;
176 if (len <= 0) return 0;
177 } else
178 len = count;
179
180 *start = page + off;
181
182 return len;
183}
184
185static int se401_write_proc(struct file *file, const char *buffer,
186 unsigned long count, void *data)
187{
188 return -EINVAL;
189}
190
191static void create_proc_se401_cam (struct usb_se401 *se401)
192{
193 char name[7];
194 struct proc_dir_entry *ent;
195
196 if (!se401_proc_entry || !se401)
197 return;
198
199 sprintf (name, "video%d", se401->vdev.minor);
200
201 ent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
202 se401_proc_entry);
203
204 if (!ent)
205 return;
206
207 ent->data = se401;
208 ent->read_proc = se401_read_proc;
209 ent->write_proc = se401_write_proc;
210 se401->proc_entry = ent;
211}
212
213static void destroy_proc_se401_cam (struct usb_se401 *se401)
214{
215
216 char name[9];
217
218 if (!se401 || !se401->proc_entry)
219 return;
220
221 sprintf(name, "video%d", se401->vdev.minor);
222 remove_proc_entry(name, se401_proc_entry);
223 se401->proc_entry = NULL;
224}
225
226static void proc_se401_create (void)
227{
228 if (video_proc_entry == NULL) {
229 err("/proc/video/ doesn't exist");
230 return;
231 }
232
233 se401_proc_entry=create_proc_entry("se401", S_IFDIR, video_proc_entry);
234
235 if (se401_proc_entry)
236 se401_proc_entry->owner = THIS_MODULE;
237 else
238 err("Unable to initialize /proc/video/se401");
239}
240
241static void proc_se401_destroy(void)
242{
243 if (se401_proc_entry == NULL)
244 return;
245
246 remove_proc_entry("se401", video_proc_entry);
247}
248#endif
249
250
251
252
253
254
255
256
257static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
258 unsigned short value, unsigned char *cp, int size)
259{
260 return usb_control_msg (
261 se401->dev,
262 set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
263 req,
264 (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
265 value,
266 0,
267 cp,
268 size,
269 HZ
270 );
271}
272
273static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
274 unsigned short param)
275{
276
277
278
279
280 return usb_control_msg (
281 se401->dev,
282 usb_sndctrlpipe(se401->dev, 0),
283 SE401_REQ_SET_EXT_FEATURE,
284 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
285 param,
286 selector,
287 NULL,
288 0,
289 HZ
290 );
291}
292
293static unsigned short se401_get_feature(struct usb_se401 *se401,
294 unsigned short selector)
295{
296
297
298
299 unsigned char cp[2];
300 usb_control_msg (
301 se401->dev,
302 usb_rcvctrlpipe(se401->dev, 0),
303 SE401_REQ_GET_EXT_FEATURE,
304 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
305 0,
306 selector,
307 cp,
308 2,
309 HZ
310 );
311 return cp[0]+cp[1]*256;
312}
313
314
315
316
317
318
319
320
321static int se401_send_pict(struct usb_se401 *se401)
322{
323 se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);
324 se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);
325 se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);
326 se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
327 se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);
328 se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);
329 se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);
330
331 return 0;
332}
333
334static void se401_set_exposure(struct usb_se401 *se401, int brightness)
335{
336 int integration=brightness<<5;
337
338 if (flickerless==50) {
339 integration=integration-integration%106667;
340 }
341 if (flickerless==60) {
342 integration=integration-integration%88889;
343 }
344 se401->brightness=integration>>5;
345 se401->expose_h=(integration>>16)&0xff;
346 se401->expose_m=(integration>>8)&0xff;
347 se401->expose_l=integration&0xff;
348}
349
350static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
351{
352 p->brightness=se401->brightness;
353 if (se401->enhance) {
354 p->whiteness=32768;
355 } else {
356 p->whiteness=0;
357 }
358 p->colour=65535;
359 p->contrast=65535;
360 p->hue=se401->rgain<<10;
361 p->palette=se401->palette;
362 p->depth=3;
363 return 0;
364}
365
366
367static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
368{
369 if (p->palette != VIDEO_PALETTE_RGB24)
370 return 1;
371 se401->palette=p->palette;
372 if (p->hue!=se401->hue) {
373 se401->rgain= p->hue>>10;
374 se401->bgain= 0x40-(p->hue>>10);
375 se401->hue=p->hue;
376 }
377 if (p->brightness!=se401->brightness) {
378 se401_set_exposure(se401, p->brightness);
379 }
380 if (p->whiteness>=32768) {
381 se401->enhance=1;
382 } else {
383 se401->enhance=0;
384 }
385 se401_send_pict(se401);
386 se401_send_pict(se401);
387 return 0;
388}
389
390
391
392
393
394static void se401_auto_resetlevel(struct usb_se401 *se401)
395{
396 unsigned int ahrc, alrc;
397 int oldreset=se401->resetlevel;
398
399
400
401
402 se401_get_feature(se401, HV7131_REG_HIREFNOH);
403 se401_get_feature(se401, HV7131_REG_HIREFNOL);
404 se401_get_feature(se401, HV7131_REG_LOREFNOH);
405 se401_get_feature(se401, HV7131_REG_LOREFNOL);
406 ahrc=256*se401_get_feature(se401, HV7131_REG_HIREFNOH) +
407 se401_get_feature(se401, HV7131_REG_HIREFNOL);
408 alrc=256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
409 se401_get_feature(se401, HV7131_REG_LOREFNOL);
410
411
412 if (alrc > 10) {
413 while (alrc>=10 && se401->resetlevel < 63) {
414 se401->resetlevel++;
415 alrc /=2;
416 }
417 } else if (ahrc > 20) {
418 while (ahrc>=20 && se401->resetlevel > 0) {
419 se401->resetlevel--;
420 ahrc /=2;
421 }
422 }
423 if (se401->resetlevel!=oldreset)
424 se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
425
426 return;
427}
428
429
430static void se401_button_irq(struct urb *urb)
431{
432 struct usb_se401 *se401 = urb->context;
433
434 if (!se401->dev) {
435 info("ohoh: device vapourished");
436 return;
437 }
438
439 if (urb->actual_length >=2 && !urb->status) {
440 if (se401->button)
441 se401->buttonpressed=1;
442 }
443}
444
445static void se401_video_irq(struct urb *urb)
446{
447 struct usb_se401 *se401 = urb->context;
448 int length = urb->actual_length;
449
450
451 if (!se401->streaming)
452 return;
453
454 if (!se401->dev) {
455 info ("ohoh: device vapourished");
456 return;
457 }
458
459
460
461
462 if (length && !urb->status) {
463 se401->nullpackets=0;
464 switch(se401->scratch[se401->scratch_next].state) {
465 case BUFFER_READY:
466 case BUFFER_BUSY: {
467 se401->dropped++;
468 break;
469 }
470 case BUFFER_UNUSED: {
471 memcpy(se401->scratch[se401->scratch_next].data, (unsigned char *)urb->transfer_buffer, length);
472 se401->scratch[se401->scratch_next].state=BUFFER_READY;
473 se401->scratch[se401->scratch_next].offset=se401->bayeroffset;
474 se401->scratch[se401->scratch_next].length=length;
475 if (waitqueue_active(&se401->wq)) {
476 wake_up_interruptible(&se401->wq);
477 }
478 se401->scratch_overflow=0;
479 se401->scratch_next++;
480 if (se401->scratch_next>=SE401_NUMSCRATCH)
481 se401->scratch_next=0;;
482 break;
483 }
484 }
485 se401->bayeroffset+=length;
486 if (se401->bayeroffset>=se401->cheight*se401->cwidth) {
487 se401->bayeroffset=0;
488 }
489 } else {
490 se401->nullpackets++;
491 if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
492 if (waitqueue_active(&se401->wq)) {
493 wake_up_interruptible(&se401->wq);
494 }
495 }
496 }
497
498
499 urb->status=0;
500 urb->dev=se401->dev;
501 if(usb_submit_urb(urb))
502 info("urb burned down");
503 return;
504}
505
506static void se401_send_size(struct usb_se401 *se401, int width, int height)
507{
508 int i=0;
509 int mode=0x03;
510 int sendheight=height;
511 int sendwidth=width;
512
513
514
515
516
517
518
519 while (i<se401->sizes && !(se401->width[i]==width && se401->height[i]==height))
520 i++;
521 while (i<se401->sizes) {
522 if (se401->width[i]==width*2 && se401->height[i]==height*2) {
523 sendheight=se401->height[i];
524 sendwidth=se401->width[i];
525 mode=0x40;
526 }
527 if (se401->width[i]==width*4 && se401->height[i]==height*4) {
528 sendheight=se401->height[i];
529 sendwidth=se401->width[i];
530 mode=0x42;
531 }
532 i++;
533 }
534
535 se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0);
536 se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
537 se401_set_feature(se401, SE401_OPERATINGMODE, mode);
538
539 if (mode==0x03) {
540 se401->format=FMT_BAYER;
541 } else {
542 se401->format=FMT_JANGGU;
543 }
544
545 return;
546}
547
548
549
550
551
552
553static int se401_start_stream(struct usb_se401 *se401)
554{
555 struct urb *urb;
556 int err=0, i;
557 se401->streaming=1;
558
559 se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
560 se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
561
562
563 se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);
564 se401_send_pict(se401);
565
566 se401_send_size(se401, se401->cwidth, se401->cheight);
567
568 se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE, 0, NULL, 0);
569
570
571 for (i=0; i<SE401_NUMFRAMES; i++) {
572 se401->frame[i].data=se401->fbuf + i * se401->maxframesize;
573 se401->frame[i].curpix=0;
574 }
575 for (i=0; i<SE401_NUMSBUF; i++) {
576 se401->sbuf[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
577 }
578
579 se401->bayeroffset=0;
580 se401->scratch_next=0;
581 se401->scratch_use=0;
582 se401->scratch_overflow=0;
583 for (i=0; i<SE401_NUMSCRATCH; i++) {
584 se401->scratch[i].data=kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
585 se401->scratch[i].state=BUFFER_UNUSED;
586 }
587
588 for (i=0; i<SE401_NUMSBUF; i++) {
589 urb=usb_alloc_urb(0);
590 if(!urb)
591 return -ENOMEM;
592
593 FILL_BULK_URB(urb, se401->dev,
594 usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT),
595 se401->sbuf[i].data, SE401_PACKETSIZE,
596 se401_video_irq,
597 se401);
598 urb->transfer_flags |= USB_QUEUE_BULK;
599
600 se401->urb[i]=urb;
601
602 err=usb_submit_urb(se401->urb[i]);
603 if(err)
604 err("urb burned down");
605 }
606
607 se401->framecount=0;
608
609 return 0;
610}
611
612static int se401_stop_stream(struct usb_se401 *se401)
613{
614 int i;
615
616 if (!se401->streaming || !se401->dev)
617 return 1;
618
619 se401->streaming=0;
620
621 se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
622
623 se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
624 se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
625
626 for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
627 se401->urb[i]->next=NULL;
628 usb_unlink_urb(se401->urb[i]);
629 usb_free_urb(se401->urb[i]);
630 se401->urb[i]=NULL;
631 kfree(se401->sbuf[i].data);
632 }
633 for (i=0; i<SE401_NUMSCRATCH; i++) {
634 kfree(se401->scratch[i].data);
635 se401->scratch[i].data=NULL;
636 }
637
638 return 0;
639}
640
641static int se401_set_size(struct usb_se401 *se401, int width, int height)
642{
643 int wasstreaming=se401->streaming;
644
645 if (se401->cwidth==width && se401->cheight==height)
646 return 0;
647
648
649 if (width <= 0 || height <= 0)
650 return 1;
651 if ((width & 1) || (height & 1))
652 return 1;
653 if (width>se401->width[se401->sizes-1])
654 return 1;
655 if (height>se401->height[se401->sizes-1])
656 return 1;
657
658
659 if (wasstreaming)
660 se401_stop_stream(se401);
661 se401->cwidth=width;
662 se401->cheight=height;
663 if (wasstreaming)
664 se401_start_stream(se401);
665 return 0;
666}
667
668
669
670
671
672
673
674
675
676
677
678
679
680static inline void enhance_picture(unsigned char *frame, int len)
681{
682 while (len--) {
683 *frame=(((*frame^255)*(*frame^255))/255)^255;
684 frame++;
685 }
686}
687
688static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
689{
690 struct se401_frame *frame=&se401->frame[se401->curframe];
691 int linelength=se401->cwidth*3;
692
693 if (frame->curlinepix >= linelength) {
694 frame->curlinepix=0;
695 frame->curline+=linelength;
696 }
697
698
699
700
701 if (frame->curlinepix < 3) {
702 *(frame->curline-frame->curlinepix)=1+data*4;
703 } else {
704 *(frame->curline-frame->curlinepix)=
705 *(frame->curline-frame->curlinepix+3)+data*4;
706 }
707 frame->curlinepix++;
708}
709
710static inline void decode_JangGu_vlc (struct usb_se401 *se401, unsigned char *data, int bit_exp, int packetlength)
711{
712 int pos=0;
713 int vlc_cod=0;
714 int vlc_size=0;
715 int vlc_data=0;
716 int bit_cur;
717 int bit;
718 data+=4;
719 while (pos < packetlength) {
720 bit_cur=8;
721 while (bit_cur && bit_exp) {
722 bit=((*data)>>(bit_cur-1))&1;
723 if (!vlc_cod) {
724 if (bit) {
725 vlc_size++;
726 } else {
727 if (!vlc_size) {
728 decode_JangGu_integrate(se401, 0);
729 } else {
730 vlc_cod=2;
731 vlc_data=0;
732 }
733 }
734 } else {
735 if (vlc_cod==2) {
736 if (!bit) vlc_data=-(1<<vlc_size)+1;
737 vlc_cod--;
738 }
739 vlc_size--;
740 vlc_data+=bit<<vlc_size;
741 if (!vlc_size) {
742 decode_JangGu_integrate(se401, vlc_data);
743 vlc_cod=0;
744 }
745 }
746 bit_cur--;
747 bit_exp--;
748 }
749 pos++;
750 data++;
751 }
752}
753
754static inline void decode_JangGu (struct usb_se401 *se401, struct se401_scratch *buffer)
755{
756 unsigned char *data=buffer->data;
757 int len=buffer->length;
758 int bit_exp=0, pix_exp=0, frameinfo=0, packetlength=0, size;
759 int datapos=0;
760
761
762 if (!se401->frame[se401->curframe].curpix) {
763 se401->frame[se401->curframe].curlinepix=0;
764 se401->frame[se401->curframe].curline=
765 se401->frame[se401->curframe].data+
766 se401->cwidth*3-1;
767 if (se401->frame[se401->curframe].grabstate==FRAME_READY)
768 se401->frame[se401->curframe].grabstate=FRAME_GRABBING;
769 se401->vlcdatapos=0;
770 }
771 while (datapos < len) {
772 size=1024-se401->vlcdatapos;
773 if (size+datapos > len)
774 size=len-datapos;
775 memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
776 se401->vlcdatapos+=size;
777 packetlength=0;
778 if (se401->vlcdatapos >= 4) {
779 bit_exp=se401->vlcdata[3]+(se401->vlcdata[2]<<8);
780 pix_exp=se401->vlcdata[1]+((se401->vlcdata[0]&0x3f)<<8);
781 frameinfo=se401->vlcdata[0]&0xc0;
782 packetlength=((bit_exp+47)>>4)<<1;
783 if (packetlength > 1024) {
784 se401->vlcdatapos=0;
785 datapos=len;
786 packetlength=0;
787 se401->error++;
788 se401->frame[se401->curframe].curpix=0;
789 }
790 }
791 if (packetlength && se401->vlcdatapos >= packetlength) {
792 decode_JangGu_vlc(se401, se401->vlcdata, bit_exp, packetlength);
793 se401->frame[se401->curframe].curpix+=pix_exp*3;
794 datapos+=size-(se401->vlcdatapos-packetlength);
795 se401->vlcdatapos=0;
796 if (se401->frame[se401->curframe].curpix>=se401->cwidth*se401->cheight*3) {
797 if (se401->frame[se401->curframe].curpix==se401->cwidth*se401->cheight*3) {
798 if (se401->frame[se401->curframe].grabstate==FRAME_GRABBING) {
799 se401->frame[se401->curframe].grabstate=FRAME_DONE;
800 se401->framecount++;
801 se401->readcount++;
802 }
803 if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
804 se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
805 }
806 } else {
807 se401->error++;
808 }
809 se401->frame[se401->curframe].curpix=0;
810 datapos=len;
811 }
812 } else {
813 datapos+=size;
814 }
815 }
816}
817
818static inline void decode_bayer (struct usb_se401 *se401, struct se401_scratch *buffer)
819{
820 unsigned char *data=buffer->data;
821 int len=buffer->length;
822 int offset=buffer->offset;
823 int datasize=se401->cwidth*se401->cheight;
824 struct se401_frame *frame=&se401->frame[se401->curframe];
825
826 unsigned char *framedata=frame->data, *curline, *nextline;
827 int width=se401->cwidth;
828 int blineoffset=0, bline;
829 int linelength=width*3, i;
830
831
832 if (frame->curpix==0) {
833 if (frame->grabstate==FRAME_READY) {
834 frame->grabstate=FRAME_GRABBING;
835 }
836 frame->curline=framedata+linelength;
837 frame->curlinepix=0;
838 }
839
840 if (offset!=frame->curpix) {
841
842 frame->curpix=0;
843 se401->error++;
844 return;
845 }
846
847
848 if (frame->curpix+len > datasize) {
849 len=datasize-frame->curpix;
850 }
851 if (se401->cheight%4)
852 blineoffset=1;
853 bline=frame->curpix/se401->cwidth+blineoffset;
854
855 curline=frame->curline;
856 nextline=curline+linelength;
857 if (nextline >= framedata+datasize*3)
858 nextline=curline;
859 while (len) {
860 if (frame->curlinepix>=width) {
861 frame->curlinepix-=width;
862 bline=frame->curpix/width+blineoffset;
863 curline+=linelength*2;
864 nextline+=linelength*2;
865 if (curline >= framedata+datasize*3) {
866 frame->curlinepix++;
867 curline-=3;
868 nextline-=3;
869 len--;
870 data++;
871 frame->curpix++;
872 }
873 if (nextline >= framedata+datasize*3)
874 nextline=curline;
875 }
876 if ((bline&1)) {
877 if ((frame->curlinepix&1)) {
878 *(curline+2)=*data;
879 *(curline-1)=*data;
880 *(nextline+2)=*data;
881 *(nextline-1)=*data;
882 } else {
883 *(curline+1)=
884 (*(curline+1)+*data)/2;
885 *(curline-2)=
886 (*(curline-2)+*data)/2;
887 *(nextline+1)=*data;
888 *(nextline-2)=*data;
889 }
890 } else {
891 if ((frame->curlinepix&1)) {
892 *(curline+1)=
893 (*(curline+1)+*data)/2;
894 *(curline-2)=
895 (*(curline-2)+*data)/2;
896 *(nextline+1)=*data;
897 *(nextline-2)=*data;
898 } else {
899 *curline=*data;
900 *(curline-3)=*data;
901 *nextline=*data;
902 *(nextline-3)=*data;
903 }
904 }
905 frame->curlinepix++;
906 curline-=3;
907 nextline-=3;
908 len--;
909 data++;
910 frame->curpix++;
911 }
912 frame->curline=curline;
913
914 if (frame->curpix>=datasize) {
915
916 framedata+=linelength;
917 for (i=0; i<linelength; i++) {
918 framedata--;
919 *framedata=*(framedata+linelength);
920 }
921
922 for (i=0; i<se401->cheight; i++) {
923 *framedata=*(framedata+3);
924 *(framedata+1)=*(framedata+4);
925 *(framedata+2)=*(framedata+5);
926 framedata+=linelength;
927 }
928 frame->curpix=0;
929 frame->grabstate=FRAME_DONE;
930 se401->framecount++;
931 se401->readcount++;
932 if (se401->frame[(se401->curframe+1)&(SE401_NUMFRAMES-1)].grabstate==FRAME_READY) {
933 se401->curframe=(se401->curframe+1) & (SE401_NUMFRAMES-1);
934 }
935 }
936}
937
938static int se401_newframe(struct usb_se401 *se401, int framenr)
939{
940 DECLARE_WAITQUEUE(wait, current);
941 int errors=0;
942
943 while (se401->streaming &&
944 (se401->frame[framenr].grabstate==FRAME_READY ||
945 se401->frame[framenr].grabstate==FRAME_GRABBING) ) {
946 if(!se401->frame[framenr].curpix) {
947 errors++;
948 }
949 wait_interruptible(
950 se401->scratch[se401->scratch_use].state!=BUFFER_READY,
951 &se401->wq,
952 &wait
953 );
954 if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
955 se401->nullpackets=0;
956 info("to many null length packets, restarting capture");
957 se401_stop_stream(se401);
958 se401_start_stream(se401);
959 } else {
960 if (se401->scratch[se401->scratch_use].state!=BUFFER_READY) {
961 se401->frame[framenr].grabstate=FRAME_ERROR;
962 return -EIO;
963 }
964 se401->scratch[se401->scratch_use].state=BUFFER_BUSY;
965 if (se401->format==FMT_JANGGU) {
966 decode_JangGu(se401, &se401->scratch[se401->scratch_use]);
967 } else {
968 decode_bayer(se401, &se401->scratch[se401->scratch_use]);
969 }
970 se401->scratch[se401->scratch_use].state=BUFFER_UNUSED;
971 se401->scratch_use++;
972 if (se401->scratch_use>=SE401_NUMSCRATCH)
973 se401->scratch_use=0;
974 if (errors > SE401_MAX_ERRORS) {
975 errors=0;
976 info("to much errors, restarting capture");
977 se401_stop_stream(se401);
978 se401_start_stream(se401);
979 }
980 }
981 }
982
983 if (se401->frame[framenr].grabstate==FRAME_DONE)
984 if (se401->enhance)
985 enhance_picture(se401->frame[framenr].data, se401->cheight*se401->cwidth*3);
986 return 0;
987}
988
989static inline void usb_se401_remove_disconnected (struct usb_se401 *se401)
990{
991 int i;
992
993 se401->dev = NULL;
994 se401->frame[0].grabstate = FRAME_ERROR;
995 se401->frame[1].grabstate = FRAME_ERROR;
996
997 se401->streaming = 0;
998
999 wake_up_interruptible(&se401->wq);
1000
1001 for (i=0; i<SE401_NUMSBUF; i++) if (se401->urb[i]) {
1002 se401->urb[i]->next = NULL;
1003 usb_unlink_urb(se401->urb[i]);
1004 usb_free_urb(se401->urb[i]);
1005 se401->urb[i] = NULL;
1006 kfree(se401->sbuf[i].data);
1007 }
1008 for (i=0; i<SE401_NUMSCRATCH; i++) if (se401->scratch[i].data) {
1009 kfree(se401->scratch[i].data);
1010 }
1011 if (se401->inturb) {
1012 usb_unlink_urb(se401->inturb);
1013 usb_free_urb(se401->inturb);
1014 }
1015 info("%s disconnected", se401->camera_name);
1016
1017#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
1018 destroy_proc_se401_cam(se401);
1019#endif
1020
1021
1022 kfree(se401->width);
1023 kfree(se401->height);
1024 kfree(se401);
1025}
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035static int se401_open(struct video_device *dev, int flags)
1036{
1037 struct usb_se401 *se401 = (struct usb_se401 *)dev;
1038 int err = 0;
1039
1040
1041 MOD_INC_USE_COUNT;
1042
1043 se401->user=1;
1044 se401->fbuf=rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
1045 if(!se401->fbuf) err=-ENOMEM;
1046
1047 if (err) {
1048 MOD_DEC_USE_COUNT;
1049 se401->user = 0;
1050 }
1051
1052 return err;
1053}
1054
1055static void se401_close(struct video_device *dev)
1056{
1057
1058 struct usb_se401 *se401 = (struct usb_se401 *)dev;
1059 int i;
1060
1061 for (i=0; i<SE401_NUMFRAMES; i++)
1062 se401->frame[i].grabstate=FRAME_UNUSED;
1063 if (se401->streaming)
1064 se401_stop_stream(se401);
1065
1066 rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
1067 se401->user=0;
1068
1069 if (se401->removed) {
1070 video_unregister_device(&se401->vdev);
1071 kfree(se401->width);
1072 kfree(se401->height);
1073 kfree(se401);
1074 se401 = NULL;
1075 info("device unregistered");
1076 }
1077
1078 MOD_DEC_USE_COUNT;
1079}
1080
1081static int se401_init_done(struct video_device *dev)
1082{
1083#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
1084 create_proc_se401_cam((struct usb_se401 *)dev);
1085#endif
1086
1087 return 0;
1088}
1089
1090static long se401_write(struct video_device *dev, const char *buf, unsigned long
1091 count, int noblock)
1092{
1093 return -EINVAL;
1094}
1095
1096static int se401_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
1097{
1098 struct usb_se401 *se401 = (struct usb_se401 *)vdev;
1099
1100 if (!se401->dev)
1101 return -EIO;
1102
1103 switch (cmd) {
1104 case VIDIOCGCAP:
1105 {
1106 struct video_capability b;
1107 strcpy(b.name, se401->camera_name);
1108 b.type = VID_TYPE_CAPTURE;
1109 b.channels = 1;
1110 b.audios = 0;
1111 b.maxwidth = se401->width[se401->sizes-1];
1112 b.maxheight = se401->height[se401->sizes-1];
1113 b.minwidth = se401->width[0];
1114 b.minheight = se401->height[0];
1115
1116 if (copy_to_user(arg, &b, sizeof(b)))
1117 return -EFAULT;
1118
1119 return 0;
1120 }
1121 case VIDIOCGCHAN:
1122 {
1123 struct video_channel v;
1124
1125 if (copy_from_user(&v, arg, sizeof(v)))
1126 return -EFAULT;
1127 if (v.channel != 0)
1128 return -EINVAL;
1129
1130 v.flags = 0;
1131 v.tuners = 0;
1132 v.type = VIDEO_TYPE_CAMERA;
1133 strcpy(v.name, "Camera");
1134
1135 if (copy_to_user(arg, &v, sizeof(v)))
1136 return -EFAULT;
1137
1138 return 0;
1139 }
1140 case VIDIOCSCHAN:
1141 {
1142 int v;
1143
1144 if (copy_from_user(&v, arg, sizeof(v)))
1145 return -EFAULT;
1146
1147 if (v != 0)
1148 return -EINVAL;
1149
1150 return 0;
1151 }
1152 case VIDIOCGPICT:
1153 {
1154 struct video_picture p;
1155
1156 se401_get_pict(se401, &p);
1157
1158 if (copy_to_user(arg, &p, sizeof(p)))
1159 return -EFAULT;
1160 return 0;
1161 }
1162 case VIDIOCSPICT:
1163 {
1164 struct video_picture p;
1165
1166 if (copy_from_user(&p, arg, sizeof(p)))
1167 return -EFAULT;
1168
1169 if (se401_set_pict(se401, &p))
1170 return -EINVAL;
1171 return 0;
1172 }
1173 case VIDIOCSWIN:
1174 {
1175 struct video_window vw;
1176
1177 if (copy_from_user(&vw, arg, sizeof(vw)))
1178 return -EFAULT;
1179 if (vw.flags)
1180 return -EINVAL;
1181 if (vw.clipcount)
1182 return -EINVAL;
1183 if (se401_set_size(se401, vw.width, vw.height))
1184 return -EINVAL;
1185
1186 return 0;
1187 }
1188 case VIDIOCGWIN:
1189 {
1190 struct video_window vw;
1191
1192 vw.x = 0;
1193 vw.y = 0;
1194 vw.chromakey = 0;
1195 vw.flags = 0;
1196 vw.clipcount = 0;
1197 vw.width = se401->cwidth;
1198 vw.height = se401->cheight;
1199
1200 if (copy_to_user(arg, &vw, sizeof(vw)))
1201 return -EFAULT;
1202
1203 return 0;
1204 }
1205 case VIDIOCGMBUF:
1206 {
1207 struct video_mbuf vm;
1208 int i;
1209
1210 memset(&vm, 0, sizeof(vm));
1211 vm.size = SE401_NUMFRAMES * se401->maxframesize;
1212 vm.frames = SE401_NUMFRAMES;
1213 for (i=0; i<SE401_NUMFRAMES; i++)
1214 vm.offsets[i] = se401->maxframesize * i;
1215
1216 if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
1217 return -EFAULT;
1218
1219 return 0;
1220 }
1221 case VIDIOCMCAPTURE:
1222 {
1223 struct video_mmap vm;
1224
1225 if (copy_from_user(&vm, arg, sizeof(vm)))
1226 return -EFAULT;
1227 if (vm.format != VIDEO_PALETTE_RGB24)
1228 return -EINVAL;
1229 if (vm.frame >= SE401_NUMFRAMES)
1230 return -EINVAL;
1231 if (se401->frame[vm.frame].grabstate != FRAME_UNUSED)
1232 return -EBUSY;
1233
1234
1235 if (se401_set_size(se401, vm.width, vm.height))
1236 return -EINVAL;
1237 se401->frame[vm.frame].grabstate=FRAME_READY;
1238
1239 if (!se401->streaming)
1240 se401_start_stream(se401);
1241
1242
1243 if (se401->framecount==0)
1244 se401_send_pict(se401);
1245
1246 if (se401->framecount%20==1)
1247 se401_auto_resetlevel(se401);
1248
1249 return 0;
1250 }
1251 case VIDIOCSYNC:
1252 {
1253 int frame, ret=0;
1254
1255 if (copy_from_user((void *)&frame, arg, sizeof(int)))
1256 return -EFAULT;
1257
1258 if(frame <0 || frame >= SE401_NUMFRAMES)
1259 return -EINVAL;
1260
1261 ret=se401_newframe(se401, frame);
1262 se401->frame[frame].grabstate=FRAME_UNUSED;
1263 return ret;
1264 }
1265 case VIDIOCGFBUF:
1266 {
1267 struct video_buffer vb;
1268
1269 memset(&vb, 0, sizeof(vb));
1270 vb.base = NULL;
1271
1272 if (copy_to_user((void *)arg, (void *)&vb, sizeof(vb)))
1273 return -EFAULT;
1274
1275 return 0;
1276 }
1277 case VIDIOCKEY:
1278 return 0;
1279 case VIDIOCCAPTURE:
1280 return -EINVAL;
1281 case VIDIOCSFBUF:
1282 return -EINVAL;
1283 case VIDIOCGTUNER:
1284 case VIDIOCSTUNER:
1285 return -EINVAL;
1286 case VIDIOCGFREQ:
1287 case VIDIOCSFREQ:
1288 return -EINVAL;
1289 case VIDIOCGAUDIO:
1290 case VIDIOCSAUDIO:
1291 return -EINVAL;
1292 default:
1293 return -ENOIOCTLCMD;
1294 }
1295
1296 return 0;
1297}
1298
1299static long se401_read(struct video_device *dev, char *buf, unsigned long count,
1300 int noblock)
1301{
1302 int realcount=count, ret=0;
1303 struct usb_se401 *se401 = (struct usb_se401 *)dev;
1304
1305
1306 if (se401->dev == NULL)
1307 return -EIO;
1308 if (realcount > se401->cwidth*se401->cheight*3)
1309 realcount=se401->cwidth*se401->cheight*3;
1310
1311
1312 if (se401->frame[0].grabstate==FRAME_GRABBING)
1313 return -EBUSY;
1314 se401->frame[0].grabstate=FRAME_READY;
1315 se401->frame[1].grabstate=FRAME_UNUSED;
1316 se401->curframe=0;
1317
1318 if (!se401->streaming)
1319 se401_start_stream(se401);
1320
1321
1322 if (se401->framecount==0)
1323 se401_send_pict(se401);
1324
1325 if (se401->framecount%20==1)
1326 se401_auto_resetlevel(se401);
1327
1328 ret=se401_newframe(se401, 0);
1329
1330 se401->frame[0].grabstate=FRAME_UNUSED;
1331 if (ret)
1332 return ret;
1333 if (copy_to_user(buf, se401->frame[0].data, realcount))
1334 return -EFAULT;
1335
1336 return realcount;
1337}
1338
1339static int se401_mmap(struct video_device *dev, const char *adr,
1340 unsigned long size)
1341{
1342 struct usb_se401 *se401 = (struct usb_se401 *)dev;
1343 unsigned long start = (unsigned long)adr;
1344 unsigned long page, pos;
1345
1346 down(&se401->lock);
1347
1348 if (se401->dev == NULL) {
1349 up(&se401->lock);
1350 return -EIO;
1351 }
1352 if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) {
1353 up(&se401->lock);
1354 return -EINVAL;
1355 }
1356 pos = (unsigned long)se401->fbuf;
1357 while (size > 0) {
1358 page = kvirt_to_pa(pos);
1359 if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
1360 up(&se401->lock);
1361 return -EAGAIN;
1362 }
1363 start += PAGE_SIZE;
1364 pos += PAGE_SIZE;
1365 if (size > PAGE_SIZE)
1366 size -= PAGE_SIZE;
1367 else
1368 size = 0;
1369 }
1370 up(&se401->lock);
1371
1372 return 0;
1373}
1374
1375static struct video_device se401_template = {
1376 name: "se401 USB camera",
1377 type: VID_TYPE_CAPTURE,
1378 hardware: VID_HARDWARE_SE401,
1379 open: se401_open,
1380 close: se401_close,
1381 read: se401_read,
1382 write: se401_write,
1383 ioctl: se401_ioctl,
1384 mmap: se401_mmap,
1385 initialize: se401_init_done,
1386};
1387
1388
1389
1390
1391static int se401_init(struct usb_se401 *se401)
1392{
1393 int i=0, rc;
1394 unsigned char cp[0x40];
1395 char temp[200];
1396
1397
1398 se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
1399
1400
1401 rc=se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0, cp, sizeof(cp));
1402 if (cp[1]!=0x41) {
1403 err("Wrong descriptor type");
1404 return 1;
1405 }
1406 sprintf (temp, "ExtraFeatures: %d", cp[3]);
1407
1408 se401->sizes=cp[4]+cp[5]*256;
1409 se401->width=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
1410 if (!se401->width)
1411 return 1;
1412 se401->height=kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
1413 if (!se401->height) {
1414 kfree(se401->width);
1415 return 1;
1416 }
1417 for (i=0; i<se401->sizes; i++) {
1418 se401->width[i]=cp[6+i*4+0]+cp[6+i*4+1]*256;
1419 se401->height[i]=cp[6+i*4+2]+cp[6+i*4+3]*256;
1420 }
1421 sprintf (temp, "%s Sizes:", temp);
1422 for (i=0; i<se401->sizes; i++) {
1423 sprintf(temp, "%s %dx%d", temp, se401->width[i], se401->height[i]);
1424 }
1425 info("%s", temp);
1426 se401->maxframesize=se401->width[se401->sizes-1]*se401->height[se401->sizes-1]*3;
1427
1428 rc=se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
1429 se401->cwidth=cp[0]+cp[1]*256;
1430 rc=se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
1431 se401->cheight=cp[0]+cp[1]*256;
1432
1433 if (!cp[2] && SE401_FORMAT_BAYER) {
1434 err("Bayer format not supported!");
1435 return 1;
1436 }
1437
1438 se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE, SE401_FORMAT_BAYER, NULL, 0);
1439
1440 rc=se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
1441 se401->brightness=cp[0]+cp[1]*256;
1442
1443 se401->resetlevel=0x2d;
1444 se401->rgain=0x20;
1445 se401->ggain=0x20;
1446 se401->bgain=0x20;
1447 se401_set_exposure(se401, 20000);
1448 se401->palette=VIDEO_PALETTE_RGB24;
1449 se401->enhance=1;
1450 se401->dropped=0;
1451 se401->error=0;
1452 se401->framecount=0;
1453 se401->readcount=0;
1454
1455
1456 se401->inturb=usb_alloc_urb(0);
1457 if (!se401->inturb) {
1458 info("Allocation of inturb failed");
1459 return 1;
1460 }
1461 FILL_INT_URB(se401->inturb, se401->dev,
1462 usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT),
1463 &se401->button, sizeof(se401->button),
1464 se401_button_irq,
1465 se401,
1466 HZ/10
1467 );
1468 if (usb_submit_urb(se401->inturb)) {
1469 info("int urb burned down");
1470 return 1;
1471 }
1472
1473
1474 se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
1475 se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
1476 se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
1477 se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
1478
1479 return 0;
1480}
1481
1482static void* se401_probe(struct usb_device *dev, unsigned int ifnum,
1483 const struct usb_device_id *id)
1484{
1485 struct usb_interface_descriptor *interface;
1486 struct usb_se401 *se401;
1487 char *camera_name=NULL;
1488
1489
1490 if (dev->descriptor.bNumConfigurations != 1)
1491 return NULL;
1492
1493 interface = &dev->actconfig->interface[ifnum].altsetting[0];
1494
1495
1496 if (dev->descriptor.idVendor == 0x03e8 &&
1497 dev->descriptor.idProduct == 0x0004) {
1498 camera_name="Endpoints/Aox SE401";
1499 } else if (dev->descriptor.idVendor == 0x0471 &&
1500 dev->descriptor.idProduct == 0x030b) {
1501 camera_name="Philips PCVC665K";
1502 } else if (dev->descriptor.idVendor == 0x047d &&
1503 dev->descriptor.idProduct == 0x5001) {
1504 camera_name="Kensington VideoCAM 67014";
1505 } else if (dev->descriptor.idVendor == 0x047d &&
1506 dev->descriptor.idProduct == 0x5002) {
1507 camera_name="Kensington VideoCAM 6701(5/7)";
1508 } else if (dev->descriptor.idVendor == 0x047d &&
1509 dev->descriptor.idProduct == 0x5003) {
1510 camera_name="Kensington VideoCAM 67016";
1511 } else
1512 return NULL;
1513
1514
1515 if (interface->bInterfaceClass != 0x00)
1516 return NULL;
1517 if (interface->bInterfaceSubClass != 0x00)
1518 return NULL;
1519
1520
1521 info("SE401 camera found: %s", camera_name);
1522
1523 if ((se401 = kmalloc(sizeof(*se401), GFP_KERNEL)) == NULL) {
1524 err("couldn't kmalloc se401 struct");
1525 return NULL;
1526 }
1527
1528 memset(se401, 0, sizeof(*se401));
1529
1530 se401->dev = dev;
1531 se401->iface = interface->bInterfaceNumber;
1532 se401->camera_name = camera_name;
1533
1534 info("firmware version: %02x", dev->descriptor.bcdDevice & 255);
1535
1536 if (se401_init(se401)) {
1537 kfree(se401);
1538 return NULL;
1539 }
1540
1541 memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
1542 memcpy(se401->vdev.name, se401->camera_name, strlen(se401->camera_name));
1543 init_waitqueue_head(&se401->wq);
1544 init_MUTEX(&se401->lock);
1545 wmb();
1546
1547 if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
1548 kfree(se401);
1549 err("video_register_device failed");
1550 return NULL;
1551 }
1552 info("registered new video device: video%d", se401->vdev.minor);
1553
1554 return se401;
1555}
1556
1557static void se401_disconnect(struct usb_device *dev, void *ptr)
1558{
1559 struct usb_se401 *se401 = (struct usb_se401 *) ptr;
1560
1561 lock_kernel();
1562
1563 if (!se401->user){
1564 video_unregister_device(&se401->vdev);
1565 usb_se401_remove_disconnected(se401);
1566 } else {
1567 se401->removed = 1;
1568 }
1569 unlock_kernel();
1570}
1571
1572static struct usb_driver se401_driver = {
1573 name: "se401",
1574 id_table: device_table,
1575 probe: se401_probe,
1576 disconnect: se401_disconnect
1577};
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587static int __init usb_se401_init(void)
1588{
1589#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
1590 proc_se401_create();
1591#endif
1592
1593 info("SE401 usb camera driver version %s registering", version);
1594 if (flickerless)
1595 if (flickerless!=50 && flickerless!=60) {
1596 info("Invallid flickerless value, use 0, 50 or 60.");
1597 return -1;
1598 }
1599 if (usb_register(&se401_driver) < 0)
1600 return -1;
1601 return 0;
1602}
1603
1604static void __exit usb_se401_exit(void)
1605{
1606 usb_deregister(&se401_driver);
1607 info("SE401 driver deregistered");
1608
1609#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
1610 proc_se401_destroy();
1611#endif
1612}
1613
1614module_init(usb_se401_init);
1615module_exit(usb_se401_exit);
1616