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