blob: 0d810189dd87836861e1974267137e6325e5b7e4 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* Linux driver for Philips webcam
2 USB and Video4Linux interface part.
3 (C) 1999-2004 Nemosoft Unv.
Luc Saillard2b455db2006-04-24 10:29:46 -03004 (C) 2004-2006 Luc Saillard (luc@saillard.org)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005
6 NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
7 driver and thus may have bugs that are not present in the original version.
8 Please send bug reports and support requests to <luc@saillard.org>.
9 The decompression routines have been implemented by reverse-engineering the
10 Nemosoft binary pwcx module. Caveat emptor.
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
26*/
27
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030028/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070029 This code forms the interface between the USB layers and the Philips
30 specific stuff. Some adanved stuff of the driver falls under an
31 NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030032 is thus not distributed in source form. The binary pwcx.o module
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 contains the code that falls under the NDA.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030034
35 In case you're wondering: 'pwc' stands for "Philips WebCam", but
Linus Torvalds1da177e2005-04-16 15:20:36 -070036 I really didn't want to type 'philips_web_cam' every time (I'm lazy as
37 any Linux kernel hacker, but I don't like uncomprehensible abbreviations
38 without explanation).
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -030039
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 Oh yes, convention: to disctinguish between all the various pointers to
41 device-structures, I use these names for the pointer variables:
42 udev: struct usb_device *
43 vdev: struct video_device *
44 pdev: struct pwc_devive *
45*/
46
47/* Contributors:
48 - Alvarado: adding whitebalance code
49 - Alistar Moire: QuickCam 3000 Pro device/product ID
50 - Tony Hoyle: Creative Labs Webcam 5 device/product ID
51 - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged
52 - Jk Fang: Sotec Afina Eye ID
53 - Xavier Roche: QuickCam Pro 4000 ID
54 - Jens Knudsen: QuickCam Zoom ID
55 - J. Debert: QuickCam for Notebooks ID
56*/
57
58#include <linux/errno.h>
59#include <linux/init.h>
60#include <linux/mm.h>
61#include <linux/module.h>
62#include <linux/poll.h>
63#include <linux/slab.h>
64#include <linux/vmalloc.h>
65#include <asm/io.h>
66
67#include "pwc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#include "pwc-kiara.h"
69#include "pwc-timon.h"
Luc Saillard2b455db2006-04-24 10:29:46 -030070#include "pwc-dec23.h"
71#include "pwc-dec1.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070072#include "pwc-uncompress.h"
73
74/* Function prototypes and driver templates */
75
76/* hotplug device table support */
Luc Saillard2b455db2006-04-24 10:29:46 -030077static const struct usb_device_id pwc_device_table [] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
79 { USB_DEVICE(0x0471, 0x0303) },
80 { USB_DEVICE(0x0471, 0x0304) },
81 { USB_DEVICE(0x0471, 0x0307) },
82 { USB_DEVICE(0x0471, 0x0308) },
83 { USB_DEVICE(0x0471, 0x030C) },
84 { USB_DEVICE(0x0471, 0x0310) },
Luc Saillard2b455db2006-04-24 10:29:46 -030085 { USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 { USB_DEVICE(0x0471, 0x0312) },
87 { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
Luc Saillard2b455db2006-04-24 10:29:46 -030088 { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
90 { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
91 { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
92 { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */
93 { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */
94 { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */
95 { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */
Mauro Carvalho Chehab6b1ce3c2007-03-21 16:35:28 -030096 { USB_DEVICE(0x046D, 0x08B6) }, /* Cisco VT Camera */
97 { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech ViewPort AV 100 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
Luc Saillard2b455db2006-04-24 10:29:46 -030099 { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */
100 { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
101 { USB_DEVICE(0x055D, 0x9002) }, /* Samsung SNC-35E (Ver3.0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
103 { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
104 { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
105 { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */
106 { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
107 { USB_DEVICE(0x0d81, 0x1900) },
108 { }
109};
110MODULE_DEVICE_TABLE(usb, pwc_device_table);
111
112static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);
113static void usb_pwc_disconnect(struct usb_interface *intf);
114
115static struct usb_driver pwc_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 .name = "Philips webcam", /* name */
117 .id_table = pwc_device_table,
118 .probe = usb_pwc_probe, /* probe() */
119 .disconnect = usb_pwc_disconnect, /* disconnect() */
120};
121
122#define MAX_DEV_HINTS 20
123#define MAX_ISOC_ERRORS 20
124
125static int default_size = PSZ_QCIF;
126static int default_fps = 10;
127static int default_fbufs = 3; /* Default number of frame buffers */
Michael Krufkyb930e1d2007-08-27 18:16:54 -0300128 int pwc_mbufs = 2; /* Default number of mmap() buffers */
Trent Piepho05ad3902007-01-30 23:26:01 -0300129#ifdef CONFIG_USB_PWC_DEBUG
Michael Krufkyb930e1d2007-08-27 18:16:54 -0300130 int pwc_trace = PWC_DEBUG_LEVEL;
Luc Saillard2b455db2006-04-24 10:29:46 -0300131#endif
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300132static int power_save;
133static int led_on = 100, led_off; /* defaults to LED that is on while in use */
Adrian Bunkb20c3cf2006-06-23 06:49:34 -0300134static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135static struct {
136 int type;
137 char serial_number[30];
138 int device_node;
139 struct pwc_device *pdev;
140} device_hint[MAX_DEV_HINTS];
141
142/***/
143
Hans Verkuilbec43662008-12-30 06:58:20 -0300144static int pwc_video_open(struct file *file);
145static int pwc_video_close(struct file *file);
Luc Saillard2b455db2006-04-24 10:29:46 -0300146static ssize_t pwc_video_read(struct file *file, char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 size_t count, loff_t *ppos);
148static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
Hans Verkuil069b7472008-12-30 07:04:34 -0300149static long pwc_video_ioctl(struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 unsigned int ioctlnr, unsigned long arg);
151static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
152
Hans Verkuilbec43662008-12-30 06:58:20 -0300153static const struct v4l2_file_operations pwc_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 .owner = THIS_MODULE,
155 .open = pwc_video_open,
156 .release = pwc_video_close,
157 .read = pwc_video_read,
158 .poll = pwc_video_poll,
159 .mmap = pwc_video_mmap,
160 .ioctl = pwc_video_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161};
162static struct video_device pwc_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 .name = "Philips Webcam", /* Filled in later */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 .release = video_device_release,
165 .fops = &pwc_fops,
166 .minor = -1,
167};
168
169/***************************************************************************/
170
171/* Okay, this is some magic that I worked out and the reasoning behind it...
172
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300173 The biggest problem with any USB device is of course: "what to do
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 when the user unplugs the device while it is in use by an application?"
175 We have several options:
176 1) Curse them with the 7 plagues when they do (requires divine intervention)
177 2) Tell them not to (won't work: they'll do it anyway)
178 3) Oops the kernel (this will have a negative effect on a user's uptime)
179 4) Do something sensible.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 Of course, we go for option 4.
182
183 It happens that this device will be linked to two times, once from
184 usb_device and once from the video_device in their respective 'private'
185 pointers. This is done when the device is probed() and all initialization
186 succeeded. The pwc_device struct links back to both structures.
187
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300188 When a device is unplugged while in use it will be removed from the
189 list of known USB devices; I also de-register it as a V4L device, but
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 unfortunately I can't free the memory since the struct is still in use
191 by the file descriptor. This free-ing is then deferend until the first
192 opportunity. Crude, but it works.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300193
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 A small 'advantage' is that if a user unplugs the cam and plugs it back
195 in, it should get assigned the same video device minor, but unfortunately
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300196 it's non-trivial to re-link the cam back to the video device... (that
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 would surely be magic! :))
198*/
199
200/***************************************************************************/
201/* Private functions */
202
203/* Here we want the physical address of the memory.
204 * This is used when initializing the contents of the area.
205 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Luc Saillard2b455db2006-04-24 10:29:46 -0300208
209static void *pwc_rvmalloc(unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210{
211 void * mem;
212 unsigned long adr;
213
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300214 mem=vmalloc_32(size);
Luc Saillard2b455db2006-04-24 10:29:46 -0300215 if (!mem)
216 return NULL;
217
218 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
219 adr=(unsigned long) mem;
220 while (size > 0)
221 {
222 SetPageReserved(vmalloc_to_page((void *)adr));
223 adr += PAGE_SIZE;
224 size -= PAGE_SIZE;
225 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 return mem;
227}
228
Luc Saillard2b455db2006-04-24 10:29:46 -0300229static void pwc_rvfree(void * mem, unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230{
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300231 unsigned long adr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
Luc Saillard2b455db2006-04-24 10:29:46 -0300233 if (!mem)
234 return;
235
236 adr=(unsigned long) mem;
237 while ((long) size > 0)
238 {
239 ClearPageReserved(vmalloc_to_page((void *)adr));
240 adr += PAGE_SIZE;
241 size -= PAGE_SIZE;
242 }
243 vfree(mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244}
245
246
247
248
249static int pwc_allocate_buffers(struct pwc_device *pdev)
250{
Luc Saillard2b455db2006-04-24 10:29:46 -0300251 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 void *kbuf;
253
Luc Saillard2b455db2006-04-24 10:29:46 -0300254 PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
256 if (pdev == NULL)
257 return -ENXIO;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300258
Luc Saillard2b455db2006-04-24 10:29:46 -0300259 /* Allocate Isochronuous pipe buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 for (i = 0; i < MAX_ISO_BUFS; i++) {
261 if (pdev->sbuf[i].data == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300262 kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263 if (kbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300264 PWC_ERROR("Failed to allocate iso buffer %d.\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 return -ENOMEM;
266 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300267 PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 pdev->sbuf[i].data = kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 }
270 }
271
272 /* Allocate frame buffer structure */
273 if (pdev->fbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300274 kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 if (kbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300276 PWC_ERROR("Failed to allocate frame buffer structure.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 return -ENOMEM;
278 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300279 PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 pdev->fbuf = kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300282
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 /* create frame buffers, and make circular ring */
284 for (i = 0; i < default_fbufs; i++) {
285 if (pdev->fbuf[i].data == NULL) {
286 kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
287 if (kbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300288 PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 return -ENOMEM;
290 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300291 PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 pdev->fbuf[i].data = kbuf;
Luc Saillard2b455db2006-04-24 10:29:46 -0300293 memset(kbuf, 0, PWC_FRAME_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 }
295 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300296
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 /* Allocate decompressor table space */
Luc Saillard2b455db2006-04-24 10:29:46 -0300298 if (DEVICE_USE_CODEC1(pdev->type))
299 err = pwc_dec1_alloc(pdev);
300 else
301 err = pwc_dec23_alloc(pdev);
302
303 if (err) {
304 PWC_ERROR("Failed to allocate decompress table.\n");
305 return err;
306 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 /* Allocate image buffer; double buffer for mmap() */
Luc Saillard2b455db2006-04-24 10:29:46 -0300309 kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 if (kbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300311 PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n",
312 pwc_mbufs * pdev->len_per_image);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 return -ENOMEM;
314 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300315 PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 pdev->image_data = kbuf;
Luc Saillard2b455db2006-04-24 10:29:46 -0300317 for (i = 0; i < pwc_mbufs; i++) {
318 pdev->images[i].offset = i * pdev->len_per_image;
319 pdev->images[i].vma_use_count = 0;
320 }
321 for (; i < MAX_IMAGES; i++) {
322 pdev->images[i].offset = 0;
323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 kbuf = NULL;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300326
Luc Saillard2b455db2006-04-24 10:29:46 -0300327 PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 return 0;
329}
330
331static void pwc_free_buffers(struct pwc_device *pdev)
332{
333 int i;
334
Luc Saillard2b455db2006-04-24 10:29:46 -0300335 PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336
337 if (pdev == NULL)
338 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 /* Release Iso-pipe buffers */
340 for (i = 0; i < MAX_ISO_BUFS; i++)
341 if (pdev->sbuf[i].data != NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300342 PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 kfree(pdev->sbuf[i].data);
344 pdev->sbuf[i].data = NULL;
345 }
346
347 /* The same for frame buffers */
348 if (pdev->fbuf != NULL) {
349 for (i = 0; i < default_fbufs; i++) {
350 if (pdev->fbuf[i].data != NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300351 PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 vfree(pdev->fbuf[i].data);
353 pdev->fbuf[i].data = NULL;
354 }
355 }
356 kfree(pdev->fbuf);
357 pdev->fbuf = NULL;
358 }
359
360 /* Intermediate decompression buffer & tables */
361 if (pdev->decompress_data != NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300362 PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 kfree(pdev->decompress_data);
364 pdev->decompress_data = NULL;
365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366
367 /* Release image buffers */
368 if (pdev->image_data != NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300369 PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data);
370 pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 }
372 pdev->image_data = NULL;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300373
Luc Saillard2b455db2006-04-24 10:29:46 -0300374 PWC_DEBUG_MEMORY("Leaving free_buffers().\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375}
376
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300377/* The frame & image buffer mess.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
379 Yes, this is a mess. Well, it used to be simple, but alas... In this
380 module, 3 buffers schemes are used to get the data from the USB bus to
381 the user program. The first scheme involves the ISO buffers (called thus
382 since they transport ISO data from the USB controller), and not really
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300383 interesting. Suffices to say the data from this buffer is quickly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 gathered in an interrupt handler (pwc_isoc_handler) and placed into the
385 frame buffer.
386
387 The frame buffer is the second scheme, and is the central element here.
388 It collects the data from a single frame from the camera (hence, the
389 name). Frames are delimited by the USB camera with a short USB packet,
390 so that's easy to detect. The frame buffers form a list that is filled
391 by the camera+USB controller and drained by the user process through
392 either read() or mmap().
393
394 The image buffer is the third scheme, in which frames are decompressed
395 and converted into planar format. For mmap() there is more than
396 one image buffer available.
397
398 The frame buffers provide the image buffering. In case the user process
399 is a bit slow, this introduces lag and some undesired side-effects.
400 The problem arises when the frame buffer is full. I used to drop the last
401 frame, which makes the data in the queue stale very quickly. But dropping
402 the frame at the head of the queue proved to be a litte bit more difficult.
403 I tried a circular linked scheme, but this introduced more problems than
404 it solved.
405
406 Because filling and draining are completely asynchronous processes, this
407 requires some fiddling with pointers and mutexes.
408
409 Eventually, I came up with a system with 2 lists: an 'empty' frame list
410 and a 'full' frame list:
411 * Initially, all frame buffers but one are on the 'empty' list; the one
412 remaining buffer is our initial fill frame.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300413 * If a frame is needed for filling, we try to take it from the 'empty'
414 list, unless that list is empty, in which case we take the buffer at
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 the head of the 'full' list.
416 * When our fill buffer has been filled, it is appended to the 'full'
417 list.
418 * If a frame is needed by read() or mmap(), it is taken from the head of
419 the 'full' list, handled, and then appended to the 'empty' list. If no
420 buffer is present on the 'full' list, we wait.
421 The advantage is that the buffer that is currently being decompressed/
422 converted, is on neither list, and thus not in our way (any other scheme
423 I tried had the problem of old data lingering in the queue).
424
425 Whatever strategy you choose, it always remains a tradeoff: with more
426 frame buffers the chances of a missed frame are reduced. On the other
427 hand, on slower machines it introduces lag because the queue will
428 always be full.
429 */
430
431/**
432 \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
433 */
Luc Saillard2b455db2006-04-24 10:29:46 -0300434static int pwc_next_fill_frame(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435{
436 int ret;
437 unsigned long flags;
438
439 ret = 0;
440 spin_lock_irqsave(&pdev->ptrlock, flags);
441 if (pdev->fill_frame != NULL) {
442 /* append to 'full' list */
443 if (pdev->full_frames == NULL) {
444 pdev->full_frames = pdev->fill_frame;
445 pdev->full_frames_tail = pdev->full_frames;
446 }
447 else {
448 pdev->full_frames_tail->next = pdev->fill_frame;
449 pdev->full_frames_tail = pdev->fill_frame;
450 }
451 }
452 if (pdev->empty_frames != NULL) {
453 /* We have empty frames available. That's easy */
454 pdev->fill_frame = pdev->empty_frames;
455 pdev->empty_frames = pdev->empty_frames->next;
456 }
457 else {
458 /* Hmm. Take it from the full list */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 /* sanity check */
460 if (pdev->full_frames == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300461 PWC_ERROR("Neither empty or full frames available!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 spin_unlock_irqrestore(&pdev->ptrlock, flags);
463 return -EINVAL;
464 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 pdev->fill_frame = pdev->full_frames;
466 pdev->full_frames = pdev->full_frames->next;
467 ret = 1;
468 }
469 pdev->fill_frame->next = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 spin_unlock_irqrestore(&pdev->ptrlock, flags);
471 return ret;
472}
473
474
475/**
476 \brief Reset all buffers, pointers and lists, except for the image_used[] buffer.
477
478 If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble.
479 */
480static void pwc_reset_buffers(struct pwc_device *pdev)
481{
482 int i;
483 unsigned long flags;
484
Harvey Harrison645635b2008-04-08 23:20:00 -0300485 PWC_DEBUG_MEMORY(">> %s __enter__\n", __func__);
Luc Saillard2b455db2006-04-24 10:29:46 -0300486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 spin_lock_irqsave(&pdev->ptrlock, flags);
488 pdev->full_frames = NULL;
489 pdev->full_frames_tail = NULL;
490 for (i = 0; i < default_fbufs; i++) {
491 pdev->fbuf[i].filled = 0;
492 if (i > 0)
493 pdev->fbuf[i].next = &pdev->fbuf[i - 1];
494 else
495 pdev->fbuf->next = NULL;
496 }
497 pdev->empty_frames = &pdev->fbuf[default_fbufs - 1];
498 pdev->empty_frames_tail = pdev->fbuf;
499 pdev->read_frame = NULL;
500 pdev->fill_frame = pdev->empty_frames;
501 pdev->empty_frames = pdev->empty_frames->next;
502
503 pdev->image_read_pos = 0;
504 pdev->fill_image = 0;
505 spin_unlock_irqrestore(&pdev->ptrlock, flags);
Luc Saillard2b455db2006-04-24 10:29:46 -0300506
Harvey Harrison645635b2008-04-08 23:20:00 -0300507 PWC_DEBUG_MEMORY("<< %s __leaving__\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508}
509
510
511/**
512 \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
513 */
Luc Saillard2b455db2006-04-24 10:29:46 -0300514int pwc_handle_frame(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515{
516 int ret = 0;
517 unsigned long flags;
518
519 spin_lock_irqsave(&pdev->ptrlock, flags);
520 /* First grab our read_frame; this is removed from all lists, so
521 we can release the lock after this without problems */
522 if (pdev->read_frame != NULL) {
523 /* This can't theoretically happen */
Luc Saillard2b455db2006-04-24 10:29:46 -0300524 PWC_ERROR("Huh? Read frame still in use?\n");
525 spin_unlock_irqrestore(&pdev->ptrlock, flags);
526 return ret;
527 }
528
529
530 if (pdev->full_frames == NULL) {
531 PWC_ERROR("Woops. No frames ready.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 }
533 else {
Luc Saillard2b455db2006-04-24 10:29:46 -0300534 pdev->read_frame = pdev->full_frames;
535 pdev->full_frames = pdev->full_frames->next;
536 pdev->read_frame->next = NULL;
537 }
538
539 if (pdev->read_frame != NULL) {
Paulius Zaleckasefad798b2008-02-03 15:42:53 +0200540 /* Decompression is a lengthy process, so it's outside of the lock.
Luc Saillard2b455db2006-04-24 10:29:46 -0300541 This gives the isoc_handler the opportunity to fill more frames
542 in the mean time.
543 */
544 spin_unlock_irqrestore(&pdev->ptrlock, flags);
545 ret = pwc_decompress(pdev);
546 spin_lock_irqsave(&pdev->ptrlock, flags);
547
548 /* We're done with read_buffer, tack it to the end of the empty buffer list */
549 if (pdev->empty_frames == NULL) {
550 pdev->empty_frames = pdev->read_frame;
551 pdev->empty_frames_tail = pdev->empty_frames;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 }
553 else {
Luc Saillard2b455db2006-04-24 10:29:46 -0300554 pdev->empty_frames_tail->next = pdev->read_frame;
555 pdev->empty_frames_tail = pdev->read_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300557 pdev->read_frame = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 }
559 spin_unlock_irqrestore(&pdev->ptrlock, flags);
560 return ret;
561}
562
563/**
564 \brief Advance pointers of image buffer (after each user request)
565*/
Luc Saillard2b455db2006-04-24 10:29:46 -0300566void pwc_next_image(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567{
568 pdev->image_used[pdev->fill_image] = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300569 pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570}
571
Luc Saillard2b455db2006-04-24 10:29:46 -0300572/**
573 * Print debug information when a frame is discarded because all of our buffer
574 * is full
575 */
576static void pwc_frame_dumped(struct pwc_device *pdev)
577{
578 pdev->vframes_dumped++;
579 if (pdev->vframe_count < FRAME_LOWMARK)
580 return;
581
582 if (pdev->vframes_dumped < 20)
583 PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count);
584 else if (pdev->vframes_dumped == 20)
585 PWC_DEBUG_FLOW("Dumping frame %d (last message)\n",
586 pdev->vframe_count);
587}
588
589static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
590{
591 int awake = 0;
592
593 /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
594 frames on the USB wire after an exposure change. This conditition is
595 however detected in the cam and a bit is set in the header.
596 */
597 if (pdev->type == 730) {
598 unsigned char *ptr = (unsigned char *)fbuf->data;
599
600 if (ptr[1] == 1 && ptr[0] & 0x10) {
601 PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
602 pdev->drop_frames += 2;
603 pdev->vframes_error++;
604 }
605 if ((ptr[0] ^ pdev->vmirror) & 0x01) {
606 if (ptr[0] & 0x01) {
607 pdev->snapshot_button_status = 1;
608 PWC_TRACE("Snapshot button pressed.\n");
609 }
610 else {
611 PWC_TRACE("Snapshot button released.\n");
612 }
613 }
614 if ((ptr[0] ^ pdev->vmirror) & 0x02) {
615 if (ptr[0] & 0x02)
616 PWC_TRACE("Image is mirrored.\n");
617 else
618 PWC_TRACE("Image is normal.\n");
619 }
620 pdev->vmirror = ptr[0] & 0x03;
621 /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
622 after a short frame; this condition is filtered out specifically. A 4 byte
623 frame doesn't make sense anyway.
624 So we get either this sequence:
625 drop_bit set -> 4 byte frame -> short frame -> good frame
626 Or this one:
627 drop_bit set -> short frame -> good frame
628 So we drop either 3 or 2 frames in all!
629 */
630 if (fbuf->filled == 4)
631 pdev->drop_frames++;
632 }
633 else if (pdev->type == 740 || pdev->type == 720) {
634 unsigned char *ptr = (unsigned char *)fbuf->data;
635 if ((ptr[0] ^ pdev->vmirror) & 0x01) {
636 if (ptr[0] & 0x01) {
637 pdev->snapshot_button_status = 1;
638 PWC_TRACE("Snapshot button pressed.\n");
639 }
640 else
641 PWC_TRACE("Snapshot button released.\n");
642 }
643 pdev->vmirror = ptr[0] & 0x03;
644 }
645
646 /* In case we were instructed to drop the frame, do so silently.
647 The buffer pointers are not updated either (but the counters are reset below).
648 */
649 if (pdev->drop_frames > 0)
650 pdev->drop_frames--;
651 else {
652 /* Check for underflow first */
653 if (fbuf->filled < pdev->frame_total_size) {
654 PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
655 " discarded.\n", fbuf->filled);
656 pdev->vframes_error++;
657 }
658 else {
659 /* Send only once per EOF */
660 awake = 1; /* delay wake_ups */
661
662 /* Find our next frame to fill. This will always succeed, since we
663 * nick a frame from either empty or full list, but if we had to
664 * take it from the full list, it means a frame got dropped.
665 */
666 if (pwc_next_fill_frame(pdev))
667 pwc_frame_dumped(pdev);
668
669 }
670 } /* !drop_frames */
671 pdev->vframe_count++;
672 return awake;
673}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674
675/* This gets called for the Isochronous pipe (video). This is done in
676 * interrupt time, so it has to be fast, not crash, and not stall. Neat.
677 */
David Howells7d12e782006-10-05 14:55:46 +0100678static void pwc_isoc_handler(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
680 struct pwc_device *pdev;
681 int i, fst, flen;
682 int awake;
683 struct pwc_frame_buf *fbuf;
684 unsigned char *fillptr = NULL, *iso_buf = NULL;
685
686 awake = 0;
687 pdev = (struct pwc_device *)urb->context;
688 if (pdev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300689 PWC_ERROR("isoc_handler() called with NULL device?!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 return;
691 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300692
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300694 PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 return;
696 }
697 if (urb->status != -EINPROGRESS && urb->status != 0) {
698 const char *errmsg;
699
700 errmsg = "Unknown";
701 switch(urb->status) {
702 case -ENOSR: errmsg = "Buffer error (overrun)"; break;
703 case -EPIPE: errmsg = "Stalled (device not responding)"; break;
704 case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break;
705 case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break;
706 case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break;
Pete Zaitcev38e2bfc2006-09-18 22:49:02 -0700707 case -ETIME: errmsg = "Device does not respond"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300709 PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300710 /* Give up after a number of contiguous errors on the USB bus.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 Appearantly something is wrong so we simulate an unplug event.
712 */
713 if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
714 {
Luc Saillard2b455db2006-04-24 10:29:46 -0300715 PWC_INFO("Too many ISOC errors, bailing out.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 pdev->error_status = EIO;
717 awake = 1;
718 wake_up_interruptible(&pdev->frameq);
719 }
720 goto handler_end; // ugly, but practical
721 }
722
723 fbuf = pdev->fill_frame;
724 if (fbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300725 PWC_ERROR("pwc_isoc_handler without valid fill frame.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 awake = 1;
727 goto handler_end;
728 }
729 else {
730 fillptr = fbuf->data + fbuf->filled;
731 }
732
733 /* Reset ISOC error counter. We did get here, after all. */
734 pdev->visoc_errors = 0;
735
736 /* vsync: 0 = don't copy data
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300737 1 = sync-hunt
738 2 = synched
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 */
740 /* Compact data */
741 for (i = 0; i < urb->number_of_packets; i++) {
742 fst = urb->iso_frame_desc[i].status;
743 flen = urb->iso_frame_desc[i].actual_length;
744 iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
745 if (fst == 0) {
746 if (flen > 0) { /* if valid data... */
747 if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */
748 pdev->vsync = 2;
749
750 /* ...copy data to frame buffer, if possible */
751 if (flen + fbuf->filled > pdev->frame_total_size) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300752 PWC_DEBUG_FLOW("Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
754 pdev->vframes_error++;
755 }
756 else {
757 memmove(fillptr, iso_buf, flen);
758 fillptr += flen;
759 }
760 }
761 fbuf->filled += flen;
762 } /* ..flen > 0 */
763
764 if (flen < pdev->vlast_packet_size) {
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300765 /* Shorter packet... We probably have the end of an image-frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 wake up read() process and let select()/poll() do something.
767 Decompression is done in user time over there.
Luc Saillard2b455db2006-04-24 10:29:46 -0300768 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769 if (pdev->vsync == 2) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300770 if (pwc_rcv_short_packet(pdev, fbuf)) {
771 awake = 1;
772 fbuf = pdev->fill_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
775 fbuf->filled = 0;
776 fillptr = fbuf->data;
777 pdev->vsync = 1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300778 }
779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 pdev->vlast_packet_size = flen;
781 } /* ..status == 0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 else {
Luc Saillard2b455db2006-04-24 10:29:46 -0300783 /* This is normally not interesting to the user, unless
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300784 * you are really debugging something, default = 0 */
785 static int iso_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 iso_error++;
787 if (iso_error < 20)
Luc Saillard2b455db2006-04-24 10:29:46 -0300788 PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
791
792handler_end:
793 if (awake)
794 wake_up_interruptible(&pdev->frameq);
795
796 urb->dev = pdev->udev;
797 i = usb_submit_urb(urb, GFP_ATOMIC);
798 if (i != 0)
Luc Saillard2b455db2006-04-24 10:29:46 -0300799 PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800}
801
802
Luc Saillard2b455db2006-04-24 10:29:46 -0300803int pwc_isoc_init(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804{
805 struct usb_device *udev;
806 struct urb *urb;
807 int i, j, ret;
808
809 struct usb_interface *intf;
810 struct usb_host_interface *idesc = NULL;
811
812 if (pdev == NULL)
813 return -EFAULT;
814 if (pdev->iso_init)
815 return 0;
816 pdev->vsync = 0;
817 udev = pdev->udev;
818
819 /* Get the current alternate interface, adjust packet size */
820 if (!udev->actconfig)
821 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 intf = usb_ifnum_to_if(udev, 0);
823 if (intf)
824 idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300825
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 if (!idesc)
827 return -EFAULT;
828
829 /* Search video endpoint */
830 pdev->vmax_packet_size = -1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300831 for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
833 pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
834 break;
835 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300836 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300837
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300839 PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");
Steven Cole093cf722005-05-03 19:07:24 -0600840 return -ENFILE; /* Odd error, that should be noticeable */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841 }
842
843 /* Set alternate interface */
844 ret = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300845 PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
847 if (ret < 0)
848 return ret;
849
850 for (i = 0; i < MAX_ISO_BUFS; i++) {
851 urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
852 if (urb == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300853 PWC_ERROR("Failed to allocate urb %d\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 ret = -ENOMEM;
855 break;
856 }
857 pdev->sbuf[i].urb = urb;
Luc Saillard2b455db2006-04-24 10:29:46 -0300858 PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 }
860 if (ret) {
861 /* De-allocate in reverse order */
Mariusz Kozlowski444f4f92006-11-16 16:38:57 +0100862 while (i--) {
Mariusz Kozlowski90b26252006-11-08 15:34:55 +0100863 usb_free_urb(pdev->sbuf[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 pdev->sbuf[i].urb = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 }
866 return ret;
867 }
868
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300869 /* init URB structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 for (i = 0; i < MAX_ISO_BUFS; i++) {
871 urb = pdev->sbuf[i].urb;
872
873 urb->interval = 1; // devik
874 urb->dev = udev;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300875 urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 urb->transfer_flags = URB_ISO_ASAP;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300877 urb->transfer_buffer = pdev->sbuf[i].data;
878 urb->transfer_buffer_length = ISO_BUFFER_SIZE;
879 urb->complete = pwc_isoc_handler;
880 urb->context = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 urb->start_frame = 0;
882 urb->number_of_packets = ISO_FRAMES_PER_DESC;
883 for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
884 urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
885 urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
886 }
887 }
888
889 /* link */
890 for (i = 0; i < MAX_ISO_BUFS; i++) {
891 ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
892 if (ret)
Luc Saillard2b455db2006-04-24 10:29:46 -0300893 PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 else
Luc Saillard2b455db2006-04-24 10:29:46 -0300895 PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 }
897
898 /* All is done... */
899 pdev->iso_init = 1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300900 PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 return 0;
902}
903
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300904static void pwc_iso_stop(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905{
906 int i;
907
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 /* Unlinking ISOC buffers one by one */
909 for (i = 0; i < MAX_ISO_BUFS; i++) {
910 struct urb *urb;
911
912 urb = pdev->sbuf[i].urb;
Al Viro5fa12472008-03-29 03:07:38 +0000913 if (urb) {
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300914 PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
915 usb_kill_urb(urb);
916 }
917 }
918}
919
920static void pwc_iso_free(struct pwc_device *pdev)
921{
922 int i;
923
924 /* Freeing ISOC buffers one by one */
925 for (i = 0; i < MAX_ISO_BUFS; i++) {
926 struct urb *urb;
927
928 urb = pdev->sbuf[i].urb;
Al Viro5fa12472008-03-29 03:07:38 +0000929 if (urb) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300930 PWC_DEBUG_MEMORY("Freeing URB\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700931 usb_free_urb(urb);
932 pdev->sbuf[i].urb = NULL;
933 }
934 }
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300935}
936
937void pwc_isoc_cleanup(struct pwc_device *pdev)
938{
939 PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
940 if (pdev == NULL)
941 return;
942 if (pdev->iso_init == 0)
943 return;
944
945 pwc_iso_stop(pdev);
946 pwc_iso_free(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
948 /* Stop camera, but only if we are sure the camera is still there (unplug
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300949 is signalled by EPIPE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 */
951 if (pdev->error_status && pdev->error_status != EPIPE) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300952 PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 usb_set_interface(pdev->udev, 0, 0);
954 }
955
956 pdev->iso_init = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300957 PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958}
959
960int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
961{
962 int ret, start;
963
964 /* Stop isoc stuff */
965 pwc_isoc_cleanup(pdev);
966 /* Reset parameters */
967 pwc_reset_buffers(pdev);
968 /* Try to set video mode... */
969 start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300970 if (ret) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300971 PWC_DEBUG_FLOW("pwc_set_video_mode attempt 1 failed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 /* That failed... restore old mode (we know that worked) */
973 start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
974 if (start) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300975 PWC_DEBUG_FLOW("pwc_set_video_mode attempt 2 failed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 }
977 }
978 if (start == 0)
979 {
980 if (pwc_isoc_init(pdev) < 0)
981 {
Luc Saillard2b455db2006-04-24 10:29:46 -0300982 PWC_WARNING("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 ret = -EAGAIN; /* let's try again, who knows if it works a second time */
984 }
985 }
986 pdev->drop_frames++; /* try to avoid garbage during switch */
987 return ret; /* Return original error code */
988}
989
Luc Saillard2b455db2006-04-24 10:29:46 -0300990/*********
991 * sysfs
992 *********/
Kay Sievers54bd5b62007-10-08 16:26:13 -0300993static struct pwc_device *cd_to_pwc(struct device *cd)
Luc Saillard2b455db2006-04-24 10:29:46 -0300994{
995 struct video_device *vdev = to_video_device(cd);
996 return video_get_drvdata(vdev);
997}
998
Kay Sievers54bd5b62007-10-08 16:26:13 -0300999static ssize_t show_pan_tilt(struct device *class_dev,
1000 struct device_attribute *attr, char *buf)
Luc Saillard2b455db2006-04-24 10:29:46 -03001001{
1002 struct pwc_device *pdev = cd_to_pwc(class_dev);
1003 return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
1004}
1005
Kay Sievers54bd5b62007-10-08 16:26:13 -03001006static ssize_t store_pan_tilt(struct device *class_dev,
1007 struct device_attribute *attr,
1008 const char *buf, size_t count)
Luc Saillard2b455db2006-04-24 10:29:46 -03001009{
1010 struct pwc_device *pdev = cd_to_pwc(class_dev);
1011 int pan, tilt;
1012 int ret = -EINVAL;
1013
1014 if (strncmp(buf, "reset", 5) == 0)
1015 ret = pwc_mpt_reset(pdev, 0x3);
1016
1017 else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
1018 ret = pwc_mpt_set_angle(pdev, pan, tilt);
1019
1020 if (ret < 0)
1021 return ret;
1022 return strlen(buf);
1023}
Kay Sievers54bd5b62007-10-08 16:26:13 -03001024static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
1025 store_pan_tilt);
Luc Saillard2b455db2006-04-24 10:29:46 -03001026
Kay Sievers54bd5b62007-10-08 16:26:13 -03001027static ssize_t show_snapshot_button_status(struct device *class_dev,
1028 struct device_attribute *attr, char *buf)
Luc Saillard2b455db2006-04-24 10:29:46 -03001029{
1030 struct pwc_device *pdev = cd_to_pwc(class_dev);
1031 int status = pdev->snapshot_button_status;
1032 pdev->snapshot_button_status = 0;
1033 return sprintf(buf, "%d\n", status);
1034}
1035
Kay Sievers54bd5b62007-10-08 16:26:13 -03001036static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
1037 NULL);
Luc Saillard2b455db2006-04-24 10:29:46 -03001038
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001039static int pwc_create_sysfs_files(struct video_device *vdev)
Luc Saillard2b455db2006-04-24 10:29:46 -03001040{
1041 struct pwc_device *pdev = video_get_drvdata(vdev);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001042 int rc;
1043
Hans Verkuilf894dfd2008-07-25 07:39:54 -03001044 rc = device_create_file(&vdev->dev, &dev_attr_button);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001045 if (rc)
1046 goto err;
1047 if (pdev->features & FEATURE_MOTOR_PANTILT) {
Hans Verkuilf894dfd2008-07-25 07:39:54 -03001048 rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001049 if (rc) goto err_button;
1050 }
1051
1052 return 0;
1053
1054err_button:
Hans Verkuilf894dfd2008-07-25 07:39:54 -03001055 device_remove_file(&vdev->dev, &dev_attr_button);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001056err:
Hans Verkuilf894dfd2008-07-25 07:39:54 -03001057 PWC_ERROR("Could not create sysfs files.\n");
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001058 return rc;
Luc Saillard2b455db2006-04-24 10:29:46 -03001059}
1060
1061static void pwc_remove_sysfs_files(struct video_device *vdev)
1062{
1063 struct pwc_device *pdev = video_get_drvdata(vdev);
1064 if (pdev->features & FEATURE_MOTOR_PANTILT)
Hans Verkuilf894dfd2008-07-25 07:39:54 -03001065 device_remove_file(&vdev->dev, &dev_attr_pan_tilt);
1066 device_remove_file(&vdev->dev, &dev_attr_button);
Luc Saillard2b455db2006-04-24 10:29:46 -03001067}
1068
Trent Piepho05ad3902007-01-30 23:26:01 -03001069#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -03001070static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
1071{
1072 switch(sensor_type) {
1073 case 0x00:
1074 return "Hyundai CMOS sensor";
1075 case 0x20:
1076 return "Sony CCD sensor + TDA8787";
1077 case 0x2E:
1078 return "Sony CCD sensor + Exas 98L59";
1079 case 0x2F:
1080 return "Sony CCD sensor + ADI 9804";
1081 case 0x30:
1082 return "Sharp CCD sensor + TDA8787";
1083 case 0x3E:
1084 return "Sharp CCD sensor + Exas 98L59";
1085 case 0x3F:
1086 return "Sharp CCD sensor + ADI 9804";
1087 case 0x40:
1088 return "UPA 1021 sensor";
1089 case 0x100:
1090 return "VGA sensor";
1091 case 0x101:
1092 return "PAL MR sensor";
1093 default:
Trent Piepho657de3c2006-06-20 00:30:57 -03001094 return "unknown type of sensor";
Luc Saillard2b455db2006-04-24 10:29:46 -03001095 }
1096}
1097#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099/***************************************************************************/
1100/* Video4Linux functions */
1101
Hans Verkuilbec43662008-12-30 06:58:20 -03001102static int pwc_video_open(struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103{
Luc Saillard2b455db2006-04-24 10:29:46 -03001104 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 struct video_device *vdev = video_devdata(file);
1106 struct pwc_device *pdev;
1107
Luc Saillard2b455db2006-04-24 10:29:46 -03001108 PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001109
Hans Verkuil601e9442008-08-23 07:24:07 -03001110 pdev = video_get_drvdata(vdev);
Eric Sesterhenn5d9a2762006-11-30 05:26:46 +01001111 BUG_ON(!pdev);
Luc Saillard2b455db2006-04-24 10:29:46 -03001112 if (pdev->vopen) {
1113 PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 return -EBUSY;
Luc Saillard2b455db2006-04-24 10:29:46 -03001115 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001116
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001117 mutex_lock(&pdev->modlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 if (!pdev->usb_init) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001119 PWC_DEBUG_OPEN("Doing first time initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 pdev->usb_init = 1;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001121
Luc Saillard2b455db2006-04-24 10:29:46 -03001122 /* Query sensor type */
1123 ret = pwc_get_cmos_sensor(pdev, &i);
1124 if (ret >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 {
Luc Saillard2b455db2006-04-24 10:29:46 -03001126 PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
1127 pdev->vdev->name,
1128 pwc_sensor_type_to_string(i), i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 }
1130 }
1131
1132 /* Turn on camera */
1133 if (power_save) {
1134 i = pwc_camera_power(pdev, 1);
1135 if (i < 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001136 PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 }
1138 /* Set LED on/off time */
1139 if (pwc_set_leds(pdev, led_on, led_off) < 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001140 PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001141
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 pwc_construct(pdev); /* set min/max sizes correct */
1143
1144 /* So far, so good. Allocate memory. */
1145 i = pwc_allocate_buffers(pdev);
1146 if (i < 0) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001147 PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
1148 pwc_free_buffers(pdev);
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001149 mutex_unlock(&pdev->modlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 return i;
1151 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 /* Reset buffers & parameters */
1154 pwc_reset_buffers(pdev);
Luc Saillard2b455db2006-04-24 10:29:46 -03001155 for (i = 0; i < pwc_mbufs; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 pdev->image_used[i] = 0;
1157 pdev->vframe_count = 0;
1158 pdev->vframes_dumped = 0;
1159 pdev->vframes_error = 0;
1160 pdev->visoc_errors = 0;
1161 pdev->error_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 pwc_construct(pdev); /* set min/max sizes correct */
1163
1164 /* Set some defaults */
1165 pdev->vsnapshot = 0;
1166
1167 /* Start iso pipe for video; first try the last used video size
1168 (or the default one); if that fails try QCIF/10 or QSIF/10;
1169 it that fails too, give up.
1170 */
1171 i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
1172 if (i) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001173 unsigned int default_resolution;
1174 PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n");
1175 if (pdev->type>= 730)
1176 default_resolution = PSZ_QSIF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 else
Luc Saillard2b455db2006-04-24 10:29:46 -03001178 default_resolution = PSZ_QCIF;
1179
1180 i = pwc_set_video_mode(pdev,
1181 pwc_image_sizes[default_resolution].x,
1182 pwc_image_sizes[default_resolution].y,
1183 10,
1184 pdev->vcompression,
1185 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 }
1187 if (i) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001188 PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
1189 pwc_free_buffers(pdev);
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001190 mutex_unlock(&pdev->modlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 return i;
1192 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001193
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 i = pwc_isoc_init(pdev);
1195 if (i) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001196 PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
1197 pwc_isoc_cleanup(pdev);
1198 pwc_free_buffers(pdev);
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001199 mutex_unlock(&pdev->modlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 return i;
1201 }
1202
Luc Saillard2b455db2006-04-24 10:29:46 -03001203 /* Initialize the webcam to sane value */
1204 pwc_set_brightness(pdev, 0x7fff);
1205 pwc_set_agc(pdev, 1, 0);
1206
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 pdev->vopen++;
1208 file->private_data = vdev;
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001209 mutex_unlock(&pdev->modlock);
Luc Saillard2b455db2006-04-24 10:29:46 -03001210 PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 return 0;
1212}
1213
Oliver Neukum85237f22007-08-21 07:10:42 +02001214
1215static void pwc_cleanup(struct pwc_device *pdev)
1216{
1217 pwc_remove_sysfs_files(pdev->vdev);
1218 video_unregister_device(pdev->vdev);
1219}
1220
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221/* Note that all cleanup is done in the reverse order as in _open */
Hans Verkuilbec43662008-12-30 06:58:20 -03001222static int pwc_video_close(struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223{
1224 struct video_device *vdev = file->private_data;
1225 struct pwc_device *pdev;
Oliver Neukum85237f22007-08-21 07:10:42 +02001226 int i, hint;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
Luc Saillard2b455db2006-04-24 10:29:46 -03001228 PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001230 lock_kernel();
Hans Verkuil601e9442008-08-23 07:24:07 -03001231 pdev = video_get_drvdata(vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 if (pdev->vopen == 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001233 PWC_DEBUG_MODULE("video_close() called on closed device?\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
1235 /* Dump statistics, but only if a reasonable amount of frames were
1236 processed (to prevent endless log-entries in case of snap-shot
1237 programs)
1238 */
1239 if (pdev->vframe_count > 20)
Luc Saillard2b455db2006-04-24 10:29:46 -03001240 PWC_DEBUG_MODULE("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
Luc Saillard2b455db2006-04-24 10:29:46 -03001242 if (DEVICE_USE_CODEC1(pdev->type))
1243 pwc_dec1_exit();
1244 else
1245 pwc_dec23_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
1247 pwc_isoc_cleanup(pdev);
1248 pwc_free_buffers(pdev);
1249
1250 /* Turn off LEDS and power down camera, but only when not unplugged */
Oliver Neukum85237f22007-08-21 07:10:42 +02001251 if (!pdev->unplugged) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 /* Turn LEDs off */
1253 if (pwc_set_leds(pdev, 0, 0) < 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001254 PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 if (power_save) {
1256 i = pwc_camera_power(pdev, 0);
1257 if (i < 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001258 PWC_ERROR("Failed to power down camera (%d)\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
Oliver Neukum85237f22007-08-21 07:10:42 +02001260 pdev->vopen--;
Jean Delvare7b9fbc32007-09-03 11:51:51 -03001261 PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
Oliver Neukum85237f22007-08-21 07:10:42 +02001262 } else {
1263 pwc_cleanup(pdev);
1264 /* Free memory (don't set pdev to 0 just yet) */
1265 kfree(pdev);
1266 /* search device_hint[] table if we occupy a slot, by any chance */
1267 for (hint = 0; hint < MAX_DEV_HINTS; hint++)
1268 if (device_hint[hint].pdev == pdev)
1269 device_hint[hint].pdev = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 }
Oliver Neukum85237f22007-08-21 07:10:42 +02001271 unlock_kernel();
1272
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 return 0;
1274}
1275
1276/*
1277 * FIXME: what about two parallel reads ????
1278 * ANSWER: Not supported. You can't open the device more than once,
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001279 despite what the V4L1 interface says. First, I don't see
1280 the need, second there's no mechanism of alerting the
1281 2nd/3rd/... process of events like changing image size.
1282 And I don't see the point of blocking that for the
1283 2nd/3rd/... process.
1284 In multi-threaded environments reading parallel from any
1285 device is tricky anyhow.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 */
1287
Luc Saillard2b455db2006-04-24 10:29:46 -03001288static ssize_t pwc_video_read(struct file *file, char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 size_t count, loff_t *ppos)
1290{
1291 struct video_device *vdev = file->private_data;
1292 struct pwc_device *pdev;
1293 int noblock = file->f_flags & O_NONBLOCK;
1294 DECLARE_WAITQUEUE(wait, current);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001295 int bytes_to_read, rv = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -03001296 void *image_buffer_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
Luc Saillard2b455db2006-04-24 10:29:46 -03001298 PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
1299 vdev, buf, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 if (vdev == NULL)
1301 return -EFAULT;
Hans Verkuil601e9442008-08-23 07:24:07 -03001302 pdev = video_get_drvdata(vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 if (pdev == NULL)
1304 return -EFAULT;
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001305
1306 mutex_lock(&pdev->modlock);
1307 if (pdev->error_status) {
1308 rv = -pdev->error_status; /* Something happened, report what. */
1309 goto err_out;
1310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311
1312 /* In case we're doing partial reads, we don't have to wait for a frame */
1313 if (pdev->image_read_pos == 0) {
1314 /* Do wait queueing according to the (doc)book */
1315 add_wait_queue(&pdev->frameq, &wait);
1316 while (pdev->full_frames == NULL) {
1317 /* Check for unplugged/etc. here */
1318 if (pdev->error_status) {
1319 remove_wait_queue(&pdev->frameq, &wait);
1320 set_current_state(TASK_RUNNING);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001321 rv = -pdev->error_status ;
1322 goto err_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001324 if (noblock) {
1325 remove_wait_queue(&pdev->frameq, &wait);
1326 set_current_state(TASK_RUNNING);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001327 rv = -EWOULDBLOCK;
1328 goto err_out;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001329 }
1330 if (signal_pending(current)) {
1331 remove_wait_queue(&pdev->frameq, &wait);
1332 set_current_state(TASK_RUNNING);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001333 rv = -ERESTARTSYS;
1334 goto err_out;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001335 }
1336 schedule();
1337 set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 }
1339 remove_wait_queue(&pdev->frameq, &wait);
1340 set_current_state(TASK_RUNNING);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001341
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 /* Decompress and release frame */
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001343 if (pwc_handle_frame(pdev)) {
1344 rv = -EFAULT;
1345 goto err_out;
1346 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 }
1348
Luc Saillard2b455db2006-04-24 10:29:46 -03001349 PWC_DEBUG_READ("Copying data to user space.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 if (pdev->vpalette == VIDEO_PALETTE_RAW)
Luc Saillard2b455db2006-04-24 10:29:46 -03001351 bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 else
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001353 bytes_to_read = pdev->view.size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
1355 /* copy bytes to user space; we allow for partial reads */
1356 if (count + pdev->image_read_pos > bytes_to_read)
1357 count = bytes_to_read - pdev->image_read_pos;
Luc Saillard2b455db2006-04-24 10:29:46 -03001358 image_buffer_addr = pdev->image_data;
1359 image_buffer_addr += pdev->images[pdev->fill_image].offset;
1360 image_buffer_addr += pdev->image_read_pos;
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001361 if (copy_to_user(buf, image_buffer_addr, count)) {
1362 rv = -EFAULT;
1363 goto err_out;
1364 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 pdev->image_read_pos += count;
1366 if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
1367 pdev->image_read_pos = 0;
1368 pwc_next_image(pdev);
1369 }
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001370 mutex_unlock(&pdev->modlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 return count;
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001372err_out:
1373 mutex_unlock(&pdev->modlock);
1374 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375}
1376
1377static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
1378{
1379 struct video_device *vdev = file->private_data;
1380 struct pwc_device *pdev;
1381
1382 if (vdev == NULL)
1383 return -EFAULT;
Hans Verkuil601e9442008-08-23 07:24:07 -03001384 pdev = video_get_drvdata(vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385 if (pdev == NULL)
1386 return -EFAULT;
1387
1388 poll_wait(file, &pdev->frameq, wait);
1389 if (pdev->error_status)
1390 return POLLERR;
1391 if (pdev->full_frames != NULL) /* we have frames waiting */
1392 return (POLLIN | POLLRDNORM);
1393
1394 return 0;
1395}
1396
Hans Verkuil069b7472008-12-30 07:04:34 -03001397static long pwc_video_ioctl(struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 unsigned int cmd, unsigned long arg)
1399{
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001400 struct video_device *vdev = file->private_data;
1401 struct pwc_device *pdev;
Hans Verkuil069b7472008-12-30 07:04:34 -03001402 long r = -ENODEV;
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001403
1404 if (!vdev)
1405 goto out;
Hans Verkuil601e9442008-08-23 07:24:07 -03001406 pdev = video_get_drvdata(vdev);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001407
1408 mutex_lock(&pdev->modlock);
1409 if (!pdev->unplugged)
Hans Verkuilf473bf72008-11-01 08:25:11 -03001410 r = video_usercopy(file, cmd, arg, pwc_video_do_ioctl);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001411 mutex_unlock(&pdev->modlock);
1412out:
1413 return r;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414}
1415
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
1417{
1418 struct video_device *vdev = file->private_data;
1419 struct pwc_device *pdev;
Luc Saillard2b455db2006-04-24 10:29:46 -03001420 unsigned long start;
1421 unsigned long size;
1422 unsigned long page, pos = 0;
1423 int index;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001424
Harvey Harrison645635b2008-04-08 23:20:00 -03001425 PWC_DEBUG_MEMORY(">> %s\n", __func__);
Hans Verkuil601e9442008-08-23 07:24:07 -03001426 pdev = video_get_drvdata(vdev);
Luc Saillard2b455db2006-04-24 10:29:46 -03001427 size = vma->vm_end - vma->vm_start;
1428 start = vma->vm_start;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001429
Luc Saillard2b455db2006-04-24 10:29:46 -03001430 /* Find the idx buffer for this mapping */
1431 for (index = 0; index < pwc_mbufs; index++) {
1432 pos = pdev->images[index].offset;
1433 if ((pos>>PAGE_SHIFT) == vma->vm_pgoff)
1434 break;
1435 }
1436 if (index == MAX_IMAGES)
1437 return -EINVAL;
1438 if (index == 0) {
1439 /*
1440 * Special case for v4l1. In v4l1, we map only one big buffer,
1441 * but in v4l2 each buffer is mapped
1442 */
1443 unsigned long total_size;
1444 total_size = pwc_mbufs * pdev->len_per_image;
1445 if (size != pdev->len_per_image && size != total_size) {
1446 PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n",
1447 size, pdev->len_per_image, total_size);
1448 return -EINVAL;
1449 }
1450 } else if (size > pdev->len_per_image)
1451 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452
Luc Saillard2b455db2006-04-24 10:29:46 -03001453 vma->vm_flags |= VM_IO; /* from 2.6.9-acX */
1454
1455 pos += (unsigned long)pdev->image_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 while (size > 0) {
1457 page = vmalloc_to_pfn((void *)pos);
1458 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1459 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 start += PAGE_SIZE;
1461 pos += PAGE_SIZE;
1462 if (size > PAGE_SIZE)
1463 size -= PAGE_SIZE;
1464 else
1465 size = 0;
1466 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001467 return 0;
1468}
1469
1470/***************************************************************************/
1471/* USB functions */
1472
1473/* This function gets called when a new device is plugged in or the usb core
1474 * is loaded.
1475 */
1476
1477static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id)
1478{
1479 struct usb_device *udev = interface_to_usbdev(intf);
1480 struct pwc_device *pdev = NULL;
1481 int vendor_id, product_id, type_id;
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001482 int i, hint, rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 int features = 0;
1484 int video_nr = -1; /* default: use next available device */
1485 char serial_number[30], *name;
1486
Luc Saillard2b455db2006-04-24 10:29:46 -03001487 vendor_id = le16_to_cpu(udev->descriptor.idVendor);
1488 product_id = le16_to_cpu(udev->descriptor.idProduct);
1489
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 /* Check if we can handle this device */
Luc Saillard2b455db2006-04-24 10:29:46 -03001491 PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
1492 vendor_id, product_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 intf->altsetting->desc.bInterfaceNumber);
1494
1495 /* the interfaces are probed one by one. We are only interested in the
1496 video interface (0) now.
1497 Interface 1 is the Audio Control, and interface 2 Audio itself.
1498 */
1499 if (intf->altsetting->desc.bInterfaceNumber > 0)
1500 return -ENODEV;
1501
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 if (vendor_id == 0x0471) {
1503 switch (product_id) {
1504 case 0x0302:
Luc Saillard2b455db2006-04-24 10:29:46 -03001505 PWC_INFO("Philips PCA645VC USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 name = "Philips 645 webcam";
1507 type_id = 645;
1508 break;
1509 case 0x0303:
Luc Saillard2b455db2006-04-24 10:29:46 -03001510 PWC_INFO("Philips PCA646VC USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511 name = "Philips 646 webcam";
1512 type_id = 646;
1513 break;
1514 case 0x0304:
Luc Saillard2b455db2006-04-24 10:29:46 -03001515 PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 name = "Askey VC010 webcam";
1517 type_id = 646;
1518 break;
1519 case 0x0307:
Luc Saillard2b455db2006-04-24 10:29:46 -03001520 PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 name = "Philips 675 webcam";
1522 type_id = 675;
1523 break;
1524 case 0x0308:
Luc Saillard2b455db2006-04-24 10:29:46 -03001525 PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 name = "Philips 680 webcam";
1527 type_id = 680;
1528 break;
1529 case 0x030C:
Luc Saillard2b455db2006-04-24 10:29:46 -03001530 PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 name = "Philips 690 webcam";
1532 type_id = 690;
1533 break;
1534 case 0x0310:
Luc Saillard2b455db2006-04-24 10:29:46 -03001535 PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 name = "Philips 730 webcam";
1537 type_id = 730;
1538 break;
1539 case 0x0311:
Luc Saillard2b455db2006-04-24 10:29:46 -03001540 PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 name = "Philips 740 webcam";
1542 type_id = 740;
1543 break;
1544 case 0x0312:
Luc Saillard2b455db2006-04-24 10:29:46 -03001545 PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 name = "Philips 750 webcam";
1547 type_id = 750;
1548 break;
1549 case 0x0313:
Luc Saillard2b455db2006-04-24 10:29:46 -03001550 PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 name = "Philips 720K/40 webcam";
1552 type_id = 720;
1553 break;
Luc Saillard2b455db2006-04-24 10:29:46 -03001554 case 0x0329:
1555 PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
1556 name = "Philips SPC 900NC webcam";
Luc Saillard9ee6d782007-04-22 23:54:36 -03001557 type_id = 740;
Luc Saillard2b455db2006-04-24 10:29:46 -03001558 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559 default:
1560 return -ENODEV;
1561 break;
1562 }
1563 }
1564 else if (vendor_id == 0x069A) {
1565 switch(product_id) {
1566 case 0x0001:
Luc Saillard2b455db2006-04-24 10:29:46 -03001567 PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568 name = "Askey VC010 webcam";
1569 type_id = 645;
1570 break;
1571 default:
1572 return -ENODEV;
1573 break;
1574 }
1575 }
1576 else if (vendor_id == 0x046d) {
1577 switch(product_id) {
1578 case 0x08b0:
Luc Saillard2b455db2006-04-24 10:29:46 -03001579 PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580 name = "Logitech QuickCam Pro 3000";
1581 type_id = 740; /* CCD sensor */
1582 break;
1583 case 0x08b1:
Luc Saillard2b455db2006-04-24 10:29:46 -03001584 PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 name = "Logitech QuickCam Notebook Pro";
1586 type_id = 740; /* CCD sensor */
1587 break;
1588 case 0x08b2:
Luc Saillard2b455db2006-04-24 10:29:46 -03001589 PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001590 name = "Logitech QuickCam Pro 4000";
1591 type_id = 740; /* CCD sensor */
1592 break;
1593 case 0x08b3:
Luc Saillard2b455db2006-04-24 10:29:46 -03001594 PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595 name = "Logitech QuickCam Zoom";
1596 type_id = 740; /* CCD sensor */
1597 break;
1598 case 0x08B4:
Luc Saillard2b455db2006-04-24 10:29:46 -03001599 PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 name = "Logitech QuickCam Zoom";
1601 type_id = 740; /* CCD sensor */
Luc Saillard2b455db2006-04-24 10:29:46 -03001602 power_save = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 break;
1604 case 0x08b5:
Luc Saillard2b455db2006-04-24 10:29:46 -03001605 PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606 name = "Logitech QuickCam Orbit";
1607 type_id = 740; /* CCD sensor */
1608 features |= FEATURE_MOTOR_PANTILT;
1609 break;
1610 case 0x08b6:
Jean Tourrilhesa63e1572007-03-21 16:29:16 -03001611 PWC_INFO("Logitech/Cisco VT Camera webcam detected.\n");
1612 name = "Cisco VT Camera";
1613 type_id = 740; /* CCD sensor */
1614 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 case 0x08b7:
Mauro Carvalho Chehab6b1ce3c2007-03-21 16:35:28 -03001616 PWC_INFO("Logitech ViewPort AV 100 webcam detected.\n");
1617 name = "Logitech ViewPort AV 100";
1618 type_id = 740; /* CCD sensor */
1619 break;
1620 case 0x08b8: /* Where this released? */
Luc Saillard2b455db2006-04-24 10:29:46 -03001621 PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 name = "Logitech QuickCam (res.)";
1623 type_id = 730; /* Assuming CMOS */
1624 break;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001625 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 return -ENODEV;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001627 break;
1628 }
1629 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 else if (vendor_id == 0x055d) {
1631 /* I don't know the difference between the C10 and the C30;
1632 I suppose the difference is the sensor, but both cameras
1633 work equally well with a type_id of 675
1634 */
1635 switch(product_id) {
1636 case 0x9000:
Luc Saillard2b455db2006-04-24 10:29:46 -03001637 PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 name = "Samsung MPC-C10";
1639 type_id = 675;
1640 break;
1641 case 0x9001:
Luc Saillard2b455db2006-04-24 10:29:46 -03001642 PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 name = "Samsung MPC-C30";
1644 type_id = 675;
1645 break;
Luc Saillard2b455db2006-04-24 10:29:46 -03001646 case 0x9002:
1647 PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
1648 name = "Samsung MPC-C30";
1649 type_id = 740;
1650 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 default:
1652 return -ENODEV;
1653 break;
1654 }
1655 }
1656 else if (vendor_id == 0x041e) {
1657 switch(product_id) {
1658 case 0x400c:
Luc Saillard2b455db2006-04-24 10:29:46 -03001659 PWC_INFO("Creative Labs Webcam 5 detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 name = "Creative Labs Webcam 5";
1661 type_id = 730;
1662 break;
1663 case 0x4011:
Luc Saillard2b455db2006-04-24 10:29:46 -03001664 PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 name = "Creative Labs Webcam Pro Ex";
1666 type_id = 740;
1667 break;
1668 default:
1669 return -ENODEV;
1670 break;
1671 }
1672 }
1673 else if (vendor_id == 0x04cc) {
1674 switch(product_id) {
1675 case 0x8116:
Luc Saillard2b455db2006-04-24 10:29:46 -03001676 PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677 name = "Sotec Afina Eye";
1678 type_id = 730;
1679 break;
1680 default:
1681 return -ENODEV;
1682 break;
1683 }
1684 }
1685 else if (vendor_id == 0x06be) {
1686 switch(product_id) {
1687 case 0x8116:
1688 /* This is essentially the same cam as the Sotec Afina Eye */
Luc Saillard2b455db2006-04-24 10:29:46 -03001689 PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001690 name = "AME Co. Afina Eye";
1691 type_id = 750;
1692 break;
1693 default:
1694 return -ENODEV;
1695 break;
1696 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001697
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 }
1699 else if (vendor_id == 0x0d81) {
1700 switch(product_id) {
1701 case 0x1900:
Luc Saillard2b455db2006-04-24 10:29:46 -03001702 PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 name = "Visionite VCS-UC300";
1704 type_id = 740; /* CCD sensor */
1705 break;
1706 case 0x1910:
Luc Saillard2b455db2006-04-24 10:29:46 -03001707 PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708 name = "Visionite VCS-UM100";
1709 type_id = 730; /* CMOS sensor */
1710 break;
1711 default:
1712 return -ENODEV;
1713 break;
1714 }
1715 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001716 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001717 return -ENODEV; /* Not any of the know types; but the list keeps growing. */
1718
1719 memset(serial_number, 0, 30);
1720 usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
Luc Saillard2b455db2006-04-24 10:29:46 -03001721 PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001722
1723 if (udev->descriptor.bNumConfigurations > 1)
Luc Saillard2b455db2006-04-24 10:29:46 -03001724 PWC_WARNING("Warning: more than 1 configuration available.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725
1726 /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01001727 pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 if (pdev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001729 PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 return -ENOMEM;
1731 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001732 pdev->type = type_id;
1733 pdev->vsize = default_size;
1734 pdev->vframes = default_fps;
1735 strcpy(pdev->serial, serial_number);
1736 pdev->features = features;
1737 if (vendor_id == 0x046D && product_id == 0x08B5)
1738 {
1739 /* Logitech QuickCam Orbit
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001740 The ranges have been determined experimentally; they may differ from cam to cam.
1741 Also, the exact ranges left-right and up-down are different for my cam
1742 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 pdev->angle_range.pan_min = -7000;
1744 pdev->angle_range.pan_max = 7000;
1745 pdev->angle_range.tilt_min = -3000;
1746 pdev->angle_range.tilt_max = 2500;
1747 }
1748
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001749 mutex_init(&pdev->modlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 spin_lock_init(&pdev->ptrlock);
1751
1752 pdev->udev = udev;
1753 init_waitqueue_head(&pdev->frameq);
1754 pdev->vcompression = pwc_preferred_compression;
1755
1756 /* Allocate video_device structure */
1757 pdev->vdev = video_device_alloc();
Al Viro5fa12472008-03-29 03:07:38 +00001758 if (!pdev->vdev) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001759 PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 kfree(pdev);
1761 return -ENOMEM;
1762 }
1763 memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
Hans Verkuil5e85e732008-07-20 06:31:39 -03001764 pdev->vdev->parent = &(udev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 strcpy(pdev->vdev->name, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 video_set_drvdata(pdev->vdev, pdev);
1767
1768 pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
Luc Saillard2b455db2006-04-24 10:29:46 -03001769 PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770
1771 /* Now search device_hint[] table for a match, so we can hint a node number. */
1772 for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
1773 if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
1774 (device_hint[hint].pdev == NULL)) {
1775 /* so far, so good... try serial number */
1776 if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
Trent Piepho657de3c2006-06-20 00:30:57 -03001777 /* match! */
1778 video_nr = device_hint[hint].device_node;
1779 PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
1780 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001781 }
1782 }
1783 }
1784
1785 pdev->vdev->release = video_device_release;
1786 i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
1787 if (i < 0) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001788 PWC_ERROR("Failed to register as video device (%d).\n", i);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001789 rc = i;
1790 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001791 }
1792 else {
Hans Verkuilc6330fb2008-10-19 18:54:26 -03001793 PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 }
1795
1796 /* occupy slot */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001797 if (hint < MAX_DEV_HINTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798 device_hint[hint].pdev = pdev;
1799
Luc Saillard2b455db2006-04-24 10:29:46 -03001800 PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 usb_set_intfdata (intf, pdev);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001802 rc = pwc_create_sysfs_files(pdev->vdev);
1803 if (rc)
1804 goto err_unreg;
Luc Saillard2b455db2006-04-24 10:29:46 -03001805
1806 /* Set the leds off */
1807 pwc_set_leds(pdev, 0, 0);
1808 pwc_camera_power(pdev, 0);
1809
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810 return 0;
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001811
1812err_unreg:
1813 if (hint < MAX_DEV_HINTS)
1814 device_hint[hint].pdev = NULL;
1815 video_unregister_device(pdev->vdev);
1816err:
1817 video_device_release(pdev->vdev); /* Drip... drip... drip... */
1818 kfree(pdev); /* Oops, no memory leaks please */
1819 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820}
1821
1822/* The user janked out the cable... */
1823static void usb_pwc_disconnect(struct usb_interface *intf)
1824{
1825 struct pwc_device *pdev;
1826 int hint;
1827
1828 lock_kernel();
1829 pdev = usb_get_intfdata (intf);
1830 usb_set_intfdata (intf, NULL);
1831 if (pdev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001832 PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 goto disconnect_out;
1834 }
1835 if (pdev->udev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001836 PWC_ERROR("pwc_disconnect() already called for %p\n", pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837 goto disconnect_out;
1838 }
1839 if (pdev->udev != interface_to_usbdev(intf)) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001840 PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 goto disconnect_out;
1842 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001843
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 /* We got unplugged; this is signalled by an EPIPE error code */
1845 if (pdev->vopen) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001846 PWC_INFO("Disconnected while webcam is in use!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 pdev->error_status = EPIPE;
1848 }
1849
1850 /* Alert waiting processes */
1851 wake_up_interruptible(&pdev->frameq);
1852 /* Wait until device is closed */
Oliver Neukum85237f22007-08-21 07:10:42 +02001853 if(pdev->vopen) {
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001854 mutex_lock(&pdev->modlock);
Oliver Neukum85237f22007-08-21 07:10:42 +02001855 pdev->unplugged = 1;
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001856 mutex_unlock(&pdev->modlock);
1857 pwc_iso_stop(pdev);
Oliver Neukum85237f22007-08-21 07:10:42 +02001858 } else {
1859 /* Device is closed, so we can safely unregister it */
1860 PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
1861 pwc_cleanup(pdev);
1862 /* Free memory (don't set pdev to 0 just yet) */
1863 kfree(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001864
1865disconnect_out:
Oliver Neukum85237f22007-08-21 07:10:42 +02001866 /* search device_hint[] table if we occupy a slot, by any chance */
1867 for (hint = 0; hint < MAX_DEV_HINTS; hint++)
1868 if (device_hint[hint].pdev == pdev)
1869 device_hint[hint].pdev = NULL;
1870 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001871
1872 unlock_kernel();
1873}
1874
Linus Torvalds1da177e2005-04-16 15:20:36 -07001875/* *grunt* We have to do atoi ourselves :-( */
1876static int pwc_atoi(const char *s)
1877{
1878 int k = 0;
1879
1880 k = 0;
1881 while (*s != '\0' && *s >= '0' && *s <= '9') {
1882 k = 10 * k + (*s - '0');
1883 s++;
1884 }
1885 return k;
1886}
1887
1888
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001889/*
1890 * Initialization code & module stuff
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 */
1892
Luc Saillard2b455db2006-04-24 10:29:46 -03001893static char *size;
1894static int fps;
1895static int fbufs;
1896static int mbufs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897static int compression = -1;
1898static int leds[2] = { -1, -1 };
Al Viro64a6f952007-10-14 19:35:30 +01001899static unsigned int leds_nargs;
Luc Saillard2b455db2006-04-24 10:29:46 -03001900static char *dev_hint[MAX_DEV_HINTS];
Al Viro64a6f952007-10-14 19:35:30 +01001901static unsigned int dev_hint_nargs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902
Luc Saillard2b455db2006-04-24 10:29:46 -03001903module_param(size, charp, 0444);
1904module_param(fps, int, 0444);
1905module_param(fbufs, int, 0444);
1906module_param(mbufs, int, 0444);
Trent Piepho05ad3902007-01-30 23:26:01 -03001907#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -03001908module_param_named(trace, pwc_trace, int, 0644);
1909#endif
1910module_param(power_save, int, 0444);
1911module_param(compression, int, 0444);
1912module_param_array(leds, int, &leds_nargs, 0444);
1913module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
1914
Linus Torvalds1da177e2005-04-16 15:20:36 -07001915MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919MODULE_PARM_DESC(trace, "For debugging purposes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923MODULE_PARM_DESC(dev_hint, "Device node hints");
1924
1925MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
1926MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
1927MODULE_LICENSE("GPL");
Luc Saillard2b455db2006-04-24 10:29:46 -03001928MODULE_ALIAS("pwcx");
1929MODULE_VERSION( PWC_VERSION );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930
1931static int __init usb_pwc_init(void)
1932{
1933 int i, sz;
1934 char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
1935
Luc Saillard2b455db2006-04-24 10:29:46 -03001936 PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
1937 PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
1938 PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
1939 PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940
1941 if (fps) {
1942 if (fps < 4 || fps > 30) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001943 PWC_ERROR("Framerate out of bounds (4-30).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 return -EINVAL;
1945 }
1946 default_fps = fps;
Luc Saillard2b455db2006-04-24 10:29:46 -03001947 PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 }
1949
Luc Saillard2b455db2006-04-24 10:29:46 -03001950 if (size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 /* string; try matching with array */
1952 for (sz = 0; sz < PSZ_MAX; sz++) {
1953 if (!strcmp(sizenames[sz], size)) { /* Found! */
1954 default_size = sz;
1955 break;
1956 }
1957 }
1958 if (sz == PSZ_MAX) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001959 PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 return -EINVAL;
1961 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001962 PWC_DEBUG_MODULE("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 }
1964 if (mbufs) {
1965 if (mbufs < 1 || mbufs > MAX_IMAGES) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001966 PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 return -EINVAL;
1968 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001969 pwc_mbufs = mbufs;
1970 PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 }
1972 if (fbufs) {
1973 if (fbufs < 2 || fbufs > MAX_FRAMES) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001974 PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001975 return -EINVAL;
1976 }
1977 default_fbufs = fbufs;
Luc Saillard2b455db2006-04-24 10:29:46 -03001978 PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 }
Trent Piepho05ad3902007-01-30 23:26:01 -03001980#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -03001981 if (pwc_trace >= 0) {
1982 PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001983 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001984#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 if (compression >= 0) {
1986 if (compression > 3) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001987 PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 return -EINVAL;
1989 }
1990 pwc_preferred_compression = compression;
Luc Saillard2b455db2006-04-24 10:29:46 -03001991 PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 }
1993 if (power_save)
Luc Saillard2b455db2006-04-24 10:29:46 -03001994 PWC_DEBUG_MODULE("Enabling power save on open/close.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001995 if (leds[0] >= 0)
1996 led_on = leds[0];
1997 if (leds[1] >= 0)
1998 led_off = leds[1];
1999
Steven Cole093cf722005-05-03 19:07:24 -06002000 /* Big device node whoopla. Basically, it allows you to assign a
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 device node (/dev/videoX) to a camera, based on its type
2002 & serial number. The format is [type[.serialnumber]:]node.
2003
2004 Any camera that isn't matched by these rules gets the next
2005 available free device node.
2006 */
2007 for (i = 0; i < MAX_DEV_HINTS; i++) {
2008 char *s, *colon, *dot;
2009
2010 /* This loop also initializes the array */
2011 device_hint[i].pdev = NULL;
2012 s = dev_hint[i];
2013 if (s != NULL && *s != '\0') {
2014 device_hint[i].type = -1; /* wildcard */
2015 strcpy(device_hint[i].serial_number, "*");
2016
2017 /* parse string: chop at ':' & '/' */
2018 colon = dot = s;
2019 while (*colon != '\0' && *colon != ':')
2020 colon++;
2021 while (*dot != '\0' && *dot != '.')
2022 dot++;
2023 /* Few sanity checks */
2024 if (*dot != '\0' && dot > colon) {
Luc Saillard2b455db2006-04-24 10:29:46 -03002025 PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026 return -EINVAL;
2027 }
2028
2029 if (*colon == '\0') {
2030 /* No colon */
2031 if (*dot != '\0') {
Luc Saillard2b455db2006-04-24 10:29:46 -03002032 PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 return -EINVAL;
2034 }
2035 else {
2036 /* No type or serial number specified, just a number. */
2037 device_hint[i].device_node = pwc_atoi(s);
2038 }
2039 }
2040 else {
2041 /* There's a colon, so we have at least a type and a device node */
2042 device_hint[i].type = pwc_atoi(s);
2043 device_hint[i].device_node = pwc_atoi(colon + 1);
2044 if (*dot != '\0') {
2045 /* There's a serial number as well */
2046 int k;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03002047
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048 dot++;
2049 k = 0;
2050 while (*dot != ':' && k < 29) {
2051 device_hint[i].serial_number[k++] = *dot;
2052 dot++;
2053 }
2054 device_hint[i].serial_number[k] = '\0';
2055 }
2056 }
Luc Saillard2b455db2006-04-24 10:29:46 -03002057 PWC_TRACE("device_hint[%d]:\n", i);
2058 PWC_TRACE(" type : %d\n", device_hint[i].type);
2059 PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number);
2060 PWC_TRACE(" node : %d\n", device_hint[i].device_node);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 }
2062 else
2063 device_hint[i].type = 0; /* not filled */
2064 } /* ..for MAX_DEV_HINTS */
2065
Luc Saillard2b455db2006-04-24 10:29:46 -03002066 PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 return usb_register(&pwc_driver);
2068}
2069
2070static void __exit usb_pwc_exit(void)
2071{
Luc Saillard2b455db2006-04-24 10:29:46 -03002072 PWC_DEBUG_MODULE("Deregistering driver.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 usb_deregister(&pwc_driver);
Luc Saillard2b455db2006-04-24 10:29:46 -03002074 PWC_INFO("Philips webcam module removed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075}
2076
2077module_init(usb_pwc_init);
2078module_exit(usb_pwc_exit);
2079
Luc Saillard2b455db2006-04-24 10:29:46 -03002080/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */