blob: 315337bfd673ab508ff70f82bbe2505f0406ad5f [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>
Luc Saillard2b455db2006-04-24 10:29:46 -030065#include <linux/version.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070066#include <asm/io.h>
67
68#include "pwc.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070069#include "pwc-kiara.h"
70#include "pwc-timon.h"
Luc Saillard2b455db2006-04-24 10:29:46 -030071#include "pwc-dec23.h"
72#include "pwc-dec1.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#include "pwc-uncompress.h"
74
75/* Function prototypes and driver templates */
76
77/* hotplug device table support */
Luc Saillard2b455db2006-04-24 10:29:46 -030078static const struct usb_device_id pwc_device_table [] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
80 { USB_DEVICE(0x0471, 0x0303) },
81 { USB_DEVICE(0x0471, 0x0304) },
82 { USB_DEVICE(0x0471, 0x0307) },
83 { USB_DEVICE(0x0471, 0x0308) },
84 { USB_DEVICE(0x0471, 0x030C) },
85 { USB_DEVICE(0x0471, 0x0310) },
Luc Saillard2b455db2006-04-24 10:29:46 -030086 { USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 { USB_DEVICE(0x0471, 0x0312) },
88 { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
Luc Saillard2b455db2006-04-24 10:29:46 -030089 { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 { USB_DEVICE(0x069A, 0x0001) }, /* Askey */
91 { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
92 { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
93 { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */
94 { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */
95 { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */
96 { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */
Mauro Carvalho Chehab6b1ce3c2007-03-21 16:35:28 -030097 { USB_DEVICE(0x046D, 0x08B6) }, /* Cisco VT Camera */
98 { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech ViewPort AV 100 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
Luc Saillard2b455db2006-04-24 10:29:46 -0300100 { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */
101 { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
102 { USB_DEVICE(0x055D, 0x9002) }, /* Samsung SNC-35E (Ver3.0) */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
104 { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
105 { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
106 { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */
107 { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */
108 { USB_DEVICE(0x0d81, 0x1900) },
109 { }
110};
111MODULE_DEVICE_TABLE(usb, pwc_device_table);
112
113static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id);
114static void usb_pwc_disconnect(struct usb_interface *intf);
115
116static struct usb_driver pwc_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 .name = "Philips webcam", /* name */
118 .id_table = pwc_device_table,
119 .probe = usb_pwc_probe, /* probe() */
120 .disconnect = usb_pwc_disconnect, /* disconnect() */
121};
122
123#define MAX_DEV_HINTS 20
124#define MAX_ISOC_ERRORS 20
125
126static int default_size = PSZ_QCIF;
127static int default_fps = 10;
128static int default_fbufs = 3; /* Default number of frame buffers */
Michael Krufkyb930e1d2007-08-27 18:16:54 -0300129 int pwc_mbufs = 2; /* Default number of mmap() buffers */
Trent Piepho05ad3902007-01-30 23:26:01 -0300130#ifdef CONFIG_USB_PWC_DEBUG
Michael Krufkyb930e1d2007-08-27 18:16:54 -0300131 int pwc_trace = PWC_DEBUG_LEVEL;
Luc Saillard2b455db2006-04-24 10:29:46 -0300132#endif
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300133static int power_save;
134static int led_on = 100, led_off; /* defaults to LED that is on while in use */
Adrian Bunkb20c3cf2006-06-23 06:49:34 -0300135static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136static struct {
137 int type;
138 char serial_number[30];
139 int device_node;
140 struct pwc_device *pdev;
141} device_hint[MAX_DEV_HINTS];
142
143/***/
144
Hans Verkuilbec43662008-12-30 06:58:20 -0300145static int pwc_video_open(struct file *file);
146static int pwc_video_close(struct file *file);
Luc Saillard2b455db2006-04-24 10:29:46 -0300147static ssize_t pwc_video_read(struct file *file, char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 size_t count, loff_t *ppos);
149static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
Hans Verkuilbec43662008-12-30 06:58:20 -0300150static int pwc_video_ioctl(struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 unsigned int ioctlnr, unsigned long arg);
152static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma);
153
Hans Verkuilbec43662008-12-30 06:58:20 -0300154static const struct v4l2_file_operations pwc_fops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 .owner = THIS_MODULE,
156 .open = pwc_video_open,
157 .release = pwc_video_close,
158 .read = pwc_video_read,
159 .poll = pwc_video_poll,
160 .mmap = pwc_video_mmap,
161 .ioctl = pwc_video_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162};
163static struct video_device pwc_template = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 .name = "Philips Webcam", /* Filled in later */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 .release = video_device_release,
166 .fops = &pwc_fops,
167 .minor = -1,
168};
169
170/***************************************************************************/
171
172/* Okay, this is some magic that I worked out and the reasoning behind it...
173
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300174 The biggest problem with any USB device is of course: "what to do
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 when the user unplugs the device while it is in use by an application?"
176 We have several options:
177 1) Curse them with the 7 plagues when they do (requires divine intervention)
178 2) Tell them not to (won't work: they'll do it anyway)
179 3) Oops the kernel (this will have a negative effect on a user's uptime)
180 4) Do something sensible.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300181
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 Of course, we go for option 4.
183
184 It happens that this device will be linked to two times, once from
185 usb_device and once from the video_device in their respective 'private'
186 pointers. This is done when the device is probed() and all initialization
187 succeeded. The pwc_device struct links back to both structures.
188
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300189 When a device is unplugged while in use it will be removed from the
190 list of known USB devices; I also de-register it as a V4L device, but
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 unfortunately I can't free the memory since the struct is still in use
192 by the file descriptor. This free-ing is then deferend until the first
193 opportunity. Crude, but it works.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300194
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 A small 'advantage' is that if a user unplugs the cam and plugs it back
196 in, it should get assigned the same video device minor, but unfortunately
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300197 it's non-trivial to re-link the cam back to the video device... (that
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 would surely be magic! :))
199*/
200
201/***************************************************************************/
202/* Private functions */
203
204/* Here we want the physical address of the memory.
205 * This is used when initializing the contents of the area.
206 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
Luc Saillard2b455db2006-04-24 10:29:46 -0300209
210static void *pwc_rvmalloc(unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211{
212 void * mem;
213 unsigned long adr;
214
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300215 mem=vmalloc_32(size);
Luc Saillard2b455db2006-04-24 10:29:46 -0300216 if (!mem)
217 return NULL;
218
219 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
220 adr=(unsigned long) mem;
221 while (size > 0)
222 {
223 SetPageReserved(vmalloc_to_page((void *)adr));
224 adr += PAGE_SIZE;
225 size -= PAGE_SIZE;
226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 return mem;
228}
229
Luc Saillard2b455db2006-04-24 10:29:46 -0300230static void pwc_rvfree(void * mem, unsigned long size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231{
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300232 unsigned long adr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
Luc Saillard2b455db2006-04-24 10:29:46 -0300234 if (!mem)
235 return;
236
237 adr=(unsigned long) mem;
238 while ((long) size > 0)
239 {
240 ClearPageReserved(vmalloc_to_page((void *)adr));
241 adr += PAGE_SIZE;
242 size -= PAGE_SIZE;
243 }
244 vfree(mem);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245}
246
247
248
249
250static int pwc_allocate_buffers(struct pwc_device *pdev)
251{
Luc Saillard2b455db2006-04-24 10:29:46 -0300252 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 void *kbuf;
254
Luc Saillard2b455db2006-04-24 10:29:46 -0300255 PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
257 if (pdev == NULL)
258 return -ENXIO;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300259
Luc Saillard2b455db2006-04-24 10:29:46 -0300260 /* Allocate Isochronuous pipe buffers */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 for (i = 0; i < MAX_ISO_BUFS; i++) {
262 if (pdev->sbuf[i].data == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300263 kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 if (kbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300265 PWC_ERROR("Failed to allocate iso buffer %d.\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 return -ENOMEM;
267 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300268 PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 pdev->sbuf[i].data = kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 }
271 }
272
273 /* Allocate frame buffer structure */
274 if (pdev->fbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300275 kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 if (kbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300277 PWC_ERROR("Failed to allocate frame buffer structure.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 return -ENOMEM;
279 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300280 PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 pdev->fbuf = kbuf;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300283
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 /* create frame buffers, and make circular ring */
285 for (i = 0; i < default_fbufs; i++) {
286 if (pdev->fbuf[i].data == NULL) {
287 kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
288 if (kbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300289 PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 return -ENOMEM;
291 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300292 PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 pdev->fbuf[i].data = kbuf;
Luc Saillard2b455db2006-04-24 10:29:46 -0300294 memset(kbuf, 0, PWC_FRAME_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 }
296 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300297
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 /* Allocate decompressor table space */
Luc Saillard2b455db2006-04-24 10:29:46 -0300299 if (DEVICE_USE_CODEC1(pdev->type))
300 err = pwc_dec1_alloc(pdev);
301 else
302 err = pwc_dec23_alloc(pdev);
303
304 if (err) {
305 PWC_ERROR("Failed to allocate decompress table.\n");
306 return err;
307 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300308
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 /* Allocate image buffer; double buffer for mmap() */
Luc Saillard2b455db2006-04-24 10:29:46 -0300310 kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 if (kbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300312 PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n",
313 pwc_mbufs * pdev->len_per_image);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 return -ENOMEM;
315 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300316 PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 pdev->image_data = kbuf;
Luc Saillard2b455db2006-04-24 10:29:46 -0300318 for (i = 0; i < pwc_mbufs; i++) {
319 pdev->images[i].offset = i * pdev->len_per_image;
320 pdev->images[i].vma_use_count = 0;
321 }
322 for (; i < MAX_IMAGES; i++) {
323 pdev->images[i].offset = 0;
324 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 kbuf = NULL;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300327
Luc Saillard2b455db2006-04-24 10:29:46 -0300328 PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 return 0;
330}
331
332static void pwc_free_buffers(struct pwc_device *pdev)
333{
334 int i;
335
Luc Saillard2b455db2006-04-24 10:29:46 -0300336 PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
338 if (pdev == NULL)
339 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 /* Release Iso-pipe buffers */
341 for (i = 0; i < MAX_ISO_BUFS; i++)
342 if (pdev->sbuf[i].data != NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300343 PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 kfree(pdev->sbuf[i].data);
345 pdev->sbuf[i].data = NULL;
346 }
347
348 /* The same for frame buffers */
349 if (pdev->fbuf != NULL) {
350 for (i = 0; i < default_fbufs; i++) {
351 if (pdev->fbuf[i].data != NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300352 PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 vfree(pdev->fbuf[i].data);
354 pdev->fbuf[i].data = NULL;
355 }
356 }
357 kfree(pdev->fbuf);
358 pdev->fbuf = NULL;
359 }
360
361 /* Intermediate decompression buffer & tables */
362 if (pdev->decompress_data != NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300363 PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 kfree(pdev->decompress_data);
365 pdev->decompress_data = NULL;
366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367
368 /* Release image buffers */
369 if (pdev->image_data != NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300370 PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data);
371 pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 }
373 pdev->image_data = NULL;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300374
Luc Saillard2b455db2006-04-24 10:29:46 -0300375 PWC_DEBUG_MEMORY("Leaving free_buffers().\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376}
377
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300378/* The frame & image buffer mess.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379
380 Yes, this is a mess. Well, it used to be simple, but alas... In this
381 module, 3 buffers schemes are used to get the data from the USB bus to
382 the user program. The first scheme involves the ISO buffers (called thus
383 since they transport ISO data from the USB controller), and not really
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300384 interesting. Suffices to say the data from this buffer is quickly
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 gathered in an interrupt handler (pwc_isoc_handler) and placed into the
386 frame buffer.
387
388 The frame buffer is the second scheme, and is the central element here.
389 It collects the data from a single frame from the camera (hence, the
390 name). Frames are delimited by the USB camera with a short USB packet,
391 so that's easy to detect. The frame buffers form a list that is filled
392 by the camera+USB controller and drained by the user process through
393 either read() or mmap().
394
395 The image buffer is the third scheme, in which frames are decompressed
396 and converted into planar format. For mmap() there is more than
397 one image buffer available.
398
399 The frame buffers provide the image buffering. In case the user process
400 is a bit slow, this introduces lag and some undesired side-effects.
401 The problem arises when the frame buffer is full. I used to drop the last
402 frame, which makes the data in the queue stale very quickly. But dropping
403 the frame at the head of the queue proved to be a litte bit more difficult.
404 I tried a circular linked scheme, but this introduced more problems than
405 it solved.
406
407 Because filling and draining are completely asynchronous processes, this
408 requires some fiddling with pointers and mutexes.
409
410 Eventually, I came up with a system with 2 lists: an 'empty' frame list
411 and a 'full' frame list:
412 * Initially, all frame buffers but one are on the 'empty' list; the one
413 remaining buffer is our initial fill frame.
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300414 * If a frame is needed for filling, we try to take it from the 'empty'
415 list, unless that list is empty, in which case we take the buffer at
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 the head of the 'full' list.
417 * When our fill buffer has been filled, it is appended to the 'full'
418 list.
419 * If a frame is needed by read() or mmap(), it is taken from the head of
420 the 'full' list, handled, and then appended to the 'empty' list. If no
421 buffer is present on the 'full' list, we wait.
422 The advantage is that the buffer that is currently being decompressed/
423 converted, is on neither list, and thus not in our way (any other scheme
424 I tried had the problem of old data lingering in the queue).
425
426 Whatever strategy you choose, it always remains a tradeoff: with more
427 frame buffers the chances of a missed frame are reduced. On the other
428 hand, on slower machines it introduces lag because the queue will
429 always be full.
430 */
431
432/**
433 \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
434 */
Luc Saillard2b455db2006-04-24 10:29:46 -0300435static int pwc_next_fill_frame(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436{
437 int ret;
438 unsigned long flags;
439
440 ret = 0;
441 spin_lock_irqsave(&pdev->ptrlock, flags);
442 if (pdev->fill_frame != NULL) {
443 /* append to 'full' list */
444 if (pdev->full_frames == NULL) {
445 pdev->full_frames = pdev->fill_frame;
446 pdev->full_frames_tail = pdev->full_frames;
447 }
448 else {
449 pdev->full_frames_tail->next = pdev->fill_frame;
450 pdev->full_frames_tail = pdev->fill_frame;
451 }
452 }
453 if (pdev->empty_frames != NULL) {
454 /* We have empty frames available. That's easy */
455 pdev->fill_frame = pdev->empty_frames;
456 pdev->empty_frames = pdev->empty_frames->next;
457 }
458 else {
459 /* Hmm. Take it from the full list */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 /* sanity check */
461 if (pdev->full_frames == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300462 PWC_ERROR("Neither empty or full frames available!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463 spin_unlock_irqrestore(&pdev->ptrlock, flags);
464 return -EINVAL;
465 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466 pdev->fill_frame = pdev->full_frames;
467 pdev->full_frames = pdev->full_frames->next;
468 ret = 1;
469 }
470 pdev->fill_frame->next = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 spin_unlock_irqrestore(&pdev->ptrlock, flags);
472 return ret;
473}
474
475
476/**
477 \brief Reset all buffers, pointers and lists, except for the image_used[] buffer.
478
479 If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble.
480 */
481static void pwc_reset_buffers(struct pwc_device *pdev)
482{
483 int i;
484 unsigned long flags;
485
Harvey Harrison645635b2008-04-08 23:20:00 -0300486 PWC_DEBUG_MEMORY(">> %s __enter__\n", __func__);
Luc Saillard2b455db2006-04-24 10:29:46 -0300487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 spin_lock_irqsave(&pdev->ptrlock, flags);
489 pdev->full_frames = NULL;
490 pdev->full_frames_tail = NULL;
491 for (i = 0; i < default_fbufs; i++) {
492 pdev->fbuf[i].filled = 0;
493 if (i > 0)
494 pdev->fbuf[i].next = &pdev->fbuf[i - 1];
495 else
496 pdev->fbuf->next = NULL;
497 }
498 pdev->empty_frames = &pdev->fbuf[default_fbufs - 1];
499 pdev->empty_frames_tail = pdev->fbuf;
500 pdev->read_frame = NULL;
501 pdev->fill_frame = pdev->empty_frames;
502 pdev->empty_frames = pdev->empty_frames->next;
503
504 pdev->image_read_pos = 0;
505 pdev->fill_image = 0;
506 spin_unlock_irqrestore(&pdev->ptrlock, flags);
Luc Saillard2b455db2006-04-24 10:29:46 -0300507
Harvey Harrison645635b2008-04-08 23:20:00 -0300508 PWC_DEBUG_MEMORY("<< %s __leaving__\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509}
510
511
512/**
513 \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
514 */
Luc Saillard2b455db2006-04-24 10:29:46 -0300515int pwc_handle_frame(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
517 int ret = 0;
518 unsigned long flags;
519
520 spin_lock_irqsave(&pdev->ptrlock, flags);
521 /* First grab our read_frame; this is removed from all lists, so
522 we can release the lock after this without problems */
523 if (pdev->read_frame != NULL) {
524 /* This can't theoretically happen */
Luc Saillard2b455db2006-04-24 10:29:46 -0300525 PWC_ERROR("Huh? Read frame still in use?\n");
526 spin_unlock_irqrestore(&pdev->ptrlock, flags);
527 return ret;
528 }
529
530
531 if (pdev->full_frames == NULL) {
532 PWC_ERROR("Woops. No frames ready.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 }
534 else {
Luc Saillard2b455db2006-04-24 10:29:46 -0300535 pdev->read_frame = pdev->full_frames;
536 pdev->full_frames = pdev->full_frames->next;
537 pdev->read_frame->next = NULL;
538 }
539
540 if (pdev->read_frame != NULL) {
Paulius Zaleckasefad798b2008-02-03 15:42:53 +0200541 /* Decompression is a lengthy process, so it's outside of the lock.
Luc Saillard2b455db2006-04-24 10:29:46 -0300542 This gives the isoc_handler the opportunity to fill more frames
543 in the mean time.
544 */
545 spin_unlock_irqrestore(&pdev->ptrlock, flags);
546 ret = pwc_decompress(pdev);
547 spin_lock_irqsave(&pdev->ptrlock, flags);
548
549 /* We're done with read_buffer, tack it to the end of the empty buffer list */
550 if (pdev->empty_frames == NULL) {
551 pdev->empty_frames = pdev->read_frame;
552 pdev->empty_frames_tail = pdev->empty_frames;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 }
554 else {
Luc Saillard2b455db2006-04-24 10:29:46 -0300555 pdev->empty_frames_tail->next = pdev->read_frame;
556 pdev->empty_frames_tail = pdev->read_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300558 pdev->read_frame = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 }
560 spin_unlock_irqrestore(&pdev->ptrlock, flags);
561 return ret;
562}
563
564/**
565 \brief Advance pointers of image buffer (after each user request)
566*/
Luc Saillard2b455db2006-04-24 10:29:46 -0300567void pwc_next_image(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568{
569 pdev->image_used[pdev->fill_image] = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300570 pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571}
572
Luc Saillard2b455db2006-04-24 10:29:46 -0300573/**
574 * Print debug information when a frame is discarded because all of our buffer
575 * is full
576 */
577static void pwc_frame_dumped(struct pwc_device *pdev)
578{
579 pdev->vframes_dumped++;
580 if (pdev->vframe_count < FRAME_LOWMARK)
581 return;
582
583 if (pdev->vframes_dumped < 20)
584 PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count);
585 else if (pdev->vframes_dumped == 20)
586 PWC_DEBUG_FLOW("Dumping frame %d (last message)\n",
587 pdev->vframe_count);
588}
589
590static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
591{
592 int awake = 0;
593
594 /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
595 frames on the USB wire after an exposure change. This conditition is
596 however detected in the cam and a bit is set in the header.
597 */
598 if (pdev->type == 730) {
599 unsigned char *ptr = (unsigned char *)fbuf->data;
600
601 if (ptr[1] == 1 && ptr[0] & 0x10) {
602 PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
603 pdev->drop_frames += 2;
604 pdev->vframes_error++;
605 }
606 if ((ptr[0] ^ pdev->vmirror) & 0x01) {
607 if (ptr[0] & 0x01) {
608 pdev->snapshot_button_status = 1;
609 PWC_TRACE("Snapshot button pressed.\n");
610 }
611 else {
612 PWC_TRACE("Snapshot button released.\n");
613 }
614 }
615 if ((ptr[0] ^ pdev->vmirror) & 0x02) {
616 if (ptr[0] & 0x02)
617 PWC_TRACE("Image is mirrored.\n");
618 else
619 PWC_TRACE("Image is normal.\n");
620 }
621 pdev->vmirror = ptr[0] & 0x03;
622 /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
623 after a short frame; this condition is filtered out specifically. A 4 byte
624 frame doesn't make sense anyway.
625 So we get either this sequence:
626 drop_bit set -> 4 byte frame -> short frame -> good frame
627 Or this one:
628 drop_bit set -> short frame -> good frame
629 So we drop either 3 or 2 frames in all!
630 */
631 if (fbuf->filled == 4)
632 pdev->drop_frames++;
633 }
634 else if (pdev->type == 740 || pdev->type == 720) {
635 unsigned char *ptr = (unsigned char *)fbuf->data;
636 if ((ptr[0] ^ pdev->vmirror) & 0x01) {
637 if (ptr[0] & 0x01) {
638 pdev->snapshot_button_status = 1;
639 PWC_TRACE("Snapshot button pressed.\n");
640 }
641 else
642 PWC_TRACE("Snapshot button released.\n");
643 }
644 pdev->vmirror = ptr[0] & 0x03;
645 }
646
647 /* In case we were instructed to drop the frame, do so silently.
648 The buffer pointers are not updated either (but the counters are reset below).
649 */
650 if (pdev->drop_frames > 0)
651 pdev->drop_frames--;
652 else {
653 /* Check for underflow first */
654 if (fbuf->filled < pdev->frame_total_size) {
655 PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
656 " discarded.\n", fbuf->filled);
657 pdev->vframes_error++;
658 }
659 else {
660 /* Send only once per EOF */
661 awake = 1; /* delay wake_ups */
662
663 /* Find our next frame to fill. This will always succeed, since we
664 * nick a frame from either empty or full list, but if we had to
665 * take it from the full list, it means a frame got dropped.
666 */
667 if (pwc_next_fill_frame(pdev))
668 pwc_frame_dumped(pdev);
669
670 }
671 } /* !drop_frames */
672 pdev->vframe_count++;
673 return awake;
674}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
676/* This gets called for the Isochronous pipe (video). This is done in
677 * interrupt time, so it has to be fast, not crash, and not stall. Neat.
678 */
David Howells7d12e782006-10-05 14:55:46 +0100679static void pwc_isoc_handler(struct urb *urb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680{
681 struct pwc_device *pdev;
682 int i, fst, flen;
683 int awake;
684 struct pwc_frame_buf *fbuf;
685 unsigned char *fillptr = NULL, *iso_buf = NULL;
686
687 awake = 0;
688 pdev = (struct pwc_device *)urb->context;
689 if (pdev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300690 PWC_ERROR("isoc_handler() called with NULL device?!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 return;
692 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300695 PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 return;
697 }
698 if (urb->status != -EINPROGRESS && urb->status != 0) {
699 const char *errmsg;
700
701 errmsg = "Unknown";
702 switch(urb->status) {
703 case -ENOSR: errmsg = "Buffer error (overrun)"; break;
704 case -EPIPE: errmsg = "Stalled (device not responding)"; break;
705 case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break;
706 case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break;
707 case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break;
Pete Zaitcev38e2bfc2006-09-18 22:49:02 -0700708 case -ETIME: errmsg = "Device does not respond"; break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300710 PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300711 /* Give up after a number of contiguous errors on the USB bus.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 Appearantly something is wrong so we simulate an unplug event.
713 */
714 if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
715 {
Luc Saillard2b455db2006-04-24 10:29:46 -0300716 PWC_INFO("Too many ISOC errors, bailing out.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 pdev->error_status = EIO;
718 awake = 1;
719 wake_up_interruptible(&pdev->frameq);
720 }
721 goto handler_end; // ugly, but practical
722 }
723
724 fbuf = pdev->fill_frame;
725 if (fbuf == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300726 PWC_ERROR("pwc_isoc_handler without valid fill frame.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 awake = 1;
728 goto handler_end;
729 }
730 else {
731 fillptr = fbuf->data + fbuf->filled;
732 }
733
734 /* Reset ISOC error counter. We did get here, after all. */
735 pdev->visoc_errors = 0;
736
737 /* vsync: 0 = don't copy data
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300738 1 = sync-hunt
739 2 = synched
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 */
741 /* Compact data */
742 for (i = 0; i < urb->number_of_packets; i++) {
743 fst = urb->iso_frame_desc[i].status;
744 flen = urb->iso_frame_desc[i].actual_length;
745 iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
746 if (fst == 0) {
747 if (flen > 0) { /* if valid data... */
748 if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */
749 pdev->vsync = 2;
750
751 /* ...copy data to frame buffer, if possible */
752 if (flen + fbuf->filled > pdev->frame_total_size) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300753 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 -0700754 pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
755 pdev->vframes_error++;
756 }
757 else {
758 memmove(fillptr, iso_buf, flen);
759 fillptr += flen;
760 }
761 }
762 fbuf->filled += flen;
763 } /* ..flen > 0 */
764
765 if (flen < pdev->vlast_packet_size) {
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300766 /* Shorter packet... We probably have the end of an image-frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 wake up read() process and let select()/poll() do something.
768 Decompression is done in user time over there.
Luc Saillard2b455db2006-04-24 10:29:46 -0300769 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (pdev->vsync == 2) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300771 if (pwc_rcv_short_packet(pdev, fbuf)) {
772 awake = 1;
773 fbuf = pdev->fill_frame;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 }
776 fbuf->filled = 0;
777 fillptr = fbuf->data;
778 pdev->vsync = 1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300779 }
780
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 pdev->vlast_packet_size = flen;
782 } /* ..status == 0 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 else {
Luc Saillard2b455db2006-04-24 10:29:46 -0300784 /* This is normally not interesting to the user, unless
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -0300785 * you are really debugging something, default = 0 */
786 static int iso_error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 iso_error++;
788 if (iso_error < 20)
Luc Saillard2b455db2006-04-24 10:29:46 -0300789 PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 }
792
793handler_end:
794 if (awake)
795 wake_up_interruptible(&pdev->frameq);
796
797 urb->dev = pdev->udev;
798 i = usb_submit_urb(urb, GFP_ATOMIC);
799 if (i != 0)
Luc Saillard2b455db2006-04-24 10:29:46 -0300800 PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801}
802
803
Luc Saillard2b455db2006-04-24 10:29:46 -0300804int pwc_isoc_init(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805{
806 struct usb_device *udev;
807 struct urb *urb;
808 int i, j, ret;
809
810 struct usb_interface *intf;
811 struct usb_host_interface *idesc = NULL;
812
813 if (pdev == NULL)
814 return -EFAULT;
815 if (pdev->iso_init)
816 return 0;
817 pdev->vsync = 0;
818 udev = pdev->udev;
819
820 /* Get the current alternate interface, adjust packet size */
821 if (!udev->actconfig)
822 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 intf = usb_ifnum_to_if(udev, 0);
824 if (intf)
825 idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300826
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 if (!idesc)
828 return -EFAULT;
829
830 /* Search video endpoint */
831 pdev->vmax_packet_size = -1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300832 for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
834 pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
835 break;
836 }
Luc Saillard2b455db2006-04-24 10:29:46 -0300837 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300838
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300840 PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");
Steven Cole093cf722005-05-03 19:07:24 -0600841 return -ENFILE; /* Odd error, that should be noticeable */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 }
843
844 /* Set alternate interface */
845 ret = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300846 PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
848 if (ret < 0)
849 return ret;
850
851 for (i = 0; i < MAX_ISO_BUFS; i++) {
852 urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
853 if (urb == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300854 PWC_ERROR("Failed to allocate urb %d\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 ret = -ENOMEM;
856 break;
857 }
858 pdev->sbuf[i].urb = urb;
Luc Saillard2b455db2006-04-24 10:29:46 -0300859 PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 }
861 if (ret) {
862 /* De-allocate in reverse order */
Mariusz Kozlowski444f4f92006-11-16 16:38:57 +0100863 while (i--) {
Mariusz Kozlowski90b26252006-11-08 15:34:55 +0100864 usb_free_urb(pdev->sbuf[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 pdev->sbuf[i].urb = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 }
867 return ret;
868 }
869
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300870 /* init URB structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 for (i = 0; i < MAX_ISO_BUFS; i++) {
872 urb = pdev->sbuf[i].urb;
873
874 urb->interval = 1; // devik
875 urb->dev = udev;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300876 urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 urb->transfer_flags = URB_ISO_ASAP;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300878 urb->transfer_buffer = pdev->sbuf[i].data;
879 urb->transfer_buffer_length = ISO_BUFFER_SIZE;
880 urb->complete = pwc_isoc_handler;
881 urb->context = pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 urb->start_frame = 0;
883 urb->number_of_packets = ISO_FRAMES_PER_DESC;
884 for (j = 0; j < ISO_FRAMES_PER_DESC; j++) {
885 urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE;
886 urb->iso_frame_desc[j].length = pdev->vmax_packet_size;
887 }
888 }
889
890 /* link */
891 for (i = 0; i < MAX_ISO_BUFS; i++) {
892 ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
893 if (ret)
Luc Saillard2b455db2006-04-24 10:29:46 -0300894 PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 else
Luc Saillard2b455db2006-04-24 10:29:46 -0300896 PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 }
898
899 /* All is done... */
900 pdev->iso_init = 1;
Luc Saillard2b455db2006-04-24 10:29:46 -0300901 PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 return 0;
903}
904
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300905static void pwc_iso_stop(struct pwc_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906{
907 int i;
908
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 /* Unlinking ISOC buffers one by one */
910 for (i = 0; i < MAX_ISO_BUFS; i++) {
911 struct urb *urb;
912
913 urb = pdev->sbuf[i].urb;
Al Viro5fa12472008-03-29 03:07:38 +0000914 if (urb) {
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300915 PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
916 usb_kill_urb(urb);
917 }
918 }
919}
920
921static void pwc_iso_free(struct pwc_device *pdev)
922{
923 int i;
924
925 /* Freeing ISOC buffers one by one */
926 for (i = 0; i < MAX_ISO_BUFS; i++) {
927 struct urb *urb;
928
929 urb = pdev->sbuf[i].urb;
Al Viro5fa12472008-03-29 03:07:38 +0000930 if (urb) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300931 PWC_DEBUG_MEMORY("Freeing URB\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 usb_free_urb(urb);
933 pdev->sbuf[i].urb = NULL;
934 }
935 }
Oliver Neukum0b67f5c2007-09-26 10:19:01 -0300936}
937
938void pwc_isoc_cleanup(struct pwc_device *pdev)
939{
940 PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
941 if (pdev == NULL)
942 return;
943 if (pdev->iso_init == 0)
944 return;
945
946 pwc_iso_stop(pdev);
947 pwc_iso_free(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
949 /* Stop camera, but only if we are sure the camera is still there (unplug
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300950 is signalled by EPIPE)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 */
952 if (pdev->error_status && pdev->error_status != EPIPE) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300953 PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 usb_set_interface(pdev->udev, 0, 0);
955 }
956
957 pdev->iso_init = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -0300958 PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959}
960
961int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
962{
963 int ret, start;
964
965 /* Stop isoc stuff */
966 pwc_isoc_cleanup(pdev);
967 /* Reset parameters */
968 pwc_reset_buffers(pdev);
969 /* Try to set video mode... */
970 start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -0300971 if (ret) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300972 PWC_DEBUG_FLOW("pwc_set_video_mode attempt 1 failed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 /* That failed... restore old mode (we know that worked) */
974 start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
975 if (start) {
Luc Saillard2b455db2006-04-24 10:29:46 -0300976 PWC_DEBUG_FLOW("pwc_set_video_mode attempt 2 failed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977 }
978 }
979 if (start == 0)
980 {
981 if (pwc_isoc_init(pdev) < 0)
982 {
Luc Saillard2b455db2006-04-24 10:29:46 -0300983 PWC_WARNING("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 ret = -EAGAIN; /* let's try again, who knows if it works a second time */
985 }
986 }
987 pdev->drop_frames++; /* try to avoid garbage during switch */
988 return ret; /* Return original error code */
989}
990
Luc Saillard2b455db2006-04-24 10:29:46 -0300991/*********
992 * sysfs
993 *********/
Kay Sievers54bd5b62007-10-08 16:26:13 -0300994static struct pwc_device *cd_to_pwc(struct device *cd)
Luc Saillard2b455db2006-04-24 10:29:46 -0300995{
996 struct video_device *vdev = to_video_device(cd);
997 return video_get_drvdata(vdev);
998}
999
Kay Sievers54bd5b62007-10-08 16:26:13 -03001000static ssize_t show_pan_tilt(struct device *class_dev,
1001 struct device_attribute *attr, char *buf)
Luc Saillard2b455db2006-04-24 10:29:46 -03001002{
1003 struct pwc_device *pdev = cd_to_pwc(class_dev);
1004 return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
1005}
1006
Kay Sievers54bd5b62007-10-08 16:26:13 -03001007static ssize_t store_pan_tilt(struct device *class_dev,
1008 struct device_attribute *attr,
1009 const char *buf, size_t count)
Luc Saillard2b455db2006-04-24 10:29:46 -03001010{
1011 struct pwc_device *pdev = cd_to_pwc(class_dev);
1012 int pan, tilt;
1013 int ret = -EINVAL;
1014
1015 if (strncmp(buf, "reset", 5) == 0)
1016 ret = pwc_mpt_reset(pdev, 0x3);
1017
1018 else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
1019 ret = pwc_mpt_set_angle(pdev, pan, tilt);
1020
1021 if (ret < 0)
1022 return ret;
1023 return strlen(buf);
1024}
Kay Sievers54bd5b62007-10-08 16:26:13 -03001025static DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
1026 store_pan_tilt);
Luc Saillard2b455db2006-04-24 10:29:46 -03001027
Kay Sievers54bd5b62007-10-08 16:26:13 -03001028static ssize_t show_snapshot_button_status(struct device *class_dev,
1029 struct device_attribute *attr, char *buf)
Luc Saillard2b455db2006-04-24 10:29:46 -03001030{
1031 struct pwc_device *pdev = cd_to_pwc(class_dev);
1032 int status = pdev->snapshot_button_status;
1033 pdev->snapshot_button_status = 0;
1034 return sprintf(buf, "%d\n", status);
1035}
1036
Kay Sievers54bd5b62007-10-08 16:26:13 -03001037static DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
1038 NULL);
Luc Saillard2b455db2006-04-24 10:29:46 -03001039
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001040static int pwc_create_sysfs_files(struct video_device *vdev)
Luc Saillard2b455db2006-04-24 10:29:46 -03001041{
1042 struct pwc_device *pdev = video_get_drvdata(vdev);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001043 int rc;
1044
Hans Verkuilf894dfd2008-07-25 07:39:54 -03001045 rc = device_create_file(&vdev->dev, &dev_attr_button);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001046 if (rc)
1047 goto err;
1048 if (pdev->features & FEATURE_MOTOR_PANTILT) {
Hans Verkuilf894dfd2008-07-25 07:39:54 -03001049 rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001050 if (rc) goto err_button;
1051 }
1052
1053 return 0;
1054
1055err_button:
Hans Verkuilf894dfd2008-07-25 07:39:54 -03001056 device_remove_file(&vdev->dev, &dev_attr_button);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001057err:
Hans Verkuilf894dfd2008-07-25 07:39:54 -03001058 PWC_ERROR("Could not create sysfs files.\n");
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001059 return rc;
Luc Saillard2b455db2006-04-24 10:29:46 -03001060}
1061
1062static void pwc_remove_sysfs_files(struct video_device *vdev)
1063{
1064 struct pwc_device *pdev = video_get_drvdata(vdev);
1065 if (pdev->features & FEATURE_MOTOR_PANTILT)
Hans Verkuilf894dfd2008-07-25 07:39:54 -03001066 device_remove_file(&vdev->dev, &dev_attr_pan_tilt);
1067 device_remove_file(&vdev->dev, &dev_attr_button);
Luc Saillard2b455db2006-04-24 10:29:46 -03001068}
1069
Trent Piepho05ad3902007-01-30 23:26:01 -03001070#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -03001071static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
1072{
1073 switch(sensor_type) {
1074 case 0x00:
1075 return "Hyundai CMOS sensor";
1076 case 0x20:
1077 return "Sony CCD sensor + TDA8787";
1078 case 0x2E:
1079 return "Sony CCD sensor + Exas 98L59";
1080 case 0x2F:
1081 return "Sony CCD sensor + ADI 9804";
1082 case 0x30:
1083 return "Sharp CCD sensor + TDA8787";
1084 case 0x3E:
1085 return "Sharp CCD sensor + Exas 98L59";
1086 case 0x3F:
1087 return "Sharp CCD sensor + ADI 9804";
1088 case 0x40:
1089 return "UPA 1021 sensor";
1090 case 0x100:
1091 return "VGA sensor";
1092 case 0x101:
1093 return "PAL MR sensor";
1094 default:
Trent Piepho657de3c2006-06-20 00:30:57 -03001095 return "unknown type of sensor";
Luc Saillard2b455db2006-04-24 10:29:46 -03001096 }
1097}
1098#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
1100/***************************************************************************/
1101/* Video4Linux functions */
1102
Hans Verkuilbec43662008-12-30 06:58:20 -03001103static int pwc_video_open(struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104{
Luc Saillard2b455db2006-04-24 10:29:46 -03001105 int i, ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 struct video_device *vdev = video_devdata(file);
1107 struct pwc_device *pdev;
1108
Luc Saillard2b455db2006-04-24 10:29:46 -03001109 PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001110
Hans Verkuil601e9442008-08-23 07:24:07 -03001111 pdev = video_get_drvdata(vdev);
Eric Sesterhenn5d9a2762006-11-30 05:26:46 +01001112 BUG_ON(!pdev);
Luc Saillard2b455db2006-04-24 10:29:46 -03001113 if (pdev->vopen) {
1114 PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 return -EBUSY;
Luc Saillard2b455db2006-04-24 10:29:46 -03001116 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001117
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001118 mutex_lock(&pdev->modlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 if (!pdev->usb_init) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001120 PWC_DEBUG_OPEN("Doing first time initialization.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 pdev->usb_init = 1;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001122
Luc Saillard2b455db2006-04-24 10:29:46 -03001123 /* Query sensor type */
1124 ret = pwc_get_cmos_sensor(pdev, &i);
1125 if (ret >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 {
Luc Saillard2b455db2006-04-24 10:29:46 -03001127 PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
1128 pdev->vdev->name,
1129 pwc_sensor_type_to_string(i), i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 }
1131 }
1132
1133 /* Turn on camera */
1134 if (power_save) {
1135 i = pwc_camera_power(pdev, 1);
1136 if (i < 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001137 PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 }
1139 /* Set LED on/off time */
1140 if (pwc_set_leds(pdev, led_on, led_off) < 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001141 PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001142
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 pwc_construct(pdev); /* set min/max sizes correct */
1144
1145 /* So far, so good. Allocate memory. */
1146 i = pwc_allocate_buffers(pdev);
1147 if (i < 0) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001148 PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
1149 pwc_free_buffers(pdev);
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001150 mutex_unlock(&pdev->modlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 return i;
1152 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001153
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 /* Reset buffers & parameters */
1155 pwc_reset_buffers(pdev);
Luc Saillard2b455db2006-04-24 10:29:46 -03001156 for (i = 0; i < pwc_mbufs; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 pdev->image_used[i] = 0;
1158 pdev->vframe_count = 0;
1159 pdev->vframes_dumped = 0;
1160 pdev->vframes_error = 0;
1161 pdev->visoc_errors = 0;
1162 pdev->error_status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 pwc_construct(pdev); /* set min/max sizes correct */
1164
1165 /* Set some defaults */
1166 pdev->vsnapshot = 0;
1167
1168 /* Start iso pipe for video; first try the last used video size
1169 (or the default one); if that fails try QCIF/10 or QSIF/10;
1170 it that fails too, give up.
1171 */
1172 i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
1173 if (i) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001174 unsigned int default_resolution;
1175 PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n");
1176 if (pdev->type>= 730)
1177 default_resolution = PSZ_QSIF;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 else
Luc Saillard2b455db2006-04-24 10:29:46 -03001179 default_resolution = PSZ_QCIF;
1180
1181 i = pwc_set_video_mode(pdev,
1182 pwc_image_sizes[default_resolution].x,
1183 pwc_image_sizes[default_resolution].y,
1184 10,
1185 pdev->vcompression,
1186 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 }
1188 if (i) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001189 PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
1190 pwc_free_buffers(pdev);
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001191 mutex_unlock(&pdev->modlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 return i;
1193 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 i = pwc_isoc_init(pdev);
1196 if (i) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001197 PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
1198 pwc_isoc_cleanup(pdev);
1199 pwc_free_buffers(pdev);
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001200 mutex_unlock(&pdev->modlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 return i;
1202 }
1203
Luc Saillard2b455db2006-04-24 10:29:46 -03001204 /* Initialize the webcam to sane value */
1205 pwc_set_brightness(pdev, 0x7fff);
1206 pwc_set_agc(pdev, 1, 0);
1207
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 pdev->vopen++;
1209 file->private_data = vdev;
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001210 mutex_unlock(&pdev->modlock);
Luc Saillard2b455db2006-04-24 10:29:46 -03001211 PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 return 0;
1213}
1214
Oliver Neukum85237f22007-08-21 07:10:42 +02001215
1216static void pwc_cleanup(struct pwc_device *pdev)
1217{
1218 pwc_remove_sysfs_files(pdev->vdev);
1219 video_unregister_device(pdev->vdev);
1220}
1221
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222/* Note that all cleanup is done in the reverse order as in _open */
Hans Verkuilbec43662008-12-30 06:58:20 -03001223static int pwc_video_close(struct file *file)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224{
1225 struct video_device *vdev = file->private_data;
1226 struct pwc_device *pdev;
Oliver Neukum85237f22007-08-21 07:10:42 +02001227 int i, hint;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228
Luc Saillard2b455db2006-04-24 10:29:46 -03001229 PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001231 lock_kernel();
Hans Verkuil601e9442008-08-23 07:24:07 -03001232 pdev = video_get_drvdata(vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 if (pdev->vopen == 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001234 PWC_DEBUG_MODULE("video_close() called on closed device?\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
1236 /* Dump statistics, but only if a reasonable amount of frames were
1237 processed (to prevent endless log-entries in case of snap-shot
1238 programs)
1239 */
1240 if (pdev->vframe_count > 20)
Luc Saillard2b455db2006-04-24 10:29:46 -03001241 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 -07001242
Luc Saillard2b455db2006-04-24 10:29:46 -03001243 if (DEVICE_USE_CODEC1(pdev->type))
1244 pwc_dec1_exit();
1245 else
1246 pwc_dec23_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
1248 pwc_isoc_cleanup(pdev);
1249 pwc_free_buffers(pdev);
1250
1251 /* Turn off LEDS and power down camera, but only when not unplugged */
Oliver Neukum85237f22007-08-21 07:10:42 +02001252 if (!pdev->unplugged) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253 /* Turn LEDs off */
1254 if (pwc_set_leds(pdev, 0, 0) < 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001255 PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 if (power_save) {
1257 i = pwc_camera_power(pdev, 0);
1258 if (i < 0)
Luc Saillard2b455db2006-04-24 10:29:46 -03001259 PWC_ERROR("Failed to power down camera (%d)\n", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 }
Oliver Neukum85237f22007-08-21 07:10:42 +02001261 pdev->vopen--;
Jean Delvare7b9fbc32007-09-03 11:51:51 -03001262 PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
Oliver Neukum85237f22007-08-21 07:10:42 +02001263 } else {
1264 pwc_cleanup(pdev);
1265 /* Free memory (don't set pdev to 0 just yet) */
1266 kfree(pdev);
1267 /* search device_hint[] table if we occupy a slot, by any chance */
1268 for (hint = 0; hint < MAX_DEV_HINTS; hint++)
1269 if (device_hint[hint].pdev == pdev)
1270 device_hint[hint].pdev = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 }
Oliver Neukum85237f22007-08-21 07:10:42 +02001272 unlock_kernel();
1273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 return 0;
1275}
1276
1277/*
1278 * FIXME: what about two parallel reads ????
1279 * ANSWER: Not supported. You can't open the device more than once,
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001280 despite what the V4L1 interface says. First, I don't see
1281 the need, second there's no mechanism of alerting the
1282 2nd/3rd/... process of events like changing image size.
1283 And I don't see the point of blocking that for the
1284 2nd/3rd/... process.
1285 In multi-threaded environments reading parallel from any
1286 device is tricky anyhow.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287 */
1288
Luc Saillard2b455db2006-04-24 10:29:46 -03001289static ssize_t pwc_video_read(struct file *file, char __user *buf,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290 size_t count, loff_t *ppos)
1291{
1292 struct video_device *vdev = file->private_data;
1293 struct pwc_device *pdev;
1294 int noblock = file->f_flags & O_NONBLOCK;
1295 DECLARE_WAITQUEUE(wait, current);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001296 int bytes_to_read, rv = 0;
Luc Saillard2b455db2006-04-24 10:29:46 -03001297 void *image_buffer_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001298
Luc Saillard2b455db2006-04-24 10:29:46 -03001299 PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
1300 vdev, buf, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 if (vdev == NULL)
1302 return -EFAULT;
Hans Verkuil601e9442008-08-23 07:24:07 -03001303 pdev = video_get_drvdata(vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 if (pdev == NULL)
1305 return -EFAULT;
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001306
1307 mutex_lock(&pdev->modlock);
1308 if (pdev->error_status) {
1309 rv = -pdev->error_status; /* Something happened, report what. */
1310 goto err_out;
1311 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
1313 /* In case we're doing partial reads, we don't have to wait for a frame */
1314 if (pdev->image_read_pos == 0) {
1315 /* Do wait queueing according to the (doc)book */
1316 add_wait_queue(&pdev->frameq, &wait);
1317 while (pdev->full_frames == NULL) {
1318 /* Check for unplugged/etc. here */
1319 if (pdev->error_status) {
1320 remove_wait_queue(&pdev->frameq, &wait);
1321 set_current_state(TASK_RUNNING);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001322 rv = -pdev->error_status ;
1323 goto err_out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001325 if (noblock) {
1326 remove_wait_queue(&pdev->frameq, &wait);
1327 set_current_state(TASK_RUNNING);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001328 rv = -EWOULDBLOCK;
1329 goto err_out;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001330 }
1331 if (signal_pending(current)) {
1332 remove_wait_queue(&pdev->frameq, &wait);
1333 set_current_state(TASK_RUNNING);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001334 rv = -ERESTARTSYS;
1335 goto err_out;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001336 }
1337 schedule();
1338 set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 }
1340 remove_wait_queue(&pdev->frameq, &wait);
1341 set_current_state(TASK_RUNNING);
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001342
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 /* Decompress and release frame */
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001344 if (pwc_handle_frame(pdev)) {
1345 rv = -EFAULT;
1346 goto err_out;
1347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 }
1349
Luc Saillard2b455db2006-04-24 10:29:46 -03001350 PWC_DEBUG_READ("Copying data to user space.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 if (pdev->vpalette == VIDEO_PALETTE_RAW)
Luc Saillard2b455db2006-04-24 10:29:46 -03001352 bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 else
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001354 bytes_to_read = pdev->view.size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355
1356 /* copy bytes to user space; we allow for partial reads */
1357 if (count + pdev->image_read_pos > bytes_to_read)
1358 count = bytes_to_read - pdev->image_read_pos;
Luc Saillard2b455db2006-04-24 10:29:46 -03001359 image_buffer_addr = pdev->image_data;
1360 image_buffer_addr += pdev->images[pdev->fill_image].offset;
1361 image_buffer_addr += pdev->image_read_pos;
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001362 if (copy_to_user(buf, image_buffer_addr, count)) {
1363 rv = -EFAULT;
1364 goto err_out;
1365 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 pdev->image_read_pos += count;
1367 if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
1368 pdev->image_read_pos = 0;
1369 pwc_next_image(pdev);
1370 }
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001371 mutex_unlock(&pdev->modlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372 return count;
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001373err_out:
1374 mutex_unlock(&pdev->modlock);
1375 return rv;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376}
1377
1378static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
1379{
1380 struct video_device *vdev = file->private_data;
1381 struct pwc_device *pdev;
1382
1383 if (vdev == NULL)
1384 return -EFAULT;
Hans Verkuil601e9442008-08-23 07:24:07 -03001385 pdev = video_get_drvdata(vdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 if (pdev == NULL)
1387 return -EFAULT;
1388
1389 poll_wait(file, &pdev->frameq, wait);
1390 if (pdev->error_status)
1391 return POLLERR;
1392 if (pdev->full_frames != NULL) /* we have frames waiting */
1393 return (POLLIN | POLLRDNORM);
1394
1395 return 0;
1396}
1397
Hans Verkuilbec43662008-12-30 06:58:20 -03001398static int pwc_video_ioctl(struct file *file,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 unsigned int cmd, unsigned long arg)
1400{
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001401 struct video_device *vdev = file->private_data;
1402 struct pwc_device *pdev;
1403 int r = -ENODEV;
1404
1405 if (!vdev)
1406 goto out;
Hans Verkuil601e9442008-08-23 07:24:07 -03001407 pdev = video_get_drvdata(vdev);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001408
1409 mutex_lock(&pdev->modlock);
1410 if (!pdev->unplugged)
Hans Verkuilf473bf72008-11-01 08:25:11 -03001411 r = video_usercopy(file, cmd, arg, pwc_video_do_ioctl);
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001412 mutex_unlock(&pdev->modlock);
1413out:
1414 return r;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415}
1416
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
1418{
1419 struct video_device *vdev = file->private_data;
1420 struct pwc_device *pdev;
Luc Saillard2b455db2006-04-24 10:29:46 -03001421 unsigned long start;
1422 unsigned long size;
1423 unsigned long page, pos = 0;
1424 int index;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001425
Harvey Harrison645635b2008-04-08 23:20:00 -03001426 PWC_DEBUG_MEMORY(">> %s\n", __func__);
Hans Verkuil601e9442008-08-23 07:24:07 -03001427 pdev = video_get_drvdata(vdev);
Luc Saillard2b455db2006-04-24 10:29:46 -03001428 size = vma->vm_end - vma->vm_start;
1429 start = vma->vm_start;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001430
Luc Saillard2b455db2006-04-24 10:29:46 -03001431 /* Find the idx buffer for this mapping */
1432 for (index = 0; index < pwc_mbufs; index++) {
1433 pos = pdev->images[index].offset;
1434 if ((pos>>PAGE_SHIFT) == vma->vm_pgoff)
1435 break;
1436 }
1437 if (index == MAX_IMAGES)
1438 return -EINVAL;
1439 if (index == 0) {
1440 /*
1441 * Special case for v4l1. In v4l1, we map only one big buffer,
1442 * but in v4l2 each buffer is mapped
1443 */
1444 unsigned long total_size;
1445 total_size = pwc_mbufs * pdev->len_per_image;
1446 if (size != pdev->len_per_image && size != total_size) {
1447 PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n",
1448 size, pdev->len_per_image, total_size);
1449 return -EINVAL;
1450 }
1451 } else if (size > pdev->len_per_image)
1452 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453
Luc Saillard2b455db2006-04-24 10:29:46 -03001454 vma->vm_flags |= VM_IO; /* from 2.6.9-acX */
1455
1456 pos += (unsigned long)pdev->image_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457 while (size > 0) {
1458 page = vmalloc_to_pfn((void *)pos);
1459 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
1460 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 start += PAGE_SIZE;
1462 pos += PAGE_SIZE;
1463 if (size > PAGE_SIZE)
1464 size -= PAGE_SIZE;
1465 else
1466 size = 0;
1467 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 return 0;
1469}
1470
1471/***************************************************************************/
1472/* USB functions */
1473
1474/* This function gets called when a new device is plugged in or the usb core
1475 * is loaded.
1476 */
1477
1478static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id)
1479{
1480 struct usb_device *udev = interface_to_usbdev(intf);
1481 struct pwc_device *pdev = NULL;
1482 int vendor_id, product_id, type_id;
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001483 int i, hint, rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484 int features = 0;
1485 int video_nr = -1; /* default: use next available device */
1486 char serial_number[30], *name;
1487
Luc Saillard2b455db2006-04-24 10:29:46 -03001488 vendor_id = le16_to_cpu(udev->descriptor.idVendor);
1489 product_id = le16_to_cpu(udev->descriptor.idProduct);
1490
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 /* Check if we can handle this device */
Luc Saillard2b455db2006-04-24 10:29:46 -03001492 PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
1493 vendor_id, product_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 intf->altsetting->desc.bInterfaceNumber);
1495
1496 /* the interfaces are probed one by one. We are only interested in the
1497 video interface (0) now.
1498 Interface 1 is the Audio Control, and interface 2 Audio itself.
1499 */
1500 if (intf->altsetting->desc.bInterfaceNumber > 0)
1501 return -ENODEV;
1502
Linus Torvalds1da177e2005-04-16 15:20:36 -07001503 if (vendor_id == 0x0471) {
1504 switch (product_id) {
1505 case 0x0302:
Luc Saillard2b455db2006-04-24 10:29:46 -03001506 PWC_INFO("Philips PCA645VC USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 name = "Philips 645 webcam";
1508 type_id = 645;
1509 break;
1510 case 0x0303:
Luc Saillard2b455db2006-04-24 10:29:46 -03001511 PWC_INFO("Philips PCA646VC USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 name = "Philips 646 webcam";
1513 type_id = 646;
1514 break;
1515 case 0x0304:
Luc Saillard2b455db2006-04-24 10:29:46 -03001516 PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517 name = "Askey VC010 webcam";
1518 type_id = 646;
1519 break;
1520 case 0x0307:
Luc Saillard2b455db2006-04-24 10:29:46 -03001521 PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 name = "Philips 675 webcam";
1523 type_id = 675;
1524 break;
1525 case 0x0308:
Luc Saillard2b455db2006-04-24 10:29:46 -03001526 PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527 name = "Philips 680 webcam";
1528 type_id = 680;
1529 break;
1530 case 0x030C:
Luc Saillard2b455db2006-04-24 10:29:46 -03001531 PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 name = "Philips 690 webcam";
1533 type_id = 690;
1534 break;
1535 case 0x0310:
Luc Saillard2b455db2006-04-24 10:29:46 -03001536 PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537 name = "Philips 730 webcam";
1538 type_id = 730;
1539 break;
1540 case 0x0311:
Luc Saillard2b455db2006-04-24 10:29:46 -03001541 PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 name = "Philips 740 webcam";
1543 type_id = 740;
1544 break;
1545 case 0x0312:
Luc Saillard2b455db2006-04-24 10:29:46 -03001546 PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 name = "Philips 750 webcam";
1548 type_id = 750;
1549 break;
1550 case 0x0313:
Luc Saillard2b455db2006-04-24 10:29:46 -03001551 PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 name = "Philips 720K/40 webcam";
1553 type_id = 720;
1554 break;
Luc Saillard2b455db2006-04-24 10:29:46 -03001555 case 0x0329:
1556 PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
1557 name = "Philips SPC 900NC webcam";
Luc Saillard9ee6d782007-04-22 23:54:36 -03001558 type_id = 740;
Luc Saillard2b455db2006-04-24 10:29:46 -03001559 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 default:
1561 return -ENODEV;
1562 break;
1563 }
1564 }
1565 else if (vendor_id == 0x069A) {
1566 switch(product_id) {
1567 case 0x0001:
Luc Saillard2b455db2006-04-24 10:29:46 -03001568 PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 name = "Askey VC010 webcam";
1570 type_id = 645;
1571 break;
1572 default:
1573 return -ENODEV;
1574 break;
1575 }
1576 }
1577 else if (vendor_id == 0x046d) {
1578 switch(product_id) {
1579 case 0x08b0:
Luc Saillard2b455db2006-04-24 10:29:46 -03001580 PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 name = "Logitech QuickCam Pro 3000";
1582 type_id = 740; /* CCD sensor */
1583 break;
1584 case 0x08b1:
Luc Saillard2b455db2006-04-24 10:29:46 -03001585 PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 name = "Logitech QuickCam Notebook Pro";
1587 type_id = 740; /* CCD sensor */
1588 break;
1589 case 0x08b2:
Luc Saillard2b455db2006-04-24 10:29:46 -03001590 PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001591 name = "Logitech QuickCam Pro 4000";
1592 type_id = 740; /* CCD sensor */
1593 break;
1594 case 0x08b3:
Luc Saillard2b455db2006-04-24 10:29:46 -03001595 PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 name = "Logitech QuickCam Zoom";
1597 type_id = 740; /* CCD sensor */
1598 break;
1599 case 0x08B4:
Luc Saillard2b455db2006-04-24 10:29:46 -03001600 PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 name = "Logitech QuickCam Zoom";
1602 type_id = 740; /* CCD sensor */
Luc Saillard2b455db2006-04-24 10:29:46 -03001603 power_save = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 break;
1605 case 0x08b5:
Luc Saillard2b455db2006-04-24 10:29:46 -03001606 PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 name = "Logitech QuickCam Orbit";
1608 type_id = 740; /* CCD sensor */
1609 features |= FEATURE_MOTOR_PANTILT;
1610 break;
1611 case 0x08b6:
Jean Tourrilhesa63e1572007-03-21 16:29:16 -03001612 PWC_INFO("Logitech/Cisco VT Camera webcam detected.\n");
1613 name = "Cisco VT Camera";
1614 type_id = 740; /* CCD sensor */
1615 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001616 case 0x08b7:
Mauro Carvalho Chehab6b1ce3c2007-03-21 16:35:28 -03001617 PWC_INFO("Logitech ViewPort AV 100 webcam detected.\n");
1618 name = "Logitech ViewPort AV 100";
1619 type_id = 740; /* CCD sensor */
1620 break;
1621 case 0x08b8: /* Where this released? */
Luc Saillard2b455db2006-04-24 10:29:46 -03001622 PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 name = "Logitech QuickCam (res.)";
1624 type_id = 730; /* Assuming CMOS */
1625 break;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001626 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 return -ENODEV;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001628 break;
1629 }
1630 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631 else if (vendor_id == 0x055d) {
1632 /* I don't know the difference between the C10 and the C30;
1633 I suppose the difference is the sensor, but both cameras
1634 work equally well with a type_id of 675
1635 */
1636 switch(product_id) {
1637 case 0x9000:
Luc Saillard2b455db2006-04-24 10:29:46 -03001638 PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639 name = "Samsung MPC-C10";
1640 type_id = 675;
1641 break;
1642 case 0x9001:
Luc Saillard2b455db2006-04-24 10:29:46 -03001643 PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 name = "Samsung MPC-C30";
1645 type_id = 675;
1646 break;
Luc Saillard2b455db2006-04-24 10:29:46 -03001647 case 0x9002:
1648 PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
1649 name = "Samsung MPC-C30";
1650 type_id = 740;
1651 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 default:
1653 return -ENODEV;
1654 break;
1655 }
1656 }
1657 else if (vendor_id == 0x041e) {
1658 switch(product_id) {
1659 case 0x400c:
Luc Saillard2b455db2006-04-24 10:29:46 -03001660 PWC_INFO("Creative Labs Webcam 5 detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 name = "Creative Labs Webcam 5";
1662 type_id = 730;
1663 break;
1664 case 0x4011:
Luc Saillard2b455db2006-04-24 10:29:46 -03001665 PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 name = "Creative Labs Webcam Pro Ex";
1667 type_id = 740;
1668 break;
1669 default:
1670 return -ENODEV;
1671 break;
1672 }
1673 }
1674 else if (vendor_id == 0x04cc) {
1675 switch(product_id) {
1676 case 0x8116:
Luc Saillard2b455db2006-04-24 10:29:46 -03001677 PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001678 name = "Sotec Afina Eye";
1679 type_id = 730;
1680 break;
1681 default:
1682 return -ENODEV;
1683 break;
1684 }
1685 }
1686 else if (vendor_id == 0x06be) {
1687 switch(product_id) {
1688 case 0x8116:
1689 /* This is essentially the same cam as the Sotec Afina Eye */
Luc Saillard2b455db2006-04-24 10:29:46 -03001690 PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 name = "AME Co. Afina Eye";
1692 type_id = 750;
1693 break;
1694 default:
1695 return -ENODEV;
1696 break;
1697 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001698
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 }
1700 else if (vendor_id == 0x0d81) {
1701 switch(product_id) {
1702 case 0x1900:
Luc Saillard2b455db2006-04-24 10:29:46 -03001703 PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001704 name = "Visionite VCS-UC300";
1705 type_id = 740; /* CCD sensor */
1706 break;
1707 case 0x1910:
Luc Saillard2b455db2006-04-24 10:29:46 -03001708 PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 name = "Visionite VCS-UM100";
1710 type_id = 730; /* CMOS sensor */
1711 break;
1712 default:
1713 return -ENODEV;
1714 break;
1715 }
1716 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001717 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 return -ENODEV; /* Not any of the know types; but the list keeps growing. */
1719
1720 memset(serial_number, 0, 30);
1721 usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
Luc Saillard2b455db2006-04-24 10:29:46 -03001722 PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723
1724 if (udev->descriptor.bNumConfigurations > 1)
Luc Saillard2b455db2006-04-24 10:29:46 -03001725 PWC_WARNING("Warning: more than 1 configuration available.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726
1727 /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
Eric Sesterhenn80b6ca42006-02-27 21:29:43 +01001728 pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001729 if (pdev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001730 PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 return -ENOMEM;
1732 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 pdev->type = type_id;
1734 pdev->vsize = default_size;
1735 pdev->vframes = default_fps;
1736 strcpy(pdev->serial, serial_number);
1737 pdev->features = features;
1738 if (vendor_id == 0x046D && product_id == 0x08B5)
1739 {
1740 /* Logitech QuickCam Orbit
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001741 The ranges have been determined experimentally; they may differ from cam to cam.
1742 Also, the exact ranges left-right and up-down are different for my cam
1743 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 pdev->angle_range.pan_min = -7000;
1745 pdev->angle_range.pan_max = 7000;
1746 pdev->angle_range.tilt_min = -3000;
1747 pdev->angle_range.tilt_max = 2500;
1748 }
1749
Matthias Kaehlckeb9378fd2007-07-02 10:04:52 -03001750 mutex_init(&pdev->modlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751 spin_lock_init(&pdev->ptrlock);
1752
1753 pdev->udev = udev;
1754 init_waitqueue_head(&pdev->frameq);
1755 pdev->vcompression = pwc_preferred_compression;
1756
1757 /* Allocate video_device structure */
1758 pdev->vdev = video_device_alloc();
Al Viro5fa12472008-03-29 03:07:38 +00001759 if (!pdev->vdev) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001760 PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 kfree(pdev);
1762 return -ENOMEM;
1763 }
1764 memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
Hans Verkuil5e85e732008-07-20 06:31:39 -03001765 pdev->vdev->parent = &(udev->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 strcpy(pdev->vdev->name, name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 video_set_drvdata(pdev->vdev, pdev);
1768
1769 pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
Luc Saillard2b455db2006-04-24 10:29:46 -03001770 PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771
1772 /* Now search device_hint[] table for a match, so we can hint a node number. */
1773 for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
1774 if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) &&
1775 (device_hint[hint].pdev == NULL)) {
1776 /* so far, so good... try serial number */
1777 if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
Trent Piepho657de3c2006-06-20 00:30:57 -03001778 /* match! */
1779 video_nr = device_hint[hint].device_node;
1780 PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
1781 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 }
1783 }
1784 }
1785
1786 pdev->vdev->release = video_device_release;
1787 i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
1788 if (i < 0) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001789 PWC_ERROR("Failed to register as video device (%d).\n", i);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001790 rc = i;
1791 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001792 }
1793 else {
Hans Verkuilc6330fb2008-10-19 18:54:26 -03001794 PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 }
1796
1797 /* occupy slot */
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001798 if (hint < MAX_DEV_HINTS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 device_hint[hint].pdev = pdev;
1800
Luc Saillard2b455db2006-04-24 10:29:46 -03001801 PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 usb_set_intfdata (intf, pdev);
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001803 rc = pwc_create_sysfs_files(pdev->vdev);
1804 if (rc)
1805 goto err_unreg;
Luc Saillard2b455db2006-04-24 10:29:46 -03001806
1807 /* Set the leds off */
1808 pwc_set_leds(pdev, 0, 0);
1809 pwc_camera_power(pdev, 0);
1810
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 return 0;
Jeff Garzikc12e3be2006-10-13 07:17:32 -03001812
1813err_unreg:
1814 if (hint < MAX_DEV_HINTS)
1815 device_hint[hint].pdev = NULL;
1816 video_unregister_device(pdev->vdev);
1817err:
1818 video_device_release(pdev->vdev); /* Drip... drip... drip... */
1819 kfree(pdev); /* Oops, no memory leaks please */
1820 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821}
1822
1823/* The user janked out the cable... */
1824static void usb_pwc_disconnect(struct usb_interface *intf)
1825{
1826 struct pwc_device *pdev;
1827 int hint;
1828
1829 lock_kernel();
1830 pdev = usb_get_intfdata (intf);
1831 usb_set_intfdata (intf, NULL);
1832 if (pdev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001833 PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834 goto disconnect_out;
1835 }
1836 if (pdev->udev == NULL) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001837 PWC_ERROR("pwc_disconnect() already called for %p\n", pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 goto disconnect_out;
1839 }
1840 if (pdev->udev != interface_to_usbdev(intf)) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001841 PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 goto disconnect_out;
1843 }
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001844
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845 /* We got unplugged; this is signalled by an EPIPE error code */
1846 if (pdev->vopen) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001847 PWC_INFO("Disconnected while webcam is in use!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 pdev->error_status = EPIPE;
1849 }
1850
1851 /* Alert waiting processes */
1852 wake_up_interruptible(&pdev->frameq);
1853 /* Wait until device is closed */
Oliver Neukum85237f22007-08-21 07:10:42 +02001854 if(pdev->vopen) {
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001855 mutex_lock(&pdev->modlock);
Oliver Neukum85237f22007-08-21 07:10:42 +02001856 pdev->unplugged = 1;
Oliver Neukum0b67f5c2007-09-26 10:19:01 -03001857 mutex_unlock(&pdev->modlock);
1858 pwc_iso_stop(pdev);
Oliver Neukum85237f22007-08-21 07:10:42 +02001859 } else {
1860 /* Device is closed, so we can safely unregister it */
1861 PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
1862 pwc_cleanup(pdev);
1863 /* Free memory (don't set pdev to 0 just yet) */
1864 kfree(pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865
1866disconnect_out:
Oliver Neukum85237f22007-08-21 07:10:42 +02001867 /* search device_hint[] table if we occupy a slot, by any chance */
1868 for (hint = 0; hint < MAX_DEV_HINTS; hint++)
1869 if (device_hint[hint].pdev == pdev)
1870 device_hint[hint].pdev = NULL;
1871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872
1873 unlock_kernel();
1874}
1875
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876/* *grunt* We have to do atoi ourselves :-( */
1877static int pwc_atoi(const char *s)
1878{
1879 int k = 0;
1880
1881 k = 0;
1882 while (*s != '\0' && *s >= '0' && *s <= '9') {
1883 k = 10 * k + (*s - '0');
1884 s++;
1885 }
1886 return k;
1887}
1888
1889
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03001890/*
1891 * Initialization code & module stuff
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 */
1893
Luc Saillard2b455db2006-04-24 10:29:46 -03001894static char *size;
1895static int fps;
1896static int fbufs;
1897static int mbufs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898static int compression = -1;
1899static int leds[2] = { -1, -1 };
Al Viro64a6f952007-10-14 19:35:30 +01001900static unsigned int leds_nargs;
Luc Saillard2b455db2006-04-24 10:29:46 -03001901static char *dev_hint[MAX_DEV_HINTS];
Al Viro64a6f952007-10-14 19:35:30 +01001902static unsigned int dev_hint_nargs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903
Luc Saillard2b455db2006-04-24 10:29:46 -03001904module_param(size, charp, 0444);
1905module_param(fps, int, 0444);
1906module_param(fbufs, int, 0444);
1907module_param(mbufs, int, 0444);
Trent Piepho05ad3902007-01-30 23:26:01 -03001908#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -03001909module_param_named(trace, pwc_trace, int, 0644);
1910#endif
1911module_param(power_save, int, 0444);
1912module_param(compression, int, 0444);
1913module_param_array(leds, int, &leds_nargs, 0444);
1914module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
1915
Linus Torvalds1da177e2005-04-16 15:20:36 -07001916MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920MODULE_PARM_DESC(trace, "For debugging purposes");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001921MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001924MODULE_PARM_DESC(dev_hint, "Device node hints");
1925
1926MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
1927MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
1928MODULE_LICENSE("GPL");
Luc Saillard2b455db2006-04-24 10:29:46 -03001929MODULE_ALIAS("pwcx");
1930MODULE_VERSION( PWC_VERSION );
Linus Torvalds1da177e2005-04-16 15:20:36 -07001931
1932static int __init usb_pwc_init(void)
1933{
1934 int i, sz;
1935 char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
1936
Luc Saillard2b455db2006-04-24 10:29:46 -03001937 PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
1938 PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
1939 PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
1940 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 -07001941
1942 if (fps) {
1943 if (fps < 4 || fps > 30) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001944 PWC_ERROR("Framerate out of bounds (4-30).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 return -EINVAL;
1946 }
1947 default_fps = fps;
Luc Saillard2b455db2006-04-24 10:29:46 -03001948 PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 }
1950
Luc Saillard2b455db2006-04-24 10:29:46 -03001951 if (size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 /* string; try matching with array */
1953 for (sz = 0; sz < PSZ_MAX; sz++) {
1954 if (!strcmp(sizenames[sz], size)) { /* Found! */
1955 default_size = sz;
1956 break;
1957 }
1958 }
1959 if (sz == PSZ_MAX) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001960 PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 return -EINVAL;
1962 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001963 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 -07001964 }
1965 if (mbufs) {
1966 if (mbufs < 1 || mbufs > MAX_IMAGES) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001967 PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 return -EINVAL;
1969 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001970 pwc_mbufs = mbufs;
1971 PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972 }
1973 if (fbufs) {
1974 if (fbufs < 2 || fbufs > MAX_FRAMES) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001975 PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 return -EINVAL;
1977 }
1978 default_fbufs = fbufs;
Luc Saillard2b455db2006-04-24 10:29:46 -03001979 PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001980 }
Trent Piepho05ad3902007-01-30 23:26:01 -03001981#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -03001982 if (pwc_trace >= 0) {
1983 PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 }
Luc Saillard2b455db2006-04-24 10:29:46 -03001985#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 if (compression >= 0) {
1987 if (compression > 3) {
Luc Saillard2b455db2006-04-24 10:29:46 -03001988 PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 return -EINVAL;
1990 }
1991 pwc_preferred_compression = compression;
Luc Saillard2b455db2006-04-24 10:29:46 -03001992 PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 }
1994 if (power_save)
Luc Saillard2b455db2006-04-24 10:29:46 -03001995 PWC_DEBUG_MODULE("Enabling power save on open/close.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 if (leds[0] >= 0)
1997 led_on = leds[0];
1998 if (leds[1] >= 0)
1999 led_off = leds[1];
2000
Steven Cole093cf722005-05-03 19:07:24 -06002001 /* Big device node whoopla. Basically, it allows you to assign a
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 device node (/dev/videoX) to a camera, based on its type
2003 & serial number. The format is [type[.serialnumber]:]node.
2004
2005 Any camera that isn't matched by these rules gets the next
2006 available free device node.
2007 */
2008 for (i = 0; i < MAX_DEV_HINTS; i++) {
2009 char *s, *colon, *dot;
2010
2011 /* This loop also initializes the array */
2012 device_hint[i].pdev = NULL;
2013 s = dev_hint[i];
2014 if (s != NULL && *s != '\0') {
2015 device_hint[i].type = -1; /* wildcard */
2016 strcpy(device_hint[i].serial_number, "*");
2017
2018 /* parse string: chop at ':' & '/' */
2019 colon = dot = s;
2020 while (*colon != '\0' && *colon != ':')
2021 colon++;
2022 while (*dot != '\0' && *dot != '.')
2023 dot++;
2024 /* Few sanity checks */
2025 if (*dot != '\0' && dot > colon) {
Luc Saillard2b455db2006-04-24 10:29:46 -03002026 PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 return -EINVAL;
2028 }
2029
2030 if (*colon == '\0') {
2031 /* No colon */
2032 if (*dot != '\0') {
Luc Saillard2b455db2006-04-24 10:29:46 -03002033 PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034 return -EINVAL;
2035 }
2036 else {
2037 /* No type or serial number specified, just a number. */
2038 device_hint[i].device_node = pwc_atoi(s);
2039 }
2040 }
2041 else {
2042 /* There's a colon, so we have at least a type and a device node */
2043 device_hint[i].type = pwc_atoi(s);
2044 device_hint[i].device_node = pwc_atoi(colon + 1);
2045 if (*dot != '\0') {
2046 /* There's a serial number as well */
2047 int k;
Mauro Carvalho Chehabd56410e2006-03-25 09:19:53 -03002048
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 dot++;
2050 k = 0;
2051 while (*dot != ':' && k < 29) {
2052 device_hint[i].serial_number[k++] = *dot;
2053 dot++;
2054 }
2055 device_hint[i].serial_number[k] = '\0';
2056 }
2057 }
Luc Saillard2b455db2006-04-24 10:29:46 -03002058 PWC_TRACE("device_hint[%d]:\n", i);
2059 PWC_TRACE(" type : %d\n", device_hint[i].type);
2060 PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number);
2061 PWC_TRACE(" node : %d\n", device_hint[i].device_node);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 }
2063 else
2064 device_hint[i].type = 0; /* not filled */
2065 } /* ..for MAX_DEV_HINTS */
2066
Luc Saillard2b455db2006-04-24 10:29:46 -03002067 PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002068 return usb_register(&pwc_driver);
2069}
2070
2071static void __exit usb_pwc_exit(void)
2072{
Luc Saillard2b455db2006-04-24 10:29:46 -03002073 PWC_DEBUG_MODULE("Deregistering driver.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 usb_deregister(&pwc_driver);
Luc Saillard2b455db2006-04-24 10:29:46 -03002075 PWC_INFO("Philips webcam module removed.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076}
2077
2078module_init(usb_pwc_init);
2079module_exit(usb_pwc_exit);
2080
Luc Saillard2b455db2006-04-24 10:29:46 -03002081/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */