2 * OmniVision OV511 Camera-to-USB Bridge Driver
4 * Copyright (c) 1999-2000 Mark W. McClelland
5 * Many improvements by Bret Wallach <bwallac1@san.rr.com>
6 * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
7 * Snapshot code by Kevin Moore
8 * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
9 * Changes by Claudio Matsuoka <claudio@conectiva.com>
11 * Based on the Linux CPiA driver written by Peter Pregler,
12 * Scott J. Bertin and Johannes Erdfelt.
14 * Please see the file: linux/Documentation/usb/ov511.txt
15 * and the website at: http://alpha.dyndns.org/ov511
18 * This program is free software; you can redistribute it and/or modify it
19 * under the terms of the GNU General Public License as published by the
20 * Free Software Foundation; either version 2 of the License, or (at your
21 * option) any later version.
23 * This program is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software Foundation,
30 * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 static const char version
[] = "1.19";
35 #define __NO_VERSION__
37 #include <linux/config.h>
38 #include <linux/module.h>
39 #include <linux/version.h>
40 #include <linux/init.h>
42 #include <linux/vmalloc.h>
43 #include <linux/slab.h>
44 #include <linux/proc_fs.h>
45 #include <linux/ctype.h>
46 #include <linux/pagemap.h>
47 #include <linux/usb.h>
49 #include <asm/semaphore.h>
50 #include <linux/wrapper.h>
54 #undef OV511_GBR422 /* Experimental -- sets the 7610 to GBR422 */
56 #define OV511_I2C_RETRIES 3
58 /* Video Size 640 x 480 x 3 bytes for RGB */
59 #define MAX_FRAME_SIZE (640 * 480 * 3)
60 #define MAX_DATA_SIZE (MAX_FRAME_SIZE + sizeof(struct timeval))
62 #define DEFAULT_WIDTH 640
63 #define DEFAULT_HEIGHT 480
65 #define GET_SEGSIZE(p) ((p) == VIDEO_PALETTE_GREY ? 256 : 384)
66 #define GET_DEPTH(p) ((p) == VIDEO_PALETTE_GREY ? 8 : ((p) == VIDEO_PALETTE_YUV422 ? 8 : 24))
68 /* PARAMETER VARIABLES: */
69 static int autoadjust
= 1; /* CCD dynamically changes exposure, etc... */
71 /* 0=no debug messages
72 * 1=init/detection/unload and other significant messages,
73 * 2=some warning messages
74 * 3=config/control function calls
75 * 4=most function calls and data parsing messages
76 * 5=highly repetitive mesgs
77 * NOTE: This should be changed to 0, 1, or 2 for production kernels
81 /* Fix vertical misalignment of red and blue at 640x480 */
82 static int fix_rgb_offset
= 0;
84 /* Snapshot mode enabled flag */
85 static int snapshot
= 0;
87 /* Sensor detection override (global for all attached cameras) */
88 static int sensor
= 0;
90 /* Increase this if you are getting "Failed to read sensor ID..." */
91 static int i2c_detect_tries
= 5;
93 /* For legal values, see the OV7610/7620 specs under register Common F,
94 * upper nybble (set to 0-F) */
95 static int aperture
= -1;
97 /* Force image to be read in RGB instead of BGR. This option allow
98 * programs that expect RGB data (e.g. gqcam) to work with this driver. */
99 static int force_rgb
= 0;
101 /* Number of seconds before inactive buffers are deallocated */
102 static int buf_timeout
= 5;
104 MODULE_PARM(autoadjust
, "i");
105 MODULE_PARM(debug
, "i");
106 MODULE_PARM(fix_rgb_offset
, "i");
107 MODULE_PARM(snapshot
, "i");
108 MODULE_PARM(sensor
, "i");
109 MODULE_PARM(i2c_detect_tries
, "i");
110 MODULE_PARM(aperture
, "i");
111 MODULE_PARM(force_rgb
, "i");
112 MODULE_PARM(buf_timeout
, "i");
114 MODULE_AUTHOR("Mark McClelland <mmcclelland@delphi.com> & Bret Wallach & Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha <cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>");
115 MODULE_DESCRIPTION("OV511 USB Camera Driver");
117 char kernel_version
[] = UTS_RELEASE
;
119 static struct usb_driver ov511_driver
;
121 /**********************************************************************
122 * List of known OV511-based cameras
123 **********************************************************************/
125 static struct cam_list clist
[] = {
126 { 0, "generic model (no ID)" },
127 { 3, "D-Link DSB-C300" },
128 { 4, "generic OV511/OV7610" },
129 { 5, "Puretek PT-6007" },
130 { 21, "Creative Labs WebCam 3" },
132 { 38, "Lifeview USB Life TV" }, /* No support yet! */
133 { 100, "Lifeview RoboCam" },
134 { 102, "AverMedia InterCam Elite" },
135 { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */
139 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
140 static struct palette_list plist
[] = {
141 { VIDEO_PALETTE_GREY
, "GREY" },
142 { VIDEO_PALETTE_HI240
, "HI240" },
143 { VIDEO_PALETTE_RGB565
, "RGB565" },
144 { VIDEO_PALETTE_RGB24
, "RGB24" },
145 { VIDEO_PALETTE_RGB32
, "RGB32" },
146 { VIDEO_PALETTE_RGB555
, "RGB555" },
147 { VIDEO_PALETTE_YUV422
, "YUV422" },
148 { VIDEO_PALETTE_YUYV
, "YUYV" },
149 { VIDEO_PALETTE_UYVY
, "UYVY" },
150 { VIDEO_PALETTE_YUV420
, "YUV420" },
151 { VIDEO_PALETTE_YUV411
, "YUV411" },
152 { VIDEO_PALETTE_RAW
, "RAW" },
153 { VIDEO_PALETTE_YUV422P
,"YUV422P" },
154 { VIDEO_PALETTE_YUV411P
,"YUV411P" },
155 { VIDEO_PALETTE_YUV420P
,"YUV420P" },
156 { VIDEO_PALETTE_YUV410P
,"YUV410P" },
161 /**********************************************************************
165 * This is a shameless copy from the USB-cpia driver (linux kernel
166 * version 2.3.29 or so, I have no idea what this code actually does ;).
167 * Actually it seems to be a copy of a shameless copy of the bttv-driver.
168 * Or that is a copy of a shameless copy of ... (To the powers: is there
169 * no generic kernel-function to do this sort of stuff?)
171 * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
172 * there will be one, but apparentely not yet -jerdfelt
174 * So I copied it again for the OV511 driver -claudio
175 **********************************************************************/
177 /* Given PGD from the address space's page table, return the kernel
178 * virtual mapping of the physical memory mapped at ADR.
180 static inline unsigned long uvirt_to_kva(pgd_t
*pgd
, unsigned long adr
)
182 unsigned long ret
= 0UL;
186 if (!pgd_none(*pgd
)) {
187 pmd
= pmd_offset(pgd
, adr
);
188 if (!pmd_none(*pmd
)) {
189 ptep
= pte_offset(pmd
, adr
);
191 if (pte_present(pte
))
192 ret
= page_address(pte_page(pte
)) |
193 (adr
& (PAGE_SIZE
-1));
200 /* Here we want the physical address of the memory.
201 * This is used when initializing the contents of the
202 * area and marking the pages as reserved.
204 static inline unsigned long kvirt_to_pa(unsigned long adr
)
206 unsigned long va
, kva
, ret
;
208 va
= VMALLOC_VMADDR(adr
);
209 kva
= uvirt_to_kva(pgd_offset_k(va
), va
);
214 static void *rvmalloc(unsigned long size
)
217 unsigned long adr
, page
;
219 /* Round it off to PAGE_SIZE */
220 size
+= (PAGE_SIZE
- 1);
221 size
&= ~(PAGE_SIZE
- 1);
223 mem
= vmalloc_32(size
);
227 memset(mem
, 0, size
); /* Clear the ram out, no junk to the user */
228 adr
= (unsigned long) mem
;
230 page
= kvirt_to_pa(adr
);
231 mem_map_reserve(MAP_NR(__va(page
)));
233 if (size
> PAGE_SIZE
)
242 static void rvfree(void *mem
, unsigned long size
)
244 unsigned long adr
, page
;
249 size
+= (PAGE_SIZE
- 1);
250 size
&= ~(PAGE_SIZE
- 1);
252 adr
=(unsigned long) mem
;
254 page
= kvirt_to_pa(adr
);
255 mem_map_unreserve(MAP_NR(__va(page
)));
257 if (size
> PAGE_SIZE
)
265 /**********************************************************************
267 * Based on the CPiA driver version 0.7.4 -claudio
268 **********************************************************************/
270 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
272 static struct proc_dir_entry
*ov511_proc_entry
= NULL
;
273 extern struct proc_dir_entry
*video_proc_entry
;
275 #define YES_NO(x) ((x) ? "yes" : "no")
277 static int ov511_read_proc(char *page
, char **start
, off_t off
,
278 int count
, int *eof
, void *data
)
282 struct usb_ov511
*ov511
= data
;
284 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
285 * or we need to get more sophisticated. */
287 out
+= sprintf (out
, "driver_version : %s\n", version
);
288 out
+= sprintf (out
, "custom_id : %d\n", ov511
->customid
);
289 out
+= sprintf (out
, "model : %s\n", ov511
->desc
?
290 clist
[ov511
->desc
].description
: "unknown");
291 out
+= sprintf (out
, "streaming : %s\n", YES_NO (ov511
->streaming
));
292 out
+= sprintf (out
, "grabbing : %s\n", YES_NO (ov511
->grabbing
));
293 out
+= sprintf (out
, "compress : %s\n", YES_NO (ov511
->compress
));
294 out
+= sprintf (out
, "subcapture : %s\n", YES_NO (ov511
->sub_flag
));
295 out
+= sprintf (out
, "sub_size : %d %d %d %d\n",
296 ov511
->subx
, ov511
->suby
, ov511
->subw
, ov511
->subh
);
297 out
+= sprintf (out
, "data_format : %s\n", force_rgb
? "RGB" : "BGR");
298 out
+= sprintf (out
, "brightness : %d\n", ov511
->brightness
>> 8);
299 out
+= sprintf (out
, "colour : %d\n", ov511
->colour
>> 8);
300 out
+= sprintf (out
, "contrast : %d\n", ov511
->contrast
>> 8);
301 out
+= sprintf (out
, "num_frames : %d\n", OV511_NUMFRAMES
);
302 for (i
= 0; i
< OV511_NUMFRAMES
; i
++) {
303 out
+= sprintf (out
, "frame : %d\n", i
);
304 out
+= sprintf (out
, " depth : %d\n",
305 ov511
->frame
[i
].depth
);
306 out
+= sprintf (out
, " size : %d %d\n",
307 ov511
->frame
[i
].width
, ov511
->frame
[i
].height
);
308 out
+= sprintf (out
, " format : ");
309 for (j
= 0; plist
[j
].num
>= 0; j
++) {
310 if (plist
[j
].num
== ov511
->frame
[i
].format
) {
311 out
+= sprintf (out
, "%s\n", plist
[j
].name
);
315 if (plist
[j
].num
< 0)
316 out
+= sprintf (out
, "unknown\n");
317 out
+= sprintf (out
, " segsize : %d\n",
318 ov511
->frame
[i
].segsize
);
319 out
+= sprintf (out
, " data_buffer : 0x%p\n",
320 ov511
->frame
[i
].data
);
322 out
+= sprintf (out
, "snap_enabled : %s\n", YES_NO (ov511
->snap_enabled
));
323 out
+= sprintf (out
, "bridge : %s\n",
324 ov511
->bridge
== BRG_OV511
? "OV511" :
325 ov511
->bridge
== BRG_OV511PLUS
? "OV511+" :
327 out
+= sprintf (out
, "sensor : %s\n",
328 ov511
->sensor
== SEN_OV7610
? "OV7610" :
329 ov511
->sensor
== SEN_OV7620
? "OV7620" :
330 ov511
->sensor
== SEN_OV7620AE
? "OV7620AE" :
332 out
+= sprintf (out
, "packet_size : %d\n", ov511
->packet_size
);
333 out
+= sprintf (out
, "framebuffer : 0x%p\n", ov511
->fbuf
);
339 if (len
<= 0) return 0;
348 static int ov511_write_proc(struct file
*file
, const char *buffer
,
349 unsigned long count
, void *data
)
354 static void create_proc_ov511_cam (struct usb_ov511
*ov511
)
357 struct proc_dir_entry
*ent
;
359 if (!ov511_proc_entry
|| !ov511
)
362 sprintf(name
, "video%d", ov511
->vdev
.minor
);
363 PDEBUG (4, "creating /proc/video/ov511/%s", name
);
365 ent
= create_proc_entry(name
, S_IFREG
|S_IRUGO
|S_IWUSR
, ov511_proc_entry
);
371 ent
->read_proc
= ov511_read_proc
;
372 ent
->write_proc
= ov511_write_proc
;
373 ov511
->proc_entry
= ent
;
376 static void destroy_proc_ov511_cam (struct usb_ov511
*ov511
)
380 if (!ov511
|| !ov511
->proc_entry
)
383 sprintf(name
, "video%d", ov511
->vdev
.minor
);
384 PDEBUG (4, "destroying %s", name
);
385 remove_proc_entry(name
, ov511_proc_entry
);
386 ov511
->proc_entry
= NULL
;
389 static void proc_ov511_create(void)
391 /* No current standard here. Alan prefers /proc/video/ as it keeps
392 * /proc "less cluttered than /proc/randomcardifoundintheshed/"
395 if (video_proc_entry
== NULL
) {
396 err("Unable to initialise /proc/video/ov511");
400 ov511_proc_entry
= create_proc_entry("ov511", S_IFDIR
, video_proc_entry
);
402 if (ov511_proc_entry
)
403 ov511_proc_entry
->owner
= THIS_MODULE
;
405 err("Unable to initialise /proc/ov511");
408 static void proc_ov511_destroy(void)
410 PDEBUG (3, "removing /proc/video/ov511");
412 if (ov511_proc_entry
== NULL
)
415 remove_proc_entry("ov511", video_proc_entry
);
417 #endif /* CONFIG_PROC_FS && CONFIG_VIDEO_PROC_FS */
420 /**********************************************************************
424 **********************************************************************/
426 static int ov511_reg_write(struct usb_device
*dev
,
432 rc
= usb_control_msg(dev
,
433 usb_sndctrlpipe(dev
, 0),
435 USB_TYPE_CLASS
| USB_RECIP_DEVICE
,
436 0, (__u16
)reg
, &value
, 1, HZ
);
438 PDEBUG(5, "reg write: 0x%02X:0x%02X, 0x%x", reg
, value
, rc
);
441 err("reg write: error %d", rc
);
446 /* returns: negative is error, pos or zero is data */
447 static int ov511_reg_read(struct usb_device
*dev
, unsigned char reg
)
450 unsigned char buffer
[1];
452 rc
= usb_control_msg(dev
,
453 usb_rcvctrlpipe(dev
, 0),
455 USB_DIR_IN
| USB_TYPE_CLASS
| USB_RECIP_DEVICE
,
456 0, (__u16
)reg
, buffer
, 1, HZ
);
458 PDEBUG(5, "reg read: 0x%02X:0x%02X", reg
, buffer
[0]);
461 err("reg read: error %d", rc
);
468 static int ov511_i2c_write(struct usb_device
*dev
,
474 PDEBUG(5, "i2c write: 0x%02X:0x%02X", reg
, value
);
476 /* Three byte write cycle */
477 for (retries
= OV511_I2C_RETRIES
; ; ) {
478 /* Select camera register */
479 rc
= ov511_reg_write(dev
, OV511_REG_I2C_SUB_ADDRESS_3_BYTE
, reg
);
480 if (rc
< 0) goto error
;
482 /* Write "value" to I2C data port of OV511 */
483 rc
= ov511_reg_write(dev
, OV511_REG_I2C_DATA_PORT
, value
);
484 if (rc
< 0) goto error
;
486 /* Initiate 3-byte write cycle */
487 rc
= ov511_reg_write(dev
, OV511_REG_I2C_CONTROL
, 0x01);
488 if (rc
< 0) goto error
;
490 do rc
= ov511_reg_read(dev
, OV511_REG_I2C_CONTROL
);
491 while (rc
> 0 && ((rc
&1) == 0)); /* Retry until idle */
492 if (rc
< 0) goto error
;
494 if ((rc
&2) == 0) /* Ack? */
498 ov511_reg_write(dev
, OV511_REG_I2C_CONTROL
, 0x10);
501 err("i2c write retries exhausted");
510 err("i2c write: error %d", rc
);
514 /* returns: negative is error, pos or zero is data */
515 static int ov511_i2c_read(struct usb_device
*dev
, unsigned char reg
)
517 int rc
, value
, retries
;
519 /* Two byte write cycle */
520 for (retries
= OV511_I2C_RETRIES
; ; ) {
521 /* Select camera register */
522 rc
= ov511_reg_write(dev
, OV511_REG_I2C_SUB_ADDRESS_2_BYTE
, reg
);
523 if (rc
< 0) goto error
;
525 /* Initiate 2-byte write cycle */
526 rc
= ov511_reg_write(dev
, OV511_REG_I2C_CONTROL
, 0x03);
527 if (rc
< 0) goto error
;
529 do rc
= ov511_reg_read(dev
, OV511_REG_I2C_CONTROL
);
530 while (rc
> 0 && ((rc
&1) == 0)); /* Retry until idle */
531 if (rc
< 0) goto error
;
533 if ((rc
&2) == 0) /* Ack? */
537 ov511_reg_write(dev
, OV511_REG_I2C_CONTROL
, 0x10);
540 err("i2c write retries exhausted");
546 /* Two byte read cycle */
547 for (retries
= OV511_I2C_RETRIES
; ; ) {
548 /* Initiate 2-byte read cycle */
549 rc
= ov511_reg_write(dev
, OV511_REG_I2C_CONTROL
, 0x05);
550 if (rc
< 0) goto error
;
552 do rc
= ov511_reg_read(dev
, OV511_REG_I2C_CONTROL
);
553 while (rc
> 0 && ((rc
&1) == 0)); /* Retry until idle */
554 if (rc
< 0) goto error
;
556 if ((rc
&2) == 0) /* Ack? */
560 rc
= ov511_reg_write(dev
, OV511_REG_I2C_CONTROL
, 0x10);
561 if (rc
< 0) goto error
;
564 err("i2c read retries exhausted");
570 value
= ov511_reg_read(dev
, OV511_REG_I2C_DATA_PORT
);
572 PDEBUG(5, "i2c read: 0x%02X:0x%02X", reg
, value
);
574 /* This is needed to make ov511_i2c_write() work */
575 rc
= ov511_reg_write(dev
, OV511_REG_I2C_CONTROL
, 0x05);
582 err("i2c read: error %d", rc
);
586 static int ov511_write_regvals(struct usb_device
*dev
,
587 struct ov511_regvals
* pRegvals
)
591 while (pRegvals
->bus
!= OV511_DONE_BUS
) {
592 if (pRegvals
->bus
== OV511_REG_BUS
) {
593 if ((rc
= ov511_reg_write(dev
, pRegvals
->reg
,
596 } else if (pRegvals
->bus
== OV511_I2C_BUS
) {
597 if ((rc
= ov511_i2c_write(dev
, pRegvals
->reg
,
601 err("Bad regval array");
610 err("write regvals: error %d", rc
);
615 static void ov511_dump_i2c_range(struct usb_device
*dev
, int reg1
, int regn
)
619 for(i
= reg1
; i
<= regn
; i
++) {
620 rc
= ov511_i2c_read(dev
, i
);
621 PDEBUG(1, "OV7610[0x%X] = 0x%X", i
, rc
);
625 static void ov511_dump_i2c_regs(struct usb_device
*dev
)
627 PDEBUG(3, "I2C REGS");
628 ov511_dump_i2c_range(dev
, 0x00, 0x38);
632 static void ov511_dump_reg_range(struct usb_device
*dev
, int reg1
, int regn
)
636 for(i
= reg1
; i
<= regn
; i
++) {
637 rc
= ov511_reg_read(dev
, i
);
638 PDEBUG(1, "OV511[0x%X] = 0x%X", i
, rc
);
642 static void ov511_dump_regs(struct usb_device
*dev
)
644 PDEBUG(1, "CAMERA INTERFACE REGS");
645 ov511_dump_reg_range(dev
, 0x10, 0x1f);
646 PDEBUG(1, "DRAM INTERFACE REGS");
647 ov511_dump_reg_range(dev
, 0x20, 0x23);
648 PDEBUG(1, "ISO FIFO REGS");
649 ov511_dump_reg_range(dev
, 0x30, 0x31);
650 PDEBUG(1, "PIO REGS");
651 ov511_dump_reg_range(dev
, 0x38, 0x39);
652 ov511_dump_reg_range(dev
, 0x3e, 0x3e);
653 PDEBUG(1, "I2C REGS");
654 ov511_dump_reg_range(dev
, 0x40, 0x49);
655 PDEBUG(1, "SYSTEM CONTROL REGS");
656 ov511_dump_reg_range(dev
, 0x50, 0x53);
657 ov511_dump_reg_range(dev
, 0x5e, 0x5f);
658 PDEBUG(1, "OmniCE REGS");
659 ov511_dump_reg_range(dev
, 0x70, 0x79);
660 ov511_dump_reg_range(dev
, 0x80, 0x9f);
661 ov511_dump_reg_range(dev
, 0xa0, 0xbf);
667 static int ov511_reset(struct usb_device
*dev
, unsigned char reset_type
)
671 PDEBUG(3, "Reset: type=0x%X", reset_type
);
672 rc
= ov511_reg_write(dev
, OV511_REG_SYSTEM_RESET
, reset_type
);
673 rc
= ov511_reg_write(dev
, OV511_REG_SYSTEM_RESET
, 0);
676 err("reset: command failed");
681 /* Temporarily stops OV511 from functioning. Must do this before changing
682 * registers while the camera is streaming */
683 static inline int ov511_stop(struct usb_device
*dev
)
685 PDEBUG(4, "stopping");
686 return (ov511_reg_write(dev
, OV511_REG_SYSTEM_RESET
, 0x3d));
689 /* Restarts OV511 after ov511_stop() is called */
690 static inline int ov511_restart(struct usb_device
*dev
)
692 PDEBUG(4, "restarting");
693 return (ov511_reg_write(dev
, OV511_REG_SYSTEM_RESET
, 0x00));
696 static int ov511_set_packet_size(struct usb_ov511
*ov511
, int size
)
700 if (ov511_stop(ov511
->dev
) < 0)
705 if (ov511
->bridge
== BRG_OV511
) {
706 if (size
== 0) alt
= OV511_ALT_SIZE_0
;
707 else if (size
== 257) alt
= OV511_ALT_SIZE_257
;
708 else if (size
== 513) alt
= OV511_ALT_SIZE_513
;
709 else if (size
== 769) alt
= OV511_ALT_SIZE_769
;
710 else if (size
== 993) alt
= OV511_ALT_SIZE_993
;
712 err("Set packet size: invalid size (%d)", size
);
715 } else if (ov511
->bridge
== BRG_OV511PLUS
) {
716 if (size
== 0) alt
= OV511PLUS_ALT_SIZE_0
;
717 else if (size
== 33) alt
= OV511PLUS_ALT_SIZE_33
;
718 else if (size
== 129) alt
= OV511PLUS_ALT_SIZE_129
;
719 else if (size
== 257) alt
= OV511PLUS_ALT_SIZE_257
;
720 else if (size
== 385) alt
= OV511PLUS_ALT_SIZE_385
;
721 else if (size
== 513) alt
= OV511PLUS_ALT_SIZE_513
;
722 else if (size
== 769) alt
= OV511PLUS_ALT_SIZE_769
;
723 else if (size
== 961) alt
= OV511PLUS_ALT_SIZE_961
;
725 err("Set packet size: invalid size (%d)", size
);
729 err("Set packet size: Invalid bridge type");
733 PDEBUG(3, "set packet size: %d, mult=%d, alt=%d", size
, mult
, alt
);
735 if (ov511_reg_write(ov511
->dev
, OV511_REG_FIFO_PACKET_SIZE
, mult
) < 0)
738 if (usb_set_interface(ov511
->dev
, ov511
->iface
, alt
) < 0) {
739 err("Set packet size: set interface error");
743 // FIXME - Should we only reset the FIFO?
744 if (ov511_reset(ov511
->dev
, OV511_RESET_NOREGS
) < 0)
747 ov511
->packet_size
= size
;
749 if (ov511_restart(ov511
->dev
) < 0)
757 ov7610_set_picture(struct usb_ov511
*ov511
, struct video_picture
*p
)
760 struct usb_device
*dev
= ov511
->dev
;
762 PDEBUG(4, "ov511_set_picture");
764 if (ov511_stop(dev
) < 0)
767 ov511
->contrast
= p
->contrast
;
768 ov511
->brightness
= p
->brightness
;
769 ov511
->colour
= p
->colour
;
771 ov511
->whiteness
= p
->whiteness
;
773 if ((ret
= ov511_i2c_read(dev
, OV7610_REG_COM_B
)) < 0)
776 /* disable auto adjust mode */
777 if (ov511_i2c_write(dev
, OV7610_REG_COM_B
, ret
& 0xfe) < 0)
780 if (ov511
->sensor
== SEN_OV7610
|| ov511
->sensor
== SEN_OV7620AE
)
781 if(ov511_i2c_write(dev
, OV7610_REG_SAT
, p
->colour
>> 8) < 0)
784 if (ov511
->sensor
== SEN_OV7610
) {
785 if(ov511_i2c_write(dev
, OV7610_REG_CNT
, p
->contrast
>> 8) < 0)
788 if(ov511_i2c_write(dev
, OV7610_REG_BRT
, p
->brightness
>> 8) < 0)
790 } else if ((ov511
->sensor
== SEN_OV7620
)
791 || (ov511
->sensor
== SEN_OV7620AE
)) {
793 cur_con
= ov511_i2c_read(dev
, OV7610_REG_CNT
);
794 cur_brt
= ov511_i2c_read(dev
, OV7610_REG_BRT
);
796 PDEBUG(1, "con=%d brt=%d", ov511_i2c_read(dev
, OV7610_REG_CNT
),
797 ov511_i2c_read(dev
, OV7610_REG_BRT
));
799 if(ov511_i2c_write(dev
, OV7610_REG_CNT
, p
->contrast
>> 8) < 0)
804 if (ov511_restart(dev
) < 0)
811 ov7610_get_picture(struct usb_ov511
*ov511
, struct video_picture
*p
)
814 struct usb_device
*dev
= ov511
->dev
;
816 PDEBUG(4, "ov511_get_picture");
818 if (ov511_stop(dev
) < 0)
821 if((ret
= ov511_i2c_read(dev
, OV7610_REG_SAT
)) < 0) return -EIO
;
822 p
->colour
= ret
<< 8;
824 if((ret
= ov511_i2c_read(dev
, OV7610_REG_CNT
)) < 0) return -EIO
;
825 p
->contrast
= ret
<< 8;
827 if((ret
= ov511_i2c_read(dev
, OV7610_REG_BRT
)) < 0) return -EIO
;
828 p
->brightness
= ret
<< 8;
831 p
->whiteness
= 105 << 8;
833 /* Can we get these from frame[0]? -claudio? */
834 p
->depth
= ov511
->frame
[0].depth
;
835 p
->palette
= ov511
->frame
[0].format
;
837 if (ov511_restart(dev
) < 0)
843 /* FIXME: 176x144, 160x140 */
844 /* LNCNT values fixed by Lawrence Glaister <lg@jfm.bc.ca> */
845 static struct mode_list mlist
[] = {
846 /* W H C PXCNT LNCNT PXDIV LNDIV M420 COMA COMC COML */
847 { 640, 480, 0, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x04, 0x9e },
848 { 640, 480, 1, 0x4f, 0x3b, 0x00, 0x00, 0x03, 0x24, 0x04, 0x9e },
849 { 320, 240, 0, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x24, 0x1e },
850 { 320, 240, 1, 0x27, 0x1d, 0x00, 0x00, 0x03, 0x04, 0x24, 0x1e },
851 { 352, 288, 0, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e },
852 { 352, 288, 1, 0x2b, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e },
853 { 384, 288, 0, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e },
854 { 384, 288, 1, 0x2f, 0x25, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e },
855 { 448, 336, 0, 0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e },
856 { 448, 336, 1 ,0x37, 0x29, 0x00, 0x00, 0x03, 0x04, 0x04, 0x1e },
861 ov511_mode_init_regs(struct usb_ov511
*ov511
,
862 int width
, int height
, int mode
, int sub_flag
)
865 struct usb_device
*dev
= ov511
->dev
;
866 int hwsbase
= 0, hwebase
= 0;
868 PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
869 width
, height
, mode
, sub_flag
);
871 if (ov511_stop(ov511
->dev
) < 0)
874 if (mode
== VIDEO_PALETTE_GREY
) {
875 ov511_reg_write(dev
, 0x16, 0x00);
876 if (ov511
->sensor
== SEN_OV7610
877 || ov511
->sensor
== SEN_OV7620AE
) {
878 /* these aren't valid on the OV7620 */
879 ov511_i2c_write(dev
, 0x0e, 0x44);
881 ov511_i2c_write(dev
, 0x13, autoadjust
? 0x21 : 0x20);
884 ov511_reg_write(dev
, 0x1e, 0x00);
885 ov511_reg_write(dev
, 0x1f, 0x01);
887 ov511_reg_write(dev
, 0x16, 0x01);
888 if (ov511
->sensor
== SEN_OV7610
889 || ov511
->sensor
== SEN_OV7620AE
) {
890 /* not valid on the OV7620 */
891 ov511_i2c_write(dev
, 0x0e, 0x04);
893 ov511_i2c_write(dev
, 0x13, autoadjust
? 0x01 : 0x00);
896 ov511_reg_write(dev
, 0x1e, 0x01);
897 ov511_reg_write(dev
, 0x1f, 0x03);
900 /* The different sensor ICs handle setting up of window differently */
901 switch (ov511
->sensor
) {
918 ov511_i2c_write(dev
, 0x17, hwsbase
+(ov511
->subx
>>2));
919 ov511_i2c_write(dev
, 0x18, hwebase
+((ov511
->subx
+ov511
->subw
)>>2));
920 ov511_i2c_write(dev
, 0x19, 0x5+(ov511
->suby
>>1));
921 ov511_i2c_write(dev
, 0x1a, 0x5+((ov511
->suby
+ov511
->subh
)>>1));
923 ov511_i2c_write(dev
, 0x17, hwsbase
);
924 ov511_i2c_write(dev
, 0x18, hwebase
+ (640>>2));
925 ov511_i2c_write(dev
, 0x19, 0x5);
926 ov511_i2c_write(dev
, 0x1a, 5 + (480>>1));
929 for (i
= 0; mlist
[i
].width
; i
++) {
930 int lncnt
, pxcnt
, clock
;
932 if (width
!= mlist
[i
].width
|| height
!= mlist
[i
].height
)
935 if (!mlist
[i
].color
&& mode
!= VIDEO_PALETTE_GREY
)
938 /* Here I'm assuming that snapshot size == image size.
939 * I hope that's always true. --claudio
941 pxcnt
= sub_flag
? (ov511
->subw
>> 3) - 1 : mlist
[i
].pxcnt
;
942 lncnt
= sub_flag
? (ov511
->subh
>> 3) - 1 : mlist
[i
].lncnt
;
944 ov511_reg_write(dev
, 0x12, pxcnt
);
945 ov511_reg_write(dev
, 0x13, lncnt
);
946 ov511_reg_write(dev
, 0x14, mlist
[i
].pxdv
);
947 ov511_reg_write(dev
, 0x15, mlist
[i
].lndv
);
948 ov511_reg_write(dev
, 0x18, mlist
[i
].m420
);
950 /* Snapshot additions */
951 ov511_reg_write(dev
, 0x1a, pxcnt
);
952 ov511_reg_write(dev
, 0x1b, lncnt
);
953 ov511_reg_write(dev
, 0x1c, mlist
[i
].pxdv
);
954 ov511_reg_write(dev
, 0x1d, mlist
[i
].lndv
);
956 /* Calculate and set the clock divisor */
957 clock
= ((sub_flag
? ov511
->subw
* ov511
->subh
: width
* height
)
958 * (mlist
[i
].color
? 3 : 2) / 2) / 66000;
959 ov511_i2c_write(dev
, 0x11, clock
);
962 ov511_i2c_write(dev
, 0x12, mlist
[i
].common_A
| 0x08);
964 ov511_i2c_write(dev
, 0x12, mlist
[i
].common_A
);
966 ov511_i2c_write(dev
, 0x14, mlist
[i
].common_C
);
968 /* 7620 doesn't have register 0x35, so play it safe */
969 if (ov511
->sensor
!= SEN_OV7620
)
970 ov511_i2c_write(dev
, 0x35, mlist
[i
].common_L
);
975 if (ov511_restart(ov511
->dev
) < 0)
978 if (mlist
[i
].width
== 0) {
979 err("Unknown mode (%d, %d): %d", width
, height
, mode
);
985 ov511_dump_i2c_regs(dev
);
991 /**********************************************************************
993 * Color correction functions
995 **********************************************************************/
998 * Turn a YUV4:2:0 block into an RGB block
1000 * Video4Linux seems to use the blue, green, red channel
1001 * order convention-- rgb[0] is blue, rgb[1] is green, rgb[2] is red.
1003 * Color space conversion coefficients taken from the excellent
1004 * http://www.inforamp.net/~poynton/ColorFAQ.html
1005 * In his terminology, this is a CCIR 601.1 YCbCr -> RGB.
1006 * Y values are given for all 4 pixels, but the U (Pb)
1007 * and V (Pr) are assumed constant over the 2x2 block.
1009 * To avoid floating point arithmetic, the color conversion
1010 * coefficients are scaled into 16.16 fixed-point integers.
1013 /* LIMIT: convert a 16.16 fixed-point value to a byte, with clipping. */
1014 #define LIMIT(x) ((x)>0xffffff?0xff: ((x)<=0xffff?0:((x)>>16)))
1017 ov511_move_420_block(int yTL
, int yTR
, int yBL
, int yBR
, int u
, int v
,
1018 int rowPixels
, unsigned char * rgb
)
1020 const double brightness
= 1.0; /* 0->black; 1->full scale */
1021 const double saturation
= 1.0; /* 0->greyscale; 1->full color */
1022 const double fixScale
= brightness
* 256 * 256;
1023 const int rvScale
= (int)(1.402 * saturation
* fixScale
);
1024 const int guScale
= (int)(-0.344136 * saturation
* fixScale
);
1025 const int gvScale
= (int)(-0.714136 * saturation
* fixScale
);
1026 const int buScale
= (int)(1.772 * saturation
* fixScale
);
1027 const int yScale
= (int)(fixScale
);
1030 g
= guScale
* u
+ gvScale
* v
;
1039 yTL
*= yScale
; yTR
*= yScale
;
1040 yBL
*= yScale
; yBR
*= yScale
;
1042 /* Write out top two pixels */
1043 rgb
[0] = LIMIT(b
+yTL
); rgb
[1] = LIMIT(g
+yTL
); rgb
[2] = LIMIT(r
+yTL
);
1044 rgb
[3] = LIMIT(b
+yTR
); rgb
[4] = LIMIT(g
+yTR
); rgb
[5] = LIMIT(r
+yTR
);
1046 /* Skip down to next line to write out bottom two pixels */
1047 rgb
+= 3 * rowPixels
;
1048 rgb
[0] = LIMIT(b
+yBL
); rgb
[1] = LIMIT(g
+yBL
); rgb
[2] = LIMIT(r
+yBL
);
1049 rgb
[3] = LIMIT(b
+yBR
); rgb
[4] = LIMIT(g
+yBR
); rgb
[5] = LIMIT(r
+yBR
);
1053 * For a 640x480 YUV4:2:0 images, data shows up in 1200 384 byte segments.
1054 * The first 64 bytes of each segment are U, the next 64 are V. The U and
1055 * V are arranged as follows:
1062 * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
1064 * The next 256 bytes are full resolution Y data and represent 4 squares
1065 * of 8x8 pixels as follows:
1067 * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
1068 * 8 9 ... 15 72 73 ... 79 200 201 ... 207
1070 * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255
1072 * Note that the U and V data in one segment represents a 16 x 16 pixel
1073 * area, but the Y data represents a 32 x 8 pixel area.
1075 * If OV511_DUMPPIX is defined, _parse_data just dumps the incoming segments,
1076 * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
1077 * this puts the data on the standard output and can be analyzed with the
1078 * parseppm.c utility I wrote. That's a much faster way for figuring out how
1079 * this data is scrambled.
1083 #define WDIV (256/HDIV)
1085 #undef OV511_DUMPPIX
1089 ov511_parse_data_rgb24(unsigned char *pIn0
, unsigned char *pOut0
,
1090 int iOutY
, int iOutUV
, int iHalf
, int iWidth
)
1094 unsigned char *pOut
, *pOut1
;
1097 pOut
= pOut0
+ iOutUV
+ (force_rgb
? 2 : 0);
1099 for (k
= 0; k
< 8; k
++) {
1101 for (l
= 0; l
< 8; l
++) {
1102 *pOut1
= *(pOut1
+ 3) = *(pOut1
+ iWidth
*3) =
1103 *(pOut1
+ iWidth
*3 + 3) = *pIn
++;
1110 pOut
= pOut0
+ iOutUV
+ (force_rgb
? 0 : 2);
1111 for (k
= 0; k
< 8; k
++) {
1113 for (l
= 0; l
< 8; l
++) {
1114 *pOut1
= *(pOut1
+ 3) = *(pOut1
+ iWidth
*3) =
1115 *(pOut1
+ iWidth
*3 + 3) = *pIn
++;
1122 pOut
= pOut0
+ iOutY
+ 1;
1123 for (k
= 0; k
< 4; k
++) {
1125 for (l
= 0; l
< 8; l
++) {
1126 for (m
= 0; m
< 8; m
++) {
1130 pOut1
+= (iWidth
- 8) * 3;
1139 ov511_parse_data_rgb24(unsigned char *pIn0
, unsigned char *pOut0
,
1140 int iOutY
, int iOutUV
, int iHalf
, int iWidth
)
1142 #ifndef OV511_DUMPPIX
1145 unsigned char *pOut
, *pOut1
;
1147 /* Just copy the Y's if in the first stripe */
1150 pOut
= pOut0
+ iOutY
;
1151 for (k
= 0; k
< 4; k
++) {
1153 for (l
= 0; l
< 8; l
++) {
1154 for (m
= 0; m
< 8; m
++) {
1158 pOut1
+= (iWidth
- 8) * 3;
1164 /* Use the first half of VUs to calculate value */
1166 pOut
= pOut0
+ iOutUV
;
1167 for (l
= 0; l
< 4; l
++) {
1168 for (m
=0; m
<8; m
++) {
1170 int y01
= *(pOut
+3);
1171 int y10
= *(pOut
+iWidth
*3);
1172 int y11
= *(pOut
+iWidth
*3+3);
1173 int v
= *(pIn
+64) - 128;
1174 int u
= *pIn
++ - 128;
1175 ov511_move_420_block(y00
, y01
, y10
, y11
, u
, v
, iWidth
,
1179 pOut
+= (iWidth
*2 - 16) * 3;
1182 /* Just copy the other UV rows */
1183 for (l
= 0; l
< 4; l
++) {
1184 for (m
= 0; m
< 8; m
++) {
1185 *pOut
++ = *(pIn
+ 64);
1189 pOut
+= (iWidth
*2 - 16) * 3;
1192 /* Calculate values if it's the second half */
1195 pOut
= pOut0
+ iOutY
;
1196 for (k
= 0; k
< 4; k
++) {
1198 for (l
=0; l
<4; l
++) {
1199 for (m
=0; m
<4; m
++) {
1204 int v
= *pOut1
- 128;
1205 int u
= *(pOut1
+1) - 128;
1206 ov511_move_420_block(y00
, y01
, y10
,
1207 y11
, u
, v
, iWidth
, pOut1
);
1210 pOut1
+= (iWidth
*2 - 8) * 3;
1217 /* Just dump pix data straight out for debug */
1221 for (i
= 0; i
< HDIV
; i
++) {
1222 for (j
= 0; j
< WDIV
; j
++) {
1227 pOut0
+= (iWidth
- WDIV
) * 3;
1234 ov511_parse_data_yuv422(unsigned char *pIn0
, unsigned char *pOut0
,
1235 int iOutY
, int iOutUV
, int iHalf
, int iWidth
)
1239 unsigned char *pOut
, *pOut1
;
1241 /* Just copy the Y's if in the first stripe */
1244 pOut
= pOut0
+ iOutY
;
1245 for (k
= 0; k
< 4; k
++) {
1247 for (l
= 0; l
< 8; l
++) {
1248 for (m
= 0; m
< 8; m
++) {
1249 *pOut1
++ = (*pIn
++) & 0xF0;
1251 pOut1
+= iWidth
- 8;
1257 /* Use the first half of VUs to calculate value */
1259 pOut
= pOut0
+ iOutUV
;
1260 for (l
= 0; l
< 4; l
++) {
1261 for (m
=0; m
<8; m
++) {
1262 unsigned char *p00
= pOut
;
1263 unsigned char *p01
= pOut
+1;
1264 unsigned char *p10
= pOut
+iWidth
;
1265 unsigned char *p11
= pOut
+iWidth
+1;
1266 int v
= *(pIn
+64) - 128;
1267 int u
= *pIn
++ - 128;
1268 int uv
= ((u
>> 4) & 0x0C) + (v
>> 6);
1277 pOut
+= (iWidth
*2 - 16);
1280 /* Just copy the other UV rows */
1281 for (l
= 0; l
< 4; l
++) {
1282 for (m
= 0; m
< 8; m
++) {
1283 int v
= *(pIn
+ 64) - 128;
1284 int u
= (*pIn
++) - 128;
1285 int uv
= ((u
>> 4) & 0x0C) + (v
>> 6);
1289 pOut
+= (iWidth
*2 - 16);
1292 /* Calculate values if it's the second half */
1295 pOut
= pOut0
+ iOutY
;
1296 for (k
= 0; k
< 4; k
++) {
1298 for (l
=0; l
<4; l
++) {
1299 for (m
=0; m
<4; m
++) {
1306 *pOut1
= (y00
& 0xF0) | uv
;
1307 *(pOut1
+1) = (y01
& 0xF0) | uv
;
1308 *(pOut1
+iWidth
) = (y10
& 0xF0) | uv
;
1309 *(pOut1
+iWidth
+1) = (y11
& 0xF0) | uv
;
1313 pOut1
+= (iWidth
*2 - 8);
1322 ov511_parse_data_yuv422p(unsigned char *pIn0
, unsigned char *pOut0
,
1323 int iOutY
, int iOutUV
, int iWidth
, int iHeight
)
1327 unsigned char *pOut
, *pOut1
;
1328 unsigned a
= iWidth
* iHeight
;
1329 unsigned w
= iWidth
/ 2;
1332 pOut
= pOut0
+ iOutUV
+ a
;
1333 for (k
= 0; k
< 8; k
++) {
1335 for (l
= 0; l
< 8; l
++) {
1336 *pOut1
= *(pOut1
+ w
) = *pIn
++;
1343 pOut
= pOut0
+ iOutUV
+ a
+ a
/2;
1344 for (k
= 0; k
< 8; k
++) {
1346 for (l
= 0; l
< 8; l
++) {
1347 *pOut1
= *(pOut1
+ w
) = *pIn
++;
1354 pOut
= pOut0
+ iOutY
;
1355 for (k
= 0; k
< 4; k
++) {
1357 for (l
= 0; l
< 8; l
++) {
1358 for (m
= 0; m
< 8; m
++)
1360 pOut1
+= iWidth
- 8;
1367 * For 640x480 RAW BW images, data shows up in 1200 256 byte segments.
1368 * The segments represent 4 squares of 8x8 pixels as follows:
1370 * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
1371 * 8 9 ... 15 72 73 ... 79 200 201 ... 207
1373 * 56 57 ... 63 120 121 ... 127 248 249 ... 255
1377 ov511_parse_data_grey(unsigned char *pIn0
, unsigned char *pOut0
,
1378 int iOutY
, int iWidth
)
1382 unsigned char *pOut
, *pOut1
;
1385 pOut
= pOut0
+ iOutY
;
1386 for (k
= 0; k
< 4; k
++) {
1388 for (l
= 0; l
< 8; l
++) {
1389 for (m
= 0; m
< 8; m
++) {
1392 pOut1
+= iWidth
- 8;
1399 * fixFrameRGBoffset--
1400 * My camera seems to return the red channel about 1 pixel
1401 * low, and the blue channel about 1 pixel high. After YUV->RGB
1402 * conversion, we can correct this easily. OSL 2/24/2000.
1404 static void fixFrameRGBoffset(struct ov511_frame
*frame
)
1407 int rowBytes
= frame
->width
*3, w
= frame
->width
;
1408 unsigned char *rgb
= frame
->data
;
1409 const int shift
= 1; /* Distance to shift pixels by, vertically */
1411 /* Don't bother with little images */
1412 if (frame
->width
< 400)
1415 /* Shift red channel up */
1416 for (y
= shift
; y
< frame
->height
; y
++) {
1417 int lp
= (y
-shift
)*rowBytes
; /* Previous line offset */
1418 int lc
= y
*rowBytes
; /* Current line offset */
1419 for (x
= 0; x
< w
; x
++)
1420 rgb
[lp
+x
*3+2] = rgb
[lc
+x
*3+2]; /* Shift red up */
1423 /* Shift blue channel down */
1424 for (y
= frame
->height
-shift
-1; y
>= 0; y
--) {
1425 int ln
= (y
+ shift
) * rowBytes
; /* Next line offset */
1426 int lc
= y
* rowBytes
; /* Current line offset */
1427 for (x
= 0; x
< w
; x
++)
1428 rgb
[ln
+x
*3+0] = rgb
[lc
+x
*3+0]; /* Shift blue down */
1432 /**********************************************************************
1434 * OV511 data transfer, IRQ handler
1436 **********************************************************************/
1438 static int ov511_move_data(struct usb_ov511
*ov511
, urb_t
*urb
)
1440 unsigned char *cdata
;
1443 struct ov511_frame
*frame
;
1444 unsigned char *pData
;
1447 PDEBUG (4, "Moving %d packets", urb
->number_of_packets
);
1449 for (i
= 0; i
< urb
->number_of_packets
; i
++) {
1450 int n
= urb
->iso_frame_desc
[i
].actual_length
;
1451 int st
= urb
->iso_frame_desc
[i
].status
;
1453 urb
->iso_frame_desc
[i
].actual_length
= 0;
1454 urb
->iso_frame_desc
[i
].status
= 0;
1456 cdata
= urb
->transfer_buffer
+ urb
->iso_frame_desc
[i
].offset
;
1458 aPackNum
[i
] = n
? cdata
[ov511
->packet_size
- 1] : -1;
1460 if (!n
|| ov511
->curframe
== -1)
1464 PDEBUG(2, "data error: [%d] len=%d, status=%d", i
, n
, st
);
1466 frame
= &ov511
->frame
[ov511
->curframe
];
1468 /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
1469 * byte non-zero. The EOF packet has image width/height in the
1470 * 10th and 11th packets. The 9th bit is given as follows:
1473 * 6: compression enabled
1474 * 5: 422/420/400 modes
1475 * 4: 422/420/400 modes
1477 * 2: snapshot bottom on
1482 /* Check for SOF/EOF packet */
1483 if ((cdata
[0] | cdata
[1] | cdata
[2] | cdata
[3] |
1484 cdata
[4] | cdata
[5] | cdata
[6] | cdata
[7]) ||
1489 if (cdata
[8] & 0x80) {
1492 ts
= (struct timeval
*)(frame
->data
+ MAX_FRAME_SIZE
);
1493 do_gettimeofday (ts
);
1495 PDEBUG(4, "Frame end, curframe = %d, packnum=%d, hw=%d, vw=%d",
1496 ov511
->curframe
, (int)(cdata
[ov511
->packet_size
- 1]),
1497 (int)(cdata
[9]), (int)(cdata
[10]));
1499 if (frame
->scanstate
== STATE_LINES
) {
1503 fixFrameRGBoffset(frame
);
1504 frame
->grabstate
= FRAME_DONE
;
1506 if (waitqueue_active(&frame
->wq
)) {
1507 frame
->grabstate
= FRAME_DONE
;
1508 wake_up_interruptible(&frame
->wq
);
1511 /* If next frame is ready or grabbing,
1513 iFrameNext
= (ov511
->curframe
+ 1) % OV511_NUMFRAMES
;
1514 if (ov511
->frame
[iFrameNext
].grabstate
== FRAME_READY
1515 || ov511
->frame
[iFrameNext
].grabstate
== FRAME_GRABBING
) {
1516 ov511
->curframe
= iFrameNext
;
1517 ov511
->frame
[iFrameNext
].scanstate
= STATE_SCANNING
;
1519 if (frame
->grabstate
== FRAME_DONE
) {
1520 PDEBUG(4, "Frame done! congratulations");
1522 PDEBUG(4, "Frame not ready? state = %d",
1523 ov511
->frame
[iFrameNext
].grabstate
);
1526 ov511
->curframe
= -1;
1529 /* Image corruption caused by misplaced frame->segment = 0
1530 * fixed by carlosf@conectiva.com.br
1534 PDEBUG(4, "Frame start, framenum = %d", ov511
->curframe
);
1536 /* Check to see if it's a snapshot frame */
1537 /* FIXME?? Should the snapshot reset go here? Performance? */
1538 if (cdata
[8] & 0x02) {
1539 frame
->snapshot
= 1;
1540 PDEBUG(3, "snapshot detected");
1543 frame
->scanstate
= STATE_LINES
;
1548 /* Are we in a frame? */
1549 if (frame
->scanstate
!= STATE_LINES
)
1552 /* Deal with leftover from last segment, if any */
1553 if (frame
->segment
) {
1554 pData
= ov511
->scratch
;
1555 iPix
= -ov511
->scratchlen
;
1556 memmove(pData
+ ov511
->scratchlen
, cdata
,
1557 iPix
+frame
->segsize
);
1559 pData
= &cdata
[iPix
= 9];
1562 /* Parse the segments */
1563 while (iPix
<= (ov511
->packet_size
- 1) - frame
->segsize
&&
1564 frame
->segment
< frame
->width
* frame
->height
/ 256) {
1566 int iY
, jY
, iUV
, jUV
;
1567 int iOutY
, iOutYP
, iOutUV
, iOutUVP
;
1568 unsigned char *pOut
;
1570 iSegY
= iSegUV
= frame
->segment
;
1573 iPix
+= frame
->segsize
;
1575 /* Handle subwindow */
1576 if (frame
->sub_flag
) {
1579 iSeg1
= iSegY
/ (ov511
->subw
/ 32);
1580 iSeg1
*= frame
->width
/ 32;
1581 iSegY
= iSeg1
+ (iSegY
% (ov511
->subw
/ 32));
1582 if (iSegY
>= frame
->width
* ov511
->subh
/ 256)
1585 iSeg1
= iSegUV
/ (ov511
->subw
/ 16);
1586 iSeg1
*= frame
->width
/ 16;
1587 iSegUV
= iSeg1
+ (iSegUV
% (ov511
->subw
/ 16));
1589 pOut
+= (ov511
->subx
+ ov511
->suby
* frame
->width
) *
1590 (frame
->depth
>> 3);
1594 * i counts segment lines
1595 * j counts segment columns
1596 * iOut is the offset (in bytes) of the upper left corner
1598 iY
= iSegY
/ (frame
->width
/ WDIV
);
1599 jY
= iSegY
- iY
* (frame
->width
/ WDIV
);
1600 iOutYP
= iY
*HDIV
*frame
->width
+ jY
*WDIV
;
1601 iOutY
= iOutYP
* (frame
->depth
>> 3);
1602 iUV
= iSegUV
/ (frame
->width
/ WDIV
* 2);
1603 jUV
= iSegUV
- iUV
* (frame
->width
/ WDIV
* 2);
1604 iOutUVP
= iUV
*HDIV
*2*frame
->width
+ jUV
*WDIV
/2;
1605 iOutUV
= iOutUVP
* (frame
->depth
>> 3);
1607 switch (frame
->format
) {
1608 case VIDEO_PALETTE_GREY
:
1609 ov511_parse_data_grey (pData
, pOut
, iOutY
, frame
->width
);
1611 case VIDEO_PALETTE_RGB24
:
1612 ov511_parse_data_rgb24 (pData
, pOut
, iOutY
, iOutUV
,
1613 iY
& 1, frame
->width
);
1615 case VIDEO_PALETTE_YUV422
:
1616 ov511_parse_data_yuv422(pData
, pOut
, iOutY
, iOutUV
,
1617 iY
& 1, frame
->width
);
1619 case VIDEO_PALETTE_YUV422P
:
1620 ov511_parse_data_yuv422p (pData
, pOut
, iOutYP
, iOutUVP
/2,
1621 frame
->width
, frame
->height
);
1624 err("Unsupported format: %d", frame
->format
);
1627 pData
= &cdata
[iPix
];
1630 /* Save extra data for next time */
1631 if (frame
->segment
< frame
->width
* frame
->height
/ 256) {
1632 ov511
->scratchlen
= (ov511
->packet_size
- 1) - iPix
;
1633 if (ov511
->scratchlen
< frame
->segsize
)
1634 memmove(ov511
->scratch
, pData
, ov511
->scratchlen
);
1636 ov511
->scratchlen
= 0;
1640 PDEBUG(5, "pn: %d %d %d %d %d %d %d %d %d %d",
1641 aPackNum
[0], aPackNum
[1], aPackNum
[2], aPackNum
[3], aPackNum
[4],
1642 aPackNum
[5],aPackNum
[6], aPackNum
[7], aPackNum
[8], aPackNum
[9]);
1647 static void ov511_isoc_irq(struct urb
*urb
)
1650 struct usb_ov511
*ov511
= urb
->context
;
1651 struct ov511_sbuf
*sbuf
;
1656 if (!ov511
->streaming
) {
1657 PDEBUG(2, "hmmm... not streaming, but got interrupt");
1661 sbuf
= &ov511
->sbuf
[ov511
->cursbuf
];
1663 /* Copy the data received into our scratch buffer */
1664 if (ov511
->curframe
>= 0) {
1665 len
= ov511_move_data(ov511
, urb
);
1666 } else if (waitqueue_active(&ov511
->wq
)) {
1667 wake_up_interruptible(&ov511
->wq
);
1670 /* Move to the next sbuf */
1671 ov511
->cursbuf
= (ov511
->cursbuf
+ 1) % OV511_NUMSBUF
;
1676 static int ov511_init_isoc(struct usb_ov511
*ov511
)
1681 PDEBUG(3, "*** Initializing capture ***");
1683 ov511
->compress
= 0;
1684 ov511
->curframe
= -1;
1686 ov511
->scratchlen
= 0;
1688 if (ov511
->bridge
== BRG_OV511
)
1689 ov511_set_packet_size(ov511
, 993);
1690 else if (ov511
->bridge
== BRG_OV511PLUS
)
1691 ov511_set_packet_size(ov511
, 961);
1693 err("invalid bridge type");
1695 for (n
= 0; n
< OV511_NUMSBUF
; n
++) {
1696 urb
= usb_alloc_urb(FRAMES_PER_DESC
);
1699 err("init isoc: usb_alloc_urb ret. NULL");
1702 ov511
->sbuf
[n
].urb
= urb
;
1703 urb
->dev
= ov511
->dev
;
1704 urb
->context
= ov511
;
1705 urb
->pipe
= usb_rcvisocpipe(ov511
->dev
, OV511_ENDPOINT_ADDRESS
);
1706 urb
->transfer_flags
= USB_ISO_ASAP
;
1707 urb
->transfer_buffer
= ov511
->sbuf
[n
].data
;
1708 urb
->complete
= ov511_isoc_irq
;
1709 urb
->number_of_packets
= FRAMES_PER_DESC
;
1710 urb
->transfer_buffer_length
= ov511
->packet_size
* FRAMES_PER_DESC
;
1711 for (fx
= 0; fx
< FRAMES_PER_DESC
; fx
++) {
1712 urb
->iso_frame_desc
[fx
].offset
= ov511
->packet_size
* fx
;
1713 urb
->iso_frame_desc
[fx
].length
= ov511
->packet_size
;
1717 ov511
->sbuf
[OV511_NUMSBUF
- 1].urb
->next
= ov511
->sbuf
[0].urb
;
1718 for (n
= 0; n
< OV511_NUMSBUF
- 1; n
++)
1719 ov511
->sbuf
[n
].urb
->next
= ov511
->sbuf
[n
+1].urb
;
1721 for (n
= 0; n
< OV511_NUMSBUF
; n
++) {
1722 err
= usb_submit_urb(ov511
->sbuf
[n
].urb
);
1724 err("init isoc: usb_submit_urb(%d) ret %d", n
, err
);
1727 ov511
->streaming
= 1;
1732 static void ov511_stop_isoc(struct usb_ov511
*ov511
)
1736 if (!ov511
->streaming
|| !ov511
->dev
)
1739 PDEBUG (3, "*** Stopping capture ***");
1741 ov511_set_packet_size(ov511
, 0);
1743 ov511
->streaming
= 0;
1745 /* Unschedule all of the iso td's */
1746 for (n
= OV511_NUMSBUF
- 1; n
>= 0; n
--) {
1747 if (ov511
->sbuf
[n
].urb
) {
1748 ov511
->sbuf
[n
].urb
->next
= NULL
;
1749 usb_unlink_urb(ov511
->sbuf
[n
].urb
);
1750 usb_free_urb(ov511
->sbuf
[n
].urb
);
1751 ov511
->sbuf
[n
].urb
= NULL
;
1756 static int ov511_new_frame(struct usb_ov511
*ov511
, int framenum
)
1758 struct ov511_frame
*frame
;
1761 PDEBUG(4, "ov511->curframe = %d, framenum = %d", ov511
->curframe
,
1766 /* If we're not grabbing a frame right now and the other frame is */
1767 /* ready to be grabbed into, then use it instead */
1768 if (ov511
->curframe
== -1) {
1769 if (ov511
->frame
[(framenum
- 1 + OV511_NUMFRAMES
) % OV511_NUMFRAMES
].grabstate
== FRAME_READY
)
1770 framenum
= (framenum
- 1 + OV511_NUMFRAMES
) % OV511_NUMFRAMES
;
1774 frame
= &ov511
->frame
[framenum
];
1775 width
= frame
->width
;
1776 height
= frame
->height
;
1778 PDEBUG (4, "framenum = %d, width = %d, height = %d", framenum
, width
,
1781 frame
->grabstate
= FRAME_GRABBING
;
1782 frame
->scanstate
= STATE_SCANNING
;
1783 frame
->scanlength
= 0; /* accumulated in ov511_parse_data() */
1784 frame
->snapshot
= 0;
1786 ov511
->curframe
= framenum
;
1788 /* Make sure it's not too big */
1789 if (width
> DEFAULT_WIDTH
)
1790 width
= DEFAULT_WIDTH
;
1792 width
&= ~7L; /* Multiple of 8 */
1794 if (height
> DEFAULT_HEIGHT
)
1795 height
= DEFAULT_HEIGHT
;
1797 width
&= ~3L; /* Multiple of 4 */
1802 /****************************************************************************
1806 ***************************************************************************/
1807 static int ov511_alloc(struct usb_ov511
*ov511
)
1811 PDEBUG(4, "entered");
1812 down(&ov511
->buf_lock
);
1814 if (ov511
->buf_state
== BUF_PEND_DEALLOC
) {
1815 ov511
->buf_state
= BUF_ALLOCATED
;
1816 del_timer(&ov511
->buf_timer
);
1819 if (ov511
->buf_state
== BUF_ALLOCATED
)
1822 ov511
->fbuf
= rvmalloc(OV511_NUMFRAMES
* MAX_DATA_SIZE
);
1826 for (i
= 0; i
< OV511_NUMFRAMES
; i
++) {
1827 ov511
->frame
[i
].grabstate
= FRAME_UNUSED
;
1828 ov511
->frame
[i
].data
= ov511
->fbuf
+ i
* MAX_DATA_SIZE
;
1829 PDEBUG(4, "frame[%d] @ %p", i
, ov511
->frame
[i
].data
);
1831 ov511
->sbuf
[i
].data
= kmalloc(FRAMES_PER_DESC
*
1832 MAX_FRAME_SIZE_PER_DESC
, GFP_KERNEL
);
1833 if (!ov511
->sbuf
[i
].data
) {
1835 kfree(ov511
->sbuf
[i
].data
);
1836 ov511
->sbuf
[i
].data
= NULL
;
1838 rvfree(ov511
->fbuf
, OV511_NUMFRAMES
* MAX_DATA_SIZE
);
1842 PDEBUG(4, "sbuf[%d] @ %p", i
, ov511
->sbuf
[i
].data
);
1844 ov511
->buf_state
= BUF_ALLOCATED
;
1846 up(&ov511
->buf_lock
);
1847 PDEBUG(4, "leaving");
1850 ov511
->buf_state
= BUF_NOT_ALLOCATED
;
1851 up(&ov511
->buf_lock
);
1852 PDEBUG(4, "errored");
1857 * - You must acquire buf_lock before entering this function.
1858 * - Because this code will free any non-null pointer, you must be sure to null
1859 * them if you explicitly free them somewhere else!
1861 static void ov511_do_dealloc(struct usb_ov511
*ov511
)
1864 PDEBUG(4, "entered");
1867 rvfree(ov511
->fbuf
, OV511_NUMFRAMES
* MAX_DATA_SIZE
);
1871 for (i
= 0; i
< OV511_NUMFRAMES
; i
++) {
1872 if (ov511
->sbuf
[i
].data
) {
1873 kfree(ov511
->sbuf
[i
].data
);
1874 ov511
->sbuf
[i
].data
= NULL
;
1878 PDEBUG(4, "buffer memory deallocated");
1879 ov511
->buf_state
= BUF_NOT_ALLOCATED
;
1880 PDEBUG(4, "leaving");
1883 static void ov511_buf_callback(unsigned long data
)
1885 struct usb_ov511
*ov511
= (struct usb_ov511
*)data
;
1886 PDEBUG(4, "entered");
1887 down(&ov511
->buf_lock
);
1889 if (ov511
->buf_state
== BUF_PEND_DEALLOC
)
1890 ov511_do_dealloc(ov511
);
1892 up(&ov511
->buf_lock
);
1893 PDEBUG(4, "leaving");
1896 static void ov511_dealloc(struct usb_ov511
*ov511
, int now
)
1898 struct timer_list
*bt
= &(ov511
->buf_timer
);
1899 PDEBUG(4, "entered");
1900 down(&ov511
->buf_lock
);
1902 PDEBUG(4, "deallocating buffer memory %s", now
? "now" : "later");
1904 if (ov511
->buf_state
== BUF_PEND_DEALLOC
) {
1905 ov511
->buf_state
= BUF_ALLOCATED
;
1910 ov511_do_dealloc(ov511
);
1912 ov511
->buf_state
= BUF_PEND_DEALLOC
;
1914 bt
->function
= ov511_buf_callback
;
1915 bt
->data
= (unsigned long)ov511
;
1916 bt
->expires
= jiffies
+ buf_timeout
* HZ
;
1919 up(&ov511
->buf_lock
);
1920 PDEBUG(4, "leaving");
1923 /****************************************************************************
1927 ***************************************************************************/
1929 static int ov511_open(struct video_device
*dev
, int flags
)
1931 struct usb_ov511
*ov511
= (struct usb_ov511
*)dev
;
1935 PDEBUG(4, "opening");
1943 if (ov511_alloc(ov511
))
1946 ov511
->sub_flag
= 0;
1948 err
= ov511_init_isoc(ov511
);
1950 ov511_dealloc(ov511
, 0);
1965 static void ov511_close(struct video_device
*dev
)
1967 struct usb_ov511
*ov511
= (struct usb_ov511
*)dev
;
1969 PDEBUG(4, "ov511_close");
1974 ov511_stop_isoc(ov511
);
1976 ov511_dealloc(ov511
, 0);
1980 video_unregister_device(&ov511
->vdev
);
1989 static int ov511_init_done(struct video_device
*dev
)
1991 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
1992 create_proc_ov511_cam((struct usb_ov511
*)dev
);
1998 static long ov511_write(struct video_device
*dev
, const char *buf
, unsigned long count
, int noblock
)
2003 static int ov511_ioctl(struct video_device
*vdev
, unsigned int cmd
, void *arg
)
2005 struct usb_ov511
*ov511
= (struct usb_ov511
*)vdev
;
2007 PDEBUG(4, "IOCtl: 0x%X", cmd
);
2015 struct video_capability b
;
2017 PDEBUG (4, "VIDIOCGCAP");
2019 strcpy(b
.name
, "OV511 USB Camera");
2020 b
.type
= VID_TYPE_CAPTURE
| VID_TYPE_SUBCAPTURE
;
2023 b
.maxwidth
= DEFAULT_WIDTH
;
2024 b
.maxheight
= DEFAULT_HEIGHT
;
2028 if (copy_to_user(arg
, &b
, sizeof(b
)))
2035 struct video_channel v
;
2037 if (copy_from_user(&v
, arg
, sizeof(v
)))
2044 v
.type
= VIDEO_TYPE_CAMERA
;
2045 strcpy(v
.name
, "Camera");
2047 if (copy_to_user(arg
, &v
, sizeof(v
)))
2056 if (copy_from_user(&v
, arg
, sizeof(v
)))
2066 struct video_picture p
;
2068 PDEBUG (4, "VIDIOCGPICT");
2070 if (ov7610_get_picture(ov511
, &p
))
2073 if (copy_to_user(arg
, &p
, sizeof(p
)))
2080 struct video_picture p
;
2083 PDEBUG (4, "VIDIOCSPICT");
2085 if (copy_from_user(&p
, arg
, sizeof(p
)))
2088 if (ov7610_set_picture(ov511
, &p
))
2091 /* FIXME: check validity */
2093 PDEBUG(4, "Setting depth=%d, palette=%d", p
.depth
, p
.palette
);
2094 for (i
= 0; i
< OV511_NUMFRAMES
; i
++) {
2095 ov511
->frame
[i
].depth
= p
.depth
;
2096 ov511
->frame
[i
].format
= p
.palette
;
2097 ov511
->frame
[i
].segsize
= GET_SEGSIZE(p
.palette
);
2102 case VIDIOCGCAPTURE
:
2106 PDEBUG (4, "VIDIOCGCAPTURE");
2108 if (copy_from_user(&vf
, arg
, sizeof(vf
)))
2110 ov511
->sub_flag
= vf
;
2113 case VIDIOCSCAPTURE
:
2115 struct video_capture vc
;
2117 if (copy_from_user(&vc
, arg
, sizeof(vc
)))
2138 ov511
->subw
= vc
.width
;
2139 ov511
->subh
= vc
.height
;
2145 struct video_window vw
;
2148 if (copy_from_user(&vw
, arg
, sizeof(vw
)))
2151 PDEBUG (4, "VIDIOCSWIN: width=%d, height=%d",
2152 vw
.width
, vw
.height
);
2159 if (vw
.height
!= DEFAULT_HEIGHT
)
2161 if (vw
.width
!= DEFAULT_WIDTH
)
2165 /* If we're collecting previous frame wait
2166 before changing modes */
2167 interruptible_sleep_on(&ov511
->wq
);
2168 if (signal_pending(current
)) return -EINTR
;
2170 result
= ov511_mode_init_regs(ov511
, vw
.width
, vw
.height
,
2171 ov511
->frame
[0].format
, ov511
->sub_flag
);
2175 for (i
= 0; i
< OV511_NUMFRAMES
; i
++) {
2176 ov511
->frame
[i
].width
= vw
.width
;
2177 ov511
->frame
[i
].height
= vw
.height
;
2184 struct video_window vw
;
2186 vw
.x
= 0; /* FIXME */
2188 vw
.width
= ov511
->frame
[0].width
;
2189 vw
.height
= ov511
->frame
[0].height
;
2193 PDEBUG (4, "VIDIOCGWIN: %dx%d", vw
.width
, vw
.height
);
2195 if (copy_to_user(arg
, &vw
, sizeof(vw
)))
2202 struct video_mbuf vm
;
2204 memset(&vm
, 0, sizeof(vm
));
2205 vm
.size
= OV511_NUMFRAMES
* MAX_DATA_SIZE
;
2206 vm
.frames
= OV511_NUMFRAMES
;
2208 vm
.offsets
[1] = MAX_FRAME_SIZE
+ sizeof (struct timeval
);
2210 if (copy_to_user((void *)arg
, (void *)&vm
, sizeof(vm
)))
2215 case VIDIOCMCAPTURE
:
2217 struct video_mmap vm
;
2220 if (copy_from_user((void *)&vm
, (void *)arg
, sizeof(vm
)))
2223 PDEBUG(4, "CMCAPTURE");
2224 PDEBUG(4, "frame: %d, size: %dx%d, format: %d",
2225 vm
.frame
, vm
.width
, vm
.height
, vm
.format
);
2227 if (vm
.format
!= VIDEO_PALETTE_RGB24
&&
2228 vm
.format
!= VIDEO_PALETTE_YUV422
&&
2229 vm
.format
!= VIDEO_PALETTE_YUV422P
&&
2230 vm
.format
!= VIDEO_PALETTE_GREY
)
2233 if ((vm
.frame
!= 0) && (vm
.frame
!= 1))
2236 if (vm
.width
> DEFAULT_WIDTH
|| vm
.height
> DEFAULT_HEIGHT
)
2239 if (ov511
->frame
[vm
.frame
].grabstate
== FRAME_GRABBING
)
2242 /* Don't compress if the size changed */
2243 if ((ov511
->frame
[vm
.frame
].width
!= vm
.width
) ||
2244 (ov511
->frame
[vm
.frame
].height
!= vm
.height
) ||
2245 (ov511
->frame
[vm
.frame
].format
!= vm
.format
) ||
2246 (ov511
->frame
[vm
.frame
].sub_flag
!=
2248 /* If we're collecting previous frame wait
2249 before changing modes */
2250 interruptible_sleep_on(&ov511
->wq
);
2251 if (signal_pending(current
)) return -EINTR
;
2252 ret
= ov511_mode_init_regs(ov511
, vm
.width
, vm
.height
,
2253 vm
.format
, ov511
->sub_flag
);
2260 ov511
->frame
[vm
.frame
].width
= vm
.width
;
2261 ov511
->frame
[vm
.frame
].height
= vm
.height
;
2262 ov511
->frame
[vm
.frame
].format
= vm
.format
;
2263 ov511
->frame
[vm
.frame
].sub_flag
= ov511
->sub_flag
;
2264 ov511
->frame
[vm
.frame
].segsize
= GET_SEGSIZE(vm
.format
);
2265 ov511
->frame
[vm
.frame
].depth
= GET_DEPTH(vm
.format
);
2267 /* Mark it as ready */
2268 ov511
->frame
[vm
.frame
].grabstate
= FRAME_READY
;
2270 return ov511_new_frame(ov511
, vm
.frame
);
2276 if (copy_from_user((void *)&frame
, arg
, sizeof(int)))
2279 PDEBUG(4, "syncing to frame %d, grabstate = %d", frame
,
2280 ov511
->frame
[frame
].grabstate
);
2282 switch (ov511
->frame
[frame
].grabstate
) {
2286 case FRAME_GRABBING
:
2294 init_waitqueue_head(&ov511
->frame
[frame
].wq
);
2296 interruptible_sleep_on(&ov511
->frame
[frame
].wq
);
2297 if (signal_pending(current
))
2299 } while (ov511
->frame
[frame
].grabstate
== FRAME_GRABBING
);
2301 if (ov511
->frame
[frame
].grabstate
== FRAME_ERROR
) {
2304 if ((ret
= ov511_new_frame(ov511
, frame
)) < 0)
2309 ov511
->frame
[frame
].grabstate
= FRAME_UNUSED
;
2311 /* Reset the hardware snapshot button */
2312 /* FIXME - Is this the best place for this? */
2313 if ((ov511
->snap_enabled
) &&
2314 (ov511
->frame
[frame
].snapshot
)) {
2315 ov511
->frame
[frame
].snapshot
= 0;
2316 ov511_reg_write(ov511
->dev
, OV511_REG_SYSTEM_SNAPSHOT
, 0x01);
2317 ov511_reg_write(ov511
->dev
, OV511_REG_SYSTEM_SNAPSHOT
, 0x03);
2318 ov511_reg_write(ov511
->dev
, OV511_REG_SYSTEM_SNAPSHOT
, 0x01);
2327 struct video_buffer vb
;
2329 memset(&vb
, 0, sizeof(vb
));
2330 vb
.base
= NULL
; /* frame buffer not supported, not used */
2332 if (copy_to_user((void *)arg
, (void *)&vb
, sizeof(vb
)))
2353 return -ENOIOCTLCMD
;
2359 static long ov511_read(struct video_device
*dev
, char *buf
, unsigned long count
, int noblock
)
2361 struct usb_ov511
*ov511
= (struct usb_ov511
*)dev
;
2364 volatile struct ov511_frame
*frame
;
2366 PDEBUG(4, "%ld bytes, noblock=%d", count
, noblock
);
2374 /* See if a frame is completed, then use it. */
2375 if (ov511
->frame
[0].grabstate
>= FRAME_DONE
) /* _DONE or _ERROR */
2377 else if (ov511
->frame
[1].grabstate
>= FRAME_DONE
)/* _DONE or _ERROR */
2380 /* If nonblocking we return immediately */
2381 if (noblock
&& (frmx
== -1))
2384 /* If no FRAME_DONE, look for a FRAME_GRABBING state. */
2385 /* See if a frame is in process (grabbing), then use it. */
2387 if (ov511
->frame
[0].grabstate
== FRAME_GRABBING
)
2389 else if (ov511
->frame
[1].grabstate
== FRAME_GRABBING
)
2393 /* If no frame is active, start one. */
2395 ov511_new_frame(ov511
, frmx
= 0);
2397 frame
= &ov511
->frame
[frmx
];
2403 /* Wait while we're grabbing the image */
2404 PDEBUG(4, "Waiting image grabbing");
2405 while (frame
->grabstate
== FRAME_GRABBING
) {
2406 interruptible_sleep_on(&ov511
->frame
[frmx
].wq
);
2407 if (signal_pending(current
))
2410 PDEBUG(4, "Got image, frame->grabstate = %d", frame
->grabstate
);
2412 if (frame
->grabstate
== FRAME_ERROR
) {
2413 frame
->bytes_read
= 0;
2414 err("** ick! ** Errored frame %d", ov511
->curframe
);
2415 if (ov511_new_frame(ov511
, frmx
))
2416 err("read: ov511_new_frame error");
2421 /* Repeat until we get a snapshot frame */
2422 if (ov511
->snap_enabled
)
2423 PDEBUG (4, "Waiting snapshot frame");
2424 if (ov511
->snap_enabled
&& !frame
->snapshot
) {
2425 frame
->bytes_read
= 0;
2426 if (ov511_new_frame(ov511
, frmx
))
2427 err("ov511_new_frame error");
2431 /* Clear the snapshot */
2432 if (ov511
->snap_enabled
&& frame
->snapshot
) {
2433 frame
->snapshot
= 0;
2434 ov511_reg_write(ov511
->dev
, OV511_REG_SYSTEM_SNAPSHOT
, 0x01);
2435 ov511_reg_write(ov511
->dev
, OV511_REG_SYSTEM_SNAPSHOT
, 0x03);
2436 ov511_reg_write(ov511
->dev
, OV511_REG_SYSTEM_SNAPSHOT
, 0x01);
2439 PDEBUG(4, "frmx=%d, bytes_read=%ld, scanlength=%ld", frmx
,
2440 frame
->bytes_read
, frame
->scanlength
);
2442 /* copy bytes to user space; we allow for partials reads */
2443 // if ((count + frame->bytes_read) > frame->scanlength)
2444 // count = frame->scanlength - frame->bytes_read;
2446 /* FIXME - count hardwired to be one frame... */
2447 count
= frame
->width
* frame
->height
* (frame
->depth
>> 3);
2449 PDEBUG(4, "Copy to user space: %ld bytes", count
);
2450 if ((i
= copy_to_user(buf
, frame
->data
+ frame
->bytes_read
, count
))) {
2451 PDEBUG(4, "Copy failed! %d bytes not copied", i
);
2455 frame
->bytes_read
+= count
;
2456 PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld",
2457 count
, frame
->bytes_read
);
2459 if (frame
->bytes_read
>= frame
->scanlength
) { /* All data has been read */
2460 frame
->bytes_read
= 0;
2462 /* Mark it as available to be used again. */
2463 ov511
->frame
[frmx
].grabstate
= FRAME_UNUSED
;
2464 if (ov511_new_frame(ov511
, !frmx
))
2465 err("ov511_new_frame returned error");
2468 PDEBUG(4, "read finished, returning %ld (sweet)", count
);
2473 static int ov511_mmap(struct video_device
*dev
, const char *adr
,
2476 struct usb_ov511
*ov511
= (struct usb_ov511
*)dev
;
2477 unsigned long start
= (unsigned long)adr
;
2478 unsigned long page
, pos
;
2480 if (ov511
->dev
== NULL
)
2483 PDEBUG(4, "mmap: %ld (%lX) bytes", size
, size
);
2485 if (size
> (((2 * MAX_DATA_SIZE
) + PAGE_SIZE
- 1) & ~(PAGE_SIZE
- 1)))
2488 pos
= (unsigned long)ov511
->fbuf
;
2490 page
= kvirt_to_pa(pos
);
2491 if (remap_page_range(start
, page
, PAGE_SIZE
, PAGE_SHARED
))
2495 if (size
> PAGE_SIZE
)
2504 static struct video_device ov511_template
= {
2505 name
: "OV511 USB Camera",
2506 type
: VID_TYPE_CAPTURE
,
2507 hardware
: VID_HARDWARE_OV511
,
2514 initialize
: ov511_init_done
,
2517 /****************************************************************************
2519 * OV511/OV7610 configuration
2521 ***************************************************************************/
2523 static int ov76xx_configure(struct usb_ov511
*ov511
)
2525 struct usb_device
*dev
= ov511
->dev
;
2529 /* Lawrence Glaister <lg@jfm.bc.ca> reports:
2531 * Register 0x0f in the 7610 has the following effects:
2533 * 0x85 (AEC method 1): Best overall, good contrast range
2534 * 0x45 (AEC method 2): Very overexposed
2535 * 0xa5 (spec sheet default): Ok, but the black level is
2536 * shifted resulting in loss of contrast
2537 * 0x05 (old driver setting): very overexposed, too much
2540 static struct ov511_regvals aRegvalsNorm7610
[] = {
2541 { OV511_I2C_BUS
, 0x10, 0xff },
2542 { OV511_I2C_BUS
, 0x16, 0x06 },
2543 { OV511_I2C_BUS
, 0x28, 0x24 },
2544 { OV511_I2C_BUS
, 0x2b, 0xac },
2545 { OV511_I2C_BUS
, 0x05, 0x00 },
2546 { OV511_I2C_BUS
, 0x06, 0x00 },
2547 { OV511_I2C_BUS
, 0x12, 0x00 },
2548 { OV511_I2C_BUS
, 0x38, 0x81 },
2549 { OV511_I2C_BUS
, 0x28, 0x24 }, /* 0c */
2550 { OV511_I2C_BUS
, 0x05, 0x00 },
2551 { OV511_I2C_BUS
, 0x0f, 0x85 }, /* lg's setting */
2552 { OV511_I2C_BUS
, 0x15, 0x01 },
2553 { OV511_I2C_BUS
, 0x20, 0x1c },
2554 { OV511_I2C_BUS
, 0x23, 0x2a },
2555 { OV511_I2C_BUS
, 0x24, 0x10 },
2556 { OV511_I2C_BUS
, 0x25, 0x8a },
2557 { OV511_I2C_BUS
, 0x27, 0xc2 },
2558 { OV511_I2C_BUS
, 0x29, 0x03 }, /* 91 */
2559 { OV511_I2C_BUS
, 0x2a, 0x04 },
2560 { OV511_I2C_BUS
, 0x2c, 0xfe },
2561 { OV511_I2C_BUS
, 0x30, 0x71 },
2562 { OV511_I2C_BUS
, 0x31, 0x60 },
2563 { OV511_I2C_BUS
, 0x32, 0x26 },
2564 { OV511_I2C_BUS
, 0x33, 0x20 },
2565 { OV511_I2C_BUS
, 0x34, 0x48 },
2566 { OV511_I2C_BUS
, 0x12, 0x24 },
2567 { OV511_I2C_BUS
, 0x11, 0x01 },
2568 { OV511_I2C_BUS
, 0x0c, 0x24 },
2569 { OV511_I2C_BUS
, 0x0d, 0x24 },
2570 { OV511_DONE_BUS
, 0x0, 0x00 },
2573 static struct ov511_regvals aRegvalsNorm7620
[] = {
2574 { OV511_I2C_BUS
, 0x10, 0xff },
2575 { OV511_I2C_BUS
, 0x16, 0x06 },
2576 { OV511_I2C_BUS
, 0x28, 0x24 },
2577 { OV511_I2C_BUS
, 0x2b, 0xac },
2578 { OV511_I2C_BUS
, 0x12, 0x00 },
2579 { OV511_I2C_BUS
, 0x28, 0x24 },
2580 { OV511_I2C_BUS
, 0x05, 0x00 },
2581 { OV511_I2C_BUS
, 0x0f, 0x85 }, /* lg's setting */
2582 { OV511_I2C_BUS
, 0x15, 0x01 },
2583 { OV511_I2C_BUS
, 0x23, 0x00 },
2584 { OV511_I2C_BUS
, 0x24, 0x10 },
2585 { OV511_I2C_BUS
, 0x25, 0x8a },
2586 { OV511_I2C_BUS
, 0x27, 0xe2 },
2587 { OV511_I2C_BUS
, 0x29, 0x03 },
2588 { OV511_I2C_BUS
, 0x2a, 0x00 },
2589 { OV511_I2C_BUS
, 0x2c, 0xfe },
2590 { OV511_I2C_BUS
, 0x30, 0x71 },
2591 { OV511_I2C_BUS
, 0x31, 0x60 },
2592 { OV511_I2C_BUS
, 0x32, 0x26 },
2593 { OV511_I2C_BUS
, 0x33, 0x20 },
2594 { OV511_I2C_BUS
, 0x34, 0x48 },
2595 { OV511_I2C_BUS
, 0x12, 0x24 },
2596 { OV511_I2C_BUS
, 0x11, 0x01 },
2597 { OV511_I2C_BUS
, 0x0c, 0x24 },
2598 { OV511_I2C_BUS
, 0x0d, 0x24 },
2599 { OV511_DONE_BUS
, 0x0, 0x00 },
2602 PDEBUG (4, "starting configuration");
2604 if(ov511_reg_write(dev
, OV511_REG_I2C_SLAVE_ID_WRITE
,
2605 OV7610_I2C_WRITE_ID
) < 0)
2608 if(ov511_reg_write(dev
, OV511_REG_I2C_SLAVE_ID_READ
,
2609 OV7610_I2C_READ_ID
) < 0)
2612 if (ov511_reset(dev
, OV511_RESET_NOREGS
) < 0)
2615 /* Reset the 76xx */
2616 if (ov511_i2c_write(dev
, 0x12, 0x80) < 0) return -1;
2618 #if 1 /* Maybe this will fix detection problems? MM */
2619 /* Wait for it to initialize */
2620 schedule_timeout (1 + 150 * HZ
/ 1000);
2623 for (i
= 0, success
= 0; i
< i2c_detect_tries
&& !success
; i
++) {
2624 if ((ov511_i2c_read(dev
, OV7610_REG_ID_HIGH
) == 0x7F) &&
2625 (ov511_i2c_read(dev
, OV7610_REG_ID_LOW
) == 0xA2)) {
2630 /* Reset the 76xx */
2631 if (ov511_i2c_write(dev
, 0x12, 0x80) < 0) return -1;
2632 /* Wait for it to initialize */
2633 schedule_timeout (1 + 150 * HZ
/ 1000);
2634 /* Dummy read to sync I2C */
2635 if (ov511_i2c_read(dev
, 0x00) < 0) return -1;
2639 PDEBUG(1, "I2C synced in %d attempt(s)", i
);
2641 err("Failed to read sensor ID. You might not have an OV76xx,");
2642 err("or it may be not responding. Report this to");
2643 err("mmcclelland@delphi.com");
2647 /* Detect sensor if user didn't use override param */
2649 rc
= ov511_i2c_read(dev
, OV7610_REG_COM_I
);
2652 err("Error detecting sensor type");
2654 } else if((rc
& 3) == 3) {
2655 info("Sensor is an OV7610");
2656 ov511
->sensor
= SEN_OV7610
;
2657 } else if((rc
& 3) == 1) {
2658 info("Sensor is an OV7620AE");
2659 ov511
->sensor
= SEN_OV7620AE
;
2660 } else if((rc
& 3) == 0) {
2661 info("Sensor is an OV7620");
2662 ov511
->sensor
= SEN_OV7620
;
2664 err("Unknown image sensor version: %d", rc
& 3);
2667 } else { /* sensor != 0; user overrode detection */
2668 ov511
->sensor
= sensor
;
2669 info("Sensor set to type %d", ov511
->sensor
);
2672 if (ov511
->sensor
== SEN_OV7620
) {
2673 PDEBUG(4, "Writing 7620 registers");
2674 if (ov511_write_regvals(dev
, aRegvalsNorm7620
))
2677 PDEBUG(4, "Writing 7610 registers");
2678 if (ov511_write_regvals(dev
, aRegvalsNorm7610
))
2682 if (aperture
< 0) { /* go with the default */
2683 if (ov511_i2c_write(dev
, 0x26, 0xa2) < 0) return -1;
2684 } else if (aperture
<= 0xf) { /* user overrode default */
2685 if (ov511_i2c_write(dev
, 0x26, (aperture
<< 4) + 2) < 0)
2688 err("Invalid setting for aperture; legal value: 0 - 15");
2693 if (ov511_i2c_write(dev
, 0x13, 0x01) < 0) return -1;
2694 if (ov511_i2c_write(dev
, 0x2d,
2695 ov511
->sensor
==SEN_OV7620
?0x91:0x93) < 0) return -1;
2697 if (ov511_i2c_write(dev
, 0x13, 0x00) < 0) return -1;
2698 if (ov511_i2c_write(dev
, 0x2d,
2699 ov511
->sensor
==SEN_OV7620
?0x81:0x83) < 0) return -1;
2700 ov511_i2c_write(dev
, 0x28, ov511_i2c_read(dev
, 0x28) | 8);
2707 static int ov511_configure(struct usb_ov511
*ov511
)
2709 struct usb_device
*dev
= ov511
->dev
;
2712 static struct ov511_regvals aRegvalsInit
[] = {
2713 { OV511_REG_BUS
, OV511_REG_SYSTEM_RESET
, 0x7f },
2714 { OV511_REG_BUS
, OV511_REG_SYSTEM_INIT
, 0x01 },
2715 { OV511_REG_BUS
, OV511_REG_SYSTEM_RESET
, 0x7f },
2716 { OV511_REG_BUS
, OV511_REG_SYSTEM_INIT
, 0x01 },
2717 { OV511_REG_BUS
, OV511_REG_SYSTEM_RESET
, 0x3f },
2718 { OV511_REG_BUS
, OV511_REG_SYSTEM_INIT
, 0x01 },
2719 { OV511_REG_BUS
, OV511_REG_SYSTEM_RESET
, 0x3d },
2720 { OV511_DONE_BUS
, 0x0, 0x00},
2723 static struct ov511_regvals aRegvalsNorm511
[] = {
2724 { OV511_REG_BUS
, OV511_REG_DRAM_ENABLE_FLOW_CONTROL
, 0x01 },
2725 { OV511_REG_BUS
, OV511_REG_SYSTEM_SNAPSHOT
, 0x02 },
2726 { OV511_REG_BUS
, OV511_REG_SYSTEM_SNAPSHOT
, 0x00 },
2727 { OV511_REG_BUS
, OV511_REG_FIFO_BITMASK
, 0x1f }, /* 0f */
2728 { OV511_REG_BUS
, OV511_OMNICE_PREDICTION_HORIZ_Y
, 0x3f },
2729 { OV511_REG_BUS
, OV511_OMNICE_PREDICTION_HORIZ_UV
, 0x3f },
2730 { OV511_REG_BUS
, OV511_OMNICE_PREDICTION_VERT_Y
, 0x01 },
2731 { OV511_REG_BUS
, OV511_OMNICE_PREDICTION_VERT_UV
, 0x01 },
2732 { OV511_REG_BUS
, OV511_OMNICE_QUANTIZATION_HORIZ_Y
, 0x01 },
2733 { OV511_REG_BUS
, OV511_OMNICE_QUANTIZATION_HORIZ_UV
, 0x01 },
2734 { OV511_REG_BUS
, OV511_OMNICE_QUANTIZATION_VERT_Y
, 0x01 },
2735 { OV511_REG_BUS
, OV511_OMNICE_QUANTIZATION_VERT_UV
, 0x01 },
2736 { OV511_REG_BUS
, OV511_OMNICE_ENABLE
, 0x06 },
2737 { OV511_REG_BUS
, OV511_OMNICE_LUT_ENABLE
, 0x03 },
2738 { OV511_DONE_BUS
, 0x0, 0x00 },
2741 memcpy(&ov511
->vdev
, &ov511_template
, sizeof(ov511_template
));
2743 for (i
= 0; i
< OV511_NUMFRAMES
; i
++)
2744 init_waitqueue_head(&ov511
->frame
[i
].wq
);
2746 init_waitqueue_head(&ov511
->wq
);
2748 if (video_register_device(&ov511
->vdev
, VFL_TYPE_GRABBER
) == -1) {
2749 err("video_register_device failed");
2753 if (ov511_write_regvals(dev
, aRegvalsInit
)) goto error
;
2754 if (ov511_write_regvals(dev
, aRegvalsNorm511
)) goto error
;
2756 ov511_set_packet_size(ov511
, 0);
2758 ov511
->snap_enabled
= snapshot
;
2760 /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
2761 * (using read() instead). */
2762 for (i
= 0; i
< OV511_NUMFRAMES
; i
++) {
2763 ov511
->frame
[i
].width
= DEFAULT_WIDTH
;
2764 ov511
->frame
[i
].height
= DEFAULT_HEIGHT
;
2765 ov511
->frame
[i
].depth
= 24;
2766 ov511
->frame
[i
].bytes_read
= 0;
2767 ov511
->frame
[i
].segment
= 0;
2768 ov511
->frame
[i
].format
= VIDEO_PALETTE_RGB24
;
2769 ov511
->frame
[i
].segsize
= GET_SEGSIZE(ov511
->frame
[i
].format
);
2772 /* Initialize to DEFAULT_WIDTH, DEFAULT_HEIGHT, YUV4:2:0 */
2774 if(ov76xx_configure(ov511
) < 0) {
2775 err("failed to configure OV76xx");
2779 if (ov511_mode_init_regs(ov511
, DEFAULT_WIDTH
, DEFAULT_HEIGHT
,
2780 VIDEO_PALETTE_RGB24
, 0) < 0)
2786 video_unregister_device(&ov511
->vdev
);
2787 usb_driver_release_interface(&ov511_driver
,
2788 &dev
->actconfig
->interface
[ov511
->iface
]);
2794 /****************************************************************************
2798 ***************************************************************************/
2800 static void* ov511_probe(struct usb_device
*dev
, unsigned int ifnum
)
2802 struct usb_interface_descriptor
*interface
;
2803 struct usb_ov511
*ov511
;
2806 PDEBUG(1, "probing for device...");
2808 /* We don't handle multi-config cameras */
2809 if (dev
->descriptor
.bNumConfigurations
!= 1)
2812 interface
= &dev
->actconfig
->interface
[ifnum
].altsetting
[0];
2814 /* Is it an OV511/OV511+? */
2815 if (dev
->descriptor
.idVendor
!= 0x05a9)
2817 if (dev
->descriptor
.idProduct
!= 0x0511
2818 && dev
->descriptor
.idProduct
!= 0xA511)
2821 /* Checking vendor/product should be enough, but what the hell */
2822 if (interface
->bInterfaceClass
!= 0xFF)
2824 if (interface
->bInterfaceSubClass
!= 0x00)
2827 /* Since code below may sleep, we use this as a lock */
2830 if ((ov511
= kmalloc(sizeof(*ov511
), GFP_KERNEL
)) == NULL
) {
2831 err("couldn't kmalloc ov511 struct");
2835 memset(ov511
, 0, sizeof(*ov511
));
2838 ov511
->iface
= interface
->bInterfaceNumber
;
2840 switch (dev
->descriptor
.idProduct
) {
2842 info("USB OV511 camera found");
2843 ov511
->bridge
= BRG_OV511
;
2846 info("USB OV511+ camera found");
2847 ov511
->bridge
= BRG_OV511PLUS
;
2851 ov511
->customid
= ov511_reg_read(dev
, OV511_REG_SYSTEM_CUSTOM_ID
);
2852 if (ov511
->customid
< 0) {
2853 err("Unable to read camera bridge registers");
2858 PDEBUG (4, "CustomID = %d", ov511
->customid
);
2859 for (i
= 0; clist
[i
].id
>= 0; i
++) {
2860 if (ov511
->customid
== clist
[i
].id
) {
2861 info("camera: %s", clist
[i
].description
);
2867 /* Lifeview USB Life TV not supported */
2868 if (clist
[i
].id
== 38) {
2869 err("This device is not supported yet.");
2873 if (clist
[i
].id
== -1) {
2874 err("Camera type (%d) not recognized", ov511
->customid
);
2875 err("Please contact mmcclelland@delphi.com to request");
2876 err("support for your camera.");
2879 /* Workaround for some applications that want data in RGB
2882 info("data format set to RGB");
2884 if (!ov511_configure(ov511
)) {
2886 init_MUTEX(&ov511
->lock
); /* to 1 == available */
2887 init_MUTEX(&ov511
->buf_lock
);
2888 ov511
->buf_state
= BUF_NOT_ALLOCATED
;
2890 err("Failed to configure camera");
2908 static void ov511_disconnect(struct usb_device
*dev
, void *ptr
)
2910 struct usb_ov511
*ov511
= (struct usb_ov511
*) ptr
;
2915 /* We don't want people trying to open up the device */
2917 video_unregister_device(&ov511
->vdev
);
2919 usb_driver_release_interface(&ov511_driver
,
2920 &ov511
->dev
->actconfig
->interface
[ov511
->iface
]);
2923 for (n
= 0; n
< OV511_NUMFRAMES
; n
++)
2924 ov511
->frame
[n
].grabstate
= FRAME_ERROR
;
2926 ov511
->curframe
= -1;
2928 /* This will cause the process to request another frame */
2929 for (n
= 0; n
< OV511_NUMFRAMES
; n
++)
2930 if (waitqueue_active(&ov511
->frame
[n
].wq
))
2931 wake_up_interruptible(&ov511
->frame
[n
].wq
);
2932 if (waitqueue_active(&ov511
->wq
))
2933 wake_up_interruptible(&ov511
->wq
);
2935 ov511
->streaming
= 0;
2937 /* Unschedule all of the iso td's */
2938 for (n
= OV511_NUMSBUF
- 1; n
>= 0; n
--) {
2939 if (ov511
->sbuf
[n
].urb
) {
2940 ov511
->sbuf
[n
].urb
->next
= NULL
;
2941 usb_unlink_urb(ov511
->sbuf
[n
].urb
);
2942 usb_free_urb(ov511
->sbuf
[n
].urb
);
2943 ov511
->sbuf
[n
].urb
= NULL
;
2947 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
2948 destroy_proc_ov511_cam(ov511
);
2951 /* FIXME - is this correct/safe? Should we acquire ov511->lock? */
2952 ov511_dealloc(ov511
, 1);
2954 /* Free the memory */
2955 if (ov511
&& !ov511
->user
) {
2963 static struct usb_driver ov511_driver
= {
2971 /****************************************************************************
2975 ***************************************************************************/
2977 static int __init
usb_ov511_init(void)
2979 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
2980 proc_ov511_create();
2983 if (usb_register(&ov511_driver
) < 0)
2986 info("ov511 driver version %s registered", version
);
2991 static void __exit
usb_ov511_exit(void)
2993 usb_deregister(&ov511_driver
);
2994 info("driver deregistered");
2996 #if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
2997 proc_ov511_destroy();
3001 module_init(usb_ov511_init
);
3002 module_exit(usb_ov511_exit
);