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