11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Linux driver for Philips webcam
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   USB and Video4Linux interface part.
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   (C) 1999-2004 Nemosoft Unv.
42b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard   (C) 2004-2006 Luc Saillard (luc@saillard.org)
56eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede   (C) 2011 Hans de Goede <hdegoede@redhat.com>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   driver and thus may have bugs that are not present in the original version.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Please send bug reports and support requests to <luc@saillard.org>.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   The decompression routines have been implemented by reverse-engineering the
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Nemosoft binary pwcx module. Caveat emptor.
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This program is free software; you can redistribute it and/or modify
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   it under the terms of the GNU General Public License as published by
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   the Free Software Foundation; either version 2 of the License, or
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   (at your option) any later version.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This program is distributed in the hope that it will be useful,
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   but WITHOUT ANY WARRANTY; without even the implied warranty of
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   GNU General Public License for more details.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   You should have received a copy of the GNU General Public License
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   along with this program; if not, write to the Free Software
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
29d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab/*
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   This code forms the interface between the USB layers and the Philips
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   specific stuff. Some adanved stuff of the driver falls under an
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and
33d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab   is thus not distributed in source form. The binary pwcx.o module
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   contains the code that falls under the NDA.
35d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
36d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab   In case you're wondering: 'pwc' stands for "Philips WebCam", but
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   I really didn't want to type 'philips_web_cam' every time (I'm lazy as
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   any Linux kernel hacker, but I don't like uncomprehensible abbreviations
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   without explanation).
40d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Oh yes, convention: to disctinguish between all the various pointers to
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   device-structures, I use these names for the pointer variables:
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   udev: struct usb_device *
449a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede   vdev: struct video_device (member of pwc_dev)
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   pdev: struct pwc_devive *
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Contributors:
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - Alvarado: adding whitebalance code
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - Alistar Moire: QuickCam 3000 Pro device/product ID
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - Tony Hoyle: Creative Labs Webcam 5 device/product ID
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - Jk Fang: Sotec Afina Eye ID
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - Xavier Roche: QuickCam Pro 4000 ID
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - Jens Knudsen: QuickCam Zoom ID
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   - J. Debert: QuickCam for Notebooks ID
57e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành   - Pham Thanh Nam: webcam snapshot button as an event input device
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/poll.h>
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
66e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành#ifdef CONFIG_USB_PWC_INPUT_EVDEV
67e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành#include <linux/usb/input.h>
68e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành#endif
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h>
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
712d8d7762d75d36a08a4a5c3d3f1c301f76cb8f56Andy Shevchenko#include <linux/kernel.h>		/* simple_strtol() */
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pwc.h"
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pwc-kiara.h"
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pwc-timon.h"
762b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#include "pwc-dec23.h"
772b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#include "pwc-dec1.h"
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Function prototypes and driver templates */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* hotplug device table support */
822b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillardstatic const struct usb_device_id pwc_device_table [] = {
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x0471, 0x0303) },
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x0471, 0x0304) },
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x0471, 0x0307) },
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x0471, 0x0308) },
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x0471, 0x030C) },
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x0471, 0x0310) },
902b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	{ USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x0471, 0x0312) },
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
932b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	{ USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */
1016b1ce3c1017adce52675ec72825f0b052a6af5d4Mauro Carvalho Chehab	{ USB_DEVICE(0x046D, 0x08B6) }, /* Cisco VT Camera */
1026b1ce3c1017adce52675ec72825f0b052a6af5d4Mauro Carvalho Chehab	{ USB_DEVICE(0x046D, 0x08B7) }, /* Logitech ViewPort AV 100 */
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
1042b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	{ USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */
1052b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	{ USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
1062b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	{ USB_DEVICE(0x055D, 0x9002) },	/* Samsung SNC-35E (Ver3.0) */
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ USB_DEVICE(0x0d81, 0x1900) },
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(usb, pwc_device_table);
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void usb_pwc_disconnect(struct usb_interface *intf);
119885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic void pwc_isoc_cleanup(struct pwc_device *pdev);
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct usb_driver pwc_driver = {
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name =			"Philips webcam",	/* name */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table =		pwc_device_table,
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe =		usb_pwc_probe,		/* probe() */
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.disconnect =		usb_pwc_disconnect,	/* disconnect() */
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_DEV_HINTS	20
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_ISOC_ERRORS	20
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
13105ad390724d1f307111a322325df83282a1479e6Trent Piepho#ifdef CONFIG_USB_PWC_DEBUG
132b930e1d851c3ffbf82127bd0e4d72ffe94d4b7f2Michael Krufky	int pwc_trace = PWC_DEBUG_LEVEL;
1332b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#endif
1343b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goedestatic int power_save = -1;
135c24e13713762a30f22468ac2c3d053abacb7672dHans de Goedestatic int leds[2] = { 100, 0 };
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***/
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
139bec43661b1dc0075b7445223ba775674133b164dHans Verkuilstatic int pwc_video_close(struct file *file);
1402b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillardstatic ssize_t pwc_video_read(struct file *file, char __user *buf,
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			  size_t count, loff_t *ppos);
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned int pwc_video_poll(struct file *file, poll_table *wait);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int  pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
145bec43661b1dc0075b7445223ba775674133b164dHans Verkuilstatic const struct v4l2_file_operations pwc_fops = {
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner =	THIS_MODULE,
14776ae853844dff124559e1b609b0c71c792a98221Hans de Goede	.open =		v4l2_fh_open,
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.release =     	pwc_video_close,
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.read =		pwc_video_read,
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.poll =		pwc_video_poll,
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.mmap =		pwc_video_mmap,
152afa38521614dcdfe12c765ff76d4c137a056e905Hans Verkuil	.unlocked_ioctl = video_ioctl2,
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct video_device pwc_template = {
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name =		"Philips Webcam",	/* Filled in later */
15676ae853844dff124559e1b609b0c71c792a98221Hans de Goede	.release =	video_device_release_empty,
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.fops =         &pwc_fops,
1589a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede	.ioctl_ops =	&pwc_ioctl_ops,
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***************************************************************************/
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Private functions */
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
164885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestruct pwc_frame_buf *pwc_get_next_fill_buf(struct pwc_device *pdev)
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
166885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	unsigned long flags = 0;
167885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	struct pwc_frame_buf *buf = NULL;
168885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
169885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
170885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	if (list_empty(&pdev->queued_bufs))
171885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		goto leave;
172885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
173885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf, list);
174885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	list_del(&buf->list);
175885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedeleave:
176885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
177885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	return buf;
1782b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard}
1792b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard
180e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thànhstatic void pwc_snapshot_button(struct pwc_device *pdev, int down)
181e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành{
182e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	if (down) {
183e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành		PWC_TRACE("Snapshot button pressed.\n");
184e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	} else {
185e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành		PWC_TRACE("Snapshot button released.\n");
186e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	}
187e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành
188e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành#ifdef CONFIG_USB_PWC_INPUT_EVDEV
189e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	if (pdev->button_dev) {
190bcd3e4b3190f0cc4e0702785220f0269f8537175Lennart Poettering		input_report_key(pdev->button_dev, KEY_CAMERA, down);
191e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành		input_sync(pdev->button_dev);
192e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	}
193e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành#endif
194e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành}
195e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành
196885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic void pwc_frame_complete(struct pwc_device *pdev)
1972b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard{
198885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	struct pwc_frame_buf *fbuf = pdev->fill_buf;
1992b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard
2002b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	/* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
2012b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	   frames on the USB wire after an exposure change. This conditition is
2022b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	   however detected  in the cam and a bit is set in the header.
2032b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	   */
2042b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	if (pdev->type == 730) {
2052b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		unsigned char *ptr = (unsigned char *)fbuf->data;
2062b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard
2072b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		if (ptr[1] == 1 && ptr[0] & 0x10) {
2082b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
2092b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			pdev->drop_frames += 2;
2102b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		}
2112b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		if ((ptr[0] ^ pdev->vmirror) & 0x01) {
212e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành			pwc_snapshot_button(pdev, ptr[0] & 0x01);
2132b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		}
2142b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		if ((ptr[0] ^ pdev->vmirror) & 0x02) {
2152b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			if (ptr[0] & 0x02)
2162b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard				PWC_TRACE("Image is mirrored.\n");
2172b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			else
2182b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard				PWC_TRACE("Image is normal.\n");
2192b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		}
2202b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		pdev->vmirror = ptr[0] & 0x03;
2212b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		/* Sometimes the trailer of the 730 is still sent as a 4 byte packet
2222b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		   after a short frame; this condition is filtered out specifically. A 4 byte
2232b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		   frame doesn't make sense anyway.
2242b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		   So we get either this sequence:
2252b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		   drop_bit set -> 4 byte frame -> short frame -> good frame
2262b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		   Or this one:
2272b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		   drop_bit set -> short frame -> good frame
2282b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		   So we drop either 3 or 2 frames in all!
2292b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		   */
2302b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		if (fbuf->filled == 4)
2312b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			pdev->drop_frames++;
232885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	} else if (pdev->type == 740 || pdev->type == 720) {
2332b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		unsigned char *ptr = (unsigned char *)fbuf->data;
2342b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		if ((ptr[0] ^ pdev->vmirror) & 0x01) {
235e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành			pwc_snapshot_button(pdev, ptr[0] & 0x01);
2362b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		}
2372b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		pdev->vmirror = ptr[0] & 0x03;
2382b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	}
2392b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard
240885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	/* In case we were instructed to drop the frame, do so silently. */
241885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	if (pdev->drop_frames > 0) {
2422b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		pdev->drop_frames--;
243885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	} else {
2442b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		/* Check for underflow first */
2452b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		if (fbuf->filled < pdev->frame_total_size) {
2462b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
2472b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard				       " discarded.\n", fbuf->filled);
248885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		} else {
249885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			fbuf->vb.v4l2_buf.field = V4L2_FIELD_NONE;
250885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			fbuf->vb.v4l2_buf.sequence = pdev->vframe_count;
251885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
252885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			pdev->fill_buf = NULL;
253885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			pdev->vsync = 0;
2542b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		}
2552b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	} /* !drop_frames */
2562b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	pdev->vframe_count++;
2572b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This gets called for the Isochronous pipe (video). This is done in
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupt time, so it has to be fast, not crash, and not stall. Neat.
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
2627d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void pwc_isoc_handler(struct urb *urb)
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
264885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	struct pwc_device *pdev = (struct pwc_device *)urb->context;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, fst, flen;
266885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	unsigned char *iso_buf = NULL;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
268885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	if (urb->status == -ENOENT || urb->status == -ECONNRESET ||
269885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	    urb->status == -ESHUTDOWN) {
2702b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
273885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
274885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	if (pdev->fill_buf == NULL)
275885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		pdev->fill_buf = pwc_get_next_fill_buf(pdev);
276885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
277885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	if (urb->status != 0) {
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		const char *errmsg;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		errmsg = "Unknown";
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch(urb->status) {
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case -ENOSR:		errmsg = "Buffer error (overrun)"; break;
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case -EPIPE:		errmsg = "Stalled (device not responding)"; break;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case -EOVERFLOW:	errmsg = "Babble (bad cable?)"; break;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case -EPROTO:		errmsg = "Bit-stuff error (bad cable?)"; break;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			case -EILSEQ:		errmsg = "CRC/Timeout (could be anything)"; break;
28738e2bfc94e95dd6005fdaf40dfec0157396741daPete Zaitcev			case -ETIME:		errmsg = "Device does not respond"; break;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
289885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		PWC_ERROR("pwc_isoc_handler() called with status %d [%s].\n",
290885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			  urb->status, errmsg);
291885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		/* Give up after a number of contiguous errors */
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
294885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			PWC_ERROR("Too many ISOC errors, bailing out.\n");
295885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			if (pdev->fill_buf) {
296885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede				vb2_buffer_done(&pdev->fill_buf->vb,
297885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede						VB2_BUF_STATE_ERROR);
298885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede				pdev->fill_buf = NULL;
299885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
301885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		pdev->vsync = 0; /* Drop the current frame */
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto handler_end;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Reset ISOC error counter. We did get here, after all. */
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->visoc_errors = 0;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* vsync: 0 = don't copy data
309d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab		  1 = sync-hunt
310d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab		  2 = synched
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Compact data */
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < urb->number_of_packets; i++) {
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		fst  = urb->iso_frame_desc[i].status;
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flen = urb->iso_frame_desc[i].actual_length;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
317885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		if (fst != 0) {
318885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			PWC_ERROR("Iso frame %d has error %d\n", i, fst);
319885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			continue;
320885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		}
321885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		if (flen > 0 && pdev->vsync) {
322885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			struct pwc_frame_buf *fbuf = pdev->fill_buf;
323885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
324885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			if (pdev->vsync == 1) {
325885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede				do_gettimeofday(&fbuf->vb.v4l2_buf.timestamp);
326885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede				pdev->vsync = 2;
327885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			}
328885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
329885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			if (flen + fbuf->filled > pdev->frame_total_size) {
330885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede				PWC_ERROR("Frame overflow (%d > %d)\n",
331885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede					  flen + fbuf->filled,
332885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede					  pdev->frame_total_size);
333885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede				pdev->vsync = 0; /* Let's wait for an EOF */
334885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			} else {
335885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede				memcpy(fbuf->data + fbuf->filled, iso_buf,
336885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede				       flen);
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				fbuf->filled += flen;
338885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			}
339885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		}
340885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		if (flen < pdev->vlast_packet_size) {
341885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			/* Shorter packet... end of frame */
342885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			if (pdev->vsync == 2)
343885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede				pwc_frame_complete(pdev);
344885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			if (pdev->fill_buf == NULL)
345885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede				pdev->fill_buf = pwc_get_next_fill_buf(pdev);
346885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			if (pdev->fill_buf) {
347885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede				pdev->fill_buf->filled = 0;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pdev->vsync = 1;
3492b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			}
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
351885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		pdev->vlast_packet_size = flen;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldshandler_end:
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	i = usb_submit_urb(urb, GFP_ATOMIC);
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (i != 0)
3572b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
360885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic int pwc_isoc_init(struct pwc_device *pdev)
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_device *udev;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct urb *urb;
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i, j, ret;
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_interface *intf;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_host_interface *idesc = NULL;
3675bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	int compression = 0; /* 0..3 = uncompressed..high */
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pdev->iso_init)
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
3716eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->vsync = 0;
3736eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede	pdev->vlast_packet_size = 0;
374885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	pdev->fill_buf = NULL;
375885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	pdev->vframe_count = 0;
3766eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede	pdev->visoc_errors = 0;
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	udev = pdev->udev;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3795bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goederetry:
3805bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	/* We first try with low compression and then retry with a higher
3815bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	   compression setting if there is not enough bandwidth. */
382938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede	ret = pwc_set_video_mode(pdev, pdev->width, pdev->height, pdev->pixfmt,
383938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede				 pdev->vframes, &compression, 1);
3845bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Get the current alternate interface, adjust packet size */
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	intf = usb_ifnum_to_if(udev, 0);
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (intf)
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!idesc)
390c246412117d871a3a90cd4e8ba2c6dea18a59f71Hans de Goede		return -EIO;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Search video endpoint */
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->vmax_packet_size = -1;
3942b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3992b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	}
400d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
4022b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");
403093cf723b2b06d774929ea07982f6a466ff22314Steven Cole		return -ENFILE; /* Odd error, that should be noticeable */
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Set alternate interface */
4072b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
4095bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	if (ret == -ENOSPC && compression < 3) {
4105bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		compression++;
4115bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		goto retry;
4125bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	}
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret < 0)
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41604613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede	/* Allocate and init Isochronuous urbs */
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < MAX_ISO_BUFS; i++) {
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (urb == NULL) {
4202b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_ERROR("Failed to allocate urb %d\n", i);
4216eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede			pdev->iso_init = 1;
4226eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede			pwc_isoc_cleanup(pdev);
4236eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede			return -ENOMEM;
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
42504613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede		pdev->urbs[i] = urb;
4262b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->interval = 1; // devik
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->dev = udev;
430d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab		urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
43104613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
43204613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede		urb->transfer_buffer = usb_alloc_coherent(udev,
43304613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede							  ISO_BUFFER_SIZE,
43404613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede							  GFP_KERNEL,
43504613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede							  &urb->transfer_dma);
43604613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede		if (urb->transfer_buffer == NULL) {
43704613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede			PWC_ERROR("Failed to allocate urb buffer %d\n", i);
43804613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede			pdev->iso_init = 1;
43904613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede			pwc_isoc_cleanup(pdev);
44004613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede			return -ENOMEM;
44104613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede		}
442d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab		urb->transfer_buffer_length = ISO_BUFFER_SIZE;
443d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab		urb->complete = pwc_isoc_handler;
444d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab		urb->context = pdev;
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->start_frame = 0;
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		urb->number_of_packets = ISO_FRAMES_PER_DESC;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* link */
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < MAX_ISO_BUFS; i++) {
45504613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede		ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL);
4565bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		if (ret == -ENOSPC && compression < 3) {
4575bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede			compression++;
4585bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede			pdev->iso_init = 1;
4595bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede			pwc_isoc_cleanup(pdev);
4605bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede			goto retry;
4615bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		}
462622d9f5d302e99dc7a06cb442e9d9ff2bb0f59b5Hans de Goede		if (ret) {
4632b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
464622d9f5d302e99dc7a06cb442e9d9ff2bb0f59b5Hans de Goede			pdev->iso_init = 1;
465622d9f5d302e99dc7a06cb442e9d9ff2bb0f59b5Hans de Goede			pwc_isoc_cleanup(pdev);
466622d9f5d302e99dc7a06cb442e9d9ff2bb0f59b5Hans de Goede			return ret;
467622d9f5d302e99dc7a06cb442e9d9ff2bb0f59b5Hans de Goede		}
46804613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede		PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->urbs[i]);
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* All is done... */
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->iso_init = 1;
4732b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4770b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukumstatic void pwc_iso_stop(struct pwc_device *pdev)
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Unlinking ISOC buffers one by one */
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for (i = 0; i < MAX_ISO_BUFS; i++) {
48304613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede		if (pdev->urbs[i]) {
48404613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede			PWC_DEBUG_MEMORY("Unlinking URB %p\n", pdev->urbs[i]);
48504613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede			usb_kill_urb(pdev->urbs[i]);
4860b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum		}
4870b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum	}
4880b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum}
4890b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum
4900b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukumstatic void pwc_iso_free(struct pwc_device *pdev)
4910b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum{
4920b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum	int i;
4930b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum
4940b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum	/* Freeing ISOC buffers one by one */
4950b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum	for (i = 0; i < MAX_ISO_BUFS; i++) {
49604613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede		if (pdev->urbs[i]) {
4972b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_DEBUG_MEMORY("Freeing URB\n");
49804613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede			if (pdev->urbs[i]->transfer_buffer) {
49904613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede				usb_free_coherent(pdev->udev,
50004613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede					pdev->urbs[i]->transfer_buffer_length,
50104613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede					pdev->urbs[i]->transfer_buffer,
50204613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede					pdev->urbs[i]->transfer_dma);
50304613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede			}
50404613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede			usb_free_urb(pdev->urbs[i]);
50504613c5e600e64840e4f753bd881cd5ab96ae403Hans de Goede			pdev->urbs[i] = NULL;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5080b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum}
5090b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum
510885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic void pwc_isoc_cleanup(struct pwc_device *pdev)
5110b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum{
5120b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum	PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
513c246412117d871a3a90cd4e8ba2c6dea18a59f71Hans de Goede
5140b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum	if (pdev->iso_init == 0)
5150b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum		return;
5160b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum
5170b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum	pwc_iso_stop(pdev);
5180b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum	pwc_iso_free(pdev);
519b824bb4b12548fedd622686d443310d574eb084eHans de Goede	usb_set_interface(pdev->udev, 0, 0);
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->iso_init = 0;
5222b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
525885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
526885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede{
527c20d78cde37018caa0313469c9320424995cc489Hans de Goede	unsigned long flags = 0;
528c20d78cde37018caa0313469c9320424995cc489Hans de Goede
529c20d78cde37018caa0313469c9320424995cc489Hans de Goede	spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
530885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	while (!list_empty(&pdev->queued_bufs)) {
531885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		struct pwc_frame_buf *buf;
532885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
533885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf,
534885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede				 list);
535885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		list_del(&buf->list);
536885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
537885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	}
538c20d78cde37018caa0313469c9320424995cc489Hans de Goede	spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
539885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede}
540885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
54105ad390724d1f307111a322325df83282a1479e6Trent Piepho#ifdef CONFIG_USB_PWC_DEBUG
5422b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillardstatic const char *pwc_sensor_type_to_string(unsigned int sensor_type)
5432b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard{
5442b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	switch(sensor_type) {
5452b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		case 0x00:
5462b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			return "Hyundai CMOS sensor";
5472b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		case 0x20:
5482b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			return "Sony CCD sensor + TDA8787";
5492b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		case 0x2E:
5502b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			return "Sony CCD sensor + Exas 98L59";
5512b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		case 0x2F:
5522b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			return "Sony CCD sensor + ADI 9804";
5532b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		case 0x30:
5542b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			return "Sharp CCD sensor + TDA8787";
5552b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		case 0x3E:
5562b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			return "Sharp CCD sensor + Exas 98L59";
5572b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		case 0x3F:
5582b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			return "Sharp CCD sensor + ADI 9804";
5592b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		case 0x40:
5602b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			return "UPA 1021 sensor";
5612b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		case 0x100:
5622b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			return "VGA sensor";
5632b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		case 0x101:
5642b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			return "PAL MR sensor";
5652b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		default:
566657de3cd32285831a56f9f96deb85c64205c42fcTrent Piepho			return "unknown type of sensor";
5672b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	}
5682b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard}
5692b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#endif
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***************************************************************************/
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Video4Linux functions */
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
574c20d78cde37018caa0313469c9320424995cc489Hans de Goedeint pwc_test_n_set_capt_file(struct pwc_device *pdev, struct file *file)
575c20d78cde37018caa0313469c9320424995cc489Hans de Goede{
576c20d78cde37018caa0313469c9320424995cc489Hans de Goede	int r = 0;
577c20d78cde37018caa0313469c9320424995cc489Hans de Goede
578c20d78cde37018caa0313469c9320424995cc489Hans de Goede	mutex_lock(&pdev->capt_file_lock);
579c20d78cde37018caa0313469c9320424995cc489Hans de Goede	if (pdev->capt_file != NULL &&
580c20d78cde37018caa0313469c9320424995cc489Hans de Goede	    pdev->capt_file != file) {
581c20d78cde37018caa0313469c9320424995cc489Hans de Goede		r = -EBUSY;
582c20d78cde37018caa0313469c9320424995cc489Hans de Goede		goto leave;
583c20d78cde37018caa0313469c9320424995cc489Hans de Goede	}
584c20d78cde37018caa0313469c9320424995cc489Hans de Goede	pdev->capt_file = file;
585c20d78cde37018caa0313469c9320424995cc489Hans de Goedeleave:
586c20d78cde37018caa0313469c9320424995cc489Hans de Goede	mutex_unlock(&pdev->capt_file_lock);
587c20d78cde37018caa0313469c9320424995cc489Hans de Goede	return r;
588c20d78cde37018caa0313469c9320424995cc489Hans de Goede}
589c20d78cde37018caa0313469c9320424995cc489Hans de Goede
59076ae853844dff124559e1b609b0c71c792a98221Hans de Goedestatic void pwc_video_release(struct v4l2_device *v)
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
59276ae853844dff124559e1b609b0c71c792a98221Hans de Goede	struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
59389dec01b7e251697720ac3d6a5310d72359eba69Dmitry Torokhov
5946c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede	v4l2_ctrl_handler_free(&pdev->ctrl_handler);
59524be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	kfree(pdev->ctrl_buf);
59689dec01b7e251697720ac3d6a5310d72359eba69Dmitry Torokhov	kfree(pdev);
59785237f202d46d55c1bffe0c5b1aa3ddc0f1dce4dOliver Neukum}
59885237f202d46d55c1bffe0c5b1aa3ddc0f1dce4dOliver Neukum
599bec43661b1dc0075b7445223ba775674133b164dHans Verkuilstatic int pwc_video_close(struct file *file)
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
60176ae853844dff124559e1b609b0c71c792a98221Hans de Goede	struct pwc_device *pdev = video_drvdata(file);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6034fba471e405f8f983085fd9f2fd9637bfc275f8fHans de Goede	if (pdev->capt_file == file) {
6044fba471e405f8f983085fd9f2fd9637bfc275f8fHans de Goede		vb2_queue_release(&pdev->vb_queue);
6054fba471e405f8f983085fd9f2fd9637bfc275f8fHans de Goede		pdev->capt_file = NULL;
6064fba471e405f8f983085fd9f2fd9637bfc275f8fHans de Goede	}
60776ae853844dff124559e1b609b0c71c792a98221Hans de Goede	return v4l2_fh_release(file);
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6102b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillardstatic ssize_t pwc_video_read(struct file *file, char __user *buf,
611885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			      size_t count, loff_t *ppos)
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
61376ae853844dff124559e1b609b0c71c792a98221Hans de Goede	struct pwc_device *pdev = video_drvdata(file);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
615b824bb4b12548fedd622686d443310d574eb084eHans de Goede	if (!pdev->udev)
616b824bb4b12548fedd622686d443310d574eb084eHans de Goede		return -ENODEV;
6170b67f5c568c545cb36f88e9f418af2df1cc58589Oliver Neukum
618c20d78cde37018caa0313469c9320424995cc489Hans de Goede	if (pwc_test_n_set_capt_file(pdev, file))
6194fba471e405f8f983085fd9f2fd9637bfc275f8fHans de Goede		return -EBUSY;
6204fba471e405f8f983085fd9f2fd9637bfc275f8fHans de Goede
621885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	return vb2_read(&pdev->vb_queue, buf, count, ppos,
622885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede			file->f_flags & O_NONBLOCK);
623885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede}
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
625885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic unsigned int pwc_video_poll(struct file *file, poll_table *wait)
626885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede{
62776ae853844dff124559e1b609b0c71c792a98221Hans de Goede	struct pwc_device *pdev = video_drvdata(file);
628d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
629b824bb4b12548fedd622686d443310d574eb084eHans de Goede	if (!pdev->udev)
630885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		return POLL_ERR;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
632885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	return vb2_poll(&pdev->vb_queue, file, wait);
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
635885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
63776ae853844dff124559e1b609b0c71c792a98221Hans de Goede	struct pwc_device *pdev = video_drvdata(file);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6394fba471e405f8f983085fd9f2fd9637bfc275f8fHans de Goede	if (pdev->capt_file != file)
6404fba471e405f8f983085fd9f2fd9637bfc275f8fHans de Goede		return -EBUSY;
6414fba471e405f8f983085fd9f2fd9637bfc275f8fHans de Goede
642885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	return vb2_mmap(&pdev->vb_queue, vma);
643885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede}
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
645885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede/***************************************************************************/
646885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede/* Videobuf2 operations */
647885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
648fc714e70dd063e6887d09872ac6158b0c20cc817Guennadi Liakhovetskistatic int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
649fc714e70dd063e6887d09872ac6158b0c20cc817Guennadi Liakhovetski				unsigned int *nbuffers, unsigned int *nplanes,
650fc714e70dd063e6887d09872ac6158b0c20cc817Guennadi Liakhovetski				unsigned int sizes[], void *alloc_ctxs[])
651885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede{
652885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	struct pwc_device *pdev = vb2_get_drv_priv(vq);
653795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede	int size;
654885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
655885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	if (*nbuffers < MIN_FRAMES)
656885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		*nbuffers = MIN_FRAMES;
657885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	else if (*nbuffers > MAX_FRAMES)
658885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		*nbuffers = MAX_FRAMES;
659885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
660885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	*nplanes = 1;
661885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
662795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede	size = pwc_get_size(pdev, MAX_WIDTH, MAX_HEIGHT);
663795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede	sizes[0] = PAGE_ALIGN(pwc_image_sizes[size][0] *
664795e6eb3262d3b7247ce450835eea6df6571d103Hans de Goede			      pwc_image_sizes[size][1] * 3 / 2);
665885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
666885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	return 0;
667885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede}
668885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
669885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic int buffer_init(struct vb2_buffer *vb)
670885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede{
671885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
6723751e288bcf3d77652ef979edc0b3ea8b21d8b97Hans de Goede
673885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	/* need vmalloc since frame buffer > 128K */
674885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	buf->data = vzalloc(PWC_FRAME_SIZE);
675885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	if (buf->data == NULL)
676885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede		return -ENOMEM;
677885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
678885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	return 0;
679885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede}
680885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
681885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic int buffer_prepare(struct vb2_buffer *vb)
682885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede{
683885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
684885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
685885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	/* Don't allow queing new buffers after device disconnection */
686b824bb4b12548fedd622686d443310d574eb084eHans de Goede	if (!pdev->udev)
687b824bb4b12548fedd622686d443310d574eb084eHans de Goede		return -ENODEV;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
692885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic int buffer_finish(struct vb2_buffer *vb)
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
694885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
695885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
696d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
697885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	/*
698885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	 * Application has called dqbuf and is getting back a buffer we've
699885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	 * filled, take the pwc data we've stored in buf->data and decompress
700885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	 * it into a usable format, storing the result in the vb2_buffer
701885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	 */
702885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	return pwc_decompress(pdev, buf);
703885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede}
704885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
705885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic void buffer_cleanup(struct vb2_buffer *vb)
706885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede{
707885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
708885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
709885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	vfree(buf->data);
710885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede}
711885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
712885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic void buffer_queue(struct vb2_buffer *vb)
713885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede{
714885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue);
715885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb);
716885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	unsigned long flags = 0;
717885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
718885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	spin_lock_irqsave(&pdev->queued_bufs_lock, flags);
719c20d78cde37018caa0313469c9320424995cc489Hans de Goede	/* Check the device has not disconnected between prep and queuing */
720c20d78cde37018caa0313469c9320424995cc489Hans de Goede	if (pdev->udev)
721c20d78cde37018caa0313469c9320424995cc489Hans de Goede		list_add_tail(&buf->list, &pdev->queued_bufs);
722c20d78cde37018caa0313469c9320424995cc489Hans de Goede	else
723c20d78cde37018caa0313469c9320424995cc489Hans de Goede		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
724885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
725885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede}
726885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
727bd323e28bd82dfd4b72c50ddc4d5fc24e3678b99Marek Szyprowskistatic int start_streaming(struct vb2_queue *vq, unsigned int count)
728885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede{
729885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	struct pwc_device *pdev = vb2_get_drv_priv(vq);
730c20d78cde37018caa0313469c9320424995cc489Hans de Goede	int r;
731885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
732c20d78cde37018caa0313469c9320424995cc489Hans de Goede	mutex_lock(&pdev->udevlock);
733c20d78cde37018caa0313469c9320424995cc489Hans de Goede	if (!pdev->udev) {
734c20d78cde37018caa0313469c9320424995cc489Hans de Goede		r = -ENODEV;
735c20d78cde37018caa0313469c9320424995cc489Hans de Goede		goto leave;
736c20d78cde37018caa0313469c9320424995cc489Hans de Goede	}
737b824bb4b12548fedd622686d443310d574eb084eHans de Goede
7386eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede	/* Turn on camera and set LEDS on */
7396eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede	pwc_camera_power(pdev, 1);
740c24e13713762a30f22468ac2c3d053abacb7672dHans de Goede	pwc_set_leds(pdev, leds[0], leds[1]);
7416eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede
742c20d78cde37018caa0313469c9320424995cc489Hans de Goede	r = pwc_isoc_init(pdev);
7435bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	if (r) {
7445bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		/* If we failed turn camera and LEDS back off */
7455bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		pwc_set_leds(pdev, 0, 0);
7465bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		pwc_camera_power(pdev, 0);
7475bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		/* And cleanup any queued bufs!! */
7485bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede		pwc_cleanup_queued_bufs(pdev);
7495bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	}
750c20d78cde37018caa0313469c9320424995cc489Hans de Goedeleave:
751c20d78cde37018caa0313469c9320424995cc489Hans de Goede	mutex_unlock(&pdev->udevlock);
752c20d78cde37018caa0313469c9320424995cc489Hans de Goede	return r;
753885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede}
754885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
755885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic int stop_streaming(struct vb2_queue *vq)
756885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede{
757885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	struct pwc_device *pdev = vb2_get_drv_priv(vq);
758885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
759c20d78cde37018caa0313469c9320424995cc489Hans de Goede	mutex_lock(&pdev->udevlock);
7606eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede	if (pdev->udev) {
7616eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede		pwc_set_leds(pdev, 0, 0);
7626eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede		pwc_camera_power(pdev, 0);
763b824bb4b12548fedd622686d443310d574eb084eHans de Goede		pwc_isoc_cleanup(pdev);
7646eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede	}
765c20d78cde37018caa0313469c9320424995cc489Hans de Goede	mutex_unlock(&pdev->udevlock);
766c20d78cde37018caa0313469c9320424995cc489Hans de Goede
767885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	pwc_cleanup_queued_bufs(pdev);
768d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
772885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goedestatic struct vb2_ops pwc_vb_queue_ops = {
773885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	.queue_setup		= queue_setup,
774885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	.buf_init		= buffer_init,
775885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	.buf_prepare		= buffer_prepare,
776885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	.buf_finish		= buffer_finish,
777885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	.buf_cleanup		= buffer_cleanup,
778885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	.buf_queue		= buffer_queue,
779885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	.start_streaming	= start_streaming,
780885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	.stop_streaming		= stop_streaming,
781885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede};
782885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***************************************************************************/
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* USB functions */
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This function gets called when a new device is plugged in or the usb core
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is loaded.
7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id)
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct usb_device *udev = interface_to_usbdev(intf);
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct pwc_device *pdev = NULL;
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int vendor_id, product_id, type_id;
795a081c3400ff2695244714293f5f6a4675c3a9493Hans de Goede	int rc;
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int features = 0;
7975bbe18d74f0c163090cd16bd25e252e8806a6c75Hans de Goede	int compression = 0;
7983b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede	int my_power_save = power_save;
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char serial_number[30], *name;
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8012b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	vendor_id = le16_to_cpu(udev->descriptor.idVendor);
8022b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	product_id = le16_to_cpu(udev->descriptor.idProduct);
8032b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Check if we can handle this device */
8052b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
8062b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		vendor_id, product_id,
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		intf->altsetting->desc.bInterfaceNumber);
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* the interfaces are probed one by one. We are only interested in the
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   video interface (0) now.
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   Interface 1 is the Audio Control, and interface 2 Audio itself.
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (intf->altsetting->desc.bInterfaceNumber > 0)
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vendor_id == 0x0471) {
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (product_id) {
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0302:
8192b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Philips PCA645VC USB webcam detected.\n");
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Philips 645 webcam";
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 645;
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0303:
8242b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Philips PCA646VC USB webcam detected.\n");
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Philips 646 webcam";
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 646;
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0304:
8292b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Askey VC010 webcam";
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 646;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0307:
8342b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Philips 675 webcam";
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 675;
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0308:
8392b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Philips 680 webcam";
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 680;
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x030C:
8442b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Philips 690 webcam";
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 690;
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0310:
8492b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Philips 730 webcam";
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 730;
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0311:
8542b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Philips 740 webcam";
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 740;
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0312:
8592b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Philips 750 webcam";
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 750;
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0313:
8642b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Philips 720K/40 webcam";
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 720;
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8682b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		case 0x0329:
8692b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
8702b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			name = "Philips SPC 900NC webcam";
8719ee6d78cd4112c0f5a257a01383c64dadbf66da9Luc Saillard			type_id = 740;
8722b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			break;
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (vendor_id == 0x069A) {
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch(product_id) {
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x0001:
8812b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Askey VC010 webcam";
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 645;
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (vendor_id == 0x046d) {
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch(product_id) {
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x08b0:
8932b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Logitech QuickCam Pro 3000";
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 740; /* CCD sensor */
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x08b1:
8982b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Logitech QuickCam Notebook Pro";
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 740; /* CCD sensor */
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x08b2:
9032b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Logitech QuickCam Pro 4000";
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 740; /* CCD sensor */
90651886df0ca8bcc42e13cad7bcfc3487268229ceaHans de Goede			if (my_power_save == -1)
90751886df0ca8bcc42e13cad7bcfc3487268229ceaHans de Goede				my_power_save = 1;
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x08b3:
9102b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Logitech QuickCam Zoom";
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 740; /* CCD sensor */
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x08B4:
9152b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Logitech QuickCam Zoom";
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 740; /* CCD sensor */
9183b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede			if (my_power_save == -1)
9193b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede				my_power_save = 1;
9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x08b5:
9222b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Logitech QuickCam Orbit";
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 740; /* CCD sensor */
92551886df0ca8bcc42e13cad7bcfc3487268229ceaHans de Goede			if (my_power_save == -1)
92651886df0ca8bcc42e13cad7bcfc3487268229ceaHans de Goede				my_power_save = 1;
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			features |= FEATURE_MOTOR_PANTILT;
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x08b6:
930a63e157fc6147ae9792325cb55fa0c6d1d0f9905Jean Tourrilhes			PWC_INFO("Logitech/Cisco VT Camera webcam detected.\n");
931a63e157fc6147ae9792325cb55fa0c6d1d0f9905Jean Tourrilhes			name = "Cisco VT Camera";
932a63e157fc6147ae9792325cb55fa0c6d1d0f9905Jean Tourrilhes			type_id = 740; /* CCD sensor */
933a63e157fc6147ae9792325cb55fa0c6d1d0f9905Jean Tourrilhes			break;
9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x08b7:
9356b1ce3c1017adce52675ec72825f0b052a6af5d4Mauro Carvalho Chehab			PWC_INFO("Logitech ViewPort AV 100 webcam detected.\n");
9366b1ce3c1017adce52675ec72825f0b052a6af5d4Mauro Carvalho Chehab			name = "Logitech ViewPort AV 100";
9376b1ce3c1017adce52675ec72825f0b052a6af5d4Mauro Carvalho Chehab			type_id = 740; /* CCD sensor */
9386b1ce3c1017adce52675ec72825f0b052a6af5d4Mauro Carvalho Chehab			break;
9396b1ce3c1017adce52675ec72825f0b052a6af5d4Mauro Carvalho Chehab		case 0x08b8: /* Where this released? */
9402b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Logitech QuickCam (res.)";
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 730; /* Assuming CMOS */
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
944d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab		default:
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
946d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab			break;
947d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab		}
948d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab	}
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (vendor_id == 0x055d) {
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* I don't know the difference between the C10 and the C30;
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   I suppose the difference is the sensor, but both cameras
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   work equally well with a type_id of 675
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 */
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch(product_id) {
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x9000:
9562b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Samsung MPC-C10";
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 675;
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x9001:
9612b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Samsung MPC-C30";
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 675;
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9652b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		case 0x9002:
9662b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
9672b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			name = "Samsung MPC-C30";
9682b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			type_id = 740;
9692b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			break;
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (vendor_id == 0x041e) {
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch(product_id) {
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x400c:
9782b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Creative Labs Webcam 5 detected.\n");
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Creative Labs Webcam 5";
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 730;
98151886df0ca8bcc42e13cad7bcfc3487268229ceaHans de Goede			if (my_power_save == -1)
98251886df0ca8bcc42e13cad7bcfc3487268229ceaHans de Goede				my_power_save = 1;
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x4011:
9852b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Creative Labs Webcam Pro Ex";
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 740;
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (vendor_id == 0x04cc) {
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch(product_id) {
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x8116:
9972b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Sotec Afina Eye";
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 730;
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (vendor_id == 0x06be) {
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch(product_id) {
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x8116:
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* This is essentially the same cam as the Sotec Afina Eye */
10102b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "AME Co. Afina Eye";
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 750;
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1018d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab
10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (vendor_id == 0x0d81) {
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch(product_id) {
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x1900:
10232b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Visionite VCS-UC300";
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 740; /* CCD sensor */
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0x1910:
10282b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard			PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			name = "Visionite VCS-UM100";
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			type_id = 730; /* CMOS sensor */
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1037d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab	else
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV; /* Not any of the know types; but the list keeps growing. */
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10403b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede	if (my_power_save == -1)
10413b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede		my_power_save = 0;
10423b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	memset(serial_number, 0, 30);
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
10452b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (udev->descriptor.bNumConfigurations > 1)
10482b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		PWC_WARNING("Warning: more than 1 configuration available.\n");
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
105180b6ca48321974a6566a1c9048ba34f60420bca6Eric Sesterhenn	pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (pdev == NULL) {
10532b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard		PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->type = type_id;
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->features = features;
10583b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede	pwc_construct(pdev); /* set min/max sizes correct */
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1060c20d78cde37018caa0313469c9320424995cc489Hans de Goede	mutex_init(&pdev->capt_file_lock);
1061c11271349ad5d4647e69e511fc481b2dd390efc4Hans de Goede	mutex_init(&pdev->udevlock);
1062885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	spin_lock_init(&pdev->queued_bufs_lock);
1063885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	INIT_LIST_HEAD(&pdev->queued_bufs);
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->udev = udev;
10663b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goede	pdev->power_save = my_power_save;
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1068885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	/* Init videobuf2 queue structure */
1069885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	memset(&pdev->vb_queue, 0, sizeof(pdev->vb_queue));
1070885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	pdev->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1071885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	pdev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
1072885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	pdev->vb_queue.drv_priv = pdev;
1073885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf);
1074885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	pdev->vb_queue.ops = &pwc_vb_queue_ops;
1075885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	pdev->vb_queue.mem_ops = &vb2_vmalloc_memops;
1076885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede	vb2_queue_init(&pdev->vb_queue);
1077885fe18f5542fe283a17f70583383c6cadcba1c3Hans de Goede
10789a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede	/* Init video_device structure */
10799a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede	memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template));
10809a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede	strcpy(pdev->vdev.name, name);
108176ae853844dff124559e1b609b0c71c792a98221Hans de Goede	set_bit(V4L2_FL_USE_FH_PRIO, &pdev->vdev.flags);
10829a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede	video_set_drvdata(&pdev->vdev, pdev);
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
10852b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
108724be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	/* Allocate USB command buffers */
108824be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	pdev->ctrl_buf = kmalloc(sizeof(pdev->cmd_buf), GFP_KERNEL);
108924be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	if (!pdev->ctrl_buf) {
109024be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
109124be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		rc = -ENOMEM;
109224be689bfbbcd6c047d7918784ff810e97648006Hans de Goede		goto err_free_mem;
109324be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	}
109424be689bfbbcd6c047d7918784ff810e97648006Hans de Goede
10956eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede#ifdef CONFIG_USB_PWC_DEBUG
10966eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede	/* Query sensor type */
10976eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede	if (pwc_get_cmos_sensor(pdev, &rc) >= 0) {
10986eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede		PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
10996eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede				pdev->vdev.name,
11006eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede				pwc_sensor_type_to_string(rc), rc);
11016eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede	}
11026eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede#endif
11036eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede
11042b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	/* Set the leds off */
11052b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	pwc_set_leds(pdev, 0, 0);
11066eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede
11076eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede	/* Setup intial videomode */
1108d167a85c5fb45b1ecdacdb9b7733833a9af78da8Hans de Goede	rc = pwc_set_video_mode(pdev, MAX_WIDTH, MAX_HEIGHT,
1109938d5b9e7c2e20a7e609ad5874c6e7d8d391e6e9Hans de Goede				V4L2_PIX_FMT_YUV420, 30, &compression, 1);
11106eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede	if (rc)
11116eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede		goto err_free_mem;
11126eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede
11136c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede	/* Register controls (and read default values from camera */
11146c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede	rc = pwc_init_controls(pdev);
11156c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede	if (rc) {
11166c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede		PWC_ERROR("Failed to register v4l2 controls (%d).\n", rc);
11176c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede		goto err_free_mem;
11186c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede	}
11196c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede
11206eba93573d2dda3f627006101c0652faeeaffde6Hans de Goede	/* And powerdown the camera until streaming starts */
11212b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard	pwc_camera_power(pdev, 0);
11222b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard
112376ae853844dff124559e1b609b0c71c792a98221Hans de Goede	/* Register the v4l2_device structure */
112476ae853844dff124559e1b609b0c71c792a98221Hans de Goede	pdev->v4l2_dev.release = pwc_video_release;
112576ae853844dff124559e1b609b0c71c792a98221Hans de Goede	rc = v4l2_device_register(&intf->dev, &pdev->v4l2_dev);
112676ae853844dff124559e1b609b0c71c792a98221Hans de Goede	if (rc) {
112776ae853844dff124559e1b609b0c71c792a98221Hans de Goede		PWC_ERROR("Failed to register v4l2-device (%d).\n", rc);
112876ae853844dff124559e1b609b0c71c792a98221Hans de Goede		goto err_free_controls;
112976ae853844dff124559e1b609b0c71c792a98221Hans de Goede	}
113076ae853844dff124559e1b609b0c71c792a98221Hans de Goede
113176ae853844dff124559e1b609b0c71c792a98221Hans de Goede	pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler;
113276ae853844dff124559e1b609b0c71c792a98221Hans de Goede	pdev->vdev.v4l2_dev = &pdev->v4l2_dev;
113376ae853844dff124559e1b609b0c71c792a98221Hans de Goede
1134a081c3400ff2695244714293f5f6a4675c3a9493Hans de Goede	rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1);
1135479567ce3af7b99d645a3c53b8ca2fc65e46efdcHans Verkuil	if (rc < 0) {
1136479567ce3af7b99d645a3c53b8ca2fc65e46efdcHans Verkuil		PWC_ERROR("Failed to register as video device (%d).\n", rc);
113776ae853844dff124559e1b609b0c71c792a98221Hans de Goede		goto err_unregister_v4l2_dev;
1138479567ce3af7b99d645a3c53b8ca2fc65e46efdcHans Verkuil	}
11399a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede	PWC_INFO("Registered as %s.\n", video_device_node_name(&pdev->vdev));
1140479567ce3af7b99d645a3c53b8ca2fc65e46efdcHans Verkuil
1141e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành#ifdef CONFIG_USB_PWC_INPUT_EVDEV
1142e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	/* register webcam snapshot button input device */
1143e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	pdev->button_dev = input_allocate_device();
1144e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	if (!pdev->button_dev) {
1145e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành		PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
114689dec01b7e251697720ac3d6a5310d72359eba69Dmitry Torokhov		rc = -ENOMEM;
114789dec01b7e251697720ac3d6a5310d72359eba69Dmitry Torokhov		goto err_video_unreg;
1148e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	}
1149e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành
115089dec01b7e251697720ac3d6a5310d72359eba69Dmitry Torokhov	usb_make_path(udev, pdev->button_phys, sizeof(pdev->button_phys));
115189dec01b7e251697720ac3d6a5310d72359eba69Dmitry Torokhov	strlcat(pdev->button_phys, "/input0", sizeof(pdev->button_phys));
115289dec01b7e251697720ac3d6a5310d72359eba69Dmitry Torokhov
1153e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	pdev->button_dev->name = "PWC snapshot button";
115489dec01b7e251697720ac3d6a5310d72359eba69Dmitry Torokhov	pdev->button_dev->phys = pdev->button_phys;
1155e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	usb_to_input_id(pdev->udev, &pdev->button_dev->id);
1156e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	pdev->button_dev->dev.parent = &pdev->udev->dev;
1157e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	pdev->button_dev->evbit[0] = BIT_MASK(EV_KEY);
1158bcd3e4b3190f0cc4e0702785220f0269f8537175Lennart Poettering	pdev->button_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
1159e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành
1160e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	rc = input_register_device(pdev->button_dev);
1161e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	if (rc) {
1162e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành		input_free_device(pdev->button_dev);
1163e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành		pdev->button_dev = NULL;
116489dec01b7e251697720ac3d6a5310d72359eba69Dmitry Torokhov		goto err_video_unreg;
1165e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành	}
1166e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành#endif
1167e32a7eccd7f016928dd864711ac654e6db62c5f3Nam Phạm Thành
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1169c12e3be0860652ed1e15c9442adcba44317211d1Jeff Garzik
117089dec01b7e251697720ac3d6a5310d72359eba69Dmitry Torokhoverr_video_unreg:
11719a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede	video_unregister_device(&pdev->vdev);
117276ae853844dff124559e1b609b0c71c792a98221Hans de Goedeerr_unregister_v4l2_dev:
117376ae853844dff124559e1b609b0c71c792a98221Hans de Goede	v4l2_device_unregister(&pdev->v4l2_dev);
11746c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goedeerr_free_controls:
11756c9cac89c009c049a9ad29cdf0f51892410fe751Hans de Goede	v4l2_ctrl_handler_free(&pdev->ctrl_handler);
117689dec01b7e251697720ac3d6a5310d72359eba69Dmitry Torokhoverr_free_mem:
117724be689bfbbcd6c047d7918784ff810e97648006Hans de Goede	kfree(pdev->ctrl_buf);
117889dec01b7e251697720ac3d6a5310d72359eba69Dmitry Torokhov	kfree(pdev);
1179c12e3be0860652ed1e15c9442adcba44317211d1Jeff Garzik	return rc;
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
118289dec01b7e251697720ac3d6a5310d72359eba69Dmitry Torokhov/* The user yanked out the cable... */
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void usb_pwc_disconnect(struct usb_interface *intf)
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
118576ae853844dff124559e1b609b0c71c792a98221Hans de Goede	struct v4l2_device *v = usb_get_intfdata(intf);
118676ae853844dff124559e1b609b0c71c792a98221Hans de Goede	struct pwc_device *pdev = container_of(v, struct pwc_device, v4l2_dev);
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1188c11271349ad5d4647e69e511fc481b2dd390efc4Hans de Goede	mutex_lock(&pdev->udevlock);
11899a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede	/* No need to keep the urbs around after disconnection */
11909a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede	pwc_isoc_cleanup(pdev);
1191b824bb4b12548fedd622686d443310d574eb084eHans de Goede	pdev->udev = NULL;
1192c11271349ad5d4647e69e511fc481b2dd390efc4Hans de Goede	mutex_unlock(&pdev->udevlock);
11939a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede
1194c20d78cde37018caa0313469c9320424995cc489Hans de Goede	pwc_cleanup_queued_bufs(pdev);
1195c20d78cde37018caa0313469c9320424995cc489Hans de Goede
11969a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede	video_unregister_device(&pdev->vdev);
119776ae853844dff124559e1b609b0c71c792a98221Hans de Goede	v4l2_device_unregister(&pdev->v4l2_dev);
11989a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede
11999a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede#ifdef CONFIG_USB_PWC_INPUT_EVDEV
12009a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede	if (pdev->button_dev)
12019a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede		input_unregister_device(pdev->button_dev);
12029a7b2d1f0eb0a6b674726c9a9d77ce83fd0b27feHans de Goede#endif
120376ae853844dff124559e1b609b0c71c792a98221Hans de Goede
120476ae853844dff124559e1b609b0c71c792a98221Hans de Goede	v4l2_device_put(&pdev->v4l2_dev);
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1208d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab/*
1209d56410e0a594150c5ca06319da7bc8901c4d455eMauro Carvalho Chehab * Initialization code & module stuff
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121264a6f9500d8e8a8e1b1adc2120e56cc88df5727fAl Virostatic unsigned int leds_nargs;
12132b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard
121405ad390724d1f307111a322325df83282a1479e6Trent Piepho#ifdef CONFIG_USB_PWC_DEBUG
12152b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillardmodule_param_named(trace, pwc_trace, int, 0644);
12162b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillard#endif
12173b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de Goedemodule_param(power_save, int, 0644);
12182b455db6d456ef2d44808a8377fd3bc832e08317Luc Saillardmodule_param_array(leds, int, &leds_nargs, 0444);
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12204315c414474cf43994f0c562ce8faea3628f550bAndrea Odetti#ifdef CONFIG_USB_PWC_DEBUG
12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(trace, "For debugging purposes");
12224315c414474cf43994f0c562ce8faea3628f550bAndrea Odetti#endif
12233b4d0ec79113e77b3fe90749ae00bfa015c73048Hans de GoedeMODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off");
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Philips & OEM USB webcam driver");
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
12292b455db6d456ef2d44808a8377fd3bc832e08317Luc SaillardMODULE_ALIAS("pwcx");
12302b455db6d456ef2d44808a8377fd3bc832e08317Luc SaillardMODULE_VERSION( PWC_VERSION );
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init usb_pwc_init(void)
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return usb_register(&pwc_driver);
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit usb_pwc_exit(void)
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	usb_deregister(&pwc_driver);
12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(usb_pwc_init);
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(usb_pwc_exit);
1244