• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/media/video/usbvideo/
1/*
2 * USB ViCam WebCam driver
3 * Copyright (c) 2002 Joe Burks (jburks@wavicle.org),
4 *                    Christopher L Cheney (ccheney@cheney.cx),
5 *                    Pavel Machek (pavel@ucw.cz),
6 *                    John Tyner (jtyner@cs.ucr.edu),
7 *                    Monroe Williams (monroe@pobox.com)
8 *
9 * Supports 3COM HomeConnect PC Digital WebCam
10 * Supports Compro PS39U WebCam
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *
26 * This source code is based heavily on the CPiA webcam driver which was
27 * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
28 *
29 * Portions of this code were also copied from usbvideo.c
30 *
31 * Special thanks to the whole team at Sourceforge for help making
32 * this driver become a reality.  Notably:
33 * Andy Armstrong who reverse engineered the color encoding and
34 * Pavel Machek and Chris Cheney who worked on reverse engineering the
35 *    camera controls and wrote the first generation driver.
36 */
37
38#include <linux/kernel.h>
39#include <linux/module.h>
40#include <linux/init.h>
41#include <linux/videodev.h>
42#include <linux/usb.h>
43#include <linux/vmalloc.h>
44#include <linux/mm.h>
45#include <linux/slab.h>
46#include <linux/smp_lock.h>
47#include <linux/mutex.h>
48#include <linux/firmware.h>
49#include <linux/ihex.h>
50#include "usbvideo.h"
51
52// #define VICAM_DEBUG
53
54#ifdef VICAM_DEBUG
55#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __func__, lineno, ##args)
56#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
57#else
58#define DBG(fmn,args...) do {} while(0)
59#endif
60
61#define DRIVER_AUTHOR           "Joe Burks, jburks@wavicle.org"
62#define DRIVER_DESC             "ViCam WebCam Driver"
63
64/* Define these values to match your device */
65#define USB_VICAM_VENDOR_ID	0x04c1
66#define USB_VICAM_PRODUCT_ID	0x009d
67#define USB_COMPRO_VENDOR_ID	0x0602
68#define USB_COMPRO_PRODUCT_ID	0x1001
69
70#define VICAM_BYTES_PER_PIXEL   3
71#define VICAM_MAX_READ_SIZE     (512*242+128)
72#define VICAM_MAX_FRAME_SIZE    (VICAM_BYTES_PER_PIXEL*320*240)
73#define VICAM_FRAMES            2
74
75#define VICAM_HEADER_SIZE       64
76
77/* rvmalloc / rvfree copied from usbvideo.c
78 *
79 * Not sure why these are not yet non-statics which I can reference through
80 * usbvideo.h the same as it is in 2.4.20.  I bet this will get fixed sometime
81 * in the future.
82 *
83*/
84static void *rvmalloc(unsigned long size)
85{
86	void *mem;
87	unsigned long adr;
88
89	size = PAGE_ALIGN(size);
90	mem = vmalloc_32(size);
91	if (!mem)
92		return NULL;
93
94	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
95	adr = (unsigned long) mem;
96	while (size > 0) {
97		SetPageReserved(vmalloc_to_page((void *)adr));
98		adr += PAGE_SIZE;
99		size -= PAGE_SIZE;
100	}
101
102	return mem;
103}
104
105static void rvfree(void *mem, unsigned long size)
106{
107	unsigned long adr;
108
109	if (!mem)
110		return;
111
112	adr = (unsigned long) mem;
113	while ((long) size > 0) {
114		ClearPageReserved(vmalloc_to_page((void *)adr));
115		adr += PAGE_SIZE;
116		size -= PAGE_SIZE;
117	}
118	vfree(mem);
119}
120
121struct vicam_camera {
122	u16 shutter_speed;	// capture shutter speed
123	u16 gain;		// capture gain
124
125	u8 *raw_image;		// raw data captured from the camera
126	u8 *framebuf;		// processed data in RGB24 format
127	u8 *cntrlbuf;		// area used to send control msgs
128
129	struct video_device vdev;	// v4l video device
130	struct usb_device *udev;	// usb device
131
132	/* guard against simultaneous accesses to the camera */
133	struct mutex cam_lock;
134
135	int is_initialized;
136	u8 open_count;
137	u8 bulkEndpoint;
138	int needsDummyRead;
139};
140
141static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
142static void vicam_disconnect(struct usb_interface *intf);
143static void read_frame(struct vicam_camera *cam, int framenum);
144static void vicam_decode_color(const u8 *, u8 *);
145
146static int __send_control_msg(struct vicam_camera *cam,
147			      u8 request,
148			      u16 value,
149			      u16 index,
150			      unsigned char *cp,
151			      u16 size)
152{
153	int status;
154
155	/* cp must be memory that has been allocated by kmalloc */
156
157	status = usb_control_msg(cam->udev,
158				 usb_sndctrlpipe(cam->udev, 0),
159				 request,
160				 USB_DIR_OUT | USB_TYPE_VENDOR |
161				 USB_RECIP_DEVICE, value, index,
162				 cp, size, 1000);
163
164	status = min(status, 0);
165
166	if (status < 0) {
167		printk(KERN_INFO "Failed sending control message, error %d.\n",
168		       status);
169	}
170
171	return status;
172}
173
174static int send_control_msg(struct vicam_camera *cam,
175			    u8 request,
176			    u16 value,
177			    u16 index,
178			    unsigned char *cp,
179			    u16 size)
180{
181	int status = -ENODEV;
182	mutex_lock(&cam->cam_lock);
183	if (cam->udev) {
184		status = __send_control_msg(cam, request, value,
185					    index, cp, size);
186	}
187	mutex_unlock(&cam->cam_lock);
188	return status;
189}
190static int
191initialize_camera(struct vicam_camera *cam)
192{
193	int err;
194	const struct ihex_binrec *rec;
195	const struct firmware *uninitialized_var(fw);
196
197	err = request_ihex_firmware(&fw, "vicam/firmware.fw", &cam->udev->dev);
198	if (err) {
199		printk(KERN_ERR "Failed to load \"vicam/firmware.fw\": %d\n",
200		       err);
201		return err;
202	}
203
204	for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) {
205		memcpy(cam->cntrlbuf, rec->data, be16_to_cpu(rec->len));
206
207		err = send_control_msg(cam, 0xff, 0, 0,
208				       cam->cntrlbuf, be16_to_cpu(rec->len));
209		if (err)
210			break;
211	}
212
213	release_firmware(fw);
214
215	return err;
216}
217
218static int
219set_camera_power(struct vicam_camera *cam, int state)
220{
221	int status;
222
223	if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
224		return status;
225
226	if (state) {
227		send_control_msg(cam, 0x55, 1, 0, NULL, 0);
228	}
229
230	return 0;
231}
232
233static long
234vicam_ioctl(struct file *file, unsigned int ioctlnr, unsigned long arg)
235{
236	void __user *user_arg = (void __user *)arg;
237	struct vicam_camera *cam = file->private_data;
238	long retval = 0;
239
240	if (!cam)
241		return -ENODEV;
242
243	switch (ioctlnr) {
244		/* query capabilities */
245	case VIDIOCGCAP:
246		{
247			struct video_capability b;
248
249			DBG("VIDIOCGCAP\n");
250			memset(&b, 0, sizeof(b));
251			strcpy(b.name, "ViCam-based Camera");
252			b.type = VID_TYPE_CAPTURE;
253			b.channels = 1;
254			b.audios = 0;
255			b.maxwidth = 320;	/* VIDEOSIZE_CIF */
256			b.maxheight = 240;
257			b.minwidth = 320;	/* VIDEOSIZE_48_48 */
258			b.minheight = 240;
259
260			if (copy_to_user(user_arg, &b, sizeof(b)))
261				retval = -EFAULT;
262
263			break;
264		}
265		/* get/set video source - we are a camera and nothing else */
266	case VIDIOCGCHAN:
267		{
268			struct video_channel v;
269
270			DBG("VIDIOCGCHAN\n");
271			if (copy_from_user(&v, user_arg, sizeof(v))) {
272				retval = -EFAULT;
273				break;
274			}
275			if (v.channel != 0) {
276				retval = -EINVAL;
277				break;
278			}
279
280			v.channel = 0;
281			strcpy(v.name, "Camera");
282			v.tuners = 0;
283			v.flags = 0;
284			v.type = VIDEO_TYPE_CAMERA;
285			v.norm = 0;
286
287			if (copy_to_user(user_arg, &v, sizeof(v)))
288				retval = -EFAULT;
289			break;
290		}
291
292	case VIDIOCSCHAN:
293		{
294			int v;
295
296			if (copy_from_user(&v, user_arg, sizeof(v)))
297				retval = -EFAULT;
298			DBG("VIDIOCSCHAN %d\n", v);
299
300			if (retval == 0 && v != 0)
301				retval = -EINVAL;
302
303			break;
304		}
305
306		/* image properties */
307	case VIDIOCGPICT:
308		{
309			struct video_picture vp;
310			DBG("VIDIOCGPICT\n");
311			memset(&vp, 0, sizeof (struct video_picture));
312			vp.brightness = cam->gain << 8;
313			vp.depth = 24;
314			vp.palette = VIDEO_PALETTE_RGB24;
315			if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
316				retval = -EFAULT;
317			break;
318		}
319
320	case VIDIOCSPICT:
321		{
322			struct video_picture vp;
323
324			if (copy_from_user(&vp, user_arg, sizeof(vp))) {
325				retval = -EFAULT;
326				break;
327			}
328
329			DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
330			    vp.palette);
331
332			cam->gain = vp.brightness >> 8;
333
334			if (vp.depth != 24
335			    || vp.palette != VIDEO_PALETTE_RGB24)
336				retval = -EINVAL;
337
338			break;
339		}
340
341		/* get/set capture window */
342	case VIDIOCGWIN:
343		{
344			struct video_window vw;
345			vw.x = 0;
346			vw.y = 0;
347			vw.width = 320;
348			vw.height = 240;
349			vw.chromakey = 0;
350			vw.flags = 0;
351			vw.clips = NULL;
352			vw.clipcount = 0;
353
354			DBG("VIDIOCGWIN\n");
355
356			if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
357				retval = -EFAULT;
358
359			// I'm not sure what the deal with a capture window is, it is very poorly described
360			// in the doc.  So I won't support it now.
361			break;
362		}
363
364	case VIDIOCSWIN:
365		{
366
367			struct video_window vw;
368
369			if (copy_from_user(&vw, user_arg, sizeof(vw))) {
370				retval = -EFAULT;
371				break;
372			}
373
374			DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
375
376			if ( vw.width != 320 || vw.height != 240 )
377				retval = -EFAULT;
378
379			break;
380		}
381
382		/* mmap interface */
383	case VIDIOCGMBUF:
384		{
385			struct video_mbuf vm;
386			int i;
387
388			DBG("VIDIOCGMBUF\n");
389			memset(&vm, 0, sizeof (vm));
390			vm.size =
391			    VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
392			vm.frames = VICAM_FRAMES;
393			for (i = 0; i < VICAM_FRAMES; i++)
394				vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
395
396			if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
397				retval = -EFAULT;
398
399			break;
400		}
401
402	case VIDIOCMCAPTURE:
403		{
404			struct video_mmap vm;
405			// int video_size;
406
407			if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
408				retval = -EFAULT;
409				break;
410			}
411
412			DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
413
414			if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
415				retval = -EINVAL;
416
417			// in theory right here we'd start the image capturing
418			// (fill in a bulk urb and submit it asynchronously)
419			//
420			// Instead we're going to do a total hack job for now and
421			// retrieve the frame in VIDIOCSYNC
422
423			break;
424		}
425
426	case VIDIOCSYNC:
427		{
428			int frame;
429
430			if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
431				retval = -EFAULT;
432				break;
433			}
434			DBG("VIDIOCSYNC: %d\n", frame);
435
436			read_frame(cam, frame);
437			vicam_decode_color(cam->raw_image,
438					   cam->framebuf +
439					   frame * VICAM_MAX_FRAME_SIZE );
440
441			break;
442		}
443
444		/* pointless to implement overlay with this camera */
445	case VIDIOCCAPTURE:
446	case VIDIOCGFBUF:
447	case VIDIOCSFBUF:
448	case VIDIOCKEY:
449		retval = -EINVAL;
450		break;
451
452		/* tuner interface - we have none */
453	case VIDIOCGTUNER:
454	case VIDIOCSTUNER:
455	case VIDIOCGFREQ:
456	case VIDIOCSFREQ:
457		retval = -EINVAL;
458		break;
459
460		/* audio interface - we have none */
461	case VIDIOCGAUDIO:
462	case VIDIOCSAUDIO:
463		retval = -EINVAL;
464		break;
465	default:
466		retval = -ENOIOCTLCMD;
467		break;
468	}
469
470	return retval;
471}
472
473static int
474vicam_open(struct file *file)
475{
476	struct vicam_camera *cam = video_drvdata(file);
477
478	DBG("open\n");
479
480	if (!cam) {
481		printk(KERN_ERR
482		       "vicam video_device improperly initialized");
483		return -EINVAL;
484	}
485
486	/* the videodev_lock held above us protects us from
487	 * simultaneous opens...for now. we probably shouldn't
488	 * rely on this fact forever.
489	 */
490
491	lock_kernel();
492	if (cam->open_count > 0) {
493		printk(KERN_INFO
494		       "vicam_open called on already opened camera");
495		unlock_kernel();
496		return -EBUSY;
497	}
498
499	cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
500	if (!cam->raw_image) {
501		unlock_kernel();
502		return -ENOMEM;
503	}
504
505	cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
506	if (!cam->framebuf) {
507		kfree(cam->raw_image);
508		unlock_kernel();
509		return -ENOMEM;
510	}
511
512	cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
513	if (!cam->cntrlbuf) {
514		kfree(cam->raw_image);
515		rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
516		unlock_kernel();
517		return -ENOMEM;
518	}
519
520	// First upload firmware, then turn the camera on
521
522	if (!cam->is_initialized) {
523		initialize_camera(cam);
524
525		cam->is_initialized = 1;
526	}
527
528	set_camera_power(cam, 1);
529
530	cam->needsDummyRead = 1;
531	cam->open_count++;
532
533	file->private_data = cam;
534	unlock_kernel();
535
536	return 0;
537}
538
539static int
540vicam_close(struct file *file)
541{
542	struct vicam_camera *cam = file->private_data;
543	int open_count;
544	struct usb_device *udev;
545
546	DBG("close\n");
547
548	/* it's not the end of the world if
549	 * we fail to turn the camera off.
550	 */
551
552	set_camera_power(cam, 0);
553
554	kfree(cam->raw_image);
555	rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
556	kfree(cam->cntrlbuf);
557
558	mutex_lock(&cam->cam_lock);
559
560	cam->open_count--;
561	open_count = cam->open_count;
562	udev = cam->udev;
563
564	mutex_unlock(&cam->cam_lock);
565
566	if (!open_count && !udev) {
567		kfree(cam);
568	}
569
570	return 0;
571}
572
573static void vicam_decode_color(const u8 *data, u8 *rgb)
574{
575	/* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
576	 * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
577	 */
578
579	int i, prevY, nextY;
580
581	prevY = 512;
582	nextY = 512;
583
584	data += VICAM_HEADER_SIZE;
585
586	for( i = 0; i < 240; i++, data += 512 ) {
587		const int y = ( i * 242 ) / 240;
588
589		int j, prevX, nextX;
590		int Y, Cr, Cb;
591
592		if ( y == 242 - 1 ) {
593			nextY = -512;
594		}
595
596		prevX = 1;
597		nextX = 1;
598
599		for ( j = 0; j < 320; j++, rgb += 3 ) {
600			const int x = ( j * 512 ) / 320;
601			const u8 * const src = &data[x];
602
603			if ( x == 512 - 1 ) {
604				nextX = -1;
605			}
606
607			Cr = ( src[prevX] - src[0] ) +
608				( src[nextX] - src[0] );
609			Cr /= 2;
610
611			Cb = ( src[prevY] - src[prevX + prevY] ) +
612				( src[prevY] - src[nextX + prevY] ) +
613				( src[nextY] - src[prevX + nextY] ) +
614				( src[nextY] - src[nextX + nextY] );
615			Cb /= 4;
616
617			Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
618
619			if ( i & 1 ) {
620				int Ct = Cr;
621				Cr = Cb;
622				Cb = Ct;
623			}
624
625			if ( ( x ^ i ) & 1 ) {
626				Cr = -Cr;
627				Cb = -Cb;
628			}
629
630			rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
631					500 ) / 900, 0, 255 );
632			rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
633					  ( 813 * Cr ) ) +
634					  500 ) / 1000, 0, 255 );
635			rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
636					500 ) / 1300, 0, 255 );
637
638			prevX = -1;
639		}
640
641		prevY = -512;
642	}
643}
644
645static void
646read_frame(struct vicam_camera *cam, int framenum)
647{
648	unsigned char *request = cam->cntrlbuf;
649	int realShutter;
650	int n;
651	int actual_length;
652
653	if (cam->needsDummyRead) {
654		cam->needsDummyRead = 0;
655		read_frame(cam, framenum);
656	}
657
658	memset(request, 0, 16);
659	request[0] = cam->gain;	// 0 = 0% gain, FF = 100% gain
660
661	request[1] = 0;	// 512x242 capture
662
663	request[2] = 0x90;	// the function of these two bytes
664	request[3] = 0x07;	// is not yet understood
665
666	if (cam->shutter_speed > 60) {
667		// Short exposure
668		realShutter =
669		    ((-15631900 / cam->shutter_speed) + 260533) / 1000;
670		request[4] = realShutter & 0xFF;
671		request[5] = (realShutter >> 8) & 0xFF;
672		request[6] = 0x03;
673		request[7] = 0x01;
674	} else {
675		// Long exposure
676		realShutter = 15600 / cam->shutter_speed - 1;
677		request[4] = 0;
678		request[5] = 0;
679		request[6] = realShutter & 0xFF;
680		request[7] = realShutter >> 8;
681	}
682
683	// Per John Markus Bj��rndalen, byte at index 8 causes problems if it isn't 0
684	request[8] = 0;
685	// bytes 9-15 do not seem to affect exposure or image quality
686
687	mutex_lock(&cam->cam_lock);
688
689	if (!cam->udev) {
690		goto done;
691	}
692
693	n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
694
695	if (n < 0) {
696		printk(KERN_ERR
697		       " Problem sending frame capture control message");
698		goto done;
699	}
700
701	n = usb_bulk_msg(cam->udev,
702			 usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
703			 cam->raw_image,
704			 512 * 242 + 128, &actual_length, 10000);
705
706	if (n < 0) {
707		printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
708		       n);
709	}
710
711 done:
712	mutex_unlock(&cam->cam_lock);
713}
714
715static ssize_t
716vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
717{
718	struct vicam_camera *cam = file->private_data;
719
720	DBG("read %d bytes.\n", (int) count);
721
722	if (*ppos >= VICAM_MAX_FRAME_SIZE) {
723		*ppos = 0;
724		return 0;
725	}
726
727	if (*ppos == 0) {
728		read_frame(cam, 0);
729		vicam_decode_color(cam->raw_image,
730				   cam->framebuf +
731				   0 * VICAM_MAX_FRAME_SIZE);
732	}
733
734	count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
735
736	if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
737		count = -EFAULT;
738	} else {
739		*ppos += count;
740	}
741
742	if (count == VICAM_MAX_FRAME_SIZE) {
743		*ppos = 0;
744	}
745
746	return count;
747}
748
749
750static int
751vicam_mmap(struct file *file, struct vm_area_struct *vma)
752{
753	// TODO: allocate the raw frame buffer if necessary
754	unsigned long page, pos;
755	unsigned long start = vma->vm_start;
756	unsigned long size  = vma->vm_end-vma->vm_start;
757	struct vicam_camera *cam = file->private_data;
758
759	if (!cam)
760		return -ENODEV;
761
762	DBG("vicam_mmap: %ld\n", size);
763
764	/* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
765	 * to the size the application requested for mmap and it was screwing apps up.
766	 if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
767	 return -EINVAL;
768	 */
769
770	pos = (unsigned long)cam->framebuf;
771	while (size > 0) {
772		page = vmalloc_to_pfn((void *)pos);
773		if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
774			return -EAGAIN;
775
776		start += PAGE_SIZE;
777		pos += PAGE_SIZE;
778		if (size > PAGE_SIZE)
779			size -= PAGE_SIZE;
780		else
781			size = 0;
782	}
783
784	return 0;
785}
786
787static const struct v4l2_file_operations vicam_fops = {
788	.owner		= THIS_MODULE,
789	.open		= vicam_open,
790	.release	= vicam_close,
791	.read		= vicam_read,
792	.mmap		= vicam_mmap,
793	.ioctl		= vicam_ioctl,
794};
795
796static struct video_device vicam_template = {
797	.name 		= "ViCam-based USB Camera",
798	.fops 		= &vicam_fops,
799	.release 	= video_device_release_empty,
800};
801
802/* table of devices that work with this driver */
803static struct usb_device_id vicam_table[] = {
804	{USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
805	{USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
806	{}			/* Terminating entry */
807};
808
809MODULE_DEVICE_TABLE(usb, vicam_table);
810
811static struct usb_driver vicam_driver = {
812	.name		= "vicam",
813	.probe		= vicam_probe,
814	.disconnect	= vicam_disconnect,
815	.id_table	= vicam_table
816};
817
818/**
819 *	vicam_probe
820 *	@intf: the interface
821 *	@id: the device id
822 *
823 *	Called by the usb core when a new device is connected that it thinks
824 *	this driver might be interested in.
825 */
826static int
827vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
828{
829	struct usb_device *dev = interface_to_usbdev(intf);
830	int bulkEndpoint = 0;
831	const struct usb_host_interface *interface;
832	const struct usb_endpoint_descriptor *endpoint;
833	struct vicam_camera *cam;
834
835	printk(KERN_INFO "ViCam based webcam connected\n");
836
837	interface = intf->cur_altsetting;
838
839	DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
840	       interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
841	endpoint = &interface->endpoint[0].desc;
842
843	if (usb_endpoint_is_bulk_in(endpoint)) {
844		/* we found a bulk in endpoint */
845		bulkEndpoint = endpoint->bEndpointAddress;
846	} else {
847		printk(KERN_ERR
848		       "No bulk in endpoint was found ?! (this is bad)\n");
849	}
850
851	if ((cam =
852	     kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
853		printk(KERN_WARNING
854		       "could not allocate kernel memory for vicam_camera struct\n");
855		return -ENOMEM;
856	}
857
858
859	cam->shutter_speed = 15;
860
861	mutex_init(&cam->cam_lock);
862
863	memcpy(&cam->vdev, &vicam_template, sizeof(vicam_template));
864	video_set_drvdata(&cam->vdev, cam);
865
866	cam->udev = dev;
867	cam->bulkEndpoint = bulkEndpoint;
868
869	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) < 0) {
870		kfree(cam);
871		printk(KERN_WARNING "video_register_device failed\n");
872		return -EIO;
873	}
874
875	printk(KERN_INFO "ViCam webcam driver now controlling device %s\n",
876		video_device_node_name(&cam->vdev));
877
878	usb_set_intfdata (intf, cam);
879
880	return 0;
881}
882
883static void
884vicam_disconnect(struct usb_interface *intf)
885{
886	int open_count;
887	struct vicam_camera *cam = usb_get_intfdata (intf);
888	usb_set_intfdata (intf, NULL);
889
890	/* we must unregister the device before taking its
891	 * cam_lock. This is because the video open call
892	 * holds the same lock as video unregister. if we
893	 * unregister inside of the cam_lock and open also
894	 * uses the cam_lock, we get deadlock.
895	 */
896
897	video_unregister_device(&cam->vdev);
898
899	/* stop the camera from being used */
900
901	mutex_lock(&cam->cam_lock);
902
903	/* mark the camera as gone */
904
905	cam->udev = NULL;
906
907	/* the only thing left to do is synchronize with
908	 * our close/release function on who should release
909	 * the camera memory. if there are any users using the
910	 * camera, it's their job. if there are no users,
911	 * it's ours.
912	 */
913
914	open_count = cam->open_count;
915
916	mutex_unlock(&cam->cam_lock);
917
918	if (!open_count) {
919		kfree(cam);
920	}
921
922	printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
923}
924
925/*
926 */
927static int __init
928usb_vicam_init(void)
929{
930	int retval;
931	DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
932	retval = usb_register(&vicam_driver);
933	if (retval)
934		printk(KERN_WARNING "usb_register failed!\n");
935	return retval;
936}
937
938static void __exit
939usb_vicam_exit(void)
940{
941	DBG(KERN_INFO
942	       "ViCam-based WebCam driver shutdown\n");
943
944	usb_deregister(&vicam_driver);
945}
946
947module_init(usb_vicam_init);
948module_exit(usb_vicam_exit);
949
950MODULE_AUTHOR(DRIVER_AUTHOR);
951MODULE_DESCRIPTION(DRIVER_DESC);
952MODULE_LICENSE("GPL");
953MODULE_FIRMWARE("vicam/firmware.fw");
954